@spectral_labs/ui 1.6.1 → 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.
- package/LICENSE +21 -0
- package/THIRD_PARTY_NOTICES.md +201 -0
- package/dist/components/command/command.svelte.d.ts +30 -0
- package/dist/components/command/command.svelte.d.ts.map +1 -1
- package/dist/components/command/command.svelte.js +85 -4
- package/dist/components/command/components/command-group.svelte +25 -15
- package/dist/components/command/components/command-group.svelte.d.ts.map +1 -1
- package/dist/components/command/components/command-input.svelte +54 -5
- package/dist/components/command/components/command-input.svelte.d.ts +1 -1
- package/dist/components/command/components/command-input.svelte.d.ts.map +1 -1
- package/dist/components/command/components/command-list.svelte +22 -3
- package/dist/components/command/components/command-list.svelte.d.ts.map +1 -1
- package/dist/components/command/components/command-root.svelte +43 -4
- package/dist/components/command/components/command-root.svelte.d.ts.map +1 -1
- package/dist/components/command/index.d.ts +1 -0
- package/dist/components/command/index.d.ts.map +1 -1
- package/dist/components/command/types.d.ts +59 -4
- package/dist/components/command/types.d.ts.map +1 -1
- package/package.json +8 -2
- package/dist/components/__tests__/overlay-scrim-source.test.js +0 -134
- package/dist/components/accordion/__tests__/AccordionTest.svelte +0 -31
- package/dist/components/accordion/__tests__/accordion.test.svelte.js +0 -139
- package/dist/components/alert-dialog/__tests__/AlertDialogTest.svelte +0 -28
- package/dist/components/alert-dialog/__tests__/alert-dialog.a11y.test.js +0 -42
- package/dist/components/alert-dialog/__tests__/alert-dialog.integration.test.svelte.js +0 -51
- package/dist/components/alert-dialog/__tests__/alert-dialog.test.svelte.js +0 -113
- package/dist/components/app-bar/__tests__/app-bar.test.svelte.js +0 -30
- package/dist/components/aspect-ratio/__tests__/aspect-ratio.test.svelte.js +0 -22
- package/dist/components/avatar/__tests__/avatar.test.svelte.js +0 -26
- package/dist/components/badge/__tests__/badge.test.svelte.js +0 -30
- package/dist/components/bottom-sheet/__tests__/BottomSheetTest.svelte +0 -22
- package/dist/components/bottom-sheet/__tests__/bottom-sheet.test.svelte.js +0 -83
- package/dist/components/button/__tests__/button.test.svelte.js +0 -63
- package/dist/components/calendar/__tests__/CalendarTest.svelte +0 -56
- package/dist/components/calendar/__tests__/calendar.test.svelte.js +0 -190
- package/dist/components/card/__tests__/card.test.svelte.js +0 -30
- package/dist/components/checkbox/__tests__/checkbox.test.svelte.js +0 -44
- package/dist/components/chips/__tests__/chips.test.svelte.js +0 -26
- package/dist/components/collapsible/__tests__/CollapsibleTest.svelte +0 -18
- package/dist/components/collapsible/__tests__/collapsible.test.svelte.js +0 -125
- package/dist/components/combobox/__tests__/ComboboxTest.svelte +0 -40
- package/dist/components/combobox/__tests__/combobox.test.svelte.js +0 -255
- package/dist/components/command/__tests__/CommandTest.svelte +0 -77
- package/dist/components/command/__tests__/command-item-passthrough.test.svelte.js +0 -284
- package/dist/components/command/__tests__/command.a11y.test.js +0 -30
- package/dist/components/command/__tests__/command.integration.test.svelte.js +0 -68
- package/dist/components/command/__tests__/command.test.svelte.js +0 -230
- package/dist/components/context-menu/__tests__/ContextMenuNonInteractiveTest.svelte +0 -32
- package/dist/components/context-menu/__tests__/ContextMenuTest.svelte +0 -25
- package/dist/components/context-menu/__tests__/context-menu.test.svelte.js +0 -141
- package/dist/components/date-field/__tests__/DateFieldTest.svelte +0 -20
- package/dist/components/date-field/__tests__/date-field.test.svelte.js +0 -139
- package/dist/components/date-picker/__tests__/DatePickerTest.svelte +0 -20
- package/dist/components/date-picker/__tests__/date-picker.test.svelte.js +0 -190
- package/dist/components/date-range-field/__tests__/DateRangeFieldTest.svelte +0 -20
- package/dist/components/date-range-field/__tests__/date-range-field.test.svelte.js +0 -130
- package/dist/components/date-range-picker/__tests__/DateRangePickerTest.svelte +0 -18
- package/dist/components/date-range-picker/__tests__/date-range-picker.test.svelte.js +0 -156
- package/dist/components/dialog/__tests__/DialogTest.svelte +0 -34
- package/dist/components/dialog/__tests__/dialog.test.svelte.js +0 -184
- package/dist/components/drop-zone/__tests__/drop-zone.test.svelte.js +0 -26
- package/dist/components/dropdown-menu/__tests__/DropdownMenuRadioTest.svelte +0 -90
- package/dist/components/dropdown-menu/__tests__/DropdownMenuTest.svelte +0 -71
- package/dist/components/dropdown-menu/__tests__/dropdown-menu-radio-group.test.svelte.js +0 -306
- package/dist/components/dropdown-menu/__tests__/dropdown-menu.test.svelte.js +0 -567
- package/dist/components/empty-state/__tests__/empty-state.test.svelte.js +0 -26
- package/dist/components/fab/__tests__/fab.test.svelte.js +0 -30
- package/dist/components/field/__tests__/FieldTest.svelte +0 -26
- package/dist/components/field/__tests__/field.test.svelte.js +0 -74
- package/dist/components/grid-list/__tests__/GridListTest.svelte +0 -46
- package/dist/components/grid-list/__tests__/grid-list.test.svelte.js +0 -231
- package/dist/components/hover-card/__tests__/HoverCardTest.svelte +0 -30
- package/dist/components/hover-card/__tests__/hover-card.test.svelte.js +0 -236
- package/dist/components/indicator/__tests__/indicator.test.svelte.js +0 -30
- package/dist/components/input/__tests__/input.test.svelte.js +0 -67
- package/dist/components/label/__tests__/label.test.svelte.js +0 -22
- package/dist/components/language-select/__tests__/language-select.test.svelte.js +0 -199
- package/dist/components/language-select/__tests__/languages.test.js +0 -87
- package/dist/components/link-preview/__tests__/LinkPreviewTest.svelte +0 -37
- package/dist/components/link-preview/__tests__/link-preview.a11y.test.js +0 -28
- package/dist/components/link-preview/__tests__/link-preview.integration.test.svelte.js +0 -54
- package/dist/components/link-preview/__tests__/link-preview.test.svelte.js +0 -215
- package/dist/components/list/__tests__/list.test.svelte.js +0 -22
- package/dist/components/menubar/__tests__/MenubarTest.svelte +0 -52
- package/dist/components/menubar/__tests__/menubar.a11y.test.js +0 -28
- package/dist/components/menubar/__tests__/menubar.integration.test.svelte.js +0 -57
- package/dist/components/menubar/__tests__/menubar.test.svelte.js +0 -328
- package/dist/components/meter/__tests__/meter.test.svelte.js +0 -26
- package/dist/components/nav-bar/__tests__/nav-bar.test.svelte.js +0 -23
- package/dist/components/nav-drawer/__tests__/nav-drawer.test.svelte.js +0 -28
- package/dist/components/nav-rail/__tests__/nav-rail.test.svelte.js +0 -28
- package/dist/components/pagination/__tests__/pagination.test.svelte.js +0 -26
- package/dist/components/pin-input/__tests__/pin-input.test.svelte.js +0 -71
- package/dist/components/popover/__tests__/PopoverTest.svelte +0 -27
- package/dist/components/popover/__tests__/popover.test.svelte.js +0 -196
- package/dist/components/progress/__tests__/progress.test.svelte.js +0 -32
- package/dist/components/radio-group/__tests__/radio-group.test.svelte.js +0 -22
- package/dist/components/range-calendar/__tests__/RangeCalendarTest.svelte +0 -23
- package/dist/components/range-calendar/__tests__/range-calendar.test.svelte.js +0 -105
- package/dist/components/rating-group/__tests__/rating-group.test.svelte.js +0 -26
- package/dist/components/scroll-area/__tests__/scroll-area.test.svelte.js +0 -34
- package/dist/components/search-field/__tests__/SearchFieldTest.svelte +0 -34
- package/dist/components/search-field/__tests__/search-field.test.svelte.js +0 -118
- package/dist/components/select/__tests__/SelectLabelPersistenceTest.svelte +0 -31
- package/dist/components/select/__tests__/SelectTest.svelte +0 -33
- package/dist/components/select/__tests__/select.test.svelte.js +0 -221
- package/dist/components/separator/__tests__/separator.test.svelte.js +0 -39
- package/dist/components/sheet/__tests__/SheetTest.svelte +0 -34
- package/dist/components/sheet/__tests__/sheet.test.svelte.js +0 -193
- package/dist/components/side-sheet/__tests__/side-sheet.test.svelte.js +0 -138
- package/dist/components/sidebar/__tests__/SidebarFullTest.svelte +0 -45
- package/dist/components/sidebar/__tests__/SidebarTest.svelte +0 -9
- package/dist/components/sidebar/__tests__/sidebar.test.svelte.js +0 -186
- package/dist/components/simple-dialog/__tests__/SimpleDialogTest.svelte +0 -40
- package/dist/components/simple-dialog/__tests__/simple-dialog.test.svelte.js +0 -50
- package/dist/components/simple-tooltip/__tests__/SimpleTooltipTest.svelte +0 -19
- package/dist/components/simple-tooltip/__tests__/simple-tooltip.test.svelte.js +0 -61
- package/dist/components/slider/__tests__/slider.test.svelte.js +0 -42
- package/dist/components/sortable-list/__tests__/NestedSortableListTest.svelte +0 -49
- package/dist/components/sortable-list/__tests__/SortableListTest.svelte +0 -42
- package/dist/components/sortable-list/__tests__/sortable-list.nested.test.svelte.js +0 -112
- package/dist/components/sortable-list/__tests__/sortable-list.test.svelte.js +0 -175
- package/dist/components/splitter/__tests__/splitter.test.svelte.js +0 -26
- package/dist/components/switch/__tests__/switch.test.svelte.js +0 -44
- package/dist/components/table/__tests__/table.test.svelte.js +0 -22
- package/dist/components/tabs/__tests__/TabsTest.svelte +0 -32
- package/dist/components/tabs/__tests__/tabs.test.svelte.js +0 -227
- package/dist/components/textarea/__tests__/textarea.test.svelte.js +0 -55
- package/dist/components/time-field/__tests__/TimeFieldTest.svelte +0 -20
- package/dist/components/time-field/__tests__/time-field.test.svelte.js +0 -100
- package/dist/components/time-range-field/__tests__/TimeRangeFieldTest.svelte +0 -20
- package/dist/components/time-range-field/__tests__/time-range-field.test.svelte.js +0 -124
- package/dist/components/toast/__tests__/toast.test.svelte.js +0 -46
- package/dist/components/toggle/__tests__/toggle.test.svelte.js +0 -38
- package/dist/components/toggle-group/__tests__/toggle-group.test.svelte.js +0 -22
- package/dist/components/toolbar/__tests__/ToolbarCompositionTest.svelte +0 -18
- package/dist/components/toolbar/__tests__/ToolbarTabstopTest.svelte +0 -10
- package/dist/components/toolbar/__tests__/toolbar.test.svelte.js +0 -63
- package/dist/components/tooltip/__tests__/TooltipTest.svelte +0 -22
- package/dist/components/tooltip/__tests__/tooltip.test.svelte.js +0 -225
- package/dist/components/tree/__tests__/TreeLabelContentTest.svelte +0 -21
- package/dist/components/tree/__tests__/TreeTest.svelte +0 -24
- package/dist/components/tree/__tests__/tree.test.svelte.js +0 -229
- package/dist/components/virtualizer/__tests__/waterfall-layout.test.js +0 -82
- package/dist/internal/announcer/__tests__/announcer.test.js +0 -42
- package/dist/internal/dismissible-layer/__tests__/dismissible-layer.test.js +0 -196
- package/dist/internal/drag-drop/__tests__/auto-scroll.test.js +0 -104
- package/dist/internal/drag-drop/__tests__/drag-session.test.svelte.js +0 -803
- package/dist/internal/drag-drop/__tests__/drag-source.test.svelte.js +0 -130
- package/dist/internal/drag-drop/__tests__/drop-delegate.test.js +0 -223
- package/dist/internal/drag-drop/__tests__/types.test.js +0 -20
- package/dist/internal/escape-layer/__tests__/escape-layer.test.js +0 -113
- package/dist/internal/focus-scope/__tests__/focus-scope.test.js +0 -225
- package/dist/internal/grace-area/__tests__/grace-area.test.js +0 -67
- package/dist/internal/helpers/__tests__/helpers.test.js +0 -123
- package/dist/internal/portal/__tests__/PortalTest.svelte +0 -21
- package/dist/internal/portal/__tests__/portal.test.js +0 -29
- package/dist/internal/portal/__tests__/portal.test.svelte.js +0 -57
- package/dist/internal/scroll-lock/__tests__/scroll-lock.test.js +0 -160
- package/dist/internal/typeahead/__tests__/typeahead.test.js +0 -61
- package/src/themes/__tests__/carbon-dark-contrast.test.ts +0 -170
- package/src/themes/__tests__/generated-css-drift.test.ts +0 -53
- 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
|
-
});
|