@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
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Equivalence tests for `normalizeForFilter`'s ASCII fast path.
|
|
3
|
+
*
|
|
4
|
+
* The function NFD-decomposes, strips combining marks, then lowercases. It runs
|
|
5
|
+
* once per cell per filter - 100,000 times for a one-column filter on a 100k
|
|
6
|
+
* grid - and a CPU profile of a browser filter put 15.5% of the whole operation
|
|
7
|
+
* inside it, more than any other single function.
|
|
8
|
+
*
|
|
9
|
+
* For a pure-ASCII string the first two steps are provably no-ops: ASCII is
|
|
10
|
+
* already in NFD, and the combining-marks block (U+0300..U+036F) contains no
|
|
11
|
+
* ASCII. So the fast path returns `lowercase(s)` directly.
|
|
12
|
+
*
|
|
13
|
+
* "Provably" is doing a lot of work in that sentence, so the first test checks
|
|
14
|
+
* it exhaustively over every ASCII code point rather than trusting the argument.
|
|
15
|
+
*/
|
|
16
|
+
import { describe, expect, it } from 'vitest'
|
|
17
|
+
import { normalizeForFilter } from './excel-filters'
|
|
18
|
+
|
|
19
|
+
/** The original implementation, verbatim, as the oracle. */
|
|
20
|
+
const DIACRITIC_RE = /[̀-ͯ]/g
|
|
21
|
+
function reference(s: string, locale?: string | ReadonlyArray<string>): string {
|
|
22
|
+
if (!s) return ''
|
|
23
|
+
const stripped = s.normalize('NFD').replace(DIACRITIC_RE, '')
|
|
24
|
+
return locale
|
|
25
|
+
? stripped.toLocaleLowerCase(locale as string | string[])
|
|
26
|
+
: stripped.toLowerCase()
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
describe('normalizeForFilter - ASCII fast path equivalence', () => {
|
|
30
|
+
it('matches on every single ASCII code point', () => {
|
|
31
|
+
for (let code = 0; code < 128; code++) {
|
|
32
|
+
const ch = String.fromCharCode(code)
|
|
33
|
+
expect(normalizeForFilter(ch), `code point ${code}`).toBe(reference(ch))
|
|
34
|
+
}
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
it('matches on every ASCII code point under a Turkish locale', () => {
|
|
38
|
+
// Turkish is the locale that makes ASCII lowercasing locale-dependent:
|
|
39
|
+
// 'I'.toLocaleLowerCase('tr') is 'ı', not 'i'. The fast path must still
|
|
40
|
+
// route through toLocaleLowerCase rather than assuming ASCII is safe.
|
|
41
|
+
for (let code = 0; code < 128; code++) {
|
|
42
|
+
const ch = String.fromCharCode(code)
|
|
43
|
+
expect(normalizeForFilter(ch, 'tr'), `code point ${code}`).toBe(reference(ch, 'tr'))
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
const CASES: Array<[string, string]> = [
|
|
48
|
+
['empty', ''],
|
|
49
|
+
['plain ascii', 'Hello World'],
|
|
50
|
+
['ascii with digits and punctuation', 'ABC-123_x.y,z!'],
|
|
51
|
+
['precomposed accents', 'café CAFÉ Café'],
|
|
52
|
+
['decomposed accents', 'café'],
|
|
53
|
+
['mixed ascii and accents', 'naive naïve NAÏVE'],
|
|
54
|
+
['german sharp s', 'straße STRASSE'],
|
|
55
|
+
['greek', 'ΣΊΣΥΦΟΣ σίσυφος'],
|
|
56
|
+
['cyrillic', 'Привет МИР'],
|
|
57
|
+
['cjk', '日本語テキスト'],
|
|
58
|
+
['emoji', 'grid 🚀 test'],
|
|
59
|
+
['combining marks alone', '̀́̂'],
|
|
60
|
+
['ascii then combining mark', 'áb'],
|
|
61
|
+
['turkish dotted capital', 'İstanbul ISTANBUL'],
|
|
62
|
+
['ligature', 'file flow'],
|
|
63
|
+
['fullwidth', 'ABC'],
|
|
64
|
+
['nbsp and control chars', 'a b\tc\nd'],
|
|
65
|
+
['long ascii', 'x'.repeat(500)],
|
|
66
|
+
['long with one non-ascii at the end', 'x'.repeat(500) + 'é'],
|
|
67
|
+
]
|
|
68
|
+
|
|
69
|
+
for (const [name, input] of CASES) {
|
|
70
|
+
it(`matches: ${name}`, () => {
|
|
71
|
+
expect(normalizeForFilter(input)).toBe(reference(input))
|
|
72
|
+
})
|
|
73
|
+
it(`matches with locale: ${name}`, () => {
|
|
74
|
+
expect(normalizeForFilter(input, 'tr')).toBe(reference(input, 'tr'))
|
|
75
|
+
expect(normalizeForFilter(input, 'de')).toBe(reference(input, 'de'))
|
|
76
|
+
})
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
it('matches across randomised mixed-script strings', () => {
|
|
80
|
+
let seed = 7
|
|
81
|
+
const rand = () => {
|
|
82
|
+
seed = (seed * 1103515245 + 12345) & 0x7fffffff
|
|
83
|
+
return seed / 0x7fffffff
|
|
84
|
+
}
|
|
85
|
+
const pools = [
|
|
86
|
+
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 -_.',
|
|
87
|
+
'áéíóúàèìòùâêîôûäëïöüñçÁÉÍÓÚÑÇ',
|
|
88
|
+
'̀́̂̃̈',
|
|
89
|
+
'ΑΒΓΔαβγδ',
|
|
90
|
+
'абвгдАБВГД',
|
|
91
|
+
'日本語中文한국어',
|
|
92
|
+
]
|
|
93
|
+
for (let trial = 0; trial < 300; trial++) {
|
|
94
|
+
let s = ''
|
|
95
|
+
const len = 1 + Math.floor(rand() * 20)
|
|
96
|
+
for (let i = 0; i < len; i++) {
|
|
97
|
+
const pool = pools[Math.floor(rand() * pools.length)]!
|
|
98
|
+
s += pool[Math.floor(rand() * pool.length)]
|
|
99
|
+
}
|
|
100
|
+
expect(normalizeForFilter(s), s).toBe(reference(s))
|
|
101
|
+
expect(normalizeForFilter(s, 'tr'), s).toBe(reference(s, 'tr'))
|
|
102
|
+
}
|
|
103
|
+
})
|
|
104
|
+
})
|
package/src/flex-render.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
/// <reference types="svelte" />
|
|
2
|
-
|
|
3
|
-
export { default as FlexRender } from './FlexRender.svelte'
|
|
1
|
+
/// <reference types="svelte" />
|
|
2
|
+
|
|
3
|
+
export { default as FlexRender } from './FlexRender.svelte'
|
package/src/form-field.ts
CHANGED
|
@@ -1,127 +1,127 @@
|
|
|
1
|
-
import type { Validator } from './validators'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Field descriptor for <SvForm> and the headless `createForm` core. Kept in a
|
|
5
|
-
* plain `.ts` module so the core can import the type without pulling in the
|
|
6
|
-
* `.svelte` component (which would create a `.svelte.ts` -> `.svelte` import
|
|
7
|
-
* cycle Vite's dev import-analysis fails to resolve).
|
|
8
|
-
*/
|
|
9
|
-
export type FormFieldType =
|
|
10
|
-
| 'text' | 'email' | 'tel' | 'textarea' | 'number' | 'password'
|
|
11
|
-
| 'select' | 'multiselect' | 'checkbox' | 'switch' | 'date' | 'color' | 'rating'
|
|
12
|
-
| 'radio' | 'slider' | 'tags' | 'phone' | 'country' | 'mask'
|
|
13
|
-
| 'datetime' | 'time' | 'daterange' | 'combobox' | 'file'
|
|
14
|
-
| 'array'
|
|
15
|
-
|
|
16
|
-
export type FormField = {
|
|
17
|
-
name: string
|
|
18
|
-
label: string
|
|
19
|
-
type?: FormFieldType
|
|
20
|
-
required?: boolean
|
|
21
|
-
/** Show the field but block edits (still submitted, unlike hidden fields). */
|
|
22
|
-
readonly?: boolean
|
|
23
|
-
/** Helper text shown under the control (distinct from a validation error). */
|
|
24
|
-
help?: string
|
|
25
|
-
placeholder?: string
|
|
26
|
-
/**
|
|
27
|
-
* Options for select/combobox/radio/multiselect. A function makes them CASCADE:
|
|
28
|
-
* the list is derived from the current form values (e.g. cities for the picked
|
|
29
|
-
* country). Pair with `dependsOn` so the child clears when the parent changes.
|
|
30
|
-
*/
|
|
31
|
-
options?:
|
|
32
|
-
| Array<{ value: string | number; label: string; color?: string }>
|
|
33
|
-
| ((values: Record<string, any>) => Array<{ value: string | number; label: string; color?: string }>)
|
|
34
|
-
/** Field name(s) this one depends on; when a parent changes, this field's value
|
|
35
|
-
* is cleared (cascading selects). */
|
|
36
|
-
dependsOn?: string | string[]
|
|
37
|
-
/** Mask pattern for `type: 'mask'` (`#`=digit, `A`=letter, `*`=alnum). */
|
|
38
|
-
mask?: string
|
|
39
|
-
/** Numeric bounds for `type: 'number'` / `'slider'`. */
|
|
40
|
-
min?: number
|
|
41
|
-
max?: number
|
|
42
|
-
step?: number
|
|
43
|
-
precision?: number
|
|
44
|
-
/** Text affixes for `type: 'number'` (e.g. `$` / `%`). */
|
|
45
|
-
prefix?: string
|
|
46
|
-
suffix?: string
|
|
47
|
-
/** Remote option loader for `type: 'combobox'` (debounced typeahead). The
|
|
48
|
-
* current form `values` are passed so it can depend on other fields. */
|
|
49
|
-
loadOptions?: (query: string, values: Record<string, any>) => Promise<Array<{ value: string | number; label: string }>>
|
|
50
|
-
/** File input hints for `type: 'file'`. */
|
|
51
|
-
accept?: string
|
|
52
|
-
multiple?: boolean
|
|
53
|
-
/**
|
|
54
|
-
* Derive this field's value from the other form values (e.g. a total). A
|
|
55
|
-
* computed field is read-only, recomputes reactively, is not user-validated,
|
|
56
|
-
* and its derived value is included in the submitted payload.
|
|
57
|
-
*/
|
|
58
|
-
computed?: (values: Record<string, any>) => any
|
|
59
|
-
/** Declarative validation rules (see `rules` - email/pattern/min/compare...). */
|
|
60
|
-
rules?: ReadonlyArray<Validator>
|
|
61
|
-
/** Return an error message, or null/undefined when valid. */
|
|
62
|
-
validate?: (value: any, values: Record<string, any>) => string | null | undefined
|
|
63
|
-
/**
|
|
64
|
-
* Async validator (e.g. "is this username taken?"). Runs after the sync checks
|
|
65
|
-
* pass, debounced (`asyncDebounce`, default 300ms) and stale-guarded so only the
|
|
66
|
-
* latest result wins. While it runs, `form.isValidating(name)` is true and the
|
|
67
|
-
* field shows a checking indicator. Submit waits for all async validators.
|
|
68
|
-
*/
|
|
69
|
-
asyncValidate?: (value: any, values: Record<string, any>) => Promise<string | null | undefined>
|
|
70
|
-
/** Debounce (ms) before `asyncValidate` runs on edit. Default 300. */
|
|
71
|
-
asyncDebounce?: number
|
|
72
|
-
/** Span full width in the grid. */
|
|
73
|
-
full?: boolean
|
|
74
|
-
/** Columns to span (generalizes `full`); `2`+ widens the field in a grid. */
|
|
75
|
-
span?: number
|
|
76
|
-
/**
|
|
77
|
-
* Show the field only when this is `true` / returns `true` (default: always).
|
|
78
|
-
* A field derived from other values, e.g. `visible: (v) => v.hasAddress`.
|
|
79
|
-
* Hidden fields are skipped in validation and excluded from the submitted values.
|
|
80
|
-
*/
|
|
81
|
-
visible?: boolean | ((values: Record<string, any>) => boolean)
|
|
82
|
-
/** Disable the field, statically or derived from other values. */
|
|
83
|
-
disabled?: boolean | ((values: Record<string, any>) => boolean)
|
|
84
|
-
/**
|
|
85
|
-
* For `type: 'array'` - the fields of each repeatable item. The value is an
|
|
86
|
-
* array of item objects; each item's fields validate against that item (so
|
|
87
|
-
* cross-field rules within a row work). `required`/`minItems`/`maxItems` gate
|
|
88
|
-
* the array length.
|
|
89
|
-
*/
|
|
90
|
-
itemFields?: ReadonlyArray<FormField>
|
|
91
|
-
/** Label for the "add item" button of an array field. Default "+ Add". */
|
|
92
|
-
addLabel?: string
|
|
93
|
-
/** Min / max item count for an array field. */
|
|
94
|
-
minItems?: number
|
|
95
|
-
maxItems?: number
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* A group of fields rendered as a titled fieldset - and, when `<SvForm stepper>`
|
|
100
|
-
* is set, as one step of a wizard. Use in place of a plain `FormField` inside the
|
|
101
|
-
* `fields` array; the schema may freely mix flat fields and sections.
|
|
102
|
-
*/
|
|
103
|
-
export type FormSection = {
|
|
104
|
-
section: string
|
|
105
|
-
description?: string
|
|
106
|
-
fields: ReadonlyArray<FormField>
|
|
107
|
-
/** Column count for this section's grid (defaults to the form's `columns`). */
|
|
108
|
-
columns?: number
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/** An entry in a form schema: either a single field or a titled section/step. */
|
|
112
|
-
export type FormEntry = FormField | FormSection
|
|
113
|
-
|
|
114
|
-
/** Narrow a schema entry to a section (has a `fields` array). */
|
|
115
|
-
export function isFormSection(e: FormEntry): e is FormSection {
|
|
116
|
-
return Array.isArray((e as FormSection).fields)
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/** Flatten a mixed schema (fields + sections) to the flat list of fields. */
|
|
120
|
-
export function flattenFields(entries: ReadonlyArray<FormEntry>): FormField[] {
|
|
121
|
-
const out: FormField[] = []
|
|
122
|
-
for (const e of entries) {
|
|
123
|
-
if (isFormSection(e)) out.push(...e.fields)
|
|
124
|
-
else out.push(e)
|
|
125
|
-
}
|
|
126
|
-
return out
|
|
127
|
-
}
|
|
1
|
+
import type { Validator } from './validators'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Field descriptor for <SvForm> and the headless `createForm` core. Kept in a
|
|
5
|
+
* plain `.ts` module so the core can import the type without pulling in the
|
|
6
|
+
* `.svelte` component (which would create a `.svelte.ts` -> `.svelte` import
|
|
7
|
+
* cycle Vite's dev import-analysis fails to resolve).
|
|
8
|
+
*/
|
|
9
|
+
export type FormFieldType =
|
|
10
|
+
| 'text' | 'email' | 'tel' | 'textarea' | 'number' | 'password'
|
|
11
|
+
| 'select' | 'multiselect' | 'checkbox' | 'switch' | 'date' | 'color' | 'rating'
|
|
12
|
+
| 'radio' | 'slider' | 'tags' | 'phone' | 'country' | 'mask'
|
|
13
|
+
| 'datetime' | 'time' | 'daterange' | 'combobox' | 'file'
|
|
14
|
+
| 'array'
|
|
15
|
+
|
|
16
|
+
export type FormField = {
|
|
17
|
+
name: string
|
|
18
|
+
label: string
|
|
19
|
+
type?: FormFieldType
|
|
20
|
+
required?: boolean
|
|
21
|
+
/** Show the field but block edits (still submitted, unlike hidden fields). */
|
|
22
|
+
readonly?: boolean
|
|
23
|
+
/** Helper text shown under the control (distinct from a validation error). */
|
|
24
|
+
help?: string
|
|
25
|
+
placeholder?: string
|
|
26
|
+
/**
|
|
27
|
+
* Options for select/combobox/radio/multiselect. A function makes them CASCADE:
|
|
28
|
+
* the list is derived from the current form values (e.g. cities for the picked
|
|
29
|
+
* country). Pair with `dependsOn` so the child clears when the parent changes.
|
|
30
|
+
*/
|
|
31
|
+
options?:
|
|
32
|
+
| Array<{ value: string | number; label: string; color?: string }>
|
|
33
|
+
| ((values: Record<string, any>) => Array<{ value: string | number; label: string; color?: string }>)
|
|
34
|
+
/** Field name(s) this one depends on; when a parent changes, this field's value
|
|
35
|
+
* is cleared (cascading selects). */
|
|
36
|
+
dependsOn?: string | string[]
|
|
37
|
+
/** Mask pattern for `type: 'mask'` (`#`=digit, `A`=letter, `*`=alnum). */
|
|
38
|
+
mask?: string
|
|
39
|
+
/** Numeric bounds for `type: 'number'` / `'slider'`. */
|
|
40
|
+
min?: number
|
|
41
|
+
max?: number
|
|
42
|
+
step?: number
|
|
43
|
+
precision?: number
|
|
44
|
+
/** Text affixes for `type: 'number'` (e.g. `$` / `%`). */
|
|
45
|
+
prefix?: string
|
|
46
|
+
suffix?: string
|
|
47
|
+
/** Remote option loader for `type: 'combobox'` (debounced typeahead). The
|
|
48
|
+
* current form `values` are passed so it can depend on other fields. */
|
|
49
|
+
loadOptions?: (query: string, values: Record<string, any>) => Promise<Array<{ value: string | number; label: string }>>
|
|
50
|
+
/** File input hints for `type: 'file'`. */
|
|
51
|
+
accept?: string
|
|
52
|
+
multiple?: boolean
|
|
53
|
+
/**
|
|
54
|
+
* Derive this field's value from the other form values (e.g. a total). A
|
|
55
|
+
* computed field is read-only, recomputes reactively, is not user-validated,
|
|
56
|
+
* and its derived value is included in the submitted payload.
|
|
57
|
+
*/
|
|
58
|
+
computed?: (values: Record<string, any>) => any
|
|
59
|
+
/** Declarative validation rules (see `rules` - email/pattern/min/compare...). */
|
|
60
|
+
rules?: ReadonlyArray<Validator>
|
|
61
|
+
/** Return an error message, or null/undefined when valid. */
|
|
62
|
+
validate?: (value: any, values: Record<string, any>) => string | null | undefined
|
|
63
|
+
/**
|
|
64
|
+
* Async validator (e.g. "is this username taken?"). Runs after the sync checks
|
|
65
|
+
* pass, debounced (`asyncDebounce`, default 300ms) and stale-guarded so only the
|
|
66
|
+
* latest result wins. While it runs, `form.isValidating(name)` is true and the
|
|
67
|
+
* field shows a checking indicator. Submit waits for all async validators.
|
|
68
|
+
*/
|
|
69
|
+
asyncValidate?: (value: any, values: Record<string, any>) => Promise<string | null | undefined>
|
|
70
|
+
/** Debounce (ms) before `asyncValidate` runs on edit. Default 300. */
|
|
71
|
+
asyncDebounce?: number
|
|
72
|
+
/** Span full width in the grid. */
|
|
73
|
+
full?: boolean
|
|
74
|
+
/** Columns to span (generalizes `full`); `2`+ widens the field in a grid. */
|
|
75
|
+
span?: number
|
|
76
|
+
/**
|
|
77
|
+
* Show the field only when this is `true` / returns `true` (default: always).
|
|
78
|
+
* A field derived from other values, e.g. `visible: (v) => v.hasAddress`.
|
|
79
|
+
* Hidden fields are skipped in validation and excluded from the submitted values.
|
|
80
|
+
*/
|
|
81
|
+
visible?: boolean | ((values: Record<string, any>) => boolean)
|
|
82
|
+
/** Disable the field, statically or derived from other values. */
|
|
83
|
+
disabled?: boolean | ((values: Record<string, any>) => boolean)
|
|
84
|
+
/**
|
|
85
|
+
* For `type: 'array'` - the fields of each repeatable item. The value is an
|
|
86
|
+
* array of item objects; each item's fields validate against that item (so
|
|
87
|
+
* cross-field rules within a row work). `required`/`minItems`/`maxItems` gate
|
|
88
|
+
* the array length.
|
|
89
|
+
*/
|
|
90
|
+
itemFields?: ReadonlyArray<FormField>
|
|
91
|
+
/** Label for the "add item" button of an array field. Default "+ Add". */
|
|
92
|
+
addLabel?: string
|
|
93
|
+
/** Min / max item count for an array field. */
|
|
94
|
+
minItems?: number
|
|
95
|
+
maxItems?: number
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* A group of fields rendered as a titled fieldset - and, when `<SvForm stepper>`
|
|
100
|
+
* is set, as one step of a wizard. Use in place of a plain `FormField` inside the
|
|
101
|
+
* `fields` array; the schema may freely mix flat fields and sections.
|
|
102
|
+
*/
|
|
103
|
+
export type FormSection = {
|
|
104
|
+
section: string
|
|
105
|
+
description?: string
|
|
106
|
+
fields: ReadonlyArray<FormField>
|
|
107
|
+
/** Column count for this section's grid (defaults to the form's `columns`). */
|
|
108
|
+
columns?: number
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** An entry in a form schema: either a single field or a titled section/step. */
|
|
112
|
+
export type FormEntry = FormField | FormSection
|
|
113
|
+
|
|
114
|
+
/** Narrow a schema entry to a section (has a `fields` array). */
|
|
115
|
+
export function isFormSection(e: FormEntry): e is FormSection {
|
|
116
|
+
return Array.isArray((e as FormSection).fields)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** Flatten a mixed schema (fields + sections) to the flat list of fields. */
|
|
120
|
+
export function flattenFields(entries: ReadonlyArray<FormEntry>): FormField[] {
|
|
121
|
+
const out: FormField[] = []
|
|
122
|
+
for (const e of entries) {
|
|
123
|
+
if (isFormSection(e)) out.push(...e.fields)
|
|
124
|
+
else out.push(e)
|
|
125
|
+
}
|
|
126
|
+
return out
|
|
127
|
+
}
|
package/src/grid-messages.ts
CHANGED
|
@@ -78,10 +78,27 @@ export type GridMessages = {
|
|
|
78
78
|
menuRemoveRow: string
|
|
79
79
|
menuRemoveColumn: string
|
|
80
80
|
menuEditComment: string
|
|
81
|
+
// Selection bar
|
|
82
|
+
selectionBarLabel: string
|
|
83
|
+
selectionBarCount: string
|
|
84
|
+
selectionBarClear: string
|
|
85
|
+
selectionBarMore: string
|
|
86
|
+
selectionBarSelectAll: string
|
|
87
|
+
selectionBarEditFields: string
|
|
88
|
+
// Bulk edit dialog
|
|
89
|
+
bulkEditTitle: string
|
|
90
|
+
bulkEditLead: string
|
|
91
|
+
bulkEditMixed: string
|
|
92
|
+
bulkEditApply: string
|
|
93
|
+
bulkEditCancel: string
|
|
94
|
+
bulkEditNoFields: string
|
|
81
95
|
chartRange: string
|
|
82
96
|
// Upsell notes (enterprise views not installed)
|
|
83
97
|
pivotUpsellTitle: string
|
|
84
98
|
pivotUpsellBody: string
|
|
99
|
+
/** Shared licensing line under every Enterprise upsell note. */
|
|
100
|
+
upsellLicense: string
|
|
101
|
+
upsellLicenseLink: string
|
|
85
102
|
}
|
|
86
103
|
|
|
87
104
|
/** English defaults - the literal strings the grid shipped before localization. */
|
|
@@ -124,6 +141,20 @@ export const defaultGridMessages: GridMessages = {
|
|
|
124
141
|
menuRemoveRow: 'Remove row',
|
|
125
142
|
menuRemoveColumn: 'Remove column',
|
|
126
143
|
menuEditComment: 'Edit comment',
|
|
144
|
+
selectionBarLabel: 'Selection actions',
|
|
145
|
+
/** Label beside the count CHIP, which carries the number itself. */
|
|
146
|
+
selectionBarCount: 'selected',
|
|
147
|
+
selectionBarClear: 'Clear selection',
|
|
148
|
+
selectionBarMore: 'More actions',
|
|
149
|
+
selectionBarSelectAll: 'Select all',
|
|
150
|
+
selectionBarEditFields: 'Edit fields',
|
|
151
|
+
bulkEditTitle: 'Edit fields',
|
|
152
|
+
bulkEditLead:
|
|
153
|
+
'Changes apply to all {count} selected items. Fields you leave alone keep their existing values.',
|
|
154
|
+
bulkEditMixed: 'Multiple values',
|
|
155
|
+
bulkEditApply: 'Apply to {count} items',
|
|
156
|
+
bulkEditCancel: 'Cancel',
|
|
157
|
+
bulkEditNoFields: 'No editable fields on this grid.',
|
|
127
158
|
opContains: 'Contains',
|
|
128
159
|
opNotContains: 'Not contains',
|
|
129
160
|
opEquals: 'Equals',
|
|
@@ -143,6 +174,9 @@ export const defaultGridMessages: GridMessages = {
|
|
|
143
174
|
chartRange: 'Chart selected range',
|
|
144
175
|
pivotUpsellTitle: 'Pivot mode',
|
|
145
176
|
pivotUpsellBody: 'Pivot mode is an Enterprise feature. Install @svgrid/enterprise and call enablePivot() to use it.',
|
|
177
|
+
upsellLicense:
|
|
178
|
+
'A license key is required for production use. Without one the feature still works, but the grid renders an unlicensed watermark.',
|
|
179
|
+
upsellLicenseLink: 'View licensing',
|
|
146
180
|
}
|
|
147
181
|
|
|
148
182
|
/**
|