@svgrid/grid 2.2.33 → 2.4.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/README.md +199 -199
- package/dist/FlexRender.svelte +96 -96
- package/dist/GridFooter.svelte +178 -139
- package/dist/GridMenus.svelte +705 -705
- package/dist/SvAutoComplete.svelte +165 -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 +275 -275
- package/dist/SvContextMenu.svelte +116 -116
- package/dist/SvCountryInput.svelte +160 -160
- package/dist/SvDrawer.svelte +254 -254
- 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.css +2814 -2804
- package/dist/SvGrid.svelte +3490 -3490
- 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 +266 -266
- package/dist/SvGroupCell.svelte +116 -116
- package/dist/SvListBox.svelte +326 -326
- package/dist/SvMaskedInput.svelte +122 -122
- package/dist/SvMenu.svelte +124 -124
- package/dist/SvMenuList.svelte +146 -146
- package/dist/SvMultiSelect.svelte +289 -289
- package/dist/SvNumberInput.svelte +168 -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/SvRichText.svelte +211 -211
- package/dist/SvRowGroupPanel.svelte +170 -170
- package/dist/SvScrollArea.svelte +61 -61
- package/dist/SvSlider.svelte +200 -200
- package/dist/SvSwitchButton.svelte +108 -108
- 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 +208 -208
- package/dist/SvTree.svelte +444 -444
- package/dist/SvTreeSelect.svelte +235 -235
- package/dist/cdn/{GridMenus-B7XhhqdN.js → GridMenus-BpVcKyUr.js} +4 -4
- package/dist/cdn/{GridMenus-BxmIvCJh.js → GridMenus-CeXL5IW4.js} +153 -150
- package/dist/cdn/{SvDateTimePicker-ClqtVIj3.js → SvDateTimePicker-DSUhIta8.js} +165 -165
- package/dist/cdn/{SvDateTimePicker-o94wfSUa.js → SvDateTimePicker-h9kPyszT.js} +572 -555
- package/dist/cdn/{SvGridChart-Cr_90pPD.js → SvGridChart-Bs2GIR2Q.js} +28 -21
- package/dist/cdn/{SvGridChart-BhnFdLd0.js → SvGridChart-CwhFz7GV.js} +2 -2
- package/dist/cdn/{SvGridChartPanel-Cmx9DHAS.js → SvGridChartPanel-1WXuStzM.js} +2 -2
- package/dist/cdn/{SvGridChartPanel-ICbxiUvK.js → SvGridChartPanel-e5_nqNP9.js} +20 -12
- package/dist/cdn/{SvGridChartView-Bx42PMvf.js → SvGridChartView-SmPW10dI.js} +3 -3
- package/dist/cdn/{SvGridChartView-B40DTJSX.js → SvGridChartView-eSPuJE6g.js} +2 -2
- package/dist/cdn/{SvGridDropdown-D0VdjeR8.js → SvGridDropdown-B1ZcLpgs.js} +1 -1
- package/dist/cdn/{SvGridDropdown-CUOdm7YA.js → SvGridDropdown-CtdbHcIS.js} +6 -5
- package/dist/cdn/{chart-T1usDN0o.js → chart-i4XcXyHJ.js} +12 -10
- package/dist/cdn/{disclose-version-DljhZohK.js → disclose-version-Dr7rEVv-.js} +989 -1081
- package/dist/cdn/{export-format-JT5pWVT8.js → export-format-Cv1Dll6k.js} +66 -245
- package/dist/cdn/{src-erjBRYfX.js → src-DbeN1ReZ.js} +9221 -8925
- package/dist/cdn/{src-ktbQVOk-.js → src-DmEQFW5_.js} +9021 -8809
- 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/columns.js +9 -2
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/_svelte_metadata.json +1 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/_metadata.json +178 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/attachments-qzRy9DX4.js +3843 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/attachments-qzRy9DX4.js.map +1 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/constants-RLNOXCpz.js +23 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/constants-RLNOXCpz.js.map +1 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/dev-DPd12uEU.js +1925 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/dev-DPd12uEU.js.map +1 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/events-CDC4DKuQ.js +206 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/events-CDC4DKuQ.js.map +1 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/flags-BD-lYX7s.js +20 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/flags-BD-lYX7s.js.map +1 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/hydration-D3UBU2t8.js +264 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/hydration-D3UBU2t8.js.map +1 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/legacy-client-B0ZUlbSQ.js +698 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/legacy-client-B0ZUlbSQ.js.map +1 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/package.json +3 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte.js +135 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte.js.map +1 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_animate.js +57 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_animate.js.map +1 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_attachments.js +2 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_compiler.js +46691 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_compiler.js.map +1 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_easing.js +239 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_easing.js.map +1 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_events.js +2 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal.js +6 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal.js.map +1 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal_client.js +7 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal_disclose-version.js +6 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal_disclose-version.js.map +1 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal_flags_async.js +7 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal_flags_async.js.map +1 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal_flags_legacy.js +7 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal_flags_legacy.js.map +1 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal_flags_tracing.js +7 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal_flags_tracing.js.map +1 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal_server.js +6 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_legacy.js +85 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_legacy.js.map +1 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_motion.js +561 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_motion.js.map +1 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_reactivity.js +26 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_reactivity.js.map +1 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_reactivity_window.js +124 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_reactivity_window.js.map +1 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_server.js +2 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_store.js +91 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_store.js.map +1 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_transition.js +242 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_transition.js.map +1 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/utils-lObbumRX.js +497 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/utils-lObbumRX.js.map +1 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/utils-mR9mAWyK.js +4929 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/utils-mR9mAWyK.js.map +1 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/validate-CezNmRkM.js +192 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/validate-CezNmRkM.js.map +1 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/version-BHHo0WE-.js +10 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/version-BHHo0WE-.js.map +1 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/warnings-yiExAB06.js +140 -0
- package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/warnings-yiExAB06.js.map +1 -0
- package/package.json +11 -11
- package/src/FlexRender.svelte +96 -96
- package/src/GridFooter.svelte +178 -139
- package/src/GridMenus.svelte +705 -705
- package/src/SvAutoComplete.svelte +165 -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 +275 -275
- package/src/SvContextMenu.svelte +116 -116
- package/src/SvCountryInput.svelte +160 -160
- package/src/SvDrawer.svelte +254 -254
- 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 +3680 -3680
- package/src/SvGrid.css +2814 -2804
- package/src/SvGrid.svelte +3490 -3490
- package/src/SvGrid.types.ts +1708 -1708
- 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 +266 -266
- package/src/SvGroupCell.svelte +116 -116
- package/src/SvListBox.svelte +326 -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 +289 -289
- package/src/SvNumberInput.svelte +168 -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/SvRichText.svelte +211 -211
- package/src/SvRowGroupPanel.svelte +170 -170
- package/src/SvScrollArea.svelte +61 -61
- package/src/SvSlider.svelte +200 -200
- package/src/SvSwitchButton.svelte +108 -108
- 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 +208 -208
- package/src/SvTree.svelte +444 -444
- package/src/SvTreeSelect.svelte +235 -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 +1391 -1391
- package/src/build-api.coverage.test.ts +633 -633
- package/src/build-api.ts +805 -805
- package/src/builtin-editors.grid.test.ts +85 -85
- package/src/cell-formatting.ts +169 -169
- package/src/cell-render.test.ts +513 -513
- package/src/cell-render.ts +496 -496
- package/src/cell-values.ts +118 -118
- package/src/chart-export.ts +201 -201
- package/src/chart-view.svelte.ts +36 -36
- package/src/chart.ts +2295 -2295
- package/src/collaboration.test.ts +104 -104
- package/src/collaboration.ts +167 -167
- package/src/columns.ts +7 -2
- package/src/core.performance.test.ts +30 -30
- package/src/core.ts +1261 -1261
- 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 +319 -319
- package/src/editing.test.ts +949 -949
- package/src/editing.ts +606 -606
- package/src/editor-contract.ts +164 -164
- package/src/editor-registry.grid.test.ts +144 -144
- package/src/editor-registry.ts +122 -122
- 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 +157 -157
- package/src/flex-render.ts +3 -3
- package/src/form-field.ts +127 -127
- package/src/group-display.test.ts +167 -167
- package/src/group-display.ts +200 -200
- package/src/index.ts +724 -724
- 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 +172 -172
- package/src/menus.ts +567 -567
- package/src/merge-objects.ts +48 -48
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/_svelte_metadata.json +1 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/_metadata.json +178 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/attachments-qzRy9DX4.js +3843 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/attachments-qzRy9DX4.js.map +1 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/constants-RLNOXCpz.js +23 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/constants-RLNOXCpz.js.map +1 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/dev-DPd12uEU.js +1925 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/dev-DPd12uEU.js.map +1 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/events-CDC4DKuQ.js +206 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/events-CDC4DKuQ.js.map +1 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/flags-BD-lYX7s.js +20 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/flags-BD-lYX7s.js.map +1 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/hydration-D3UBU2t8.js +264 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/hydration-D3UBU2t8.js.map +1 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/legacy-client-B0ZUlbSQ.js +698 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/legacy-client-B0ZUlbSQ.js.map +1 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/package.json +3 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte.js +135 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte.js.map +1 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_animate.js +57 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_animate.js.map +1 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_attachments.js +2 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_compiler.js +46691 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_compiler.js.map +1 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_easing.js +239 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_easing.js.map +1 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_events.js +2 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal.js +6 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal.js.map +1 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal_client.js +7 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal_disclose-version.js +6 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal_disclose-version.js.map +1 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal_flags_async.js +7 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal_flags_async.js.map +1 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal_flags_legacy.js +7 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal_flags_legacy.js.map +1 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal_flags_tracing.js +7 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal_flags_tracing.js.map +1 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal_server.js +6 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_legacy.js +85 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_legacy.js.map +1 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_motion.js +561 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_motion.js.map +1 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_reactivity.js +26 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_reactivity.js.map +1 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_reactivity_window.js +124 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_reactivity_window.js.map +1 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_server.js +2 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_store.js +91 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_store.js.map +1 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_transition.js +242 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_transition.js.map +1 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/utils-lObbumRX.js +497 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/utils-lObbumRX.js.map +1 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/utils-mR9mAWyK.js +4929 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/utils-mR9mAWyK.js.map +1 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/validate-CezNmRkM.js +192 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/validate-CezNmRkM.js.map +1 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/version-BHHo0WE-.js +10 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/version-BHHo0WE-.js.map +1 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/warnings-yiExAB06.js +140 -0
- package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/warnings-yiExAB06.js.map +1 -0
- package/src/overlays.test.ts +90 -90
- package/src/render-component.ts +28 -28
- package/src/row-resize.ts +210 -210
- 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 +491 -491
- 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 +488 -488
- 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 +526 -526
- package/src/svgrid.async-editor-options.test.ts +271 -271
- package/src/svgrid.auto-row-height.test.ts +204 -204
- package/src/svgrid.behavior.test.ts +705 -705
- package/src/svgrid.charting.test.ts +534 -534
- package/src/svgrid.comments-autocomplete.test.ts +123 -123
- 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 +322 -322
- package/src/svgrid.filter-menu-scroll.test.ts +112 -112
- package/src/svgrid.footer-pagesize.svelte.test.ts +86 -0
- 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.new-features.wrapper.test.ts +251 -251
- package/src/svgrid.tree-data.test.ts +186 -186
- package/src/svgrid.wrapper.test.ts +40 -40
- package/src/svgriddropdown.async-panel.svelte.test.ts +195 -195
- package/src/test-setup.ts +62 -62
- package/src/themes/index.ts +257 -257
- package/src/toast-store.svelte.ts +246 -246
- 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 +296 -296
package/src/createGrid.svelte.ts
CHANGED
|
@@ -1,42 +1,42 @@
|
|
|
1
|
-
import { createSvGridCore } from './core'
|
|
2
|
-
import type {
|
|
3
|
-
RowData,
|
|
4
|
-
SvGrid,
|
|
5
|
-
SvGridOptions,
|
|
6
|
-
TableFeatures,
|
|
7
|
-
} from './core'
|
|
8
|
-
|
|
9
|
-
export type SvelteGrid<
|
|
10
|
-
TFeatures extends TableFeatures,
|
|
11
|
-
TData extends RowData,
|
|
12
|
-
TSelected = {},
|
|
13
|
-
> = SvGrid<TData> & {
|
|
14
|
-
readonly state: Readonly<TSelected>
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export function createSvGrid<
|
|
18
|
-
TFeatures extends TableFeatures,
|
|
19
|
-
TData extends RowData,
|
|
20
|
-
TSelected = {},
|
|
21
|
-
>(
|
|
22
|
-
gridOptions: SvGridOptions<TFeatures, TData>,
|
|
23
|
-
selector: (state: Record<string, any>) => TSelected = () => ({}) as TSelected,
|
|
24
|
-
): SvelteGrid<TFeatures, TData, TSelected> {
|
|
25
|
-
const grid = createSvGridCore(gridOptions) as SvelteGrid<TFeatures, TData, TSelected>
|
|
26
|
-
let selected = $state(selector(grid.store.state))
|
|
27
|
-
grid.store.subscribe(() => {
|
|
28
|
-
selected = selector(grid.store.state)
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
Object.defineProperty(grid, 'state', {
|
|
32
|
-
get() {
|
|
33
|
-
return selected
|
|
34
|
-
},
|
|
35
|
-
configurable: true,
|
|
36
|
-
enumerable: true,
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
return grid
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export const createGrid = createSvGrid
|
|
1
|
+
import { createSvGridCore } from './core'
|
|
2
|
+
import type {
|
|
3
|
+
RowData,
|
|
4
|
+
SvGrid,
|
|
5
|
+
SvGridOptions,
|
|
6
|
+
TableFeatures,
|
|
7
|
+
} from './core'
|
|
8
|
+
|
|
9
|
+
export type SvelteGrid<
|
|
10
|
+
TFeatures extends TableFeatures,
|
|
11
|
+
TData extends RowData,
|
|
12
|
+
TSelected = {},
|
|
13
|
+
> = SvGrid<TData> & {
|
|
14
|
+
readonly state: Readonly<TSelected>
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function createSvGrid<
|
|
18
|
+
TFeatures extends TableFeatures,
|
|
19
|
+
TData extends RowData,
|
|
20
|
+
TSelected = {},
|
|
21
|
+
>(
|
|
22
|
+
gridOptions: SvGridOptions<TFeatures, TData>,
|
|
23
|
+
selector: (state: Record<string, any>) => TSelected = () => ({}) as TSelected,
|
|
24
|
+
): SvelteGrid<TFeatures, TData, TSelected> {
|
|
25
|
+
const grid = createSvGridCore(gridOptions) as SvelteGrid<TFeatures, TData, TSelected>
|
|
26
|
+
let selected = $state(selector(grid.store.state))
|
|
27
|
+
grid.store.subscribe(() => {
|
|
28
|
+
selected = selector(grid.store.state)
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
Object.defineProperty(grid, 'state', {
|
|
32
|
+
get() {
|
|
33
|
+
return selected
|
|
34
|
+
},
|
|
35
|
+
configurable: true,
|
|
36
|
+
enumerable: true,
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
return grid
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export const createGrid = createSvGrid
|
package/src/createGrid.test.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest'
|
|
2
|
-
import { createGridState } from './index'
|
|
3
|
-
|
|
4
|
-
describe('createGrid', () => {
|
|
5
|
-
it('createGridState updates controlled values', () => {
|
|
6
|
-
const [sorting, setSorting] = createGridState([{ id: 'age', desc: false }])
|
|
7
|
-
setSorting((prev) => prev.map((entry) => ({ ...entry, desc: true })))
|
|
8
|
-
expect(sorting()[0]?.desc).toBe(true)
|
|
9
|
-
})
|
|
10
|
-
})
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import { createGridState } from './index'
|
|
3
|
+
|
|
4
|
+
describe('createGrid', () => {
|
|
5
|
+
it('createGridState updates controlled values', () => {
|
|
6
|
+
const [sorting, setSorting] = createGridState([{ id: 'age', desc: false }])
|
|
7
|
+
setSorting((prev) => prev.map((entry) => ({ ...entry, desc: true })))
|
|
8
|
+
expect(sorting()[0]?.desc).toBe(true)
|
|
9
|
+
})
|
|
10
|
+
})
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import type { Updater } from './core'
|
|
2
|
-
|
|
3
|
-
export function createGridState<TState>(
|
|
4
|
-
initialValue: TState,
|
|
5
|
-
): [() => TState, (updater: Updater<TState>) => void] {
|
|
6
|
-
let value = $state(initialValue)
|
|
7
|
-
|
|
8
|
-
return [
|
|
9
|
-
() => value,
|
|
10
|
-
(updater: Updater<TState>) => {
|
|
11
|
-
if (updater instanceof Function) value = updater(value)
|
|
12
|
-
else value = updater
|
|
13
|
-
},
|
|
14
|
-
]
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export const createSvGridState = createGridState
|
|
1
|
+
import type { Updater } from './core'
|
|
2
|
+
|
|
3
|
+
export function createGridState<TState>(
|
|
4
|
+
initialValue: TState,
|
|
5
|
+
): [() => TState, (updater: Updater<TState>) => void] {
|
|
6
|
+
let value = $state(initialValue)
|
|
7
|
+
|
|
8
|
+
return [
|
|
9
|
+
() => value,
|
|
10
|
+
(updater: Updater<TState>) => {
|
|
11
|
+
if (updater instanceof Function) value = updater(value)
|
|
12
|
+
else value = updater
|
|
13
|
+
},
|
|
14
|
+
]
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const createSvGridState = createGridState
|
|
@@ -1,250 +1,250 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* createListbox - the HEADLESS core behind <SvListBox>, in the same spirit as
|
|
3
|
-
* `createSvGrid` for the grid: a runes-based state machine (roving active index,
|
|
4
|
-
* single/multi selection, full keyboard) with **prop-getters** you spread onto
|
|
5
|
-
* YOUR OWN markup. No styles, no DOM assumptions - render it however you like.
|
|
6
|
-
*
|
|
7
|
-
* ```svelte
|
|
8
|
-
* <script lang="ts">
|
|
9
|
-
* import { createListbox } from '@svgrid/grid'
|
|
10
|
-
* let value = $state<string | null>(null)
|
|
11
|
-
* const lb = createListbox({
|
|
12
|
-
* options: () => options, value: () => value,
|
|
13
|
-
* onChange: (v) => (value = v),
|
|
14
|
-
* })
|
|
15
|
-
* </script>
|
|
16
|
-
* <ul {...lb.rootProps()}>
|
|
17
|
-
* {#each options as opt, i}
|
|
18
|
-
* <li {...lb.optionProps(i)}>{opt.label}</li>
|
|
19
|
-
* {/each}
|
|
20
|
-
* </ul>
|
|
21
|
-
* ```
|
|
22
|
-
*
|
|
23
|
-
* The styled <SvListBox> is just one renderer over this core.
|
|
24
|
-
*/
|
|
25
|
-
import { createTypeaheadBuffer, isTypeaheadKey, nextTypeaheadIndex, type ListOption } from './list-option'
|
|
26
|
-
import { editorAria, type EditorAriaState } from './editor-contract'
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* A `Set` is accepted (and echoed back) in multi-select mode so a caller whose
|
|
30
|
-
* selection is already set-shaped - a filter checklist whose default state is
|
|
31
|
-
* "every value selected" - never has to materialize it as an array to drive the
|
|
32
|
-
* listbox, or to spread it back out again on every click.
|
|
33
|
-
*/
|
|
34
|
-
export type ListboxValue =
|
|
35
|
-
| string
|
|
36
|
-
| number
|
|
37
|
-
| ReadonlyArray<string | number>
|
|
38
|
-
| ReadonlySet<string | number>
|
|
39
|
-
| null
|
|
40
|
-
|
|
41
|
-
/** Reactive inputs are passed as getters so the core tracks live prop changes
|
|
42
|
-
* (the same controlled pattern Svelte headless libraries use). */
|
|
43
|
-
export type ListboxConfig = {
|
|
44
|
-
options: () => ReadonlyArray<ListOption>
|
|
45
|
-
value: () => ListboxValue
|
|
46
|
-
onChange?: (value: string | number | Array<string | number> | Set<string | number>) => void
|
|
47
|
-
multiple?: () => boolean
|
|
48
|
-
disabled?: () => boolean
|
|
49
|
-
ariaLabel?: () => string | undefined
|
|
50
|
-
// Editor contract (ARIA + validation) - folded into rootProps().
|
|
51
|
-
id?: () => string | undefined
|
|
52
|
-
invalid?: () => boolean
|
|
53
|
-
required?: () => boolean
|
|
54
|
-
error?: () => string | undefined
|
|
55
|
-
hint?: () => string | undefined
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export type OptionProps = {
|
|
59
|
-
role: 'option'
|
|
60
|
-
id: string
|
|
61
|
-
'aria-selected': boolean
|
|
62
|
-
'aria-disabled': boolean | undefined
|
|
63
|
-
'data-idx': number
|
|
64
|
-
'data-active': '' | undefined
|
|
65
|
-
'data-selected': '' | undefined
|
|
66
|
-
onclick: () => void
|
|
67
|
-
onpointermove: () => void
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export type ListboxRootProps = {
|
|
71
|
-
role: 'listbox'
|
|
72
|
-
id: string | undefined
|
|
73
|
-
'aria-multiselectable': boolean
|
|
74
|
-
'aria-label': string | undefined
|
|
75
|
-
'aria-disabled': boolean
|
|
76
|
-
'aria-activedescendant': string | undefined
|
|
77
|
-
'aria-invalid': 'true' | undefined
|
|
78
|
-
'aria-required': 'true' | undefined
|
|
79
|
-
'aria-describedby': string | undefined
|
|
80
|
-
tabindex: number
|
|
81
|
-
onkeydown: (e: KeyboardEvent) => void
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export type Listbox = {
|
|
85
|
-
/** Currently highlighted option index (roving focus). */
|
|
86
|
-
readonly activeIndex: number
|
|
87
|
-
/** Selected values as an array (single mode -> 0 or 1 entry). */
|
|
88
|
-
readonly selectedValues: Array<string | number>
|
|
89
|
-
isSelected: (value: string | number) => boolean
|
|
90
|
-
isActive: (index: number) => boolean
|
|
91
|
-
setActive: (index: number) => void
|
|
92
|
-
/** Toggle (multi) / set (single) the option at `index`. */
|
|
93
|
-
pick: (index: number) => void
|
|
94
|
-
/** Move the active highlight by `delta`, wrapping over enabled options. */
|
|
95
|
-
move: (delta: number) => void
|
|
96
|
-
first: () => void
|
|
97
|
-
last: () => void
|
|
98
|
-
onKeydown: (e: KeyboardEvent) => void
|
|
99
|
-
/** Spread onto the list container element. */
|
|
100
|
-
rootProps: () => ListboxRootProps
|
|
101
|
-
/** Spread onto the option element at `index`. */
|
|
102
|
-
optionProps: (index: number) => OptionProps
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
let uid = 0
|
|
106
|
-
|
|
107
|
-
/** Normalize a listbox value to an array (pure). */
|
|
108
|
-
export function toSelectedArray(value: ListboxValue, multiple: boolean): Array<string | number> {
|
|
109
|
-
if (value == null) return []
|
|
110
|
-
if (value instanceof Set || Array.isArray(value)) {
|
|
111
|
-
const all = [...(value as Iterable<string | number>)]
|
|
112
|
-
return multiple ? all : all.slice(0, 1)
|
|
113
|
-
}
|
|
114
|
-
return [value as string | number]
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Membership set for a listbox value (pure). A `Set` value is reused as-is, so
|
|
119
|
-
* `isSelected` stays O(1) without copying - the difference between a linear
|
|
120
|
-
* scan per rendered row and a hash hit when the selection runs to thousands of
|
|
121
|
-
* entries.
|
|
122
|
-
*/
|
|
123
|
-
export function toSelectedSet(value: ListboxValue, multiple: boolean): ReadonlySet<string | number> {
|
|
124
|
-
if (value instanceof Set) return value
|
|
125
|
-
return new Set(toSelectedArray(value, multiple))
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
export function createListbox(config: ListboxConfig): Listbox {
|
|
129
|
-
const id = `sv-lb-${uid++}`
|
|
130
|
-
const opts = () => config.options()
|
|
131
|
-
const multiple = () => config.multiple?.() ?? false
|
|
132
|
-
const disabled = () => config.disabled?.() ?? false
|
|
133
|
-
|
|
134
|
-
let active = $state(0)
|
|
135
|
-
// `selectedSet` drives membership; `selected` (the ordered array) stays a
|
|
136
|
-
// lazy derived so a large selection is only flattened when someone reads it.
|
|
137
|
-
const selectedSet = $derived(toSelectedSet(config.value(), multiple()))
|
|
138
|
-
const selected = $derived(toSelectedArray(config.value(), multiple()))
|
|
139
|
-
const enabledIdx = $derived(opts().map((o, i) => (o.disabled ? -1 : i)).filter((i) => i >= 0))
|
|
140
|
-
|
|
141
|
-
// Keep the active index on an enabled option as options change.
|
|
142
|
-
$effect(() => {
|
|
143
|
-
const o = opts()[active]
|
|
144
|
-
if (!o || o.disabled) active = enabledIdx[0] ?? 0
|
|
145
|
-
})
|
|
146
|
-
|
|
147
|
-
const isSelected = (value: string | number) => selectedSet.has(value)
|
|
148
|
-
const isActive = (index: number) => index === active
|
|
149
|
-
const optionId = (index: number) => `${id}-opt-${index}`
|
|
150
|
-
|
|
151
|
-
function setActive(index: number) {
|
|
152
|
-
const o = opts()[index]
|
|
153
|
-
if (o && !o.disabled) active = index
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
function pick(index: number) {
|
|
157
|
-
const o = opts()[index]
|
|
158
|
-
if (!o || o.disabled || disabled()) return
|
|
159
|
-
active = index
|
|
160
|
-
if (multiple()) {
|
|
161
|
-
const set = new Set(selectedSet)
|
|
162
|
-
set.has(o.value) ? set.delete(o.value) : set.add(o.value)
|
|
163
|
-
// Echo back the shape we were handed. Toggling one option must not
|
|
164
|
-
// disturb selected values that aren't currently in `options` (search has
|
|
165
|
-
// narrowed the list, say) - they ride along in the set untouched.
|
|
166
|
-
config.onChange?.(config.value() instanceof Set ? set : [...set])
|
|
167
|
-
} else {
|
|
168
|
-
config.onChange?.(o.value)
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
function move(delta: number) {
|
|
173
|
-
const list = enabledIdx
|
|
174
|
-
if (!list.length) return
|
|
175
|
-
const pos = list.indexOf(active)
|
|
176
|
-
const next = list[(pos + delta + list.length) % list.length]
|
|
177
|
-
if (next != null) active = next
|
|
178
|
-
}
|
|
179
|
-
const first = () => { active = enabledIdx[0] ?? 0 }
|
|
180
|
-
const last = () => { active = enabledIdx.at(-1) ?? 0 }
|
|
181
|
-
|
|
182
|
-
// Type-ahead: typing a label prefix jumps the active highlight to it.
|
|
183
|
-
const typeahead = createTypeaheadBuffer()
|
|
184
|
-
function onTypeahead(char: string) {
|
|
185
|
-
const buffer = typeahead.push(char.toLowerCase())
|
|
186
|
-
const next = nextTypeaheadIndex(opts(), buffer, active)
|
|
187
|
-
if (next >= 0) active = next
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
function onKeydown(e: KeyboardEvent) {
|
|
191
|
-
if (disabled()) return
|
|
192
|
-
switch (e.key) {
|
|
193
|
-
case 'ArrowDown': e.preventDefault(); move(1); break
|
|
194
|
-
case 'ArrowUp': e.preventDefault(); move(-1); break
|
|
195
|
-
case 'Home': e.preventDefault(); first(); break
|
|
196
|
-
case 'End': e.preventDefault(); last(); break
|
|
197
|
-
case ' ':
|
|
198
|
-
case 'Enter': e.preventDefault(); pick(active); break
|
|
199
|
-
default: if (isTypeaheadKey(e)) onTypeahead(e.key)
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
// Editor-contract ARIA state, folded onto the focusable listbox root.
|
|
204
|
-
const ariaState = (): EditorAriaState => ({
|
|
205
|
-
id: config.id?.(),
|
|
206
|
-
invalid: config.invalid?.(),
|
|
207
|
-
required: config.required?.(),
|
|
208
|
-
error: config.error?.(),
|
|
209
|
-
hint: config.hint?.(),
|
|
210
|
-
ariaLabel: config.ariaLabel?.(),
|
|
211
|
-
})
|
|
212
|
-
|
|
213
|
-
return {
|
|
214
|
-
get activeIndex() { return active },
|
|
215
|
-
get selectedValues() { return selected },
|
|
216
|
-
isSelected,
|
|
217
|
-
isActive,
|
|
218
|
-
setActive,
|
|
219
|
-
pick,
|
|
220
|
-
move,
|
|
221
|
-
first,
|
|
222
|
-
last,
|
|
223
|
-
onKeydown,
|
|
224
|
-
rootProps: () => ({
|
|
225
|
-
role: 'listbox' as const,
|
|
226
|
-
id: config.id?.(),
|
|
227
|
-
'aria-multiselectable': multiple(),
|
|
228
|
-
'aria-disabled': disabled(),
|
|
229
|
-
'aria-activedescendant': opts()[active] ? optionId(active) : undefined,
|
|
230
|
-
// aria-label + aria-invalid/required/describedby from the editor contract.
|
|
231
|
-
...editorAria(ariaState()),
|
|
232
|
-
tabindex: disabled() ? -1 : 0,
|
|
233
|
-
onkeydown: onKeydown,
|
|
234
|
-
}),
|
|
235
|
-
optionProps: (index: number) => {
|
|
236
|
-
const o = opts()[index]
|
|
237
|
-
return {
|
|
238
|
-
role: 'option',
|
|
239
|
-
id: optionId(index),
|
|
240
|
-
'aria-selected': o ? isSelected(o.value) : false,
|
|
241
|
-
'aria-disabled': o?.disabled,
|
|
242
|
-
'data-idx': index,
|
|
243
|
-
'data-active': isActive(index) ? '' : undefined,
|
|
244
|
-
'data-selected': o && isSelected(o.value) ? '' : undefined,
|
|
245
|
-
onclick: () => pick(index),
|
|
246
|
-
onpointermove: () => setActive(index),
|
|
247
|
-
}
|
|
248
|
-
},
|
|
249
|
-
}
|
|
250
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* createListbox - the HEADLESS core behind <SvListBox>, in the same spirit as
|
|
3
|
+
* `createSvGrid` for the grid: a runes-based state machine (roving active index,
|
|
4
|
+
* single/multi selection, full keyboard) with **prop-getters** you spread onto
|
|
5
|
+
* YOUR OWN markup. No styles, no DOM assumptions - render it however you like.
|
|
6
|
+
*
|
|
7
|
+
* ```svelte
|
|
8
|
+
* <script lang="ts">
|
|
9
|
+
* import { createListbox } from '@svgrid/grid'
|
|
10
|
+
* let value = $state<string | null>(null)
|
|
11
|
+
* const lb = createListbox({
|
|
12
|
+
* options: () => options, value: () => value,
|
|
13
|
+
* onChange: (v) => (value = v),
|
|
14
|
+
* })
|
|
15
|
+
* </script>
|
|
16
|
+
* <ul {...lb.rootProps()}>
|
|
17
|
+
* {#each options as opt, i}
|
|
18
|
+
* <li {...lb.optionProps(i)}>{opt.label}</li>
|
|
19
|
+
* {/each}
|
|
20
|
+
* </ul>
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* The styled <SvListBox> is just one renderer over this core.
|
|
24
|
+
*/
|
|
25
|
+
import { createTypeaheadBuffer, isTypeaheadKey, nextTypeaheadIndex, type ListOption } from './list-option'
|
|
26
|
+
import { editorAria, type EditorAriaState } from './editor-contract'
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* A `Set` is accepted (and echoed back) in multi-select mode so a caller whose
|
|
30
|
+
* selection is already set-shaped - a filter checklist whose default state is
|
|
31
|
+
* "every value selected" - never has to materialize it as an array to drive the
|
|
32
|
+
* listbox, or to spread it back out again on every click.
|
|
33
|
+
*/
|
|
34
|
+
export type ListboxValue =
|
|
35
|
+
| string
|
|
36
|
+
| number
|
|
37
|
+
| ReadonlyArray<string | number>
|
|
38
|
+
| ReadonlySet<string | number>
|
|
39
|
+
| null
|
|
40
|
+
|
|
41
|
+
/** Reactive inputs are passed as getters so the core tracks live prop changes
|
|
42
|
+
* (the same controlled pattern Svelte headless libraries use). */
|
|
43
|
+
export type ListboxConfig = {
|
|
44
|
+
options: () => ReadonlyArray<ListOption>
|
|
45
|
+
value: () => ListboxValue
|
|
46
|
+
onChange?: (value: string | number | Array<string | number> | Set<string | number>) => void
|
|
47
|
+
multiple?: () => boolean
|
|
48
|
+
disabled?: () => boolean
|
|
49
|
+
ariaLabel?: () => string | undefined
|
|
50
|
+
// Editor contract (ARIA + validation) - folded into rootProps().
|
|
51
|
+
id?: () => string | undefined
|
|
52
|
+
invalid?: () => boolean
|
|
53
|
+
required?: () => boolean
|
|
54
|
+
error?: () => string | undefined
|
|
55
|
+
hint?: () => string | undefined
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export type OptionProps = {
|
|
59
|
+
role: 'option'
|
|
60
|
+
id: string
|
|
61
|
+
'aria-selected': boolean
|
|
62
|
+
'aria-disabled': boolean | undefined
|
|
63
|
+
'data-idx': number
|
|
64
|
+
'data-active': '' | undefined
|
|
65
|
+
'data-selected': '' | undefined
|
|
66
|
+
onclick: () => void
|
|
67
|
+
onpointermove: () => void
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export type ListboxRootProps = {
|
|
71
|
+
role: 'listbox'
|
|
72
|
+
id: string | undefined
|
|
73
|
+
'aria-multiselectable': boolean
|
|
74
|
+
'aria-label': string | undefined
|
|
75
|
+
'aria-disabled': boolean
|
|
76
|
+
'aria-activedescendant': string | undefined
|
|
77
|
+
'aria-invalid': 'true' | undefined
|
|
78
|
+
'aria-required': 'true' | undefined
|
|
79
|
+
'aria-describedby': string | undefined
|
|
80
|
+
tabindex: number
|
|
81
|
+
onkeydown: (e: KeyboardEvent) => void
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export type Listbox = {
|
|
85
|
+
/** Currently highlighted option index (roving focus). */
|
|
86
|
+
readonly activeIndex: number
|
|
87
|
+
/** Selected values as an array (single mode -> 0 or 1 entry). */
|
|
88
|
+
readonly selectedValues: Array<string | number>
|
|
89
|
+
isSelected: (value: string | number) => boolean
|
|
90
|
+
isActive: (index: number) => boolean
|
|
91
|
+
setActive: (index: number) => void
|
|
92
|
+
/** Toggle (multi) / set (single) the option at `index`. */
|
|
93
|
+
pick: (index: number) => void
|
|
94
|
+
/** Move the active highlight by `delta`, wrapping over enabled options. */
|
|
95
|
+
move: (delta: number) => void
|
|
96
|
+
first: () => void
|
|
97
|
+
last: () => void
|
|
98
|
+
onKeydown: (e: KeyboardEvent) => void
|
|
99
|
+
/** Spread onto the list container element. */
|
|
100
|
+
rootProps: () => ListboxRootProps
|
|
101
|
+
/** Spread onto the option element at `index`. */
|
|
102
|
+
optionProps: (index: number) => OptionProps
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
let uid = 0
|
|
106
|
+
|
|
107
|
+
/** Normalize a listbox value to an array (pure). */
|
|
108
|
+
export function toSelectedArray(value: ListboxValue, multiple: boolean): Array<string | number> {
|
|
109
|
+
if (value == null) return []
|
|
110
|
+
if (value instanceof Set || Array.isArray(value)) {
|
|
111
|
+
const all = [...(value as Iterable<string | number>)]
|
|
112
|
+
return multiple ? all : all.slice(0, 1)
|
|
113
|
+
}
|
|
114
|
+
return [value as string | number]
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Membership set for a listbox value (pure). A `Set` value is reused as-is, so
|
|
119
|
+
* `isSelected` stays O(1) without copying - the difference between a linear
|
|
120
|
+
* scan per rendered row and a hash hit when the selection runs to thousands of
|
|
121
|
+
* entries.
|
|
122
|
+
*/
|
|
123
|
+
export function toSelectedSet(value: ListboxValue, multiple: boolean): ReadonlySet<string | number> {
|
|
124
|
+
if (value instanceof Set) return value
|
|
125
|
+
return new Set(toSelectedArray(value, multiple))
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function createListbox(config: ListboxConfig): Listbox {
|
|
129
|
+
const id = `sv-lb-${uid++}`
|
|
130
|
+
const opts = () => config.options()
|
|
131
|
+
const multiple = () => config.multiple?.() ?? false
|
|
132
|
+
const disabled = () => config.disabled?.() ?? false
|
|
133
|
+
|
|
134
|
+
let active = $state(0)
|
|
135
|
+
// `selectedSet` drives membership; `selected` (the ordered array) stays a
|
|
136
|
+
// lazy derived so a large selection is only flattened when someone reads it.
|
|
137
|
+
const selectedSet = $derived(toSelectedSet(config.value(), multiple()))
|
|
138
|
+
const selected = $derived(toSelectedArray(config.value(), multiple()))
|
|
139
|
+
const enabledIdx = $derived(opts().map((o, i) => (o.disabled ? -1 : i)).filter((i) => i >= 0))
|
|
140
|
+
|
|
141
|
+
// Keep the active index on an enabled option as options change.
|
|
142
|
+
$effect(() => {
|
|
143
|
+
const o = opts()[active]
|
|
144
|
+
if (!o || o.disabled) active = enabledIdx[0] ?? 0
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
const isSelected = (value: string | number) => selectedSet.has(value)
|
|
148
|
+
const isActive = (index: number) => index === active
|
|
149
|
+
const optionId = (index: number) => `${id}-opt-${index}`
|
|
150
|
+
|
|
151
|
+
function setActive(index: number) {
|
|
152
|
+
const o = opts()[index]
|
|
153
|
+
if (o && !o.disabled) active = index
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function pick(index: number) {
|
|
157
|
+
const o = opts()[index]
|
|
158
|
+
if (!o || o.disabled || disabled()) return
|
|
159
|
+
active = index
|
|
160
|
+
if (multiple()) {
|
|
161
|
+
const set = new Set(selectedSet)
|
|
162
|
+
set.has(o.value) ? set.delete(o.value) : set.add(o.value)
|
|
163
|
+
// Echo back the shape we were handed. Toggling one option must not
|
|
164
|
+
// disturb selected values that aren't currently in `options` (search has
|
|
165
|
+
// narrowed the list, say) - they ride along in the set untouched.
|
|
166
|
+
config.onChange?.(config.value() instanceof Set ? set : [...set])
|
|
167
|
+
} else {
|
|
168
|
+
config.onChange?.(o.value)
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function move(delta: number) {
|
|
173
|
+
const list = enabledIdx
|
|
174
|
+
if (!list.length) return
|
|
175
|
+
const pos = list.indexOf(active)
|
|
176
|
+
const next = list[(pos + delta + list.length) % list.length]
|
|
177
|
+
if (next != null) active = next
|
|
178
|
+
}
|
|
179
|
+
const first = () => { active = enabledIdx[0] ?? 0 }
|
|
180
|
+
const last = () => { active = enabledIdx.at(-1) ?? 0 }
|
|
181
|
+
|
|
182
|
+
// Type-ahead: typing a label prefix jumps the active highlight to it.
|
|
183
|
+
const typeahead = createTypeaheadBuffer()
|
|
184
|
+
function onTypeahead(char: string) {
|
|
185
|
+
const buffer = typeahead.push(char.toLowerCase())
|
|
186
|
+
const next = nextTypeaheadIndex(opts(), buffer, active)
|
|
187
|
+
if (next >= 0) active = next
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function onKeydown(e: KeyboardEvent) {
|
|
191
|
+
if (disabled()) return
|
|
192
|
+
switch (e.key) {
|
|
193
|
+
case 'ArrowDown': e.preventDefault(); move(1); break
|
|
194
|
+
case 'ArrowUp': e.preventDefault(); move(-1); break
|
|
195
|
+
case 'Home': e.preventDefault(); first(); break
|
|
196
|
+
case 'End': e.preventDefault(); last(); break
|
|
197
|
+
case ' ':
|
|
198
|
+
case 'Enter': e.preventDefault(); pick(active); break
|
|
199
|
+
default: if (isTypeaheadKey(e)) onTypeahead(e.key)
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Editor-contract ARIA state, folded onto the focusable listbox root.
|
|
204
|
+
const ariaState = (): EditorAriaState => ({
|
|
205
|
+
id: config.id?.(),
|
|
206
|
+
invalid: config.invalid?.(),
|
|
207
|
+
required: config.required?.(),
|
|
208
|
+
error: config.error?.(),
|
|
209
|
+
hint: config.hint?.(),
|
|
210
|
+
ariaLabel: config.ariaLabel?.(),
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
return {
|
|
214
|
+
get activeIndex() { return active },
|
|
215
|
+
get selectedValues() { return selected },
|
|
216
|
+
isSelected,
|
|
217
|
+
isActive,
|
|
218
|
+
setActive,
|
|
219
|
+
pick,
|
|
220
|
+
move,
|
|
221
|
+
first,
|
|
222
|
+
last,
|
|
223
|
+
onKeydown,
|
|
224
|
+
rootProps: () => ({
|
|
225
|
+
role: 'listbox' as const,
|
|
226
|
+
id: config.id?.(),
|
|
227
|
+
'aria-multiselectable': multiple(),
|
|
228
|
+
'aria-disabled': disabled(),
|
|
229
|
+
'aria-activedescendant': opts()[active] ? optionId(active) : undefined,
|
|
230
|
+
// aria-label + aria-invalid/required/describedby from the editor contract.
|
|
231
|
+
...editorAria(ariaState()),
|
|
232
|
+
tabindex: disabled() ? -1 : 0,
|
|
233
|
+
onkeydown: onKeydown,
|
|
234
|
+
}),
|
|
235
|
+
optionProps: (index: number) => {
|
|
236
|
+
const o = opts()[index]
|
|
237
|
+
return {
|
|
238
|
+
role: 'option',
|
|
239
|
+
id: optionId(index),
|
|
240
|
+
'aria-selected': o ? isSelected(o.value) : false,
|
|
241
|
+
'aria-disabled': o?.disabled,
|
|
242
|
+
'data-idx': index,
|
|
243
|
+
'data-active': isActive(index) ? '' : undefined,
|
|
244
|
+
'data-selected': o && isSelected(o.value) ? '' : undefined,
|
|
245
|
+
onclick: () => pick(index),
|
|
246
|
+
onpointermove: () => setActive(index),
|
|
247
|
+
}
|
|
248
|
+
},
|
|
249
|
+
}
|
|
250
|
+
}
|