@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
@@ -26,6 +26,7 @@ import {
26
26
  import type { Color } from 'reka-ui'
27
27
  import { UiDropdown, UiDropdownTrigger, UiDropdownContent, UiDropdownItem } from '../UiDropdown'
28
28
  import type { ColorFormat, UiColorPickerPreset, UiColorPickerProps, UiColorPickerSwatchSize } from './types'
29
+ import { useControlShape } from '../../composables/useControlShape'
29
30
 
30
31
  const props = withDefaults(defineProps<UiColorPickerProps>(), {
31
32
  modelValue: undefined,
@@ -54,8 +55,8 @@ const presetsLabel = computed<string | null>(() => {
54
55
  // Preset selector swatch sizes; the selection check icon scales to half the swatch.
55
56
  // maxPerRow is how many swatches (at that size + gap) fit the panel's content width.
56
57
  const SWATCH_SIZE_CLASSES: Record<UiColorPickerSwatchSize, { swatch: string; swatchPickerList: string; indicatorWrapper: string; indicator: string; maxPerRow: number }> = {
57
- sm: { swatch: 'size-6', swatchPickerList: 'gap-2', indicatorWrapper: 'ring-2', indicator: 'h-3 w-3', maxPerRow: 8 },
58
- lg: { swatch: 'size-12', swatchPickerList: 'gap-4', indicatorWrapper: 'ring-4', indicator: 'h-4 w-4', maxPerRow: 4 },
58
+ sm: { swatch: 'size-6', swatchPickerList: 'gap-2', indicatorWrapper: 'ring-2', indicator: 'size-3', maxPerRow: 8 },
59
+ lg: { swatch: 'size-12', swatchPickerList: 'gap-4', indicatorWrapper: 'ring-4', indicator: 'size-5', maxPerRow: 4 },
59
60
  }
60
61
  const swatchSizeClasses = computed(() => SWATCH_SIZE_CLASSES[props.presetConfig?.swatchSize ?? 'lg'])
61
62
 
@@ -124,10 +125,12 @@ const MODE_CHANNELS: Record<Exclude<ColorFormat, 'hex'>, ChannelDef[]> = {
124
125
  ],
125
126
  }
126
127
 
128
+ const fieldShape = useControlShape('field', 'md')
129
+
127
130
  // Shared styling for each bordered value box (the hex field and each channel field).
128
131
  // The mode switcher is a separate bordered box (the dropdown trigger draws its own).
129
132
  const FIELD_BOX_CLASS =
130
- 'flex h-full items-center rounded-lg border border-solid border-borders-neutral-strong bg-actions-neutral-idle-alpha-light transition-all focus-within:border-actions-primary-idle-alpha-strong'
133
+ 'flex h-full items-center border border-solid border-control-field-border bg-control-field-bg transition-all focus-within:bg-control-field-bg-focus has-[input:focus-visible]:focus-ring'
131
134
 
132
135
  // Detect a value's mode. reka represents hex as space 'rgb', so hex must be
133
136
  // matched on the '#' prefix; rgb/hsl/hsb (and hsv→hsb) come from normalizeColor.
@@ -268,14 +271,14 @@ watch(
268
271
  color-space="hsb"
269
272
  x-channel="saturation"
270
273
  y-channel="brightness"
271
- class="relative h-[189px] w-full rounded-md"
274
+ class="relative h-[189px] w-full rounded-row"
272
275
  :class="{ 'cursor-not-allowed': disabled }"
273
276
  @update:color="onColorUpdate"
274
277
  @change-end="onCommit"
275
278
  >
276
279
  <ColorAreaArea
277
280
  :style="style"
278
- class="absolute inset-0 rounded-md"
281
+ class="absolute inset-0 rounded-row"
279
282
  >
280
283
  <ColorAreaThumb class="group size-6 rounded-full border-4 border-actions-neutral-invert-idle transition-shadow hover:cursor-pointer hover:shadow-md">
281
284
  <span class="pointer-events-none absolute -inset-1 rounded-full bg-actions-primary-hover-overlay opacity-0 transition-opacity group-hover:opacity-100" />
@@ -322,13 +325,13 @@ watch(
322
325
  <div
323
326
  v-if="showCustomControls"
324
327
  data-testid="ui-color-picker-field"
325
- class="flex h-10 w-full items-center gap-2"
326
- :class="{ 'cursor-not-allowed opacity-50': disabled }"
328
+ class="flex w-full items-center gap-2"
329
+ :class="[fieldShape.height, { 'cursor-not-allowed opacity-50': disabled }]"
327
330
  >
328
331
  <!-- Mode switcher — its own bordered box; hidden when only one mode is available -->
329
332
  <div
330
333
  v-if="showSwitcher"
331
- class="h-full w-20 shrink-0"
334
+ class="h-full w-21 shrink-0"
332
335
  >
333
336
  <UiDropdown
334
337
  v-model="colorMode"
@@ -357,12 +360,12 @@ watch(
357
360
  :model-value="internalColor"
358
361
  :disabled="disabled"
359
362
  color-space="hsb"
360
- :class="[FIELD_BOX_CLASS, 'min-w-0 flex-1 gap-1.5 px-3']"
363
+ :class="[FIELD_BOX_CLASS, fieldShape.radius, 'min-w-0 flex-1 gap-1.5 px-3']"
361
364
  @update:color="onColorUpdate"
362
365
  >
363
366
  <ColorSwatch
364
367
  :color="internalColor"
365
- class="size-4 shrink-0 rounded-[5px] border border-borders-neutral-light bg-(--reka-color-swatch-color)"
368
+ class="size-4 shrink-0 rounded-check border border-borders-neutral-light bg-(--reka-color-swatch-color)"
366
369
  />
367
370
  <Label
368
371
  :for="fieldId"
@@ -386,7 +389,7 @@ watch(
386
389
  :disabled="disabled"
387
390
  :color-space="colorMode"
388
391
  :channel="ch.channel"
389
- :class="[FIELD_BOX_CLASS, 'min-w-0 flex-1 justify-center px-2']"
392
+ :class="[FIELD_BOX_CLASS, fieldShape.radius, 'min-w-0 flex-1 justify-center px-2']"
390
393
  @update:color="onColorUpdate"
391
394
  >
392
395
  <ColorFieldInput
@@ -456,7 +459,7 @@ watch(
456
459
  class="absolute inset-0 flex items-center justify-center rounded-full bg-actions-neutral-hover-overlay opacity-0 transition-opacity group-hover:opacity-100 group-focus-visible:opacity-100"
457
460
  >
458
461
  <div
459
- class="i-ls-check-circle-fill text-text-neutral-invert-tertiary"
462
+ class="i-ph-check-circle-fill text-text-neutral-invert-tertiary"
460
463
  :class="swatchSizeClasses.indicator"
461
464
  />
462
465
  </span>
@@ -472,7 +475,7 @@ watch(
472
475
  :class="swatchSizeClasses.indicatorWrapper"
473
476
  >
474
477
  <div
475
- class="i-ls-check-circle-fill text-text-neutral-invert-base"
478
+ class="i-ph-check-circle-fill text-text-neutral-invert-base"
476
479
  :class="swatchSizeClasses.indicator"
477
480
  />
478
481
  </span>
@@ -0,0 +1,52 @@
1
+ import type { FieldSize } from '../../composables/useControlShape'
2
+
3
+ export type UiComboboxSize = FieldSize
4
+
5
+ export interface UiComboboxOption {
6
+ value: string
7
+ label: string
8
+ description?: string
9
+ disabled?: boolean
10
+ /** Shown instead of the description, typically why the option is disabled. */
11
+ hint?: string
12
+ }
13
+
14
+ export interface UiComboboxGroup<T extends UiComboboxOption = UiComboboxOption> {
15
+ label: string
16
+ options: T[]
17
+ }
18
+
19
+ /** A selectable row after the options, picked like an option but emitted as `action`. `icon` is a complete icon class such as `i-ph-user-plus`. */
20
+ export interface UiComboboxAction {
21
+ id: string
22
+ label: string
23
+ icon?: string
24
+ disabled?: boolean
25
+ }
26
+
27
+ export interface UiComboboxProps<T extends UiComboboxOption = UiComboboxOption> {
28
+ modelValue?: string
29
+ items?: UiComboboxGroup<T>[]
30
+ /** Selectable rows after the options. */
31
+ actions?: UiComboboxAction[]
32
+ loading?: boolean
33
+ size?: UiComboboxSize
34
+ placeholder?: string
35
+ disabled?: boolean
36
+ label?: string
37
+ ariaLabel?: string
38
+ /** Translated result count, announced through a polite live region while the list is open. */
39
+ resultsLabel?: string
40
+ id?: string
41
+ /** Rows shown before the list scrolls, with a peek of the next one. All rows show when unset. */
42
+ maxVisibleOptions?: number
43
+ /** Options show a checkbox and the list stays open after a pick, so several can be picked in a row. */
44
+ multiple?: boolean
45
+ /** Values of the options shown checked when `multiple` is set. Picking one of them emits `deselect`. */
46
+ selected?: string[]
47
+ /**
48
+ * 'trigger' matches the list to the field. 'compact' caps it at 480px, so on a wide field part of the
49
+ * page behind stays visible, such as a list that updates while picking.
50
+ */
51
+ width?: 'trigger' | 'compact'
52
+ }
@@ -0,0 +1,296 @@
1
+ <script setup lang="ts" generic="T extends UiComboboxOption">
2
+ import {
3
+ ComboboxAnchor,
4
+ ComboboxContent,
5
+ ComboboxGroup,
6
+ ComboboxInput,
7
+ ComboboxItem,
8
+ ComboboxLabel,
9
+ ComboboxPortal,
10
+ ComboboxRoot,
11
+ ComboboxViewport,
12
+ } from 'reka-ui'
13
+ import { computed, nextTick, ref, watch } from 'vue'
14
+ import CheckboxGlyph from '../UiInputCheckbox/CheckboxGlyph.vue'
15
+ import UiFieldWrapper from '../UiFieldWrapper/UiFieldWrapper.vue'
16
+ import { useControlShape } from '../../composables/useControlShape'
17
+ import type { UiComboboxAction, UiComboboxOption, UiComboboxProps, UiComboboxSize } from './UiCombobox.types'
18
+
19
+ const props = withDefaults(defineProps<UiComboboxProps<T>>(), {
20
+ modelValue: '',
21
+ items: () => [],
22
+ actions: () => [],
23
+ loading: false,
24
+ size: 'md',
25
+ placeholder: undefined,
26
+ disabled: false,
27
+ label: undefined,
28
+ ariaLabel: undefined,
29
+ resultsLabel: undefined,
30
+ id: undefined,
31
+ maxVisibleOptions: undefined,
32
+ multiple: false,
33
+ selected: () => [],
34
+ width: 'trigger',
35
+ })
36
+
37
+ const emit = defineEmits<{
38
+ 'update:modelValue': [value: string]
39
+ 'update:open': [open: boolean]
40
+ 'select': [option: T]
41
+ 'deselect': [option: T]
42
+ 'action': [id: string]
43
+ }>()
44
+
45
+ const slots = defineSlots<{
46
+ item?: (props: { option: T }) => unknown
47
+ empty?: () => unknown
48
+ action?: (props: { action: UiComboboxAction }) => unknown
49
+ /** Pinned under the options, outside their scroll: `close` closes the list. Hidden from assistive tech, so keep anything focusable out of the Tab order (`tabindex="-1"`) and redundant with Escape. */
50
+ footer?: (props: { close: () => void }) => unknown
51
+ }>()
52
+
53
+ const FIELD_PADDING: Record<UiComboboxSize, string> = {
54
+ sm: 'px-2 gap-1',
55
+ md: 'px-3 gap-1.5',
56
+ lg: 'px-4 gap-2',
57
+ xl: 'px-4 gap-2',
58
+ }
59
+
60
+ const ITEM_CLASSES = 'focus-indicator-none group/option flex items-center gap-2 min-h-10 px-3 py-1.5 rounded-row cursor-pointer outline-hidden transition-colors duration-150 text-content-text-md-regular text-text-neutral-base data-highlighted:bg-actions-neutral-hover-overlay data-[state=checked]:bg-actions-primary-active-overlay data-disabled:opacity-50 data-disabled:cursor-not-allowed'
61
+
62
+ const shape = useControlShape('field', () => props.size)
63
+ const open = ref(false)
64
+
65
+ const fieldClasses = computed(() => [
66
+ 'relative flex items-center w-full border transition-all duration-150',
67
+ 'bg-control-field-bg border-control-field-border',
68
+ 'focus-within:bg-control-field-bg-focus has-[input:focus-visible]:focus-ring',
69
+ "before:content-[''] before:absolute before:-inset-px before:rounded-[inherit] before:pointer-events-none before:opacity-0 before:transition-opacity before:bg-actions-neutral-hover-overlay [&>*]:relative",
70
+ props.disabled ? 'opacity-50 cursor-not-allowed' : 'hover:not-focus-within:before:opacity-100',
71
+ shape.value.height,
72
+ shape.value.radius,
73
+ FIELD_PADDING[props.size],
74
+ ])
75
+
76
+ const WIDTH_CLASSES = {
77
+ trigger: 'w-(--reka-combobox-trigger-width)',
78
+ compact: 'w-[min(var(--reka-combobox-trigger-width),30rem)]',
79
+ } as const
80
+
81
+ const options = computed(() => props.items.flatMap(group => group.options))
82
+ const hasContent = computed(() => options.value.length > 0 || props.actions.length > 0 || (!!slots.empty && !props.loading))
83
+
84
+ const viewport = ref<{ $el: HTMLElement } | null>(null)
85
+ const viewportMaxHeight = ref<string>()
86
+
87
+ async function fitVisibleOptions () {
88
+ viewportMaxHeight.value = undefined
89
+ if (!open.value || !props.maxVisibleOptions) return
90
+ await nextTick()
91
+ const element = viewport.value?.$el
92
+ const peeked = element?.querySelectorAll('[role=option]')[props.maxVisibleOptions]
93
+ if (!element || !peeked) return
94
+ const row = peeked.getBoundingClientRect()
95
+ viewportMaxHeight.value = `${row.top + row.height / 2 - element.getBoundingClientRect().top + element.scrollTop}px`
96
+ }
97
+
98
+ watch([open, () => props.items, () => props.actions, () => props.maxVisibleOptions], fitVisibleOptions, { flush: 'post' })
99
+
100
+ function onOpenChange (value: boolean) {
101
+ if (open.value === value) return
102
+ open.value = value
103
+ emit('update:open', value)
104
+ }
105
+
106
+ defineExpose({
107
+ /** Closes the list, for a pick that leads somewhere else, such as a dialog. */
108
+ close: () => onOpenChange(false),
109
+ })
110
+
111
+ // Reka hands back the whole checked list; the one value that differs from `selected` is the pick.
112
+ function onMultipleValueChange (values: unknown[]) {
113
+ const action = props.actions.find(candidate => values.includes(candidate))
114
+ if (action) {
115
+ emit('action', action.id)
116
+ emit('update:modelValue', '')
117
+ onOpenChange(false)
118
+ return
119
+ }
120
+ const added = values.find(value => !props.selected.includes(value as string))
121
+ const removed = props.selected.find(value => !values.includes(value))
122
+ const picked = options.value.find(option => option.value === (added ?? removed))
123
+ if (!picked) return
124
+ if (added === undefined) emit('deselect', picked)
125
+ else emit('select', picked)
126
+ }
127
+
128
+ function onValueChange (value: unknown) {
129
+ if (props.multiple) {
130
+ onMultipleValueChange(Array.isArray(value) ? value : [])
131
+ return
132
+ }
133
+ if (props.actions.includes(value as UiComboboxAction)) {
134
+ emit('action', (value as UiComboboxAction).id)
135
+ } else {
136
+ const picked = options.value.find(option => option.value === value)
137
+ if (picked) emit('select', picked)
138
+ }
139
+ emit('update:modelValue', '')
140
+ }
141
+ </script>
142
+
143
+ <template>
144
+ <UiFieldWrapper
145
+ :id="id"
146
+ :label="label"
147
+ >
148
+ <template #default="{ fieldId }">
149
+ <ComboboxRoot
150
+ :model-value="multiple ? selected : null"
151
+ :open="open"
152
+ :multiple="multiple"
153
+ :disabled="disabled"
154
+ ignore-filter
155
+ open-on-click
156
+ :reset-search-term-on-blur="false"
157
+ :reset-search-term-on-select="false"
158
+ @update:model-value="onValueChange"
159
+ @update:open="onOpenChange"
160
+ >
161
+ <ComboboxAnchor :class="fieldClasses">
162
+ <ComboboxInput
163
+ :id="fieldId"
164
+ :model-value="modelValue"
165
+ :placeholder="placeholder"
166
+ :aria-label="ariaLabel"
167
+ :aria-expanded="open && hasContent"
168
+ class="flex-1 min-w-0 bg-transparent outline-none text-content-text-md-regular text-text-neutral-base placeholder:text-control-placeholder disabled:cursor-not-allowed"
169
+ data-testid="ui-combobox-input"
170
+ @update:model-value="emit('update:modelValue', $event)"
171
+ />
172
+ <span
173
+ v-if="loading"
174
+ class="size-4 shrink-0 rounded-full border-2 border-current border-t-transparent animate-spin text-text-neutral-tertiary"
175
+ data-testid="ui-combobox-loader"
176
+ />
177
+ </ComboboxAnchor>
178
+
179
+ <ComboboxPortal>
180
+ <ComboboxContent
181
+ position="popper"
182
+ align="start"
183
+ :side-offset="8"
184
+ data-colors-semantic="light"
185
+ :aria-busy="loading || undefined"
186
+ :hide-when-empty="!hasContent"
187
+ :class="WIDTH_CLASSES[width]"
188
+ class="focus-indicator-none z-overlay flex flex-col p-1 rounded-container border border-container-border bg-surface-neutral-bg-main shadow-shadows-drop-shadow-lg max-w-(--reka-combobox-content-available-width) max-h-(--reka-combobox-content-available-height)"
189
+ >
190
+ <ComboboxViewport
191
+ ref="viewport"
192
+ class="flex flex-col gap-1 min-h-0 max-h-[300px] rounded-row"
193
+ :style="{ maxHeight: viewportMaxHeight }"
194
+ >
195
+ <div
196
+ v-if="slots.empty && options.length === 0 && !loading"
197
+ class="px-3 py-2 text-content-text-md-regular text-text-neutral-secondary"
198
+ data-testid="ui-combobox-empty"
199
+ >
200
+ <slot name="empty" />
201
+ </div>
202
+
203
+ <ComboboxGroup
204
+ v-for="(group, index) in items"
205
+ :key="`${index}-${group.label}`"
206
+ class="flex flex-col gap-1"
207
+ >
208
+ <ComboboxLabel class="px-3 pt-2 pb-1 text-content-legends-bold-md text-text-neutral-tertiary">
209
+ {{ group.label }}
210
+ </ComboboxLabel>
211
+ <ComboboxItem
212
+ v-for="option in group.options"
213
+ :key="option.value"
214
+ :value="option.value"
215
+ :disabled="option.disabled"
216
+ :text-value="option.label"
217
+ :class="ITEM_CLASSES"
218
+ data-testid="ui-combobox-option"
219
+ >
220
+ <CheckboxGlyph
221
+ v-if="multiple"
222
+ :checked="selected.includes(option.value)"
223
+ :disabled="option.disabled"
224
+ />
225
+ <slot
226
+ name="item"
227
+ :option="option"
228
+ >
229
+ <span class="flex flex-col min-w-0 py-1">
230
+ <span class="truncate text-content-text-md-medium">{{ option.label }}</span>
231
+ <span
232
+ v-if="option.hint || option.description"
233
+ class="truncate text-content-legends-medium-md text-text-neutral-secondary"
234
+ >
235
+ {{ option.hint ?? option.description }}
236
+ </span>
237
+ </span>
238
+ </slot>
239
+ </ComboboxItem>
240
+ </ComboboxGroup>
241
+
242
+ <ComboboxItem
243
+ v-for="action in actions"
244
+ :key="action.id"
245
+ :value="action"
246
+ :disabled="action.disabled"
247
+ :text-value="action.label"
248
+ :class="ITEM_CLASSES"
249
+ data-testid="ui-combobox-action"
250
+ >
251
+ <slot
252
+ name="action"
253
+ :action="action"
254
+ >
255
+ <span
256
+ v-if="action.icon"
257
+ class="size-4 shrink-0"
258
+ :class="action.icon"
259
+ aria-hidden="true"
260
+ />
261
+ <span class="truncate">{{ action.label }}</span>
262
+ </slot>
263
+ </ComboboxItem>
264
+ </ComboboxViewport>
265
+
266
+ <!--
267
+ The whole card is the listbox, which may only hold options: the footer is a pointer shortcut,
268
+ hidden from assistive tech, and Escape stays the keyboard way out. pointerdown is prevented so a
269
+ click here keeps the focus in the field.
270
+ -->
271
+ <div
272
+ v-if="slots.footer"
273
+ class="flex items-center gap-2 shrink-0 -mx-1 -mb-1 mt-1 pl-4 pr-2 py-2 border-t border-container-border"
274
+ aria-hidden="true"
275
+ data-testid="ui-combobox-footer"
276
+ @pointerdown.prevent
277
+ >
278
+ <slot
279
+ name="footer"
280
+ :close="() => onOpenChange(false)"
281
+ />
282
+ </div>
283
+ </ComboboxContent>
284
+ </ComboboxPortal>
285
+ </ComboboxRoot>
286
+
287
+ <div
288
+ class="sr-only"
289
+ aria-live="polite"
290
+ data-testid="ui-combobox-live"
291
+ >
292
+ {{ open && resultsLabel ? resultsLabel : '' }}
293
+ </div>
294
+ </template>
295
+ </UiFieldWrapper>
296
+ </template>
@@ -0,0 +1,2 @@
1
+ export { default as UiCombobox } from './UiCombobox.vue'
2
+ export * from './UiCombobox.types'
@@ -0,0 +1,47 @@
1
+ export interface UiDataTableColumn<TData> {
2
+ /**
3
+ * Unique column id. Also names the per-column slots:
4
+ * `#cell-<id>` and `#header-<id>`.
5
+ */
6
+ id: string
7
+ /** Header label. An empty string renders an empty header cell. */
8
+ header: string
9
+ /**
10
+ * Row property rendered by default. Omit for columns rendered
11
+ * entirely through their `#cell-<id>` slot.
12
+ */
13
+ accessorKey?: keyof TData & string
14
+ /**
15
+ * Shows the sort affordance on the header. Sorting logic stays in the
16
+ * consumer: bind `v-model:sorting` and sort/refetch the data yourself.
17
+ * @default false
18
+ */
19
+ sortable?: boolean
20
+ /**
21
+ * Content alignment. Textual data stays left-aligned; reserve `right`
22
+ * for numeric data.
23
+ * @default 'left'
24
+ */
25
+ align?: 'left' | 'right'
26
+ /** Fixed column width as a CSS value (e.g. '160px', '20%'). */
27
+ width?: string
28
+ /**
29
+ * Minimum column width as a CSS length (e.g. '160px'). The column never
30
+ * shrinks below it: when the columns do not fit, the table grows wider
31
+ * than its region, which scrolls horizontally.
32
+ */
33
+ minWidth?: string
34
+ /**
35
+ * Keeps the header and the values of the column on one line: the column
36
+ * grows to fit them instead of wrapping, and the table grows wider than
37
+ * its region when needed, as with `minWidth`.
38
+ * @default false
39
+ */
40
+ nowrap?: boolean
41
+ }
42
+
43
+ export interface UiDataTableSort {
44
+ /** Column id being sorted. */
45
+ id: string
46
+ direction: 'asc' | 'desc'
47
+ }