@oxyhq/bloom 0.7.6 → 0.7.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commonjs/theme/apply-dark-class.js +28 -10
- package/lib/commonjs/theme/apply-dark-class.js.map +1 -1
- package/lib/commonjs/theme/color-presets.js +10 -4
- package/lib/commonjs/theme/color-presets.js.map +1 -1
- package/lib/commonjs/theme/color-scope/index.web.js +19 -2
- package/lib/commonjs/theme/color-scope/index.web.js.map +1 -1
- package/lib/commonjs/theme/index.js +6 -0
- package/lib/commonjs/theme/index.js.map +1 -1
- package/lib/commonjs/theme/preset-vars.js +54 -1
- package/lib/commonjs/theme/preset-vars.js.map +1 -1
- package/lib/module/theme/apply-dark-class.js +24 -11
- package/lib/module/theme/apply-dark-class.js.map +1 -1
- package/lib/module/theme/color-presets.js +10 -4
- package/lib/module/theme/color-presets.js.map +1 -1
- package/lib/module/theme/color-scope/index.web.js +22 -3
- package/lib/module/theme/color-scope/index.web.js.map +1 -1
- package/lib/module/theme/index.js +1 -1
- package/lib/module/theme/index.js.map +1 -1
- package/lib/module/theme/preset-vars.js +53 -1
- package/lib/module/theme/preset-vars.js.map +1 -1
- package/lib/typescript/commonjs/theme/apply-dark-class.d.ts +18 -9
- package/lib/typescript/commonjs/theme/apply-dark-class.d.ts.map +1 -1
- package/lib/typescript/commonjs/theme/color-presets.d.ts +10 -4
- package/lib/typescript/commonjs/theme/color-presets.d.ts.map +1 -1
- package/lib/typescript/commonjs/theme/color-scope/index.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/theme/index.d.ts +1 -1
- package/lib/typescript/commonjs/theme/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/theme/preset-vars.d.ts +30 -0
- package/lib/typescript/commonjs/theme/preset-vars.d.ts.map +1 -1
- package/lib/typescript/module/theme/apply-dark-class.d.ts +18 -9
- package/lib/typescript/module/theme/apply-dark-class.d.ts.map +1 -1
- package/lib/typescript/module/theme/color-presets.d.ts +10 -4
- package/lib/typescript/module/theme/color-presets.d.ts.map +1 -1
- package/lib/typescript/module/theme/color-scope/index.web.d.ts.map +1 -1
- package/lib/typescript/module/theme/index.d.ts +1 -1
- package/lib/typescript/module/theme/index.d.ts.map +1 -1
- package/lib/typescript/module/theme/preset-vars.d.ts +30 -0
- package/lib/typescript/module/theme/preset-vars.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/BloomColorScope.test.tsx +14 -0
- package/src/__tests__/apply-dark-class.test.ts +65 -0
- package/src/__tests__/preset-vars.test.ts +47 -1
- package/src/theme/apply-dark-class.ts +24 -11
- package/src/theme/color-presets.ts +10 -4
- package/src/theme/color-scope/index.web.tsx +23 -2
- package/src/theme/index.ts +1 -0
- package/src/theme/preset-vars.ts +53 -1
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { Platform } from 'react-native';
|
|
2
2
|
import { APP_COLOR_PRESETS, type AppColorName } from './color-presets';
|
|
3
|
-
import { getPresetVars } from './preset-vars';
|
|
3
|
+
import { getPresetVars, toWebColorValue } from './preset-vars';
|
|
4
|
+
|
|
5
|
+
// Re-exported so the web var-contract helper is reachable from this file (the
|
|
6
|
+
// home of the web write path). Defined in `preset-vars.ts` next to the related
|
|
7
|
+
// HSL parsing so native (which never imports this module) doesn't pull it in.
|
|
8
|
+
export { toWebColorValue } from './preset-vars';
|
|
4
9
|
|
|
5
10
|
export function applyDarkClass(resolved: 'light' | 'dark') {
|
|
6
11
|
if (Platform.OS === 'web' && typeof document !== 'undefined') {
|
|
@@ -10,16 +15,24 @@ export function applyDarkClass(resolved: 'light' | 'dark') {
|
|
|
10
15
|
|
|
11
16
|
/**
|
|
12
17
|
* Apply a color preset's CSS custom properties to the document root.
|
|
13
|
-
* No-op on native — only affects web.
|
|
18
|
+
* No-op on native — only affects web (early-returns on `Platform.OS !== 'web'`).
|
|
19
|
+
*
|
|
20
|
+
* Web var contract (the form Tailwind v4 `@theme inline` compiles to)
|
|
21
|
+
* -------------------------------------------------------------------
|
|
22
|
+
* The shadcn/Tailwind-v4 web apps compile their color utilities to reference the
|
|
23
|
+
* BASE token directly (`.bg-background { background-color: var(--background) }`),
|
|
24
|
+
* so on web the base `--x` tokens MUST be FULL CSS colors. We therefore write
|
|
25
|
+
* them as `hsl(...)` (e.g. `--primary: hsl(185 100% 20%)`) — `var(--primary)`
|
|
26
|
+
* then resolves to a valid color. The resolved `--color-*` vars are written
|
|
27
|
+
* verbatim as `rgb(...)` (already full colors, used by native `color-mix` alpha
|
|
28
|
+
* utilities; harmless on web). Non-color tokens (`--radius`, etc.) pass through
|
|
29
|
+
* unchanged. See `toWebColorValue`.
|
|
14
30
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* see `getPresetVars` / `hslTripletToRgb`. Includes extended tokens (card,
|
|
21
|
-
* chart-*, content-area, sidebar-*) so consumer apps don't need to synthesize
|
|
22
|
-
* them.
|
|
31
|
+
* NATIVE writes the SAME tokens as RAW HSL triples (no `hsl()` wrapper) via
|
|
32
|
+
* `rootVariables` (`native-root-vars.native.ts`), consumed through bloom's
|
|
33
|
+
* native `global.css` `hsl(var(--x))` indirection — that path is untouched here.
|
|
34
|
+
* Includes extended tokens (card, chart-*, content-area, sidebar-*) so consumer
|
|
35
|
+
* apps don't need to synthesize them.
|
|
23
36
|
*/
|
|
24
37
|
export function applyColorPresetVars(preset: AppColorName, resolved: 'light' | 'dark') {
|
|
25
38
|
if (Platform.OS !== 'web' || typeof document === 'undefined') return;
|
|
@@ -29,6 +42,6 @@ export function applyColorPresetVars(preset: AppColorName, resolved: 'light' | '
|
|
|
29
42
|
const root = document.documentElement.style;
|
|
30
43
|
|
|
31
44
|
for (const [key, value] of Object.entries(vars)) {
|
|
32
|
-
root.setProperty(key, value);
|
|
45
|
+
root.setProperty(key, toWebColorValue(key, value));
|
|
33
46
|
}
|
|
34
47
|
}
|
|
@@ -7,10 +7,16 @@ export type AppColorName = 'teal' | 'blue' | 'green' | 'amber' | 'yellow' | 'red
|
|
|
7
7
|
* names) — keep in mind the values are platform-agnostic **raw HSL triples**
|
|
8
8
|
* (e.g. `'185 100% 20%'` or `'185 100% 20% / 0.5'`), not CSS-resolved colors.
|
|
9
9
|
* The same map drives both:
|
|
10
|
-
* - the web layer
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
10
|
+
* - the web layer: the base `--x` tokens are wrapped to full `hsl(...)` colors
|
|
11
|
+
* (via `toWebColorValue`) before being written to `document.documentElement`
|
|
12
|
+
* / a `BloomColorScope` element, so `var(--x)` — the form Tailwind v4
|
|
13
|
+
* `@theme inline` compiles its color utilities to — resolves to a valid
|
|
14
|
+
* color directly; the resolved `--color-*` companions are written as
|
|
15
|
+
* `rgb(...)`, and
|
|
16
|
+
* - the native layer (`buildTheme` resolves the raw triples into `hsl(...)`
|
|
17
|
+
* strings consumable by React Native styles; `native-root-vars.native.ts`
|
|
18
|
+
* writes the raw triples through bloom's `hsl(var(--x))` `global.css`
|
|
19
|
+
* indirection).
|
|
14
20
|
*
|
|
15
21
|
* The `--` prefix is an implementation detail we will drop in a future major.
|
|
16
22
|
*/
|
|
@@ -3,8 +3,29 @@ import React, { Children, cloneElement, isValidElement, useContext, useMemo } fr
|
|
|
3
3
|
import { BloomThemeContext, type BloomThemeContextValue } from '../BloomThemeProvider';
|
|
4
4
|
import { buildTheme } from '../build-theme';
|
|
5
5
|
import type { AppColorName } from '../color-presets';
|
|
6
|
+
import { toWebColorValue } from '../preset-vars';
|
|
6
7
|
import { buildScopeVars } from './style-builder';
|
|
7
8
|
|
|
9
|
+
/**
|
|
10
|
+
* `buildScopeVars` returns the preset's tokens as platform-agnostic raw HSL
|
|
11
|
+
* triples (shared with the native write path). On web they are scoped onto an
|
|
12
|
+
* element's inline `style`, where Tailwind v4's compiled utilities read them as
|
|
13
|
+
* `var(--x)` directly — so the base tokens MUST be full CSS colors. Wrap each
|
|
14
|
+
* raw triple in `hsl(...)` via `toWebColorValue`; `--color-*` rgb vars and
|
|
15
|
+
* non-color tokens pass through. See `toWebColorValue` in `../preset-vars`.
|
|
16
|
+
*/
|
|
17
|
+
function buildWebScopeVars(
|
|
18
|
+
colorPreset: AppColorName,
|
|
19
|
+
mode: 'light' | 'dark',
|
|
20
|
+
): React.CSSProperties {
|
|
21
|
+
const raw = buildScopeVars(colorPreset, mode);
|
|
22
|
+
const out: Record<string, string> = {};
|
|
23
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
24
|
+
out[key] = toWebColorValue(key, value);
|
|
25
|
+
}
|
|
26
|
+
return out as React.CSSProperties;
|
|
27
|
+
}
|
|
28
|
+
|
|
8
29
|
export interface BloomColorScopeProps {
|
|
9
30
|
/**
|
|
10
31
|
* Preset to apply within this subtree. When `undefined`, the scope is a
|
|
@@ -63,7 +84,7 @@ export function BloomColorScope({
|
|
|
63
84
|
}, [colorPreset, resolvedMode, parent]);
|
|
64
85
|
|
|
65
86
|
const varsStyle = useMemo(
|
|
66
|
-
() =>
|
|
87
|
+
() => buildWebScopeVars(colorPreset, resolvedMode),
|
|
67
88
|
[colorPreset, resolvedMode],
|
|
68
89
|
);
|
|
69
90
|
|
|
@@ -104,7 +125,7 @@ export function useColorScopeStyle(colorPreset: AppColorName): React.CSSProperti
|
|
|
104
125
|
}
|
|
105
126
|
const resolvedMode = parent.theme.mode;
|
|
106
127
|
return useMemo(
|
|
107
|
-
() =>
|
|
128
|
+
() => buildWebScopeVars(colorPreset, resolvedMode),
|
|
108
129
|
[colorPreset, resolvedMode],
|
|
109
130
|
);
|
|
110
131
|
}
|
package/src/theme/index.ts
CHANGED
package/src/theme/preset-vars.ts
CHANGED
|
@@ -83,6 +83,53 @@ export function hslTripletToRgb(triplet: string): string {
|
|
|
83
83
|
return `rgb(${red} ${green} ${blue})`;
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
/**
|
|
87
|
+
* Prefix that marks a Tailwind v4 resolved color var (`--color-primary`). These
|
|
88
|
+
* are already emitted as full `rgb(...)` colors by `getPresetVars` and must be
|
|
89
|
+
* written to web verbatim — wrapping them would corrupt the value.
|
|
90
|
+
*/
|
|
91
|
+
const RESOLVED_COLOR_VAR_PREFIX = '--color-';
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Matches a shadcn-style raw HSL triple — `H S% L%`, optionally with an alpha
|
|
95
|
+
* tail `H S% L% / A`. The value starts with a digit (or a leading `-`) and
|
|
96
|
+
* carries at least one `%` (the saturation/lightness units), which together
|
|
97
|
+
* distinguish a bare triple from an already-resolved CSS color (`rgb(...)`,
|
|
98
|
+
* `hsl(...)`, `#fff`, named colors) or a unitless/length token (`--radius`).
|
|
99
|
+
* Mirrors the triple shape parsed by `hslTripletToRgb`.
|
|
100
|
+
*/
|
|
101
|
+
const RAW_HSL_TRIPLE = /^-?\d[\d.]*\s+[\d.]+%/;
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Transform a single preset var into the value to write to a WEB element
|
|
105
|
+
* (`document.documentElement` or a `BloomColorScope` subtree element).
|
|
106
|
+
*
|
|
107
|
+
* The web apps (Vite + Tailwind v4 + shadcn) compile their `@theme inline`
|
|
108
|
+
* block so the color utilities reference the BASE token directly — e.g.
|
|
109
|
+
* `.bg-background { background-color: var(--background) }`. So on web the base
|
|
110
|
+
* `--x` tokens MUST resolve to a COMPLETE CSS color; a bare HSL triple
|
|
111
|
+
* (`185 50% 5%`) is invalid as a `background-color` value and renders
|
|
112
|
+
* transparent (the production incident this fixes). We therefore wrap raw
|
|
113
|
+
* triples in `hsl(...)`, preserving the exact preset color math (and any `/ A`
|
|
114
|
+
* alpha tail, valid in modern `hsl(H S% L% / A)` syntax) with zero rounding
|
|
115
|
+
* drift.
|
|
116
|
+
*
|
|
117
|
+
* Values that are already full colors pass through unchanged:
|
|
118
|
+
* - `--color-*` resolved vars (already `rgb(...)` from `getPresetVars`),
|
|
119
|
+
* - any value not shaped like a raw HSL triple (`--radius: 0.5rem`,
|
|
120
|
+
* pre-resolved `rgb(...)`/`hsl(...)`, etc.).
|
|
121
|
+
*
|
|
122
|
+
* NATIVE never calls this — `getPresetVars` returns raw triples verbatim and
|
|
123
|
+
* `native-root-vars.native.ts` writes them through bloom's `hsl(var(--x))`
|
|
124
|
+
* native `global.css` indirection. Pure function — no side effects — so it is
|
|
125
|
+
* unit-testable in isolation.
|
|
126
|
+
*/
|
|
127
|
+
export function toWebColorValue(key: string, value: string): string {
|
|
128
|
+
if (key.startsWith(RESOLVED_COLOR_VAR_PREFIX)) return value;
|
|
129
|
+
if (!RAW_HSL_TRIPLE.test(value)) return value;
|
|
130
|
+
return `hsl(${value})`;
|
|
131
|
+
}
|
|
132
|
+
|
|
86
133
|
const RESOLVED_COLOR_MAP: Record<string, string> = {
|
|
87
134
|
'--background': '--color-background',
|
|
88
135
|
'--foreground': '--color-foreground',
|
|
@@ -183,6 +230,11 @@ export function getPresetVars(
|
|
|
183
230
|
* on native. `BloomThemeProvider` already writes the base preset vars on web;
|
|
184
231
|
* call this only when an app needs the extended (card/chart/sidebar) tokens on
|
|
185
232
|
* the document root.
|
|
233
|
+
*
|
|
234
|
+
* The base raw-HSL-triple tokens are wrapped to full `hsl(...)` colors via
|
|
235
|
+
* `toWebColorValue` so `var(--x)` (the form Tailwind v4 `@theme inline`
|
|
236
|
+
* compiles to) resolves directly on web; `--color-*` rgb vars pass through. See
|
|
237
|
+
* `toWebColorValue` for the web var contract.
|
|
186
238
|
*/
|
|
187
239
|
export function applyPresetVarsToDocument(
|
|
188
240
|
colorName: AppColorName,
|
|
@@ -194,6 +246,6 @@ export function applyPresetVarsToDocument(
|
|
|
194
246
|
const vars = getPresetVars(colorName, mode, options);
|
|
195
247
|
const root = document.documentElement.style;
|
|
196
248
|
for (const [key, value] of Object.entries(vars)) {
|
|
197
|
-
root.setProperty(key, value);
|
|
249
|
+
root.setProperty(key, toWebColorValue(key, value));
|
|
198
250
|
}
|
|
199
251
|
}
|