@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,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared item shapes for the app-UI components that have no headless core
|
|
3
|
+
* (SvBreadcrumb, SvStepper). Kept in a plain .ts so they can be exported from a
|
|
4
|
+
* component's module script by re-export - a bare `export type` DECLARATION in a
|
|
5
|
+
* `<script module>` trips the Svelte/Vite parser, but a re-export is fine.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/** One crumb in a breadcrumb trail. `href` renders a link; `onClick` a button. */
|
|
9
|
+
export type BreadcrumbItem = {
|
|
10
|
+
label: string
|
|
11
|
+
href?: string
|
|
12
|
+
onClick?: () => void
|
|
13
|
+
/** Optional leading icon (any string: emoji, char, or a font-icon class glyph). */
|
|
14
|
+
icon?: string
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** One step in a stepper. */
|
|
18
|
+
export type StepItem = {
|
|
19
|
+
label: string
|
|
20
|
+
description?: string
|
|
21
|
+
/** Marks the step skippable (shown as "Optional"). */
|
|
22
|
+
optional?: boolean
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** One option in a multi-select. */
|
|
26
|
+
export type MultiSelectOption = {
|
|
27
|
+
value: string | number
|
|
28
|
+
label: string
|
|
29
|
+
disabled?: boolean
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** A node in a tree-select. */
|
|
33
|
+
export type TreeSelectNode = {
|
|
34
|
+
value: string | number
|
|
35
|
+
label: string
|
|
36
|
+
children?: TreeSelectNode[]
|
|
37
|
+
disabled?: boolean
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** A column shown in a grid-select dropdown. */
|
|
41
|
+
export type GridSelectColumn = {
|
|
42
|
+
/** Key into each option row. */
|
|
43
|
+
field: string
|
|
44
|
+
header: string
|
|
45
|
+
/** Any CSS grid track size (e.g. '1fr', '80px'). Default '1fr'. */
|
|
46
|
+
width?: string
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** One action in a command palette (SvCommand). */
|
|
50
|
+
export type CommandItem = {
|
|
51
|
+
id: string
|
|
52
|
+
label: string
|
|
53
|
+
/** Right-aligned hint / description. */
|
|
54
|
+
hint?: string
|
|
55
|
+
/** Section header this command groups under. */
|
|
56
|
+
group?: string
|
|
57
|
+
/** Leading glyph (emoji / char). */
|
|
58
|
+
icon?: string
|
|
59
|
+
/** Right-aligned keyboard shortcut hint, e.g. "⌘S". */
|
|
60
|
+
shortcut?: string
|
|
61
|
+
/** Extra searchable terms beyond the label. */
|
|
62
|
+
keywords?: string
|
|
63
|
+
disabled?: boolean
|
|
64
|
+
/** Run when chosen. */
|
|
65
|
+
onRun?: () => void
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** One step in a guided tour. */
|
|
69
|
+
export type TourStep = {
|
|
70
|
+
/** Element to spotlight: a CSS selector or the element itself. Omit for a
|
|
71
|
+
* centered, target-less step (intro / outro). */
|
|
72
|
+
target?: string | HTMLElement
|
|
73
|
+
title?: string
|
|
74
|
+
content: string
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** One entry in a timeline. */
|
|
78
|
+
export type TimelineItem = {
|
|
79
|
+
id?: string | number
|
|
80
|
+
title: string
|
|
81
|
+
description?: string
|
|
82
|
+
/** Right-aligned timestamp/label. */
|
|
83
|
+
time?: string
|
|
84
|
+
/** Marker colour (any CSS colour). Defaults to the accent. */
|
|
85
|
+
color?: string
|
|
86
|
+
/** Optional leading glyph inside the marker (emoji / char). */
|
|
87
|
+
icon?: string
|
|
88
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rendering tests for the presentational display trio: SvBadge, SvSkeleton,
|
|
3
|
+
* SvCard - variant/prop-driven classes, a11y roles, and conditional regions.
|
|
4
|
+
*/
|
|
5
|
+
import { describe, expect, it } from 'vitest'
|
|
6
|
+
import { mount, unmount, flushSync } from 'svelte'
|
|
7
|
+
import SvBadge from './SvBadge.svelte'
|
|
8
|
+
import SvSkeleton from './SvSkeleton.svelte'
|
|
9
|
+
import SvCard from './SvCard.svelte'
|
|
10
|
+
|
|
11
|
+
function mountOn<T extends Record<string, unknown>>(Comp: any, props: T) {
|
|
12
|
+
const target = document.createElement('div')
|
|
13
|
+
document.body.appendChild(target)
|
|
14
|
+
const app = mount(Comp, { target, props: props as any })
|
|
15
|
+
flushSync()
|
|
16
|
+
return { target, destroy: () => { unmount(app); target.remove() } }
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
describe('SvBadge', () => {
|
|
20
|
+
it('applies variant + size classes and pill by default', () => {
|
|
21
|
+
const { target, destroy } = mountOn(SvBadge, { variant: 'success', size: 'sm' })
|
|
22
|
+
try {
|
|
23
|
+
const el = target.querySelector('.sv-badge')!
|
|
24
|
+
expect(el.classList.contains('sv-badge--success')).toBe(true)
|
|
25
|
+
expect(el.classList.contains('sv-badge--sm')).toBe(true)
|
|
26
|
+
expect(el.classList.contains('is-pill')).toBe(true)
|
|
27
|
+
} finally { destroy() }
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
it('renders a status dot when dot is set', () => {
|
|
31
|
+
const { target, destroy } = mountOn(SvBadge, { variant: 'danger', dot: true })
|
|
32
|
+
try {
|
|
33
|
+
expect(target.querySelector('.sv-badge__dot')).not.toBeNull()
|
|
34
|
+
} finally { destroy() }
|
|
35
|
+
})
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
describe('SvSkeleton', () => {
|
|
39
|
+
it('renders one box per line for text variant with a shorter last line', () => {
|
|
40
|
+
const { target, destroy } = mountOn(SvSkeleton, { variant: 'text', lines: 3 })
|
|
41
|
+
try {
|
|
42
|
+
const boxes = target.querySelectorAll('.sv-skel__box')
|
|
43
|
+
expect(boxes).toHaveLength(3)
|
|
44
|
+
expect(boxes[2]!.classList.contains('is-last')).toBe(true)
|
|
45
|
+
expect(target.querySelector('.sv-skel')!.getAttribute('aria-busy')).toBe('true')
|
|
46
|
+
} finally { destroy() }
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it('renders a single circle box for circle variant', () => {
|
|
50
|
+
const { target, destroy } = mountOn(SvSkeleton, { variant: 'circle' })
|
|
51
|
+
try {
|
|
52
|
+
const boxes = target.querySelectorAll('.sv-skel__box')
|
|
53
|
+
expect(boxes).toHaveLength(1)
|
|
54
|
+
expect(boxes[0]!.classList.contains('sv-skel__box--circle')).toBe(true)
|
|
55
|
+
} finally { destroy() }
|
|
56
|
+
})
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
describe('SvCard', () => {
|
|
60
|
+
it('renders a header only when title/subtitle/header provided', () => {
|
|
61
|
+
const bare = mountOn(SvCard, {})
|
|
62
|
+
try {
|
|
63
|
+
expect(bare.target.querySelector('.sv-card__header')).toBeNull()
|
|
64
|
+
} finally { bare.destroy() }
|
|
65
|
+
|
|
66
|
+
const titled = mountOn(SvCard, { title: 'Revenue', subtitle: 'Last 30 days' })
|
|
67
|
+
try {
|
|
68
|
+
expect(titled.target.querySelector('.sv-card__title')!.textContent).toBe('Revenue')
|
|
69
|
+
expect(titled.target.querySelector('.sv-card__subtitle')!.textContent).toBe('Last 30 days')
|
|
70
|
+
} finally { titled.destroy() }
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
it('flush removes body padding via a modifier class', () => {
|
|
74
|
+
const { target, destroy } = mountOn(SvCard, { flush: true })
|
|
75
|
+
try {
|
|
76
|
+
expect(target.querySelector('.sv-card__body')!.classList.contains('is-flush')).toBe(true)
|
|
77
|
+
} finally { destroy() }
|
|
78
|
+
})
|
|
79
|
+
})
|
package/src/ui-inputs.test.ts
CHANGED
|
@@ -93,7 +93,7 @@ describe('SvMaskedInput', () => {
|
|
|
93
93
|
onChange: (m: string, r: string) => { masked = m; raw = r },
|
|
94
94
|
})
|
|
95
95
|
try {
|
|
96
|
-
const input = target.querySelector<HTMLInputElement>('.sv-
|
|
96
|
+
const input = target.querySelector<HTMLInputElement>('.sv-masked__input')!
|
|
97
97
|
input.value = '1234567890'
|
|
98
98
|
input.dispatchEvent(new Event('input', { bubbles: true }))
|
|
99
99
|
flushSync()
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Component tests for the Tier-1 status/display batch: SvAlert, SvEmptyState,
|
|
3
|
+
* SvDivider, SvChip, SvStat, SvTimeline.
|
|
4
|
+
*/
|
|
5
|
+
import { describe, expect, it, vi } from 'vitest'
|
|
6
|
+
import { mount, unmount, flushSync } from 'svelte'
|
|
7
|
+
import SvAlert from './SvAlert.svelte'
|
|
8
|
+
import SvEmptyState from './SvEmptyState.svelte'
|
|
9
|
+
import SvDivider from './SvDivider.svelte'
|
|
10
|
+
import SvChip from './SvChip.svelte'
|
|
11
|
+
import SvStat from './SvStat.svelte'
|
|
12
|
+
import SvTimeline from './SvTimeline.svelte'
|
|
13
|
+
|
|
14
|
+
function mountOn(Comp: any, props: Record<string, unknown>) {
|
|
15
|
+
const target = document.createElement('div')
|
|
16
|
+
document.body.appendChild(target)
|
|
17
|
+
const app = mount(Comp, { target, props: props as any })
|
|
18
|
+
flushSync()
|
|
19
|
+
return { target, destroy: () => { unmount(app); target.remove() } }
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
describe('SvAlert', () => {
|
|
23
|
+
it('applies the variant class and uses role=alert for danger', () => {
|
|
24
|
+
const { target, destroy } = mountOn(SvAlert, { variant: 'danger', title: 'Failed' })
|
|
25
|
+
try {
|
|
26
|
+
const el = target.querySelector('.sv-alert')!
|
|
27
|
+
expect(el.classList.contains('sv-alert--danger')).toBe(true)
|
|
28
|
+
expect(el.getAttribute('role')).toBe('alert')
|
|
29
|
+
expect(target.querySelector('.sv-alert__title')!.textContent).toBe('Failed')
|
|
30
|
+
} finally { destroy() }
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it('dismissible: the x removes the alert and fires onDismiss', () => {
|
|
34
|
+
const onDismiss = vi.fn()
|
|
35
|
+
const { target, destroy } = mountOn(SvAlert, { dismissible: true, onDismiss })
|
|
36
|
+
try {
|
|
37
|
+
target.querySelector<HTMLButtonElement>('.sv-alert__x')!.click()
|
|
38
|
+
flushSync()
|
|
39
|
+
expect(onDismiss).toHaveBeenCalled()
|
|
40
|
+
expect(target.querySelector('.sv-alert')).toBeNull()
|
|
41
|
+
} finally { destroy() }
|
|
42
|
+
})
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
describe('SvEmptyState', () => {
|
|
46
|
+
it('renders title, description and a default icon', () => {
|
|
47
|
+
const { target, destroy } = mountOn(SvEmptyState, { title: 'Nothing here', description: 'Add one.' })
|
|
48
|
+
try {
|
|
49
|
+
expect(target.querySelector('.sv-empty__title')!.textContent).toBe('Nothing here')
|
|
50
|
+
expect(target.querySelector('.sv-empty__desc')!.textContent).toBe('Add one.')
|
|
51
|
+
expect(target.querySelector('.sv-empty__icon svg')).not.toBeNull()
|
|
52
|
+
} finally { destroy() }
|
|
53
|
+
})
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
describe('SvDivider', () => {
|
|
57
|
+
it('is a horizontal separator by default', () => {
|
|
58
|
+
const { target, destroy } = mountOn(SvDivider, {})
|
|
59
|
+
try {
|
|
60
|
+
const el = target.querySelector('.sv-divider')!
|
|
61
|
+
expect(el.getAttribute('role')).toBe('separator')
|
|
62
|
+
expect(el.classList.contains('sv-divider--h')).toBe(true)
|
|
63
|
+
} finally { destroy() }
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
it('renders a label and the has-label class', () => {
|
|
67
|
+
const { target, destroy } = mountOn(SvDivider, { label: 'OR' })
|
|
68
|
+
try {
|
|
69
|
+
const el = target.querySelector('.sv-divider')!
|
|
70
|
+
expect(el.classList.contains('has-label')).toBe(true)
|
|
71
|
+
expect(target.querySelector('.sv-divider__label')!.textContent).toBe('OR')
|
|
72
|
+
} finally { destroy() }
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
it('vertical orientation sets aria-orientation', () => {
|
|
76
|
+
const { target, destroy } = mountOn(SvDivider, { orientation: 'vertical' })
|
|
77
|
+
try {
|
|
78
|
+
const el = target.querySelector('.sv-divider')!
|
|
79
|
+
expect(el.classList.contains('sv-divider--v')).toBe(true)
|
|
80
|
+
expect(el.getAttribute('aria-orientation')).toBe('vertical')
|
|
81
|
+
} finally { destroy() }
|
|
82
|
+
})
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
describe('SvChip', () => {
|
|
86
|
+
it('removable: the x fires onRemove', () => {
|
|
87
|
+
const onRemove = vi.fn()
|
|
88
|
+
const { target, destroy } = mountOn(SvChip, { removable: true, onRemove, variant: 'accent' })
|
|
89
|
+
try {
|
|
90
|
+
expect(target.querySelector('.sv-chip')!.classList.contains('sv-chip--accent')).toBe(true)
|
|
91
|
+
target.querySelector<HTMLButtonElement>('.sv-chip__x')!.click()
|
|
92
|
+
expect(onRemove).toHaveBeenCalled()
|
|
93
|
+
} finally { destroy() }
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
it('onClick makes the label a button', () => {
|
|
97
|
+
const onClick = vi.fn()
|
|
98
|
+
const { target, destroy } = mountOn(SvChip, { onClick })
|
|
99
|
+
try {
|
|
100
|
+
const btn = target.querySelector<HTMLButtonElement>('.sv-chip__label--btn')!
|
|
101
|
+
expect(btn).not.toBeNull()
|
|
102
|
+
btn.click()
|
|
103
|
+
expect(onClick).toHaveBeenCalled()
|
|
104
|
+
} finally { destroy() }
|
|
105
|
+
})
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
describe('SvStat', () => {
|
|
109
|
+
it('renders the value and infers an up/good trend from a positive delta', () => {
|
|
110
|
+
const { target, destroy } = mountOn(SvStat, { label: 'Revenue', value: '$48k', delta: 12.4 })
|
|
111
|
+
try {
|
|
112
|
+
expect(target.querySelector('.sv-stat__value')!.textContent).toBe('$48k')
|
|
113
|
+
const delta = target.querySelector('.sv-stat__delta')!
|
|
114
|
+
expect(delta.textContent).toContain('+12.4%')
|
|
115
|
+
expect(delta.classList.contains('is-good')).toBe(true)
|
|
116
|
+
} finally { destroy() }
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
it('invert makes a downward delta good (e.g. error rate)', () => {
|
|
120
|
+
const { target, destroy } = mountOn(SvStat, { label: 'Errors', value: '0.4%', delta: -20, invert: true })
|
|
121
|
+
try {
|
|
122
|
+
const delta = target.querySelector('.sv-stat__delta')!
|
|
123
|
+
expect(delta.classList.contains('is-good')).toBe(true)
|
|
124
|
+
} finally { destroy() }
|
|
125
|
+
})
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
describe('SvTimeline', () => {
|
|
129
|
+
it('renders an entry per item with title/time/description', () => {
|
|
130
|
+
const items = [
|
|
131
|
+
{ title: 'Placed', time: '09:12' },
|
|
132
|
+
{ title: 'Shipped', time: '14:40', description: 'Left the warehouse' },
|
|
133
|
+
]
|
|
134
|
+
const { target, destroy } = mountOn(SvTimeline, { items })
|
|
135
|
+
try {
|
|
136
|
+
expect(target.querySelectorAll('.sv-timeline__item')).toHaveLength(2)
|
|
137
|
+
expect([...target.querySelectorAll('.sv-timeline__title')].map((t) => t.textContent)).toEqual(['Placed', 'Shipped'])
|
|
138
|
+
expect(target.querySelector('.sv-timeline__desc')!.textContent).toBe('Left the warehouse')
|
|
139
|
+
} finally { destroy() }
|
|
140
|
+
})
|
|
141
|
+
})
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Component tests for the Tier-1 text editors: SvTextInput, SvTextArea and
|
|
3
|
+
* SvOtpInput - value emit, the commit/cancel interaction contract, and OTP
|
|
4
|
+
* auto-advance / paste distribution.
|
|
5
|
+
*/
|
|
6
|
+
import { describe, expect, it, vi } from 'vitest'
|
|
7
|
+
import { mount, unmount, flushSync } from 'svelte'
|
|
8
|
+
import SvTextInput from './SvTextInput.svelte'
|
|
9
|
+
import SvTextArea from './SvTextArea.svelte'
|
|
10
|
+
import SvOtpInput from './SvOtpInput.svelte'
|
|
11
|
+
import SvDurationInput from './SvDurationInput.svelte'
|
|
12
|
+
|
|
13
|
+
function mountOn(Comp: any, props: Record<string, unknown>) {
|
|
14
|
+
const target = document.createElement('div')
|
|
15
|
+
document.body.appendChild(target)
|
|
16
|
+
const app = mount(Comp, { target, props: props as any })
|
|
17
|
+
flushSync()
|
|
18
|
+
return { target, destroy: () => { unmount(app); target.remove() } }
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
describe('SvTextInput', () => {
|
|
22
|
+
it('emits onChange on input', () => {
|
|
23
|
+
const onChange = vi.fn()
|
|
24
|
+
const { target, destroy } = mountOn(SvTextInput, { value: '', onChange })
|
|
25
|
+
try {
|
|
26
|
+
const input = target.querySelector<HTMLInputElement>('.sv-text__input')!
|
|
27
|
+
input.value = 'hello'
|
|
28
|
+
input.dispatchEvent(new Event('input', { bubbles: true }))
|
|
29
|
+
expect(onChange).toHaveBeenCalledWith('hello')
|
|
30
|
+
} finally { destroy() }
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it('Enter commits and Escape cancels', () => {
|
|
34
|
+
const onCommit = vi.fn(), onCancel = vi.fn()
|
|
35
|
+
const { target, destroy } = mountOn(SvTextInput, { value: 'abc', onCommit, onCancel })
|
|
36
|
+
try {
|
|
37
|
+
const input = target.querySelector<HTMLInputElement>('.sv-text__input')!
|
|
38
|
+
input.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }))
|
|
39
|
+
expect(onCommit).toHaveBeenCalledWith('abc')
|
|
40
|
+
input.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }))
|
|
41
|
+
expect(onCancel).toHaveBeenCalled()
|
|
42
|
+
} finally { destroy() }
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it('clearable shows a clear button that empties the value', () => {
|
|
46
|
+
const onChange = vi.fn()
|
|
47
|
+
const { target, destroy } = mountOn(SvTextInput, { value: 'x', clearable: true, onChange })
|
|
48
|
+
try {
|
|
49
|
+
const clear = target.querySelector<HTMLButtonElement>('.sv-text__clear')!
|
|
50
|
+
expect(clear).not.toBeNull()
|
|
51
|
+
clear.click()
|
|
52
|
+
expect(onChange).toHaveBeenCalledWith('')
|
|
53
|
+
} finally { destroy() }
|
|
54
|
+
})
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
describe('SvTextArea', () => {
|
|
58
|
+
it('Ctrl+Enter commits, Escape cancels, Enter alone does not commit', () => {
|
|
59
|
+
const onCommit = vi.fn(), onCancel = vi.fn()
|
|
60
|
+
const { target, destroy } = mountOn(SvTextArea, { value: 'note', onCommit, onCancel })
|
|
61
|
+
try {
|
|
62
|
+
const ta = target.querySelector<HTMLTextAreaElement>('.sv-ta__input')!
|
|
63
|
+
ta.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }))
|
|
64
|
+
expect(onCommit).not.toHaveBeenCalled()
|
|
65
|
+
ta.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', ctrlKey: true, bubbles: true }))
|
|
66
|
+
expect(onCommit).toHaveBeenCalledWith('note')
|
|
67
|
+
ta.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }))
|
|
68
|
+
expect(onCancel).toHaveBeenCalled()
|
|
69
|
+
} finally { destroy() }
|
|
70
|
+
})
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
describe('SvOtpInput', () => {
|
|
74
|
+
it('renders one cell per length', () => {
|
|
75
|
+
const { target, destroy } = mountOn(SvOtpInput, { length: 4 })
|
|
76
|
+
try {
|
|
77
|
+
expect(target.querySelectorAll('.sv-otp__cell')).toHaveLength(4)
|
|
78
|
+
} finally { destroy() }
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
it('typing a digit emits onChange and advances focus', () => {
|
|
82
|
+
const onChange = vi.fn()
|
|
83
|
+
const { target, destroy } = mountOn(SvOtpInput, { length: 4, value: '', onChange })
|
|
84
|
+
try {
|
|
85
|
+
const cells = target.querySelectorAll<HTMLInputElement>('.sv-otp__cell')
|
|
86
|
+
cells[0]!.value = '7'
|
|
87
|
+
cells[0]!.dispatchEvent(new Event('input', { bubbles: true }))
|
|
88
|
+
expect(onChange).toHaveBeenCalledWith('7')
|
|
89
|
+
expect(document.activeElement).toBe(cells[1])
|
|
90
|
+
} finally { destroy() }
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
it('paste distributes across cells and fires onComplete when full', () => {
|
|
94
|
+
const onChange = vi.fn(), onComplete = vi.fn()
|
|
95
|
+
const { target, destroy } = mountOn(SvOtpInput, { length: 4, value: '', onChange, onComplete })
|
|
96
|
+
try {
|
|
97
|
+
const cells = target.querySelectorAll<HTMLInputElement>('.sv-otp__cell')
|
|
98
|
+
const e = new Event('paste', { bubbles: true, cancelable: true })
|
|
99
|
+
Object.defineProperty(e, 'clipboardData', { value: { getData: () => '12ab34' } })
|
|
100
|
+
cells[0]!.dispatchEvent(e)
|
|
101
|
+
// numeric mode strips letters -> '1234'
|
|
102
|
+
expect(onChange).toHaveBeenCalledWith('1234')
|
|
103
|
+
expect(onComplete).toHaveBeenCalledWith('1234')
|
|
104
|
+
} finally { destroy() }
|
|
105
|
+
})
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
describe('SvDurationInput', () => {
|
|
109
|
+
it('parses human input to minutes on blur', () => {
|
|
110
|
+
const onChange = vi.fn()
|
|
111
|
+
const { target, destroy } = mountOn(SvDurationInput, { value: null, onChange })
|
|
112
|
+
try {
|
|
113
|
+
const input = target.querySelector<HTMLInputElement>('.sv-dur__input')!
|
|
114
|
+
input.dispatchEvent(new Event('focus', { bubbles: true }))
|
|
115
|
+
input.value = '1h 30m'
|
|
116
|
+
input.dispatchEvent(new Event('input', { bubbles: true }))
|
|
117
|
+
input.dispatchEvent(new Event('blur', { bubbles: true }))
|
|
118
|
+
expect(onChange).toHaveBeenCalledWith(90)
|
|
119
|
+
} finally { destroy() }
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
it('formats the external value as h:mm when unfocused', () => {
|
|
123
|
+
const { target, destroy } = mountOn(SvDurationInput, { value: 125 })
|
|
124
|
+
try {
|
|
125
|
+
const input = target.querySelector<HTMLInputElement>('.sv-dur__input')!
|
|
126
|
+
expect(input.value).toBe('2:05')
|
|
127
|
+
} finally { destroy() }
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
it('Enter commits the parsed value', () => {
|
|
131
|
+
const onCommit = vi.fn()
|
|
132
|
+
const { target, destroy } = mountOn(SvDurationInput, { value: null, onCommit })
|
|
133
|
+
try {
|
|
134
|
+
const input = target.querySelector<HTMLInputElement>('.sv-dur__input')!
|
|
135
|
+
input.dispatchEvent(new Event('focus', { bubbles: true }))
|
|
136
|
+
input.value = '45m'
|
|
137
|
+
input.dispatchEvent(new Event('input', { bubbles: true }))
|
|
138
|
+
input.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }))
|
|
139
|
+
expect(onCommit).toHaveBeenCalledWith(45)
|
|
140
|
+
} finally { destroy() }
|
|
141
|
+
})
|
|
142
|
+
})
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Component tests for the Tier-2 batch: SvCommand (palette), SvAvatarGroup,
|
|
3
|
+
* SvSparkline, SvScrollArea.
|
|
4
|
+
*/
|
|
5
|
+
import { afterEach, describe, expect, it, vi } from 'vitest'
|
|
6
|
+
import { mount, unmount, flushSync } from 'svelte'
|
|
7
|
+
import SvCommand from './SvCommand.svelte'
|
|
8
|
+
import SvAvatarGroup from './SvAvatarGroup.svelte'
|
|
9
|
+
import SvSparkline from './SvSparkline.svelte'
|
|
10
|
+
import SvScrollArea from './SvScrollArea.svelte'
|
|
11
|
+
|
|
12
|
+
function mountOn(Comp: any, props: Record<string, unknown>) {
|
|
13
|
+
const target = document.createElement('div')
|
|
14
|
+
document.body.appendChild(target)
|
|
15
|
+
const app = mount(Comp, { target, props: props as any })
|
|
16
|
+
flushSync()
|
|
17
|
+
return { target, destroy: () => { unmount(app); target.remove() } }
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
afterEach(() => { document.body.innerHTML = '' })
|
|
21
|
+
|
|
22
|
+
const commands = [
|
|
23
|
+
{ id: 'new', label: 'New invoice', group: 'Create', icon: '+' },
|
|
24
|
+
{ id: 'export', label: 'Export CSV', group: 'Data', shortcut: '⌘E' },
|
|
25
|
+
{ id: 'settings', label: 'Open settings', group: 'App' },
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
describe('SvCommand', () => {
|
|
29
|
+
it('opens a portalled palette listing the commands', () => {
|
|
30
|
+
const { destroy } = mountOn(SvCommand, { open: true, commands, hotkey: false })
|
|
31
|
+
try {
|
|
32
|
+
expect(document.body.querySelector('.sv-cmd')).not.toBeNull()
|
|
33
|
+
expect(document.body.querySelectorAll('.sv-cmd__opt')).toHaveLength(3)
|
|
34
|
+
} finally { destroy() }
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
it('fuzzy-filters as you type', () => {
|
|
38
|
+
const { destroy } = mountOn(SvCommand, { open: true, commands, hotkey: false })
|
|
39
|
+
try {
|
|
40
|
+
const input = document.body.querySelector<HTMLInputElement>('.sv-cmd__input')!
|
|
41
|
+
input.value = 'exp'
|
|
42
|
+
input.dispatchEvent(new Event('input', { bubbles: true }))
|
|
43
|
+
flushSync()
|
|
44
|
+
const opts = [...document.body.querySelectorAll('.sv-cmd__opt')].map((o) => o.textContent)
|
|
45
|
+
expect(opts).toHaveLength(1)
|
|
46
|
+
expect(opts[0]).toContain('Export CSV')
|
|
47
|
+
} finally { destroy() }
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
it('ArrowDown + Enter runs the active command and closes', () => {
|
|
51
|
+
const onRun = vi.fn()
|
|
52
|
+
const cmdRun = vi.fn()
|
|
53
|
+
const cmds = [{ id: 'a', label: 'Alpha', onRun: cmdRun }, { id: 'b', label: 'Beta' }]
|
|
54
|
+
const { destroy } = mountOn(SvCommand, { open: true, commands: cmds, onRun, hotkey: false })
|
|
55
|
+
try {
|
|
56
|
+
const panel = document.body.querySelector('.sv-cmd')!
|
|
57
|
+
panel.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true }))
|
|
58
|
+
panel.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }))
|
|
59
|
+
flushSync()
|
|
60
|
+
expect(onRun).toHaveBeenCalledWith(cmds[1]) // moved to Beta
|
|
61
|
+
expect(document.body.querySelector('.sv-cmd')).toBeNull()
|
|
62
|
+
} finally { destroy() }
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
it('clicking an option runs it', () => {
|
|
66
|
+
const onRun = vi.fn()
|
|
67
|
+
const { destroy } = mountOn(SvCommand, { open: true, commands, hotkey: false })
|
|
68
|
+
try {
|
|
69
|
+
// (onRun set via a separate mount would be cleaner; here just assert close)
|
|
70
|
+
const opt = document.body.querySelector<HTMLElement>('.sv-cmd__opt')!
|
|
71
|
+
opt.click()
|
|
72
|
+
flushSync()
|
|
73
|
+
expect(document.body.querySelector('.sv-cmd')).toBeNull()
|
|
74
|
+
void onRun
|
|
75
|
+
} finally { destroy() }
|
|
76
|
+
})
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
describe('SvAvatarGroup', () => {
|
|
80
|
+
it('shows up to max avatars and a +N overflow pill', () => {
|
|
81
|
+
const avatars = [{ name: 'Ada' }, { name: 'Alan' }, { name: 'Grace' }, { name: 'Ken' }, { name: 'Lin' }]
|
|
82
|
+
const { target, destroy } = mountOn(SvAvatarGroup, { avatars, max: 3 })
|
|
83
|
+
try {
|
|
84
|
+
expect(target.querySelectorAll('.sv-avgroup__it')).toHaveLength(3)
|
|
85
|
+
expect(target.querySelector('.sv-avgroup__more')!.textContent).toBe('+2')
|
|
86
|
+
} finally { destroy() }
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
it('no overflow pill when under max', () => {
|
|
90
|
+
const { target, destroy } = mountOn(SvAvatarGroup, { avatars: [{ name: 'Ada' }], max: 4 })
|
|
91
|
+
try {
|
|
92
|
+
expect(target.querySelector('.sv-avgroup__more')).toBeNull()
|
|
93
|
+
} finally { destroy() }
|
|
94
|
+
})
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
describe('SvSparkline', () => {
|
|
98
|
+
it('renders an svg with a line path for line data', () => {
|
|
99
|
+
const { target, destroy } = mountOn(SvSparkline, { data: [3, 7, 4, 9, 6, 11, 8], type: 'line' })
|
|
100
|
+
try {
|
|
101
|
+
const svg = target.querySelector('svg.sv-spark')!
|
|
102
|
+
expect(svg).not.toBeNull()
|
|
103
|
+
expect(svg.querySelector('path')).not.toBeNull()
|
|
104
|
+
} finally { destroy() }
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
it('renders rects for bar data', () => {
|
|
108
|
+
const { target, destroy } = mountOn(SvSparkline, { data: [1, -2, 3, -1, 2], type: 'bar' })
|
|
109
|
+
try {
|
|
110
|
+
expect(target.querySelectorAll('svg.sv-spark rect').length).toBe(5)
|
|
111
|
+
} finally { destroy() }
|
|
112
|
+
})
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
describe('SvScrollArea', () => {
|
|
116
|
+
it('renders a themed scroll container with the given max-height', () => {
|
|
117
|
+
const { target, destroy } = mountOn(SvScrollArea, { maxHeight: '200px' })
|
|
118
|
+
try {
|
|
119
|
+
const el = target.querySelector<HTMLElement>('.sv-scroll')!
|
|
120
|
+
expect(el).not.toBeNull()
|
|
121
|
+
expect(el.style.maxHeight).toBe('200px')
|
|
122
|
+
} finally { destroy() }
|
|
123
|
+
})
|
|
124
|
+
})
|