@opendata-ai/openchart-vanilla 8.0.0-rc.2 → 8.0.0-rc.21
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/dist/{chunk-W34KN7FD.js → chunk-2NAQRP66.js} +2 -2
- package/dist/chunk-DCODCLWI.js +234 -0
- package/dist/chunk-DCODCLWI.js.map +1 -0
- package/dist/{chunk-5EOV5JQZ.js → chunk-EKAUQAAX.js} +50 -46
- package/dist/chunk-EKAUQAAX.js.map +1 -0
- package/dist/{chunk-ENXSUXC5.js → chunk-KNT5AZ2O.js} +7309 -5490
- package/dist/chunk-KNT5AZ2O.js.map +1 -0
- package/dist/chunk-RM5XS6NR.js +113 -0
- package/dist/chunk-RM5XS6NR.js.map +1 -0
- package/dist/chunk-T32UHMZA.js +282 -0
- package/dist/chunk-T32UHMZA.js.map +1 -0
- package/dist/export-gif.d.ts +113 -0
- package/dist/export-gif.js +21 -0
- package/dist/export-gif.js.map +1 -0
- package/dist/index.d.ts +283 -24
- package/dist/index.js +2012 -763
- package/dist/index.js.map +1 -1
- package/dist/{mount-CUKQLeqD.d.ts → mount-Dvv8NYIv.d.ts} +117 -3
- package/dist/simulation-worker.js +83 -2
- package/dist/static.js +7 -69
- package/dist/static.js.map +1 -1
- package/dist/story/index.d.ts +3 -2
- package/dist/story/index.js +5 -3
- package/dist/story/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/styles.css.map +1 -1
- package/package.json +14 -6
- package/dist/chunk-5EOV5JQZ.js.map +0 -1
- package/dist/chunk-ENXSUXC5.js.map +0 -1
- package/src/__test-fixtures__/dom.ts +0 -70
- package/src/__test-fixtures__/specs.ts +0 -214
- package/src/__tests__/animation.test.ts +0 -358
- package/src/__tests__/annotations-render.test.ts +0 -201
- package/src/__tests__/compound-labels.test.ts +0 -122
- package/src/__tests__/continuous-legend.test.ts +0 -91
- package/src/__tests__/crosshair.test.ts +0 -130
- package/src/__tests__/edit-events.test.ts +0 -902
- package/src/__tests__/events.test.ts +0 -387
- package/src/__tests__/export.test.ts +0 -241
- package/src/__tests__/font-race.test.ts +0 -199
- package/src/__tests__/gradient-ids.test.ts +0 -159
- package/src/__tests__/gradient-utils.test.ts +0 -125
- package/src/__tests__/known-bugs-render.test.ts +0 -183
- package/src/__tests__/map.test.ts +0 -293
- package/src/__tests__/mount.test.ts +0 -357
- package/src/__tests__/pattern-fills.test.ts +0 -105
- package/src/__tests__/resize-timing.test.ts +0 -218
- package/src/__tests__/sankey.test.ts +0 -133
- package/src/__tests__/selection-events.test.ts +0 -869
- package/src/__tests__/series-search.test.ts +0 -311
- package/src/__tests__/static.test.ts +0 -141
- package/src/__tests__/svg-renderer.test.ts +0 -895
- package/src/__tests__/table-keyboard.test.ts +0 -361
- package/src/__tests__/table-mount.test.ts +0 -639
- package/src/__tests__/tilemap.test.ts +0 -158
- package/src/__tests__/tooltip.test.ts +0 -337
- package/src/__tests__/transition.test.ts +0 -1777
- package/src/__tests__/you-draw-it.test.ts +0 -273
- package/src/animation-vars.ts +0 -42
- package/src/animation.ts +0 -76
- package/src/barlist-mount.ts +0 -383
- package/src/barlist-renderer.ts +0 -267
- package/src/dom-helpers.ts +0 -17
- package/src/export.ts +0 -482
- package/src/gradient-utils.ts +0 -138
- package/src/graph/__tests__/canvas-renderer.test.ts +0 -713
- package/src/graph/__tests__/graph-mount.test.ts +0 -213
- package/src/graph/__tests__/interaction.test.ts +0 -205
- package/src/graph/__tests__/keyboard.test.ts +0 -653
- package/src/graph/__tests__/search.test.ts +0 -88
- package/src/graph/__tests__/simulation.test.ts +0 -233
- package/src/graph/__tests__/spatial-index.test.ts +0 -142
- package/src/graph/__tests__/zoom.test.ts +0 -203
- package/src/graph/canvas-renderer.ts +0 -747
- package/src/graph/interaction.ts +0 -367
- package/src/graph/keyboard.ts +0 -208
- package/src/graph/search.ts +0 -50
- package/src/graph/simulation-worker-url.ts +0 -12
- package/src/graph/simulation-worker.ts +0 -278
- package/src/graph/simulation.ts +0 -422
- package/src/graph/spatial-index.ts +0 -121
- package/src/graph/types.ts +0 -47
- package/src/graph/worker-protocol.ts +0 -70
- package/src/graph/zoom.ts +0 -134
- package/src/graph-mount.ts +0 -888
- package/src/index.ts +0 -76
- package/src/interactions/chart-events.ts +0 -139
- package/src/interactions/crosshair.ts +0 -233
- package/src/interactions/drag-handler.ts +0 -175
- package/src/interactions/editing-drags.ts +0 -515
- package/src/interactions/index.ts +0 -25
- package/src/interactions/keyboard-nav.ts +0 -111
- package/src/interactions/legend-interaction.ts +0 -46
- package/src/interactions/selection.ts +0 -280
- package/src/interactions/tooltip-events.ts +0 -72
- package/src/map-camera.ts +0 -88
- package/src/map-mount.ts +0 -701
- package/src/map-renderer.ts +0 -338
- package/src/map-transition.ts +0 -83
- package/src/measure-text.ts +0 -134
- package/src/mount.ts +0 -1382
- package/src/pattern-utils.ts +0 -110
- package/src/renderers/annotations.ts +0 -388
- package/src/renderers/axes.ts +0 -351
- package/src/renderers/brand.ts +0 -87
- package/src/renderers/chrome.ts +0 -196
- package/src/renderers/endpoint-labels.ts +0 -150
- package/src/renderers/legend.ts +0 -311
- package/src/renderers/marks.ts +0 -561
- package/src/renderers/metrics.ts +0 -63
- package/src/renderers/svg-dom.ts +0 -40
- package/src/renderers/table-cells.ts +0 -446
- package/src/resize-observer.ts +0 -46
- package/src/sankey-mount.ts +0 -622
- package/src/sankey-renderer.ts +0 -614
- package/src/series-search.ts +0 -392
- package/src/static.ts +0 -251
- package/src/story/__tests__/camera-math.test.ts +0 -145
- package/src/story/__tests__/create-chart-story.test.ts +0 -317
- package/src/story/__tests__/progress-math.test.ts +0 -95
- package/src/story/__tests__/scroll-driver.test.ts +0 -130
- package/src/story/__tests__/tween.test.ts +0 -159
- package/src/story/camera-math.ts +0 -125
- package/src/story/create-chart-story.ts +0 -353
- package/src/story/crossfade.ts +0 -70
- package/src/story/index.ts +0 -39
- package/src/story/progress-math.ts +0 -85
- package/src/story/resolve-camera-target.ts +0 -119
- package/src/story/scroll-driver.ts +0 -206
- package/src/story/story-camera.ts +0 -49
- package/src/story/tween.ts +0 -112
- package/src/story/types.ts +0 -76
- package/src/svg-ids.ts +0 -23
- package/src/svg-renderer.ts +0 -383
- package/src/table-keyboard.ts +0 -266
- package/src/table-mount.ts +0 -567
- package/src/table-renderer.ts +0 -414
- package/src/text-edit-overlay.ts +0 -255
- package/src/theme-tokens.ts +0 -51
- package/src/tilemap-mount.ts +0 -511
- package/src/tilemap-renderer.ts +0 -396
- package/src/tooltip.ts +0 -177
- package/src/transition.ts +0 -2816
- package/src/you-draw-it.ts +0 -480
- /package/dist/{chunk-W34KN7FD.js.map → chunk-2NAQRP66.js.map} +0 -0
|
@@ -1,361 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
-
import { attachKeyboardNav } from '../table-keyboard';
|
|
3
|
-
|
|
4
|
-
// ---------------------------------------------------------------------------
|
|
5
|
-
// Helpers
|
|
6
|
-
// ---------------------------------------------------------------------------
|
|
7
|
-
|
|
8
|
-
function createTableDOM(rows: number, cols: number, opts?: { search?: boolean }): HTMLDivElement {
|
|
9
|
-
const wrapper = document.createElement('div');
|
|
10
|
-
const table = document.createElement('table');
|
|
11
|
-
|
|
12
|
-
// thead
|
|
13
|
-
const thead = document.createElement('thead');
|
|
14
|
-
const headerRow = document.createElement('tr');
|
|
15
|
-
for (let c = 0; c < cols; c++) {
|
|
16
|
-
const th = document.createElement('th');
|
|
17
|
-
th.textContent = `Col${c}`;
|
|
18
|
-
th.setAttribute('data-column', `col${c}`);
|
|
19
|
-
const sortBtn = document.createElement('button');
|
|
20
|
-
sortBtn.setAttribute('data-sort-column', `col${c}`);
|
|
21
|
-
th.appendChild(sortBtn);
|
|
22
|
-
headerRow.appendChild(th);
|
|
23
|
-
}
|
|
24
|
-
thead.appendChild(headerRow);
|
|
25
|
-
table.appendChild(thead);
|
|
26
|
-
|
|
27
|
-
// tbody
|
|
28
|
-
const tbody = document.createElement('tbody');
|
|
29
|
-
for (let r = 0; r < rows; r++) {
|
|
30
|
-
const tr = document.createElement('tr');
|
|
31
|
-
for (let c = 0; c < cols; c++) {
|
|
32
|
-
const td = document.createElement('td');
|
|
33
|
-
td.textContent = `R${r}C${c}`;
|
|
34
|
-
tr.appendChild(td);
|
|
35
|
-
}
|
|
36
|
-
tbody.appendChild(tr);
|
|
37
|
-
}
|
|
38
|
-
table.appendChild(tbody);
|
|
39
|
-
wrapper.appendChild(table);
|
|
40
|
-
|
|
41
|
-
// Search input
|
|
42
|
-
if (opts?.search) {
|
|
43
|
-
const searchDiv = document.createElement('div');
|
|
44
|
-
searchDiv.className = 'oc-table-search';
|
|
45
|
-
const input = document.createElement('input');
|
|
46
|
-
searchDiv.appendChild(input);
|
|
47
|
-
wrapper.appendChild(searchDiv);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return wrapper;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function keydown(el: HTMLElement, key: string): void {
|
|
54
|
-
el.dispatchEvent(new KeyboardEvent('keydown', { key, bubbles: true }));
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function focusTbody(wrapper: HTMLDivElement): HTMLElement {
|
|
58
|
-
const tbody = wrapper.querySelector('tbody')!;
|
|
59
|
-
tbody.dispatchEvent(new Event('focus'));
|
|
60
|
-
return tbody;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// ---------------------------------------------------------------------------
|
|
64
|
-
// Tests
|
|
65
|
-
// ---------------------------------------------------------------------------
|
|
66
|
-
|
|
67
|
-
describe('attachKeyboardNav', () => {
|
|
68
|
-
let wrapper: HTMLDivElement;
|
|
69
|
-
let onSort: ReturnType<typeof vi.fn>;
|
|
70
|
-
let onClearSearch: ReturnType<typeof vi.fn>;
|
|
71
|
-
let onAnnounce: ReturnType<typeof vi.fn>;
|
|
72
|
-
let cleanup: () => void;
|
|
73
|
-
|
|
74
|
-
function attach(w: HTMLDivElement): () => void {
|
|
75
|
-
return attachKeyboardNav({
|
|
76
|
-
wrapper: w,
|
|
77
|
-
onSort,
|
|
78
|
-
onClearSearch,
|
|
79
|
-
onAnnounce,
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
beforeEach(() => {
|
|
84
|
-
onSort = vi.fn();
|
|
85
|
-
onClearSearch = vi.fn();
|
|
86
|
-
onAnnounce = vi.fn();
|
|
87
|
-
wrapper = createTableDOM(5, 3);
|
|
88
|
-
document.body.appendChild(wrapper);
|
|
89
|
-
cleanup = attach(wrapper);
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
afterEach(() => {
|
|
93
|
-
cleanup();
|
|
94
|
-
document.body.innerHTML = '';
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
it('makes tbody focusable', () => {
|
|
98
|
-
const tbody = wrapper.querySelector('tbody')!;
|
|
99
|
-
expect(tbody.getAttribute('tabindex')).toBe('0');
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
it('makes header cells focusable', () => {
|
|
103
|
-
const headers = wrapper.querySelectorAll('thead th');
|
|
104
|
-
for (const th of headers) {
|
|
105
|
-
expect(th.getAttribute('tabindex')).toBe('0');
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
it('returns noop cleanup when no table exists', () => {
|
|
110
|
-
const empty = document.createElement('div');
|
|
111
|
-
const c = attachKeyboardNav({
|
|
112
|
-
wrapper: empty,
|
|
113
|
-
onSort,
|
|
114
|
-
onClearSearch,
|
|
115
|
-
onAnnounce,
|
|
116
|
-
});
|
|
117
|
-
expect(c).toBeTypeOf('function');
|
|
118
|
-
c(); // should not throw
|
|
119
|
-
});
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
describe('tbody arrow key navigation', () => {
|
|
123
|
-
let wrapper: HTMLDivElement;
|
|
124
|
-
let onSort: ReturnType<typeof vi.fn>;
|
|
125
|
-
let onClearSearch: ReturnType<typeof vi.fn>;
|
|
126
|
-
let onAnnounce: ReturnType<typeof vi.fn>;
|
|
127
|
-
let cleanup: () => void;
|
|
128
|
-
|
|
129
|
-
beforeEach(() => {
|
|
130
|
-
onSort = vi.fn();
|
|
131
|
-
onClearSearch = vi.fn();
|
|
132
|
-
onAnnounce = vi.fn();
|
|
133
|
-
wrapper = createTableDOM(5, 3);
|
|
134
|
-
document.body.appendChild(wrapper);
|
|
135
|
-
cleanup = attachKeyboardNav({
|
|
136
|
-
wrapper,
|
|
137
|
-
onSort,
|
|
138
|
-
onClearSearch,
|
|
139
|
-
onAnnounce,
|
|
140
|
-
});
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
afterEach(() => {
|
|
144
|
-
cleanup();
|
|
145
|
-
document.body.innerHTML = '';
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
it('focus highlights first cell and sets aria-activedescendant', () => {
|
|
149
|
-
const tbody = focusTbody(wrapper);
|
|
150
|
-
expect(tbody.getAttribute('aria-activedescendant')).toBe('oc-cell-0-0');
|
|
151
|
-
const cell = wrapper.querySelector('.oc-table-cell-focus');
|
|
152
|
-
expect(cell).not.toBeNull();
|
|
153
|
-
expect(cell?.textContent).toBe('R0C0');
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
it('ArrowDown moves focus down one row', () => {
|
|
157
|
-
const tbody = focusTbody(wrapper);
|
|
158
|
-
keydown(tbody, 'ArrowDown');
|
|
159
|
-
expect(tbody.getAttribute('aria-activedescendant')).toBe('oc-cell-1-0');
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
it('ArrowDown does not go past last row', () => {
|
|
163
|
-
const tbody = focusTbody(wrapper);
|
|
164
|
-
for (let i = 0; i < 10; i++) keydown(tbody, 'ArrowDown');
|
|
165
|
-
expect(tbody.getAttribute('aria-activedescendant')).toBe('oc-cell-4-0');
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
it('ArrowRight moves focus right one column', () => {
|
|
169
|
-
const tbody = focusTbody(wrapper);
|
|
170
|
-
keydown(tbody, 'ArrowRight');
|
|
171
|
-
expect(tbody.getAttribute('aria-activedescendant')).toBe('oc-cell-0-1');
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
it('ArrowRight does not go past last column', () => {
|
|
175
|
-
const tbody = focusTbody(wrapper);
|
|
176
|
-
for (let i = 0; i < 10; i++) keydown(tbody, 'ArrowRight');
|
|
177
|
-
expect(tbody.getAttribute('aria-activedescendant')).toBe('oc-cell-0-2');
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
it('ArrowLeft moves focus left', () => {
|
|
181
|
-
const tbody = focusTbody(wrapper);
|
|
182
|
-
keydown(tbody, 'ArrowRight');
|
|
183
|
-
keydown(tbody, 'ArrowRight');
|
|
184
|
-
keydown(tbody, 'ArrowLeft');
|
|
185
|
-
expect(tbody.getAttribute('aria-activedescendant')).toBe('oc-cell-0-1');
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
it('ArrowLeft does not go past first column', () => {
|
|
189
|
-
const tbody = focusTbody(wrapper);
|
|
190
|
-
keydown(tbody, 'ArrowLeft');
|
|
191
|
-
expect(tbody.getAttribute('aria-activedescendant')).toBe('oc-cell-0-0');
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
it('Home moves to first column in current row', () => {
|
|
195
|
-
const tbody = focusTbody(wrapper);
|
|
196
|
-
keydown(tbody, 'ArrowRight');
|
|
197
|
-
keydown(tbody, 'ArrowRight');
|
|
198
|
-
keydown(tbody, 'Home');
|
|
199
|
-
expect(tbody.getAttribute('aria-activedescendant')).toBe('oc-cell-0-0');
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
it('End moves to last column in current row', () => {
|
|
203
|
-
const tbody = focusTbody(wrapper);
|
|
204
|
-
keydown(tbody, 'End');
|
|
205
|
-
expect(tbody.getAttribute('aria-activedescendant')).toBe('oc-cell-0-2');
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
it('navigation clears previous focus highlight', () => {
|
|
209
|
-
const tbody = focusTbody(wrapper);
|
|
210
|
-
keydown(tbody, 'ArrowDown');
|
|
211
|
-
const focused = wrapper.querySelectorAll('.oc-table-cell-focus');
|
|
212
|
-
expect(focused.length).toBe(1);
|
|
213
|
-
expect(focused[0].textContent).toBe('R1C0');
|
|
214
|
-
});
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
describe('header keyboard navigation', () => {
|
|
218
|
-
let wrapper: HTMLDivElement;
|
|
219
|
-
let onSort: ReturnType<typeof vi.fn>;
|
|
220
|
-
let onClearSearch: ReturnType<typeof vi.fn>;
|
|
221
|
-
let onAnnounce: ReturnType<typeof vi.fn>;
|
|
222
|
-
let cleanup: () => void;
|
|
223
|
-
|
|
224
|
-
beforeEach(() => {
|
|
225
|
-
onSort = vi.fn();
|
|
226
|
-
onClearSearch = vi.fn();
|
|
227
|
-
onAnnounce = vi.fn();
|
|
228
|
-
wrapper = createTableDOM(3, 3);
|
|
229
|
-
document.body.appendChild(wrapper);
|
|
230
|
-
cleanup = attachKeyboardNav({
|
|
231
|
-
wrapper,
|
|
232
|
-
onSort,
|
|
233
|
-
onClearSearch,
|
|
234
|
-
onAnnounce,
|
|
235
|
-
});
|
|
236
|
-
});
|
|
237
|
-
|
|
238
|
-
afterEach(() => {
|
|
239
|
-
cleanup();
|
|
240
|
-
document.body.innerHTML = '';
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
it('ArrowUp from first body row moves focus to header', () => {
|
|
244
|
-
const tbody = focusTbody(wrapper);
|
|
245
|
-
// ArrowUp from row 0 should focus the header
|
|
246
|
-
keydown(tbody, 'ArrowUp');
|
|
247
|
-
// Focus moved to header, so tbody's activedescendant should remain unchanged
|
|
248
|
-
const headers = wrapper.querySelectorAll('thead th');
|
|
249
|
-
// Can't easily check document.activeElement in happy-dom, but header focus() was called
|
|
250
|
-
expect(headers[0]).toBeDefined();
|
|
251
|
-
});
|
|
252
|
-
|
|
253
|
-
it('Enter on header triggers sort', () => {
|
|
254
|
-
const headers = wrapper.querySelectorAll('thead th');
|
|
255
|
-
keydown(headers[1] as HTMLElement, 'Enter');
|
|
256
|
-
expect(onSort).toHaveBeenCalledWith('col1');
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
it('Space on header triggers sort', () => {
|
|
260
|
-
const headers = wrapper.querySelectorAll('thead th');
|
|
261
|
-
keydown(headers[0] as HTMLElement, ' ');
|
|
262
|
-
expect(onSort).toHaveBeenCalledWith('col0');
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
it('ArrowRight on header moves to next header', () => {
|
|
266
|
-
// This tests the focus logic; in happy-dom we just verify no errors
|
|
267
|
-
const headers = wrapper.querySelectorAll('thead th');
|
|
268
|
-
keydown(headers[0] as HTMLElement, 'ArrowRight');
|
|
269
|
-
// Should not throw
|
|
270
|
-
});
|
|
271
|
-
|
|
272
|
-
it('ArrowDown from header moves to body at same column', () => {
|
|
273
|
-
const headers = wrapper.querySelectorAll('thead th');
|
|
274
|
-
keydown(headers[1] as HTMLElement, 'ArrowDown');
|
|
275
|
-
const tbody = wrapper.querySelector('tbody')!;
|
|
276
|
-
// The tbody should have activedescendant set to first row, column 1
|
|
277
|
-
expect(tbody.getAttribute('aria-activedescendant')).toBe('oc-cell-0-1');
|
|
278
|
-
});
|
|
279
|
-
});
|
|
280
|
-
|
|
281
|
-
describe('search escape handling', () => {
|
|
282
|
-
let wrapper: HTMLDivElement;
|
|
283
|
-
let onSort: ReturnType<typeof vi.fn>;
|
|
284
|
-
let onClearSearch: ReturnType<typeof vi.fn>;
|
|
285
|
-
let onAnnounce: ReturnType<typeof vi.fn>;
|
|
286
|
-
let cleanup: () => void;
|
|
287
|
-
|
|
288
|
-
beforeEach(() => {
|
|
289
|
-
onSort = vi.fn();
|
|
290
|
-
onClearSearch = vi.fn();
|
|
291
|
-
onAnnounce = vi.fn();
|
|
292
|
-
wrapper = createTableDOM(3, 3, { search: true });
|
|
293
|
-
document.body.appendChild(wrapper);
|
|
294
|
-
cleanup = attachKeyboardNav({
|
|
295
|
-
wrapper,
|
|
296
|
-
onSort,
|
|
297
|
-
onClearSearch,
|
|
298
|
-
onAnnounce,
|
|
299
|
-
});
|
|
300
|
-
});
|
|
301
|
-
|
|
302
|
-
afterEach(() => {
|
|
303
|
-
cleanup();
|
|
304
|
-
document.body.innerHTML = '';
|
|
305
|
-
});
|
|
306
|
-
|
|
307
|
-
it('Escape in search input calls onClearSearch', () => {
|
|
308
|
-
const input = wrapper.querySelector('.oc-table-search input')!;
|
|
309
|
-
keydown(input as HTMLElement, 'Escape');
|
|
310
|
-
expect(onClearSearch).toHaveBeenCalledTimes(1);
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
it('Escape in search announces "Search cleared"', () => {
|
|
314
|
-
const input = wrapper.querySelector('.oc-table-search input')!;
|
|
315
|
-
keydown(input as HTMLElement, 'Escape');
|
|
316
|
-
expect(onAnnounce).toHaveBeenCalledWith('Search cleared');
|
|
317
|
-
});
|
|
318
|
-
|
|
319
|
-
it('non-Escape keys in search do not trigger clear', () => {
|
|
320
|
-
const input = wrapper.querySelector('.oc-table-search input')!;
|
|
321
|
-
keydown(input as HTMLElement, 'a');
|
|
322
|
-
keydown(input as HTMLElement, 'Enter');
|
|
323
|
-
expect(onClearSearch).not.toHaveBeenCalled();
|
|
324
|
-
});
|
|
325
|
-
});
|
|
326
|
-
|
|
327
|
-
describe('cleanup', () => {
|
|
328
|
-
it('removes event listeners after cleanup', () => {
|
|
329
|
-
const wrapper = createTableDOM(3, 3, { search: true });
|
|
330
|
-
document.body.appendChild(wrapper);
|
|
331
|
-
|
|
332
|
-
const onSort = vi.fn();
|
|
333
|
-
const onClearSearch = vi.fn();
|
|
334
|
-
const onAnnounce = vi.fn();
|
|
335
|
-
|
|
336
|
-
const cleanup = attachKeyboardNav({
|
|
337
|
-
wrapper,
|
|
338
|
-
onSort,
|
|
339
|
-
onClearSearch,
|
|
340
|
-
onAnnounce,
|
|
341
|
-
});
|
|
342
|
-
|
|
343
|
-
cleanup();
|
|
344
|
-
|
|
345
|
-
// After cleanup, keyboard events should not trigger callbacks
|
|
346
|
-
const tbody = wrapper.querySelector('tbody')!;
|
|
347
|
-
tbody.dispatchEvent(new Event('focus'));
|
|
348
|
-
keydown(tbody, 'ArrowDown');
|
|
349
|
-
|
|
350
|
-
const input = wrapper.querySelector('.oc-table-search input')!;
|
|
351
|
-
keydown(input as HTMLElement, 'Escape');
|
|
352
|
-
|
|
353
|
-
expect(onClearSearch).not.toHaveBeenCalled();
|
|
354
|
-
|
|
355
|
-
// Focus highlight should be cleared
|
|
356
|
-
const focused = wrapper.querySelectorAll('.oc-table-cell-focus');
|
|
357
|
-
expect(focused.length).toBe(0);
|
|
358
|
-
|
|
359
|
-
document.body.innerHTML = '';
|
|
360
|
-
});
|
|
361
|
-
});
|