@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,215 +0,0 @@
1
- import { flushSync, mount, unmount } from 'svelte';
2
- import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
3
- import LinkPreviewRoot from '../components/link-preview-root.svelte';
4
- import LinkPreviewTest from './LinkPreviewTest.svelte';
5
- describe('link-preview', () => {
6
- let target;
7
- let instance;
8
- function setup(props = {}) {
9
- target = document.createElement('div');
10
- document.body.appendChild(target);
11
- instance = mount(LinkPreviewTest, { target, props });
12
- return target;
13
- }
14
- function setupRoot(props = {}) {
15
- target = document.createElement('div');
16
- document.body.appendChild(target);
17
- instance = mount(LinkPreviewRoot, { target, props });
18
- return target;
19
- }
20
- afterEach(() => {
21
- vi.useRealTimers();
22
- if (instance)
23
- unmount(instance);
24
- target?.remove();
25
- });
26
- // --- Basic rendering ---
27
- it('renders root', () => {
28
- setupRoot();
29
- expect(target.querySelector('.sp-link-preview-root')).toBeTruthy();
30
- });
31
- it('root has data-state="closed" by default', () => {
32
- setup();
33
- const root = target.querySelector('.sp-link-preview-root');
34
- expect(root?.getAttribute('data-state')).toBe('closed');
35
- });
36
- // --- Trigger ---
37
- it('trigger renders as an anchor', () => {
38
- setup();
39
- const trigger = target.querySelector('.sp-link-preview-trigger');
40
- expect(trigger?.tagName).toBe('A');
41
- });
42
- it('trigger has href attribute', () => {
43
- setup();
44
- const trigger = target.querySelector('.sp-link-preview-trigger');
45
- expect(trigger?.getAttribute('href')).toBe('https://example.com');
46
- });
47
- it('trigger has aria-haspopup="dialog"', () => {
48
- setup();
49
- const trigger = target.querySelector('.sp-link-preview-trigger');
50
- expect(trigger?.getAttribute('aria-haspopup')).toBe('dialog');
51
- });
52
- it('trigger has aria-expanded="false" when closed', () => {
53
- setup();
54
- const trigger = target.querySelector('.sp-link-preview-trigger');
55
- expect(trigger?.getAttribute('aria-expanded')).toBe('false');
56
- });
57
- // --- Content ---
58
- it('content not rendered when closed', () => {
59
- setup();
60
- expect(target.querySelector('[role="dialog"]')).toBeNull();
61
- });
62
- it('content appears on mouseenter with delay', () => {
63
- vi.useFakeTimers();
64
- setup({ openDelay: 0, closeDelay: 0 });
65
- const trigger = target.querySelector('.sp-link-preview-trigger');
66
- trigger.dispatchEvent(new MouseEvent('mouseenter', { bubbles: true }));
67
- vi.advanceTimersByTime(10);
68
- flushSync();
69
- // Content is portalled to document.body, not inside target
70
- const content = document.querySelector('[role="dialog"]');
71
- expect(content).toBeTruthy();
72
- });
73
- it('content has data-state="open" when visible', () => {
74
- vi.useFakeTimers();
75
- setup({ openDelay: 0 });
76
- const trigger = target.querySelector('.sp-link-preview-trigger');
77
- trigger.dispatchEvent(new MouseEvent('mouseenter', { bubbles: true }));
78
- vi.advanceTimersByTime(10);
79
- flushSync();
80
- // Content is portalled to document.body, not inside target
81
- const content = document.querySelector('[role="dialog"]');
82
- expect(content?.getAttribute('data-state')).toBe('open');
83
- });
84
- it('trigger has aria-expanded="true" when content is visible', () => {
85
- vi.useFakeTimers();
86
- setup({ openDelay: 0 });
87
- const trigger = target.querySelector('.sp-link-preview-trigger');
88
- trigger.dispatchEvent(new MouseEvent('mouseenter', { bubbles: true }));
89
- vi.advanceTimersByTime(10);
90
- flushSync();
91
- expect(trigger.getAttribute('aria-expanded')).toBe('true');
92
- });
93
- it('trigger has aria-controls when open', () => {
94
- vi.useFakeTimers();
95
- setup({ openDelay: 0 });
96
- const trigger = target.querySelector('.sp-link-preview-trigger');
97
- trigger.dispatchEvent(new MouseEvent('mouseenter', { bubbles: true }));
98
- vi.advanceTimersByTime(10);
99
- flushSync();
100
- // Content is portalled to document.body, not inside target
101
- const content = document.querySelector('[role="dialog"]');
102
- expect(trigger.getAttribute('aria-controls')).toBe(content?.id);
103
- });
104
- // --- Focus behavior ---
105
- it('opens on focus', () => {
106
- vi.useFakeTimers();
107
- setup({ openDelay: 0 });
108
- const trigger = target.querySelector('.sp-link-preview-trigger');
109
- trigger.dispatchEvent(new FocusEvent('focus', { bubbles: true }));
110
- vi.advanceTimersByTime(10);
111
- flushSync();
112
- // Content is portalled to document.body, not inside target
113
- expect(document.querySelector('[role="dialog"]')).toBeTruthy();
114
- });
115
- it('closes on blur', () => {
116
- vi.useFakeTimers();
117
- setup({ openDelay: 0, closeDelay: 0 });
118
- const trigger = target.querySelector('.sp-link-preview-trigger');
119
- trigger.dispatchEvent(new FocusEvent('focus', { bubbles: true }));
120
- vi.advanceTimersByTime(10);
121
- flushSync();
122
- // Content is portalled to document.body, not inside target
123
- expect(document.querySelector('[role="dialog"]')).toBeTruthy();
124
- trigger.dispatchEvent(new FocusEvent('blur', { bubbles: true }));
125
- vi.advanceTimersByTime(10);
126
- flushSync();
127
- expect(document.querySelector('[role="dialog"]')).toBeNull();
128
- });
129
- describe('portal opt-out (disablePortal)', () => {
130
- beforeEach(() => {
131
- vi.useFakeTimers();
132
- });
133
- it('portals to document.body by default', () => {
134
- const localTarget = document.createElement('div');
135
- document.body.appendChild(localTarget);
136
- const localInstance = mount(LinkPreviewTest, {
137
- target: localTarget,
138
- props: { open: true },
139
- });
140
- flushSync(); // flush $effect (dispatches mouseenter → setTimeout(0))
141
- vi.advanceTimersByTime(0); // fire the 0ms timer → open = true
142
- flushSync(); // re-render content
143
- try {
144
- expect(localTarget.querySelector('.sp-link-preview-content')).toBeNull();
145
- expect(document.body.querySelector('.sp-link-preview-content')).toBeTruthy();
146
- }
147
- finally {
148
- unmount(localInstance);
149
- localTarget.remove();
150
- }
151
- });
152
- it('renders inline when disablePortal={true}', () => {
153
- const localTarget = document.createElement('div');
154
- document.body.appendChild(localTarget);
155
- const localInstance = mount(LinkPreviewTest, {
156
- target: localTarget,
157
- props: { open: true, disablePortal: true },
158
- });
159
- flushSync();
160
- vi.advanceTimersByTime(0);
161
- flushSync();
162
- try {
163
- expect(localTarget.querySelector('.sp-link-preview-content')).toBeTruthy();
164
- }
165
- finally {
166
- unmount(localInstance);
167
- localTarget.remove();
168
- }
169
- });
170
- it('preserves consumer class on the content element when inline', () => {
171
- const localTarget = document.createElement('div');
172
- document.body.appendChild(localTarget);
173
- const localInstance = mount(LinkPreviewTest, {
174
- target: localTarget,
175
- props: { open: true, disablePortal: true, contentClass: 'my-consumer-class' },
176
- });
177
- flushSync();
178
- vi.advanceTimersByTime(0);
179
- flushSync();
180
- try {
181
- const el = localTarget.querySelector('.sp-link-preview-content.my-consumer-class');
182
- expect(el).toBeTruthy();
183
- }
184
- finally {
185
- unmount(localInstance);
186
- localTarget.remove();
187
- }
188
- });
189
- });
190
- it('content is portalled to document.body when open', () => {
191
- vi.useFakeTimers();
192
- const localTarget = document.createElement('div');
193
- document.body.appendChild(localTarget);
194
- const localInstance = mount(LinkPreviewTest, {
195
- target: localTarget,
196
- props: { openDelay: 0, closeDelay: 0 },
197
- });
198
- flushSync();
199
- try {
200
- const trigger = localTarget.querySelector('.sp-link-preview-trigger');
201
- trigger.dispatchEvent(new MouseEvent('mouseenter', { bubbles: true }));
202
- vi.advanceTimersByTime(10);
203
- flushSync();
204
- // Content should NOT be rendered inside the local mount target
205
- expect(localTarget.querySelector('.sp-link-preview-content')).toBeNull();
206
- // Content SHOULD be rendered somewhere in the document (portalled)
207
- expect(document.querySelector('.sp-link-preview-content')).toBeTruthy();
208
- }
209
- finally {
210
- unmount(localInstance);
211
- localTarget.remove();
212
- vi.useRealTimers();
213
- }
214
- });
215
- });
@@ -1,22 +0,0 @@
1
- import { mount, unmount } from 'svelte';
2
- import { afterEach, describe, expect, it } from 'vitest';
3
- import ListRoot from '../components/list-root.svelte';
4
- describe('list', () => {
5
- let target;
6
- let instance;
7
- function setup(props = {}) {
8
- target = document.createElement('div');
9
- document.body.appendChild(target);
10
- instance = mount(ListRoot, { target, props });
11
- return target;
12
- }
13
- afterEach(() => {
14
- if (instance)
15
- unmount(instance);
16
- target?.remove();
17
- });
18
- it('renders with role=list', () => {
19
- setup();
20
- expect(target.querySelector('[role="list"]')).toBeTruthy();
21
- });
22
- });
@@ -1,52 +0,0 @@
1
- <script lang="ts">
2
- import DropdownMenuItem from '../../dropdown-menu/components/dropdown-menu-item.svelte'
3
- import DropdownMenuSeparator from '../../dropdown-menu/components/dropdown-menu-separator.svelte'
4
- import DropdownMenuSubContent from '../../dropdown-menu/components/dropdown-menu-sub-content.svelte'
5
- import DropdownMenuSubTrigger from '../../dropdown-menu/components/dropdown-menu-sub-trigger.svelte'
6
- import DropdownMenuSub from '../../dropdown-menu/components/dropdown-menu-sub.svelte'
7
- import MenubarContent from '../components/menubar-content.svelte'
8
- import MenubarMenu from '../components/menubar-menu.svelte'
9
- import MenubarRoot from '../components/menubar-root.svelte'
10
- import MenubarTrigger from '../components/menubar-trigger.svelte'
11
-
12
- const {
13
- loop = true,
14
- portalTo,
15
- withSub = false,
16
- }: { loop?: boolean; portalTo?: HTMLElement | string; withSub?: boolean } = $props()
17
- </script>
18
-
19
- <MenubarRoot {loop}>
20
- <MenubarMenu value="file">
21
- <MenubarTrigger>File</MenubarTrigger>
22
- <MenubarContent {portalTo}>
23
- <DropdownMenuItem>New</DropdownMenuItem>
24
- <DropdownMenuItem>Open</DropdownMenuItem>
25
- <DropdownMenuSeparator />
26
- <DropdownMenuItem>Save</DropdownMenuItem>
27
- {#if withSub}
28
- <DropdownMenuSub>
29
- <DropdownMenuSubTrigger>Share</DropdownMenuSubTrigger>
30
- <DropdownMenuSubContent>
31
- <DropdownMenuItem>Email</DropdownMenuItem>
32
- <DropdownMenuItem>Copy Link</DropdownMenuItem>
33
- </DropdownMenuSubContent>
34
- </DropdownMenuSub>
35
- {/if}
36
- </MenubarContent>
37
- </MenubarMenu>
38
- <MenubarMenu value="edit">
39
- <MenubarTrigger>Edit</MenubarTrigger>
40
- <MenubarContent {portalTo}>
41
- <DropdownMenuItem>Undo</DropdownMenuItem>
42
- <DropdownMenuItem>Redo</DropdownMenuItem>
43
- </MenubarContent>
44
- </MenubarMenu>
45
- <MenubarMenu value="view">
46
- <MenubarTrigger>View</MenubarTrigger>
47
- <MenubarContent {portalTo}>
48
- <DropdownMenuItem>Zoom In</DropdownMenuItem>
49
- <DropdownMenuItem>Zoom Out</DropdownMenuItem>
50
- </MenubarContent>
51
- </MenubarMenu>
52
- </MenubarRoot>
@@ -1,28 +0,0 @@
1
- import { mount, unmount } from 'svelte';
2
- import { afterEach, describe, expect, it } from 'vitest';
3
- import { configureAxe } from 'vitest-axe';
4
- import * as matchers from 'vitest-axe/matchers';
5
- import MenubarTest from './MenubarTest.svelte';
6
- expect.extend(matchers);
7
- const axe = configureAxe({
8
- rules: {
9
- region: { enabled: false },
10
- 'page-has-heading-one': { enabled: false },
11
- 'landmark-one-main': { enabled: false },
12
- },
13
- });
14
- describe('menubar a11y', () => {
15
- let cleanup;
16
- afterEach(() => cleanup?.());
17
- it('has no axe violations', async () => {
18
- const container = document.createElement('div');
19
- document.body.appendChild(container);
20
- const instance = mount(MenubarTest, { target: container });
21
- const results = await axe(container);
22
- cleanup = () => {
23
- unmount(instance);
24
- container.remove();
25
- };
26
- expect(results).toHaveNoViolations();
27
- });
28
- });
@@ -1,57 +0,0 @@
1
- import { flushSync, mount, unmount } from 'svelte';
2
- import { afterEach, describe, expect, it } from 'vitest';
3
- import MenubarTest from './MenubarTest.svelte';
4
- describe('menubar integration', () => {
5
- let target;
6
- let instance;
7
- function setup(props = {}) {
8
- target = document.createElement('div');
9
- document.body.appendChild(target);
10
- instance = mount(MenubarTest, { target, props: { portalTo: target, ...props } });
11
- flushSync();
12
- return target;
13
- }
14
- afterEach(() => {
15
- if (instance)
16
- unmount(instance);
17
- target?.remove();
18
- });
19
- it('first trigger is Tab-reachable (tabindex=0)', () => {
20
- setup();
21
- const triggers = target.querySelectorAll('[data-menubar-trigger]');
22
- expect(triggers[0]?.getAttribute('tabindex')).toBe('0');
23
- expect(triggers[1]?.getAttribute('tabindex')).toBe('-1');
24
- expect(triggers[2]?.getAttribute('tabindex')).toBe('-1');
25
- });
26
- it('full flow: click → select item → menu closes', () => {
27
- setup();
28
- const triggers = target.querySelectorAll('[data-menubar-trigger]');
29
- triggers[0].click();
30
- flushSync();
31
- const menu = target.querySelector('[role="menu"]');
32
- expect(menu).toBeTruthy();
33
- const items = menu.querySelectorAll('[role="menuitem"]');
34
- items[0].click();
35
- flushSync();
36
- expect(target.querySelector('[role="menu"]')).toBeNull();
37
- });
38
- it('full flow: click File → hover Edit → Edit opens', () => {
39
- setup();
40
- const triggers = target.querySelectorAll('[data-menubar-trigger]');
41
- triggers[0].click();
42
- flushSync();
43
- triggers[1].dispatchEvent(new MouseEvent('mouseenter', { bubbles: true }));
44
- flushSync();
45
- expect(triggers[0].getAttribute('data-state')).toBe('closed');
46
- expect(triggers[1].getAttribute('data-state')).toBe('open');
47
- });
48
- it('roving tabindex updates after ArrowRight', () => {
49
- setup();
50
- const triggers = target.querySelectorAll('[data-menubar-trigger]');
51
- triggers[0].focus();
52
- triggers[0].dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowRight', bubbles: true }));
53
- flushSync();
54
- expect(triggers[1]?.getAttribute('tabindex')).toBe('0');
55
- expect(triggers[0]?.getAttribute('tabindex')).toBe('-1');
56
- });
57
- });