@noxlovette/material 0.5.1 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (329) hide show
  1. package/bin/material-claude-skill.js +31 -0
  2. package/claude-skill/material-design/SKILL.md +68 -0
  3. package/claude-skill/material-design/references/accessibility-checklist.md +29 -0
  4. package/claude-skill/material-design/references/component-patterns.md +55 -0
  5. package/claude-skill/material-design/references/motion-guide.md +163 -0
  6. package/claude-skill/material-design/references/tokens-and-styles.md +68 -0
  7. package/dist/animation/Shapes.stories.svelte +10 -6
  8. package/dist/animation/TransitionPatterns.stories.svelte +30 -20
  9. package/dist/animation/containerTransform.d.ts +4 -2
  10. package/dist/animation/containerTransform.js +4 -2
  11. package/dist/animation/enterExit.js +5 -2
  12. package/dist/animation/skeleton.d.ts +1 -1
  13. package/dist/animation/skeleton.js +1 -1
  14. package/dist/components/badge/Badge.mdx +70 -0
  15. package/dist/components/badge/Badge.stories.svelte +38 -20
  16. package/dist/components/badge/Badge.svelte +12 -5
  17. package/dist/components/badge/theme.d.ts +30 -7
  18. package/dist/components/badge/theme.js +25 -5
  19. package/dist/components/badge/types.d.ts +18 -4
  20. package/dist/components/buttons/Button.mdx +85 -0
  21. package/dist/components/buttons/Button.stories.svelte +62 -27
  22. package/dist/components/buttons/Button.svelte +29 -25
  23. package/dist/components/buttons/Button.svelte.d.ts +11 -9
  24. package/dist/components/buttons/ButtonIcon.mdx +52 -0
  25. package/dist/components/buttons/ButtonIcon.stories.svelte +72 -48
  26. package/dist/components/buttons/ButtonIcon.svelte +58 -36
  27. package/dist/components/buttons/ButtonIcon.svelte.d.ts +9 -7
  28. package/dist/components/buttons/FAB.mdx +84 -0
  29. package/dist/components/buttons/FAB.stories.svelte +103 -24
  30. package/dist/components/buttons/FAB.stories.svelte.d.ts +2 -17
  31. package/dist/components/buttons/FAB.svelte +353 -29
  32. package/dist/components/buttons/FAB.svelte.d.ts +11 -6
  33. package/dist/components/buttons/FABMenu.svelte +27 -8
  34. package/dist/components/buttons/FABMenu.svelte.d.ts +7 -3
  35. package/dist/components/buttons/FABMenuItem.svelte +20 -16
  36. package/dist/components/buttons/FABMenuItem.svelte.d.ts +3 -3
  37. package/dist/components/buttons/Toggle.stories.svelte +31 -23
  38. package/dist/components/buttons/Toggle.stories.svelte.d.ts +2 -17
  39. package/dist/components/buttons/Toggle.svelte +28 -25
  40. package/dist/components/buttons/Toggle.svelte.d.ts +5 -5
  41. package/dist/components/buttons/button-group/ButtonGroup.mdx +39 -0
  42. package/dist/components/buttons/button-group/ButtonGroup.stories.svelte +62 -43
  43. package/dist/components/buttons/button-group/ButtonGroup.stories.svelte.d.ts +2 -17
  44. package/dist/components/buttons/button-group/ButtonGroup.svelte +102 -8
  45. package/dist/components/buttons/button-group/ButtonGroup.svelte.d.ts +6 -7
  46. package/dist/components/buttons/button-group/theme.d.ts +46 -16
  47. package/dist/components/buttons/button-group/theme.js +14 -9
  48. package/dist/components/buttons/button-group/types.d.ts +13 -7
  49. package/dist/components/buttons/connected/ConnectedButtonGroup.mdx +43 -0
  50. package/dist/components/buttons/connected/ConnectedButtonGroup.stories.svelte +56 -74
  51. package/dist/components/buttons/connected/ConnectedButtonGroup.stories.svelte.d.ts +2 -17
  52. package/dist/components/buttons/connected/ConnectedButtonGroup.svelte +16 -4
  53. package/dist/components/buttons/connected/ConnectedButtonGroup.svelte.d.ts +4 -4
  54. package/dist/components/buttons/connected/ConnectedButtonGroupItem.svelte +35 -8
  55. package/dist/components/buttons/connected/ConnectedButtonGroupItem.svelte.d.ts +2 -3
  56. package/dist/components/buttons/connected/theme.d.ts +34 -19
  57. package/dist/components/buttons/connected/theme.js +33 -10
  58. package/dist/components/buttons/connected/types.d.ts +36 -9
  59. package/dist/components/buttons/shapeMorph.d.ts +26 -0
  60. package/dist/components/buttons/shapeMorph.js +142 -0
  61. package/dist/components/buttons/split-button/SplitButton.mdx +48 -0
  62. package/dist/components/buttons/split-button/SplitButton.stories.svelte +9 -14
  63. package/dist/components/buttons/split-button/SplitButton.svelte +66 -49
  64. package/dist/components/buttons/split-button/SplitButton.svelte.d.ts +6 -11
  65. package/dist/components/buttons/split-button/theme.d.ts +111 -18
  66. package/dist/components/buttons/split-button/theme.js +75 -17
  67. package/dist/components/buttons/split-button/types.d.ts +24 -18
  68. package/dist/components/buttons/theme.d.ts +423 -231
  69. package/dist/components/buttons/theme.js +287 -381
  70. package/dist/components/buttons/types.d.ts +130 -125
  71. package/dist/components/cards/Card.mdx +44 -0
  72. package/dist/components/cards/Card.stories.svelte +11 -11
  73. package/dist/components/cards/theme.js +6 -6
  74. package/dist/components/chips/Chip.mdx +68 -0
  75. package/dist/components/chips/Chip.stories.svelte +4 -4
  76. package/dist/components/chips/theme.d.ts +1 -1
  77. package/dist/components/chips/theme.js +4 -4
  78. package/dist/components/containers/action-rail/ActionRail.stories.svelte +1 -0
  79. package/dist/components/containers/action-rail/theme.d.ts +1 -1
  80. package/dist/components/containers/action-rail/theme.js +2 -2
  81. package/dist/components/containers/app/theme.d.ts +1 -1
  82. package/dist/components/containers/app/theme.js +1 -1
  83. package/dist/components/containers/bottom-sheet/BottomSheet.mdx +64 -0
  84. package/dist/components/containers/bottom-sheet/BottomSheet.stories.svelte +108 -12
  85. package/dist/components/containers/bottom-sheet/BottomSheet.svelte +179 -109
  86. package/dist/components/containers/bottom-sheet/BottomSheet.svelte.d.ts +10 -5
  87. package/dist/components/containers/bottom-sheet/index.d.ts +1 -0
  88. package/dist/components/containers/bottom-sheet/index.js +1 -0
  89. package/dist/components/containers/bottom-sheet/theme.d.ts +45 -0
  90. package/dist/components/containers/bottom-sheet/theme.js +42 -0
  91. package/dist/components/containers/bottom-sheet/types.d.ts +37 -5
  92. package/dist/components/containers/carousel/Carousel.mdx +80 -0
  93. package/dist/components/containers/carousel/Carousel.stories.svelte +131 -0
  94. package/dist/components/containers/carousel/Carousel.stories.svelte.d.ts +4 -0
  95. package/dist/components/containers/carousel/Carousel.svelte +194 -0
  96. package/dist/components/containers/carousel/Carousel.svelte.d.ts +25 -0
  97. package/dist/components/containers/carousel/index.d.ts +3 -0
  98. package/dist/components/containers/{stack → carousel}/index.js +1 -2
  99. package/dist/components/containers/carousel/keylines.d.ts +32 -0
  100. package/dist/components/containers/carousel/keylines.js +88 -0
  101. package/dist/components/containers/carousel/theme.d.ts +162 -0
  102. package/dist/components/containers/carousel/theme.js +67 -0
  103. package/dist/components/containers/carousel/types.d.ts +52 -0
  104. package/dist/components/containers/context-menu/ContextMenu.stories.svelte +1 -0
  105. package/dist/components/containers/context-menu/ContextMenu.svelte +2 -2
  106. package/dist/components/containers/context-menu/ContextMenu.svelte.d.ts +1 -1
  107. package/dist/components/containers/context-menu/theme.d.ts +1 -1
  108. package/dist/components/containers/context-menu/theme.js +11 -11
  109. package/dist/components/containers/dialogue/Dialogue.mdx +65 -0
  110. package/dist/components/containers/dialogue/Dialogue.stories.svelte +4 -4
  111. package/dist/components/containers/dialogue/Dialogue.svelte +2 -2
  112. package/dist/components/containers/dialogue/theme.d.ts +1 -1
  113. package/dist/components/containers/dialogue/theme.js +4 -4
  114. package/dist/components/containers/dialogue/types.d.ts +1 -1
  115. package/dist/components/containers/divider/Divider.stories.svelte +2 -1
  116. package/dist/components/containers/divider/Divider.svelte +2 -2
  117. package/dist/components/containers/divider/theme.d.ts +7 -7
  118. package/dist/components/containers/divider/theme.js +3 -3
  119. package/dist/components/containers/index.d.ts +1 -1
  120. package/dist/components/containers/index.js +1 -1
  121. package/dist/components/containers/link-preview/theme.d.ts +1 -1
  122. package/dist/components/containers/link-preview/theme.js +3 -3
  123. package/dist/components/containers/list/List.svelte +18 -0
  124. package/dist/components/containers/list/List.svelte.d.ts +4 -0
  125. package/dist/components/containers/list/ListItem.mdx +100 -0
  126. package/dist/components/containers/list/ListItem.stories.svelte +177 -42
  127. package/dist/components/containers/list/ListItem.stories.svelte.d.ts +2 -17
  128. package/dist/components/containers/list/ListItem.svelte +92 -37
  129. package/dist/components/containers/list/ListItem.svelte.d.ts +1 -1
  130. package/dist/components/containers/list/context.d.ts +6 -0
  131. package/dist/components/containers/list/context.js +4 -0
  132. package/dist/components/containers/list/index.d.ts +1 -0
  133. package/dist/components/containers/list/index.js +1 -0
  134. package/dist/components/containers/list/theme.d.ts +487 -12
  135. package/dist/components/containers/list/theme.js +141 -14
  136. package/dist/components/containers/list/types.d.ts +39 -5
  137. package/dist/components/containers/menu/Menu.mdx +52 -0
  138. package/dist/components/containers/menu/Menu.stories.svelte +14 -14
  139. package/dist/components/containers/menu/Menu.svelte +2 -2
  140. package/dist/components/containers/menu/MenuGroup.svelte +1 -1
  141. package/dist/components/containers/menu/MenuGroup.svelte.d.ts +1 -1
  142. package/dist/components/containers/menu/MenuSub.svelte +1 -1
  143. package/dist/components/containers/menu/menu-item/MenuItem.svelte +1 -1
  144. package/dist/components/containers/menu/theme.d.ts +1 -1
  145. package/dist/components/containers/menu/theme.js +9 -9
  146. package/dist/components/containers/pane/DraggablePane.stories.svelte +4 -3
  147. package/dist/components/containers/pane/DraggablePane.svelte +2 -2
  148. package/dist/components/containers/pane/Pane.stories.svelte +11 -10
  149. package/dist/components/containers/pane/Pane.svelte +24 -2
  150. package/dist/components/containers/pane/PaneGrid.stories.svelte +19 -18
  151. package/dist/components/containers/pane/PaneGrid.svelte +3 -2
  152. package/dist/components/containers/pane/PaneGrid.svelte.d.ts +2 -1
  153. package/dist/components/containers/pane/PaneHandle.svelte +48 -2
  154. package/dist/components/containers/pane/PaneHandle.svelte.d.ts +4 -0
  155. package/dist/components/containers/pane/resizeStore.svelte.d.ts +10 -1
  156. package/dist/components/containers/pane/resizeStore.svelte.js +13 -2
  157. package/dist/components/containers/pane/theme.d.ts +1 -1
  158. package/dist/components/containers/pane/theme.js +131 -47
  159. package/dist/components/containers/pane/types.d.ts +3 -2
  160. package/dist/components/containers/popover/Popover.mdx +45 -0
  161. package/dist/components/containers/popover/Popover.stories.svelte +1 -1
  162. package/dist/components/containers/popover/Popover.svelte +1 -1
  163. package/dist/components/containers/popover/theme.d.ts +1 -1
  164. package/dist/components/containers/popover/theme.js +4 -4
  165. package/dist/components/containers/scroll-area/theme.js +3 -3
  166. package/dist/components/containers/side-sheet/SideSheet.mdx +71 -0
  167. package/dist/components/containers/side-sheet/SideSheet.stories.svelte +113 -17
  168. package/dist/components/containers/side-sheet/SideSheet.svelte +113 -66
  169. package/dist/components/containers/side-sheet/SideSheet.svelte.d.ts +8 -7
  170. package/dist/components/containers/side-sheet/index.d.ts +1 -0
  171. package/dist/components/containers/side-sheet/index.js +1 -0
  172. package/dist/components/containers/side-sheet/theme.d.ts +108 -0
  173. package/dist/components/containers/side-sheet/theme.js +72 -0
  174. package/dist/components/containers/side-sheet/types.d.ts +35 -7
  175. package/dist/components/date/DateField.stories.svelte +4 -3
  176. package/dist/components/date/DateField.svelte +11 -2
  177. package/dist/components/date/DateRangeField.stories.svelte +4 -3
  178. package/dist/components/date/DateRangeField.svelte +12 -3
  179. package/dist/components/date/theme.d.ts +8 -8
  180. package/dist/components/date/theme.js +32 -32
  181. package/dist/components/forms/checkbox/Checkbox.mdx +35 -0
  182. package/dist/components/forms/checkbox/Checkbox.stories.svelte +2 -2
  183. package/dist/components/forms/checkbox/Checkbox.svelte +1 -1
  184. package/dist/components/forms/checkbox/theme.d.ts +1 -1
  185. package/dist/components/forms/checkbox/theme.js +4 -4
  186. package/dist/components/forms/command/Command.stories.svelte +1 -0
  187. package/dist/components/forms/command/theme.d.ts +1 -1
  188. package/dist/components/forms/command/theme.js +10 -10
  189. package/dist/components/forms/pin/theme.d.ts +1 -1
  190. package/dist/components/forms/pin/theme.js +5 -5
  191. package/dist/components/forms/radio-group/RadioGroup.svelte +1 -1
  192. package/dist/components/forms/radio-group/theme.d.ts +1 -1
  193. package/dist/components/forms/radio-group/theme.js +6 -6
  194. package/dist/components/forms/search/Search.mdx +38 -0
  195. package/dist/components/forms/search/Search.stories.svelte +19 -9
  196. package/dist/components/forms/search/Search.svelte +40 -17
  197. package/dist/components/forms/search/Search.svelte.d.ts +2 -2
  198. package/dist/components/forms/search/theme.d.ts +46 -13
  199. package/dist/components/forms/search/theme.js +14 -9
  200. package/dist/components/forms/search/types.d.ts +18 -12
  201. package/dist/components/forms/select/Select.mdx +53 -0
  202. package/dist/components/forms/select/Select.stories.svelte +4 -4
  203. package/dist/components/forms/select/Select.svelte +12 -4
  204. package/dist/components/forms/select/SelectItem.svelte +1 -1
  205. package/dist/components/forms/select/theme.d.ts +1 -1
  206. package/dist/components/forms/select/theme.js +14 -14
  207. package/dist/components/forms/slider/Slider.mdx +85 -0
  208. package/dist/components/forms/slider/Slider.stories.svelte +7 -7
  209. package/dist/components/forms/slider/Slider.svelte +46 -28
  210. package/dist/components/forms/slider/theme.d.ts +15 -1
  211. package/dist/components/forms/slider/theme.js +29 -18
  212. package/dist/components/forms/slider/types.d.ts +3 -2
  213. package/dist/components/forms/switch/Switch.mdx +38 -0
  214. package/dist/components/forms/switch/Switch.stories.svelte +3 -3
  215. package/dist/components/forms/switch/theme.d.ts +1 -1
  216. package/dist/components/forms/switch/theme.js +7 -7
  217. package/dist/components/forms/textfield/Textfield.mdx +53 -0
  218. package/dist/components/forms/textfield/Textfield.stories.svelte +6 -6
  219. package/dist/components/forms/textfield/Textfield.svelte +1 -0
  220. package/dist/components/forms/textfield/theme.d.ts +1 -1
  221. package/dist/components/forms/textfield/theme.js +20 -20
  222. package/dist/components/forms/toggle-group/theme.d.ts +1 -1
  223. package/dist/components/forms/toggle-group/theme.js +3 -3
  224. package/dist/components/forms/tooltip/Tooltip.stories.svelte +1 -0
  225. package/dist/components/forms/tooltip/theme.d.ts +1 -1
  226. package/dist/components/forms/tooltip/theme.js +4 -4
  227. package/dist/components/misc/Avatar.stories.svelte +5 -4
  228. package/dist/components/misc/ThemeSettings.svelte +9 -9
  229. package/dist/components/misc/ThemeSwitcher.svelte +3 -3
  230. package/dist/components/misc/theme.js +5 -5
  231. package/dist/components/nav/appbar/AppBar.mdx +71 -0
  232. package/dist/components/nav/appbar/AppBar.stories.svelte +93 -3
  233. package/dist/components/nav/appbar/AppBar.stories.svelte.d.ts +2 -17
  234. package/dist/components/nav/appbar/AppBar.svelte +90 -37
  235. package/dist/components/nav/appbar/AppBar.svelte.d.ts +9 -2
  236. package/dist/components/nav/appbar/theme.d.ts +86 -19
  237. package/dist/components/nav/appbar/theme.js +160 -24
  238. package/dist/components/nav/appbar/types.d.ts +46 -9
  239. package/dist/components/nav/breadcrumb/Breadcrumb.stories.svelte +1 -0
  240. package/dist/components/nav/breadcrumb/theme.d.ts +1 -1
  241. package/dist/components/nav/breadcrumb/theme.js +6 -6
  242. package/dist/components/nav/navbar/Navbar.mdx +38 -0
  243. package/dist/components/nav/navbar/Navbar.svelte +1 -1
  244. package/dist/components/nav/navbar/NavbarItem.svelte +12 -9
  245. package/dist/components/nav/navbar/theme.d.ts +3 -3
  246. package/dist/components/nav/navbar/theme.js +7 -7
  247. package/dist/components/nav/rail/Rail.mdx +73 -0
  248. package/dist/components/nav/rail/Rail.stories.svelte +3 -7
  249. package/dist/components/nav/rail/Rail.svelte +5 -2
  250. package/dist/components/nav/rail/RailItem.svelte +12 -9
  251. package/dist/components/nav/rail/theme.d.ts +1 -1
  252. package/dist/components/nav/rail/theme.js +14 -14
  253. package/dist/components/nav/rail/types.d.ts +8 -1
  254. package/dist/components/nav/tabs/Tabs.mdx +62 -0
  255. package/dist/components/nav/tabs/Tabs.stories.svelte +1 -1
  256. package/dist/components/nav/tabs/theme.d.ts +1 -1
  257. package/dist/components/nav/tabs/theme.js +5 -5
  258. package/dist/components/pill/Pill.mdx +32 -0
  259. package/dist/components/pill/Pill.stories.svelte +1 -1
  260. package/dist/components/pill/theme.d.ts +2 -2
  261. package/dist/components/pill/theme.js +2 -2
  262. package/dist/components/progress/LinearProgress.svelte +2 -2
  263. package/dist/components/progress/Progress.mdx +50 -0
  264. package/dist/components/progress/Progress.stories.svelte +6 -6
  265. package/dist/components/snackbar/Snackbar.mdx +52 -0
  266. package/dist/components/snackbar/Snackbar.stories.svelte +5 -5
  267. package/dist/components/snackbar/Snackbar.svelte +1 -1
  268. package/dist/components/snackbar/theme.d.ts +4 -4
  269. package/dist/components/snackbar/theme.js +5 -5
  270. package/dist/components/table/Table.stories.svelte +1 -0
  271. package/dist/components/table/TableHeader.svelte +1 -1
  272. package/dist/components/table/theme.d.ts +1 -1
  273. package/dist/components/table/theme.js +4 -4
  274. package/dist/components/time/TimeField.stories.svelte +3 -2
  275. package/dist/components/time/TimeField.svelte +2 -2
  276. package/dist/components/time/TimepickerInput.svelte +1 -1
  277. package/dist/components/time/theme.d.ts +1 -1
  278. package/dist/components/time/theme.js +6 -6
  279. package/dist/components/toolbar/Toolbar.stories.svelte +1 -0
  280. package/dist/components/toolbar/Toolbar.svelte +1 -1
  281. package/dist/components/toolbar/Toolbar.svelte.d.ts +1 -1
  282. package/dist/components/toolbar/theme.d.ts +1 -1
  283. package/dist/components/toolbar/theme.js +15 -15
  284. package/dist/components/typography/Typography.mdx +67 -0
  285. package/dist/components/typography/body/Body.stories.svelte +2 -1
  286. package/dist/components/typography/body/theme.d.ts +16 -13
  287. package/dist/components/typography/body/theme.js +20 -5
  288. package/dist/components/typography/body/types.d.ts +2 -1
  289. package/dist/components/typography/display/Display.stories.svelte +2 -1
  290. package/dist/components/typography/display/theme.d.ts +16 -13
  291. package/dist/components/typography/display/theme.js +20 -5
  292. package/dist/components/typography/display/types.d.ts +2 -1
  293. package/dist/components/typography/headline/Headline.stories.svelte +2 -1
  294. package/dist/components/typography/headline/theme.d.ts +16 -13
  295. package/dist/components/typography/headline/theme.js +20 -5
  296. package/dist/components/typography/headline/types.d.ts +2 -1
  297. package/dist/components/typography/kbd/Kbd.stories.svelte +2 -1
  298. package/dist/components/typography/kbd/theme.d.ts +5 -5
  299. package/dist/components/typography/kbd/theme.js +3 -3
  300. package/dist/components/typography/label/Label.stories.svelte +2 -1
  301. package/dist/components/typography/label/theme.d.ts +15 -12
  302. package/dist/components/typography/label/theme.js +20 -5
  303. package/dist/components/typography/label/types.d.ts +2 -1
  304. package/dist/components/typography/title/Title.stories.svelte +2 -1
  305. package/dist/components/typography/title/theme.d.ts +16 -13
  306. package/dist/components/typography/title/theme.js +20 -5
  307. package/dist/components/typography/title/types.d.ts +2 -1
  308. package/dist/index.css +2 -0
  309. package/dist/styles/component.css +78 -175
  310. package/dist/styles/elevation.css +9 -0
  311. package/dist/styles/layers.css +33 -0
  312. package/dist/styles/spacing.css +29 -0
  313. package/dist/styles/typescale.css +635 -20
  314. package/dist/utils/Layer.svelte +1 -1
  315. package/dist/utils/icon/Icon.svelte +8 -6
  316. package/dist/utils/icon/theme.d.ts +1 -1
  317. package/dist/utils/icon/theme.js +1 -1
  318. package/dist/utils/tv.d.ts +6 -0
  319. package/dist/utils/tv.js +12 -0
  320. package/package.json +19 -15
  321. package/dist/components/containers/stack/HStack.svelte +0 -23
  322. package/dist/components/containers/stack/HStack.svelte.d.ts +0 -5
  323. package/dist/components/containers/stack/VStack.svelte +0 -23
  324. package/dist/components/containers/stack/VStack.svelte.d.ts +0 -5
  325. package/dist/components/containers/stack/index.d.ts +0 -4
  326. package/dist/components/containers/stack/theme.d.ts +0 -66
  327. package/dist/components/containers/stack/theme.js +0 -26
  328. package/dist/components/containers/stack/types.d.ts +0 -12
  329. /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`: it dismisses itself on Esc, backdrop click, or
3
- dragging the handle below a minimum height, and stays mounted until its exit animation
4
- finishes. The optional `close` callback reports why ('esc' | 'click' | 'low').
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 MenuItem from '../menu/menu-item/MenuItem.svelte';
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 playgroundOpen = $state(false);
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="Playground" asChild>
23
- <div class="p-6">
24
- <Button onclick={() => (playgroundOpen = true)}>Open bottom sheet</Button>
25
- <BottomSheet bind:open={playgroundOpen}>
26
- <MenuItem iconProps={{ name: 'share' }}>Share</MenuItem>
27
- <MenuItem iconProps={{ name: 'link' }}>Copy link</MenuItem>
28
- <MenuItem iconProps={{ name: 'download' }}>Download</MenuItem>
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 are surfaces containing supplementary content that are anchored to the bottom of the screen.
3
+ Bottom sheets show secondary content anchored to the bottom of the screen.
4
4
 
5
- They provide access to supplementary content and actions, such as navigation or a menu,
6
- while keeping the main screen content visible.
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
- @see https://m3.material.io/components/bottom-sheets/overview
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 { BottomSheetProps } from './types.js';
16
+ import { animate, type AnimationPlaybackControls } from 'motion';
17
+ import type { Attachment } from 'svelte/attachments';
12
18
  import { untrack } from 'svelte';
13
- import { enterExit, Presence } from '../../../animation/index.js';
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 DEFAULT_HEIGHT = 480;
16
- const DISMISS_HEIGHT = 48;
37
+ const sheet = new Presence(() => open);
38
+ const modal = $derived(variant === 'modal');
39
+ const cls = $derived(bottomSheet({ variant }));
17
40
 
18
- let { children, open = $bindable(true), close }: BottomSheetProps = $props();
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
- let height = $state(DEFAULT_HEIGHT);
21
- let container: HTMLDivElement | undefined = $state();
22
- let isDragging = $state(false);
23
- let startY = $state(0);
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 sheet = new Presence(() => open);
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
- // untrack: re-running this attachment on every drag would call showModal() on an open dialog.
28
- const showModal = (node: HTMLDialogElement) => {
29
- untrack(() => node.clientHeight < height && (height = node.clientHeight));
30
- node.showModal();
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
- const dismiss = (reason: 'esc' | 'click' | 'low') => {
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
- // A sheet dragged shut keeps its collapsed height through the exit; restore it on reopen.
39
- $effect.pre(() => {
40
- if (open) untrack(() => height < DISMISS_HEIGHT && (height = DEFAULT_HEIGHT));
41
- });
98
+ function activateHandle() {
99
+ if (dragged) return;
100
+ if (modal) dismiss('handle');
101
+ else expanded = !expanded;
102
+ }
42
103
 
43
- const moveWheel = (e: WheelEvent) => {
44
- e.preventDefault();
45
- height += e.deltaY;
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
- const moveMouse = (e: { clientY: number }) => {
50
- if (isDragging) {
51
- const distance = e.clientY - startY;
52
- height -= distance;
53
- startY = e.clientY;
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
- $effect(() => {
58
- if (height < DISMISS_HEIGHT && untrack(() => open)) dismiss('low');
59
- });
60
- </script>
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
- <svelte:window
63
- onmousemove={moveMouse}
64
- onmouseup={() => (isDragging = false)}
65
- ontouchmove={(e) => moveMouse(e.touches[0])}
66
- ontouchend={() => (isDragging = false)}
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
- {#if sheet.mounted}
70
- <dialog
71
- class="bg-md-sys-color-surface-container-low text-md-sys-color-on-surface mx-auto mt-auto w-full max-w-2xl overflow-hidden rounded-t-md"
72
- style:max-height="{height}px"
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
- class="flex h-12 w-full cursor-grab items-center justify-center"
90
- onmousedown={(e) => {
91
- e.preventDefault();
92
- isDragging = true;
93
- startY = e.clientY;
94
- }}
95
- ontouchstart={(e) => {
96
- isDragging = true;
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
- </dialog>
105
- {/if}
173
+ </div>
174
+ {/snippet}
106
175
 
107
- <style>
108
- dialog::backdrop {
109
- background-color: rgba(0, 0, 0, 0.5);
110
- animation: backdrop var(--md-sys-motion-duration-effects-spring)
111
- var(--md-sys-motion-timing-function-effects-spring);
112
- }
113
- dialog[data-state='closed'] {
114
- pointer-events: none;
115
- }
116
- dialog[data-state='closed']::backdrop {
117
- background-color: transparent;
118
- animation: backdropReverse var(--md-sys-motion-duration-fast-effects-spring)
119
- var(--md-sys-motion-timing-function-fast-effects-spring);
120
- }
121
- @keyframes backdrop {
122
- from {
123
- background-color: transparent;
124
- }
125
- to {
126
- background-color: rgba(0, 0, 0, 0.5);
127
- }
128
- }
129
- @keyframes backdropReverse {
130
- from {
131
- background-color: rgba(0, 0, 0, 0.5);
132
- }
133
- to {
134
- background-color: transparent;
135
- }
136
- }
137
- </style>
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 are surfaces containing supplementary content that are anchored to the bottom of the screen.
3
+ * Bottom sheets show secondary content anchored to the bottom of the screen.
4
4
  *
5
- * They provide access to supplementary content and actions, such as navigation or a menu,
6
- * while keeping the main screen content visible.
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
- * @see https://m3.material.io/components/bottom-sheets/overview
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,2 +1,3 @@
1
+ export * from './theme.js';
1
2
  export * from './types.js';
2
3
  export { default as BottomSheet } from './BottomSheet.svelte';
@@ -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 '../../../utils/tv.js';
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 '../../../utils/tv.js';
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-layer-sheet 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
+ });