@urbicon-ui/blocks 6.21.0 → 6.21.2

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 (142) hide show
  1. package/dist/components/Calendar/calendar.variants.d.ts +132 -419
  2. package/dist/components/CommandPalette/commandPalette.variants.d.ts +24 -51
  3. package/dist/components/CompositionBar/CompositionBar.svelte +6 -1
  4. package/dist/components/CompositionBar/composition-bar.variants.d.ts +23 -83
  5. package/dist/components/CompositionBar/composition-bar.variants.js +9 -3
  6. package/dist/components/EmptyState/emptyState.variants.d.ts +11 -27
  7. package/dist/components/FileUpload/fileUpload.variants.d.ts +24 -93
  8. package/dist/components/Guide/GuidePanel.svelte +38 -0
  9. package/dist/components/Guide/guide.variants.d.ts +69 -124
  10. package/dist/components/Guide/guide.variants.js +6 -1
  11. package/dist/components/NumberInput/NumberInput.svelte +197 -0
  12. package/dist/components/NumberInput/NumberInput.svelte.d.ts +4 -0
  13. package/dist/components/NumberInput/index.d.ts +55 -0
  14. package/dist/components/NumberInput/index.js +1 -0
  15. package/dist/components/Planner/planner.variants.d.ts +23 -94
  16. package/dist/components/Sankey/sankey.variants.d.ts +15 -48
  17. package/dist/components/SidebarLayout/sidebar-layout.variants.d.ts +10 -38
  18. package/dist/components/SidebarLayout/sidebar-layout.variants.js +12 -2
  19. package/dist/components/ThemeSwitcher/themeSwitcher.variants.d.ts +9 -36
  20. package/dist/components/index.d.ts +2 -0
  21. package/dist/components/index.js +1 -0
  22. package/dist/i18n/index.d.ts +8 -372
  23. package/dist/internal/charts/variants.d.ts +18 -31
  24. package/dist/primitives/Accordion/Accordion.svelte +11 -0
  25. package/dist/primitives/Accordion/AccordionItem.svelte +9 -3
  26. package/dist/primitives/Accordion/accordion.variants.d.ts +12 -43
  27. package/dist/primitives/Accordion/accordion.variants.js +6 -2
  28. package/dist/primitives/Accordion/index.d.ts +12 -0
  29. package/dist/primitives/Alert/alert.variants.d.ts +21 -62
  30. package/dist/primitives/Avatar/avatar.variants.d.ts +18 -138
  31. package/dist/primitives/Badge/Badge.svelte +12 -4
  32. package/dist/primitives/Badge/badge.variants.d.ts +19 -92
  33. package/dist/primitives/Badge/badge.variants.js +11 -4
  34. package/dist/primitives/Badge/index.d.ts +26 -6
  35. package/dist/primitives/Breadcrumb/Breadcrumb.svelte +11 -6
  36. package/dist/primitives/Breadcrumb/breadcrumb.variants.d.ts +13 -40
  37. package/dist/primitives/Breadcrumb/index.d.ts +2 -2
  38. package/dist/primitives/Button/button.variants.d.ts +19 -98
  39. package/dist/primitives/Button/button.variants.js +13 -9
  40. package/dist/primitives/ButtonGroup/buttongroup.variants.d.ts +9 -29
  41. package/dist/primitives/ButtonGroup/buttongroup.variants.js +3 -1
  42. package/dist/primitives/Card/card.variants.d.ts +14 -81
  43. package/dist/primitives/Checkbox/Checkbox.svelte +3 -3
  44. package/dist/primitives/Checkbox/checkbox.variants.d.ts +18 -77
  45. package/dist/primitives/Collapsible/Collapsible.svelte +10 -0
  46. package/dist/primitives/Collapsible/collapsible.variants.d.ts +11 -40
  47. package/dist/primitives/Collapsible/collapsible.variants.js +7 -2
  48. package/dist/primitives/Collapsible/index.d.ts +16 -0
  49. package/dist/primitives/Combobox/Combobox.svelte +478 -104
  50. package/dist/primitives/Combobox/combobox.variants.d.ts +112 -94
  51. package/dist/primitives/Combobox/combobox.variants.js +94 -13
  52. package/dist/primitives/Combobox/index.d.ts +166 -51
  53. package/dist/primitives/ConfirmDialog/index.d.ts +19 -0
  54. package/dist/primitives/Dialog/Dialog.svelte +95 -10
  55. package/dist/primitives/Dialog/dialog.variants.d.ts +15 -54
  56. package/dist/primitives/Dialog/index.d.ts +12 -1
  57. package/dist/primitives/Drawer/Drawer.svelte +23 -11
  58. package/dist/primitives/Drawer/drawer.variants.d.ts +22 -49
  59. package/dist/primitives/Drawer/drawer.variants.js +45 -10
  60. package/dist/primitives/Drawer/index.d.ts +13 -4
  61. package/dist/primitives/FormField/FormField.svelte +6 -6
  62. package/dist/primitives/FormField/index.d.ts +13 -4
  63. package/dist/primitives/Input/Input.svelte +8 -4
  64. package/dist/primitives/Input/input.variants.d.ts +32 -139
  65. package/dist/primitives/Input/input.variants.js +12 -10
  66. package/dist/primitives/JourneyTimeline/journey-timeline.variants.d.ts +55 -197
  67. package/dist/primitives/JourneyTimeline/journey-timeline.variants.js +4 -1
  68. package/dist/primitives/Menu/Menu.svelte +66 -4
  69. package/dist/primitives/Menu/index.d.ts +25 -0
  70. package/dist/primitives/Menu/menu.variants.d.ts +29 -93
  71. package/dist/primitives/Pagination/Pagination.svelte +28 -13
  72. package/dist/primitives/Pagination/index.d.ts +44 -0
  73. package/dist/primitives/Pagination/pagination.variants.d.ts +16 -54
  74. package/dist/primitives/Pagination/pagination.variants.js +16 -14
  75. package/dist/primitives/Popover/Popover.svelte +11 -1
  76. package/dist/primitives/Popover/index.d.ts +3 -3
  77. package/dist/primitives/Popover/popover.variants.d.ts +4 -2
  78. package/dist/primitives/Progress/progress.variants.d.ts +19 -83
  79. package/dist/primitives/Progress/progress.variants.js +2 -1
  80. package/dist/primitives/RadioGroup/RadioGroup.svelte +3 -3
  81. package/dist/primitives/RadioGroup/radioGroup.variants.d.ts +28 -109
  82. package/dist/primitives/SegmentGroup/SegmentGroup.svelte +14 -6
  83. package/dist/primitives/SegmentGroup/segmentgroup.variants.d.ts +12 -53
  84. package/dist/primitives/SegmentGroup/segmentgroup.variants.js +10 -10
  85. package/dist/primitives/Select/Select.svelte +21 -11
  86. package/dist/primitives/Select/index.d.ts +7 -0
  87. package/dist/primitives/Select/select.variants.d.ts +61 -150
  88. package/dist/primitives/Select/select.variants.js +24 -4
  89. package/dist/primitives/Separator/separator.variants.d.ts +4 -2
  90. package/dist/primitives/Sidebar/Sidebar.svelte +10 -15
  91. package/dist/primitives/Sidebar/sidebar.variants.d.ts +11 -29
  92. package/dist/primitives/Skeleton/skeleton.variants.d.ts +9 -36
  93. package/dist/primitives/Slider/Slider.svelte +4 -8
  94. package/dist/primitives/Slider/slider.variants.d.ts +37 -136
  95. package/dist/primitives/Slider/slider.variants.js +8 -5
  96. package/dist/primitives/Spinner/spinner.variants.d.ts +38 -135
  97. package/dist/primitives/Stepper/stepper.variants.d.ts +32 -130
  98. package/dist/primitives/Tab/Tab.svelte +14 -6
  99. package/dist/primitives/Tab/tab.variants.d.ts +17 -78
  100. package/dist/primitives/Textarea/Textarea.svelte +4 -5
  101. package/dist/primitives/Textarea/textarea.variants.d.ts +33 -118
  102. package/dist/primitives/Textarea/textarea.variants.js +17 -12
  103. package/dist/primitives/Toast/Toaster.svelte +58 -5
  104. package/dist/primitives/Toast/index.d.ts +39 -0
  105. package/dist/primitives/Toast/toast.store.svelte.d.ts +25 -1
  106. package/dist/primitives/Toast/toast.store.svelte.js +91 -1
  107. package/dist/primitives/Toast/toast.variants.d.ts +40 -78
  108. package/dist/primitives/Toast/toast.variants.js +15 -0
  109. package/dist/primitives/Toggle/Toggle.svelte +17 -3
  110. package/dist/primitives/Toggle/index.d.ts +8 -2
  111. package/dist/primitives/Toggle/toggle.variants.d.ts +24 -71
  112. package/dist/primitives/Toggle/toggle.variants.js +26 -0
  113. package/dist/primitives/Toolbar/toolbar.variants.d.ts +9 -60
  114. package/dist/primitives/Tooltip/Tooltip.svelte +58 -21
  115. package/dist/primitives/Tooltip/Tooltip.svelte.d.ts +1 -1
  116. package/dist/primitives/Tooltip/index.d.ts +45 -3
  117. package/dist/primitives/Tooltip/tooltip.variants.d.ts +14 -53
  118. package/dist/primitives/Tooltip/tooltip.variants.js +9 -3
  119. package/dist/primitives/index.d.ts +3 -3
  120. package/dist/style/foundation.css +4 -1
  121. package/dist/style/interaction.css +39 -11
  122. package/dist/style/semantic.css +2 -2
  123. package/dist/style/themes/index.css +1 -1
  124. package/dist/translations/de.d.ts +3 -0
  125. package/dist/translations/de.js +4 -1
  126. package/dist/translations/en.d.ts +3 -0
  127. package/dist/translations/en.js +4 -1
  128. package/dist/utils/guide.svelte.d.ts +8 -2
  129. package/dist/utils/guide.svelte.js +86 -5
  130. package/dist/utils/index.d.ts +2 -1
  131. package/dist/utils/index.js +5 -0
  132. package/dist/utils/overlay.d.ts +33 -4
  133. package/dist/utils/overlay.js +61 -18
  134. package/dist/utils/roving.d.ts +15 -0
  135. package/dist/utils/roving.js +44 -0
  136. package/dist/utils/use-floating-panel.svelte.d.ts +4 -1
  137. package/dist/utils/use-floating-panel.svelte.js +23 -1
  138. package/dist/utils/use-form-field.svelte.d.ts +9 -9
  139. package/dist/utils/use-form-field.svelte.js +12 -12
  140. package/dist/utils/variants.d.ts +60 -16
  141. package/dist/utils/variants.js +424 -123
  142. package/package.json +9 -6
@@ -3,14 +3,9 @@
3
3
  import { getBlocksConfig, resolveSlotClasses } from '../../provider';
4
4
  import { resolveIcon } from '../../icons';
5
5
  import CloseIconDefault from '../../icons/CloseIcon.svelte';
6
- import { onDestroy } from 'svelte';
6
+ import { onDestroy, tick } from 'svelte';
7
7
  import { fade, fly } from 'svelte/transition';
8
- import {
9
- trapFocus,
10
- showDialogModal,
11
- closeDialogModal,
12
- unlockBodyScroll
13
- } from '../../utils/overlay';
8
+ import { trapFocus, showDialogModal, closeDialogModal } from '../../utils/overlay';
14
9
  import { overlayStack, getOverlayMotion } from '../../utils';
15
10
  import Button from '../Button/Button.svelte';
16
11
  import type { DrawerProps } from './index';
@@ -28,6 +23,7 @@
28
23
  placement = 'right',
29
24
  size = 'md',
30
25
  intent = 'neutral',
26
+ accentEdge = false,
31
27
  onClose,
32
28
  hideCloseButton = false,
33
29
  closeOnBackdropClick = true,
@@ -61,13 +57,16 @@
61
57
  let panelElement = $state<HTMLElement>();
62
58
  let isVisible = $state(false);
63
59
  let previouslyFocused: HTMLElement | null = null;
60
+ // Release for the body-scroll lock this instance holds while modal — set by
61
+ // showDialogModal, idempotent, so both teardown paths below may call it.
62
+ let releaseScrollLock: (() => void) | undefined;
64
63
 
65
64
  const uid = $props.id();
66
65
  const titleId = $derived(title ? `drawer-title-${uid}` : undefined);
67
66
  const bodyId = `drawer-body-${uid}`;
68
67
  const overlayId = `drawer-${uid}`;
69
68
 
70
- const variantProps: DrawerVariants = $derived({ placement, size, intent });
69
+ const variantProps: DrawerVariants = $derived({ placement, size, intent, accentEdge });
71
70
  const styles = $derived(drawerVariants(variantProps));
72
71
  const slotClasses = $derived(
73
72
  resolveSlotClasses(blocksConfig, 'Drawer', preset, variantProps, slotClassesProp)
@@ -122,7 +121,15 @@
122
121
  if (open && !isVisible) {
123
122
  isVisible = true;
124
123
  previouslyFocused = document.activeElement as HTMLElement;
125
- showDialogModal(dialogElement, panelElement);
124
+ // Defer until the `{#if isVisible}` block has rendered so `bind:this` has
125
+ // assigned dialogElement/panelElement — showDialogModal captures the refs
126
+ // by value, so promoting before the bind would silently no-op (never modal).
127
+ // The guard covers same-flush teardown: if the component unmounts before
128
+ // the tick resolves, bind:this has nulled dialogElement and onDestroy has
129
+ // already run — a lock taken now could never be released.
130
+ tick().then(() => {
131
+ if (dialogElement) releaseScrollLock = showDialogModal(dialogElement, panelElement);
132
+ });
126
133
  }
127
134
  });
128
135
 
@@ -132,7 +139,11 @@
132
139
  });
133
140
 
134
141
  onDestroy(() => {
135
- unlockBodyScroll();
142
+ // Safety net for destroy-while-open, where no outro runs. Releasing is
143
+ // idempotent and scoped to this instance's own lock, so a regular close
144
+ // (already released in handleOutroEnd) or a never-opened instance make
145
+ // this a no-op — it can never free another overlay's lock.
146
+ releaseScrollLock?.();
136
147
  });
137
148
 
138
149
  function handleBackdropDirectClick() {
@@ -149,7 +160,8 @@
149
160
  }
150
161
 
151
162
  function handleOutroEnd() {
152
- closeDialogModal(dialogElement, previouslyFocused);
163
+ closeDialogModal(dialogElement, previouslyFocused, releaseScrollLock);
164
+ releaseScrollLock = undefined;
153
165
  isVisible = false;
154
166
  previouslyFocused = null;
155
167
  }
@@ -1,95 +1,68 @@
1
1
  import { type SlotNames, type VariantProps } from '../../utils/variants.js';
2
- export declare const drawerVariants: (props?: import("../../utils/variants.js").TVProps<{
3
- placement: {
4
- left: {
5
- dialog: string;
6
- panel: string;
7
- };
8
- right: {
9
- dialog: string;
10
- panel: string;
11
- };
12
- top: {
13
- dialog: string;
14
- panel: string;
15
- };
16
- bottom: {
17
- dialog: string;
18
- panel: string;
19
- };
20
- };
21
- size: {
22
- sm: {};
23
- md: {};
24
- lg: {};
25
- xl: {};
26
- full: {};
27
- };
28
- intent: {
29
- neutral: {};
30
- primary: {};
31
- secondary: {};
32
- success: {};
33
- warning: {};
34
- danger: {};
35
- };
36
- }> | undefined) => {
2
+ export declare const drawerVariants: ((props?: {
3
+ placement?: "top" | "right" | "bottom" | "left" | undefined;
4
+ size?: "sm" | "md" | "lg" | "xl" | "full" | undefined;
5
+ intent?: "primary" | "secondary" | "success" | "warning" | "danger" | "neutral" | undefined;
6
+ accentEdge?: boolean | undefined;
7
+ } | undefined) => {
37
8
  dialog: (props?: ({
38
9
  placement?: "top" | "right" | "bottom" | "left" | undefined;
39
10
  size?: "sm" | "md" | "lg" | "xl" | "full" | undefined;
40
11
  intent?: "primary" | "secondary" | "success" | "warning" | "danger" | "neutral" | undefined;
12
+ accentEdge?: boolean | undefined;
41
13
  } & {
42
- class?: string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | /*elided*/ any | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined;
43
- className?: string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | /*elided*/ any | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined;
14
+ class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
44
15
  }) | undefined) => string;
45
16
  backdrop: (props?: ({
46
17
  placement?: "top" | "right" | "bottom" | "left" | undefined;
47
18
  size?: "sm" | "md" | "lg" | "xl" | "full" | undefined;
48
19
  intent?: "primary" | "secondary" | "success" | "warning" | "danger" | "neutral" | undefined;
20
+ accentEdge?: boolean | undefined;
49
21
  } & {
50
- class?: string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | /*elided*/ any | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined;
51
- className?: string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | /*elided*/ any | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined;
22
+ class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
52
23
  }) | undefined) => string;
53
24
  panel: (props?: ({
54
25
  placement?: "top" | "right" | "bottom" | "left" | undefined;
55
26
  size?: "sm" | "md" | "lg" | "xl" | "full" | undefined;
56
27
  intent?: "primary" | "secondary" | "success" | "warning" | "danger" | "neutral" | undefined;
28
+ accentEdge?: boolean | undefined;
57
29
  } & {
58
- class?: string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | /*elided*/ any | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined;
59
- className?: string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | /*elided*/ any | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined;
30
+ class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
60
31
  }) | undefined) => string;
61
32
  header: (props?: ({
62
33
  placement?: "top" | "right" | "bottom" | "left" | undefined;
63
34
  size?: "sm" | "md" | "lg" | "xl" | "full" | undefined;
64
35
  intent?: "primary" | "secondary" | "success" | "warning" | "danger" | "neutral" | undefined;
36
+ accentEdge?: boolean | undefined;
65
37
  } & {
66
- class?: string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | /*elided*/ any | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined;
67
- className?: string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | /*elided*/ any | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined;
38
+ class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
68
39
  }) | undefined) => string;
69
40
  title: (props?: ({
70
41
  placement?: "top" | "right" | "bottom" | "left" | undefined;
71
42
  size?: "sm" | "md" | "lg" | "xl" | "full" | undefined;
72
43
  intent?: "primary" | "secondary" | "success" | "warning" | "danger" | "neutral" | undefined;
44
+ accentEdge?: boolean | undefined;
73
45
  } & {
74
- class?: string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | /*elided*/ any | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined;
75
- className?: string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | /*elided*/ any | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined;
46
+ class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
76
47
  }) | undefined) => string;
77
48
  body: (props?: ({
78
49
  placement?: "top" | "right" | "bottom" | "left" | undefined;
79
50
  size?: "sm" | "md" | "lg" | "xl" | "full" | undefined;
80
51
  intent?: "primary" | "secondary" | "success" | "warning" | "danger" | "neutral" | undefined;
52
+ accentEdge?: boolean | undefined;
81
53
  } & {
82
- class?: string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | /*elided*/ any | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined;
83
- className?: string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | /*elided*/ any | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined;
54
+ class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
84
55
  }) | undefined) => string;
85
56
  footer: (props?: ({
86
57
  placement?: "top" | "right" | "bottom" | "left" | undefined;
87
58
  size?: "sm" | "md" | "lg" | "xl" | "full" | undefined;
88
59
  intent?: "primary" | "secondary" | "success" | "warning" | "danger" | "neutral" | undefined;
60
+ accentEdge?: boolean | undefined;
89
61
  } & {
90
- class?: string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | /*elided*/ any | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined;
91
- className?: string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | (string | false | /*elided*/ any | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined)[] | null | undefined;
62
+ class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
92
63
  }) | undefined) => string;
64
+ }) & {
65
+ readonly config: import("../../utils/variants.js").TVConfig;
93
66
  };
94
67
  export type DrawerVariants = VariantProps<typeof drawerVariants>;
95
68
  /** Slot names derived from the `tv()` config above — single source of truth for `slotClasses`. */
@@ -53,13 +53,24 @@ export const drawerVariants = tv({
53
53
  xl: {},
54
54
  full: {}
55
55
  },
56
+ // Semantic purpose. By default the Drawer paints no accent (symmetry with
57
+ // Dialog — intent is surfaced only as `data-intent` for consumer hooks).
58
+ // Each value additionally parks its colour in `--drawer-accent`, consumed
59
+ // *only* when `accentEdge` is on (see the accentEdge×placement compounds).
56
60
  intent: {
57
- neutral: {},
58
- primary: {},
59
- secondary: {},
60
- success: {},
61
- warning: {},
62
- danger: {}
61
+ neutral: { panel: '[--drawer-accent:var(--color-border-strong)]' },
62
+ primary: { panel: '[--drawer-accent:var(--color-primary)]' },
63
+ secondary: { panel: '[--drawer-accent:var(--color-secondary)]' },
64
+ success: { panel: '[--drawer-accent:var(--color-success)]' },
65
+ warning: { panel: '[--drawer-accent:var(--color-warning)]' },
66
+ danger: { panel: '[--drawer-accent:var(--color-danger)]' }
67
+ },
68
+ // Opt-in edge accent (DRW-1 completion). Off by default so the Drawer keeps
69
+ // Dialog symmetry; on, the docked (viewport-facing) edge is thickened to 2px
70
+ // and tinted in the intent colour via the placement compounds below.
71
+ accentEdge: {
72
+ true: {},
73
+ false: {}
63
74
  }
64
75
  },
65
76
  compoundVariants: [
@@ -84,13 +95,37 @@ export const drawerVariants = tv({
84
95
  { placement: 'bottom', size: 'md', class: { panel: 'h-72' } },
85
96
  { placement: 'bottom', size: 'lg', class: { panel: 'h-96' } },
86
97
  { placement: 'bottom', size: 'xl', class: { panel: 'h-[32rem]' } },
87
- { placement: 'bottom', size: 'full', class: { panel: 'h-full' } }
88
- // Intent accent borders removed for symmetry with Dialog.
89
- // Intent is conveyed at the call site via icon + heading color.
98
+ { placement: 'bottom', size: 'full', class: { panel: 'h-full' } },
99
+ // Edge accent (opt-in via `accentEdge`). The tinted 2px border lands on the
100
+ // *inner* edge the one facing the viewport so it reads as a coloured seam
101
+ // between the drawer and the page, never a floating outline. Placement picks
102
+ // the physical side; the colour comes from `--drawer-accent` (intent axis).
103
+ // Default (no accentEdge) leaves the panel exactly as before — Dialog symmetry.
104
+ {
105
+ accentEdge: true,
106
+ placement: 'left',
107
+ class: { panel: 'border-r-2 [border-right-color:var(--drawer-accent)]' }
108
+ },
109
+ {
110
+ accentEdge: true,
111
+ placement: 'right',
112
+ class: { panel: 'border-l-2 [border-left-color:var(--drawer-accent)]' }
113
+ },
114
+ {
115
+ accentEdge: true,
116
+ placement: 'top',
117
+ class: { panel: 'border-b-2 [border-bottom-color:var(--drawer-accent)]' }
118
+ },
119
+ {
120
+ accentEdge: true,
121
+ placement: 'bottom',
122
+ class: { panel: 'border-t-2 [border-top-color:var(--drawer-accent)]' }
123
+ }
90
124
  ],
91
125
  defaultVariants: {
92
126
  placement: 'right',
93
127
  size: 'md',
94
- intent: 'neutral'
128
+ intent: 'neutral',
129
+ accentEdge: false
95
130
  }
96
131
  });
@@ -37,13 +37,22 @@ export interface DrawerProps extends Omit<HTMLDialogAttributes, 'children' | 'op
37
37
  /** Width (for left/right) or height (for top/bottom) of the drawer panel. @default 'md' */
38
38
  size?: DrawerVariants['size'];
39
39
  /**
40
- * Semantic purpose marker (mirrors Dialog). After the Lighter-Refactor,
41
- * the Drawer itself no longer paints an accent border the value is
42
- * exposed on the panel as `data-intent="…"` so consumers can hook
43
- * presets, CSS overrides, or icon/title color via their own snippets.
40
+ * Semantic purpose marker (mirrors Dialog). By default the Drawer paints no
41
+ * accent border the value is exposed on the panel as `data-intent="…"` so
42
+ * consumers can hook presets, CSS overrides, or icon/title color via their own
43
+ * snippets. Set {@link accentEdge} to also tint the docked edge in this colour.
44
44
  * @default 'neutral'
45
45
  */
46
46
  intent?: DrawerVariants['intent'];
47
+ /**
48
+ * Tint the panel's docked (viewport-facing) edge with a 2px accent border in
49
+ * the {@link intent} colour — `border-right` for `left`, `border-left` for
50
+ * `right`, `border-bottom` for `top`, `border-top` for `bottom`. Off by
51
+ * default, keeping symmetry with Dialog; opt in for a coloured seam that ties
52
+ * the drawer to a semantic purpose (e.g. a `danger` confirm drawer).
53
+ * @default false
54
+ */
55
+ accentEdge?: DrawerVariants['accentEdge'];
47
56
  /** Fires when the drawer is dismissed via Escape, backdrop click, or close button. */
48
57
  onClose?: () => void;
49
58
  /** Hides the built-in close button in the header. @default false */
@@ -4,7 +4,7 @@
4
4
 
5
5
  let {
6
6
  label,
7
- hint,
7
+ helper,
8
8
  error,
9
9
  required = false,
10
10
  disabled = false,
@@ -20,7 +20,7 @@
20
20
  // `useFormField` / XC-2 for the contract.
21
21
  const ff = useFormField(() => ({
22
22
  fieldId: idProp ?? `field-${propsId}`,
23
- hint,
23
+ helper,
24
24
  error,
25
25
  required,
26
26
  disabled
@@ -59,12 +59,12 @@
59
59
  >
60
60
  {error}
61
61
  </div>
62
- {:else if ff.hintId}
62
+ {:else if ff.helperId}
63
63
  <div
64
- id={ff.hintId}
65
- class={['text-text-tertiary text-xs', slotClasses.hint].filter(Boolean).join(' ')}
64
+ id={ff.helperId}
65
+ class={['text-text-tertiary text-xs', slotClasses.helper].filter(Boolean).join(' ')}
66
66
  >
67
- {hint}
67
+ {helper}
68
68
  </div>
69
69
  {/if}
70
70
  </div>
@@ -17,7 +17,7 @@ import type { HTMLAttributes } from 'svelte/elements';
17
17
  *
18
18
  * @example
19
19
  * ```svelte
20
- * <FormField label="Document" required error={fileError} hint="PDF, JPG, PNG — max 10 MB">
20
+ * <FormField label="Document" required error={fileError} helper="PDF, JPG, PNG — max 10 MB">
21
21
  * {#snippet children({ id, describedBy, invalid })}
22
22
  * <FileUpload {id} aria-describedby={describedBy} aria-invalid={invalid} bind:files />
23
23
  * {/snippet}
@@ -27,8 +27,12 @@ import type { HTMLAttributes } from 'svelte/elements';
27
27
  export interface FormFieldProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {
28
28
  /** Label rendered above the control. Auto-linked to the slot via the generated `id`. */
29
29
  label?: string;
30
- /** Helper text shown below the control. Hidden when `error` is present. */
31
- hint?: string;
30
+ /**
31
+ * Helper text shown below the control. Hidden when `error` is present.
32
+ * Named `helper` to match the built-in helper prop of the form primitives
33
+ * (Input, Select, Toggle, …) — one vocabulary across the API seam.
34
+ */
35
+ helper?: string;
32
36
  /**
33
37
  * Error message shown below the control. Replaces the helper text and
34
38
  * propagates `invalid: true` to the slot for ARIA wiring.
@@ -54,8 +58,13 @@ export interface FormFieldProps extends Omit<HTMLAttributes<HTMLDivElement>, 'ch
54
58
  class?: string;
55
59
  /**
56
60
  * Per-slot class overrides.
61
+ *
62
+ * FormField has no `tv()` config (it is a bare layout wrapper), so this
63
+ * key union is a hand-maintained literal instead of the usual
64
+ * `SlotNames<typeof xVariants>` derivation — keep it in sync with the
65
+ * elements rendered in `FormField.svelte`.
57
66
  */
58
- slotClasses?: Partial<Record<'wrapper' | 'label' | 'message' | 'hint', string>>;
67
+ slotClasses?: Partial<Record<'wrapper' | 'label' | 'message' | 'helper', string>>;
59
68
  /**
60
69
  * Snippet receiving wiring metadata (`id`, `describedBy`, `invalid`,
61
70
  * `required`, `disabled`). The wrapped control should spread or apply
@@ -42,6 +42,7 @@
42
42
  persistDebounceMs = 300,
43
43
  persistVersion = 1,
44
44
  persistNamespace,
45
+ onkeydown: userOnKeydown,
45
46
  ...restProps
46
47
  }: InputProps = $props();
47
48
 
@@ -119,7 +120,7 @@
119
120
  const propsId = $props.id();
120
121
  const ff = useFormField(() => ({
121
122
  fieldId: `input-${propsId}`,
122
- hint: helper,
123
+ helper,
123
124
  error,
124
125
  required,
125
126
  disabled
@@ -147,11 +148,14 @@
147
148
  if (!disabled && onRightIconClick) onRightIconClick();
148
149
  }
149
150
 
150
- function handleKeydown(event: KeyboardEvent) {
151
+ function handleKeydown(event: KeyboardEvent & { currentTarget: EventTarget & HTMLInputElement }) {
151
152
  if (event.key === 'Escape' && shouldShowClear) {
152
153
  event.preventDefault();
153
154
  handleClear();
154
155
  }
156
+ // Forward the consumer's onkeydown (NumberInput's Arrow-step, etc.) — Input's
157
+ // own handler is hardcoded on the element, so without this it would swallow it.
158
+ userOnKeydown?.(event);
155
159
  }
156
160
 
157
161
  $effect(() => {
@@ -280,9 +284,9 @@
280
284
  >
281
285
  {error}
282
286
  </div>
283
- {:else if ff.hintId}
287
+ {:else if ff.helperId}
284
288
  <div
285
- id={ff.hintId}
289
+ id={ff.helperId}
286
290
  class={unstyled
287
291
  ? (slotClasses?.message ?? '')
288
292
  : styles.message({ class: slotClasses?.message })}