@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
|
@@ -14,6 +14,8 @@ import type { ButtonSize, ButtonVariant } from '../../types-generic';
|
|
|
14
14
|
|
|
15
15
|
/** Props for Button component */
|
|
16
16
|
export interface Props extends Omit<HTMLButtonAttributes, 'class' | 'href'> {
|
|
17
|
+
/** Target density; omit to inherit the ThemeProvider setting. */
|
|
18
|
+
density?: 'comfortable' | 'touch';
|
|
17
19
|
/** Visual variant */
|
|
18
20
|
variant?: ButtonVariant;
|
|
19
21
|
/** Size variant */
|
|
@@ -62,6 +64,7 @@ const {
|
|
|
62
64
|
target,
|
|
63
65
|
rel,
|
|
64
66
|
download,
|
|
67
|
+
density,
|
|
65
68
|
...rest
|
|
66
69
|
}: Props = $props();
|
|
67
70
|
|
|
@@ -118,7 +121,7 @@ function handleClick(event: MouseEvent) {
|
|
|
118
121
|
{target}
|
|
119
122
|
{rel}
|
|
120
123
|
{download}
|
|
121
|
-
class="button {variant} {size} {className}"
|
|
124
|
+
data-density={density} class="button {variant} {size} {className}"
|
|
122
125
|
class:disabled={isDisabled}
|
|
123
126
|
class:full-width={fullWidth}
|
|
124
127
|
class:loading
|
|
@@ -140,7 +143,7 @@ function handleClick(event: MouseEvent) {
|
|
|
140
143
|
{type}
|
|
141
144
|
disabled={isDisabled}
|
|
142
145
|
aria-busy={loading}
|
|
143
|
-
class="button {variant} {size} {className}"
|
|
146
|
+
data-density={density} class="button {variant} {size} {className}"
|
|
144
147
|
class:full-width={fullWidth}
|
|
145
148
|
class:loading
|
|
146
149
|
onclick={handleClick}
|
|
@@ -295,10 +298,21 @@ function handleClick(event: MouseEvent) {
|
|
|
295
298
|
outline-offset: 2px;
|
|
296
299
|
}
|
|
297
300
|
|
|
301
|
+
/* Phones: every size is at least a 44px touch target. */
|
|
302
|
+
@media (max-width: 48rem) {
|
|
303
|
+
.button {
|
|
304
|
+
min-block-size: 2.75rem;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
298
308
|
/* Reduced motion */
|
|
299
309
|
@media (prefers-reduced-motion: reduce) {
|
|
300
310
|
.spinner {
|
|
301
311
|
animation: none;
|
|
302
312
|
}
|
|
303
313
|
}
|
|
314
|
+
|
|
315
|
+
.button[data-density='touch'] { --smrt-control-target-min: var(--smrt-touch-target-min, 48px); }
|
|
316
|
+
.button[data-density='comfortable'] { --smrt-control-target-min: 0px; }
|
|
317
|
+
.button { min-height: var(--smrt-control-target-min, 0px); min-width: var(--smrt-control-target-min, 0px); }
|
|
304
318
|
</style>
|
|
@@ -9,6 +9,8 @@ import type { HTMLAnchorAttributes, HTMLButtonAttributes } from 'svelte/elements
|
|
|
9
9
|
import type { ButtonSize, ButtonVariant } from '../../types-generic';
|
|
10
10
|
/** Props for Button component */
|
|
11
11
|
export interface Props extends Omit<HTMLButtonAttributes, 'class' | 'href'> {
|
|
12
|
+
/** Target density; omit to inherit the ThemeProvider setting. */
|
|
13
|
+
density?: 'comfortable' | 'touch';
|
|
12
14
|
/** Visual variant */
|
|
13
15
|
variant?: ButtonVariant;
|
|
14
16
|
/** Size variant */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Button.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/ui/Button.svelte.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EACV,oBAAoB,EACpB,oBAAoB,EACrB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGrE,iCAAiC;AACjC,MAAM,WAAW,KAAM,SAAQ,IAAI,CAAC,oBAAoB,EAAE,OAAO,GAAG,MAAM,CAAC;IACzE,qBAAqB;IACrB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,mBAAmB;IACnB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,6CAA6C;IAC7C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iCAAiC;IACjC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,wBAAwB;IACxB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,oBAAoB;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,MAAM,CAAC,EAAE,oBAAoB,CAAC,QAAQ,CAAC,CAAC;IACxC,6EAA6E;IAC7E,GAAG,CAAC,EAAE,oBAAoB,CAAC,KAAK,CAAC,CAAC;IAClC,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,oBAAoB,CAAC,UAAU,CAAC,CAAC;CAC7C;
|
|
1
|
+
{"version":3,"file":"Button.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/ui/Button.svelte.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EACV,oBAAoB,EACpB,oBAAoB,EACrB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGrE,iCAAiC;AACjC,MAAM,WAAW,KAAM,SAAQ,IAAI,CAAC,oBAAoB,EAAE,OAAO,GAAG,MAAM,CAAC;IACzE,iEAAiE;IACjE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC;IAClC,qBAAqB;IACrB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,mBAAmB;IACnB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,6CAA6C;IAC7C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iCAAiC;IACjC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,wBAAwB;IACxB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,oBAAoB;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,MAAM,CAAC,EAAE,oBAAoB,CAAC,QAAQ,CAAC,CAAC;IACxC,6EAA6E;IAC7E,GAAG,CAAC,EAAE,oBAAoB,CAAC,KAAK,CAAC,CAAC;IAClC,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,oBAAoB,CAAC,UAAU,CAAC,CAAC;CAC7C;AAoGD,QAAA,MAAM,MAAM,2CAAwC,CAAC;AACrD,KAAK,MAAM,GAAG,UAAU,CAAC,OAAO,MAAM,CAAC,CAAC;AACxC,eAAe,MAAM,CAAC"}
|
|
@@ -52,15 +52,24 @@ const {
|
|
|
52
52
|
</div>
|
|
53
53
|
|
|
54
54
|
<style>
|
|
55
|
+
/*
|
|
56
|
+
* Themeable look (app-level custom properties; defaults keep the stock look):
|
|
57
|
+
* --smrt-card-border edge of default and elevated cards
|
|
58
|
+
* --smrt-card-background card fill
|
|
59
|
+
* --smrt-card-shadow shadow of default cards (elevated keeps its elevation)
|
|
60
|
+
* --smrt-card-divider rule between the header/footer and the content
|
|
61
|
+
* The `outlined` variant always draws its outline.
|
|
62
|
+
*/
|
|
55
63
|
.card {
|
|
56
|
-
background: var(--smrt-color-surface);
|
|
64
|
+
background: var(--smrt-card-background, var(--smrt-color-surface));
|
|
57
65
|
border-radius: var(--smrt-radius-medium);
|
|
58
66
|
transition: all var(--smrt-duration-short2) var(--smrt-easing-standard);
|
|
59
67
|
}
|
|
60
68
|
|
|
61
69
|
/* Variants */
|
|
62
70
|
.default {
|
|
63
|
-
border: 1px solid var(--smrt-color-outline-variant);
|
|
71
|
+
border: var(--smrt-card-border, 1px solid var(--smrt-color-outline-variant));
|
|
72
|
+
box-shadow: var(--smrt-card-shadow, none);
|
|
64
73
|
}
|
|
65
74
|
|
|
66
75
|
.outlined {
|
|
@@ -68,7 +77,7 @@ const {
|
|
|
68
77
|
}
|
|
69
78
|
|
|
70
79
|
.elevated {
|
|
71
|
-
border: 1px solid var(--smrt-color-outline-variant);
|
|
80
|
+
border: var(--smrt-card-border, 1px solid var(--smrt-color-outline-variant));
|
|
72
81
|
box-shadow: var(--smrt-elevation-2);
|
|
73
82
|
}
|
|
74
83
|
|
|
@@ -98,7 +107,7 @@ const {
|
|
|
98
107
|
/* Header */
|
|
99
108
|
.card-header {
|
|
100
109
|
padding: var(--smrt-spacing-6);
|
|
101
|
-
border-bottom: 1px solid var(--smrt-color-outline-variant);
|
|
110
|
+
border-bottom: var(--smrt-card-divider, 1px solid var(--smrt-color-outline-variant));
|
|
102
111
|
}
|
|
103
112
|
|
|
104
113
|
.padding-sm .card-header {
|
|
@@ -112,7 +121,7 @@ const {
|
|
|
112
121
|
/* Footer */
|
|
113
122
|
.card-footer {
|
|
114
123
|
padding: var(--smrt-spacing-6);
|
|
115
|
-
border-top: 1px solid var(--smrt-color-outline-variant);
|
|
124
|
+
border-top: var(--smrt-card-divider, 1px solid var(--smrt-color-outline-variant));
|
|
116
125
|
background: var(--smrt-color-surface-container-low);
|
|
117
126
|
border-bottom-left-radius: var(--smrt-radius-medium);
|
|
118
127
|
border-bottom-right-radius: var(--smrt-radius-medium);
|
|
@@ -18,6 +18,14 @@ export interface Props {
|
|
|
18
18
|
label?: string;
|
|
19
19
|
/** Custom trigger content. */
|
|
20
20
|
trigger?: Snippet;
|
|
21
|
+
/** Accessible name of the trigger button when it shows only an icon (`aria-label`); omit to use its visible content (an icon trigger then falls back to `label`). */
|
|
22
|
+
triggerLabel?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Trigger look: `button` (bordered, the default) or `icon`, a borderless 44px
|
|
25
|
+
* round icon button (a "more" or row-actions menu) that takes the surrounding
|
|
26
|
+
* text colour.
|
|
27
|
+
*/
|
|
28
|
+
variant?: 'button' | 'icon';
|
|
21
29
|
/** Menu items. */
|
|
22
30
|
items: MenuItem[];
|
|
23
31
|
/** Menu placement relative to the trigger. */
|
|
@@ -31,6 +39,8 @@ export interface Props {
|
|
|
31
39
|
const {
|
|
32
40
|
label,
|
|
33
41
|
trigger,
|
|
42
|
+
triggerLabel,
|
|
43
|
+
variant = 'button',
|
|
34
44
|
items,
|
|
35
45
|
placement = 'bottom-start',
|
|
36
46
|
onselect,
|
|
@@ -39,6 +49,16 @@ const {
|
|
|
39
49
|
|
|
40
50
|
const instanceId = $props.id();
|
|
41
51
|
const menuId = `smrt-menu-${instanceId}`;
|
|
52
|
+
|
|
53
|
+
// An icon trigger shows no text, so without triggerLabel or label the button
|
|
54
|
+
// has no accessible name.
|
|
55
|
+
$effect(() => {
|
|
56
|
+
if (variant === 'icon' && !triggerLabel && !label) {
|
|
57
|
+
console.warn(
|
|
58
|
+
'[Dropdown] variant="icon" needs triggerLabel (or label): the trigger button has no accessible name.',
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
42
62
|
let open = $state(false);
|
|
43
63
|
let wrapEl = $state<HTMLElement | null>(null);
|
|
44
64
|
let triggerEl = $state<HTMLButtonElement | null>(null);
|
|
@@ -132,6 +152,8 @@ $effect(() => {
|
|
|
132
152
|
bind:this={triggerEl}
|
|
133
153
|
type="button"
|
|
134
154
|
class="dropdown__trigger"
|
|
155
|
+
class:dropdown__trigger--icon={variant === 'icon'}
|
|
156
|
+
aria-label={triggerLabel ?? (variant === 'icon' ? label : undefined)}
|
|
135
157
|
aria-haspopup="menu"
|
|
136
158
|
aria-expanded={open}
|
|
137
159
|
aria-controls={open ? menuId : undefined}
|
|
@@ -160,7 +182,10 @@ $effect(() => {
|
|
|
160
182
|
tabindex={-1}
|
|
161
183
|
onclick={() => selectItem(item)}
|
|
162
184
|
>
|
|
163
|
-
{item.
|
|
185
|
+
{#if item.icon}
|
|
186
|
+
<span class="dropdown__item-icon" aria-hidden="true">{@render item.icon()}</span>
|
|
187
|
+
{/if}
|
|
188
|
+
<span class="dropdown__item-label">{item.label}</span>
|
|
164
189
|
</button>
|
|
165
190
|
{/each}
|
|
166
191
|
</div>
|
|
@@ -187,6 +212,24 @@ $effect(() => {
|
|
|
187
212
|
outline: 2px solid var(--smrt-color-primary);
|
|
188
213
|
outline-offset: 2px;
|
|
189
214
|
}
|
|
215
|
+
/* Icon trigger: a 44px round "more" button in the surrounding text colour. */
|
|
216
|
+
.dropdown__trigger--icon {
|
|
217
|
+
display: inline-flex;
|
|
218
|
+
align-items: center;
|
|
219
|
+
justify-content: center;
|
|
220
|
+
box-sizing: border-box;
|
|
221
|
+
inline-size: 2.75rem;
|
|
222
|
+
block-size: 2.75rem;
|
|
223
|
+
padding: 0;
|
|
224
|
+
border: none;
|
|
225
|
+
border-radius: var(--smrt-radius-full, 999px);
|
|
226
|
+
background: transparent;
|
|
227
|
+
color: inherit;
|
|
228
|
+
}
|
|
229
|
+
.dropdown__trigger--icon:hover:not(:disabled),
|
|
230
|
+
.dropdown__trigger--icon[aria-expanded='true'] {
|
|
231
|
+
background: color-mix(in srgb, currentColor 10%, transparent);
|
|
232
|
+
}
|
|
190
233
|
.dropdown__trigger:disabled {
|
|
191
234
|
opacity: 0.5;
|
|
192
235
|
cursor: not-allowed;
|
|
@@ -226,6 +269,12 @@ $effect(() => {
|
|
|
226
269
|
|
|
227
270
|
.dropdown__item {
|
|
228
271
|
appearance: none;
|
|
272
|
+
display: flex;
|
|
273
|
+
align-items: center;
|
|
274
|
+
gap: var(--smrt-spacing-2, 8px);
|
|
275
|
+
/* A touch target: menu rows are at least 44px tall. */
|
|
276
|
+
min-block-size: 2.75rem;
|
|
277
|
+
box-sizing: border-box;
|
|
229
278
|
font: inherit;
|
|
230
279
|
text-align: left;
|
|
231
280
|
cursor: pointer;
|
|
@@ -236,6 +285,11 @@ $effect(() => {
|
|
|
236
285
|
color: var(--smrt-color-on-surface);
|
|
237
286
|
white-space: nowrap;
|
|
238
287
|
}
|
|
288
|
+
.dropdown__item-icon {
|
|
289
|
+
display: inline-flex;
|
|
290
|
+
flex: none;
|
|
291
|
+
color: var(--smrt-color-on-surface-variant);
|
|
292
|
+
}
|
|
239
293
|
.dropdown__item:hover:not(:disabled) {
|
|
240
294
|
background: var(--smrt-color-surface-container-high);
|
|
241
295
|
}
|
|
@@ -14,6 +14,14 @@ export interface Props {
|
|
|
14
14
|
label?: string;
|
|
15
15
|
/** Custom trigger content. */
|
|
16
16
|
trigger?: Snippet;
|
|
17
|
+
/** Accessible name of the trigger button when it shows only an icon (`aria-label`); omit to use its visible content (an icon trigger then falls back to `label`). */
|
|
18
|
+
triggerLabel?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Trigger look: `button` (bordered, the default) or `icon`, a borderless 44px
|
|
21
|
+
* round icon button (a "more" or row-actions menu) that takes the surrounding
|
|
22
|
+
* text colour.
|
|
23
|
+
*/
|
|
24
|
+
variant?: 'button' | 'icon';
|
|
17
25
|
/** Menu items. */
|
|
18
26
|
items: MenuItem[];
|
|
19
27
|
/** Menu placement relative to the trigger. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Dropdown.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/ui/Dropdown.svelte.ts"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEtC,OAAO,KAAK,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAGvE,MAAM,WAAW,KAAK;IACpB,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8BAA8B;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,kBAAkB;IAClB,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,8CAA8C;IAC9C,SAAS,CAAC,EAAE,iBAAiB,CAAC;IAC9B,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,2BAA2B;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;
|
|
1
|
+
{"version":3,"file":"Dropdown.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/ui/Dropdown.svelte.ts"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEtC,OAAO,KAAK,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAGvE,MAAM,WAAW,KAAK;IACpB,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8BAA8B;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,qKAAqK;IACrK,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,OAAO,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;IAC5B,kBAAkB;IAClB,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,8CAA8C;IAC9C,SAAS,CAAC,EAAE,iBAAiB,CAAC;IAC9B,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,2BAA2B;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AA+ID,QAAA,MAAM,QAAQ,2CAAwC,CAAC;AACvD,KAAK,QAAQ,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC;AAC5C,eAAe,QAAQ,CAAC"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* IconToggle — an icon-only toggle button for dense filter and view-switcher
|
|
4
|
+
* rows. The icon is the `children` snippet (any icon set); `label` is both the
|
|
5
|
+
* accessible name and the tooltip text. `pressed` is reflected with
|
|
6
|
+
* `aria-pressed`, so a row of them is a one-of-many (or a many) toggle group;
|
|
7
|
+
* the owner decides what pressing means (this component keeps no state). An
|
|
8
|
+
* optional `count` shows as a small badge and is part of the accessible name
|
|
9
|
+
* and tooltip. The hit area is at least 44px square.
|
|
10
|
+
*/
|
|
11
|
+
import type { Snippet } from 'svelte';
|
|
12
|
+
import type { HTMLButtonAttributes } from 'svelte/elements';
|
|
13
|
+
import type { TooltipPlacement } from '../../types-generic';
|
|
14
|
+
import Tooltip from './Tooltip.svelte';
|
|
15
|
+
|
|
16
|
+
export interface Props
|
|
17
|
+
extends Omit<
|
|
18
|
+
HTMLButtonAttributes,
|
|
19
|
+
'class' | 'children' | 'aria-label' | 'aria-pressed' | 'title'
|
|
20
|
+
> {
|
|
21
|
+
/** Accessible name and tooltip text (what the button does or filters). */
|
|
22
|
+
label: string;
|
|
23
|
+
/** Whether the toggle is on (`aria-pressed`). */
|
|
24
|
+
pressed?: boolean;
|
|
25
|
+
/** Optional count badge; included in the accessible name and tooltip. */
|
|
26
|
+
count?: number;
|
|
27
|
+
/** A CSS colour (a token such as `var(--status-draft)` or a value) shown when the toggle is pressed. */
|
|
28
|
+
tone?: string;
|
|
29
|
+
/** The icon. Decorative: it is hidden from assistive technology. */
|
|
30
|
+
children: Snippet;
|
|
31
|
+
/** Where the tooltip opens. */
|
|
32
|
+
tooltipPlacement?: TooltipPlacement;
|
|
33
|
+
/** Additional CSS class names. */
|
|
34
|
+
class?: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const {
|
|
38
|
+
label,
|
|
39
|
+
pressed = false,
|
|
40
|
+
count,
|
|
41
|
+
tone,
|
|
42
|
+
children,
|
|
43
|
+
tooltipPlacement = 'top',
|
|
44
|
+
disabled = false,
|
|
45
|
+
type = 'button',
|
|
46
|
+
class: className = '',
|
|
47
|
+
...rest
|
|
48
|
+
}: Props = $props();
|
|
49
|
+
|
|
50
|
+
const name = $derived(count === undefined ? label : `${label} (${count})`);
|
|
51
|
+
</script>
|
|
52
|
+
|
|
53
|
+
<Tooltip text={name} placement={tooltipPlacement}>
|
|
54
|
+
<button
|
|
55
|
+
{...rest}
|
|
56
|
+
{type}
|
|
57
|
+
{disabled}
|
|
58
|
+
class="icon-toggle {className}"
|
|
59
|
+
class:pressed
|
|
60
|
+
class:toned={tone !== undefined}
|
|
61
|
+
style:--icon-toggle-tone={tone}
|
|
62
|
+
aria-pressed={pressed}
|
|
63
|
+
aria-label={name}
|
|
64
|
+
>
|
|
65
|
+
<span class="icon" aria-hidden="true">{@render children()}</span>
|
|
66
|
+
{#if count !== undefined}<span class="count" aria-hidden="true">{count}</span>{/if}
|
|
67
|
+
</button>
|
|
68
|
+
</Tooltip>
|
|
69
|
+
|
|
70
|
+
<style>
|
|
71
|
+
.icon-toggle {
|
|
72
|
+
position: relative;
|
|
73
|
+
display: inline-flex;
|
|
74
|
+
align-items: center;
|
|
75
|
+
justify-content: center;
|
|
76
|
+
box-sizing: border-box;
|
|
77
|
+
min-width: 2.75rem;
|
|
78
|
+
min-height: 2.75rem;
|
|
79
|
+
padding: 0;
|
|
80
|
+
border: 1px solid var(--smrt-color-outline-variant, var(--smrt-color-outline));
|
|
81
|
+
border-radius: var(--smrt-radius-full, 999px);
|
|
82
|
+
background: var(--smrt-color-surface-container, var(--smrt-color-surface));
|
|
83
|
+
color: var(--smrt-color-on-surface);
|
|
84
|
+
font: inherit;
|
|
85
|
+
cursor: pointer;
|
|
86
|
+
}
|
|
87
|
+
.icon-toggle:hover:not(:disabled) {
|
|
88
|
+
background: var(--smrt-color-surface-container-high, var(--smrt-color-surface-container));
|
|
89
|
+
}
|
|
90
|
+
/* Pressed is not told by colour alone (WCAG 1.4.1): it also draws a 2px ring
|
|
91
|
+
in its text colour, where unpressed has a 1px outline. */
|
|
92
|
+
.icon-toggle.pressed {
|
|
93
|
+
border-color: transparent;
|
|
94
|
+
background: var(--smrt-color-primary-container, var(--smrt-color-secondary-container));
|
|
95
|
+
color: var(--smrt-color-on-primary-container, var(--smrt-color-on-secondary-container));
|
|
96
|
+
box-shadow: inset 0 0 0 2px currentColor;
|
|
97
|
+
}
|
|
98
|
+
/* A toned toggle is neutral until pressed, then wears its tone. */
|
|
99
|
+
.icon-toggle.toned {
|
|
100
|
+
color: var(--smrt-color-on-surface-variant, var(--smrt-color-on-surface));
|
|
101
|
+
}
|
|
102
|
+
.icon-toggle.toned.pressed {
|
|
103
|
+
background: color-mix(in srgb, var(--icon-toggle-tone) 16%, var(--smrt-color-surface));
|
|
104
|
+
color: var(--icon-toggle-tone);
|
|
105
|
+
box-shadow: inset 0 0 0 2px var(--icon-toggle-tone);
|
|
106
|
+
}
|
|
107
|
+
.icon-toggle:focus-visible {
|
|
108
|
+
outline: 2px solid var(--smrt-color-primary);
|
|
109
|
+
outline-offset: 2px;
|
|
110
|
+
}
|
|
111
|
+
.icon-toggle:disabled {
|
|
112
|
+
opacity: 0.5;
|
|
113
|
+
cursor: not-allowed;
|
|
114
|
+
}
|
|
115
|
+
.icon {
|
|
116
|
+
display: inline-flex;
|
|
117
|
+
}
|
|
118
|
+
.count {
|
|
119
|
+
position: absolute;
|
|
120
|
+
z-index: 2;
|
|
121
|
+
top: -0.3rem;
|
|
122
|
+
right: -0.3rem;
|
|
123
|
+
box-sizing: border-box;
|
|
124
|
+
min-width: 1.15rem;
|
|
125
|
+
padding: 0 0.3rem;
|
|
126
|
+
border-radius: var(--smrt-radius-full, 999px);
|
|
127
|
+
/* Outlined, not filled: a surface-coloured face (so the button's edge does
|
|
128
|
+
not show through where the badge overlaps it), a 1px theme outline and
|
|
129
|
+
neutral text, readable on light and dark themes alike. */
|
|
130
|
+
border: 1px solid var(--smrt-color-outline);
|
|
131
|
+
background: var(--smrt-color-surface);
|
|
132
|
+
color: var(--smrt-color-on-surface-variant);
|
|
133
|
+
font-size: 0.68rem;
|
|
134
|
+
font-weight: 700;
|
|
135
|
+
line-height: 1.15rem;
|
|
136
|
+
text-align: center;
|
|
137
|
+
font-variant-numeric: tabular-nums;
|
|
138
|
+
}
|
|
139
|
+
</style>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IconToggle — an icon-only toggle button for dense filter and view-switcher
|
|
3
|
+
* rows. The icon is the `children` snippet (any icon set); `label` is both the
|
|
4
|
+
* accessible name and the tooltip text. `pressed` is reflected with
|
|
5
|
+
* `aria-pressed`, so a row of them is a one-of-many (or a many) toggle group;
|
|
6
|
+
* the owner decides what pressing means (this component keeps no state). An
|
|
7
|
+
* optional `count` shows as a small badge and is part of the accessible name
|
|
8
|
+
* and tooltip. The hit area is at least 44px square.
|
|
9
|
+
*/
|
|
10
|
+
import type { Snippet } from 'svelte';
|
|
11
|
+
import type { HTMLButtonAttributes } from 'svelte/elements';
|
|
12
|
+
import type { TooltipPlacement } from '../../types-generic';
|
|
13
|
+
export interface Props extends Omit<HTMLButtonAttributes, 'class' | 'children' | 'aria-label' | 'aria-pressed' | 'title'> {
|
|
14
|
+
/** Accessible name and tooltip text (what the button does or filters). */
|
|
15
|
+
label: string;
|
|
16
|
+
/** Whether the toggle is on (`aria-pressed`). */
|
|
17
|
+
pressed?: boolean;
|
|
18
|
+
/** Optional count badge; included in the accessible name and tooltip. */
|
|
19
|
+
count?: number;
|
|
20
|
+
/** A CSS colour (a token such as `var(--status-draft)` or a value) shown when the toggle is pressed. */
|
|
21
|
+
tone?: string;
|
|
22
|
+
/** The icon. Decorative: it is hidden from assistive technology. */
|
|
23
|
+
children: Snippet;
|
|
24
|
+
/** Where the tooltip opens. */
|
|
25
|
+
tooltipPlacement?: TooltipPlacement;
|
|
26
|
+
/** Additional CSS class names. */
|
|
27
|
+
class?: string;
|
|
28
|
+
}
|
|
29
|
+
declare const IconToggle: import("svelte").Component<Props, {}, "">;
|
|
30
|
+
type IconToggle = ReturnType<typeof IconToggle>;
|
|
31
|
+
export default IconToggle;
|
|
32
|
+
//# sourceMappingURL=IconToggle.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IconToggle.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/ui/IconToggle.svelte.ts"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAI5D,MAAM,WAAW,KACf,SAAQ,IAAI,CACV,oBAAoB,EACpB,OAAO,GAAG,UAAU,GAAG,YAAY,GAAG,cAAc,GAAG,OAAO,CAC/D;IACD,0EAA0E;IAC1E,KAAK,EAAE,MAAM,CAAC;IACd,iDAAiD;IACjD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,yEAAyE;IACzE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wGAAwG;IACxG,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oEAAoE;IACpE,QAAQ,EAAE,OAAO,CAAC;IAClB,+BAA+B;IAC/B,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,kCAAkC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAoCD,QAAA,MAAM,UAAU,2CAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* IconToggleGroup — joins a row of `IconToggle`s into one labelled group: a
|
|
4
|
+
* single segmented strip with shared edges and rounded ends, exposed to
|
|
5
|
+
* assistive technology as `role="group"` named by `label` ("Filter by type").
|
|
6
|
+
* It adds no behaviour; each toggle keeps its own `pressed` state and
|
|
7
|
+
* `onclick`, so it works for one-of-many and many-of-many alike. Put one group
|
|
8
|
+
* per kind of filter and lay the groups out yourself.
|
|
9
|
+
*/
|
|
10
|
+
import type { Snippet } from 'svelte';
|
|
11
|
+
|
|
12
|
+
export interface Props {
|
|
13
|
+
/** Names the group for assistive technology (what these toggles filter). */
|
|
14
|
+
label: string;
|
|
15
|
+
/** The `IconToggle`s. */
|
|
16
|
+
children: Snippet;
|
|
17
|
+
/** Additional CSS class names. */
|
|
18
|
+
class?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const { label, children, class: className = '' }: Props = $props();
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<div class="icon-toggle-group {className}" role="group" aria-label={label}>
|
|
25
|
+
{@render children()}
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<style>
|
|
29
|
+
.icon-toggle-group {
|
|
30
|
+
display: inline-flex;
|
|
31
|
+
flex-wrap: wrap;
|
|
32
|
+
max-width: 100%;
|
|
33
|
+
isolation: isolate;
|
|
34
|
+
}
|
|
35
|
+
/* Shared edges: one border between neighbours, square inside, round ends.
|
|
36
|
+
Each toggle sits in tooltip wrappers, so the rules reach it by descendant. */
|
|
37
|
+
.icon-toggle-group :global(.icon-toggle) {
|
|
38
|
+
border-radius: 0;
|
|
39
|
+
}
|
|
40
|
+
.icon-toggle-group > :global(* + *) {
|
|
41
|
+
margin-inline-start: -1px;
|
|
42
|
+
}
|
|
43
|
+
.icon-toggle-group > :global(:first-child .icon-toggle) {
|
|
44
|
+
border-start-start-radius: var(--smrt-radius-full, 999px);
|
|
45
|
+
border-end-start-radius: var(--smrt-radius-full, 999px);
|
|
46
|
+
}
|
|
47
|
+
.icon-toggle-group > :global(:last-child .icon-toggle) {
|
|
48
|
+
border-start-end-radius: var(--smrt-radius-full, 999px);
|
|
49
|
+
border-end-end-radius: var(--smrt-radius-full, 999px);
|
|
50
|
+
}
|
|
51
|
+
/* The pressed one sits above its neighbours so its tint is not clipped by them. */
|
|
52
|
+
.icon-toggle-group :global(.icon-toggle.pressed),
|
|
53
|
+
.icon-toggle-group :global(.icon-toggle:focus-visible) {
|
|
54
|
+
z-index: 1;
|
|
55
|
+
}
|
|
56
|
+
</style>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IconToggleGroup — joins a row of `IconToggle`s into one labelled group: a
|
|
3
|
+
* single segmented strip with shared edges and rounded ends, exposed to
|
|
4
|
+
* assistive technology as `role="group"` named by `label` ("Filter by type").
|
|
5
|
+
* It adds no behaviour; each toggle keeps its own `pressed` state and
|
|
6
|
+
* `onclick`, so it works for one-of-many and many-of-many alike. Put one group
|
|
7
|
+
* per kind of filter and lay the groups out yourself.
|
|
8
|
+
*/
|
|
9
|
+
import type { Snippet } from 'svelte';
|
|
10
|
+
export interface Props {
|
|
11
|
+
/** Names the group for assistive technology (what these toggles filter). */
|
|
12
|
+
label: string;
|
|
13
|
+
/** The `IconToggle`s. */
|
|
14
|
+
children: Snippet;
|
|
15
|
+
/** Additional CSS class names. */
|
|
16
|
+
class?: string;
|
|
17
|
+
}
|
|
18
|
+
declare const IconToggleGroup: import("svelte").Component<Props, {}, "">;
|
|
19
|
+
type IconToggleGroup = ReturnType<typeof IconToggleGroup>;
|
|
20
|
+
export default IconToggleGroup;
|
|
21
|
+
//# sourceMappingURL=IconToggleGroup.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IconToggleGroup.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/ui/IconToggleGroup.svelte.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAGtC,MAAM,WAAW,KAAK;IACpB,4EAA4E;IAC5E,KAAK,EAAE,MAAM,CAAC;IACd,yBAAyB;IACzB,QAAQ,EAAE,OAAO,CAAC;IAClB,kCAAkC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAiBD,QAAA,MAAM,eAAe,2CAAwC,CAAC;AAC9D,KAAK,eAAe,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC;AAC1D,eAAe,eAAe,CAAC"}
|
|
@@ -6,6 +6,14 @@ export interface Props {
|
|
|
6
6
|
label: string;
|
|
7
7
|
/** Content rendered inside the trigger button in place of the label text. */
|
|
8
8
|
trigger?: Snippet;
|
|
9
|
+
/** Accessible name of the trigger button when it shows only an icon (`aria-label`); omit to use its visible content (an icon trigger then falls back to `label`). */
|
|
10
|
+
triggerLabel?: string;
|
|
11
|
+
/**
|
|
12
|
+
* Trigger look: `button` (bordered, the default) or `icon`, a borderless
|
|
13
|
+
* 44px round icon button that takes the surrounding text colour (set the
|
|
14
|
+
* colour on the popover's `class`).
|
|
15
|
+
*/
|
|
16
|
+
variant?: 'button' | 'icon';
|
|
9
17
|
/** The popover content. */
|
|
10
18
|
children?: Snippet;
|
|
11
19
|
/** Whether the popover is visible. */
|
|
@@ -25,6 +33,8 @@ export interface Props {
|
|
|
25
33
|
let {
|
|
26
34
|
label,
|
|
27
35
|
trigger,
|
|
36
|
+
triggerLabel,
|
|
37
|
+
variant = 'button',
|
|
28
38
|
children,
|
|
29
39
|
open = $bindable(false),
|
|
30
40
|
disabled = false,
|
|
@@ -74,7 +84,9 @@ $effect(() => {
|
|
|
74
84
|
bind:this={triggerEl}
|
|
75
85
|
type="button"
|
|
76
86
|
class="popover__trigger"
|
|
87
|
+
class:popover__trigger--icon={variant === 'icon'}
|
|
77
88
|
aria-haspopup="dialog"
|
|
89
|
+
aria-label={triggerLabel ?? (variant === 'icon' ? label : undefined)}
|
|
78
90
|
aria-expanded={open}
|
|
79
91
|
aria-controls={open ? panelId : undefined}
|
|
80
92
|
{disabled}
|
|
@@ -103,7 +115,11 @@ $effect(() => {
|
|
|
103
115
|
.popover__trigger { appearance: none; padding: var(--smrt-spacing-2) var(--smrt-spacing-3); border: 1px solid var(--smrt-color-outline); border-radius: var(--smrt-radius-medium); background: var(--smrt-color-surface); color: var(--smrt-color-on-surface); font: inherit; cursor: pointer; }
|
|
104
116
|
.popover__trigger:focus-visible, .popover__panel:focus-visible { outline: 2px solid var(--smrt-color-primary); outline-offset: 2px; }
|
|
105
117
|
.popover__trigger:disabled { opacity: .5; cursor: not-allowed; }
|
|
106
|
-
|
|
118
|
+
/* Icon trigger: a 44px round glyph in the surrounding colour. Hover and open nudge the glyph; focus keeps the standard primary ring (a soft ring in the glyph's colour fell under 3:1 on ordinary surfaces). */
|
|
119
|
+
.popover__trigger--icon { display: inline-flex; align-items: center; justify-content: center; box-sizing: border-box; inline-size: 2.75rem; block-size: 2.75rem; padding: 0; border: none; border-radius: var(--smrt-radius-full, 999px); background: transparent; color: inherit; }
|
|
120
|
+
.popover__trigger--icon:hover:not(:disabled), .popover__trigger--icon[aria-expanded='true'] { background: transparent; color: color-mix(in srgb, currentColor 80%, var(--smrt-color-on-surface)); }
|
|
121
|
+
.popover__trigger--icon:focus-visible { background: transparent; }
|
|
122
|
+
.popover__panel { position: absolute; z-index: var(--smrt-z-index-popover, 1000); box-sizing: border-box; inline-size: var(--smrt-popover-panel-width, auto); min-width: min(16rem, calc(100vw - 2rem)); max-width: calc(100vw - 2rem); padding: var(--smrt-popover-panel-padding, var(--smrt-spacing-4)); border: 1px solid var(--smrt-color-outline-variant); border-radius: var(--smrt-radius-large); background: var(--smrt-color-surface-container); color: var(--smrt-color-on-surface); box-shadow: var(--smrt-elevation-3); }
|
|
107
123
|
.popover__panel--bottom-start { top: calc(100% + var(--smrt-spacing-1)); left: 0; }
|
|
108
124
|
.popover__panel--bottom-end { top: calc(100% + var(--smrt-spacing-1)); right: 0; }
|
|
109
125
|
.popover__panel--top-start { bottom: calc(100% + var(--smrt-spacing-1)); left: 0; }
|
|
@@ -4,6 +4,14 @@ export interface Props {
|
|
|
4
4
|
label: string;
|
|
5
5
|
/** Content rendered inside the trigger button in place of the label text. */
|
|
6
6
|
trigger?: Snippet;
|
|
7
|
+
/** Accessible name of the trigger button when it shows only an icon (`aria-label`); omit to use its visible content (an icon trigger then falls back to `label`). */
|
|
8
|
+
triggerLabel?: string;
|
|
9
|
+
/**
|
|
10
|
+
* Trigger look: `button` (bordered, the default) or `icon`, a borderless
|
|
11
|
+
* 44px round icon button that takes the surrounding text colour (set the
|
|
12
|
+
* colour on the popover's `class`).
|
|
13
|
+
*/
|
|
14
|
+
variant?: 'button' | 'icon';
|
|
7
15
|
/** The popover content. */
|
|
8
16
|
children?: Snippet;
|
|
9
17
|
/** Whether the popover is visible. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Popover.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/ui/Popover.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,OAAO,EAAQ,MAAM,QAAQ,CAAC;AAG5C,MAAM,WAAW,KAAK;IACpB,oEAAoE;IACpE,KAAK,EAAE,MAAM,CAAC;IACd,6EAA6E;IAC7E,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,2BAA2B;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sCAAsC;IACtC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,kCAAkC;IAClC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,uDAAuD;IACvD,SAAS,CAAC,EAAE,cAAc,GAAG,YAAY,GAAG,WAAW,GAAG,SAAS,CAAC;IACpE,sDAAsD;IACtD,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,yCAAyC;IACzC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,kCAAkC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;
|
|
1
|
+
{"version":3,"file":"Popover.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/ui/Popover.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,OAAO,EAAQ,MAAM,QAAQ,CAAC;AAG5C,MAAM,WAAW,KAAK;IACpB,oEAAoE;IACpE,KAAK,EAAE,MAAM,CAAC;IACd,6EAA6E;IAC7E,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,qKAAqK;IACrK,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,OAAO,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;IAC5B,2BAA2B;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sCAAsC;IACtC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,kCAAkC;IAClC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,uDAAuD;IACvD,SAAS,CAAC,EAAE,cAAc,GAAG,YAAY,GAAG,WAAW,GAAG,SAAS,CAAC;IACpE,sDAAsD;IACtD,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,yCAAyC;IACzC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,kCAAkC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAqED,QAAA,MAAM,OAAO,+CAAwC,CAAC;AACtD,KAAK,OAAO,GAAG,UAAU,CAAC,OAAO,OAAO,CAAC,CAAC;AAC1C,eAAe,OAAO,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { render, screen } from '@testing-library/svelte';
|
|
2
|
+
import userEvent from '@testing-library/user-event';
|
|
3
|
+
import { createRawSnippet } from 'svelte';
|
|
4
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
5
|
+
import { expectNoA11yViolations } from '../../../test-support/a11y';
|
|
6
|
+
import IconToggle from '../IconToggle.svelte';
|
|
7
|
+
const icon = createRawSnippet(() => ({
|
|
8
|
+
render: () => '<svg viewBox="0 0 24 24" width="18" height="18"></svg>',
|
|
9
|
+
}));
|
|
10
|
+
describe('IconToggle', () => {
|
|
11
|
+
it('is a labelled toggle button reflecting pressed', () => {
|
|
12
|
+
render(IconToggle, {
|
|
13
|
+
props: { label: 'Grid', pressed: true, children: icon },
|
|
14
|
+
});
|
|
15
|
+
const button = screen.getByRole('button', { name: 'Grid' });
|
|
16
|
+
expect(button).toHaveAttribute('aria-pressed', 'true');
|
|
17
|
+
expect(button).toHaveAttribute('type', 'button');
|
|
18
|
+
});
|
|
19
|
+
it('shows a count badge that is part of the name and the tooltip', () => {
|
|
20
|
+
render(IconToggle, {
|
|
21
|
+
props: { label: 'Draft', count: 12, children: icon },
|
|
22
|
+
});
|
|
23
|
+
const button = screen.getByRole('button', { name: 'Draft (12)' });
|
|
24
|
+
expect(button).toHaveAttribute('aria-pressed', 'false');
|
|
25
|
+
expect(screen.getByRole('tooltip')).toHaveTextContent('Draft (12)');
|
|
26
|
+
expect(button.querySelector('.count')).toHaveTextContent('12');
|
|
27
|
+
});
|
|
28
|
+
it('keeps no state of its own: it calls onclick and the owner decides', async () => {
|
|
29
|
+
const onclick = vi.fn();
|
|
30
|
+
render(IconToggle, {
|
|
31
|
+
props: { label: 'Cards', pressed: false, onclick, children: icon },
|
|
32
|
+
});
|
|
33
|
+
await userEvent.click(screen.getByRole('button', { name: 'Cards' }));
|
|
34
|
+
expect(onclick).toHaveBeenCalledTimes(1);
|
|
35
|
+
expect(screen.getByRole('button', { name: 'Cards' })).toHaveAttribute('aria-pressed', 'false');
|
|
36
|
+
});
|
|
37
|
+
it('is axe-clean', async () => {
|
|
38
|
+
const { container } = render(IconToggle, {
|
|
39
|
+
props: { label: 'Grid', count: 3, children: icon },
|
|
40
|
+
});
|
|
41
|
+
await expectNoA11yViolations(container);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
describe('IconToggle tone', () => {
|
|
45
|
+
it('carries its tone as a custom property and a toned class', () => {
|
|
46
|
+
render(IconToggle, {
|
|
47
|
+
props: { label: 'Draft', tone: 'var(--status-draft)', children: icon },
|
|
48
|
+
});
|
|
49
|
+
const button = screen.getByRole('button', { name: 'Draft' });
|
|
50
|
+
expect(button).toHaveClass('toned');
|
|
51
|
+
expect(button.style.getPropertyValue('--icon-toggle-tone')).toBe('var(--status-draft)');
|
|
52
|
+
});
|
|
53
|
+
it('has no tone styling unless asked', () => {
|
|
54
|
+
render(IconToggle, { props: { label: 'Grid', children: icon } });
|
|
55
|
+
const button = screen.getByRole('button', { name: 'Grid' });
|
|
56
|
+
expect(button).not.toHaveClass('toned');
|
|
57
|
+
expect(button.style.getPropertyValue('--icon-toggle-tone')).toBe('');
|
|
58
|
+
});
|
|
59
|
+
});
|