@dorsk/tsumikit 0.38.1 → 0.39.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 +33 -13
- package/dist/components/atoms/Icon.svelte.d.ts +17 -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 +4 -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/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/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 +14 -3
- 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
package/dist/autoresize.d.ts
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Usage: <textarea use:autoresize={value} ...></textarea>
|
|
7
7
|
*/
|
|
8
|
+
/** Height `rows` lines would occupy: line boxes plus vertical padding and borders. */
|
|
9
|
+
export declare function rowsFloor(node: HTMLTextAreaElement): number;
|
|
8
10
|
export declare function autoresize(node: HTMLTextAreaElement, _value?: string): {
|
|
9
11
|
update(): void;
|
|
10
12
|
destroy(): void;
|
package/dist/autoresize.js
CHANGED
|
@@ -5,12 +5,26 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Usage: <textarea use:autoresize={value} ...></textarea>
|
|
7
7
|
*/
|
|
8
|
+
/** Height `rows` lines would occupy: line boxes plus vertical padding and borders. */
|
|
9
|
+
export function rowsFloor(node) {
|
|
10
|
+
const rows = node.rows || 0;
|
|
11
|
+
if (rows <= 1)
|
|
12
|
+
return 0;
|
|
13
|
+
const cs = getComputedStyle(node);
|
|
14
|
+
const fontSize = parseFloat(cs.fontSize) || 16;
|
|
15
|
+
const lh = parseFloat(cs.lineHeight) || fontSize * 1.2;
|
|
16
|
+
const box = (parseFloat(cs.paddingTop) || 0) +
|
|
17
|
+
(parseFloat(cs.paddingBottom) || 0) +
|
|
18
|
+
(parseFloat(cs.borderTopWidth) || 0) +
|
|
19
|
+
(parseFloat(cs.borderBottomWidth) || 0);
|
|
20
|
+
return rows * lh + box;
|
|
21
|
+
}
|
|
8
22
|
export function autoresize(node, _value) {
|
|
9
23
|
const resize = () => {
|
|
10
24
|
// A manual drag handle may set `min-height` as a user-chosen floor; grow
|
|
11
25
|
// with content but never collapse below it. Content always wins the lower
|
|
12
26
|
// bound, so dragging shorter than the text can't shrink past it.
|
|
13
|
-
const floor = parseFloat(node.style.minHeight) || 0;
|
|
27
|
+
const floor = Math.max(parseFloat(node.style.minHeight) || 0, rowsFloor(node));
|
|
14
28
|
node.style.height = 'auto';
|
|
15
29
|
node.style.height = `${Math.max(node.scrollHeight, floor)}px`;
|
|
16
30
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
2
3
|
// Cover / thumbnail tile: a lazy <img> that swaps to a seeded gradient with
|
|
3
4
|
// initials (or an icon) when there is no source or it fails to load. Width
|
|
4
5
|
// comes from `size`, height from `aspect`; `status` overlays a Dot/Badge in
|
|
@@ -8,22 +9,7 @@
|
|
|
8
9
|
import Icon from './Icon.svelte';
|
|
9
10
|
import type { IconName } from './Icon.svelte';
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
src,
|
|
13
|
-
alt,
|
|
14
|
-
seed,
|
|
15
|
-
aspect = '1/1',
|
|
16
|
-
size,
|
|
17
|
-
radius = 'md',
|
|
18
|
-
fit = 'cover',
|
|
19
|
-
fallback = 'initials',
|
|
20
|
-
icon = 'image',
|
|
21
|
-
status,
|
|
22
|
-
hover = false,
|
|
23
|
-
onerror,
|
|
24
|
-
class: klass = '',
|
|
25
|
-
...rest
|
|
26
|
-
}: {
|
|
12
|
+
type Own = {
|
|
27
13
|
src?: string | null;
|
|
28
14
|
alt: string;
|
|
29
15
|
/** Drives the gradient hue and the initials. Defaults to `alt`. */
|
|
@@ -43,8 +29,23 @@
|
|
|
43
29
|
hover?: boolean;
|
|
44
30
|
onerror?: () => void;
|
|
45
31
|
class?: string;
|
|
46
|
-
|
|
47
|
-
|
|
32
|
+
};
|
|
33
|
+
let {
|
|
34
|
+
src,
|
|
35
|
+
alt,
|
|
36
|
+
seed,
|
|
37
|
+
aspect = '1/1',
|
|
38
|
+
size,
|
|
39
|
+
radius = 'md',
|
|
40
|
+
fit = 'cover',
|
|
41
|
+
fallback = 'initials',
|
|
42
|
+
icon = 'image',
|
|
43
|
+
status,
|
|
44
|
+
hover = false,
|
|
45
|
+
onerror,
|
|
46
|
+
class: klass = '',
|
|
47
|
+
...rest
|
|
48
|
+
}: Omit<HTMLAttributes<HTMLElement>, keyof Own> & Own = $props();
|
|
48
49
|
|
|
49
50
|
let failed = $state(false);
|
|
50
51
|
$effect(() => {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
1
2
|
import type { Snippet } from 'svelte';
|
|
2
3
|
import type { IconName } from './Icon.svelte';
|
|
3
|
-
type
|
|
4
|
+
type Own = {
|
|
4
5
|
src?: string | null;
|
|
5
6
|
alt: string;
|
|
6
7
|
/** Drives the gradient hue and the initials. Defaults to `alt`. */
|
|
@@ -20,8 +21,8 @@ type $$ComponentProps = {
|
|
|
20
21
|
hover?: boolean;
|
|
21
22
|
onerror?: () => void;
|
|
22
23
|
class?: string;
|
|
23
|
-
[key: string]: unknown;
|
|
24
24
|
};
|
|
25
|
+
type $$ComponentProps = Omit<HTMLAttributes<HTMLElement>, keyof Own> & Own;
|
|
25
26
|
declare const Artwork: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
26
27
|
type Artwork = ReturnType<typeof Artwork>;
|
|
27
28
|
export default Artwork;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
2
3
|
// Inline label primitive — the project's single pill. Covers three jobs via
|
|
3
4
|
// props rather than separate components:
|
|
4
5
|
// • state → `tone` semantic palette, or `color` for any CSS colour
|
|
@@ -23,31 +24,21 @@
|
|
|
23
24
|
violet: 'var(--c-violet)',
|
|
24
25
|
};
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
tone = 'neutral',
|
|
28
|
-
color,
|
|
29
|
-
as = 'span',
|
|
30
|
-
size = 'md',
|
|
31
|
-
variant = 'chip',
|
|
32
|
-
mono = false,
|
|
33
|
-
uppercase = false,
|
|
34
|
-
numeric = false,
|
|
35
|
-
truncate = false,
|
|
36
|
-
maxWidth,
|
|
37
|
-
border = true,
|
|
38
|
-
active = false,
|
|
39
|
-
dot = false,
|
|
40
|
-
icon,
|
|
41
|
-
removable = false,
|
|
42
|
-
onremove,
|
|
43
|
-
class: klass = '',
|
|
44
|
-
children,
|
|
45
|
-
...rest
|
|
46
|
-
}: {
|
|
27
|
+
type Own = {
|
|
47
28
|
tone?: Tone;
|
|
29
|
+
/** Fill the free space of a flex row (`flex: 1 1 0`). */
|
|
30
|
+
grow?: boolean;
|
|
31
|
+
/** `false` pins the box (`flex: none`) so a flex row cannot squeeze it. */
|
|
32
|
+
shrink?: boolean;
|
|
33
|
+
/** Full-width block. */
|
|
34
|
+
block?: boolean;
|
|
48
35
|
// Any CSS colour (or var()) for a one-off tint; overrides `tone`.
|
|
49
36
|
color?: string;
|
|
50
|
-
as?: 'span' | 'button';
|
|
37
|
+
as?: 'span' | 'button' | 'a';
|
|
38
|
+
/** Renders an anchor (implies `as="a"`). */
|
|
39
|
+
href?: string;
|
|
40
|
+
/** Opens in a new tab with a trailing arrow glyph. */
|
|
41
|
+
external?: boolean;
|
|
51
42
|
// `xs` is the densest form for counters in tight rows.
|
|
52
43
|
size?: 'xs' | 'sm' | 'md';
|
|
53
44
|
// `text` drops the chip (no fill, ring or padding) but keeps badge
|
|
@@ -74,16 +65,47 @@
|
|
|
74
65
|
onremove?: (e: MouseEvent) => void;
|
|
75
66
|
class?: string;
|
|
76
67
|
children?: Snippet;
|
|
77
|
-
|
|
78
|
-
|
|
68
|
+
};
|
|
69
|
+
let {
|
|
70
|
+
tone = 'neutral',
|
|
71
|
+
color,
|
|
72
|
+
as = 'span',
|
|
73
|
+
href,
|
|
74
|
+
external = false,
|
|
75
|
+
size = 'md',
|
|
76
|
+
variant = 'chip',
|
|
77
|
+
mono = false,
|
|
78
|
+
uppercase = false,
|
|
79
|
+
numeric = false,
|
|
80
|
+
truncate = false,
|
|
81
|
+
maxWidth,
|
|
82
|
+
border = true,
|
|
83
|
+
active = false,
|
|
84
|
+
dot = false,
|
|
85
|
+
icon,
|
|
86
|
+
removable = false,
|
|
87
|
+
onremove,
|
|
88
|
+
class: klass = '',
|
|
89
|
+
grow = false,
|
|
90
|
+
shrink = true,
|
|
91
|
+
block = false,
|
|
92
|
+
children,
|
|
93
|
+
...rest
|
|
94
|
+
}: Omit<HTMLAttributes<HTMLElement>, keyof Own> & Own = $props();
|
|
79
95
|
|
|
80
96
|
const toneColor = $derived(color ?? (tone === 'neutral' ? undefined : TONE_COLOR[tone]));
|
|
81
97
|
</script>
|
|
82
98
|
|
|
83
99
|
<svelte:element
|
|
84
|
-
this={as}
|
|
100
|
+
this={href ? 'a' : as}
|
|
101
|
+
{href}
|
|
102
|
+
target={href && external ? '_blank' : undefined}
|
|
103
|
+
rel={href && external ? 'noopener noreferrer' : undefined}
|
|
85
104
|
data-tsu="Badge"
|
|
86
105
|
class="badge {klass}"
|
|
106
|
+
class:grow={grow}
|
|
107
|
+
class:no-shrink={!shrink}
|
|
108
|
+
class:block={block}
|
|
87
109
|
class:badge-ok={tone === 'ok'}
|
|
88
110
|
class:badge-warn={tone === 'warn'}
|
|
89
111
|
class:badge-danger={tone === 'danger'}
|
|
@@ -98,7 +120,7 @@
|
|
|
98
120
|
class:truncate
|
|
99
121
|
class:borderless={!border}
|
|
100
122
|
class:active
|
|
101
|
-
class:interactive={as === 'button'}
|
|
123
|
+
class:interactive={as === 'button' || !!href}
|
|
102
124
|
style:--badge-tone={toneColor}
|
|
103
125
|
style:--badge-max-width={maxWidth}
|
|
104
126
|
{...rest}
|
|
@@ -114,6 +136,7 @@
|
|
|
114
136
|
{:else}
|
|
115
137
|
{@render children?.()}
|
|
116
138
|
{/if}
|
|
139
|
+
{#if href && external}<Icon name="external" />{/if}
|
|
117
140
|
{#if removable}
|
|
118
141
|
<button
|
|
119
142
|
type="button"
|
|
@@ -127,6 +150,17 @@
|
|
|
127
150
|
</svelte:element>
|
|
128
151
|
|
|
129
152
|
<style>
|
|
153
|
+
.grow {
|
|
154
|
+
flex: 1 1 0;
|
|
155
|
+
min-width: 0;
|
|
156
|
+
}
|
|
157
|
+
.no-shrink {
|
|
158
|
+
flex: none;
|
|
159
|
+
}
|
|
160
|
+
.block {
|
|
161
|
+
display: flex;
|
|
162
|
+
width: 100%;
|
|
163
|
+
}
|
|
130
164
|
.badge {
|
|
131
165
|
display: inline-flex;
|
|
132
166
|
align-items: center;
|
|
@@ -1,10 +1,21 @@
|
|
|
1
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
1
2
|
import type { Snippet } from 'svelte';
|
|
2
3
|
import { type IconName } from './Icon.svelte';
|
|
3
4
|
type Tone = 'neutral' | 'ok' | 'warn' | 'danger' | 'info' | 'accent' | 'muted' | 'violet';
|
|
4
|
-
type
|
|
5
|
+
type Own = {
|
|
5
6
|
tone?: Tone;
|
|
7
|
+
/** Fill the free space of a flex row (`flex: 1 1 0`). */
|
|
8
|
+
grow?: boolean;
|
|
9
|
+
/** `false` pins the box (`flex: none`) so a flex row cannot squeeze it. */
|
|
10
|
+
shrink?: boolean;
|
|
11
|
+
/** Full-width block. */
|
|
12
|
+
block?: boolean;
|
|
6
13
|
color?: string;
|
|
7
|
-
as?: 'span' | 'button';
|
|
14
|
+
as?: 'span' | 'button' | 'a';
|
|
15
|
+
/** Renders an anchor (implies `as="a"`). */
|
|
16
|
+
href?: string;
|
|
17
|
+
/** Opens in a new tab with a trailing arrow glyph. */
|
|
18
|
+
external?: boolean;
|
|
8
19
|
size?: 'xs' | 'sm' | 'md';
|
|
9
20
|
variant?: 'chip' | 'text';
|
|
10
21
|
mono?: boolean;
|
|
@@ -20,8 +31,8 @@ type $$ComponentProps = {
|
|
|
20
31
|
onremove?: (e: MouseEvent) => void;
|
|
21
32
|
class?: string;
|
|
22
33
|
children?: Snippet;
|
|
23
|
-
[key: string]: unknown;
|
|
24
34
|
};
|
|
35
|
+
type $$ComponentProps = Omit<HTMLAttributes<HTMLElement>, keyof Own> & Own;
|
|
25
36
|
declare const Badge: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
26
37
|
type Badge = ReturnType<typeof Badge>;
|
|
27
38
|
export default Badge;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import type { ControlSize } from '../../size';
|
|
3
|
+
import { canonicalTone, type Tone } from '../../tone';
|
|
2
4
|
import type { Snippet } from 'svelte';
|
|
3
5
|
import type { HTMLButtonAttributes } from 'svelte/elements';
|
|
4
6
|
|
|
@@ -9,8 +11,8 @@
|
|
|
9
11
|
// Semantic state tint layered on top of the variant: tints text/border and
|
|
10
12
|
// adds a subtle fill on hover. For stateful controls — an "on"/active toggle
|
|
11
13
|
// (`accent`), positive actions (`success`), or cost/severity states.
|
|
12
|
-
tone?:
|
|
13
|
-
size?:
|
|
14
|
+
tone?: Tone | 'none';
|
|
15
|
+
size?: ControlSize;
|
|
14
16
|
control?: boolean;
|
|
15
17
|
// Fully rounded ends (`--r-pill`) on any size/variant.
|
|
16
18
|
pill?: boolean;
|
|
@@ -39,8 +41,8 @@
|
|
|
39
41
|
// Square text/icon control whose side equals the current height contract:
|
|
40
42
|
// `size` tier, or `--control-height` with `control`.
|
|
41
43
|
square?: boolean;
|
|
42
|
-
// Outlined `--box-lg
|
|
43
|
-
// for tinted severity chips
|
|
44
|
+
// Outlined `--box-lg`-tall chip (header/toolbar action): a square for a lone
|
|
45
|
+
// glyph, otherwise sized to its text. Pairs with `tone` for tinted severity chips.
|
|
44
46
|
chip?: boolean;
|
|
45
47
|
iconInline?: boolean;
|
|
46
48
|
hoverDanger?: boolean;
|
|
@@ -86,6 +88,7 @@
|
|
|
86
88
|
children,
|
|
87
89
|
...rest
|
|
88
90
|
}: ButtonProps = $props();
|
|
91
|
+
const t = $derived(canonicalTone(tone));
|
|
89
92
|
|
|
90
93
|
// A link-flavoured Button is a real <a>; native `disabled`/`type` don't apply,
|
|
91
94
|
// so a disabled link is expressed via aria-disabled + inert pointer handling.
|
|
@@ -121,7 +124,7 @@
|
|
|
121
124
|
class:btn-grow={grow}
|
|
122
125
|
class:btn-primary={variant === 'primary'}
|
|
123
126
|
class:btn-ghost={variant === 'ghost'}
|
|
124
|
-
class:btn-danger={variant === 'danger' || (
|
|
127
|
+
class:btn-danger={variant === 'danger' || (t === 'danger' && variant === 'default')}
|
|
125
128
|
class:btn-link={variant === 'link'}
|
|
126
129
|
class:btn-pill={pill}
|
|
127
130
|
class:no-shrink={!shrink}
|
|
@@ -137,11 +140,11 @@
|
|
|
137
140
|
class:btn-collapse-container={collapseLabel === 'container'}
|
|
138
141
|
class:hit-compact={hitArea === 'compact'}
|
|
139
142
|
style:--btn-box={box ? `var(--box-${box})` : undefined}
|
|
140
|
-
class:btn-tone-accent={
|
|
141
|
-
class:btn-tone-success={
|
|
142
|
-
class:btn-tone-info={
|
|
143
|
-
class:btn-tone-warn={
|
|
144
|
-
class:btn-tone-danger={
|
|
143
|
+
class:btn-tone-accent={t === 'accent'}
|
|
144
|
+
class:btn-tone-success={t === 'ok'}
|
|
145
|
+
class:btn-tone-info={t === 'info'}
|
|
146
|
+
class:btn-tone-warn={t === 'warn'}
|
|
147
|
+
class:btn-tone-danger={t === 'danger'}
|
|
145
148
|
class:btn-icon-inline={iconInline}
|
|
146
149
|
class:hover-danger={hoverDanger}
|
|
147
150
|
class:loading
|
|
@@ -277,11 +280,16 @@
|
|
|
277
280
|
min-height: var(--box-lg);
|
|
278
281
|
min-width: var(--box-lg);
|
|
279
282
|
height: var(--box-lg);
|
|
280
|
-
width:
|
|
281
|
-
padding: 0;
|
|
283
|
+
width: auto;
|
|
284
|
+
padding: 0 var(--sp-2);
|
|
285
|
+
gap: var(--sp-1);
|
|
282
286
|
flex: none;
|
|
283
287
|
border-radius: var(--r-md);
|
|
284
288
|
}
|
|
289
|
+
.btn-chip:has(> :global(svg):only-child) {
|
|
290
|
+
width: var(--box-lg);
|
|
291
|
+
padding: 0;
|
|
292
|
+
}
|
|
285
293
|
|
|
286
294
|
/* Uniform-height control: icon buttons, inputs and action buttons that share a
|
|
287
295
|
toolbar/composer row line up exactly. */
|
|
@@ -334,6 +342,16 @@
|
|
|
334
342
|
background: color-mix(in srgb, var(--ok) 14%, transparent);
|
|
335
343
|
border-color: var(--ok);
|
|
336
344
|
}
|
|
345
|
+
.btn-control.btn-danger,
|
|
346
|
+
.btn-control.btn-tone-danger {
|
|
347
|
+
color: var(--danger);
|
|
348
|
+
border-color: color-mix(in srgb, var(--danger) 50%, var(--border));
|
|
349
|
+
}
|
|
350
|
+
.btn-control.btn-danger:hover:not(:disabled),
|
|
351
|
+
.btn-control.btn-tone-danger:hover:not(:disabled) {
|
|
352
|
+
background: color-mix(in srgb, var(--danger) 14%, transparent);
|
|
353
|
+
border-color: var(--danger);
|
|
354
|
+
}
|
|
337
355
|
/* A positive primary action uses success as its fill, not merely as the
|
|
338
356
|
neutral tint. This follows the control override so both heights match. */
|
|
339
357
|
.btn-primary.btn-tone-success {
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import type { ControlSize } from '../../size';
|
|
2
|
+
import { type Tone } from '../../tone';
|
|
1
3
|
import type { Snippet } from 'svelte';
|
|
2
4
|
import type { HTMLButtonAttributes } from 'svelte/elements';
|
|
3
5
|
type ButtonProps = HTMLButtonAttributes & {
|
|
4
6
|
variant?: 'default' | 'primary' | 'ghost' | 'danger' | 'link';
|
|
5
|
-
tone?:
|
|
6
|
-
size?:
|
|
7
|
+
tone?: Tone | 'none';
|
|
8
|
+
size?: ControlSize;
|
|
7
9
|
control?: boolean;
|
|
8
10
|
pill?: boolean;
|
|
9
11
|
block?: boolean;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
+
import { canonicalTone, type Tone as SharedTone } from '../../tone';
|
|
2
4
|
// Elevated surface primitive — the canonical card/panel container. Owns its
|
|
3
5
|
// background/border/radius/padding from theme tokens. `tap` adds the
|
|
4
6
|
// interactive hover/active affordance for tappable list items (e.g. session
|
|
@@ -25,8 +27,38 @@
|
|
|
25
27
|
import type { Snippet } from 'svelte';
|
|
26
28
|
import SectionHeader from '../molecules/SectionHeader.svelte';
|
|
27
29
|
|
|
28
|
-
type Tone =
|
|
30
|
+
type Tone = SharedTone | 'attention';
|
|
29
31
|
|
|
32
|
+
type Own = {
|
|
33
|
+
/** Polymorphic attributes for `as="a"` / `as="button"`. */
|
|
34
|
+
href?: string;
|
|
35
|
+
target?: string;
|
|
36
|
+
rel?: string;
|
|
37
|
+
type?: 'button' | 'submit' | 'reset';
|
|
38
|
+
tap?: boolean;
|
|
39
|
+
interactive?: boolean;
|
|
40
|
+
as?: 'div' | 'button' | 'a' | 'li' | 'section' | 'form';
|
|
41
|
+
padding?: 'none' | 'sm' | 'md' | 'lg';
|
|
42
|
+
surface?: 'base' | 'raised' | 'sunken';
|
|
43
|
+
tone?: Tone;
|
|
44
|
+
stacked?: boolean;
|
|
45
|
+
stackTone?: Tone;
|
|
46
|
+
stackY?: number;
|
|
47
|
+
stackX?: number;
|
|
48
|
+
title?: string;
|
|
49
|
+
subtitle?: string;
|
|
50
|
+
gap?: string;
|
|
51
|
+
/** `hidden` clips children to the rounded box. */
|
|
52
|
+
overflow?: 'visible' | 'hidden';
|
|
53
|
+
maxWidth?: string;
|
|
54
|
+
onclick?: (e: MouseEvent | KeyboardEvent) => void;
|
|
55
|
+
class?: string;
|
|
56
|
+
style?: string;
|
|
57
|
+
header?: Snippet;
|
|
58
|
+
footer?: Snippet;
|
|
59
|
+
actions?: Snippet;
|
|
60
|
+
children?: Snippet;
|
|
61
|
+
};
|
|
30
62
|
let {
|
|
31
63
|
tap = false,
|
|
32
64
|
interactive = false,
|
|
@@ -41,6 +73,7 @@
|
|
|
41
73
|
title,
|
|
42
74
|
subtitle,
|
|
43
75
|
gap,
|
|
76
|
+
overflow,
|
|
44
77
|
maxWidth,
|
|
45
78
|
onclick,
|
|
46
79
|
class: klass = '',
|
|
@@ -50,30 +83,8 @@
|
|
|
50
83
|
actions,
|
|
51
84
|
children,
|
|
52
85
|
...rest
|
|
53
|
-
}:
|
|
54
|
-
|
|
55
|
-
interactive?: boolean;
|
|
56
|
-
as?: 'div' | 'button' | 'a' | 'li' | 'section' | 'form';
|
|
57
|
-
padding?: 'none' | 'sm' | 'md' | 'lg';
|
|
58
|
-
surface?: 'base' | 'raised' | 'sunken';
|
|
59
|
-
tone?: Tone;
|
|
60
|
-
stacked?: boolean;
|
|
61
|
-
stackTone?: Tone;
|
|
62
|
-
stackY?: number;
|
|
63
|
-
stackX?: number;
|
|
64
|
-
title?: string;
|
|
65
|
-
subtitle?: string;
|
|
66
|
-
gap?: string;
|
|
67
|
-
maxWidth?: string;
|
|
68
|
-
onclick?: (e: MouseEvent | KeyboardEvent) => void;
|
|
69
|
-
class?: string;
|
|
70
|
-
style?: string;
|
|
71
|
-
header?: Snippet;
|
|
72
|
-
footer?: Snippet;
|
|
73
|
-
actions?: Snippet;
|
|
74
|
-
children?: Snippet;
|
|
75
|
-
[key: string]: unknown;
|
|
76
|
-
} = $props();
|
|
86
|
+
}: Omit<HTMLAttributes<HTMLElement>, keyof Own> & Own = $props();
|
|
87
|
+
const t = $derived(canonicalTone(tone));
|
|
77
88
|
|
|
78
89
|
let stackStyle = $derived(
|
|
79
90
|
stacked ? `--stack-y:${stackY}px;--stack-x:${stackX}px;` : ''
|
|
@@ -112,11 +123,12 @@
|
|
|
112
123
|
class:surface-sunken={surface === 'sunken'}
|
|
113
124
|
class:card-tap={tap || interactive}
|
|
114
125
|
class:card-max={maxWidth !== undefined}
|
|
115
|
-
class:card-ok={
|
|
116
|
-
class:card-warn={
|
|
117
|
-
class:card-danger={
|
|
118
|
-
class:card-info={
|
|
119
|
-
class:card-attention={
|
|
126
|
+
class:card-ok={t === 'ok'}
|
|
127
|
+
class:card-warn={t === 'warn'}
|
|
128
|
+
class:card-danger={t === 'danger'}
|
|
129
|
+
class:card-info={t === 'info'}
|
|
130
|
+
class:card-attention={t === 'attention'}
|
|
131
|
+
class:card-accent={t === 'accent'}
|
|
120
132
|
class:card-stacked={stacked}
|
|
121
133
|
class:stack-ok={stacked && stackTone === 'ok'}
|
|
122
134
|
class:stack-warn={stacked && stackTone === 'warn'}
|
|
@@ -126,6 +138,7 @@
|
|
|
126
138
|
class:card-gap={!framed && gap !== undefined}
|
|
127
139
|
style:--card-gap={gap}
|
|
128
140
|
style:max-width={maxWidth}
|
|
141
|
+
style:overflow={overflow}
|
|
129
142
|
style={`${stackStyle}${style}`}
|
|
130
143
|
role={interactive && !native ? 'button' : undefined}
|
|
131
144
|
tabindex={interactive && !native ? 0 : undefined}
|
|
@@ -153,6 +166,7 @@
|
|
|
153
166
|
<style>
|
|
154
167
|
.card {
|
|
155
168
|
--card-pad: var(--sp-4);
|
|
169
|
+
min-width: 0;
|
|
156
170
|
background: var(--bg-elevated);
|
|
157
171
|
border: 1px solid var(--border);
|
|
158
172
|
border-radius: var(--r-lg);
|
|
@@ -234,6 +248,9 @@
|
|
|
234
248
|
.card-attention {
|
|
235
249
|
--card-tone: var(--attention-bar);
|
|
236
250
|
}
|
|
251
|
+
.card-accent {
|
|
252
|
+
--card-tone: var(--accent);
|
|
253
|
+
}
|
|
237
254
|
.card-ok,
|
|
238
255
|
.card-warn,
|
|
239
256
|
.card-danger,
|
|
@@ -1,6 +1,13 @@
|
|
|
1
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
2
|
+
import { type Tone as SharedTone } from '../../tone';
|
|
1
3
|
import type { Snippet } from 'svelte';
|
|
2
|
-
type Tone =
|
|
3
|
-
type
|
|
4
|
+
type Tone = SharedTone | 'attention';
|
|
5
|
+
type Own = {
|
|
6
|
+
/** Polymorphic attributes for `as="a"` / `as="button"`. */
|
|
7
|
+
href?: string;
|
|
8
|
+
target?: string;
|
|
9
|
+
rel?: string;
|
|
10
|
+
type?: 'button' | 'submit' | 'reset';
|
|
4
11
|
tap?: boolean;
|
|
5
12
|
interactive?: boolean;
|
|
6
13
|
as?: 'div' | 'button' | 'a' | 'li' | 'section' | 'form';
|
|
@@ -14,6 +21,8 @@ type $$ComponentProps = {
|
|
|
14
21
|
title?: string;
|
|
15
22
|
subtitle?: string;
|
|
16
23
|
gap?: string;
|
|
24
|
+
/** `hidden` clips children to the rounded box. */
|
|
25
|
+
overflow?: 'visible' | 'hidden';
|
|
17
26
|
maxWidth?: string;
|
|
18
27
|
onclick?: (e: MouseEvent | KeyboardEvent) => void;
|
|
19
28
|
class?: string;
|
|
@@ -22,8 +31,8 @@ type $$ComponentProps = {
|
|
|
22
31
|
footer?: Snippet;
|
|
23
32
|
actions?: Snippet;
|
|
24
33
|
children?: Snippet;
|
|
25
|
-
[key: string]: unknown;
|
|
26
34
|
};
|
|
35
|
+
type $$ComponentProps = Omit<HTMLAttributes<HTMLElement>, keyof Own> & Own;
|
|
27
36
|
declare const Card: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
28
37
|
type Card = ReturnType<typeof Card>;
|
|
29
38
|
export default Card;
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
indeterminate = false,
|
|
12
12
|
invalid = false,
|
|
13
13
|
label,
|
|
14
|
+
labelHidden = false,
|
|
14
15
|
id,
|
|
15
16
|
'aria-describedby': ariaDescribedby,
|
|
16
17
|
'aria-invalid': ariaInvalid,
|
|
@@ -23,6 +24,8 @@
|
|
|
23
24
|
/** Error state: danger box border + aria-invalid. */
|
|
24
25
|
invalid?: boolean;
|
|
25
26
|
label: string;
|
|
27
|
+
/** Keep `label` for AT only (sr-only). */
|
|
28
|
+
labelHidden?: boolean;
|
|
26
29
|
id?: string;
|
|
27
30
|
'aria-describedby'?: string | null;
|
|
28
31
|
'aria-invalid'?: HTMLInputAttributes['aria-invalid'];
|
|
@@ -49,7 +52,7 @@
|
|
|
49
52
|
aria-invalid={ariaInvalid ?? (isInvalid ? 'true' : undefined)}
|
|
50
53
|
/>
|
|
51
54
|
<span class="box" aria-hidden="true"></span>
|
|
52
|
-
<span class="label-text">{label}</span>
|
|
55
|
+
<span class="label-text" class:sr-only={labelHidden}>{label}</span>
|
|
53
56
|
</label>
|
|
54
57
|
|
|
55
58
|
<style>
|
|
@@ -108,7 +111,7 @@
|
|
|
108
111
|
clip-path: polygon(22% 42%, 78% 42%, 78% 58%, 22% 58%);
|
|
109
112
|
}
|
|
110
113
|
input:focus-visible + .box {
|
|
111
|
-
outline:
|
|
114
|
+
outline: var(--focus-ring);
|
|
112
115
|
outline-offset: 2px;
|
|
113
116
|
}
|
|
114
117
|
input[aria-invalid='true']:not(:checked):not(:indeterminate) + .box {
|
|
@@ -120,4 +123,15 @@
|
|
|
120
123
|
.checkbox:has(input:disabled) {
|
|
121
124
|
cursor: not-allowed;
|
|
122
125
|
}
|
|
126
|
+
.sr-only {
|
|
127
|
+
position: absolute;
|
|
128
|
+
width: 1px;
|
|
129
|
+
height: 1px;
|
|
130
|
+
padding: 0;
|
|
131
|
+
margin: -1px;
|
|
132
|
+
overflow: hidden;
|
|
133
|
+
clip: rect(0, 0, 0, 0);
|
|
134
|
+
white-space: nowrap;
|
|
135
|
+
border: 0;
|
|
136
|
+
}
|
|
123
137
|
</style>
|
|
@@ -5,6 +5,8 @@ type $$ComponentProps = HTMLInputAttributes & {
|
|
|
5
5
|
/** Error state: danger box border + aria-invalid. */
|
|
6
6
|
invalid?: boolean;
|
|
7
7
|
label: string;
|
|
8
|
+
/** Keep `label` for AT only (sr-only). */
|
|
9
|
+
labelHidden?: boolean;
|
|
8
10
|
id?: string;
|
|
9
11
|
'aria-describedby'?: string | null;
|
|
10
12
|
'aria-invalid'?: HTMLInputAttributes['aria-invalid'];
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
2
3
|
// Status dot — a small coloured disc, optionally followed by a label. Owns its
|
|
3
4
|
// own styling (it does not rely on any global `.dot` rules). Colour comes from
|
|
4
5
|
// either:
|
|
@@ -20,34 +21,39 @@
|
|
|
20
21
|
hibernated: 'var(--dot-hibernated)',
|
|
21
22
|
};
|
|
22
23
|
|
|
24
|
+
type Own = {
|
|
25
|
+
status?: Status;
|
|
26
|
+
color?: string;
|
|
27
|
+
label?: string;
|
|
28
|
+
glow?: boolean;
|
|
29
|
+
ring?: boolean;
|
|
30
|
+
/** Focusable (`tabindex=0`, `role=img`) so it can anchor a Tooltip. */
|
|
31
|
+
interactive?: boolean;
|
|
32
|
+
class?: string;
|
|
33
|
+
};
|
|
23
34
|
let {
|
|
24
35
|
status = 'active',
|
|
25
36
|
color,
|
|
26
37
|
label,
|
|
27
38
|
glow = false,
|
|
28
39
|
ring = false,
|
|
40
|
+
interactive = false,
|
|
29
41
|
class: klass = '',
|
|
30
42
|
...rest
|
|
31
|
-
}:
|
|
32
|
-
status?: Status;
|
|
33
|
-
color?: string;
|
|
34
|
-
label?: string;
|
|
35
|
-
glow?: boolean;
|
|
36
|
-
ring?: boolean;
|
|
37
|
-
class?: string;
|
|
38
|
-
[key: string]: unknown;
|
|
39
|
-
} = $props();
|
|
43
|
+
}: Omit<HTMLAttributes<HTMLSpanElement>, keyof Own> & Own = $props();
|
|
40
44
|
|
|
41
45
|
const resolved = $derived(color ?? STATUS_COLOR[status]);
|
|
42
46
|
</script>
|
|
43
47
|
|
|
44
48
|
{#if label}
|
|
45
|
-
|
|
49
|
+
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
|
50
|
+
<span class="dot-row {klass}" data-tsu="Dot" role={interactive ? 'img' : undefined} tabindex={interactive ? 0 : undefined} aria-label={interactive ? label : undefined} {...rest}>
|
|
46
51
|
<span class="dot" class:glow class:ring style="--dot-color:{resolved}"></span>
|
|
47
52
|
<Text variant="caption">{label}</Text>
|
|
48
53
|
</span>
|
|
49
54
|
{:else}
|
|
50
|
-
|
|
55
|
+
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
|
56
|
+
<span class="dot {klass}" class:glow class:ring style="--dot-color:{resolved}" data-tsu="Dot" role={interactive ? 'img' : undefined} tabindex={interactive ? 0 : undefined} {...rest}></span>
|
|
51
57
|
{/if}
|
|
52
58
|
|
|
53
59
|
<style>
|