rei-kit 1.0.3 → 2.0.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/dist/tokens.css CHANGED
@@ -1,14 +1,23 @@
1
1
  /* rei-kit design tokens.
2
2
  *
3
3
  * Semantic names on purpose. An app renames nothing to rebrand: it redefines
4
- * these values, and every component follows. */
5
- @theme {
6
- --color-primary: #26667f;
7
- --color-accent: #124170;
8
- --color-positive: #67c090;
9
- --color-negative: #e05b4f;
10
- --color-warning: #d89a3e;
11
-
4
+ * these values, and every component follows.
5
+ *
6
+ * Three axes, each changed independently:
7
+ *
8
+ * colour — the eleven roles below; a palette redefines them
9
+ * material — how a surface is made: its fill, edge, depth and blur
10
+ * motion — how long things take and how they arrive
11
+ *
12
+ * A material (`rei-kit/materials.css`) changes the second without touching the
13
+ * first, which is how one app can be glass in one palette and brutalist in
14
+ * another without a component knowing either word.
15
+ *
16
+ * `static` so every variable is emitted whether or not a utility uses it.
17
+ * Components read many of these through `var()` in their own styles, and a
18
+ * theme variable Tailwind decided was unused would resolve to nothing there —
19
+ * a shadow that silently is not, which is exactly how `PriceCard` shipped. */
20
+ @theme static {
12
21
  --color-canvas: #f4faf8;
13
22
  --color-surface: #ffffff;
14
23
  --color-muted: #ddf4e7;
@@ -32,6 +41,167 @@
32
41
  --radius-card: 16px;
33
42
  --radius-shell: 30px;
34
43
  --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
44
+
45
+ /* ---------------------------------------------------------------------
46
+ Motion.
47
+
48
+ Two curves and four durations, where there had been ten durations and a
49
+ cubic-bezier pasted into eight files. `sheet` is the iOS sheet curve:
50
+ quick take-off, long soft landing. `standard` is for everything that is
51
+ not arriving from an edge.
52
+ --------------------------------------------------------------------- */
53
+ --ease-standard: cubic-bezier(0.22, 1, 0.36, 1);
54
+ --ease-sheet: cubic-bezier(0.32, 0.72, 0, 1);
55
+ }
56
+
57
+ /* ---------------------------------------------------------------------------
58
+ The filled roles, and the ink that sits on them.
59
+
60
+ Declared twice on purpose. `@theme reference` gives Tailwind the names, so
61
+ `bg-primary` and `text-on-primary` exist, without emitting a value. The
62
+ values come from the block below, at zero specificity inside the theme
63
+ layer — so anything an app states, in its own `@theme` or anywhere else,
64
+ wins in *both* modes.
65
+
66
+ That matters because the kit lightens these in the dark. Written as a plain
67
+ `.dark` rule, that lightening beat every app's own brand: an app that set
68
+ its primary in `@theme` switched to the dark mode and got Rei's blue. The
69
+ consumer checks of two apps caught it before it shipped.
70
+ --------------------------------------------------------------------------- */
71
+ @theme reference {
72
+ --color-primary: #26667f;
73
+ --color-accent: #124170;
74
+ --color-positive: #67c090;
75
+ --color-negative: #c9463b;
76
+ --color-warning: #d89a3e;
77
+
78
+ --color-on-primary: #ffffff;
79
+ --color-on-accent: #ffffff;
80
+ --color-on-positive: #07141a;
81
+ --color-on-negative: #ffffff;
82
+ --color-on-warning: #07141a;
83
+ }
84
+
85
+ @layer theme {
86
+ :where(:root) {
87
+ --color-primary: #26667f;
88
+ --color-accent: #124170;
89
+ --color-positive: #67c090;
90
+ --color-negative: #c9463b;
91
+ --color-warning: #d89a3e;
92
+
93
+ --color-on-primary: #ffffff;
94
+ --color-on-accent: #ffffff;
95
+ --color-on-positive: #07141a;
96
+ --color-on-negative: #ffffff;
97
+ --color-on-warning: #07141a;
98
+ }
99
+
100
+ /* The filled roles lighten in the dark as well as the grounds darken. They
101
+ used not to: the light-mode primary on the dark surface measured 2.3:1,
102
+ so every link and focus ring in dark mode was below the line for a
103
+ control, and nothing but a measurement would have said so. */
104
+ :where(.dark) {
105
+ --color-primary: #5fb0c9;
106
+ --color-accent: #8cb8e0;
107
+ --color-negative: #f07a6f;
108
+ --color-warning: #e6ad58;
109
+
110
+ --color-on-primary: #07141a;
111
+ --color-on-accent: #07141a;
112
+ --color-on-positive: #07141a;
113
+ --color-on-negative: #07141a;
114
+ --color-on-warning: #07141a;
115
+ }
116
+
117
+ /* The on-colours follow their fill, whatever the fill turns out to be.
118
+ Black or white, whichever is further from the fill's lightness — so an
119
+ app that rebrands its primary and forgets `on-primary` gets readable text
120
+ instead of white on yellow.
121
+
122
+ A safety net, not a guarantee: across a hundred measured fills it never
123
+ falls below 3.9:1 and clears 4.5:1 on almost all of them. A palette sets
124
+ its on-colours explicitly, measured to WCAG AA, and so can an app. For the
125
+ kit's own colours it picks exactly what measurement picks. */
126
+ @supports (color: oklch(from red l c h)) {
127
+ :where(:root) {
128
+ --color-on-primary: oklch(from var(--color-primary) clamp(0, calc((0.6 - l) * 1000), 1) 0 0);
129
+ --color-on-accent: oklch(from var(--color-accent) clamp(0, calc((0.6 - l) * 1000), 1) 0 0);
130
+ --color-on-positive: oklch(
131
+ from var(--color-positive) clamp(0, calc((0.6 - l) * 1000), 1) 0 0
132
+ );
133
+ --color-on-negative: oklch(
134
+ from var(--color-negative) clamp(0, calc((0.6 - l) * 1000), 1) 0 0
135
+ );
136
+ --color-on-warning: oklch(from var(--color-warning) clamp(0, calc((0.6 - l) * 1000), 1) 0 0);
137
+ }
138
+ }
139
+ }
140
+
141
+ /* Material knobs that no utility is named after. Plain custom properties, so
142
+ a material or an app can set them on any element and the subtree follows. */
143
+ :root {
144
+ --shadow-color: #0f2229;
145
+
146
+ /* ---------------------------------------------------------------------
147
+ Depth.
148
+
149
+ Four levels, named for what sits at them rather than for how big the
150
+ blur is: a card on the page, something lifted off it, a layer over the
151
+ whole page, and a control you can press. A material redefines all four,
152
+ which is how "a soft shadow" becomes "a hard offset" or "a raised puff"
153
+ across fifty components at once.
154
+
155
+ `--shadow-color` rather than a hex inside each shadow, so dark mode
156
+ changes one value instead of twelve.
157
+
158
+ Not in `@theme`, on purpose. Tailwind turns a theme shadow into a
159
+ `shadow-*` utility by *inlining its value*, so it can splice in a shadow
160
+ colour — which freezes it at whatever these say here. A material
161
+ redefining `--shadow-control` would reach every component except the ones
162
+ using `shadow-control`, and nothing would say so. Out here there is no such
163
+ utility to reach for; the way in is `shadow-(--shadow-control)`, which is
164
+ read at runtime like everything else.
165
+ --------------------------------------------------------------------- */
166
+ --shadow-card:
167
+ 0 1px 2px color-mix(in oklab, var(--shadow-color) 4%, transparent),
168
+ 0 2px 8px -2px color-mix(in oklab, var(--shadow-color) 6%, transparent);
169
+ --shadow-raised:
170
+ 0 1px 2px color-mix(in oklab, var(--shadow-color) 6%, transparent),
171
+ 0 12px 28px -10px color-mix(in oklab, var(--shadow-color) 18%, transparent);
172
+ --shadow-overlay:
173
+ 0 4px 12px -4px color-mix(in oklab, var(--shadow-color) 10%, transparent),
174
+ 0 24px 48px -16px color-mix(in oklab, var(--shadow-color) 28%, transparent);
175
+ --shadow-control: 0 1px 2px color-mix(in oklab, var(--shadow-color) 5%, transparent);
176
+ --shadow-control-pressed: none;
177
+
178
+ /* How much of the surface colour a surface keeps. Below 100% it lets the
179
+ page through, which is what glass is. */
180
+ --surface-opacity: 100%;
181
+ /* `none`, not `blur(0)`. Any backdrop-filter at all — zero included — makes
182
+ the element the containing block for its `position: fixed` descendants, so
183
+ a menu opened inside a card would position itself against the card. Only
184
+ a material that actually blurs pays that cost. */
185
+ --surface-backdrop: none;
186
+ --surface-border-width: 1px;
187
+ --surface-border-color: var(--color-hair);
188
+
189
+ --control-opacity: 100%;
190
+ --control-border-width: 1px;
191
+
192
+ /* The page behind everything. A material that needs something to blur puts
193
+ it here; the quiet one needs nothing. */
194
+ --canvas-backdrop: none;
195
+
196
+ /* What pressing a control does to it. A shrink by default; a material that
197
+ draws hard offset shadows presses *into* them instead. */
198
+ --press-scale: 0.97;
199
+ --press-offset: 0px;
200
+
201
+ --duration-fast: 150ms;
202
+ --duration-base: 200ms;
203
+ --duration-slow: 340ms;
204
+ --duration-slower: 420ms;
35
205
  }
36
206
 
37
207
  /* Class-based rather than media-based: the app decides, and a user preference
@@ -45,13 +215,89 @@
45
215
  --color-ink: #e6f0ee;
46
216
  --color-ink-soft: #8fa8b2;
47
217
  --color-hair: #1c3945;
218
+
219
+ /* A shadow cast by a light ink would glow. Depth on a dark page is always
220
+ cast by black. */
221
+ --shadow-color: #000000;
48
222
  }
223
+
224
+ /* Honouring the two preferences that say "less of this" — for every material
225
+ at once, so no material can forget to. */
226
+ @media (prefers-reduced-motion: reduce) {
227
+ :root {
228
+ --duration-fast: 0ms;
229
+ --duration-base: 0ms;
230
+ --duration-slow: 0ms;
231
+ --duration-slower: 0ms;
232
+ --press-scale: 1;
233
+ }
234
+ }
235
+
49
236
  /* rei-kit utilities.
50
237
  *
51
238
  * Declared with @utility rather than @layer utilities so an app can also reach
52
239
  * them from @apply inside a component's own styles — @layer classes cannot be
53
240
  * applied that way, which is a mistake worth only making once. */
54
241
 
242
+ /* ---------------------------------------------------------------------------
243
+ Surfaces.
244
+
245
+ The one place a component learns what it is made of. Before these, every
246
+ card wrote `border border-hair bg-surface shadow-…` out in full, which is
247
+ how a material could not have reached them: there was no single thing to
248
+ redefine. Now a card says `surface` and the material says what that means.
249
+ --------------------------------------------------------------------------- */
250
+ @utility surface {
251
+ background-color: color-mix(in oklab, var(--color-surface) var(--surface-opacity), transparent);
252
+ border: var(--surface-border-width) solid var(--surface-border-color);
253
+ /* `--surface-shadow` lets one card be lifted — a recommended plan, a hovered
254
+ tile — without a second shadow utility racing this one for the same
255
+ property. Unset, it is the card depth. */
256
+ box-shadow: var(--surface-shadow, var(--shadow-card));
257
+ backdrop-filter: var(--surface-backdrop);
258
+ -webkit-backdrop-filter: var(--surface-backdrop);
259
+ }
260
+
261
+ /* Lifted off the page: a toast, a popover, a card that is the point. */
262
+ @utility surface-raised {
263
+ background-color: color-mix(in oklab, var(--color-surface) var(--surface-opacity), transparent);
264
+ border: var(--surface-border-width) solid var(--surface-border-color);
265
+ box-shadow: var(--shadow-raised);
266
+ backdrop-filter: var(--surface-backdrop);
267
+ -webkit-backdrop-filter: var(--surface-backdrop);
268
+ }
269
+
270
+ /* Over the whole page: a dialog, a menu, a sheet. Always more opaque than a
271
+ card, because what is behind it is exactly what the reader has been asked
272
+ to stop looking at. */
273
+ @utility surface-overlay {
274
+ background-color: color-mix(
275
+ in oklab,
276
+ var(--color-surface) calc(var(--surface-opacity) + (100% - var(--surface-opacity)) / 2),
277
+ transparent
278
+ );
279
+ border: var(--surface-border-width) solid var(--surface-border-color);
280
+ box-shadow: var(--shadow-overlay);
281
+ backdrop-filter: var(--surface-backdrop);
282
+ -webkit-backdrop-filter: var(--surface-backdrop);
283
+ }
284
+
285
+ /* Something you type into or press that is not the main action. */
286
+ @utility control {
287
+ background-color: color-mix(in oklab, var(--color-surface) var(--control-opacity), transparent);
288
+ border: var(--control-border-width) solid var(--surface-border-color);
289
+ box-shadow: var(--shadow-control);
290
+ backdrop-filter: var(--surface-backdrop);
291
+ -webkit-backdrop-filter: var(--surface-backdrop);
292
+ }
293
+
294
+ /* The page itself. Put it on the element that fills the viewport. */
295
+ @utility canvas {
296
+ background-color: var(--color-canvas);
297
+ background-image: var(--canvas-backdrop);
298
+ background-attachment: fixed;
299
+ }
300
+
55
301
  /* Scrolling stays, the bar goes. On a narrow column a visible track reads as a
56
302
  stray line rather than as a control. */
57
303
  @utility no-scrollbar {
@@ -0,0 +1,71 @@
1
+ import { Ref } from 'vue';
2
+ export declare const MATERIALS: readonly ["quiet", "glass", "brutal", "soft"];
3
+ export type Material = (typeof MATERIALS)[number];
4
+ export declare function isMaterial(value: unknown): value is Material;
5
+ /**
6
+ * Switches the material for everything under `root`.
7
+ *
8
+ * `quiet` removes the attribute rather than writing it, because quiet is what
9
+ * the tokens already are — there is nothing to override.
10
+ *
11
+ * Needs `rei-kit/materials.css` (or the one material file) imported after
12
+ * `tokens.css`, or the attribute changes nothing.
13
+ */
14
+ export declare function applyMaterial(material: Material, root?: HTMLElement): void;
15
+ /** The eleven colour roles plus the five on-colours, for one mode. */
16
+ export interface PaletteRoles {
17
+ primary: string;
18
+ accent: string;
19
+ positive: string;
20
+ negative: string;
21
+ warning: string;
22
+ canvas: string;
23
+ surface: string;
24
+ muted: string;
25
+ ink: string;
26
+ inkSoft: string;
27
+ hair: string;
28
+ onPrimary: string;
29
+ onAccent: string;
30
+ onPositive: string;
31
+ onNegative: string;
32
+ onWarning: string;
33
+ }
34
+ export interface Palette {
35
+ /** The value for `data-palette`. */
36
+ name: string;
37
+ /** A display name. */
38
+ label: string;
39
+ /** Who made it. Several are well-known open palettes, credited here. */
40
+ origin: string;
41
+ /** Four colours for a picker to show at a glance. */
42
+ swatch: readonly [string, string, string, string];
43
+ light: PaletteRoles;
44
+ dark: PaletteRoles;
45
+ }
46
+ export declare const PALETTES: readonly Palette[];
47
+ export type PaletteName = string;
48
+ export declare function isPaletteName(value: unknown): value is PaletteName;
49
+ /**
50
+ * Switches the palette for everything under `root`.
51
+ *
52
+ * `rei` is the tokens' own palette, so it removes the attribute. Needs
53
+ * `rei-kit/palettes.css` imported after `tokens.css`.
54
+ */
55
+ export declare function applyPalette(name: PaletteName, root?: HTMLElement): void;
56
+ /** Call once at startup, before `useMaterial`, to namespace the stored value. */
57
+ export declare function setMaterialStorageKey(key: string): void;
58
+ /**
59
+ * The active material, as a writable ref. Assigning it stores and applies it.
60
+ *
61
+ * @example
62
+ * ```ts
63
+ * const material = useMaterial()
64
+ * material.value = 'glass'
65
+ * ```
66
+ */
67
+ export declare function useMaterial(): Ref<Material>;
68
+ /** Call once at startup, before `usePalette`, to namespace the stored value. */
69
+ export declare function setPaletteStorageKey(key: string): void;
70
+ /** The active palette's name, as a writable ref. Assigning it stores and applies it. */
71
+ export declare function usePalette(): Ref<PaletteName>;
package/dist/web.js CHANGED
@@ -62,7 +62,7 @@ var BaseAccordion_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @
62
62
  }), 128))]);
63
63
  };
64
64
  }
65
- }), [["__scopeId", "data-v-d7bddb65"]]);
65
+ }), [["__scopeId", "data-v-03e2e1d0"]]);
66
66
  //#endregion
67
67
  //#region src/web/BaseBreadcrumb.vue?vue&type=script&setup=true&lang.ts
68
68
  var _hoisted_1$6 = ["aria-label"];
@@ -102,7 +102,7 @@ var BaseBreadcrumb_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/*
102
102
  }), 128))])], 8, _hoisted_1$6);
103
103
  };
104
104
  }
105
- }), [["__scopeId", "data-v-85ee4b4e"]]);
105
+ }), [["__scopeId", "data-v-dcc01b03"]]);
106
106
  //#endregion
107
107
  //#region src/web/BaseDisclosure.vue?vue&type=script&setup=true&lang.ts
108
108
  var _hoisted_1$5 = { class: "rk-disclosure" };
@@ -148,7 +148,7 @@ var BaseDisclosure_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/*
148
148
  }, [createElementVNode("div", _hoisted_6$1, [createElementVNode("div", { class: normalizeClass(["rk-disclosure-body", { "is-open": open.value }]) }, [renderSlot(_ctx.$slots, "default", {}, void 0, true)], 2)])], 10, _hoisted_5$2)]);
149
149
  };
150
150
  }
151
- }), [["__scopeId", "data-v-e09c1481"]]);
151
+ }), [["__scopeId", "data-v-ad5c09f5"]]);
152
152
  //#endregion
153
153
  //#region src/web/BaseModal.vue?vue&type=script&setup=true&lang.ts
154
154
  var _hoisted_1$4 = ["role", "aria-label"];
@@ -263,7 +263,7 @@ var BaseModal_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PU
263
263
  }, [createElementVNode("div", {
264
264
  ref_key: "panel",
265
265
  ref: panel,
266
- class: "rk-modal-panel",
266
+ class: "rk-modal-panel surface-overlay",
267
267
  role: __props.tone === "alert" ? "alertdialog" : "dialog",
268
268
  "aria-modal": "true",
269
269
  "aria-label": __props.title,
@@ -291,7 +291,7 @@ var BaseModal_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PU
291
291
  })]);
292
292
  };
293
293
  }
294
- }), [["__scopeId", "data-v-e092f731"]]);
294
+ }), [["__scopeId", "data-v-c6537cc8"]]);
295
295
  //#endregion
296
296
  //#region src/web/BasePagination.vue?vue&type=script&setup=true&lang.ts
297
297
  var _hoisted_1$3 = ["aria-label"];
@@ -385,7 +385,7 @@ var BasePagination_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/*
385
385
  ], 8, _hoisted_1$3);
386
386
  };
387
387
  }
388
- }), [["__scopeId", "data-v-cc4bbb58"]]);
388
+ }), [["__scopeId", "data-v-29950578"]]);
389
389
  //#endregion
390
390
  //#region src/web/BaseTabs.vue?vue&type=script&setup=true&lang.ts
391
391
  var _hoisted_1$2 = ["aria-label"];
@@ -471,7 +471,7 @@ var BaseTabs_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PUR
471
471
  }), 128))]);
472
472
  };
473
473
  }
474
- }), [["__scopeId", "data-v-b854e7f5"]]);
474
+ }), [["__scopeId", "data-v-2a18b30e"]]);
475
475
  //#endregion
476
476
  //#region src/web/BaseTooltip.vue?vue&type=script&setup=true&lang.ts
477
477
  var _hoisted_1$1 = { class: "rk-tip" };
@@ -494,7 +494,7 @@ var BaseTooltip_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__
494
494
  }, toDisplayString(__props.label), 11, _hoisted_2$1)]);
495
495
  };
496
496
  }
497
- }), [["__scopeId", "data-v-3ed61bd4"]]);
497
+ }), [["__scopeId", "data-v-3a572640"]]);
498
498
  //#endregion
499
499
  //#region src/web/NavLinks.vue?vue&type=script&setup=true&lang.ts
500
500
  var _hoisted_1 = ["aria-label"];
@@ -530,7 +530,7 @@ var NavLinks_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PUR
530
530
  }), 128))])], 8, _hoisted_1);
531
531
  };
532
532
  }
533
- }), [["__scopeId", "data-v-5e640548"]]);
533
+ }), [["__scopeId", "data-v-52e5d553"]]);
534
534
  //#endregion
535
535
  export { BaseAccordion_default as BaseAccordion, BaseBreadcrumb_default as BaseBreadcrumb, BaseDisclosure_default as BaseDisclosure, BaseModal_default as BaseModal, BasePagination_default as BasePagination, BaseTabs_default as BaseTabs, BaseTooltip_default as BaseTooltip, NavLinks_default as NavLinks };
536
536