@svgrid/grid 1.1.1 → 1.2.1

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 (188) hide show
  1. package/dist/FlexRender.svelte +96 -96
  2. package/dist/SvGrid.controller.svelte.js +17 -6
  3. package/dist/SvGrid.css +2012 -2012
  4. package/dist/SvGrid.svelte +2571 -2346
  5. package/dist/SvGridDropdown.svelte +7 -3
  6. package/dist/build-api.js +2 -2
  7. package/dist/cdn/svgrid.js +13504 -0
  8. package/dist/cdn/svgrid.svelte-external.js +11188 -0
  9. package/dist/cell-values.d.ts +1 -1
  10. package/dist/cell-values.js +7 -7
  11. package/dist/column-types.js +1 -1
  12. package/dist/core.d.ts +1 -1
  13. package/dist/core.js +2 -2
  14. package/dist/summaries.js +4 -4
  15. package/package.json +12 -2
  16. package/src/FlexRender.svelte +96 -96
  17. package/src/SvGrid.controller.svelte.ts +2363 -2352
  18. package/src/SvGrid.css +2012 -2012
  19. package/src/SvGrid.svelte +2571 -2346
  20. package/src/SvGrid.types.ts +537 -537
  21. package/src/SvGridDropdown.svelte +7 -3
  22. package/src/a11y.contract.test.ts +49 -49
  23. package/src/a11y.test.ts +59 -59
  24. package/src/a11y.ts +59 -59
  25. package/src/build-api.ts +683 -683
  26. package/src/cell-formatting.ts +169 -169
  27. package/src/cell-values.ts +4 -4
  28. package/src/column-types.ts +1 -1
  29. package/src/core.performance.test.ts +30 -30
  30. package/src/core.ts +1077 -1077
  31. package/src/createGrid.svelte.ts +42 -42
  32. package/src/createGrid.test.ts +10 -10
  33. package/src/createGridState.svelte.ts +17 -17
  34. package/src/editing.ts +669 -669
  35. package/src/flex-render.ts +3 -3
  36. package/src/index.ts +208 -208
  37. package/src/keyboard.test.ts +59 -59
  38. package/src/keyboard.ts +97 -97
  39. package/src/merge-objects.ts +48 -48
  40. package/src/render-component.ts +28 -28
  41. package/src/spreadsheet.test.ts +489 -489
  42. package/src/spreadsheet.ts +304 -304
  43. package/src/static-functions.ts +11 -11
  44. package/src/subscribe.ts +38 -38
  45. package/src/summaries.ts +4 -4
  46. package/src/svgrid-wrapper.types.ts +412 -412
  47. package/src/svgrid.features.test.ts +157 -157
  48. package/src/svgrid.wrapper.test.ts +40 -40
  49. package/src/virtualization/column-virtualizer.test.ts +27 -27
  50. package/src/virtualization/column-virtualizer.ts +30 -30
  51. package/src/virtualization/svelte-virtualizer.svelte.ts +26 -26
  52. package/src/virtualization/types.ts +30 -30
  53. package/src/virtualization/virtualizer.test.ts +47 -47
  54. package/src/virtualization/virtualizer.ts +296 -296
  55. package/dist/SvGrid.helpers.test.d.ts +0 -1
  56. package/dist/SvGrid.helpers.test.js +0 -298
  57. package/dist/SvGridChart.test.d.ts +0 -1
  58. package/dist/SvGridChart.test.js +0 -62
  59. package/dist/a11y.contract.test.d.ts +0 -1
  60. package/dist/a11y.contract.test.js +0 -39
  61. package/dist/a11y.test.d.ts +0 -1
  62. package/dist/a11y.test.js +0 -44
  63. package/dist/aligned-grids.test.d.ts +0 -1
  64. package/dist/aligned-grids.test.js +0 -75
  65. package/dist/build-api.coverage.test.d.ts +0 -20
  66. package/dist/build-api.coverage.test.js +0 -505
  67. package/dist/cell-formatting.test.d.ts +0 -1
  68. package/dist/cell-formatting.test.js +0 -234
  69. package/dist/cell-render.test.d.ts +0 -1
  70. package/dist/cell-render.test.js +0 -338
  71. package/dist/chart-export.test.d.ts +0 -1
  72. package/dist/chart-export.test.js +0 -302
  73. package/dist/chart.coverage.test.d.ts +0 -1
  74. package/dist/chart.coverage.test.js +0 -748
  75. package/dist/chart.test.d.ts +0 -1
  76. package/dist/chart.test.js +0 -289
  77. package/dist/clipboard.test.d.ts +0 -1
  78. package/dist/clipboard.test.js +0 -700
  79. package/dist/collaboration.coverage.test.d.ts +0 -1
  80. package/dist/collaboration.coverage.test.js +0 -200
  81. package/dist/collaboration.test.d.ts +0 -1
  82. package/dist/collaboration.test.js +0 -65
  83. package/dist/column-groups.test.d.ts +0 -1
  84. package/dist/column-groups.test.js +0 -56
  85. package/dist/column-types.test.d.ts +0 -1
  86. package/dist/column-types.test.js +0 -62
  87. package/dist/columns.test.d.ts +0 -1
  88. package/dist/columns.test.js +0 -625
  89. package/dist/conditional-formatting.test.d.ts +0 -1
  90. package/dist/conditional-formatting.test.js +0 -87
  91. package/dist/core.coverage.test.d.ts +0 -1
  92. package/dist/core.coverage.test.js +0 -186
  93. package/dist/core.performance.test.d.ts +0 -1
  94. package/dist/core.performance.test.js +0 -29
  95. package/dist/createGrid.test.d.ts +0 -1
  96. package/dist/createGrid.test.js +0 -9
  97. package/dist/editing.test.d.ts +0 -1
  98. package/dist/editing.test.js +0 -732
  99. package/dist/editors/cell-editors.coverage.test.d.ts +0 -1
  100. package/dist/editors/cell-editors.coverage.test.js +0 -139
  101. package/dist/editors/cell-editors.test.d.ts +0 -1
  102. package/dist/editors/cell-editors.test.js +0 -75
  103. package/dist/facet-buckets.test.d.ts +0 -1
  104. package/dist/facet-buckets.test.js +0 -296
  105. package/dist/fill-patterns.test.d.ts +0 -1
  106. package/dist/fill-patterns.test.js +0 -81
  107. package/dist/filter-operators.test.d.ts +0 -1
  108. package/dist/filter-operators.test.js +0 -135
  109. package/dist/filtering/excel-filters.test.d.ts +0 -1
  110. package/dist/filtering/excel-filters.test.js +0 -116
  111. package/dist/filtering/locale-filter.test.d.ts +0 -13
  112. package/dist/filtering/locale-filter.test.js +0 -189
  113. package/dist/flex-render.test.d.ts +0 -1
  114. package/dist/flex-render.test.js +0 -142
  115. package/dist/group-aggregate.test.d.ts +0 -1
  116. package/dist/group-aggregate.test.js +0 -32
  117. package/dist/hyperformula-adapter.test.d.ts +0 -1
  118. package/dist/hyperformula-adapter.test.js +0 -205
  119. package/dist/keyboard-handlers.coverage.test.d.ts +0 -1
  120. package/dist/keyboard-handlers.coverage.test.js +0 -495
  121. package/dist/keyboard.test.d.ts +0 -1
  122. package/dist/keyboard.test.js +0 -27
  123. package/dist/menus.test.d.ts +0 -1
  124. package/dist/menus.test.js +0 -560
  125. package/dist/named-views.coverage.test.d.ts +0 -1
  126. package/dist/named-views.coverage.test.js +0 -180
  127. package/dist/named-views.test.d.ts +0 -1
  128. package/dist/named-views.test.js +0 -57
  129. package/dist/new-features.test.d.ts +0 -1
  130. package/dist/new-features.test.js +0 -183
  131. package/dist/render-component.test.d.ts +0 -1
  132. package/dist/render-component.test.js +0 -41
  133. package/dist/row-drag.test.d.ts +0 -1
  134. package/dist/row-drag.test.js +0 -142
  135. package/dist/row-resize.test.d.ts +0 -1
  136. package/dist/row-resize.test.js +0 -329
  137. package/dist/scroll-sync.test.d.ts +0 -1
  138. package/dist/scroll-sync.test.js +0 -290
  139. package/dist/selection.multi-range.test.d.ts +0 -1
  140. package/dist/selection.multi-range.test.js +0 -55
  141. package/dist/selection.test.d.ts +0 -1
  142. package/dist/selection.test.js +0 -647
  143. package/dist/server-data-source.coverage.test.d.ts +0 -1
  144. package/dist/server-data-source.coverage.test.js +0 -154
  145. package/dist/server-data-source.test.d.ts +0 -1
  146. package/dist/server-data-source.test.js +0 -81
  147. package/dist/sparkline.test.d.ts +0 -1
  148. package/dist/sparkline.test.js +0 -52
  149. package/dist/spreadsheet.test.d.ts +0 -1
  150. package/dist/spreadsheet.test.js +0 -446
  151. package/dist/subscribe.test.d.ts +0 -1
  152. package/dist/subscribe.test.js +0 -93
  153. package/dist/svgrid.api-extensions.test.d.ts +0 -14
  154. package/dist/svgrid.api-extensions.test.js +0 -334
  155. package/dist/svgrid.api.test.d.ts +0 -15
  156. package/dist/svgrid.api.test.js +0 -169
  157. package/dist/svgrid.behavior.test.d.ts +0 -15
  158. package/dist/svgrid.behavior.test.js +0 -625
  159. package/dist/svgrid.column-reorder.test.d.ts +0 -15
  160. package/dist/svgrid.column-reorder.test.js +0 -224
  161. package/dist/svgrid.comments-autocomplete.test.d.ts +0 -1
  162. package/dist/svgrid.comments-autocomplete.test.js +0 -96
  163. package/dist/svgrid.context-menu.test.d.ts +0 -1
  164. package/dist/svgrid.context-menu.test.js +0 -102
  165. package/dist/svgrid.features.test.d.ts +0 -1
  166. package/dist/svgrid.features.test.js +0 -129
  167. package/dist/svgrid.interaction.test.d.ts +0 -9
  168. package/dist/svgrid.interaction.test.js +0 -349
  169. package/dist/svgrid.locale-filtering.test.d.ts +0 -15
  170. package/dist/svgrid.locale-filtering.test.js +0 -261
  171. package/dist/svgrid.new-features.wrapper.test.d.ts +0 -1
  172. package/dist/svgrid.new-features.wrapper.test.js +0 -194
  173. package/dist/svgrid.row-pinning.test.d.ts +0 -14
  174. package/dist/svgrid.row-pinning.test.js +0 -250
  175. package/dist/svgrid.set-filter.test.d.ts +0 -17
  176. package/dist/svgrid.set-filter.test.js +0 -268
  177. package/dist/svgrid.wrapper.test.d.ts +0 -1
  178. package/dist/svgrid.wrapper.test.js +0 -59
  179. package/dist/test-setup.d.ts +0 -1
  180. package/dist/test-setup.js +0 -35
  181. package/dist/transaction.test.d.ts +0 -1
  182. package/dist/transaction.test.js +0 -89
  183. package/dist/virtualization/column-virtualizer.test.d.ts +0 -1
  184. package/dist/virtualization/column-virtualizer.test.js +0 -25
  185. package/dist/virtualization/scroll-scaling.test.d.ts +0 -1
  186. package/dist/virtualization/scroll-scaling.test.js +0 -127
  187. package/dist/virtualization/virtualizer.test.d.ts +0 -1
  188. package/dist/virtualization/virtualizer.test.js +0 -41
@@ -1,224 +0,0 @@
1
- /**
2
- * Component tests for engine-level column reorder. Mount a real
3
- * <SvGrid> with `enableColumnReorder={true}`, then exercise both
4
- * surfaces:
5
- *
6
- * - Imperative: api.setColumnOrder() / getColumnOrder() reorders the
7
- * DOM and fires onColumnOrderChange.
8
- * - User drag: dispatch dragstart / dragover / drop events on header
9
- * elements, assert the resulting DOM order matches the drop side.
10
- * - Drop indicator: the hovered header gets `is-drag-target-before` /
11
- * `is-drag-target-after` while a drag is in flight.
12
- * - Headers carry `draggable=true` only when the prop is on.
13
- * - Pin groups: reorder within a pin group is honored.
14
- */
15
- import { describe, expect, it } from 'vitest';
16
- import { mount, unmount } from 'svelte';
17
- import SvGrid from './SvGrid.svelte';
18
- import { columnFilteringFeature, createCoreRowModel, createFilteredRowModel, createSortedRowModel, rowSortingFeature, sortFns, tableFeatures, } from './index';
19
- const features = tableFeatures({ columnFilteringFeature, rowSortingFeature });
20
- const rows = [
21
- { id: 'P-1', first: 'Ada', last: 'Lovelace', team: 'Research', salary: 145000 },
22
- { id: 'P-2', first: 'Linus', last: 'Torvalds', team: 'Kernel', salary: 188000 },
23
- { id: 'P-3', first: 'Grace', last: 'Hopper', team: 'Compilers', salary: 152000 },
24
- ];
25
- const cols = [
26
- { field: 'id', header: 'ID', width: 100 },
27
- { field: 'first', header: 'First', width: 140 },
28
- { field: 'last', header: 'Last', width: 140 },
29
- { field: 'team', header: 'Team', width: 160 },
30
- { field: 'salary', header: 'Salary', width: 130 },
31
- ];
32
- function mountGrid(opts = {}) {
33
- return new Promise((res, rej) => {
34
- const target = document.createElement('div');
35
- document.body.appendChild(target);
36
- let api = null;
37
- const app = mount(SvGrid, {
38
- target,
39
- props: {
40
- data: rows,
41
- columns: cols,
42
- features,
43
- _rowModels: {
44
- coreRowModel: createCoreRowModel(),
45
- filteredRowModel: createFilteredRowModel(),
46
- sortedRowModel: createSortedRowModel(sortFns),
47
- },
48
- containerHeight: 360,
49
- virtualization: false,
50
- columnVirtualization: false,
51
- enableInlineEditing: false,
52
- showPagination: false,
53
- showColumnFilters: false,
54
- showGlobalFilter: false,
55
- showRowSelection: false,
56
- enableColumnReorder: opts.enableColumnReorder,
57
- columnOrder: opts.columnOrder,
58
- onColumnOrderChange: opts.onColumnOrderChange,
59
- onApiReady(received) {
60
- api = received;
61
- res({
62
- target,
63
- api,
64
- destroy: () => {
65
- unmount(app);
66
- target.remove();
67
- },
68
- });
69
- },
70
- },
71
- });
72
- queueMicrotask(() => { if (!api)
73
- rej(new Error('onApiReady never fired')); });
74
- });
75
- }
76
- const tick = () => new Promise((r) => queueMicrotask(r));
77
- function headerOrder(target) {
78
- const ths = target.querySelectorAll('th[data-svgrid-header-col]');
79
- return Array.from(ths).map((th) => th.dataset.svgridHeaderCol ?? '');
80
- }
81
- function header(target, id) {
82
- // jsdom doesn't ship CSS.escape; our ids are simple alphanumerics so
83
- // a plain attribute selector is fine.
84
- const el = target.querySelector(`th[data-svgrid-header-col="${id}"]`);
85
- if (!el)
86
- throw new Error(`header not found: ${id}`);
87
- return el;
88
- }
89
- describe('SvGrid column reorder - default off', () => {
90
- it('does NOT set draggable on headers when the prop is unset', async () => {
91
- const { target, destroy } = await mountGrid();
92
- try {
93
- await tick();
94
- const draggables = target.querySelectorAll('th[data-svgrid-header-col][draggable="true"]');
95
- expect(draggables.length).toBe(0);
96
- }
97
- finally {
98
- destroy();
99
- }
100
- });
101
- });
102
- describe('SvGrid column reorder - enableColumnReorder=true', () => {
103
- it('sets draggable=true on every visible header', async () => {
104
- const { target, destroy } = await mountGrid({ enableColumnReorder: true });
105
- try {
106
- await tick();
107
- const ths = target.querySelectorAll('th[data-svgrid-header-col]');
108
- expect(ths.length).toBe(cols.length);
109
- for (const th of ths) {
110
- expect(th.getAttribute('draggable')).toBe('true');
111
- }
112
- }
113
- finally {
114
- destroy();
115
- }
116
- });
117
- it('honors the initial columnOrder prop', async () => {
118
- const order = ['salary', 'id', 'last', 'first', 'team'];
119
- const { target, destroy } = await mountGrid({
120
- enableColumnReorder: true,
121
- columnOrder: order,
122
- });
123
- try {
124
- await tick();
125
- expect(headerOrder(target)).toEqual(order);
126
- }
127
- finally {
128
- destroy();
129
- }
130
- });
131
- });
132
- describe('SvGrid column reorder - imperative api', () => {
133
- it('api.getColumnOrder() returns the current visual order', async () => {
134
- const { api, destroy } = await mountGrid({ enableColumnReorder: true });
135
- try {
136
- expect(api.getColumnOrder()).toEqual(['id', 'first', 'last', 'team', 'salary']);
137
- }
138
- finally {
139
- destroy();
140
- }
141
- });
142
- it('api.setColumnOrder() reorders the DOM headers', async () => {
143
- const { target, api, destroy } = await mountGrid({ enableColumnReorder: true });
144
- try {
145
- api.setColumnOrder(['team', 'id', 'salary', 'first', 'last']);
146
- await tick();
147
- expect(headerOrder(target)).toEqual(['team', 'id', 'salary', 'first', 'last']);
148
- }
149
- finally {
150
- destroy();
151
- }
152
- });
153
- it('api.setColumnOrder() fires onColumnOrderChange with the new order', async () => {
154
- const events = [];
155
- const { api, destroy } = await mountGrid({
156
- enableColumnReorder: true,
157
- onColumnOrderChange: (order) => events.push([...order]),
158
- });
159
- try {
160
- api.setColumnOrder(['last', 'first', 'id', 'team', 'salary']);
161
- await tick();
162
- expect(events.length).toBeGreaterThanOrEqual(1);
163
- const latest = events[events.length - 1];
164
- expect(latest).toEqual(['last', 'first', 'id', 'team', 'salary']);
165
- }
166
- finally {
167
- destroy();
168
- }
169
- });
170
- it('api.setColumnOrder() with a partial list keeps unlisted columns in their existing relative position', async () => {
171
- // Pass only ['salary', 'id']; the other three keep their original
172
- // relative order AFTER the listed ones.
173
- const { target, api, destroy } = await mountGrid({ enableColumnReorder: true });
174
- try {
175
- api.setColumnOrder(['salary', 'id']);
176
- await tick();
177
- const order = headerOrder(target);
178
- expect(order[0]).toBe('salary');
179
- expect(order[1]).toBe('id');
180
- // The remaining columns (first / last / team) should follow,
181
- // in their original relative order from `cols`.
182
- expect(order.slice(2)).toEqual(['first', 'last', 'team']);
183
- }
184
- finally {
185
- destroy();
186
- }
187
- });
188
- });
189
- describe('SvGrid column reorder - drag wiring (DOM)', () => {
190
- // Note: jsdom does not ship `DragEvent`, so we can't drive the full
191
- // dragstart → dragover → drop pipeline end-to-end here. Real-browser
192
- // coverage lives in the Playwright suite. These tests verify that the
193
- // wiring IS present in the DOM so a real DragEvent would reach the
194
- // grid's reactive state.
195
- it('every header has dragstart / dragover / dragleave / drop / dragend listeners attached', async () => {
196
- const { target, destroy } = await mountGrid({ enableColumnReorder: true });
197
- try {
198
- await tick();
199
- const ths = target.querySelectorAll('th[data-svgrid-header-col]');
200
- expect(ths.length).toBe(cols.length);
201
- // Each <th> must be draggable AND have an onclick-equivalent
202
- // dispatch chain. We can't easily probe addEventListener
203
- // attachments, so use the `draggable` attribute as the proxy -
204
- // the grid only sets it when listeners are wired.
205
- for (const th of ths) {
206
- expect(th.getAttribute('draggable')).toBe('true');
207
- }
208
- }
209
- finally {
210
- destroy();
211
- }
212
- });
213
- it('does NOT add the drop-target class before any drag is initiated', async () => {
214
- const { target, destroy } = await mountGrid({ enableColumnReorder: true });
215
- try {
216
- await tick();
217
- const drop = target.querySelectorAll('.is-drag-target-before, .is-drag-target-after, .is-dragging');
218
- expect(drop.length).toBe(0);
219
- }
220
- finally {
221
- destroy();
222
- }
223
- });
224
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,96 +0,0 @@
1
- /**
2
- * Track C: free-text autocomplete cell type + editable cell comments.
3
- */
4
- import { describe, expect, it } from 'vitest';
5
- import { mount, unmount } from 'svelte';
6
- import SvGrid from './SvGrid.svelte';
7
- import { createCoreRowModel, tableFeatures } from './index';
8
- const features = tableFeatures({});
9
- const rows = [
10
- { id: 1, name: 'Ann', city: 'Paris' },
11
- { id: 2, name: 'Bo', city: 'Berlin' },
12
- ];
13
- const tick = () => new Promise((r) => queueMicrotask(r));
14
- function mountGrid(extraCols, props = {}) {
15
- return new Promise((res) => {
16
- const target = document.createElement('div');
17
- document.body.appendChild(target);
18
- const app = mount(SvGrid, {
19
- target,
20
- props: {
21
- data: rows,
22
- columns: [{ field: 'name', header: 'Name', width: 160, editorType: 'text' }, ...extraCols],
23
- features,
24
- _rowModels: { coreRowModel: createCoreRowModel() },
25
- rowHeight: 32,
26
- containerHeight: 360,
27
- virtualization: false,
28
- enableInlineEditing: true,
29
- enableCellSelection: true,
30
- onApiReady(api) {
31
- res({ api, target, destroy: () => { unmount(app); target.remove(); } });
32
- },
33
- ...props,
34
- },
35
- });
36
- });
37
- }
38
- function dataCell(target, col) {
39
- return target.querySelectorAll('.sv-grid-cell[data-svgrid-row]')[col];
40
- }
41
- describe('autocomplete cell type', () => {
42
- it('filters suggestions as you type and commits the picked option', async () => {
43
- const { api, target, destroy } = await mountGrid([
44
- {
45
- field: 'city',
46
- header: 'City',
47
- width: 200,
48
- editorType: 'autocomplete',
49
- editorOptions: ['Paris', 'Berlin', 'Boston', 'Brussels'],
50
- },
51
- ]);
52
- await tick();
53
- // city is the 2nd column => index 1 in the first row's cells
54
- const cell = target.querySelectorAll('.sv-grid-cell[data-svgrid-row="0"]')[1];
55
- cell.dispatchEvent(new MouseEvent('dblclick', { bubbles: true }));
56
- await tick();
57
- const input = target.querySelector('.sv-grid-cell-editor-autocomplete');
58
- expect(input).not.toBeNull();
59
- input.value = 'B';
60
- input.dispatchEvent(new Event('input', { bubbles: true }));
61
- await tick();
62
- const opts = [...target.querySelectorAll('.sv-grid-autocomplete-option')].map((b) => b.textContent?.trim());
63
- // 'B' matches Berlin, Boston, Brussels - not Paris
64
- expect(opts).toEqual(['Berlin', 'Boston', 'Brussels']);
65
- const berlin = [...target.querySelectorAll('.sv-grid-autocomplete-option')].find((b) => b.textContent?.trim() === 'Boston');
66
- berlin.dispatchEvent(new MouseEvent('mousedown', { bubbles: true }));
67
- await tick();
68
- expect(api.getCellValue(0, 'city')).toBe('Boston');
69
- destroy();
70
- });
71
- });
72
- describe('editable comments', () => {
73
- it('adds a comment via the context menu and emits onNoteChange', async () => {
74
- const changes = [];
75
- const { target, destroy } = await mountGrid([{ field: 'city', header: 'City', width: 200, editorType: 'text' }], { contextMenu: true, editableComments: true, onNoteChange: (e) => changes.push(e) });
76
- await tick();
77
- const cell = dataCell(target, 0);
78
- cell.dispatchEvent(new MouseEvent('contextmenu', { bubbles: true, cancelable: true }));
79
- await tick();
80
- const editItem = [...target.querySelectorAll('.sv-grid-context-menu .sv-grid-menu-item')].find((b) => b.textContent?.trim() === 'Edit comment');
81
- expect(editItem).toBeTruthy();
82
- editItem.click();
83
- await tick();
84
- const ta = target.querySelector('.sv-grid-comment-textarea');
85
- expect(ta).not.toBeNull();
86
- ta.value = 'Needs review';
87
- ta.dispatchEvent(new Event('input', { bubbles: true }));
88
- await tick();
89
- target.querySelector('.sv-grid-comment-save').click();
90
- await tick();
91
- expect(changes.length).toBe(1);
92
- expect(changes[0].note).toBe('Needs review');
93
- expect(target.querySelector('.sv-grid-comment-editor')).toBeNull();
94
- destroy();
95
- });
96
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,102 +0,0 @@
1
- /**
2
- * Right-click context menu (Track A). Mounts a grid with `contextMenu`,
3
- * fires a synthetic `contextmenu` event on a cell, and asserts the menu
4
- * opens with the expected items and that actions/close work.
5
- */
6
- import { describe, expect, it } from 'vitest';
7
- import { mount, unmount } from 'svelte';
8
- import SvGrid from './SvGrid.svelte';
9
- import { createCoreRowModel, createFilteredRowModel, createSortedRowModel, rowSelectionFeature, rowSortingFeature, sortFns, tableFeatures, } from './index';
10
- const features = tableFeatures({ rowSortingFeature, rowSelectionFeature });
11
- const rows = Array.from({ length: 6 }, (_, i) => ({
12
- id: i + 1,
13
- name: `Person ${i + 1}`,
14
- team: ['A', 'B'][i % 2],
15
- }));
16
- const cols = [
17
- { field: 'name', header: 'Name', width: 200, editorType: 'text' },
18
- { field: 'team', header: 'Team', width: 160, editorType: 'text' },
19
- ];
20
- const tick = () => new Promise((r) => queueMicrotask(r));
21
- function mountGrid(contextMenu) {
22
- return new Promise((res, rej) => {
23
- const target = document.createElement('div');
24
- document.body.appendChild(target);
25
- const app = mount(SvGrid, {
26
- target,
27
- props: {
28
- data: rows,
29
- columns: cols,
30
- features,
31
- _rowModels: {
32
- coreRowModel: createCoreRowModel(),
33
- filteredRowModel: createFilteredRowModel(),
34
- sortedRowModel: createSortedRowModel(sortFns),
35
- },
36
- rowHeight: 32,
37
- containerHeight: 400,
38
- virtualization: false,
39
- enableCellSelection: true,
40
- contextMenu,
41
- onApiReady(api) {
42
- res({ api, target, destroy: () => { unmount(app); target.remove(); } });
43
- },
44
- },
45
- });
46
- queueMicrotask(() => { if (!target.querySelector('[role="grid"]'))
47
- rej(new Error('no grid')); });
48
- });
49
- }
50
- function rightClickFirstCell(target) {
51
- const cell = target.querySelector('.sv-grid-cell[data-svgrid-row]');
52
- const r = cell.getBoundingClientRect();
53
- cell.dispatchEvent(new MouseEvent('contextmenu', { bubbles: true, cancelable: true, clientX: r.x + 4, clientY: r.y + 4 }));
54
- return cell;
55
- }
56
- describe('SvGrid context menu', () => {
57
- it('opens the default menu on right-click with the built-in items', async () => {
58
- const { target, destroy } = await mountGrid(true);
59
- await tick();
60
- rightClickFirstCell(target);
61
- await tick();
62
- const menu = target.querySelector('.sv-grid-context-menu');
63
- expect(menu).not.toBeNull();
64
- const labels = [...menu.querySelectorAll('.sv-grid-menu-item')].map((b) => b.textContent?.trim());
65
- expect(labels).toContain('Copy');
66
- expect(labels).toContain('Paste');
67
- expect(labels).toContain('Remove row');
68
- expect(labels).toContain('Remove column');
69
- destroy();
70
- });
71
- it('does not open when contextMenu is omitted (native menu shows)', async () => {
72
- const { target, destroy } = await mountGrid(undefined);
73
- await tick();
74
- const cell = target.querySelector('.sv-grid-cell[data-svgrid-row]');
75
- const ev = new MouseEvent('contextmenu', { bubbles: true, cancelable: true });
76
- cell.dispatchEvent(ev);
77
- await tick();
78
- expect(target.querySelector('.sv-grid-context-menu')).toBeNull();
79
- expect(ev.defaultPrevented).toBe(false);
80
- destroy();
81
- });
82
- it('renders only the configured custom items and runs the action', async () => {
83
- let ran = 0;
84
- const items = [
85
- 'copy',
86
- 'separator',
87
- { key: 'flag', label: 'Flag row', action: () => { ran += 1; } },
88
- ];
89
- const { target, destroy } = await mountGrid(items);
90
- await tick();
91
- rightClickFirstCell(target);
92
- await tick();
93
- const labels = [...target.querySelectorAll('.sv-grid-context-menu .sv-grid-menu-item')].map((b) => b.textContent?.trim());
94
- expect(labels).toEqual(['Copy', 'Flag row']);
95
- const flag = [...target.querySelectorAll('.sv-grid-context-menu .sv-grid-menu-item')].find((b) => b.textContent?.trim() === 'Flag row');
96
- flag.click();
97
- expect(ran).toBe(1);
98
- await tick();
99
- expect(target.querySelector('.sv-grid-context-menu')).toBeNull();
100
- destroy();
101
- });
102
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,129 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { columnFilteringFeature, columnGroupingFeature, createCoreRowModel, createExpandedRowModel, createFilteredRowModel, createGroupedRowModel, createPaginatedRowModel, createSortedRowModel, createSvGrid, rowExpandingFeature, rowSelectionFeature, rowSortingFeature, sortFns, subscribeSvGrid, tableFeatures, } from './index';
3
- describe('SvGrid features', () => {
4
- it('supports sorting and pagination row model pipeline', () => {
5
- const _features = tableFeatures({
6
- columnFilteringFeature,
7
- columnGroupingFeature,
8
- rowExpandingFeature,
9
- rowSelectionFeature,
10
- rowSortingFeature,
11
- });
12
- const columns = [
13
- { field: 'firstName' },
14
- { field: 'age' },
15
- ];
16
- const data = [
17
- { firstName: 'John', age: 40, status: 'pending' },
18
- { firstName: 'Amy', age: 22, status: 'active' },
19
- { firstName: 'Kate', age: 31, status: 'active' },
20
- ];
21
- const grid = createSvGrid({
22
- _features,
23
- _rowModels: {
24
- coreRowModel: createCoreRowModel(),
25
- filteredRowModel: createFilteredRowModel(),
26
- sortedRowModel: createSortedRowModel(sortFns),
27
- groupedRowModel: createGroupedRowModel(),
28
- expandedRowModel: createExpandedRowModel(),
29
- paginatedRowModel: createPaginatedRowModel(),
30
- },
31
- columns,
32
- data,
33
- state: {
34
- columnFilters: [{ id: 'firstName', value: 'a', fn: 'includesString' }],
35
- grouping: ['status'],
36
- expanded: { group_status_active: true },
37
- sorting: [{ id: 'age', desc: false }],
38
- pagination: { pageIndex: 0, pageSize: 2 },
39
- },
40
- });
41
- const rows = grid.getRowModel().rows;
42
- expect(rows).toHaveLength(1);
43
- expect(rows[0]?.id).toContain('group_status_');
44
- });
45
- it('supports row selection and expansion toggles', () => {
46
- const _features = tableFeatures({
47
- rowExpandingFeature,
48
- rowSelectionFeature,
49
- });
50
- const columns = [
51
- { field: 'firstName' },
52
- ];
53
- const data = [
54
- { firstName: 'Amy', age: 22 },
55
- ];
56
- const grid = createSvGrid({
57
- _features,
58
- _rowModels: {
59
- coreRowModel: createCoreRowModel(),
60
- },
61
- columns,
62
- data,
63
- });
64
- const row = grid.getRowModel().rows[0];
65
- expect(row).toBeDefined();
66
- row?.toggleSelected();
67
- row?.toggleExpanded();
68
- expect(row?.getIsSelected()).toBe(true);
69
- expect(row?.getIsExpanded()).toBe(true);
70
- });
71
- it('supports selector subscriptions with stable shape', () => {
72
- const _features = tableFeatures({ rowSortingFeature });
73
- const grid = createSvGrid({
74
- _features,
75
- _rowModels: {
76
- coreRowModel: createCoreRowModel(),
77
- },
78
- columns: [{ field: 'firstName' }],
79
- data: [{ firstName: 'Amy', age: 22 }],
80
- });
81
- const selected = subscribeSvGrid(grid, (state) => ({
82
- sorting: state.sorting,
83
- pageIndex: state.pagination?.pageIndex ?? 0,
84
- }));
85
- expect(selected.current.pageIndex).toBe(0);
86
- });
87
- it('supports active cell movement primitives', () => {
88
- const _features = tableFeatures({ rowSortingFeature });
89
- const grid = createSvGrid({
90
- _features,
91
- _rowModels: { coreRowModel: createCoreRowModel() },
92
- columns: [
93
- { field: 'firstName' },
94
- { field: 'age' },
95
- ],
96
- data: [
97
- { firstName: 'Amy', age: 22 },
98
- { firstName: 'John', age: 40 },
99
- ],
100
- });
101
- grid.moveActiveCell({ rowDelta: 1, colDelta: 1 });
102
- expect(grid.getState().activeCell.rowIndex).toBe(1);
103
- expect(grid.getState().activeCell.colIndex).toBe(1);
104
- });
105
- it('supports multi-column sorting clauses', () => {
106
- const _features = tableFeatures({ rowSortingFeature });
107
- const grid = createSvGrid({
108
- _features,
109
- _rowModels: {
110
- coreRowModel: createCoreRowModel(),
111
- sortedRowModel: createSortedRowModel(sortFns),
112
- },
113
- columns: [
114
- { field: 'firstName' },
115
- { field: 'age', editorType: 'number' },
116
- ],
117
- data: [
118
- { firstName: 'Amy', age: 20 },
119
- { firstName: 'Amy', age: 30 },
120
- { firstName: 'Bob', age: 10 },
121
- ],
122
- state: { sorting: [{ id: 'firstName', desc: false }, { id: 'age', desc: true }] },
123
- });
124
- const rows = grid.getRowModel().rows;
125
- expect(rows[0]?.original.firstName).toBe('Amy');
126
- expect(rows[0]?.original.age).toBe(30);
127
- expect(rows[1]?.original.age).toBe(20);
128
- });
129
- });
@@ -1,9 +0,0 @@
1
- /**
2
- * Interaction-driven tests against <SvGrid />. Targeting code paths that
3
- * only run in response to events: keyboard, pointer, scroll, edit lifecycle.
4
- *
5
- * Each test mounts a small grid, fires a synthetic event, awaits a tick,
6
- * then asserts on the api object's snapshot. The goal is breadth: hit as
7
- * many branches inside SvGrid.svelte as possible.
8
- */
9
- export {};