@livestorm/ui-vue 2.0.5 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (302) hide show
  1. package/README.md +9 -6
  2. package/components-vite.js +2 -2
  3. package/dist/UiButton-uyW8EHRJ.mjs +602 -0
  4. package/dist/UiTimelineItem-EiOEi1yF.mjs +7293 -0
  5. package/dist/UiTooltip-DZcPD6_N.mjs +158 -0
  6. package/dist/a11y-CaZxRWzo.mjs +6 -0
  7. package/dist/breakpoints.mjs +4 -9
  8. package/dist/bus.mjs +5 -5
  9. package/dist/components.mjs +236 -222
  10. package/dist/i18n-B8QOMuFD.mjs +46 -0
  11. package/dist/index.mjs +4 -87
  12. package/dist/integrations.mjs +3 -14
  13. package/dist/layouts.mjs +228 -236
  14. package/dist/responsive.mjs +31 -36
  15. package/dist/slot.mjs +11 -17
  16. package/dist/toastDSV2-D3xDZPe5.mjs +105 -0
  17. package/dist/types/index.d.ts +23 -1
  18. package/dist/types/src/components/Toast/ToastMessage.vue.d.ts +17 -7
  19. package/dist/types/src/components/Toast/toastDSV2.d.ts +89 -64
  20. package/dist/types/src/components/UiActionBar/UiActionBar.vue.d.ts +3 -1
  21. package/dist/types/src/components/UiActionBar/UiActionBarItem.vue.d.ts +18 -3
  22. package/dist/types/src/components/UiActionBar/types.d.ts +5 -1
  23. package/dist/types/src/components/UiAvatar/UiAvatar.vue.d.ts +4 -2
  24. package/dist/types/src/components/UiAvatarList/UiAvatarList.vue.d.ts +3 -2
  25. package/dist/types/src/components/UiBanner/UiBanner.vue.d.ts +13 -1
  26. package/dist/types/src/components/UiButton/UiButton.vue.d.ts +102 -38
  27. package/dist/types/src/components/UiButtonGroup/UiButtonGroup.vue.d.ts +8 -2
  28. package/dist/types/src/components/UiButtonGroup/UiButtonGroupItem.vue.d.ts +3 -0
  29. package/dist/types/src/components/UiButtonGroup/types.d.ts +5 -1
  30. package/dist/types/src/components/UiChoice/UiChoice.vue.d.ts +71 -0
  31. package/dist/types/src/components/UiChoice/index.d.ts +2 -0
  32. package/dist/types/src/components/UiChoice/types.d.ts +7 -0
  33. package/dist/types/src/components/UiColorField/UiColorField.vue.d.ts +1 -1
  34. package/dist/types/src/components/UiColorPicker/UiColorPicker.vue.d.ts +2 -2
  35. package/dist/types/src/components/UiCombobox/UiCombobox.types.d.ts +47 -0
  36. package/dist/types/src/components/UiCombobox/UiCombobox.vue.d.ts +40 -0
  37. package/dist/types/src/components/UiCombobox/index.d.ts +2 -0
  38. package/dist/types/src/components/UiDataTable/UiDataTable.types.d.ts +46 -0
  39. package/dist/types/src/components/UiDataTable/UiDataTable.vue.d.ts +136 -0
  40. package/dist/types/src/components/UiDataTable/index.d.ts +5 -0
  41. package/dist/types/src/components/UiDrawer/UiDrawer.vue.d.ts +28 -0
  42. package/dist/types/src/components/UiDrawer/UiDrawerContent.vue.d.ts +18 -0
  43. package/dist/types/src/components/UiDrawer/UiDrawerTrigger.vue.d.ts +14 -0
  44. package/dist/types/src/components/UiDropdown/DropdownItemCheckbox.vue.d.ts +3 -0
  45. package/dist/types/src/components/UiDropdown/UiDropdownContent.vue.d.ts +10 -0
  46. package/dist/types/src/components/UiDropdown/UiDropdownGroup.vue.d.ts +17 -0
  47. package/dist/types/src/components/UiDropdown/UiDropdownItem.vue.d.ts +9 -4
  48. package/dist/types/src/components/UiDropdown/UiDropdownTrigger.vue.d.ts +21 -5
  49. package/dist/types/src/components/UiDropdown/index.d.ts +1 -0
  50. package/dist/types/src/components/UiEmojiPickerList/UiEmojiPickerList.vue.d.ts +22 -0
  51. package/dist/types/src/components/UiEmptyState/UiEmptyState.vue.d.ts +8 -3
  52. package/dist/types/src/components/UiFieldWrapper/UiFieldWrapper.vue.d.ts +2 -2
  53. package/dist/types/src/components/UiInputCheckbox/CheckboxGlyph.vue.d.ts +17 -0
  54. package/dist/types/src/components/UiInputCheckbox/UiInputCheckbox.vue.d.ts +35 -4
  55. package/dist/types/src/components/UiInputEmoji/UiInputEmoji.vue.d.ts +45 -0
  56. package/dist/types/src/components/UiInputRadio/RadioGlyph.vue.d.ts +19 -0
  57. package/dist/types/src/components/UiInputRadio/UiInputRadio.vue.d.ts +80 -0
  58. package/dist/types/src/components/UiInputRadio/UiInputRadioGroup.vue.d.ts +86 -0
  59. package/dist/types/src/components/UiInputRadio/types.d.ts +19 -0
  60. package/dist/types/src/components/UiInputSelect/UiInputSelect.vue.d.ts +5 -5
  61. package/dist/types/src/components/UiInputTextarea/UiInputTextarea.vue.d.ts +5 -5
  62. package/dist/types/src/components/UiListItem/UiListItem.vue.d.ts +18 -4
  63. package/dist/types/src/components/UiLoader/UiLoader.vue.d.ts +6 -5
  64. package/dist/types/src/components/UiLoader/UiSpinnerIcon.vue.d.ts +3 -0
  65. package/dist/types/src/components/UiLogo/UiLogo.vue.d.ts +9 -3
  66. package/dist/types/src/components/UiMenu/UiMenuContent.vue.d.ts +15 -2
  67. package/dist/types/src/components/UiMenu/UiMenuItem.vue.d.ts +9 -3
  68. package/dist/types/src/components/UiNestedOptions/UiNestedOptions.vue.d.ts +13 -0
  69. package/dist/types/src/components/UiPage/UiPage.vue.d.ts +106 -8
  70. package/dist/types/src/components/UiPagination/UiPagination.vue.d.ts +36 -0
  71. package/dist/types/src/components/UiPagination/index.d.ts +2 -0
  72. package/dist/types/src/components/UiPagination/types.d.ts +4 -0
  73. package/dist/types/src/components/UiPane/UiPane.vue.d.ts +22 -0
  74. package/dist/types/src/components/UiPane/UiPaneContent.vue.d.ts +75 -0
  75. package/dist/types/src/components/UiPane/UiPaneTrigger.vue.d.ts +14 -0
  76. package/dist/types/src/components/UiPane/index.d.ts +5 -0
  77. package/dist/types/src/components/UiProgress/UiProgress.vue.d.ts +1 -1
  78. package/dist/types/src/components/UiRating/UiRating.vue.d.ts +62 -0
  79. package/dist/types/src/components/UiRating/types.d.ts +1 -0
  80. package/dist/types/src/components/UiRoomButton/UiRoomButton.vue.d.ts +5 -3
  81. package/dist/types/src/components/UiRoomCountdown/UiRoomCountdown.vue.d.ts +32 -0
  82. package/dist/types/src/components/UiShell/UiShell.vue.d.ts +3 -0
  83. package/dist/types/src/components/UiSideMenu/UiSideMenu.vue.d.ts +22 -1
  84. package/dist/types/src/components/UiSideMenu/UiSideMenuItemContent.vue.d.ts +2 -2
  85. package/dist/types/src/components/UiSwitch/UiSwitch.vue.d.ts +114 -0
  86. package/dist/types/src/components/UiSwitch/types.d.ts +3 -0
  87. package/dist/types/src/components/UiTable/UiTable.vue.d.ts +13 -4
  88. package/dist/types/src/components/UiTable/UiTableActionsCell.vue.d.ts +49 -0
  89. package/dist/types/src/components/UiTable/UiTableActionsHeaderCell.vue.d.ts +3 -0
  90. package/dist/types/src/components/UiTable/UiTableBody.vue.d.ts +11 -1
  91. package/dist/types/src/components/UiTable/UiTableCell.vue.d.ts +16 -1
  92. package/dist/types/src/components/UiTable/UiTableHeaderCell.vue.d.ts +31 -2
  93. package/dist/types/src/components/UiTable/UiTableRow.vue.d.ts +32 -2
  94. package/dist/types/src/components/UiTable/context.d.ts +3 -0
  95. package/dist/types/src/components/UiTable/index.d.ts +4 -0
  96. package/dist/types/src/components/UiTabs/UiTabs.vue.d.ts +8 -2
  97. package/dist/types/src/components/UiTag/UiTag.types.d.ts +25 -0
  98. package/dist/types/src/components/UiTag/UiTag.vue.d.ts +5 -26
  99. package/dist/types/src/components/UiTag/index.d.ts +2 -1
  100. package/dist/types/src/components/UiTextField/UiTextField.vue.d.ts +10 -5
  101. package/dist/types/src/components/UiTooltip/UiTooltipProvider.vue.d.ts +1 -0
  102. package/dist/types/src/components/UiTooltip/UiTooltipTrigger.vue.d.ts +2 -2
  103. package/dist/types/src/composables/storedThemingApplies.d.ts +17 -0
  104. package/dist/types/src/composables/useButtonStyles.d.ts +1 -0
  105. package/dist/types/src/composables/useChoiceboxSurface.d.ts +11 -0
  106. package/dist/types/src/composables/useContentMode.d.ts +23 -0
  107. package/dist/types/src/composables/useControlModes.d.ts +7 -0
  108. package/dist/types/src/composables/useControlShape.d.ts +24 -0
  109. package/dist/types/src/composables/useFieldFocusEvents.d.ts +12 -0
  110. package/dist/types/src/composables/useIconSize.d.ts +13 -0
  111. package/dist/types/src/composables/usePullGesture.d.ts +42 -0
  112. package/dist/types/src/composables/useThemeAndModes.d.ts +4 -0
  113. package/dist/types/src/constants/sizes.d.ts +1 -1
  114. package/dist/types/src/theming/colorScale.d.ts +165 -0
  115. package/dist/types/src/theming/legacyColorScale.d.ts +27 -0
  116. package/dist/types/src/theming/presetColors.d.ts +11 -0
  117. package/dist/types/src/theming/primitiveTokens.d.ts +2 -0
  118. package/dist/types/src/utils/effectiveOpacity.d.ts +2 -0
  119. package/dist/types/src/utils/numbers.d.ts +1 -2
  120. package/dist/types/src/utils/tokenColor.d.ts +2 -0
  121. package/dist/ui-vue.css +2 -1
  122. package/dist/utils.mjs +165 -194
  123. package/index.d.ts +22 -0
  124. package/index.js +44 -0
  125. package/package.json +28 -20
  126. package/src/components/Toast/LayoutToasts.vue +19 -11
  127. package/src/components/Toast/ToastMessage.vue +130 -73
  128. package/src/components/Toast/toastDSV2.ts +238 -67
  129. package/src/components/UiActionBar/UiActionBar.vue +15 -5
  130. package/src/components/UiActionBar/UiActionBarItem.vue +65 -38
  131. package/src/components/UiActionBar/types.ts +16 -1
  132. package/src/components/UiAvatar/UiAvatar.vue +9 -3
  133. package/src/components/UiAvatarList/UiAvatarList.vue +51 -20
  134. package/src/components/UiBadge/UiBadge.vue +1 -1
  135. package/src/components/UiBanner/UiBanner.vue +77 -27
  136. package/src/components/UiBreadcrumb/UiBreadcrumb.vue +1 -1
  137. package/src/components/UiButton/UiButton.vue +96 -29
  138. package/src/components/UiButtonGroup/UiButtonGroup.vue +22 -16
  139. package/src/components/UiButtonGroup/UiButtonGroupItem.vue +44 -14
  140. package/src/components/UiButtonGroup/types.ts +20 -1
  141. package/src/components/UiCard/UiCard.vue +20 -23
  142. package/src/components/UiCarousel/UiCarousel.vue +2 -2
  143. package/src/components/UiChoice/UiChoice.vue +187 -0
  144. package/src/components/UiChoice/index.ts +2 -0
  145. package/src/components/UiChoice/types.ts +11 -0
  146. package/src/components/UiColorField/UiColorField.vue +2 -2
  147. package/src/components/UiColorPicker/UiColorPicker.vue +16 -13
  148. package/src/components/UiCombobox/UiCombobox.types.ts +52 -0
  149. package/src/components/UiCombobox/UiCombobox.vue +296 -0
  150. package/src/components/UiCombobox/index.ts +2 -0
  151. package/src/components/UiDataTable/UiDataTable.types.ts +47 -0
  152. package/src/components/UiDataTable/UiDataTable.vue +422 -0
  153. package/src/components/UiDataTable/index.ts +12 -0
  154. package/src/components/UiDialog/UiDialogClose.vue +1 -1
  155. package/src/components/UiDialog/UiDialogContent.vue +22 -7
  156. package/src/components/UiDrawer/UiDrawer.vue +16 -0
  157. package/src/components/UiDrawer/UiDrawerContent.vue +42 -0
  158. package/src/components/UiDrawer/UiDrawerTrigger.vue +17 -0
  159. package/src/components/UiDropdown/DropdownItemCheckbox.vue +10 -0
  160. package/src/components/UiDropdown/UiDropdownContent.vue +32 -21
  161. package/src/components/UiDropdown/UiDropdownGroup.vue +23 -0
  162. package/src/components/UiDropdown/UiDropdownItem.vue +45 -18
  163. package/src/components/UiDropdown/UiDropdownSeparator.vue +1 -1
  164. package/src/components/UiDropdown/UiDropdownTrigger.vue +139 -45
  165. package/src/components/UiDropdown/index.ts +1 -0
  166. package/src/components/UiEmojiPickerList/UiEmojiPickerList.vue +122 -0
  167. package/src/components/UiEmptyState/UiEmptyState.vue +16 -4
  168. package/src/components/UiFieldWrapper/UiFieldWrapper.vue +10 -4
  169. package/src/components/UiHorizontalSeparator/UiHorizontalSeparator.vue +2 -2
  170. package/src/components/UiInputCheckbox/CheckboxGlyph.vue +78 -0
  171. package/src/components/UiInputCheckbox/UiInputCheckbox.vue +213 -177
  172. package/src/components/UiInputEmoji/UiInputEmoji.vue +96 -0
  173. package/src/components/UiInputRadio/RadioGlyph.vue +45 -0
  174. package/src/components/UiInputRadio/UiInputRadio.vue +382 -0
  175. package/src/components/UiInputRadio/UiInputRadioGroup.vue +166 -0
  176. package/src/components/UiInputRadio/types.ts +24 -0
  177. package/src/components/UiInputSelect/UiInputSelect.vue +9 -7
  178. package/src/components/UiInputTextarea/UiInputTextarea.vue +20 -35
  179. package/src/components/UiLabel/UiLabel.vue +1 -1
  180. package/src/components/UiListItem/UiListItem.vue +55 -9
  181. package/src/components/UiLoader/UiLoader.vue +11 -29
  182. package/src/components/UiLoader/UiSpinnerIcon.vue +21 -0
  183. package/src/components/UiLogo/UiLogo.vue +41 -7
  184. package/src/components/UiMenu/UiMenuContent.vue +24 -3
  185. package/src/components/UiMenu/UiMenuGroup.vue +1 -1
  186. package/src/components/UiMenu/UiMenuItem.vue +14 -3
  187. package/src/components/UiMenu/UiMenuSubContent.vue +1 -1
  188. package/src/components/UiMenu/UiMenuSubTrigger.vue +2 -2
  189. package/src/components/UiNestedOptions/UiNestedOptions.vue +6 -0
  190. package/src/components/UiPage/UiPage.vue +273 -47
  191. package/src/components/UiPageHeader/UiPageHeader.vue +29 -9
  192. package/src/components/UiPagination/UiPagination.vue +99 -0
  193. package/src/components/UiPagination/index.ts +2 -0
  194. package/src/components/UiPagination/types.ts +28 -0
  195. package/src/components/UiPane/UiPane.vue +20 -0
  196. package/src/components/UiPane/UiPaneContent.vue +232 -0
  197. package/src/components/UiPane/UiPaneTrigger.vue +14 -0
  198. package/src/components/UiPane/index.ts +12 -0
  199. package/src/components/UiPopover/UiPopoverContent.vue +21 -1
  200. package/src/components/UiProgress/UiProgress.vue +2 -2
  201. package/src/components/UiRating/UiRating.vue +258 -0
  202. package/src/components/UiRating/types.ts +1 -0
  203. package/src/components/UiRoomButton/UiRoomButton.vue +14 -45
  204. package/src/components/UiRoomCountdown/UiRoomCountdown.vue +376 -0
  205. package/src/components/UiShell/UiShell.vue +10 -4
  206. package/src/components/UiSideMenu/UiSideMenu.vue +158 -18
  207. package/src/components/UiSideMenu/UiSideMenuItemContent.vue +22 -18
  208. package/src/components/UiStepper/UiStepper.vue +3 -16
  209. package/src/components/UiStepper/UiStepperDescription.vue +1 -13
  210. package/src/components/UiStepper/UiStepperIndicator.vue +17 -57
  211. package/src/components/UiStepper/UiStepperItem.vue +1 -8
  212. package/src/components/UiStepper/UiStepperSeparator.vue +5 -16
  213. package/src/components/UiStepper/UiStepperTitle.vue +1 -10
  214. package/src/components/UiSwitch/UiSwitch.vue +375 -0
  215. package/src/components/UiSwitch/types.ts +5 -0
  216. package/src/components/UiTable/UiTable.vue +98 -8
  217. package/src/components/UiTable/UiTableActionsCell.vue +135 -0
  218. package/src/components/UiTable/UiTableActionsHeaderCell.vue +19 -0
  219. package/src/components/UiTable/UiTableBody.vue +16 -1
  220. package/src/components/UiTable/UiTableCell.vue +33 -16
  221. package/src/components/UiTable/UiTableHeader.vue +6 -5
  222. package/src/components/UiTable/UiTableHeaderCell.vue +61 -9
  223. package/src/components/UiTable/UiTableRow.vue +46 -10
  224. package/src/components/UiTable/context.ts +5 -0
  225. package/src/components/UiTable/index.ts +4 -0
  226. package/src/components/UiTabs/UiTabs.vue +61 -63
  227. package/src/components/UiTag/UiTag.types.ts +28 -0
  228. package/src/components/UiTag/UiTag.vue +24 -42
  229. package/src/components/UiTag/index.ts +2 -0
  230. package/src/components/UiTextField/UiTextField.vue +27 -47
  231. package/src/components/UiTimeline/README.md +6 -6
  232. package/src/components/UiTimeline/UiTimelineItem.vue +3 -3
  233. package/src/components/UiTooltip/UiTooltipContent.vue +1 -1
  234. package/src/components/UiTooltip/UiTooltipProvider.vue +3 -0
  235. package/src/components/UiTooltip/UiTooltipTrigger.vue +16 -1
  236. package/src/composables/storedThemingApplies.ts +19 -0
  237. package/src/composables/useButtonStyles.ts +9 -13
  238. package/src/composables/useChoiceboxSurface.ts +36 -0
  239. package/src/composables/useContentMode.ts +66 -0
  240. package/src/composables/useControlModes.ts +11 -0
  241. package/src/composables/useControlShape.ts +34 -0
  242. package/src/composables/useFieldFocusEvents.ts +30 -0
  243. package/src/composables/useIconSize.ts +43 -0
  244. package/src/composables/usePullGesture.ts +142 -0
  245. package/src/composables/useThemeAndModes.ts +28 -1
  246. package/src/constants/sizes.ts +1 -1
  247. package/src/css/body.css +16 -1
  248. package/src/css/fonts.css +39 -5
  249. package/src/global.d.ts +44 -0
  250. package/src/theming/colorScale.ts +173 -0
  251. package/src/theming/legacyColorScale.ts +58 -0
  252. package/src/theming/presetColors.ts +33 -0
  253. package/src/theming/primitiveTokens.ts +71 -0
  254. package/src/utils/effectiveOpacity.ts +8 -0
  255. package/src/utils/i18n.ts +6 -0
  256. package/src/utils/numbers.ts +1 -1
  257. package/src/utils/responsive.d.ts +14 -0
  258. package/src/utils/tokenColor.ts +9 -0
  259. package/dist/UiTimelineItem.vue_vue_type_style_index_0_lang-DJFdCn2R.mjs +0 -5456
  260. package/dist/a11y-BhF_nl7L.mjs +0 -159
  261. package/dist/i18n-Cktw9hIu.mjs +0 -49
  262. package/dist/toastDSV2-wMh-UMzW.mjs +0 -74
  263. package/dist/types/src/components/UiAvatar/index.d.ts +0 -1
  264. package/dist/types/src/components/UiAvatarList/index.d.ts +0 -1
  265. package/dist/types/src/components/UiBadge/index.d.ts +0 -1
  266. package/dist/types/src/components/UiBanner/index.d.ts +0 -2
  267. package/dist/types/src/components/UiButtonGroup/index.d.ts +0 -3
  268. package/dist/types/src/components/UiCarousel/index.d.ts +0 -2
  269. package/dist/types/src/components/UiColorField/index.d.ts +0 -2
  270. package/dist/types/src/components/UiDialog/MarketplaceHeaderExample.vue.d.ts +0 -28
  271. package/dist/types/src/components/UiDialog/index.d.ts +0 -7
  272. package/dist/types/src/components/UiFieldWrapper/index.d.ts +0 -1
  273. package/dist/types/src/components/UiInputCheckbox/index.d.ts +0 -2
  274. package/dist/types/src/components/UiInputSelect/index.d.ts +0 -2
  275. package/dist/types/src/components/UiInputTextarea/index.d.ts +0 -2
  276. package/dist/types/src/components/UiMenu/index.d.ts +0 -10
  277. package/dist/types/src/components/UiProgress/index.d.ts +0 -2
  278. package/dist/types/src/components/UiTabs/index.d.ts +0 -2
  279. package/dist/types/src/components/UiTimeline/index.d.ts +0 -2
  280. package/dist/types/src/components/UiTooltip/index.d.ts +0 -4
  281. package/dist/types/src/mixins/DynamicAction.d.ts +0 -30
  282. package/dist/useThemeAndModes-BzYwSOEv.mjs +0 -108
  283. package/src/components/UiAvatar/index.js +0 -1
  284. package/src/components/UiAvatarList/index.js +0 -1
  285. package/src/components/UiBadge/index.ts +0 -2
  286. package/src/components/UiBanner/index.ts +0 -2
  287. package/src/components/UiButtonGroup/index.ts +0 -3
  288. package/src/components/UiCarousel/index.ts +0 -2
  289. package/src/components/UiColorField/index.ts +0 -2
  290. package/src/components/UiDialog/MarketplaceHeaderExample.vue +0 -217
  291. package/src/components/UiDialog/index.ts +0 -18
  292. package/src/components/UiFieldWrapper/index.ts +0 -1
  293. package/src/components/UiInputCheckbox/index.ts +0 -2
  294. package/src/components/UiInputSelect/index.ts +0 -2
  295. package/src/components/UiInputTextarea/index.ts +0 -2
  296. package/src/components/UiMenu/index.ts +0 -10
  297. package/src/components/UiProgress/index.ts +0 -2
  298. package/src/components/UiTabs/index.ts +0 -5
  299. package/src/components/UiTag/index.js +0 -1
  300. package/src/components/UiTimeline/index.ts +0 -2
  301. package/src/components/UiTooltip/index.js +0 -4
  302. package/src/mixins/DynamicAction.js +0 -61
@@ -1,7 +1,7 @@
1
1
  import { computed, type MaybeRefOrGetter, toValue } from 'vue'
2
2
 
3
3
  // Single source of truth for the action-button visual language (background,
4
- // text, border, hover/active overlays) keyed by `variant` × `color`. Both
4
+ // text, hover/active overlays) keyed by `variant` × `color`. Both
5
5
  // `UiButton` and `UiDropdownTrigger` consume this so a trigger styled as a
6
6
  // tertiary button stays pixel-identical to a real `UiButton` without copying
7
7
  // token names around.
@@ -81,16 +81,6 @@ const TEXT_MAP: Record<ButtonVariant, Record<ButtonColor, string>> = {
81
81
  },
82
82
  }
83
83
 
84
- // Border — only `secondary` draws one.
85
- const BORDER_MAP: Record<ButtonColor, string[]> = {
86
- 'primary': ['border', 'border-borders-primary-strong'],
87
- 'neutral': ['border', 'border-borders-neutral-strong'],
88
- 'neutral-invert': ['border', 'border-borders-neutral-invert-strong'],
89
- 'success': ['border', 'border-borders-success-strong'],
90
- 'warning': ['border', 'border-borders-warning-strong'],
91
- 'error': ['border', 'border-borders-danger-strong'],
92
- }
93
-
94
84
  // Hover overlay tints keyed by `variant-color`, in both the `group-hover:`
95
85
  // flavor (layered button overlay element) and the `before:` flavor
96
86
  // (single-element trigger pseudo). Kept as literals for Tailwind extraction.
@@ -205,9 +195,14 @@ export function useButtonStyles(options: UseButtonStylesOptions) {
205
195
  /** Text color class for the current variant × color. */
206
196
  const textClass = computed(() => TEXT_MAP[variant.value][color.value])
207
197
 
208
- /** Border classes — only `secondary` paints a border. */
198
+ /** Soft border of the secondary fill layer; transparent except in the accessible look. */
209
199
  const borderClasses = computed(() =>
210
- variant.value === 'secondary' ? (BORDER_MAP[color.value] ?? []) : [],
200
+ variant.value === 'secondary' ? ['border', 'border-control-soft-border'] : [],
201
+ )
202
+
203
+ /** Tertiary labels are underlined in the accessible look. */
204
+ const decorationClass = computed(() =>
205
+ variant.value === 'tertiary' ? '[text-decoration-line:var(--control-link-decoration)] underline-offset-3' : '',
211
206
  )
212
207
 
213
208
  /**
@@ -236,6 +231,7 @@ export function useButtonStyles(options: UseButtonStylesOptions) {
236
231
  bgClass,
237
232
  textClass,
238
233
  borderClasses,
234
+ decorationClass,
239
235
  overlayClasses,
240
236
  beforeHoverOverlayClass,
241
237
  }
@@ -0,0 +1,36 @@
1
+ import { computed, type ComputedRef, type MaybeRefOrGetter, toValue } from 'vue'
2
+ import type { ChoiceControl } from '../components/UiChoice/types'
3
+
4
+ interface ChoiceboxState {
5
+ control: ChoiceControl
6
+ selected: boolean
7
+ disabled: boolean
8
+ error?: boolean
9
+ }
10
+
11
+ // Only the row's own control rings the surface: a control in the content slot keeps its own focus
12
+ const FOCUS_RING: Record<ChoiceControl, string> = {
13
+ radio: 'has-[[role=radio]:focus-visible]:focus-ring',
14
+ switch: 'has-[[role=switch]:focus-visible]:focus-ring',
15
+ checkbox: 'has-[[type=checkbox]:focus-visible]:focus-ring',
16
+ }
17
+
18
+ /** Border, fill, radius and focus ring of a UiChoice choicebox */
19
+ export function useChoiceboxSurface (state: MaybeRefOrGetter<ChoiceboxState>): ComputedRef<string[]> {
20
+ return computed(() => {
21
+ const { control, selected, disabled, error } = toValue(state)
22
+ const classes = ['rounded-row border', FOCUS_RING[control]]
23
+
24
+ if (error) {
25
+ classes.push('bg-actions-danger-idle-alpha-light', selected ? 'border-actions-danger-idle' : 'border-control-error-border')
26
+ } else if (disabled) {
27
+ classes.push('bg-control-choice-bg-disabled border-control-choice-border-disabled')
28
+ } else if (selected) {
29
+ classes.push('bg-control-choice-selected-bg border-control-choice-selected-border hover:bg-control-choice-selected-bg-hover')
30
+ } else {
31
+ classes.push('bg-control-choice-bg border-control-choice-border hover:bg-control-choice-bg-hover hover:border-control-choice-border-hover')
32
+ }
33
+
34
+ return classes
35
+ })
36
+ }
@@ -0,0 +1,66 @@
1
+ import { computed, onMounted, onUnmounted, ref, type Ref } from 'vue'
2
+ import useThemeAndModes from './useThemeAndModes'
3
+ import { storedThemingApplies } from './storedThemingApplies'
4
+
5
+ /**
6
+ * Registers an element as a page "content" surface so the stored content mode
7
+ * (driven by the ThemePicker) applies its `data-colors-semantic` — the same
8
+ * behaviour `UiPage` gives its page content, without pulling in the full page
9
+ * layout (and its `<main>`).
10
+ *
11
+ * Content ships light. The stored content mode applies where the picker
12
+ * exists (see storedThemingApplies); everyone else gets the shipped default
13
+ * regardless of what localStorage may hold.
14
+ *
15
+ * The predicate is read in onMounted, not at setup: setup also runs during
16
+ * SSR (no localStorage), and server + client-hydration markup must be
17
+ * identical — stored modes take over right after mount instead.
18
+ *
19
+ * @param element Template ref of the content element to watch.
20
+ * @param selector Unique key for the watch registry — one per logical surface
21
+ * (e.g. `[data-name="ui-page-content"]`).
22
+ * @returns `contentMode`, to bind to the element's `data-colors-semantic`.
23
+ */
24
+ export function useContentMode (
25
+ element: Ref<HTMLElement | undefined>,
26
+ selector: string,
27
+ ) {
28
+ const { addElementToWatch, removeElementToWatch, currentContentMode } = useThemeAndModes()
29
+ const storedApplies = ref(false)
30
+
31
+ // Captured at registration: Vue has already nulled the template ref by the
32
+ // time onUnmounted runs, and unregistering needs the element it registered.
33
+ let registered: HTMLElement | undefined
34
+
35
+ // Always resolve to a concrete mode, never undefined. useThemeAndModes also
36
+ // sets this attribute imperatively; if the binding resolved to undefined,
37
+ // Vue would strip the attribute on the re-render that follows the onMounted
38
+ // flag flip, and the content would silently inherit the *shell* mode from
39
+ // <body> — reading as "content mode resets to dark on every navigation".
40
+ const contentMode = computed(() => (
41
+ storedApplies.value ? currentContentMode.value : 'light'
42
+ ))
43
+
44
+ onMounted(() => {
45
+ storedApplies.value = storedThemingApplies()
46
+
47
+ if (!element.value) { return }
48
+
49
+ registered = element.value
50
+ addElementToWatch('content', {
51
+ selector,
52
+ element: registered,
53
+ ...(storedApplies.value ? {} : { modeOverride: 'light' }),
54
+ })
55
+ })
56
+
57
+ // The registry outlives this component, so a surface that unmounts without
58
+ // this stays referenced and keeps being written to.
59
+ onUnmounted(() => {
60
+ if (registered) {
61
+ removeElementToWatch('content', { selector, element: registered })
62
+ }
63
+ })
64
+
65
+ return { contentMode }
66
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Applies the accessibility look on the app root: `data-accessibility="on"`.
3
+ * The control tokens read this attribute.
4
+ */
5
+ export function applyControlModes (
6
+ { accessibility }: { accessibility: boolean },
7
+ root: HTMLElement = document.body,
8
+ ) {
9
+ if (accessibility) root.setAttribute('data-accessibility', 'on')
10
+ else root.removeAttribute('data-accessibility')
11
+ }
@@ -0,0 +1,34 @@
1
+ import { computed, type ComputedRef, type MaybeRefOrGetter, toValue } from 'vue'
2
+
3
+ // NOTE: every class must be a complete literal string: Tailwind's static
4
+ // extractor can't see interpolated class names.
5
+
6
+ export type FieldSize = 'sm' | 'md' | 'lg' | 'xl'
7
+ type ButtonSize = 'xs' | 'sm' | 'md' | 'lg'
8
+
9
+ interface FieldShape { height: string, radius: string, chevron: string }
10
+
11
+ const FIELD_SHAPES: Record<FieldSize, FieldShape> = {
12
+ sm: { height: 'h-field-sm', radius: 'rounded-field-sm', chevron: 'size-3.5' },
13
+ md: { height: 'h-field-md', radius: 'rounded-field-md', chevron: 'size-4' },
14
+ lg: { height: 'h-field-lg', radius: 'rounded-field-lg', chevron: 'size-5' },
15
+ xl: { height: 'h-field-xl', radius: 'rounded-field-xl', chevron: 'size-6' },
16
+ }
17
+
18
+ const BUTTON_SHAPES: Record<ButtonSize, { height: string, square: string, radius: string }> = {
19
+ xs: { height: 'h-button-xs', square: 'size-button-xs', radius: 'rounded-button-xs' },
20
+ sm: { height: 'h-button-sm', square: 'size-button-sm', radius: 'rounded-button-sm' },
21
+ md: { height: 'h-button-md', square: 'size-button-md', radius: 'rounded-button-md' },
22
+ lg: { height: 'h-button-lg', square: 'size-button-lg', radius: 'rounded-button-lg' },
23
+ }
24
+
25
+ interface ControlShapes {
26
+ field: { size: FieldSize, shape: FieldShape }
27
+ button: { size: ButtonSize, shape: { height: string, square: string, radius: string } }
28
+ }
29
+
30
+ export function useControlShape<K extends keyof ControlShapes> (kind: K, size: MaybeRefOrGetter<ControlShapes[K]['size']>): ComputedRef<ControlShapes[K]['shape']> {
31
+ return computed(() => (kind === 'field'
32
+ ? FIELD_SHAPES[toValue(size) as FieldSize]
33
+ : BUTTON_SHAPES[toValue(size) as ButtonSize]) as ControlShapes[K]['shape'])
34
+ }
@@ -0,0 +1,30 @@
1
+ import { ref } from 'vue'
2
+
3
+ export function useFieldFocusEvents(emit: {
4
+ (event: 'focus', payload: FocusEvent): void
5
+ (event: 'blur', payload: FocusEvent): void
6
+ (event: 'keydown', payload: KeyboardEvent): void
7
+ (event: 'keyup', payload: KeyboardEvent): void
8
+ }) {
9
+ const isFocused = ref(false)
10
+
11
+ function handleFocus(event: FocusEvent) {
12
+ isFocused.value = true
13
+ emit('focus', event)
14
+ }
15
+
16
+ function handleBlur(event: FocusEvent) {
17
+ isFocused.value = false
18
+ emit('blur', event)
19
+ }
20
+
21
+ function handleKeydown(event: KeyboardEvent) {
22
+ emit('keydown', event)
23
+ }
24
+
25
+ function handleKeyup(event: KeyboardEvent) {
26
+ emit('keyup', event)
27
+ }
28
+
29
+ return { isFocused, handleFocus, handleBlur, handleKeydown, handleKeyup }
30
+ }
@@ -0,0 +1,43 @@
1
+ import { computed, type MaybeRefOrGetter, toValue } from 'vue'
2
+
3
+ // Single source of truth for the icon diameter a control renders at, keyed by
4
+ // the control's size name.
5
+ //
6
+ // Every control that puts an icon inside itself consumes this — buttons, button
7
+ // groups, action bar items, dropdown triggers, text fields, stepper indicators,
8
+ // loaders — so a design change to the ladder is one edit here instead of one
9
+ // per component. Components covering only part of the ladder (an action bar
10
+ // stops at md, a text field starts at sm) index the rungs they expose.
11
+ //
12
+ // NOTE: every class must be a complete literal string — Tailwind's static
13
+ // extractor can't see interpolated class names (`size-${n}`).
14
+
15
+ export const ICON_SIZES = {
16
+ xs: 'size-3',
17
+ sm: 'size-4',
18
+ md: 'size-5',
19
+ lg: 'size-6',
20
+ xl: 'size-7',
21
+ } as const
22
+
23
+ export type IconSizeName = keyof typeof ICON_SIZES
24
+
25
+ /** Reactive icon size class for a control's `size`. */
26
+ export function useIconSize(size: MaybeRefOrGetter<IconSizeName>) {
27
+ return computed(() => ICON_SIZES[toValue(size)])
28
+ }
29
+
30
+ // A button's trailing icon (external link, chevron) sits one step below its
31
+ // leading icon so it reads as an affordance, not as content.
32
+ const TRAILING_ICON_SIZES = {
33
+ xs: 'size-2.5',
34
+ sm: 'size-3.5',
35
+ md: 'size-4',
36
+ lg: 'size-5',
37
+ xl: 'size-6',
38
+ } as const
39
+
40
+ /** Reactive trailing icon size class for a control's `size`. */
41
+ export function useTrailingIconSize(size: MaybeRefOrGetter<IconSizeName>) {
42
+ return computed(() => TRAILING_ICON_SIZES[toValue(size)])
43
+ }
@@ -0,0 +1,142 @@
1
+ import { computed, ref, toValue, type MaybeRefOrGetter } from 'vue'
2
+
3
+ interface UsePullGestureOptions {
4
+ /**
5
+ * Pointer travel (px, ascending) at which each stage is reached. An empty
6
+ * list disables the gesture.
7
+ */
8
+ stages: MaybeRefOrGetter<number[]>
9
+ /**
10
+ * Travel (px) up to which the element tracks the pointer 1:1; resistance
11
+ * builds beyond it. Defaults to the last stage.
12
+ */
13
+ resistFrom?: MaybeRefOrGetter<number | undefined>
14
+ /**
15
+ * Visible travel the pulled element tends toward once resisting. Defaults to
16
+ * five times the last stage.
17
+ */
18
+ maxOffset?: MaybeRefOrGetter<number | undefined>
19
+ /** Called on release when at least one stage was reached. */
20
+ onRelease?: (stage: number) => void
21
+ }
22
+
23
+ interface Point {
24
+ x: number
25
+ y: number
26
+ }
27
+
28
+ const REST: Point = { x: 0, y: 0 }
29
+
30
+ // Travel (px) under which a press still counts as a click, not a drag.
31
+ const DRAG_SLOP = 4
32
+
33
+ // Detent at each stage: the element holds still for this much travel past
34
+ // the threshold, then catches up at double speed over the same distance.
35
+ const DETENT = 8
36
+
37
+ function detentLag (distance: number, stages: number[]) {
38
+ return stages.reduce(
39
+ (lag, threshold) => lag + Math.max(0, DETENT - Math.abs(distance - threshold - DETENT)),
40
+ 0,
41
+ )
42
+ }
43
+
44
+ // Free travel up to `free`, then an iOS-style rubber band lets the visible
45
+ // travel approach `max` asymptotically.
46
+ function resist (distance: number, free: number, max: number) {
47
+ if (distance <= free) return distance
48
+ const tail = max - free
49
+ if (tail <= 0) return free
50
+ const beyond = distance - free
51
+ return free + (tail * beyond) / (beyond + tail)
52
+ }
53
+
54
+ /**
55
+ * Pull gesture in any direction with staged thresholds: the element follows
56
+ * the pointer through the stages and resists beyond the last one. Bind the
57
+ * returned pointer handlers to the pulled element and apply `offset` as its
58
+ * translation; on release the state snaps back to rest.
59
+ */
60
+ export function usePullGesture (options: UsePullGestureOptions) {
61
+ const isPulling = ref(false)
62
+ const delta = ref<Point>(REST)
63
+ let pointerId: number | null = null
64
+ let start: Point = REST
65
+ let didDrag = false
66
+
67
+ const stages = computed(() => toValue(options.stages))
68
+ const enabled = computed(() => stages.value.length > 0)
69
+ const lastStage = computed(() => stages.value[stages.value.length - 1] ?? 0)
70
+ const resistFrom = computed(() => toValue(options.resistFrom) ?? lastStage.value)
71
+ const maxOffset = computed(() => toValue(options.maxOffset) ?? lastStage.value * 5)
72
+ const distance = computed(() => Math.hypot(delta.value.x, delta.value.y))
73
+ const stage = computed(() => stages.value.filter(threshold => distance.value >= threshold).length)
74
+ const offset = computed<Point>(() => {
75
+ if (distance.value === 0) return REST
76
+ const eased = distance.value - detentLag(distance.value, stages.value)
77
+ const ratio = resist(eased, resistFrom.value, maxOffset.value) / distance.value
78
+ return { x: delta.value.x * ratio, y: delta.value.y * ratio }
79
+ })
80
+
81
+ function reset () {
82
+ isPulling.value = false
83
+ delta.value = REST
84
+ pointerId = null
85
+ }
86
+
87
+ function onPointerDown (event: PointerEvent) {
88
+ if (!enabled.value || !event.isPrimary || event.button !== 0) return
89
+ pointerId = event.pointerId
90
+ start = { x: event.clientX, y: event.clientY }
91
+ didDrag = false
92
+ isPulling.value = true
93
+ // Keep receiving move/up events once the pointer leaves the element.
94
+ ;(event.currentTarget as Element | null)?.setPointerCapture?.(event.pointerId)
95
+ }
96
+
97
+ function track (event: PointerEvent) {
98
+ delta.value = { x: event.clientX - start.x, y: event.clientY - start.y }
99
+ if (distance.value > DRAG_SLOP) didDrag = true
100
+ }
101
+
102
+ function onPointerMove (event: PointerEvent) {
103
+ if (!isPulling.value || event.pointerId !== pointerId) return
104
+ track(event)
105
+ }
106
+
107
+ function onPointerUp (event: PointerEvent) {
108
+ if (!isPulling.value || event.pointerId !== pointerId) return
109
+ // A fast drag can end past the last delivered move: judge the release position.
110
+ track(event)
111
+ const reached = stage.value
112
+ reset()
113
+ if (reached > 0) options.onRelease?.(reached)
114
+ }
115
+
116
+ function onPointerCancel (event: PointerEvent) {
117
+ if (event.pointerId !== pointerId) return
118
+ reset()
119
+ }
120
+
121
+ /**
122
+ * Whether the press that just ended was a drag. Lets a click handler ignore
123
+ * the click the browser fires after a drag; the next press starts clean.
124
+ */
125
+ function consumeDrag () {
126
+ const wasDrag = didDrag
127
+ didDrag = false
128
+ return wasDrag
129
+ }
130
+
131
+ return {
132
+ enabled,
133
+ isPulling,
134
+ stage,
135
+ offset,
136
+ onPointerDown,
137
+ onPointerMove,
138
+ onPointerUp,
139
+ onPointerCancel,
140
+ consumeDrag,
141
+ }
142
+ }
@@ -1,4 +1,5 @@
1
1
  import { useStorage } from '@vueuse/core'
2
+ import { storedThemingApplies } from './storedThemingApplies'
2
3
  import { computed, getCurrentInstance, ref, watch } from 'vue'
3
4
  import {
4
5
  THEME_LIST,
@@ -124,10 +125,35 @@ export default function useThemeAndModes (
124
125
  list.value.set(selector, { element, modeOverride })
125
126
  }
126
127
 
128
+ /**
129
+ * Drops an element from the watch list. The registries outlive every
130
+ * component that registers with them, so an element that unmounts without
131
+ * this stays referenced — and keeps being written to — for the life of the
132
+ * page.
133
+ *
134
+ * The element is part of the descriptor because a selector is a surface, not
135
+ * an instance: where two instances of one surface overlap (a route leaving
136
+ * while its replacement mounts), the leaving one must not drop the entry the
137
+ * incoming one just registered.
138
+ * @param listType Which registry the element was added to.
139
+ * @param descriptor The selector it was registered under, and the element itself.
140
+ * @returns void
141
+ */
142
+ function removeElementToWatch (
143
+ listType: 'mode' | 'content',
144
+ { selector, element }: { selector: string, element: HTMLElement }
145
+ ) {
146
+ const list = listType === 'mode' ? modeTemplateRefsToWatch : contentTemplateRefsToWatch
147
+ if (list.value.get(selector)?.element === element) {
148
+ list.value.delete(selector)
149
+ }
150
+ }
151
+
127
152
  return {
128
153
  initOnAppMounted,
129
154
  registerWatchers,
130
155
  addElementToWatch,
156
+ removeElementToWatch,
131
157
  updateContentMode,
132
158
 
133
159
  updateTheme,
@@ -214,7 +240,8 @@ const DYNAMIC_TOKENS_STORAGE_KEY = 'customThemeTokens'
214
240
  */
215
241
  function applyStoredDynamicTokens () {
216
242
  try {
217
- if (localStorage.getItem('ls-internal-theming') !== 'true') return
243
+ // Seed tokens are picker output — same consumption rule as stored modes.
244
+ if (!storedThemingApplies()) return
218
245
 
219
246
  const stored = localStorage.getItem(DYNAMIC_TOKENS_STORAGE_KEY)
220
247
  if (!stored) return
@@ -1,2 +1,2 @@
1
- export const SIZES = ['sm', 'md', 'lg'] as const
1
+ export const SIZES = ['xs', 'sm', 'md', 'lg'] as const
2
2
  export type Size = typeof SIZES[number]
package/src/css/body.css CHANGED
@@ -14,6 +14,21 @@
14
14
  line-height: 1.5;
15
15
  font-weight: 400;
16
16
  color: var(--color-grey-700);
17
+ font-feature-settings: 'cv01', 'cv05', 'cv09', 'cv11', 'ss03';
18
+ font-optical-sizing: auto;
19
+ font-kerning: normal;
20
+ font-synthesis: none;
21
+ text-rendering: optimizeLegibility;
22
+ -webkit-font-smoothing: antialiased;
23
+ -moz-osx-font-smoothing: grayscale;
24
+ }
25
+
26
+ h1, h2, h3, h4, h5, h6 {
27
+ text-wrap: balance;
28
+ }
29
+
30
+ p {
31
+ text-wrap: pretty;
17
32
  }
18
33
  }
19
34
 
@@ -34,5 +49,5 @@
34
49
  https://css-tricks.com/almanac/selectors/f/focus-visible/#aa-how-do-browsers-determine-when-something-is-focus-visible
35
50
  */
36
51
  *:focus-visible:not(input, .base-input, textarea, .v-popper__popper, .focus-indicator-none, [contenteditable]) {
37
- @apply ring-2 ring-inset ring-focus-ring;
52
+ @apply focus-ring;
38
53
  }
package/src/css/fonts.css CHANGED
@@ -1,10 +1,44 @@
1
1
  /*
2
- Inter via Google Fonts — kept OUT of the base stylesheet (./style) on
3
- purpose: a third-party font request must be the consumer's choice (GDPR,
4
- self-hosting). Apps that want the quick path import this file once:
2
+ Inter Variable, served from the inter-ui package (OFL-1.1) - kept OUT of
3
+ the base stylesheet (./style) on purpose: loading a font must stay the
4
+ consumer's choice. Apps that want the quick path import this file once:
5
5
 
6
6
  import '@livestorm/ui-vue/fonts'
7
7
 
8
- The monorepo keeps loading it through ui-vue-legacy's style chain.
8
+ The Latin subsets come last so the browser tries them first; it downloads a
9
+ full file only for text they do not cover. Their unicode-range is the
10
+ subset's own character map.
9
11
  */
10
- @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap');
12
+ @font-face {
13
+ font-family: 'Inter';
14
+ font-style: normal;
15
+ font-weight: 100 900;
16
+ font-display: swap;
17
+ src: url('inter-ui/variable/InterVariable.woff2') format('woff2');
18
+ }
19
+
20
+ @font-face {
21
+ font-family: 'Inter';
22
+ font-style: italic;
23
+ font-weight: 100 900;
24
+ font-display: swap;
25
+ src: url('inter-ui/variable/InterVariable-Italic.woff2') format('woff2');
26
+ }
27
+
28
+ @font-face {
29
+ font-family: 'Inter';
30
+ font-style: normal;
31
+ font-weight: 100 900;
32
+ font-display: swap;
33
+ src: url('inter-ui/variable-latin/InterVariable-subset.woff2') format('woff2');
34
+ unicode-range: U+0000, U+0020-007E, U+00A0-00AC, U+00AE-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-200B, U+2010-2027, U+202F-2055, U+2057, U+205F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+FEFF;
35
+ }
36
+
37
+ @font-face {
38
+ font-family: 'Inter';
39
+ font-style: italic;
40
+ font-weight: 100 900;
41
+ font-display: swap;
42
+ src: url('inter-ui/variable-latin/InterVariable-Italic-subset.woff2') format('woff2');
43
+ unicode-range: U+0000, U+0020-007E, U+00A0-00AC, U+00AE-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-200B, U+2010-2027, U+202F-2055, U+2057, U+205F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+FEFF;
44
+ }