@poodle64/ui 2026.10.3 → 2026.10.5
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 +105 -7
- package/dist/components/ui/context-column/context-column.svelte +118 -21
- package/dist/components/ui/context-column/context-column.svelte.d.ts +24 -1
- package/dist/components/ui/document-pane/document-pane.svelte +136 -0
- package/dist/components/ui/document-pane/document-pane.svelte.d.ts +43 -0
- package/dist/components/ui/document-pane/index.d.ts +2 -0
- package/dist/components/ui/document-pane/index.js +2 -0
- package/dist/components/ui/ledger/head-cell.svelte +73 -0
- package/dist/components/ui/ledger/head-cell.svelte.d.ts +19 -0
- package/dist/components/ui/ledger/index.d.ts +1 -1
- package/dist/components/ui/ledger/ledger-columns.svelte +29 -21
- package/dist/components/ui/ledger/ledger-columns.svelte.d.ts +50 -13
- package/dist/components/ui/ledger/ledger.d.ts +6 -0
- package/dist/components/ui/ledger/ledger.js +9 -1
- package/dist/components/ui/ledger/ledger.svelte +65 -84
- package/dist/components/ui/ledger/ledger.svelte.d.ts +6 -1
- package/dist/components/ui/ledger/look.d.ts +32 -0
- package/dist/components/ui/ledger/look.js +32 -0
- package/dist/components/ui/ledger/types.d.ts +21 -11
- package/dist/components/ui/list-toolbar/icon-action.svelte +42 -0
- package/dist/components/ui/list-toolbar/icon-action.svelte.d.ts +7 -0
- package/dist/components/ui/list-toolbar/index.d.ts +3 -0
- package/dist/components/ui/list-toolbar/index.js +2 -0
- package/dist/components/ui/list-toolbar/list-toolbar.svelte +85 -0
- package/dist/components/ui/list-toolbar/list-toolbar.svelte.d.ts +32 -0
- package/dist/components/ui/list-toolbar/types.d.ts +18 -0
- package/dist/components/ui/list-toolbar/types.js +1 -0
- package/dist/components/ui/panel/panel.svelte +8 -1
- package/dist/components/ui/panel/panel.svelte.d.ts +6 -0
- package/dist/components/ui/record-list/index.d.ts +3 -0
- package/dist/components/ui/record-list/index.js +2 -0
- package/dist/components/ui/record-list/record-list.svelte +489 -0
- package/dist/components/ui/record-list/record-list.svelte.d.ts +89 -0
- package/dist/components/ui/record-list/thumbnail.svelte +32 -0
- package/dist/components/ui/record-list/thumbnail.svelte.d.ts +14 -0
- package/dist/components/ui/record-list/types.d.ts +40 -0
- package/dist/components/ui/record-list/types.js +1 -0
- package/dist/components/ui/record-switcher/index.d.ts +3 -0
- package/dist/components/ui/record-switcher/index.js +2 -0
- package/dist/components/ui/record-switcher/record-switcher.svelte +167 -0
- package/dist/components/ui/record-switcher/record-switcher.svelte.d.ts +28 -0
- package/dist/components/ui/record-switcher/types.d.ts +22 -0
- package/dist/components/ui/record-switcher/types.js +1 -0
- package/package.json +1 -1
- package/registry/component-map.json +34 -6
- package/registry/component-map.md +8 -4
|
@@ -45,30 +45,31 @@ export interface LedgerRow {
|
|
|
45
45
|
} | null;
|
|
46
46
|
}
|
|
47
47
|
/**
|
|
48
|
-
* A column
|
|
49
|
-
*
|
|
50
|
-
* `balance`, to offer the running balance at all, with `text` saying what it
|
|
51
|
-
* counts). Date, title and amount always show, first and in that order; the
|
|
52
|
-
* balance is always last. Every other key is the module's, in its order.
|
|
48
|
+
* A column a module offers a list in the ledger's look: the Ledger, and the
|
|
49
|
+
* RecordList for rows that are not money.
|
|
53
50
|
*/
|
|
54
|
-
export interface
|
|
51
|
+
export interface ListColumn<R> {
|
|
55
52
|
key: string;
|
|
56
53
|
/** Its name in the Columns menu, and its head unless `head` is shorter. */
|
|
57
54
|
label: string;
|
|
58
55
|
head?: string;
|
|
59
|
-
/** A grid track, or one for a narrow
|
|
56
|
+
/** A grid track, or one for a narrow list and one for a wide one (1200px and up). */
|
|
60
57
|
width?: string | {
|
|
61
58
|
narrow: string;
|
|
62
59
|
wide: string;
|
|
63
60
|
};
|
|
64
61
|
align?: 'start' | 'end';
|
|
65
|
-
/**
|
|
66
|
-
|
|
62
|
+
/**
|
|
63
|
+
* Ticked until the viewer chooses. Defaults to true. `'wide'` is ticked
|
|
64
|
+
* only on a wide list, so extra width shows more columns and the viewer
|
|
65
|
+
* can still tick it back on a narrow one.
|
|
66
|
+
*/
|
|
67
|
+
on?: boolean | 'wide';
|
|
67
68
|
/**
|
|
68
69
|
* What a click on the head sorts this column by: the real value, a number
|
|
69
70
|
* rather than its display text. Without it a column with `text` sorts by
|
|
70
|
-
* that text and a `cell`-only column does not sort. The running
|
|
71
|
-
* never sorts, since it depends on the order.
|
|
71
|
+
* that text and a `cell`-only column does not sort. The ledger's running
|
|
72
|
+
* balance never sorts, since it depends on the order.
|
|
72
73
|
*/
|
|
73
74
|
sort?: (row: R) => number | string | null | undefined;
|
|
74
75
|
/** A plain cell. */
|
|
@@ -79,6 +80,15 @@ export interface LedgerColumn<R extends LedgerRow = LedgerRow> {
|
|
|
79
80
|
*/
|
|
80
81
|
cell?: Snippet<[R]>;
|
|
81
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* A column the module offers the ledger. The keys `date`, `title`, `amount`
|
|
85
|
+
* and `balance` are the ledger's own cells: list one to rename or resize it
|
|
86
|
+
* (and, for `balance`, to offer the running balance at all, with `text` saying
|
|
87
|
+
* what it counts). Date, title and amount always show, first and in that
|
|
88
|
+
* order; the balance is always last, and off until ticked. Every other key is
|
|
89
|
+
* the module's, in its order.
|
|
90
|
+
*/
|
|
91
|
+
export type LedgerColumn<R extends LedgerRow = LedgerRow> = ListColumn<R>;
|
|
82
92
|
/** The viewer's own choices, which the consumer persists. */
|
|
83
93
|
export interface LedgerPreferences {
|
|
84
94
|
/** The ticked columns' keys, `balance` included. */
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/** An icon button, or an icon link, named by its tooltip. Inside a `Tooltip.Provider`. */
|
|
3
|
+
import { mergeProps } from 'bits-ui';
|
|
4
|
+
import { buttonVariants } from '../button/index.js';
|
|
5
|
+
import * as Tooltip from '../tooltip/index.js';
|
|
6
|
+
import type { ListIconAction } from './types.js';
|
|
7
|
+
|
|
8
|
+
let { action }: { action: ListIconAction } = $props();
|
|
9
|
+
const Icon = $derived(action.icon);
|
|
10
|
+
const klass = buttonVariants({ variant: 'ghost', size: 'icon-sm' });
|
|
11
|
+
|
|
12
|
+
/** The trigger's own handlers (a click closes the tooltip) chained with the action's. */
|
|
13
|
+
const merged = (props: Record<string, unknown>) =>
|
|
14
|
+
mergeProps(props, { onclick: action.onclick, class: klass, 'aria-label': action.label });
|
|
15
|
+
/** A link takes no button `type`. */
|
|
16
|
+
function asLink(props: Record<string, unknown>) {
|
|
17
|
+
const { type: _type, ...rest } = merged(props);
|
|
18
|
+
return rest;
|
|
19
|
+
}
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<Tooltip.Root>
|
|
23
|
+
<Tooltip.Trigger>
|
|
24
|
+
{#snippet child({ props })}
|
|
25
|
+
{#if action.href && !action.disabled}
|
|
26
|
+
<a
|
|
27
|
+
{...asLink(props)}
|
|
28
|
+
href={action.href}
|
|
29
|
+
download={action.download === true ? '' : action.download || undefined}
|
|
30
|
+
data-slot="list-action"
|
|
31
|
+
>
|
|
32
|
+
<Icon />
|
|
33
|
+
</a>
|
|
34
|
+
{:else}
|
|
35
|
+
<button {...merged(props)} type="button" disabled={action.disabled} data-slot="list-action">
|
|
36
|
+
<Icon />
|
|
37
|
+
</button>
|
|
38
|
+
{/if}
|
|
39
|
+
{/snippet}
|
|
40
|
+
</Tooltip.Trigger>
|
|
41
|
+
<Tooltip.Content side="bottom">{action.label}</Tooltip.Content>
|
|
42
|
+
</Tooltip.Root>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ListIconAction } from './types.js';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
action: ListIconAction;
|
|
4
|
+
};
|
|
5
|
+
declare const IconAction: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
6
|
+
type IconAction = ReturnType<typeof IconAction>;
|
|
7
|
+
export default IconAction;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* The bar above a list, on the page ground: the list's title and count,
|
|
4
|
+
* then its icon actions (each named by its tooltip) and its one labelled
|
|
5
|
+
* action. The ledger draws its own with this, so every list's bar is the
|
|
6
|
+
* same bar.
|
|
7
|
+
*
|
|
8
|
+
* <ListToolbar title="Owned properties" meta="3 properties"
|
|
9
|
+
* tools={[{ label: 'Download as CSV', icon: Download, onclick: save }]}
|
|
10
|
+
* action={{ label: 'Add property', icon: Plus, href: '/property/new' }} />
|
|
11
|
+
*/
|
|
12
|
+
import type { Snippet } from 'svelte';
|
|
13
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
14
|
+
import Button from '../button/button.svelte';
|
|
15
|
+
import * as Tooltip from '../tooltip/index.js';
|
|
16
|
+
import IconAction from './icon-action.svelte';
|
|
17
|
+
import { cn } from '../../../utils.js';
|
|
18
|
+
import type { ListAction, ListIconAction } from './types.js';
|
|
19
|
+
|
|
20
|
+
let {
|
|
21
|
+
title,
|
|
22
|
+
meta,
|
|
23
|
+
leading,
|
|
24
|
+
children,
|
|
25
|
+
tools = [],
|
|
26
|
+
action,
|
|
27
|
+
label,
|
|
28
|
+
class: className,
|
|
29
|
+
...restProps
|
|
30
|
+
}: Omit<HTMLAttributes<HTMLDivElement>, 'title'> & {
|
|
31
|
+
title?: string;
|
|
32
|
+
/** Beside the title, quieter: the count, or what the list is of. */
|
|
33
|
+
meta?: string;
|
|
34
|
+
/** Before the title: a switch between views of the same list. */
|
|
35
|
+
leading?: Snippet;
|
|
36
|
+
/** The list's own controls, before its icon actions: a menu, a filter. */
|
|
37
|
+
children?: Snippet;
|
|
38
|
+
/** Icon actions, each named by its tooltip. */
|
|
39
|
+
tools?: ListIconAction[];
|
|
40
|
+
/** The one labelled action, last. */
|
|
41
|
+
action?: ListAction;
|
|
42
|
+
/** The toolbar's accessible name. Defaults to the title. */
|
|
43
|
+
label?: string;
|
|
44
|
+
class?: string;
|
|
45
|
+
} = $props();
|
|
46
|
+
|
|
47
|
+
const ActionIcon = $derived(action?.icon);
|
|
48
|
+
</script>
|
|
49
|
+
|
|
50
|
+
<div
|
|
51
|
+
role="toolbar"
|
|
52
|
+
aria-label={label ?? title}
|
|
53
|
+
class={cn('flex min-h-11 flex-none items-center gap-2 px-2 pb-2', className)}
|
|
54
|
+
data-slot="list-toolbar"
|
|
55
|
+
{...restProps}
|
|
56
|
+
>
|
|
57
|
+
{@render leading?.()}
|
|
58
|
+
<!-- Crowded, the count gives way before the title, and the title ends in an ellipsis. -->
|
|
59
|
+
<div class="flex min-w-0 items-baseline gap-2.5 whitespace-nowrap">
|
|
60
|
+
{#if title}<h2 class="text-body min-w-0 truncate font-semibold">{title}</h2>{/if}
|
|
61
|
+
{#if meta}<span class="text-muted-foreground min-w-0 shrink-[100] truncate text-sm">{meta}</span>{/if}
|
|
62
|
+
</div>
|
|
63
|
+
<span class="min-w-0 flex-1"></span>
|
|
64
|
+
{@render children?.()}
|
|
65
|
+
{#if tools.length}
|
|
66
|
+
<Tooltip.Provider delayDuration={150}>
|
|
67
|
+
{#each tools as tool (tool.label)}
|
|
68
|
+
<IconAction action={tool} />
|
|
69
|
+
{/each}
|
|
70
|
+
</Tooltip.Provider>
|
|
71
|
+
{/if}
|
|
72
|
+
{#if action}
|
|
73
|
+
<Button
|
|
74
|
+
variant="outline"
|
|
75
|
+
size="sm"
|
|
76
|
+
href={action.href}
|
|
77
|
+
download={action.href ? (action.download === true ? '' : action.download || undefined) : undefined}
|
|
78
|
+
disabled={action.disabled}
|
|
79
|
+
onclick={action.onclick}
|
|
80
|
+
data-slot="list-toolbar-action"
|
|
81
|
+
>
|
|
82
|
+
{#if ActionIcon}<ActionIcon />{/if}{action.label}
|
|
83
|
+
</Button>
|
|
84
|
+
{/if}
|
|
85
|
+
</div>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The bar above a list, on the page ground: the list's title and count,
|
|
3
|
+
* then its icon actions (each named by its tooltip) and its one labelled
|
|
4
|
+
* action. The ledger draws its own with this, so every list's bar is the
|
|
5
|
+
* same bar.
|
|
6
|
+
*
|
|
7
|
+
* <ListToolbar title="Owned properties" meta="3 properties"
|
|
8
|
+
* tools={[{ label: 'Download as CSV', icon: Download, onclick: save }]}
|
|
9
|
+
* action={{ label: 'Add property', icon: Plus, href: '/property/new' }} />
|
|
10
|
+
*/
|
|
11
|
+
import type { Snippet } from 'svelte';
|
|
12
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
13
|
+
import type { ListAction, ListIconAction } from './types.js';
|
|
14
|
+
type $$ComponentProps = Omit<HTMLAttributes<HTMLDivElement>, 'title'> & {
|
|
15
|
+
title?: string;
|
|
16
|
+
/** Beside the title, quieter: the count, or what the list is of. */
|
|
17
|
+
meta?: string;
|
|
18
|
+
/** Before the title: a switch between views of the same list. */
|
|
19
|
+
leading?: Snippet;
|
|
20
|
+
/** The list's own controls, before its icon actions: a menu, a filter. */
|
|
21
|
+
children?: Snippet;
|
|
22
|
+
/** Icon actions, each named by its tooltip. */
|
|
23
|
+
tools?: ListIconAction[];
|
|
24
|
+
/** The one labelled action, last. */
|
|
25
|
+
action?: ListAction;
|
|
26
|
+
/** The toolbar's accessible name. Defaults to the title. */
|
|
27
|
+
label?: string;
|
|
28
|
+
class?: string;
|
|
29
|
+
};
|
|
30
|
+
declare const ListToolbar: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
31
|
+
type ListToolbar = ReturnType<typeof ListToolbar>;
|
|
32
|
+
export default ListToolbar;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { IconComponent } from '../app-shell/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* One action a list or a pane offers: a button, or a link when it has `href`.
|
|
4
|
+
* As an icon action its `label` is the tooltip and the accessible name.
|
|
5
|
+
*/
|
|
6
|
+
export interface ListAction {
|
|
7
|
+
label: string;
|
|
8
|
+
icon?: IconComponent;
|
|
9
|
+
onclick?: (event: MouseEvent) => void;
|
|
10
|
+
href?: string;
|
|
11
|
+
/** On a link, saves the target rather than opening it; a string names the file. */
|
|
12
|
+
download?: boolean | string;
|
|
13
|
+
disabled?: boolean;
|
|
14
|
+
}
|
|
15
|
+
/** An action drawn as its icon alone. */
|
|
16
|
+
export type ListIconAction = ListAction & {
|
|
17
|
+
icon: IconComponent;
|
|
18
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
tone = 'default',
|
|
26
26
|
children,
|
|
27
27
|
pad = true,
|
|
28
|
+
scroll = false,
|
|
28
29
|
class: klass = '',
|
|
29
30
|
ref = $bindable(null),
|
|
30
31
|
...restProps
|
|
@@ -70,6 +71,12 @@
|
|
|
70
71
|
tone?: 'default' | 'destructive';
|
|
71
72
|
children: Snippet;
|
|
72
73
|
pad?: boolean;
|
|
74
|
+
/**
|
|
75
|
+
* The body scrolls inside the card, under a header that stays: the card
|
|
76
|
+
* is as tall as what it holds up to the height its container gives it,
|
|
77
|
+
* and the full height when given one (`h-full`).
|
|
78
|
+
*/
|
|
79
|
+
scroll?: boolean;
|
|
73
80
|
} = $props();
|
|
74
81
|
|
|
75
82
|
const destructive = $derived(tone === 'destructive');
|
|
@@ -124,7 +131,7 @@
|
|
|
124
131
|
{/if}
|
|
125
132
|
</header>
|
|
126
133
|
{/if}
|
|
127
|
-
<div class={pad
|
|
134
|
+
<div class={cn(pad && 'p-4', scroll && 'min-h-0 flex-1 overflow-y-auto')} data-slot="panel-body">
|
|
128
135
|
{@render children()}
|
|
129
136
|
</div>
|
|
130
137
|
{#if footer}
|
|
@@ -45,6 +45,12 @@ type $$ComponentProps = WithElementRef<HTMLAttributes<HTMLElement>> & {
|
|
|
45
45
|
tone?: 'default' | 'destructive';
|
|
46
46
|
children: Snippet;
|
|
47
47
|
pad?: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* The body scrolls inside the card, under a header that stays: the card
|
|
50
|
+
* is as tall as what it holds up to the height its container gives it,
|
|
51
|
+
* and the full height when given one (`h-full`).
|
|
52
|
+
*/
|
|
53
|
+
scroll?: boolean;
|
|
48
54
|
};
|
|
49
55
|
declare const Panel: Component<$$ComponentProps, {}, "ref">;
|
|
50
56
|
type Panel = ReturnType<typeof Panel>;
|