@svgrid/grid 2.6.22 → 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.
- package/dist/GridMenus.svelte +184 -6
- package/dist/SvAutoComplete.svelte +4 -0
- package/dist/SvComboBox.svelte +5 -1
- package/dist/SvDateRangeInput.svelte +25 -3
- package/dist/SvDropDownList.svelte +4 -0
- package/dist/SvForm.svelte +8 -8
- package/dist/SvGrid.controller.svelte.d.ts +48 -1
- package/dist/SvGrid.controller.svelte.js +214 -52
- package/dist/SvGrid.css +221 -0
- package/dist/SvGrid.helpers.d.ts +55 -0
- package/dist/SvGrid.helpers.js +83 -0
- package/dist/SvGrid.svelte +145 -0
- package/dist/SvGrid.types.d.ts +105 -0
- package/dist/SvGridCellEditor.svelte +99 -17
- package/dist/SvGridSelect.svelte +6 -2
- package/dist/SvGridSelect.svelte.d.ts +1 -1
- package/dist/SvListBox.svelte +8 -0
- package/dist/SvMultiSelect.svelte +6 -2
- package/dist/SvMultiSelect.svelte.d.ts +1 -1
- package/dist/SvNumberInput.svelte +4 -0
- package/dist/SvRichCell.svelte +125 -0
- package/dist/SvRichCell.svelte.d.ts +15 -0
- package/dist/SvTextArea.svelte +5 -1
- package/dist/SvTreeSelect.svelte +6 -2
- package/dist/SvTreeSelect.svelte.d.ts +1 -1
- package/dist/builtin-editors.d.ts +2 -2
- package/dist/builtin-editors.js +19 -3
- package/dist/cdn/GridMenus-BzWXQjv3.js +600 -0
- package/dist/cdn/GridMenus-xr_rHx8F.js +601 -0
- package/dist/cdn/SvDateRangeInput-CaOuMs8O.js +198 -0
- package/dist/cdn/SvDateRangeInput-DMLKmGEc.js +199 -0
- package/dist/cdn/SvDateTimePicker-CCbDZNZB.js +816 -0
- package/dist/cdn/SvDateTimePicker-sonaH0oh.js +812 -0
- package/dist/cdn/SvGridCellEditor-BAPSC7EL.js +550 -0
- package/dist/cdn/SvGridCellEditor-BwzmUWtL.js +549 -0
- package/dist/cdn/date-format-BNii4zeD.js +1393 -0
- package/dist/cdn/date-format-BnnHlqGw.js +1395 -0
- package/dist/cdn/{editor-registry-CiI0xlKg.js → editor-registry-BhgE3S84.js} +51 -25
- package/dist/cdn/{src-D1lXwq1l.js → src-DGo7IHug.js} +5730 -5198
- package/dist/cdn/{src-C9Hihx1W.js → src-skQN5eqh.js} +7216 -6684
- package/dist/cdn/svgrid.js +14 -12
- package/dist/cdn/svgrid.svelte-external.js +14 -12
- package/dist/cell-values.d.ts +16 -0
- package/dist/cell-values.js +28 -0
- package/dist/clipboard.d.ts +22 -0
- package/dist/clipboard.js +405 -27
- package/dist/editing.js +12 -7
- package/dist/editors/cell-editors.d.ts +11 -0
- package/dist/editors/cell-editors.js +18 -1
- package/dist/grid-messages.d.ts +15 -0
- package/dist/grid-messages.js +15 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/list-option.d.ts +6 -0
- package/dist/menus.js +40 -7
- package/dist/sanitize-html.d.ts +37 -0
- package/dist/sanitize-html.js +234 -0
- package/dist/selection-bar-view.svelte.d.ts +25 -0
- package/dist/selection-bar-view.svelte.js +13 -0
- package/dist/selection.d.ts +2 -1
- package/dist/selection.js +129 -13
- package/package.json +1 -1
- package/src/GridMenus.svelte +184 -6
- package/src/SvAutoComplete.svelte +4 -0
- package/src/SvComboBox.svelte +5 -1
- package/src/SvDateRangeInput.svelte +25 -3
- package/src/SvDropDownList.svelte +4 -0
- package/src/SvForm.svelte +8 -8
- package/src/SvGrid.controller.svelte.ts +251 -61
- package/src/SvGrid.css +221 -0
- package/src/SvGrid.helpers.ts +87 -0
- package/src/SvGrid.svelte +145 -0
- package/src/SvGrid.types.ts +112 -0
- package/src/SvGridCellEditor.svelte +99 -17
- package/src/SvGridSelect.svelte +6 -2
- package/src/SvListBox.svelte +8 -0
- package/src/SvMultiSelect.svelte +6 -2
- package/src/SvNumberInput.svelte +4 -0
- package/src/SvRichCell.svelte +125 -0
- package/src/SvTextArea.svelte +5 -1
- package/src/SvTreeSelect.svelte +6 -2
- package/src/builtin-editors.test.ts +18 -1
- package/src/builtin-editors.ts +19 -3
- package/src/cell-values.ts +30 -0
- package/src/clipboard.test.ts +93 -20
- package/src/clipboard.ts +433 -33
- package/src/date-string-column.test.ts +87 -0
- package/src/editing.test.ts +25 -0
- package/src/editing.ts +12 -9
- package/src/editor-block-prop.test.ts +132 -0
- package/src/editors/cell-editors.ts +27 -1
- package/src/grid-messages.ts +34 -0
- package/src/index.ts +13 -0
- package/src/list-option.ts +6 -0
- package/src/menus.test.ts +43 -0
- package/src/menus.ts +37 -7
- package/src/move-cells.test.ts +850 -0
- package/src/number-editor-literal.test.ts +84 -0
- package/src/number-editor.grid.test.ts +160 -0
- package/src/sanitize-html.test.ts +182 -0
- package/src/sanitize-html.ts +235 -0
- package/src/selection-bar-view.svelte.ts +36 -0
- package/src/selection.test.ts +157 -0
- package/src/selection.ts +131 -13
- package/src/svgrid.filter-menu-listbox.svelte.test.ts +56 -10
- package/src/svgrid.in-suggest-snapshot.svelte.test.ts +91 -0
- package/src/svgrid.menu-scroll-close.test.ts +204 -0
- package/src/svgrid.selection-bar-seam.test.ts +185 -0
- package/src/svgrid.upsell-license.test.ts +117 -0
- package/dist/cdn/GridMenus-BuoBPqxx.js +0 -493
- package/dist/cdn/GridMenus-n4llxoOI.js +0 -494
- package/dist/cdn/SvDateTimePicker-CHnUkWcH.js +0 -2206
- package/dist/cdn/SvDateTimePicker-CRQH_U7E.js +0 -2201
- package/dist/cdn/SvGridCellEditor-BGUCzuPB.js +0 -523
- package/dist/cdn/SvGridCellEditor-G8IMWIws.js +0 -522
package/src/cell-values.ts
CHANGED
|
@@ -18,6 +18,36 @@ export function getColumnBaseValue<TData extends RowData>(row: Row<TData>, colum
|
|
|
18
18
|
return row.getCellValueByColumnId(column.id);
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Map a visible row back to its slot in the data array.
|
|
23
|
+
*
|
|
24
|
+
* The bulk writers (paste, clear) rebuild `internalData` immutably, so unlike
|
|
25
|
+
* the inline editor - which mutates `row.original` in place and never needs an
|
|
26
|
+
* index - they have to locate the slot first. They used to read it as
|
|
27
|
+
* `Number(row.id)`, which is only the array index under the DEFAULT `getRowId`.
|
|
28
|
+
* A grid with `getRowId={(t) => String(t.id)}` over 1-based ids wrote one row
|
|
29
|
+
* BELOW the selection on every paste, and one with non-numeric ids ('PLAT-412')
|
|
30
|
+
* parsed to NaN and dropped the write silently.
|
|
31
|
+
*
|
|
32
|
+
* Identity is the reliable key: the row model's `original` IS the object in
|
|
33
|
+
* `data`. Returns a lookup rather than a per-row scan so a multi-row paste
|
|
34
|
+
* stays O(n) instead of O(n * rows).
|
|
35
|
+
*/
|
|
36
|
+
export function createDataIndexLookup<TData extends RowData>(
|
|
37
|
+
data: ReadonlyArray<TData>,
|
|
38
|
+
): (row: Row<TData>) => number {
|
|
39
|
+
const byRef = new Map<unknown, number>();
|
|
40
|
+
for (let i = 0; i < data.length; i += 1) {
|
|
41
|
+
// First slot wins: with a duplicated object reference in `data`, writing
|
|
42
|
+
// the earlier one matches what the row model itself resolves to.
|
|
43
|
+
if (!byRef.has(data[i])) byRef.set(data[i], i);
|
|
44
|
+
}
|
|
45
|
+
return (row) => {
|
|
46
|
+
const hit = byRef.get(row?.original);
|
|
47
|
+
return hit === undefined ? -1 : hit;
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
21
51
|
export function isGroupRow<TData extends RowData>(row: Row<TData>) {
|
|
22
52
|
// Tree rows are expandable too, but they are real data rows - rendering one as
|
|
23
53
|
// a full-width banner would swallow its cells. Only grouping's synthetic rows
|
package/src/clipboard.test.ts
CHANGED
|
@@ -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
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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
|
|
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
|
|
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
|
-
//
|
|
762
|
-
//
|
|
763
|
-
ctx._rows[0].
|
|
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', () => {
|