@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
|
@@ -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
|
|
|
6
7
|
export type CardVariant = 'outline' | 'filled' | 'tinted';
|
|
7
8
|
|
|
@@ -15,6 +16,8 @@
|
|
|
15
16
|
padded?: boolean;
|
|
16
17
|
title?: string;
|
|
17
18
|
eyebrow?: string;
|
|
19
|
+
/** Leading icon above the title. Ignored when you pass `header`. */
|
|
20
|
+
icon?: Snippet;
|
|
18
21
|
header?: Snippet;
|
|
19
22
|
footer?: Snippet;
|
|
20
23
|
children: Snippet;
|
|
@@ -28,6 +31,7 @@
|
|
|
28
31
|
padded = true,
|
|
29
32
|
title,
|
|
30
33
|
eyebrow,
|
|
34
|
+
icon,
|
|
31
35
|
header,
|
|
32
36
|
footer,
|
|
33
37
|
class: className = '',
|
|
@@ -49,11 +53,12 @@
|
|
|
49
53
|
{className}"
|
|
50
54
|
{...rest}
|
|
51
55
|
>
|
|
52
|
-
{#if header || title || eyebrow}
|
|
53
|
-
<div class="flex flex-col gap-1 {padded ? 'px-
|
|
56
|
+
{#if header || title || eyebrow || icon}
|
|
57
|
+
<div class="flex flex-col gap-1 {padded ? 'px-5 pt-5' : ''}">
|
|
54
58
|
{#if header}
|
|
55
59
|
{@render header()}
|
|
56
60
|
{:else}
|
|
61
|
+
{#if icon}<span class={iconLg}>{@render icon()}</span>{/if}
|
|
57
62
|
{#if eyebrow}
|
|
58
63
|
<span class="font-mono text-xs tracking-wide text-text-muted uppercase">{eyebrow}</span>
|
|
59
64
|
{/if}
|
|
@@ -64,12 +69,12 @@
|
|
|
64
69
|
</div>
|
|
65
70
|
{/if}
|
|
66
71
|
|
|
67
|
-
<div class="flex-1 {padded ? (header || title || eyebrow ? 'px-
|
|
72
|
+
<div class="flex-1 {padded ? (header || title || eyebrow ? 'px-5 pt-3.5 pb-5' : 'p-5') : ''}">
|
|
68
73
|
{@render children()}
|
|
69
74
|
</div>
|
|
70
75
|
|
|
71
76
|
{#if footer}
|
|
72
|
-
<div class="border-t border-hairline {padded ? 'px-
|
|
77
|
+
<div class="border-t border-hairline {padded ? 'px-5 py-3.5' : ''}">
|
|
73
78
|
{@render footer()}
|
|
74
79
|
</div>
|
|
75
80
|
{/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,10 +3,13 @@
|
|
|
3
3
|
import type { HTMLFieldsetAttributes } from 'svelte/elements';
|
|
4
4
|
import Checkbox from './Checkbox.svelte';
|
|
5
5
|
import type { Tone } from '../../core/tones.js';
|
|
6
|
+
import { iconLg } from './icon.js';
|
|
6
7
|
|
|
7
8
|
export interface CheckboxOption {
|
|
8
9
|
value: string;
|
|
9
10
|
label: string;
|
|
11
|
+
/** Leading icon, 20px. Drawn in `boxed` mode only. */
|
|
12
|
+
icon?: Snippet;
|
|
10
13
|
description?: string;
|
|
11
14
|
disabled?: boolean;
|
|
12
15
|
}
|
|
@@ -76,6 +79,9 @@
|
|
|
76
79
|
{checked ? 'border-text bg-bg-alt' : 'border-hairline hover:border-hairline-strong'}
|
|
77
80
|
{disabled ? 'pointer-events-none opacity-50' : ''}"
|
|
78
81
|
>
|
|
82
|
+
{#if option.icon}
|
|
83
|
+
<span class={iconLg}>{@render option.icon()}</span>
|
|
84
|
+
{/if}
|
|
79
85
|
<Checkbox
|
|
80
86
|
{checked}
|
|
81
87
|
{disabled}
|
|
@@ -1,13 +1,17 @@
|
|
|
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
|
|
|
8
10
|
export interface ComboboxOption {
|
|
9
11
|
value: string;
|
|
10
12
|
label: string;
|
|
13
|
+
/** Leading icon, 16px. */
|
|
14
|
+
icon?: Snippet;
|
|
11
15
|
/** Second line under the label. */
|
|
12
16
|
description?: string;
|
|
13
17
|
disabled?: boolean;
|
|
@@ -142,7 +146,7 @@
|
|
|
142
146
|
|
|
143
147
|
<div
|
|
144
148
|
bind:this={wrapper}
|
|
145
|
-
class="relative inline-flex w-full items-center gap-2 border bg-bg pr-2 pl-
|
|
149
|
+
class="relative inline-flex w-full items-center gap-2 border bg-bg pr-2 pl-3.5 transition-colors duration-150 ease-brand-out
|
|
146
150
|
{invalid ? 'border-danger' : `border-hairline ${toneFocusWithinBorder[tone]}`}
|
|
147
151
|
{disabled ? 'pointer-events-none opacity-50' : ''} {className}"
|
|
148
152
|
>
|
|
@@ -166,7 +170,7 @@
|
|
|
166
170
|
}}
|
|
167
171
|
onfocus={openList}
|
|
168
172
|
onkeydown={onKeydown}
|
|
169
|
-
class="h-
|
|
173
|
+
class="h-10 w-full min-w-0 bg-transparent font-sans text-[15px] text-text placeholder:text-text-muted focus:outline-none"
|
|
170
174
|
/>
|
|
171
175
|
|
|
172
176
|
{#if name}<input type="hidden" {name} {value} />{/if}
|
|
@@ -234,6 +238,7 @@
|
|
|
234
238
|
{index === active ? toneSoft[tone] : 'text-text-secondary'}"
|
|
235
239
|
>
|
|
236
240
|
<span class="flex items-center gap-2">
|
|
241
|
+
{#if option.icon}<span class={iconMd}>{@render option.icon()}</span>{/if}
|
|
237
242
|
<span class="min-w-0 flex-1 truncate">{option.label}</span>
|
|
238
243
|
{#if option.value === value}
|
|
239
244
|
<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
|
|
|
26
32
|
interface Props {
|
|
@@ -34,6 +40,11 @@
|
|
|
34
40
|
* Pass `null` to wire your own trigger only.
|
|
35
41
|
*/
|
|
36
42
|
hotkey?: string | null;
|
|
43
|
+
/**
|
|
44
|
+
* Key that opens the palette on its own, pressed anywhere the reader
|
|
45
|
+
* isn't typing. Default `'/'`. Pass `null` to turn it off.
|
|
46
|
+
*/
|
|
47
|
+
quickKey?: string | null;
|
|
37
48
|
onselect?: (item: CommandItem) => void;
|
|
38
49
|
class?: string;
|
|
39
50
|
}
|
|
@@ -45,6 +56,7 @@
|
|
|
45
56
|
emptyText,
|
|
46
57
|
tone = 'brand',
|
|
47
58
|
hotkey = 'k',
|
|
59
|
+
quickKey = '/',
|
|
48
60
|
onselect,
|
|
49
61
|
class: className = ''
|
|
50
62
|
}: Props = $props();
|
|
@@ -82,11 +94,27 @@
|
|
|
82
94
|
});
|
|
83
95
|
|
|
84
96
|
$effect(() => {
|
|
85
|
-
if (!hotkey) return;
|
|
97
|
+
if (!hotkey && !quickKey) return;
|
|
86
98
|
const onKeydown = (event: KeyboardEvent) => {
|
|
87
|
-
|
|
99
|
+
const key = event.key.toLowerCase();
|
|
100
|
+
|
|
101
|
+
if ((event.metaKey || event.ctrlKey) && key === hotkey?.toLowerCase()) {
|
|
88
102
|
event.preventDefault();
|
|
89
103
|
open = !open;
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// A bare key can only open the palette, never close it: while it is
|
|
108
|
+
// open the keystroke belongs to the query field.
|
|
109
|
+
if (
|
|
110
|
+
key === quickKey?.toLowerCase() &&
|
|
111
|
+
!event.metaKey &&
|
|
112
|
+
!event.ctrlKey &&
|
|
113
|
+
!event.altKey &&
|
|
114
|
+
!isTypingTarget(event.target)
|
|
115
|
+
) {
|
|
116
|
+
event.preventDefault();
|
|
117
|
+
open = true;
|
|
90
118
|
}
|
|
91
119
|
};
|
|
92
120
|
window.addEventListener('keydown', onKeydown);
|
|
@@ -138,7 +166,7 @@
|
|
|
138
166
|
class="mx-auto mt-[12vh] mb-auto w-[min(36rem,calc(100vw-2rem))] max-w-none border border-hairline bg-bg p-0 text-text backdrop:bg-text/40 {className}"
|
|
139
167
|
>
|
|
140
168
|
<div use:focusTrap={{ autofocus: false }} onkeydown={onKeydown} role="none" class="flex flex-col">
|
|
141
|
-
<div class="flex items-center gap-3 border-b border-hairline px-
|
|
169
|
+
<div class="flex items-center gap-3 border-b border-hairline px-3.5">
|
|
142
170
|
<svg
|
|
143
171
|
class="size-4 shrink-0 text-text-muted"
|
|
144
172
|
viewBox="0 0 16 16"
|
|
@@ -156,7 +184,7 @@
|
|
|
156
184
|
autocomplete="off"
|
|
157
185
|
aria-label={placeholder ?? t.current.commandPlaceholder}
|
|
158
186
|
placeholder={placeholder ?? t.current.commandPlaceholder}
|
|
159
|
-
class="h-
|
|
187
|
+
class="h-11 w-full min-w-0 bg-transparent font-sans text-[15px] text-text placeholder:text-text-muted focus:outline-none"
|
|
160
188
|
/>
|
|
161
189
|
<Kbd>esc</Kbd>
|
|
162
190
|
</div>
|
|
@@ -168,13 +196,15 @@
|
|
|
168
196
|
class="max-h-80 overflow-y-auto py-1"
|
|
169
197
|
>
|
|
170
198
|
{#if flat.length === 0}
|
|
171
|
-
<p class="px-
|
|
199
|
+
<p class="px-3.5 py-10 text-center font-sans text-sm text-text-muted">
|
|
172
200
|
{emptyText ?? t.current.noResults}
|
|
173
201
|
</p>
|
|
174
202
|
{:else}
|
|
175
203
|
{#each groups as [group, groupItems] (group)}
|
|
176
204
|
{#if group}
|
|
177
|
-
<p
|
|
205
|
+
<p
|
|
206
|
+
class="px-3.5 pt-3 pb-1 font-mono text-[10px] tracking-wide text-text-muted uppercase"
|
|
207
|
+
>
|
|
178
208
|
{group}
|
|
179
209
|
</p>
|
|
180
210
|
{/if}
|
|
@@ -189,10 +219,11 @@
|
|
|
189
219
|
aria-disabled={item.disabled}
|
|
190
220
|
onclick={() => run(item)}
|
|
191
221
|
onpointermove={() => (cursor.index = index)}
|
|
192
|
-
class="flex cursor-pointer items-center gap-3 px-
|
|
222
|
+
class="flex cursor-pointer items-center gap-3 px-3.5 py-2 font-sans text-[14px] transition-colors duration-100
|
|
193
223
|
{item.disabled ? 'pointer-events-none opacity-40' : ''}
|
|
194
224
|
{index === active ? toneSoft[tone] : 'text-text-secondary'}"
|
|
195
225
|
>
|
|
226
|
+
{#if item.icon}<span class={iconMd}>{@render item.icon()}</span>{/if}
|
|
196
227
|
<span class="flex min-w-0 flex-1 flex-col gap-0.5">
|
|
197
228
|
<span class="truncate">{item.label}</span>
|
|
198
229
|
{#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
|
}
|
|
@@ -94,7 +94,7 @@
|
|
|
94
94
|
|
|
95
95
|
<div
|
|
96
96
|
bind:this={wrapper}
|
|
97
|
-
class="inline-flex w-full items-center gap-1 border bg-bg pr-1 pl-
|
|
97
|
+
class="inline-flex w-full items-center gap-1 border bg-bg pr-1 pl-3.5 transition-colors duration-150 ease-brand-out
|
|
98
98
|
{invalid ? 'border-danger' : `border-hairline ${toneFocusWithinBorder[tone]}`}
|
|
99
99
|
{disabled ? 'pointer-events-none opacity-50' : ''} {className}"
|
|
100
100
|
>
|
|
@@ -118,7 +118,7 @@
|
|
|
118
118
|
}}
|
|
119
119
|
onblur={commit}
|
|
120
120
|
onkeydown={onKeydown}
|
|
121
|
-
class="h-
|
|
121
|
+
class="h-10 w-full min-w-0 bg-transparent font-sans text-[15px] text-text tabular-nums placeholder:text-text-muted focus:outline-none"
|
|
122
122
|
/>
|
|
123
123
|
|
|
124
124
|
{#if name}<input type="hidden" {name} {value} />{/if}
|
|
@@ -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';
|
|
@@ -15,6 +16,8 @@
|
|
|
15
16
|
size?: DrawerSize;
|
|
16
17
|
title?: string;
|
|
17
18
|
description?: string;
|
|
19
|
+
/** Leading icon beside the title. */
|
|
20
|
+
icon?: Snippet;
|
|
18
21
|
dismissible?: boolean;
|
|
19
22
|
footer?: Snippet;
|
|
20
23
|
onclose?: () => void;
|
|
@@ -27,6 +30,7 @@
|
|
|
27
30
|
size = 'md',
|
|
28
31
|
title,
|
|
29
32
|
description,
|
|
33
|
+
icon,
|
|
30
34
|
dismissible = true,
|
|
31
35
|
footer,
|
|
32
36
|
onclose,
|
|
@@ -91,7 +95,8 @@
|
|
|
91
95
|
>
|
|
92
96
|
<div class="flex h-full flex-col">
|
|
93
97
|
{#if title || dismissible}
|
|
94
|
-
<div class="flex items-start gap-4 border-b border-hairline px-
|
|
98
|
+
<div class="flex items-start gap-4 border-b border-hairline px-5 py-4">
|
|
99
|
+
{#if icon}<span class={iconLg}>{@render icon()}</span>{/if}
|
|
95
100
|
<div class="flex min-w-0 flex-1 flex-col gap-1">
|
|
96
101
|
{#if title}
|
|
97
102
|
<h2 class="font-heading text-lg font-medium tracking-tight">{title}</h2>
|
|
@@ -116,7 +121,7 @@
|
|
|
116
121
|
{/if}
|
|
117
122
|
|
|
118
123
|
<div
|
|
119
|
-
class="flex-1 overflow-y-auto px-
|
|
124
|
+
class="flex-1 overflow-y-auto px-5 py-4 font-sans text-[15px] leading-relaxed text-text-secondary"
|
|
120
125
|
>
|
|
121
126
|
{@render children()}
|
|
122
127
|
</div>
|
|
@@ -173,7 +173,7 @@
|
|
|
173
173
|
<ul class="flex flex-col border border-hairline">
|
|
174
174
|
{#each files as file, i (file.name + file.size + i)}
|
|
175
175
|
<li
|
|
176
|
-
class="flex items-center gap-3 border-b border-hairline px-
|
|
176
|
+
class="flex items-center gap-3 border-b border-hairline px-3.5 py-2.5 font-sans last:border-b-0"
|
|
177
177
|
>
|
|
178
178
|
<span class="min-w-0 flex-1 truncate text-sm text-text">{file.name}</span>
|
|
179
179
|
<span class="shrink-0 font-mono text-xs text-text-muted">{formatSize(file.size)}</span>
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
<svelte:element
|
|
30
30
|
this={href ? 'a' : 'div'}
|
|
31
31
|
{href}
|
|
32
|
-
class="group flex flex-col gap-3 bg-bg p-
|
|
32
|
+
class="group flex flex-col gap-3 bg-bg p-5 {href
|
|
33
33
|
? `transition-colors duration-150 ease-brand-out ${focusRing} ${toneRing[tone]}`
|
|
34
34
|
: ''} {className}"
|
|
35
35
|
{...rest}
|
|
@@ -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[];
|
|
@@ -59,11 +62,12 @@
|
|
|
59
62
|
href={item.href}
|
|
60
63
|
target={item.external ? '_blank' : undefined}
|
|
61
64
|
rel={item.external ? 'noreferrer' : undefined}
|
|
62
|
-
class="font-sans text-sm text-text-secondary transition-colors duration-150 ease-brand-out {toneHoverText[
|
|
65
|
+
class="inline-flex items-center gap-2 font-sans text-sm text-text-secondary transition-colors duration-150 ease-brand-out {toneHoverText[
|
|
63
66
|
tone
|
|
64
67
|
]}"
|
|
65
68
|
>
|
|
66
|
-
{item.
|
|
69
|
+
{#if item.icon}<span class={iconSm}>{@render item.icon()}</span
|
|
70
|
+
>{/if}{item.label}
|
|
67
71
|
{#if item.external}<span aria-hidden="true" class="text-[0.85em]">↗</span
|
|
68
72
|
>{/if}
|
|
69
73
|
</a>
|
|
@@ -30,14 +30,14 @@
|
|
|
30
30
|
}: Props = $props();
|
|
31
31
|
|
|
32
32
|
const sizes: Record<InputSize, string> = {
|
|
33
|
-
sm: 'h-
|
|
34
|
-
md: 'h-
|
|
35
|
-
lg: 'h-
|
|
33
|
+
sm: 'h-8 text-[13px]',
|
|
34
|
+
md: 'h-10 text-[15px]',
|
|
35
|
+
lg: 'h-11 text-base'
|
|
36
36
|
};
|
|
37
37
|
</script>
|
|
38
38
|
|
|
39
39
|
<span
|
|
40
|
-
class="inline-flex w-full items-center gap-2 border bg-bg px-
|
|
40
|
+
class="inline-flex w-full items-center gap-2 border bg-bg px-3.5 transition-colors duration-150 ease-brand-out
|
|
41
41
|
{sizes[size]}
|
|
42
42
|
{invalid
|
|
43
43
|
? 'border-danger focus-within:border-danger'
|
|
@@ -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>`. */
|
|
@@ -37,7 +38,7 @@
|
|
|
37
38
|
disabled={href ? undefined : disabled}
|
|
38
39
|
aria-disabled={disabled ? 'true' : undefined}
|
|
39
40
|
tabindex={disabled ? undefined : -1}
|
|
40
|
-
class="flex w-full items-center gap-2.5 px-3 py-
|
|
41
|
+
class="flex w-full items-center gap-2.5 px-3 py-1.5 text-left text-[14px] transition-colors duration-100 ease-brand-out focus:outline-none disabled:pointer-events-none disabled:opacity-40
|
|
41
42
|
{tone === 'neutral'
|
|
42
43
|
? 'text-text-secondary hover:bg-bg-inset focus-visible:bg-bg-inset'
|
|
43
44
|
: `${toneText[tone]} ${toneSoftHover[tone]}`}
|
|
@@ -49,7 +50,7 @@
|
|
|
49
50
|
<path d="m2 7 3.2 3.2L12 3.6" stroke="currentColor" stroke-width="1.6" />
|
|
50
51
|
</svg>
|
|
51
52
|
{:else if icon}
|
|
52
|
-
<span class=
|
|
53
|
+
<span class={iconMd}>{@render icon()}</span>
|
|
53
54
|
{/if}
|
|
54
55
|
<span class="min-w-0 flex-1 truncate">{@render children()}</span>
|
|
55
56
|
{#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';
|
|
@@ -11,6 +12,8 @@
|
|
|
11
12
|
open?: boolean;
|
|
12
13
|
title?: string;
|
|
13
14
|
description?: string;
|
|
15
|
+
/** Leading icon beside the title. */
|
|
16
|
+
icon?: Snippet;
|
|
14
17
|
size?: ModalSize;
|
|
15
18
|
/** Clicking the backdrop or pressing Escape closes the dialog. */
|
|
16
19
|
dismissible?: boolean;
|
|
@@ -26,6 +29,7 @@
|
|
|
26
29
|
open = $bindable(false),
|
|
27
30
|
title,
|
|
28
31
|
description,
|
|
32
|
+
icon,
|
|
29
33
|
size = 'md',
|
|
30
34
|
dismissible = true,
|
|
31
35
|
showClose,
|
|
@@ -74,7 +78,8 @@
|
|
|
74
78
|
>
|
|
75
79
|
<div class="flex flex-col">
|
|
76
80
|
{#if title || closable}
|
|
77
|
-
<div class="flex items-start gap-4 border-b border-hairline px-
|
|
81
|
+
<div class="flex items-start gap-4 border-b border-hairline px-5 py-4">
|
|
82
|
+
{#if icon}<span class={iconLg}>{@render icon()}</span>{/if}
|
|
78
83
|
<div class="flex min-w-0 flex-1 flex-col gap-1">
|
|
79
84
|
{#if title}
|
|
80
85
|
<h2 class="font-heading text-lg font-medium tracking-tight">{title}</h2>
|
|
@@ -98,12 +103,12 @@
|
|
|
98
103
|
</div>
|
|
99
104
|
{/if}
|
|
100
105
|
|
|
101
|
-
<div class="px-
|
|
106
|
+
<div class="px-5 py-4 font-sans text-[15px] leading-relaxed text-text-secondary">
|
|
102
107
|
{@render children()}
|
|
103
108
|
</div>
|
|
104
109
|
|
|
105
110
|
{#if footer}
|
|
106
|
-
<div class="flex items-center justify-end gap-3 border-t border-hairline px-
|
|
111
|
+
<div class="flex items-center justify-end gap-3 border-t border-hairline px-5 py-3.5">
|
|
107
112
|
{@render footer()}
|
|
108
113
|
</div>
|
|
109
114
|
{/if}
|
|
@@ -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
|
|
|
18
23
|
interface Props {
|
|
@@ -153,7 +158,7 @@
|
|
|
153
158
|
tone
|
|
154
159
|
]}"
|
|
155
160
|
>
|
|
156
|
-
{option.label}
|
|
161
|
+
{#if option.icon}<span class={iconSm}>{@render option.icon()}</span>{/if}{option.label}
|
|
157
162
|
<button
|
|
158
163
|
type="button"
|
|
159
164
|
onclick={() => remove(option)}
|
|
@@ -259,6 +264,7 @@
|
|
|
259
264
|
</svg>
|
|
260
265
|
{/if}
|
|
261
266
|
</span>
|
|
267
|
+
{#if option.icon}<span class={iconMd}>{@render option.icon()}</span>{/if}
|
|
262
268
|
<span class="flex min-w-0 flex-1 flex-col gap-0.5">
|
|
263
269
|
<span class="truncate">{option.label}</span>
|
|
264
270
|
{#if option.description}
|