@loidolt/theme-svelte 0.2.0 → 0.4.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 +21 -0
- package/dist/components/Accordion.svelte +100 -0
- package/dist/components/Accordion.svelte.d.ts +50 -0
- package/dist/components/Alert.svelte +6 -3
- package/dist/components/Alert.svelte.d.ts +3 -2
- package/dist/components/AlertDialog.svelte +130 -0
- package/dist/components/AlertDialog.svelte.d.ts +35 -0
- package/dist/components/AppShell.svelte +2 -1
- package/dist/components/AppShell.svelte.d.ts +1 -0
- package/dist/components/Badge.svelte +9 -2
- package/dist/components/Badge.svelte.d.ts +2 -1
- package/dist/components/Brand.svelte +29 -15
- package/dist/components/Brand.svelte.d.ts +8 -4
- package/dist/components/Breadcrumbs.svelte +53 -0
- package/dist/components/Breadcrumbs.svelte.d.ts +18 -0
- package/dist/components/Button.svelte +43 -21
- package/dist/components/Button.svelte.d.ts +9 -4
- package/dist/components/Card.svelte +23 -5
- package/dist/components/Card.svelte.d.ts +11 -4
- package/dist/components/CodeBlock.svelte +55 -0
- package/dist/components/CodeBlock.svelte.d.ts +14 -0
- package/dist/components/CommentList.svelte +67 -0
- package/dist/components/CommentList.svelte.d.ts +53 -0
- package/dist/components/Dialog.svelte +25 -3
- package/dist/components/Dialog.svelte.d.ts +4 -1
- package/dist/components/Drawer.svelte +105 -0
- package/dist/components/Drawer.svelte.d.ts +31 -0
- package/dist/components/DropdownMenu.svelte +2 -2
- package/dist/components/DropdownMenu.svelte.d.ts +1 -1
- package/dist/components/EmptyState.svelte +40 -0
- package/dist/components/EmptyState.svelte.d.ts +19 -0
- package/dist/components/Fieldset.svelte +60 -0
- package/dist/components/Fieldset.svelte.d.ts +19 -0
- package/dist/components/FileInput.svelte +47 -0
- package/dist/components/FileInput.svelte.d.ts +15 -0
- package/dist/components/Filmstrip.svelte +72 -0
- package/dist/components/Filmstrip.svelte.d.ts +50 -0
- package/dist/components/FloatingBar.svelte +43 -0
- package/dist/components/FloatingBar.svelte.d.ts +16 -0
- package/dist/components/IconButton.svelte +1 -1
- package/dist/components/Input.svelte.d.ts +1 -1
- package/dist/components/ListRow.svelte +50 -0
- package/dist/components/ListRow.svelte.d.ts +18 -0
- package/dist/components/Marker.svelte +38 -0
- package/dist/components/Marker.svelte.d.ts +14 -0
- package/dist/components/NavMenu.svelte +6 -1
- package/dist/components/NavMenu.svelte.d.ts +2 -1
- package/dist/components/NumberField.svelte +12 -1
- package/dist/components/NumberField.svelte.d.ts +1 -1
- package/dist/components/Pagination.svelte +86 -0
- package/dist/components/Pagination.svelte.d.ts +22 -0
- package/dist/components/Popover.svelte +24 -3
- package/dist/components/Popover.svelte.d.ts +4 -1
- package/dist/components/RadioGroup.svelte.d.ts +2 -2
- package/dist/components/RecordStepper.svelte +58 -0
- package/dist/components/RecordStepper.svelte.d.ts +18 -0
- package/dist/components/SegmentedNav.svelte +53 -0
- package/dist/components/SegmentedNav.svelte.d.ts +22 -0
- package/dist/components/Select.svelte.d.ts +2 -2
- package/dist/components/Stat.svelte +41 -0
- package/dist/components/Stat.svelte.d.ts +17 -0
- package/dist/components/StatusDot.svelte +27 -0
- package/dist/components/StatusDot.svelte.d.ts +12 -0
- package/dist/components/SwatchGroup.svelte +69 -0
- package/dist/components/SwatchGroup.svelte.d.ts +44 -0
- package/dist/components/Switch.svelte +19 -0
- package/dist/components/Table.svelte +30 -3
- package/dist/components/Table.svelte.d.ts +13 -0
- package/dist/components/TableHeader.svelte +72 -0
- package/dist/components/TableHeader.svelte.d.ts +24 -0
- package/dist/components/Tabs.svelte +23 -5
- package/dist/components/Tabs.svelte.d.ts +4 -3
- package/dist/components/Textarea.svelte.d.ts +1 -1
- package/dist/components/ThemeToggle.svelte +133 -0
- package/dist/components/ThemeToggle.svelte.d.ts +20 -0
- package/dist/components/Thumbnail.svelte +51 -0
- package/dist/components/Thumbnail.svelte.d.ts +19 -0
- package/dist/components/ToggleGroup.svelte +107 -0
- package/dist/components/ToggleGroup.svelte.d.ts +46 -0
- package/dist/components/TooltipProvider.svelte +1 -0
- package/dist/components/Workspace.svelte +27 -6
- package/dist/components/Workspace.svelte.d.ts +12 -0
- package/dist/index.d.ts +29 -2
- package/dist/index.js +26 -1
- package/dist/media.svelte.d.ts +48 -0
- package/dist/media.svelte.js +69 -0
- package/dist/theme.svelte.d.ts +86 -0
- package/dist/theme.svelte.js +166 -0
- package/dist/toaster.svelte.d.ts +2 -0
- package/dist/toaster.svelte.js +51 -9
- package/dist/types.d.ts +21 -0
- package/package.json +10 -8
package/README.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# @loidolt/theme-svelte
|
|
2
|
+
|
|
3
|
+
Accessible Svelte 5 components and state helpers for the Loidolt design system.
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
npm install @loidolt/theme-svelte
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Import the global styles once:
|
|
10
|
+
|
|
11
|
+
```css
|
|
12
|
+
@import '@loidolt/theme-svelte/styles.css';
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Then import components from the package barrel:
|
|
16
|
+
|
|
17
|
+
```svelte
|
|
18
|
+
<script>
|
|
19
|
+
import { Button, Field, Input } from '@loidolt/theme-svelte';
|
|
20
|
+
</script>
|
|
21
|
+
```
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
<script lang="ts" generics="T extends string = string">
|
|
2
|
+
import { Accordion as AccordionPrimitive } from 'bits-ui';
|
|
3
|
+
import type { Snippet } from 'svelte';
|
|
4
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
5
|
+
import type { Disclosure, HeadingLevel } from '../types.js';
|
|
6
|
+
import { cx } from '../utils.js';
|
|
7
|
+
|
|
8
|
+
interface Props extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {
|
|
9
|
+
items: Disclosure<T>[];
|
|
10
|
+
/** Narrowed from the DOM attribute: the Bits root this spreads onto rejects `null`. */
|
|
11
|
+
id?: string;
|
|
12
|
+
/** Lets more than one panel stay open. `value` is then an array. */
|
|
13
|
+
multiple?: boolean;
|
|
14
|
+
/** Open panel, or panels when `multiple`. Bindable. */
|
|
15
|
+
value?: T | T[];
|
|
16
|
+
/**
|
|
17
|
+
* Heading level of every trigger's wrapper. Panels sit at one level below whatever heading
|
|
18
|
+
* introduces the accordion, so keep this in step with the surrounding outline.
|
|
19
|
+
*/
|
|
20
|
+
headingLevel?: HeadingLevel;
|
|
21
|
+
disabled?: boolean;
|
|
22
|
+
/** Panel body, rendered for each item with the item's own value. */
|
|
23
|
+
children: Snippet<[{ value: T }]>;
|
|
24
|
+
class?: string;
|
|
25
|
+
itemClass?: string;
|
|
26
|
+
contentClass?: string;
|
|
27
|
+
onValueChange?: (value: T | T[]) => void;
|
|
28
|
+
ref?: HTMLDivElement | null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
let {
|
|
32
|
+
items,
|
|
33
|
+
multiple = false,
|
|
34
|
+
value = $bindable(),
|
|
35
|
+
headingLevel = 3,
|
|
36
|
+
disabled = false,
|
|
37
|
+
children,
|
|
38
|
+
class: className,
|
|
39
|
+
itemClass,
|
|
40
|
+
contentClass,
|
|
41
|
+
onValueChange,
|
|
42
|
+
ref = $bindable(null),
|
|
43
|
+
...rest
|
|
44
|
+
}: Props = $props();
|
|
45
|
+
|
|
46
|
+
// Bits discriminates single/multiple at the type level with a different `value` shape for
|
|
47
|
+
// each. The panels are identical either way, so the markup lives in one snippet and only the
|
|
48
|
+
// Root differs.
|
|
49
|
+
const change = (next: string | string[]) => {
|
|
50
|
+
value = next as T | T[];
|
|
51
|
+
onValueChange?.(next as T | T[]);
|
|
52
|
+
};
|
|
53
|
+
</script>
|
|
54
|
+
|
|
55
|
+
{#snippet panels()}
|
|
56
|
+
{#each items as item (item.value)}
|
|
57
|
+
<AccordionPrimitive.Item
|
|
58
|
+
value={item.value}
|
|
59
|
+
disabled={item.disabled}
|
|
60
|
+
class={cx('ldt-accordion__item', itemClass)}
|
|
61
|
+
>
|
|
62
|
+
<AccordionPrimitive.Header level={headingLevel} class="ldt-accordion__heading">
|
|
63
|
+
<AccordionPrimitive.Trigger class="ldt-accordion__trigger">
|
|
64
|
+
<span class="ldt-accordion__label">{item.title}</span>
|
|
65
|
+
<!-- Decorative: the trigger's `aria-expanded` already carries open state. -->
|
|
66
|
+
<span class="ldt-accordion__indicator" aria-hidden="true"></span>
|
|
67
|
+
</AccordionPrimitive.Trigger>
|
|
68
|
+
</AccordionPrimitive.Header>
|
|
69
|
+
<AccordionPrimitive.Content class={cx('ldt-accordion__content', contentClass)}>
|
|
70
|
+
<div class="ldt-accordion__body">{@render children({ value: item.value })}</div>
|
|
71
|
+
</AccordionPrimitive.Content>
|
|
72
|
+
</AccordionPrimitive.Item>
|
|
73
|
+
{/each}
|
|
74
|
+
{/snippet}
|
|
75
|
+
|
|
76
|
+
{#if multiple}
|
|
77
|
+
<AccordionPrimitive.Root
|
|
78
|
+
bind:ref
|
|
79
|
+
type="multiple"
|
|
80
|
+
value={(value ?? []) as string[]}
|
|
81
|
+
onValueChange={change}
|
|
82
|
+
{disabled}
|
|
83
|
+
class={cx('ldt-accordion', className)}
|
|
84
|
+
{...rest}
|
|
85
|
+
>
|
|
86
|
+
{@render panels()}
|
|
87
|
+
</AccordionPrimitive.Root>
|
|
88
|
+
{:else}
|
|
89
|
+
<AccordionPrimitive.Root
|
|
90
|
+
bind:ref
|
|
91
|
+
type="single"
|
|
92
|
+
value={(value ?? '') as string}
|
|
93
|
+
onValueChange={change}
|
|
94
|
+
{disabled}
|
|
95
|
+
class={cx('ldt-accordion', className)}
|
|
96
|
+
{...rest}
|
|
97
|
+
>
|
|
98
|
+
{@render panels()}
|
|
99
|
+
</AccordionPrimitive.Root>
|
|
100
|
+
{/if}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
+
import type { Disclosure, HeadingLevel } from '../types.js';
|
|
4
|
+
declare function $$render<T extends string = string>(): {
|
|
5
|
+
props: Omit<HTMLAttributes<HTMLDivElement>, "children"> & {
|
|
6
|
+
items: Disclosure<T>[];
|
|
7
|
+
/** Narrowed from the DOM attribute: the Bits root this spreads onto rejects `null`. */
|
|
8
|
+
id?: string;
|
|
9
|
+
/** Lets more than one panel stay open. `value` is then an array. */
|
|
10
|
+
multiple?: boolean;
|
|
11
|
+
/** Open panel, or panels when `multiple`. Bindable. */
|
|
12
|
+
value?: T | T[];
|
|
13
|
+
/**
|
|
14
|
+
* Heading level of every trigger's wrapper. Panels sit at one level below whatever heading
|
|
15
|
+
* introduces the accordion, so keep this in step with the surrounding outline.
|
|
16
|
+
*/
|
|
17
|
+
headingLevel?: HeadingLevel;
|
|
18
|
+
disabled?: boolean;
|
|
19
|
+
/** Panel body, rendered for each item with the item's own value. */
|
|
20
|
+
children: Snippet<[{
|
|
21
|
+
value: T;
|
|
22
|
+
}]>;
|
|
23
|
+
class?: string;
|
|
24
|
+
itemClass?: string;
|
|
25
|
+
contentClass?: string;
|
|
26
|
+
onValueChange?: (value: T | T[]) => void;
|
|
27
|
+
ref?: HTMLDivElement | null;
|
|
28
|
+
};
|
|
29
|
+
exports: {};
|
|
30
|
+
bindings: "value" | "ref";
|
|
31
|
+
slots: {};
|
|
32
|
+
events: {};
|
|
33
|
+
};
|
|
34
|
+
declare class __sveltets_Render<T extends string = string> {
|
|
35
|
+
props(): ReturnType<typeof $$render<T>>['props'];
|
|
36
|
+
events(): ReturnType<typeof $$render<T>>['events'];
|
|
37
|
+
slots(): ReturnType<typeof $$render<T>>['slots'];
|
|
38
|
+
bindings(): "value" | "ref";
|
|
39
|
+
exports(): {};
|
|
40
|
+
}
|
|
41
|
+
interface $$IsomorphicComponent {
|
|
42
|
+
new <T extends string = string>(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']>> & {
|
|
43
|
+
$$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
|
|
44
|
+
} & ReturnType<__sveltets_Render<T>['exports']>;
|
|
45
|
+
<T extends string = string>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
|
|
46
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
47
|
+
}
|
|
48
|
+
declare const Accordion: $$IsomorphicComponent;
|
|
49
|
+
type Accordion<T extends string = string> = InstanceType<typeof Accordion<T>>;
|
|
50
|
+
export default Accordion;
|
|
@@ -4,9 +4,10 @@
|
|
|
4
4
|
import type { HeadingLevel, StatusVariant } from '../types.js';
|
|
5
5
|
import { cx } from '../utils.js';
|
|
6
6
|
|
|
7
|
-
interface Props extends HTMLAttributes<HTMLDivElement> {
|
|
7
|
+
interface Props extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {
|
|
8
8
|
variant?: StatusVariant;
|
|
9
|
-
|
|
9
|
+
/** Optional heading. Accepts a snippet for rich content; omit it for a body-only alert. */
|
|
10
|
+
title?: string | Snippet;
|
|
10
11
|
/** Heading element used for the title, so the alert fits the page outline. */
|
|
11
12
|
headingLevel?: HeadingLevel;
|
|
12
13
|
class?: string;
|
|
@@ -31,6 +32,8 @@
|
|
|
31
32
|
role={variant === 'error' ? 'alert' : 'status'}
|
|
32
33
|
{...rest}
|
|
33
34
|
>
|
|
34
|
-
<svelte:element this={`h${headingLevel}`} class="ldt-alert__title"
|
|
35
|
+
{#if title}<svelte:element this={`h${headingLevel}`} class="ldt-alert__title"
|
|
36
|
+
>{#if typeof title === 'string'}{title}{:else}{@render title()}{/if}</svelte:element
|
|
37
|
+
>{/if}
|
|
35
38
|
{#if children}<div class="ldt-alert__description">{@render children()}</div>{/if}
|
|
36
39
|
</div>
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { Snippet } from 'svelte';
|
|
2
2
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
3
|
import type { HeadingLevel, StatusVariant } from '../types.js';
|
|
4
|
-
interface Props extends HTMLAttributes<HTMLDivElement> {
|
|
4
|
+
interface Props extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {
|
|
5
5
|
variant?: StatusVariant;
|
|
6
|
-
|
|
6
|
+
/** Optional heading. Accepts a snippet for rich content; omit it for a body-only alert. */
|
|
7
|
+
title?: string | Snippet;
|
|
7
8
|
/** Heading element used for the title, so the alert fits the page outline. */
|
|
8
9
|
headingLevel?: HeadingLevel;
|
|
9
10
|
class?: string;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { AlertDialog as AlertDialogPrimitive } from 'bits-ui';
|
|
3
|
+
import type { Snippet } from 'svelte';
|
|
4
|
+
import type { AlertDialogContentProps } from 'bits-ui';
|
|
5
|
+
import type {
|
|
6
|
+
ActionVariant,
|
|
7
|
+
ControlSize,
|
|
8
|
+
DialogSize,
|
|
9
|
+
HeadingLevel,
|
|
10
|
+
TriggerChildProps,
|
|
11
|
+
} from '../types.js';
|
|
12
|
+
import { cx } from '../utils.js';
|
|
13
|
+
|
|
14
|
+
type Props = Omit<AlertDialogContentProps, 'children' | 'class' | 'child'> & {
|
|
15
|
+
open?: boolean;
|
|
16
|
+
title: string;
|
|
17
|
+
/** What confirming will do. Say the consequence here, not in the button. */
|
|
18
|
+
description?: string;
|
|
19
|
+
/** Trigger contents, rendered inside a button styled with `triggerClass`. */
|
|
20
|
+
trigger?: Snippet;
|
|
21
|
+
/** Full control of the trigger element — receives the props Bits needs on it. */
|
|
22
|
+
triggerChild?: Snippet<[TriggerChildProps]>;
|
|
23
|
+
/** Button variant for the default trigger. An explicit `triggerClass` wins wholesale. */
|
|
24
|
+
triggerVariant?: ActionVariant;
|
|
25
|
+
triggerSize?: ControlSize;
|
|
26
|
+
triggerClass?: string;
|
|
27
|
+
/** Extra body content between the description and the buttons. */
|
|
28
|
+
children?: Snippet;
|
|
29
|
+
confirmLabel?: string;
|
|
30
|
+
cancelLabel?: string;
|
|
31
|
+
/** Colour of the confirm button. Use `danger` for anything destructive. */
|
|
32
|
+
confirmVariant?: ActionVariant;
|
|
33
|
+
onConfirm?: () => void;
|
|
34
|
+
onCancel?: () => void;
|
|
35
|
+
size?: DialogSize;
|
|
36
|
+
headingLevel?: HeadingLevel;
|
|
37
|
+
/** `class` lands on the portaled Content element. */
|
|
38
|
+
class?: string;
|
|
39
|
+
overlayClass?: string;
|
|
40
|
+
onOpenChange?: (open: boolean) => void;
|
|
41
|
+
ref?: HTMLElement | null;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
let {
|
|
45
|
+
open = $bindable(false),
|
|
46
|
+
title,
|
|
47
|
+
description,
|
|
48
|
+
trigger,
|
|
49
|
+
triggerChild,
|
|
50
|
+
triggerVariant,
|
|
51
|
+
triggerSize,
|
|
52
|
+
triggerClass,
|
|
53
|
+
children,
|
|
54
|
+
confirmLabel = 'Confirm',
|
|
55
|
+
cancelLabel = 'Cancel',
|
|
56
|
+
confirmVariant = 'primary',
|
|
57
|
+
onConfirm,
|
|
58
|
+
onCancel,
|
|
59
|
+
size = 'sm',
|
|
60
|
+
headingLevel = 2,
|
|
61
|
+
class: className,
|
|
62
|
+
overlayClass,
|
|
63
|
+
onOpenChange,
|
|
64
|
+
ref = $bindable(null),
|
|
65
|
+
...rest
|
|
66
|
+
}: Props = $props();
|
|
67
|
+
|
|
68
|
+
// An explicit triggerClass keeps today's contract and wins outright.
|
|
69
|
+
const triggerClasses = $derived(
|
|
70
|
+
triggerClass ??
|
|
71
|
+
cx(
|
|
72
|
+
'ldt-button',
|
|
73
|
+
triggerVariant && triggerVariant !== 'default' && `ldt-button--${triggerVariant}`,
|
|
74
|
+
triggerSize && triggerSize !== 'md' && `ldt-button--${triggerSize}`
|
|
75
|
+
)
|
|
76
|
+
);
|
|
77
|
+
</script>
|
|
78
|
+
|
|
79
|
+
<!--
|
|
80
|
+
A decision the user has to answer before anything else continues. Unlike `Dialog` it has no
|
|
81
|
+
close affordance in the corner and does not dismiss on an outside click — Bits' alertdialog
|
|
82
|
+
role enforces that, and it is the point: a confirmation you can dismiss by missing is not one.
|
|
83
|
+
Focus opens on Cancel, so a stray Enter cannot confirm a destructive action.
|
|
84
|
+
-->
|
|
85
|
+
<AlertDialogPrimitive.Root bind:open {onOpenChange}>
|
|
86
|
+
{#if triggerChild}<AlertDialogPrimitive.Trigger
|
|
87
|
+
>{#snippet child(childProps)}{@render triggerChild(
|
|
88
|
+
childProps
|
|
89
|
+
)}{/snippet}</AlertDialogPrimitive.Trigger
|
|
90
|
+
>{:else if trigger}<AlertDialogPrimitive.Trigger class={triggerClasses}
|
|
91
|
+
>{@render trigger()}</AlertDialogPrimitive.Trigger
|
|
92
|
+
>{/if}
|
|
93
|
+
<AlertDialogPrimitive.Portal>
|
|
94
|
+
<AlertDialogPrimitive.Overlay class={cx('ldt-overlay', overlayClass)} />
|
|
95
|
+
<AlertDialogPrimitive.Content
|
|
96
|
+
bind:ref
|
|
97
|
+
class={cx('ldt-dialog', size && `ldt-dialog--${size}`, className)}
|
|
98
|
+
{...rest}
|
|
99
|
+
>
|
|
100
|
+
<header class="ldt-dialog__header">
|
|
101
|
+
<div>
|
|
102
|
+
<AlertDialogPrimitive.Title level={headingLevel} class="ldt-dialog__title"
|
|
103
|
+
>{title}</AlertDialogPrimitive.Title
|
|
104
|
+
>{#if description}<AlertDialogPrimitive.Description class="ldt-dialog__description"
|
|
105
|
+
>{description}</AlertDialogPrimitive.Description
|
|
106
|
+
>{/if}
|
|
107
|
+
</div>
|
|
108
|
+
</header>
|
|
109
|
+
{#if children}<div class="ldt-dialog__body">{@render children()}</div>{/if}
|
|
110
|
+
<footer class="ldt-dialog__footer">
|
|
111
|
+
<AlertDialogPrimitive.Cancel
|
|
112
|
+
class="ldt-button ldt-button--quiet"
|
|
113
|
+
onclick={() => onCancel?.()}>{cancelLabel}</AlertDialogPrimitive.Cancel
|
|
114
|
+
>
|
|
115
|
+
<!--
|
|
116
|
+
Bits leaves the Action button open on purpose, for callers awaiting a request. This
|
|
117
|
+
wrapper is the declarative form, so it closes: `open` is bindable, and work that has to
|
|
118
|
+
keep the dialog up can set it back to `true` from `onConfirm`.
|
|
119
|
+
-->
|
|
120
|
+
<AlertDialogPrimitive.Action
|
|
121
|
+
class={cx('ldt-button', confirmVariant !== 'default' && `ldt-button--${confirmVariant}`)}
|
|
122
|
+
onclick={() => {
|
|
123
|
+
onConfirm?.();
|
|
124
|
+
open = false;
|
|
125
|
+
}}>{confirmLabel}</AlertDialogPrimitive.Action
|
|
126
|
+
>
|
|
127
|
+
</footer>
|
|
128
|
+
</AlertDialogPrimitive.Content>
|
|
129
|
+
</AlertDialogPrimitive.Portal>
|
|
130
|
+
</AlertDialogPrimitive.Root>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { AlertDialogContentProps } from 'bits-ui';
|
|
3
|
+
import type { ActionVariant, ControlSize, DialogSize, HeadingLevel, TriggerChildProps } from '../types.js';
|
|
4
|
+
type Props = Omit<AlertDialogContentProps, 'children' | 'class' | 'child'> & {
|
|
5
|
+
open?: boolean;
|
|
6
|
+
title: string;
|
|
7
|
+
/** What confirming will do. Say the consequence here, not in the button. */
|
|
8
|
+
description?: string;
|
|
9
|
+
/** Trigger contents, rendered inside a button styled with `triggerClass`. */
|
|
10
|
+
trigger?: Snippet;
|
|
11
|
+
/** Full control of the trigger element — receives the props Bits needs on it. */
|
|
12
|
+
triggerChild?: Snippet<[TriggerChildProps]>;
|
|
13
|
+
/** Button variant for the default trigger. An explicit `triggerClass` wins wholesale. */
|
|
14
|
+
triggerVariant?: ActionVariant;
|
|
15
|
+
triggerSize?: ControlSize;
|
|
16
|
+
triggerClass?: string;
|
|
17
|
+
/** Extra body content between the description and the buttons. */
|
|
18
|
+
children?: Snippet;
|
|
19
|
+
confirmLabel?: string;
|
|
20
|
+
cancelLabel?: string;
|
|
21
|
+
/** Colour of the confirm button. Use `danger` for anything destructive. */
|
|
22
|
+
confirmVariant?: ActionVariant;
|
|
23
|
+
onConfirm?: () => void;
|
|
24
|
+
onCancel?: () => void;
|
|
25
|
+
size?: DialogSize;
|
|
26
|
+
headingLevel?: HeadingLevel;
|
|
27
|
+
/** `class` lands on the portaled Content element. */
|
|
28
|
+
class?: string;
|
|
29
|
+
overlayClass?: string;
|
|
30
|
+
onOpenChange?: (open: boolean) => void;
|
|
31
|
+
ref?: HTMLElement | null;
|
|
32
|
+
};
|
|
33
|
+
declare const AlertDialog: import("svelte").Component<Props, {}, "ref" | "open">;
|
|
34
|
+
type AlertDialog = ReturnType<typeof AlertDialog>;
|
|
35
|
+
export default AlertDialog;
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import { cx } from '../utils.js';
|
|
5
5
|
|
|
6
6
|
interface Props extends HTMLAttributes<HTMLDivElement> {
|
|
7
|
+
/** Complete banner/header content, such as `Topbar`; rendered without another landmark wrapper. */
|
|
7
8
|
header?: Snippet;
|
|
8
9
|
children: Snippet;
|
|
9
10
|
footer?: Snippet;
|
|
@@ -25,7 +26,7 @@
|
|
|
25
26
|
</script>
|
|
26
27
|
|
|
27
28
|
<div bind:this={ref} class={cx('ldt-app-shell', className)} {...rest}>
|
|
28
|
-
{#if header}
|
|
29
|
+
{#if header}{@render header()}{/if}
|
|
29
30
|
<main id={mainId}>{@render children()}</main>
|
|
30
31
|
{#if footer}<footer>{@render footer()}</footer>{/if}
|
|
31
32
|
</div>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Snippet } from 'svelte';
|
|
2
2
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
3
|
interface Props extends HTMLAttributes<HTMLDivElement> {
|
|
4
|
+
/** Complete banner/header content, such as `Topbar`; rendered without another landmark wrapper. */
|
|
4
5
|
header?: Snippet;
|
|
5
6
|
children: Snippet;
|
|
6
7
|
footer?: Snippet;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
3
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
4
|
-
import type { BadgeVariant } from '../types.js';
|
|
4
|
+
import type { BadgeSize, BadgeVariant } from '../types.js';
|
|
5
5
|
import { cx } from '../utils.js';
|
|
6
6
|
|
|
7
7
|
interface Props extends HTMLAttributes<HTMLSpanElement> {
|
|
8
8
|
variant?: BadgeVariant;
|
|
9
|
+
size?: BadgeSize;
|
|
9
10
|
class?: string;
|
|
10
11
|
children: Snippet;
|
|
11
12
|
ref?: HTMLSpanElement | null;
|
|
@@ -13,6 +14,7 @@
|
|
|
13
14
|
|
|
14
15
|
let {
|
|
15
16
|
variant = 'default',
|
|
17
|
+
size = 'inline',
|
|
16
18
|
class: className,
|
|
17
19
|
children,
|
|
18
20
|
ref = $bindable(null),
|
|
@@ -22,6 +24,11 @@
|
|
|
22
24
|
|
|
23
25
|
<span
|
|
24
26
|
bind:this={ref}
|
|
25
|
-
class={cx(
|
|
27
|
+
class={cx(
|
|
28
|
+
'ldt-badge',
|
|
29
|
+
variant !== 'default' && `ldt-badge--${variant}`,
|
|
30
|
+
size !== 'inline' && `ldt-badge--${size}`,
|
|
31
|
+
className
|
|
32
|
+
)}
|
|
26
33
|
{...rest}>{@render children()}</span
|
|
27
34
|
>
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { Snippet } from 'svelte';
|
|
2
2
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
-
import type { BadgeVariant } from '../types.js';
|
|
3
|
+
import type { BadgeSize, BadgeVariant } from '../types.js';
|
|
4
4
|
interface Props extends HTMLAttributes<HTMLSpanElement> {
|
|
5
5
|
variant?: BadgeVariant;
|
|
6
|
+
size?: BadgeSize;
|
|
6
7
|
class?: string;
|
|
7
8
|
children: Snippet;
|
|
8
9
|
ref?: HTMLSpanElement | null;
|
|
@@ -3,17 +3,24 @@
|
|
|
3
3
|
import type { HTMLAnchorAttributes, HTMLAttributes } from 'svelte/elements';
|
|
4
4
|
import { cx } from '../utils.js';
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
6
|
+
interface CommonProps {
|
|
7
|
+
name: string;
|
|
8
|
+
/** Secondary line, e.g. an environment or version marker. */
|
|
9
|
+
meta?: string;
|
|
10
|
+
mark?: Snippet;
|
|
11
|
+
class?: string;
|
|
12
|
+
ref?: HTMLElement | null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Discriminated on `href`: an `<a>` with anchor attributes, or a plain `<span>`.
|
|
16
|
+
type Props = CommonProps &
|
|
17
|
+
(
|
|
18
|
+
| (Omit<HTMLAnchorAttributes, 'class'> & {
|
|
19
|
+
/** Renders an `<a>` instead of a `<span>`. */
|
|
20
|
+
href: string;
|
|
21
|
+
})
|
|
22
|
+
| (Omit<HTMLAttributes<HTMLSpanElement>, 'class'> & { href?: never })
|
|
23
|
+
);
|
|
17
24
|
|
|
18
25
|
let {
|
|
19
26
|
name,
|
|
@@ -28,8 +35,15 @@
|
|
|
28
35
|
|
|
29
36
|
{#snippet content()}{#if mark}{@render mark()}{/if}<strong class="ldt-brand__name">{name}</strong
|
|
30
37
|
>{#if meta}<span class="ldt-brand__meta">{meta}</span>{/if}{/snippet}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
38
|
+
<!-- TS cannot narrow the destructured `rest` by `href`, so each branch casts to its side
|
|
39
|
+
of the union. The public Props type still rejects mismatched attributes. -->
|
|
40
|
+
{#if href}<a
|
|
41
|
+
bind:this={ref}
|
|
42
|
+
{href}
|
|
43
|
+
class={cx('ldt-brand', className)}
|
|
44
|
+
{...rest as HTMLAnchorAttributes}>{@render content()}</a
|
|
45
|
+
>{:else}<span
|
|
46
|
+
bind:this={ref}
|
|
47
|
+
class={cx('ldt-brand', className)}
|
|
48
|
+
{...rest as HTMLAttributes<HTMLSpanElement>}>{@render content()}</span
|
|
35
49
|
>{/if}
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import type { Snippet } from 'svelte';
|
|
2
2
|
import type { HTMLAnchorAttributes, HTMLAttributes } from 'svelte/elements';
|
|
3
|
-
|
|
3
|
+
interface CommonProps {
|
|
4
4
|
name: string;
|
|
5
5
|
/** Secondary line, e.g. an environment or version marker. */
|
|
6
6
|
meta?: string;
|
|
7
|
-
/** Renders an `<a>` instead of a `<span>`. */
|
|
8
|
-
href?: string;
|
|
9
7
|
mark?: Snippet;
|
|
10
8
|
class?: string;
|
|
11
9
|
ref?: HTMLElement | null;
|
|
12
|
-
}
|
|
10
|
+
}
|
|
11
|
+
type Props = CommonProps & ((Omit<HTMLAnchorAttributes, 'class'> & {
|
|
12
|
+
/** Renders an `<a>` instead of a `<span>`. */
|
|
13
|
+
href: string;
|
|
14
|
+
}) | (Omit<HTMLAttributes<HTMLSpanElement>, 'class'> & {
|
|
15
|
+
href?: never;
|
|
16
|
+
}));
|
|
13
17
|
declare const Brand: import("svelte").Component<Props, {}, "ref">;
|
|
14
18
|
type Brand = ReturnType<typeof Brand>;
|
|
15
19
|
export default Brand;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
+
import type { Crumb } from '../types.js';
|
|
4
|
+
import { cx } from '../utils.js';
|
|
5
|
+
|
|
6
|
+
interface Props extends HTMLAttributes<HTMLElement> {
|
|
7
|
+
/** Ordered trail, root first. The last entry is the current page and is never a link. */
|
|
8
|
+
items: Crumb[];
|
|
9
|
+
/** Accessible name of the landmark. Several trails on one page need distinct names. */
|
|
10
|
+
label?: string;
|
|
11
|
+
/**
|
|
12
|
+
* Separator drawn between crumbs. Decorative — it lives in a `::before` on the list item, so
|
|
13
|
+
* it is never read out or copied with the text.
|
|
14
|
+
*/
|
|
15
|
+
separator?: string;
|
|
16
|
+
class?: string;
|
|
17
|
+
ref?: HTMLElement | null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
let {
|
|
21
|
+
items,
|
|
22
|
+
label = 'Breadcrumb',
|
|
23
|
+
separator = '/',
|
|
24
|
+
class: className,
|
|
25
|
+
ref = $bindable(null),
|
|
26
|
+
...rest
|
|
27
|
+
}: Props = $props();
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<nav
|
|
31
|
+
bind:this={ref}
|
|
32
|
+
class={cx('ldt-breadcrumbs', className)}
|
|
33
|
+
aria-label={label}
|
|
34
|
+
style={`--ldt-breadcrumb-separator: ${JSON.stringify(separator)}`}
|
|
35
|
+
{...rest}
|
|
36
|
+
>
|
|
37
|
+
<ol class="ldt-breadcrumbs__list">
|
|
38
|
+
{#each items as item, index (item.label)}
|
|
39
|
+
{@const current = index === items.length - 1}
|
|
40
|
+
<li class="ldt-breadcrumbs__item">
|
|
41
|
+
{#if item.href && !current}
|
|
42
|
+
<a class="ldt-breadcrumbs__link" href={item.href}>{item.label}</a>
|
|
43
|
+
{:else}
|
|
44
|
+
<!-- The current page is not a link, and says so. Marking it up as one that goes
|
|
45
|
+
nowhere is the most common breadcrumb defect. -->
|
|
46
|
+
<span class="ldt-breadcrumbs__current" aria-current={current ? 'page' : undefined}
|
|
47
|
+
>{item.label}</span
|
|
48
|
+
>
|
|
49
|
+
{/if}
|
|
50
|
+
</li>
|
|
51
|
+
{/each}
|
|
52
|
+
</ol>
|
|
53
|
+
</nav>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
2
|
+
import type { Crumb } from '../types.js';
|
|
3
|
+
interface Props extends HTMLAttributes<HTMLElement> {
|
|
4
|
+
/** Ordered trail, root first. The last entry is the current page and is never a link. */
|
|
5
|
+
items: Crumb[];
|
|
6
|
+
/** Accessible name of the landmark. Several trails on one page need distinct names. */
|
|
7
|
+
label?: string;
|
|
8
|
+
/**
|
|
9
|
+
* Separator drawn between crumbs. Decorative — it lives in a `::before` on the list item, so
|
|
10
|
+
* it is never read out or copied with the text.
|
|
11
|
+
*/
|
|
12
|
+
separator?: string;
|
|
13
|
+
class?: string;
|
|
14
|
+
ref?: HTMLElement | null;
|
|
15
|
+
}
|
|
16
|
+
declare const Breadcrumbs: import("svelte").Component<Props, {}, "ref">;
|
|
17
|
+
type Breadcrumbs = ReturnType<typeof Breadcrumbs>;
|
|
18
|
+
export default Breadcrumbs;
|