@weapp-tailwindcss/react-native 0.1.0

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.
@@ -0,0 +1,179 @@
1
+ //#region src/runtime.ts
2
+ let activeManifest;
3
+ let activeEnvironment = {};
4
+ const styleMetadata = /* @__PURE__ */ new Map();
5
+ let styleSheetFactory;
6
+ let nativeStyleSheet = {};
7
+ function createStyleSheet(manifest) {
8
+ const source = manifest.styleSheet ?? Object.fromEntries(Object.entries(manifest.styleEntries ?? {}).map(([id, rule]) => [id, rule.style]));
9
+ nativeStyleSheet = styleSheetFactory?.(source) ?? source;
10
+ }
11
+ function flatten(value, result) {
12
+ if (!value) return;
13
+ if (typeof value === "string") {
14
+ result.push(...value.split(/\s+/).filter(Boolean));
15
+ return;
16
+ }
17
+ if (Array.isArray(value)) {
18
+ for (const item of value) flatten(item, result);
19
+ return;
20
+ }
21
+ for (const [className, enabled] of Object.entries(value)) if (enabled) result.push(className);
22
+ }
23
+ function canonicalTokens(value) {
24
+ const tokens = [];
25
+ flatten(value, tokens);
26
+ return [...new Set(tokens)].sort();
27
+ }
28
+ function matches(rule, environment) {
29
+ if (rule.colorScheme && rule.colorScheme !== environment.colorScheme) return false;
30
+ if (!rule.platform) return true;
31
+ if (rule.platform === "native") return environment.platform !== "web";
32
+ return rule.platform === environment.platform;
33
+ }
34
+ function resolveRules(ids, manifest, environment) {
35
+ const normal = [];
36
+ const important = [];
37
+ for (const id of ids) {
38
+ const rule = manifest?.styleEntries?.[id];
39
+ if (rule) {
40
+ if (!matches(rule, environment)) continue;
41
+ (rule.important ? important : normal).push({
42
+ rule,
43
+ id
44
+ });
45
+ continue;
46
+ }
47
+ const fallbackIds = manifest?.staticLookup?.[id] ?? [];
48
+ if (fallbackIds.length) for (const fallbackId of fallbackIds) {
49
+ const fallbackRule = manifest.styleEntries?.[fallbackId];
50
+ if (!fallbackRule || !matches(fallbackRule, environment)) continue;
51
+ (fallbackRule.important ? important : normal).push({
52
+ rule: fallbackRule,
53
+ id: fallbackId
54
+ });
55
+ }
56
+ else for (const fallbackRule of manifest?.rules?.[id] ?? []) {
57
+ if (!matches(fallbackRule, environment)) continue;
58
+ (fallbackRule.important ? important : normal).push({
59
+ rule: fallbackRule,
60
+ id
61
+ });
62
+ }
63
+ }
64
+ const order = (left, right) => (left.rule.order ?? 0) - (right.rule.order ?? 0);
65
+ normal.sort(order);
66
+ important.sort(order);
67
+ const style = {};
68
+ const importantStyle = {};
69
+ for (const { rule } of normal) Object.assign(style, rule.style);
70
+ for (const { rule } of important) {
71
+ Object.assign(style, rule.style);
72
+ Object.assign(importantStyle, rule.style);
73
+ }
74
+ const normalIds = normal.map((item) => item.id);
75
+ const importantIds = important.map((item) => item.id);
76
+ const asStyleValue = (ids, fallback) => {
77
+ if (!styleSheetFactory) return fallback;
78
+ const values = ids.map((id) => nativeStyleSheet[id]).filter((value) => value !== void 0);
79
+ if (values.length === 1) return values[0];
80
+ if (values.length > 1) return values;
81
+ return fallback;
82
+ };
83
+ return {
84
+ style,
85
+ importantStyle,
86
+ styleValue: asStyleValue(normalIds, style),
87
+ importantValue: asStyleValue(importantIds, importantStyle)
88
+ };
89
+ }
90
+ function resolveDynamic(value, manifest, environment) {
91
+ const classNames = canonicalTokens(value);
92
+ return resolveRules(manifest?.staticLookup ? classNames.flatMap((className) => manifest.staticLookup?.[className] ?? []) : classNames, manifest, environment);
93
+ }
94
+ function rememberStyle(style, importantStyle) {
95
+ if (importantStyle && (typeof importantStyle !== "object" || Object.keys(importantStyle).length)) styleMetadata.set(style, { important: importantStyle });
96
+ return style;
97
+ }
98
+ function createNativeStyleRuntime(initialManifest) {
99
+ let manifest = initialManifest;
100
+ let environment = activeEnvironment;
101
+ const cache = /* @__PURE__ */ new Map();
102
+ const runtime = {
103
+ tw(value, requestedEnvironment = {}) {
104
+ const effectiveEnvironment = {
105
+ ...environment,
106
+ ...requestedEnvironment
107
+ };
108
+ const key = `${canonicalTokens(value).join("")}|${effectiveEnvironment.colorScheme ?? ""}|${effectiveEnvironment.platform ?? ""}`;
109
+ const cached = cache.get(key);
110
+ if (cached) return cached;
111
+ const resolved = resolveDynamic(value, manifest, effectiveEnvironment);
112
+ const style = rememberStyle(resolved.styleValue, resolved.importantValue);
113
+ cache.set(key, style);
114
+ return style;
115
+ },
116
+ getStaticStyle(ids, requestedEnvironment = {}) {
117
+ const effectiveEnvironment = {
118
+ ...environment,
119
+ ...requestedEnvironment
120
+ };
121
+ const resolved = resolveRules(ids, manifest, effectiveEnvironment);
122
+ return rememberStyle(resolved.styleValue, resolved.importantValue);
123
+ },
124
+ composeStyle(tailwindStyle, inlineStyle) {
125
+ const important = styleMetadata.get(tailwindStyle)?.important;
126
+ return important !== void 0 ? [
127
+ tailwindStyle,
128
+ inlineStyle,
129
+ important
130
+ ] : [tailwindStyle, inlineStyle];
131
+ },
132
+ setManifest(nextManifest) {
133
+ manifest = nextManifest;
134
+ cache.clear();
135
+ styleMetadata.clear();
136
+ createStyleSheet(nextManifest);
137
+ activeManifest = nextManifest;
138
+ },
139
+ setEnvironment(nextEnvironment) {
140
+ environment = nextEnvironment;
141
+ activeEnvironment = nextEnvironment;
142
+ cache.clear();
143
+ },
144
+ getManifest() {
145
+ return manifest;
146
+ }
147
+ };
148
+ if (initialManifest) {
149
+ createStyleSheet(initialManifest);
150
+ activeManifest = initialManifest;
151
+ }
152
+ return runtime;
153
+ }
154
+ const defaultRuntime = createNativeStyleRuntime();
155
+ function setManifest(manifest) {
156
+ defaultRuntime.setManifest(manifest);
157
+ }
158
+ /** 由 Expo virtual module 注入,避免 runtime 引入 Node-only 的 require shim。 */
159
+ function setStyleSheetFactory(factory) {
160
+ styleSheetFactory = factory;
161
+ if (activeManifest) createStyleSheet(activeManifest);
162
+ }
163
+ function setEnvironment(environment) {
164
+ defaultRuntime.setEnvironment(environment);
165
+ }
166
+ function getManifest() {
167
+ return activeManifest ?? defaultRuntime.getManifest();
168
+ }
169
+ function tw(value, environment) {
170
+ return defaultRuntime.tw(value, environment);
171
+ }
172
+ function getStaticStyle(ids, environment) {
173
+ return defaultRuntime.getStaticStyle(ids, environment);
174
+ }
175
+ function composeStyle(tailwindStyle, inlineStyle) {
176
+ return defaultRuntime.composeStyle(tailwindStyle, inlineStyle);
177
+ }
178
+ //#endregion
179
+ export { composeStyle, createNativeStyleRuntime, getManifest, getStaticStyle, setEnvironment, setManifest, setStyleSheetFactory, tw };
@@ -0,0 +1,50 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_compiler = require("./compiler.cjs");
3
+ let weapp_tailwindcss_generator = require("weapp-tailwindcss/generator");
4
+ //#region src/tailwind.ts
5
+ /**
6
+ * 使用 weapp-tailwindcss 的 Tailwind v4 generator 生成原始 CSS,再编译为 RN manifest。
7
+ */
8
+ async function generateNativeStylesheet(options = {}) {
9
+ const source = await (0, weapp_tailwindcss_generator.resolveTailwindV4Source)(options);
10
+ const generator = (0, weapp_tailwindcss_generator.createWeappTailwindcssGenerator)(source);
11
+ const sourcePatterns = options.sourceGlobs?.map((pattern) => ({
12
+ base: source.projectRoot,
13
+ pattern,
14
+ negated: false
15
+ }));
16
+ const generatorCandidates = new Set(options.candidates ?? []);
17
+ for (const candidate of generatorCandidates) {
18
+ const base = candidate.split(":").at(-1);
19
+ if (base && /^(?:ios|android|native):/.test(candidate)) generatorCandidates.add(base);
20
+ }
21
+ let generated = await generator.generate({
22
+ target: "web",
23
+ ...generatorCandidates.size ? { candidates: generatorCandidates } : {},
24
+ scanSources: sourcePatterns ?? true
25
+ });
26
+ const platformBases = /* @__PURE__ */ new Set();
27
+ for (const candidate of generated.rawCandidates ?? []) {
28
+ const base = candidate.split(":").at(-1);
29
+ if (base && /^(?:ios|android|native):/.test(candidate) && !generated.classSet.has(base)) platformBases.add(base);
30
+ }
31
+ if (platformBases.size) generated = await generator.generate({
32
+ target: "web",
33
+ candidates: /* @__PURE__ */ new Set([...generatorCandidates, ...platformBases]),
34
+ scanSources: sourcePatterns ?? true
35
+ });
36
+ const classSet = new Set(generated.classSet);
37
+ const requestedCandidates = new Set(options.candidates ?? []);
38
+ for (const candidate of generated.rawCandidates ?? []) {
39
+ const base = candidate.split(":").at(-1);
40
+ if (base && generated.classSet.has(base) && /^(?:dark|ios|android|native):/.test(candidate)) requestedCandidates.add(candidate);
41
+ }
42
+ for (const candidate of requestedCandidates) classSet.add(candidate);
43
+ const manifest = require_compiler.compileNativeStylesheet(generated.rawCss, { classSet });
44
+ require_compiler.addNativeVariantRules(manifest, requestedCandidates);
45
+ require_compiler.finalizeNativeManifest(manifest);
46
+ generator.dispose?.();
47
+ return manifest;
48
+ }
49
+ //#endregion
50
+ exports.generateNativeStylesheet = generateNativeStylesheet;
@@ -0,0 +1,13 @@
1
+ import { o as NativeStyleManifest } from "./types-BTxnqaRV.js";
2
+ import { TailwindV4SourceOptions } from "weapp-tailwindcss/generator";
3
+ //#region src/tailwind.d.ts
4
+ interface GenerateNativeStylesheetOptions extends TailwindV4SourceOptions {
5
+ candidates?: Iterable<string> | undefined;
6
+ sourceGlobs?: string[] | undefined;
7
+ }
8
+ /**
9
+ * 使用 weapp-tailwindcss 的 Tailwind v4 generator 生成原始 CSS,再编译为 RN manifest。
10
+ */
11
+ declare function generateNativeStylesheet(options?: GenerateNativeStylesheetOptions): Promise<NativeStyleManifest>;
12
+ //#endregion
13
+ export { GenerateNativeStylesheetOptions, generateNativeStylesheet };
@@ -0,0 +1,49 @@
1
+ import { addNativeVariantRules, compileNativeStylesheet, finalizeNativeManifest } from "./compiler.js";
2
+ import { createWeappTailwindcssGenerator, resolveTailwindV4Source } from "weapp-tailwindcss/generator";
3
+ //#region src/tailwind.ts
4
+ /**
5
+ * 使用 weapp-tailwindcss 的 Tailwind v4 generator 生成原始 CSS,再编译为 RN manifest。
6
+ */
7
+ async function generateNativeStylesheet(options = {}) {
8
+ const source = await resolveTailwindV4Source(options);
9
+ const generator = createWeappTailwindcssGenerator(source);
10
+ const sourcePatterns = options.sourceGlobs?.map((pattern) => ({
11
+ base: source.projectRoot,
12
+ pattern,
13
+ negated: false
14
+ }));
15
+ const generatorCandidates = new Set(options.candidates ?? []);
16
+ for (const candidate of generatorCandidates) {
17
+ const base = candidate.split(":").at(-1);
18
+ if (base && /^(?:ios|android|native):/.test(candidate)) generatorCandidates.add(base);
19
+ }
20
+ let generated = await generator.generate({
21
+ target: "web",
22
+ ...generatorCandidates.size ? { candidates: generatorCandidates } : {},
23
+ scanSources: sourcePatterns ?? true
24
+ });
25
+ const platformBases = /* @__PURE__ */ new Set();
26
+ for (const candidate of generated.rawCandidates ?? []) {
27
+ const base = candidate.split(":").at(-1);
28
+ if (base && /^(?:ios|android|native):/.test(candidate) && !generated.classSet.has(base)) platformBases.add(base);
29
+ }
30
+ if (platformBases.size) generated = await generator.generate({
31
+ target: "web",
32
+ candidates: /* @__PURE__ */ new Set([...generatorCandidates, ...platformBases]),
33
+ scanSources: sourcePatterns ?? true
34
+ });
35
+ const classSet = new Set(generated.classSet);
36
+ const requestedCandidates = new Set(options.candidates ?? []);
37
+ for (const candidate of generated.rawCandidates ?? []) {
38
+ const base = candidate.split(":").at(-1);
39
+ if (base && generated.classSet.has(base) && /^(?:dark|ios|android|native):/.test(candidate)) requestedCandidates.add(candidate);
40
+ }
41
+ for (const candidate of requestedCandidates) classSet.add(candidate);
42
+ const manifest = compileNativeStylesheet(generated.rawCss, { classSet });
43
+ addNativeVariantRules(manifest, requestedCandidates);
44
+ finalizeNativeManifest(manifest);
45
+ generator.dispose?.();
46
+ return manifest;
47
+ }
48
+ //#endregion
49
+ export { generateNativeStylesheet };
@@ -0,0 +1,48 @@
1
+ //#region src/types.d.ts
2
+ type NativePlatform = 'android' | 'ios' | 'native' | 'web';
3
+ interface NativeStyleEnvironment {
4
+ colorScheme?: 'light' | 'dark' | undefined;
5
+ platform?: NativePlatform | undefined;
6
+ }
7
+ interface NativeStyleRule {
8
+ style: Record<string, unknown>;
9
+ colorScheme?: 'dark' | undefined;
10
+ platform?: NativePlatform | undefined;
11
+ important?: boolean | undefined;
12
+ order?: number | undefined;
13
+ id?: string | undefined;
14
+ }
15
+ interface NativeCompilerWarning {
16
+ className?: string | undefined;
17
+ property?: string | undefined;
18
+ message: string;
19
+ }
20
+ interface NativeStyleManifest {
21
+ version: 1;
22
+ classSet: string[];
23
+ rules: Record<string, NativeStyleRule[]>;
24
+ /** 可直接交给 StyleSheet.create 的稳定规则表。 */
25
+ styleSheet?: Record<string, Record<string, unknown>>;
26
+ /** styleSheet 规则的条件和优先级元数据。 */
27
+ styleEntries?: Record<string, NativeStyleRule>;
28
+ /** 每个 class token 对应的静态 style ID,Babel 编译结果直接使用它。 */
29
+ staticLookup?: Record<string, string[]>;
30
+ variables: Record<string, string>;
31
+ warnings: NativeCompilerWarning[];
32
+ }
33
+ interface CompileNativeStylesheetOptions {
34
+ classSet?: Iterable<string> | undefined;
35
+ ignorePreflight?: boolean | undefined;
36
+ }
37
+ type NativeClassValue = string | false | null | undefined | NativeClassValue[] | Record<string, boolean>;
38
+ type NativeStyleValue = Record<string, unknown> | number | readonly NativeStyleValue[];
39
+ interface NativeStyleRuntime {
40
+ tw: (value: NativeClassValue, environment?: NativeStyleEnvironment) => NativeStyleValue;
41
+ getStaticStyle: (ids: readonly string[], environment?: NativeStyleEnvironment) => NativeStyleValue;
42
+ composeStyle: (tailwindStyle: NativeStyleValue, inlineStyle: unknown) => NativeStyleValue[];
43
+ setManifest: (manifest: NativeStyleManifest) => void;
44
+ setEnvironment: (environment: NativeStyleEnvironment) => void;
45
+ getManifest: () => NativeStyleManifest | undefined;
46
+ }
47
+ //#endregion
48
+ export { NativeStyleEnvironment as a, NativeStyleRuntime as c, NativePlatform as i, NativeStyleValue as l, NativeClassValue as n, NativeStyleManifest as o, NativeCompilerWarning as r, NativeStyleRule as s, CompileNativeStylesheetOptions as t };
package/package.json ADDED
@@ -0,0 +1,109 @@
1
+ {
2
+ "name": "@weapp-tailwindcss/react-native",
3
+ "type": "module",
4
+ "version": "0.1.0",
5
+ "description": "Tailwind CSS 4 compiler and Expo Metro integration for React Native.",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/sonofmagic/weapp-tailwindcss.git",
10
+ "directory": "packages/react-native"
11
+ },
12
+ "sideEffects": true,
13
+ "exports": {
14
+ ".": {
15
+ "types": "./dist/index.d.ts",
16
+ "import": "./dist/index.js",
17
+ "require": "./dist/index.cjs"
18
+ },
19
+ "./compiler": {
20
+ "types": "./dist/compiler.d.ts",
21
+ "import": "./dist/compiler.js",
22
+ "require": "./dist/compiler.cjs"
23
+ },
24
+ "./tailwind": {
25
+ "types": "./dist/tailwind.d.ts",
26
+ "import": "./dist/tailwind.js",
27
+ "require": "./dist/tailwind.cjs"
28
+ },
29
+ "./babel": {
30
+ "types": "./dist/babel.d.ts",
31
+ "import": "./dist/babel.js",
32
+ "require": "./dist/babel.cjs"
33
+ },
34
+ "./metro": {
35
+ "types": "./dist/metro.d.ts",
36
+ "import": "./dist/metro.js",
37
+ "require": "./dist/metro.cjs"
38
+ },
39
+ "./runtime": {
40
+ "types": "./dist/runtime.d.ts",
41
+ "import": "./dist/runtime.js",
42
+ "require": "./dist/runtime.cjs"
43
+ },
44
+ "./env": {
45
+ "types": "./dist/env.d.ts",
46
+ "import": "./dist/env.js",
47
+ "require": "./dist/env.cjs"
48
+ },
49
+ "./metro-transformer": {
50
+ "types": "./dist/metro-transformer.d.ts",
51
+ "import": "./dist/metro-transformer.js",
52
+ "require": "./dist/metro-transformer.cjs"
53
+ },
54
+ "./package.json": "./package.json"
55
+ },
56
+ "main": "./dist/index.cjs",
57
+ "module": "./dist/index.js",
58
+ "types": "./dist/index.d.ts",
59
+ "files": [
60
+ "dist"
61
+ ],
62
+ "engines": {
63
+ "node": ">=22.12.0"
64
+ },
65
+ "publishConfig": {
66
+ "access": "public"
67
+ },
68
+ "peerDependencies": {
69
+ "@babel/core": ">=7.22.0",
70
+ "expo": ">=54.0.0",
71
+ "react": ">=19.0.0",
72
+ "react-native": ">=0.81.0",
73
+ "tailwindcss": ">=4.0.0"
74
+ },
75
+ "peerDependenciesMeta": {
76
+ "@babel/core": {
77
+ "optional": true
78
+ },
79
+ "expo": {
80
+ "optional": true
81
+ },
82
+ "react": {
83
+ "optional": true
84
+ },
85
+ "react-native": {
86
+ "optional": true
87
+ },
88
+ "tailwindcss": {
89
+ "optional": true
90
+ }
91
+ },
92
+ "dependencies": {
93
+ "@babel/types": "^8.0.4",
94
+ "postcss": "^8.5.22",
95
+ "weapp-tailwindcss": "^5.2.2"
96
+ },
97
+ "devDependencies": {
98
+ "@babel/core": "^8.0.1",
99
+ "vitest": "^4.1.0"
100
+ },
101
+ "scripts": {
102
+ "build": "tsdown",
103
+ "test": "vitest run",
104
+ "bench": "vitest bench",
105
+ "test:dev": "vitest",
106
+ "lint": "eslint .",
107
+ "release": "pnpm publish"
108
+ }
109
+ }