@classic-homes/theme-svelte 1.22.0 → 1.22.2

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 (110) hide show
  1. package/dist/lib/components/Alert.svelte +8 -10
  2. package/dist/lib/components/Combobox.svelte +2 -2
  3. package/dist/lib/components/DataPanel.svelte +19 -5
  4. package/dist/lib/components/DataTable.svelte +15 -6
  5. package/dist/lib/components/DataTable.svelte.d.ts +1 -1
  6. package/dist/lib/components/DateTimePicker.svelte +31 -34
  7. package/dist/lib/components/DropdownMenu.svelte +52 -30
  8. package/dist/lib/components/DropdownMenu.svelte.d.ts +5 -0
  9. package/dist/lib/components/FileUpload.svelte +5 -19
  10. package/dist/lib/components/HeaderSearch.svelte +18 -10
  11. package/dist/lib/components/MultiSelect.svelte +2 -2
  12. package/dist/lib/components/NumberInput.svelte +15 -2
  13. package/dist/lib/components/Select.svelte +19 -5
  14. package/dist/lib/components/Select.svelte.d.ts +4 -0
  15. package/dist/lib/components/Signature.svelte +15 -4
  16. package/dist/lib/components/Signature.svelte.d.ts +1 -1
  17. package/dist/lib/components/Skeleton.svelte.d.ts +1 -1
  18. package/dist/lib/components/Slider.svelte +8 -6
  19. package/dist/lib/components/Tabs.svelte +10 -12
  20. package/dist/lib/components/Toast.svelte +12 -12
  21. package/dist/lib/components/data-table/DataTableColumnVisibility.svelte +24 -26
  22. package/dist/lib/components/data-table/DataTableEditableCell.svelte +31 -18
  23. package/dist/lib/components/data-table/DataTableEditableCell.svelte.d.ts +0 -7
  24. package/dist/lib/components/data-table/DataTablePagination.svelte +5 -1
  25. package/dist/lib/components/data-table/DataTableVirtual.svelte +4 -7
  26. package/dist/lib/components/data-table/DataTableVirtual.svelte.d.ts +3 -0
  27. package/dist/lib/components/data-table/createDataTable.svelte.d.ts +6 -1
  28. package/dist/lib/components/data-table/createDataTable.svelte.js +22 -9
  29. package/dist/lib/components/layout/AppShell.svelte +1 -1
  30. package/dist/lib/components/layout/DashboardLayout.svelte +15 -6
  31. package/dist/lib/components/layout/Footer.svelte +6 -6
  32. package/dist/lib/components/layout/FormPageLayout.svelte +4 -3
  33. package/dist/lib/components/layout/Sidebar.svelte +53 -21
  34. package/dist/lib/components/media/Image.svelte.d.ts +1 -1
  35. package/dist/lib/components/media/Lightbox.svelte +13 -9
  36. package/dist/lib/components/media/MediaCarousel.svelte +5 -0
  37. package/dist/lib/components/media/MediaGrid.svelte +4 -1
  38. package/dist/lib/components/notifications/NotificationDialog.svelte +8 -5
  39. package/dist/lib/components/notifications/NotificationItem.svelte +16 -6
  40. package/dist/lib/components/studio/InsertPalette.svelte +4 -1
  41. package/dist/lib/components/studio/StudioCanvas.svelte +23 -2
  42. package/dist/lib/components/studio/StudioCanvas.svelte.d.ts +5 -1
  43. package/dist/lib/composables/useAsync.svelte.d.ts +1 -1
  44. package/dist/lib/composables/useAsync.svelte.js +33 -14
  45. package/dist/lib/composables/useFocusTrap.svelte.js +9 -2
  46. package/dist/lib/composables/useForm.svelte.js +19 -7
  47. package/dist/lib/composables/usePersistedForm.svelte.js +37 -10
  48. package/dist/lib/notices/sanitize.js +10 -3
  49. package/dist/lib/notices/store.d.ts +3 -3
  50. package/dist/lib/notices/store.js +14 -2
  51. package/dist/lib/notices/types.d.ts +8 -8
  52. package/dist/lib/notices/types.js +5 -1
  53. package/dist/lib/stores/sidebar.svelte.d.ts +12 -0
  54. package/dist/lib/stores/sidebar.svelte.js +76 -26
  55. package/dist/lib/stores/toast.svelte.js +12 -1
  56. package/dist/lib/utils/date.d.ts +3 -1
  57. package/dist/lib/utils/date.js +54 -34
  58. package/dist/lib/utils/form.d.ts +2 -1
  59. package/dist/lib/utils/form.js +3 -2
  60. package/dist/lib/utils/media.js +4 -3
  61. package/dist/lib/utils/url.d.ts +10 -0
  62. package/dist/lib/utils/url.js +21 -0
  63. package/dist/lib/utils.js +14 -1
  64. package/package.json +5 -4
  65. package/dist/__tests__/FileUpload.test.js +0 -45
  66. package/dist/__tests__/a11y/Alert.a11y.test.js +0 -84
  67. package/dist/__tests__/a11y/AlertDialog.a11y.test.js +0 -126
  68. package/dist/__tests__/a11y/Button.a11y.test.js +0 -66
  69. package/dist/__tests__/a11y/Card.a11y.test.js +0 -77
  70. package/dist/__tests__/a11y/Combobox.a11y.test.js +0 -209
  71. package/dist/__tests__/a11y/Dialog.a11y.test.js +0 -103
  72. package/dist/__tests__/a11y/DropdownMenu.a11y.test.js +0 -132
  73. package/dist/__tests__/a11y/FileUpload.a11y.test.js +0 -158
  74. package/dist/__tests__/a11y/FilterToolbar.a11y.test.js +0 -62
  75. package/dist/__tests__/a11y/Icon.a11y.test.js +0 -119
  76. package/dist/__tests__/a11y/Input.a11y.test.js +0 -96
  77. package/dist/__tests__/a11y/LiveRegion.a11y.test.js +0 -102
  78. package/dist/__tests__/a11y/Media.a11y.test.js +0 -145
  79. package/dist/__tests__/a11y/PublicLayout.a11y.test.js +0 -139
  80. package/dist/__tests__/a11y/SegmentedControl.a11y.test.js +0 -50
  81. package/dist/__tests__/a11y/Switch.a11y.test.js +0 -95
  82. package/dist/__tests__/a11y/Tabs.a11y.test.js +0 -116
  83. package/dist/__tests__/a11y/Textarea.a11y.test.js +0 -111
  84. package/dist/__tests__/a11y/Toolbar.a11y.test.js +0 -31
  85. package/dist/__tests__/a11y/ViewToggle.a11y.test.js +0 -40
  86. package/dist/__tests__/action-header.test.js +0 -150
  87. package/dist/__tests__/alert-dialog-dismiss.test.js +0 -54
  88. package/dist/__tests__/code-field.test.js +0 -65
  89. package/dist/__tests__/control-text-color.test.js +0 -29
  90. package/dist/__tests__/data-panel-card-gestures.test.js +0 -138
  91. package/dist/__tests__/data-panel-viewport.test.js +0 -45
  92. package/dist/__tests__/dropdown-trigger.test.js +0 -39
  93. package/dist/__tests__/header-search.test.js +0 -90
  94. package/dist/__tests__/media-components.test.js +0 -206
  95. package/dist/__tests__/media-hls.test.js +0 -273
  96. package/dist/__tests__/media-matterport.test.js +0 -296
  97. package/dist/__tests__/media-players.test.js +0 -244
  98. package/dist/__tests__/media-scrubber.test.js +0 -44
  99. package/dist/__tests__/media-utils.test.js +0 -427
  100. package/dist/__tests__/nav-access.test.js +0 -145
  101. package/dist/__tests__/page-header.test.js +0 -36
  102. package/dist/__tests__/public-layout-drawer.test.js +0 -116
  103. package/dist/__tests__/setup.js +0 -56
  104. package/dist/__tests__/sidebar-collapse.test.js +0 -58
  105. package/dist/__tests__/sidebar-docs-parity.test.js +0 -134
  106. package/dist/__tests__/sidebar-expansion.test.js +0 -59
  107. package/dist/__tests__/sidebar-items.test.js +0 -59
  108. package/dist/__tests__/sidebar-mobile.test.js +0 -86
  109. package/dist/__tests__/studio-canvas-item.svelte.test.js +0 -98
  110. package/dist/__tests__/studio.test.js +0 -240
@@ -1,240 +0,0 @@
1
- /**
2
- * Studio editor frame: outline selection and reordering (pointer-free, by
3
- * keyboard), the save and issues signals, and the responsive move of the
4
- * outline and inspector into sheets.
5
- */
6
- import { describe, it, expect, vi, afterEach } from 'vitest';
7
- import { mount, unmount, flushSync, tick, createRawSnippet } from 'svelte';
8
- import StudioOutline from '../lib/components/studio/StudioOutline.svelte';
9
- import SaveStatus from '../lib/components/studio/SaveStatus.svelte';
10
- import IssuesButton from '../lib/components/studio/IssuesButton.svelte';
11
- import Studio from '../lib/components/studio/Studio.svelte';
12
- import StudioCanvasItem from '../lib/components/studio/StudioCanvasItem.svelte';
13
- let instance = null;
14
- let host;
15
- function render(component, props) {
16
- host = document.createElement('div');
17
- document.body.appendChild(host);
18
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
19
- instance = mount(component, { target: host, props });
20
- flushSync();
21
- return host;
22
- }
23
- function viewport(width) {
24
- vi.spyOn(window, 'matchMedia').mockImplementation((query) => {
25
- const min = Number(/min-width:\s*(\d+)/.exec(query)?.[1] ?? 0);
26
- return {
27
- matches: width >= min,
28
- media: query,
29
- onchange: null,
30
- addEventListener: vi.fn(),
31
- removeEventListener: vi.fn(),
32
- addListener: vi.fn(),
33
- removeListener: vi.fn(),
34
- dispatchEvent: vi.fn(),
35
- };
36
- });
37
- }
38
- const html = (markup) => createRawSnippet(() => ({ render: () => markup }));
39
- function key(target, k, init = {}) {
40
- target.dispatchEvent(new KeyboardEvent('keydown', { key: k, bubbles: true, ...init }));
41
- flushSync();
42
- }
43
- afterEach(() => {
44
- if (instance)
45
- unmount(instance);
46
- instance = null;
47
- host?.remove();
48
- document.body.innerHTML = '';
49
- vi.restoreAllMocks();
50
- });
51
- const entries = [
52
- { id: 'a', title: 'Name' },
53
- { id: 'b', title: 'Email', issues: 2 },
54
- { id: 'c', title: 'Rating' },
55
- ];
56
- describe('StudioOutline', () => {
57
- it('selects a row and marks it current', () => {
58
- const onSelect = vi.fn();
59
- const el = render(StudioOutline, { items: entries, selected: 'a', onSelect });
60
- const rows = el.querySelectorAll('[data-outline-row]');
61
- rows[2].click();
62
- flushSync();
63
- expect(onSelect).toHaveBeenCalledWith('c');
64
- expect(rows[2].getAttribute('aria-current')).toBe('true');
65
- expect(rows[0].hasAttribute('aria-current')).toBe(false);
66
- });
67
- it('keeps one row in the tab order and moves focus with the arrow keys', () => {
68
- const el = render(StudioOutline, { items: entries, selected: 'b' });
69
- const rows = el.querySelectorAll('[data-outline-row]');
70
- expect([...rows].map((r) => r.tabIndex)).toEqual([-1, 0, -1]);
71
- rows[1].focus();
72
- key(rows[1], 'ArrowDown');
73
- expect(document.activeElement).toBe(rows[2]);
74
- });
75
- it('shows issue counts as text, not only colour', () => {
76
- const el = render(StudioOutline, { items: entries });
77
- expect(el.textContent).toContain('2');
78
- expect(el.textContent).toContain('issues');
79
- });
80
- it('reorders with the keyboard: pick up, move, drop', () => {
81
- const onReorder = vi.fn();
82
- const el = render(StudioOutline, { items: entries, onReorder });
83
- const handle = el.querySelector('[data-sortable-handle="a"]');
84
- expect(handle.getAttribute('aria-label')).toBe('Reorder Name');
85
- key(handle, ' ');
86
- expect(handle.getAttribute('aria-pressed')).toBe('true');
87
- key(handle, 'ArrowDown');
88
- expect(onReorder).toHaveBeenCalledWith(0, 1);
89
- });
90
- it('moves in one step with Alt+Arrow', () => {
91
- const onReorder = vi.fn();
92
- const el = render(StudioOutline, { items: entries, onReorder });
93
- const handle = el.querySelector('[data-sortable-handle="c"]');
94
- key(handle, 'ArrowUp', { altKey: true });
95
- expect(onReorder).toHaveBeenCalledWith(2, 1);
96
- });
97
- it('ignores arrows on a handle that is not picked up', () => {
98
- const onReorder = vi.fn();
99
- const el = render(StudioOutline, { items: entries, onReorder });
100
- key(el.querySelector('[data-sortable-handle="a"]'), 'ArrowDown');
101
- expect(onReorder).not.toHaveBeenCalled();
102
- });
103
- it('has no drag handles when reordering is off', () => {
104
- const el = render(StudioOutline, { items: entries });
105
- expect(el.querySelector('[data-sortable-handle]')).toBeNull();
106
- });
107
- it('renders the add button only when onAdd is given', () => {
108
- const onAdd = vi.fn();
109
- const el = render(StudioOutline, { items: entries, onAdd, addLabel: 'Add question' });
110
- const add = [...el.querySelectorAll('button')].find((b) => b.textContent?.includes('Add question'));
111
- add.click();
112
- expect(onAdd).toHaveBeenCalled();
113
- });
114
- });
115
- describe('SaveStatus', () => {
116
- it('shows one word for routine states and announces nothing', () => {
117
- const el = render(SaveStatus, { state: 'saved' });
118
- expect(el.textContent).toContain('Saved');
119
- expect(el.querySelector('[role="status"]').textContent).toBe('');
120
- });
121
- it('announces failures and offers Retry in its details', async () => {
122
- const onRetry = vi.fn();
123
- const el = render(SaveStatus, {
124
- state: 'error',
125
- detail: 'The server did not answer.',
126
- onRetry,
127
- });
128
- expect(el.querySelector('[role="status"]').textContent).toBe('Not saved');
129
- const trigger = el.querySelector('button');
130
- expect(trigger.getAttribute('aria-label')).toContain('Not saved');
131
- trigger.click();
132
- flushSync();
133
- await tick();
134
- const retry = [...document.querySelectorAll('button')].find((b) => b.textContent?.includes('Retry'));
135
- expect(document.body.textContent).toContain('The server did not answer.');
136
- retry.click();
137
- expect(onRetry).toHaveBeenCalled();
138
- });
139
- });
140
- describe('IssuesButton', () => {
141
- const issues = [
142
- { id: '1', message: 'Add a question', location: 'Questions' },
143
- { id: '2', message: 'Add at least two options', location: 'Question 2' },
144
- { id: '3', message: 'Consider a close date', severity: 'warning' },
145
- ];
146
- it('is hidden when there is nothing to fix', () => {
147
- const el = render(IssuesButton, { issues: [] });
148
- expect(el.querySelector('button')).toBeNull();
149
- });
150
- it('names errors and suggestions in its label', () => {
151
- const el = render(IssuesButton, { issues });
152
- expect(el.querySelector('button').getAttribute('aria-label')).toBe('2 issues to fix, 1 suggestion');
153
- });
154
- it('jumps to an issue and closes', async () => {
155
- const onSelect = vi.fn();
156
- const el = render(IssuesButton, { issues, onSelect });
157
- el.querySelector('button').click();
158
- flushSync();
159
- await tick();
160
- const entry = [...document.querySelectorAll('button')].find((b) => b.textContent?.includes('Add at least two options'));
161
- entry.click();
162
- flushSync();
163
- expect(onSelect).toHaveBeenCalledWith(issues[1]);
164
- });
165
- });
166
- describe('Studio layout', () => {
167
- const parts = {
168
- bar: html('<header>Bar</header>'),
169
- rail: html('<nav>Rail</nav>'),
170
- canvas: html('<p>Canvas</p>'),
171
- inspector: html('<div>Inspector</div>'),
172
- };
173
- it('shows rail, canvas and inspector side by side when wide', () => {
174
- viewport(1440);
175
- const el = render(Studio, parts);
176
- expect(el.querySelector('aside[aria-label="Outline"]')).not.toBeNull();
177
- expect(el.querySelector('aside[aria-label="Properties"]')).not.toBeNull();
178
- expect(el.textContent).not.toContain('Outline');
179
- });
180
- it('moves the rail into a sheet below 1280px', () => {
181
- viewport(1024);
182
- const el = render(Studio, parts);
183
- expect(el.querySelector('aside[aria-label="Outline"]')).toBeNull();
184
- expect(el.querySelector('aside[aria-label="Properties"]')).not.toBeNull();
185
- const open = [...el.querySelectorAll('button')].find((b) => b.textContent?.includes('Outline'));
186
- open.click();
187
- flushSync();
188
- expect(document.body.textContent).toContain('Rail');
189
- });
190
- it('leaves only the canvas on phones', () => {
191
- viewport(390);
192
- const el = render(Studio, parts);
193
- expect(el.querySelector('aside')).toBeNull();
194
- expect(el.textContent).toContain('Canvas');
195
- const labels = [...el.querySelectorAll('button')].map((b) => b.textContent?.trim());
196
- expect(labels).toEqual(['Outline', 'Properties']);
197
- });
198
- });
199
- describe('StudioCanvasItem', () => {
200
- it('selects on click and offers a keyboard way in', () => {
201
- const onSelect = vi.fn();
202
- const el = render(StudioCanvasItem, {
203
- label: 'Question 1',
204
- onSelect,
205
- children: html('<p>Body</p>'),
206
- });
207
- const edit = el.querySelector('button');
208
- expect(edit.textContent?.trim()).toBe('Edit Question 1');
209
- el.querySelector('p').click();
210
- expect(onSelect).toHaveBeenCalled();
211
- });
212
- it('inserts below without needing a selection change', () => {
213
- const onInsert = vi.fn();
214
- const el = render(StudioCanvasItem, {
215
- label: 'Question 1',
216
- selected: true,
217
- onInsert,
218
- children: html('<p>Body</p>'),
219
- });
220
- el.querySelector('button[aria-label="Add below Question 1"]').click();
221
- expect(onInsert).toHaveBeenCalled();
222
- });
223
- });
224
- describe('StudioCanvasItem quick actions', () => {
225
- it('does not select the item when focus lands on its "+" (a closing dialog returns it there)', () => {
226
- const onSelect = vi.fn();
227
- const el = render(StudioCanvasItem, {
228
- label: 'Question 1',
229
- onSelect,
230
- onInsert: () => { },
231
- children: html('<p>Body</p>'),
232
- });
233
- el.querySelector('button[aria-label="Add below Question 1"]').focus();
234
- flushSync();
235
- expect(onSelect).not.toHaveBeenCalled();
236
- el.querySelector('button').focus(); // the "Edit Question 1" button
237
- flushSync();
238
- expect(onSelect).toHaveBeenCalledTimes(1);
239
- });
240
- });