@thomasfosterau/components 0.0.0 → 0.2.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/LICENSE +21 -0
- package/README.md +241 -56
- package/dist/canvas/VectorCanvas.svelte +320 -0
- package/dist/canvas/VectorCanvas.svelte.d.ts +105 -0
- package/dist/canvas/history.d.ts +105 -0
- package/dist/canvas/history.js +147 -0
- package/dist/canvas/index.d.ts +15 -0
- package/dist/canvas/index.js +14 -0
- package/dist/canvas/types.d.ts +91 -0
- package/dist/canvas/types.js +13 -0
- package/dist/canvas/utils.d.ts +66 -0
- package/dist/canvas/utils.js +114 -0
- package/dist/charts/Chart.svelte +300 -0
- package/dist/charts/Chart.svelte.d.ts +50 -0
- package/dist/charts/index.d.ts +11 -0
- package/dist/charts/index.js +10 -0
- package/dist/charts/types.d.ts +28 -0
- package/dist/charts/types.js +6 -0
- package/dist/citations/BookCitation.svelte +53 -0
- package/dist/citations/BookCitation.svelte.d.ts +41 -0
- package/dist/citations/ChapterCitation.svelte +38 -0
- package/dist/citations/ChapterCitation.svelte.d.ts +50 -0
- package/dist/citations/Citation.svelte +47 -0
- package/dist/citations/Citation.svelte.d.ts +24 -0
- package/dist/citations/CreditList.svelte +69 -0
- package/dist/citations/CreditList.svelte.d.ts +47 -0
- package/dist/citations/DOILink.svelte +28 -0
- package/dist/citations/DOILink.svelte.d.ts +19 -0
- package/dist/citations/Footnote.svelte +39 -0
- package/dist/citations/Footnote.svelte.d.ts +17 -0
- package/dist/citations/FootnoteList.svelte +36 -0
- package/dist/citations/FootnoteList.svelte.d.ts +21 -0
- package/dist/citations/ISBNLink.svelte +29 -0
- package/dist/citations/ISBNLink.svelte.d.ts +19 -0
- package/dist/citations/ISSNLink.svelte +29 -0
- package/dist/citations/ISSNLink.svelte.d.ts +19 -0
- package/dist/citations/Publisher.svelte +34 -0
- package/dist/citations/Publisher.svelte.d.ts +14 -0
- package/dist/citations/ReferenceList.svelte +53 -0
- package/dist/citations/ReferenceList.svelte.d.ts +21 -0
- package/dist/citations/ReportCitation.svelte +41 -0
- package/dist/citations/ReportCitation.svelte.d.ts +36 -0
- package/dist/citations/ScholarlyArticleCitation.svelte +64 -0
- package/dist/citations/ScholarlyArticleCitation.svelte.d.ts +41 -0
- package/dist/citations/ThesisCitation.svelte +35 -0
- package/dist/citations/ThesisCitation.svelte.d.ts +29 -0
- package/dist/citations/bibliography.svelte.d.ts +55 -0
- package/dist/citations/bibliography.svelte.js +78 -0
- package/dist/citations/citation.d.ts +71 -0
- package/dist/citations/citation.js +121 -0
- package/dist/citations/csl.d.ts +102 -0
- package/dist/citations/csl.js +20 -0
- package/dist/citations/index.d.ts +31 -0
- package/dist/citations/index.js +36 -0
- package/dist/citations/list-format.d.ts +34 -0
- package/dist/citations/list-format.js +40 -0
- package/dist/context.svelte.d.ts +46 -0
- package/dist/context.svelte.js +51 -0
- package/dist/data/ChatBubble.svelte +48 -0
- package/dist/data/ChatBubble.svelte.d.ts +33 -0
- package/dist/data/DataGrid.svelte +150 -0
- package/dist/data/DataGrid.svelte.d.ts +118 -0
- package/dist/data/DescriptionList.svelte +53 -0
- package/dist/data/DescriptionList.svelte.d.ts +26 -0
- package/dist/data/DescriptionRow.svelte +56 -0
- package/dist/data/DescriptionRow.svelte.d.ts +21 -0
- package/dist/data/DiffText.svelte +29 -0
- package/dist/data/DiffText.svelte.d.ts +19 -0
- package/dist/data/ItemList.svelte +80 -0
- package/dist/data/ItemList.svelte.d.ts +52 -0
- package/dist/data/LinkListItem.svelte +46 -0
- package/dist/data/LinkListItem.svelte.d.ts +21 -0
- package/dist/data/MessageThread.svelte +29 -0
- package/dist/data/MessageThread.svelte.d.ts +17 -0
- package/dist/data/Pagination.svelte +136 -0
- package/dist/data/Pagination.svelte.d.ts +79 -0
- package/dist/data/PaginationFooter.svelte +42 -0
- package/dist/data/PaginationFooter.svelte.d.ts +61 -0
- package/dist/data/ResultCount.svelte +27 -0
- package/dist/data/ResultCount.svelte.d.ts +18 -0
- package/dist/data/Table.svelte +151 -0
- package/dist/data/Table.svelte.d.ts +75 -0
- package/dist/data/TreeList.svelte +41 -0
- package/dist/data/TreeList.svelte.d.ts +17 -0
- package/dist/data/TreeListItem.svelte +29 -0
- package/dist/data/TreeListItem.svelte.d.ts +10 -0
- package/dist/data/description-context.d.ts +39 -0
- package/dist/data/description-context.js +36 -0
- package/dist/data/diff.d.ts +14 -0
- package/dist/data/diff.js +10 -0
- package/dist/data/index.d.ts +37 -0
- package/dist/data/index.js +37 -0
- package/dist/data/list-item.d.ts +30 -0
- package/dist/data/list-item.js +19 -0
- package/dist/data/pagination.d.ts +81 -0
- package/dist/data/pagination.js +79 -0
- package/dist/data/table-types.d.ts +71 -0
- package/dist/data/table-types.js +35 -0
- package/dist/feedback/ConfirmDialog.svelte +79 -0
- package/dist/feedback/ConfirmDialog.svelte.d.ts +82 -0
- package/dist/feedback/Dialog.svelte +47 -0
- package/dist/feedback/Dialog.svelte.d.ts +36 -0
- package/dist/feedback/DialogFrame.svelte +64 -0
- package/dist/feedback/DialogFrame.svelte.d.ts +23 -0
- package/dist/feedback/Drawer.svelte +43 -0
- package/dist/feedback/Drawer.svelte.d.ts +43 -0
- package/dist/feedback/LoadingBoundary.svelte +61 -0
- package/dist/feedback/LoadingBoundary.svelte.d.ts +34 -0
- package/dist/feedback/ProgressBar.svelte +46 -0
- package/dist/feedback/ProgressBar.svelte.d.ts +28 -0
- package/dist/feedback/SegmentBar.svelte +83 -0
- package/dist/feedback/SegmentBar.svelte.d.ts +37 -0
- package/dist/feedback/StatTile.svelte +77 -0
- package/dist/feedback/StatTile.svelte.d.ts +50 -0
- package/dist/feedback/Stats.svelte +18 -0
- package/dist/feedback/Stats.svelte.d.ts +16 -0
- package/dist/feedback/Steps.svelte +72 -0
- package/dist/feedback/Steps.svelte.d.ts +61 -0
- package/dist/feedback/Timeline.svelte +86 -0
- package/dist/feedback/Timeline.svelte.d.ts +55 -0
- package/dist/feedback/Toaster.svelte +78 -0
- package/dist/feedback/Toaster.svelte.d.ts +32 -0
- package/dist/feedback/index.d.ts +34 -0
- package/dist/feedback/index.js +29 -0
- package/dist/feedback/sizes.d.ts +41 -0
- package/dist/feedback/sizes.js +69 -0
- package/dist/feedback/toaster.d.ts +48 -0
- package/dist/feedback/toaster.js +29 -0
- package/dist/fields/Calendar.svelte +60 -0
- package/dist/fields/Calendar.svelte.d.ts +11 -0
- package/dist/fields/CalendarMonths.svelte +86 -0
- package/dist/fields/CalendarMonths.svelte.d.ts +30 -0
- package/dist/fields/Checkbox.svelte +33 -0
- package/dist/fields/Checkbox.svelte.d.ts +30 -0
- package/dist/fields/CheckboxGroup.svelte +41 -0
- package/dist/fields/CheckboxGroup.svelte.d.ts +40 -0
- package/dist/fields/Combobox.svelte +229 -0
- package/dist/fields/Combobox.svelte.d.ts +133 -0
- package/dist/fields/DateField.svelte +37 -0
- package/dist/fields/DateField.svelte.d.ts +20 -0
- package/dist/fields/DateInput.svelte +31 -0
- package/dist/fields/DateInput.svelte.d.ts +35 -0
- package/dist/fields/DatePicker.svelte +47 -0
- package/dist/fields/DatePicker.svelte.d.ts +25 -0
- package/dist/fields/DateRangePicker.svelte +70 -0
- package/dist/fields/DateRangePicker.svelte.d.ts +43 -0
- package/dist/fields/Dropzone.svelte +232 -0
- package/dist/fields/Dropzone.svelte.d.ts +103 -0
- package/dist/fields/FieldErrors.svelte +30 -0
- package/dist/fields/FieldErrors.svelte.d.ts +11 -0
- package/dist/fields/Fieldset.svelte +53 -0
- package/dist/fields/Fieldset.svelte.d.ts +27 -0
- package/dist/fields/FileInput.svelte +68 -0
- package/dist/fields/FileInput.svelte.d.ts +39 -0
- package/dist/fields/FormField.svelte +78 -0
- package/dist/fields/FormField.svelte.d.ts +29 -0
- package/dist/fields/ImageInput.svelte +87 -0
- package/dist/fields/ImageInput.svelte.d.ts +45 -0
- package/dist/fields/MultiSelect.svelte +112 -0
- package/dist/fields/MultiSelect.svelte.d.ts +75 -0
- package/dist/fields/NumberField.svelte +190 -0
- package/dist/fields/NumberField.svelte.d.ts +76 -0
- package/dist/fields/PasswordInput.svelte +95 -0
- package/dist/fields/PasswordInput.svelte.d.ts +58 -0
- package/dist/fields/PickerPopover.svelte +47 -0
- package/dist/fields/PickerPopover.svelte.d.ts +16 -0
- package/dist/fields/PinInput.svelte +83 -0
- package/dist/fields/PinInput.svelte.d.ts +66 -0
- package/dist/fields/PushToggle.svelte +93 -0
- package/dist/fields/PushToggle.svelte.d.ts +55 -0
- package/dist/fields/RadioGroup.svelte +88 -0
- package/dist/fields/RadioGroup.svelte.d.ts +41 -0
- package/dist/fields/RangeCalendar.svelte +51 -0
- package/dist/fields/RangeCalendar.svelte.d.ts +23 -0
- package/dist/fields/Rating.svelte +127 -0
- package/dist/fields/Rating.svelte.d.ts +86 -0
- package/dist/fields/SearchInput.svelte +58 -0
- package/dist/fields/SearchInput.svelte.d.ts +33 -0
- package/dist/fields/SegmentGroup.svelte +91 -0
- package/dist/fields/SegmentGroup.svelte.d.ts +20 -0
- package/dist/fields/Select.svelte +36 -0
- package/dist/fields/Select.svelte.d.ts +35 -0
- package/dist/fields/Slider.svelte +194 -0
- package/dist/fields/Slider.svelte.d.ts +100 -0
- package/dist/fields/TagsInput.svelte +256 -0
- package/dist/fields/TagsInput.svelte.d.ts +102 -0
- package/dist/fields/TextInput.svelte +26 -0
- package/dist/fields/TextInput.svelte.d.ts +36 -0
- package/dist/fields/Textarea.svelte +22 -0
- package/dist/fields/Textarea.svelte.d.ts +31 -0
- package/dist/fields/TimeField.svelte +30 -0
- package/dist/fields/TimeField.svelte.d.ts +19 -0
- package/dist/fields/Toggle.svelte +72 -0
- package/dist/fields/Toggle.svelte.d.ts +38 -0
- package/dist/fields/VideoInput.svelte +35 -0
- package/dist/fields/VideoInput.svelte.d.ts +46 -0
- package/dist/fields/calendar-props.d.ts +119 -0
- package/dist/fields/calendar-props.js +51 -0
- package/dist/fields/dates.d.ts +28 -0
- package/dist/fields/dates.js +26 -0
- package/dist/fields/field-types.d.ts +80 -0
- package/dist/fields/field-types.js +92 -0
- package/dist/fields/file-validation.d.ts +30 -0
- package/dist/fields/file-validation.js +51 -0
- package/dist/fields/index.d.ts +43 -0
- package/dist/fields/index.js +42 -0
- package/dist/fields/latest-search.svelte.d.ts +38 -0
- package/dist/fields/latest-search.svelte.js +85 -0
- package/dist/fields/number-format.d.ts +52 -0
- package/dist/fields/number-format.js +89 -0
- package/dist/fields/segmented-field.d.ts +128 -0
- package/dist/fields/segmented-field.js +52 -0
- package/dist/fields/slider-keys.d.ts +21 -0
- package/dist/fields/slider-keys.js +37 -0
- package/dist/formatting/Countdown.svelte +110 -0
- package/dist/formatting/Countdown.svelte.d.ts +35 -0
- package/dist/formatting/DateTime.svelte +35 -0
- package/dist/formatting/DateTime.svelte.d.ts +26 -0
- package/dist/formatting/Duration.svelte +18 -0
- package/dist/formatting/Duration.svelte.d.ts +20 -0
- package/dist/formatting/FormatList.svelte +31 -0
- package/dist/formatting/FormatList.svelte.d.ts +46 -0
- package/dist/formatting/Highlight.svelte +51 -0
- package/dist/formatting/Highlight.svelte.d.ts +19 -0
- package/dist/formatting/Number.svelte +35 -0
- package/dist/formatting/Number.svelte.d.ts +43 -0
- package/dist/formatting/RelativeTime.svelte +69 -0
- package/dist/formatting/RelativeTime.svelte.d.ts +26 -0
- package/dist/formatting/Year.svelte +39 -0
- package/dist/formatting/Year.svelte.d.ts +21 -0
- package/dist/formatting/duration.d.ts +44 -0
- package/dist/formatting/duration.js +125 -0
- package/dist/formatting/index.d.ts +15 -0
- package/dist/formatting/index.js +17 -0
- package/dist/forms/EntityForm.svelte +185 -0
- package/dist/forms/EntityForm.svelte.d.ts +66 -0
- package/dist/forms/FormActions.svelte +29 -0
- package/dist/forms/FormActions.svelte.d.ts +37 -0
- package/dist/forms/FormErrors.svelte +21 -0
- package/dist/forms/FormErrors.svelte.d.ts +16 -0
- package/dist/forms/HiddenField.svelte +22 -0
- package/dist/forms/HiddenField.svelte.d.ts +11 -0
- package/dist/forms/SearchForm.svelte +43 -0
- package/dist/forms/SearchForm.svelte.d.ts +36 -0
- package/dist/forms/entity-form.d.ts +12 -0
- package/dist/forms/entity-form.js +12 -0
- package/dist/forms/index.d.ts +14 -0
- package/dist/forms/index.js +14 -0
- package/dist/hotkeys/HotkeyBadge.svelte +39 -0
- package/dist/hotkeys/HotkeyBadge.svelte.d.ts +25 -0
- package/dist/hotkeys/HotkeyHelpDialog.svelte +68 -0
- package/dist/hotkeys/HotkeyHelpDialog.svelte.d.ts +35 -0
- package/dist/hotkeys/HotkeyProvider.svelte +92 -0
- package/dist/hotkeys/HotkeyProvider.svelte.d.ts +4 -0
- package/dist/hotkeys/context.svelte.d.ts +47 -0
- package/dist/hotkeys/context.svelte.js +72 -0
- package/dist/hotkeys/index.d.ts +28 -0
- package/dist/hotkeys/index.js +27 -0
- package/dist/hotkeys/match.d.ts +65 -0
- package/dist/hotkeys/match.js +135 -0
- package/dist/hotkeys/registry.svelte.d.ts +55 -0
- package/dist/hotkeys/registry.svelte.js +110 -0
- package/dist/hotkeys/types.d.ts +74 -0
- package/dist/hotkeys/types.js +18 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.js +37 -0
- package/dist/infobox/Infobox.svelte +79 -0
- package/dist/infobox/Infobox.svelte.d.ts +33 -0
- package/dist/infobox/InfoboxHeader.svelte +35 -0
- package/dist/infobox/InfoboxHeader.svelte.d.ts +18 -0
- package/dist/infobox/InfoboxImage.svelte +38 -0
- package/dist/infobox/InfoboxImage.svelte.d.ts +21 -0
- package/dist/infobox/InfoboxRow.svelte +50 -0
- package/dist/infobox/InfoboxRow.svelte.d.ts +25 -0
- package/dist/infobox/InfoboxSection.svelte +24 -0
- package/dist/infobox/InfoboxSection.svelte.d.ts +12 -0
- package/dist/infobox/index.d.ts +21 -0
- package/dist/infobox/index.js +20 -0
- package/dist/infobox/types.d.ts +86 -0
- package/dist/infobox/types.js +27 -0
- package/dist/layout/AppShell.svelte +50 -0
- package/dist/layout/AppShell.svelte.d.ts +28 -0
- package/dist/layout/Breadcrumbs.svelte +52 -0
- package/dist/layout/Breadcrumbs.svelte.d.ts +18 -0
- package/dist/layout/Cluster.svelte +28 -0
- package/dist/layout/Cluster.svelte.d.ts +27 -0
- package/dist/layout/DetailLayout.svelte +50 -0
- package/dist/layout/DetailLayout.svelte.d.ts +19 -0
- package/dist/layout/FilterBar.svelte +40 -0
- package/dist/layout/FilterBar.svelte.d.ts +12 -0
- package/dist/layout/Fits.svelte +27 -0
- package/dist/layout/Fits.svelte.d.ts +13 -0
- package/dist/layout/Flow.svelte +46 -0
- package/dist/layout/Flow.svelte.d.ts +16 -0
- package/dist/layout/Footer.svelte +32 -0
- package/dist/layout/Footer.svelte.d.ts +12 -0
- package/dist/layout/Grid.svelte +23 -0
- package/dist/layout/Grid.svelte.d.ts +26 -0
- package/dist/layout/HStack.svelte +12 -0
- package/dist/layout/HStack.svelte.d.ts +34 -0
- package/dist/layout/Hero.svelte +76 -0
- package/dist/layout/Hero.svelte.d.ts +36 -0
- package/dist/layout/Main.svelte +30 -0
- package/dist/layout/Main.svelte.d.ts +15 -0
- package/dist/layout/Navbar.svelte +68 -0
- package/dist/layout/Navbar.svelte.d.ts +31 -0
- package/dist/layout/PageHeader.svelte +77 -0
- package/dist/layout/PageHeader.svelte.d.ts +33 -0
- package/dist/layout/Section.svelte +72 -0
- package/dist/layout/Section.svelte.d.ts +40 -0
- package/dist/layout/Sidebar.svelte +54 -0
- package/dist/layout/Sidebar.svelte.d.ts +27 -0
- package/dist/layout/Spacer.svelte +12 -0
- package/dist/layout/Spacer.svelte.d.ts +6 -0
- package/dist/layout/Tabs.svelte +85 -0
- package/dist/layout/Tabs.svelte.d.ts +42 -0
- package/dist/layout/VStack.svelte +12 -0
- package/dist/layout/VStack.svelte.d.ts +29 -0
- package/dist/layout/index.d.ts +38 -0
- package/dist/layout/index.js +38 -0
- package/dist/layout/space.d.ts +44 -0
- package/dist/layout/space.js +76 -0
- package/dist/layout/types.d.ts +52 -0
- package/dist/layout/types.js +27 -0
- package/dist/links/ContextLinks.svelte +28 -0
- package/dist/links/ContextLinks.svelte.d.ts +20 -0
- package/dist/links/EmailLink.svelte +26 -0
- package/dist/links/EmailLink.svelte.d.ts +20 -0
- package/dist/links/index.d.ts +7 -0
- package/dist/links/index.js +7 -0
- package/dist/media/Figure.svelte +26 -0
- package/dist/media/Figure.svelte.d.ts +12 -0
- package/dist/media/Image.svelte +76 -0
- package/dist/media/Image.svelte.d.ts +41 -0
- package/dist/media/Video.svelte +65 -0
- package/dist/media/Video.svelte.d.ts +29 -0
- package/dist/media/image-dimensions.d.ts +28 -0
- package/dist/media/image-dimensions.js +34 -0
- package/dist/media/index.d.ts +10 -0
- package/dist/media/index.js +10 -0
- package/dist/search/CommandPalette.svelte +257 -0
- package/dist/search/CommandPalette.svelte.d.ts +59 -0
- package/dist/search/index.d.ts +13 -0
- package/dist/search/index.js +13 -0
- package/dist/search/types.d.ts +40 -0
- package/dist/search/types.js +20 -0
- package/dist/seo/Head.svelte +190 -0
- package/dist/seo/Head.svelte.d.ts +86 -0
- package/dist/seo/JsonLd.svelte +30 -0
- package/dist/seo/JsonLd.svelte.d.ts +20 -0
- package/dist/seo/index.d.ts +18 -0
- package/dist/seo/index.js +17 -0
- package/dist/seo/json-ld.d.ts +33 -0
- package/dist/seo/json-ld.js +29 -0
- package/dist/seo/og-image.d.ts +72 -0
- package/dist/seo/og-image.js +82 -0
- package/dist/seo/types.d.ts +43 -0
- package/dist/seo/types.js +6 -0
- package/dist/theme.css +161 -0
- package/dist/tips/PopoverTip.svelte +80 -0
- package/dist/tips/PopoverTip.svelte.d.ts +33 -0
- package/dist/tips/Tip.svelte +91 -0
- package/dist/tips/Tip.svelte.d.ts +25 -0
- package/dist/tips/index.d.ts +15 -0
- package/dist/tips/index.js +14 -0
- package/dist/tips/tip-stack.d.ts +26 -0
- package/dist/tips/tip-stack.js +37 -0
- package/dist/tips/tip-store.svelte.d.ts +75 -0
- package/dist/tips/tip-store.svelte.js +158 -0
- package/dist/tips/types.d.ts +46 -0
- package/dist/tips/types.js +6 -0
- package/dist/ui/Accordion.svelte +75 -0
- package/dist/ui/Accordion.svelte.d.ts +50 -0
- package/dist/ui/AccordionItem.svelte +73 -0
- package/dist/ui/AccordionItem.svelte.d.ts +18 -0
- package/dist/ui/Alert.svelte +61 -0
- package/dist/ui/Alert.svelte.d.ts +37 -0
- package/dist/ui/Badge.svelte +39 -0
- package/dist/ui/Badge.svelte.d.ts +32 -0
- package/dist/ui/Button.svelte +44 -0
- package/dist/ui/Button.svelte.d.ts +29 -0
- package/dist/ui/ButtonGroup.svelte +24 -0
- package/dist/ui/ButtonGroup.svelte.d.ts +17 -0
- package/dist/ui/Card.svelte +49 -0
- package/dist/ui/Card.svelte.d.ts +44 -0
- package/dist/ui/Chip.svelte +58 -0
- package/dist/ui/Chip.svelte.d.ts +21 -0
- package/dist/ui/ConfirmButton.svelte +75 -0
- package/dist/ui/ConfirmButton.svelte.d.ts +48 -0
- package/dist/ui/ContextMenu.svelte +75 -0
- package/dist/ui/ContextMenu.svelte.d.ts +25 -0
- package/dist/ui/Disclosure.svelte +46 -0
- package/dist/ui/Disclosure.svelte.d.ts +22 -0
- package/dist/ui/Divider.svelte +47 -0
- package/dist/ui/Divider.svelte.d.ts +28 -0
- package/dist/ui/DropdownMenu.svelte +44 -0
- package/dist/ui/DropdownMenu.svelte.d.ts +30 -0
- package/dist/ui/EmptyState.svelte +37 -0
- package/dist/ui/EmptyState.svelte.d.ts +22 -0
- package/dist/ui/ExternalLink.svelte +38 -0
- package/dist/ui/ExternalLink.svelte.d.ts +34 -0
- package/dist/ui/Heading.svelte +58 -0
- package/dist/ui/Heading.svelte.d.ts +22 -0
- package/dist/ui/Link.svelte +34 -0
- package/dist/ui/Link.svelte.d.ts +20 -0
- package/dist/ui/LinkButton.svelte +51 -0
- package/dist/ui/LinkButton.svelte.d.ts +33 -0
- package/dist/ui/Menu.svelte +24 -0
- package/dist/ui/Menu.svelte.d.ts +13 -0
- package/dist/ui/MenuCheckboxItem.svelte +33 -0
- package/dist/ui/MenuCheckboxItem.svelte.d.ts +20 -0
- package/dist/ui/MenuItem.svelte +73 -0
- package/dist/ui/MenuItem.svelte.d.ts +21 -0
- package/dist/ui/MenuRadioGroup.svelte +25 -0
- package/dist/ui/MenuRadioGroup.svelte.d.ts +20 -0
- package/dist/ui/MenuRadioItem.svelte +20 -0
- package/dist/ui/MenuRadioItem.svelte.d.ts +15 -0
- package/dist/ui/MenuSeparator.svelte +27 -0
- package/dist/ui/MenuSeparator.svelte.d.ts +8 -0
- package/dist/ui/MenuSub.svelte +24 -0
- package/dist/ui/MenuSub.svelte.d.ts +15 -0
- package/dist/ui/Popover.svelte +63 -0
- package/dist/ui/Popover.svelte.d.ts +40 -0
- package/dist/ui/ShareButton.svelte +64 -0
- package/dist/ui/ShareButton.svelte.d.ts +39 -0
- package/dist/ui/Skeleton.svelte +43 -0
- package/dist/ui/Skeleton.svelte.d.ts +22 -0
- package/dist/ui/Spinner.svelte +41 -0
- package/dist/ui/Spinner.svelte.d.ts +35 -0
- package/dist/ui/Stack.svelte +36 -0
- package/dist/ui/Stack.svelte.d.ts +48 -0
- package/dist/ui/ThemeToggle.svelte +65 -0
- package/dist/ui/ThemeToggle.svelte.d.ts +24 -0
- package/dist/ui/ToggleButton.svelte +58 -0
- package/dist/ui/ToggleButton.svelte.d.ts +45 -0
- package/dist/ui/ToggleGroup.svelte +142 -0
- package/dist/ui/ToggleGroup.svelte.d.ts +86 -0
- package/dist/ui/Toolbar.svelte +40 -0
- package/dist/ui/Toolbar.svelte.d.ts +20 -0
- package/dist/ui/ToolbarButton.svelte +29 -0
- package/dist/ui/ToolbarButton.svelte.d.ts +21 -0
- package/dist/ui/ToolbarLink.svelte +21 -0
- package/dist/ui/ToolbarLink.svelte.d.ts +12 -0
- package/dist/ui/ToolbarSeparator.svelte +22 -0
- package/dist/ui/ToolbarSeparator.svelte.d.ts +12 -0
- package/dist/ui/ToolbarToggleGroup.svelte +66 -0
- package/dist/ui/ToolbarToggleGroup.svelte.d.ts +52 -0
- package/dist/ui/Tooltip.svelte +54 -0
- package/dist/ui/Tooltip.svelte.d.ts +35 -0
- package/dist/ui/VisuallyHidden.svelte +23 -0
- package/dist/ui/VisuallyHidden.svelte.d.ts +10 -0
- package/dist/ui/accordion-context.d.ts +26 -0
- package/dist/ui/accordion-context.js +23 -0
- package/dist/ui/colour-token.d.ts +41 -0
- package/dist/ui/colour-token.js +49 -0
- package/dist/ui/context-menu.d.ts +13 -0
- package/dist/ui/context-menu.js +13 -0
- package/dist/ui/index.d.ts +63 -0
- package/dist/ui/index.js +62 -0
- package/dist/ui/menu-context.d.ts +20 -0
- package/dist/ui/menu-context.js +22 -0
- package/dist/ui/menu-parts/CheckboxItemPart.svelte +26 -0
- package/dist/ui/menu-parts/CheckboxItemPart.svelte.d.ts +5 -0
- package/dist/ui/menu-parts/ItemPart.svelte +29 -0
- package/dist/ui/menu-parts/ItemPart.svelte.d.ts +5 -0
- package/dist/ui/menu-parts/RadioGroupPart.svelte +24 -0
- package/dist/ui/menu-parts/RadioGroupPart.svelte.d.ts +5 -0
- package/dist/ui/menu-parts/RadioItemPart.svelte +22 -0
- package/dist/ui/menu-parts/RadioItemPart.svelte.d.ts +5 -0
- package/dist/ui/menu-parts/SeparatorPart.svelte +16 -0
- package/dist/ui/menu-parts/SeparatorPart.svelte.d.ts +5 -0
- package/dist/ui/menu-parts/SubPart.svelte +28 -0
- package/dist/ui/menu-parts/SubPart.svelte.d.ts +5 -0
- package/dist/ui/menu-parts/menu-parts.d.ts +104 -0
- package/dist/ui/menu-parts/menu-parts.js +31 -0
- package/dist/ui/menu-parts/parts.d.ts +12 -0
- package/dist/ui/menu-parts/parts.js +27 -0
- package/dist/ui/slug.d.ts +19 -0
- package/dist/ui/slug.js +25 -0
- package/dist/ui/toggle-classes.d.ts +39 -0
- package/dist/ui/toggle-classes.js +36 -0
- package/dist/ui/tones.d.ts +103 -0
- package/dist/ui/tones.js +240 -0
- package/package.json +41 -25
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { HTMLInputAttributes } from 'svelte/elements';
|
|
2
|
+
import { type FieldSize } from './field-types.ts';
|
|
3
|
+
import { type NumberLocales } from './number-format.ts';
|
|
4
|
+
interface Props extends Omit<HTMLInputAttributes, 'value' | 'type' | 'size' | 'min' | 'max' | 'step' | 'inputmode' | 'children'> {
|
|
5
|
+
/** The number, or `undefined` while the field is empty. Bindable. */
|
|
6
|
+
value?: number | undefined;
|
|
7
|
+
/** The lowest value; also what Home goes to. */
|
|
8
|
+
min?: number | undefined;
|
|
9
|
+
/** The highest value; also what End goes to. */
|
|
10
|
+
max?: number | undefined;
|
|
11
|
+
/**
|
|
12
|
+
* Increment for the buttons and the arrow keys.
|
|
13
|
+
* @defaultValue `1`
|
|
14
|
+
*/
|
|
15
|
+
step?: number | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* Increment for Page Up / Page Down.
|
|
18
|
+
* @defaultValue `step * 10`
|
|
19
|
+
*/
|
|
20
|
+
largeStep?: number | undefined;
|
|
21
|
+
/** How the value is displayed and parsed, e.g. `{ style: 'unit', unit: 'centimeter' }`, `{ style: 'percent' }`, `{ style: 'currency', currency: 'AUD' }`. */
|
|
22
|
+
formatOptions?: Intl.NumberFormatOptions | undefined;
|
|
23
|
+
/** BCP 47 locale(s) to format and parse in; falls back to the context's `locale()`. */
|
|
24
|
+
locales?: NumberLocales;
|
|
25
|
+
/**
|
|
26
|
+
* Show the − / + buttons.
|
|
27
|
+
* @defaultValue `true`
|
|
28
|
+
*/
|
|
29
|
+
showStepper?: boolean | undefined;
|
|
30
|
+
/**
|
|
31
|
+
* Accessible name of the − button.
|
|
32
|
+
* @defaultValue `'Decrease'`
|
|
33
|
+
*/
|
|
34
|
+
decrementLabel?: string | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* Accessible name of the + button.
|
|
37
|
+
* @defaultValue `'Increase'`
|
|
38
|
+
*/
|
|
39
|
+
incrementLabel?: string | undefined;
|
|
40
|
+
/** Called with the committed number on blur, Enter or a step — not on every keystroke. */
|
|
41
|
+
onCommit?: ((value: number | undefined) => void) | undefined;
|
|
42
|
+
/** Posts the raw number (not the formatted text) under this name, through a hidden input. */
|
|
43
|
+
name?: string | undefined;
|
|
44
|
+
/**
|
|
45
|
+
* daisyUI size step.
|
|
46
|
+
* @defaultValue `'md'`
|
|
47
|
+
*/
|
|
48
|
+
size?: FieldSize | undefined;
|
|
49
|
+
/**
|
|
50
|
+
* Disables the input and both buttons.
|
|
51
|
+
* @defaultValue `false`
|
|
52
|
+
*/
|
|
53
|
+
disabled?: boolean | undefined;
|
|
54
|
+
/** `FieldControl`: the input's `id`, which `FormField`'s label points at. Minted when omitted. */
|
|
55
|
+
id?: string | undefined;
|
|
56
|
+
/**
|
|
57
|
+
* `FieldControl`: space-separated ids for `aria-describedby`.
|
|
58
|
+
* @defaultValue `''`
|
|
59
|
+
*/
|
|
60
|
+
describedBy?: string | undefined;
|
|
61
|
+
/**
|
|
62
|
+
* `FieldControl`: the visible label's id. Not used — the input is
|
|
63
|
+
* labelable, so the `FormField`'s `<label for>` already names it; taken
|
|
64
|
+
* here so a spread `FieldControl` does not leak it as an attribute.
|
|
65
|
+
*/
|
|
66
|
+
labelId?: string | undefined;
|
|
67
|
+
/**
|
|
68
|
+
* `FieldControl`: the field is in error — sets `aria-invalid` and `input-error`.
|
|
69
|
+
* @defaultValue `false`
|
|
70
|
+
*/
|
|
71
|
+
invalid?: boolean | undefined;
|
|
72
|
+
}
|
|
73
|
+
/** An exact number the reader types or nudges, shown locale-formatted (units, percent, currency) with − / + stepper buttons: the APG spinbutton. */
|
|
74
|
+
declare const NumberField: import("svelte").Component<Props, {}, "value">;
|
|
75
|
+
type NumberField = ReturnType<typeof NumberField>;
|
|
76
|
+
export default NumberField;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
<!-- @component
|
|
2
|
+
A password field with a "Show password" toggle and the `autocomplete` a password manager needs to fill or generate it.
|
|
3
|
+
-->
|
|
4
|
+
<!--
|
|
5
|
+
PasswordInput — a `TextInput`-styled password field inside a daisyUI
|
|
6
|
+
`input` composite, with a trailing toggle that flips the input between
|
|
7
|
+
`type="password"` and `type="text"`, and a `purpose` prop that sets
|
|
8
|
+
`autocomplete` to `current-password` or `new-password`, which is what makes
|
|
9
|
+
a password manager fill (sign-in) or offer to generate (sign-up).
|
|
10
|
+
|
|
11
|
+
Why not a `revealable` prop on `TextInput`: `TextInput` IS a bare `<input>`,
|
|
12
|
+
and a toggle needs a wrapper and a button, which would move where `class`
|
|
13
|
+
and `...rest` land for every existing caller. So this follows `SearchInput`,
|
|
14
|
+
the composite-input precedent: a `<div class="input">` (not a `<label>`,
|
|
15
|
+
which would fold the toggle's name into the input's accessible name when
|
|
16
|
+
the field sits inside `FormField`), the native input inside it, a trailing
|
|
17
|
+
button. `...rest` (`id`, `name`, `minlength`, `aria-*`, `data-*`) goes on
|
|
18
|
+
the inner input, the element a label, a test and a form need; `class` goes
|
|
19
|
+
on the wrapper and `inputClass` on the input. `passwordrules` is passed
|
|
20
|
+
through when given, never defaulted.
|
|
21
|
+
|
|
22
|
+
ARIA contract: the toggle is an APG button with `aria-pressed` — a real
|
|
23
|
+
`<button type="button">` (so it never submits the form) with a CONSTANT
|
|
24
|
+
name, `showLabel`, and a pressed state ("Show password, toggle button,
|
|
25
|
+
pressed"), rather than a name that swaps between "Show" and "Hide", which
|
|
26
|
+
some screen readers do not re-announce. It `aria-controls` the input; its
|
|
27
|
+
icon is `aria-hidden`. Activating it leaves focus on the toggle and keeps
|
|
28
|
+
the input's selection range across the type flip. The input keeps native
|
|
29
|
+
semantics plus `FieldControl`'s `aria-describedby`, `aria-invalid` and
|
|
30
|
+
`required`.
|
|
31
|
+
|
|
32
|
+
The field is hidden again when its form submits, so a revealed password
|
|
33
|
+
does not survive into the browser's form-restore cache.
|
|
34
|
+
-->
|
|
35
|
+
<script lang="ts">import { Eye, EyeOff } from "@lucide/svelte";
|
|
36
|
+
import { inputButtonSize, inputSize } from "./field-types.js";
|
|
37
|
+
let { value = $bindable(""), purpose = "current", revealed = $bindable(false), revealable = true, showLabel = "Show password", size = "md", inputClass, id: idProp, describedBy = "", labelId: _labelId, invalid = false, class: className, ...rest } = $props();
|
|
38
|
+
const uid = $props.id();
|
|
39
|
+
const id = $derived(idProp ?? uid);
|
|
40
|
+
let input = $state(null);
|
|
41
|
+
/**
|
|
42
|
+
* Flip `revealed`, keeping the caret / selection where it was. Chromium
|
|
43
|
+
* rebuilds a text field's inner editor when its `type` changes and drops the
|
|
44
|
+
* selection at the next rendering step, so the range is put back in the
|
|
45
|
+
* following animation frame.
|
|
46
|
+
*/
|
|
47
|
+
function toggle() {
|
|
48
|
+
const start = input?.selectionStart ?? null;
|
|
49
|
+
const end = input?.selectionEnd ?? null;
|
|
50
|
+
revealed = !revealed;
|
|
51
|
+
if (start === null || end === null) return;
|
|
52
|
+
requestAnimationFrame(() => input?.setSelectionRange(start, end));
|
|
53
|
+
}
|
|
54
|
+
// Hide again on submit, so a revealed password is not restored with the form.
|
|
55
|
+
$effect(() => {
|
|
56
|
+
const form = input?.form;
|
|
57
|
+
if (form === null || form === undefined) return;
|
|
58
|
+
const hide = () => {
|
|
59
|
+
revealed = false;
|
|
60
|
+
};
|
|
61
|
+
form.addEventListener("submit", hide);
|
|
62
|
+
return () => form.removeEventListener("submit", hide);
|
|
63
|
+
});
|
|
64
|
+
</script>
|
|
65
|
+
|
|
66
|
+
<div class={['input w-full', inputSize[size], invalid && 'input-error', revealable && 'pe-1', className]}>
|
|
67
|
+
<input
|
|
68
|
+
{...rest}
|
|
69
|
+
bind:this={input}
|
|
70
|
+
{id}
|
|
71
|
+
type={revealed ? 'text' : 'password'}
|
|
72
|
+
autocomplete={purpose === 'new' ? 'new-password' : 'current-password'}
|
|
73
|
+
bind:value
|
|
74
|
+
aria-invalid={invalid ? 'true' : undefined}
|
|
75
|
+
aria-describedby={describedBy === '' ? undefined : describedBy}
|
|
76
|
+
class={inputClass}
|
|
77
|
+
/>
|
|
78
|
+
{#if revealable}
|
|
79
|
+
<button
|
|
80
|
+
type="button"
|
|
81
|
+
aria-pressed={revealed}
|
|
82
|
+
aria-controls={id}
|
|
83
|
+
disabled={rest.disabled === true}
|
|
84
|
+
class={['btn btn-square btn-ghost', inputButtonSize[size]]}
|
|
85
|
+
onclick={toggle}
|
|
86
|
+
>
|
|
87
|
+
{#if revealed}
|
|
88
|
+
<EyeOff class="size-4" aria-hidden="true" />
|
|
89
|
+
{:else}
|
|
90
|
+
<Eye class="size-4" aria-hidden="true" />
|
|
91
|
+
{/if}
|
|
92
|
+
<span class="sr-only">{showLabel}</span>
|
|
93
|
+
</button>
|
|
94
|
+
{/if}
|
|
95
|
+
</div>
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { HTMLInputAttributes } from 'svelte/elements';
|
|
2
|
+
import { type FieldSize } from './field-types.ts';
|
|
3
|
+
interface Props extends Omit<HTMLInputAttributes, 'type' | 'value' | 'size' | 'autocomplete'> {
|
|
4
|
+
/**
|
|
5
|
+
* The password. Bindable.
|
|
6
|
+
* @defaultValue `''`
|
|
7
|
+
*/
|
|
8
|
+
value?: string | undefined;
|
|
9
|
+
/**
|
|
10
|
+
* Which password: sets `autocomplete` to `current-password` (sign-in) or `new-password` (sign-up, change password).
|
|
11
|
+
* @defaultValue `'current'`
|
|
12
|
+
*/
|
|
13
|
+
purpose?: 'current' | 'new' | undefined;
|
|
14
|
+
/**
|
|
15
|
+
* Whether the text is currently shown. Bindable.
|
|
16
|
+
* @defaultValue `false`
|
|
17
|
+
*/
|
|
18
|
+
revealed?: boolean | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* Render the show/hide toggle; without it the field is a styled `type="password"`.
|
|
21
|
+
* @defaultValue `true`
|
|
22
|
+
*/
|
|
23
|
+
revealable?: boolean | undefined;
|
|
24
|
+
/**
|
|
25
|
+
* The toggle's accessible name; its `aria-pressed` state says whether it is on.
|
|
26
|
+
* @defaultValue `'Show password'`
|
|
27
|
+
*/
|
|
28
|
+
showLabel?: string | undefined;
|
|
29
|
+
/**
|
|
30
|
+
* daisyUI size step.
|
|
31
|
+
* @defaultValue `'md'`
|
|
32
|
+
*/
|
|
33
|
+
size?: FieldSize | undefined;
|
|
34
|
+
/** Extra classes on the inner `<input>`; `class` goes on the wrapper. */
|
|
35
|
+
inputClass?: string | undefined;
|
|
36
|
+
/** `FieldControl`: the input's `id`, which `FormField`'s label points at. Minted when omitted. */
|
|
37
|
+
id?: string | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* `FieldControl`: space-separated ids for `aria-describedby`.
|
|
40
|
+
* @defaultValue `''`
|
|
41
|
+
*/
|
|
42
|
+
describedBy?: string | undefined;
|
|
43
|
+
/**
|
|
44
|
+
* `FieldControl`: the visible label's id. Not used — the input is
|
|
45
|
+
* labelable, so the `FormField`'s `<label for>` already names it; taken
|
|
46
|
+
* here so a spread `FieldControl` does not leak it as an attribute.
|
|
47
|
+
*/
|
|
48
|
+
labelId?: string | undefined;
|
|
49
|
+
/**
|
|
50
|
+
* `FieldControl`: the field is in error — sets `aria-invalid` and `input-error`.
|
|
51
|
+
* @defaultValue `false`
|
|
52
|
+
*/
|
|
53
|
+
invalid?: boolean | undefined;
|
|
54
|
+
}
|
|
55
|
+
/** A password field with a "Show password" toggle and the `autocomplete` a password manager needs to fill or generate it. */
|
|
56
|
+
declare const PasswordInput: import("svelte").Component<Props, {}, "value" | "revealed">;
|
|
57
|
+
type PasswordInput = ReturnType<typeof PasswordInput>;
|
|
58
|
+
export default PasswordInput;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
<!-- @component
|
|
2
|
+
The trigger and calendar popover `DatePicker` and `DateRangePicker` share; internal, not exported.
|
|
3
|
+
-->
|
|
4
|
+
<!--
|
|
5
|
+
PickerPopover — the calendar button that sits in a picker's shell, and
|
|
6
|
+
the popover it opens. `parts` is `DatePicker` or `DateRangePicker`; both
|
|
7
|
+
expose `Trigger`, `Portal`, `Content` and `Calendar` with the same props,
|
|
8
|
+
and their calendar body is `CalendarMonths`, the same one `Calendar`
|
|
9
|
+
renders inline.
|
|
10
|
+
|
|
11
|
+
The trigger is icon-only, so it is named by `triggerLabel` ("Choose
|
|
12
|
+
date"), the glyph `aria-hidden`; bits-ui gives it `aria-haspopup="dialog"`
|
|
13
|
+
and `aria-expanded`. The popover is a `role="dialog"` named by
|
|
14
|
+
`calendarLabel`; bits-ui moves focus into the grid, closes on Escape and
|
|
15
|
+
returns focus to the trigger.
|
|
16
|
+
-->
|
|
17
|
+
<script lang="ts">import { Calendar as CalendarIcon } from "@lucide/svelte";
|
|
18
|
+
import { Portal } from "bits-ui";
|
|
19
|
+
import CalendarMonths from "./CalendarMonths.svelte";
|
|
20
|
+
let { parts, triggerLabel, calendarLabel, months, disabled } = $props();
|
|
21
|
+
// SAFETY: both namespaces' Trigger / Content / Calendar are the same
|
|
22
|
+
// bits-ui popover and calendar parts under two names. (`DateRangePicker`
|
|
23
|
+
// exports no `Portal`, so the shared utility is used for both.)
|
|
24
|
+
const P = $derived(parts);
|
|
25
|
+
</script>
|
|
26
|
+
|
|
27
|
+
<P.Trigger {disabled}>
|
|
28
|
+
{#snippet child({ props })}
|
|
29
|
+
<button {...props} type="button" class="btn btn-ghost btn-xs btn-square ms-1" aria-label={triggerLabel}>
|
|
30
|
+
<CalendarIcon class="size-4" aria-hidden="true" />
|
|
31
|
+
</button>
|
|
32
|
+
{/snippet}
|
|
33
|
+
</P.Trigger>
|
|
34
|
+
<Portal>
|
|
35
|
+
<P.Content
|
|
36
|
+
sideOffset={6}
|
|
37
|
+
role="dialog"
|
|
38
|
+
aria-label={calendarLabel}
|
|
39
|
+
class="card card-border bg-base-100 rounded-box z-50 p-3 shadow-md"
|
|
40
|
+
>
|
|
41
|
+
<P.Calendar>
|
|
42
|
+
{#snippet children({ months: grid, weekdays })}
|
|
43
|
+
<CalendarMonths {parts} {...months} months={grid} {weekdays} />
|
|
44
|
+
{/snippet}
|
|
45
|
+
</P.Calendar>
|
|
46
|
+
</P.Content>
|
|
47
|
+
</Portal>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type DatePicker, type DateRangePicker } from 'bits-ui';
|
|
2
|
+
interface Props {
|
|
3
|
+
parts: typeof DatePicker | typeof DateRangePicker;
|
|
4
|
+
triggerLabel: string;
|
|
5
|
+
calendarLabel: string;
|
|
6
|
+
months: {
|
|
7
|
+
readonly locale: string;
|
|
8
|
+
readonly previousLabel: string;
|
|
9
|
+
readonly nextLabel: string;
|
|
10
|
+
};
|
|
11
|
+
disabled: boolean;
|
|
12
|
+
}
|
|
13
|
+
/** The trigger and calendar popover `DatePicker` and `DateRangePicker` share; internal, not exported. */
|
|
14
|
+
declare const PickerPopover: import("svelte").Component<Props, {}, "">;
|
|
15
|
+
type PickerPopover = ReturnType<typeof PickerPopover>;
|
|
16
|
+
export default PickerPopover;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
<!-- @component
|
|
2
|
+
A fixed-length code — a sign-in code, a TOTP, an invite code — typed one character per visible cell into one real input, on bits-ui's `PinInput`.
|
|
3
|
+
-->
|
|
4
|
+
<!--
|
|
5
|
+
PinInput — one real `<input>` (bits-ui `PinInput`) drawn as a row of
|
|
6
|
+
cells. Being one input is the whole point: paste, SMS autofill
|
|
7
|
+
(`autocomplete="one-time-code"`), password managers and form posting all
|
|
8
|
+
treat it as one field, and a screen reader hears one text field rather
|
|
9
|
+
than six unlabelled one-character edits — the failure mode of the
|
|
10
|
+
hand-rolled six-`<input maxlength=1>` pattern.
|
|
11
|
+
|
|
12
|
+
ARIA contract: there is no APG pattern for segmented code entry; the
|
|
13
|
+
contract is "a single text input". The input carries the `FieldControl` id
|
|
14
|
+
(bits-ui `inputId`), so `FormField`'s `<label for>` names it, plus
|
|
15
|
+
`aria-describedby`, `aria-invalid`, `required`, `inputmode`,
|
|
16
|
+
`autocomplete` and `maxlength`. The cells are `aria-hidden` presentation
|
|
17
|
+
and nothing in them is focusable. The keyboard is the platform's: typing
|
|
18
|
+
advances, Backspace deletes, arrows move the caret, paste fills the code;
|
|
19
|
+
bits-ui draws the fake caret in the active cell.
|
|
20
|
+
|
|
21
|
+
`charset` maps to `inputmode` and to bits-ui's own patterns
|
|
22
|
+
(`REGEXP_ONLY_DIGITS` / `REGEXP_ONLY_DIGITS_AND_CHARS`), which both reject
|
|
23
|
+
a keystroke that does not match and become the input's `pattern`.
|
|
24
|
+
`pasteTransformer` defaults to stripping whitespace and hyphens, so a code
|
|
25
|
+
pasted from an email as "123 456" or "123-456" lands as "123456".
|
|
26
|
+
|
|
27
|
+
Styling decision (the issue asked for one to be recorded): bits-ui's
|
|
28
|
+
explicit `PinInput.Cell` elements, styled with `input`-like utilities and
|
|
29
|
+
the literal `pinCellSize` table, rather than daisyUI `otp` on the hidden
|
|
30
|
+
input. bits-ui renders the real input transparent over the cells, so
|
|
31
|
+
`otp`'s CSS-drawn cells would sit on an invisible element, and bits-ui's
|
|
32
|
+
fake caret and its password-manager badge offset
|
|
33
|
+
(`pushPasswordManagerStrategy`) are positioned against the cells.
|
|
34
|
+
|
|
35
|
+
`masked` renders `•` in each filled cell in place of the character (bits-ui
|
|
36
|
+
2.20 has no masking prop). The input itself is unchanged — it keeps
|
|
37
|
+
`autocomplete` so a password manager can still fill it, and it is
|
|
38
|
+
transparent, so the characters are never drawn.
|
|
39
|
+
-->
|
|
40
|
+
<script lang="ts">import { PinInput, REGEXP_ONLY_DIGITS, REGEXP_ONLY_DIGITS_AND_CHARS } from "bits-ui";
|
|
41
|
+
import { pinCellSize } from "./field-types.js";
|
|
42
|
+
let { value = $bindable(""), length = 6, charset = "numeric", masked = false, onComplete, pasteTransformer = (text) => text.replace(/[\s-]/g, ""), autocomplete = "one-time-code", size = "md", disabled = false, id, describedBy = "", labelId: _labelId, invalid = false, class: className, ...rest } = $props();
|
|
43
|
+
const uid = $props.id();
|
|
44
|
+
const inputId = $derived(id ?? uid);
|
|
45
|
+
</script>
|
|
46
|
+
|
|
47
|
+
<PinInput.Root
|
|
48
|
+
{...rest}
|
|
49
|
+
bind:value
|
|
50
|
+
{inputId}
|
|
51
|
+
maxlength={length}
|
|
52
|
+
pattern={charset === 'numeric' ? REGEXP_ONLY_DIGITS : REGEXP_ONLY_DIGITS_AND_CHARS}
|
|
53
|
+
inputmode={charset === 'numeric' ? 'numeric' : 'text'}
|
|
54
|
+
{autocomplete}
|
|
55
|
+
{disabled}
|
|
56
|
+
{pasteTransformer}
|
|
57
|
+
onComplete={(code: string) => onComplete?.(code)}
|
|
58
|
+
aria-describedby={describedBy === '' ? undefined : describedBy}
|
|
59
|
+
aria-invalid={invalid ? 'true' : undefined}
|
|
60
|
+
class={['flex items-center gap-2 has-disabled:opacity-50', className]}
|
|
61
|
+
>
|
|
62
|
+
{#snippet children({ cells })}
|
|
63
|
+
{#each cells as cell, index (index)}
|
|
64
|
+
<PinInput.Cell
|
|
65
|
+
{cell}
|
|
66
|
+
aria-hidden="true"
|
|
67
|
+
class={[
|
|
68
|
+
'relative flex items-center justify-center rounded-field border bg-base-100 font-mono',
|
|
69
|
+
'data-active:outline-2 data-active:outline-offset-2',
|
|
70
|
+
invalid ? 'border-error data-active:outline-error' : 'border-base-content/20 data-active:outline-primary',
|
|
71
|
+
pinCellSize[size],
|
|
72
|
+
]}
|
|
73
|
+
>
|
|
74
|
+
{#if cell.char !== null && cell.char !== undefined}
|
|
75
|
+
{masked ? '•' : cell.char}
|
|
76
|
+
{/if}
|
|
77
|
+
{#if cell.hasFakeCaret}
|
|
78
|
+
<span class="h-1/2 w-px animate-pulse bg-base-content motion-reduce:animate-none"></span>
|
|
79
|
+
{/if}
|
|
80
|
+
</PinInput.Cell>
|
|
81
|
+
{/each}
|
|
82
|
+
{/snippet}
|
|
83
|
+
</PinInput.Root>
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { PinInput } from 'bits-ui';
|
|
2
|
+
import type { HTMLInputAttributes } from 'svelte/elements';
|
|
3
|
+
import { type FieldSize } from './field-types.ts';
|
|
4
|
+
interface Props extends Omit<HTMLInputAttributes, 'value' | 'size' | 'type' | 'maxlength' | 'pattern' | 'children' | 'inputmode'> {
|
|
5
|
+
/**
|
|
6
|
+
* The code typed so far. Bindable.
|
|
7
|
+
* @defaultValue `''`
|
|
8
|
+
*/
|
|
9
|
+
value?: string | undefined;
|
|
10
|
+
/**
|
|
11
|
+
* Number of cells, and the input's `maxlength`.
|
|
12
|
+
* @defaultValue `6`
|
|
13
|
+
*/
|
|
14
|
+
length?: number | undefined;
|
|
15
|
+
/**
|
|
16
|
+
* Which characters are accepted; sets `inputmode` and the input's pattern.
|
|
17
|
+
* @defaultValue `'numeric'`
|
|
18
|
+
*/
|
|
19
|
+
charset?: 'numeric' | 'alphanumeric' | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* Show `•` in the cells instead of the characters (a PIN rather than a code).
|
|
22
|
+
* @defaultValue `false`
|
|
23
|
+
*/
|
|
24
|
+
masked?: boolean | undefined;
|
|
25
|
+
/** Called once every cell is filled, with the full code — typically to submit. */
|
|
26
|
+
onComplete?: ((code: string) => void) | undefined;
|
|
27
|
+
/** Normalise pasted text before it is applied. Defaults to stripping whitespace and hyphens. */
|
|
28
|
+
pasteTransformer?: ((text: string) => string) | undefined;
|
|
29
|
+
/**
|
|
30
|
+
* The input's `autocomplete`.
|
|
31
|
+
* @defaultValue `'one-time-code'`
|
|
32
|
+
*/
|
|
33
|
+
autocomplete?: HTMLInputAttributes['autocomplete'];
|
|
34
|
+
/**
|
|
35
|
+
* Size step of the cells.
|
|
36
|
+
* @defaultValue `'md'`
|
|
37
|
+
*/
|
|
38
|
+
size?: FieldSize | undefined;
|
|
39
|
+
/**
|
|
40
|
+
* Disables the input.
|
|
41
|
+
* @defaultValue `false`
|
|
42
|
+
*/
|
|
43
|
+
disabled?: boolean | undefined;
|
|
44
|
+
/** `FieldControl`: the real input's `id`, which `FormField`'s label points at. */
|
|
45
|
+
id?: string | undefined;
|
|
46
|
+
/**
|
|
47
|
+
* `FieldControl`: space-separated ids for `aria-describedby`.
|
|
48
|
+
* @defaultValue `''`
|
|
49
|
+
*/
|
|
50
|
+
describedBy?: string | undefined;
|
|
51
|
+
/**
|
|
52
|
+
* `FieldControl`: the visible label's id. Not used — the real input is
|
|
53
|
+
* labelable, so the `FormField`'s `<label for>` already names it; taken
|
|
54
|
+
* here so a spread `FieldControl` does not leak it as an attribute.
|
|
55
|
+
*/
|
|
56
|
+
labelId?: string | undefined;
|
|
57
|
+
/**
|
|
58
|
+
* `FieldControl`: the field is in error — sets `aria-invalid` and the error border.
|
|
59
|
+
* @defaultValue `false`
|
|
60
|
+
*/
|
|
61
|
+
invalid?: boolean | undefined;
|
|
62
|
+
}
|
|
63
|
+
/** A fixed-length code — a sign-in code, a TOTP, an invite code — typed one character per visible cell into one real input, on bits-ui's `PinInput`. */
|
|
64
|
+
declare const PinInput: import("svelte").Component<Props, {}, "value">;
|
|
65
|
+
type PinInput = ReturnType<typeof PinInput>;
|
|
66
|
+
export default PinInput;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
<!-- @component
|
|
2
|
+
A `Toggle` that subscribes this browser to Web Push, or unsubscribes it, through the caller’s `enable` / `disable`.
|
|
3
|
+
-->
|
|
4
|
+
<!--
|
|
5
|
+
PushToggle — the browser half of Web Push behind one `Toggle`: it reads
|
|
6
|
+
whether THIS browser is subscribed, and turns the subscription on or off
|
|
7
|
+
through the caller's `enable` / `disable`.
|
|
8
|
+
|
|
9
|
+
The switch reflects this browser's registration, not the account's
|
|
10
|
+
preference — two different questions, and a settings page asks both.
|
|
11
|
+
`enable` / `disable` are props rather than imports because the network calls
|
|
12
|
+
(subscribing with the VAPID key, registering the endpoint with the app's
|
|
13
|
+
API) belong to the app's own client; injecting them keeps this package free
|
|
14
|
+
of it.
|
|
15
|
+
|
|
16
|
+
Every failure of `enable` is a different thing to tell the reader — the
|
|
17
|
+
browser cannot, the site cannot, or they said no — so `enable` RESOLVES with
|
|
18
|
+
an outcome instead of throwing, and each reason renders its own message.
|
|
19
|
+
The switch writes back what actually happened (see `Toggle`), so a denied
|
|
20
|
+
permission never reads as "on".
|
|
21
|
+
|
|
22
|
+
The subscription state is read on mount, from the browser, rather than
|
|
23
|
+
trusted from a prop: the page may be cached, and the reader may have revoked
|
|
24
|
+
the permission in browser settings since it rendered. `supported` and
|
|
25
|
+
`readSubscribed` default to the real browser checks and exist so a caller
|
|
26
|
+
(or a test) can supply its own.
|
|
27
|
+
|
|
28
|
+
ARIA contract: `Toggle`'s — a native checkbox with `role="switch"`, named by
|
|
29
|
+
`label`. The notice under it is a polite live region, so a refusal is
|
|
30
|
+
announced when it appears.
|
|
31
|
+
-->
|
|
32
|
+
<script lang="ts">import Toggle from "./Toggle.svelte";
|
|
33
|
+
let { available, enable, disable, supported = typeof navigator !== "undefined" && "serviceWorker" in navigator && "PushManager" in globalThis, readSubscribed = async () => {
|
|
34
|
+
const registration = await navigator.serviceWorker.ready;
|
|
35
|
+
return await registration.pushManager.getSubscription() !== null;
|
|
36
|
+
}, label = "Send push notifications to this browser", description, unavailableMessage = "Push notifications aren't available on this site yet.", unsupportedMessage = "This browser can't receive push notifications.", deniedMessage = "This browser is blocking notifications. Allow them in your browser settings to turn this on.", class: className } = $props();
|
|
37
|
+
let subscribed = $state(false);
|
|
38
|
+
let notice = $state(undefined);
|
|
39
|
+
// Aborted on unmount, so a request in flight when the reader navigates away
|
|
40
|
+
// is cancelled rather than resolving into a destroyed component.
|
|
41
|
+
const controller = new AbortController();
|
|
42
|
+
$effect(() => () => controller.abort());
|
|
43
|
+
$effect(() => {
|
|
44
|
+
if (!available) return;
|
|
45
|
+
if (!supported) {
|
|
46
|
+
notice = "unsupported";
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
void readSubscribed(controller.signal).then((value) => {
|
|
50
|
+
subscribed = value;
|
|
51
|
+
}, () => {
|
|
52
|
+
// Unreadable is reported as off; the switch still works.
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
const apply = async (next) => {
|
|
56
|
+
notice = undefined;
|
|
57
|
+
if (!next) {
|
|
58
|
+
await disable(controller.signal);
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
const result = await enable(controller.signal);
|
|
62
|
+
if (result._tag === "enabled") return true;
|
|
63
|
+
notice = result._tag;
|
|
64
|
+
return false;
|
|
65
|
+
};
|
|
66
|
+
const messages = $derived({
|
|
67
|
+
unsupported: unsupportedMessage,
|
|
68
|
+
unavailable: unavailableMessage,
|
|
69
|
+
denied: deniedMessage
|
|
70
|
+
});
|
|
71
|
+
const noticeTone = {
|
|
72
|
+
unsupported: "text-base-content/70",
|
|
73
|
+
unavailable: "text-base-content/70",
|
|
74
|
+
denied: "text-warning"
|
|
75
|
+
};
|
|
76
|
+
</script>
|
|
77
|
+
|
|
78
|
+
{#if !available}
|
|
79
|
+
<p class={['text-base-content/70 text-sm', className]}>{unavailableMessage}</p>
|
|
80
|
+
{:else}
|
|
81
|
+
<div class={['flex flex-col gap-2', className]}>
|
|
82
|
+
<Toggle
|
|
83
|
+
{label}
|
|
84
|
+
{description}
|
|
85
|
+
checked={subscribed}
|
|
86
|
+
disabled={!supported}
|
|
87
|
+
onChange={apply}
|
|
88
|
+
/>
|
|
89
|
+
<p class={['text-sm', notice === undefined ? '' : noticeTone[notice]]} aria-live="polite">
|
|
90
|
+
{notice === undefined ? '' : messages[notice]}
|
|
91
|
+
</p>
|
|
92
|
+
</div>
|
|
93
|
+
{/if}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/** Why `enable` did not subscribe this browser. */
|
|
2
|
+
export type PushDeclineReason = 'unsupported' | 'unavailable' | 'denied';
|
|
3
|
+
/**
|
|
4
|
+
* What `enable` resolves with: it worked, or why not. The `_tag` shape
|
|
5
|
+
* matches a tagged-union result an Effect client already returns.
|
|
6
|
+
*/
|
|
7
|
+
export interface PushEnableResult {
|
|
8
|
+
readonly _tag: 'enabled' | PushDeclineReason;
|
|
9
|
+
}
|
|
10
|
+
interface Props {
|
|
11
|
+
/** False when the site has no push configuration (no VAPID key pair): the switch is not offered. */
|
|
12
|
+
available: boolean;
|
|
13
|
+
/** Subscribe this browser and register it. Resolves with the outcome rather than throwing. */
|
|
14
|
+
enable: (signal: AbortSignal) => Promise<PushEnableResult>;
|
|
15
|
+
/** Unsubscribe this browser. Its resolved value is ignored. */
|
|
16
|
+
disable: (signal: AbortSignal) => Promise<unknown>;
|
|
17
|
+
/**
|
|
18
|
+
* Whether this browser can do Web Push at all.
|
|
19
|
+
* @defaultValue feature detection (`serviceWorker` and `PushManager`)
|
|
20
|
+
*/
|
|
21
|
+
supported?: boolean | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* Whether this browser is subscribed now.
|
|
24
|
+
* @defaultValue asks the service worker's `PushManager`
|
|
25
|
+
*/
|
|
26
|
+
readSubscribed?: ((signal: AbortSignal) => Promise<boolean>) | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* Text beside the switch; its accessible name.
|
|
29
|
+
* @defaultValue `'Send push notifications to this browser'`
|
|
30
|
+
*/
|
|
31
|
+
label?: string | undefined;
|
|
32
|
+
/** A sentence under the switch. */
|
|
33
|
+
description?: string | undefined;
|
|
34
|
+
/**
|
|
35
|
+
* Shown instead of the switch when `available` is false.
|
|
36
|
+
* @defaultValue `"Push notifications aren't available on this site yet."`
|
|
37
|
+
*/
|
|
38
|
+
unavailableMessage?: string | undefined;
|
|
39
|
+
/**
|
|
40
|
+
* Shown instead of the switch when the browser cannot do Web Push.
|
|
41
|
+
* @defaultValue `"This browser can't receive push notifications."`
|
|
42
|
+
*/
|
|
43
|
+
unsupportedMessage?: string | undefined;
|
|
44
|
+
/**
|
|
45
|
+
* Shown when the browser’s notification permission is denied.
|
|
46
|
+
* @defaultValue `'This browser is blocking notifications. Allow them in your browser settings to turn this on.'`
|
|
47
|
+
*/
|
|
48
|
+
deniedMessage?: string | undefined;
|
|
49
|
+
/** Extra classes, merged last. */
|
|
50
|
+
class?: string | undefined;
|
|
51
|
+
}
|
|
52
|
+
/** A `Toggle` that subscribes this browser to Web Push, or unsubscribes it, through the caller’s `enable` / `disable`. */
|
|
53
|
+
declare const PushToggle: import("svelte").Component<Props, {}, "">;
|
|
54
|
+
type PushToggle = ReturnType<typeof PushToggle>;
|
|
55
|
+
export default PushToggle;
|