rnwind 0.0.10 → 0.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rnwind",
3
- "version": "0.0.10",
3
+ "version": "0.0.11",
4
4
  "description": "Tailwind for React Native",
5
5
  "author": "https://github.com/sagltd",
6
6
  "license": "MIT",
@@ -1,4 +1,5 @@
1
1
  import { compile } from '@tailwindcss/node'
2
+ import * as tailwindNode from '@tailwindcss/node'
2
3
  import { Scanner, type SourceEntry } from '@tailwindcss/oxide'
3
4
  import { formatHex as culoriFormatHex } from 'culori'
4
5
  import { Features, transform, type TransformOptions } from 'lightningcss'
@@ -183,6 +184,8 @@ export interface ParsedOutput {
183
184
  export class TailwindParser {
184
185
  private readonly scanner: Scanner
185
186
  private compiler: TailwindCompiler | undefined
187
+ /** Full resolved base theme (built-in palette + user `@theme`), colors lowered to sRGB. Source for `useColor` / `useToken`. */
188
+ private baseThemeTokens: ThemeTable | null = null
186
189
  private readonly themeSchemes: ThemeSchemeTable
187
190
  private readonly schemeAliases: ReadonlyMap<string, string>
188
191
  /**
@@ -281,10 +284,16 @@ export class TailwindParser {
281
284
  */
282
285
  private buildThemeTokens(resolver: ReadonlyMap<string, string>): ThemeTables {
283
286
  const out: ThemeTables = {}
287
+ // BASE: the full resolved theme (built-in palette + user `@theme`). The
288
+ // runtime merges this under the active scheme, so `useColor('pink-500')`
289
+ // and `useColor('<your-token>')` both resolve in every scheme.
290
+ if (this.baseThemeTokens) out[BASE_SCHEME] = this.baseThemeTokens
291
+ // VARIANTS: only the per-scheme overrides the user wrote (`.dark { … }` /
292
+ // `@variant dark { … }`) — they layer on top of base at runtime.
284
293
  for (const scheme of this.themeSchemes.keys()) {
294
+ if (scheme === BASE_SCHEME) continue
285
295
  const userTable = this.themeSchemes.get(scheme)
286
296
  if (!userTable || userTable.size === 0) continue
287
-
288
297
  const schemeResolver = new Map(resolver)
289
298
  for (const [k, v] of this.effectiveVars(scheme)) schemeResolver.set(k, v)
290
299
  const table: ThemeTable = {}
@@ -313,6 +322,13 @@ export class TailwindParser {
313
322
  } catch (error) {
314
323
  throw wrapThemeError(error)
315
324
  }
325
+ // Load the resolved design system ONCE to capture the FULL theme — the
326
+ // built-in palette (`pink-500`, …) plus the user's `@theme` tokens — so
327
+ // `useColor` / `useToken` resolve any theme value, not just the utilities
328
+ // a class happened to use (Tailwind tree-shakes `:root`, so the compiled
329
+ // CSS alone never carries the full palette). Best-effort: a load failure
330
+ // just narrows the hooks to the user's own tokens.
331
+ this.baseThemeTokens = await loadBaseThemeTokens(ready)
316
332
  return this.compiler
317
333
  }
318
334
 
@@ -501,6 +517,55 @@ function lowerColorToken(raw: string, resolver: ReadonlyMap<string, string>): st
501
517
  return normalizeColorString(substituted) ?? substituted
502
518
  }
503
519
 
520
+ /** Theme token families excluded from the registered base table — pure Tailwind internals with no `useColor`/`useToken` value. */
521
+ const INTERNAL_TOKEN_PREFIXES: readonly string[] = ['--tw-', '--default-']
522
+
523
+ /** Shape of a resolved design-system theme entry from `@tailwindcss/node`'s unstable loader. */
524
+ interface DesignSystemTheme {
525
+ theme?: { entries?: () => Iterable<[string, { value?: unknown }]> }
526
+ }
527
+
528
+ /**
529
+ * `@tailwindcss/node`'s `__unstable__loadDesignSystem` — exists at runtime but
530
+ * isn't in the package's published types, so it's accessed through a narrowed
531
+ * cast rather than a named import. Returns `undefined` when the (unstable) API
532
+ * isn't present, so {@link loadBaseThemeTokens} degrades gracefully.
533
+ */
534
+ const loadDesignSystem = (tailwindNode as unknown as {
535
+ __unstable__loadDesignSystem?: (css: string, options: { base: string }) => Promise<DesignSystemTheme>
536
+ }).__unstable__loadDesignSystem
537
+
538
+ /**
539
+ * Load the FULL resolved Tailwind theme (built-in palette + the user's
540
+ * `@theme`) via the design-system API and flatten it to an RN-safe token
541
+ * table — `--color-*` values lowered to sRGB, everything else passed through.
542
+ * This is what lets `useColor` / `useToken` resolve ANY theme token, including
543
+ * built-ins a class never used (Tailwind tree-shakes the compiled `:root`, so
544
+ * the compiled CSS alone can't supply the full palette). Internal `--tw-*` /
545
+ * `--default-*` families are dropped. Returns `null` on any failure so the
546
+ * caller degrades to the user's own `@theme` tokens.
547
+ * @param themeCss Compile-ready theme CSS (variants stripped, custom-variants added).
548
+ * @returns Flattened base token table, or null.
549
+ */
550
+ async function loadBaseThemeTokens(themeCss: string): Promise<ThemeTable | null> {
551
+ if (typeof loadDesignSystem !== 'function') return null
552
+ try {
553
+ const design = await loadDesignSystem(themeCss, { base: process.cwd() })
554
+ const entries = design.theme?.entries?.()
555
+ if (!entries) return null
556
+ const table: ThemeTable = {}
557
+ for (const [name, entry] of entries) {
558
+ const raw = entry?.value
559
+ if (typeof raw !== 'string') continue
560
+ if (INTERNAL_TOKEN_PREFIXES.some((prefix) => name.startsWith(prefix))) continue
561
+ table[name] = name.startsWith('--color-') ? (normalizeColorString(raw) ?? raw) : raw
562
+ }
563
+ return table
564
+ } catch {
565
+ return null
566
+ }
567
+ }
568
+
504
569
  /**
505
570
  * Wrap an error from `@tailwindcss/node`'s compiler or `lightningcss`'s
506
571
  * transform with a `rnwind:` prefix so the user sees a clear "this came