dowel-ui 0.1.0 → 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/README.md CHANGED
@@ -8,7 +8,7 @@ The lacodda line design system: theme tokens and React primitives, distributed a
8
8
 
9
9
  A dowel is the hidden peg that joins two boards so the seam does not show. That is what this does for the products of the line: they look made by one hand, and nobody sees the joint.
10
10
 
11
- **Status:** v0.1.0 - the theme. Primitives and the registry follow; see the [roadmap](#roadmap).
11
+ **Status:** v0.2.0 - the theme and the scales. Primitives and the registry follow; see the [roadmap](#roadmap).
12
12
 
13
13
  ## The theme
14
14
 
@@ -54,8 +54,11 @@ The stock palette is dropped deliberately, so a stray `bg-zinc-800` does not com
54
54
  - **The accent is derived, not configured.** A product states one hue and the theme works out the rest, including what colour text has to be to sit on top of it. A light accent takes dark glyphs, a dark one white - checked against every colour in the line rather than left to each product to get right.
55
55
  - **The greys belong to the product.** They carry a trace of its hue, so the chrome of one product is not the chrome of another with a different button colour.
56
56
  - **Contrast is a test, not an intention.** Every accent of the line is measured against WCAG AA in CI, in both themes, as a fill and as text.
57
+ - **The scales were read, not invented.** Radius, type, elevation and stacking order come from what the line's products already draw, so existing code fits them - and the places where those products disagreed with themselves are settled rather than preserved.
57
58
 
58
- Full vocabulary, with every token shown in both themes: **[the token reference](https://lacodda.github.io/dowel/reference/tokens/)**.
59
+ The same vocabulary also ships as [DTCG](https://www.designtokens.org/tr/2025.10/format/) JSON at `dowel-ui/tokens.json`, generated from the stylesheet so the two cannot drift.
60
+
61
+ Full vocabulary, shown rather than tabulated: **[colours](https://lacodda.github.io/dowel/reference/tokens/)** in both themes, and **[the scales](https://lacodda.github.io/dowel/reference/scales/)** - radius, type, motion, elevation and stacking order.
59
62
 
60
63
  ## Roadmap
61
64
 
package/dist/index.d.ts CHANGED
@@ -4,12 +4,36 @@ export declare const colorTokens: readonly ["bg", "raise", "soft", "softer", "li
4
4
  /** Tokens a product overrides to make the theme its own: the accent from the
5
5
  * brand-line registry, and how much of it bleeds into the greys. */
6
6
  export declare const themeParameters: readonly ["accent-base", "neutral-base", "neutral-tint", "neutral-tint-strong", "ground", "ink"];
7
- /** Everything else the theme defines. */
8
- export declare const otherTokens: readonly ["shadow-raise"];
7
+ /** Elevation. Three steps, and they change with the theme: a shadow that
8
+ * works on a dark ground is invisible on a light one. */
9
+ export declare const elevationTokens: readonly ["shadow-lift", "shadow-raise", "shadow-float"];
10
+ /** Corner radius. `md` is the control radius - inputs, buttons, list rows;
11
+ * `inner` is what a shape nested inside another one takes. */
12
+ export declare const radiusTokens: readonly ["radius-xs", "radius-sm", "radius-md", "radius-lg", "radius-xl", "radius-2xl", "radius-inner"];
13
+ /** Type: sizes with their line heights, weights, and the two tracking steps
14
+ * the products actually need. */
15
+ export declare const typeTokens: readonly ["font-sans", "font-mono", "text-2xs", "text-xs", "text-sm", "text-base", "text-lg", "text-xl", "text-2xl", "font-weight-normal", "font-weight-medium", "font-weight-semibold", "tracking-caption", "tracking-tight"];
16
+ /** Motion. The durations are read directly rather than through a utility -
17
+ * Tailwind's `duration-*` takes a literal number - while the easings are a
18
+ * namespace, so `ease-out` is a class. */
19
+ export declare const motionTokens: readonly ["duration-quick", "duration-base", "duration-slow", "ease-out", "ease-in-out"];
20
+ /** Stacking order. Not a Tailwind namespace either: a component reads these
21
+ * as `z-index: var(--z-modal)`. The names are a promise about what covers
22
+ * what, and the values only mean anything relative to each other. */
23
+ export declare const layerTokens: readonly ["z-popup", "z-sticky", "z-menu", "z-floating", "z-overlay", "z-modal", "z-palette", "z-toast"];
24
+ /** Every token the theme defines, in one list. Anything that iterates the
25
+ * vocabulary - a docs page, an inspector, the JSON export, the test that keeps
26
+ * this file honest against the stylesheet - reads this, so a new category
27
+ * cannot be added and quietly missed by half of them. */
28
+ export declare const allTokens: readonly ["bg", "raise", "soft", "softer", "line", "line-2", "text", "dim", "faint", "accent", "accent-2", "accent-soft", "on-accent", "good", "good-soft", "warn", "warn-soft", "bad", "bad-soft", "info", "info-soft", "accent-base", "neutral-base", "neutral-tint", "neutral-tint-strong", "ground", "ink", "shadow-lift", "shadow-raise", "shadow-float", "radius-xs", "radius-sm", "radius-md", "radius-lg", "radius-xl", "radius-2xl", "radius-inner", "font-sans", "font-mono", "text-2xs", "text-xs", "text-sm", "text-base", "text-lg", "text-xl", "text-2xl", "font-weight-normal", "font-weight-medium", "font-weight-semibold", "tracking-caption", "tracking-tight", "duration-quick", "duration-base", "duration-slow", "ease-out", "ease-in-out", "z-popup", "z-sticky", "z-menu", "z-floating", "z-overlay", "z-modal", "z-palette", "z-toast"];
9
29
  export type ColorToken = (typeof colorTokens)[number];
10
30
  export type ThemeParameter = (typeof themeParameters)[number];
11
- export type OtherToken = (typeof otherTokens)[number];
12
- export type Token = ColorToken | ThemeParameter | OtherToken;
31
+ export type ElevationToken = (typeof elevationTokens)[number];
32
+ export type RadiusToken = (typeof radiusTokens)[number];
33
+ export type TypeToken = (typeof typeTokens)[number];
34
+ export type MotionToken = (typeof motionTokens)[number];
35
+ export type LayerToken = (typeof layerTokens)[number];
36
+ export type Token = ColorToken | ThemeParameter | ElevationToken | RadiusToken | TypeToken | MotionToken | LayerToken;
13
37
  /** The custom property a token is read from: `token('accent')` is
14
38
  * `'--accent'`. Spelled out here so that no caller builds the string itself
15
39
  * and gets the prefix subtly wrong. */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAiBA;6DAC6D;AAC7D,eAAO,MAAM,WAAW,0NAsBd,CAAA;AAEV;oEACoE;AACpE,eAAO,MAAM,eAAe,kGAOlB,CAAA;AAEV,yCAAyC;AACzC,eAAO,MAAM,WAAW,2BAA4B,CAAA;AAEpD,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAA;AACrD,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAA;AAC7D,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAA;AACrD,MAAM,MAAM,KAAK,GAAG,UAAU,GAAG,cAAc,GAAG,UAAU,CAAA;AAE5D;;uCAEuC;AACvC,wBAAgB,KAAK,CAAC,IAAI,EAAE,KAAK,GAAG,MAAM,CAEzC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAiBA;6DAC6D;AAC7D,eAAO,MAAM,WAAW,0NAsBd,CAAA;AAEV;oEACoE;AACpE,eAAO,MAAM,eAAe,kGAOlB,CAAA;AAEV;yDACyD;AACzD,eAAO,MAAM,eAAe,0DAA2D,CAAA;AAEvF;8DAC8D;AAC9D,eAAO,MAAM,YAAY,0GAQf,CAAA;AAEV;iCACiC;AACjC,eAAO,MAAM,UAAU,gOAeb,CAAA;AAEV;;0CAE0C;AAC1C,eAAO,MAAM,YAAY,0FAMf,CAAA;AAEV;;qEAEqE;AACrE,eAAO,MAAM,WAAW,0GASd,CAAA;AAEV;;;yDAGyD;AACzD,eAAO,MAAM,SAAS,k0BAQZ,CAAA;AAEV,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAA;AACrD,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAA;AAC7D,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAA;AAC7D,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAA;AACvD,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,CAAC,CAAA;AACnD,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAA;AACvD,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAA;AACrD,MAAM,MAAM,KAAK,GACb,UAAU,GACV,cAAc,GACd,cAAc,GACd,WAAW,GACX,SAAS,GACT,WAAW,GACX,UAAU,CAAA;AAEd;;uCAEuC;AACvC,wBAAgB,KAAK,CAAC,IAAI,EAAE,KAAK,GAAG,MAAM,CAEzC"}
package/dist/index.js CHANGED
@@ -49,8 +49,74 @@ export const themeParameters = [
49
49
  'ground',
50
50
  'ink',
51
51
  ];
52
- /** Everything else the theme defines. */
53
- export const otherTokens = ['shadow-raise'];
52
+ /** Elevation. Three steps, and they change with the theme: a shadow that
53
+ * works on a dark ground is invisible on a light one. */
54
+ export const elevationTokens = ['shadow-lift', 'shadow-raise', 'shadow-float'];
55
+ /** Corner radius. `md` is the control radius - inputs, buttons, list rows;
56
+ * `inner` is what a shape nested inside another one takes. */
57
+ export const radiusTokens = [
58
+ 'radius-xs',
59
+ 'radius-sm',
60
+ 'radius-md',
61
+ 'radius-lg',
62
+ 'radius-xl',
63
+ 'radius-2xl',
64
+ 'radius-inner',
65
+ ];
66
+ /** Type: sizes with their line heights, weights, and the two tracking steps
67
+ * the products actually need. */
68
+ export const typeTokens = [
69
+ 'font-sans',
70
+ 'font-mono',
71
+ 'text-2xs',
72
+ 'text-xs',
73
+ 'text-sm',
74
+ 'text-base',
75
+ 'text-lg',
76
+ 'text-xl',
77
+ 'text-2xl',
78
+ 'font-weight-normal',
79
+ 'font-weight-medium',
80
+ 'font-weight-semibold',
81
+ 'tracking-caption',
82
+ 'tracking-tight',
83
+ ];
84
+ /** Motion. The durations are read directly rather than through a utility -
85
+ * Tailwind's `duration-*` takes a literal number - while the easings are a
86
+ * namespace, so `ease-out` is a class. */
87
+ export const motionTokens = [
88
+ 'duration-quick',
89
+ 'duration-base',
90
+ 'duration-slow',
91
+ 'ease-out',
92
+ 'ease-in-out',
93
+ ];
94
+ /** Stacking order. Not a Tailwind namespace either: a component reads these
95
+ * as `z-index: var(--z-modal)`. The names are a promise about what covers
96
+ * what, and the values only mean anything relative to each other. */
97
+ export const layerTokens = [
98
+ 'z-popup',
99
+ 'z-sticky',
100
+ 'z-menu',
101
+ 'z-floating',
102
+ 'z-overlay',
103
+ 'z-modal',
104
+ 'z-palette',
105
+ 'z-toast',
106
+ ];
107
+ /** Every token the theme defines, in one list. Anything that iterates the
108
+ * vocabulary - a docs page, an inspector, the JSON export, the test that keeps
109
+ * this file honest against the stylesheet - reads this, so a new category
110
+ * cannot be added and quietly missed by half of them. */
111
+ export const allTokens = [
112
+ ...colorTokens,
113
+ ...themeParameters,
114
+ ...elevationTokens,
115
+ ...radiusTokens,
116
+ ...typeTokens,
117
+ ...motionTokens,
118
+ ...layerTokens,
119
+ ];
54
120
  /** The custom property a token is read from: `token('accent')` is
55
121
  * `'--accent'`. Spelled out here so that no caller builds the string itself
56
122
  * and gets the prefix subtly wrong. */
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH;6DAC6D;AAC7D,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,IAAI;IACJ,OAAO;IACP,MAAM;IACN,QAAQ;IACR,MAAM;IACN,QAAQ;IACR,MAAM;IACN,KAAK;IACL,OAAO;IACP,QAAQ;IACR,UAAU;IACV,aAAa;IACb,WAAW;IACX,MAAM;IACN,WAAW;IACX,MAAM;IACN,WAAW;IACX,KAAK;IACL,UAAU;IACV,MAAM;IACN,WAAW;CACH,CAAA;AAEV;oEACoE;AACpE,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,aAAa;IACb,cAAc;IACd,cAAc;IACd,qBAAqB;IACrB,QAAQ;IACR,KAAK;CACG,CAAA;AAEV,yCAAyC;AACzC,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,cAAc,CAAU,CAAA;AAOpD;;uCAEuC;AACvC,MAAM,UAAU,KAAK,CAAC,IAAW;IAC/B,OAAO,KAAK,IAAI,EAAE,CAAA;AACpB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH;6DAC6D;AAC7D,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,IAAI;IACJ,OAAO;IACP,MAAM;IACN,QAAQ;IACR,MAAM;IACN,QAAQ;IACR,MAAM;IACN,KAAK;IACL,OAAO;IACP,QAAQ;IACR,UAAU;IACV,aAAa;IACb,WAAW;IACX,MAAM;IACN,WAAW;IACX,MAAM;IACN,WAAW;IACX,KAAK;IACL,UAAU;IACV,MAAM;IACN,WAAW;CACH,CAAA;AAEV;oEACoE;AACpE,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,aAAa;IACb,cAAc;IACd,cAAc;IACd,qBAAqB;IACrB,QAAQ;IACR,KAAK;CACG,CAAA;AAEV;yDACyD;AACzD,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,aAAa,EAAE,cAAc,EAAE,cAAc,CAAU,CAAA;AAEvF;8DAC8D;AAC9D,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,WAAW;IACX,WAAW;IACX,WAAW;IACX,WAAW;IACX,WAAW;IACX,YAAY;IACZ,cAAc;CACN,CAAA;AAEV;iCACiC;AACjC,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,WAAW;IACX,WAAW;IACX,UAAU;IACV,SAAS;IACT,SAAS;IACT,WAAW;IACX,SAAS;IACT,SAAS;IACT,UAAU;IACV,oBAAoB;IACpB,oBAAoB;IACpB,sBAAsB;IACtB,kBAAkB;IAClB,gBAAgB;CACR,CAAA;AAEV;;0CAE0C;AAC1C,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,gBAAgB;IAChB,eAAe;IACf,eAAe;IACf,UAAU;IACV,aAAa;CACL,CAAA;AAEV;;qEAEqE;AACrE,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,SAAS;IACT,UAAU;IACV,QAAQ;IACR,YAAY;IACZ,WAAW;IACX,SAAS;IACT,WAAW;IACX,SAAS;CACD,CAAA;AAEV;;;yDAGyD;AACzD,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,GAAG,WAAW;IACd,GAAG,eAAe;IAClB,GAAG,eAAe;IAClB,GAAG,YAAY;IACf,GAAG,UAAU;IACb,GAAG,YAAY;IACf,GAAG,WAAW;CACN,CAAA;AAkBV;;uCAEuC;AACvC,MAAM,UAAU,KAAK,CAAC,IAAW;IAC/B,OAAO,KAAK,IAAI,EAAE,CAAA;AACpB,CAAC"}
package/dist/theme.css CHANGED
@@ -80,7 +80,14 @@
80
80
  --bad-soft: color-mix(in oklab, var(--bad) 14%, transparent);
81
81
  --info-soft: color-mix(in oklab, var(--info) 15%, transparent);
82
82
 
83
+ /* Elevation, three steps. The products had one shadow and used it for
84
+ * everything that leaves the flow - a toast, a dropdown and a modal all
85
+ * floated by the same amount, so a modal never felt further away than the
86
+ * menu it covered. `raise` keeps its original value, so nothing shifts under
87
+ * the products already using it; the other two are the steps either side. */
88
+ --shadow-lift: 0 2px 8px rgb(0 0 0 / 0.3);
83
89
  --shadow-raise: 0 10px 34px rgb(0 0 0 / 0.45);
90
+ --shadow-float: 0 24px 60px rgb(0 0 0 / 0.55);
84
91
  }
85
92
 
86
93
  /*
@@ -125,7 +132,9 @@
125
132
  --bad-soft: color-mix(in oklab, var(--bad) 12%, transparent);
126
133
  --info-soft: color-mix(in oklab, var(--info) 11%, transparent);
127
134
 
135
+ --shadow-lift: 0 2px 8px rgb(30 24 38 / 0.08);
128
136
  --shadow-raise: 0 10px 30px rgb(30 24 38 / 0.14);
137
+ --shadow-float: 0 24px 60px rgb(30 24 38 / 0.18);
129
138
  }
130
139
  }
131
140
 
@@ -161,7 +170,9 @@
161
170
  --bad-soft: color-mix(in oklab, var(--bad) 12%, transparent);
162
171
  --info-soft: color-mix(in oklab, var(--info) 11%, transparent);
163
172
 
173
+ --shadow-lift: 0 2px 8px rgb(30 24 38 / 0.08);
164
174
  --shadow-raise: 0 10px 30px rgb(30 24 38 / 0.14);
175
+ --shadow-float: 0 24px 60px rgb(30 24 38 / 0.18);
165
176
  }
166
177
 
167
178
  /*
@@ -236,10 +247,131 @@
236
247
  --color-white: #fff;
237
248
  --color-black: #000;
238
249
 
250
+ /*
251
+ * Type. System stacks on purpose: a downloaded face costs a network round
252
+ * trip before the first word appears, and the line's products are desktop
253
+ * tools where the operating system's own face is the one the user already
254
+ * reads everything else in.
255
+ */
239
256
  --font-sans: 'Segoe UI Variable Text', 'Segoe UI', system-ui, -apple-system, sans-serif;
240
257
  --font-mono: ui-monospace, 'Cascadia Code', 'SF Mono', Consolas, monospace;
241
258
 
259
+ /*
260
+ * Radius. Taken from what the products actually draw, not from a ratio:
261
+ * `rounded-[9px]` appears twenty times and `rounded-[10px]` twelve, because
262
+ * a control and the primary button were tuned by eye and then copied. The
263
+ * scale keeps the cluster they landed in and gives it names.
264
+ *
265
+ * `md` is the control radius - inputs, buttons, list rows. That the primary
266
+ * button was one pixel rounder than every other variant is not preserved:
267
+ * the products differ from themselves there, and buttons of the same size
268
+ * sitting side by side should not have mismatched corners.
269
+ */
270
+ --radius-xs: 4px;
271
+ --radius-sm: 6px;
272
+ --radius-md: 9px;
273
+ --radius-lg: 12px;
274
+ --radius-xl: 16px;
275
+ --radius-2xl: 20px;
276
+
277
+ /*
278
+ * A radius nested inside another has to be smaller by the gap between them,
279
+ * or the inner corner looks wrong against the outer one. The products did
280
+ * this by hand once - 18px outside, 17px inside - and nowhere else.
281
+ */
282
+ --radius-inner: calc(var(--radius-lg) - 1px);
283
+
284
+ /*
285
+ * Type scale. The products live between 10px and 14px: `text-sm` and
286
+ * `text-xs` together account for nine tenths of every size in both, and the
287
+ * rest scattered across 9, 9.5, 10, 10.5, 11, 11.5, 12.5 and 13 - nine steps
288
+ * inside four pixels, which no eye distinguishes and no reason justifies.
289
+ * This is the same range with the noise removed.
290
+ */
291
+ --text-2xs: 10px;
292
+ --text-2xs--line-height: 14px;
293
+ --text-xs: 11px;
294
+ --text-xs--line-height: 15px;
295
+ --text-sm: 12px;
296
+ --text-sm--line-height: 16px;
297
+ --text-base: 14px;
298
+ --text-base--line-height: 20px;
299
+ --text-lg: 16px;
300
+ --text-lg--line-height: 22px;
301
+ --text-xl: 18px;
302
+ --text-xl--line-height: 24px;
303
+ --text-2xl: 21px;
304
+ --text-2xl--line-height: 28px;
305
+
306
+ /* Weights. `semibold` is what both products use for anything emphasised;
307
+ * `bold` appears in neither, and the one `font-[650]` in a page title is the
308
+ * kind of value a scale exists to absorb. */
309
+ --font-weight-normal: 400;
310
+ --font-weight-medium: 500;
311
+ --font-weight-semibold: 600;
312
+
313
+ /* Tracking. The uppercase caption is the only place the products track at
314
+ * all - and they do it at 0.08em in six files and 0.09em in three, a
315
+ * difference nobody can see. One name settles it. */
316
+ --tracking-caption: 0.085em;
317
+ --tracking-tight: -0.01em;
318
+
319
+ /* Easing. `out` for anything the user asked for - it arrives fast and
320
+ * settles, which reads as responsive. `in-out` for something moving on its
321
+ * own. `in` is deliberately absent: it starts slowly, which on a control
322
+ * reads as lag. */
323
+ --ease-out: cubic-bezier(0.2, 0, 0, 1);
324
+ --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
325
+
326
+ /*
327
+ * Elevation. Three steps, because the products had one and used it for a
328
+ * toast, a dropdown and a modal alike - so a modal never sat further from
329
+ * the page than the menu it covered.
330
+ */
331
+ --shadow-lift: var(--shadow-lift);
242
332
  --shadow-raise: var(--shadow-raise);
333
+ --shadow-float: var(--shadow-float);
334
+ }
335
+
336
+ /*
337
+ * Stacking order.
338
+ *
339
+ * Not in `@theme`: Tailwind has no z-index namespace, so `z-50` is a literal
340
+ * fifty and a named step would not compile. These are custom properties a
341
+ * component reads directly - `z-index: var(--z-modal)`.
342
+ *
343
+ * The order is the products' own, with the gaps closed. They ran 10 for an
344
+ * in-flow popup, 20 sticky, 30 menu, 40 for a floating button, 50 for modals
345
+ * and drawers, then jumped to 70 and 80 for the command palette - which had to
346
+ * clear the modal layer and had no name to do it with.
347
+ */
348
+ :root {
349
+ /*
350
+ * Motion. One duration existed before this - 160ms on a route change - and
351
+ * everything else rode Tailwind's default. These are the steps around it:
352
+ * `quick` for a colour or an opacity that should feel immediate, `base` for
353
+ * something that moves, `slow` for something arriving from off-screen.
354
+ *
355
+ * Not in `@theme`: Tailwind's `duration-*` utility takes a literal number,
356
+ * not a named step, so these are read directly - `transition-duration:
357
+ * var(--duration-base)`. The easing curves opposite them ARE a namespace,
358
+ * so `ease-out` is a class.
359
+ *
360
+ * Every duration here is for people who want motion: `prefers-reduced-
361
+ * motion` cuts them to nothing further down.
362
+ */
363
+ --duration-quick: 120ms;
364
+ --duration-base: 160ms;
365
+ --duration-slow: 240ms;
366
+
367
+ --z-popup: 10;
368
+ --z-sticky: 20;
369
+ --z-menu: 30;
370
+ --z-floating: 40;
371
+ --z-overlay: 50;
372
+ --z-modal: 60;
373
+ --z-palette: 70;
374
+ --z-toast: 80;
243
375
  }
244
376
 
245
377
  /*
@@ -0,0 +1,233 @@
1
+ {
2
+ "$description": "The dowel token vocabulary: the scales every product of the lacodda line is drawn on. Colours are omitted - they are derived per product from its own accent.",
3
+ "radius": {
4
+ "$type": "dimension",
5
+ "$description": "Corner radius. `md` is the control radius: inputs, buttons, list rows.",
6
+ "xs": {
7
+ "$value": {
8
+ "value": 4,
9
+ "unit": "px"
10
+ }
11
+ },
12
+ "sm": {
13
+ "$value": {
14
+ "value": 6,
15
+ "unit": "px"
16
+ }
17
+ },
18
+ "md": {
19
+ "$value": {
20
+ "value": 9,
21
+ "unit": "px"
22
+ }
23
+ },
24
+ "lg": {
25
+ "$value": {
26
+ "value": 12,
27
+ "unit": "px"
28
+ }
29
+ },
30
+ "xl": {
31
+ "$value": {
32
+ "value": 16,
33
+ "unit": "px"
34
+ }
35
+ },
36
+ "2xl": {
37
+ "$value": {
38
+ "value": 20,
39
+ "unit": "px"
40
+ }
41
+ }
42
+ },
43
+ "typography": {
44
+ "$type": "typography",
45
+ "$description": "Type steps, each with the line height it is set on.",
46
+ "2xs": {
47
+ "$value": {
48
+ "fontSize": {
49
+ "value": 10,
50
+ "unit": "px"
51
+ },
52
+ "lineHeight": {
53
+ "value": 14,
54
+ "unit": "px"
55
+ }
56
+ }
57
+ },
58
+ "xs": {
59
+ "$value": {
60
+ "fontSize": {
61
+ "value": 11,
62
+ "unit": "px"
63
+ },
64
+ "lineHeight": {
65
+ "value": 15,
66
+ "unit": "px"
67
+ }
68
+ }
69
+ },
70
+ "sm": {
71
+ "$value": {
72
+ "fontSize": {
73
+ "value": 12,
74
+ "unit": "px"
75
+ },
76
+ "lineHeight": {
77
+ "value": 16,
78
+ "unit": "px"
79
+ }
80
+ }
81
+ },
82
+ "base": {
83
+ "$value": {
84
+ "fontSize": {
85
+ "value": 14,
86
+ "unit": "px"
87
+ },
88
+ "lineHeight": {
89
+ "value": 20,
90
+ "unit": "px"
91
+ }
92
+ }
93
+ },
94
+ "lg": {
95
+ "$value": {
96
+ "fontSize": {
97
+ "value": 16,
98
+ "unit": "px"
99
+ },
100
+ "lineHeight": {
101
+ "value": 22,
102
+ "unit": "px"
103
+ }
104
+ }
105
+ },
106
+ "xl": {
107
+ "$value": {
108
+ "fontSize": {
109
+ "value": 18,
110
+ "unit": "px"
111
+ },
112
+ "lineHeight": {
113
+ "value": 24,
114
+ "unit": "px"
115
+ }
116
+ }
117
+ },
118
+ "2xl": {
119
+ "$value": {
120
+ "fontSize": {
121
+ "value": 21,
122
+ "unit": "px"
123
+ },
124
+ "lineHeight": {
125
+ "value": 28,
126
+ "unit": "px"
127
+ }
128
+ }
129
+ }
130
+ },
131
+ "fontFamily": {
132
+ "$type": "fontFamily",
133
+ "sans": {
134
+ "$value": [
135
+ "Segoe UI Variable Text",
136
+ "Segoe UI",
137
+ "system-ui",
138
+ "-apple-system",
139
+ "sans-serif"
140
+ ]
141
+ },
142
+ "mono": {
143
+ "$value": [
144
+ "ui-monospace",
145
+ "Cascadia Code",
146
+ "SF Mono",
147
+ "Consolas",
148
+ "monospace"
149
+ ]
150
+ }
151
+ },
152
+ "fontWeight": {
153
+ "$type": "fontWeight",
154
+ "normal": {
155
+ "$value": 400
156
+ },
157
+ "medium": {
158
+ "$value": 500
159
+ },
160
+ "semibold": {
161
+ "$value": 600
162
+ }
163
+ },
164
+ "duration": {
165
+ "$type": "duration",
166
+ "$description": "Motion. Cut to nothing under `prefers-reduced-motion`.",
167
+ "quick": {
168
+ "$value": {
169
+ "value": 120,
170
+ "unit": "ms"
171
+ }
172
+ },
173
+ "base": {
174
+ "$value": {
175
+ "value": 160,
176
+ "unit": "ms"
177
+ }
178
+ },
179
+ "slow": {
180
+ "$value": {
181
+ "value": 240,
182
+ "unit": "ms"
183
+ }
184
+ }
185
+ },
186
+ "easing": {
187
+ "$type": "cubicBezier",
188
+ "out": {
189
+ "$value": [
190
+ 0.2,
191
+ 0,
192
+ 0,
193
+ 1
194
+ ]
195
+ },
196
+ "in-out": {
197
+ "$value": [
198
+ 0.4,
199
+ 0,
200
+ 0.2,
201
+ 1
202
+ ]
203
+ }
204
+ },
205
+ "layer": {
206
+ "$type": "number",
207
+ "$description": "Stacking order. The names are a promise about what covers what; the values only mean anything relative to each other.",
208
+ "popup": {
209
+ "$value": 10
210
+ },
211
+ "sticky": {
212
+ "$value": 20
213
+ },
214
+ "menu": {
215
+ "$value": 30
216
+ },
217
+ "floating": {
218
+ "$value": 40
219
+ },
220
+ "overlay": {
221
+ "$value": 50
222
+ },
223
+ "modal": {
224
+ "$value": 60
225
+ },
226
+ "palette": {
227
+ "$value": 70
228
+ },
229
+ "toast": {
230
+ "$value": 80
231
+ }
232
+ }
233
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dowel-ui",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "The lacodda line design system: theme tokens and React primitives, distributed as a shadcn-compatible registry.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -33,10 +33,11 @@
33
33
  "types": "./dist/index.d.ts",
34
34
  "import": "./dist/index.js"
35
35
  },
36
- "./theme.css": "./dist/theme.css"
36
+ "./theme.css": "./dist/theme.css",
37
+ "./tokens.json": "./dist/tokens.json"
37
38
  },
38
39
  "scripts": {
39
- "build": "tsc && node ../../tools/copy-theme.mjs",
40
+ "build": "tsc && node ../../tools/copy-theme.mjs && node ../../tools/build-tokens-json.mjs",
40
41
  "typecheck": "tsc --noEmit",
41
42
  "prepack": "node ../../tools/copy-readme.mjs"
42
43
  },