@happyvertical/smrt-ui 0.51.39 → 0.53.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +25 -3
- package/README.md +558 -8
- package/dist/actions/__tests__/swipe-dismiss.test.js +69 -0
- package/dist/actions/swipe-dismiss.d.ts +42 -0
- package/dist/actions/swipe-dismiss.d.ts.map +1 -0
- package/dist/actions/swipe-dismiss.js +69 -0
- package/dist/components/calendar/Calendar.svelte +5 -0
- package/dist/components/calendar/Calendar.svelte.d.ts.map +1 -1
- package/dist/components/calendar/CalendarView.svelte +1250 -0
- package/dist/components/calendar/CalendarView.svelte.d.ts +66 -0
- package/dist/components/calendar/CalendarView.svelte.d.ts.map +1 -0
- package/dist/components/calendar/DayView.svelte +5 -0
- package/dist/components/calendar/DayView.svelte.d.ts.map +1 -1
- package/dist/components/calendar/__tests__/CalendarView.test.js +226 -0
- package/dist/components/calendar/__tests__/calendar-model.test.js +138 -0
- package/dist/components/calendar/calendar-model.d.ts +178 -0
- package/dist/components/calendar/calendar-model.d.ts.map +1 -0
- package/dist/components/calendar/calendar-model.js +362 -0
- package/dist/components/calendar/index.d.ts +12 -1
- package/dist/components/calendar/index.d.ts.map +1 -1
- package/dist/components/calendar/index.js +11 -1
- package/dist/components/data/CollectionList.svelte +23 -5
- package/dist/components/data/CollectionList.svelte.d.ts +8 -2
- package/dist/components/data/CollectionList.svelte.d.ts.map +1 -1
- package/dist/components/data/DataTable.svelte +178 -55
- package/dist/components/data/DataTable.svelte.d.ts.map +1 -1
- package/dist/components/data/DataTableController.d.ts +4 -0
- package/dist/components/data/DataTableController.d.ts.map +1 -1
- package/dist/components/data/DataTableController.js +11 -4
- package/dist/components/data/DataTableResponsive.d.ts +4 -0
- package/dist/components/data/DataTableResponsive.d.ts.map +1 -0
- package/dist/components/data/DataTableResponsive.js +22 -0
- package/dist/components/data/ListSortSelect.svelte +121 -0
- package/dist/components/data/ListSortSelect.svelte.d.ts +22 -0
- package/dist/components/data/ListSortSelect.svelte.d.ts.map +1 -0
- package/dist/components/data/SortableHeader.svelte +169 -0
- package/dist/components/data/SortableHeader.svelte.d.ts +30 -0
- package/dist/components/data/SortableHeader.svelte.d.ts.map +1 -0
- package/dist/components/data/__tests__/CollectionList.test.js +37 -0
- package/dist/components/data/__tests__/DataTable.test.js +76 -0
- package/dist/components/data/__tests__/DataTableController.test.js +35 -0
- package/dist/components/data/__tests__/DataTableResponsive.test.js +80 -0
- package/dist/components/data/__tests__/SortableHeader.test.js +101 -0
- package/dist/components/data/__tests__/link-step-surface.test.js +172 -0
- package/dist/components/data/__tests__/list-sort-state.svelte.test.js +71 -0
- package/dist/components/data/__tests__/list-sort.test.js +91 -0
- package/dist/components/data/__tests__/responsive-table.fixture.svelte +29 -0
- package/dist/components/data/__tests__/responsive-table.fixture.svelte.d.ts +7 -0
- package/dist/components/data/__tests__/responsive-table.fixture.svelte.d.ts.map +1 -0
- package/dist/components/data/__tests__/surface-navigation.test.js +121 -0
- package/dist/components/data/data-surface.d.ts +1 -0
- package/dist/components/data/data-surface.d.ts.map +1 -1
- package/dist/components/data/data-surface.js +1 -0
- package/dist/components/data/index.d.ts +6 -0
- package/dist/components/data/index.d.ts.map +1 -1
- package/dist/components/data/index.js +6 -0
- package/dist/components/data/link-surface.d.ts +79 -0
- package/dist/components/data/link-surface.d.ts.map +1 -0
- package/dist/components/data/link-surface.js +155 -0
- package/dist/components/data/list-sort-state.svelte.d.ts +39 -0
- package/dist/components/data/list-sort-state.svelte.d.ts.map +1 -0
- package/dist/components/data/list-sort-state.svelte.js +47 -0
- package/dist/components/data/list-sort.d.ts +94 -0
- package/dist/components/data/list-sort.d.ts.map +1 -0
- package/dist/components/data/list-sort.js +182 -0
- package/dist/components/data/step-surface.d.ts +73 -0
- package/dist/components/data/step-surface.d.ts.map +1 -0
- package/dist/components/data/step-surface.js +177 -0
- package/dist/components/data/surface-navigation.d.ts +49 -0
- package/dist/components/data/surface-navigation.d.ts.map +1 -0
- package/dist/components/data/surface-navigation.js +100 -0
- package/dist/components/data/types.d.ts +27 -0
- package/dist/components/data/types.d.ts.map +1 -1
- package/dist/components/display/DateDisplay.svelte +76 -14
- package/dist/components/display/DateDisplay.svelte.d.ts +2 -0
- package/dist/components/display/DateDisplay.svelte.d.ts.map +1 -1
- package/dist/components/display/Icon.svelte +3 -16
- package/dist/components/display/Icon.svelte.d.ts +0 -9
- package/dist/components/display/Icon.svelte.d.ts.map +1 -1
- package/dist/components/display/StatusBadge.svelte +29 -2
- package/dist/components/display/StatusBadge.svelte.d.ts +4 -2
- package/dist/components/display/StatusBadge.svelte.d.ts.map +1 -1
- package/dist/components/display/__tests__/DateDisplay.test.js +82 -1
- package/dist/components/display/__tests__/Icon.test.js +132 -2
- package/dist/components/display/__tests__/StatusBadge.test.js +78 -0
- package/dist/components/display/icons.svelte.d.ts +11 -0
- package/dist/components/display/icons.svelte.d.ts.map +1 -0
- package/dist/components/display/icons.svelte.js +60 -0
- package/dist/components/display/index.d.ts +3 -1
- package/dist/components/display/index.d.ts.map +1 -1
- package/dist/components/display/index.js +1 -0
- package/dist/components/display/types.d.ts +2 -0
- package/dist/components/display/types.d.ts.map +1 -1
- package/dist/components/feedback/ConfirmDialog.svelte +59 -48
- package/dist/components/feedback/ConfirmDialog.svelte.d.ts +14 -2
- package/dist/components/feedback/ConfirmDialog.svelte.d.ts.map +1 -1
- package/dist/components/feedback/PhoneSheet.svelte +224 -0
- package/dist/components/feedback/PhoneSheet.svelte.d.ts +35 -0
- package/dist/components/feedback/PhoneSheet.svelte.d.ts.map +1 -0
- package/dist/components/feedback/ToastViewport.svelte +156 -8
- package/dist/components/feedback/ToastViewport.svelte.d.ts +5 -1
- package/dist/components/feedback/ToastViewport.svelte.d.ts.map +1 -1
- package/dist/components/feedback/WorkingStrip.svelte +426 -0
- package/dist/components/feedback/WorkingStrip.svelte.d.ts +37 -0
- package/dist/components/feedback/WorkingStrip.svelte.d.ts.map +1 -0
- package/dist/components/feedback/__tests__/ConfirmDialog.test.js +38 -20
- package/dist/components/feedback/__tests__/PhoneSheet.test.js +101 -0
- package/dist/components/feedback/__tests__/WorkingStrip.test.js +172 -0
- package/dist/components/feedback/__tests__/confirm-message.fixture.svelte +9 -0
- package/dist/components/feedback/__tests__/confirm-message.fixture.svelte.d.ts +19 -0
- package/dist/components/feedback/__tests__/confirm-message.fixture.svelte.d.ts.map +1 -0
- package/dist/components/feedback/__tests__/toast.test.js +142 -1
- package/dist/components/feedback/index.d.ts +5 -1
- package/dist/components/feedback/index.d.ts.map +1 -1
- package/dist/components/feedback/index.js +5 -0
- package/dist/components/feedback/toast.d.ts +13 -1
- package/dist/components/feedback/toast.d.ts.map +1 -1
- package/dist/components/feedback/toast.js +51 -10
- package/dist/components/feedback/working-status.d.ts +34 -0
- package/dist/components/feedback/working-status.d.ts.map +1 -0
- package/dist/components/feedback/working-status.js +5 -0
- package/dist/components/forms/CameraCapture.svelte +619 -0
- package/dist/components/forms/CameraCapture.svelte.d.ts +42 -0
- package/dist/components/forms/CameraCapture.svelte.d.ts.map +1 -0
- package/dist/components/forms/Checkbox.svelte +34 -3
- package/dist/components/forms/Checkbox.svelte.d.ts +2 -0
- package/dist/components/forms/Checkbox.svelte.d.ts.map +1 -1
- package/dist/components/forms/Combobox.svelte +108 -12
- package/dist/components/forms/Combobox.svelte.d.ts +6 -0
- package/dist/components/forms/Combobox.svelte.d.ts.map +1 -1
- package/dist/components/forms/DictationButton.svelte +128 -0
- package/dist/components/forms/DictationButton.svelte.d.ts +19 -0
- package/dist/components/forms/DictationButton.svelte.d.ts.map +1 -0
- package/dist/components/forms/DictationStatus.svelte +164 -0
- package/dist/components/forms/DictationStatus.svelte.d.ts +11 -0
- package/dist/components/forms/DictationStatus.svelte.d.ts.map +1 -0
- package/dist/components/forms/Fieldset.svelte +5 -1
- package/dist/components/forms/Fieldset.svelte.d.ts +2 -0
- package/dist/components/forms/Fieldset.svelte.d.ts.map +1 -1
- package/dist/components/forms/Form.svelte +5 -0
- package/dist/components/forms/Form.svelte.d.ts +1 -0
- package/dist/components/forms/Form.svelte.d.ts.map +1 -1
- package/dist/components/forms/FormActionBar.svelte +84 -0
- package/dist/components/forms/FormActionBar.svelte.d.ts +23 -0
- package/dist/components/forms/FormActionBar.svelte.d.ts.map +1 -0
- package/dist/components/forms/Input.svelte +17 -1
- package/dist/components/forms/Input.svelte.d.ts +2 -0
- package/dist/components/forms/Input.svelte.d.ts.map +1 -1
- package/dist/components/forms/Listbox.svelte +39 -1
- package/dist/components/forms/Listbox.svelte.d.ts.map +1 -1
- package/dist/components/forms/MultiSelect.svelte +41 -1
- package/dist/components/forms/MultiSelect.svelte.d.ts.map +1 -1
- package/dist/components/forms/Radio.svelte +16 -4
- package/dist/components/forms/RadioGroup.svelte +7 -1
- package/dist/components/forms/RadioGroup.svelte.d.ts +2 -0
- package/dist/components/forms/RadioGroup.svelte.d.ts.map +1 -1
- package/dist/components/forms/SearchInput.svelte +207 -0
- package/dist/components/forms/SearchInput.svelte.d.ts +22 -0
- package/dist/components/forms/SearchInput.svelte.d.ts.map +1 -0
- package/dist/components/forms/SegmentedControl.svelte +152 -11
- package/dist/components/forms/SegmentedControl.svelte.d.ts +4 -0
- package/dist/components/forms/SegmentedControl.svelte.d.ts.map +1 -1
- package/dist/components/forms/Select.svelte +17 -1
- package/dist/components/forms/Select.svelte.d.ts +2 -0
- package/dist/components/forms/Select.svelte.d.ts.map +1 -1
- package/dist/components/forms/SignaturePad.svelte +436 -0
- package/dist/components/forms/SignaturePad.svelte.d.ts +32 -0
- package/dist/components/forms/SignaturePad.svelte.d.ts.map +1 -0
- package/dist/components/forms/StagedControlReview.svelte +21 -12
- package/dist/components/forms/StagedControlReview.svelte.d.ts.map +1 -1
- package/dist/components/forms/Switch.svelte +18 -5
- package/dist/components/forms/Switch.svelte.d.ts +2 -0
- package/dist/components/forms/Switch.svelte.d.ts.map +1 -1
- package/dist/components/forms/TagsInput.svelte +8 -1
- package/dist/components/forms/Textarea.svelte +16 -1
- package/dist/components/forms/Textarea.svelte.d.ts +2 -0
- package/dist/components/forms/Textarea.svelte.d.ts.map +1 -1
- package/dist/components/forms/__tests__/CameraCapture.test.js +504 -0
- package/dist/components/forms/__tests__/Combobox.test.js +354 -0
- package/dist/components/forms/__tests__/ControlHitArea.test.js +73 -0
- package/dist/components/forms/__tests__/DictationButton.test.js +176 -0
- package/dist/components/forms/__tests__/Fieldset.test.js +37 -0
- package/dist/components/forms/__tests__/Form.test.js +46 -0
- package/dist/components/forms/__tests__/FormActionBar.test.js +22 -0
- package/dist/components/forms/__tests__/Listbox.test.js +303 -0
- package/dist/components/forms/__tests__/MultiSelect.test.js +281 -0
- package/dist/components/forms/__tests__/SearchInput.test.js +92 -0
- package/dist/components/forms/__tests__/SignaturePad.test.js +338 -0
- package/dist/components/forms/__tests__/StagedControlReview.test.js +37 -3
- package/dist/components/forms/__tests__/camera-capture-session.test.js +207 -0
- package/dist/components/forms/__tests__/capture-form-retry.test.js +166 -0
- package/dist/components/forms/__tests__/capture-form.fixture.svelte +38 -0
- package/dist/components/forms/__tests__/capture-form.fixture.svelte.d.ts +10 -0
- package/dist/components/forms/__tests__/capture-form.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/capture-test-env.d.ts +70 -0
- package/dist/components/forms/__tests__/capture-test-env.d.ts.map +1 -0
- package/dist/components/forms/__tests__/capture-test-env.js +122 -0
- package/dist/components/forms/__tests__/capture-touch.fixture.svelte +15 -0
- package/dist/components/forms/__tests__/capture-touch.fixture.svelte.d.ts +8 -0
- package/dist/components/forms/__tests__/capture-touch.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/combobox-form.fixture.svelte +29 -0
- package/dist/components/forms/__tests__/combobox-form.fixture.svelte.d.ts +14 -0
- package/dist/components/forms/__tests__/combobox-form.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/combobox-labels.fixture.svelte +19 -0
- package/dist/components/forms/__tests__/combobox-labels.fixture.svelte.d.ts +11 -0
- package/dist/components/forms/__tests__/combobox-labels.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/composite-registration.fixture.svelte +29 -0
- package/dist/components/forms/__tests__/composite-registration.fixture.svelte.d.ts +8 -0
- package/dist/components/forms/__tests__/composite-registration.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/control-interaction.test.js +19 -1
- package/dist/components/forms/__tests__/control-proposals.test.js +63 -0
- package/dist/components/forms/__tests__/dictation-recording.test.js +582 -0
- package/dist/components/forms/__tests__/dictation.test.js +486 -0
- package/dist/components/forms/__tests__/form-attachment.fixture.svelte +28 -0
- package/dist/components/forms/__tests__/form-attachment.fixture.svelte.d.ts +11 -0
- package/dist/components/forms/__tests__/form-attachment.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/form-retry-form.fixture.svelte +31 -0
- package/dist/components/forms/__tests__/form-retry-form.fixture.svelte.d.ts +13 -0
- package/dist/components/forms/__tests__/form-retry-form.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/form-retry-form.test.js +107 -0
- package/dist/components/forms/__tests__/hidden-controls-form-retry.test.js +69 -0
- package/dist/components/forms/__tests__/hidden-controls-form.fixture.svelte +29 -0
- package/dist/components/forms/__tests__/hidden-controls-form.fixture.svelte.d.ts +9 -0
- package/dist/components/forms/__tests__/hidden-controls-form.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/listbox-form.fixture.svelte +27 -0
- package/dist/components/forms/__tests__/listbox-form.fixture.svelte.d.ts +13 -0
- package/dist/components/forms/__tests__/listbox-form.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/long-press.test.js +175 -0
- package/dist/components/forms/__tests__/multiselect-form.fixture.svelte +27 -0
- package/dist/components/forms/__tests__/multiselect-form.fixture.svelte.d.ts +13 -0
- package/dist/components/forms/__tests__/multiselect-form.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/native-file-field.test.js +177 -0
- package/dist/components/forms/__tests__/place-picker.fixture.svelte +33 -0
- package/dist/components/forms/__tests__/place-picker.fixture.svelte.d.ts +12 -0
- package/dist/components/forms/__tests__/place-picker.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/segmented-posting.fixture.svelte +28 -0
- package/dist/components/forms/__tests__/segmented-posting.fixture.svelte.d.ts +12 -0
- package/dist/components/forms/__tests__/segmented-posting.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/segmented-posting.test.js +92 -0
- package/dist/components/forms/__tests__/signature-pad-logic.test.js +54 -0
- package/dist/components/forms/__tests__/touch-density.fixture.svelte +34 -0
- package/dist/components/forms/__tests__/touch-density.fixture.svelte.d.ts +8 -0
- package/dist/components/forms/__tests__/touch-density.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/touch-density.test.js +66 -0
- package/dist/components/forms/audio-capture.d.ts +69 -0
- package/dist/components/forms/audio-capture.d.ts.map +1 -0
- package/dist/components/forms/audio-capture.js +193 -0
- package/dist/components/forms/camera-capture-session.d.ts +81 -0
- package/dist/components/forms/camera-capture-session.d.ts.map +1 -0
- package/dist/components/forms/camera-capture-session.js +130 -0
- package/dist/components/forms/control-interaction.d.ts +6 -0
- package/dist/components/forms/control-interaction.d.ts.map +1 -1
- package/dist/components/forms/control-interaction.js +12 -1
- package/dist/components/forms/control-proposals.d.ts +55 -0
- package/dist/components/forms/control-proposals.d.ts.map +1 -0
- package/dist/components/forms/control-proposals.js +188 -0
- package/dist/components/forms/dictation-transcribe.d.ts +36 -0
- package/dist/components/forms/dictation-transcribe.d.ts.map +1 -0
- package/dist/components/forms/dictation-transcribe.js +65 -0
- package/dist/components/forms/dictation.svelte.d.ts +200 -0
- package/dist/components/forms/dictation.svelte.d.ts.map +1 -0
- package/dist/components/forms/dictation.svelte.js +686 -0
- package/dist/components/forms/form-retry/__tests__/boundaries.test.js +23 -0
- package/dist/components/forms/form-retry/__tests__/content-digest.test.js +70 -0
- package/dist/components/forms/form-retry/__tests__/controller.test.js +802 -0
- package/dist/components/forms/form-retry/__tests__/fake-kit.d.ts +82 -0
- package/dist/components/forms/form-retry/__tests__/fake-kit.d.ts.map +1 -0
- package/dist/components/forms/form-retry/__tests__/fake-kit.js +180 -0
- package/dist/components/forms/form-retry/__tests__/form-draft.test.js +169 -0
- package/dist/components/forms/form-retry/__tests__/ssr.test.js +37 -0
- package/dist/components/forms/form-retry/__tests__/storage.d.ts +26 -0
- package/dist/components/forms/form-retry/__tests__/storage.d.ts.map +1 -0
- package/dist/components/forms/form-retry/__tests__/storage.js +63 -0
- package/dist/components/forms/form-retry/__tests__/submission-key.test.js +236 -0
- package/dist/components/forms/form-retry/__tests__/submitted-draft.test.js +334 -0
- package/dist/components/forms/form-retry/content-digest.d.ts +54 -0
- package/dist/components/forms/form-retry/content-digest.d.ts.map +1 -0
- package/dist/components/forms/form-retry/content-digest.js +169 -0
- package/dist/components/forms/form-retry/controller.d.ts +214 -0
- package/dist/components/forms/form-retry/controller.d.ts.map +1 -0
- package/dist/components/forms/form-retry/controller.js +404 -0
- package/dist/components/forms/form-retry/form-draft.d.ts +68 -0
- package/dist/components/forms/form-retry/form-draft.d.ts.map +1 -0
- package/dist/components/forms/form-retry/form-draft.js +161 -0
- package/dist/components/forms/form-retry/index.d.ts +19 -0
- package/dist/components/forms/form-retry/index.d.ts.map +1 -0
- package/dist/components/forms/form-retry/index.js +16 -0
- package/dist/components/forms/form-retry/submission-key.d.ts +244 -0
- package/dist/components/forms/form-retry/submission-key.d.ts.map +1 -0
- package/dist/components/forms/form-retry/submission-key.js +342 -0
- package/dist/components/forms/form-retry/submitted-draft.d.ts +112 -0
- package/dist/components/forms/form-retry/submitted-draft.d.ts.map +1 -0
- package/dist/components/forms/form-retry/submitted-draft.js +270 -0
- package/dist/components/forms/form-retry/types.d.ts +84 -0
- package/dist/components/forms/form-retry/types.d.ts.map +1 -0
- package/dist/components/forms/form-retry/types.js +13 -0
- package/dist/components/forms/index.d.ts +21 -2
- package/dist/components/forms/index.d.ts.map +1 -1
- package/dist/components/forms/index.js +22 -1
- package/dist/components/forms/insert-text.d.ts +12 -0
- package/dist/components/forms/insert-text.d.ts.map +1 -0
- package/dist/components/forms/insert-text.js +38 -0
- package/dist/components/forms/long-press.d.ts +88 -0
- package/dist/components/forms/long-press.d.ts.map +1 -0
- package/dist/components/forms/long-press.js +213 -0
- package/dist/components/forms/native-file-field.d.ts +94 -0
- package/dist/components/forms/native-file-field.d.ts.map +1 -0
- package/dist/components/forms/native-file-field.js +147 -0
- package/dist/components/forms/ready-beep.d.ts +24 -0
- package/dist/components/forms/ready-beep.d.ts.map +1 -0
- package/dist/components/forms/ready-beep.js +82 -0
- package/dist/components/forms/signature-pad-logic.d.ts +50 -0
- package/dist/components/forms/signature-pad-logic.d.ts.map +1 -0
- package/dist/components/forms/signature-pad-logic.js +48 -0
- package/dist/components/forms/types.d.ts +41 -0
- package/dist/components/forms/types.d.ts.map +1 -1
- package/dist/components/layout/PageHeader.svelte +151 -17
- package/dist/components/layout/PageHeader.svelte.d.ts +47 -7
- package/dist/components/layout/PageHeader.svelte.d.ts.map +1 -1
- package/dist/components/layout/__tests__/PageHeader.test.js +87 -1
- package/dist/components/layout/index.d.ts +1 -0
- package/dist/components/layout/index.d.ts.map +1 -1
- package/dist/components/layout/index.js +1 -0
- package/dist/components/layout/page-header-context.d.ts +25 -0
- package/dist/components/layout/page-header-context.d.ts.map +1 -0
- package/dist/components/layout/page-header-context.js +16 -0
- package/dist/components/nav/FilterChips.svelte +8 -1
- package/dist/components/nav/FilterChips.svelte.d.ts +2 -0
- package/dist/components/nav/FilterChips.svelte.d.ts.map +1 -1
- package/dist/components/nav/Tabs.svelte +241 -0
- package/dist/components/nav/Tabs.svelte.d.ts +15 -0
- package/dist/components/nav/Tabs.svelte.d.ts.map +1 -1
- package/dist/components/nav/__tests__/LinkTabs.test.js +117 -0
- package/dist/components/nav/index.d.ts +1 -0
- package/dist/components/nav/index.d.ts.map +1 -1
- package/dist/components/nav/index.js +1 -0
- package/dist/components/nav/tabs-overflow.d.ts +12 -0
- package/dist/components/nav/tabs-overflow.d.ts.map +1 -0
- package/dist/components/nav/tabs-overflow.js +17 -0
- package/dist/components/nav/types.d.ts +8 -0
- package/dist/components/nav/types.d.ts.map +1 -1
- package/dist/components/ui/Button.svelte +16 -2
- package/dist/components/ui/Button.svelte.d.ts +2 -0
- package/dist/components/ui/Button.svelte.d.ts.map +1 -1
- package/dist/components/ui/Card.svelte +14 -5
- package/dist/components/ui/Dropdown.svelte +55 -1
- package/dist/components/ui/Dropdown.svelte.d.ts +8 -0
- package/dist/components/ui/Dropdown.svelte.d.ts.map +1 -1
- package/dist/components/ui/IconToggle.svelte +139 -0
- package/dist/components/ui/IconToggle.svelte.d.ts +32 -0
- package/dist/components/ui/IconToggle.svelte.d.ts.map +1 -0
- package/dist/components/ui/IconToggleGroup.svelte +56 -0
- package/dist/components/ui/IconToggleGroup.svelte.d.ts +21 -0
- package/dist/components/ui/IconToggleGroup.svelte.d.ts.map +1 -0
- package/dist/components/ui/Pagination.svelte +1 -1
- package/dist/components/ui/Popover.svelte +17 -1
- package/dist/components/ui/Popover.svelte.d.ts +8 -0
- package/dist/components/ui/Popover.svelte.d.ts.map +1 -1
- package/dist/components/ui/__tests__/IconToggle.test.js +59 -0
- package/dist/components/ui/__tests__/IconToggleGroup.test.js +30 -0
- package/dist/components/ui/__tests__/Popover.test.js +44 -0
- package/dist/components/ui/__tests__/dropdown-popover-icon.test.js +125 -0
- package/dist/components/ui/__tests__/phone-touch-targets.test.js +39 -0
- package/dist/components/ui/index.d.ts +2 -0
- package/dist/components/ui/index.d.ts.map +1 -1
- package/dist/components/ui/index.js +2 -0
- package/dist/i18n/strings.ui.d.ts +65 -0
- package/dist/i18n/strings.ui.d.ts.map +1 -1
- package/dist/i18n/strings.ui.js +72 -0
- package/dist/styles/tokens.css +2 -0
- package/dist/svelte/__tests__/playground.test.js +3 -1
- package/dist/svelte/playground/CalendarPreview.svelte +140 -0
- package/dist/svelte/playground/CalendarPreview.svelte.d.ts +4 -0
- package/dist/svelte/playground/CalendarPreview.svelte.d.ts.map +1 -0
- package/dist/svelte/playground/CapturePreview.svelte +56 -0
- package/dist/svelte/playground/CapturePreview.svelte.d.ts +4 -0
- package/dist/svelte/playground/CapturePreview.svelte.d.ts.map +1 -0
- package/dist/svelte/playground.d.ts.map +1 -1
- package/dist/svelte/playground.js +20 -0
- package/dist/themes/ThemeProvider.svelte +9 -0
- package/dist/themes/ThemeProvider.svelte.d.ts +2 -0
- package/dist/themes/ThemeProvider.svelte.d.ts.map +1 -1
- package/dist/themes/css-generator.d.ts.map +1 -1
- package/dist/themes/css-generator.js +3 -0
- package/dist/themes/styles/glass.css +4 -0
- package/dist/themes/styles/happyvertical.css +4 -0
- package/dist/themes/styles/material.css +4 -0
- package/dist/themes/styles/smrt.css +4 -0
- package/dist/themes/styles/studio.css +4 -0
- package/dist/types-generic.d.ts +2 -0
- package/dist/types-generic.d.ts.map +1 -1
- package/package.json +9 -3
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
ListSortSelect — a "Sort by" picker for lists without column headers
|
|
3
|
+
(card lists, and tables that turn into cards on phones).
|
|
4
|
+
|
|
5
|
+
One option per column and direction, in plain words: dates read
|
|
6
|
+
"newest first / oldest first", numbers "highest first / lowest first",
|
|
7
|
+
text "A–Z / Z–A". Calls `onChange` with the chosen sort; server-sorted lists
|
|
8
|
+
navigate to `listSortHref(...)` there.
|
|
9
|
+
-->
|
|
10
|
+
<script lang="ts">
|
|
11
|
+
import type {
|
|
12
|
+
ListSort,
|
|
13
|
+
ListSortDirection,
|
|
14
|
+
ListSortSelectColumn,
|
|
15
|
+
} from './list-sort.js';
|
|
16
|
+
import type { ListSortState } from './list-sort-state.svelte.js';
|
|
17
|
+
|
|
18
|
+
interface Props {
|
|
19
|
+
/** Sortable columns; each gives two options, one per direction. */
|
|
20
|
+
columns: readonly ListSortSelectColumn[];
|
|
21
|
+
/** The list's sort state; supplies `sort` and `onChange`. */
|
|
22
|
+
list?: ListSortState;
|
|
23
|
+
/** Current sort of the list, when `list` is not given. */
|
|
24
|
+
sort?: ListSort;
|
|
25
|
+
/** Called with the chosen sort, when `list` is not given. */
|
|
26
|
+
onChange?: (sort: ListSort) => void;
|
|
27
|
+
/** Visible label for the picker (default "Sort by"). */
|
|
28
|
+
label?: string;
|
|
29
|
+
/** Id of the select element, tying the label to it. */
|
|
30
|
+
id?: string;
|
|
31
|
+
/** Extra class names. */
|
|
32
|
+
class?: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
let {
|
|
36
|
+
columns,
|
|
37
|
+
list,
|
|
38
|
+
sort: sortProp,
|
|
39
|
+
onChange: onChangeProp,
|
|
40
|
+
label = 'Sort by',
|
|
41
|
+
id = `list-sort-${Math.random().toString(36).slice(2, 9)}`,
|
|
42
|
+
class: className = '',
|
|
43
|
+
}: Props = $props();
|
|
44
|
+
|
|
45
|
+
function directionWords(
|
|
46
|
+
kind: ListSortSelectColumn['kind'],
|
|
47
|
+
direction: ListSortDirection,
|
|
48
|
+
): string {
|
|
49
|
+
if (kind === 'date')
|
|
50
|
+
return direction === 'desc' ? 'newest first' : 'oldest first';
|
|
51
|
+
if (kind === 'number')
|
|
52
|
+
return direction === 'desc' ? 'highest first' : 'lowest first';
|
|
53
|
+
return direction === 'asc' ? 'A–Z' : 'Z–A';
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const sort = $derived<ListSort>(
|
|
57
|
+
list?.sort ??
|
|
58
|
+
sortProp ?? { columnId: columns[0]?.id ?? '', direction: 'desc' },
|
|
59
|
+
);
|
|
60
|
+
const onChange = (next: ListSort) => {
|
|
61
|
+
if (list) void list.set(next);
|
|
62
|
+
else onChangeProp?.(next);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const options = $derived(
|
|
66
|
+
columns.flatMap((column) => {
|
|
67
|
+
const order: ListSortDirection[] =
|
|
68
|
+
column.kind === 'date' || column.kind === 'number'
|
|
69
|
+
? ['desc', 'asc']
|
|
70
|
+
: ['asc', 'desc'];
|
|
71
|
+
return order.map((direction) => ({
|
|
72
|
+
value: `${column.id}:${direction}`,
|
|
73
|
+
label: `${column.label}, ${directionWords(column.kind, direction)}`,
|
|
74
|
+
}));
|
|
75
|
+
}),
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
function handleChange(event: Event) {
|
|
79
|
+
const value = (event.currentTarget as HTMLSelectElement).value;
|
|
80
|
+
const separator = value.lastIndexOf(':');
|
|
81
|
+
const direction = value.slice(separator + 1);
|
|
82
|
+
if (direction !== 'asc' && direction !== 'desc') return;
|
|
83
|
+
onChange({ columnId: value.slice(0, separator), direction });
|
|
84
|
+
}
|
|
85
|
+
</script>
|
|
86
|
+
|
|
87
|
+
<div class={`list-sort-select ${className}`}>
|
|
88
|
+
<label class="list-sort-select__label" for={id}>{label}</label>
|
|
89
|
+
<select
|
|
90
|
+
{id}
|
|
91
|
+
class="list-sort-select__control"
|
|
92
|
+
value={`${sort.columnId}:${sort.direction}`}
|
|
93
|
+
onchange={handleChange}
|
|
94
|
+
>
|
|
95
|
+
{#each options as option (option.value)}
|
|
96
|
+
<option value={option.value}>{option.label}</option>
|
|
97
|
+
{/each}
|
|
98
|
+
</select>
|
|
99
|
+
</div>
|
|
100
|
+
|
|
101
|
+
<style>
|
|
102
|
+
.list-sort-select {
|
|
103
|
+
display: inline-flex;
|
|
104
|
+
align-items: center;
|
|
105
|
+
gap: 0.5rem;
|
|
106
|
+
}
|
|
107
|
+
.list-sort-select__label {
|
|
108
|
+
font-size: 0.875rem;
|
|
109
|
+
color: var(--color-text-secondary, inherit);
|
|
110
|
+
white-space: nowrap;
|
|
111
|
+
}
|
|
112
|
+
.list-sort-select__control {
|
|
113
|
+
min-height: 2.75rem;
|
|
114
|
+
padding: 0.25rem 0.5rem;
|
|
115
|
+
border: 1px solid var(--color-border, currentColor);
|
|
116
|
+
border-radius: var(--radius-md, 0.375rem);
|
|
117
|
+
background: var(--color-surface, transparent);
|
|
118
|
+
color: inherit;
|
|
119
|
+
font: inherit;
|
|
120
|
+
}
|
|
121
|
+
</style>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ListSort, ListSortSelectColumn } from './list-sort.js';
|
|
2
|
+
import type { ListSortState } from './list-sort-state.svelte.js';
|
|
3
|
+
interface Props {
|
|
4
|
+
/** Sortable columns; each gives two options, one per direction. */
|
|
5
|
+
columns: readonly ListSortSelectColumn[];
|
|
6
|
+
/** The list's sort state; supplies `sort` and `onChange`. */
|
|
7
|
+
list?: ListSortState;
|
|
8
|
+
/** Current sort of the list, when `list` is not given. */
|
|
9
|
+
sort?: ListSort;
|
|
10
|
+
/** Called with the chosen sort, when `list` is not given. */
|
|
11
|
+
onChange?: (sort: ListSort) => void;
|
|
12
|
+
/** Visible label for the picker (default "Sort by"). */
|
|
13
|
+
label?: string;
|
|
14
|
+
/** Id of the select element, tying the label to it. */
|
|
15
|
+
id?: string;
|
|
16
|
+
/** Extra class names. */
|
|
17
|
+
class?: string;
|
|
18
|
+
}
|
|
19
|
+
declare const ListSortSelect: import("svelte").Component<Props, {}, "">;
|
|
20
|
+
type ListSortSelect = ReturnType<typeof ListSortSelect>;
|
|
21
|
+
export default ListSortSelect;
|
|
22
|
+
//# sourceMappingURL=ListSortSelect.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ListSortSelect.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/data/ListSortSelect.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,QAAQ,EAER,oBAAoB,EACrB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAGjE,UAAU,KAAK;IACb,mEAAmE;IACnE,OAAO,EAAE,SAAS,oBAAoB,EAAE,CAAC;IACzC,6DAA6D;IAC7D,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,0DAA0D;IAC1D,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,IAAI,CAAC;IACpC,wDAAwD;IACxD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uDAAuD;IACvD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,yBAAyB;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAwED,QAAA,MAAM,cAAc,2CAAwC,CAAC;AAC7D,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AACxD,eAAe,cAAc,CAAC"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
SortableHeader — a sortable column header for a hand-rolled table.
|
|
3
|
+
|
|
4
|
+
Renders the `<th>` itself so `aria-sort` sits on the column header. The
|
|
5
|
+
control inside is a link when `href` is given (server-sorted lists keep the
|
|
6
|
+
sort in the URL; build it with `listSortHref`) or a button calling `onSort`
|
|
7
|
+
(client-sorted lists; compute the next sort with `toggleListSort`) — or
|
|
8
|
+
pass a list's state (`createUrlListSort` / `createLocalListSort`) as `list`
|
|
9
|
+
and it supplies all three. Both are
|
|
10
|
+
reachable by Tab and activated with Enter (a button also with Space). The
|
|
11
|
+
indicator shows ↑/↓ on the sorted column and a faint ↕ on the others.
|
|
12
|
+
|
|
13
|
+
Use `as="div"` with `role="columnheader"` semantics for grid layouts that
|
|
14
|
+
are not a `<table>`.
|
|
15
|
+
|
|
16
|
+
Style hooks (set on the header or an ancestor): `--sortable-header-padding`
|
|
17
|
+
(the control's padding) and `--sortable-header-font-weight` (default 600;
|
|
18
|
+
`inherit` takes the surrounding head row's weight).
|
|
19
|
+
-->
|
|
20
|
+
<script lang="ts">
|
|
21
|
+
import type { Snippet } from 'svelte';
|
|
22
|
+
import {
|
|
23
|
+
type ListSort,
|
|
24
|
+
type ListSortSpec,
|
|
25
|
+
listSortActionLabel,
|
|
26
|
+
listSortAria,
|
|
27
|
+
} from './list-sort.js';
|
|
28
|
+
import type { ListSortState } from './list-sort-state.svelte.js';
|
|
29
|
+
|
|
30
|
+
interface Props {
|
|
31
|
+
/** Id of the column this header sorts by. */
|
|
32
|
+
columnId: string;
|
|
33
|
+
/** Column name shown in the header and used in the sort announcement. */
|
|
34
|
+
label: string;
|
|
35
|
+
/** The list's sort state; supplies `sort`, `spec`, `href`, and `onSort`. */
|
|
36
|
+
list?: ListSortState;
|
|
37
|
+
/** Current sort of the list. */
|
|
38
|
+
sort?: ListSort | null;
|
|
39
|
+
/** Link to the list sorted by this column (server-sorted lists). */
|
|
40
|
+
href?: string;
|
|
41
|
+
/** Called on activation (client-sorted lists). */
|
|
42
|
+
onSort?: (columnId: string) => void;
|
|
43
|
+
/** The list's sort spec; gives the column's first direction for the label. */
|
|
44
|
+
spec?: ListSortSpec;
|
|
45
|
+
/** Render a table `th` (default) or a `div` column header for grid layouts. */
|
|
46
|
+
as?: 'th' | 'div';
|
|
47
|
+
/** Horizontal alignment of the header content. */
|
|
48
|
+
align?: 'start' | 'center' | 'end';
|
|
49
|
+
/** Extra class names. */
|
|
50
|
+
class?: string;
|
|
51
|
+
children?: Snippet;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
let {
|
|
55
|
+
columnId,
|
|
56
|
+
label,
|
|
57
|
+
list,
|
|
58
|
+
sort: sortProp,
|
|
59
|
+
href: hrefProp,
|
|
60
|
+
onSort: onSortProp,
|
|
61
|
+
spec: specProp,
|
|
62
|
+
as = 'th',
|
|
63
|
+
align = 'start',
|
|
64
|
+
class: className = '',
|
|
65
|
+
children,
|
|
66
|
+
}: Props = $props();
|
|
67
|
+
|
|
68
|
+
const sort = $derived(list ? list.sort : sortProp);
|
|
69
|
+
const spec = $derived(list ? list.spec : specProp);
|
|
70
|
+
const href = $derived(list ? list.href(columnId) : hrefProp);
|
|
71
|
+
const onSort = $derived(
|
|
72
|
+
list ? (id: string) => void list.toggle(id) : onSortProp,
|
|
73
|
+
);
|
|
74
|
+
const aria = $derived(listSortAria(sort, columnId));
|
|
75
|
+
const active = $derived(aria !== 'none');
|
|
76
|
+
const actionLabel = $derived(listSortActionLabel(sort, columnId, label, spec));
|
|
77
|
+
</script>
|
|
78
|
+
|
|
79
|
+
{#snippet content()}
|
|
80
|
+
<span class="sortable-header__label">
|
|
81
|
+
{#if children}{@render children()}{:else}{label}{/if}
|
|
82
|
+
</span>
|
|
83
|
+
<span class="sortable-header__icon" class:is-active={active} aria-hidden="true">
|
|
84
|
+
{#if aria === 'ascending'}↑{:else if aria === 'descending'}↓{:else}↕{/if}
|
|
85
|
+
</span>
|
|
86
|
+
{/snippet}
|
|
87
|
+
|
|
88
|
+
<svelte:element
|
|
89
|
+
this={as}
|
|
90
|
+
class={`sortable-header sortable-header--${align} ${className}`}
|
|
91
|
+
class:is-sorted={active}
|
|
92
|
+
scope={as === 'th' ? 'col' : undefined}
|
|
93
|
+
role={as === 'div' ? 'columnheader' : undefined}
|
|
94
|
+
aria-sort={aria}
|
|
95
|
+
data-sort-column={columnId}
|
|
96
|
+
>
|
|
97
|
+
{#if href}
|
|
98
|
+
<a
|
|
99
|
+
class="sortable-header__control"
|
|
100
|
+
{href}
|
|
101
|
+
aria-label={actionLabel}
|
|
102
|
+
data-sveltekit-noscroll
|
|
103
|
+
data-sveltekit-keepfocus
|
|
104
|
+
data-sveltekit-replacestate
|
|
105
|
+
onclick={() => onSort?.(columnId)}
|
|
106
|
+
>
|
|
107
|
+
{@render content()}
|
|
108
|
+
</a>
|
|
109
|
+
{:else}
|
|
110
|
+
<button
|
|
111
|
+
type="button"
|
|
112
|
+
class="sortable-header__control"
|
|
113
|
+
aria-label={actionLabel}
|
|
114
|
+
onclick={() => onSort?.(columnId)}
|
|
115
|
+
>
|
|
116
|
+
{@render content()}
|
|
117
|
+
</button>
|
|
118
|
+
{/if}
|
|
119
|
+
</svelte:element>
|
|
120
|
+
|
|
121
|
+
<style>
|
|
122
|
+
.sortable-header {
|
|
123
|
+
padding: 0;
|
|
124
|
+
font-weight: inherit;
|
|
125
|
+
text-align: start;
|
|
126
|
+
}
|
|
127
|
+
.sortable-header--center {
|
|
128
|
+
text-align: center;
|
|
129
|
+
}
|
|
130
|
+
.sortable-header--end {
|
|
131
|
+
text-align: end;
|
|
132
|
+
}
|
|
133
|
+
.sortable-header__control {
|
|
134
|
+
display: inline-flex;
|
|
135
|
+
align-items: center;
|
|
136
|
+
gap: 0.25rem;
|
|
137
|
+
min-height: 2.75rem;
|
|
138
|
+
width: 100%;
|
|
139
|
+
padding: var(--sortable-header-padding, 0.5rem 0.75rem);
|
|
140
|
+
border: 0;
|
|
141
|
+
background: transparent;
|
|
142
|
+
color: inherit;
|
|
143
|
+
font: inherit;
|
|
144
|
+
font-weight: var(--sortable-header-font-weight, 600);
|
|
145
|
+
text-align: inherit;
|
|
146
|
+
text-decoration: none;
|
|
147
|
+
cursor: pointer;
|
|
148
|
+
}
|
|
149
|
+
.sortable-header--center .sortable-header__control {
|
|
150
|
+
justify-content: center;
|
|
151
|
+
}
|
|
152
|
+
.sortable-header--end .sortable-header__control {
|
|
153
|
+
justify-content: flex-end;
|
|
154
|
+
}
|
|
155
|
+
.sortable-header__control:hover .sortable-header__label {
|
|
156
|
+
text-decoration: underline;
|
|
157
|
+
}
|
|
158
|
+
.sortable-header__control:focus-visible {
|
|
159
|
+
outline: 2px solid var(--color-focus, var(--color-primary, currentColor));
|
|
160
|
+
outline-offset: -2px;
|
|
161
|
+
}
|
|
162
|
+
.sortable-header__icon {
|
|
163
|
+
opacity: 0.35;
|
|
164
|
+
font-size: 0.85em;
|
|
165
|
+
}
|
|
166
|
+
.sortable-header__icon.is-active {
|
|
167
|
+
opacity: 1;
|
|
168
|
+
}
|
|
169
|
+
</style>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import { type ListSort, type ListSortSpec } from './list-sort.js';
|
|
3
|
+
import type { ListSortState } from './list-sort-state.svelte.js';
|
|
4
|
+
interface Props {
|
|
5
|
+
/** Id of the column this header sorts by. */
|
|
6
|
+
columnId: string;
|
|
7
|
+
/** Column name shown in the header and used in the sort announcement. */
|
|
8
|
+
label: string;
|
|
9
|
+
/** The list's sort state; supplies `sort`, `spec`, `href`, and `onSort`. */
|
|
10
|
+
list?: ListSortState;
|
|
11
|
+
/** Current sort of the list. */
|
|
12
|
+
sort?: ListSort | null;
|
|
13
|
+
/** Link to the list sorted by this column (server-sorted lists). */
|
|
14
|
+
href?: string;
|
|
15
|
+
/** Called on activation (client-sorted lists). */
|
|
16
|
+
onSort?: (columnId: string) => void;
|
|
17
|
+
/** The list's sort spec; gives the column's first direction for the label. */
|
|
18
|
+
spec?: ListSortSpec;
|
|
19
|
+
/** Render a table `th` (default) or a `div` column header for grid layouts. */
|
|
20
|
+
as?: 'th' | 'div';
|
|
21
|
+
/** Horizontal alignment of the header content. */
|
|
22
|
+
align?: 'start' | 'center' | 'end';
|
|
23
|
+
/** Extra class names. */
|
|
24
|
+
class?: string;
|
|
25
|
+
children?: Snippet;
|
|
26
|
+
}
|
|
27
|
+
declare const SortableHeader: import("svelte").Component<Props, {}, "">;
|
|
28
|
+
type SortableHeader = ReturnType<typeof SortableHeader>;
|
|
29
|
+
export default SortableHeader;
|
|
30
|
+
//# sourceMappingURL=SortableHeader.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SortableHeader.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/data/SortableHeader.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EACL,KAAK,QAAQ,EACb,KAAK,YAAY,EAGlB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAGjE,UAAU,KAAK;IACb,6CAA6C;IAC7C,QAAQ,EAAE,MAAM,CAAC;IACjB,yEAAyE;IACzE,KAAK,EAAE,MAAM,CAAC;IACd,4EAA4E;IAC5E,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,gCAAgC;IAChC,IAAI,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;IACvB,oEAAoE;IACpE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kDAAkD;IAClD,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,8EAA8E;IAC9E,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,+EAA+E;IAC/E,EAAE,CAAC,EAAE,IAAI,GAAG,KAAK,CAAC;IAClB,kDAAkD;IAClD,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;IACnC,yBAAyB;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AA0DD,QAAA,MAAM,cAAc,2CAAwC,CAAC;AAC7D,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AACxD,eAAe,cAAc,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { render, screen } from '@testing-library/svelte';
|
|
2
|
+
import userEvent from '@testing-library/user-event';
|
|
3
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
4
|
+
import CollectionList from '../CollectionList.svelte';
|
|
5
|
+
const items = [
|
|
6
|
+
{ id: 'a', title: 'First' },
|
|
7
|
+
{ id: 'b', title: 'Second' },
|
|
8
|
+
];
|
|
9
|
+
describe('CollectionList', () => {
|
|
10
|
+
it.each([
|
|
11
|
+
'list',
|
|
12
|
+
'divided',
|
|
13
|
+
'grid',
|
|
14
|
+
'gallery',
|
|
15
|
+
])('renders the %s layout', (layout) => {
|
|
16
|
+
const { container } = render(CollectionList, {
|
|
17
|
+
props: { items, itemKey: 'id', title: 'title', layout },
|
|
18
|
+
});
|
|
19
|
+
expect(container.querySelector(`ul.collection--${layout}`)).not.toBeNull();
|
|
20
|
+
expect(screen.getByText('First')).toBeInTheDocument();
|
|
21
|
+
});
|
|
22
|
+
it('selects an item with its labelled checkbox', async () => {
|
|
23
|
+
const onselectionchange = vi.fn();
|
|
24
|
+
render(CollectionList, {
|
|
25
|
+
props: {
|
|
26
|
+
items,
|
|
27
|
+
itemKey: 'id',
|
|
28
|
+
title: 'title',
|
|
29
|
+
layout: 'gallery',
|
|
30
|
+
selectable: true,
|
|
31
|
+
onselectionchange,
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
await userEvent.click(screen.getByRole('checkbox', { name: 'Select Second' }));
|
|
35
|
+
expect(onselectionchange).toHaveBeenCalledWith(new Set(['b']));
|
|
36
|
+
});
|
|
37
|
+
});
|
|
@@ -53,6 +53,35 @@ describe('DataTable', () => {
|
|
|
53
53
|
await userEvent.click(screen.getByRole('button', { name: 'Clear sorting for Name' }));
|
|
54
54
|
expect(nameHeader).not.toHaveAttribute('aria-sort');
|
|
55
55
|
});
|
|
56
|
+
it('starts a date/count column descending and toggles without clearing when not clearable', async () => {
|
|
57
|
+
render(DataTable, {
|
|
58
|
+
props: {
|
|
59
|
+
data,
|
|
60
|
+
columns: [
|
|
61
|
+
columns[0],
|
|
62
|
+
{
|
|
63
|
+
id: 'age',
|
|
64
|
+
label: 'Age',
|
|
65
|
+
accessor: 'age',
|
|
66
|
+
sortable: true,
|
|
67
|
+
sortFirstDirection: 'desc',
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
sortable: true,
|
|
71
|
+
sortClearable: false,
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
const ageHeader = screen.getByRole('columnheader', { name: 'Age' });
|
|
75
|
+
await userEvent.click(screen.getByRole('button', { name: 'Sort Age descending' }));
|
|
76
|
+
expect(ageHeader).toHaveAttribute('aria-sort', 'descending');
|
|
77
|
+
const firstCell = () => screen.getAllByRole('row')[1]?.textContent ?? '';
|
|
78
|
+
expect(firstCell()).toContain('Linus');
|
|
79
|
+
await userEvent.click(screen.getByRole('button', { name: 'Sort Age ascending' }));
|
|
80
|
+
expect(ageHeader).toHaveAttribute('aria-sort', 'ascending');
|
|
81
|
+
expect(firstCell()).toContain('Ada');
|
|
82
|
+
await userEvent.click(screen.getByRole('button', { name: 'Sort Age descending' }));
|
|
83
|
+
expect(ageHeader).toHaveAttribute('aria-sort', 'descending');
|
|
84
|
+
});
|
|
56
85
|
it('announces the next action for each rule in a multi-column sort', async () => {
|
|
57
86
|
const multiSortColumns = [columns[0], { ...columns[1], sortable: true }];
|
|
58
87
|
render(DataTable, {
|
|
@@ -729,3 +758,50 @@ describe('DataTable', () => {
|
|
|
729
758
|
await expectNoA11yViolations(container);
|
|
730
759
|
});
|
|
731
760
|
});
|
|
761
|
+
describe('DataTable phoneLayout', () => {
|
|
762
|
+
it('keeps the scrolling table unless asked for cards', () => {
|
|
763
|
+
const { container } = render(DataTable, {
|
|
764
|
+
props: { data, columns, caption: 'People' },
|
|
765
|
+
});
|
|
766
|
+
expect(container.querySelector('.data-table-container--phone-cards')).toBeNull();
|
|
767
|
+
});
|
|
768
|
+
it('marks the container for the phone card layout and keeps the table semantics', () => {
|
|
769
|
+
const { container } = render(DataTable, {
|
|
770
|
+
props: { data, columns, caption: 'People', phoneLayout: 'cards' },
|
|
771
|
+
});
|
|
772
|
+
expect(container.querySelector('.data-table-container.data-table-container--phone-cards')).not.toBeNull();
|
|
773
|
+
expect(screen.getByRole('table', { name: 'People' })).toBeInTheDocument();
|
|
774
|
+
expect(screen.getAllByRole('row')).toHaveLength(3);
|
|
775
|
+
});
|
|
776
|
+
it('gives cards explicit table roles and a visible column label per cell', async () => {
|
|
777
|
+
const { container } = render(DataTable, {
|
|
778
|
+
props: { data, columns, caption: 'People', phoneLayout: 'cards' },
|
|
779
|
+
});
|
|
780
|
+
// Explicit roles survive the block/grid restyle (WebKit drops implicit
|
|
781
|
+
// table roles once display changes).
|
|
782
|
+
expect(container.querySelector('table')).toHaveAttribute('role', 'table');
|
|
783
|
+
for (const row of container.querySelectorAll('tr')) {
|
|
784
|
+
expect(row).toHaveAttribute('role', 'row');
|
|
785
|
+
}
|
|
786
|
+
for (const header of container.querySelectorAll('thead th')) {
|
|
787
|
+
expect(header).toHaveAttribute('role', 'columnheader');
|
|
788
|
+
}
|
|
789
|
+
const cells = container.querySelectorAll('tbody td[data-column-id]');
|
|
790
|
+
expect(cells.length).toBeGreaterThan(0);
|
|
791
|
+
for (const cell of cells) {
|
|
792
|
+
expect(cell).toHaveAttribute('role', 'cell');
|
|
793
|
+
const column = columns.find((candidate) => candidate.id === cell.getAttribute('data-column-id'));
|
|
794
|
+
expect(cell).toHaveAttribute('data-label', column?.label);
|
|
795
|
+
}
|
|
796
|
+
// The header stays in the accessibility tree (visually hidden, not removed).
|
|
797
|
+
expect(screen.getAllByRole('columnheader').length).toBe(columns.length);
|
|
798
|
+
await expectNoA11yViolations(container);
|
|
799
|
+
});
|
|
800
|
+
it('adds no explicit roles or labels outside cards mode', () => {
|
|
801
|
+
const { container } = render(DataTable, {
|
|
802
|
+
props: { data, columns, caption: 'People' },
|
|
803
|
+
});
|
|
804
|
+
expect(container.querySelector('table')).not.toHaveAttribute('role');
|
|
805
|
+
expect(container.querySelector('[data-label]')).toBeNull();
|
|
806
|
+
});
|
|
807
|
+
});
|
|
@@ -118,6 +118,41 @@ describe('DataTableController', () => {
|
|
|
118
118
|
{ columnId: 'age', direction: 'asc' },
|
|
119
119
|
]);
|
|
120
120
|
});
|
|
121
|
+
it('starts a column at its first direction and toggles without clearing when not clearable', () => {
|
|
122
|
+
const controller = createDataTableController({ initialState: state });
|
|
123
|
+
const toggle = () => controller.dispatch({
|
|
124
|
+
type: 'toggleSorting',
|
|
125
|
+
columnId: 'age',
|
|
126
|
+
firstDirection: 'desc',
|
|
127
|
+
clearable: false,
|
|
128
|
+
});
|
|
129
|
+
toggle();
|
|
130
|
+
expect(controller.snapshot().state.sorting).toEqual([
|
|
131
|
+
{ columnId: 'age', direction: 'desc' },
|
|
132
|
+
]);
|
|
133
|
+
toggle();
|
|
134
|
+
expect(controller.snapshot().state.sorting).toEqual([
|
|
135
|
+
{ columnId: 'age', direction: 'asc' },
|
|
136
|
+
]);
|
|
137
|
+
toggle();
|
|
138
|
+
expect(controller.snapshot().state.sorting).toEqual([
|
|
139
|
+
{ columnId: 'age', direction: 'desc' },
|
|
140
|
+
]);
|
|
141
|
+
// Clearable (default) with a desc-first column: desc -> asc -> cleared.
|
|
142
|
+
const cycling = createDataTableController({ initialState: state });
|
|
143
|
+
const cycle = () => cycling.dispatch({
|
|
144
|
+
type: 'toggleSorting',
|
|
145
|
+
columnId: 'age',
|
|
146
|
+
firstDirection: 'desc',
|
|
147
|
+
});
|
|
148
|
+
cycle();
|
|
149
|
+
cycle();
|
|
150
|
+
expect(cycling.snapshot().state.sorting).toEqual([
|
|
151
|
+
{ columnId: 'age', direction: 'asc' },
|
|
152
|
+
]);
|
|
153
|
+
cycle();
|
|
154
|
+
expect(cycling.snapshot().state.sorting).toEqual([]);
|
|
155
|
+
});
|
|
121
156
|
it('proposes controlled transitions without mutating until the host reconciles state', () => {
|
|
122
157
|
const onStateChange = vi.fn();
|
|
123
158
|
const controller = createDataTableController({ state, onStateChange });
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { render, screen, waitFor } from '@testing-library/svelte';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import DataTable from '../DataTable.svelte';
|
|
4
|
+
import { createDataTableController } from '../DataTableController.js';
|
|
5
|
+
import { responsiveColumns } from '../DataTableResponsive.js';
|
|
6
|
+
const columns = Array.from({ length: 6 }, (_, index) => ({
|
|
7
|
+
id: `c${index}`,
|
|
8
|
+
label: `Column ${index}`,
|
|
9
|
+
responsive: { priority: index, keepVisible: index === 0 },
|
|
10
|
+
headerPath: [{ id: 'group', label: 'Group' }],
|
|
11
|
+
}));
|
|
12
|
+
const data = [
|
|
13
|
+
{
|
|
14
|
+
id: 'row',
|
|
15
|
+
...Object.fromEntries(columns.map((column) => [column.id, column.label])),
|
|
16
|
+
},
|
|
17
|
+
];
|
|
18
|
+
async function resize(container, width) {
|
|
19
|
+
const root = container.querySelector('.data-table-container');
|
|
20
|
+
Object.defineProperty(root, 'clientWidth', {
|
|
21
|
+
configurable: true,
|
|
22
|
+
value: width,
|
|
23
|
+
});
|
|
24
|
+
window.dispatchEvent(new Event('resize'));
|
|
25
|
+
await waitFor(() => expect(root).toHaveClass(width <= 800 ? 'data-table-container--narrow' : 'data-table-container'));
|
|
26
|
+
}
|
|
27
|
+
describe('responsive column collapse', () => {
|
|
28
|
+
it('keeps mandatory columns and highest priorities in display order', () => {
|
|
29
|
+
expect(responsiveColumns(columns, 390, 160).map((column) => column.id)).toEqual(['c0', 'c5']);
|
|
30
|
+
expect(responsiveColumns(columns, 768, 160).map((column) => column.id)).toEqual(['c0', 'c3', 'c4', 'c5']);
|
|
31
|
+
});
|
|
32
|
+
it('handles missing metadata, equal priorities, invalid numbers, and oversized mandatory sets', () => {
|
|
33
|
+
const plain = columns.map((column) => ({
|
|
34
|
+
...column,
|
|
35
|
+
responsive: undefined,
|
|
36
|
+
}));
|
|
37
|
+
expect(responsiveColumns(plain, 320, Number.NaN).map((column) => column.id)).toEqual(['c0', 'c1']);
|
|
38
|
+
expect(responsiveColumns([{ ...plain[0], responsive: { priority: Number.NaN } }, plain[1]], 160, 160).map((column) => column.id)).toEqual(['c0']);
|
|
39
|
+
expect(responsiveColumns(columns.map((column) => ({
|
|
40
|
+
...column,
|
|
41
|
+
responsive: { keepVisible: true },
|
|
42
|
+
})), 100, 160)).toHaveLength(6);
|
|
43
|
+
expect(responsiveColumns([], 0, 160)).toEqual([]);
|
|
44
|
+
});
|
|
45
|
+
it('matches headers/cells/groups to container width and restores without mutating controller visibility', async () => {
|
|
46
|
+
const controller = createDataTableController({
|
|
47
|
+
initialState: { columnVisibility: [{ columnId: 'c5', visible: false }] },
|
|
48
|
+
});
|
|
49
|
+
const { container } = render(DataTable, {
|
|
50
|
+
props: {
|
|
51
|
+
data,
|
|
52
|
+
columns,
|
|
53
|
+
rowKey: 'id',
|
|
54
|
+
controller,
|
|
55
|
+
responsiveMode: 'hide-columns',
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
const visibility = controller.getState().columnVisibility;
|
|
59
|
+
await resize(container, 390);
|
|
60
|
+
await waitFor(() => expect(screen.getAllByRole('cell')).toHaveLength(2));
|
|
61
|
+
expect(screen.getByRole('columnheader', { name: 'Group' })).toHaveAttribute('colspan', '2');
|
|
62
|
+
expect(screen.queryByRole('columnheader', { name: 'Column 5' })).toBeNull();
|
|
63
|
+
expect(screen.getByRole('columnheader', { name: 'Column 4' })).toBeInTheDocument();
|
|
64
|
+
expect(controller.getState().columnVisibility).toEqual(visibility);
|
|
65
|
+
await resize(container, 1200);
|
|
66
|
+
await waitFor(() => expect(screen.getAllByRole('cell')).toHaveLength(5));
|
|
67
|
+
expect(screen.getByRole('columnheader', { name: 'Group' })).toHaveAttribute('colspan', '5');
|
|
68
|
+
});
|
|
69
|
+
it('preserves the scroll default regardless of narrow width', async () => {
|
|
70
|
+
const { container } = render(DataTable, { props: { data, columns } });
|
|
71
|
+
const root = container.querySelector('.data-table-container');
|
|
72
|
+
Object.defineProperty(root, 'clientWidth', {
|
|
73
|
+
configurable: true,
|
|
74
|
+
value: 390,
|
|
75
|
+
});
|
|
76
|
+
window.dispatchEvent(new Event('resize'));
|
|
77
|
+
await waitFor(() => expect(screen.getAllByRole('cell')).toHaveLength(6));
|
|
78
|
+
expect(root).not.toHaveClass('data-table-container--narrow');
|
|
79
|
+
});
|
|
80
|
+
});
|