@ansh-ui/tokens 0.2.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/LICENSE +21 -0
- package/dist/ansh.css +307 -0
- package/dist/index.cjs +573 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +815 -0
- package/dist/index.d.ts +815 -0
- package/dist/index.js +546 -0
- package/dist/index.js.map +1 -0
- package/package.json +45 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,546 @@
|
|
|
1
|
+
// src/primitives.ts
|
|
2
|
+
var space = {
|
|
3
|
+
0: "0",
|
|
4
|
+
px: "1px",
|
|
5
|
+
0.5: "0.125rem",
|
|
6
|
+
// 2px
|
|
7
|
+
1: "0.25rem",
|
|
8
|
+
// 4px
|
|
9
|
+
1.5: "0.375rem",
|
|
10
|
+
// 6px
|
|
11
|
+
2: "0.5rem",
|
|
12
|
+
// 8px
|
|
13
|
+
3: "0.75rem",
|
|
14
|
+
// 12px
|
|
15
|
+
4: "1rem",
|
|
16
|
+
// 16px
|
|
17
|
+
5: "1.25rem",
|
|
18
|
+
// 20px
|
|
19
|
+
6: "1.5rem",
|
|
20
|
+
// 24px
|
|
21
|
+
8: "2rem",
|
|
22
|
+
// 32px
|
|
23
|
+
10: "2.5rem",
|
|
24
|
+
// 40px
|
|
25
|
+
12: "3rem",
|
|
26
|
+
// 48px
|
|
27
|
+
16: "4rem",
|
|
28
|
+
// 64px
|
|
29
|
+
20: "5rem",
|
|
30
|
+
// 80px
|
|
31
|
+
24: "6rem",
|
|
32
|
+
// 96px
|
|
33
|
+
32: "8rem",
|
|
34
|
+
// 128px
|
|
35
|
+
40: "10rem",
|
|
36
|
+
// 160px
|
|
37
|
+
48: "12rem",
|
|
38
|
+
// 192px
|
|
39
|
+
56: "14rem",
|
|
40
|
+
// 224px
|
|
41
|
+
64: "16rem"
|
|
42
|
+
// 256px
|
|
43
|
+
};
|
|
44
|
+
var fontSize = {
|
|
45
|
+
xs: ["0.75rem", { lineHeight: "1.125rem", letterSpacing: "0.01em" }],
|
|
46
|
+
sm: ["0.875rem", { lineHeight: "1.375rem", letterSpacing: "0.005em" }],
|
|
47
|
+
base: ["1rem", { lineHeight: "1.625rem", letterSpacing: "0" }],
|
|
48
|
+
lg: ["1.125rem", { lineHeight: "1.75rem", letterSpacing: "-0.005em" }],
|
|
49
|
+
xl: ["1.25rem", { lineHeight: "1.875rem", letterSpacing: "-0.01em" }],
|
|
50
|
+
"2xl": ["1.5rem", { lineHeight: "2rem", letterSpacing: "-0.015em" }],
|
|
51
|
+
"3xl": ["1.875rem", { lineHeight: "2.375rem", letterSpacing: "-0.02em" }],
|
|
52
|
+
"4xl": ["2.25rem", { lineHeight: "2.625rem", letterSpacing: "-0.025em" }],
|
|
53
|
+
"5xl": ["3rem", { lineHeight: "3.25rem", letterSpacing: "-0.03em" }],
|
|
54
|
+
"6xl": ["3.75rem", { lineHeight: "3.9rem", letterSpacing: "-0.035em" }],
|
|
55
|
+
"7xl": ["4.5rem", { lineHeight: "4.6rem", letterSpacing: "-0.04em" }]
|
|
56
|
+
};
|
|
57
|
+
var fontWeight = {
|
|
58
|
+
normal: "400",
|
|
59
|
+
medium: "500",
|
|
60
|
+
semibold: "600",
|
|
61
|
+
bold: "700"
|
|
62
|
+
};
|
|
63
|
+
var fontFamily = {
|
|
64
|
+
/**
|
|
65
|
+
* The system UI stack. Deliberately not a webfont: the fastest, most legible text on any
|
|
66
|
+
* platform is the font the user's OS already has loaded, and a design system should not force
|
|
67
|
+
* a font decision on its consumers.
|
|
68
|
+
*/
|
|
69
|
+
sans: [
|
|
70
|
+
"ui-sans-serif",
|
|
71
|
+
"system-ui",
|
|
72
|
+
"-apple-system",
|
|
73
|
+
"BlinkMacSystemFont",
|
|
74
|
+
"Segoe UI",
|
|
75
|
+
"Roboto",
|
|
76
|
+
"Helvetica Neue",
|
|
77
|
+
"Arial",
|
|
78
|
+
"sans-serif"
|
|
79
|
+
].join(", "),
|
|
80
|
+
mono: [
|
|
81
|
+
"ui-monospace",
|
|
82
|
+
"SFMono-Regular",
|
|
83
|
+
"Menlo",
|
|
84
|
+
"Monaco",
|
|
85
|
+
"Consolas",
|
|
86
|
+
"Liberation Mono",
|
|
87
|
+
"Courier New",
|
|
88
|
+
"monospace"
|
|
89
|
+
].join(", ")
|
|
90
|
+
};
|
|
91
|
+
var radius = {
|
|
92
|
+
none: "0",
|
|
93
|
+
xs: "0.25rem",
|
|
94
|
+
// 4px
|
|
95
|
+
sm: "0.375rem",
|
|
96
|
+
// 6px
|
|
97
|
+
md: "0.5rem",
|
|
98
|
+
// 8px
|
|
99
|
+
lg: "0.75rem",
|
|
100
|
+
// 12px
|
|
101
|
+
xl: "1rem",
|
|
102
|
+
// 16px
|
|
103
|
+
"2xl": "1.5rem",
|
|
104
|
+
// 24px
|
|
105
|
+
"3xl": "2rem",
|
|
106
|
+
// 32px
|
|
107
|
+
full: "9999px"
|
|
108
|
+
};
|
|
109
|
+
var shadow = {
|
|
110
|
+
none: "none",
|
|
111
|
+
xs: "0 1px 2px 0 var(--ansh-shadow-color, rgb(15 23 42 / 0.05))",
|
|
112
|
+
sm: "0 1px 3px 0 var(--ansh-shadow-color, rgb(15 23 42 / 0.08)), 0 1px 2px -1px var(--ansh-shadow-color, rgb(15 23 42 / 0.06))",
|
|
113
|
+
md: "0 4px 6px -1px var(--ansh-shadow-color, rgb(15 23 42 / 0.08)), 0 2px 4px -2px var(--ansh-shadow-color, rgb(15 23 42 / 0.06))",
|
|
114
|
+
lg: "0 10px 15px -3px var(--ansh-shadow-color, rgb(15 23 42 / 0.08)), 0 4px 6px -4px var(--ansh-shadow-color, rgb(15 23 42 / 0.05))",
|
|
115
|
+
xl: "0 20px 25px -5px var(--ansh-shadow-color, rgb(15 23 42 / 0.1)), 0 8px 10px -6px var(--ansh-shadow-color, rgb(15 23 42 / 0.05))",
|
|
116
|
+
"2xl": "0 25px 50px -12px var(--ansh-shadow-color, rgb(15 23 42 / 0.2))",
|
|
117
|
+
/** Inset — for pressed states and inputs. */
|
|
118
|
+
inner: "inset 0 2px 4px 0 var(--ansh-shadow-color, rgb(15 23 42 / 0.06))",
|
|
119
|
+
/**
|
|
120
|
+
* Glow. Uses `currentColor` so a button's glow automatically matches its own accent without
|
|
121
|
+
* the author repeating the colour.
|
|
122
|
+
*/
|
|
123
|
+
glow: "0 0 24px -4px currentColor",
|
|
124
|
+
glowLg: "0 0 48px -8px currentColor"
|
|
125
|
+
};
|
|
126
|
+
var blur = {
|
|
127
|
+
none: "0",
|
|
128
|
+
xs: "2px",
|
|
129
|
+
sm: "4px",
|
|
130
|
+
md: "8px",
|
|
131
|
+
lg: "16px",
|
|
132
|
+
xl: "24px",
|
|
133
|
+
"2xl": "40px",
|
|
134
|
+
"3xl": "64px"
|
|
135
|
+
};
|
|
136
|
+
var duration = {
|
|
137
|
+
instant: "0.1s",
|
|
138
|
+
fast: "0.2s",
|
|
139
|
+
normal: "0.3s",
|
|
140
|
+
moderate: "0.45s",
|
|
141
|
+
slow: "0.6s",
|
|
142
|
+
slower: "0.9s",
|
|
143
|
+
deliberate: "1.2s"
|
|
144
|
+
};
|
|
145
|
+
var easing = {
|
|
146
|
+
linear: "linear",
|
|
147
|
+
standard: "cubic-bezier(0.4, 0, 0.2, 1)",
|
|
148
|
+
emphasized: "cubic-bezier(0.22, 1, 0.36, 1)",
|
|
149
|
+
enter: "cubic-bezier(0, 0, 0.2, 1)",
|
|
150
|
+
exit: "cubic-bezier(0.4, 0, 1, 1)",
|
|
151
|
+
overshoot: "cubic-bezier(0.34, 1.56, 0.64, 1)",
|
|
152
|
+
cinematic: "cubic-bezier(0.16, 1, 0.3, 1)"
|
|
153
|
+
};
|
|
154
|
+
var zIndex = {
|
|
155
|
+
hide: "-1",
|
|
156
|
+
base: "0",
|
|
157
|
+
raised: "10",
|
|
158
|
+
dropdown: "1000",
|
|
159
|
+
sticky: "1100",
|
|
160
|
+
overlay: "1200",
|
|
161
|
+
modal: "1300",
|
|
162
|
+
popover: "1400",
|
|
163
|
+
toast: "1500",
|
|
164
|
+
tooltip: "1600",
|
|
165
|
+
/** Reserved for skip links and focus traps, which must beat everything. */
|
|
166
|
+
max: "2147483647"
|
|
167
|
+
};
|
|
168
|
+
var breakpoint = {
|
|
169
|
+
sm: "640px",
|
|
170
|
+
md: "768px",
|
|
171
|
+
lg: "1024px",
|
|
172
|
+
xl: "1280px",
|
|
173
|
+
"2xl": "1536px"
|
|
174
|
+
};
|
|
175
|
+
var neutral = {
|
|
176
|
+
50: "oklch(98.5% 0.002 264)",
|
|
177
|
+
100: "oklch(96.8% 0.004 264)",
|
|
178
|
+
200: "oklch(92.9% 0.007 264)",
|
|
179
|
+
300: "oklch(86.9% 0.011 264)",
|
|
180
|
+
400: "oklch(70.7% 0.018 264)",
|
|
181
|
+
500: "oklch(55.4% 0.022 264)",
|
|
182
|
+
600: "oklch(44.6% 0.021 264)",
|
|
183
|
+
700: "oklch(37.2% 0.019 264)",
|
|
184
|
+
800: "oklch(27.9% 0.017 264)",
|
|
185
|
+
900: "oklch(20.8% 0.015 264)",
|
|
186
|
+
950: "oklch(13.8% 0.014 264)",
|
|
187
|
+
1e3: "oklch(8.5% 0.012 264)"
|
|
188
|
+
};
|
|
189
|
+
var brand = {
|
|
190
|
+
50: "oklch(97% 0.017 253)",
|
|
191
|
+
100: "oklch(93.8% 0.036 253)",
|
|
192
|
+
200: "oklch(88.5% 0.069 253)",
|
|
193
|
+
300: "oklch(80.9% 0.111 253)",
|
|
194
|
+
400: "oklch(71.4% 0.153 253)",
|
|
195
|
+
500: "oklch(62.3% 0.188 253)",
|
|
196
|
+
600: "oklch(54.6% 0.208 253)",
|
|
197
|
+
700: "oklch(46.4% 0.192 253)",
|
|
198
|
+
800: "oklch(39.1% 0.16 253)",
|
|
199
|
+
900: "oklch(33.5% 0.129 253)",
|
|
200
|
+
950: "oklch(23.2% 0.093 253)"
|
|
201
|
+
};
|
|
202
|
+
var status = {
|
|
203
|
+
success: {
|
|
204
|
+
subtle: "oklch(95.5% 0.035 155)",
|
|
205
|
+
default: "oklch(58% 0.15 155)",
|
|
206
|
+
strong: "oklch(44% 0.12 155)"
|
|
207
|
+
},
|
|
208
|
+
warning: {
|
|
209
|
+
subtle: "oklch(96.5% 0.045 85)",
|
|
210
|
+
default: "oklch(72% 0.16 75)",
|
|
211
|
+
strong: "oklch(52% 0.13 65)"
|
|
212
|
+
},
|
|
213
|
+
danger: {
|
|
214
|
+
subtle: "oklch(95.5% 0.03 25)",
|
|
215
|
+
default: "oklch(58% 0.21 25)",
|
|
216
|
+
strong: "oklch(46% 0.18 25)"
|
|
217
|
+
},
|
|
218
|
+
info: {
|
|
219
|
+
subtle: "oklch(96% 0.025 240)",
|
|
220
|
+
default: "oklch(62% 0.17 245)",
|
|
221
|
+
strong: "oklch(48% 0.15 250)"
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
// src/semantic.ts
|
|
226
|
+
var light = {
|
|
227
|
+
surface: {
|
|
228
|
+
canvas: neutral[50],
|
|
229
|
+
raised: "#ffffff",
|
|
230
|
+
overlay: "#ffffff",
|
|
231
|
+
sunken: neutral[100],
|
|
232
|
+
glass: "oklch(100% 0 0 / 0.72)",
|
|
233
|
+
scrim: "oklch(20.8% 0.015 264 / 0.45)"
|
|
234
|
+
},
|
|
235
|
+
content: {
|
|
236
|
+
primary: neutral[900],
|
|
237
|
+
secondary: neutral[600],
|
|
238
|
+
tertiary: neutral[500],
|
|
239
|
+
disabled: neutral[400],
|
|
240
|
+
onAccent: "#ffffff",
|
|
241
|
+
inverse: neutral[50]
|
|
242
|
+
},
|
|
243
|
+
border: {
|
|
244
|
+
subtle: neutral[200],
|
|
245
|
+
default: neutral[300],
|
|
246
|
+
strong: neutral[400],
|
|
247
|
+
focus: brand[600]
|
|
248
|
+
},
|
|
249
|
+
accent: {
|
|
250
|
+
subtle: brand[50],
|
|
251
|
+
muted: brand[100],
|
|
252
|
+
default: brand[600],
|
|
253
|
+
hover: brand[700],
|
|
254
|
+
active: brand[800],
|
|
255
|
+
// A step darker than `default`: brand colours tuned to look right as a fill are usually too
|
|
256
|
+
// light to pass contrast as text on a white surface.
|
|
257
|
+
text: brand[700]
|
|
258
|
+
},
|
|
259
|
+
state: {
|
|
260
|
+
successSubtle: status.success.subtle,
|
|
261
|
+
success: status.success.strong,
|
|
262
|
+
warningSubtle: status.warning.subtle,
|
|
263
|
+
warning: status.warning.strong,
|
|
264
|
+
dangerSubtle: status.danger.subtle,
|
|
265
|
+
danger: status.danger.strong,
|
|
266
|
+
infoSubtle: status.info.subtle,
|
|
267
|
+
info: status.info.strong
|
|
268
|
+
},
|
|
269
|
+
shadowColor: "oklch(20.8% 0.015 264 / 0.08)"
|
|
270
|
+
};
|
|
271
|
+
var dark = {
|
|
272
|
+
surface: {
|
|
273
|
+
canvas: neutral[1e3],
|
|
274
|
+
raised: neutral[950],
|
|
275
|
+
overlay: neutral[900],
|
|
276
|
+
sunken: "oklch(6% 0.01 264)",
|
|
277
|
+
glass: "oklch(13.8% 0.014 264 / 0.68)",
|
|
278
|
+
scrim: "oklch(4% 0.008 264 / 0.65)"
|
|
279
|
+
},
|
|
280
|
+
content: {
|
|
281
|
+
primary: neutral[100],
|
|
282
|
+
secondary: neutral[300],
|
|
283
|
+
tertiary: neutral[400],
|
|
284
|
+
disabled: neutral[600],
|
|
285
|
+
onAccent: "#ffffff",
|
|
286
|
+
inverse: neutral[950]
|
|
287
|
+
},
|
|
288
|
+
border: {
|
|
289
|
+
// Borders on dark surfaces work by being *lighter* than the surface, and need less contrast
|
|
290
|
+
// than their light-mode counterparts to read as the same weight.
|
|
291
|
+
subtle: "oklch(100% 0 0 / 0.08)",
|
|
292
|
+
default: "oklch(100% 0 0 / 0.14)",
|
|
293
|
+
strong: "oklch(100% 0 0 / 0.24)",
|
|
294
|
+
focus: brand[400]
|
|
295
|
+
},
|
|
296
|
+
accent: {
|
|
297
|
+
subtle: "oklch(23.2% 0.093 253 / 0.4)",
|
|
298
|
+
muted: brand[950],
|
|
299
|
+
default: brand[500],
|
|
300
|
+
hover: brand[400],
|
|
301
|
+
active: brand[300],
|
|
302
|
+
text: brand[300]
|
|
303
|
+
},
|
|
304
|
+
state: {
|
|
305
|
+
successSubtle: "oklch(30% 0.08 155 / 0.35)",
|
|
306
|
+
success: "oklch(72% 0.16 155)",
|
|
307
|
+
warningSubtle: "oklch(32% 0.09 75 / 0.35)",
|
|
308
|
+
warning: "oklch(80% 0.15 80)",
|
|
309
|
+
dangerSubtle: "oklch(30% 0.11 25 / 0.35)",
|
|
310
|
+
danger: "oklch(70% 0.19 25)",
|
|
311
|
+
infoSubtle: "oklch(30% 0.09 245 / 0.35)",
|
|
312
|
+
info: "oklch(74% 0.15 245)"
|
|
313
|
+
},
|
|
314
|
+
// Deeper and more spread than light mode, since a dark shadow on a dark surface needs more
|
|
315
|
+
// opacity to register at all.
|
|
316
|
+
shadowColor: "oklch(0% 0 0 / 0.5)"
|
|
317
|
+
};
|
|
318
|
+
var themes = { light, dark };
|
|
319
|
+
|
|
320
|
+
// src/css.ts
|
|
321
|
+
var CSS_PREFIX = "ansh";
|
|
322
|
+
function flatten(target, value, path) {
|
|
323
|
+
if (typeof value === "string") {
|
|
324
|
+
target.set(`--${CSS_PREFIX}-${path.join("-")}`, value);
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
if (Array.isArray(value)) {
|
|
328
|
+
const [size, meta] = value;
|
|
329
|
+
target.set(`--${CSS_PREFIX}-${path.join("-")}`, size);
|
|
330
|
+
if (meta && typeof meta === "object") {
|
|
331
|
+
if (meta.lineHeight) {
|
|
332
|
+
target.set(`--${CSS_PREFIX}-${path.join("-")}-leading`, meta.lineHeight);
|
|
333
|
+
}
|
|
334
|
+
if (meta.letterSpacing) {
|
|
335
|
+
target.set(`--${CSS_PREFIX}-${path.join("-")}-tracking`, meta.letterSpacing);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
if (value && typeof value === "object") {
|
|
341
|
+
for (const [key, child] of Object.entries(value)) {
|
|
342
|
+
flatten(target, child, [...path, cssSegment(key)]);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
function cssSegment(key) {
|
|
347
|
+
return key.replace(".", "-").replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
|
|
348
|
+
}
|
|
349
|
+
function structuralVariables() {
|
|
350
|
+
const out = /* @__PURE__ */ new Map();
|
|
351
|
+
flatten(out, space, ["space"]);
|
|
352
|
+
flatten(out, radius, ["radius"]);
|
|
353
|
+
flatten(out, shadow, ["shadow"]);
|
|
354
|
+
flatten(out, blur, ["blur"]);
|
|
355
|
+
flatten(out, duration, ["duration"]);
|
|
356
|
+
flatten(out, easing, ["ease"]);
|
|
357
|
+
flatten(out, zIndex, ["z"]);
|
|
358
|
+
flatten(out, fontSize, ["text"]);
|
|
359
|
+
flatten(out, fontWeight, ["weight"]);
|
|
360
|
+
flatten(out, fontFamily, ["font"]);
|
|
361
|
+
flatten(out, breakpoint, ["screen"]);
|
|
362
|
+
return out;
|
|
363
|
+
}
|
|
364
|
+
function themeVariables(tokens2) {
|
|
365
|
+
const out = /* @__PURE__ */ new Map();
|
|
366
|
+
flatten(out, tokens2.surface, ["surface"]);
|
|
367
|
+
flatten(out, tokens2.content, ["content"]);
|
|
368
|
+
flatten(out, tokens2.border, ["border"]);
|
|
369
|
+
flatten(out, tokens2.accent, ["accent"]);
|
|
370
|
+
flatten(out, tokens2.state, ["state"]);
|
|
371
|
+
out.set(`--${CSS_PREFIX}-shadow-color`, tokens2.shadowColor);
|
|
372
|
+
return out;
|
|
373
|
+
}
|
|
374
|
+
function declarations(variables, indent = " ") {
|
|
375
|
+
return [...variables].map(([name, value]) => `${indent}${name}: ${value};`).join("\n");
|
|
376
|
+
}
|
|
377
|
+
function generateCss() {
|
|
378
|
+
const structural = structuralVariables();
|
|
379
|
+
const lightVars = themeVariables(light);
|
|
380
|
+
const darkVars = themeVariables(dark);
|
|
381
|
+
return `/**
|
|
382
|
+
* Ansh design tokens.
|
|
383
|
+
*
|
|
384
|
+
* Generated from @ansh-ui/tokens \u2014 do not edit by hand.
|
|
385
|
+
* Override any variable in your own stylesheet after importing this file.
|
|
386
|
+
*/
|
|
387
|
+
|
|
388
|
+
:root {
|
|
389
|
+
color-scheme: light dark;
|
|
390
|
+
|
|
391
|
+
${declarations(structural)}
|
|
392
|
+
|
|
393
|
+
${declarations(lightVars)}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/* Automatic dark mode, only when the document has not opted into manual control. */
|
|
397
|
+
@media (prefers-color-scheme: dark) {
|
|
398
|
+
:root:not([data-theme]) {
|
|
399
|
+
${declarations(darkVars, " ")}
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/* Explicit theme control. Works at any level of the tree, not just :root. */
|
|
404
|
+
[data-theme='dark'] {
|
|
405
|
+
${declarations(darkVars)}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
[data-theme='light'] {
|
|
409
|
+
${declarations(lightVars)}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Reduced-motion safety net.
|
|
414
|
+
*
|
|
415
|
+
* The engine honours \`prefers-reduced-motion\` in JavaScript, but any CSS transition or
|
|
416
|
+
* animation an application author writes is outside its reach. Neutralising them here means a
|
|
417
|
+
* consumer gets correct behaviour for their own styles too, simply by importing this file.
|
|
418
|
+
*
|
|
419
|
+
* Durations are set to 0.01ms rather than 0 so that \`transitionend\` and \`animationend\` still
|
|
420
|
+
* fire \u2014 code that waits on those events would otherwise hang forever.
|
|
421
|
+
*/
|
|
422
|
+
@media (prefers-reduced-motion: reduce) {
|
|
423
|
+
*,
|
|
424
|
+
*::before,
|
|
425
|
+
*::after {
|
|
426
|
+
animation-duration: 0.01ms !important;
|
|
427
|
+
animation-iteration-count: 1 !important;
|
|
428
|
+
transition-duration: 0.01ms !important;
|
|
429
|
+
scroll-behavior: auto !important;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Utility classes for the split-text behaviour.
|
|
435
|
+
*
|
|
436
|
+
* The behaviour sets \`--ansh-index\` and \`--ansh-total\` on every unit, which makes a
|
|
437
|
+
* staggered reveal possible in pure CSS with no JavaScript timing at all.
|
|
438
|
+
*/
|
|
439
|
+
.ansh-char,
|
|
440
|
+
.ansh-word,
|
|
441
|
+
.ansh-line {
|
|
442
|
+
display: inline-block;
|
|
443
|
+
/* Required for transforms to apply to inline content, and for masks to clip descenders. */
|
|
444
|
+
will-change: transform, opacity;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
.ansh-mask {
|
|
448
|
+
display: inline-block;
|
|
449
|
+
overflow: hidden;
|
|
450
|
+
vertical-align: top;
|
|
451
|
+
}
|
|
452
|
+
`;
|
|
453
|
+
}
|
|
454
|
+
function applyTheme(theme, target) {
|
|
455
|
+
if (typeof document === "undefined") return;
|
|
456
|
+
const element = target ?? document.documentElement;
|
|
457
|
+
if (theme === "system") element.removeAttribute("data-theme");
|
|
458
|
+
else element.setAttribute("data-theme", theme);
|
|
459
|
+
}
|
|
460
|
+
function resolveTheme(target) {
|
|
461
|
+
if (typeof document === "undefined") return "light";
|
|
462
|
+
const element = target ?? document.documentElement;
|
|
463
|
+
const explicit = element.closest("[data-theme]")?.getAttribute("data-theme");
|
|
464
|
+
if (explicit === "dark" || explicit === "light") return explicit;
|
|
465
|
+
return typeof matchMedia === "function" && matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
466
|
+
}
|
|
467
|
+
function themeStyle(theme) {
|
|
468
|
+
const out = {};
|
|
469
|
+
for (const [name, value] of themeVariables(theme === "dark" ? dark : light)) {
|
|
470
|
+
out[name] = value;
|
|
471
|
+
}
|
|
472
|
+
return out;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// src/index.ts
|
|
476
|
+
var tokens = {
|
|
477
|
+
space,
|
|
478
|
+
radius,
|
|
479
|
+
shadow,
|
|
480
|
+
blur,
|
|
481
|
+
duration,
|
|
482
|
+
easing,
|
|
483
|
+
zIndex,
|
|
484
|
+
fontSize,
|
|
485
|
+
fontWeight,
|
|
486
|
+
fontFamily,
|
|
487
|
+
breakpoint
|
|
488
|
+
};
|
|
489
|
+
function tailwindPreset() {
|
|
490
|
+
return {
|
|
491
|
+
theme: {
|
|
492
|
+
extend: {
|
|
493
|
+
spacing: space,
|
|
494
|
+
borderRadius: radius,
|
|
495
|
+
boxShadow: shadow,
|
|
496
|
+
blur,
|
|
497
|
+
fontFamily: { sans: [fontFamily.sans], mono: [fontFamily.mono] },
|
|
498
|
+
fontSize,
|
|
499
|
+
fontWeight,
|
|
500
|
+
screens: breakpoint,
|
|
501
|
+
zIndex,
|
|
502
|
+
transitionDuration: Object.fromEntries(
|
|
503
|
+
Object.entries(duration).map(([key, value]) => [key, value])
|
|
504
|
+
),
|
|
505
|
+
transitionTimingFunction: easing,
|
|
506
|
+
// Semantic colours are wired to the CSS variables rather than to literal values, so a
|
|
507
|
+
// Tailwind class like `bg-surface-raised` follows the active theme automatically.
|
|
508
|
+
colors: {
|
|
509
|
+
surface: {
|
|
510
|
+
canvas: "var(--ansh-surface-canvas)",
|
|
511
|
+
raised: "var(--ansh-surface-raised)",
|
|
512
|
+
overlay: "var(--ansh-surface-overlay)",
|
|
513
|
+
sunken: "var(--ansh-surface-sunken)",
|
|
514
|
+
glass: "var(--ansh-surface-glass)"
|
|
515
|
+
},
|
|
516
|
+
content: {
|
|
517
|
+
primary: "var(--ansh-content-primary)",
|
|
518
|
+
secondary: "var(--ansh-content-secondary)",
|
|
519
|
+
tertiary: "var(--ansh-content-tertiary)",
|
|
520
|
+
disabled: "var(--ansh-content-disabled)",
|
|
521
|
+
"on-accent": "var(--ansh-content-on-accent)",
|
|
522
|
+
inverse: "var(--ansh-content-inverse)"
|
|
523
|
+
},
|
|
524
|
+
line: {
|
|
525
|
+
subtle: "var(--ansh-border-subtle)",
|
|
526
|
+
DEFAULT: "var(--ansh-border-default)",
|
|
527
|
+
strong: "var(--ansh-border-strong)",
|
|
528
|
+
focus: "var(--ansh-border-focus)"
|
|
529
|
+
},
|
|
530
|
+
accent: {
|
|
531
|
+
subtle: "var(--ansh-accent-subtle)",
|
|
532
|
+
muted: "var(--ansh-accent-muted)",
|
|
533
|
+
DEFAULT: "var(--ansh-accent-default)",
|
|
534
|
+
hover: "var(--ansh-accent-hover)",
|
|
535
|
+
active: "var(--ansh-accent-active)",
|
|
536
|
+
text: "var(--ansh-accent-text)"
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
};
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
export { CSS_PREFIX, applyTheme, blur, brand, breakpoint, dark, duration, easing, fontFamily, fontSize, fontWeight, generateCss, light, neutral, radius, resolveTheme, shadow, space, status, structuralVariables, tailwindPreset, themeStyle, themeVariables, themes, tokens, zIndex };
|
|
545
|
+
//# sourceMappingURL=index.js.map
|
|
546
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/primitives.ts","../src/semantic.ts","../src/css.ts","../src/index.ts"],"names":["tokens"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Primitive design tokens.\n *\n * These are the raw values — the vocabulary. Semantic tokens (in `semantic.ts`) map *meaning*\n * onto them, and that indirection is what makes theming possible: `--ansh-surface` can point\n * at `slate.50` in light mode and `slate.950` in dark mode without any component changing.\n *\n * Every scale here is derived from a rule rather than hand-picked, so extending it is\n * unambiguous and a designer can predict what step 9 looks like without checking.\n */\n\n/**\n * Spacing — an 8-point grid with half-steps below 8px.\n *\n * The half-steps matter: 8px is too coarse for optical adjustments like the gap between an icon\n * and its label, and every design system that omits them ends up with arbitrary one-off values.\n * Named by their pixel value at the default root size so `space[4]` is unambiguously 16px.\n */\nexport const space = {\n 0: '0',\n px: '1px',\n 0.5: '0.125rem', // 2px\n 1: '0.25rem', // 4px\n 1.5: '0.375rem', // 6px\n 2: '0.5rem', // 8px\n 3: '0.75rem', // 12px\n 4: '1rem', // 16px\n 5: '1.25rem', // 20px\n 6: '1.5rem', // 24px\n 8: '2rem', // 32px\n 10: '2.5rem', // 40px\n 12: '3rem', // 48px\n 16: '4rem', // 64px\n 20: '5rem', // 80px\n 24: '6rem', // 96px\n 32: '8rem', // 128px\n 40: '10rem', // 160px\n 48: '12rem', // 192px\n 56: '14rem', // 224px\n 64: '16rem', // 256px\n} as const\n\n/**\n * Typography — a modular scale at ratio 1.2 (minor third), rounded to sensible pixel values.\n *\n * 1.2 rather than the more common 1.25 or golden ratio: on the wide viewports these components\n * target, a steeper ratio makes display sizes enormous before the body sizes have room to\n * differentiate. 1.2 gives eight useful steps between 12px and 60px.\n *\n * Each step pairs a size with a line height, because a size without its leading is not a\n * typographic decision — and line height must *decrease* proportionally as size increases.\n */\nexport const fontSize = {\n xs: ['0.75rem', { lineHeight: '1.125rem', letterSpacing: '0.01em' }],\n sm: ['0.875rem', { lineHeight: '1.375rem', letterSpacing: '0.005em' }],\n base: ['1rem', { lineHeight: '1.625rem', letterSpacing: '0' }],\n lg: ['1.125rem', { lineHeight: '1.75rem', letterSpacing: '-0.005em' }],\n xl: ['1.25rem', { lineHeight: '1.875rem', letterSpacing: '-0.01em' }],\n '2xl': ['1.5rem', { lineHeight: '2rem', letterSpacing: '-0.015em' }],\n '3xl': ['1.875rem', { lineHeight: '2.375rem', letterSpacing: '-0.02em' }],\n '4xl': ['2.25rem', { lineHeight: '2.625rem', letterSpacing: '-0.025em' }],\n '5xl': ['3rem', { lineHeight: '3.25rem', letterSpacing: '-0.03em' }],\n '6xl': ['3.75rem', { lineHeight: '3.9rem', letterSpacing: '-0.035em' }],\n '7xl': ['4.5rem', { lineHeight: '4.6rem', letterSpacing: '-0.04em' }],\n} as const satisfies Record<\n string,\n readonly [string, { lineHeight: string; letterSpacing: string }]\n>\n\nexport const fontWeight = {\n normal: '400',\n medium: '500',\n semibold: '600',\n bold: '700',\n} as const\n\nexport const fontFamily = {\n /**\n * The system UI stack. Deliberately not a webfont: the fastest, most legible text on any\n * platform is the font the user's OS already has loaded, and a design system should not force\n * a font decision on its consumers.\n */\n sans: [\n 'ui-sans-serif',\n 'system-ui',\n '-apple-system',\n 'BlinkMacSystemFont',\n 'Segoe UI',\n 'Roboto',\n 'Helvetica Neue',\n 'Arial',\n 'sans-serif',\n ].join(', '),\n mono: [\n 'ui-monospace',\n 'SFMono-Regular',\n 'Menlo',\n 'Monaco',\n 'Consolas',\n 'Liberation Mono',\n 'Courier New',\n 'monospace',\n ].join(', '),\n} as const\n\n/** Corner radii. `full` is a large fixed value rather than 50%, so pills stay pill-shaped. */\nexport const radius = {\n none: '0',\n xs: '0.25rem', // 4px\n sm: '0.375rem', // 6px\n md: '0.5rem', // 8px\n lg: '0.75rem', // 12px\n xl: '1rem', // 16px\n '2xl': '1.5rem', // 24px\n '3xl': '2rem', // 32px\n full: '9999px',\n} as const\n\n/**\n * Elevation — layered shadows, not single ones.\n *\n * A single `box-shadow` cannot describe real light: an object casts both a tight contact shadow\n * directly beneath it and a broader ambient shadow further out. Every step here composes both,\n * which is the difference between a card that sits on the page and one that looks pasted onto it.\n *\n * Shadow colour is a token so it can shift with the theme — a pure-black shadow on a dark\n * surface is invisible, so the dark theme uses a deeper, more spread variant.\n */\nexport const shadow = {\n none: 'none',\n xs: '0 1px 2px 0 var(--ansh-shadow-color, rgb(15 23 42 / 0.05))',\n sm:\n '0 1px 3px 0 var(--ansh-shadow-color, rgb(15 23 42 / 0.08)), ' +\n '0 1px 2px -1px var(--ansh-shadow-color, rgb(15 23 42 / 0.06))',\n md:\n '0 4px 6px -1px var(--ansh-shadow-color, rgb(15 23 42 / 0.08)), ' +\n '0 2px 4px -2px var(--ansh-shadow-color, rgb(15 23 42 / 0.06))',\n lg:\n '0 10px 15px -3px var(--ansh-shadow-color, rgb(15 23 42 / 0.08)), ' +\n '0 4px 6px -4px var(--ansh-shadow-color, rgb(15 23 42 / 0.05))',\n xl:\n '0 20px 25px -5px var(--ansh-shadow-color, rgb(15 23 42 / 0.1)), ' +\n '0 8px 10px -6px var(--ansh-shadow-color, rgb(15 23 42 / 0.05))',\n '2xl': '0 25px 50px -12px var(--ansh-shadow-color, rgb(15 23 42 / 0.2))',\n /** Inset — for pressed states and inputs. */\n inner: 'inset 0 2px 4px 0 var(--ansh-shadow-color, rgb(15 23 42 / 0.06))',\n /**\n * Glow. Uses `currentColor` so a button's glow automatically matches its own accent without\n * the author repeating the colour.\n */\n glow: '0 0 24px -4px currentColor',\n glowLg: '0 0 48px -8px currentColor',\n} as const\n\n/** Backdrop blur steps, for glass surfaces. */\nexport const blur = {\n none: '0',\n xs: '2px',\n sm: '4px',\n md: '8px',\n lg: '16px',\n xl: '24px',\n '2xl': '40px',\n '3xl': '64px',\n} as const\n\n/**\n * Motion durations in seconds.\n *\n * Named by intent rather than by number. The values follow a rule of thumb that holds up well:\n * the distance travelled should determine the duration, so a tooltip appearing in place is\n * `instant`, a dropdown is `fast`, and a full-screen sheet is `slow`.\n */\nexport const duration = {\n instant: '0.1s',\n fast: '0.2s',\n normal: '0.3s',\n moderate: '0.45s',\n slow: '0.6s',\n slower: '0.9s',\n deliberate: '1.2s',\n} as const\n\n/**\n * CSS timing functions matching the engine's `signature` easings exactly.\n *\n * Keeping these in lockstep means a CSS transition and a JS animation on the same element move\n * identically — which matters more than it sounds, because mismatched curves on adjacent\n * elements is one of those things that reads as \"cheap\" without the viewer knowing why.\n */\nexport const easing = {\n linear: 'linear',\n standard: 'cubic-bezier(0.4, 0, 0.2, 1)',\n emphasized: 'cubic-bezier(0.22, 1, 0.36, 1)',\n enter: 'cubic-bezier(0, 0, 0.2, 1)',\n exit: 'cubic-bezier(0.4, 0, 1, 1)',\n overshoot: 'cubic-bezier(0.34, 1.56, 0.64, 1)',\n cinematic: 'cubic-bezier(0.16, 1, 0.3, 1)',\n} as const\n\n/**\n * Z-index scale.\n *\n * Sparse, deliberate values with names. The alternative — `z-index: 9999` scattered through a\n * codebase — is the single most common source of stacking bugs in a component library.\n */\nexport const zIndex = {\n hide: '-1',\n base: '0',\n raised: '10',\n dropdown: '1000',\n sticky: '1100',\n overlay: '1200',\n modal: '1300',\n popover: '1400',\n toast: '1500',\n tooltip: '1600',\n /** Reserved for skip links and focus traps, which must beat everything. */\n max: '2147483647',\n} as const\n\n/** Breakpoints, matching the widths where real layout decisions occur. */\nexport const breakpoint = {\n sm: '640px',\n md: '768px',\n lg: '1024px',\n xl: '1280px',\n '2xl': '1536px',\n} as const\n\n/**\n * Neutral ramp, defined in OKLCH.\n *\n * Lightness steps are perceptually even, which a hex-defined grey ramp never is — the usual\n * result is a scale that looks well-spaced at the light end and bunched at the dark end. A slight\n * blue chroma (hue 264) keeps it from reading as muddy against saturated accents.\n */\nexport const neutral = {\n 50: 'oklch(98.5% 0.002 264)',\n 100: 'oklch(96.8% 0.004 264)',\n 200: 'oklch(92.9% 0.007 264)',\n 300: 'oklch(86.9% 0.011 264)',\n 400: 'oklch(70.7% 0.018 264)',\n 500: 'oklch(55.4% 0.022 264)',\n 600: 'oklch(44.6% 0.021 264)',\n 700: 'oklch(37.2% 0.019 264)',\n 800: 'oklch(27.9% 0.017 264)',\n 900: 'oklch(20.8% 0.015 264)',\n 950: 'oklch(13.8% 0.014 264)',\n 1000: 'oklch(8.5% 0.012 264)',\n} as const\n\n/** The Ansh brand ramp — the blue the library ships with. */\nexport const brand = {\n 50: 'oklch(97% 0.017 253)',\n 100: 'oklch(93.8% 0.036 253)',\n 200: 'oklch(88.5% 0.069 253)',\n 300: 'oklch(80.9% 0.111 253)',\n 400: 'oklch(71.4% 0.153 253)',\n 500: 'oklch(62.3% 0.188 253)',\n 600: 'oklch(54.6% 0.208 253)',\n 700: 'oklch(46.4% 0.192 253)',\n 800: 'oklch(39.1% 0.16 253)',\n 900: 'oklch(33.5% 0.129 253)',\n 950: 'oklch(23.2% 0.093 253)',\n} as const\n\n/** Status ramps. Only the steps that get used are defined, rather than a full 11 for each. */\nexport const status = {\n success: {\n subtle: 'oklch(95.5% 0.035 155)',\n default: 'oklch(58% 0.15 155)',\n strong: 'oklch(44% 0.12 155)',\n },\n warning: {\n subtle: 'oklch(96.5% 0.045 85)',\n default: 'oklch(72% 0.16 75)',\n strong: 'oklch(52% 0.13 65)',\n },\n danger: {\n subtle: 'oklch(95.5% 0.03 25)',\n default: 'oklch(58% 0.21 25)',\n strong: 'oklch(46% 0.18 25)',\n },\n info: {\n subtle: 'oklch(96% 0.025 240)',\n default: 'oklch(62% 0.17 245)',\n strong: 'oklch(48% 0.15 250)',\n },\n} as const\n","import { brand, neutral, shadow, status } from './primitives'\n\n/**\n * Semantic tokens — meaning mapped onto primitives.\n *\n * This layer is why theming works. A component references `surface.raised`, never `neutral.100`.\n * Switching to dark mode remaps `surface.raised` to `neutral.900`, and every component follows\n * without a single change. A component that reaches past this layer to a primitive is a bug: it\n * will look wrong in one theme and nobody will notice until a user reports it.\n *\n * The naming follows a consistent pattern:\n *\n * - `surface.*` — backgrounds, ordered by elevation\n * - `content.*` — text and icons, ordered by prominence\n * - `border.*` — dividers and outlines, ordered by strength\n * - `accent.*` — the interactive brand colour and its states\n * - `state.*` — success/warning/danger/info\n */\n\nexport interface SemanticTokens {\n surface: {\n /** The page background. */\n canvas: string\n /** Cards and panels sitting on the canvas. */\n raised: string\n /** Menus, popovers and anything floating above `raised`. */\n overlay: string\n /** Subtly recessed areas — code blocks, well insets. */\n sunken: string\n /** Translucent glass surface, for use with `backdrop-filter`. */\n glass: string\n /** The scrim behind a modal. */\n scrim: string\n }\n content: {\n /** Body text and headings. Must reach 7:1 against `surface.canvas`. */\n primary: string\n /** Supporting text. Must reach 4.5:1. */\n secondary: string\n /** De-emphasised text — timestamps, captions. Must reach 4.5:1 at ≥14px. */\n tertiary: string\n /** Placeholder and disabled text. Exempt from contrast minimums by WCAG. */\n disabled: string\n /** Text placed on top of `accent.default`. */\n onAccent: string\n /** Inverted text, for use on `content.primary` as a background. */\n inverse: string\n }\n border: {\n /** Hairline dividers. */\n subtle: string\n /** Input and card outlines. */\n default: string\n /** Hovered or emphasised outlines. */\n strong: string\n /** The focus ring. Must reach 3:1 against both adjacent surfaces. */\n focus: string\n }\n accent: {\n subtle: string\n muted: string\n default: string\n hover: string\n active: string\n /** For text and icons rendered in the accent colour on a neutral surface. */\n text: string\n }\n state: {\n successSubtle: string\n success: string\n warningSubtle: string\n warning: string\n dangerSubtle: string\n danger: string\n infoSubtle: string\n info: string\n }\n /** The shadow colour the elevation scale multiplies through. */\n shadowColor: string\n}\n\n/**\n * Light theme.\n *\n * Contrast ratios against `surface.canvas` (`neutral.50`):\n * `content.primary` → 15.8:1 (AAA)\n * `content.secondary` → 7.4:1 (AAA)\n * `content.tertiary` → 4.7:1 (AA)\n * `border.focus` → 3.4:1 (AA non-text)\n */\nexport const light: SemanticTokens = {\n surface: {\n canvas: neutral[50],\n raised: '#ffffff',\n overlay: '#ffffff',\n sunken: neutral[100],\n glass: 'oklch(100% 0 0 / 0.72)',\n scrim: 'oklch(20.8% 0.015 264 / 0.45)',\n },\n content: {\n primary: neutral[900],\n secondary: neutral[600],\n tertiary: neutral[500],\n disabled: neutral[400],\n onAccent: '#ffffff',\n inverse: neutral[50],\n },\n border: {\n subtle: neutral[200],\n default: neutral[300],\n strong: neutral[400],\n focus: brand[600],\n },\n accent: {\n subtle: brand[50],\n muted: brand[100],\n default: brand[600],\n hover: brand[700],\n active: brand[800],\n // A step darker than `default`: brand colours tuned to look right as a fill are usually too\n // light to pass contrast as text on a white surface.\n text: brand[700],\n },\n state: {\n successSubtle: status.success.subtle,\n success: status.success.strong,\n warningSubtle: status.warning.subtle,\n warning: status.warning.strong,\n dangerSubtle: status.danger.subtle,\n danger: status.danger.strong,\n infoSubtle: status.info.subtle,\n info: status.info.strong,\n },\n shadowColor: 'oklch(20.8% 0.015 264 / 0.08)',\n}\n\n/**\n * Dark theme.\n *\n * Not an inversion of `light`. Three adjustments that a mechanical inversion misses:\n *\n * 1. **Surfaces get lighter as they rise, not darker.** In light mode, elevation is signalled by\n * shadow. On a dark background shadow is invisible, so elevation must be signalled by the\n * surface itself becoming lighter.\n * 2. **Chroma is raised.** Saturated colours read as less vivid against dark backgrounds\n * (Helmholtz–Kohlrausch), so accents step *lighter* rather than mirroring their light-mode step.\n * 3. **Body text is not pure white.** `#fff` on a near-black background causes halation — the\n * text appears to bleed. `neutral.100` reads as white while staying comfortable.\n */\nexport const dark: SemanticTokens = {\n surface: {\n canvas: neutral[1000],\n raised: neutral[950],\n overlay: neutral[900],\n sunken: 'oklch(6% 0.01 264)',\n glass: 'oklch(13.8% 0.014 264 / 0.68)',\n scrim: 'oklch(4% 0.008 264 / 0.65)',\n },\n content: {\n primary: neutral[100],\n secondary: neutral[300],\n tertiary: neutral[400],\n disabled: neutral[600],\n onAccent: '#ffffff',\n inverse: neutral[950],\n },\n border: {\n // Borders on dark surfaces work by being *lighter* than the surface, and need less contrast\n // than their light-mode counterparts to read as the same weight.\n subtle: 'oklch(100% 0 0 / 0.08)',\n default: 'oklch(100% 0 0 / 0.14)',\n strong: 'oklch(100% 0 0 / 0.24)',\n focus: brand[400],\n },\n accent: {\n subtle: 'oklch(23.2% 0.093 253 / 0.4)',\n muted: brand[950],\n default: brand[500],\n hover: brand[400],\n active: brand[300],\n text: brand[300],\n },\n state: {\n successSubtle: 'oklch(30% 0.08 155 / 0.35)',\n success: 'oklch(72% 0.16 155)',\n warningSubtle: 'oklch(32% 0.09 75 / 0.35)',\n warning: 'oklch(80% 0.15 80)',\n dangerSubtle: 'oklch(30% 0.11 25 / 0.35)',\n danger: 'oklch(70% 0.19 25)',\n infoSubtle: 'oklch(30% 0.09 245 / 0.35)',\n info: 'oklch(74% 0.15 245)',\n },\n // Deeper and more spread than light mode, since a dark shadow on a dark surface needs more\n // opacity to register at all.\n shadowColor: 'oklch(0% 0 0 / 0.5)',\n}\n\nexport const themes = { light, dark } as const\nexport type ThemeName = keyof typeof themes\n\n/** Re-exported so the CSS emitter can reference the elevation scale alongside the themes. */\nexport { shadow }\n","import {\n blur,\n breakpoint,\n duration,\n easing,\n fontFamily,\n fontSize,\n fontWeight,\n radius,\n shadow,\n space,\n zIndex,\n} from './primitives'\nimport { type SemanticTokens, dark, light } from './semantic'\n\n/**\n * CSS custom property generation.\n *\n * Tokens exist twice on purpose — as TypeScript values and as CSS variables — because the two\n * are consumed differently and neither can serve both jobs:\n *\n * - **TypeScript** values are needed where JavaScript computes with them: passing colours into\n * canvas effects, deriving palettes, computing contrast.\n * - **CSS variables** are needed for everything the cascade should own: theming a subtree,\n * respecting `prefers-color-scheme`, and letting a consumer override a token in their own\n * stylesheet without touching a build step.\n *\n * This module is the bridge, and it is generated from the same source of truth so the two can't\n * drift.\n */\n\nexport const CSS_PREFIX = 'ansh'\n\n/** Flatten a nested token object into `--prefix-path-to-key` variable declarations. */\nfunction flatten(target: Map<string, string>, value: unknown, path: readonly string[]): void {\n if (typeof value === 'string') {\n target.set(`--${CSS_PREFIX}-${path.join('-')}`, value)\n return\n }\n if (Array.isArray(value)) {\n // Font size entries are `[size, { lineHeight, letterSpacing }]`. Emit each part under a\n // suffixed name so `--ansh-text-lg` and `--ansh-text-lg-leading` are both available.\n const [size, meta] = value as [string, Record<string, string> | undefined]\n target.set(`--${CSS_PREFIX}-${path.join('-')}`, size)\n if (meta && typeof meta === 'object') {\n if (meta.lineHeight) {\n target.set(`--${CSS_PREFIX}-${path.join('-')}-leading`, meta.lineHeight)\n }\n if (meta.letterSpacing) {\n target.set(`--${CSS_PREFIX}-${path.join('-')}-tracking`, meta.letterSpacing)\n }\n }\n return\n }\n if (value && typeof value === 'object') {\n for (const [key, child] of Object.entries(value)) {\n flatten(target, child, [...path, cssSegment(key)])\n }\n }\n}\n\n/**\n * Convert a token key into a CSS-safe, CSS-conventional name segment.\n *\n * Two transformations, each fixing a real problem:\n *\n * - **Decimal points** (`space[0.5]`) are invalid in a custom property name, so they become\n * hyphens: `--ansh-space-0-5`.\n * - **camelCase** (`onAccent`, `successSubtle`) becomes kebab-case. CSS custom properties are\n * case-sensitive, and nobody writing CSS types `var(--ansh-content-onAccent)` — they type\n * `--ansh-content-on-accent`, get no error, and silently inherit the wrong colour. That\n * exact mismatch shipped in this library's own button styles: filled buttons fell back to the\n * inherited text colour, which is dark text on an accent fill.\n */\nfunction cssSegment(key: string): string {\n return key\n .replace('.', '-')\n .replace(/([a-z0-9])([A-Z])/g, '$1-$2')\n .toLowerCase()\n}\n\n/** Structural tokens — identical in every theme. */\nexport function structuralVariables(): Map<string, string> {\n const out = new Map<string, string>()\n flatten(out, space, ['space'])\n flatten(out, radius, ['radius'])\n flatten(out, shadow, ['shadow'])\n flatten(out, blur, ['blur'])\n flatten(out, duration, ['duration'])\n flatten(out, easing, ['ease'])\n flatten(out, zIndex, ['z'])\n flatten(out, fontSize, ['text'])\n flatten(out, fontWeight, ['weight'])\n flatten(out, fontFamily, ['font'])\n flatten(out, breakpoint, ['screen'])\n return out\n}\n\n/** Theme-dependent tokens for one theme. */\nexport function themeVariables(tokens: SemanticTokens): Map<string, string> {\n const out = new Map<string, string>()\n flatten(out, tokens.surface, ['surface'])\n flatten(out, tokens.content, ['content'])\n flatten(out, tokens.border, ['border'])\n flatten(out, tokens.accent, ['accent'])\n flatten(out, tokens.state, ['state'])\n out.set(`--${CSS_PREFIX}-shadow-color`, tokens.shadowColor)\n return out\n}\n\nfunction declarations(variables: Map<string, string>, indent = ' '): string {\n return [...variables].map(([name, value]) => `${indent}${name}: ${value};`).join('\\n')\n}\n\n/**\n * Emit the complete stylesheet.\n *\n * The theming strategy is deliberately layered so it works for every consumer:\n *\n * 1. `:root` carries the light theme, so the default works with no configuration.\n * 2. `@media (prefers-color-scheme: dark)` applies dark automatically — but *only* when the\n * document has not opted into manual control, guarded by `:root:not([data-theme])`. Without\n * that guard, a user who explicitly chose light mode in an app whose OS is dark would get dark\n * anyway, which is the single most common theming bug in the wild.\n * 3. `[data-theme='dark']` and `[data-theme='light']` allow explicit control at any level of the\n * tree, so a single dark card on a light page works with no extra plumbing.\n */\nexport function generateCss(): string {\n const structural = structuralVariables()\n const lightVars = themeVariables(light)\n const darkVars = themeVariables(dark)\n\n return `/**\n * Ansh design tokens.\n *\n * Generated from @ansh-ui/tokens — do not edit by hand.\n * Override any variable in your own stylesheet after importing this file.\n */\n\n:root {\n color-scheme: light dark;\n\n${declarations(structural)}\n\n${declarations(lightVars)}\n}\n\n/* Automatic dark mode, only when the document has not opted into manual control. */\n@media (prefers-color-scheme: dark) {\n :root:not([data-theme]) {\n${declarations(darkVars, ' ')}\n }\n}\n\n/* Explicit theme control. Works at any level of the tree, not just :root. */\n[data-theme='dark'] {\n${declarations(darkVars)}\n}\n\n[data-theme='light'] {\n${declarations(lightVars)}\n}\n\n/**\n * Reduced-motion safety net.\n *\n * The engine honours \\`prefers-reduced-motion\\` in JavaScript, but any CSS transition or\n * animation an application author writes is outside its reach. Neutralising them here means a\n * consumer gets correct behaviour for their own styles too, simply by importing this file.\n *\n * Durations are set to 0.01ms rather than 0 so that \\`transitionend\\` and \\`animationend\\` still\n * fire — code that waits on those events would otherwise hang forever.\n */\n@media (prefers-reduced-motion: reduce) {\n *,\n *::before,\n *::after {\n animation-duration: 0.01ms !important;\n animation-iteration-count: 1 !important;\n transition-duration: 0.01ms !important;\n scroll-behavior: auto !important;\n }\n}\n\n/**\n * Utility classes for the split-text behaviour.\n *\n * The behaviour sets \\`--ansh-index\\` and \\`--ansh-total\\` on every unit, which makes a\n * staggered reveal possible in pure CSS with no JavaScript timing at all.\n */\n.ansh-char,\n.ansh-word,\n.ansh-line {\n display: inline-block;\n /* Required for transforms to apply to inline content, and for masks to clip descenders. */\n will-change: transform, opacity;\n}\n\n.ansh-mask {\n display: inline-block;\n overflow: hidden;\n vertical-align: top;\n}\n`\n}\n\n/**\n * Apply a theme imperatively.\n *\n * Sets `data-theme` on the target, which the stylesheet above already understands. Prefer this\n * over injecting inline styles: it keeps every token in one cascade layer and lets the browser\n * do the work.\n *\n * @param theme `'light'`, `'dark'`, or `'system'` to hand control back to `prefers-color-scheme`.\n * @param target Defaults to `document.documentElement`. Pass an element to theme a subtree.\n */\nexport function applyTheme(theme: 'light' | 'dark' | 'system', target?: HTMLElement): void {\n if (typeof document === 'undefined') return\n const element = target ?? document.documentElement\n if (theme === 'system') element.removeAttribute('data-theme')\n else element.setAttribute('data-theme', theme)\n}\n\n/**\n * Read the currently applied theme.\n *\n * Resolves `'system'` to whichever theme is actually in effect, because callers generally want to\n * know what the user is *seeing*, not how it was configured.\n */\nexport function resolveTheme(target?: HTMLElement): 'light' | 'dark' {\n if (typeof document === 'undefined') return 'light'\n const element = target ?? document.documentElement\n const explicit = element.closest('[data-theme]')?.getAttribute('data-theme')\n if (explicit === 'dark' || explicit === 'light') return explicit\n return typeof matchMedia === 'function' && matchMedia('(prefers-color-scheme: dark)').matches\n ? 'dark'\n : 'light'\n}\n\n/**\n * Build an inline `style` object for a subtree override.\n *\n * Used by framework `<ThemeProvider>` components that need to apply a theme before the stylesheet\n * has necessarily loaded — during SSR, most importantly, where a flash of the wrong theme is\n * otherwise unavoidable.\n */\nexport function themeStyle(theme: 'light' | 'dark'): Record<string, string> {\n const out: Record<string, string> = {}\n for (const [name, value] of themeVariables(theme === 'dark' ? dark : light)) {\n out[name] = value\n }\n return out\n}\n","/**\n * @ansh-ui/tokens — the Ansh design language.\n *\n * Tokens are exported both as TypeScript values (for code that computes with them) and as CSS\n * custom properties (for everything the cascade should own). Both are generated from the same\n * source, so they cannot drift.\n *\n * ```ts\n * import '@ansh-ui/tokens/ansh.css'\n * import { space, applyTheme } from '@ansh-ui/tokens'\n * ```\n */\n\nexport * from './primitives'\nexport * from './semantic'\nexport * from './css'\n\nimport {\n blur,\n breakpoint,\n duration,\n easing,\n fontFamily,\n fontSize,\n fontWeight,\n radius,\n shadow,\n space,\n zIndex,\n} from './primitives'\n\n/**\n * Every structural token in one object.\n *\n * Convenient for a Tailwind preset or a styled-components theme, where the consumer wants the\n * whole scale rather than individual imports.\n */\nexport const tokens = {\n space,\n radius,\n shadow,\n blur,\n duration,\n easing,\n zIndex,\n fontSize,\n fontWeight,\n fontFamily,\n breakpoint,\n} as const\n\nexport type Tokens = typeof tokens\n\n/**\n * A Tailwind CSS preset that maps Ansh tokens onto Tailwind's theme keys.\n *\n * Returned as a plain object rather than importing Tailwind types, so this package stays free of a\n * Tailwind dependency for the majority of consumers who don't use it.\n *\n * ```js\n * // tailwind.config.js\n * import { tailwindPreset } from '@ansh-ui/tokens'\n * export default { presets: [tailwindPreset()] }\n * ```\n */\nexport function tailwindPreset() {\n return {\n theme: {\n extend: {\n spacing: space,\n borderRadius: radius,\n boxShadow: shadow,\n blur,\n fontFamily: { sans: [fontFamily.sans], mono: [fontFamily.mono] },\n fontSize,\n fontWeight,\n screens: breakpoint,\n zIndex,\n transitionDuration: Object.fromEntries(\n Object.entries(duration).map(([key, value]) => [key, value]),\n ),\n transitionTimingFunction: easing,\n // Semantic colours are wired to the CSS variables rather than to literal values, so a\n // Tailwind class like `bg-surface-raised` follows the active theme automatically.\n colors: {\n surface: {\n canvas: 'var(--ansh-surface-canvas)',\n raised: 'var(--ansh-surface-raised)',\n overlay: 'var(--ansh-surface-overlay)',\n sunken: 'var(--ansh-surface-sunken)',\n glass: 'var(--ansh-surface-glass)',\n },\n content: {\n primary: 'var(--ansh-content-primary)',\n secondary: 'var(--ansh-content-secondary)',\n tertiary: 'var(--ansh-content-tertiary)',\n disabled: 'var(--ansh-content-disabled)',\n 'on-accent': 'var(--ansh-content-on-accent)',\n inverse: 'var(--ansh-content-inverse)',\n },\n line: {\n subtle: 'var(--ansh-border-subtle)',\n DEFAULT: 'var(--ansh-border-default)',\n strong: 'var(--ansh-border-strong)',\n focus: 'var(--ansh-border-focus)',\n },\n accent: {\n subtle: 'var(--ansh-accent-subtle)',\n muted: 'var(--ansh-accent-muted)',\n DEFAULT: 'var(--ansh-accent-default)',\n hover: 'var(--ansh-accent-hover)',\n active: 'var(--ansh-accent-active)',\n text: 'var(--ansh-accent-text)',\n },\n },\n },\n },\n }\n}\n"]}
|