rnwind 0.0.8 → 0.0.10
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.
- package/lib/cjs/core/parser/color.cjs +33 -1
- package/lib/cjs/core/parser/color.cjs.map +1 -1
- package/lib/cjs/core/parser/color.d.ts +10 -0
- package/lib/cjs/core/parser/declaration.cjs +121 -9
- package/lib/cjs/core/parser/declaration.cjs.map +1 -1
- package/lib/cjs/core/parser/gradient.cjs +46 -12
- package/lib/cjs/core/parser/gradient.cjs.map +1 -1
- package/lib/cjs/core/parser/gradient.d.ts +2 -1
- package/lib/cjs/core/parser/keyframes.cjs +27 -12
- package/lib/cjs/core/parser/keyframes.cjs.map +1 -1
- package/lib/cjs/core/parser/keyframes.d.ts +11 -0
- package/lib/cjs/core/parser/layout-dispatcher.cjs +33 -10
- package/lib/cjs/core/parser/layout-dispatcher.cjs.map +1 -1
- package/lib/cjs/core/parser/length.cjs +17 -1
- package/lib/cjs/core/parser/length.cjs.map +1 -1
- package/lib/cjs/core/parser/safe-area.cjs +24 -3
- package/lib/cjs/core/parser/safe-area.cjs.map +1 -1
- package/lib/cjs/core/parser/theme-vars.cjs +58 -8
- package/lib/cjs/core/parser/theme-vars.cjs.map +1 -1
- package/lib/cjs/core/parser/tokens.cjs +77 -9
- package/lib/cjs/core/parser/tokens.cjs.map +1 -1
- package/lib/cjs/core/parser/tokens.d.ts +9 -0
- package/lib/cjs/core/parser/transform.cjs +18 -9
- package/lib/cjs/core/parser/transform.cjs.map +1 -1
- package/lib/cjs/core/parser/tw-parser.cjs +136 -34
- package/lib/cjs/core/parser/tw-parser.cjs.map +1 -1
- package/lib/cjs/core/parser/tw-parser.d.ts +20 -0
- package/lib/cjs/core/parser/typography-dispatcher.cjs +19 -1
- package/lib/cjs/core/parser/typography-dispatcher.cjs.map +1 -1
- package/lib/cjs/core/parser/typography.cjs +15 -18
- package/lib/cjs/core/parser/typography.cjs.map +1 -1
- package/lib/cjs/core/parser/typography.d.ts +5 -5
- package/lib/cjs/core/style-builder/build-style.cjs +12 -3
- package/lib/cjs/core/style-builder/build-style.cjs.map +1 -1
- package/lib/cjs/core/style-builder/build-style.d.ts +3 -1
- package/lib/cjs/core/style-builder/union-builder.cjs +9 -11
- package/lib/cjs/core/style-builder/union-builder.cjs.map +1 -1
- package/lib/cjs/core/style-builder/union-builder.d.ts +7 -8
- package/lib/cjs/metro/dts.cjs +6 -1
- package/lib/cjs/metro/dts.cjs.map +1 -1
- package/lib/cjs/metro/transformer.cjs +42 -77
- package/lib/cjs/metro/transformer.cjs.map +1 -1
- package/lib/cjs/metro/with-config.cjs +9 -29
- package/lib/cjs/metro/with-config.cjs.map +1 -1
- package/lib/cjs/runtime/hooks/use-scheme.cjs +17 -11
- package/lib/cjs/runtime/hooks/use-scheme.cjs.map +1 -1
- package/lib/cjs/runtime/hooks/use-scheme.d.ts +7 -4
- package/lib/cjs/runtime/index.cjs +2 -1
- package/lib/cjs/runtime/index.cjs.map +1 -1
- package/lib/cjs/runtime/index.d.ts +2 -2
- package/lib/cjs/runtime/lookup-css.cjs +41 -0
- package/lib/cjs/runtime/lookup-css.cjs.map +1 -1
- package/lib/cjs/runtime/lookup-css.d.ts +29 -0
- package/lib/cjs/runtime/resolve.cjs +8 -6
- package/lib/cjs/runtime/resolve.cjs.map +1 -1
- package/lib/cjs/runtime/wrap.cjs +50 -57
- package/lib/cjs/runtime/wrap.cjs.map +1 -1
- package/lib/cjs/runtime/wrap.d.ts +10 -4
- package/lib/cjs/testing/index.cjs +1 -1
- package/lib/cjs/testing/index.cjs.map +1 -1
- package/lib/esm/core/parser/color.d.ts +10 -0
- package/lib/esm/core/parser/color.mjs +34 -3
- package/lib/esm/core/parser/color.mjs.map +1 -1
- package/lib/esm/core/parser/declaration.mjs +122 -10
- package/lib/esm/core/parser/declaration.mjs.map +1 -1
- package/lib/esm/core/parser/gradient.d.ts +2 -1
- package/lib/esm/core/parser/gradient.mjs +45 -11
- package/lib/esm/core/parser/gradient.mjs.map +1 -1
- package/lib/esm/core/parser/keyframes.d.ts +11 -0
- package/lib/esm/core/parser/keyframes.mjs +27 -12
- package/lib/esm/core/parser/keyframes.mjs.map +1 -1
- package/lib/esm/core/parser/layout-dispatcher.mjs +33 -10
- package/lib/esm/core/parser/layout-dispatcher.mjs.map +1 -1
- package/lib/esm/core/parser/length.mjs +17 -1
- package/lib/esm/core/parser/length.mjs.map +1 -1
- package/lib/esm/core/parser/safe-area.mjs +24 -3
- package/lib/esm/core/parser/safe-area.mjs.map +1 -1
- package/lib/esm/core/parser/theme-vars.mjs +58 -8
- package/lib/esm/core/parser/theme-vars.mjs.map +1 -1
- package/lib/esm/core/parser/tokens.d.ts +9 -0
- package/lib/esm/core/parser/tokens.mjs +77 -10
- package/lib/esm/core/parser/tokens.mjs.map +1 -1
- package/lib/esm/core/parser/transform.mjs +18 -9
- package/lib/esm/core/parser/transform.mjs.map +1 -1
- package/lib/esm/core/parser/tw-parser.d.ts +20 -0
- package/lib/esm/core/parser/tw-parser.mjs +138 -36
- package/lib/esm/core/parser/tw-parser.mjs.map +1 -1
- package/lib/esm/core/parser/typography-dispatcher.mjs +19 -1
- package/lib/esm/core/parser/typography-dispatcher.mjs.map +1 -1
- package/lib/esm/core/parser/typography.d.ts +5 -5
- package/lib/esm/core/parser/typography.mjs +15 -18
- package/lib/esm/core/parser/typography.mjs.map +1 -1
- package/lib/esm/core/style-builder/build-style.d.ts +3 -1
- package/lib/esm/core/style-builder/build-style.mjs +12 -3
- package/lib/esm/core/style-builder/build-style.mjs.map +1 -1
- package/lib/esm/core/style-builder/union-builder.d.ts +7 -8
- package/lib/esm/core/style-builder/union-builder.mjs +9 -11
- package/lib/esm/core/style-builder/union-builder.mjs.map +1 -1
- package/lib/esm/metro/dts.mjs +6 -1
- package/lib/esm/metro/dts.mjs.map +1 -1
- package/lib/esm/metro/transformer.mjs +42 -77
- package/lib/esm/metro/transformer.mjs.map +1 -1
- package/lib/esm/metro/with-config.mjs +10 -30
- package/lib/esm/metro/with-config.mjs.map +1 -1
- package/lib/esm/runtime/hooks/use-scheme.d.ts +7 -4
- package/lib/esm/runtime/hooks/use-scheme.mjs +17 -11
- package/lib/esm/runtime/hooks/use-scheme.mjs.map +1 -1
- package/lib/esm/runtime/index.d.ts +2 -2
- package/lib/esm/runtime/index.mjs +2 -2
- package/lib/esm/runtime/index.mjs.map +1 -1
- package/lib/esm/runtime/lookup-css.d.ts +29 -0
- package/lib/esm/runtime/lookup-css.mjs +39 -1
- package/lib/esm/runtime/lookup-css.mjs.map +1 -1
- package/lib/esm/runtime/resolve.mjs +9 -7
- package/lib/esm/runtime/resolve.mjs.map +1 -1
- package/lib/esm/runtime/wrap.d.ts +10 -4
- package/lib/esm/runtime/wrap.mjs +50 -57
- package/lib/esm/runtime/wrap.mjs.map +1 -1
- package/lib/esm/testing/index.mjs +2 -2
- package/lib/esm/testing/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/core/parser/color.ts +32 -1
- package/src/core/parser/declaration.ts +119 -10
- package/src/core/parser/gradient.ts +48 -11
- package/src/core/parser/keyframes.ts +31 -3
- package/src/core/parser/layout-dispatcher.ts +32 -9
- package/src/core/parser/length.ts +18 -1
- package/src/core/parser/safe-area.ts +23 -2
- package/src/core/parser/theme-vars.ts +75 -8
- package/src/core/parser/tokens.ts +76 -9
- package/src/core/parser/transform.ts +19 -8
- package/src/core/parser/tw-parser.ts +148 -31
- package/src/core/parser/typography-dispatcher.ts +20 -1
- package/src/core/parser/typography.ts +15 -15
- package/src/core/style-builder/build-style.ts +12 -1
- package/src/core/style-builder/union-builder.ts +10 -12
- package/src/metro/dts.ts +6 -1
- package/src/metro/transformer.ts +42 -78
- package/src/metro/with-config.ts +10 -29
- package/src/runtime/hooks/use-scheme.ts +17 -10
- package/src/runtime/index.ts +2 -1
- package/src/runtime/lookup-css.ts +42 -0
- package/src/runtime/resolve.ts +9 -7
- package/src/runtime/wrap.tsx +57 -61
- package/src/testing/index.ts +3 -0
|
@@ -2,6 +2,7 @@ import { type SourceEntry } from '@tailwindcss/oxide';
|
|
|
2
2
|
import { type GradientAtomInfo } from './gradient';
|
|
3
3
|
import { type HapticRequest } from './haptics';
|
|
4
4
|
import type { RNStyle } from './types';
|
|
5
|
+
import type { ThemeTables } from '../types';
|
|
5
6
|
/** Parser configuration — one instance per Metro session, theme CSS fixed. */
|
|
6
7
|
export interface TailwindParserConfig {
|
|
7
8
|
/**
|
|
@@ -94,6 +95,14 @@ export interface ParsedOutput {
|
|
|
94
95
|
* provider's `windowWidth`.
|
|
95
96
|
*/
|
|
96
97
|
breakpoints: ReadonlyMap<string, number>;
|
|
98
|
+
/**
|
|
99
|
+
* Per-scheme user theme token tables (`--color-*`, `--spacing-*`, …) with
|
|
100
|
+
* `--color-*` values lowered to sRGB. The style-builder emits these as
|
|
101
|
+
* `registerThemeTokens({...})` in the manifest so `useColor` / `useToken` /
|
|
102
|
+
* `useSize` resolve out of the box, without the user threading a `tables`
|
|
103
|
+
* prop on the provider. Keyed by scheme (`base` + each declared variant).
|
|
104
|
+
*/
|
|
105
|
+
themeTokens: ThemeTables;
|
|
97
106
|
}
|
|
98
107
|
/**
|
|
99
108
|
* Parses one source file's Tailwind usage into RN-ready style objects.
|
|
@@ -170,6 +179,17 @@ export declare class TailwindParser {
|
|
|
170
179
|
* @returns Effective var name → value lookup for the scheme.
|
|
171
180
|
*/
|
|
172
181
|
private effectiveVars;
|
|
182
|
+
/**
|
|
183
|
+
* Build the per-scheme theme token tables for `registerThemeTokens` —
|
|
184
|
+
* the data source for `useColor` / `useToken` / `useSize`. Emits one table
|
|
185
|
+
* per scheme the user wrote tokens under (`base` + each variant block /
|
|
186
|
+
* `.dark` override). `--color-*` values are lowered to sRGB (matching the
|
|
187
|
+
* className path) using `resolver` so a wide-gamut or `var()`-referencing
|
|
188
|
+
* token resolves to an RN-renderable string; other tokens pass through.
|
|
189
|
+
* @param resolver Full compiled `:root` table, for resolving `var()` refs.
|
|
190
|
+
* @returns Scheme → (token name → value) map.
|
|
191
|
+
*/
|
|
192
|
+
private buildThemeTokens;
|
|
173
193
|
/**
|
|
174
194
|
* Build the Tailwind compiler on first use and cache it. The theme CSS
|
|
175
195
|
* gets a `theme(inline)` modifier on its `@import 'tailwindcss'` so
|
|
@@ -5,11 +5,12 @@ import { Features, transform } from 'lightningcss';
|
|
|
5
5
|
import { declarationToRnEntries } from './declaration.mjs';
|
|
6
6
|
import { detectGradientAtom } from './gradient.mjs';
|
|
7
7
|
import { detectHapticAtom } from './haptics.mjs';
|
|
8
|
-
import { keyframesName,
|
|
8
|
+
import { keyframesName, keyframeSelectorOffsets, pickAnimationName } from './keyframes.mjs';
|
|
9
9
|
import { serializeInitialValue } from './property.mjs';
|
|
10
10
|
import { classNameFromSelector } from './selector.mjs';
|
|
11
11
|
import { extractThemeVars, extractSchemeAliases, extractCustomVariantSchemes, BASE_SCHEME, compileReadyTheme } from './theme-vars.mjs';
|
|
12
|
-
import { serializeTokens } from './tokens.mjs';
|
|
12
|
+
import { substituteThemeVars, serializeTokens, coerceUnparsedValue } from './tokens.mjs';
|
|
13
|
+
import { normalizeColorString } from './color.mjs';
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Default LightningCSS transform options for TailwindParser's visitor.
|
|
@@ -145,6 +146,33 @@ class TailwindParser {
|
|
|
145
146
|
merged.set(k, v);
|
|
146
147
|
return merged;
|
|
147
148
|
}
|
|
149
|
+
/**
|
|
150
|
+
* Build the per-scheme theme token tables for `registerThemeTokens` —
|
|
151
|
+
* the data source for `useColor` / `useToken` / `useSize`. Emits one table
|
|
152
|
+
* per scheme the user wrote tokens under (`base` + each variant block /
|
|
153
|
+
* `.dark` override). `--color-*` values are lowered to sRGB (matching the
|
|
154
|
+
* className path) using `resolver` so a wide-gamut or `var()`-referencing
|
|
155
|
+
* token resolves to an RN-renderable string; other tokens pass through.
|
|
156
|
+
* @param resolver Full compiled `:root` table, for resolving `var()` refs.
|
|
157
|
+
* @returns Scheme → (token name → value) map.
|
|
158
|
+
*/
|
|
159
|
+
buildThemeTokens(resolver) {
|
|
160
|
+
const out = {};
|
|
161
|
+
for (const scheme of this.themeSchemes.keys()) {
|
|
162
|
+
const userTable = this.themeSchemes.get(scheme);
|
|
163
|
+
if (!userTable || userTable.size === 0)
|
|
164
|
+
continue;
|
|
165
|
+
const schemeResolver = new Map(resolver);
|
|
166
|
+
for (const [k, v] of this.effectiveVars(scheme))
|
|
167
|
+
schemeResolver.set(k, v);
|
|
168
|
+
const table = {};
|
|
169
|
+
for (const [name, raw] of userTable) {
|
|
170
|
+
table[name] = name.startsWith('--color-') ? lowerColorToken(raw, schemeResolver) : raw;
|
|
171
|
+
}
|
|
172
|
+
out[scheme] = table;
|
|
173
|
+
}
|
|
174
|
+
return out;
|
|
175
|
+
}
|
|
148
176
|
/**
|
|
149
177
|
* Build the Tailwind compiler on first use and cache it. The theme CSS
|
|
150
178
|
* gets a `theme(inline)` modifier on its `@import 'tailwindcss'` so
|
|
@@ -281,7 +309,8 @@ class TailwindParser {
|
|
|
281
309
|
// surface their role + resolved colour so the transformer
|
|
282
310
|
// can rewrite `<LinearGradient className="...">` into
|
|
283
311
|
// `colors={...}` / `start={...}` / `end={...}` props.
|
|
284
|
-
const
|
|
312
|
+
const gradientTable = schemeTables.get(BASE_SCHEME) ?? schemeTables.get(schemes[0] ?? BASE_SCHEME);
|
|
313
|
+
const gradient = detectGradientAtom(rule.value.declarations.declarations, gradientTable);
|
|
285
314
|
if (gradient)
|
|
286
315
|
gradientAtoms.set(className, gradient);
|
|
287
316
|
// Haptics may live on the rule directly OR inside a
|
|
@@ -302,8 +331,8 @@ class TailwindParser {
|
|
|
302
331
|
const steps = [];
|
|
303
332
|
const baseTable = schemeTables.get(BASE_SCHEME) ?? schemeTables.get(schemes[0] ?? BASE_SCHEME);
|
|
304
333
|
for (const frame of rule.value.keyframes) {
|
|
305
|
-
const
|
|
306
|
-
if (
|
|
334
|
+
const offsets = keyframeSelectorOffsets(frame.selectors);
|
|
335
|
+
if (offsets.length === 0)
|
|
307
336
|
continue;
|
|
308
337
|
const style = {};
|
|
309
338
|
const frameDecls = frame.declarations.declarations ?? [];
|
|
@@ -311,7 +340,10 @@ class TailwindParser {
|
|
|
311
340
|
for (const [key, value] of declarationToRnEntries(decl, baseTable))
|
|
312
341
|
style[key] = value;
|
|
313
342
|
}
|
|
314
|
-
|
|
343
|
+
// One frame can carry several offsets (`0%, 100% { … }`); emit a
|
|
344
|
+
// step for each so the terminal frame isn't lost.
|
|
345
|
+
for (const offset of offsets)
|
|
346
|
+
steps.push({ offset, style });
|
|
315
347
|
}
|
|
316
348
|
keyframes.set(name, { name, steps });
|
|
317
349
|
},
|
|
@@ -332,9 +364,23 @@ class TailwindParser {
|
|
|
332
364
|
if (!referencedKeyframes.has(name))
|
|
333
365
|
keyframes.delete(name);
|
|
334
366
|
}
|
|
335
|
-
|
|
367
|
+
const themeTokens = this.buildThemeTokens(compiledTheme);
|
|
368
|
+
return { atoms, keyframes, propertyDefaults, gradientAtoms, hapticAtoms, candidates: [...candidates], schemes, breakpoints, themeTokens };
|
|
336
369
|
}
|
|
337
370
|
}
|
|
371
|
+
/**
|
|
372
|
+
* Lower a `--color-*` token value to an RN-renderable sRGB string, matching
|
|
373
|
+
* the className path: resolve any `var()` ref via `resolver`, then lower a
|
|
374
|
+
* wide-gamut form (`oklch(…)`, `lab(…)`, `color(p3 …)`) to sRGB. Hex / rgb /
|
|
375
|
+
* named colors pass through unchanged.
|
|
376
|
+
* @param raw Raw token value.
|
|
377
|
+
* @param resolver Var name → value table for resolving `var()` references.
|
|
378
|
+
* @returns RN-safe color string.
|
|
379
|
+
*/
|
|
380
|
+
function lowerColorToken(raw, resolver) {
|
|
381
|
+
const substituted = substituteThemeVars(raw, resolver);
|
|
382
|
+
return normalizeColorString(substituted) ?? substituted;
|
|
383
|
+
}
|
|
338
384
|
/**
|
|
339
385
|
* Wrap an error from `@tailwindcss/node`'s compiler or `lightningcss`'s
|
|
340
386
|
* transform with a `rnwind:` prefix so the user sees a clear "this came
|
|
@@ -381,6 +427,7 @@ function emptyOutput() {
|
|
|
381
427
|
candidates: [],
|
|
382
428
|
schemes: [BASE_SCHEME],
|
|
383
429
|
breakpoints: new Map(),
|
|
430
|
+
themeTokens: {},
|
|
384
431
|
};
|
|
385
432
|
}
|
|
386
433
|
/**
|
|
@@ -452,8 +499,8 @@ function processStyleRule(declarations, className, ctx, nestedRules = []) {
|
|
|
452
499
|
ctx.referencedKeyframes.add(animationRef);
|
|
453
500
|
}
|
|
454
501
|
applyComposedTransform(bucket, ctx.schemes, ruleLocalVars);
|
|
455
|
-
applyComposedShadow(bucket, ctx.schemes, ruleLocalVars);
|
|
456
|
-
applyComposedRing(bucket, ctx.schemes, ruleLocalVars);
|
|
502
|
+
applyComposedShadow(bucket, ctx.schemes, ruleLocalVars, ruleSchemeTables);
|
|
503
|
+
applyComposedRing(bucket, ctx.schemes, ruleLocalVars, ruleSchemeTables);
|
|
457
504
|
// Phase 2: nested rules — three orthogonal flavours, dispatched on
|
|
458
505
|
// the lightningcss node `type`:
|
|
459
506
|
// - `media`: Tailwind v4 responsive variants (`sm:`, `md:`, …) wrap
|
|
@@ -598,7 +645,7 @@ function applyMediaRule(nested, className, bucket, ctx, ruleSchemeTables, ruleLo
|
|
|
598
645
|
for (const [k, v] of collectRuleLocalVars(decls))
|
|
599
646
|
nestedLocalVars.set(k, v);
|
|
600
647
|
applyComposedTransformToScheme(schemeBucket, nestedLocalVars);
|
|
601
|
-
applyComposedShadowToScheme(schemeBucket, nestedLocalVars);
|
|
648
|
+
applyComposedShadowToScheme(schemeBucket, nestedLocalVars, table);
|
|
602
649
|
bucket[scheme] = schemeBucket;
|
|
603
650
|
}
|
|
604
651
|
}
|
|
@@ -635,7 +682,7 @@ function applyInteractiveNestedRule(nested, bucket, ctx, ruleSchemeTables, ruleL
|
|
|
635
682
|
for (const [k, v] of collectRuleLocalVars(decls))
|
|
636
683
|
nestedLocalVars.set(k, v);
|
|
637
684
|
applyComposedTransformToScheme(schemeBucket, nestedLocalVars);
|
|
638
|
-
applyComposedShadowToScheme(schemeBucket, nestedLocalVars);
|
|
685
|
+
applyComposedShadowToScheme(schemeBucket, nestedLocalVars, table);
|
|
639
686
|
bucket[scheme] = schemeBucket;
|
|
640
687
|
}
|
|
641
688
|
}
|
|
@@ -701,7 +748,7 @@ function applyNestedSchemeRule(nested, bucket, ctx, ruleSchemeTables, ruleLocalV
|
|
|
701
748
|
for (const [k, v] of collectRuleLocalVars(innerDecls))
|
|
702
749
|
nestedLocalVars.set(k, v);
|
|
703
750
|
applyComposedTransformToScheme(schemeBucket, nestedLocalVars);
|
|
704
|
-
applyComposedShadowToScheme(schemeBucket, nestedLocalVars);
|
|
751
|
+
applyComposedShadowToScheme(schemeBucket, nestedLocalVars, table);
|
|
705
752
|
bucket[targetScheme] = schemeBucket;
|
|
706
753
|
}
|
|
707
754
|
/**
|
|
@@ -802,12 +849,13 @@ function applyComposedTransformToScheme(style, ruleLocalVars) {
|
|
|
802
849
|
* prop.
|
|
803
850
|
* @param style Scheme-specific style map.
|
|
804
851
|
* @param ruleLocalVars Combined outer+nested `--tw-*` vars.
|
|
852
|
+
* @param table Per-scheme var table for resolving `var(--color-x)` in colors.
|
|
805
853
|
*/
|
|
806
|
-
function applyComposedShadowToScheme(style, ruleLocalVars) {
|
|
854
|
+
function applyComposedShadowToScheme(style, ruleLocalVars, table) {
|
|
807
855
|
const rawShadow = ruleLocalVars.get('--tw-shadow');
|
|
808
856
|
const rawShadowColor = ruleLocalVars.get('--tw-shadow-color');
|
|
809
857
|
if (!rawShadow && rawShadowColor) {
|
|
810
|
-
const color = resolveCustomColorString(rawShadowColor);
|
|
858
|
+
const color = resolveCustomColorString(rawShadowColor, table);
|
|
811
859
|
if (!color)
|
|
812
860
|
return;
|
|
813
861
|
delete style.boxShadow;
|
|
@@ -836,8 +884,9 @@ function applyComposedShadowToScheme(style, ruleLocalVars) {
|
|
|
836
884
|
* @param bucket Per-scheme style map for the atom.
|
|
837
885
|
* @param schemes Scheme names active for this parse.
|
|
838
886
|
* @param ruleLocalVars Rule-local `--tw-*` vars.
|
|
887
|
+
* @param schemeTables Per-scheme var tables for resolving `var(--color-x)`.
|
|
839
888
|
*/
|
|
840
|
-
function applyComposedShadow(bucket, schemes, ruleLocalVars) {
|
|
889
|
+
function applyComposedShadow(bucket, schemes, ruleLocalVars, schemeTables) {
|
|
841
890
|
const rawShadow = ruleLocalVars.get('--tw-shadow');
|
|
842
891
|
const rawShadowColor = ruleLocalVars.get('--tw-shadow-color');
|
|
843
892
|
// Color-only utility (`shadow-red-50`, `shadow-gray-200`, …): emit
|
|
@@ -846,10 +895,11 @@ function applyComposedShadow(bucket, schemes, ruleLocalVars) {
|
|
|
846
895
|
// where setting `--tw-shadow-color` swaps in a solid color). Offset /
|
|
847
896
|
// blur / elevation come from the partner size utility's atom.
|
|
848
897
|
if (!rawShadow && rawShadowColor) {
|
|
849
|
-
const color = resolveCustomColorString(rawShadowColor);
|
|
850
|
-
if (!color)
|
|
851
|
-
return;
|
|
852
898
|
for (const scheme of schemes) {
|
|
899
|
+
// Resolve per scheme — a custom token may differ between light/dark.
|
|
900
|
+
const color = resolveCustomColorString(rawShadowColor, schemeTables.get(scheme));
|
|
901
|
+
if (!color)
|
|
902
|
+
continue;
|
|
853
903
|
const style = bucket[scheme] ?? {};
|
|
854
904
|
delete style.boxShadow;
|
|
855
905
|
style.shadowColor = color;
|
|
@@ -882,35 +932,62 @@ function applyComposedShadow(bucket, schemes, ruleLocalVars) {
|
|
|
882
932
|
* @param bucket Per-scheme style map for the atom.
|
|
883
933
|
* @param schemes Scheme names active for this parse.
|
|
884
934
|
* @param ruleLocalVars Rule-local `--tw-*` vars.
|
|
935
|
+
* @param schemeTables Per-scheme var tables for resolving `var(--color-x)`.
|
|
885
936
|
*/
|
|
886
|
-
function applyComposedRing(bucket, schemes, ruleLocalVars) {
|
|
937
|
+
function applyComposedRing(bucket, schemes, ruleLocalVars, schemeTables) {
|
|
887
938
|
const ringColor = ruleLocalVars.get('--tw-ring-color');
|
|
888
939
|
if (!ringColor)
|
|
889
940
|
return;
|
|
890
|
-
const color = resolveCustomColorString(ringColor);
|
|
891
|
-
if (!color)
|
|
892
|
-
return;
|
|
893
941
|
for (const scheme of schemes) {
|
|
942
|
+
// Resolve per scheme — a custom token may differ between light/dark.
|
|
943
|
+
const color = resolveCustomColorString(ringColor, schemeTables.get(scheme));
|
|
944
|
+
if (!color)
|
|
945
|
+
continue;
|
|
894
946
|
const style = bucket[scheme] ?? {};
|
|
895
947
|
if (!('borderColor' in style))
|
|
896
948
|
style.borderColor = color;
|
|
897
949
|
bucket[scheme] = style;
|
|
898
950
|
}
|
|
899
951
|
}
|
|
952
|
+
/**
|
|
953
|
+
* Tailwind composable shadow/inset-shadow alpha defaults. Their `100%` lives
|
|
954
|
+
* in an `@property` initial-value (not the rule's local vars), so after the
|
|
955
|
+
* `@supports` color-mix is unwrapped, `var(--tw-shadow-alpha)` is left dangling
|
|
956
|
+
* and the shadow color fails to resolve. Seed the default; a `/<opacity>`
|
|
957
|
+
* modifier still wins because the in-rule table value overrides it.
|
|
958
|
+
*/
|
|
959
|
+
const COMPOSABLE_ALPHA_DEFAULTS = new Map([
|
|
960
|
+
['--tw-shadow-alpha', '100%'],
|
|
961
|
+
['--tw-inset-shadow-alpha', '100%'],
|
|
962
|
+
]);
|
|
900
963
|
/**
|
|
901
964
|
* Resolve a CSS color string (`oklch(0.971 0.013 17.38)`, `#ff0000`,
|
|
902
965
|
* `rgb(0 0 0 / 0.1)`) to the hex string RN's `shadowColor` accepts.
|
|
903
966
|
* Wraps culori's parser via {@link parseCssColorToHex}.
|
|
904
|
-
*
|
|
967
|
+
*
|
|
968
|
+
* Custom `@theme` color tokens arrive as `var(--color-x)` (only the default
|
|
969
|
+
* palette is `theme(inline)`-d), so `table` is substituted FIRST — without it
|
|
970
|
+
* `shadow-<token>` / `ring-<token>` silently drop the color (culori can't
|
|
971
|
+
* parse a bare `var()`). The table is per-scheme so a token that differs
|
|
972
|
+
* between light/dark resolves to the right value for each.
|
|
973
|
+
* @param raw Raw color text from a `--tw-shadow-color` / `--tw-ring-color` prop.
|
|
974
|
+
* @param table Per-scheme var table for resolving `var(--color-x)` references.
|
|
905
975
|
* @returns `#rrggbb` string, or null when culori can't parse it.
|
|
906
976
|
*/
|
|
907
|
-
function resolveCustomColorString(raw) {
|
|
908
|
-
const
|
|
909
|
-
|
|
977
|
+
function resolveCustomColorString(raw, table) {
|
|
978
|
+
const seeded = new Map([...COMPOSABLE_ALPHA_DEFAULTS, ...(table ?? [])]);
|
|
979
|
+
const substituted = substituteThemeVars(raw, seeded);
|
|
980
|
+
// `coerceUnparsedValue` collapses Tailwind's opacity shape
|
|
981
|
+
// `color-mix(in oklab, <color> <pct>%, transparent)` (emitted by
|
|
982
|
+
// `shadow-<token>` / `ring-<token>`) to a flat rgba/hex and unwraps
|
|
983
|
+
// `var(…, fallback)`. Modern spaces (`oklch(…)`) then lower via
|
|
984
|
+
// `normalizeColorString`; anything still un-RN-safe falls to culori.
|
|
985
|
+
const coerced = coerceUnparsedValue(unwrapVariableFallback(substituted).trim());
|
|
986
|
+
if (typeof coerced !== 'string' || coerced.length === 0 || coerced.startsWith('var('))
|
|
910
987
|
return null;
|
|
911
|
-
if (
|
|
912
|
-
return
|
|
913
|
-
return parseCssColorToHex(
|
|
988
|
+
if (coerced.startsWith('#') || coerced.startsWith('rgb') || coerced.startsWith('hsl'))
|
|
989
|
+
return coerced;
|
|
990
|
+
return normalizeColorString(coerced) ?? parseCssColorToHex(coerced);
|
|
914
991
|
}
|
|
915
992
|
/**
|
|
916
993
|
* Parse any CSS color expression into an `#rrggbb` string via culori.
|
|
@@ -1016,6 +1093,12 @@ function parseShadowColor(expr) {
|
|
|
1016
1093
|
return rgba;
|
|
1017
1094
|
if (working.startsWith('#'))
|
|
1018
1095
|
return { color: working, opacity: 1 };
|
|
1096
|
+
// Named (`red`) / modern (`hsl(…)`, `oklch(…)`) colors — culori → sRGB hex.
|
|
1097
|
+
// Without this they fell to the default black at 0.1 alpha, silently losing
|
|
1098
|
+
// the user's `shadow-[0_2px_4px_red]` color.
|
|
1099
|
+
const hex = formatHexSafe(working);
|
|
1100
|
+
if (hex)
|
|
1101
|
+
return { color: hex, opacity: 1 };
|
|
1019
1102
|
return { color: '#000', opacity: 0.1 };
|
|
1020
1103
|
}
|
|
1021
1104
|
/**
|
|
@@ -1220,8 +1303,8 @@ function resolveLengthExpression(text) {
|
|
|
1220
1303
|
if (evaluated.unit === '%')
|
|
1221
1304
|
return `${stripTrailingZeros(evaluated.value)}%`;
|
|
1222
1305
|
if (evaluated.unit === 'rem')
|
|
1223
|
-
return evaluated.value * 16;
|
|
1224
|
-
return evaluated.value;
|
|
1306
|
+
return roundTransformValue(evaluated.value * 16);
|
|
1307
|
+
return roundTransformValue(evaluated.value);
|
|
1225
1308
|
}
|
|
1226
1309
|
/**
|
|
1227
1310
|
* Evaluate a CSS length expression to a `{value, unit}` pair.
|
|
@@ -1448,19 +1531,38 @@ function parseArithmeticFactor(tokens, cursor) {
|
|
|
1448
1531
|
return number_;
|
|
1449
1532
|
}
|
|
1450
1533
|
/**
|
|
1451
|
-
* Resolve a scale factor expressed as a percentage (`150%`)
|
|
1534
|
+
* Resolve a scale factor expressed as a percentage (`150%`), number (`1.5`),
|
|
1535
|
+
* or a `calc()` expression. Tailwind emits NEGATIVE scale utilities as a calc
|
|
1536
|
+
* (`-scale-x-100` → `calc(100% * -1)`), so a plain percent/number regex
|
|
1537
|
+
* silently dropped them — `-scale-*` (the horizontal-flip idiom) rendered
|
|
1538
|
+
* nothing. Fall back to the shared arithmetic evaluator, reading `%` as a
|
|
1539
|
+
* fraction (`100%` → 1) and rounding off f32 noise.
|
|
1452
1540
|
* @param text Raw value.
|
|
1453
|
-
* @returns Scale number (e.g. 1.5 for 150%), or null.
|
|
1541
|
+
* @returns Scale number (e.g. 1.5 for 150%, -1 for `calc(100% * -1)`), or null.
|
|
1454
1542
|
*/
|
|
1455
1543
|
function resolveNumberOrPercent(text) {
|
|
1456
1544
|
const trimmed = text.trim();
|
|
1457
1545
|
const percent = /^(-?\d+(?:\.\d+)?)%$/.exec(trimmed);
|
|
1458
1546
|
if (percent)
|
|
1459
|
-
return Number(percent[1]) / 100;
|
|
1547
|
+
return roundTransformValue(Number(percent[1]) / 100);
|
|
1460
1548
|
const bare = /^-?\d+(?:\.\d+)?$/.exec(trimmed);
|
|
1461
1549
|
if (bare)
|
|
1462
|
-
return Number(trimmed);
|
|
1463
|
-
|
|
1550
|
+
return roundTransformValue(Number(trimmed));
|
|
1551
|
+
const evaluated = evaluateLengthExpr(trimmed);
|
|
1552
|
+
if (!evaluated || evaluated.unit === 'rem')
|
|
1553
|
+
return null;
|
|
1554
|
+
return roundTransformValue(evaluated.unit === '%' ? evaluated.value / 100 : evaluated.value);
|
|
1555
|
+
}
|
|
1556
|
+
/**
|
|
1557
|
+
* Round a composed-transform numeric value to 4 decimals. lightningcss
|
|
1558
|
+
* serializes arbitrary literals (`scale-x-[0.333]`) back as noisy f32 text
|
|
1559
|
+
* (`0.3330000042915344`), and the resolvers `Number()` that verbatim — round
|
|
1560
|
+
* so the RN `transform` array stays clean.
|
|
1561
|
+
* @param value Raw number.
|
|
1562
|
+
* @returns Rounded number.
|
|
1563
|
+
*/
|
|
1564
|
+
function roundTransformValue(value) {
|
|
1565
|
+
return Math.round(value * 10_000) / 10_000;
|
|
1464
1566
|
}
|
|
1465
1567
|
/**
|
|
1466
1568
|
* Extract the angle from Tailwind's `skewX(12deg)` / `skewY(-5deg)` /
|