rnwind 0.0.5 → 0.0.6

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.
@@ -37,6 +37,32 @@ let registryVersion = 0;
37
37
  const resolvedCache = new Map();
38
38
  /** Version the cache was last valid for (`getStyleVersion()` + {@link registryVersion}). */
39
39
  let cachedFor = -1;
40
+ /**
41
+ * Hard ceiling on the resolved cache. The cache is pure memoisation, so
42
+ * eviction only costs a re-resolve (sub-µs) — never correctness. Build
43
+ * molecules are NOT in here; they live permanently in `molecules`.
44
+ */
45
+ const MAX_RESOLVED_CACHE = 2048;
46
+ /**
47
+ * Store a resolved result, bulk-evicting the OLDEST half when the cache
48
+ * hits {@link MAX_RESOLVED_CACHE}. `Map` preserves insertion order, so the
49
+ * first keys are the oldest. Bulk eviction keeps the hot (cache-hit) path
50
+ * free of per-access LRU bookkeeping at the cost of an occasional small
51
+ * recompute burst under sustained pressure (web / long sessions).
52
+ * @param key Cache key.
53
+ * @param value Resolved result to store.
54
+ */
55
+ function cacheResolved(key, value) {
56
+ if (resolvedCache.size >= MAX_RESOLVED_CACHE) {
57
+ let drop = resolvedCache.size >> 1;
58
+ for (const oldKey of resolvedCache.keys()) {
59
+ resolvedCache.delete(oldKey);
60
+ if (--drop <= 0)
61
+ break;
62
+ }
63
+ }
64
+ resolvedCache.set(key, value);
65
+ }
40
66
  /** `GradientDirection` → expo-linear-gradient start/end points. */
41
67
  const DIRECTION_POINTS = {
42
68
  'to-t': { start: { x: 0.5, y: 1 }, end: { x: 0.5, y: 0 } },
@@ -84,13 +110,17 @@ function registerHaptics(map) {
84
110
  const stateSignatureCache = new WeakMap();
85
111
  /**
86
112
  * Cache key dimension for the reactive context — everything that can
87
- * change a resolved style.
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.
88
118
  * @param state Rnwind context.
89
119
  * @returns Compact signature string.
90
120
  */
91
121
  function stateSignature(state) {
92
122
  const { insets } = state;
93
- return `${state.scheme}|${insets.top},${insets.right},${insets.bottom},${insets.left}|${state.fontScale}|${state.windowWidth}`;
123
+ return `${state.scheme}|${insets.top},${insets.right},${insets.bottom},${insets.left}|${state.fontScale}|${state.activeBreakpoint}`;
94
124
  }
95
125
  /**
96
126
  * Memoised {@link stateSignature} — one `WeakMap.get` on the hot path
@@ -275,6 +305,23 @@ function attachFeatures(base, tokens) {
275
305
  result.haptics = collected;
276
306
  return result;
277
307
  }
308
+ /**
309
+ * Flatten the per-atom style array into ONE object — a *runtime molecule*.
310
+ * RN flattens a style array left-to-right (later wins), which is exactly
311
+ * `Object.assign` semantics, so the merged object renders identically
312
+ * while giving dynamic (cva / clsx) classNames the same single-object
313
+ * shape a build-time molecule has. The caller caches the result per
314
+ * `(className · state)`, so the merge runs once per unique context.
315
+ * @param array Per-atom style array from `lookupCss`.
316
+ * @returns Single merged style object.
317
+ */
318
+ function mergeStyleArray(array) {
319
+ const out = {};
320
+ for (const entry of array)
321
+ if (entry && typeof entry === 'object')
322
+ Object.assign(out, entry);
323
+ return out;
324
+ }
278
325
  /**
279
326
  * Compose a resolved style with a caller-supplied inline style (user wins).
280
327
  * @param style
@@ -315,7 +362,7 @@ function resolve(className, state, userStyle, interactState) {
315
362
  const normalized = normalizeClassname.normalizeClassName(className);
316
363
  if (normalized.length === 0) {
317
364
  const empty = { style: EMPTY };
318
- resolvedCache.set(key, empty);
365
+ cacheResolved(key, empty);
319
366
  return userStyle === undefined || userStyle === null ? empty : { style: [userStyle] };
320
367
  }
321
368
  // Molecules are static pre-merges; anything carrying `active:`/`focus:`
@@ -323,10 +370,15 @@ function resolve(className, state, userStyle, interactState) {
323
370
  const tokens = normalized.split(' ');
324
371
  const molecule = interactState ? undefined : molecules[state.scheme]?.[normalized] ?? molecules[COMMON_SCHEME]?.[normalized];
325
372
  // Feature-only tokens (gradient / haptic / truncate) carry no style — keep
326
- // them out of the atom lookup so they don't warn as "unknown class".
327
- const style = molecule === undefined ? lookupCss.lookupCss(tokens.filter((token) => !isFeatureOnlyToken(token)).join(' '), state, undefined, interactState) : molecule;
373
+ // them out of the atom lookup so they don't warn as "unknown class". The
374
+ // atom array is merged into ONE object (a runtime molecule) so dynamic
375
+ // (cva / clsx) classNames get the same single-object shape as a build
376
+ // molecule; the cache below pins the context, so the merge is correct.
377
+ const style = molecule === undefined
378
+ ? mergeStyleArray(lookupCss.lookupCss(tokens.filter((token) => !isFeatureOnlyToken(token)).join(' '), state, undefined, interactState))
379
+ : molecule;
328
380
  const base = attachFeatures({ style }, tokens);
329
- resolvedCache.set(key, base);
381
+ cacheResolved(key, base);
330
382
  return userStyle === undefined || userStyle === null ? base : { ...base, style: withUserStyle(base.style, userStyle) };
331
383
  }
332
384
  /** Test-only — clear the molecule / gradient / haptic registries + cache. */
@@ -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/** 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.\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.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 * 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 resolvedCache.set(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\".\n const style =\n molecule === undefined ? lookupCss(tokens.filter((token) => !isFeatureOnlyToken(token)).join(' '), state, undefined, interactState) : molecule\n const base = attachFeatures({ style }, tokens)\n resolvedCache.set(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\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 { 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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"}
@@ -58,4 +58,9 @@ export declare function registerHaptics(map: Record<string, HapticRequest>): voi
58
58
  export declare function resolve(className: string | null | undefined, state: RnwindState, userStyle?: unknown, interactState?: InteractState): ResolvedCss;
59
59
  /** Test-only — clear the molecule / gradient / haptic registries + cache. */
60
60
  export declare function __resetResolveState(): void;
61
+ /** Test-only — current resolved-cache entry count + its hard ceiling. */
62
+ export declare function __resolveCacheStats(): {
63
+ size: number;
64
+ max: number;
65
+ };
61
66
  export { normalizeClassName } from '../core/normalize-classname';
@@ -58,4 +58,9 @@ export declare function registerHaptics(map: Record<string, HapticRequest>): voi
58
58
  export declare function resolve(className: string | null | undefined, state: RnwindState, userStyle?: unknown, interactState?: InteractState): ResolvedCss;
59
59
  /** Test-only — clear the molecule / gradient / haptic registries + cache. */
60
60
  export declare function __resetResolveState(): void;
61
+ /** Test-only — current resolved-cache entry count + its hard ceiling. */
62
+ export declare function __resolveCacheStats(): {
63
+ size: number;
64
+ max: number;
65
+ };
61
66
  export { normalizeClassName } from '../core/normalize-classname';
@@ -35,6 +35,32 @@ let registryVersion = 0;
35
35
  const resolvedCache = new Map();
36
36
  /** Version the cache was last valid for (`getStyleVersion()` + {@link registryVersion}). */
37
37
  let cachedFor = -1;
38
+ /**
39
+ * Hard ceiling on the resolved cache. The cache is pure memoisation, so
40
+ * eviction only costs a re-resolve (sub-µs) — never correctness. Build
41
+ * molecules are NOT in here; they live permanently in `molecules`.
42
+ */
43
+ const MAX_RESOLVED_CACHE = 2048;
44
+ /**
45
+ * Store a resolved result, bulk-evicting the OLDEST half when the cache
46
+ * hits {@link MAX_RESOLVED_CACHE}. `Map` preserves insertion order, so the
47
+ * first keys are the oldest. Bulk eviction keeps the hot (cache-hit) path
48
+ * free of per-access LRU bookkeeping at the cost of an occasional small
49
+ * recompute burst under sustained pressure (web / long sessions).
50
+ * @param key Cache key.
51
+ * @param value Resolved result to store.
52
+ */
53
+ function cacheResolved(key, value) {
54
+ if (resolvedCache.size >= MAX_RESOLVED_CACHE) {
55
+ let drop = resolvedCache.size >> 1;
56
+ for (const oldKey of resolvedCache.keys()) {
57
+ resolvedCache.delete(oldKey);
58
+ if (--drop <= 0)
59
+ break;
60
+ }
61
+ }
62
+ resolvedCache.set(key, value);
63
+ }
38
64
  /** `GradientDirection` → expo-linear-gradient start/end points. */
39
65
  const DIRECTION_POINTS = {
40
66
  'to-t': { start: { x: 0.5, y: 1 }, end: { x: 0.5, y: 0 } },
@@ -82,13 +108,17 @@ function registerHaptics(map) {
82
108
  const stateSignatureCache = new WeakMap();
83
109
  /**
84
110
  * Cache key dimension for the reactive context — everything that can
85
- * change a resolved style.
111
+ * change a resolved style. Uses the breakpoint TIER (`activeBreakpoint`),
112
+ * NOT the raw `windowWidth`: two widths in the same tier gate `md:*` atoms
113
+ * identically, so they resolve the same. This collapses the window axis
114
+ * from "every pixel" to ~6 values, bounding the cache on resizable
115
+ * surfaces (web / desktop) without changing any result.
86
116
  * @param state Rnwind context.
87
117
  * @returns Compact signature string.
88
118
  */
89
119
  function stateSignature(state) {
90
120
  const { insets } = state;
91
- return `${state.scheme}|${insets.top},${insets.right},${insets.bottom},${insets.left}|${state.fontScale}|${state.windowWidth}`;
121
+ return `${state.scheme}|${insets.top},${insets.right},${insets.bottom},${insets.left}|${state.fontScale}|${state.activeBreakpoint}`;
92
122
  }
93
123
  /**
94
124
  * Memoised {@link stateSignature} — one `WeakMap.get` on the hot path
@@ -273,6 +303,23 @@ function attachFeatures(base, tokens) {
273
303
  result.haptics = collected;
274
304
  return result;
275
305
  }
306
+ /**
307
+ * Flatten the per-atom style array into ONE object — a *runtime molecule*.
308
+ * RN flattens a style array left-to-right (later wins), which is exactly
309
+ * `Object.assign` semantics, so the merged object renders identically
310
+ * while giving dynamic (cva / clsx) classNames the same single-object
311
+ * shape a build-time molecule has. The caller caches the result per
312
+ * `(className · state)`, so the merge runs once per unique context.
313
+ * @param array Per-atom style array from `lookupCss`.
314
+ * @returns Single merged style object.
315
+ */
316
+ function mergeStyleArray(array) {
317
+ const out = {};
318
+ for (const entry of array)
319
+ if (entry && typeof entry === 'object')
320
+ Object.assign(out, entry);
321
+ return out;
322
+ }
276
323
  /**
277
324
  * Compose a resolved style with a caller-supplied inline style (user wins).
278
325
  * @param style
@@ -313,7 +360,7 @@ function resolve(className, state, userStyle, interactState) {
313
360
  const normalized = normalizeClassName(className);
314
361
  if (normalized.length === 0) {
315
362
  const empty = { style: EMPTY };
316
- resolvedCache.set(key, empty);
363
+ cacheResolved(key, empty);
317
364
  return userStyle === undefined || userStyle === null ? empty : { style: [userStyle] };
318
365
  }
319
366
  // Molecules are static pre-merges; anything carrying `active:`/`focus:`
@@ -321,10 +368,15 @@ function resolve(className, state, userStyle, interactState) {
321
368
  const tokens = normalized.split(' ');
322
369
  const molecule = interactState ? undefined : molecules[state.scheme]?.[normalized] ?? molecules[COMMON_SCHEME]?.[normalized];
323
370
  // Feature-only tokens (gradient / haptic / truncate) carry no style — keep
324
- // them out of the atom lookup so they don't warn as "unknown class".
325
- const style = molecule === undefined ? lookupCss(tokens.filter((token) => !isFeatureOnlyToken(token)).join(' '), state, undefined, interactState) : molecule;
371
+ // them out of the atom lookup so they don't warn as "unknown class". The
372
+ // atom array is merged into ONE object (a runtime molecule) so dynamic
373
+ // (cva / clsx) classNames get the same single-object shape as a build
374
+ // molecule; the cache below pins the context, so the merge is correct.
375
+ const style = molecule === undefined
376
+ ? mergeStyleArray(lookupCss(tokens.filter((token) => !isFeatureOnlyToken(token)).join(' '), state, undefined, interactState))
377
+ : molecule;
326
378
  const base = attachFeatures({ style }, tokens);
327
- resolvedCache.set(key, base);
379
+ cacheResolved(key, base);
328
380
  return userStyle === undefined || userStyle === null ? base : { ...base, style: withUserStyle(base.style, userStyle) };
329
381
  }
330
382
  /** Test-only — clear the molecule / gradient / haptic registries + cache. */
@@ -1 +1 @@
1
- {"version":3,"file":"resolve.mjs","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/** 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.\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.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 * 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 resolvedCache.set(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\".\n const style =\n molecule === undefined ? lookupCss(tokens.filter((token) => !isFeatureOnlyToken(token)).join(' '), state, undefined, interactState) : molecule\n const base = attachFeatures({ style }, tokens)\n resolvedCache.set(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\nexport {normalizeClassName} from '../core/normalize-classname'"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"resolve.mjs","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":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rnwind",
3
- "version": "0.0.5",
3
+ "version": "0.0.6",
4
4
  "description": "Tailwind for React Native",
5
5
  "author": "https://github.com/sagltd",
6
6
  "license": "MIT",
@@ -43,6 +43,33 @@ const resolvedCache = new Map<string, ResolvedCss>()
43
43
  /** Version the cache was last valid for (`getStyleVersion()` + {@link registryVersion}). */
44
44
  let cachedFor = -1
45
45
 
46
+ /**
47
+ * Hard ceiling on the resolved cache. The cache is pure memoisation, so
48
+ * eviction only costs a re-resolve (sub-µs) — never correctness. Build
49
+ * molecules are NOT in here; they live permanently in `molecules`.
50
+ */
51
+ const MAX_RESOLVED_CACHE = 2048
52
+
53
+ /**
54
+ * Store a resolved result, bulk-evicting the OLDEST half when the cache
55
+ * hits {@link MAX_RESOLVED_CACHE}. `Map` preserves insertion order, so the
56
+ * first keys are the oldest. Bulk eviction keeps the hot (cache-hit) path
57
+ * free of per-access LRU bookkeeping at the cost of an occasional small
58
+ * recompute burst under sustained pressure (web / long sessions).
59
+ * @param key Cache key.
60
+ * @param value Resolved result to store.
61
+ */
62
+ function cacheResolved(key: string, value: ResolvedCss): void {
63
+ if (resolvedCache.size >= MAX_RESOLVED_CACHE) {
64
+ let drop = resolvedCache.size >> 1
65
+ for (const oldKey of resolvedCache.keys()) {
66
+ resolvedCache.delete(oldKey)
67
+ if (--drop <= 0) break
68
+ }
69
+ }
70
+ resolvedCache.set(key, value)
71
+ }
72
+
46
73
  /** A unit-square gradient endpoint. */
47
74
  interface GradientPoint {
48
75
  readonly x: number
@@ -121,13 +148,17 @@ const stateSignatureCache = new WeakMap<RnwindState, string>()
121
148
 
122
149
  /**
123
150
  * Cache key dimension for the reactive context — everything that can
124
- * change a resolved style.
151
+ * change a resolved style. Uses the breakpoint TIER (`activeBreakpoint`),
152
+ * NOT the raw `windowWidth`: two widths in the same tier gate `md:*` atoms
153
+ * identically, so they resolve the same. This collapses the window axis
154
+ * from "every pixel" to ~6 values, bounding the cache on resizable
155
+ * surfaces (web / desktop) without changing any result.
125
156
  * @param state Rnwind context.
126
157
  * @returns Compact signature string.
127
158
  */
128
159
  function stateSignature(state: RnwindState): string {
129
160
  const { insets } = state
130
- return `${state.scheme}|${insets.top},${insets.right},${insets.bottom},${insets.left}|${state.fontScale}|${state.windowWidth}`
161
+ return `${state.scheme}|${insets.top},${insets.right},${insets.bottom},${insets.left}|${state.fontScale}|${state.activeBreakpoint}`
131
162
  }
132
163
 
133
164
  /**
@@ -303,6 +334,22 @@ function attachFeatures(base: ResolvedCss, tokens: readonly string[]): ResolvedC
303
334
  return result
304
335
  }
305
336
 
337
+ /**
338
+ * Flatten the per-atom style array into ONE object — a *runtime molecule*.
339
+ * RN flattens a style array left-to-right (later wins), which is exactly
340
+ * `Object.assign` semantics, so the merged object renders identically
341
+ * while giving dynamic (cva / clsx) classNames the same single-object
342
+ * shape a build-time molecule has. The caller caches the result per
343
+ * `(className · state)`, so the merge runs once per unique context.
344
+ * @param array Per-atom style array from `lookupCss`.
345
+ * @returns Single merged style object.
346
+ */
347
+ function mergeStyleArray(array: readonly unknown[]): Record<string, unknown> {
348
+ const out: Record<string, unknown> = {}
349
+ for (const entry of array) if (entry && typeof entry === 'object') Object.assign(out, entry)
350
+ return out
351
+ }
352
+
306
353
  /**
307
354
  * Compose a resolved style with a caller-supplied inline style (user wins).
308
355
  * @param style
@@ -349,7 +396,7 @@ export function resolve(
349
396
  const normalized = normalizeClassName(className)
350
397
  if (normalized.length === 0) {
351
398
  const empty: ResolvedCss = { style: EMPTY }
352
- resolvedCache.set(key, empty)
399
+ cacheResolved(key, empty)
353
400
  return userStyle === undefined || userStyle === null ? empty : { style: [userStyle] }
354
401
  }
355
402
  // Molecules are static pre-merges; anything carrying `active:`/`focus:`
@@ -357,11 +404,16 @@ export function resolve(
357
404
  const tokens = normalized.split(' ')
358
405
  const molecule = interactState ? undefined : molecules[state.scheme]?.[normalized] ?? molecules[COMMON_SCHEME]?.[normalized]
359
406
  // Feature-only tokens (gradient / haptic / truncate) carry no style — keep
360
- // them out of the atom lookup so they don't warn as "unknown class".
407
+ // them out of the atom lookup so they don't warn as "unknown class". The
408
+ // atom array is merged into ONE object (a runtime molecule) so dynamic
409
+ // (cva / clsx) classNames get the same single-object shape as a build
410
+ // molecule; the cache below pins the context, so the merge is correct.
361
411
  const style =
362
- molecule === undefined ? lookupCss(tokens.filter((token) => !isFeatureOnlyToken(token)).join(' '), state, undefined, interactState) : molecule
412
+ molecule === undefined
413
+ ? mergeStyleArray(lookupCss(tokens.filter((token) => !isFeatureOnlyToken(token)).join(' '), state, undefined, interactState))
414
+ : molecule
363
415
  const base = attachFeatures({ style }, tokens)
364
- resolvedCache.set(key, base)
416
+ cacheResolved(key, base)
365
417
  return userStyle === undefined || userStyle === null ? base : { ...base, style: withUserStyle(base.style, userStyle) }
366
418
  }
367
419
 
@@ -378,4 +430,9 @@ export function __resetResolveState(): void {
378
430
  cachedFor = -1
379
431
  }
380
432
 
433
+ /** Test-only — current resolved-cache entry count + its hard ceiling. */
434
+ export function __resolveCacheStats(): { size: number; max: number } {
435
+ return { size: resolvedCache.size, max: MAX_RESOLVED_CACHE }
436
+ }
437
+
381
438
  export {normalizeClassName} from '../core/normalize-classname'