@livestorm/ui-vue 2.0.5 → 4.0.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 (302) hide show
  1. package/README.md +9 -6
  2. package/components-vite.js +2 -2
  3. package/dist/UiButton-uyW8EHRJ.mjs +602 -0
  4. package/dist/UiTimelineItem-EiOEi1yF.mjs +7293 -0
  5. package/dist/UiTooltip-DZcPD6_N.mjs +158 -0
  6. package/dist/a11y-CaZxRWzo.mjs +6 -0
  7. package/dist/breakpoints.mjs +4 -9
  8. package/dist/bus.mjs +5 -5
  9. package/dist/components.mjs +236 -222
  10. package/dist/i18n-B8QOMuFD.mjs +46 -0
  11. package/dist/index.mjs +4 -87
  12. package/dist/integrations.mjs +3 -14
  13. package/dist/layouts.mjs +228 -236
  14. package/dist/responsive.mjs +31 -36
  15. package/dist/slot.mjs +11 -17
  16. package/dist/toastDSV2-D3xDZPe5.mjs +105 -0
  17. package/dist/types/index.d.ts +23 -1
  18. package/dist/types/src/components/Toast/ToastMessage.vue.d.ts +17 -7
  19. package/dist/types/src/components/Toast/toastDSV2.d.ts +89 -64
  20. package/dist/types/src/components/UiActionBar/UiActionBar.vue.d.ts +3 -1
  21. package/dist/types/src/components/UiActionBar/UiActionBarItem.vue.d.ts +18 -3
  22. package/dist/types/src/components/UiActionBar/types.d.ts +5 -1
  23. package/dist/types/src/components/UiAvatar/UiAvatar.vue.d.ts +4 -2
  24. package/dist/types/src/components/UiAvatarList/UiAvatarList.vue.d.ts +3 -2
  25. package/dist/types/src/components/UiBanner/UiBanner.vue.d.ts +13 -1
  26. package/dist/types/src/components/UiButton/UiButton.vue.d.ts +102 -38
  27. package/dist/types/src/components/UiButtonGroup/UiButtonGroup.vue.d.ts +8 -2
  28. package/dist/types/src/components/UiButtonGroup/UiButtonGroupItem.vue.d.ts +3 -0
  29. package/dist/types/src/components/UiButtonGroup/types.d.ts +5 -1
  30. package/dist/types/src/components/UiChoice/UiChoice.vue.d.ts +71 -0
  31. package/dist/types/src/components/UiChoice/index.d.ts +2 -0
  32. package/dist/types/src/components/UiChoice/types.d.ts +7 -0
  33. package/dist/types/src/components/UiColorField/UiColorField.vue.d.ts +1 -1
  34. package/dist/types/src/components/UiColorPicker/UiColorPicker.vue.d.ts +2 -2
  35. package/dist/types/src/components/UiCombobox/UiCombobox.types.d.ts +47 -0
  36. package/dist/types/src/components/UiCombobox/UiCombobox.vue.d.ts +40 -0
  37. package/dist/types/src/components/UiCombobox/index.d.ts +2 -0
  38. package/dist/types/src/components/UiDataTable/UiDataTable.types.d.ts +46 -0
  39. package/dist/types/src/components/UiDataTable/UiDataTable.vue.d.ts +136 -0
  40. package/dist/types/src/components/UiDataTable/index.d.ts +5 -0
  41. package/dist/types/src/components/UiDrawer/UiDrawer.vue.d.ts +28 -0
  42. package/dist/types/src/components/UiDrawer/UiDrawerContent.vue.d.ts +18 -0
  43. package/dist/types/src/components/UiDrawer/UiDrawerTrigger.vue.d.ts +14 -0
  44. package/dist/types/src/components/UiDropdown/DropdownItemCheckbox.vue.d.ts +3 -0
  45. package/dist/types/src/components/UiDropdown/UiDropdownContent.vue.d.ts +10 -0
  46. package/dist/types/src/components/UiDropdown/UiDropdownGroup.vue.d.ts +17 -0
  47. package/dist/types/src/components/UiDropdown/UiDropdownItem.vue.d.ts +9 -4
  48. package/dist/types/src/components/UiDropdown/UiDropdownTrigger.vue.d.ts +21 -5
  49. package/dist/types/src/components/UiDropdown/index.d.ts +1 -0
  50. package/dist/types/src/components/UiEmojiPickerList/UiEmojiPickerList.vue.d.ts +22 -0
  51. package/dist/types/src/components/UiEmptyState/UiEmptyState.vue.d.ts +8 -3
  52. package/dist/types/src/components/UiFieldWrapper/UiFieldWrapper.vue.d.ts +2 -2
  53. package/dist/types/src/components/UiInputCheckbox/CheckboxGlyph.vue.d.ts +17 -0
  54. package/dist/types/src/components/UiInputCheckbox/UiInputCheckbox.vue.d.ts +35 -4
  55. package/dist/types/src/components/UiInputEmoji/UiInputEmoji.vue.d.ts +45 -0
  56. package/dist/types/src/components/UiInputRadio/RadioGlyph.vue.d.ts +19 -0
  57. package/dist/types/src/components/UiInputRadio/UiInputRadio.vue.d.ts +80 -0
  58. package/dist/types/src/components/UiInputRadio/UiInputRadioGroup.vue.d.ts +86 -0
  59. package/dist/types/src/components/UiInputRadio/types.d.ts +19 -0
  60. package/dist/types/src/components/UiInputSelect/UiInputSelect.vue.d.ts +5 -5
  61. package/dist/types/src/components/UiInputTextarea/UiInputTextarea.vue.d.ts +5 -5
  62. package/dist/types/src/components/UiListItem/UiListItem.vue.d.ts +18 -4
  63. package/dist/types/src/components/UiLoader/UiLoader.vue.d.ts +6 -5
  64. package/dist/types/src/components/UiLoader/UiSpinnerIcon.vue.d.ts +3 -0
  65. package/dist/types/src/components/UiLogo/UiLogo.vue.d.ts +9 -3
  66. package/dist/types/src/components/UiMenu/UiMenuContent.vue.d.ts +15 -2
  67. package/dist/types/src/components/UiMenu/UiMenuItem.vue.d.ts +9 -3
  68. package/dist/types/src/components/UiNestedOptions/UiNestedOptions.vue.d.ts +13 -0
  69. package/dist/types/src/components/UiPage/UiPage.vue.d.ts +106 -8
  70. package/dist/types/src/components/UiPagination/UiPagination.vue.d.ts +36 -0
  71. package/dist/types/src/components/UiPagination/index.d.ts +2 -0
  72. package/dist/types/src/components/UiPagination/types.d.ts +4 -0
  73. package/dist/types/src/components/UiPane/UiPane.vue.d.ts +22 -0
  74. package/dist/types/src/components/UiPane/UiPaneContent.vue.d.ts +75 -0
  75. package/dist/types/src/components/UiPane/UiPaneTrigger.vue.d.ts +14 -0
  76. package/dist/types/src/components/UiPane/index.d.ts +5 -0
  77. package/dist/types/src/components/UiProgress/UiProgress.vue.d.ts +1 -1
  78. package/dist/types/src/components/UiRating/UiRating.vue.d.ts +62 -0
  79. package/dist/types/src/components/UiRating/types.d.ts +1 -0
  80. package/dist/types/src/components/UiRoomButton/UiRoomButton.vue.d.ts +5 -3
  81. package/dist/types/src/components/UiRoomCountdown/UiRoomCountdown.vue.d.ts +32 -0
  82. package/dist/types/src/components/UiShell/UiShell.vue.d.ts +3 -0
  83. package/dist/types/src/components/UiSideMenu/UiSideMenu.vue.d.ts +22 -1
  84. package/dist/types/src/components/UiSideMenu/UiSideMenuItemContent.vue.d.ts +2 -2
  85. package/dist/types/src/components/UiSwitch/UiSwitch.vue.d.ts +114 -0
  86. package/dist/types/src/components/UiSwitch/types.d.ts +3 -0
  87. package/dist/types/src/components/UiTable/UiTable.vue.d.ts +13 -4
  88. package/dist/types/src/components/UiTable/UiTableActionsCell.vue.d.ts +49 -0
  89. package/dist/types/src/components/UiTable/UiTableActionsHeaderCell.vue.d.ts +3 -0
  90. package/dist/types/src/components/UiTable/UiTableBody.vue.d.ts +11 -1
  91. package/dist/types/src/components/UiTable/UiTableCell.vue.d.ts +16 -1
  92. package/dist/types/src/components/UiTable/UiTableHeaderCell.vue.d.ts +31 -2
  93. package/dist/types/src/components/UiTable/UiTableRow.vue.d.ts +32 -2
  94. package/dist/types/src/components/UiTable/context.d.ts +3 -0
  95. package/dist/types/src/components/UiTable/index.d.ts +4 -0
  96. package/dist/types/src/components/UiTabs/UiTabs.vue.d.ts +8 -2
  97. package/dist/types/src/components/UiTag/UiTag.types.d.ts +25 -0
  98. package/dist/types/src/components/UiTag/UiTag.vue.d.ts +5 -26
  99. package/dist/types/src/components/UiTag/index.d.ts +2 -1
  100. package/dist/types/src/components/UiTextField/UiTextField.vue.d.ts +10 -5
  101. package/dist/types/src/components/UiTooltip/UiTooltipProvider.vue.d.ts +1 -0
  102. package/dist/types/src/components/UiTooltip/UiTooltipTrigger.vue.d.ts +2 -2
  103. package/dist/types/src/composables/storedThemingApplies.d.ts +17 -0
  104. package/dist/types/src/composables/useButtonStyles.d.ts +1 -0
  105. package/dist/types/src/composables/useChoiceboxSurface.d.ts +11 -0
  106. package/dist/types/src/composables/useContentMode.d.ts +23 -0
  107. package/dist/types/src/composables/useControlModes.d.ts +7 -0
  108. package/dist/types/src/composables/useControlShape.d.ts +24 -0
  109. package/dist/types/src/composables/useFieldFocusEvents.d.ts +12 -0
  110. package/dist/types/src/composables/useIconSize.d.ts +13 -0
  111. package/dist/types/src/composables/usePullGesture.d.ts +42 -0
  112. package/dist/types/src/composables/useThemeAndModes.d.ts +4 -0
  113. package/dist/types/src/constants/sizes.d.ts +1 -1
  114. package/dist/types/src/theming/colorScale.d.ts +165 -0
  115. package/dist/types/src/theming/legacyColorScale.d.ts +27 -0
  116. package/dist/types/src/theming/presetColors.d.ts +11 -0
  117. package/dist/types/src/theming/primitiveTokens.d.ts +2 -0
  118. package/dist/types/src/utils/effectiveOpacity.d.ts +2 -0
  119. package/dist/types/src/utils/numbers.d.ts +1 -2
  120. package/dist/types/src/utils/tokenColor.d.ts +2 -0
  121. package/dist/ui-vue.css +2 -1
  122. package/dist/utils.mjs +165 -194
  123. package/index.d.ts +22 -0
  124. package/index.js +44 -0
  125. package/package.json +28 -20
  126. package/src/components/Toast/LayoutToasts.vue +19 -11
  127. package/src/components/Toast/ToastMessage.vue +130 -73
  128. package/src/components/Toast/toastDSV2.ts +238 -67
  129. package/src/components/UiActionBar/UiActionBar.vue +15 -5
  130. package/src/components/UiActionBar/UiActionBarItem.vue +65 -38
  131. package/src/components/UiActionBar/types.ts +16 -1
  132. package/src/components/UiAvatar/UiAvatar.vue +9 -3
  133. package/src/components/UiAvatarList/UiAvatarList.vue +51 -20
  134. package/src/components/UiBadge/UiBadge.vue +1 -1
  135. package/src/components/UiBanner/UiBanner.vue +77 -27
  136. package/src/components/UiBreadcrumb/UiBreadcrumb.vue +1 -1
  137. package/src/components/UiButton/UiButton.vue +96 -29
  138. package/src/components/UiButtonGroup/UiButtonGroup.vue +22 -16
  139. package/src/components/UiButtonGroup/UiButtonGroupItem.vue +44 -14
  140. package/src/components/UiButtonGroup/types.ts +20 -1
  141. package/src/components/UiCard/UiCard.vue +20 -23
  142. package/src/components/UiCarousel/UiCarousel.vue +2 -2
  143. package/src/components/UiChoice/UiChoice.vue +187 -0
  144. package/src/components/UiChoice/index.ts +2 -0
  145. package/src/components/UiChoice/types.ts +11 -0
  146. package/src/components/UiColorField/UiColorField.vue +2 -2
  147. package/src/components/UiColorPicker/UiColorPicker.vue +16 -13
  148. package/src/components/UiCombobox/UiCombobox.types.ts +52 -0
  149. package/src/components/UiCombobox/UiCombobox.vue +296 -0
  150. package/src/components/UiCombobox/index.ts +2 -0
  151. package/src/components/UiDataTable/UiDataTable.types.ts +47 -0
  152. package/src/components/UiDataTable/UiDataTable.vue +422 -0
  153. package/src/components/UiDataTable/index.ts +12 -0
  154. package/src/components/UiDialog/UiDialogClose.vue +1 -1
  155. package/src/components/UiDialog/UiDialogContent.vue +22 -7
  156. package/src/components/UiDrawer/UiDrawer.vue +16 -0
  157. package/src/components/UiDrawer/UiDrawerContent.vue +42 -0
  158. package/src/components/UiDrawer/UiDrawerTrigger.vue +17 -0
  159. package/src/components/UiDropdown/DropdownItemCheckbox.vue +10 -0
  160. package/src/components/UiDropdown/UiDropdownContent.vue +32 -21
  161. package/src/components/UiDropdown/UiDropdownGroup.vue +23 -0
  162. package/src/components/UiDropdown/UiDropdownItem.vue +45 -18
  163. package/src/components/UiDropdown/UiDropdownSeparator.vue +1 -1
  164. package/src/components/UiDropdown/UiDropdownTrigger.vue +139 -45
  165. package/src/components/UiDropdown/index.ts +1 -0
  166. package/src/components/UiEmojiPickerList/UiEmojiPickerList.vue +122 -0
  167. package/src/components/UiEmptyState/UiEmptyState.vue +16 -4
  168. package/src/components/UiFieldWrapper/UiFieldWrapper.vue +10 -4
  169. package/src/components/UiHorizontalSeparator/UiHorizontalSeparator.vue +2 -2
  170. package/src/components/UiInputCheckbox/CheckboxGlyph.vue +78 -0
  171. package/src/components/UiInputCheckbox/UiInputCheckbox.vue +213 -177
  172. package/src/components/UiInputEmoji/UiInputEmoji.vue +96 -0
  173. package/src/components/UiInputRadio/RadioGlyph.vue +45 -0
  174. package/src/components/UiInputRadio/UiInputRadio.vue +382 -0
  175. package/src/components/UiInputRadio/UiInputRadioGroup.vue +166 -0
  176. package/src/components/UiInputRadio/types.ts +24 -0
  177. package/src/components/UiInputSelect/UiInputSelect.vue +9 -7
  178. package/src/components/UiInputTextarea/UiInputTextarea.vue +20 -35
  179. package/src/components/UiLabel/UiLabel.vue +1 -1
  180. package/src/components/UiListItem/UiListItem.vue +55 -9
  181. package/src/components/UiLoader/UiLoader.vue +11 -29
  182. package/src/components/UiLoader/UiSpinnerIcon.vue +21 -0
  183. package/src/components/UiLogo/UiLogo.vue +41 -7
  184. package/src/components/UiMenu/UiMenuContent.vue +24 -3
  185. package/src/components/UiMenu/UiMenuGroup.vue +1 -1
  186. package/src/components/UiMenu/UiMenuItem.vue +14 -3
  187. package/src/components/UiMenu/UiMenuSubContent.vue +1 -1
  188. package/src/components/UiMenu/UiMenuSubTrigger.vue +2 -2
  189. package/src/components/UiNestedOptions/UiNestedOptions.vue +6 -0
  190. package/src/components/UiPage/UiPage.vue +273 -47
  191. package/src/components/UiPageHeader/UiPageHeader.vue +29 -9
  192. package/src/components/UiPagination/UiPagination.vue +99 -0
  193. package/src/components/UiPagination/index.ts +2 -0
  194. package/src/components/UiPagination/types.ts +28 -0
  195. package/src/components/UiPane/UiPane.vue +20 -0
  196. package/src/components/UiPane/UiPaneContent.vue +232 -0
  197. package/src/components/UiPane/UiPaneTrigger.vue +14 -0
  198. package/src/components/UiPane/index.ts +12 -0
  199. package/src/components/UiPopover/UiPopoverContent.vue +21 -1
  200. package/src/components/UiProgress/UiProgress.vue +2 -2
  201. package/src/components/UiRating/UiRating.vue +258 -0
  202. package/src/components/UiRating/types.ts +1 -0
  203. package/src/components/UiRoomButton/UiRoomButton.vue +14 -45
  204. package/src/components/UiRoomCountdown/UiRoomCountdown.vue +376 -0
  205. package/src/components/UiShell/UiShell.vue +10 -4
  206. package/src/components/UiSideMenu/UiSideMenu.vue +158 -18
  207. package/src/components/UiSideMenu/UiSideMenuItemContent.vue +22 -18
  208. package/src/components/UiStepper/UiStepper.vue +3 -16
  209. package/src/components/UiStepper/UiStepperDescription.vue +1 -13
  210. package/src/components/UiStepper/UiStepperIndicator.vue +17 -57
  211. package/src/components/UiStepper/UiStepperItem.vue +1 -8
  212. package/src/components/UiStepper/UiStepperSeparator.vue +5 -16
  213. package/src/components/UiStepper/UiStepperTitle.vue +1 -10
  214. package/src/components/UiSwitch/UiSwitch.vue +375 -0
  215. package/src/components/UiSwitch/types.ts +5 -0
  216. package/src/components/UiTable/UiTable.vue +98 -8
  217. package/src/components/UiTable/UiTableActionsCell.vue +135 -0
  218. package/src/components/UiTable/UiTableActionsHeaderCell.vue +19 -0
  219. package/src/components/UiTable/UiTableBody.vue +16 -1
  220. package/src/components/UiTable/UiTableCell.vue +33 -16
  221. package/src/components/UiTable/UiTableHeader.vue +6 -5
  222. package/src/components/UiTable/UiTableHeaderCell.vue +61 -9
  223. package/src/components/UiTable/UiTableRow.vue +46 -10
  224. package/src/components/UiTable/context.ts +5 -0
  225. package/src/components/UiTable/index.ts +4 -0
  226. package/src/components/UiTabs/UiTabs.vue +61 -63
  227. package/src/components/UiTag/UiTag.types.ts +28 -0
  228. package/src/components/UiTag/UiTag.vue +24 -42
  229. package/src/components/UiTag/index.ts +2 -0
  230. package/src/components/UiTextField/UiTextField.vue +27 -47
  231. package/src/components/UiTimeline/README.md +6 -6
  232. package/src/components/UiTimeline/UiTimelineItem.vue +3 -3
  233. package/src/components/UiTooltip/UiTooltipContent.vue +1 -1
  234. package/src/components/UiTooltip/UiTooltipProvider.vue +3 -0
  235. package/src/components/UiTooltip/UiTooltipTrigger.vue +16 -1
  236. package/src/composables/storedThemingApplies.ts +19 -0
  237. package/src/composables/useButtonStyles.ts +9 -13
  238. package/src/composables/useChoiceboxSurface.ts +36 -0
  239. package/src/composables/useContentMode.ts +66 -0
  240. package/src/composables/useControlModes.ts +11 -0
  241. package/src/composables/useControlShape.ts +34 -0
  242. package/src/composables/useFieldFocusEvents.ts +30 -0
  243. package/src/composables/useIconSize.ts +43 -0
  244. package/src/composables/usePullGesture.ts +142 -0
  245. package/src/composables/useThemeAndModes.ts +28 -1
  246. package/src/constants/sizes.ts +1 -1
  247. package/src/css/body.css +16 -1
  248. package/src/css/fonts.css +39 -5
  249. package/src/global.d.ts +44 -0
  250. package/src/theming/colorScale.ts +173 -0
  251. package/src/theming/legacyColorScale.ts +58 -0
  252. package/src/theming/presetColors.ts +33 -0
  253. package/src/theming/primitiveTokens.ts +71 -0
  254. package/src/utils/effectiveOpacity.ts +8 -0
  255. package/src/utils/i18n.ts +6 -0
  256. package/src/utils/numbers.ts +1 -1
  257. package/src/utils/responsive.d.ts +14 -0
  258. package/src/utils/tokenColor.ts +9 -0
  259. package/dist/UiTimelineItem.vue_vue_type_style_index_0_lang-DJFdCn2R.mjs +0 -5456
  260. package/dist/a11y-BhF_nl7L.mjs +0 -159
  261. package/dist/i18n-Cktw9hIu.mjs +0 -49
  262. package/dist/toastDSV2-wMh-UMzW.mjs +0 -74
  263. package/dist/types/src/components/UiAvatar/index.d.ts +0 -1
  264. package/dist/types/src/components/UiAvatarList/index.d.ts +0 -1
  265. package/dist/types/src/components/UiBadge/index.d.ts +0 -1
  266. package/dist/types/src/components/UiBanner/index.d.ts +0 -2
  267. package/dist/types/src/components/UiButtonGroup/index.d.ts +0 -3
  268. package/dist/types/src/components/UiCarousel/index.d.ts +0 -2
  269. package/dist/types/src/components/UiColorField/index.d.ts +0 -2
  270. package/dist/types/src/components/UiDialog/MarketplaceHeaderExample.vue.d.ts +0 -28
  271. package/dist/types/src/components/UiDialog/index.d.ts +0 -7
  272. package/dist/types/src/components/UiFieldWrapper/index.d.ts +0 -1
  273. package/dist/types/src/components/UiInputCheckbox/index.d.ts +0 -2
  274. package/dist/types/src/components/UiInputSelect/index.d.ts +0 -2
  275. package/dist/types/src/components/UiInputTextarea/index.d.ts +0 -2
  276. package/dist/types/src/components/UiMenu/index.d.ts +0 -10
  277. package/dist/types/src/components/UiProgress/index.d.ts +0 -2
  278. package/dist/types/src/components/UiTabs/index.d.ts +0 -2
  279. package/dist/types/src/components/UiTimeline/index.d.ts +0 -2
  280. package/dist/types/src/components/UiTooltip/index.d.ts +0 -4
  281. package/dist/types/src/mixins/DynamicAction.d.ts +0 -30
  282. package/dist/useThemeAndModes-BzYwSOEv.mjs +0 -108
  283. package/src/components/UiAvatar/index.js +0 -1
  284. package/src/components/UiAvatarList/index.js +0 -1
  285. package/src/components/UiBadge/index.ts +0 -2
  286. package/src/components/UiBanner/index.ts +0 -2
  287. package/src/components/UiButtonGroup/index.ts +0 -3
  288. package/src/components/UiCarousel/index.ts +0 -2
  289. package/src/components/UiColorField/index.ts +0 -2
  290. package/src/components/UiDialog/MarketplaceHeaderExample.vue +0 -217
  291. package/src/components/UiDialog/index.ts +0 -18
  292. package/src/components/UiFieldWrapper/index.ts +0 -1
  293. package/src/components/UiInputCheckbox/index.ts +0 -2
  294. package/src/components/UiInputSelect/index.ts +0 -2
  295. package/src/components/UiInputTextarea/index.ts +0 -2
  296. package/src/components/UiMenu/index.ts +0 -10
  297. package/src/components/UiProgress/index.ts +0 -2
  298. package/src/components/UiTabs/index.ts +0 -5
  299. package/src/components/UiTag/index.js +0 -1
  300. package/src/components/UiTimeline/index.ts +0 -2
  301. package/src/components/UiTooltip/index.js +0 -4
  302. package/src/mixins/DynamicAction.js +0 -61
@@ -3,11 +3,14 @@ import { ToggleGroupRoot } from 'reka-ui'
3
3
  import type { AcceptableValue } from 'reka-ui'
4
4
  import { useDebounceFn, useResizeObserver } from '@vueuse/core'
5
5
  import { computed, nextTick, onMounted, provide, ref, watch } from 'vue'
6
- import type { ButtonGroupColor, ButtonGroupSize } from './types'
6
+ import type { ButtonGroupColor, ButtonGroupSize, ButtonGroupVariant } from './types'
7
7
  import {
8
8
  BUTTON_GROUP_COLOR_KEY,
9
+ BUTTON_GROUP_INNER_RADIUS,
10
+ BUTTON_GROUP_RAIL_RADIUS,
9
11
  BUTTON_GROUP_REGISTER_KEY,
10
12
  BUTTON_GROUP_SIZE_KEY,
13
+ BUTTON_GROUP_VARIANT_KEY,
11
14
  } from './types'
12
15
 
13
16
  interface UiButtonGroupProps {
@@ -16,6 +19,8 @@ interface UiButtonGroupProps {
16
19
  disabled?: boolean
17
20
  size?: ButtonGroupSize
18
21
  color?: ButtonGroupColor
22
+ /** `strong` fills the selected item with the color; `light` raises it on the surface and writes its label in the color. */
23
+ variant?: ButtonGroupVariant
19
24
  name?: string
20
25
  orientation?: 'horizontal' | 'vertical'
21
26
  /**
@@ -24,14 +29,18 @@ interface UiButtonGroupProps {
24
29
  * Set to true to allow clearing the selection by clicking the active item.
25
30
  */
26
31
  allowDeselect?: boolean
32
+ /** When false, the group hugs its items instead of filling its container. */
33
+ fullWidth?: boolean
27
34
  }
28
35
 
29
36
  const props = withDefaults(defineProps<UiButtonGroupProps>(), {
30
37
  size: 'md',
31
38
  color: 'neutral',
39
+ variant: 'strong',
32
40
  orientation: 'horizontal',
33
41
  disabled: false,
34
42
  allowDeselect: false,
43
+ fullWidth: true,
35
44
  modelValue: undefined,
36
45
  defaultValue: undefined,
37
46
  name: undefined,
@@ -43,6 +52,7 @@ const emit = defineEmits<{
43
52
 
44
53
  provide(BUTTON_GROUP_SIZE_KEY, computed(() => props.size))
45
54
  provide(BUTTON_GROUP_COLOR_KEY, computed(() => props.color))
55
+ provide(BUTTON_GROUP_VARIANT_KEY, computed(() => props.variant))
46
56
 
47
57
  // --- Sliding indicator -----------------------------------------------------
48
58
  // Each item registers its DOM node on mount. When the selected value or
@@ -85,12 +95,10 @@ function updateIndicator () {
85
95
  return
86
96
  }
87
97
 
88
- const rootRect = rootEl.getBoundingClientRect()
89
- const itemRect = activeEl.getBoundingClientRect()
90
98
  indicatorStyle.value = {
91
- transform: `translate(${itemRect.left - rootRect.left}px, ${itemRect.top - rootRect.top}px)`,
92
- width: `${itemRect.width}px`,
93
- height: `${itemRect.height}px`,
99
+ transform: `translate(${activeEl.offsetLeft}px, ${activeEl.offsetTop}px)`,
100
+ width: `${activeEl.offsetWidth}px`,
101
+ height: `${activeEl.offsetHeight}px`,
94
102
  }
95
103
  indicatorVisible.value = true
96
104
  }
@@ -124,6 +132,7 @@ useResizeObserver(resizeTarget, debouncedUpdate)
124
132
 
125
133
  const sizeClasses = computed(() => {
126
134
  switch (props.size) {
135
+ case 'xs': return 'h-6 p-0.5 gap-0.5'
127
136
  case 'sm': return 'h-8 p-0.5 gap-0.5'
128
137
  case 'lg': return 'h-12 p-1 gap-1'
129
138
  case 'md':
@@ -149,15 +158,12 @@ const INDICATOR_BG: Record<ButtonGroupColor, string> = {
149
158
  'error': 'bg-actions-danger-idle',
150
159
  }
151
160
 
152
- const INDICATOR_RADIUS: Record<ButtonGroupSize, string> = {
153
- sm: 'rounded-md',
154
- md: 'rounded-lg',
155
- lg: 'rounded-lg',
156
- }
157
-
158
161
  const railBgClass = computed(() => RAIL_BG[props.color])
159
- const indicatorBgClass = computed(() => INDICATOR_BG[props.color])
160
- const indicatorRadiusClass = computed(() => INDICATOR_RADIUS[props.size])
162
+ const indicatorBgClass = computed(() => props.variant === 'light'
163
+ ? 'bg-surface-neutral-bg-main shadow-elevation-level-1'
164
+ : INDICATOR_BG[props.color])
165
+ const indicatorRadiusClass = computed(() => BUTTON_GROUP_INNER_RADIUS[props.size])
166
+ const railRadiusClass = computed(() => BUTTON_GROUP_RAIL_RADIUS[props.size])
161
167
 
162
168
  function handleUpdate (value: AcceptableValue | AcceptableValue[]) {
163
169
  const next = Array.isArray(value) ? value[0] : value
@@ -183,8 +189,8 @@ function handleUpdate (value: AcceptableValue | AcceptableValue[]) {
183
189
  :name="name"
184
190
  :roving-focus="true"
185
191
  type="single"
186
- class="relative inline-flex w-full items-stretch rounded-lg"
187
- :class="[sizeClasses, railBgClass, { 'flex-col h-auto': orientation === 'vertical' }]"
192
+ class="relative inline-flex items-stretch"
193
+ :class="[fullWidth ? 'w-full' : 'w-fit', sizeClasses, railRadiusClass, railBgClass, { 'flex-col h-auto': orientation === 'vertical' }]"
188
194
  @update:model-value="handleUpdate"
189
195
  >
190
196
  <div
@@ -1,26 +1,33 @@
1
1
  <script setup lang="ts">
2
2
  import { ToggleGroupItem } from 'reka-ui'
3
3
  import { computed, inject, onBeforeUnmount, onMounted, ref, watch } from 'vue'
4
- import type { ButtonGroupColor } from './types'
4
+ import { useIconSize } from '../../composables/useIconSize'
5
+ import type { ButtonGroupColor, ButtonGroupVariant } from './types'
5
6
  import {
6
7
  BUTTON_GROUP_COLOR_KEY,
8
+ BUTTON_GROUP_INNER_RADIUS,
7
9
  BUTTON_GROUP_REGISTER_KEY,
8
10
  BUTTON_GROUP_SIZE_KEY,
11
+ BUTTON_GROUP_VARIANT_KEY,
9
12
  } from './types'
10
13
 
11
14
  interface UiButtonGroupItemProps {
12
15
  value: string
13
16
  disabled?: boolean
14
17
  ariaLabel?: string
18
+ /** Icon class (e.g. "i-ph-text-align-left") rendered before the slot, sized per group size. */
19
+ icon?: string
15
20
  }
16
21
 
17
22
  const props = withDefaults(defineProps<UiButtonGroupItemProps>(), {
18
23
  disabled: false,
19
24
  ariaLabel: undefined,
25
+ icon: undefined,
20
26
  })
21
27
 
22
28
  const size = inject(BUTTON_GROUP_SIZE_KEY, computed(() => 'md' as const))
23
29
  const color = inject(BUTTON_GROUP_COLOR_KEY, computed<ButtonGroupColor>(() => 'neutral'))
30
+ const variant = inject(BUTTON_GROUP_VARIANT_KEY, computed<ButtonGroupVariant>(() => 'strong'))
24
31
  const registry = inject(BUTTON_GROUP_REGISTER_KEY, null)
25
32
 
26
33
  const itemRef = ref<InstanceType<typeof ToggleGroupItem> | null>(null)
@@ -55,13 +62,16 @@ onBeforeUnmount(() => {
55
62
  // (rail height − rail padding) in horizontal mode, and drives height in vertical mode.
56
63
  const sizeClasses = computed(() => {
57
64
  switch (size.value) {
58
- case 'sm': return 'px-2.5 py-1.5 gap-1 rounded-md text-action-button-sm'
59
- case 'lg': return 'px-6 py-2.5 gap-2 rounded-lg text-action-button-lg'
65
+ case 'xs': return 'px-2 py-0.5 gap-1 text-action-button-sm'
66
+ case 'sm': return 'px-2.5 py-1.5 gap-1 text-action-button-sm'
67
+ case 'lg': return 'px-6 py-2.5 gap-2 text-action-button-lg'
60
68
  case 'md':
61
- default: return 'px-4 py-2.5 gap-1.5 rounded-lg text-action-button-md'
69
+ default: return 'px-4 py-2.5 gap-1.5 text-action-button-md'
62
70
  }
63
71
  })
64
72
 
73
+ const iconSizeClass = useIconSize(size)
74
+
65
75
  // Per-color state classes. The selected fill is drawn by the parent's sliding
66
76
  // indicator <div>, so items only set text color per state. Hover bg/text apply
67
77
  // only to unselected items (data-[state=off]) so the hover tint never stacks
@@ -71,41 +81,56 @@ const COLOR_CLASSES: Record<ButtonGroupColor, string> = {
71
81
  'text-actions-neutral-idle-alpha-strong',
72
82
  'data-[state=off]:hover:bg-actions-neutral-hover-overlay',
73
83
  'data-[state=off]:hover:text-actions-neutral-idle',
74
- 'data-[state=on]:text-actions-neutral-invert-idle',
75
84
  ].join(' '),
76
85
  'neutral-invert': [
77
86
  'text-actions-neutral-invert-idle-alpha-strong',
78
87
  'data-[state=off]:hover:bg-actions-neutral-invert-hover-overlay',
79
88
  'data-[state=off]:hover:text-actions-neutral-invert-idle',
80
- 'data-[state=on]:text-actions-neutral-idle',
81
89
  ].join(' '),
82
90
  'primary': [
83
91
  'text-actions-primary-idle-alpha-strong',
84
92
  'data-[state=off]:hover:bg-actions-primary-hover-overlay',
85
93
  'data-[state=off]:hover:text-actions-primary-idle',
86
- 'data-[state=on]:text-actions-neutral-invert-idle',
87
94
  ].join(' '),
88
95
  'success': [
89
96
  'text-actions-success-idle-alpha-strong',
90
97
  'data-[state=off]:hover:bg-actions-success-hover-overlay',
91
98
  'data-[state=off]:hover:text-actions-success-idle',
92
- 'data-[state=on]:text-actions-neutral-invert-idle',
93
99
  ].join(' '),
94
100
  'warning': [
95
101
  'text-actions-warning-idle-alpha-strong',
96
102
  'data-[state=off]:hover:bg-actions-warning-hover-overlay',
97
103
  'data-[state=off]:hover:text-actions-warning-idle',
98
- 'data-[state=on]:text-actions-neutral-invert-idle',
99
104
  ].join(' '),
100
105
  'error': [
101
106
  'text-actions-danger-idle-alpha-strong',
102
107
  'data-[state=off]:hover:bg-actions-danger-hover-overlay',
103
108
  'data-[state=off]:hover:text-actions-danger-idle',
104
- 'data-[state=on]:text-actions-neutral-invert-idle',
105
109
  ].join(' '),
106
110
  }
107
111
 
108
- const colorClasses = computed(() => COLOR_CLASSES[color.value])
112
+ const STRONG_SELECTED_TEXT: Record<ButtonGroupColor, string> = {
113
+ 'neutral': 'data-[state=on]:text-actions-neutral-invert-idle',
114
+ 'neutral-invert': 'data-[state=on]:text-actions-neutral-idle',
115
+ 'primary': 'data-[state=on]:text-actions-neutral-invert-idle',
116
+ 'success': 'data-[state=on]:text-actions-neutral-invert-idle',
117
+ 'warning': 'data-[state=on]:text-actions-neutral-invert-idle',
118
+ 'error': 'data-[state=on]:text-actions-neutral-invert-idle',
119
+ }
120
+
121
+ const LIGHT_SELECTED_TEXT: Record<ButtonGroupColor, string> = {
122
+ 'neutral': 'data-[state=on]:text-actions-neutral-idle',
123
+ 'neutral-invert': 'data-[state=on]:text-actions-neutral-idle',
124
+ 'primary': 'data-[state=on]:text-actions-primary-idle',
125
+ 'success': 'data-[state=on]:text-actions-success-idle',
126
+ 'warning': 'data-[state=on]:text-actions-warning-idle',
127
+ 'error': 'data-[state=on]:text-actions-danger-idle',
128
+ }
129
+
130
+ const colorClasses = computed(() => [
131
+ COLOR_CLASSES[color.value],
132
+ (variant.value === 'light' ? LIGHT_SELECTED_TEXT : STRONG_SELECTED_TEXT)[color.value],
133
+ ])
109
134
  </script>
110
135
 
111
136
  <template>
@@ -114,12 +139,17 @@ const colorClasses = computed(() => COLOR_CLASSES[color.value])
114
139
  :value="value"
115
140
  :disabled="disabled"
116
141
  :aria-label="ariaLabel"
117
- class="relative z-10 flex-1 inline-flex items-center justify-center transition-colors cursor-pointer outline-none
118
- focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-focus-ring
142
+ class="relative z-10 flex-1 inline-flex items-center justify-center whitespace-nowrap transition-colors cursor-pointer outline-none
143
+ focus-visible:focus-ring
119
144
  data-[disabled]:opacity-50 data-[disabled]:cursor-not-allowed
120
145
  data-[state=off]:data-[disabled]:hover:bg-transparent"
121
- :class="[sizeClasses, colorClasses]"
146
+ :class="[sizeClasses, BUTTON_GROUP_INNER_RADIUS[size], colorClasses]"
122
147
  >
148
+ <span
149
+ v-if="icon"
150
+ :class="[icon, iconSizeClass]"
151
+ class="shrink-0"
152
+ />
123
153
  <slot />
124
154
  </ToggleGroupItem>
125
155
  </template>
@@ -1,6 +1,6 @@
1
1
  import type { ComputedRef, InjectionKey } from 'vue'
2
2
 
3
- export type ButtonGroupSize = 'sm' | 'md' | 'lg'
3
+ export type ButtonGroupSize = 'xs' | 'sm' | 'md' | 'lg'
4
4
  export type ButtonGroupColor =
5
5
  | 'neutral'
6
6
  | 'neutral-invert'
@@ -8,6 +8,7 @@ export type ButtonGroupColor =
8
8
  | 'success'
9
9
  | 'warning'
10
10
  | 'error'
11
+ export type ButtonGroupVariant = 'strong' | 'light'
11
12
 
12
13
  export interface ButtonGroupRegister {
13
14
  register(value: string, el: HTMLElement): void
@@ -20,5 +21,23 @@ export const BUTTON_GROUP_SIZE_KEY: InjectionKey<ComputedRef<ButtonGroupSize>> =
20
21
  export const BUTTON_GROUP_COLOR_KEY: InjectionKey<ComputedRef<ButtonGroupColor>> =
21
22
  Symbol('ui-button-group-color')
22
23
 
24
+ export const BUTTON_GROUP_VARIANT_KEY: InjectionKey<ComputedRef<ButtonGroupVariant>> =
25
+ Symbol('ui-button-group-variant')
26
+
23
27
  export const BUTTON_GROUP_REGISTER_KEY: InjectionKey<ButtonGroupRegister> =
24
28
  Symbol('ui-button-group-register')
29
+
30
+ export const BUTTON_GROUP_RAIL_RADIUS: Record<ButtonGroupSize, string> = {
31
+ xs: 'rounded-button-xs',
32
+ sm: 'rounded-button-sm',
33
+ md: 'rounded-button-md',
34
+ lg: 'rounded-field-lg',
35
+ }
36
+
37
+ // Inner radius stays concentric with the rail: rail radius minus rail padding.
38
+ export const BUTTON_GROUP_INNER_RADIUS: Record<ButtonGroupSize, string> = {
39
+ xs: 'rounded-[calc(var(--radius-button-xs)_-_2px)]',
40
+ sm: 'rounded-[calc(var(--radius-button-sm)_-_2px)]',
41
+ md: 'rounded-[calc(var(--radius-button-md)_-_2px)]',
42
+ lg: 'rounded-[calc(var(--radius-field-lg)_-_4px)]',
43
+ }
@@ -23,35 +23,40 @@ const props = withDefaults(defineProps<UiCardProps>(), {
23
23
  disabled: false,
24
24
  })
25
25
 
26
- const baseCardClasses = 'bg-surface-neutral-alpha-100 border border-borders-neutral-light'
26
+ const baseCardClasses = 'bg-surface-neutral-bg-main'
27
27
 
28
28
  const variantClasses = computed(() => {
29
29
  if (props.selected) {
30
- return 'bg-surface-primary-alpha-100 border border-borders-neutral-light ring-2 ring-actions-primary-idle'
30
+ return 'bg-surface-primary-alpha-100 ring-2 ring-actions-primary-idle'
31
31
  }
32
32
 
33
33
  switch (props.variant) {
34
34
  case 'success':
35
- return 'bg-surface-success-alpha-200 border border-borders-neutral-light'
35
+ return 'bg-surface-success-alpha-200'
36
36
  case 'warning':
37
- return 'bg-surface-warning-alpha-100 border border-borders-neutral-light'
37
+ return 'bg-surface-warning-alpha-100'
38
38
  case 'danger':
39
- return 'bg-surface-danger-alpha-100 border border-borders-neutral-light'
39
+ return 'bg-surface-danger-alpha-100'
40
40
  case 'primary':
41
- return 'bg-surface-primary-alpha-100 border border-borders-neutral-light'
41
+ return 'bg-surface-primary-alpha-100'
42
42
  case 'primary-fill':
43
- return 'bg-surface-primary-bg-alpha border border-borders-neutral-light'
43
+ return 'bg-surface-primary-bg-alpha'
44
44
  case 'transparent':
45
- return 'bg-transparent border border-borders-neutral-light'
45
+ return 'bg-transparent'
46
46
  case 'neutral':
47
- return 'bg-surface-neutral-alpha-100 border border-borders-neutral-light'
48
47
  case 'white':
49
- return 'bg-surface-neutral-bg-main border border-borders-neutral-light'
48
+ return baseCardClasses
50
49
  default:
51
50
  return baseCardClasses
52
51
  }
53
52
  })
54
53
 
54
+ // A selected card is always a choice; a disabled one cannot be acted on.
55
+ const borderClasses = computed(() => {
56
+ const isInteractive = props.selected || (props.interactive && !props.disabled)
57
+ return isInteractive ? 'border border-container-interactive-border' : 'border border-container-border'
58
+ })
59
+
55
60
  const paddingClasses = computed(() => {
56
61
  // Based on Figma: default padding is 32px (p-8)
57
62
  switch (props.padding) {
@@ -70,11 +75,7 @@ const paddingClasses = computed(() => {
70
75
 
71
76
  const interactiveClasses = computed(() => {
72
77
  if (!props.interactive || props.disabled) return ''
73
- // Don't apply hover ring if already selected (to preserve the selected ring-2)
74
- if (props.selected) {
75
- return 'cursor-pointer transition-all duration-150 hover:shadow-shadows-drop-shadow-lg'
76
- }
77
- return 'cursor-pointer transition-all duration-150 hover:ring-1 hover:ring-shadow-neutral-100 hover:shadow-shadows-drop-shadow-lg'
78
+ return 'cursor-pointer transition-all duration-150 hover:bg-surface-neutral-bg-main hover:shadow-container-hover'
78
79
  })
79
80
 
80
81
  const disabledClasses = computed(() => {
@@ -86,23 +87,19 @@ const disabledClasses = computed(() => {
86
87
  <template>
87
88
  <div
88
89
  :class="[
89
- 'rounded-xl relative overflow-hidden',
90
+ 'rounded-container relative overflow-hidden',
90
91
  variantClasses,
92
+ borderClasses,
93
+ 'shadow-container',
91
94
  paddingClasses,
92
95
  interactiveClasses,
93
96
  disabledClasses,
94
97
  ]"
95
98
  >
96
- <!-- Hover overlay for interactive cards -->
97
- <div
98
- v-if="interactive && !disabled"
99
- class="absolute inset-0 bg-actions-neutral-hover-overlay rounded-xl opacity-0 hover:opacity-100 transition-opacity duration-150 pointer-events-none"
100
- />
101
-
102
99
  <!-- Selected overlay -->
103
100
  <div
104
101
  v-if="selected"
105
- class="absolute inset-0 bg-actions-primary-idle-alpha-light rounded-xl pointer-events-none"
102
+ class="absolute inset-0 bg-actions-primary-idle-alpha-light rounded-[inherit] pointer-events-none"
106
103
  />
107
104
 
108
105
  <div class="relative z-10 h-full">
@@ -176,7 +176,7 @@ defineExpose({
176
176
  variant="tertiary"
177
177
  color="primary"
178
178
  size="md"
179
- icon="i-ls-chevron-left"
179
+ icon="i-ph-caret-left"
180
180
  label="Previous slide"
181
181
  :disabled="!canScrollPrev"
182
182
  @click="scrollPrev"
@@ -205,7 +205,7 @@ defineExpose({
205
205
  variant="tertiary"
206
206
  color="primary"
207
207
  size="md"
208
- icon="i-ls-chevron-right"
208
+ icon="i-ph-caret-right"
209
209
  label="Next slide"
210
210
  :disabled="!canScrollNext"
211
211
  @click="scrollNext"
@@ -0,0 +1,187 @@
1
+ <script setup lang="ts">
2
+ import { computed, inject, provide, ref } from 'vue'
3
+ import UiInputCheckbox from '../UiInputCheckbox/UiInputCheckbox.vue'
4
+ import UiInputRadio from '../UiInputRadio/UiInputRadio.vue'
5
+ import { RADIO_GROUP_KEY } from '../UiInputRadio/types'
6
+ import UiSwitch from '../UiSwitch/UiSwitch.vue'
7
+ import type { RadioValue } from '../UiInputRadio/types'
8
+ import type { ChoiceControl, ChoiceValue, ControlPosition } from './types'
9
+ import { CHOICE_ROW_KEY } from './types'
10
+ import { useChoiceboxSurface } from '../../composables/useChoiceboxSurface'
11
+
12
+ interface UiChoiceProps {
13
+ /**
14
+ * The control rendered in the row
15
+ */
16
+ control: ChoiceControl
17
+ /**
18
+ * The label text
19
+ */
20
+ label: string
21
+ /**
22
+ * Supporting text under the label, announced with the control
23
+ */
24
+ description?: string
25
+ /**
26
+ * Info tooltip next to the label
27
+ */
28
+ labelInfo?: string
29
+ /**
30
+ * The value this row selects. Required when `control` is `radio`; `null` is a valid value.
31
+ * A radio row goes inside a UiInputRadioGroup, which owns the selection.
32
+ */
33
+ value?: RadioValue
34
+ /**
35
+ * Switch and checkbox: whether the row is on. A radio reads its group instead.
36
+ */
37
+ modelValue?: ChoiceValue
38
+ /**
39
+ * Whether the row is disabled
40
+ * @default false
41
+ */
42
+ disabled?: boolean
43
+ /**
44
+ * Whether the row uses the small height
45
+ * @default false
46
+ */
47
+ compact?: boolean
48
+ /**
49
+ * Which side of the text the control sits on
50
+ * @default 'end'
51
+ */
52
+ controlPosition?: ControlPosition
53
+ }
54
+
55
+ const props = withDefaults(defineProps<UiChoiceProps>(), {
56
+ description: undefined,
57
+ labelInfo: undefined,
58
+ value: undefined,
59
+ modelValue: undefined,
60
+ disabled: false,
61
+ compact: false,
62
+ controlPosition: 'end',
63
+ })
64
+
65
+ const emit = defineEmits<{
66
+ 'update:modelValue': [value: ChoiceValue]
67
+ }>()
68
+
69
+ defineSlots<{
70
+ /** Radio only: extra content under the text, such as a field the option configures */
71
+ content?(): unknown
72
+ /** Radio only: an icon or a logo before the text */
73
+ icon?(): unknown
74
+ }>()
75
+
76
+ const enclosingGroup = inject(RADIO_GROUP_KEY, undefined)
77
+
78
+ if (props.control === 'radio' && props.value === undefined) {
79
+ console.warn(`UiChoice: the radio row "${props.label}" needs a \`value\`: without one it never shows as selected`)
80
+ }
81
+ provide(CHOICE_ROW_KEY, true)
82
+
83
+ // A radio is also disabled by its group, as UiInputRadio decides
84
+ const isDisabled = computed(() => props.disabled || (props.control === 'radio' && (enclosingGroup?.disabled.value ?? false)))
85
+
86
+ const controlRef = ref<HTMLElement | null>(null)
87
+
88
+ const inErroredGroup = computed(() => props.control === 'radio' && (enclosingGroup?.error.value ?? false))
89
+
90
+ const isSelected = computed(() => {
91
+ if (props.control !== 'radio') {
92
+ return props.modelValue === true
93
+ }
94
+ return props.value !== undefined && enclosingGroup?.modelValue.value === props.value
95
+ })
96
+
97
+ // `null` is a valid option value; a missing one falls back to an empty string
98
+ const radioValue = computed(() => props.value === undefined ? '' : props.value)
99
+
100
+ const isSwitch = computed(() => props.control === 'switch')
101
+
102
+ // A switch is a setting, not a choice: on, it keeps the idle surface
103
+ const surfaceClasses = useChoiceboxSurface(() => ({
104
+ control: props.control,
105
+ selected: isSelected.value && !isSwitch.value,
106
+ disabled: isDisabled.value,
107
+ error: inErroredGroup.value,
108
+ }))
109
+
110
+ const rowClasses = computed(() => [
111
+ 'group/option flex items-center w-full text-content-text-md-regular',
112
+ props.compact ? 'min-h-field-sm px-3 py-1' : 'p-3',
113
+ surfaceClasses.value,
114
+ isDisabled.value ? 'cursor-not-allowed' : 'cursor-pointer',
115
+ ])
116
+
117
+ const controlAtEnd = computed(() => props.controlPosition === 'end')
118
+
119
+ // The control handles clicks inside its own box; the row forwards the rest.
120
+ function onRowClick (event: MouseEvent) {
121
+ if (isDisabled.value || controlRef.value?.contains(event.target as Node)) {
122
+ return
123
+ }
124
+ controlRef.value
125
+ ?.querySelector<HTMLElement>('[role="radio"], [role="switch"], input[type="checkbox"]')
126
+ ?.click()
127
+ }
128
+ </script>
129
+
130
+ <template>
131
+ <div
132
+ data-testid="ui-choice"
133
+ :data-state="isSelected ? 'checked' : 'unchecked'"
134
+ :class="rowClasses"
135
+ @click="onRowClick"
136
+ >
137
+ <div
138
+ ref="controlRef"
139
+ :class="controlAtEnd || (control === 'radio' && $slots.content) ? 'w-full' : 'w-fit'"
140
+ >
141
+ <UiInputRadio
142
+ v-if="control === 'radio'"
143
+ :value="radioValue"
144
+ :label="label"
145
+ :description="description"
146
+ :label-info="labelInfo"
147
+ :disabled="disabled"
148
+ :control-position="controlPosition"
149
+ >
150
+ <template
151
+ v-if="$slots.icon"
152
+ #icon
153
+ >
154
+ <slot name="icon" />
155
+ </template>
156
+ <template
157
+ v-if="$slots.content"
158
+ #content
159
+ >
160
+ <slot name="content" />
161
+ </template>
162
+ </UiInputRadio>
163
+ <UiSwitch
164
+ v-else-if="control === 'switch'"
165
+ :model-value="modelValue === true"
166
+ :label="label"
167
+ :description="description"
168
+ :label-info="labelInfo"
169
+ :disabled="disabled"
170
+ :switch-position="controlAtEnd ? 'right' : 'left'"
171
+ :full-width="controlAtEnd"
172
+ @update:model-value="emit('update:modelValue', $event)"
173
+ />
174
+ <UiInputCheckbox
175
+ v-else
176
+ :model-value="modelValue === true"
177
+ :label="label"
178
+ :description="description"
179
+ :label-info="labelInfo"
180
+ :disabled="disabled"
181
+ :control-position="controlPosition"
182
+ :full-width="controlAtEnd"
183
+ @update:model-value="emit('update:modelValue', $event as boolean)"
184
+ />
185
+ </div>
186
+ </div>
187
+ </template>
@@ -0,0 +1,2 @@
1
+ export { default } from './UiChoice.vue'
2
+ export type { ChoiceControl, ChoiceValue, ControlPosition } from './types'
@@ -0,0 +1,11 @@
1
+ import type { InjectionKey } from 'vue'
2
+
3
+ export type ChoiceControl = 'radio' | 'switch' | 'checkbox'
4
+
5
+ export type ChoiceValue = boolean
6
+
7
+ /** Which side of the text a radio, checkbox or switch sits on */
8
+ export type ControlPosition = 'start' | 'end'
9
+
10
+ /** Provided by UiChoice, which draws the option row around the control it wraps */
11
+ export const CHOICE_ROW_KEY: InjectionKey<boolean> = Symbol('ui-choice-row')
@@ -129,7 +129,7 @@ function onPickerChange(value: string): void {
129
129
  <span
130
130
  data-testid="ui-color-field-swatch"
131
131
  aria-hidden="true"
132
- class="block size-full rounded border border-borders-neutral-light"
132
+ class="block size-full rounded-check border border-borders-neutral-light"
133
133
  :style="{ backgroundColor: currentHex }"
134
134
  />
135
135
  </template>
@@ -140,7 +140,7 @@ function onPickerChange(value: string): void {
140
140
  align="start"
141
141
  :side-offset="8"
142
142
  data-colors-semantic="light"
143
- class="border-none shadow-none rounded-2xl!"
143
+ class="border-none shadow-none"
144
144
  @open-auto-focus.prevent
145
145
  >
146
146
  <UiColorPicker