@svgrid/grid 2.2.27 → 2.2.29
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/README.md +199 -199
- package/dist/FlexRender.svelte +96 -96
- package/dist/GridFooter.svelte +179 -179
- package/dist/GridMenus.svelte +782 -734
- package/dist/SvAutoComplete.svelte +165 -165
- package/dist/SvCalendar.svelte +503 -503
- package/dist/SvCarousel.svelte +141 -141
- package/dist/SvCheckBox.svelte +101 -101
- package/dist/SvColorInput.svelte +181 -181
- package/dist/SvComboBox.svelte +275 -275
- package/dist/SvContextMenu.svelte +116 -116
- package/dist/SvCountryInput.svelte +160 -160
- package/dist/SvDrawer.svelte +254 -250
- package/dist/SvDropDownList.svelte +374 -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 +14 -1
- package/dist/SvGrid.controller.svelte.js +112 -28
- package/dist/SvGrid.css +2704 -2723
- package/dist/SvGrid.svelte +3361 -3333
- package/dist/SvGrid.types.d.ts +20 -5
- package/dist/SvGridChart.svelte +1724 -1724
- package/dist/SvGridChartPanel.svelte +485 -485
- package/dist/SvGridChartView.svelte +70 -70
- package/dist/SvGridDropdown.svelte +696 -696
- package/dist/SvGridSelect.svelte +259 -259
- package/dist/SvGroupCell.svelte +109 -109
- package/dist/SvListBox.svelte +326 -287
- package/dist/SvListBox.svelte.d.ts +10 -1
- package/dist/SvMaskedInput.svelte +122 -122
- package/dist/SvMenu.svelte +124 -124
- package/dist/SvMenuList.svelte +146 -146
- package/dist/SvMultiSelect.svelte +281 -281
- package/dist/SvNumberInput.svelte +168 -168
- package/dist/SvOtpInput.svelte +158 -158
- package/dist/SvPasswordInput.svelte +151 -151
- package/dist/SvPhoneInput.svelte +133 -131
- package/dist/SvPopover.svelte +197 -197
- package/dist/SvRadioGroup.svelte +107 -107
- package/dist/SvRowGroupPanel.svelte +170 -170
- package/dist/SvScrollArea.svelte +61 -61
- package/dist/SvSlider.svelte +200 -200
- package/dist/SvSwitchButton.svelte +107 -107
- package/dist/SvTagsInput.svelte +112 -112
- 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 +204 -204
- package/dist/SvTree.svelte +437 -437
- package/dist/SvTreeSelect.svelte +233 -233
- package/dist/cdn/GridMenus-Da_p7SKS.js +486 -0
- package/dist/cdn/GridMenus-Ds3OpzZT.js +490 -0
- package/dist/cdn/{SvDateTimePicker-B1sDc9Pz.js → SvDateTimePicker-B8GopjhC.js} +2 -2
- package/dist/cdn/{SvDateTimePicker-Bh0FTs1E.js → SvDateTimePicker-DB0aIEk8.js} +2 -2
- package/dist/cdn/{SvGridChart-Bgk4hDs8.js → SvGridChart-BcLCYvw9.js} +1 -1
- package/dist/cdn/{SvGridChart-BKQsO5fZ.js → SvGridChart-BhnFdLd0.js} +1 -1
- package/dist/cdn/{SvGridChartPanel-DkCc2Z7b.js → SvGridChartPanel-Cmx9DHAS.js} +1 -1
- package/dist/cdn/{SvGridChartPanel-DSkHIQDd.js → SvGridChartPanel-DvjwxLvK.js} +1 -1
- package/dist/cdn/{SvGridChartView-BrbVaELm.js → SvGridChartView-B40DTJSX.js} +1 -1
- package/dist/cdn/{SvGridChartView-i9rWvSKg.js → SvGridChartView-PwqI4s02.js} +1 -1
- package/dist/cdn/{SvGridDropdown-D08sVmAy.js → SvGridDropdown-DjALc_4f.js} +1 -1
- package/dist/cdn/{SvGridDropdown-CGxxopQ4.js → SvGridDropdown-hpnHvOGt.js} +1 -1
- package/dist/cdn/{src-cgs1wcUS.js → src-BLJfdyL0.js} +4034 -3889
- package/dist/cdn/{src-Cw8d9U8j.js → src-DYDCiC0D.js} +7053 -6908
- package/dist/cdn/svgrid.js +9 -9
- package/dist/cdn/svgrid.svelte-external.js +9 -9
- package/dist/chart-export.js +8 -8
- package/dist/column-groups.js +8 -10
- package/dist/column-id.d.ts +9 -0
- package/dist/column-id.js +25 -0
- package/dist/core.js +2 -1
- package/dist/createListbox.svelte.d.ts +15 -2
- package/dist/createListbox.svelte.js +27 -6
- package/dist/editing.d.ts +1 -0
- package/dist/editing.js +45 -10
- package/dist/filtering/excel-filters.d.ts +30 -10
- package/dist/filtering/excel-filters.js +96 -15
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/menus.d.ts +2 -0
- package/dist/menus.js +25 -0
- package/dist/row-resize.js +40 -0
- package/dist/selection.js +1 -1
- package/package.json +10 -10
- package/src/FlexRender.svelte +96 -96
- package/src/GridFooter.svelte +179 -179
- package/src/GridMenus.svelte +782 -734
- package/src/SvAutoComplete.svelte +165 -165
- package/src/SvCalendar.svelte +503 -503
- package/src/SvCalendar.test.ts +226 -226
- package/src/SvCarousel.svelte +141 -141
- package/src/SvCheckBox.svelte +101 -101
- package/src/SvColorInput.svelte +181 -181
- package/src/SvComboBox.svelte +275 -275
- package/src/SvContextMenu.svelte +116 -116
- package/src/SvCountryInput.svelte +160 -160
- package/src/SvDrawer.svelte +254 -250
- package/src/SvDrawer.test.ts +18 -1
- package/src/SvDropDownList.svelte +374 -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 +3335 -3239
- package/src/SvGrid.css +2704 -2723
- package/src/SvGrid.svelte +3361 -3333
- package/src/SvGrid.types.ts +1628 -1613
- package/src/SvGridChart.svelte +1724 -1724
- package/src/SvGridChartPanel.svelte +485 -485
- package/src/SvGridChartView.svelte +70 -70
- package/src/SvGridDropdown.svelte +696 -696
- package/src/SvGridSelect.svelte +259 -259
- package/src/SvGroupCell.svelte +109 -109
- package/src/SvListBox.svelte +326 -287
- 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 +281 -281
- package/src/SvNavPane.test.ts +15 -4
- package/src/SvNumberInput.svelte +168 -168
- package/src/SvOtpInput.svelte +158 -158
- package/src/SvPasswordInput.svelte +151 -151
- package/src/SvPhoneInput.svelte +133 -131
- package/src/SvPopover.svelte +197 -197
- package/src/SvRadioGroup.svelte +107 -107
- package/src/SvRowGroupPanel.svelte +170 -170
- package/src/SvScrollArea.svelte +61 -61
- package/src/SvSlider.svelte +200 -200
- package/src/SvSwitchButton.svelte +107 -107
- package/src/SvTagsInput.svelte +112 -112
- 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 +204 -204
- package/src/SvTree.svelte +437 -437
- package/src/SvTreeSelect.svelte +233 -233
- 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 +1391 -1391
- package/src/build-api.coverage.test.ts +633 -633
- package/src/build-api.ts +895 -895
- package/src/builtin-editors.grid.test.ts +85 -85
- package/src/cell-formatting.ts +169 -169
- package/src/cell-render.ts +469 -469
- package/src/chart-export.ts +201 -201
- package/src/chart-view.svelte.ts +36 -36
- package/src/chart.ts +2296 -2296
- package/src/collaboration.test.ts +104 -104
- package/src/collaboration.ts +167 -167
- package/src/column-groups.test.ts +48 -0
- package/src/column-groups.ts +8 -10
- package/src/column-id.ts +30 -0
- package/src/core.performance.test.ts +30 -30
- package/src/core.ts +1112 -1111
- 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 +39 -7
- package/src/createMenu.svelte.ts +225 -225
- 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 +319 -319
- package/src/editing.test.ts +949 -859
- package/src/editing.ts +709 -675
- package/src/editor-contract.ts +157 -157
- package/src/export-data-api.test.ts +126 -126
- package/src/export-format.test.ts +107 -107
- package/src/export-format.ts +598 -598
- package/src/filter-operators.ts +157 -157
- package/src/filtering/excel-filters.test.ts +44 -1
- package/src/filtering/excel-filters.ts +91 -14
- package/src/flex-render.ts +3 -3
- package/src/form-field.ts +127 -127
- package/src/index.ts +715 -713
- package/src/js-scroller.svelte.ts +173 -173
- 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 +172 -172
- package/src/menus.test.ts +736 -700
- package/src/menus.ts +679 -652
- package/src/merge-objects.ts +48 -48
- package/src/overlays.test.ts +90 -90
- package/src/render-component.ts +28 -28
- package/src/row-resize.test.ts +100 -0
- package/src/row-resize.ts +36 -0
- package/src/scheduler-model.test.ts +562 -562
- package/src/scheduler-model.ts +872 -872
- package/src/selection.test.ts +754 -754
- package/src/selection.ts +600 -600
- package/src/server-data-source.test.ts +289 -289
- package/src/server-data-source.ts +413 -413
- package/src/sparkline.test.ts +68 -68
- package/src/sparkline.ts +169 -169
- package/src/spreadsheet.test.ts +489 -489
- package/src/spreadsheet.ts +312 -312
- package/src/static-functions.ts +11 -11
- package/src/subscribe.ts +38 -38
- package/src/svgrid-wrapper.types.ts +524 -524
- package/src/svgrid.api-extensions.test.ts +8 -3
- package/src/svgrid.behavior.test.ts +706 -706
- package/src/svgrid.cell-dom-ids.test.ts +96 -0
- package/src/svgrid.charting.test.ts +534 -534
- package/src/svgrid.conditional-stat-scope.test.ts +111 -0
- package/src/svgrid.features.test.ts +157 -157
- package/src/svgrid.filter-menu-listbox.svelte.test.ts +308 -0
- package/src/svgrid.filter-menu-scroll.test.ts +3 -1
- package/src/svgrid.group-header-ids.test.ts +121 -0
- package/src/svgrid.new-features.wrapper.test.ts +251 -251
- package/src/svgrid.wrapper.test.ts +40 -40
- package/src/test-setup.ts +62 -62
- package/src/themes/index.ts +215 -215
- package/src/toast-store.svelte.ts +246 -246
- package/src/toast-store.test.ts +147 -147
- package/src/ui-buttons.test.ts +144 -144
- package/src/ui-inputs.test.ts +118 -118
- 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 +296 -296
- package/themes/ember.css +71 -71
- package/dist/cdn/GridMenus-BzxEYNtW.js +0 -421
- package/dist/cdn/GridMenus-Dr-nGEXn.js +0 -417
|
@@ -1,85 +1,85 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* End-to-end: after registerBuiltinEditors(), a column with editorType 'duration'
|
|
3
|
-
* mounts SvDurationInput in the editing cell (proving the built-in registration +
|
|
4
|
-
* the SvGrid registry wiring together).
|
|
5
|
-
*/
|
|
6
|
-
import { afterEach, describe, expect, it } from 'vitest'
|
|
7
|
-
import { mount, unmount } from 'svelte'
|
|
8
|
-
import SvGrid from './SvGrid.svelte'
|
|
9
|
-
import {
|
|
10
|
-
registerBuiltinEditors,
|
|
11
|
-
unregisterCellEditor,
|
|
12
|
-
registeredCellEditorTypes,
|
|
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; task: string; estimate: number }
|
|
25
|
-
|
|
26
|
-
const features = tableFeatures({ columnFilteringFeature, rowSortingFeature })
|
|
27
|
-
const rows: Row[] = [
|
|
28
|
-
{ id: 1, task: 'Design', estimate: 90 },
|
|
29
|
-
{ id: 2, task: 'Build', estimate: 240 },
|
|
30
|
-
]
|
|
31
|
-
const cols: ColumnDef<typeof features, Row>[] = [
|
|
32
|
-
{ field: 'task', header: 'Task', width: 200, editorType: 'text' },
|
|
33
|
-
{ field: 'estimate', header: 'Estimate', width: 160, editorType: 'duration' },
|
|
34
|
-
]
|
|
35
|
-
|
|
36
|
-
const tick = () => new Promise<void>((r) => queueMicrotask(r))
|
|
37
|
-
|
|
38
|
-
function mountGrid() {
|
|
39
|
-
return new Promise<{ api: SvGridApi<typeof features, Row>; target: HTMLElement; destroy: () => void }>(
|
|
40
|
-
(res) => {
|
|
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
|
-
},
|
|
65
|
-
)
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
afterEach(() => {
|
|
69
|
-
for (const t of registeredCellEditorTypes()) unregisterCellEditor(t)
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
describe('registerBuiltinEditors in SvGrid', () => {
|
|
73
|
-
it("mounts SvDurationInput for an editorType 'duration' cell", async () => {
|
|
74
|
-
registerBuiltinEditors()
|
|
75
|
-
const { api, target, destroy } = await mountGrid()
|
|
76
|
-
try {
|
|
77
|
-
api.startEditing(0, 'estimate')
|
|
78
|
-
await tick()
|
|
79
|
-
await tick()
|
|
80
|
-
expect(target.querySelector('.sv-dur__input')).not.toBeNull()
|
|
81
|
-
} finally {
|
|
82
|
-
destroy()
|
|
83
|
-
}
|
|
84
|
-
})
|
|
85
|
-
})
|
|
1
|
+
/**
|
|
2
|
+
* End-to-end: after registerBuiltinEditors(), a column with editorType 'duration'
|
|
3
|
+
* mounts SvDurationInput in the editing cell (proving the built-in registration +
|
|
4
|
+
* the SvGrid registry wiring together).
|
|
5
|
+
*/
|
|
6
|
+
import { afterEach, describe, expect, it } from 'vitest'
|
|
7
|
+
import { mount, unmount } from 'svelte'
|
|
8
|
+
import SvGrid from './SvGrid.svelte'
|
|
9
|
+
import {
|
|
10
|
+
registerBuiltinEditors,
|
|
11
|
+
unregisterCellEditor,
|
|
12
|
+
registeredCellEditorTypes,
|
|
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; task: string; estimate: number }
|
|
25
|
+
|
|
26
|
+
const features = tableFeatures({ columnFilteringFeature, rowSortingFeature })
|
|
27
|
+
const rows: Row[] = [
|
|
28
|
+
{ id: 1, task: 'Design', estimate: 90 },
|
|
29
|
+
{ id: 2, task: 'Build', estimate: 240 },
|
|
30
|
+
]
|
|
31
|
+
const cols: ColumnDef<typeof features, Row>[] = [
|
|
32
|
+
{ field: 'task', header: 'Task', width: 200, editorType: 'text' },
|
|
33
|
+
{ field: 'estimate', header: 'Estimate', width: 160, editorType: 'duration' },
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
const tick = () => new Promise<void>((r) => queueMicrotask(r))
|
|
37
|
+
|
|
38
|
+
function mountGrid() {
|
|
39
|
+
return new Promise<{ api: SvGridApi<typeof features, Row>; target: HTMLElement; destroy: () => void }>(
|
|
40
|
+
(res) => {
|
|
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
|
+
},
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
afterEach(() => {
|
|
69
|
+
for (const t of registeredCellEditorTypes()) unregisterCellEditor(t)
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
describe('registerBuiltinEditors in SvGrid', () => {
|
|
73
|
+
it("mounts SvDurationInput for an editorType 'duration' cell", async () => {
|
|
74
|
+
registerBuiltinEditors()
|
|
75
|
+
const { api, target, destroy } = await mountGrid()
|
|
76
|
+
try {
|
|
77
|
+
api.startEditing(0, 'estimate')
|
|
78
|
+
await tick()
|
|
79
|
+
await tick()
|
|
80
|
+
expect(target.querySelector('.sv-dur__input')).not.toBeNull()
|
|
81
|
+
} finally {
|
|
82
|
+
destroy()
|
|
83
|
+
}
|
|
84
|
+
})
|
|
85
|
+
})
|
package/src/cell-formatting.ts
CHANGED
|
@@ -1,169 +1,169 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Helpers for SvGrid column `format` presets (numbers, currency, percent, date patterns).
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
/** Map shortcut date patterns to Intl options (merged with caller `options`). */
|
|
6
|
-
export function resolveDatePattern(
|
|
7
|
-
pattern: string | undefined,
|
|
8
|
-
kind: 'date' | 'datetime',
|
|
9
|
-
): Intl.DateTimeFormatOptions | undefined {
|
|
10
|
-
if (!pattern) return undefined
|
|
11
|
-
|
|
12
|
-
const p = pattern.trim()
|
|
13
|
-
|
|
14
|
-
switch (p) {
|
|
15
|
-
/** Short numeric local date (no weekday). */
|
|
16
|
-
case 'd':
|
|
17
|
-
return kind === 'datetime'
|
|
18
|
-
? {
|
|
19
|
-
year: 'numeric',
|
|
20
|
-
month: 'numeric',
|
|
21
|
-
day: 'numeric',
|
|
22
|
-
hour: 'numeric',
|
|
23
|
-
minute: 'numeric',
|
|
24
|
-
}
|
|
25
|
-
: { year: 'numeric', month: 'numeric', day: 'numeric' }
|
|
26
|
-
/** Long spelled-out date (+ time if datetime). */
|
|
27
|
-
case 'D':
|
|
28
|
-
return kind === 'datetime'
|
|
29
|
-
? {
|
|
30
|
-
weekday: 'long',
|
|
31
|
-
year: 'numeric',
|
|
32
|
-
month: 'long',
|
|
33
|
-
day: 'numeric',
|
|
34
|
-
hour: 'numeric',
|
|
35
|
-
minute: 'numeric',
|
|
36
|
-
}
|
|
37
|
-
: { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }
|
|
38
|
-
/** ISO-friendly yyyy-mm-dd (with time when datetime). */
|
|
39
|
-
case 'y-m-d':
|
|
40
|
-
return kind === 'datetime'
|
|
41
|
-
? {
|
|
42
|
-
year: 'numeric',
|
|
43
|
-
month: '2-digit',
|
|
44
|
-
day: '2-digit',
|
|
45
|
-
hour: '2-digit',
|
|
46
|
-
minute: '2-digit',
|
|
47
|
-
hour12: false,
|
|
48
|
-
}
|
|
49
|
-
: { year: 'numeric', month: '2-digit', day: '2-digit' }
|
|
50
|
-
case 'medium':
|
|
51
|
-
return { dateStyle: 'medium', timeStyle: kind === 'datetime' ? 'short' : undefined }
|
|
52
|
-
case 'short':
|
|
53
|
-
return { dateStyle: 'short', timeStyle: kind === 'datetime' ? 'short' : undefined }
|
|
54
|
-
case 'long':
|
|
55
|
-
return { dateStyle: 'long', timeStyle: kind === 'datetime' ? 'short' : undefined }
|
|
56
|
-
default:
|
|
57
|
-
return undefined
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
type NumericFormatInput = {
|
|
62
|
-
type: 'number' | 'currency' | 'percent'
|
|
63
|
-
locales?: string | readonly string[]
|
|
64
|
-
currency?: string
|
|
65
|
-
/** When type is percent: treat value as 0–100 instead of Intl’s 0–1 fraction */
|
|
66
|
-
valueIsPercentPoints?: boolean
|
|
67
|
-
options?: Intl.NumberFormatOptions
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* `Intl.NumberFormat` is one of the most expensive constructors in the
|
|
72
|
-
* platform - building one per cell on every scroll makes large grids
|
|
73
|
-
* noticeably stutter. Cache instances by config signature (locale + style
|
|
74
|
-
* + currency + options).
|
|
75
|
-
*/
|
|
76
|
-
const numberFormatterCache = new Map<string, Intl.NumberFormat>()
|
|
77
|
-
function getNumberFormatter(
|
|
78
|
-
locales: string | readonly string[] | undefined,
|
|
79
|
-
options: Intl.NumberFormatOptions,
|
|
80
|
-
): Intl.NumberFormat {
|
|
81
|
-
// Stable key - for normal column configs the options object is reused
|
|
82
|
-
// (declared in module scope), so this stringifies a small static shape.
|
|
83
|
-
const key =
|
|
84
|
-
(Array.isArray(locales) ? locales.join(',') : locales ?? '') +
|
|
85
|
-
'|' +
|
|
86
|
-
(options.style ?? '') +
|
|
87
|
-
'|' +
|
|
88
|
-
(options.currency ?? '') +
|
|
89
|
-
'|' +
|
|
90
|
-
(options.minimumFractionDigits ?? '') +
|
|
91
|
-
'|' +
|
|
92
|
-
(options.maximumFractionDigits ?? '') +
|
|
93
|
-
'|' +
|
|
94
|
-
(options.useGrouping ?? '') +
|
|
95
|
-
'|' +
|
|
96
|
-
(options.currencyDisplay ?? '') +
|
|
97
|
-
'|' +
|
|
98
|
-
(options.notation ?? '')
|
|
99
|
-
let fmt = numberFormatterCache.get(key)
|
|
100
|
-
if (!fmt) {
|
|
101
|
-
fmt = new Intl.NumberFormat(locales as string | string[] | undefined, options)
|
|
102
|
-
numberFormatterCache.set(key, fmt)
|
|
103
|
-
}
|
|
104
|
-
return fmt
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/** Cache of `Intl.DateTimeFormat` by `(locale, options)` signature. */
|
|
108
|
-
const dateFormatterCache = new Map<string, Intl.DateTimeFormat>()
|
|
109
|
-
export function getDateFormatter(
|
|
110
|
-
locales: string | readonly string[] | undefined,
|
|
111
|
-
options: Intl.DateTimeFormatOptions,
|
|
112
|
-
): Intl.DateTimeFormat {
|
|
113
|
-
const key =
|
|
114
|
-
(Array.isArray(locales) ? locales.join(',') : locales ?? '') +
|
|
115
|
-
'|' +
|
|
116
|
-
(options.dateStyle ?? '') +
|
|
117
|
-
'|' +
|
|
118
|
-
(options.timeStyle ?? '') +
|
|
119
|
-
'|' +
|
|
120
|
-
(options.year ?? '') +
|
|
121
|
-
'|' +
|
|
122
|
-
(options.month ?? '') +
|
|
123
|
-
'|' +
|
|
124
|
-
(options.day ?? '') +
|
|
125
|
-
'|' +
|
|
126
|
-
(options.hour ?? '') +
|
|
127
|
-
'|' +
|
|
128
|
-
(options.minute ?? '') +
|
|
129
|
-
'|' +
|
|
130
|
-
(options.second ?? '') +
|
|
131
|
-
'|' +
|
|
132
|
-
(options.weekday ?? '') +
|
|
133
|
-
'|' +
|
|
134
|
-
(options.hour12 ?? '')
|
|
135
|
-
let fmt = dateFormatterCache.get(key)
|
|
136
|
-
if (!fmt) {
|
|
137
|
-
fmt = new Intl.DateTimeFormat(locales as string | string[] | undefined, options)
|
|
138
|
-
dateFormatterCache.set(key, fmt)
|
|
139
|
-
}
|
|
140
|
-
return fmt
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/** Format a numeric value for number / currency / percent column formats. */
|
|
144
|
-
export function formatNumericWithConfig(value: unknown, config: NumericFormatInput): string {
|
|
145
|
-
const n = typeof value === 'number' ? value : Number(value)
|
|
146
|
-
if (!Number.isFinite(n)) return String(value ?? '')
|
|
147
|
-
|
|
148
|
-
const locales = config.locales
|
|
149
|
-
|
|
150
|
-
if (config.type === 'currency') {
|
|
151
|
-
return getNumberFormatter(locales, {
|
|
152
|
-
style: 'currency',
|
|
153
|
-
currency: config.currency ?? 'USD',
|
|
154
|
-
...config.options,
|
|
155
|
-
}).format(n)
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
if (config.type === 'percent') {
|
|
159
|
-
const frac = config.valueIsPercentPoints === true ? n / 100 : n
|
|
160
|
-
return getNumberFormatter(locales, {
|
|
161
|
-
style: 'percent',
|
|
162
|
-
minimumFractionDigits: 0,
|
|
163
|
-
maximumFractionDigits: 2,
|
|
164
|
-
...config.options,
|
|
165
|
-
}).format(frac)
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
return getNumberFormatter(locales, config.options ?? {}).format(n)
|
|
169
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Helpers for SvGrid column `format` presets (numbers, currency, percent, date patterns).
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/** Map shortcut date patterns to Intl options (merged with caller `options`). */
|
|
6
|
+
export function resolveDatePattern(
|
|
7
|
+
pattern: string | undefined,
|
|
8
|
+
kind: 'date' | 'datetime',
|
|
9
|
+
): Intl.DateTimeFormatOptions | undefined {
|
|
10
|
+
if (!pattern) return undefined
|
|
11
|
+
|
|
12
|
+
const p = pattern.trim()
|
|
13
|
+
|
|
14
|
+
switch (p) {
|
|
15
|
+
/** Short numeric local date (no weekday). */
|
|
16
|
+
case 'd':
|
|
17
|
+
return kind === 'datetime'
|
|
18
|
+
? {
|
|
19
|
+
year: 'numeric',
|
|
20
|
+
month: 'numeric',
|
|
21
|
+
day: 'numeric',
|
|
22
|
+
hour: 'numeric',
|
|
23
|
+
minute: 'numeric',
|
|
24
|
+
}
|
|
25
|
+
: { year: 'numeric', month: 'numeric', day: 'numeric' }
|
|
26
|
+
/** Long spelled-out date (+ time if datetime). */
|
|
27
|
+
case 'D':
|
|
28
|
+
return kind === 'datetime'
|
|
29
|
+
? {
|
|
30
|
+
weekday: 'long',
|
|
31
|
+
year: 'numeric',
|
|
32
|
+
month: 'long',
|
|
33
|
+
day: 'numeric',
|
|
34
|
+
hour: 'numeric',
|
|
35
|
+
minute: 'numeric',
|
|
36
|
+
}
|
|
37
|
+
: { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }
|
|
38
|
+
/** ISO-friendly yyyy-mm-dd (with time when datetime). */
|
|
39
|
+
case 'y-m-d':
|
|
40
|
+
return kind === 'datetime'
|
|
41
|
+
? {
|
|
42
|
+
year: 'numeric',
|
|
43
|
+
month: '2-digit',
|
|
44
|
+
day: '2-digit',
|
|
45
|
+
hour: '2-digit',
|
|
46
|
+
minute: '2-digit',
|
|
47
|
+
hour12: false,
|
|
48
|
+
}
|
|
49
|
+
: { year: 'numeric', month: '2-digit', day: '2-digit' }
|
|
50
|
+
case 'medium':
|
|
51
|
+
return { dateStyle: 'medium', timeStyle: kind === 'datetime' ? 'short' : undefined }
|
|
52
|
+
case 'short':
|
|
53
|
+
return { dateStyle: 'short', timeStyle: kind === 'datetime' ? 'short' : undefined }
|
|
54
|
+
case 'long':
|
|
55
|
+
return { dateStyle: 'long', timeStyle: kind === 'datetime' ? 'short' : undefined }
|
|
56
|
+
default:
|
|
57
|
+
return undefined
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
type NumericFormatInput = {
|
|
62
|
+
type: 'number' | 'currency' | 'percent'
|
|
63
|
+
locales?: string | readonly string[]
|
|
64
|
+
currency?: string
|
|
65
|
+
/** When type is percent: treat value as 0–100 instead of Intl’s 0–1 fraction */
|
|
66
|
+
valueIsPercentPoints?: boolean
|
|
67
|
+
options?: Intl.NumberFormatOptions
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* `Intl.NumberFormat` is one of the most expensive constructors in the
|
|
72
|
+
* platform - building one per cell on every scroll makes large grids
|
|
73
|
+
* noticeably stutter. Cache instances by config signature (locale + style
|
|
74
|
+
* + currency + options).
|
|
75
|
+
*/
|
|
76
|
+
const numberFormatterCache = new Map<string, Intl.NumberFormat>()
|
|
77
|
+
function getNumberFormatter(
|
|
78
|
+
locales: string | readonly string[] | undefined,
|
|
79
|
+
options: Intl.NumberFormatOptions,
|
|
80
|
+
): Intl.NumberFormat {
|
|
81
|
+
// Stable key - for normal column configs the options object is reused
|
|
82
|
+
// (declared in module scope), so this stringifies a small static shape.
|
|
83
|
+
const key =
|
|
84
|
+
(Array.isArray(locales) ? locales.join(',') : locales ?? '') +
|
|
85
|
+
'|' +
|
|
86
|
+
(options.style ?? '') +
|
|
87
|
+
'|' +
|
|
88
|
+
(options.currency ?? '') +
|
|
89
|
+
'|' +
|
|
90
|
+
(options.minimumFractionDigits ?? '') +
|
|
91
|
+
'|' +
|
|
92
|
+
(options.maximumFractionDigits ?? '') +
|
|
93
|
+
'|' +
|
|
94
|
+
(options.useGrouping ?? '') +
|
|
95
|
+
'|' +
|
|
96
|
+
(options.currencyDisplay ?? '') +
|
|
97
|
+
'|' +
|
|
98
|
+
(options.notation ?? '')
|
|
99
|
+
let fmt = numberFormatterCache.get(key)
|
|
100
|
+
if (!fmt) {
|
|
101
|
+
fmt = new Intl.NumberFormat(locales as string | string[] | undefined, options)
|
|
102
|
+
numberFormatterCache.set(key, fmt)
|
|
103
|
+
}
|
|
104
|
+
return fmt
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** Cache of `Intl.DateTimeFormat` by `(locale, options)` signature. */
|
|
108
|
+
const dateFormatterCache = new Map<string, Intl.DateTimeFormat>()
|
|
109
|
+
export function getDateFormatter(
|
|
110
|
+
locales: string | readonly string[] | undefined,
|
|
111
|
+
options: Intl.DateTimeFormatOptions,
|
|
112
|
+
): Intl.DateTimeFormat {
|
|
113
|
+
const key =
|
|
114
|
+
(Array.isArray(locales) ? locales.join(',') : locales ?? '') +
|
|
115
|
+
'|' +
|
|
116
|
+
(options.dateStyle ?? '') +
|
|
117
|
+
'|' +
|
|
118
|
+
(options.timeStyle ?? '') +
|
|
119
|
+
'|' +
|
|
120
|
+
(options.year ?? '') +
|
|
121
|
+
'|' +
|
|
122
|
+
(options.month ?? '') +
|
|
123
|
+
'|' +
|
|
124
|
+
(options.day ?? '') +
|
|
125
|
+
'|' +
|
|
126
|
+
(options.hour ?? '') +
|
|
127
|
+
'|' +
|
|
128
|
+
(options.minute ?? '') +
|
|
129
|
+
'|' +
|
|
130
|
+
(options.second ?? '') +
|
|
131
|
+
'|' +
|
|
132
|
+
(options.weekday ?? '') +
|
|
133
|
+
'|' +
|
|
134
|
+
(options.hour12 ?? '')
|
|
135
|
+
let fmt = dateFormatterCache.get(key)
|
|
136
|
+
if (!fmt) {
|
|
137
|
+
fmt = new Intl.DateTimeFormat(locales as string | string[] | undefined, options)
|
|
138
|
+
dateFormatterCache.set(key, fmt)
|
|
139
|
+
}
|
|
140
|
+
return fmt
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/** Format a numeric value for number / currency / percent column formats. */
|
|
144
|
+
export function formatNumericWithConfig(value: unknown, config: NumericFormatInput): string {
|
|
145
|
+
const n = typeof value === 'number' ? value : Number(value)
|
|
146
|
+
if (!Number.isFinite(n)) return String(value ?? '')
|
|
147
|
+
|
|
148
|
+
const locales = config.locales
|
|
149
|
+
|
|
150
|
+
if (config.type === 'currency') {
|
|
151
|
+
return getNumberFormatter(locales, {
|
|
152
|
+
style: 'currency',
|
|
153
|
+
currency: config.currency ?? 'USD',
|
|
154
|
+
...config.options,
|
|
155
|
+
}).format(n)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (config.type === 'percent') {
|
|
159
|
+
const frac = config.valueIsPercentPoints === true ? n / 100 : n
|
|
160
|
+
return getNumberFormatter(locales, {
|
|
161
|
+
style: 'percent',
|
|
162
|
+
minimumFractionDigits: 0,
|
|
163
|
+
maximumFractionDigits: 2,
|
|
164
|
+
...config.options,
|
|
165
|
+
}).format(frac)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return getNumberFormatter(locales, config.options ?? {}).format(n)
|
|
169
|
+
}
|