@tenphi/glaze 0.0.0-snapshot.c13086f → 0.0.0-snapshot.c61bbdf
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/AGENTS.md +158 -0
- package/README.md +106 -1015
- package/dist/index.cjs +3991 -973
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1559 -157
- package/dist/index.d.mts +1559 -157
- package/dist/index.mjs +3959 -973
- package/dist/index.mjs.map +1 -1
- package/docs/contrast.mdx +702 -0
- package/docs/exporting.mdx +624 -0
- package/docs/getting-started.mdx +486 -0
- package/docs/methodology.mdx +973 -0
- package/docs/migration.md +278 -0
- package/docs/mixes.mdx +268 -0
- package/docs/okhst.mdx +596 -0
- package/docs/reference/color-definitions.md +498 -0
- package/docs/reference/color-tokens.md +390 -0
- package/docs/reference/configuration.md +437 -0
- package/docs/reference/contrast.md +276 -0
- package/docs/reference/index.md +218 -0
- package/docs/reference/output.md +594 -0
- package/docs/reference/palette.md +387 -0
- package/docs/reference/theme.md +326 -0
- package/docs/reference/utilities.md +499 -0
- package/docs/schemes.mdx +546 -0
- package/docs/shadows-and-glows.mdx +509 -0
- package/package.json +18 -9
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Palettes
|
|
3
|
+
description: glaze.palette() — composing themes into one token namespace, prefixes, collisions, the primary alias, and palette snapshots.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
A palette composes several [themes](./theme.md) into a single token namespace: one `tokens()` / `css()` / `tailwind()` call emits every theme, each under its own prefix. How to choose a prefix strategy for an app is covered in [Exporting and integration](../exporting.mdx).
|
|
7
|
+
|
|
8
|
+
## `glaze.palette(themes, options?)`
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import { glaze } from '@tenphi/glaze';
|
|
12
|
+
|
|
13
|
+
const primary = glaze(280, 80);
|
|
14
|
+
primary.colors({
|
|
15
|
+
surface: { tone: 97 },
|
|
16
|
+
'surface-text': { base: 'surface', tone: '-52', contrast: 'AA' },
|
|
17
|
+
accent: { tone: 52, mode: 'fixed' },
|
|
18
|
+
});
|
|
19
|
+
const danger = primary.extend({ hue: 23 });
|
|
20
|
+
const success = primary.extend({ hue: 145 });
|
|
21
|
+
|
|
22
|
+
const palette = glaze.palette({ primary, danger, success });
|
|
23
|
+
const withAlias = glaze.palette(
|
|
24
|
+
{ primary, danger, success },
|
|
25
|
+
{ primary: 'primary' },
|
|
26
|
+
);
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
| Parameter | Type | Description |
|
|
30
|
+
| --- | --- | --- |
|
|
31
|
+
| `themes` | `Record<string, GlazeTheme>` | Themes keyed by name. The name becomes the default token prefix (`<name>-`). Insertion order is the output order. |
|
|
32
|
+
| `options` | `GlazePaletteOptions` | Optional. |
|
|
33
|
+
|
|
34
|
+
`GlazePaletteOptions`:
|
|
35
|
+
|
|
36
|
+
| Option | Type | Description |
|
|
37
|
+
| --- | --- | --- |
|
|
38
|
+
| `primary` | `string` | Name of the primary theme. Its tokens are also emitted **without** a prefix in every output method except `json()`, as short aliases next to the prefixed ones. See [Primary theme aliases](#primary-theme-aliases). Throws `glaze: primary theme "<name>" not found in palette. Available: <names>.` when no theme has that name. |
|
|
39
|
+
|
|
40
|
+
The palette holds the theme instances you pass, not copies: changing a theme later changes the palette's next export.
|
|
41
|
+
|
|
42
|
+
## Palette members
|
|
43
|
+
|
|
44
|
+
| Member | Description |
|
|
45
|
+
| --- | --- |
|
|
46
|
+
| `palette.list()` | Theme names in insertion order. |
|
|
47
|
+
| `palette.primary` | The primary theme name set at creation, or `undefined`. Readonly. |
|
|
48
|
+
| `palette.theme(name)` | The live theme instance with that name, or `undefined`. |
|
|
49
|
+
| `palette.themes()` | Shallow copy of the theme map. The values are the same instances the palette holds. |
|
|
50
|
+
| `palette.export(override?)` | Authoring snapshot, restorable with `glaze.paletteFrom()`. See [below](#paletteexportoverride--glazepalettefromdata). |
|
|
51
|
+
| `palette.tokens(options?)` | Flat token map grouped by scheme variant. |
|
|
52
|
+
| `palette.tasty(options?)` | [Tasty](https://tasty.style) style-to-state bindings. |
|
|
53
|
+
| `palette.json(options?)` | Per-theme resolved color JSON. Not restorable as authoring config. |
|
|
54
|
+
| `palette.css(options?)` | CSS custom property declaration strings. |
|
|
55
|
+
| `palette.dtcg(options?)` | Per-scheme W3C DTCG token documents. |
|
|
56
|
+
| `palette.dtcgResolver(options?)` | One DTCG Resolver-Module document for every scheme. |
|
|
57
|
+
| `palette.tailwind(options?)` | One Tailwind CSS v4 theme with scheme overrides. |
|
|
58
|
+
|
|
59
|
+
## `palette.export(override?)` / `glaze.paletteFrom(data)`
|
|
60
|
+
|
|
61
|
+
`palette.export()` returns a JSON-safe authoring snapshot: each theme's [`theme.export()`](./theme.md#themeexportoverride) plus the primary name. The optional `override` (`GlazeConfigOverride`) is forwarded to every nested `theme.export(override)`.
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
const snapshot = withAlias.export();
|
|
65
|
+
// → {
|
|
66
|
+
// kind: 'palette',
|
|
67
|
+
// version: 2,
|
|
68
|
+
// themes: {
|
|
69
|
+
// primary: {
|
|
70
|
+
// kind: 'theme',
|
|
71
|
+
// version: 2,
|
|
72
|
+
// hue: 280,
|
|
73
|
+
// saturation: 80,
|
|
74
|
+
// colors: {…},
|
|
75
|
+
// config: {…},
|
|
76
|
+
// },
|
|
77
|
+
// danger: { kind: 'theme', version: 2, hue: 23, … },
|
|
78
|
+
// success: { kind: 'theme', version: 2, hue: 145, … },
|
|
79
|
+
// },
|
|
80
|
+
// primary: 'primary', // omitted when the palette has none
|
|
81
|
+
// }
|
|
82
|
+
|
|
83
|
+
const restored = glaze.paletteFrom(JSON.parse(JSON.stringify(snapshot)));
|
|
84
|
+
const brand = restored.theme('primary')!;
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
`GlazePaletteExport`:
|
|
88
|
+
|
|
89
|
+
| Field | Type | Description |
|
|
90
|
+
| --- | --- | --- |
|
|
91
|
+
| `kind` | `'palette'` | Snapshot kind. Always written. |
|
|
92
|
+
| `version` | `number` | Schema version, `GLAZE_EXPORT_VERSION` (`2`). Always written. |
|
|
93
|
+
| `themes` | `Record<string, GlazeThemeExport>` | One theme snapshot per theme, keyed by name. |
|
|
94
|
+
| `primary` | `string` | The primary theme name. Omitted when the palette has none. |
|
|
95
|
+
|
|
96
|
+
Use `export()` / `paletteFrom()` to persist and restore the authoring graph (themes, color definitions, relations). Use `json()` / `tokens()` / `css()` / … to emit resolved color strings for apps and design tools.
|
|
97
|
+
|
|
98
|
+
`glaze.paletteFrom(data)` rebuilds every theme with the [`themeFrom`](./theme.md#glazethemefromdata--glazefromdata) rules and recreates the palette with the snapshot's `primary`. It throws when:
|
|
99
|
+
|
|
100
|
+
- `data` is not an object, or `kind` is present and not `'palette'`, or `version` is invalid or newer than `GLAZE_EXPORT_VERSION` (messages prefixed `glaze.paletteFrom:`).
|
|
101
|
+
- `themes` is missing or not an object: `glaze.paletteFrom: expected a "themes" object map of theme exports.`
|
|
102
|
+
- A theme entry fails a `themeFrom` check. The message is prefixed with the theme, for example `glaze.paletteFrom (theme "brand"): …`.
|
|
103
|
+
- A theme entry has no `version` of its own, the palette is version `1`, and the entry has shadow colors or a `shadowTuning` — the entry inherits the palette's version for this check. See [Authoring snapshots](./index.md#authoring-snapshots-and-versioning).
|
|
104
|
+
- `primary` names a theme that isn't in `themes`.
|
|
105
|
+
|
|
106
|
+
## `GlazePaletteExportOptions`
|
|
107
|
+
|
|
108
|
+
Every palette output method except `json()` accepts these on top of its own options:
|
|
109
|
+
|
|
110
|
+
| Option | Type | Default | Description |
|
|
111
|
+
| --- | --- | --- | --- |
|
|
112
|
+
| `prefix` | `boolean \| Record<string, string>` | `true` | `true` prefixes each theme's tokens with `"<themeName>-"`. A map sets a custom prefix per theme; themes not in the map fall back to `"<themeName>-"`. `false` disables prefixing. |
|
|
113
|
+
| `primary` | `string \| false` | The palette's `primary` | A theme name sets or changes the primary for this call (throws if no theme has that name). `false` disables the primary alias for this call. |
|
|
114
|
+
| `splitHue` | `boolean` | `false` | Emit hue as separate custom properties. Used by `tasty()` and `css()` only; ignored by the other methods. See [`splitHue` in palettes](#splithue-in-palettes). |
|
|
115
|
+
|
|
116
|
+
Each method's own options:
|
|
117
|
+
|
|
118
|
+
| Method | Own options (type) | Notes |
|
|
119
|
+
| --- | --- | --- |
|
|
120
|
+
| `palette.tokens(options?)` | `format`, `modes` (`GlazeJsonOptions`) | |
|
|
121
|
+
| `palette.tasty(options?)` | `format`, `modes`, `states`, `splitHue` (`GlazeTokenOptions`) | `name` is ignored: the hue var base name is each theme's name. `states` defaults to the global config. |
|
|
122
|
+
| `palette.json(options?)` | `format`, `modes` (`GlazeJsonOptions`) | No prefix, primary, or collision handling — see [`palette.json()`](#palettejson). |
|
|
123
|
+
| `palette.css(options?)` | `format`, `suffix`, `splitHue` (`GlazeCssOptions`) | No `modes`: always returns all four strings. `name` is ignored, as for `tasty()`. |
|
|
124
|
+
| `palette.dtcg(options?)` | `colorSpace`, `modes` (`GlazeDtcgOptions`) | |
|
|
125
|
+
| `palette.dtcgResolver(options?)` | `colorSpace`, `modes`, `setName`, `modifierName`, `contextNames`, `version` (`GlazeDtcgResolverOptions`) | |
|
|
126
|
+
| `palette.tailwind(options?)` | `format`, `modes`, `namespace`, `darkSelector`, `highContrastSelector` (`GlazeTailwindOptions`) | `prefix` (theme prefix) and `namespace` (the `--color-` CSS namespace) are separate options. |
|
|
127
|
+
|
|
128
|
+
The option semantics and defaults are documented once, in [Output formats](./output.md).
|
|
129
|
+
|
|
130
|
+
## Prefix behavior
|
|
131
|
+
|
|
132
|
+
By default every token is prefixed with its theme name:
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
palette.tokens();
|
|
136
|
+
// → {
|
|
137
|
+
// light: {
|
|
138
|
+
// 'primary-surface': 'oklch(0.97 0.0128 280)',
|
|
139
|
+
// 'primary-surface-text': 'oklch(0.5286 0.1912 280)',
|
|
140
|
+
// 'primary-accent': 'oklch(0.5961 0.181 280)',
|
|
141
|
+
// 'danger-surface': 'oklch(0.97 0.0129 23)',
|
|
142
|
+
// …
|
|
143
|
+
// },
|
|
144
|
+
// dark: { … },
|
|
145
|
+
// }
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
A custom map renames some prefixes; any theme not listed falls back to `"<themeName>-"`:
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
palette.tokens({ prefix: { primary: 'brand-', danger: 'error-' } });
|
|
152
|
+
// → 'brand-surface', 'error-surface', 'success-surface', …
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Disable prefixing:
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
palette.tokens({ prefix: false });
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
With `prefix: false`, themes that share color names collide; see the next section.
|
|
162
|
+
|
|
163
|
+
## Collision detection
|
|
164
|
+
|
|
165
|
+
When two themes produce the same output key — through `prefix: false`, a custom prefix map, or the primary's unprefixed aliases — the **first-written value wins** and Glaze logs a `console.warn` for every skipped token:
|
|
166
|
+
|
|
167
|
+
```text
|
|
168
|
+
glaze: token "surface" from theme "danger" collides with theme
|
|
169
|
+
"primary" — skipping.
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Write order is theme insertion order. For each theme, its prefixed tokens are written first and, if it is the primary, its unprefixed aliases immediately after (labeled `"<name> (primary)"` in the warning). So a primary alias wins over a later theme that emits the same unprefixed name.
|
|
173
|
+
|
|
174
|
+
> [!TIP]
|
|
175
|
+
> With `prefix: false`, also pass `primary: false` (or create the palette without a primary). Otherwise the primary's alias pass collides with the primary's own unprefixed tokens and warns once per token.
|
|
176
|
+
|
|
177
|
+
## Primary theme aliases
|
|
178
|
+
|
|
179
|
+
The primary theme's tokens are duplicated without a prefix:
|
|
180
|
+
|
|
181
|
+
```ts
|
|
182
|
+
const palette = glaze.palette(
|
|
183
|
+
{ primary, danger, success },
|
|
184
|
+
{ primary: 'primary' },
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
palette.tokens();
|
|
188
|
+
// → {
|
|
189
|
+
// light: {
|
|
190
|
+
// 'primary-surface': 'oklch(0.97 0.0128 280)',
|
|
191
|
+
// …
|
|
192
|
+
// surface: 'oklch(0.97 0.0128 280)', // unprefixed alias
|
|
193
|
+
// 'surface-text': 'oklch(0.5286 0.1912 280)',
|
|
194
|
+
// accent: 'oklch(0.5961 0.181 280)',
|
|
195
|
+
// 'danger-surface': 'oklch(0.97 0.0129 23)',
|
|
196
|
+
// …
|
|
197
|
+
// },
|
|
198
|
+
// …
|
|
199
|
+
// }
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Override the primary per export:
|
|
203
|
+
|
|
204
|
+
```ts
|
|
205
|
+
// danger's tokens get the unprefixed aliases
|
|
206
|
+
palette.tokens({ primary: 'danger' });
|
|
207
|
+
// no aliases
|
|
208
|
+
palette.tokens({ primary: false });
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
The alias works with any prefix mode. With a custom map, the primary's tokens are still duplicated without a prefix:
|
|
212
|
+
|
|
213
|
+
```ts
|
|
214
|
+
palette.tokens({ prefix: { primary: 'p-', danger: 'd-' } });
|
|
215
|
+
// → 'p-surface' + 'surface' (alias) + 'd-surface' + 'success-surface'
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
The alias applies to `tokens`, `tasty`, `css`, `dtcg`, `dtcgResolver`, and `tailwind` — not `json`.
|
|
219
|
+
|
|
220
|
+
## Palette output methods
|
|
221
|
+
|
|
222
|
+
### `palette.tokens()`
|
|
223
|
+
|
|
224
|
+
Same shape as [`theme.tokens()`](./output.md#tokensoptions), with every theme merged into each variant map.
|
|
225
|
+
|
|
226
|
+
### `palette.tasty()`
|
|
227
|
+
|
|
228
|
+
Same shape as [`theme.tasty()`](./output.md#tastyoptions), with every theme's `#<prefix><name>` keys in one object. State aliases come from the per-call `states` option, then the global config.
|
|
229
|
+
|
|
230
|
+
### `palette.json()`
|
|
231
|
+
|
|
232
|
+
Groups by theme name instead of prefixing, so there is nothing to collide:
|
|
233
|
+
|
|
234
|
+
```ts
|
|
235
|
+
palette.json();
|
|
236
|
+
// → {
|
|
237
|
+
// primary: {
|
|
238
|
+
// surface: {
|
|
239
|
+
// light: 'oklch(0.97 0.0128 280)',
|
|
240
|
+
// dark: 'oklch(0.279 0.1015 280)',
|
|
241
|
+
// },
|
|
242
|
+
// …
|
|
243
|
+
// },
|
|
244
|
+
// danger: {
|
|
245
|
+
// surface: {
|
|
246
|
+
// light: 'oklch(0.97 0.0129 23)',
|
|
247
|
+
// dark: 'oklch(0.279 0.0791 23)',
|
|
248
|
+
// },
|
|
249
|
+
// …
|
|
250
|
+
// },
|
|
251
|
+
// success: { … },
|
|
252
|
+
// }
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Accepts `format` and `modes`. Its type also allows `prefix`, but the value is ignored, and there is no primary alias. The per-theme entries have the [`theme.json()`](./output.md#jsonoptions) shape.
|
|
256
|
+
|
|
257
|
+
### `palette.css()`
|
|
258
|
+
|
|
259
|
+
Accepts `GlazeCssOptions` plus `GlazePaletteExportOptions`. It has no `modes` option: all four strings (`light`, `dark`, `lightContrast`, `darkContrast`) are always returned, each holding every theme's declarations joined by newlines.
|
|
260
|
+
|
|
261
|
+
```ts
|
|
262
|
+
const css = palette.css();
|
|
263
|
+
const stylesheet = `
|
|
264
|
+
:root { ${css.light} }
|
|
265
|
+
@media (prefers-color-scheme: dark) {
|
|
266
|
+
:root { ${css.dark} }
|
|
267
|
+
}
|
|
268
|
+
`;
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### `palette.dtcg()`
|
|
272
|
+
|
|
273
|
+
Accepts `GlazeDtcgOptions` plus `GlazePaletteExportOptions`. Prefix defaults to `true` and the palette `primary` is honored:
|
|
274
|
+
|
|
275
|
+
```ts
|
|
276
|
+
palette.dtcg();
|
|
277
|
+
// → {
|
|
278
|
+
// light: {
|
|
279
|
+
// 'primary-surface': {
|
|
280
|
+
// $type: 'color',
|
|
281
|
+
// $value: {
|
|
282
|
+
// colorSpace: 'srgb',
|
|
283
|
+
// components: […],
|
|
284
|
+
// hex: '#f3f4fe',
|
|
285
|
+
// },
|
|
286
|
+
// },
|
|
287
|
+
// …
|
|
288
|
+
// surface: { …, $value: { …, hex: '#f3f4fe' } }, // unprefixed alias
|
|
289
|
+
// …
|
|
290
|
+
// 'danger-surface': { …, $value: { …, hex: '#fef2f1' } },
|
|
291
|
+
// …
|
|
292
|
+
// },
|
|
293
|
+
// dark: { … },
|
|
294
|
+
// }
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
### `palette.dtcgResolver()`
|
|
298
|
+
|
|
299
|
+
Same document as [`theme.dtcgResolver()`](./output.md#dtcgresolveroptions), with every theme (prefixed, plus primary aliases) merged into the single `sets.base` source and into each `scheme` context. Accepts `GlazeDtcgResolverOptions` plus `GlazePaletteExportOptions`.
|
|
300
|
+
|
|
301
|
+
```ts
|
|
302
|
+
palette.dtcgResolver();
|
|
303
|
+
// → {
|
|
304
|
+
// version: '2025.10',
|
|
305
|
+
// sets: {
|
|
306
|
+
// base: {
|
|
307
|
+
// sources: [
|
|
308
|
+
// {
|
|
309
|
+
// 'primary-surface': {…},
|
|
310
|
+
// …
|
|
311
|
+
// surface: {…},
|
|
312
|
+
// …
|
|
313
|
+
// 'danger-surface': {…},
|
|
314
|
+
// …
|
|
315
|
+
// },
|
|
316
|
+
// ],
|
|
317
|
+
// },
|
|
318
|
+
// },
|
|
319
|
+
// modifiers: {
|
|
320
|
+
// scheme: {
|
|
321
|
+
// default: 'light',
|
|
322
|
+
// contexts: { light: [], dark: [{ … }] },
|
|
323
|
+
// },
|
|
324
|
+
// },
|
|
325
|
+
// resolutionOrder: [
|
|
326
|
+
// { $ref: '#/sets/base' },
|
|
327
|
+
// { $ref: '#/modifiers/scheme' },
|
|
328
|
+
// ],
|
|
329
|
+
// }
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
### `palette.tailwind()`
|
|
333
|
+
|
|
334
|
+
All themes merge into one `@theme` block plus one block per override, so every color is reachable as a Tailwind utility. Accepts `GlazeTailwindOptions` plus `GlazePaletteExportOptions`.
|
|
335
|
+
|
|
336
|
+
```css
|
|
337
|
+
/* palette.tailwind() */
|
|
338
|
+
@theme {
|
|
339
|
+
--color-primary-surface: oklch(0.97 0.0128 280);
|
|
340
|
+
/* … */
|
|
341
|
+
--color-surface: oklch(0.97 0.0128 280); /* unprefixed alias */
|
|
342
|
+
/* … */
|
|
343
|
+
--color-danger-surface: oklch(0.97 0.0129 23);
|
|
344
|
+
/* … */
|
|
345
|
+
}
|
|
346
|
+
.dark {
|
|
347
|
+
--color-primary-surface: oklch(0.279 0.1015 280);
|
|
348
|
+
/* … */
|
|
349
|
+
}
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
## `splitHue` in palettes
|
|
353
|
+
|
|
354
|
+
`palette.css({ splitHue: true })` and `palette.tasty({ splitHue: true })` follow the [`splitHue` rules](./output.md#hue-channel-splitting-splithue) per theme, with two differences:
|
|
355
|
+
|
|
356
|
+
- The theme-level hue var is named after the theme (`--primary-hue`, `--danger-hue`); the `name` option is ignored.
|
|
357
|
+
- Per-color hue vars use the theme's prefix (`--primary-accent-hue`). The primary's unprefixed aliases reference those same vars instead of declaring their own, so they never collide with another theme's hue vars.
|
|
358
|
+
|
|
359
|
+
```css
|
|
360
|
+
/* palette.css({ splitHue: true }).light
|
|
361
|
+
primary: 'primary', every theme pastel */
|
|
362
|
+
--primary-hue: 280;
|
|
363
|
+
--primary-accent-hue: calc(var(--primary-hue) + 20);
|
|
364
|
+
--primary-surface-color: oklch(0.97 0.0084 var(--primary-hue));
|
|
365
|
+
--primary-accent-color: oklch(0.5961 0.0608 var(--primary-accent-hue));
|
|
366
|
+
--surface-color: oklch(0.97 0.0084 var(--primary-hue));
|
|
367
|
+
--accent-color: oklch(0.5961 0.0608 var(--primary-accent-hue));
|
|
368
|
+
--danger-hue: 23;
|
|
369
|
+
--danger-accent-hue: calc(var(--danger-hue) + 20);
|
|
370
|
+
--danger-surface-color: oklch(0.97 0.0084 var(--danger-hue));
|
|
371
|
+
--danger-accent-color: oklch(0.5961 0.0608 var(--danger-accent-hue));
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
That output comes from two pastel themes:
|
|
375
|
+
|
|
376
|
+
```ts
|
|
377
|
+
const primary = glaze(280, 60, { pastel: true });
|
|
378
|
+
primary.colors({
|
|
379
|
+
surface: { tone: 97 },
|
|
380
|
+
accent: { tone: 52, hue: '+20' },
|
|
381
|
+
});
|
|
382
|
+
const danger = primary.extend({ hue: 23 });
|
|
383
|
+
|
|
384
|
+
glaze
|
|
385
|
+
.palette({ primary, danger }, { primary: 'primary' })
|
|
386
|
+
.css({ splitHue: true });
|
|
387
|
+
```
|