@svgrid/grid 2.6.21 → 2.7.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.
- package/CHANGELOG.md +150 -88
- package/README.md +221 -199
- package/dist/FlexRender.svelte +96 -96
- package/dist/GridFooter.svelte +181 -181
- package/dist/GridMenus.svelte +201 -18
- package/dist/SvAutoComplete.svelte +169 -165
- package/dist/SvAvatar.svelte +75 -75
- package/dist/SvCalendar.svelte +503 -503
- package/dist/SvCarousel.svelte +141 -141
- package/dist/SvCheckBox.svelte +102 -102
- package/dist/SvCircularProgress.svelte +109 -109
- package/dist/SvColorInput.svelte +181 -181
- package/dist/SvComboBox.svelte +279 -275
- package/dist/SvContextMenu.svelte +116 -116
- package/dist/SvCountryInput.svelte +163 -163
- package/dist/SvDateRangeInput.svelte +25 -3
- package/dist/SvDrawer.svelte +254 -254
- package/dist/SvDropDownList.svelte +378 -374
- package/dist/SvDurationInput.svelte +126 -126
- package/dist/SvField.svelte +293 -293
- package/dist/SvForm.svelte +437 -437
- package/dist/SvGrid.controller.svelte.d.ts +61 -9
- package/dist/SvGrid.controller.svelte.js +363 -123
- package/dist/SvGrid.css +222 -1
- package/dist/SvGrid.helpers.d.ts +55 -0
- package/dist/SvGrid.helpers.js +83 -0
- package/dist/SvGrid.svelte +255 -56
- package/dist/SvGrid.types.d.ts +146 -1
- package/dist/SvGridCellEditor.svelte +744 -662
- package/dist/SvGridChart.svelte +1716 -1716
- package/dist/SvGridChartPanel.svelte +485 -485
- package/dist/SvGridChartView.svelte +70 -70
- package/dist/SvGridDropdown.svelte +728 -728
- package/dist/SvGridSelect.svelte +270 -266
- package/dist/SvGridSelect.svelte.d.ts +1 -1
- package/dist/SvGroupCell.svelte +116 -116
- package/dist/SvListBox.svelte +334 -326
- package/dist/SvMaskedInput.svelte +122 -122
- package/dist/SvMenu.svelte +124 -124
- package/dist/SvMenuList.svelte +146 -146
- package/dist/SvMultiSelect.svelte +293 -289
- package/dist/SvMultiSelect.svelte.d.ts +1 -1
- package/dist/SvNumberInput.svelte +172 -168
- package/dist/SvOtpInput.svelte +158 -158
- package/dist/SvPasswordInput.svelte +151 -151
- package/dist/SvPhoneInput.svelte +133 -133
- package/dist/SvPopover.svelte +197 -197
- package/dist/SvProgress.svelte +116 -116
- package/dist/SvRadioGroup.svelte +107 -107
- package/dist/SvRating.svelte +112 -112
- package/dist/SvResult.svelte +73 -73
- package/dist/SvRichCell.svelte +125 -0
- package/dist/SvRichCell.svelte.d.ts +15 -0
- package/dist/SvRichText.svelte +211 -211
- package/dist/SvRowGroupPanel.svelte +170 -170
- package/dist/SvScrollArea.svelte +61 -61
- package/dist/SvSlider.svelte +203 -203
- package/dist/SvSwitchButton.svelte +108 -108
- package/dist/SvTagsInput.svelte +115 -115
- package/dist/SvTextArea.svelte +5 -1
- package/dist/SvTextInput.svelte +147 -147
- package/dist/SvTimePicker.svelte +245 -245
- package/dist/SvToaster.svelte +159 -159
- package/dist/SvToggleButton.svelte +85 -85
- package/dist/SvTooltip.svelte +161 -161
- package/dist/SvTour.svelte +208 -208
- package/dist/SvTree.svelte +444 -444
- package/dist/SvTreeSelect.svelte +239 -235
- 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-C4oLsJyj.js +600 -0
- package/dist/cdn/GridMenus-yEivjNwl.js +601 -0
- package/dist/cdn/SvDateRangeInput-Bh0A0JkF.js +199 -0
- package/dist/cdn/SvDateRangeInput-DflbiP7N.js +198 -0
- package/dist/cdn/SvDateTimePicker-BWwpfB_o.js +812 -0
- package/dist/cdn/SvDateTimePicker-Bivn8dAP.js +816 -0
- package/dist/cdn/SvGridCellEditor-AXL8cHGO.js +550 -0
- package/dist/cdn/SvGridCellEditor-Ba7rY3eu.js +549 -0
- package/dist/cdn/{SvGridChart-BwVos976.js → SvGridChart-Bs2GIR2Q.js} +1 -1
- package/dist/cdn/{SvGridChart-BEJmNNx9.js → SvGridChart-CwhFz7GV.js} +1 -1
- package/dist/cdn/{SvGridChartPanel-BOknOkrP.js → SvGridChartPanel-1WXuStzM.js} +1 -1
- package/dist/cdn/{SvGridChartPanel-D2PjII4O.js → SvGridChartPanel-e5_nqNP9.js} +1 -1
- package/dist/cdn/{SvGridChartView-00LPUHL1.js → SvGridChartView-SmPW10dI.js} +1 -1
- package/dist/cdn/{SvGridChartView-BhUEJ5ki.js → SvGridChartView-eSPuJE6g.js} +1 -1
- package/dist/cdn/{SvGridDropdown-D0VdjeR8.js → SvGridDropdown-B1ZcLpgs.js} +1 -1
- package/dist/cdn/{SvGridDropdown-D13MtJ2j.js → SvGridDropdown-CtdbHcIS.js} +1 -1
- package/dist/cdn/column-resize-DsfNXMom.js +102 -0
- package/dist/cdn/date-format-CcP1tafP.js +1395 -0
- package/dist/cdn/date-format-DZT7T1wf.js +1393 -0
- package/dist/cdn/{editor-registry-CiI0xlKg.js → editor-registry-BhgE3S84.js} +51 -25
- package/dist/cdn/row-resize-BRcimkUT.js +95 -0
- package/dist/cdn/{src-BYq-qyrp.js → src-COC0vnpg.js} +7846 -7317
- package/dist/cdn/{src-DBel9wRZ.js → src-pYGV2rMR.js} +10033 -9504
- package/dist/cdn/svgrid.js +15 -11
- package/dist/cdn/svgrid.svelte-external.js +15 -11
- package/dist/cell-values.d.ts +16 -0
- package/dist/cell-values.js +28 -0
- package/dist/chart-export.js +8 -8
- package/dist/clipboard.d.ts +22 -0
- package/dist/clipboard.js +405 -27
- package/dist/column-groups.js +1 -1
- package/dist/column-resize.d.ts +46 -0
- package/dist/column-resize.js +205 -0
- package/dist/columns.d.ts +0 -3
- package/dist/columns.js +0 -57
- package/dist/core.d.ts +19 -4
- package/dist/core.js +460 -119
- 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/filtering/excel-filters.js +28 -0
- package/dist/grid-messages.d.ts +15 -0
- package/dist/grid-messages.js +15 -0
- package/dist/group-display.d.ts +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.js +10 -0
- package/dist/list-option.d.ts +6 -0
- package/dist/menus.js +41 -8
- package/dist/row-resize.d.ts +11 -0
- package/dist/row-resize.js +7 -1
- 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 +133 -8
- package/dist/spreadsheet.d.ts +1 -1
- package/dist/spreadsheet.js +1 -1
- package/package.json +11 -11
- package/src/FlexRender.svelte +96 -96
- package/src/GridFooter.svelte +181 -181
- package/src/GridMenus.svelte +201 -18
- package/src/SvAutoComplete.svelte +169 -165
- package/src/SvAvatar.svelte +75 -75
- package/src/SvCalendar.svelte +503 -503
- package/src/SvCalendar.test.ts +226 -226
- package/src/SvCarousel.svelte +141 -141
- package/src/SvCheckBox.svelte +102 -102
- package/src/SvCircularProgress.svelte +109 -109
- package/src/SvColorInput.svelte +181 -181
- package/src/SvComboBox.svelte +279 -275
- package/src/SvContextMenu.svelte +116 -116
- package/src/SvCountryInput.svelte +163 -163
- package/src/SvDateRangeInput.svelte +25 -3
- package/src/SvDrawer.svelte +254 -254
- package/src/SvDropDownList.svelte +378 -374
- package/src/SvDurationInput.svelte +126 -126
- package/src/SvField.svelte +293 -293
- package/src/SvForm.svelte +437 -437
- package/src/SvForm.test.ts +411 -411
- package/src/SvGrid.controller.svelte.ts +404 -133
- package/src/SvGrid.css +222 -1
- package/src/SvGrid.helpers.ts +87 -0
- package/src/SvGrid.svelte +255 -56
- package/src/SvGrid.types.ts +2092 -1940
- package/src/SvGridCellEditor.svelte +744 -662
- package/src/SvGridChart.svelte +1716 -1716
- package/src/SvGridChartPanel.svelte +485 -485
- package/src/SvGridChartView.svelte +70 -70
- package/src/SvGridDropdown.svelte +728 -728
- package/src/SvGridSelect.svelte +270 -266
- package/src/SvGroupCell.svelte +116 -116
- package/src/SvListBox.svelte +334 -326
- package/src/SvMaskedInput.svelte +122 -122
- package/src/SvMenu.svelte +124 -124
- package/src/SvMenu.test.ts +97 -97
- package/src/SvMenuList.svelte +146 -146
- package/src/SvMultiSelect.svelte +293 -289
- package/src/SvNumberInput.svelte +172 -168
- package/src/SvOtpInput.svelte +158 -158
- package/src/SvPasswordInput.svelte +151 -151
- package/src/SvPhoneInput.svelte +133 -133
- package/src/SvPopover.svelte +197 -197
- package/src/SvProgress.svelte +116 -116
- package/src/SvRadioGroup.svelte +107 -107
- package/src/SvRating.svelte +112 -112
- package/src/SvResult.svelte +73 -73
- package/src/SvRichCell.svelte +125 -0
- package/src/SvRichText.svelte +211 -211
- package/src/SvRowGroupPanel.svelte +170 -170
- package/src/SvScrollArea.svelte +61 -61
- package/src/SvSlider.svelte +203 -203
- package/src/SvSwitchButton.svelte +108 -108
- package/src/SvTagsInput.svelte +115 -115
- package/src/SvTextArea.svelte +5 -1
- package/src/SvTextInput.svelte +147 -147
- package/src/SvTimePicker.svelte +245 -245
- package/src/SvToaster.svelte +159 -159
- package/src/SvToaster.test.ts +95 -95
- package/src/SvToggleButton.svelte +85 -85
- package/src/SvTooltip.svelte +161 -161
- package/src/SvTour.svelte +208 -208
- package/src/SvTree.svelte +444 -444
- package/src/SvTreeSelect.svelte +239 -235
- package/src/a11y/dismissable.test.ts +119 -119
- package/src/a11y/dismissable.ts +114 -114
- package/src/a11y.contract.test.ts +49 -49
- package/src/a11y.test.ts +59 -59
- package/src/a11y.ts +61 -61
- package/src/ai.test.ts +502 -502
- package/src/ai.ts +1419 -1419
- package/src/build-api.coverage.test.ts +633 -633
- package/src/build-api.ts +846 -846
- package/src/builtin-editors.grid.test.ts +83 -83
- package/src/builtin-editors.test.ts +18 -1
- package/src/builtin-editors.ts +19 -3
- package/src/cell-formatting.ts +171 -171
- package/src/cell-render.test.ts +513 -513
- package/src/cell-render.ts +496 -496
- package/src/cell-values.ts +148 -118
- package/src/chart-export.ts +202 -202
- package/src/chart-view.svelte.ts +36 -36
- package/src/chart.ts +2321 -2321
- package/src/clipboard.test.ts +93 -20
- package/src/clipboard.ts +433 -33
- package/src/collaboration.test.ts +104 -104
- package/src/collaboration.ts +167 -167
- package/src/column-groups.ts +78 -78
- package/src/column-resize.test.ts +381 -0
- package/src/column-resize.ts +227 -0
- package/src/columns.test.ts +0 -103
- package/src/columns.ts +0 -58
- package/src/core.aggregate.test.ts +134 -0
- package/src/core.filter.test.ts +156 -0
- package/src/core.grouping.test.ts +146 -0
- package/src/core.performance.test.ts +30 -30
- package/src/core.row-shape.test.ts +119 -0
- package/src/core.rowmodel-cache.test.ts +121 -0
- package/src/core.sort.test.ts +293 -0
- package/src/core.ts +1865 -1468
- package/src/createAutocomplete.svelte.ts +132 -132
- package/src/createCombobox.svelte.ts +191 -191
- package/src/createCountryInput.svelte.ts +157 -157
- package/src/createDropdownList.svelte.ts +168 -168
- package/src/createForm.svelte.ts +386 -386
- package/src/createGrid.svelte.ts +42 -42
- package/src/createGrid.test.ts +10 -10
- package/src/createGridState.svelte.ts +17 -17
- package/src/createListbox.svelte.ts +250 -250
- package/src/createMenu.svelte.ts +224 -224
- package/src/createPopoverSelect.svelte.ts +213 -213
- package/src/createSlider.svelte.ts +191 -191
- package/src/createTooltip.svelte.ts +144 -144
- package/src/createTree.svelte.ts +322 -322
- package/src/date-string-column.test.ts +87 -0
- package/src/datetime/date-core.ts +206 -206
- package/src/datetime/date-restrict.ts +61 -61
- package/src/datetime/timezone.ts +135 -135
- package/src/dock-manager-model.ts +596 -596
- package/src/dock-model.ts +374 -374
- package/src/editing.test.ts +974 -949
- package/src/editing.ts +609 -606
- package/src/editor-block-prop.test.ts +132 -0
- package/src/editor-contract.ts +171 -171
- package/src/editor-registry.grid.test.ts +144 -144
- package/src/editor-registry.ts +122 -122
- package/src/editors/cell-editors.ts +27 -1
- package/src/export-data-api.test.ts +126 -126
- package/src/export-format.test.ts +107 -107
- package/src/export-format.ts +601 -601
- package/src/filter-operators.ts +160 -160
- package/src/filtering/excel-filters.ts +325 -295
- package/src/filtering/normalize-fast-path.test.ts +104 -0
- package/src/flex-render.ts +3 -3
- package/src/form-field.ts +127 -127
- package/src/grid-messages.ts +34 -0
- package/src/group-display.test.ts +167 -167
- package/src/group-display.ts +200 -200
- package/src/headless.ts +87 -87
- package/src/index.ts +25 -1
- package/src/js-scroller.svelte.ts +173 -173
- package/src/keyboard-handlers.ts +270 -270
- package/src/keyboard.test.ts +59 -59
- package/src/keyboard.ts +97 -97
- package/src/list-nav.test.ts +49 -49
- package/src/list-nav.ts +29 -29
- package/src/list-option.test.ts +56 -56
- package/src/list-option.ts +179 -173
- package/src/menus.test.ts +43 -0
- package/src/menus.ts +597 -567
- package/src/merge-objects.ts +48 -48
- 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/overlays.test.ts +90 -90
- package/src/positioning.ts +268 -268
- package/src/render-component.ts +28 -28
- package/src/resize-props.test.ts +361 -0
- package/src/row-drag-touch.ts +211 -211
- package/src/row-drag.test.ts +353 -353
- package/src/row-drag.ts +415 -415
- package/src/row-resize.test.ts +524 -493
- package/src/row-resize.ts +228 -210
- package/src/sanitize-html.test.ts +182 -0
- package/src/sanitize-html.ts +235 -0
- package/src/scheduler-ical.ts +181 -181
- package/src/scheduler-model.test.ts +562 -562
- package/src/scheduler-model.ts +873 -873
- package/src/selection-bar-view.svelte.ts +36 -0
- package/src/selection.test.ts +900 -743
- package/src/selection.ts +135 -8
- package/src/server-data-source.test.ts +383 -383
- package/src/server-data-source.ts +469 -469
- package/src/sparkline.test.ts +68 -68
- package/src/sparkline.ts +169 -169
- package/src/spreadsheet.test.ts +488 -488
- package/src/spreadsheet.ts +312 -312
- package/src/static-functions.ts +11 -11
- package/src/subscribe.ts +38 -38
- package/src/summaries.ts +113 -113
- package/src/svgrid-wrapper.types.ts +563 -563
- package/src/svgrid.async-editor-options.test.ts +273 -273
- package/src/svgrid.auto-row-height.test.ts +204 -204
- package/src/svgrid.behavior.test.ts +910 -910
- package/src/svgrid.charting.test.ts +534 -534
- package/src/svgrid.comments-autocomplete.test.ts +127 -127
- package/src/svgrid.context-menu.test.ts +147 -147
- package/src/svgrid.features.test.ts +157 -157
- package/src/svgrid.filter-depth.test.ts +163 -163
- package/src/svgrid.filter-menu-listbox.svelte.test.ts +377 -331
- package/src/svgrid.filter-menu-scroll.test.ts +112 -112
- package/src/svgrid.grand-total.test.ts +188 -188
- package/src/svgrid.group-display-mode.test.ts +171 -171
- package/src/svgrid.group-footers.test.ts +121 -121
- package/src/svgrid.group-pagination.test.ts +153 -153
- package/src/svgrid.in-suggest-snapshot.svelte.test.ts +91 -0
- package/src/svgrid.menu-scroll-close.test.ts +204 -0
- package/src/svgrid.new-features.wrapper.test.ts +251 -251
- package/src/svgrid.selection-bar-seam.test.ts +185 -0
- package/src/svgrid.tree-data.test.ts +186 -186
- package/src/svgrid.upsell-license.test.ts +117 -0
- package/src/svgrid.wrapper.test.ts +63 -63
- package/src/svgriddropdown.async-panel.svelte.test.ts +195 -195
- package/src/test-setup.ts +62 -62
- package/src/themes/index.ts +288 -288
- package/src/toast-store.svelte.ts +250 -250
- package/src/toast-store.test.ts +147 -147
- package/src/tree-row-model.test.ts +168 -168
- package/src/ui-buttons.test.ts +144 -144
- package/src/ui-inputs.test.ts +118 -118
- package/src/ui-localization.test.ts +113 -113
- package/src/ui-range.test.ts +70 -70
- package/src/ui-selection.test.ts +155 -155
- package/src/ui-tier1.test.ts +142 -142
- package/src/virtual.test.ts +88 -88
- package/src/virtualization/column-virtualizer.test.ts +27 -27
- package/src/virtualization/column-virtualizer.ts +30 -30
- package/src/virtualization/svelte-virtualizer.svelte.ts +26 -26
- package/src/virtualization/types.ts +30 -30
- package/src/virtualization/virtualizer.test.ts +47 -47
- package/src/virtualization/virtualizer.ts +322 -322
- package/dist/cdn/GridMenus-BfTAKn84.js +0 -488
- package/dist/cdn/GridMenus-C3bJd7w8.js +0 -489
- 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
|
@@ -1,144 +1,144 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Integration test for the cell-editor registry wiring in SvGrid.svelte: a
|
|
3
|
-
* component registered via `registerCellEditor` is actually mounted when a cell
|
|
4
|
-
* of that custom `editorType` starts editing.
|
|
5
|
-
*/
|
|
6
|
-
import { afterEach, describe, expect, it, vi } from 'vitest'
|
|
7
|
-
import { mount, unmount } from 'svelte'
|
|
8
|
-
import SvGrid from './SvGrid.svelte'
|
|
9
|
-
import SvRating from './SvRating.svelte'
|
|
10
|
-
import {
|
|
11
|
-
registerCellEditor,
|
|
12
|
-
unregisterCellEditor,
|
|
13
|
-
createCoreRowModel,
|
|
14
|
-
createFilteredRowModel,
|
|
15
|
-
createPaginatedRowModel,
|
|
16
|
-
createSortedRowModel,
|
|
17
|
-
sortFns,
|
|
18
|
-
tableFeatures,
|
|
19
|
-
columnFilteringFeature,
|
|
20
|
-
rowSortingFeature,
|
|
21
|
-
} from './index'
|
|
22
|
-
import type { ColumnDef, SvGridApi } from './index'
|
|
23
|
-
|
|
24
|
-
type Row = { id: number; name: string; score: number }
|
|
25
|
-
|
|
26
|
-
const features = tableFeatures({ columnFilteringFeature, rowSortingFeature })
|
|
27
|
-
const rows: Row[] = [
|
|
28
|
-
{ id: 1, name: 'Ada', score: 3 },
|
|
29
|
-
{ id: 2, name: 'Alan', score: 5 },
|
|
30
|
-
]
|
|
31
|
-
const cols: ColumnDef<typeof features, Row>[] = [
|
|
32
|
-
{ field: 'name', header: 'Name', width: 200, editorType: 'text' },
|
|
33
|
-
// Custom editor type resolved through the registry:
|
|
34
|
-
{ field: 'score', header: 'Score', width: 160, editorType: 'stars' },
|
|
35
|
-
]
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
function mountGrid() {
|
|
39
|
-
return new Promise<{ api: SvGridApi<typeof features, Row>; target: HTMLElement; destroy: () => void }>(
|
|
40
|
-
(res, rej) => {
|
|
41
|
-
const target = document.createElement('div')
|
|
42
|
-
document.body.appendChild(target)
|
|
43
|
-
const app = mount(SvGrid, {
|
|
44
|
-
target,
|
|
45
|
-
props: {
|
|
46
|
-
data: rows,
|
|
47
|
-
columns: cols,
|
|
48
|
-
features,
|
|
49
|
-
_rowModels: {
|
|
50
|
-
coreRowModel: createCoreRowModel(),
|
|
51
|
-
filteredRowModel: createFilteredRowModel(),
|
|
52
|
-
sortedRowModel: createSortedRowModel(sortFns),
|
|
53
|
-
paginatedRowModel: createPaginatedRowModel(),
|
|
54
|
-
},
|
|
55
|
-
rowHeight: 36,
|
|
56
|
-
containerHeight: 300,
|
|
57
|
-
virtualization: false,
|
|
58
|
-
enableInlineEditing: true,
|
|
59
|
-
onApiReady(api: SvGridApi<typeof features, Row>) {
|
|
60
|
-
res({ api, target, destroy: () => { unmount(app); target.remove() } })
|
|
61
|
-
},
|
|
62
|
-
} as any,
|
|
63
|
-
})
|
|
64
|
-
queueMicrotask(() => rej.length && undefined)
|
|
65
|
-
},
|
|
66
|
-
)
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
afterEach(() => {
|
|
70
|
-
unregisterCellEditor('stars')
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
describe('registry wiring in SvGrid', () => {
|
|
74
|
-
it('mounts a registered component when a custom-editorType cell edits', async () => {
|
|
75
|
-
registerCellEditor('stars', {
|
|
76
|
-
component: SvRating,
|
|
77
|
-
props: (ctx) => ({
|
|
78
|
-
value: ctx.value,
|
|
79
|
-
onChange: (v: number) => ctx.onCommit(v),
|
|
80
|
-
}),
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
const { api, target, destroy } = await mountGrid()
|
|
84
|
-
try {
|
|
85
|
-
api.startEditing(0, 'score')
|
|
86
|
-
// The editor UI is a lazy chunk (SvGridCellEditor), so a fixed number of
|
|
87
|
-
// ticks is a race - poll the same assertion until the import lands.
|
|
88
|
-
await vi.waitFor(() => {
|
|
89
|
-
// The registered SvRating editor is mounted in the editing overlay.
|
|
90
|
-
expect(target.querySelector('.sv-rating')).not.toBeNull()
|
|
91
|
-
})
|
|
92
|
-
} finally {
|
|
93
|
-
destroy()
|
|
94
|
-
}
|
|
95
|
-
})
|
|
96
|
-
|
|
97
|
-
it('hands the editor the full EditorInteraction contract, not a subset', async () => {
|
|
98
|
-
// The contract type used to be documented but never supplied: the registry
|
|
99
|
-
// passed only value/onChange/onCommit/onCancel, so an editor written against
|
|
100
|
-
// `EditorInteraction` (Tab-to-move, dismiss-without-commit, in-cell tuning)
|
|
101
|
-
// silently got undefined for half of it.
|
|
102
|
-
let seen: Record<string, unknown> = {}
|
|
103
|
-
registerCellEditor('stars', {
|
|
104
|
-
component: SvRating,
|
|
105
|
-
props: (ctx) => {
|
|
106
|
-
seen = ctx as unknown as Record<string, unknown>
|
|
107
|
-
return { value: ctx.value }
|
|
108
|
-
},
|
|
109
|
-
})
|
|
110
|
-
|
|
111
|
-
const { api, target, destroy } = await mountGrid()
|
|
112
|
-
try {
|
|
113
|
-
api.startEditing(0, 'score')
|
|
114
|
-
// SvGridCellEditor is a lazy chunk; poll until it has mounted and run the
|
|
115
|
-
// registration's props mapping.
|
|
116
|
-
await vi.waitFor(() => expect(typeof seen.onCommit).toBe('function'))
|
|
117
|
-
expect(typeof seen.onCommit).toBe('function')
|
|
118
|
-
expect(typeof seen.onCancel).toBe('function')
|
|
119
|
-
expect(typeof seen.onChange).toBe('function')
|
|
120
|
-
expect(typeof seen.onCommitAndMove).toBe('function')
|
|
121
|
-
expect(typeof seen.onRequestClose).toBe('function')
|
|
122
|
-
expect(seen.inCell).toBe(true)
|
|
123
|
-
expect(seen.rowId).toBeTruthy()
|
|
124
|
-
expect(seen.columnId).toBe('score')
|
|
125
|
-
void target
|
|
126
|
-
} finally {
|
|
127
|
-
destroy()
|
|
128
|
-
}
|
|
129
|
-
})
|
|
130
|
-
|
|
131
|
-
it('defaults to passing the whole contract when a registration has no props mapping', async () => {
|
|
132
|
-
// A registration with no `props` should still work for a contract-aware
|
|
133
|
-
// editor - that is the point of the default mapping.
|
|
134
|
-
registerCellEditor('stars', SvRating)
|
|
135
|
-
const { api, target, destroy } = await mountGrid()
|
|
136
|
-
try {
|
|
137
|
-
api.startEditing(0, 'score')
|
|
138
|
-
// SvGridCellEditor is a lazy chunk; poll rather than fixing a tick count.
|
|
139
|
-
await vi.waitFor(() => expect(target.querySelector('.sv-rating')).not.toBeNull())
|
|
140
|
-
} finally {
|
|
141
|
-
destroy()
|
|
142
|
-
}
|
|
143
|
-
})
|
|
144
|
-
})
|
|
1
|
+
/**
|
|
2
|
+
* Integration test for the cell-editor registry wiring in SvGrid.svelte: a
|
|
3
|
+
* component registered via `registerCellEditor` is actually mounted when a cell
|
|
4
|
+
* of that custom `editorType` starts editing.
|
|
5
|
+
*/
|
|
6
|
+
import { afterEach, describe, expect, it, vi } from 'vitest'
|
|
7
|
+
import { mount, unmount } from 'svelte'
|
|
8
|
+
import SvGrid from './SvGrid.svelte'
|
|
9
|
+
import SvRating from './SvRating.svelte'
|
|
10
|
+
import {
|
|
11
|
+
registerCellEditor,
|
|
12
|
+
unregisterCellEditor,
|
|
13
|
+
createCoreRowModel,
|
|
14
|
+
createFilteredRowModel,
|
|
15
|
+
createPaginatedRowModel,
|
|
16
|
+
createSortedRowModel,
|
|
17
|
+
sortFns,
|
|
18
|
+
tableFeatures,
|
|
19
|
+
columnFilteringFeature,
|
|
20
|
+
rowSortingFeature,
|
|
21
|
+
} from './index'
|
|
22
|
+
import type { ColumnDef, SvGridApi } from './index'
|
|
23
|
+
|
|
24
|
+
type Row = { id: number; name: string; score: number }
|
|
25
|
+
|
|
26
|
+
const features = tableFeatures({ columnFilteringFeature, rowSortingFeature })
|
|
27
|
+
const rows: Row[] = [
|
|
28
|
+
{ id: 1, name: 'Ada', score: 3 },
|
|
29
|
+
{ id: 2, name: 'Alan', score: 5 },
|
|
30
|
+
]
|
|
31
|
+
const cols: ColumnDef<typeof features, Row>[] = [
|
|
32
|
+
{ field: 'name', header: 'Name', width: 200, editorType: 'text' },
|
|
33
|
+
// Custom editor type resolved through the registry:
|
|
34
|
+
{ field: 'score', header: 'Score', width: 160, editorType: 'stars' },
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
function mountGrid() {
|
|
39
|
+
return new Promise<{ api: SvGridApi<typeof features, Row>; target: HTMLElement; destroy: () => void }>(
|
|
40
|
+
(res, rej) => {
|
|
41
|
+
const target = document.createElement('div')
|
|
42
|
+
document.body.appendChild(target)
|
|
43
|
+
const app = mount(SvGrid, {
|
|
44
|
+
target,
|
|
45
|
+
props: {
|
|
46
|
+
data: rows,
|
|
47
|
+
columns: cols,
|
|
48
|
+
features,
|
|
49
|
+
_rowModels: {
|
|
50
|
+
coreRowModel: createCoreRowModel(),
|
|
51
|
+
filteredRowModel: createFilteredRowModel(),
|
|
52
|
+
sortedRowModel: createSortedRowModel(sortFns),
|
|
53
|
+
paginatedRowModel: createPaginatedRowModel(),
|
|
54
|
+
},
|
|
55
|
+
rowHeight: 36,
|
|
56
|
+
containerHeight: 300,
|
|
57
|
+
virtualization: false,
|
|
58
|
+
enableInlineEditing: true,
|
|
59
|
+
onApiReady(api: SvGridApi<typeof features, Row>) {
|
|
60
|
+
res({ api, target, destroy: () => { unmount(app); target.remove() } })
|
|
61
|
+
},
|
|
62
|
+
} as any,
|
|
63
|
+
})
|
|
64
|
+
queueMicrotask(() => rej.length && undefined)
|
|
65
|
+
},
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
afterEach(() => {
|
|
70
|
+
unregisterCellEditor('stars')
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
describe('registry wiring in SvGrid', () => {
|
|
74
|
+
it('mounts a registered component when a custom-editorType cell edits', async () => {
|
|
75
|
+
registerCellEditor('stars', {
|
|
76
|
+
component: SvRating,
|
|
77
|
+
props: (ctx) => ({
|
|
78
|
+
value: ctx.value,
|
|
79
|
+
onChange: (v: number) => ctx.onCommit(v),
|
|
80
|
+
}),
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
const { api, target, destroy } = await mountGrid()
|
|
84
|
+
try {
|
|
85
|
+
api.startEditing(0, 'score')
|
|
86
|
+
// The editor UI is a lazy chunk (SvGridCellEditor), so a fixed number of
|
|
87
|
+
// ticks is a race - poll the same assertion until the import lands.
|
|
88
|
+
await vi.waitFor(() => {
|
|
89
|
+
// The registered SvRating editor is mounted in the editing overlay.
|
|
90
|
+
expect(target.querySelector('.sv-rating')).not.toBeNull()
|
|
91
|
+
})
|
|
92
|
+
} finally {
|
|
93
|
+
destroy()
|
|
94
|
+
}
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
it('hands the editor the full EditorInteraction contract, not a subset', async () => {
|
|
98
|
+
// The contract type used to be documented but never supplied: the registry
|
|
99
|
+
// passed only value/onChange/onCommit/onCancel, so an editor written against
|
|
100
|
+
// `EditorInteraction` (Tab-to-move, dismiss-without-commit, in-cell tuning)
|
|
101
|
+
// silently got undefined for half of it.
|
|
102
|
+
let seen: Record<string, unknown> = {}
|
|
103
|
+
registerCellEditor('stars', {
|
|
104
|
+
component: SvRating,
|
|
105
|
+
props: (ctx) => {
|
|
106
|
+
seen = ctx as unknown as Record<string, unknown>
|
|
107
|
+
return { value: ctx.value }
|
|
108
|
+
},
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
const { api, target, destroy } = await mountGrid()
|
|
112
|
+
try {
|
|
113
|
+
api.startEditing(0, 'score')
|
|
114
|
+
// SvGridCellEditor is a lazy chunk; poll until it has mounted and run the
|
|
115
|
+
// registration's props mapping.
|
|
116
|
+
await vi.waitFor(() => expect(typeof seen.onCommit).toBe('function'))
|
|
117
|
+
expect(typeof seen.onCommit).toBe('function')
|
|
118
|
+
expect(typeof seen.onCancel).toBe('function')
|
|
119
|
+
expect(typeof seen.onChange).toBe('function')
|
|
120
|
+
expect(typeof seen.onCommitAndMove).toBe('function')
|
|
121
|
+
expect(typeof seen.onRequestClose).toBe('function')
|
|
122
|
+
expect(seen.inCell).toBe(true)
|
|
123
|
+
expect(seen.rowId).toBeTruthy()
|
|
124
|
+
expect(seen.columnId).toBe('score')
|
|
125
|
+
void target
|
|
126
|
+
} finally {
|
|
127
|
+
destroy()
|
|
128
|
+
}
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
it('defaults to passing the whole contract when a registration has no props mapping', async () => {
|
|
132
|
+
// A registration with no `props` should still work for a contract-aware
|
|
133
|
+
// editor - that is the point of the default mapping.
|
|
134
|
+
registerCellEditor('stars', SvRating)
|
|
135
|
+
const { api, target, destroy } = await mountGrid()
|
|
136
|
+
try {
|
|
137
|
+
api.startEditing(0, 'score')
|
|
138
|
+
// SvGridCellEditor is a lazy chunk; poll rather than fixing a tick count.
|
|
139
|
+
await vi.waitFor(() => expect(target.querySelector('.sv-rating')).not.toBeNull())
|
|
140
|
+
} finally {
|
|
141
|
+
destroy()
|
|
142
|
+
}
|
|
143
|
+
})
|
|
144
|
+
})
|
package/src/editor-registry.ts
CHANGED
|
@@ -1,122 +1,122 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* editor-registry - the extension point that opens up the grid's cell editors.
|
|
3
|
-
*
|
|
4
|
-
* Historically SvGrid rendered cell editors through a fixed `{#if editorType ===
|
|
5
|
-
* ...}` chain over a closed `CellEditorType` union. This registry lets any
|
|
6
|
-
* component - a built-in `Sv*` editor or one you author - be mounted for a
|
|
7
|
-
* column by name, wired to one uniform in-cell contract (change / commit /
|
|
8
|
-
* cancel). Register once at module load:
|
|
9
|
-
*
|
|
10
|
-
* ```ts
|
|
11
|
-
* import { registerCellEditor } from '@svgrid/grid'
|
|
12
|
-
* import StarRating from './StarRating.svelte'
|
|
13
|
-
* registerCellEditor('stars', StarRating)
|
|
14
|
-
* // then: columns = [{ field: 'score', editorType: 'stars' }]
|
|
15
|
-
* ```
|
|
16
|
-
*
|
|
17
|
-
* The registered component receives the {@link CellEditorContext} as props
|
|
18
|
-
* (value + onChange/onCommit/onCancel), or a custom mapping via `props`.
|
|
19
|
-
* Framework-light: this file only holds the Map + helpers; the grid does the
|
|
20
|
-
* mounting.
|
|
21
|
-
*/
|
|
22
|
-
import type { Component } from 'svelte'
|
|
23
|
-
import type { EditorInteraction } from './editor-contract'
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Context the grid hands a cell editor when it mounts one for an edit.
|
|
27
|
-
*
|
|
28
|
-
* Extends {@link EditorInteraction} - the shared commit / cancel / move contract
|
|
29
|
-
* the `Sv*` editors are written against - and narrows the parts the grid always
|
|
30
|
-
* supplies, so a registered component and a built-in editor speak the same
|
|
31
|
-
* language. `onCommitAndMove`, `onRequestClose` and `inCell` come from the
|
|
32
|
-
* contract and are always populated by the grid.
|
|
33
|
-
*/
|
|
34
|
-
export type CellEditorContext<T = unknown> = Required<
|
|
35
|
-
Pick<EditorInteraction<T>, 'onCommit' | 'onCancel' | 'onCommitAndMove' | 'onRequestClose' | 'inCell'>
|
|
36
|
-
> & {
|
|
37
|
-
/** The value currently being edited. */
|
|
38
|
-
value: T
|
|
39
|
-
/** Id of the row being edited. */
|
|
40
|
-
rowId: string
|
|
41
|
-
/** Id of the column being edited. */
|
|
42
|
-
columnId: string
|
|
43
|
-
/** Update the in-progress value WITHOUT ending the edit. */
|
|
44
|
-
onChange: (value: T) => void
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/** How a registered component is mounted and wired for a cell edit. */
|
|
48
|
-
export type CellEditorRegistration = {
|
|
49
|
-
/** The Svelte component to mount in the editing cell. */
|
|
50
|
-
component: Component<any>
|
|
51
|
-
/**
|
|
52
|
-
* Map the editing context to the component's props. Defaults to
|
|
53
|
-
* {@link defaultEditorProps} (value + onChange/onCommit/onCancel).
|
|
54
|
-
*/
|
|
55
|
-
props?: (ctx: CellEditorContext) => Record<string, unknown>
|
|
56
|
-
/** Hint that the editor should open its popover immediately on mount. */
|
|
57
|
-
autoOpen?: boolean
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const registry = new Map<string, CellEditorRegistration>()
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Register a cell editor under `type`. Pass a component (uses the default prop
|
|
64
|
-
* mapping) or a full {@link CellEditorRegistration} for custom prop mapping.
|
|
65
|
-
* Re-registering the same type replaces it.
|
|
66
|
-
*/
|
|
67
|
-
export function registerCellEditor(
|
|
68
|
-
type: string,
|
|
69
|
-
registration: CellEditorRegistration | Component<any>,
|
|
70
|
-
): void {
|
|
71
|
-
registry.set(
|
|
72
|
-
type,
|
|
73
|
-
typeof registration === 'function' ? { component: registration } : registration,
|
|
74
|
-
)
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/** Look up a registered cell editor by type. */
|
|
78
|
-
export function getCellEditor(type: string): CellEditorRegistration | undefined {
|
|
79
|
-
return registry.get(type)
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/** Whether a custom editor is registered for `type`. */
|
|
83
|
-
export function hasCellEditor(type: string): boolean {
|
|
84
|
-
return registry.has(type)
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/** Remove a registered cell editor. */
|
|
88
|
-
export function unregisterCellEditor(type: string): void {
|
|
89
|
-
registry.delete(type)
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/** All registered custom editor type names. */
|
|
93
|
-
export function registeredCellEditorTypes(): string[] {
|
|
94
|
-
return [...registry.keys()]
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* The default context → props mapping used when a registration has no `props`.
|
|
99
|
-
* Passes the whole {@link EditorInteraction} surface, so an editor written
|
|
100
|
-
* against the shared contract works when registered with no mapping at all.
|
|
101
|
-
* Svelte ignores props a component doesn't declare, so the extra keys are inert
|
|
102
|
-
* for a simple editor that only wants `value` + `onCommit`.
|
|
103
|
-
*/
|
|
104
|
-
export function defaultEditorProps(ctx: CellEditorContext): Record<string, unknown> {
|
|
105
|
-
return {
|
|
106
|
-
value: ctx.value,
|
|
107
|
-
onChange: ctx.onChange,
|
|
108
|
-
onCommit: ctx.onCommit,
|
|
109
|
-
onCancel: ctx.onCancel,
|
|
110
|
-
onCommitAndMove: ctx.onCommitAndMove,
|
|
111
|
-
onRequestClose: ctx.onRequestClose,
|
|
112
|
-
inCell: ctx.inCell,
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/** Resolve the props to spread onto a registered editor for a given context. */
|
|
117
|
-
export function resolveEditorProps(
|
|
118
|
-
registration: CellEditorRegistration,
|
|
119
|
-
ctx: CellEditorContext,
|
|
120
|
-
): Record<string, unknown> {
|
|
121
|
-
return registration.props ? registration.props(ctx) : defaultEditorProps(ctx)
|
|
122
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* editor-registry - the extension point that opens up the grid's cell editors.
|
|
3
|
+
*
|
|
4
|
+
* Historically SvGrid rendered cell editors through a fixed `{#if editorType ===
|
|
5
|
+
* ...}` chain over a closed `CellEditorType` union. This registry lets any
|
|
6
|
+
* component - a built-in `Sv*` editor or one you author - be mounted for a
|
|
7
|
+
* column by name, wired to one uniform in-cell contract (change / commit /
|
|
8
|
+
* cancel). Register once at module load:
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { registerCellEditor } from '@svgrid/grid'
|
|
12
|
+
* import StarRating from './StarRating.svelte'
|
|
13
|
+
* registerCellEditor('stars', StarRating)
|
|
14
|
+
* // then: columns = [{ field: 'score', editorType: 'stars' }]
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* The registered component receives the {@link CellEditorContext} as props
|
|
18
|
+
* (value + onChange/onCommit/onCancel), or a custom mapping via `props`.
|
|
19
|
+
* Framework-light: this file only holds the Map + helpers; the grid does the
|
|
20
|
+
* mounting.
|
|
21
|
+
*/
|
|
22
|
+
import type { Component } from 'svelte'
|
|
23
|
+
import type { EditorInteraction } from './editor-contract'
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Context the grid hands a cell editor when it mounts one for an edit.
|
|
27
|
+
*
|
|
28
|
+
* Extends {@link EditorInteraction} - the shared commit / cancel / move contract
|
|
29
|
+
* the `Sv*` editors are written against - and narrows the parts the grid always
|
|
30
|
+
* supplies, so a registered component and a built-in editor speak the same
|
|
31
|
+
* language. `onCommitAndMove`, `onRequestClose` and `inCell` come from the
|
|
32
|
+
* contract and are always populated by the grid.
|
|
33
|
+
*/
|
|
34
|
+
export type CellEditorContext<T = unknown> = Required<
|
|
35
|
+
Pick<EditorInteraction<T>, 'onCommit' | 'onCancel' | 'onCommitAndMove' | 'onRequestClose' | 'inCell'>
|
|
36
|
+
> & {
|
|
37
|
+
/** The value currently being edited. */
|
|
38
|
+
value: T
|
|
39
|
+
/** Id of the row being edited. */
|
|
40
|
+
rowId: string
|
|
41
|
+
/** Id of the column being edited. */
|
|
42
|
+
columnId: string
|
|
43
|
+
/** Update the in-progress value WITHOUT ending the edit. */
|
|
44
|
+
onChange: (value: T) => void
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** How a registered component is mounted and wired for a cell edit. */
|
|
48
|
+
export type CellEditorRegistration = {
|
|
49
|
+
/** The Svelte component to mount in the editing cell. */
|
|
50
|
+
component: Component<any>
|
|
51
|
+
/**
|
|
52
|
+
* Map the editing context to the component's props. Defaults to
|
|
53
|
+
* {@link defaultEditorProps} (value + onChange/onCommit/onCancel).
|
|
54
|
+
*/
|
|
55
|
+
props?: (ctx: CellEditorContext) => Record<string, unknown>
|
|
56
|
+
/** Hint that the editor should open its popover immediately on mount. */
|
|
57
|
+
autoOpen?: boolean
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const registry = new Map<string, CellEditorRegistration>()
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Register a cell editor under `type`. Pass a component (uses the default prop
|
|
64
|
+
* mapping) or a full {@link CellEditorRegistration} for custom prop mapping.
|
|
65
|
+
* Re-registering the same type replaces it.
|
|
66
|
+
*/
|
|
67
|
+
export function registerCellEditor(
|
|
68
|
+
type: string,
|
|
69
|
+
registration: CellEditorRegistration | Component<any>,
|
|
70
|
+
): void {
|
|
71
|
+
registry.set(
|
|
72
|
+
type,
|
|
73
|
+
typeof registration === 'function' ? { component: registration } : registration,
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Look up a registered cell editor by type. */
|
|
78
|
+
export function getCellEditor(type: string): CellEditorRegistration | undefined {
|
|
79
|
+
return registry.get(type)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Whether a custom editor is registered for `type`. */
|
|
83
|
+
export function hasCellEditor(type: string): boolean {
|
|
84
|
+
return registry.has(type)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Remove a registered cell editor. */
|
|
88
|
+
export function unregisterCellEditor(type: string): void {
|
|
89
|
+
registry.delete(type)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** All registered custom editor type names. */
|
|
93
|
+
export function registeredCellEditorTypes(): string[] {
|
|
94
|
+
return [...registry.keys()]
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* The default context → props mapping used when a registration has no `props`.
|
|
99
|
+
* Passes the whole {@link EditorInteraction} surface, so an editor written
|
|
100
|
+
* against the shared contract works when registered with no mapping at all.
|
|
101
|
+
* Svelte ignores props a component doesn't declare, so the extra keys are inert
|
|
102
|
+
* for a simple editor that only wants `value` + `onCommit`.
|
|
103
|
+
*/
|
|
104
|
+
export function defaultEditorProps(ctx: CellEditorContext): Record<string, unknown> {
|
|
105
|
+
return {
|
|
106
|
+
value: ctx.value,
|
|
107
|
+
onChange: ctx.onChange,
|
|
108
|
+
onCommit: ctx.onCommit,
|
|
109
|
+
onCancel: ctx.onCancel,
|
|
110
|
+
onCommitAndMove: ctx.onCommitAndMove,
|
|
111
|
+
onRequestClose: ctx.onRequestClose,
|
|
112
|
+
inCell: ctx.inCell,
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** Resolve the props to spread onto a registered editor for a given context. */
|
|
117
|
+
export function resolveEditorProps(
|
|
118
|
+
registration: CellEditorRegistration,
|
|
119
|
+
ctx: CellEditorContext,
|
|
120
|
+
): Record<string, unknown> {
|
|
121
|
+
return registration.props ? registration.props(ctx) : defaultEditorProps(ctx)
|
|
122
|
+
}
|
|
@@ -35,6 +35,17 @@ export type CellEditorOption = { value: string | number; label: string; color?:
|
|
|
35
35
|
export type ParseEditorValueOptions = {
|
|
36
36
|
/** When true, list/chips return an array; otherwise a scalar. */
|
|
37
37
|
multiple?: boolean
|
|
38
|
+
/**
|
|
39
|
+
* Keep a date as the plain `YYYY-MM-DD` string the user picked, instead of a
|
|
40
|
+
* full ISO timestamp. Set for `cellDataType: 'dateString'` columns, which
|
|
41
|
+
* exist precisely to hold ISO date strings.
|
|
42
|
+
*
|
|
43
|
+
* It is not only about shape. `new Date('2026-12-25').toISOString()` sends
|
|
44
|
+
* the value through UTC, so a local midnight becomes the previous or next
|
|
45
|
+
* day either side of the meridian - the stored DATE changes depending on
|
|
46
|
+
* where the user is sitting. Slicing the picked date avoids that entirely.
|
|
47
|
+
*/
|
|
48
|
+
dateOnly?: boolean
|
|
38
49
|
}
|
|
39
50
|
|
|
40
51
|
/** Normalize the loose `editorOptions` ColumnDef prop into a uniform shape.
|
|
@@ -83,7 +94,22 @@ export function parseEditorValue(
|
|
|
83
94
|
return s || '#000000'
|
|
84
95
|
}
|
|
85
96
|
if (type === 'date') {
|
|
86
|
-
const
|
|
97
|
+
const raw = String(value ?? '')
|
|
98
|
+
if (opts?.dateOnly) {
|
|
99
|
+
// Take the calendar date the editor produced as-is. It already arrives
|
|
100
|
+
// as `YYYY-MM-DD` (or that prefix on a datetime), so there is nothing to
|
|
101
|
+
// convert - and converting is exactly what shifts the day across a
|
|
102
|
+
// timezone boundary.
|
|
103
|
+
const match = /^(\d{4}-\d{2}-\d{2})/.exec(raw.trim())
|
|
104
|
+
if (match) return match[1]
|
|
105
|
+
const parsed = new Date(raw)
|
|
106
|
+
if (Number.isNaN(parsed.getTime())) return null
|
|
107
|
+
// A non-ISO input (a locale string) still has to become a date string.
|
|
108
|
+
// Use the LOCAL parts, so the day is the one the user saw.
|
|
109
|
+
const pad = (n: number) => String(n).padStart(2, '0')
|
|
110
|
+
return `${parsed.getFullYear()}-${pad(parsed.getMonth() + 1)}-${pad(parsed.getDate())}`
|
|
111
|
+
}
|
|
112
|
+
const date = new Date(raw)
|
|
87
113
|
return Number.isNaN(date.getTime()) ? null : date.toISOString()
|
|
88
114
|
}
|
|
89
115
|
if (type === 'datetime') {
|