@leavepulse/ui 0.69.0 → 0.70.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 (634) hide show
  1. package/README.md +37 -0
  2. package/dist/assets/LoaderMark-DxBV2iDJ.css +43 -0
  3. package/dist/assets/LpActivityLine-B3EwNQEB.css +33 -0
  4. package/dist/assets/{LpCommandPalette-DxyjhYn_.css → LpCommandPalette-u-zOxKWa.css} +21 -31
  5. package/dist/assets/LpDock-Cbh0wQUv.css +17 -0
  6. package/dist/assets/{LpDropzone-Qb8k7cg4.css → LpDropzone-Bb1vBTeU.css} +12 -17
  7. package/dist/assets/{LpImageEditor-CElPDzpF.css → LpImageEditor-XM5bAziW.css} +6 -6
  8. package/dist/assets/LpLogViewer-BDNW6P52.css +38 -0
  9. package/dist/assets/{LpPalettePreview-CJmAKgYW.css → LpPalettePreview-B9VKDrvA.css} +2 -7
  10. package/dist/assets/LpShinyText-D69cBYDR.css +61 -0
  11. package/dist/assets/LpStatus-430OGTZY.css +17 -0
  12. package/dist/assets/LpStepMark-Drvx33Vg.css +10 -0
  13. package/dist/assets/{LpTable-BPERfJIk.css → LpTable-DHxEQ_-3.css} +19 -19
  14. package/dist/assets/LpTabs-BJ-nrJuI.css +18 -0
  15. package/dist/assets/LpTextReveal-DjI1MsDS.css +35 -0
  16. package/dist/assets/LpTypewriter-CXAm9Nca.css +27 -0
  17. package/dist/chunks/AttentionDot-DCBf4aWg.js +25 -0
  18. package/dist/chunks/{ContextMenuItems-B7XFHksm.js → ContextMenuItems-B5uE8Znw.js} +1 -1
  19. package/dist/chunks/{DropzoneLinkField-CjkrpDqO.js → DropzoneLinkField-Bw8Flkhk.js} +2 -2
  20. package/dist/chunks/FieldWrapper-BiennROB.js +43 -0
  21. package/dist/chunks/{LayoutCanvas-DF9CovaK.js → LayoutCanvas-BsJIzhdd.js} +1 -1
  22. package/dist/chunks/{LayoutNode-D9bIFzk0.js → LayoutNode-DJVhkSGk.js} +6 -8
  23. package/dist/chunks/LegendSwatch-BhRjrtzv.js +18 -0
  24. package/dist/chunks/LoaderMark-C1dubiKn.js +85 -0
  25. package/dist/chunks/{LpActionBar-MPKMu3pz.js → LpActionBar-CzOFar5t.js} +14 -20
  26. package/dist/chunks/LpActivityLine-CJvzrNpj.js +95 -0
  27. package/dist/chunks/{LpAddressInput-DG0BTqdH.js → LpAddressInput-CNnLTDZg.js} +7 -7
  28. package/dist/chunks/LpAlert-C5igj802.js +119 -0
  29. package/dist/chunks/{LpAppShell-DPh1756q.js → LpAppShell-CEUAB8kK.js} +15 -16
  30. package/dist/chunks/{LpAutocomplete-Dgn6hw3p.js → LpAutocomplete-D92niDHE.js} +15 -32
  31. package/dist/chunks/{LpAvatar-Bs0Fb1lC.js → LpAvatar-CLPl-qOF.js} +18 -6
  32. package/dist/chunks/LpBadge-HOEPBYmi.js +126 -0
  33. package/dist/chunks/LpBreadcrumbs-DYoPc3P4.js +144 -0
  34. package/dist/chunks/{LpButton-DNR-YAq5.js → LpButton-CVxBfGjd.js} +12 -4
  35. package/dist/chunks/{LpCalendar-BLya39Fh.js → LpCalendar-pVL91-Pl.js} +1 -1
  36. package/dist/chunks/{LpCard-Bf71NXZq.js → LpCard-CqKLnEhl.js} +18 -8
  37. package/dist/chunks/{LpCheckbox-Da5oZPHo.js → LpCheckbox-DHc2bHDe.js} +9 -6
  38. package/dist/chunks/{LpCodeBlock-lLbmslfs.js → LpCodeBlock-BGsQhxw8.js} +24 -32
  39. package/dist/chunks/LpCodeDisplay-CIKKT2iW.js +189 -0
  40. package/dist/chunks/LpCollapse-CWS9M_lm.js +115 -0
  41. package/dist/chunks/{LpColorPicker-DtEfBAcK.js → LpColorPicker-DFugXNUi.js} +10 -5
  42. package/dist/chunks/{LpConfirmDialog-D7s4jakB.js → LpConfirmDialog-CfGCux8m.js} +3 -3
  43. package/dist/chunks/{LpConfirmHost-DrYI5y1K.js → LpConfirmHost-exB7JmcO.js} +1 -1
  44. package/dist/chunks/{LpContextMenu-CRnjoqSt.js → LpContextMenu-COwOwRgI.js} +13 -5
  45. package/dist/chunks/LpCopyButton-DzHjnFs0.js +133 -0
  46. package/dist/chunks/LpCountdown-Dtq1ihlJ.js +231 -0
  47. package/dist/chunks/LpDataList-B-5nHfNw.js +120 -0
  48. package/dist/chunks/LpDatePicker-BUe1VUC0.js +168 -0
  49. package/dist/chunks/LpDateRangePicker-C_k65vGR.js +126 -0
  50. package/dist/chunks/{LpDisclosure-6AplYBub.js → LpDisclosure-DOarzlAG.js} +22 -11
  51. package/dist/chunks/{LpDrawer-Q4SOxM4s.js → LpDrawer-DGNKRsGq.js} +9 -4
  52. package/dist/chunks/{LpDropdownMenu-DWTt0ooM.js → LpDropdownMenu-CRgrhdAH.js} +10 -5
  53. package/dist/chunks/LpEditable-DTqLt2lT.js +236 -0
  54. package/dist/chunks/{LpEmptyState-om1UnFjV.js → LpEmptyState-KTKipws2.js} +1 -1
  55. package/dist/chunks/{LpFieldNotice-CHuDeLjc.js → LpFieldNotice-CurbNuXI.js} +1 -1
  56. package/dist/chunks/{LpFileTree-CW24YsVX.js → LpFileTree-DMISXVHC.js} +5 -3
  57. package/dist/chunks/{LpFileTreeNode-BXhTHaKW.js → LpFileTreeNode-CPXB_Yy3.js} +42 -55
  58. package/dist/chunks/{LpFormField-DPb47HEm.js → LpFormField-BWwgm1E4.js} +23 -9
  59. package/dist/chunks/LpFrame-BVQCQLDI.js +155 -0
  60. package/dist/chunks/LpGauge-Bk8TwJj0.js +204 -0
  61. package/dist/chunks/LpGlowBorder-B8V-QzIl.js +40 -0
  62. package/dist/chunks/{LpHintExample-C1eKYdeL.js → LpHintExample-9Py0wc-L.js} +11 -34
  63. package/dist/chunks/{LpHintLayer-7UOdWQG3.js → LpHintLayer-p4hqzdyA.js} +27 -14
  64. package/dist/chunks/{LpHints-BUtBp9-w.js → LpHints-CCrhRfy9.js} +3 -3
  65. package/dist/chunks/LpHoverCard-spGxyw7T.js +130 -0
  66. package/dist/chunks/{LpIcon-6tSrZ3Zy.js → LpIcon-HJP5xMz4.js} +1 -1
  67. package/dist/chunks/LpIdenticon-BzdC_qz9.js +63 -0
  68. package/dist/chunks/{LpInfraNode-Ds_8SZgN.js → LpInfraNode-CUC3t4na.js} +39 -25
  69. package/dist/chunks/{LpInput-CUyr6PIE.js → LpInput-CDuwODJG.js} +44 -18
  70. package/dist/chunks/{LpLightbox-B9J8rzsj.js → LpLightbox-XJ0LpTcZ.js} +69 -69
  71. package/dist/chunks/LpLoader-DjJEX8hL.js +92 -0
  72. package/dist/chunks/{LpLogViewer-4QFc-sVN.js → LpLogViewer-elZHbj85.js} +225 -129
  73. package/dist/chunks/LpMagnetic-CtXKLa2Y.js +62 -0
  74. package/dist/chunks/{LpMapPicker-BTbkFeSG.js → LpMapPicker-BtIl7NOM.js} +34 -31
  75. package/dist/chunks/LpMasonry--k0571qG.js +185 -0
  76. package/dist/chunks/{LpMediaGallery-CuPcscx3.js → LpMediaGallery-D5swlmZ_.js} +3 -3
  77. package/dist/chunks/{LpModal-hk1noDcr.js → LpModal-eBMt2Fqn.js} +8 -3
  78. package/dist/chunks/{LpModalNav-DQd2keZm.js → LpModalNav-D4Z0wVHR.js} +4 -4
  79. package/dist/chunks/{LpNotificationBell-X84PJIxD.js → LpNotificationBell-DPZmP5dM.js} +32 -48
  80. package/dist/chunks/LpNumberField-B9k-h2HE.js +140 -0
  81. package/dist/chunks/{LpNumberFlow-z4WPZcZu.js → LpNumberFlow-Cfyh033Q.js} +8 -28
  82. package/dist/chunks/{LpOtpInput-PbeNJ5In.js → LpOtpInput-CeBPsM7D.js} +2 -1
  83. package/dist/chunks/{LpPagination-Bx-VG4Ag.js → LpPagination-VNCX6pFC.js} +37 -6
  84. package/dist/chunks/{LpPalettePreview-CFav_7co.js → LpPalettePreview-BNB8T_MY.js} +1 -1
  85. package/dist/chunks/{LpPasswordInput-CbnXitAS.js → LpPasswordInput-DTV18FIh.js} +20 -20
  86. package/dist/chunks/{LpPhoneInput-DP69HONS.js → LpPhoneInput-C60tx1tC.js} +12 -7
  87. package/dist/chunks/{LpPie-yLF9-aDR.js → LpPie-CFuV7pZv.js} +158 -47
  88. package/dist/chunks/LpPipeline-D81yh_NX.js +329 -0
  89. package/dist/chunks/{LpPopover-DVnkHaOu.js → LpPopover-BEIcqb9p.js} +8 -3
  90. package/dist/chunks/{LpProgress-CA86wxXu.js → LpProgress-CE-m5OpD.js} +23 -63
  91. package/dist/chunks/LpQuota-2Sw_gqcJ.js +162 -0
  92. package/dist/chunks/{LpRadioGroup-8S5hf8lE.js → LpRadioGroup-CGBr5nIp.js} +1 -1
  93. package/dist/chunks/{LpRangeCalendar-ByQi-WUz.js → LpRangeCalendar-c5qj7YcC.js} +1 -1
  94. package/dist/chunks/{LpRangeSlider-C1yF9-nP.js → LpRangeSlider-Dv6lNvHY.js} +6 -2
  95. package/dist/chunks/LpRelativeTime-CKzVqAo9.js +73 -0
  96. package/dist/chunks/LpRepeater-D0VjmD6y.js +140 -0
  97. package/dist/chunks/LpRevealOnScroll-DcQjexLy.js +76 -0
  98. package/dist/chunks/LpScramble-TDO5Kdou.js +85 -0
  99. package/dist/chunks/LpSecretField-DMfdJ1cQ.js +307 -0
  100. package/dist/chunks/{LpSection-BmRXe6ZP.js → LpSection-BW4xJ-Li.js} +1 -1
  101. package/dist/chunks/{LpSegmented-CW3bFHM4.js → LpSegmented-BO99Sr4m.js} +11 -14
  102. package/dist/chunks/{LpSelect-BCyDYoih.js → LpSelect-B4f_yRi5.js} +93 -108
  103. package/dist/chunks/LpShaderBackdrop-Bote0iuy.js +332 -0
  104. package/dist/chunks/LpShinyText-DX2ajtWq.js +48 -0
  105. package/dist/chunks/{LpSidebar-DfIiS-lB.js → LpSidebar-D-M0Y_7U.js} +5 -3
  106. package/dist/chunks/{LpSidebarNav-C5FDNI0t.js → LpSidebarNav-DF-TYxOV.js} +3 -3
  107. package/dist/chunks/{LpSlider-Cuzmrd7p.js → LpSlider-DuoRpOrH.js} +6 -2
  108. package/dist/chunks/{LpSparkline-DXT4KrSi.js → LpSparkline-CExIRDb3.js} +32 -27
  109. package/dist/chunks/LpSpotlight-4F3NeUMY.js +41 -0
  110. package/dist/chunks/{LpStat-iBMF5QNk.js → LpStat-B2ix1Q7t.js} +38 -35
  111. package/dist/chunks/LpStatus-C7kx5PKE.js +86 -0
  112. package/dist/chunks/LpStepMark-DK-5BKAt.js +101 -0
  113. package/dist/chunks/LpStepper-DRFfdJaq.js +76 -0
  114. package/dist/chunks/{LpSwap-D82jiecV.js → LpSwap-DzE6M3Mg.js} +1 -1
  115. package/dist/chunks/LpSwitch-DrzKrZZV.js +112 -0
  116. package/dist/chunks/{LpTableFilter-CuIbgdW0.js → LpTableFilter-DyvHGbOk.js} +3 -2
  117. package/dist/chunks/{LpTableOfContents-C_4VBktT.js → LpTableOfContents-rYvo8z5T.js} +34 -21
  118. package/dist/chunks/{LpTagsInput-DiXrpYeE.js → LpTagsInput-DgpBFRV2.js} +68 -71
  119. package/dist/chunks/LpTextReveal-CtAnOUkp.js +140 -0
  120. package/dist/chunks/{LpTextarea-xoQd5Lnp.js → LpTextarea-DiWjeVoJ.js} +12 -11
  121. package/dist/chunks/{LpThemeProvider-CQ2jC9TA.js → LpThemeProvider-DcbfOxsU.js} +1 -1
  122. package/dist/chunks/LpThemeStudio-DguwHdGt.js +416 -0
  123. package/dist/chunks/LpThemeStudioSection-BwhqYDLf.js +20 -0
  124. package/dist/chunks/LpThemeSwitcher-D5uz0MhK.js +278 -0
  125. package/dist/chunks/{LpTimeField-MFgAsNc5.js → LpTimeField-BFQVf_PW.js} +13 -5
  126. package/dist/chunks/{LpToaster-C4zE9zB7.js → LpToaster-Wv9ksj4q.js} +49 -82
  127. package/dist/chunks/{LpTooltip-suFCM34F.js → LpTooltip-Cz8SQwRt.js} +8 -3
  128. package/dist/chunks/{LpTopologyCanvas-6ozNrQKh.js → LpTopologyCanvas-ZhKthfgz.js} +1 -1
  129. package/dist/chunks/{LpTour-BUp3Jt2e.js → LpTour-NfRJNEIP.js} +24 -18
  130. package/dist/chunks/LpTruncate-D_5Pfv5B.js +112 -0
  131. package/dist/chunks/LpTypewriter-BCL_a6wE.js +159 -0
  132. package/dist/chunks/{LpUptimeBar-B6kHw4Cj.js → LpUptimeBar-DWegV2p6.js} +9 -8
  133. package/dist/chunks/{LpVideoBackdrop-qWRYBOTQ.js → LpVideoBackdrop-DS1wGv-X.js} +7 -8
  134. package/dist/chunks/{MenuTitle-obgek0B7.js → MenuTitle-BjQZX8tQ.js} +1 -1
  135. package/dist/chunks/OptionContent-CmYUUeWj.js +40 -0
  136. package/dist/chunks/PickerField-CHRS1h7K.js +116 -0
  137. package/dist/chunks/RevealToggle-C-KzaQGJ.js +65 -0
  138. package/dist/chunks/StepConnector-37OgEOXA.js +41 -0
  139. package/dist/chunks/TourCard-BXuVHsfn.js +123 -0
  140. package/dist/chunks/backdrop-Dkf2vM81.js +59 -0
  141. package/dist/chunks/{icons-DVhZ_plB.js → icons-4IywzkHk.js} +1 -1
  142. package/dist/chunks/{useTheme-2qHG8NEU.js → useTheme-BOV_-AiY.js} +9 -65
  143. package/dist/component-names.d.ts +1 -1
  144. package/dist/components/AttentionDot.vue.d.ts +9 -0
  145. package/dist/components/AttentionDot.vue.js +4 -0
  146. package/dist/components/ContextMenuItems.vue.js +1 -1
  147. package/dist/components/DropzoneLinkField.vue.js +1 -1
  148. package/dist/components/FieldWrapper.vue.d.ts +25 -0
  149. package/dist/components/FieldWrapper.vue.js +4 -0
  150. package/dist/components/LayoutCanvas.vue.js +1 -1
  151. package/dist/components/LayoutNode.vue.d.ts +4 -4
  152. package/dist/components/LayoutNode.vue.js +1 -1
  153. package/dist/components/LegendSwatch.vue.d.ts +6 -0
  154. package/dist/components/LegendSwatch.vue.js +4 -0
  155. package/dist/components/LoaderMark.vue.d.ts +12 -0
  156. package/dist/components/LoaderMark.vue.js +4 -0
  157. package/dist/components/LpActionBar.vue.js +1 -1
  158. package/dist/components/LpActivityLine.vue.d.ts +58 -0
  159. package/dist/components/LpActivityLine.vue.js +4 -0
  160. package/dist/components/LpAddressInput.vue.js +1 -1
  161. package/dist/components/LpAlert.vue.d.ts +2 -2
  162. package/dist/components/LpAlert.vue.js +1 -1
  163. package/dist/components/LpAppShell.vue.d.ts +8 -7
  164. package/dist/components/LpAppShell.vue.js +1 -1
  165. package/dist/components/LpAutocomplete.vue.js +1 -1
  166. package/dist/components/LpAvatar.vue.d.ts +16 -0
  167. package/dist/components/LpAvatar.vue.js +1 -1
  168. package/dist/components/LpBadge.vue.d.ts +19 -5
  169. package/dist/components/LpBadge.vue.js +1 -1
  170. package/dist/components/LpBreadcrumbs.vue.js +1 -1
  171. package/dist/components/LpButton.vue.d.ts +2 -2
  172. package/dist/components/LpButton.vue.js +1 -1
  173. package/dist/components/LpCalendar.vue.js +1 -1
  174. package/dist/components/LpCard.vue.d.ts +24 -0
  175. package/dist/components/LpCard.vue.js +1 -1
  176. package/dist/components/LpChart.vue.js +107 -138
  177. package/dist/components/LpCheckbox.vue.d.ts +2 -2
  178. package/dist/components/LpCheckbox.vue.js +1 -1
  179. package/dist/components/LpCodeBlock.vue.js +1 -1
  180. package/dist/components/LpCodeDisplay.vue.d.ts +89 -0
  181. package/dist/components/LpCodeDisplay.vue.js +4 -0
  182. package/dist/components/LpCollapse.vue.d.ts +58 -0
  183. package/dist/components/LpCollapse.vue.js +4 -0
  184. package/dist/components/LpColorPicker.vue.d.ts +2 -2
  185. package/dist/components/LpColorPicker.vue.js +1 -1
  186. package/dist/components/LpCommandPalette.vue.js +34 -23
  187. package/dist/components/LpConfirmDialog.vue.js +1 -1
  188. package/dist/components/LpConfirmHost.vue.js +1 -1
  189. package/dist/components/LpContextMenu.vue.js +1 -1
  190. package/dist/components/LpCopyButton.vue.d.ts +82 -0
  191. package/dist/components/LpCopyButton.vue.js +4 -0
  192. package/dist/components/LpCountdown.vue.d.ts +100 -0
  193. package/dist/components/LpCountdown.vue.js +4 -0
  194. package/dist/components/LpDataList.vue.d.ts +66 -0
  195. package/dist/components/LpDataList.vue.js +4 -0
  196. package/dist/components/LpDatePicker.vue.d.ts +1 -1
  197. package/dist/components/LpDatePicker.vue.js +1 -1
  198. package/dist/components/LpDateRangePicker.vue.d.ts +1 -1
  199. package/dist/components/LpDateRangePicker.vue.js +1 -1
  200. package/dist/components/LpDisclosure.vue.js +1 -1
  201. package/dist/components/LpDock.vue.d.ts +74 -0
  202. package/dist/components/LpDock.vue.js +204 -0
  203. package/dist/components/LpDrawer.vue.js +1 -1
  204. package/dist/components/LpDropdownMenu.vue.js +1 -1
  205. package/dist/components/LpDropzone.vue.d.ts +8 -1
  206. package/dist/components/LpDropzone.vue.js +36 -15
  207. package/dist/components/LpEditable.vue.d.ts +85 -0
  208. package/dist/components/LpEditable.vue.js +4 -0
  209. package/dist/components/LpEmptyState.vue.js +1 -1
  210. package/dist/components/LpFieldNotice.vue.js +1 -1
  211. package/dist/components/LpFileTree.vue.js +1 -1
  212. package/dist/components/LpFileTreeNode.vue.js +1 -1
  213. package/dist/components/LpFormField.vue.js +1 -1
  214. package/dist/components/LpFrame.vue.d.ts +22 -0
  215. package/dist/components/LpFrame.vue.js +4 -0
  216. package/dist/components/LpGauge.vue.d.ts +116 -0
  217. package/dist/components/LpGauge.vue.js +4 -0
  218. package/dist/components/LpGlowBorder.vue.d.ts +47 -0
  219. package/dist/components/LpGlowBorder.vue.js +4 -0
  220. package/dist/components/LpHintExample.vue.d.ts +2 -2
  221. package/dist/components/LpHintExample.vue.js +1 -1
  222. package/dist/components/LpHintLayer.vue.js +1 -1
  223. package/dist/components/LpHints.vue.js +1 -1
  224. package/dist/components/LpHoverCard.vue.d.ts +60 -0
  225. package/dist/components/LpHoverCard.vue.js +4 -0
  226. package/dist/components/LpIcon.vue.js +1 -1
  227. package/dist/components/LpIdenticon.vue.d.ts +37 -0
  228. package/dist/components/LpIdenticon.vue.js +4 -0
  229. package/dist/components/LpImageEditor.vue.js +13 -19
  230. package/dist/components/LpInfraNode.vue.js +1 -1
  231. package/dist/components/LpInput.vue.d.ts +10 -0
  232. package/dist/components/LpInput.vue.js +1 -1
  233. package/dist/components/LpLightbox.vue.js +1 -1
  234. package/dist/components/LpLoader.vue.d.ts +106 -0
  235. package/dist/components/LpLoader.vue.js +4 -0
  236. package/dist/components/LpLogViewer.vue.js +1 -1
  237. package/dist/components/LpMagnetic.vue.d.ts +28 -0
  238. package/dist/components/LpMagnetic.vue.js +4 -0
  239. package/dist/components/LpMapPicker.vue.js +1 -1
  240. package/dist/components/LpMasonry.vue.d.ts +42 -0
  241. package/dist/components/LpMasonry.vue.js +4 -0
  242. package/dist/components/LpMediaGallery.vue.js +1 -1
  243. package/dist/components/LpModal.vue.js +1 -1
  244. package/dist/components/LpModalNav.vue.js +1 -1
  245. package/dist/components/LpNotificationBell.vue.d.ts +15 -6
  246. package/dist/components/LpNotificationBell.vue.js +1 -1
  247. package/dist/components/LpNumberField.vue.d.ts +57 -0
  248. package/dist/components/LpNumberField.vue.js +1 -1
  249. package/dist/components/LpNumberFlow.vue.js +1 -1
  250. package/dist/components/LpOtpInput.vue.d.ts +12 -4
  251. package/dist/components/LpOtpInput.vue.js +1 -1
  252. package/dist/components/LpPagination.vue.js +1 -1
  253. package/dist/components/LpPaletteFacts.vue.js +1 -1
  254. package/dist/components/LpPaletteHeader.vue.js +2 -2
  255. package/dist/components/LpPalettePreview.vue.js +1 -1
  256. package/dist/components/LpPaletteStats.vue.js +1 -1
  257. package/dist/components/LpPasswordInput.vue.d.ts +12 -1
  258. package/dist/components/LpPasswordInput.vue.js +1 -1
  259. package/dist/components/LpPhoneInput.vue.js +1 -1
  260. package/dist/components/LpPie.vue.d.ts +3 -1
  261. package/dist/components/LpPie.vue.js +1 -1
  262. package/dist/components/LpPipeline.vue.d.ts +91 -0
  263. package/dist/components/LpPipeline.vue.js +4 -0
  264. package/dist/components/LpPopover.vue.d.ts +2 -2
  265. package/dist/components/LpPopover.vue.js +1 -1
  266. package/dist/components/LpProgress.vue.d.ts +11 -4
  267. package/dist/components/LpProgress.vue.js +1 -1
  268. package/dist/components/LpQuota.vue.d.ts +68 -0
  269. package/dist/components/LpQuota.vue.js +4 -0
  270. package/dist/components/LpRadioGroup.vue.js +1 -1
  271. package/dist/components/LpRangeCalendar.vue.js +1 -1
  272. package/dist/components/LpRangeSlider.vue.js +1 -1
  273. package/dist/components/LpRelativeTime.vue.d.ts +41 -0
  274. package/dist/components/LpRelativeTime.vue.js +4 -0
  275. package/dist/components/LpRepeater.vue.d.ts +48 -0
  276. package/dist/components/LpRepeater.vue.js +4 -0
  277. package/dist/components/LpRevealOnScroll.vue.d.ts +67 -0
  278. package/dist/components/LpRevealOnScroll.vue.js +4 -0
  279. package/dist/components/LpRollingText.vue.d.ts +1 -1
  280. package/dist/components/LpScramble.vue.d.ts +55 -0
  281. package/dist/components/LpScramble.vue.js +4 -0
  282. package/dist/components/LpScrollArea.vue.d.ts +1 -1
  283. package/dist/components/LpSecretField.vue.d.ts +108 -0
  284. package/dist/components/LpSecretField.vue.js +4 -0
  285. package/dist/components/LpSection.vue.js +1 -1
  286. package/dist/components/LpSegmented.vue.js +1 -1
  287. package/dist/components/LpSelect.vue.d.ts +2 -0
  288. package/dist/components/LpSelect.vue.js +1 -1
  289. package/dist/components/LpShaderBackdrop.vue.d.ts +39 -0
  290. package/dist/components/LpShaderBackdrop.vue.js +4 -0
  291. package/dist/components/LpShinyText.vue.d.ts +39 -0
  292. package/dist/components/LpShinyText.vue.js +4 -0
  293. package/dist/components/LpShortcutsDialog.vue.js +1 -1
  294. package/dist/components/LpSidebar.vue.js +1 -1
  295. package/dist/components/LpSidebarNav.vue.js +1 -1
  296. package/dist/components/LpSlider.vue.js +1 -1
  297. package/dist/components/LpSparkline.vue.d.ts +4 -3
  298. package/dist/components/LpSparkline.vue.js +1 -1
  299. package/dist/components/LpSpotlight.vue.d.ts +37 -0
  300. package/dist/components/LpSpotlight.vue.js +4 -0
  301. package/dist/components/LpStat.vue.js +1 -1
  302. package/dist/components/LpStatus.vue.d.ts +65 -0
  303. package/dist/components/LpStatus.vue.js +4 -0
  304. package/dist/components/LpStepMark.vue.d.ts +31 -0
  305. package/dist/components/LpStepMark.vue.js +4 -0
  306. package/dist/components/LpStepper.vue.js +1 -1
  307. package/dist/components/LpSwap.vue.js +1 -1
  308. package/dist/components/LpSwitch.vue.d.ts +2 -2
  309. package/dist/components/LpSwitch.vue.js +1 -1
  310. package/dist/components/LpTable.vue.js +104 -120
  311. package/dist/components/LpTableFilter.vue.js +1 -1
  312. package/dist/components/LpTableOfContents.vue.d.ts +6 -1
  313. package/dist/components/LpTableOfContents.vue.js +1 -1
  314. package/dist/components/LpTabs.vue.d.ts +5 -5
  315. package/dist/components/LpTabs.vue.js +25 -33
  316. package/dist/components/LpTagsInput.vue.js +1 -1
  317. package/dist/components/LpTextReveal.vue.d.ts +58 -0
  318. package/dist/components/LpTextReveal.vue.js +4 -0
  319. package/dist/components/LpTextarea.vue.js +1 -1
  320. package/dist/components/LpThemeProvider.vue.js +1 -1
  321. package/dist/components/LpThemeStudio.vue.d.ts +54 -0
  322. package/dist/components/LpThemeStudio.vue.js +4 -0
  323. package/dist/components/LpThemeStudioSection.vue.d.ts +16 -0
  324. package/dist/components/LpThemeStudioSection.vue.js +4 -0
  325. package/dist/components/LpThemeSwitcher.vue.d.ts +32 -1
  326. package/dist/components/LpThemeSwitcher.vue.js +1 -1
  327. package/dist/components/LpTimeField.vue.d.ts +2 -0
  328. package/dist/components/LpTimeField.vue.js +1 -1
  329. package/dist/components/LpToaster.vue.js +1 -1
  330. package/dist/components/LpTooltip.vue.d.ts +2 -2
  331. package/dist/components/LpTooltip.vue.js +1 -1
  332. package/dist/components/LpTopologyCanvas.vue.js +1 -1
  333. package/dist/components/LpTour.vue.js +1 -1
  334. package/dist/components/LpTruncate.vue.d.ts +34 -0
  335. package/dist/components/LpTruncate.vue.js +4 -0
  336. package/dist/components/LpTypewriter.vue.d.ts +61 -0
  337. package/dist/components/LpTypewriter.vue.js +4 -0
  338. package/dist/components/LpUptimeBar.vue.js +1 -1
  339. package/dist/components/LpVideoBackdrop.vue.js +1 -1
  340. package/dist/components/MenuTitle.vue.js +1 -1
  341. package/dist/components/OptionContent.vue.d.ts +7 -0
  342. package/dist/components/OptionContent.vue.js +4 -0
  343. package/dist/components/PickerField.vue.d.ts +43 -0
  344. package/dist/components/PickerField.vue.js +4 -0
  345. package/dist/components/RevealToggle.vue.d.ts +21 -0
  346. package/dist/components/RevealToggle.vue.js +4 -0
  347. package/dist/components/StepConnector.vue.d.ts +19 -0
  348. package/dist/components/StepConnector.vue.js +4 -0
  349. package/dist/components/TourCard.vue.js +1 -1
  350. package/dist/components/badge.d.ts +1 -0
  351. package/dist/components/badge.js +4 -0
  352. package/dist/components/chart.d.ts +5 -1
  353. package/dist/components/chart.js +2 -21
  354. package/dist/components/dateRange.d.ts +11 -0
  355. package/dist/components/dateRange.js +12 -0
  356. package/dist/components/dock.d.ts +19 -0
  357. package/dist/components/dock.js +16 -0
  358. package/dist/components/dropdown.d.ts +10 -1
  359. package/dist/components/dropdown.js +7 -2
  360. package/dist/components/fieldText.d.ts +38 -0
  361. package/dist/components/fieldText.js +53 -0
  362. package/dist/components/fileTree.d.ts +7 -3
  363. package/dist/components/fileTree.js +12 -18
  364. package/dist/components/format.d.ts +41 -0
  365. package/dist/components/format.js +67 -0
  366. package/dist/components/identicon.d.ts +38 -0
  367. package/dist/components/identicon.js +85 -0
  368. package/dist/components/masonry.d.ts +32 -0
  369. package/dist/components/masonry.js +40 -0
  370. package/dist/components/menuWhen.js +1 -1
  371. package/dist/components/meter.d.ts +64 -0
  372. package/dist/components/meter.js +53 -0
  373. package/dist/components/otp.d.ts +1 -1
  374. package/dist/components/otp.js +7 -2
  375. package/dist/components/pipeline.d.ts +55 -0
  376. package/dist/components/pipeline.js +51 -0
  377. package/dist/components/quota.d.ts +57 -0
  378. package/dist/components/quota.js +40 -0
  379. package/dist/components/relativeTime.d.ts +24 -0
  380. package/dist/components/relativeTime.js +56 -0
  381. package/dist/components/reveal.d.ts +18 -0
  382. package/dist/components/reveal.js +32 -0
  383. package/dist/components/scramble.d.ts +68 -0
  384. package/dist/components/scramble.js +58 -0
  385. package/dist/components/shaderBackdrop.d.ts +20 -0
  386. package/dist/components/shaderBackdrop.js +156 -0
  387. package/dist/components/slider.d.ts +5 -0
  388. package/dist/components/slider.js +24 -0
  389. package/dist/components/slotText.d.ts +2 -0
  390. package/dist/components/slotText.js +9 -0
  391. package/dist/components/status.d.ts +14 -0
  392. package/dist/components/status.js +22 -0
  393. package/dist/components/tableFacets.d.ts +8 -0
  394. package/dist/components/tableFacets.js +19 -0
  395. package/dist/components/textSplit.d.ts +17 -0
  396. package/dist/components/textSplit.js +24 -0
  397. package/dist/components/timeSpan.d.ts +78 -0
  398. package/dist/components/timeSpan.js +85 -0
  399. package/dist/components/tone.d.ts +43 -0
  400. package/dist/components/tone.js +82 -0
  401. package/dist/components/tour.js +3 -2
  402. package/dist/components/typewriter.d.ts +36 -0
  403. package/dist/components/typewriter.js +53 -0
  404. package/dist/components/videoBackdrop.js +5 -6
  405. package/dist/composables/easing.d.ts +22 -1
  406. package/dist/composables/easing.js +42 -1
  407. package/dist/composables/pseudoLocale.d.ts +15 -0
  408. package/dist/composables/pseudoLocale.js +96 -0
  409. package/dist/composables/scroll.js +5 -3
  410. package/dist/composables/useClipboard.d.ts +4 -1
  411. package/dist/composables/useClipboard.js +12 -2
  412. package/dist/composables/useField.d.ts +8 -0
  413. package/dist/composables/useField.js +5 -0
  414. package/dist/composables/useForm.js +19 -5
  415. package/dist/composables/useInView.d.ts +11 -0
  416. package/dist/composables/useInView.js +39 -0
  417. package/dist/composables/useLoadingGate.d.ts +8 -0
  418. package/dist/composables/useLoadingGate.js +38 -0
  419. package/dist/composables/useLpConfig.d.ts +10 -0
  420. package/dist/composables/useLpConfig.js +11 -1
  421. package/dist/composables/useMediaQuery.js +3 -1
  422. package/dist/composables/useNow.d.ts +16 -0
  423. package/dist/composables/useNow.js +39 -0
  424. package/dist/composables/usePersisted.js +14 -7
  425. package/dist/composables/usePillTransition.d.ts +5 -2
  426. package/dist/composables/usePillTransition.js +4 -3
  427. package/dist/composables/usePointerFrame.d.ts +18 -0
  428. package/dist/composables/usePointerFrame.js +31 -0
  429. package/dist/composables/useReducedMotion.d.ts +2 -0
  430. package/dist/composables/useReducedMotion.js +7 -0
  431. package/dist/composables/useRepeater.d.ts +17 -0
  432. package/dist/composables/useRepeater.js +31 -0
  433. package/dist/composables/useResizeObserver.d.ts +8 -0
  434. package/dist/composables/useResizeObserver.js +33 -0
  435. package/dist/composables/useRevealedValue.d.ts +31 -0
  436. package/dist/composables/useRevealedValue.js +26 -0
  437. package/dist/composables/useScramble.d.ts +42 -0
  438. package/dist/composables/useScramble.js +76 -0
  439. package/dist/composables/useShift.js +2 -10
  440. package/dist/composables/useSpotlight.d.ts +18 -0
  441. package/dist/composables/useSpotlight.js +53 -0
  442. package/dist/composables/useTilt.js +26 -18
  443. package/dist/composables/useTween.d.ts +43 -0
  444. package/dist/composables/useTween.js +69 -0
  445. package/dist/composables/useView.d.ts +18 -0
  446. package/dist/composables/useView.js +61 -0
  447. package/dist/icons-all.js +1 -1
  448. package/dist/index.d.ts +98 -1
  449. package/dist/index.js +262 -104
  450. package/dist/theme/define.d.ts +12 -0
  451. package/dist/theme/studio.d.ts +90 -0
  452. package/package.json +5 -2
  453. package/src/component-names.ts +33 -0
  454. package/src/components/AttentionDot.vue +27 -0
  455. package/src/components/FieldWrapper.vue +38 -0
  456. package/src/components/LayoutNode.vue +5 -9
  457. package/src/components/LegendSwatch.vue +15 -0
  458. package/src/components/LoaderMark.vue +90 -0
  459. package/src/components/LpActionBar.vue +12 -20
  460. package/src/components/LpActivityLine.vue +186 -0
  461. package/src/components/LpAlert.vue +54 -24
  462. package/src/components/LpAppShell.vue +7 -11
  463. package/src/components/LpAutocomplete.vue +16 -14
  464. package/src/components/LpAvatar.vue +17 -2
  465. package/src/components/LpBadge.vue +77 -13
  466. package/src/components/LpBreadcrumbs.vue +101 -35
  467. package/src/components/LpButton.vue +15 -3
  468. package/src/components/LpCard.vue +30 -7
  469. package/src/components/LpChart.vue +143 -154
  470. package/src/components/LpCheckbox.vue +10 -4
  471. package/src/components/LpCodeBlock.vue +11 -19
  472. package/src/components/LpCodeDisplay.vue +228 -0
  473. package/src/components/LpCollapse.vue +162 -0
  474. package/src/components/LpColorPicker.vue +10 -1
  475. package/src/components/LpCommandPalette.vue +38 -24
  476. package/src/components/LpContextMenu.vue +10 -1
  477. package/src/components/LpCopyButton.vue +185 -0
  478. package/src/components/LpCountdown.vue +308 -0
  479. package/src/components/LpDataList.vue +154 -0
  480. package/src/components/LpDatePicker.vue +53 -104
  481. package/src/components/LpDateRangePicker.vue +49 -95
  482. package/src/components/LpDisclosure.vue +58 -36
  483. package/src/components/LpDock.vue +274 -0
  484. package/src/components/LpDrawer.vue +10 -1
  485. package/src/components/LpDropdownMenu.vue +10 -1
  486. package/src/components/LpDropzone.vue +34 -13
  487. package/src/components/LpEditable.vue +293 -0
  488. package/src/components/LpFileTree.vue +5 -1
  489. package/src/components/LpFileTreeNode.vue +25 -50
  490. package/src/components/LpFormField.vue +22 -3
  491. package/src/components/LpFrame.vue +200 -0
  492. package/src/components/LpGauge.vue +287 -0
  493. package/src/components/LpGlowBorder.vue +60 -0
  494. package/src/components/LpHintExample.vue +9 -32
  495. package/src/components/LpHintLayer.vue +13 -3
  496. package/src/components/LpHoverCard.vue +175 -0
  497. package/src/components/LpIdenticon.vue +69 -0
  498. package/src/components/LpImageEditor.vue +15 -18
  499. package/src/components/LpInfraNode.vue +27 -16
  500. package/src/components/LpInput.vue +30 -16
  501. package/src/components/LpLightbox.vue +44 -23
  502. package/src/components/LpLoader.vue +145 -0
  503. package/src/components/LpLogViewer.vue +311 -82
  504. package/src/components/LpMagnetic.vue +97 -0
  505. package/src/components/LpMapPicker.vue +26 -28
  506. package/src/components/LpMasonry.vue +247 -0
  507. package/src/components/LpModal.vue +10 -1
  508. package/src/components/LpNotificationBell.vue +33 -49
  509. package/src/components/LpNumberField.vue +79 -14
  510. package/src/components/LpNumberFlow.vue +10 -35
  511. package/src/components/LpOtpInput.vue +7 -2
  512. package/src/components/LpPagination.vue +38 -4
  513. package/src/components/LpPalettePreview.vue +2 -7
  514. package/src/components/LpPasswordInput.vue +16 -14
  515. package/src/components/LpPhoneInput.vue +12 -3
  516. package/src/components/LpPie.vue +197 -36
  517. package/src/components/LpPipeline.vue +366 -0
  518. package/src/components/LpPopover.vue +10 -1
  519. package/src/components/LpProgress.vue +22 -84
  520. package/src/components/LpQuota.vue +197 -0
  521. package/src/components/LpRangeSlider.vue +5 -1
  522. package/src/components/LpRelativeTime.vue +90 -0
  523. package/src/components/LpRepeater.vue +80 -0
  524. package/src/components/LpRevealOnScroll.vue +125 -0
  525. package/src/components/LpScramble.vue +107 -0
  526. package/src/components/LpSecretField.vue +313 -0
  527. package/src/components/LpSegmented.vue +3 -10
  528. package/src/components/LpSelect.vue +78 -64
  529. package/src/components/LpShaderBackdrop.vue +434 -0
  530. package/src/components/LpShinyText.vue +139 -0
  531. package/src/components/LpSidebar.vue +2 -0
  532. package/src/components/LpSlider.vue +5 -1
  533. package/src/components/LpSparkline.vue +55 -37
  534. package/src/components/LpSpotlight.vue +51 -0
  535. package/src/components/LpStat.vue +6 -2
  536. package/src/components/LpStatus.vue +127 -0
  537. package/src/components/LpStepMark.vue +138 -0
  538. package/src/components/LpStepper.vue +37 -43
  539. package/src/components/LpSwap.vue +2 -2
  540. package/src/components/LpSwitch.vue +15 -22
  541. package/src/components/LpTable.vue +47 -63
  542. package/src/components/LpTableFilter.vue +1 -0
  543. package/src/components/LpTableOfContents.vue +53 -29
  544. package/src/components/LpTabs.vue +10 -21
  545. package/src/components/LpTagsInput.vue +53 -37
  546. package/src/components/LpTextReveal.vue +236 -0
  547. package/src/components/LpTextarea.vue +11 -11
  548. package/src/components/LpThemeStudio.vue +216 -0
  549. package/src/components/LpThemeStudioSection.vue +16 -0
  550. package/src/components/LpThemeSwitcher.vue +156 -47
  551. package/src/components/LpTimeField.vue +9 -1
  552. package/src/components/LpToaster.vue +63 -83
  553. package/src/components/LpTooltip.vue +10 -1
  554. package/src/components/LpTour.vue +24 -13
  555. package/src/components/LpTruncate.vue +135 -0
  556. package/src/components/LpTypewriter.vue +236 -0
  557. package/src/components/LpUptimeBar.vue +6 -5
  558. package/src/components/LpVideoBackdrop.vue +15 -13
  559. package/src/components/OptionContent.vue +17 -0
  560. package/src/components/PickerField.vue +58 -0
  561. package/src/components/RevealToggle.vue +51 -0
  562. package/src/components/StepConnector.vue +54 -0
  563. package/src/components/TourCard.vue +29 -16
  564. package/src/components/badge.ts +8 -0
  565. package/src/components/chart.ts +8 -23
  566. package/src/components/dateRange.ts +25 -0
  567. package/src/components/dock.ts +31 -0
  568. package/src/components/dropdown.ts +15 -3
  569. package/src/components/fieldText.ts +95 -0
  570. package/src/components/fileTree.ts +19 -21
  571. package/src/components/format.ts +136 -0
  572. package/src/components/identicon.ts +160 -0
  573. package/src/components/masonry.ts +73 -0
  574. package/src/components/meter.ts +122 -0
  575. package/src/components/otp.ts +14 -3
  576. package/src/components/pipeline.ts +101 -0
  577. package/src/components/quota.ts +111 -0
  578. package/src/components/relativeTime.ts +118 -0
  579. package/src/components/reveal.ts +56 -0
  580. package/src/components/scramble.ts +138 -0
  581. package/src/components/shaderBackdrop.ts +208 -0
  582. package/src/components/slider.ts +30 -0
  583. package/src/components/slotText.ts +13 -0
  584. package/src/components/status.ts +46 -0
  585. package/src/components/tableFacets.ts +25 -0
  586. package/src/components/textSplit.ts +55 -0
  587. package/src/components/timeSpan.ts +183 -0
  588. package/src/components/tone.ts +144 -0
  589. package/src/components/tour.ts +3 -2
  590. package/src/components/typewriter.ts +104 -0
  591. package/src/components/videoBackdrop.ts +7 -6
  592. package/src/composables/easing.ts +66 -1
  593. package/src/composables/pseudoLocale.ts +105 -0
  594. package/src/composables/scroll.ts +6 -3
  595. package/src/composables/useClipboard.ts +25 -3
  596. package/src/composables/useField.ts +12 -0
  597. package/src/composables/useForm.ts +27 -6
  598. package/src/composables/useInView.ts +61 -0
  599. package/src/composables/useLoadingGate.ts +63 -0
  600. package/src/composables/useLpConfig.ts +20 -1
  601. package/src/composables/useMediaQuery.ts +6 -2
  602. package/src/composables/useNow.ts +84 -0
  603. package/src/composables/usePersisted.ts +19 -8
  604. package/src/composables/usePillTransition.ts +21 -13
  605. package/src/composables/usePointerFrame.ts +72 -0
  606. package/src/composables/useReducedMotion.ts +22 -0
  607. package/src/composables/useRepeater.ts +44 -0
  608. package/src/composables/useResizeObserver.ts +59 -0
  609. package/src/composables/useRevealedValue.ts +84 -0
  610. package/src/composables/useScramble.ts +152 -0
  611. package/src/composables/useShift.ts +10 -16
  612. package/src/composables/useSpotlight.ts +82 -0
  613. package/src/composables/useTilt.ts +40 -23
  614. package/src/composables/useTween.ts +149 -0
  615. package/src/composables/useView.ts +93 -0
  616. package/src/index.css +1 -0
  617. package/src/index.ts +143 -1
  618. package/src/kit-icons.ts +1 -1
  619. package/src/theme/define.ts +65 -0
  620. package/src/theme/studio.ts +202 -0
  621. package/src/tokens/effects.css +151 -0
  622. package/src/tokens/tokens.css +131 -39
  623. package/src/tokens/utilities.css +81 -0
  624. package/dist/assets/LpTabs-Bk7v4bZz.css +0 -18
  625. package/dist/chunks/LpAlert-BdvxvcWE.js +0 -85
  626. package/dist/chunks/LpBadge-Fe0D1bYx.js +0 -62
  627. package/dist/chunks/LpBreadcrumbs-rzOKkLiI.js +0 -98
  628. package/dist/chunks/LpDatePicker-BMfM454Y.js +0 -243
  629. package/dist/chunks/LpDateRangePicker-CNb9X3eL.js +0 -195
  630. package/dist/chunks/LpNumberField-DO1ufKvE.js +0 -107
  631. package/dist/chunks/LpStepper-C2slwObu.js +0 -90
  632. package/dist/chunks/LpSwitch-CZy9_IoA.js +0 -132
  633. package/dist/chunks/LpThemeSwitcher-CDoziW0z.js +0 -166
  634. package/dist/chunks/TourCard-BKI7X9-r.js +0 -105
@@ -0,0 +1,186 @@
1
+ <script lang="ts">
2
+ // The consumer's `class` is merged into the root's own rather than appended to
3
+ // it, so opt out of the automatic pass-through that would add it unmerged.
4
+ export default { inheritAttrs: false }
5
+ </script>
6
+
7
+ <script setup lang="ts">
8
+ /*
9
+ * A hairline along the edge of a card, table or page that says "something is
10
+ * happening here": a sweep while the length of the work is unknown, a fill once
11
+ * it is, a quick run to the end and a fade when it is done.
12
+ *
13
+ * Not LpProgress. LpProgress is a reading the user looks AT: it has a track,
14
+ * a caption, a value that persists. This is ambient: it has no track, lies over
15
+ * the edge of something else without taking space, is absent while idle, waits
16
+ * a beat before appearing so a fast load never flashes it, and on completion
17
+ * finishes its run before fading, so "done" is seen rather than the line just
18
+ * vanishing mid-way.
19
+ */
20
+ import { computed, onBeforeUnmount, ref, watch } from "vue"
21
+ import { durationToken, prefersReducedMotion } from "../composables/easing"
22
+ import { useLoadingGate } from "../composables/useLoadingGate"
23
+ import { useLabels } from "../composables/useLpConfig"
24
+ import { useMergedAttrs } from "../composables/useMergedClass"
25
+ import { meterFraction, TONE_COLOR, type MeterTone } from "./meter"
26
+
27
+ const props = withDefaults(
28
+ defineProps<{
29
+ /** Work is in flight. Going false finishes the line and fades it out. */
30
+ active?: boolean
31
+ /** Known progress. Unset or null: the length of the work is unknown, and the line sweeps. */
32
+ value?: number | null
33
+ max?: number
34
+ tone?: MeterTone
35
+ /**
36
+ * Where it lies. `top` and `bottom` are absolute, over the edge of the
37
+ * nearest positioned ancestor (give the card `relative`), so showing it
38
+ * moves nothing; `inline` takes its own line in the flow.
39
+ */
40
+ placement?: "top" | "bottom" | "inline"
41
+ /** Thickness in px. */
42
+ height?: number
43
+ /**
44
+ * Ms to wait before showing. Work that finishes within it never shows the
45
+ * line at all: a flash of activity for a 90 ms request is noise.
46
+ */
47
+ delay?: number
48
+ labels?: Partial<{ busy: string }>
49
+ }>(),
50
+ { active: true, value: null, max: 100, tone: "brand", placement: "top", height: 2, delay: 150 },
51
+ )
52
+
53
+ const text = useLabels("activityLine", { busy: "Loading" }, () => props.labels)
54
+
55
+ /*
56
+ * Whether it is up at all is the same question LpLoader answers, so it is
57
+ * answered the same way (useLoadingGate): wait `delay` before appearing, and
58
+ * once up stay long enough to be read as a state rather than a blink.
59
+ *
60
+ * On top of that the line has an exit of its own:
61
+ * idle → running → (gate closes) → finishing → idle. `finishing` is the run to
62
+ * the end and the fade after it; then the element is gone.
63
+ */
64
+ const gated = useLoadingGate(() => props.active, {
65
+ delay: () => (prefersReducedMotion() ? 0 : props.delay),
66
+ minVisible: 300,
67
+ })
68
+ const phase = ref<"idle" | "running" | "finishing">("idle")
69
+ let doneTimer: ReturnType<typeof setTimeout> | undefined
70
+
71
+ watch(
72
+ gated,
73
+ (on) => {
74
+ clearTimeout(doneTimer)
75
+ if (on) {
76
+ phase.value = "running"
77
+ return
78
+ }
79
+ if (phase.value === "idle") return
80
+ phase.value = "finishing"
81
+ // The run to the end (slow), then the fade (medium), then gone.
82
+ const hold = prefersReducedMotion() ? 0 : durationToken("duration-medium") * 3
83
+ doneTimer = setTimeout(() => (phase.value = "idle"), hold)
84
+ },
85
+ { immediate: true },
86
+ )
87
+ onBeforeUnmount(() => clearTimeout(doneTimer))
88
+
89
+ const determinate = computed(() => props.value != null)
90
+ const fraction = computed(() =>
91
+ phase.value === "finishing" ? 1 : determinate.value ? meterFraction(props.value as number, 0, props.max) : 0,
92
+ )
93
+
94
+ const { class: rootClass, attrs: rest } = useMergedAttrs(() =>
95
+ [
96
+ "pointer-events-none overflow-hidden",
97
+ props.placement === "inline" ? "relative block w-full" : "z-[2]",
98
+ "transition-opacity duration-(--duration-medium) ease-(--ease-emphasized) motion-reduce:transition-none",
99
+ ].join(" "),
100
+ )
101
+
102
+ /*
103
+ * Edge placement goes inline, not through `absolute top-0` classes: a card's
104
+ * skin (`.lp-skin-panel > *`) makes every direct child `position: relative`
105
+ * with a more specific selector than a utility class, which collapsed the line
106
+ * to zero width exactly where it is meant to be used, as a card's first child.
107
+ */
108
+ const edge = computed(() =>
109
+ props.placement === "inline"
110
+ ? {}
111
+ : { position: "absolute" as const, left: 0, right: 0, [props.placement]: 0 },
112
+ )
113
+
114
+ // The fade starts once the run to the end is over, not with it.
115
+ const opacity = computed(() => (phase.value === "running" ? 1 : 0))
116
+ const fadeDelay = computed(() => (phase.value === "finishing" ? "var(--duration-slow)" : "0ms"))
117
+ </script>
118
+
119
+ <template>
120
+ <span
121
+ v-if="phase !== 'idle' || placement === 'inline'"
122
+ role="progressbar"
123
+ :aria-label="text.busy"
124
+ :aria-hidden="phase === 'idle' ? 'true' : undefined"
125
+ :aria-busy="phase === 'running' ? 'true' : undefined"
126
+ :aria-valuenow="determinate && phase !== 'idle' ? (value as number) : undefined"
127
+ :aria-valuemin="determinate ? 0 : undefined"
128
+ :aria-valuemax="determinate ? max : undefined"
129
+ :class="rootClass"
130
+ :style="{ ...edge, height: `${height}px`, opacity, transitionDelay: fadeDelay, '--lp-al-color': TONE_COLOR[tone] }"
131
+ v-bind="rest"
132
+ >
133
+ <!-- The sweep: a short bright segment crossing the edge. Faded rather than
134
+ cut when the work turns determinate or ends. -->
135
+ <span
136
+ class="lp-sweep lp-activity-sweep absolute inset-y-0 left-0 w-2/5 rounded-pill transition-opacity duration-(--duration-medium)"
137
+ :class="determinate || phase === 'finishing' ? 'opacity-0' : 'opacity-100'"
138
+ />
139
+ <!-- The fill, scaled rather than sized, so it eases on the compositor. A
140
+ shimmer runs along it while it is still filling. -->
141
+ <span
142
+ class="absolute inset-0 origin-left rounded-pill transition-transform duration-(--duration-slow) ease-(--ease-emphasized) motion-reduce:transition-none"
143
+ :style="{ transform: `scaleX(${fraction})`, backgroundColor: 'var(--lp-al-color)' }"
144
+ >
145
+ <span v-if="determinate && phase === 'running'" class="lp-activity-shimmer absolute inset-0" />
146
+ </span>
147
+ </span>
148
+ </template>
149
+
150
+ <style>
151
+ /*
152
+ * Unscoped and namespaced, like the other kit animations: the keyframes are
153
+ * shared by every line on the page. The sweep's travel is the kit's own
154
+ * (.lp-sweep in tokens.css); this paints it, soft at both ends.
155
+ */
156
+ .lp-activity-sweep {
157
+ background: linear-gradient(90deg, transparent, var(--lp-al-color) 35%, var(--lp-al-color) 65%, transparent);
158
+ }
159
+
160
+ .lp-activity-shimmer {
161
+ background: linear-gradient(90deg, transparent, color-mix(in oklab, var(--color-surface) 45%, transparent), transparent);
162
+ background-size: 40% 100%;
163
+ background-repeat: no-repeat;
164
+ animation: lp-activity-shimmer 1.6s linear infinite;
165
+ }
166
+
167
+ @keyframes lp-activity-shimmer {
168
+ 0% {
169
+ background-position: -40% 0;
170
+ }
171
+ 100% {
172
+ background-position: 140% 0;
173
+ }
174
+ }
175
+
176
+ @media (prefers-reduced-motion: reduce) {
177
+ /* The sweep lies still across the line (tokens.css); a solid tint rather than its soft ends. */
178
+ .lp-activity-sweep {
179
+ background: var(--lp-al-color);
180
+ }
181
+ .lp-activity-shimmer {
182
+ animation: none;
183
+ display: none;
184
+ }
185
+ }
186
+ </style>
@@ -7,18 +7,29 @@ export default { inheritAttrs: false }
7
7
 
8
8
  <script setup lang="ts">
9
9
  import { tv, type VariantProps } from "tailwind-variants"
10
- import { computed, ref, watch } from "vue"
10
+ import { computed, ref, useSlots, watch } from "vue"
11
11
  import { useMergedAttrs } from "../composables/useMergedClass"
12
12
  import LpIcon from "./LpIcon.vue"
13
+ import LpLoader from "./LpLoader.vue"
14
+ import LpSwap from "./LpSwap.vue"
15
+ import { slotText } from "./slotText"
16
+ import { TONES, toneLook } from "./tone"
13
17
 
14
18
  const alert = tv({
15
- base: "flex gap-3 rounded-card border p-4 text-sm",
19
+ /*
20
+ * An alert changes while it is read (saving → saved → failed), so the change
21
+ * shows as one: the tint eases between variants, the icon turns over, and
22
+ * the message is swapped by LpSwap, its box easing to the new height.
23
+ */
24
+ base: "flex gap-3 rounded-card border p-4 text-sm transition-[background-color,border-color,color] duration-(--duration-medium) ease-(--ease-emphasized) motion-reduce:transition-none",
16
25
  variants: {
26
+ // The tint is the tone's quiet panel (tone.ts); an info alert is a plain
27
+ // neutral panel whose meaning is carried by its brand-coloured icon alone.
17
28
  variant: {
18
- info: "border-line bg-surface-soft text-ink",
19
- success: "border-action/30 bg-action/10 text-ink",
20
- warning: "border-accent/30 bg-accent/10 text-ink",
21
- danger: "border-danger/30 bg-danger/10 text-ink",
29
+ info: `${TONES.neutral.panel} text-ink`,
30
+ success: `${TONES.success.panel} text-ink`,
31
+ warning: `${TONES.warning.panel} text-ink`,
32
+ danger: `${TONES.danger.panel} text-ink`,
22
33
  },
23
34
  },
24
35
  defaultVariants: { variant: "info" },
@@ -33,13 +44,6 @@ const ICONS: Record<NonNullable<AlertVariants["variant"]>, string> = {
33
44
  danger: "lucide:octagon-alert",
34
45
  }
35
46
 
36
- const ICON_TONE: Record<NonNullable<AlertVariants["variant"]>, string> = {
37
- info: "text-brand",
38
- success: "text-action",
39
- warning: "text-accent",
40
- danger: "text-danger",
41
- }
42
-
43
47
  const props = withDefaults(
44
48
  defineProps<{
45
49
  variant?: AlertVariants["variant"]
@@ -54,7 +58,7 @@ const props = withDefaults(
54
58
  */
55
59
  live?: "assertive" | "polite" | false
56
60
  /**
57
- * Work is under way: the icon becomes a spinning loader (unless `icon` is
61
+ * Work is under way: the icon becomes LpLoader's spinner (unless `icon` is
58
62
  * given, which then spins instead) and the alert is announced politely.
59
63
  * A loader drawn as a still icon read as a frozen page.
60
64
  */
@@ -78,23 +82,49 @@ const role = computed(() => {
78
82
 
79
83
  // `p-3` or a different border must beat the variant's own, not race it.
80
84
  const { class: rootClass, attrs: rest } = useMergedAttrs(() => alert({ variant: props.variant }))
81
- const resolvedIcon = computed(() => props.icon ?? (props.busy ? "lucide:loader-circle" : ICONS[props.variant ?? "info"]))
82
- const iconTone = computed(() => ICON_TONE[props.variant ?? "info"])
85
+ const spinning = computed(() => props.busy && !props.icon)
86
+ const resolvedIcon = computed(() => props.icon ?? ICONS[props.variant ?? "info"])
87
+ const iconTone = computed(() => toneLook(props.variant ?? "info").text)
88
+
89
+ // What counts as another message: the variant, the title and the slot's words
90
+ // when it is plain text. Rich content keeps its key and only eases its height.
91
+ const slots = useSlots()
92
+ const messageKey = () => [props.variant, props.title ?? "", slotText(slots.default) ?? ""].join("\u0000")
83
93
  </script>
84
94
 
85
95
  <template>
86
96
  <div :class="rootClass" :role="role" :aria-busy="busy || undefined" v-bind="rest">
87
- <LpIcon
88
- :name="resolvedIcon"
89
- :size="18"
90
- :class="['mt-0.5 shrink-0', iconTone, busy ? 'animate-spin motion-reduce:animate-none' : '']"
91
- aria-hidden="true"
92
- />
93
- <div class="min-w-0">
97
+ <!-- The busy loader shows at once, since it replaces the icon, and stays
98
+ silent: the alert's own role and aria-busy already announce the work. -->
99
+ <span class="relative mt-0.5 grid size-[18px] shrink-0 place-items-center" aria-hidden="true">
100
+ <Transition
101
+ enter-from-class="scale-50 opacity-0"
102
+ leave-to-class="scale-50 opacity-0"
103
+ enter-active-class="transition-[scale,opacity] duration-(--duration-medium) ease-(--ease-emphasized) motion-reduce:transition-none"
104
+ leave-active-class="absolute transition-[scale,opacity] duration-(--duration-fast) ease-out motion-reduce:transition-none"
105
+ >
106
+ <LpLoader
107
+ v-if="spinning"
108
+ key="busy"
109
+ size="inline"
110
+ :delay="0"
111
+ class="text-[18px] transition-colors duration-(--duration-medium)"
112
+ :class="iconTone"
113
+ />
114
+ <LpIcon
115
+ v-else
116
+ :key="resolvedIcon"
117
+ :name="resolvedIcon"
118
+ :size="18"
119
+ :class="[iconTone, 'transition-colors duration-(--duration-medium)', busy ? 'animate-spin motion-reduce:animate-none' : '']"
120
+ />
121
+ </Transition>
122
+ </span>
123
+ <LpSwap :swap-key="messageKey()" class="min-w-0 flex-1">
94
124
  <p v-if="title" class="font-semibold text-ink">{{ title }}</p>
95
125
  <div :class="['text-muted-strong', title ? 'mt-0.5' : '']">
96
126
  <slot />
97
127
  </div>
98
- </div>
128
+ </LpSwap>
99
129
  </div>
100
130
  </template>
@@ -66,8 +66,6 @@ const props = withDefaults(
66
66
  isActive?: (item: SidebarItem) => boolean
67
67
  /** Override the header title. Falls back to the active item's label. */
68
68
  title?: string
69
- /** Mobile drawer open state (v-model:open). */
70
- open?: boolean
71
69
  /** Tailwind breakpoint below which the rail becomes a drawer. */
72
70
  mobileBreakpoint?: "sm" | "md" | "lg" | "xl"
73
71
  /** Show the brand/header divider in the rail. */
@@ -94,7 +92,6 @@ const props = withDefaults(
94
92
 
95
93
  const emit = defineEmits<{
96
94
  (e: "update:modelValue", id: string): void
97
- (e: "update:open", value: boolean): void
98
95
  (e: "update:collapsed", keys: string[]): void
99
96
  (e: "select", item: SidebarItem): void
100
97
  }>()
@@ -139,10 +136,9 @@ const pageTitle = computed(() => {
139
136
 
140
137
  // Mobile drawer: also close it on every path change, so href/select navigation
141
138
  // from a nav item dismisses it.
142
- const drawerOpen = computed({
143
- get: () => props.open ?? false,
144
- set: (v) => emit("update:open", v),
145
- })
139
+ // Its own state when the app does not bind it: the shell's burger must open
140
+ // the drawer either way. v-model:open still controls it from outside.
141
+ const drawerOpen = defineModel<boolean>("open", { default: false })
146
142
  const text = useLabels(
147
143
  "appShell",
148
144
  { openMenu: "Open menu", skipToContent: "Skip to content" },
@@ -165,7 +161,7 @@ function skipToMain() {
165
161
  watch(
166
162
  () => props.path,
167
163
  () => {
168
- if (drawerOpen.value) emit("update:open", false)
164
+ if (drawerOpen.value) drawerOpen.value = false
169
165
  scrollArea.value?.viewportEl?.scrollTo({ top: 0, left: 0, behavior: "instant" })
170
166
  },
171
167
  )
@@ -186,7 +182,7 @@ const burgerHidden: Record<NonNullable<typeof props.mobileBreakpoint>, string> =
186
182
  const burgerClass = computed(() => burgerHidden[props.mobileBreakpoint])
187
183
 
188
184
  // Expose the burger trigger so a host can omit its own header entirely.
189
- const _openDrawer = () => emit("update:open", true)
185
+ const _openDrawer = () => (drawerOpen.value = true)
190
186
  defineExpose({ openDrawer: _openDrawer })
191
187
 
192
188
  // The shell claims the full viewport height, which is wrong when it is embedded in a page that already has a header of its own.
@@ -221,7 +217,7 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
221
217
  :auto-collapse-after="autoCollapseAfter"
222
218
  class="shrink-0"
223
219
  @update:model-value="onModel"
224
- @update:open="(v) => emit('update:open', v)"
220
+ @update:open="(v) => (drawerOpen = v)"
225
221
  @update:collapsed="(v) => emit('update:collapsed', v)"
226
222
  @select="onSelect"
227
223
  >
@@ -256,7 +252,7 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
256
252
  size="sm"
257
253
  square
258
254
  :aria-label="text.openMenu"
259
- @click="emit('update:open', true)"
255
+ @click="drawerOpen = true"
260
256
  >
261
257
  <LpIcon name="lucide:menu" :size="18" />
262
258
  </LpButton>
@@ -36,9 +36,11 @@ import { computed, nextTick, ref, useAttrs, useId, watch } from "vue"
36
36
  import { useFieldControl } from "../composables/useField"
37
37
  import { useInputFilter } from "../composables/useInputFilter"
38
38
  import { useLabels } from "../composables/useLpConfig"
39
- import { CLOSE_ICON, OPTION_ITEM, POPOVER_PANEL } from "./dropdown"
39
+ import { CLOSE_ICON, OPTION_ITEM, optionStagger, POPOVER_PANEL } from "./dropdown"
40
40
  import LpIcon from "./LpIcon.vue"
41
+ import OptionContent from "./OptionContent.vue"
41
42
  import type { LpOptionBase, OptionSelection } from "./options"
43
+ import { useOutsideGuard, usePortalTarget } from "../composables/useView"
42
44
 
43
45
  export type AutocompleteOption = LpOptionBase<string>
44
46
 
@@ -256,11 +258,18 @@ function choose(opt: AutocompleteOption) {
256
258
  }
257
259
 
258
260
  function clear() {
261
+ if (field.value.disabled) return
259
262
  typing.value = false
260
263
  draft.value = null
261
264
  emit("update:modelValue", "")
262
265
  open.value = false
263
266
  }
267
+
268
+ // Overlays open in the window this component renders in (an LpFrame's, inside one).
269
+ const portalTo = usePortalTarget()
270
+ // What happens in another document (the page around a frame, or a frame in
271
+ // the page) is not "outside" for this layer.
272
+ const guardOutside = useOutsideGuard()
264
273
  </script>
265
274
 
266
275
  <template>
@@ -360,7 +369,7 @@ function clear() {
360
369
  </Transition>
361
370
  </div>
362
371
  <button
363
- v-if="clearable && hasValue"
372
+ v-if="clearable && hasValue && !field.disabled"
364
373
  type="button"
365
374
  class="group flex shrink-0 items-center text-muted outline-none transition-colors duration-[var(--duration-fast)] hover:text-ink"
366
375
  :aria-label="labels.clear"
@@ -375,8 +384,10 @@ function clear() {
375
384
  </button>
376
385
  </ComboboxAnchor>
377
386
 
378
- <ComboboxPortal>
387
+ <ComboboxPortal :to="portalTo">
379
388
  <ComboboxContent
389
+ @interact-outside="guardOutside"
390
+ @escape-key-down="guardOutside"
380
391
  :collision-padding="8"
381
392
  position="popper"
382
393
  :side-offset="6"
@@ -396,20 +407,11 @@ function clear() {
396
407
  :key="opt.value"
397
408
  :value="opt.value"
398
409
  :disabled="opt.disabled"
399
- :style="{ animationDelay: `${Math.min(i, 12) * 22}ms` }"
410
+ :style="optionStagger(i)"
400
411
  :class="[OPTION_ITEM, 'justify-between data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50']"
401
412
  @select.prevent="choose(opt)"
402
413
  >
403
- <span class="flex min-w-0 items-center gap-2.5">
404
- <img v-if="opt.image" :src="opt.image" alt="" class="size-6 shrink-0 rounded-full object-cover" />
405
- <LpIcon v-else-if="opt.icon" :name="opt.icon" :size="16" class="shrink-0 text-muted" />
406
- <span class="flex min-w-0 flex-col">
407
- <span class="truncate">{{ opt.label ?? opt.value }}</span>
408
- <span v-if="opt.description" class="truncate text-xs text-muted">
409
- {{ opt.description }}
410
- </span>
411
- </span>
412
- </span>
414
+ <OptionContent :option="opt" />
413
415
  </ComboboxItem>
414
416
  </ComboboxViewport>
415
417
  </ComboboxContent>
@@ -11,6 +11,7 @@ import { computed, onMounted, ref } from "vue"
11
11
  import type { ContextMenuItemDef } from "./LpContextMenu.vue"
12
12
  import { MenuWhen } from "./menuWhen"
13
13
  import LpIcon from "./LpIcon.vue"
14
+ import LpIdenticon from "./LpIdenticon.vue"
14
15
  import { useMergedAttrs } from "../composables/useMergedClass"
15
16
 
16
17
  const avatar = tv({
@@ -48,6 +49,14 @@ const props = withDefaults(
48
49
  * letters read as noise. `fallback` text still wins when both are given.
49
50
  */
50
51
  icon?: string
52
+ /**
53
+ * Draw an identicon while there is no picture, instead of initials: a
54
+ * pattern and colour derived from a string, so accounts that never set an
55
+ * avatar still look different from each other. `true` derives it from
56
+ * `alt`; a string is the seed itself (an id outlives a rename). `fallback`
57
+ * text and `icon` still win when given.
58
+ */
59
+ identicon?: boolean | string
51
60
  size?: AvatarVariants["size"]
52
61
  /** Explicit pixel size, wins over `size` — for avatars keyed to a layout. */
53
62
  pixelSize?: number
@@ -111,6 +120,11 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(() =>
111
120
  // <ClientOnly>.
112
121
  const mounted = ref(false)
113
122
 
123
+ const identiconSeed = computed(() => {
124
+ if (!props.identicon || props.fallback || props.icon) return ""
125
+ return props.identicon === true ? (props.alt ?? "").trim() : props.identicon
126
+ })
127
+
114
128
  const menuHeading = computed(() => props.menuTitle ?? props.alt)
115
129
  onMounted(() => {
116
130
  mounted.value = true
@@ -129,8 +143,9 @@ onMounted(() => {
129
143
  >
130
144
  <AvatarRoot :class="rootClass" :style="sizeStyle" v-bind="rest">
131
145
  <AvatarImage v-if="src && mounted" :src="src" :alt="alt" class="size-full object-cover animate-[fade-in_var(--duration-medium)_ease] motion-reduce:animate-none" />
132
- <AvatarFallback>
133
- <LpIcon v-if="icon && !fallback" :name="icon" :size="iconSize" />
146
+ <AvatarFallback :class="identiconSeed ? 'size-full' : undefined">
147
+ <LpIdenticon v-if="identiconSeed" :seed="identiconSeed" :padding="shape === 'circle' ? 0.24 : 0.14" />
148
+ <LpIcon v-else-if="icon && !fallback" :name="icon" :size="iconSize" />
134
149
  <template v-else>{{ initials }}</template>
135
150
  </AvatarFallback>
136
151
  </AvatarRoot>
@@ -6,7 +6,15 @@ export default { inheritAttrs: false }
6
6
 
7
7
  <script setup lang="ts">
8
8
  import { tv, type VariantProps } from "tailwind-variants"
9
+ import { useSlots } from "vue"
10
+ import { useLabels } from "../composables/useLpConfig"
9
11
  import { useMergedClass } from "../composables/useMergedClass"
12
+ import { BADGE_REMOVE } from "./badge"
13
+ import LpIcon from "./LpIcon.vue"
14
+ import LpRollingText from "./LpRollingText.vue"
15
+ import LpShift from "./LpShift.vue"
16
+ import { slotText } from "./slotText"
17
+ import { TONES } from "./tone"
10
18
 
11
19
  const badge = tv({
12
20
  /*
@@ -17,7 +25,14 @@ const badge = tv({
17
25
  * the moment it gained a status. The badge now occupies the height it says it
18
26
  * does and leaves the line it sits on alone.
19
27
  */
20
- base: "inline-flex shrink-0 items-center gap-1.5 rounded-pill align-middle font-medium leading-[1.2]",
28
+ /*
29
+ * A status changes while it is watched, so the change shows as one: the
30
+ * colours ease between tones, the width eases (LpShift) and plain text rolls
31
+ * to the new word (LpRollingText). The outline tone draws its edge as an
32
+ * inset ring rather than a border, so switching to it neither adds a pixel
33
+ * nor snaps: the ring is there in every tone, transparent.
34
+ */
35
+ base: "inline-flex shrink-0 items-center rounded-pill align-middle font-medium leading-[1.2] ring-1 ring-transparent ring-inset transition-[color,background-color,box-shadow] duration-(--duration-medium) ease-(--ease-emphasized) motion-reduce:transition-none",
21
36
  variants: {
22
37
  size: {
23
38
  // Fits inside a text-sm line without growing it — for a badge beside a
@@ -26,16 +41,30 @@ const badge = tv({
26
41
  md: "px-2.5 py-0.5 text-xs",
27
42
  lg: "px-3 py-1 text-sm",
28
43
  },
44
+ /*
45
+ * The kit's tones (tone.ts) under every name they go by, so a badge and a
46
+ * tinted row in one tone are one colour. `warning` is partial trouble,
47
+ * which every status surface eventually needs: without it a half-failed
48
+ * thing has to render as either fine or broken.
49
+ */
29
50
  tone: {
30
- neutral: "bg-surface-soft text-muted-strong",
31
- brand: "bg-brand-soft text-brand",
32
- action: "bg-action/15 text-action",
33
- success: "bg-action/15 text-action",
34
- // Partial trouble, which every status surface eventually needs: without
35
- // it a half-failed thing has to render as either fine or broken.
36
- warning: "bg-accent/15 text-accent",
37
- danger: "bg-danger-soft text-danger",
38
- outline: "border border-line text-ink",
51
+ neutral: TONES.neutral.chip,
52
+ muted: TONES.neutral.chip,
53
+ brand: TONES.brand.chip,
54
+ info: TONES.brand.chip,
55
+ action: TONES.success.chip,
56
+ success: TONES.success.chip,
57
+ ok: TONES.success.chip,
58
+ warning: TONES.warning.chip,
59
+ accent: TONES.warning.chip,
60
+ danger: TONES.danger.chip,
61
+ error: TONES.danger.chip,
62
+ outline: "text-ink ring-line",
63
+ },
64
+ // A chip that can be taken away (a tag, a filter in force): the ✕ sits
65
+ // tight to the trailing edge, so that side keeps only a hair of padding.
66
+ removable: {
67
+ true: "gap-1 pr-1",
39
68
  },
40
69
  },
41
70
  defaultVariants: { tone: "neutral", size: "md" },
@@ -48,14 +77,49 @@ const props = defineProps<{
48
77
  /** `sm` is the one that does not disturb a text-sm line it sits on. */
49
78
  size?: BadgeVariants["size"]
50
79
  dot?: boolean
80
+ /** A ✕ after the content that emits `remove`: a tag, a filter chip. */
81
+ removable?: boolean
82
+ /** Accessible name of the ✕, e.g. "Remove tag alpha". */
83
+ removeLabel?: string
84
+ }>()
85
+
86
+ const emit = defineEmits<{
87
+ /** The ✕ was pressed. */
88
+ (e: "remove"): void
51
89
  }>()
52
90
 
53
- const classes = useMergedClass(() => badge({ tone: props.tone, size: props.size }))
91
+ defineSlots<{
92
+ default?: () => unknown
93
+ /** Replaces the ✕ (with `removable`), for a chip whose remove control is another primitive's. */
94
+ remove?: () => unknown
95
+ }>()
96
+
97
+ const text = useLabels("badge", { remove: "Remove" })
98
+
99
+ const classes = useMergedClass(() => badge({ tone: props.tone, size: props.size, removable: props.removable }))
100
+
101
+ // Plain words roll to the new ones; richer content only eases its width.
102
+ const slots = useSlots()
103
+ const plainText = () => slotText(slots.default)
54
104
  </script>
55
105
 
56
106
  <template>
57
107
  <span v-bind="$attrs" :class="classes">
58
- <span v-if="dot" class="size-1.5 rounded-full bg-current" />
59
- <slot />
108
+ <!-- min-w-0 / max-w-full: a chip given a max width truncates its words
109
+ instead of spilling them past its edge. -->
110
+ <LpShift axis="width" class="min-w-0">
111
+ <span class="inline-flex max-w-full items-center gap-1.5 whitespace-nowrap">
112
+ <span v-if="dot" class="size-1.5 shrink-0 rounded-full bg-current" />
113
+ <LpRollingText v-if="plainText() !== null" :value="plainText()!" align="start" />
114
+ <slot v-else />
115
+ </span>
116
+ </LpShift>
117
+ <template v-if="removable">
118
+ <slot name="remove">
119
+ <button type="button" :class="BADGE_REMOVE" :aria-label="removeLabel ?? text.remove" @click="emit('remove')">
120
+ <LpIcon name="lucide:x" :size="12" />
121
+ </button>
122
+ </slot>
123
+ </template>
60
124
  </span>
61
125
  </template>