@nqmcreative/ui 0.1.1 → 0.2.1
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 +89 -34
- package/cli/index.mjs +83 -33
- package/dist/core/calendar.d.ts +3 -0
- package/dist/core/calendar.js +36 -0
- package/dist/core/dialog.svelte.d.ts +14 -0
- package/dist/core/dialog.svelte.js +23 -0
- package/dist/core/files.d.ts +35 -0
- package/dist/core/files.js +62 -0
- package/dist/core/index.d.ts +37 -0
- package/dist/core/index.js +35 -0
- package/dist/core/list.svelte.d.ts +41 -0
- package/dist/core/list.svelte.js +77 -0
- package/dist/core/number.d.ts +7 -0
- package/dist/core/number.js +17 -0
- package/dist/core/pagination.d.ts +6 -0
- package/dist/core/pagination.js +21 -0
- package/dist/core/password.d.ts +8 -0
- package/dist/core/password.js +23 -0
- package/dist/core/table.d.ts +22 -0
- package/dist/core/table.js +41 -0
- package/dist/core/theme.svelte.d.ts +16 -0
- package/dist/core/theme.svelte.js +34 -0
- package/dist/core/trigger.d.ts +35 -0
- package/dist/core/trigger.js +77 -0
- package/dist/index.d.ts +11 -103
- package/dist/index.js +11 -75
- package/dist/{components → styles/matte}/AccordionItem.svelte +1 -1
- package/dist/{components → styles/matte}/AccordionItem.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Alert.svelte +8 -2
- package/dist/{components → styles/matte}/Alert.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Avatar.svelte +1 -1
- package/dist/{components → styles/matte}/Avatar.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Badge.svelte +8 -3
- package/dist/{components → styles/matte}/Badge.svelte.d.ts +1 -3
- package/dist/{components → styles/matte}/Breadcrumb.svelte +2 -2
- package/dist/{components → styles/matte}/Breadcrumb.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Button.svelte +1 -1
- package/dist/{components → styles/matte}/Button.svelte.d.ts +1 -1
- package/dist/styles/matte/CTASection.svelte +76 -0
- package/dist/styles/matte/CTASection.svelte.d.ts +18 -0
- package/dist/{components → styles/matte}/Calendar.svelte +7 -17
- package/dist/{components → styles/matte}/Calendar.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Card.svelte +1 -1
- package/dist/{components → styles/matte}/Card.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Checkbox.svelte +1 -1
- package/dist/{components → styles/matte}/Checkbox.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/CheckboxGroup.svelte +1 -1
- package/dist/{components → styles/matte}/CheckboxGroup.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Combobox.svelte +31 -42
- package/dist/{components → styles/matte}/Combobox.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/CommandPalette.svelte +26 -41
- package/dist/{components → styles/matte}/CommandPalette.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/ConfirmDialog.svelte +2 -2
- package/dist/{components → styles/matte}/ConfirmDialog.svelte.d.ts +2 -2
- package/dist/{components → styles/matte}/ContextMenu.svelte +5 -7
- package/dist/{components → styles/matte}/DatePicker.svelte +7 -11
- package/dist/{components → styles/matte}/DatePicker.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Drawer.svelte +4 -7
- package/dist/{components → styles/matte}/Dropdown.svelte +18 -36
- package/dist/{components → styles/matte}/Dropdown.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Dropzone.svelte +11 -43
- package/dist/{components → styles/matte}/Dropzone.svelte.d.ts +2 -5
- package/dist/{components → styles/matte}/EmptyState.svelte +1 -1
- package/dist/{components → styles/matte}/EmptyState.svelte.d.ts +1 -1
- package/dist/styles/matte/FeatureCard.svelte +58 -0
- package/dist/styles/matte/FeatureCard.svelte.d.ts +16 -0
- package/dist/styles/matte/FeatureGrid.svelte +62 -0
- package/dist/styles/matte/FeatureGrid.svelte.d.ts +16 -0
- package/dist/{components → styles/matte}/Footer.svelte +1 -1
- package/dist/{components → styles/matte}/Footer.svelte.d.ts +1 -1
- package/dist/styles/matte/HeroSection.svelte +80 -0
- package/dist/styles/matte/HeroSection.svelte.d.ts +21 -0
- package/dist/{components → styles/matte}/Input.svelte +1 -1
- package/dist/{components → styles/matte}/Input.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Link.svelte +1 -1
- package/dist/{components → styles/matte}/Link.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/LocaleProvider.svelte +1 -1
- package/dist/{components → styles/matte}/LocaleProvider.svelte.d.ts +1 -1
- package/dist/styles/matte/LogoCloud.svelte +61 -0
- package/dist/styles/matte/LogoCloud.svelte.d.ts +19 -0
- package/dist/{components → styles/matte}/MenuItem.svelte +1 -1
- package/dist/{components → styles/matte}/MenuItem.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Modal.svelte +4 -7
- package/dist/{components → styles/matte}/MultiSelect.svelte +18 -37
- package/dist/{components → styles/matte}/MultiSelect.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Navbar.svelte +2 -2
- package/dist/{components → styles/matte}/Navbar.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/NumberInput.svelte +4 -8
- package/dist/{components → styles/matte}/NumberInput.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Pagination.svelte +4 -15
- package/dist/{components → styles/matte}/Pagination.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/PasswordInput.svelte +4 -13
- package/dist/{components → styles/matte}/PasswordInput.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Popover.svelte +16 -41
- package/dist/{components → styles/matte}/Popover.svelte.d.ts +1 -1
- package/dist/styles/matte/PricingCard.svelte +107 -0
- package/dist/styles/matte/PricingCard.svelte.d.ts +25 -0
- package/dist/{components → styles/matte}/Progress.svelte +3 -2
- package/dist/{components → styles/matte}/Progress.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Radio.svelte +1 -1
- package/dist/{components → styles/matte}/Radio.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/RadioGroup.svelte +1 -1
- package/dist/{components → styles/matte}/RadioGroup.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/SegmentedControl.svelte +1 -1
- package/dist/{components → styles/matte}/SegmentedControl.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Select.svelte +1 -1
- package/dist/{components → styles/matte}/Select.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Sidebar.svelte +2 -2
- package/dist/{components → styles/matte}/Sidebar.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Slider.svelte +3 -2
- package/dist/{components → styles/matte}/Slider.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Spinner.svelte +2 -2
- package/dist/{components → styles/matte}/Spinner.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Stat.svelte +1 -1
- package/dist/{components → styles/matte}/Stat.svelte.d.ts +1 -1
- package/dist/styles/matte/StatsBand.svelte +57 -0
- package/dist/styles/matte/StatsBand.svelte.d.ts +20 -0
- package/dist/{components → styles/matte}/Steps.svelte +1 -1
- package/dist/{components → styles/matte}/Steps.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Switch.svelte +1 -1
- package/dist/{components → styles/matte}/Switch.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Table.svelte +6 -28
- package/dist/{components → styles/matte}/Table.svelte.d.ts +2 -6
- package/dist/{components → styles/matte}/Tabs.svelte +8 -1
- package/dist/{components → styles/matte}/Tabs.svelte.d.ts +1 -1
- package/dist/styles/matte/Testimonial.svelte +67 -0
- package/dist/styles/matte/Testimonial.svelte.d.ts +19 -0
- package/dist/{components → styles/matte}/Textarea.svelte +1 -1
- package/dist/{components → styles/matte}/Textarea.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/ThemeToggle.svelte +14 -27
- package/dist/{components → styles/matte}/ThemeToggle.svelte.d.ts +2 -6
- package/dist/{components → styles/matte}/Toaster.svelte +4 -4
- package/dist/styles/matte/index.d.ts +109 -0
- package/dist/styles/matte/index.js +83 -0
- package/dist/styles/paper/Accordion.svelte +17 -0
- package/dist/styles/paper/Accordion.svelte.d.ts +8 -0
- package/dist/styles/paper/AccordionItem.svelte +46 -0
- package/dist/styles/paper/AccordionItem.svelte.d.ts +14 -0
- package/dist/styles/paper/Alert.svelte +99 -0
- package/dist/styles/paper/Alert.svelte.d.ts +18 -0
- package/dist/styles/paper/Avatar.svelte +60 -0
- package/dist/styles/paper/Avatar.svelte.d.ts +16 -0
- package/dist/styles/paper/AvatarGroup.svelte +17 -0
- package/dist/styles/paper/AvatarGroup.svelte.d.ts +8 -0
- package/dist/styles/paper/Badge.svelte +58 -0
- package/dist/styles/paper/Badge.svelte.d.ts +16 -0
- package/dist/styles/paper/Breadcrumb.svelte +49 -0
- package/dist/styles/paper/Breadcrumb.svelte.d.ts +14 -0
- package/dist/styles/paper/Button.svelte +96 -0
- package/dist/styles/paper/Button.svelte.d.ts +21 -0
- package/dist/styles/paper/CTASection.svelte +76 -0
- package/dist/styles/paper/CTASection.svelte.d.ts +18 -0
- package/dist/styles/paper/Calendar.svelte +202 -0
- package/dist/styles/paper/Calendar.svelte.d.ts +22 -0
- package/dist/styles/paper/Card.svelte +78 -0
- package/dist/styles/paper/Card.svelte.d.ts +21 -0
- package/dist/styles/paper/Checkbox.svelte +75 -0
- package/dist/styles/paper/Checkbox.svelte.d.ts +15 -0
- package/dist/styles/paper/CheckboxGroup.svelte +111 -0
- package/dist/styles/paper/CheckboxGroup.svelte.d.ts +30 -0
- package/dist/styles/paper/Combobox.svelte +266 -0
- package/dist/styles/paper/Combobox.svelte.d.ts +29 -0
- package/dist/styles/paper/CommandPalette.svelte +209 -0
- package/dist/styles/paper/CommandPalette.svelte.d.ts +32 -0
- package/dist/styles/paper/ConfirmDialog.svelte +97 -0
- package/dist/styles/paper/ConfirmDialog.svelte.d.ts +22 -0
- package/dist/styles/paper/ContextMenu.svelte +88 -0
- package/dist/styles/paper/ContextMenu.svelte.d.ts +15 -0
- package/dist/styles/paper/DatePicker.svelte +192 -0
- package/dist/styles/paper/DatePicker.svelte.d.ts +23 -0
- package/dist/styles/paper/Divider.svelte +30 -0
- package/dist/styles/paper/Divider.svelte.d.ts +10 -0
- package/dist/styles/paper/Drawer.svelte +165 -0
- package/dist/styles/paper/Drawer.svelte.d.ts +20 -0
- package/dist/styles/paper/Dropdown.svelte +94 -0
- package/dist/styles/paper/Dropdown.svelte.d.ts +23 -0
- package/dist/styles/paper/Dropzone.svelte +210 -0
- package/dist/styles/paper/Dropzone.svelte.d.ts +29 -0
- package/dist/styles/paper/EmptyState.svelte +71 -0
- package/dist/styles/paper/EmptyState.svelte.d.ts +18 -0
- package/dist/styles/paper/FeatureCard.svelte +58 -0
- package/dist/styles/paper/FeatureCard.svelte.d.ts +16 -0
- package/dist/styles/paper/FeatureGrid.svelte +62 -0
- package/dist/styles/paper/FeatureGrid.svelte.d.ts +16 -0
- package/dist/styles/paper/Field.svelte +42 -0
- package/dist/styles/paper/Field.svelte.d.ts +16 -0
- package/dist/styles/paper/Footer.svelte +91 -0
- package/dist/styles/paper/Footer.svelte.d.ts +25 -0
- package/dist/styles/paper/HeroSection.svelte +86 -0
- package/dist/styles/paper/HeroSection.svelte.d.ts +21 -0
- package/dist/styles/paper/Input.svelte +60 -0
- package/dist/styles/paper/Input.svelte.d.ts +18 -0
- package/dist/styles/paper/InputGroup.svelte +20 -0
- package/dist/styles/paper/InputGroup.svelte.d.ts +11 -0
- package/dist/styles/paper/Kbd.svelte +17 -0
- package/dist/styles/paper/Kbd.svelte.d.ts +8 -0
- package/dist/styles/paper/Label.svelte +16 -0
- package/dist/styles/paper/Label.svelte.d.ts +9 -0
- package/dist/styles/paper/Link.svelte +44 -0
- package/dist/styles/paper/Link.svelte.d.ts +16 -0
- package/dist/styles/paper/LocaleProvider.svelte +24 -0
- package/dist/styles/paper/LocaleProvider.svelte.d.ts +10 -0
- package/dist/styles/paper/LogoCloud.svelte +61 -0
- package/dist/styles/paper/LogoCloud.svelte.d.ts +19 -0
- package/dist/styles/paper/MenuItem.svelte +64 -0
- package/dist/styles/paper/MenuItem.svelte.d.ts +18 -0
- package/dist/styles/paper/MenuSeparator.svelte +22 -0
- package/dist/styles/paper/MenuSeparator.svelte.d.ts +8 -0
- package/dist/styles/paper/Modal.svelte +118 -0
- package/dist/styles/paper/Modal.svelte.d.ts +21 -0
- package/dist/styles/paper/MultiSelect.svelte +287 -0
- package/dist/styles/paper/MultiSelect.svelte.d.ts +31 -0
- package/dist/styles/paper/Navbar.svelte +201 -0
- package/dist/styles/paper/Navbar.svelte.d.ts +33 -0
- package/dist/styles/paper/NumberInput.svelte +96 -0
- package/dist/styles/paper/NumberInput.svelte.d.ts +15 -0
- package/dist/styles/paper/Pagination.svelte +83 -0
- package/dist/styles/paper/Pagination.svelte.d.ts +15 -0
- package/dist/styles/paper/PasswordInput.svelte +100 -0
- package/dist/styles/paper/PasswordInput.svelte.d.ts +12 -0
- package/dist/styles/paper/Popover.svelte +89 -0
- package/dist/styles/paper/Popover.svelte.d.ts +19 -0
- package/dist/styles/paper/PricingCard.svelte +108 -0
- package/dist/styles/paper/PricingCard.svelte.d.ts +25 -0
- package/dist/styles/paper/Progress.svelte +59 -0
- package/dist/styles/paper/Progress.svelte.d.ts +17 -0
- package/dist/styles/paper/Radio.svelte +55 -0
- package/dist/styles/paper/Radio.svelte.d.ts +15 -0
- package/dist/styles/paper/RadioGroup.svelte +95 -0
- package/dist/styles/paper/RadioGroup.svelte.d.ts +27 -0
- package/dist/styles/paper/SegmentedControl.svelte +88 -0
- package/dist/styles/paper/SegmentedControl.svelte.d.ts +25 -0
- package/dist/styles/paper/Select.svelte +61 -0
- package/dist/styles/paper/Select.svelte.d.ts +20 -0
- package/dist/styles/paper/Sidebar.svelte +206 -0
- package/dist/styles/paper/Sidebar.svelte.d.ts +36 -0
- package/dist/styles/paper/Skeleton.svelte +46 -0
- package/dist/styles/paper/Skeleton.svelte.d.ts +13 -0
- package/dist/styles/paper/Slider.svelte +80 -0
- package/dist/styles/paper/Slider.svelte.d.ts +19 -0
- package/dist/styles/paper/Spinner.svelte +34 -0
- package/dist/styles/paper/Spinner.svelte.d.ts +13 -0
- package/dist/styles/paper/Stat.svelte +51 -0
- package/dist/styles/paper/Stat.svelte.d.ts +16 -0
- package/dist/styles/paper/StatsBand.svelte +63 -0
- package/dist/styles/paper/StatsBand.svelte.d.ts +20 -0
- package/dist/styles/paper/Steps.svelte +141 -0
- package/dist/styles/paper/Steps.svelte.d.ts +24 -0
- package/dist/styles/paper/Switch.svelte +64 -0
- package/dist/styles/paper/Switch.svelte.d.ts +14 -0
- package/dist/styles/paper/Table.svelte +217 -0
- package/dist/styles/paper/Table.svelte.d.ts +66 -0
- package/dist/styles/paper/Tabs.svelte +102 -0
- package/dist/styles/paper/Tabs.svelte.d.ts +23 -0
- package/dist/styles/paper/Testimonial.svelte +64 -0
- package/dist/styles/paper/Testimonial.svelte.d.ts +19 -0
- package/dist/styles/paper/Textarea.svelte +54 -0
- package/dist/styles/paper/Textarea.svelte.d.ts +12 -0
- package/dist/styles/paper/ThemeToggle.svelte +130 -0
- package/dist/styles/paper/ThemeToggle.svelte.d.ts +16 -0
- package/dist/styles/paper/Toaster.svelte +132 -0
- package/dist/styles/paper/Toaster.svelte.d.ts +8 -0
- package/dist/styles/paper/Tooltip.svelte +33 -0
- package/dist/styles/paper/Tooltip.svelte.d.ts +12 -0
- package/dist/styles/paper/fonts.css +46 -0
- package/dist/styles/paper/index.d.ts +109 -0
- package/dist/styles/paper/index.js +83 -0
- package/dist/styles/paper/theme.css +222 -0
- package/package.json +531 -201
- package/registry.json +658 -339
- /package/dist/{actions → core/actions}/anchor.d.ts +0 -0
- /package/dist/{actions → core/actions}/anchor.js +0 -0
- /package/dist/{actions → core/actions}/dismissable.d.ts +0 -0
- /package/dist/{actions → core/actions}/dismissable.js +0 -0
- /package/dist/{date.d.ts → core/date.d.ts} +0 -0
- /package/dist/{date.js → core/date.js} +0 -0
- /package/dist/{locale.svelte.d.ts → core/locale.svelte.d.ts} +0 -0
- /package/dist/{locale.svelte.js → core/locale.svelte.js} +0 -0
- /package/dist/{toast.svelte.d.ts → core/toast.svelte.d.ts} +0 -0
- /package/dist/{toast.svelte.js → core/toast.svelte.js} +0 -0
- /package/dist/{tones.d.ts → core/tones.d.ts} +0 -0
- /package/dist/{tones.js → core/tones.js} +0 -0
- /package/dist/{components → styles/matte}/Accordion.svelte +0 -0
- /package/dist/{components → styles/matte}/Accordion.svelte.d.ts +0 -0
- /package/dist/{components → styles/matte}/AvatarGroup.svelte +0 -0
- /package/dist/{components → styles/matte}/AvatarGroup.svelte.d.ts +0 -0
- /package/dist/{components → styles/matte}/ContextMenu.svelte.d.ts +0 -0
- /package/dist/{components → styles/matte}/Divider.svelte +0 -0
- /package/dist/{components → styles/matte}/Divider.svelte.d.ts +0 -0
- /package/dist/{components → styles/matte}/Drawer.svelte.d.ts +0 -0
- /package/dist/{components → styles/matte}/Field.svelte +0 -0
- /package/dist/{components → styles/matte}/Field.svelte.d.ts +0 -0
- /package/dist/{components → styles/matte}/InputGroup.svelte +0 -0
- /package/dist/{components → styles/matte}/InputGroup.svelte.d.ts +0 -0
- /package/dist/{components → styles/matte}/Kbd.svelte +0 -0
- /package/dist/{components → styles/matte}/Kbd.svelte.d.ts +0 -0
- /package/dist/{components → styles/matte}/Label.svelte +0 -0
- /package/dist/{components → styles/matte}/Label.svelte.d.ts +0 -0
- /package/dist/{components → styles/matte}/MenuSeparator.svelte +0 -0
- /package/dist/{components → styles/matte}/MenuSeparator.svelte.d.ts +0 -0
- /package/dist/{components → styles/matte}/Modal.svelte.d.ts +0 -0
- /package/dist/{components → styles/matte}/Skeleton.svelte +0 -0
- /package/dist/{components → styles/matte}/Skeleton.svelte.d.ts +0 -0
- /package/dist/{components → styles/matte}/Toaster.svelte.d.ts +0 -0
- /package/dist/{components → styles/matte}/Tooltip.svelte +0 -0
- /package/dist/{components → styles/matte}/Tooltip.svelte.d.ts +0 -0
- /package/dist/{fonts.css → styles/matte/fonts.css} +0 -0
- /package/dist/{theme.css → styles/matte/theme.css} +0 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
export interface StepItem {
|
|
3
|
+
label: string;
|
|
4
|
+
description?: string;
|
|
5
|
+
/** Marks the step as failed — shown in `danger` regardless of position. */
|
|
6
|
+
error?: boolean;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
}
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<script lang="ts">
|
|
12
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
13
|
+
import { focusRing, toneFill, toneRing, toneText, type Tone } from '../../core/tones.js';
|
|
14
|
+
|
|
15
|
+
interface Props extends Omit<HTMLAttributes<HTMLElement>, 'onchange'> {
|
|
16
|
+
items: StepItem[];
|
|
17
|
+
/** Bindable, zero-based. Steps before it count as done. */
|
|
18
|
+
current?: number;
|
|
19
|
+
orientation?: 'horizontal' | 'vertical';
|
|
20
|
+
tone?: Tone;
|
|
21
|
+
/** Let the user jump to a completed step by clicking it. */
|
|
22
|
+
clickable?: boolean;
|
|
23
|
+
/** Hide the connecting rule between steps. */
|
|
24
|
+
bare?: boolean;
|
|
25
|
+
onchange?: (index: number) => void;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
let {
|
|
29
|
+
items,
|
|
30
|
+
current = $bindable(0),
|
|
31
|
+
orientation = 'horizontal',
|
|
32
|
+
tone = 'brand',
|
|
33
|
+
clickable = false,
|
|
34
|
+
bare = false,
|
|
35
|
+
class: className = '',
|
|
36
|
+
onchange,
|
|
37
|
+
...rest
|
|
38
|
+
}: Props = $props();
|
|
39
|
+
|
|
40
|
+
function status(index: number): 'done' | 'current' | 'todo' {
|
|
41
|
+
if (index < current) return 'done';
|
|
42
|
+
if (index === current) return 'current';
|
|
43
|
+
return 'todo';
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const marker =
|
|
47
|
+
'flex size-8 shrink-0 items-center justify-center rounded-full border font-sans text-xs font-semibold transition-colors duration-150 ease-brand-out';
|
|
48
|
+
|
|
49
|
+
function markerTone(state: 'done' | 'current' | 'todo', item: StepItem) {
|
|
50
|
+
if (item.error) return 'border-danger bg-danger-light text-danger';
|
|
51
|
+
if (state === 'done') return `${toneFill[tone]} border-transparent text-text-inverse shadow-xs`;
|
|
52
|
+
if (state === 'current') return `border-2 border-current bg-bg ${toneText[tone]}`;
|
|
53
|
+
return 'border-hairline-strong bg-bg text-text-muted';
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function go(index: number, item: StepItem) {
|
|
57
|
+
if (!clickable || item.disabled || index > current) return;
|
|
58
|
+
current = index;
|
|
59
|
+
onchange?.(index);
|
|
60
|
+
}
|
|
61
|
+
</script>
|
|
62
|
+
|
|
63
|
+
{#snippet glyph(index: number, state: 'done' | 'current' | 'todo', item: StepItem)}
|
|
64
|
+
{#if item.error}
|
|
65
|
+
!
|
|
66
|
+
{:else if state === 'done'}
|
|
67
|
+
<svg class="size-3.5" viewBox="0 0 14 14" fill="none" aria-hidden="true">
|
|
68
|
+
<path
|
|
69
|
+
d="m2 7 3.2 3.2L12 3.6"
|
|
70
|
+
stroke="currentColor"
|
|
71
|
+
stroke-width="2"
|
|
72
|
+
stroke-linecap="round"
|
|
73
|
+
stroke-linejoin="round"
|
|
74
|
+
/>
|
|
75
|
+
</svg>
|
|
76
|
+
{:else}
|
|
77
|
+
{index + 1}
|
|
78
|
+
{/if}
|
|
79
|
+
{/snippet}
|
|
80
|
+
|
|
81
|
+
<nav
|
|
82
|
+
aria-label="Progress"
|
|
83
|
+
class="flex w-full {orientation === 'vertical' ? 'flex-col gap-0' : 'flex-row'} {className}"
|
|
84
|
+
{...rest}
|
|
85
|
+
>
|
|
86
|
+
{#each items as item, i (item.label)}
|
|
87
|
+
{@const state = status(i)}
|
|
88
|
+
<div
|
|
89
|
+
class="flex min-w-0 {orientation === 'vertical' ? 'flex-row gap-3' : 'flex-1 flex-col gap-2'}"
|
|
90
|
+
>
|
|
91
|
+
<!-- marker + rule -->
|
|
92
|
+
<div
|
|
93
|
+
class="flex shrink-0 items-center {orientation === 'vertical'
|
|
94
|
+
? 'flex-col self-stretch'
|
|
95
|
+
: 'w-full flex-row'}"
|
|
96
|
+
>
|
|
97
|
+
{#if clickable && state !== 'todo' && !item.disabled}
|
|
98
|
+
<button
|
|
99
|
+
type="button"
|
|
100
|
+
onclick={() => go(i, item)}
|
|
101
|
+
aria-current={state === 'current' ? 'step' : undefined}
|
|
102
|
+
class="{marker} cursor-pointer {markerTone(state, item)} {focusRing} {toneRing[tone]}"
|
|
103
|
+
>
|
|
104
|
+
{@render glyph(i, state, item)}
|
|
105
|
+
</button>
|
|
106
|
+
{:else}
|
|
107
|
+
<div
|
|
108
|
+
aria-current={state === 'current' ? 'step' : undefined}
|
|
109
|
+
class="{marker} {markerTone(state, item)}"
|
|
110
|
+
>
|
|
111
|
+
{@render glyph(i, state, item)}
|
|
112
|
+
</div>
|
|
113
|
+
{/if}
|
|
114
|
+
|
|
115
|
+
{#if !bare && i < items.length - 1}
|
|
116
|
+
<span
|
|
117
|
+
class="rounded-full {orientation === 'vertical'
|
|
118
|
+
? 'my-1 w-0.5 flex-1'
|
|
119
|
+
: 'mx-3 h-0.5 flex-1'} {i < current ? toneFill[tone] : 'bg-hairline'}"
|
|
120
|
+
></span>
|
|
121
|
+
{/if}
|
|
122
|
+
</div>
|
|
123
|
+
|
|
124
|
+
<!-- copy -->
|
|
125
|
+
<div class="flex min-w-0 flex-col gap-0.5 {orientation === 'vertical' ? 'pb-6' : 'pr-3'}">
|
|
126
|
+
<span
|
|
127
|
+
class="font-sans text-sm leading-snug break-words {state === 'todo'
|
|
128
|
+
? 'text-text-muted'
|
|
129
|
+
: 'font-medium text-text'}"
|
|
130
|
+
>
|
|
131
|
+
{item.label}
|
|
132
|
+
</span>
|
|
133
|
+
{#if item.description}
|
|
134
|
+
<span class="font-sans text-[13px] leading-snug break-words text-text-muted">
|
|
135
|
+
{item.description}
|
|
136
|
+
</span>
|
|
137
|
+
{/if}
|
|
138
|
+
</div>
|
|
139
|
+
</div>
|
|
140
|
+
{/each}
|
|
141
|
+
</nav>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface StepItem {
|
|
2
|
+
label: string;
|
|
3
|
+
description?: string;
|
|
4
|
+
/** Marks the step as failed — shown in `danger` regardless of position. */
|
|
5
|
+
error?: boolean;
|
|
6
|
+
disabled?: boolean;
|
|
7
|
+
}
|
|
8
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
9
|
+
import { type Tone } from '../../core/tones.js';
|
|
10
|
+
interface Props extends Omit<HTMLAttributes<HTMLElement>, 'onchange'> {
|
|
11
|
+
items: StepItem[];
|
|
12
|
+
/** Bindable, zero-based. Steps before it count as done. */
|
|
13
|
+
current?: number;
|
|
14
|
+
orientation?: 'horizontal' | 'vertical';
|
|
15
|
+
tone?: Tone;
|
|
16
|
+
/** Let the user jump to a completed step by clicking it. */
|
|
17
|
+
clickable?: boolean;
|
|
18
|
+
/** Hide the connecting rule between steps. */
|
|
19
|
+
bare?: boolean;
|
|
20
|
+
onchange?: (index: number) => void;
|
|
21
|
+
}
|
|
22
|
+
declare const Steps: import("svelte").Component<Props, {}, "current">;
|
|
23
|
+
type Steps = ReturnType<typeof Steps>;
|
|
24
|
+
export default Steps;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { HTMLButtonAttributes } from 'svelte/elements';
|
|
3
|
+
import { focusRing, toneFill, toneRing, type Tone } from '../../core/tones.js';
|
|
4
|
+
|
|
5
|
+
export type SwitchSize = 'sm' | 'md';
|
|
6
|
+
|
|
7
|
+
interface Props extends Omit<HTMLButtonAttributes, 'onclick' | 'onchange'> {
|
|
8
|
+
checked?: boolean;
|
|
9
|
+
label?: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
tone?: Tone;
|
|
12
|
+
size?: SwitchSize;
|
|
13
|
+
onchange?: (checked: boolean) => void;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
let {
|
|
17
|
+
checked = $bindable(false),
|
|
18
|
+
label,
|
|
19
|
+
description,
|
|
20
|
+
tone = 'brand',
|
|
21
|
+
size = 'md',
|
|
22
|
+
disabled = false,
|
|
23
|
+
onchange,
|
|
24
|
+
class: className = '',
|
|
25
|
+
...rest
|
|
26
|
+
}: Props = $props();
|
|
27
|
+
|
|
28
|
+
const sizes: Record<SwitchSize, { track: string; thumb: string; travel: string }> = {
|
|
29
|
+
sm: { track: 'h-5 w-9', thumb: 'size-4', travel: 'translate-x-4' },
|
|
30
|
+
md: { track: 'h-6 w-11', thumb: 'size-5', travel: 'translate-x-5' }
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
function toggle() {
|
|
34
|
+
checked = !checked;
|
|
35
|
+
onchange?.(checked);
|
|
36
|
+
}
|
|
37
|
+
</script>
|
|
38
|
+
|
|
39
|
+
<div class="inline-flex items-start gap-3 {disabled ? 'opacity-50' : ''} {className}">
|
|
40
|
+
<button
|
|
41
|
+
type="button"
|
|
42
|
+
role="switch"
|
|
43
|
+
aria-checked={checked}
|
|
44
|
+
aria-label={label}
|
|
45
|
+
{disabled}
|
|
46
|
+
onclick={toggle}
|
|
47
|
+
class="relative mt-0.5 inline-flex shrink-0 items-center rounded-full p-0.5 transition-colors duration-200 ease-brand-out disabled:pointer-events-none
|
|
48
|
+
{sizes[size].track} {checked ? toneFill[tone] : 'bg-hairline-strong'} {focusRing} {toneRing[tone]}"
|
|
49
|
+
{...rest}
|
|
50
|
+
>
|
|
51
|
+
<span
|
|
52
|
+
class="rounded-full bg-bg shadow-sm transition-transform duration-200 ease-brand-out
|
|
53
|
+
{sizes[size].thumb} {checked ? sizes[size].travel : 'translate-x-0'}"
|
|
54
|
+
></span>
|
|
55
|
+
</button>
|
|
56
|
+
{#if label || description}
|
|
57
|
+
<span class="flex flex-col gap-0.5 font-sans text-sm">
|
|
58
|
+
{#if label}<span class="leading-snug text-text">{label}</span>{/if}
|
|
59
|
+
{#if description}
|
|
60
|
+
<span class="text-[13px] leading-snug text-text-muted">{description}</span>
|
|
61
|
+
{/if}
|
|
62
|
+
</span>
|
|
63
|
+
{/if}
|
|
64
|
+
</div>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { HTMLButtonAttributes } from 'svelte/elements';
|
|
2
|
+
import { type Tone } from '../../core/tones.js';
|
|
3
|
+
export type SwitchSize = 'sm' | 'md';
|
|
4
|
+
interface Props extends Omit<HTMLButtonAttributes, 'onclick' | 'onchange'> {
|
|
5
|
+
checked?: boolean;
|
|
6
|
+
label?: string;
|
|
7
|
+
description?: string;
|
|
8
|
+
tone?: Tone;
|
|
9
|
+
size?: SwitchSize;
|
|
10
|
+
onchange?: (checked: boolean) => void;
|
|
11
|
+
}
|
|
12
|
+
declare const Switch: import("svelte").Component<Props, {}, "checked">;
|
|
13
|
+
type Switch = ReturnType<typeof Switch>;
|
|
14
|
+
export default Switch;
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
export interface TableColumn {
|
|
3
|
+
key: string;
|
|
4
|
+
label: string;
|
|
5
|
+
align?: 'left' | 'center' | 'right';
|
|
6
|
+
/** Extra classes for this column's cells, e.g. `'w-40 tabular-nums'`. */
|
|
7
|
+
class?: string;
|
|
8
|
+
/** Allow clicking the header to sort by this column. */
|
|
9
|
+
sortable?: boolean;
|
|
10
|
+
}
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<script lang="ts" generics="T extends Record<string, unknown>">
|
|
14
|
+
import type { Snippet } from 'svelte';
|
|
15
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
16
|
+
import Checkbox from './Checkbox.svelte';
|
|
17
|
+
import type { Tone } from '../../core/tones.js';
|
|
18
|
+
import { nextSort, sortRows, toggleKey, type TableSort } from '../../core/table.js';
|
|
19
|
+
import { useLocale } from '../../core/locale.svelte.js';
|
|
20
|
+
|
|
21
|
+
interface Props extends Omit<HTMLAttributes<HTMLDivElement>, 'onselect'> {
|
|
22
|
+
columns: TableColumn[];
|
|
23
|
+
rows: T[];
|
|
24
|
+
/** Custom cell rendering — falls back to the raw value. */
|
|
25
|
+
cell?: Snippet<[{ row: T; column: TableColumn; value: unknown }]>;
|
|
26
|
+
/** Shown instead of the body when `rows` is empty. */
|
|
27
|
+
empty?: Snippet;
|
|
28
|
+
caption?: string;
|
|
29
|
+
striped?: boolean;
|
|
30
|
+
hoverable?: boolean;
|
|
31
|
+
compact?: boolean;
|
|
32
|
+
/** Header stays put while the body scrolls — pair with a `max-h-*` class. */
|
|
33
|
+
stickyHeader?: boolean;
|
|
34
|
+
|
|
35
|
+
/** Bindable. Set it to sort; leave `sortable` columns to drive it. */
|
|
36
|
+
sort?: TableSort | null;
|
|
37
|
+
/** Sort the rows here rather than refetching them server-side. Default true. */
|
|
38
|
+
sortLocally?: boolean;
|
|
39
|
+
onsort?: (sort: TableSort | null) => void;
|
|
40
|
+
|
|
41
|
+
/** Turns on the checkbox column. Bindable list of selected row keys. */
|
|
42
|
+
selectable?: boolean;
|
|
43
|
+
selected?: string[];
|
|
44
|
+
/** Which field identifies a row. Default `'id'`. */
|
|
45
|
+
rowKey?: string;
|
|
46
|
+
tone?: Tone;
|
|
47
|
+
onselect?: (selected: string[]) => void;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
let {
|
|
51
|
+
columns,
|
|
52
|
+
rows,
|
|
53
|
+
cell,
|
|
54
|
+
empty,
|
|
55
|
+
caption,
|
|
56
|
+
striped = false,
|
|
57
|
+
hoverable = true,
|
|
58
|
+
compact = false,
|
|
59
|
+
stickyHeader = false,
|
|
60
|
+
sort = $bindable(null),
|
|
61
|
+
sortLocally = true,
|
|
62
|
+
onsort,
|
|
63
|
+
selectable = false,
|
|
64
|
+
selected = $bindable([]),
|
|
65
|
+
rowKey = 'id',
|
|
66
|
+
tone = 'brand',
|
|
67
|
+
onselect,
|
|
68
|
+
class: className = '',
|
|
69
|
+
...rest
|
|
70
|
+
}: Props = $props();
|
|
71
|
+
|
|
72
|
+
const t = useLocale();
|
|
73
|
+
|
|
74
|
+
const aligns = {
|
|
75
|
+
left: 'text-left',
|
|
76
|
+
center: 'text-center',
|
|
77
|
+
right: 'text-right'
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const pad = $derived(compact ? 'px-4 py-2' : 'px-4 py-3');
|
|
81
|
+
|
|
82
|
+
const sorted = $derived(sortLocally ? sortRows(rows, sort) : rows);
|
|
83
|
+
|
|
84
|
+
function toggleSort(column: TableColumn) {
|
|
85
|
+
if (!column.sortable) return;
|
|
86
|
+
const next = nextSort(sort, column.key);
|
|
87
|
+
sort = next;
|
|
88
|
+
onsort?.(next);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const keyOf = (row: T) => String(row[rowKey] ?? '');
|
|
92
|
+
|
|
93
|
+
const allSelected = $derived(
|
|
94
|
+
sorted.length > 0 && sorted.every((row) => selected.includes(keyOf(row)))
|
|
95
|
+
);
|
|
96
|
+
const someSelected = $derived(
|
|
97
|
+
!allSelected && sorted.some((row) => selected.includes(keyOf(row)))
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
function toggleAll() {
|
|
101
|
+
selected = allSelected ? [] : sorted.map(keyOf);
|
|
102
|
+
onselect?.(selected);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function toggleRow(row: T) {
|
|
106
|
+
selected = toggleKey(selected, keyOf(row));
|
|
107
|
+
onselect?.(selected);
|
|
108
|
+
}
|
|
109
|
+
</script>
|
|
110
|
+
|
|
111
|
+
<div
|
|
112
|
+
class="w-full overflow-auto rounded-lg border border-hairline bg-bg shadow-xs {className}"
|
|
113
|
+
{...rest}
|
|
114
|
+
>
|
|
115
|
+
<table class="w-full border-collapse font-sans text-sm">
|
|
116
|
+
{#if caption}
|
|
117
|
+
<caption
|
|
118
|
+
class="border-b border-hairline px-4 py-3 text-left font-sans text-[13px] text-text-muted"
|
|
119
|
+
>
|
|
120
|
+
{caption}
|
|
121
|
+
</caption>
|
|
122
|
+
{/if}
|
|
123
|
+
<thead class={stickyHeader ? 'sticky top-0 z-10' : ''}>
|
|
124
|
+
<tr class="border-b border-hairline bg-bg-alt">
|
|
125
|
+
{#if selectable}
|
|
126
|
+
<th scope="col" class="w-10 {pad}">
|
|
127
|
+
<Checkbox
|
|
128
|
+
checked={allSelected}
|
|
129
|
+
indeterminate={someSelected}
|
|
130
|
+
{tone}
|
|
131
|
+
aria-label={t.current.selectAllRows}
|
|
132
|
+
onchange={toggleAll}
|
|
133
|
+
/>
|
|
134
|
+
</th>
|
|
135
|
+
{/if}
|
|
136
|
+
{#each columns as column (column.key)}
|
|
137
|
+
<th
|
|
138
|
+
scope="col"
|
|
139
|
+
aria-sort={sort?.key === column.key
|
|
140
|
+
? sort.direction === 'asc'
|
|
141
|
+
? 'ascending'
|
|
142
|
+
: 'descending'
|
|
143
|
+
: undefined}
|
|
144
|
+
class="text-[13px] font-semibold text-text-muted {pad} {aligns[
|
|
145
|
+
column.align ?? 'left'
|
|
146
|
+
]} {column.class ?? ''}"
|
|
147
|
+
>
|
|
148
|
+
{#if column.sortable}
|
|
149
|
+
<button
|
|
150
|
+
type="button"
|
|
151
|
+
onclick={() => toggleSort(column)}
|
|
152
|
+
class="inline-flex items-center gap-1.5 rounded transition-colors duration-150 hover:text-text focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-current
|
|
153
|
+
{sort?.key === column.key ? 'text-text' : ''}"
|
|
154
|
+
>
|
|
155
|
+
{column.label}
|
|
156
|
+
<span class="text-[9px] leading-none" aria-hidden="true">
|
|
157
|
+
{#if sort?.key === column.key}
|
|
158
|
+
{sort.direction === 'asc' ? '▲' : '▼'}
|
|
159
|
+
{:else}
|
|
160
|
+
⇅
|
|
161
|
+
{/if}
|
|
162
|
+
</span>
|
|
163
|
+
</button>
|
|
164
|
+
{:else}
|
|
165
|
+
{column.label}
|
|
166
|
+
{/if}
|
|
167
|
+
</th>
|
|
168
|
+
{/each}
|
|
169
|
+
</tr>
|
|
170
|
+
</thead>
|
|
171
|
+
<tbody>
|
|
172
|
+
{#if sorted.length === 0}
|
|
173
|
+
<tr>
|
|
174
|
+
<td
|
|
175
|
+
colspan={columns.length + (selectable ? 1 : 0)}
|
|
176
|
+
class="px-4 py-10 text-center text-sm text-text-muted"
|
|
177
|
+
>
|
|
178
|
+
{#if empty}{@render empty()}{:else}{t.current.noData}{/if}
|
|
179
|
+
</td>
|
|
180
|
+
</tr>
|
|
181
|
+
{:else}
|
|
182
|
+
{#each sorted as row, i (selectable ? keyOf(row) : i)}
|
|
183
|
+
{@const isSelected = selectable && selected.includes(keyOf(row))}
|
|
184
|
+
<tr
|
|
185
|
+
aria-selected={selectable ? isSelected : undefined}
|
|
186
|
+
class="border-b border-hairline last:border-b-0
|
|
187
|
+
{isSelected ? 'bg-brand-light' : striped && i % 2 === 1 ? 'bg-bg-alt' : ''}
|
|
188
|
+
{hoverable ? 'transition-colors duration-150 hover:bg-bg-alt' : ''}"
|
|
189
|
+
>
|
|
190
|
+
{#if selectable}
|
|
191
|
+
<td class={pad}>
|
|
192
|
+
<Checkbox
|
|
193
|
+
checked={isSelected}
|
|
194
|
+
{tone}
|
|
195
|
+
aria-label={t.current.selectRow}
|
|
196
|
+
onchange={() => toggleRow(row)}
|
|
197
|
+
/>
|
|
198
|
+
</td>
|
|
199
|
+
{/if}
|
|
200
|
+
{#each columns as column (column.key)}
|
|
201
|
+
<td
|
|
202
|
+
class="text-text-secondary {pad} {aligns[column.align ?? 'left']} {column.class ??
|
|
203
|
+
''}"
|
|
204
|
+
>
|
|
205
|
+
{#if cell}
|
|
206
|
+
{@render cell({ row, column, value: row[column.key] })}
|
|
207
|
+
{:else}
|
|
208
|
+
{row[column.key] ?? ''}
|
|
209
|
+
{/if}
|
|
210
|
+
</td>
|
|
211
|
+
{/each}
|
|
212
|
+
</tr>
|
|
213
|
+
{/each}
|
|
214
|
+
{/if}
|
|
215
|
+
</tbody>
|
|
216
|
+
</table>
|
|
217
|
+
</div>
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
export interface TableColumn {
|
|
2
|
+
key: string;
|
|
3
|
+
label: string;
|
|
4
|
+
align?: 'left' | 'center' | 'right';
|
|
5
|
+
/** Extra classes for this column's cells, e.g. `'w-40 tabular-nums'`. */
|
|
6
|
+
class?: string;
|
|
7
|
+
/** Allow clicking the header to sort by this column. */
|
|
8
|
+
sortable?: boolean;
|
|
9
|
+
}
|
|
10
|
+
import type { Snippet } from 'svelte';
|
|
11
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
12
|
+
import type { Tone } from '../../core/tones.js';
|
|
13
|
+
import { type TableSort } from '../../core/table.js';
|
|
14
|
+
declare function $$render<T extends Record<string, unknown>>(): {
|
|
15
|
+
props: Omit<HTMLAttributes<HTMLDivElement>, "onselect"> & {
|
|
16
|
+
columns: TableColumn[];
|
|
17
|
+
rows: T[];
|
|
18
|
+
/** Custom cell rendering — falls back to the raw value. */
|
|
19
|
+
cell?: Snippet<[{
|
|
20
|
+
row: T;
|
|
21
|
+
column: TableColumn;
|
|
22
|
+
value: unknown;
|
|
23
|
+
}]>;
|
|
24
|
+
/** Shown instead of the body when `rows` is empty. */
|
|
25
|
+
empty?: Snippet;
|
|
26
|
+
caption?: string;
|
|
27
|
+
striped?: boolean;
|
|
28
|
+
hoverable?: boolean;
|
|
29
|
+
compact?: boolean;
|
|
30
|
+
/** Header stays put while the body scrolls — pair with a `max-h-*` class. */
|
|
31
|
+
stickyHeader?: boolean;
|
|
32
|
+
/** Bindable. Set it to sort; leave `sortable` columns to drive it. */
|
|
33
|
+
sort?: TableSort | null;
|
|
34
|
+
/** Sort the rows here rather than refetching them server-side. Default true. */
|
|
35
|
+
sortLocally?: boolean;
|
|
36
|
+
onsort?: (sort: TableSort | null) => void;
|
|
37
|
+
/** Turns on the checkbox column. Bindable list of selected row keys. */
|
|
38
|
+
selectable?: boolean;
|
|
39
|
+
selected?: string[];
|
|
40
|
+
/** Which field identifies a row. Default `'id'`. */
|
|
41
|
+
rowKey?: string;
|
|
42
|
+
tone?: Tone;
|
|
43
|
+
onselect?: (selected: string[]) => void;
|
|
44
|
+
};
|
|
45
|
+
exports: {};
|
|
46
|
+
bindings: "sort" | "selected";
|
|
47
|
+
slots: {};
|
|
48
|
+
events: {};
|
|
49
|
+
};
|
|
50
|
+
declare class __sveltets_Render<T extends Record<string, unknown>> {
|
|
51
|
+
props(): ReturnType<typeof $$render<T>>['props'];
|
|
52
|
+
events(): ReturnType<typeof $$render<T>>['events'];
|
|
53
|
+
slots(): ReturnType<typeof $$render<T>>['slots'];
|
|
54
|
+
bindings(): "sort" | "selected";
|
|
55
|
+
exports(): {};
|
|
56
|
+
}
|
|
57
|
+
interface $$IsomorphicComponent {
|
|
58
|
+
new <T extends Record<string, unknown>>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T>['props']>, ReturnType<__sveltets_Render<T>['events']>, ReturnType<__sveltets_Render<T>['slots']>> & {
|
|
59
|
+
$$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
|
|
60
|
+
} & ReturnType<__sveltets_Render<T>['exports']>;
|
|
61
|
+
<T extends Record<string, unknown>>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
|
|
62
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
63
|
+
}
|
|
64
|
+
declare const Table: $$IsomorphicComponent;
|
|
65
|
+
type Table<T extends Record<string, unknown>> = InstanceType<typeof Table<T>>;
|
|
66
|
+
export default Table;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
+
import {
|
|
4
|
+
focusRing,
|
|
5
|
+
toneBorder,
|
|
6
|
+
toneRing,
|
|
7
|
+
toneSoft,
|
|
8
|
+
toneText,
|
|
9
|
+
type Tone
|
|
10
|
+
} from '../../core/tones.js';
|
|
11
|
+
|
|
12
|
+
export interface TabItem {
|
|
13
|
+
value: string;
|
|
14
|
+
label: string;
|
|
15
|
+
disabled?: boolean;
|
|
16
|
+
/** Small count/label rendered after the tab title. */
|
|
17
|
+
badge?: string | number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export type TabsVariant = 'underline' | 'pill' | 'segmented';
|
|
21
|
+
|
|
22
|
+
interface Props extends Omit<HTMLAttributes<HTMLDivElement>, 'onchange'> {
|
|
23
|
+
items: TabItem[];
|
|
24
|
+
/** Bindable — the `value` of the active tab. */
|
|
25
|
+
value?: string;
|
|
26
|
+
variant?: TabsVariant;
|
|
27
|
+
tone?: Tone;
|
|
28
|
+
/** Spread tabs evenly across the full width. */
|
|
29
|
+
fullWidth?: boolean;
|
|
30
|
+
onchange?: (value: string) => void;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
let {
|
|
34
|
+
items,
|
|
35
|
+
value = $bindable(items[0]?.value ?? ''),
|
|
36
|
+
variant = 'underline',
|
|
37
|
+
tone = 'brand',
|
|
38
|
+
fullWidth = false,
|
|
39
|
+
onchange,
|
|
40
|
+
class: className = '',
|
|
41
|
+
...rest
|
|
42
|
+
}: Props = $props();
|
|
43
|
+
|
|
44
|
+
function select(item: TabItem) {
|
|
45
|
+
if (item.disabled) return;
|
|
46
|
+
value = item.value;
|
|
47
|
+
onchange?.(item.value);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const listClass = $derived(
|
|
51
|
+
{
|
|
52
|
+
underline: 'gap-5 border-b border-hairline',
|
|
53
|
+
pill: 'gap-1.5',
|
|
54
|
+
segmented: 'gap-1 rounded-lg border border-hairline bg-bg-inset p-1'
|
|
55
|
+
}[variant]
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
function tabClass(active: boolean) {
|
|
59
|
+
const base = `inline-flex items-center justify-center gap-2 font-sans text-sm font-medium whitespace-nowrap transition-all duration-150 ease-brand-out disabled:opacity-40 disabled:pointer-events-none ${focusRing} ${toneRing[tone]}`;
|
|
60
|
+
if (variant === 'underline') {
|
|
61
|
+
return `${base} -mb-px rounded-t-md border-b-2 px-1 pb-2.5 ${
|
|
62
|
+
active
|
|
63
|
+
? `${toneBorder[tone]} ${toneText[tone]}`
|
|
64
|
+
: 'border-transparent text-text-muted hover:text-text'
|
|
65
|
+
}`;
|
|
66
|
+
}
|
|
67
|
+
if (variant === 'pill') {
|
|
68
|
+
return `${base} h-9 rounded-full px-3.5 ${
|
|
69
|
+
active ? toneSoft[tone] : 'text-text-muted hover:bg-bg-inset hover:text-text'
|
|
70
|
+
}`;
|
|
71
|
+
}
|
|
72
|
+
return `${base} h-8 rounded-md px-3.5 ${
|
|
73
|
+
active ? 'bg-bg text-text shadow-xs' : 'text-text-muted hover:text-text'
|
|
74
|
+
}`;
|
|
75
|
+
}
|
|
76
|
+
</script>
|
|
77
|
+
|
|
78
|
+
<div
|
|
79
|
+
role="tablist"
|
|
80
|
+
class="flex items-center overflow-x-auto {listClass} {fullWidth ? '*:flex-1' : ''} {className}"
|
|
81
|
+
{...rest}
|
|
82
|
+
>
|
|
83
|
+
{#each items as item (item.value)}
|
|
84
|
+
<button
|
|
85
|
+
type="button"
|
|
86
|
+
role="tab"
|
|
87
|
+
aria-selected={value === item.value}
|
|
88
|
+
disabled={item.disabled}
|
|
89
|
+
onclick={() => select(item)}
|
|
90
|
+
class={tabClass(value === item.value)}
|
|
91
|
+
>
|
|
92
|
+
{item.label}
|
|
93
|
+
{#if item.badge !== undefined}
|
|
94
|
+
<span
|
|
95
|
+
class="rounded-full bg-bg-inset px-1.5 text-[11px] font-normal text-text-muted tabular-nums"
|
|
96
|
+
>
|
|
97
|
+
{item.badge}
|
|
98
|
+
</span>
|
|
99
|
+
{/if}
|
|
100
|
+
</button>
|
|
101
|
+
{/each}
|
|
102
|
+
</div>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
2
|
+
import { type Tone } from '../../core/tones.js';
|
|
3
|
+
export interface TabItem {
|
|
4
|
+
value: string;
|
|
5
|
+
label: string;
|
|
6
|
+
disabled?: boolean;
|
|
7
|
+
/** Small count/label rendered after the tab title. */
|
|
8
|
+
badge?: string | number;
|
|
9
|
+
}
|
|
10
|
+
export type TabsVariant = 'underline' | 'pill' | 'segmented';
|
|
11
|
+
interface Props extends Omit<HTMLAttributes<HTMLDivElement>, 'onchange'> {
|
|
12
|
+
items: TabItem[];
|
|
13
|
+
/** Bindable — the `value` of the active tab. */
|
|
14
|
+
value?: string;
|
|
15
|
+
variant?: TabsVariant;
|
|
16
|
+
tone?: Tone;
|
|
17
|
+
/** Spread tabs evenly across the full width. */
|
|
18
|
+
fullWidth?: boolean;
|
|
19
|
+
onchange?: (value: string) => void;
|
|
20
|
+
}
|
|
21
|
+
declare const Tabs: import("svelte").Component<Props, {}, "value">;
|
|
22
|
+
type Tabs = ReturnType<typeof Tabs>;
|
|
23
|
+
export default Tabs;
|