@nqmcreative/ui 0.2.2 → 0.3.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 +15 -15
- package/cli/index.mjs +81 -42
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.js +1 -1
- package/dist/core/toast.svelte.d.ts +3 -0
- package/dist/core/trigger.d.ts +6 -0
- package/dist/core/trigger.js +13 -0
- package/dist/styles/matte/AccordionItem.svelte +5 -0
- package/dist/styles/matte/AccordionItem.svelte.d.ts +2 -0
- package/dist/styles/matte/Avatar.svelte +15 -0
- package/dist/styles/matte/Avatar.svelte.d.ts +3 -0
- package/dist/styles/matte/Badge.svelte +5 -0
- package/dist/styles/matte/Badge.svelte.d.ts +2 -0
- package/dist/styles/matte/Breadcrumb.svelte +11 -4
- package/dist/styles/matte/Breadcrumb.svelte.d.ts +3 -0
- package/dist/styles/matte/Button.svelte +62 -11
- package/dist/styles/matte/Button.svelte.d.ts +14 -2
- package/dist/styles/matte/Card.svelte +9 -4
- package/dist/styles/matte/Card.svelte.d.ts +2 -0
- package/dist/styles/matte/CheckboxGroup.svelte +6 -0
- package/dist/styles/matte/CheckboxGroup.svelte.d.ts +2 -0
- package/dist/styles/matte/Combobox.svelte +7 -2
- package/dist/styles/matte/Combobox.svelte.d.ts +3 -0
- package/dist/styles/matte/CommandPalette.svelte +38 -7
- package/dist/styles/matte/CommandPalette.svelte.d.ts +8 -0
- package/dist/styles/matte/DatePicker.svelte +2 -2
- package/dist/styles/matte/Drawer.svelte +7 -2
- package/dist/styles/matte/Drawer.svelte.d.ts +2 -0
- package/dist/styles/matte/Dropzone.svelte +1 -1
- package/dist/styles/matte/FeatureCard.svelte +1 -1
- package/dist/styles/matte/Footer.svelte +6 -2
- package/dist/styles/matte/Footer.svelte.d.ts +2 -0
- package/dist/styles/matte/Input.svelte +4 -4
- package/dist/styles/matte/Link.svelte +9 -0
- package/dist/styles/matte/Link.svelte.d.ts +4 -0
- package/dist/styles/matte/MenuItem.svelte +3 -2
- package/dist/styles/matte/Modal.svelte +8 -3
- package/dist/styles/matte/Modal.svelte.d.ts +2 -0
- package/dist/styles/matte/MultiSelect.svelte +7 -1
- package/dist/styles/matte/MultiSelect.svelte.d.ts +3 -0
- package/dist/styles/matte/Navbar.svelte +18 -4
- package/dist/styles/matte/Navbar.svelte.d.ts +2 -0
- package/dist/styles/matte/PricingCard.svelte +19 -11
- package/dist/styles/matte/PricingCard.svelte.d.ts +2 -0
- package/dist/styles/matte/RadioGroup.svelte +6 -0
- package/dist/styles/matte/RadioGroup.svelte.d.ts +2 -0
- package/dist/styles/matte/SegmentedControl.svelte +17 -3
- package/dist/styles/matte/SegmentedControl.svelte.d.ts +5 -0
- package/dist/styles/matte/Select.svelte +1 -1
- package/dist/styles/matte/Sidebar.svelte +76 -26
- package/dist/styles/matte/Sidebar.svelte.d.ts +15 -1
- package/dist/styles/matte/Stat.svelte +8 -1
- package/dist/styles/matte/Stat.svelte.d.ts +3 -0
- package/dist/styles/matte/StatsBand.svelte +1 -1
- package/dist/styles/matte/Steps.svelte +7 -0
- package/dist/styles/matte/Steps.svelte.d.ts +3 -0
- package/dist/styles/matte/Table.svelte +154 -98
- package/dist/styles/matte/Table.svelte.d.ts +12 -0
- package/dist/styles/matte/Tabs.svelte +5 -0
- package/dist/styles/matte/Tabs.svelte.d.ts +3 -0
- package/dist/styles/matte/Testimonial.svelte +2 -2
- package/dist/styles/matte/Textarea.svelte +1 -1
- package/dist/styles/matte/Toaster.svelte +3 -0
- package/dist/styles/matte/icon.d.ts +21 -0
- package/dist/styles/matte/icon.js +21 -0
- package/dist/styles/matte/index.d.ts +1 -3
- package/dist/styles/matte/index.js +0 -2
- package/dist/styles/paper/AccordionItem.svelte +5 -0
- package/dist/styles/paper/AccordionItem.svelte.d.ts +2 -0
- package/dist/styles/paper/Avatar.svelte +15 -0
- package/dist/styles/paper/Avatar.svelte.d.ts +3 -0
- package/dist/styles/paper/Badge.svelte +5 -0
- package/dist/styles/paper/Badge.svelte.d.ts +2 -0
- package/dist/styles/paper/Breadcrumb.svelte +8 -4
- package/dist/styles/paper/Breadcrumb.svelte.d.ts +3 -0
- package/dist/styles/paper/Button.svelte +58 -7
- package/dist/styles/paper/Button.svelte.d.ts +14 -2
- package/dist/styles/paper/Card.svelte +6 -1
- package/dist/styles/paper/Card.svelte.d.ts +2 -0
- package/dist/styles/paper/CheckboxGroup.svelte +6 -0
- package/dist/styles/paper/CheckboxGroup.svelte.d.ts +2 -0
- package/dist/styles/paper/Combobox.svelte +5 -0
- package/dist/styles/paper/Combobox.svelte.d.ts +3 -0
- package/dist/styles/paper/CommandPalette.svelte +31 -2
- package/dist/styles/paper/CommandPalette.svelte.d.ts +8 -0
- package/dist/styles/paper/Drawer.svelte +5 -0
- package/dist/styles/paper/Drawer.svelte.d.ts +2 -0
- package/dist/styles/paper/Footer.svelte +6 -2
- package/dist/styles/paper/Footer.svelte.d.ts +2 -0
- package/dist/styles/paper/Link.svelte +9 -0
- package/dist/styles/paper/Link.svelte.d.ts +4 -0
- package/dist/styles/paper/MenuItem.svelte +2 -1
- package/dist/styles/paper/Modal.svelte +14 -1
- package/dist/styles/paper/Modal.svelte.d.ts +2 -0
- package/dist/styles/paper/MultiSelect.svelte +7 -1
- package/dist/styles/paper/MultiSelect.svelte.d.ts +3 -0
- package/dist/styles/paper/Navbar.svelte +18 -4
- package/dist/styles/paper/Navbar.svelte.d.ts +2 -0
- package/dist/styles/paper/PricingCard.svelte +23 -15
- package/dist/styles/paper/PricingCard.svelte.d.ts +2 -0
- package/dist/styles/paper/RadioGroup.svelte +6 -0
- package/dist/styles/paper/RadioGroup.svelte.d.ts +2 -0
- package/dist/styles/paper/SegmentedControl.svelte +16 -2
- package/dist/styles/paper/SegmentedControl.svelte.d.ts +5 -0
- package/dist/styles/paper/Sidebar.svelte +76 -26
- package/dist/styles/paper/Sidebar.svelte.d.ts +15 -1
- package/dist/styles/paper/Stat.svelte +8 -1
- package/dist/styles/paper/Stat.svelte.d.ts +3 -0
- package/dist/styles/paper/Steps.svelte +7 -0
- package/dist/styles/paper/Steps.svelte.d.ts +3 -0
- package/dist/styles/paper/Table.svelte +153 -97
- package/dist/styles/paper/Table.svelte.d.ts +12 -0
- package/dist/styles/paper/Tabs.svelte +5 -0
- package/dist/styles/paper/Tabs.svelte.d.ts +3 -0
- package/dist/styles/paper/Toaster.svelte +3 -0
- package/dist/styles/paper/fonts.css +34 -7
- package/dist/styles/paper/icon.d.ts +21 -0
- package/dist/styles/paper/icon.js +21 -0
- package/dist/styles/paper/index.d.ts +1 -3
- package/dist/styles/paper/index.js +0 -2
- package/dist/styles/paper/theme.css +11 -8
- package/dist/styles/sprout/AccordionItem.svelte +5 -0
- package/dist/styles/sprout/AccordionItem.svelte.d.ts +2 -0
- package/dist/styles/sprout/Avatar.svelte +15 -0
- package/dist/styles/sprout/Avatar.svelte.d.ts +3 -0
- package/dist/styles/sprout/Badge.svelte +5 -0
- package/dist/styles/sprout/Badge.svelte.d.ts +2 -0
- package/dist/styles/sprout/Breadcrumb.svelte +8 -4
- package/dist/styles/sprout/Breadcrumb.svelte.d.ts +3 -0
- package/dist/styles/sprout/Button.svelte +58 -7
- package/dist/styles/sprout/Button.svelte.d.ts +14 -2
- package/dist/styles/sprout/Card.svelte +6 -1
- package/dist/styles/sprout/Card.svelte.d.ts +2 -0
- package/dist/styles/sprout/CheckboxGroup.svelte +6 -0
- package/dist/styles/sprout/CheckboxGroup.svelte.d.ts +2 -0
- package/dist/styles/sprout/Combobox.svelte +5 -0
- package/dist/styles/sprout/Combobox.svelte.d.ts +3 -0
- package/dist/styles/sprout/CommandPalette.svelte +31 -2
- package/dist/styles/sprout/CommandPalette.svelte.d.ts +8 -0
- package/dist/styles/sprout/Drawer.svelte +5 -0
- package/dist/styles/sprout/Drawer.svelte.d.ts +2 -0
- package/dist/styles/sprout/Footer.svelte +6 -2
- package/dist/styles/sprout/Footer.svelte.d.ts +2 -0
- package/dist/styles/sprout/Link.svelte +9 -0
- package/dist/styles/sprout/Link.svelte.d.ts +4 -0
- package/dist/styles/sprout/MenuItem.svelte +2 -1
- package/dist/styles/sprout/Modal.svelte +14 -1
- package/dist/styles/sprout/Modal.svelte.d.ts +2 -0
- package/dist/styles/sprout/MultiSelect.svelte +7 -1
- package/dist/styles/sprout/MultiSelect.svelte.d.ts +3 -0
- package/dist/styles/sprout/Navbar.svelte +18 -4
- package/dist/styles/sprout/Navbar.svelte.d.ts +2 -0
- package/dist/styles/sprout/PricingCard.svelte +23 -15
- package/dist/styles/sprout/PricingCard.svelte.d.ts +2 -0
- package/dist/styles/sprout/RadioGroup.svelte +6 -0
- package/dist/styles/sprout/RadioGroup.svelte.d.ts +2 -0
- package/dist/styles/sprout/SegmentedControl.svelte +16 -2
- package/dist/styles/sprout/SegmentedControl.svelte.d.ts +5 -0
- package/dist/styles/sprout/Sidebar.svelte +76 -26
- package/dist/styles/sprout/Sidebar.svelte.d.ts +15 -1
- package/dist/styles/sprout/Stat.svelte +8 -1
- package/dist/styles/sprout/Stat.svelte.d.ts +3 -0
- package/dist/styles/sprout/Steps.svelte +7 -0
- package/dist/styles/sprout/Steps.svelte.d.ts +3 -0
- package/dist/styles/sprout/Table.svelte +153 -97
- package/dist/styles/sprout/Table.svelte.d.ts +12 -0
- package/dist/styles/sprout/Tabs.svelte +5 -0
- package/dist/styles/sprout/Tabs.svelte.d.ts +3 -0
- package/dist/styles/sprout/Toaster.svelte +3 -0
- package/dist/styles/sprout/fonts.css +7 -8
- package/dist/styles/sprout/icon.d.ts +21 -0
- package/dist/styles/sprout/icon.js +21 -0
- package/dist/styles/sprout/index.d.ts +1 -3
- package/dist/styles/sprout/index.js +0 -2
- package/dist/styles/sprout/theme.css +6 -6
- package/package.json +2 -26
- package/registry.json +3 -36
- package/dist/styles/matte/NumberInput.svelte +0 -96
- package/dist/styles/matte/NumberInput.svelte.d.ts +0 -15
- package/dist/styles/matte/PasswordInput.svelte +0 -95
- package/dist/styles/matte/PasswordInput.svelte.d.ts +0 -12
- package/dist/styles/paper/NumberInput.svelte +0 -96
- package/dist/styles/paper/NumberInput.svelte.d.ts +0 -15
- package/dist/styles/paper/PasswordInput.svelte +0 -100
- package/dist/styles/paper/PasswordInput.svelte.d.ts +0 -12
- package/dist/styles/sprout/NumberInput.svelte +0 -97
- package/dist/styles/sprout/NumberInput.svelte.d.ts +0 -15
- package/dist/styles/sprout/PasswordInput.svelte +0 -101
- package/dist/styles/sprout/PasswordInput.svelte.d.ts +0 -12
|
@@ -9,6 +9,8 @@ interface Props extends HTMLAttributes<HTMLSpanElement> {
|
|
|
9
9
|
size?: BadgeSize;
|
|
10
10
|
/** Small filled circle before the label. */
|
|
11
11
|
dot?: boolean;
|
|
12
|
+
/** Leading icon, 14px — sits where the dot would. */
|
|
13
|
+
icon?: Snippet;
|
|
12
14
|
children: Snippet;
|
|
13
15
|
}
|
|
14
16
|
declare const Badge: import("svelte").Component<Props, {}, "">;
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
2
3
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
4
|
import { toneHoverText, type Tone } from '../../core/tones.js';
|
|
4
5
|
import { useLocale } from '../../core/locale.svelte.js';
|
|
6
|
+
import { iconMd } from './icon.js';
|
|
5
7
|
|
|
6
8
|
export interface BreadcrumbItem {
|
|
7
9
|
label: string;
|
|
8
10
|
href?: string;
|
|
11
|
+
/** Leading icon — a home mark on the first crumb, say. */
|
|
12
|
+
icon?: Snippet;
|
|
9
13
|
}
|
|
10
14
|
|
|
11
15
|
interface Props extends HTMLAttributes<HTMLElement> {
|
|
@@ -29,18 +33,18 @@
|
|
|
29
33
|
{#if item.href && i < items.length - 1}
|
|
30
34
|
<a
|
|
31
35
|
href={item.href}
|
|
32
|
-
class="rounded px-1 py-0.5 text-text-muted transition-colors duration-150 ease-brand-out hover:bg-bg-inset {toneHoverText[
|
|
36
|
+
class="inline-flex items-center gap-1.5 rounded px-1 py-0.5 text-text-muted transition-colors duration-150 ease-brand-out hover:bg-bg-inset {toneHoverText[
|
|
33
37
|
tone
|
|
34
38
|
]}"
|
|
35
39
|
>
|
|
36
|
-
{item.label}
|
|
40
|
+
{#if item.icon}<span class={iconMd}>{@render item.icon()}</span>{/if}{item.label}
|
|
37
41
|
</a>
|
|
38
42
|
{:else}
|
|
39
43
|
<span
|
|
40
|
-
class="px-1 py-0.5 font-medium text-text"
|
|
44
|
+
class="inline-flex items-center gap-1.5 px-1 py-0.5 font-medium text-text"
|
|
41
45
|
aria-current={i === items.length - 1 ? 'page' : undefined}
|
|
42
46
|
>
|
|
43
|
-
{item.label}
|
|
47
|
+
{#if item.icon}<span class={iconMd}>{@render item.icon()}</span>{/if}{item.label}
|
|
44
48
|
</span>
|
|
45
49
|
{/if}
|
|
46
50
|
</li>
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
1
2
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
2
3
|
import { type Tone } from '../../core/tones.js';
|
|
3
4
|
export interface BreadcrumbItem {
|
|
4
5
|
label: string;
|
|
5
6
|
href?: string;
|
|
7
|
+
/** Leading icon — a home mark on the first crumb, say. */
|
|
8
|
+
icon?: Snippet;
|
|
6
9
|
}
|
|
7
10
|
interface Props extends HTMLAttributes<HTMLElement> {
|
|
8
11
|
items: BreadcrumbItem[];
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
3
|
import type { HTMLButtonAttributes } from 'svelte/elements';
|
|
4
4
|
import Spinner from './Spinner.svelte';
|
|
5
|
+
import { iconMd, iconSm } from './icon.js';
|
|
5
6
|
import {
|
|
6
7
|
focusRing,
|
|
7
8
|
toneBorderSoft,
|
|
@@ -18,7 +19,7 @@
|
|
|
18
19
|
export type ButtonVariant = 'solid' | 'soft' | 'outline' | 'ghost' | 'link' | 'primary';
|
|
19
20
|
export type ButtonSize = 'sm' | 'md' | 'lg' | 'xl';
|
|
20
21
|
|
|
21
|
-
interface Props extends HTMLButtonAttributes {
|
|
22
|
+
interface Props extends Omit<HTMLButtonAttributes, 'onclick'> {
|
|
22
23
|
variant?: ButtonVariant;
|
|
23
24
|
tone?: Tone;
|
|
24
25
|
size?: ButtonSize;
|
|
@@ -29,7 +30,19 @@
|
|
|
29
30
|
loading?: boolean;
|
|
30
31
|
/** Stretch to the container's full width. */
|
|
31
32
|
block?: boolean;
|
|
32
|
-
|
|
33
|
+
/** Leading icon. The spinner takes its place while the button is busy. */
|
|
34
|
+
icon?: Snippet;
|
|
35
|
+
/** Trailing icon. */
|
|
36
|
+
iconEnd?: Snippet;
|
|
37
|
+
/** Square button with no label — pass an `aria-label`. */
|
|
38
|
+
iconOnly?: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Return a promise — a save, a submit, a fetch — and the button spins and
|
|
41
|
+
* locks itself until it settles, without any state in the parent. It
|
|
42
|
+
* unlocks on a rejection too, so catch failures inside the handler.
|
|
43
|
+
*/
|
|
44
|
+
onclick?: (event: MouseEvent) => unknown;
|
|
45
|
+
children?: Snippet;
|
|
33
46
|
}
|
|
34
47
|
|
|
35
48
|
let {
|
|
@@ -39,6 +52,10 @@
|
|
|
39
52
|
href,
|
|
40
53
|
loading = false,
|
|
41
54
|
block = false,
|
|
55
|
+
icon,
|
|
56
|
+
iconEnd,
|
|
57
|
+
iconOnly = false,
|
|
58
|
+
onclick,
|
|
42
59
|
disabled = false,
|
|
43
60
|
type = 'button',
|
|
44
61
|
class: className = '',
|
|
@@ -62,6 +79,13 @@
|
|
|
62
79
|
xl: 'h-14 px-8 text-base'
|
|
63
80
|
};
|
|
64
81
|
|
|
82
|
+
const squares: Record<ButtonSize, string> = {
|
|
83
|
+
sm: 'size-9',
|
|
84
|
+
md: 'size-11',
|
|
85
|
+
lg: 'size-12',
|
|
86
|
+
xl: 'size-14'
|
|
87
|
+
};
|
|
88
|
+
|
|
65
89
|
const variantClass = $derived.by(() => {
|
|
66
90
|
switch (variant) {
|
|
67
91
|
case 'primary':
|
|
@@ -83,7 +107,24 @@
|
|
|
83
107
|
});
|
|
84
108
|
|
|
85
109
|
const isLink = $derived(variant === 'link');
|
|
86
|
-
|
|
110
|
+
|
|
111
|
+
/** Set by an `onclick` that returned a promise, on top of the `loading` prop. */
|
|
112
|
+
let pending = $state(false);
|
|
113
|
+
const busy = $derived(loading || pending);
|
|
114
|
+
const inert = $derived(disabled || busy);
|
|
115
|
+
|
|
116
|
+
const iconClass = $derived(size === 'sm' ? iconSm : iconMd);
|
|
117
|
+
|
|
118
|
+
async function handleClick(event: MouseEvent) {
|
|
119
|
+
const result = onclick?.(event);
|
|
120
|
+
// Anything else is a plain handler: nothing to wait for, nothing to lock.
|
|
121
|
+
if (!(result instanceof Promise)) return;
|
|
122
|
+
pending = true;
|
|
123
|
+
// The handler owns its own errors — catch them there to show a message.
|
|
124
|
+
// All the button needs to know is that the work has settled.
|
|
125
|
+
await result.catch(() => {});
|
|
126
|
+
pending = false;
|
|
127
|
+
}
|
|
87
128
|
</script>
|
|
88
129
|
|
|
89
130
|
<svelte:element
|
|
@@ -92,14 +133,24 @@
|
|
|
92
133
|
type={href ? undefined : type}
|
|
93
134
|
disabled={href ? undefined : inert}
|
|
94
135
|
aria-disabled={href && inert ? 'true' : undefined}
|
|
95
|
-
aria-busy={
|
|
136
|
+
aria-busy={busy ? 'true' : undefined}
|
|
96
137
|
role={href ? 'button' : undefined}
|
|
97
|
-
class="{base} {focusRing} {toneRing[tone]} {variantClass} {isLink
|
|
138
|
+
class="{base} {focusRing} {toneRing[tone]} {variantClass} {isLink
|
|
139
|
+
? ''
|
|
140
|
+
: iconOnly
|
|
141
|
+
? squares[size]
|
|
142
|
+
: sizes[size]}
|
|
98
143
|
{block ? 'w-full' : ''} {className}"
|
|
99
144
|
{...rest}
|
|
145
|
+
onclick={handleClick}
|
|
100
146
|
>
|
|
101
|
-
{#if
|
|
147
|
+
{#if busy}
|
|
102
148
|
<Spinner size={size === 'sm' ? 'xs' : 'sm'} label="" />
|
|
149
|
+
{:else if icon}
|
|
150
|
+
<span class={iconClass} aria-hidden="true">{@render icon()}</span>
|
|
151
|
+
{/if}
|
|
152
|
+
{@render children?.()}
|
|
153
|
+
{#if iconEnd && !iconOnly}
|
|
154
|
+
<span class={iconClass} aria-hidden="true">{@render iconEnd()}</span>
|
|
103
155
|
{/if}
|
|
104
|
-
{@render children()}
|
|
105
156
|
</svelte:element>
|
|
@@ -3,7 +3,7 @@ import type { HTMLButtonAttributes } from 'svelte/elements';
|
|
|
3
3
|
import { type Tone } from '../../core/tones.js';
|
|
4
4
|
export type ButtonVariant = 'solid' | 'soft' | 'outline' | 'ghost' | 'link' | 'primary';
|
|
5
5
|
export type ButtonSize = 'sm' | 'md' | 'lg' | 'xl';
|
|
6
|
-
interface Props extends HTMLButtonAttributes {
|
|
6
|
+
interface Props extends Omit<HTMLButtonAttributes, 'onclick'> {
|
|
7
7
|
variant?: ButtonVariant;
|
|
8
8
|
tone?: Tone;
|
|
9
9
|
size?: ButtonSize;
|
|
@@ -14,7 +14,19 @@ interface Props extends HTMLButtonAttributes {
|
|
|
14
14
|
loading?: boolean;
|
|
15
15
|
/** Stretch to the container's full width. */
|
|
16
16
|
block?: boolean;
|
|
17
|
-
|
|
17
|
+
/** Leading icon. The spinner takes its place while the button is busy. */
|
|
18
|
+
icon?: Snippet;
|
|
19
|
+
/** Trailing icon. */
|
|
20
|
+
iconEnd?: Snippet;
|
|
21
|
+
/** Square button with no label — pass an `aria-label`. */
|
|
22
|
+
iconOnly?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Return a promise — a save, a submit, a fetch — and the button spins and
|
|
25
|
+
* locks itself until it settles, without any state in the parent. It
|
|
26
|
+
* unlocks on a rejection too, so catch failures inside the handler.
|
|
27
|
+
*/
|
|
28
|
+
onclick?: (event: MouseEvent) => unknown;
|
|
29
|
+
children?: Snippet;
|
|
18
30
|
}
|
|
19
31
|
declare const Button: import("svelte").Component<Props, {}, "">;
|
|
20
32
|
type Button = ReturnType<typeof Button>;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
3
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
4
4
|
import { toneBorderLeft, toneHoverBorder, toneSurface, type Tone } from '../../core/tones.js';
|
|
5
|
+
import { iconLg } from './icon.js';
|
|
5
6
|
import { soft, softOnHover } from './lift.js';
|
|
6
7
|
|
|
7
8
|
export type CardVariant = 'outline' | 'filled' | 'tinted';
|
|
@@ -16,6 +17,8 @@
|
|
|
16
17
|
padded?: boolean;
|
|
17
18
|
title?: string;
|
|
18
19
|
eyebrow?: string;
|
|
20
|
+
/** Leading icon above the title. Ignored when you pass `header`. */
|
|
21
|
+
icon?: Snippet;
|
|
19
22
|
header?: Snippet;
|
|
20
23
|
footer?: Snippet;
|
|
21
24
|
children: Snippet;
|
|
@@ -29,6 +32,7 @@
|
|
|
29
32
|
padded = true,
|
|
30
33
|
title,
|
|
31
34
|
eyebrow,
|
|
35
|
+
icon,
|
|
32
36
|
header,
|
|
33
37
|
footer,
|
|
34
38
|
class: className = '',
|
|
@@ -55,11 +59,12 @@
|
|
|
55
59
|
{className}"
|
|
56
60
|
{...rest}
|
|
57
61
|
>
|
|
58
|
-
{#if header || title || eyebrow}
|
|
62
|
+
{#if header || title || eyebrow || icon}
|
|
59
63
|
<div class="flex flex-col gap-1 {padded ? 'px-6 pt-6' : ''}">
|
|
60
64
|
{#if header}
|
|
61
65
|
{@render header()}
|
|
62
66
|
{:else}
|
|
67
|
+
{#if icon}<span class={iconLg}>{@render icon()}</span>{/if}
|
|
63
68
|
{#if eyebrow}
|
|
64
69
|
<span class="font-sans text-xs font-semibold text-text-muted">{eyebrow}</span>
|
|
65
70
|
{/if}
|
|
@@ -12,6 +12,8 @@ interface Props extends HTMLAttributes<HTMLDivElement> {
|
|
|
12
12
|
padded?: boolean;
|
|
13
13
|
title?: string;
|
|
14
14
|
eyebrow?: string;
|
|
15
|
+
/** Leading icon above the title. Ignored when you pass `header`. */
|
|
16
|
+
icon?: Snippet;
|
|
15
17
|
header?: Snippet;
|
|
16
18
|
footer?: Snippet;
|
|
17
19
|
children: Snippet;
|
|
@@ -3,11 +3,14 @@
|
|
|
3
3
|
import type { HTMLFieldsetAttributes } from 'svelte/elements';
|
|
4
4
|
import Checkbox from './Checkbox.svelte';
|
|
5
5
|
import { toneBorder, toneSurface, type Tone } from '../../core/tones.js';
|
|
6
|
+
import { iconLg } from './icon.js';
|
|
6
7
|
import { edge } from './lift.js';
|
|
7
8
|
|
|
8
9
|
export interface CheckboxOption {
|
|
9
10
|
value: string;
|
|
10
11
|
label: string;
|
|
12
|
+
/** Leading icon, 20px. Drawn in `boxed` mode only. */
|
|
13
|
+
icon?: Snippet;
|
|
11
14
|
description?: string;
|
|
12
15
|
disabled?: boolean;
|
|
13
16
|
}
|
|
@@ -79,6 +82,9 @@
|
|
|
79
82
|
: 'border-hairline bg-bg hover:border-hairline-strong'}
|
|
80
83
|
{disabled ? 'pointer-events-none opacity-50' : ''}"
|
|
81
84
|
>
|
|
85
|
+
{#if option.icon}
|
|
86
|
+
<span class={iconLg}>{@render option.icon()}</span>
|
|
87
|
+
{/if}
|
|
82
88
|
<Checkbox
|
|
83
89
|
{checked}
|
|
84
90
|
{disabled}
|
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
2
3
|
import { anchored } from '../../core/actions/anchor.js';
|
|
3
4
|
import { clickOutside, portal } from '../../core/actions/dismissable.js';
|
|
4
5
|
import { ListCursor, groupItems, matchQuery, revealIndex } from '../../core/list.svelte.js';
|
|
5
6
|
import { toneFocusWithinBorder, toneSoft, toneText, type Tone } from '../../core/tones.js';
|
|
6
7
|
import { useLocale } from '../../core/locale.svelte.js';
|
|
8
|
+
import { iconMd } from './icon.js';
|
|
7
9
|
import { edge, soft } from './lift.js';
|
|
8
10
|
|
|
9
11
|
export interface ComboboxOption {
|
|
10
12
|
value: string;
|
|
11
13
|
label: string;
|
|
14
|
+
/** Leading icon, 16px. */
|
|
15
|
+
icon?: Snippet;
|
|
12
16
|
/** Second line under the label. */
|
|
13
17
|
description?: string;
|
|
14
18
|
disabled?: boolean;
|
|
@@ -238,6 +242,7 @@
|
|
|
238
242
|
{index === active ? toneSoft[tone] : 'text-text-secondary'}"
|
|
239
243
|
>
|
|
240
244
|
<span class="flex items-center gap-2">
|
|
245
|
+
{#if option.icon}<span class={iconMd}>{@render option.icon()}</span>{/if}
|
|
241
246
|
<span class="min-w-0 flex-1 truncate">{option.label}</span>
|
|
242
247
|
{#if option.value === value}
|
|
243
248
|
<svg
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
1
2
|
import { type Tone } from '../../core/tones.js';
|
|
2
3
|
export interface ComboboxOption {
|
|
3
4
|
value: string;
|
|
4
5
|
label: string;
|
|
6
|
+
/** Leading icon, 16px. */
|
|
7
|
+
icon?: Snippet;
|
|
5
8
|
/** Second line under the label. */
|
|
6
9
|
description?: string;
|
|
7
10
|
disabled?: boolean;
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
<script module lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
|
|
2
4
|
export interface CommandItem {
|
|
3
5
|
id: string;
|
|
4
6
|
label: string;
|
|
7
|
+
/** Leading icon, 16px. */
|
|
8
|
+
icon?: Snippet;
|
|
5
9
|
/** Second line under the label. */
|
|
6
10
|
description?: string;
|
|
7
11
|
/** Items sharing a group are rendered under one heading. */
|
|
@@ -21,6 +25,8 @@
|
|
|
21
25
|
import { ListCursor, groupItems, matchQuery, revealIndex } from '../../core/list.svelte.js';
|
|
22
26
|
import { useLocale } from '../../core/locale.svelte.js';
|
|
23
27
|
import { toneSoft, type Tone } from '../../core/tones.js';
|
|
28
|
+
import { isTypingTarget } from '../../core/trigger.js';
|
|
29
|
+
import { iconMd } from './icon.js';
|
|
24
30
|
import Kbd from './Kbd.svelte';
|
|
25
31
|
import { float } from './lift.js';
|
|
26
32
|
|
|
@@ -35,6 +41,11 @@
|
|
|
35
41
|
* Pass `null` to wire your own trigger only.
|
|
36
42
|
*/
|
|
37
43
|
hotkey?: string | null;
|
|
44
|
+
/**
|
|
45
|
+
* Key that opens the palette on its own, pressed anywhere the reader
|
|
46
|
+
* isn't typing. Default `'/'`. Pass `null` to turn it off.
|
|
47
|
+
*/
|
|
48
|
+
quickKey?: string | null;
|
|
38
49
|
onselect?: (item: CommandItem) => void;
|
|
39
50
|
class?: string;
|
|
40
51
|
}
|
|
@@ -46,6 +57,7 @@
|
|
|
46
57
|
emptyText,
|
|
47
58
|
tone = 'brand',
|
|
48
59
|
hotkey = 'k',
|
|
60
|
+
quickKey = '/',
|
|
49
61
|
onselect,
|
|
50
62
|
class: className = ''
|
|
51
63
|
}: Props = $props();
|
|
@@ -83,11 +95,27 @@
|
|
|
83
95
|
});
|
|
84
96
|
|
|
85
97
|
$effect(() => {
|
|
86
|
-
if (!hotkey) return;
|
|
98
|
+
if (!hotkey && !quickKey) return;
|
|
87
99
|
const onKeydown = (event: KeyboardEvent) => {
|
|
88
|
-
|
|
100
|
+
const key = event.key.toLowerCase();
|
|
101
|
+
|
|
102
|
+
if ((event.metaKey || event.ctrlKey) && key === hotkey?.toLowerCase()) {
|
|
89
103
|
event.preventDefault();
|
|
90
104
|
open = !open;
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// A bare key can only open the palette, never close it: while it is
|
|
109
|
+
// open the keystroke belongs to the query field.
|
|
110
|
+
if (
|
|
111
|
+
key === quickKey?.toLowerCase() &&
|
|
112
|
+
!event.metaKey &&
|
|
113
|
+
!event.ctrlKey &&
|
|
114
|
+
!event.altKey &&
|
|
115
|
+
!isTypingTarget(event.target)
|
|
116
|
+
) {
|
|
117
|
+
event.preventDefault();
|
|
118
|
+
open = true;
|
|
91
119
|
}
|
|
92
120
|
};
|
|
93
121
|
window.addEventListener('keydown', onKeydown);
|
|
@@ -192,6 +220,7 @@
|
|
|
192
220
|
{item.disabled ? 'pointer-events-none opacity-40' : ''}
|
|
193
221
|
{index === active ? toneSoft[tone] : 'text-text-secondary'}"
|
|
194
222
|
>
|
|
223
|
+
{#if item.icon}<span class={iconMd}>{@render item.icon()}</span>{/if}
|
|
195
224
|
<span class="flex min-w-0 flex-1 flex-col gap-0.5">
|
|
196
225
|
<span class="truncate">{item.label}</span>
|
|
197
226
|
{#if item.description}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
1
2
|
export interface CommandItem {
|
|
2
3
|
id: string;
|
|
3
4
|
label: string;
|
|
5
|
+
/** Leading icon, 16px. */
|
|
6
|
+
icon?: Snippet;
|
|
4
7
|
/** Second line under the label. */
|
|
5
8
|
description?: string;
|
|
6
9
|
/** Items sharing a group are rendered under one heading. */
|
|
@@ -24,6 +27,11 @@ interface Props {
|
|
|
24
27
|
* Pass `null` to wire your own trigger only.
|
|
25
28
|
*/
|
|
26
29
|
hotkey?: string | null;
|
|
30
|
+
/**
|
|
31
|
+
* Key that opens the palette on its own, pressed anywhere the reader
|
|
32
|
+
* isn't typing. Default `'/'`. Pass `null` to turn it off.
|
|
33
|
+
*/
|
|
34
|
+
quickKey?: string | null;
|
|
27
35
|
onselect?: (item: CommandItem) => void;
|
|
28
36
|
class?: string;
|
|
29
37
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
|
+
import { iconLg } from './icon.js';
|
|
3
4
|
import type { HTMLDialogAttributes } from 'svelte/elements';
|
|
4
5
|
import { useLocale } from '../../core/locale.svelte.js';
|
|
5
6
|
import { isBackdropClick, syncDialog } from '../../core/dialog.svelte.js';
|
|
@@ -16,6 +17,8 @@
|
|
|
16
17
|
size?: DrawerSize;
|
|
17
18
|
title?: string;
|
|
18
19
|
description?: string;
|
|
20
|
+
/** Leading icon beside the title. */
|
|
21
|
+
icon?: Snippet;
|
|
19
22
|
dismissible?: boolean;
|
|
20
23
|
footer?: Snippet;
|
|
21
24
|
onclose?: () => void;
|
|
@@ -28,6 +31,7 @@
|
|
|
28
31
|
size = 'md',
|
|
29
32
|
title,
|
|
30
33
|
description,
|
|
34
|
+
icon,
|
|
31
35
|
dismissible = true,
|
|
32
36
|
footer,
|
|
33
37
|
onclose,
|
|
@@ -93,6 +97,7 @@
|
|
|
93
97
|
<div class="flex h-full flex-col">
|
|
94
98
|
{#if title || dismissible}
|
|
95
99
|
<div class="flex items-start gap-4 border-b border-hairline px-5 py-4">
|
|
100
|
+
{#if icon}<span class={iconLg}>{@render icon()}</span>{/if}
|
|
96
101
|
<div class="flex min-w-0 flex-1 flex-col gap-1">
|
|
97
102
|
{#if title}
|
|
98
103
|
<h2 class="font-heading text-base font-semibold text-text">{title}</h2>
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
export interface FooterLink {
|
|
3
3
|
label: string;
|
|
4
4
|
href?: string;
|
|
5
|
+
/** Leading icon, 14px. */
|
|
6
|
+
icon?: Snippet;
|
|
5
7
|
external?: boolean;
|
|
6
8
|
}
|
|
7
9
|
|
|
@@ -14,6 +16,7 @@
|
|
|
14
16
|
<script lang="ts">
|
|
15
17
|
import type { Snippet } from 'svelte';
|
|
16
18
|
import { toneHoverText, type Tone } from '../../core/tones.js';
|
|
19
|
+
import { iconSm } from './icon.js';
|
|
17
20
|
|
|
18
21
|
interface Props {
|
|
19
22
|
columns?: FooterColumn[];
|
|
@@ -57,11 +60,12 @@
|
|
|
57
60
|
href={item.href}
|
|
58
61
|
target={item.external ? '_blank' : undefined}
|
|
59
62
|
rel={item.external ? 'noreferrer' : undefined}
|
|
60
|
-
class="font-sans text-[13px] text-text-muted transition-colors duration-150 ease-brand-out {toneHoverText[
|
|
63
|
+
class="inline-flex items-center gap-2 font-sans text-[13px] text-text-muted transition-colors duration-150 ease-brand-out {toneHoverText[
|
|
61
64
|
tone
|
|
62
65
|
]}"
|
|
63
66
|
>
|
|
64
|
-
{item.
|
|
67
|
+
{#if item.icon}<span class={iconSm}>{@render item.icon()}</span
|
|
68
|
+
>{/if}{item.label}
|
|
65
69
|
{#if item.external}<span aria-hidden="true" class="text-[0.85em]">↗</span
|
|
66
70
|
>{/if}
|
|
67
71
|
</a>
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
3
|
import type { HTMLAnchorAttributes } from 'svelte/elements';
|
|
4
4
|
import { focusRing, toneHoverText, toneRing, toneText, type Tone } from '../../core/tones.js';
|
|
5
|
+
import { iconSm } from './icon.js';
|
|
5
6
|
|
|
6
7
|
interface Props extends HTMLAnchorAttributes {
|
|
7
8
|
tone?: Tone;
|
|
@@ -11,6 +12,10 @@
|
|
|
11
12
|
external?: boolean;
|
|
12
13
|
/** Inherit the surrounding text colour instead of the tone. */
|
|
13
14
|
muted?: boolean;
|
|
15
|
+
/** Leading icon, 14px. */
|
|
16
|
+
icon?: Snippet;
|
|
17
|
+
/** Trailing icon, before the external mark. */
|
|
18
|
+
iconEnd?: Snippet;
|
|
14
19
|
children: Snippet;
|
|
15
20
|
}
|
|
16
21
|
|
|
@@ -19,6 +24,8 @@
|
|
|
19
24
|
underline = 'hover',
|
|
20
25
|
external = false,
|
|
21
26
|
muted = false,
|
|
27
|
+
icon,
|
|
28
|
+
iconEnd,
|
|
22
29
|
class: className = '',
|
|
23
30
|
children,
|
|
24
31
|
...rest
|
|
@@ -39,6 +46,8 @@
|
|
|
39
46
|
{underlines[underline]} {focusRing} {toneRing[tone]} {className}"
|
|
40
47
|
{...rest}
|
|
41
48
|
>
|
|
49
|
+
{#if icon}<span class={iconSm}>{@render icon()}</span>{/if}
|
|
42
50
|
{@render children()}
|
|
51
|
+
{#if iconEnd}<span class={iconSm}>{@render iconEnd()}</span>{/if}
|
|
43
52
|
{#if external}<span aria-hidden="true" class="text-[0.85em]">↗</span>{/if}
|
|
44
53
|
</a>
|
|
@@ -9,6 +9,10 @@ interface Props extends HTMLAnchorAttributes {
|
|
|
9
9
|
external?: boolean;
|
|
10
10
|
/** Inherit the surrounding text colour instead of the tone. */
|
|
11
11
|
muted?: boolean;
|
|
12
|
+
/** Leading icon, 14px. */
|
|
13
|
+
icon?: Snippet;
|
|
14
|
+
/** Trailing icon, before the external mark. */
|
|
15
|
+
iconEnd?: Snippet;
|
|
12
16
|
children: Snippet;
|
|
13
17
|
}
|
|
14
18
|
declare const Link: import("svelte").Component<Props, {}, "">;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
3
|
import type { HTMLButtonAttributes } from 'svelte/elements';
|
|
4
4
|
import { toneSoftHover, toneText, type Tone } from '../../core/tones.js';
|
|
5
|
+
import { iconMd } from './icon.js';
|
|
5
6
|
|
|
6
7
|
interface Props extends HTMLButtonAttributes {
|
|
7
8
|
/** Renders an `<a>` instead of a `<button>`. */
|
|
@@ -55,7 +56,7 @@
|
|
|
55
56
|
/>
|
|
56
57
|
</svg>
|
|
57
58
|
{:else if icon}
|
|
58
|
-
<span class=
|
|
59
|
+
<span class={iconMd}>{@render icon()}</span>
|
|
59
60
|
{/if}
|
|
60
61
|
<span class="min-w-0 flex-1 truncate">{@render children()}</span>
|
|
61
62
|
{#if shortcut}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
|
+
import { iconLg } from './icon.js';
|
|
3
4
|
import type { HTMLDialogAttributes } from 'svelte/elements';
|
|
4
5
|
import { useLocale } from '../../core/locale.svelte.js';
|
|
5
6
|
import { isBackdropClick, syncDialog } from '../../core/dialog.svelte.js';
|
|
@@ -12,6 +13,8 @@
|
|
|
12
13
|
open?: boolean;
|
|
13
14
|
title?: string;
|
|
14
15
|
description?: string;
|
|
16
|
+
/** Leading icon beside the title. */
|
|
17
|
+
icon?: Snippet;
|
|
15
18
|
size?: ModalSize;
|
|
16
19
|
/** Clicking the backdrop or pressing Escape closes the dialog. */
|
|
17
20
|
dismissible?: boolean;
|
|
@@ -27,6 +30,7 @@
|
|
|
27
30
|
open = $bindable(false),
|
|
28
31
|
title,
|
|
29
32
|
description,
|
|
33
|
+
icon,
|
|
30
34
|
size = 'md',
|
|
31
35
|
dismissible = true,
|
|
32
36
|
showClose,
|
|
@@ -76,6 +80,7 @@
|
|
|
76
80
|
<div class="flex flex-col">
|
|
77
81
|
{#if title || closable}
|
|
78
82
|
<div class="flex items-start gap-4 px-6 pt-5 pb-3">
|
|
83
|
+
{#if icon}<span class={iconLg}>{@render icon()}</span>{/if}
|
|
79
84
|
<div class="flex min-w-0 flex-1 flex-col gap-1">
|
|
80
85
|
{#if title}
|
|
81
86
|
<h2 class="font-heading text-base font-semibold text-text">{title}</h2>
|
|
@@ -104,7 +109,15 @@
|
|
|
104
109
|
</div>
|
|
105
110
|
{/if}
|
|
106
111
|
|
|
107
|
-
|
|
112
|
+
<!--
|
|
113
|
+
The body's top padding depends on what sits above it: 8px is the right
|
|
114
|
+
gap under a header, and far too tight when there is none — a titleless
|
|
115
|
+
modal, ConfirmDialog among them, would otherwise start against the edge.
|
|
116
|
+
-->
|
|
117
|
+
<div
|
|
118
|
+
class="px-6 pb-5 font-sans text-sm leading-relaxed text-text-secondary
|
|
119
|
+
{title || closable ? 'pt-2' : 'pt-5'}"
|
|
120
|
+
>
|
|
108
121
|
{@render children()}
|
|
109
122
|
</div>
|
|
110
123
|
|
|
@@ -6,6 +6,8 @@ interface Props extends HTMLDialogAttributes {
|
|
|
6
6
|
open?: boolean;
|
|
7
7
|
title?: string;
|
|
8
8
|
description?: string;
|
|
9
|
+
/** Leading icon beside the title. */
|
|
10
|
+
icon?: Snippet;
|
|
9
11
|
size?: ModalSize;
|
|
10
12
|
/** Clicking the backdrop or pressing Escape closes the dialog. */
|
|
11
13
|
dismissible?: boolean;
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
<script module lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
|
|
2
4
|
export interface MultiSelectOption {
|
|
3
5
|
value: string;
|
|
4
6
|
label: string;
|
|
7
|
+
/** Leading icon, 16px. */
|
|
8
|
+
icon?: Snippet;
|
|
5
9
|
description?: string;
|
|
6
10
|
disabled?: boolean;
|
|
7
11
|
group?: string;
|
|
@@ -13,6 +17,7 @@
|
|
|
13
17
|
import { clickOutside, portal } from '../../core/actions/dismissable.js';
|
|
14
18
|
import { ListCursor, groupItems, matchQuery, revealIndex } from '../../core/list.svelte.js';
|
|
15
19
|
import { useLocale } from '../../core/locale.svelte.js';
|
|
20
|
+
import { iconMd, iconSm } from './icon.js';
|
|
16
21
|
import { toneFocusWithinBorder, toneSoft, toneText, type Tone } from '../../core/tones.js';
|
|
17
22
|
import { edge, soft } from './lift.js';
|
|
18
23
|
|
|
@@ -154,7 +159,7 @@
|
|
|
154
159
|
tone
|
|
155
160
|
]}"
|
|
156
161
|
>
|
|
157
|
-
{option.label}
|
|
162
|
+
{#if option.icon}<span class={iconSm}>{@render option.icon()}</span>{/if}{option.label}
|
|
158
163
|
<button
|
|
159
164
|
type="button"
|
|
160
165
|
onclick={() => remove(option)}
|
|
@@ -274,6 +279,7 @@
|
|
|
274
279
|
</svg>
|
|
275
280
|
{/if}
|
|
276
281
|
</span>
|
|
282
|
+
{#if option.icon}<span class={iconMd}>{@render option.icon()}</span>{/if}
|
|
277
283
|
<span class="flex min-w-0 flex-1 flex-col gap-0.5">
|
|
278
284
|
<span class="truncate">{option.label}</span>
|
|
279
285
|
{#if option.description}
|