@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
@@ -2,6 +2,7 @@
2
2
  import type { SideMenuItemProps } from './types'
3
3
  import { computed, useSlots } from 'vue'
4
4
  import { useForwardExpose } from 'reka-ui'
5
+ import UiBadge from '../UiBadge/UiBadge.vue'
5
6
 
6
7
  // Visual body of a side menu item (icon, label, badge, interactive overlay).
7
8
  // Extracted from UiSideMenuItem so the latter can optionally wrap this in a
@@ -41,12 +42,17 @@ const props = withDefaults(defineProps<SideMenuItemProps & {
41
42
  alwaysShowLabel: false,
42
43
  })
43
44
 
44
- // Normalise the badge into either a display string (count pill) or null (dot)
45
- // when shown. `showBadge` gates rendering so 0/false stay hidden.
46
45
  const showBadge = computed(() => props.badge === true || (typeof props.badge === 'number' && props.badge > 0))
47
- const badgeCount = computed(() => {
48
- if (typeof props.badge !== 'number') return null
49
- return props.badge > 99 ? '99+' : String(props.badge)
46
+ const badgeCount = computed(() => typeof props.badge === 'number' ? props.badge : undefined)
47
+
48
+ // An icon sits inside the item's 10px padding, whereas a 40px avatar fills the
49
+ // box on its own: the avatar variant needs offsets 10px smaller to land the
50
+ // badge on the same corner of the item.
51
+ const badgePositionClass = computed(() => {
52
+ if (badgeCount.value !== undefined) {
53
+ return hasAvatarSlot.value ? '-top-1 -right-1' : '-top-3.5 -right-3.5'
54
+ }
55
+ return hasAvatarSlot.value ? 'top-0 right-0' : '-top-2.5 -right-2.5'
50
56
  })
51
57
 
52
58
  const textAlignClass = computed(() => {
@@ -88,7 +94,7 @@ const textAlignClass = computed(() => {
88
94
  <button
89
95
  v-else
90
96
  type="button"
91
- class="block w-full h-full absolute inset-0 z-20 transition-all duration-150 cursor-pointer focus:outline-none focus-visible:ring-2 focus-visible:ring-actions-primary-idle rounded-xl"
97
+ class="block w-full h-full absolute inset-0 z-20 transition-all duration-150 cursor-pointer focus:outline-none focus-visible:focus-ring rounded-xl"
92
98
  :class="{ 'pointer-events-none': insideInteractive }"
93
99
  :tabindex="insideInteractive ? -1 : undefined"
94
100
  :aria-hidden="insideInteractive ? 'true' : undefined"
@@ -103,7 +109,7 @@ const textAlignClass = computed(() => {
103
109
  isActive ? 'bg-actions-neutral-active-overlay text-actions-neutral-idle' : 'text-actions-neutral-idle-alpha-strong',
104
110
  // Avatar box is 40px; on mobile `p-1` makes its total height (48px)
105
111
  // match icon items (`p-3` + 24px icon). Both are 40px on desktop.
106
- hasAvatarSlot ? 'p-1 md:p-0' : 'p-3',
112
+ hasAvatarSlot ? 'p-1 md:p-0' : 'p-2.5',
107
113
  ]"
108
114
  >
109
115
  <!-- Icon/avatar wrapper: anchors the notification badge to the icon's
@@ -119,23 +125,21 @@ const textAlignClass = computed(() => {
119
125
  <div
120
126
  v-if="icon"
121
127
  :class="[
122
- 'w-6 h-6 md:w-4 md:h-4',
128
+ 'w-6 h-6 md:w-5 md:h-5',
123
129
  icon
124
130
  ]"
125
131
  aria-hidden="true"
126
132
  />
127
- <!-- Notification badge, pushed out toward the button's top-right
128
- corner (past the icon's p-3 padding). -->
129
- <div
133
+ <!-- Notification badge, pushed out toward the item's top-right corner. -->
134
+ <UiBadge
130
135
  v-if="showBadge"
131
- class="absolute z-30 pointer-events-none flex items-center justify-center bg-surface-danger-bg-alpha text-text-neutral-invert-base rounded-2xl"
132
- :class="badgeCount
133
- ? '-top-3.5 -right-3.5 min-w-4 px-1 py-0.5 text-content-badges-bold-md'
134
- : '-top-2.5 -right-2.5 w-2 h-2'"
136
+ :count="badgeCount"
137
+ color="danger"
138
+ variant="strong"
139
+ class="absolute z-30 pointer-events-none"
140
+ :class="badgePositionClass"
135
141
  aria-hidden="true"
136
- >
137
- <span v-if="badgeCount">{{ badgeCount }}</span>
138
- </div>
142
+ />
139
143
  </div>
140
144
  <div
141
145
  class="pl-4 flex md:hidden text-content-text-md-regular font-bold truncate w-full items-center md:justify-center md:text-center"
@@ -18,23 +18,10 @@ provide('stepperOrientation', toRef(props, 'orientation'))
18
18
  <StepperRoot
19
19
  v-bind="{ ...forwarded, ...$attrs }"
20
20
  class="ui-stepper"
21
- :class="{
22
- 'ui-stepper--horizontal': isHorizontal,
23
- 'ui-stepper--vertical': !isHorizontal,
24
- }"
21
+ :class="isHorizontal
22
+ ? 'ui-stepper--horizontal flex items-start gap-8'
23
+ : 'ui-stepper--vertical [&>*:not(:last-child)]:mb-2'"
25
24
  >
26
25
  <slot />
27
26
  </StepperRoot>
28
27
  </template>
29
-
30
- <style>
31
- @reference '@livestorm/ui-tokens/output/supernova/index.css';
32
-
33
- .ui-stepper--horizontal {
34
- @apply flex items-start gap-8;
35
- }
36
-
37
- .ui-stepper--vertical > *:not(:last-child) {
38
- @apply mb-2;
39
- }
40
- </style>
@@ -8,20 +8,8 @@ defineProps<StepperDescriptionProps>()
8
8
  <template>
9
9
  <StepperDescription
10
10
  v-bind="$attrs"
11
- :class="[
12
- 'ui-stepper-description',
13
- 'transition-all duration-200',
14
- ]"
11
+ class="ui-stepper-description block max-w-60 truncate text-content-text-md-regular text-text-neutral-tertiary transition-all duration-200"
15
12
  >
16
13
  <slot />
17
14
  </StepperDescription>
18
15
  </template>
19
-
20
- <style scoped>
21
- @reference '@livestorm/ui-tokens/output/supernova/index.css';
22
-
23
- .ui-stepper-description {
24
- @apply max-w-60 truncate;
25
- @apply text-content-text-md-regular text-text-neutral-tertiary block;
26
- }
27
- </style>
@@ -1,6 +1,7 @@
1
1
  <script setup lang="ts">
2
2
  import type { StepperIndicatorProps } from 'reka-ui'
3
3
  import { StepperIndicator } from 'reka-ui'
4
+ import { useIconSize } from '../../composables/useIconSize'
4
5
 
5
6
  type Size = 'sm' | 'md' | 'lg'
6
7
 
@@ -13,81 +14,40 @@ interface UiStepperIndicatorProps extends StepperIndicatorProps {
13
14
  const { size = 'md', showCheckmark = true, icon } = defineProps<UiStepperIndicatorProps>()
14
15
 
15
16
  const sizeClasses = {
16
- sm: 'size-6 text-content-text-md-regular',
17
- md: 'size-8 text-content-text-md-regular',
18
- lg: 'size-10 text-content-text-lg-regular',
17
+ sm: 'size-8 text-content-text-md-regular',
18
+ md: 'size-10 text-content-text-md-regular',
19
+ lg: 'size-12 text-content-text-lg-regular',
19
20
  }
20
21
 
21
- const iconSizeClasses = {
22
- sm: 'size-3',
23
- md: 'size-4',
24
- lg: 'size-5',
25
- }
22
+ const iconSizeClass = useIconSize(() => size)
26
23
  </script>
27
24
 
28
25
  <template>
29
26
  <StepperIndicator
30
27
  v-bind="$attrs"
31
- class="stepper-indicator"
28
+ class="stepper-indicator flex items-center justify-center shrink-0 rounded-full font-semibold transition-all duration-200 bg-surface-neutral-alpha-200 text-text-neutral-base group-data-[state=active]/step:bg-surface-primary-bg-alpha group-data-[state=active]/step:text-text-neutral-invert-base"
32
29
  :class="sizeClasses[size]"
33
30
  >
34
31
  <span
35
32
  v-if="icon"
36
- class="stepper-custom-icon"
37
- :class="[iconSizeClasses[size], icon]"
33
+ class="stepper-custom-icon block"
34
+ :class="[iconSizeClass, icon, { 'group-data-[state=completed]/step:hidden': showCheckmark }]"
35
+ data-testid="ui-stepper-indicator-icon"
38
36
  />
39
37
 
40
38
  <span
41
39
  v-if="showCheckmark"
42
- class="stepper-checkmark i-ls-check"
43
- :class="iconSizeClasses[size]"
40
+ class="stepper-checkmark i-ph-check hidden group-data-[state=completed]/step:block"
41
+ :class="iconSizeClass"
42
+ data-testid="ui-stepper-indicator-checkmark"
44
43
  />
45
44
 
46
- <span class="stepper-number">
45
+ <span
46
+ class="stepper-number"
47
+ :class="{ hidden: icon, 'group-data-[state=completed]/step:hidden': showCheckmark }"
48
+ data-testid="ui-stepper-indicator-number"
49
+ >
47
50
  <slot />
48
51
  </span>
49
52
  </StepperIndicator>
50
53
  </template>
51
-
52
- <style>
53
- @reference '@livestorm/ui-tokens/output/supernova/index.css';
54
-
55
- .stepper-indicator {
56
- @apply flex items-center justify-center shrink-0;
57
- @apply rounded-full;
58
- @apply transition-all duration-200 font-semibold;
59
- @apply bg-surface-neutral-alpha-200 text-text-neutral-base;
60
- }
61
-
62
- [data-state="active"] .stepper-indicator {
63
- @apply bg-surface-primary-bg-alpha text-text-neutral-invert-base;
64
- }
65
-
66
- .stepper-custom-icon {
67
- @apply block;
68
- }
69
-
70
- [data-state="completed"] .stepper-custom-icon {
71
- @apply hidden;
72
- }
73
-
74
- .stepper-custom-icon ~ .stepper-number {
75
- @apply hidden;
76
- }
77
-
78
- [data-state="completed"] .stepper-custom-icon ~ .stepper-number {
79
- @apply block;
80
- }
81
-
82
- .stepper-checkmark {
83
- @apply hidden;
84
- }
85
-
86
- [data-state="completed"] .stepper-checkmark {
87
- @apply block;
88
- }
89
-
90
- [data-state="completed"] .stepper-number {
91
- @apply hidden;
92
- }
93
- </style>
@@ -16,15 +16,8 @@ withDefaults(defineProps<UiStepperItemProps>(), {
16
16
  v-bind="$attrs"
17
17
  :step="step"
18
18
  :disabled="disabled"
19
- class="ui-stepper-item"
19
+ class="ui-stepper-item group/step relative"
20
20
  >
21
21
  <slot />
22
22
  </StepperItem>
23
23
  </template>
24
-
25
- <style>
26
- @reference '@livestorm/ui-tokens/output/supernova/index.css';
27
- .ui-stepper-item {
28
- @apply relative;
29
- }
30
- </style>
@@ -28,22 +28,11 @@ const orientation = computed(() => props.orientation || unref(injectedOrientatio
28
28
  >
29
29
  <StepperSeparator
30
30
  v-bind="$attrs"
31
- :class="[
32
- 'ui-stepper-separator',
33
- 'transition-colors duration-200',
34
- {
35
- 'h-px w-full min-w-8': orientation === 'horizontal',
36
- 'w-px min-h-8': orientation === 'vertical',
37
- }
38
- ]"
31
+ class="ui-stepper-separator bg-surface-neutral-alpha-400 transition-colors duration-200"
32
+ :class="{
33
+ 'h-px w-full min-w-8': orientation === 'horizontal',
34
+ 'w-px min-h-8': orientation === 'vertical',
35
+ }"
39
36
  />
40
37
  </div>
41
38
  </template>
42
-
43
- <style scoped>
44
- @reference '@livestorm/ui-tokens/output/supernova/index.css';
45
-
46
- .ui-stepper-separator {
47
- @apply bg-surface-neutral-alpha-400;
48
- }
49
- </style>
@@ -8,17 +8,8 @@ defineProps<StepperTitleProps>()
8
8
  <template>
9
9
  <StepperTitle
10
10
  v-bind="$attrs"
11
- :class="[
12
- 'ui-stepper-title',
13
- ]"
11
+ class="ui-stepper-title text-content-text-lg-bold text-text-neutral-secondary"
14
12
  >
15
13
  <slot />
16
14
  </StepperTitle>
17
15
  </template>
18
-
19
- <style scoped>
20
- @reference '@livestorm/ui-tokens/output/supernova/index.css';
21
- .ui-stepper-title {
22
- @apply text-content-text-lg-bold text-content-text-lg-bold text-text-neutral-secondary;
23
- }
24
- </style>
@@ -0,0 +1,375 @@
1
+ <script setup lang="ts">
2
+ import { computed, inject, ref } from 'vue'
3
+ import type { ComponentPublicInstance } from 'vue'
4
+ import { Label, SwitchRoot, SwitchThumb, useId } from 'reka-ui'
5
+ import type { SwitchColor, SwitchPosition, SwitchSize } from './types'
6
+ import UiTooltip from '../UiTooltip/UiTooltip.vue'
7
+ import { CHOICE_ROW_KEY } from '../UiChoice/types'
8
+
9
+ interface UiSwitchProps {
10
+ /**
11
+ * Whether the switch is on
12
+ * @default false
13
+ */
14
+ modelValue?: boolean
15
+ /**
16
+ * The label text
17
+ */
18
+ label?: string
19
+ /**
20
+ * Description text below the label
21
+ */
22
+ description?: string
23
+ /**
24
+ * Info tooltip for the label
25
+ */
26
+ labelInfo?: string
27
+ /**
28
+ * Icon class rendered between the switch and the text (e.g. `i-ph-bell`)
29
+ */
30
+ icon?: string
31
+ /**
32
+ * Whether the switch is disabled
33
+ * @default false
34
+ */
35
+ disabled?: boolean
36
+ /**
37
+ * Whether the switch has an error
38
+ * @default false
39
+ */
40
+ error?: boolean
41
+ /**
42
+ * Color of the on state (error takes precedence)
43
+ * @default 'primary'
44
+ */
45
+ color?: SwitchColor
46
+ /**
47
+ * Size of the switch
48
+ * @default 'sm'
49
+ */
50
+ size?: SwitchSize
51
+ /**
52
+ * Which side of the text the switch sits on
53
+ * @default 'left'
54
+ */
55
+ switchPosition?: SwitchPosition
56
+ /**
57
+ * Whether to show a background behind the switch and its text
58
+ * @default false
59
+ */
60
+ showBg?: boolean
61
+ /**
62
+ * Whether the switch stretches to fill its container, which spreads the
63
+ * text and the switch to opposite edges
64
+ * @default false
65
+ */
66
+ fullWidth?: boolean
67
+ /**
68
+ * Switch name attribute (renders a hidden input for native forms)
69
+ */
70
+ name?: string
71
+ /**
72
+ * Switch id attribute
73
+ */
74
+ id?: string
75
+ /**
76
+ * Accessible name for the switch, for switches rendered without a label
77
+ */
78
+ ariaLabel?: string
79
+ }
80
+
81
+ const props = withDefaults(defineProps<UiSwitchProps>(), {
82
+ modelValue: false,
83
+ label: undefined,
84
+ description: undefined,
85
+ labelInfo: undefined,
86
+ icon: undefined,
87
+ disabled: false,
88
+ error: false,
89
+ color: 'primary',
90
+ size: 'sm',
91
+ switchPosition: 'left',
92
+ showBg: false,
93
+ fullWidth: false,
94
+ name: undefined,
95
+ id: undefined,
96
+ ariaLabel: undefined,
97
+ })
98
+
99
+ const emit = defineEmits<{
100
+ 'update:modelValue': [value: boolean]
101
+ 'focus': [event: FocusEvent]
102
+ 'blur': [event: FocusEvent]
103
+ }>()
104
+
105
+ const generatedId = useId()
106
+ const inputId = computed(() => props.id ?? generatedId)
107
+
108
+ const isChecked = computed(() => props.modelValue)
109
+ const inChoiceRow = inject(CHOICE_ROW_KEY, false)
110
+
111
+ // Design palette: primary | warning, with error mapping onto the danger tokens
112
+ const palette = computed(() => props.error ? 'danger' : props.color === 'warning' ? 'warning' : 'primary')
113
+
114
+ const descriptionId = computed(() => props.description ? `${inputId.value}-description` : undefined)
115
+
116
+ // Inside UiChoice a disabled switch greys out instead of fading with the row
117
+ const greyedOut = computed(() => inChoiceRow && props.disabled && !props.error)
118
+
119
+ const trackClasses = computed(() => {
120
+ const baseClasses = [
121
+ 'relative shrink-0 inline-flex items-center rounded-full',
122
+ 'border p-[3px] transition-colors',
123
+ 'focus:outline-hidden',
124
+ 'cursor-pointer disabled:cursor-not-allowed',
125
+ ]
126
+
127
+ // sm: 40x24 track / 16px thumb, xs: 32x20 track / 12px thumb
128
+ baseClasses.push(props.size === 'xs' ? 'h-5 w-8' : 'h-6 w-10')
129
+
130
+ if (greyedOut.value) {
131
+ baseClasses.push('border-transparent', isChecked.value ? 'bg-surface-neutral-alpha-400' : 'bg-surface-neutral-alpha-200')
132
+ } else if (isChecked.value) {
133
+ const checkedClasses = {
134
+ primary: 'bg-control-switch-on border-transparent',
135
+ warning: 'bg-actions-warning-idle-alpha-strong border-actions-warning-idle-alpha-strong',
136
+ danger: 'bg-actions-danger-idle-alpha-strong border-actions-danger-idle-alpha-strong',
137
+ }
138
+ baseClasses.push(checkedClasses[palette.value])
139
+ if (!props.disabled) {
140
+ // On warning/danger the border lightens on hover (primary keeps its border)
141
+ const checkedHoverClasses = {
142
+ primary: '',
143
+ warning: 'group-hover:border-borders-warning-default',
144
+ danger: 'group-hover:border-borders-danger-default',
145
+ }
146
+ baseClasses.push(checkedHoverClasses[palette.value])
147
+ }
148
+ } else {
149
+ const uncheckedBorderClasses = {
150
+ primary: 'border-control-off-border',
151
+ warning: 'border-borders-warning-strong',
152
+ danger: 'border-control-error-border',
153
+ }
154
+ baseClasses.push('bg-control-off', uncheckedBorderClasses[palette.value])
155
+ if (!props.disabled) {
156
+ // Border thickens on hover; padding shrinks in step so the thumb
157
+ // keeps its exact position and travel distance
158
+ baseClasses.push('group-hover:border-2 group-hover:p-0.5')
159
+ }
160
+ }
161
+
162
+ // The row draws the focus ring, or the choicebox around it
163
+ baseClasses.push('focus-indicator-none')
164
+
165
+ return baseClasses
166
+ })
167
+
168
+ const trackHoverOverlayClasses = computed(() => {
169
+ const overlayClasses = {
170
+ primary: isChecked.value ? 'bg-actions-primary-hover-overlay' : 'bg-actions-neutral-hover-overlay',
171
+ warning: 'bg-actions-warning-hover-overlay',
172
+ danger: 'bg-actions-danger-hover-overlay',
173
+ }
174
+ return overlayClasses[palette.value]
175
+ })
176
+
177
+ const thumbClasses = computed(() => {
178
+ const baseClasses = ['pointer-events-none block rounded-full transition-transform']
179
+
180
+ if (props.size === 'xs') {
181
+ baseClasses.push('size-3 data-[state=checked]:translate-x-3')
182
+ } else {
183
+ baseClasses.push('size-4 data-[state=checked]:translate-x-4')
184
+ }
185
+
186
+ baseClasses.push(isChecked.value
187
+ ? 'bg-actions-neutral-invert-idle'
188
+ : 'bg-control-off-knob')
189
+
190
+ return baseClasses
191
+ })
192
+
193
+ const innerWrapperClasses = computed(() => {
194
+ const classes = ['group relative flex items-center rounded-field-md', inChoiceRow && props.switchPosition === 'right' ? 'gap-6' : 'gap-2']
195
+
196
+ if (props.switchPosition === 'right') {
197
+ classes.push('flex-row-reverse')
198
+ }
199
+
200
+ if (props.disabled) {
201
+ classes.push(inChoiceRow ? 'cursor-not-allowed' : 'opacity-50 cursor-not-allowed')
202
+ } else {
203
+ classes.push('cursor-pointer')
204
+ }
205
+
206
+ if (inChoiceRow) {
207
+ return classes
208
+ }
209
+
210
+ if (!props.showBg) {
211
+ classes.push('isolate before:absolute before:-inset-x-3 before:-inset-y-1.5 before:-z-10 before:rounded-field-md before:pointer-events-none has-[[role=switch]:focus-visible]:before:focus-ring')
212
+ return classes
213
+ }
214
+
215
+ classes.push('p-2 shadow-[0px_1px_2px_0px_var(--color-shadow-neutral-100)] has-[[role=switch]:focus-visible]:focus-ring')
216
+ classes.push(props.error ? 'bg-actions-danger-idle-alpha-light' : 'bg-actions-neutral-idle-alpha-light')
217
+
218
+ return classes
219
+ })
220
+
221
+ const labelClasses = computed(() => ({
222
+ 'text-content-text-md-medium': inChoiceRow,
223
+ 'text-content-text-md-regular': !inChoiceRow,
224
+ 'text-text-danger-base': props.error,
225
+ 'text-text-neutral-base': !props.error && !greyedOut.value,
226
+ 'text-text-neutral-tertiary': greyedOut.value,
227
+ 'cursor-not-allowed': props.disabled,
228
+ 'cursor-pointer': !props.disabled,
229
+ }))
230
+
231
+ // Text hugs the switch when the component sizes to its content, but stays at
232
+ // the leading edge when it stretches, so the row reads label-left/switch-right.
233
+ const textAlignsToSwitch = computed(() => props.switchPosition === 'right' && !props.fullWidth)
234
+
235
+ const descriptionClasses = computed(() => ({
236
+ 'text-right': textAlignsToSwitch.value,
237
+ 'text-text-danger-tertiary': props.error,
238
+ 'text-text-neutral-secondary': !props.error && !greyedOut.value,
239
+ 'text-text-neutral-tertiary': greyedOut.value,
240
+ 'cursor-not-allowed': props.disabled,
241
+ 'cursor-pointer': !props.disabled,
242
+ }))
243
+
244
+ // SwitchRoot is a generic component, so InstanceType<typeof SwitchRoot> can't be used
245
+ const switchRef = ref<ComponentPublicInstance | null>(null)
246
+
247
+ function switchElement (): HTMLElement | undefined {
248
+ return (switchRef.value?.$el as HTMLElement | undefined) ?? undefined
249
+ }
250
+
251
+ // Make the whole wrapper (description, icon, background) toggle the switch.
252
+ // Clicks on the button itself or on the label are skipped: the button handles
253
+ // its own clicks and the label forwards to the button natively via `for`.
254
+ function onWrapperClick (event: MouseEvent) {
255
+ if (props.disabled) {
256
+ return
257
+ }
258
+
259
+ const target = event.target as HTMLElement
260
+ const switchEl = switchElement()
261
+
262
+ if (!switchEl || target === switchEl || switchEl.contains(target)) {
263
+ return
264
+ }
265
+ if (target.closest('label')) {
266
+ return
267
+ }
268
+
269
+ switchEl.click()
270
+ }
271
+
272
+ defineExpose({
273
+ focus: () => switchElement()?.focus(),
274
+ blur: () => switchElement()?.blur(),
275
+ })
276
+ </script>
277
+
278
+ <template>
279
+ <div
280
+ class="ui-switch-wrapper"
281
+ :class="fullWidth ? 'w-full' : 'w-fit'"
282
+ >
283
+ <div
284
+ :class="innerWrapperClasses"
285
+ @click="onWrapperClick"
286
+ >
287
+ <SwitchRoot
288
+ :id="inputId"
289
+ ref="switchRef"
290
+ :model-value="modelValue"
291
+ :disabled="disabled"
292
+ :name="name"
293
+ :class="trackClasses"
294
+ :aria-label="ariaLabel"
295
+ :aria-invalid="error || undefined"
296
+ :aria-describedby="descriptionId"
297
+ @update:model-value="emit('update:modelValue', $event)"
298
+ @focus="emit('focus', $event)"
299
+ @blur="emit('blur', $event)"
300
+ >
301
+ <SwitchThumb :class="thumbClasses" />
302
+
303
+ <div
304
+ v-if="!disabled"
305
+ class="absolute inset-0 rounded-full opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none"
306
+ :class="trackHoverOverlayClasses"
307
+ />
308
+ </SwitchRoot>
309
+
310
+ <!-- optional leading icon -->
311
+ <slot name="icon">
312
+ <span
313
+ v-if="icon"
314
+ class="size-4 shrink-0"
315
+ :class="[icon, error ? 'text-text-danger-base' : 'text-text-neutral-secondary']"
316
+ />
317
+ </slot>
318
+
319
+ <div
320
+ v-if="label || description || $slots.label"
321
+ class="flex flex-col min-w-0 flex-1"
322
+ :class="{ 'items-end': textAlignsToSwitch, 'gap-1': inChoiceRow }"
323
+ >
324
+ <div
325
+ class="flex items-center gap-2"
326
+ :class="{ 'flex-row-reverse': textAlignsToSwitch }"
327
+ >
328
+ <Label
329
+ :for="inputId"
330
+ :class="labelClasses"
331
+ >
332
+ <slot name="label">
333
+ {{ label }}
334
+ </slot>
335
+ </Label>
336
+
337
+ <!-- info tooltip -->
338
+ <UiTooltip
339
+ v-if="labelInfo"
340
+ :content="labelInfo"
341
+ >
342
+ <!-- stays neutral even in error state, per design -->
343
+ <div
344
+ class="flex items-center justify-center size-4 cursor-help shrink-0 text-text-neutral-tertiary"
345
+ data-testid="ui-switch-label-info"
346
+ @click.stop
347
+ >
348
+ <span class="i-ph-info-fill size-4" />
349
+ </div>
350
+ </UiTooltip>
351
+ </div>
352
+
353
+ <span
354
+ v-if="description"
355
+ :id="descriptionId"
356
+ class="text-content-text-md-regular"
357
+ :class="descriptionClasses"
358
+ >
359
+ {{ description }}
360
+ </span>
361
+ </div>
362
+
363
+ <!-- Background hover overlay -->
364
+ <div
365
+ v-if="showBg && !disabled"
366
+ class="absolute inset-0 opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none rounded-[inherit]"
367
+ :class="{
368
+ 'bg-actions-danger-hover-overlay': error,
369
+ 'bg-actions-primary-hover-overlay': isChecked && !error,
370
+ 'bg-actions-neutral-hover-overlay': !isChecked && !error,
371
+ }"
372
+ />
373
+ </div>
374
+ </div>
375
+ </template>
@@ -0,0 +1,5 @@
1
+ export type SwitchSize = 'sm' | 'xs'
2
+
3
+ export type SwitchColor = 'primary' | 'warning'
4
+
5
+ export type SwitchPosition = 'left' | 'right'