@livestorm/ui-vue 3.0.0 → 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 (291) hide show
  1. package/README.md +3 -3
  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 -231
  10. package/dist/i18n-B8QOMuFD.mjs +46 -0
  11. package/dist/index.mjs +4 -91
  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 +19 -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/types.d.ts +2 -0
  21. package/dist/types/src/components/UiAvatar/UiAvatar.vue.d.ts +4 -2
  22. package/dist/types/src/components/UiAvatarList/UiAvatarList.vue.d.ts +3 -2
  23. package/dist/types/src/components/UiBanner/UiBanner.vue.d.ts +13 -1
  24. package/dist/types/src/components/UiButton/UiButton.vue.d.ts +95 -35
  25. package/dist/types/src/components/UiButtonGroup/UiButtonGroup.vue.d.ts +8 -2
  26. package/dist/types/src/components/UiButtonGroup/types.d.ts +4 -0
  27. package/dist/types/src/components/UiChoice/UiChoice.vue.d.ts +71 -0
  28. package/dist/types/src/components/UiChoice/index.d.ts +2 -0
  29. package/dist/types/src/components/UiChoice/types.d.ts +7 -0
  30. package/dist/types/src/components/UiColorField/UiColorField.vue.d.ts +1 -1
  31. package/dist/types/src/components/UiColorPicker/UiColorPicker.vue.d.ts +2 -2
  32. package/dist/types/src/components/UiCombobox/UiCombobox.types.d.ts +47 -0
  33. package/dist/types/src/components/UiCombobox/UiCombobox.vue.d.ts +40 -0
  34. package/dist/types/src/components/UiCombobox/index.d.ts +2 -0
  35. package/dist/types/src/components/UiDataTable/UiDataTable.types.d.ts +46 -0
  36. package/dist/types/src/components/UiDataTable/UiDataTable.vue.d.ts +136 -0
  37. package/dist/types/src/components/UiDataTable/index.d.ts +5 -0
  38. package/dist/types/src/components/UiDrawer/UiDrawer.vue.d.ts +28 -0
  39. package/dist/types/src/components/UiDrawer/UiDrawerContent.vue.d.ts +18 -0
  40. package/dist/types/src/components/UiDrawer/UiDrawerTrigger.vue.d.ts +14 -0
  41. package/dist/types/src/components/UiDropdown/DropdownItemCheckbox.vue.d.ts +3 -0
  42. package/dist/types/src/components/UiDropdown/UiDropdownContent.vue.d.ts +10 -0
  43. package/dist/types/src/components/UiDropdown/UiDropdownGroup.vue.d.ts +17 -0
  44. package/dist/types/src/components/UiDropdown/UiDropdownItem.vue.d.ts +8 -5
  45. package/dist/types/src/components/UiDropdown/UiDropdownTrigger.vue.d.ts +21 -5
  46. package/dist/types/src/components/UiDropdown/index.d.ts +1 -0
  47. package/dist/types/src/components/UiEmojiPickerList/UiEmojiPickerList.vue.d.ts +22 -0
  48. package/dist/types/src/components/UiEmptyState/UiEmptyState.vue.d.ts +8 -3
  49. package/dist/types/src/components/UiFieldWrapper/UiFieldWrapper.vue.d.ts +2 -2
  50. package/dist/types/src/components/UiInputCheckbox/CheckboxGlyph.vue.d.ts +17 -0
  51. package/dist/types/src/components/UiInputCheckbox/UiInputCheckbox.vue.d.ts +35 -4
  52. package/dist/types/src/components/UiInputRadio/RadioGlyph.vue.d.ts +19 -0
  53. package/dist/types/src/components/UiInputRadio/UiInputRadio.vue.d.ts +21 -8
  54. package/dist/types/src/components/UiInputRadio/UiInputRadioGroup.vue.d.ts +6 -1
  55. package/dist/types/src/components/UiInputRadio/types.d.ts +1 -1
  56. package/dist/types/src/components/UiInputSelect/UiInputSelect.vue.d.ts +5 -5
  57. package/dist/types/src/components/UiInputTextarea/UiInputTextarea.vue.d.ts +5 -5
  58. package/dist/types/src/components/UiListItem/UiListItem.vue.d.ts +18 -4
  59. package/dist/types/src/components/UiLoader/UiSpinnerIcon.vue.d.ts +3 -0
  60. package/dist/types/src/components/UiMenu/UiMenuContent.vue.d.ts +15 -2
  61. package/dist/types/src/components/UiMenu/UiMenuItem.vue.d.ts +9 -3
  62. package/dist/types/src/components/UiNestedOptions/UiNestedOptions.vue.d.ts +13 -0
  63. package/dist/types/src/components/UiPage/UiPage.vue.d.ts +79 -15
  64. package/dist/types/src/components/UiPagination/UiPagination.vue.d.ts +36 -0
  65. package/dist/types/src/components/UiPagination/index.d.ts +2 -0
  66. package/dist/types/src/components/UiPagination/types.d.ts +4 -0
  67. package/dist/types/src/components/UiPane/UiPane.vue.d.ts +22 -0
  68. package/dist/types/src/components/UiPane/UiPaneContent.vue.d.ts +75 -0
  69. package/dist/types/src/components/UiPane/UiPaneTrigger.vue.d.ts +14 -0
  70. package/dist/types/src/components/UiPane/index.d.ts +5 -0
  71. package/dist/types/src/components/UiRating/UiRating.vue.d.ts +62 -0
  72. package/dist/types/src/components/UiRating/types.d.ts +1 -0
  73. package/dist/types/src/components/UiRoomButton/UiRoomButton.vue.d.ts +5 -3
  74. package/dist/types/src/components/UiRoomCountdown/UiRoomCountdown.vue.d.ts +32 -0
  75. package/dist/types/src/components/UiShell/UiShell.vue.d.ts +3 -0
  76. package/dist/types/src/components/UiSideMenu/UiSideMenu.vue.d.ts +22 -1
  77. package/dist/types/src/components/UiSideMenu/UiSideMenuItemContent.vue.d.ts +2 -2
  78. package/dist/types/src/components/UiSwitch/UiSwitch.vue.d.ts +10 -5
  79. package/dist/types/src/components/UiTable/UiTable.vue.d.ts +13 -4
  80. package/dist/types/src/components/UiTable/UiTableActionsCell.vue.d.ts +49 -0
  81. package/dist/types/src/components/UiTable/UiTableActionsHeaderCell.vue.d.ts +3 -0
  82. package/dist/types/src/components/UiTable/UiTableBody.vue.d.ts +11 -1
  83. package/dist/types/src/components/UiTable/UiTableCell.vue.d.ts +16 -1
  84. package/dist/types/src/components/UiTable/UiTableHeaderCell.vue.d.ts +31 -2
  85. package/dist/types/src/components/UiTable/UiTableRow.vue.d.ts +32 -2
  86. package/dist/types/src/components/UiTable/context.d.ts +3 -0
  87. package/dist/types/src/components/UiTable/index.d.ts +4 -0
  88. package/dist/types/src/components/UiTabs/UiTabs.vue.d.ts +3 -0
  89. package/dist/types/src/components/UiTag/UiTag.types.d.ts +25 -0
  90. package/dist/types/src/components/UiTag/UiTag.vue.d.ts +5 -26
  91. package/dist/types/src/components/UiTag/index.d.ts +2 -1
  92. package/dist/types/src/components/UiTextField/UiTextField.vue.d.ts +10 -5
  93. package/dist/types/src/components/UiTooltip/UiTooltipProvider.vue.d.ts +1 -0
  94. package/dist/types/src/components/UiTooltip/UiTooltipTrigger.vue.d.ts +2 -2
  95. package/dist/types/src/composables/storedThemingApplies.d.ts +17 -0
  96. package/dist/types/src/composables/useButtonStyles.d.ts +1 -0
  97. package/dist/types/src/composables/useChoiceboxSurface.d.ts +11 -0
  98. package/dist/types/src/composables/useContentMode.d.ts +7 -9
  99. package/dist/types/src/composables/useControlModes.d.ts +7 -0
  100. package/dist/types/src/composables/useControlShape.d.ts +24 -0
  101. package/dist/types/src/composables/useFieldFocusEvents.d.ts +12 -0
  102. package/dist/types/src/composables/useIconSize.d.ts +2 -0
  103. package/dist/types/src/composables/usePullGesture.d.ts +42 -0
  104. package/dist/types/src/composables/useThemeAndModes.d.ts +4 -0
  105. package/dist/types/src/theming/colorScale.d.ts +165 -0
  106. package/dist/types/src/theming/legacyColorScale.d.ts +27 -0
  107. package/dist/types/src/theming/presetColors.d.ts +11 -0
  108. package/dist/types/src/theming/primitiveTokens.d.ts +2 -0
  109. package/dist/types/src/utils/effectiveOpacity.d.ts +2 -0
  110. package/dist/types/src/utils/numbers.d.ts +1 -2
  111. package/dist/types/src/utils/tokenColor.d.ts +2 -0
  112. package/dist/ui-vue.css +2 -1
  113. package/dist/utils.mjs +165 -194
  114. package/index.d.ts +18 -0
  115. package/index.js +36 -0
  116. package/package.json +26 -21
  117. package/src/components/Toast/LayoutToasts.vue +19 -11
  118. package/src/components/Toast/ToastMessage.vue +125 -68
  119. package/src/components/Toast/toastDSV2.ts +238 -67
  120. package/src/components/UiActionBar/UiActionBar.vue +4 -3
  121. package/src/components/UiActionBar/UiActionBarItem.vue +9 -6
  122. package/src/components/UiActionBar/types.ts +13 -0
  123. package/src/components/UiAvatar/UiAvatar.vue +8 -2
  124. package/src/components/UiAvatarList/UiAvatarList.vue +51 -20
  125. package/src/components/UiBadge/UiBadge.vue +1 -1
  126. package/src/components/UiBanner/UiBanner.vue +71 -21
  127. package/src/components/UiBreadcrumb/UiBreadcrumb.vue +1 -1
  128. package/src/components/UiButton/UiButton.vue +92 -25
  129. package/src/components/UiButtonGroup/UiButtonGroup.vue +21 -17
  130. package/src/components/UiButtonGroup/UiButtonGroupItem.vue +33 -15
  131. package/src/components/UiButtonGroup/types.ts +19 -0
  132. package/src/components/UiCard/UiCard.vue +20 -23
  133. package/src/components/UiChoice/UiChoice.vue +187 -0
  134. package/src/components/UiChoice/index.ts +2 -0
  135. package/src/components/UiChoice/types.ts +11 -0
  136. package/src/components/UiColorField/UiColorField.vue +2 -2
  137. package/src/components/UiColorPicker/UiColorPicker.vue +11 -8
  138. package/src/components/UiCombobox/UiCombobox.types.ts +52 -0
  139. package/src/components/UiCombobox/UiCombobox.vue +296 -0
  140. package/src/components/UiCombobox/index.ts +2 -0
  141. package/src/components/UiDataTable/UiDataTable.types.ts +47 -0
  142. package/src/components/UiDataTable/UiDataTable.vue +422 -0
  143. package/src/components/UiDataTable/index.ts +12 -0
  144. package/src/components/UiDialog/UiDialogContent.vue +22 -7
  145. package/src/components/UiDrawer/UiDrawer.vue +16 -0
  146. package/src/components/UiDrawer/UiDrawerContent.vue +42 -0
  147. package/src/components/UiDrawer/UiDrawerTrigger.vue +17 -0
  148. package/src/components/UiDropdown/DropdownItemCheckbox.vue +10 -0
  149. package/src/components/UiDropdown/UiDropdownContent.vue +32 -21
  150. package/src/components/UiDropdown/UiDropdownGroup.vue +23 -0
  151. package/src/components/UiDropdown/UiDropdownItem.vue +38 -18
  152. package/src/components/UiDropdown/UiDropdownSeparator.vue +1 -1
  153. package/src/components/UiDropdown/UiDropdownTrigger.vue +138 -43
  154. package/src/components/UiDropdown/index.ts +1 -0
  155. package/src/components/UiEmojiPickerList/UiEmojiPickerList.vue +122 -0
  156. package/src/components/UiEmptyState/UiEmptyState.vue +16 -4
  157. package/src/components/UiFieldWrapper/UiFieldWrapper.vue +9 -3
  158. package/src/components/UiHorizontalSeparator/UiHorizontalSeparator.vue +2 -2
  159. package/src/components/UiInputCheckbox/CheckboxGlyph.vue +78 -0
  160. package/src/components/UiInputCheckbox/UiInputCheckbox.vue +213 -177
  161. package/src/components/UiInputEmoji/UiInputEmoji.vue +18 -95
  162. package/src/components/UiInputRadio/RadioGlyph.vue +45 -0
  163. package/src/components/UiInputRadio/UiInputRadio.vue +177 -169
  164. package/src/components/UiInputRadio/UiInputRadioGroup.vue +15 -5
  165. package/src/components/UiInputRadio/types.ts +1 -2
  166. package/src/components/UiInputSelect/UiInputSelect.vue +9 -7
  167. package/src/components/UiInputTextarea/UiInputTextarea.vue +20 -35
  168. package/src/components/UiLabel/UiLabel.vue +1 -1
  169. package/src/components/UiListItem/UiListItem.vue +55 -9
  170. package/src/components/UiLoader/UiLoader.vue +4 -20
  171. package/src/components/UiLoader/UiSpinnerIcon.vue +21 -0
  172. package/src/components/UiMenu/UiMenuContent.vue +24 -3
  173. package/src/components/UiMenu/UiMenuGroup.vue +1 -1
  174. package/src/components/UiMenu/UiMenuItem.vue +14 -3
  175. package/src/components/UiMenu/UiMenuSubContent.vue +1 -1
  176. package/src/components/UiMenu/UiMenuSubTrigger.vue +1 -1
  177. package/src/components/UiNestedOptions/UiNestedOptions.vue +6 -0
  178. package/src/components/UiPage/UiPage.vue +190 -32
  179. package/src/components/UiPagination/UiPagination.vue +99 -0
  180. package/src/components/UiPagination/index.ts +2 -0
  181. package/src/components/UiPagination/types.ts +28 -0
  182. package/src/components/UiPane/UiPane.vue +20 -0
  183. package/src/components/UiPane/UiPaneContent.vue +232 -0
  184. package/src/components/UiPane/UiPaneTrigger.vue +14 -0
  185. package/src/components/UiPane/index.ts +12 -0
  186. package/src/components/UiPopover/UiPopoverContent.vue +21 -1
  187. package/src/components/UiProgress/UiProgress.vue +2 -2
  188. package/src/components/UiRating/UiRating.vue +258 -0
  189. package/src/components/UiRating/types.ts +1 -0
  190. package/src/components/UiRoomButton/UiRoomButton.vue +10 -41
  191. package/src/components/UiRoomCountdown/UiRoomCountdown.vue +376 -0
  192. package/src/components/UiShell/UiShell.vue +9 -3
  193. package/src/components/UiSideMenu/UiSideMenu.vue +155 -18
  194. package/src/components/UiSideMenu/UiSideMenuItemContent.vue +20 -16
  195. package/src/components/UiStepper/UiStepper.vue +3 -16
  196. package/src/components/UiStepper/UiStepperDescription.vue +1 -13
  197. package/src/components/UiStepper/UiStepperIndicator.vue +11 -48
  198. package/src/components/UiStepper/UiStepperItem.vue +1 -8
  199. package/src/components/UiStepper/UiStepperSeparator.vue +5 -16
  200. package/src/components/UiStepper/UiStepperTitle.vue +1 -10
  201. package/src/components/UiSwitch/UiSwitch.vue +44 -28
  202. package/src/components/UiTable/UiTable.vue +98 -8
  203. package/src/components/UiTable/UiTableActionsCell.vue +135 -0
  204. package/src/components/UiTable/UiTableActionsHeaderCell.vue +19 -0
  205. package/src/components/UiTable/UiTableBody.vue +16 -1
  206. package/src/components/UiTable/UiTableCell.vue +33 -16
  207. package/src/components/UiTable/UiTableHeader.vue +6 -5
  208. package/src/components/UiTable/UiTableHeaderCell.vue +61 -9
  209. package/src/components/UiTable/UiTableRow.vue +46 -10
  210. package/src/components/UiTable/context.ts +5 -0
  211. package/src/components/UiTable/index.ts +4 -0
  212. package/src/components/UiTabs/UiTabs.vue +56 -61
  213. package/src/components/UiTag/UiTag.types.ts +28 -0
  214. package/src/components/UiTag/UiTag.vue +24 -42
  215. package/src/components/UiTag/index.ts +2 -0
  216. package/src/components/UiTextField/UiTextField.vue +21 -36
  217. package/src/components/UiTooltip/UiTooltipContent.vue +1 -1
  218. package/src/components/UiTooltip/UiTooltipProvider.vue +3 -0
  219. package/src/components/UiTooltip/UiTooltipTrigger.vue +16 -1
  220. package/src/composables/storedThemingApplies.ts +19 -0
  221. package/src/composables/useButtonStyles.ts +9 -13
  222. package/src/composables/useChoiceboxSurface.ts +36 -0
  223. package/src/composables/useContentMode.ts +29 -16
  224. package/src/composables/useControlModes.ts +11 -0
  225. package/src/composables/useControlShape.ts +34 -0
  226. package/src/composables/useFieldFocusEvents.ts +30 -0
  227. package/src/composables/useIconSize.ts +15 -0
  228. package/src/composables/usePullGesture.ts +142 -0
  229. package/src/composables/useThemeAndModes.ts +28 -1
  230. package/src/css/body.css +16 -1
  231. package/src/css/fonts.css +39 -5
  232. package/src/global.d.ts +36 -0
  233. package/src/theming/colorScale.ts +173 -0
  234. package/src/theming/legacyColorScale.ts +58 -0
  235. package/src/theming/presetColors.ts +33 -0
  236. package/src/theming/primitiveTokens.ts +71 -0
  237. package/src/utils/effectiveOpacity.ts +8 -0
  238. package/src/utils/i18n.ts +6 -0
  239. package/src/utils/numbers.ts +1 -1
  240. package/src/utils/responsive.d.ts +14 -0
  241. package/src/utils/tokenColor.ts +9 -0
  242. package/dist/UiTimelineItem.vue_vue_type_style_index_0_lang-LpdvGf5X.mjs +0 -6093
  243. package/dist/a11y-BhF_nl7L.mjs +0 -159
  244. package/dist/i18n-Cktw9hIu.mjs +0 -49
  245. package/dist/toastDSV2-wMh-UMzW.mjs +0 -74
  246. package/dist/types/src/components/UiAvatar/index.d.ts +0 -1
  247. package/dist/types/src/components/UiAvatarList/index.d.ts +0 -1
  248. package/dist/types/src/components/UiBadge/index.d.ts +0 -1
  249. package/dist/types/src/components/UiBanner/index.d.ts +0 -2
  250. package/dist/types/src/components/UiButtonGroup/index.d.ts +0 -3
  251. package/dist/types/src/components/UiCarousel/index.d.ts +0 -2
  252. package/dist/types/src/components/UiColorField/index.d.ts +0 -2
  253. package/dist/types/src/components/UiDialog/MarketplaceHeaderExample.vue.d.ts +0 -28
  254. package/dist/types/src/components/UiDialog/index.d.ts +0 -7
  255. package/dist/types/src/components/UiFieldWrapper/index.d.ts +0 -1
  256. package/dist/types/src/components/UiInputCheckbox/index.d.ts +0 -2
  257. package/dist/types/src/components/UiInputEmoji/index.d.ts +0 -1
  258. package/dist/types/src/components/UiInputRadio/index.d.ts +0 -3
  259. package/dist/types/src/components/UiInputSelect/index.d.ts +0 -2
  260. package/dist/types/src/components/UiInputTextarea/index.d.ts +0 -2
  261. package/dist/types/src/components/UiMenu/index.d.ts +0 -10
  262. package/dist/types/src/components/UiProgress/index.d.ts +0 -2
  263. package/dist/types/src/components/UiSwitch/index.d.ts +0 -2
  264. package/dist/types/src/components/UiTabs/index.d.ts +0 -2
  265. package/dist/types/src/components/UiTimeline/index.d.ts +0 -2
  266. package/dist/types/src/components/UiTooltip/index.d.ts +0 -4
  267. package/dist/types/src/mixins/DynamicAction.d.ts +0 -30
  268. package/dist/useThemeAndModes-BzYwSOEv.mjs +0 -108
  269. package/src/components/UiAvatar/index.js +0 -1
  270. package/src/components/UiAvatarList/index.js +0 -1
  271. package/src/components/UiBadge/index.ts +0 -2
  272. package/src/components/UiBanner/index.ts +0 -2
  273. package/src/components/UiButtonGroup/index.ts +0 -3
  274. package/src/components/UiCarousel/index.ts +0 -2
  275. package/src/components/UiColorField/index.ts +0 -2
  276. package/src/components/UiDialog/MarketplaceHeaderExample.vue +0 -217
  277. package/src/components/UiDialog/index.ts +0 -18
  278. package/src/components/UiFieldWrapper/index.ts +0 -1
  279. package/src/components/UiInputCheckbox/index.ts +0 -2
  280. package/src/components/UiInputEmoji/index.ts +0 -1
  281. package/src/components/UiInputRadio/index.ts +0 -3
  282. package/src/components/UiInputSelect/index.ts +0 -2
  283. package/src/components/UiInputTextarea/index.ts +0 -2
  284. package/src/components/UiMenu/index.ts +0 -10
  285. package/src/components/UiProgress/index.ts +0 -2
  286. package/src/components/UiSwitch/index.ts +0 -2
  287. package/src/components/UiTabs/index.ts +0 -5
  288. package/src/components/UiTag/index.js +0 -1
  289. package/src/components/UiTimeline/index.ts +0 -2
  290. package/src/components/UiTooltip/index.js +0 -4
  291. package/src/mixins/DynamicAction.js +0 -61
@@ -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
+ }