@thomasfosterau/components 0.0.0 → 0.1.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 +2 -2
- package/dist/canvas/VectorCanvas.svelte +239 -0
- package/dist/canvas/VectorCanvas.svelte.d.ts +87 -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 +38 -0
- package/dist/context.svelte.d.ts +46 -0
- package/dist/context.svelte.js +51 -0
- package/dist/data/DataGrid.svelte +150 -0
- package/dist/data/DataGrid.svelte.d.ts +118 -0
- package/dist/data/DescriptionList.svelte +47 -0
- package/dist/data/DescriptionList.svelte.d.ts +26 -0
- package/dist/data/DescriptionRow.svelte +55 -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/Pagination.svelte +136 -0
- package/dist/data/Pagination.svelte.d.ts +71 -0
- package/dist/data/PaginationFooter.svelte +41 -0
- package/dist/data/PaginationFooter.svelte.d.ts +59 -0
- package/dist/data/ResultCount.svelte +27 -0
- package/dist/data/ResultCount.svelte.d.ts +18 -0
- package/dist/data/Table.svelte +145 -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 +33 -0
- package/dist/data/description-context.js +35 -0
- package/dist/data/diff.d.ts +14 -0
- package/dist/data/diff.js +10 -0
- package/dist/data/index.d.ts +35 -0
- package/dist/data/index.js +35 -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 +64 -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 +77 -0
- package/dist/feedback/Dialog.svelte.d.ts +37 -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 +36 -0
- package/dist/feedback/StatTile.svelte +77 -0
- package/dist/feedback/StatTile.svelte.d.ts +49 -0
- package/dist/feedback/Stats.svelte +18 -0
- package/dist/feedback/Stats.svelte.d.ts +16 -0
- package/dist/feedback/Timeline.svelte +86 -0
- package/dist/feedback/Timeline.svelte.d.ts +52 -0
- package/dist/feedback/Toaster.svelte +78 -0
- package/dist/feedback/Toaster.svelte.d.ts +32 -0
- package/dist/feedback/index.d.ts +31 -0
- package/dist/feedback/index.js +27 -0
- package/dist/feedback/sizes.d.ts +27 -0
- package/dist/feedback/sizes.js +41 -0
- package/dist/feedback/toaster.d.ts +48 -0
- package/dist/feedback/toaster.js +29 -0
- package/dist/fields/Checkbox.svelte +33 -0
- package/dist/fields/Checkbox.svelte.d.ts +24 -0
- package/dist/fields/CheckboxGroup.svelte +41 -0
- package/dist/fields/CheckboxGroup.svelte.d.ts +40 -0
- package/dist/fields/Combobox.svelte +222 -0
- package/dist/fields/Combobox.svelte.d.ts +98 -0
- package/dist/fields/DateInput.svelte +31 -0
- package/dist/fields/DateInput.svelte.d.ts +29 -0
- package/dist/fields/FieldErrors.svelte +30 -0
- package/dist/fields/FieldErrors.svelte.d.ts +11 -0
- package/dist/fields/Fieldset.svelte +48 -0
- package/dist/fields/Fieldset.svelte.d.ts +26 -0
- package/dist/fields/FileInput.svelte +67 -0
- package/dist/fields/FileInput.svelte.d.ts +33 -0
- package/dist/fields/FormField.svelte +54 -0
- package/dist/fields/FormField.svelte.d.ts +29 -0
- package/dist/fields/ImageInput.svelte +87 -0
- package/dist/fields/ImageInput.svelte.d.ts +39 -0
- package/dist/fields/PushToggle.svelte +93 -0
- package/dist/fields/PushToggle.svelte.d.ts +55 -0
- package/dist/fields/RadioGroup.svelte +85 -0
- package/dist/fields/RadioGroup.svelte.d.ts +41 -0
- package/dist/fields/SearchInput.svelte +57 -0
- package/dist/fields/SearchInput.svelte.d.ts +33 -0
- package/dist/fields/Select.svelte +36 -0
- package/dist/fields/Select.svelte.d.ts +29 -0
- package/dist/fields/TextInput.svelte +26 -0
- package/dist/fields/TextInput.svelte.d.ts +30 -0
- package/dist/fields/Textarea.svelte +22 -0
- package/dist/fields/Textarea.svelte.d.ts +25 -0
- package/dist/fields/Toggle.svelte +72 -0
- package/dist/fields/Toggle.svelte.d.ts +32 -0
- package/dist/fields/VideoInput.svelte +35 -0
- package/dist/fields/VideoInput.svelte.d.ts +40 -0
- package/dist/fields/field-types.d.ts +51 -0
- package/dist/fields/field-types.js +60 -0
- package/dist/fields/index.d.ts +34 -0
- package/dist/fields/index.js +34 -0
- package/dist/formatting/DateTime.svelte +35 -0
- package/dist/formatting/DateTime.svelte.d.ts +26 -0
- package/dist/formatting/FormatList.svelte +31 -0
- package/dist/formatting/FormatList.svelte.d.ts +46 -0
- package/dist/formatting/Highlight.svelte +47 -0
- package/dist/formatting/Highlight.svelte.d.ts +15 -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/index.d.ts +12 -0
- package/dist/formatting/index.js +14 -0
- package/dist/forms/EntityForm.svelte +177 -0
- package/dist/forms/EntityForm.svelte.d.ts +57 -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 +23 -0
- package/dist/hotkeys/index.js +22 -0
- package/dist/hotkeys/match.d.ts +65 -0
- package/dist/hotkeys/match.js +133 -0
- package/dist/hotkeys/registry.svelte.d.ts +55 -0
- package/dist/hotkeys/registry.svelte.js +110 -0
- package/dist/hotkeys/types.d.ts +72 -0
- package/dist/hotkeys/types.js +18 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.js +36 -0
- package/dist/infobox/Infobox.svelte +79 -0
- package/dist/infobox/Infobox.svelte.d.ts +26 -0
- package/dist/infobox/InfoboxHeader.svelte +27 -0
- package/dist/infobox/InfoboxHeader.svelte.d.ts +11 -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/Breadcrumbs.svelte +52 -0
- package/dist/layout/Breadcrumbs.svelte.d.ts +18 -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/Footer.svelte +32 -0
- package/dist/layout/Footer.svelte.d.ts +12 -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/Tabs.svelte +85 -0
- package/dist/layout/Tabs.svelte.d.ts +42 -0
- package/dist/layout/index.d.ts +29 -0
- package/dist/layout/index.js +29 -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 +37 -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 +71 -0
- package/dist/seo/og-image.js +81 -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 +25 -0
- package/dist/tips/tip-stack.js +37 -0
- package/dist/tips/tip-store.svelte.d.ts +74 -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/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 +43 -0
- package/dist/ui/Button.svelte.d.ts +29 -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/Disclosure.svelte +39 -0
- package/dist/ui/Disclosure.svelte.d.ts +22 -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 +54 -0
- package/dist/ui/Menu.svelte.d.ts +34 -0
- package/dist/ui/MenuItem.svelte +75 -0
- package/dist/ui/MenuItem.svelte.d.ts +21 -0
- package/dist/ui/MenuSeparator.svelte +26 -0
- package/dist/ui/MenuSeparator.svelte.d.ts +8 -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/ThemeToggle.svelte +65 -0
- package/dist/ui/ThemeToggle.svelte.d.ts +24 -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/colour-token.d.ts +41 -0
- package/dist/ui/colour-token.js +49 -0
- package/dist/ui/index.d.ts +44 -0
- package/dist/ui/index.js +44 -0
- package/dist/ui/menu-context.d.ts +22 -0
- package/dist/ui/menu-context.js +26 -0
- package/dist/ui/slug.d.ts +19 -0
- package/dist/ui/slug.js +25 -0
- package/dist/ui/tones.d.ts +68 -0
- package/dist/ui/tones.js +150 -0
- package/package.json +25 -25
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
2
|
+
import { type Size } from '../ui/tones.ts';
|
|
3
|
+
interface Props extends Omit<HTMLAttributes<HTMLElement>, 'children'> {
|
|
4
|
+
/** The offset the current page was rendered with. */
|
|
5
|
+
offset: number;
|
|
6
|
+
/** The page size the current page was rendered with. */
|
|
7
|
+
limit: number;
|
|
8
|
+
/** The unpaged total across every page. */
|
|
9
|
+
total: number;
|
|
10
|
+
/**
|
|
11
|
+
* `window` renders numbered page links with gaps; `prevNext` a bare Previous/Next pair.
|
|
12
|
+
* @defaultValue `'window'`
|
|
13
|
+
*/
|
|
14
|
+
variant?: 'window' | 'prevNext' | undefined;
|
|
15
|
+
/**
|
|
16
|
+
* Build the link for a target offset. Preserving the page's own query
|
|
17
|
+
* parameters is the caller's job — `pageHref` does it for a JSON:API
|
|
18
|
+
* URL — and the result is resolved through the components context.
|
|
19
|
+
*/
|
|
20
|
+
href?: ((offset: number) => string) | undefined;
|
|
21
|
+
/** Page without navigating. Ignored when `href` is given. */
|
|
22
|
+
onPage?: ((offset: number) => void) | undefined;
|
|
23
|
+
/**
|
|
24
|
+
* Pages rendered either side of the current one.
|
|
25
|
+
* @defaultValue `1`
|
|
26
|
+
*/
|
|
27
|
+
siblings?: number | undefined;
|
|
28
|
+
/**
|
|
29
|
+
* The navigation landmark's accessible name.
|
|
30
|
+
* @defaultValue `'Pagination'`
|
|
31
|
+
*/
|
|
32
|
+
label?: string | undefined;
|
|
33
|
+
/**
|
|
34
|
+
* Text of the previous-page control.
|
|
35
|
+
* @defaultValue `'Previous'`
|
|
36
|
+
*/
|
|
37
|
+
previousLabel?: string | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* Text of the next-page control.
|
|
40
|
+
* @defaultValue `'Next'`
|
|
41
|
+
*/
|
|
42
|
+
nextLabel?: string | undefined;
|
|
43
|
+
/**
|
|
44
|
+
* How a numbered control is named — its digit alone is not a name.
|
|
45
|
+
* @defaultValue `"Page <page>"`
|
|
46
|
+
*/
|
|
47
|
+
pageLabel?: ((page: number) => string) | undefined;
|
|
48
|
+
/**
|
|
49
|
+
* daisyUI size step.
|
|
50
|
+
* @defaultValue `'sm'`
|
|
51
|
+
*/
|
|
52
|
+
size?: Size | undefined;
|
|
53
|
+
/** Print the range line ("Showing 41–60 of 151"). */
|
|
54
|
+
showRange?: boolean | undefined;
|
|
55
|
+
/**
|
|
56
|
+
* The range line when `showRange`.
|
|
57
|
+
* @defaultValue `"Showing <start>–<end> of <total>"`
|
|
58
|
+
*/
|
|
59
|
+
rangeLabel?: ((start: number, end: number, total: number) => string) | undefined;
|
|
60
|
+
/** Text between the two arms in `prevNext` mode ("Page 2 of 8"). */
|
|
61
|
+
statusLabel?: ((page: number, pages: number) => string) | undefined;
|
|
62
|
+
/**
|
|
63
|
+
* Locale(s) for `Intl` formatting.
|
|
64
|
+
* @defaultValue the components context's `locale()`
|
|
65
|
+
*/
|
|
66
|
+
locales?: string | readonly string[] | undefined;
|
|
67
|
+
}
|
|
68
|
+
/** Offset-based page navigation: numbered links with gaps or a bare Previous/Next pair, as links (`href`) or callbacks (`onPage`). */
|
|
69
|
+
declare const Pagination: import("svelte").Component<Props, {}, "">;
|
|
70
|
+
type Pagination = ReturnType<typeof Pagination>;
|
|
71
|
+
export default Pagination;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<!-- @component
|
|
2
|
+
The count line and the pager that sit under a paginated index page.
|
|
3
|
+
-->
|
|
4
|
+
<!--
|
|
5
|
+
PaginationFooter — what sits under a paginated index page: the count, and
|
|
6
|
+
the pager.
|
|
7
|
+
|
|
8
|
+
The two always travel together, and rendering them separately at each call
|
|
9
|
+
site meant the same dozen lines in every listing — a dozen lines in which
|
|
10
|
+
the limit, the offset and the total are threaded through twice and can
|
|
11
|
+
disagree. Here they come from one set of props, so they cannot.
|
|
12
|
+
|
|
13
|
+
`ResultCount` and `Pagination` stay exported on their own: a page that shows
|
|
14
|
+
a count without paging, or pages without a count, is a real thing. This is
|
|
15
|
+
the pairing, not a replacement.
|
|
16
|
+
|
|
17
|
+
ARIA contract: whatever its two parts carry — a `<p>` and a labelled `<nav>`.
|
|
18
|
+
-->
|
|
19
|
+
<script lang="ts">import Pagination from "./Pagination.svelte";
|
|
20
|
+
import ResultCount from "./ResultCount.svelte";
|
|
21
|
+
let { shown, offset, limit, total, href, onPage, variant = "window", siblings = 1, size = "sm", label = "Pagination", previousLabel = "Previous", nextLabel = "Next", pageLabel, countLabel, locales, class: className, ...rest } = $props();
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<div {...rest} class={['space-y-4', className]}>
|
|
25
|
+
<ResultCount {shown} {total} label={countLabel} {locales} />
|
|
26
|
+
<Pagination
|
|
27
|
+
{offset}
|
|
28
|
+
{limit}
|
|
29
|
+
{total}
|
|
30
|
+
{variant}
|
|
31
|
+
{href}
|
|
32
|
+
{onPage}
|
|
33
|
+
{siblings}
|
|
34
|
+
{size}
|
|
35
|
+
{label}
|
|
36
|
+
{previousLabel}
|
|
37
|
+
{nextLabel}
|
|
38
|
+
{pageLabel}
|
|
39
|
+
{locales}
|
|
40
|
+
/>
|
|
41
|
+
</div>
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
2
|
+
import type { Size } from '../ui/tones.ts';
|
|
3
|
+
interface Props extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {
|
|
4
|
+
/** Rows on this page — the length of what was rendered. */
|
|
5
|
+
shown: number;
|
|
6
|
+
/** The offset this page was rendered with. */
|
|
7
|
+
offset: number;
|
|
8
|
+
/** The page size this page was rendered with. */
|
|
9
|
+
limit: number;
|
|
10
|
+
/** The unpaged total. */
|
|
11
|
+
total: number;
|
|
12
|
+
/** Build the link for a target offset; the page's own query parameters included. */
|
|
13
|
+
href?: ((offset: number) => string) | undefined;
|
|
14
|
+
/** Page without navigating. Ignored when `href` is given. */
|
|
15
|
+
onPage?: ((offset: number) => void) | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* `window` renders numbered page links with gaps; `prevNext` a bare Previous/Next pair.
|
|
18
|
+
* @defaultValue `'window'`
|
|
19
|
+
*/
|
|
20
|
+
variant?: 'window' | 'prevNext' | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* Pages rendered either side of the current one.
|
|
23
|
+
* @defaultValue `1`
|
|
24
|
+
*/
|
|
25
|
+
siblings?: number | undefined;
|
|
26
|
+
/**
|
|
27
|
+
* daisyUI size step.
|
|
28
|
+
* @defaultValue `'sm'`
|
|
29
|
+
*/
|
|
30
|
+
size?: Size | undefined;
|
|
31
|
+
/**
|
|
32
|
+
* The pager landmark's accessible name.
|
|
33
|
+
* @defaultValue `'Pagination'`
|
|
34
|
+
*/
|
|
35
|
+
label?: string | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* Text of the previous-page control.
|
|
38
|
+
* @defaultValue `'Previous'`
|
|
39
|
+
*/
|
|
40
|
+
previousLabel?: string | undefined;
|
|
41
|
+
/**
|
|
42
|
+
* Text of the next-page control.
|
|
43
|
+
* @defaultValue `'Next'`
|
|
44
|
+
*/
|
|
45
|
+
nextLabel?: string | undefined;
|
|
46
|
+
/** How a numbered control is named; see `Pagination`. */
|
|
47
|
+
pageLabel?: ((page: number) => string) | undefined;
|
|
48
|
+
/** The count line, when "Showing x of y" is not the sentence wanted. */
|
|
49
|
+
countLabel?: ((shown: number, total: number) => string) | undefined;
|
|
50
|
+
/**
|
|
51
|
+
* Locale(s) for `Intl` formatting.
|
|
52
|
+
* @defaultValue the components context's `locale()`
|
|
53
|
+
*/
|
|
54
|
+
locales?: string | readonly string[] | undefined;
|
|
55
|
+
}
|
|
56
|
+
/** The count line and the pager that sit under a paginated index page. */
|
|
57
|
+
declare const PaginationFooter: import("svelte").Component<Props, {}, "">;
|
|
58
|
+
type PaginationFooter = ReturnType<typeof PaginationFooter>;
|
|
59
|
+
export default PaginationFooter;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<!-- @component
|
|
2
|
+
The "Showing 24 of 310" line under a list.
|
|
3
|
+
-->
|
|
4
|
+
<!--
|
|
5
|
+
ResultCount — "Showing 24 of 310" under a list.
|
|
6
|
+
|
|
7
|
+
Every list an API serves is a `LIMIT`ed window, so a page that showed only
|
|
8
|
+
the window would quietly imply it was everything; this says otherwise. It
|
|
9
|
+
renders nothing when `shown` is zero: an empty result is already saying
|
|
10
|
+
"nothing here" through its empty state, and "Showing 0 of 0" beside that is
|
|
11
|
+
noise, not reassurance.
|
|
12
|
+
|
|
13
|
+
ARIA contract: a plain `<p>`. Not a live region — the count is part of the
|
|
14
|
+
page that was just rendered, not an update to it, and announcing it on
|
|
15
|
+
every keystroke of a filter is the thing live regions are misused for.
|
|
16
|
+
-->
|
|
17
|
+
<script lang="ts">import { getComponentsContext } from "../context.svelte.js";
|
|
18
|
+
let { shown, total, label, locales = getComponentsContext().locale(), class: className, ...rest } = $props();
|
|
19
|
+
// Formatter and formatted string in separate `$derived`s: the constructor
|
|
20
|
+
// is the expensive half and only the locale should rebuild it.
|
|
21
|
+
const counts = $derived(new Intl.NumberFormat(locales));
|
|
22
|
+
const text = $derived(label === undefined ? `Showing ${counts.format(shown)} of ${counts.format(total)}` : label(shown, total));
|
|
23
|
+
</script>
|
|
24
|
+
|
|
25
|
+
{#if shown > 0}
|
|
26
|
+
<p {...rest} class={['text-base-content/60 text-sm tabular-nums', className]}>{text}</p>
|
|
27
|
+
{/if}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
2
|
+
interface Props extends Omit<HTMLAttributes<HTMLParagraphElement>, 'children'> {
|
|
3
|
+
/** Rows on this page. */
|
|
4
|
+
shown: number;
|
|
5
|
+
/** Rows the query matched in total, before the window was applied. */
|
|
6
|
+
total: number;
|
|
7
|
+
/** The whole line, when "Showing x of y" is not the sentence wanted. */
|
|
8
|
+
label?: ((shown: number, total: number) => string) | undefined;
|
|
9
|
+
/**
|
|
10
|
+
* Locale(s) for `Intl` formatting.
|
|
11
|
+
* @defaultValue the components context's `locale()`
|
|
12
|
+
*/
|
|
13
|
+
locales?: string | readonly string[] | undefined;
|
|
14
|
+
}
|
|
15
|
+
/** The "Showing 24 of 310" line under a list. */
|
|
16
|
+
declare const ResultCount: import("svelte").Component<Props, {}, "">;
|
|
17
|
+
type ResultCount = ReturnType<typeof ResultCount>;
|
|
18
|
+
export default ResultCount;
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
<!-- @component
|
|
2
|
+
A daisyUI `table` from column definitions and rows, with optional sortable headers and activatable rows.
|
|
3
|
+
-->
|
|
4
|
+
<!--
|
|
5
|
+
Table — columns in, rows in, a daisyUI `table` out.
|
|
6
|
+
|
|
7
|
+
It decides nothing about WHICH rows: a caller hands it the window it wants
|
|
8
|
+
shown, in the order it wants it, and this draws the header, the body, the
|
|
9
|
+
footer and the empty state. Sorting is the same deal — the header offers
|
|
10
|
+
the control and announces the state, and the caller (or `DataGrid`) does
|
|
11
|
+
the reordering. That split is what lets one component serve both a
|
|
12
|
+
client-side grid over 40 rows and a server-paged listing over 40,000, where
|
|
13
|
+
sorting the page in hand would be a lie.
|
|
14
|
+
|
|
15
|
+
ARIA contract: a real `<table>` with `<th scope="col">` headers. `caption`
|
|
16
|
+
is the table's accessible name — an unnamed table is one a screen-reader
|
|
17
|
+
user cannot tell from the next one — and `captionHidden` keeps it for
|
|
18
|
+
assistive technology only when the page's own heading already shows it. A
|
|
19
|
+
sortable column's header is a real `<button>` inside the `<th>` (the
|
|
20
|
+
activation), and the `<th>` carries `aria-sort` (the state); the arrow
|
|
21
|
+
beside it is `aria-hidden`, because the sort must be announced by the state
|
|
22
|
+
and not by a glyph.
|
|
23
|
+
|
|
24
|
+
`onSelect` makes each row activatable with `role="button"`, `tabindex="0"`
|
|
25
|
+
and Enter/Space — a click handler on a bare `<tr>` is invisible to everyone
|
|
26
|
+
not using a mouse. It costs the row its `row` semantics, so prefer a link
|
|
27
|
+
or a button inside a cell where the row's structure matters, and keep this
|
|
28
|
+
for a grid whose whole row is one destination.
|
|
29
|
+
|
|
30
|
+
The empty state is not an optional nicety: a table body with no rows and no
|
|
31
|
+
explanation reads as broken, and only the caller knows whether "nothing"
|
|
32
|
+
means "none yet" or "none matched".
|
|
33
|
+
-->
|
|
34
|
+
<script lang="ts" generics="T">import { columnAriaSort, nextSortState } from "./table-types.js";
|
|
35
|
+
let { rows, columns, rowKey, caption, captionHidden = false, size = "md", zebra = false, pinRows = false, sort = $bindable(undefined), onSort, onSelect, emptyMessage = "Nothing to show.", emptyState, foot, sortLabel = (column) => `Sort by ${column.header}`, containerClass, class: className, ...rest } = $props();
|
|
36
|
+
const tableSize = {
|
|
37
|
+
xs: "table-xs",
|
|
38
|
+
sm: "table-sm",
|
|
39
|
+
md: "table-md",
|
|
40
|
+
lg: "table-lg",
|
|
41
|
+
xl: "table-xl"
|
|
42
|
+
};
|
|
43
|
+
/** Alignment and the column's own classes, shared by its `<th>` and `<td>`. */
|
|
44
|
+
const columnClass = (column) => [column.align === "end" ? "text-end" : "text-start", column.class];
|
|
45
|
+
const toggleSort = (column) => {
|
|
46
|
+
const next = nextSortState(sort, column.key);
|
|
47
|
+
sort = next;
|
|
48
|
+
onSort?.(next);
|
|
49
|
+
};
|
|
50
|
+
/** The arrow beside a sorted header. Decorative — `aria-sort` is the state. */
|
|
51
|
+
const sortIndicator = (key) => {
|
|
52
|
+
if (sort === undefined || sort.key !== key) return "";
|
|
53
|
+
return sort.direction === "asc" ? "▲" : "▼";
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Everything an activatable row needs, as one spread — or nothing at all
|
|
57
|
+
* when it is not activatable. Assembled here rather than as four attribute
|
|
58
|
+
* ternaries in the markup, because those four have to agree with each other
|
|
59
|
+
* (a `role` without a `tabindex` is a lie) and one object is where that
|
|
60
|
+
* agreement is visible.
|
|
61
|
+
*/
|
|
62
|
+
const rowAttributes = (row) => onSelect === undefined ? {} : {
|
|
63
|
+
role: "button",
|
|
64
|
+
tabindex: 0,
|
|
65
|
+
class: "cursor-pointer",
|
|
66
|
+
onclick: () => {
|
|
67
|
+
onSelect(row);
|
|
68
|
+
},
|
|
69
|
+
onkeydown: (event) => {
|
|
70
|
+
if (event.key !== "Enter" && event.key !== " ") return;
|
|
71
|
+
// Space scrolls the page and Enter can submit a wrapping form;
|
|
72
|
+
// an activation that also does one of those is a bug report.
|
|
73
|
+
event.preventDefault();
|
|
74
|
+
onSelect(row);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
</script>
|
|
78
|
+
|
|
79
|
+
<div class={['overflow-x-auto', containerClass]}>
|
|
80
|
+
<table
|
|
81
|
+
{...rest}
|
|
82
|
+
class={[
|
|
83
|
+
'table bg-base-100',
|
|
84
|
+
tableSize[size],
|
|
85
|
+
zebra && 'table-zebra',
|
|
86
|
+
pinRows && 'table-pin-rows',
|
|
87
|
+
className,
|
|
88
|
+
]}
|
|
89
|
+
>
|
|
90
|
+
{#if caption !== undefined}
|
|
91
|
+
<caption class={captionHidden ? 'sr-only' : 'p-3 text-start text-sm font-medium'}>
|
|
92
|
+
{caption}
|
|
93
|
+
</caption>
|
|
94
|
+
{/if}
|
|
95
|
+
<thead>
|
|
96
|
+
<tr>
|
|
97
|
+
{#each columns as column (column.key)}
|
|
98
|
+
<th scope="col" class={columnClass(column)} aria-sort={column.sortable ? columnAriaSort(sort, column.key) : undefined}>
|
|
99
|
+
{#if column.sortable}
|
|
100
|
+
<button
|
|
101
|
+
type="button"
|
|
102
|
+
class="link link-hover inline-flex items-center gap-1"
|
|
103
|
+
onclick={() => {
|
|
104
|
+
toggleSort(column);
|
|
105
|
+
}}
|
|
106
|
+
aria-label={sortLabel(column)}
|
|
107
|
+
>
|
|
108
|
+
{column.header}
|
|
109
|
+
<span aria-hidden="true" class="text-xs">{sortIndicator(column.key)}</span>
|
|
110
|
+
</button>
|
|
111
|
+
{:else}
|
|
112
|
+
{column.header}
|
|
113
|
+
{/if}
|
|
114
|
+
</th>
|
|
115
|
+
{/each}
|
|
116
|
+
</tr>
|
|
117
|
+
</thead>
|
|
118
|
+
<tbody>
|
|
119
|
+
{#if rows.length === 0}
|
|
120
|
+
<tr>
|
|
121
|
+
<!-- Without the colspan the message sits under the first column and
|
|
122
|
+
the table looks like it lost its data rather than never had any. -->
|
|
123
|
+
<td colspan={columns.length} class="text-base-content/60 py-8 text-center">
|
|
124
|
+
{#if emptyState}{@render emptyState()}{:else}{emptyMessage}{/if}
|
|
125
|
+
</td>
|
|
126
|
+
</tr>
|
|
127
|
+
{:else}
|
|
128
|
+
{#each rows as row (rowKey(row))}
|
|
129
|
+
<tr class="hover:bg-base-200" {...rowAttributes(row)}>
|
|
130
|
+
{#each columns as column (column.key)}
|
|
131
|
+
<td class={columnClass(column)}>
|
|
132
|
+
{#if column.cell}{@render column.cell(row)}{:else}{column.value(row)}{/if}
|
|
133
|
+
</td>
|
|
134
|
+
{/each}
|
|
135
|
+
</tr>
|
|
136
|
+
{/each}
|
|
137
|
+
{/if}
|
|
138
|
+
</tbody>
|
|
139
|
+
{#if foot}
|
|
140
|
+
<tfoot>
|
|
141
|
+
<tr>{@render foot()}</tr>
|
|
142
|
+
</tfoot>
|
|
143
|
+
{/if}
|
|
144
|
+
</table>
|
|
145
|
+
</div>
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { HTMLTableAttributes } from 'svelte/elements';
|
|
3
|
+
import type { Size } from '../ui/tones.ts';
|
|
4
|
+
import { type SortState, type TableColumn } from './table-types.ts';
|
|
5
|
+
declare function $$render<T>(): {
|
|
6
|
+
props: Omit<HTMLTableAttributes, "children"> & {
|
|
7
|
+
/** The rows to draw, in the order to draw them. */
|
|
8
|
+
rows: readonly T[];
|
|
9
|
+
/** Column definitions: header, cell renderer, sort key. */
|
|
10
|
+
columns: readonly TableColumn<T>[];
|
|
11
|
+
/** Stable identity per row — the `{#each}` key. */
|
|
12
|
+
rowKey: (row: T) => string;
|
|
13
|
+
/** The table's accessible name, rendered as its `<caption>`. */
|
|
14
|
+
caption?: string | undefined;
|
|
15
|
+
/** Keep the caption for assistive technology only. */
|
|
16
|
+
captionHidden?: boolean | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* daisyUI size step.
|
|
19
|
+
* @defaultValue `'md'`
|
|
20
|
+
*/
|
|
21
|
+
size?: Size | undefined;
|
|
22
|
+
/** Stripe alternate rows. */
|
|
23
|
+
zebra?: boolean | undefined;
|
|
24
|
+
/**
|
|
25
|
+
* Stick the header row while the body scrolls. Needs the scroll container
|
|
26
|
+
* to be the scrolling element, so give it a `max-h-*` through `class`
|
|
27
|
+
* when the page itself should not scroll.
|
|
28
|
+
*/
|
|
29
|
+
pinRows?: boolean | undefined;
|
|
30
|
+
/** Which column is sorted, and which way. Bindable; `undefined` is unsorted. */
|
|
31
|
+
sort?: SortState | undefined;
|
|
32
|
+
/** Called with the next state when a sortable header is activated. */
|
|
33
|
+
onSort?: ((sort: SortState | undefined) => void) | undefined;
|
|
34
|
+
/** Makes every row activatable by pointer and keyboard. */
|
|
35
|
+
onSelect?: ((row: T) => void) | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* The line shown instead of an empty body.
|
|
38
|
+
* @defaultValue `'Nothing to show.'`
|
|
39
|
+
*/
|
|
40
|
+
emptyMessage?: string | undefined;
|
|
41
|
+
/** Richer empty state, in place of `emptyMessage`. */
|
|
42
|
+
emptyState?: Snippet<[]> | undefined;
|
|
43
|
+
/** A `<tfoot>` row — totals, or a summary. Render `<td>`/`<th>` cells. */
|
|
44
|
+
foot?: Snippet<[]> | undefined;
|
|
45
|
+
/**
|
|
46
|
+
* How a sortable column's button is named.
|
|
47
|
+
* @defaultValue `"Sort by <header>"`
|
|
48
|
+
*/
|
|
49
|
+
sortLabel?: ((column: TableColumn<T>) => string) | undefined;
|
|
50
|
+
/** Classes on the scroll container the table sits in. */
|
|
51
|
+
containerClass?: string | undefined;
|
|
52
|
+
};
|
|
53
|
+
exports: {};
|
|
54
|
+
bindings: "sort";
|
|
55
|
+
slots: {};
|
|
56
|
+
events: {};
|
|
57
|
+
};
|
|
58
|
+
declare class __sveltets_Render<T> {
|
|
59
|
+
props(): ReturnType<typeof $$render<T>>['props'];
|
|
60
|
+
events(): ReturnType<typeof $$render<T>>['events'];
|
|
61
|
+
slots(): ReturnType<typeof $$render<T>>['slots'];
|
|
62
|
+
bindings(): "sort";
|
|
63
|
+
exports(): {};
|
|
64
|
+
}
|
|
65
|
+
interface $$IsomorphicComponent {
|
|
66
|
+
new <T>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T>['props']>, ReturnType<__sveltets_Render<T>['events']>, ReturnType<__sveltets_Render<T>['slots']>> & {
|
|
67
|
+
$$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
|
|
68
|
+
} & ReturnType<__sveltets_Render<T>['exports']>;
|
|
69
|
+
<T>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
|
|
70
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
71
|
+
}
|
|
72
|
+
/** A daisyUI `table` from column definitions and rows, with optional sortable headers and activatable rows. */
|
|
73
|
+
declare const Table: $$IsomorphicComponent;
|
|
74
|
+
type Table<T> = InstanceType<typeof Table<T>>;
|
|
75
|
+
export default Table;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<!-- @component
|
|
2
|
+
One collapsible node of a hierarchy: an always-visible summary row and a subtree that folds away under it.
|
|
3
|
+
-->
|
|
4
|
+
<!--
|
|
5
|
+
TreeList — one collapsible node of a hierarchy: a summary row that is always
|
|
6
|
+
visible, and a subtree that folds away under it.
|
|
7
|
+
|
|
8
|
+
Built on `<details>` / `<summary>` rather than a `{#if}` and a button, and
|
|
9
|
+
deliberately NOT on a bits-ui primitive: the element already gives the
|
|
10
|
+
disclosure semantics, the keyboard behaviour, and — on a modern browser —
|
|
11
|
+
find-in-page inside the collapsed content, which no JavaScript
|
|
12
|
+
implementation matches. A hand-rolled equivalent is three ARIA attributes
|
|
13
|
+
that have to stay in step with each other.
|
|
14
|
+
|
|
15
|
+
Open by default: a taxonomy the reader has to unfold node by node hides the
|
|
16
|
+
shape they came to see. Pass `open={false}` where the subtree is an aside.
|
|
17
|
+
|
|
18
|
+
ARIA contract: the platform's disclosure semantics, plus a `<ul>`/`<li>`
|
|
19
|
+
structure so the nesting is announced as nesting. No `aria-expanded` is
|
|
20
|
+
written by hand — the browser maps `open`, and a second copy can only ever
|
|
21
|
+
disagree with it. This is a disclosure tree, not an ARIA `tree` widget:
|
|
22
|
+
`role="tree"` would commit the caller to roving tabindex and typeahead over
|
|
23
|
+
arbitrary nested content, which is a much larger promise than folding a
|
|
24
|
+
taxonomy.
|
|
25
|
+
-->
|
|
26
|
+
<script lang="ts">let { open = $bindable(true), title, children, class: className, ...rest } = $props();
|
|
27
|
+
export {};
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<ul {...rest} class={['ml-1 pl-0', className]}>
|
|
31
|
+
<li class="relative block pl-2">
|
|
32
|
+
<details bind:open>
|
|
33
|
+
<summary
|
|
34
|
+
class="focus-visible:outline-primary block cursor-pointer marker:hidden focus:outline-hidden focus-visible:outline-1 focus-visible:outline-dotted"
|
|
35
|
+
>
|
|
36
|
+
{#if typeof title === 'string'}{title}{:else}{@render title()}{/if}
|
|
37
|
+
</summary>
|
|
38
|
+
{@render children?.()}
|
|
39
|
+
</details>
|
|
40
|
+
</li>
|
|
41
|
+
</ul>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
+
interface Props extends Omit<HTMLAttributes<HTMLUListElement>, 'title' | 'children'> {
|
|
4
|
+
/**
|
|
5
|
+
* Whether the subtree starts unfolded. Bindable.
|
|
6
|
+
* @defaultValue `true`
|
|
7
|
+
*/
|
|
8
|
+
open?: boolean | undefined;
|
|
9
|
+
/** The always-visible summary row — its own text, or richer markup. */
|
|
10
|
+
title: string | Snippet<[]>;
|
|
11
|
+
/** The subtree — typically nested `TreeListItem`s. */
|
|
12
|
+
children?: Snippet<[]> | undefined;
|
|
13
|
+
}
|
|
14
|
+
/** One collapsible node of a hierarchy: an always-visible summary row and a subtree that folds away under it. */
|
|
15
|
+
declare const TreeList: import("svelte").Component<Props, {}, "open">;
|
|
16
|
+
type TreeList = ReturnType<typeof TreeList>;
|
|
17
|
+
export default TreeList;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<!-- @component
|
|
2
|
+
One leaf under a `TreeList`, drawn with the connector rule that makes the nesting readable.
|
|
3
|
+
-->
|
|
4
|
+
<!--
|
|
5
|
+
TreeListItem — one leaf under a `TreeList`, drawn with the connector rule
|
|
6
|
+
that makes the nesting readable.
|
|
7
|
+
|
|
8
|
+
The rule is a border on the item rather than a line drawn between items, so
|
|
9
|
+
a subtree that grows or folds redraws itself; `last:border-transparent`
|
|
10
|
+
stops it running past the final child, which is the detail that separates a
|
|
11
|
+
tree from a stack of indented rows.
|
|
12
|
+
|
|
13
|
+
ARIA contract: a plain `<li>`. It is a list item inside its parent's list,
|
|
14
|
+
and the nesting is the structure — nothing is added.
|
|
15
|
+
-->
|
|
16
|
+
<script lang="ts">let { children, class: className, ...rest } = $props();
|
|
17
|
+
export {};
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<li
|
|
21
|
+
{...rest}
|
|
22
|
+
class={[
|
|
23
|
+
"border-base-300 border-l-2 before:absolute before:top-2 before:left-1 before:block before:content-['']",
|
|
24
|
+
'last:border-transparent',
|
|
25
|
+
className,
|
|
26
|
+
]}
|
|
27
|
+
>
|
|
28
|
+
{@render children?.()}
|
|
29
|
+
</li>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
+
interface Props extends Omit<HTMLAttributes<HTMLLIElement>, 'children'> {
|
|
4
|
+
/** The leaf's content, beside the connector rule. */
|
|
5
|
+
children?: Snippet<[]> | undefined;
|
|
6
|
+
}
|
|
7
|
+
/** One leaf under a `TreeList`, drawn with the connector rule that makes the nesting readable. */
|
|
8
|
+
declare const TreeListItem: import("svelte").Component<Props, {}, "">;
|
|
9
|
+
type TreeListItem = ReturnType<typeof TreeListItem>;
|
|
10
|
+
export default TreeListItem;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How a {@link DescriptionRow} learns which {@link DescriptionList} it is
|
|
3
|
+
* inside.
|
|
4
|
+
*
|
|
5
|
+
* The four list variants render their rows differently — a `grid` row is a
|
|
6
|
+
* wrapper holding a stacked `<dt>`/`<dd>` pair, while a `card` row's `<dt>`
|
|
7
|
+
* and `<dd>` are siblings in the list's own two-column grid, because a
|
|
8
|
+
* wrapper would break the alignment the grid exists for. A call site writes
|
|
9
|
+
* the same `<DescriptionRow>` either way.
|
|
10
|
+
*
|
|
11
|
+
* The variant travels down as context rather than as a prop so a caller
|
|
12
|
+
* cannot get a list and its rows out of step, and so the list stays the
|
|
13
|
+
* single place the choice is made. A row mounted with no list above it gets
|
|
14
|
+
* the defaults, which is what makes one usable inside an app's own `<dl>`.
|
|
15
|
+
*
|
|
16
|
+
* @module
|
|
17
|
+
*/
|
|
18
|
+
/** The presentation a `DescriptionList` asks its rows for. */
|
|
19
|
+
export interface DescriptionListStyle {
|
|
20
|
+
readonly variant: 'grid' | 'card' | 'divided' | 'inline';
|
|
21
|
+
/** Render values in a fixed-width face that breaks anywhere. */
|
|
22
|
+
readonly mono: boolean;
|
|
23
|
+
/** Render a row whose value is empty, using `emptyLabel`. */
|
|
24
|
+
readonly showEmpty: boolean;
|
|
25
|
+
/** What an empty value reads as when `showEmpty`. */
|
|
26
|
+
readonly emptyLabel: string;
|
|
27
|
+
}
|
|
28
|
+
/** The presentation a `DescriptionRow` uses outside any `DescriptionList`: the `grid` variant, proportional text, empty rows hidden. */
|
|
29
|
+
export declare const defaultDescriptionListStyle: DescriptionListStyle;
|
|
30
|
+
/** Declare the style every descendant `DescriptionRow` renders in. */
|
|
31
|
+
export declare function setDescriptionListStyle(style: () => DescriptionListStyle): void;
|
|
32
|
+
/** The enclosing list's style, or the defaults when there is no enclosing list. */
|
|
33
|
+
export declare function getDescriptionListStyle(): () => DescriptionListStyle;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How a {@link DescriptionRow} learns which {@link DescriptionList} it is
|
|
3
|
+
* inside.
|
|
4
|
+
*
|
|
5
|
+
* The four list variants render their rows differently — a `grid` row is a
|
|
6
|
+
* wrapper holding a stacked `<dt>`/`<dd>` pair, while a `card` row's `<dt>`
|
|
7
|
+
* and `<dd>` are siblings in the list's own two-column grid, because a
|
|
8
|
+
* wrapper would break the alignment the grid exists for. A call site writes
|
|
9
|
+
* the same `<DescriptionRow>` either way.
|
|
10
|
+
*
|
|
11
|
+
* The variant travels down as context rather than as a prop so a caller
|
|
12
|
+
* cannot get a list and its rows out of step, and so the list stays the
|
|
13
|
+
* single place the choice is made. A row mounted with no list above it gets
|
|
14
|
+
* the defaults, which is what makes one usable inside an app's own `<dl>`.
|
|
15
|
+
*
|
|
16
|
+
* @module
|
|
17
|
+
*/
|
|
18
|
+
import { getContext, setContext } from 'svelte';
|
|
19
|
+
/** The presentation a `DescriptionRow` uses outside any `DescriptionList`: the `grid` variant, proportional text, empty rows hidden. */
|
|
20
|
+
export const defaultDescriptionListStyle = {
|
|
21
|
+
variant: 'grid',
|
|
22
|
+
mono: false,
|
|
23
|
+
showEmpty: false,
|
|
24
|
+
emptyLabel: 'unrecorded',
|
|
25
|
+
};
|
|
26
|
+
const STYLE_KEY = Symbol('@thomasfosterau/components:description-list');
|
|
27
|
+
/** Declare the style every descendant `DescriptionRow` renders in. */
|
|
28
|
+
export function setDescriptionListStyle(style) {
|
|
29
|
+
setContext(STYLE_KEY, style);
|
|
30
|
+
}
|
|
31
|
+
/** The enclosing list's style, or the defaults when there is no enclosing list. */
|
|
32
|
+
export function getDescriptionListStyle() {
|
|
33
|
+
return (getContext(STYLE_KEY) ??
|
|
34
|
+
(() => defaultDescriptionListStyle));
|
|
35
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The segment shape `DiffText` renders.
|
|
3
|
+
*
|
|
4
|
+
* A `.ts` module rather than a `<script module>` block so the diff algorithm
|
|
5
|
+
* that produces these — which is the app's, not this package's — can import
|
|
6
|
+
* the type without reaching through a component.
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
/** One run of a word- or character-level diff. */
|
|
11
|
+
export interface DiffSegment {
|
|
12
|
+
readonly kind: 'equal' | 'insert' | 'delete';
|
|
13
|
+
readonly text: string;
|
|
14
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The segment shape `DiffText` renders.
|
|
3
|
+
*
|
|
4
|
+
* A `.ts` module rather than a `<script module>` block so the diff algorithm
|
|
5
|
+
* that produces these — which is the app's, not this package's — can import
|
|
6
|
+
* the type without reaching through a component.
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
export {};
|