@spectral_labs/ui 1.7.0 → 1.8.0-next.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 (150) hide show
  1. package/LICENSE +21 -0
  2. package/THIRD_PARTY_NOTICES.md +201 -0
  3. package/package.json +8 -2
  4. package/dist/components/__tests__/overlay-scrim-source.test.js +0 -134
  5. package/dist/components/accordion/__tests__/AccordionTest.svelte +0 -31
  6. package/dist/components/accordion/__tests__/accordion.test.svelte.js +0 -139
  7. package/dist/components/alert-dialog/__tests__/AlertDialogTest.svelte +0 -28
  8. package/dist/components/alert-dialog/__tests__/alert-dialog.a11y.test.js +0 -42
  9. package/dist/components/alert-dialog/__tests__/alert-dialog.integration.test.svelte.js +0 -51
  10. package/dist/components/alert-dialog/__tests__/alert-dialog.test.svelte.js +0 -113
  11. package/dist/components/app-bar/__tests__/app-bar.test.svelte.js +0 -30
  12. package/dist/components/aspect-ratio/__tests__/aspect-ratio.test.svelte.js +0 -22
  13. package/dist/components/avatar/__tests__/avatar.test.svelte.js +0 -26
  14. package/dist/components/badge/__tests__/badge.test.svelte.js +0 -30
  15. package/dist/components/bottom-sheet/__tests__/BottomSheetTest.svelte +0 -22
  16. package/dist/components/bottom-sheet/__tests__/bottom-sheet.test.svelte.js +0 -83
  17. package/dist/components/button/__tests__/button.test.svelte.js +0 -63
  18. package/dist/components/calendar/__tests__/CalendarTest.svelte +0 -56
  19. package/dist/components/calendar/__tests__/calendar.test.svelte.js +0 -190
  20. package/dist/components/card/__tests__/card.test.svelte.js +0 -30
  21. package/dist/components/checkbox/__tests__/checkbox.test.svelte.js +0 -44
  22. package/dist/components/chips/__tests__/chips.test.svelte.js +0 -26
  23. package/dist/components/collapsible/__tests__/CollapsibleTest.svelte +0 -18
  24. package/dist/components/collapsible/__tests__/collapsible.test.svelte.js +0 -125
  25. package/dist/components/combobox/__tests__/ComboboxTest.svelte +0 -40
  26. package/dist/components/combobox/__tests__/combobox.test.svelte.js +0 -255
  27. package/dist/components/command/__tests__/CommandInlineDirectTest.svelte +0 -29
  28. package/dist/components/command/__tests__/CommandInlineTest.svelte +0 -89
  29. package/dist/components/command/__tests__/CommandTest.svelte +0 -77
  30. package/dist/components/command/__tests__/command-inline.test.svelte.js +0 -392
  31. package/dist/components/command/__tests__/command-item-passthrough.test.svelte.js +0 -284
  32. package/dist/components/command/__tests__/command.a11y.test.js +0 -30
  33. package/dist/components/command/__tests__/command.integration.test.svelte.js +0 -68
  34. package/dist/components/command/__tests__/command.test.svelte.js +0 -230
  35. package/dist/components/context-menu/__tests__/ContextMenuNonInteractiveTest.svelte +0 -32
  36. package/dist/components/context-menu/__tests__/ContextMenuTest.svelte +0 -25
  37. package/dist/components/context-menu/__tests__/context-menu.test.svelte.js +0 -141
  38. package/dist/components/date-field/__tests__/DateFieldTest.svelte +0 -20
  39. package/dist/components/date-field/__tests__/date-field.test.svelte.js +0 -139
  40. package/dist/components/date-picker/__tests__/DatePickerTest.svelte +0 -20
  41. package/dist/components/date-picker/__tests__/date-picker.test.svelte.js +0 -190
  42. package/dist/components/date-range-field/__tests__/DateRangeFieldTest.svelte +0 -20
  43. package/dist/components/date-range-field/__tests__/date-range-field.test.svelte.js +0 -130
  44. package/dist/components/date-range-picker/__tests__/DateRangePickerTest.svelte +0 -18
  45. package/dist/components/date-range-picker/__tests__/date-range-picker.test.svelte.js +0 -156
  46. package/dist/components/dialog/__tests__/DialogTest.svelte +0 -34
  47. package/dist/components/dialog/__tests__/dialog.test.svelte.js +0 -184
  48. package/dist/components/drop-zone/__tests__/drop-zone.test.svelte.js +0 -26
  49. package/dist/components/dropdown-menu/__tests__/DropdownMenuRadioTest.svelte +0 -90
  50. package/dist/components/dropdown-menu/__tests__/DropdownMenuTest.svelte +0 -71
  51. package/dist/components/dropdown-menu/__tests__/dropdown-menu-radio-group.test.svelte.js +0 -306
  52. package/dist/components/dropdown-menu/__tests__/dropdown-menu.test.svelte.js +0 -567
  53. package/dist/components/empty-state/__tests__/empty-state.test.svelte.js +0 -26
  54. package/dist/components/fab/__tests__/fab.test.svelte.js +0 -30
  55. package/dist/components/field/__tests__/FieldTest.svelte +0 -26
  56. package/dist/components/field/__tests__/field.test.svelte.js +0 -74
  57. package/dist/components/grid-list/__tests__/GridListTest.svelte +0 -46
  58. package/dist/components/grid-list/__tests__/grid-list.test.svelte.js +0 -231
  59. package/dist/components/hover-card/__tests__/HoverCardTest.svelte +0 -30
  60. package/dist/components/hover-card/__tests__/hover-card.test.svelte.js +0 -236
  61. package/dist/components/indicator/__tests__/indicator.test.svelte.js +0 -30
  62. package/dist/components/input/__tests__/input.test.svelte.js +0 -67
  63. package/dist/components/label/__tests__/label.test.svelte.js +0 -22
  64. package/dist/components/language-select/__tests__/language-select.test.svelte.js +0 -199
  65. package/dist/components/language-select/__tests__/languages.test.js +0 -87
  66. package/dist/components/link-preview/__tests__/LinkPreviewTest.svelte +0 -37
  67. package/dist/components/link-preview/__tests__/link-preview.a11y.test.js +0 -28
  68. package/dist/components/link-preview/__tests__/link-preview.integration.test.svelte.js +0 -54
  69. package/dist/components/link-preview/__tests__/link-preview.test.svelte.js +0 -215
  70. package/dist/components/list/__tests__/list.test.svelte.js +0 -22
  71. package/dist/components/menubar/__tests__/MenubarTest.svelte +0 -52
  72. package/dist/components/menubar/__tests__/menubar.a11y.test.js +0 -28
  73. package/dist/components/menubar/__tests__/menubar.integration.test.svelte.js +0 -57
  74. package/dist/components/menubar/__tests__/menubar.test.svelte.js +0 -328
  75. package/dist/components/meter/__tests__/meter.test.svelte.js +0 -26
  76. package/dist/components/nav-bar/__tests__/nav-bar.test.svelte.js +0 -23
  77. package/dist/components/nav-drawer/__tests__/nav-drawer.test.svelte.js +0 -28
  78. package/dist/components/nav-rail/__tests__/nav-rail.test.svelte.js +0 -28
  79. package/dist/components/pagination/__tests__/pagination.test.svelte.js +0 -26
  80. package/dist/components/pin-input/__tests__/pin-input.test.svelte.js +0 -71
  81. package/dist/components/popover/__tests__/PopoverTest.svelte +0 -27
  82. package/dist/components/popover/__tests__/popover.test.svelte.js +0 -196
  83. package/dist/components/progress/__tests__/progress.test.svelte.js +0 -32
  84. package/dist/components/radio-group/__tests__/radio-group.test.svelte.js +0 -22
  85. package/dist/components/range-calendar/__tests__/RangeCalendarTest.svelte +0 -23
  86. package/dist/components/range-calendar/__tests__/range-calendar.test.svelte.js +0 -105
  87. package/dist/components/rating-group/__tests__/rating-group.test.svelte.js +0 -26
  88. package/dist/components/scroll-area/__tests__/scroll-area.test.svelte.js +0 -34
  89. package/dist/components/search-field/__tests__/SearchFieldTest.svelte +0 -34
  90. package/dist/components/search-field/__tests__/search-field.test.svelte.js +0 -118
  91. package/dist/components/select/__tests__/SelectLabelPersistenceTest.svelte +0 -31
  92. package/dist/components/select/__tests__/SelectTest.svelte +0 -33
  93. package/dist/components/select/__tests__/select.test.svelte.js +0 -221
  94. package/dist/components/separator/__tests__/separator.test.svelte.js +0 -39
  95. package/dist/components/sheet/__tests__/SheetTest.svelte +0 -34
  96. package/dist/components/sheet/__tests__/sheet.test.svelte.js +0 -193
  97. package/dist/components/side-sheet/__tests__/side-sheet.test.svelte.js +0 -138
  98. package/dist/components/sidebar/__tests__/SidebarFullTest.svelte +0 -45
  99. package/dist/components/sidebar/__tests__/SidebarTest.svelte +0 -9
  100. package/dist/components/sidebar/__tests__/sidebar.test.svelte.js +0 -186
  101. package/dist/components/simple-dialog/__tests__/SimpleDialogTest.svelte +0 -40
  102. package/dist/components/simple-dialog/__tests__/simple-dialog.test.svelte.js +0 -50
  103. package/dist/components/simple-tooltip/__tests__/SimpleTooltipTest.svelte +0 -19
  104. package/dist/components/simple-tooltip/__tests__/simple-tooltip.test.svelte.js +0 -61
  105. package/dist/components/slider/__tests__/slider.test.svelte.js +0 -42
  106. package/dist/components/sortable-list/__tests__/NestedSortableListTest.svelte +0 -49
  107. package/dist/components/sortable-list/__tests__/SortableListTest.svelte +0 -42
  108. package/dist/components/sortable-list/__tests__/sortable-list.nested.test.svelte.js +0 -112
  109. package/dist/components/sortable-list/__tests__/sortable-list.test.svelte.js +0 -175
  110. package/dist/components/splitter/__tests__/splitter.test.svelte.js +0 -26
  111. package/dist/components/switch/__tests__/switch.test.svelte.js +0 -44
  112. package/dist/components/table/__tests__/table.test.svelte.js +0 -22
  113. package/dist/components/tabs/__tests__/TabsTest.svelte +0 -32
  114. package/dist/components/tabs/__tests__/tabs.test.svelte.js +0 -227
  115. package/dist/components/textarea/__tests__/textarea.test.svelte.js +0 -55
  116. package/dist/components/time-field/__tests__/TimeFieldTest.svelte +0 -20
  117. package/dist/components/time-field/__tests__/time-field.test.svelte.js +0 -100
  118. package/dist/components/time-range-field/__tests__/TimeRangeFieldTest.svelte +0 -20
  119. package/dist/components/time-range-field/__tests__/time-range-field.test.svelte.js +0 -124
  120. package/dist/components/toast/__tests__/toast.test.svelte.js +0 -46
  121. package/dist/components/toggle/__tests__/toggle.test.svelte.js +0 -38
  122. package/dist/components/toggle-group/__tests__/toggle-group.test.svelte.js +0 -22
  123. package/dist/components/toolbar/__tests__/ToolbarCompositionTest.svelte +0 -18
  124. package/dist/components/toolbar/__tests__/ToolbarTabstopTest.svelte +0 -10
  125. package/dist/components/toolbar/__tests__/toolbar.test.svelte.js +0 -63
  126. package/dist/components/tooltip/__tests__/TooltipTest.svelte +0 -22
  127. package/dist/components/tooltip/__tests__/tooltip.test.svelte.js +0 -225
  128. package/dist/components/tree/__tests__/TreeLabelContentTest.svelte +0 -21
  129. package/dist/components/tree/__tests__/TreeTest.svelte +0 -24
  130. package/dist/components/tree/__tests__/tree.test.svelte.js +0 -229
  131. package/dist/components/virtualizer/__tests__/waterfall-layout.test.js +0 -82
  132. package/dist/internal/announcer/__tests__/announcer.test.js +0 -42
  133. package/dist/internal/dismissible-layer/__tests__/dismissible-layer.test.js +0 -196
  134. package/dist/internal/drag-drop/__tests__/auto-scroll.test.js +0 -104
  135. package/dist/internal/drag-drop/__tests__/drag-session.test.svelte.js +0 -803
  136. package/dist/internal/drag-drop/__tests__/drag-source.test.svelte.js +0 -130
  137. package/dist/internal/drag-drop/__tests__/drop-delegate.test.js +0 -223
  138. package/dist/internal/drag-drop/__tests__/types.test.js +0 -20
  139. package/dist/internal/escape-layer/__tests__/escape-layer.test.js +0 -113
  140. package/dist/internal/focus-scope/__tests__/focus-scope.test.js +0 -225
  141. package/dist/internal/grace-area/__tests__/grace-area.test.js +0 -67
  142. package/dist/internal/helpers/__tests__/helpers.test.js +0 -123
  143. package/dist/internal/portal/__tests__/PortalTest.svelte +0 -21
  144. package/dist/internal/portal/__tests__/portal.test.js +0 -29
  145. package/dist/internal/portal/__tests__/portal.test.svelte.js +0 -57
  146. package/dist/internal/scroll-lock/__tests__/scroll-lock.test.js +0 -160
  147. package/dist/internal/typeahead/__tests__/typeahead.test.js +0 -61
  148. package/src/themes/__tests__/carbon-dark-contrast.test.ts +0 -170
  149. package/src/themes/__tests__/generated-css-drift.test.ts +0 -53
  150. package/src/themes/__tests__/scrim-opaque.test.ts +0 -52
@@ -1,255 +0,0 @@
1
- import { flushSync, mount, unmount } from 'svelte';
2
- import { afterEach, describe, expect, it, vi } from 'vitest';
3
- import ComboboxRoot from '../components/combobox-root.svelte';
4
- import ComboboxTest from './ComboboxTest.svelte';
5
- describe('combobox', () => {
6
- let target;
7
- let instance;
8
- function setup(props = {}) {
9
- target = document.createElement('div');
10
- document.body.appendChild(target);
11
- instance = mount(ComboboxTest, { target, props: { portalTo: target, ...props } });
12
- flushSync();
13
- return target;
14
- }
15
- function setupRoot(props = {}) {
16
- target = document.createElement('div');
17
- document.body.appendChild(target);
18
- instance = mount(ComboboxRoot, { target, props });
19
- return target;
20
- }
21
- afterEach(() => {
22
- if (instance)
23
- unmount(instance);
24
- target?.remove();
25
- });
26
- // --- Existing tests ---
27
- it('renders closed by default', () => {
28
- setupRoot();
29
- const root = target.querySelector('.sp-combobox-root');
30
- expect(root?.getAttribute('data-state')).toBe('closed');
31
- });
32
- it('renders hidden input when name is provided', () => {
33
- setupRoot({ name: 'fruit', value: 'Apple' });
34
- const input = target.querySelector('input[type="hidden"][name="fruit"]');
35
- expect(input).toBeTruthy();
36
- expect(input?.value).toBe('Apple');
37
- });
38
- // --- Input ARIA ---
39
- it('input has role="combobox"', () => {
40
- setup();
41
- const input = target.querySelector('[role="combobox"]');
42
- expect(input).toBeTruthy();
43
- });
44
- it('input has aria-expanded="false" when closed', () => {
45
- setup();
46
- const input = target.querySelector('[role="combobox"]');
47
- expect(input?.getAttribute('aria-expanded')).toBe('false');
48
- });
49
- it('input has aria-autocomplete="list"', () => {
50
- setup();
51
- const input = target.querySelector('[role="combobox"]');
52
- expect(input?.getAttribute('aria-autocomplete')).toBe('list');
53
- });
54
- it('input has autocomplete="off"', () => {
55
- setup();
56
- const input = target.querySelector('[role="combobox"]');
57
- expect(input?.autocomplete).toBe('off');
58
- });
59
- // --- Open on focus ---
60
- it('opens on input focus', () => {
61
- setup();
62
- const input = target.querySelector('[role="combobox"]');
63
- input.dispatchEvent(new FocusEvent('focus', { bubbles: true }));
64
- flushSync();
65
- expect(target.querySelector('.sp-combobox-root')?.getAttribute('data-state')).toBe('open');
66
- });
67
- // --- Keyboard navigation ---
68
- it('arrowDown opens listbox and navigates to next item', () => {
69
- setup();
70
- const input = target.querySelector('[role="combobox"]');
71
- input.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true }));
72
- flushSync();
73
- // Should be open
74
- expect(target.querySelector('.sp-combobox-root')?.getAttribute('data-state')).toBe('open');
75
- });
76
- it('escape closes the listbox', () => {
77
- setup();
78
- const input = target.querySelector('[role="combobox"]');
79
- // Open first
80
- input.dispatchEvent(new FocusEvent('focus', { bubbles: true }));
81
- flushSync();
82
- expect(target.querySelector('.sp-combobox-root')?.getAttribute('data-state')).toBe('open');
83
- // Escape
84
- input.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
85
- flushSync();
86
- expect(target.querySelector('.sp-combobox-root')?.getAttribute('data-state')).toBe('closed');
87
- });
88
- // --- IME composition guard ---
89
- it('ignores keydown during IME composition', () => {
90
- setup();
91
- const input = target.querySelector('[role="combobox"]');
92
- // Simulate IME composition event (isComposing: true)
93
- const event = new KeyboardEvent('keydown', {
94
- key: 'ArrowDown',
95
- bubbles: true,
96
- composed: true,
97
- });
98
- // Override isComposing since KeyboardEvent constructor doesn't support it directly
99
- Object.defineProperty(event, 'isComposing', { value: true });
100
- input.dispatchEvent(event);
101
- flushSync();
102
- // Should NOT have opened because isComposing was true
103
- expect(target.querySelector('.sp-combobox-root')?.getAttribute('data-state')).toBe('closed');
104
- });
105
- it('calls onOpenChange with new value on each open transition', () => {
106
- const calls = [];
107
- const localTarget = document.createElement('div');
108
- document.body.appendChild(localTarget);
109
- const localInstance = mount(ComboboxTest, {
110
- target: localTarget,
111
- props: {
112
- open: false,
113
- portalTo: localTarget,
114
- onOpenChange: (open) => calls.push(open),
115
- },
116
- });
117
- flushSync();
118
- try {
119
- const input = localTarget.querySelector('.sp-combobox-input');
120
- input.dispatchEvent(new FocusEvent('focus', { bubbles: true }));
121
- flushSync();
122
- expect(calls).toEqual([true]);
123
- input.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
124
- flushSync();
125
- expect(calls).toEqual([true, false]);
126
- }
127
- finally {
128
- unmount(localInstance);
129
- localTarget.remove();
130
- }
131
- });
132
- it('processes keydown when not composing', () => {
133
- setup();
134
- const input = target.querySelector('[role="combobox"]');
135
- const event = new KeyboardEvent('keydown', {
136
- key: 'ArrowDown',
137
- bubbles: true,
138
- });
139
- Object.defineProperty(event, 'isComposing', { value: false });
140
- input.dispatchEvent(event);
141
- flushSync();
142
- // Should have opened because isComposing was false
143
- expect(target.querySelector('.sp-combobox-root')?.getAttribute('data-state')).toBe('open');
144
- });
145
- describe('content positioning (FloatingLayerState)', () => {
146
- // Floating UI's computePosition is async; give it a microtask to run.
147
- async function openAndWaitForFloating(props = {}) {
148
- setup(props);
149
- const input = target.querySelector('[role="combobox"]');
150
- input.dispatchEvent(new FocusEvent('focus', { bubbles: true }));
151
- flushSync();
152
- }
153
- it('applies inline position:absolute on content after opening', async () => {
154
- await openAndWaitForFloating({ disablePortal: true });
155
- const content = target.querySelector('.sp-combobox-content');
156
- await vi.waitFor(() => {
157
- expect(content.style.position).toBe('absolute');
158
- });
159
- });
160
- it('applies inline top and left written by Floating UI (not CSS 100%/0)', async () => {
161
- await openAndWaitForFloating({ disablePortal: true });
162
- const content = target.querySelector('.sp-combobox-content');
163
- await vi.waitFor(() => {
164
- // Floating UI writes pixel values — in jsdom they resolve to '0px'
165
- // since getBoundingClientRect returns zero, but the values must be
166
- // *inline styles* (not CSS rules) so the '100%' top and '0' right
167
- // that caused the bug are gone.
168
- expect(content.style.top).toMatch(/px$/);
169
- expect(content.style.left).toMatch(/px$/);
170
- });
171
- });
172
- it('accepts the side prop (default: bottom)', async () => {
173
- await openAndWaitForFloating({ disablePortal: true, side: 'top' });
174
- const content = target.querySelector('.sp-combobox-content');
175
- expect(content).toBeTruthy();
176
- });
177
- it('accepts the sideOffset prop', async () => {
178
- await openAndWaitForFloating({ disablePortal: true, sideOffset: 12 });
179
- const content = target.querySelector('.sp-combobox-content');
180
- expect(content).toBeTruthy();
181
- });
182
- it('accepts the align prop', async () => {
183
- await openAndWaitForFloating({ disablePortal: true, align: 'center' });
184
- const content = target.querySelector('.sp-combobox-content');
185
- expect(content).toBeTruthy();
186
- });
187
- it('does not stretch to full body width anymore when portaled', async () => {
188
- // Regression: the bug rendered the content with right:0 against body,
189
- // producing a full-viewport-width menu. After the fix, the content is
190
- // positioned (via FloatingLayerState) and does NOT have `right: 0`
191
- // inherited from the stylesheet.
192
- await openAndWaitForFloating({});
193
- const content = document.body.querySelector('.sp-combobox-content');
194
- await vi.waitFor(() => {
195
- const cs = window.getComputedStyle(content);
196
- // Floating UI writes `left` inline → `right` in CSS should not be 0
197
- // (the old buggy rule `right: 0` is removed). A reasonable proxy:
198
- // assert that `width` isn't pinned to viewport / body width.
199
- expect(cs.right).not.toBe('0px');
200
- });
201
- });
202
- });
203
- describe('portal opt-out (disablePortal)', () => {
204
- it('portals to document.body by default', () => {
205
- const localTarget = document.createElement('div');
206
- document.body.appendChild(localTarget);
207
- const localInstance = mount(ComboboxTest, {
208
- target: localTarget,
209
- props: { open: true },
210
- });
211
- flushSync();
212
- try {
213
- expect(localTarget.querySelector('.sp-combobox-content')).toBeNull();
214
- expect(document.body.querySelector('.sp-combobox-content')).toBeTruthy();
215
- }
216
- finally {
217
- unmount(localInstance);
218
- localTarget.remove();
219
- }
220
- });
221
- it('renders inline when disablePortal={true}', () => {
222
- const localTarget = document.createElement('div');
223
- document.body.appendChild(localTarget);
224
- const localInstance = mount(ComboboxTest, {
225
- target: localTarget,
226
- props: { open: true, disablePortal: true },
227
- });
228
- flushSync();
229
- try {
230
- expect(localTarget.querySelector('.sp-combobox-content')).toBeTruthy();
231
- }
232
- finally {
233
- unmount(localInstance);
234
- localTarget.remove();
235
- }
236
- });
237
- it('preserves consumer class on the content element when inline', () => {
238
- const localTarget = document.createElement('div');
239
- document.body.appendChild(localTarget);
240
- const localInstance = mount(ComboboxTest, {
241
- target: localTarget,
242
- props: { open: true, disablePortal: true, contentClass: 'my-consumer-class' },
243
- });
244
- flushSync();
245
- try {
246
- const el = localTarget.querySelector('.sp-combobox-content.my-consumer-class');
247
- expect(el).toBeTruthy();
248
- }
249
- finally {
250
- unmount(localInstance);
251
- localTarget.remove();
252
- }
253
- });
254
- });
255
- });
@@ -1,29 +0,0 @@
1
- <script lang="ts">
2
- import CommandInput from '../components/command-input.svelte'
3
- import CommandItem from '../components/command-item.svelte'
4
- import CommandList from '../components/command-list.svelte'
5
- import CommandRoot from '../components/command-root.svelte'
6
-
7
- /**
8
- * The same inline composition with NO `Command.Group`.
9
- *
10
- * The group and the item each gate rendering on their own predicate, and
11
- * both read the registry. Reviewing #224 turned up two distinct failures
12
- * behind one symptom, so the group must be removable from the picture for a
13
- * test to say which mechanism it is exercising.
14
- */
15
- let open = $state(false)
16
- let value = $state('')
17
-
18
- export function setOpen(next: boolean) {
19
- open = next
20
- }
21
- </script>
22
-
23
- <CommandRoot mode="inline" bind:open bind:value>
24
- <CommandInput class="probe-input" />
25
- <CommandList>
26
- <CommandItem value="copy" keywords={['duplicate']}>Copy</CommandItem>
27
- <CommandItem value="paste">Paste</CommandItem>
28
- </CommandList>
29
- </CommandRoot>
@@ -1,89 +0,0 @@
1
- <script lang="ts">
2
- import type { CommandMode } from '../command.svelte.js'
3
- import CommandEmpty from '../components/command-empty.svelte'
4
- import CommandGroup from '../components/command-group.svelte'
5
- import CommandInput from '../components/command-input.svelte'
6
- import CommandItem from '../components/command-item.svelte'
7
- import CommandList from '../components/command-list.svelte'
8
- import CommandRoot from '../components/command-root.svelte'
9
-
10
- type Entry = { value: string; label: string; keywords?: string[] }
11
-
12
- /**
13
- * Harness for the `inline` composition: a field that outlives its results.
14
- *
15
- * The harness OWNS `open` and `entries` as local state and exposes accessors,
16
- * rather than taking them as props a test would try to reassign — Svelte 5
17
- * props are not writable through the object `mount()` returns. Owning them
18
- * here is also closer to real use: `bind:open` lets the Root push a close
19
- * back (Escape, outside pointer) and the test observes the same value the
20
- * consumer would.
21
- *
22
- * `entries` is mutable so a test can change the COLLECTION between two
23
- * openings — the case where a stale selection, a dead ARIA reference or a
24
- * lost first arrow would actually show up.
25
- */
26
- const {
27
- initialOpen = false,
28
- initialEntries = [
29
- { value: 'copy', label: 'Copy', keywords: ['duplicate'] },
30
- { value: 'paste', label: 'Paste' },
31
- { value: 'cut', label: 'Cut' },
32
- ] as Entry[],
33
- mode = 'inline' as CommandMode,
34
- portalTo = undefined,
35
- trapFocus = undefined,
36
- onOpenChange = undefined,
37
- onEscapeKeydown = undefined,
38
- onSelect = undefined,
39
- inputAttrs = undefined,
40
- }: {
41
- initialOpen?: boolean
42
- initialEntries?: Entry[]
43
- mode?: CommandMode
44
- portalTo?: HTMLElement | string
45
- trapFocus?: boolean
46
- onOpenChange?: (open: boolean) => void
47
- onEscapeKeydown?: (event: KeyboardEvent) => void
48
- onSelect?: (value: string) => void
49
- inputAttrs?: Record<string, unknown>
50
- } = $props()
51
-
52
- let open = $state(initialOpen)
53
- let entries = $state(initialEntries)
54
- let value = $state('')
55
- let element = $state<HTMLInputElement | null>(null)
56
-
57
- export function setOpen(next: boolean) {
58
- open = next
59
- }
60
- export function getOpen() {
61
- return open
62
- }
63
- export function setEntries(next: Entry[]) {
64
- entries = next
65
- }
66
- export function getElement() {
67
- return element
68
- }
69
- </script>
70
-
71
- <CommandRoot bind:value bind:open {mode} {portalTo} {trapFocus} {onOpenChange} {onEscapeKeydown}>
72
- <CommandInput
73
- placeholder="Search..."
74
- wrapperClass="probe-wrapper"
75
- class="probe-input"
76
- bind:element
77
- {...inputAttrs ?? {}}
78
- />
79
- <CommandList>
80
- <CommandEmpty>No results found.</CommandEmpty>
81
- <CommandGroup heading="Actions">
82
- {#each entries as entry (entry.value)}
83
- <CommandItem value={entry.value} keywords={entry.keywords} {onSelect}>
84
- {entry.label}
85
- </CommandItem>
86
- {/each}
87
- </CommandGroup>
88
- </CommandList>
89
- </CommandRoot>
@@ -1,77 +0,0 @@
1
- <script lang="ts">
2
- import CommandEmpty from '../components/command-empty.svelte'
3
- import CommandGroup from '../components/command-group.svelte'
4
- import CommandInput from '../components/command-input.svelte'
5
- import CommandItem from '../components/command-item.svelte'
6
- import CommandList from '../components/command-list.svelte'
7
- import CommandRoot from '../components/command-root.svelte'
8
- import CommandSeparator from '../components/command-separator.svelte'
9
-
10
- let {
11
- value = $bindable(''),
12
- shouldFilter = true,
13
- open = $bindable(true),
14
- portalTo = undefined,
15
- closeOnEscape = true,
16
- closeOnOutsideClick = true,
17
- onOpenChange = undefined,
18
- onClose = undefined,
19
- itemAttrs = undefined,
20
- disabledItemAttrs = undefined,
21
- onItemSelect = undefined,
22
- onDisabledItemSelect = undefined,
23
- }: {
24
- value?: string
25
- shouldFilter?: boolean
26
- open?: boolean
27
- portalTo?: HTMLElement | string
28
- closeOnEscape?: boolean
29
- closeOnOutsideClick?: boolean
30
- onOpenChange?: (open: boolean) => void
31
- onClose?: () => void
32
- /** Arbitrary HTML attributes / native handlers spread onto the `copy` item. */
33
- itemAttrs?: Record<string, unknown>
34
- /** Same, spread onto the `settings` item (the disabled one). */
35
- disabledItemAttrs?: Record<string, unknown>
36
- /** Spectral `onSelect` of the `copy` item. */
37
- onItemSelect?: (value: string) => void
38
- /** Spectral `onSelect` of the `settings` item. */
39
- onDisabledItemSelect?: (value: string) => void
40
- } = $props()
41
- </script>
42
-
43
- <CommandRoot
44
- bind:value
45
- bind:open
46
- {shouldFilter}
47
- {portalTo}
48
- {closeOnEscape}
49
- {closeOnOutsideClick}
50
- {onOpenChange}
51
- {onClose}
52
- >
53
- <CommandInput placeholder="Type a command..." />
54
- <CommandList>
55
- <CommandEmpty>No results found.</CommandEmpty>
56
- <CommandGroup heading="Actions">
57
- <CommandItem
58
- value="copy"
59
- keywords={['duplicate']}
60
- onSelect={onItemSelect}
61
- {...itemAttrs ?? {}}>Copy</CommandItem
62
- >
63
- <CommandItem value="paste">Paste</CommandItem>
64
- <CommandItem value="cut">Cut</CommandItem>
65
- </CommandGroup>
66
- <CommandSeparator />
67
- <CommandGroup heading="Navigation">
68
- <CommandItem value="home">Home</CommandItem>
69
- <CommandItem
70
- value="settings"
71
- disabled
72
- onSelect={onDisabledItemSelect}
73
- {...disabledItemAttrs ?? {}}>Settings</CommandItem
74
- >
75
- </CommandGroup>
76
- </CommandList>
77
- </CommandRoot>