@nqmcreative/ui 0.2.3 → 0.4.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 +209 -15
- package/cli/index.mjs +328 -112
- package/dist/core/color.d.ts +24 -0
- package/dist/core/color.js +39 -0
- package/dist/core/index.d.ts +8 -1
- package/dist/core/index.js +5 -1
- package/dist/core/locale.svelte.d.ts +8 -0
- package/dist/core/locale.svelte.js +14 -0
- package/dist/core/number.d.ts +22 -0
- package/dist/core/number.js +33 -0
- package/dist/core/pin.d.ts +23 -0
- package/dist/core/pin.js +38 -0
- package/dist/core/tags.d.ts +37 -0
- package/dist/core/tags.js +51 -0
- package/dist/core/time.d.ts +30 -0
- package/dist/core/time.js +78 -0
- package/dist/core/toast.svelte.d.ts +3 -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 +58 -7
- package/dist/styles/matte/Button.svelte.d.ts +14 -2
- package/dist/styles/matte/Card.svelte +6 -1
- 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/ColorInput.svelte +110 -0
- package/dist/styles/matte/ColorInput.svelte.d.ts +16 -0
- package/dist/styles/matte/Combobox.svelte +5 -0
- package/dist/styles/matte/Combobox.svelte.d.ts +3 -0
- package/dist/styles/matte/CommandPalette.svelte +6 -0
- package/dist/styles/matte/CommandPalette.svelte.d.ts +3 -0
- package/dist/styles/matte/CurrencyInput.svelte +108 -0
- package/dist/styles/matte/CurrencyInput.svelte.d.ts +26 -0
- package/dist/styles/matte/Drawer.svelte +5 -0
- package/dist/styles/matte/Drawer.svelte.d.ts +2 -0
- package/dist/styles/matte/FileInput.svelte +194 -0
- package/dist/styles/matte/FileInput.svelte.d.ts +32 -0
- package/dist/styles/matte/Footer.svelte +6 -2
- package/dist/styles/matte/Footer.svelte.d.ts +2 -0
- package/dist/styles/matte/InputAddon.svelte +36 -0
- package/dist/styles/matte/InputAddon.svelte.d.ts +13 -0
- package/dist/styles/matte/Link.svelte +9 -0
- package/dist/styles/matte/Link.svelte.d.ts +4 -0
- package/dist/styles/matte/MenuItem.svelte +2 -1
- package/dist/styles/matte/Modal.svelte +5 -0
- 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/PinInput.svelte +137 -0
- package/dist/styles/matte/PinInput.svelte.d.ts +25 -0
- package/dist/styles/matte/PricingCard.svelte +16 -8
- 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/SearchInput.svelte +87 -0
- package/dist/styles/matte/SearchInput.svelte.d.ts +24 -0
- package/dist/styles/matte/SegmentedControl.svelte +16 -2
- package/dist/styles/matte/SegmentedControl.svelte.d.ts +5 -0
- package/dist/styles/matte/Sidebar.svelte +2 -1
- package/dist/styles/matte/Stat.svelte +8 -1
- package/dist/styles/matte/Stat.svelte.d.ts +3 -0
- package/dist/styles/matte/Steps.svelte +7 -0
- package/dist/styles/matte/Steps.svelte.d.ts +3 -0
- package/dist/styles/matte/Table.svelte +153 -97
- 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/TagsInput.svelte +173 -0
- package/dist/styles/matte/TagsInput.svelte.d.ts +29 -0
- package/dist/styles/matte/TimeInput.svelte +129 -0
- package/dist/styles/matte/TimeInput.svelte.d.ts +21 -0
- 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 +8 -2
- package/dist/styles/matte/index.js +8 -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/ColorInput.svelte +112 -0
- package/dist/styles/paper/ColorInput.svelte.d.ts +16 -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 +6 -0
- package/dist/styles/paper/CommandPalette.svelte.d.ts +3 -0
- package/dist/styles/paper/CurrencyInput.svelte +108 -0
- package/dist/styles/paper/CurrencyInput.svelte.d.ts +26 -0
- package/dist/styles/paper/Drawer.svelte +5 -0
- package/dist/styles/paper/Drawer.svelte.d.ts +2 -0
- package/dist/styles/paper/FileInput.svelte +204 -0
- package/dist/styles/paper/FileInput.svelte.d.ts +32 -0
- package/dist/styles/paper/Footer.svelte +6 -2
- package/dist/styles/paper/Footer.svelte.d.ts +2 -0
- package/dist/styles/paper/InputAddon.svelte +36 -0
- package/dist/styles/paper/InputAddon.svelte.d.ts +13 -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 +5 -0
- 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/PinInput.svelte +137 -0
- package/dist/styles/paper/PinInput.svelte.d.ts +25 -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/SearchInput.svelte +92 -0
- package/dist/styles/paper/SearchInput.svelte.d.ts +24 -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 +2 -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/TagsInput.svelte +178 -0
- package/dist/styles/paper/TagsInput.svelte.d.ts +29 -0
- package/dist/styles/paper/TimeInput.svelte +155 -0
- package/dist/styles/paper/TimeInput.svelte.d.ts +21 -0
- package/dist/styles/paper/Toaster.svelte +3 -0
- package/dist/styles/paper/icon.d.ts +21 -0
- package/dist/styles/paper/icon.js +21 -0
- package/dist/styles/paper/index.d.ts +8 -2
- package/dist/styles/paper/index.js +8 -2
- 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/ColorInput.svelte +112 -0
- package/dist/styles/sprout/ColorInput.svelte.d.ts +16 -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 +6 -0
- package/dist/styles/sprout/CommandPalette.svelte.d.ts +3 -0
- package/dist/styles/sprout/CurrencyInput.svelte +108 -0
- package/dist/styles/sprout/CurrencyInput.svelte.d.ts +26 -0
- package/dist/styles/sprout/Drawer.svelte +5 -0
- package/dist/styles/sprout/Drawer.svelte.d.ts +2 -0
- package/dist/styles/sprout/FileInput.svelte +205 -0
- package/dist/styles/sprout/FileInput.svelte.d.ts +32 -0
- package/dist/styles/sprout/Footer.svelte +6 -2
- package/dist/styles/sprout/Footer.svelte.d.ts +2 -0
- package/dist/styles/sprout/InputAddon.svelte +37 -0
- package/dist/styles/sprout/InputAddon.svelte.d.ts +13 -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 +5 -0
- 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/PinInput.svelte +138 -0
- package/dist/styles/sprout/PinInput.svelte.d.ts +25 -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/SearchInput.svelte +92 -0
- package/dist/styles/sprout/SearchInput.svelte.d.ts +24 -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 +2 -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/TagsInput.svelte +179 -0
- package/dist/styles/sprout/TagsInput.svelte.d.ts +29 -0
- package/dist/styles/sprout/TimeInput.svelte +155 -0
- package/dist/styles/sprout/TimeInput.svelte.d.ts +21 -0
- package/dist/styles/sprout/Toaster.svelte +3 -0
- package/dist/styles/sprout/icon.d.ts +21 -0
- package/dist/styles/sprout/icon.js +21 -0
- package/dist/styles/sprout/index.d.ts +8 -2
- package/dist/styles/sprout/index.js +8 -2
- package/package.json +98 -26
- package/registry.json +143 -35
- 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
|
@@ -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}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { HTMLInputAttributes } from 'svelte/elements';
|
|
3
|
+
import { normaliseHex } from '../../core/color.js';
|
|
4
|
+
import { useLocale } from '../../core/locale.svelte.js';
|
|
5
|
+
import type { Tone } from '../../core/tones.js';
|
|
6
|
+
import Input, { type InputSize } from './Input.svelte';
|
|
7
|
+
|
|
8
|
+
interface Props extends Omit<HTMLInputAttributes, 'size' | 'prefix' | 'suffix' | 'type'> {
|
|
9
|
+
/** Bindable `#rrggbb`. Shorthand and alpha are normalised away on blur. */
|
|
10
|
+
value?: string;
|
|
11
|
+
size?: InputSize;
|
|
12
|
+
tone?: Tone;
|
|
13
|
+
invalid?: boolean;
|
|
14
|
+
/** Fixed choices under the field. Empty hides the row. */
|
|
15
|
+
swatches?: string[];
|
|
16
|
+
class?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
let {
|
|
20
|
+
value = $bindable('#000000'),
|
|
21
|
+
size = 'md',
|
|
22
|
+
tone = 'brand',
|
|
23
|
+
invalid = false,
|
|
24
|
+
disabled = false,
|
|
25
|
+
swatches = [],
|
|
26
|
+
class: className = '',
|
|
27
|
+
...rest
|
|
28
|
+
}: Props = $props();
|
|
29
|
+
|
|
30
|
+
const t = useLocale();
|
|
31
|
+
|
|
32
|
+
// The text can be mid-typing (`#a2`) while the swatch needs a real colour,
|
|
33
|
+
// so the swatch follows the last value that parsed rather than the field.
|
|
34
|
+
let text = $state('');
|
|
35
|
+
let editing = $state(false);
|
|
36
|
+
|
|
37
|
+
$effect(() => {
|
|
38
|
+
if (!editing) text = value;
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const resolved = $derived(normaliseHex(text) ?? normaliseHex(value) ?? '#000000');
|
|
42
|
+
|
|
43
|
+
// Same reason as CurrencyInput: at input time the bound `text` is one
|
|
44
|
+
// keystroke behind, so the element is the only current source.
|
|
45
|
+
function onText(event: Event & { currentTarget: HTMLInputElement }) {
|
|
46
|
+
const hex = normaliseHex(event.currentTarget.value);
|
|
47
|
+
if (hex) value = hex;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function settle() {
|
|
51
|
+
editing = false;
|
|
52
|
+
value = normaliseHex(text) ?? value;
|
|
53
|
+
text = value;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function choose(hex: string) {
|
|
57
|
+
value = normaliseHex(hex) ?? value;
|
|
58
|
+
text = value;
|
|
59
|
+
}
|
|
60
|
+
</script>
|
|
61
|
+
|
|
62
|
+
<div class="flex w-full flex-col gap-2 {className}">
|
|
63
|
+
<Input
|
|
64
|
+
bind:value={text}
|
|
65
|
+
{size}
|
|
66
|
+
{tone}
|
|
67
|
+
{invalid}
|
|
68
|
+
{disabled}
|
|
69
|
+
spellcheck="false"
|
|
70
|
+
autocapitalize="none"
|
|
71
|
+
placeholder="#000000"
|
|
72
|
+
oninput={onText}
|
|
73
|
+
onfocus={() => (editing = true)}
|
|
74
|
+
onblur={settle}
|
|
75
|
+
class="[&_input]:uppercase [&_input]:tabular-nums"
|
|
76
|
+
{...rest}
|
|
77
|
+
>
|
|
78
|
+
{#snippet prefix()}
|
|
79
|
+
<span
|
|
80
|
+
class="relative grid size-5 place-items-center overflow-hidden rounded border border-hairline-strong"
|
|
81
|
+
>
|
|
82
|
+
<span class="absolute inset-0" style="background-color: {resolved}"></span>
|
|
83
|
+
<input
|
|
84
|
+
type="color"
|
|
85
|
+
value={resolved}
|
|
86
|
+
{disabled}
|
|
87
|
+
aria-label={t.current.pickColour}
|
|
88
|
+
oninput={(event) => choose(event.currentTarget.value)}
|
|
89
|
+
class="absolute inset-0 cursor-pointer opacity-0 disabled:cursor-not-allowed"
|
|
90
|
+
/>
|
|
91
|
+
</span>
|
|
92
|
+
{/snippet}
|
|
93
|
+
</Input>
|
|
94
|
+
|
|
95
|
+
{#if swatches.length}
|
|
96
|
+
<div class="flex flex-wrap gap-1.5">
|
|
97
|
+
{#each swatches as swatch (swatch)}
|
|
98
|
+
<button
|
|
99
|
+
type="button"
|
|
100
|
+
{disabled}
|
|
101
|
+
onclick={() => choose(swatch)}
|
|
102
|
+
title={swatch}
|
|
103
|
+
aria-label={swatch}
|
|
104
|
+
aria-pressed={resolved === normaliseHex(swatch)}
|
|
105
|
+
class="size-6 rounded-lg border transition-transform duration-150 hover:-translate-y-0.5 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-current disabled:pointer-events-none disabled:opacity-50
|
|
106
|
+
{resolved === normaliseHex(swatch) ? 'border-text' : 'border-hairline-strong'}"
|
|
107
|
+
style="background-color: {swatch}"
|
|
108
|
+
></button>
|
|
109
|
+
{/each}
|
|
110
|
+
</div>
|
|
111
|
+
{/if}
|
|
112
|
+
</div>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { HTMLInputAttributes } from 'svelte/elements';
|
|
2
|
+
import type { Tone } from '../../core/tones.js';
|
|
3
|
+
import { type InputSize } from './Input.svelte';
|
|
4
|
+
interface Props extends Omit<HTMLInputAttributes, 'size' | 'prefix' | 'suffix' | 'type'> {
|
|
5
|
+
/** Bindable `#rrggbb`. Shorthand and alpha are normalised away on blur. */
|
|
6
|
+
value?: string;
|
|
7
|
+
size?: InputSize;
|
|
8
|
+
tone?: Tone;
|
|
9
|
+
invalid?: boolean;
|
|
10
|
+
/** Fixed choices under the field. Empty hides the row. */
|
|
11
|
+
swatches?: string[];
|
|
12
|
+
class?: string;
|
|
13
|
+
}
|
|
14
|
+
declare const ColorInput: import("svelte").Component<Props, {}, "value">;
|
|
15
|
+
type ColorInput = ReturnType<typeof ColorInput>;
|
|
16
|
+
export default ColorInput;
|
|
@@ -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. */
|
|
@@ -22,6 +26,7 @@
|
|
|
22
26
|
import { useLocale } from '../../core/locale.svelte.js';
|
|
23
27
|
import { toneSoft, type Tone } from '../../core/tones.js';
|
|
24
28
|
import { isTypingTarget } from '../../core/trigger.js';
|
|
29
|
+
import { iconMd } from './icon.js';
|
|
25
30
|
import Kbd from './Kbd.svelte';
|
|
26
31
|
import { float } from './lift.js';
|
|
27
32
|
|
|
@@ -215,6 +220,7 @@
|
|
|
215
220
|
{item.disabled ? 'pointer-events-none opacity-40' : ''}
|
|
216
221
|
{index === active ? toneSoft[tone] : 'text-text-secondary'}"
|
|
217
222
|
>
|
|
223
|
+
{#if item.icon}<span class={iconMd}>{@render item.icon()}</span>{/if}
|
|
218
224
|
<span class="flex min-w-0 flex-1 flex-col gap-0.5">
|
|
219
225
|
<span class="truncate">{item.label}</span>
|
|
220
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. */
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { HTMLInputAttributes } from 'svelte/elements';
|
|
3
|
+
import { formatGrouped, parseGrouped } from '../../core/number.js';
|
|
4
|
+
import type { Tone } from '../../core/tones.js';
|
|
5
|
+
import Input, { type InputSize } from './Input.svelte';
|
|
6
|
+
|
|
7
|
+
interface Props extends Omit<
|
|
8
|
+
HTMLInputAttributes,
|
|
9
|
+
'size' | 'prefix' | 'suffix' | 'value' | 'min' | 'max'
|
|
10
|
+
> {
|
|
11
|
+
/** Bindable amount. `null` is an empty field, which is not the same as 0. */
|
|
12
|
+
value?: number | null;
|
|
13
|
+
min?: number;
|
|
14
|
+
max?: number;
|
|
15
|
+
/** Thousands separator. */
|
|
16
|
+
group?: string;
|
|
17
|
+
/** Decimal separator. */
|
|
18
|
+
decimal?: string;
|
|
19
|
+
/** Decimal places the amount settles to when the field loses focus. */
|
|
20
|
+
precision?: number;
|
|
21
|
+
/** Leading mark — `Rp`, `$`, `€`. */
|
|
22
|
+
currency?: string;
|
|
23
|
+
/** Trailing mark instead, for the locales that write it that way. */
|
|
24
|
+
unit?: string;
|
|
25
|
+
size?: InputSize;
|
|
26
|
+
tone?: Tone;
|
|
27
|
+
invalid?: boolean;
|
|
28
|
+
class?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
let {
|
|
32
|
+
value = $bindable(null),
|
|
33
|
+
min,
|
|
34
|
+
max,
|
|
35
|
+
group = ',',
|
|
36
|
+
decimal = '.',
|
|
37
|
+
precision = 2,
|
|
38
|
+
currency,
|
|
39
|
+
unit,
|
|
40
|
+
size = 'md',
|
|
41
|
+
tone = 'brand',
|
|
42
|
+
invalid = false,
|
|
43
|
+
disabled = false,
|
|
44
|
+
class: className = '',
|
|
45
|
+
...rest
|
|
46
|
+
}: Props = $props();
|
|
47
|
+
|
|
48
|
+
const options = $derived({ group, decimal, precision });
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* What the field shows. Two states on purpose: grouped and padded while the
|
|
52
|
+
* caret is elsewhere, and exactly what was typed while it is not — grouping
|
|
53
|
+
* a number as it is typed moves the caret out from under the fingers.
|
|
54
|
+
*/
|
|
55
|
+
let text = $state('');
|
|
56
|
+
let editing = $state(false);
|
|
57
|
+
|
|
58
|
+
$effect(() => {
|
|
59
|
+
if (editing) return;
|
|
60
|
+
text = value === null || value === undefined ? '' : formatGrouped(value, options);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// Read off the element, not off `text`: the binding that feeds `text` has
|
|
64
|
+
// not flushed yet when this fires, so it still holds the previous keystroke.
|
|
65
|
+
function onInput(event: Event & { currentTarget: HTMLInputElement }) {
|
|
66
|
+
const parsed = parseGrouped(event.currentTarget.value, options);
|
|
67
|
+
value = parsed === null ? null : clamp(parsed);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function clamp(amount: number) {
|
|
71
|
+
if (min !== undefined && amount < min) return min;
|
|
72
|
+
if (max !== undefined && amount > max) return max;
|
|
73
|
+
return amount;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function settle() {
|
|
77
|
+
editing = false;
|
|
78
|
+
const parsed = parseGrouped(text, options);
|
|
79
|
+
value = parsed === null ? null : clamp(parsed);
|
|
80
|
+
text = value === null ? '' : formatGrouped(value, options);
|
|
81
|
+
}
|
|
82
|
+
</script>
|
|
83
|
+
|
|
84
|
+
<Input
|
|
85
|
+
bind:value={text}
|
|
86
|
+
{size}
|
|
87
|
+
{tone}
|
|
88
|
+
{invalid}
|
|
89
|
+
{disabled}
|
|
90
|
+
inputmode="decimal"
|
|
91
|
+
oninput={onInput}
|
|
92
|
+
onfocus={() => (editing = true)}
|
|
93
|
+
onblur={settle}
|
|
94
|
+
class={className}
|
|
95
|
+
{...rest}
|
|
96
|
+
>
|
|
97
|
+
{#snippet prefix()}
|
|
98
|
+
{#if currency}
|
|
99
|
+
<span class="text-xs font-medium text-text-muted">{currency}</span>
|
|
100
|
+
{/if}
|
|
101
|
+
{/snippet}
|
|
102
|
+
|
|
103
|
+
{#snippet suffix()}
|
|
104
|
+
{#if unit}
|
|
105
|
+
<span class="text-xs font-medium text-text-muted">{unit}</span>
|
|
106
|
+
{/if}
|
|
107
|
+
{/snippet}
|
|
108
|
+
</Input>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { HTMLInputAttributes } from 'svelte/elements';
|
|
2
|
+
import type { Tone } from '../../core/tones.js';
|
|
3
|
+
import { type InputSize } from './Input.svelte';
|
|
4
|
+
interface Props extends Omit<HTMLInputAttributes, 'size' | 'prefix' | 'suffix' | 'value' | 'min' | 'max'> {
|
|
5
|
+
/** Bindable amount. `null` is an empty field, which is not the same as 0. */
|
|
6
|
+
value?: number | null;
|
|
7
|
+
min?: number;
|
|
8
|
+
max?: number;
|
|
9
|
+
/** Thousands separator. */
|
|
10
|
+
group?: string;
|
|
11
|
+
/** Decimal separator. */
|
|
12
|
+
decimal?: string;
|
|
13
|
+
/** Decimal places the amount settles to when the field loses focus. */
|
|
14
|
+
precision?: number;
|
|
15
|
+
/** Leading mark — `Rp`, `$`, `€`. */
|
|
16
|
+
currency?: string;
|
|
17
|
+
/** Trailing mark instead, for the locales that write it that way. */
|
|
18
|
+
unit?: string;
|
|
19
|
+
size?: InputSize;
|
|
20
|
+
tone?: Tone;
|
|
21
|
+
invalid?: boolean;
|
|
22
|
+
class?: string;
|
|
23
|
+
}
|
|
24
|
+
declare const CurrencyInput: import("svelte").Component<Props, {}, "value">;
|
|
25
|
+
type CurrencyInput = ReturnType<typeof CurrencyInput>;
|
|
26
|
+
export default CurrencyInput;
|
|
@@ -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>
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { formatSize as toReadableSize, sortFiles, type RejectedFile } from '../../core/files.js';
|
|
3
|
+
import { useLocale } from '../../core/locale.svelte.js';
|
|
4
|
+
import { toneFocusWithinBorder, type Tone } from '../../core/tones.js';
|
|
5
|
+
import { edge } from './lift.js';
|
|
6
|
+
import type { InputSize } from './Input.svelte';
|
|
7
|
+
|
|
8
|
+
interface Props {
|
|
9
|
+
/** Bindable list of accepted files. */
|
|
10
|
+
files?: File[];
|
|
11
|
+
/** Same syntax as the input's `accept` — `'image/*,.pdf'`. */
|
|
12
|
+
accept?: string;
|
|
13
|
+
multiple?: boolean;
|
|
14
|
+
/** Per-file ceiling in bytes. `0` means no limit. */
|
|
15
|
+
maxSize?: number;
|
|
16
|
+
/** Cap on how many files may be held at once. `0` means no limit. */
|
|
17
|
+
maxFiles?: number;
|
|
18
|
+
disabled?: boolean;
|
|
19
|
+
size?: InputSize;
|
|
20
|
+
tone?: Tone;
|
|
21
|
+
invalid?: boolean;
|
|
22
|
+
/** Text on the button. Defaults to the locale's `chooseFile`. */
|
|
23
|
+
label?: string;
|
|
24
|
+
/** Shown while nothing is chosen. Defaults to the locale's `noFile`. */
|
|
25
|
+
placeholder?: string;
|
|
26
|
+
/** Show the list of held files below the row. */
|
|
27
|
+
showList?: boolean;
|
|
28
|
+
/** The `name` the hidden input posts under, for a plain form submit. */
|
|
29
|
+
name?: string;
|
|
30
|
+
onaccept?: (files: File[]) => void;
|
|
31
|
+
onreject?: (rejected: RejectedFile[]) => void;
|
|
32
|
+
class?: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
let {
|
|
36
|
+
files = $bindable([]),
|
|
37
|
+
accept,
|
|
38
|
+
multiple = false,
|
|
39
|
+
maxSize = 0,
|
|
40
|
+
maxFiles = 0,
|
|
41
|
+
disabled = false,
|
|
42
|
+
size = 'md',
|
|
43
|
+
tone = 'brand',
|
|
44
|
+
invalid = false,
|
|
45
|
+
label,
|
|
46
|
+
placeholder,
|
|
47
|
+
showList = true,
|
|
48
|
+
name,
|
|
49
|
+
onaccept,
|
|
50
|
+
onreject,
|
|
51
|
+
class: className = ''
|
|
52
|
+
}: Props = $props();
|
|
53
|
+
|
|
54
|
+
const t = useLocale();
|
|
55
|
+
|
|
56
|
+
let input: HTMLInputElement | null = $state(null);
|
|
57
|
+
let rejected = $state<RejectedFile[]>([]);
|
|
58
|
+
|
|
59
|
+
const formatSize = (bytes: number) => toReadableSize(bytes, t.current.byteUnits);
|
|
60
|
+
|
|
61
|
+
/** One file reads as its name and weight; several read as a count. */
|
|
62
|
+
const summary = $derived.by(() => {
|
|
63
|
+
if (files.length === 0) return placeholder ?? t.current.noFile;
|
|
64
|
+
if (files.length === 1) return `${files[0].name} · ${formatSize(files[0].size)}`;
|
|
65
|
+
return `${files.length} ${t.current.selected}`;
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
function add(incoming: FileList | File[] | null) {
|
|
69
|
+
if (!incoming || disabled) return;
|
|
70
|
+
|
|
71
|
+
const { accepted, rejected: bad } = sortFiles(incoming, {
|
|
72
|
+
accept,
|
|
73
|
+
maxSize,
|
|
74
|
+
maxFiles,
|
|
75
|
+
multiple,
|
|
76
|
+
held: files.length
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
rejected = bad;
|
|
80
|
+
if (bad.length) onreject?.(bad);
|
|
81
|
+
if (accepted.length === 0) return;
|
|
82
|
+
|
|
83
|
+
files = multiple ? [...files, ...accepted] : accepted.slice(0, 1);
|
|
84
|
+
onaccept?.(accepted);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function clear() {
|
|
88
|
+
files = [];
|
|
89
|
+
rejected = [];
|
|
90
|
+
if (input) input.value = '';
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const reasons: Record<RejectedFile['reason'], string> = $derived({
|
|
94
|
+
type: t.current.rejectedType,
|
|
95
|
+
size: t.current.rejectedSize,
|
|
96
|
+
count: t.current.rejectedCount
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const sizes: Record<InputSize, string> = {
|
|
100
|
+
sm: 'h-8 text-[13px]',
|
|
101
|
+
md: 'h-10 text-sm',
|
|
102
|
+
lg: 'h-11 text-[15px]'
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const buttons: Record<InputSize, string> = {
|
|
106
|
+
sm: 'h-6 px-2 text-[11px]',
|
|
107
|
+
md: 'h-7 px-2.5 text-xs',
|
|
108
|
+
lg: 'h-8 px-3 text-xs'
|
|
109
|
+
};
|
|
110
|
+
</script>
|
|
111
|
+
|
|
112
|
+
<div class="flex w-full flex-col gap-3 {className}">
|
|
113
|
+
<span
|
|
114
|
+
class="inline-flex w-full items-center gap-2 rounded-xl border bg-bg px-1 {edge} transition-colors duration-150 ease-brand-out
|
|
115
|
+
{sizes[size]}
|
|
116
|
+
{invalid
|
|
117
|
+
? 'border-danger focus-within:border-danger'
|
|
118
|
+
: `border-hairline-strong ${toneFocusWithinBorder[tone]}`}
|
|
119
|
+
{disabled ? 'pointer-events-none opacity-50' : ''}"
|
|
120
|
+
>
|
|
121
|
+
<button
|
|
122
|
+
type="button"
|
|
123
|
+
{disabled}
|
|
124
|
+
onclick={() => input?.click()}
|
|
125
|
+
class="shrink-0 rounded-lg border border-hairline-strong bg-bg-alt font-sans font-medium text-text-secondary transition-colors duration-150 hover:bg-bg-inset hover:text-text focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-current
|
|
126
|
+
{buttons[size]}"
|
|
127
|
+
>
|
|
128
|
+
{label ?? t.current.chooseFile}
|
|
129
|
+
</button>
|
|
130
|
+
|
|
131
|
+
<span
|
|
132
|
+
class="min-w-0 flex-1 truncate font-sans {files.length ? 'text-text' : 'text-text-muted'}"
|
|
133
|
+
>
|
|
134
|
+
{summary}
|
|
135
|
+
</span>
|
|
136
|
+
|
|
137
|
+
{#if files.length}
|
|
138
|
+
<button
|
|
139
|
+
type="button"
|
|
140
|
+
onclick={clear}
|
|
141
|
+
aria-label={t.current.remove}
|
|
142
|
+
class="mr-1 shrink-0 rounded p-1 text-text-muted transition-colors duration-150 hover:bg-bg-inset hover:text-danger focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-danger"
|
|
143
|
+
>
|
|
144
|
+
<svg class="size-3.5" viewBox="0 0 14 14" fill="none" aria-hidden="true">
|
|
145
|
+
<path
|
|
146
|
+
d="m2 2 10 10M12 2 2 12"
|
|
147
|
+
stroke="currentColor"
|
|
148
|
+
stroke-width="1.6"
|
|
149
|
+
stroke-linecap="round"
|
|
150
|
+
/>
|
|
151
|
+
</svg>
|
|
152
|
+
</button>
|
|
153
|
+
{/if}
|
|
154
|
+
</span>
|
|
155
|
+
|
|
156
|
+
<input
|
|
157
|
+
bind:this={input}
|
|
158
|
+
type="file"
|
|
159
|
+
{name}
|
|
160
|
+
{accept}
|
|
161
|
+
{multiple}
|
|
162
|
+
{disabled}
|
|
163
|
+
aria-invalid={invalid ? 'true' : undefined}
|
|
164
|
+
class="sr-only"
|
|
165
|
+
onchange={(event) => add(event.currentTarget.files)}
|
|
166
|
+
/>
|
|
167
|
+
|
|
168
|
+
{#if rejected.length}
|
|
169
|
+
<ul class="flex flex-col gap-1">
|
|
170
|
+
{#each rejected as item (item.file.name + item.reason)}
|
|
171
|
+
<li class="font-sans text-sm text-danger">
|
|
172
|
+
{item.file.name} — {reasons[item.reason]}
|
|
173
|
+
</li>
|
|
174
|
+
{/each}
|
|
175
|
+
</ul>
|
|
176
|
+
{/if}
|
|
177
|
+
|
|
178
|
+
{#if showList && multiple && files.length > 1}
|
|
179
|
+
<ul class="flex flex-col rounded-[20px] border border-hairline bg-bg {edge}">
|
|
180
|
+
{#each files as file, i (file.name + file.size + i)}
|
|
181
|
+
<li
|
|
182
|
+
class="flex items-center gap-3 border-b border-hairline px-4 py-2.5 font-sans last:border-b-0"
|
|
183
|
+
>
|
|
184
|
+
<span class="min-w-0 flex-1 truncate text-sm text-text">{file.name}</span>
|
|
185
|
+
<span class="shrink-0 text-xs text-text-muted tabular-nums">{formatSize(file.size)}</span>
|
|
186
|
+
<button
|
|
187
|
+
type="button"
|
|
188
|
+
onclick={() => (files = files.filter((_, at) => at !== i))}
|
|
189
|
+
aria-label="{t.current.remove} {file.name}"
|
|
190
|
+
class="-m-1 shrink-0 rounded p-1 text-text-muted transition-colors duration-150 hover:bg-bg-inset hover:text-danger focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-danger"
|
|
191
|
+
>
|
|
192
|
+
<svg class="size-3.5" viewBox="0 0 14 14" fill="none" aria-hidden="true">
|
|
193
|
+
<path
|
|
194
|
+
d="m2 2 10 10M12 2 2 12"
|
|
195
|
+
stroke="currentColor"
|
|
196
|
+
stroke-width="1.6"
|
|
197
|
+
stroke-linecap="round"
|
|
198
|
+
/>
|
|
199
|
+
</svg>
|
|
200
|
+
</button>
|
|
201
|
+
</li>
|
|
202
|
+
{/each}
|
|
203
|
+
</ul>
|
|
204
|
+
{/if}
|
|
205
|
+
</div>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type RejectedFile } from '../../core/files.js';
|
|
2
|
+
import { type Tone } from '../../core/tones.js';
|
|
3
|
+
import type { InputSize } from './Input.svelte';
|
|
4
|
+
interface Props {
|
|
5
|
+
/** Bindable list of accepted files. */
|
|
6
|
+
files?: File[];
|
|
7
|
+
/** Same syntax as the input's `accept` — `'image/*,.pdf'`. */
|
|
8
|
+
accept?: string;
|
|
9
|
+
multiple?: boolean;
|
|
10
|
+
/** Per-file ceiling in bytes. `0` means no limit. */
|
|
11
|
+
maxSize?: number;
|
|
12
|
+
/** Cap on how many files may be held at once. `0` means no limit. */
|
|
13
|
+
maxFiles?: number;
|
|
14
|
+
disabled?: boolean;
|
|
15
|
+
size?: InputSize;
|
|
16
|
+
tone?: Tone;
|
|
17
|
+
invalid?: boolean;
|
|
18
|
+
/** Text on the button. Defaults to the locale's `chooseFile`. */
|
|
19
|
+
label?: string;
|
|
20
|
+
/** Shown while nothing is chosen. Defaults to the locale's `noFile`. */
|
|
21
|
+
placeholder?: string;
|
|
22
|
+
/** Show the list of held files below the row. */
|
|
23
|
+
showList?: boolean;
|
|
24
|
+
/** The `name` the hidden input posts under, for a plain form submit. */
|
|
25
|
+
name?: string;
|
|
26
|
+
onaccept?: (files: File[]) => void;
|
|
27
|
+
onreject?: (rejected: RejectedFile[]) => void;
|
|
28
|
+
class?: string;
|
|
29
|
+
}
|
|
30
|
+
declare const FileInput: import("svelte").Component<Props, {}, "files">;
|
|
31
|
+
type FileInput = ReturnType<typeof FileInput>;
|
|
32
|
+
export default FileInput;
|