@svgrid/grid 1.2.33 → 2.0.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 +6 -5
- package/dist/FlexRender.svelte +96 -96
- package/dist/GridFooter.svelte +178 -178
- package/dist/SvAccordion.svelte +109 -0
- package/dist/SvAccordion.svelte.d.ts +28 -0
- package/dist/SvAlert.svelte +92 -0
- package/dist/SvAlert.svelte.d.ts +27 -0
- package/dist/SvAutoComplete.svelte +47 -18
- package/dist/SvAutoComplete.svelte.d.ts +2 -5
- package/dist/SvAvatar.svelte +75 -0
- package/dist/SvAvatar.svelte.d.ts +14 -0
- package/dist/SvAvatarGroup.svelte +48 -0
- package/dist/SvAvatarGroup.svelte.d.ts +16 -0
- package/dist/SvBadge.svelte +54 -0
- package/dist/SvBadge.svelte.d.ts +23 -0
- package/dist/SvBreadcrumb.svelte +88 -0
- package/dist/SvBreadcrumb.svelte.d.ts +23 -0
- package/dist/SvButtonGroup.svelte +121 -0
- package/dist/SvButtonGroup.svelte.d.ts +16 -0
- package/dist/SvCalendar.svelte +72 -9
- package/dist/SvCalendar.svelte.d.ts +34 -1
- package/dist/SvCard.svelte +71 -0
- package/dist/SvCard.svelte.d.ts +28 -0
- package/dist/SvCarousel.svelte +134 -0
- package/dist/SvCarousel.svelte.d.ts +28 -0
- package/dist/SvCheckBox.svelte +36 -21
- package/dist/SvCheckBox.svelte.d.ts +2 -5
- package/dist/SvChip.svelte +88 -0
- package/dist/SvChip.svelte.d.ts +31 -0
- package/dist/SvCircularProgress.svelte +109 -0
- package/dist/SvCircularProgress.svelte.d.ts +31 -0
- package/dist/SvColorInput.svelte +54 -27
- package/dist/SvColorInput.svelte.d.ts +10 -6
- package/dist/SvComboBox.svelte +119 -33
- package/dist/SvComboBox.svelte.d.ts +18 -6
- package/dist/SvCommand.svelte +197 -0
- package/dist/SvCommand.svelte.d.ts +26 -0
- package/dist/SvContextMenu.svelte +96 -0
- package/dist/SvContextMenu.svelte.d.ts +25 -0
- package/dist/SvCountryInput.svelte +56 -21
- package/dist/SvCountryInput.svelte.d.ts +9 -5
- package/dist/SvDateRangeInput.svelte +256 -0
- package/dist/SvDateRangeInput.svelte.d.ts +37 -0
- package/dist/SvDateTimePicker.svelte +57 -20
- package/dist/SvDateTimePicker.svelte.d.ts +12 -4
- package/dist/SvDivider.svelte +61 -0
- package/dist/SvDivider.svelte.d.ts +22 -0
- package/dist/SvDrawer.svelte +226 -0
- package/dist/SvDrawer.svelte.d.ts +43 -0
- package/dist/SvDropDownList.svelte +114 -35
- package/dist/SvDropDownList.svelte.d.ts +7 -6
- package/dist/SvDurationInput.svelte +108 -0
- package/dist/SvDurationInput.svelte.d.ts +15 -0
- package/dist/SvEmptyState.svelte +59 -0
- package/dist/SvEmptyState.svelte.d.ts +25 -0
- package/dist/SvField.svelte +85 -0
- package/dist/SvField.svelte.d.ts +30 -0
- package/dist/SvFileUpload.svelte +169 -0
- package/dist/SvFileUpload.svelte.d.ts +24 -0
- package/dist/SvForm.svelte +7 -1
- package/dist/SvForm.svelte.d.ts +3 -0
- package/dist/SvGauge.svelte +7 -1
- package/dist/SvGauge.svelte.d.ts +11 -0
- package/dist/SvGrid.controller.svelte.d.ts +6 -0
- package/dist/SvGrid.controller.svelte.js +64 -9
- package/dist/SvGrid.css +2376 -2343
- package/dist/SvGrid.svelte +2764 -2651
- package/dist/SvGrid.types.d.ts +366 -0
- package/dist/SvGridBoard.svelte +2281 -0
- package/dist/SvGridBoard.svelte.d.ts +31 -0
- package/dist/SvGridDropdown.svelte +666 -665
- package/dist/SvGridSelect.svelte +255 -0
- package/dist/SvGridSelect.svelte.d.ts +32 -0
- package/dist/SvGroupCell.svelte +109 -0
- package/dist/SvGroupCell.svelte.d.ts +41 -0
- package/dist/SvListBox.svelte +123 -36
- package/dist/SvListBox.svelte.d.ts +12 -8
- package/dist/SvMaskedInput.svelte +53 -13
- package/dist/SvMaskedInput.svelte.d.ts +16 -6
- package/dist/SvMenu.svelte +101 -0
- package/dist/SvMenu.svelte.d.ts +26 -0
- package/dist/SvMenuList.svelte +143 -0
- package/dist/SvMenuList.svelte.d.ts +24 -0
- package/dist/SvModal.svelte +220 -0
- package/dist/SvModal.svelte.d.ts +31 -0
- package/dist/SvMultiSelect.svelte +277 -0
- package/dist/SvMultiSelect.svelte.d.ts +31 -0
- package/dist/SvNavPane.svelte +314 -0
- package/dist/SvNavPane.svelte.d.ts +59 -0
- package/dist/SvNumberInput.svelte +23 -9
- package/dist/SvNumberInput.svelte.d.ts +2 -0
- package/dist/SvOtpInput.svelte +157 -0
- package/dist/SvOtpInput.svelte.d.ts +16 -0
- package/dist/SvPagination.svelte +100 -0
- package/dist/SvPagination.svelte.d.ts +16 -0
- package/dist/SvPasswordInput.svelte +42 -12
- package/dist/SvPasswordInput.svelte.d.ts +13 -6
- package/dist/SvPhoneInput.svelte +43 -11
- package/dist/SvPhoneInput.svelte.d.ts +10 -11
- package/dist/SvPopover.svelte +127 -0
- package/dist/SvPopover.svelte.d.ts +35 -0
- package/dist/SvProgress.svelte +116 -0
- package/dist/SvProgress.svelte.d.ts +32 -0
- package/dist/SvRadioGroup.svelte +40 -22
- package/dist/SvRadioGroup.svelte.d.ts +2 -10
- package/dist/SvRating.svelte +51 -30
- package/dist/SvRating.svelte.d.ts +10 -7
- package/dist/SvRichText.svelte +192 -0
- package/dist/SvRichText.svelte.d.ts +16 -0
- package/dist/SvRowGroupPanel.svelte +147 -0
- package/dist/SvRowGroupPanel.svelte.d.ts +17 -0
- package/dist/SvScrollArea.svelte +50 -0
- package/dist/SvScrollArea.svelte.d.ts +22 -0
- package/dist/SvSkeleton.svelte +76 -0
- package/dist/SvSkeleton.svelte.d.ts +25 -0
- package/dist/SvSlider.svelte +41 -9
- package/dist/SvSlider.svelte.d.ts +4 -4
- package/dist/SvSparkline.svelte +77 -0
- package/dist/SvSparkline.svelte.d.ts +28 -0
- package/dist/SvSplitter.svelte +138 -0
- package/dist/SvSplitter.svelte.d.ts +32 -0
- package/dist/SvStat.svelte +86 -0
- package/dist/SvStat.svelte.d.ts +30 -0
- package/dist/SvStepper.svelte +91 -0
- package/dist/SvStepper.svelte.d.ts +24 -0
- package/dist/SvSwitchButton.svelte +39 -24
- package/dist/SvSwitchButton.svelte.d.ts +2 -5
- package/dist/SvTabs.svelte +147 -28
- package/dist/SvTabs.svelte.d.ts +16 -4
- package/dist/SvTagsInput.svelte +59 -22
- package/dist/SvTagsInput.svelte.d.ts +9 -4
- package/dist/SvTextArea.svelte +113 -0
- package/dist/SvTextArea.svelte.d.ts +18 -0
- package/dist/SvTextInput.svelte +115 -0
- package/dist/SvTextInput.svelte.d.ts +20 -0
- package/dist/SvTimePicker.svelte +19 -5
- package/dist/SvTimePicker.svelte.d.ts +12 -0
- package/dist/SvTimeline.svelte +75 -0
- package/dist/SvTimeline.svelte.d.ts +24 -0
- package/dist/SvToaster.svelte +124 -0
- package/dist/SvToaster.svelte.d.ts +10 -0
- package/dist/SvToggleButton.svelte +37 -12
- package/dist/SvToggleButton.svelte.d.ts +2 -4
- package/dist/SvTooltip.svelte +113 -0
- package/dist/SvTooltip.svelte.d.ts +22 -0
- package/dist/SvTour.svelte +151 -0
- package/dist/SvTour.svelte.d.ts +25 -0
- package/dist/SvTree.svelte +286 -44
- package/dist/SvTree.svelte.d.ts +26 -9
- package/dist/SvTreeSelect.svelte +222 -0
- package/dist/SvTreeSelect.svelte.d.ts +24 -0
- package/dist/a11y/dismissable.d.ts +32 -0
- package/dist/a11y/dismissable.js +54 -0
- package/dist/a11y/focus-trap.d.ts +39 -0
- package/dist/a11y/focus-trap.js +142 -0
- package/dist/a11y/live-region.d.ts +8 -0
- package/dist/a11y/live-region.js +60 -0
- package/dist/a11y/scroll-lock.d.ts +4 -0
- package/dist/a11y/scroll-lock.js +41 -0
- package/dist/a11y.d.ts +3 -1
- package/dist/a11y.js +1 -1
- package/dist/avatar.d.ts +10 -0
- package/dist/avatar.js +22 -0
- package/dist/builtin-editors.d.ts +5 -0
- package/dist/builtin-editors.js +55 -0
- package/dist/cdn/svgrid.js +16022 -8235
- package/dist/cdn/svgrid.svelte-external.js +14543 -6765
- package/dist/columns.js +3 -2
- package/dist/core.d.ts +7 -1
- package/dist/countries.d.ts +12 -0
- package/dist/countries.js +24 -0
- package/dist/createAccordion.svelte.d.ts +71 -0
- package/dist/createAccordion.svelte.js +99 -0
- package/dist/createAutocomplete.svelte.d.ts +13 -4
- package/dist/createAutocomplete.svelte.js +11 -1
- package/dist/createButtonGroup.svelte.d.ts +62 -0
- package/dist/createButtonGroup.svelte.js +154 -0
- package/dist/createCalendar.svelte.d.ts +5 -0
- package/dist/createCalendar.svelte.js +2 -0
- package/dist/createCheckbox.svelte.d.ts +9 -17
- package/dist/createCheckbox.svelte.js +28 -1
- package/dist/createColorInput.svelte.d.ts +12 -22
- package/dist/createColorInput.svelte.js +13 -0
- package/dist/createCombobox.svelte.d.ts +16 -5
- package/dist/createCombobox.svelte.js +13 -2
- package/dist/createCountryInput.svelte.d.ts +14 -3
- package/dist/createCountryInput.svelte.js +12 -2
- package/dist/createDateTimePicker.svelte.d.ts +17 -2
- package/dist/createDateTimePicker.svelte.js +12 -2
- package/dist/createDropdownList.svelte.d.ts +14 -5
- package/dist/createDropdownList.svelte.js +50 -1
- package/dist/createFileUpload.svelte.d.ts +68 -0
- package/dist/createFileUpload.svelte.js +122 -0
- package/dist/createListbox.svelte.d.ts +10 -1
- package/dist/createListbox.svelte.js +48 -1
- package/dist/createMaskedInput.svelte.d.ts +11 -2
- package/dist/createMaskedInput.svelte.js +11 -1
- package/dist/createNumberInput.svelte.d.ts +1 -0
- package/dist/createNumberInput.svelte.js +1 -0
- package/dist/createPasswordInput.svelte.d.ts +19 -21
- package/dist/createPasswordInput.svelte.js +16 -4
- package/dist/createPhoneInput.svelte.d.ts +26 -7
- package/dist/createPhoneInput.svelte.js +24 -3
- package/dist/createPopoverSelect.svelte.d.ts +86 -0
- package/dist/createPopoverSelect.svelte.js +196 -0
- package/dist/createRadioGroup.svelte.d.ts +9 -0
- package/dist/createRadioGroup.svelte.js +11 -1
- package/dist/createRating.svelte.d.ts +11 -0
- package/dist/createRating.svelte.js +12 -1
- package/dist/createSlider.svelte.d.ts +2 -0
- package/dist/createSlider.svelte.js +16 -5
- package/dist/createSplitter.svelte.d.ts +67 -0
- package/dist/createSplitter.svelte.js +99 -0
- package/dist/createSwitch.svelte.d.ts +9 -16
- package/dist/createSwitch.svelte.js +28 -1
- package/dist/createTabs.svelte.d.ts +7 -0
- package/dist/createTabs.svelte.js +17 -2
- package/dist/createTagsInput.svelte.d.ts +13 -1
- package/dist/createTagsInput.svelte.js +12 -3
- package/dist/createToggle.svelte.d.ts +9 -0
- package/dist/createToggle.svelte.js +12 -1
- package/dist/createTree.svelte.d.ts +19 -0
- package/dist/createTree.svelte.js +108 -15
- package/dist/debounce.d.ts +11 -0
- package/dist/debounce.js +30 -0
- package/dist/duration.d.ts +15 -0
- package/dist/duration.js +51 -0
- package/dist/editor-contract.d.ts +62 -7
- package/dist/editor-contract.js +45 -5
- package/dist/editor-registry.d.ts +67 -0
- package/dist/editor-registry.js +38 -0
- package/dist/editors/cell-editors.d.ts +1 -1
- package/dist/editors/cell-editors.js +5 -0
- package/dist/fuzzy.d.ts +3 -0
- package/dist/fuzzy.js +41 -0
- package/dist/grid-select.d.ts +9 -0
- package/dist/grid-select.js +8 -0
- package/dist/index.d.ts +79 -6
- package/dist/index.js +78 -4
- package/dist/keyboard-handlers.js +19 -0
- package/dist/list-option.d.ts +36 -0
- package/dist/list-option.js +68 -0
- package/dist/otp.d.ts +16 -0
- package/dist/otp.js +26 -0
- package/dist/paginate.d.ts +20 -0
- package/dist/paginate.js +40 -0
- package/dist/popover.d.ts +15 -1
- package/dist/popover.js +29 -3
- package/dist/recurrence.d.ts +36 -0
- package/dist/recurrence.js +90 -0
- package/dist/server-data-source.d.ts +89 -0
- package/dist/server-data-source.js +4 -0
- package/dist/server-group-model.d.ts +98 -0
- package/dist/server-group-model.js +263 -0
- package/dist/toast-store.svelte.d.ts +41 -0
- package/dist/toast-store.svelte.js +113 -0
- package/dist/tree-select.d.ts +19 -0
- package/dist/tree-select.js +40 -0
- package/dist/ui-app.types.d.ts +80 -0
- package/dist/ui-app.types.js +7 -0
- package/dist/validators.d.ts +43 -0
- package/dist/validators.js +53 -0
- package/dist/virtual.d.ts +35 -0
- package/dist/virtual.js +34 -0
- package/package.json +85 -85
- package/src/FlexRender.svelte +96 -96
- package/src/GridFooter.svelte +178 -178
- package/src/SvAccordion.svelte +109 -0
- package/src/SvAccordion.test.ts +66 -0
- package/src/SvAlert.svelte +92 -0
- package/src/SvAutoComplete.svelte +47 -18
- package/src/SvAvatar.svelte +75 -0
- package/src/SvAvatarGroup.svelte +48 -0
- package/src/SvBadge.svelte +54 -0
- package/src/SvBreadcrumb.svelte +88 -0
- package/src/SvButtonGroup.svelte +121 -0
- package/src/SvButtonGroup.test.ts +72 -0
- package/src/SvCalendar.svelte +72 -9
- package/src/SvCard.svelte +71 -0
- package/src/SvCarousel.svelte +134 -0
- package/src/SvCheckBox.svelte +36 -21
- package/src/SvChip.svelte +88 -0
- package/src/SvCircularProgress.svelte +109 -0
- package/src/SvColorInput.svelte +54 -27
- package/src/SvComboBox.svelte +119 -33
- package/src/SvCommand.svelte +197 -0
- package/src/SvContextMenu.svelte +96 -0
- package/src/SvCountryInput.svelte +56 -21
- package/src/SvDateRangeInput.svelte +256 -0
- package/src/SvDateRangeInput.test.ts +80 -0
- package/src/SvDateTimePicker.svelte +57 -20
- package/src/SvDivider.svelte +61 -0
- package/src/SvDrawer.svelte +226 -0
- package/src/SvDrawer.test.ts +125 -0
- package/src/SvDropDownList.svelte +114 -35
- package/src/SvDurationInput.svelte +108 -0
- package/src/SvEmptyState.svelte +59 -0
- package/src/SvField.svelte +85 -0
- package/src/SvFileUpload.svelte +169 -0
- package/src/SvFileUpload.test.ts +59 -0
- package/src/SvForm.svelte +7 -1
- package/src/SvGauge.svelte +7 -1
- package/src/SvGrid.controller.svelte.ts +2553 -2494
- package/src/SvGrid.css +2376 -2343
- package/src/SvGrid.svelte +2764 -2651
- package/src/SvGrid.types.ts +944 -570
- package/src/SvGridBoard.svelte +2281 -0
- package/src/SvGridDropdown.svelte +666 -665
- package/src/SvGridSelect.svelte +255 -0
- package/src/SvGridSelect.test.ts +100 -0
- package/src/SvGroupCell.svelte +109 -0
- package/src/SvListBox.svelte +123 -36
- package/src/SvMaskedInput.svelte +53 -13
- package/src/SvMenu.svelte +101 -0
- package/src/SvMenu.test.ts +73 -0
- package/src/SvMenuList.svelte +143 -0
- package/src/SvModal.svelte +220 -0
- package/src/SvMultiSelect.svelte +277 -0
- package/src/SvMultiSelect.test.ts +167 -0
- package/src/SvNavPane.svelte +314 -0
- package/src/SvNavPane.test.ts +70 -0
- package/src/SvNumberInput.svelte +23 -9
- package/src/SvOtpInput.svelte +157 -0
- package/src/SvPagination.svelte +100 -0
- package/src/SvPasswordInput.svelte +42 -12
- package/src/SvPhoneInput.svelte +43 -11
- package/src/SvPopover.svelte +127 -0
- package/src/SvProgress.svelte +116 -0
- package/src/SvRadioGroup.svelte +40 -22
- package/src/SvRating.svelte +51 -30
- package/src/SvRichText.svelte +192 -0
- package/src/SvRowGroupPanel.svelte +147 -0
- package/src/SvScrollArea.svelte +50 -0
- package/src/SvSkeleton.svelte +76 -0
- package/src/SvSlider.svelte +41 -9
- package/src/SvSparkline.svelte +77 -0
- package/src/SvSplitter.svelte +138 -0
- package/src/SvSplitter.test.ts +55 -0
- package/src/SvStat.svelte +86 -0
- package/src/SvStepper.svelte +91 -0
- package/src/SvSwitchButton.svelte +39 -24
- package/src/SvTabs.svelte +147 -28
- package/src/SvTagsInput.svelte +59 -22
- package/src/SvTextArea.svelte +113 -0
- package/src/SvTextInput.svelte +115 -0
- package/src/SvTimePicker.svelte +19 -5
- package/src/SvTimeline.svelte +75 -0
- package/src/SvToaster.svelte +124 -0
- package/src/SvToaster.test.ts +63 -0
- package/src/SvToggleButton.svelte +37 -12
- package/src/SvTooltip.svelte +113 -0
- package/src/SvTour.svelte +151 -0
- package/src/SvTree.svelte +286 -44
- package/src/SvTreeSelect.svelte +222 -0
- package/src/SvTreeSelect.test.ts +87 -0
- package/src/a11y/dismissable.test.ts +95 -0
- package/src/a11y/dismissable.ts +94 -0
- package/src/a11y/focus-trap.test.ts +110 -0
- package/src/a11y/focus-trap.ts +134 -0
- package/src/a11y/live-region.test.ts +40 -0
- package/src/a11y/live-region.ts +65 -0
- package/src/a11y/scroll-lock.test.ts +38 -0
- package/src/a11y/scroll-lock.ts +41 -0
- package/src/a11y.contract.test.ts +49 -49
- package/src/a11y.test.ts +59 -59
- package/src/a11y.ts +61 -59
- package/src/avatar.test.ts +32 -0
- package/src/avatar.ts +21 -0
- package/src/board.test.ts +927 -0
- package/src/build-api.ts +798 -798
- package/src/builtin-editors.grid.test.ts +85 -0
- package/src/builtin-editors.test.ts +58 -0
- package/src/builtin-editors.ts +56 -0
- package/src/cell-formatting.ts +169 -169
- package/src/cell-render.ts +469 -469
- package/src/collaboration.test.ts +104 -104
- package/src/collaboration.ts +167 -167
- package/src/columns.ts +3 -2
- package/src/core.performance.test.ts +30 -30
- package/src/core.ts +1111 -1101
- package/src/countries.ts +25 -0
- package/src/createAccordion.svelte.ts +126 -0
- package/src/createAutocomplete.svelte.ts +18 -1
- package/src/createButtonGroup.svelte.ts +166 -0
- package/src/createCalendar.svelte.ts +6 -0
- package/src/createCheckbox.svelte.ts +23 -1
- package/src/createColorInput.svelte.ts +20 -0
- package/src/createCombobox.svelte.ts +22 -2
- package/src/createCountryInput.svelte.ts +21 -2
- package/src/createDateTimePicker.svelte.ts +23 -2
- package/src/createDropdownList.svelte.ts +31 -2
- package/src/createFileUpload.svelte.ts +144 -0
- 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 +35 -3
- package/src/createMaskedInput.svelte.ts +18 -1
- package/src/createNumberInput.svelte.ts +2 -0
- package/src/createPasswordInput.svelte.ts +31 -5
- package/src/createPhoneInput.svelte.ts +38 -4
- package/src/createPopoverSelect.svelte.ts +208 -0
- package/src/createRadioGroup.svelte.ts +23 -1
- package/src/createRating.svelte.ts +26 -1
- package/src/createSlider.svelte.ts +14 -3
- package/src/createSplitter.svelte.ts +119 -0
- package/src/createSwitch.svelte.ts +26 -3
- package/src/createTabs.svelte.ts +20 -3
- package/src/createTagsInput.svelte.ts +24 -3
- package/src/createToggle.svelte.ts +25 -2
- package/src/createTree.svelte.ts +104 -14
- package/src/debounce.test.ts +50 -0
- package/src/debounce.ts +41 -0
- package/src/duration.test.ts +41 -0
- package/src/duration.ts +51 -0
- package/src/editing.test.ts +859 -859
- package/src/editing.ts +675 -675
- package/src/editor-contract.ts +87 -8
- package/src/editor-registry.grid.test.ts +98 -0
- package/src/editor-registry.test.ts +86 -0
- package/src/editor-registry.ts +106 -0
- package/src/editors/cell-editors.ts +10 -1
- package/src/export-data-api.test.ts +126 -126
- package/src/export-format.test.ts +107 -107
- package/src/export-format.ts +598 -598
- package/src/flex-render.ts +3 -3
- package/src/fuzzy.test.ts +40 -0
- package/src/fuzzy.ts +39 -0
- package/src/grid-select.test.ts +28 -0
- package/src/grid-select.ts +20 -0
- package/src/index.ts +463 -318
- package/src/keyboard-handlers.ts +20 -0
- package/src/keyboard.test.ts +59 -59
- package/src/keyboard.ts +97 -97
- package/src/list-option.ts +74 -0
- package/src/list-power.test.ts +71 -0
- package/src/menus.ts +582 -582
- package/src/merge-objects.ts +48 -48
- package/src/otp.test.ts +28 -0
- package/src/otp.ts +28 -0
- package/src/overlays.test.ts +85 -0
- package/src/paginate.test.ts +41 -0
- package/src/paginate.ts +61 -0
- package/src/phone-valid.test.ts +26 -0
- package/src/popover.ts +31 -3
- package/src/progress.test.ts +55 -0
- package/src/recurrence.test.ts +91 -0
- package/src/recurrence.ts +111 -0
- package/src/render-component.ts +28 -28
- package/src/selection.test.ts +754 -754
- package/src/selection.ts +600 -600
- package/src/server-data-source.test.ts +289 -289
- package/src/server-data-source.ts +413 -311
- package/src/server-group-model.test.ts +294 -0
- package/src/server-group-model.ts +370 -0
- package/src/sparkline.test.ts +68 -68
- package/src/sparkline.ts +169 -169
- package/src/spreadsheet.test.ts +489 -489
- package/src/spreadsheet.ts +304 -304
- package/src/static-functions.ts +11 -11
- package/src/subscribe.ts +38 -38
- package/src/svgrid-wrapper.types.ts +439 -439
- package/src/svgrid.behavior.test.ts +706 -706
- package/src/svgrid.features.test.ts +157 -157
- package/src/svgrid.new-features.wrapper.test.ts +251 -251
- package/src/svgrid.responsive.test.ts +72 -0
- package/src/svgrid.wrapper.test.ts +40 -40
- package/src/toast-store.svelte.ts +148 -0
- package/src/toast-store.test.ts +86 -0
- package/src/tree-edit.test.ts +49 -0
- package/src/tree-filter.test.ts +56 -0
- package/src/tree-select.test.ts +48 -0
- package/src/tree-select.ts +62 -0
- package/src/ui-app.test.ts +130 -0
- package/src/ui-app.types.ts +88 -0
- package/src/ui-display.test.ts +79 -0
- package/src/ui-inputs.test.ts +1 -1
- package/src/ui-status.test.ts +141 -0
- package/src/ui-tier1.test.ts +142 -0
- package/src/ui-tier2.test.ts +124 -0
- package/src/ui-tier3.test.ts +139 -0
- package/src/validators.test.ts +58 -0
- package/src/validators.ts +105 -0
- package/src/virtual.test.ts +72 -0
- package/src/virtual.ts +67 -0
- 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
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
*/
|
|
18
18
|
import { formatDate, parseDate } from './datetime/date-format'
|
|
19
19
|
import { toDate, clampDate, withTime, startOfDay, type DateLike } from './datetime/date-core'
|
|
20
|
+
import { editorAria, type EditorAriaState } from './editor-contract'
|
|
20
21
|
|
|
21
22
|
export type DateTimeValue = Date | string | number | null
|
|
22
23
|
export type DropDownDisplayMode = 'both' | 'calendar' | 'time'
|
|
@@ -40,6 +41,17 @@ export type DateTimePickerConfig = {
|
|
|
40
41
|
stepMinutes?: () => number
|
|
41
42
|
disabled?: () => boolean
|
|
42
43
|
readonly?: () => boolean
|
|
44
|
+
/** Accessible label for the open-picker toggle (localizable). */
|
|
45
|
+
toggleLabel?: () => string | undefined
|
|
46
|
+
/** Accessible label for the clear button (localizable). */
|
|
47
|
+
clearLabel?: () => string | undefined
|
|
48
|
+
// Editor contract (ARIA + validation) - folded into inputProps().
|
|
49
|
+
id?: () => string | undefined
|
|
50
|
+
invalid?: () => boolean
|
|
51
|
+
required?: () => boolean
|
|
52
|
+
error?: () => string | undefined
|
|
53
|
+
hint?: () => string | undefined
|
|
54
|
+
ariaLabel?: () => string | undefined
|
|
43
55
|
}
|
|
44
56
|
|
|
45
57
|
const defaultLocale = () => (typeof navigator !== 'undefined' ? navigator.language : 'en-US')
|
|
@@ -164,9 +176,18 @@ export function createDateTimePicker(config: DateTimePickerConfig) {
|
|
|
164
176
|
* alongside `bind:value={dtp.text}`. */
|
|
165
177
|
inputProps() {
|
|
166
178
|
return {
|
|
179
|
+
id: config.id?.(),
|
|
167
180
|
type: 'text' as const,
|
|
168
181
|
disabled: isDisabled(),
|
|
169
182
|
readonly: isReadonly(),
|
|
183
|
+
...editorAria({
|
|
184
|
+
id: config.id?.(),
|
|
185
|
+
invalid: config.invalid?.(),
|
|
186
|
+
required: config.required?.(),
|
|
187
|
+
error: config.error?.(),
|
|
188
|
+
hint: config.hint?.(),
|
|
189
|
+
ariaLabel: config.ariaLabel?.(),
|
|
190
|
+
} satisfies EditorAriaState),
|
|
170
191
|
onblur: commitFromText,
|
|
171
192
|
onkeydown: onInputKeydown,
|
|
172
193
|
}
|
|
@@ -175,7 +196,7 @@ export function createDateTimePicker(config: DateTimePickerConfig) {
|
|
|
175
196
|
toggleProps() {
|
|
176
197
|
return {
|
|
177
198
|
type: 'button' as const,
|
|
178
|
-
'aria-label': 'Open picker',
|
|
199
|
+
'aria-label': config.toggleLabel?.() ?? 'Open picker',
|
|
179
200
|
'aria-haspopup': 'dialog' as const,
|
|
180
201
|
'aria-expanded': open,
|
|
181
202
|
disabled: !isInteractive,
|
|
@@ -187,7 +208,7 @@ export function createDateTimePicker(config: DateTimePickerConfig) {
|
|
|
187
208
|
clearProps() {
|
|
188
209
|
return {
|
|
189
210
|
type: 'button' as const,
|
|
190
|
-
'aria-label': 'Clear',
|
|
211
|
+
'aria-label': config.clearLabel?.() ?? 'Clear',
|
|
191
212
|
onclick: () => commit(null),
|
|
192
213
|
}
|
|
193
214
|
},
|
|
@@ -19,7 +19,8 @@
|
|
|
19
19
|
* {/if}
|
|
20
20
|
* ```
|
|
21
21
|
*/
|
|
22
|
-
import type
|
|
22
|
+
import { createTypeaheadBuffer, isTypeaheadKey, nextTypeaheadIndex, type ListOption } from './list-option'
|
|
23
|
+
import { editorAria, type EditorAriaState } from './editor-contract'
|
|
23
24
|
|
|
24
25
|
export type DropdownValue = string | number | null
|
|
25
26
|
|
|
@@ -32,12 +33,27 @@ export type DropdownListConfig = {
|
|
|
32
33
|
ariaLabel?: () => string | undefined
|
|
33
34
|
/** DOM focus hook provided by the renderer; the core never touches the DOM. */
|
|
34
35
|
focusTrigger?: () => void
|
|
36
|
+
// Editor contract (ARIA + validation) - folded into triggerProps().
|
|
37
|
+
id?: () => string | undefined
|
|
38
|
+
invalid?: () => boolean
|
|
39
|
+
required?: () => boolean
|
|
40
|
+
error?: () => string | undefined
|
|
41
|
+
hint?: () => string | undefined
|
|
35
42
|
}
|
|
36
43
|
|
|
37
44
|
export function createDropdownList(config: DropdownListConfig) {
|
|
38
45
|
const opts = () => config.options()
|
|
39
46
|
const disabled = () => config.disabled?.() ?? false
|
|
40
47
|
|
|
48
|
+
const ariaState = (): EditorAriaState => ({
|
|
49
|
+
id: config.id?.(),
|
|
50
|
+
invalid: config.invalid?.(),
|
|
51
|
+
required: config.required?.(),
|
|
52
|
+
error: config.error?.(),
|
|
53
|
+
hint: config.hint?.(),
|
|
54
|
+
ariaLabel: config.ariaLabel?.(),
|
|
55
|
+
})
|
|
56
|
+
|
|
41
57
|
let open = $state(false)
|
|
42
58
|
let active = $state(-1)
|
|
43
59
|
|
|
@@ -61,8 +77,20 @@ export function createDropdownList(config: DropdownListConfig) {
|
|
|
61
77
|
const pos = enabledIdx.indexOf(active)
|
|
62
78
|
active = enabledIdx[(pos + d + enabledIdx.length) % enabledIdx.length] ?? active
|
|
63
79
|
}
|
|
80
|
+
// Type-ahead: typing a label prefix jumps the active option (and selects it
|
|
81
|
+
// when the list is closed, matching a native <select>).
|
|
82
|
+
const typeahead = createTypeaheadBuffer()
|
|
83
|
+
function onTypeahead(char: string) {
|
|
84
|
+
const buffer = typeahead.push(char.toLowerCase())
|
|
85
|
+
const from = active >= 0 ? active : opts().findIndex((o) => o.value === config.value())
|
|
86
|
+
const next = nextTypeaheadIndex(opts(), buffer, from)
|
|
87
|
+
if (next < 0) return
|
|
88
|
+
active = next
|
|
89
|
+
if (!open) config.onChange?.(opts()[next]!.value)
|
|
90
|
+
}
|
|
64
91
|
function onKeydown(e: KeyboardEvent) {
|
|
65
92
|
if (disabled()) return
|
|
93
|
+
if (isTypeaheadKey(e)) { onTypeahead(e.key); return }
|
|
66
94
|
if (!open && (e.key === 'ArrowDown' || e.key === 'Enter' || e.key === ' ')) { e.preventDefault(); openPanel(); return }
|
|
67
95
|
if (!open) return
|
|
68
96
|
if (e.key === 'ArrowDown') { e.preventDefault(); move(1) }
|
|
@@ -93,10 +121,11 @@ export function createDropdownList(config: DropdownListConfig) {
|
|
|
93
121
|
onKeydown,
|
|
94
122
|
/** Spread onto the trigger <button>. */
|
|
95
123
|
triggerProps: () => ({
|
|
124
|
+
id: config.id?.(),
|
|
96
125
|
type: 'button' as const,
|
|
97
126
|
'aria-haspopup': 'listbox' as const,
|
|
98
127
|
'aria-expanded': open,
|
|
99
|
-
|
|
128
|
+
...editorAria(ariaState()),
|
|
100
129
|
disabled: disabled(),
|
|
101
130
|
onclick: toggle,
|
|
102
131
|
onkeydown: onKeydown,
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* createFileUpload - the HEADLESS core behind <SvFileUpload>: a drag-and-drop
|
|
3
|
+
* file field with accept / size / count validation, exposed as **prop-getters**
|
|
4
|
+
* you spread onto YOUR OWN markup. The DataTransfer / File reading is a DOM
|
|
5
|
+
* concern that stays in the renderer; the core owns the list, validation, drag
|
|
6
|
+
* state and ARIA. Parity: Smart `smart-file-upload`.
|
|
7
|
+
*
|
|
8
|
+
* ```svelte
|
|
9
|
+
* <script lang="ts">
|
|
10
|
+
* import { createFileUpload } from '@svgrid/grid'
|
|
11
|
+
* let files = $state<File[]>([])
|
|
12
|
+
* const fu = createFileUpload({ files: () => files, onChange: (f) => (files = f) })
|
|
13
|
+
* </script>
|
|
14
|
+
* <div {...fu.dropzoneProps()} ondrop={(e) => fu.addFiles([...e.dataTransfer.files])}>...</div>
|
|
15
|
+
* <input {...fu.inputProps()} />
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
import { editorAria, type EditorAriaState } from './editor-contract'
|
|
19
|
+
|
|
20
|
+
export type FileRejectReason = 'type' | 'size' | 'count'
|
|
21
|
+
export type FileRejection = { file: File; reason: FileRejectReason }
|
|
22
|
+
|
|
23
|
+
/** Reactive inputs are passed as getters so the core tracks live prop changes. */
|
|
24
|
+
export type FileUploadConfig = {
|
|
25
|
+
files: () => File[]
|
|
26
|
+
onChange?: (files: File[]) => void
|
|
27
|
+
/** Rejected files (wrong type / too big / over the count cap). */
|
|
28
|
+
onReject?: (rejections: FileRejection[]) => void
|
|
29
|
+
/** Comma list like "image/*,.pdf" (matches MIME or extension). */
|
|
30
|
+
accept?: () => string | undefined
|
|
31
|
+
multiple?: () => boolean
|
|
32
|
+
/** Max size per file in bytes. */
|
|
33
|
+
maxSize?: () => number | undefined
|
|
34
|
+
/** Max number of files (multiple mode). */
|
|
35
|
+
maxFiles?: () => number | undefined
|
|
36
|
+
disabled?: () => boolean
|
|
37
|
+
readonly?: () => boolean
|
|
38
|
+
// Editor contract (ARIA + validation) - folded into dropzoneProps().
|
|
39
|
+
id?: () => string | undefined
|
|
40
|
+
invalid?: () => boolean
|
|
41
|
+
required?: () => boolean
|
|
42
|
+
error?: () => string | undefined
|
|
43
|
+
hint?: () => string | undefined
|
|
44
|
+
ariaLabel?: () => string | undefined
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Whether `file` satisfies an `accept` list (MIME globs or extensions). Pure. */
|
|
48
|
+
export function fileMatchesAccept(file: File, accept?: string): boolean {
|
|
49
|
+
if (!accept || !accept.trim()) return true
|
|
50
|
+
const name = file.name.toLowerCase()
|
|
51
|
+
const type = file.type.toLowerCase()
|
|
52
|
+
return accept.split(',').map((s) => s.trim().toLowerCase()).filter(Boolean).some((tok) => {
|
|
53
|
+
if (tok.startsWith('.')) return name.endsWith(tok)
|
|
54
|
+
if (tok.endsWith('/*')) return type.startsWith(tok.slice(0, -1))
|
|
55
|
+
return type === tok
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function createFileUpload(config: FileUploadConfig) {
|
|
60
|
+
const accept = () => config.accept?.()
|
|
61
|
+
const multiple = () => config.multiple?.() ?? false
|
|
62
|
+
const maxSize = () => config.maxSize?.()
|
|
63
|
+
const maxFiles = () => config.maxFiles?.()
|
|
64
|
+
const disabled = () => config.disabled?.() ?? false
|
|
65
|
+
const readonly = () => config.readonly?.() ?? false
|
|
66
|
+
const isInteractive = $derived(!disabled() && !readonly())
|
|
67
|
+
|
|
68
|
+
let dragging = $state(false)
|
|
69
|
+
|
|
70
|
+
function addFiles(incoming: File[]) {
|
|
71
|
+
if (!isInteractive || !incoming.length) return
|
|
72
|
+
const accepted: File[] = []
|
|
73
|
+
const rejected: FileRejection[] = []
|
|
74
|
+
for (const f of incoming) {
|
|
75
|
+
if (!fileMatchesAccept(f, accept())) { rejected.push({ file: f, reason: 'type' }); continue }
|
|
76
|
+
const cap = maxSize()
|
|
77
|
+
if (cap != null && f.size > cap) { rejected.push({ file: f, reason: 'size' }); continue }
|
|
78
|
+
accepted.push(f)
|
|
79
|
+
}
|
|
80
|
+
let next = multiple() ? [...config.files(), ...accepted] : accepted.slice(-1)
|
|
81
|
+
const limit = maxFiles()
|
|
82
|
+
if (multiple() && limit != null && next.length > limit) {
|
|
83
|
+
for (const f of next.slice(limit)) rejected.push({ file: f, reason: 'count' })
|
|
84
|
+
next = next.slice(0, limit)
|
|
85
|
+
}
|
|
86
|
+
if (rejected.length) config.onReject?.(rejected)
|
|
87
|
+
config.onChange?.(next)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function removeAt(index: number) {
|
|
91
|
+
if (!isInteractive) return
|
|
92
|
+
config.onChange?.(config.files().filter((_, i) => i !== index))
|
|
93
|
+
}
|
|
94
|
+
function clear() { if (isInteractive) config.onChange?.([]) }
|
|
95
|
+
|
|
96
|
+
const setDragging = (v: boolean) => { if (isInteractive) dragging = v }
|
|
97
|
+
|
|
98
|
+
const ariaState = (): EditorAriaState => ({
|
|
99
|
+
id: config.id?.(),
|
|
100
|
+
invalid: config.invalid?.(),
|
|
101
|
+
required: config.required?.(),
|
|
102
|
+
error: config.error?.(),
|
|
103
|
+
hint: config.hint?.(),
|
|
104
|
+
ariaLabel: config.ariaLabel?.(),
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
/** Whether files are being dragged over the dropzone. */
|
|
109
|
+
get dragging() { return dragging },
|
|
110
|
+
/** Whether interaction is allowed. */
|
|
111
|
+
get isInteractive() { return isInteractive },
|
|
112
|
+
/** Selected files (controlled value). */
|
|
113
|
+
get files() { return config.files() },
|
|
114
|
+
addFiles,
|
|
115
|
+
removeAt,
|
|
116
|
+
clear,
|
|
117
|
+
setDragging,
|
|
118
|
+
/** Spread onto the dropzone element (click opens the picker; Enter/Space too).
|
|
119
|
+
* Wire drag events yourself (they carry a DataTransfer): call
|
|
120
|
+
* `setDragging(true/false)` and `addFiles([...e.dataTransfer.files])`. */
|
|
121
|
+
dropzoneProps: () => ({
|
|
122
|
+
role: 'button' as const,
|
|
123
|
+
tabindex: isInteractive ? 0 : -1,
|
|
124
|
+
'data-dragging': dragging ? '' : undefined,
|
|
125
|
+
'aria-disabled': !isInteractive || undefined,
|
|
126
|
+
...editorAria(ariaState()),
|
|
127
|
+
}),
|
|
128
|
+
/** Spread onto the visually-hidden <input type="file">. */
|
|
129
|
+
inputProps: () => ({
|
|
130
|
+
type: 'file' as const,
|
|
131
|
+
accept: accept(),
|
|
132
|
+
multiple: multiple(),
|
|
133
|
+
disabled: !isInteractive,
|
|
134
|
+
tabindex: -1,
|
|
135
|
+
}),
|
|
136
|
+
/** Spread onto a selected file's remove <button> at `index`. */
|
|
137
|
+
removeProps: (index: number) => ({
|
|
138
|
+
type: 'button' as const,
|
|
139
|
+
onclick: () => removeAt(index),
|
|
140
|
+
}),
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export type FileUpload = ReturnType<typeof createFileUpload>
|
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
|
|
@@ -22,7 +22,8 @@
|
|
|
22
22
|
*
|
|
23
23
|
* The styled <SvListBox> is just one renderer over this core.
|
|
24
24
|
*/
|
|
25
|
-
import type
|
|
25
|
+
import { createTypeaheadBuffer, isTypeaheadKey, nextTypeaheadIndex, type ListOption } from './list-option'
|
|
26
|
+
import { editorAria, type EditorAriaState } from './editor-contract'
|
|
26
27
|
|
|
27
28
|
export type ListboxValue = string | number | Array<string | number> | null
|
|
28
29
|
|
|
@@ -35,6 +36,12 @@ export type ListboxConfig = {
|
|
|
35
36
|
multiple?: () => boolean
|
|
36
37
|
disabled?: () => boolean
|
|
37
38
|
ariaLabel?: () => string | undefined
|
|
39
|
+
// Editor contract (ARIA + validation) - folded into rootProps().
|
|
40
|
+
id?: () => string | undefined
|
|
41
|
+
invalid?: () => boolean
|
|
42
|
+
required?: () => boolean
|
|
43
|
+
error?: () => string | undefined
|
|
44
|
+
hint?: () => string | undefined
|
|
38
45
|
}
|
|
39
46
|
|
|
40
47
|
export type OptionProps = {
|
|
@@ -51,10 +58,14 @@ export type OptionProps = {
|
|
|
51
58
|
|
|
52
59
|
export type ListboxRootProps = {
|
|
53
60
|
role: 'listbox'
|
|
61
|
+
id: string | undefined
|
|
54
62
|
'aria-multiselectable': boolean
|
|
55
63
|
'aria-label': string | undefined
|
|
56
64
|
'aria-disabled': boolean
|
|
57
65
|
'aria-activedescendant': string | undefined
|
|
66
|
+
'aria-invalid': 'true' | undefined
|
|
67
|
+
'aria-required': 'true' | undefined
|
|
68
|
+
'aria-describedby': string | undefined
|
|
58
69
|
tabindex: number
|
|
59
70
|
onkeydown: (e: KeyboardEvent) => void
|
|
60
71
|
}
|
|
@@ -136,6 +147,14 @@ export function createListbox(config: ListboxConfig): Listbox {
|
|
|
136
147
|
const first = () => { active = enabledIdx[0] ?? 0 }
|
|
137
148
|
const last = () => { active = enabledIdx.at(-1) ?? 0 }
|
|
138
149
|
|
|
150
|
+
// Type-ahead: typing a label prefix jumps the active highlight to it.
|
|
151
|
+
const typeahead = createTypeaheadBuffer()
|
|
152
|
+
function onTypeahead(char: string) {
|
|
153
|
+
const buffer = typeahead.push(char.toLowerCase())
|
|
154
|
+
const next = nextTypeaheadIndex(opts(), buffer, active)
|
|
155
|
+
if (next >= 0) active = next
|
|
156
|
+
}
|
|
157
|
+
|
|
139
158
|
function onKeydown(e: KeyboardEvent) {
|
|
140
159
|
if (disabled()) return
|
|
141
160
|
switch (e.key) {
|
|
@@ -145,9 +164,20 @@ export function createListbox(config: ListboxConfig): Listbox {
|
|
|
145
164
|
case 'End': e.preventDefault(); last(); break
|
|
146
165
|
case ' ':
|
|
147
166
|
case 'Enter': e.preventDefault(); pick(active); break
|
|
167
|
+
default: if (isTypeaheadKey(e)) onTypeahead(e.key)
|
|
148
168
|
}
|
|
149
169
|
}
|
|
150
170
|
|
|
171
|
+
// Editor-contract ARIA state, folded onto the focusable listbox root.
|
|
172
|
+
const ariaState = (): EditorAriaState => ({
|
|
173
|
+
id: config.id?.(),
|
|
174
|
+
invalid: config.invalid?.(),
|
|
175
|
+
required: config.required?.(),
|
|
176
|
+
error: config.error?.(),
|
|
177
|
+
hint: config.hint?.(),
|
|
178
|
+
ariaLabel: config.ariaLabel?.(),
|
|
179
|
+
})
|
|
180
|
+
|
|
151
181
|
return {
|
|
152
182
|
get activeIndex() { return active },
|
|
153
183
|
get selectedValues() { return selected },
|
|
@@ -160,11 +190,13 @@ export function createListbox(config: ListboxConfig): Listbox {
|
|
|
160
190
|
last,
|
|
161
191
|
onKeydown,
|
|
162
192
|
rootProps: () => ({
|
|
163
|
-
role: 'listbox',
|
|
193
|
+
role: 'listbox' as const,
|
|
194
|
+
id: config.id?.(),
|
|
164
195
|
'aria-multiselectable': multiple(),
|
|
165
|
-
'aria-label': config.ariaLabel?.(),
|
|
166
196
|
'aria-disabled': disabled(),
|
|
167
197
|
'aria-activedescendant': opts()[active] ? optionId(active) : undefined,
|
|
198
|
+
// aria-label + aria-invalid/required/describedby from the editor contract.
|
|
199
|
+
...editorAria(ariaState()),
|
|
168
200
|
tabindex: disabled() ? -1 : 0,
|
|
169
201
|
onkeydown: onKeydown,
|
|
170
202
|
}),
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
* The styled <SvMaskedInput> is just one renderer over this core.
|
|
17
17
|
*/
|
|
18
18
|
import { applyMask, unmask, isMaskComplete } from './datetime/mask'
|
|
19
|
+
import { editorAria, type EditorAriaState } from './editor-contract'
|
|
19
20
|
|
|
20
21
|
/** Reactive inputs are passed as getters so the core tracks live prop changes. */
|
|
21
22
|
export type MaskedInputConfig = {
|
|
@@ -26,6 +27,12 @@ export type MaskedInputConfig = {
|
|
|
26
27
|
placeholder?: () => string | undefined
|
|
27
28
|
disabled?: () => boolean
|
|
28
29
|
readonly?: () => boolean
|
|
30
|
+
// Editor contract (ARIA + validation) - folded into inputProps().
|
|
31
|
+
id?: () => string | undefined
|
|
32
|
+
invalid?: () => boolean
|
|
33
|
+
required?: () => boolean
|
|
34
|
+
error?: () => string | undefined
|
|
35
|
+
hint?: () => string | undefined
|
|
29
36
|
ariaLabel?: () => string | undefined
|
|
30
37
|
}
|
|
31
38
|
|
|
@@ -58,6 +65,15 @@ export function createMaskedInput(config: MaskedInputConfig) {
|
|
|
58
65
|
config.onChange?.(masked, raw, m ? isMaskComplete(masked, m) : true)
|
|
59
66
|
}
|
|
60
67
|
|
|
68
|
+
const ariaState = (): EditorAriaState => ({
|
|
69
|
+
id: config.id?.(),
|
|
70
|
+
invalid: config.invalid?.(),
|
|
71
|
+
required: config.required?.(),
|
|
72
|
+
error: config.error?.(),
|
|
73
|
+
hint: config.hint?.(),
|
|
74
|
+
ariaLabel: config.ariaLabel?.(),
|
|
75
|
+
})
|
|
76
|
+
|
|
61
77
|
return {
|
|
62
78
|
/** The current masked display text. */
|
|
63
79
|
get masked() { return text },
|
|
@@ -67,12 +83,13 @@ export function createMaskedInput(config: MaskedInputConfig) {
|
|
|
67
83
|
get complete() { return mask() ? isMaskComplete(text, mask()) : true },
|
|
68
84
|
/** Spread onto the text input element. */
|
|
69
85
|
inputProps: () => ({
|
|
86
|
+
id: config.id?.(),
|
|
70
87
|
value: text,
|
|
71
88
|
type: 'text' as const,
|
|
72
89
|
placeholder: config.placeholder?.() ?? mask(),
|
|
73
90
|
disabled: disabled(),
|
|
74
91
|
readonly: readonly(),
|
|
75
|
-
|
|
92
|
+
...editorAria(ariaState()),
|
|
76
93
|
oninput: onInput,
|
|
77
94
|
}),
|
|
78
95
|
}
|
|
@@ -39,6 +39,7 @@ export type NumberInputConfig = {
|
|
|
39
39
|
invalid?: () => boolean
|
|
40
40
|
required?: () => boolean
|
|
41
41
|
error?: () => string | undefined
|
|
42
|
+
hint?: () => string | undefined
|
|
42
43
|
ariaLabel?: () => string | undefined
|
|
43
44
|
}
|
|
44
45
|
|
|
@@ -138,6 +139,7 @@ export function createNumberInput(config: NumberInputConfig) {
|
|
|
138
139
|
invalid: config.invalid?.(),
|
|
139
140
|
required: config.required?.(),
|
|
140
141
|
error: config.error?.(),
|
|
142
|
+
hint: config.hint?.(),
|
|
141
143
|
ariaLabel: config.ariaLabel?.(),
|
|
142
144
|
})
|
|
143
145
|
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
*
|
|
16
16
|
* The styled <SvPasswordInput> is just one renderer over this core.
|
|
17
17
|
*/
|
|
18
|
+
import { editorAria, type EditorAriaState } from './editor-contract'
|
|
18
19
|
|
|
19
20
|
export const STRENGTH_LABELS = ['', 'Weak', 'Fair', 'Good', 'Strong']
|
|
20
21
|
|
|
@@ -36,8 +37,21 @@ export type PasswordInputConfig = {
|
|
|
36
37
|
placeholder?: () => string | undefined
|
|
37
38
|
disabled?: () => boolean
|
|
38
39
|
readonly?: () => boolean
|
|
39
|
-
ariaLabel?: () => string | undefined
|
|
40
40
|
autocomplete?: () => string | undefined
|
|
41
|
+
// Localizable strings (fall back to the built-in English defaults).
|
|
42
|
+
/** Accessible label for the reveal toggle when the value is hidden. */
|
|
43
|
+
showLabel?: () => string | undefined
|
|
44
|
+
/** Accessible label for the reveal toggle when the value is shown. */
|
|
45
|
+
hideLabel?: () => string | undefined
|
|
46
|
+
/** Strength labels indexed 0-4 (index 0 unused; 1..4 = weak..strong). */
|
|
47
|
+
strengthLabels?: () => readonly string[]
|
|
48
|
+
// Editor contract (ARIA + validation) - folded into inputProps().
|
|
49
|
+
id?: () => string | undefined
|
|
50
|
+
invalid?: () => boolean
|
|
51
|
+
required?: () => boolean
|
|
52
|
+
error?: () => string | undefined
|
|
53
|
+
hint?: () => string | undefined
|
|
54
|
+
ariaLabel?: () => string | undefined
|
|
41
55
|
}
|
|
42
56
|
|
|
43
57
|
export function createPasswordInput(config: PasswordInputConfig) {
|
|
@@ -53,29 +67,41 @@ export function createPasswordInput(config: PasswordInputConfig) {
|
|
|
53
67
|
}
|
|
54
68
|
const toggle = () => (revealed = !revealed)
|
|
55
69
|
|
|
70
|
+
const ariaState = (): EditorAriaState => ({
|
|
71
|
+
id: config.id?.(),
|
|
72
|
+
invalid: config.invalid?.(),
|
|
73
|
+
required: config.required?.(),
|
|
74
|
+
error: config.error?.(),
|
|
75
|
+
hint: config.hint?.(),
|
|
76
|
+
ariaLabel: config.ariaLabel?.(),
|
|
77
|
+
})
|
|
78
|
+
|
|
56
79
|
return {
|
|
57
80
|
/** Whether the value is currently shown as plain text. */
|
|
58
81
|
get revealed() { return revealed },
|
|
59
82
|
/** Strength score, 0-4. */
|
|
60
83
|
get strength() { return strength },
|
|
61
|
-
/** Human label for the strength score. */
|
|
62
|
-
get strengthLabel() { return STRENGTH_LABELS[strength] },
|
|
84
|
+
/** Human label for the strength score (localizable via `strengthLabels`). */
|
|
85
|
+
get strengthLabel() { return (config.strengthLabels?.() ?? STRENGTH_LABELS)[strength] },
|
|
63
86
|
toggle,
|
|
64
87
|
/** Spread onto the text/password input element. */
|
|
65
88
|
inputProps: () => ({
|
|
89
|
+
id: config.id?.(),
|
|
66
90
|
value: config.value(),
|
|
67
91
|
type: (revealed ? 'text' : 'password') as 'text' | 'password',
|
|
68
92
|
placeholder: config.placeholder?.(),
|
|
69
93
|
disabled: disabled(),
|
|
70
94
|
readonly: readonly(),
|
|
71
95
|
autocomplete: (config.autocomplete?.() ?? 'current-password') as AutoFill,
|
|
72
|
-
|
|
96
|
+
...editorAria(ariaState()),
|
|
73
97
|
oninput: onInput,
|
|
74
98
|
}),
|
|
75
99
|
/** Spread onto the reveal (show/hide) toggle button. */
|
|
76
100
|
toggleProps: () => ({
|
|
77
101
|
type: 'button' as const,
|
|
78
|
-
'aria-label': revealed
|
|
102
|
+
'aria-label': revealed
|
|
103
|
+
? (config.hideLabel?.() ?? 'Hide password')
|
|
104
|
+
: (config.showLabel?.() ?? 'Show password'),
|
|
79
105
|
'aria-pressed': revealed,
|
|
80
106
|
disabled: disabled(),
|
|
81
107
|
tabindex: -1,
|