@sveltier/ui 0.0.0-stage → 0.1.0-alpha.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/LICENSE +21 -0
- package/README.md +82 -2
- package/dist/components/Accordion/Accordion.svelte +74 -0
- package/dist/components/Accordion/Accordion.svelte.d.ts +25 -0
- package/dist/components/Accordion/accordion.css +88 -0
- package/dist/components/Accordion/index.d.ts +2 -0
- package/dist/components/Accordion/index.js +1 -0
- package/dist/components/Accordion/types.d.ts +64 -0
- package/dist/components/Accordion/types.js +1 -0
- package/dist/components/Alert/Alert.svelte +88 -0
- package/dist/components/Alert/Alert.svelte.d.ts +4 -0
- package/dist/components/Alert/alert.css +78 -0
- package/dist/components/Alert/index.d.ts +2 -0
- package/dist/components/Alert/index.js +1 -0
- package/dist/components/Alert/types.d.ts +67 -0
- package/dist/components/Alert/types.js +1 -0
- package/dist/components/Avatar/Avatar.svelte +47 -0
- package/dist/components/Avatar/Avatar.svelte.d.ts +4 -0
- package/dist/components/Avatar/avatar.css +34 -0
- package/dist/components/Avatar/index.d.ts +2 -0
- package/dist/components/Avatar/index.js +1 -0
- package/dist/components/Avatar/types.d.ts +47 -0
- package/dist/components/Avatar/types.js +1 -0
- package/dist/components/Badge/Badge.svelte +53 -0
- package/dist/components/Badge/Badge.svelte.d.ts +4 -0
- package/dist/components/Badge/badge.css +57 -0
- package/dist/components/Badge/index.d.ts +2 -0
- package/dist/components/Badge/index.js +1 -0
- package/dist/components/Badge/types.d.ts +43 -0
- package/dist/components/Badge/types.js +1 -0
- package/dist/components/Button/Button.svelte +85 -0
- package/dist/components/Button/Button.svelte.d.ts +4 -0
- package/dist/components/Button/button.css +132 -0
- package/dist/components/Button/index.d.ts +2 -0
- package/dist/components/Button/index.js +1 -0
- package/dist/components/Button/types.d.ts +76 -0
- package/dist/components/Button/types.js +1 -0
- package/dist/components/ButtonGroup/ButtonGroup.svelte +61 -0
- package/dist/components/ButtonGroup/ButtonGroup.svelte.d.ts +4 -0
- package/dist/components/ButtonGroup/button-group.css +39 -0
- package/dist/components/ButtonGroup/index.d.ts +2 -0
- package/dist/components/ButtonGroup/index.js +1 -0
- package/dist/components/ButtonGroup/types.d.ts +48 -0
- package/dist/components/ButtonGroup/types.js +1 -0
- package/dist/components/Card/Card.svelte +53 -0
- package/dist/components/Card/Card.svelte.d.ts +4 -0
- package/dist/components/Card/card.css +62 -0
- package/dist/components/Card/index.d.ts +2 -0
- package/dist/components/Card/index.js +1 -0
- package/dist/components/Card/types.d.ts +56 -0
- package/dist/components/Card/types.js +1 -0
- package/dist/components/Checkbox/Checkbox.svelte +105 -0
- package/dist/components/Checkbox/Checkbox.svelte.d.ts +4 -0
- package/dist/components/Checkbox/checkbox.css +138 -0
- package/dist/components/Checkbox/index.d.ts +2 -0
- package/dist/components/Checkbox/index.js +1 -0
- package/dist/components/Checkbox/types.d.ts +76 -0
- package/dist/components/Checkbox/types.js +1 -0
- package/dist/components/Chip/Chip.svelte +109 -0
- package/dist/components/Chip/Chip.svelte.d.ts +4 -0
- package/dist/components/Chip/chip.css +101 -0
- package/dist/components/Chip/index.d.ts +2 -0
- package/dist/components/Chip/index.js +1 -0
- package/dist/components/Chip/types.d.ts +69 -0
- package/dist/components/Chip/types.js +1 -0
- package/dist/components/Choice/Choice.svelte +60 -0
- package/dist/components/Choice/Choice.svelte.d.ts +4 -0
- package/dist/components/Choice/choice.css +75 -0
- package/dist/components/Choice/types.d.ts +43 -0
- package/dist/components/Choice/types.js +1 -0
- package/dist/components/Dialog/Dialog.svelte +36 -0
- package/dist/components/Dialog/Dialog.svelte.d.ts +4 -0
- package/dist/components/Dialog/index.d.ts +2 -0
- package/dist/components/Dialog/index.js +1 -0
- package/dist/components/Dialog/types.d.ts +50 -0
- package/dist/components/Dialog/types.js +1 -0
- package/dist/components/Divider/Divider.svelte +19 -0
- package/dist/components/Divider/Divider.svelte.d.ts +4 -0
- package/dist/components/Divider/divider.css +23 -0
- package/dist/components/Divider/index.d.ts +2 -0
- package/dist/components/Divider/index.js +1 -0
- package/dist/components/Divider/types.d.ts +10 -0
- package/dist/components/Divider/types.js +1 -0
- package/dist/components/Field/Field.svelte +95 -0
- package/dist/components/Field/Field.svelte.d.ts +4 -0
- package/dist/components/Field/field.css +210 -0
- package/dist/components/Field/index.d.ts +3 -0
- package/dist/components/Field/index.js +2 -0
- package/dist/components/Field/types.d.ts +109 -0
- package/dist/components/Field/types.js +2 -0
- package/dist/components/Form/Form.svelte +93 -0
- package/dist/components/Form/Form.svelte.d.ts +8 -0
- package/dist/components/Form/form.css +16 -0
- package/dist/components/Form/index.d.ts +2 -0
- package/dist/components/Form/index.js +1 -0
- package/dist/components/Form/types.d.ts +38 -0
- package/dist/components/Form/types.js +1 -0
- package/dist/components/Icon/Icon.svelte +38 -0
- package/dist/components/Icon/Icon.svelte.d.ts +4 -0
- package/dist/components/Icon/icon.css +33 -0
- package/dist/components/Icon/index.d.ts +2 -0
- package/dist/components/Icon/index.js +1 -0
- package/dist/components/Icon/types.d.ts +34 -0
- package/dist/components/Icon/types.js +1 -0
- package/dist/components/List/List.svelte +39 -0
- package/dist/components/List/List.svelte.d.ts +4 -0
- package/dist/components/List/ListItem.svelte +57 -0
- package/dist/components/List/ListItem.svelte.d.ts +4 -0
- package/dist/components/List/index.d.ts +3 -0
- package/dist/components/List/index.js +2 -0
- package/dist/components/List/list.css +127 -0
- package/dist/components/List/types.d.ts +67 -0
- package/dist/components/List/types.js +1 -0
- package/dist/components/Menu/Menu.svelte +195 -0
- package/dist/components/Menu/Menu.svelte.d.ts +4 -0
- package/dist/components/Menu/index.d.ts +2 -0
- package/dist/components/Menu/index.js +1 -0
- package/dist/components/Menu/menu.css +103 -0
- package/dist/components/Menu/types.d.ts +90 -0
- package/dist/components/Menu/types.js +1 -0
- package/dist/components/Modal/Modal.svelte +146 -0
- package/dist/components/Modal/Modal.svelte.d.ts +4 -0
- package/dist/components/Modal/modal.css +150 -0
- package/dist/components/Modal/types.d.ts +54 -0
- package/dist/components/Modal/types.js +1 -0
- package/dist/components/NativeSelect/NativeSelect.svelte +110 -0
- package/dist/components/NativeSelect/NativeSelect.svelte.d.ts +25 -0
- package/dist/components/NativeSelect/index.d.ts +2 -0
- package/dist/components/NativeSelect/index.js +1 -0
- package/dist/components/NativeSelect/native-select.css +45 -0
- package/dist/components/NativeSelect/types.d.ts +58 -0
- package/dist/components/NativeSelect/types.js +1 -0
- package/dist/components/NumberField/NumberField.svelte +246 -0
- package/dist/components/NumberField/NumberField.svelte.d.ts +4 -0
- package/dist/components/NumberField/index.d.ts +2 -0
- package/dist/components/NumberField/index.js +1 -0
- package/dist/components/NumberField/number-field.css +74 -0
- package/dist/components/NumberField/types.d.ts +73 -0
- package/dist/components/NumberField/types.js +1 -0
- package/dist/components/Popover/Popover.svelte +115 -0
- package/dist/components/Popover/Popover.svelte.d.ts +4 -0
- package/dist/components/Popover/index.d.ts +2 -0
- package/dist/components/Popover/index.js +1 -0
- package/dist/components/Popover/popover.css +67 -0
- package/dist/components/Popover/types.d.ts +83 -0
- package/dist/components/Popover/types.js +1 -0
- package/dist/components/Progress/ProgressCircular.svelte +61 -0
- package/dist/components/Progress/ProgressCircular.svelte.d.ts +4 -0
- package/dist/components/Progress/ProgressLinear.svelte +44 -0
- package/dist/components/Progress/ProgressLinear.svelte.d.ts +4 -0
- package/dist/components/Progress/index.d.ts +3 -0
- package/dist/components/Progress/index.js +2 -0
- package/dist/components/Progress/progress-circular.css +61 -0
- package/dist/components/Progress/progress-linear.css +67 -0
- package/dist/components/Progress/types.d.ts +53 -0
- package/dist/components/Progress/types.js +1 -0
- package/dist/components/RadioGroup/RadioGroup.svelte +149 -0
- package/dist/components/RadioGroup/RadioGroup.svelte.d.ts +25 -0
- package/dist/components/RadioGroup/index.d.ts +2 -0
- package/dist/components/RadioGroup/index.js +1 -0
- package/dist/components/RadioGroup/radio-group.css +139 -0
- package/dist/components/RadioGroup/types.d.ts +93 -0
- package/dist/components/RadioGroup/types.js +1 -0
- package/dist/components/SegmentedControl/SegmentedControl.svelte +70 -0
- package/dist/components/SegmentedControl/SegmentedControl.svelte.d.ts +25 -0
- package/dist/components/SegmentedControl/index.d.ts +2 -0
- package/dist/components/SegmentedControl/index.js +1 -0
- package/dist/components/SegmentedControl/segmented-control.css +68 -0
- package/dist/components/SegmentedControl/types.d.ts +60 -0
- package/dist/components/SegmentedControl/types.js +1 -0
- package/dist/components/Sheet/Sheet.svelte +56 -0
- package/dist/components/Sheet/Sheet.svelte.d.ts +4 -0
- package/dist/components/Sheet/index.d.ts +2 -0
- package/dist/components/Sheet/index.js +2 -0
- package/dist/components/Sheet/sheet.css +61 -0
- package/dist/components/Sheet/types.d.ts +51 -0
- package/dist/components/Sheet/types.js +1 -0
- package/dist/components/Skeleton/Skeleton.svelte +33 -0
- package/dist/components/Skeleton/Skeleton.svelte.d.ts +4 -0
- package/dist/components/Skeleton/index.d.ts +2 -0
- package/dist/components/Skeleton/index.js +1 -0
- package/dist/components/Skeleton/skeleton.css +70 -0
- package/dist/components/Skeleton/types.d.ts +25 -0
- package/dist/components/Skeleton/types.js +1 -0
- package/dist/components/Slider/Slider.svelte +153 -0
- package/dist/components/Slider/Slider.svelte.d.ts +4 -0
- package/dist/components/Slider/index.d.ts +2 -0
- package/dist/components/Slider/index.js +1 -0
- package/dist/components/Slider/slider.css +206 -0
- package/dist/components/Slider/types.d.ts +102 -0
- package/dist/components/Slider/types.js +1 -0
- package/dist/components/Switch/Switch.svelte +94 -0
- package/dist/components/Switch/Switch.svelte.d.ts +4 -0
- package/dist/components/Switch/index.d.ts +2 -0
- package/dist/components/Switch/index.js +1 -0
- package/dist/components/Switch/switch.css +118 -0
- package/dist/components/Switch/types.d.ts +67 -0
- package/dist/components/Switch/types.js +1 -0
- package/dist/components/Tabs/Tabs.svelte +93 -0
- package/dist/components/Tabs/Tabs.svelte.d.ts +25 -0
- package/dist/components/Tabs/index.d.ts +2 -0
- package/dist/components/Tabs/index.js +1 -0
- package/dist/components/Tabs/tabs.css +73 -0
- package/dist/components/Tabs/types.d.ts +59 -0
- package/dist/components/Tabs/types.js +1 -0
- package/dist/components/TextField/TextField.svelte +115 -0
- package/dist/components/TextField/TextField.svelte.d.ts +4 -0
- package/dist/components/TextField/index.d.ts +2 -0
- package/dist/components/TextField/index.js +1 -0
- package/dist/components/TextField/types.d.ts +57 -0
- package/dist/components/TextField/types.js +1 -0
- package/dist/components/Textarea/Textarea.svelte +116 -0
- package/dist/components/Textarea/Textarea.svelte.d.ts +4 -0
- package/dist/components/Textarea/index.d.ts +2 -0
- package/dist/components/Textarea/index.js +1 -0
- package/dist/components/Textarea/textarea.css +35 -0
- package/dist/components/Textarea/types.d.ts +60 -0
- package/dist/components/Textarea/types.js +1 -0
- package/dist/components/Tooltip/Tooltip.svelte +161 -0
- package/dist/components/Tooltip/Tooltip.svelte.d.ts +4 -0
- package/dist/components/Tooltip/index.d.ts +2 -0
- package/dist/components/Tooltip/index.js +1 -0
- package/dist/components/Tooltip/tooltip.css +44 -0
- package/dist/components/Tooltip/types.d.ts +55 -0
- package/dist/components/Tooltip/types.js +1 -0
- package/dist/core/defaults/DefaultsProvider.svelte +30 -0
- package/dist/core/defaults/DefaultsProvider.svelte.d.ts +13 -0
- package/dist/core/defaults/context.d.ts +45 -0
- package/dist/core/defaults/context.js +38 -0
- package/dist/core/display/display.d.ts +39 -0
- package/dist/core/display/display.js +53 -0
- package/dist/core/errors/codes.d.ts +124 -0
- package/dist/core/errors/codes.js +108 -0
- package/dist/core/errors/errors.d.ts +8 -0
- package/dist/core/errors/errors.js +7 -0
- package/dist/core/form/constraints.d.ts +15 -0
- package/dist/core/form/constraints.js +42 -0
- package/dist/core/form/context.d.ts +19 -0
- package/dist/core/form/context.js +4 -0
- package/dist/core/form/field.svelte.d.ts +34 -0
- package/dist/core/form/field.svelte.js +66 -0
- package/dist/core/form/number.d.ts +24 -0
- package/dist/core/form/number.js +71 -0
- package/dist/core/form/types.d.ts +22 -0
- package/dist/core/form/types.js +1 -0
- package/dist/core/locale/locale.d.ts +56 -0
- package/dist/core/locale/locale.js +82 -0
- package/dist/core/overlay/types.d.ts +33 -0
- package/dist/core/overlay/types.js +1 -0
- package/dist/core/props/classes.d.ts +21 -0
- package/dist/core/props/classes.js +44 -0
- package/dist/core/props/element.d.ts +18 -0
- package/dist/core/props/element.js +1 -0
- package/dist/core/props/types.d.ts +47 -0
- package/dist/core/props/types.js +16 -0
- package/dist/core/provider/UIProvider.svelte +63 -0
- package/dist/core/provider/UIProvider.svelte.d.ts +29 -0
- package/dist/core/theme/ThemeProvider.svelte +178 -0
- package/dist/core/theme/ThemeProvider.svelte.d.ts +25 -0
- package/dist/core/theme/color.d.ts +23 -0
- package/dist/core/theme/color.js +54 -0
- package/dist/core/theme/context.d.ts +25 -0
- package/dist/core/theme/context.js +14 -0
- package/dist/core/theme/css.d.ts +25 -0
- package/dist/core/theme/css.js +73 -0
- package/dist/core/theme/define.d.ts +11 -0
- package/dist/core/theme/define.js +21 -0
- package/dist/core/theme/resolve.d.ts +6 -0
- package/dist/core/theme/resolve.js +18 -0
- package/dist/core/theme/theme-provider.css +13 -0
- package/dist/core/theme/types.d.ts +35 -0
- package/dist/core/theme/types.js +61 -0
- package/dist/core/toast/ToastOutlet.svelte +192 -0
- package/dist/core/toast/ToastOutlet.svelte.d.ts +11 -0
- package/dist/core/toast/ToastProvider.svelte +39 -0
- package/dist/core/toast/ToastProvider.svelte.d.ts +19 -0
- package/dist/core/toast/toast.css +134 -0
- package/dist/core/toast/toast.svelte.d.ts +117 -0
- package/dist/core/toast/toast.svelte.js +133 -0
- package/dist/dev/off.d.ts +5 -0
- package/dist/dev/off.js +4 -0
- package/dist/dev/on.d.ts +20 -0
- package/dist/dev/on.js +49 -0
- package/dist/index.d.ts +67 -0
- package/dist/index.js +83 -0
- package/dist/primitives/anchored/anchored.d.ts +39 -0
- package/dist/primitives/anchored/anchored.js +104 -0
- package/dist/primitives/anchored/fallback.d.ts +31 -0
- package/dist/primitives/anchored/fallback.js +73 -0
- package/dist/primitives/focus/focus-trap.d.ts +25 -0
- package/dist/primitives/focus/focus-trap.js +86 -0
- package/dist/primitives/focus/roving-focus.d.ts +22 -0
- package/dist/primitives/focus/roving-focus.js +86 -0
- package/dist/primitives/focus/tabbable.d.ts +9 -0
- package/dist/primitives/focus/tabbable.js +75 -0
- package/dist/primitives/inert/inert-others.d.ts +12 -0
- package/dist/primitives/inert/inert-others.js +44 -0
- package/dist/primitives/keyboard/keymap.d.ts +17 -0
- package/dist/primitives/keyboard/keymap.js +39 -0
- package/dist/primitives/keyboard/typeahead.d.ts +18 -0
- package/dist/primitives/keyboard/typeahead.js +50 -0
- package/dist/primitives/layer/dismissable.d.ts +32 -0
- package/dist/primitives/layer/dismissable.js +91 -0
- package/dist/primitives/motion/easing.d.ts +9 -0
- package/dist/primitives/motion/easing.js +46 -0
- package/dist/primitives/motion/motion.d.ts +59 -0
- package/dist/primitives/motion/motion.js +80 -0
- package/dist/primitives/portal/Portal.svelte +37 -0
- package/dist/primitives/portal/Portal.svelte.d.ts +9 -0
- package/dist/primitives/portal/PortalContent.svelte +15 -0
- package/dist/primitives/portal/PortalContent.svelte.d.ts +9 -0
- package/dist/primitives/portal/portal.css +8 -0
- package/dist/primitives/scroll-lock/scroll-lock.d.ts +10 -0
- package/dist/primitives/scroll-lock/scroll-lock.js +33 -0
- package/dist/primitives/virtual/virtual-list.svelte.d.ts +65 -0
- package/dist/primitives/virtual/virtual-list.svelte.js +291 -0
- package/dist/styles/base.css +44 -0
- package/dist/styles/props.css +140 -0
- package/dist/styles/tokens.css +84 -0
- package/dist/styles/visually-hidden.css +16 -0
- package/dist/themes/aurora.d.ts +13 -0
- package/dist/themes/aurora.js +103 -0
- package/dist/themes/heritage.d.ts +13 -0
- package/dist/themes/heritage.js +102 -0
- package/dist/themes/maison.d.ts +13 -0
- package/dist/themes/maison.js +99 -0
- package/dist/themes/milano.d.ts +13 -0
- package/dist/themes/milano.js +101 -0
- package/dist/themes/monolith.d.ts +13 -0
- package/dist/themes/monolith.js +101 -0
- package/package.json +87 -5
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as ButtonGroup } from './ButtonGroup.svelte';
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
+
import type { ElementProps } from '../../core/props/element.js';
|
|
4
|
+
import type { Color, Density, Rounded, Size, Variant } from '../../core/props/types.js';
|
|
5
|
+
/**
|
|
6
|
+
* The ButtonGroup props that `DefaultsProvider` and `UIProvider` can set for a subtree. The
|
|
7
|
+
* group passes them on to its Buttons.
|
|
8
|
+
*/
|
|
9
|
+
export interface ButtonGroupDefaults {
|
|
10
|
+
/**
|
|
11
|
+
* The variant of the Buttons.
|
|
12
|
+
* @default 'outlined'
|
|
13
|
+
*/
|
|
14
|
+
variant: Variant;
|
|
15
|
+
/**
|
|
16
|
+
* The size of the Buttons.
|
|
17
|
+
* @default 'md'
|
|
18
|
+
*/
|
|
19
|
+
size: Size;
|
|
20
|
+
/**
|
|
21
|
+
* The density of the Buttons.
|
|
22
|
+
* @default 'default'
|
|
23
|
+
*/
|
|
24
|
+
density: Density;
|
|
25
|
+
/**
|
|
26
|
+
* The colour of the Buttons.
|
|
27
|
+
* @default 'primary'
|
|
28
|
+
*/
|
|
29
|
+
color: Color;
|
|
30
|
+
/**
|
|
31
|
+
* The rounding of the group's outer corners; inner corners are square.
|
|
32
|
+
* @default true
|
|
33
|
+
*/
|
|
34
|
+
rounded: Rounded;
|
|
35
|
+
}
|
|
36
|
+
declare module '../../core/defaults/context.js' {
|
|
37
|
+
interface ComponentDefaults {
|
|
38
|
+
ButtonGroup: ButtonGroupDefaults;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Buttons joined into one control: shared borders, square inner corners, and the same
|
|
43
|
+
* variant, size, density and colour unless a Button says otherwise. Give it an `aria-label`.
|
|
44
|
+
*/
|
|
45
|
+
export type ButtonGroupProps = ElementProps<HTMLDivElement, HTMLAttributes<HTMLDivElement>, Partial<ButtonGroupDefaults> & {
|
|
46
|
+
/** The Buttons. */
|
|
47
|
+
children?: Snippet;
|
|
48
|
+
}>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
// A surface with a header, content and actions. See CardProps for the props.
|
|
3
|
+
import { useDefaults } from '../../core/defaults/context.js';
|
|
4
|
+
import { sharedClasses } from '../../core/props/classes.js';
|
|
5
|
+
import './card.css';
|
|
6
|
+
import type { CardDefaults, CardProps } from './types.js';
|
|
7
|
+
|
|
8
|
+
let {
|
|
9
|
+
variant,
|
|
10
|
+
color,
|
|
11
|
+
density,
|
|
12
|
+
rounded,
|
|
13
|
+
title,
|
|
14
|
+
subtitle,
|
|
15
|
+
level,
|
|
16
|
+
prepend,
|
|
17
|
+
append,
|
|
18
|
+
actions,
|
|
19
|
+
children,
|
|
20
|
+
class: className,
|
|
21
|
+
ref = $bindable(null),
|
|
22
|
+
...rest
|
|
23
|
+
}: CardProps = $props();
|
|
24
|
+
|
|
25
|
+
const resolve = useDefaults<CardDefaults>('Card', {
|
|
26
|
+
variant: 'elevated',
|
|
27
|
+
color: 'neutral',
|
|
28
|
+
density: 'default',
|
|
29
|
+
rounded: true
|
|
30
|
+
});
|
|
31
|
+
const p = $derived(resolve({ variant, color, density, rounded }));
|
|
32
|
+
</script>
|
|
33
|
+
|
|
34
|
+
<div bind:this={ref} {...rest} class={['sv-card', sharedClasses(p, 'Card'), className]}>
|
|
35
|
+
{#if title || subtitle || prepend || append}
|
|
36
|
+
<div class="sv-card__header">
|
|
37
|
+
{#if prepend}<div class="sv-card__prepend">{@render prepend()}</div>{/if}
|
|
38
|
+
{#if title || subtitle}
|
|
39
|
+
<div class="sv-card__heading">
|
|
40
|
+
{#if title}
|
|
41
|
+
<svelte:element this={level ? `h${level}` : 'div'} class="sv-card__title">
|
|
42
|
+
{title}
|
|
43
|
+
</svelte:element>
|
|
44
|
+
{/if}
|
|
45
|
+
{#if subtitle}<div class="sv-card__subtitle">{subtitle}</div>{/if}
|
|
46
|
+
</div>
|
|
47
|
+
{/if}
|
|
48
|
+
{#if append}<div class="sv-card__append">{@render append()}</div>{/if}
|
|
49
|
+
</div>
|
|
50
|
+
{/if}
|
|
51
|
+
{@render children?.()}
|
|
52
|
+
{#if actions}<div class="sv-card__actions">{@render actions()}</div>{/if}
|
|
53
|
+
</div>
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
@layer sv.tokens, sv.base, sv.components, sv.utilities;
|
|
2
|
+
|
|
3
|
+
@layer sv.components {
|
|
4
|
+
/* Sections a φ step apart inside Fibonacci padding, both times the density. */
|
|
5
|
+
.sv-card {
|
|
6
|
+
display: flex;
|
|
7
|
+
flex-direction: column;
|
|
8
|
+
gap: calc(var(--sv-space-13) * var(--sv-density));
|
|
9
|
+
box-sizing: border-box;
|
|
10
|
+
min-inline-size: 0;
|
|
11
|
+
padding: calc(var(--sv-space-21) * var(--sv-density));
|
|
12
|
+
border: var(--sv-hairline) solid var(--sv-variant-border);
|
|
13
|
+
border-radius: var(--sv-rounded, var(--sv-radius-lg));
|
|
14
|
+
background-color: var(--sv-variant-bg);
|
|
15
|
+
box-shadow: var(--sv-variant-shadow);
|
|
16
|
+
color: var(--sv-variant-fg);
|
|
17
|
+
font-size: var(--sv-text-sm);
|
|
18
|
+
line-height: var(--sv-leading-normal);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/* A neutral outline is the theme's border, not the text colour. */
|
|
22
|
+
.sv-card.sv-variant-outlined.sv-color-neutral {
|
|
23
|
+
--sv-variant-border: var(--sv-color-border);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.sv-card__header {
|
|
27
|
+
display: flex;
|
|
28
|
+
gap: var(--sv-space-13);
|
|
29
|
+
align-items: center;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.sv-card__heading {
|
|
33
|
+
display: grid;
|
|
34
|
+
flex: 1;
|
|
35
|
+
gap: var(--sv-space-3);
|
|
36
|
+
min-inline-size: 0;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.sv-card__title {
|
|
40
|
+
margin: 0;
|
|
41
|
+
font: var(--sv-weight-display) var(--sv-text-lg) / var(--sv-leading-snug) var(--sv-font-display);
|
|
42
|
+
letter-spacing: var(--sv-tracking-display);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.sv-card__subtitle {
|
|
46
|
+
font-size: var(--sv-text-xs);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.sv-card__prepend,
|
|
50
|
+
.sv-card__append {
|
|
51
|
+
display: flex;
|
|
52
|
+
flex: none;
|
|
53
|
+
align-items: center;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.sv-card__actions {
|
|
57
|
+
display: flex;
|
|
58
|
+
flex-wrap: wrap;
|
|
59
|
+
gap: var(--sv-space-8);
|
|
60
|
+
align-items: center;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Card } from './Card.svelte';
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
+
import type { ElementProps } from '../../core/props/element.js';
|
|
4
|
+
import type { Color, Density, Rounded, Variant } from '../../core/props/types.js';
|
|
5
|
+
/** The Card props that `DefaultsProvider` and `UIProvider` can set for a subtree. */
|
|
6
|
+
export interface CardDefaults {
|
|
7
|
+
/**
|
|
8
|
+
* Visual weight: a raised surface by default.
|
|
9
|
+
* @default 'elevated'
|
|
10
|
+
*/
|
|
11
|
+
variant: Variant;
|
|
12
|
+
/**
|
|
13
|
+
* The colour the variant is painted with. Neutral cards use the theme's surface, text and
|
|
14
|
+
* border colours.
|
|
15
|
+
* @default 'neutral'
|
|
16
|
+
*/
|
|
17
|
+
color: Color;
|
|
18
|
+
/**
|
|
19
|
+
* Multiplies the padding and the space between sections.
|
|
20
|
+
* @default 'default'
|
|
21
|
+
*/
|
|
22
|
+
density: Density;
|
|
23
|
+
/**
|
|
24
|
+
* Corner rounding. `true` keeps the theme's radius.
|
|
25
|
+
* @default true
|
|
26
|
+
*/
|
|
27
|
+
rounded: Rounded;
|
|
28
|
+
}
|
|
29
|
+
declare module '../../core/defaults/context.js' {
|
|
30
|
+
interface ComponentDefaults {
|
|
31
|
+
Card: CardDefaults;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* A surface that groups content about one thing: a header, the content and actions. Links
|
|
36
|
+
* and buttons inside it are what is clickable, not the card.
|
|
37
|
+
*/
|
|
38
|
+
export type CardProps = ElementProps<HTMLDivElement, HTMLAttributes<HTMLDivElement>, Partial<CardDefaults> & {
|
|
39
|
+
/** The title, in the header. */
|
|
40
|
+
title?: string;
|
|
41
|
+
/** A line under the title. */
|
|
42
|
+
subtitle?: string;
|
|
43
|
+
/**
|
|
44
|
+
* Makes the title a heading of this level (`<h2>`, `<h3>`…), so it is in the page's
|
|
45
|
+
* outline. Without it the title is styled text.
|
|
46
|
+
*/
|
|
47
|
+
level?: 1 | 2 | 3 | 4 | 5 | 6;
|
|
48
|
+
/** Content before the title, such as an avatar or an icon. */
|
|
49
|
+
prepend?: Snippet;
|
|
50
|
+
/** Content after the title, such as a menu button. */
|
|
51
|
+
append?: Snippet;
|
|
52
|
+
/** Buttons or links at the bottom. */
|
|
53
|
+
actions?: Snippet;
|
|
54
|
+
/** The content. */
|
|
55
|
+
children?: Snippet;
|
|
56
|
+
}>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
// A box that is checked or not, with its label beside it and validation. See CheckboxProps.
|
|
3
|
+
import { untrack } from 'svelte';
|
|
4
|
+
import { DEV, warnUnnamed } from '#dev';
|
|
5
|
+
import { useDefaults } from '../../core/defaults/context.js';
|
|
6
|
+
import { createField } from '../../core/form/field.svelte.js';
|
|
7
|
+
import { useLocale } from '../../core/locale/locale.js';
|
|
8
|
+
import { sharedClasses } from '../../core/props/classes.js';
|
|
9
|
+
import Choice from '../Choice/Choice.svelte';
|
|
10
|
+
import './checkbox.css';
|
|
11
|
+
import type { CheckboxDefaults, CheckboxProps } from './types.js';
|
|
12
|
+
|
|
13
|
+
let {
|
|
14
|
+
color,
|
|
15
|
+
size,
|
|
16
|
+
density,
|
|
17
|
+
disabled,
|
|
18
|
+
checked = $bindable(false),
|
|
19
|
+
indeterminate = $bindable(false),
|
|
20
|
+
label,
|
|
21
|
+
hint,
|
|
22
|
+
error,
|
|
23
|
+
rules,
|
|
24
|
+
validateOn,
|
|
25
|
+
required = false,
|
|
26
|
+
id,
|
|
27
|
+
'aria-describedby': describedBy,
|
|
28
|
+
class: className,
|
|
29
|
+
style,
|
|
30
|
+
ref = $bindable(null),
|
|
31
|
+
...rest
|
|
32
|
+
}: CheckboxProps = $props();
|
|
33
|
+
|
|
34
|
+
const resolve = useDefaults<CheckboxDefaults>('Checkbox', {
|
|
35
|
+
color: 'primary',
|
|
36
|
+
size: 'md',
|
|
37
|
+
density: 'default',
|
|
38
|
+
disabled: false
|
|
39
|
+
});
|
|
40
|
+
const p = $derived(resolve({ color, size, density, disabled }));
|
|
41
|
+
const locale = useLocale();
|
|
42
|
+
// A form reset goes back to the state the box started in, as it does for a form rendered on
|
|
43
|
+
// the server.
|
|
44
|
+
const initial = untrack(() => checked ?? false);
|
|
45
|
+
|
|
46
|
+
const field = createField<boolean>({
|
|
47
|
+
value: () => checked ?? false,
|
|
48
|
+
// Rules run on a checked box only, as they run on a filled field only.
|
|
49
|
+
empty: (on) => !on,
|
|
50
|
+
check: (on) => (!on && required ? locale.t('required') : undefined),
|
|
51
|
+
rules: () => rules,
|
|
52
|
+
error: () => error,
|
|
53
|
+
validateOn: () => validateOn,
|
|
54
|
+
control: () => ref
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
if (DEV) $effect(() => warnUnnamed('Checkbox', ref));
|
|
58
|
+
|
|
59
|
+
// A toggle is a whole edit, so it also counts as leaving: the message shows at once, even in
|
|
60
|
+
// Safari, where a click does not focus the checkbox.
|
|
61
|
+
function toggled() {
|
|
62
|
+
field.changed();
|
|
63
|
+
field.left();
|
|
64
|
+
}
|
|
65
|
+
</script>
|
|
66
|
+
|
|
67
|
+
<Choice
|
|
68
|
+
{id}
|
|
69
|
+
{label}
|
|
70
|
+
{hint}
|
|
71
|
+
error={field.error}
|
|
72
|
+
{required}
|
|
73
|
+
disabled={p.disabled}
|
|
74
|
+
class={[
|
|
75
|
+
'sv-checkbox',
|
|
76
|
+
sharedClasses(p, 'Checkbox'),
|
|
77
|
+
indeterminate && 'sv-checkbox--indeterminate',
|
|
78
|
+
className
|
|
79
|
+
]}
|
|
80
|
+
{style}
|
|
81
|
+
onchange={toggled}
|
|
82
|
+
>
|
|
83
|
+
{#snippet children(attributes)}
|
|
84
|
+
<span class="sv-checkbox__control">
|
|
85
|
+
<input
|
|
86
|
+
bind:this={ref}
|
|
87
|
+
defaultChecked={initial}
|
|
88
|
+
{...rest}
|
|
89
|
+
{...attributes}
|
|
90
|
+
aria-describedby={[describedBy, attributes['aria-describedby']].filter(Boolean).join(' ') ||
|
|
91
|
+
undefined}
|
|
92
|
+
type="checkbox"
|
|
93
|
+
class="sv-checkbox__input"
|
|
94
|
+
bind:checked
|
|
95
|
+
bind:indeterminate
|
|
96
|
+
/>
|
|
97
|
+
<span class="sv-checkbox__box" aria-hidden="true">
|
|
98
|
+
<svg class="sv-checkbox__mark" viewBox="0 0 24 24" focusable="false">
|
|
99
|
+
<path class="sv-checkbox__check" d="M5 12.5l4.5 4.5 9.5-9.5" />
|
|
100
|
+
<path class="sv-checkbox__dash" d="M6.5 12h11" />
|
|
101
|
+
</svg>
|
|
102
|
+
</span>
|
|
103
|
+
</span>
|
|
104
|
+
{/snippet}
|
|
105
|
+
</Choice>
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
@layer sv.tokens, sv.base, sv.components, sv.utilities;
|
|
2
|
+
|
|
3
|
+
@layer sv.components {
|
|
4
|
+
/* The box is as tall as a line of the label, 1.272em with the label's √φ line height. */
|
|
5
|
+
.sv-checkbox {
|
|
6
|
+
--sv-checkbox-size: 1.272em;
|
|
7
|
+
--sv-checkbox-border: calc(var(--sv-hairline) * 1.5);
|
|
8
|
+
--sv-choice-control: var(--sv-checkbox-size);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/*
|
|
12
|
+
* The native input lies over the drawn box, invisible, so focus, keys, forms and autofill stay
|
|
13
|
+
* native. The box sits on the first line of the label.
|
|
14
|
+
*/
|
|
15
|
+
.sv-checkbox__control {
|
|
16
|
+
position: relative;
|
|
17
|
+
display: inline-flex;
|
|
18
|
+
flex: none;
|
|
19
|
+
margin-block-start: calc((1lh - var(--sv-checkbox-size)) / 2);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.sv-checkbox__input {
|
|
23
|
+
position: absolute;
|
|
24
|
+
inset: 0;
|
|
25
|
+
inline-size: 100%;
|
|
26
|
+
block-size: 100%;
|
|
27
|
+
margin: 0;
|
|
28
|
+
opacity: 0;
|
|
29
|
+
cursor: inherit;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/* Never rounder than a quarter of its side, so a checkbox does not pass for a radio. */
|
|
33
|
+
.sv-checkbox__box {
|
|
34
|
+
position: relative;
|
|
35
|
+
display: grid;
|
|
36
|
+
place-items: center;
|
|
37
|
+
box-sizing: border-box;
|
|
38
|
+
inline-size: var(--sv-checkbox-size);
|
|
39
|
+
block-size: var(--sv-checkbox-size);
|
|
40
|
+
border: var(--sv-checkbox-border) solid var(--sv-color-border-strong);
|
|
41
|
+
border-radius: min(var(--sv-radius-sm), var(--sv-checkbox-size) * 0.236);
|
|
42
|
+
background-color: var(--sv-color-surface);
|
|
43
|
+
color: var(--sv-on-color);
|
|
44
|
+
pointer-events: none;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/* The fill (before) and the state layer (after) cover the border. */
|
|
48
|
+
.sv-checkbox__box::before,
|
|
49
|
+
.sv-checkbox__box::after {
|
|
50
|
+
content: '';
|
|
51
|
+
position: absolute;
|
|
52
|
+
inset: calc(var(--sv-checkbox-border) * -1);
|
|
53
|
+
border-radius: inherit;
|
|
54
|
+
opacity: 0;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.sv-checkbox__box::before {
|
|
58
|
+
background-color: var(--sv-color);
|
|
59
|
+
transform: scale(0.618);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.sv-checkbox__box::after {
|
|
63
|
+
background-color: var(--sv-color-text);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.sv-checkbox__mark {
|
|
67
|
+
position: relative;
|
|
68
|
+
inline-size: 100%;
|
|
69
|
+
block-size: 100%;
|
|
70
|
+
fill: none;
|
|
71
|
+
stroke: currentColor;
|
|
72
|
+
stroke-width: 3;
|
|
73
|
+
stroke-linecap: round;
|
|
74
|
+
stroke-linejoin: round;
|
|
75
|
+
opacity: 0;
|
|
76
|
+
transform: scale(0.618);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/* A check scales in with its fill; nothing else moves. */
|
|
80
|
+
.sv-checkbox__box::before,
|
|
81
|
+
.sv-checkbox__mark {
|
|
82
|
+
transition:
|
|
83
|
+
opacity var(--sv-duration-fast) var(--sv-ease),
|
|
84
|
+
transform var(--sv-duration-fast) var(--sv-ease);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.sv-checkbox__input:checked + .sv-checkbox__box::before,
|
|
88
|
+
.sv-checkbox__input:checked + .sv-checkbox__box .sv-checkbox__mark,
|
|
89
|
+
.sv-checkbox--indeterminate .sv-checkbox__box::before,
|
|
90
|
+
.sv-checkbox--indeterminate .sv-checkbox__mark {
|
|
91
|
+
opacity: 1;
|
|
92
|
+
transform: none;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.sv-checkbox__input:checked + .sv-checkbox__box::after,
|
|
96
|
+
.sv-checkbox--indeterminate .sv-checkbox__box::after {
|
|
97
|
+
background-color: var(--sv-on-color);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/* The dash stands in for the check while the state is indeterminate. */
|
|
101
|
+
.sv-checkbox__dash,
|
|
102
|
+
.sv-checkbox--indeterminate .sv-checkbox__check {
|
|
103
|
+
display: none;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.sv-checkbox--indeterminate .sv-checkbox__dash {
|
|
107
|
+
display: inline;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/*
|
|
111
|
+
* Hover and press mix the mark's colour over the box, as they do over a flat Button. The
|
|
112
|
+
* disabled guard adds no weight, so an invalid box keeps its error border under the pointer.
|
|
113
|
+
*/
|
|
114
|
+
@media (hover: hover) {
|
|
115
|
+
:where(.sv-checkbox:not(.sv-choice--disabled)) > .sv-choice__row:hover .sv-checkbox__box {
|
|
116
|
+
border-color: var(--sv-color-text-muted);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
:where(.sv-checkbox:not(.sv-choice--disabled))
|
|
120
|
+
> .sv-choice__row:hover
|
|
121
|
+
.sv-checkbox__box::after {
|
|
122
|
+
opacity: var(--sv-state-hover);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
:where(.sv-checkbox:not(.sv-choice--disabled)) > .sv-choice__row:active .sv-checkbox__box::after {
|
|
127
|
+
opacity: var(--sv-state-press);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.sv-checkbox__input:focus-visible + .sv-checkbox__box {
|
|
131
|
+
outline: var(--sv-focus-width) solid var(--sv-color);
|
|
132
|
+
outline-offset: var(--sv-focus-offset);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.sv-choice--invalid > .sv-choice__row .sv-checkbox__box {
|
|
136
|
+
border-color: var(--sv-color-error);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Checkbox } from './Checkbox.svelte';
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { HTMLInputAttributes } from 'svelte/elements';
|
|
2
|
+
import type { Rule, ValidateOn } from '../../core/form/types.js';
|
|
3
|
+
import type { ElementProps } from '../../core/props/element.js';
|
|
4
|
+
import type { Color, Density, Size } from '../../core/props/types.js';
|
|
5
|
+
import type { ChoiceContentProps } from '../Choice/types.js';
|
|
6
|
+
/** The Checkbox props that `DefaultsProvider` and `UIProvider` can set for a subtree. */
|
|
7
|
+
export interface CheckboxDefaults {
|
|
8
|
+
/**
|
|
9
|
+
* The colour of the checked box. An invalid checkbox uses `error`.
|
|
10
|
+
* @default 'primary'
|
|
11
|
+
*/
|
|
12
|
+
color: Color;
|
|
13
|
+
/**
|
|
14
|
+
* The size of the box and the label text.
|
|
15
|
+
* @default 'md'
|
|
16
|
+
*/
|
|
17
|
+
size: Size;
|
|
18
|
+
/**
|
|
19
|
+
* Multiplies the height of the row, never the text.
|
|
20
|
+
* @default 'default'
|
|
21
|
+
*/
|
|
22
|
+
density: Density;
|
|
23
|
+
/**
|
|
24
|
+
* Mutes the checkbox and disables its input.
|
|
25
|
+
* @default false
|
|
26
|
+
*/
|
|
27
|
+
disabled: boolean;
|
|
28
|
+
}
|
|
29
|
+
declare module '../../core/defaults/context.js' {
|
|
30
|
+
interface ComponentDefaults {
|
|
31
|
+
Checkbox: CheckboxDefaults;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
type CheckboxOwnProps = Partial<CheckboxDefaults> & ChoiceContentProps & {
|
|
35
|
+
/**
|
|
36
|
+
* Whether the box is checked. Bindable.
|
|
37
|
+
* @default false
|
|
38
|
+
*/
|
|
39
|
+
checked?: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Shows a dash for a state that is neither checked nor unchecked, such as a "select all"
|
|
42
|
+
* box over a partly selected list. A press clears it. Bindable.
|
|
43
|
+
* @default false
|
|
44
|
+
*/
|
|
45
|
+
indeterminate?: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* What the form submits under `name` while the box is checked.
|
|
48
|
+
* @default 'on'
|
|
49
|
+
*/
|
|
50
|
+
value?: string;
|
|
51
|
+
/** Checks run in order after `required`, with the checked state. The first message is shown. */
|
|
52
|
+
rules?: readonly Rule<boolean>[];
|
|
53
|
+
/** When the message shows. Defaults to the form's setting, else `'blur'`. */
|
|
54
|
+
validateOn?: ValidateOn;
|
|
55
|
+
/**
|
|
56
|
+
* The box must be checked, as for accepting terms. Adds an asterisk to the label.
|
|
57
|
+
* @default false
|
|
58
|
+
*/
|
|
59
|
+
required?: boolean;
|
|
60
|
+
/** Inline style of the checkbox's root element. */
|
|
61
|
+
style?: string | null;
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* A box that is checked or not, with its label beside it: the platform's own checkbox, drawn in
|
|
65
|
+
* the theme. `class` and `style` apply to the root; `id`, `ref`, `name` and every other attribute
|
|
66
|
+
* go to the `<input type="checkbox">`. The label is the press target, at least 24px tall.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* <Checkbox label="Email me a receipt" name="receipt" bind:checked={receipt} />
|
|
70
|
+
*
|
|
71
|
+
* <Checkbox name="terms" required bind:checked={accepted}>
|
|
72
|
+
* {#snippet label()}I accept the <a href="/terms">terms of service</a>{/snippet}
|
|
73
|
+
* </Checkbox>
|
|
74
|
+
*/
|
|
75
|
+
export type CheckboxProps = ElementProps<HTMLInputElement, Omit<HTMLInputAttributes, 'type' | 'children'>, CheckboxOwnProps>;
|
|
76
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
// A tag, a filter, an action or a link, as a compact pill. See ChipProps for the props.
|
|
3
|
+
import { useDefaults } from '../../core/defaults/context.js';
|
|
4
|
+
import { sveltierError } from '../../core/errors/errors.js';
|
|
5
|
+
import { useLocale } from '../../core/locale/locale.js';
|
|
6
|
+
import { sharedClasses } from '../../core/props/classes.js';
|
|
7
|
+
import './chip.css';
|
|
8
|
+
import type { ChipDefaults, ChipProps } from './types.js';
|
|
9
|
+
|
|
10
|
+
let {
|
|
11
|
+
variant,
|
|
12
|
+
size,
|
|
13
|
+
density,
|
|
14
|
+
color,
|
|
15
|
+
rounded,
|
|
16
|
+
disabled,
|
|
17
|
+
selected = $bindable(),
|
|
18
|
+
closable = false,
|
|
19
|
+
closeLabel,
|
|
20
|
+
onclose,
|
|
21
|
+
href,
|
|
22
|
+
onclick,
|
|
23
|
+
prepend,
|
|
24
|
+
append,
|
|
25
|
+
children,
|
|
26
|
+
class: className,
|
|
27
|
+
ref = $bindable(null),
|
|
28
|
+
...rest
|
|
29
|
+
}: ChipProps = $props();
|
|
30
|
+
|
|
31
|
+
const resolve = useDefaults<ChipDefaults>('Chip', {
|
|
32
|
+
variant: 'tonal',
|
|
33
|
+
size: 'sm',
|
|
34
|
+
density: 'default',
|
|
35
|
+
color: 'neutral',
|
|
36
|
+
rounded: true,
|
|
37
|
+
disabled: false
|
|
38
|
+
});
|
|
39
|
+
const p = $derived(resolve({ variant, size, density, color, rounded, disabled }));
|
|
40
|
+
const locale = useLocale();
|
|
41
|
+
|
|
42
|
+
const toggle = $derived(selected !== undefined);
|
|
43
|
+
const tag = $derived.by(() => {
|
|
44
|
+
const element = href != null ? 'a' : toggle || onclick ? 'button' : 'span';
|
|
45
|
+
// A close button inside a button or a link would nest one control in another.
|
|
46
|
+
if (closable && element !== 'span') {
|
|
47
|
+
throw sveltierError(
|
|
48
|
+
'SV4001',
|
|
49
|
+
'Chip: a closable chip cannot also be a button or a link, since its close button would sit inside it. Put the action in a Button next to the chip.'
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
return element;
|
|
53
|
+
});
|
|
54
|
+
const action = $derived(tag !== 'span');
|
|
55
|
+
|
|
56
|
+
function click(event: MouseEvent) {
|
|
57
|
+
if (p.disabled) {
|
|
58
|
+
event.preventDefault();
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
if (toggle) selected = !selected;
|
|
62
|
+
(onclick as ((event: MouseEvent) => void) | null | undefined)?.(event);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const CHECK = 'M4 12.5 5.5 11l4 4 9-9L20 7.5 9.5 18z';
|
|
66
|
+
const CLOSE =
|
|
67
|
+
'M6.4 5 12 10.6 17.6 5 19 6.4 13.4 12l5.6 5.6-1.4 1.4-5.6-5.6L6.4 19 5 17.6l5.6-5.6L5 6.4z';
|
|
68
|
+
</script>
|
|
69
|
+
|
|
70
|
+
<svelte:element
|
|
71
|
+
this={tag}
|
|
72
|
+
bind:this={ref}
|
|
73
|
+
{...rest}
|
|
74
|
+
href={tag === 'a' && !p.disabled ? href : undefined}
|
|
75
|
+
type={tag === 'button' ? 'button' : undefined}
|
|
76
|
+
role={tag === 'a' && p.disabled ? 'link' : undefined}
|
|
77
|
+
disabled={(tag === 'button' && p.disabled) || undefined}
|
|
78
|
+
aria-disabled={(tag === 'a' && p.disabled) || undefined}
|
|
79
|
+
aria-pressed={toggle ? selected : undefined}
|
|
80
|
+
class={[
|
|
81
|
+
'sv-chip',
|
|
82
|
+
sharedClasses({ ...p, variant: selected ? 'flat' : p.variant }, 'Chip'),
|
|
83
|
+
action && 'sv-chip--action',
|
|
84
|
+
p.disabled && 'sv-chip--disabled',
|
|
85
|
+
className
|
|
86
|
+
]}
|
|
87
|
+
onclick={action ? click : undefined}
|
|
88
|
+
>
|
|
89
|
+
{#if selected}
|
|
90
|
+
<span class="sv-chip__prepend">
|
|
91
|
+
<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d={CHECK} /></svg>
|
|
92
|
+
</span>
|
|
93
|
+
{:else if prepend}
|
|
94
|
+
<span class="sv-chip__prepend">{@render prepend()}</span>
|
|
95
|
+
{/if}
|
|
96
|
+
{#if children}<span class="sv-chip__label">{@render children()}</span>{/if}
|
|
97
|
+
{#if append}<span class="sv-chip__append">{@render append()}</span>{/if}
|
|
98
|
+
{#if closable}
|
|
99
|
+
<button
|
|
100
|
+
type="button"
|
|
101
|
+
class="sv-chip__close"
|
|
102
|
+
aria-label={closeLabel ?? locale.t('close')}
|
|
103
|
+
disabled={p.disabled}
|
|
104
|
+
onclick={() => onclose?.()}
|
|
105
|
+
>
|
|
106
|
+
<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d={CLOSE} /></svg>
|
|
107
|
+
</button>
|
|
108
|
+
{/if}
|
|
109
|
+
</svelte:element>
|