@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
@@ -55,13 +55,6 @@ type HeadroomGap = keyof typeof HEADROOM_GAP_PX
55
55
  const DEFAULT_HEADROOM_GAP: HeadroomGap = 'md'
56
56
 
57
57
  const props = withDefaults(defineProps<{
58
- /**
59
- * Extra classes for the inner content `<section>`. Use to override the
60
- * default surface, e.g. `bg-surface-neutral-300` instead of the standard
61
- * `bg-surface-neutral-bg-main`. Appended after the defaults so it wins on
62
- * conflicting utilities.
63
- */
64
- pageContentClasses?: string
65
58
  /**
66
59
  * Page title surfaced as the label of UiShell's fallback mobile menu topbar
67
60
  * (shown on a headerless page that has a side menu). Lets a page name its
@@ -69,14 +62,60 @@ const props = withDefaults(defineProps<{
69
62
  */
70
63
  title?: string
71
64
  /**
72
- * The shape of the page inside the content card.
73
- * - `document` (default): the card scrolls as a single column. The common
74
- * dashboard page — lists, forms, detail views.
65
+ * The shape of the page inside the content card. Padded shapes use the
66
+ * page padding P (16px below md, 24px from md), which the page exposes to
67
+ * its content as `var(--ui-page-padding)`. P applies inside the card only:
68
+ * the page header and the tabs above it keep their own spacing.
69
+ * - `document` (default): the card scrolls as a single column and pads
70
+ * its content with P on every side. Forms, settings, content blocks.
71
+ * - `list`: like `document`, but the content is padded with P at the top
72
+ * only: toolbars, tables and pagination run from card edge to card edge
73
+ * and pad their sides with `--ui-page-inline`. The content is held to the
74
+ * card height, so a child that may shrink (`flex-1 min-h-0`) becomes the
75
+ * scroll region and a table header in it stays in view; anything taller
76
+ * still scrolls the card.
75
77
  * - `app`: the card fills the available height and never scrolls itself;
76
- * the page owns its own scroll regions. For editor-style pages (split
77
- * panes, canvases) that would otherwise opt out of UiPage entirely.
78
+ * the page owns its scroll regions and layout, so the content is not
79
+ * padded. Each region pads itself with `var(--ui-page-padding)`.
80
+ *
81
+ * Edge-to-edge bands (toolbars, pagination) read `--ui-page-inline` for
82
+ * their side padding. UiDataTable pads its scroll region with it, so a
83
+ * wide table scrolls from card edge to card edge. It is set to P on a
84
+ * `list` page only and left unset everywhere else, so a band
85
+ * picks its inset with one class:
86
+ * - `px-(--ui-page-inline)`: P on a list page, 0 elsewhere.
87
+ * - `px-(--ui-page-inline,var(--spacing-space-4))`: P on a list page, the
88
+ * band's own inset elsewhere.
89
+ *
90
+ * A page with a `leftSlot` keeps the split layout insets instead of P: its
91
+ * header slot aligns with the aside, not with the content.
78
92
  */
79
- variant?: 'document' | 'app'
93
+ variant?: 'document' | 'list' | 'app'
94
+ /**
95
+ * Column split when a leftSlot is present: `third` (default) gives the
96
+ * aside 1/3 and the card 2/3; `half` splits them evenly; `fill` lets the
97
+ * aside take all remaining width while the card hugs its content — for
98
+ * app pages whose card is a fixed-width side panel (e.g. the room's
99
+ * interactions sidepane).
100
+ */
101
+ leftSlotRatio?: 'third' | 'half' | 'fill'
102
+ /**
103
+ * How the content card sits in the frame.
104
+ * - `anchored` (default): the dashboard page card — flush to the bottom and
105
+ * right edges, rounded top-left, page-card chrome (level-3 elevation).
106
+ * - `floating`: a detached card with a thin gutter on every side, rounded
107
+ * all around, elevated-card chrome (level-2 elevation + inner glow +
108
+ * container border). The room's panel treatment.
109
+ */
110
+ frame?: 'anchored' | 'floating'
111
+ /**
112
+ * Viewport gate for the leftSlot: `lg` (default) renders the aside only
113
+ * from the lg breakpoint — the dashboard behavior, where the aside is
114
+ * secondary. `none` keeps the aside at every width, for app pages whose
115
+ * aside is primary content (the room's stage, the lobby's session
116
+ * information) and must never unmount with the viewport.
117
+ */
118
+ leftSlotBreakpoint?: 'lg' | 'none'
80
119
  /**
81
120
  * Headroom above the content card, letting the shell background show
82
121
  * through. Sizes map to px via `HEADROOM_GAP_PX`.
@@ -87,28 +126,85 @@ const props = withDefaults(defineProps<{
87
126
  * on a page that would otherwise get the default.
88
127
  */
89
128
  headroomGap?: HeadroomGap
129
+ /**
130
+ * Drops the content padding a `document` or `list` page gets by default, so the
131
+ * page's content reaches the card edges. Only for pages whose layout is
132
+ * edge-to-edge by design: full-bleed bands, or scroll regions that must
133
+ * sit against the card edge. Has no effect on `app` pages, which never get
134
+ * the padding.
135
+ */
136
+ flush?: boolean
137
+ /**
138
+ * The fill of an anchored content card.
139
+ * - `container` (default): the white content surface.
140
+ * - `background`: the grey page background, for screens whose content is
141
+ * already cards or regions, so they do not sit in a second white box.
142
+ * A floating card keeps its elevated fill.
143
+ */
144
+ surface?: 'container' | 'background'
90
145
  }>(), {
91
- pageContentClasses: '',
92
146
  title: undefined,
93
147
  variant: 'document',
148
+ leftSlotRatio: 'third',
149
+ frame: 'anchored',
150
+ leftSlotBreakpoint: 'lg',
94
151
  headroomGap: undefined,
152
+ flush: false,
153
+ surface: 'container',
95
154
  })
96
155
 
97
156
  const slots = defineSlots<{
98
157
  banner?(): Slot
99
158
  pageHeader?(): Slot
100
159
  pageTabs?(): Slot
160
+ /**
161
+ * Summary on the page background, between the page header (and tabs) and
162
+ * the content card, e.g. stat cards. It shares the page header's edges.
163
+ */
164
+ pageSummary?(): Slot
101
165
  leftSlot?(): Slot
102
166
  header?(): Slot
103
167
  footer?(): Slot
104
168
  default?(): Slot
105
169
  }>()
106
170
 
107
- // An `app` page manages its own scrolling, so every level from the page
108
- // content down to the card must stop scrolling and stop growing past the
109
- // viewport — otherwise a split-pane editor gets a second, outer scrollbar.
171
+ // An `app` page manages its own scrolling: the card clips and its row is
172
+ // pinned to the viewport, otherwise a split-pane editor gets a second, outer scrollbar.
110
173
  const isApp = computed(() => props.variant === 'app')
111
174
  const scrollClass = computed(() => (isApp.value ? 'overflow-hidden' : 'overflow-y-auto'))
175
+ const fillsCard = computed(() => isApp.value || props.variant === 'list')
176
+
177
+ // Spelled out as literals: Tailwind only generates classes it can see as
178
+ // complete strings in the source.
179
+ const pageColumnsClass = computed(() => {
180
+ const gated = props.leftSlotBreakpoint === 'lg'
181
+ if (props.leftSlotRatio === 'half') {
182
+ return gated ? 'has-[>:nth-child(2)]:lg:grid-cols-[1fr_1fr]' : 'has-[>:nth-child(2)]:grid-cols-[1fr_1fr]'
183
+ }
184
+ if (props.leftSlotRatio === 'fill') {
185
+ return gated ? 'has-[>:nth-child(2)]:lg:grid-cols-[minmax(0,1fr)_auto]' : 'has-[>:nth-child(2)]:grid-cols-[minmax(0,1fr)_auto]'
186
+ }
187
+ return gated ? 'has-[>:nth-child(2)]:lg:grid-cols-[1fr_2fr]' : 'has-[>:nth-child(2)]:grid-cols-[1fr_2fr]'
188
+ })
189
+
190
+ // Frame treatment. The chrome pairs are exclusive per frame (never merged),
191
+ // so conflicting utilities can't race on stylesheet order.
192
+ const isFloating = computed(() => props.frame === 'floating')
193
+ const frameGutterClass = computed(() => (isFloating.value ? 'p-1 gap-x-1' : 'lg:gap-x-8'))
194
+ const cardRadiusClass = computed(() => (isFloating.value ? 'rounded-container' : 'rounded-tl-container'))
195
+ // Anchored keeps the page-card chrome: shadow-elevation-level-3 keeps
196
+ // drop-shadow-2xl's exact geometry and light-mode colors, but its colors
197
+ // resolve to transparent in dark content mode — the card no longer draws a
198
+ // dark ring on the dark shell. Floating takes the elevated-card treatment
199
+ // from the elevation proposal (level 2 + inner glow + container border).
200
+ const anchoredFillClass = computed(() => (
201
+ props.surface === 'background' ? 'bg-surface-neutral-300' : 'bg-surface-neutral-bg-main'
202
+ ))
203
+ const cardChromeClass = computed(() => (
204
+ isFloating.value
205
+ ? 'bg-elevation-2 shadow-elevation-level-2 inset-shadow-inner-glow border border-container-border'
206
+ : `${anchoredFillClass.value} shadow-elevation-level-3`
207
+ ))
112
208
 
113
209
  // Check for slot presence
114
210
  const bannerSlot = computed(() => !!slots.banner)
@@ -118,13 +214,55 @@ const leftSlot = computed(() => !!slots.leftSlot)
118
214
  const headerSlot = computed(() => !!slots.header)
119
215
  const footerSlot = computed(() => !!slots.footer)
120
216
 
121
- // Row track for the card grid. An `app` page needs its main row to take the
217
+ const PAGE_INSETS = {
218
+ header: 'px-(--ui-page-padding) pt-(--ui-page-padding)',
219
+ headerBottom: 'pb-(--ui-page-padding)',
220
+ content: 'p-(--ui-page-padding)',
221
+ }
222
+ // A split page aligns its header with the aside rather than with the content.
223
+ const SPLIT_INSETS = {
224
+ header: 'px-4 pt-4 lg:px-10 lg:pt-8',
225
+ headerBottom: 'pb-4 lg:pb-8',
226
+ content: 'px-4 py-4 lg:px-10 lg:pt-8 lg:pb-10',
227
+ }
228
+ const isSplitLayout = computed(() => leftSlot.value)
229
+ // The header slot and the content share one side inset so their left edges align.
230
+ const insets = computed(() => (isSplitLayout.value ? SPLIT_INSETS : PAGE_INSETS))
231
+
232
+ const pageInlineClass = computed(() => (props.variant === 'list' ? '[--ui-page-inline:var(--ui-page-padding)]' : ''))
233
+
234
+ const isContentPadded = computed(() => !isApp.value && !props.flush)
235
+ const contentPaddingClass = computed(() => {
236
+ if (!isContentPadded.value) return ''
237
+ return props.variant === 'list' ? 'pt-(--ui-page-padding)' : insets.value.content
238
+ })
239
+ // The padded content's top padding already spaces it from the header.
240
+ const headerBottomPaddingClass = computed(() => (isContentPadded.value ? '' : insets.value.headerBottom))
241
+
242
+ // Who scrolls: the page-content row, or the card inside it?
243
+ // - `app`: neither — the page owns its scroll regions. The row is pinned to the
244
+ // viewport but left unclipped, or it would eat the card's elevation shadow.
245
+ // - leftSlot layout: the row. The aside can be taller than the viewport and
246
+ // scrolls together with the card (historical auth-page behavior). The 1px
247
+ // top padding keeps the card's elevation ring inside the scrollport.
248
+ // - plain `document`: the card. Its row is pinned to the viewport height
249
+ // (minmax(0,1fr)) so the card's own overflow-y-auto engages, and the row
250
+ // stays unclipped — a scrollport would clip the card's elevation shadow
251
+ // at the flush edges.
252
+ const pageContentScrollClass = computed(() => {
253
+ if (isApp.value) return 'overflow-visible grid-rows-[minmax(0,1fr)]'
254
+ return leftSlot.value
255
+ ? 'overflow-y-auto pt-px'
256
+ : 'overflow-visible grid-rows-[minmax(0,1fr)]'
257
+ })
258
+
259
+ // Row track for the card grid. An `app` or `list` page needs its main row to take the
122
260
  // leftover height and be allowed to shrink (minmax(0,1fr)), so nested
123
261
  // overflow containers resolve against a real height instead of growing.
124
262
  // Spelled out as literals: Tailwind only generates classes it can see as
125
263
  // complete strings in the source.
126
264
  const cardRowsClass = computed(() => {
127
- if (!isApp.value) { return headerSlot.value ? 'grid-rows-[min-content]' : '' }
265
+ if (!fillsCard.value) { return headerSlot.value ? 'grid-rows-[min-content]' : '' }
128
266
  if (headerSlot.value && footerSlot.value) { return 'grid-rows-[min-content_minmax(0,1fr)_min-content]' }
129
267
  if (headerSlot.value) { return 'grid-rows-[min-content_minmax(0,1fr)]' }
130
268
  if (footerSlot.value) { return 'grid-rows-[minmax(0,1fr)_min-content]' }
@@ -164,7 +302,9 @@ if (!app) {
164
302
  // Prefer the app-installed $responsive (it may carry custom flags); fall
165
303
  // back to the shared singleton so no plugin registration is required.
166
304
  const responsive = computed(() => app.appContext.config.globalProperties.$responsive ?? useResponsive())
167
- const displayLeftSlot = computed(() => responsive.value.width >= BREAKPOINT_LG)
305
+ const displayLeftSlot = computed(() => (
306
+ props.leftSlotBreakpoint === 'none' || responsive.value.width >= BREAKPOINT_LG
307
+ ))
168
308
 
169
309
  const UiPage = ref<HTMLElement | undefined>()
170
310
  const PageContent = ref<HTMLElement | undefined>()
@@ -179,7 +319,10 @@ const { contentMode } = useContentMode(PageContent, '[data-name="ui-page-content
179
319
  <main
180
320
  ref="UiPage"
181
321
  data-name="ui-page-wrapper"
182
- class="ui-page h-full flex flex-col"
322
+ :class="[
323
+ 'ui-page h-full flex flex-col [--ui-page-padding:var(--spacing-space-4)] md:[--ui-page-padding:var(--spacing-space-6)]',
324
+ pageInlineClass,
325
+ ]"
183
326
  >
184
327
  <section
185
328
  v-if="bannerSlot"
@@ -211,13 +354,21 @@ const { contentMode } = useContentMode(PageContent, '[data-name="ui-page-content
211
354
  </section>
212
355
 
213
356
  <section
214
- ref="PageContent"
357
+ v-if="$slots.pageSummary"
358
+ data-name="pageSummary"
359
+ class="px-4 pb-(--ui-page-padding) md:pl-0 md:pr-8"
360
+ >
361
+ <slot name="pageSummary" />
362
+ </section>
363
+
364
+ <section
215
365
  data-name="pageContent"
216
366
  :class="[
217
- 'page-content flex-1 w-full grid has-[>:nth-child(2)]:lg:grid-cols-[1fr_2fr] lg:gap-x-8 min-h-0',
218
- scrollClass,
367
+ 'page-content flex-1 w-full grid min-h-0',
368
+ frameGutterClass,
369
+ pageColumnsClass,
370
+ pageContentScrollClass,
219
371
  ]"
220
- :data-colors-semantic="contentMode"
221
372
  >
222
373
  <aside
223
374
  v-if="leftSlot && displayLeftSlot"
@@ -227,23 +378,30 @@ const { contentMode } = useContentMode(PageContent, '[data-name="ui-page-content
227
378
  <slot name="leftSlot" />
228
379
  </aside>
229
380
 
381
+ <!-- No overflow-hidden here: the card handles its own content
382
+ clipping via scrollClass, and clipping this wrapper would eat
383
+ the card's elevation shadow on every side but the top. -->
230
384
  <div
231
- class="min-w-0 overflow-hidden rounded-tl-xl"
385
+ ref="PageContent"
386
+ data-name="ui-page-content"
387
+ :class="['min-w-0', cardRadiusClass]"
232
388
  :style="headroomGapStyle"
389
+ :data-colors-semantic="contentMode"
233
390
  >
234
391
  <section
235
392
  :class="[
236
- 'content min-w-0 h-full bg-surface-neutral-bg-main grid shadow-shadows-drop-shadow-2xl rounded-tl-xl',
393
+ 'content min-w-0 h-full grid [view-transition-name:ui-page-card]',
394
+ cardChromeClass,
395
+ cardRadiusClass,
237
396
  scrollClass,
238
397
  cardRowsClass,
239
- props.pageContentClasses,
240
398
  ]"
241
399
  data-name="ui-shell-content"
242
400
  >
243
401
  <section
244
402
  v-if="headerSlot"
245
403
  data-name="header"
246
- class="content-header p-4 sm:p-6"
404
+ :class="['content-header', insets.header, headerBottomPaddingClass]"
247
405
  >
248
406
  <slot name="header" />
249
407
  </section>
@@ -252,10 +410,10 @@ const { contentMode } = useContentMode(PageContent, '[data-name="ui-page-content
252
410
  data-name="main-content"
253
411
  :class="[
254
412
  'route-content w-full min-w-0 flex flex-col',
413
+ contentPaddingClass,
255
414
  // Let the row shrink so an editor's own overflow containers
256
- // resolve against a real height. Scoped to `app` so the 15
257
- // existing document pages keep their current growth behaviour.
258
- isApp ? 'min-h-0' : '',
415
+ // resolve against a real height. Document pages keep growing.
416
+ fillsCard ? 'min-h-0' : '',
259
417
  ]"
260
418
  >
261
419
  <slot>
@@ -0,0 +1,99 @@
1
+ <script setup lang="ts">
2
+ import { computed } from 'vue'
3
+ import { PaginationEllipsis, PaginationList, PaginationListItem, PaginationNext, PaginationPrev, PaginationRoot } from 'reka-ui'
4
+ import { PAGINATION_ACTIVE_CLASSES, PAGINATION_IDLE_CLASSES, PAGINATION_RAIL_CLASSES } from './types'
5
+ import type { UiPaginationColor } from './types'
6
+
7
+ interface UiPaginationProps {
8
+ /** Controlled current page. Bind with `v-model:page`. */
9
+ page?: number
10
+ /** Initial page when uncontrolled. */
11
+ defaultPage?: number
12
+ /** Number of items per page. */
13
+ itemsPerPage?: number
14
+ /** Total number of items across all pages. */
15
+ total: number
16
+ /** Number of sibling pages shown around the current page. */
17
+ siblingCount?: number
18
+ disabled?: boolean
19
+ /** Always show the first and last page, with an ellipsis in between when needed. */
20
+ showEdges?: boolean
21
+ color?: UiPaginationColor
22
+ previousLabel?: string
23
+ nextLabel?: string
24
+ }
25
+
26
+ const props = withDefaults(defineProps<UiPaginationProps>(), {
27
+ page: undefined,
28
+ defaultPage: 1,
29
+ itemsPerPage: 10,
30
+ siblingCount: 1,
31
+ disabled: false,
32
+ showEdges: true,
33
+ color: 'neutral',
34
+ previousLabel: 'Previous page',
35
+ nextLabel: 'Next page',
36
+ })
37
+
38
+ defineEmits<{
39
+ 'update:page': [value: number]
40
+ }>()
41
+
42
+ const idleClasses = computed(() => PAGINATION_IDLE_CLASSES[props.color])
43
+ const activeClasses = computed(() => PAGINATION_ACTIVE_CLASSES[props.color])
44
+ const railClasses = computed(() => PAGINATION_RAIL_CLASSES[props.color])
45
+ </script>
46
+
47
+ <template>
48
+ <PaginationRoot
49
+ :page="page"
50
+ :default-page="defaultPage"
51
+ :items-per-page="itemsPerPage"
52
+ :total="total"
53
+ :sibling-count="siblingCount"
54
+ :disabled="disabled"
55
+ :show-edges="showEdges"
56
+ class="inline-flex items-center gap-2"
57
+ @update:page="$emit('update:page', $event)"
58
+ >
59
+ <PaginationPrev
60
+ class="flex h-10 shrink-0 items-center justify-center rounded-button-lg px-2.5 outline-none transition-colors focus-visible:focus-ring disabled:pointer-events-none disabled:opacity-50"
61
+ :class="idleClasses"
62
+ :aria-label="previousLabel"
63
+ >
64
+ <span class="i-ph-caret-left size-4" />
65
+ </PaginationPrev>
66
+
67
+ <PaginationList
68
+ v-slot="{ items }"
69
+ class="flex h-10 shrink-0 items-center gap-1 rounded-button-lg p-0.5"
70
+ :class="railClasses"
71
+ >
72
+ <template
73
+ v-for="(item, index) in items"
74
+ :key="item.type === 'page' ? `page-${item.value}` : `ellipsis-${index}`"
75
+ >
76
+ <PaginationListItem
77
+ v-if="item.type === 'page'"
78
+ :value="item.value"
79
+ class="flex h-full items-center justify-center rounded-[calc(var(--radius-button-lg)_-_2px)] px-3 text-action-button-md outline-none transition-colors focus-visible:focus-ring"
80
+ :class="[idleClasses, activeClasses]"
81
+ >
82
+ {{ item.value }}
83
+ </PaginationListItem>
84
+ <PaginationEllipsis
85
+ v-else
86
+ class="flex h-full items-center justify-center px-3 text-action-button-md text-actions-neutral-idle"
87
+ />
88
+ </template>
89
+ </PaginationList>
90
+
91
+ <PaginationNext
92
+ class="flex h-10 shrink-0 items-center justify-center rounded-button-lg px-2.5 outline-none transition-colors focus-visible:focus-ring disabled:pointer-events-none disabled:opacity-50"
93
+ :class="idleClasses"
94
+ :aria-label="nextLabel"
95
+ >
96
+ <span class="i-ph-caret-right size-4" />
97
+ </PaginationNext>
98
+ </PaginationRoot>
99
+ </template>
@@ -0,0 +1,2 @@
1
+ export { default as UiPagination } from './UiPagination.vue'
2
+ export type { UiPaginationColor } from './types'
@@ -0,0 +1,28 @@
1
+ export type UiPaginationColor = 'neutral' | 'neutral-invert' | 'primary' | 'success' | 'warning' | 'error'
2
+
3
+ export const PAGINATION_IDLE_CLASSES: Record<UiPaginationColor, string> = {
4
+ 'neutral': 'text-actions-neutral-idle hover:bg-actions-neutral-hover-overlay',
5
+ 'neutral-invert': 'text-actions-neutral-invert-idle-alpha-strong hover:bg-actions-neutral-invert-hover-overlay hover:text-actions-neutral-invert-idle',
6
+ 'primary': 'text-actions-primary-idle-alpha-strong hover:bg-actions-primary-hover-overlay hover:text-actions-primary-idle',
7
+ 'success': 'text-actions-success-idle-alpha-strong hover:bg-actions-success-hover-overlay hover:text-actions-success-idle',
8
+ 'warning': 'text-actions-warning-idle-alpha-strong hover:bg-actions-warning-hover-overlay hover:text-actions-warning-idle',
9
+ 'error': 'text-actions-danger-idle-alpha-strong hover:bg-actions-danger-hover-overlay hover:text-actions-danger-idle',
10
+ }
11
+
12
+ export const PAGINATION_ACTIVE_CLASSES: Record<UiPaginationColor, string> = {
13
+ 'neutral': 'data-[selected=true]:bg-actions-neutral-idle data-[selected=true]:text-actions-neutral-invert-idle data-[selected=true]:hover:bg-actions-neutral-idle',
14
+ 'neutral-invert': 'data-[selected=true]:bg-actions-neutral-invert-idle data-[selected=true]:text-actions-neutral-idle data-[selected=true]:hover:bg-actions-neutral-invert-idle',
15
+ 'primary': 'data-[selected=true]:bg-actions-primary-idle data-[selected=true]:text-actions-neutral-invert-idle data-[selected=true]:hover:bg-actions-primary-idle',
16
+ 'success': 'data-[selected=true]:bg-actions-success-idle data-[selected=true]:text-actions-neutral-invert-idle data-[selected=true]:hover:bg-actions-success-idle',
17
+ 'warning': 'data-[selected=true]:bg-actions-warning-idle data-[selected=true]:text-actions-neutral-invert-idle data-[selected=true]:hover:bg-actions-warning-idle',
18
+ 'error': 'data-[selected=true]:bg-actions-danger-idle data-[selected=true]:text-actions-neutral-invert-idle data-[selected=true]:hover:bg-actions-danger-idle',
19
+ }
20
+
21
+ export const PAGINATION_RAIL_CLASSES: Record<UiPaginationColor, string> = {
22
+ 'neutral': 'bg-actions-neutral-idle-alpha-light',
23
+ 'neutral-invert': 'bg-actions-neutral-invert-idle-alpha-light',
24
+ 'primary': 'bg-actions-primary-idle-alpha-light',
25
+ 'success': 'bg-actions-success-idle-alpha-light',
26
+ 'warning': 'bg-actions-warning-idle-alpha-light',
27
+ 'error': 'bg-actions-danger-idle-alpha-light',
28
+ }
@@ -0,0 +1,20 @@
1
+ <script setup lang="ts">
2
+ import type { DialogRootEmits, DialogRootProps } from 'reka-ui'
3
+ import { DialogRoot, useForwardPropsEmits } from 'reka-ui'
4
+
5
+ // A pane floats above the interface without an overlay, so it is non-modal by default.
6
+ const props = withDefaults(defineProps<DialogRootProps>(), {
7
+ open: undefined,
8
+ defaultOpen: false,
9
+ modal: false,
10
+ })
11
+ const emits = defineEmits<DialogRootEmits>()
12
+
13
+ const forwarded = useForwardPropsEmits(props, emits)
14
+ </script>
15
+
16
+ <template>
17
+ <DialogRoot v-bind="{ ...forwarded, ...$attrs }">
18
+ <slot />
19
+ </DialogRoot>
20
+ </template>