@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.
- package/LICENSE +21 -0
- package/THIRD_PARTY_NOTICES.md +201 -0
- 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__/CommandInlineDirectTest.svelte +0 -29
- package/dist/components/command/__tests__/CommandInlineTest.svelte +0 -89
- package/dist/components/command/__tests__/CommandTest.svelte +0 -77
- package/dist/components/command/__tests__/command-inline.test.svelte.js +0 -392
- 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,130 +0,0 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
-
import { dragSession } from '../drag-session.svelte.js';
|
|
3
|
-
import { DragSourceState } from '../drag-source.svelte.js';
|
|
4
|
-
function createSourceConfig(id, overrides = {}) {
|
|
5
|
-
return {
|
|
6
|
-
id,
|
|
7
|
-
getItems: () => [{ 'test-type': id, 'text/plain': `Item ${id}` }],
|
|
8
|
-
onDragStart: vi.fn(),
|
|
9
|
-
onDragEnd: vi.fn(),
|
|
10
|
-
...overrides,
|
|
11
|
-
};
|
|
12
|
-
}
|
|
13
|
-
function createElement(parent = document.body) {
|
|
14
|
-
const el = document.createElement('div');
|
|
15
|
-
Object.defineProperty(el, 'getBoundingClientRect', {
|
|
16
|
-
value: () => ({
|
|
17
|
-
top: 0,
|
|
18
|
-
left: 0,
|
|
19
|
-
bottom: 100,
|
|
20
|
-
right: 200,
|
|
21
|
-
width: 200,
|
|
22
|
-
height: 100,
|
|
23
|
-
x: 0,
|
|
24
|
-
y: 0,
|
|
25
|
-
toJSON() { },
|
|
26
|
-
}),
|
|
27
|
-
});
|
|
28
|
-
el.setPointerCapture = vi.fn();
|
|
29
|
-
el.releasePointerCapture = vi.fn();
|
|
30
|
-
parent.appendChild(el);
|
|
31
|
-
return el;
|
|
32
|
-
}
|
|
33
|
-
/** Polyfill PointerEvent for jsdom. */
|
|
34
|
-
function ensurePointerEventPolyfill() {
|
|
35
|
-
if (typeof globalThis.PointerEvent === 'undefined') {
|
|
36
|
-
;
|
|
37
|
-
globalThis.PointerEvent = class PointerEvent extends MouseEvent {
|
|
38
|
-
pointerId;
|
|
39
|
-
pointerType;
|
|
40
|
-
constructor(type, init = {}) {
|
|
41
|
-
super(type, init);
|
|
42
|
-
this.pointerId = init.pointerId ?? 0;
|
|
43
|
-
this.pointerType = init.pointerType ?? '';
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
function createMousePointerEvent(type, x, y) {
|
|
49
|
-
return new PointerEvent(type, {
|
|
50
|
-
clientX: x,
|
|
51
|
-
clientY: y,
|
|
52
|
-
pointerId: 1,
|
|
53
|
-
pointerType: 'mouse',
|
|
54
|
-
bubbles: true,
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
describe('dragSourceState', () => {
|
|
58
|
-
beforeEach(() => {
|
|
59
|
-
dragSession._resetForTests();
|
|
60
|
-
ensurePointerEventPolyfill();
|
|
61
|
-
});
|
|
62
|
-
describe('nested sources (#190)', () => {
|
|
63
|
-
it('the innermost source claims the pointerdown — the ancestor never sees it', () => {
|
|
64
|
-
const outerEl = createElement();
|
|
65
|
-
const innerEl = createElement(outerEl);
|
|
66
|
-
const outerConfig = createSourceConfig('outer');
|
|
67
|
-
const innerConfig = createSourceConfig('inner');
|
|
68
|
-
const outer = new DragSourceState(outerConfig);
|
|
69
|
-
const inner = new DragSourceState(innerConfig);
|
|
70
|
-
outer.attach(outerEl);
|
|
71
|
-
inner.attach(innerEl);
|
|
72
|
-
// pointerdown on the inner element bubbles through the outer element
|
|
73
|
-
innerEl.dispatchEvent(createMousePointerEvent('pointerdown', 100, 100));
|
|
74
|
-
expect(dragSession.sourceId).toBe('inner');
|
|
75
|
-
// Crossing the threshold starts the drag for the inner source only
|
|
76
|
-
innerEl.dispatchEvent(createMousePointerEvent('pointermove', 110, 110));
|
|
77
|
-
expect(dragSession.isDragging).toBe(true);
|
|
78
|
-
expect(dragSession.sourceId).toBe('inner');
|
|
79
|
-
expect(inner.isDragging).toBe(true);
|
|
80
|
-
expect(outer.isDragging).toBe(false);
|
|
81
|
-
expect(innerConfig.onDragStart).toHaveBeenCalled();
|
|
82
|
-
expect(outerConfig.onDragStart).not.toHaveBeenCalled();
|
|
83
|
-
// The session ends cleanly on pointerup — no stuck ghost
|
|
84
|
-
innerEl.dispatchEvent(createMousePointerEvent('pointerup', 110, 110));
|
|
85
|
-
expect(dragSession.isDragging).toBe(false);
|
|
86
|
-
expect(dragSession.sourceId).toBeNull();
|
|
87
|
-
expect(document.querySelector('.sp-drag-ghost')).toBeNull();
|
|
88
|
-
inner.detach();
|
|
89
|
-
outer.detach();
|
|
90
|
-
outerEl.remove();
|
|
91
|
-
});
|
|
92
|
-
it('dragging the outer source directly still works', () => {
|
|
93
|
-
const outerEl = createElement();
|
|
94
|
-
const innerEl = createElement(outerEl);
|
|
95
|
-
const outerConfig = createSourceConfig('outer-direct');
|
|
96
|
-
const innerConfig = createSourceConfig('inner-direct');
|
|
97
|
-
const outer = new DragSourceState(outerConfig);
|
|
98
|
-
const inner = new DragSourceState(innerConfig);
|
|
99
|
-
outer.attach(outerEl);
|
|
100
|
-
inner.attach(innerEl);
|
|
101
|
-
// pointerdown on the outer element itself (not inside the inner source)
|
|
102
|
-
outerEl.dispatchEvent(createMousePointerEvent('pointerdown', 100, 100));
|
|
103
|
-
expect(dragSession.sourceId).toBe('outer-direct');
|
|
104
|
-
outerEl.dispatchEvent(createMousePointerEvent('pointermove', 110, 110));
|
|
105
|
-
expect(dragSession.isDragging).toBe(true);
|
|
106
|
-
expect(outer.isDragging).toBe(true);
|
|
107
|
-
outerEl.dispatchEvent(createMousePointerEvent('pointerup', 110, 110));
|
|
108
|
-
expect(dragSession.isDragging).toBe(false);
|
|
109
|
-
inner.detach();
|
|
110
|
-
outer.detach();
|
|
111
|
-
outerEl.remove();
|
|
112
|
-
});
|
|
113
|
-
it('a disabled inner source lets the outer source claim the event', () => {
|
|
114
|
-
const outerEl = createElement();
|
|
115
|
-
const innerEl = createElement(outerEl);
|
|
116
|
-
const outerConfig = createSourceConfig('outer-en');
|
|
117
|
-
const innerConfig = createSourceConfig('inner-dis', { isDisabled: true });
|
|
118
|
-
const outer = new DragSourceState(outerConfig);
|
|
119
|
-
const inner = new DragSourceState(innerConfig);
|
|
120
|
-
outer.attach(outerEl);
|
|
121
|
-
inner.attach(innerEl);
|
|
122
|
-
innerEl.dispatchEvent(createMousePointerEvent('pointerdown', 100, 100));
|
|
123
|
-
expect(dragSession.sourceId).toBe('outer-en');
|
|
124
|
-
dragSession.cancel();
|
|
125
|
-
inner.detach();
|
|
126
|
-
outer.detach();
|
|
127
|
-
outerEl.remove();
|
|
128
|
-
});
|
|
129
|
-
});
|
|
130
|
-
});
|
|
@@ -1,223 +0,0 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, it } from 'vitest';
|
|
2
|
-
import { DropDelegate } from '../drop-delegate.svelte.js';
|
|
3
|
-
function createContainer(orientation, itemCount, itemSize = 50, gap = 0) {
|
|
4
|
-
const container = document.createElement('div');
|
|
5
|
-
// Mock getBoundingClientRect for the container
|
|
6
|
-
const containerHeight = orientation === 'vertical' ? itemCount * itemSize + (itemCount - 1) * gap : itemSize;
|
|
7
|
-
const containerWidth = orientation === 'horizontal' ? itemCount * itemSize + (itemCount - 1) * gap : 200;
|
|
8
|
-
Object.defineProperty(container, 'getBoundingClientRect', {
|
|
9
|
-
value: () => ({
|
|
10
|
-
top: 0,
|
|
11
|
-
left: 0,
|
|
12
|
-
bottom: containerHeight,
|
|
13
|
-
right: containerWidth,
|
|
14
|
-
width: containerWidth,
|
|
15
|
-
height: containerHeight,
|
|
16
|
-
x: 0,
|
|
17
|
-
y: 0,
|
|
18
|
-
toJSON() { },
|
|
19
|
-
}),
|
|
20
|
-
});
|
|
21
|
-
for (let i = 0; i < itemCount; i++) {
|
|
22
|
-
const item = document.createElement('div');
|
|
23
|
-
item.dataset.dndKey = `item-${i}`;
|
|
24
|
-
const offset = i * (itemSize + gap);
|
|
25
|
-
if (orientation === 'vertical') {
|
|
26
|
-
Object.defineProperty(item, 'getBoundingClientRect', {
|
|
27
|
-
value: () => ({
|
|
28
|
-
top: offset,
|
|
29
|
-
bottom: offset + itemSize,
|
|
30
|
-
left: 0,
|
|
31
|
-
right: 200,
|
|
32
|
-
width: 200,
|
|
33
|
-
height: itemSize,
|
|
34
|
-
x: 0,
|
|
35
|
-
y: offset,
|
|
36
|
-
toJSON() { },
|
|
37
|
-
}),
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
else {
|
|
41
|
-
Object.defineProperty(item, 'getBoundingClientRect', {
|
|
42
|
-
value: () => ({
|
|
43
|
-
top: 0,
|
|
44
|
-
bottom: itemSize,
|
|
45
|
-
left: offset,
|
|
46
|
-
right: offset + itemSize,
|
|
47
|
-
width: itemSize,
|
|
48
|
-
height: itemSize,
|
|
49
|
-
x: offset,
|
|
50
|
-
y: 0,
|
|
51
|
-
toJSON() { },
|
|
52
|
-
}),
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
container.appendChild(item);
|
|
56
|
-
}
|
|
57
|
-
return container;
|
|
58
|
-
}
|
|
59
|
-
describe('dropDelegate', () => {
|
|
60
|
-
describe('vertical orientation', () => {
|
|
61
|
-
let delegate;
|
|
62
|
-
let container;
|
|
63
|
-
beforeEach(() => {
|
|
64
|
-
delegate = new DropDelegate({ orientation: 'vertical' });
|
|
65
|
-
container = createContainer('vertical', 3, 50); // 3 items, 50px each
|
|
66
|
-
});
|
|
67
|
-
it('returns root for empty container', () => {
|
|
68
|
-
const empty = document.createElement('div');
|
|
69
|
-
const target = delegate.getDropTargetFromPoint(empty, 100, 100);
|
|
70
|
-
expect(target).toEqual({ type: 'root' });
|
|
71
|
-
});
|
|
72
|
-
it('returns "before" within 5px of item top edge', () => {
|
|
73
|
-
const target = delegate.getDropTargetFromPoint(container, 100, 2);
|
|
74
|
-
expect(target).toEqual({ type: 'item', key: 'item-0', dropPosition: 'before' });
|
|
75
|
-
});
|
|
76
|
-
it('returns "after" within 5px of item bottom edge', () => {
|
|
77
|
-
const target = delegate.getDropTargetFromPoint(container, 100, 48);
|
|
78
|
-
expect(target).toEqual({ type: 'item', key: 'item-0', dropPosition: 'after' });
|
|
79
|
-
});
|
|
80
|
-
it('returns "before" for midpoint split in upper half (no allowDropOn)', () => {
|
|
81
|
-
// Center of first item = 25px, point at 15px is in upper half
|
|
82
|
-
const target = delegate.getDropTargetFromPoint(container, 100, 15);
|
|
83
|
-
expect(target).toEqual({ type: 'item', key: 'item-0', dropPosition: 'before' });
|
|
84
|
-
});
|
|
85
|
-
it('returns "after" for midpoint split in lower half (no allowDropOn)', () => {
|
|
86
|
-
// Center of first item = 25px, point at 35px is in lower half
|
|
87
|
-
const target = delegate.getDropTargetFromPoint(container, 100, 35);
|
|
88
|
-
expect(target).toEqual({ type: 'item', key: 'item-0', dropPosition: 'after' });
|
|
89
|
-
});
|
|
90
|
-
it('returns "on" when allowDropOn is true and point is in center', () => {
|
|
91
|
-
const onDelegate = new DropDelegate({ orientation: 'vertical', allowDropOn: true });
|
|
92
|
-
const target = onDelegate.getDropTargetFromPoint(container, 100, 25);
|
|
93
|
-
expect(target).toEqual({ type: 'item', key: 'item-0', dropPosition: 'on' });
|
|
94
|
-
});
|
|
95
|
-
it('still returns "before" at top edge even with allowDropOn', () => {
|
|
96
|
-
const onDelegate = new DropDelegate({ orientation: 'vertical', allowDropOn: true });
|
|
97
|
-
const target = onDelegate.getDropTargetFromPoint(container, 100, 2);
|
|
98
|
-
expect(target).toEqual({ type: 'item', key: 'item-0', dropPosition: 'before' });
|
|
99
|
-
});
|
|
100
|
-
it('targets second item correctly', () => {
|
|
101
|
-
const target = delegate.getDropTargetFromPoint(container, 100, 65);
|
|
102
|
-
expect(target).toEqual({ type: 'item', key: 'item-1', dropPosition: 'before' });
|
|
103
|
-
});
|
|
104
|
-
it('targets last item', () => {
|
|
105
|
-
const target = delegate.getDropTargetFromPoint(container, 100, 135);
|
|
106
|
-
expect(target).toEqual({ type: 'item', key: 'item-2', dropPosition: 'after' });
|
|
107
|
-
});
|
|
108
|
-
it('returns "before" first item when above all items', () => {
|
|
109
|
-
// Point above all items (negative y wouldn't happen in practice, but testing edge)
|
|
110
|
-
const target = delegate.getDropTargetFromPoint(container, 100, -10);
|
|
111
|
-
expect(target).toEqual({ type: 'item', key: 'item-0', dropPosition: 'before' });
|
|
112
|
-
});
|
|
113
|
-
it('returns "after" last item when below all items', () => {
|
|
114
|
-
const target = delegate.getDropTargetFromPoint(container, 100, 200);
|
|
115
|
-
expect(target).toEqual({ type: 'item', key: 'item-2', dropPosition: 'after' });
|
|
116
|
-
});
|
|
117
|
-
it('getItems returns items sorted by position', () => {
|
|
118
|
-
const items = delegate.getItems(container);
|
|
119
|
-
expect(items.map((el) => el.dataset.dndKey)).toEqual(['item-0', 'item-1', 'item-2']);
|
|
120
|
-
});
|
|
121
|
-
});
|
|
122
|
-
describe('horizontal orientation', () => {
|
|
123
|
-
let delegate;
|
|
124
|
-
let container;
|
|
125
|
-
beforeEach(() => {
|
|
126
|
-
delegate = new DropDelegate({ orientation: 'horizontal' });
|
|
127
|
-
container = createContainer('horizontal', 3, 50);
|
|
128
|
-
});
|
|
129
|
-
it('returns "before" within 5px of left edge', () => {
|
|
130
|
-
const target = delegate.getDropTargetFromPoint(container, 2, 25);
|
|
131
|
-
expect(target).toEqual({ type: 'item', key: 'item-0', dropPosition: 'before' });
|
|
132
|
-
});
|
|
133
|
-
it('returns "after" within 5px of right edge', () => {
|
|
134
|
-
const target = delegate.getDropTargetFromPoint(container, 48, 25);
|
|
135
|
-
expect(target).toEqual({ type: 'item', key: 'item-0', dropPosition: 'after' });
|
|
136
|
-
});
|
|
137
|
-
it('returns midpoint split for center', () => {
|
|
138
|
-
const target = delegate.getDropTargetFromPoint(container, 15, 25);
|
|
139
|
-
expect(target).toEqual({ type: 'item', key: 'item-0', dropPosition: 'before' });
|
|
140
|
-
});
|
|
141
|
-
it('returns "after" last item when past all items', () => {
|
|
142
|
-
const target = delegate.getDropTargetFromPoint(container, 200, 25);
|
|
143
|
-
expect(target).toEqual({ type: 'item', key: 'item-2', dropPosition: 'after' });
|
|
144
|
-
});
|
|
145
|
-
});
|
|
146
|
-
describe('rTL direction', () => {
|
|
147
|
-
let delegate;
|
|
148
|
-
let container;
|
|
149
|
-
beforeEach(() => {
|
|
150
|
-
delegate = new DropDelegate({ orientation: 'horizontal', direction: 'rtl' });
|
|
151
|
-
container = createContainer('horizontal', 3, 50);
|
|
152
|
-
});
|
|
153
|
-
it('returns "before" at right edge in RTL', () => {
|
|
154
|
-
const target = delegate.getDropTargetFromPoint(container, 48, 25);
|
|
155
|
-
expect(target).toEqual({ type: 'item', key: 'item-0', dropPosition: 'before' });
|
|
156
|
-
});
|
|
157
|
-
it('returns "after" at left edge in RTL', () => {
|
|
158
|
-
const target = delegate.getDropTargetFromPoint(container, 2, 25);
|
|
159
|
-
expect(target).toEqual({ type: 'item', key: 'item-0', dropPosition: 'after' });
|
|
160
|
-
});
|
|
161
|
-
});
|
|
162
|
-
describe('getDropTargetFromIndex', () => {
|
|
163
|
-
it('returns target for valid index', () => {
|
|
164
|
-
const delegate = new DropDelegate({ orientation: 'vertical' });
|
|
165
|
-
const container = createContainer('vertical', 3, 50);
|
|
166
|
-
const target = delegate.getDropTargetFromIndex(container, 1, 'before');
|
|
167
|
-
expect(target).toEqual({ type: 'item', key: 'item-1', dropPosition: 'before' });
|
|
168
|
-
});
|
|
169
|
-
it('clamps index to valid range', () => {
|
|
170
|
-
const delegate = new DropDelegate({ orientation: 'vertical' });
|
|
171
|
-
const container = createContainer('vertical', 3, 50);
|
|
172
|
-
const target = delegate.getDropTargetFromIndex(container, 10, 'after');
|
|
173
|
-
expect(target).toEqual({ type: 'item', key: 'item-2', dropPosition: 'after' });
|
|
174
|
-
});
|
|
175
|
-
it('returns root for empty container', () => {
|
|
176
|
-
const delegate = new DropDelegate({ orientation: 'vertical' });
|
|
177
|
-
const empty = document.createElement('div');
|
|
178
|
-
const target = delegate.getDropTargetFromIndex(empty, 0, 'before');
|
|
179
|
-
expect(target).toEqual({ type: 'root' });
|
|
180
|
-
});
|
|
181
|
-
});
|
|
182
|
-
describe('getIndicatorRect', () => {
|
|
183
|
-
it('returns horizontal line for vertical list "before"', () => {
|
|
184
|
-
const delegate = new DropDelegate({ orientation: 'vertical' });
|
|
185
|
-
const container = createContainer('vertical', 3, 50);
|
|
186
|
-
const rect = delegate.getIndicatorRect(container, {
|
|
187
|
-
type: 'item',
|
|
188
|
-
key: 'item-1',
|
|
189
|
-
dropPosition: 'before',
|
|
190
|
-
});
|
|
191
|
-
expect(rect).not.toBeNull();
|
|
192
|
-
expect(rect.y).toBe(50); // top of item-1
|
|
193
|
-
expect(rect.height).toBe(2);
|
|
194
|
-
});
|
|
195
|
-
it('returns horizontal line for vertical list "after"', () => {
|
|
196
|
-
const delegate = new DropDelegate({ orientation: 'vertical' });
|
|
197
|
-
const container = createContainer('vertical', 3, 50);
|
|
198
|
-
const rect = delegate.getIndicatorRect(container, {
|
|
199
|
-
type: 'item',
|
|
200
|
-
key: 'item-1',
|
|
201
|
-
dropPosition: 'after',
|
|
202
|
-
});
|
|
203
|
-
expect(rect).not.toBeNull();
|
|
204
|
-
expect(rect.y).toBe(100); // bottom of item-1
|
|
205
|
-
});
|
|
206
|
-
it('returns null for root target', () => {
|
|
207
|
-
const delegate = new DropDelegate({ orientation: 'vertical' });
|
|
208
|
-
const container = createContainer('vertical', 3, 50);
|
|
209
|
-
const rect = delegate.getIndicatorRect(container, { type: 'root' });
|
|
210
|
-
expect(rect).toBeNull();
|
|
211
|
-
});
|
|
212
|
-
it('returns null for unknown key', () => {
|
|
213
|
-
const delegate = new DropDelegate({ orientation: 'vertical' });
|
|
214
|
-
const container = createContainer('vertical', 3, 50);
|
|
215
|
-
const rect = delegate.getIndicatorRect(container, {
|
|
216
|
-
type: 'item',
|
|
217
|
-
key: 'nonexistent',
|
|
218
|
-
dropPosition: 'before',
|
|
219
|
-
});
|
|
220
|
-
expect(rect).toBeNull();
|
|
221
|
-
});
|
|
222
|
-
});
|
|
223
|
-
});
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { DROP_OPERATION } from '../types.js';
|
|
3
|
-
describe('dROP_OPERATION', () => {
|
|
4
|
-
it('has cancel as 0', () => {
|
|
5
|
-
expect(DROP_OPERATION.cancel).toBe(0);
|
|
6
|
-
});
|
|
7
|
-
it('has move as 1', () => {
|
|
8
|
-
expect(DROP_OPERATION.move).toBe(1);
|
|
9
|
-
});
|
|
10
|
-
it('has copy as 2', () => {
|
|
11
|
-
expect(DROP_OPERATION.copy).toBe(2);
|
|
12
|
-
});
|
|
13
|
-
it('has link as 4', () => {
|
|
14
|
-
expect(DROP_OPERATION.link).toBe(4);
|
|
15
|
-
});
|
|
16
|
-
it('has all as 7 (move | copy | link)', () => {
|
|
17
|
-
expect(DROP_OPERATION.all).toBe(7);
|
|
18
|
-
expect(DROP_OPERATION.all).toBe(DROP_OPERATION.move | DROP_OPERATION.copy | DROP_OPERATION.link);
|
|
19
|
-
});
|
|
20
|
-
});
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
-
import { EscapeLayerState, resetEscapeLayerStack } from '../escape-layer.svelte.js';
|
|
3
|
-
describe('escapeLayer', () => {
|
|
4
|
-
afterEach(() => {
|
|
5
|
-
resetEscapeLayerStack();
|
|
6
|
-
});
|
|
7
|
-
it('calls onEscapeKeydown when Escape is pressed', () => {
|
|
8
|
-
const onEscape = vi.fn();
|
|
9
|
-
const layer = new EscapeLayerState({ enabled: true, onEscapeKeydown: onEscape });
|
|
10
|
-
layer.mount();
|
|
11
|
-
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
|
|
12
|
-
expect(onEscape).toHaveBeenCalledOnce();
|
|
13
|
-
layer.unmount();
|
|
14
|
-
});
|
|
15
|
-
it('ignores non-Escape keys', () => {
|
|
16
|
-
const onEscape = vi.fn();
|
|
17
|
-
const layer = new EscapeLayerState({ enabled: true, onEscapeKeydown: onEscape });
|
|
18
|
-
layer.mount();
|
|
19
|
-
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }));
|
|
20
|
-
expect(onEscape).not.toHaveBeenCalled();
|
|
21
|
-
layer.unmount();
|
|
22
|
-
});
|
|
23
|
-
it('only the topmost layer handles Escape (stack)', () => {
|
|
24
|
-
const onEscape1 = vi.fn();
|
|
25
|
-
const onEscape2 = vi.fn();
|
|
26
|
-
const layer1 = new EscapeLayerState({ enabled: true, onEscapeKeydown: onEscape1 });
|
|
27
|
-
const layer2 = new EscapeLayerState({ enabled: true, onEscapeKeydown: onEscape2 });
|
|
28
|
-
layer1.mount();
|
|
29
|
-
layer2.mount();
|
|
30
|
-
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
|
|
31
|
-
expect(onEscape1).not.toHaveBeenCalled();
|
|
32
|
-
expect(onEscape2).toHaveBeenCalledOnce();
|
|
33
|
-
layer2.unmount();
|
|
34
|
-
layer1.unmount();
|
|
35
|
-
});
|
|
36
|
-
it('respects ignore behavior', () => {
|
|
37
|
-
const onEscape = vi.fn();
|
|
38
|
-
const layer = new EscapeLayerState({
|
|
39
|
-
enabled: true,
|
|
40
|
-
onEscapeKeydown: onEscape,
|
|
41
|
-
behavior: 'ignore',
|
|
42
|
-
});
|
|
43
|
-
layer.mount();
|
|
44
|
-
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
|
|
45
|
-
expect(onEscape).not.toHaveBeenCalled();
|
|
46
|
-
layer.unmount();
|
|
47
|
-
});
|
|
48
|
-
it('defer-otherwise-close falls through to bottom', () => {
|
|
49
|
-
const onEscape1 = vi.fn();
|
|
50
|
-
const onEscape2 = vi.fn();
|
|
51
|
-
const layer1 = new EscapeLayerState({
|
|
52
|
-
enabled: true,
|
|
53
|
-
onEscapeKeydown: onEscape1,
|
|
54
|
-
behavior: 'defer-otherwise-close',
|
|
55
|
-
});
|
|
56
|
-
const layer2 = new EscapeLayerState({
|
|
57
|
-
enabled: true,
|
|
58
|
-
onEscapeKeydown: onEscape2,
|
|
59
|
-
behavior: 'defer-otherwise-close',
|
|
60
|
-
});
|
|
61
|
-
layer1.mount();
|
|
62
|
-
layer2.mount();
|
|
63
|
-
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
|
|
64
|
-
expect(onEscape1).toHaveBeenCalledOnce();
|
|
65
|
-
expect(onEscape2).not.toHaveBeenCalled();
|
|
66
|
-
layer2.unmount();
|
|
67
|
-
layer1.unmount();
|
|
68
|
-
});
|
|
69
|
-
it('does not mount when enabled is false', () => {
|
|
70
|
-
const onEscape = vi.fn();
|
|
71
|
-
const layer = new EscapeLayerState({ enabled: false, onEscapeKeydown: onEscape });
|
|
72
|
-
layer.mount();
|
|
73
|
-
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
|
|
74
|
-
expect(onEscape).not.toHaveBeenCalled();
|
|
75
|
-
layer.unmount();
|
|
76
|
-
});
|
|
77
|
-
it('cleans up when all layers unmount', () => {
|
|
78
|
-
const layer = new EscapeLayerState({ enabled: true, onEscapeKeydown: vi.fn() });
|
|
79
|
-
layer.mount();
|
|
80
|
-
layer.unmount();
|
|
81
|
-
// Should not throw after cleanup
|
|
82
|
-
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
|
|
83
|
-
});
|
|
84
|
-
it('resolves behavior at keydown time (getter can flip between keypresses)', () => {
|
|
85
|
-
// A layer may pass `behavior` as a getter and decide per keypress — the
|
|
86
|
-
// submenu layer closes itself only when focus lives inside its content,
|
|
87
|
-
// and defers to the parent menu layer otherwise.
|
|
88
|
-
let topBehavior = 'close';
|
|
89
|
-
const onBottom = vi.fn();
|
|
90
|
-
const onTop = vi.fn();
|
|
91
|
-
const bottom = new EscapeLayerState({ enabled: true, onEscapeKeydown: onBottom });
|
|
92
|
-
const top = new EscapeLayerState({
|
|
93
|
-
enabled: true,
|
|
94
|
-
get behavior() {
|
|
95
|
-
return topBehavior;
|
|
96
|
-
},
|
|
97
|
-
onEscapeKeydown: onTop,
|
|
98
|
-
});
|
|
99
|
-
bottom.mount();
|
|
100
|
-
top.mount();
|
|
101
|
-
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
|
|
102
|
-
expect(onTop).toHaveBeenCalledOnce();
|
|
103
|
-
expect(onBottom).not.toHaveBeenCalled();
|
|
104
|
-
// Same mounted layer, new answer from the getter: the keypress falls
|
|
105
|
-
// through to the bottom layer in the SAME stack state.
|
|
106
|
-
topBehavior = 'defer-otherwise-close';
|
|
107
|
-
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
|
|
108
|
-
expect(onTop).toHaveBeenCalledOnce();
|
|
109
|
-
expect(onBottom).toHaveBeenCalledOnce();
|
|
110
|
-
top.unmount();
|
|
111
|
-
bottom.unmount();
|
|
112
|
-
});
|
|
113
|
-
});
|