@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
|
@@ -6,13 +6,11 @@
|
|
|
6
6
|
* Provides a consistent confirmation dialog for destructive actions
|
|
7
7
|
* or important decisions.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* dialog; Escape (caught at the document level while open) cancels; and focus is
|
|
13
|
-
* restored to the opener when the dialog closes.
|
|
9
|
+
* Native showModal() puts confirmations above existing Modal/Drawer surfaces,
|
|
10
|
+
* traps focus and makes the background inert. Escape is handled locally so
|
|
11
|
+
* only the active confirmation requests cancellation.
|
|
14
12
|
*/
|
|
15
|
-
import { tick } from 'svelte';
|
|
13
|
+
import { type Snippet, tick } from 'svelte';
|
|
16
14
|
import { ripple } from '../../actions/ripple.js';
|
|
17
15
|
|
|
18
16
|
/** Props for ConfirmDialog component */
|
|
@@ -21,8 +19,8 @@ export interface Props {
|
|
|
21
19
|
open: boolean;
|
|
22
20
|
/** Dialog title */
|
|
23
21
|
title: string;
|
|
24
|
-
/**
|
|
25
|
-
message: string;
|
|
22
|
+
/** Plain text or rich message snippet */
|
|
23
|
+
message: string | Snippet;
|
|
26
24
|
/** Confirm button label */
|
|
27
25
|
confirmLabel?: string;
|
|
28
26
|
/** Cancel button label */
|
|
@@ -49,7 +47,8 @@ const {
|
|
|
49
47
|
oncancel,
|
|
50
48
|
}: Props = $props();
|
|
51
49
|
|
|
52
|
-
|
|
50
|
+
const instanceId = $props.id();
|
|
51
|
+
let backdropEl = $state<HTMLDialogElement | null>(null);
|
|
53
52
|
let confirmBtnEl = $state<HTMLButtonElement | null>(null);
|
|
54
53
|
// The element focused before the dialog opened, restored on close.
|
|
55
54
|
let previouslyFocused: HTMLElement | null = null;
|
|
@@ -63,38 +62,43 @@ function focusableEls(): HTMLElement[] {
|
|
|
63
62
|
);
|
|
64
63
|
}
|
|
65
64
|
|
|
66
|
-
//
|
|
65
|
+
// Keep the parent's open prop authoritative; native cancellation requests it.
|
|
67
66
|
$effect(() => {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
});
|
|
83
|
-
} else if (previouslyFocused) {
|
|
84
|
-
previouslyFocused.focus();
|
|
67
|
+
const dialog = backdropEl;
|
|
68
|
+
if (!open || !dialog) return;
|
|
69
|
+
previouslyFocused = document.activeElement as HTMLElement | null;
|
|
70
|
+
dialog.showModal();
|
|
71
|
+
void tick().then(() => {
|
|
72
|
+
if (!dialog.open) return;
|
|
73
|
+
const target = confirmBtnEl?.disabled
|
|
74
|
+
? (focusableEls()[0] ?? dialog)
|
|
75
|
+
: confirmBtnEl;
|
|
76
|
+
target?.focus();
|
|
77
|
+
});
|
|
78
|
+
return () => {
|
|
79
|
+
if (dialog.open) dialog.close();
|
|
80
|
+
previouslyFocused?.focus();
|
|
85
81
|
previouslyFocused = null;
|
|
86
|
-
}
|
|
82
|
+
};
|
|
87
83
|
});
|
|
88
84
|
|
|
85
|
+
function handleCancel(event: Event) {
|
|
86
|
+
event.preventDefault();
|
|
87
|
+
event.stopPropagation();
|
|
88
|
+
oncancel?.();
|
|
89
|
+
}
|
|
90
|
+
|
|
89
91
|
function handleBackdropClick(e: MouseEvent) {
|
|
90
92
|
if (e.target === e.currentTarget) {
|
|
91
93
|
oncancel?.();
|
|
92
94
|
}
|
|
93
95
|
}
|
|
94
96
|
|
|
95
|
-
// Escape handling lives at the document level (below) so it fires regardless of
|
|
96
|
-
// where focus currently is. This handler, bound to the dialog, only traps Tab.
|
|
97
97
|
function handleKeydown(e: KeyboardEvent) {
|
|
98
|
+
if (e.key === 'Escape') {
|
|
99
|
+
handleCancel(e);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
98
102
|
if (e.key !== 'Tab') return;
|
|
99
103
|
|
|
100
104
|
// Trap focus within the dialog so Tab can't escape to the page behind.
|
|
@@ -117,33 +121,30 @@ function handleKeydown(e: KeyboardEvent) {
|
|
|
117
121
|
first.focus();
|
|
118
122
|
}
|
|
119
123
|
}
|
|
120
|
-
|
|
121
|
-
function handleWindowKeydown(e: KeyboardEvent) {
|
|
122
|
-
if (open && e.key === 'Escape') {
|
|
123
|
-
e.preventDefault();
|
|
124
|
-
oncancel?.();
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
124
|
</script>
|
|
128
125
|
|
|
129
|
-
<svelte:window onkeydown={handleWindowKeydown} />
|
|
130
|
-
|
|
131
126
|
{#if open}
|
|
132
127
|
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
|
|
133
|
-
<
|
|
128
|
+
<dialog
|
|
134
129
|
bind:this={backdropEl}
|
|
135
130
|
class="dialog-backdrop"
|
|
136
|
-
role="dialog"
|
|
137
131
|
aria-modal="true"
|
|
138
|
-
aria-labelledby=
|
|
139
|
-
aria-describedby=
|
|
132
|
+
aria-labelledby={`${instanceId}-title`}
|
|
133
|
+
aria-describedby={`${instanceId}-message`}
|
|
140
134
|
tabindex="-1"
|
|
141
135
|
onclick={handleBackdropClick}
|
|
142
136
|
onkeydown={handleKeydown}
|
|
137
|
+
oncancel={handleCancel}
|
|
143
138
|
>
|
|
144
139
|
<div class="dialog-content">
|
|
145
|
-
<h2 id=
|
|
146
|
-
<
|
|
140
|
+
<h2 id={`${instanceId}-title`} class="dialog-title">{title}</h2>
|
|
141
|
+
<div id={`${instanceId}-message`} class="dialog-message">
|
|
142
|
+
{#if typeof message === 'string'}
|
|
143
|
+
{message}
|
|
144
|
+
{:else}
|
|
145
|
+
{@render message()}
|
|
146
|
+
{/if}
|
|
147
|
+
</div>
|
|
147
148
|
|
|
148
149
|
<div class="dialog-actions">
|
|
149
150
|
<button
|
|
@@ -171,7 +172,7 @@ function handleWindowKeydown(e: KeyboardEvent) {
|
|
|
171
172
|
</button>
|
|
172
173
|
</div>
|
|
173
174
|
</div>
|
|
174
|
-
</
|
|
175
|
+
</dialog>
|
|
175
176
|
{/if}
|
|
176
177
|
|
|
177
178
|
<style>
|
|
@@ -181,9 +182,19 @@ function handleWindowKeydown(e: KeyboardEvent) {
|
|
|
181
182
|
display: flex;
|
|
182
183
|
align-items: center;
|
|
183
184
|
justify-content: center;
|
|
184
|
-
|
|
185
|
-
|
|
185
|
+
width: 100%;
|
|
186
|
+
height: 100%;
|
|
187
|
+
max-width: 100%;
|
|
188
|
+
max-height: 100%;
|
|
189
|
+
margin: 0;
|
|
190
|
+
border: none;
|
|
191
|
+
box-sizing: border-box;
|
|
192
|
+
background: transparent;
|
|
186
193
|
padding: 1rem;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.dialog-backdrop::backdrop {
|
|
197
|
+
background-color: var(--smrt-color-scrim, rgba(0, 0, 0, 0.4));
|
|
187
198
|
backdrop-filter: blur(2px);
|
|
188
199
|
}
|
|
189
200
|
|
|
@@ -1,11 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ConfirmDialog - Modal confirmation dialog
|
|
3
|
+
* refactored for Material 3
|
|
4
|
+
*
|
|
5
|
+
* Provides a consistent confirmation dialog for destructive actions
|
|
6
|
+
* or important decisions.
|
|
7
|
+
*
|
|
8
|
+
* Native showModal() puts confirmations above existing Modal/Drawer surfaces,
|
|
9
|
+
* traps focus and makes the background inert. Escape is handled locally so
|
|
10
|
+
* only the active confirmation requests cancellation.
|
|
11
|
+
*/
|
|
12
|
+
import { type Snippet } from 'svelte';
|
|
1
13
|
/** Props for ConfirmDialog component */
|
|
2
14
|
export interface Props {
|
|
3
15
|
/** Whether the dialog is open */
|
|
4
16
|
open: boolean;
|
|
5
17
|
/** Dialog title */
|
|
6
18
|
title: string;
|
|
7
|
-
/**
|
|
8
|
-
message: string;
|
|
19
|
+
/** Plain text or rich message snippet */
|
|
20
|
+
message: string | Snippet;
|
|
9
21
|
/** Confirm button label */
|
|
10
22
|
confirmLabel?: string;
|
|
11
23
|
/** Cancel button label */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConfirmDialog.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/feedback/ConfirmDialog.svelte.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ConfirmDialog.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/feedback/ConfirmDialog.svelte.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,KAAK,OAAO,EAAQ,MAAM,QAAQ,CAAC;AAI5C,wCAAwC;AACxC,MAAM,WAAW,KAAK;IACpB,iCAAiC;IACjC,IAAI,EAAE,OAAO,CAAC;IACd,mBAAmB;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,yCAAyC;IACzC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;IAC1B,2BAA2B;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,0BAA0B;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gDAAgD;IAChD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,oCAAoC;IACpC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,qCAAqC;IACrC,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACvB;AA8HD,QAAA,MAAM,aAAa,2CAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* PhoneSheet — the phone replacement for drawers and centered modals.
|
|
4
|
+
*
|
|
5
|
+
* - `variant="page"`: a full-screen page (a notifications list, a picker);
|
|
6
|
+
* - `variant="sheet"`: slides up from the bottom with a grabber; a swipe down
|
|
7
|
+
* on its header closes it.
|
|
8
|
+
*
|
|
9
|
+
* It closes on its close button and Escape, moves focus into itself when it
|
|
10
|
+
* opens, and returns focus to the opener when it closes. It is positioned
|
|
11
|
+
* `absolute; inset: 0`, so it covers its nearest positioned ancestor — inside
|
|
12
|
+
* an `AdminShell`, render it in the `overlays` snippet so it covers the
|
|
13
|
+
* screen above the phone bottom bar. The host may keep it mounted while
|
|
14
|
+
* closed (it is hidden and inert), so a chat inside keeps its draft.
|
|
15
|
+
*/
|
|
16
|
+
import type { Snippet } from 'svelte';
|
|
17
|
+
import { tick } from 'svelte';
|
|
18
|
+
import { swipeDismiss } from '../../actions/swipe-dismiss.js';
|
|
19
|
+
import { M } from '../../i18n/strings.ui.js';
|
|
20
|
+
import { useI18n } from '../../i18n/use-i18n.js';
|
|
21
|
+
|
|
22
|
+
export interface Props {
|
|
23
|
+
/** Whether the sheet is shown. */
|
|
24
|
+
open: boolean;
|
|
25
|
+
/** Heading shown in the sheet header; also names the dialog. */
|
|
26
|
+
title: string;
|
|
27
|
+
/** Called on the close button, Escape, or a swipe down (sheet). */
|
|
28
|
+
onclose: () => void;
|
|
29
|
+
/** `page` covers the area; `sheet` slides up with rounded corners. */
|
|
30
|
+
variant?: 'page' | 'sheet';
|
|
31
|
+
/** Element id, for `aria-controls` on the button that opens it. */
|
|
32
|
+
id?: string;
|
|
33
|
+
/** Accessible name of the close button (default "Close {title}"). */
|
|
34
|
+
closeLabel?: string;
|
|
35
|
+
/** Sheet body. */
|
|
36
|
+
children: Snippet;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
let {
|
|
40
|
+
open,
|
|
41
|
+
title,
|
|
42
|
+
onclose,
|
|
43
|
+
variant = 'page',
|
|
44
|
+
id,
|
|
45
|
+
closeLabel,
|
|
46
|
+
children,
|
|
47
|
+
}: Props = $props();
|
|
48
|
+
|
|
49
|
+
const { t } = useI18n();
|
|
50
|
+
const instanceId = $props.id();
|
|
51
|
+
const headingId = `phone-sheet-${instanceId}`;
|
|
52
|
+
let root: HTMLElement | undefined = $state();
|
|
53
|
+
let returnFocus: HTMLElement | null = null;
|
|
54
|
+
|
|
55
|
+
$effect(() => {
|
|
56
|
+
if (!open) return;
|
|
57
|
+
returnFocus =
|
|
58
|
+
document.activeElement instanceof HTMLElement
|
|
59
|
+
? document.activeElement
|
|
60
|
+
: null;
|
|
61
|
+
void tick().then(() => root?.focus({ preventScroll: true }));
|
|
62
|
+
return () => {
|
|
63
|
+
const target = returnFocus;
|
|
64
|
+
returnFocus = null;
|
|
65
|
+
if (target && document.contains(target)) {
|
|
66
|
+
target.focus({ preventScroll: true });
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
function onkeydown(event: KeyboardEvent): void {
|
|
72
|
+
if (event.key !== 'Escape' || event.defaultPrevented) return;
|
|
73
|
+
event.preventDefault();
|
|
74
|
+
event.stopPropagation();
|
|
75
|
+
onclose();
|
|
76
|
+
}
|
|
77
|
+
</script>
|
|
78
|
+
|
|
79
|
+
<div
|
|
80
|
+
bind:this={root}
|
|
81
|
+
{id}
|
|
82
|
+
class="phone-sheet phone-sheet--{variant}"
|
|
83
|
+
class:open
|
|
84
|
+
role="dialog"
|
|
85
|
+
aria-modal="false"
|
|
86
|
+
aria-labelledby={headingId}
|
|
87
|
+
aria-hidden={!open}
|
|
88
|
+
inert={!open}
|
|
89
|
+
tabindex="-1"
|
|
90
|
+
data-escape-scope
|
|
91
|
+
data-testid="phone-sheet"
|
|
92
|
+
{onkeydown}
|
|
93
|
+
>
|
|
94
|
+
<header
|
|
95
|
+
class="phone-sheet__header"
|
|
96
|
+
use:swipeDismiss={{
|
|
97
|
+
direction: 'down',
|
|
98
|
+
onDismiss: onclose,
|
|
99
|
+
enabled: variant === 'sheet',
|
|
100
|
+
}}
|
|
101
|
+
>
|
|
102
|
+
{#if variant === 'sheet'}
|
|
103
|
+
<span class="phone-sheet__grabber" aria-hidden="true"></span>
|
|
104
|
+
{/if}
|
|
105
|
+
<h2 id={headingId}>{title}</h2>
|
|
106
|
+
<button
|
|
107
|
+
type="button"
|
|
108
|
+
class="phone-sheet__close"
|
|
109
|
+
aria-label={closeLabel ?? t(M['ui.phone_sheet.close'], { title })}
|
|
110
|
+
onclick={onclose}
|
|
111
|
+
>
|
|
112
|
+
<svg
|
|
113
|
+
viewBox="0 0 24 24"
|
|
114
|
+
width="22"
|
|
115
|
+
height="22"
|
|
116
|
+
aria-hidden="true"
|
|
117
|
+
fill="none"
|
|
118
|
+
stroke="currentColor"
|
|
119
|
+
stroke-width="2"
|
|
120
|
+
stroke-linecap="round"
|
|
121
|
+
>
|
|
122
|
+
<path d="M18 6 6 18M6 6l12 12" />
|
|
123
|
+
</svg>
|
|
124
|
+
</button>
|
|
125
|
+
</header>
|
|
126
|
+
<div class="phone-sheet__body">
|
|
127
|
+
{@render children()}
|
|
128
|
+
</div>
|
|
129
|
+
</div>
|
|
130
|
+
|
|
131
|
+
<style>
|
|
132
|
+
.phone-sheet {
|
|
133
|
+
position: absolute;
|
|
134
|
+
inset: 0;
|
|
135
|
+
z-index: 30;
|
|
136
|
+
display: grid;
|
|
137
|
+
grid-template-rows: auto minmax(0, 1fr);
|
|
138
|
+
background: var(--smrt-color-surface);
|
|
139
|
+
color: var(--smrt-color-on-surface);
|
|
140
|
+
transform: translateY(100%);
|
|
141
|
+
visibility: hidden;
|
|
142
|
+
transition:
|
|
143
|
+
transform var(--smrt-duration-medium1, 250ms) var(--smrt-easing-standard, ease),
|
|
144
|
+
visibility 0s linear var(--smrt-duration-medium1, 250ms);
|
|
145
|
+
outline: none;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.phone-sheet.open {
|
|
149
|
+
transform: none;
|
|
150
|
+
visibility: visible;
|
|
151
|
+
transition: transform var(--smrt-duration-medium1, 250ms)
|
|
152
|
+
var(--smrt-easing-standard, ease);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.phone-sheet--sheet {
|
|
156
|
+
border-start-start-radius: var(--smrt-radius-lg);
|
|
157
|
+
border-start-end-radius: var(--smrt-radius-lg);
|
|
158
|
+
box-shadow: var(--smrt-elevation-3);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.phone-sheet__header {
|
|
162
|
+
position: relative;
|
|
163
|
+
display: flex;
|
|
164
|
+
align-items: center;
|
|
165
|
+
justify-content: space-between;
|
|
166
|
+
gap: var(--smrt-spacing-2);
|
|
167
|
+
min-block-size: 3.5rem;
|
|
168
|
+
padding-block: 0;
|
|
169
|
+
padding-inline: var(--smrt-spacing-4) var(--smrt-spacing-2);
|
|
170
|
+
border-block-end: 1px solid var(--smrt-color-outline-variant);
|
|
171
|
+
touch-action: pan-x;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.phone-sheet__grabber {
|
|
175
|
+
position: absolute;
|
|
176
|
+
inset-block-start: var(--smrt-spacing-1);
|
|
177
|
+
inset-inline-start: 50%;
|
|
178
|
+
inline-size: 2.5rem;
|
|
179
|
+
block-size: 0.25rem;
|
|
180
|
+
border-radius: var(--smrt-radius-full);
|
|
181
|
+
background: var(--smrt-color-outline-variant);
|
|
182
|
+
transform: translateX(-50%);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.phone-sheet__header h2 {
|
|
186
|
+
margin: 0;
|
|
187
|
+
font: var(--smrt-typography-title-medium-font);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.phone-sheet__close {
|
|
191
|
+
display: inline-grid;
|
|
192
|
+
place-items: center;
|
|
193
|
+
inline-size: 2.75rem;
|
|
194
|
+
block-size: 2.75rem;
|
|
195
|
+
border: 0;
|
|
196
|
+
border-radius: var(--smrt-radius-full);
|
|
197
|
+
background: transparent;
|
|
198
|
+
color: inherit;
|
|
199
|
+
cursor: pointer;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.phone-sheet__close:hover,
|
|
203
|
+
.phone-sheet__close:focus-visible {
|
|
204
|
+
background: var(--smrt-color-surface-container-high);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.phone-sheet__close:focus-visible {
|
|
208
|
+
outline: 2px solid var(--smrt-color-primary);
|
|
209
|
+
outline-offset: -2px;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.phone-sheet__body {
|
|
213
|
+
min-block-size: 0;
|
|
214
|
+
overflow: auto;
|
|
215
|
+
overscroll-behavior: contain;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
@media (prefers-reduced-motion: reduce) {
|
|
219
|
+
.phone-sheet,
|
|
220
|
+
.phone-sheet.open {
|
|
221
|
+
transition: none;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
</style>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PhoneSheet — the phone replacement for drawers and centered modals.
|
|
3
|
+
*
|
|
4
|
+
* - `variant="page"`: a full-screen page (a notifications list, a picker);
|
|
5
|
+
* - `variant="sheet"`: slides up from the bottom with a grabber; a swipe down
|
|
6
|
+
* on its header closes it.
|
|
7
|
+
*
|
|
8
|
+
* It closes on its close button and Escape, moves focus into itself when it
|
|
9
|
+
* opens, and returns focus to the opener when it closes. It is positioned
|
|
10
|
+
* `absolute; inset: 0`, so it covers its nearest positioned ancestor — inside
|
|
11
|
+
* an `AdminShell`, render it in the `overlays` snippet so it covers the
|
|
12
|
+
* screen above the phone bottom bar. The host may keep it mounted while
|
|
13
|
+
* closed (it is hidden and inert), so a chat inside keeps its draft.
|
|
14
|
+
*/
|
|
15
|
+
import type { Snippet } from 'svelte';
|
|
16
|
+
export interface Props {
|
|
17
|
+
/** Whether the sheet is shown. */
|
|
18
|
+
open: boolean;
|
|
19
|
+
/** Heading shown in the sheet header; also names the dialog. */
|
|
20
|
+
title: string;
|
|
21
|
+
/** Called on the close button, Escape, or a swipe down (sheet). */
|
|
22
|
+
onclose: () => void;
|
|
23
|
+
/** `page` covers the area; `sheet` slides up with rounded corners. */
|
|
24
|
+
variant?: 'page' | 'sheet';
|
|
25
|
+
/** Element id, for `aria-controls` on the button that opens it. */
|
|
26
|
+
id?: string;
|
|
27
|
+
/** Accessible name of the close button (default "Close {title}"). */
|
|
28
|
+
closeLabel?: string;
|
|
29
|
+
/** Sheet body. */
|
|
30
|
+
children: Snippet;
|
|
31
|
+
}
|
|
32
|
+
declare const PhoneSheet: import("svelte").Component<Props, {}, "">;
|
|
33
|
+
type PhoneSheet = ReturnType<typeof PhoneSheet>;
|
|
34
|
+
export default PhoneSheet;
|
|
35
|
+
//# sourceMappingURL=PhoneSheet.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PhoneSheet.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/feedback/PhoneSheet.svelte.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAOtC,MAAM,WAAW,KAAK;IACpB,kCAAkC;IAClC,IAAI,EAAE,OAAO,CAAC;IACd,gEAAgE;IAChE,KAAK,EAAE,MAAM,CAAC;IACd,mEAAmE;IACnE,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC3B,mEAAmE;IACnE,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,qEAAqE;IACrE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kBAAkB;IAClB,QAAQ,EAAE,OAAO,CAAC;CACnB;AA2ED,QAAA,MAAM,UAAU,2CAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
|
|
@@ -10,7 +10,17 @@ export interface Props {
|
|
|
10
10
|
/** Toaster instance that manages the toast queue. */
|
|
11
11
|
toaster?: Toaster;
|
|
12
12
|
/** Screen corner where toasts appear. */
|
|
13
|
-
position?:
|
|
13
|
+
position?:
|
|
14
|
+
| 'top-start'
|
|
15
|
+
| 'top-center'
|
|
16
|
+
| 'top-end'
|
|
17
|
+
| 'bottom-start'
|
|
18
|
+
| 'bottom-center'
|
|
19
|
+
| 'bottom-end';
|
|
20
|
+
/** CSS length inset from the window or anchor region. */
|
|
21
|
+
inset?: string;
|
|
22
|
+
/** Optional content region used for toast placement. */
|
|
23
|
+
anchor?: HTMLElement | null;
|
|
14
24
|
/** CSS class to apply to the viewport container. */
|
|
15
25
|
class?: string;
|
|
16
26
|
}
|
|
@@ -18,10 +28,131 @@ let {
|
|
|
18
28
|
toaster = defaultToaster,
|
|
19
29
|
position = 'bottom-end',
|
|
20
30
|
class: className = '',
|
|
31
|
+
inset = 'var(--smrt-spacing-4, 1rem)',
|
|
32
|
+
anchor = null,
|
|
21
33
|
}: Props = $props();
|
|
34
|
+
const instanceId = $props.id();
|
|
35
|
+
const hoverReason = `${instanceId}-hover`;
|
|
36
|
+
const focusReason = `${instanceId}-focus`;
|
|
22
37
|
let toasts = $state<Toast[]>([]);
|
|
38
|
+
let bounds = $state<{
|
|
39
|
+
top: number;
|
|
40
|
+
right: number;
|
|
41
|
+
bottom: number;
|
|
42
|
+
left: number;
|
|
43
|
+
width: number;
|
|
44
|
+
} | null>(null);
|
|
23
45
|
|
|
24
|
-
$effect(() =>
|
|
46
|
+
$effect(() => {
|
|
47
|
+
if (!anchor) {
|
|
48
|
+
bounds = null;
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const region = anchor;
|
|
52
|
+
function measure() {
|
|
53
|
+
const rect = region.getBoundingClientRect();
|
|
54
|
+
bounds = {
|
|
55
|
+
top: rect.top,
|
|
56
|
+
right: window.innerWidth - rect.right,
|
|
57
|
+
bottom: window.innerHeight - rect.bottom,
|
|
58
|
+
left: rect.left,
|
|
59
|
+
width: rect.width,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
measure();
|
|
63
|
+
const observer = new ResizeObserver(measure);
|
|
64
|
+
observer.observe(region);
|
|
65
|
+
window.addEventListener('resize', measure);
|
|
66
|
+
document.addEventListener('scroll', measure, true);
|
|
67
|
+
return () => {
|
|
68
|
+
observer.disconnect();
|
|
69
|
+
window.removeEventListener('resize', measure);
|
|
70
|
+
document.removeEventListener('scroll', measure, true);
|
|
71
|
+
};
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// A popover outside the topmost modal remains inert. Keep the live region and
|
|
75
|
+
// its controls inside the active dialog instead, preserving their Svelte owner.
|
|
76
|
+
function followModal(node: HTMLElement) {
|
|
77
|
+
const marker = document.createComment('toast viewport host');
|
|
78
|
+
node.before(marker);
|
|
79
|
+
let stack: HTMLDialogElement[] = [];
|
|
80
|
+
function update(records: MutationRecord[] = []) {
|
|
81
|
+
const dialogs = Array.from(
|
|
82
|
+
document.querySelectorAll<HTMLDialogElement>('dialog[open]'),
|
|
83
|
+
).filter((dialog) => dialog.matches(':modal'));
|
|
84
|
+
stack = stack.filter((dialog) => dialogs.includes(dialog));
|
|
85
|
+
for (const dialog of dialogs)
|
|
86
|
+
if (!stack.includes(dialog)) stack.push(dialog);
|
|
87
|
+
for (const record of records) {
|
|
88
|
+
if (record.type !== 'attributes' || record.attributeName !== 'open')
|
|
89
|
+
continue;
|
|
90
|
+
const dialog = record.target as HTMLDialogElement;
|
|
91
|
+
if (!dialogs.includes(dialog)) continue;
|
|
92
|
+
stack = [...stack.filter((item) => item !== dialog), dialog];
|
|
93
|
+
}
|
|
94
|
+
const focused = dialogs
|
|
95
|
+
.filter((dialog) => dialog.contains(document.activeElement))
|
|
96
|
+
.at(-1);
|
|
97
|
+
if (focused)
|
|
98
|
+
stack = [...stack.filter((dialog) => dialog !== focused), focused];
|
|
99
|
+
const host = stack.at(-1) ?? marker.parentElement;
|
|
100
|
+
if (!host || node.parentElement === host) return;
|
|
101
|
+
const active = node.contains(document.activeElement)
|
|
102
|
+
? (document.activeElement as HTMLElement)
|
|
103
|
+
: null;
|
|
104
|
+
if (host === marker.parentElement) marker.after(node);
|
|
105
|
+
else host.append(node);
|
|
106
|
+
active?.focus();
|
|
107
|
+
if (!node.contains(document.activeElement)) {
|
|
108
|
+
for (const toast of toasts) toaster.resume?.(toast.id, focusReason);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
update();
|
|
112
|
+
const observer = new MutationObserver(update);
|
|
113
|
+
observer.observe(document.documentElement, {
|
|
114
|
+
subtree: true,
|
|
115
|
+
childList: true,
|
|
116
|
+
attributes: true,
|
|
117
|
+
attributeFilter: ['open'],
|
|
118
|
+
});
|
|
119
|
+
const focus = () => update();
|
|
120
|
+
document.addEventListener('focusin', focus);
|
|
121
|
+
return {
|
|
122
|
+
destroy() {
|
|
123
|
+
observer.disconnect();
|
|
124
|
+
document.removeEventListener('focusin', focus);
|
|
125
|
+
marker.remove();
|
|
126
|
+
node.remove();
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function handleFocusOut(event: FocusEvent, id: string) {
|
|
132
|
+
if (
|
|
133
|
+
event.currentTarget instanceof HTMLElement &&
|
|
134
|
+
event.relatedTarget instanceof Node &&
|
|
135
|
+
event.currentTarget.contains(event.relatedTarget)
|
|
136
|
+
)
|
|
137
|
+
return;
|
|
138
|
+
toaster.resume?.(id, focusReason);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
$effect(() => {
|
|
142
|
+
const queue = toaster;
|
|
143
|
+
let ids: string[] = [];
|
|
144
|
+
const unsubscribe = queue.subscribe((next) => {
|
|
145
|
+
ids = next.map((toast) => toast.id);
|
|
146
|
+
toasts = next;
|
|
147
|
+
});
|
|
148
|
+
return () => {
|
|
149
|
+
unsubscribe();
|
|
150
|
+
for (const id of ids) {
|
|
151
|
+
queue.resume?.(id, hoverReason);
|
|
152
|
+
queue.resume?.(id, focusReason);
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
});
|
|
25
156
|
|
|
26
157
|
async function runAction(toast: Toast) {
|
|
27
158
|
await toast.action?.run();
|
|
@@ -29,23 +160,40 @@ async function runAction(toast: Toast) {
|
|
|
29
160
|
}
|
|
30
161
|
</script>
|
|
31
162
|
|
|
32
|
-
<section class="viewport viewport--{position} {className}" aria-label="Notifications" aria-live="polite"
|
|
163
|
+
<section use:followModal class="viewport viewport--{position} {className}" aria-label="Notifications" aria-live="polite"
|
|
164
|
+
style:--toast-inset={inset}
|
|
165
|
+
style:--toast-top={bounds ? `${bounds.top}px` : undefined}
|
|
166
|
+
style:--toast-right={bounds ? `${bounds.right}px` : undefined}
|
|
167
|
+
style:--toast-bottom={bounds ? `${bounds.bottom}px` : undefined}
|
|
168
|
+
style:--toast-left={bounds ? `${bounds.left}px` : undefined}
|
|
169
|
+
style:--toast-region-width={bounds ? `${bounds.width}px` : undefined}
|
|
170
|
+
>
|
|
33
171
|
{#each toasts as toast (toast.id)}
|
|
172
|
+
<div role="group" aria-label={toast.title ?? 'Notification'}
|
|
173
|
+
onmouseenter={() => toaster.pause?.(toast.id, hoverReason)}
|
|
174
|
+
onmouseleave={() => toaster.resume?.(toast.id, hoverReason)}
|
|
175
|
+
onfocusin={() => toaster.pause?.(toast.id, focusReason)}
|
|
176
|
+
onfocusout={(event) => handleFocusOut(event, toast.id)}
|
|
177
|
+
>
|
|
34
178
|
<Alert variant={toast.variant} title={toast.title} dismissible ondismiss={() => toaster.dismiss(toast.id)}>
|
|
35
179
|
{toast.message}
|
|
36
180
|
{#snippet action()}
|
|
37
181
|
{#if toast.action}<button type="button" onclick={() => runAction(toast)}>{toast.action.label}</button>{/if}
|
|
38
182
|
{/snippet}
|
|
39
183
|
</Alert>
|
|
184
|
+
</div>
|
|
40
185
|
{/each}
|
|
41
186
|
</section>
|
|
42
187
|
|
|
43
188
|
<style>
|
|
44
|
-
.viewport { position: fixed; z-index: var(--smrt-z-index-toast, 1200); display: grid; width: min(24rem, calc(100vw - 2 * var(--
|
|
189
|
+
.viewport { position: fixed; z-index: var(--smrt-z-index-toast, 1200); display: grid; width: min(24rem, calc(var(--toast-region-width, 100vw) - 2 * var(--toast-inset))); gap: var(--smrt-spacing-2); pointer-events: none; }
|
|
45
190
|
.viewport :global(.alert) { pointer-events: auto; box-shadow: var(--smrt-elevation-3); }
|
|
46
|
-
.viewport--top-start { top: var(--
|
|
47
|
-
.viewport--top-end { top: var(--
|
|
48
|
-
.viewport--bottom-start { bottom: var(--
|
|
49
|
-
.viewport--bottom-end { right: var(--
|
|
191
|
+
.viewport--top-start { top: calc(var(--toast-top, 0px) + var(--toast-inset)); left: calc(var(--toast-left, 0px) + var(--toast-inset)); }
|
|
192
|
+
.viewport--top-end { top: calc(var(--toast-top, 0px) + var(--toast-inset)); right: calc(var(--toast-right, 0px) + var(--toast-inset)); }
|
|
193
|
+
.viewport--bottom-start { bottom: calc(var(--toast-bottom, 0px) + var(--toast-inset)); left: calc(var(--toast-left, 0px) + var(--toast-inset)); }
|
|
194
|
+
.viewport--bottom-end { right: calc(var(--toast-right, 0px) + var(--toast-inset)); bottom: calc(var(--toast-bottom, 0px) + var(--toast-inset)); }
|
|
195
|
+
.viewport--top-center, .viewport--bottom-center { left: calc(var(--toast-left, 0px) + var(--toast-region-width, 100vw) / 2); transform: translateX(-50%); }
|
|
196
|
+
.viewport--top-center { top: calc(var(--toast-top, 0px) + var(--toast-inset)); }
|
|
197
|
+
.viewport--bottom-center { bottom: calc(var(--toast-bottom, 0px) + var(--toast-inset)); }
|
|
50
198
|
button { padding: var(--smrt-spacing-1) var(--smrt-spacing-2); border: 1px solid currentColor; border-radius: var(--smrt-radius-small); background: transparent; color: inherit; font: inherit; cursor: pointer; }
|
|
51
199
|
</style>
|