@svgrid/grid 1.0.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 (213) hide show
  1. package/LICENSE +33 -0
  2. package/README.md +39 -0
  3. package/dist/FlexRender.svelte +96 -0
  4. package/dist/FlexRender.svelte.d.ts +49 -0
  5. package/dist/SvGrid.svelte +8742 -0
  6. package/dist/SvGrid.svelte.d.ts +381 -0
  7. package/dist/SvGridChart.svelte +653 -0
  8. package/dist/SvGridChart.svelte.d.ts +25 -0
  9. package/dist/SvGridChart.test.d.ts +1 -0
  10. package/dist/SvGridChart.test.js +62 -0
  11. package/dist/SvGridDropdown.svelte +675 -0
  12. package/dist/SvGridDropdown.svelte.d.ts +40 -0
  13. package/dist/a11y.contract.test.d.ts +1 -0
  14. package/dist/a11y.contract.test.js +39 -0
  15. package/dist/a11y.d.ts +38 -0
  16. package/dist/a11y.js +37 -0
  17. package/dist/a11y.test.d.ts +1 -0
  18. package/dist/a11y.test.js +44 -0
  19. package/dist/cell-formatting.d.ts +17 -0
  20. package/dist/cell-formatting.js +141 -0
  21. package/dist/cell-formatting.test.d.ts +1 -0
  22. package/dist/cell-formatting.test.js +234 -0
  23. package/dist/chart-export.d.ts +14 -0
  24. package/dist/chart-export.js +112 -0
  25. package/dist/chart.d.ts +226 -0
  26. package/dist/chart.js +732 -0
  27. package/dist/chart.test.d.ts +1 -0
  28. package/dist/chart.test.js +289 -0
  29. package/dist/collaboration.d.ts +74 -0
  30. package/dist/collaboration.js +98 -0
  31. package/dist/collaboration.test.d.ts +1 -0
  32. package/dist/collaboration.test.js +65 -0
  33. package/dist/conditional-formatting.d.ts +91 -0
  34. package/dist/conditional-formatting.js +170 -0
  35. package/dist/conditional-formatting.test.d.ts +1 -0
  36. package/dist/conditional-formatting.test.js +87 -0
  37. package/dist/core.coverage.test.d.ts +1 -0
  38. package/dist/core.coverage.test.js +186 -0
  39. package/dist/core.d.ts +370 -0
  40. package/dist/core.js +568 -0
  41. package/dist/core.performance.test.d.ts +1 -0
  42. package/dist/core.performance.test.js +29 -0
  43. package/dist/createGrid.svelte.d.ts +6 -0
  44. package/dist/createGrid.svelte.js +17 -0
  45. package/dist/createGrid.test.d.ts +1 -0
  46. package/dist/createGrid.test.js +9 -0
  47. package/dist/createGridState.svelte.d.ts +3 -0
  48. package/dist/createGridState.svelte.js +13 -0
  49. package/dist/editors/cell-editors.d.ts +23 -0
  50. package/dist/editors/cell-editors.js +97 -0
  51. package/dist/editors/cell-editors.test.d.ts +1 -0
  52. package/dist/editors/cell-editors.test.js +75 -0
  53. package/dist/fill-patterns.d.ts +30 -0
  54. package/dist/fill-patterns.js +207 -0
  55. package/dist/fill-patterns.test.d.ts +1 -0
  56. package/dist/fill-patterns.test.js +81 -0
  57. package/dist/filtering/excel-filters.d.ts +26 -0
  58. package/dist/filtering/excel-filters.js +64 -0
  59. package/dist/filtering/excel-filters.test.d.ts +1 -0
  60. package/dist/filtering/excel-filters.test.js +116 -0
  61. package/dist/filtering/locale-filter.test.d.ts +13 -0
  62. package/dist/filtering/locale-filter.test.js +189 -0
  63. package/dist/flex-render.d.ts +1 -0
  64. package/dist/flex-render.js +2 -0
  65. package/dist/flex-render.test.d.ts +1 -0
  66. package/dist/flex-render.test.js +142 -0
  67. package/dist/group-aggregate.test.d.ts +1 -0
  68. package/dist/group-aggregate.test.js +32 -0
  69. package/dist/index.d.ts +29 -0
  70. package/dist/index.js +27 -0
  71. package/dist/keyboard.d.ts +8 -0
  72. package/dist/keyboard.js +91 -0
  73. package/dist/keyboard.test.d.ts +1 -0
  74. package/dist/keyboard.test.js +27 -0
  75. package/dist/merge-objects.d.ts +9 -0
  76. package/dist/merge-objects.js +28 -0
  77. package/dist/named-views.d.ts +42 -0
  78. package/dist/named-views.js +80 -0
  79. package/dist/named-views.test.d.ts +1 -0
  80. package/dist/named-views.test.js +57 -0
  81. package/dist/new-features.test.d.ts +1 -0
  82. package/dist/new-features.test.js +183 -0
  83. package/dist/render-component.d.ts +13 -0
  84. package/dist/render-component.js +14 -0
  85. package/dist/render-component.test.d.ts +1 -0
  86. package/dist/render-component.test.js +41 -0
  87. package/dist/server-data-source.d.ts +76 -0
  88. package/dist/server-data-source.js +83 -0
  89. package/dist/server-data-source.test.d.ts +1 -0
  90. package/dist/server-data-source.test.js +81 -0
  91. package/dist/sparkline.d.ts +56 -0
  92. package/dist/sparkline.js +97 -0
  93. package/dist/sparkline.test.d.ts +1 -0
  94. package/dist/sparkline.test.js +52 -0
  95. package/dist/static-functions.d.ts +1 -0
  96. package/dist/static-functions.js +1 -0
  97. package/dist/subscribe.d.ts +9 -0
  98. package/dist/subscribe.js +31 -0
  99. package/dist/subscribe.test.d.ts +1 -0
  100. package/dist/subscribe.test.js +93 -0
  101. package/dist/sv-grid-scrollbar.d.ts +1 -0
  102. package/dist/sv-grid-scrollbar.js +310 -0
  103. package/dist/svgrid-wrapper.types.d.ts +341 -0
  104. package/dist/svgrid-wrapper.types.js +1 -0
  105. package/dist/svgrid.api-extensions.test.d.ts +14 -0
  106. package/dist/svgrid.api-extensions.test.js +334 -0
  107. package/dist/svgrid.api.test.d.ts +15 -0
  108. package/dist/svgrid.api.test.js +169 -0
  109. package/dist/svgrid.behavior.test.d.ts +15 -0
  110. package/dist/svgrid.behavior.test.js +605 -0
  111. package/dist/svgrid.column-reorder.test.d.ts +15 -0
  112. package/dist/svgrid.column-reorder.test.js +224 -0
  113. package/dist/svgrid.features.test.d.ts +1 -0
  114. package/dist/svgrid.features.test.js +129 -0
  115. package/dist/svgrid.interaction.test.d.ts +9 -0
  116. package/dist/svgrid.interaction.test.js +318 -0
  117. package/dist/svgrid.locale-filtering.test.d.ts +15 -0
  118. package/dist/svgrid.locale-filtering.test.js +261 -0
  119. package/dist/svgrid.new-features.wrapper.test.d.ts +1 -0
  120. package/dist/svgrid.new-features.wrapper.test.js +136 -0
  121. package/dist/svgrid.row-pinning.test.d.ts +14 -0
  122. package/dist/svgrid.row-pinning.test.js +250 -0
  123. package/dist/svgrid.set-filter.test.d.ts +17 -0
  124. package/dist/svgrid.set-filter.test.js +268 -0
  125. package/dist/svgrid.wrapper.test.d.ts +1 -0
  126. package/dist/svgrid.wrapper.test.js +33 -0
  127. package/dist/test-setup.d.ts +1 -0
  128. package/dist/test-setup.js +29 -0
  129. package/dist/transaction.test.d.ts +1 -0
  130. package/dist/transaction.test.js +89 -0
  131. package/dist/virtualization/column-virtualizer.d.ts +20 -0
  132. package/dist/virtualization/column-virtualizer.js +19 -0
  133. package/dist/virtualization/column-virtualizer.test.d.ts +1 -0
  134. package/dist/virtualization/column-virtualizer.test.js +25 -0
  135. package/dist/virtualization/svelte-virtualizer.svelte.d.ts +11 -0
  136. package/dist/virtualization/svelte-virtualizer.svelte.js +20 -0
  137. package/dist/virtualization/types.d.ts +28 -0
  138. package/dist/virtualization/types.js +1 -0
  139. package/dist/virtualization/virtualizer.d.ts +13 -0
  140. package/dist/virtualization/virtualizer.js +232 -0
  141. package/dist/virtualization/virtualizer.test.d.ts +1 -0
  142. package/dist/virtualization/virtualizer.test.js +41 -0
  143. package/package.json +69 -0
  144. package/src/FlexRender.svelte +96 -0
  145. package/src/SvGrid.svelte +8742 -0
  146. package/src/SvGridChart.svelte +653 -0
  147. package/src/SvGridChart.test.ts +69 -0
  148. package/src/SvGridDropdown.svelte +675 -0
  149. package/src/a11y.contract.test.ts +49 -0
  150. package/src/a11y.test.ts +59 -0
  151. package/src/a11y.ts +59 -0
  152. package/src/cell-formatting.test.ts +273 -0
  153. package/src/cell-formatting.ts +169 -0
  154. package/src/chart-export.ts +144 -0
  155. package/src/chart.test.ts +311 -0
  156. package/src/chart.ts +934 -0
  157. package/src/collaboration.test.ts +74 -0
  158. package/src/collaboration.ts +161 -0
  159. package/src/conditional-formatting.test.ts +107 -0
  160. package/src/conditional-formatting.ts +239 -0
  161. package/src/core.coverage.test.ts +230 -0
  162. package/src/core.performance.test.ts +30 -0
  163. package/src/core.ts +991 -0
  164. package/src/createGrid.svelte.ts +42 -0
  165. package/src/createGrid.test.ts +10 -0
  166. package/src/createGridState.svelte.ts +17 -0
  167. package/src/editors/cell-editors.test.ts +80 -0
  168. package/src/editors/cell-editors.ts +127 -0
  169. package/src/fill-patterns.test.ts +93 -0
  170. package/src/fill-patterns.ts +229 -0
  171. package/src/filtering/excel-filters.test.ts +131 -0
  172. package/src/filtering/excel-filters.ts +101 -0
  173. package/src/filtering/locale-filter.test.ts +220 -0
  174. package/src/flex-render.test.ts +143 -0
  175. package/src/flex-render.ts +3 -0
  176. package/src/group-aggregate.test.ts +48 -0
  177. package/src/index.ts +159 -0
  178. package/src/keyboard.test.ts +59 -0
  179. package/src/keyboard.ts +97 -0
  180. package/src/merge-objects.ts +48 -0
  181. package/src/named-views.test.ts +66 -0
  182. package/src/named-views.ts +120 -0
  183. package/src/new-features.test.ts +217 -0
  184. package/src/render-component.test.ts +51 -0
  185. package/src/render-component.ts +28 -0
  186. package/src/server-data-source.test.ts +88 -0
  187. package/src/server-data-source.ts +163 -0
  188. package/src/sparkline.test.ts +59 -0
  189. package/src/sparkline.ts +164 -0
  190. package/src/static-functions.ts +11 -0
  191. package/src/subscribe.test.ts +103 -0
  192. package/src/subscribe.ts +38 -0
  193. package/src/sv-grid-scrollbar.ts +347 -0
  194. package/src/svgrid-wrapper.types.ts +382 -0
  195. package/src/svgrid.api-extensions.test.ts +362 -0
  196. package/src/svgrid.api.test.ts +192 -0
  197. package/src/svgrid.behavior.test.ts +657 -0
  198. package/src/svgrid.column-reorder.test.ts +234 -0
  199. package/src/svgrid.features.test.ts +157 -0
  200. package/src/svgrid.interaction.test.ts +355 -0
  201. package/src/svgrid.locale-filtering.test.ts +259 -0
  202. package/src/svgrid.new-features.wrapper.test.ts +164 -0
  203. package/src/svgrid.row-pinning.test.ts +266 -0
  204. package/src/svgrid.set-filter.test.ts +270 -0
  205. package/src/svgrid.wrapper.test.ts +35 -0
  206. package/src/test-setup.ts +37 -0
  207. package/src/transaction.test.ts +100 -0
  208. package/src/virtualization/column-virtualizer.test.ts +27 -0
  209. package/src/virtualization/column-virtualizer.ts +30 -0
  210. package/src/virtualization/svelte-virtualizer.svelte.ts +24 -0
  211. package/src/virtualization/types.ts +30 -0
  212. package/src/virtualization/virtualizer.test.ts +47 -0
  213. package/src/virtualization/virtualizer.ts +270 -0
@@ -0,0 +1,234 @@
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
+
16
+ import { describe, expect, it } from 'vitest'
17
+ import { mount, unmount } from 'svelte'
18
+ import SvGrid from './SvGrid.svelte'
19
+ import {
20
+ columnFilteringFeature,
21
+ createCoreRowModel,
22
+ createFilteredRowModel,
23
+ createSortedRowModel,
24
+ rowSortingFeature,
25
+ sortFns,
26
+ tableFeatures,
27
+ } from './index'
28
+ import type { ColumnDef, SvGridApi } from './index'
29
+
30
+ type Row = { id: string; first: string; last: string; team: string; salary: number }
31
+
32
+ const features = tableFeatures({ columnFilteringFeature, rowSortingFeature })
33
+
34
+ const rows: Row[] = [
35
+ { id: 'P-1', first: 'Ada', last: 'Lovelace', team: 'Research', salary: 145_000 },
36
+ { id: 'P-2', first: 'Linus', last: 'Torvalds', team: 'Kernel', salary: 188_000 },
37
+ { id: 'P-3', first: 'Grace', last: 'Hopper', team: 'Compilers', salary: 152_000 },
38
+ ]
39
+
40
+ const cols: ColumnDef<typeof features, Row>[] = [
41
+ { field: 'id', header: 'ID', width: 100 },
42
+ { field: 'first', header: 'First', width: 140 },
43
+ { field: 'last', header: 'Last', width: 140 },
44
+ { field: 'team', header: 'Team', width: 160 },
45
+ { field: 'salary', header: 'Salary', width: 130 },
46
+ ]
47
+
48
+ type MountOpts = {
49
+ enableColumnReorder?: boolean
50
+ columnOrder?: string[]
51
+ onColumnOrderChange?: (order: ReadonlyArray<string>) => void
52
+ }
53
+
54
+ function mountGrid(opts: MountOpts = {}) {
55
+ return new Promise<{
56
+ target: HTMLElement
57
+ api: SvGridApi<typeof features, Row>
58
+ destroy: () => void
59
+ }>((res, rej) => {
60
+ const target = document.createElement('div')
61
+ document.body.appendChild(target)
62
+ let api: SvGridApi<typeof features, Row> | null = null
63
+ const app = mount(SvGrid, {
64
+ target,
65
+ props: {
66
+ data: rows,
67
+ columns: cols,
68
+ features,
69
+ _rowModels: {
70
+ coreRowModel: createCoreRowModel(),
71
+ filteredRowModel: createFilteredRowModel(),
72
+ sortedRowModel: createSortedRowModel(sortFns),
73
+ },
74
+ containerHeight: 360,
75
+ virtualization: false,
76
+ columnVirtualization: false,
77
+ enableInlineEditing: false,
78
+ showPagination: false,
79
+ showColumnFilters: false,
80
+ showGlobalFilter: false,
81
+ showRowSelection: false,
82
+ enableColumnReorder: opts.enableColumnReorder,
83
+ columnOrder: opts.columnOrder,
84
+ onColumnOrderChange: opts.onColumnOrderChange,
85
+ onApiReady(received: SvGridApi<typeof features, Row>) {
86
+ api = received
87
+ res({
88
+ target,
89
+ api,
90
+ destroy: () => {
91
+ unmount(app)
92
+ target.remove()
93
+ },
94
+ })
95
+ },
96
+ } as any,
97
+ })
98
+ queueMicrotask(() => { if (!api) rej(new Error('onApiReady never fired')) })
99
+ })
100
+ }
101
+
102
+ const tick = () => new Promise<void>((r) => queueMicrotask(r))
103
+
104
+ function headerOrder(target: HTMLElement): string[] {
105
+ const ths = target.querySelectorAll<HTMLElement>('th[data-svgrid-header-col]')
106
+ return Array.from(ths).map((th) => th.dataset.svgridHeaderCol ?? '')
107
+ }
108
+
109
+ function header(target: HTMLElement, id: string): HTMLElement {
110
+ // jsdom doesn't ship CSS.escape; our ids are simple alphanumerics so
111
+ // a plain attribute selector is fine.
112
+ const el = target.querySelector<HTMLElement>(`th[data-svgrid-header-col="${id}"]`)
113
+ if (!el) throw new Error(`header not found: ${id}`)
114
+ return el
115
+ }
116
+
117
+ describe('SvGrid column reorder - default off', () => {
118
+ it('does NOT set draggable on headers when the prop is unset', async () => {
119
+ const { target, destroy } = await mountGrid()
120
+ try {
121
+ await tick()
122
+ const draggables = target.querySelectorAll('th[data-svgrid-header-col][draggable="true"]')
123
+ expect(draggables.length).toBe(0)
124
+ } finally { destroy() }
125
+ })
126
+ })
127
+
128
+ describe('SvGrid column reorder - enableColumnReorder=true', () => {
129
+ it('sets draggable=true on every visible header', async () => {
130
+ const { target, destroy } = await mountGrid({ enableColumnReorder: true })
131
+ try {
132
+ await tick()
133
+ const ths = target.querySelectorAll<HTMLElement>('th[data-svgrid-header-col]')
134
+ expect(ths.length).toBe(cols.length)
135
+ for (const th of ths) {
136
+ expect(th.getAttribute('draggable')).toBe('true')
137
+ }
138
+ } finally { destroy() }
139
+ })
140
+
141
+ it('honors the initial columnOrder prop', async () => {
142
+ const order = ['salary', 'id', 'last', 'first', 'team']
143
+ const { target, destroy } = await mountGrid({
144
+ enableColumnReorder: true,
145
+ columnOrder: order,
146
+ })
147
+ try {
148
+ await tick()
149
+ expect(headerOrder(target)).toEqual(order)
150
+ } finally { destroy() }
151
+ })
152
+ })
153
+
154
+ describe('SvGrid column reorder - imperative api', () => {
155
+ it('api.getColumnOrder() returns the current visual order', async () => {
156
+ const { api, destroy } = await mountGrid({ enableColumnReorder: true })
157
+ try {
158
+ expect(api.getColumnOrder()).toEqual(['id', 'first', 'last', 'team', 'salary'])
159
+ } finally { destroy() }
160
+ })
161
+
162
+ it('api.setColumnOrder() reorders the DOM headers', async () => {
163
+ const { target, api, destroy } = await mountGrid({ enableColumnReorder: true })
164
+ try {
165
+ api.setColumnOrder(['team', 'id', 'salary', 'first', 'last'])
166
+ await tick()
167
+ expect(headerOrder(target)).toEqual(['team', 'id', 'salary', 'first', 'last'])
168
+ } finally { destroy() }
169
+ })
170
+
171
+ it('api.setColumnOrder() fires onColumnOrderChange with the new order', async () => {
172
+ const events: string[][] = []
173
+ const { api, destroy } = await mountGrid({
174
+ enableColumnReorder: true,
175
+ onColumnOrderChange: (order) => events.push([...order]),
176
+ })
177
+ try {
178
+ api.setColumnOrder(['last', 'first', 'id', 'team', 'salary'])
179
+ await tick()
180
+ expect(events.length).toBeGreaterThanOrEqual(1)
181
+ const latest = events[events.length - 1]!
182
+ expect(latest).toEqual(['last', 'first', 'id', 'team', 'salary'])
183
+ } finally { destroy() }
184
+ })
185
+
186
+ it('api.setColumnOrder() with a partial list keeps unlisted columns in their existing relative position', async () => {
187
+ // Pass only ['salary', 'id']; the other three keep their original
188
+ // relative order AFTER the listed ones.
189
+ const { target, api, destroy } = await mountGrid({ enableColumnReorder: true })
190
+ try {
191
+ api.setColumnOrder(['salary', 'id'])
192
+ await tick()
193
+ const order = headerOrder(target)
194
+ expect(order[0]).toBe('salary')
195
+ expect(order[1]).toBe('id')
196
+ // The remaining columns (first / last / team) should follow,
197
+ // in their original relative order from `cols`.
198
+ expect(order.slice(2)).toEqual(['first', 'last', 'team'])
199
+ } finally { destroy() }
200
+ })
201
+ })
202
+
203
+ describe('SvGrid column reorder - drag wiring (DOM)', () => {
204
+ // Note: jsdom does not ship `DragEvent`, so we can't drive the full
205
+ // dragstart → dragover → drop pipeline end-to-end here. Real-browser
206
+ // coverage lives in the Playwright suite. These tests verify that the
207
+ // wiring IS present in the DOM so a real DragEvent would reach the
208
+ // grid's reactive state.
209
+
210
+ it('every header has dragstart / dragover / dragleave / drop / dragend listeners attached', async () => {
211
+ const { target, destroy } = await mountGrid({ enableColumnReorder: true })
212
+ try {
213
+ await tick()
214
+ const ths = target.querySelectorAll<HTMLElement>('th[data-svgrid-header-col]')
215
+ expect(ths.length).toBe(cols.length)
216
+ // Each <th> must be draggable AND have an onclick-equivalent
217
+ // dispatch chain. We can't easily probe addEventListener
218
+ // attachments, so use the `draggable` attribute as the proxy -
219
+ // the grid only sets it when listeners are wired.
220
+ for (const th of ths) {
221
+ expect(th.getAttribute('draggable')).toBe('true')
222
+ }
223
+ } finally { destroy() }
224
+ })
225
+
226
+ it('does NOT add the drop-target class before any drag is initiated', async () => {
227
+ const { target, destroy } = await mountGrid({ enableColumnReorder: true })
228
+ try {
229
+ await tick()
230
+ const drop = target.querySelectorAll('.is-drag-target-before, .is-drag-target-after, .is-dragging')
231
+ expect(drop.length).toBe(0)
232
+ } finally { destroy() }
233
+ })
234
+ })
@@ -0,0 +1,157 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import {
3
+ columnFilteringFeature,
4
+ columnGroupingFeature,
5
+ createCoreRowModel,
6
+ createExpandedRowModel,
7
+ createFilteredRowModel,
8
+ createGroupedRowModel,
9
+ createPaginatedRowModel,
10
+ createSortedRowModel,
11
+ createSvGrid,
12
+ rowExpandingFeature,
13
+ rowSelectionFeature,
14
+ rowSortingFeature,
15
+ sortFns,
16
+ subscribeSvGrid,
17
+ tableFeatures,
18
+ } from './index'
19
+ import type { ColumnDef } from './index'
20
+
21
+ type Person = { firstName: string; age: number; status?: string }
22
+
23
+ describe('SvGrid features', () => {
24
+ it('supports sorting and pagination row model pipeline', () => {
25
+ const _features = tableFeatures({
26
+ columnFilteringFeature,
27
+ columnGroupingFeature,
28
+ rowExpandingFeature,
29
+ rowSelectionFeature,
30
+ rowSortingFeature,
31
+ })
32
+ const columns: Array<ColumnDef<typeof _features, Person>> = [
33
+ { field: 'firstName' },
34
+ { field: 'age' },
35
+ ]
36
+ const data: Array<Person> = [
37
+ { firstName: 'John', age: 40, status: 'pending' },
38
+ { firstName: 'Amy', age: 22, status: 'active' },
39
+ { firstName: 'Kate', age: 31, status: 'active' },
40
+ ]
41
+
42
+ const grid = createSvGrid({
43
+ _features,
44
+ _rowModels: {
45
+ coreRowModel: createCoreRowModel(),
46
+ filteredRowModel: createFilteredRowModel(),
47
+ sortedRowModel: createSortedRowModel(sortFns),
48
+ groupedRowModel: createGroupedRowModel(),
49
+ expandedRowModel: createExpandedRowModel(),
50
+ paginatedRowModel: createPaginatedRowModel(),
51
+ },
52
+ columns,
53
+ data,
54
+ state: {
55
+ columnFilters: [{ id: 'firstName', value: 'a', fn: 'includesString' }],
56
+ grouping: ['status'],
57
+ expanded: { group_status_active: true },
58
+ sorting: [{ id: 'age', desc: false }],
59
+ pagination: { pageIndex: 0, pageSize: 2 },
60
+ },
61
+ })
62
+
63
+ const rows = grid.getRowModel().rows
64
+ expect(rows).toHaveLength(1)
65
+ expect(rows[0]?.id).toContain('group_status_')
66
+ })
67
+
68
+ it('supports row selection and expansion toggles', () => {
69
+ const _features = tableFeatures({
70
+ rowExpandingFeature,
71
+ rowSelectionFeature,
72
+ })
73
+ const columns: Array<ColumnDef<typeof _features, Person>> = [
74
+ { field: 'firstName' },
75
+ ]
76
+ const data: Array<Person> = [
77
+ { firstName: 'Amy', age: 22 },
78
+ ]
79
+ const grid = createSvGrid({
80
+ _features,
81
+ _rowModels: {
82
+ coreRowModel: createCoreRowModel(),
83
+ },
84
+ columns,
85
+ data,
86
+ })
87
+ const row = grid.getRowModel().rows[0]
88
+ expect(row).toBeDefined()
89
+ row?.toggleSelected()
90
+ row?.toggleExpanded()
91
+ expect(row?.getIsSelected()).toBe(true)
92
+ expect(row?.getIsExpanded()).toBe(true)
93
+ })
94
+
95
+ it('supports selector subscriptions with stable shape', () => {
96
+ const _features = tableFeatures({ rowSortingFeature })
97
+ const grid = createSvGrid({
98
+ _features,
99
+ _rowModels: {
100
+ coreRowModel: createCoreRowModel(),
101
+ },
102
+ columns: [{ field: 'firstName' }],
103
+ data: [{ firstName: 'Amy', age: 22 }],
104
+ })
105
+ const selected = subscribeSvGrid(grid, (state) => ({
106
+ sorting: state.sorting,
107
+ pageIndex: state.pagination?.pageIndex ?? 0,
108
+ }))
109
+ expect(selected.current.pageIndex).toBe(0)
110
+ })
111
+
112
+ it('supports active cell movement primitives', () => {
113
+ const _features = tableFeatures({ rowSortingFeature })
114
+ const grid = createSvGrid({
115
+ _features,
116
+ _rowModels: { coreRowModel: createCoreRowModel() },
117
+ columns: [
118
+ { field: 'firstName' },
119
+ { field: 'age' },
120
+ ],
121
+ data: [
122
+ { firstName: 'Amy', age: 22 },
123
+ { firstName: 'John', age: 40 },
124
+ ],
125
+ })
126
+
127
+ grid.moveActiveCell({ rowDelta: 1, colDelta: 1 })
128
+ expect(grid.getState().activeCell.rowIndex).toBe(1)
129
+ expect(grid.getState().activeCell.colIndex).toBe(1)
130
+ })
131
+
132
+ it('supports multi-column sorting clauses', () => {
133
+ const _features = tableFeatures({ rowSortingFeature })
134
+ const grid = createSvGrid({
135
+ _features,
136
+ _rowModels: {
137
+ coreRowModel: createCoreRowModel(),
138
+ sortedRowModel: createSortedRowModel(sortFns),
139
+ },
140
+ columns: [
141
+ { field: 'firstName' },
142
+ { field: 'age', editorType: 'number' },
143
+ ],
144
+ data: [
145
+ { firstName: 'Amy', age: 20 },
146
+ { firstName: 'Amy', age: 30 },
147
+ { firstName: 'Bob', age: 10 },
148
+ ],
149
+ state: { sorting: [{ id: 'firstName', desc: false }, { id: 'age', desc: true }] },
150
+ })
151
+
152
+ const rows = grid.getRowModel().rows
153
+ expect(rows[0]?.original.firstName).toBe('Amy')
154
+ expect(rows[0]?.original.age).toBe(30)
155
+ expect(rows[1]?.original.age).toBe(20)
156
+ })
157
+ })