@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.
Files changed (316) 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 +60 -0
  8. package/dist/animation/Shapes.stories.svelte.d.ts +3 -0
  9. package/dist/animation/TransitionPatterns.stories.svelte +32 -20
  10. package/dist/animation/containerTransform.d.ts +11 -0
  11. package/dist/animation/containerTransform.js +11 -0
  12. package/dist/animation/enterExit.d.ts +9 -0
  13. package/dist/animation/enterExit.js +6 -3
  14. package/dist/animation/index.d.ts +1 -0
  15. package/dist/animation/index.js +1 -0
  16. package/dist/animation/shapeMorph.svelte.d.ts +52 -0
  17. package/dist/animation/shapeMorph.svelte.js +112 -0
  18. package/dist/animation/shapesAnimatableSmall.d.ts +28 -22
  19. package/dist/animation/shapesAnimatableSmall.js +32 -23
  20. package/dist/animation/sharedAxisTransition.d.ts +22 -0
  21. package/dist/animation/sharedAxisTransition.js +25 -1
  22. package/dist/animation/skeleton.d.ts +6 -1
  23. package/dist/animation/skeleton.js +6 -1
  24. package/dist/components/badge/Badge.mdx +70 -0
  25. package/dist/components/badge/Badge.stories.svelte +38 -20
  26. package/dist/components/badge/Badge.svelte +12 -5
  27. package/dist/components/badge/theme.d.ts +30 -7
  28. package/dist/components/badge/theme.js +24 -4
  29. package/dist/components/badge/types.d.ts +18 -4
  30. package/dist/components/buttons/Button.mdx +85 -0
  31. package/dist/components/buttons/Button.stories.svelte +62 -27
  32. package/dist/components/buttons/Button.svelte +29 -25
  33. package/dist/components/buttons/Button.svelte.d.ts +11 -9
  34. package/dist/components/buttons/ButtonIcon.mdx +52 -0
  35. package/dist/components/buttons/ButtonIcon.stories.svelte +72 -48
  36. package/dist/components/buttons/ButtonIcon.svelte +58 -36
  37. package/dist/components/buttons/ButtonIcon.svelte.d.ts +9 -7
  38. package/dist/components/buttons/FAB.mdx +84 -0
  39. package/dist/components/buttons/FAB.stories.svelte +103 -24
  40. package/dist/components/buttons/FAB.stories.svelte.d.ts +2 -17
  41. package/dist/components/buttons/FAB.svelte +353 -29
  42. package/dist/components/buttons/FAB.svelte.d.ts +11 -6
  43. package/dist/components/buttons/FABMenu.svelte +27 -8
  44. package/dist/components/buttons/FABMenu.svelte.d.ts +7 -3
  45. package/dist/components/buttons/FABMenuItem.svelte +20 -16
  46. package/dist/components/buttons/FABMenuItem.svelte.d.ts +3 -3
  47. package/dist/components/buttons/Toggle.stories.svelte +31 -23
  48. package/dist/components/buttons/Toggle.stories.svelte.d.ts +2 -17
  49. package/dist/components/buttons/Toggle.svelte +28 -25
  50. package/dist/components/buttons/Toggle.svelte.d.ts +5 -5
  51. package/dist/components/buttons/button-group/ButtonGroup.mdx +39 -0
  52. package/dist/components/buttons/button-group/ButtonGroup.stories.svelte +62 -43
  53. package/dist/components/buttons/button-group/ButtonGroup.stories.svelte.d.ts +2 -17
  54. package/dist/components/buttons/button-group/ButtonGroup.svelte +102 -8
  55. package/dist/components/buttons/button-group/ButtonGroup.svelte.d.ts +6 -7
  56. package/dist/components/buttons/button-group/theme.d.ts +45 -15
  57. package/dist/components/buttons/button-group/theme.js +13 -8
  58. package/dist/components/buttons/button-group/types.d.ts +13 -7
  59. package/dist/components/buttons/connected/ConnectedButtonGroup.mdx +43 -0
  60. package/dist/components/buttons/connected/ConnectedButtonGroup.stories.svelte +56 -74
  61. package/dist/components/buttons/connected/ConnectedButtonGroup.stories.svelte.d.ts +2 -17
  62. package/dist/components/buttons/connected/ConnectedButtonGroup.svelte +16 -4
  63. package/dist/components/buttons/connected/ConnectedButtonGroup.svelte.d.ts +4 -4
  64. package/dist/components/buttons/connected/ConnectedButtonGroupItem.svelte +35 -8
  65. package/dist/components/buttons/connected/ConnectedButtonGroupItem.svelte.d.ts +2 -3
  66. package/dist/components/buttons/connected/theme.d.ts +33 -18
  67. package/dist/components/buttons/connected/theme.js +32 -9
  68. package/dist/components/buttons/connected/types.d.ts +36 -9
  69. package/dist/components/buttons/shapeMorph.d.ts +26 -0
  70. package/dist/components/buttons/shapeMorph.js +142 -0
  71. package/dist/components/buttons/split-button/SplitButton.mdx +48 -0
  72. package/dist/components/buttons/split-button/SplitButton.stories.svelte +9 -14
  73. package/dist/components/buttons/split-button/SplitButton.svelte +65 -48
  74. package/dist/components/buttons/split-button/SplitButton.svelte.d.ts +6 -11
  75. package/dist/components/buttons/split-button/theme.d.ts +110 -17
  76. package/dist/components/buttons/split-button/theme.js +74 -16
  77. package/dist/components/buttons/split-button/types.d.ts +24 -18
  78. package/dist/components/buttons/theme.d.ts +422 -230
  79. package/dist/components/buttons/theme.js +286 -380
  80. package/dist/components/buttons/types.d.ts +130 -125
  81. package/dist/components/cards/Card.mdx +44 -0
  82. package/dist/components/cards/Card.stories.svelte +11 -11
  83. package/dist/components/cards/theme.js +5 -5
  84. package/dist/components/chips/Chip.mdx +68 -0
  85. package/dist/components/chips/Chip.stories.svelte +4 -4
  86. package/dist/components/chips/theme.js +3 -3
  87. package/dist/components/containers/action-rail/ActionRail.stories.svelte +1 -0
  88. package/dist/components/containers/action-rail/theme.js +1 -1
  89. package/dist/components/containers/bottom-sheet/BottomSheet.mdx +64 -0
  90. package/dist/components/containers/bottom-sheet/BottomSheet.stories.svelte +108 -12
  91. package/dist/components/containers/bottom-sheet/BottomSheet.svelte +179 -109
  92. package/dist/components/containers/bottom-sheet/BottomSheet.svelte.d.ts +10 -5
  93. package/dist/components/containers/bottom-sheet/index.d.ts +1 -0
  94. package/dist/components/containers/bottom-sheet/index.js +1 -0
  95. package/dist/components/containers/bottom-sheet/theme.d.ts +45 -0
  96. package/dist/components/containers/bottom-sheet/theme.js +42 -0
  97. package/dist/components/containers/bottom-sheet/types.d.ts +37 -5
  98. package/dist/components/containers/carousel/Carousel.mdx +80 -0
  99. package/dist/components/containers/carousel/Carousel.stories.svelte +131 -0
  100. package/dist/components/containers/carousel/Carousel.stories.svelte.d.ts +4 -0
  101. package/dist/components/containers/carousel/Carousel.svelte +194 -0
  102. package/dist/components/containers/carousel/Carousel.svelte.d.ts +25 -0
  103. package/dist/components/containers/carousel/index.d.ts +3 -0
  104. package/dist/components/containers/{stack → carousel}/index.js +1 -2
  105. package/dist/components/containers/carousel/keylines.d.ts +32 -0
  106. package/dist/components/containers/carousel/keylines.js +88 -0
  107. package/dist/components/containers/carousel/theme.d.ts +162 -0
  108. package/dist/components/containers/carousel/theme.js +67 -0
  109. package/dist/components/containers/carousel/types.d.ts +52 -0
  110. package/dist/components/containers/context-menu/ContextMenu.stories.svelte +1 -0
  111. package/dist/components/containers/context-menu/ContextMenu.svelte +2 -2
  112. package/dist/components/containers/context-menu/ContextMenu.svelte.d.ts +1 -1
  113. package/dist/components/containers/context-menu/theme.js +10 -10
  114. package/dist/components/containers/dialogue/Dialogue.mdx +65 -0
  115. package/dist/components/containers/dialogue/Dialogue.stories.svelte +4 -4
  116. package/dist/components/containers/dialogue/Dialogue.svelte +1 -1
  117. package/dist/components/containers/dialogue/theme.js +3 -3
  118. package/dist/components/containers/divider/Divider.stories.svelte +2 -1
  119. package/dist/components/containers/divider/Divider.svelte +2 -2
  120. package/dist/components/containers/divider/theme.d.ts +6 -6
  121. package/dist/components/containers/divider/theme.js +2 -2
  122. package/dist/components/containers/index.d.ts +1 -1
  123. package/dist/components/containers/index.js +1 -1
  124. package/dist/components/containers/link-preview/theme.js +2 -2
  125. package/dist/components/containers/list/List.svelte +18 -0
  126. package/dist/components/containers/list/List.svelte.d.ts +4 -0
  127. package/dist/components/containers/list/ListItem.mdx +100 -0
  128. package/dist/components/containers/list/ListItem.stories.svelte +177 -42
  129. package/dist/components/containers/list/ListItem.stories.svelte.d.ts +2 -17
  130. package/dist/components/containers/list/ListItem.svelte +92 -37
  131. package/dist/components/containers/list/ListItem.svelte.d.ts +1 -1
  132. package/dist/components/containers/list/context.d.ts +6 -0
  133. package/dist/components/containers/list/context.js +4 -0
  134. package/dist/components/containers/list/index.d.ts +1 -0
  135. package/dist/components/containers/list/index.js +1 -0
  136. package/dist/components/containers/list/theme.d.ts +487 -12
  137. package/dist/components/containers/list/theme.js +140 -13
  138. package/dist/components/containers/list/types.d.ts +39 -5
  139. package/dist/components/containers/menu/Menu.mdx +52 -0
  140. package/dist/components/containers/menu/Menu.stories.svelte +14 -14
  141. package/dist/components/containers/menu/Menu.svelte +1 -1
  142. package/dist/components/containers/menu/MenuGroup.svelte +1 -1
  143. package/dist/components/containers/menu/MenuGroup.svelte.d.ts +1 -1
  144. package/dist/components/containers/menu/menu-item/MenuItem.svelte +1 -1
  145. package/dist/components/containers/menu/theme.js +8 -8
  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.js +129 -45
  158. package/dist/components/containers/pane/types.d.ts +3 -2
  159. package/dist/components/containers/popover/Popover.mdx +45 -0
  160. package/dist/components/containers/popover/Popover.stories.svelte +1 -1
  161. package/dist/components/containers/popover/Popover.svelte +1 -1
  162. package/dist/components/containers/popover/theme.js +3 -3
  163. package/dist/components/containers/scroll-area/theme.js +2 -2
  164. package/dist/components/containers/side-sheet/SideSheet.mdx +71 -0
  165. package/dist/components/containers/side-sheet/SideSheet.stories.svelte +113 -17
  166. package/dist/components/containers/side-sheet/SideSheet.svelte +113 -66
  167. package/dist/components/containers/side-sheet/SideSheet.svelte.d.ts +8 -7
  168. package/dist/components/containers/side-sheet/index.d.ts +1 -0
  169. package/dist/components/containers/side-sheet/index.js +1 -0
  170. package/dist/components/containers/side-sheet/theme.d.ts +108 -0
  171. package/dist/components/containers/side-sheet/theme.js +72 -0
  172. package/dist/components/containers/side-sheet/types.d.ts +35 -7
  173. package/dist/components/date/DateField.stories.svelte +4 -3
  174. package/dist/components/date/DateField.svelte +49 -26
  175. package/dist/components/date/DateField.svelte.d.ts +2 -0
  176. package/dist/components/date/DateRangeField.stories.svelte +4 -3
  177. package/dist/components/date/DateRangeField.svelte +54 -31
  178. package/dist/components/date/DateRangeField.svelte.d.ts +2 -0
  179. package/dist/components/date/calendarMotion.d.ts +9 -0
  180. package/dist/components/date/calendarMotion.js +23 -0
  181. package/dist/components/date/theme.d.ts +7 -7
  182. package/dist/components/date/theme.js +34 -30
  183. package/dist/components/forms/checkbox/Checkbox.mdx +35 -0
  184. package/dist/components/forms/checkbox/Checkbox.stories.svelte +2 -2
  185. package/dist/components/forms/checkbox/Checkbox.svelte +1 -1
  186. package/dist/components/forms/checkbox/theme.js +3 -3
  187. package/dist/components/forms/command/Command.stories.svelte +1 -0
  188. package/dist/components/forms/command/theme.js +9 -9
  189. package/dist/components/forms/pin/theme.js +4 -4
  190. package/dist/components/forms/radio-group/RadioGroup.svelte +1 -1
  191. package/dist/components/forms/radio-group/theme.js +5 -5
  192. package/dist/components/forms/search/Search.mdx +38 -0
  193. package/dist/components/forms/search/Search.stories.svelte +19 -9
  194. package/dist/components/forms/search/Search.svelte +40 -17
  195. package/dist/components/forms/search/Search.svelte.d.ts +2 -2
  196. package/dist/components/forms/search/theme.d.ts +45 -12
  197. package/dist/components/forms/search/theme.js +13 -8
  198. package/dist/components/forms/search/types.d.ts +18 -12
  199. package/dist/components/forms/select/Select.mdx +53 -0
  200. package/dist/components/forms/select/Select.stories.svelte +4 -4
  201. package/dist/components/forms/select/Select.svelte +10 -2
  202. package/dist/components/forms/select/SelectItem.svelte +1 -1
  203. package/dist/components/forms/select/theme.js +12 -12
  204. package/dist/components/forms/slider/Slider.mdx +85 -0
  205. package/dist/components/forms/slider/Slider.stories.svelte +7 -7
  206. package/dist/components/forms/slider/Slider.svelte +46 -28
  207. package/dist/components/forms/slider/theme.d.ts +14 -0
  208. package/dist/components/forms/slider/theme.js +28 -17
  209. package/dist/components/forms/slider/types.d.ts +3 -2
  210. package/dist/components/forms/switch/Switch.mdx +38 -0
  211. package/dist/components/forms/switch/Switch.stories.svelte +3 -3
  212. package/dist/components/forms/switch/theme.js +6 -6
  213. package/dist/components/forms/textfield/Textfield.mdx +53 -0
  214. package/dist/components/forms/textfield/Textfield.stories.svelte +6 -6
  215. package/dist/components/forms/textfield/Textfield.svelte +1 -0
  216. package/dist/components/forms/textfield/theme.d.ts +3 -0
  217. package/dist/components/forms/textfield/theme.js +22 -19
  218. package/dist/components/forms/toggle-group/theme.js +2 -2
  219. package/dist/components/forms/tooltip/Tooltip.stories.svelte +1 -0
  220. package/dist/components/forms/tooltip/theme.js +3 -3
  221. package/dist/components/misc/Avatar.stories.svelte +5 -4
  222. package/dist/components/misc/ThemeSettings.svelte +9 -9
  223. package/dist/components/misc/ThemeSwitcher.svelte +3 -3
  224. package/dist/components/misc/theme.js +4 -4
  225. package/dist/components/nav/appbar/AppBar.mdx +71 -0
  226. package/dist/components/nav/appbar/AppBar.stories.svelte +93 -3
  227. package/dist/components/nav/appbar/AppBar.stories.svelte.d.ts +2 -17
  228. package/dist/components/nav/appbar/AppBar.svelte +90 -37
  229. package/dist/components/nav/appbar/AppBar.svelte.d.ts +9 -2
  230. package/dist/components/nav/appbar/theme.d.ts +85 -18
  231. package/dist/components/nav/appbar/theme.js +159 -23
  232. package/dist/components/nav/appbar/types.d.ts +46 -9
  233. package/dist/components/nav/breadcrumb/Breadcrumb.stories.svelte +1 -0
  234. package/dist/components/nav/breadcrumb/theme.js +5 -5
  235. package/dist/components/nav/navbar/Navbar.mdx +38 -0
  236. package/dist/components/nav/navbar/Navbar.svelte +1 -1
  237. package/dist/components/nav/navbar/NavbarItem.svelte +12 -9
  238. package/dist/components/nav/navbar/theme.js +6 -6
  239. package/dist/components/nav/rail/Rail.mdx +73 -0
  240. package/dist/components/nav/rail/Rail.stories.svelte +3 -7
  241. package/dist/components/nav/rail/Rail.svelte +1 -0
  242. package/dist/components/nav/rail/RailItem.svelte +12 -9
  243. package/dist/components/nav/rail/theme.js +13 -13
  244. package/dist/components/nav/rail/types.d.ts +4 -1
  245. package/dist/components/nav/tabs/TabHolder.svelte +29 -3
  246. package/dist/components/nav/tabs/TabHolder.svelte.d.ts +3 -1
  247. package/dist/components/nav/tabs/Tabs.mdx +62 -0
  248. package/dist/components/nav/tabs/Tabs.stories.svelte +1 -1
  249. package/dist/components/nav/tabs/theme.js +4 -4
  250. package/dist/components/pill/Pill.mdx +32 -0
  251. package/dist/components/pill/Pill.stories.svelte +1 -1
  252. package/dist/components/pill/theme.d.ts +1 -1
  253. package/dist/components/pill/theme.js +1 -1
  254. package/dist/components/progress/LinearProgress.svelte +1 -1
  255. package/dist/components/progress/Progress.mdx +50 -0
  256. package/dist/components/progress/Progress.stories.svelte +6 -6
  257. package/dist/components/snackbar/Snackbar.mdx +52 -0
  258. package/dist/components/snackbar/Snackbar.stories.svelte +5 -5
  259. package/dist/components/snackbar/Snackbar.svelte +1 -1
  260. package/dist/components/snackbar/theme.d.ts +3 -3
  261. package/dist/components/snackbar/theme.js +4 -4
  262. package/dist/components/table/Table.stories.svelte +1 -0
  263. package/dist/components/table/TableHeader.svelte +1 -1
  264. package/dist/components/table/theme.js +3 -3
  265. package/dist/components/time/TimeField.stories.svelte +3 -2
  266. package/dist/components/time/TimeField.svelte +14 -8
  267. package/dist/components/time/TimeField.svelte.d.ts +6 -0
  268. package/dist/components/time/TimepickerInput.svelte +9 -5
  269. package/dist/components/time/theme.js +5 -5
  270. package/dist/components/time/types.d.ts +11 -1
  271. package/dist/components/toolbar/Toolbar.stories.svelte +1 -0
  272. package/dist/components/toolbar/Toolbar.svelte +1 -1
  273. package/dist/components/toolbar/Toolbar.svelte.d.ts +1 -1
  274. package/dist/components/toolbar/theme.js +14 -14
  275. package/dist/components/typography/Typography.mdx +67 -0
  276. package/dist/components/typography/body/Body.stories.svelte +2 -1
  277. package/dist/components/typography/body/theme.d.ts +15 -12
  278. package/dist/components/typography/body/theme.js +19 -4
  279. package/dist/components/typography/body/types.d.ts +2 -1
  280. package/dist/components/typography/display/Display.stories.svelte +2 -1
  281. package/dist/components/typography/display/theme.d.ts +15 -12
  282. package/dist/components/typography/display/theme.js +19 -4
  283. package/dist/components/typography/display/types.d.ts +2 -1
  284. package/dist/components/typography/headline/Headline.stories.svelte +2 -1
  285. package/dist/components/typography/headline/theme.d.ts +15 -12
  286. package/dist/components/typography/headline/theme.js +19 -4
  287. package/dist/components/typography/headline/types.d.ts +2 -1
  288. package/dist/components/typography/kbd/Kbd.stories.svelte +2 -1
  289. package/dist/components/typography/kbd/theme.d.ts +4 -4
  290. package/dist/components/typography/kbd/theme.js +2 -2
  291. package/dist/components/typography/label/Label.stories.svelte +2 -1
  292. package/dist/components/typography/label/theme.d.ts +15 -12
  293. package/dist/components/typography/label/theme.js +19 -4
  294. package/dist/components/typography/label/types.d.ts +2 -1
  295. package/dist/components/typography/title/Title.stories.svelte +2 -1
  296. package/dist/components/typography/title/theme.d.ts +15 -12
  297. package/dist/components/typography/title/theme.js +19 -4
  298. package/dist/components/typography/title/types.d.ts +2 -1
  299. package/dist/index.css +1 -0
  300. package/dist/styles/component.css +78 -175
  301. package/dist/styles/elevation.css +9 -0
  302. package/dist/styles/spacing.css +29 -0
  303. package/dist/styles/typescale.css +635 -20
  304. package/dist/utils/Layer.svelte +1 -1
  305. package/dist/utils/icon/Icon.svelte +8 -6
  306. package/dist/utils/icon/loadingShapes.js +11 -10
  307. package/package.json +19 -15
  308. package/dist/components/containers/stack/HStack.svelte +0 -23
  309. package/dist/components/containers/stack/HStack.svelte.d.ts +0 -5
  310. package/dist/components/containers/stack/VStack.svelte +0 -23
  311. package/dist/components/containers/stack/VStack.svelte.d.ts +0 -5
  312. package/dist/components/containers/stack/index.d.ts +0 -4
  313. package/dist/components/containers/stack/theme.d.ts +0 -66
  314. package/dist/components/containers/stack/theme.js +0 -26
  315. package/dist/components/containers/stack/types.d.ts +0 -12
  316. /package/dist/components/containers/{stack → carousel}/types.js +0 -0
@@ -1,27 +1,25 @@
1
1
  <!--
2
2
  @component
3
- A leading action button fused to a trailing chevron trigger that opens a menu
4
- of related actions — e.g. "Reply" with a dropdown for "Reply all" / "Forward".
3
+ A split button: a leading button for the main action and a trailing button that opens a menu of
4
+ related ones, such as Send with Schedule send. The two share one colour style and sit 2dp apart;
5
+ their inner corners tighten at rest and round out while hovered, pressed or open.
5
6
 
6
- The two segments render as one connected shape: pill on the outer edges,
7
- squared on the corners where they touch (see `SPLIT_BUTTON_INNER_RADIUS`).
8
- Compose the dropdown from `MenuItem` (and `Divider`, headings, etc.), the
9
- same way you would with `Menu`.
7
+ Compose the menu from `MenuItem`s (and `Divider`, headings), as with `Menu`. For one trigger that
8
+ only opens a menu, use `Menu`; for selectable options, `ConnectedButtonGroup`.
10
9
 
11
- Contrast with `Menu` (a single trigger that only ever opens a menu — no
12
- separate primary action) and `ConnectedButtonGroup` (multiple equal,
13
- selectable items, no menu).
14
-
15
- @see https://m3.material.io/components/buttons/guidelines#834f5f31-e363-4d0f-bc4d-abac128f5f0e
10
+ @see https://m3.material.io/components/split-button/specs
16
11
  -->
17
12
  <script lang="ts">
18
13
  import { enterExit, presence } from '../../../animation/index.js';
19
- import { DropdownMenu } from 'bits-ui';
14
+ import { Icon, Layer } from '../../../utils/index.js';
15
+ import { Button, DropdownMenu } from 'bits-ui';
20
16
  import clsx from 'clsx';
21
- import Button from '../Button.svelte';
22
- import ButtonIcon from '../ButtonIcon.svelte';
23
- import { buttonIcon } from '../theme.js';
24
- import { SPLIT_BUTTON_INNER_RADIUS, splitButton } from './theme.js';
17
+ import { buttonColor, buttonElevation } from '../theme.js';
18
+ import { menu } from '../../containers/menu/theme.js';
19
+ import { SPLIT_CHEVRON_OFFSET, splitButton } from './theme.js';
20
+ import { animate } from 'motion';
21
+ import { springTokens, springTransition } from '../../../animation/spring.js';
22
+ import { shapeMorph, splitCorners } from '../shapeMorph.js';
25
23
  import type { SplitButtonProps } from './types.js';
26
24
 
27
25
  let {
@@ -30,61 +28,80 @@ selectable items, no menu).
30
28
  onclick,
31
29
  iconProps,
32
30
  variant = 'filled',
33
- color = 'default',
34
- size = 'md',
31
+ size = 'sm',
35
32
  disabled = false,
36
33
  open = $bindable(false),
37
34
  align = 'end',
38
35
  menuLabel = 'More options',
36
+ 'aria-label': ariaLabel,
39
37
  class: className
40
38
  }: SplitButtonProps = $props();
41
39
 
42
- const cls = $derived(splitButton({ open }));
43
- // Reuse ButtonIcon's own icon-size classes so the chevron matches exactly
44
- // what ButtonIcon would render — `iconProps.class` fully replaces its
45
- // internal size classes (see ButtonIcon.svelte), so we recompute them here.
46
- const chevronCls = $derived(
47
- clsx(buttonIcon({ variant, color, size, width: 'narrow' }).icon(), cls.icon())
48
- );
40
+ const cls = $derived(splitButton({ size }));
49
41
 
50
- const innerRadius = $derived(SPLIT_BUTTON_INNER_RADIUS[size ?? 'md']);
51
- const leadingStyle = $derived(
52
- `border-start-end-radius:${innerRadius};border-end-end-radius:${innerRadius}`
53
- );
54
- const trailingStyle = $derived(
55
- `border-start-start-radius:${innerRadius};border-end-start-radius:${innerRadius}`
42
+ let leadingEl = $state<HTMLElement | null>(null);
43
+ let trailingEl = $state<HTMLElement | null>(null);
44
+ $effect(() => (leadingEl ? shapeMorph(leadingEl, splitCorners('leading')) : undefined));
45
+ $effect(() => (trailingEl ? shapeMorph(trailingEl, splitCorners('trailing')) : undefined));
46
+
47
+ // Open: the menu icon springs to centre (cancelling its resting offset) and flips.
48
+ let chevronEl = $state<HTMLElement | null>(null);
49
+ $effect(() => {
50
+ const el = chevronEl;
51
+ if (!el) return;
52
+ const target = { x: open ? SPLIT_CHEVRON_OFFSET[size] : 0, rotate: open ? 180 : 0 };
53
+ const controls = matchMedia('(prefers-reduced-motion: reduce)').matches
54
+ ? animate(el, target, { duration: 0 })
55
+ : animate(el, target, springTransition(springTokens.fastSpatial));
56
+ return () => controls.stop();
57
+ });
58
+ const colorCls = $derived(
59
+ clsx(buttonColor({ variant, state: 'default' }), buttonElevation[variant])
56
60
  );
57
61
  </script>
58
62
 
59
63
  <div class={cls.root({ class: clsx(className) })}>
60
- <Button {variant} {color} {size} {disabled} {iconProps} {onclick} style={leadingStyle}>
61
- {@render children()}
62
- </Button>
63
-
64
+ <Button.Root
65
+ bind:ref={leadingEl}
66
+ type="button"
67
+ {disabled}
68
+ {onclick}
69
+ aria-label={ariaLabel}
70
+ class={cls.leading({ class: colorCls })}
71
+ data-cy="m3-split-button"
72
+ >
73
+ {#if iconProps}
74
+ <Icon {...iconProps} class={cls.leadingIcon({ class: clsx(iconProps.class) })} />
75
+ {/if}
76
+ {@render children?.()}
77
+ <Layer />
78
+ </Button.Root>
64
79
  <DropdownMenu.Root bind:open>
65
80
  <DropdownMenu.Trigger {disabled}>
66
81
  {#snippet child({ props })}
67
- <ButtonIcon
68
- {variant}
69
- {color}
70
- {size}
71
- {disabled}
72
- width="narrow"
73
- style={trailingStyle}
74
- tooltipContent={menuLabel}
75
- iconProps={{ name: 'arrow_drop_down', class: chevronCls }}
82
+ <Button.Root
83
+ bind:ref={trailingEl}
84
+ type="button"
76
85
  {...props}
77
- />
86
+ aria-label={menuLabel}
87
+ class={cls.trailing({ class: colorCls })}
88
+ data-cy="m3-split-button-menu"
89
+ >
90
+ <span bind:this={chevronEl} class="inline-flex">
91
+ <Icon name="keyboard_arrow_down" class={cls.chevron()} />
92
+ </span>
93
+ <Layer />
94
+ </Button.Root>
78
95
  {/snippet}
79
96
  </DropdownMenu.Trigger>
80
-
81
97
  <DropdownMenu.Portal>
82
98
  <DropdownMenu.Content {align} sideOffset={4} class="z-100">
83
99
  {#snippet child({ wrapperProps, props, open: isOpen })}
84
- <div {...wrapperProps} class={wrapperProps.class as any}>
100
+ <div {...wrapperProps}>
101
+ <!-- Menu's own panel, so MenuItem rows look the same here. -->
85
102
  <div
86
103
  {...props}
87
- class="bg-md-sys-color-surface-container-high shadow-elevation-3 ring-md-sys-color-outline/10 max-w-sm min-w-48 gap-1 overflow-y-auto rounded-lg px-2 py-1"
104
+ class={menu().content()}
88
105
  {@attach presence(() => isOpen, enterExit.scale)}
89
106
  >
90
107
  {@render menuChildren()}
@@ -1,18 +1,13 @@
1
1
  import type { SplitButtonProps } from './types.js';
2
2
  /**
3
- * A leading action button fused to a trailing chevron trigger that opens a menu
4
- * of related actions — e.g. "Reply" with a dropdown for "Reply all" / "Forward".
3
+ * A split button: a leading button for the main action and a trailing button that opens a menu of
4
+ * related ones, such as Send with Schedule send. The two share one colour style and sit 2dp apart;
5
+ * their inner corners tighten at rest and round out while hovered, pressed or open.
5
6
  *
6
- * The two segments render as one connected shape: pill on the outer edges,
7
- * squared on the corners where they touch (see `SPLIT_BUTTON_INNER_RADIUS`).
8
- * Compose the dropdown from `MenuItem` (and `Divider`, headings, etc.), the
9
- * same way you would with `Menu`.
7
+ * Compose the menu from `MenuItem`s (and `Divider`, headings), as with `Menu`. For one trigger that
8
+ * only opens a menu, use `Menu`; for selectable options, `ConnectedButtonGroup`.
10
9
  *
11
- * Contrast with `Menu` (a single trigger that only ever opens a menu — no
12
- * separate primary action) and `ConnectedButtonGroup` (multiple equal,
13
- * selectable items, no menu).
14
- *
15
- * @see https://m3.material.io/components/buttons/guidelines#834f5f31-e363-4d0f-bc4d-abac128f5f0e
10
+ * @see https://m3.material.io/components/split-button/specs
16
11
  */
17
12
  declare const SplitButton: import("svelte").Component<SplitButtonProps, {}, "open">;
18
13
  type SplitButton = ReturnType<typeof SplitButton>;
@@ -1,35 +1,128 @@
1
1
  import { type VariantProps } from 'tailwind-variants';
2
- import type { ButtonMDVariants } from '../theme.js';
3
2
  export type SplitButtonVariants = VariantProps<typeof splitButton>;
4
- export declare const SPLIT_BUTTON_INNER_RADIUS: Record<NonNullable<ButtonMDVariants['size']>, string>;
5
3
  export declare const splitButton: import("tailwind-variants").TVReturnType<{
6
- open: {
7
- true: {
8
- icon: string;
4
+ size: {
5
+ xs: {
6
+ leading: string[];
7
+ leadingIcon: "size-spacing-250 text-[20px]";
8
+ trailing: string[];
9
+ chevron: string;
10
+ };
11
+ sm: {
12
+ leading: string[];
13
+ leadingIcon: "size-spacing-250 text-[20px]";
14
+ trailing: string[];
15
+ chevron: string;
16
+ };
17
+ md: {
18
+ leading: string[];
19
+ leadingIcon: "size-spacing-300 text-[24px]";
20
+ trailing: string[];
21
+ chevron: string;
22
+ };
23
+ lg: {
24
+ leading: string[];
25
+ leadingIcon: "size-spacing-400 text-[32px]";
26
+ trailing: string[];
27
+ chevron: string;
28
+ };
29
+ xl: {
30
+ leading: string[];
31
+ leadingIcon: "size-spacing-500 text-[40px]";
32
+ trailing: string[];
33
+ chevron: string;
9
34
  };
10
- false: {};
11
35
  };
12
36
  }, {
13
37
  root: string;
14
- icon: string;
38
+ leading: string[];
39
+ leadingIcon: string;
40
+ trailing: string[];
41
+ chevron: string;
15
42
  }, undefined, {
16
- open: {
17
- true: {
18
- icon: string;
43
+ size: {
44
+ xs: {
45
+ leading: string[];
46
+ leadingIcon: "size-spacing-250 text-[20px]";
47
+ trailing: string[];
48
+ chevron: string;
49
+ };
50
+ sm: {
51
+ leading: string[];
52
+ leadingIcon: "size-spacing-250 text-[20px]";
53
+ trailing: string[];
54
+ chevron: string;
55
+ };
56
+ md: {
57
+ leading: string[];
58
+ leadingIcon: "size-spacing-300 text-[24px]";
59
+ trailing: string[];
60
+ chevron: string;
61
+ };
62
+ lg: {
63
+ leading: string[];
64
+ leadingIcon: "size-spacing-400 text-[32px]";
65
+ trailing: string[];
66
+ chevron: string;
67
+ };
68
+ xl: {
69
+ leading: string[];
70
+ leadingIcon: "size-spacing-500 text-[40px]";
71
+ trailing: string[];
72
+ chevron: string;
19
73
  };
20
- false: {};
21
74
  };
22
75
  }, {
23
76
  root: string;
24
- icon: string;
77
+ leading: string[];
78
+ leadingIcon: string;
79
+ trailing: string[];
80
+ chevron: string;
25
81
  }, import("tailwind-variants").TVReturnTypeLike<{
26
- open: {
27
- true: {
28
- icon: string;
82
+ size: {
83
+ xs: {
84
+ leading: string[];
85
+ leadingIcon: "size-spacing-250 text-[20px]";
86
+ trailing: string[];
87
+ chevron: string;
88
+ };
89
+ sm: {
90
+ leading: string[];
91
+ leadingIcon: "size-spacing-250 text-[20px]";
92
+ trailing: string[];
93
+ chevron: string;
94
+ };
95
+ md: {
96
+ leading: string[];
97
+ leadingIcon: "size-spacing-300 text-[24px]";
98
+ trailing: string[];
99
+ chevron: string;
100
+ };
101
+ lg: {
102
+ leading: string[];
103
+ leadingIcon: "size-spacing-400 text-[32px]";
104
+ trailing: string[];
105
+ chevron: string;
106
+ };
107
+ xl: {
108
+ leading: string[];
109
+ leadingIcon: "size-spacing-500 text-[40px]";
110
+ trailing: string[];
111
+ chevron: string;
29
112
  };
30
- false: {};
31
113
  };
32
114
  }, {
33
115
  root: string;
34
- icon: string;
116
+ leading: string[];
117
+ leadingIcon: string;
118
+ trailing: string[];
119
+ chevron: string;
35
120
  }>>;
121
+ /** The chevron's resting offset toward the leading button, in px (the `-translate-x-*` above). */
122
+ export declare const SPLIT_CHEVRON_OFFSET: {
123
+ readonly xs: 1;
124
+ readonly sm: 1;
125
+ readonly md: 2;
126
+ readonly lg: 3;
127
+ readonly xl: 6;
128
+ };
@@ -1,26 +1,84 @@
1
1
  import { tv } from 'tailwind-variants';
2
- // Inner (touching) corner radius per size — matches the ConnectedButtonGroup
3
- // scale (see buttons/connected/theme.ts's `--cbg-inner`), since a split button
4
- // is conceptually a 2-item connected group with a menu instead of a selection.
5
- export const SPLIT_BUTTON_INNER_RADIUS = {
6
- xs: '0.25rem',
7
- sm: '0.5rem',
8
- md: '0.5rem',
9
- lg: '1rem',
10
- xl: '1.25rem'
11
- };
2
+ import { buttonBase, buttonSizes } from '../theme.js';
3
+ /*
4
+ * Split button, per https://m3.material.io/components/split-button/specs. Both halves take the
5
+ * button's height, type and outline for their size. The leading button has its own padding, the
6
+ * trailing button a fixed width around a larger menu icon, and they sit 2dp apart. The corner
7
+ * rules are `.md-btn-split-*` in styles/component.css: inner corners --split-inner at rest,
8
+ * --split-active while hovered, focused or pressed, and fully round on the trailing button while
9
+ * the menu is open.
10
+ */
12
11
  export const splitButton = tv({
13
12
  slots: {
14
- root: 'inline-flex items-center gap-0.5',
15
- icon: 'transition-transform md-sys-motion-fast-spatial'
13
+ root: 'inline-flex items-stretch gap-spacing-25',
14
+ leading: [buttonBase, 'md-btn-split-leading'],
15
+ leadingIcon: 'shrink-0',
16
+ trailing: [buttonBase, 'md-btn-split-trailing px-spacing-0'],
17
+ // Off centre toward the leading button while closed (it balances the round outer edge);
18
+ // SplitButton.svelte springs it to centre and flips it while open.
19
+ chevron: 'shrink-0'
16
20
  },
17
21
  variants: {
18
- open: {
19
- true: { icon: 'rotate-180' },
20
- false: {}
22
+ size: {
23
+ xs: {
24
+ leading: [
25
+ buttonSizes.xs.base,
26
+ 'ps-spacing-150 pe-spacing-125 [--split-active:0.5rem] [--split-inner:0.25rem]'
27
+ ],
28
+ leadingIcon: buttonSizes.xs.icon,
29
+ trailing: [
30
+ buttonSizes.xs.base,
31
+ 'w-spacing-600 [--split-active:0.5rem] [--split-inner:0.25rem]'
32
+ ],
33
+ chevron: 'size-[22px] -translate-x-px text-[22px]'
34
+ },
35
+ sm: {
36
+ leading: [
37
+ buttonSizes.sm.base,
38
+ 'ps-spacing-200 pe-spacing-150 [--split-active:0.75rem] [--split-inner:0.25rem]'
39
+ ],
40
+ leadingIcon: buttonSizes.sm.icon,
41
+ trailing: [
42
+ buttonSizes.sm.base,
43
+ 'w-spacing-600 [--split-active:0.75rem] [--split-inner:0.25rem]'
44
+ ],
45
+ chevron: 'size-[22px] -translate-x-px text-[22px]'
46
+ },
47
+ md: {
48
+ leading: [
49
+ buttonSizes.md.base,
50
+ 'px-spacing-300 [--split-active:0.75rem] [--split-inner:0.25rem]'
51
+ ],
52
+ leadingIcon: buttonSizes.md.icon,
53
+ trailing: [
54
+ buttonSizes.md.base,
55
+ 'w-spacing-700 [--split-active:0.75rem] [--split-inner:0.25rem]'
56
+ ],
57
+ chevron: 'size-[26px] -translate-x-spacing-25 text-[26px]'
58
+ },
59
+ lg: {
60
+ leading: [
61
+ buttonSizes.lg.base,
62
+ 'px-spacing-600 [--split-active:1.25rem] [--split-inner:0.5rem]'
63
+ ],
64
+ leadingIcon: buttonSizes.lg.icon,
65
+ trailing: [buttonSizes.lg.base, 'w-24 [--split-active:1.25rem] [--split-inner:0.5rem]'],
66
+ chevron: 'size-[38px] -translate-x-[3px] text-[38px]'
67
+ },
68
+ xl: {
69
+ leading: [
70
+ buttonSizes.xl.base,
71
+ 'px-spacing-800 [--split-active:1.25rem] [--split-inner:0.75rem]'
72
+ ],
73
+ leadingIcon: buttonSizes.xl.icon,
74
+ trailing: [buttonSizes.xl.base, 'w-34 [--split-active:1.25rem] [--split-inner:0.75rem]'],
75
+ chevron: 'size-[50px] -translate-x-spacing-75 text-[50px]'
76
+ }
21
77
  }
22
78
  },
23
79
  defaultVariants: {
24
- open: false
80
+ size: 'sm'
25
81
  }
26
82
  });
83
+ /** The chevron's resting offset toward the leading button, in px (the `-translate-x-*` above). */
84
+ export const SPLIT_CHEVRON_OFFSET = { xs: 1, sm: 1, md: 2, lg: 3, xl: 6 };
@@ -1,33 +1,39 @@
1
1
  import type { IconProps } from '../../../utils/index.js';
2
2
  import type { Snippet } from 'svelte';
3
- import type { ButtonMDVariants } from '../theme.js';
3
+ import type { ButtonSize } from '../theme.js';
4
4
  export type SplitButtonProps = {
5
- /** Label/content for the leading action button. */
6
- children: Snippet;
7
- /** `MenuItem` (or similar) rows rendered inside the trailing dropdown panel. */
5
+ /** The leading button's label. It can have a label, an icon, or both. */
6
+ children?: Snippet;
7
+ /** The menu: `MenuItem`s (and dividers or headings), as in `Menu`. */
8
8
  menuChildren: Snippet;
9
- /** Called when the leading button itself is pressed (the primary action). */
9
+ /** The leading button's action. */
10
10
  onclick?: (e: MouseEvent) => void;
11
- /** Optional leading icon for the primary action button. */
11
+ /** The leading button's icon. */
12
12
  iconProps?: IconProps;
13
- /** The visual style shared by both segments. */
14
- variant?: ButtonMDVariants['variant'];
15
- /** The color scheme shared by both segments. */
16
- color?: ButtonMDVariants['color'];
17
- /** The size shared by both segments. Drives height, padding, and typescale. */
18
- size?: ButtonMDVariants['size'];
19
- /** Disables both the primary action and the menu trigger. */
13
+ /**
14
+ * Colour style of both buttons. Same colours as `Button`; opening the menu doesn't change them.
15
+ * There is no text split button.
16
+ * @default 'filled'
17
+ */
18
+ variant?: 'elevated' | 'filled' | 'tonal' | 'outlined';
19
+ /**
20
+ * Height 32, 40, 56, 96 or 136dp.
21
+ * @default 'sm'
22
+ */
23
+ size?: ButtonSize;
24
+ /** Disables both buttons. */
20
25
  disabled?: boolean;
21
- /** Controlled open state of the trailing dropdown. @bindable */
26
+ /** Whether the menu is open. Bindable. */
22
27
  open?: boolean;
23
- /** Alignment of the dropdown panel relative to the trailing trigger. @default 'end' */
28
+ /** Menu alignment against the trailing button. @default 'end' */
24
29
  align?: 'start' | 'center' | 'end';
25
30
  /**
26
- * Accessible label for the trailing menu trigger (it has no visible text,
27
- * only a chevron), and the tooltip shown on hover.
31
+ * Accessible name of the trailing button, which shows only an icon.
28
32
  * @default 'More options'
29
33
  */
30
34
  menuLabel?: string;
31
- /** Additional CSS classes applied to the outer wrapper. */
35
+ /** Accessible name of the leading button when it shows only an icon. */
36
+ 'aria-label'?: string;
37
+ /** Classes for the wrapper. */
32
38
  class?: string;
33
39
  };