@svgrid/grid 1.2.34 → 2.0.1
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/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 +33 -0
- package/dist/SvGrid.svelte +116 -3
- 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 +2 -1
- 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 +16021 -8234
- package/dist/cdn/svgrid.svelte-external.js +14542 -6764
- 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 +1 -1
- 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 +68 -9
- package/src/SvGrid.css +33 -0
- package/src/SvGrid.svelte +116 -3
- package/src/SvGrid.types.ts +374 -0
- package/src/SvGridBoard.svelte +2281 -0
- package/src/SvGridDropdown.svelte +2 -1
- 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.ts +3 -1
- package/src/avatar.test.ts +32 -0
- package/src/avatar.ts +21 -0
- package/src/board.test.ts +927 -0
- 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/columns.ts +3 -2
- package/src/core.ts +10 -0
- 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/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/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/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 +150 -5
- package/src/keyboard-handlers.ts +20 -0
- package/src/list-option.ts +74 -0
- package/src/list-power.test.ts +71 -0
- 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/server-data-source.ts +102 -0
- package/src/server-group-model.test.ts +294 -0
- package/src/server-group-model.ts +370 -0
- package/src/svgrid.responsive.test.ts +72 -0
- 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
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for the file-upload core's pure accept matching, plus SvFileUpload
|
|
3
|
+
* rendering: the dropzone carries the editor contract, the selected-files list
|
|
4
|
+
* renders, and remove emits the trimmed list.
|
|
5
|
+
*/
|
|
6
|
+
import { describe, expect, it } from 'vitest'
|
|
7
|
+
import { mount, unmount, flushSync } from 'svelte'
|
|
8
|
+
import SvFileUpload from './SvFileUpload.svelte'
|
|
9
|
+
import { fileMatchesAccept } from './createFileUpload.svelte'
|
|
10
|
+
|
|
11
|
+
const mk = (name: string, type = '') => new File(['x'], name, { type })
|
|
12
|
+
|
|
13
|
+
describe('fileMatchesAccept', () => {
|
|
14
|
+
it('matches extensions, MIME globs and exact MIME (and passes when empty)', () => {
|
|
15
|
+
expect(fileMatchesAccept(mk('a.pdf'), '.pdf')).toBe(true)
|
|
16
|
+
expect(fileMatchesAccept(mk('a.png', 'image/png'), 'image/*')).toBe(true)
|
|
17
|
+
expect(fileMatchesAccept(mk('a.png', 'image/png'), 'image/png')).toBe(true)
|
|
18
|
+
expect(fileMatchesAccept(mk('a.txt', 'text/plain'), 'image/*,.pdf')).toBe(false)
|
|
19
|
+
expect(fileMatchesAccept(mk('anything'), undefined)).toBe(true)
|
|
20
|
+
})
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
function mountFu(props: Record<string, unknown>) {
|
|
24
|
+
const target = document.createElement('div')
|
|
25
|
+
document.body.appendChild(target)
|
|
26
|
+
const app = mount(SvFileUpload, { target, props: props as any })
|
|
27
|
+
flushSync()
|
|
28
|
+
return { target, destroy: () => { unmount(app); target.remove() } }
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
describe('SvFileUpload', () => {
|
|
32
|
+
it('renders a dropzone with the editor contract wired', () => {
|
|
33
|
+
const { target, destroy } = mountFu({ files: [], accept: 'image/*', label: 'Avatar', required: true, invalid: true, error: 'Required' })
|
|
34
|
+
try {
|
|
35
|
+
const zone = target.querySelector<HTMLElement>('.sv-file__zone')!
|
|
36
|
+
expect(zone.getAttribute('role')).toBe('button')
|
|
37
|
+
expect(zone.getAttribute('aria-invalid')).toBe('true')
|
|
38
|
+
expect(zone.getAttribute('aria-required')).toBe('true')
|
|
39
|
+
expect(target.querySelector('.sv-field__label')!.textContent).toContain('Avatar')
|
|
40
|
+
expect(target.querySelector('.sv-field__error')!.textContent).toBe('Required')
|
|
41
|
+
const input = target.querySelector<HTMLInputElement>('.sv-file__input')!
|
|
42
|
+
expect(input.accept).toBe('image/*')
|
|
43
|
+
} finally { destroy() }
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
it('lists selected files and removes one on click', () => {
|
|
47
|
+
let got: File[] | undefined
|
|
48
|
+
const files = [mk('a.png', 'image/png'), mk('b.png', 'image/png')]
|
|
49
|
+
const { target, destroy } = mountFu({ files, multiple: true, onChange: (f: File[]) => (got = f) })
|
|
50
|
+
try {
|
|
51
|
+
const items = target.querySelectorAll('.sv-file__item')
|
|
52
|
+
expect(items).toHaveLength(2)
|
|
53
|
+
target.querySelector<HTMLButtonElement>('.sv-file__remove')!.click()
|
|
54
|
+
flushSync()
|
|
55
|
+
expect(got).toHaveLength(1)
|
|
56
|
+
expect(got![0].name).toBe('b.png')
|
|
57
|
+
} finally { destroy() }
|
|
58
|
+
})
|
|
59
|
+
})
|
package/src/SvForm.svelte
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
<script lang="ts" module>
|
|
2
|
+
import type { Validator } from './validators'
|
|
3
|
+
|
|
2
4
|
export type FormFieldType =
|
|
3
5
|
| 'text' | 'email' | 'tel' | 'textarea' | 'number' | 'password'
|
|
4
6
|
| 'select' | 'checkbox' | 'switch' | 'date' | 'color' | 'rating'
|
|
@@ -10,6 +12,8 @@
|
|
|
10
12
|
required?: boolean
|
|
11
13
|
placeholder?: string
|
|
12
14
|
options?: Array<{ value: string | number; label: string }>
|
|
15
|
+
/** Declarative validation rules (see `rules` - email/pattern/min/compare...). */
|
|
16
|
+
rules?: ReadonlyArray<Validator>
|
|
13
17
|
/** Return an error message, or null/undefined when valid. */
|
|
14
18
|
validate?: (value: any, values: Record<string, any>) => string | null | undefined
|
|
15
19
|
/** Span full width in the grid. */
|
|
@@ -32,6 +36,7 @@
|
|
|
32
36
|
import SvColorInput from './SvColorInput.svelte'
|
|
33
37
|
import SvRating from './SvRating.svelte'
|
|
34
38
|
import SvButton from './SvButton.svelte'
|
|
39
|
+
import { runRules } from './validators'
|
|
35
40
|
|
|
36
41
|
type Props = {
|
|
37
42
|
fields: ReadonlyArray<FormField>
|
|
@@ -64,7 +69,8 @@
|
|
|
64
69
|
const v = values[name]
|
|
65
70
|
let err: string | null | undefined = null
|
|
66
71
|
if (field.required && (v == null || v === '' || (Array.isArray(v) && !v.length))) err = `${field.label} is required`
|
|
67
|
-
|
|
72
|
+
if (!err && field.rules) err = runRules(v, field.rules, values)
|
|
73
|
+
if (!err && field.validate) err = field.validate(v, values)
|
|
68
74
|
const next = { ...errors }
|
|
69
75
|
if (err) next[name] = err
|
|
70
76
|
else delete next[name]
|
package/src/SvGauge.svelte
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* The arc/needle geometry + `role="meter"` ARIA live in the headless
|
|
8
8
|
* `createGauge` core; this component is just one styled renderer over it.
|
|
9
9
|
*/
|
|
10
|
+
import { type EditorDir } from './editor-contract'
|
|
10
11
|
import { createGauge } from './createGauge.svelte'
|
|
11
12
|
|
|
12
13
|
type Band = { from: number; to: number; color: string }
|
|
@@ -28,6 +29,8 @@
|
|
|
28
29
|
thickness?: number
|
|
29
30
|
formatValue?: (v: number) => string
|
|
30
31
|
ariaLabel?: string
|
|
32
|
+
/** Text direction for the center label / unit. */
|
|
33
|
+
dir?: EditorDir
|
|
31
34
|
}
|
|
32
35
|
|
|
33
36
|
let {
|
|
@@ -43,8 +46,11 @@
|
|
|
43
46
|
thickness = 14,
|
|
44
47
|
formatValue,
|
|
45
48
|
ariaLabel,
|
|
49
|
+
dir,
|
|
46
50
|
}: Props = $props()
|
|
47
51
|
|
|
52
|
+
const resolvedDir = $derived(dir === 'ltr' || dir === 'rtl' ? dir : undefined)
|
|
53
|
+
|
|
48
54
|
const gauge = createGauge({
|
|
49
55
|
value: () => value,
|
|
50
56
|
min: () => min,
|
|
@@ -63,7 +69,7 @@
|
|
|
63
69
|
const display = $derived(label ?? `${formatValue ? formatValue(clamped) : Math.round(clamped)}${unit}`)
|
|
64
70
|
</script>
|
|
65
71
|
|
|
66
|
-
<div class="sv-gauge" {...gauge.rootProps()}>
|
|
72
|
+
<div class="sv-gauge" dir={resolvedDir} {...gauge.rootProps()}>
|
|
67
73
|
<svg viewBox={`0 0 ${size} ${size}`} width={size} height={size} class="sv-gauge__svg">
|
|
68
74
|
<!-- track -->
|
|
69
75
|
<path d={arcPath(min, max, r)} class="sv-gauge__track" fill="none" stroke-width={thickness} stroke-linecap="round" />
|
|
@@ -441,6 +441,28 @@ export function createSvGridController<
|
|
|
441
441
|
viewportVersion;
|
|
442
442
|
return scrollContainer ? scrollContainer.clientHeight : 0;
|
|
443
443
|
});
|
|
444
|
+
|
|
445
|
+
// --- responsive (narrow-container) mode ---
|
|
446
|
+
const responsiveBreakpoint = $derived(
|
|
447
|
+
props.responsive && typeof props.responsive === "object" && props.responsive.breakpoint != null
|
|
448
|
+
? props.responsive.breakpoint
|
|
449
|
+
: 640,
|
|
450
|
+
);
|
|
451
|
+
// Below the breakpoint: un-pin columns (pan the whole grid), suspend
|
|
452
|
+
// fitColumns, and hide `hideBelow` columns. Guarded on width > 0 so it never
|
|
453
|
+
// triggers before the grid has measured.
|
|
454
|
+
const isNarrowResponsive = $derived(
|
|
455
|
+
!!props.responsive && viewportWidth > 0 && viewportWidth < responsiveBreakpoint,
|
|
456
|
+
);
|
|
457
|
+
const EMPTY_PINNING = { left: [] as string[], right: [] as string[] };
|
|
458
|
+
const effectivePinning = $derived(isNarrowResponsive ? EMPTY_PINNING : columnPinning);
|
|
459
|
+
// A column with `hideBelow: N` is dropped while `responsive` is on and the
|
|
460
|
+
// grid is narrower than N px (reads viewportWidth so it re-runs on resize).
|
|
461
|
+
function isHiddenByResponsive(column: { columnDef?: { hideBelow?: number } }): boolean {
|
|
462
|
+
if (!props.responsive) return false;
|
|
463
|
+
const hb = column.columnDef?.hideBelow;
|
|
464
|
+
return hb != null && viewportWidth > 0 && viewportWidth < hb;
|
|
465
|
+
}
|
|
444
466
|
const scrollMetrics = $derived.by(() => {
|
|
445
467
|
scrollVersion;
|
|
446
468
|
viewportVersion;
|
|
@@ -698,7 +720,12 @@ export function createSvGridController<
|
|
|
698
720
|
const allColumns = $derived.by(() => {
|
|
699
721
|
let raw = grid
|
|
700
722
|
.getAllColumns()
|
|
701
|
-
.filter(
|
|
723
|
+
.filter(
|
|
724
|
+
(column) =>
|
|
725
|
+
!hiddenColumns[column.id] &&
|
|
726
|
+
!hiddenByGroupCollapse[column.id] &&
|
|
727
|
+
!isHiddenByResponsive(column),
|
|
728
|
+
);
|
|
702
729
|
// Apply user reorder (if any). Unknown ids in userColumnOrder are
|
|
703
730
|
// skipped; columns not in userColumnOrder keep their original
|
|
704
731
|
// relative order after the user-ordered ones.
|
|
@@ -715,8 +742,8 @@ export function createSvGridController<
|
|
|
715
742
|
}
|
|
716
743
|
raw = ordered;
|
|
717
744
|
}
|
|
718
|
-
const leftIds =
|
|
719
|
-
const rightIds =
|
|
745
|
+
const leftIds = effectivePinning.left;
|
|
746
|
+
const rightIds = effectivePinning.right;
|
|
720
747
|
if (!leftIds.length && !rightIds.length) return raw;
|
|
721
748
|
const pinned = new Set([...leftIds, ...rightIds]);
|
|
722
749
|
const findById = (id: string) => raw.find((column) => column.id === id);
|
|
@@ -907,14 +934,14 @@ export function createSvGridController<
|
|
|
907
934
|
const selectionWidth = showRowSelectionEffective ? selectionColumnWidth : 0;
|
|
908
935
|
const left: Record<string, number> = {};
|
|
909
936
|
let leftAcc = rowNumberWidth + selectionWidth;
|
|
910
|
-
for (const id of
|
|
937
|
+
for (const id of effectivePinning.left) {
|
|
911
938
|
left[id] = leftAcc;
|
|
912
939
|
leftAcc += getColumnWidth(id);
|
|
913
940
|
}
|
|
914
941
|
const right: Record<string, number> = {};
|
|
915
942
|
let rightAcc = 0;
|
|
916
|
-
for (let i =
|
|
917
|
-
const id =
|
|
943
|
+
for (let i = effectivePinning.right.length - 1; i >= 0; i -= 1) {
|
|
944
|
+
const id = effectivePinning.right[i];
|
|
918
945
|
if (!id) continue;
|
|
919
946
|
right[id] = rightAcc;
|
|
920
947
|
rightAcc += getColumnWidth(id);
|
|
@@ -1471,8 +1498,8 @@ export function createSvGridController<
|
|
|
1471
1498
|
// that edge and the window are also rendered; negligible for typical grids,
|
|
1472
1499
|
// and correctness beats shaving a few off-screen cells.)
|
|
1473
1500
|
const window = virtualColumns;
|
|
1474
|
-
const hasLeft =
|
|
1475
|
-
const hasRight =
|
|
1501
|
+
const hasLeft = effectivePinning.left.length > 0;
|
|
1502
|
+
const hasRight = effectivePinning.right.length > 0;
|
|
1476
1503
|
if ((!hasLeft && !hasRight) || window.length === 0) return window;
|
|
1477
1504
|
|
|
1478
1505
|
const firstIdx = window[0]!.index;
|
|
@@ -1828,7 +1855,8 @@ export function createSvGridController<
|
|
|
1828
1855
|
// Track viewport size (not scrollVersion) so we don't recompute on
|
|
1829
1856
|
// every scroll - only when the container actually resizes.
|
|
1830
1857
|
viewportVersion;
|
|
1831
|
-
|
|
1858
|
+
// Narrow responsive mode pans instead of scaling, so skip fit scaling.
|
|
1859
|
+
if (!props.fitColumns || isNarrowResponsive) return null;
|
|
1832
1860
|
const cols = grid.getAllColumns().filter((c) => !hiddenColumns[c.id]);
|
|
1833
1861
|
if (!cols.length) return null;
|
|
1834
1862
|
const rowNumberWidth = showRowNumbersEffective ? rowNumberColumnWidth : 0;
|
|
@@ -2016,11 +2044,39 @@ export function createSvGridController<
|
|
|
2016
2044
|
return map;
|
|
2017
2045
|
});
|
|
2018
2046
|
|
|
2047
|
+
// Server-side set-filter values: when a column's filter menu opens and the
|
|
2048
|
+
// consumer provides `serverFilterValues`, fetch the distinct values from the
|
|
2049
|
+
// server once (cached per column) instead of deriving them from the loaded
|
|
2050
|
+
// page - so the checklist shows every value, not just what's on screen.
|
|
2051
|
+
let serverFacetValues = $state<Record<string, Array<string>>>({});
|
|
2052
|
+
let serverFacetLoading = $state<string | null>(null);
|
|
2053
|
+
$effect(() => {
|
|
2054
|
+
const columnId = filterMenuFor ?? columnMenuFor;
|
|
2055
|
+
const fetcher = props.serverFilterValues;
|
|
2056
|
+
if (!columnId || !fetcher || serverFacetValues[columnId]) return;
|
|
2057
|
+
serverFacetLoading = columnId;
|
|
2058
|
+
let cancelled = false;
|
|
2059
|
+
void fetcher(columnId)
|
|
2060
|
+
.then((values) => {
|
|
2061
|
+
if (cancelled) return;
|
|
2062
|
+
serverFacetValues = { ...serverFacetValues, [columnId]: values };
|
|
2063
|
+
serverFacetLoading = null;
|
|
2064
|
+
})
|
|
2065
|
+
.catch(() => {
|
|
2066
|
+
if (!cancelled) serverFacetLoading = null;
|
|
2067
|
+
});
|
|
2068
|
+
return () => {
|
|
2069
|
+
cancelled = true;
|
|
2070
|
+
};
|
|
2071
|
+
});
|
|
2072
|
+
|
|
2019
2073
|
const columnMenuFacetValues = $derived.by(() => {
|
|
2020
2074
|
// The funnel popover drives via `filterMenuFor`; the column menu's Filter
|
|
2021
2075
|
// tab drives via `columnMenuFor`. Support whichever is open.
|
|
2022
2076
|
const columnId = filterMenuFor ?? columnMenuFor;
|
|
2023
2077
|
if (!columnId) return [] as Array<string>;
|
|
2078
|
+
// Server-provided distinct values win (fetched + cached above).
|
|
2079
|
+
if (props.serverFilterValues) return serverFacetValues[columnId] ?? [];
|
|
2024
2080
|
const column = allColumns.find((entry) => entry.id === columnId);
|
|
2025
2081
|
if (!column) return [] as Array<string>;
|
|
2026
2082
|
// Range-bucketed facets for numeric / date columns with many values.
|
|
@@ -2150,6 +2206,8 @@ export function createSvGridController<
|
|
|
2150
2206
|
get MIN_COLUMN_WIDTH() { return MIN_COLUMN_WIDTH; },
|
|
2151
2207
|
get columnPinning() { return columnPinning; },
|
|
2152
2208
|
set columnPinning(v) { columnPinning = v as never; },
|
|
2209
|
+
get effectivePinning() { return effectivePinning; },
|
|
2210
|
+
get isNarrowResponsive() { return isNarrowResponsive; },
|
|
2153
2211
|
get columnVirtualizerVersion() { return columnVirtualizerVersion; },
|
|
2154
2212
|
set columnVirtualizerVersion(v) { columnVirtualizerVersion = v as never; },
|
|
2155
2213
|
get gridStateVersion() { return gridStateVersion; },
|
|
@@ -2450,6 +2508,7 @@ export function createSvGridController<
|
|
|
2450
2508
|
get buildBuckets() { return buildBuckets; },
|
|
2451
2509
|
get isInBucket() { return isInBucket; },
|
|
2452
2510
|
get facetBucketsByColumn() { return facetBucketsByColumn; },
|
|
2511
|
+
get serverFacetLoading() { return serverFacetLoading; },
|
|
2453
2512
|
get columnMenuFacetValues() { return columnMenuFacetValues; },
|
|
2454
2513
|
get columnMenuVisibleFacets() { return columnMenuVisibleFacets; },
|
|
2455
2514
|
get isFacetChecked() { return isFacetChecked; },
|
package/src/SvGrid.css
CHANGED
|
@@ -730,6 +730,13 @@
|
|
|
730
730
|
background: var(--sg-header-bg, #f5f7fb);
|
|
731
731
|
}
|
|
732
732
|
|
|
733
|
+
/* Responsive (narrow) mode: smooth momentum touch panning, and let touch
|
|
734
|
+
gestures pan the grid freely (the wheel-trap contain stays for pointer). */
|
|
735
|
+
.sv-grid-container.sv-grid-narrow {
|
|
736
|
+
-webkit-overflow-scrolling: touch;
|
|
737
|
+
scroll-behavior: auto;
|
|
738
|
+
}
|
|
739
|
+
|
|
733
740
|
.sv-grid-container {
|
|
734
741
|
scrollbar-width: auto;
|
|
735
742
|
-ms-overflow-style: auto;
|
|
@@ -2341,3 +2348,29 @@ select.sv-grid-fr-editor {
|
|
|
2341
2348
|
.sv-grid-filter-operator-btn.is-open {
|
|
2342
2349
|
opacity: 1;
|
|
2343
2350
|
}
|
|
2351
|
+
|
|
2352
|
+
/* Kanban board mode search box (board.searchable) */
|
|
2353
|
+
.sv-grid-board-search {
|
|
2354
|
+
display: flex;
|
|
2355
|
+
align-items: center;
|
|
2356
|
+
gap: 6px;
|
|
2357
|
+
margin-bottom: 8px;
|
|
2358
|
+
padding: 5px 9px;
|
|
2359
|
+
border: 1px solid var(--sg-border, #e4e7ec);
|
|
2360
|
+
border-radius: var(--sg-radius, 8px);
|
|
2361
|
+
background: var(--sg-bg, #fff);
|
|
2362
|
+
color: color-mix(in srgb, var(--sg-fg, #101828) 55%, transparent);
|
|
2363
|
+
max-width: 280px;
|
|
2364
|
+
}
|
|
2365
|
+
.sv-grid-board-search:focus-within {
|
|
2366
|
+
border-color: var(--sg-accent, #3b82f6);
|
|
2367
|
+
}
|
|
2368
|
+
.sv-grid-board-search input {
|
|
2369
|
+
flex: 1 1 auto;
|
|
2370
|
+
border: 0;
|
|
2371
|
+
outline: none;
|
|
2372
|
+
background: transparent;
|
|
2373
|
+
font: inherit;
|
|
2374
|
+
font-size: 0.82rem;
|
|
2375
|
+
color: var(--sg-fg, #101828);
|
|
2376
|
+
}
|
package/src/SvGrid.svelte
CHANGED
|
@@ -25,6 +25,12 @@
|
|
|
25
25
|
import { buildSparkline, toSparklineValues } from "./sparkline";
|
|
26
26
|
import SvGridDropdown from "./SvGridDropdown.svelte";
|
|
27
27
|
import SvDateTimePicker from "./SvDateTimePicker.svelte";
|
|
28
|
+
import {
|
|
29
|
+
hasCellEditor,
|
|
30
|
+
getCellEditor,
|
|
31
|
+
resolveEditorProps,
|
|
32
|
+
type CellEditorContext,
|
|
33
|
+
} from "./editor-registry";
|
|
28
34
|
import { timeStringToDate, dateToTimeString } from "./SvGrid.helpers";
|
|
29
35
|
import type {
|
|
30
36
|
Props,
|
|
@@ -49,8 +55,20 @@
|
|
|
49
55
|
import { createSvGridController } from "./SvGrid.controller.svelte";
|
|
50
56
|
import GridMenus from "./GridMenus.svelte";
|
|
51
57
|
import GridFooter from "./GridFooter.svelte";
|
|
58
|
+
import SvGridBoard from "./SvGridBoard.svelte";
|
|
52
59
|
let props: Props<TFeatures, TData> = $props();
|
|
53
60
|
const ctrl = createSvGridController(props);
|
|
61
|
+
// Kanban board mode: when `board` is set the grid renders lanes of cards
|
|
62
|
+
// instead of the table (see SvGridBoard). Narrowed derived so the template
|
|
63
|
+
// branch can pass it non-null.
|
|
64
|
+
const boardConfig = $derived(props.board);
|
|
65
|
+
// The board renders the grid's FILTERED + SORTED rows (not raw data), so the
|
|
66
|
+
// search box / column filters / sort all flow through to the lanes.
|
|
67
|
+
const boardData = $derived(
|
|
68
|
+
ctrl.allRowsBeforePagination
|
|
69
|
+
.filter((r) => !ctrl.isGroupRow(r))
|
|
70
|
+
.map((r) => r.original),
|
|
71
|
+
);
|
|
54
72
|
|
|
55
73
|
// ---- View facade: re-bind the controller's reactive members as locals so the
|
|
56
74
|
// markup stays identical. Assignable state + bindings + DOM refs use c.* directly.
|
|
@@ -127,6 +145,16 @@
|
|
|
127
145
|
const hasConditionalFormats = $derived(ctrl.hasConditionalFormats);
|
|
128
146
|
const cellConditionalFormat = $derived(ctrl.cellConditionalFormat);
|
|
129
147
|
const isGroupRow = $derived(ctrl.isGroupRow);
|
|
148
|
+
// Server-side group / tree a11y: aria-level on every tree row, aria-expanded
|
|
149
|
+
// on the expandable ones. Undefined (attribute omitted) when serverGroup is off.
|
|
150
|
+
const serverGroup = $derived(props.serverGroup);
|
|
151
|
+
function sgAriaLevel(row: Row<TData>): number | undefined {
|
|
152
|
+
return serverGroup ? serverGroup.level(row.original as TData) + 1 : undefined;
|
|
153
|
+
}
|
|
154
|
+
function sgAriaExpanded(row: Row<TData>): boolean | undefined {
|
|
155
|
+
if (!serverGroup || !serverGroup.isGroup(row.original as TData)) return undefined;
|
|
156
|
+
return serverGroup.expanded?.(row.original as TData) ?? false;
|
|
157
|
+
}
|
|
130
158
|
const sortDirectionByColumn = $derived(ctrl.sortDirectionByColumn);
|
|
131
159
|
const groupingColumns = $derived(ctrl.groupingColumns);
|
|
132
160
|
const paginationState = $derived(ctrl.paginationState);
|
|
@@ -202,6 +230,22 @@
|
|
|
202
230
|
return "sv-grid-cell-flash";
|
|
203
231
|
}
|
|
204
232
|
|
|
233
|
+
// Keyboard-accessible column resize (#79): focus a resize handle and use the
|
|
234
|
+
// arrow keys (Shift = fine 1px step). Complements the pointer-drag resize.
|
|
235
|
+
function resizeColumnByKeyboard(e: KeyboardEvent, columnId: string) {
|
|
236
|
+
let delta = 0;
|
|
237
|
+
const step = e.shiftKey ? 1 : 10;
|
|
238
|
+
if (e.key === "ArrowLeft") delta = -step;
|
|
239
|
+
else if (e.key === "ArrowRight") delta = step;
|
|
240
|
+
else return;
|
|
241
|
+
e.preventDefault();
|
|
242
|
+
const current = ctrl.getColumnWidth(columnId);
|
|
243
|
+
ctrl.columnWidths = {
|
|
244
|
+
...ctrl.columnWidths,
|
|
245
|
+
[columnId]: Math.max(40, current + delta),
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
|
|
205
249
|
// ---- Full-row editing -------------------------------------------------
|
|
206
250
|
const fullRowEdit = $derived(ctrl.fullRowEdit);
|
|
207
251
|
// Commit the whole row when the user clicks away from its editors (Excel /
|
|
@@ -282,6 +326,27 @@
|
|
|
282
326
|
const updateEditingCellValue = $derived(ctrl.updateEditingCellValue);
|
|
283
327
|
const onEditorKeyDown = $derived(ctrl.onEditorKeyDown);
|
|
284
328
|
const focusOnMount = $derived(ctrl.focusOnMount);
|
|
329
|
+
|
|
330
|
+
// Build the interaction context handed to a CUSTOM cell editor registered via
|
|
331
|
+
// `registerCellEditor`. Maps the grid's editing lifecycle onto the uniform
|
|
332
|
+
// change / commit / cancel contract every registered editor speaks.
|
|
333
|
+
function buildRegisteredEditorContext(): CellEditorContext {
|
|
334
|
+
const cell = ctrl.editingCell;
|
|
335
|
+
return {
|
|
336
|
+
value: cell?.value,
|
|
337
|
+
rowId: cell?.rowId ?? "",
|
|
338
|
+
columnId: cell?.columnId ?? "",
|
|
339
|
+
onChange: (v: unknown) => updateEditingCellValue(v),
|
|
340
|
+
onCommit: (v?: unknown) => {
|
|
341
|
+
if (v !== undefined) updateEditingCellValue(v);
|
|
342
|
+
saveEditingCell();
|
|
343
|
+
},
|
|
344
|
+
onCancel: () => {
|
|
345
|
+
ctrl.editingCell = null;
|
|
346
|
+
ctrl.gridRootEl?.focus({ preventScroll: true });
|
|
347
|
+
},
|
|
348
|
+
};
|
|
349
|
+
}
|
|
285
350
|
const onHeaderSortClick = $derived(ctrl.onHeaderSortClick);
|
|
286
351
|
const onGridKeyDown = $derived(ctrl.onGridKeyDown);
|
|
287
352
|
const onGridPaste = $derived(ctrl.onGridPaste);
|
|
@@ -323,6 +388,39 @@
|
|
|
323
388
|
<div class="sv-grid-state sv-grid-state-error" role="alert">
|
|
324
389
|
{props.error}
|
|
325
390
|
</div>
|
|
391
|
+
{:else if boardConfig}
|
|
392
|
+
<div
|
|
393
|
+
class="sv-grid-root sv-grid-board-root"
|
|
394
|
+
class:sv-grid-root-fill={props.containerHeight === "100%"}
|
|
395
|
+
style={`height: ${
|
|
396
|
+
typeof props.containerHeight === "string"
|
|
397
|
+
? props.containerHeight
|
|
398
|
+
: `${props.containerHeight ?? 520}px`
|
|
399
|
+
}; display: flex; flex-direction: column;`}
|
|
400
|
+
>
|
|
401
|
+
{#if boardConfig.searchable !== false}
|
|
402
|
+
<label class="sv-grid-board-search">
|
|
403
|
+
<svg viewBox="0 0 16 16" aria-hidden="true" width="14" height="14">
|
|
404
|
+
<circle cx="7" cy="7" r="4.5" fill="none" stroke="currentColor" stroke-width="1.5" />
|
|
405
|
+
<line x1="10.2" y1="10.2" x2="14" y2="14" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" />
|
|
406
|
+
</svg>
|
|
407
|
+
<input
|
|
408
|
+
type="search"
|
|
409
|
+
placeholder={boardConfig.searchPlaceholder ?? "Search cards..."}
|
|
410
|
+
bind:value={ctrl.globalFilter}
|
|
411
|
+
aria-label="Search cards"
|
|
412
|
+
/>
|
|
413
|
+
</label>
|
|
414
|
+
{/if}
|
|
415
|
+
<div style="flex: 1 1 auto; min-height: 0;">
|
|
416
|
+
<SvGridBoard
|
|
417
|
+
data={boardData}
|
|
418
|
+
columns={props.columns}
|
|
419
|
+
board={boardConfig}
|
|
420
|
+
getRowId={props.getRowId}
|
|
421
|
+
/>
|
|
422
|
+
</div>
|
|
423
|
+
</div>
|
|
326
424
|
{:else}
|
|
327
425
|
{#snippet icon(name: string)}
|
|
328
426
|
<svg
|
|
@@ -874,6 +972,12 @@
|
|
|
874
972
|
onblur={() => saveEditingCell()}
|
|
875
973
|
onkeydown={onEditorKeyDown}
|
|
876
974
|
/>
|
|
975
|
+
{:else if hasCellEditor(String(ctrl.editingCell?.editorType ?? ""))}
|
|
976
|
+
<!-- Custom editor registered via `registerCellEditor(type, Component)`:
|
|
977
|
+
mount it and hand it the uniform change / commit / cancel context. -->
|
|
978
|
+
{@const _reg = getCellEditor(String(ctrl.editingCell?.editorType))!}
|
|
979
|
+
{@const CustomCellEditor = _reg.component}
|
|
980
|
+
<CustomCellEditor {...resolveEditorProps(_reg, buildRegisteredEditorContext())} />
|
|
877
981
|
{:else}
|
|
878
982
|
<input
|
|
879
983
|
use:focusOnMount
|
|
@@ -1246,6 +1350,7 @@
|
|
|
1246
1350
|
<div
|
|
1247
1351
|
class="sv-grid-container sv-grid-container-custom-scrollbars"
|
|
1248
1352
|
class:sv-grid-has-vscroll={hasMeasured && hasVerticalOverflow}
|
|
1353
|
+
class:sv-grid-narrow={ctrl.isNarrowResponsive}
|
|
1249
1354
|
bind:this={ctrl.scrollContainer}
|
|
1250
1355
|
onscroll={onBodyScroll}
|
|
1251
1356
|
style={`overflow: auto; position: relative; height: calc(100% - ${hasMeasured && hasHorizontalOverflow ? 16 : 0}px);`}
|
|
@@ -1258,6 +1363,7 @@
|
|
|
1258
1363
|
activeDescendantId,
|
|
1259
1364
|
rowCount: allRows.length,
|
|
1260
1365
|
colCount: allColumns.length,
|
|
1366
|
+
treegrid: !!props.serverGroup,
|
|
1261
1367
|
})}
|
|
1262
1368
|
onkeydown={onGridKeyDown}
|
|
1263
1369
|
onpaste={onGridPaste}
|
|
@@ -1544,7 +1650,7 @@
|
|
|
1544
1650
|
class:is-active={isColumnFiltered(
|
|
1545
1651
|
header.column.id,
|
|
1546
1652
|
)}
|
|
1547
|
-
aria-label=
|
|
1653
|
+
aria-label={`Filter ${toolPanelHeaderLabel(header.column)}`}
|
|
1548
1654
|
aria-haspopup="menu"
|
|
1549
1655
|
onclick={(event) =>
|
|
1550
1656
|
openFilterMenu(event, header.column.id)}
|
|
@@ -1556,7 +1662,7 @@
|
|
|
1556
1662
|
type="button"
|
|
1557
1663
|
class="sv-grid-col-menu-btn"
|
|
1558
1664
|
class:is-open={columnMenuFor === header.column.id}
|
|
1559
|
-
aria-label=
|
|
1665
|
+
aria-label={`${toolPanelHeaderLabel(header.column)} column menu`}
|
|
1560
1666
|
aria-haspopup="menu"
|
|
1561
1667
|
onclick={(event) =>
|
|
1562
1668
|
openColumnMenu(event, header.column.id)}
|
|
@@ -1595,9 +1701,12 @@
|
|
|
1595
1701
|
header.column.id}
|
|
1596
1702
|
role="separator"
|
|
1597
1703
|
aria-orientation="vertical"
|
|
1598
|
-
aria-label=
|
|
1704
|
+
aria-label={`Resize ${toolPanelHeaderLabel(header.column)}`}
|
|
1705
|
+
tabindex="0"
|
|
1599
1706
|
onpointerdown={(event) =>
|
|
1600
1707
|
startColumnResize(event, header.column.id)}
|
|
1708
|
+
onkeydown={(event) =>
|
|
1709
|
+
resizeColumnByKeyboard(event, header.column.id)}
|
|
1601
1710
|
ondblclick={(event) => event.stopPropagation()}
|
|
1602
1711
|
></div>
|
|
1603
1712
|
{/if}
|
|
@@ -1789,6 +1898,8 @@
|
|
|
1789
1898
|
rowIndex % 2 === 1}
|
|
1790
1899
|
class:sv-grid-row-draggable={rowDragManagedEffective}
|
|
1791
1900
|
{...getGridRowA11yProps(rowIndex + 1)}
|
|
1901
|
+
aria-level={sgAriaLevel(row)}
|
|
1902
|
+
aria-expanded={sgAriaExpanded(row)}
|
|
1792
1903
|
{...rowDragAttrs(rowIndex)}
|
|
1793
1904
|
style={`height: ${rowItem.size}px;`}
|
|
1794
1905
|
>
|
|
@@ -2038,6 +2149,8 @@
|
|
|
2038
2149
|
rowIndex % 2 === 1}
|
|
2039
2150
|
class:sv-grid-row-draggable={rowDragManagedEffective}
|
|
2040
2151
|
{...getGridRowA11yProps(rowIndex + 1)}
|
|
2152
|
+
aria-level={sgAriaLevel(row)}
|
|
2153
|
+
aria-expanded={sgAriaExpanded(row)}
|
|
2041
2154
|
{...rowDragAttrs(rowIndex)}
|
|
2042
2155
|
>
|
|
2043
2156
|
{#if showRowNumbersEffective}
|