@oxyhq/bloom 0.7.7 → 0.8.0

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 (109) hide show
  1. package/lib/commonjs/normalize-colors.d.js +2 -0
  2. package/lib/commonjs/normalize-colors.d.js.map +1 -0
  3. package/lib/commonjs/theme/apply-dark-class.js +8 -24
  4. package/lib/commonjs/theme/apply-dark-class.js.map +1 -1
  5. package/lib/commonjs/theme/build-theme.js +39 -61
  6. package/lib/commonjs/theme/build-theme.js.map +1 -1
  7. package/lib/commonjs/theme/color-presets.js +9 -9
  8. package/lib/commonjs/theme/color-scope/index.web.js +7 -14
  9. package/lib/commonjs/theme/color-scope/index.web.js.map +1 -1
  10. package/lib/commonjs/theme/color-scope/style-builder.js +7 -6
  11. package/lib/commonjs/theme/color-scope/style-builder.js.map +1 -1
  12. package/lib/commonjs/theme/color-space.js +76 -0
  13. package/lib/commonjs/theme/color-space.js.map +1 -0
  14. package/lib/commonjs/theme/index.js +0 -6
  15. package/lib/commonjs/theme/index.js.map +1 -1
  16. package/lib/commonjs/theme/native-root-vars.native.js +28 -18
  17. package/lib/commonjs/theme/native-root-vars.native.js.map +1 -1
  18. package/lib/commonjs/theme/preset-vars.js +20 -152
  19. package/lib/commonjs/theme/preset-vars.js.map +1 -1
  20. package/lib/commonjs/theme/token-registry.js +123 -0
  21. package/lib/commonjs/theme/token-registry.js.map +1 -0
  22. package/lib/module/normalize-colors.d.js +2 -0
  23. package/lib/module/normalize-colors.d.js.map +1 -0
  24. package/lib/module/theme/apply-dark-class.js +8 -19
  25. package/lib/module/theme/apply-dark-class.js.map +1 -1
  26. package/lib/module/theme/build-theme.js +39 -61
  27. package/lib/module/theme/build-theme.js.map +1 -1
  28. package/lib/module/theme/color-presets.js +9 -9
  29. package/lib/module/theme/color-scope/index.web.js +7 -14
  30. package/lib/module/theme/color-scope/index.web.js.map +1 -1
  31. package/lib/module/theme/color-scope/style-builder.js +7 -6
  32. package/lib/module/theme/color-scope/style-builder.js.map +1 -1
  33. package/lib/module/theme/color-space.js +69 -0
  34. package/lib/module/theme/color-space.js.map +1 -0
  35. package/lib/module/theme/index.js +1 -1
  36. package/lib/module/theme/index.js.map +1 -1
  37. package/lib/module/theme/native-root-vars.native.js +29 -18
  38. package/lib/module/theme/native-root-vars.native.js.map +1 -1
  39. package/lib/module/theme/preset-vars.js +19 -150
  40. package/lib/module/theme/preset-vars.js.map +1 -1
  41. package/lib/module/theme/token-registry.js +113 -0
  42. package/lib/module/theme/token-registry.js.map +1 -0
  43. package/lib/typescript/commonjs/theme/apply-dark-class.d.ts +5 -10
  44. package/lib/typescript/commonjs/theme/apply-dark-class.d.ts.map +1 -1
  45. package/lib/typescript/commonjs/theme/build-theme.d.ts +1 -1
  46. package/lib/typescript/commonjs/theme/build-theme.d.ts.map +1 -1
  47. package/lib/typescript/commonjs/theme/color-presets.d.ts +9 -9
  48. package/lib/typescript/commonjs/theme/color-scope/index.web.d.ts.map +1 -1
  49. package/lib/typescript/commonjs/theme/color-scope/style-builder.d.ts +5 -2
  50. package/lib/typescript/commonjs/theme/color-scope/style-builder.d.ts.map +1 -1
  51. package/lib/typescript/commonjs/theme/color-space.d.ts +28 -0
  52. package/lib/typescript/commonjs/theme/color-space.d.ts.map +1 -0
  53. package/lib/typescript/commonjs/theme/index.d.ts +1 -2
  54. package/lib/typescript/commonjs/theme/index.d.ts.map +1 -1
  55. package/lib/typescript/commonjs/theme/native-root-vars.native.d.ts +25 -15
  56. package/lib/typescript/commonjs/theme/native-root-vars.native.d.ts.map +1 -1
  57. package/lib/typescript/commonjs/theme/preset-vars.d.ts +11 -74
  58. package/lib/typescript/commonjs/theme/preset-vars.d.ts.map +1 -1
  59. package/lib/typescript/commonjs/theme/token-registry.d.ts +53 -0
  60. package/lib/typescript/commonjs/theme/token-registry.d.ts.map +1 -0
  61. package/lib/typescript/commonjs/theme/types.d.ts +3 -0
  62. package/lib/typescript/commonjs/theme/types.d.ts.map +1 -1
  63. package/lib/typescript/module/theme/apply-dark-class.d.ts +5 -10
  64. package/lib/typescript/module/theme/apply-dark-class.d.ts.map +1 -1
  65. package/lib/typescript/module/theme/build-theme.d.ts +1 -1
  66. package/lib/typescript/module/theme/build-theme.d.ts.map +1 -1
  67. package/lib/typescript/module/theme/color-presets.d.ts +9 -9
  68. package/lib/typescript/module/theme/color-scope/index.web.d.ts.map +1 -1
  69. package/lib/typescript/module/theme/color-scope/style-builder.d.ts +5 -2
  70. package/lib/typescript/module/theme/color-scope/style-builder.d.ts.map +1 -1
  71. package/lib/typescript/module/theme/color-space.d.ts +28 -0
  72. package/lib/typescript/module/theme/color-space.d.ts.map +1 -0
  73. package/lib/typescript/module/theme/index.d.ts +1 -2
  74. package/lib/typescript/module/theme/index.d.ts.map +1 -1
  75. package/lib/typescript/module/theme/native-root-vars.native.d.ts +25 -15
  76. package/lib/typescript/module/theme/native-root-vars.native.d.ts.map +1 -1
  77. package/lib/typescript/module/theme/preset-vars.d.ts +11 -74
  78. package/lib/typescript/module/theme/preset-vars.d.ts.map +1 -1
  79. package/lib/typescript/module/theme/token-registry.d.ts +53 -0
  80. package/lib/typescript/module/theme/token-registry.d.ts.map +1 -0
  81. package/lib/typescript/module/theme/types.d.ts +3 -0
  82. package/lib/typescript/module/theme/types.d.ts.map +1 -1
  83. package/package.json +1 -1
  84. package/src/__tests__/BloomColorScope.test.tsx +5 -5
  85. package/src/__tests__/BloomThemeProvider.test.tsx +4 -3
  86. package/src/__tests__/apply-dark-class.test.ts +26 -21
  87. package/src/__tests__/native-root-vars.test.ts +8 -7
  88. package/src/__tests__/preset-vars.test.ts +31 -77
  89. package/src/__tests__/theme.test.ts +6 -6
  90. package/src/normalize-colors.d.ts +22 -0
  91. package/src/react-native-css.d.ts +3 -3
  92. package/src/theme/__tests__/__fixtures__/golden-resolved-tokens.json +574 -0
  93. package/src/theme/__tests__/__snapshots__/visual-gallery.test.tsx.snap +838 -0
  94. package/src/theme/__tests__/color-space.test.ts +28 -0
  95. package/src/theme/__tests__/golden-tokens.test.ts +33 -0
  96. package/src/theme/__tests__/runtime-contract.test.ts +49 -0
  97. package/src/theme/__tests__/token-registry.test.ts +30 -0
  98. package/src/theme/__tests__/visual-gallery.test.tsx +10 -0
  99. package/src/theme/apply-dark-class.ts +8 -17
  100. package/src/theme/build-theme.ts +39 -67
  101. package/src/theme/color-presets.ts +9 -9
  102. package/src/theme/color-scope/index.web.tsx +7 -14
  103. package/src/theme/color-scope/style-builder.ts +7 -4
  104. package/src/theme/color-space.ts +56 -0
  105. package/src/theme/index.ts +1 -6
  106. package/src/theme/native-root-vars.native.ts +28 -18
  107. package/src/theme/preset-vars.ts +17 -178
  108. package/src/theme/token-registry.ts +159 -0
  109. package/src/theme/types.ts +3 -0
@@ -5,17 +5,17 @@ export type AppColorName = 'teal' | 'blue' | 'green' | 'amber' | 'yellow' | 'red
5
5
  * Keys carry a leading `--` for historical reasons (shadcn-style CSS variable
6
6
  * names) — keep in mind the values are platform-agnostic **raw HSL triples**
7
7
  * (e.g. `'185 100% 20%'` or `'185 100% 20% / 0.5'`), not CSS-resolved colors.
8
- * The same map drives both:
9
- * - the web layer: the base `--x` tokens are wrapped to full `hsl(...)` colors
10
- * (via `toWebColorValue`) before being written to `document.documentElement`
11
- * / a `BloomColorScope` element, so `var(--x)` the form Tailwind v4
12
- * `@theme inline` compiles its color utilities to resolves to a valid
13
- * color directly; the resolved `--color-*` companions are written as
14
- * `rgb(...)`, and
8
+ * The single canonical resolver `getResolvedTokens` (in `token-registry.ts`)
9
+ * converts this raw map to sRGB `rgb(...)` for every runtime write — the same
10
+ * values drive BOTH layers:
11
+ * - the web layer: `getResolvedTokens`'s `rgb(...)` strings are written to
12
+ * `document.documentElement` / a `BloomColorScope` element, so `var(--x)`
13
+ * the form Tailwind v4 `@theme inline` compiles its color utilities to
14
+ * resolves to a valid color directly, and
15
15
  * - the native layer (`buildTheme` resolves the raw triples into `hsl(...)`
16
16
  * strings consumable by React Native styles; `native-root-vars.native.ts`
17
- * writes the raw triples through bloom's `hsl(var(--x))` `global.css`
18
- * indirection).
17
+ * writes the same canonical `rgb(...)` values into react-native-css's
18
+ * `rootVariables` family).
19
19
  *
20
20
  * The `--` prefix is an implementation detail we will drop in a future major.
21
21
  */
@@ -1 +1 @@
1
- {"version":3,"file":"index.web.d.ts","sourceRoot":"","sources":["../../../../../src/theme/color-scope/index.web.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsE,MAAM,OAAO,CAAC;AAI3F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAwBrD,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,WAAW,EAAE,YAAY,GAAG,SAAS,CAAC;IACtC;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,yGAAyG;IACzG,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAuBD,wBAAgB,eAAe,CAAC,EAC9B,WAAW,EACX,OAAe,EACf,KAAK,EACL,QAAQ,GACT,EAAE,oBAAoB,2CA4CtB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,YAAY,GAAG,KAAK,CAAC,aAAa,CAUjF"}
1
+ {"version":3,"file":"index.web.d.ts","sourceRoot":"","sources":["../../../../../src/theme/color-scope/index.web.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsE,MAAM,OAAO,CAAC;AAI3F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAiBrD,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,WAAW,EAAE,YAAY,GAAG,SAAS,CAAC;IACtC;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,yGAAyG;IACzG,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAuBD,wBAAgB,eAAe,CAAC,EAC9B,WAAW,EACX,OAAe,EACf,KAAK,EACL,QAAQ,GACT,EAAE,oBAAoB,2CA4CtB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,YAAY,GAAG,KAAK,CAAC,aAAa,CAUjF"}
@@ -13,8 +13,11 @@ export type VariableContextProviderComponent = React.ComponentType<{
13
13
  }>;
14
14
  /**
15
15
  * Build the CSS custom-property map for a preset, ready to be applied to a
16
- * subtree. Always includes the resolved `--color-*` vars so Tailwind v4
17
- * `@theme` utilities (e.g. `bg-background`) honour the scope.
16
+ * subtree. Every token is resolved to an sRGB `rgb(...)` string via
17
+ * `getResolvedTokens` the single canonical token pipeline shared by web and
18
+ * native — so Tailwind v4 `@theme` utilities (e.g. `bg-background`) and
19
+ * `color-mix`-based alpha utilities (`bg-primary/10`) both resolve against the
20
+ * same color values. Keys retain the leading `--`.
18
21
  */
19
22
  export declare function buildScopeVars(colorPreset: AppColorName, mode: 'light' | 'dark'): Record<string, string>;
20
23
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"style-builder.d.ts","sourceRoot":"","sources":["../../../../../src/theme/color-scope/style-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAY,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAGxE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAGrD;;;;;GAKG;AACH,MAAM,MAAM,gCAAgC,GAAG,KAAK,CAAC,aAAa,CAAC;IACjE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,CAAC,CAAC;AASH;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,WAAW,EAAE,YAAY,EACzB,IAAI,EAAE,OAAO,GAAG,MAAM,GACrB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAExB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,0BAA0B,IAAI,gCAAgC,GAAG,IAAI,CAKpF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,YAAY,EACzB,IAAI,EAAE,OAAO,GAAG,MAAM,GACrB,SAAS,CAAC,SAAS,CAAC,CAKtB"}
1
+ {"version":3,"file":"style-builder.d.ts","sourceRoot":"","sources":["../../../../../src/theme/color-scope/style-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAY,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAGxE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAGrD;;;;;GAKG;AACH,MAAM,MAAM,gCAAgC,GAAG,KAAK,CAAC,aAAa,CAAC;IACjE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,CAAC,CAAC;AASH;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC5B,WAAW,EAAE,YAAY,EACzB,IAAI,EAAE,OAAO,GAAG,MAAM,GACrB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAExB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,0BAA0B,IAAI,gCAAgC,GAAG,IAAI,CAKpF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,YAAY,EACzB,IAAI,EAAE,OAAO,GAAG,MAAM,GACrB,SAAS,CAAC,SAAS,CAAC,CAKtB"}
@@ -0,0 +1,28 @@
1
+ export interface Oklch {
2
+ l: number;
3
+ c: number;
4
+ h: number;
5
+ }
6
+ export interface Rgb {
7
+ r: number;
8
+ g: number;
9
+ b: number;
10
+ }
11
+ /** OKLCH → linear OKLab → linear sRGB → gamma sRGB → 0..255. Pure. */
12
+ export declare function oklchToSrgb({ l, c, h }: Oklch): Rgb;
13
+ export declare function srgbToRgbString({ r, g, b }: Rgb, alpha?: number): string;
14
+ /**
15
+ * Parse an `rgb(...)` / `rgba(...)` string into an {@link Rgb}.
16
+ *
17
+ * Contract: input MUST be an `rgb(...)` / `rgba(...)` string (e.g. a resolved
18
+ * token from `getResolvedTokens`). Both modern (`rgb(r g b)`) and legacy
19
+ * (`rgb(r, g, b)`) syntaxes are accepted. Anything else throws — this is a
20
+ * canonical-pipeline primitive and a non-rgb input signals a real bug at the
21
+ * call site, never a value to silently coerce to black.
22
+ *
23
+ * @throws {Error} if `s` is not an `rgb()` / `rgba()` string.
24
+ */
25
+ export declare function parseRgbString(s: string): Rgb;
26
+ /** Cheap perceptual-ish distance in sRGB (sufficient for a ≤1 rounding gate). */
27
+ export declare function deltaE(a: Rgb, b: Rgb): number;
28
+ //# sourceMappingURL=color-space.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"color-space.d.ts","sourceRoot":"","sources":["../../../../src/theme/color-space.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,KAAK;IAAG,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE;AAC1D,MAAM,WAAW,GAAG;IAAG,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE;AAMxD,sEAAsE;AACtE,wBAAgB,WAAW,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,KAAK,GAAG,GAAG,CAgBnD;AAED,wBAAgB,eAAe,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAIxE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,GAAG,GAAG,CAO7C;AAED,iFAAiF;AACjF,wBAAgB,MAAM,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,GAAG,MAAM,CAE7C"}
@@ -7,8 +7,7 @@ export { useTheme, useThemeColor, useBloomTheme } from './use-theme';
7
7
  export type { Theme, ThemeColors, ThemeMode } from './types';
8
8
  export type { AppColorName, AppColorPreset, PresetTokens } from './color-presets';
9
9
  export { APP_COLOR_NAMES, PREMIUM_COLOR_NAMES, APP_COLOR_PRESETS, HEX_TO_APP_COLOR, hexToAppColorName, } from './color-presets';
10
- export { getPresetVars, applyPresetVarsToDocument, toWebColorValue, } from './preset-vars';
11
- export type { PresetVarsOptions } from './preset-vars';
10
+ export { getPresetVars, applyPresetVarsToDocument } from './preset-vars';
12
11
  export { applyDarkClass } from './apply-dark-class';
13
12
  export { setColorSchemeSafe } from './set-color-scheme-safe';
14
13
  export { initCssInteropDarkMode } from './init-css-interop';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/theme/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,YAAY,EACV,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACpE,YAAY,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACrE,YAAY,EAAE,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAC7D,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAClF,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,iBAAiB,EACjB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,aAAa,EACb,yBAAyB,EACzB,eAAe,GAChB,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,YAAY,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAC5E,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/theme/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,YAAY,EACV,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACpE,YAAY,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACrE,YAAY,EAAE,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAC7D,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAClF,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,iBAAiB,EACjB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,aAAa,EAAE,yBAAyB,EAAE,MAAM,eAAe,CAAC;AACzE,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,YAAY,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAC5E,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC"}
@@ -21,18 +21,28 @@ import { type AppColorName } from './color-presets';
21
21
  * `BloomThemeProvider`'s `VariableContextProvider` only feeds path #1, so the navigator
22
22
  * host and every portal/modal — which render outside that subtree — never see the
23
23
  * preset vars and fall through to `rootVariables`/`universalVariables`. By default those
24
- * families hold only react-native-css's own `__rn-css-rem`/`__rn-css-color` entries
25
- * (Bloom's `global.css` defines the `hsl(var(--primary))` indirection but not the HSL
26
- * triples themselves those are injected at runtime), so the whole tree below the
27
- * navigator renders monochrome. Writing the vars into `rootVariables` here is the
28
- * exact same mechanism react-native-css uses for compiled `:root {}` / `@theme` vars
29
- * (`StyleCollection.inject` does `rootVariables(name).set(valueArray)`), so portaled
30
- * content resolves the palette identically regardless of React-tree position.
24
+ * families hold only react-native-css's own `__rn-css-rem`/`__rn-css-color` entries, so
25
+ * the whole tree below the navigator renders monochrome until the palette is injected at
26
+ * runtime. Writing the vars into `rootVariables` here is the exact same mechanism
27
+ * react-native-css uses for compiled `:root {}` / `@theme` vars (`StyleCollection.inject`
28
+ * does `rootVariables(name).set(valueArray)`), so portaled content resolves the palette
29
+ * identically regardless of React-tree position.
31
30
  *
32
- * The raw tokens are written as HSL triples (`primary: '205 87% 53%'`) and the
33
- * resolved Tailwind v4 `--color-*` vars as sRGB `rgb(...)` (`color-primary:
34
- * 'rgb(31 153 239)'`) the latter so `color-mix`-based alpha utilities resolve
35
- * on native (see `getPresetVars` / `hslTripletToRgb`).
31
+ * Consumer contract (CRITICAL single canonical color pipeline)
32
+ * -------------------------------------------------------------
33
+ * Each base `--x` token is now written as a FULL `rgb(...)` color (not a raw HSL
34
+ * triple). A consuming app's Tailwind `@theme` must therefore reference these
35
+ * base tokens DIRECTLY (its Tailwind color var equals `var(--x)`) and must NOT
36
+ * wrap them in `hsl(...)`. The legacy `hsl(var(--x))` indirection (which assumed
37
+ * a raw triple) would produce the invalid `hsl(rgb(...))` and must be removed in
38
+ * every consumer. Web and native now share this one contract.
39
+ *
40
+ * Every token is written as an sRGB `rgb(...)` string from the single canonical
41
+ * token pipeline (`getResolvedTokens`) — `primary: 'rgb(31 153 239)'` — the SAME
42
+ * values web writes to `document.documentElement`. sRGB is the space
43
+ * react-native-css's `color-mix` resolver registers, so `color-mix`-based alpha
44
+ * utilities (`bg-primary/10`) resolve on native; full (non-alpha) utilities
45
+ * resolve directly through bloom's `global.css` `var(--x)` indirection.
36
46
  *
37
47
  * Why a STATIC `import`, not a runtime `require` (critical)
38
48
  * ---------------------------------------------------------
@@ -62,15 +72,15 @@ import { type AppColorName } from './color-presets';
62
72
  * `shared.rootVariables[name]`, and `@property --x` goes through
63
73
  * `name.startsWith("--") ? name.slice(2) : name`. The lookup side matches: a `var(--x)`
64
74
  * reference compiles to `[{}, "var", ident.slice(2)]`, so `varResolver` looks up the
65
- * bare name. `buildScopeVars` returns keys WITH the `--` prefix, so we strip it before
66
- * writing each entry.
75
+ * bare name. `getResolvedTokens` returns keys WITH the `--` prefix, so we strip it
76
+ * before writing each entry.
67
77
  *
68
78
  * Value shape
69
79
  * -----------
70
80
  * Each entry is a `VariableValue[]` — an array of `[value, mediaCondition?]` tuples.
71
81
  * Bloom's preset vars are unconditional, so each is a single-element `[[value]]`, e.g.
72
- * `rootVariables('primary').set([['205 87% 53%']])`. This is the same shape the compiler
73
- * emits for unconditional `:root` vars.
82
+ * `rootVariables('primary').set([['rgb(31 153 239)']])`. This is the same shape the
83
+ * compiler emits for unconditional `:root` vars.
74
84
  *
75
85
  * This is native-only and additive: the `VariableContextProvider` wrapper stays (it is
76
86
  * the correct, scoped mechanism for `BloomColorScope` subtree overrides and harmlessly
@@ -1 +1 @@
1
- {"version":3,"file":"native-root-vars.native.d.ts","sourceRoot":"","sources":["../../../../src/theme/native-root-vars.native.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAEpD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6EG;AAEH;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,YAAY,EAAE,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAS3F"}
1
+ {"version":3,"file":"native-root-vars.native.d.ts","sourceRoot":"","sources":["../../../../src/theme/native-root-vars.native.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAGpD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuFG;AAEH;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,YAAY,EAAE,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAS3F"}
@@ -1,72 +1,4 @@
1
1
  import { type AppColorName, type PresetTokens } from './color-presets';
2
- /**
3
- * Convert a shadcn-style HSL triple (`'H S% L%'`, optionally with an alpha tail
4
- * `'H S% L% / A'`) into an sRGB `rgb(...)` string.
5
- *
6
- * Why rgb and not hsl (the native alpha-utility bug this fixes)
7
- * -------------------------------------------------------------
8
- * Tailwind v4 compiles an alpha-on-theme-color utility (`bg-primary/10`) into a
9
- * `color-mix(... var(--color-primary) 10%, transparent)` declaration. On native,
10
- * react-native-css resolves that `color-mix` at runtime via `colorjs.io/fn`, but
11
- * its `color-mix` implementation registers ONLY the `sRGB`, `P3`, and `OKLab`
12
- * color spaces — never `HSL`. So if `--color-primary` resolves to an `hsl(...)`
13
- * string, `parse('hsl(...)')` throws, the mix is swallowed, and the utility
14
- * silently produces no color. Emitting the resolved var as `rgb(...)` (a space
15
- * colorjs.io always has registered) makes the alpha utilities resolve on native,
16
- * matching web. Full (non-alpha) utilities already worked because React Native's
17
- * native color parser handles `hsl()` directly; only `color-mix` was affected.
18
- *
19
- * Output is space-separated channels (`rgb(31 153 239)`), the modern CSS syntax
20
- * parsed by both `colorjs.io/fn` (with only sRGB/P3/OKLab registered) and
21
- * react-native-web / browsers. An alpha tail emits `rgb(r g b / a)`, likewise
22
- * parsed by both.
23
- *
24
- * Pure function — standard HSL→sRGB conversion, channels rounded to integers.
25
- * Tolerates a `deg` suffix on the hue and `%` suffixes on saturation/lightness.
26
- */
27
- export declare function hslTripletToRgb(triplet: string): string;
28
- /**
29
- * Transform a single preset var into the value to write to a WEB element
30
- * (`document.documentElement` or a `BloomColorScope` subtree element).
31
- *
32
- * The web apps (Vite + Tailwind v4 + shadcn) compile their `@theme inline`
33
- * block so the color utilities reference the BASE token directly — e.g.
34
- * `.bg-background { background-color: var(--background) }`. So on web the base
35
- * `--x` tokens MUST resolve to a COMPLETE CSS color; a bare HSL triple
36
- * (`185 50% 5%`) is invalid as a `background-color` value and renders
37
- * transparent (the production incident this fixes). We therefore wrap raw
38
- * triples in `hsl(...)`, preserving the exact preset color math (and any `/ A`
39
- * alpha tail, valid in modern `hsl(H S% L% / A)` syntax) with zero rounding
40
- * drift.
41
- *
42
- * Values that are already full colors pass through unchanged:
43
- * - `--color-*` resolved vars (already `rgb(...)` from `getPresetVars`),
44
- * - any value not shaped like a raw HSL triple (`--radius: 0.5rem`,
45
- * pre-resolved `rgb(...)`/`hsl(...)`, etc.).
46
- *
47
- * NATIVE never calls this — `getPresetVars` returns raw triples verbatim and
48
- * `native-root-vars.native.ts` writes them through bloom's `hsl(var(--x))`
49
- * native `global.css` indirection. Pure function — no side effects — so it is
50
- * unit-testable in isolation.
51
- */
52
- export declare function toWebColorValue(key: string, value: string): string;
53
- export interface PresetVarsOptions {
54
- /**
55
- * Also emit Tailwind v4 resolved `--color-*` vars (as sRGB `rgb(...)` strings)
56
- * alongside the raw HSL triples. Needed when scoping a subtree where
57
- * Tailwind's `@theme` block has already precomputed `--color-*` at `:root`,
58
- * so overriding `--background` alone wouldn't cascade to `bg-background`.
59
- *
60
- * The resolved vars are emitted as `rgb(...)` rather than `hsl(...)` so the
61
- * alpha-on-theme-color utilities (`bg-primary/10`, `text-foreground/50`)
62
- * resolve on native: Tailwind compiles those to a runtime `color-mix(...)` that
63
- * react-native-css evaluates via `colorjs.io/fn`, which only registers the
64
- * sRGB/P3/OKLab spaces (not HSL) — so an `hsl(...)` var would throw and the
65
- * utility would silently render no color. See `hslTripletToRgb`. Default
66
- * `false`.
67
- */
68
- includeResolvedColorVars?: boolean;
69
- }
70
2
  /**
71
3
  * Bloom's base preset tokens extended with the surface/card/chart/sidebar
72
4
  * tokens that apps layer on top of the core shadcn palette. Synthesized from
@@ -74,18 +6,23 @@ export interface PresetVarsOptions {
74
6
  *
75
7
  * This is the single source of truth for extended theming vars — consumer apps
76
8
  * must not redefine these per-app.
9
+ *
10
+ * Values are platform-agnostic **raw HSL triples** (`'185 100% 20%'`, optionally
11
+ * with a `/ A` alpha tail). The single canonical resolver `getResolvedTokens`
12
+ * (in `token-registry.ts`) converts these to sRGB `rgb(...)` for BOTH web and
13
+ * native runtime writes — this function only produces the raw triple map.
77
14
  */
78
- export declare function getPresetVars(colorName: AppColorName, mode: 'light' | 'dark', options?: PresetVarsOptions): PresetTokens;
15
+ export declare function getPresetVars(colorName: AppColorName, mode: 'light' | 'dark'): PresetTokens;
79
16
  /**
80
17
  * Apply a preset's extended vars to `document.documentElement`. Web-only no-op
81
18
  * on native. `BloomThemeProvider` already writes the base preset vars on web;
82
19
  * call this only when an app needs the extended (card/chart/sidebar) tokens on
83
20
  * the document root.
84
21
  *
85
- * The base raw-HSL-triple tokens are wrapped to full `hsl(...)` colors via
86
- * `toWebColorValue` so `var(--x)` (the form Tailwind v4 `@theme inline`
87
- * compiles to) resolves directly on web; `--color-*` rgb vars pass through. See
88
- * `toWebColorValue` for the web var contract.
22
+ * Tokens are resolved to sRGB `rgb(...)` via the single canonical
23
+ * `getResolvedTokens` pipeline, so `var(--x)` the form Tailwind v4
24
+ * `@theme inline` compiles its color utilities to resolves directly to a
25
+ * valid color on web.
89
26
  */
90
- export declare function applyPresetVarsToDocument(colorName: AppColorName, mode: 'light' | 'dark', options?: PresetVarsOptions): void;
27
+ export declare function applyPresetVarsToDocument(colorName: AppColorName, mode: 'light' | 'dark'): void;
91
28
  //# sourceMappingURL=preset-vars.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"preset-vars.d.ts","sourceRoot":"","sources":["../../../../src/theme/preset-vars.ts"],"names":[],"mappings":"AACA,OAAO,EAAqB,KAAK,YAAY,EAAE,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAU1F;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CA+CvD;AAmBD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAIlE;AAyBD,MAAM,WAAW,iBAAiB;IAChC;;;;;;;;;;;;;OAaG;IACH,wBAAwB,CAAC,EAAE,OAAO,CAAC;CACpC;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,SAAS,EAAE,YAAY,EACvB,IAAI,EAAE,OAAO,GAAG,MAAM,EACtB,OAAO,GAAE,iBAAsB,GAC9B,YAAY,CAwCd;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,YAAY,EACvB,IAAI,EAAE,OAAO,GAAG,MAAM,EACtB,OAAO,CAAC,EAAE,iBAAiB,GAC1B,IAAI,CAQN"}
1
+ {"version":3,"file":"preset-vars.d.ts","sourceRoot":"","sources":["../../../../src/theme/preset-vars.ts"],"names":[],"mappings":"AACA,OAAO,EAAqB,KAAK,YAAY,EAAE,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAe1F;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAC3B,SAAS,EAAE,YAAY,EACvB,IAAI,EAAE,OAAO,GAAG,MAAM,GACrB,YAAY,CAiCd;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,YAAY,EACvB,IAAI,EAAE,OAAO,GAAG,MAAM,GACrB,IAAI,CAQN"}
@@ -0,0 +1,53 @@
1
+ import { APP_COLOR_NAMES, type AppColorName } from './color-presets';
2
+ /**
3
+ * The canonical set of Bloom theme token names — WITHOUT the leading `--`.
4
+ *
5
+ * This is the single source of truth for which tokens a preset produces. It
6
+ * covers exactly the keys returned by `getPresetVars(name, mode)` (the base
7
+ * shadcn palette plus the synthesized extended tokens: card/chart/content-area/
8
+ * sidebar-*). The list is intentionally hand-maintained and verified by
9
+ * `token-registry.test.ts` against the live `getPresetVars('oxy', 'light')`
10
+ * output, so any drift in the preset shape fails CI.
11
+ *
12
+ * Order mirrors `getPresetVars`'s insertion order: base tokens first (in the
13
+ * order they appear in the preset data), then the synthesized extended tokens.
14
+ */
15
+ export declare const CANONICAL_TOKENS: readonly ["background", "foreground", "surface", "surface-foreground", "popover", "popover-foreground", "primary", "primary-foreground", "secondary", "secondary-foreground", "muted", "muted-foreground", "accent", "accent-foreground", "destructive", "border", "input", "ring", "sidebar", "card", "card-foreground", "chart-1", "chart-2", "chart-3", "chart-4", "chart-5", "content-area", "sidebar-foreground", "sidebar-primary", "sidebar-primary-foreground", "sidebar-accent", "sidebar-accent-foreground", "sidebar-border", "sidebar-ring"];
16
+ /** A canonical token name (no leading `--`). */
17
+ export type CanonicalToken = (typeof CANONICAL_TOKENS)[number];
18
+ /**
19
+ * Convert a shadcn-style HSL triple (`'H S% L%'`, optionally with an alpha tail
20
+ * `'H S% L% / A'`) into an sRGB `rgb(...)` string.
21
+ *
22
+ * Standard HSL→sRGB math with integer-rounded channels and modern
23
+ * space-separated output (`rgb(r g b)` / `rgb(r g b / a)`). This is the SINGLE
24
+ * conversion the whole library uses — web document writes, web scope vars, and
25
+ * native `rootVariables` all flow through `getResolvedTokens`, which calls this.
26
+ * The byte-for-byte output is frozen by the golden parity fixture
27
+ * (`__fixtures__/golden-resolved-tokens.json`), so the visible palette cannot
28
+ * drift.
29
+ *
30
+ * Task 2's `oklchToSrgb` (in `color-space.ts`) stays available for a FUTURE
31
+ * OKLCH re-authoring of the seed palette; it is intentionally NOT used here —
32
+ * routing through OKLCH would shift the rounded channels off the frozen palette.
33
+ *
34
+ * Pure function — no side effects.
35
+ */
36
+ export declare function hslToSrgb(triple: string): string;
37
+ /**
38
+ * Resolve a preset's canonical runtime color tokens to sRGB `rgb(...)` strings.
39
+ *
40
+ * THE single source of runtime color tokens for the whole library, on BOTH web
41
+ * and native. Takes the raw triple map from `getPresetVars(preset, mode)` (base
42
+ * + extended) and converts every value that looks like an HSL triple via
43
+ * `hslToSrgb`. Non-triple values (already-resolved colors, length/radius tokens)
44
+ * pass through unchanged. Keys retain the `--` prefix, so each `--x` token IS a
45
+ * full CSS color — no resolved-color companion universe, no per-platform wrapping.
46
+ *
47
+ * The result is frozen by the golden parity fixture
48
+ * (`__fixtures__/golden-resolved-tokens.json`), guaranteeing the visible palette
49
+ * matches the previous resolved-color pipeline byte-for-byte.
50
+ */
51
+ export declare function getResolvedTokens(preset: AppColorName, mode: 'light' | 'dark'): Record<string, string>;
52
+ export { APP_COLOR_NAMES };
53
+ //# sourceMappingURL=token-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-registry.d.ts","sourceRoot":"","sources":["../../../../src/theme/token-registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAGrE;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,gBAAgB,0hBAmCnB,CAAC;AAEX,gDAAgD;AAChD,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAW/D;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CA+ChD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,YAAY,EACpB,IAAI,EAAE,OAAO,GAAG,MAAM,GACrB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAOxB;AAED,OAAO,EAAE,eAAe,EAAE,CAAC"}
@@ -10,8 +10,11 @@ export interface ThemeColors {
10
10
  borderLight: string;
11
11
  primary: string;
12
12
  primaryForeground: string;
13
+ /** Preset accent tint (`--accent`) — a soft brand-tinted surface, NOT the page surface. */
13
14
  primaryLight: string;
15
+ /** Focus-ring shade (`--ring`) — the preset's emphasized ring/border color, NOT the page background. */
14
16
  primaryDark: string;
17
+ /** Preset secondary surface (`--secondary`) — a muted companion surface, NOT a mirror of `primary`. */
15
18
  secondary: string;
16
19
  tint: string;
17
20
  icon: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/theme/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,GAAG,UAAU,CAAC;AAEjE,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,kBAAkB,EAAE,MAAM,CAAC;IAE3B,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IAErB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IAEpB,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IAEpB,SAAS,EAAE,MAAM,CAAC;IAElB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IAEnB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IAEb,aAAa,EAAE,MAAM,CAAC;IACtB,uBAAuB,EAAE,MAAM,CAAC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,cAAc,EAAE,MAAM,CAAC;IACvB,wBAAwB,EAAE,MAAM,CAAC;IACjC,UAAU,EAAE,MAAM,CAAC;IAEnB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC;IACvB,MAAM,EAAE,WAAW,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;CAClB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/theme/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,GAAG,UAAU,CAAC;AAEjE,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,kBAAkB,EAAE,MAAM,CAAC;IAE3B,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IAErB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IAEpB,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,2FAA2F;IAC3F,YAAY,EAAE,MAAM,CAAC;IACrB,wGAAwG;IACxG,WAAW,EAAE,MAAM,CAAC;IAEpB,uGAAuG;IACvG,SAAS,EAAE,MAAM,CAAC;IAElB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IAEnB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IAEb,aAAa,EAAE,MAAM,CAAC;IACtB,uBAAuB,EAAE,MAAM,CAAC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,cAAc,EAAE,MAAM,CAAC;IACvB,wBAAwB,EAAE,MAAM,CAAC;IACjC,UAAU,EAAE,MAAM,CAAC;IAEnB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC;IACvB,MAAM,EAAE,WAAW,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;CAClB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxyhq/bloom",
3
- "version": "0.7.7",
3
+ "version": "0.8.0",
4
4
  "description": "Bloom UI — Oxy ecosystem component library for React Native + Expo + Web",
5
5
  "main": "lib/commonjs/index.js",
6
6
  "module": "lib/module/index.js",
@@ -153,17 +153,17 @@ describe('BloomColorScope', () => {
153
153
  );
154
154
 
155
155
  // Web var contract: the scoped base tokens (`--background`, `--primary`)
156
- // must be full `hsl(...)` colors never bare HSL triples so the web
157
- // apps' `var(--x)` color utilities resolve. (The production incident was a
158
- // bare triple here too.)
156
+ // must be full `rgb(...)` colors from the single canonical pipeline
157
+ // never bare HSL triples — so the web apps' `var(--x)` color utilities
158
+ // resolve. (The production incident was a bare triple here too.)
159
159
  const vars = Object.assign(
160
160
  {},
161
161
  ...flat.filter((entry) => '--background' in entry || '--primary' in entry),
162
162
  ) as Record<string, unknown>;
163
163
  const background = String(vars['--background'] ?? '');
164
164
  const primary = String(vars['--primary'] ?? '');
165
- expect(background.startsWith('hsl(')).toBe(true);
166
- expect(primary.startsWith('hsl(')).toBe(true);
165
+ expect(background.startsWith('rgb(')).toBe(true);
166
+ expect(primary.startsWith('rgb(')).toBe(true);
167
167
  expect(/^-?\d[\d.]*\s+[\d.]+%/.test(background)).toBe(false);
168
168
  });
169
169
  });
@@ -72,8 +72,8 @@ describe('BloomThemeProvider', () => {
72
72
  <ThemeDisplay />
73
73
  </BloomThemeProvider>,
74
74
  );
75
- // Blue preset primary is HSL(205, 87%, 53%) derived from --primary CSS var
76
- expect(getByTestId('primary').props.children).toBe('hsl(205, 87%, 53%)');
75
+ // Blue preset primary is HSL(205, 87%, 53%) canonical sRGB rgb(31 153 239)
76
+ expect(getByTestId('primary').props.children).toBe('rgb(31 153 239)');
77
77
  });
78
78
 
79
79
  it('generates different background colors for light and dark modes', () => {
@@ -135,7 +135,8 @@ describe('useThemeColor', () => {
135
135
  <ColorDisplay colorKey="primary" />
136
136
  </BloomThemeProvider>,
137
137
  );
138
- expect(getByTestId('color').props.children).toBe('hsl(185, 100%, 20%)');
138
+ // teal preset primary HSL(185, 100%, 20%) → canonical sRGB rgb(0 94 102)
139
+ expect(getByTestId('color').props.children).toBe('rgb(0 94 102)');
139
140
  });
140
141
  });
141
142
 
@@ -4,14 +4,13 @@
4
4
 
5
5
  import { Platform } from 'react-native';
6
6
 
7
- import { applyColorPresetVars, toWebColorValue } from '../theme/apply-dark-class';
7
+ import { applyColorPresetVars } from '../theme/apply-dark-class';
8
8
 
9
- // `applyColorPresetVars` is the WEB write path that feeds the live document. It
10
- // regressed by writing the base `--x` tokens as bare HSL triples (`185 50% 5%`),
11
- // which the shadcn/Tailwind-v4 web apps consume directly as
12
- // `background-color: var(--background)` invalid CSS transparent → unstyled
13
- // app. These tests pin the corrected contract: base tokens are full `hsl(...)`
14
- // colors, `--color-*` companions stay `rgb(...)`.
9
+ // `applyColorPresetVars` is the WEB write path that feeds the live document. The
10
+ // single canonical token pipeline (`getResolvedTokens`) resolves every base
11
+ // token to a full `rgb(...)` color, so the shadcn/Tailwind-v4 web apps that
12
+ // consume `background-color: var(--background)` directly get a valid color (the
13
+ // production incident was a bare HSL triple here). These tests pin that contract.
15
14
 
16
15
  describe('applyColorPresetVars — web document var contract', () => {
17
16
  const originalOS = Platform.OS;
@@ -26,11 +25,7 @@ describe('applyColorPresetVars — web document var contract', () => {
26
25
  document.documentElement.removeAttribute('style');
27
26
  });
28
27
 
29
- it('re-exports toWebColorValue (helper is consumed by the web write paths)', () => {
30
- expect(toWebColorValue('--background', '185 50% 5%')).toBe('hsl(185 50% 5%)');
31
- });
32
-
33
- it('writes base tokens to the document as full hsl() colors, not bare triples', () => {
28
+ it('writes base tokens to the document as full rgb() colors, not bare triples', () => {
34
29
  applyColorPresetVars('oxy', 'dark');
35
30
 
36
31
  const style = document.documentElement.style;
@@ -39,22 +34,32 @@ describe('applyColorPresetVars — web document var contract', () => {
39
34
  const foreground = style.getPropertyValue('--foreground').trim();
40
35
 
41
36
  expect(background).not.toBe('');
42
- // The exact bug: a bare `H S% L%` triple. Must be a wrapped color now.
43
- expect(background.startsWith('hsl(')).toBe(true);
37
+ // The exact bug: a bare `H S% L%` triple. Must be a resolved color now.
38
+ expect(background.startsWith('rgb(')).toBe(true);
44
39
  expect(background.endsWith(')')).toBe(true);
45
40
  expect(/^-?\d[\d.]*\s+[\d.]+%/.test(background)).toBe(false);
46
41
 
47
- expect(primary.startsWith('hsl(')).toBe(true);
48
- expect(foreground.startsWith('hsl(')).toBe(true);
42
+ expect(primary.startsWith('rgb(')).toBe(true);
43
+ expect(foreground.startsWith('rgb(')).toBe(true);
49
44
  });
50
45
 
51
- it('keeps the resolved --color-* vars as rgb() full colors', () => {
46
+ it('writes the extended tokens (card/chart/sidebar) as rgb() colors too', () => {
52
47
  applyColorPresetVars('oxy', 'dark');
53
48
 
54
- const colorPrimary = document.documentElement.style
55
- .getPropertyValue('--color-primary')
56
- .trim();
57
- expect(colorPrimary.startsWith('rgb(')).toBe(true);
49
+ const style = document.documentElement.style;
50
+ expect(style.getPropertyValue('--card').trim().startsWith('rgb(')).toBe(true);
51
+ expect(style.getPropertyValue('--sidebar-primary').trim().startsWith('rgb(')).toBe(true);
52
+ });
53
+
54
+ it('does NOT emit any legacy resolved-color companion vars', () => {
55
+ applyColorPresetVars('oxy', 'dark');
56
+ const style = document.documentElement.style;
57
+ // The base `--x` token IS the color now; no resolved-color companion universe
58
+ // should be written. Scan every property that was set rather than referencing
59
+ // the legacy name literally.
60
+ const prefix = `--${'color'}-`;
61
+ const written = Array.from({ length: style.length }, (_, i) => style.item(i));
62
+ expect(written.some((name) => name.startsWith(prefix))).toBe(false);
58
63
  });
59
64
 
60
65
  it('no-ops on native (does not touch the document)', () => {
@@ -52,16 +52,17 @@ describe('applyNativeRootVars (native variant)', () => {
52
52
  applyNativeRootVars('blue', 'light');
53
53
  });
54
54
 
55
- // Keys are bare (no `--`), and the raw HSL triple is present unwrapped.
55
+ // Keys are bare (no `--`), and the value is the single canonical sRGB
56
+ // `rgb(...)` color from `getResolvedTokens` (`205 87% 53%` → `rgb(31 153 239)`).
57
+ // sRGB is the space react-native-css's `color-mix` resolver registers, so
58
+ // alpha utilities (`bg-primary/10`) resolve on native.
56
59
  expect(sets).toHaveProperty('primary');
57
60
  expect(sets).not.toHaveProperty('--primary');
58
- expect(sets.primary).toEqual([['205 87% 53%']]);
61
+ expect(sets.primary).toEqual([['rgb(31 153 239)']]);
59
62
 
60
- // Resolved Tailwind v4 `--color-*` vars are written too, also bare-keyed,
61
- // and as sRGB `rgb(...)` (not `hsl(...)`) so native `color-mix` alpha
62
- // utilities resolve — `205 87% 53%` → `rgb(31 153 239)`.
63
- expect(sets).toHaveProperty('color-primary');
64
- expect(sets['color-primary']).toEqual([['rgb(31 153 239)']]);
63
+ // The legacy resolved-color companion universe is gone the base token IS
64
+ // rgb, so no `color-primary` companion is written.
65
+ expect(sets).not.toHaveProperty('color-primary');
65
66
 
66
67
  // Every value is a single-element value-array `[[value]]` of strings.
67
68
  for (const value of Object.values(sets)) {