@pitlane/theme 0.2.0 → 0.3.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.
- package/CHANGELOG.md +119 -0
- package/README.md +66 -28
- package/dist/default.d.mts +605 -0
- package/dist/default.mjs +584 -0
- package/dist/dtcg.d.mts +127 -0
- package/dist/dtcg.mjs +468 -0
- package/dist/index.d.mts +76 -348
- package/dist/index.mjs +54 -458
- package/dist/schema-CRP607Pg.d.mts +320 -0
- package/dist/schema-JmfNnMzr.mjs +572 -0
- package/dist/schema.d.mts +2 -0
- package/dist/schema.mjs +2 -0
- package/dist/theme-CMaWrQJ5.mjs +237 -0
- package/dist/theme-Ck-4suI4.d.mts +278 -0
- package/package.json +58 -48
|
@@ -0,0 +1,572 @@
|
|
|
1
|
+
import { createSchema, fail } from "remix/data-schema";
|
|
2
|
+
//#region src/tokens.ts
|
|
3
|
+
/**
|
|
4
|
+
* The error {@link createTheme} throws for every structural failure:
|
|
5
|
+
* one problem, one sentence.
|
|
6
|
+
*
|
|
7
|
+
* | Failure | Message shape |
|
|
8
|
+
* | --- | --- |
|
|
9
|
+
* | No schema entry | `"space.md" has no schema entry` |
|
|
10
|
+
* | Unknown reference | `"color.bg" references unknown token "color.nope"` |
|
|
11
|
+
* | Reference type mismatch | `"color.bg" references "space.md" of type "dimension" where "color" is required` |
|
|
12
|
+
* | Reference to an untyped token | `"color.bg" references untyped token "animate.spin"` |
|
|
13
|
+
* | Reference cycle | `Reference cycle: color.a → color.b → color.a` |
|
|
14
|
+
* | Variable collision | `Tokens "a.b" and "a-b" both produce the CSS variable --a-b` |
|
|
15
|
+
* | Reserved characters | `Token or group name "a.b" contains characters reserved by references (".", "{", "}")` |
|
|
16
|
+
* | Empty identifier | `Token path segment "!!" produces an empty CSS identifier` |
|
|
17
|
+
* | Unknown mode token | `Mode "dark" overrides unknown token "color.nope"` |
|
|
18
|
+
*
|
|
19
|
+
* Bad token *values* raise `ValidationError` from `remix/data-schema`
|
|
20
|
+
* instead, because there may be several and each carries its own path.
|
|
21
|
+
*
|
|
22
|
+
* @see {@link createTheme}
|
|
23
|
+
*/
|
|
24
|
+
var ThemeError = class extends Error {
|
|
25
|
+
name = "ThemeError";
|
|
26
|
+
};
|
|
27
|
+
const VAR_RE = /^var\((--[a-z0-9-]+)\)$/;
|
|
28
|
+
const EMBEDDED_VAR_RE = /var\((--[a-z0-9-]+)\)/g;
|
|
29
|
+
/**
|
|
30
|
+
* Rejects a value carrying a `{path.to.token}` reference. Braces are never
|
|
31
|
+
* valid in a CSS value, so one can only be a reference left behind from the
|
|
32
|
+
* format this package used before 0.3.0, and passing it through would put
|
|
33
|
+
* `{color.white}` in the stylesheet where a color belongs.
|
|
34
|
+
*
|
|
35
|
+
* @internal
|
|
36
|
+
*/
|
|
37
|
+
function assertNoStringReference(value, key) {
|
|
38
|
+
if (typeof value !== "string" || !value.includes("{")) return;
|
|
39
|
+
let match = /\{([^{}]+)\}/.exec(value);
|
|
40
|
+
if (match === null) return;
|
|
41
|
+
throw new ThemeError(`"${key}" contains the reference "{${match[1]}}", which is no longer a value. Reference a token by property access in an extend layer: .extend(base => ({ tokens: { … base.${match[1]} … } }))`);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* The token a whole-value `var()` reference names, or `null` when the value is
|
|
45
|
+
* not one. A reference is written as a property access on the layer below, and
|
|
46
|
+
* an accessor leaf is a `var()` string, so this is what a reference looks like
|
|
47
|
+
* by the time the compiler sees it.
|
|
48
|
+
*
|
|
49
|
+
* @internal
|
|
50
|
+
*/
|
|
51
|
+
function referenceTarget(value) {
|
|
52
|
+
if (typeof value !== "string") return null;
|
|
53
|
+
let match = VAR_RE.exec(value);
|
|
54
|
+
return match ? match[1] : null;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Every `var()` a value mentions, including inside a larger string. A composite
|
|
58
|
+
* is authored as CSS text, so a reference interpolated into a shadow or a
|
|
59
|
+
* transition shows up here rather than as the whole value.
|
|
60
|
+
*
|
|
61
|
+
* @internal
|
|
62
|
+
*/
|
|
63
|
+
function mentionedVarNames(value) {
|
|
64
|
+
if (typeof value !== "string" || !value.includes("var(")) return [];
|
|
65
|
+
return [...value.matchAll(EMBEDDED_VAR_RE)].map((match) => match[1]);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Kebab-cases one path segment for a CSS variable name. Throws when
|
|
69
|
+
* the segment reduces to an empty identifier.
|
|
70
|
+
*
|
|
71
|
+
* @internal
|
|
72
|
+
*/
|
|
73
|
+
function kebabSegment(segment) {
|
|
74
|
+
let kebab = segment.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
75
|
+
if (!kebab) throw new ThemeError(`Token path segment "${segment}" produces an empty CSS identifier`);
|
|
76
|
+
return kebab;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Walks the token tree and the schema tree together, in document
|
|
80
|
+
* order, into one list of tagged entries. Rejects a token with no
|
|
81
|
+
* schema entry, a reserved character in a name, and two tokens whose
|
|
82
|
+
* paths collide after kebab-casing.
|
|
83
|
+
*
|
|
84
|
+
* @internal
|
|
85
|
+
*/
|
|
86
|
+
function collectTokens(tokens, schema) {
|
|
87
|
+
let entries = [];
|
|
88
|
+
walk(tokens, schema, void 0, [], entries, /* @__PURE__ */ new Map());
|
|
89
|
+
linkVarReferences(entries);
|
|
90
|
+
return entries;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Links a whole-value `var()` to the token it names, so it is type-checked,
|
|
94
|
+
* resolvable by `raw`, and visible to `select`. The link is a second pass
|
|
95
|
+
* because a layer may reference a token declared after it.
|
|
96
|
+
*
|
|
97
|
+
* A `var()` naming something this theme does not declare is left alone: it may
|
|
98
|
+
* be a custom property the application defines elsewhere.
|
|
99
|
+
*/
|
|
100
|
+
function linkVarReferences(entries) {
|
|
101
|
+
let byVarName = new Map(entries.map((entry) => [entry.varName, entry]));
|
|
102
|
+
for (let entry of entries) {
|
|
103
|
+
if (entry.kind !== "typed" || entry.aliasOf !== void 0) continue;
|
|
104
|
+
if (typeof entry.value !== "string") continue;
|
|
105
|
+
let varName = referenceTarget(entry.value);
|
|
106
|
+
if (varName === null) continue;
|
|
107
|
+
let target = byVarName.get(varName);
|
|
108
|
+
if (target !== void 0) entry.aliasOf = target.key;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function walk(node, schema, inherited, path, out, varNames) {
|
|
112
|
+
for (let [key, value] of Object.entries(node)) {
|
|
113
|
+
let childPath = [...path, key];
|
|
114
|
+
let childKey = childPath.join(".");
|
|
115
|
+
if (/[.{}]/.test(key)) throw new ThemeError(`Token or group name "${childKey}" contains characters reserved by references (".", "{", "}")`);
|
|
116
|
+
let child = childSchema(schema, key);
|
|
117
|
+
let own = selfSchema(child) ?? inherited;
|
|
118
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
119
|
+
walk(value, child, own, childPath, out, varNames);
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
if (own === void 0) throw new ThemeError(`"${childKey}" has no schema entry`);
|
|
123
|
+
assertNoStringReference(value, childKey);
|
|
124
|
+
let varName = `--${childPath.map(kebabSegment).join("-")}`;
|
|
125
|
+
let existing = varNames.get(varName);
|
|
126
|
+
if (existing !== void 0) throw new ThemeError(`Tokens "${existing}" and "${childKey}" both produce the CSS variable ${varName}`);
|
|
127
|
+
varNames.set(varName, childKey);
|
|
128
|
+
let common = {
|
|
129
|
+
key: childKey,
|
|
130
|
+
path: childPath,
|
|
131
|
+
varName
|
|
132
|
+
};
|
|
133
|
+
let tag = own[TAG];
|
|
134
|
+
if (tag === "any") out.push({
|
|
135
|
+
kind: "untyped",
|
|
136
|
+
...common,
|
|
137
|
+
value: String(value)
|
|
138
|
+
});
|
|
139
|
+
else if (tag === "scale") out.push({
|
|
140
|
+
kind: "scale",
|
|
141
|
+
...common,
|
|
142
|
+
value
|
|
143
|
+
});
|
|
144
|
+
else out.push({
|
|
145
|
+
kind: "typed",
|
|
146
|
+
...common,
|
|
147
|
+
type: tag,
|
|
148
|
+
value
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
//#endregion
|
|
153
|
+
//#region src/serialize.ts
|
|
154
|
+
const FONT_WEIGHT_KEYWORDS = {
|
|
155
|
+
thin: 100,
|
|
156
|
+
hairline: 100,
|
|
157
|
+
"extra-light": 200,
|
|
158
|
+
"ultra-light": 200,
|
|
159
|
+
light: 300,
|
|
160
|
+
normal: 400,
|
|
161
|
+
regular: 400,
|
|
162
|
+
book: 400,
|
|
163
|
+
medium: 500,
|
|
164
|
+
"semi-bold": 600,
|
|
165
|
+
"demi-bold": 600,
|
|
166
|
+
bold: 700,
|
|
167
|
+
"extra-bold": 800,
|
|
168
|
+
"ultra-bold": 800,
|
|
169
|
+
black: 900,
|
|
170
|
+
heavy: 900,
|
|
171
|
+
"extra-black": 950,
|
|
172
|
+
"ultra-black": 950
|
|
173
|
+
};
|
|
174
|
+
const COLOR_FUNCTIONS = {
|
|
175
|
+
hsl: {
|
|
176
|
+
fn: "hsl",
|
|
177
|
+
percents: [1, 2]
|
|
178
|
+
},
|
|
179
|
+
hwb: {
|
|
180
|
+
fn: "hwb",
|
|
181
|
+
percents: [1, 2]
|
|
182
|
+
},
|
|
183
|
+
lab: { fn: "lab" },
|
|
184
|
+
lch: { fn: "lch" },
|
|
185
|
+
oklab: { fn: "oklab" },
|
|
186
|
+
oklch: { fn: "oklch" }
|
|
187
|
+
};
|
|
188
|
+
const COLOR_SPACES = /* @__PURE__ */ new Set([
|
|
189
|
+
"srgb",
|
|
190
|
+
"srgb-linear",
|
|
191
|
+
"display-p3",
|
|
192
|
+
"a98-rgb",
|
|
193
|
+
"prophoto-rgb",
|
|
194
|
+
"rec2020",
|
|
195
|
+
"xyz-d65",
|
|
196
|
+
"xyz-d50"
|
|
197
|
+
]);
|
|
198
|
+
const STROKE_KEYWORDS = /* @__PURE__ */ new Set([
|
|
199
|
+
"solid",
|
|
200
|
+
"dashed",
|
|
201
|
+
"dotted",
|
|
202
|
+
"double",
|
|
203
|
+
"groove",
|
|
204
|
+
"ridge",
|
|
205
|
+
"outset",
|
|
206
|
+
"inset"
|
|
207
|
+
]);
|
|
208
|
+
function serializeValue(type, value, ctx, key) {
|
|
209
|
+
switch (type) {
|
|
210
|
+
case "color": return serializeColor(value, key);
|
|
211
|
+
case "dimension": return serializeMeasure(value, ["px", "rem"], key);
|
|
212
|
+
case "duration": return serializeMeasure(value, ["ms", "s"], key);
|
|
213
|
+
case "fontFamily": return serializeFontFamily(value, key);
|
|
214
|
+
case "fontWeight": return serializeFontWeight(value, key);
|
|
215
|
+
case "number": return serializeNumber(value, key);
|
|
216
|
+
case "cubicBezier": return serializeCubicBezier(value, key);
|
|
217
|
+
case "shadow": return serializeShadow(value, ctx, key);
|
|
218
|
+
case "border": return serializeBorder(value, ctx, key);
|
|
219
|
+
case "transition": return serializeTransition(value, ctx, key);
|
|
220
|
+
case "gradient": return serializeGradient(value, ctx, key);
|
|
221
|
+
case "strokeStyle": return serializeStrokeStyle(value, key);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
function field(type, value, ctx, key) {
|
|
225
|
+
return serializeValue(type, value, ctx, key);
|
|
226
|
+
}
|
|
227
|
+
function invalid(key, type, value) {
|
|
228
|
+
return new ThemeError(`"${key}" has an invalid ${type} value: ${JSON.stringify(value)}`);
|
|
229
|
+
}
|
|
230
|
+
function serializeColor(value, key) {
|
|
231
|
+
if (typeof value === "string") return value;
|
|
232
|
+
if (typeof value !== "object" || value === null) throw invalid(key, "color", value);
|
|
233
|
+
let { colorSpace, components, alpha, hex } = value;
|
|
234
|
+
if (typeof hex === "string") return hex;
|
|
235
|
+
if (typeof colorSpace !== "string" || !Array.isArray(components)) throw invalid(key, "color", value);
|
|
236
|
+
let parts = components.map((component) => component === "none" ? "none" : serializeComponent(component, key));
|
|
237
|
+
let alphaPart = alpha === void 0 ? "" : ` / ${serializeComponent(alpha, key)}`;
|
|
238
|
+
let fn = COLOR_FUNCTIONS[colorSpace];
|
|
239
|
+
if (fn) {
|
|
240
|
+
let printed = parts.map((part, index) => fn.percents?.includes(index) && part !== "none" ? `${part}%` : part);
|
|
241
|
+
return `${fn.fn}(${printed.join(" ")}${alphaPart})`;
|
|
242
|
+
}
|
|
243
|
+
if (COLOR_SPACES.has(colorSpace)) return `color(${colorSpace} ${parts.join(" ")}${alphaPart})`;
|
|
244
|
+
throw new ThemeError(`"${key}" has unknown colorSpace "${colorSpace}"`);
|
|
245
|
+
}
|
|
246
|
+
function serializeComponent(value, key) {
|
|
247
|
+
if (typeof value !== "number" || !Number.isFinite(value)) throw invalid(key, "color component", value);
|
|
248
|
+
return String(value);
|
|
249
|
+
}
|
|
250
|
+
function serializeMeasure(value, units, key) {
|
|
251
|
+
if (typeof value === "string") return value;
|
|
252
|
+
if (typeof value === "object" && value !== null) {
|
|
253
|
+
let { value: amount, unit } = value;
|
|
254
|
+
if (typeof amount === "number" && typeof unit === "string" && units.includes(unit)) return `${amount}${unit}`;
|
|
255
|
+
}
|
|
256
|
+
throw invalid(key, `dimension/duration (${units.join("|")})`, value);
|
|
257
|
+
}
|
|
258
|
+
function serializeFontFamily(value, key) {
|
|
259
|
+
if (typeof value === "string") return value;
|
|
260
|
+
let names = Array.isArray(value) ? value : [value];
|
|
261
|
+
if (names.length === 0) throw invalid(key, "fontFamily", value);
|
|
262
|
+
return names.map((name) => {
|
|
263
|
+
if (typeof name !== "string") throw invalid(key, "fontFamily", value);
|
|
264
|
+
return /^[a-zA-Z][a-zA-Z-]*$/.test(name) ? name : `"${name.replaceAll("\"", "\\\"")}"`;
|
|
265
|
+
}).join(", ");
|
|
266
|
+
}
|
|
267
|
+
function serializeFontWeight(value, key) {
|
|
268
|
+
if (typeof value === "number") {
|
|
269
|
+
if (value >= 1 && value <= 1e3) return String(value);
|
|
270
|
+
throw invalid(key, "fontWeight", value);
|
|
271
|
+
}
|
|
272
|
+
if (typeof value === "string") {
|
|
273
|
+
let mapped = FONT_WEIGHT_KEYWORDS[value];
|
|
274
|
+
if (mapped !== void 0) return String(mapped);
|
|
275
|
+
throw new ThemeError(`"${key}" has unknown fontWeight keyword "${value}"`);
|
|
276
|
+
}
|
|
277
|
+
throw invalid(key, "fontWeight", value);
|
|
278
|
+
}
|
|
279
|
+
function serializeNumber(value, key) {
|
|
280
|
+
if (typeof value === "string") return value;
|
|
281
|
+
if (typeof value !== "number" || !Number.isFinite(value)) throw invalid(key, "number", value);
|
|
282
|
+
return String(value);
|
|
283
|
+
}
|
|
284
|
+
function serializeCubicBezier(value, key) {
|
|
285
|
+
if (typeof value === "string") return value;
|
|
286
|
+
if (!Array.isArray(value) || value.length !== 4) throw invalid(key, "cubicBezier", value);
|
|
287
|
+
return `cubic-bezier(${value.map((part) => serializeComponent(part, key)).join(", ")})`;
|
|
288
|
+
}
|
|
289
|
+
function serializeShadow(value, ctx, key) {
|
|
290
|
+
if (typeof value === "string") return value;
|
|
291
|
+
return (Array.isArray(value) ? value : [value]).map((shadow) => {
|
|
292
|
+
if (typeof shadow !== "object" || shadow === null) throw invalid(key, "shadow", value);
|
|
293
|
+
let { color, offsetX, offsetY, blur, spread, inset } = shadow;
|
|
294
|
+
let parts = [
|
|
295
|
+
field("dimension", offsetX, ctx, key),
|
|
296
|
+
field("dimension", offsetY, ctx, key),
|
|
297
|
+
blur === void 0 ? "0" : field("dimension", blur, ctx, key),
|
|
298
|
+
spread === void 0 ? "0" : field("dimension", spread, ctx, key),
|
|
299
|
+
field("color", color, ctx, key)
|
|
300
|
+
];
|
|
301
|
+
return `${inset === true ? "inset " : ""}${parts.join(" ")}`;
|
|
302
|
+
}).join(", ");
|
|
303
|
+
}
|
|
304
|
+
function serializeBorder(value, ctx, key) {
|
|
305
|
+
if (typeof value === "string") return value;
|
|
306
|
+
if (typeof value !== "object" || value === null) throw invalid(key, "border", value);
|
|
307
|
+
let { color, width, style } = value;
|
|
308
|
+
return `${field("dimension", width, ctx, key)} ${field("strokeStyle", style, ctx, key)} ${field("color", color, ctx, key)}`;
|
|
309
|
+
}
|
|
310
|
+
function serializeTransition(value, ctx, key) {
|
|
311
|
+
if (typeof value === "string") return value;
|
|
312
|
+
if (typeof value !== "object" || value === null) throw invalid(key, "transition", value);
|
|
313
|
+
let { duration, timingFunction, delay } = value;
|
|
314
|
+
let delayPart = delay === void 0 ? "0s" : field("duration", delay, ctx, key);
|
|
315
|
+
return `${field("duration", duration, ctx, key)} ${field("cubicBezier", timingFunction, ctx, key)} ${delayPart}`;
|
|
316
|
+
}
|
|
317
|
+
function serializeGradient(value, ctx, key) {
|
|
318
|
+
if (typeof value === "string") return value;
|
|
319
|
+
if (!Array.isArray(value)) throw invalid(key, "gradient", value);
|
|
320
|
+
return value.map((stop) => {
|
|
321
|
+
if (typeof stop !== "object" || stop === null) throw invalid(key, "gradient", value);
|
|
322
|
+
let { color, position } = stop;
|
|
323
|
+
if (typeof position !== "number") throw invalid(key, "gradient stop position", position);
|
|
324
|
+
return `${field("color", color, ctx, key)} ${Number((position * 100).toFixed(4))}%`;
|
|
325
|
+
}).join(", ");
|
|
326
|
+
}
|
|
327
|
+
function serializeStrokeStyle(value, key) {
|
|
328
|
+
if (typeof value === "string") {
|
|
329
|
+
if (STROKE_KEYWORDS.has(value)) return value;
|
|
330
|
+
throw new ThemeError(`"${key}" has unknown strokeStyle keyword "${value}"`);
|
|
331
|
+
}
|
|
332
|
+
if (typeof value === "object" && value !== null) return "dashed";
|
|
333
|
+
throw invalid(key, "strokeStyle", value);
|
|
334
|
+
}
|
|
335
|
+
//#endregion
|
|
336
|
+
//#region src/schema.ts
|
|
337
|
+
/** @internal */
|
|
338
|
+
const TAG = Symbol.for("pitlane.theme.tag");
|
|
339
|
+
/** @internal */
|
|
340
|
+
const SELF = Symbol.for("pitlane.theme.self");
|
|
341
|
+
const NO_REFS = { varRefFor(key) {
|
|
342
|
+
return `var(--${key.replaceAll(".", "-")})`;
|
|
343
|
+
} };
|
|
344
|
+
/**
|
|
345
|
+
* Standard Schema path segments may be objects, so stringify each one
|
|
346
|
+
* rather than relying on `Array#join`.
|
|
347
|
+
*
|
|
348
|
+
* @internal
|
|
349
|
+
*/
|
|
350
|
+
function pathKey(path) {
|
|
351
|
+
return path.map((segment) => typeof segment === "object" && segment !== null && "key" in segment ? String(segment.key) : String(segment)).join(".");
|
|
352
|
+
}
|
|
353
|
+
function tokenSchema(tag) {
|
|
354
|
+
let schema = createSchema((value, context) => {
|
|
355
|
+
let key = pathKey(context.path);
|
|
356
|
+
if (tag === "any") {
|
|
357
|
+
if (typeof value === "string" || typeof value === "number") return { value: String(value) };
|
|
358
|
+
return fail(`"${key}" must be a string or a number`, context.path);
|
|
359
|
+
}
|
|
360
|
+
try {
|
|
361
|
+
return { value: serializeValue(tag === "scale" ? "dimension" : tag, value, NO_REFS, key) };
|
|
362
|
+
} catch (error) {
|
|
363
|
+
return fail(error.message, context.path);
|
|
364
|
+
}
|
|
365
|
+
});
|
|
366
|
+
return Object.assign(schema, { [TAG]: tag });
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* A `color` token. Accepts any CSS color, including `light-dark()`,
|
|
370
|
+
* `color-mix()`, and `currentColor`, plus DTCG's structured form.
|
|
371
|
+
*
|
|
372
|
+
* @returns A schema declaring the `color` token type
|
|
373
|
+
*
|
|
374
|
+
* @example
|
|
375
|
+
* ```ts
|
|
376
|
+
* let schema = { color: s.color() };
|
|
377
|
+
* let tokens = { color: { white: "#fff", page: lightDark("#fff", "#111") } };
|
|
378
|
+
* ```
|
|
379
|
+
*/
|
|
380
|
+
function color() {
|
|
381
|
+
return tokenSchema("color");
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* A `dimension` token. Accepts any CSS length, including `clamp()`,
|
|
385
|
+
* `calc()`, `%`, and `em`.
|
|
386
|
+
*
|
|
387
|
+
* @returns A schema declaring the `dimension` token type
|
|
388
|
+
*/
|
|
389
|
+
function dimension() {
|
|
390
|
+
return tokenSchema("dimension");
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* A `duration` token. Accepts `ms`, `s`, and `calc()`.
|
|
394
|
+
*
|
|
395
|
+
* @returns A schema declaring the `duration` token type
|
|
396
|
+
*/
|
|
397
|
+
function duration() {
|
|
398
|
+
return tokenSchema("duration");
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* A `number` token. Accepts a finite number, which is what unitless
|
|
402
|
+
* CSS values such as `line-height` and `opacity` take.
|
|
403
|
+
*
|
|
404
|
+
* @returns A schema declaring the `number` token type
|
|
405
|
+
*/
|
|
406
|
+
function number() {
|
|
407
|
+
return tokenSchema("number");
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* A `cubicBezier` token, named for the CSS property it feeds. Accepts
|
|
411
|
+
* a four-number tuple or `cubic-bezier(…)` text.
|
|
412
|
+
*
|
|
413
|
+
* @returns A schema declaring the `cubicBezier` token type
|
|
414
|
+
*/
|
|
415
|
+
function easing() {
|
|
416
|
+
return tokenSchema("cubicBezier");
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* A `shadow` token. Accepts CSS shadow text, `inset` included.
|
|
420
|
+
*
|
|
421
|
+
* @returns A schema declaring the `shadow` token type
|
|
422
|
+
*/
|
|
423
|
+
function shadow() {
|
|
424
|
+
return tokenSchema("shadow");
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* A `border` token. Accepts CSS border shorthand text.
|
|
428
|
+
*
|
|
429
|
+
* @returns A schema declaring the `border` token type
|
|
430
|
+
*/
|
|
431
|
+
function border() {
|
|
432
|
+
return tokenSchema("border");
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* A `transition` token. Accepts CSS transition shorthand text.
|
|
436
|
+
*
|
|
437
|
+
* @returns A schema declaring the `transition` token type
|
|
438
|
+
*/
|
|
439
|
+
function transition() {
|
|
440
|
+
return tokenSchema("transition");
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* A `gradient` token. Accepts CSS gradient function text.
|
|
444
|
+
*
|
|
445
|
+
* @returns A schema declaring the `gradient` token type
|
|
446
|
+
*/
|
|
447
|
+
function gradient() {
|
|
448
|
+
return tokenSchema("gradient");
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* A `strokeStyle` token, named for the CSS value it holds. Accepts a
|
|
452
|
+
* line-style keyword.
|
|
453
|
+
*
|
|
454
|
+
* @returns A schema declaring the `strokeStyle` token type
|
|
455
|
+
*/
|
|
456
|
+
function stroke() {
|
|
457
|
+
return tokenSchema("strokeStyle");
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* The two font token types, grouped because they share a prefix.
|
|
461
|
+
*
|
|
462
|
+
* `font.family()` accepts a font stack, as a string or an array of
|
|
463
|
+
* names; an array joins with commas and quotes what needs quoting.
|
|
464
|
+
* `font.weight()` accepts 1 to 1000 or one of DTCG's nineteen
|
|
465
|
+
* keywords, and emits the number.
|
|
466
|
+
*
|
|
467
|
+
* @example
|
|
468
|
+
* ```ts
|
|
469
|
+
* let schema = { font: s.font.family(), weight: s.font.weight() };
|
|
470
|
+
* let tokens = { font: { sans: ["Inter var", "system-ui"] }, weight: { bold: 700 } };
|
|
471
|
+
* ```
|
|
472
|
+
*/
|
|
473
|
+
let font = {
|
|
474
|
+
family: () => tokenSchema("fontFamily"),
|
|
475
|
+
weight: () => tokenSchema("fontWeight")
|
|
476
|
+
};
|
|
477
|
+
/**
|
|
478
|
+
* A dimension token whose accessor leaf is a multiplier rather than a
|
|
479
|
+
* value. The token emits its own custom property; the accessor leaf is
|
|
480
|
+
* callable, and carries the base itself as `.token`.
|
|
481
|
+
*
|
|
482
|
+
* This is Tailwind's `--spacing`: one base that the whole scale
|
|
483
|
+
* multiplies, with no named steps.
|
|
484
|
+
*
|
|
485
|
+
* @returns A schema declaring a scale token
|
|
486
|
+
*
|
|
487
|
+
* @example
|
|
488
|
+
* ```ts
|
|
489
|
+
* let theme = createTheme({
|
|
490
|
+
* schema: { spacing: s.scale() },
|
|
491
|
+
* tokens: { spacing: "0.25rem" },
|
|
492
|
+
* });
|
|
493
|
+
*
|
|
494
|
+
* theme.token.spacing(4); // "calc(var(--spacing) * 4)"
|
|
495
|
+
* theme.token.spacing.token; // "var(--spacing)"
|
|
496
|
+
* ```
|
|
497
|
+
*/
|
|
498
|
+
function scale() {
|
|
499
|
+
return tokenSchema("scale");
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
* A token with no type. Its value is emitted verbatim and its accessor
|
|
503
|
+
* leaf brands as a plain `string`, which the open-grammar CSS
|
|
504
|
+
* properties accept and the token-mapped longhands still reject.
|
|
505
|
+
*
|
|
506
|
+
* This exists for CSS values with no DTCG type, such as
|
|
507
|
+
* `spin 1s linear infinite` and `16 / 9`. An untyped token may not be
|
|
508
|
+
* the target of a typed token's reference, because there is no type to
|
|
509
|
+
* check against.
|
|
510
|
+
*
|
|
511
|
+
* @returns A schema declaring an untyped token
|
|
512
|
+
*/
|
|
513
|
+
function any() {
|
|
514
|
+
return tokenSchema("any");
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* A node that is itself typed and also carries per-child overrides.
|
|
518
|
+
* `self` applies to that node and to every descendant without its own
|
|
519
|
+
* entry; each key in `children` overrides it from there down.
|
|
520
|
+
*
|
|
521
|
+
* The self schema rides on a symbol key, so no token name is reserved:
|
|
522
|
+
* a token named `default` can carry its own type.
|
|
523
|
+
*
|
|
524
|
+
* @param self - The schema for this node and its unlabelled descendants
|
|
525
|
+
* @param children - Per-child schema overrides
|
|
526
|
+
* @returns A schema group
|
|
527
|
+
*
|
|
528
|
+
* @example
|
|
529
|
+
* ```ts
|
|
530
|
+
* let schema = {
|
|
531
|
+
* control: s.group(s.dimension(), { color: s.color(), opacity: s.number() }),
|
|
532
|
+
* };
|
|
533
|
+
* // control.height.sm is a dimension; control.color.border is a color.
|
|
534
|
+
* ```
|
|
535
|
+
*/
|
|
536
|
+
function group(self, children) {
|
|
537
|
+
return {
|
|
538
|
+
...children,
|
|
539
|
+
[SELF]: self
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* True when a node declares a token type rather than grouping others.
|
|
544
|
+
*
|
|
545
|
+
* @internal
|
|
546
|
+
*/
|
|
547
|
+
function isTokenSchema(node) {
|
|
548
|
+
return typeof node === "object" && node !== null && TAG in node;
|
|
549
|
+
}
|
|
550
|
+
/**
|
|
551
|
+
* The schema a node declares for itself and its unlabelled children,
|
|
552
|
+
* or `undefined` when it only groups.
|
|
553
|
+
*
|
|
554
|
+
* @internal
|
|
555
|
+
*/
|
|
556
|
+
function selfSchema(node) {
|
|
557
|
+
if (isTokenSchema(node)) return node;
|
|
558
|
+
if (typeof node === "object" && node !== null && SELF in node) return node[SELF];
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* The schema node for one child key, or `undefined` when the parent
|
|
562
|
+
* declares nothing for it.
|
|
563
|
+
*
|
|
564
|
+
* @internal
|
|
565
|
+
*/
|
|
566
|
+
function childSchema(node, key) {
|
|
567
|
+
if (typeof node !== "object" || node === null || isTokenSchema(node)) return void 0;
|
|
568
|
+
if (!Object.hasOwn(node, key)) return void 0;
|
|
569
|
+
return node[key];
|
|
570
|
+
}
|
|
571
|
+
//#endregion
|
|
572
|
+
export { assertNoStringReference as C, referenceTarget as D, mentionedVarNames as E, ThemeError as S, kebabSegment as T, selfSchema as _, childSchema as a, transition as b, duration as c, gradient as d, group as f, scale as g, pathKey as h, border as i, easing as l, number as m, TAG as n, color as o, isTokenSchema as p, any as r, dimension as s, SELF as t, font as u, shadow as v, collectTokens as w, serializeValue as x, stroke as y };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { C as stroke, S as shadow, _ as isTokenSchema, a as TAG, b as scale, c as border, d as dimension, f as duration, g as group, h as gradient, i as SchemaTag, l as childSchema, m as font, n as SchemaGroup, o as TokenSchema, p as easing, r as SchemaNode, s as any, t as SELF, u as color, v as number, w as transition, x as selfSchema, y as pathKey } from "./schema-CRP607Pg.mjs";
|
|
2
|
+
export { SELF, SchemaGroup, SchemaNode, SchemaTag, TAG, TokenSchema, any, border, childSchema, color, dimension, duration, easing, font, gradient, group, isTokenSchema, number, pathKey, scale, selfSchema, shadow, stroke, transition };
|
package/dist/schema.mjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { _ as selfSchema, a as childSchema, b as transition, c as duration, d as gradient, f as group, g as scale, h as pathKey, i as border, l as easing, m as number, n as TAG, o as color, p as isTokenSchema, r as any, s as dimension, t as SELF, u as font, v as shadow, y as stroke } from "./schema-JmfNnMzr.mjs";
|
|
2
|
+
export { SELF, TAG, any, border, childSchema, color, dimension, duration, easing, font, gradient, group, isTokenSchema, number, pathKey, scale, selfSchema, shadow, stroke, transition };
|