@noxlovette/material 0.5.0 → 0.6.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/bin/material-claude-skill.js +31 -0
- package/claude-skill/material-design/SKILL.md +68 -0
- package/claude-skill/material-design/references/accessibility-checklist.md +29 -0
- package/claude-skill/material-design/references/component-patterns.md +55 -0
- package/claude-skill/material-design/references/motion-guide.md +163 -0
- package/claude-skill/material-design/references/tokens-and-styles.md +68 -0
- package/dist/animation/Shapes.stories.svelte +60 -0
- package/dist/animation/Shapes.stories.svelte.d.ts +3 -0
- package/dist/animation/TransitionPatterns.stories.svelte +32 -20
- package/dist/animation/containerTransform.d.ts +11 -0
- package/dist/animation/containerTransform.js +11 -0
- package/dist/animation/enterExit.d.ts +9 -0
- package/dist/animation/enterExit.js +6 -3
- package/dist/animation/index.d.ts +1 -0
- package/dist/animation/index.js +1 -0
- package/dist/animation/shapeMorph.svelte.d.ts +52 -0
- package/dist/animation/shapeMorph.svelte.js +112 -0
- package/dist/animation/shapesAnimatableSmall.d.ts +28 -22
- package/dist/animation/shapesAnimatableSmall.js +32 -23
- package/dist/animation/sharedAxisTransition.d.ts +22 -0
- package/dist/animation/sharedAxisTransition.js +25 -1
- package/dist/animation/skeleton.d.ts +6 -1
- package/dist/animation/skeleton.js +6 -1
- package/dist/components/badge/Badge.mdx +70 -0
- package/dist/components/badge/Badge.stories.svelte +38 -20
- package/dist/components/badge/Badge.svelte +12 -5
- package/dist/components/badge/theme.d.ts +30 -7
- package/dist/components/badge/theme.js +24 -4
- package/dist/components/badge/types.d.ts +18 -4
- package/dist/components/buttons/Button.mdx +85 -0
- package/dist/components/buttons/Button.stories.svelte +62 -27
- package/dist/components/buttons/Button.svelte +29 -25
- package/dist/components/buttons/Button.svelte.d.ts +11 -9
- package/dist/components/buttons/ButtonIcon.mdx +52 -0
- package/dist/components/buttons/ButtonIcon.stories.svelte +72 -48
- package/dist/components/buttons/ButtonIcon.svelte +58 -36
- package/dist/components/buttons/ButtonIcon.svelte.d.ts +9 -7
- package/dist/components/buttons/FAB.mdx +84 -0
- package/dist/components/buttons/FAB.stories.svelte +103 -24
- package/dist/components/buttons/FAB.stories.svelte.d.ts +2 -17
- package/dist/components/buttons/FAB.svelte +353 -29
- package/dist/components/buttons/FAB.svelte.d.ts +11 -6
- package/dist/components/buttons/FABMenu.svelte +27 -8
- package/dist/components/buttons/FABMenu.svelte.d.ts +7 -3
- package/dist/components/buttons/FABMenuItem.svelte +20 -16
- package/dist/components/buttons/FABMenuItem.svelte.d.ts +3 -3
- package/dist/components/buttons/Toggle.stories.svelte +31 -23
- package/dist/components/buttons/Toggle.stories.svelte.d.ts +2 -17
- package/dist/components/buttons/Toggle.svelte +28 -25
- package/dist/components/buttons/Toggle.svelte.d.ts +5 -5
- package/dist/components/buttons/button-group/ButtonGroup.mdx +39 -0
- package/dist/components/buttons/button-group/ButtonGroup.stories.svelte +62 -43
- package/dist/components/buttons/button-group/ButtonGroup.stories.svelte.d.ts +2 -17
- package/dist/components/buttons/button-group/ButtonGroup.svelte +102 -8
- package/dist/components/buttons/button-group/ButtonGroup.svelte.d.ts +6 -7
- package/dist/components/buttons/button-group/theme.d.ts +45 -15
- package/dist/components/buttons/button-group/theme.js +13 -8
- package/dist/components/buttons/button-group/types.d.ts +13 -7
- package/dist/components/buttons/connected/ConnectedButtonGroup.mdx +43 -0
- package/dist/components/buttons/connected/ConnectedButtonGroup.stories.svelte +56 -74
- package/dist/components/buttons/connected/ConnectedButtonGroup.stories.svelte.d.ts +2 -17
- package/dist/components/buttons/connected/ConnectedButtonGroup.svelte +16 -4
- package/dist/components/buttons/connected/ConnectedButtonGroup.svelte.d.ts +4 -4
- package/dist/components/buttons/connected/ConnectedButtonGroupItem.svelte +35 -8
- package/dist/components/buttons/connected/ConnectedButtonGroupItem.svelte.d.ts +2 -3
- package/dist/components/buttons/connected/theme.d.ts +33 -18
- package/dist/components/buttons/connected/theme.js +32 -9
- package/dist/components/buttons/connected/types.d.ts +36 -9
- package/dist/components/buttons/shapeMorph.d.ts +26 -0
- package/dist/components/buttons/shapeMorph.js +142 -0
- package/dist/components/buttons/split-button/SplitButton.mdx +48 -0
- package/dist/components/buttons/split-button/SplitButton.stories.svelte +9 -14
- package/dist/components/buttons/split-button/SplitButton.svelte +65 -48
- package/dist/components/buttons/split-button/SplitButton.svelte.d.ts +6 -11
- package/dist/components/buttons/split-button/theme.d.ts +110 -17
- package/dist/components/buttons/split-button/theme.js +74 -16
- package/dist/components/buttons/split-button/types.d.ts +24 -18
- package/dist/components/buttons/theme.d.ts +422 -230
- package/dist/components/buttons/theme.js +286 -380
- package/dist/components/buttons/types.d.ts +130 -125
- package/dist/components/cards/Card.mdx +44 -0
- package/dist/components/cards/Card.stories.svelte +11 -11
- package/dist/components/cards/theme.js +5 -5
- package/dist/components/chips/Chip.mdx +68 -0
- package/dist/components/chips/Chip.stories.svelte +4 -4
- package/dist/components/chips/theme.js +3 -3
- package/dist/components/containers/action-rail/ActionRail.stories.svelte +1 -0
- package/dist/components/containers/action-rail/theme.js +1 -1
- package/dist/components/containers/bottom-sheet/BottomSheet.mdx +64 -0
- package/dist/components/containers/bottom-sheet/BottomSheet.stories.svelte +108 -12
- package/dist/components/containers/bottom-sheet/BottomSheet.svelte +179 -109
- package/dist/components/containers/bottom-sheet/BottomSheet.svelte.d.ts +10 -5
- package/dist/components/containers/bottom-sheet/index.d.ts +1 -0
- package/dist/components/containers/bottom-sheet/index.js +1 -0
- package/dist/components/containers/bottom-sheet/theme.d.ts +45 -0
- package/dist/components/containers/bottom-sheet/theme.js +42 -0
- package/dist/components/containers/bottom-sheet/types.d.ts +37 -5
- package/dist/components/containers/carousel/Carousel.mdx +80 -0
- package/dist/components/containers/carousel/Carousel.stories.svelte +131 -0
- package/dist/components/containers/carousel/Carousel.stories.svelte.d.ts +4 -0
- package/dist/components/containers/carousel/Carousel.svelte +194 -0
- package/dist/components/containers/carousel/Carousel.svelte.d.ts +25 -0
- package/dist/components/containers/carousel/index.d.ts +3 -0
- package/dist/components/containers/{stack → carousel}/index.js +1 -2
- package/dist/components/containers/carousel/keylines.d.ts +32 -0
- package/dist/components/containers/carousel/keylines.js +88 -0
- package/dist/components/containers/carousel/theme.d.ts +162 -0
- package/dist/components/containers/carousel/theme.js +67 -0
- package/dist/components/containers/carousel/types.d.ts +52 -0
- package/dist/components/containers/context-menu/ContextMenu.stories.svelte +1 -0
- package/dist/components/containers/context-menu/ContextMenu.svelte +2 -2
- package/dist/components/containers/context-menu/ContextMenu.svelte.d.ts +1 -1
- package/dist/components/containers/context-menu/theme.js +10 -10
- package/dist/components/containers/dialogue/Dialogue.mdx +65 -0
- package/dist/components/containers/dialogue/Dialogue.stories.svelte +4 -4
- package/dist/components/containers/dialogue/Dialogue.svelte +1 -1
- package/dist/components/containers/dialogue/theme.js +3 -3
- package/dist/components/containers/divider/Divider.stories.svelte +2 -1
- package/dist/components/containers/divider/Divider.svelte +2 -2
- package/dist/components/containers/divider/theme.d.ts +6 -6
- package/dist/components/containers/divider/theme.js +2 -2
- package/dist/components/containers/index.d.ts +1 -1
- package/dist/components/containers/index.js +1 -1
- package/dist/components/containers/link-preview/theme.js +2 -2
- package/dist/components/containers/list/List.svelte +18 -0
- package/dist/components/containers/list/List.svelte.d.ts +4 -0
- package/dist/components/containers/list/ListItem.mdx +100 -0
- package/dist/components/containers/list/ListItem.stories.svelte +177 -42
- package/dist/components/containers/list/ListItem.stories.svelte.d.ts +2 -17
- package/dist/components/containers/list/ListItem.svelte +92 -37
- package/dist/components/containers/list/ListItem.svelte.d.ts +1 -1
- package/dist/components/containers/list/context.d.ts +6 -0
- package/dist/components/containers/list/context.js +4 -0
- package/dist/components/containers/list/index.d.ts +1 -0
- package/dist/components/containers/list/index.js +1 -0
- package/dist/components/containers/list/theme.d.ts +487 -12
- package/dist/components/containers/list/theme.js +140 -13
- package/dist/components/containers/list/types.d.ts +39 -5
- package/dist/components/containers/menu/Menu.mdx +52 -0
- package/dist/components/containers/menu/Menu.stories.svelte +14 -14
- package/dist/components/containers/menu/Menu.svelte +1 -1
- package/dist/components/containers/menu/MenuGroup.svelte +1 -1
- package/dist/components/containers/menu/MenuGroup.svelte.d.ts +1 -1
- package/dist/components/containers/menu/menu-item/MenuItem.svelte +1 -1
- package/dist/components/containers/menu/theme.js +8 -8
- package/dist/components/containers/pane/DraggablePane.stories.svelte +4 -3
- package/dist/components/containers/pane/DraggablePane.svelte +2 -2
- package/dist/components/containers/pane/Pane.stories.svelte +11 -10
- package/dist/components/containers/pane/Pane.svelte +24 -2
- package/dist/components/containers/pane/PaneGrid.stories.svelte +19 -18
- package/dist/components/containers/pane/PaneGrid.svelte +3 -2
- package/dist/components/containers/pane/PaneGrid.svelte.d.ts +2 -1
- package/dist/components/containers/pane/PaneHandle.svelte +48 -2
- package/dist/components/containers/pane/PaneHandle.svelte.d.ts +4 -0
- package/dist/components/containers/pane/resizeStore.svelte.d.ts +10 -1
- package/dist/components/containers/pane/resizeStore.svelte.js +13 -2
- package/dist/components/containers/pane/theme.js +129 -45
- package/dist/components/containers/pane/types.d.ts +3 -2
- package/dist/components/containers/popover/Popover.mdx +45 -0
- package/dist/components/containers/popover/Popover.stories.svelte +1 -1
- package/dist/components/containers/popover/Popover.svelte +1 -1
- package/dist/components/containers/popover/theme.js +3 -3
- package/dist/components/containers/scroll-area/theme.js +2 -2
- package/dist/components/containers/side-sheet/SideSheet.mdx +71 -0
- package/dist/components/containers/side-sheet/SideSheet.stories.svelte +113 -17
- package/dist/components/containers/side-sheet/SideSheet.svelte +113 -66
- package/dist/components/containers/side-sheet/SideSheet.svelte.d.ts +8 -7
- package/dist/components/containers/side-sheet/index.d.ts +1 -0
- package/dist/components/containers/side-sheet/index.js +1 -0
- package/dist/components/containers/side-sheet/theme.d.ts +108 -0
- package/dist/components/containers/side-sheet/theme.js +72 -0
- package/dist/components/containers/side-sheet/types.d.ts +35 -7
- package/dist/components/date/DateField.stories.svelte +4 -3
- package/dist/components/date/DateField.svelte +49 -26
- package/dist/components/date/DateField.svelte.d.ts +2 -0
- package/dist/components/date/DateRangeField.stories.svelte +4 -3
- package/dist/components/date/DateRangeField.svelte +54 -31
- package/dist/components/date/DateRangeField.svelte.d.ts +2 -0
- package/dist/components/date/calendarMotion.d.ts +9 -0
- package/dist/components/date/calendarMotion.js +23 -0
- package/dist/components/date/theme.d.ts +7 -7
- package/dist/components/date/theme.js +34 -30
- package/dist/components/forms/checkbox/Checkbox.mdx +35 -0
- package/dist/components/forms/checkbox/Checkbox.stories.svelte +2 -2
- package/dist/components/forms/checkbox/Checkbox.svelte +1 -1
- package/dist/components/forms/checkbox/theme.js +3 -3
- package/dist/components/forms/command/Command.stories.svelte +1 -0
- package/dist/components/forms/command/theme.js +9 -9
- package/dist/components/forms/pin/theme.js +4 -4
- package/dist/components/forms/radio-group/RadioGroup.svelte +1 -1
- package/dist/components/forms/radio-group/theme.js +5 -5
- package/dist/components/forms/search/Search.mdx +38 -0
- package/dist/components/forms/search/Search.stories.svelte +19 -9
- package/dist/components/forms/search/Search.svelte +40 -17
- package/dist/components/forms/search/Search.svelte.d.ts +2 -2
- package/dist/components/forms/search/theme.d.ts +45 -12
- package/dist/components/forms/search/theme.js +13 -8
- package/dist/components/forms/search/types.d.ts +18 -12
- package/dist/components/forms/select/Select.mdx +53 -0
- package/dist/components/forms/select/Select.stories.svelte +4 -4
- package/dist/components/forms/select/Select.svelte +10 -2
- package/dist/components/forms/select/SelectItem.svelte +1 -1
- package/dist/components/forms/select/theme.js +12 -12
- package/dist/components/forms/slider/Slider.mdx +85 -0
- package/dist/components/forms/slider/Slider.stories.svelte +7 -7
- package/dist/components/forms/slider/Slider.svelte +46 -28
- package/dist/components/forms/slider/theme.d.ts +14 -0
- package/dist/components/forms/slider/theme.js +28 -17
- package/dist/components/forms/slider/types.d.ts +3 -2
- package/dist/components/forms/switch/Switch.mdx +38 -0
- package/dist/components/forms/switch/Switch.stories.svelte +3 -3
- package/dist/components/forms/switch/theme.js +6 -6
- package/dist/components/forms/textfield/Textfield.mdx +53 -0
- package/dist/components/forms/textfield/Textfield.stories.svelte +6 -6
- package/dist/components/forms/textfield/Textfield.svelte +1 -0
- package/dist/components/forms/textfield/theme.d.ts +3 -0
- package/dist/components/forms/textfield/theme.js +22 -19
- package/dist/components/forms/toggle-group/theme.js +2 -2
- package/dist/components/forms/tooltip/Tooltip.stories.svelte +1 -0
- package/dist/components/forms/tooltip/theme.js +3 -3
- package/dist/components/misc/Avatar.stories.svelte +5 -4
- package/dist/components/misc/ThemeSettings.svelte +9 -9
- package/dist/components/misc/ThemeSwitcher.svelte +3 -3
- package/dist/components/misc/theme.js +4 -4
- package/dist/components/nav/appbar/AppBar.mdx +71 -0
- package/dist/components/nav/appbar/AppBar.stories.svelte +93 -3
- package/dist/components/nav/appbar/AppBar.stories.svelte.d.ts +2 -17
- package/dist/components/nav/appbar/AppBar.svelte +90 -37
- package/dist/components/nav/appbar/AppBar.svelte.d.ts +9 -2
- package/dist/components/nav/appbar/theme.d.ts +85 -18
- package/dist/components/nav/appbar/theme.js +159 -23
- package/dist/components/nav/appbar/types.d.ts +46 -9
- package/dist/components/nav/breadcrumb/Breadcrumb.stories.svelte +1 -0
- package/dist/components/nav/breadcrumb/theme.js +5 -5
- package/dist/components/nav/navbar/Navbar.mdx +38 -0
- package/dist/components/nav/navbar/Navbar.svelte +1 -1
- package/dist/components/nav/navbar/NavbarItem.svelte +12 -9
- package/dist/components/nav/navbar/theme.js +6 -6
- package/dist/components/nav/rail/Rail.mdx +73 -0
- package/dist/components/nav/rail/Rail.stories.svelte +3 -7
- package/dist/components/nav/rail/Rail.svelte +1 -0
- package/dist/components/nav/rail/RailItem.svelte +12 -9
- package/dist/components/nav/rail/theme.js +13 -13
- package/dist/components/nav/rail/types.d.ts +4 -1
- package/dist/components/nav/tabs/TabHolder.svelte +29 -3
- package/dist/components/nav/tabs/TabHolder.svelte.d.ts +3 -1
- package/dist/components/nav/tabs/Tabs.mdx +62 -0
- package/dist/components/nav/tabs/Tabs.stories.svelte +1 -1
- package/dist/components/nav/tabs/theme.js +4 -4
- package/dist/components/pill/Pill.mdx +32 -0
- package/dist/components/pill/Pill.stories.svelte +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/progress/Progress.mdx +50 -0
- package/dist/components/progress/Progress.stories.svelte +6 -6
- package/dist/components/snackbar/Snackbar.mdx +52 -0
- package/dist/components/snackbar/Snackbar.stories.svelte +5 -5
- package/dist/components/snackbar/Snackbar.svelte +1 -1
- package/dist/components/snackbar/theme.d.ts +3 -3
- package/dist/components/snackbar/theme.js +4 -4
- package/dist/components/table/Table.stories.svelte +1 -0
- package/dist/components/table/TableHeader.svelte +1 -1
- package/dist/components/table/theme.js +3 -3
- package/dist/components/time/TimeField.stories.svelte +3 -2
- package/dist/components/time/TimeField.svelte +14 -8
- package/dist/components/time/TimeField.svelte.d.ts +6 -0
- package/dist/components/time/TimepickerInput.svelte +9 -5
- package/dist/components/time/theme.js +5 -5
- package/dist/components/time/types.d.ts +11 -1
- package/dist/components/toolbar/Toolbar.stories.svelte +1 -0
- package/dist/components/toolbar/Toolbar.svelte +1 -1
- package/dist/components/toolbar/Toolbar.svelte.d.ts +1 -1
- package/dist/components/toolbar/theme.js +14 -14
- package/dist/components/typography/Typography.mdx +67 -0
- package/dist/components/typography/body/Body.stories.svelte +2 -1
- package/dist/components/typography/body/theme.d.ts +15 -12
- package/dist/components/typography/body/theme.js +19 -4
- package/dist/components/typography/body/types.d.ts +2 -1
- package/dist/components/typography/display/Display.stories.svelte +2 -1
- package/dist/components/typography/display/theme.d.ts +15 -12
- package/dist/components/typography/display/theme.js +19 -4
- package/dist/components/typography/display/types.d.ts +2 -1
- package/dist/components/typography/headline/Headline.stories.svelte +2 -1
- package/dist/components/typography/headline/theme.d.ts +15 -12
- package/dist/components/typography/headline/theme.js +19 -4
- package/dist/components/typography/headline/types.d.ts +2 -1
- package/dist/components/typography/kbd/Kbd.stories.svelte +2 -1
- package/dist/components/typography/kbd/theme.d.ts +4 -4
- package/dist/components/typography/kbd/theme.js +2 -2
- package/dist/components/typography/label/Label.stories.svelte +2 -1
- package/dist/components/typography/label/theme.d.ts +15 -12
- package/dist/components/typography/label/theme.js +19 -4
- package/dist/components/typography/label/types.d.ts +2 -1
- package/dist/components/typography/title/Title.stories.svelte +2 -1
- package/dist/components/typography/title/theme.d.ts +15 -12
- package/dist/components/typography/title/theme.js +19 -4
- package/dist/components/typography/title/types.d.ts +2 -1
- package/dist/index.css +1 -0
- package/dist/styles/component.css +78 -175
- package/dist/styles/elevation.css +9 -0
- package/dist/styles/spacing.css +29 -0
- package/dist/styles/typescale.css +635 -20
- package/dist/utils/Layer.svelte +1 -1
- package/dist/utils/icon/Icon.svelte +8 -6
- package/dist/utils/icon/loadingShapes.js +11 -10
- package/package.json +19 -15
- package/dist/components/containers/stack/HStack.svelte +0 -23
- package/dist/components/containers/stack/HStack.svelte.d.ts +0 -5
- package/dist/components/containers/stack/VStack.svelte +0 -23
- package/dist/components/containers/stack/VStack.svelte.d.ts +0 -5
- package/dist/components/containers/stack/index.d.ts +0 -4
- package/dist/components/containers/stack/theme.d.ts +0 -66
- package/dist/components/containers/stack/theme.js +0 -26
- package/dist/components/containers/stack/types.d.ts +0 -12
- /package/dist/components/containers/{stack → carousel}/types.js +0 -0
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
<!--
|
|
2
2
|
@component
|
|
3
|
-
|
|
4
|
-
shape (
|
|
5
|
-
through an overlaid check icon.
|
|
3
|
+
One item of a `ConnectedButtonGroup`: a toggle button. Selection shows through its colour and
|
|
4
|
+
shape (it rounds out), not a check mark.
|
|
6
5
|
-->
|
|
7
6
|
<script lang="ts">
|
|
8
7
|
import { ToggleGroup } from 'bits-ui';
|
|
9
8
|
import clsx from 'clsx';
|
|
10
9
|
import { getContext } from 'svelte';
|
|
11
10
|
import { Icon, Layer } from '../../../utils/index.js';
|
|
11
|
+
import { buttonColor, buttonElevation } from '../theme.js';
|
|
12
|
+
import { connectedCorners, shapeMorph } from '../shapeMorph.js';
|
|
12
13
|
import { connectedButtonGroupItem } from './theme.js';
|
|
13
14
|
import type { ConnectedButtonGroupCtx, ConnectedButtonGroupItemProps } from './types.js';
|
|
14
15
|
|
|
@@ -17,18 +18,44 @@ through an overlaid check icon.
|
|
|
17
18
|
label,
|
|
18
19
|
iconProps,
|
|
19
20
|
disabled = false,
|
|
21
|
+
'aria-label': ariaLabel,
|
|
20
22
|
class: className
|
|
21
23
|
}: ConnectedButtonGroupItemProps = $props();
|
|
22
24
|
|
|
25
|
+
let ref = $state<HTMLElement | null>(null);
|
|
26
|
+
$effect(() => (ref ? shapeMorph(ref, connectedCorners) : undefined));
|
|
27
|
+
|
|
23
28
|
const ctx = getContext<ConnectedButtonGroupCtx | undefined>('connectedButtonGroup');
|
|
24
|
-
const
|
|
25
|
-
const
|
|
26
|
-
|
|
29
|
+
const variant = $derived(ctx?.variant ?? 'filled');
|
|
30
|
+
const selected = $derived(
|
|
31
|
+
ctx?.type === 'multiple'
|
|
32
|
+
? Array.isArray(ctx.value) && ctx.value.includes(value)
|
|
33
|
+
: ctx?.value === value
|
|
34
|
+
);
|
|
35
|
+
const cls = $derived(
|
|
36
|
+
connectedButtonGroupItem({ size: ctx?.size ?? 'sm', shape: ctx?.shape ?? 'round' })
|
|
37
|
+
);
|
|
27
38
|
</script>
|
|
28
39
|
|
|
29
|
-
<ToggleGroup.Item
|
|
40
|
+
<ToggleGroup.Item
|
|
41
|
+
bind:ref
|
|
42
|
+
{value}
|
|
43
|
+
{disabled}
|
|
44
|
+
aria-label={ariaLabel}
|
|
45
|
+
class={cls.base({
|
|
46
|
+
class: clsx(
|
|
47
|
+
buttonColor({ variant, state: selected ? 'selected' : 'unselected' }),
|
|
48
|
+
buttonElevation[variant],
|
|
49
|
+
className
|
|
50
|
+
)
|
|
51
|
+
})}
|
|
52
|
+
>
|
|
30
53
|
{#if iconProps}
|
|
31
|
-
<Icon
|
|
54
|
+
<Icon
|
|
55
|
+
fill={selected ? 1 : 0}
|
|
56
|
+
{...iconProps}
|
|
57
|
+
class={cls.icon({ class: clsx(iconProps.class) })}
|
|
58
|
+
/>
|
|
32
59
|
{/if}
|
|
33
60
|
{#if label}
|
|
34
61
|
<span>{label}</span>
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import type { ConnectedButtonGroupItemProps } from './types.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
* shape (
|
|
5
|
-
* through an overlaid check icon.
|
|
3
|
+
* One item of a `ConnectedButtonGroup`: a toggle button. Selection shows through its colour and
|
|
4
|
+
* shape (it rounds out), not a check mark.
|
|
6
5
|
*/
|
|
7
6
|
declare const ConnectedButtonGroupItem: import("svelte").Component<ConnectedButtonGroupItemProps, {}, "">;
|
|
8
7
|
type ConnectedButtonGroupItem = ReturnType<typeof ConnectedButtonGroupItem>;
|
|
@@ -38,19 +38,24 @@ export declare const connectedButtonGroup: import("tailwind-variants").TVReturnT
|
|
|
38
38
|
export declare const connectedButtonGroupItem: import("tailwind-variants").TVReturnType<{
|
|
39
39
|
size: {
|
|
40
40
|
xs: {
|
|
41
|
-
base: string;
|
|
41
|
+
base: string[];
|
|
42
|
+
icon: "size-spacing-250 text-[20px]";
|
|
42
43
|
};
|
|
43
44
|
sm: {
|
|
44
|
-
base: string;
|
|
45
|
+
base: string[];
|
|
46
|
+
icon: "size-spacing-250 text-[20px]";
|
|
45
47
|
};
|
|
46
48
|
md: {
|
|
47
|
-
base: string;
|
|
49
|
+
base: string[];
|
|
50
|
+
icon: "size-spacing-300 text-[24px]";
|
|
48
51
|
};
|
|
49
52
|
lg: {
|
|
50
|
-
base: string;
|
|
53
|
+
base: string[];
|
|
54
|
+
icon: "size-spacing-400 text-[32px]";
|
|
51
55
|
};
|
|
52
56
|
xl: {
|
|
53
|
-
base: string;
|
|
57
|
+
base: string[];
|
|
58
|
+
icon: "size-spacing-500 text-[40px]";
|
|
54
59
|
};
|
|
55
60
|
};
|
|
56
61
|
shape: {
|
|
@@ -62,24 +67,29 @@ export declare const connectedButtonGroupItem: import("tailwind-variants").TVRet
|
|
|
62
67
|
};
|
|
63
68
|
};
|
|
64
69
|
}, {
|
|
65
|
-
base: string;
|
|
70
|
+
base: string[];
|
|
66
71
|
icon: string;
|
|
67
72
|
}, undefined, {
|
|
68
73
|
size: {
|
|
69
74
|
xs: {
|
|
70
|
-
base: string;
|
|
75
|
+
base: string[];
|
|
76
|
+
icon: "size-spacing-250 text-[20px]";
|
|
71
77
|
};
|
|
72
78
|
sm: {
|
|
73
|
-
base: string;
|
|
79
|
+
base: string[];
|
|
80
|
+
icon: "size-spacing-250 text-[20px]";
|
|
74
81
|
};
|
|
75
82
|
md: {
|
|
76
|
-
base: string;
|
|
83
|
+
base: string[];
|
|
84
|
+
icon: "size-spacing-300 text-[24px]";
|
|
77
85
|
};
|
|
78
86
|
lg: {
|
|
79
|
-
base: string;
|
|
87
|
+
base: string[];
|
|
88
|
+
icon: "size-spacing-400 text-[32px]";
|
|
80
89
|
};
|
|
81
90
|
xl: {
|
|
82
|
-
base: string;
|
|
91
|
+
base: string[];
|
|
92
|
+
icon: "size-spacing-500 text-[40px]";
|
|
83
93
|
};
|
|
84
94
|
};
|
|
85
95
|
shape: {
|
|
@@ -91,24 +101,29 @@ export declare const connectedButtonGroupItem: import("tailwind-variants").TVRet
|
|
|
91
101
|
};
|
|
92
102
|
};
|
|
93
103
|
}, {
|
|
94
|
-
base: string;
|
|
104
|
+
base: string[];
|
|
95
105
|
icon: string;
|
|
96
106
|
}, import("tailwind-variants").TVReturnTypeLike<{
|
|
97
107
|
size: {
|
|
98
108
|
xs: {
|
|
99
|
-
base: string;
|
|
109
|
+
base: string[];
|
|
110
|
+
icon: "size-spacing-250 text-[20px]";
|
|
100
111
|
};
|
|
101
112
|
sm: {
|
|
102
|
-
base: string;
|
|
113
|
+
base: string[];
|
|
114
|
+
icon: "size-spacing-250 text-[20px]";
|
|
103
115
|
};
|
|
104
116
|
md: {
|
|
105
|
-
base: string;
|
|
117
|
+
base: string[];
|
|
118
|
+
icon: "size-spacing-300 text-[24px]";
|
|
106
119
|
};
|
|
107
120
|
lg: {
|
|
108
|
-
base: string;
|
|
121
|
+
base: string[];
|
|
122
|
+
icon: "size-spacing-400 text-[32px]";
|
|
109
123
|
};
|
|
110
124
|
xl: {
|
|
111
|
-
base: string;
|
|
125
|
+
base: string[];
|
|
126
|
+
icon: "size-spacing-500 text-[40px]";
|
|
112
127
|
};
|
|
113
128
|
};
|
|
114
129
|
shape: {
|
|
@@ -120,6 +135,6 @@ export declare const connectedButtonGroupItem: import("tailwind-variants").TVRet
|
|
|
120
135
|
};
|
|
121
136
|
};
|
|
122
137
|
}, {
|
|
123
|
-
base: string;
|
|
138
|
+
base: string[];
|
|
124
139
|
icon: string;
|
|
125
140
|
}>>;
|
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import { tv } from 'tailwind-variants';
|
|
2
|
+
import { buttonBase, buttonSizes } from '../theme.js';
|
|
3
|
+
/*
|
|
4
|
+
* Connected button group, per https://m3.material.io/components/button-groups/specs: toggle
|
|
5
|
+
* buttons 2dp apart that share one outline shape. Items take the button's measurements for their
|
|
6
|
+
* size. Corners (`.md-btn-connected` in styles/component.css): inner corners --cbg-inner, then
|
|
7
|
+
* --cbg-pressed while pressed and fully round while selected; outer corners --cbg-outer, fully
|
|
8
|
+
* round or, for the square shape, the inner size. XS and S items are at least 48dp wide.
|
|
9
|
+
*/
|
|
2
10
|
export const connectedButtonGroup = tv({
|
|
3
11
|
slots: {
|
|
4
|
-
root: 'flex w-full items-stretch gap-
|
|
12
|
+
root: 'flex w-full items-stretch gap-spacing-25'
|
|
5
13
|
},
|
|
6
14
|
variants: {
|
|
7
15
|
orientation: {
|
|
@@ -15,19 +23,34 @@ export const connectedButtonGroup = tv({
|
|
|
15
23
|
});
|
|
16
24
|
export const connectedButtonGroupItem = tv({
|
|
17
25
|
slots: {
|
|
18
|
-
base: 'md-btn-connected
|
|
19
|
-
icon: '
|
|
26
|
+
base: [buttonBase, 'md-btn-connected min-w-spacing-600 flex-1'],
|
|
27
|
+
icon: 'shrink-0'
|
|
20
28
|
},
|
|
21
29
|
variants: {
|
|
22
30
|
size: {
|
|
23
|
-
xs: {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
31
|
+
xs: {
|
|
32
|
+
base: [buttonSizes.xs.base, '[--cbg-inner:0.5rem] [--cbg-pressed:0.25rem]'],
|
|
33
|
+
icon: buttonSizes.xs.icon
|
|
34
|
+
},
|
|
35
|
+
sm: {
|
|
36
|
+
base: [buttonSizes.sm.base, '[--cbg-inner:0.5rem] [--cbg-pressed:0.25rem]'],
|
|
37
|
+
icon: buttonSizes.sm.icon
|
|
38
|
+
},
|
|
39
|
+
md: {
|
|
40
|
+
base: [buttonSizes.md.base, '[--cbg-inner:0.5rem] [--cbg-pressed:0.25rem]'],
|
|
41
|
+
icon: buttonSizes.md.icon
|
|
42
|
+
},
|
|
43
|
+
lg: {
|
|
44
|
+
base: [buttonSizes.lg.base, '[--cbg-inner:1rem] [--cbg-pressed:0.75rem]'],
|
|
45
|
+
icon: buttonSizes.lg.icon
|
|
46
|
+
},
|
|
47
|
+
xl: {
|
|
48
|
+
base: [buttonSizes.xl.base, '[--cbg-inner:1.25rem] [--cbg-pressed:1rem]'],
|
|
49
|
+
icon: buttonSizes.xl.icon
|
|
50
|
+
}
|
|
28
51
|
},
|
|
29
52
|
shape: {
|
|
30
|
-
round: { base: '[--cbg-outer:
|
|
53
|
+
round: { base: '[--cbg-outer:var(--btn-round)]' },
|
|
31
54
|
square: { base: '[--cbg-outer:var(--cbg-inner)]' }
|
|
32
55
|
}
|
|
33
56
|
},
|
|
@@ -1,33 +1,60 @@
|
|
|
1
1
|
import type { IconProps } from '../../../utils/index.js';
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
|
+
import type { ButtonSize } from '../theme.js';
|
|
3
4
|
import type { ConnectedButtonGroupVariants } from './theme.js';
|
|
5
|
+
export type ConnectedButtonGroupVariant = 'elevated' | 'filled' | 'tonal' | 'outlined';
|
|
4
6
|
export type ConnectedButtonGroupCtx = {
|
|
5
|
-
size:
|
|
7
|
+
size: ButtonSize;
|
|
6
8
|
shape: 'round' | 'square';
|
|
9
|
+
variant: ConnectedButtonGroupVariant;
|
|
10
|
+
type: 'single' | 'multiple';
|
|
11
|
+
value: any;
|
|
7
12
|
};
|
|
8
13
|
export type ConnectedButtonGroupProps = ConnectedButtonGroupVariants & {
|
|
9
|
-
/**
|
|
14
|
+
/** One selected item at a time, or several. */
|
|
10
15
|
type: 'single' | 'multiple';
|
|
11
|
-
/**
|
|
16
|
+
/** The selected value (`single`) or values (`multiple`). Bindable. */
|
|
12
17
|
value?: any;
|
|
18
|
+
/** Called when the selection changes. */
|
|
13
19
|
onValueChange?: (value: any) => void;
|
|
20
|
+
/** Disables every item. */
|
|
14
21
|
disabled?: boolean;
|
|
22
|
+
/** Whether arrow keys wrap from the last item to the first. @default true */
|
|
15
23
|
loop?: boolean;
|
|
24
|
+
/** @default 'horizontal' */
|
|
16
25
|
orientation?: 'horizontal' | 'vertical';
|
|
17
|
-
/**
|
|
26
|
+
/**
|
|
27
|
+
* Toggle button colour style of the items: unselected and selected colours as for `Toggle`.
|
|
28
|
+
* @default 'filled'
|
|
29
|
+
*/
|
|
30
|
+
variant?: ConnectedButtonGroupVariant;
|
|
31
|
+
/**
|
|
32
|
+
* Outer corners: fully round, or square (the inner corner size). Inner corners are the same
|
|
33
|
+
* for both.
|
|
34
|
+
* @default 'round'
|
|
35
|
+
*/
|
|
18
36
|
shape?: ConnectedButtonGroupCtx['shape'];
|
|
19
|
-
/**
|
|
20
|
-
|
|
37
|
+
/**
|
|
38
|
+
* Height, padding and type of the items, as for `Button`: 32, 40, 56, 96 or 136dp.
|
|
39
|
+
* @default 'sm'
|
|
40
|
+
*/
|
|
41
|
+
size?: ButtonSize;
|
|
42
|
+
/** `ConnectedButtonGroupItem`s. */
|
|
21
43
|
children?: Snippet;
|
|
44
|
+
/** Accessible name of the group. */
|
|
45
|
+
'aria-label'?: string;
|
|
22
46
|
class?: string;
|
|
23
47
|
};
|
|
24
48
|
export type ConnectedButtonGroupItemProps = {
|
|
25
|
-
/** The value this item
|
|
49
|
+
/** The value this item selects. */
|
|
26
50
|
value: string;
|
|
27
|
-
/**
|
|
51
|
+
/** The label. */
|
|
28
52
|
label?: string;
|
|
29
|
-
/**
|
|
53
|
+
/** A leading icon. It fills while the item is selected. */
|
|
30
54
|
iconProps?: IconProps;
|
|
55
|
+
/** Accessible name, for an item with only an icon. */
|
|
56
|
+
'aria-label'?: string;
|
|
57
|
+
/** Disables the item. */
|
|
31
58
|
disabled?: boolean;
|
|
32
59
|
class?: string;
|
|
33
60
|
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export type ButtonState = {
|
|
2
|
+
pressed: boolean;
|
|
3
|
+
/** A mouse or pen over the button (never touch, where hover sticks after a tap). */
|
|
4
|
+
hovered: boolean;
|
|
5
|
+
focusVisible: boolean;
|
|
6
|
+
};
|
|
7
|
+
/** Corner radii in px, in logical order: start-start, start-end, end-end, end-start. */
|
|
8
|
+
export type Corners = [number, number, number, number];
|
|
9
|
+
type CornerResolver = (el: HTMLElement, state: ButtonState, px: (prop: string) => number) => Corners;
|
|
10
|
+
/** Springs `el`'s four corners to whatever `corners` resolves for its current state. */
|
|
11
|
+
export declare function shapeMorph(el: HTMLElement, corners: CornerResolver): () => void;
|
|
12
|
+
/** Button, Toggle, ButtonIcon: --btn-shape at rest, --btn-pressed while pressed. */
|
|
13
|
+
export declare const buttonCorners: CornerResolver;
|
|
14
|
+
/**
|
|
15
|
+
* Split button halves. Outer corners stay round; inner corners are --split-inner at rest,
|
|
16
|
+
* --split-active while hovered, focused or pressed, and fully round on the trailing button while
|
|
17
|
+
* its menu is open.
|
|
18
|
+
*/
|
|
19
|
+
export declare const splitCorners: (side: "leading" | "trailing") => CornerResolver;
|
|
20
|
+
/**
|
|
21
|
+
* Connected button group items. Inner corners (facing a neighbour) are --cbg-inner, then
|
|
22
|
+
* --cbg-pressed while pressed and fully round while selected; outer corners (the group's ends)
|
|
23
|
+
* are --cbg-outer.
|
|
24
|
+
*/
|
|
25
|
+
export declare const connectedCorners: CornerResolver;
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { springTokens, springTransition } from '../../animation/spring.js';
|
|
2
|
+
import { animate, motionValue } from 'motion';
|
|
3
|
+
const CORNER_PROPS = [
|
|
4
|
+
'borderStartStartRadius',
|
|
5
|
+
'borderStartEndRadius',
|
|
6
|
+
'borderEndEndRadius',
|
|
7
|
+
'borderEndStartRadius'
|
|
8
|
+
];
|
|
9
|
+
/** A length custom property in px. Handles the px, rem and em values the button classes use. */
|
|
10
|
+
const lengthVar = (el, style, prop) => {
|
|
11
|
+
const value = style.getPropertyValue(prop).trim();
|
|
12
|
+
const n = parseFloat(value);
|
|
13
|
+
if (Number.isNaN(n))
|
|
14
|
+
return 0;
|
|
15
|
+
if (value.endsWith('rem'))
|
|
16
|
+
return n * parseFloat(getComputedStyle(document.documentElement).fontSize);
|
|
17
|
+
if (value.endsWith('em'))
|
|
18
|
+
return n * parseFloat(style.fontSize);
|
|
19
|
+
if (value.endsWith('%'))
|
|
20
|
+
return (n / 100) * Math.min(el.offsetWidth, el.offsetHeight);
|
|
21
|
+
return n;
|
|
22
|
+
};
|
|
23
|
+
const isDisabled = (el) => el.matches(':disabled, [aria-disabled="true"], [data-disabled]');
|
|
24
|
+
/** Springs `el`'s four corners to whatever `corners` resolves for its current state. */
|
|
25
|
+
export function shapeMorph(el, corners) {
|
|
26
|
+
const reduced = matchMedia('(prefers-reduced-motion: reduce)');
|
|
27
|
+
const spring = springTransition(springTokens.fastSpatial);
|
|
28
|
+
const state = { pressed: false, hovered: false, focusVisible: false };
|
|
29
|
+
const resolve = () => {
|
|
30
|
+
const style = getComputedStyle(el);
|
|
31
|
+
return corners(el, state, (prop) => lengthVar(el, style, prop));
|
|
32
|
+
};
|
|
33
|
+
const initial = resolve();
|
|
34
|
+
const values = initial.map((r) => motionValue(r));
|
|
35
|
+
const controls = [];
|
|
36
|
+
const unsubscribe = values.map((v, i) => v.on('change', (r) => (el.style[CORNER_PROPS[i]] = `${r}px`)));
|
|
37
|
+
values.forEach((v, i) => (el.style[CORNER_PROPS[i]] = `${v.get()}px`));
|
|
38
|
+
// Each spring restarts only when its target changes; a retarget mid-flight inherits velocity.
|
|
39
|
+
const targets = [...initial];
|
|
40
|
+
const retarget = () => {
|
|
41
|
+
resolve().forEach((to, i) => {
|
|
42
|
+
if (to === targets[i])
|
|
43
|
+
return;
|
|
44
|
+
targets[i] = to;
|
|
45
|
+
controls[i]?.stop();
|
|
46
|
+
if (reduced.matches)
|
|
47
|
+
values[i].jump(to);
|
|
48
|
+
else
|
|
49
|
+
controls[i] = animate(values[i], to, spring);
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
const set = (key, on) => {
|
|
53
|
+
if (state[key] === on)
|
|
54
|
+
return;
|
|
55
|
+
state[key] = on;
|
|
56
|
+
retarget();
|
|
57
|
+
};
|
|
58
|
+
const onPointerDown = (e) => {
|
|
59
|
+
if (e.button === 0 && !isDisabled(el))
|
|
60
|
+
set('pressed', true);
|
|
61
|
+
};
|
|
62
|
+
const onKeyDown = (e) => {
|
|
63
|
+
if (!e.repeat && (e.key === ' ' || e.key === 'Enter') && !isDisabled(el))
|
|
64
|
+
set('pressed', true);
|
|
65
|
+
};
|
|
66
|
+
const release = () => set('pressed', false);
|
|
67
|
+
const onEnter = (e) => {
|
|
68
|
+
if (e.pointerType !== 'touch')
|
|
69
|
+
set('hovered', true);
|
|
70
|
+
};
|
|
71
|
+
const onLeave = () => set('hovered', false);
|
|
72
|
+
const onFocus = () => set('focusVisible', el.matches(':focus-visible'));
|
|
73
|
+
const onBlur = () => {
|
|
74
|
+
state.pressed = false;
|
|
75
|
+
set('focusVisible', false);
|
|
76
|
+
};
|
|
77
|
+
// Selection, open state, size and shape arrive as attribute changes. Not `style`: the springs
|
|
78
|
+
// write the corners there every frame.
|
|
79
|
+
const observer = new MutationObserver(retarget);
|
|
80
|
+
observer.observe(el, {
|
|
81
|
+
attributes: true,
|
|
82
|
+
attributeFilter: ['class', 'data-state', 'aria-pressed', 'aria-expanded']
|
|
83
|
+
});
|
|
84
|
+
el.addEventListener('pointerdown', onPointerDown);
|
|
85
|
+
el.addEventListener('pointerenter', onEnter);
|
|
86
|
+
el.addEventListener('pointerleave', onLeave);
|
|
87
|
+
el.addEventListener('keydown', onKeyDown);
|
|
88
|
+
el.addEventListener('keyup', release);
|
|
89
|
+
el.addEventListener('focus', onFocus);
|
|
90
|
+
el.addEventListener('blur', onBlur);
|
|
91
|
+
window.addEventListener('pointerup', release);
|
|
92
|
+
window.addEventListener('pointercancel', release);
|
|
93
|
+
return () => {
|
|
94
|
+
observer.disconnect();
|
|
95
|
+
controls.forEach((c) => c?.stop());
|
|
96
|
+
unsubscribe.forEach((u) => u());
|
|
97
|
+
el.removeEventListener('pointerdown', onPointerDown);
|
|
98
|
+
el.removeEventListener('pointerenter', onEnter);
|
|
99
|
+
el.removeEventListener('pointerleave', onLeave);
|
|
100
|
+
el.removeEventListener('keydown', onKeyDown);
|
|
101
|
+
el.removeEventListener('keyup', release);
|
|
102
|
+
el.removeEventListener('focus', onFocus);
|
|
103
|
+
el.removeEventListener('blur', onBlur);
|
|
104
|
+
window.removeEventListener('pointerup', release);
|
|
105
|
+
window.removeEventListener('pointercancel', release);
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
const all = (r) => [r, r, r, r];
|
|
109
|
+
/** Button, Toggle, ButtonIcon: --btn-shape at rest, --btn-pressed while pressed. */
|
|
110
|
+
export const buttonCorners = (_el, { pressed }, px) => all(pressed ? px('--btn-pressed') || px('--btn-shape') : px('--btn-shape'));
|
|
111
|
+
/**
|
|
112
|
+
* Split button halves. Outer corners stay round; inner corners are --split-inner at rest,
|
|
113
|
+
* --split-active while hovered, focused or pressed, and fully round on the trailing button while
|
|
114
|
+
* its menu is open.
|
|
115
|
+
*/
|
|
116
|
+
export const splitCorners = (side) => (el, { pressed, hovered, focusVisible }, px) => {
|
|
117
|
+
const outer = px('--btn-round');
|
|
118
|
+
const open = side === 'trailing' && el.dataset.state === 'open';
|
|
119
|
+
const active = (pressed || hovered || focusVisible) && !isDisabled(el);
|
|
120
|
+
const inner = open ? outer : active ? px('--split-active') : px('--split-inner');
|
|
121
|
+
return side === 'leading' ? [outer, inner, inner, outer] : [inner, outer, outer, inner];
|
|
122
|
+
};
|
|
123
|
+
/**
|
|
124
|
+
* Connected button group items. Inner corners (facing a neighbour) are --cbg-inner, then
|
|
125
|
+
* --cbg-pressed while pressed and fully round while selected; outer corners (the group's ends)
|
|
126
|
+
* are --cbg-outer.
|
|
127
|
+
*/
|
|
128
|
+
export const connectedCorners = (el, { pressed }, px) => {
|
|
129
|
+
const selected = el.dataset.state === 'on';
|
|
130
|
+
const inner = pressed && !isDisabled(el)
|
|
131
|
+
? px('--cbg-pressed')
|
|
132
|
+
: selected
|
|
133
|
+
? px('--btn-round')
|
|
134
|
+
: px('--cbg-inner');
|
|
135
|
+
const outer = px('--cbg-outer');
|
|
136
|
+
const first = el.parentElement?.firstElementChild === el;
|
|
137
|
+
const last = el.parentElement?.lastElementChild === el;
|
|
138
|
+
const s = first ? outer : inner;
|
|
139
|
+
const e = last ? outer : inner;
|
|
140
|
+
// Horizontal: the start corners face the previous item. Vertical: the top corners do.
|
|
141
|
+
return el.dataset.orientation === 'vertical' ? [s, s, e, e] : [s, e, e, s];
|
|
142
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Meta, Title, Subtitle, Canvas, Controls } from '@storybook/addon-docs/blocks';
|
|
2
|
+
import * as SplitStories from './SplitButton.stories.svelte';
|
|
3
|
+
|
|
4
|
+
<Meta of={SplitStories} />
|
|
5
|
+
|
|
6
|
+
<Title />
|
|
7
|
+
|
|
8
|
+
<Subtitle>Split buttons open a menu of options related to their main action.</Subtitle>
|
|
9
|
+
|
|
10
|
+
[M3 spec](https://m3.material.io/components/split-button/specs) ·
|
|
11
|
+
`import { SplitButton } from '@noxlovette/material';`
|
|
12
|
+
|
|
13
|
+
<Canvas of={SplitStories.Playground} />
|
|
14
|
+
|
|
15
|
+
<Controls of={SplitStories.Playground} />
|
|
16
|
+
|
|
17
|
+
## Anatomy
|
|
18
|
+
|
|
19
|
+
- **Leading button:** the main action, with a label, an icon, or both. An icon-only leading
|
|
20
|
+
button needs an `aria-label`.
|
|
21
|
+
- **Trailing button:** always a menu icon. It opens the menu (`menuLabel` names it) and flips the
|
|
22
|
+
icon while open.
|
|
23
|
+
|
|
24
|
+
The two share one colour style (elevated, filled, tonal or outlined; there is no text split
|
|
25
|
+
button), and opening the menu doesn't change their colours.
|
|
26
|
+
|
|
27
|
+
<Canvas of={SplitStories.WithLeadingIcon} />
|
|
28
|
+
|
|
29
|
+
## Shape and size
|
|
30
|
+
|
|
31
|
+
The buttons sit 2dp apart. Their outer corners are fully round; the inner corners are small at
|
|
32
|
+
rest and round out while hovered, focused or pressed. While the menu is open, the trailing
|
|
33
|
+
button becomes fully round and centres its icon, which sits slightly toward the leading button
|
|
34
|
+
otherwise.
|
|
35
|
+
|
|
36
|
+
| `size` | Height | Inner corner | Hovered/pressed | Trailing width | Menu icon |
|
|
37
|
+
| ------ | ------ | ------------ | --------------- | -------------- | --------- |
|
|
38
|
+
| `xs` | 32dp | 4dp | 8dp | 48dp | 22dp |
|
|
39
|
+
| `sm` | 40dp | 4dp | 12dp | 48dp | 22dp |
|
|
40
|
+
| `md` | 56dp | 4dp | 12dp | 56dp | 26dp |
|
|
41
|
+
| `lg` | 96dp | 8dp | 20dp | 96dp | 38dp |
|
|
42
|
+
| `xl` | 136dp | 12dp | 20dp | 136dp | 50dp |
|
|
43
|
+
|
|
44
|
+
<Canvas of={SplitStories.Sizes} />
|
|
45
|
+
|
|
46
|
+
## Migrating
|
|
47
|
+
|
|
48
|
+
`color` and the `text` variant are gone, and the default size is now `sm`.
|
|
@@ -9,11 +9,7 @@
|
|
|
9
9
|
argTypes: {
|
|
10
10
|
variant: {
|
|
11
11
|
control: 'select',
|
|
12
|
-
options: ['elevated', 'filled', 'tonal', 'outlined'
|
|
13
|
-
},
|
|
14
|
-
color: {
|
|
15
|
-
control: 'select',
|
|
16
|
-
options: ['default', 'primary', 'secondary', 'tertiary', 'error']
|
|
12
|
+
options: ['elevated', 'filled', 'tonal', 'outlined']
|
|
17
13
|
},
|
|
18
14
|
size: {
|
|
19
15
|
control: 'select',
|
|
@@ -22,15 +18,14 @@
|
|
|
22
18
|
},
|
|
23
19
|
args: {
|
|
24
20
|
variant: 'filled',
|
|
25
|
-
|
|
26
|
-
size: 'md'
|
|
21
|
+
size: 'sm'
|
|
27
22
|
}
|
|
28
23
|
});
|
|
29
24
|
</script>
|
|
30
25
|
|
|
31
26
|
<Story name="Playground">
|
|
32
27
|
{#snippet template(args)}
|
|
33
|
-
<SplitButton variant={args.variant}
|
|
28
|
+
<SplitButton variant={args.variant} size={args.size}>
|
|
34
29
|
{#snippet children()}
|
|
35
30
|
Reply
|
|
36
31
|
{/snippet}
|
|
@@ -42,8 +37,8 @@
|
|
|
42
37
|
{/snippet}
|
|
43
38
|
</Story>
|
|
44
39
|
|
|
45
|
-
<Story name="
|
|
46
|
-
<div class="p-
|
|
40
|
+
<Story name="With leading icon" asChild>
|
|
41
|
+
<div class="p-spacing-300">
|
|
47
42
|
<SplitButton iconProps={{ name: 'send' }}>
|
|
48
43
|
{#snippet children()}
|
|
49
44
|
Send
|
|
@@ -57,8 +52,8 @@
|
|
|
57
52
|
</Story>
|
|
58
53
|
|
|
59
54
|
<Story name="Variants" asChild>
|
|
60
|
-
<div class="flex flex-wrap items-center
|
|
61
|
-
{#each ['elevated', 'filled', 'tonal', 'outlined'
|
|
55
|
+
<div class="gap-spacing-300 p-spacing-300 flex flex-wrap items-center">
|
|
56
|
+
{#each ['elevated', 'filled', 'tonal', 'outlined'] as const as variant (variant)}
|
|
62
57
|
<SplitButton {variant}>
|
|
63
58
|
{#snippet children()}
|
|
64
59
|
Reply
|
|
@@ -73,7 +68,7 @@
|
|
|
73
68
|
</Story>
|
|
74
69
|
|
|
75
70
|
<Story name="Sizes" asChild>
|
|
76
|
-
<div class="flex flex-
|
|
71
|
+
<div class="gap-spacing-300 p-spacing-300 flex flex-col items-start">
|
|
77
72
|
{#each ['xs', 'sm', 'md', 'lg', 'xl'] as const as size (size)}
|
|
78
73
|
<SplitButton {size}>
|
|
79
74
|
{#snippet children()}
|
|
@@ -89,7 +84,7 @@
|
|
|
89
84
|
</Story>
|
|
90
85
|
|
|
91
86
|
<Story name="Disabled" asChild>
|
|
92
|
-
<div class="p-
|
|
87
|
+
<div class="p-spacing-300">
|
|
93
88
|
<SplitButton disabled>
|
|
94
89
|
{#snippet children()}
|
|
95
90
|
Reply
|