diff --git a/README.md b/README.md
index 2d40951..ed5f57c 100644
--- a/README.md
+++ b/README.md
@@ -18,11 +18,12 @@ Install the library
`npm install tailwindcss-react-native tailwindcss` or `yarn add tailwindcss-react-native tailwindcss`
-Create a `tailwind.config.js` and set `content`
+Create a `tailwind.config.js` and set `content` and added the `tailwindcss-react-native/plugin`
```js
// tailwind.config.js
module.exports = {
+ plugins: [require("tailwindcss-react-native/plugin")],
content: [
"./screens/**/*.{js,ts,jsx,tsx}",
"./pages/**/*.{js,ts,jsx,tsx}",
@@ -200,11 +201,11 @@ function MyAppsProviders ({ children }) {
You don't need to provide these props if you are using Babel or spreading the CLI output.
-| Prop | Values | Default | Description |
-| -------- | ----------------------------------------------------- | ----------- | --------------------------------------------------------------------------------------------------------- |
-| platform | `native`, `web`, `ios`, `android`, `windows`, `macos` | Platform.OS | Specifies how the className is transformed. `ios`, `android`, `windows`, `macos` are aliases for `native` |
-| style | Compiled style object | | |
-| media | Compiled media object | | |
+| Prop | Values | Default | Description |
+| -------- | ------------------------------------------------------------------- | ----------- | ----------------------------------------- |
+| platform | `web`, `native`, `ios`, `android`, `windows`, `macos`, `web-inline` | Platform.OS | Specifies how the styles are transformed. |
+| style | Compiled style object | | |
+| media | Compiled media object | | |
## Component API
@@ -265,17 +266,22 @@ Options can be provided via the babel config
```js
// babel.config.js
module.exports = {
- plugins: [["tailwindcss-react-native/babel", { platform: "native" }]],
+ plugins: [
+ [
+ "tailwindcss-react-native/babel",
+ { tailwindConfig: "./tailwind.native.config.js" },
+ ],
+ ],
};
```
-| Option | Values | Default | Description |
-| -------------- | ----------------------------------------------------- | --------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
-| platform | `native`, `web`, `ios`, `android`, `windows`, `macos` | `native` | Specifies how the className is transformed. `ios`, `android`, `windows`, `macos` are aliases for `native` |
-| hmr | `boolean` | Development: `true`
Production: `false` | Allow fast-refresh of styles |
-| tailwindConfig | Path relative to `cwd` | `tailwind.config.js` | Provide a custom `tailwind.config.js`. Useful for setting different settings per platform. |
-| allowModules | `*`, `string[]` | `*` | Only transform components from these imported modules. `*` will transform all modules |
-| blockModules | `string[]` | `[]` | Do not transform components from these imported modules. |
+| Option | Values | Default | Description |
+| -------------- | ----------------------------------------------------- | --------------------------------------------- | ------------------------------------------------------------------------------------------ |
+| platform | `native`, `web`, `ios`, `android`, `windows`, `macos` | `native` | Specifies how the className is transformed. |
+| hmr | `boolean` | Development: `true`
Production: `false` | Allow fast-refresh of styles |
+| tailwindConfig | Path relative to `cwd` | `tailwind.config.js` | Provide a custom `tailwind.config.js`. Useful for setting different settings per platform. |
+| allowModules | `*`, `string[]` | `*` | Only transform components from these imported modules. `*` will transform all modules |
+| blockModules | `string[]` | `[]` | Do not transform components from these imported modules. |
### CLI Options
diff --git a/__tests__/custom-tailwindcss/platform-prefixes.ts b/__tests__/custom-tailwindcss/platform-prefixes.ts
new file mode 100644
index 0000000..5232bd9
--- /dev/null
+++ b/__tests__/custom-tailwindcss/platform-prefixes.ts
@@ -0,0 +1,80 @@
+import { tailwindRunner } from "../tailwindcss/runner";
+
+tailwindRunner("Platform Prefixes", [
+ [
+ "ios:w-px",
+ {
+ styles: {
+ "ios_w-px_0": { width: 1 },
+ },
+ media: {
+ "ios_w-px": [["ios", 0]],
+ },
+ },
+ ],
+ [
+ "android:w-px",
+ {
+ styles: {
+ "android_w-px_0": { width: 1 },
+ },
+ media: {
+ "android_w-px": [["android", 0]],
+ },
+ },
+ ],
+ [
+ "windows:w-px",
+ {
+ styles: {
+ "windows_w-px_0": { width: 1 },
+ },
+ media: {
+ "windows_w-px": [["windows", 0]],
+ },
+ },
+ ],
+ [
+ "macos:w-px",
+ {
+ styles: {
+ "macos_w-px_0": { width: 1 },
+ },
+ media: {
+ "macos_w-px": [["macos", 0]],
+ },
+ },
+ ],
+ [
+ "web:w-px",
+ {
+ styles: {
+ "web_w-px_0": { width: 1 },
+ },
+ media: {
+ "web_w-px": [["web-inline", 0]],
+ },
+ },
+ ],
+ [
+ "native:w-px",
+ {
+ styles: {
+ "native_w-px_0": { width: 1 },
+ "native_w-px_1": { width: 1 },
+ "native_w-px_2": { width: 1 },
+ "native_w-px_3": { width: 1 },
+ "native_w-px_4": { width: 1 },
+ },
+ media: {
+ "native_w-px": [
+ ["native", 0],
+ ["android", 1],
+ ["ios", 2],
+ ["windows", 3],
+ ["macos", 4],
+ ],
+ },
+ },
+ ],
+]);
diff --git a/__tests__/tailwindcss/runner.ts b/__tests__/tailwindcss/runner.ts
index 8faccce..9ce1966 100644
--- a/__tests__/tailwindcss/runner.ts
+++ b/__tests__/tailwindcss/runner.ts
@@ -1,9 +1,9 @@
-import { getNativeTailwindConfig } from "../../src/babel/tailwind/native-config";
import { extractStyles } from "../../src/babel/native-style-extraction";
import { normaliseSelector } from "../../src/shared/selector";
import { MediaRecord, StyleRecord } from "../../src/types/common";
-const nativeConfig = getNativeTailwindConfig();
+import plugin from "../../src/plugin";
+import { nativePlugin } from "../../src/plugin/native";
export type Test = [string, Expected];
@@ -22,23 +22,16 @@ export function tailwindRunner(name: string, testCases: Test[]) {
});
}
-export function assertStyles(
- css: string,
- { styles: expectedStyles, media: expectedMedia }: Expected
-) {
- const { styles, media } = extractStyles({
+export function assertStyles(css: string, { styles, media = {} }: Expected) {
+ const output = extractStyles({
theme: {},
- ...nativeConfig,
+ plugins: [plugin, nativePlugin()],
// eslint-disable-next-line @typescript-eslint/no-explicit-any
content: [{ raw: "", extension: "html" } as any],
safelist: [css],
});
- expect(styles).toEqual(expectedStyles);
-
- if (expectedMedia) {
- expect(media).toEqual(expectedMedia);
- }
+ expect(output).toEqual({ styles, media });
}
/**
diff --git a/plugin.js b/plugin.js
new file mode 100644
index 0000000..572666d
--- /dev/null
+++ b/plugin.js
@@ -0,0 +1 @@
+module.exports = require("./dist/plugin").default;
diff --git a/src/babel/tailwind/get-tailwind-config.ts b/src/babel/tailwind/get-tailwind-config.ts
index d741a69..7756130 100644
--- a/src/babel/tailwind/get-tailwind-config.ts
+++ b/src/babel/tailwind/get-tailwind-config.ts
@@ -4,7 +4,7 @@ import { existsSync } from "node:fs";
import resolveTailwindConfig from "tailwindcss/resolveConfig";
import { TailwindConfig } from "tailwindcss/tailwind-config";
-import { getNativeTailwindConfig } from "./native-config";
+import { nativePlugin } from "../../plugin/native";
export interface GetTailwindConfigOptions {
rem?: number;
@@ -33,16 +33,9 @@ export function getTailwindConfig(
userConfig = {};
}
- const nativeConfig = getNativeTailwindConfig(options);
-
const mergedConfig = {
- ...nativeConfig,
...userConfig,
- theme: {
- ...nativeConfig.theme,
- ...userConfig.theme,
- },
- plugins: [...(nativeConfig.plugins ?? []), ...(userConfig.plugins ?? [])],
+ plugins: [nativePlugin(options), ...(userConfig.plugins ?? [])],
};
return resolveTailwindConfig(mergedConfig);
diff --git a/src/babel/tailwind/native-config.ts b/src/babel/tailwind/native-config.ts
deleted file mode 100644
index 907ed6e..0000000
--- a/src/babel/tailwind/native-config.ts
+++ /dev/null
@@ -1,248 +0,0 @@
-import { TailwindConfig } from "tailwindcss/tailwind-config";
-import { nativePlugin } from "./native-plugin";
-
-export interface GetNativeTailwindConfigOptions {
- rem?: number;
-}
-
-export function getNativeTailwindConfig({
- rem = 16,
-}: GetNativeTailwindConfigOptions = {}) {
- const config: Partial = {
- plugins: [nativePlugin],
- corePlugins: {
- accentColor: false,
- accessibility: false,
- animation: false,
- appearance: false,
- aspectRatio: false,
- backdropBlur: false,
- backdropBrightness: false,
- backdropContrast: false,
- backdropFilter: false,
- backdropGrayscale: false,
- backdropHueRotate: false,
- backdropInvert: false,
- backdropOpacity: false,
- backdropSaturate: false,
- backdropSepia: false,
- backgroundAttachment: false,
- backgroundBlendMode: false,
- backgroundClip: false,
- backgroundImage: false,
- backgroundOrigin: false,
- backgroundPosition: false,
- backgroundRepeat: false,
- backgroundSize: false,
- blur: false,
- borderCollapse: false,
- boxDecorationBreak: false,
- boxShadow: false,
- boxSizing: false,
- breakAfter: false,
- breakBefore: false,
- breakInside: false,
- brightness: false,
- caretColor: false,
- clear: false,
- columns: false,
- content: false,
- contrast: false,
- cursor: false,
- divideColor: false,
- divideOpacity: false,
- divideStyle: false,
- divideWidth: false,
- dropShadow: false,
- fill: false,
- filter: false,
- float: false,
- fontSmoothing: false,
- gap: false,
- gradientColorStops: false,
- grayscale: false,
- gridAutoColumns: false,
- gridAutoFlow: false,
- gridAutoRows: false,
- gridColumn: false,
- gridColumnEnd: false,
- gridColumnStart: false,
- gridRow: false,
- gridRowEnd: false,
- gridRowStart: false,
- gridTemplateColumns: false,
- gridTemplateRows: false,
- hueRotate: false,
- invert: false,
- isolation: false,
- justifyItems: false,
- justifySelf: false,
- listStylePosition: false,
- listStyleType: false,
- mixBlendMode: false,
- objectFit: false,
- objectPosition: false,
- order: false,
- overscrollBehavior: false,
- placeItems: false,
- placeSelf: false,
- placeholderColor: false,
- placeholderOpacity: false,
- preflight: false,
- resize: false,
- ringColor: false,
- ringOffsetColor: false,
- ringOffsetWidth: false,
- ringOpacity: false,
- ringWidth: false,
- rotate: false,
- saturate: false,
- scale: false,
- scrollBehavior: false,
- scrollMargin: false,
- scrollPadding: false,
- scrollSnapAlign: false,
- scrollSnapStop: false,
- scrollSnapType: false,
- sepia: false,
- skew: false,
- space: false,
- stroke: false,
- strokeWidth: false,
- tableLayout: false,
- textIndent: false,
- textOverflow: false,
- touchAction: false,
- transform: false,
- transformOrigin: false,
- transitionDelay: false,
- transitionDuration: false,
- transitionProperty: false,
- transitionTimingFunction: false,
- translate: false,
- userSelect: false,
- verticalAlign: false,
- visibility: false,
- whitespace: false,
- willChange: false,
- wordBreak: false,
- },
- theme: {
- aspectRatio: {
- auto: "0",
- square: "1",
- video: "1.777777778",
- },
- letterSpacing: {
- tighter: "-0.5px",
- tight: "-0.25px",
- normal: "0px",
- wide: "0.25px",
- wider: "0.5px",
- widest: "1px",
- },
- spacing: {
- px: "1px",
- 0: "0px",
- 0.5: `${rem * 0.125}px`,
- 1: `${rem * 0.25}px`,
- 1.5: `${rem * 0.375}px`,
- 2: `${rem * 0.5}px`,
- 2.5: `${rem * 0.625}px`,
- 3: `${rem * 0.75}px`,
- 3.5: `${rem * 0.875}px`,
- 4: `${rem * 1}px`,
- 5: `${rem * 1.25}px`,
- 6: `${rem * 1.5}px`,
- 7: `${rem * 1.75}px`,
- 8: `${rem * 2}px`,
- 9: `${rem * 2.25}px`,
- 10: `${rem * 2.5}px`,
- 11: `${rem * 2.75}px`,
- 12: `${rem * 3}px`,
- 14: `${rem * 3.5}px`,
- 16: `${rem * 4}px`,
- 20: `${rem * 5}px`,
- 24: `${rem * 6}px`,
- 28: `${rem * 7}px`,
- 32: `${rem * 8}px`,
- 36: `${rem * 9}px`,
- 40: `${rem * 10}px`,
- 44: `${rem * 11}px`,
- 48: `${rem * 12}px`,
- 52: `${rem * 13}px`,
- 56: `${rem * 14}px`,
- 60: `${rem * 15}px`,
- 64: `${rem * 16}px`,
- 72: `${rem * 18}px`,
- 80: `${rem * 20}px`,
- 96: `${rem * 24}px`,
- },
- borderRadius: {
- none: "0px",
- sm: `${rem * 0.125}px`,
- DEFAULT: `${rem * 0.25}px`,
- md: `${rem * 0.375}px`,
- lg: `${rem * 0.5}px`,
- xl: `${rem * 0.75}px`,
- "2xl": `${rem * 1}px`,
- "3xl": `${rem * 1.5}px`,
- full: "9999px",
- },
- fontSize: {
- xs: [`${rem * 0.75}px`, { lineHeight: `${rem * 1}px` }],
- sm: [`${rem * 0.875}px`, { lineHeight: `${rem * 1.25}px` }],
- base: [`${rem * 1}px`, { lineHeight: `${rem * 1.5}px` }],
- lg: [`${rem * 1.125}px`, { lineHeight: `${rem * 1.75}px` }],
- xl: [`${rem * 1.25}px`, { lineHeight: `${rem * 1.75}px` }],
- "2xl": [`${rem * 1.5}px`, { lineHeight: `${rem * 2}px` }],
- "3xl": [`${rem * 1.875}px`, { lineHeight: `${rem * 2.25}px` }],
- "4xl": [`${rem * 2.25}px`, { lineHeight: `${rem * 2.5}px` }],
- "5xl": [`${rem * 3}px`, { lineHeight: "1" }],
- "6xl": [`${rem * 3.75}px`, { lineHeight: "1" }],
- "7xl": [`${rem * 4.5}px`, { lineHeight: "1" }],
- "8xl": [`${rem * 6}px`, { lineHeight: "1" }],
- "9xl": [`${rem * 8}px`, { lineHeight: "1" }],
- },
- lineHeight: {
- none: "1",
- tight: "1.25",
- snug: "1.375",
- normal: "1.5",
- relaxed: "1.625",
- loose: "2",
- 3: `${rem * 0.75}px`,
- 4: `${rem * 1}px`,
- 5: `${rem * 1.25}px`,
- 6: `${rem * 1.5}px`,
- 7: `${rem * 1.75}px`,
- 8: `${rem * 2}px`,
- 9: `${rem * 2.25}px`,
- 10: `${rem * 2.5}px`,
- },
- maxWidth: ({ theme, breakpoints }) => ({
- none: "none",
- 0: `${rem * 0}px`,
- xs: `${rem * 20}px`,
- sm: `${rem * 24}px`,
- md: `${rem * 28}px`,
- lg: `${rem * 32}px`,
- xl: `${rem * 36}px`,
- "2xl": `${rem * 42}px`,
- "3xl": `${rem * 48}px`,
- "4xl": `${rem * 56}px`,
- "5xl": `${rem * 64}px`,
- "6xl": `${rem * 72}px`,
- "7xl": `${rem * 80}px`,
- full: "100%",
- min: "min-content",
- max: "max-content",
- fit: "fit-content",
- prose: "65ch",
- ...breakpoints(theme("screens")),
- }),
- },
- };
-
- return config;
-}
diff --git a/src/babel/tailwind/native-plugin.ts b/src/babel/tailwind/native-plugin.ts
deleted file mode 100644
index 2b29b21..0000000
--- a/src/babel/tailwind/native-plugin.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-import plugin from "tailwindcss/plugin";
-
-export const nativePlugin = plugin(function ({
- addVariant,
- matchUtilities,
- theme,
-}) {
- addVariant("native", "@media native");
- addVariant("ios", "");
- addVariant("android", "");
-
- matchUtilities(
- {
- aspect: (value: string) => {
- let aspectRatio = value;
-
- if (value.includes("/")) {
- const [left, right] = value.split("/").map((n) => {
- return Number.parseInt(n, 10);
- });
-
- aspectRatio = `${left / right}`;
- }
-
- return {
- aspectRatio,
- };
- },
- },
- { values: theme("aspectRatio") }
- );
-});
diff --git a/src/babel/utils/get-import-blocked-components.ts b/src/babel/utils/get-import-blocked-components.ts
index 236698e..82c14df 100644
--- a/src/babel/utils/get-import-blocked-components.ts
+++ b/src/babel/utils/get-import-blocked-components.ts
@@ -6,9 +6,10 @@ import micromatch from "micromatch";
import { NodePath } from "@babel/core";
import { ImportDeclaration } from "@babel/types";
import { VisitorState } from "../visitor";
+import { platforms } from "../../shared/platforms";
const allowedIndexFiles: string[] = [];
-for (const platform of ["android", "ios", "native", "web", "windows"]) {
+for (const platform of platforms) {
for (const extension of ["js", "jsx", "ts", "tsx"]) {
allowedIndexFiles.push(`index.${platform}.${extension}`);
}
diff --git a/src/context.ts b/src/context.ts
index e30881d..608f336 100644
--- a/src/context.ts
+++ b/src/context.ts
@@ -1,6 +1,7 @@
import { createContext } from "react";
-import { Appearance, ColorSchemeName, Platform } from "react-native";
+import { Appearance, ColorSchemeName } from "react-native";
import { MediaRecord, StyleRecord } from "./types/common";
+import { Platform } from "./shared/platforms";
declare global {
// eslint-disable-next-line no-var
@@ -27,6 +28,6 @@ export const TailwindSetColorSchemeContext = createContext<
>(() => {
return;
});
-export const TailwindPlatformContext = createContext<
- typeof Platform.OS | "native" | undefined
->(undefined);
+export const TailwindPlatformContext = createContext(
+ undefined
+);
diff --git a/src/plugin/index.ts b/src/plugin/index.ts
new file mode 100644
index 0000000..3b328a3
--- /dev/null
+++ b/src/plugin/index.ts
@@ -0,0 +1,15 @@
+import plugin from "tailwindcss/plugin";
+import { platforms, nativePlatforms } from "../shared/platforms";
+
+export default plugin(function ({ addVariant }) {
+ for (const platform of platforms) {
+ addVariant(platform, `@media ${platform}`);
+ }
+
+ addVariant(
+ "native",
+ nativePlatforms.map((platform) => `@media ${platform}`)
+ );
+
+ addVariant("web", "@media web-inline");
+});
diff --git a/src/plugin/native.ts b/src/plugin/native.ts
new file mode 100644
index 0000000..6530034
--- /dev/null
+++ b/src/plugin/native.ts
@@ -0,0 +1,271 @@
+import plugin from "tailwindcss/plugin";
+import { TailwindConfig } from "tailwindcss/tailwind-config";
+
+export interface NativePluginOptions {
+ rem?: number;
+}
+
+export const nativePlugin = plugin.withOptions(
+ function () {
+ return ({ matchUtilities, theme }) => {
+ matchUtilities(
+ {
+ aspect: (value: string) => {
+ let aspectRatio = value;
+
+ if (value.includes("/")) {
+ const [left, right] = value.split("/").map((n) => {
+ return Number.parseInt(n, 10);
+ });
+
+ aspectRatio = `${left / right}`;
+ }
+
+ return {
+ aspectRatio,
+ };
+ },
+ },
+ { values: theme("aspectRatio") }
+ );
+ };
+ },
+ function ({ rem = 16 } = {}) {
+ const config: Partial = {
+ corePlugins: {
+ accentColor: false,
+ accessibility: false,
+ animation: false,
+ appearance: false,
+ aspectRatio: false,
+ backdropBlur: false,
+ backdropBrightness: false,
+ backdropContrast: false,
+ backdropFilter: false,
+ backdropGrayscale: false,
+ backdropHueRotate: false,
+ backdropInvert: false,
+ backdropOpacity: false,
+ backdropSaturate: false,
+ backdropSepia: false,
+ backgroundAttachment: false,
+ backgroundBlendMode: false,
+ backgroundClip: false,
+ backgroundImage: false,
+ backgroundOrigin: false,
+ backgroundPosition: false,
+ backgroundRepeat: false,
+ backgroundSize: false,
+ blur: false,
+ borderCollapse: false,
+ boxDecorationBreak: false,
+ boxShadow: false,
+ boxSizing: false,
+ breakAfter: false,
+ breakBefore: false,
+ breakInside: false,
+ brightness: false,
+ caretColor: false,
+ clear: false,
+ columns: false,
+ content: false,
+ contrast: false,
+ cursor: false,
+ divideColor: false,
+ divideOpacity: false,
+ divideStyle: false,
+ divideWidth: false,
+ dropShadow: false,
+ fill: false,
+ filter: false,
+ float: false,
+ fontSmoothing: false,
+ gap: false,
+ gradientColorStops: false,
+ grayscale: false,
+ gridAutoColumns: false,
+ gridAutoFlow: false,
+ gridAutoRows: false,
+ gridColumn: false,
+ gridColumnEnd: false,
+ gridColumnStart: false,
+ gridRow: false,
+ gridRowEnd: false,
+ gridRowStart: false,
+ gridTemplateColumns: false,
+ gridTemplateRows: false,
+ hueRotate: false,
+ invert: false,
+ isolation: false,
+ justifyItems: false,
+ justifySelf: false,
+ listStylePosition: false,
+ listStyleType: false,
+ mixBlendMode: false,
+ objectFit: false,
+ objectPosition: false,
+ order: false,
+ overscrollBehavior: false,
+ placeItems: false,
+ placeSelf: false,
+ placeholderColor: false,
+ placeholderOpacity: false,
+ preflight: false,
+ resize: false,
+ ringColor: false,
+ ringOffsetColor: false,
+ ringOffsetWidth: false,
+ ringOpacity: false,
+ ringWidth: false,
+ rotate: false,
+ saturate: false,
+ scale: false,
+ scrollBehavior: false,
+ scrollMargin: false,
+ scrollPadding: false,
+ scrollSnapAlign: false,
+ scrollSnapStop: false,
+ scrollSnapType: false,
+ sepia: false,
+ skew: false,
+ space: false,
+ stroke: false,
+ strokeWidth: false,
+ tableLayout: false,
+ textIndent: false,
+ textOverflow: false,
+ touchAction: false,
+ transform: false,
+ transformOrigin: false,
+ transitionDelay: false,
+ transitionDuration: false,
+ transitionProperty: false,
+ transitionTimingFunction: false,
+ translate: false,
+ userSelect: false,
+ verticalAlign: false,
+ visibility: false,
+ whitespace: false,
+ willChange: false,
+ wordBreak: false,
+ },
+ theme: {
+ aspectRatio: {
+ auto: "0",
+ square: "1",
+ video: "1.777777778",
+ },
+ letterSpacing: {
+ tighter: "-0.5px",
+ tight: "-0.25px",
+ normal: "0px",
+ wide: "0.25px",
+ wider: "0.5px",
+ widest: "1px",
+ },
+ spacing: {
+ px: "1px",
+ 0: "0px",
+ 0.5: `${rem * 0.125}px`,
+ 1: `${rem * 0.25}px`,
+ 1.5: `${rem * 0.375}px`,
+ 2: `${rem * 0.5}px`,
+ 2.5: `${rem * 0.625}px`,
+ 3: `${rem * 0.75}px`,
+ 3.5: `${rem * 0.875}px`,
+ 4: `${rem * 1}px`,
+ 5: `${rem * 1.25}px`,
+ 6: `${rem * 1.5}px`,
+ 7: `${rem * 1.75}px`,
+ 8: `${rem * 2}px`,
+ 9: `${rem * 2.25}px`,
+ 10: `${rem * 2.5}px`,
+ 11: `${rem * 2.75}px`,
+ 12: `${rem * 3}px`,
+ 14: `${rem * 3.5}px`,
+ 16: `${rem * 4}px`,
+ 20: `${rem * 5}px`,
+ 24: `${rem * 6}px`,
+ 28: `${rem * 7}px`,
+ 32: `${rem * 8}px`,
+ 36: `${rem * 9}px`,
+ 40: `${rem * 10}px`,
+ 44: `${rem * 11}px`,
+ 48: `${rem * 12}px`,
+ 52: `${rem * 13}px`,
+ 56: `${rem * 14}px`,
+ 60: `${rem * 15}px`,
+ 64: `${rem * 16}px`,
+ 72: `${rem * 18}px`,
+ 80: `${rem * 20}px`,
+ 96: `${rem * 24}px`,
+ },
+ borderRadius: {
+ none: "0px",
+ sm: `${rem * 0.125}px`,
+ DEFAULT: `${rem * 0.25}px`,
+ md: `${rem * 0.375}px`,
+ lg: `${rem * 0.5}px`,
+ xl: `${rem * 0.75}px`,
+ "2xl": `${rem * 1}px`,
+ "3xl": `${rem * 1.5}px`,
+ full: "9999px",
+ },
+ fontSize: {
+ xs: [`${rem * 0.75}px`, { lineHeight: `${rem * 1}px` }],
+ sm: [`${rem * 0.875}px`, { lineHeight: `${rem * 1.25}px` }],
+ base: [`${rem * 1}px`, { lineHeight: `${rem * 1.5}px` }],
+ lg: [`${rem * 1.125}px`, { lineHeight: `${rem * 1.75}px` }],
+ xl: [`${rem * 1.25}px`, { lineHeight: `${rem * 1.75}px` }],
+ "2xl": [`${rem * 1.5}px`, { lineHeight: `${rem * 2}px` }],
+ "3xl": [`${rem * 1.875}px`, { lineHeight: `${rem * 2.25}px` }],
+ "4xl": [`${rem * 2.25}px`, { lineHeight: `${rem * 2.5}px` }],
+ "5xl": [`${rem * 3}px`, { lineHeight: "1" }],
+ "6xl": [`${rem * 3.75}px`, { lineHeight: "1" }],
+ "7xl": [`${rem * 4.5}px`, { lineHeight: "1" }],
+ "8xl": [`${rem * 6}px`, { lineHeight: "1" }],
+ "9xl": [`${rem * 8}px`, { lineHeight: "1" }],
+ },
+ lineHeight: {
+ none: "1",
+ tight: "1.25",
+ snug: "1.375",
+ normal: "1.5",
+ relaxed: "1.625",
+ loose: "2",
+ 3: `${rem * 0.75}px`,
+ 4: `${rem * 1}px`,
+ 5: `${rem * 1.25}px`,
+ 6: `${rem * 1.5}px`,
+ 7: `${rem * 1.75}px`,
+ 8: `${rem * 2}px`,
+ 9: `${rem * 2.25}px`,
+ 10: `${rem * 2.5}px`,
+ },
+ maxWidth: ({ theme, breakpoints }) => ({
+ none: "none",
+ 0: `${rem * 0}px`,
+ xs: `${rem * 20}px`,
+ sm: `${rem * 24}px`,
+ md: `${rem * 28}px`,
+ lg: `${rem * 32}px`,
+ xl: `${rem * 36}px`,
+ "2xl": `${rem * 42}px`,
+ "3xl": `${rem * 48}px`,
+ "4xl": `${rem * 56}px`,
+ "5xl": `${rem * 64}px`,
+ "6xl": `${rem * 72}px`,
+ "7xl": `${rem * 80}px`,
+ full: "100%",
+ min: "min-content",
+ max: "max-content",
+ fit: "fit-content",
+ prose: "65ch",
+ ...breakpoints(theme("screens")),
+ }),
+ },
+ };
+
+ return config;
+ }
+);
diff --git a/src/shared/platforms.ts b/src/shared/platforms.ts
new file mode 100644
index 0000000..deaa8e7
--- /dev/null
+++ b/src/shared/platforms.ts
@@ -0,0 +1,21 @@
+import { Platform } from "react-native";
+
+export type Platform = typeof Platform.OS | "native" | "web-inline";
+
+export const platforms: Platform[] = [
+ "android",
+ "ios",
+ "web",
+ "native",
+ "windows",
+ "macos",
+ "web-inline",
+];
+
+export const nativePlatforms: Platform[] = [
+ "native",
+ "android",
+ "ios",
+ "windows",
+ "macos",
+];