rnwind 0.0.8 → 0.0.9

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 (131) hide show
  1. package/lib/cjs/core/parser/color.cjs +33 -1
  2. package/lib/cjs/core/parser/color.cjs.map +1 -1
  3. package/lib/cjs/core/parser/color.d.ts +10 -0
  4. package/lib/cjs/core/parser/declaration.cjs +121 -9
  5. package/lib/cjs/core/parser/declaration.cjs.map +1 -1
  6. package/lib/cjs/core/parser/gradient.cjs +46 -12
  7. package/lib/cjs/core/parser/gradient.cjs.map +1 -1
  8. package/lib/cjs/core/parser/gradient.d.ts +2 -1
  9. package/lib/cjs/core/parser/keyframes.cjs +27 -12
  10. package/lib/cjs/core/parser/keyframes.cjs.map +1 -1
  11. package/lib/cjs/core/parser/keyframes.d.ts +11 -0
  12. package/lib/cjs/core/parser/layout-dispatcher.cjs +33 -10
  13. package/lib/cjs/core/parser/layout-dispatcher.cjs.map +1 -1
  14. package/lib/cjs/core/parser/length.cjs +17 -1
  15. package/lib/cjs/core/parser/length.cjs.map +1 -1
  16. package/lib/cjs/core/parser/safe-area.cjs +24 -3
  17. package/lib/cjs/core/parser/safe-area.cjs.map +1 -1
  18. package/lib/cjs/core/parser/theme-vars.cjs +58 -8
  19. package/lib/cjs/core/parser/theme-vars.cjs.map +1 -1
  20. package/lib/cjs/core/parser/tokens.cjs +77 -9
  21. package/lib/cjs/core/parser/tokens.cjs.map +1 -1
  22. package/lib/cjs/core/parser/tokens.d.ts +9 -0
  23. package/lib/cjs/core/parser/transform.cjs +18 -9
  24. package/lib/cjs/core/parser/transform.cjs.map +1 -1
  25. package/lib/cjs/core/parser/tw-parser.cjs +93 -33
  26. package/lib/cjs/core/parser/tw-parser.cjs.map +1 -1
  27. package/lib/cjs/core/parser/typography-dispatcher.cjs +19 -1
  28. package/lib/cjs/core/parser/typography-dispatcher.cjs.map +1 -1
  29. package/lib/cjs/core/parser/typography.cjs +15 -18
  30. package/lib/cjs/core/parser/typography.cjs.map +1 -1
  31. package/lib/cjs/core/parser/typography.d.ts +5 -5
  32. package/lib/cjs/core/style-builder/union-builder.cjs +0 -10
  33. package/lib/cjs/core/style-builder/union-builder.cjs.map +1 -1
  34. package/lib/cjs/core/style-builder/union-builder.d.ts +0 -8
  35. package/lib/cjs/metro/dts.cjs +6 -1
  36. package/lib/cjs/metro/dts.cjs.map +1 -1
  37. package/lib/cjs/metro/transformer.cjs +42 -77
  38. package/lib/cjs/metro/transformer.cjs.map +1 -1
  39. package/lib/cjs/metro/with-config.cjs +9 -29
  40. package/lib/cjs/metro/with-config.cjs.map +1 -1
  41. package/lib/cjs/runtime/hooks/use-scheme.cjs +9 -6
  42. package/lib/cjs/runtime/hooks/use-scheme.cjs.map +1 -1
  43. package/lib/cjs/runtime/hooks/use-scheme.d.ts +7 -4
  44. package/lib/cjs/runtime/index.cjs +1 -1
  45. package/lib/cjs/runtime/index.cjs.map +1 -1
  46. package/lib/cjs/runtime/index.d.ts +1 -1
  47. package/lib/cjs/runtime/lookup-css.cjs +14 -0
  48. package/lib/cjs/runtime/lookup-css.cjs.map +1 -1
  49. package/lib/cjs/runtime/lookup-css.d.ts +11 -0
  50. package/lib/cjs/runtime/resolve.cjs +8 -6
  51. package/lib/cjs/runtime/resolve.cjs.map +1 -1
  52. package/lib/cjs/runtime/wrap.cjs +50 -57
  53. package/lib/cjs/runtime/wrap.cjs.map +1 -1
  54. package/lib/cjs/runtime/wrap.d.ts +10 -4
  55. package/lib/esm/core/parser/color.d.ts +10 -0
  56. package/lib/esm/core/parser/color.mjs +33 -2
  57. package/lib/esm/core/parser/color.mjs.map +1 -1
  58. package/lib/esm/core/parser/declaration.mjs +122 -10
  59. package/lib/esm/core/parser/declaration.mjs.map +1 -1
  60. package/lib/esm/core/parser/gradient.d.ts +2 -1
  61. package/lib/esm/core/parser/gradient.mjs +45 -11
  62. package/lib/esm/core/parser/gradient.mjs.map +1 -1
  63. package/lib/esm/core/parser/keyframes.d.ts +11 -0
  64. package/lib/esm/core/parser/keyframes.mjs +27 -12
  65. package/lib/esm/core/parser/keyframes.mjs.map +1 -1
  66. package/lib/esm/core/parser/layout-dispatcher.mjs +33 -10
  67. package/lib/esm/core/parser/layout-dispatcher.mjs.map +1 -1
  68. package/lib/esm/core/parser/length.mjs +17 -1
  69. package/lib/esm/core/parser/length.mjs.map +1 -1
  70. package/lib/esm/core/parser/safe-area.mjs +24 -3
  71. package/lib/esm/core/parser/safe-area.mjs.map +1 -1
  72. package/lib/esm/core/parser/theme-vars.mjs +58 -8
  73. package/lib/esm/core/parser/theme-vars.mjs.map +1 -1
  74. package/lib/esm/core/parser/tokens.d.ts +9 -0
  75. package/lib/esm/core/parser/tokens.mjs +77 -10
  76. package/lib/esm/core/parser/tokens.mjs.map +1 -1
  77. package/lib/esm/core/parser/transform.mjs +18 -9
  78. package/lib/esm/core/parser/transform.mjs.map +1 -1
  79. package/lib/esm/core/parser/tw-parser.mjs +95 -35
  80. package/lib/esm/core/parser/tw-parser.mjs.map +1 -1
  81. package/lib/esm/core/parser/typography-dispatcher.mjs +19 -1
  82. package/lib/esm/core/parser/typography-dispatcher.mjs.map +1 -1
  83. package/lib/esm/core/parser/typography.d.ts +5 -5
  84. package/lib/esm/core/parser/typography.mjs +15 -18
  85. package/lib/esm/core/parser/typography.mjs.map +1 -1
  86. package/lib/esm/core/style-builder/union-builder.d.ts +0 -8
  87. package/lib/esm/core/style-builder/union-builder.mjs +0 -10
  88. package/lib/esm/core/style-builder/union-builder.mjs.map +1 -1
  89. package/lib/esm/metro/dts.mjs +6 -1
  90. package/lib/esm/metro/dts.mjs.map +1 -1
  91. package/lib/esm/metro/transformer.mjs +42 -77
  92. package/lib/esm/metro/transformer.mjs.map +1 -1
  93. package/lib/esm/metro/with-config.mjs +10 -30
  94. package/lib/esm/metro/with-config.mjs.map +1 -1
  95. package/lib/esm/runtime/hooks/use-scheme.d.ts +7 -4
  96. package/lib/esm/runtime/hooks/use-scheme.mjs +9 -6
  97. package/lib/esm/runtime/hooks/use-scheme.mjs.map +1 -1
  98. package/lib/esm/runtime/index.d.ts +1 -1
  99. package/lib/esm/runtime/index.mjs +1 -1
  100. package/lib/esm/runtime/index.mjs.map +1 -1
  101. package/lib/esm/runtime/lookup-css.d.ts +11 -0
  102. package/lib/esm/runtime/lookup-css.mjs +14 -1
  103. package/lib/esm/runtime/lookup-css.mjs.map +1 -1
  104. package/lib/esm/runtime/resolve.mjs +9 -7
  105. package/lib/esm/runtime/resolve.mjs.map +1 -1
  106. package/lib/esm/runtime/wrap.d.ts +10 -4
  107. package/lib/esm/runtime/wrap.mjs +50 -57
  108. package/lib/esm/runtime/wrap.mjs.map +1 -1
  109. package/package.json +1 -1
  110. package/src/core/parser/color.ts +32 -1
  111. package/src/core/parser/declaration.ts +119 -10
  112. package/src/core/parser/gradient.ts +48 -11
  113. package/src/core/parser/keyframes.ts +31 -3
  114. package/src/core/parser/layout-dispatcher.ts +32 -9
  115. package/src/core/parser/length.ts +18 -1
  116. package/src/core/parser/safe-area.ts +23 -2
  117. package/src/core/parser/theme-vars.ts +75 -8
  118. package/src/core/parser/tokens.ts +76 -9
  119. package/src/core/parser/transform.ts +19 -8
  120. package/src/core/parser/tw-parser.ts +95 -30
  121. package/src/core/parser/typography-dispatcher.ts +20 -1
  122. package/src/core/parser/typography.ts +15 -15
  123. package/src/core/style-builder/union-builder.ts +0 -11
  124. package/src/metro/dts.ts +6 -1
  125. package/src/metro/transformer.ts +42 -78
  126. package/src/metro/with-config.ts +10 -29
  127. package/src/runtime/hooks/use-scheme.ts +9 -6
  128. package/src/runtime/index.ts +1 -1
  129. package/src/runtime/lookup-css.ts +14 -0
  130. package/src/runtime/resolve.ts +9 -7
  131. package/src/runtime/wrap.tsx +57 -61
@@ -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, keyframeSelectorOffset, pickAnimationName } from './keyframes.mjs';
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 { serializeTokens, substituteThemeVars, coerceUnparsedValue } from './tokens.mjs';
13
+ import { normalizeColorString } from './color.mjs';
13
14
 
14
15
  /**
15
16
  * Default LightningCSS transform options for TailwindParser's visitor.
@@ -281,7 +282,8 @@ class TailwindParser {
281
282
  // surface their role + resolved colour so the transformer
282
283
  // can rewrite `<LinearGradient className="...">` into
283
284
  // `colors={...}` / `start={...}` / `end={...}` props.
284
- const gradient = detectGradientAtom(rule.value.declarations.declarations);
285
+ const gradientTable = schemeTables.get(BASE_SCHEME) ?? schemeTables.get(schemes[0] ?? BASE_SCHEME);
286
+ const gradient = detectGradientAtom(rule.value.declarations.declarations, gradientTable);
285
287
  if (gradient)
286
288
  gradientAtoms.set(className, gradient);
287
289
  // Haptics may live on the rule directly OR inside a
@@ -302,8 +304,8 @@ class TailwindParser {
302
304
  const steps = [];
303
305
  const baseTable = schemeTables.get(BASE_SCHEME) ?? schemeTables.get(schemes[0] ?? BASE_SCHEME);
304
306
  for (const frame of rule.value.keyframes) {
305
- const offset = keyframeSelectorOffset(frame.selectors);
306
- if (!offset)
307
+ const offsets = keyframeSelectorOffsets(frame.selectors);
308
+ if (offsets.length === 0)
307
309
  continue;
308
310
  const style = {};
309
311
  const frameDecls = frame.declarations.declarations ?? [];
@@ -311,7 +313,10 @@ class TailwindParser {
311
313
  for (const [key, value] of declarationToRnEntries(decl, baseTable))
312
314
  style[key] = value;
313
315
  }
314
- steps.push({ offset, style });
316
+ // One frame can carry several offsets (`0%, 100% { }`); emit a
317
+ // step for each so the terminal frame isn't lost.
318
+ for (const offset of offsets)
319
+ steps.push({ offset, style });
315
320
  }
316
321
  keyframes.set(name, { name, steps });
317
322
  },
@@ -452,8 +457,8 @@ function processStyleRule(declarations, className, ctx, nestedRules = []) {
452
457
  ctx.referencedKeyframes.add(animationRef);
453
458
  }
454
459
  applyComposedTransform(bucket, ctx.schemes, ruleLocalVars);
455
- applyComposedShadow(bucket, ctx.schemes, ruleLocalVars);
456
- applyComposedRing(bucket, ctx.schemes, ruleLocalVars);
460
+ applyComposedShadow(bucket, ctx.schemes, ruleLocalVars, ruleSchemeTables);
461
+ applyComposedRing(bucket, ctx.schemes, ruleLocalVars, ruleSchemeTables);
457
462
  // Phase 2: nested rules — three orthogonal flavours, dispatched on
458
463
  // the lightningcss node `type`:
459
464
  // - `media`: Tailwind v4 responsive variants (`sm:`, `md:`, …) wrap
@@ -598,7 +603,7 @@ function applyMediaRule(nested, className, bucket, ctx, ruleSchemeTables, ruleLo
598
603
  for (const [k, v] of collectRuleLocalVars(decls))
599
604
  nestedLocalVars.set(k, v);
600
605
  applyComposedTransformToScheme(schemeBucket, nestedLocalVars);
601
- applyComposedShadowToScheme(schemeBucket, nestedLocalVars);
606
+ applyComposedShadowToScheme(schemeBucket, nestedLocalVars, table);
602
607
  bucket[scheme] = schemeBucket;
603
608
  }
604
609
  }
@@ -635,7 +640,7 @@ function applyInteractiveNestedRule(nested, bucket, ctx, ruleSchemeTables, ruleL
635
640
  for (const [k, v] of collectRuleLocalVars(decls))
636
641
  nestedLocalVars.set(k, v);
637
642
  applyComposedTransformToScheme(schemeBucket, nestedLocalVars);
638
- applyComposedShadowToScheme(schemeBucket, nestedLocalVars);
643
+ applyComposedShadowToScheme(schemeBucket, nestedLocalVars, table);
639
644
  bucket[scheme] = schemeBucket;
640
645
  }
641
646
  }
@@ -701,7 +706,7 @@ function applyNestedSchemeRule(nested, bucket, ctx, ruleSchemeTables, ruleLocalV
701
706
  for (const [k, v] of collectRuleLocalVars(innerDecls))
702
707
  nestedLocalVars.set(k, v);
703
708
  applyComposedTransformToScheme(schemeBucket, nestedLocalVars);
704
- applyComposedShadowToScheme(schemeBucket, nestedLocalVars);
709
+ applyComposedShadowToScheme(schemeBucket, nestedLocalVars, table);
705
710
  bucket[targetScheme] = schemeBucket;
706
711
  }
707
712
  /**
@@ -802,12 +807,13 @@ function applyComposedTransformToScheme(style, ruleLocalVars) {
802
807
  * prop.
803
808
  * @param style Scheme-specific style map.
804
809
  * @param ruleLocalVars Combined outer+nested `--tw-*` vars.
810
+ * @param table Per-scheme var table for resolving `var(--color-x)` in colors.
805
811
  */
806
- function applyComposedShadowToScheme(style, ruleLocalVars) {
812
+ function applyComposedShadowToScheme(style, ruleLocalVars, table) {
807
813
  const rawShadow = ruleLocalVars.get('--tw-shadow');
808
814
  const rawShadowColor = ruleLocalVars.get('--tw-shadow-color');
809
815
  if (!rawShadow && rawShadowColor) {
810
- const color = resolveCustomColorString(rawShadowColor);
816
+ const color = resolveCustomColorString(rawShadowColor, table);
811
817
  if (!color)
812
818
  return;
813
819
  delete style.boxShadow;
@@ -836,8 +842,9 @@ function applyComposedShadowToScheme(style, ruleLocalVars) {
836
842
  * @param bucket Per-scheme style map for the atom.
837
843
  * @param schemes Scheme names active for this parse.
838
844
  * @param ruleLocalVars Rule-local `--tw-*` vars.
845
+ * @param schemeTables Per-scheme var tables for resolving `var(--color-x)`.
839
846
  */
840
- function applyComposedShadow(bucket, schemes, ruleLocalVars) {
847
+ function applyComposedShadow(bucket, schemes, ruleLocalVars, schemeTables) {
841
848
  const rawShadow = ruleLocalVars.get('--tw-shadow');
842
849
  const rawShadowColor = ruleLocalVars.get('--tw-shadow-color');
843
850
  // Color-only utility (`shadow-red-50`, `shadow-gray-200`, …): emit
@@ -846,10 +853,11 @@ function applyComposedShadow(bucket, schemes, ruleLocalVars) {
846
853
  // where setting `--tw-shadow-color` swaps in a solid color). Offset /
847
854
  // blur / elevation come from the partner size utility's atom.
848
855
  if (!rawShadow && rawShadowColor) {
849
- const color = resolveCustomColorString(rawShadowColor);
850
- if (!color)
851
- return;
852
856
  for (const scheme of schemes) {
857
+ // Resolve per scheme — a custom token may differ between light/dark.
858
+ const color = resolveCustomColorString(rawShadowColor, schemeTables.get(scheme));
859
+ if (!color)
860
+ continue;
853
861
  const style = bucket[scheme] ?? {};
854
862
  delete style.boxShadow;
855
863
  style.shadowColor = color;
@@ -882,35 +890,62 @@ function applyComposedShadow(bucket, schemes, ruleLocalVars) {
882
890
  * @param bucket Per-scheme style map for the atom.
883
891
  * @param schemes Scheme names active for this parse.
884
892
  * @param ruleLocalVars Rule-local `--tw-*` vars.
893
+ * @param schemeTables Per-scheme var tables for resolving `var(--color-x)`.
885
894
  */
886
- function applyComposedRing(bucket, schemes, ruleLocalVars) {
895
+ function applyComposedRing(bucket, schemes, ruleLocalVars, schemeTables) {
887
896
  const ringColor = ruleLocalVars.get('--tw-ring-color');
888
897
  if (!ringColor)
889
898
  return;
890
- const color = resolveCustomColorString(ringColor);
891
- if (!color)
892
- return;
893
899
  for (const scheme of schemes) {
900
+ // Resolve per scheme — a custom token may differ between light/dark.
901
+ const color = resolveCustomColorString(ringColor, schemeTables.get(scheme));
902
+ if (!color)
903
+ continue;
894
904
  const style = bucket[scheme] ?? {};
895
905
  if (!('borderColor' in style))
896
906
  style.borderColor = color;
897
907
  bucket[scheme] = style;
898
908
  }
899
909
  }
910
+ /**
911
+ * Tailwind composable shadow/inset-shadow alpha defaults. Their `100%` lives
912
+ * in an `@property` initial-value (not the rule's local vars), so after the
913
+ * `@supports` color-mix is unwrapped, `var(--tw-shadow-alpha)` is left dangling
914
+ * and the shadow color fails to resolve. Seed the default; a `/<opacity>`
915
+ * modifier still wins because the in-rule table value overrides it.
916
+ */
917
+ const COMPOSABLE_ALPHA_DEFAULTS = new Map([
918
+ ['--tw-shadow-alpha', '100%'],
919
+ ['--tw-inset-shadow-alpha', '100%'],
920
+ ]);
900
921
  /**
901
922
  * Resolve a CSS color string (`oklch(0.971 0.013 17.38)`, `#ff0000`,
902
923
  * `rgb(0 0 0 / 0.1)`) to the hex string RN's `shadowColor` accepts.
903
924
  * Wraps culori's parser via {@link parseCssColorToHex}.
904
- * @param raw Raw color text from a `--tw-shadow-color` custom prop.
925
+ *
926
+ * Custom `@theme` color tokens arrive as `var(--color-x)` (only the default
927
+ * palette is `theme(inline)`-d), so `table` is substituted FIRST — without it
928
+ * `shadow-<token>` / `ring-<token>` silently drop the color (culori can't
929
+ * parse a bare `var()`). The table is per-scheme so a token that differs
930
+ * between light/dark resolves to the right value for each.
931
+ * @param raw Raw color text from a `--tw-shadow-color` / `--tw-ring-color` prop.
932
+ * @param table Per-scheme var table for resolving `var(--color-x)` references.
905
933
  * @returns `#rrggbb` string, or null when culori can't parse it.
906
934
  */
907
- function resolveCustomColorString(raw) {
908
- const text = unwrapVariableFallback(raw).trim();
909
- if (text.length === 0)
935
+ function resolveCustomColorString(raw, table) {
936
+ const seeded = new Map([...COMPOSABLE_ALPHA_DEFAULTS, ...(table ?? [])]);
937
+ const substituted = substituteThemeVars(raw, seeded);
938
+ // `coerceUnparsedValue` collapses Tailwind's opacity shape
939
+ // `color-mix(in oklab, <color> <pct>%, transparent)` (emitted by
940
+ // `shadow-<token>` / `ring-<token>`) to a flat rgba/hex and unwraps
941
+ // `var(…, fallback)`. Modern spaces (`oklch(…)`) then lower via
942
+ // `normalizeColorString`; anything still un-RN-safe falls to culori.
943
+ const coerced = coerceUnparsedValue(unwrapVariableFallback(substituted).trim());
944
+ if (typeof coerced !== 'string' || coerced.length === 0 || coerced.startsWith('var('))
910
945
  return null;
911
- if (text.startsWith('#'))
912
- return text;
913
- return parseCssColorToHex(text);
946
+ if (coerced.startsWith('#') || coerced.startsWith('rgb') || coerced.startsWith('hsl'))
947
+ return coerced;
948
+ return normalizeColorString(coerced) ?? parseCssColorToHex(coerced);
914
949
  }
915
950
  /**
916
951
  * Parse any CSS color expression into an `#rrggbb` string via culori.
@@ -1016,6 +1051,12 @@ function parseShadowColor(expr) {
1016
1051
  return rgba;
1017
1052
  if (working.startsWith('#'))
1018
1053
  return { color: working, opacity: 1 };
1054
+ // Named (`red`) / modern (`hsl(…)`, `oklch(…)`) colors — culori → sRGB hex.
1055
+ // Without this they fell to the default black at 0.1 alpha, silently losing
1056
+ // the user's `shadow-[0_2px_4px_red]` color.
1057
+ const hex = formatHexSafe(working);
1058
+ if (hex)
1059
+ return { color: hex, opacity: 1 };
1019
1060
  return { color: '#000', opacity: 0.1 };
1020
1061
  }
1021
1062
  /**
@@ -1220,8 +1261,8 @@ function resolveLengthExpression(text) {
1220
1261
  if (evaluated.unit === '%')
1221
1262
  return `${stripTrailingZeros(evaluated.value)}%`;
1222
1263
  if (evaluated.unit === 'rem')
1223
- return evaluated.value * 16;
1224
- return evaluated.value;
1264
+ return roundTransformValue(evaluated.value * 16);
1265
+ return roundTransformValue(evaluated.value);
1225
1266
  }
1226
1267
  /**
1227
1268
  * Evaluate a CSS length expression to a `{value, unit}` pair.
@@ -1448,19 +1489,38 @@ function parseArithmeticFactor(tokens, cursor) {
1448
1489
  return number_;
1449
1490
  }
1450
1491
  /**
1451
- * Resolve a scale factor expressed as a percentage (`150%`) or number (`1.5`).
1492
+ * Resolve a scale factor expressed as a percentage (`150%`), number (`1.5`),
1493
+ * or a `calc()` expression. Tailwind emits NEGATIVE scale utilities as a calc
1494
+ * (`-scale-x-100` → `calc(100% * -1)`), so a plain percent/number regex
1495
+ * silently dropped them — `-scale-*` (the horizontal-flip idiom) rendered
1496
+ * nothing. Fall back to the shared arithmetic evaluator, reading `%` as a
1497
+ * fraction (`100%` → 1) and rounding off f32 noise.
1452
1498
  * @param text Raw value.
1453
- * @returns Scale number (e.g. 1.5 for 150%), or null.
1499
+ * @returns Scale number (e.g. 1.5 for 150%, -1 for `calc(100% * -1)`), or null.
1454
1500
  */
1455
1501
  function resolveNumberOrPercent(text) {
1456
1502
  const trimmed = text.trim();
1457
1503
  const percent = /^(-?\d+(?:\.\d+)?)%$/.exec(trimmed);
1458
1504
  if (percent)
1459
- return Number(percent[1]) / 100;
1505
+ return roundTransformValue(Number(percent[1]) / 100);
1460
1506
  const bare = /^-?\d+(?:\.\d+)?$/.exec(trimmed);
1461
1507
  if (bare)
1462
- return Number(trimmed);
1463
- return null;
1508
+ return roundTransformValue(Number(trimmed));
1509
+ const evaluated = evaluateLengthExpr(trimmed);
1510
+ if (!evaluated || evaluated.unit === 'rem')
1511
+ return null;
1512
+ return roundTransformValue(evaluated.unit === '%' ? evaluated.value / 100 : evaluated.value);
1513
+ }
1514
+ /**
1515
+ * Round a composed-transform numeric value to 4 decimals. lightningcss
1516
+ * serializes arbitrary literals (`scale-x-[0.333]`) back as noisy f32 text
1517
+ * (`0.3330000042915344`), and the resolvers `Number()` that verbatim — round
1518
+ * so the RN `transform` array stays clean.
1519
+ * @param value Raw number.
1520
+ * @returns Rounded number.
1521
+ */
1522
+ function roundTransformValue(value) {
1523
+ return Math.round(value * 10_000) / 10_000;
1464
1524
  }
1465
1525
  /**
1466
1526
  * Extract the angle from Tailwind's `skewX(12deg)` / `skewY(-5deg)` /