@ggui-ai/project-config 0.1.0-rc.1
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/LICENSE +201 -0
- package/README.md +66 -0
- package/dist/discovery.d.ts +74 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +167 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/mcp-mount-discovery.d.ts +82 -0
- package/dist/mcp-mount-discovery.d.ts.map +1 -0
- package/dist/mcp-mount-discovery.js +226 -0
- package/dist/node.d.ts +69 -0
- package/dist/node.d.ts.map +1 -0
- package/dist/node.js +157 -0
- package/dist/primitive-discovery.d.ts +95 -0
- package/dist/primitive-discovery.d.ts.map +1 -0
- package/dist/primitive-discovery.js +281 -0
- package/dist/primitives-manifest.d.ts +106 -0
- package/dist/primitives-manifest.d.ts.map +1 -0
- package/dist/primitives-manifest.js +131 -0
- package/dist/schema.d.ts +520 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +556 -0
- package/dist/theme-loader.d.ts +104 -0
- package/dist/theme-loader.d.ts.map +1 -0
- package/dist/theme-loader.js +263 -0
- package/dist/theme.d.ts +311 -0
- package/dist/theme.d.ts.map +1 -0
- package/dist/theme.js +366 -0
- package/dist/ui-manifest.d.ts +95 -0
- package/dist/ui-manifest.d.ts.map +1 -0
- package/dist/ui-manifest.js +114 -0
- package/package.json +67 -0
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Theme loader — resolves `ggui.json#theme` into a validated
|
|
3
|
+
* `LoadedTheme` at boot.
|
|
4
|
+
*
|
|
5
|
+
* The flow:
|
|
6
|
+
*
|
|
7
|
+
* ggui.json.theme (undefined | string | { preset, mode, overrides } | { file, mode })
|
|
8
|
+
* → undefined → default light theme
|
|
9
|
+
* → string OR { preset } → registry lookup via @ggui-ai/design
|
|
10
|
+
* → { file } → readFile → JSON.parse → parseThemeDocument
|
|
11
|
+
*
|
|
12
|
+
* Non-throwing per the blueprint + primitive discovery precedent —
|
|
13
|
+
* one malformed theme should surface as a structured issue, not an
|
|
14
|
+
* exception. `ggui serve` escalates issues to a fatal exit before
|
|
15
|
+
* binding a port.
|
|
16
|
+
*
|
|
17
|
+
* ## cssVariables pre-rendering
|
|
18
|
+
*
|
|
19
|
+
* The loader pre-renders the `:root { --ggui-*: value; }` CSS block
|
|
20
|
+
* via `@ggui-ai/design/themes`: `parseTheme(id, DtcgTheme)` for the
|
|
21
|
+
* preset / default paths (full DTCG with canvas + motion tokens) and
|
|
22
|
+
* `generateCssVariables(ThemeDocument)` for the file path (the
|
|
23
|
+
* duck-typed walker accepts the plain DTCG document without requiring
|
|
24
|
+
* the strict {@link DtcgTheme} shape). Downstream consumers (console,
|
|
25
|
+
* render endpoint, MCP apps iframe) inject the pre-rendered string
|
|
26
|
+
* without re-walking the token tree.
|
|
27
|
+
*
|
|
28
|
+
* ## Mode handling
|
|
29
|
+
*
|
|
30
|
+
* `mode: 'light' | 'dark'` is propagated on every `LoadedTheme`
|
|
31
|
+
* variant so consumers can emit `color-scheme: dark` and pick the
|
|
32
|
+
* matching variant from the registry. For the file path, `mode`
|
|
33
|
+
* is metadata only — the file's tokens ARE the resolved theme,
|
|
34
|
+
* not a switch.
|
|
35
|
+
*/
|
|
36
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
37
|
+
import { dirname, isAbsolute, resolve } from 'node:path';
|
|
38
|
+
import { generateCssVariables, getRawTheme, getTheme, lightTheme, parseTheme, } from '@ggui-ai/design/themes';
|
|
39
|
+
import { parseThemeDocument } from './theme.js';
|
|
40
|
+
/**
|
|
41
|
+
* Load the theme declared in `ggui.json#theme`, or fall back to the
|
|
42
|
+
* shipped default when the field is absent.
|
|
43
|
+
*
|
|
44
|
+
* Non-throwing — single-issue failure mode returned as a tagged
|
|
45
|
+
* result. Throws only for programmer errors (non-absolute
|
|
46
|
+
* `projectRoot`), matching the other discovery helpers.
|
|
47
|
+
*/
|
|
48
|
+
export function loadTheme(options) {
|
|
49
|
+
const { projectRoot, manifest } = options;
|
|
50
|
+
if (!isAbsolute(projectRoot)) {
|
|
51
|
+
throw new Error(`loadTheme: projectRoot must be absolute, got ${projectRoot}`);
|
|
52
|
+
}
|
|
53
|
+
const themeConfig = manifest.theme;
|
|
54
|
+
// ── Default path (no `theme` declared) ──────────────────────────
|
|
55
|
+
if (themeConfig === undefined) {
|
|
56
|
+
return {
|
|
57
|
+
ok: true,
|
|
58
|
+
theme: {
|
|
59
|
+
source: 'default',
|
|
60
|
+
mode: 'light',
|
|
61
|
+
document: lightTheme,
|
|
62
|
+
cssVariables: parseTheme('default', lightTheme).cssVariables,
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
// ── String shorthand: preset id ─────────────────────────────────
|
|
67
|
+
if (typeof themeConfig === 'string') {
|
|
68
|
+
return loadPreset(themeConfig, 'light', undefined);
|
|
69
|
+
}
|
|
70
|
+
// ── File path ───────────────────────────────────────────────────
|
|
71
|
+
if ('file' in themeConfig) {
|
|
72
|
+
return loadFile(themeConfig.file, themeConfig.mode ?? 'light', projectRoot);
|
|
73
|
+
}
|
|
74
|
+
// ── Preset object ───────────────────────────────────────────────
|
|
75
|
+
return loadPreset(themeConfig.preset, themeConfig.mode ?? 'light', themeConfig.overrides);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Resolve a registered preset (with optional mode + overrides) into
|
|
79
|
+
* a `LoadedTheme`. Returns an issue when the preset id is
|
|
80
|
+
* unregistered.
|
|
81
|
+
*
|
|
82
|
+
* When `overrides` is supplied, each entry is applied as a deep-set
|
|
83
|
+
* onto the resolved raw `DtcgTheme` BEFORE CSS emission. Unknown
|
|
84
|
+
* dot-paths are silently dropped — the console token editor mints
|
|
85
|
+
* valid keys and an accidentally-stale override should not fail
|
|
86
|
+
* manifest parse.
|
|
87
|
+
*/
|
|
88
|
+
function loadPreset(preset, mode, overrides) {
|
|
89
|
+
// Resolve the raw token tree first so we can layer overrides
|
|
90
|
+
// before parseTheme walks the leaves.
|
|
91
|
+
const raw = getRawTheme(preset, mode);
|
|
92
|
+
if (!raw) {
|
|
93
|
+
return {
|
|
94
|
+
ok: false,
|
|
95
|
+
issue: {
|
|
96
|
+
path: preset,
|
|
97
|
+
message: `Theme preset "${preset}" is not registered. ` +
|
|
98
|
+
`Use one of the registered ids (e.g. "ggui", "claudic", ` +
|
|
99
|
+
`"premium-zen") or switch to { file: "./..." }.`,
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
// No overrides: hand off to the registry's parser directly so we
|
|
104
|
+
// share its cache.
|
|
105
|
+
if (!overrides || Object.keys(overrides).length === 0) {
|
|
106
|
+
const parsed = getTheme(preset, mode);
|
|
107
|
+
if (!parsed) {
|
|
108
|
+
// Should not happen — getRawTheme succeeded above. Defensive.
|
|
109
|
+
return {
|
|
110
|
+
ok: false,
|
|
111
|
+
issue: {
|
|
112
|
+
path: preset,
|
|
113
|
+
message: `Theme preset "${preset}" parsed unexpectedly empty.`,
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
ok: true,
|
|
119
|
+
theme: {
|
|
120
|
+
source: 'preset',
|
|
121
|
+
preset,
|
|
122
|
+
mode,
|
|
123
|
+
document: raw,
|
|
124
|
+
cssVariables: parsed.cssVariables,
|
|
125
|
+
},
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
// With overrides: clone the raw tree, deep-set each leaf's $value,
|
|
129
|
+
// then re-parse. We bypass the registry's cache because the
|
|
130
|
+
// override set is per-call and would pollute it.
|
|
131
|
+
const mutated = applyOverrides(raw, overrides);
|
|
132
|
+
const parsed = parseTheme(preset, mutated);
|
|
133
|
+
return {
|
|
134
|
+
ok: true,
|
|
135
|
+
theme: {
|
|
136
|
+
source: 'preset',
|
|
137
|
+
preset,
|
|
138
|
+
mode,
|
|
139
|
+
overrides,
|
|
140
|
+
document: mutated,
|
|
141
|
+
cssVariables: parsed.cssVariables,
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Load a DTCG JSON file from a project-relative path. Existing
|
|
147
|
+
* file-loading flow, refactored out of `loadTheme` so the entry
|
|
148
|
+
* point stays small.
|
|
149
|
+
*/
|
|
150
|
+
function loadFile(filePath, mode, projectRoot) {
|
|
151
|
+
const absolutePath = isAbsolute(filePath)
|
|
152
|
+
? filePath
|
|
153
|
+
: resolve(projectRoot, filePath);
|
|
154
|
+
if (!existsSync(absolutePath)) {
|
|
155
|
+
return {
|
|
156
|
+
ok: false,
|
|
157
|
+
issue: {
|
|
158
|
+
path: filePath,
|
|
159
|
+
message: `Declared theme file not found. Resolved to ${absolutePath}; ` +
|
|
160
|
+
`check the path is correct relative to ggui.json.`,
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
let raw;
|
|
165
|
+
try {
|
|
166
|
+
raw = readFileSync(absolutePath, 'utf-8');
|
|
167
|
+
}
|
|
168
|
+
catch (cause) {
|
|
169
|
+
return {
|
|
170
|
+
ok: false,
|
|
171
|
+
issue: {
|
|
172
|
+
path: absolutePath,
|
|
173
|
+
message: `Could not read theme file: ${errorMessage(cause)}`,
|
|
174
|
+
cause,
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
let decoded;
|
|
179
|
+
try {
|
|
180
|
+
decoded = JSON.parse(raw);
|
|
181
|
+
}
|
|
182
|
+
catch (cause) {
|
|
183
|
+
return {
|
|
184
|
+
ok: false,
|
|
185
|
+
issue: {
|
|
186
|
+
path: absolutePath,
|
|
187
|
+
message: `Theme file is not valid JSON: ${errorMessage(cause)}`,
|
|
188
|
+
cause,
|
|
189
|
+
},
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
let document;
|
|
193
|
+
try {
|
|
194
|
+
document = parseThemeDocument(decoded);
|
|
195
|
+
}
|
|
196
|
+
catch (cause) {
|
|
197
|
+
return {
|
|
198
|
+
ok: false,
|
|
199
|
+
issue: {
|
|
200
|
+
path: absolutePath,
|
|
201
|
+
message: `Theme file failed schema validation: ${errorMessage(cause)}`,
|
|
202
|
+
cause,
|
|
203
|
+
},
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
return {
|
|
207
|
+
ok: true,
|
|
208
|
+
theme: {
|
|
209
|
+
source: 'file',
|
|
210
|
+
path: absolutePath,
|
|
211
|
+
mode,
|
|
212
|
+
document,
|
|
213
|
+
cssVariables: generateCssVariables(document),
|
|
214
|
+
},
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Apply flat dot-path overrides onto a copy of the raw `DtcgTheme`
|
|
219
|
+
* tree. Each override key (`color.primary.500`) walks into the
|
|
220
|
+
* tree; only leaves that already exist as `{ $value, $type }` token
|
|
221
|
+
* objects are mutated — anything else is silently ignored.
|
|
222
|
+
*
|
|
223
|
+
* Returns a deep-cloned tree so the source registry entry is not
|
|
224
|
+
* mutated (the registry's `parsedCache` would otherwise serve stale
|
|
225
|
+
* CSS to subsequent calls).
|
|
226
|
+
*/
|
|
227
|
+
function applyOverrides(source, overrides) {
|
|
228
|
+
// Structured clone covers the nested DTCG token tree cleanly —
|
|
229
|
+
// the tree is plain JSON-shaped data (no functions, no Dates).
|
|
230
|
+
const cloned = structuredClone(source);
|
|
231
|
+
for (const [path, value] of Object.entries(overrides)) {
|
|
232
|
+
const segments = path.split('.');
|
|
233
|
+
let cursor = cloned;
|
|
234
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
235
|
+
if (cursor === null || typeof cursor !== 'object')
|
|
236
|
+
break;
|
|
237
|
+
cursor = cursor[segments[i]];
|
|
238
|
+
}
|
|
239
|
+
if (cursor === null || typeof cursor !== 'object')
|
|
240
|
+
continue;
|
|
241
|
+
const leafKey = segments[segments.length - 1];
|
|
242
|
+
const leaf = cursor[leafKey];
|
|
243
|
+
if (leaf !== null &&
|
|
244
|
+
typeof leaf === 'object' &&
|
|
245
|
+
'$value' in leaf &&
|
|
246
|
+
'$type' in leaf) {
|
|
247
|
+
// Mutate $value only — keep $type and any $description intact.
|
|
248
|
+
leaf.$value = value;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
return cloned;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Convenience wrapper for the "I have a `ggui.json` path" flow.
|
|
255
|
+
* Resolves the project root from the manifest path.
|
|
256
|
+
*/
|
|
257
|
+
export function loadThemeFromGguiJsonPath(manifestPath, manifest) {
|
|
258
|
+
const projectRoot = dirname(resolve(manifestPath));
|
|
259
|
+
return loadTheme({ projectRoot, manifest });
|
|
260
|
+
}
|
|
261
|
+
function errorMessage(cause) {
|
|
262
|
+
return cause instanceof Error ? cause.message : String(cause);
|
|
263
|
+
}
|
package/dist/theme.d.ts
ADDED
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ggui.json#theme` → plain DTCG JSON document.
|
|
3
|
+
*
|
|
4
|
+
* The theme file is a plain JSON document matching the Design Tokens
|
|
5
|
+
* Community Group (DTCG) spec. It is one of the open file-format
|
|
6
|
+
* surfaces in the ggui manifest model, alongside
|
|
7
|
+
* `ggui.primitives.json` and `ggui.ui.json`.
|
|
8
|
+
*
|
|
9
|
+
* **Shape parity with the internal `DtcgTheme`.** This v1 schema is
|
|
10
|
+
* deliberately the same shape as `@ggui-ai/design`'s canonical
|
|
11
|
+
* {@link DtcgTheme} — `color`/`font`/`spacing`/`shape`/`motion`/
|
|
12
|
+
* `canvas`/`accessibility`/`zIndex` — so an authored `theme.json`
|
|
13
|
+
* uses the same vocabulary the curated registry themes (light/dark/
|
|
14
|
+
* premium-*) use. Previously this schema was Tailwind-style flat
|
|
15
|
+
* (`typography`/`radius`/`shadow` at root); the v1 schema now mirrors
|
|
16
|
+
* the internal shape to remove the divergence.
|
|
17
|
+
*
|
|
18
|
+
* **External-tool compatibility.** External tooling (Figma Tokens,
|
|
19
|
+
* Style Dictionary, Tokens Studio) commonly emits only a subset of
|
|
20
|
+
* the canonical shape. Only the original required groups (`color`,
|
|
21
|
+
* `font`, `spacing`, `shape`) stay required; `motion`, `canvas`,
|
|
22
|
+
* `accessibility`, `zIndex`, and the new DTCG metadata fields
|
|
23
|
+
* (`$name`, `$description`, `$metadata`) are all OPTIONAL so tools
|
|
24
|
+
* that only emit colors + dimensions still parse cleanly.
|
|
25
|
+
*
|
|
26
|
+
* **BREAKING for old `theme.json` files.** Authors who hand-wrote a
|
|
27
|
+
* `theme.json` against the pre-rc schema must rename:
|
|
28
|
+
*
|
|
29
|
+
* - `typography.fontFamily` → `font.family`
|
|
30
|
+
* - `typography.fontSize` → `font.size`
|
|
31
|
+
* - `typography.fontWeight` → `font.weight`
|
|
32
|
+
* - `typography.lineHeight` → `font.lineHeight`
|
|
33
|
+
* - top-level `radius` → `shape.radius`
|
|
34
|
+
* - top-level `shadow` → `shape.shadow`
|
|
35
|
+
* - top-level `duration` → `motion.duration`
|
|
36
|
+
* - top-level `transition` → `motion.transition`
|
|
37
|
+
*
|
|
38
|
+
* Plus: under `font.family`, `sans` is the only required sub-token
|
|
39
|
+
* (was previously freeform); other family slots (`mono`, …) are
|
|
40
|
+
* optional. The font-family record itself stays open so additional
|
|
41
|
+
* named families parse without a schema change.
|
|
42
|
+
*
|
|
43
|
+
* **Ownership boundary:**
|
|
44
|
+
*
|
|
45
|
+
* - *Where* the theme lives → `ggui.json#theme` (pointer string).
|
|
46
|
+
* - *What* the theme file looks like → this module's schema.
|
|
47
|
+
* - *How* DTCG tokens become CSS variables → `@ggui-ai/design`'s
|
|
48
|
+
* `generateCssVariables` (stays over there; this schema does not
|
|
49
|
+
* emit). The duck-typed walker accepts any DTCG-shaped tree, so
|
|
50
|
+
* the new nested groups (`font.size`, `shape.radius`, …) walk
|
|
51
|
+
* into `--ggui-font-size-md`/`--ggui-shape-radius-md` CSS vars
|
|
52
|
+
* without code changes.
|
|
53
|
+
* - *Built-in default* when `theme` is absent → `@ggui-ai/design`'s
|
|
54
|
+
* shipped `lightTheme`.
|
|
55
|
+
*
|
|
56
|
+
* **Extending rules:**
|
|
57
|
+
*
|
|
58
|
+
* 1. Additive only within `schema: '1'`. New optional fields must
|
|
59
|
+
* default to no-op behaviour so older tooling ignores them.
|
|
60
|
+
* 2. Framework-neutral + host-neutral. No vendor names in enum
|
|
61
|
+
* values, no build-pipeline fields. (`canvas` IS hosting-
|
|
62
|
+
* vendor vocabulary; it is opt-in via the optional field.)
|
|
63
|
+
* 3. Root and per-group objects are strict — unknown keys fail
|
|
64
|
+
* parse. Same discipline as `ggui.json`, `ggui.ui.json`, and
|
|
65
|
+
* `ggui.primitives.json`.
|
|
66
|
+
*
|
|
67
|
+
* **Strictness tradeoff:**
|
|
68
|
+
*
|
|
69
|
+
* Individual DTCG token leaves are validated with a discriminated
|
|
70
|
+
* union over `$type` (color / dimension / fontFamily / fontWeight /
|
|
71
|
+
* shadow / duration / cubicBezier / transition / number). Each
|
|
72
|
+
* variant validates its `$value` shape. `$description` is accepted
|
|
73
|
+
* everywhere as a free-form docstring. Token leaves under newer
|
|
74
|
+
* groups (`canvas`, `accessibility`, `zIndex`) accept a slightly
|
|
75
|
+
* wider token vocabulary because external tools sometimes encode
|
|
76
|
+
* scalar/array values with permissive `$type` strings (`string`,
|
|
77
|
+
* `array`, …); the schema accepts those without enumerating every
|
|
78
|
+
* possible spelling.
|
|
79
|
+
*/
|
|
80
|
+
import { z } from 'zod';
|
|
81
|
+
/**
|
|
82
|
+
* Plain DTCG theme document v1. Required groups (`color`, `font`,
|
|
83
|
+
* `spacing`, `shape`) map 1:1 to `@ggui-ai/design`'s
|
|
84
|
+
* `generateCssVariables` walker targets — anything less would mean
|
|
85
|
+
* a partial CSS output worse than falling back to the shipped
|
|
86
|
+
* default. Optional groups (`motion`, `canvas`, `accessibility`,
|
|
87
|
+
* `zIndex`) are the well-known DTCG additives; present → emitted,
|
|
88
|
+
* absent → the design system's built-in fallbacks apply.
|
|
89
|
+
*
|
|
90
|
+
* `$name`, `$description`, and `$metadata` are accepted as optional
|
|
91
|
+
* DTCG-standard metadata. They round-trip cleanly to/from the
|
|
92
|
+
* internal `DtcgTheme` shape but external tools don't always emit
|
|
93
|
+
* them.
|
|
94
|
+
*
|
|
95
|
+
* Strict root: unknown top-level keys fail parse. `$schema`,
|
|
96
|
+
* `$version`, `$name`, `$description`, `$metadata` are all
|
|
97
|
+
* allow-listed (DTCG metadata); anything else is a typo. Additive
|
|
98
|
+
* slices add new fields here under `schema: '1'`.
|
|
99
|
+
*/
|
|
100
|
+
export declare const ThemeDocumentV1: z.ZodObject<{
|
|
101
|
+
/** Optional DTCG spec URL. Not validated — the spec hasn't frozen
|
|
102
|
+
* a canonical URL and hand-authored themes often omit it. */
|
|
103
|
+
$schema: z.ZodOptional<z.ZodString>;
|
|
104
|
+
/** Optional author-declared version. Not validated — string-form. */
|
|
105
|
+
$version: z.ZodOptional<z.ZodString>;
|
|
106
|
+
/** Optional human-readable theme name. DTCG metadata; mirrors
|
|
107
|
+
* `DtcgTheme.$name`. */
|
|
108
|
+
$name: z.ZodOptional<z.ZodString>;
|
|
109
|
+
/** Optional human-readable theme description. DTCG metadata;
|
|
110
|
+
* mirrors `DtcgTheme.$description`. */
|
|
111
|
+
$description: z.ZodOptional<z.ZodString>;
|
|
112
|
+
/** Optional metadata bag — font fallback, hosting-philosophy notes,
|
|
113
|
+
* etc. Mirrors `DtcgTheme.$metadata`. */
|
|
114
|
+
$metadata: z.ZodOptional<z.ZodObject<{
|
|
115
|
+
font: z.ZodOptional<z.ZodString>;
|
|
116
|
+
fontUrl: z.ZodOptional<z.ZodString>;
|
|
117
|
+
philosophy: z.ZodOptional<z.ZodString>;
|
|
118
|
+
}, z.core.$strict>>;
|
|
119
|
+
/** Color tokens — palettes + semantic roles. Required. */
|
|
120
|
+
color: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodObject<{
|
|
121
|
+
$type: z.ZodLiteral<"color">;
|
|
122
|
+
$value: z.ZodString;
|
|
123
|
+
$description: z.ZodOptional<z.ZodString>;
|
|
124
|
+
}, z.core.$strict>, z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
125
|
+
$type: z.ZodLiteral<"color">;
|
|
126
|
+
$value: z.ZodString;
|
|
127
|
+
$description: z.ZodOptional<z.ZodString>;
|
|
128
|
+
}, z.core.$strict>>]>>;
|
|
129
|
+
/** Spacing scale. Required. */
|
|
130
|
+
spacing: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
131
|
+
$type: z.ZodLiteral<"dimension">;
|
|
132
|
+
$value: z.ZodString;
|
|
133
|
+
$description: z.ZodOptional<z.ZodString>;
|
|
134
|
+
}, z.core.$strict>>;
|
|
135
|
+
/** Font tokens — `family` / `size` / `weight` / `lineHeight`. Required. */
|
|
136
|
+
font: z.ZodObject<{
|
|
137
|
+
family: z.ZodIntersection<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
138
|
+
$type: z.ZodLiteral<"fontFamily">;
|
|
139
|
+
$value: z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>;
|
|
140
|
+
$description: z.ZodOptional<z.ZodString>;
|
|
141
|
+
}, z.core.$strict>>, z.ZodObject<{
|
|
142
|
+
sans: z.ZodObject<{
|
|
143
|
+
$type: z.ZodLiteral<"fontFamily">;
|
|
144
|
+
$value: z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>;
|
|
145
|
+
$description: z.ZodOptional<z.ZodString>;
|
|
146
|
+
}, z.core.$strict>;
|
|
147
|
+
}, z.core.$strip>>;
|
|
148
|
+
size: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
149
|
+
$type: z.ZodLiteral<"dimension">;
|
|
150
|
+
$value: z.ZodString;
|
|
151
|
+
$description: z.ZodOptional<z.ZodString>;
|
|
152
|
+
}, z.core.$strict>>;
|
|
153
|
+
weight: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
154
|
+
$type: z.ZodLiteral<"fontWeight">;
|
|
155
|
+
$value: z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>;
|
|
156
|
+
$description: z.ZodOptional<z.ZodString>;
|
|
157
|
+
}, z.core.$strict>>;
|
|
158
|
+
lineHeight: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodObject<{
|
|
159
|
+
$type: z.ZodLiteral<"number">;
|
|
160
|
+
$value: z.ZodNumber;
|
|
161
|
+
$description: z.ZodOptional<z.ZodString>;
|
|
162
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
163
|
+
$type: z.ZodLiteral<"dimension">;
|
|
164
|
+
$value: z.ZodString;
|
|
165
|
+
$description: z.ZodOptional<z.ZodString>;
|
|
166
|
+
}, z.core.$strict>]>>;
|
|
167
|
+
}, z.core.$strict>;
|
|
168
|
+
/** Shape tokens — `radius` + `shadow`. Required. */
|
|
169
|
+
shape: z.ZodObject<{
|
|
170
|
+
radius: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
171
|
+
$type: z.ZodLiteral<"dimension">;
|
|
172
|
+
$value: z.ZodString;
|
|
173
|
+
$description: z.ZodOptional<z.ZodString>;
|
|
174
|
+
}, z.core.$strict>>;
|
|
175
|
+
shadow: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
176
|
+
$type: z.ZodLiteral<"shadow">;
|
|
177
|
+
$value: z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
178
|
+
offsetX: z.ZodString;
|
|
179
|
+
offsetY: z.ZodString;
|
|
180
|
+
blur: z.ZodString;
|
|
181
|
+
spread: z.ZodString;
|
|
182
|
+
color: z.ZodString;
|
|
183
|
+
}, z.core.$strict>]>;
|
|
184
|
+
$description: z.ZodOptional<z.ZodString>;
|
|
185
|
+
}, z.core.$strict>>;
|
|
186
|
+
}, z.core.$strict>;
|
|
187
|
+
/** Motion tokens — `duration` + `transition` (required sub-records),
|
|
188
|
+
* `easing` + `keyframes` (optional sub-records). Optional. */
|
|
189
|
+
motion: z.ZodOptional<z.ZodObject<{
|
|
190
|
+
duration: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
191
|
+
$type: z.ZodLiteral<"duration">;
|
|
192
|
+
$value: z.ZodString;
|
|
193
|
+
$description: z.ZodOptional<z.ZodString>;
|
|
194
|
+
}, z.core.$strict>>;
|
|
195
|
+
easing: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
196
|
+
$type: z.ZodLiteral<"cubicBezier">;
|
|
197
|
+
$value: z.ZodString;
|
|
198
|
+
$description: z.ZodOptional<z.ZodString>;
|
|
199
|
+
}, z.core.$strict>>>;
|
|
200
|
+
transition: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
201
|
+
$type: z.ZodLiteral<"transition">;
|
|
202
|
+
$value: z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
203
|
+
duration: z.ZodString;
|
|
204
|
+
timingFunction: z.ZodString;
|
|
205
|
+
property: z.ZodOptional<z.ZodString>;
|
|
206
|
+
}, z.core.$strict>]>;
|
|
207
|
+
$description: z.ZodOptional<z.ZodString>;
|
|
208
|
+
}, z.core.$strict>>;
|
|
209
|
+
keyframes: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
210
|
+
$type: z.ZodString;
|
|
211
|
+
$value: z.ZodUnknown;
|
|
212
|
+
$description: z.ZodOptional<z.ZodString>;
|
|
213
|
+
}, z.core.$strict>>>;
|
|
214
|
+
}, z.core.$strict>>;
|
|
215
|
+
/** Canvas configuration for the GenerativeCanvas background.
|
|
216
|
+
* Optional — external tools won't emit this. */
|
|
217
|
+
canvas: z.ZodOptional<z.ZodObject<{
|
|
218
|
+
mode: z.ZodObject<{
|
|
219
|
+
$type: z.ZodString;
|
|
220
|
+
$value: z.ZodUnknown;
|
|
221
|
+
$description: z.ZodOptional<z.ZodString>;
|
|
222
|
+
}, z.core.$strict>;
|
|
223
|
+
speed: z.ZodObject<{
|
|
224
|
+
$type: z.ZodString;
|
|
225
|
+
$value: z.ZodUnknown;
|
|
226
|
+
$description: z.ZodOptional<z.ZodString>;
|
|
227
|
+
}, z.core.$strict>;
|
|
228
|
+
colors: z.ZodObject<{
|
|
229
|
+
$type: z.ZodString;
|
|
230
|
+
$value: z.ZodUnknown;
|
|
231
|
+
$description: z.ZodOptional<z.ZodString>;
|
|
232
|
+
}, z.core.$strict>;
|
|
233
|
+
background: z.ZodObject<{
|
|
234
|
+
$type: z.ZodString;
|
|
235
|
+
$value: z.ZodUnknown;
|
|
236
|
+
$description: z.ZodOptional<z.ZodString>;
|
|
237
|
+
}, z.core.$strict>;
|
|
238
|
+
}, z.core.$strict>>;
|
|
239
|
+
/** Accessibility tokens (focus ring, reduced motion, high contrast).
|
|
240
|
+
* Optional. */
|
|
241
|
+
accessibility: z.ZodOptional<z.ZodObject<{
|
|
242
|
+
focusRing: z.ZodOptional<z.ZodObject<{
|
|
243
|
+
color: z.ZodObject<{
|
|
244
|
+
$type: z.ZodLiteral<"color">;
|
|
245
|
+
$value: z.ZodString;
|
|
246
|
+
$description: z.ZodOptional<z.ZodString>;
|
|
247
|
+
}, z.core.$strict>;
|
|
248
|
+
width: z.ZodObject<{
|
|
249
|
+
$type: z.ZodLiteral<"dimension">;
|
|
250
|
+
$value: z.ZodString;
|
|
251
|
+
$description: z.ZodOptional<z.ZodString>;
|
|
252
|
+
}, z.core.$strict>;
|
|
253
|
+
offset: z.ZodObject<{
|
|
254
|
+
$type: z.ZodLiteral<"dimension">;
|
|
255
|
+
$value: z.ZodString;
|
|
256
|
+
$description: z.ZodOptional<z.ZodString>;
|
|
257
|
+
}, z.core.$strict>;
|
|
258
|
+
}, z.core.$strict>>;
|
|
259
|
+
reducedMotion: z.ZodOptional<z.ZodObject<{
|
|
260
|
+
duration: z.ZodObject<{
|
|
261
|
+
$type: z.ZodLiteral<"duration">;
|
|
262
|
+
$value: z.ZodString;
|
|
263
|
+
$description: z.ZodOptional<z.ZodString>;
|
|
264
|
+
}, z.core.$strict>;
|
|
265
|
+
}, z.core.$strict>>;
|
|
266
|
+
highContrast: z.ZodOptional<z.ZodObject<{
|
|
267
|
+
borderWidth: z.ZodObject<{
|
|
268
|
+
$type: z.ZodLiteral<"dimension">;
|
|
269
|
+
$value: z.ZodString;
|
|
270
|
+
$description: z.ZodOptional<z.ZodString>;
|
|
271
|
+
}, z.core.$strict>;
|
|
272
|
+
textColor: z.ZodObject<{
|
|
273
|
+
$type: z.ZodLiteral<"color">;
|
|
274
|
+
$value: z.ZodString;
|
|
275
|
+
$description: z.ZodOptional<z.ZodString>;
|
|
276
|
+
}, z.core.$strict>;
|
|
277
|
+
backgroundColor: z.ZodObject<{
|
|
278
|
+
$type: z.ZodLiteral<"color">;
|
|
279
|
+
$value: z.ZodString;
|
|
280
|
+
$description: z.ZodOptional<z.ZodString>;
|
|
281
|
+
}, z.core.$strict>;
|
|
282
|
+
linkColor: z.ZodObject<{
|
|
283
|
+
$type: z.ZodLiteral<"color">;
|
|
284
|
+
$value: z.ZodString;
|
|
285
|
+
$description: z.ZodOptional<z.ZodString>;
|
|
286
|
+
}, z.core.$strict>;
|
|
287
|
+
}, z.core.$strict>>;
|
|
288
|
+
}, z.core.$strict>>;
|
|
289
|
+
/** Z-index scale. Optional. */
|
|
290
|
+
zIndex: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
291
|
+
$type: z.ZodLiteral<"number">;
|
|
292
|
+
$value: z.ZodNumber;
|
|
293
|
+
$description: z.ZodOptional<z.ZodString>;
|
|
294
|
+
}, z.core.$strict>>>;
|
|
295
|
+
}, z.core.$strict>;
|
|
296
|
+
/** Static TypeScript type derived from the v1 schema. */
|
|
297
|
+
export type ThemeDocumentV1 = z.infer<typeof ThemeDocumentV1>;
|
|
298
|
+
/** Canonical type alias used everywhere else. */
|
|
299
|
+
export type ThemeDocument = ThemeDocumentV1;
|
|
300
|
+
/**
|
|
301
|
+
* Parse a raw JSON value into a validated {@link ThemeDocument}.
|
|
302
|
+
* Throws a `ZodError` with human-readable issues on invalid input.
|
|
303
|
+
*/
|
|
304
|
+
export declare function parseThemeDocument(raw: unknown): ThemeDocument;
|
|
305
|
+
/**
|
|
306
|
+
* Safe-parse variant — returns a discriminated `z.safeParse` result.
|
|
307
|
+
* Prefer this inside CLI tooling where you want to render the issue
|
|
308
|
+
* list without try/catch.
|
|
309
|
+
*/
|
|
310
|
+
export declare function safeParseThemeDocument(raw: unknown): ReturnType<typeof ThemeDocumentV1.safeParse>;
|
|
311
|
+
//# sourceMappingURL=theme.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../src/theme.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8EG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA2PxB;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,eAAe;IAC1B;kEAC8D;;IAG9D,qEAAqE;;IAGrE;6BACyB;;IAGzB;4CACwC;;IAGxC;8CAC0C;;;;;;IAG1C,0DAA0D;;;;;;;;;;IAG1D,+BAA+B;;;;;;IAG/B,2EAA2E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAG3E,oDAAoD;;;;;;;;;;;;;;;;;;;IAGpD;mEAC+D;;;;;;;;;;;;;;;;;;;;;;;;;;;IAG/D;qDACiD;;;;;;;;;;;;;;;;;;;;;;;IAGjD;oBACgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAGhB,+BAA+B;;;;;;kBAE/B,CAAC;AAEH,yDAAyD;AACzD,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAE9D,iDAAiD;AACjD,MAAM,MAAM,aAAa,GAAG,eAAe,CAAC;AAE5C;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,aAAa,CAE9D;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,OAAO,GACX,UAAU,CAAC,OAAO,eAAe,CAAC,SAAS,CAAC,CAE9C"}
|