@colimuca123/nativewind 4.2.2-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. package/LICENSE +21 -0
  2. package/README.OpenSource +11 -0
  3. package/babel.js +1 -0
  4. package/dist/doctor.d.ts +1 -0
  5. package/dist/doctor.js +21 -0
  6. package/dist/doctor.js.map +1 -0
  7. package/dist/index.d.ts +4 -0
  8. package/dist/index.js +20 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/metro/common.d.ts +4 -0
  11. package/dist/metro/common.js +8 -0
  12. package/dist/metro/common.js.map +1 -0
  13. package/dist/metro/index.d.ts +15 -0
  14. package/dist/metro/index.js +47 -0
  15. package/dist/metro/index.js.map +1 -0
  16. package/dist/metro/picocolors.d.ts +26 -0
  17. package/dist/metro/picocolors.js +53 -0
  18. package/dist/metro/picocolors.js.map +1 -0
  19. package/dist/metro/tailwind/index.d.ts +5 -0
  20. package/dist/metro/tailwind/index.js +25 -0
  21. package/dist/metro/tailwind/index.js.map +1 -0
  22. package/dist/metro/tailwind/types.d.ts +8 -0
  23. package/dist/metro/tailwind/types.js +3 -0
  24. package/dist/metro/tailwind/types.js.map +1 -0
  25. package/dist/metro/tailwind/v3/child.d.ts +0 -0
  26. package/dist/metro/tailwind/v3/child.js +45 -0
  27. package/dist/metro/tailwind/v3/child.js.map +1 -0
  28. package/dist/metro/tailwind/v3/index.d.ts +6 -0
  29. package/dist/metro/tailwind/v3/index.js +81 -0
  30. package/dist/metro/tailwind/v3/index.js.map +1 -0
  31. package/dist/metro/typescript.d.ts +1 -0
  32. package/dist/metro/typescript.js +46 -0
  33. package/dist/metro/typescript.js.map +1 -0
  34. package/dist/stylesheet.d.ts +5 -0
  35. package/dist/stylesheet.js +25 -0
  36. package/dist/stylesheet.js.map +1 -0
  37. package/dist/tailwind/color.d.ts +4 -0
  38. package/dist/tailwind/color.js +25 -0
  39. package/dist/tailwind/color.js.map +1 -0
  40. package/dist/tailwind/common.d.ts +2 -0
  41. package/dist/tailwind/common.js +24 -0
  42. package/dist/tailwind/common.js.map +1 -0
  43. package/dist/tailwind/dark-mode.d.ts +4 -0
  44. package/dist/tailwind/dark-mode.js +48 -0
  45. package/dist/tailwind/dark-mode.js.map +1 -0
  46. package/dist/tailwind/index.d.ts +0 -0
  47. package/dist/tailwind/index.js +13 -0
  48. package/dist/tailwind/index.js.map +1 -0
  49. package/dist/tailwind/native.d.ts +3 -0
  50. package/dist/tailwind/native.js +265 -0
  51. package/dist/tailwind/native.js.map +1 -0
  52. package/dist/tailwind/prop-modifier.d.ts +4 -0
  53. package/dist/tailwind/prop-modifier.js +13 -0
  54. package/dist/tailwind/prop-modifier.js.map +1 -0
  55. package/dist/tailwind/safe-area.d.ts +4 -0
  56. package/dist/tailwind/safe-area.js +216 -0
  57. package/dist/tailwind/safe-area.js.map +1 -0
  58. package/dist/tailwind/shadows.d.ts +4 -0
  59. package/dist/tailwind/shadows.js +79 -0
  60. package/dist/tailwind/shadows.js.map +1 -0
  61. package/dist/tailwind/switch.d.ts +8 -0
  62. package/dist/tailwind/switch.js +51 -0
  63. package/dist/tailwind/switch.js.map +1 -0
  64. package/dist/tailwind/translate.d.ts +2 -0
  65. package/dist/tailwind/translate.js +40 -0
  66. package/dist/tailwind/translate.js.map +1 -0
  67. package/dist/tailwind/verify.d.ts +4 -0
  68. package/dist/tailwind/verify.js +22 -0
  69. package/dist/tailwind/verify.js.map +1 -0
  70. package/dist/tailwind/web.d.ts +3 -0
  71. package/dist/tailwind/web.js +40 -0
  72. package/dist/tailwind/web.js.map +1 -0
  73. package/dist/test.d.ts +373 -0
  74. package/dist/test.js +161 -0
  75. package/dist/test.js.map +1 -0
  76. package/dist/theme.d.ts +1 -0
  77. package/dist/theme.js +9 -0
  78. package/dist/theme.js.map +1 -0
  79. package/expo-snack.js +71 -0
  80. package/jsx-dev-runtime/index.d.ts +1 -0
  81. package/jsx-dev-runtime/index.js +1 -0
  82. package/jsx-runtime/index.d.ts +1 -0
  83. package/jsx-runtime/index.js +1 -0
  84. package/metro/package.json +1 -0
  85. package/package.json +75 -0
  86. package/preset/package.json +3 -0
  87. package/src/__tests__/README.md +3 -0
  88. package/src/__tests__/accessibility.tsx +41 -0
  89. package/src/__tests__/backgrounds.tsx +239 -0
  90. package/src/__tests__/borders.tsx +355 -0
  91. package/src/__tests__/container-queries.tsx +59 -0
  92. package/src/__tests__/custom-theme.tsx +45 -0
  93. package/src/__tests__/custom.tsx +17 -0
  94. package/src/__tests__/dark-mode.ios.tsx +251 -0
  95. package/src/__tests__/doctor.tsx +13 -0
  96. package/src/__tests__/effects.ios.tsx +230 -0
  97. package/src/__tests__/elevation.tsx +22 -0
  98. package/src/__tests__/filters.tsx +201 -0
  99. package/src/__tests__/flexbox-grid.tsx +670 -0
  100. package/src/__tests__/groups.tsx +134 -0
  101. package/src/__tests__/interactivity.tsx +547 -0
  102. package/src/__tests__/layout.tsx +854 -0
  103. package/src/__tests__/modifier-{}.tsx +71 -0
  104. package/src/__tests__/platform-modifiers-test.ios.tsx +34 -0
  105. package/src/__tests__/preset.tsx +9 -0
  106. package/src/__tests__/reusing-styles.tsx +44 -0
  107. package/src/__tests__/safe-area.test.ios.tsx +427 -0
  108. package/src/__tests__/sizing.tsx +241 -0
  109. package/src/__tests__/spacing.tsx +106 -0
  110. package/src/__tests__/states.tsx +145 -0
  111. package/src/__tests__/svg.tsx +25 -0
  112. package/src/__tests__/tables.tsx +103 -0
  113. package/src/__tests__/theme.tsx +245 -0
  114. package/src/__tests__/transforms.tsx +509 -0
  115. package/src/__tests__/transition-animations.tsx +254 -0
  116. package/src/__tests__/typography.tsx +657 -0
  117. package/src/__tests__/unofficial-plugins.test.ios.tsx +171 -0
  118. package/src/doctor.ts +28 -0
  119. package/src/index.tsx +16 -0
  120. package/src/metro/common.ts +11 -0
  121. package/src/metro/index.ts +77 -0
  122. package/src/metro/picocolors.ts +76 -0
  123. package/src/metro/tailwind/index.ts +22 -0
  124. package/src/metro/tailwind/types.ts +9 -0
  125. package/src/metro/tailwind/v3/child.ts +61 -0
  126. package/src/metro/tailwind/v3/index.ts +103 -0
  127. package/src/metro/typescript.ts +69 -0
  128. package/src/stylesheet.ts +31 -0
  129. package/src/tailwind/color.ts +23 -0
  130. package/src/tailwind/common.ts +26 -0
  131. package/src/tailwind/dark-mode.ts +46 -0
  132. package/src/tailwind/index.ts +15 -0
  133. package/src/tailwind/native.ts +374 -0
  134. package/src/tailwind/prop-modifier.ts +7 -0
  135. package/src/tailwind/safe-area.ts +262 -0
  136. package/src/tailwind/shadows.ts +100 -0
  137. package/src/tailwind/switch.ts +59 -0
  138. package/src/tailwind/translate.ts +51 -0
  139. package/src/tailwind/verify.ts +16 -0
  140. package/src/tailwind/web.ts +38 -0
  141. package/src/tailwindcss-internals.d.ts +7 -0
  142. package/src/test.tsx +224 -0
  143. package/src/theme.ts +15 -0
  144. package/test/package.json +4 -0
  145. package/theme/package.json +3 -0
  146. package/types.d.ts +1 -0
@@ -0,0 +1,171 @@
1
+ /** @jsxImportSource nativewind */
2
+
3
+ /**
4
+ * This file has some examples of unofficial plugins used by the community.
5
+ *
6
+ * They are not officially supported by NativeWind
7
+ */
8
+
9
+ import { Text, View } from "react-native";
10
+
11
+ import flattenColorPalette from "tailwindcss/lib/util/flattenColorPalette";
12
+ import plugin from "tailwindcss/plugin";
13
+
14
+ import { render, screen } from "../test";
15
+
16
+ const testID = "nativewind";
17
+
18
+ test("tw-colors", async () => {
19
+ const { createThemes } = require("tw-colors");
20
+
21
+ // Render will inject data
22
+ await render(
23
+ <View className="theme-light">
24
+ <View testID={testID} className="text-primary" />
25
+ </View>,
26
+ {
27
+ config: {
28
+ plugins: [
29
+ createThemes(
30
+ {
31
+ light: {
32
+ primary: "red",
33
+ },
34
+ dark: {
35
+ primary: "blue",
36
+ },
37
+ },
38
+ {
39
+ produceThemeClass: (themeName: string) => `theme-${themeName}`,
40
+ },
41
+ ),
42
+ ],
43
+ },
44
+ },
45
+ );
46
+
47
+ expect(screen.getByTestId(testID)).toHaveStyle({
48
+ color: "hsla(0, 100%, 50%, 1)",
49
+ });
50
+
51
+ screen.rerender(
52
+ <View className="theme-dark">
53
+ <View testID={testID} className="text-primary" />
54
+ </View>,
55
+ );
56
+
57
+ expect(screen.getByTestId(testID)).toHaveStyle({
58
+ color: "hsla(240, 100%, 50%, 1)",
59
+ });
60
+ });
61
+
62
+ test("text-shadow", async () => {
63
+ const textShadowPlugin = plugin(
64
+ function ({ addBase, matchUtilities, matchComponents, theme }: any) {
65
+ addBase({
66
+ ":root": {
67
+ "--ts-text-shadow-color": "rgba(0, 0,0,0.50)",
68
+ "--ts-text-shadow-x": "1px",
69
+ "--ts-text-shadow-y": "1px",
70
+ "--ts-text-shadow-blur": "2px",
71
+ },
72
+ });
73
+
74
+ matchUtilities(
75
+ {
76
+ [`text-shadow-x`]: (value: Record<string, string>) => ({
77
+ "--ts-text-shadow-x": value,
78
+ }),
79
+ [`text-shadow-y`]: (value: Record<string, string>) => ({
80
+ "--ts-text-shadow-y": value,
81
+ }),
82
+ [`text-shadow-blur`]: (value: Record<string, string>) => ({
83
+ "--ts-text-shadow-blur": value,
84
+ }),
85
+ },
86
+ {
87
+ values: theme("textShadowSteps"),
88
+ type: "length",
89
+ supportsNegativeValues: true,
90
+ },
91
+ );
92
+
93
+ matchUtilities(
94
+ {
95
+ [`text-shadow`]: (value: Record<string, string>) => ({
96
+ "--ts-text-shadow-color": value,
97
+ }),
98
+ },
99
+ {
100
+ values: flattenColorPalette(theme("colors")),
101
+ type: "color",
102
+ },
103
+ );
104
+
105
+ matchComponents(
106
+ {
107
+ [`text-shadow`]: (value: number) => ({
108
+ textShadow:
109
+ value === 1
110
+ ? `var(--ts-text-shadow-x) var(--ts-text-shadow-y) var(--ts-text-shadow-blur) var(--ts-text-shadow-color)`
111
+ : `calc(var(--ts-text-shadow-x) * ${value}) calc(var(--ts-text-shadow-y) * ${value}) var(--ts-text-shadow-blur) var(--ts-text-shadow-color)`,
112
+ }),
113
+ },
114
+ {
115
+ type: "number",
116
+ values: theme("textShadowMultiplier"),
117
+ },
118
+ );
119
+ },
120
+ {
121
+ theme: {
122
+ experimental: false,
123
+ textShadowMultiplier: {
124
+ DEFAULT: 1,
125
+ sm: 4,
126
+ md: 8,
127
+ lg: 12,
128
+ xl: 16,
129
+ },
130
+ textShadowSteps: {
131
+ xs: "1px",
132
+ sm: "2px",
133
+ md: "3px",
134
+ lg: "4px",
135
+ xl: "5px",
136
+ 0: "0",
137
+ 1: "1px",
138
+ 2: "2px",
139
+ 3: "3px",
140
+ 4: "4px",
141
+ 5: "5px",
142
+ 6: "6px",
143
+ 7: "7px",
144
+ 8: "8px",
145
+ 9: "9px",
146
+ 10: "10px",
147
+ },
148
+ },
149
+ },
150
+ );
151
+
152
+ await render(
153
+ <Text testID={testID} className="text-shadow-lg text-shadow-red-500" />,
154
+ {
155
+ config: {
156
+ plugins: [textShadowPlugin],
157
+ },
158
+ },
159
+ );
160
+
161
+ const text = screen.getByTestId(testID);
162
+
163
+ expect(text).toHaveStyle({
164
+ textShadowColor: "#ef4444",
165
+ textShadowOffset: {
166
+ height: 12,
167
+ width: 12,
168
+ },
169
+ textShadowRadius: 2,
170
+ });
171
+ });
package/src/doctor.ts ADDED
@@ -0,0 +1,28 @@
1
+ import { verifyData, verifyFlag, verifyJSX } from "react-native-css-interop";
2
+
3
+ export function verifyInstallation() {
4
+ if (process.env.NODE_ENV !== "development") {
5
+ console.warn(
6
+ "verifyInstallation() was called in a non-development environment()",
7
+ );
8
+ }
9
+
10
+ if (!verifyJSX()) {
11
+ throw new Error(
12
+ "jsxImportSource was not set to 'nativewind'. Please refer to http://nativewind.dev/troubleshooting#jsxImportSource",
13
+ );
14
+ }
15
+ if (!verifyData()) {
16
+ throw new Error(
17
+ "Nativewind received no data. Please refer to http://nativewind.dev/troubleshooting#no-data",
18
+ );
19
+ }
20
+ if (!verifyFlag("nativewind")) {
21
+ throw new Error(
22
+ "Nativewind: was unable to detect the 'nativewind/preset'. Please refer to http://nativewind.dev/troubleshooting#tailwind-preset",
23
+ );
24
+ }
25
+
26
+ console.log("NativeWind verifyInstallation() found no errors");
27
+ return true;
28
+ }
package/src/index.tsx ADDED
@@ -0,0 +1,16 @@
1
+ export { verifyInstallation } from "./doctor";
2
+
3
+ export {
4
+ StyleSheet,
5
+ colorScheme,
6
+ createInteropElement,
7
+ cssInterop,
8
+ rem,
9
+ remapProps,
10
+ useSafeAreaEnv,
11
+ useUnstableNativeVariable,
12
+ vars,
13
+ } from "react-native-css-interop";
14
+
15
+ export { useColorScheme } from "./stylesheet";
16
+ export { createElement } from "react";
@@ -0,0 +1,11 @@
1
+ // This is separated so it can be used in tests
2
+ // Importing `withTailwind` will cause Jest to fail
3
+ export const cssToReactNativeRuntimeOptions = {
4
+ /*
5
+ * Ignore all warnings from `--tw` variables.
6
+ * These are set by a number of Tailwind classes (and by @base) and
7
+ * will flood the user with invalid warnings
8
+ */
9
+ ignorePropertyWarningRegex: ["^--tw-"],
10
+ grouping: ["^group(/.*)?"],
11
+ };
@@ -0,0 +1,77 @@
1
+ import path from "path";
2
+
3
+ import { debug as debugFn } from "debug";
4
+ import type { MetroConfig } from "metro-config";
5
+ import {
6
+ withCssInterop,
7
+ WithCssInteropOptions,
8
+ } from "react-native-css-interop/metro";
9
+
10
+ import { cssToReactNativeRuntimeOptions } from "./common";
11
+ import { tailwindCli, tailwindConfig } from "./tailwind";
12
+ import { setupTypeScript } from "./typescript";
13
+
14
+ interface WithNativeWindOptions extends WithCssInteropOptions {
15
+ input: string;
16
+ projectRoot?: string;
17
+ outputDir?: string;
18
+ configPath?: string;
19
+ cliCommand?: string;
20
+ browserslist?: string | null;
21
+ browserslistEnv?: string | null;
22
+ typescriptEnvPath?: string;
23
+ disableTypeScriptGeneration?: boolean;
24
+ }
25
+
26
+ const debug = debugFn("nativewind");
27
+
28
+ export function withNativeWind(
29
+ config: MetroConfig,
30
+ {
31
+ input,
32
+ inlineRem = 14,
33
+ configPath: tailwindConfigPath = "tailwind.config",
34
+ browserslist = "last 1 version",
35
+ browserslistEnv = "native",
36
+ typescriptEnvPath = "nativewind-env.d.ts",
37
+ disableTypeScriptGeneration = false,
38
+ ...options
39
+ }: WithNativeWindOptions = {} as WithNativeWindOptions,
40
+ ): MetroConfig {
41
+ if (input) input = path.resolve(input);
42
+
43
+ debug(`input: ${input}`);
44
+
45
+ const { important } = tailwindConfig(path.resolve(tailwindConfigPath));
46
+
47
+ debug(`important: ${important}`);
48
+
49
+ const cli = tailwindCli(debug);
50
+
51
+ if (!disableTypeScriptGeneration) {
52
+ debug(`checking TypeScript setup`);
53
+ setupTypeScript(typescriptEnvPath);
54
+ }
55
+
56
+ return withCssInterop(config, {
57
+ ...cssToReactNativeRuntimeOptions,
58
+ ...options,
59
+ inlineRem,
60
+ selectorPrefix: typeof important === "string" ? important : undefined,
61
+ input,
62
+ parent: {
63
+ name: "nativewind",
64
+ debug: "nativewind",
65
+ },
66
+ getCSSForPlatform: (platform, onChange) => {
67
+ debug(`getCSSForPlatform: ${platform}`);
68
+ return cli.getCSSForPlatform({
69
+ platform,
70
+ input,
71
+ browserslist,
72
+ browserslistEnv,
73
+ onChange,
74
+ });
75
+ },
76
+ });
77
+ }
@@ -0,0 +1,76 @@
1
+ // ISC License
2
+
3
+ // Copyright (c) 2021 Alexey Raspopov, Kostiantyn Denysov, Anton Verinov
4
+
5
+ // Permission to use, copy, modify, and/or distribute this software for any
6
+ // purpose with or without fee is hereby granted, provided that the above
7
+ // copyright notice and this permission notice appear in all copies.
8
+
9
+ // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
+ //
17
+ // https://github.com/alexeyraspopov/picocolors/blob/b6261487e7b81aaab2440e397a356732cad9e342/picocolors.js#L1
18
+
19
+ const { env, stdout } = globalThis?.process ?? {};
20
+
21
+ const enabled =
22
+ env &&
23
+ !env.NO_COLOR &&
24
+ (env.FORCE_COLOR || (stdout?.isTTY && !env.CI && env.TERM !== "dumb"));
25
+
26
+ const replaceClose = (
27
+ str: string,
28
+ close: string,
29
+ replace: string,
30
+ index: number,
31
+ ): string => {
32
+ const start = str.substring(0, index) + replace;
33
+ const end = str.substring(index + close.length);
34
+ const nextIndex = end.indexOf(close);
35
+ return ~nextIndex
36
+ ? start + replaceClose(end, close, replace, nextIndex)
37
+ : start + end;
38
+ };
39
+
40
+ const formatter = (open: string, close: string, replace = open) => {
41
+ if (!enabled) return String;
42
+ return (input: string) => {
43
+ const string = "" + input;
44
+ const index = string.indexOf(close, open.length);
45
+ return ~index
46
+ ? open + replaceClose(string, close, replace, index) + close
47
+ : open + string + close;
48
+ };
49
+ };
50
+
51
+ export const reset = enabled ? (s: string) => `\x1b[0m${s}\x1b[0m` : String;
52
+ export const bold = formatter("\x1b[1m", "\x1b[22m", "\x1b[22m\x1b[1m");
53
+ export const dim = formatter("\x1b[2m", "\x1b[22m", "\x1b[22m\x1b[2m");
54
+ export const italic = formatter("\x1b[3m", "\x1b[23m");
55
+ export const underline = formatter("\x1b[4m", "\x1b[24m");
56
+ export const inverse = formatter("\x1b[7m", "\x1b[27m");
57
+ export const hidden = formatter("\x1b[8m", "\x1b[28m");
58
+ export const strikethrough = formatter("\x1b[9m", "\x1b[29m");
59
+ export const black = formatter("\x1b[30m", "\x1b[39m");
60
+ export const red = formatter("\x1b[31m", "\x1b[39m");
61
+ export const green = formatter("\x1b[32m", "\x1b[39m");
62
+ export const yellow = formatter("\x1b[33m", "\x1b[39m");
63
+ export const blue = formatter("\x1b[34m", "\x1b[39m");
64
+ export const magenta = formatter("\x1b[35m", "\x1b[39m");
65
+ export const purple = formatter("\x1b[38;2;173;127;168m", "\x1b[39m");
66
+ export const cyan = formatter("\x1b[36m", "\x1b[39m");
67
+ export const white = formatter("\x1b[37m", "\x1b[39m");
68
+ export const gray = formatter("\x1b[90m", "\x1b[39m");
69
+ export const bgBlack = formatter("\x1b[40m", "\x1b[49m");
70
+ export const bgRed = formatter("\x1b[41m", "\x1b[49m");
71
+ export const bgGreen = formatter("\x1b[42m", "\x1b[49m");
72
+ export const bgYellow = formatter("\x1b[43m", "\x1b[49m");
73
+ export const bgBlue = formatter("\x1b[44m", "\x1b[49m");
74
+ export const bgMagenta = formatter("\x1b[45m", "\x1b[49m");
75
+ export const bgCyan = formatter("\x1b[46m", "\x1b[49m");
76
+ export const bgWhite = formatter("\x1b[47m", "\x1b[49m");
@@ -0,0 +1,22 @@
1
+ import { Debugger } from "debug";
2
+ import tailwindPackage from "tailwindcss/package.json";
3
+
4
+ import { tailwindCliV3, tailwindConfigV3 } from "./v3";
5
+
6
+ const isV3 = tailwindPackage.version.split(".")[0].includes("3");
7
+
8
+ export function tailwindCli(debug: Debugger) {
9
+ if (isV3) {
10
+ return tailwindCliV3(debug);
11
+ }
12
+
13
+ throw new Error("NativeWind only supports Tailwind CSS v3");
14
+ }
15
+
16
+ export function tailwindConfig(path: string) {
17
+ if (isV3) {
18
+ return tailwindConfigV3(path);
19
+ } else {
20
+ throw new Error("NativeWind only supports Tailwind CSS v3");
21
+ }
22
+ }
@@ -0,0 +1,9 @@
1
+ import { GetCSSForPlatformOnChange } from "react-native-css-interop/metro";
2
+
3
+ export interface TailwindCliOptions {
4
+ input: string;
5
+ platform: string;
6
+ browserslist?: string | null;
7
+ browserslistEnv?: string | null;
8
+ onChange?: GetCSSForPlatformOnChange;
9
+ }
@@ -0,0 +1,61 @@
1
+ /**
2
+ * This is a hack around Tailwind CSS v3, please read tailwind/v3/index.ts for more information.
3
+ */
4
+ (async function () {
5
+ const fs = require("fs");
6
+
7
+ const fakeOutput = "FAKE_OUTPUT";
8
+ let currentContents = "";
9
+
10
+ const originalReadFile = fs.promises.readFile;
11
+ fs.promises.readFile = async (path: string, encoding: string) => {
12
+ if (path === fakeOutput) {
13
+ return currentContents;
14
+ }
15
+ return originalReadFile(path, encoding);
16
+ };
17
+
18
+ const originalMkdir = fs.promises.mkdir.bind(fs.promises.mkdir);
19
+ fs.promises.mkdir = async (path: string, ...args: any) => {
20
+ if (path === fakeOutput) {
21
+ return;
22
+ }
23
+ return originalMkdir(path, ...args);
24
+ };
25
+
26
+ let previousData = "";
27
+ fs.promises.writeFile = async (
28
+ path: string,
29
+ data: string | Buffer,
30
+ ...args: any
31
+ ) => {
32
+ if (path !== fakeOutput) {
33
+ throw new Error(`Tailwind CLI attempted to write file ${path}`);
34
+ }
35
+
36
+ if (!process.send) {
37
+ process.exit(42);
38
+ }
39
+
40
+ const newData = data.toString();
41
+
42
+ if (previousData !== newData) {
43
+ previousData = newData;
44
+ process.send(newData);
45
+ }
46
+
47
+ return;
48
+ };
49
+
50
+ const { build } = require("tailwindcss/lib/cli/build");
51
+ const args: Record<string, string | boolean | undefined> = {
52
+ "--input": process.env.NATIVEWIND_INPUT,
53
+ "--output": fakeOutput,
54
+ };
55
+
56
+ if (process.env.NATIVEWIND_WATCH === "true") {
57
+ args["--watch"] = true;
58
+ }
59
+
60
+ await build(args);
61
+ })();
@@ -0,0 +1,103 @@
1
+ import { fork } from "child_process";
2
+
3
+ import { Debugger } from "debug";
4
+ import { type Config } from "tailwindcss";
5
+
6
+ import { TailwindCliOptions } from "../types";
7
+
8
+ /**
9
+ * Tailwind CLI v3 is not very well suited for programmatic usage.
10
+ * The recommended usage is PostCSS, but then we need to rebuild the plugin array/watcher/etc
11
+ *
12
+ * We also can't invoke the CLI directly as it writes to the file system/process.stdout/console.error
13
+ * in hard to capture ways.
14
+ *
15
+ * Our hack is simply to fork a child process (allows us to capture the terminal output)
16
+ * and override the fs (allows us to capture the output file)
17
+ *
18
+ * This is all a bad idea, but gives us full control over the output
19
+ */
20
+
21
+ const child_file = __dirname + "/child.js";
22
+
23
+ const getEnv = (options: TailwindCliOptions) => {
24
+ return {
25
+ ...process.env,
26
+ NATIVEWIND_INPUT: options.input,
27
+ NATIVEWIND_OS: options.platform,
28
+ NATIVEWIND_WATCH: options.onChange ? "true" : "false",
29
+ BROWSERSLIST: options.browserslist ?? undefined,
30
+ BROWSERSLIST_ENV: options.browserslistEnv ?? undefined,
31
+ };
32
+ };
33
+
34
+ export const tailwindCliV3 = function (debug: Debugger) {
35
+ return {
36
+ getCSSForPlatform(options: TailwindCliOptions) {
37
+ debug("Start development Tailwind CLI");
38
+ return new Promise<string>((resolve, reject) => {
39
+ try {
40
+ const child = fork(child_file, {
41
+ stdio: "pipe",
42
+ env: getEnv(options),
43
+ });
44
+
45
+ let initialMessage = true;
46
+ let initialDoneIn = true;
47
+
48
+ child.stderr?.on("data", (data) => {
49
+ data = data.toString();
50
+ if (data.includes("Done in")) {
51
+ if (initialDoneIn) {
52
+ initialDoneIn = false;
53
+ }
54
+ } else if (data.includes("warn -")) {
55
+ console.warn(data);
56
+ }
57
+ });
58
+
59
+ child.stdout?.on("data", (data) => {
60
+ data = data.toString();
61
+ });
62
+
63
+ child.on("message", (message) => {
64
+ if (initialMessage) {
65
+ resolve(message.toString());
66
+ initialMessage = false;
67
+ debug("Finished initial development Tailwind CLI");
68
+ } else if (options.onChange) {
69
+ debug("Tailwind CLI detected new styles");
70
+ options.onChange(message.toString());
71
+ }
72
+ });
73
+ } catch (e) {
74
+ reject(e);
75
+ }
76
+ });
77
+ },
78
+ };
79
+ };
80
+
81
+ const flattenPresets = (configs: Partial<Config>[] = []): Partial<Config>[] => {
82
+ if (!configs) return [];
83
+ return configs.flatMap((config) => [
84
+ config,
85
+ ...flattenPresets(config.presets),
86
+ ]);
87
+ };
88
+
89
+ export function tailwindConfigV3(path: string) {
90
+ const config: Config = require("tailwindcss/loadConfig")(path);
91
+
92
+ const hasPreset = flattenPresets(config.presets).some((preset) => {
93
+ return preset.nativewind;
94
+ });
95
+
96
+ if (!hasPreset) {
97
+ throw new Error(
98
+ "Tailwind CSS has not been configured with the NativeWind preset",
99
+ );
100
+ }
101
+
102
+ return config;
103
+ }
@@ -0,0 +1,69 @@
1
+ import { existsSync, readFileSync, writeFileSync } from "fs";
2
+
3
+ import { CommentArray, parse, stringify } from "comment-json";
4
+
5
+ import { bold, cyan } from "./picocolors";
6
+
7
+ export function setupTypeScript(envPath: string) {
8
+ try {
9
+ const ts = require("typescript");
10
+ if (!ts) {
11
+ return;
12
+ }
13
+
14
+ const configFileName = ts.findConfigFile(
15
+ "./",
16
+ ts.sys.fileExists,
17
+ "tsconfig.json",
18
+ );
19
+
20
+ const userConfig = parse(
21
+ readFileSync(configFileName, {
22
+ encoding: "utf-8",
23
+ }),
24
+ );
25
+
26
+ if (
27
+ typeof userConfig !== "object" ||
28
+ !userConfig ||
29
+ Array.isArray(userConfig)
30
+ ) {
31
+ return;
32
+ }
33
+
34
+ const output: string[] = [];
35
+ let updatedConfig = false;
36
+
37
+ if (!existsSync(envPath)) {
38
+ writeFileSync(
39
+ envPath,
40
+ `/// <reference types="nativewind/types" />
41
+
42
+ // NOTE: This file should not be edited and should be committed with your source code. It is generated by NativeWind.`,
43
+ );
44
+ output.push(`Created ${cyan(envPath)}`);
45
+ }
46
+
47
+ userConfig.include ??= new CommentArray(envPath);
48
+ if (
49
+ Array.isArray(userConfig.include) &&
50
+ !userConfig.include.includes(envPath)
51
+ ) {
52
+ userConfig.include.push(envPath);
53
+ updatedConfig = true;
54
+ output.push(
55
+ `Updated ${configFileName} to include the ${cyan(envPath)} file`,
56
+ );
57
+ }
58
+
59
+ if (updatedConfig) {
60
+ writeFileSync(configFileName, stringify(userConfig, null, 2));
61
+ }
62
+
63
+ if (output.length) {
64
+ console.log(
65
+ `${cyan(bold("NativeWind"))} made the following changes to your project to support TypeScript:\n - ${output.join("\n - ")}`,
66
+ );
67
+ }
68
+ } catch {}
69
+ }
@@ -0,0 +1,31 @@
1
+ import {
2
+ StyleSheet,
3
+ useColorScheme as useCSSColorScheme,
4
+ } from "react-native-css-interop";
5
+
6
+ export function useColorScheme() {
7
+ const colorScheme = useCSSColorScheme();
8
+ return {
9
+ ...colorScheme,
10
+ setColorScheme(scheme: Parameters<typeof colorScheme.setColorScheme>[0]) {
11
+ const darkMode = StyleSheet.getFlag("darkMode") ?? "media";
12
+ if (darkMode === "media") {
13
+ throw new Error(
14
+ "Unable to manually set color scheme without using darkMode: class. See: https://tailwindcss.com/docs/dark-mode#toggling-dark-mode-manually",
15
+ );
16
+ }
17
+
18
+ colorScheme?.setColorScheme(scheme);
19
+ },
20
+ toggleColorScheme() {
21
+ const darkMode = StyleSheet.getFlag("darkMode") ?? "media";
22
+ if (darkMode === "media") {
23
+ throw new Error(
24
+ "Unable to manually set color scheme without using darkMode: class. See: https://tailwindcss.com/docs/dark-mode#toggling-dark-mode-manually",
25
+ );
26
+ }
27
+
28
+ colorScheme?.toggleColorScheme();
29
+ },
30
+ };
31
+ }