@noxlovette/material 0.6.0 → 0.7.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/claude-skill/material-design/SKILL.md +5 -2
- package/claude-skill/material-design/references/accessibility-checklist.md +5 -0
- package/claude-skill/material-design/references/component-patterns.md +24 -3
- package/claude-skill/material-design/references/motion-guide.md +53 -11
- package/claude-skill/material-design/references/tokens-and-styles.md +4 -0
- package/dist/animation/TransitionPatterns.stories.svelte +50 -0
- package/dist/animation/containerTransform.js +10 -4
- package/dist/animation/reducedMotion.d.ts +2 -0
- package/dist/animation/reducedMotion.js +2 -0
- package/dist/animation/sharedAxisTransition.d.ts +20 -3
- package/dist/animation/sharedAxisTransition.js +67 -8
- package/dist/attachments/drag.d.ts +52 -0
- package/dist/attachments/drag.js +217 -0
- package/dist/attachments/index.d.ts +1 -0
- package/dist/attachments/index.js +1 -0
- package/dist/components/badge/theme.js +1 -1
- package/dist/components/buttons/button-group/theme.d.ts +1 -1
- package/dist/components/buttons/button-group/theme.js +1 -1
- package/dist/components/buttons/connected/theme.d.ts +1 -1
- package/dist/components/buttons/connected/theme.js +1 -1
- package/dist/components/buttons/split-button/SplitButton.svelte +1 -1
- package/dist/components/buttons/split-button/theme.d.ts +1 -1
- package/dist/components/buttons/split-button/theme.js +1 -1
- package/dist/components/buttons/theme.d.ts +1 -1
- package/dist/components/buttons/theme.js +3 -3
- package/dist/components/cards/theme.js +1 -1
- package/dist/components/chips/Chip.mdx +24 -11
- package/dist/components/chips/Chip.stories.svelte +10 -0
- package/dist/components/chips/Chip.svelte +58 -18
- package/dist/components/chips/Chip.svelte.d.ts +3 -1
- package/dist/components/chips/ChipGroup.stories.svelte +73 -0
- package/dist/components/chips/ChipGroup.stories.svelte.d.ts +4 -0
- package/dist/components/chips/ChipGroup.svelte +242 -0
- package/dist/components/chips/ChipGroup.svelte.d.ts +33 -0
- package/dist/components/chips/index.d.ts +1 -0
- package/dist/components/chips/index.js +1 -0
- package/dist/components/chips/theme.d.ts +183 -22
- package/dist/components/chips/theme.js +117 -26
- package/dist/components/chips/types.d.ts +36 -2
- package/dist/components/containers/action-rail/theme.d.ts +1 -1
- package/dist/components/containers/action-rail/theme.js +2 -2
- package/dist/components/containers/app/theme.d.ts +2 -2
- package/dist/components/containers/app/theme.js +2 -2
- package/dist/components/containers/bottom-sheet/BottomSheet.stories.svelte +1 -1
- package/dist/components/containers/bottom-sheet/theme.d.ts +1 -1
- package/dist/components/containers/bottom-sheet/theme.js +2 -2
- package/dist/components/containers/carousel/theme.d.ts +1 -1
- package/dist/components/containers/carousel/theme.js +1 -1
- package/dist/components/containers/context-menu/theme.d.ts +1 -1
- package/dist/components/containers/context-menu/theme.js +2 -2
- package/dist/components/containers/dialogue/Dialogue.svelte +1 -1
- package/dist/components/containers/dialogue/theme.d.ts +1 -1
- package/dist/components/containers/dialogue/theme.js +3 -3
- package/dist/components/containers/dialogue/types.d.ts +1 -1
- package/dist/components/containers/divider/theme.d.ts +1 -1
- package/dist/components/containers/divider/theme.js +1 -1
- package/dist/components/containers/link-preview/theme.d.ts +1 -1
- package/dist/components/containers/link-preview/theme.js +2 -2
- package/dist/components/containers/list/List.svelte +8 -2
- package/dist/components/containers/list/ListItem.mdx +6 -0
- package/dist/components/containers/list/ListItem.svelte +77 -2
- package/dist/components/containers/list/context.d.ts +14 -0
- package/dist/components/containers/list/theme.d.ts +7 -1
- package/dist/components/containers/list/theme.js +11 -3
- package/dist/components/containers/menu/Menu.svelte +1 -1
- package/dist/components/containers/menu/MenuSub.svelte +1 -1
- package/dist/components/containers/menu/theme.d.ts +1 -1
- package/dist/components/containers/menu/theme.js +1 -1
- package/dist/components/containers/pane/DraggablePane.svelte +25 -63
- package/dist/components/containers/pane/Pane.svelte +1 -1
- package/dist/components/containers/pane/theme.d.ts +1 -1
- package/dist/components/containers/pane/theme.js +35 -9
- package/dist/components/containers/popover/theme.d.ts +4 -4
- package/dist/components/containers/popover/theme.js +2 -2
- package/dist/components/containers/scroll-area/theme.js +1 -1
- package/dist/components/containers/side-sheet/theme.d.ts +1 -1
- package/dist/components/containers/side-sheet/theme.js +1 -1
- package/dist/components/date/theme.d.ts +7 -7
- package/dist/components/date/theme.js +1 -1
- package/dist/components/forms/checkbox/theme.d.ts +1 -1
- package/dist/components/forms/checkbox/theme.js +2 -2
- package/dist/components/forms/command/theme.d.ts +4 -4
- package/dist/components/forms/command/theme.js +1 -1
- package/dist/components/forms/pin/theme.d.ts +1 -1
- package/dist/components/forms/pin/theme.js +1 -1
- package/dist/components/forms/radio-group/theme.d.ts +1 -1
- package/dist/components/forms/radio-group/theme.js +1 -1
- package/dist/components/forms/search/theme.d.ts +1 -1
- package/dist/components/forms/search/theme.js +1 -1
- package/dist/components/forms/select/Select.svelte +2 -2
- package/dist/components/forms/select/theme.d.ts +1 -1
- package/dist/components/forms/select/theme.js +2 -2
- package/dist/components/forms/slider/theme.d.ts +1 -1
- package/dist/components/forms/slider/theme.js +1 -1
- package/dist/components/forms/switch/theme.d.ts +1 -1
- package/dist/components/forms/switch/theme.js +1 -1
- package/dist/components/forms/textfield/theme.d.ts +1 -1
- package/dist/components/forms/textfield/theme.js +1 -1
- package/dist/components/forms/toggle-group/theme.d.ts +1 -1
- package/dist/components/forms/toggle-group/theme.js +1 -1
- package/dist/components/forms/tooltip/theme.d.ts +1 -1
- package/dist/components/forms/tooltip/theme.js +2 -2
- package/dist/components/misc/Avatar.stories.svelte +56 -7
- package/dist/components/misc/Avatar.stories.svelte.d.ts +2 -17
- package/dist/components/misc/Avatar.svelte +82 -8
- package/dist/components/misc/Avatar.svelte.d.ts +5 -0
- package/dist/components/misc/ThemeSwitcher.svelte +1 -1
- package/dist/components/misc/theme.d.ts +6 -0
- package/dist/components/misc/theme.js +6 -4
- package/dist/components/misc/types.d.ts +17 -1
- package/dist/components/nav/appbar/theme.d.ts +1 -1
- package/dist/components/nav/appbar/theme.js +3 -2
- package/dist/components/nav/breadcrumb/theme.d.ts +1 -1
- package/dist/components/nav/breadcrumb/theme.js +1 -1
- package/dist/components/nav/currentRoute.d.ts +11 -0
- package/dist/components/nav/currentRoute.js +28 -0
- package/dist/components/nav/navbar/NavbarItem.svelte +3 -6
- package/dist/components/nav/navbar/theme.d.ts +3 -3
- package/dist/components/nav/navbar/theme.js +2 -2
- package/dist/components/nav/rail/Rail.mdx +65 -23
- package/dist/components/nav/rail/Rail.stories.svelte +24 -4
- package/dist/components/nav/rail/Rail.stories.svelte.d.ts +2 -17
- package/dist/components/nav/rail/Rail.svelte +165 -48
- package/dist/components/nav/rail/Rail.svelte.d.ts +6 -3
- package/dist/components/nav/rail/RailItem.svelte +122 -65
- package/dist/components/nav/rail/RailItem.svelte.d.ts +3 -2
- package/dist/components/nav/rail/theme.d.ts +70 -85
- package/dist/components/nav/rail/theme.js +80 -67
- package/dist/components/nav/rail/types.d.ts +4 -0
- package/dist/components/nav/tabs/Tabs.stories.svelte +2 -1
- package/dist/components/nav/tabs/theme.d.ts +1 -1
- package/dist/components/nav/tabs/theme.js +1 -1
- package/dist/components/pill/theme.d.ts +1 -1
- package/dist/components/pill/theme.js +1 -1
- package/dist/components/progress/LinearProgress.svelte +1 -1
- package/dist/components/snackbar/theme.d.ts +1 -1
- package/dist/components/snackbar/theme.js +2 -2
- package/dist/components/table/theme.d.ts +1 -1
- package/dist/components/table/theme.js +1 -1
- package/dist/components/time/TimeField.svelte +1 -1
- package/dist/components/time/theme.d.ts +1 -1
- package/dist/components/time/theme.js +1 -1
- package/dist/components/toolbar/theme.d.ts +1 -1
- package/dist/components/toolbar/theme.js +2 -2
- package/dist/components/typography/body/theme.d.ts +1 -1
- package/dist/components/typography/body/theme.js +1 -1
- package/dist/components/typography/display/theme.d.ts +1 -1
- package/dist/components/typography/display/theme.js +1 -1
- package/dist/components/typography/headline/theme.d.ts +1 -1
- package/dist/components/typography/headline/theme.js +1 -1
- package/dist/components/typography/kbd/theme.d.ts +1 -1
- package/dist/components/typography/kbd/theme.js +1 -1
- package/dist/components/typography/label/theme.js +1 -1
- package/dist/components/typography/title/theme.d.ts +1 -1
- package/dist/components/typography/title/theme.js +1 -1
- package/dist/index.css +3 -0
- package/dist/styles/components.css +50 -0
- package/dist/styles/icon.css +13 -0
- package/dist/styles/layers.css +33 -0
- package/dist/utils/icon/Icon.stories.svelte +97 -0
- package/dist/utils/icon/Icon.stories.svelte.d.ts +4 -0
- package/dist/utils/icon/Icon.svelte +101 -12
- package/dist/utils/icon/Icon.svelte.d.ts +9 -0
- package/dist/utils/icon/MaterialSymbolsProvider.svelte +11 -4
- package/dist/utils/icon/base-icons.d.ts +1 -1
- package/dist/utils/icon/base-icons.js +1 -1
- package/dist/utils/icon/icon-names.d.ts +2 -0
- package/dist/utils/icon/icon-names.js +2 -0
- package/dist/utils/icon/swap.d.ts +6 -0
- package/dist/utils/icon/swap.js +45 -0
- package/dist/utils/icon/theme.d.ts +1 -1
- package/dist/utils/icon/theme.js +1 -1
- package/dist/utils/icon/types.d.ts +59 -7
- package/dist/utils/tv.d.ts +5 -0
- package/dist/utils/tv.js +20 -0
- package/package.json +2 -1
|
@@ -1,72 +1,163 @@
|
|
|
1
|
-
import { tv } from '
|
|
1
|
+
import { tv } from '../../utils/tv.js';
|
|
2
|
+
/*
|
|
3
|
+
Values from the M3 chip tokens (md.comp.{assist,filter,input,suggestion}-chip.*):
|
|
4
|
+
https://m3.material.io/components/chips/specs
|
|
5
|
+
|
|
6
|
+
- 32dp tall, 8dp corners, label-large. Padding is 16dp on each side, 8dp on a side that holds an
|
|
7
|
+
icon, and 4dp before an avatar; 8dp between elements. Icons are 18dp, avatars a 24dp circle.
|
|
8
|
+
- The 1dp outline is a border, so it sits inside the 32dp and stays visible (and darkens) while
|
|
9
|
+
the separate focus indicator is showing.
|
|
10
|
+
- Disabled: flat chips lose their fill-less outline to on-surface/12; elevated and selected
|
|
11
|
+
containers turn on-surface/12 with no shadow; label and icons are on-surface/38.
|
|
12
|
+
|
|
13
|
+
Chip doesn't use md-component-button-base: its disabled fill would paint flat chips, which M3
|
|
14
|
+
leaves unfilled.
|
|
15
|
+
|
|
16
|
+
An input chip is a container holding two sibling buttons, the primary `action` and the remove
|
|
17
|
+
button, since one can't nest inside the other. The container keeps the look (and shows the focus
|
|
18
|
+
indicator while the action has focus); the action carries the padding, and its state layer covers the whole chip.
|
|
19
|
+
*/
|
|
2
20
|
export const chip = tv({
|
|
3
21
|
slots: {
|
|
4
|
-
|
|
5
|
-
|
|
22
|
+
// in-data-dragged: M3's dragged state, set by ChipGroup on the chip's slot: 8dp elevation and
|
|
23
|
+
// a 16% state layer.
|
|
24
|
+
base: 'in-data-dragged:shadow-elevation-4 in-data-dragged:before:bg-current/16 state-layer md-sys-state-focus-indicator relative inline-flex h-spacing-400 max-w-max shrink-0 items-center justify-center gap-spacing-100 rounded-sm border border-transparent px-spacing-200 md-sys-typescale-label-large select-none before:rounded-sm transition-[background-color,border-color,box-shadow] md-sys-motion-effects',
|
|
25
|
+
// 18dp is the chip spec's own icon size, between the 16 and 20 Icon presets.
|
|
26
|
+
icon: 'size-[18px] shrink-0 text-[18px]',
|
|
27
|
+
avatar: 'size-spacing-300 shrink-0 overflow-hidden rounded-full',
|
|
28
|
+
// Static, so its Layer (state layer and hit area) spans the whole chip; the remove button is
|
|
29
|
+
// positioned and later in the DOM, so it stays on top.
|
|
30
|
+
action: 'static flex h-full min-w-spacing-0 cursor-pointer items-center gap-spacing-100 self-stretch rounded-sm px-spacing-200 outline-none disabled:cursor-not-allowed',
|
|
6
31
|
label: '',
|
|
7
|
-
|
|
8
|
-
|
|
32
|
+
// 18dp glyph with a 48dp touch target around it (::after).
|
|
33
|
+
trailing: "relative inline-flex size-[18px] shrink-0 cursor-pointer items-center justify-center rounded-full after:absolute after:top-1/2 after:left-1/2 after:size-spacing-600 after:-translate-1/2 after:content-['']",
|
|
34
|
+
checkIcon: 'size-[18px] shrink-0'
|
|
9
35
|
},
|
|
10
36
|
variants: {
|
|
11
37
|
variant: {
|
|
12
|
-
assist: '',
|
|
13
|
-
filter: '',
|
|
14
|
-
input: '',
|
|
15
|
-
suggestion:
|
|
38
|
+
assist: { base: 'text-md-sys-color-on-surface', icon: 'text-md-sys-color-primary' },
|
|
39
|
+
filter: { base: 'text-md-sys-color-on-surface-variant' },
|
|
40
|
+
input: { base: 'text-md-sys-color-on-surface-variant' },
|
|
41
|
+
suggestion: {
|
|
42
|
+
base: 'text-md-sys-color-on-surface-variant',
|
|
43
|
+
icon: 'text-md-sys-color-primary'
|
|
44
|
+
}
|
|
16
45
|
},
|
|
17
46
|
elevated: {
|
|
18
|
-
true: '',
|
|
47
|
+
true: { base: 'shadow-elevation-1 hover:shadow-elevation-2' },
|
|
19
48
|
false: ''
|
|
20
49
|
},
|
|
21
50
|
selected: {
|
|
22
|
-
true:
|
|
51
|
+
true: {
|
|
52
|
+
base: 'bg-md-sys-color-secondary-container text-md-sys-color-on-secondary-container'
|
|
53
|
+
},
|
|
54
|
+
false: ''
|
|
55
|
+
},
|
|
56
|
+
leading: {
|
|
57
|
+
none: '',
|
|
58
|
+
icon: { base: 'pl-spacing-100', action: 'pl-spacing-100' },
|
|
59
|
+
avatar: { base: 'pl-spacing-50', action: 'pl-spacing-50' }
|
|
60
|
+
},
|
|
61
|
+
/** A trailing icon: the filter chip's `trailingIconProps`, or the input chip's remove button. */
|
|
62
|
+
trailing: {
|
|
63
|
+
true: { base: 'pr-spacing-100', action: 'pr-spacing-100' },
|
|
23
64
|
false: ''
|
|
24
65
|
},
|
|
25
66
|
disabled: {
|
|
26
|
-
true:
|
|
67
|
+
true: {
|
|
68
|
+
base: 'text-md-sys-color-on-surface/38 shadow-none hover:shadow-none',
|
|
69
|
+
icon: 'text-md-sys-color-on-surface/38',
|
|
70
|
+
avatar: 'opacity-38',
|
|
71
|
+
trailing: 'text-md-sys-color-on-surface/38',
|
|
72
|
+
checkIcon: 'text-md-sys-color-on-surface/38'
|
|
73
|
+
},
|
|
27
74
|
false: ''
|
|
28
75
|
}
|
|
29
76
|
},
|
|
30
77
|
compoundVariants: [
|
|
78
|
+
// Flat, unselected: no fill, outline-variant border that darkens on focus.
|
|
31
79
|
{
|
|
32
80
|
elevated: false,
|
|
33
81
|
selected: false,
|
|
82
|
+
// The spec keeps a dragged flat chip unfilled, but one floating over its neighbours needs an
|
|
83
|
+
// opaque container, so it takes the elevated chip's.
|
|
34
84
|
class: {
|
|
35
|
-
base: '
|
|
85
|
+
base: 'border-md-sys-color-outline-variant focus-visible:border-md-sys-color-on-surface-variant in-data-dragged:bg-md-sys-color-surface-container-low'
|
|
36
86
|
}
|
|
37
87
|
},
|
|
38
88
|
{
|
|
39
|
-
|
|
40
|
-
|
|
89
|
+
variant: 'assist',
|
|
90
|
+
elevated: false,
|
|
91
|
+
class: { base: 'focus-visible:border-md-sys-color-on-surface' }
|
|
92
|
+
},
|
|
93
|
+
{ elevated: true, selected: false, class: { base: 'bg-md-sys-color-surface-container-low' } },
|
|
94
|
+
// A flat selected filter chip lifts on hover.
|
|
95
|
+
{
|
|
96
|
+
variant: 'filter',
|
|
97
|
+
elevated: false,
|
|
98
|
+
selected: true,
|
|
99
|
+
class: { base: 'hover:shadow-elevation-1' }
|
|
100
|
+
},
|
|
101
|
+
// Unselected filter icons are primary; selected ones inherit on-secondary-container.
|
|
102
|
+
{ variant: 'filter', selected: false, class: { icon: 'text-md-sys-color-primary' } },
|
|
103
|
+
// Input chips are the reverse: on-surface-variant, primary once selected.
|
|
104
|
+
{ variant: 'input', selected: true, class: { icon: 'text-md-sys-color-primary' } },
|
|
105
|
+
// The input chip's container has no padding of its own before the action, and needs the
|
|
106
|
+
// focus indicator (and darker border) while the action is focused.
|
|
107
|
+
{
|
|
108
|
+
variant: 'input',
|
|
41
109
|
class: {
|
|
42
|
-
base: '
|
|
110
|
+
base: 'pl-spacing-0 has-[[data-chip-action]:focus-visible]:outline-3 has-[[data-chip-action]:focus-visible]:outline-offset-2 has-[[data-chip-action]:focus-visible]:outline-md-sys-color-secondary has-[[data-chip-action]:focus-visible]:outline-solid'
|
|
43
111
|
}
|
|
44
112
|
},
|
|
113
|
+
{ variant: 'input', trailing: false, class: { base: 'pr-spacing-0' } },
|
|
45
114
|
{
|
|
46
|
-
|
|
115
|
+
variant: 'input',
|
|
116
|
+
elevated: false,
|
|
117
|
+
selected: false,
|
|
47
118
|
class: {
|
|
48
|
-
base: '
|
|
119
|
+
base: 'has-[[data-chip-action]:focus-visible]:border-md-sys-color-on-surface-variant'
|
|
49
120
|
}
|
|
50
121
|
},
|
|
51
122
|
{
|
|
52
|
-
|
|
123
|
+
disabled: true,
|
|
124
|
+
elevated: false,
|
|
53
125
|
selected: false,
|
|
54
|
-
class: {
|
|
126
|
+
class: { base: 'border-md-sys-color-on-surface/12' }
|
|
55
127
|
},
|
|
56
128
|
{
|
|
57
129
|
disabled: true,
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
130
|
+
elevated: true,
|
|
131
|
+
class: { base: 'bg-md-sys-color-on-surface/12' }
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
disabled: true,
|
|
135
|
+
selected: true,
|
|
136
|
+
class: { base: 'bg-md-sys-color-on-surface/12 text-md-sys-color-on-surface/38' }
|
|
64
137
|
}
|
|
65
138
|
],
|
|
66
139
|
defaultVariants: {
|
|
67
140
|
variant: 'assist',
|
|
68
141
|
elevated: false,
|
|
69
142
|
selected: false,
|
|
143
|
+
leading: 'none',
|
|
144
|
+
trailing: false,
|
|
70
145
|
disabled: false
|
|
71
146
|
}
|
|
72
147
|
});
|
|
148
|
+
/** Layout of a set of chips: 8dp apart, wrapping onto new lines. */
|
|
149
|
+
export const chipGroup = tv({
|
|
150
|
+
slots: {
|
|
151
|
+
base: 'relative flex flex-wrap gap-spacing-100',
|
|
152
|
+
// Its own stacking context only while dragged, so the chip floats over its neighbours.
|
|
153
|
+
item: 'relative flex touch-manipulation data-dragged:z-10 data-dragged:cursor-grabbing',
|
|
154
|
+
hint: 'sr-only',
|
|
155
|
+
live: 'sr-only'
|
|
156
|
+
},
|
|
157
|
+
variants: {
|
|
158
|
+
reorderable: {
|
|
159
|
+
true: { item: 'cursor-grab select-none [-webkit-touch-callout:none]' },
|
|
160
|
+
false: ''
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
});
|
|
@@ -26,18 +26,52 @@ export type ChipProps = ChipVariants & AnchorButtonAttributes & {
|
|
|
26
26
|
disabled?: boolean;
|
|
27
27
|
/** Configuration for the leading icon. */
|
|
28
28
|
iconProps?: IconProps;
|
|
29
|
+
/**
|
|
30
|
+
* Filter chips only: a trailing icon, e.g. `arrow_drop_down` on a chip that opens a menu.
|
|
31
|
+
*/
|
|
32
|
+
trailingIconProps?: IconProps;
|
|
29
33
|
/**
|
|
30
34
|
* Custom leading content (e.g. an avatar image) rendered instead of `iconProps`.
|
|
31
35
|
* Typically used by 'input' chips to represent a contact or entity.
|
|
32
36
|
*/
|
|
33
37
|
avatar?: Snippet;
|
|
34
38
|
/**
|
|
35
|
-
* Called when the trailing remove icon is activated
|
|
36
|
-
* Providing this renders the trailing remove affordance on 'input' chips.
|
|
39
|
+
* Called when the trailing remove icon is activated, or on Backspace/Delete while the chip
|
|
40
|
+
* has focus. Providing this renders the trailing remove affordance on 'input' chips. Move
|
|
41
|
+
* focus to a neighbouring chip (or the input) afterwards, or it falls back to the page.
|
|
37
42
|
*/
|
|
38
43
|
onRemove?: () => void;
|
|
44
|
+
/**
|
|
45
|
+
* Accessible name of the input chip's remove button. Name the item, e.g. `Remove Ada`.
|
|
46
|
+
* @default 'Remove'
|
|
47
|
+
*/
|
|
48
|
+
removeLabel?: string;
|
|
39
49
|
/** The label content of the chip. */
|
|
40
50
|
children: Snippet;
|
|
41
51
|
/** The `formaction` attribute for the chip when used in a form. */
|
|
42
52
|
formaction?: string;
|
|
43
53
|
};
|
|
54
|
+
export type ChipGroupProps<T> = {
|
|
55
|
+
/** The items, one chip each. With `reorderable`, dragging rewrites their order. Bindable. */
|
|
56
|
+
items: T[];
|
|
57
|
+
/** A stable, unique key per item. */
|
|
58
|
+
key: (item: T) => string;
|
|
59
|
+
/** Renders one item's `Chip`. */
|
|
60
|
+
chip: Snippet<[item: T, index: number]>;
|
|
61
|
+
/**
|
|
62
|
+
* Lets people reorder the chips: drag one (on touch, press and hold first), or focus one and
|
|
63
|
+
* press Alt+Arrow. The dragged chip takes M3's dragged state and its neighbours make room.
|
|
64
|
+
* @default false
|
|
65
|
+
*/
|
|
66
|
+
reorderable?: boolean;
|
|
67
|
+
/** Called with the new order after a drag or a keyboard move. */
|
|
68
|
+
onReorder?: (items: T[]) => void;
|
|
69
|
+
/**
|
|
70
|
+
* The item's name in the announcement after a move ("Ada, moved to 2 of 5"). Defaults to its
|
|
71
|
+
* `key`.
|
|
72
|
+
*/
|
|
73
|
+
itemLabel?: (item: T) => string;
|
|
74
|
+
/** Accessible name of the group. */
|
|
75
|
+
'aria-label'?: string;
|
|
76
|
+
class?: string;
|
|
77
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type VariantProps } from '
|
|
1
|
+
import { type VariantProps } from '../../../utils/tv.js';
|
|
2
2
|
export type ActionRailVariants = VariantProps<typeof actionRail>;
|
|
3
3
|
export declare const actionRail: import("tailwind-variants").TVReturnType<{
|
|
4
4
|
anchor: {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { tv } from '
|
|
1
|
+
import { tv } from '../../../utils/tv.js';
|
|
2
2
|
export const actionRail = tv({
|
|
3
3
|
slots: {
|
|
4
|
-
base: 'z-
|
|
4
|
+
base: 'z-layer-bar flex flex-col items-center justify-center right-spacing-0'
|
|
5
5
|
},
|
|
6
6
|
variants: {
|
|
7
7
|
anchor: {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { type VariantProps } from '
|
|
1
|
+
import { type VariantProps } from '../../../utils/tv.js';
|
|
2
2
|
export type AppVariants = VariantProps<typeof app>;
|
|
3
|
-
export declare const app: import("tailwind-variants").TVReturnType<{} | {} | {}, undefined, "bg-md-sys-color-surface-container text-md-sys-color-on-background min-h-dvh caret-md-sys-color-primary selection:bg-md-sys-color-primary-container selection:text-md-sys-color-on-primary-container relative min-h-dvh pt-[env(safe-area-inset-top)] pr-[env(safe-area-inset-right)] pb-[env(safe-area-inset-bottom)] pl-[env(safe-area-inset-left)] antialiased", {} | {}, undefined, import("tailwind-variants").TVReturnTypeLike<unknown, undefined>>;
|
|
3
|
+
export declare const app: import("tailwind-variants").TVReturnType<{} | {} | {}, undefined, "md-app bg-md-sys-color-surface-container text-md-sys-color-on-background min-h-dvh caret-md-sys-color-primary selection:bg-md-sys-color-primary-container selection:text-md-sys-color-on-primary-container relative min-h-dvh pt-[env(safe-area-inset-top)] pr-[env(safe-area-inset-right)] pb-[env(safe-area-inset-bottom)] pl-[calc(env(safe-area-inset-left)+var(--md-rail-inset,0px))] antialiased", {} | {}, undefined, import("tailwind-variants").TVReturnTypeLike<unknown, undefined>>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { tv } from '
|
|
1
|
+
import { tv } from '../../../utils/tv.js';
|
|
2
2
|
export const app = tv({
|
|
3
|
-
base: 'bg-md-sys-color-surface-container text-md-sys-color-on-background min-h-dvh caret-md-sys-color-primary selection:bg-md-sys-color-primary-container selection:text-md-sys-color-on-primary-container relative min-h-dvh pt-[env(safe-area-inset-top)] pr-[env(safe-area-inset-right)] pb-[env(safe-area-inset-bottom)] pl-[env(safe-area-inset-left)] antialiased'
|
|
3
|
+
base: 'md-app bg-md-sys-color-surface-container text-md-sys-color-on-background min-h-dvh caret-md-sys-color-primary selection:bg-md-sys-color-primary-container selection:text-md-sys-color-on-primary-container relative min-h-dvh pt-[env(safe-area-inset-top)] pr-[env(safe-area-inset-right)] pb-[env(safe-area-inset-bottom)] pl-[calc(env(safe-area-inset-left)+var(--md-rail-inset,0px))] antialiased'
|
|
4
4
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type VariantProps } from '
|
|
1
|
+
import { type VariantProps } from '../../../utils/tv.js';
|
|
2
2
|
export type BottomSheetVariants = VariantProps<typeof bottomSheet>;
|
|
3
3
|
export declare const bottomSheet: import("tailwind-variants").TVReturnType<{
|
|
4
4
|
variant: {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { tv } from '
|
|
1
|
+
import { tv } from '../../../utils/tv.js';
|
|
2
2
|
/*
|
|
3
3
|
M3 bottom sheet (https://m3.material.io/components/bottom-sheets/specs): `surface-container-low`
|
|
4
4
|
at elevation 1, 28dp top corners. Full window width up to 640dp; past 640dp it keeps 56dp side
|
|
@@ -11,7 +11,7 @@ import { tv } from 'tailwind-variants';
|
|
|
11
11
|
export const bottomSheet = tv({
|
|
12
12
|
slots: {
|
|
13
13
|
base: [
|
|
14
|
-
'fixed inset-x-spacing-0 top-auto bottom-spacing-0 z-
|
|
14
|
+
'fixed inset-x-spacing-0 top-auto bottom-spacing-0 z-layer-sheet mx-auto mt-auto mb-spacing-0 p-spacing-0',
|
|
15
15
|
'w-full max-w-160 sm:w-[calc(100%-7rem)]',
|
|
16
16
|
'max-h-[calc(100dvh-4.5rem)] sm:max-h-[calc(100dvh-3.5rem)]',
|
|
17
17
|
'overflow-visible bg-transparent outline-none'
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { tv } from '
|
|
1
|
+
import { tv } from '../../../utils/tv.js';
|
|
2
2
|
/*
|
|
3
3
|
M3 carousel (https://m3.material.io/components/carousel/specs): 28dp items on `surface`, 8dp
|
|
4
4
|
apart. Multi-browse and hero layouts pad 16dp on both sides and 8dp top/bottom; uncontained
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type VariantProps } from '
|
|
1
|
+
import { type VariantProps } from '../../../utils/tv.js';
|
|
2
2
|
export type ContextMenuVariants = VariantProps<typeof contextMenu>;
|
|
3
3
|
export declare const contextMenu: import("tailwind-variants").TVReturnType<{
|
|
4
4
|
selected: {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { tv } from '
|
|
1
|
+
import { tv } from '../../../utils/tv.js';
|
|
2
2
|
export const contextMenu = tv({
|
|
3
3
|
slots: {
|
|
4
4
|
content: `
|
|
5
|
-
z-
|
|
5
|
+
z-layer-popup min-w-48 max-w-sm gap-spacing-50 overflow-y-auto rounded-lg
|
|
6
6
|
bg-md-sys-color-surface-container-high px-spacing-100 py-spacing-50
|
|
7
7
|
shadow-elevation-3 ring-md-sys-color-outline/10
|
|
8
8
|
`,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type VariantProps } from '
|
|
1
|
+
import { type VariantProps } from '../../../utils/tv.js';
|
|
2
2
|
export type DialogueVariants = VariantProps<typeof dialogue>;
|
|
3
3
|
export declare const dialogue: import("tailwind-variants").TVReturnType<{
|
|
4
4
|
[key: string]: {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { tv } from '
|
|
1
|
+
import { tv } from '../../../utils/tv.js';
|
|
2
2
|
export const dialogue = tv({
|
|
3
3
|
slots: {
|
|
4
|
-
base: 'fixed inset-spacing-0 z-
|
|
5
|
-
inner: 'fixed inset-spacing-0 z-
|
|
4
|
+
base: 'fixed inset-spacing-0 z-layer-modal bg-md-sys-color-scrim/32',
|
|
5
|
+
inner: 'fixed inset-spacing-0 z-layer-modal m-auto h-max w-full outline-none bg-md-sys-color-surface-container-high shadow-elevation-3 flex flex-col rounded-[28px] p-spacing-300 gap-spacing-200',
|
|
6
6
|
headlineContainer: 'md-sys-typescale-headline-small text-md-sys-color-on-surface',
|
|
7
7
|
supportingTextContainer: 'md-sys-typescale-body-medium text-md-sys-color-on-surface-variant',
|
|
8
8
|
buttonContainer: 'mt-spacing-100 flex items-center justify-end gap-spacing-100'
|
|
@@ -18,7 +18,7 @@ export type DialogueProps = DialogueVariants & Dialog.RootProps & {
|
|
|
18
18
|
headline?: string;
|
|
19
19
|
/** The label for the confirmation button. */
|
|
20
20
|
confirmText: string;
|
|
21
|
-
/** The label for the cancel button. Defaults to '
|
|
21
|
+
/** The label for the cancel button. Defaults to 'Cancel'. */
|
|
22
22
|
cancelText?: string;
|
|
23
23
|
/**
|
|
24
24
|
* Optional additional content to be rendered between the supporting text
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type VariantProps } from '
|
|
1
|
+
import { type VariantProps } from '../../../utils/tv.js';
|
|
2
2
|
export type LinkPreviewVariants = VariantProps<typeof linkPreview>;
|
|
3
3
|
export declare const linkPreview: import("tailwind-variants").TVReturnType<{
|
|
4
4
|
[key: string]: {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { tv } from '
|
|
1
|
+
import { tv } from '../../../utils/tv.js';
|
|
2
2
|
export const linkPreview = tv({
|
|
3
3
|
slots: {
|
|
4
|
-
base: 'relative z-
|
|
4
|
+
base: 'relative z-layer-popup min-w-48 max-w-sm rounded-2xl bg-md-sys-color-surface-container-high p-spacing-200 shadow-elevation-3 ring-1 ring-md-sys-color-outline/20 overflow-hidden',
|
|
5
5
|
content: 'flex flex-col gap-spacing-100'
|
|
6
6
|
}
|
|
7
7
|
});
|
|
@@ -6,13 +6,19 @@
|
|
|
6
6
|
|
|
7
7
|
let { variant = 'standard', class: className, children, ...restProps }: ListProps = $props();
|
|
8
8
|
|
|
9
|
+
let element = $state<HTMLElement>();
|
|
10
|
+
|
|
9
11
|
setListContext({
|
|
10
12
|
get variant() {
|
|
11
13
|
return variant;
|
|
12
|
-
}
|
|
14
|
+
},
|
|
15
|
+
get element() {
|
|
16
|
+
return element;
|
|
17
|
+
},
|
|
18
|
+
from: null
|
|
13
19
|
});
|
|
14
20
|
</script>
|
|
15
21
|
|
|
16
|
-
<ul class={list({ variant, class: clsx(className) })} {...restProps}>
|
|
22
|
+
<ul bind:this={element} class={list({ variant, class: clsx(className) })} {...restProps}>
|
|
17
23
|
{@render children?.()}
|
|
18
24
|
</ul>
|
|
@@ -91,6 +91,12 @@ chevron, `aria-expanded` and `aria-controls`. The nested items are `inert` while
|
|
|
91
91
|
content to 38%. Hover, focus and press tints come from the shared state layer. The keyboard focus
|
|
92
92
|
ring is drawn inside the item, so segments don't overlap.
|
|
93
93
|
|
|
94
|
+
When the selection moves inside one `List` (a nav list following the route, a single-select
|
|
95
|
+
list), the fill travels: it springs from where the old one was drawn to the newly selected item,
|
|
96
|
+
up or down, on the `spatial` spring. It passes over the items in between, and a selection that
|
|
97
|
+
moves again mid-flight picks up from where the fill is. When several items change at once, or
|
|
98
|
+
under reduced motion, the fill just appears on the selected item.
|
|
99
|
+
|
|
94
100
|
<Canvas of={ListStories.Disabled} />
|
|
95
101
|
|
|
96
102
|
## Where this differs from the tokens
|
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
import { Icon, Layer } from '../../../utils/index.js';
|
|
3
3
|
import clsx from 'clsx';
|
|
4
4
|
import { listItem } from './theme.js';
|
|
5
|
-
import { getListContext } from './context.js';
|
|
5
|
+
import { getListContext, type SelectionRect } from './context.js';
|
|
6
|
+
import { untrack } from 'svelte';
|
|
7
|
+
import { animate, type AnimationPlaybackControlsWithThen } from 'motion';
|
|
8
|
+
import { springTokens, springTransition } from '../../../animation/spring.js';
|
|
6
9
|
import type { ListitemProps } from './types.js';
|
|
7
10
|
import Badge from '../../badge/Badge.svelte';
|
|
8
11
|
|
|
@@ -53,6 +56,71 @@
|
|
|
53
56
|
})
|
|
54
57
|
);
|
|
55
58
|
|
|
59
|
+
/*
|
|
60
|
+
The selected fill travels. Before an update, the item losing the selection leaves where its
|
|
61
|
+
fill is drawn (mid-flight too) in the List's context; after it, the item gaining the
|
|
62
|
+
selection springs its new fill over from there, on spatial: a sizeable move, and part of a
|
|
63
|
+
navigation, so no fastSpatial bounce. Without a List, or with several items selected or
|
|
64
|
+
deselected at once, the fill just appears where it belongs. Reduced motion skips the ride.
|
|
65
|
+
*/
|
|
66
|
+
const showFill = $derived(!!selected && !disabled);
|
|
67
|
+
let fill = $state<HTMLElement>();
|
|
68
|
+
let travelling = $state(false);
|
|
69
|
+
let wasShown = untrack(() => showFill);
|
|
70
|
+
let ride: AnimationPlaybackControlsWithThen | undefined;
|
|
71
|
+
|
|
72
|
+
const measure = (el: HTMLElement): SelectionRect | null => {
|
|
73
|
+
const box = ctx?.element?.getBoundingClientRect();
|
|
74
|
+
if (!box) return null;
|
|
75
|
+
const r = el.getBoundingClientRect();
|
|
76
|
+
return {
|
|
77
|
+
top: r.top - box.top,
|
|
78
|
+
bottom: r.bottom - box.top,
|
|
79
|
+
left: r.left - box.left,
|
|
80
|
+
right: r.right - box.left
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
$effect.pre(() => {
|
|
85
|
+
const shown = showFill;
|
|
86
|
+
untrack(() => {
|
|
87
|
+
if (!wasShown || shown || !ctx || !fill) return;
|
|
88
|
+
ctx.from = measure(fill);
|
|
89
|
+
ride?.stop();
|
|
90
|
+
travelling = false;
|
|
91
|
+
// Only for this update: a deselect with no select after it leaves nothing behind.
|
|
92
|
+
queueMicrotask(() => (ctx.from = null));
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
$effect(() => {
|
|
97
|
+
const shown = showFill;
|
|
98
|
+
untrack(() => {
|
|
99
|
+
const gained = shown && !wasShown;
|
|
100
|
+
wasShown = shown;
|
|
101
|
+
const from = ctx?.from;
|
|
102
|
+
if (!gained || !from || !fill) return;
|
|
103
|
+
ctx!.from = null;
|
|
104
|
+
const to = measure(fill);
|
|
105
|
+
if (!to || matchMedia('(prefers-reduced-motion: reduce)').matches) return;
|
|
106
|
+
// Above the items it passes over, which are the item's siblings.
|
|
107
|
+
travelling = true;
|
|
108
|
+
ride = animate(
|
|
109
|
+
fill,
|
|
110
|
+
{
|
|
111
|
+
top: [`${from.top - to.top}px`, '0px'],
|
|
112
|
+
bottom: [`${to.bottom - from.bottom}px`, '0px'],
|
|
113
|
+
left: [`${from.left - to.left}px`, '0px'],
|
|
114
|
+
right: [`${to.right - from.right}px`, '0px']
|
|
115
|
+
},
|
|
116
|
+
springTransition(springTokens.spatial)
|
|
117
|
+
);
|
|
118
|
+
ride.then(() => (travelling = false));
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
$effect(() => () => ride?.stop());
|
|
123
|
+
|
|
56
124
|
const attrs = $derived.by(() => {
|
|
57
125
|
const { label: _, href, onclick, ...extra } = rest;
|
|
58
126
|
const a: Record<string, unknown> = { ...extra };
|
|
@@ -81,6 +149,9 @@
|
|
|
81
149
|
</script>
|
|
82
150
|
|
|
83
151
|
{#snippet content()}
|
|
152
|
+
{#if showFill}
|
|
153
|
+
<span bind:this={fill} class={cls.selection()} aria-hidden="true"></span>
|
|
154
|
+
{/if}
|
|
84
155
|
{#if interactive}
|
|
85
156
|
<Layer />
|
|
86
157
|
{/if}
|
|
@@ -121,7 +192,11 @@
|
|
|
121
192
|
{/snippet}
|
|
122
193
|
|
|
123
194
|
{#snippet item()}
|
|
124
|
-
<svelte:element
|
|
195
|
+
<svelte:element
|
|
196
|
+
this={tag}
|
|
197
|
+
class={cls.base({ class: clsx(className, travelling && 'z-10') })}
|
|
198
|
+
{...attrs}
|
|
199
|
+
>
|
|
125
200
|
{@render content()}
|
|
126
201
|
</svelte:element>
|
|
127
202
|
{#if children}
|
|
@@ -1,5 +1,19 @@
|
|
|
1
|
+
/** Where the outgoing selection was drawn, relative to the list's box. */
|
|
2
|
+
export type SelectionRect = {
|
|
3
|
+
top: number;
|
|
4
|
+
bottom: number;
|
|
5
|
+
left: number;
|
|
6
|
+
right: number;
|
|
7
|
+
};
|
|
1
8
|
type ListContext = {
|
|
2
9
|
readonly variant: 'standard' | 'segmented';
|
|
10
|
+
/** The list's own element, which selection rects are measured against. */
|
|
11
|
+
readonly element: HTMLElement | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* Handed from the item losing the selection to the one gaining it within one update, so the
|
|
14
|
+
* selected fill travels between them. Cleared once that update settles.
|
|
15
|
+
*/
|
|
16
|
+
from: SelectionRect | null;
|
|
3
17
|
};
|
|
4
18
|
export declare const setListContext: (ctx: ListContext) => ListContext;
|
|
5
19
|
export declare const getListContext: () => ListContext | undefined;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type VariantProps } from '
|
|
1
|
+
import { type VariantProps } from '../../../utils/tv.js';
|
|
2
2
|
export type ListVariants = VariantProps<typeof list>;
|
|
3
3
|
export type ListMediaVariants = VariantProps<typeof listMedia>;
|
|
4
4
|
export declare const list: import("tailwind-variants").TVReturnType<{
|
|
@@ -85,6 +85,7 @@ export declare const listItem: import("tailwind-variants").TVReturnType<{
|
|
|
85
85
|
};
|
|
86
86
|
}, {
|
|
87
87
|
base: string[];
|
|
88
|
+
selection: string;
|
|
88
89
|
leading: string;
|
|
89
90
|
body: string;
|
|
90
91
|
overline: string;
|
|
@@ -165,6 +166,7 @@ export declare const listItem: import("tailwind-variants").TVReturnType<{
|
|
|
165
166
|
};
|
|
166
167
|
}, {
|
|
167
168
|
base: string[];
|
|
169
|
+
selection: string;
|
|
168
170
|
leading: string;
|
|
169
171
|
body: string;
|
|
170
172
|
overline: string;
|
|
@@ -245,6 +247,7 @@ export declare const listItem: import("tailwind-variants").TVReturnType<{
|
|
|
245
247
|
};
|
|
246
248
|
}, {
|
|
247
249
|
base: string[];
|
|
250
|
+
selection: string;
|
|
248
251
|
leading: string;
|
|
249
252
|
body: string;
|
|
250
253
|
overline: string;
|
|
@@ -327,6 +330,7 @@ export declare const listiem: import("tailwind-variants").TVReturnType<{
|
|
|
327
330
|
};
|
|
328
331
|
}, {
|
|
329
332
|
base: string[];
|
|
333
|
+
selection: string;
|
|
330
334
|
leading: string;
|
|
331
335
|
body: string;
|
|
332
336
|
overline: string;
|
|
@@ -407,6 +411,7 @@ export declare const listiem: import("tailwind-variants").TVReturnType<{
|
|
|
407
411
|
};
|
|
408
412
|
}, {
|
|
409
413
|
base: string[];
|
|
414
|
+
selection: string;
|
|
410
415
|
leading: string;
|
|
411
416
|
body: string;
|
|
412
417
|
overline: string;
|
|
@@ -487,6 +492,7 @@ export declare const listiem: import("tailwind-variants").TVReturnType<{
|
|
|
487
492
|
};
|
|
488
493
|
}, {
|
|
489
494
|
base: string[];
|
|
495
|
+
selection: string;
|
|
490
496
|
leading: string;
|
|
491
497
|
body: string;
|
|
492
498
|
overline: string;
|