@noxlovette/material 0.5.1 → 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 +10 -6
- package/dist/animation/TransitionPatterns.stories.svelte +30 -20
- package/dist/animation/containerTransform.d.ts +4 -2
- package/dist/animation/containerTransform.js +4 -2
- package/dist/animation/enterExit.js +5 -2
- package/dist/animation/skeleton.d.ts +1 -1
- package/dist/animation/skeleton.js +1 -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 +11 -2
- package/dist/components/date/DateRangeField.stories.svelte +4 -3
- package/dist/components/date/DateRangeField.svelte +12 -3
- package/dist/components/date/theme.d.ts +7 -7
- package/dist/components/date/theme.js +31 -31
- 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.js +19 -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/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 +1 -1
- package/dist/components/time/TimepickerInput.svelte +1 -1
- package/dist/components/time/theme.js +5 -5
- 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/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
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Meta, Title, Subtitle, Canvas, ArgTypes } from '@storybook/addon-docs/blocks';
|
|
2
|
+
import * as SheetStories from './BottomSheet.stories.svelte';
|
|
3
|
+
|
|
4
|
+
<Meta of={SheetStories} />
|
|
5
|
+
|
|
6
|
+
<Title />
|
|
7
|
+
|
|
8
|
+
<Subtitle>Bottom sheets show secondary content anchored to the bottom of the screen.</Subtitle>
|
|
9
|
+
|
|
10
|
+
[M3 spec](https://m3.material.io/components/bottom-sheets/specs) ·
|
|
11
|
+
`import { BottomSheet } from '@noxlovette/material';`
|
|
12
|
+
|
|
13
|
+
<Canvas of={SheetStories.Modal} />
|
|
14
|
+
|
|
15
|
+
<ArgTypes />
|
|
16
|
+
|
|
17
|
+
## Modal or standard
|
|
18
|
+
|
|
19
|
+
- **`modal`** (default) opens in front of the app above a scrim, and blocks everything else until
|
|
20
|
+
it's dismissed. Use it for actions or choices that need an answer, such as a share sheet. It is
|
|
21
|
+
a native `<dialog>` opened with `showModal()`, so the browser handles the focus trap, top-layer
|
|
22
|
+
stacking and making the page behind it inert.
|
|
23
|
+
- **`standard`** leaves the rest of the screen usable, like an audio player over a list. There is
|
|
24
|
+
no scrim, and it never dismisses itself: the drag handle toggles `expanded` between its full
|
|
25
|
+
height and `peekHeight`. Hide it by setting `open` to false.
|
|
26
|
+
|
|
27
|
+
<Canvas of={SheetStories.Standard} />
|
|
28
|
+
|
|
29
|
+
## Opening and dismissing
|
|
30
|
+
|
|
31
|
+
Bind `open`. The sheet slides up on the spatial spring, and when it closes it stays mounted until
|
|
32
|
+
the slide out finishes. It slides without fading, as M3 asks of sheets.
|
|
33
|
+
|
|
34
|
+
A modal sheet dismisses itself, sets `open` to false, and tells `close` why:
|
|
35
|
+
|
|
36
|
+
| Reason | When |
|
|
37
|
+
| -------- | ------------------------------------------------------------ |
|
|
38
|
+
| `esc` | Escape |
|
|
39
|
+
| `scrim` | A tap on the scrim |
|
|
40
|
+
| `drag` | A flick down, or a drag past half the sheet's height |
|
|
41
|
+
| `handle` | Activating the drag handle (Enter, Space, a click, or a tap) |
|
|
42
|
+
|
|
43
|
+
A shorter drag springs back, carrying the finger's velocity.
|
|
44
|
+
|
|
45
|
+
## Size
|
|
46
|
+
|
|
47
|
+
The sheet spans the window up to 640dp. On windows over 640dp wide it keeps 56dp side margins.
|
|
48
|
+
It stops 72dp below the top of the window (56dp over 640dp), and taller content scrolls inside
|
|
49
|
+
it, under the drag handle.
|
|
50
|
+
|
|
51
|
+
The sheet doesn't pad its content, so lists can run edge to edge. Pad other content yourself;
|
|
52
|
+
M3 sheets usually keep text 16–24dp from the edges.
|
|
53
|
+
|
|
54
|
+
<Canvas of={SheetStories.ScrollingContent} />
|
|
55
|
+
|
|
56
|
+
## Accessibility
|
|
57
|
+
|
|
58
|
+
- **Name the sheet.** Use `label`, or point `aria-labelledby` at a heading inside it.
|
|
59
|
+
- **The drag handle is a button**, 48dp, with the 3dp focus ring. For keyboard and screen reader
|
|
60
|
+
users it does what dragging does: it reads "Close sheet" on a modal sheet, and "Expand sheet" or
|
|
61
|
+
"Collapse sheet" on a standard one. Only hide it (`hideHandle`) on a sheet that can't be dragged
|
|
62
|
+
anyway.
|
|
63
|
+
- A modal sheet moves focus into itself when it opens (to the handle, the first focusable
|
|
64
|
+
element), and the browser returns focus to the opener when it closes.
|
|
@@ -1,31 +1,127 @@
|
|
|
1
1
|
<!--
|
|
2
|
-
BottomSheet is controlled with `bind:open
|
|
3
|
-
dragging
|
|
4
|
-
|
|
2
|
+
BottomSheet is controlled with `bind:open`. A modal sheet dismisses itself (Esc, scrim tap,
|
|
3
|
+
dragging it down, activating the handle) and reports why through `close`. A standard sheet
|
|
4
|
+
never dismisses itself: dragging or activating the handle toggles `expanded`.
|
|
5
5
|
-->
|
|
6
6
|
<script module lang="ts">
|
|
7
7
|
import { defineMeta } from '@storybook/addon-svelte-csf';
|
|
8
8
|
import BottomSheet from './BottomSheet.svelte';
|
|
9
9
|
import Button from '../../buttons/Button.svelte';
|
|
10
|
-
import
|
|
10
|
+
import ButtonIcon from '../../buttons/ButtonIcon.svelte';
|
|
11
|
+
import List from '../list/List.svelte';
|
|
12
|
+
import ListItem from '../list/ListItem.svelte';
|
|
13
|
+
import Icon from '../../../utils/icon/Icon.svelte';
|
|
11
14
|
|
|
12
15
|
const { Story } = defineMeta({
|
|
13
16
|
title: 'Containers/Bottom Sheet',
|
|
14
17
|
component: BottomSheet
|
|
15
18
|
});
|
|
19
|
+
|
|
20
|
+
const shareTargets = [
|
|
21
|
+
{ name: 'share', label: 'Share' },
|
|
22
|
+
{ name: 'link', label: 'Copy link' },
|
|
23
|
+
{ name: 'download', label: 'Download' },
|
|
24
|
+
{ name: 'edit', label: 'Rename' },
|
|
25
|
+
{ name: 'delete', label: 'Move to trash' }
|
|
26
|
+
];
|
|
16
27
|
</script>
|
|
17
28
|
|
|
18
29
|
<script lang="ts">
|
|
19
|
-
let
|
|
30
|
+
let modalOpen = $state(false);
|
|
31
|
+
let lastReason = $state('');
|
|
32
|
+
let longOpen = $state(false);
|
|
33
|
+
let playerOpen = $state(true);
|
|
34
|
+
let playerExpanded = $state(false);
|
|
20
35
|
</script>
|
|
21
36
|
|
|
22
|
-
<Story name="
|
|
23
|
-
<div class="p-
|
|
24
|
-
<Button onclick={() => (
|
|
25
|
-
<
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
37
|
+
<Story name="Modal" asChild>
|
|
38
|
+
<div class="gap-spacing-100 p-spacing-300 flex flex-col items-start">
|
|
39
|
+
<Button onclick={() => (modalOpen = true)}>Open bottom sheet</Button>
|
|
40
|
+
<p class="md-sys-typescale-body-medium">
|
|
41
|
+
{lastReason ? `Dismissed by: ${lastReason}` : 'Drag it down, tap the scrim, or press Esc.'}
|
|
42
|
+
</p>
|
|
43
|
+
<BottomSheet bind:open={modalOpen} label="File actions" close={(r) => (lastReason = r)}>
|
|
44
|
+
<List class="pb-spacing-200">
|
|
45
|
+
{#each shareTargets as t (t.name)}
|
|
46
|
+
<ListItem headline={t.label} onclick={() => (modalOpen = false)}>
|
|
47
|
+
{#snippet leading()}
|
|
48
|
+
<Icon name={t.name} size="sm" />
|
|
49
|
+
{/snippet}
|
|
50
|
+
</ListItem>
|
|
51
|
+
{/each}
|
|
52
|
+
</List>
|
|
53
|
+
</BottomSheet>
|
|
54
|
+
</div>
|
|
55
|
+
</Story>
|
|
56
|
+
|
|
57
|
+
<Story name="Scrolling content" asChild>
|
|
58
|
+
<div class="p-spacing-300">
|
|
59
|
+
<Button onclick={() => (longOpen = true)}>Open a long sheet</Button>
|
|
60
|
+
<BottomSheet bind:open={longOpen} aria-labelledby="terms-heading">
|
|
61
|
+
<div class="gap-spacing-200 px-spacing-300 pb-spacing-300 flex flex-col">
|
|
62
|
+
<h2 id="terms-heading" class="md-sys-typescale-title-large">Terms of service</h2>
|
|
63
|
+
{#each { length: 12 } as _, i (i)}
|
|
64
|
+
<p class="md-sys-typescale-body-medium text-md-sys-color-on-surface-variant">
|
|
65
|
+
{i + 1}. The sheet stops 72dp below the top of the window (56dp on wider windows) and
|
|
66
|
+
this content scrolls inside it. The drag handle stays put.
|
|
67
|
+
</p>
|
|
68
|
+
{/each}
|
|
69
|
+
<Button onclick={() => (longOpen = false)}>Accept</Button>
|
|
70
|
+
</div>
|
|
71
|
+
</BottomSheet>
|
|
72
|
+
</div>
|
|
73
|
+
</Story>
|
|
74
|
+
|
|
75
|
+
<!-- Its own iframe on the docs page: an open, fixed-position sheet would cover the docs. -->
|
|
76
|
+
<Story name="Standard" asChild parameters={{ docs: { story: { inline: false, height: '36rem' } } }}>
|
|
77
|
+
<div class="gap-spacing-200 p-spacing-300 flex min-h-[32rem] flex-col">
|
|
78
|
+
<p class="md-sys-typescale-body-large max-w-md">
|
|
79
|
+
A standard sheet leaves the page usable. Drag the handle, or activate it, to expand and
|
|
80
|
+
collapse the player.
|
|
81
|
+
</p>
|
|
82
|
+
<div class="gap-spacing-100 flex">
|
|
83
|
+
<Button variant="tonal" onclick={() => (playerOpen = !playerOpen)}>
|
|
84
|
+
{playerOpen ? 'Hide player' : 'Show player'}
|
|
85
|
+
</Button>
|
|
86
|
+
<Button variant="text" onclick={() => (playerExpanded = !playerExpanded)}>
|
|
87
|
+
{playerExpanded ? 'Collapse' : 'Expand'}
|
|
88
|
+
</Button>
|
|
89
|
+
</div>
|
|
90
|
+
<BottomSheet
|
|
91
|
+
variant="standard"
|
|
92
|
+
bind:open={playerOpen}
|
|
93
|
+
bind:expanded={playerExpanded}
|
|
94
|
+
peekHeight={120}
|
|
95
|
+
label="Now playing"
|
|
96
|
+
>
|
|
97
|
+
<div class="gap-spacing-300 px-spacing-300 pb-spacing-300 flex flex-col">
|
|
98
|
+
<div class="gap-spacing-200 flex items-center">
|
|
99
|
+
<div
|
|
100
|
+
class="bg-md-sys-color-tertiary-container text-md-sys-color-on-tertiary-container size-spacing-700 flex items-center justify-center rounded-lg"
|
|
101
|
+
>
|
|
102
|
+
<Icon name="music_note" />
|
|
103
|
+
</div>
|
|
104
|
+
<div class="min-w-spacing-0 flex-1">
|
|
105
|
+
<p class="md-sys-typescale-title-medium">Harbour lights</p>
|
|
106
|
+
<p class="md-sys-typescale-body-medium text-md-sys-color-on-surface-variant">
|
|
107
|
+
The Tidelines
|
|
108
|
+
</p>
|
|
109
|
+
</div>
|
|
110
|
+
<ButtonIcon variant="filled" iconProps={{ name: 'pause' }} aria-label="Pause" />
|
|
111
|
+
</div>
|
|
112
|
+
<div
|
|
113
|
+
class="bg-md-sys-color-secondary-container aspect-square w-full max-w-72 self-center rounded-3xl"
|
|
114
|
+
></div>
|
|
115
|
+
<div class="gap-spacing-200 flex justify-center">
|
|
116
|
+
<ButtonIcon
|
|
117
|
+
variant="standard"
|
|
118
|
+
iconProps={{ name: 'skip_previous' }}
|
|
119
|
+
aria-label="Previous"
|
|
120
|
+
/>
|
|
121
|
+
<ButtonIcon variant="filled" iconProps={{ name: 'pause' }} aria-label="Pause" />
|
|
122
|
+
<ButtonIcon variant="standard" iconProps={{ name: 'skip_next' }} aria-label="Next" />
|
|
123
|
+
</div>
|
|
124
|
+
</div>
|
|
29
125
|
</BottomSheet>
|
|
30
126
|
</div>
|
|
31
127
|
</Story>
|
|
@@ -1,137 +1,207 @@
|
|
|
1
1
|
<!--
|
|
2
2
|
@component
|
|
3
|
-
Bottom sheets
|
|
3
|
+
Bottom sheets show secondary content anchored to the bottom of the screen.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
- **Modal** (default): a native `<dialog>` above a scrim. It dismisses on Esc, a scrim tap, a
|
|
6
|
+
downward drag, or activating the drag handle.
|
|
7
|
+
- **Standard**: no scrim, the rest of the screen stays usable. Dragging or activating the handle
|
|
8
|
+
switches between expanded and collapsed to `peekHeight`.
|
|
7
9
|
|
|
8
|
-
|
|
10
|
+
Visibility is controlled with `bind:open`; the sheet stays mounted until its exit animation
|
|
11
|
+
finishes. The content scrolls inside the sheet once it reaches its maximum height.
|
|
12
|
+
|
|
13
|
+
@see https://m3.material.io/components/bottom-sheets/specs
|
|
9
14
|
-->
|
|
10
15
|
<script lang="ts">
|
|
11
|
-
import type
|
|
16
|
+
import { animate, type AnimationPlaybackControls } from 'motion';
|
|
17
|
+
import type { Attachment } from 'svelte/attachments';
|
|
12
18
|
import { untrack } from 'svelte';
|
|
13
|
-
import
|
|
19
|
+
import clsx from 'clsx';
|
|
20
|
+
import { enterExit, Presence, springTokens, springTransition } from '../../../animation/index.js';
|
|
21
|
+
import { bottomSheet } from './theme.js';
|
|
22
|
+
import type { BottomSheetCloseReason, BottomSheetProps } from './types.js';
|
|
23
|
+
|
|
24
|
+
let {
|
|
25
|
+
children,
|
|
26
|
+
variant = 'modal',
|
|
27
|
+
open = $bindable(true),
|
|
28
|
+
expanded = $bindable(true),
|
|
29
|
+
peekHeight = 112,
|
|
30
|
+
label,
|
|
31
|
+
hideHandle = false,
|
|
32
|
+
close,
|
|
33
|
+
class: className,
|
|
34
|
+
'aria-labelledby': labelledby
|
|
35
|
+
}: BottomSheetProps = $props();
|
|
14
36
|
|
|
15
|
-
const
|
|
16
|
-
const
|
|
37
|
+
const sheet = new Presence(() => open);
|
|
38
|
+
const modal = $derived(variant === 'modal');
|
|
39
|
+
const cls = $derived(bottomSheet({ variant }));
|
|
17
40
|
|
|
18
|
-
let
|
|
41
|
+
let height = $state(0);
|
|
42
|
+
/** Where the sheet rests: 0 when expanded, lower when a standard sheet is collapsed. */
|
|
43
|
+
const rest = $derived(!modal && !expanded ? Math.max(0, height - peekHeight) : 0);
|
|
19
44
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
let
|
|
23
|
-
let
|
|
45
|
+
// The drag offset lives outside Svelte state: it changes every pointer move and is written
|
|
46
|
+
// straight to the container's transform.
|
|
47
|
+
let el: HTMLElement | undefined;
|
|
48
|
+
let offset = 0;
|
|
49
|
+
let velocity = 0;
|
|
50
|
+
let controls: AnimationPlaybackControls | undefined;
|
|
24
51
|
|
|
25
|
-
const
|
|
52
|
+
const set = (y: number) => {
|
|
53
|
+
offset = y;
|
|
54
|
+
if (el) el.style.transform = `translateY(${y}px)`;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
/** Springs to `to`, carrying the velocity of the drag that let go. */
|
|
58
|
+
const settle = (to: number) => {
|
|
59
|
+
controls?.stop();
|
|
60
|
+
controls = animate(offset, to, {
|
|
61
|
+
...springTransition(springTokens.spatial),
|
|
62
|
+
velocity,
|
|
63
|
+
onUpdate: set
|
|
64
|
+
});
|
|
65
|
+
velocity = 0;
|
|
66
|
+
};
|
|
26
67
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
68
|
+
const follow: Attachment<HTMLElement> = (node) => {
|
|
69
|
+
el = node;
|
|
70
|
+
height = node.offsetHeight;
|
|
71
|
+
set(untrack(() => rest));
|
|
72
|
+
$effect(() => {
|
|
73
|
+
const to = rest;
|
|
74
|
+
untrack(() => !drag && settle(to));
|
|
75
|
+
});
|
|
76
|
+
return () => {
|
|
77
|
+
controls?.stop();
|
|
78
|
+
el = undefined;
|
|
79
|
+
};
|
|
31
80
|
};
|
|
32
81
|
|
|
33
|
-
|
|
82
|
+
// untrack: re-running this attachment would call showModal() on an open dialog. The dialog
|
|
83
|
+
// unmounts after its exit instead of calling close(), so focus is returned to the opener here.
|
|
84
|
+
const showModal: Attachment<HTMLDialogElement> = (node) =>
|
|
85
|
+
untrack(() => {
|
|
86
|
+
const opener = document.activeElement;
|
|
87
|
+
node.showModal();
|
|
88
|
+
return () => {
|
|
89
|
+
if (opener instanceof HTMLElement && opener.isConnected) opener.focus();
|
|
90
|
+
};
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const dismiss = (reason: BottomSheetCloseReason) => {
|
|
34
94
|
open = false;
|
|
35
95
|
close?.(reason);
|
|
36
96
|
};
|
|
37
97
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
if (
|
|
41
|
-
|
|
98
|
+
function activateHandle() {
|
|
99
|
+
if (dragged) return;
|
|
100
|
+
if (modal) dismiss('handle');
|
|
101
|
+
else expanded = !expanded;
|
|
102
|
+
}
|
|
42
103
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if (container && container.clientHeight < height) height = container.clientHeight;
|
|
47
|
-
};
|
|
104
|
+
// Dragging: window listeners, so a fast drag that leaves the 48dp handle area keeps tracking.
|
|
105
|
+
let drag: { startY: number; start: number; lastY: number; lastT: number } | null = null;
|
|
106
|
+
let dragged = false;
|
|
48
107
|
|
|
49
|
-
|
|
50
|
-
if (
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
|
|
108
|
+
function onpointerdown(e: PointerEvent) {
|
|
109
|
+
if (e.button !== 0) return;
|
|
110
|
+
controls?.stop();
|
|
111
|
+
dragged = false;
|
|
112
|
+
velocity = 0;
|
|
113
|
+
drag = { startY: e.clientY, start: offset, lastY: e.clientY, lastT: e.timeStamp };
|
|
114
|
+
window.addEventListener('pointermove', onpointermove);
|
|
115
|
+
window.addEventListener('pointerup', onpointerup);
|
|
116
|
+
window.addEventListener('pointercancel', onpointerup);
|
|
117
|
+
}
|
|
56
118
|
|
|
57
|
-
|
|
58
|
-
if (
|
|
59
|
-
|
|
60
|
-
|
|
119
|
+
function onpointermove(e: PointerEvent) {
|
|
120
|
+
if (!drag) return;
|
|
121
|
+
const dy = e.clientY - drag.startY;
|
|
122
|
+
if (!dragged && Math.abs(dy) < 4) return;
|
|
123
|
+
dragged = true;
|
|
124
|
+
const dt = e.timeStamp - drag.lastT;
|
|
125
|
+
if (dt > 0) velocity = ((e.clientY - drag.lastY) / dt) * 1000;
|
|
126
|
+
drag.lastY = e.clientY;
|
|
127
|
+
drag.lastT = e.timeStamp;
|
|
128
|
+
const next = drag.start + dy;
|
|
129
|
+
const max = modal ? height : height - peekHeight;
|
|
130
|
+
// Past the expanded position the sheet resists, at a quarter of the finger's travel.
|
|
131
|
+
set(Math.min(max, next < 0 ? next / 4 : next));
|
|
132
|
+
}
|
|
61
133
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
134
|
+
function onpointerup() {
|
|
135
|
+
window.removeEventListener('pointermove', onpointermove);
|
|
136
|
+
window.removeEventListener('pointerup', onpointerup);
|
|
137
|
+
window.removeEventListener('pointercancel', onpointerup);
|
|
138
|
+
if (!drag) return;
|
|
139
|
+
drag = null;
|
|
140
|
+
if (!dragged) return;
|
|
141
|
+
// Where a fling would carry the sheet in the next 150ms decides where it goes.
|
|
142
|
+
const projected = offset + velocity * 0.15;
|
|
143
|
+
if (modal) {
|
|
144
|
+
if (projected > height / 2) dismiss('drag');
|
|
145
|
+
else settle(0);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
const collapse = projected > (height - peekHeight) / 2;
|
|
149
|
+
if (collapse === !expanded) settle(rest);
|
|
150
|
+
else expanded = !collapse;
|
|
151
|
+
}
|
|
152
|
+
</script>
|
|
68
153
|
|
|
69
|
-
{#
|
|
70
|
-
<
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
data-state={open ? 'open' : 'closed'}
|
|
74
|
-
{@attach showModal}
|
|
75
|
-
{@attach sheet.attach(enterExit.bottomSheet)}
|
|
76
|
-
oncancel={(e) => {
|
|
77
|
-
e.preventDefault();
|
|
78
|
-
dismiss('esc');
|
|
79
|
-
}}
|
|
80
|
-
onmousedown={(e) => {
|
|
81
|
-
if (e.target != e.currentTarget) return;
|
|
82
|
-
dismiss('click');
|
|
83
|
-
}}
|
|
84
|
-
onwheel={moveWheel}
|
|
85
|
-
>
|
|
86
|
-
<div class="px-4" bind:this={container}>
|
|
154
|
+
{#snippet surface()}
|
|
155
|
+
<div class={cls.container()} bind:offsetHeight={height} {@attach follow}>
|
|
156
|
+
{#if !hideHandle}
|
|
157
|
+
<!-- Pointer drag target; the button inside is the keyboard/screen reader equivalent. -->
|
|
87
158
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
88
|
-
<div
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
startY = e.touches[0].clientY;
|
|
98
|
-
}}
|
|
99
|
-
>
|
|
100
|
-
<div class="bg-md-sys-color-on-surface-variant/40 h-1 w-8 rounded-full"></div>
|
|
159
|
+
<div class={cls.handleArea()} {onpointerdown}>
|
|
160
|
+
<button
|
|
161
|
+
type="button"
|
|
162
|
+
class={cls.handle()}
|
|
163
|
+
aria-label={modal ? 'Close sheet' : expanded ? 'Collapse sheet' : 'Expand sheet'}
|
|
164
|
+
onclick={activateHandle}
|
|
165
|
+
>
|
|
166
|
+
<span class={cls.handleBar()}></span>
|
|
167
|
+
</button>
|
|
101
168
|
</div>
|
|
169
|
+
{/if}
|
|
170
|
+
<div class={cls.body()}>
|
|
102
171
|
{@render children()}
|
|
103
172
|
</div>
|
|
104
|
-
</
|
|
105
|
-
{/
|
|
173
|
+
</div>
|
|
174
|
+
{/snippet}
|
|
106
175
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
176
|
+
{#if sheet.mounted}
|
|
177
|
+
{#if modal}
|
|
178
|
+
<dialog
|
|
179
|
+
class={cls.base({ class: clsx(className) })}
|
|
180
|
+
aria-label={label}
|
|
181
|
+
aria-labelledby={labelledby}
|
|
182
|
+
data-state={open ? 'open' : 'closed'}
|
|
183
|
+
{@attach showModal}
|
|
184
|
+
{@attach sheet.attach(enterExit.bottomSheet)}
|
|
185
|
+
oncancel={(e) => {
|
|
186
|
+
e.preventDefault();
|
|
187
|
+
dismiss('esc');
|
|
188
|
+
}}
|
|
189
|
+
onmousedown={(e) => {
|
|
190
|
+
// Only the ::backdrop (or the gap a drag uncovers) targets the dialog itself.
|
|
191
|
+
if (e.target === e.currentTarget) dismiss('scrim');
|
|
192
|
+
}}
|
|
193
|
+
>
|
|
194
|
+
{@render surface()}
|
|
195
|
+
</dialog>
|
|
196
|
+
{:else}
|
|
197
|
+
<div
|
|
198
|
+
class={cls.base({ class: clsx(className) })}
|
|
199
|
+
role="region"
|
|
200
|
+
aria-label={label}
|
|
201
|
+
aria-labelledby={labelledby}
|
|
202
|
+
{@attach sheet.attach(enterExit.bottomSheet)}
|
|
203
|
+
>
|
|
204
|
+
{@render surface()}
|
|
205
|
+
</div>
|
|
206
|
+
{/if}
|
|
207
|
+
{/if}
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import type { BottomSheetProps } from './types.js';
|
|
2
2
|
/**
|
|
3
|
-
* Bottom sheets
|
|
3
|
+
* Bottom sheets show secondary content anchored to the bottom of the screen.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* - **Modal** (default): a native `<dialog>` above a scrim. It dismisses on Esc, a scrim tap, a
|
|
6
|
+
* downward drag, or activating the drag handle.
|
|
7
|
+
* - **Standard**: no scrim, the rest of the screen stays usable. Dragging or activating the handle
|
|
8
|
+
* switches between expanded and collapsed to `peekHeight`.
|
|
7
9
|
*
|
|
8
|
-
*
|
|
10
|
+
* Visibility is controlled with `bind:open`; the sheet stays mounted until its exit animation
|
|
11
|
+
* finishes. The content scrolls inside the sheet once it reaches its maximum height.
|
|
12
|
+
*
|
|
13
|
+
* @see https://m3.material.io/components/bottom-sheets/specs
|
|
9
14
|
*/
|
|
10
|
-
declare const BottomSheet: import("svelte").Component<BottomSheetProps, {}, "open">;
|
|
15
|
+
declare const BottomSheet: import("svelte").Component<BottomSheetProps, {}, "open" | "expanded">;
|
|
11
16
|
type BottomSheet = ReturnType<typeof BottomSheet>;
|
|
12
17
|
export default BottomSheet;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// THIS FILE IS AUTO-GENERATED BY scripts/generate-components-index.ts - DO NOT EDIT MANUALLY
|
|
2
2
|
// re-export TS/JS modules from this folder
|
|
3
|
+
export * from './theme.js';
|
|
3
4
|
export * from './types.js';
|
|
4
5
|
// default exports for components in this folder
|
|
5
6
|
export { default as BottomSheet } from './BottomSheet.svelte';
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { type VariantProps } from 'tailwind-variants';
|
|
2
|
+
export type BottomSheetVariants = VariantProps<typeof bottomSheet>;
|
|
3
|
+
export declare const bottomSheet: import("tailwind-variants").TVReturnType<{
|
|
4
|
+
variant: {
|
|
5
|
+
modal: {
|
|
6
|
+
base: string[];
|
|
7
|
+
};
|
|
8
|
+
standard: {};
|
|
9
|
+
};
|
|
10
|
+
}, {
|
|
11
|
+
base: string[];
|
|
12
|
+
container: string[];
|
|
13
|
+
handleArea: string;
|
|
14
|
+
handle: string;
|
|
15
|
+
handleBar: string;
|
|
16
|
+
body: string;
|
|
17
|
+
}, undefined, {
|
|
18
|
+
variant: {
|
|
19
|
+
modal: {
|
|
20
|
+
base: string[];
|
|
21
|
+
};
|
|
22
|
+
standard: {};
|
|
23
|
+
};
|
|
24
|
+
}, {
|
|
25
|
+
base: string[];
|
|
26
|
+
container: string[];
|
|
27
|
+
handleArea: string;
|
|
28
|
+
handle: string;
|
|
29
|
+
handleBar: string;
|
|
30
|
+
body: string;
|
|
31
|
+
}, import("tailwind-variants").TVReturnTypeLike<{
|
|
32
|
+
variant: {
|
|
33
|
+
modal: {
|
|
34
|
+
base: string[];
|
|
35
|
+
};
|
|
36
|
+
standard: {};
|
|
37
|
+
};
|
|
38
|
+
}, {
|
|
39
|
+
base: string[];
|
|
40
|
+
container: string[];
|
|
41
|
+
handleArea: string;
|
|
42
|
+
handle: string;
|
|
43
|
+
handleBar: string;
|
|
44
|
+
body: string;
|
|
45
|
+
}>>;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { tv } from 'tailwind-variants';
|
|
2
|
+
/*
|
|
3
|
+
M3 bottom sheet (https://m3.material.io/components/bottom-sheets/specs): `surface-container-low`
|
|
4
|
+
at elevation 1, 28dp top corners. Full window width up to 640dp; past 640dp it keeps 56dp side
|
|
5
|
+
margins. It stops 72dp below the top of the window (56dp past 640dp) and its content scrolls
|
|
6
|
+
inside it. The drag handle is 32×4dp `on-surface-variant` at 40%, with 22dp above and below.
|
|
7
|
+
|
|
8
|
+
`base` is what enters and exits (the dialog, or the standard sheet's wrapper); `container` is
|
|
9
|
+
the surface itself, which follows the drag.
|
|
10
|
+
*/
|
|
11
|
+
export const bottomSheet = tv({
|
|
12
|
+
slots: {
|
|
13
|
+
base: [
|
|
14
|
+
'fixed inset-x-spacing-0 top-auto bottom-spacing-0 z-40 mx-auto mt-auto mb-spacing-0 p-spacing-0',
|
|
15
|
+
'w-full max-w-160 sm:w-[calc(100%-7rem)]',
|
|
16
|
+
'max-h-[calc(100dvh-4.5rem)] sm:max-h-[calc(100dvh-3.5rem)]',
|
|
17
|
+
'overflow-visible bg-transparent outline-none'
|
|
18
|
+
],
|
|
19
|
+
container: [
|
|
20
|
+
'bg-md-sys-color-surface-container-low text-md-sys-color-on-surface shadow-elevation-1',
|
|
21
|
+
'flex max-h-[inherit] flex-col rounded-t-[28px] will-change-transform'
|
|
22
|
+
],
|
|
23
|
+
handleArea: 'flex h-spacing-600 shrink-0 cursor-grab touch-none justify-center active:cursor-grabbing',
|
|
24
|
+
handle: 'md-sys-state-focus-indicator flex h-spacing-600 w-spacing-600 items-center justify-center rounded-full outline-none',
|
|
25
|
+
handleBar: 'bg-md-sys-color-on-surface-variant/40 h-spacing-50 w-spacing-400 rounded-full',
|
|
26
|
+
body: 'min-h-spacing-0 flex-1 overflow-y-auto overscroll-contain pb-[env(safe-area-inset-bottom)]'
|
|
27
|
+
},
|
|
28
|
+
variants: {
|
|
29
|
+
variant: {
|
|
30
|
+
modal: {
|
|
31
|
+
base: [
|
|
32
|
+
'backdrop:bg-md-sys-color-scrim/32 backdrop:transition-[background-color]',
|
|
33
|
+
'backdrop:md-sys-motion-effects starting:backdrop:bg-transparent',
|
|
34
|
+
'data-[state=closed]:pointer-events-none',
|
|
35
|
+
'data-[state=closed]:backdrop:bg-transparent'
|
|
36
|
+
]
|
|
37
|
+
},
|
|
38
|
+
standard: {}
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
defaultVariants: { variant: 'modal' }
|
|
42
|
+
});
|