@svgrid/grid 2.6.21 → 2.6.23

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 (151) hide show
  1. package/CHANGELOG.md +62 -0
  2. package/README.md +22 -0
  3. package/dist/GridMenus.svelte +201 -18
  4. package/dist/SvAutoComplete.svelte +4 -0
  5. package/dist/SvComboBox.svelte +5 -1
  6. package/dist/SvDateRangeInput.svelte +25 -3
  7. package/dist/SvDropDownList.svelte +4 -0
  8. package/dist/SvForm.svelte +8 -8
  9. package/dist/SvGrid.controller.svelte.d.ts +61 -9
  10. package/dist/SvGrid.controller.svelte.js +363 -123
  11. package/dist/SvGrid.css +222 -1
  12. package/dist/SvGrid.helpers.d.ts +55 -0
  13. package/dist/SvGrid.helpers.js +83 -0
  14. package/dist/SvGrid.svelte +255 -56
  15. package/dist/SvGrid.types.d.ts +146 -1
  16. package/dist/SvGridCellEditor.svelte +99 -17
  17. package/dist/SvGridSelect.svelte +6 -2
  18. package/dist/SvGridSelect.svelte.d.ts +1 -1
  19. package/dist/SvListBox.svelte +8 -0
  20. package/dist/SvMultiSelect.svelte +6 -2
  21. package/dist/SvMultiSelect.svelte.d.ts +1 -1
  22. package/dist/SvNumberInput.svelte +4 -0
  23. package/dist/SvRichCell.svelte +125 -0
  24. package/dist/SvRichCell.svelte.d.ts +15 -0
  25. package/dist/SvTextArea.svelte +5 -1
  26. package/dist/SvTreeSelect.svelte +6 -2
  27. package/dist/SvTreeSelect.svelte.d.ts +1 -1
  28. package/dist/builtin-editors.d.ts +2 -2
  29. package/dist/builtin-editors.js +19 -3
  30. package/dist/cdn/GridMenus-BzWXQjv3.js +600 -0
  31. package/dist/cdn/GridMenus-xr_rHx8F.js +601 -0
  32. package/dist/cdn/SvDateRangeInput-CaOuMs8O.js +198 -0
  33. package/dist/cdn/SvDateRangeInput-DMLKmGEc.js +199 -0
  34. package/dist/cdn/SvDateTimePicker-CCbDZNZB.js +816 -0
  35. package/dist/cdn/SvDateTimePicker-sonaH0oh.js +812 -0
  36. package/dist/cdn/SvGridCellEditor-BAPSC7EL.js +550 -0
  37. package/dist/cdn/SvGridCellEditor-BwzmUWtL.js +549 -0
  38. package/dist/cdn/column-resize-DsfNXMom.js +102 -0
  39. package/dist/cdn/date-format-BNii4zeD.js +1393 -0
  40. package/dist/cdn/date-format-BnnHlqGw.js +1395 -0
  41. package/dist/cdn/{editor-registry-CiI0xlKg.js → editor-registry-BhgE3S84.js} +51 -25
  42. package/dist/cdn/row-resize-BRcimkUT.js +95 -0
  43. package/dist/cdn/{src-DBel9wRZ.js → src-DGo7IHug.js} +10017 -9488
  44. package/dist/cdn/{src-BYq-qyrp.js → src-skQN5eqh.js} +7829 -7300
  45. package/dist/cdn/svgrid.js +14 -10
  46. package/dist/cdn/svgrid.svelte-external.js +14 -10
  47. package/dist/cell-values.d.ts +16 -0
  48. package/dist/cell-values.js +28 -0
  49. package/dist/clipboard.d.ts +22 -0
  50. package/dist/clipboard.js +405 -27
  51. package/dist/column-groups.js +1 -1
  52. package/dist/column-resize.d.ts +46 -0
  53. package/dist/column-resize.js +205 -0
  54. package/dist/columns.d.ts +0 -3
  55. package/dist/columns.js +0 -57
  56. package/dist/core.d.ts +19 -4
  57. package/dist/core.js +460 -119
  58. package/dist/editing.js +12 -7
  59. package/dist/editors/cell-editors.d.ts +11 -0
  60. package/dist/editors/cell-editors.js +18 -1
  61. package/dist/filtering/excel-filters.js +28 -0
  62. package/dist/grid-messages.d.ts +15 -0
  63. package/dist/grid-messages.js +15 -0
  64. package/dist/group-display.d.ts +1 -1
  65. package/dist/index.d.ts +6 -1
  66. package/dist/index.js +10 -0
  67. package/dist/list-option.d.ts +6 -0
  68. package/dist/menus.js +41 -8
  69. package/dist/row-resize.d.ts +11 -0
  70. package/dist/row-resize.js +7 -1
  71. package/dist/sanitize-html.d.ts +37 -0
  72. package/dist/sanitize-html.js +234 -0
  73. package/dist/selection-bar-view.svelte.d.ts +25 -0
  74. package/dist/selection-bar-view.svelte.js +13 -0
  75. package/dist/selection.d.ts +2 -1
  76. package/dist/selection.js +133 -8
  77. package/dist/spreadsheet.d.ts +1 -1
  78. package/dist/spreadsheet.js +1 -1
  79. package/package.json +1 -1
  80. package/src/GridMenus.svelte +201 -18
  81. package/src/SvAutoComplete.svelte +4 -0
  82. package/src/SvComboBox.svelte +5 -1
  83. package/src/SvDateRangeInput.svelte +25 -3
  84. package/src/SvDropDownList.svelte +4 -0
  85. package/src/SvForm.svelte +8 -8
  86. package/src/SvGrid.controller.svelte.ts +404 -133
  87. package/src/SvGrid.css +222 -1
  88. package/src/SvGrid.helpers.ts +87 -0
  89. package/src/SvGrid.svelte +255 -56
  90. package/src/SvGrid.types.ts +153 -1
  91. package/src/SvGridCellEditor.svelte +99 -17
  92. package/src/SvGridSelect.svelte +6 -2
  93. package/src/SvListBox.svelte +8 -0
  94. package/src/SvMultiSelect.svelte +6 -2
  95. package/src/SvNumberInput.svelte +4 -0
  96. package/src/SvRichCell.svelte +125 -0
  97. package/src/SvTextArea.svelte +5 -1
  98. package/src/SvTreeSelect.svelte +6 -2
  99. package/src/builtin-editors.test.ts +18 -1
  100. package/src/builtin-editors.ts +19 -3
  101. package/src/cell-values.ts +30 -0
  102. package/src/clipboard.test.ts +93 -20
  103. package/src/clipboard.ts +433 -33
  104. package/src/column-groups.ts +1 -1
  105. package/src/column-resize.test.ts +381 -0
  106. package/src/column-resize.ts +227 -0
  107. package/src/columns.test.ts +0 -103
  108. package/src/columns.ts +0 -58
  109. package/src/core.aggregate.test.ts +134 -0
  110. package/src/core.filter.test.ts +156 -0
  111. package/src/core.grouping.test.ts +146 -0
  112. package/src/core.row-shape.test.ts +119 -0
  113. package/src/core.rowmodel-cache.test.ts +121 -0
  114. package/src/core.sort.test.ts +293 -0
  115. package/src/core.ts +516 -119
  116. package/src/date-string-column.test.ts +87 -0
  117. package/src/editing.test.ts +25 -0
  118. package/src/editing.ts +12 -9
  119. package/src/editor-block-prop.test.ts +132 -0
  120. package/src/editors/cell-editors.ts +27 -1
  121. package/src/filtering/excel-filters.ts +30 -0
  122. package/src/filtering/normalize-fast-path.test.ts +104 -0
  123. package/src/grid-messages.ts +34 -0
  124. package/src/group-display.ts +1 -1
  125. package/src/index.ts +25 -1
  126. package/src/list-option.ts +6 -0
  127. package/src/menus.test.ts +43 -0
  128. package/src/menus.ts +38 -8
  129. package/src/move-cells.test.ts +850 -0
  130. package/src/number-editor-literal.test.ts +84 -0
  131. package/src/number-editor.grid.test.ts +160 -0
  132. package/src/resize-props.test.ts +361 -0
  133. package/src/row-resize.test.ts +31 -0
  134. package/src/row-resize.ts +21 -3
  135. package/src/sanitize-html.test.ts +182 -0
  136. package/src/sanitize-html.ts +235 -0
  137. package/src/selection-bar-view.svelte.ts +36 -0
  138. package/src/selection.test.ts +157 -0
  139. package/src/selection.ts +135 -8
  140. package/src/spreadsheet.ts +1 -1
  141. package/src/svgrid.filter-menu-listbox.svelte.test.ts +56 -10
  142. package/src/svgrid.in-suggest-snapshot.svelte.test.ts +91 -0
  143. package/src/svgrid.menu-scroll-close.test.ts +204 -0
  144. package/src/svgrid.selection-bar-seam.test.ts +185 -0
  145. package/src/svgrid.upsell-license.test.ts +117 -0
  146. package/dist/cdn/GridMenus-BfTAKn84.js +0 -488
  147. package/dist/cdn/GridMenus-C3bJd7w8.js +0 -489
  148. package/dist/cdn/SvDateTimePicker-CHnUkWcH.js +0 -2206
  149. package/dist/cdn/SvDateTimePicker-CRQH_U7E.js +0 -2201
  150. package/dist/cdn/SvGridCellEditor-BGUCzuPB.js +0 -523
  151. package/dist/cdn/SvGridCellEditor-G8IMWIws.js +0 -522
@@ -20,6 +20,12 @@ interface FakeOptions {
20
20
  groupRows?: Set<number>
21
21
  /** Predicate for editability; default true. */
22
22
  editableAt?: (r: number, c: number) => boolean
23
+ /**
24
+ * Data indices in DISPLAY order, i.e. what a sort/filter produces. Default is
25
+ * `[0, 1, 2, …]`, where display and data order coincide - which is exactly
26
+ * the case that hides row-index bugs, so the ordering tests pass a permutation.
27
+ */
28
+ displayOrder?: number[]
23
29
  }
24
30
 
25
31
  function makeCtx(opts: FakeOptions = {}) {
@@ -41,15 +47,22 @@ function makeCtx(opts: FakeOptions = {}) {
41
47
  },
42
48
  }))
43
49
 
44
- // allRows mirror internalData by index; row.id === index as a string.
45
- const buildRows = () =>
46
- data.map((row, index) => ({
47
- id: String(index),
48
- original: row,
49
- getCanExpand: () => opts.groupRows?.has(index) ?? false,
50
- getCellValueByColumnId: (colId: string) =>
51
- (row as Record<string, unknown>)[colId],
52
- }))
50
+ // allRows are the rows AS DISPLAYED. By default that mirrors internalData by
51
+ // index (row.id === index as a string); `displayOrder` reorders them the way
52
+ // a sort or filter would, leaving `original` pointing at the same objects.
53
+ const rowsFrom = (source: Array<Record<string, unknown>>) => {
54
+ const order = opts.displayOrder ?? source.map((_, i) => i)
55
+ return order
56
+ .filter((dataIndex) => source[dataIndex] !== undefined)
57
+ .map((dataIndex) => ({
58
+ id: String(dataIndex),
59
+ original: source[dataIndex],
60
+ getCanExpand: () => opts.groupRows?.has(dataIndex) ?? false,
61
+ getCellValueByColumnId: (colId: string) =>
62
+ (source[dataIndex] as Record<string, unknown>)[colId],
63
+ }))
64
+ }
65
+ const buildRows = () => rowsFrom(data)
53
66
 
54
67
  let activeCell: { rowIndex: number; colIndex: number } | null = null
55
68
 
@@ -107,13 +120,7 @@ function makeCtx(opts: FakeOptions = {}) {
107
120
  get: () => backing,
108
121
  set: (next: Array<Record<string, unknown>>) => {
109
122
  backing = next
110
- ctx._rows = next.map((row, index) => ({
111
- id: String(index),
112
- original: row,
113
- getCanExpand: () => opts.groupRows?.has(index) ?? false,
114
- getCellValueByColumnId: (colId: string) =>
115
- (row as Record<string, unknown>)[colId],
116
- }))
123
+ ctx._rows = rowsFrom(next)
117
124
  },
118
125
  })
119
126
 
@@ -195,6 +202,53 @@ describe('writeCellRaw', () => {
195
202
  cb.writeCellRaw(0, 'noField', 5)
196
203
  expect(ctx.internalData[0]).toEqual({ a: 1 })
197
204
  })
205
+
206
+ describe('when the view is sorted or filtered (display order != data order)', () => {
207
+ // `rowIndex` is a DISPLAY index. These functions used to index
208
+ // `internalData` with it, which is the same row only while the two orders
209
+ // coincide - so the fill handle and enterprise bulk edit read from one row
210
+ // and wrote to another as soon as a column was sorted.
211
+ const sorted = () =>
212
+ makeCtx({
213
+ columns: [{ id: 'a', field: 'a', editable: true, editorType: 'text' }],
214
+ data: [{ a: 'data0' }, { a: 'data1' }, { a: 'data2' }],
215
+ displayOrder: [2, 0, 1],
216
+ })
217
+
218
+ it('readCellRaw reads the row shown at that position', () => {
219
+ const cb = createClipboard(sorted())
220
+ expect(cb.readCellRaw(0, 'a')).toBe('data2')
221
+ expect(cb.readCellRaw(1, 'a')).toBe('data0')
222
+ expect(cb.readCellRaw(2, 'a')).toBe('data1')
223
+ })
224
+
225
+ it('writeCellRaw writes the row shown at that position', () => {
226
+ const ctx = sorted()
227
+ const cb = createClipboard(ctx)
228
+ cb.writeCellRaw(0, 'a', 'WRITTEN')
229
+ expect(ctx.internalData.map((d: any) => d.a)).toEqual([
230
+ 'data0',
231
+ 'data1',
232
+ 'WRITTEN',
233
+ ])
234
+ })
235
+
236
+ it('reports the position in props.data to onCellValueChange', () => {
237
+ const ctx = sorted()
238
+ const onCellValueChange = vi.fn()
239
+ ctx.props.onCellValueChange = onCellValueChange
240
+ createClipboard(ctx).writeCellRaw(0, 'a', 'WRITTEN')
241
+ expect(onCellValueChange).toHaveBeenCalledWith(
242
+ expect.objectContaining({ rowIndex: 2, oldValue: 'data2', newValue: 'WRITTEN' }),
243
+ )
244
+ })
245
+
246
+ it('records the edit under the displayed row id', () => {
247
+ const ctx = sorted()
248
+ createClipboard(ctx).writeCellRaw(1, 'a', 'WRITTEN')
249
+ expect(ctx.editedCellValues['0:a']).toBe('WRITTEN')
250
+ })
251
+ })
198
252
  })
199
253
 
200
254
  describe('clearSelectedCellValues', () => {
@@ -753,14 +807,14 @@ describe('clearSelectedCells', () => {
753
807
  expect(ctx.internalData[0].a).toBe('x')
754
808
  })
755
809
 
756
- it('skips rows whose id maps outside the data bounds', () => {
810
+ it('skips a row whose data object is not in the data array', () => {
757
811
  const ctx = makeCtx({
758
812
  columns: [{ id: 'a', field: 'a', editable: true, editorType: 'text' }],
759
813
  data: [{ a: 'x' }],
760
814
  })
761
- // Force the row's id to a non-numeric value so Number(id) is NaN
762
- // and the integer/bounds guard skips it.
763
- ctx._rows[0].id = 'not-a-number'
815
+ // A row model pointing at an object that is no longer in `internalData`
816
+ // (a stale model after data was replaced) has no slot to write to.
817
+ ctx._rows[0].original = { a: 'stale' }
764
818
  ctx.selectionRange = {
765
819
  anchor: { rowIndex: 0, colIndex: 0 },
766
820
  focus: { rowIndex: 0, colIndex: 0 },
@@ -769,6 +823,25 @@ describe('clearSelectedCells', () => {
769
823
  expect(cb.clearSelectedCells()).toBe(false)
770
824
  expect(ctx.internalData[0].a).toBe('x')
771
825
  })
826
+
827
+ it('clears the selected row when getRowId does not return the array index', () => {
828
+ // The bug this guards: the row -> data-slot lookup used to be
829
+ // `Number(row.id)`, which is the array index only under the DEFAULT
830
+ // getRowId. Ids that are 1-based (or not numbers at all) cleared the row
831
+ // below the selection, or silently cleared nothing.
832
+ const ctx = makeCtx({
833
+ columns: [{ id: 'a', field: 'a', editable: true, editorType: 'text' }],
834
+ data: [{ a: 'x0' }, { a: 'x1' }, { a: 'x2' }],
835
+ })
836
+ ctx._rows.forEach((r: any, i: number) => { r.id = `PLAT-${i + 1}` })
837
+ ctx.selectionRange = {
838
+ anchor: { rowIndex: 1, colIndex: 0 },
839
+ focus: { rowIndex: 1, colIndex: 0 },
840
+ }
841
+ const cb = createClipboard(ctx)
842
+ expect(cb.clearSelectedCells()).toBe(true)
843
+ expect(ctx.internalData.map((d: any) => d.a)).toEqual(['x0', '', 'x2'])
844
+ })
772
845
  })
773
846
 
774
847
  describe('cutSelectionToClipboard', () => {