Project background

At the initial stage of the project, we needed to establish our own design system. We spike some schemes, and Tailwind-RN is one of them. If it is useful or will use tailwind-RN, you can come in and have a look to avoid stepping on the pit.

Later, I thought the project was relatively simple, and Tailwind was not very friendly to the new project partners, so we didn’t adopt it.

Introduction to the

GitHub – Vadimdemedes /tailwind- Rn: 🦎 Use tailwind CSS in React Native projects

Tailwind advocated atomic CSS classes to be flexible, reusable, and less repetitive, as well as therapeutic for people with OCD (after all, remembering class names is sometimes a headache). Of course, there is some familiarity cost for beginners, you need to know some of its rules, familiar with its naming system and so on. If you are not familiar with tailwind, please do a Google search.

Tailwind-rn is a tailwind-based implementation that uses the CSS classes generated by tailwind and then does some processing (CSS declaration conversion, removal of CSS declarations that do not apply to Rn, etc.) to convert them to a Styles format for Rn.

All styles are generated from Tailwind CSS source and not hard-coded, which makes it easy to keep this module up-to-date with latest changes in Tailwind CSS itself.

use

So let’s just kind of look at how tailwind -Rn might be used in Rn.

import React from 'react';
import {SafeAreaView, View, Text} from 'react-native';
import tailwind from 'tailwind-rn';

const App = () = > (
	<SafeAreaView style={tailwind('h-full')} >
		<View style={tailwind('pt-12 items-center')} >
			<View style={tailwind('bg-blue-200 px-3 py-1 rounded-full')} >
				<Text style={tailwind('text-blue-800 font-semibold')} >
					Hello Tailwind
				</Text>
			</View>
		</View>
	</SafeAreaView>
);

export default App;
Copy the code

The tailwind method is re-exposed from tailwind. Ts, along with a getColor method.

import { create } from 'tailwind-rn';
import styles from './styles.json';

const { tailwind, getColor } = create(styles);

tailwind('text-blue-500 text-opacity-50');
//=> {color: rgba(66, 153, 225, 0.5)'}
Copy the code

Styles. json is created using the CLI. This file is a tailwind CSS class → RN Styles mapping. So if you have enabled purge and added some custom styles, you will need to manually execute the CLI command line each time to regenerate styles.json.

As an easy way to do this, you can listen for tailwind. Config.js to change and then automatically generate styles.json, since custom styles change this file.

Some advantages

Purge function

Turn on the Purge configuration, which allows you to generate as few atomic RN styles as possible, maximizing the reduced volume. It is recommended not to enable it at development time, but to execute it once at packaging time.

// Default tailwind config
/ / Refer to https://unpkg.com/browse/[email protected]/stubs/defaultConfig.stub.js

module.exports = {
    purge: {
        enabled: true.content: ['.. /.. /src/**/*.ts'.'.. /.. /src/**/*.tsx']},variants: {
        extend: {}},plugins: []};Copy the code

Custom theme

Tailwind-rn also works well with tailwind’s design system, which allows you to use its built-in design system without configuration, or to add and override values to define your own design system.

theme: {
  fontSize: {
    xs: 12.sm: 14.base: 16.lg: 18,},extend: {
		// Custom extend will generate custom classes in addition to the tailwind default
    colors: {
      brand: {
        primary: {
          100: '#2c28f7'
        },
        secondary: {
          100: '#146d23'}}},padding: {
      7.5: 30
    },
    width: {
      12.5: 50.'3/7': '42.857143%'.'4/7': '57.142857%'
    },
    borderWidth: {
      1.5: 6}}}Copy the code

Some of the pit

No support for individual border (top, bottom, left, right) color attributes

Tailwind only supports full border color, but does not support top, bottom, left, and right borders.

border-black {
	--tw-border-opacity: 1;
	border-color: rgba(0.0.0.var(--tw-border-opacity));
}
Copy the code

Tailwind ships with 73 colors out of the box and 5 breakpoints, which means there are already 365 border color utilities. If we added per-side border colors, that would jump to 1825 classes.

The official answer is that if the color support of four borders is added, Tailwind may need an additional 1825 CSS declarations, so it is not under consideration for the time being. 【 Issue link 】

The solution given is to create a new Component class using @apply

.code-block {
    @apply .border .border-grey-light;
    border-left-width: config('borderWidths.4');
    border-left-color: config('borderColors.grey-dark');
}
Copy the code

Tailwind – Rn does not use @apply to redefine a custom class. The official explanation is that using @apply is actually using tailwind(‘xx’). I was hoping that tailwind -Rn would help me type my custom classes into styles.json instead of having to manually define tailwind(‘xx’) and import it manually.

I think tailwind() function itself is an equivalent of @apply already. @apply py-2 px-2 bg-blue-500 is the same as tailwind('py-2 px-2 bg-blue-500'). Support @apply

So the implementation on RN is similar

arrow: { ... tailwind(['w-0'.'h-0'.'border-solid'.'border - 1.5']),
  borderTopColor: getColor('bg-black-medium'),
  borderLeftColor: getColor('bg-white-dark'),
  borderBottomColor: getColor('bg-black-medium'),
  borderRightColor: getColor('bg-black-medium')}Copy the code

Does not support a StyleSheet. HairLineWidth

React Native defines a logical pixel unit that has no units. **

RN is a cross-platform framework. On IOS, the size is usually described in logical pixel unit pt, while on Android, the size is usually described in logical pixel unit DP. It is not good to choose RN either. RN provides developers with the logical pixel size that has been converted through DPR (device pixel ratio), and developers no longer need to worry about the size numerical calculation problems caused by different device DPR

Through the interpretation of the above, so the width of 1, represents the 1 pt on ios, represent 1 dp on android, show the device pixels in double screen is a physical pixel is 2, three times the screen is 3 physical pixels, and a pixel border is actually represent physical pixels, so the ios on the triple screen to display a pixel border, The corresponding value should be 0.33333pt.

Since we need to use RN’s hairLineWidth to help us automatically calculate from device to device, we can’t use configuration files to do this, so the solution is a bit more hardcore, which is to simply plug in styles.json.

Custom.style.ts to handle class declarations that tailwind- Rn cannot handle.

// custom.styles.ts

import { StyleSheet } from 'react-native';

export const customStyles = {
  'border-hair': {
	    borderWidth: StyleSheet.hairlineWidth
  },
  'border-t-hair': {
	    borderTopWidth: StyleSheet.hairlineWidth
  },
  'border-b-hair': {
      borderBottomWidth: StyleSheet.hairlineWidth
  },
  'border-l-hair': {
      borderLeftWidth: StyleSheet.hairlineWidth
  },
  'border-r-hair': {
      borderRightWidth: StyleSheet.hairlineWidth
  },
  'width-hair': {
      width: StyleSheet.hairlineWidth
  }
};

export type CustomStylesKey = keyof typeof customStyles;
Copy the code

Then merge in tailwind. Ts

// tailwind.ts
import { create } from 'tailwind-rn';
import { assign } from 'lodash';

const { tailwind } = create(assign(styles, customStyles));
Copy the code

Intelligent prompt is not supported

Tailwind’s smart tip plugin is available on all the major ides, but tailwind’s tip plugin is not friendly to Tailwind – Rn and is easy to fix

  • Implement your own plug-in, compatible with various ides
  • Redefine the type, a neat way to do it, and I’ll show you how to do that

The editor doesn’t support intelligent hints, so we can take advantage of Typescript’s type system to tweak it a bit and make it self-inferential

// tailwind.ts

import { create } from 'tailwind-rn';
import styles from 'src/styles/styles.json';
import { assign } from 'lodash';
import { customStyles, CustomStylesKey } from 'src/styles/custom.style';

const { tailwind } = create(assign(styles, customStyles));

export type TailwindKey = keyof typeof styles | CustomStylesKey;

export default (keys: TailwindKey[]) => tailwind(keys.join(' '));
Copy the code

This forces the string to be an array so that the IDE can identify its tailwind key type

// Recommended
tailwind('h-11 bg-red-100')

// After the modification
tailwind(['h-11'.'bg-red-100'])
Copy the code

GetColor conflicts with Purge

When using the getColor method provided by Tailwind – Rn and having the Purge configuration enabled

// tailwind.config.js
module.exports = {
    purge: {
        enabled: true.content: ['.. /.. /src/**/*.ts'.'.. /.. /src/**/*.tsx']},// ...
}
Copy the code

Since Tailwind doesn’t support border colors by default, I had to use the method RN provided. But to do so, I need to use the getColor method.

// PageA.styles.ts
const styles = StyleSheet.create({
    container: {
        ...tailwind('w-11 h-11 bg-black text-white'),
        borderTopColor: getColor("blue-500")}})Copy the code

But after I used Purge, Tailwind scanned the CSS classes that were already in use by default, so blue-500 was not recognized and was not packaged into styles.json.

That’s the problem. The solution is simple: use the CSS classes provided by Tailwind

// PageA.styles.ts
const styles = StyleSheet.create({
    container: {
        ...tailwind('w-11 h-11 bg-black text-white'),
        borderTopColor: getColor("bg-blue-500 bg-opacity-50")}})Copy the code

The getColor in the source code will scan the background by default, so it will concatenate the bg- by default

// Pass the name of a color (e.g. "bg-blue-500") and receive a color value (e.g. "#4399e1"),
Opacity (e.g. "bg-black bg-50 ") and get a color with opacity (e.g. "rgba(0,0, 0.5)")
const getColor = name= > {
		// const style = tailwind(name.split(' ').map(className => `bg-${className}`).join(' '));
    const style = tailwind(name);
    return style.backgroundColor;
};
Copy the code

In response to this problem, I submitted a PR to the official, but I don’t know when to merge.

Purge function will conflict with getColor by Rynxiao · Pull Request #96 · Vadimdemedes/Tailwind – RN

Obviously, modifying the source code is not reliable, and the next update may kill your original Apply code, so we will implement it ourselves.

// tailwind.ts

export const getColor = (keys: TailwindKey[]) = > {
    const style = tailwind(key.join(' '));
    return style.backgroundColor;
};
Copy the code

conclusion

  • It’s really annoying to use it at the beginning, looking for it one class at a time, but after getting familiar with its naming conventions, it’s actually pretty smooth to write.
  • There are some pits, but they are not unsolvable problems, the biggest use of native RN Style masturbation.

Refer to the link

  • Github.com/vadimdemede…
  • Talk about the React Native screen adaptation