Giter Club home page Giter Club logo

react-native-styled.macro's Introduction

Disclaimer: This library is still in Beta. Use with caution. The Roadmap for v1.0.0 is available here.

💅 styled.macro

A Utility-first Styling Library for React Native.

Features

  • Zero-overhead: Styles get injected via the StyleSheet API during compilation.
  • 🍂 Minimal footprint: Styles that are never used won't make it to the final App bundle.
  • 🎲 Variants support: Conditionally style based on Platform, Layout or Screen size ... etc.
  • 💅 Style props: Supports common style-related Component props e.g. numberOfLines.
  • 🔌 Customizable (Coming soon): Optionally override the default theme by adding styled.config.js file

Table of Contents

Getting started

Compatible with React Native v0.62.0 or later

yarn add react-native-styled.macro babel-plugin-macros

Add babel-plugin-macros to your Babel config (if you haven't already)

// babel.config.js
module.exports = function (api) {
	return {
		plugins: ['macros'],
		// ... other stuff
	};
};

To use the library simply import the macro as follows:

import styled from 'react-native-styled.macro';

const Heading = ({ text }) => (
	<Text
		{...styled([
			'my-4',
			'text-2xl',
			'text-gray-900',
			'font-semibold',
			'letter-wide',
		])}
	>
		{text}
	</Text>
);

The compiled output for the above code will look something like the following:

import { Text } from 'react-native';
+import { StyleSheet } from 'react-native';
+import { rem } from 'react-native-styled.macro/path/not/relevant';
-import styled from 'react-native-styled.macro';

+const styles = StyleSheet.create({
+	_default: {
+		marginVertical: rem(1),
+		fontSize: rem(1.5),
+		color: '#1a202c',
+		fontWeight: '600',
+		letterSpacing: rem(0.025),
+	},
+});

const Heading = ({ text }) => (
	<Text
-		{...styled([
-			'my-4',
-			'text-2xl',
-			'text-gray-900',
-			'font-semibold',
-			'letter-wide',
-		])}
+		{...{
+			style: styles._default,
+		}}
	>
		{text}
	</Text>
);

How does it work?

  • styled (you can name it anything) is a Babel Macro which means it will be executed during compilation.
  • It will map the given styles and resolve the necessary style attributes/props.
  • It will try to merge styles of the same variant if possible so we don't end up creating an object for every style e.g. text-2xl.
  • For the best performance, it will then use the good/old StyleSheet.create to create the styles as you should normally do by yourself in a React Native app.

The output for any code you write will look more or less the same as above. The only exception is a style with multiple variants because we need to add logic to switch styles at runtime (same as you would do e.g. using Platform.select())

Available Styles

See docs/styles.md

Variants

Platform (Built-in)

Enables Platform-specific style. Based on the value of Platform.OS.

Possible values: android, ios, web or whatever the value of Platform.OS.

Example:

styled([
	'bg-white',
	'web:bg-purple-600',
	'android:bg-green-600',
	'ios:bg-blue-600',
]);

Layout (Built-in)

Enables Layout-specific style. Based on the value of I18nManager.isRTL.

Possible keys: ltr or rtl.

Example:

styled(['text-auto', 'rtl:text-right', 'ltr:text-left']);

Responsive

Built on the top of React Native's useWindowDimensions hook. Possible keys: sm, md, lg, xl or custom values (see below).

Example

import styled from 'react-native-styled.macro';
import { useWindowVariant } from 'react-native-styled.macro/lib';

const MyComponent = () => {
	const windowVariant = useWindowVariant();

	return (
		<Text
			{...styled(['w-full', 'md:w-64'], {
				...windowVariant /* other variants */,
			})}
		>
			My text
		</Text>
	);
};

You can also pass custom breakpoints as follows:

// Note: passing a custom object will remove the default breakpoints e.g. `sm`.
useWindowVariant({
	tablet: 640,
	laptop: 768,
	// .. anything really
});

// use it later
styled(['tablet:w-full', 'laptop:w-64']);

Dark mode

Since styled accepts arbitrary keys as variants supporting Dark mode can be easily acheived as follows:

import { useColorScheme } from 'react-native';
import styled from 'react-native-styled.macro';

const MyComponent = () => {
	// Can either be 'dark' or 'light'
	const colorScheme = useColorScheme();

	return (
		<Text
			{...styled(['text-black', 'dark:text-white'], {
				dark: colorScheme === 'dark',
			})}
		>
			My text
		</Text>
	);
};

Best Practices

Group variant styles together

Do NOT

styled(['web:bg-gray-100', 'bg-white', 'text-black', 'web:rounded']);

Do

styled(['bg-white', 'text-black', 'web:rounded', 'web:bg-gray-100']);

In addition to the readability concern, it also enables some compile-time optimizations.

Prior Art

  • Tailwind CSS (website): Tailwind is a great utility-first CSS framework. We borrowed the utility-first approach from there and re-imagined how it can be used in React Native apps to build user interfaces faster without additional Runtime overhead.

Alternatives

  • tailwind-react-native (github): A very promising Tailwind-like library made with React Native in mind.

License

MIT © Ahmed T. Ali

react-native-styled.macro's People

Contributors

branikclimbs avatar dependabot[bot] avatar jeffreyyoung avatar z0al avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

react-native-styled.macro's Issues

The automated release is failing 🚨

🚨 The automated release from the master branch failed. 🚨

I recommend you give this issue a high priority, so other packages depending on you could benefit from your bug fixes and new features.

You can find below the list of errors reported by semantic-release. Each one of them has to be resolved in order to automatically publish your package. I’m sure you can resolve this 💪.

Errors are usually caused by a misconfiguration or an authentication problem. With each error reported below you will find explanation and guidance to help you to resolve it.

Once all the errors are resolved, semantic-release will release your package the next time you push a commit to the master branch. You can also manually restart the failed CI job that runs semantic-release.

If you are not sure how to resolve this, here is some links that can help you:

If those don’t help, or if this issue is reporting something you think isn’t right, you can always ask the humans behind semantic-release.


Invalid npm token.

The npm token configured in the NPM_TOKEN environment variable must be a valid token allowing to publish to the registry https://registry.npmjs.org/.

If you are using Two-Factor Authentication, make configure the auth-only level is supported. semantic-release cannot publish with the default auth-and-writes level.

Please make sure to set the NPM_TOKEN environment variable in your CI with the exact value of the npm token.


Good luck with your project ✨

Your semantic-release bot 📦🚀

Dynamic style inside styled

Hi,
I just started using this library in my side project and I came across a situation where I need inject dynamic style inside the ...styled([]).

I want to change the fontSize to be different according to the prop passed. For eg.

  const fontSize = big ? 'text-6xl' : 'text-3xl';

and than use

  <Text {...styled([fontSize, 'text-center', 'uppercase'])}>Text</Text>

But It seems I cannot use a variable inside the styled.
Is there anyway I can achieve the above or I am missing something here?

Could I use the Babel plugin with any React Native styles?

Hey there, cool package. I came across it on Twitter the other day (I maintain Dripsy, a responsive design system for RNW.)

I think the static extraction of styles is a really cool idea that you have here. I'm wondering if there's a way I might be able to repurpose the Babel plugin for Dripsy to improve performance, namely on web.

Would you have any suggestions for how I might do that? I don't really know my way around Babel, but I was wondering if your plugin could be generalized to any react native inline styles by chance.

Thanks so much!

config / plugins

hi there - this library looks amazing.

i basically wasted a bunch of time building a runtime version of this, but this looks way better. is there anything i can do to help? i know adding custom configs is likely the next step, also are you thinking of a plugin system?

cheers!

Unable to Run Example Project

Hello!

I've tried running the example project in the repo as follows:

  • Clone the branch
  • cd example
  • yarn install
  • expo start
  • Open in simulator.

Unfortunately, I always get this error:

Unable to resolve module react-native-styled.macro/lib from App.tsx: react-native-styled.macro/lib could not be found within the project.

react-native-styled macro-example-error

I've tried all the suggestions for resolving with no success.

Do you know how I can run the example without getting this error?

Cannot import the macro

So apparently publishing an npm package for RN isn't as easy as I thought. Importing the macro in a RN/Expo app doesn't work:

Failed building JavaScript bundle.
Cannot use import statement outside a module
... the rest of the stack...
basically points to the first line in macro.js

I tried transpiling the code before publishing to npm by setting module: "commonjs in tsconfig.json but that didn't help because then the error would move to the react-native module itself (because we use the StyleSheet.flatten API during compilation). Similar to what you would get if you didn't configure Jest correctly.

import typeof AccessibilityInfo from './Libraries/Components/AccessibilityInfo/AccessibilityInfo';
^^^^^^

SyntaxError: Cannot use import statement outside a module

Strangely enough, importing the useWindowVariant hook works just fine.

Missing h-full style

Hi, I noticed that there are no percentage height styles. I find myself using h-full a lot but there might be cases when others can be useful as well, is there any reason why there are no percentage heights included in the base theme?

Roadmap (v1.0.0)

What is this?

In this issue, I want to provide some context and share what I have in mind about the future of styled.macro.

It should be made clear that I'm currently experimenting with this library in a private app. My focus is to know what works in practice and what doesn't, explore the limitations, and hopefully come up with ways to address them.

If you are already using styled.macro in a project then I'd love to hear your feedback too. Please either comment on this issue or create a new one and let's have a chat.

Todos

  • Accept styles as a string in addition to the current array syntax. (available since v0.9.0)

    Example:

    styled('text-lg text-black dark:text-white', variants);
  • TypeScript autocompletion (>= v4.1). It should work at least for the default theme

  • Export styleOf helper
    It's similar to styled but it returns the style object directly. It should make it easier to pass styles to props like textStyle, containerStyle ...etc. It will also throw if you passed a style that results in a props e.g. numberOfLines

    Example:

    import { Flatlist } from 'react-native';
    import { styleOf } from 'react-native-styled.macro';
    
    // Instead of `styled(...).style`
    <Flatlist {...props} columnWrapperStyle={styleOf('flex-1 px-4')} />;
  • Export theme helper
    Enables accessing theme object directly.

    Example:

    import { theme } from 'react-native-styled.macro';
    
    theme() // { /* the full theme object */}
    theme('colors.gray.700') //  #hex
  • Custom theming

    The user should be able to define styled.config.js like this:

    module.exports = {
    	theme: (defaultTheme: Theme) => {
    		return {
    			...defaultTheme,
    			// ... custom stuff
    		};
    	},
    };
  • Custom plugins

    The user should be able to add additional style generators (i.e. plugins) via styled.config.js:

    function myPlugin(theme: Theme){
      return {
        'my-style' {
          paddingTop: theme.padding['10']
        }
      }
    }
    
    module.exports = {
      theme: (theme: Theme) => theme,
      plugins: [ myPlugin ]
    };
  • Support missing styles

    • Box Shadow
    • Font family
    • Reset helpers for width & height (i.e. w-auto & h-auto). (#68)
  • Review default theme style values. Currently, they mostly follow Tailwind CSS but it may make sense to revisit them to be more useful for React Native Apps.

  • Proper documentation and FAQs (and ideally, a docusaurus.io website)

  • TBD. Comment below if you have something in mind.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.