@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,51 +0,0 @@
1
- import { flushSync, mount, unmount } from 'svelte';
2
- import { afterEach, describe, expect, it } from 'vitest';
3
- import AlertDialogTest from './AlertDialogTest.svelte';
4
- describe('alert-dialog integration', () => {
5
- let target;
6
- let instance;
7
- function setup(props = {}) {
8
- target = document.createElement('div');
9
- document.body.appendChild(target);
10
- instance = mount(AlertDialogTest, { 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('full flow: trigger → confirm → closes', () => {
20
- setup();
21
- target.querySelector('.sp-alert-dialog-trigger').click();
22
- flushSync();
23
- expect(target.querySelector('[role="alertdialog"]')).toBeTruthy();
24
- target.querySelector('.sp-alert-dialog-action').click();
25
- flushSync();
26
- expect(target.querySelector('[role="alertdialog"]')).toBeNull();
27
- });
28
- it('full flow: trigger → cancel → closes', () => {
29
- setup();
30
- target.querySelector('.sp-alert-dialog-trigger').click();
31
- flushSync();
32
- target.querySelector('.sp-alert-dialog-cancel').click();
33
- flushSync();
34
- expect(target.querySelector('[role="alertdialog"]')).toBeNull();
35
- });
36
- it('full flow: trigger → escape → closes', () => {
37
- setup();
38
- target.querySelector('.sp-alert-dialog-trigger').click();
39
- flushSync();
40
- flushSync();
41
- document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true, cancelable: true }));
42
- flushSync();
43
- expect(target.querySelector('[role="alertdialog"]')).toBeNull();
44
- });
45
- it('overlay click does NOT close', () => {
46
- setup({ open: true });
47
- target.querySelector('.sp-alert-dialog-overlay').click();
48
- flushSync();
49
- expect(target.querySelector('[role="alertdialog"]')).toBeTruthy();
50
- });
51
- });
@@ -1,113 +0,0 @@
1
- import { flushSync, mount, unmount } from 'svelte';
2
- import { afterEach, describe, expect, it } from 'vitest';
3
- import AlertDialogTest from './AlertDialogTest.svelte';
4
- describe('alert-dialog', () => {
5
- let target;
6
- let instance;
7
- function setup(props = {}) {
8
- target = document.createElement('div');
9
- document.body.appendChild(target);
10
- instance = mount(AlertDialogTest, { target, props: { portalTo: target, ...props } });
11
- flushSync();
12
- return target;
13
- }
14
- afterEach(() => {
15
- if (instance)
16
- unmount(instance);
17
- target?.remove();
18
- });
19
- // --- Basic rendering ---
20
- it('renders root with data-state="closed"', () => {
21
- setup();
22
- const root = target.querySelector('.sp-alert-dialog-root');
23
- expect(root?.getAttribute('data-state')).toBe('closed');
24
- });
25
- it('trigger opens alert dialog', () => {
26
- setup();
27
- const trigger = target.querySelector('.sp-alert-dialog-trigger');
28
- trigger.click();
29
- flushSync();
30
- expect(target.querySelector('[role="alertdialog"]')).toBeTruthy();
31
- });
32
- // --- Content ARIA ---
33
- it('content has role="alertdialog"', () => {
34
- setup({ open: true });
35
- const content = target.querySelector('[role="alertdialog"]');
36
- expect(content).toBeTruthy();
37
- });
38
- it('content has aria-modal="true"', () => {
39
- setup({ open: true });
40
- const content = target.querySelector('[role="alertdialog"]');
41
- expect(content?.getAttribute('aria-modal')).toBe('true');
42
- });
43
- it('content has aria-labelledby pointing to title', () => {
44
- setup({ open: true });
45
- const content = target.querySelector('[role="alertdialog"]');
46
- const title = target.querySelector('.sp-alert-dialog-title');
47
- expect(content?.getAttribute('aria-labelledby')).toBe(title?.id);
48
- });
49
- it('content has aria-describedby pointing to description', () => {
50
- setup({ open: true });
51
- const content = target.querySelector('[role="alertdialog"]');
52
- const desc = target.querySelector('.sp-alert-dialog-description');
53
- expect(content?.getAttribute('aria-describedby')).toBe(desc?.id);
54
- });
55
- // --- Trigger ARIA ---
56
- it('trigger has aria-haspopup="dialog"', () => {
57
- setup();
58
- const trigger = target.querySelector('.sp-alert-dialog-trigger');
59
- expect(trigger?.getAttribute('aria-haspopup')).toBe('dialog');
60
- });
61
- it('trigger has aria-expanded matching open state', () => {
62
- setup();
63
- const trigger = target.querySelector('.sp-alert-dialog-trigger');
64
- expect(trigger.getAttribute('aria-expanded')).toBe('false');
65
- trigger.click();
66
- flushSync();
67
- expect(trigger.getAttribute('aria-expanded')).toBe('true');
68
- });
69
- // --- No outside click dismiss ---
70
- it('overlay does NOT close on click (unlike Dialog)', () => {
71
- setup({ open: true });
72
- const overlay = target.querySelector('.sp-alert-dialog-overlay');
73
- expect(overlay).toBeTruthy();
74
- // AlertDialog overlay does NOT have onclick close
75
- // The dialog should still be open
76
- expect(target.querySelector('[role="alertdialog"]')).toBeTruthy();
77
- });
78
- // --- Action and Cancel buttons ---
79
- it('action button closes the dialog', () => {
80
- setup({ open: true });
81
- const action = target.querySelector('.sp-alert-dialog-action');
82
- action.click();
83
- flushSync();
84
- expect(target.querySelector('[role="alertdialog"]')).toBeNull();
85
- });
86
- it('cancel button closes the dialog', () => {
87
- setup({ open: true });
88
- const cancel = target.querySelector('.sp-alert-dialog-cancel');
89
- cancel.click();
90
- flushSync();
91
- expect(target.querySelector('[role="alertdialog"]')).toBeNull();
92
- });
93
- // --- Escape key ---
94
- it('escape key closes the alert dialog', () => {
95
- setup({ open: true });
96
- flushSync();
97
- expect(target.querySelector('[role="alertdialog"]')).toBeTruthy();
98
- document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true, cancelable: true }));
99
- flushSync();
100
- expect(target.querySelector('[role="alertdialog"]')).toBeNull();
101
- });
102
- // --- Content visibility ---
103
- it('content not rendered when closed', () => {
104
- setup({ open: false });
105
- expect(target.querySelector('[role="alertdialog"]')).toBeNull();
106
- });
107
- // --- Title ---
108
- it('title renders as h2 by default', () => {
109
- setup({ open: true });
110
- const title = target.querySelector('.sp-alert-dialog-title');
111
- expect(title?.tagName).toBe('H2');
112
- });
113
- });
@@ -1,30 +0,0 @@
1
- import { mount, unmount } from 'svelte';
2
- import { afterEach, describe, expect, it } from 'vitest';
3
- import AppBar from '../app-bar.svelte';
4
- describe('app-bar', () => {
5
- let target;
6
- let instance;
7
- function setup(props = {}) {
8
- target = document.createElement('div');
9
- document.body.appendChild(target);
10
- instance = mount(AppBar, { target, props });
11
- return target;
12
- }
13
- afterEach(() => {
14
- if (instance)
15
- unmount(instance);
16
- target?.remove();
17
- });
18
- it('renders header element', () => {
19
- setup();
20
- expect(target.querySelector('header')).toBeTruthy();
21
- });
22
- it('applies size class', () => {
23
- setup({ size: 'small', title: 'Test' });
24
- expect(target.querySelector('.sp-app-bar.small')).toBeTruthy();
25
- });
26
- it('shows title', () => {
27
- setup({ title: 'Test' });
28
- expect(target.querySelector('.sp-app-bar-title')?.textContent).toBe('Test');
29
- });
30
- });
@@ -1,22 +0,0 @@
1
- import { mount, unmount } from 'svelte';
2
- import { afterEach, describe, expect, it } from 'vitest';
3
- import AspectRatio from '../aspect-ratio.svelte';
4
- describe('aspect-ratio', () => {
5
- let target;
6
- let instance;
7
- function setup(props = {}) {
8
- target = document.createElement('div');
9
- document.body.appendChild(target);
10
- instance = mount(AspectRatio, { target, props });
11
- return target;
12
- }
13
- afterEach(() => {
14
- if (instance)
15
- unmount(instance);
16
- target?.remove();
17
- });
18
- it('renders container', () => {
19
- setup();
20
- expect(target.querySelector('.sp-aspect-ratio')).toBeTruthy();
21
- });
22
- });
@@ -1,26 +0,0 @@
1
- import { mount, unmount } from 'svelte';
2
- import { afterEach, describe, expect, it } from 'vitest';
3
- import Avatar from '../avatar.svelte';
4
- describe('avatar', () => {
5
- let target;
6
- let instance;
7
- function setup(props = {}) {
8
- target = document.createElement('div');
9
- document.body.appendChild(target);
10
- instance = mount(Avatar, { target, props });
11
- return target;
12
- }
13
- afterEach(() => {
14
- if (instance)
15
- unmount(instance);
16
- target?.remove();
17
- });
18
- it('renders avatar', () => {
19
- setup();
20
- expect(target.querySelector('.sp-avatar')).toBeTruthy();
21
- });
22
- it('applies size class', () => {
23
- setup({ size: 'lg' });
24
- expect(target.querySelector('.sp-avatar')?.className.includes('lg')).toBeTruthy();
25
- });
26
- });
@@ -1,30 +0,0 @@
1
- import { mount, unmount } from 'svelte';
2
- import { afterEach, describe, expect, it } from 'vitest';
3
- import Badge from '../badge.svelte';
4
- describe('badge', () => {
5
- let target;
6
- let instance;
7
- function setup(props = {}) {
8
- target = document.createElement('div');
9
- document.body.appendChild(target);
10
- instance = mount(Badge, { target, props });
11
- return target;
12
- }
13
- afterEach(() => {
14
- if (instance)
15
- unmount(instance);
16
- target?.remove();
17
- });
18
- it('renders span', () => {
19
- setup();
20
- expect(target.querySelector('.sp-badge')).toBeTruthy();
21
- });
22
- it('applies variant', () => {
23
- setup({ variant: 'outlined' });
24
- expect(target.querySelector('.sp-badge')?.className.includes('outlined')).toBeTruthy();
25
- });
26
- it('applies color', () => {
27
- setup({ color: 'success' });
28
- expect(target.querySelector('.sp-badge')?.className.includes('success')).toBeTruthy();
29
- });
30
- });
@@ -1,22 +0,0 @@
1
- <script lang="ts">
2
- import BottomSheetRoot from '../components/bottom-sheet-root.svelte'
3
-
4
- let {
5
- open = $bindable(false),
6
- mode = 'modal' as const,
7
- portalTo = undefined,
8
- onOpenChange = undefined,
9
- }: {
10
- open?: boolean
11
- mode?: 'standard' | 'modal'
12
- portalTo?: HTMLElement | string
13
- onOpenChange?: (open: boolean) => void
14
- } = $props()
15
- </script>
16
-
17
- <button type="button" data-testid="opener" onclick={() => (open = true)}>open</button>
18
- <BottomSheetRoot bind:open {mode} {portalTo} {onOpenChange}>
19
- <p data-testid="sheet-content">hello</p>
20
- <button type="button" data-testid="inside">inside</button>
21
- </BottomSheetRoot>
22
- <button type="button" data-testid="outside">outside</button>
@@ -1,83 +0,0 @@
1
- import { flushSync, mount, unmount } from 'svelte';
2
- import { afterEach, describe, expect, it } from 'vitest';
3
- import BottomSheetTest from './BottomSheetTest.svelte';
4
- // jsdom does not define PointerEvent — polyfill it for tests
5
- if (typeof globalThis.PointerEvent === 'undefined') {
6
- // @ts-expect-error — minimal polyfill for testing
7
- globalThis.PointerEvent = class PointerEvent extends MouseEvent {
8
- constructor(type, init) {
9
- super(type, init);
10
- }
11
- };
12
- }
13
- describe('bottom-sheet', () => {
14
- let target;
15
- let instance;
16
- function setup(props = {}) {
17
- target = document.createElement('div');
18
- document.body.appendChild(target);
19
- instance = mount(BottomSheetTest, { target, props: { portalTo: target, ...props } });
20
- flushSync();
21
- return target;
22
- }
23
- afterEach(() => {
24
- if (instance)
25
- unmount(instance);
26
- target?.remove();
27
- });
28
- it('stays closed by default and does not render content', () => {
29
- setup();
30
- expect(target.querySelector('[data-testid="sheet-content"]')).toBeNull();
31
- });
32
- it('renders content when opened', () => {
33
- setup({ open: true, mode: 'modal' });
34
- flushSync();
35
- expect(target.querySelector('[data-testid="sheet-content"]')).toBeTruthy();
36
- });
37
- it('closes on Escape key', () => {
38
- setup({ open: true, mode: 'modal' });
39
- flushSync();
40
- document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
41
- flushSync();
42
- expect(target.querySelector('[data-testid="sheet-content"]')).toBeNull();
43
- });
44
- it('closes on outside pointerdown in modal mode', () => {
45
- setup({ open: true, mode: 'modal' });
46
- flushSync();
47
- // DismissibleLayerState listens on document — dispatch outside the sheet element
48
- document.dispatchEvent(new PointerEvent('pointerdown', { bubbles: true, clientX: 9999, clientY: 9999 }));
49
- flushSync();
50
- expect(target.querySelector('[data-testid="sheet-content"]')).toBeNull();
51
- });
52
- it('keeps focus on inside element when focused (modal)', () => {
53
- setup({ open: true, mode: 'modal' });
54
- flushSync();
55
- const inside = target.querySelector('[data-testid="inside"]');
56
- inside.focus();
57
- expect(document.activeElement).toBe(inside);
58
- });
59
- it('calls onOpenChange(false) when Escape is pressed', () => {
60
- instance = null;
61
- const calls = [];
62
- const localTarget = document.createElement('div');
63
- document.body.appendChild(localTarget);
64
- const localInstance = mount(BottomSheetTest, {
65
- target: localTarget,
66
- props: {
67
- open: true,
68
- portalTo: localTarget,
69
- onOpenChange: (open) => calls.push(open),
70
- },
71
- });
72
- flushSync();
73
- try {
74
- document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape' }));
75
- flushSync();
76
- expect(calls).toEqual([false]);
77
- }
78
- finally {
79
- unmount(localInstance);
80
- localTarget.remove();
81
- }
82
- });
83
- });
@@ -1,63 +0,0 @@
1
- import { mount, unmount } from 'svelte';
2
- import { afterEach, describe, expect, it } from 'vitest';
3
- import Button from '../button.svelte';
4
- describe('button', () => {
5
- let target;
6
- let instance;
7
- function setup(props = {}) {
8
- target = document.createElement('div');
9
- document.body.appendChild(target);
10
- instance = mount(Button, { target, props });
11
- return target;
12
- }
13
- afterEach(() => {
14
- if (instance)
15
- unmount(instance);
16
- target?.remove();
17
- });
18
- it('renders a button element by default', () => {
19
- setup();
20
- expect(target.querySelector('button')).toBeTruthy();
21
- });
22
- it('applies variant class', () => {
23
- setup({ variant: 'outlined' });
24
- const btn = target.querySelector('button');
25
- expect(btn.className).toContain('outlined');
26
- });
27
- it('applies color class', () => {
28
- setup({ color: 'secondary' });
29
- const btn = target.querySelector('button');
30
- expect(btn.className).toContain('secondary');
31
- });
32
- it('applies size class', () => {
33
- setup({ size: 'lg' });
34
- const btn = target.querySelector('button');
35
- expect(btn.className).toContain('lg');
36
- });
37
- it('renders as anchor when href is provided', () => {
38
- setup({ href: '/test' });
39
- const link = target.querySelector('a');
40
- expect(link).toBeTruthy();
41
- expect(link?.getAttribute('href')).toBe('/test');
42
- });
43
- it('sets disabled attribute', () => {
44
- setup({ disabled: true });
45
- const btn = target.querySelector('button');
46
- expect(btn.hasAttribute('disabled')).toBe(true);
47
- });
48
- it('sets aria-disabled on link buttons when disabled', () => {
49
- setup({ href: '/test', disabled: true });
50
- const link = target.querySelector('a');
51
- expect(link.getAttribute('aria-disabled')).toBe('true');
52
- });
53
- it('applies custom class', () => {
54
- setup({ class: 'my-custom' });
55
- const btn = target.querySelector('button');
56
- expect(btn.className).toContain('my-custom');
57
- });
58
- it('has data-variant attribute', () => {
59
- setup({ variant: 'tonal' });
60
- const btn = target.querySelector('button');
61
- expect(btn.getAttribute('data-variant')).toBe('tonal');
62
- });
63
- });
@@ -1,56 +0,0 @@
1
- <script lang="ts">
2
- import type { DateMatcher, DateValue } from '../../../internal/date-time/types.js'
3
- import * as Calendar from '../index.js'
4
-
5
- let {
6
- value = $bindable<DateValue | undefined>(undefined),
7
- placeholder = $bindable<DateValue | undefined>(undefined),
8
- minValue = undefined,
9
- maxValue = undefined,
10
- disabled = false,
11
- readonly: isReadonly = false,
12
- locale = 'en-US',
13
- weekStartsOn = 1 as 0 | 1 | 2 | 3 | 4 | 5 | 6,
14
- numberOfMonths = 1,
15
- preventDeselect = false,
16
- isDateDisabled = undefined,
17
- }: {
18
- value?: DateValue
19
- placeholder?: DateValue
20
- minValue?: DateValue
21
- maxValue?: DateValue
22
- disabled?: boolean
23
- readonly?: boolean
24
- locale?: string
25
- weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6
26
- numberOfMonths?: number
27
- preventDeselect?: boolean
28
- isDateDisabled?: DateMatcher
29
- } = $props()
30
-
31
- // Array of month indices for multi-month rendering
32
- const monthIndices = $derived(Array.from({ length: numberOfMonths }, (_, i) => i))
33
- </script>
34
-
35
- <Calendar.Root
36
- bind:value
37
- bind:placeholder
38
- {minValue}
39
- {maxValue}
40
- {disabled}
41
- readonly={isReadonly}
42
- {locale}
43
- {weekStartsOn}
44
- {numberOfMonths}
45
- {preventDeselect}
46
- {isDateDisabled}
47
- >
48
- <Calendar.Header>
49
- <Calendar.PrevButton>‹</Calendar.PrevButton>
50
- <Calendar.Heading />
51
- <Calendar.NextButton>›</Calendar.NextButton>
52
- </Calendar.Header>
53
- {#each monthIndices as monthIndex (monthIndex)}
54
- <Calendar.Grid {monthIndex} />
55
- {/each}
56
- </Calendar.Root>