@lyeve-labs/ui-kit 0.23.3 → 0.25.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.
Files changed (60) hide show
  1. package/README.md +42 -0
  2. package/dist/components/AccordionItem.svelte +3 -5
  3. package/dist/components/AccountMenu.svelte +4 -3
  4. package/dist/components/Alert.svelte +2 -1
  5. package/dist/components/AppShell.svelte +166 -54
  6. package/dist/components/AppShell.svelte.d.ts +41 -6
  7. package/dist/components/Autocomplete.svelte +3 -2
  8. package/dist/components/Badge.svelte +10 -5
  9. package/dist/components/Banner.svelte +2 -1
  10. package/dist/components/Breadcrumb.svelte +7 -2
  11. package/dist/components/Button.svelte +15 -2
  12. package/dist/components/Card.svelte +1 -1
  13. package/dist/components/Collapsible.svelte +5 -4
  14. package/dist/components/CopyButton.svelte +2 -1
  15. package/dist/components/DatePicker.svelte +77 -62
  16. package/dist/components/Drawer.svelte +6 -5
  17. package/dist/components/Dropdown.svelte +5 -2
  18. package/dist/components/FileInput.svelte +1 -1
  19. package/dist/components/Modal.svelte +6 -3
  20. package/dist/components/MultiSelect.svelte +8 -6
  21. package/dist/components/NumberInput.svelte +2 -2
  22. package/dist/components/PageHeader.svelte +13 -1
  23. package/dist/components/PageShell.svelte +62 -7
  24. package/dist/components/PageShell.svelte.d.ts +27 -1
  25. package/dist/components/Pagination.svelte +7 -2
  26. package/dist/components/PasswordInput.svelte +2 -1
  27. package/dist/components/Progress.svelte +1 -1
  28. package/dist/components/SearchInput.svelte +3 -2
  29. package/dist/components/SectionHeading.svelte +10 -1
  30. package/dist/components/SegmentedControl.svelte +101 -27
  31. package/dist/components/SegmentedControl.svelte.d.ts +9 -0
  32. package/dist/components/Select.svelte +4 -3
  33. package/dist/components/SidebarNav.svelte +26 -17
  34. package/dist/components/StepIndicator.svelte +7 -9
  35. package/dist/components/Table.svelte +39 -29
  36. package/dist/components/Tabs.svelte +128 -24
  37. package/dist/components/Tag.svelte +2 -1
  38. package/dist/components/ThemeToggle.svelte +2 -1
  39. package/dist/components/Toaster.svelte +6 -2
  40. package/dist/components/Toggle.svelte +23 -5
  41. package/dist/components/Tooltip.svelte +10 -5
  42. package/dist/components/TreeView.svelte +2 -2
  43. package/dist/components/dialog/Dialog.svelte +15 -32
  44. package/dist/index.d.ts +4 -1
  45. package/dist/index.js +7 -1
  46. package/dist/internal/choice.js +10 -3
  47. package/dist/internal/field.js +3 -3
  48. package/dist/internal/layout.d.ts +10 -1
  49. package/dist/internal/layout.js +10 -1
  50. package/dist/internal/panel.d.ts +13 -3
  51. package/dist/internal/panel.js +16 -5
  52. package/dist/internal/scroll-edges.d.ts +33 -0
  53. package/dist/internal/scroll-edges.js +33 -0
  54. package/dist/internal/touch.d.ts +28 -0
  55. package/dist/internal/touch.js +28 -0
  56. package/dist/motion.d.ts +63 -0
  57. package/dist/motion.js +165 -0
  58. package/dist/styles/theme.css +131 -63
  59. package/package.json +1 -1
  60. package/src/lib/styles/theme.css +131 -63
@@ -115,24 +115,59 @@
115
115
  --z-index-toast: 600; /* transient status */
116
116
  --z-index-skip-link: 700; /* the first tab stop in the document */
117
117
 
118
- /* -- Motion - how long a transition or an entrance runs -------- *
119
- * Four durations shipped as literals inside the animate-[...]
120
- * utility of the component that used them, so the only way to
121
- * read the kit's motion was to grep four components. They are
122
- * stated here at the values they already ran at.
118
+ /* -- Motion - four durations, three curves, one rule for exits -- *
119
+ * Named for what they are used for, so the choice is made by
120
+ * reading the name:
121
+ *
122
+ * fast a state change in place: colour, opacity, border,
123
+ * shadow, focus
124
+ * base movement in place (a knob, a chevron, a collapse, a
125
+ * tab indicator) and a small surface arriving (menu,
126
+ * popover, tooltip, toast)
127
+ * slow a large surface arriving (dialog, drawer)
128
+ * progress a value moving (a progress bar's width)
129
+ *
130
+ * enter arriving: starts fast and settles
131
+ * exit leaving: starts slow and accelerates away
132
+ * move changing in place
133
+ *
134
+ * An exit runs one rung faster than its entrance and on exit:
135
+ * slow in, base out; base in, fast out. Entrances and exits move
136
+ * only opacity and transform.
123
137
  *
124
138
  * Tailwind builds no utility from a --duration-* token: there is
125
- * no such theme namespace, and `duration-collapse` compiles to
126
- * nothing at all. Each one is read through var() from an
127
- * arbitrary utility instead, which is why they are listed in
128
- * VAR_ONLY in theme-tokens.test.ts.
139
+ * no such theme namespace, and `duration-fast` would compile to
140
+ * nothing. The @utility rules after this block declare the four
141
+ * by hand, which is why the tokens are listed in VAR_ONLY in
142
+ * theme-tokens.test.ts. --ease-* is a real namespace and the
143
+ * three curves become ease-enter, ease-exit and ease-move on
144
+ * their own.
145
+ *
146
+ * Every transition-* utility reads the two --default-* values, so
147
+ * `transition-colors` alone is complete. Before this a component
148
+ * wrote `duration-150` fifty times to say the same thing.
129
149
  *
130
150
  * The reduced-motion block at the foot of this file overrides
131
- * every one of them and stays the authority on whether they run. */
132
- --duration-modal-in: 120ms; /* Modal, the centred entrance */
133
- --duration-toast-in: 140ms; /* Toaster, one toast arriving */
134
- --duration-drawer-in: 150ms; /* Drawer, either edge */
135
- --duration-collapse: 200ms; /* Accordion and Collapsible */
151
+ * every one of them and stays the authority on whether they run;
152
+ * the Svelte presets in motion.ts honour the same preference for
153
+ * the entrances and exits that run outside CSS. */
154
+ --duration-fast: 120ms;
155
+ --duration-base: 200ms;
156
+ --duration-slow: 320ms;
157
+ --duration-progress: 500ms;
158
+
159
+ --ease-enter: cubic-bezier(0.22, 1, 0.36, 1);
160
+ --ease-exit: cubic-bezier(0.32, 0, 0.67, 0);
161
+ --ease-move: cubic-bezier(0.65, 0, 0.35, 1);
162
+
163
+ --default-transition-duration: var(--duration-fast);
164
+ --default-transition-timing-function: var(--ease-move);
165
+
166
+ /* The one entrance that is a CSS animation. A panel inside <details> is
167
+ * shown and removed by the browser, so a Svelte transition never sees it
168
+ * leave; it plays this on the way in and nothing on the way out. Every
169
+ * other surface enters and leaves through the presets in motion.ts. */
170
+ --animate-popover-in: popover-in var(--duration-base) var(--ease-enter);
136
171
 
137
172
  /* ── Typography · families ───────────────────────────────────── */
138
173
  --font-sans:
@@ -242,7 +277,8 @@
242
277
  --spacing-input-y: 0.5rem; /* 8px - input vertical padding */
243
278
  /* 38px - the height of every single-line control. Stated once so an Input,
244
279
  * a Select and a NumberInput sitting in the same row line up. Derived from
245
- * the 13px/1.25 control text plus input-y padding and a 1px border. */
280
+ * the 13px/1.25 control text plus input-y padding and a 1px border. Under a
281
+ * coarse pointer it is 44px; see the touch-target block below the palette. */
246
282
  --spacing-control: 2.375rem;
247
283
  --spacing-panel-max: 15rem; /* 240px - the scroll cap on a floating option list */
248
284
  /* 56px - the app header bar, and the sidebar's brand row above the nav.
@@ -257,6 +293,58 @@
257
293
  --spacing-inline: 0.5rem; /* 8px - default inline gap */
258
294
  }
259
295
 
296
+ /*
297
+ * Touch targets.
298
+ *
299
+ * Measured over 48 admin routes at 400px: 2,007 of 2,097 visible controls
300
+ * were under the 44px SC 2.5.5 asks of a finger, and the kit owned 96% of
301
+ * them, because the control height above is 38px and it is right at 38px on
302
+ * a desktop. The size a pointer needs is a property of the pointer, not of
303
+ * the screen width, so the fix keys on `pointer: coarse` and a mouse never
304
+ * sees it: the desktop visual is unchanged to the pixel.
305
+ *
306
+ * Two mechanisms, chosen per control by whether the visual may grow.
307
+ *
308
+ * The token moves. Under a coarse pointer `--spacing-control` is 44px, so
309
+ * every single-line field, and every control that states `min-h-control`
310
+ * under the `coarse:` variant (Button, Tabs, a sidebar row, a menu item),
311
+ * grows to the finger's size and the row they share still lines up.
312
+ *
313
+ * `hit-area` does not move the visual. A switch, a checkbox, a breadcrumb, a
314
+ * pager button, a close cross and an icon inside an input are drawn small on
315
+ * purpose and grown to 44px would push their neighbours around; each one
316
+ * draws an invisible box centred on itself that is never smaller than the
317
+ * control size, and a tap on the box lands on the control. The element must
318
+ * be positioned (`relative`, or `absolute` where it already is) for the box
319
+ * to centre on it; the utility does not set position itself, because a
320
+ * position it set would fight the `absolute` an input's clear button relies
321
+ * on. Two neighbours' boxes may overlap; the later one in document order
322
+ * wins the overlap, which is the spacing exception SC 2.5.8 allows for.
323
+ */
324
+ @custom-variant coarse (@media (pointer: coarse));
325
+
326
+ @media (pointer: coarse) {
327
+ :root {
328
+ --spacing-control: 2.75rem; /* 44px */
329
+ }
330
+ }
331
+
332
+ @utility hit-area {
333
+ @media (pointer: coarse) {
334
+ &::before {
335
+ content: '';
336
+ position: absolute;
337
+ left: 50%;
338
+ top: 50%;
339
+ width: 100%;
340
+ height: 100%;
341
+ min-width: var(--spacing-control);
342
+ min-height: var(--spacing-control);
343
+ translate: -50% -50%;
344
+ }
345
+ }
346
+ }
347
+
260
348
  /* ── Soft Light · activated by html[data-theme="light"] ──────────────────── */
261
349
  html[data-theme='light'] {
262
350
  --color-ink: #f6f7f9;
@@ -290,61 +378,41 @@ html[data-theme='light'] {
290
378
  }
291
379
 
292
380
  /*
293
- * The entrance keyframes, declared here and not in the components that play
294
- * them.
295
- *
296
- * Modal, Drawer and Toaster each held their own `@keyframes` in a scoped
297
- * `<style>` block and started it from a Tailwind `animate-[...]` class. Svelte
298
- * renames a scoped keyframe to `svelte-<hash>-<name>` and rewrites only the
299
- * references inside that same style block, so the class asked the browser for
300
- * `modal-in` while the only rule declared was `svelte-ta60gp-modal-in`. An
301
- * animation-name that resolves to nothing is not an error: the element simply
302
- * appears, and all four entrances had been dead in every consumer.
303
- *
304
- * A keyframe named from a class has to be global, and the file every consumer
305
- * already imports is the one place it can be global from.
381
+ * The four durations as utilities. A --duration-* token generates nothing
382
+ * (see the motion section of the @theme block), so each is declared here the
383
+ * way Tailwind's own duration-* is: the custom property it sets is what the
384
+ * transition-* utilities read, and the longhand covers an element that
385
+ * writes `transition` by hand.
306
386
  */
307
- @keyframes modal-in {
308
- from {
309
- opacity: 0;
310
- transform: translateY(6px) scale(0.98);
311
- }
312
- to {
313
- opacity: 1;
314
- transform: translateY(0) scale(1);
315
- }
387
+ @utility duration-fast {
388
+ --tw-duration: var(--duration-fast);
389
+ transition-duration: var(--duration-fast);
316
390
  }
317
-
318
- @keyframes drawer-in-right {
319
- from {
320
- opacity: 0;
321
- transform: translateX(16px);
322
- }
323
- to {
324
- opacity: 1;
325
- transform: translateX(0);
326
- }
391
+ @utility duration-base {
392
+ --tw-duration: var(--duration-base);
393
+ transition-duration: var(--duration-base);
327
394
  }
328
-
329
- @keyframes drawer-in-left {
330
- from {
331
- opacity: 0;
332
- transform: translateX(-16px);
333
- }
334
- to {
335
- opacity: 1;
336
- transform: translateX(0);
337
- }
395
+ @utility duration-slow {
396
+ --tw-duration: var(--duration-slow);
397
+ transition-duration: var(--duration-slow);
398
+ }
399
+ @utility duration-progress {
400
+ --tw-duration: var(--duration-progress);
401
+ transition-duration: var(--duration-progress);
338
402
  }
339
403
 
340
- @keyframes toast-in {
404
+ /*
405
+ * Declared here and not in the component that plays it. Svelte renames a
406
+ * scoped keyframe to `svelte-<hash>-<name>` and rewrites only the references
407
+ * inside that same style block, so a class asking for `popover-in` would find
408
+ * no rule and the element would simply appear. A keyframe named from a class
409
+ * has to be global, and the file every consumer imports is the one place it
410
+ * can be global from. It draws the same frame as the popover preset.
411
+ */
412
+ @keyframes popover-in {
341
413
  from {
342
414
  opacity: 0;
343
- transform: translateX(12px);
344
- }
345
- to {
346
- opacity: 1;
347
- transform: translateX(0);
415
+ transform: translateY(-4px) scale(0.96);
348
416
  }
349
417
  }
350
418