@thomasfosterau/components 0.1.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/README.md +241 -56
- package/dist/canvas/VectorCanvas.svelte +89 -8
- package/dist/canvas/VectorCanvas.svelte.d.ts +19 -1
- package/dist/canvas/types.d.ts +1 -1
- package/dist/charts/types.d.ts +1 -1
- package/dist/citations/list-format.js +3 -1
- package/dist/data/ChatBubble.svelte +48 -0
- package/dist/data/ChatBubble.svelte.d.ts +33 -0
- package/dist/data/DescriptionList.svelte +9 -3
- package/dist/data/DescriptionList.svelte.d.ts +1 -1
- package/dist/data/DescriptionRow.svelte +6 -5
- package/dist/data/MessageThread.svelte +29 -0
- package/dist/data/MessageThread.svelte.d.ts +17 -0
- package/dist/data/Pagination.svelte +5 -5
- package/dist/data/Pagination.svelte.d.ts +8 -0
- package/dist/data/PaginationFooter.svelte +2 -1
- package/dist/data/PaginationFooter.svelte.d.ts +2 -0
- package/dist/data/Table.svelte +9 -3
- package/dist/data/description-context.d.ts +12 -6
- package/dist/data/description-context.js +6 -5
- package/dist/data/index.d.ts +2 -0
- package/dist/data/index.js +2 -0
- package/dist/data/table-types.d.ts +7 -0
- package/dist/feedback/Dialog.svelte +19 -49
- package/dist/feedback/Dialog.svelte.d.ts +0 -1
- 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/SegmentBar.svelte.d.ts +1 -0
- package/dist/feedback/StatTile.svelte.d.ts +1 -0
- package/dist/feedback/Steps.svelte +72 -0
- package/dist/feedback/Steps.svelte.d.ts +61 -0
- package/dist/feedback/Timeline.svelte.d.ts +3 -0
- package/dist/feedback/index.d.ts +3 -0
- package/dist/feedback/index.js +2 -0
- package/dist/feedback/sizes.d.ts +14 -0
- package/dist/feedback/sizes.js +28 -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 +1 -1
- package/dist/fields/Checkbox.svelte.d.ts +6 -0
- package/dist/fields/Combobox.svelte +61 -54
- package/dist/fields/Combobox.svelte.d.ts +38 -3
- package/dist/fields/DateField.svelte +37 -0
- package/dist/fields/DateField.svelte.d.ts +20 -0
- package/dist/fields/DateInput.svelte +1 -1
- package/dist/fields/DateInput.svelte.d.ts +6 -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/Fieldset.svelte +7 -2
- package/dist/fields/Fieldset.svelte.d.ts +3 -2
- package/dist/fields/FileInput.svelte +3 -2
- package/dist/fields/FileInput.svelte.d.ts +6 -0
- package/dist/fields/FormField.svelte +27 -3
- package/dist/fields/ImageInput.svelte.d.ts +6 -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/RadioGroup.svelte +3 -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 +2 -1
- package/dist/fields/SegmentGroup.svelte +91 -0
- package/dist/fields/SegmentGroup.svelte.d.ts +20 -0
- package/dist/fields/Select.svelte +1 -1
- package/dist/fields/Select.svelte.d.ts +6 -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 +1 -1
- package/dist/fields/TextInput.svelte.d.ts +6 -0
- package/dist/fields/Textarea.svelte +1 -1
- package/dist/fields/Textarea.svelte.d.ts +6 -0
- package/dist/fields/TimeField.svelte +30 -0
- package/dist/fields/TimeField.svelte.d.ts +19 -0
- package/dist/fields/Toggle.svelte +1 -1
- package/dist/fields/Toggle.svelte.d.ts +6 -0
- package/dist/fields/VideoInput.svelte.d.ts +6 -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 +29 -0
- package/dist/fields/field-types.js +32 -0
- package/dist/fields/file-validation.d.ts +30 -0
- package/dist/fields/file-validation.js +51 -0
- package/dist/fields/index.d.ts +9 -0
- package/dist/fields/index.js +8 -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/Duration.svelte +18 -0
- package/dist/formatting/Duration.svelte.d.ts +20 -0
- package/dist/formatting/Highlight.svelte +4 -0
- package/dist/formatting/Highlight.svelte.d.ts +4 -0
- package/dist/formatting/duration.d.ts +44 -0
- package/dist/formatting/duration.js +125 -0
- package/dist/formatting/index.d.ts +3 -0
- package/dist/formatting/index.js +3 -0
- package/dist/forms/EntityForm.svelte +53 -45
- package/dist/forms/EntityForm.svelte.d.ts +12 -3
- package/dist/hotkeys/index.d.ts +5 -0
- package/dist/hotkeys/index.js +5 -0
- package/dist/hotkeys/match.js +12 -10
- package/dist/hotkeys/types.d.ts +4 -2
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/infobox/Infobox.svelte +2 -2
- package/dist/infobox/Infobox.svelte.d.ts +7 -0
- package/dist/infobox/InfoboxHeader.svelte +15 -7
- package/dist/infobox/InfoboxHeader.svelte.d.ts +7 -0
- package/dist/infobox/types.d.ts +5 -5
- package/dist/layout/AppShell.svelte +50 -0
- package/dist/layout/AppShell.svelte.d.ts +28 -0
- package/dist/layout/Cluster.svelte +28 -0
- package/dist/layout/Cluster.svelte.d.ts +27 -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/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/Navbar.svelte +2 -2
- package/dist/layout/Sidebar.svelte +1 -1
- package/dist/layout/Spacer.svelte +12 -0
- package/dist/layout/Spacer.svelte.d.ts +6 -0
- package/dist/layout/VStack.svelte +12 -0
- package/dist/layout/VStack.svelte.d.ts +29 -0
- package/dist/layout/index.d.ts +9 -0
- package/dist/layout/index.js +9 -0
- package/dist/layout/space.d.ts +44 -0
- package/dist/layout/space.js +76 -0
- package/dist/search/types.d.ts +3 -0
- package/dist/seo/og-image.d.ts +4 -3
- package/dist/seo/og-image.js +4 -3
- package/dist/tips/tip-stack.d.ts +1 -0
- package/dist/tips/tip-store.svelte.d.ts +2 -1
- 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/Button.svelte +3 -2
- package/dist/ui/ButtonGroup.svelte +24 -0
- package/dist/ui/ButtonGroup.svelte.d.ts +17 -0
- package/dist/ui/ContextMenu.svelte +75 -0
- package/dist/ui/ContextMenu.svelte.d.ts +25 -0
- package/dist/ui/Disclosure.svelte +7 -0
- package/dist/ui/Disclosure.svelte.d.ts +2 -2
- 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/Menu.svelte +17 -47
- package/dist/ui/Menu.svelte.d.ts +3 -24
- package/dist/ui/MenuCheckboxItem.svelte +33 -0
- package/dist/ui/MenuCheckboxItem.svelte.d.ts +20 -0
- package/dist/ui/MenuItem.svelte +29 -31
- package/dist/ui/MenuItem.svelte.d.ts +2 -2
- 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 +12 -11
- package/dist/ui/MenuSub.svelte +24 -0
- package/dist/ui/MenuSub.svelte.d.ts +15 -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/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/accordion-context.d.ts +26 -0
- package/dist/ui/accordion-context.js +23 -0
- package/dist/ui/context-menu.d.ts +13 -0
- package/dist/ui/context-menu.js +13 -0
- package/dist/ui/index.d.ts +19 -0
- package/dist/ui/index.js +18 -0
- package/dist/ui/menu-context.d.ts +13 -15
- package/dist/ui/menu-context.js +14 -18
- 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/toggle-classes.d.ts +39 -0
- package/dist/ui/toggle-classes.js +36 -0
- package/dist/ui/tones.d.ts +35 -0
- package/dist/ui/tones.js +90 -0
- package/package.json +34 -18
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
<!-- @component
|
|
2
|
+
An application menu behind a trigger — a bits-ui dropdown of `MenuItem`s styled as a daisyUI `menu`.
|
|
3
|
+
-->
|
|
4
|
+
<!--
|
|
5
|
+
DropdownMenu — an application menu: bits-ui's `DropdownMenu`, which owns
|
|
6
|
+
`aria-haspopup`/`aria-expanded` on the trigger, arrow-key roving focus,
|
|
7
|
+
typeahead, Escape to close and focus return. The daisyUI `menu` styling is
|
|
8
|
+
applied to a `<ul>` INSIDE the content; that list and its items' `<li>`
|
|
9
|
+
wrappers carry `role="none"` so the presentation layer does not come
|
|
10
|
+
between `role="menu"` and its `role="menuitem"` children in the
|
|
11
|
+
accessibility tree.
|
|
12
|
+
|
|
13
|
+
It is a separate component from `Menu` (site navigation) so that bits-ui's
|
|
14
|
+
dropdown runtime is reached only by an app that actually renders a
|
|
15
|
+
dropdown: `Menu`, `MenuItem`, `MenuSeparator` and `Sidebar` import nothing
|
|
16
|
+
from bits-ui (#129). The children are the same `MenuItem` /
|
|
17
|
+
`MenuSeparator` a `Menu` takes; this component lends them its bits-ui item
|
|
18
|
+
and separator parts through context (`menu-parts/menu-parts.ts`), and
|
|
19
|
+
the same for `MenuCheckboxItem`, `MenuRadioGroup`, `MenuRadioItem` and
|
|
20
|
+
`MenuSub`.
|
|
21
|
+
-->
|
|
22
|
+
<script lang="ts">import { DropdownMenu } from "bits-ui";
|
|
23
|
+
import { menuParts } from "./menu-parts/parts.js";
|
|
24
|
+
import { setMenuParts } from "./menu-parts/menu-parts.js";
|
|
25
|
+
let { label, open = $bindable(false), side = "bottom", align = "end", class: className, trigger, children } = $props();
|
|
26
|
+
setMenuParts(menuParts("dropdown"));
|
|
27
|
+
</script>
|
|
28
|
+
|
|
29
|
+
<DropdownMenu.Root bind:open>
|
|
30
|
+
{#if trigger}
|
|
31
|
+
<DropdownMenu.Trigger>
|
|
32
|
+
{#snippet child({ props })}
|
|
33
|
+
{@render trigger({ props })}
|
|
34
|
+
{/snippet}
|
|
35
|
+
</DropdownMenu.Trigger>
|
|
36
|
+
{/if}
|
|
37
|
+
<DropdownMenu.Portal>
|
|
38
|
+
<DropdownMenu.Content {side} {align} sideOffset={8} aria-label={label} class="z-50">
|
|
39
|
+
<ul role="none" class={['menu bg-base-100 rounded-box w-56 p-2 shadow-md', className]}>
|
|
40
|
+
{@render children()}
|
|
41
|
+
</ul>
|
|
42
|
+
</DropdownMenu.Content>
|
|
43
|
+
</DropdownMenu.Portal>
|
|
44
|
+
</DropdownMenu.Root>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { DropdownMenu } from 'bits-ui';
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
interface Props {
|
|
4
|
+
/** Accessible name of the open menu. */
|
|
5
|
+
label: string;
|
|
6
|
+
/** Whether the menu is open. Bindable. */
|
|
7
|
+
open?: boolean | undefined;
|
|
8
|
+
/**
|
|
9
|
+
* Which side of the trigger the menu opens on.
|
|
10
|
+
* @defaultValue `'bottom'`
|
|
11
|
+
*/
|
|
12
|
+
side?: 'top' | 'right' | 'bottom' | 'left' | undefined;
|
|
13
|
+
/**
|
|
14
|
+
* Alignment against the trigger.
|
|
15
|
+
* @defaultValue `'end'`
|
|
16
|
+
*/
|
|
17
|
+
align?: 'start' | 'center' | 'end' | undefined;
|
|
18
|
+
/** Extra classes on the `<ul class="menu">`. */
|
|
19
|
+
class?: string | undefined;
|
|
20
|
+
/** The trigger — the caller's own element, spreading `props`. */
|
|
21
|
+
trigger?: Snippet<[{
|
|
22
|
+
props: Record<string, unknown>;
|
|
23
|
+
}]> | undefined;
|
|
24
|
+
/** The `MenuItem`s. */
|
|
25
|
+
children: Snippet<[]>;
|
|
26
|
+
}
|
|
27
|
+
/** An application menu behind a trigger — a bits-ui dropdown of `MenuItem`s styled as a daisyUI `menu`. */
|
|
28
|
+
declare const DropdownMenu: import("svelte").Component<Props, {}, "open">;
|
|
29
|
+
type DropdownMenu = ReturnType<typeof DropdownMenu>;
|
|
30
|
+
export default DropdownMenu;
|
package/dist/ui/Menu.svelte
CHANGED
|
@@ -1,54 +1,24 @@
|
|
|
1
1
|
<!-- @component
|
|
2
|
-
A
|
|
2
|
+
A labelled navigation list: a `<nav>` landmark around a daisyUI `menu` of `MenuItem` links.
|
|
3
3
|
-->
|
|
4
4
|
<!--
|
|
5
|
-
Menu —
|
|
6
|
-
|
|
5
|
+
Menu — site navigation: a `<nav>` landmark around a `<ul class="menu">` of
|
|
6
|
+
links, where the current page marks itself with `aria-current="page"`.
|
|
7
|
+
Links, list, landmark — no widget, no roving focus, no Escape. Everything
|
|
8
|
+
stays reachable with nothing but Tab, which is the correct behaviour for
|
|
9
|
+
navigation and the wrong behaviour for a menu.
|
|
7
10
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
correct behaviour for navigation and the wrong behaviour for a menu.
|
|
13
|
-
|
|
14
|
-
`mode="dropdown"` is an application menu: bits-ui's `DropdownMenu`, which
|
|
15
|
-
owns `aria-haspopup`/`aria-expanded` on the trigger, arrow-key roving
|
|
16
|
-
focus, typeahead, Escape to close and focus return. The daisyUI `menu`
|
|
17
|
-
styling is applied to a `<ul>` INSIDE the content; that list and its items'
|
|
18
|
-
`<li>` wrappers carry `role="none"` so the presentation layer does not come
|
|
19
|
-
between `role="menu"` and its `role="menuitem"` children in the
|
|
20
|
-
accessibility tree.
|
|
21
|
-
|
|
22
|
-
The mode reaches `MenuItem` through context rather than a prop, so the two
|
|
23
|
-
can never be set inconsistently. See `menu-context.ts`.
|
|
11
|
+
An application menu behind a trigger is `DropdownMenu`, which takes the
|
|
12
|
+
same `MenuItem`s. The two are separate components so this one imports
|
|
13
|
+
nothing from bits-ui: a page that only navigates (`Sidebar` included) never
|
|
14
|
+
loads the dropdown runtime (#129).
|
|
24
15
|
-->
|
|
25
|
-
<script lang="ts">
|
|
26
|
-
|
|
27
|
-
let { mode = "nav", label, open = $bindable(false), side = "bottom", align = "end", class: className, trigger, children } = $props();
|
|
28
|
-
setMenuMode(() => mode);
|
|
16
|
+
<script lang="ts">let { label, class: className, children } = $props();
|
|
17
|
+
export {};
|
|
29
18
|
</script>
|
|
30
19
|
|
|
31
|
-
{
|
|
32
|
-
<
|
|
33
|
-
{
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
{@render trigger({ props })}
|
|
37
|
-
{/snippet}
|
|
38
|
-
</DropdownMenu.Trigger>
|
|
39
|
-
{/if}
|
|
40
|
-
<DropdownMenu.Portal>
|
|
41
|
-
<DropdownMenu.Content {side} {align} sideOffset={8} aria-label={label} class="z-50">
|
|
42
|
-
<ul role="none" class={['menu bg-base-100 rounded-box w-56 p-2 shadow-md', className]}>
|
|
43
|
-
{@render children()}
|
|
44
|
-
</ul>
|
|
45
|
-
</DropdownMenu.Content>
|
|
46
|
-
</DropdownMenu.Portal>
|
|
47
|
-
</DropdownMenu.Root>
|
|
48
|
-
{:else}
|
|
49
|
-
<nav aria-label={label}>
|
|
50
|
-
<ul class={['menu w-full gap-1 p-0', className]}>
|
|
51
|
-
{@render children()}
|
|
52
|
-
</ul>
|
|
53
|
-
</nav>
|
|
54
|
-
{/if}
|
|
20
|
+
<nav aria-label={label}>
|
|
21
|
+
<ul class={['menu w-full gap-1 p-0', className]}>
|
|
22
|
+
{@render children()}
|
|
23
|
+
</ul>
|
|
24
|
+
</nav>
|
package/dist/ui/Menu.svelte.d.ts
CHANGED
|
@@ -1,34 +1,13 @@
|
|
|
1
1
|
import type { Snippet } from 'svelte';
|
|
2
2
|
interface Props {
|
|
3
|
-
/**
|
|
4
|
-
* `nav` renders a navigation list; `dropdown` a menu behind `trigger`.
|
|
5
|
-
* @defaultValue `'nav'`
|
|
6
|
-
*/
|
|
7
|
-
mode?: 'dropdown' | 'nav' | undefined;
|
|
8
|
-
/** Accessible name of the navigation landmark / the open menu. */
|
|
3
|
+
/** Accessible name of the navigation landmark. */
|
|
9
4
|
label: string;
|
|
10
|
-
/** Whether the dropdown is open. Bindable; ignored in `nav` mode. */
|
|
11
|
-
open?: boolean | undefined;
|
|
12
|
-
/**
|
|
13
|
-
* Which side of the trigger the dropdown opens on.
|
|
14
|
-
* @defaultValue `'bottom'`
|
|
15
|
-
*/
|
|
16
|
-
side?: 'top' | 'right' | 'bottom' | 'left' | undefined;
|
|
17
|
-
/**
|
|
18
|
-
* Alignment against the trigger.
|
|
19
|
-
* @defaultValue `'end'`
|
|
20
|
-
*/
|
|
21
|
-
align?: 'start' | 'center' | 'end' | undefined;
|
|
22
5
|
/** Extra classes on the `<ul class="menu">`. */
|
|
23
6
|
class?: string | undefined;
|
|
24
|
-
/** The dropdown's trigger — the caller's own element, spreading `props`. */
|
|
25
|
-
trigger?: Snippet<[{
|
|
26
|
-
props: Record<string, unknown>;
|
|
27
|
-
}]> | undefined;
|
|
28
7
|
/** The `MenuItem`s. */
|
|
29
8
|
children: Snippet<[]>;
|
|
30
9
|
}
|
|
31
|
-
/** A
|
|
32
|
-
declare const Menu: import("svelte").Component<Props, {}, "
|
|
10
|
+
/** A labelled navigation list: a `<nav>` landmark around a daisyUI `menu` of `MenuItem` links. */
|
|
11
|
+
declare const Menu: import("svelte").Component<Props, {}, "">;
|
|
33
12
|
type Menu = ReturnType<typeof Menu>;
|
|
34
13
|
export default Menu;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<!-- @component
|
|
2
|
+
An on/off entry of a `DropdownMenu` or `ContextMenu` (`role="menuitemcheckbox"`).
|
|
3
|
+
-->
|
|
4
|
+
<!--
|
|
5
|
+
MenuCheckboxItem — a setting toggled from a menu ("Show archived"). It
|
|
6
|
+
renders the checkbox item part its enclosing `DropdownMenu` or
|
|
7
|
+
`ContextMenu` lends it through context (`menu-parts/CheckboxItemPart.svelte`),
|
|
8
|
+
so this file imports nothing from bits-ui and costs a navigation-only page
|
|
9
|
+
nothing (#129).
|
|
10
|
+
|
|
11
|
+
ARIA contract: `role="menuitemcheckbox"` with `aria-checked` from bits-ui;
|
|
12
|
+
the check mark is `aria-hidden`. A checkbox item belongs to an application
|
|
13
|
+
menu, not a navigation list, so outside a `DropdownMenu` / `ContextMenu` it
|
|
14
|
+
renders nothing.
|
|
15
|
+
-->
|
|
16
|
+
<script lang="ts">import { getMenuParts } from "./menu-parts/menu-parts.js";
|
|
17
|
+
let { checked = $bindable(false), onCheckedChange, disabled = false, class: className, children } = $props();
|
|
18
|
+
const parts = getMenuParts();
|
|
19
|
+
const change = (next) => {
|
|
20
|
+
checked = next;
|
|
21
|
+
onCheckedChange?.(next);
|
|
22
|
+
};
|
|
23
|
+
</script>
|
|
24
|
+
|
|
25
|
+
{#if parts}
|
|
26
|
+
<parts.checkboxItem
|
|
27
|
+
{checked}
|
|
28
|
+
onCheckedChange={change}
|
|
29
|
+
{disabled}
|
|
30
|
+
class={className}
|
|
31
|
+
label={children}
|
|
32
|
+
/>
|
|
33
|
+
{/if}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
interface Props {
|
|
3
|
+
/**
|
|
4
|
+
* Whether the item is checked. Bindable.
|
|
5
|
+
* @defaultValue `false`
|
|
6
|
+
*/
|
|
7
|
+
checked?: boolean | undefined;
|
|
8
|
+
/** Called with the next state when the reader toggles it. */
|
|
9
|
+
onCheckedChange?: ((checked: boolean) => void) | undefined;
|
|
10
|
+
/** Shown but not activatable. */
|
|
11
|
+
disabled?: boolean | undefined;
|
|
12
|
+
/** Extra classes on the `<li>`. */
|
|
13
|
+
class?: string | undefined;
|
|
14
|
+
/** The item's label. */
|
|
15
|
+
children: Snippet<[]>;
|
|
16
|
+
}
|
|
17
|
+
/** An on/off entry of a `DropdownMenu` or `ContextMenu` (`role="menuitemcheckbox"`). */
|
|
18
|
+
declare const MenuCheckboxItem: import("svelte").Component<Props, {}, "checked">;
|
|
19
|
+
type MenuCheckboxItem = ReturnType<typeof MenuCheckboxItem>;
|
|
20
|
+
export default MenuCheckboxItem;
|
package/dist/ui/MenuItem.svelte
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<!-- @component
|
|
2
|
-
One entry of a `Menu
|
|
2
|
+
One entry of a `Menu` (a navigation link), or of a `DropdownMenu` or `ContextMenu` (a bits-ui menu item).
|
|
3
3
|
-->
|
|
4
4
|
<!--
|
|
5
|
-
MenuItem — one entry of a `Menu`,
|
|
6
|
-
enclosing
|
|
5
|
+
MenuItem — one entry of a `Menu`, `DropdownMenu` or `ContextMenu`; which
|
|
6
|
+
one is decided by the enclosing menu, never by a prop.
|
|
7
7
|
|
|
8
8
|
In `nav` mode it is a plain `<li><a>`: the current page takes daisyUI's
|
|
9
9
|
`menu-active` AND `aria-current="page"`, because the highlight is a
|
|
@@ -11,25 +11,28 @@ One entry of a `Menu`, in whichever mode the enclosing `Menu` declared.
|
|
|
11
11
|
context's `isCurrent(href)`, which is what an app without a router-aware
|
|
12
12
|
context uses.
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
Inside a `DropdownMenu` or `ContextMenu` it renders the item part that menu lends it
|
|
15
|
+
(`menu-parts/ItemPart.svelte`, through context), which goes through
|
|
16
|
+
bits-ui's `DropdownMenu.Item` `child` snippet, so the element is still the
|
|
17
|
+
caller's own `<a>` or `<button>` — carrying bits-ui's `role="menuitem"`, its
|
|
18
|
+
focus management and its selection handling — rather than a `<div>`
|
|
19
|
+
pretending to be one. This file imports nothing from bits-ui, so a
|
|
20
|
+
navigation-only page never loads the dropdown runtime (#129). An item with
|
|
21
|
+
an `href` is a link and must stay a link (middle-click, "open in new tab");
|
|
22
|
+
an item without one is a button.
|
|
20
23
|
|
|
21
|
-
ARIA contract: the `<li>` wrapper is `role="none"`
|
|
22
|
-
does not sit between `role="menu"` and `role="menuitem"
|
|
23
|
-
bits-ui's
|
|
24
|
-
`aria-disabled` + no `href
|
|
24
|
+
ARIA contract: inside a `DropdownMenu` the `<li>` wrapper is `role="none"`
|
|
25
|
+
so it does not sit between `role="menu"` and `role="menuitem"`, and
|
|
26
|
+
`disabled` is bits-ui's (skipped by arrow keys, not activatable). In a
|
|
27
|
+
navigation list `disabled` is `aria-disabled` + no `href`, where there is
|
|
28
|
+
no widget to skip.
|
|
25
29
|
The `icon` snippet is decorative — the label carries the meaning.
|
|
26
30
|
-->
|
|
27
|
-
<script lang="ts">import {
|
|
28
|
-
import {
|
|
29
|
-
import { getMenuMode } from "./menu-context.js";
|
|
31
|
+
<script lang="ts">import { getComponentsContext } from "../context.svelte.js";
|
|
32
|
+
import { getMenuParts } from "./menu-parts/menu-parts.js";
|
|
30
33
|
let { href, onSelect, current, disabled = false, icon, class: className, children } = $props();
|
|
31
34
|
const context = getComponentsContext();
|
|
32
|
-
const
|
|
35
|
+
const parts = getMenuParts();
|
|
33
36
|
const resolved = $derived(href === undefined ? undefined : context.href(href));
|
|
34
37
|
// bits-ui's `onSelect` is not optional-friendly under
|
|
35
38
|
// `exactOptionalPropertyTypes`; a stable wrapper is simpler than a spread.
|
|
@@ -42,20 +45,15 @@ const isCurrent = $derived(current ?? (resolved === undefined ? false : context.
|
|
|
42
45
|
{@render children()}
|
|
43
46
|
{/snippet}
|
|
44
47
|
|
|
45
|
-
{#if
|
|
46
|
-
<
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
</a>
|
|
55
|
-
{/if}
|
|
56
|
-
{/snippet}
|
|
57
|
-
</DropdownMenu.Item>
|
|
58
|
-
</li>
|
|
48
|
+
{#if parts}
|
|
49
|
+
<parts.item
|
|
50
|
+
href={resolved}
|
|
51
|
+
current={isCurrent}
|
|
52
|
+
{disabled}
|
|
53
|
+
onSelect={select}
|
|
54
|
+
class={className}
|
|
55
|
+
{label}
|
|
56
|
+
/>
|
|
59
57
|
{:else}
|
|
60
58
|
<li class={className}>
|
|
61
59
|
{#if resolved === undefined}
|
|
@@ -12,10 +12,10 @@ interface Props {
|
|
|
12
12
|
icon?: Snippet<[]> | undefined;
|
|
13
13
|
/** Extra classes on the `<li>`. */
|
|
14
14
|
class?: string | undefined;
|
|
15
|
-
/** The item's
|
|
15
|
+
/** The item's label. */
|
|
16
16
|
children: Snippet<[]>;
|
|
17
17
|
}
|
|
18
|
-
/** One entry of a `Menu
|
|
18
|
+
/** One entry of a `Menu` (a navigation link), or of a `DropdownMenu` or `ContextMenu` (a bits-ui menu item). */
|
|
19
19
|
declare const MenuItem: import("svelte").Component<Props, {}, "">;
|
|
20
20
|
type MenuItem = ReturnType<typeof MenuItem>;
|
|
21
21
|
export default MenuItem;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<!-- @component
|
|
2
|
+
A set of mutually exclusive `MenuRadioItem`s in a `DropdownMenu` or `ContextMenu`.
|
|
3
|
+
-->
|
|
4
|
+
<!--
|
|
5
|
+
MenuRadioGroup — one choice from a few, made in a menu ("Sort by: name,
|
|
6
|
+
date, size"). It renders the radio group part its enclosing `DropdownMenu`
|
|
7
|
+
or `ContextMenu` lends it through context (`menu-parts/RadioGroupPart.svelte`),
|
|
8
|
+
so this file imports nothing from bits-ui (#129).
|
|
9
|
+
|
|
10
|
+
ARIA contract: a `role="group"` named by its visible `label` heading, around
|
|
11
|
+
`role="menuitemradio"` items, exactly one `aria-checked`. Outside a
|
|
12
|
+
`DropdownMenu` / `ContextMenu` it renders nothing.
|
|
13
|
+
-->
|
|
14
|
+
<script lang="ts">import { getMenuParts } from "./menu-parts/menu-parts.js";
|
|
15
|
+
let { value = $bindable(""), onValueChange, label, class: className, children } = $props();
|
|
16
|
+
const parts = getMenuParts();
|
|
17
|
+
const change = (next) => {
|
|
18
|
+
value = next;
|
|
19
|
+
onValueChange?.(next);
|
|
20
|
+
};
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
{#if parts}
|
|
24
|
+
<parts.radioGroup {value} onValueChange={change} {label} class={className} {children} />
|
|
25
|
+
{/if}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
interface Props {
|
|
3
|
+
/**
|
|
4
|
+
* The chosen item's value; empty string when none is chosen. Bindable.
|
|
5
|
+
* @defaultValue `''`
|
|
6
|
+
*/
|
|
7
|
+
value?: string | undefined;
|
|
8
|
+
/** Called with the chosen value. */
|
|
9
|
+
onValueChange?: ((value: string) => void) | undefined;
|
|
10
|
+
/** Visible group heading; also its accessible name. */
|
|
11
|
+
label?: string | undefined;
|
|
12
|
+
/** Extra classes on the `<li>`. */
|
|
13
|
+
class?: string | undefined;
|
|
14
|
+
/** The `MenuRadioItem`s. */
|
|
15
|
+
children: Snippet<[]>;
|
|
16
|
+
}
|
|
17
|
+
/** A set of mutually exclusive `MenuRadioItem`s in a `DropdownMenu` or `ContextMenu`. */
|
|
18
|
+
declare const MenuRadioGroup: import("svelte").Component<Props, {}, "value">;
|
|
19
|
+
type MenuRadioGroup = ReturnType<typeof MenuRadioGroup>;
|
|
20
|
+
export default MenuRadioGroup;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<!-- @component
|
|
2
|
+
One option of a `MenuRadioGroup` (`role="menuitemradio"`).
|
|
3
|
+
-->
|
|
4
|
+
<!--
|
|
5
|
+
MenuRadioItem — one option of a `MenuRadioGroup`. It renders the radio
|
|
6
|
+
item part its enclosing `DropdownMenu` or `ContextMenu` lends it through
|
|
7
|
+
context (`menu-parts/RadioItemPart.svelte`), so this file imports nothing
|
|
8
|
+
from bits-ui (#129).
|
|
9
|
+
|
|
10
|
+
ARIA contract: `role="menuitemradio"` with `aria-checked`; the dot is
|
|
11
|
+
`aria-hidden`. Outside a `DropdownMenu` / `ContextMenu` it renders nothing.
|
|
12
|
+
-->
|
|
13
|
+
<script lang="ts">import { getMenuParts } from "./menu-parts/menu-parts.js";
|
|
14
|
+
let { value, disabled = false, class: className, children } = $props();
|
|
15
|
+
const parts = getMenuParts();
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
{#if parts}
|
|
19
|
+
<parts.radioItem {value} {disabled} class={className} label={children} />
|
|
20
|
+
{/if}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
interface Props {
|
|
3
|
+
/** The value this item chooses in its `MenuRadioGroup`. */
|
|
4
|
+
value: string;
|
|
5
|
+
/** Shown but not activatable. */
|
|
6
|
+
disabled?: boolean | undefined;
|
|
7
|
+
/** Extra classes on the `<li>`. */
|
|
8
|
+
class?: string | undefined;
|
|
9
|
+
/** The item's label. */
|
|
10
|
+
children: Snippet<[]>;
|
|
11
|
+
}
|
|
12
|
+
/** One option of a `MenuRadioGroup` (`role="menuitemradio"`). */
|
|
13
|
+
declare const MenuRadioItem: import("svelte").Component<Props, {}, "">;
|
|
14
|
+
type MenuRadioItem = ReturnType<typeof MenuRadioItem>;
|
|
15
|
+
export default MenuRadioItem;
|
|
@@ -6,21 +6,22 @@ A rule between groups of `MenuItem`s.
|
|
|
6
6
|
|
|
7
7
|
ARIA contract: a real `role="separator"`, which is what tells a screen
|
|
8
8
|
reader the grouping exists at all; a bare styled `<li>` is a line sighted
|
|
9
|
-
readers can see and nobody else can.
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
presentational list item stays out
|
|
9
|
+
readers can see and nobody else can. Inside a `DropdownMenu` or `ContextMenu` it renders the
|
|
10
|
+
separator part that menu lends it through context: bits-ui's own separator
|
|
11
|
+
(which also marks it non-focusable for the menu's arrow-key navigation),
|
|
12
|
+
wrapped in a `role="none"` `<li>` so the presentational list item stays out
|
|
13
|
+
of the accessibility tree. This file imports nothing from bits-ui (#129).
|
|
14
|
+
|
|
15
|
+
Outside a menu, use `Divider`: it is the free-standing rule, and this one
|
|
16
|
+
must stay an `<li>` inside the menu's list.
|
|
13
17
|
-->
|
|
14
|
-
<script lang="ts">import {
|
|
15
|
-
import { getMenuMode } from "./menu-context.js";
|
|
18
|
+
<script lang="ts">import { getMenuParts } from "./menu-parts/menu-parts.js";
|
|
16
19
|
let { class: className } = $props();
|
|
17
|
-
const
|
|
20
|
+
const parts = getMenuParts();
|
|
18
21
|
</script>
|
|
19
22
|
|
|
20
|
-
{#if
|
|
21
|
-
<
|
|
22
|
-
<DropdownMenu.Separator class={['divider my-1 h-px', className]} />
|
|
23
|
-
</li>
|
|
23
|
+
{#if parts}
|
|
24
|
+
<parts.separator class={className} />
|
|
24
25
|
{:else}
|
|
25
26
|
<li role="separator" class={['divider my-1 h-px', className]}></li>
|
|
26
27
|
{/if}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<!-- @component
|
|
2
|
+
A submenu of a `DropdownMenu` or `ContextMenu`: an item that opens a further menu.
|
|
3
|
+
-->
|
|
4
|
+
<!--
|
|
5
|
+
MenuSub — an item that opens a further menu ("Move to ▸"). It renders the
|
|
6
|
+
submenu part its enclosing `DropdownMenu` or `ContextMenu` lends it through
|
|
7
|
+
context (`menu-parts/SubPart.svelte`), so this file imports nothing from
|
|
8
|
+
bits-ui (#129). The children are the same `MenuItem`s, separators and
|
|
9
|
+
checkbox / radio items the parent menu takes.
|
|
10
|
+
|
|
11
|
+
ARIA contract: the opener is a `role="menuitem"` with
|
|
12
|
+
`aria-haspopup="menu"` and `aria-expanded`; → opens the submenu and focuses
|
|
13
|
+
its first item, ← closes it and returns focus to the opener. Outside a
|
|
14
|
+
`DropdownMenu` / `ContextMenu` it renders nothing: a navigation list has no
|
|
15
|
+
submenus to open.
|
|
16
|
+
-->
|
|
17
|
+
<script lang="ts">import { getMenuParts } from "./menu-parts/menu-parts.js";
|
|
18
|
+
let { label, disabled = false, class: className, children } = $props();
|
|
19
|
+
const parts = getMenuParts();
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
{#if parts}
|
|
23
|
+
<parts.sub {label} {disabled} class={className} {children} />
|
|
24
|
+
{/if}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
interface Props {
|
|
3
|
+
/** Text of the item that opens the submenu. */
|
|
4
|
+
label: string;
|
|
5
|
+
/** Shown but not activatable. */
|
|
6
|
+
disabled?: boolean | undefined;
|
|
7
|
+
/** Extra classes on the `<li>`. */
|
|
8
|
+
class?: string | undefined;
|
|
9
|
+
/** The submenu's items. */
|
|
10
|
+
children: Snippet<[]>;
|
|
11
|
+
}
|
|
12
|
+
/** A submenu of a `DropdownMenu` or `ContextMenu`: an item that opens a further menu. */
|
|
13
|
+
declare const MenuSub: import("svelte").Component<Props, {}, "">;
|
|
14
|
+
type MenuSub = ReturnType<typeof MenuSub>;
|
|
15
|
+
export default MenuSub;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<!-- @component
|
|
2
|
+
An indeterminate loading indicator in daisyUI's `loading` shapes, named for assistive technology unless it is decorative.
|
|
3
|
+
-->
|
|
4
|
+
<!--
|
|
5
|
+
Spinner — "something is happening, and there is no shape to preview": a
|
|
6
|
+
panel waiting on a fetch, a lazy section, an inline "Checking…". When the
|
|
7
|
+
content's shape is known, `Skeleton` is the better placeholder.
|
|
8
|
+
|
|
9
|
+
ARIA contract, mirroring `Skeleton`'s on purpose: the wrapper is
|
|
10
|
+
`role="status"` (a polite live region, so its appearance is announced)
|
|
11
|
+
named by `aria-label={label}` — `status` does not take its name from its
|
|
12
|
+
content — and the animated shape is `aria-hidden`. With `showLabel` the
|
|
13
|
+
visible text is `aria-hidden` too, so the label is announced once.
|
|
14
|
+
|
|
15
|
+
`decorative` is for a spinner whose meaning something else already
|
|
16
|
+
carries — `Button`'s `aria-busy`, a live region around it — and renders the
|
|
17
|
+
shape alone, `aria-hidden`, with no role. Never nest a non-decorative
|
|
18
|
+
spinner inside another live region: two regions announce twice.
|
|
19
|
+
|
|
20
|
+
Motion: daisyUI's `loading` already slows its animation under
|
|
21
|
+
`prefers-reduced-motion: reduce` rather than stopping it — a frozen spinner
|
|
22
|
+
reads as "hung" (WCAG 2.3.3) — so nothing is added here.
|
|
23
|
+
-->
|
|
24
|
+
<script lang="ts">import { loadingSize, loadingVariant, textTone } from "./tones.js";
|
|
25
|
+
let { variant = "spinner", size = "md", tone, label = "Loading", showLabel = false, decorative = false, class: className, ...rest } = $props();
|
|
26
|
+
const shape = $derived([
|
|
27
|
+
"loading",
|
|
28
|
+
loadingVariant[variant],
|
|
29
|
+
loadingSize[size],
|
|
30
|
+
tone !== undefined && textTone[tone]
|
|
31
|
+
]);
|
|
32
|
+
</script>
|
|
33
|
+
|
|
34
|
+
{#if decorative}
|
|
35
|
+
<span {...rest} aria-hidden="true" class={[shape, className]}></span>
|
|
36
|
+
{:else}
|
|
37
|
+
<span {...rest} role="status" aria-label={label} class={['inline-flex items-center gap-2', className]}>
|
|
38
|
+
<span aria-hidden="true" class={shape}></span>
|
|
39
|
+
{#if showLabel}<span aria-hidden="true">{label}</span>{/if}
|
|
40
|
+
</span>
|
|
41
|
+
{/if}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
2
|
+
import { type Size, type SpinnerVariant, type Tone } from './tones.ts';
|
|
3
|
+
interface Props extends HTMLAttributes<HTMLSpanElement> {
|
|
4
|
+
/**
|
|
5
|
+
* The daisyUI `loading` shape.
|
|
6
|
+
* @defaultValue `'spinner'`
|
|
7
|
+
*/
|
|
8
|
+
variant?: SpinnerVariant | undefined;
|
|
9
|
+
/**
|
|
10
|
+
* daisyUI size step.
|
|
11
|
+
* @defaultValue `'md'`
|
|
12
|
+
*/
|
|
13
|
+
size?: Size | undefined;
|
|
14
|
+
/** Colour, through `textTone`; inherits `currentColor` when omitted. */
|
|
15
|
+
tone?: Tone | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* What assistive technology announces.
|
|
18
|
+
* @defaultValue `'Loading'`
|
|
19
|
+
*/
|
|
20
|
+
label?: string | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* Print `label` beside the spinner.
|
|
23
|
+
* @defaultValue `false`
|
|
24
|
+
*/
|
|
25
|
+
showLabel?: boolean | undefined;
|
|
26
|
+
/**
|
|
27
|
+
* Something else already says it is loading: render the shape only, `aria-hidden`, with no role.
|
|
28
|
+
* @defaultValue `false`
|
|
29
|
+
*/
|
|
30
|
+
decorative?: boolean | undefined;
|
|
31
|
+
}
|
|
32
|
+
/** An indeterminate loading indicator in daisyUI's `loading` shapes, named for assistive technology unless it is decorative. */
|
|
33
|
+
declare const Spinner: import("svelte").Component<Props, {}, "">;
|
|
34
|
+
type Spinner = ReturnType<typeof Spinner>;
|
|
35
|
+
export default Spinner;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<!-- @component
|
|
2
|
+
Overlapping cards or images on daisyUI `stack`: only the top item is exposed, the rest are visual depth.
|
|
3
|
+
-->
|
|
4
|
+
<!--
|
|
5
|
+
Stack — a pile with a peek of what is behind: a "3 photos" thumbnail, a
|
|
6
|
+
collapsed pile of notifications. The first item is on top.
|
|
7
|
+
|
|
8
|
+
The rule this component exists for: daisyUI's `stack` only paints the
|
|
9
|
+
items behind; every child stays in the DOM, so a screen reader would read
|
|
10
|
+
all three cards and Tab would land on links hidden behind the top one.
|
|
11
|
+
So every item after the first is `inert` (not focusable, not clickable)
|
|
12
|
+
and `aria-hidden` (not read). The depth is then reported in words: the top
|
|
13
|
+
item ends with a visually hidden `countLabel(count)` ("3 items") whenever
|
|
14
|
+
there is more than one, so it is not visual-only.
|
|
15
|
+
|
|
16
|
+
The items are data, not children: `stack.css` positions them with
|
|
17
|
+
`.stack > *:nth-child(n)`, so each must be a direct child of the root and
|
|
18
|
+
no wrapper (not even `display: contents`) can group the ones behind.
|
|
19
|
+
-->
|
|
20
|
+
<script lang="ts" generics="T">import { stackDirection } from "./tones.js";
|
|
21
|
+
let { items, item, direction = "bottom", count, countLabel = (n) => `${n} items`, class: className, ...rest } = $props();
|
|
22
|
+
const total = $derived(count ?? items.length);
|
|
23
|
+
</script>
|
|
24
|
+
|
|
25
|
+
<div {...rest} class={['stack', stackDirection[direction], className]}>
|
|
26
|
+
{#each items as entry, index (index)}
|
|
27
|
+
{#if index === 0}
|
|
28
|
+
<div>
|
|
29
|
+
{@render item(entry, true)}
|
|
30
|
+
{#if total > 1}<span class="sr-only">{countLabel(total)}</span>{/if}
|
|
31
|
+
</div>
|
|
32
|
+
{:else}
|
|
33
|
+
<div inert aria-hidden="true">{@render item(entry, false)}</div>
|
|
34
|
+
{/if}
|
|
35
|
+
{/each}
|
|
36
|
+
</div>
|