@oxyhq/bloom 0.84.0 → 0.85.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.
@@ -81,8 +81,22 @@ Object.defineProperty(exports, "bloomThemeCss", {
81
81
  return _themeCss.bloomThemeCss;
82
82
  }
83
83
  });
84
+ Object.defineProperty(exports, "buildSeedScopeVars", {
85
+ enumerable: true,
86
+ get: function () {
87
+ return _seedScope.buildSeedScopeVars;
88
+ }
89
+ });
90
+ Object.defineProperty(exports, "getPresetVars", {
91
+ enumerable: true,
92
+ get: function () {
93
+ return _presetVars.getPresetVars;
94
+ }
95
+ });
84
96
  var _tailwindPreset = require("./tailwind-preset.js");
85
97
  var _themeCss = require("./theme-css.js");
98
+ var _presetVars = require("../theme/preset-vars.js");
99
+ var _seedScope = require("../theme/color-scope/seed-scope.js");
86
100
  var _colorRoles = require("./color-roles.js");
87
101
  var _scales = require("./scales.js");
88
102
  var _shadows = require("./shadows");
@@ -1 +1 @@
1
- {"version":3,"names":["_tailwindPreset","require","_themeCss","_colorRoles","_scales","_shadows"],"sourceRoot":"../../../src","sources":["design-tokens/index.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmBA,IAAAA,eAAA,GAAAC,OAAA;AAMA,IAAAC,SAAA,GAAAD,OAAA;AAEA,IAAAE,WAAA,GAAAF,OAAA;AAOA,IAAAG,OAAA,GAAAH,OAAA;AASA,IAAAI,QAAA,GAAAJ,OAAA","ignoreList":[]}
1
+ {"version":3,"names":["_tailwindPreset","require","_themeCss","_presetVars","_seedScope","_colorRoles","_scales","_shadows"],"sourceRoot":"../../../src","sources":["design-tokens/index.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqBA,IAAAA,eAAA,GAAAC,OAAA;AAMA,IAAAC,SAAA,GAAAD,OAAA;AAgBA,IAAAE,WAAA,GAAAF,OAAA;AAEA,IAAAG,UAAA,GAAAH,OAAA;AAGA,IAAAI,WAAA,GAAAJ,OAAA;AAOA,IAAAK,OAAA,GAAAL,OAAA;AASA,IAAAM,QAAA,GAAAN,OAAA","ignoreList":[]}
@@ -10,6 +10,8 @@
10
10
  * `p-space-8`, `rounded-radius-20`, `text-body`, `font-body`, `shadow-s`).
11
11
  * - `bloomThemeCss` / `bloomThemeBlock` — the Tailwind v4 `@theme` equivalent
12
12
  * for CSS-configured web apps.
13
+ * - `getPresetVars` / `buildSeedScopeVars` — the resolved token VALUES behind
14
+ * that alias layer, for a named preset or an arbitrary brand seed.
13
15
  * - The raw token maps (`FILL_ROLES`, `TEXT_ROLES`, `BORDER_ROLES`, `SPACING`,
14
16
  * `RADIUS`, `TYPOGRAPHY`, `SHADOW_BOX`) for direct programmatic use.
15
17
  * - `bloomShadowStyle` — platform-correct shadow style object (web box-shadow /
@@ -21,6 +23,23 @@
21
23
 
22
24
  export { bloomTailwindPreset } from "./tailwind-preset.js";
23
25
  export { bloomThemeCss, bloomThemeBlock } from "./theme-css.js";
26
+
27
+ /* The resolved counterpart of `bloomThemeCss()`. That emits the alias layer
28
+ * (`--color-x: var(--x)`); these resolve `--x` itself, so a build script can
29
+ * write a static `:root` / `.dark` block and a prerendered page paints the real
30
+ * theme before `BloomThemeProvider` runs — instead of a hand-written palette
31
+ * that drifts from the preset it claims to mirror.
32
+ *
33
+ * `getPresetVars` returns the canonical tokens alone, which is all a document
34
+ * root needs. `buildSeedScopeVars` also returns the `--color-x` aliases, which a
35
+ * SCOPED block (a brand section, a forced-dark region) does need: a `--color-x`
36
+ * alias substitutes where it is declared, so overriding `--x` on a subtree does
37
+ * not move an alias declared at `:root`.
38
+ *
39
+ * Both are pure — no React, no react-native — so they run in a plain node/bun
40
+ * build script as well as in an app. */
41
+ export { getPresetVars } from "../theme/preset-vars.js";
42
+ export { buildSeedScopeVars } from "../theme/color-scope/seed-scope.js";
24
43
  export { FILL_ROLES, TEXT_ROLES, BORDER_ROLES } from "./color-roles.js";
25
44
  export { SPACING, RADIUS, BORDER_WIDTH, TYPOGRAPHY, FONT_FAMILY_VARS } from "./scales.js";
26
45
  export { SHADOW_BOX, bloomShadowStyle } from './shadows';
@@ -1 +1 @@
1
- {"version":3,"names":["bloomTailwindPreset","bloomThemeCss","bloomThemeBlock","FILL_ROLES","TEXT_ROLES","BORDER_ROLES","SPACING","RADIUS","BORDER_WIDTH","TYPOGRAPHY","FONT_FAMILY_VARS","SHADOW_BOX","bloomShadowStyle"],"sourceRoot":"../../../src","sources":["design-tokens/index.ts"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,SAASA,mBAAmB,QAAQ,sBAAmB;AAMvD,SAASC,aAAa,EAAEC,eAAe,QAAQ,gBAAa;AAE5D,SACEC,UAAU,EACVC,UAAU,EACVC,YAAY,QACP,kBAAe;AAGtB,SACEC,OAAO,EACPC,MAAM,EACNC,YAAY,EACZC,UAAU,EACVC,gBAAgB,QACX,aAAU;AAGjB,SAASC,UAAU,EAAEC,gBAAgB,QAAQ,WAAW","ignoreList":[]}
1
+ {"version":3,"names":["bloomTailwindPreset","bloomThemeCss","bloomThemeBlock","getPresetVars","buildSeedScopeVars","FILL_ROLES","TEXT_ROLES","BORDER_ROLES","SPACING","RADIUS","BORDER_WIDTH","TYPOGRAPHY","FONT_FAMILY_VARS","SHADOW_BOX","bloomShadowStyle"],"sourceRoot":"../../../src","sources":["design-tokens/index.ts"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,SAASA,mBAAmB,QAAQ,sBAAmB;AAMvD,SAASC,aAAa,EAAEC,eAAe,QAAQ,gBAAa;;AAE5D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAASC,aAAa,QAAQ,yBAAsB;AAEpD,SAASC,kBAAkB,QAAQ,oCAAiC;AAGpE,SACEC,UAAU,EACVC,UAAU,EACVC,YAAY,QACP,kBAAe;AAGtB,SACEC,OAAO,EACPC,MAAM,EACNC,YAAY,EACZC,UAAU,EACVC,gBAAgB,QACX,aAAU;AAGjB,SAASC,UAAU,EAAEC,gBAAgB,QAAQ,WAAW","ignoreList":[]}
@@ -8,6 +8,8 @@
8
8
  * `p-space-8`, `rounded-radius-20`, `text-body`, `font-body`, `shadow-s`).
9
9
  * - `bloomThemeCss` / `bloomThemeBlock` — the Tailwind v4 `@theme` equivalent
10
10
  * for CSS-configured web apps.
11
+ * - `getPresetVars` / `buildSeedScopeVars` — the resolved token VALUES behind
12
+ * that alias layer, for a named preset or an arbitrary brand seed.
11
13
  * - The raw token maps (`FILL_ROLES`, `TEXT_ROLES`, `BORDER_ROLES`, `SPACING`,
12
14
  * `RADIUS`, `TYPOGRAPHY`, `SHADOW_BOX`) for direct programmatic use.
13
15
  * - `bloomShadowStyle` — platform-correct shadow style object (web box-shadow /
@@ -19,6 +21,10 @@
19
21
  export { bloomTailwindPreset } from './tailwind-preset';
20
22
  export type { TailwindPreset, TailwindPresetThemeExtend, } from './tailwind-preset';
21
23
  export { bloomThemeCss, bloomThemeBlock } from './theme-css';
24
+ export { getPresetVars } from '../theme/preset-vars';
25
+ export type { ExplicitAccents } from '../theme/preset-vars';
26
+ export { buildSeedScopeVars } from '../theme/color-scope/seed-scope';
27
+ export type { SeedScopeOptions } from '../theme/color-scope/seed-scope';
22
28
  export { FILL_ROLES, TEXT_ROLES, BORDER_ROLES, } from './color-roles';
23
29
  export type { FillRole, TextRole, BorderRole } from './color-roles';
24
30
  export { SPACING, RADIUS, BORDER_WIDTH, TYPOGRAPHY, FONT_FAMILY_VARS, } from './scales';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/design-tokens/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,YAAY,EACV,cAAc,EACd,yBAAyB,GAC1B,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE7D,OAAO,EACL,UAAU,EACV,UAAU,EACV,YAAY,GACb,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEpE,OAAO,EACL,OAAO,EACP,MAAM,EACN,YAAY,EACZ,UAAU,EACV,gBAAgB,GACjB,MAAM,UAAU,CAAC;AAClB,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAEvD,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AACzD,YAAY,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/design-tokens/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,YAAY,EACV,cAAc,EACd,yBAAyB,GAC1B,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAgB7D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,YAAY,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,YAAY,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAExE,OAAO,EACL,UAAU,EACV,UAAU,EACV,YAAY,GACb,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEpE,OAAO,EACL,OAAO,EACP,MAAM,EACN,YAAY,EACZ,UAAU,EACV,gBAAgB,GACjB,MAAM,UAAU,CAAC;AAClB,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAEvD,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AACzD,YAAY,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC"}
@@ -8,6 +8,8 @@
8
8
  * `p-space-8`, `rounded-radius-20`, `text-body`, `font-body`, `shadow-s`).
9
9
  * - `bloomThemeCss` / `bloomThemeBlock` — the Tailwind v4 `@theme` equivalent
10
10
  * for CSS-configured web apps.
11
+ * - `getPresetVars` / `buildSeedScopeVars` — the resolved token VALUES behind
12
+ * that alias layer, for a named preset or an arbitrary brand seed.
11
13
  * - The raw token maps (`FILL_ROLES`, `TEXT_ROLES`, `BORDER_ROLES`, `SPACING`,
12
14
  * `RADIUS`, `TYPOGRAPHY`, `SHADOW_BOX`) for direct programmatic use.
13
15
  * - `bloomShadowStyle` — platform-correct shadow style object (web box-shadow /
@@ -19,6 +21,10 @@
19
21
  export { bloomTailwindPreset } from './tailwind-preset';
20
22
  export type { TailwindPreset, TailwindPresetThemeExtend, } from './tailwind-preset';
21
23
  export { bloomThemeCss, bloomThemeBlock } from './theme-css';
24
+ export { getPresetVars } from '../theme/preset-vars';
25
+ export type { ExplicitAccents } from '../theme/preset-vars';
26
+ export { buildSeedScopeVars } from '../theme/color-scope/seed-scope';
27
+ export type { SeedScopeOptions } from '../theme/color-scope/seed-scope';
22
28
  export { FILL_ROLES, TEXT_ROLES, BORDER_ROLES, } from './color-roles';
23
29
  export type { FillRole, TextRole, BorderRole } from './color-roles';
24
30
  export { SPACING, RADIUS, BORDER_WIDTH, TYPOGRAPHY, FONT_FAMILY_VARS, } from './scales';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/design-tokens/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,YAAY,EACV,cAAc,EACd,yBAAyB,GAC1B,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE7D,OAAO,EACL,UAAU,EACV,UAAU,EACV,YAAY,GACb,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEpE,OAAO,EACL,OAAO,EACP,MAAM,EACN,YAAY,EACZ,UAAU,EACV,gBAAgB,GACjB,MAAM,UAAU,CAAC;AAClB,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAEvD,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AACzD,YAAY,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/design-tokens/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,YAAY,EACV,cAAc,EACd,yBAAyB,GAC1B,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAgB7D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,YAAY,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,YAAY,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAExE,OAAO,EACL,UAAU,EACV,UAAU,EACV,YAAY,GACb,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEpE,OAAO,EACL,OAAO,EACP,MAAM,EACN,YAAY,EACZ,UAAU,EACV,gBAAgB,GACjB,MAAM,UAAU,CAAC;AAClB,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAEvD,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AACzD,YAAY,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxyhq/bloom",
3
- "version": "0.84.0",
3
+ "version": "0.85.0",
4
4
  "packageManager": "bun@1.3.14",
5
5
  "description": "Bloom UI — Oxy ecosystem component library for React Native + Expo + Web",
6
6
  "main": "lib/commonjs/index.js",
@@ -1,10 +1,12 @@
1
- import { readFileSync } from 'node:fs';
2
- import { join } from 'node:path';
1
+ import { existsSync, readFileSync, statSync } from 'node:fs';
2
+ import { dirname, join, relative } from 'node:path';
3
3
 
4
4
  import {
5
5
  bloomTailwindPreset,
6
6
  bloomThemeCss,
7
7
  bloomThemeBlock,
8
+ getPresetVars,
9
+ buildSeedScopeVars,
8
10
  FILL_ROLES,
9
11
  TEXT_ROLES,
10
12
  BORDER_ROLES,
@@ -16,6 +18,7 @@ import {
16
18
  SHADOW_BOX,
17
19
  bloomShadowStyle,
18
20
  } from '../design-tokens';
21
+ import { APP_COLOR_PRESETS } from '../theme/color-presets';
19
22
  import { CANONICAL_TOKENS } from '../theme/token-registry';
20
23
 
21
24
  describe('design-tokens color roles', () => {
@@ -190,3 +193,113 @@ describe('design-tokens shadow style (web default)', () => {
190
193
  expect(style).toHaveProperty('boxShadow', SHADOW_BOX.m);
191
194
  });
192
195
  });
196
+
197
+ describe('design-tokens resolved token values', () => {
198
+ it('getPresetVars resolves a preset to canonical tokens only', () => {
199
+ const vars = getPresetVars('oxy', 'dark');
200
+ expect(vars['--background']).toMatch(/^rgb/);
201
+ // A document root needs the canonical tokens alone — the `--color-x` alias
202
+ // layer comes from theme.css / bloomThemeCss().
203
+ expect(Object.keys(vars).some((k) => k.startsWith('--color-'))).toBe(false);
204
+ });
205
+
206
+ it('buildSeedScopeVars also emits the --color-x aliases a scope needs', () => {
207
+ const vars = buildSeedScopeVars({ seed: '#7c5aed', mode: 'dark' });
208
+ const aliases = Object.keys(vars).filter((k) => k.startsWith('--color-'));
209
+ expect(aliases.length).toBeGreaterThan(0);
210
+ for (const alias of aliases) {
211
+ expect(vars[alias]).toBe(vars[alias.replace('--color-', '--')]);
212
+ }
213
+ });
214
+
215
+ it("a preset's own seed reproduces that preset exactly", () => {
216
+ // What lets a consumer theme a brand scope and the document root through one
217
+ // code path: the seed form is not an approximation of the preset form.
218
+ const preset = APP_COLOR_PRESETS.oxy;
219
+ for (const mode of ['light', 'dark'] as const) {
220
+ const fromPreset = getPresetVars('oxy', mode);
221
+ const fromSeed = buildSeedScopeVars({
222
+ seed: preset.hex,
223
+ mode,
224
+ variant: preset.variant,
225
+ });
226
+ for (const [token, value] of Object.entries(fromPreset)) {
227
+ expect(fromSeed[token]).toBe(value);
228
+ }
229
+ }
230
+ });
231
+ });
232
+
233
+ describe('design-tokens entry stays free of react / react-native', () => {
234
+ /* Build scripts import this entry from plain node/bun to emit a static theme
235
+ * stylesheet (see the export's doc comment). A `react-native` import anywhere
236
+ * in its transitive graph makes that throw at import time — in the CONSUMER's
237
+ * build, with a parse error inside node_modules and nothing pointing back
238
+ * here. Jest cannot catch it by importing the module: this suite runs in the
239
+ * RN preset, where both packages resolve. So walk the graph statically. */
240
+ const SOURCE_ROOT = join(__dirname, '..');
241
+ /* Captures the clause of every `import`/`export … from '…'`, so a type-only
242
+ * one can be told apart from a value one. `import { type ViewStyle } from
243
+ * 'react-native'` is erased by the compiler and is FINE here; a value import
244
+ * of the same module is not. A scanner blind to the difference reports the
245
+ * shipped `shadows.ts` as a violation. */
246
+ const IMPORT_RE = /(?:import|export)\s+([\s\S]*?)\s*from\s*['"]([^'"]+)['"]/g;
247
+
248
+ function isValueImport(clause: string): boolean {
249
+ const trimmed = clause.trim();
250
+ if (trimmed.startsWith('type ') || trimmed === 'type') return false;
251
+ const named = /^\{([\s\S]*)\}$/.exec(trimmed)?.[1];
252
+ if (named === undefined) return true; // default or namespace import — always a value
253
+ return named
254
+ .split(',')
255
+ .map((specifier) => specifier.trim())
256
+ .filter(Boolean)
257
+ .some((specifier) => !specifier.startsWith('type '));
258
+ }
259
+
260
+ function resolve(specifier: string, fromFile: string): string | null {
261
+ const base = join(dirname(fromFile), specifier);
262
+ for (const candidate of [
263
+ base,
264
+ `${base}.ts`,
265
+ `${base}.tsx`,
266
+ join(base, 'index.ts'),
267
+ join(base, 'index.tsx'),
268
+ ]) {
269
+ if (existsSync(candidate) && statSync(candidate).isFile()) return candidate;
270
+ }
271
+ return null;
272
+ }
273
+
274
+ const entry = join(SOURCE_ROOT, 'design-tokens', 'index.ts');
275
+ const visited = new Set<string>();
276
+ const offenders: string[] = [];
277
+ const queue = [entry];
278
+
279
+ for (let file = queue.pop(); file !== undefined; file = queue.pop()) {
280
+ if (visited.has(file)) continue;
281
+ visited.add(file);
282
+ const source = readFileSync(file, 'utf8');
283
+ for (const match of source.matchAll(IMPORT_RE)) {
284
+ const [, clause = '', specifier = ''] = match;
285
+ if (!isValueImport(clause)) continue;
286
+ if (specifier === 'react' || specifier === 'react-native' || specifier.startsWith('react-native/')) {
287
+ offenders.push(`${relative(SOURCE_ROOT, file)} imports ${specifier}`);
288
+ continue;
289
+ }
290
+ if (!specifier.startsWith('.')) continue;
291
+ const resolved = resolve(specifier, file);
292
+ if (resolved) queue.push(resolved);
293
+ }
294
+ }
295
+
296
+ it('imports neither react nor react-native anywhere in its graph', () => {
297
+ expect(offenders).toEqual([]);
298
+ });
299
+
300
+ it('actually walked the graph', () => {
301
+ // Without a floor, a resolver that silently returns null for everything
302
+ // would report a clean graph of one file.
303
+ expect(visited.size).toBeGreaterThan(8);
304
+ });
305
+ });
@@ -8,6 +8,8 @@
8
8
  * `p-space-8`, `rounded-radius-20`, `text-body`, `font-body`, `shadow-s`).
9
9
  * - `bloomThemeCss` / `bloomThemeBlock` — the Tailwind v4 `@theme` equivalent
10
10
  * for CSS-configured web apps.
11
+ * - `getPresetVars` / `buildSeedScopeVars` — the resolved token VALUES behind
12
+ * that alias layer, for a named preset or an arbitrary brand seed.
11
13
  * - The raw token maps (`FILL_ROLES`, `TEXT_ROLES`, `BORDER_ROLES`, `SPACING`,
12
14
  * `RADIUS`, `TYPOGRAPHY`, `SHADOW_BOX`) for direct programmatic use.
13
15
  * - `bloomShadowStyle` — platform-correct shadow style object (web box-shadow /
@@ -25,6 +27,25 @@ export type {
25
27
 
26
28
  export { bloomThemeCss, bloomThemeBlock } from './theme-css';
27
29
 
30
+ /* The resolved counterpart of `bloomThemeCss()`. That emits the alias layer
31
+ * (`--color-x: var(--x)`); these resolve `--x` itself, so a build script can
32
+ * write a static `:root` / `.dark` block and a prerendered page paints the real
33
+ * theme before `BloomThemeProvider` runs — instead of a hand-written palette
34
+ * that drifts from the preset it claims to mirror.
35
+ *
36
+ * `getPresetVars` returns the canonical tokens alone, which is all a document
37
+ * root needs. `buildSeedScopeVars` also returns the `--color-x` aliases, which a
38
+ * SCOPED block (a brand section, a forced-dark region) does need: a `--color-x`
39
+ * alias substitutes where it is declared, so overriding `--x` on a subtree does
40
+ * not move an alias declared at `:root`.
41
+ *
42
+ * Both are pure — no React, no react-native — so they run in a plain node/bun
43
+ * build script as well as in an app. */
44
+ export { getPresetVars } from '../theme/preset-vars';
45
+ export type { ExplicitAccents } from '../theme/preset-vars';
46
+ export { buildSeedScopeVars } from '../theme/color-scope/seed-scope';
47
+ export type { SeedScopeOptions } from '../theme/color-scope/seed-scope';
48
+
28
49
  export {
29
50
  FILL_ROLES,
30
51
  TEXT_ROLES,