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.
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 +161 -10
  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 +43 -60
  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 +162 -11
  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 +43 -60
  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 +160 -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 +45 -61
  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
@@ -36,6 +36,17 @@ type WindowHeightProvider = () => number;
36
36
  * module cache.
37
37
  */
38
38
  type SchemeLoader = (scheme: string) => void;
39
+ /**
40
+ * Public breakpoint-tier for a width — the count of registered breakpoints
41
+ * whose threshold is reached. Used by the runtime resolver as its width
42
+ * cache dimension: the numeric tier is bounded AND exact, unlike the
43
+ * clamped `activeBreakpoint` NAME (which collapses tier-0 into the smallest
44
+ * breakpoint, so widths straddling that threshold would share a cache key
45
+ * and serve a stale style).
46
+ * @param windowWidth Live window width in px.
47
+ * @returns Tier 0..N.
48
+ */
49
+ export declare function breakpointTier(windowWidth: number): number;
39
50
  /**
40
51
  * Per-render snapshot of which interactive states (active, focus) are
41
52
  * currently engaged. Forwarded from the `useInteract()` hook the
@@ -110,17 +110,19 @@ function registerHaptics(map) {
110
110
  const stateSignatureCache = new WeakMap();
111
111
  /**
112
112
  * Cache key dimension for the reactive context — everything that can
113
- * change a resolved style. Uses the breakpoint TIER (`activeBreakpoint`),
114
- * NOT the raw `windowWidth`: two widths in the same tier gate `md:*` atoms
115
- * identically, so they resolve the same. This collapses the window axis
116
- * from "every pixel" to ~6 values, bounding the cache on resizable
117
- * surfaces (web / desktop) without changing any result.
113
+ * change a resolved style. Uses the numeric breakpoint TIER (count of
114
+ * thresholds reached) from `breakpointTier(windowWidth)`, NOT the
115
+ * `activeBreakpoint` NAME: the name clamps tier-0 into the smallest
116
+ * breakpoint, so widths straddling that threshold (e.g. 320 vs 700 with
117
+ * `sm=640`) would collide on one cache key and serve a stale style. The
118
+ * tier is exact AND bounded — two widths in the same tier gate every
119
+ * `sm:`/`md:`/… atom identically, so they resolve the same.
118
120
  * @param state Rnwind context.
119
121
  * @returns Compact signature string.
120
122
  */
121
123
  function stateSignature(state) {
122
124
  const { insets } = state;
123
- return `${state.scheme}|${insets.top},${insets.right},${insets.bottom},${insets.left}|${state.fontScale}|${state.activeBreakpoint}`;
125
+ return `${state.scheme}|${insets.top},${insets.right},${insets.bottom},${insets.left}|${state.fontScale}|${lookupCss.breakpointTier(state.windowWidth)}`;
124
126
  }
125
127
  /**
126
128
  * Memoised {@link stateSignature} — one `WeakMap.get` on the hot path
@@ -1 +1 @@
1
- {"version":3,"file":"resolve.cjs","sources":["../../../../src/runtime/resolve.ts"],"sourcesContent":["import { getStyleVersion, lookupCss, type InteractState } from './lookup-css'\nimport type { RnwindState } from './components/rnwind-provider'\nimport { normalizeClassName } from '../core/normalize-classname'\nimport type { GradientAtomInfo, GradientDirection } from '../core/parser/gradient'\nimport type { HapticRequest, HapticTrigger } from '../core/parser/haptics'\n\n/**\n * Rich className resolver — the runtime heart of the wrap / `useCss`.\n *\n * Resolution order, per className string:\n * 1. **Molecule** — a build-time PRE-MERGED single style object for the\n * whole literal className (per scheme). One map lookup returns it by\n * reference: no array, no merge, no per-atom loop. The common case.\n * 2. **Atom fallback** — for a className the scanner never saw (a\n * runtime-built string like `` `${className} px-2` ``) OR one that\n * carries context-dependent atoms (`pt-safe`, `text-base`, `md:*`),\n * fall back to per-atom resolution via `lookupCss`, which folds in\n * insets / fontScale / breakpoint / scheme.\n *\n * Results are cached by `(normalized className, scheme, insets, fontScale,\n * breakpoint)` so repeated renders return the SAME reference until the\n * reactive context changes. Atoms / molecules / features all live in\n * build-time registries the generated `.rnwind/*.js` modules populate.\n */\n\n/** Always-loaded fallback scheme key. */\nconst COMMON_SCHEME = 'common'\n\n/** Empty style sentinel. */\nconst EMPTY: readonly unknown[] = []\n\n/** scheme → normalized className → pre-merged style object. */\nlet molecules: Record<string, Record<string, unknown>> = Object.create(null)\n/** atom name → gradient role + resolved colour. */\nlet gradients: Record<string, GradientAtomInfo> = Object.create(null)\n/** atom name (incl. `active:`/`focus:` prefix) → haptic request. */\nlet haptics: Record<string, HapticRequest> = Object.create(null)\n/** Bumps on any molecule/gradient/haptic registration. */\nlet registryVersion = 0\n\n/** Per-(className·state) resolved cache — strong references between context changes. */\nconst resolvedCache = new Map<string, ResolvedCss>()\n/** Version the cache was last valid for (`getStyleVersion()` + {@link registryVersion}). */\nlet cachedFor = -1\n\n/**\n * Hard ceiling on the resolved cache. The cache is pure memoisation, so\n * eviction only costs a re-resolve (sub-µs) — never correctness. Build\n * molecules are NOT in here; they live permanently in `molecules`.\n */\nconst MAX_RESOLVED_CACHE = 2048\n\n/**\n * Store a resolved result, bulk-evicting the OLDEST half when the cache\n * hits {@link MAX_RESOLVED_CACHE}. `Map` preserves insertion order, so the\n * first keys are the oldest. Bulk eviction keeps the hot (cache-hit) path\n * free of per-access LRU bookkeeping at the cost of an occasional small\n * recompute burst under sustained pressure (web / long sessions).\n * @param key Cache key.\n * @param value Resolved result to store.\n */\nfunction cacheResolved(key: string, value: ResolvedCss): void {\n if (resolvedCache.size >= MAX_RESOLVED_CACHE) {\n let drop = resolvedCache.size >> 1\n for (const oldKey of resolvedCache.keys()) {\n resolvedCache.delete(oldKey)\n if (--drop <= 0) break\n }\n }\n resolvedCache.set(key, value)\n}\n\n/** A unit-square gradient endpoint. */\ninterface GradientPoint {\n readonly x: number\n readonly y: number\n}\n\n/** Rich resolution: the RN `style` plus any className-derived props. */\nexport interface ResolvedCss {\n /** RN `style` value — a single molecule object (by ref) or an atom array. */\n readonly style: unknown\n /** Gradient stop colours (when the className is a complete gradient). */\n readonly colors?: readonly string[]\n /** Gradient start point. */\n readonly start?: GradientPoint\n /** Gradient end point. */\n readonly end?: GradientPoint\n /** Text truncation line count. */\n readonly numberOfLines?: number\n /** Text ellipsize mode. */\n readonly ellipsizeMode?: 'tail' | 'clip'\n /** Haptic requests present on the className, for the wrap to dispatch. */\n readonly haptics?: readonly { readonly request: HapticRequest; readonly trigger: HapticTrigger }[]\n}\n\n/** `GradientDirection` → expo-linear-gradient start/end points. */\nconst DIRECTION_POINTS: Record<GradientDirection, { start: GradientPoint; end: GradientPoint }> = {\n 'to-t': { start: { x: 0.5, y: 1 }, end: { x: 0.5, y: 0 } },\n 'to-b': { start: { x: 0.5, y: 0 }, end: { x: 0.5, y: 1 } },\n 'to-l': { start: { x: 1, y: 0.5 }, end: { x: 0, y: 0.5 } },\n 'to-r': { start: { x: 0, y: 0.5 }, end: { x: 1, y: 0.5 } },\n 'to-tl': { start: { x: 1, y: 1 }, end: { x: 0, y: 0 } },\n 'to-tr': { start: { x: 0, y: 1 }, end: { x: 1, y: 0 } },\n 'to-bl': { start: { x: 1, y: 0 }, end: { x: 0, y: 1 } },\n 'to-br': { start: { x: 0, y: 0 }, end: { x: 1, y: 1 } },\n unknown: { start: { x: 0, y: 0.5 }, end: { x: 1, y: 0.5 } },\n}\n\n/**\n * Register one scheme's pre-merged molecules (atom-merged literal\n * classNames). Merges onto any existing entries for the scheme.\n * @param scheme Scheme name (or `'common'`).\n * @param entries Normalized className → merged style object.\n */\nexport function registerMolecules(scheme: string, entries: Record<string, unknown>): void {\n molecules[scheme] = { ...molecules[scheme], ...entries }\n registryVersion += 1\n}\n\n/**\n * Register the gradient atom map (atom name → role + resolved colour).\n * @param map Atom name → gradient info.\n */\nexport function registerGradients(map: Record<string, GradientAtomInfo>): void {\n gradients = map\n registryVersion += 1\n}\n\n/**\n * Register the haptic atom map (atom name → request).\n * @param map Atom name → haptic request.\n */\nexport function registerHaptics(map: Record<string, HapticRequest>): void {\n haptics = map\n registryVersion += 1\n}\n\n\n\n/**\n * Per-state-object signature memo. `RnwindState` is created fresh (via the\n * provider's `useMemo`) whenever any field changes, so its identity is a\n * sound key — a new object means a new signature. Keyed weakly so states\n * GC with their provider.\n */\nconst stateSignatureCache = new WeakMap<RnwindState, string>()\n\n/**\n * Cache key dimension for the reactive context — everything that can\n * change a resolved style. Uses the breakpoint TIER (`activeBreakpoint`),\n * NOT the raw `windowWidth`: two widths in the same tier gate `md:*` atoms\n * identically, so they resolve the same. This collapses the window axis\n * from \"every pixel\" to ~6 values, bounding the cache on resizable\n * surfaces (web / desktop) without changing any result.\n * @param state Rnwind context.\n * @returns Compact signature string.\n */\nfunction stateSignature(state: RnwindState): string {\n const { insets } = state\n return `${state.scheme}|${insets.top},${insets.right},${insets.bottom},${insets.left}|${state.fontScale}|${state.activeBreakpoint}`\n}\n\n/**\n * Memoised {@link stateSignature} — one `WeakMap.get` on the hot path\n * instead of rebuilding the template string every resolve.\n * @param state Rnwind context.\n * @returns Cached compact signature.\n */\nfunction stateSignatureCached(state: RnwindState): string {\n let signature = stateSignatureCache.get(state)\n if (signature === undefined) {\n signature = stateSignature(state)\n stateSignatureCache.set(state, signature)\n }\n return signature\n}\n\n/**\n * Compact signature of the live interactive state for the cache key.\n * @param interactState Active/focus flags, or undefined for the plain path.\n * @returns Two-bit signature (`''` when no interactive state).\n */\nfunction interactSignature(interactState?: InteractState): string {\n if (!interactState) return ''\n const active = interactState.active ? 1 : 0\n const focus = interactState.focus ? 1 : 0\n return `${active}${focus}`\n}\n\n/**\n * Whether a token is a feature-ONLY utility (gradient stop/direction,\n * haptic request, or text-truncate) that contributes NO RN `style`. These\n * are folded in via {@link attachFeatures}, so they must be kept OUT of\n * the `lookupCss` input — otherwise the atom resolver treats them as\n * unknown style atoms and emits a spurious \"unknown class\" dev warning\n * (e.g. for `active:haptic-rigid`).\n * @param token Atom name.\n * @returns True when the token carries no style.\n */\nfunction isFeatureOnlyToken(token: string): boolean {\n return Boolean(gradients[token]) || Boolean(haptics[token]) || truncateForToken(token) !== null\n}\n\n/**\n * Lifecycle trigger for a haptic atom from its variant prefix.\n * @param token Atom name (maybe `active:`/`focus:`/`hover:` prefixed).\n * @returns The trigger.\n */\nfunction hapticTriggerForToken(token: string): HapticTrigger {\n const colon = token.indexOf(':')\n if (colon === -1) return 'mount'\n const prefix = token.slice(0, colon)\n if (prefix === 'active') return 'pressIn'\n if (prefix === 'focus') return 'focus'\n if (prefix === 'hover') return 'hover'\n return 'mount'\n}\n\n/**\n * Syntactic text-truncate directive for one atom.\n * @param token Atom name.\n * @returns Partial truncate props, or null.\n */\nfunction truncateForToken(token: string): { numberOfLines?: number; ellipsizeMode?: 'tail' | 'clip' } | null {\n if (token === 'truncate') return { numberOfLines: 1, ellipsizeMode: 'tail' }\n if (token === 'text-ellipsis') return { ellipsizeMode: 'tail' }\n if (token === 'text-clip') return { ellipsizeMode: 'clip' }\n if (token === 'line-clamp-none') return { numberOfLines: 0 }\n if (token.startsWith('line-clamp-')) {\n const count = Number(token.slice('line-clamp-'.length))\n if (Number.isInteger(count) && count >= 0) return { numberOfLines: count }\n }\n return null\n}\n\n/**\n * Assemble gradient props from gradient roles present in the atom list.\n * @param tokens Atom names.\n * @returns `{colors, start, end}` or null when not a complete gradient.\n */\nfunction assembleGradient(tokens: readonly string[]): { colors: string[]; start: GradientPoint; end: GradientPoint } | null {\n let from: string | undefined\n let via: string | undefined\n let to: string | undefined\n let dir: GradientDirection | undefined\n for (const token of tokens) {\n const info = gradients[token]\n if (!info) continue\n switch (info.role) {\n case 'from': {\n from = info.color\n break\n }\n case 'via': {\n via = info.color\n break\n }\n case 'to': {\n to = info.color\n break\n }\n default: {\n ;({ dir } = info)\n }\n }\n }\n if (dir === undefined) return null\n const colors = [from, via, to].filter((color): color is string => color !== undefined)\n if (colors.length < 2) return null\n const points = DIRECTION_POINTS[dir]\n return { colors, start: points.start, end: points.end }\n}\n\n/**\n * Fold every truncate directive across the atom list into one result —\n * last token wins per prop (matches Tailwind last-wins).\n * @param tokens Atom names.\n * @returns Merged truncate props (empty when none apply).\n */\nfunction collectTruncate(tokens: readonly string[]): { numberOfLines?: number; ellipsizeMode?: 'tail' | 'clip' } {\n const out: { numberOfLines?: number; ellipsizeMode?: 'tail' | 'clip' } = {}\n for (const token of tokens) {\n const truncate = truncateForToken(token)\n if (!truncate) continue\n if (truncate.numberOfLines !== undefined) out.numberOfLines = truncate.numberOfLines\n if (truncate.ellipsizeMode !== undefined) out.ellipsizeMode = truncate.ellipsizeMode\n }\n return out\n}\n\n/**\n * Collect every haptic request present in the atom list, tagged with the\n * lifecycle trigger its variant prefix implies.\n * @param tokens Atom names.\n * @returns Haptic request list, or undefined when none apply.\n */\nfunction collectHaptics(tokens: readonly string[]): { request: HapticRequest; trigger: HapticTrigger }[] | undefined {\n let collected: { request: HapticRequest; trigger: HapticTrigger }[] | undefined\n for (const token of tokens) {\n const request = haptics[token]\n if (!request) continue\n collected ??= []\n collected.push({ request, trigger: hapticTriggerForToken(token) })\n }\n return collected\n}\n\n/**\n * Scan tokens for the className-derived feature props (gradient,\n * truncate, haptics) and fold them onto the base result.\n * @param base Result carrying the resolved `style`.\n * @param tokens Atom names.\n * @returns The result with any feature props attached.\n */\nfunction attachFeatures(base: ResolvedCss, tokens: readonly string[]): ResolvedCss {\n const { numberOfLines, ellipsizeMode } = collectTruncate(tokens)\n const collected = collectHaptics(tokens)\n const gradient = assembleGradient(tokens)\n const result: Mutable<ResolvedCss> = { style: base.style }\n if (gradient) {\n result.colors = gradient.colors\n result.start = gradient.start\n result.end = gradient.end\n }\n // `numberOfLines: 0` is kept (RN reads it as \"unlimited\"): `line-clamp-none`\n // must be able to explicitly reset an earlier `line-clamp-N` on the same\n // element — dropping the 0 would silently leave the prior limit in place.\n if (numberOfLines !== undefined) {\n result.numberOfLines = numberOfLines\n if (ellipsizeMode !== undefined) result.ellipsizeMode = ellipsizeMode\n }\n if (collected) result.haptics = collected\n return result\n}\n\n/**\n * Flatten the per-atom style array into ONE object — a *runtime molecule*.\n * RN flattens a style array left-to-right (later wins), which is exactly\n * `Object.assign` semantics, so the merged object renders identically\n * while giving dynamic (cva / clsx) classNames the same single-object\n * shape a build-time molecule has. The caller caches the result per\n * `(className · state)`, so the merge runs once per unique context.\n * @param array Per-atom style array from `lookupCss`.\n * @returns Single merged style object.\n */\nfunction mergeStyleArray(array: readonly unknown[]): Record<string, unknown> {\n const out: Record<string, unknown> = {}\n for (const entry of array) if (entry && typeof entry === 'object') Object.assign(out, entry)\n return out\n}\n\n/**\n * Compose a resolved style with a caller-supplied inline style (user wins).\n * @param style\n * @param userStyle\n */\nfunction withUserStyle(style: unknown, userStyle: unknown): unknown {\n return Array.isArray(style) ? [...style, userStyle] : [style, userStyle]\n}\n\n/**\n * Resolve a className against the reactive context into a style plus any\n * className-derived props. Molecule-first (one lookup, by reference),\n * atom-fallback for unseen / context-dependent strings, cached per\n * `(className, state)`.\n * @param className Raw className string.\n * @param state Rnwind context from `useRnwind()`.\n * @param userStyle Optional inline style appended last (wins).\n * @param interactState Live active/focus flags (for `active:`/`focus:` atoms).\n * @returns The resolved style + feature props.\n */\nexport function resolve(\n className: string | null | undefined,\n state: RnwindState,\n userStyle?: unknown,\n interactState?: InteractState,\n): ResolvedCss {\n const version = getStyleVersion() + registryVersion\n if (version !== cachedFor) {\n resolvedCache.clear()\n cachedFor = version\n }\n if (className == null) {\n return { style: userStyle === undefined || userStyle === null ? EMPTY : [userStyle] }\n }\n // Key on the RAW className so the hot (cache-hit) path skips normalize\n // entirely — normalization only runs on a miss. The state signature is\n // memoised per state object, so the hit path is one WeakMap.get + one\n // string concat + one Map.get.\n const key = `${className}@${stateSignatureCached(state)}@${interactSignature(interactState)}`\n const cached = resolvedCache.get(key)\n if (cached !== undefined) {\n return userStyle === undefined || userStyle === null ? cached : { ...cached, style: withUserStyle(cached.style, userStyle) }\n }\n const normalized = normalizeClassName(className)\n if (normalized.length === 0) {\n const empty: ResolvedCss = { style: EMPTY }\n cacheResolved(key, empty)\n return userStyle === undefined || userStyle === null ? empty : { style: [userStyle] }\n }\n // Molecules are static pre-merges; anything carrying `active:`/`focus:`\n // is never registered as one, so the atom path handles interactive state.\n const tokens = normalized.split(' ')\n const molecule = interactState ? undefined : molecules[state.scheme]?.[normalized] ?? molecules[COMMON_SCHEME]?.[normalized]\n // Feature-only tokens (gradient / haptic / truncate) carry no style — keep\n // them out of the atom lookup so they don't warn as \"unknown class\". The\n // atom array is merged into ONE object (a runtime molecule) so dynamic\n // (cva / clsx) classNames get the same single-object shape as a build\n // molecule; the cache below pins the context, so the merge is correct.\n const style =\n molecule === undefined\n ? mergeStyleArray(lookupCss(tokens.filter((token) => !isFeatureOnlyToken(token)).join(' '), state, undefined, interactState))\n : molecule\n const base = attachFeatures({ style }, tokens)\n cacheResolved(key, base)\n return userStyle === undefined || userStyle === null ? base : { ...base, style: withUserStyle(base.style, userStyle) }\n}\n\n/** Local mutable view for building the frozen-shaped result. */\ntype Mutable<T> = { -readonly [K in keyof T]: T[K] }\n\n/** Test-only — clear the molecule / gradient / haptic registries + cache. */\nexport function __resetResolveState(): void {\n molecules = Object.create(null)\n gradients = Object.create(null)\n haptics = Object.create(null)\n resolvedCache.clear()\n registryVersion += 1\n cachedFor = -1\n}\n\n/** Test-only — current resolved-cache entry count + its hard ceiling. */\nexport function __resolveCacheStats(): { size: number; max: number } {\n return { size: resolvedCache.size, max: MAX_RESOLVED_CACHE }\n}\n\nexport {normalizeClassName} from '../core/normalize-classname'"],"names":["getStyleVersion","normalizeClassName","lookupCss"],"mappings":"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"}
1
+ {"version":3,"file":"resolve.cjs","sources":["../../../../src/runtime/resolve.ts"],"sourcesContent":["import { breakpointTier, getStyleVersion, lookupCss, type InteractState } from './lookup-css'\nimport type { RnwindState } from './components/rnwind-provider'\nimport { normalizeClassName } from '../core/normalize-classname'\nimport type { GradientAtomInfo, GradientDirection } from '../core/parser/gradient'\nimport type { HapticRequest, HapticTrigger } from '../core/parser/haptics'\n\n/**\n * Rich className resolver — the runtime heart of the wrap / `useCss`.\n *\n * Resolution order, per className string:\n * 1. **Molecule** — a build-time PRE-MERGED single style object for the\n * whole literal className (per scheme). One map lookup returns it by\n * reference: no array, no merge, no per-atom loop. The common case.\n * 2. **Atom fallback** — for a className the scanner never saw (a\n * runtime-built string like `` `${className} px-2` ``) OR one that\n * carries context-dependent atoms (`pt-safe`, `text-base`, `md:*`),\n * fall back to per-atom resolution via `lookupCss`, which folds in\n * insets / fontScale / breakpoint / scheme.\n *\n * Results are cached by `(normalized className, scheme, insets, fontScale,\n * breakpoint)` so repeated renders return the SAME reference until the\n * reactive context changes. Atoms / molecules / features all live in\n * build-time registries the generated `.rnwind/*.js` modules populate.\n */\n\n/** Always-loaded fallback scheme key. */\nconst COMMON_SCHEME = 'common'\n\n/** Empty style sentinel. */\nconst EMPTY: readonly unknown[] = []\n\n/** scheme → normalized className → pre-merged style object. */\nlet molecules: Record<string, Record<string, unknown>> = Object.create(null)\n/** atom name → gradient role + resolved colour. */\nlet gradients: Record<string, GradientAtomInfo> = Object.create(null)\n/** atom name (incl. `active:`/`focus:` prefix) → haptic request. */\nlet haptics: Record<string, HapticRequest> = Object.create(null)\n/** Bumps on any molecule/gradient/haptic registration. */\nlet registryVersion = 0\n\n/** Per-(className·state) resolved cache — strong references between context changes. */\nconst resolvedCache = new Map<string, ResolvedCss>()\n/** Version the cache was last valid for (`getStyleVersion()` + {@link registryVersion}). */\nlet cachedFor = -1\n\n/**\n * Hard ceiling on the resolved cache. The cache is pure memoisation, so\n * eviction only costs a re-resolve (sub-µs) — never correctness. Build\n * molecules are NOT in here; they live permanently in `molecules`.\n */\nconst MAX_RESOLVED_CACHE = 2048\n\n/**\n * Store a resolved result, bulk-evicting the OLDEST half when the cache\n * hits {@link MAX_RESOLVED_CACHE}. `Map` preserves insertion order, so the\n * first keys are the oldest. Bulk eviction keeps the hot (cache-hit) path\n * free of per-access LRU bookkeeping at the cost of an occasional small\n * recompute burst under sustained pressure (web / long sessions).\n * @param key Cache key.\n * @param value Resolved result to store.\n */\nfunction cacheResolved(key: string, value: ResolvedCss): void {\n if (resolvedCache.size >= MAX_RESOLVED_CACHE) {\n let drop = resolvedCache.size >> 1\n for (const oldKey of resolvedCache.keys()) {\n resolvedCache.delete(oldKey)\n if (--drop <= 0) break\n }\n }\n resolvedCache.set(key, value)\n}\n\n/** A unit-square gradient endpoint. */\ninterface GradientPoint {\n readonly x: number\n readonly y: number\n}\n\n/** Rich resolution: the RN `style` plus any className-derived props. */\nexport interface ResolvedCss {\n /** RN `style` value — a single molecule object (by ref) or an atom array. */\n readonly style: unknown\n /** Gradient stop colours (when the className is a complete gradient). */\n readonly colors?: readonly string[]\n /** Gradient start point. */\n readonly start?: GradientPoint\n /** Gradient end point. */\n readonly end?: GradientPoint\n /** Text truncation line count. */\n readonly numberOfLines?: number\n /** Text ellipsize mode. */\n readonly ellipsizeMode?: 'tail' | 'clip'\n /** Haptic requests present on the className, for the wrap to dispatch. */\n readonly haptics?: readonly { readonly request: HapticRequest; readonly trigger: HapticTrigger }[]\n}\n\n/** `GradientDirection` → expo-linear-gradient start/end points. */\nconst DIRECTION_POINTS: Record<GradientDirection, { start: GradientPoint; end: GradientPoint }> = {\n 'to-t': { start: { x: 0.5, y: 1 }, end: { x: 0.5, y: 0 } },\n 'to-b': { start: { x: 0.5, y: 0 }, end: { x: 0.5, y: 1 } },\n 'to-l': { start: { x: 1, y: 0.5 }, end: { x: 0, y: 0.5 } },\n 'to-r': { start: { x: 0, y: 0.5 }, end: { x: 1, y: 0.5 } },\n 'to-tl': { start: { x: 1, y: 1 }, end: { x: 0, y: 0 } },\n 'to-tr': { start: { x: 0, y: 1 }, end: { x: 1, y: 0 } },\n 'to-bl': { start: { x: 1, y: 0 }, end: { x: 0, y: 1 } },\n 'to-br': { start: { x: 0, y: 0 }, end: { x: 1, y: 1 } },\n unknown: { start: { x: 0, y: 0.5 }, end: { x: 1, y: 0.5 } },\n}\n\n/**\n * Register one scheme's pre-merged molecules (atom-merged literal\n * classNames). Merges onto any existing entries for the scheme.\n * @param scheme Scheme name (or `'common'`).\n * @param entries Normalized className → merged style object.\n */\nexport function registerMolecules(scheme: string, entries: Record<string, unknown>): void {\n molecules[scheme] = { ...molecules[scheme], ...entries }\n registryVersion += 1\n}\n\n/**\n * Register the gradient atom map (atom name → role + resolved colour).\n * @param map Atom name → gradient info.\n */\nexport function registerGradients(map: Record<string, GradientAtomInfo>): void {\n gradients = map\n registryVersion += 1\n}\n\n/**\n * Register the haptic atom map (atom name → request).\n * @param map Atom name → haptic request.\n */\nexport function registerHaptics(map: Record<string, HapticRequest>): void {\n haptics = map\n registryVersion += 1\n}\n\n\n\n/**\n * Per-state-object signature memo. `RnwindState` is created fresh (via the\n * provider's `useMemo`) whenever any field changes, so its identity is a\n * sound key — a new object means a new signature. Keyed weakly so states\n * GC with their provider.\n */\nconst stateSignatureCache = new WeakMap<RnwindState, string>()\n\n/**\n * Cache key dimension for the reactive context — everything that can\n * change a resolved style. Uses the numeric breakpoint TIER (count of\n * thresholds reached) from `breakpointTier(windowWidth)`, NOT the\n * `activeBreakpoint` NAME: the name clamps tier-0 into the smallest\n * breakpoint, so widths straddling that threshold (e.g. 320 vs 700 with\n * `sm=640`) would collide on one cache key and serve a stale style. The\n * tier is exact AND bounded — two widths in the same tier gate every\n * `sm:`/`md:`/… atom identically, so they resolve the same.\n * @param state Rnwind context.\n * @returns Compact signature string.\n */\nfunction stateSignature(state: RnwindState): string {\n const { insets } = state\n return `${state.scheme}|${insets.top},${insets.right},${insets.bottom},${insets.left}|${state.fontScale}|${breakpointTier(state.windowWidth)}`\n}\n\n/**\n * Memoised {@link stateSignature} — one `WeakMap.get` on the hot path\n * instead of rebuilding the template string every resolve.\n * @param state Rnwind context.\n * @returns Cached compact signature.\n */\nfunction stateSignatureCached(state: RnwindState): string {\n let signature = stateSignatureCache.get(state)\n if (signature === undefined) {\n signature = stateSignature(state)\n stateSignatureCache.set(state, signature)\n }\n return signature\n}\n\n/**\n * Compact signature of the live interactive state for the cache key.\n * @param interactState Active/focus flags, or undefined for the plain path.\n * @returns Two-bit signature (`''` when no interactive state).\n */\nfunction interactSignature(interactState?: InteractState): string {\n if (!interactState) return ''\n const active = interactState.active ? 1 : 0\n const focus = interactState.focus ? 1 : 0\n return `${active}${focus}`\n}\n\n/**\n * Whether a token is a feature-ONLY utility (gradient stop/direction,\n * haptic request, or text-truncate) that contributes NO RN `style`. These\n * are folded in via {@link attachFeatures}, so they must be kept OUT of\n * the `lookupCss` input — otherwise the atom resolver treats them as\n * unknown style atoms and emits a spurious \"unknown class\" dev warning\n * (e.g. for `active:haptic-rigid`).\n * @param token Atom name.\n * @returns True when the token carries no style.\n */\nfunction isFeatureOnlyToken(token: string): boolean {\n return Boolean(gradients[token]) || Boolean(haptics[token]) || truncateForToken(token) !== null\n}\n\n/**\n * Lifecycle trigger for a haptic atom from its variant prefix.\n * @param token Atom name (maybe `active:`/`focus:`/`hover:` prefixed).\n * @returns The trigger.\n */\nfunction hapticTriggerForToken(token: string): HapticTrigger {\n const colon = token.indexOf(':')\n if (colon === -1) return 'mount'\n const prefix = token.slice(0, colon)\n if (prefix === 'active') return 'pressIn'\n if (prefix === 'focus') return 'focus'\n if (prefix === 'hover') return 'hover'\n return 'mount'\n}\n\n/**\n * Syntactic text-truncate directive for one atom.\n * @param token Atom name.\n * @returns Partial truncate props, or null.\n */\nfunction truncateForToken(token: string): { numberOfLines?: number; ellipsizeMode?: 'tail' | 'clip' } | null {\n if (token === 'truncate') return { numberOfLines: 1, ellipsizeMode: 'tail' }\n if (token === 'text-ellipsis') return { ellipsizeMode: 'tail' }\n if (token === 'text-clip') return { ellipsizeMode: 'clip' }\n if (token === 'line-clamp-none') return { numberOfLines: 0 }\n if (token.startsWith('line-clamp-')) {\n const count = Number(token.slice('line-clamp-'.length))\n if (Number.isInteger(count) && count >= 0) return { numberOfLines: count }\n }\n return null\n}\n\n/**\n * Assemble gradient props from gradient roles present in the atom list.\n * @param tokens Atom names.\n * @returns `{colors, start, end}` or null when not a complete gradient.\n */\nfunction assembleGradient(tokens: readonly string[]): { colors: string[]; start: GradientPoint; end: GradientPoint } | null {\n let from: string | undefined\n let via: string | undefined\n let to: string | undefined\n let dir: GradientDirection | undefined\n for (const token of tokens) {\n const info = gradients[token]\n if (!info) continue\n switch (info.role) {\n case 'from': {\n from = info.color\n break\n }\n case 'via': {\n via = info.color\n break\n }\n case 'to': {\n to = info.color\n break\n }\n default: {\n ;({ dir } = info)\n }\n }\n }\n if (dir === undefined) return null\n const colors = [from, via, to].filter((color): color is string => color !== undefined)\n if (colors.length < 2) return null\n const points = DIRECTION_POINTS[dir]\n return { colors, start: points.start, end: points.end }\n}\n\n/**\n * Fold every truncate directive across the atom list into one result —\n * last token wins per prop (matches Tailwind last-wins).\n * @param tokens Atom names.\n * @returns Merged truncate props (empty when none apply).\n */\nfunction collectTruncate(tokens: readonly string[]): { numberOfLines?: number; ellipsizeMode?: 'tail' | 'clip' } {\n const out: { numberOfLines?: number; ellipsizeMode?: 'tail' | 'clip' } = {}\n for (const token of tokens) {\n const truncate = truncateForToken(token)\n if (!truncate) continue\n if (truncate.numberOfLines !== undefined) out.numberOfLines = truncate.numberOfLines\n if (truncate.ellipsizeMode !== undefined) out.ellipsizeMode = truncate.ellipsizeMode\n }\n return out\n}\n\n/**\n * Collect every haptic request present in the atom list, tagged with the\n * lifecycle trigger its variant prefix implies.\n * @param tokens Atom names.\n * @returns Haptic request list, or undefined when none apply.\n */\nfunction collectHaptics(tokens: readonly string[]): { request: HapticRequest; trigger: HapticTrigger }[] | undefined {\n let collected: { request: HapticRequest; trigger: HapticTrigger }[] | undefined\n for (const token of tokens) {\n const request = haptics[token]\n if (!request) continue\n collected ??= []\n collected.push({ request, trigger: hapticTriggerForToken(token) })\n }\n return collected\n}\n\n/**\n * Scan tokens for the className-derived feature props (gradient,\n * truncate, haptics) and fold them onto the base result.\n * @param base Result carrying the resolved `style`.\n * @param tokens Atom names.\n * @returns The result with any feature props attached.\n */\nfunction attachFeatures(base: ResolvedCss, tokens: readonly string[]): ResolvedCss {\n const { numberOfLines, ellipsizeMode } = collectTruncate(tokens)\n const collected = collectHaptics(tokens)\n const gradient = assembleGradient(tokens)\n const result: Mutable<ResolvedCss> = { style: base.style }\n if (gradient) {\n result.colors = gradient.colors\n result.start = gradient.start\n result.end = gradient.end\n }\n // `numberOfLines: 0` is kept (RN reads it as \"unlimited\"): `line-clamp-none`\n // must be able to explicitly reset an earlier `line-clamp-N` on the same\n // element — dropping the 0 would silently leave the prior limit in place.\n if (numberOfLines !== undefined) {\n result.numberOfLines = numberOfLines\n if (ellipsizeMode !== undefined) result.ellipsizeMode = ellipsizeMode\n }\n if (collected) result.haptics = collected\n return result\n}\n\n/**\n * Flatten the per-atom style array into ONE object — a *runtime molecule*.\n * RN flattens a style array left-to-right (later wins), which is exactly\n * `Object.assign` semantics, so the merged object renders identically\n * while giving dynamic (cva / clsx) classNames the same single-object\n * shape a build-time molecule has. The caller caches the result per\n * `(className · state)`, so the merge runs once per unique context.\n * @param array Per-atom style array from `lookupCss`.\n * @returns Single merged style object.\n */\nfunction mergeStyleArray(array: readonly unknown[]): Record<string, unknown> {\n const out: Record<string, unknown> = {}\n for (const entry of array) if (entry && typeof entry === 'object') Object.assign(out, entry)\n return out\n}\n\n/**\n * Compose a resolved style with a caller-supplied inline style (user wins).\n * @param style\n * @param userStyle\n */\nfunction withUserStyle(style: unknown, userStyle: unknown): unknown {\n return Array.isArray(style) ? [...style, userStyle] : [style, userStyle]\n}\n\n/**\n * Resolve a className against the reactive context into a style plus any\n * className-derived props. Molecule-first (one lookup, by reference),\n * atom-fallback for unseen / context-dependent strings, cached per\n * `(className, state)`.\n * @param className Raw className string.\n * @param state Rnwind context from `useRnwind()`.\n * @param userStyle Optional inline style appended last (wins).\n * @param interactState Live active/focus flags (for `active:`/`focus:` atoms).\n * @returns The resolved style + feature props.\n */\nexport function resolve(\n className: string | null | undefined,\n state: RnwindState,\n userStyle?: unknown,\n interactState?: InteractState,\n): ResolvedCss {\n const version = getStyleVersion() + registryVersion\n if (version !== cachedFor) {\n resolvedCache.clear()\n cachedFor = version\n }\n if (className == null) {\n return { style: userStyle === undefined || userStyle === null ? EMPTY : [userStyle] }\n }\n // Key on the RAW className so the hot (cache-hit) path skips normalize\n // entirely — normalization only runs on a miss. The state signature is\n // memoised per state object, so the hit path is one WeakMap.get + one\n // string concat + one Map.get.\n const key = `${className}@${stateSignatureCached(state)}@${interactSignature(interactState)}`\n const cached = resolvedCache.get(key)\n if (cached !== undefined) {\n return userStyle === undefined || userStyle === null ? cached : { ...cached, style: withUserStyle(cached.style, userStyle) }\n }\n const normalized = normalizeClassName(className)\n if (normalized.length === 0) {\n const empty: ResolvedCss = { style: EMPTY }\n cacheResolved(key, empty)\n return userStyle === undefined || userStyle === null ? empty : { style: [userStyle] }\n }\n // Molecules are static pre-merges; anything carrying `active:`/`focus:`\n // is never registered as one, so the atom path handles interactive state.\n const tokens = normalized.split(' ')\n const molecule = interactState ? undefined : molecules[state.scheme]?.[normalized] ?? molecules[COMMON_SCHEME]?.[normalized]\n // Feature-only tokens (gradient / haptic / truncate) carry no style — keep\n // them out of the atom lookup so they don't warn as \"unknown class\". The\n // atom array is merged into ONE object (a runtime molecule) so dynamic\n // (cva / clsx) classNames get the same single-object shape as a build\n // molecule; the cache below pins the context, so the merge is correct.\n const style =\n molecule === undefined\n ? mergeStyleArray(lookupCss(tokens.filter((token) => !isFeatureOnlyToken(token)).join(' '), state, undefined, interactState))\n : molecule\n const base = attachFeatures({ style }, tokens)\n cacheResolved(key, base)\n return userStyle === undefined || userStyle === null ? base : { ...base, style: withUserStyle(base.style, userStyle) }\n}\n\n/** Local mutable view for building the frozen-shaped result. */\ntype Mutable<T> = { -readonly [K in keyof T]: T[K] }\n\n/** Test-only — clear the molecule / gradient / haptic registries + cache. */\nexport function __resetResolveState(): void {\n molecules = Object.create(null)\n gradients = Object.create(null)\n haptics = Object.create(null)\n resolvedCache.clear()\n registryVersion += 1\n cachedFor = -1\n}\n\n/** Test-only — current resolved-cache entry count + its hard ceiling. */\nexport function __resolveCacheStats(): { size: number; max: number } {\n return { size: resolvedCache.size, max: MAX_RESOLVED_CACHE }\n}\n\nexport {normalizeClassName} from '../core/normalize-classname'"],"names":["breakpointTier","getStyleVersion","normalizeClassName","lookupCss"],"mappings":"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"}
@@ -75,8 +75,10 @@ const CLASSNAME_SUFFIX = 'ClassName';
75
75
  * handled separately by the leaf and never reaches here.
76
76
  * @param props Mutable prop object being assembled for the host.
77
77
  * @param state Rnwind context for resolution.
78
+ * @param interactState Live press/focus state so `active:`/`focus:` variants
79
+ * on a secondary class prop resolve too (undefined for non-interactive).
78
80
  */
79
- function applyContainerClassNames(props, state) {
81
+ function applyContainerClassNames(props, state, interactState) {
80
82
  for (const key of Object.keys(props)) {
81
83
  if (!key.endsWith(CLASSNAME_SUFFIX))
82
84
  continue;
@@ -84,7 +86,7 @@ function applyContainerClassNames(props, state) {
84
86
  if (typeof value !== 'string')
85
87
  continue;
86
88
  const styleKey = `${key.slice(0, -CLASSNAME_SUFFIX.length)}Style`;
87
- props[styleKey] = resolve.resolve(value, state, props[styleKey]).style;
89
+ props[styleKey] = resolve.resolve(value, state, props[styleKey], interactState).style;
88
90
  delete props[key];
89
91
  }
90
92
  }
@@ -99,12 +101,13 @@ function applyContainerClassNames(props, state) {
99
101
  * @param state Rnwind context — used to resolve secondary class props.
100
102
  * @param onHaptics Dispatcher from context.
101
103
  * @param userOnPressIn Caller-supplied onPressIn to chain after the haptic.
104
+ * @param interactState Live press/focus state for secondary class props.
102
105
  * @returns The merged prop object for `createElement`.
103
106
  */
104
- function buildProps(rest, resolved, state, onHaptics, userOnPressIn) {
107
+ function buildProps(rest, resolved, state, onHaptics, userOnPressIn, interactState) {
105
108
  warnIfHapticsUnwired(onHaptics, resolved.haptics);
106
109
  const props = { ...rest, style: resolved.style };
107
- applyContainerClassNames(props, state);
110
+ applyContainerClassNames(props, state, interactState);
108
111
  if (resolved.colors) {
109
112
  props.colors = resolved.colors;
110
113
  props.start = resolved.start;
@@ -129,56 +132,20 @@ function buildProps(rest, resolved, state, onHaptics, userOnPressIn) {
129
132
  }
130
133
  return props;
131
134
  }
132
- /**
133
- * Non-interactive leaf: resolve className → style (+ features) and
134
- * forward. One context read, one molecule/atom resolve.
135
- * @param props Leaf props.
136
- * @param props.as
137
- * @param props.className
138
- * @param props.style
139
- * @param props.onPressIn
140
- * @returns The rendered `as` element.
141
- */
142
- function PlainLeaf({ as: As, className, style, onPressIn, ...rest }) {
143
- const state = rnwindProvider.useRnwind();
144
- const resolved = resolve.resolve(className, state, style);
145
- useMountHaptics(resolved, state.onHaptics);
146
- return React.createElement(As, buildProps(rest, resolved, state, state.onHaptics, onPressIn));
147
- }
148
- /**
149
- * Interactive leaf: tracks press/focus via `useInteract()`, feeds it into
150
- * `resolve` so `active:`/`focus:` atoms apply, and chains the
151
- * press/focus handlers.
152
- * @param props Leaf props.
153
- * @param props.as
154
- * @param props.className
155
- * @param props.style
156
- * @param props.onPressIn
157
- * @param props.onPressOut
158
- * @param props.onFocus
159
- * @param props.onBlur
160
- * @returns The rendered `as` element with interactive wiring.
161
- */
162
- function InteractiveLeaf({ as: As, className, style, onPressIn, onPressOut, onFocus, onBlur, ...rest }) {
163
- const state = rnwindProvider.useRnwind();
164
- const interact = useInteract.useInteract();
165
- const resolved = resolve.resolve(className, state, style, interact.state);
166
- useMountHaptics(resolved, state.onHaptics);
167
- const props = buildProps(rest, resolved, state, state.onHaptics, onPressIn);
168
- props.onPressIn = chainHandlers.chainPress(props.onPressIn, interact.onPressIn);
169
- props.onPressOut = chainHandlers.chainPress(onPressOut, interact.onPressOut);
170
- props.onFocus = chainHandlers.chainFocus(onFocus, interact.onFocus);
171
- props.onBlur = chainHandlers.chainFocus(onBlur, interact.onBlur);
172
- return React.createElement(As, props);
173
- }
174
135
  /**
175
136
  * Wrap a component so its `className` prop resolves to RN `style` (plus
176
137
  * gradient / truncate props and haptic dispatch) at render — no matter
177
138
  * how className arrived: written directly, spread through `{...rest}`, or
178
- * forwarded down custom wrappers. The returned component is hook-free; it
179
- * dispatches to a plain or interactive leaf so non-interactive elements
180
- * never pay for press/focus state. `ref` (a normal prop in React 19) and
181
- * all other props forward untouched.
139
+ * forwarded down custom wrappers. `ref` (a normal prop in React 19) and all
140
+ * other props forward untouched.
141
+ *
142
+ * A SINGLE stable component does the work and always calls `useInteract()`,
143
+ * so its identity never changes when `className` flips between interactive
144
+ * (`active:`/`focus:`) and not — swapping the rendered component type would
145
+ * unmount + remount the whole host subtree (lost state, effect re-runs,
146
+ * visual flash). `useInteract` is cheap and shares one idle-state ref, so the
147
+ * always-on cost is a couple of `useState` cells; the press/focus handlers
148
+ * and live state only wire in when the className actually needs them.
182
149
  * @example
183
150
  * ```tsx
184
151
  * const Pressable = wrap(RNPressable)
@@ -190,16 +157,42 @@ function InteractiveLeaf({ as: As, className, style, onPressIn, onPressOut, onFo
190
157
  function wrap(Component) {
191
158
  const as = Component;
192
159
  /**
193
- * The wrapped component hook-free dispatcher to a leaf.
160
+ * The wrapped component. Stable identity + unconditional hooks; branches
161
+ * internally on whether the className carries an interactive variant.
194
162
  * @param props Forwarded props with `className` intercepted.
195
- * @param props.className
196
- * @returns The rendered leaf.
163
+ * @param props.className Raw className string.
164
+ * @param props.style Caller-supplied style, merged under the resolved style.
165
+ * @param props.onPressIn Caller onPressIn — chained after haptics / interact.
166
+ * @param props.onPressOut Caller onPressOut — chained with interact when active.
167
+ * @param props.onFocus Caller onFocus — chained with interact when active.
168
+ * @param props.onBlur Caller onBlur — chained with interact when active.
169
+ * @returns The rendered `as` element.
197
170
  */
198
- function RnwindWrapped({ className, ...rest }) {
199
- if (className !== undefined && hasInteractiveVariant(className)) {
200
- return React.createElement(InteractiveLeaf, { as, className, ...rest });
171
+ function RnwindWrapped({ className, style, onPressIn, onPressOut, onFocus, onBlur, ...rest }) {
172
+ const state = rnwindProvider.useRnwind();
173
+ const interact = useInteract.useInteract();
174
+ const isInteractive = className !== undefined && hasInteractiveVariant(className);
175
+ const interactState = isInteractive ? interact.state : undefined;
176
+ const resolved = resolve.resolve(className, state, style, interactState);
177
+ useMountHaptics(resolved, state.onHaptics);
178
+ const props = buildProps(rest, resolved, state, state.onHaptics, onPressIn, interactState);
179
+ if (isInteractive) {
180
+ props.onPressIn = chainHandlers.chainPress(props.onPressIn, interact.onPressIn);
181
+ props.onPressOut = chainHandlers.chainPress(onPressOut, interact.onPressOut);
182
+ props.onFocus = chainHandlers.chainFocus(onFocus, interact.onFocus);
183
+ props.onBlur = chainHandlers.chainFocus(onBlur, interact.onBlur);
184
+ }
185
+ else {
186
+ // Forward the caller's press/focus handlers untouched (onPressIn is
187
+ // already set by buildProps, possibly haptic-chained).
188
+ if (onPressOut !== undefined)
189
+ props.onPressOut = onPressOut;
190
+ if (onFocus !== undefined)
191
+ props.onFocus = onFocus;
192
+ if (onBlur !== undefined)
193
+ props.onBlur = onBlur;
201
194
  }
202
- return React.createElement(PlainLeaf, { as, className, ...rest });
195
+ return React.createElement(as, props);
203
196
  }
204
197
  RnwindWrapped.displayName = `wrap(${displayNameOf(Component)})`;
205
198
  return RnwindWrapped;
@@ -1 +1 @@
1
- {"version":3,"file":"wrap.cjs","sources":["../../../../src/runtime/wrap.tsx"],"sourcesContent":["import { createElement, useEffect, useRef, type ComponentType, type ReactElement } from 'react'\nimport { chainFocus, chainPress } from './chain-handlers'\nimport { useInteract } from './hooks/use-interact'\nimport { useRnwind } from './components/rnwind-provider'\nimport type { RnwindState } from './components/rnwind-provider'\nimport { resolve, type ResolvedCss } from './resolve'\nimport type { OnHaptics } from '../core/parser/haptics'\n\n/** Matches a leading `active:` / `focus:` variant token (`\\b` excludes `inactive:`). */\nconst INTERACTIVE_VARIANT = /\\b(?:active|focus):/\n\n/** One-shot guard so the missing-`onHaptics` warning logs once per session. */\nlet warnedMissingOnHaptics = false\n\n/**\n * Dev-only warning when a className carries a haptic utility but no\n * `onHaptics` dispatcher is wired on the nearest `<RnwindProvider>` — the\n * haptic would silently drop otherwise. Fires once per session.\n * @param onHaptics The dispatcher from context (or undefined).\n * @param haptics The resolved haptic requests (or undefined).\n */\nfunction warnIfHapticsUnwired(onHaptics: OnHaptics | undefined, haptics: ResolvedCss['haptics']): void {\n if (onHaptics || !haptics || haptics.length === 0) return\n const isDevelopment = typeof __DEV__ === 'undefined' || __DEV__\n if (!isDevelopment || warnedMissingOnHaptics) return\n warnedMissingOnHaptics = true\n // eslint-disable-next-line no-console\n console.warn(\n 'rnwind: a `haptic-*` utility resolved but no `onHaptics` callback is wired on <RnwindProvider>. ' +\n 'Pass `onHaptics` on the provider to forward the request to expo-haptics (or any library).',\n )\n}\n\n/**\n * Whether a className needs press/focus state tracking.\n * @param className Raw className string.\n * @returns True when an `active:` / `focus:` variant is present.\n */\nfunction hasInteractiveVariant(className: string): boolean {\n return INTERACTIVE_VARIANT.test(className)\n}\n\n/**\n * Best-effort display name for the wrapped component.\n * @param component Component being wrapped.\n * @returns Its `displayName`, `name`, or `'Component'`.\n */\nfunction displayNameOf(component: unknown): string {\n const named = component as { displayName?: string; name?: string }\n return named.displayName ?? named.name ?? 'Component'\n}\n\n/**\n * Fire the `mount`-trigger haptics once, after the element mounts. Snaps\n * the resolved requests + dispatcher at mount via a `useRef` initializer\n * (evaluated only on the first render), so an unstable inline `onHaptics`\n * doesn't re-fire them and no ref is written during render.\n * @param resolved The resolved className (carries any haptic requests).\n * @param onHaptics The dispatcher from context (or undefined).\n */\nfunction useMountHaptics(resolved: ResolvedCss, onHaptics: OnHaptics | undefined): void {\n const mount = useRef({ resolved, onHaptics })\n useEffect(() => {\n const { resolved: current, onHaptics: dispatch } = mount.current\n if (!dispatch || !current.haptics) return\n for (const entry of current.haptics) if (entry.trigger === 'mount') dispatch(entry.request, 'mount')\n }, [])\n}\n\n/** Suffix marking a secondary class-prop (`contentContainerClassName`, …). */\nconst CLASSNAME_SUFFIX = 'ClassName'\n\n/**\n * Resolve every secondary `<prefix>ClassName` prop (e.g.\n * `contentContainerClassName` on a ScrollView / FlatList) into its\n * matching `<prefix>Style`, in place. Any existing `<prefix>Style` is\n * appended last (caller wins). The original `*ClassName` prop is deleted\n * so RN never sees an unknown attribute. The primary `className` is\n * handled separately by the leaf and never reaches here.\n * @param props Mutable prop object being assembled for the host.\n * @param state Rnwind context for resolution.\n */\nfunction applyContainerClassNames(props: Record<string, unknown>, state: RnwindState): void {\n for (const key of Object.keys(props)) {\n if (!key.endsWith(CLASSNAME_SUFFIX)) continue\n const value = props[key]\n if (typeof value !== 'string') continue\n const styleKey = `${key.slice(0, -CLASSNAME_SUFFIX.length)}Style`\n props[styleKey] = resolve(value, state, props[styleKey]).style\n delete props[key]\n }\n}\n\n/**\n * Build the props for the wrapped host: resolved `style`, gradient\n * (`colors`/`start`/`end`), truncate (`numberOfLines`/`ellipsizeMode`),\n * secondary `<prefix>ClassName` → `<prefix>Style`, and a chained\n * `onPressIn` that fires press-trigger haptics. Unknown props on a host\n * are simply ignored by RN, so this stays generic.\n * @param rest Forwarded props (incl. `ref`).\n * @param resolved Resolved className result.\n * @param state Rnwind context — used to resolve secondary class props.\n * @param onHaptics Dispatcher from context.\n * @param userOnPressIn Caller-supplied onPressIn to chain after the haptic.\n * @returns The merged prop object for `createElement`.\n */\nfunction buildProps(\n rest: Record<string, unknown>,\n resolved: ResolvedCss,\n state: RnwindState,\n onHaptics: OnHaptics | undefined,\n userOnPressIn?: unknown,\n): Record<string, unknown> {\n warnIfHapticsUnwired(onHaptics, resolved.haptics)\n const props: Record<string, unknown> = { ...rest, style: resolved.style }\n applyContainerClassNames(props, state)\n if (resolved.colors) {\n props.colors = resolved.colors\n props.start = resolved.start\n props.end = resolved.end\n }\n if (resolved.numberOfLines !== undefined) {\n props.numberOfLines = resolved.numberOfLines\n if (resolved.ellipsizeMode !== undefined) props.ellipsizeMode = resolved.ellipsizeMode\n }\n const pressHaptics = onHaptics && resolved.haptics?.filter((entry) => entry.trigger === 'pressIn')\n if (pressHaptics && pressHaptics.length > 0) {\n const previous = userOnPressIn as ((event: unknown) => void) | undefined\n props.onPressIn = (event: unknown): void => {\n for (const entry of pressHaptics) onHaptics(entry.request, 'pressIn')\n previous?.(event)\n }\n } else if (userOnPressIn !== undefined) {\n props.onPressIn = userOnPressIn\n }\n return props\n}\n\n/** Props a leaf receives — the wrapped `as` tag plus forwarded props. */\ninterface LeafProps {\n readonly as: ComponentType<Record<string, unknown>>\n readonly className?: string\n readonly style?: unknown\n readonly [key: string]: unknown\n}\n\n/**\n * Non-interactive leaf: resolve className → style (+ features) and\n * forward. One context read, one molecule/atom resolve.\n * @param props Leaf props.\n * @param props.as\n * @param props.className\n * @param props.style\n * @param props.onPressIn\n * @returns The rendered `as` element.\n */\nfunction PlainLeaf({ as: As, className, style, onPressIn, ...rest }: LeafProps): ReactElement {\n const state = useRnwind()\n const resolved = resolve(className, state, style)\n useMountHaptics(resolved, state.onHaptics)\n return createElement(As, buildProps(rest, resolved, state, state.onHaptics, onPressIn))\n}\n\n/**\n * Interactive leaf: tracks press/focus via `useInteract()`, feeds it into\n * `resolve` so `active:`/`focus:` atoms apply, and chains the\n * press/focus handlers.\n * @param props Leaf props.\n * @param props.as\n * @param props.className\n * @param props.style\n * @param props.onPressIn\n * @param props.onPressOut\n * @param props.onFocus\n * @param props.onBlur\n * @returns The rendered `as` element with interactive wiring.\n */\nfunction InteractiveLeaf({ as: As, className, style, onPressIn, onPressOut, onFocus, onBlur, ...rest }: LeafProps): ReactElement {\n const state = useRnwind()\n const interact = useInteract()\n const resolved = resolve(className, state, style, interact.state)\n useMountHaptics(resolved, state.onHaptics)\n const props = buildProps(rest, resolved, state, state.onHaptics, onPressIn)\n props.onPressIn = chainPress(props.onPressIn as Parameters<typeof chainPress>[0], interact.onPressIn)\n props.onPressOut = chainPress(onPressOut as Parameters<typeof chainPress>[0], interact.onPressOut)\n props.onFocus = chainFocus(onFocus as Parameters<typeof chainFocus>[0], interact.onFocus)\n props.onBlur = chainFocus(onBlur as Parameters<typeof chainFocus>[0], interact.onBlur)\n return createElement(As, props)\n}\n\n/**\n * Wrap a component so its `className` prop resolves to RN `style` (plus\n * gradient / truncate props and haptic dispatch) at render — no matter\n * how className arrived: written directly, spread through `{...rest}`, or\n * forwarded down custom wrappers. The returned component is hook-free; it\n * dispatches to a plain or interactive leaf so non-interactive elements\n * never pay for press/focus state. `ref` (a normal prop in React 19) and\n * all other props forward untouched.\n * @example\n * ```tsx\n * const Pressable = wrap(RNPressable)\n * <Pressable className=\"active:bg-sky-700 px-4 haptic-light\" onPress={fn} />\n * ```\n * @param Component Any component accepting a `style` prop.\n * @returns A component accepting `className`.\n */\nexport function wrap<P>(Component: ComponentType<P>): ComponentType<P & { className?: string }> {\n const as = Component as unknown as ComponentType<Record<string, unknown>>\n /**\n * The wrapped component — hook-free dispatcher to a leaf.\n * @param props Forwarded props with `className` intercepted.\n * @param props.className\n * @returns The rendered leaf.\n */\n function RnwindWrapped({ className, ...rest }: { className?: string; [key: string]: unknown }): ReactElement {\n if (className !== undefined && hasInteractiveVariant(className)) {\n return createElement(InteractiveLeaf, { as, className, ...rest })\n }\n return createElement(PlainLeaf, { as, className, ...rest })\n }\n RnwindWrapped.displayName = `wrap(${displayNameOf(Component)})`\n return RnwindWrapped as unknown as ComponentType<P & { className?: string }>\n}\n\n/**\n * Whether a namespace member name denotes a component to wrap —\n * PascalCase and not a React context (`*Context`). Lowercase utilities /\n * hooks (`createAnimatedComponent`, `spring`) pass through untouched.\n * @param name Member key.\n * @returns True when the member should be `wrap()`-ed.\n */\nfunction isComponentMember(name: string): boolean {\n return /^[A-Z]/.test(name) && !name.endsWith('Context')\n}\n\n/**\n * Wrap a component NAMESPACE (a default/namespace import like reanimated's\n * `Animated`) so member access — `Animated.View`, `Animated.ScrollView` —\n * returns a `wrap()`-ed component whose `className` resolves at render.\n * Returns a Proxy: component members are wrapped lazily and memoised so\n * each access yields the SAME wrapped component (stable identity — React\n * would remount otherwise). Non-component members (`createAnimatedComponent`,\n * config objects) pass straight through.\n * @example\n * ```tsx\n * const Animated = wrapNamespace(RNReanimated)\n * <Animated.View className=\"enter-fade\" />\n * ```\n * @param namespace The imported namespace object.\n * @returns A Proxy that wraps component members on access.\n */\nexport function wrapNamespace<T extends object>(namespace: T): T {\n const cache = new Map<string, unknown>()\n return new Proxy(namespace, {\n get(target, key, receiver): unknown {\n const value = Reflect.get(target, key, receiver)\n if (typeof key !== 'string' || !isComponentMember(key)) return value\n if (!value || (typeof value !== 'function' && typeof value !== 'object')) return value\n let wrapped = cache.get(key)\n if (wrapped === undefined) {\n wrapped = wrap(value as ComponentType<unknown>)\n cache.set(key, wrapped)\n }\n return wrapped\n },\n })\n}\n"],"names":["useRef","useEffect","resolve","useRnwind","createElement","useInteract","chainPress","chainFocus"],"mappings":"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"}
1
+ {"version":3,"file":"wrap.cjs","sources":["../../../../src/runtime/wrap.tsx"],"sourcesContent":["import { createElement, useEffect, useRef, type ComponentType, type ReactElement } from 'react'\nimport { chainFocus, chainPress } from './chain-handlers'\nimport { useInteract } from './hooks/use-interact'\nimport { useRnwind } from './components/rnwind-provider'\nimport type { RnwindState } from './components/rnwind-provider'\nimport type { InteractState } from './lookup-css'\nimport { resolve, type ResolvedCss } from './resolve'\nimport type { OnHaptics } from '../core/parser/haptics'\n\n/** Matches a leading `active:` / `focus:` variant token (`\\b` excludes `inactive:`). */\nconst INTERACTIVE_VARIANT = /\\b(?:active|focus):/\n\n/** One-shot guard so the missing-`onHaptics` warning logs once per session. */\nlet warnedMissingOnHaptics = false\n\n/**\n * Dev-only warning when a className carries a haptic utility but no\n * `onHaptics` dispatcher is wired on the nearest `<RnwindProvider>` — the\n * haptic would silently drop otherwise. Fires once per session.\n * @param onHaptics The dispatcher from context (or undefined).\n * @param haptics The resolved haptic requests (or undefined).\n */\nfunction warnIfHapticsUnwired(onHaptics: OnHaptics | undefined, haptics: ResolvedCss['haptics']): void {\n if (onHaptics || !haptics || haptics.length === 0) return\n const isDevelopment = typeof __DEV__ === 'undefined' || __DEV__\n if (!isDevelopment || warnedMissingOnHaptics) return\n warnedMissingOnHaptics = true\n // eslint-disable-next-line no-console\n console.warn(\n 'rnwind: a `haptic-*` utility resolved but no `onHaptics` callback is wired on <RnwindProvider>. ' +\n 'Pass `onHaptics` on the provider to forward the request to expo-haptics (or any library).',\n )\n}\n\n/**\n * Whether a className needs press/focus state tracking.\n * @param className Raw className string.\n * @returns True when an `active:` / `focus:` variant is present.\n */\nfunction hasInteractiveVariant(className: string): boolean {\n return INTERACTIVE_VARIANT.test(className)\n}\n\n/**\n * Best-effort display name for the wrapped component.\n * @param component Component being wrapped.\n * @returns Its `displayName`, `name`, or `'Component'`.\n */\nfunction displayNameOf(component: unknown): string {\n const named = component as { displayName?: string; name?: string }\n return named.displayName ?? named.name ?? 'Component'\n}\n\n/**\n * Fire the `mount`-trigger haptics once, after the element mounts. Snaps\n * the resolved requests + dispatcher at mount via a `useRef` initializer\n * (evaluated only on the first render), so an unstable inline `onHaptics`\n * doesn't re-fire them and no ref is written during render.\n * @param resolved The resolved className (carries any haptic requests).\n * @param onHaptics The dispatcher from context (or undefined).\n */\nfunction useMountHaptics(resolved: ResolvedCss, onHaptics: OnHaptics | undefined): void {\n const mount = useRef({ resolved, onHaptics })\n useEffect(() => {\n const { resolved: current, onHaptics: dispatch } = mount.current\n if (!dispatch || !current.haptics) return\n for (const entry of current.haptics) if (entry.trigger === 'mount') dispatch(entry.request, 'mount')\n }, [])\n}\n\n/** Suffix marking a secondary class-prop (`contentContainerClassName`, …). */\nconst CLASSNAME_SUFFIX = 'ClassName'\n\n/**\n * Resolve every secondary `<prefix>ClassName` prop (e.g.\n * `contentContainerClassName` on a ScrollView / FlatList) into its\n * matching `<prefix>Style`, in place. Any existing `<prefix>Style` is\n * appended last (caller wins). The original `*ClassName` prop is deleted\n * so RN never sees an unknown attribute. The primary `className` is\n * handled separately by the leaf and never reaches here.\n * @param props Mutable prop object being assembled for the host.\n * @param state Rnwind context for resolution.\n * @param interactState Live press/focus state so `active:`/`focus:` variants\n * on a secondary class prop resolve too (undefined for non-interactive).\n */\nfunction applyContainerClassNames(\n props: Record<string, unknown>,\n state: RnwindState,\n interactState?: InteractState,\n): void {\n for (const key of Object.keys(props)) {\n if (!key.endsWith(CLASSNAME_SUFFIX)) continue\n const value = props[key]\n if (typeof value !== 'string') continue\n const styleKey = `${key.slice(0, -CLASSNAME_SUFFIX.length)}Style`\n props[styleKey] = resolve(value, state, props[styleKey], interactState).style\n delete props[key]\n }\n}\n\n/**\n * Build the props for the wrapped host: resolved `style`, gradient\n * (`colors`/`start`/`end`), truncate (`numberOfLines`/`ellipsizeMode`),\n * secondary `<prefix>ClassName` → `<prefix>Style`, and a chained\n * `onPressIn` that fires press-trigger haptics. Unknown props on a host\n * are simply ignored by RN, so this stays generic.\n * @param rest Forwarded props (incl. `ref`).\n * @param resolved Resolved className result.\n * @param state Rnwind context — used to resolve secondary class props.\n * @param onHaptics Dispatcher from context.\n * @param userOnPressIn Caller-supplied onPressIn to chain after the haptic.\n * @param interactState Live press/focus state for secondary class props.\n * @returns The merged prop object for `createElement`.\n */\nfunction buildProps(\n rest: Record<string, unknown>,\n resolved: ResolvedCss,\n state: RnwindState,\n onHaptics: OnHaptics | undefined,\n userOnPressIn?: unknown,\n interactState?: InteractState,\n): Record<string, unknown> {\n warnIfHapticsUnwired(onHaptics, resolved.haptics)\n const props: Record<string, unknown> = { ...rest, style: resolved.style }\n applyContainerClassNames(props, state, interactState)\n if (resolved.colors) {\n props.colors = resolved.colors\n props.start = resolved.start\n props.end = resolved.end\n }\n if (resolved.numberOfLines !== undefined) {\n props.numberOfLines = resolved.numberOfLines\n if (resolved.ellipsizeMode !== undefined) props.ellipsizeMode = resolved.ellipsizeMode\n }\n const pressHaptics = onHaptics && resolved.haptics?.filter((entry) => entry.trigger === 'pressIn')\n if (pressHaptics && pressHaptics.length > 0) {\n const previous = userOnPressIn as ((event: unknown) => void) | undefined\n props.onPressIn = (event: unknown): void => {\n for (const entry of pressHaptics) onHaptics(entry.request, 'pressIn')\n previous?.(event)\n }\n } else if (userOnPressIn !== undefined) {\n props.onPressIn = userOnPressIn\n }\n return props\n}\n\n/** Props the wrapped renderer accepts — `className` plus forwarded props. */\ninterface WrappedProps {\n readonly className?: string\n readonly style?: unknown\n readonly onPressIn?: unknown\n readonly onPressOut?: unknown\n readonly onFocus?: unknown\n readonly onBlur?: unknown\n readonly [key: string]: unknown\n}\n\n/**\n * Wrap a component so its `className` prop resolves to RN `style` (plus\n * gradient / truncate props and haptic dispatch) at render — no matter\n * how className arrived: written directly, spread through `{...rest}`, or\n * forwarded down custom wrappers. `ref` (a normal prop in React 19) and all\n * other props forward untouched.\n *\n * A SINGLE stable component does the work and always calls `useInteract()`,\n * so its identity never changes when `className` flips between interactive\n * (`active:`/`focus:`) and not — swapping the rendered component type would\n * unmount + remount the whole host subtree (lost state, effect re-runs,\n * visual flash). `useInteract` is cheap and shares one idle-state ref, so the\n * always-on cost is a couple of `useState` cells; the press/focus handlers\n * and live state only wire in when the className actually needs them.\n * @example\n * ```tsx\n * const Pressable = wrap(RNPressable)\n * <Pressable className=\"active:bg-sky-700 px-4 haptic-light\" onPress={fn} />\n * ```\n * @param Component Any component accepting a `style` prop.\n * @returns A component accepting `className`.\n */\nexport function wrap<P>(Component: ComponentType<P>): ComponentType<P & { className?: string }> {\n const as = Component as unknown as ComponentType<Record<string, unknown>>\n /**\n * The wrapped component. Stable identity + unconditional hooks; branches\n * internally on whether the className carries an interactive variant.\n * @param props Forwarded props with `className` intercepted.\n * @param props.className Raw className string.\n * @param props.style Caller-supplied style, merged under the resolved style.\n * @param props.onPressIn Caller onPressIn — chained after haptics / interact.\n * @param props.onPressOut Caller onPressOut — chained with interact when active.\n * @param props.onFocus Caller onFocus — chained with interact when active.\n * @param props.onBlur Caller onBlur — chained with interact when active.\n * @returns The rendered `as` element.\n */\n function RnwindWrapped({ className, style, onPressIn, onPressOut, onFocus, onBlur, ...rest }: WrappedProps): ReactElement {\n const state = useRnwind()\n const interact = useInteract()\n const isInteractive = className !== undefined && hasInteractiveVariant(className)\n const interactState = isInteractive ? interact.state : undefined\n const resolved = resolve(className, state, style, interactState)\n useMountHaptics(resolved, state.onHaptics)\n const props = buildProps(rest, resolved, state, state.onHaptics, onPressIn, interactState)\n if (isInteractive) {\n props.onPressIn = chainPress(props.onPressIn as Parameters<typeof chainPress>[0], interact.onPressIn)\n props.onPressOut = chainPress(onPressOut as Parameters<typeof chainPress>[0], interact.onPressOut)\n props.onFocus = chainFocus(onFocus as Parameters<typeof chainFocus>[0], interact.onFocus)\n props.onBlur = chainFocus(onBlur as Parameters<typeof chainFocus>[0], interact.onBlur)\n } else {\n // Forward the caller's press/focus handlers untouched (onPressIn is\n // already set by buildProps, possibly haptic-chained).\n if (onPressOut !== undefined) props.onPressOut = onPressOut\n if (onFocus !== undefined) props.onFocus = onFocus\n if (onBlur !== undefined) props.onBlur = onBlur\n }\n return createElement(as, props)\n }\n RnwindWrapped.displayName = `wrap(${displayNameOf(Component)})`\n return RnwindWrapped as unknown as ComponentType<P & { className?: string }>\n}\n\n/**\n * Whether a namespace member name denotes a component to wrap —\n * PascalCase and not a React context (`*Context`). Lowercase utilities /\n * hooks (`createAnimatedComponent`, `spring`) pass through untouched.\n * @param name Member key.\n * @returns True when the member should be `wrap()`-ed.\n */\nfunction isComponentMember(name: string): boolean {\n return /^[A-Z]/.test(name) && !name.endsWith('Context')\n}\n\n/**\n * Wrap a component NAMESPACE (a default/namespace import like reanimated's\n * `Animated`) so member access — `Animated.View`, `Animated.ScrollView` —\n * returns a `wrap()`-ed component whose `className` resolves at render.\n * Returns a Proxy: component members are wrapped lazily and memoised so\n * each access yields the SAME wrapped component (stable identity — React\n * would remount otherwise). Non-component members (`createAnimatedComponent`,\n * config objects) pass straight through.\n * @example\n * ```tsx\n * const Animated = wrapNamespace(RNReanimated)\n * <Animated.View className=\"enter-fade\" />\n * ```\n * @param namespace The imported namespace object.\n * @returns A Proxy that wraps component members on access.\n */\nexport function wrapNamespace<T extends object>(namespace: T): T {\n const cache = new Map<string, unknown>()\n return new Proxy(namespace, {\n get(target, key, receiver): unknown {\n const value = Reflect.get(target, key, receiver)\n if (typeof key !== 'string' || !isComponentMember(key)) return value\n if (!value || (typeof value !== 'function' && typeof value !== 'object')) return value\n let wrapped = cache.get(key)\n if (wrapped === undefined) {\n wrapped = wrap(value as ComponentType<unknown>)\n cache.set(key, wrapped)\n }\n return wrapped\n },\n })\n}\n"],"names":["useRef","useEffect","resolve","useRnwind","useInteract","chainPress","chainFocus","createElement"],"mappings":"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"}
@@ -3,10 +3,16 @@ import { type ComponentType } from 'react';
3
3
  * Wrap a component so its `className` prop resolves to RN `style` (plus
4
4
  * gradient / truncate props and haptic dispatch) at render — no matter
5
5
  * how className arrived: written directly, spread through `{...rest}`, or
6
- * forwarded down custom wrappers. The returned component is hook-free; it
7
- * dispatches to a plain or interactive leaf so non-interactive elements
8
- * never pay for press/focus state. `ref` (a normal prop in React 19) and
9
- * all other props forward untouched.
6
+ * forwarded down custom wrappers. `ref` (a normal prop in React 19) and all
7
+ * other props forward untouched.
8
+ *
9
+ * A SINGLE stable component does the work and always calls `useInteract()`,
10
+ * so its identity never changes when `className` flips between interactive
11
+ * (`active:`/`focus:`) and not — swapping the rendered component type would
12
+ * unmount + remount the whole host subtree (lost state, effect re-runs,
13
+ * visual flash). `useInteract` is cheap and shares one idle-state ref, so the
14
+ * always-on cost is a couple of `useState` cells; the press/focus handlers
15
+ * and live state only wire in when the className actually needs them.
10
16
  * @example
11
17
  * ```tsx
12
18
  * const Pressable = wrap(RNPressable)
@@ -1,4 +1,14 @@
1
1
  import type { CssColor } from 'lightningcss';
2
+ /**
3
+ * Lower a wide-gamut / modern CSS color STRING (`oklch(…)`, `lab(…)`,
4
+ * `color(display-p3 …)`, …) to an sRGB hex/rgba string RN can paint. Returns
5
+ * `null` for anything RN already understands (hex, rgb, hsl, named) so the
6
+ * caller keeps the original text — only the unrepresentable forms convert.
7
+ * Mirrors {@link cssColorToString}'s culori lowering for the string path.
8
+ * @param text Resolved CSS color text (post theme-var substitution).
9
+ * @returns sRGB color string, or `null` when no conversion is needed/possible.
10
+ */
11
+ export declare function normalizeColorString(text: string): string | null;
2
12
  /**
3
13
  * Convert a lightningcss `CssColor` to an RN-safe color string. RGB
4
14
  * passes through unchanged. LAB / LCH / OKLAB / OKLCH / `color(xyz-…)`
@@ -32,7 +32,9 @@ function byteToHex(byte) {
32
32
  function rgbIntsToString(r, g, b, alpha) {
33
33
  if (alpha >= 1)
34
34
  return `#${byteToHex(r)}${byteToHex(g)}${byteToHex(b)}`;
35
- return `rgba(${r}, ${g}, ${b}, ${alpha})`;
35
+ // Round the alpha to shed f32 noise (`0.2 0.20000000298…`) — RN parses
36
+ // either, but the rounded form keeps generated StyleSheets compact.
37
+ return `rgba(${r}, ${g}, ${b}, ${Math.round(alpha * 10_000) / 10_000})`;
36
38
  }
37
39
  /**
38
40
  * Format a float-RGB triple + alpha (CSS `color(srgb …)` forms) as
@@ -130,6 +132,35 @@ function xyzToHex(color) {
130
132
  const mode = color.type === 'xyz-d50' ? 'xyz50' : 'xyz65';
131
133
  return withAlpha(formatHex({ mode, x: color.x, y: color.y, z: color.z }) ?? null, color.alpha);
132
134
  }
135
+ /**
136
+ * Modern CSS color functions RN's native view manager can't paint —
137
+ * everything else (hex, `rgb()`/`rgba()`, `hsl()`/`hsla()`, named colors,
138
+ * `transparent`, `currentColor`) RN reads directly and must pass through
139
+ * untouched. Custom `@theme` tokens reach the parser as `var(--color-x)`
140
+ * (only the default palette is `theme(inline)`-d), so they flow through the
141
+ * unparsed-string path where the typed {@link cssColorToString} never runs —
142
+ * this is the one place that lowers their wide-gamut values to sRGB.
143
+ */
144
+ const RN_UNREADABLE_COLOR_PREFIXES = ['oklch(', 'oklab(', 'lab(', 'lch(', 'color(', 'hwb('];
145
+ /**
146
+ * Lower a wide-gamut / modern CSS color STRING (`oklch(…)`, `lab(…)`,
147
+ * `color(display-p3 …)`, …) to an sRGB hex/rgba string RN can paint. Returns
148
+ * `null` for anything RN already understands (hex, rgb, hsl, named) so the
149
+ * caller keeps the original text — only the unrepresentable forms convert.
150
+ * Mirrors {@link cssColorToString}'s culori lowering for the string path.
151
+ * @param text Resolved CSS color text (post theme-var substitution).
152
+ * @returns sRGB color string, or `null` when no conversion is needed/possible.
153
+ */
154
+ function normalizeColorString(text) {
155
+ const lower = text.trim().toLowerCase();
156
+ if (!RN_UNREADABLE_COLOR_PREFIXES.some((prefix) => lower.startsWith(prefix)))
157
+ return null;
158
+ const parsed = rgb(text);
159
+ if (!parsed || ![parsed.r, parsed.g, parsed.b].every((v) => typeof v === 'number' && Number.isFinite(v)))
160
+ return null;
161
+ const alpha = typeof parsed.alpha === 'number' ? parsed.alpha : 1;
162
+ return rgbIntsToString(clampByte(parsed.r * 255), clampByte(parsed.g * 255), clampByte(parsed.b * 255), alpha);
163
+ }
133
164
  /**
134
165
  * Convert a lightningcss `CssColor` to an RN-safe color string. RGB
135
166
  * passes through unchanged. LAB / LCH / OKLAB / OKLCH / `color(xyz-…)`
@@ -187,5 +218,5 @@ function cssColorToString(color) {
187
218
  }
188
219
  }
189
220
 
190
- export { cssColorToString };
221
+ export { cssColorToString, normalizeColorString };
191
222
  //# sourceMappingURL=color.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"color.mjs","sources":["../../../../../src/core/parser/color.ts"],"sourcesContent":["import type { CssColor, LABColor } from 'lightningcss'\nimport { formatHex, rgb as culoriRgb } from 'culori'\n\n/**\n * Clamp a 0-255 float to the integer byte range RN color strings accept.\n * @param value Unclamped float (may be negative or above 255).\n * @returns Integer in `[0, 255]`.\n */\nfunction clampByte(value: number): number {\n if (value < 0) return 0\n if (value > 255) return 255\n return Math.round(value)\n}\n\n/**\n * Two-digit hex encoding of a 0-255 byte.\n * @param byte Byte value (may be out-of-range — clamped).\n * @returns Zero-padded two-char hex string.\n */\nfunction byteToHex(byte: number): string {\n const hex = clampByte(byte).toString(16)\n return hex.length === 1 ? `0${hex}` : hex\n}\n\n/**\n * Format an integer-RGB triple + alpha as `#rrggbb` or `rgba(r, g, b, a)`.\n * @param r 0-255 red.\n * @param g 0-255 green.\n * @param b 0-255 blue.\n * @param alpha 0-1 alpha.\n * @returns Color string.\n */\nfunction rgbIntsToString(r: number, g: number, b: number, alpha: number): string {\n if (alpha >= 1) return `#${byteToHex(r)}${byteToHex(g)}${byteToHex(b)}`\n return `rgba(${r}, ${g}, ${b}, ${alpha})`\n}\n\n/**\n * Format a float-RGB triple + alpha (CSS `color(srgb …)` forms) as\n * hex/rgba.\n * @param r 0-1 red.\n * @param g 0-1 green.\n * @param b 0-1 blue.\n * @param alpha 0-1 alpha.\n * @returns Color string.\n */\nfunction floatRgbToString(r: number, g: number, b: number, alpha: number): string {\n return rgbIntsToString(clampByte(r * 255), clampByte(g * 255), clampByte(b * 255), alpha)\n}\n\n/**\n * Dispatch a LAB-family color through culori's hex formatter.\n * @param color Typed LAB-family color.\n * @returns `#rrggbb` string, or `null` when culori couldn't convert.\n */\nfunction culoriHexFor(color: LABColor): string | null {\n switch (color.type) {\n case 'oklch': {\n return formatHex({ mode: 'oklch', l: color.l, c: color.c, h: color.h }) ?? null\n }\n case 'oklab': {\n return formatHex({ mode: 'oklab', l: color.l, a: color.a, b: color.b }) ?? null\n }\n case 'lab': {\n return formatHex({ mode: 'lab', l: color.l, a: color.a, b: color.b }) ?? null\n }\n case 'lch': {\n return formatHex({ mode: 'lch', l: color.l, c: color.c, h: color.h }) ?? null\n }\n default: {\n return null\n }\n }\n}\n\n/**\n * Composite a culori-produced sRGB hex with the source alpha into the RN\n * color string. Shared tail for every culori-backed conversion (lab\n * family, XYZ, wide-gamut RGB): opaque → the hex as-is; translucent →\n * `rgba(...)` rebuilt from the hex channels.\n * @param hex sRGB hex from culori, or `null` when culori rejected the color.\n * @param alpha Source alpha (0–1).\n * @returns RN color string.\n */\nfunction withAlpha(hex: string | null, alpha: number): string {\n if (!hex) return alpha < 1 ? 'rgba(0, 0, 0, 0)' : 'transparent'\n if (alpha >= 1) return hex\n const back = culoriRgb(hex)\n if (!back) return hex\n return rgbIntsToString(clampByte(back.r * 255), clampByte(back.g * 255), clampByte(back.b * 255), alpha)\n}\n\n/**\n * Convert a LAB / LCH / OKLAB / OKLCH color to sRGB hex via culori. RN\n * can't evaluate these modern color spaces at paint time; compile-time\n * lowering to sRGB is the only portable path.\n * @param color Typed lab-family color.\n * @returns Hex or rgba string in sRGB.\n */\nfunction labFamilyToHex(color: LABColor): string {\n return withAlpha(culoriHexFor(color), color.alpha)\n}\n\n/**\n * Convert a wide-gamut `color(<space> r g b)` triple to sRGB hex via\n * culori. The channels are NOT sRGB — each space (display-p3, rec2020,\n * a98-rgb, prophoto-rgb, srgb-linear) carries its own primaries / transfer\n * function, so a bare `channel * 255` would mis-paint. culori does the\n * gamut + gamma conversion to sRGB.\n * @param mode culori mode key for the source space.\n * @param r Source red (0–1).\n * @param g Source green (0–1).\n * @param b Source blue (0–1).\n * @param alpha Alpha channel (0–1).\n * @returns sRGB color string RN accepts.\n */\nfunction wideGamutToHex(mode: 'lrgb' | 'p3' | 'a98' | 'prophoto' | 'rec2020', r: number, g: number, b: number, alpha: number): string {\n return withAlpha(formatHex({ mode, r, g, b }) ?? null, alpha)\n}\n\n/**\n * Convert a CSS `color(xyz-d50 …)` / `color(xyz-d65 …)` value to sRGB hex\n * via culori.\n * @param color Typed XYZ color (discriminated by `type`).\n * @param color.type Whether the color is in the D50 or D65 XYZ space.\n * @param color.x CIE X component (0–1).\n * @param color.y CIE Y component (0–1).\n * @param color.z CIE Z component (0–1).\n * @param color.alpha Alpha channel (0–1).\n * @returns `#rrggbb` string, or `'transparent'` when culori rejects it.\n */\nfunction xyzToHex(color: { type: 'xyz-d50' | 'xyz-d65'; x: number; y: number; z: number; alpha: number }): string {\n const mode = color.type === 'xyz-d50' ? 'xyz50' : 'xyz65'\n return withAlpha(formatHex({ mode, x: color.x, y: color.y, z: color.z }) ?? null, color.alpha)\n}\n\n/**\n * Convert a lightningcss `CssColor` to an RN-safe color string. RGB\n * passes through unchanged. LAB / LCH / OKLAB / OKLCH / `color(xyz-…)`\n * forms go through culori to reach sRGB — RN's native view manager only\n * understands sRGB-family strings. SystemColor keywords (`'background'`,\n * `'canvas'`, …) pass through untouched; they have no RN analog and the\n * runtime ignores unknown color strings gracefully.\n * @param color Typed color value.\n * @returns Color string RN accepts.\n */\nexport function cssColorToString(color: CssColor): string {\n if (typeof color === 'string') return color\n switch (color.type) {\n case 'rgb': {\n return rgbIntsToString(color.r, color.g, color.b, color.alpha)\n }\n case 'lab':\n case 'lch':\n case 'oklab':\n case 'oklch': {\n return labFamilyToHex(color)\n }\n case 'srgb': {\n return floatRgbToString(color.r, color.g, color.b, color.alpha)\n }\n case 'srgb-linear': {\n return wideGamutToHex('lrgb', color.r, color.g, color.b, color.alpha)\n }\n case 'display-p3': {\n return wideGamutToHex('p3', color.r, color.g, color.b, color.alpha)\n }\n case 'a98-rgb': {\n return wideGamutToHex('a98', color.r, color.g, color.b, color.alpha)\n }\n case 'prophoto-rgb': {\n return wideGamutToHex('prophoto', color.r, color.g, color.b, color.alpha)\n }\n case 'rec2020': {\n return wideGamutToHex('rec2020', color.r, color.g, color.b, color.alpha)\n }\n case 'xyz-d50':\n case 'xyz-d65': {\n return xyzToHex(color)\n }\n case 'currentcolor': {\n return 'currentColor'\n }\n case 'light-dark': {\n return cssColorToString(color.light)\n }\n default: {\n return 'transparent'\n }\n }\n}\n"],"names":["culoriRgb"],"mappings":";;AAGA;;;;AAIG;AACH,SAAS,SAAS,CAAC,KAAa,EAAA;IAC9B,IAAI,KAAK,GAAG,CAAC;AAAE,QAAA,OAAO,CAAC;IACvB,IAAI,KAAK,GAAG,GAAG;AAAE,QAAA,OAAO,GAAG;AAC3B,IAAA,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;AAC1B;AAEA;;;;AAIG;AACH,SAAS,SAAS,CAAC,IAAY,EAAA;IAC7B,MAAM,GAAG,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC;AACxC,IAAA,OAAO,GAAG,CAAC,MAAM,KAAK,CAAC,GAAG,CAAA,CAAA,EAAI,GAAG,CAAA,CAAE,GAAG,GAAG;AAC3C;AAEA;;;;;;;AAOG;AACH,SAAS,eAAe,CAAC,CAAS,EAAE,CAAS,EAAE,CAAS,EAAE,KAAa,EAAA;IACrE,IAAI,KAAK,IAAI,CAAC;AAAE,QAAA,OAAO,IAAI,SAAS,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,EAAE;IACvE,OAAO,CAAA,KAAA,EAAQ,CAAC,CAAA,EAAA,EAAK,CAAC,KAAK,CAAC,CAAA,EAAA,EAAK,KAAK,CAAA,CAAA,CAAG;AAC3C;AAEA;;;;;;;;AAQG;AACH,SAAS,gBAAgB,CAAC,CAAS,EAAE,CAAS,EAAE,CAAS,EAAE,KAAa,EAAA;IACtE,OAAO,eAAe,CAAC,SAAS,CAAC,CAAC,GAAG,GAAG,CAAC,EAAE,SAAS,CAAC,CAAC,GAAG,GAAG,CAAC,EAAE,SAAS,CAAC,CAAC,GAAG,GAAG,CAAC,EAAE,KAAK,CAAC;AAC3F;AAEA;;;;AAIG;AACH,SAAS,YAAY,CAAC,KAAe,EAAA;AACnC,IAAA,QAAQ,KAAK,CAAC,IAAI;QAChB,KAAK,OAAO,EAAE;AACZ,YAAA,OAAO,SAAS,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,IAAI;QACjF;QACA,KAAK,OAAO,EAAE;AACZ,YAAA,OAAO,SAAS,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,IAAI;QACjF;QACA,KAAK,KAAK,EAAE;AACV,YAAA,OAAO,SAAS,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,IAAI;QAC/E;QACA,KAAK,KAAK,EAAE;AACV,YAAA,OAAO,SAAS,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,IAAI;QAC/E;QACA,SAAS;AACP,YAAA,OAAO,IAAI;QACb;;AAEJ;AAEA;;;;;;;;AAQG;AACH,SAAS,SAAS,CAAC,GAAkB,EAAE,KAAa,EAAA;AAClD,IAAA,IAAI,CAAC,GAAG;QAAE,OAAO,KAAK,GAAG,CAAC,GAAG,kBAAkB,GAAG,aAAa;IAC/D,IAAI,KAAK,IAAI,CAAC;AAAE,QAAA,OAAO,GAAG;AAC1B,IAAA,MAAM,IAAI,GAAGA,GAAS,CAAC,GAAG,CAAC;AAC3B,IAAA,IAAI,CAAC,IAAI;AAAE,QAAA,OAAO,GAAG;AACrB,IAAA,OAAO,eAAe,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,GAAG,GAAG,CAAC,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC,GAAG,GAAG,CAAC,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC,GAAG,GAAG,CAAC,EAAE,KAAK,CAAC;AAC1G;AAEA;;;;;;AAMG;AACH,SAAS,cAAc,CAAC,KAAe,EAAA;IACrC,OAAO,SAAS,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC;AACpD;AAEA;;;;;;;;;;;;AAYG;AACH,SAAS,cAAc,CAAC,IAAoD,EAAE,CAAS,EAAE,CAAS,EAAE,CAAS,EAAE,KAAa,EAAA;AAC1H,IAAA,OAAO,SAAS,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,IAAI,EAAE,KAAK,CAAC;AAC/D;AAEA;;;;;;;;;;AAUG;AACH,SAAS,QAAQ,CAAC,KAAsF,EAAA;AACtG,IAAA,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,KAAK,SAAS,GAAG,OAAO,GAAG,OAAO;AACzD,IAAA,OAAO,SAAS,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC;AAChG;AAEA;;;;;;;;;AASG;AACG,SAAU,gBAAgB,CAAC,KAAe,EAAA;IAC9C,IAAI,OAAO,KAAK,KAAK,QAAQ;AAAE,QAAA,OAAO,KAAK;AAC3C,IAAA,QAAQ,KAAK,CAAC,IAAI;QAChB,KAAK,KAAK,EAAE;AACV,YAAA,OAAO,eAAe,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC;QAChE;AACA,QAAA,KAAK,KAAK;AACV,QAAA,KAAK,KAAK;AACV,QAAA,KAAK,OAAO;QACZ,KAAK,OAAO,EAAE;AACZ,YAAA,OAAO,cAAc,CAAC,KAAK,CAAC;QAC9B;QACA,KAAK,MAAM,EAAE;AACX,YAAA,OAAO,gBAAgB,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC;QACjE;QACA,KAAK,aAAa,EAAE;YAClB,OAAO,cAAc,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC;QACvE;QACA,KAAK,YAAY,EAAE;YACjB,OAAO,cAAc,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC;QACrE;QACA,KAAK,SAAS,EAAE;YACd,OAAO,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC;QACtE;QACA,KAAK,cAAc,EAAE;YACnB,OAAO,cAAc,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC;QAC3E;QACA,KAAK,SAAS,EAAE;YACd,OAAO,cAAc,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC;QAC1E;AACA,QAAA,KAAK,SAAS;QACd,KAAK,SAAS,EAAE;AACd,YAAA,OAAO,QAAQ,CAAC,KAAK,CAAC;QACxB;QACA,KAAK,cAAc,EAAE;AACnB,YAAA,OAAO,cAAc;QACvB;QACA,KAAK,YAAY,EAAE;AACjB,YAAA,OAAO,gBAAgB,CAAC,KAAK,CAAC,KAAK,CAAC;QACtC;QACA,SAAS;AACP,YAAA,OAAO,aAAa;QACtB;;AAEJ;;;;"}
1
+ {"version":3,"file":"color.mjs","sources":["../../../../../src/core/parser/color.ts"],"sourcesContent":["import type { CssColor, LABColor } from 'lightningcss'\nimport { formatHex, rgb as culoriRgb } from 'culori'\n\n/**\n * Clamp a 0-255 float to the integer byte range RN color strings accept.\n * @param value Unclamped float (may be negative or above 255).\n * @returns Integer in `[0, 255]`.\n */\nfunction clampByte(value: number): number {\n if (value < 0) return 0\n if (value > 255) return 255\n return Math.round(value)\n}\n\n/**\n * Two-digit hex encoding of a 0-255 byte.\n * @param byte Byte value (may be out-of-range — clamped).\n * @returns Zero-padded two-char hex string.\n */\nfunction byteToHex(byte: number): string {\n const hex = clampByte(byte).toString(16)\n return hex.length === 1 ? `0${hex}` : hex\n}\n\n/**\n * Format an integer-RGB triple + alpha as `#rrggbb` or `rgba(r, g, b, a)`.\n * @param r 0-255 red.\n * @param g 0-255 green.\n * @param b 0-255 blue.\n * @param alpha 0-1 alpha.\n * @returns Color string.\n */\nfunction rgbIntsToString(r: number, g: number, b: number, alpha: number): string {\n if (alpha >= 1) return `#${byteToHex(r)}${byteToHex(g)}${byteToHex(b)}`\n // Round the alpha to shed f32 noise (`0.2 → 0.20000000298…`) — RN parses\n // either, but the rounded form keeps generated StyleSheets compact.\n return `rgba(${r}, ${g}, ${b}, ${Math.round(alpha * 10_000) / 10_000})`\n}\n\n/**\n * Format a float-RGB triple + alpha (CSS `color(srgb …)` forms) as\n * hex/rgba.\n * @param r 0-1 red.\n * @param g 0-1 green.\n * @param b 0-1 blue.\n * @param alpha 0-1 alpha.\n * @returns Color string.\n */\nfunction floatRgbToString(r: number, g: number, b: number, alpha: number): string {\n return rgbIntsToString(clampByte(r * 255), clampByte(g * 255), clampByte(b * 255), alpha)\n}\n\n/**\n * Dispatch a LAB-family color through culori's hex formatter.\n * @param color Typed LAB-family color.\n * @returns `#rrggbb` string, or `null` when culori couldn't convert.\n */\nfunction culoriHexFor(color: LABColor): string | null {\n switch (color.type) {\n case 'oklch': {\n return formatHex({ mode: 'oklch', l: color.l, c: color.c, h: color.h }) ?? null\n }\n case 'oklab': {\n return formatHex({ mode: 'oklab', l: color.l, a: color.a, b: color.b }) ?? null\n }\n case 'lab': {\n return formatHex({ mode: 'lab', l: color.l, a: color.a, b: color.b }) ?? null\n }\n case 'lch': {\n return formatHex({ mode: 'lch', l: color.l, c: color.c, h: color.h }) ?? null\n }\n default: {\n return null\n }\n }\n}\n\n/**\n * Composite a culori-produced sRGB hex with the source alpha into the RN\n * color string. Shared tail for every culori-backed conversion (lab\n * family, XYZ, wide-gamut RGB): opaque → the hex as-is; translucent →\n * `rgba(...)` rebuilt from the hex channels.\n * @param hex sRGB hex from culori, or `null` when culori rejected the color.\n * @param alpha Source alpha (0–1).\n * @returns RN color string.\n */\nfunction withAlpha(hex: string | null, alpha: number): string {\n if (!hex) return alpha < 1 ? 'rgba(0, 0, 0, 0)' : 'transparent'\n if (alpha >= 1) return hex\n const back = culoriRgb(hex)\n if (!back) return hex\n return rgbIntsToString(clampByte(back.r * 255), clampByte(back.g * 255), clampByte(back.b * 255), alpha)\n}\n\n/**\n * Convert a LAB / LCH / OKLAB / OKLCH color to sRGB hex via culori. RN\n * can't evaluate these modern color spaces at paint time; compile-time\n * lowering to sRGB is the only portable path.\n * @param color Typed lab-family color.\n * @returns Hex or rgba string in sRGB.\n */\nfunction labFamilyToHex(color: LABColor): string {\n return withAlpha(culoriHexFor(color), color.alpha)\n}\n\n/**\n * Convert a wide-gamut `color(<space> r g b)` triple to sRGB hex via\n * culori. The channels are NOT sRGB — each space (display-p3, rec2020,\n * a98-rgb, prophoto-rgb, srgb-linear) carries its own primaries / transfer\n * function, so a bare `channel * 255` would mis-paint. culori does the\n * gamut + gamma conversion to sRGB.\n * @param mode culori mode key for the source space.\n * @param r Source red (0–1).\n * @param g Source green (0–1).\n * @param b Source blue (0–1).\n * @param alpha Alpha channel (0–1).\n * @returns sRGB color string RN accepts.\n */\nfunction wideGamutToHex(mode: 'lrgb' | 'p3' | 'a98' | 'prophoto' | 'rec2020', r: number, g: number, b: number, alpha: number): string {\n return withAlpha(formatHex({ mode, r, g, b }) ?? null, alpha)\n}\n\n/**\n * Convert a CSS `color(xyz-d50 …)` / `color(xyz-d65 …)` value to sRGB hex\n * via culori.\n * @param color Typed XYZ color (discriminated by `type`).\n * @param color.type Whether the color is in the D50 or D65 XYZ space.\n * @param color.x CIE X component (0–1).\n * @param color.y CIE Y component (0–1).\n * @param color.z CIE Z component (0–1).\n * @param color.alpha Alpha channel (0–1).\n * @returns `#rrggbb` string, or `'transparent'` when culori rejects it.\n */\nfunction xyzToHex(color: { type: 'xyz-d50' | 'xyz-d65'; x: number; y: number; z: number; alpha: number }): string {\n const mode = color.type === 'xyz-d50' ? 'xyz50' : 'xyz65'\n return withAlpha(formatHex({ mode, x: color.x, y: color.y, z: color.z }) ?? null, color.alpha)\n}\n\n/**\n * Modern CSS color functions RN's native view manager can't paint —\n * everything else (hex, `rgb()`/`rgba()`, `hsl()`/`hsla()`, named colors,\n * `transparent`, `currentColor`) RN reads directly and must pass through\n * untouched. Custom `@theme` tokens reach the parser as `var(--color-x)`\n * (only the default palette is `theme(inline)`-d), so they flow through the\n * unparsed-string path where the typed {@link cssColorToString} never runs —\n * this is the one place that lowers their wide-gamut values to sRGB.\n */\nconst RN_UNREADABLE_COLOR_PREFIXES: readonly string[] = ['oklch(', 'oklab(', 'lab(', 'lch(', 'color(', 'hwb(']\n\n/**\n * Lower a wide-gamut / modern CSS color STRING (`oklch(…)`, `lab(…)`,\n * `color(display-p3 …)`, …) to an sRGB hex/rgba string RN can paint. Returns\n * `null` for anything RN already understands (hex, rgb, hsl, named) so the\n * caller keeps the original text — only the unrepresentable forms convert.\n * Mirrors {@link cssColorToString}'s culori lowering for the string path.\n * @param text Resolved CSS color text (post theme-var substitution).\n * @returns sRGB color string, or `null` when no conversion is needed/possible.\n */\nexport function normalizeColorString(text: string): string | null {\n const lower = text.trim().toLowerCase()\n if (!RN_UNREADABLE_COLOR_PREFIXES.some((prefix) => lower.startsWith(prefix))) return null\n const parsed = culoriRgb(text)\n if (!parsed || ![parsed.r, parsed.g, parsed.b].every((v) => typeof v === 'number' && Number.isFinite(v))) return null\n const alpha = typeof parsed.alpha === 'number' ? parsed.alpha : 1\n return rgbIntsToString(clampByte(parsed.r * 255), clampByte(parsed.g * 255), clampByte(parsed.b * 255), alpha)\n}\n\n/**\n * Convert a lightningcss `CssColor` to an RN-safe color string. RGB\n * passes through unchanged. LAB / LCH / OKLAB / OKLCH / `color(xyz-…)`\n * forms go through culori to reach sRGB — RN's native view manager only\n * understands sRGB-family strings. SystemColor keywords (`'background'`,\n * `'canvas'`, …) pass through untouched; they have no RN analog and the\n * runtime ignores unknown color strings gracefully.\n * @param color Typed color value.\n * @returns Color string RN accepts.\n */\nexport function cssColorToString(color: CssColor): string {\n if (typeof color === 'string') return color\n switch (color.type) {\n case 'rgb': {\n return rgbIntsToString(color.r, color.g, color.b, color.alpha)\n }\n case 'lab':\n case 'lch':\n case 'oklab':\n case 'oklch': {\n return labFamilyToHex(color)\n }\n case 'srgb': {\n return floatRgbToString(color.r, color.g, color.b, color.alpha)\n }\n case 'srgb-linear': {\n return wideGamutToHex('lrgb', color.r, color.g, color.b, color.alpha)\n }\n case 'display-p3': {\n return wideGamutToHex('p3', color.r, color.g, color.b, color.alpha)\n }\n case 'a98-rgb': {\n return wideGamutToHex('a98', color.r, color.g, color.b, color.alpha)\n }\n case 'prophoto-rgb': {\n return wideGamutToHex('prophoto', color.r, color.g, color.b, color.alpha)\n }\n case 'rec2020': {\n return wideGamutToHex('rec2020', color.r, color.g, color.b, color.alpha)\n }\n case 'xyz-d50':\n case 'xyz-d65': {\n return xyzToHex(color)\n }\n case 'currentcolor': {\n return 'currentColor'\n }\n case 'light-dark': {\n return cssColorToString(color.light)\n }\n default: {\n return 'transparent'\n }\n }\n}\n"],"names":["culoriRgb"],"mappings":"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"}