@dorsk/tsumikit 0.38.1 → 0.40.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/dist/autoresize.d.ts +2 -0
- package/dist/autoresize.js +15 -1
- package/dist/components/atoms/Artwork.svelte +19 -18
- package/dist/components/atoms/Artwork.svelte.d.ts +3 -2
- package/dist/components/atoms/Badge.svelte +60 -26
- package/dist/components/atoms/Badge.svelte.d.ts +14 -3
- package/dist/components/atoms/Button.svelte +30 -12
- package/dist/components/atoms/Button.svelte.d.ts +4 -2
- package/dist/components/atoms/Card.svelte +47 -30
- package/dist/components/atoms/Card.svelte.d.ts +12 -3
- package/dist/components/atoms/Checkbox.svelte +16 -2
- package/dist/components/atoms/Checkbox.svelte.d.ts +2 -0
- package/dist/components/atoms/Dot.svelte +17 -11
- package/dist/components/atoms/Dot.svelte.d.ts +5 -2
- package/dist/components/atoms/Gauge.svelte +19 -18
- package/dist/components/atoms/Gauge.svelte.d.ts +3 -2
- package/dist/components/atoms/Heading.svelte +20 -19
- package/dist/components/atoms/Heading.svelte.d.ts +3 -2
- package/dist/components/atoms/Icon.svelte +36 -13
- package/dist/components/atoms/Icon.svelte.d.ts +20 -2
- package/dist/components/atoms/Input.svelte +17 -3
- package/dist/components/atoms/Input.svelte.d.ts +2 -1
- package/dist/components/atoms/Kbd.svelte +25 -3
- package/dist/components/atoms/Kbd.svelte.d.ts +5 -1
- package/dist/components/atoms/Link.svelte +16 -12
- package/dist/components/atoms/Link.svelte.d.ts +6 -2
- package/dist/components/atoms/Progress.svelte +119 -4
- package/dist/components/atoms/Progress.svelte.d.ts +28 -2
- package/dist/components/atoms/Scrim.svelte +7 -2
- package/dist/components/atoms/Scrim.svelte.d.ts +2 -0
- package/dist/components/atoms/SegmentedProgress.svelte +14 -2
- package/dist/components/atoms/SegmentedProgress.svelte.d.ts +5 -2
- package/dist/components/atoms/Select.svelte +18 -6
- package/dist/components/atoms/Select.svelte.d.ts +3 -3
- package/dist/components/atoms/Skeleton.svelte +12 -11
- package/dist/components/atoms/Skeleton.svelte.d.ts +3 -2
- package/dist/components/atoms/Slider.svelte +45 -3
- package/dist/components/atoms/Slider.svelte.d.ts +7 -0
- package/dist/components/atoms/Spinner.svelte +2 -0
- package/dist/components/atoms/Spinner.svelte.d.ts +2 -0
- package/dist/components/atoms/Switch.svelte +70 -18
- package/dist/components/atoms/Switch.svelte.d.ts +5 -1
- package/dist/components/atoms/Text.svelte +39 -26
- package/dist/components/atoms/Text.svelte.d.ts +7 -3
- package/dist/components/atoms/Textarea.svelte +47 -10
- package/dist/components/atoms/Textarea.svelte.d.ts +10 -3
- package/dist/components/layouts/AppShell.svelte +7 -3
- package/dist/components/layouts/AppShell.svelte.d.ts +2 -0
- package/dist/components/layouts/AutoGrid.svelte +8 -0
- package/dist/components/layouts/AutoGrid.svelte.d.ts +2 -0
- package/dist/components/layouts/Cluster.svelte +62 -1
- package/dist/components/layouts/Cluster.svelte.d.ts +9 -0
- package/dist/components/layouts/NavItem.svelte +22 -1
- package/dist/components/layouts/NavItem.svelte.d.ts +5 -0
- package/dist/components/layouts/NavSection.svelte +4 -1
- package/dist/components/layouts/NavSection.svelte.d.ts +2 -0
- package/dist/components/layouts/ResizablePanel.svelte +14 -3
- package/dist/components/layouts/ResizablePanel.svelte.d.ts +5 -0
- package/dist/components/layouts/Stack.svelte +41 -0
- package/dist/components/layouts/Stack.svelte.d.ts +9 -0
- package/dist/components/layouts/Toolbar.svelte +122 -0
- package/dist/components/layouts/Toolbar.svelte.d.ts +22 -0
- package/dist/components/molecules/AttachmentList.svelte +59 -0
- package/dist/components/molecules/AttachmentList.svelte.d.ts +13 -0
- package/dist/components/molecules/Breadcrumb.svelte +6 -2
- package/dist/components/molecules/Breadcrumb.svelte.d.ts +2 -0
- package/dist/components/molecules/Callout.svelte +10 -4
- package/dist/components/molecules/Callout.svelte.d.ts +1 -1
- package/dist/components/molecules/CapBar.svelte +5 -1
- package/dist/components/molecules/ChatBubble.svelte +158 -0
- package/dist/components/molecules/ChatBubble.svelte.d.ts +26 -0
- package/dist/components/molecules/CodeBlock.svelte +36 -3
- package/dist/components/molecules/CodeBlock.svelte.d.ts +8 -0
- package/dist/components/molecules/Composer.svelte +195 -0
- package/dist/components/molecules/Composer.svelte.d.ts +27 -0
- package/dist/components/molecules/ConfirmModal.svelte +15 -5
- package/dist/components/molecules/ConfirmModal.svelte.d.ts +5 -1
- package/dist/components/molecules/Drawer.svelte +9 -6
- package/dist/components/molecules/Dropzone.svelte +9 -3
- package/dist/components/molecules/Dropzone.svelte.d.ts +2 -0
- package/dist/components/molecules/EmptyState.svelte +9 -5
- package/dist/components/molecules/EmptyState.svelte.d.ts +3 -1
- package/dist/components/molecules/Field.svelte +7 -1
- package/dist/components/molecules/Field.svelte.d.ts +2 -0
- package/dist/components/molecules/FileButton.svelte +2 -1
- package/dist/components/molecules/FileButton.svelte.d.ts +2 -1
- package/dist/components/molecules/FilterInput.svelte +13 -3
- package/dist/components/molecules/FilterInput.svelte.d.ts +4 -1
- package/dist/components/molecules/FontScalePicker.svelte +8 -1
- package/dist/components/molecules/IconButton.svelte +32 -7
- package/dist/components/molecules/IconButton.svelte.d.ts +9 -1
- package/dist/components/molecules/KeyValue.svelte +4 -1
- package/dist/components/molecules/KeyValue.svelte.d.ts +2 -1
- package/dist/components/molecules/Menu.svelte +50 -5
- package/dist/components/molecules/Menu.svelte.d.ts +10 -1
- package/dist/components/molecules/Meter.svelte +91 -0
- package/dist/components/molecules/Meter.svelte.d.ts +29 -0
- package/dist/components/molecules/Metric.svelte +134 -8
- package/dist/components/molecules/Metric.svelte.d.ts +20 -2
- package/dist/components/molecules/Modal.svelte +26 -12
- package/dist/components/molecules/Modal.svelte.d.ts +7 -1
- package/dist/components/molecules/Pagination.svelte +25 -1
- package/dist/components/molecules/Pagination.svelte.d.ts +9 -2
- package/dist/components/molecules/Popover.svelte +16 -5
- package/dist/components/molecules/Popover.svelte.d.ts +5 -0
- package/dist/components/molecules/Prose.svelte +140 -0
- package/dist/components/molecules/Prose.svelte.d.ts +13 -0
- package/dist/components/molecules/RadioGroup.svelte +42 -2
- package/dist/components/molecules/RadioGroup.svelte.d.ts +4 -1
- package/dist/components/molecules/SectionHeader.svelte +5 -2
- package/dist/components/molecules/SectionHeader.svelte.d.ts +1 -1
- package/dist/components/molecules/SegmentedControl.svelte +36 -1
- package/dist/components/molecules/SegmentedControl.svelte.d.ts +11 -1
- package/dist/components/molecules/SelectButton.svelte +64 -4
- package/dist/components/molecules/SelectButton.svelte.d.ts +18 -1
- package/dist/components/molecules/Tabs.svelte +21 -3
- package/dist/components/molecules/Tabs.svelte.d.ts +6 -0
- package/dist/components/molecules/Timestamp.svelte +13 -6
- package/dist/components/molecules/Timestamp.svelte.d.ts +4 -0
- package/dist/components/molecules/Toaster.svelte +54 -38
- package/dist/components/molecules/Toaster.svelte.d.ts +5 -1
- package/dist/components/molecules/Toggle.svelte +2 -1
- package/dist/components/molecules/Toggle.svelte.d.ts +2 -1
- package/dist/components/molecules/Tooltip.svelte +32 -5
- package/dist/components/molecules/Tooltip.svelte.d.ts +9 -0
- package/dist/components/molecules/Truncate.svelte +156 -18
- package/dist/components/molecules/Truncate.svelte.d.ts +17 -1
- package/dist/components/molecules/WorkingDir.svelte +6 -0
- package/dist/components/molecules/WorkingDir.svelte.d.ts +2 -0
- package/dist/components/organisms/DataTable.svelte +38 -10
- package/dist/components/organisms/DataTable.svelte.d.ts +4 -0
- package/dist/components/organisms/FilterSearchBar.svelte +9 -2
- package/dist/components/organisms/FilterSearchBar.svelte.d.ts +4 -1
- package/dist/index.d.ts +10 -2
- package/dist/index.js +8 -1
- package/dist/size.d.ts +2 -0
- package/dist/size.js +1 -0
- package/dist/styles/tokens.css +3 -0
- package/dist/timestamp.d.ts +2 -2
- package/dist/timestamp.js +4 -4
- package/dist/tone.d.ts +1 -1
- package/dist/tone.js +1 -1
- package/dist/truncate.d.ts +13 -1
- package/dist/truncate.js +39 -0
- package/package.json +5 -3
|
@@ -1,4 +1,18 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import type { IconName } from '../atoms/Icon.svelte';
|
|
3
|
+
import type { Tone } from '../../tone';
|
|
4
|
+
|
|
5
|
+
export type MetricSegment = {
|
|
6
|
+
glyph?: string;
|
|
7
|
+
icon?: IconName;
|
|
8
|
+
value: string | number;
|
|
9
|
+
tone?: Tone;
|
|
10
|
+
hint?: string;
|
|
11
|
+
};
|
|
12
|
+
</script>
|
|
13
|
+
|
|
1
14
|
<script lang="ts">
|
|
15
|
+
import { canonicalTone } from '../../tone';
|
|
2
16
|
// KPI / stat tile — the dashboard's repeating "one number" card. Composes on
|
|
3
17
|
// top of `Card` and lays out four parts:
|
|
4
18
|
// • an uppercase, letter-spaced micro-label (top-left)
|
|
@@ -9,9 +23,8 @@
|
|
|
9
23
|
// `neutral` keeps the chip on the plain accent. Everything is token-driven.
|
|
10
24
|
import type { Snippet } from 'svelte';
|
|
11
25
|
import Card from '../atoms/Card.svelte';
|
|
12
|
-
import Icon
|
|
13
|
-
|
|
14
|
-
type Tone = 'neutral' | 'ok' | 'warn' | 'danger' | 'info';
|
|
26
|
+
import Icon from '../atoms/Icon.svelte';
|
|
27
|
+
import Tooltip from './Tooltip.svelte';
|
|
15
28
|
|
|
16
29
|
let {
|
|
17
30
|
label,
|
|
@@ -25,6 +38,12 @@
|
|
|
25
38
|
// Theme-aware surface shade, forwarded to the composed Card so tiles can
|
|
26
39
|
// opt into the same shade as sibling panels (no app-level :global override).
|
|
27
40
|
surface = 'base',
|
|
41
|
+
size = 'md',
|
|
42
|
+
layout = 'card',
|
|
43
|
+
href,
|
|
44
|
+
external = false,
|
|
45
|
+
onclick,
|
|
46
|
+
segments,
|
|
28
47
|
class: klass = '',
|
|
29
48
|
// Raw SVG markup for a custom icon — passed through to `Icon` so any glyph
|
|
30
49
|
// outside the registry can fill the chip.
|
|
@@ -39,25 +58,78 @@
|
|
|
39
58
|
tone?: Tone;
|
|
40
59
|
tintValue?: boolean;
|
|
41
60
|
surface?: 'base' | 'raised' | 'sunken';
|
|
61
|
+
/** `sm` is a dense tile (smaller value, tighter padding). */
|
|
62
|
+
size?: 'sm' | 'md';
|
|
63
|
+
/** Render the tile as a link / button with tap feedback. */
|
|
64
|
+
href?: string;
|
|
65
|
+
/** With `href`: new tab plus an arrow glyph after the label. */
|
|
66
|
+
external?: boolean;
|
|
67
|
+
onclick?: (e: MouseEvent | KeyboardEvent) => void;
|
|
68
|
+
/** `inline` drops the Card and renders a single stat row. */
|
|
69
|
+
layout?: 'card' | 'inline';
|
|
70
|
+
/** Extra stats after the value, each with an optional Tooltip hint. */
|
|
71
|
+
segments?: MetricSegment[];
|
|
42
72
|
class?: string;
|
|
43
73
|
iconChildren?: Snippet;
|
|
44
74
|
[key: string]: unknown;
|
|
45
75
|
} = $props();
|
|
46
76
|
</script>
|
|
47
77
|
|
|
78
|
+
{#snippet segment(seg: MetricSegment)}
|
|
79
|
+
{@const c = canonicalTone(seg.tone ?? 'neutral')}
|
|
80
|
+
<span class="metric-seg metric-seg-{c}">
|
|
81
|
+
{#if seg.icon}<Icon name={seg.icon} />{:else if seg.glyph}<span aria-hidden="true">{seg.glyph}</span>{/if}
|
|
82
|
+
<span class="metric-seg-val">{seg.value}</span>
|
|
83
|
+
</span>
|
|
84
|
+
{/snippet}
|
|
85
|
+
|
|
86
|
+
{#snippet segmentRow()}
|
|
87
|
+
{#if segments?.length}
|
|
88
|
+
<div class="metric-segments">
|
|
89
|
+
{#each segments as seg, i (i)}
|
|
90
|
+
{#if seg.hint}
|
|
91
|
+
<Tooltip text={seg.hint}>{#snippet trigger()}{@render segment(seg)}{/snippet}</Tooltip>
|
|
92
|
+
{:else}
|
|
93
|
+
{@render segment(seg)}
|
|
94
|
+
{/if}
|
|
95
|
+
{/each}
|
|
96
|
+
</div>
|
|
97
|
+
{/if}
|
|
98
|
+
{/snippet}
|
|
99
|
+
|
|
100
|
+
{#if layout === 'inline'}
|
|
101
|
+
<div
|
|
102
|
+
data-tsu="Metric"
|
|
103
|
+
class="metric metric-inline metric-{canonicalTone(tone)} {tintValue ? 'metric-tint' : ''} {klass}"
|
|
104
|
+
class:metric-sm={size === 'sm'}
|
|
105
|
+
{...rest}
|
|
106
|
+
>
|
|
107
|
+
<span class="metric-label">{label}</span>
|
|
108
|
+
<span class="metric-value">
|
|
109
|
+
<span class="metric-num">{value}</span>
|
|
110
|
+
{#if unit}<span class="metric-unit">{unit}</span>{/if}
|
|
111
|
+
</span>
|
|
112
|
+
{@render segmentRow()}
|
|
113
|
+
{#if sub}<span class="metric-sub">{sub}</span>{/if}
|
|
114
|
+
</div>
|
|
115
|
+
{:else}
|
|
48
116
|
<Card
|
|
49
117
|
data-tsu="Metric"
|
|
50
|
-
class="metric metric-{tone} {tintValue ? 'metric-tint' : ''} {klass}"
|
|
118
|
+
class="metric metric-{canonicalTone(tone)} {tintValue ? 'metric-tint' : ''} {size === 'sm' ? 'metric-sm' : ''} {klass}"
|
|
119
|
+
padding={size === 'sm' ? 'sm' : undefined}
|
|
51
120
|
{surface}
|
|
121
|
+
as={href ? 'a' : onclick ? 'button' : 'div'}
|
|
122
|
+
{href}
|
|
123
|
+
target={href && external ? '_blank' : undefined}
|
|
124
|
+
rel={href && external ? 'noopener noreferrer' : undefined}
|
|
125
|
+
{onclick}
|
|
126
|
+
tap={!!(href || onclick)}
|
|
52
127
|
{...rest}
|
|
53
128
|
>
|
|
54
129
|
<div class="metric-head">
|
|
55
|
-
<span class="metric-label">{label}</span>
|
|
130
|
+
<span class="metric-label">{label}{#if href && external}<Icon name="external" />{/if}</span>
|
|
56
131
|
{#if icon || iconChildren}
|
|
57
132
|
<span class="metric-chip" aria-hidden="true">
|
|
58
|
-
<!-- Only forward a children snippet when a custom icon was actually
|
|
59
|
-
provided; otherwise Icon's `children` branch always wins and the
|
|
60
|
-
registry `name` glyph never renders (empty chip). -->
|
|
61
133
|
{#if iconChildren}
|
|
62
134
|
<Icon name={icon}>{@render iconChildren()}</Icon>
|
|
63
135
|
{:else}
|
|
@@ -70,8 +142,10 @@
|
|
|
70
142
|
<span class="metric-num">{value}</span>
|
|
71
143
|
{#if unit}<span class="metric-unit">{unit}</span>{/if}
|
|
72
144
|
</div>
|
|
145
|
+
{@render segmentRow()}
|
|
73
146
|
{#if sub}<div class="metric-sub">{sub}</div>{/if}
|
|
74
147
|
</Card>
|
|
148
|
+
{/if}
|
|
75
149
|
|
|
76
150
|
<style>
|
|
77
151
|
:global(.metric) {
|
|
@@ -130,6 +204,8 @@
|
|
|
130
204
|
line-height: 1.1;
|
|
131
205
|
}
|
|
132
206
|
.metric-num {
|
|
207
|
+
min-width: 0;
|
|
208
|
+
overflow-wrap: anywhere;
|
|
133
209
|
font-size: var(--fs-2xl);
|
|
134
210
|
font-weight: var(--fw-semibold);
|
|
135
211
|
color: var(--text);
|
|
@@ -148,4 +224,54 @@
|
|
|
148
224
|
color: var(--text-faint);
|
|
149
225
|
line-height: 1.4;
|
|
150
226
|
}
|
|
227
|
+
:global(.metric-sm) .metric-num {
|
|
228
|
+
font-size: var(--fs-lg);
|
|
229
|
+
}
|
|
230
|
+
:global(.metric-sm) .metric-chip {
|
|
231
|
+
width: 1.5rem;
|
|
232
|
+
height: 1.5rem;
|
|
233
|
+
font-size: 0.875rem;
|
|
234
|
+
}
|
|
235
|
+
.metric-inline {
|
|
236
|
+
flex-direction: row;
|
|
237
|
+
align-items: baseline;
|
|
238
|
+
flex-wrap: wrap;
|
|
239
|
+
gap: var(--sp-2) var(--sp-3);
|
|
240
|
+
min-width: 0;
|
|
241
|
+
}
|
|
242
|
+
.metric-inline .metric-num {
|
|
243
|
+
font-size: var(--fs-md);
|
|
244
|
+
}
|
|
245
|
+
.metric-segments {
|
|
246
|
+
display: flex;
|
|
247
|
+
flex-wrap: wrap;
|
|
248
|
+
align-items: baseline;
|
|
249
|
+
gap: var(--sp-1) var(--sp-3);
|
|
250
|
+
font-family: var(--font-mono);
|
|
251
|
+
font-size: var(--fs-xs);
|
|
252
|
+
color: var(--text-muted);
|
|
253
|
+
}
|
|
254
|
+
.metric-seg {
|
|
255
|
+
display: inline-flex;
|
|
256
|
+
align-items: center;
|
|
257
|
+
gap: var(--sp-1);
|
|
258
|
+
--seg-tone: var(--text-muted);
|
|
259
|
+
color: var(--seg-tone);
|
|
260
|
+
font-variant-numeric: tabular-nums;
|
|
261
|
+
}
|
|
262
|
+
.metric-seg-ok {
|
|
263
|
+
--seg-tone: var(--ok);
|
|
264
|
+
}
|
|
265
|
+
.metric-seg-warn {
|
|
266
|
+
--seg-tone: var(--warn);
|
|
267
|
+
}
|
|
268
|
+
.metric-seg-danger {
|
|
269
|
+
--seg-tone: var(--danger);
|
|
270
|
+
}
|
|
271
|
+
.metric-seg-info {
|
|
272
|
+
--seg-tone: var(--info);
|
|
273
|
+
}
|
|
274
|
+
.metric-seg-accent {
|
|
275
|
+
--seg-tone: var(--accent);
|
|
276
|
+
}
|
|
151
277
|
</style>
|
|
@@ -1,6 +1,13 @@
|
|
|
1
|
+
import type { IconName } from '../atoms/Icon.svelte';
|
|
2
|
+
import type { Tone } from '../../tone';
|
|
3
|
+
export type MetricSegment = {
|
|
4
|
+
glyph?: string;
|
|
5
|
+
icon?: IconName;
|
|
6
|
+
value: string | number;
|
|
7
|
+
tone?: Tone;
|
|
8
|
+
hint?: string;
|
|
9
|
+
};
|
|
1
10
|
import type { Snippet } from 'svelte';
|
|
2
|
-
import { type IconName } from '../atoms/Icon.svelte';
|
|
3
|
-
type Tone = 'neutral' | 'ok' | 'warn' | 'danger' | 'info';
|
|
4
11
|
type $$ComponentProps = {
|
|
5
12
|
label: string;
|
|
6
13
|
value: string | number;
|
|
@@ -10,6 +17,17 @@ type $$ComponentProps = {
|
|
|
10
17
|
tone?: Tone;
|
|
11
18
|
tintValue?: boolean;
|
|
12
19
|
surface?: 'base' | 'raised' | 'sunken';
|
|
20
|
+
/** `sm` is a dense tile (smaller value, tighter padding). */
|
|
21
|
+
size?: 'sm' | 'md';
|
|
22
|
+
/** Render the tile as a link / button with tap feedback. */
|
|
23
|
+
href?: string;
|
|
24
|
+
/** With `href`: new tab plus an arrow glyph after the label. */
|
|
25
|
+
external?: boolean;
|
|
26
|
+
onclick?: (e: MouseEvent | KeyboardEvent) => void;
|
|
27
|
+
/** `inline` drops the Card and renders a single stat row. */
|
|
28
|
+
layout?: 'card' | 'inline';
|
|
29
|
+
/** Extra stats after the value, each with an optional Tooltip hint. */
|
|
30
|
+
segments?: MetricSegment[];
|
|
13
31
|
class?: string;
|
|
14
32
|
iconChildren?: Snippet;
|
|
15
33
|
[key: string]: unknown;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { canonicalTone, type Tone } from '../../tone';
|
|
2
3
|
// Accessible dialog / bottom-sheet built on the native <dialog> element, so
|
|
3
4
|
// the platform gives us the hard parts for free: top-layer rendering above
|
|
4
5
|
// everything (no z-index races), a real focus trap, inert background, initial
|
|
@@ -12,11 +13,12 @@
|
|
|
12
13
|
import Spinner from '../atoms/Spinner.svelte';
|
|
13
14
|
import IconButton from './IconButton.svelte';
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
const TONE_ICON: Record<Exclude<Tone, 'neutral'>, IconName> = {
|
|
16
|
+
const TONE_ICON: Record<Exclude<Tone, 'neutral' | 'success'>, IconName> = {
|
|
17
17
|
danger: 'warning',
|
|
18
18
|
warn: 'warning',
|
|
19
|
-
info: 'info'
|
|
19
|
+
info: 'info',
|
|
20
|
+
ok: 'check',
|
|
21
|
+
accent: 'info'
|
|
20
22
|
};
|
|
21
23
|
|
|
22
24
|
let {
|
|
@@ -28,7 +30,11 @@
|
|
|
28
30
|
size = 'md',
|
|
29
31
|
tone = 'neutral',
|
|
30
32
|
busy = false,
|
|
31
|
-
resizeKey
|
|
33
|
+
resizeKey,
|
|
34
|
+
class: klass = '',
|
|
35
|
+
style: styleProp = '',
|
|
36
|
+
bodyClass = '',
|
|
37
|
+
maxHeight,
|
|
32
38
|
}: {
|
|
33
39
|
title: string;
|
|
34
40
|
/** Controlled visibility. When provided the `<dialog>` stays mounted and
|
|
@@ -49,7 +55,14 @@
|
|
|
49
55
|
/** When set, the sheet is horizontally resizable on desktop and the chosen
|
|
50
56
|
* width persists under this localStorage key. */
|
|
51
57
|
resizeKey?: string;
|
|
58
|
+
class?: string;
|
|
59
|
+
style?: string;
|
|
60
|
+
/** Class on the inner sheet (the visible panel). */
|
|
61
|
+
bodyClass?: string;
|
|
62
|
+
/** Cap the sheet height; the body scrolls inside it. */
|
|
63
|
+
maxHeight?: string;
|
|
52
64
|
} = $props();
|
|
65
|
+
const t = $derived(canonicalTone(tone));
|
|
53
66
|
|
|
54
67
|
const titleId = `modal-title-${Math.random().toString(36).slice(2, 8)}`;
|
|
55
68
|
|
|
@@ -135,12 +148,12 @@
|
|
|
135
148
|
<dialog
|
|
136
149
|
bind:this={dialogEl}
|
|
137
150
|
data-tsu="Modal"
|
|
138
|
-
class="modal"
|
|
151
|
+
class="modal {klass}"
|
|
139
152
|
class:resizing
|
|
140
153
|
aria-labelledby={titleId}
|
|
141
154
|
aria-busy={busy || undefined}
|
|
142
|
-
data-tone={
|
|
143
|
-
style={width != null ? `--sheet-w: ${width}px
|
|
155
|
+
data-tone={t === 'neutral' ? undefined : t}
|
|
156
|
+
style="{width != null ? `--sheet-w: ${width}px;` : ''}{styleProp}"
|
|
144
157
|
oncancel={(e) => {
|
|
145
158
|
e.preventDefault(); /* keep parent the source of truth for open state */
|
|
146
159
|
requestClose();
|
|
@@ -151,16 +164,17 @@
|
|
|
151
164
|
onclick={onDialogClick}
|
|
152
165
|
>
|
|
153
166
|
<div
|
|
154
|
-
class="sheet"
|
|
167
|
+
class="sheet {bodyClass}"
|
|
168
|
+
style:max-height={maxHeight}
|
|
155
169
|
class:sheet-sm={size === 'sm'}
|
|
156
170
|
class:sheet-lg={size === 'lg'}
|
|
157
171
|
class:sheet-xl={size === 'xl'}
|
|
158
|
-
class:sheet-toned={
|
|
159
|
-
style:--modal-tone={
|
|
172
|
+
class:sheet-toned={t !== 'neutral'}
|
|
173
|
+
style:--modal-tone={t === 'neutral' ? undefined : `var(--${t})`}
|
|
160
174
|
>
|
|
161
175
|
<div class="sheet-head">
|
|
162
|
-
{#if
|
|
163
|
-
<span class="sheet-tone-icon"><Icon name={TONE_ICON[
|
|
176
|
+
{#if t !== 'neutral'}
|
|
177
|
+
<span class="sheet-tone-icon"><Icon name={TONE_ICON[t]} size={18} /></span>
|
|
164
178
|
{/if}
|
|
165
179
|
<span id={titleId} class="sheet-title truncate">{title}</span>
|
|
166
180
|
{#if busy}<Spinner label="Working" />{/if}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { type Tone } from '../../tone';
|
|
1
2
|
import type { Snippet } from 'svelte';
|
|
2
|
-
type Tone = 'neutral' | 'danger' | 'warn' | 'info';
|
|
3
3
|
type $$ComponentProps = {
|
|
4
4
|
title: string;
|
|
5
5
|
/** Controlled visibility. When provided the `<dialog>` stays mounted and
|
|
@@ -20,6 +20,12 @@ type $$ComponentProps = {
|
|
|
20
20
|
/** When set, the sheet is horizontally resizable on desktop and the chosen
|
|
21
21
|
* width persists under this localStorage key. */
|
|
22
22
|
resizeKey?: string;
|
|
23
|
+
class?: string;
|
|
24
|
+
style?: string;
|
|
25
|
+
/** Class on the inner sheet (the visible panel). */
|
|
26
|
+
bodyClass?: string;
|
|
27
|
+
/** Cap the sheet height; the body scrolls inside it. */
|
|
28
|
+
maxHeight?: string;
|
|
23
29
|
};
|
|
24
30
|
declare const Modal: import("svelte").Component<$$ComponentProps, {}, "open">;
|
|
25
31
|
type Modal = ReturnType<typeof Modal>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import type { ControlSize } from '../../size';
|
|
2
3
|
// Page navigation in two flavours: page mode (`page` + `pageCount`) or
|
|
3
4
|
// offset mode (`offset` + `limit` + `total`, page/pageCount derived and
|
|
4
5
|
// `offset` written back). Numbered buttons collapse to prev / "3 / 12" /
|
|
@@ -17,6 +18,9 @@
|
|
|
17
18
|
showEdges = true,
|
|
18
19
|
showRange = false,
|
|
19
20
|
size = 'md',
|
|
21
|
+
grow = false,
|
|
22
|
+
shrink = true,
|
|
23
|
+
block = false,
|
|
20
24
|
label = 'Pagination',
|
|
21
25
|
class: klass = ''
|
|
22
26
|
}: {
|
|
@@ -34,7 +38,13 @@
|
|
|
34
38
|
showEdges?: boolean;
|
|
35
39
|
/** Show "1–20 / 412" (offset mode) or "3 / 12" next to the buttons. */
|
|
36
40
|
showRange?: boolean;
|
|
37
|
-
size?:
|
|
41
|
+
size?: ControlSize;
|
|
42
|
+
/** Fill the free space of a flex row (`flex: 1 1 0`). */
|
|
43
|
+
grow?: boolean;
|
|
44
|
+
/** `false` pins the box (`flex: none`) so a flex row cannot squeeze it. */
|
|
45
|
+
shrink?: boolean;
|
|
46
|
+
/** Full-width block. */
|
|
47
|
+
block?: boolean;
|
|
38
48
|
label?: string;
|
|
39
49
|
class?: string;
|
|
40
50
|
} = $props();
|
|
@@ -95,6 +105,9 @@
|
|
|
95
105
|
<nav
|
|
96
106
|
data-tsu="Pagination"
|
|
97
107
|
class="pagination {klass}"
|
|
108
|
+
class:grow={grow}
|
|
109
|
+
class:no-shrink={!shrink}
|
|
110
|
+
class:block={block}
|
|
98
111
|
class:pagination-sm={size === 'sm'}
|
|
99
112
|
aria-label={label}
|
|
100
113
|
>
|
|
@@ -139,6 +152,17 @@
|
|
|
139
152
|
</nav>
|
|
140
153
|
|
|
141
154
|
<style>
|
|
155
|
+
.grow {
|
|
156
|
+
flex: 1 1 0;
|
|
157
|
+
min-width: 0;
|
|
158
|
+
}
|
|
159
|
+
.no-shrink {
|
|
160
|
+
flex: none;
|
|
161
|
+
}
|
|
162
|
+
.block {
|
|
163
|
+
display: flex;
|
|
164
|
+
width: 100%;
|
|
165
|
+
}
|
|
142
166
|
.pagination {
|
|
143
167
|
container-type: inline-size;
|
|
144
168
|
display: flex;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ControlSize } from '../../size';
|
|
1
2
|
type $$ComponentProps = {
|
|
2
3
|
/** 1-based current page. */
|
|
3
4
|
page?: number;
|
|
@@ -13,10 +14,16 @@ type $$ComponentProps = {
|
|
|
13
14
|
showEdges?: boolean;
|
|
14
15
|
/** Show "1–20 / 412" (offset mode) or "3 / 12" next to the buttons. */
|
|
15
16
|
showRange?: boolean;
|
|
16
|
-
size?:
|
|
17
|
+
size?: ControlSize;
|
|
18
|
+
/** Fill the free space of a flex row (`flex: 1 1 0`). */
|
|
19
|
+
grow?: boolean;
|
|
20
|
+
/** `false` pins the box (`flex: none`) so a flex row cannot squeeze it. */
|
|
21
|
+
shrink?: boolean;
|
|
22
|
+
/** Full-width block. */
|
|
23
|
+
block?: boolean;
|
|
17
24
|
label?: string;
|
|
18
25
|
class?: string;
|
|
19
26
|
};
|
|
20
|
-
declare const Pagination: import("svelte").Component<$$ComponentProps, {}, "
|
|
27
|
+
declare const Pagination: import("svelte").Component<$$ComponentProps, {}, "offset" | "page">;
|
|
21
28
|
type Pagination = ReturnType<typeof Pagination>;
|
|
22
29
|
export default Pagination;
|
|
@@ -38,7 +38,11 @@
|
|
|
38
38
|
role = 'dialog',
|
|
39
39
|
haspopup = 'dialog',
|
|
40
40
|
onopen,
|
|
41
|
-
onclose
|
|
41
|
+
onclose,
|
|
42
|
+
class: klass = '',
|
|
43
|
+
style: styleProp = '',
|
|
44
|
+
panelClass = '',
|
|
45
|
+
panelStyle = '',
|
|
42
46
|
}: {
|
|
43
47
|
placement?: Placement;
|
|
44
48
|
gap?: number;
|
|
@@ -74,6 +78,11 @@
|
|
|
74
78
|
haspopup?: HasPopup;
|
|
75
79
|
onopen?: () => void;
|
|
76
80
|
onclose?: () => void;
|
|
81
|
+
class?: string;
|
|
82
|
+
style?: string;
|
|
83
|
+
/** Class / inline style on the floating panel. */
|
|
84
|
+
panelClass?: string;
|
|
85
|
+
panelStyle?: string;
|
|
77
86
|
} = $props();
|
|
78
87
|
|
|
79
88
|
const canonicalChrome = $derived(
|
|
@@ -118,7 +127,8 @@
|
|
|
118
127
|
bind:this={triggerEl}
|
|
119
128
|
data-tsu="Popover"
|
|
120
129
|
type="button"
|
|
121
|
-
class="pop-trigger {triggerClass}"
|
|
130
|
+
class="pop-trigger {triggerClass} {klass}"
|
|
131
|
+
style={styleProp}
|
|
122
132
|
class:bare
|
|
123
133
|
class:canonical={canonicalChrome}
|
|
124
134
|
class:trigger-primary={variant === 'primary'}
|
|
@@ -149,7 +159,8 @@
|
|
|
149
159
|
bind:this={panelEl}
|
|
150
160
|
{id}
|
|
151
161
|
popover="auto"
|
|
152
|
-
class="pop-panel"
|
|
162
|
+
class="pop-panel {panelClass}"
|
|
163
|
+
style={panelStyle}
|
|
153
164
|
{role}
|
|
154
165
|
aria-label={label}
|
|
155
166
|
ontoggle={onToggle}
|
|
@@ -311,7 +322,7 @@
|
|
|
311
322
|
cursor: not-allowed;
|
|
312
323
|
}
|
|
313
324
|
/* `bare`: strip the chrome down to a plain button the consumer styles. */
|
|
314
|
-
.pop-trigger.bare {
|
|
325
|
+
:where(.pop-trigger.bare) {
|
|
315
326
|
height: auto;
|
|
316
327
|
min-height: 0;
|
|
317
328
|
min-width: 0;
|
|
@@ -320,7 +331,7 @@
|
|
|
320
331
|
border: 0;
|
|
321
332
|
background: none;
|
|
322
333
|
}
|
|
323
|
-
.pop-trigger.bare:hover:not(:disabled) {
|
|
334
|
+
:where(.pop-trigger.bare:hover:not(:disabled)) {
|
|
324
335
|
background: none;
|
|
325
336
|
}
|
|
326
337
|
.pop-panel {
|
|
@@ -40,6 +40,11 @@ type $$ComponentProps = {
|
|
|
40
40
|
haspopup?: HasPopup;
|
|
41
41
|
onopen?: () => void;
|
|
42
42
|
onclose?: () => void;
|
|
43
|
+
class?: string;
|
|
44
|
+
style?: string;
|
|
45
|
+
/** Class / inline style on the floating panel. */
|
|
46
|
+
panelClass?: string;
|
|
47
|
+
panelStyle?: string;
|
|
43
48
|
};
|
|
44
49
|
declare const Popover: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
45
50
|
type Popover = ReturnType<typeof Popover>;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
// Markdown style contract: headings, paragraphs, inline/block code, tables,
|
|
3
|
+
// quotes, lists and images, driven by the --md-* tokens. Feed it rendered
|
|
4
|
+
// `html` (already sanitised upstream) or children markup.
|
|
5
|
+
import type { Snippet } from 'svelte';
|
|
6
|
+
|
|
7
|
+
let {
|
|
8
|
+
html,
|
|
9
|
+
children,
|
|
10
|
+
compact = false,
|
|
11
|
+
class: klass = '',
|
|
12
|
+
style: styleProp = ''
|
|
13
|
+
}: {
|
|
14
|
+
/** Pre-rendered, trusted HTML. */
|
|
15
|
+
html?: string;
|
|
16
|
+
children?: Snippet;
|
|
17
|
+
/** Tighter vertical rhythm for chat bubbles. */
|
|
18
|
+
compact?: boolean;
|
|
19
|
+
class?: string;
|
|
20
|
+
style?: string;
|
|
21
|
+
} = $props();
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<div data-tsu="Prose" class="prose {klass}" class:compact style={styleProp}>
|
|
25
|
+
{#if html !== undefined}{@html html}{:else}{@render children?.()}{/if}
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<style>
|
|
29
|
+
.prose {
|
|
30
|
+
color: var(--md-text, var(--text));
|
|
31
|
+
font-size: var(--fs-sm);
|
|
32
|
+
line-height: var(--lh-normal);
|
|
33
|
+
overflow-wrap: anywhere;
|
|
34
|
+
--prose-gap: var(--sp-3);
|
|
35
|
+
}
|
|
36
|
+
.prose.compact {
|
|
37
|
+
--prose-gap: var(--sp-2);
|
|
38
|
+
}
|
|
39
|
+
.prose :global(> * + *) {
|
|
40
|
+
margin-top: var(--prose-gap);
|
|
41
|
+
}
|
|
42
|
+
.prose :global(p) {
|
|
43
|
+
margin: 0;
|
|
44
|
+
}
|
|
45
|
+
.prose :global(h1),
|
|
46
|
+
.prose :global(h2),
|
|
47
|
+
.prose :global(h3),
|
|
48
|
+
.prose :global(h4) {
|
|
49
|
+
margin: 0;
|
|
50
|
+
color: var(--md-heading, var(--text));
|
|
51
|
+
font-weight: var(--fw-semibold);
|
|
52
|
+
line-height: var(--lh-tight);
|
|
53
|
+
}
|
|
54
|
+
.prose :global(h1) {
|
|
55
|
+
font-size: var(--fs-xl);
|
|
56
|
+
}
|
|
57
|
+
.prose :global(h2) {
|
|
58
|
+
font-size: var(--fs-lg);
|
|
59
|
+
}
|
|
60
|
+
.prose :global(h3) {
|
|
61
|
+
font-size: var(--fs-md);
|
|
62
|
+
}
|
|
63
|
+
.prose :global(h4) {
|
|
64
|
+
font-size: var(--fs-base);
|
|
65
|
+
}
|
|
66
|
+
.prose :global(strong) {
|
|
67
|
+
color: var(--md-strong, var(--text));
|
|
68
|
+
font-weight: var(--fw-semibold);
|
|
69
|
+
}
|
|
70
|
+
.prose :global(a) {
|
|
71
|
+
color: var(--accent);
|
|
72
|
+
text-decoration: underline;
|
|
73
|
+
text-underline-offset: 0.15em;
|
|
74
|
+
}
|
|
75
|
+
.prose :global(code) {
|
|
76
|
+
font-family: var(--font-mono);
|
|
77
|
+
font-size: 0.92em;
|
|
78
|
+
color: var(--md-code, var(--text));
|
|
79
|
+
background: var(--md-code-bg, var(--bg-elevated-2));
|
|
80
|
+
padding: 0.1em 0.35em;
|
|
81
|
+
border-radius: var(--r-sm);
|
|
82
|
+
}
|
|
83
|
+
.prose :global(pre) {
|
|
84
|
+
margin: 0;
|
|
85
|
+
padding: var(--sp-3);
|
|
86
|
+
background: var(--bg-elevated);
|
|
87
|
+
border: 1px solid var(--border);
|
|
88
|
+
border-radius: var(--r-md);
|
|
89
|
+
overflow-x: auto;
|
|
90
|
+
font-family: var(--font-mono);
|
|
91
|
+
font-size: var(--fs-xs);
|
|
92
|
+
line-height: 1.5;
|
|
93
|
+
}
|
|
94
|
+
.prose :global(pre code) {
|
|
95
|
+
padding: 0;
|
|
96
|
+
background: none;
|
|
97
|
+
color: inherit;
|
|
98
|
+
font-size: inherit;
|
|
99
|
+
}
|
|
100
|
+
.prose :global(blockquote) {
|
|
101
|
+
margin: 0;
|
|
102
|
+
padding-inline-start: var(--sp-3);
|
|
103
|
+
border-inline-start: 3px solid var(--border-strong);
|
|
104
|
+
color: var(--text-muted);
|
|
105
|
+
}
|
|
106
|
+
.prose :global(ul),
|
|
107
|
+
.prose :global(ol) {
|
|
108
|
+
margin: 0;
|
|
109
|
+
padding-inline-start: 1.4em;
|
|
110
|
+
}
|
|
111
|
+
.prose :global(li + li) {
|
|
112
|
+
margin-top: var(--sp-1);
|
|
113
|
+
}
|
|
114
|
+
.prose :global(table) {
|
|
115
|
+
border-collapse: collapse;
|
|
116
|
+
width: 100%;
|
|
117
|
+
font-size: var(--fs-xs);
|
|
118
|
+
}
|
|
119
|
+
.prose :global(th),
|
|
120
|
+
.prose :global(td) {
|
|
121
|
+
padding: var(--sp-1) var(--sp-2);
|
|
122
|
+
border: 1px solid var(--border);
|
|
123
|
+
text-align: left;
|
|
124
|
+
vertical-align: top;
|
|
125
|
+
}
|
|
126
|
+
.prose :global(th) {
|
|
127
|
+
background: var(--bg-elevated-2);
|
|
128
|
+
color: var(--text-muted);
|
|
129
|
+
font-weight: var(--fw-semibold);
|
|
130
|
+
}
|
|
131
|
+
.prose :global(img) {
|
|
132
|
+
max-width: 100%;
|
|
133
|
+
height: auto;
|
|
134
|
+
border-radius: var(--r-md);
|
|
135
|
+
}
|
|
136
|
+
.prose :global(hr) {
|
|
137
|
+
border: 0;
|
|
138
|
+
border-top: 1px solid var(--border);
|
|
139
|
+
}
|
|
140
|
+
</style>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
/** Pre-rendered, trusted HTML. */
|
|
4
|
+
html?: string;
|
|
5
|
+
children?: Snippet;
|
|
6
|
+
/** Tighter vertical rhythm for chat bubbles. */
|
|
7
|
+
compact?: boolean;
|
|
8
|
+
class?: string;
|
|
9
|
+
style?: string;
|
|
10
|
+
};
|
|
11
|
+
declare const Prose: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
12
|
+
type Prose = ReturnType<typeof Prose>;
|
|
13
|
+
export default Prose;
|