@happyvertical/smrt-ui 0.51.39 → 0.53.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +25 -3
- package/README.md +558 -8
- package/dist/actions/__tests__/swipe-dismiss.test.js +69 -0
- package/dist/actions/swipe-dismiss.d.ts +42 -0
- package/dist/actions/swipe-dismiss.d.ts.map +1 -0
- package/dist/actions/swipe-dismiss.js +69 -0
- package/dist/components/calendar/Calendar.svelte +5 -0
- package/dist/components/calendar/Calendar.svelte.d.ts.map +1 -1
- package/dist/components/calendar/CalendarView.svelte +1250 -0
- package/dist/components/calendar/CalendarView.svelte.d.ts +66 -0
- package/dist/components/calendar/CalendarView.svelte.d.ts.map +1 -0
- package/dist/components/calendar/DayView.svelte +5 -0
- package/dist/components/calendar/DayView.svelte.d.ts.map +1 -1
- package/dist/components/calendar/__tests__/CalendarView.test.js +226 -0
- package/dist/components/calendar/__tests__/calendar-model.test.js +138 -0
- package/dist/components/calendar/calendar-model.d.ts +178 -0
- package/dist/components/calendar/calendar-model.d.ts.map +1 -0
- package/dist/components/calendar/calendar-model.js +362 -0
- package/dist/components/calendar/index.d.ts +12 -1
- package/dist/components/calendar/index.d.ts.map +1 -1
- package/dist/components/calendar/index.js +11 -1
- package/dist/components/data/CollectionList.svelte +23 -5
- package/dist/components/data/CollectionList.svelte.d.ts +8 -2
- package/dist/components/data/CollectionList.svelte.d.ts.map +1 -1
- package/dist/components/data/DataTable.svelte +178 -55
- package/dist/components/data/DataTable.svelte.d.ts.map +1 -1
- package/dist/components/data/DataTableController.d.ts +4 -0
- package/dist/components/data/DataTableController.d.ts.map +1 -1
- package/dist/components/data/DataTableController.js +11 -4
- package/dist/components/data/DataTableResponsive.d.ts +4 -0
- package/dist/components/data/DataTableResponsive.d.ts.map +1 -0
- package/dist/components/data/DataTableResponsive.js +22 -0
- package/dist/components/data/ListSortSelect.svelte +121 -0
- package/dist/components/data/ListSortSelect.svelte.d.ts +22 -0
- package/dist/components/data/ListSortSelect.svelte.d.ts.map +1 -0
- package/dist/components/data/SortableHeader.svelte +169 -0
- package/dist/components/data/SortableHeader.svelte.d.ts +30 -0
- package/dist/components/data/SortableHeader.svelte.d.ts.map +1 -0
- package/dist/components/data/__tests__/CollectionList.test.js +37 -0
- package/dist/components/data/__tests__/DataTable.test.js +76 -0
- package/dist/components/data/__tests__/DataTableController.test.js +35 -0
- package/dist/components/data/__tests__/DataTableResponsive.test.js +80 -0
- package/dist/components/data/__tests__/SortableHeader.test.js +101 -0
- package/dist/components/data/__tests__/link-step-surface.test.js +172 -0
- package/dist/components/data/__tests__/list-sort-state.svelte.test.js +71 -0
- package/dist/components/data/__tests__/list-sort.test.js +91 -0
- package/dist/components/data/__tests__/responsive-table.fixture.svelte +29 -0
- package/dist/components/data/__tests__/responsive-table.fixture.svelte.d.ts +7 -0
- package/dist/components/data/__tests__/responsive-table.fixture.svelte.d.ts.map +1 -0
- package/dist/components/data/__tests__/surface-navigation.test.js +121 -0
- package/dist/components/data/data-surface.d.ts +1 -0
- package/dist/components/data/data-surface.d.ts.map +1 -1
- package/dist/components/data/data-surface.js +1 -0
- package/dist/components/data/index.d.ts +6 -0
- package/dist/components/data/index.d.ts.map +1 -1
- package/dist/components/data/index.js +6 -0
- package/dist/components/data/link-surface.d.ts +79 -0
- package/dist/components/data/link-surface.d.ts.map +1 -0
- package/dist/components/data/link-surface.js +155 -0
- package/dist/components/data/list-sort-state.svelte.d.ts +39 -0
- package/dist/components/data/list-sort-state.svelte.d.ts.map +1 -0
- package/dist/components/data/list-sort-state.svelte.js +47 -0
- package/dist/components/data/list-sort.d.ts +94 -0
- package/dist/components/data/list-sort.d.ts.map +1 -0
- package/dist/components/data/list-sort.js +182 -0
- package/dist/components/data/step-surface.d.ts +73 -0
- package/dist/components/data/step-surface.d.ts.map +1 -0
- package/dist/components/data/step-surface.js +177 -0
- package/dist/components/data/surface-navigation.d.ts +49 -0
- package/dist/components/data/surface-navigation.d.ts.map +1 -0
- package/dist/components/data/surface-navigation.js +100 -0
- package/dist/components/data/types.d.ts +27 -0
- package/dist/components/data/types.d.ts.map +1 -1
- package/dist/components/display/DateDisplay.svelte +76 -14
- package/dist/components/display/DateDisplay.svelte.d.ts +2 -0
- package/dist/components/display/DateDisplay.svelte.d.ts.map +1 -1
- package/dist/components/display/Icon.svelte +3 -16
- package/dist/components/display/Icon.svelte.d.ts +0 -9
- package/dist/components/display/Icon.svelte.d.ts.map +1 -1
- package/dist/components/display/StatusBadge.svelte +29 -2
- package/dist/components/display/StatusBadge.svelte.d.ts +4 -2
- package/dist/components/display/StatusBadge.svelte.d.ts.map +1 -1
- package/dist/components/display/__tests__/DateDisplay.test.js +82 -1
- package/dist/components/display/__tests__/Icon.test.js +132 -2
- package/dist/components/display/__tests__/StatusBadge.test.js +78 -0
- package/dist/components/display/icons.svelte.d.ts +11 -0
- package/dist/components/display/icons.svelte.d.ts.map +1 -0
- package/dist/components/display/icons.svelte.js +60 -0
- package/dist/components/display/index.d.ts +3 -1
- package/dist/components/display/index.d.ts.map +1 -1
- package/dist/components/display/index.js +1 -0
- package/dist/components/display/types.d.ts +2 -0
- package/dist/components/display/types.d.ts.map +1 -1
- package/dist/components/feedback/ConfirmDialog.svelte +59 -48
- package/dist/components/feedback/ConfirmDialog.svelte.d.ts +14 -2
- package/dist/components/feedback/ConfirmDialog.svelte.d.ts.map +1 -1
- package/dist/components/feedback/PhoneSheet.svelte +224 -0
- package/dist/components/feedback/PhoneSheet.svelte.d.ts +35 -0
- package/dist/components/feedback/PhoneSheet.svelte.d.ts.map +1 -0
- package/dist/components/feedback/ToastViewport.svelte +156 -8
- package/dist/components/feedback/ToastViewport.svelte.d.ts +5 -1
- package/dist/components/feedback/ToastViewport.svelte.d.ts.map +1 -1
- package/dist/components/feedback/WorkingStrip.svelte +426 -0
- package/dist/components/feedback/WorkingStrip.svelte.d.ts +37 -0
- package/dist/components/feedback/WorkingStrip.svelte.d.ts.map +1 -0
- package/dist/components/feedback/__tests__/ConfirmDialog.test.js +38 -20
- package/dist/components/feedback/__tests__/PhoneSheet.test.js +101 -0
- package/dist/components/feedback/__tests__/WorkingStrip.test.js +172 -0
- package/dist/components/feedback/__tests__/confirm-message.fixture.svelte +9 -0
- package/dist/components/feedback/__tests__/confirm-message.fixture.svelte.d.ts +19 -0
- package/dist/components/feedback/__tests__/confirm-message.fixture.svelte.d.ts.map +1 -0
- package/dist/components/feedback/__tests__/toast.test.js +142 -1
- package/dist/components/feedback/index.d.ts +5 -1
- package/dist/components/feedback/index.d.ts.map +1 -1
- package/dist/components/feedback/index.js +5 -0
- package/dist/components/feedback/toast.d.ts +13 -1
- package/dist/components/feedback/toast.d.ts.map +1 -1
- package/dist/components/feedback/toast.js +51 -10
- package/dist/components/feedback/working-status.d.ts +34 -0
- package/dist/components/feedback/working-status.d.ts.map +1 -0
- package/dist/components/feedback/working-status.js +5 -0
- package/dist/components/forms/CameraCapture.svelte +619 -0
- package/dist/components/forms/CameraCapture.svelte.d.ts +42 -0
- package/dist/components/forms/CameraCapture.svelte.d.ts.map +1 -0
- package/dist/components/forms/Checkbox.svelte +34 -3
- package/dist/components/forms/Checkbox.svelte.d.ts +2 -0
- package/dist/components/forms/Checkbox.svelte.d.ts.map +1 -1
- package/dist/components/forms/Combobox.svelte +108 -12
- package/dist/components/forms/Combobox.svelte.d.ts +6 -0
- package/dist/components/forms/Combobox.svelte.d.ts.map +1 -1
- package/dist/components/forms/DictationButton.svelte +128 -0
- package/dist/components/forms/DictationButton.svelte.d.ts +19 -0
- package/dist/components/forms/DictationButton.svelte.d.ts.map +1 -0
- package/dist/components/forms/DictationStatus.svelte +164 -0
- package/dist/components/forms/DictationStatus.svelte.d.ts +11 -0
- package/dist/components/forms/DictationStatus.svelte.d.ts.map +1 -0
- package/dist/components/forms/Fieldset.svelte +5 -1
- package/dist/components/forms/Fieldset.svelte.d.ts +2 -0
- package/dist/components/forms/Fieldset.svelte.d.ts.map +1 -1
- package/dist/components/forms/Form.svelte +5 -0
- package/dist/components/forms/Form.svelte.d.ts +1 -0
- package/dist/components/forms/Form.svelte.d.ts.map +1 -1
- package/dist/components/forms/FormActionBar.svelte +84 -0
- package/dist/components/forms/FormActionBar.svelte.d.ts +23 -0
- package/dist/components/forms/FormActionBar.svelte.d.ts.map +1 -0
- package/dist/components/forms/Input.svelte +17 -1
- package/dist/components/forms/Input.svelte.d.ts +2 -0
- package/dist/components/forms/Input.svelte.d.ts.map +1 -1
- package/dist/components/forms/Listbox.svelte +39 -1
- package/dist/components/forms/Listbox.svelte.d.ts.map +1 -1
- package/dist/components/forms/MultiSelect.svelte +41 -1
- package/dist/components/forms/MultiSelect.svelte.d.ts.map +1 -1
- package/dist/components/forms/Radio.svelte +16 -4
- package/dist/components/forms/RadioGroup.svelte +7 -1
- package/dist/components/forms/RadioGroup.svelte.d.ts +2 -0
- package/dist/components/forms/RadioGroup.svelte.d.ts.map +1 -1
- package/dist/components/forms/SearchInput.svelte +207 -0
- package/dist/components/forms/SearchInput.svelte.d.ts +22 -0
- package/dist/components/forms/SearchInput.svelte.d.ts.map +1 -0
- package/dist/components/forms/SegmentedControl.svelte +152 -11
- package/dist/components/forms/SegmentedControl.svelte.d.ts +4 -0
- package/dist/components/forms/SegmentedControl.svelte.d.ts.map +1 -1
- package/dist/components/forms/Select.svelte +17 -1
- package/dist/components/forms/Select.svelte.d.ts +2 -0
- package/dist/components/forms/Select.svelte.d.ts.map +1 -1
- package/dist/components/forms/SignaturePad.svelte +436 -0
- package/dist/components/forms/SignaturePad.svelte.d.ts +32 -0
- package/dist/components/forms/SignaturePad.svelte.d.ts.map +1 -0
- package/dist/components/forms/StagedControlReview.svelte +21 -12
- package/dist/components/forms/StagedControlReview.svelte.d.ts.map +1 -1
- package/dist/components/forms/Switch.svelte +18 -5
- package/dist/components/forms/Switch.svelte.d.ts +2 -0
- package/dist/components/forms/Switch.svelte.d.ts.map +1 -1
- package/dist/components/forms/TagsInput.svelte +8 -1
- package/dist/components/forms/Textarea.svelte +16 -1
- package/dist/components/forms/Textarea.svelte.d.ts +2 -0
- package/dist/components/forms/Textarea.svelte.d.ts.map +1 -1
- package/dist/components/forms/__tests__/CameraCapture.test.js +504 -0
- package/dist/components/forms/__tests__/Combobox.test.js +354 -0
- package/dist/components/forms/__tests__/ControlHitArea.test.js +73 -0
- package/dist/components/forms/__tests__/DictationButton.test.js +176 -0
- package/dist/components/forms/__tests__/Fieldset.test.js +37 -0
- package/dist/components/forms/__tests__/Form.test.js +46 -0
- package/dist/components/forms/__tests__/FormActionBar.test.js +22 -0
- package/dist/components/forms/__tests__/Listbox.test.js +303 -0
- package/dist/components/forms/__tests__/MultiSelect.test.js +281 -0
- package/dist/components/forms/__tests__/SearchInput.test.js +92 -0
- package/dist/components/forms/__tests__/SignaturePad.test.js +338 -0
- package/dist/components/forms/__tests__/StagedControlReview.test.js +37 -3
- package/dist/components/forms/__tests__/camera-capture-session.test.js +207 -0
- package/dist/components/forms/__tests__/capture-form-retry.test.js +166 -0
- package/dist/components/forms/__tests__/capture-form.fixture.svelte +38 -0
- package/dist/components/forms/__tests__/capture-form.fixture.svelte.d.ts +10 -0
- package/dist/components/forms/__tests__/capture-form.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/capture-test-env.d.ts +70 -0
- package/dist/components/forms/__tests__/capture-test-env.d.ts.map +1 -0
- package/dist/components/forms/__tests__/capture-test-env.js +122 -0
- package/dist/components/forms/__tests__/capture-touch.fixture.svelte +15 -0
- package/dist/components/forms/__tests__/capture-touch.fixture.svelte.d.ts +8 -0
- package/dist/components/forms/__tests__/capture-touch.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/combobox-form.fixture.svelte +29 -0
- package/dist/components/forms/__tests__/combobox-form.fixture.svelte.d.ts +14 -0
- package/dist/components/forms/__tests__/combobox-form.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/combobox-labels.fixture.svelte +19 -0
- package/dist/components/forms/__tests__/combobox-labels.fixture.svelte.d.ts +11 -0
- package/dist/components/forms/__tests__/combobox-labels.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/composite-registration.fixture.svelte +29 -0
- package/dist/components/forms/__tests__/composite-registration.fixture.svelte.d.ts +8 -0
- package/dist/components/forms/__tests__/composite-registration.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/control-interaction.test.js +19 -1
- package/dist/components/forms/__tests__/control-proposals.test.js +63 -0
- package/dist/components/forms/__tests__/dictation-recording.test.js +582 -0
- package/dist/components/forms/__tests__/dictation.test.js +486 -0
- package/dist/components/forms/__tests__/form-attachment.fixture.svelte +28 -0
- package/dist/components/forms/__tests__/form-attachment.fixture.svelte.d.ts +11 -0
- package/dist/components/forms/__tests__/form-attachment.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/form-retry-form.fixture.svelte +31 -0
- package/dist/components/forms/__tests__/form-retry-form.fixture.svelte.d.ts +13 -0
- package/dist/components/forms/__tests__/form-retry-form.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/form-retry-form.test.js +107 -0
- package/dist/components/forms/__tests__/hidden-controls-form-retry.test.js +69 -0
- package/dist/components/forms/__tests__/hidden-controls-form.fixture.svelte +29 -0
- package/dist/components/forms/__tests__/hidden-controls-form.fixture.svelte.d.ts +9 -0
- package/dist/components/forms/__tests__/hidden-controls-form.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/listbox-form.fixture.svelte +27 -0
- package/dist/components/forms/__tests__/listbox-form.fixture.svelte.d.ts +13 -0
- package/dist/components/forms/__tests__/listbox-form.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/long-press.test.js +175 -0
- package/dist/components/forms/__tests__/multiselect-form.fixture.svelte +27 -0
- package/dist/components/forms/__tests__/multiselect-form.fixture.svelte.d.ts +13 -0
- package/dist/components/forms/__tests__/multiselect-form.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/native-file-field.test.js +177 -0
- package/dist/components/forms/__tests__/place-picker.fixture.svelte +33 -0
- package/dist/components/forms/__tests__/place-picker.fixture.svelte.d.ts +12 -0
- package/dist/components/forms/__tests__/place-picker.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/segmented-posting.fixture.svelte +28 -0
- package/dist/components/forms/__tests__/segmented-posting.fixture.svelte.d.ts +12 -0
- package/dist/components/forms/__tests__/segmented-posting.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/segmented-posting.test.js +92 -0
- package/dist/components/forms/__tests__/signature-pad-logic.test.js +54 -0
- package/dist/components/forms/__tests__/touch-density.fixture.svelte +34 -0
- package/dist/components/forms/__tests__/touch-density.fixture.svelte.d.ts +8 -0
- package/dist/components/forms/__tests__/touch-density.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/touch-density.test.js +66 -0
- package/dist/components/forms/audio-capture.d.ts +69 -0
- package/dist/components/forms/audio-capture.d.ts.map +1 -0
- package/dist/components/forms/audio-capture.js +193 -0
- package/dist/components/forms/camera-capture-session.d.ts +81 -0
- package/dist/components/forms/camera-capture-session.d.ts.map +1 -0
- package/dist/components/forms/camera-capture-session.js +130 -0
- package/dist/components/forms/control-interaction.d.ts +6 -0
- package/dist/components/forms/control-interaction.d.ts.map +1 -1
- package/dist/components/forms/control-interaction.js +12 -1
- package/dist/components/forms/control-proposals.d.ts +55 -0
- package/dist/components/forms/control-proposals.d.ts.map +1 -0
- package/dist/components/forms/control-proposals.js +188 -0
- package/dist/components/forms/dictation-transcribe.d.ts +36 -0
- package/dist/components/forms/dictation-transcribe.d.ts.map +1 -0
- package/dist/components/forms/dictation-transcribe.js +65 -0
- package/dist/components/forms/dictation.svelte.d.ts +200 -0
- package/dist/components/forms/dictation.svelte.d.ts.map +1 -0
- package/dist/components/forms/dictation.svelte.js +686 -0
- package/dist/components/forms/form-retry/__tests__/boundaries.test.js +23 -0
- package/dist/components/forms/form-retry/__tests__/content-digest.test.js +70 -0
- package/dist/components/forms/form-retry/__tests__/controller.test.js +802 -0
- package/dist/components/forms/form-retry/__tests__/fake-kit.d.ts +82 -0
- package/dist/components/forms/form-retry/__tests__/fake-kit.d.ts.map +1 -0
- package/dist/components/forms/form-retry/__tests__/fake-kit.js +180 -0
- package/dist/components/forms/form-retry/__tests__/form-draft.test.js +169 -0
- package/dist/components/forms/form-retry/__tests__/ssr.test.js +37 -0
- package/dist/components/forms/form-retry/__tests__/storage.d.ts +26 -0
- package/dist/components/forms/form-retry/__tests__/storage.d.ts.map +1 -0
- package/dist/components/forms/form-retry/__tests__/storage.js +63 -0
- package/dist/components/forms/form-retry/__tests__/submission-key.test.js +236 -0
- package/dist/components/forms/form-retry/__tests__/submitted-draft.test.js +334 -0
- package/dist/components/forms/form-retry/content-digest.d.ts +54 -0
- package/dist/components/forms/form-retry/content-digest.d.ts.map +1 -0
- package/dist/components/forms/form-retry/content-digest.js +169 -0
- package/dist/components/forms/form-retry/controller.d.ts +214 -0
- package/dist/components/forms/form-retry/controller.d.ts.map +1 -0
- package/dist/components/forms/form-retry/controller.js +404 -0
- package/dist/components/forms/form-retry/form-draft.d.ts +68 -0
- package/dist/components/forms/form-retry/form-draft.d.ts.map +1 -0
- package/dist/components/forms/form-retry/form-draft.js +161 -0
- package/dist/components/forms/form-retry/index.d.ts +19 -0
- package/dist/components/forms/form-retry/index.d.ts.map +1 -0
- package/dist/components/forms/form-retry/index.js +16 -0
- package/dist/components/forms/form-retry/submission-key.d.ts +244 -0
- package/dist/components/forms/form-retry/submission-key.d.ts.map +1 -0
- package/dist/components/forms/form-retry/submission-key.js +342 -0
- package/dist/components/forms/form-retry/submitted-draft.d.ts +112 -0
- package/dist/components/forms/form-retry/submitted-draft.d.ts.map +1 -0
- package/dist/components/forms/form-retry/submitted-draft.js +270 -0
- package/dist/components/forms/form-retry/types.d.ts +84 -0
- package/dist/components/forms/form-retry/types.d.ts.map +1 -0
- package/dist/components/forms/form-retry/types.js +13 -0
- package/dist/components/forms/index.d.ts +21 -2
- package/dist/components/forms/index.d.ts.map +1 -1
- package/dist/components/forms/index.js +22 -1
- package/dist/components/forms/insert-text.d.ts +12 -0
- package/dist/components/forms/insert-text.d.ts.map +1 -0
- package/dist/components/forms/insert-text.js +38 -0
- package/dist/components/forms/long-press.d.ts +88 -0
- package/dist/components/forms/long-press.d.ts.map +1 -0
- package/dist/components/forms/long-press.js +213 -0
- package/dist/components/forms/native-file-field.d.ts +94 -0
- package/dist/components/forms/native-file-field.d.ts.map +1 -0
- package/dist/components/forms/native-file-field.js +147 -0
- package/dist/components/forms/ready-beep.d.ts +24 -0
- package/dist/components/forms/ready-beep.d.ts.map +1 -0
- package/dist/components/forms/ready-beep.js +82 -0
- package/dist/components/forms/signature-pad-logic.d.ts +50 -0
- package/dist/components/forms/signature-pad-logic.d.ts.map +1 -0
- package/dist/components/forms/signature-pad-logic.js +48 -0
- package/dist/components/forms/types.d.ts +41 -0
- package/dist/components/forms/types.d.ts.map +1 -1
- package/dist/components/layout/PageHeader.svelte +151 -17
- package/dist/components/layout/PageHeader.svelte.d.ts +47 -7
- package/dist/components/layout/PageHeader.svelte.d.ts.map +1 -1
- package/dist/components/layout/__tests__/PageHeader.test.js +87 -1
- package/dist/components/layout/index.d.ts +1 -0
- package/dist/components/layout/index.d.ts.map +1 -1
- package/dist/components/layout/index.js +1 -0
- package/dist/components/layout/page-header-context.d.ts +25 -0
- package/dist/components/layout/page-header-context.d.ts.map +1 -0
- package/dist/components/layout/page-header-context.js +16 -0
- package/dist/components/nav/FilterChips.svelte +8 -1
- package/dist/components/nav/FilterChips.svelte.d.ts +2 -0
- package/dist/components/nav/FilterChips.svelte.d.ts.map +1 -1
- package/dist/components/nav/Tabs.svelte +241 -0
- package/dist/components/nav/Tabs.svelte.d.ts +15 -0
- package/dist/components/nav/Tabs.svelte.d.ts.map +1 -1
- package/dist/components/nav/__tests__/LinkTabs.test.js +117 -0
- package/dist/components/nav/index.d.ts +1 -0
- package/dist/components/nav/index.d.ts.map +1 -1
- package/dist/components/nav/index.js +1 -0
- package/dist/components/nav/tabs-overflow.d.ts +12 -0
- package/dist/components/nav/tabs-overflow.d.ts.map +1 -0
- package/dist/components/nav/tabs-overflow.js +17 -0
- package/dist/components/nav/types.d.ts +8 -0
- package/dist/components/nav/types.d.ts.map +1 -1
- package/dist/components/ui/Button.svelte +16 -2
- package/dist/components/ui/Button.svelte.d.ts +2 -0
- package/dist/components/ui/Button.svelte.d.ts.map +1 -1
- package/dist/components/ui/Card.svelte +14 -5
- package/dist/components/ui/Dropdown.svelte +55 -1
- package/dist/components/ui/Dropdown.svelte.d.ts +8 -0
- package/dist/components/ui/Dropdown.svelte.d.ts.map +1 -1
- package/dist/components/ui/IconToggle.svelte +139 -0
- package/dist/components/ui/IconToggle.svelte.d.ts +32 -0
- package/dist/components/ui/IconToggle.svelte.d.ts.map +1 -0
- package/dist/components/ui/IconToggleGroup.svelte +56 -0
- package/dist/components/ui/IconToggleGroup.svelte.d.ts +21 -0
- package/dist/components/ui/IconToggleGroup.svelte.d.ts.map +1 -0
- package/dist/components/ui/Pagination.svelte +1 -1
- package/dist/components/ui/Popover.svelte +17 -1
- package/dist/components/ui/Popover.svelte.d.ts +8 -0
- package/dist/components/ui/Popover.svelte.d.ts.map +1 -1
- package/dist/components/ui/__tests__/IconToggle.test.js +59 -0
- package/dist/components/ui/__tests__/IconToggleGroup.test.js +30 -0
- package/dist/components/ui/__tests__/Popover.test.js +44 -0
- package/dist/components/ui/__tests__/dropdown-popover-icon.test.js +125 -0
- package/dist/components/ui/__tests__/phone-touch-targets.test.js +39 -0
- package/dist/components/ui/index.d.ts +2 -0
- package/dist/components/ui/index.d.ts.map +1 -1
- package/dist/components/ui/index.js +2 -0
- package/dist/i18n/strings.ui.d.ts +65 -0
- package/dist/i18n/strings.ui.d.ts.map +1 -1
- package/dist/i18n/strings.ui.js +72 -0
- package/dist/styles/tokens.css +2 -0
- package/dist/svelte/__tests__/playground.test.js +3 -1
- package/dist/svelte/playground/CalendarPreview.svelte +140 -0
- package/dist/svelte/playground/CalendarPreview.svelte.d.ts +4 -0
- package/dist/svelte/playground/CalendarPreview.svelte.d.ts.map +1 -0
- package/dist/svelte/playground/CapturePreview.svelte +56 -0
- package/dist/svelte/playground/CapturePreview.svelte.d.ts +4 -0
- package/dist/svelte/playground/CapturePreview.svelte.d.ts.map +1 -0
- package/dist/svelte/playground.d.ts.map +1 -1
- package/dist/svelte/playground.js +20 -0
- package/dist/themes/ThemeProvider.svelte +9 -0
- package/dist/themes/ThemeProvider.svelte.d.ts +2 -0
- package/dist/themes/ThemeProvider.svelte.d.ts.map +1 -1
- package/dist/themes/css-generator.d.ts.map +1 -1
- package/dist/themes/css-generator.js +3 -0
- package/dist/themes/styles/glass.css +4 -0
- package/dist/themes/styles/happyvertical.css +4 -0
- package/dist/themes/styles/material.css +4 -0
- package/dist/themes/styles/smrt.css +4 -0
- package/dist/themes/styles/studio.css +4 -0
- package/dist/types-generic.d.ts +2 -0
- package/dist/types-generic.d.ts.map +1 -1
- package/package.json +9 -3
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A short "ready" beep, made with the Web Audio API (no sound files).
|
|
3
|
+
*
|
|
4
|
+
* Browsers only start audio after a user gesture. A long press fires from a
|
|
5
|
+
* timer while the finger is still down, which on touch screens is not a
|
|
6
|
+
* gesture yet, so `playReadyBeep` resolves `false` when the audio could not
|
|
7
|
+
* start; the host plays it again from the release (`pointerup` is a gesture).
|
|
8
|
+
* `primeReadyBeep` creates the audio context early, from a gesture, so later
|
|
9
|
+
* beeps start immediately.
|
|
10
|
+
*/
|
|
11
|
+
let context = null;
|
|
12
|
+
function audioContextCtor() {
|
|
13
|
+
if (typeof window === 'undefined')
|
|
14
|
+
return null;
|
|
15
|
+
const w = window;
|
|
16
|
+
return (w.AudioContext ??
|
|
17
|
+
w.webkitAudioContext ??
|
|
18
|
+
null);
|
|
19
|
+
}
|
|
20
|
+
function getContext() {
|
|
21
|
+
if (context)
|
|
22
|
+
return context;
|
|
23
|
+
const Ctor = audioContextCtor();
|
|
24
|
+
if (!Ctor)
|
|
25
|
+
return null;
|
|
26
|
+
try {
|
|
27
|
+
context = new Ctor();
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
context = null;
|
|
31
|
+
}
|
|
32
|
+
return context;
|
|
33
|
+
}
|
|
34
|
+
/** Create (or wake) the audio context; call from a user gesture. */
|
|
35
|
+
export function primeReadyBeep() {
|
|
36
|
+
const ctx = getContext();
|
|
37
|
+
if (ctx && ctx.state === 'suspended') {
|
|
38
|
+
void ctx.resume().catch(() => undefined);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Play two quick rising tones (about 0.2s). Resolves `true` when it played,
|
|
43
|
+
* `false` when audio is unavailable or not allowed yet.
|
|
44
|
+
*/
|
|
45
|
+
export async function playReadyBeep(options = {}) {
|
|
46
|
+
const ctx = getContext();
|
|
47
|
+
if (!ctx)
|
|
48
|
+
return false;
|
|
49
|
+
try {
|
|
50
|
+
if (ctx.state === 'suspended')
|
|
51
|
+
await ctx.resume();
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
if (ctx.state !== 'running')
|
|
57
|
+
return false;
|
|
58
|
+
const volume = Math.max(0, Math.min(1, options.volume ?? 0.12));
|
|
59
|
+
const start = ctx.currentTime + 0.01;
|
|
60
|
+
const tones = [
|
|
61
|
+
[660, 0],
|
|
62
|
+
[990, 0.1],
|
|
63
|
+
];
|
|
64
|
+
for (const [frequency, at] of tones) {
|
|
65
|
+
const oscillator = ctx.createOscillator();
|
|
66
|
+
const gain = ctx.createGain();
|
|
67
|
+
oscillator.type = 'sine';
|
|
68
|
+
oscillator.frequency.value = frequency;
|
|
69
|
+
gain.gain.setValueAtTime(0, start + at);
|
|
70
|
+
gain.gain.linearRampToValueAtTime(volume, start + at + 0.01);
|
|
71
|
+
gain.gain.exponentialRampToValueAtTime(0.0001, start + at + 0.09);
|
|
72
|
+
oscillator.connect(gain);
|
|
73
|
+
gain.connect(ctx.destination);
|
|
74
|
+
oscillator.start(start + at);
|
|
75
|
+
oscillator.stop(start + at + 0.1);
|
|
76
|
+
}
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
/** Tests: forget the shared audio context. */
|
|
80
|
+
export function resetReadyBeepForTests() {
|
|
81
|
+
context = null;
|
|
82
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure input logic for `SignaturePad.svelte`: the pointer-type gate and the
|
|
3
|
+
* pointer-to-canvas coordinate mapping. Free of DOM and settings dependencies
|
|
4
|
+
* so both are testable without a browser. The component takes `stylusOnly` as a
|
|
5
|
+
* prop the caller resolves (from a tenant setting, a device profile, …) and
|
|
6
|
+
* never decides it itself.
|
|
7
|
+
*
|
|
8
|
+
* Ported from teamworks-os `signature-pad-logic.ts`, smrt#3290.
|
|
9
|
+
*/
|
|
10
|
+
/** `PointerEvent.pointerType`; browsers may report values beyond the three known ones. */
|
|
11
|
+
export type SignaturePointerType = 'pen' | 'touch' | 'mouse' | (string & {});
|
|
12
|
+
/**
|
|
13
|
+
* Paper and ink colours for the signature bitmap. A signature is document
|
|
14
|
+
* content, not chrome: it stays dark ink on white paper in every theme and
|
|
15
|
+
* colour scheme, so the exported PNG reads the same wherever it is shown.
|
|
16
|
+
*/
|
|
17
|
+
export declare const SIGNATURE_PAPER_COLOR = "#ffffff";
|
|
18
|
+
export declare const SIGNATURE_INK_COLOR = "#111111";
|
|
19
|
+
/**
|
|
20
|
+
* Whether a pointer of `pointerType` may draw a stroke.
|
|
21
|
+
*
|
|
22
|
+
* With `stylusOnly`, only `pen` is accepted: finger and mouse input are
|
|
23
|
+
* ignored outright, since nothing at the pointer-event level can tell a
|
|
24
|
+
* gloved finger from a stylus. Otherwise pen, touch and mouse are accepted.
|
|
25
|
+
* Unknown pointer types are rejected in both modes.
|
|
26
|
+
*/
|
|
27
|
+
export declare function isAcceptedPointerType(pointerType: SignaturePointerType, stylusOnly: boolean): boolean;
|
|
28
|
+
/** The subset of `DOMRect` the coordinate mapping needs. */
|
|
29
|
+
export interface CanvasDisplayRect {
|
|
30
|
+
left: number;
|
|
31
|
+
top: number;
|
|
32
|
+
width: number;
|
|
33
|
+
height: number;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Maps viewport `clientX`/`clientY` (CSS pixels) to the canvas's backing-pixel
|
|
37
|
+
* space.
|
|
38
|
+
*
|
|
39
|
+
* The canvas has a fixed backing resolution but is displayed at `width: 100%`,
|
|
40
|
+
* so the raw `clientX - rect.left` offset is only right when the displayed size
|
|
41
|
+
* happens to equal the backing size; anywhere else the ink drifts from the
|
|
42
|
+
* stylus and clips near the edges. Scaling by `backing / displayed` keeps them
|
|
43
|
+
* aligned. A zero-size rect (not laid out yet) falls back to 1:1 instead of
|
|
44
|
+
* dividing by zero.
|
|
45
|
+
*/
|
|
46
|
+
export declare function mapPointerToCanvasPoint(clientX: number, clientY: number, rect: CanvasDisplayRect, canvasWidth: number, canvasHeight: number): {
|
|
47
|
+
x: number;
|
|
48
|
+
y: number;
|
|
49
|
+
};
|
|
50
|
+
//# sourceMappingURL=signature-pad-logic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signature-pad-logic.d.ts","sourceRoot":"","sources":["../../../src/components/forms/signature-pad-logic.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,0FAA0F;AAC1F,MAAM,MAAM,oBAAoB,GAAG,KAAK,GAAG,OAAO,GAAG,OAAO,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAE7E;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,YAAY,CAAC;AAC/C,eAAO,MAAM,mBAAmB,YAAY,CAAC;AAE7C;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,oBAAoB,EACjC,UAAU,EAAE,OAAO,GAClB,OAAO,CAKT;AAED,4DAA4D;AAC5D,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,iBAAiB,EACvB,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,GACnB;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAO1B"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure input logic for `SignaturePad.svelte`: the pointer-type gate and the
|
|
3
|
+
* pointer-to-canvas coordinate mapping. Free of DOM and settings dependencies
|
|
4
|
+
* so both are testable without a browser. The component takes `stylusOnly` as a
|
|
5
|
+
* prop the caller resolves (from a tenant setting, a device profile, …) and
|
|
6
|
+
* never decides it itself.
|
|
7
|
+
*
|
|
8
|
+
* Ported from teamworks-os `signature-pad-logic.ts`, smrt#3290.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Paper and ink colours for the signature bitmap. A signature is document
|
|
12
|
+
* content, not chrome: it stays dark ink on white paper in every theme and
|
|
13
|
+
* colour scheme, so the exported PNG reads the same wherever it is shown.
|
|
14
|
+
*/
|
|
15
|
+
export const SIGNATURE_PAPER_COLOR = '#ffffff';
|
|
16
|
+
export const SIGNATURE_INK_COLOR = '#111111';
|
|
17
|
+
/**
|
|
18
|
+
* Whether a pointer of `pointerType` may draw a stroke.
|
|
19
|
+
*
|
|
20
|
+
* With `stylusOnly`, only `pen` is accepted: finger and mouse input are
|
|
21
|
+
* ignored outright, since nothing at the pointer-event level can tell a
|
|
22
|
+
* gloved finger from a stylus. Otherwise pen, touch and mouse are accepted.
|
|
23
|
+
* Unknown pointer types are rejected in both modes.
|
|
24
|
+
*/
|
|
25
|
+
export function isAcceptedPointerType(pointerType, stylusOnly) {
|
|
26
|
+
if (stylusOnly)
|
|
27
|
+
return pointerType === 'pen';
|
|
28
|
+
return (pointerType === 'pen' || pointerType === 'touch' || pointerType === 'mouse');
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Maps viewport `clientX`/`clientY` (CSS pixels) to the canvas's backing-pixel
|
|
32
|
+
* space.
|
|
33
|
+
*
|
|
34
|
+
* The canvas has a fixed backing resolution but is displayed at `width: 100%`,
|
|
35
|
+
* so the raw `clientX - rect.left` offset is only right when the displayed size
|
|
36
|
+
* happens to equal the backing size; anywhere else the ink drifts from the
|
|
37
|
+
* stylus and clips near the edges. Scaling by `backing / displayed` keeps them
|
|
38
|
+
* aligned. A zero-size rect (not laid out yet) falls back to 1:1 instead of
|
|
39
|
+
* dividing by zero.
|
|
40
|
+
*/
|
|
41
|
+
export function mapPointerToCanvasPoint(clientX, clientY, rect, canvasWidth, canvasHeight) {
|
|
42
|
+
const scaleX = rect.width > 0 ? canvasWidth / rect.width : 1;
|
|
43
|
+
const scaleY = rect.height > 0 ? canvasHeight / rect.height : 1;
|
|
44
|
+
return {
|
|
45
|
+
x: (clientX - rect.left) * scaleX,
|
|
46
|
+
y: (clientY - rect.top) * scaleY,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
@@ -11,4 +11,45 @@ export interface RangeSliderValue {
|
|
|
11
11
|
export interface SegmentedControlOption extends ControlOption {
|
|
12
12
|
icon?: string;
|
|
13
13
|
}
|
|
14
|
+
/** What `CameraCapture` and `SignaturePad` hand to `onCapture`. */
|
|
15
|
+
export interface CaptureResult {
|
|
16
|
+
/** The encoded image (JPEG/PNG/WebP for photos, PNG for signatures). */
|
|
17
|
+
blob: Blob;
|
|
18
|
+
/** The same image as a `data:` URL, convenient for an inline preview. */
|
|
19
|
+
dataUrl: string;
|
|
20
|
+
}
|
|
21
|
+
/** Rendered states of `CameraCapture`, exposed as its `data-state` attribute. */
|
|
22
|
+
export type CameraCaptureState = 'off' | 'starting' | 'streaming' | 'reviewing' | 'committed' | 'permission-denied' | 'no-camera' | 'unsupported' | 'error' | 'fallback';
|
|
23
|
+
/** Text overrides for `CameraCapture`; defaults come from the `ui` i18n catalog. */
|
|
24
|
+
export interface CameraCaptureLabels {
|
|
25
|
+
region: string;
|
|
26
|
+
preview: string;
|
|
27
|
+
starting: string;
|
|
28
|
+
off: string;
|
|
29
|
+
unsupported: string;
|
|
30
|
+
permissionDenied: string;
|
|
31
|
+
noCamera: string;
|
|
32
|
+
error: string;
|
|
33
|
+
retry: string;
|
|
34
|
+
capture: string;
|
|
35
|
+
retake: string;
|
|
36
|
+
usePhoto: string;
|
|
37
|
+
reviewAlt: string;
|
|
38
|
+
committedAlt: string;
|
|
39
|
+
committed: string;
|
|
40
|
+
choosePhoto: string;
|
|
41
|
+
}
|
|
42
|
+
/** Rendered states of `SignaturePad`, exposed as its `data-state` attribute. */
|
|
43
|
+
export type SignaturePadState = 'empty' | 'signed' | 'committed';
|
|
44
|
+
/** Text overrides for `SignaturePad`; defaults come from the `ui` i18n catalog. */
|
|
45
|
+
export interface SignaturePadLabels {
|
|
46
|
+
region: string;
|
|
47
|
+
canvasEmpty: string;
|
|
48
|
+
canvasSigned: string;
|
|
49
|
+
hintAny: string;
|
|
50
|
+
hintStylus: string;
|
|
51
|
+
clear: string;
|
|
52
|
+
useSignature: string;
|
|
53
|
+
committed: string;
|
|
54
|
+
}
|
|
14
55
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/forms/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAE9D,MAAM,WAAW,SAAS;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,sBAAuB,SAAQ,aAAa;IAC3D,IAAI,CAAC,EAAE,MAAM,CAAC;CACf"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/forms/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAE9D,MAAM,WAAW,SAAS;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,sBAAuB,SAAQ,aAAa;IAC3D,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,mEAAmE;AACnE,MAAM,WAAW,aAAa;IAC5B,wEAAwE;IACxE,IAAI,EAAE,IAAI,CAAC;IACX,yEAAyE;IACzE,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,iFAAiF;AACjF,MAAM,MAAM,kBAAkB,GAC1B,KAAK,GACL,UAAU,GACV,WAAW,GACX,WAAW,GACX,WAAW,GACX,mBAAmB,GACnB,WAAW,GACX,aAAa,GACb,OAAO,GACP,UAAU,CAAC;AAEf,oFAAoF;AACpF,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,gFAAgF;AAChF,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,QAAQ,GAAG,WAAW,CAAC;AAEjE,mFAAmF;AACnF,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB"}
|
|
@@ -1,41 +1,107 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
/**
|
|
3
|
-
* PageHeader -
|
|
4
|
-
*
|
|
3
|
+
* PageHeader - one header per page: an ancestors-only breadcrumb row, the
|
|
4
|
+
* page title (`<h1>`), and the page's own actions, right-aligned.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
6
|
+
* Page-header contract (shared with AdminShell in smrt-svelte/workspace):
|
|
7
|
+
* - `crumbs` are the page's ancestors only, never the page itself; none on
|
|
8
|
+
* section homes. Inside a shell that sets `setPageHeaderContext()`, pages
|
|
9
|
+
* pass only `parents` (ancestors the nav doesn't know, e.g. the article
|
|
10
|
+
* above its video) and the shell adds the rest; the shell also hears the
|
|
11
|
+
* title (for its phone top bar). smrt-svelte's `shellPageTrailFor()`
|
|
12
|
+
* computes such a trail from a nav.
|
|
13
|
+
* - The crumb row carries `data-shell-breadcrumbs` and the title
|
|
14
|
+
* `data-shell-page-title`: on phones AdminShell hides the crumbs and
|
|
15
|
+
* visually hides the title, because its phone top bar shows the back arrow
|
|
16
|
+
* and the title instead.
|
|
17
|
+
* - No in-page back link: the crumbs (and the phone top bar) are the way
|
|
18
|
+
* back. `backHref` is kept only for pages outside such a shell.
|
|
19
|
+
* - An editable title (`titleField`, e.g. an article's headline) renders
|
|
20
|
+
* inside the `<h1>`, so the heading is still the page's title in the
|
|
21
|
+
* outline and is named by the field's value, while the field keeps its own
|
|
22
|
+
* label. Such a heading has no `data-shell-page-title`: it stays visible on
|
|
23
|
+
* phones, because it is the input. Pass the live value as `title` so the
|
|
24
|
+
* shell (the phone top bar) follows along as the person types.
|
|
8
25
|
*/
|
|
9
26
|
import type { Snippet } from 'svelte';
|
|
10
27
|
import { ripple } from '../../actions/ripple.js';
|
|
11
28
|
import { Icon } from '../display/index.js';
|
|
29
|
+
import {
|
|
30
|
+
getPageHeaderContext,
|
|
31
|
+
type PageHeaderCrumb,
|
|
32
|
+
} from './page-header-context.js';
|
|
12
33
|
|
|
13
34
|
export interface Props {
|
|
14
35
|
/** Page title */
|
|
15
36
|
title: string;
|
|
16
37
|
/** Optional subtitle/description */
|
|
17
38
|
subtitle?: string;
|
|
18
|
-
/**
|
|
39
|
+
/**
|
|
40
|
+
* All ancestors of this page, outermost first (never the page itself).
|
|
41
|
+
* Overrides the shell's trail; usually pass `parents` instead.
|
|
42
|
+
*/
|
|
43
|
+
crumbs?: readonly PageHeaderCrumb[];
|
|
44
|
+
/** Ancestors past the shell's nav, outermost first. */
|
|
45
|
+
parents?: readonly PageHeaderCrumb[];
|
|
46
|
+
/** Shorter title for the shell (e.g. its phone top bar); default `title`. */
|
|
47
|
+
shortTitle?: string;
|
|
48
|
+
/** Accessible name of the breadcrumb nav. */
|
|
49
|
+
crumbsLabel?: string;
|
|
50
|
+
/**
|
|
51
|
+
* Back navigation URL.
|
|
52
|
+
* @deprecated Use `crumbs`; inside AdminShell the phone top bar goes back.
|
|
53
|
+
*/
|
|
19
54
|
backHref?: string;
|
|
20
55
|
/** Back link label */
|
|
21
56
|
backLabel?: string;
|
|
22
|
-
/**
|
|
57
|
+
/**
|
|
58
|
+
* An editable title rendered inside the `<h1>` in place of `title`'s text
|
|
59
|
+
* (a labelled text field styled as the heading). `title` still names the
|
|
60
|
+
* page for the shell; keep it in sync with the field's value.
|
|
61
|
+
*/
|
|
62
|
+
titleField?: Snippet;
|
|
63
|
+
/** Slot for action buttons (right-aligned beside the title) */
|
|
23
64
|
actions?: Snippet;
|
|
24
|
-
/**
|
|
65
|
+
/** Small line under the title (status, dates, counts) */
|
|
66
|
+
meta?: Snippet;
|
|
67
|
+
/** Slot for additional content below the title row (e.g. page tabs) */
|
|
25
68
|
children?: Snippet;
|
|
26
69
|
}
|
|
27
70
|
|
|
28
71
|
const {
|
|
29
72
|
title,
|
|
30
73
|
subtitle,
|
|
74
|
+
crumbs,
|
|
75
|
+
parents = [],
|
|
76
|
+
shortTitle,
|
|
77
|
+
crumbsLabel = 'Breadcrumb',
|
|
31
78
|
backHref,
|
|
32
79
|
backLabel = 'Back',
|
|
80
|
+
titleField,
|
|
33
81
|
actions,
|
|
82
|
+
meta,
|
|
34
83
|
children,
|
|
35
84
|
}: Props = $props();
|
|
85
|
+
|
|
86
|
+
const shell = getPageHeaderContext();
|
|
87
|
+
const trail = $derived<readonly PageHeaderCrumb[]>(
|
|
88
|
+
crumbs ?? (shell ? shell.crumbs(parents) : parents),
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
$effect(() => shell?.report?.({ title: shortTitle ?? title, parents }));
|
|
36
92
|
</script>
|
|
37
93
|
|
|
38
|
-
<header class="page-header">
|
|
94
|
+
<header class="page-header" data-page-header>
|
|
95
|
+
{#if trail.length > 0}
|
|
96
|
+
<nav class="page-crumbs" aria-label={crumbsLabel} data-shell-breadcrumbs>
|
|
97
|
+
<ol>
|
|
98
|
+
{#each trail as crumb, index (`${index}:${crumb.href}`)}
|
|
99
|
+
<li><a href={crumb.href}>{crumb.label}</a></li>
|
|
100
|
+
{/each}
|
|
101
|
+
</ol>
|
|
102
|
+
</nav>
|
|
103
|
+
{/if}
|
|
104
|
+
|
|
39
105
|
<div class="header-main">
|
|
40
106
|
<div class="header-content">
|
|
41
107
|
{#if backHref}
|
|
@@ -44,10 +110,19 @@ const {
|
|
|
44
110
|
<span>{backLabel}</span>
|
|
45
111
|
</a>
|
|
46
112
|
{/if}
|
|
47
|
-
|
|
113
|
+
{#if titleField}
|
|
114
|
+
<h1 class="page-title page-title-field" data-page-title-field>
|
|
115
|
+
{@render titleField()}
|
|
116
|
+
</h1>
|
|
117
|
+
{:else}
|
|
118
|
+
<h1 class="page-title" data-shell-page-title>{title}</h1>
|
|
119
|
+
{/if}
|
|
48
120
|
{#if subtitle}
|
|
49
121
|
<p class="page-subtitle">{subtitle}</p>
|
|
50
122
|
{/if}
|
|
123
|
+
{#if meta}
|
|
124
|
+
<div class="page-meta">{@render meta()}</div>
|
|
125
|
+
{/if}
|
|
51
126
|
</div>
|
|
52
127
|
|
|
53
128
|
{#if actions}
|
|
@@ -58,7 +133,7 @@ const {
|
|
|
58
133
|
</div>
|
|
59
134
|
|
|
60
135
|
{#if children}
|
|
61
|
-
<div class="header-extra">
|
|
136
|
+
<div class="header-extra" data-page-header-extra>
|
|
62
137
|
{@render children()}
|
|
63
138
|
</div>
|
|
64
139
|
{/if}
|
|
@@ -66,15 +141,60 @@ const {
|
|
|
66
141
|
|
|
67
142
|
<style>
|
|
68
143
|
.page-header {
|
|
69
|
-
margin-bottom:
|
|
70
|
-
|
|
144
|
+
margin-bottom: 1.5rem;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.page-crumbs {
|
|
148
|
+
margin-bottom: var(--smrt-spacing-1, 4px);
|
|
149
|
+
color: var(--smrt-color-on-surface-variant);
|
|
150
|
+
font: var(--smrt-typography-body-small-font);
|
|
151
|
+
font-size: 0.84rem;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.page-crumbs ol {
|
|
155
|
+
display: flex;
|
|
156
|
+
flex-wrap: wrap;
|
|
157
|
+
align-items: center;
|
|
158
|
+
gap: 0.35rem;
|
|
159
|
+
margin: 0;
|
|
160
|
+
padding: 0;
|
|
161
|
+
list-style: none;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.page-crumbs li {
|
|
165
|
+
display: flex;
|
|
166
|
+
align-items: center;
|
|
167
|
+
min-width: 0;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.page-crumbs li + li::before {
|
|
171
|
+
content: '/';
|
|
172
|
+
margin-inline-end: 0.35rem;
|
|
173
|
+
color: var(--smrt-color-outline);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.page-crumbs a {
|
|
177
|
+
color: inherit;
|
|
178
|
+
text-decoration: none;
|
|
179
|
+
overflow-wrap: anywhere;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.page-crumbs a:hover {
|
|
183
|
+
color: var(--smrt-color-primary);
|
|
184
|
+
text-decoration: underline;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.page-crumbs a:focus-visible {
|
|
188
|
+
outline: 2px solid var(--smrt-color-primary);
|
|
189
|
+
outline-offset: 2px;
|
|
190
|
+
border-radius: var(--smrt-radius-sm, 4px);
|
|
71
191
|
}
|
|
72
192
|
|
|
73
193
|
.header-main {
|
|
74
194
|
display: flex;
|
|
75
195
|
justify-content: space-between;
|
|
76
196
|
align-items: flex-start;
|
|
77
|
-
gap: 1.5rem;
|
|
197
|
+
gap: 0.75rem 1.5rem;
|
|
78
198
|
flex-wrap: wrap;
|
|
79
199
|
}
|
|
80
200
|
|
|
@@ -83,7 +203,7 @@ const {
|
|
|
83
203
|
flex-direction: column;
|
|
84
204
|
gap: var(--smrt-spacing-1, 4px);
|
|
85
205
|
flex: 1;
|
|
86
|
-
min-width: 200px;
|
|
206
|
+
min-width: min(100%, 200px);
|
|
87
207
|
}
|
|
88
208
|
|
|
89
209
|
.back-link {
|
|
@@ -109,13 +229,26 @@ const {
|
|
|
109
229
|
color: var(--smrt-color-on-surface);
|
|
110
230
|
margin: 0;
|
|
111
231
|
letter-spacing: -0.5px;
|
|
232
|
+
overflow-wrap: anywhere;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.page-title-field {
|
|
236
|
+
min-width: 0;
|
|
112
237
|
}
|
|
113
238
|
|
|
114
239
|
.page-subtitle {
|
|
115
240
|
font: var(--smrt-typography-body-medium-font);
|
|
116
241
|
color: var(--smrt-color-on-surface-variant);
|
|
117
242
|
margin: 0;
|
|
118
|
-
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
.page-meta {
|
|
246
|
+
display: flex;
|
|
247
|
+
flex-wrap: wrap;
|
|
248
|
+
align-items: center;
|
|
249
|
+
gap: 0.5rem;
|
|
250
|
+
font: var(--smrt-typography-body-small-font);
|
|
251
|
+
color: var(--smrt-color-on-surface-variant);
|
|
119
252
|
}
|
|
120
253
|
|
|
121
254
|
.header-actions {
|
|
@@ -123,9 +256,10 @@ const {
|
|
|
123
256
|
gap: 0.75rem;
|
|
124
257
|
align-items: center;
|
|
125
258
|
flex-wrap: wrap;
|
|
259
|
+
margin-inline-start: auto;
|
|
126
260
|
}
|
|
127
261
|
|
|
128
262
|
.header-extra {
|
|
129
|
-
margin-top:
|
|
263
|
+
margin-top: 1rem;
|
|
130
264
|
}
|
|
131
|
-
</style>
|
|
265
|
+
</style>
|
|
@@ -1,23 +1,63 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* PageHeader -
|
|
3
|
-
*
|
|
2
|
+
* PageHeader - one header per page: an ancestors-only breadcrumb row, the
|
|
3
|
+
* page title (`<h1>`), and the page's own actions, right-aligned.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* Page-header contract (shared with AdminShell in smrt-svelte/workspace):
|
|
6
|
+
* - `crumbs` are the page's ancestors only, never the page itself; none on
|
|
7
|
+
* section homes. Inside a shell that sets `setPageHeaderContext()`, pages
|
|
8
|
+
* pass only `parents` (ancestors the nav doesn't know, e.g. the article
|
|
9
|
+
* above its video) and the shell adds the rest; the shell also hears the
|
|
10
|
+
* title (for its phone top bar). smrt-svelte's `shellPageTrailFor()`
|
|
11
|
+
* computes such a trail from a nav.
|
|
12
|
+
* - The crumb row carries `data-shell-breadcrumbs` and the title
|
|
13
|
+
* `data-shell-page-title`: on phones AdminShell hides the crumbs and
|
|
14
|
+
* visually hides the title, because its phone top bar shows the back arrow
|
|
15
|
+
* and the title instead.
|
|
16
|
+
* - No in-page back link: the crumbs (and the phone top bar) are the way
|
|
17
|
+
* back. `backHref` is kept only for pages outside such a shell.
|
|
18
|
+
* - An editable title (`titleField`, e.g. an article's headline) renders
|
|
19
|
+
* inside the `<h1>`, so the heading is still the page's title in the
|
|
20
|
+
* outline and is named by the field's value, while the field keeps its own
|
|
21
|
+
* label. Such a heading has no `data-shell-page-title`: it stays visible on
|
|
22
|
+
* phones, because it is the input. Pass the live value as `title` so the
|
|
23
|
+
* shell (the phone top bar) follows along as the person types.
|
|
7
24
|
*/
|
|
8
25
|
import type { Snippet } from 'svelte';
|
|
26
|
+
import { type PageHeaderCrumb } from './page-header-context.js';
|
|
9
27
|
export interface Props {
|
|
10
28
|
/** Page title */
|
|
11
29
|
title: string;
|
|
12
30
|
/** Optional subtitle/description */
|
|
13
31
|
subtitle?: string;
|
|
14
|
-
/**
|
|
32
|
+
/**
|
|
33
|
+
* All ancestors of this page, outermost first (never the page itself).
|
|
34
|
+
* Overrides the shell's trail; usually pass `parents` instead.
|
|
35
|
+
*/
|
|
36
|
+
crumbs?: readonly PageHeaderCrumb[];
|
|
37
|
+
/** Ancestors past the shell's nav, outermost first. */
|
|
38
|
+
parents?: readonly PageHeaderCrumb[];
|
|
39
|
+
/** Shorter title for the shell (e.g. its phone top bar); default `title`. */
|
|
40
|
+
shortTitle?: string;
|
|
41
|
+
/** Accessible name of the breadcrumb nav. */
|
|
42
|
+
crumbsLabel?: string;
|
|
43
|
+
/**
|
|
44
|
+
* Back navigation URL.
|
|
45
|
+
* @deprecated Use `crumbs`; inside AdminShell the phone top bar goes back.
|
|
46
|
+
*/
|
|
15
47
|
backHref?: string;
|
|
16
48
|
/** Back link label */
|
|
17
49
|
backLabel?: string;
|
|
18
|
-
/**
|
|
50
|
+
/**
|
|
51
|
+
* An editable title rendered inside the `<h1>` in place of `title`'s text
|
|
52
|
+
* (a labelled text field styled as the heading). `title` still names the
|
|
53
|
+
* page for the shell; keep it in sync with the field's value.
|
|
54
|
+
*/
|
|
55
|
+
titleField?: Snippet;
|
|
56
|
+
/** Slot for action buttons (right-aligned beside the title) */
|
|
19
57
|
actions?: Snippet;
|
|
20
|
-
/**
|
|
58
|
+
/** Small line under the title (status, dates, counts) */
|
|
59
|
+
meta?: Snippet;
|
|
60
|
+
/** Slot for additional content below the title row (e.g. page tabs) */
|
|
21
61
|
children?: Snippet;
|
|
22
62
|
}
|
|
23
63
|
declare const PageHeader: import("svelte").Component<Props, {}, "">;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PageHeader.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/layout/PageHeader.svelte.ts"],"names":[],"mappings":"AAGA
|
|
1
|
+
{"version":3,"file":"PageHeader.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/layout/PageHeader.svelte.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAGtC,OAAO,EAEL,KAAK,eAAe,EACrB,MAAM,0BAA0B,CAAC;AAGlC,MAAM,WAAW,KAAK;IACpB,iBAAiB;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,oCAAoC;IACpC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,MAAM,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;IACpC,uDAAuD;IACvD,OAAO,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;IACrC,6EAA6E;IAC7E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6CAA6C;IAC7C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sBAAsB;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,+DAA+D;IAC/D,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,yDAAyD;IACzD,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,uEAAuE;IACvE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAoFD,QAAA,MAAM,UAAU,2CAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* title, optional subtitle, optional back link, and actions/children snippets.
|
|
6
6
|
*/
|
|
7
7
|
import { render, screen } from '@testing-library/svelte';
|
|
8
|
-
import { createRawSnippet } from 'svelte';
|
|
8
|
+
import { createRawSnippet, flushSync } from 'svelte';
|
|
9
9
|
import { describe, expect, it } from 'vitest';
|
|
10
10
|
import { expectNoA11yViolations } from '../../../test-support/a11y';
|
|
11
11
|
import PageHeader from '../PageHeader.svelte';
|
|
@@ -66,6 +66,92 @@ describe('PageHeader', () => {
|
|
|
66
66
|
render(PageHeader, { props: { title: 'Detail' } });
|
|
67
67
|
expect(screen.queryByRole('link')).not.toBeInTheDocument();
|
|
68
68
|
});
|
|
69
|
+
it('renders ancestors-only crumbs above the title', () => {
|
|
70
|
+
render(PageHeader, {
|
|
71
|
+
props: {
|
|
72
|
+
title: 'Fair opens Friday',
|
|
73
|
+
crumbs: [
|
|
74
|
+
{ label: 'Alpha Times', href: '/sites/alpha' },
|
|
75
|
+
{ label: 'Content', href: '/sites/alpha/articles' },
|
|
76
|
+
],
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
const nav = screen.getByRole('navigation', { name: 'Breadcrumb' });
|
|
80
|
+
expect(nav).toHaveAttribute('data-shell-breadcrumbs');
|
|
81
|
+
const links = nav.querySelectorAll('a');
|
|
82
|
+
expect([...links].map((a) => a.textContent)).toEqual([
|
|
83
|
+
'Alpha Times',
|
|
84
|
+
'Content',
|
|
85
|
+
]);
|
|
86
|
+
// The current page is the heading, not a crumb.
|
|
87
|
+
expect(nav).not.toHaveTextContent('Fair opens Friday');
|
|
88
|
+
expect(screen.getByRole('heading', { level: 1, name: 'Fair opens Friday' })).toHaveAttribute('data-shell-page-title');
|
|
89
|
+
});
|
|
90
|
+
it('renders no crumb row without ancestors', () => {
|
|
91
|
+
render(PageHeader, { props: { title: 'Content', crumbs: [] } });
|
|
92
|
+
expect(screen.queryByRole('navigation')).not.toBeInTheDocument();
|
|
93
|
+
});
|
|
94
|
+
it('renders the meta snippet under the title', () => {
|
|
95
|
+
render(PageHeader, {
|
|
96
|
+
props: { title: 'Detail', meta: snippet('<span>Draft</span>') },
|
|
97
|
+
});
|
|
98
|
+
expect(screen.getByText('Draft')).toBeInTheDocument();
|
|
99
|
+
});
|
|
100
|
+
it('takes its trail from the shell and reports its title', () => {
|
|
101
|
+
const reports = [];
|
|
102
|
+
const context = new Map([
|
|
103
|
+
[
|
|
104
|
+
Symbol.for('smrt-ui.page-header'),
|
|
105
|
+
{
|
|
106
|
+
crumbs: (parents) => [
|
|
107
|
+
{ label: 'Alpha Times', href: '/sites/alpha' },
|
|
108
|
+
...parents,
|
|
109
|
+
],
|
|
110
|
+
report: (page) => {
|
|
111
|
+
reports.push(page);
|
|
112
|
+
return undefined;
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
],
|
|
116
|
+
]);
|
|
117
|
+
render(PageHeader, {
|
|
118
|
+
props: {
|
|
119
|
+
title: 'Create video',
|
|
120
|
+
parents: [{ label: 'Videos', href: '/sites/alpha/articles/a1/videos' }],
|
|
121
|
+
},
|
|
122
|
+
context,
|
|
123
|
+
});
|
|
124
|
+
const nav = screen.getByRole('navigation', { name: 'Breadcrumb' });
|
|
125
|
+
expect([...nav.querySelectorAll('a')].map((a) => a.textContent)).toEqual([
|
|
126
|
+
'Alpha Times',
|
|
127
|
+
'Videos',
|
|
128
|
+
]);
|
|
129
|
+
flushSync();
|
|
130
|
+
expect(reports).toEqual([
|
|
131
|
+
{
|
|
132
|
+
title: 'Create video',
|
|
133
|
+
parents: [{ label: 'Videos', href: '/sites/alpha/articles/a1/videos' }],
|
|
134
|
+
},
|
|
135
|
+
]);
|
|
136
|
+
});
|
|
137
|
+
it('renders an editable title inside the h1 and keeps it visible on phones', async () => {
|
|
138
|
+
const { container } = render(PageHeader, {
|
|
139
|
+
props: {
|
|
140
|
+
title: 'Council passes budget',
|
|
141
|
+
titleField: snippet('<input name="title" aria-label="Title" value="Council passes budget" />'),
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
const heading = screen.getByRole('heading', { level: 1 });
|
|
145
|
+
const field = screen.getByRole('textbox', { name: 'Title' });
|
|
146
|
+
expect(heading).toContainElement(field);
|
|
147
|
+
// The heading is named by the field's value; the field keeps its label.
|
|
148
|
+
expect(heading).toHaveAccessibleName('Council passes budget');
|
|
149
|
+
// No data-shell-page-title: the shell must not hide the input on phones.
|
|
150
|
+
expect(heading).not.toHaveAttribute('data-shell-page-title');
|
|
151
|
+
expect(heading).toHaveAttribute('data-page-title-field');
|
|
152
|
+
expect(container.querySelectorAll('h1')).toHaveLength(1);
|
|
153
|
+
await expectNoA11yViolations(container);
|
|
154
|
+
});
|
|
69
155
|
it('is axe-clean with subtitle, back link, and actions', async () => {
|
|
70
156
|
const { container } = render(PageHeader, {
|
|
71
157
|
props: {
|