@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,135 @@
1
+ <script setup lang="ts">
2
+ import { computed, inject, ref, unref, useSlots } from 'vue'
3
+ import { PopoverContent, PopoverPortal, PopoverRoot, PopoverTrigger } from 'reka-ui'
4
+ import { useTranslate } from '../../utils/i18n'
5
+ import { UI_TABLE_SIZE_KEY, type UiTableSize } from './context'
6
+
7
+ /**
8
+ * Host for trailing row actions. Place it as the last cell of a row, under a
9
+ * UiTableActionsHeaderCell. The overlay variants reveal the actions over the
10
+ * preceding cells on row hover or keyboard focus; the menu variant renders a
11
+ * persistent trigger instead. Without content it renders an empty cell, for
12
+ * rows that have no actions.
13
+ */
14
+ export interface UiTableActionsCellProps {
15
+ /**
16
+ * `default` masks the cells behind the actions with a row-state backdrop,
17
+ * for bare buttons per the Figma spec. `floating` drops the backdrop for
18
+ * self-contained content that brings its own surface, like a UiActionBar.
19
+ * `menu` tucks the actions behind an always-visible trigger button that
20
+ * opens them in a popover on click — no hover needed, so it also works
21
+ * on touch devices.
22
+ * @default 'default'
23
+ */
24
+ variant?: 'default' | 'floating' | 'menu'
25
+ /**
26
+ * Accessible label of the menu trigger. Defaults to the built-in
27
+ * "More actions" label.
28
+ */
29
+ menuLabel?: string
30
+ /**
31
+ * Keeps the overlay actions shown without row hover or focus, e.g. while
32
+ * a menu they opened is open.
33
+ * @default false
34
+ */
35
+ revealed?: boolean
36
+ }
37
+
38
+ const props = withDefaults(defineProps<UiTableActionsCellProps>(), {
39
+ variant: 'default',
40
+ menuLabel: undefined,
41
+ revealed: false,
42
+ })
43
+
44
+ const slots = useSlots()
45
+
46
+ const translate = useTranslate()
47
+
48
+ const size = inject(UI_TABLE_SIZE_KEY, ref<UiTableSize>('md'))
49
+
50
+ const heightClass = computed(() => (unref(size) === 'lg' ? 'h-16' : 'h-12'))
51
+
52
+ const overlayVisibilityClass = computed(() => (
53
+ props.revealed
54
+ ? 'pointer-events-auto opacity-100'
55
+ : 'pointer-events-none opacity-0 group-hover:pointer-events-auto group-hover:opacity-100 group-focus-within:pointer-events-auto group-focus-within:opacity-100'
56
+ ))
57
+
58
+ const overlayVariantClass = computed(() => (
59
+ props.variant === 'floating'
60
+ ? 'pr-3'
61
+ : 'ui-table__actions--backdrop gap-2 rounded-r-table-row py-1 pl-2 pr-3'
62
+ ))
63
+
64
+ const emptyCellClasses = computed(() => [heightClass.value, props.variant === 'menu' ? 'ui-table__empty-menu-cell' : 'ui-table__zero-width-cell'])
65
+
66
+ const menuOpen = ref(false)
67
+ const menuContent = ref<HTMLElement | null>(null)
68
+
69
+ const menuTriggerLabel = computed(() => props.menuLabel ?? translate('general_table_more-actions'))
70
+
71
+ // Land the opening focus on the container, not the first action: focusing
72
+ // an action would immediately pop its tooltip.
73
+ function onMenuOpenAutoFocus (event: Event) {
74
+ event.preventDefault()
75
+ menuContent.value?.focus()
76
+ }
77
+ </script>
78
+
79
+ <template>
80
+ <td
81
+ v-if="!slots.default"
82
+ class="p-0"
83
+ :class="emptyCellClasses"
84
+ />
85
+ <td
86
+ v-else-if="variant === 'menu'"
87
+ class="ui-table__menu-cell relative px-3 text-right"
88
+ :class="heightClass"
89
+ @click.stop
90
+ @keydown.stop
91
+ >
92
+ <PopoverRoot v-model:open="menuOpen">
93
+ <PopoverTrigger
94
+ :aria-label="menuTriggerLabel"
95
+ class="inline-flex size-button-sm cursor-pointer items-center justify-center rounded-button-sm align-middle text-actions-neutral-idle transition-colors hover:bg-actions-neutral-hover-overlay"
96
+ >
97
+ <span class="i-ph-dots-three size-4 shrink-0" />
98
+ </PopoverTrigger>
99
+ <PopoverPortal>
100
+ <PopoverContent
101
+ side="bottom"
102
+ align="end"
103
+ :side-offset="4"
104
+ class="z-overlay"
105
+ @open-auto-focus="onMenuOpenAutoFocus"
106
+ >
107
+ <!-- Row action menus are one-shot: picking an action closes them. -->
108
+ <div
109
+ ref="menuContent"
110
+ tabindex="-1"
111
+ class="focus-indicator-none outline-none"
112
+ @click="menuOpen = false"
113
+ >
114
+ <slot />
115
+ </div>
116
+ </PopoverContent>
117
+ </PopoverPortal>
118
+ </PopoverRoot>
119
+ </td>
120
+ <td
121
+ v-else
122
+ class="ui-table__actions-cell ui-table__zero-width-cell sticky right-0 w-0 p-0"
123
+ :class="heightClass"
124
+ >
125
+ <div
126
+ class="ui-table__actions absolute inset-y-0 right-0 flex items-center transition-opacity"
127
+ :class="[overlayVisibilityClass, overlayVariantClass]"
128
+ data-testid="ui-table-actions"
129
+ @click.stop
130
+ @keydown.stop
131
+ >
132
+ <slot />
133
+ </div>
134
+ </td>
135
+ </template>
@@ -0,0 +1,19 @@
1
+ <script setup lang="ts">
2
+ import { useTranslate } from '../../utils/i18n'
3
+
4
+ /**
5
+ * Header of the trailing actions column, paired with UiTableActionsCell. The
6
+ * column takes no width of its own: overlay actions sit over the row end and
7
+ * menu triggers size it. It names the column for assistive tech.
8
+ */
9
+ const translate = useTranslate()
10
+ </script>
11
+
12
+ <template>
13
+ <th
14
+ scope="col"
15
+ class="w-0 p-0"
16
+ >
17
+ <span class="sr-only">{{ translate('general_table_more-actions') }}</span>
18
+ </th>
19
+ </template>
@@ -1,5 +1,20 @@
1
+ <script setup lang="ts">
2
+ export interface UiTableBodyProps {
3
+ /**
4
+ * Starts the zebra on the first row, so a body that follows another body
5
+ * with an odd number of rows keeps the stripes alternating.
6
+ * @default false
7
+ */
8
+ zebraOffset?: boolean
9
+ }
10
+
11
+ withDefaults(defineProps<UiTableBodyProps>(), {
12
+ zebraOffset: false,
13
+ })
14
+ </script>
15
+
1
16
  <template>
2
- <tbody>
17
+ <tbody :data-zebra-offset="zebraOffset ? '' : undefined">
3
18
  <slot />
4
19
  </tbody>
5
20
  </template>
@@ -1,26 +1,43 @@
1
1
  <script setup lang="ts">
2
- import { inject, computed, unref, type Ref } from 'vue'
2
+ import { computed, inject, ref, unref } from 'vue'
3
+ import { UI_TABLE_SIZE_KEY, type UiTableSize } from './context'
3
4
 
4
- const variant = inject<Ref<'condensed' | 'large'>>('tableVariant')
5
- const isEven = inject<boolean>('rowIsEven', false)
6
- const hoverEffect = inject<Ref<boolean>>('hoverEffect')
5
+ export interface UiTableCellProps {
6
+ /**
7
+ * Renders an en dash (–), the convention for missing values.
8
+ * @default false
9
+ */
10
+ empty?: boolean
11
+ /**
12
+ * Content alignment. Textual data stays left-aligned; reserve `right` for numeric data.
13
+ * @default 'left'
14
+ */
15
+ align?: 'left' | 'right'
16
+ }
7
17
 
8
- const cellClasses = computed(() => ({
9
- 'h-10': unref(variant) === 'condensed',
10
- 'h-20': unref(variant) === 'large',
11
- 'bg-surface-neutral-alpha-100': isEven,
12
- 'group-hover:bg-surface-neutral-alpha-200': unref(hoverEffect) && isEven,
13
- 'group-hover:bg-surface-neutral-alpha-100': unref(hoverEffect) && !isEven,
14
- 'first:rounded-l-md': true,
15
- 'last:rounded-r-md': true,
16
- }))
18
+ withDefaults(defineProps<UiTableCellProps>(), {
19
+ empty: false,
20
+ align: 'left',
21
+ })
22
+
23
+ const size = inject(UI_TABLE_SIZE_KEY, ref<UiTableSize>('md'))
24
+
25
+ const sizeClasses = computed(() => (
26
+ unref(size) === 'lg'
27
+ ? 'h-16 text-content-text-md-medium'
28
+ : 'h-12 text-content-legends-medium-md'
29
+ ))
17
30
  </script>
18
31
 
19
32
  <template>
20
33
  <td
21
- :class="cellClasses"
22
- class="px-3 overflow-hidden text-ellipsis transition-colors"
34
+ :class="[sizeClasses, align === 'right' ? 'text-right' : 'text-left']"
35
+ class="overflow-hidden px-3 text-ellipsis text-text-neutral-base transition-colors"
23
36
  >
24
- <slot />
37
+ <span
38
+ v-if="empty"
39
+ class="text-text-neutral-secondary"
40
+ >–</span>
41
+ <slot v-else />
25
42
  </td>
26
43
  </template>
@@ -1,12 +1,13 @@
1
1
  <script setup lang="ts">
2
- import { inject, computed, unref, type Ref } from 'vue'
2
+ import { computed, inject, ref, unref } from 'vue'
3
+ import { UI_TABLE_SIZE_KEY, type UiTableSize } from './context'
3
4
 
4
- const variant = inject<Ref<'condensed' | 'large'>>('tableVariant')
5
+ const size = inject(UI_TABLE_SIZE_KEY, ref<UiTableSize>('md'))
5
6
 
6
7
  const headerClasses = computed(() => ({
7
- 'h-10': unref(variant) === 'condensed',
8
- 'h-12': unref(variant) === 'large',
9
- 'sticky top-0 z-20': true,
8
+ 'h-10': unref(size) === 'md',
9
+ 'h-12': unref(size) === 'lg',
10
+ 'sticky top-0 z-20 bg-surface-neutral-bg-main': true,
10
11
  }))
11
12
  </script>
12
13
 
@@ -1,19 +1,71 @@
1
1
  <script setup lang="ts">
2
- import { inject, computed, unref, type Ref } from 'vue'
2
+ import { computed, inject, ref, unref } from 'vue'
3
+ import { UI_TABLE_SIZE_KEY, type UiTableSize } from './context'
3
4
 
4
- const variant = inject<Ref<'condensed' | 'large'>>('tableVariant')
5
+ export type UiTableSortDirection = 'asc' | 'desc' | 'none'
5
6
 
6
- const cellClasses = computed(() => ({
7
- 'h-10': unref(variant) === 'condensed',
8
- 'h-12': unref(variant) === 'large',
9
- }))
7
+ export interface UiTableHeaderCellProps {
8
+ /**
9
+ * Renders the sort affordance and makes the header interactive.
10
+ * Sorting itself stays in the consumer: listen to `sort` and update `sort-direction`.
11
+ * @default false
12
+ */
13
+ sortable?: boolean
14
+ /**
15
+ * Current sort direction, controlled by the consumer.
16
+ * @default 'none'
17
+ */
18
+ sortDirection?: UiTableSortDirection
19
+ /**
20
+ * Content alignment. Textual data stays left-aligned; reserve `right` for numeric data.
21
+ * @default 'left'
22
+ */
23
+ align?: 'left' | 'right'
24
+ }
25
+
26
+ const props = withDefaults(defineProps<UiTableHeaderCellProps>(), {
27
+ sortable: false,
28
+ sortDirection: 'none',
29
+ align: 'left',
30
+ })
31
+
32
+ const emit = defineEmits<{
33
+ sort: []
34
+ }>()
35
+
36
+ const size = inject(UI_TABLE_SIZE_KEY, ref<UiTableSize>('md'))
37
+
38
+ const heightClass = computed(() => (unref(size) === 'lg' ? 'h-12' : 'h-10'))
39
+
40
+ const ariaSort = computed(() => {
41
+ if (!props.sortable) return undefined
42
+ return ({ asc: 'ascending', desc: 'descending', none: 'none' } as const)[props.sortDirection]
43
+ })
10
44
  </script>
11
45
 
12
46
  <template>
13
47
  <th
14
- :class="cellClasses"
15
- class="px-3 py-1 text-left text-content-legends-bold-md text-text-neutral-tertiary"
48
+ scope="col"
49
+ :aria-sort="ariaSort"
50
+ :class="[heightClass, align === 'right' ? 'text-right' : 'text-left', sortable ? 'p-0' : 'px-3 pt-1 pb-2.5']"
51
+ class="align-bottom text-content-legends-bold-md text-text-neutral-tertiary"
16
52
  >
17
- <slot />
53
+ <button
54
+ v-if="sortable"
55
+ type="button"
56
+ class="group/sort flex size-full items-end justify-start gap-2 rounded-row px-3 pt-1 pb-2.5 transition-colors hover:text-text-neutral-base focus-visible:text-text-neutral-base"
57
+ :class="align === 'right' ? 'flex-row-reverse text-right' : 'text-left'"
58
+ @click="emit('sort')"
59
+ >
60
+ <slot />
61
+ <span
62
+ class="size-3 shrink-0 transition-opacity"
63
+ :class="[
64
+ sortDirection === 'asc' ? 'i-ph-caret-up' : 'i-ph-caret-down',
65
+ sortDirection === 'none' ? 'opacity-0 group-hover/sort:opacity-100 group-focus-visible/sort:opacity-100' : 'opacity-100',
66
+ ]"
67
+ />
68
+ </button>
69
+ <slot v-else />
18
70
  </th>
19
71
  </template>
@@ -1,26 +1,62 @@
1
1
  <script setup lang="ts">
2
- import { inject, computed, provide, unref, type Ref } from 'vue'
2
+ import { computed } from 'vue'
3
3
 
4
4
  export interface UiTableRowProps {
5
- isEven?: boolean
5
+ /**
6
+ * Marks the row as selected.
7
+ * @default false
8
+ */
9
+ selected?: boolean
10
+ /**
11
+ * Makes the row interactive: hover feedback, pointer cursor and keyboard focus.
12
+ * @default false
13
+ */
14
+ clickable?: boolean
15
+ /**
16
+ * The row hosts a link stretched over it: positions the row for the link
17
+ * and gives it the hover and focus tone.
18
+ * @default false
19
+ */
20
+ linked?: boolean
21
+ /**
22
+ * Takes part in the table zebra. Turn it off for a row that is not a data
23
+ * row, such as an overlay over the rows: it is neither striped nor counted.
24
+ * @default true
25
+ */
26
+ zebra?: boolean
6
27
  }
7
28
 
8
- const props = defineProps<UiTableRowProps>()
29
+ const props = withDefaults(defineProps<UiTableRowProps>(), {
30
+ selected: false,
31
+ clickable: false,
32
+ linked: false,
33
+ zebra: true,
34
+ })
9
35
 
10
- const variant = inject<Ref<'condensed' | 'large'>>('tableVariant')
36
+ const rowClasses = computed(() => ({ 'cursor-pointer': props.clickable, relative: props.linked }))
11
37
 
12
- provide('rowIsEven', props.isEven)
38
+ const emit = defineEmits<{
39
+ click: [event: MouseEvent | KeyboardEvent]
40
+ }>()
13
41
 
14
- const rowClasses = computed(() => ({
15
- 'h-12': unref(variant) === 'condensed',
16
- 'h-20': unref(variant) === 'large',
17
- }))
42
+ function onActivate (event: MouseEvent | KeyboardEvent) {
43
+ if (!props.clickable) return
44
+ emit('click', event)
45
+ }
18
46
  </script>
19
47
 
20
48
  <template>
21
49
  <tr
22
- :class="rowClasses"
23
50
  class="group"
51
+ :class="rowClasses"
52
+ :data-clickable="clickable ? '' : undefined"
53
+ :data-linked="linked ? '' : undefined"
54
+ :data-selected="selected ? '' : undefined"
55
+ :data-zebra-skip="zebra ? undefined : ''"
56
+ :tabindex="clickable ? 0 : undefined"
57
+ @click="onActivate"
58
+ @keydown.enter.self="onActivate"
59
+ @keydown.space.self.prevent="onActivate"
24
60
  >
25
61
  <slot />
26
62
  </tr>
@@ -0,0 +1,5 @@
1
+ import type { InjectionKey, Ref } from 'vue'
2
+
3
+ export type UiTableSize = 'md' | 'lg'
4
+
5
+ export const UI_TABLE_SIZE_KEY: InjectionKey<Ref<UiTableSize>> = Symbol('ui-table-size')
@@ -1,6 +1,10 @@
1
1
  export { default as UiTable } from './UiTable.vue'
2
2
  export { default as UiTableHeader } from './UiTableHeader.vue'
3
3
  export { default as UiTableHeaderCell } from './UiTableHeaderCell.vue'
4
+ export { default as UiTableActionsHeaderCell } from './UiTableActionsHeaderCell.vue'
4
5
  export { default as UiTableBody } from './UiTableBody.vue'
5
6
  export { default as UiTableRow } from './UiTableRow.vue'
6
7
  export { default as UiTableCell } from './UiTableCell.vue'
8
+ export { default as UiTableActionsCell } from './UiTableActionsCell.vue'
9
+ export type { UiTableSize } from './context'
10
+ export type { UiTableSortDirection } from './UiTableHeaderCell.vue'
@@ -23,22 +23,23 @@ export interface UiTabsProps {
23
23
  modelValue: string
24
24
  /** Size of the tabs */
25
25
  size?: 'sm' | 'md'
26
+ /** Horizontal alignment of the tabs inside the component */
27
+ align?: 'start' | 'center'
26
28
  }
27
29
 
28
30
  const props = withDefaults(defineProps<UiTabsProps>(), {
29
31
  size: 'md',
32
+ align: 'start',
30
33
  })
31
34
 
32
35
  const emit = defineEmits<{
33
36
  'update:modelValue': [value: string]
34
37
  }>()
35
38
 
36
- const slots = defineSlots<{
39
+ defineSlots<{
37
40
  badge?(props: { tab: Tab }): unknown
38
41
  }>()
39
42
 
40
- const hasBadgeSlot = computed(() => !!slots.badge)
41
-
42
43
  const sizeClasses = computed(() => {
43
44
  return {
44
45
  container: 'gap-4',
@@ -124,17 +125,12 @@ function handleKeydown (event: KeyboardEvent, currentValue: string) {
124
125
  }
125
126
 
126
127
  function updateIndicatorPosition () {
127
- if (!tabsContainer.value) return
128
-
129
128
  const activeButton = tabRefs.value.get(props.modelValue)
130
129
  if (!activeButton) return
131
130
 
132
- const containerRect = tabsContainer.value.getBoundingClientRect()
133
- const buttonRect = activeButton.getBoundingClientRect()
134
-
135
131
  indicatorStyle.value = {
136
- transform: `translateX(${buttonRect.left - containerRect.left}px)`,
137
- width: `${buttonRect.width}px`,
132
+ transform: `translateX(${activeButton.offsetLeft}px)`,
133
+ width: `${activeButton.offsetWidth}px`,
138
134
  }
139
135
  }
140
136
 
@@ -152,7 +148,7 @@ onMounted(async () => {
152
148
  updateIndicatorPosition()
153
149
  })
154
150
 
155
- useResizeObserver(tabsContainer, debouncedUpdatePosition)
151
+ useResizeObserver(() => [tabsContainer.value, ...tabRefs.value.values()], debouncedUpdatePosition)
156
152
 
157
153
  onBeforeUnmount(() => {
158
154
  tabRefs.value.clear()
@@ -160,62 +156,61 @@ onBeforeUnmount(() => {
160
156
  </script>
161
157
 
162
158
  <template>
163
- <div class="ui-tabs border-b border-borders-neutral-light relative">
164
- <div
165
- ref="tabsContainer"
166
- role="tablist"
167
- class="flex items-center"
168
- :class="sizeClasses.container"
169
- >
170
- <button
171
- v-for="tab in tabs"
172
- :key="tab.value"
173
- :ref="(el) => setTabRef(el, tab.value)"
174
- type="button"
175
- role="tab"
176
- :aria-selected="isActive(tab.value)"
177
- :aria-disabled="tab.disabled"
178
- :data-testid="tab.testId"
179
- :tabindex="isActive(tab.value) ? 0 : -1"
180
- class="relative outline-none flex items-center gap-2 cursor-pointer font-semibold transition-colors duration-150"
181
- :class="[
182
- sizeClasses.tab,
183
- sizeClasses.text,
184
- {
185
- 'text-actions-primary-idle': isActive(tab.value),
186
- 'text-actions-neutral-idle-alpha-strong hover:text-actions-neutral-idle': !isActive(tab.value) && !tab.disabled,
187
- 'text-actions-neutral-idle-alpha-strong cursor-not-allowed opacity-50': tab.disabled,
188
- },
189
- ]"
190
- :disabled="tab.disabled"
191
- @click="selectTab(tab.value)"
192
- @keydown="handleKeydown($event, tab.value)"
159
+ <div class="ui-tabs border-b border-divider">
160
+ <!-- The 1px bottom overlap lays the indicator over the border -->
161
+ <div class="relative -mb-px overflow-x-auto [scrollbar-width:none]">
162
+ <div
163
+ ref="tabsContainer"
164
+ role="tablist"
165
+ class="flex items-center"
166
+ :class="[sizeClasses.container, { 'justify-center-safe': align === 'center' }]"
193
167
  >
194
- <span
195
- v-if="tab.icon"
196
- :class="tab.icon"
197
- class="size-5"
198
- />
199
- <span>{{ tab.label }}</span>
200
- <div
201
- v-if="hasBadgeSlot"
202
- class="w-4 h-4"
168
+ <button
169
+ v-for="tab in tabs"
170
+ :key="tab.value"
171
+ :ref="(el) => setTabRef(el, tab.value)"
172
+ type="button"
173
+ role="tab"
174
+ :aria-selected="isActive(tab.value)"
175
+ :aria-disabled="tab.disabled"
176
+ :data-testid="tab.testId"
177
+ :tabindex="isActive(tab.value) ? 0 : -1"
178
+ class="relative outline-none flex shrink-0 items-center gap-2 whitespace-nowrap cursor-pointer font-semibold transition-colors duration-150"
179
+ :class="[
180
+ sizeClasses.tab,
181
+ sizeClasses.text,
182
+ {
183
+ 'text-actions-primary-idle': isActive(tab.value),
184
+ 'text-actions-neutral-idle-alpha-strong hover:text-actions-neutral-idle': !isActive(tab.value) && !tab.disabled,
185
+ 'text-actions-neutral-idle-alpha-strong cursor-not-allowed opacity-50': tab.disabled,
186
+ },
187
+ ]"
188
+ :disabled="tab.disabled"
189
+ @click="selectTab(tab.value)"
190
+ @keydown="handleKeydown($event, tab.value)"
203
191
  >
192
+ <span
193
+ v-if="tab.icon"
194
+ :class="tab.icon"
195
+ class="size-5"
196
+ />
197
+ <span>{{ tab.label }}</span>
204
198
  <slot
205
199
  name="badge"
206
200
  :tab="tab"
207
201
  />
208
- </div>
209
- </button>
202
+ </button>
203
+ </div>
204
+
205
+ <!-- Sliding indicator -->
206
+ <div
207
+ data-testid="ui-tabs-indicator"
208
+ class="absolute bottom-0 left-0 h-0.5 bg-actions-primary-idle transition-[transform,width] duration-[250ms] ease-out will-change-[transform,width]"
209
+ :style="{
210
+ transform: indicatorStyle.transform,
211
+ width: indicatorStyle.width,
212
+ }"
213
+ />
210
214
  </div>
211
-
212
- <!-- Sliding indicator -->
213
- <div
214
- class="absolute -bottom-px left-0 h-0.5 bg-actions-primary-idle transition-[transform,width] duration-[250ms] ease-out will-change-[transform,width]"
215
- :style="{
216
- transform: indicatorStyle.transform,
217
- width: indicatorStyle.width,
218
- }"
219
- />
220
215
  </div>
221
216
  </template>
@@ -0,0 +1,28 @@
1
+ export type UiTagSize = 'xxs' | 'xs' | 'sm' | 'md'
2
+
3
+ export type UiTagColor = 'primary' | 'neutral' | 'danger' | 'warning' | 'success' | 'neutral-invert'
4
+
5
+ export type UiTagVariant = 'light' | 'strong'
6
+
7
+ export interface UiTagProps {
8
+ /**
9
+ * Size of the tag
10
+ */
11
+ size?: UiTagSize
12
+ /**
13
+ * Color variant of the tag
14
+ */
15
+ color?: UiTagColor
16
+ /**
17
+ * Variant of the tag
18
+ */
19
+ variant?: UiTagVariant
20
+ /**
21
+ * Label text for the tag
22
+ */
23
+ label?: string
24
+ /**
25
+ * Whether to show hover effects
26
+ */
27
+ withHoverEffect?: boolean
28
+ }