@happyvertical/smrt-ui 0.38.26 → 0.39.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 (205) hide show
  1. package/AGENTS.md +23 -7
  2. package/README.md +132 -0
  3. package/dist/components/data/CollectionList.svelte +106 -0
  4. package/dist/components/data/CollectionList.svelte.d.ts +49 -0
  5. package/dist/components/data/CollectionList.svelte.d.ts.map +1 -0
  6. package/dist/components/data/CollectionToolbar.svelte +72 -0
  7. package/dist/components/data/CollectionToolbar.svelte.d.ts +20 -0
  8. package/dist/components/data/CollectionToolbar.svelte.d.ts.map +1 -0
  9. package/dist/components/data/DataTable.svelte +107 -17
  10. package/dist/components/data/DataTable.svelte.d.ts +2 -2
  11. package/dist/components/data/DataTable.svelte.d.ts.map +1 -1
  12. package/dist/components/data/__tests__/DataTable.test.js +61 -1
  13. package/dist/components/data/index.d.ts +2 -0
  14. package/dist/components/data/index.d.ts.map +1 -1
  15. package/dist/components/data/index.js +2 -0
  16. package/dist/components/data/types.d.ts +33 -0
  17. package/dist/components/data/types.d.ts.map +1 -1
  18. package/dist/components/feedback/Alert.svelte +53 -0
  19. package/dist/components/feedback/Alert.svelte.d.ts +14 -0
  20. package/dist/components/feedback/Alert.svelte.d.ts.map +1 -0
  21. package/dist/components/feedback/Drawer.svelte +34 -0
  22. package/dist/components/feedback/Drawer.svelte.d.ts +18 -0
  23. package/dist/components/feedback/Drawer.svelte.d.ts.map +1 -0
  24. package/dist/components/feedback/Meter.svelte +33 -0
  25. package/dist/components/feedback/Meter.svelte.d.ts +16 -0
  26. package/dist/components/feedback/Meter.svelte.d.ts.map +1 -0
  27. package/dist/components/feedback/Modal.svelte +9 -5
  28. package/dist/components/feedback/Modal.svelte.d.ts +2 -2
  29. package/dist/components/feedback/Modal.svelte.d.ts.map +1 -1
  30. package/dist/components/feedback/Progress.svelte +61 -0
  31. package/dist/components/feedback/Progress.svelte.d.ts +14 -0
  32. package/dist/components/feedback/Progress.svelte.d.ts.map +1 -0
  33. package/dist/components/feedback/Spinner.svelte +17 -0
  34. package/dist/components/feedback/Spinner.svelte.d.ts +9 -0
  35. package/dist/components/feedback/Spinner.svelte.d.ts.map +1 -0
  36. package/dist/components/feedback/ToastViewport.svelte +48 -0
  37. package/dist/components/feedback/ToastViewport.svelte.d.ts +10 -0
  38. package/dist/components/feedback/ToastViewport.svelte.d.ts.map +1 -0
  39. package/dist/components/feedback/__tests__/toast.test.js +49 -0
  40. package/dist/components/feedback/index.d.ts +8 -0
  41. package/dist/components/feedback/index.d.ts.map +1 -1
  42. package/dist/components/feedback/index.js +10 -3
  43. package/dist/components/feedback/toast.d.ts +28 -0
  44. package/dist/components/feedback/toast.d.ts.map +1 -0
  45. package/dist/components/feedback/toast.js +58 -0
  46. package/dist/components/forms/Checkbox.svelte +149 -0
  47. package/dist/components/forms/Checkbox.svelte.d.ts +13 -0
  48. package/dist/components/forms/Checkbox.svelte.d.ts.map +1 -0
  49. package/dist/components/forms/Combobox.svelte +172 -0
  50. package/dist/components/forms/Combobox.svelte.d.ts +18 -0
  51. package/dist/components/forms/Combobox.svelte.d.ts.map +1 -0
  52. package/dist/components/forms/DatePicker.svelte +25 -0
  53. package/dist/components/forms/DatePicker.svelte.d.ts +12 -0
  54. package/dist/components/forms/DatePicker.svelte.d.ts.map +1 -0
  55. package/dist/components/forms/ErrorSummary.svelte +32 -0
  56. package/dist/components/forms/ErrorSummary.svelte.d.ts +11 -0
  57. package/dist/components/forms/ErrorSummary.svelte.d.ts.map +1 -0
  58. package/dist/components/forms/Fieldset.svelte +32 -0
  59. package/dist/components/forms/Fieldset.svelte.d.ts +13 -0
  60. package/dist/components/forms/Fieldset.svelte.d.ts.map +1 -0
  61. package/dist/components/forms/FilePicker.svelte +116 -0
  62. package/dist/components/forms/FilePicker.svelte.d.ts +19 -0
  63. package/dist/components/forms/FilePicker.svelte.d.ts.map +1 -0
  64. package/dist/components/forms/Form.svelte +55 -2
  65. package/dist/components/forms/Form.svelte.d.ts +11 -1
  66. package/dist/components/forms/Form.svelte.d.ts.map +1 -1
  67. package/dist/components/forms/FormGroup.svelte +19 -2
  68. package/dist/components/forms/FormGroup.svelte.d.ts +3 -0
  69. package/dist/components/forms/FormGroup.svelte.d.ts.map +1 -1
  70. package/dist/components/forms/Input.svelte +127 -0
  71. package/dist/components/forms/Input.svelte.d.ts +9 -1
  72. package/dist/components/forms/Input.svelte.d.ts.map +1 -1
  73. package/dist/components/forms/InputGroup.svelte +17 -0
  74. package/dist/components/forms/InputGroup.svelte.d.ts +11 -0
  75. package/dist/components/forms/InputGroup.svelte.d.ts.map +1 -0
  76. package/dist/components/forms/Listbox.svelte +97 -0
  77. package/dist/components/forms/Listbox.svelte.d.ts +15 -0
  78. package/dist/components/forms/Listbox.svelte.d.ts.map +1 -0
  79. package/dist/components/forms/MultiSelect.svelte +159 -0
  80. package/dist/components/forms/MultiSelect.svelte.d.ts +16 -0
  81. package/dist/components/forms/MultiSelect.svelte.d.ts.map +1 -0
  82. package/dist/components/forms/Radio.svelte +34 -0
  83. package/dist/components/forms/Radio.svelte.d.ts +10 -0
  84. package/dist/components/forms/Radio.svelte.d.ts.map +1 -0
  85. package/dist/components/forms/RadioGroup.svelte +130 -0
  86. package/dist/components/forms/RadioGroup.svelte.d.ts +19 -0
  87. package/dist/components/forms/RadioGroup.svelte.d.ts.map +1 -0
  88. package/dist/components/forms/RangeSlider.svelte +137 -0
  89. package/dist/components/forms/RangeSlider.svelte.d.ts +21 -0
  90. package/dist/components/forms/RangeSlider.svelte.d.ts.map +1 -0
  91. package/dist/components/forms/SegmentedControl.svelte +87 -0
  92. package/dist/components/forms/SegmentedControl.svelte.d.ts +17 -0
  93. package/dist/components/forms/SegmentedControl.svelte.d.ts.map +1 -0
  94. package/dist/components/forms/Select.svelte +84 -3
  95. package/dist/components/forms/Select.svelte.d.ts +6 -1
  96. package/dist/components/forms/Select.svelte.d.ts.map +1 -1
  97. package/dist/components/forms/Slider.svelte +131 -0
  98. package/dist/components/forms/Slider.svelte.d.ts +18 -0
  99. package/dist/components/forms/Slider.svelte.d.ts.map +1 -0
  100. package/dist/components/forms/Switch.svelte +128 -0
  101. package/dist/components/forms/Switch.svelte.d.ts +14 -0
  102. package/dist/components/forms/Switch.svelte.d.ts.map +1 -0
  103. package/dist/components/forms/TagsInput.svelte +106 -0
  104. package/dist/components/forms/TagsInput.svelte.d.ts +17 -0
  105. package/dist/components/forms/TagsInput.svelte.d.ts.map +1 -0
  106. package/dist/components/forms/Textarea.svelte +84 -3
  107. package/dist/components/forms/Textarea.svelte.d.ts +6 -1
  108. package/dist/components/forms/Textarea.svelte.d.ts.map +1 -1
  109. package/dist/components/forms/TimePicker.svelte +25 -0
  110. package/dist/components/forms/TimePicker.svelte.d.ts +12 -0
  111. package/dist/components/forms/TimePicker.svelte.d.ts.map +1 -0
  112. package/dist/components/forms/ToggleButton.svelte +79 -0
  113. package/dist/components/forms/ToggleButton.svelte.d.ts +13 -0
  114. package/dist/components/forms/ToggleButton.svelte.d.ts.map +1 -0
  115. package/dist/components/forms/__tests__/composite-controls.fixture.svelte +29 -0
  116. package/dist/components/forms/__tests__/composite-controls.fixture.svelte.d.ts +8 -0
  117. package/dist/components/forms/__tests__/composite-controls.fixture.svelte.d.ts.map +1 -0
  118. package/dist/components/forms/__tests__/composite-controls.test.js +33 -0
  119. package/dist/components/forms/__tests__/control-interaction.test.js +95 -0
  120. package/dist/components/forms/__tests__/core-controls.fixture.svelte +39 -0
  121. package/dist/components/forms/__tests__/core-controls.fixture.svelte.d.ts +8 -0
  122. package/dist/components/forms/__tests__/core-controls.fixture.svelte.d.ts.map +1 -0
  123. package/dist/components/forms/__tests__/core-controls.test.js +90 -0
  124. package/dist/components/forms/control-dom.d.ts +6 -0
  125. package/dist/components/forms/control-dom.d.ts.map +1 -0
  126. package/dist/components/forms/control-dom.js +38 -0
  127. package/dist/components/forms/control-interaction-context.d.ts +9 -0
  128. package/dist/components/forms/control-interaction-context.d.ts.map +1 -0
  129. package/dist/components/forms/control-interaction-context.js +15 -0
  130. package/dist/components/forms/control-interaction.d.ts +147 -0
  131. package/dist/components/forms/control-interaction.d.ts.map +1 -0
  132. package/dist/components/forms/control-interaction.js +265 -0
  133. package/dist/components/forms/form-group-context.d.ts +7 -0
  134. package/dist/components/forms/form-group-context.d.ts.map +1 -1
  135. package/dist/components/forms/index.d.ts +22 -1
  136. package/dist/components/forms/index.d.ts.map +1 -1
  137. package/dist/components/forms/index.js +21 -1
  138. package/dist/components/forms/radio-group-context.d.ts +12 -0
  139. package/dist/components/forms/radio-group-context.d.ts.map +1 -0
  140. package/dist/components/forms/radio-group-context.js +11 -0
  141. package/dist/components/forms/types.d.ts +14 -0
  142. package/dist/components/forms/types.d.ts.map +1 -0
  143. package/dist/components/forms/types.js +1 -0
  144. package/dist/components/forms/use-control-registration.svelte.d.ts +8 -0
  145. package/dist/components/forms/use-control-registration.svelte.d.ts.map +1 -0
  146. package/dist/components/forms/use-control-registration.svelte.js +15 -0
  147. package/dist/components/ui/Accordion.svelte +44 -0
  148. package/dist/components/ui/Accordion.svelte.d.ts +12 -0
  149. package/dist/components/ui/Accordion.svelte.d.ts.map +1 -0
  150. package/dist/components/ui/AccordionItem.svelte +42 -0
  151. package/dist/components/ui/AccordionItem.svelte.d.ts +11 -0
  152. package/dist/components/ui/AccordionItem.svelte.d.ts.map +1 -0
  153. package/dist/components/ui/Disclosure.svelte +50 -0
  154. package/dist/components/ui/Disclosure.svelte.d.ts +13 -0
  155. package/dist/components/ui/Disclosure.svelte.d.ts.map +1 -0
  156. package/dist/components/ui/Dropdown.svelte +5 -7
  157. package/dist/components/ui/Dropdown.svelte.d.ts +9 -0
  158. package/dist/components/ui/Dropdown.svelte.d.ts.map +1 -1
  159. package/dist/components/ui/Popover.svelte +102 -0
  160. package/dist/components/ui/Popover.svelte.d.ts +16 -0
  161. package/dist/components/ui/Popover.svelte.d.ts.map +1 -0
  162. package/dist/components/ui/__tests__/interaction-primitives.fixture.svelte +13 -0
  163. package/dist/components/ui/__tests__/interaction-primitives.fixture.svelte.d.ts +19 -0
  164. package/dist/components/ui/__tests__/interaction-primitives.fixture.svelte.d.ts.map +1 -0
  165. package/dist/components/ui/__tests__/interaction-primitives.test.js +31 -0
  166. package/dist/components/ui/accordion-context.d.ts +7 -0
  167. package/dist/components/ui/accordion-context.d.ts.map +1 -0
  168. package/dist/components/ui/accordion-context.js +11 -0
  169. package/dist/components/ui/index.d.ts +5 -1
  170. package/dist/components/ui/index.d.ts.map +1 -1
  171. package/dist/components/ui/index.js +5 -1
  172. package/dist/index.d.ts +1 -1
  173. package/dist/index.d.ts.map +1 -1
  174. package/dist/playground.d.ts +2 -0
  175. package/dist/playground.d.ts.map +1 -0
  176. package/dist/playground.js +1 -0
  177. package/dist/svelte/__tests__/playground.test.js +18 -0
  178. package/dist/svelte/playground/BaseControlsPreview.svelte +233 -0
  179. package/dist/svelte/playground/BaseControlsPreview.svelte.d.ts +4 -0
  180. package/dist/svelte/playground/BaseControlsPreview.svelte.d.ts.map +1 -0
  181. package/dist/svelte/playground/CollectionsPreview.svelte +59 -0
  182. package/dist/svelte/playground/CollectionsPreview.svelte.d.ts +4 -0
  183. package/dist/svelte/playground/CollectionsPreview.svelte.d.ts.map +1 -0
  184. package/dist/svelte/playground/DataTablePreview.svelte +247 -0
  185. package/dist/svelte/playground/DataTablePreview.svelte.d.ts +4 -0
  186. package/dist/svelte/playground/DataTablePreview.svelte.d.ts.map +1 -0
  187. package/dist/svelte/playground/FeedbackPreview.svelte +51 -0
  188. package/dist/svelte/playground/FeedbackPreview.svelte.d.ts +4 -0
  189. package/dist/svelte/playground/FeedbackPreview.svelte.d.ts.map +1 -0
  190. package/dist/svelte/playground/InteractiveControlsPreview.svelte +109 -0
  191. package/dist/svelte/playground/InteractiveControlsPreview.svelte.d.ts +4 -0
  192. package/dist/svelte/playground/InteractiveControlsPreview.svelte.d.ts.map +1 -0
  193. package/dist/svelte/playground.d.ts +20 -0
  194. package/dist/svelte/playground.d.ts.map +1 -0
  195. package/dist/svelte/playground.js +65 -0
  196. package/dist/theme/index.d.ts +6 -4
  197. package/dist/theme/index.d.ts.map +1 -1
  198. package/dist/theme/index.js +6 -7
  199. package/dist/themes/context.svelte.js +1 -1
  200. package/dist/themes/index.d.ts +1 -1
  201. package/dist/themes/index.js +1 -1
  202. package/dist/themes/smrt/index.js +1 -1
  203. package/dist/types-generic.d.ts +7 -1
  204. package/dist/types-generic.d.ts.map +1 -1
  205. package/package.json +23 -12
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Disclosure.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/ui/Disclosure.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAGtC,MAAM,WAAW,KAAK;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAoCD,QAAA,MAAM,UAAU,+CAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
@@ -1,7 +1,3 @@
1
- <script module lang="ts">
2
- let menuIdCounter = 0;
3
- </script>
4
-
5
1
  <script lang="ts">
6
2
  /**
7
3
  * Dropdown / Menu — a trigger button and a positioned menu list.
@@ -12,8 +8,9 @@ let menuIdCounter = 0;
12
8
  * Space to activate, Escape to close + refocus the trigger, and click-outside to
13
9
  * dismiss. CSS-anchored via `placement` — no JS positioning dependency.
14
10
  */
15
- import { tick } from 'svelte';
11
+
16
12
  import type { Snippet } from 'svelte';
13
+ import { tick } from 'svelte';
17
14
  import type { DropdownPlacement, MenuItem } from '../../types-generic';
18
15
 
19
16
  export interface Props {
@@ -40,7 +37,8 @@ const {
40
37
  disabled = false,
41
38
  }: Props = $props();
42
39
 
43
- const menuId = `smrt-menu-${(menuIdCounter += 1)}`;
40
+ const instanceId = $props.id();
41
+ const menuId = `smrt-menu-${instanceId}`;
44
42
  let open = $state(false);
45
43
  let wrapEl = $state<HTMLElement | null>(null);
46
44
  let triggerEl = $state<HTMLButtonElement | null>(null);
@@ -84,7 +82,7 @@ function onTriggerKeydown(event: KeyboardEvent) {
84
82
  function focusByOffset(offset: number) {
85
83
  const order = enabledIndexes;
86
84
  if (order.length === 0) return;
87
- const current = itemEls.findIndex((el) => el === document.activeElement);
85
+ const current = itemEls.indexOf(document.activeElement as HTMLButtonElement);
88
86
  const pos = order.indexOf(current);
89
87
  const next = order[(pos + offset + order.length) % order.length];
90
88
  itemEls[next]?.focus();
@@ -1,3 +1,12 @@
1
+ /**
2
+ * Dropdown / Menu — a trigger button and a positioned menu list.
3
+ *
4
+ * Implements the WAI-ARIA menu-button pattern: trigger has
5
+ * `aria-haspopup="menu"` + `aria-expanded`; the list is `role="menu"` with
6
+ * `role="menuitem"` buttons under roving focus (ArrowUp/Down/Home/End), Enter/
7
+ * Space to activate, Escape to close + refocus the trigger, and click-outside to
8
+ * dismiss. CSS-anchored via `placement` — no JS positioning dependency.
9
+ */
1
10
  import type { Snippet } from 'svelte';
2
11
  import type { DropdownPlacement, MenuItem } from '../../types-generic';
3
12
  export interface Props {
@@ -1 +1 @@
1
- {"version":3,"file":"Dropdown.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/ui/Dropdown.svelte.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAGvE,MAAM,WAAW,KAAK;IACpB,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8BAA8B;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,kBAAkB;IAClB,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,8CAA8C;IAC9C,SAAS,CAAC,EAAE,iBAAiB,CAAC;IAC9B,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,2BAA2B;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAgID,QAAA,MAAM,QAAQ,2CAAwC,CAAC;AACvD,KAAK,QAAQ,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC;AAC5C,eAAe,QAAQ,CAAC"}
1
+ {"version":3,"file":"Dropdown.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/ui/Dropdown.svelte.ts"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEtC,OAAO,KAAK,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAGvE,MAAM,WAAW,KAAK;IACpB,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8BAA8B;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,kBAAkB;IAClB,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,8CAA8C;IAC9C,SAAS,CAAC,EAAE,iBAAiB,CAAC;IAC9B,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,2BAA2B;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAgID,QAAA,MAAM,QAAQ,2CAAwC,CAAC;AACvD,KAAK,QAAQ,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC;AAC5C,eAAe,QAAQ,CAAC"}
@@ -0,0 +1,102 @@
1
+ <script lang="ts">
2
+ import { type Snippet, tick } from 'svelte';
3
+
4
+ export interface Props {
5
+ label: string;
6
+ trigger?: Snippet;
7
+ children?: Snippet;
8
+ open?: boolean;
9
+ disabled?: boolean;
10
+ placement?: 'bottom-start' | 'bottom-end' | 'top-start' | 'top-end';
11
+ closeOnOutsideClick?: boolean;
12
+ onopenchange?: (open: boolean) => void;
13
+ class?: string;
14
+ }
15
+
16
+ let {
17
+ label,
18
+ trigger,
19
+ children,
20
+ open = $bindable(false),
21
+ disabled = false,
22
+ placement = 'bottom-start',
23
+ closeOnOutsideClick = true,
24
+ onopenchange,
25
+ class: className = '',
26
+ }: Props = $props();
27
+
28
+ const instanceId = $props.id();
29
+ const panelId = `popover-${instanceId}`;
30
+ let rootEl = $state<HTMLSpanElement | null>(null);
31
+ let triggerEl = $state<HTMLButtonElement | null>(null);
32
+ let panelEl = $state<HTMLDivElement | null>(null);
33
+
34
+ async function setOpen(next: boolean, focusPanel = false) {
35
+ if (disabled) return;
36
+ open = next;
37
+ onopenchange?.(next);
38
+ if (next && focusPanel) {
39
+ await tick();
40
+ panelEl?.focus();
41
+ }
42
+ }
43
+
44
+ function handleKeydown(event: KeyboardEvent) {
45
+ if (event.key === 'Escape' && open) {
46
+ event.preventDefault();
47
+ setOpen(false);
48
+ triggerEl?.focus();
49
+ }
50
+ }
51
+
52
+ $effect(() => {
53
+ if (!open || !closeOnOutsideClick) return;
54
+ const handlePointerDown = (event: PointerEvent) => {
55
+ if (rootEl && !rootEl.contains(event.target as Node)) setOpen(false);
56
+ };
57
+ document.addEventListener('pointerdown', handlePointerDown, true);
58
+ return () =>
59
+ document.removeEventListener('pointerdown', handlePointerDown, true);
60
+ });
61
+ </script>
62
+
63
+ <span bind:this={rootEl} class="popover {className}">
64
+ <button
65
+ bind:this={triggerEl}
66
+ type="button"
67
+ class="popover__trigger"
68
+ aria-haspopup="dialog"
69
+ aria-expanded={open}
70
+ aria-controls={open ? panelId : undefined}
71
+ {disabled}
72
+ onclick={() => setOpen(!open, !open)}
73
+ onkeydown={handleKeydown}
74
+ >
75
+ {#if trigger}{@render trigger()}{:else}{label}{/if}
76
+ </button>
77
+ {#if open}
78
+ <div
79
+ bind:this={panelEl}
80
+ id={panelId}
81
+ class="popover__panel popover__panel--{placement}"
82
+ role="dialog"
83
+ aria-label={label}
84
+ tabindex="-1"
85
+ onkeydown={handleKeydown}
86
+ >
87
+ {#if children}{@render children()}{/if}
88
+ </div>
89
+ {/if}
90
+ </span>
91
+
92
+ <style>
93
+ .popover { position: relative; display: inline-flex; }
94
+ .popover__trigger { appearance: none; padding: var(--smrt-spacing-2) var(--smrt-spacing-3); border: 1px solid var(--smrt-color-outline-variant); border-radius: var(--smrt-radius-medium); background: var(--smrt-color-surface); color: var(--smrt-color-on-surface); font: inherit; cursor: pointer; }
95
+ .popover__trigger:focus-visible, .popover__panel:focus-visible { outline: 2px solid var(--smrt-color-primary); outline-offset: 2px; }
96
+ .popover__trigger:disabled { opacity: .5; cursor: not-allowed; }
97
+ .popover__panel { position: absolute; z-index: var(--smrt-z-index-popover, 1000); min-width: 16rem; padding: var(--smrt-spacing-4); border: 1px solid var(--smrt-color-outline-variant); border-radius: var(--smrt-radius-large); background: var(--smrt-color-surface-container); color: var(--smrt-color-on-surface); box-shadow: var(--smrt-elevation-3); }
98
+ .popover__panel--bottom-start { top: calc(100% + var(--smrt-spacing-1)); left: 0; }
99
+ .popover__panel--bottom-end { top: calc(100% + var(--smrt-spacing-1)); right: 0; }
100
+ .popover__panel--top-start { bottom: calc(100% + var(--smrt-spacing-1)); left: 0; }
101
+ .popover__panel--top-end { right: 0; bottom: calc(100% + var(--smrt-spacing-1)); }
102
+ </style>
@@ -0,0 +1,16 @@
1
+ import { type Snippet } from 'svelte';
2
+ export interface Props {
3
+ label: string;
4
+ trigger?: Snippet;
5
+ children?: Snippet;
6
+ open?: boolean;
7
+ disabled?: boolean;
8
+ placement?: 'bottom-start' | 'bottom-end' | 'top-start' | 'top-end';
9
+ closeOnOutsideClick?: boolean;
10
+ onopenchange?: (open: boolean) => void;
11
+ class?: string;
12
+ }
13
+ declare const Popover: import("svelte").Component<Props, {}, "open">;
14
+ type Popover = ReturnType<typeof Popover>;
15
+ export default Popover;
16
+ //# sourceMappingURL=Popover.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Popover.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/ui/Popover.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,OAAO,EAAQ,MAAM,QAAQ,CAAC;AAG5C,MAAM,WAAW,KAAK;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,cAAc,GAAG,YAAY,GAAG,WAAW,GAAG,SAAS,CAAC;IACpE,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAmED,QAAA,MAAM,OAAO,+CAAwC,CAAC;AACtD,KAAK,OAAO,GAAG,UAAU,CAAC,OAAO,OAAO,CAAC,CAAC;AAC1C,eAAe,OAAO,CAAC"}
@@ -0,0 +1,13 @@
1
+ <script lang="ts">
2
+ import Accordion from '../Accordion.svelte';
3
+ import AccordionItem from '../AccordionItem.svelte';
4
+ import Disclosure from '../Disclosure.svelte';
5
+ import Popover from '../Popover.svelte';
6
+ </script>
7
+
8
+ <Popover label="Filters"><p>Filter controls</p></Popover>
9
+ <Disclosure title="Details"><p>Disclosure details</p></Disclosure>
10
+ <Accordion>
11
+ <AccordionItem value="one" title="First section"><p>First content</p></AccordionItem>
12
+ <AccordionItem value="two" title="Second section"><p>Second content</p></AccordionItem>
13
+ </Accordion>
@@ -0,0 +1,19 @@
1
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
2
+ new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
3
+ $$bindings?: Bindings;
4
+ } & Exports;
5
+ (internal: unknown, props: {
6
+ $$events?: Events;
7
+ $$slots?: Slots;
8
+ }): Exports & {
9
+ $set?: any;
10
+ $on?: any;
11
+ };
12
+ z_$$bindings?: Bindings;
13
+ }
14
+ declare const InteractionPrimitives: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
15
+ [evt: string]: CustomEvent<any>;
16
+ }, {}, {}, string>;
17
+ type InteractionPrimitives = InstanceType<typeof InteractionPrimitives>;
18
+ export default InteractionPrimitives;
19
+ //# sourceMappingURL=interaction-primitives.fixture.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interaction-primitives.fixture.svelte.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/__tests__/interaction-primitives.fixture.svelte.ts"],"names":[],"mappings":"AAwBA,UAAU,kCAAkC,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,OAAO,GAAG,EAAE,EAAE,QAAQ,GAAG,MAAM;IACpM,KAAK,OAAO,EAAE,OAAO,QAAQ,EAAE,2BAA2B,CAAC,KAAK,CAAC,GAAG,OAAO,QAAQ,EAAE,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG;QAAE,UAAU,CAAC,EAAE,QAAQ,CAAA;KAAE,GAAG,OAAO,CAAC;IACjK,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,KAAK,CAAA;KAAC,GAAG,OAAO,GAAG;QAAE,IAAI,CAAC,EAAE,GAAG,CAAC;QAAC,GAAG,CAAC,EAAE,GAAG,CAAA;KAAE,CAAC;IACtG,YAAY,CAAC,EAAE,QAAQ,CAAC;CAC3B;AAKD,QAAA,MAAM,qBAAqB;;kBAA+E,CAAC;AACzF,KAAK,qBAAqB,GAAG,YAAY,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAC1E,eAAe,qBAAqB,CAAC"}
@@ -0,0 +1,31 @@
1
+ import { render, screen } from '@testing-library/svelte';
2
+ import userEvent from '@testing-library/user-event';
3
+ import { describe, expect, it } from 'vitest';
4
+ import { expectNoA11yViolations } from '../../../test-support/a11y';
5
+ import Fixture from './interaction-primitives.fixture.svelte';
6
+ describe('interaction primitives', () => {
7
+ it('opens and dismisses a popover', async () => {
8
+ render(Fixture);
9
+ const trigger = screen.getByRole('button', { name: 'Filters' });
10
+ await userEvent.click(trigger);
11
+ expect(screen.getByRole('dialog', { name: 'Filters' })).toBeInTheDocument();
12
+ await userEvent.keyboard('{Escape}');
13
+ expect(screen.queryByRole('dialog', { name: 'Filters' })).not.toBeInTheDocument();
14
+ expect(trigger).toHaveFocus();
15
+ });
16
+ it('supports disclosure and single-value accordion semantics', async () => {
17
+ render(Fixture);
18
+ await userEvent.click(screen.getByText('Details'));
19
+ expect(screen.getByText('Disclosure details')).toBeVisible();
20
+ await userEvent.click(screen.getByRole('button', { name: 'First section' }));
21
+ expect(screen.getByRole('region', { name: 'First section' })).toHaveTextContent('First content');
22
+ await userEvent.click(screen.getByRole('button', { name: 'Second section' }));
23
+ expect(screen.queryByText('First content')).not.toBeInTheDocument();
24
+ });
25
+ it('is axe-clean with interactive content open', async () => {
26
+ const { container } = render(Fixture);
27
+ await userEvent.click(screen.getByRole('button', { name: 'Filters' }));
28
+ await userEvent.click(screen.getByRole('button', { name: 'First section' }));
29
+ await expectNoA11yViolations(container);
30
+ });
31
+ });
@@ -0,0 +1,7 @@
1
+ export interface AccordionContext {
2
+ isOpen(value: string): boolean;
3
+ toggle(value: string): void;
4
+ }
5
+ export declare function setAccordionContext(context: AccordionContext): void;
6
+ export declare function getAccordionContext(): AccordionContext;
7
+ //# sourceMappingURL=accordion-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"accordion-context.d.ts","sourceRoot":"","sources":["../../../src/components/ui/accordion-context.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IAC/B,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAEnE;AAED,wBAAgB,mBAAmB,IAAI,gBAAgB,CAKtD"}
@@ -0,0 +1,11 @@
1
+ import { getContext, setContext } from 'svelte';
2
+ const ACCORDION_CONTEXT = Symbol('smrt-accordion');
3
+ export function setAccordionContext(context) {
4
+ setContext(ACCORDION_CONTEXT, context);
5
+ }
6
+ export function getAccordionContext() {
7
+ const context = getContext(ACCORDION_CONTEXT);
8
+ if (!context)
9
+ throw new Error('AccordionItem must be nested inside Accordion');
10
+ return context;
11
+ }
@@ -1,13 +1,17 @@
1
1
  /**
2
2
  * UI components - Buttons, cards, badges, and other UI elements
3
3
  */
4
+ export { default as Accordion } from './Accordion.svelte';
5
+ export { default as AccordionItem } from './AccordionItem.svelte';
4
6
  export { default as Avatar } from './Avatar.svelte';
5
7
  export { default as Badge } from './Badge.svelte';
6
8
  export { default as Button } from './Button.svelte';
7
9
  export { default as Card } from './Card.svelte';
8
10
  export { default as Chip } from './Chip.svelte';
9
- export { default as Dropdown } from './Dropdown.svelte';
11
+ export { default as Disclosure } from './Disclosure.svelte';
12
+ export { default as Dropdown, default as Menu } from './Dropdown.svelte';
10
13
  export { default as Pagination } from './Pagination.svelte';
14
+ export { default as Popover } from './Popover.svelte';
11
15
  export { default as Skeleton } from './Skeleton.svelte';
12
16
  export { default as Tooltip } from './Tooltip.svelte';
13
17
  export { default as Tree } from './Tree.svelte';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/ui/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/ui/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAElE,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,eAAe,CAAC"}
@@ -1,14 +1,18 @@
1
1
  /**
2
2
  * UI components - Buttons, cards, badges, and other UI elements
3
3
  */
4
+ export { default as Accordion } from './Accordion.svelte';
5
+ export { default as AccordionItem } from './AccordionItem.svelte';
4
6
  // Export components
5
7
  export { default as Avatar } from './Avatar.svelte';
6
8
  export { default as Badge } from './Badge.svelte';
7
9
  export { default as Button } from './Button.svelte';
8
10
  export { default as Card } from './Card.svelte';
9
11
  export { default as Chip } from './Chip.svelte';
10
- export { default as Dropdown } from './Dropdown.svelte';
12
+ export { default as Disclosure } from './Disclosure.svelte';
13
+ export { default as Dropdown, default as Menu } from './Dropdown.svelte';
11
14
  export { default as Pagination } from './Pagination.svelte';
15
+ export { default as Popover } from './Popover.svelte';
12
16
  export { default as Skeleton } from './Skeleton.svelte';
13
17
  export { default as Tooltip } from './Tooltip.svelte';
14
18
  export { default as Tree } from './Tree.svelte';
package/dist/index.d.ts CHANGED
@@ -20,9 +20,9 @@ export * from './components/nav/index.js';
20
20
  export { default as PermissionCheck } from './components/permissions/PermissionCheck.svelte';
21
21
  export { default as RoleBadge } from './components/roles/RoleBadge.svelte';
22
22
  export { default as RoleSelector } from './components/roles/RoleSelector.svelte';
23
- export type { ThemeMode } from './components/theme/index.js';
24
23
  export * from './components/ui/index.js';
25
24
  export * from './registry/index.js';
26
25
  export * from './theme/index.js';
26
+ export type { ColorScheme as ThemeMode } from './themes/types.js';
27
27
  export type * from './types-generic.js';
28
28
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EACb,UAAU,GACX,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAE7C,cAAc,gCAAgC,CAAC;AAE/C,cAAc,4BAA4B,CAAC;AAE3C,cAAc,+BAA+B,CAAC;AAE9C,cAAc,gCAAgC,CAAC;AAE/C,cAAc,8BAA8B,CAAC;AAE7C,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,gDAAgD,CAAC;AAC3F,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,gDAAgD,CAAC;AAE3F,cAAc,2BAA2B,CAAC;AAE1C,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,iDAAiD,CAAC;AAE7F,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,qCAAqC,CAAC;AAC3E,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,wCAAwC,CAAC;AAEjF,YAAY,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAE7D,cAAc,0BAA0B,CAAC;AAEzC,cAAc,qBAAqB,CAAC;AAEpC,cAAc,kBAAkB,CAAC;AAEjC,mBAAmB,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EACb,UAAU,GACX,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAE7C,cAAc,gCAAgC,CAAC;AAE/C,cAAc,4BAA4B,CAAC;AAE3C,cAAc,+BAA+B,CAAC;AAE9C,cAAc,gCAAgC,CAAC;AAE/C,cAAc,8BAA8B,CAAC;AAE7C,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,gDAAgD,CAAC;AAC3F,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,gDAAgD,CAAC;AAE3F,cAAc,2BAA2B,CAAC;AAE1C,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,iDAAiD,CAAC;AAE7F,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,qCAAqC,CAAC;AAC3E,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,wCAAwC,CAAC;AAEjF,cAAc,0BAA0B,CAAC;AAEzC,cAAc,qBAAqB,CAAC;AAEpC,cAAc,kBAAkB,CAAC;AAEjC,YAAY,EAAE,WAAW,IAAI,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAElE,mBAAmB,oBAAoB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { default } from './svelte/playground.js';
2
+ //# sourceMappingURL=playground.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"playground.d.ts","sourceRoot":"","sources":["../src/playground.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC"}
@@ -0,0 +1 @@
1
+ export { default } from './svelte/playground.js';
@@ -0,0 +1,18 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import playground from '../playground.js';
3
+ describe('smrt-ui playground', () => {
4
+ it('publishes themed base-control and data-table previews', () => {
5
+ expect(playground.packageName).toBe('@happyvertical/smrt-ui');
6
+ expect(playground.entries.map((entry) => entry.id)).toEqual([
7
+ 'base-controls',
8
+ 'interactive-controls',
9
+ 'feedback-overlays',
10
+ 'collections',
11
+ 'data-table',
12
+ ]);
13
+ for (const entry of playground.entries) {
14
+ expect(entry.loadComponent).toEqual(expect.any(Function));
15
+ expect(entry.modes).toHaveProperty('mock');
16
+ }
17
+ });
18
+ });
@@ -0,0 +1,233 @@
1
+ <script lang="ts">
2
+ import Form from '../../components/forms/Form.svelte';
3
+ import FormGroup from '../../components/forms/FormGroup.svelte';
4
+ import Input from '../../components/forms/Input.svelte';
5
+ import Select from '../../components/forms/Select.svelte';
6
+ import Textarea from '../../components/forms/Textarea.svelte';
7
+ import Toggle from '../../components/forms/Toggle.svelte';
8
+ import Badge from '../../components/ui/Badge.svelte';
9
+ import Button from '../../components/ui/Button.svelte';
10
+
11
+ let name = $state('Ada Lovelace');
12
+ let email = $state('ada@example.com');
13
+ let seats = $state(12);
14
+ let startDate = $state('2026-07-09');
15
+ let role = $state('admin');
16
+ let notes = $state(
17
+ 'These controls stay lightweight because they do not require a Provider.',
18
+ );
19
+ let enabled = $state(true);
20
+ let saveCount = $state(0);
21
+
22
+ function handleSubmit() {
23
+ saveCount += 1;
24
+ }
25
+ </script>
26
+
27
+ <div class="workbench">
28
+ <div class="workbench__header">
29
+ <div>
30
+ <p class="eyebrow">Provider-free</p>
31
+ <h4>Form controls</h4>
32
+ <p class="supporting">
33
+ Native semantics, shared focus states, and the active playground theme.
34
+ </p>
35
+ </div>
36
+ <Badge variant="success">Ready</Badge>
37
+ </div>
38
+
39
+ <Form class="controls-form" onsubmit={handleSubmit}>
40
+ <div class="control-grid">
41
+ <FormGroup label="Name" hint="Standard text input" required>
42
+ <Input name="name" bind:value={name} required />
43
+ </FormGroup>
44
+
45
+ <FormGroup label="Email" hint="Native email validation">
46
+ <Input name="email" type="email" bind:value={email} />
47
+ </FormGroup>
48
+
49
+ <FormGroup label="Seats" hint="Numeric input">
50
+ <Input name="seats" type="number" min="1" bind:value={seats} />
51
+ </FormGroup>
52
+
53
+ <FormGroup label="Start date" hint="Native date picker">
54
+ <Input name="startDate" type="date" bind:value={startDate} />
55
+ </FormGroup>
56
+
57
+ <FormGroup label="Role" hint="Native select with themed chrome">
58
+ <Select name="role" bind:value={role}>
59
+ <option value="admin">Admin</option>
60
+ <option value="editor">Editor</option>
61
+ <option value="viewer">Viewer</option>
62
+ </Select>
63
+ </FormGroup>
64
+
65
+ <FormGroup
66
+ label="Workspace key"
67
+ error="That key is already in use"
68
+ >
69
+ <Input name="workspaceKey" value="western-lab" />
70
+ </FormGroup>
71
+
72
+ <div class="control-grid__wide">
73
+ <FormGroup label="Notes" hint="Resizable multiline input">
74
+ <Textarea name="notes" rows={3} bind:value={notes} />
75
+ </FormGroup>
76
+ </div>
77
+
78
+ <div class="control-grid__wide toggles">
79
+ <Toggle label="Workspace enabled" bind:checked={enabled} />
80
+ <Toggle label="Unavailable setting" disabled />
81
+ </div>
82
+ </div>
83
+
84
+ <div class="actions">
85
+ <div class="actions__buttons">
86
+ <Button type="submit">Save changes</Button>
87
+ <Button variant="secondary">Duplicate</Button>
88
+ <Button variant="ghost">Cancel</Button>
89
+ <Button variant="danger">Delete</Button>
90
+ <Button disabled>Disabled</Button>
91
+ </div>
92
+ <p class="save-status" aria-live="polite">
93
+ {saveCount === 0
94
+ ? 'Submit the form to test its event handling.'
95
+ : `Saved ${saveCount} ${saveCount === 1 ? 'time' : 'times'}.`}
96
+ </p>
97
+ </div>
98
+ </Form>
99
+
100
+ <div class="status-row" aria-label="Badge variants">
101
+ <span>Status</span>
102
+ <Badge>Default</Badge>
103
+ <Badge variant="primary">Primary</Badge>
104
+ <Badge variant="success">Success</Badge>
105
+ <Badge variant="warning">Warning</Badge>
106
+ <Badge variant="error">Error</Badge>
107
+ </div>
108
+ </div>
109
+
110
+ <style>
111
+ .workbench {
112
+ display: grid;
113
+ gap: var(--smrt-spacing-6);
114
+ color: var(--smrt-color-on-surface);
115
+ }
116
+
117
+ .workbench__header,
118
+ .actions,
119
+ .actions__buttons,
120
+ .status-row,
121
+ .toggles {
122
+ display: flex;
123
+ align-items: center;
124
+ }
125
+
126
+ .workbench__header,
127
+ .actions {
128
+ justify-content: space-between;
129
+ gap: var(--smrt-spacing-4);
130
+ }
131
+
132
+ .workbench__header {
133
+ padding-bottom: var(--smrt-spacing-4);
134
+ border-bottom: 1px solid var(--smrt-color-outline-variant);
135
+ }
136
+
137
+ h4,
138
+ p {
139
+ margin: 0;
140
+ }
141
+
142
+ h4 {
143
+ font: var(--smrt-typography-headline-small-font);
144
+ }
145
+
146
+ .eyebrow {
147
+ margin-bottom: var(--smrt-spacing-1);
148
+ color: var(--smrt-color-primary);
149
+ font: var(--smrt-typography-label-small-font);
150
+ letter-spacing: 0.1em;
151
+ text-transform: uppercase;
152
+ }
153
+
154
+ .supporting,
155
+ .save-status,
156
+ .status-row > span:first-child {
157
+ color: var(--smrt-color-on-surface-variant);
158
+ }
159
+
160
+ .supporting {
161
+ margin-top: var(--smrt-spacing-1);
162
+ font: var(--smrt-typography-body-medium-font);
163
+ }
164
+
165
+ :global(.controls-form) {
166
+ display: grid;
167
+ gap: var(--smrt-spacing-4);
168
+ }
169
+
170
+ .control-grid {
171
+ display: grid;
172
+ grid-template-columns: repeat(2, minmax(0, 1fr));
173
+ column-gap: var(--smrt-spacing-6);
174
+ }
175
+
176
+ .control-grid__wide {
177
+ grid-column: 1 / -1;
178
+ }
179
+
180
+ .toggles,
181
+ .actions__buttons,
182
+ .status-row {
183
+ flex-wrap: wrap;
184
+ gap: var(--smrt-spacing-3);
185
+ }
186
+
187
+ .toggles {
188
+ min-height: 3rem;
189
+ }
190
+
191
+ .actions {
192
+ align-items: flex-start;
193
+ padding-top: var(--smrt-spacing-5);
194
+ border-top: 1px solid var(--smrt-color-outline-variant);
195
+ }
196
+
197
+ .save-status {
198
+ max-width: 18rem;
199
+ font: var(--smrt-typography-body-small-font);
200
+ text-align: right;
201
+ }
202
+
203
+ .status-row {
204
+ padding: var(--smrt-spacing-4);
205
+ border-radius: var(--smrt-radius-medium);
206
+ background: var(--smrt-color-surface-container-low);
207
+ }
208
+
209
+ .status-row > span:first-child {
210
+ margin-right: var(--smrt-spacing-1);
211
+ font: var(--smrt-typography-label-medium-font);
212
+ }
213
+
214
+ @media (max-width: 760px) {
215
+ .control-grid {
216
+ grid-template-columns: 1fr;
217
+ }
218
+
219
+ .control-grid__wide {
220
+ grid-column: auto;
221
+ }
222
+
223
+ .workbench__header,
224
+ .actions {
225
+ align-items: flex-start;
226
+ flex-direction: column;
227
+ }
228
+
229
+ .save-status {
230
+ text-align: left;
231
+ }
232
+ }
233
+ </style>
@@ -0,0 +1,4 @@
1
+ declare const BaseControlsPreview: import("svelte").Component<Record<string, never>, {}, "">;
2
+ type BaseControlsPreview = ReturnType<typeof BaseControlsPreview>;
3
+ export default BaseControlsPreview;
4
+ //# sourceMappingURL=BaseControlsPreview.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BaseControlsPreview.svelte.d.ts","sourceRoot":"","sources":["../../../src/svelte/playground/BaseControlsPreview.svelte.ts"],"names":[],"mappings":"AA0HA,QAAA,MAAM,mBAAmB,2DAAwC,CAAC;AAClE,KAAK,mBAAmB,GAAG,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAClE,eAAe,mBAAmB,CAAC"}