rnwind 0.0.7 → 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.
- 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 +161 -10
- 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 +93 -33
- package/lib/cjs/core/parser/tw-parser.cjs.map +1 -1
- 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/union-builder.cjs +0 -10
- package/lib/cjs/core/style-builder/union-builder.cjs.map +1 -1
- package/lib/cjs/core/style-builder/union-builder.d.ts +0 -8
- package/lib/cjs/metro/dts.cjs +6 -1
- package/lib/cjs/metro/dts.cjs.map +1 -1
- package/lib/cjs/metro/transformer.cjs +43 -60
- 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 +9 -6
- 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 +1 -1
- package/lib/cjs/runtime/index.cjs.map +1 -1
- package/lib/cjs/runtime/index.d.ts +1 -1
- package/lib/cjs/runtime/lookup-css.cjs +14 -0
- package/lib/cjs/runtime/lookup-css.cjs.map +1 -1
- package/lib/cjs/runtime/lookup-css.d.ts +11 -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/esm/core/parser/color.d.ts +10 -0
- package/lib/esm/core/parser/color.mjs +33 -2
- package/lib/esm/core/parser/color.mjs.map +1 -1
- package/lib/esm/core/parser/declaration.mjs +162 -11
- 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.mjs +95 -35
- 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/union-builder.d.ts +0 -8
- package/lib/esm/core/style-builder/union-builder.mjs +0 -10
- 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 +43 -60
- 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 +9 -6
- package/lib/esm/runtime/hooks/use-scheme.mjs.map +1 -1
- package/lib/esm/runtime/index.d.ts +1 -1
- package/lib/esm/runtime/index.mjs +1 -1
- package/lib/esm/runtime/index.mjs.map +1 -1
- package/lib/esm/runtime/lookup-css.d.ts +11 -0
- package/lib/esm/runtime/lookup-css.mjs +14 -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/package.json +1 -1
- package/src/core/parser/color.ts +32 -1
- package/src/core/parser/declaration.ts +160 -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 +95 -30
- package/src/core/parser/typography-dispatcher.ts +20 -1
- package/src/core/parser/typography.ts +15 -15
- package/src/core/style-builder/union-builder.ts +0 -11
- package/src/metro/dts.ts +6 -1
- package/src/metro/transformer.ts +45 -61
- package/src/metro/with-config.ts +10 -29
- package/src/runtime/hooks/use-scheme.ts +9 -6
- package/src/runtime/index.ts +1 -1
- package/src/runtime/lookup-css.ts +14 -0
- package/src/runtime/resolve.ts +9 -7
- package/src/runtime/wrap.tsx +57 -61
|
@@ -96,39 +96,48 @@ function angleToString(angle) {
|
|
|
96
96
|
}
|
|
97
97
|
/**
|
|
98
98
|
* Convert a `NumberOrPercentage` to a plain number. Percentages become
|
|
99
|
-
* their fractional equivalent (e.g. `50%` → `0.5`).
|
|
99
|
+
* their fractional equivalent (e.g. `50%` → `0.5`). Rounded so a literal
|
|
100
|
+
* like `scale-[1.7]` doesn't carry lightningcss's f32 noise
|
|
101
|
+
* (`1.7000000476837158`) into the RN `transform` array.
|
|
100
102
|
* @param value Typed value.
|
|
101
103
|
* @returns Plain number.
|
|
102
104
|
*/
|
|
103
105
|
function numberOrPercentageToNumber(value) {
|
|
104
|
-
|
|
105
|
-
return value.value;
|
|
106
|
-
return value.value;
|
|
106
|
+
return roundNumber(value.value);
|
|
107
107
|
}
|
|
108
108
|
/**
|
|
109
109
|
* Convert a length-or-percentage used by translate into the shape RN
|
|
110
110
|
* accepts (`number` for px, `string` for `%`). Percentages stay as
|
|
111
|
-
* strings so RN layout can resolve them against the element size.
|
|
111
|
+
* strings so RN layout can resolve them against the element size. Pixel
|
|
112
|
+
* values are rounded to shed f32 noise (`3.3px` → `3.299999952…`).
|
|
112
113
|
* @param value Typed length or percentage.
|
|
113
114
|
* @returns RN-style translate value.
|
|
114
115
|
*/
|
|
115
116
|
function lengthOrPercentToNumber(value) {
|
|
116
117
|
if (value.type === 'dimension')
|
|
117
|
-
return length.lengthToPx(value.value);
|
|
118
|
+
return roundNumber(length.lengthToPx(value.value));
|
|
118
119
|
if (value.type === 'value')
|
|
119
|
-
return length.lengthToPx(value.value);
|
|
120
|
+
return roundNumber(length.lengthToPx(value.value));
|
|
120
121
|
if (value.type === 'percentage')
|
|
121
122
|
return `${formatNumber(value.value * 100)}%`;
|
|
122
123
|
return 0;
|
|
123
124
|
}
|
|
125
|
+
/**
|
|
126
|
+
* Round a number to 4 decimals — sheds lightningcss's f32 representation
|
|
127
|
+
* noise while staying well below subpixel / sub-percent precision.
|
|
128
|
+
* @param value Raw number.
|
|
129
|
+
* @returns Rounded number.
|
|
130
|
+
*/
|
|
131
|
+
function roundNumber(value) {
|
|
132
|
+
return Math.round(value * 10_000) / 10_000;
|
|
133
|
+
}
|
|
124
134
|
/**
|
|
125
135
|
* Render a number without trailing IEEE noise.
|
|
126
136
|
* @param value Number to format.
|
|
127
137
|
* @returns Compact string form.
|
|
128
138
|
*/
|
|
129
139
|
function formatNumber(value) {
|
|
130
|
-
|
|
131
|
-
return String(rounded);
|
|
140
|
+
return String(roundNumber(value));
|
|
132
141
|
}
|
|
133
142
|
/**
|
|
134
143
|
* Convert lightningcss's typed `transform: ...` value into RN's
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transform.cjs","sources":["../../../../../src/core/parser/transform.ts"],"sourcesContent":["import type { Angle, LengthValue, NumberOrPercentage, Rotate, Scale, Transform, Translate } from 'lightningcss'\nimport type { RNEntry } from './types'\nimport { lengthToPx } from './length'\n\ntype RnTransformRecord = Record<string, string | number>\n\ntype DimensionPercent =\n | { type: 'dimension'; value: LengthValue }\n | { type: 'percentage'; value: number }\n | { type: 'calc'; value: unknown }\n\n/**\n * Map a single typed transform function into zero-or-more RN transform\n * operations. Compound ops (like `translate`, `scale`, `skew`) expand\n * into per-axis entries the way RN expects them.\n * @param fn Typed transform function.\n * @returns RN transform operations.\n */\nfunction mapTransformFunction(fn: Transform): RnTransformRecord[] | null {\n switch (fn.type) {\n case 'rotate':\n case 'rotateZ': {\n return [{ rotate: angleToString(fn.value) }]\n }\n case 'rotateX': {\n return [{ rotateX: angleToString(fn.value) }]\n }\n case 'rotateY': {\n return [{ rotateY: angleToString(fn.value) }]\n }\n case 'scale': {\n const [x, y] = fn.value\n return [{ scaleX: numberOrPercentageToNumber(x) }, { scaleY: numberOrPercentageToNumber(y) }]\n }\n case 'scaleX': {\n return [{ scaleX: numberOrPercentageToNumber(fn.value) }]\n }\n case 'scaleY': {\n return [{ scaleY: numberOrPercentageToNumber(fn.value) }]\n }\n case 'translateX': {\n return [{ translateX: lengthOrPercentToNumber(fn.value) }]\n }\n case 'translateY': {\n return [{ translateY: lengthOrPercentToNumber(fn.value) }]\n }\n case 'translate': {\n const [x, y] = fn.value\n const out: RnTransformRecord[] = [{ translateX: lengthOrPercentToNumber(x) }]\n if (y) out.push({ translateY: lengthOrPercentToNumber(y) })\n return out\n }\n case 'translate3d': {\n const [x, y] = fn.value\n return [{ translateX: lengthOrPercentToNumber(x) }, { translateY: lengthOrPercentToNumber(y) }]\n }\n case 'skew': {\n const [x, y] = fn.value\n const out: RnTransformRecord[] = [{ skewX: angleToString(x) }]\n if (y) out.push({ skewY: angleToString(y) })\n return out\n }\n case 'skewX': {\n return [{ skewX: angleToString(fn.value) }]\n }\n case 'skewY': {\n return [{ skewY: angleToString(fn.value) }]\n }\n default: {\n // RN doesn't have a direct equivalent for `matrix()` / `matrix3d()` /\n // `perspective()` at the transform-op level — skip silently. Tailwind's\n // generated transforms stay within rotate/translate/scale/skew.\n return null\n }\n }\n}\n\n/**\n * Serialize a typed angle into the CSS degree string RN accepts\n * (`'45deg'`, `'0.5turn'` → `'180deg'`).\n * @param angle Typed angle.\n * @returns Degree string.\n */\nfunction angleToString(angle: Angle): string {\n switch (angle.type) {\n case 'deg': {\n return `${formatNumber(angle.value)}deg`\n }\n case 'rad': {\n return `${formatNumber((angle.value * 180) / Math.PI)}deg`\n }\n case 'grad': {\n return `${formatNumber((angle.value * 360) / 400)}deg`\n }\n case 'turn': {\n return `${formatNumber(angle.value * 360)}deg`\n }\n default: {\n return '0deg'\n }\n }\n}\n\n/**\n * Convert a `NumberOrPercentage` to a plain number. Percentages become\n * their fractional equivalent (e.g. `50%` → `0.5`).\n * @param value Typed value.\n * @returns Plain number.\n */\nfunction numberOrPercentageToNumber(value: NumberOrPercentage): number {\n if (value.type === 'percentage') return value.value\n return value.value\n}\n\n/**\n * Convert a length-or-percentage used by translate into the shape RN\n * accepts (`number` for px, `string` for `%`). Percentages stay as\n * strings so RN layout can resolve them against the element size.\n * @param value Typed length or percentage.\n * @returns RN-style translate value.\n */\nfunction lengthOrPercentToNumber(value: DimensionPercent | { type: 'value'; value: LengthValue }): number | string {\n if (value.type === 'dimension') return lengthToPx(value.value)\n if (value.type === 'value') return lengthToPx(value.value)\n if (value.type === 'percentage') return `${formatNumber(value.value * 100)}%`\n return 0\n}\n\n/**\n * Render a number without trailing IEEE noise.\n * @param value Number to format.\n * @returns Compact string form.\n */\nfunction formatNumber(value: number): string {\n const rounded = Math.round(value * 10_000) / 10_000\n return String(rounded)\n}\n\n/**\n * Convert lightningcss's typed `transform: ...` value into RN's\n * `transform: [{ op: value }, ...]` array. RN supports a restricted subset\n * of CSS transforms — this function picks out the ones it actually\n * handles and drops the rest.\n *\n * Reanimated v4's CSS engine reads this same array shape, so the output\n * is drop-in for both static RN `style` props and `Animated.View` styles.\n * @param fns Typed transform function list.\n * @returns Zero-or-one RN entry with the `transform` array.\n */\nexport function transformFunctionsToEntries(fns: readonly Transform[]): readonly RNEntry[] {\n const ops: RnTransformRecord[] = []\n for (const fn of fns) {\n const mapped = mapTransformFunction(fn)\n if (mapped) ops.push(...mapped)\n }\n if (ops.length === 0) return []\n return [['transform', ops]]\n}\n\n/**\n * Convert Tailwind v4's typed `rotate: ...` (individual property) into\n * the RN transform array. Tailwind's `rotate-*` utilities emit this\n * property rather than the classic `transform: rotate(...)` shorthand.\n * @param value Typed rotate value.\n * @returns Zero-or-one RN entry.\n */\nexport function rotateToEntries(value: Rotate | 'none'): readonly RNEntry[] {\n if (value === 'none') return []\n return [['transform', [{ rotate: angleToString(value.angle) }]]]\n}\n\n/**\n * Convert Tailwind v4's typed `translate: ...` into the RN transform\n * array. Both axes are emitted as separate ops so each is independently\n * animatable by Reanimated.\n * @param value Typed translate value.\n * @returns Zero-or-one RN entry.\n */\nexport function translateToEntries(value: Translate | 'none'): readonly RNEntry[] {\n if (value === 'none') return []\n const ops: RnTransformRecord[] = [{ translateX: lengthOrPercentToNumber(value.x) }]\n const yNumber = lengthOrPercentToNumber(value.y)\n if (yNumber !== 0) ops.push({ translateY: yNumber })\n return [['transform', ops]]\n}\n\n/**\n * Convert Tailwind v4's typed `scale: ...` into the RN transform array.\n * @param value Typed scale value.\n * @returns Zero-or-one RN entry.\n */\nexport function scaleToEntries(value: Scale | 'none'): readonly RNEntry[] {\n if (value === 'none') return []\n return [['transform', [{ scaleX: numberOrPercentageToNumber(value.x) }, { scaleY: numberOrPercentageToNumber(value.y) }]]]\n}\n"],"names":["lengthToPx"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"transform.cjs","sources":["../../../../../src/core/parser/transform.ts"],"sourcesContent":["import type { Angle, LengthValue, NumberOrPercentage, Rotate, Scale, Transform, Translate } from 'lightningcss'\nimport type { RNEntry } from './types'\nimport { lengthToPx } from './length'\n\ntype RnTransformRecord = Record<string, string | number>\n\ntype DimensionPercent =\n | { type: 'dimension'; value: LengthValue }\n | { type: 'percentage'; value: number }\n | { type: 'calc'; value: unknown }\n\n/**\n * Map a single typed transform function into zero-or-more RN transform\n * operations. Compound ops (like `translate`, `scale`, `skew`) expand\n * into per-axis entries the way RN expects them.\n * @param fn Typed transform function.\n * @returns RN transform operations.\n */\nfunction mapTransformFunction(fn: Transform): RnTransformRecord[] | null {\n switch (fn.type) {\n case 'rotate':\n case 'rotateZ': {\n return [{ rotate: angleToString(fn.value) }]\n }\n case 'rotateX': {\n return [{ rotateX: angleToString(fn.value) }]\n }\n case 'rotateY': {\n return [{ rotateY: angleToString(fn.value) }]\n }\n case 'scale': {\n const [x, y] = fn.value\n return [{ scaleX: numberOrPercentageToNumber(x) }, { scaleY: numberOrPercentageToNumber(y) }]\n }\n case 'scaleX': {\n return [{ scaleX: numberOrPercentageToNumber(fn.value) }]\n }\n case 'scaleY': {\n return [{ scaleY: numberOrPercentageToNumber(fn.value) }]\n }\n case 'translateX': {\n return [{ translateX: lengthOrPercentToNumber(fn.value) }]\n }\n case 'translateY': {\n return [{ translateY: lengthOrPercentToNumber(fn.value) }]\n }\n case 'translate': {\n const [x, y] = fn.value\n const out: RnTransformRecord[] = [{ translateX: lengthOrPercentToNumber(x) }]\n if (y) out.push({ translateY: lengthOrPercentToNumber(y) })\n return out\n }\n case 'translate3d': {\n const [x, y] = fn.value\n return [{ translateX: lengthOrPercentToNumber(x) }, { translateY: lengthOrPercentToNumber(y) }]\n }\n case 'skew': {\n const [x, y] = fn.value\n const out: RnTransformRecord[] = [{ skewX: angleToString(x) }]\n if (y) out.push({ skewY: angleToString(y) })\n return out\n }\n case 'skewX': {\n return [{ skewX: angleToString(fn.value) }]\n }\n case 'skewY': {\n return [{ skewY: angleToString(fn.value) }]\n }\n default: {\n // RN doesn't have a direct equivalent for `matrix()` / `matrix3d()` /\n // `perspective()` at the transform-op level — skip silently. Tailwind's\n // generated transforms stay within rotate/translate/scale/skew.\n return null\n }\n }\n}\n\n/**\n * Serialize a typed angle into the CSS degree string RN accepts\n * (`'45deg'`, `'0.5turn'` → `'180deg'`).\n * @param angle Typed angle.\n * @returns Degree string.\n */\nfunction angleToString(angle: Angle): string {\n switch (angle.type) {\n case 'deg': {\n return `${formatNumber(angle.value)}deg`\n }\n case 'rad': {\n return `${formatNumber((angle.value * 180) / Math.PI)}deg`\n }\n case 'grad': {\n return `${formatNumber((angle.value * 360) / 400)}deg`\n }\n case 'turn': {\n return `${formatNumber(angle.value * 360)}deg`\n }\n default: {\n return '0deg'\n }\n }\n}\n\n/**\n * Convert a `NumberOrPercentage` to a plain number. Percentages become\n * their fractional equivalent (e.g. `50%` → `0.5`). Rounded so a literal\n * like `scale-[1.7]` doesn't carry lightningcss's f32 noise\n * (`1.7000000476837158`) into the RN `transform` array.\n * @param value Typed value.\n * @returns Plain number.\n */\nfunction numberOrPercentageToNumber(value: NumberOrPercentage): number {\n return roundNumber(value.value)\n}\n\n/**\n * Convert a length-or-percentage used by translate into the shape RN\n * accepts (`number` for px, `string` for `%`). Percentages stay as\n * strings so RN layout can resolve them against the element size. Pixel\n * values are rounded to shed f32 noise (`3.3px` → `3.299999952…`).\n * @param value Typed length or percentage.\n * @returns RN-style translate value.\n */\nfunction lengthOrPercentToNumber(value: DimensionPercent | { type: 'value'; value: LengthValue }): number | string {\n if (value.type === 'dimension') return roundNumber(lengthToPx(value.value))\n if (value.type === 'value') return roundNumber(lengthToPx(value.value))\n if (value.type === 'percentage') return `${formatNumber(value.value * 100)}%`\n return 0\n}\n\n/**\n * Round a number to 4 decimals — sheds lightningcss's f32 representation\n * noise while staying well below subpixel / sub-percent precision.\n * @param value Raw number.\n * @returns Rounded number.\n */\nfunction roundNumber(value: number): number {\n return Math.round(value * 10_000) / 10_000\n}\n\n/**\n * Render a number without trailing IEEE noise.\n * @param value Number to format.\n * @returns Compact string form.\n */\nfunction formatNumber(value: number): string {\n return String(roundNumber(value))\n}\n\n/**\n * Convert lightningcss's typed `transform: ...` value into RN's\n * `transform: [{ op: value }, ...]` array. RN supports a restricted subset\n * of CSS transforms — this function picks out the ones it actually\n * handles and drops the rest.\n *\n * Reanimated v4's CSS engine reads this same array shape, so the output\n * is drop-in for both static RN `style` props and `Animated.View` styles.\n * @param fns Typed transform function list.\n * @returns Zero-or-one RN entry with the `transform` array.\n */\nexport function transformFunctionsToEntries(fns: readonly Transform[]): readonly RNEntry[] {\n const ops: RnTransformRecord[] = []\n for (const fn of fns) {\n const mapped = mapTransformFunction(fn)\n if (mapped) ops.push(...mapped)\n }\n if (ops.length === 0) return []\n return [['transform', ops]]\n}\n\n/**\n * Convert Tailwind v4's typed `rotate: ...` (individual property) into\n * the RN transform array. Tailwind's `rotate-*` utilities emit this\n * property rather than the classic `transform: rotate(...)` shorthand.\n * @param value Typed rotate value.\n * @returns Zero-or-one RN entry.\n */\nexport function rotateToEntries(value: Rotate | 'none'): readonly RNEntry[] {\n if (value === 'none') return []\n return [['transform', [{ rotate: angleToString(value.angle) }]]]\n}\n\n/**\n * Convert Tailwind v4's typed `translate: ...` into the RN transform\n * array. Both axes are emitted as separate ops so each is independently\n * animatable by Reanimated.\n * @param value Typed translate value.\n * @returns Zero-or-one RN entry.\n */\nexport function translateToEntries(value: Translate | 'none'): readonly RNEntry[] {\n if (value === 'none') return []\n const ops: RnTransformRecord[] = [{ translateX: lengthOrPercentToNumber(value.x) }]\n const yNumber = lengthOrPercentToNumber(value.y)\n if (yNumber !== 0) ops.push({ translateY: yNumber })\n return [['transform', ops]]\n}\n\n/**\n * Convert Tailwind v4's typed `scale: ...` into the RN transform array.\n * @param value Typed scale value.\n * @returns Zero-or-one RN entry.\n */\nexport function scaleToEntries(value: Scale | 'none'): readonly RNEntry[] {\n if (value === 'none') return []\n return [['transform', [{ scaleX: numberOrPercentageToNumber(value.x) }, { scaleY: numberOrPercentageToNumber(value.y) }]]]\n}\n"],"names":["lengthToPx"],"mappings":"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"}
|
|
@@ -12,6 +12,7 @@ var property = require('./property.cjs');
|
|
|
12
12
|
var selector = require('./selector.cjs');
|
|
13
13
|
var themeVars = require('./theme-vars.cjs');
|
|
14
14
|
var tokens = require('./tokens.cjs');
|
|
15
|
+
var color = require('./color.cjs');
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* Default LightningCSS transform options for TailwindParser's visitor.
|
|
@@ -283,7 +284,8 @@ class TailwindParser {
|
|
|
283
284
|
// surface their role + resolved colour so the transformer
|
|
284
285
|
// can rewrite `<LinearGradient className="...">` into
|
|
285
286
|
// `colors={...}` / `start={...}` / `end={...}` props.
|
|
286
|
-
const
|
|
287
|
+
const gradientTable = schemeTables.get(themeVars.BASE_SCHEME) ?? schemeTables.get(schemes[0] ?? themeVars.BASE_SCHEME);
|
|
288
|
+
const gradient$1 = gradient.detectGradientAtom(rule.value.declarations.declarations, gradientTable);
|
|
287
289
|
if (gradient$1)
|
|
288
290
|
gradientAtoms.set(className, gradient$1);
|
|
289
291
|
// Haptics may live on the rule directly OR inside a
|
|
@@ -304,8 +306,8 @@ class TailwindParser {
|
|
|
304
306
|
const steps = [];
|
|
305
307
|
const baseTable = schemeTables.get(themeVars.BASE_SCHEME) ?? schemeTables.get(schemes[0] ?? themeVars.BASE_SCHEME);
|
|
306
308
|
for (const frame of rule.value.keyframes) {
|
|
307
|
-
const
|
|
308
|
-
if (
|
|
309
|
+
const offsets = keyframes.keyframeSelectorOffsets(frame.selectors);
|
|
310
|
+
if (offsets.length === 0)
|
|
309
311
|
continue;
|
|
310
312
|
const style = {};
|
|
311
313
|
const frameDecls = frame.declarations.declarations ?? [];
|
|
@@ -313,7 +315,10 @@ class TailwindParser {
|
|
|
313
315
|
for (const [key, value] of declaration.declarationToRnEntries(decl, baseTable))
|
|
314
316
|
style[key] = value;
|
|
315
317
|
}
|
|
316
|
-
|
|
318
|
+
// One frame can carry several offsets (`0%, 100% { … }`); emit a
|
|
319
|
+
// step for each so the terminal frame isn't lost.
|
|
320
|
+
for (const offset of offsets)
|
|
321
|
+
steps.push({ offset, style });
|
|
317
322
|
}
|
|
318
323
|
keyframes$1.set(name, { name, steps });
|
|
319
324
|
},
|
|
@@ -454,8 +459,8 @@ function processStyleRule(declarations, className, ctx, nestedRules = []) {
|
|
|
454
459
|
ctx.referencedKeyframes.add(animationRef);
|
|
455
460
|
}
|
|
456
461
|
applyComposedTransform(bucket, ctx.schemes, ruleLocalVars);
|
|
457
|
-
applyComposedShadow(bucket, ctx.schemes, ruleLocalVars);
|
|
458
|
-
applyComposedRing(bucket, ctx.schemes, ruleLocalVars);
|
|
462
|
+
applyComposedShadow(bucket, ctx.schemes, ruleLocalVars, ruleSchemeTables);
|
|
463
|
+
applyComposedRing(bucket, ctx.schemes, ruleLocalVars, ruleSchemeTables);
|
|
459
464
|
// Phase 2: nested rules — three orthogonal flavours, dispatched on
|
|
460
465
|
// the lightningcss node `type`:
|
|
461
466
|
// - `media`: Tailwind v4 responsive variants (`sm:`, `md:`, …) wrap
|
|
@@ -600,7 +605,7 @@ function applyMediaRule(nested, className, bucket, ctx, ruleSchemeTables, ruleLo
|
|
|
600
605
|
for (const [k, v] of collectRuleLocalVars(decls))
|
|
601
606
|
nestedLocalVars.set(k, v);
|
|
602
607
|
applyComposedTransformToScheme(schemeBucket, nestedLocalVars);
|
|
603
|
-
applyComposedShadowToScheme(schemeBucket, nestedLocalVars);
|
|
608
|
+
applyComposedShadowToScheme(schemeBucket, nestedLocalVars, table);
|
|
604
609
|
bucket[scheme] = schemeBucket;
|
|
605
610
|
}
|
|
606
611
|
}
|
|
@@ -637,7 +642,7 @@ function applyInteractiveNestedRule(nested, bucket, ctx, ruleSchemeTables, ruleL
|
|
|
637
642
|
for (const [k, v] of collectRuleLocalVars(decls))
|
|
638
643
|
nestedLocalVars.set(k, v);
|
|
639
644
|
applyComposedTransformToScheme(schemeBucket, nestedLocalVars);
|
|
640
|
-
applyComposedShadowToScheme(schemeBucket, nestedLocalVars);
|
|
645
|
+
applyComposedShadowToScheme(schemeBucket, nestedLocalVars, table);
|
|
641
646
|
bucket[scheme] = schemeBucket;
|
|
642
647
|
}
|
|
643
648
|
}
|
|
@@ -703,7 +708,7 @@ function applyNestedSchemeRule(nested, bucket, ctx, ruleSchemeTables, ruleLocalV
|
|
|
703
708
|
for (const [k, v] of collectRuleLocalVars(innerDecls))
|
|
704
709
|
nestedLocalVars.set(k, v);
|
|
705
710
|
applyComposedTransformToScheme(schemeBucket, nestedLocalVars);
|
|
706
|
-
applyComposedShadowToScheme(schemeBucket, nestedLocalVars);
|
|
711
|
+
applyComposedShadowToScheme(schemeBucket, nestedLocalVars, table);
|
|
707
712
|
bucket[targetScheme] = schemeBucket;
|
|
708
713
|
}
|
|
709
714
|
/**
|
|
@@ -804,12 +809,13 @@ function applyComposedTransformToScheme(style, ruleLocalVars) {
|
|
|
804
809
|
* prop.
|
|
805
810
|
* @param style Scheme-specific style map.
|
|
806
811
|
* @param ruleLocalVars Combined outer+nested `--tw-*` vars.
|
|
812
|
+
* @param table Per-scheme var table for resolving `var(--color-x)` in colors.
|
|
807
813
|
*/
|
|
808
|
-
function applyComposedShadowToScheme(style, ruleLocalVars) {
|
|
814
|
+
function applyComposedShadowToScheme(style, ruleLocalVars, table) {
|
|
809
815
|
const rawShadow = ruleLocalVars.get('--tw-shadow');
|
|
810
816
|
const rawShadowColor = ruleLocalVars.get('--tw-shadow-color');
|
|
811
817
|
if (!rawShadow && rawShadowColor) {
|
|
812
|
-
const color = resolveCustomColorString(rawShadowColor);
|
|
818
|
+
const color = resolveCustomColorString(rawShadowColor, table);
|
|
813
819
|
if (!color)
|
|
814
820
|
return;
|
|
815
821
|
delete style.boxShadow;
|
|
@@ -838,8 +844,9 @@ function applyComposedShadowToScheme(style, ruleLocalVars) {
|
|
|
838
844
|
* @param bucket Per-scheme style map for the atom.
|
|
839
845
|
* @param schemes Scheme names active for this parse.
|
|
840
846
|
* @param ruleLocalVars Rule-local `--tw-*` vars.
|
|
847
|
+
* @param schemeTables Per-scheme var tables for resolving `var(--color-x)`.
|
|
841
848
|
*/
|
|
842
|
-
function applyComposedShadow(bucket, schemes, ruleLocalVars) {
|
|
849
|
+
function applyComposedShadow(bucket, schemes, ruleLocalVars, schemeTables) {
|
|
843
850
|
const rawShadow = ruleLocalVars.get('--tw-shadow');
|
|
844
851
|
const rawShadowColor = ruleLocalVars.get('--tw-shadow-color');
|
|
845
852
|
// Color-only utility (`shadow-red-50`, `shadow-gray-200`, …): emit
|
|
@@ -848,10 +855,11 @@ function applyComposedShadow(bucket, schemes, ruleLocalVars) {
|
|
|
848
855
|
// where setting `--tw-shadow-color` swaps in a solid color). Offset /
|
|
849
856
|
// blur / elevation come from the partner size utility's atom.
|
|
850
857
|
if (!rawShadow && rawShadowColor) {
|
|
851
|
-
const color = resolveCustomColorString(rawShadowColor);
|
|
852
|
-
if (!color)
|
|
853
|
-
return;
|
|
854
858
|
for (const scheme of schemes) {
|
|
859
|
+
// Resolve per scheme — a custom token may differ between light/dark.
|
|
860
|
+
const color = resolveCustomColorString(rawShadowColor, schemeTables.get(scheme));
|
|
861
|
+
if (!color)
|
|
862
|
+
continue;
|
|
855
863
|
const style = bucket[scheme] ?? {};
|
|
856
864
|
delete style.boxShadow;
|
|
857
865
|
style.shadowColor = color;
|
|
@@ -884,35 +892,62 @@ function applyComposedShadow(bucket, schemes, ruleLocalVars) {
|
|
|
884
892
|
* @param bucket Per-scheme style map for the atom.
|
|
885
893
|
* @param schemes Scheme names active for this parse.
|
|
886
894
|
* @param ruleLocalVars Rule-local `--tw-*` vars.
|
|
895
|
+
* @param schemeTables Per-scheme var tables for resolving `var(--color-x)`.
|
|
887
896
|
*/
|
|
888
|
-
function applyComposedRing(bucket, schemes, ruleLocalVars) {
|
|
897
|
+
function applyComposedRing(bucket, schemes, ruleLocalVars, schemeTables) {
|
|
889
898
|
const ringColor = ruleLocalVars.get('--tw-ring-color');
|
|
890
899
|
if (!ringColor)
|
|
891
900
|
return;
|
|
892
|
-
const color = resolveCustomColorString(ringColor);
|
|
893
|
-
if (!color)
|
|
894
|
-
return;
|
|
895
901
|
for (const scheme of schemes) {
|
|
902
|
+
// Resolve per scheme — a custom token may differ between light/dark.
|
|
903
|
+
const color = resolveCustomColorString(ringColor, schemeTables.get(scheme));
|
|
904
|
+
if (!color)
|
|
905
|
+
continue;
|
|
896
906
|
const style = bucket[scheme] ?? {};
|
|
897
907
|
if (!('borderColor' in style))
|
|
898
908
|
style.borderColor = color;
|
|
899
909
|
bucket[scheme] = style;
|
|
900
910
|
}
|
|
901
911
|
}
|
|
912
|
+
/**
|
|
913
|
+
* Tailwind composable shadow/inset-shadow alpha defaults. Their `100%` lives
|
|
914
|
+
* in an `@property` initial-value (not the rule's local vars), so after the
|
|
915
|
+
* `@supports` color-mix is unwrapped, `var(--tw-shadow-alpha)` is left dangling
|
|
916
|
+
* and the shadow color fails to resolve. Seed the default; a `/<opacity>`
|
|
917
|
+
* modifier still wins because the in-rule table value overrides it.
|
|
918
|
+
*/
|
|
919
|
+
const COMPOSABLE_ALPHA_DEFAULTS = new Map([
|
|
920
|
+
['--tw-shadow-alpha', '100%'],
|
|
921
|
+
['--tw-inset-shadow-alpha', '100%'],
|
|
922
|
+
]);
|
|
902
923
|
/**
|
|
903
924
|
* Resolve a CSS color string (`oklch(0.971 0.013 17.38)`, `#ff0000`,
|
|
904
925
|
* `rgb(0 0 0 / 0.1)`) to the hex string RN's `shadowColor` accepts.
|
|
905
926
|
* Wraps culori's parser via {@link parseCssColorToHex}.
|
|
906
|
-
*
|
|
927
|
+
*
|
|
928
|
+
* Custom `@theme` color tokens arrive as `var(--color-x)` (only the default
|
|
929
|
+
* palette is `theme(inline)`-d), so `table` is substituted FIRST — without it
|
|
930
|
+
* `shadow-<token>` / `ring-<token>` silently drop the color (culori can't
|
|
931
|
+
* parse a bare `var()`). The table is per-scheme so a token that differs
|
|
932
|
+
* between light/dark resolves to the right value for each.
|
|
933
|
+
* @param raw Raw color text from a `--tw-shadow-color` / `--tw-ring-color` prop.
|
|
934
|
+
* @param table Per-scheme var table for resolving `var(--color-x)` references.
|
|
907
935
|
* @returns `#rrggbb` string, or null when culori can't parse it.
|
|
908
936
|
*/
|
|
909
|
-
function resolveCustomColorString(raw) {
|
|
910
|
-
const
|
|
911
|
-
|
|
937
|
+
function resolveCustomColorString(raw, table) {
|
|
938
|
+
const seeded = new Map([...COMPOSABLE_ALPHA_DEFAULTS, ...(table ?? [])]);
|
|
939
|
+
const substituted = tokens.substituteThemeVars(raw, seeded);
|
|
940
|
+
// `coerceUnparsedValue` collapses Tailwind's opacity shape
|
|
941
|
+
// `color-mix(in oklab, <color> <pct>%, transparent)` (emitted by
|
|
942
|
+
// `shadow-<token>` / `ring-<token>`) to a flat rgba/hex and unwraps
|
|
943
|
+
// `var(…, fallback)`. Modern spaces (`oklch(…)`) then lower via
|
|
944
|
+
// `normalizeColorString`; anything still un-RN-safe falls to culori.
|
|
945
|
+
const coerced = tokens.coerceUnparsedValue(unwrapVariableFallback(substituted).trim());
|
|
946
|
+
if (typeof coerced !== 'string' || coerced.length === 0 || coerced.startsWith('var('))
|
|
912
947
|
return null;
|
|
913
|
-
if (
|
|
914
|
-
return
|
|
915
|
-
return parseCssColorToHex(
|
|
948
|
+
if (coerced.startsWith('#') || coerced.startsWith('rgb') || coerced.startsWith('hsl'))
|
|
949
|
+
return coerced;
|
|
950
|
+
return color.normalizeColorString(coerced) ?? parseCssColorToHex(coerced);
|
|
916
951
|
}
|
|
917
952
|
/**
|
|
918
953
|
* Parse any CSS color expression into an `#rrggbb` string via culori.
|
|
@@ -1018,6 +1053,12 @@ function parseShadowColor(expr) {
|
|
|
1018
1053
|
return rgba;
|
|
1019
1054
|
if (working.startsWith('#'))
|
|
1020
1055
|
return { color: working, opacity: 1 };
|
|
1056
|
+
// Named (`red`) / modern (`hsl(…)`, `oklch(…)`) colors — culori → sRGB hex.
|
|
1057
|
+
// Without this they fell to the default black at 0.1 alpha, silently losing
|
|
1058
|
+
// the user's `shadow-[0_2px_4px_red]` color.
|
|
1059
|
+
const hex = formatHexSafe(working);
|
|
1060
|
+
if (hex)
|
|
1061
|
+
return { color: hex, opacity: 1 };
|
|
1021
1062
|
return { color: '#000', opacity: 0.1 };
|
|
1022
1063
|
}
|
|
1023
1064
|
/**
|
|
@@ -1222,8 +1263,8 @@ function resolveLengthExpression(text) {
|
|
|
1222
1263
|
if (evaluated.unit === '%')
|
|
1223
1264
|
return `${stripTrailingZeros(evaluated.value)}%`;
|
|
1224
1265
|
if (evaluated.unit === 'rem')
|
|
1225
|
-
return evaluated.value * 16;
|
|
1226
|
-
return evaluated.value;
|
|
1266
|
+
return roundTransformValue(evaluated.value * 16);
|
|
1267
|
+
return roundTransformValue(evaluated.value);
|
|
1227
1268
|
}
|
|
1228
1269
|
/**
|
|
1229
1270
|
* Evaluate a CSS length expression to a `{value, unit}` pair.
|
|
@@ -1450,19 +1491,38 @@ function parseArithmeticFactor(tokens, cursor) {
|
|
|
1450
1491
|
return number_;
|
|
1451
1492
|
}
|
|
1452
1493
|
/**
|
|
1453
|
-
* Resolve a scale factor expressed as a percentage (`150%`)
|
|
1494
|
+
* Resolve a scale factor expressed as a percentage (`150%`), number (`1.5`),
|
|
1495
|
+
* or a `calc()` expression. Tailwind emits NEGATIVE scale utilities as a calc
|
|
1496
|
+
* (`-scale-x-100` → `calc(100% * -1)`), so a plain percent/number regex
|
|
1497
|
+
* silently dropped them — `-scale-*` (the horizontal-flip idiom) rendered
|
|
1498
|
+
* nothing. Fall back to the shared arithmetic evaluator, reading `%` as a
|
|
1499
|
+
* fraction (`100%` → 1) and rounding off f32 noise.
|
|
1454
1500
|
* @param text Raw value.
|
|
1455
|
-
* @returns Scale number (e.g. 1.5 for 150%), or null.
|
|
1501
|
+
* @returns Scale number (e.g. 1.5 for 150%, -1 for `calc(100% * -1)`), or null.
|
|
1456
1502
|
*/
|
|
1457
1503
|
function resolveNumberOrPercent(text) {
|
|
1458
1504
|
const trimmed = text.trim();
|
|
1459
1505
|
const percent = /^(-?\d+(?:\.\d+)?)%$/.exec(trimmed);
|
|
1460
1506
|
if (percent)
|
|
1461
|
-
return Number(percent[1]) / 100;
|
|
1507
|
+
return roundTransformValue(Number(percent[1]) / 100);
|
|
1462
1508
|
const bare = /^-?\d+(?:\.\d+)?$/.exec(trimmed);
|
|
1463
1509
|
if (bare)
|
|
1464
|
-
return Number(trimmed);
|
|
1465
|
-
|
|
1510
|
+
return roundTransformValue(Number(trimmed));
|
|
1511
|
+
const evaluated = evaluateLengthExpr(trimmed);
|
|
1512
|
+
if (!evaluated || evaluated.unit === 'rem')
|
|
1513
|
+
return null;
|
|
1514
|
+
return roundTransformValue(evaluated.unit === '%' ? evaluated.value / 100 : evaluated.value);
|
|
1515
|
+
}
|
|
1516
|
+
/**
|
|
1517
|
+
* Round a composed-transform numeric value to 4 decimals. lightningcss
|
|
1518
|
+
* serializes arbitrary literals (`scale-x-[0.333]`) back as noisy f32 text
|
|
1519
|
+
* (`0.3330000042915344`), and the resolvers `Number()` that verbatim — round
|
|
1520
|
+
* so the RN `transform` array stays clean.
|
|
1521
|
+
* @param value Raw number.
|
|
1522
|
+
* @returns Rounded number.
|
|
1523
|
+
*/
|
|
1524
|
+
function roundTransformValue(value) {
|
|
1525
|
+
return Math.round(value * 10_000) / 10_000;
|
|
1466
1526
|
}
|
|
1467
1527
|
/**
|
|
1468
1528
|
* Extract the angle from Tailwind's `skewX(12deg)` / `skewY(-5deg)` /
|