@leavepulse/ui 0.68.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 (640) 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.d.ts +10 -0
  177. package/dist/components/LpChart.vue.js +122 -142
  178. package/dist/components/LpCheckbox.vue.d.ts +2 -2
  179. package/dist/components/LpCheckbox.vue.js +1 -1
  180. package/dist/components/LpCodeBlock.vue.js +1 -1
  181. package/dist/components/LpCodeDisplay.vue.d.ts +89 -0
  182. package/dist/components/LpCodeDisplay.vue.js +4 -0
  183. package/dist/components/LpCollapse.vue.d.ts +58 -0
  184. package/dist/components/LpCollapse.vue.js +4 -0
  185. package/dist/components/LpColorPicker.vue.d.ts +2 -2
  186. package/dist/components/LpColorPicker.vue.js +1 -1
  187. package/dist/components/LpCommandPalette.vue.js +34 -23
  188. package/dist/components/LpConfirmDialog.vue.js +1 -1
  189. package/dist/components/LpConfirmHost.vue.js +1 -1
  190. package/dist/components/LpContextMenu.vue.js +1 -1
  191. package/dist/components/LpCopyButton.vue.d.ts +82 -0
  192. package/dist/components/LpCopyButton.vue.js +4 -0
  193. package/dist/components/LpCountdown.vue.d.ts +100 -0
  194. package/dist/components/LpCountdown.vue.js +4 -0
  195. package/dist/components/LpDataList.vue.d.ts +66 -0
  196. package/dist/components/LpDataList.vue.js +4 -0
  197. package/dist/components/LpDatePicker.vue.d.ts +1 -1
  198. package/dist/components/LpDatePicker.vue.js +1 -1
  199. package/dist/components/LpDateRangePicker.vue.d.ts +1 -1
  200. package/dist/components/LpDateRangePicker.vue.js +1 -1
  201. package/dist/components/LpDisclosure.vue.js +1 -1
  202. package/dist/components/LpDock.vue.d.ts +74 -0
  203. package/dist/components/LpDock.vue.js +204 -0
  204. package/dist/components/LpDrawer.vue.js +1 -1
  205. package/dist/components/LpDropdownMenu.vue.js +1 -1
  206. package/dist/components/LpDropzone.vue.d.ts +8 -1
  207. package/dist/components/LpDropzone.vue.js +36 -15
  208. package/dist/components/LpEditable.vue.d.ts +85 -0
  209. package/dist/components/LpEditable.vue.js +4 -0
  210. package/dist/components/LpEmptyState.vue.js +1 -1
  211. package/dist/components/LpFieldNotice.vue.js +1 -1
  212. package/dist/components/LpFileTree.vue.js +1 -1
  213. package/dist/components/LpFileTreeNode.vue.js +1 -1
  214. package/dist/components/LpFormField.vue.js +1 -1
  215. package/dist/components/LpFrame.vue.d.ts +22 -0
  216. package/dist/components/LpFrame.vue.js +4 -0
  217. package/dist/components/LpGauge.vue.d.ts +116 -0
  218. package/dist/components/LpGauge.vue.js +4 -0
  219. package/dist/components/LpGlowBorder.vue.d.ts +47 -0
  220. package/dist/components/LpGlowBorder.vue.js +4 -0
  221. package/dist/components/LpHintExample.vue.d.ts +2 -2
  222. package/dist/components/LpHintExample.vue.js +1 -1
  223. package/dist/components/LpHintLayer.vue.js +1 -1
  224. package/dist/components/LpHints.vue.js +1 -1
  225. package/dist/components/LpHoverCard.vue.d.ts +60 -0
  226. package/dist/components/LpHoverCard.vue.js +4 -0
  227. package/dist/components/LpIcon.vue.js +1 -1
  228. package/dist/components/LpIdenticon.vue.d.ts +37 -0
  229. package/dist/components/LpIdenticon.vue.js +4 -0
  230. package/dist/components/LpImageEditor.vue.js +13 -19
  231. package/dist/components/LpInfraNode.vue.js +1 -1
  232. package/dist/components/LpInput.vue.d.ts +10 -0
  233. package/dist/components/LpInput.vue.js +1 -1
  234. package/dist/components/LpLightbox.vue.js +1 -1
  235. package/dist/components/LpLoader.vue.d.ts +106 -0
  236. package/dist/components/LpLoader.vue.js +4 -0
  237. package/dist/components/LpLogViewer.vue.js +1 -1
  238. package/dist/components/LpMagnetic.vue.d.ts +28 -0
  239. package/dist/components/LpMagnetic.vue.js +4 -0
  240. package/dist/components/LpMapPicker.vue.js +1 -1
  241. package/dist/components/LpMasonry.vue.d.ts +42 -0
  242. package/dist/components/LpMasonry.vue.js +4 -0
  243. package/dist/components/LpMediaGallery.vue.js +1 -1
  244. package/dist/components/LpModal.vue.js +1 -1
  245. package/dist/components/LpModalNav.vue.js +1 -1
  246. package/dist/components/LpNotificationBell.vue.d.ts +15 -6
  247. package/dist/components/LpNotificationBell.vue.js +1 -1
  248. package/dist/components/LpNumberField.vue.d.ts +57 -0
  249. package/dist/components/LpNumberField.vue.js +1 -1
  250. package/dist/components/LpNumberFlow.vue.js +1 -1
  251. package/dist/components/LpOtpInput.vue.d.ts +12 -4
  252. package/dist/components/LpOtpInput.vue.js +1 -1
  253. package/dist/components/LpPagination.vue.js +1 -1
  254. package/dist/components/LpPaletteFacts.vue.js +1 -1
  255. package/dist/components/LpPaletteHeader.vue.js +2 -2
  256. package/dist/components/LpPalettePreview.vue.js +1 -1
  257. package/dist/components/LpPaletteStats.vue.js +1 -1
  258. package/dist/components/LpPasswordInput.vue.d.ts +12 -1
  259. package/dist/components/LpPasswordInput.vue.js +1 -1
  260. package/dist/components/LpPhoneInput.vue.js +1 -1
  261. package/dist/components/LpPie.vue.d.ts +3 -1
  262. package/dist/components/LpPie.vue.js +1 -1
  263. package/dist/components/LpPipeline.vue.d.ts +91 -0
  264. package/dist/components/LpPipeline.vue.js +4 -0
  265. package/dist/components/LpPopover.vue.d.ts +2 -2
  266. package/dist/components/LpPopover.vue.js +1 -1
  267. package/dist/components/LpProgress.vue.d.ts +11 -4
  268. package/dist/components/LpProgress.vue.js +1 -1
  269. package/dist/components/LpQuota.vue.d.ts +68 -0
  270. package/dist/components/LpQuota.vue.js +4 -0
  271. package/dist/components/LpRadioGroup.vue.js +1 -1
  272. package/dist/components/LpRangeCalendar.vue.js +1 -1
  273. package/dist/components/LpRangeSlider.vue.js +1 -1
  274. package/dist/components/LpRelativeTime.vue.d.ts +41 -0
  275. package/dist/components/LpRelativeTime.vue.js +4 -0
  276. package/dist/components/LpRepeater.vue.d.ts +48 -0
  277. package/dist/components/LpRepeater.vue.js +4 -0
  278. package/dist/components/LpRevealOnScroll.vue.d.ts +67 -0
  279. package/dist/components/LpRevealOnScroll.vue.js +4 -0
  280. package/dist/components/LpRollingText.vue.d.ts +1 -1
  281. package/dist/components/LpScramble.vue.d.ts +55 -0
  282. package/dist/components/LpScramble.vue.js +4 -0
  283. package/dist/components/LpScrollArea.vue.d.ts +1 -1
  284. package/dist/components/LpSecretField.vue.d.ts +108 -0
  285. package/dist/components/LpSecretField.vue.js +4 -0
  286. package/dist/components/LpSection.vue.js +1 -1
  287. package/dist/components/LpSegmented.vue.js +1 -1
  288. package/dist/components/LpSelect.vue.d.ts +2 -0
  289. package/dist/components/LpSelect.vue.js +1 -1
  290. package/dist/components/LpShaderBackdrop.vue.d.ts +39 -0
  291. package/dist/components/LpShaderBackdrop.vue.js +4 -0
  292. package/dist/components/LpShinyText.vue.d.ts +39 -0
  293. package/dist/components/LpShinyText.vue.js +4 -0
  294. package/dist/components/LpShortcutsDialog.vue.js +1 -1
  295. package/dist/components/LpSidebar.vue.js +1 -1
  296. package/dist/components/LpSidebarNav.vue.js +1 -1
  297. package/dist/components/LpSlider.vue.js +1 -1
  298. package/dist/components/LpSparkline.vue.d.ts +4 -3
  299. package/dist/components/LpSparkline.vue.js +1 -1
  300. package/dist/components/LpSpotlight.vue.d.ts +37 -0
  301. package/dist/components/LpSpotlight.vue.js +4 -0
  302. package/dist/components/LpStat.vue.js +1 -1
  303. package/dist/components/LpStatus.vue.d.ts +65 -0
  304. package/dist/components/LpStatus.vue.js +4 -0
  305. package/dist/components/LpStepMark.vue.d.ts +31 -0
  306. package/dist/components/LpStepMark.vue.js +4 -0
  307. package/dist/components/LpStepper.vue.js +1 -1
  308. package/dist/components/LpSwap.vue.js +1 -1
  309. package/dist/components/LpSwitch.vue.d.ts +2 -2
  310. package/dist/components/LpSwitch.vue.js +1 -1
  311. package/dist/components/LpTable.vue.js +104 -120
  312. package/dist/components/LpTableFilter.vue.js +1 -1
  313. package/dist/components/LpTableOfContents.vue.d.ts +6 -1
  314. package/dist/components/LpTableOfContents.vue.js +1 -1
  315. package/dist/components/LpTabs.vue.d.ts +5 -5
  316. package/dist/components/LpTabs.vue.js +25 -33
  317. package/dist/components/LpTagsInput.vue.js +1 -1
  318. package/dist/components/LpTextReveal.vue.d.ts +58 -0
  319. package/dist/components/LpTextReveal.vue.js +4 -0
  320. package/dist/components/LpTextarea.vue.js +1 -1
  321. package/dist/components/LpThemeProvider.vue.js +1 -1
  322. package/dist/components/LpThemeStudio.vue.d.ts +54 -0
  323. package/dist/components/LpThemeStudio.vue.js +4 -0
  324. package/dist/components/LpThemeStudioSection.vue.d.ts +16 -0
  325. package/dist/components/LpThemeStudioSection.vue.js +4 -0
  326. package/dist/components/LpThemeSwitcher.vue.d.ts +32 -1
  327. package/dist/components/LpThemeSwitcher.vue.js +1 -1
  328. package/dist/components/LpTimeField.vue.d.ts +2 -0
  329. package/dist/components/LpTimeField.vue.js +1 -1
  330. package/dist/components/LpToaster.vue.js +1 -1
  331. package/dist/components/LpTooltip.vue.d.ts +2 -2
  332. package/dist/components/LpTooltip.vue.js +1 -1
  333. package/dist/components/LpTopologyCanvas.vue.js +1 -1
  334. package/dist/components/LpTour.vue.js +1 -1
  335. package/dist/components/LpTruncate.vue.d.ts +34 -0
  336. package/dist/components/LpTruncate.vue.js +4 -0
  337. package/dist/components/LpTypewriter.vue.d.ts +61 -0
  338. package/dist/components/LpTypewriter.vue.js +4 -0
  339. package/dist/components/LpUptimeBar.vue.js +1 -1
  340. package/dist/components/LpVideoBackdrop.vue.js +1 -1
  341. package/dist/components/MenuTitle.vue.js +1 -1
  342. package/dist/components/OptionContent.vue.d.ts +7 -0
  343. package/dist/components/OptionContent.vue.js +4 -0
  344. package/dist/components/PickerField.vue.d.ts +43 -0
  345. package/dist/components/PickerField.vue.js +4 -0
  346. package/dist/components/RevealToggle.vue.d.ts +21 -0
  347. package/dist/components/RevealToggle.vue.js +4 -0
  348. package/dist/components/StepConnector.vue.d.ts +19 -0
  349. package/dist/components/StepConnector.vue.js +4 -0
  350. package/dist/components/TourCard.vue.js +1 -1
  351. package/dist/components/badge.d.ts +1 -0
  352. package/dist/components/badge.js +4 -0
  353. package/dist/components/chart.d.ts +5 -1
  354. package/dist/components/chart.js +2 -21
  355. package/dist/components/dateRange.d.ts +11 -0
  356. package/dist/components/dateRange.js +12 -0
  357. package/dist/components/dock.d.ts +19 -0
  358. package/dist/components/dock.js +16 -0
  359. package/dist/components/dropdown.d.ts +10 -1
  360. package/dist/components/dropdown.js +7 -2
  361. package/dist/components/fieldText.d.ts +38 -0
  362. package/dist/components/fieldText.js +53 -0
  363. package/dist/components/fileTree.d.ts +7 -3
  364. package/dist/components/fileTree.js +12 -18
  365. package/dist/components/format.d.ts +41 -0
  366. package/dist/components/format.js +67 -0
  367. package/dist/components/identicon.d.ts +38 -0
  368. package/dist/components/identicon.js +85 -0
  369. package/dist/components/masonry.d.ts +32 -0
  370. package/dist/components/masonry.js +40 -0
  371. package/dist/components/menuWhen.js +1 -1
  372. package/dist/components/meter.d.ts +64 -0
  373. package/dist/components/meter.js +53 -0
  374. package/dist/components/otp.d.ts +1 -1
  375. package/dist/components/otp.js +7 -2
  376. package/dist/components/pipeline.d.ts +55 -0
  377. package/dist/components/pipeline.js +51 -0
  378. package/dist/components/quota.d.ts +57 -0
  379. package/dist/components/quota.js +40 -0
  380. package/dist/components/relativeTime.d.ts +24 -0
  381. package/dist/components/relativeTime.js +56 -0
  382. package/dist/components/reveal.d.ts +18 -0
  383. package/dist/components/reveal.js +32 -0
  384. package/dist/components/scramble.d.ts +68 -0
  385. package/dist/components/scramble.js +58 -0
  386. package/dist/components/shaderBackdrop.d.ts +20 -0
  387. package/dist/components/shaderBackdrop.js +156 -0
  388. package/dist/components/slider.d.ts +5 -0
  389. package/dist/components/slider.js +24 -0
  390. package/dist/components/slotText.d.ts +2 -0
  391. package/dist/components/slotText.js +9 -0
  392. package/dist/components/status.d.ts +14 -0
  393. package/dist/components/status.js +22 -0
  394. package/dist/components/tableFacets.d.ts +8 -0
  395. package/dist/components/tableFacets.js +19 -0
  396. package/dist/components/textSplit.d.ts +17 -0
  397. package/dist/components/textSplit.js +24 -0
  398. package/dist/components/timeSpan.d.ts +78 -0
  399. package/dist/components/timeSpan.js +85 -0
  400. package/dist/components/tone.d.ts +43 -0
  401. package/dist/components/tone.js +82 -0
  402. package/dist/components/tour.js +3 -2
  403. package/dist/components/typewriter.d.ts +36 -0
  404. package/dist/components/typewriter.js +53 -0
  405. package/dist/components/videoBackdrop.js +5 -6
  406. package/dist/composables/easing.d.ts +22 -1
  407. package/dist/composables/easing.js +42 -1
  408. package/dist/composables/pseudoLocale.d.ts +15 -0
  409. package/dist/composables/pseudoLocale.js +96 -0
  410. package/dist/composables/scroll.js +5 -3
  411. package/dist/composables/useClipboard.d.ts +4 -1
  412. package/dist/composables/useClipboard.js +12 -2
  413. package/dist/composables/useField.d.ts +8 -0
  414. package/dist/composables/useField.js +5 -0
  415. package/dist/composables/useForm.js +19 -5
  416. package/dist/composables/useHintSystem.d.ts +4 -0
  417. package/dist/composables/useHintSystem.js +33 -1
  418. package/dist/composables/useHints.js +9 -3
  419. package/dist/composables/useInView.d.ts +11 -0
  420. package/dist/composables/useInView.js +39 -0
  421. package/dist/composables/useLoadingGate.d.ts +8 -0
  422. package/dist/composables/useLoadingGate.js +38 -0
  423. package/dist/composables/useLpConfig.d.ts +10 -0
  424. package/dist/composables/useLpConfig.js +11 -1
  425. package/dist/composables/useMediaQuery.js +3 -1
  426. package/dist/composables/useNow.d.ts +16 -0
  427. package/dist/composables/useNow.js +39 -0
  428. package/dist/composables/usePersisted.js +14 -7
  429. package/dist/composables/usePillTransition.d.ts +5 -2
  430. package/dist/composables/usePillTransition.js +4 -3
  431. package/dist/composables/usePointerFrame.d.ts +18 -0
  432. package/dist/composables/usePointerFrame.js +31 -0
  433. package/dist/composables/useReducedMotion.d.ts +2 -0
  434. package/dist/composables/useReducedMotion.js +7 -0
  435. package/dist/composables/useRepeater.d.ts +17 -0
  436. package/dist/composables/useRepeater.js +31 -0
  437. package/dist/composables/useResizeObserver.d.ts +8 -0
  438. package/dist/composables/useResizeObserver.js +33 -0
  439. package/dist/composables/useRevealedValue.d.ts +31 -0
  440. package/dist/composables/useRevealedValue.js +26 -0
  441. package/dist/composables/useScramble.d.ts +42 -0
  442. package/dist/composables/useScramble.js +76 -0
  443. package/dist/composables/useShift.js +2 -10
  444. package/dist/composables/useSpotlight.d.ts +18 -0
  445. package/dist/composables/useSpotlight.js +53 -0
  446. package/dist/composables/useTilt.js +26 -18
  447. package/dist/composables/useTween.d.ts +43 -0
  448. package/dist/composables/useTween.js +69 -0
  449. package/dist/composables/useView.d.ts +18 -0
  450. package/dist/composables/useView.js +61 -0
  451. package/dist/icons-all.js +1 -1
  452. package/dist/index.d.ts +98 -1
  453. package/dist/index.js +262 -104
  454. package/dist/theme/define.d.ts +12 -0
  455. package/dist/theme/studio.d.ts +90 -0
  456. package/package.json +5 -2
  457. package/src/component-names.ts +33 -0
  458. package/src/components/AttentionDot.vue +27 -0
  459. package/src/components/FieldWrapper.vue +38 -0
  460. package/src/components/LayoutNode.vue +5 -9
  461. package/src/components/LegendSwatch.vue +15 -0
  462. package/src/components/LoaderMark.vue +90 -0
  463. package/src/components/LpActionBar.vue +12 -20
  464. package/src/components/LpActivityLine.vue +186 -0
  465. package/src/components/LpAlert.vue +54 -24
  466. package/src/components/LpAppShell.vue +7 -11
  467. package/src/components/LpAutocomplete.vue +16 -14
  468. package/src/components/LpAvatar.vue +17 -2
  469. package/src/components/LpBadge.vue +77 -13
  470. package/src/components/LpBreadcrumbs.vue +101 -35
  471. package/src/components/LpButton.vue +15 -3
  472. package/src/components/LpCard.vue +30 -7
  473. package/src/components/LpChart.vue +152 -156
  474. package/src/components/LpCheckbox.vue +10 -4
  475. package/src/components/LpCodeBlock.vue +11 -19
  476. package/src/components/LpCodeDisplay.vue +228 -0
  477. package/src/components/LpCollapse.vue +162 -0
  478. package/src/components/LpColorPicker.vue +10 -1
  479. package/src/components/LpCommandPalette.vue +38 -24
  480. package/src/components/LpContextMenu.vue +10 -1
  481. package/src/components/LpCopyButton.vue +185 -0
  482. package/src/components/LpCountdown.vue +308 -0
  483. package/src/components/LpDataList.vue +154 -0
  484. package/src/components/LpDatePicker.vue +53 -104
  485. package/src/components/LpDateRangePicker.vue +49 -95
  486. package/src/components/LpDisclosure.vue +58 -36
  487. package/src/components/LpDock.vue +274 -0
  488. package/src/components/LpDrawer.vue +10 -1
  489. package/src/components/LpDropdownMenu.vue +10 -1
  490. package/src/components/LpDropzone.vue +34 -13
  491. package/src/components/LpEditable.vue +293 -0
  492. package/src/components/LpFileTree.vue +5 -1
  493. package/src/components/LpFileTreeNode.vue +25 -50
  494. package/src/components/LpFormField.vue +22 -3
  495. package/src/components/LpFrame.vue +200 -0
  496. package/src/components/LpGauge.vue +287 -0
  497. package/src/components/LpGlowBorder.vue +60 -0
  498. package/src/components/LpHintExample.vue +14 -38
  499. package/src/components/LpHintLayer.vue +13 -3
  500. package/src/components/LpHoverCard.vue +175 -0
  501. package/src/components/LpIdenticon.vue +69 -0
  502. package/src/components/LpImageEditor.vue +15 -18
  503. package/src/components/LpInfraNode.vue +27 -16
  504. package/src/components/LpInput.vue +30 -16
  505. package/src/components/LpLightbox.vue +44 -23
  506. package/src/components/LpLoader.vue +145 -0
  507. package/src/components/LpLogViewer.vue +311 -82
  508. package/src/components/LpMagnetic.vue +97 -0
  509. package/src/components/LpMapPicker.vue +26 -28
  510. package/src/components/LpMasonry.vue +247 -0
  511. package/src/components/LpModal.vue +10 -1
  512. package/src/components/LpNotificationBell.vue +33 -49
  513. package/src/components/LpNumberField.vue +79 -14
  514. package/src/components/LpNumberFlow.vue +10 -35
  515. package/src/components/LpOtpInput.vue +7 -2
  516. package/src/components/LpPagination.vue +38 -4
  517. package/src/components/LpPalettePreview.vue +2 -7
  518. package/src/components/LpPasswordInput.vue +16 -14
  519. package/src/components/LpPhoneInput.vue +12 -3
  520. package/src/components/LpPie.vue +197 -36
  521. package/src/components/LpPipeline.vue +366 -0
  522. package/src/components/LpPopover.vue +10 -1
  523. package/src/components/LpProgress.vue +22 -84
  524. package/src/components/LpQuota.vue +197 -0
  525. package/src/components/LpRangeSlider.vue +5 -1
  526. package/src/components/LpRelativeTime.vue +90 -0
  527. package/src/components/LpRepeater.vue +80 -0
  528. package/src/components/LpRevealOnScroll.vue +125 -0
  529. package/src/components/LpScramble.vue +107 -0
  530. package/src/components/LpSecretField.vue +313 -0
  531. package/src/components/LpSegmented.vue +3 -10
  532. package/src/components/LpSelect.vue +78 -64
  533. package/src/components/LpShaderBackdrop.vue +434 -0
  534. package/src/components/LpShinyText.vue +139 -0
  535. package/src/components/LpSidebar.vue +2 -0
  536. package/src/components/LpSlider.vue +5 -1
  537. package/src/components/LpSparkline.vue +55 -37
  538. package/src/components/LpSpotlight.vue +51 -0
  539. package/src/components/LpStat.vue +6 -2
  540. package/src/components/LpStatus.vue +127 -0
  541. package/src/components/LpStepMark.vue +138 -0
  542. package/src/components/LpStepper.vue +37 -43
  543. package/src/components/LpSwap.vue +2 -2
  544. package/src/components/LpSwitch.vue +15 -22
  545. package/src/components/LpTable.vue +47 -63
  546. package/src/components/LpTableFilter.vue +1 -0
  547. package/src/components/LpTableOfContents.vue +53 -29
  548. package/src/components/LpTabs.vue +10 -21
  549. package/src/components/LpTagsInput.vue +53 -37
  550. package/src/components/LpTextReveal.vue +236 -0
  551. package/src/components/LpTextarea.vue +11 -11
  552. package/src/components/LpThemeStudio.vue +216 -0
  553. package/src/components/LpThemeStudioSection.vue +16 -0
  554. package/src/components/LpThemeSwitcher.vue +156 -47
  555. package/src/components/LpTimeField.vue +9 -1
  556. package/src/components/LpToaster.vue +63 -83
  557. package/src/components/LpTooltip.vue +10 -1
  558. package/src/components/LpTour.vue +24 -13
  559. package/src/components/LpTruncate.vue +135 -0
  560. package/src/components/LpTypewriter.vue +236 -0
  561. package/src/components/LpUptimeBar.vue +6 -5
  562. package/src/components/LpVideoBackdrop.vue +15 -13
  563. package/src/components/OptionContent.vue +17 -0
  564. package/src/components/PickerField.vue +58 -0
  565. package/src/components/RevealToggle.vue +51 -0
  566. package/src/components/StepConnector.vue +54 -0
  567. package/src/components/TourCard.vue +29 -16
  568. package/src/components/badge.ts +8 -0
  569. package/src/components/chart.ts +8 -23
  570. package/src/components/dateRange.ts +25 -0
  571. package/src/components/dock.ts +31 -0
  572. package/src/components/dropdown.ts +15 -3
  573. package/src/components/fieldText.ts +95 -0
  574. package/src/components/fileTree.ts +19 -21
  575. package/src/components/format.ts +136 -0
  576. package/src/components/identicon.ts +160 -0
  577. package/src/components/masonry.ts +73 -0
  578. package/src/components/meter.ts +122 -0
  579. package/src/components/otp.ts +14 -3
  580. package/src/components/pipeline.ts +101 -0
  581. package/src/components/quota.ts +111 -0
  582. package/src/components/relativeTime.ts +118 -0
  583. package/src/components/reveal.ts +56 -0
  584. package/src/components/scramble.ts +138 -0
  585. package/src/components/shaderBackdrop.ts +208 -0
  586. package/src/components/slider.ts +30 -0
  587. package/src/components/slotText.ts +13 -0
  588. package/src/components/status.ts +46 -0
  589. package/src/components/tableFacets.ts +25 -0
  590. package/src/components/textSplit.ts +55 -0
  591. package/src/components/timeSpan.ts +183 -0
  592. package/src/components/tone.ts +144 -0
  593. package/src/components/tour.ts +3 -2
  594. package/src/components/typewriter.ts +104 -0
  595. package/src/components/videoBackdrop.ts +7 -6
  596. package/src/composables/easing.ts +66 -1
  597. package/src/composables/pseudoLocale.ts +105 -0
  598. package/src/composables/scroll.ts +6 -3
  599. package/src/composables/useClipboard.ts +25 -3
  600. package/src/composables/useField.ts +12 -0
  601. package/src/composables/useForm.ts +27 -6
  602. package/src/composables/useHintSystem.ts +40 -0
  603. package/src/composables/useHints.ts +14 -3
  604. package/src/composables/useInView.ts +61 -0
  605. package/src/composables/useLoadingGate.ts +63 -0
  606. package/src/composables/useLpConfig.ts +20 -1
  607. package/src/composables/useMediaQuery.ts +6 -2
  608. package/src/composables/useNow.ts +84 -0
  609. package/src/composables/usePersisted.ts +19 -8
  610. package/src/composables/usePillTransition.ts +21 -13
  611. package/src/composables/usePointerFrame.ts +72 -0
  612. package/src/composables/useReducedMotion.ts +22 -0
  613. package/src/composables/useRepeater.ts +44 -0
  614. package/src/composables/useResizeObserver.ts +59 -0
  615. package/src/composables/useRevealedValue.ts +84 -0
  616. package/src/composables/useScramble.ts +152 -0
  617. package/src/composables/useShift.ts +10 -16
  618. package/src/composables/useSpotlight.ts +82 -0
  619. package/src/composables/useTilt.ts +40 -23
  620. package/src/composables/useTween.ts +149 -0
  621. package/src/composables/useView.ts +93 -0
  622. package/src/index.css +1 -0
  623. package/src/index.ts +143 -1
  624. package/src/kit-icons.ts +1 -1
  625. package/src/theme/define.ts +65 -0
  626. package/src/theme/studio.ts +202 -0
  627. package/src/tokens/effects.css +151 -0
  628. package/src/tokens/tokens.css +131 -39
  629. package/src/tokens/utilities.css +81 -0
  630. package/dist/assets/LpTabs-Bk7v4bZz.css +0 -18
  631. package/dist/chunks/LpAlert-BdvxvcWE.js +0 -85
  632. package/dist/chunks/LpBadge-Fe0D1bYx.js +0 -62
  633. package/dist/chunks/LpBreadcrumbs-rzOKkLiI.js +0 -98
  634. package/dist/chunks/LpDatePicker-BMfM454Y.js +0 -243
  635. package/dist/chunks/LpDateRangePicker-CNb9X3eL.js +0 -195
  636. package/dist/chunks/LpNumberField-DO1ufKvE.js +0 -107
  637. package/dist/chunks/LpStepper-C2slwObu.js +0 -90
  638. package/dist/chunks/LpSwitch-CZy9_IoA.js +0 -132
  639. package/dist/chunks/LpThemeSwitcher-CDoziW0z.js +0 -166
  640. package/dist/chunks/TourCard-BKI7X9-r.js +0 -105
@@ -17,11 +17,12 @@ export default { inheritAttrs: false }
17
17
  * value either way).
18
18
  */
19
19
  import { ProgressIndicator, ProgressRoot } from "reka-ui"
20
- import { computed, onBeforeUnmount, ref, watch } from "vue"
21
- import { easeOut, prefersReducedMotion } from "../composables/easing"
20
+ import { computed } from "vue"
22
21
  import { useMergedAttrs } from "../composables/useMergedClass"
23
- import { useReveal } from "../composables/useReveal"
22
+ import { useRevealedValue } from "../composables/useRevealedValue"
24
23
  import LpNumberFlow from "./LpNumberFlow.vue"
24
+ import { capacityThresholds, METER_HEADER, METER_TRACK, meterFraction, toneAt } from "./meter"
25
+ import { toneLook, type ToneName } from "./tone"
25
26
 
26
27
  const props = withDefaults(
27
28
  defineProps<{
@@ -35,8 +36,11 @@ const props = withDefaults(
35
36
  * different at 92% than at 12%, and consumers were each re-deriving that
36
37
  * with their own palette — which also put raw colours back into components
37
38
  * the theme can no longer reach.
39
+ *
40
+ * Any of the kit's tone names works (tone.ts): `success`/`warning` read the
41
+ * same as `action`/`accent`.
38
42
  */
39
- tone?: "brand" | "action" | "danger" | "accent" | "auto"
43
+ tone?: ToneName | "auto"
40
44
  /** `auto` tone: the fill fraction, 0–1, where the bar turns accent. */
41
45
  warnAt?: number
42
46
  /** `auto` tone: the fill fraction, 0–1, where it turns danger. */
@@ -105,44 +109,9 @@ const props = withDefaults(
105
109
  * gap to the other end. Interpolating here and handing both the same number
106
110
  * keeps them exactly level, because there is only one number.
107
111
  */
108
- /*
109
- * `shown` is the position on screen, and it is the thing that is animated —
110
- * not a phase that something else multiplies by.
111
- *
112
- * The earlier shape kept an eased 0..1 and derived the position from it and a
113
- * `from` captured in the watcher. That could not work: `from` was read off a
114
- * computed over `props.value`, so by the time the watcher ran it already
115
- * reported the DESTINATION, and every sweep after the first interpolated from
116
- * the answer to the answer. The entrance still animated, which is what made
117
- * the bug look like a decision — the bar filled beautifully once and jumped
118
- * forever after.
119
- *
120
- * Animating the position directly removes the question. Wherever the bar is is
121
- * where the next sweep starts, including one that interrupts another midway.
122
- */
123
- const shown = ref(props.animateOnMount ? 0 : props.value)
124
- let raf = 0
125
-
126
- const runSweep = (to: number, ms: number) => {
127
- if (raf) cancelAnimationFrame(raf)
128
- const from = shown.value
129
- if (prefersReducedMotion() || ms <= 0 || from === to) {
130
- shown.value = to
131
- return
132
- }
133
- const t0 = performance.now()
134
- const step = (now: number) => {
135
- const t = Math.min(1, (now - t0) / ms)
136
- // The kit's shared curve — the same function LpNumberFlow eases on, so the
137
- // arc and the counter agree by construction rather than by comment.
138
- shown.value = from + (to - from) * easeOut(t)
139
- raf = t < 1 ? requestAnimationFrame(step) : 0
140
- }
141
- raf = requestAnimationFrame(step)
142
- }
143
-
144
- onBeforeUnmount(() => {
145
- if (raf) cancelAnimationFrame(raf)
112
+ const { el: revealAnchor, shown } = useRevealedValue(() => props.value, {
113
+ animateOnMount: () => props.animateOnMount,
114
+ duration: () => props.duration,
146
115
  })
147
116
 
148
117
  /*
@@ -154,26 +123,10 @@ onBeforeUnmount(() => {
154
123
  * reka's ProgressRoot is a component, so the ref holds an instance; take its
155
124
  * host element to observe.
156
125
  */
157
- const { el: revealAnchor, revealed } = useReveal({ immediate: () => !props.animateOnMount })
158
-
159
126
  const bindReveal = (instance: unknown) => {
160
127
  revealAnchor.value = (instance as { $el?: Element } | null)?.$el ?? null
161
128
  }
162
129
 
163
- watch(
164
- revealed,
165
- (visible) => {
166
- if (visible && props.animateOnMount) runSweep(props.value, props.duration)
167
- },
168
- { immediate: true },
169
- )
170
-
171
- /* A later change eases to the new value from wherever the bar stands. */
172
- watch(
173
- () => [props.value, props.max],
174
- () => runSweep(props.value, props.duration),
175
- )
176
-
177
130
  // A zero or missing max (no quota known yet) reads as empty, not as NaN%.
178
131
  const pct = computed(() => {
179
132
  const ratio = props.max > 0 ? (shown.value / props.max) * 100 : 0
@@ -181,19 +134,18 @@ const pct = computed(() => {
181
134
  })
182
135
 
183
136
  /*
184
- * The tone actually painted. `auto` reads the fill and crosses two thresholds;
185
- * every other value passes straight through.
137
+ * The tone actually painted. `auto` reads the fill against the capacity scale
138
+ * LpGauge and LpQuota use (meter.ts), so a bar and a gauge showing one disk
139
+ * turn amber at the same point; every other value passes straight through.
186
140
  *
187
141
  * Thresholds are compared against the TARGET, not the animated position, so a
188
142
  * bar does not change colour partway through its own sweep — it fills in the
189
143
  * colour its reading warrants.
190
144
  */
191
145
  const paintedTone = computed(() => {
192
- if (props.tone !== "auto") return props.tone
193
- const fraction = props.max > 0 ? props.value / props.max : 0
194
- if (fraction >= props.dangerAt) return "danger"
195
- if (fraction >= props.warnAt) return "accent"
196
- return "action"
146
+ if (props.tone !== "auto") return toneLook(props.tone)
147
+ const fraction = meterFraction(props.value, 0, props.max)
148
+ return toneLook(toneAt(fraction, capacityThresholds(0, 1, props.warnAt, props.dangerAt)))
197
149
  })
198
150
 
199
151
  const captionText = computed(() => {
@@ -201,20 +153,6 @@ const captionText = computed(() => {
201
153
  return typeof props.caption === "string" ? props.caption : `${Math.round(pct.value)}%`
202
154
  })
203
155
 
204
- const bar: Record<string, string> = {
205
- brand: "bg-brand",
206
- action: "bg-action",
207
- danger: "bg-danger",
208
- accent: "bg-accent",
209
- }
210
-
211
- const stroke: Record<string, string> = {
212
- brand: "var(--color-brand)",
213
- action: "var(--color-action)",
214
- danger: "var(--color-danger)",
215
- accent: "var(--color-accent)",
216
- }
217
-
218
156
  /*
219
157
  * The arc is drawn by dashing the circumference: one dash as long as the filled
220
158
  * fraction, one gap covering the rest. Rotated -90° so it starts at twelve
@@ -235,7 +173,7 @@ const dash = computed(() => {
235
173
  return Math.min(raw, full - props.thickness * 1.5)
236
174
  })
237
175
 
238
- const BAR_TRACK = "h-1.5 w-full overflow-hidden rounded-pill bg-surface-soft"
176
+ const BAR_TRACK = `${METER_TRACK} overflow-hidden`
239
177
 
240
178
  /*
241
179
  * The consumer's class lands on whichever element is the outside of the
@@ -280,7 +218,7 @@ const staticCaption = computed(() =>
280
218
  :cy="size / 2"
281
219
  :r="radius"
282
220
  fill="none"
283
- :stroke="stroke[paintedTone]"
221
+ :stroke="paintedTone.color"
284
222
  :stroke-width="thickness"
285
223
  stroke-linecap="round"
286
224
  :stroke-dasharray="`${dash} ${circumference - dash}`"
@@ -307,7 +245,7 @@ const staticCaption = computed(() =>
307
245
  <!-- Wrapped only when there is a header to carry. A bare bar stays the single
308
246
  element it has always been, so an existing caller's layout is untouched. -->
309
247
  <div v-else-if="title || captionText" :class="rootClass" v-bind="rest">
310
- <div class="flex items-baseline justify-between gap-2 text-xs">
248
+ <div :class="METER_HEADER" class="gap-2 text-xs">
311
249
  <span class="text-muted">{{ title }}</span>
312
250
  <!-- Tabular, so a figure ticking upward doesn't shuffle its own width. -->
313
251
  <span class="font-mono tabular-nums text-muted-strong">{{ captionText }}</span>
@@ -320,7 +258,7 @@ const staticCaption = computed(() =>
320
258
  >
321
259
  <ProgressIndicator
322
260
  class="h-full rounded-pill transition-colors duration-medium"
323
- :class="bar[paintedTone]"
261
+ :class="paintedTone.bg"
324
262
  :style="{ width: `${pct}%` }"
325
263
  />
326
264
  </ProgressRoot>
@@ -336,7 +274,7 @@ const staticCaption = computed(() =>
336
274
  >
337
275
  <ProgressIndicator
338
276
  class="h-full rounded-pill transition-colors duration-medium"
339
- :class="bar[paintedTone]"
277
+ :class="paintedTone.bg"
340
278
  :style="{ width: `${pct}%` }"
341
279
  />
342
280
  </ProgressRoot>
@@ -0,0 +1,197 @@
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
+ * "Used of limit": storage, seats, API calls. A header with the reading, a bar,
10
+ * and a line saying what is left, with the tone rising as the limit nears.
11
+ *
12
+ * The bar is drawn here rather than borrowed from LpProgress. LpProgress shows
13
+ * one fraction clamped to full, which is right for progress and wrong for a
14
+ * quota on two counts: a quota is often made of parts (a stacked bar), and an
15
+ * exceeded quota has to SHOW the excess. Here the bar stretches to hold what is
16
+ * used and the limit becomes a mark along it, so 12 of 10 GB reads as a bar
17
+ * running past a line instead of as a full bar indistinguishable from 10 of 10.
18
+ * The tone scale, the track and the header row are LpProgress's (meter.ts), so
19
+ * the two agree on one disk and look like one family.
20
+ */
21
+ import { computed } from "vue"
22
+ import { useLabels } from "../composables/useLpConfig"
23
+ import { useLocale } from "../composables/useLocale"
24
+ import { useMergedAttrs } from "../composables/useMergedClass"
25
+ import { useRevealedValue } from "../composables/useRevealedValue"
26
+ import LpIcon from "./LpIcon.vue"
27
+ import LpNumberFlow from "./LpNumberFlow.vue"
28
+ import LpRollingText from "./LpRollingText.vue"
29
+ import { METER_HEADER, METER_TRACK } from "./meter"
30
+ import { formatAmount, quotaSegments, quotaState, type QuotaPart, type QuotaUnit } from "./quota"
31
+ import { toneLook } from "./tone"
32
+
33
+ export type QuotaLabels = {
34
+ /** `{amount}` is what remains. */
35
+ left: string
36
+ /** `{amount}` is the excess. */
37
+ over: string
38
+ /** Shown instead of what remains when there is no limit. */
39
+ unlimited: string
40
+ /** The spoken reading, followed by what is left or over. `{used}`, `{limit}`. */
41
+ reading: string
42
+ }
43
+
44
+ const props = withDefaults(
45
+ defineProps<{
46
+ used: number
47
+ /** Unset, zero or Infinity means unlimited: the reading stays, the bar and "left" go. */
48
+ limit?: number | null
49
+ /** What is counted ("Storage", "Seats"). Also the accessible name. */
50
+ label?: string
51
+ /** `"bytes"`, a plain suffix ("seats"), or a formatter. See `formatAmount`. */
52
+ unit?: QuotaUnit
53
+ /**
54
+ * What the used amount is made of. The bar stacks them and a legend names
55
+ * them; their sum need not equal `used` (a part can be left unlisted), but
56
+ * the bar shows the parts, so list them all if the bar should add up.
57
+ */
58
+ parts?: QuotaPart[]
59
+ /** Share of the limit (0–1) where the quota turns warning. */
60
+ warnAt?: number
61
+ /** Share of the limit where it turns danger. Over the limit is always danger. */
62
+ dangerAt?: number
63
+ /** Hide the legend under a stacked bar, for a compact row where the tooltip of the page says enough. */
64
+ hideLegend?: boolean
65
+ /** Fill from empty when first seen. */
66
+ animateOnMount?: boolean
67
+ locale?: string
68
+ labels?: Partial<QuotaLabels>
69
+ }>(),
70
+ { limit: null, warnAt: 0.8, dangerAt: 0.9, hideLegend: false, animateOnMount: true },
71
+ )
72
+
73
+ const text = useLabels<QuotaLabels>(
74
+ "quota",
75
+ {
76
+ left: "{amount} left",
77
+ over: "{amount} over the limit",
78
+ unlimited: "No limit",
79
+ reading: "{used} of {limit} used",
80
+ },
81
+ () => props.labels,
82
+ )
83
+ const locale = useLocale(() => props.locale)
84
+
85
+ const state = computed(() => quotaState(props.used, props.limit, props.warnAt, props.dangerAt))
86
+ const look = computed(() => toneLook(state.value.tone))
87
+ const fmt = (v: number) => formatAmount(v, props.unit, locale.value)
88
+
89
+ /*
90
+ * Without parts the used amount is one part in the tone it earns, so a single
91
+ * bar and a stacked one share the layout, the overflow mark and the motion.
92
+ */
93
+ const layout = computed(() =>
94
+ quotaSegments(
95
+ props.parts?.length ? props.parts : [{ label: props.label ?? "", value: props.used, color: look.value.color }],
96
+ props.limit,
97
+ ),
98
+ )
99
+
100
+ // The bar's segments ease in CSS and the figure rolls in LpNumberFlow, so only the held value is needed here.
101
+ const { el: revealAnchor, revealed, target: shownUsed } = useRevealedValue(() => props.used, {
102
+ animateOnMount: () => props.animateOnMount,
103
+ })
104
+
105
+ const footer = computed(() => {
106
+ const s = state.value
107
+ if (!s.limited) return text.value.unlimited
108
+ if (s.over > 0) return text.value.over.replace("{amount}", fmt(s.over))
109
+ return text.value.left.replace("{amount}", fmt(s.remaining))
110
+ })
111
+
112
+ /* Spoken: the reading, then the same verdict the footer shows. */
113
+ const valueText = computed(() =>
114
+ state.value.limited
115
+ ? `${text.value.reading.replace("{used}", fmt(props.used)).replace("{limit}", fmt(props.limit as number))}, ${footer.value}`
116
+ : `${fmt(props.used)}, ${text.value.unlimited}`,
117
+ )
118
+
119
+ // Ink while the reading is fine: a calm quota should not be coloured at all.
120
+ const readingTone = computed(() => (state.value.tone === "ok" ? "text-ink" : look.value.text))
121
+
122
+ const { class: rootClass, attrs: rest } = useMergedAttrs("flex w-full flex-col gap-1.5")
123
+ </script>
124
+
125
+ <template>
126
+ <div
127
+ :ref="(el) => (revealAnchor = el as Element | null)"
128
+ :role="state.limited ? 'meter' : 'group'"
129
+ :aria-valuenow="state.limited ? used : undefined"
130
+ :aria-valuemin="state.limited ? 0 : undefined"
131
+ :aria-valuemax="state.limited ? (limit as number) : undefined"
132
+ :aria-valuetext="state.limited ? valueText : undefined"
133
+ :aria-label="label"
134
+ :class="rootClass"
135
+ v-bind="rest"
136
+ >
137
+ <div :class="METER_HEADER" class="gap-3 text-sm">
138
+ <span v-if="label" class="truncate text-ink">{{ label }}</span>
139
+ <span class="ml-auto shrink-0 font-mono text-xs tabular-nums text-muted">
140
+ <LpNumberFlow
141
+ :value="shownUsed"
142
+ :format="fmt"
143
+ :animate-on-mount="false"
144
+ class="transition-colors duration-(--duration-medium)"
145
+ :class="readingTone"
146
+ />
147
+ <template v-if="state.limited">
148
+ <span class="px-1">/</span>
149
+ <LpNumberFlow :value="limit as number" :format="fmt" :animate-on-mount="false" />
150
+ </template>
151
+ </span>
152
+ </div>
153
+
154
+ <div
155
+ v-if="state.limited || parts?.length"
156
+ class="relative"
157
+ :class="METER_TRACK"
158
+ aria-hidden="true"
159
+ >
160
+ <div class="flex h-full w-full gap-px overflow-hidden rounded-pill">
161
+ <span
162
+ v-for="seg in layout.segments"
163
+ :key="seg.label"
164
+ class="h-full shrink-0 transition-[width,background-color] duration-700 ease-(--ease-emphasized) motion-reduce:transition-none"
165
+ :style="{ width: revealed ? `${seg.share * 100}%` : '0%', backgroundColor: seg.color }"
166
+ />
167
+ </div>
168
+ <!-- The limit, once the bar has run past it. Taller than the track so it
169
+ reads as a line across the bar, not as one more part. -->
170
+ <span
171
+ class="absolute -inset-y-1 w-0.5 -translate-x-1/2 rounded-pill bg-ink transition-[left,opacity] duration-700 ease-(--ease-emphasized) motion-reduce:transition-none"
172
+ :style="{ left: `${(layout.limitAt ?? 1) * 100}%`, opacity: layout.limitAt != null && revealed ? 1 : 0 }"
173
+ />
174
+ </div>
175
+
176
+ <div
177
+ class="flex items-center gap-1 text-xs transition-colors duration-(--duration-medium)"
178
+ :class="state.over > 0 ? look.text : 'text-muted'"
179
+ >
180
+ <LpIcon
181
+ name="lucide:triangle-alert"
182
+ :size="12"
183
+ class="shrink-0 transition-[opacity,width] duration-(--duration-medium)"
184
+ :class="state.over > 0 ? 'w-3 opacity-100' : 'w-0 opacity-0'"
185
+ />
186
+ <LpRollingText :value="footer" align="start" />
187
+ </div>
188
+
189
+ <ul v-if="parts?.length && !hideLegend" class="mt-1 flex flex-wrap gap-x-4 gap-y-1 text-xs text-muted">
190
+ <li v-for="seg in layout.segments" :key="seg.label" class="flex items-center gap-1.5">
191
+ <span class="size-2 shrink-0 rounded-full" :style="{ backgroundColor: seg.color }" />
192
+ <span>{{ seg.label }}</span>
193
+ <span class="font-mono tabular-nums text-muted-strong">{{ fmt(seg.value) }}</span>
194
+ </li>
195
+ </ul>
196
+ </div>
197
+ </template>
@@ -16,6 +16,7 @@ export default { inheritAttrs: false }
16
16
  import { SliderRange, SliderRoot, SliderThumb, SliderTrack } from "reka-ui"
17
17
  import { useFieldControl } from "../composables/useField"
18
18
  import { useMergedAttrs } from "../composables/useMergedClass"
19
+ import { SLIDER_GLIDE, useSliderDrag } from "./slider"
19
20
 
20
21
  const props = withDefaults(
21
22
  defineProps<{
@@ -56,8 +57,9 @@ function onCommit(v: number[] | undefined) {
56
57
  const field = useFieldControl(() => ({ wrapped: false, disabled: props.disabled }))
57
58
 
58
59
  const { class: rootClass, attrs: rest } = useMergedAttrs(
59
- "relative flex h-5 w-full touch-none select-none items-center data-[disabled]:opacity-55",
60
+ `relative flex h-5 w-full touch-none select-none items-center data-[disabled]:opacity-55 ${SLIDER_GLIDE}`,
60
61
  )
62
+ const { dragging, onPointerDown } = useSliderDrag()
61
63
 
62
64
  const thumbClass =
63
65
  "group/thumb relative block size-4 rounded-pill border-2 border-brand bg-surface shadow outline-none transition-transform duration-[var(--duration-fast)] ease-[var(--ease-emphasized)] hover:scale-110 active:scale-95 focus-visible:ring-2 focus-visible:ring-ring motion-reduce:hover:scale-100 motion-reduce:active:scale-100"
@@ -75,6 +77,8 @@ const labelClass =
75
77
  :disabled="field.disabled"
76
78
  :class="rootClass"
77
79
  v-bind="rest"
80
+ :data-dragging="dragging || undefined"
81
+ @pointerdown="onPointerDown"
78
82
  @update:model-value="onUpdate"
79
83
  @value-commit="onCommit"
80
84
  >
@@ -0,0 +1,90 @@
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 date said the way people say it ("3 min ago", "in 2 h"), kept true as time
10
+ * passes, with the exact date one hover away.
11
+ *
12
+ * Each instance sleeps until its own text would change (useNow with the
13
+ * formatter's `refreshIn`): a "just now" wakes in seconds, a "last month" once
14
+ * an hour, so a table of old rows costs almost nothing between changes. When
15
+ * the text does change it rolls to the new one, so "4 min ago" becoming
16
+ * "5 min ago" is seen as the same clock moving.
17
+ */
18
+ import { computed } from "vue"
19
+ import { useLocale } from "../composables/useLocale"
20
+ import { useMergedAttrs } from "../composables/useMergedClass"
21
+ import { useNow } from "../composables/useNow"
22
+ import LpRollingText from "./LpRollingText.vue"
23
+ import LpTooltip from "./LpTooltip.vue"
24
+ import { formatRelativeTime } from "./relativeTime"
25
+ import { toEpoch } from "./timeSpan"
26
+
27
+ const props = withDefaults(
28
+ defineProps<{
29
+ /** A Date, an ISO string or epoch milliseconds. */
30
+ date: Date | string | number
31
+ /** Intl's width: `long` "3 minutes ago", `short` "3 min. ago", `narrow` "3m ago". */
32
+ format?: Intl.RelativeTimeFormatStyle
33
+ /** Within this many ms of now it reads "now" rather than counting seconds. */
34
+ nowWithin?: number
35
+ /**
36
+ * Show the exact date on hover and focus. Off, it moves to the native
37
+ * `title` instead, for a dense log where tooltips would get in the way of
38
+ * reading; it is never shown both ways at once, which would stack two
39
+ * hints on one hover.
40
+ */
41
+ tooltip?: boolean
42
+ /** How the exact date is written. Defaults to the full date with the time. */
43
+ absolute?: Intl.DateTimeFormatOptions
44
+ locale?: string
45
+ }>(),
46
+ { format: "long", tooltip: true, nowWithin: 45_000 },
47
+ )
48
+
49
+ const locale = useLocale(() => props.locale)
50
+ const at = computed(() => toEpoch(props.date))
51
+ const options = computed(() => ({ locale: locale.value, style: props.format, nowWithin: props.nowWithin }))
52
+
53
+ /*
54
+ * The clock wakes only when this text would change (`refreshIn`): a "just
55
+ * now" in seconds, a "last month" once an hour, nothing while the tab is
56
+ * hidden. A new date or wording reschedules it, since the wait planned for the
57
+ * old one may be far too long for the new.
58
+ */
59
+ const now = useNow(true, {
60
+ nextIn: (t) => formatRelativeTime(at.value, t, options.value).refreshIn,
61
+ restartOn: () => [at.value, locale.value, props.format, props.nowWithin],
62
+ })
63
+ const reading = computed(() => formatRelativeTime(at.value, now.value, options.value))
64
+
65
+ const exact = computed(() => {
66
+ if (!Number.isFinite(at.value)) return ""
67
+ return new Intl.DateTimeFormat(locale.value, props.absolute ?? { dateStyle: "full", timeStyle: "short" }).format(at.value)
68
+ })
69
+ const iso = computed(() => (Number.isFinite(at.value) ? new Date(at.value).toISOString() : undefined))
70
+
71
+ const { class: rootClass, attrs: rest } = useMergedAttrs("inline-flex whitespace-nowrap tabular-nums")
72
+ </script>
73
+
74
+ <template>
75
+ <LpTooltip v-if="tooltip && exact" :content="exact">
76
+ <!-- Focusable, so the exact date is reachable from the keyboard too; the
77
+ tooltip is a description, the relative text stays the name. -->
78
+ <time
79
+ :datetime="iso"
80
+ tabindex="0"
81
+ :class="[rootClass, 'rounded-[3px] outline-none focus-visible:ring-2 focus-visible:ring-ring']"
82
+ v-bind="rest"
83
+ >
84
+ <LpRollingText :value="reading.text" align="start" />
85
+ </time>
86
+ </LpTooltip>
87
+ <time v-else :datetime="iso" :title="exact || undefined" :class="rootClass" v-bind="rest">
88
+ <LpRollingText :value="reading.text" align="start" />
89
+ </time>
90
+ </template>
@@ -0,0 +1,80 @@
1
+ <script setup lang="ts" generic="T extends object">
2
+ import { nextTick, ref } from "vue"
3
+ import { useFieldControl } from "../composables/useField"
4
+ import { useLabels } from "../composables/useLpConfig"
5
+ import { useMergedAttrs } from "../composables/useMergedClass"
6
+ import { useRepeater, type RepeaterItemKey } from "../composables/useRepeater"
7
+ import LpButton from "./LpButton.vue"
8
+ import LpIcon from "./LpIcon.vue"
9
+
10
+ defineOptions({ inheritAttrs: false })
11
+ const props = defineProps<{
12
+ /** Return a fresh item when Add is pressed. Data and validation remain the caller's. */
13
+ createItem: () => T
14
+ /** Stable business key for immutable reloads; omitted, object identity keeps unsaved rows stable. */
15
+ itemKey?: RepeaterItemKey<T>
16
+ label?: string
17
+ disabled?: boolean
18
+ labels?: Partial<{ add: string; remove: string; empty: string }>
19
+ }>()
20
+ const model = defineModel<T[]>({ default: () => [] })
21
+ defineSlots<{
22
+ default?(props: { item: T; index: number; disabled: boolean; update: (item: T) => void; remove: () => void }): unknown
23
+ empty?(): unknown
24
+ }>()
25
+
26
+ const field = useFieldControl(() => ({ wrapped: false, disabled: props.disabled }))
27
+ const text = useLabels("repeater", { add: "Add item", remove: "Remove item {index}", empty: "No items" }, () => props.labels)
28
+ const list = useRepeater({
29
+ value: () => model.value,
30
+ set: (items) => { model.value = items },
31
+ createItem: () => props.createItem(),
32
+ itemKey: () => props.itemKey,
33
+ disabled: () => field.value.disabled,
34
+ })
35
+ const { rows } = list
36
+ const root = ref<HTMLElement | null>(null)
37
+ const addButton = ref<InstanceType<typeof LpButton> | null>(null)
38
+ const focusable = 'input:not([type="hidden"]):not([disabled]), textarea:not([disabled]), select:not([disabled]), button:not([disabled]), [tabindex="0"], [contenteditable="true"]'
39
+ function focusRow(index: number) {
40
+ root.value?.querySelectorAll<HTMLElement>("[data-lp-repeater-row]")[index]?.querySelector<HTMLElement>(focusable)?.focus()
41
+ }
42
+ async function add() {
43
+ if (field.value.disabled) return
44
+ list.add()
45
+ await nextTick()
46
+ focusRow(model.value.length - 1)
47
+ }
48
+ async function remove(index: number) {
49
+ if (field.value.disabled) return
50
+ const row = root.value?.querySelectorAll<HTMLElement>("[data-lp-repeater-row]")[index]
51
+ const restore = row?.contains(row.ownerDocument.activeElement)
52
+ list.remove(index)
53
+ if (!restore) return
54
+ await nextTick()
55
+ if (model.value.length) focusRow(Math.min(index, model.value.length - 1))
56
+ else (addButton.value?.$el as HTMLElement | undefined)?.focus()
57
+ }
58
+ defineExpose({ add, remove, update: list.update })
59
+ const { class: rootClass, attrs: rest } = useMergedAttrs("flex min-w-0 flex-col gap-2")
60
+ </script>
61
+
62
+ <template>
63
+ <div ref="root" v-bind="rest" :class="rootClass">
64
+ <div class="flex items-center justify-between gap-2">
65
+ <span v-if="label" class="text-sm font-medium text-ink">{{ label }}</span>
66
+ <LpButton ref="addButton" size="xs" variant="ghost" :disabled="field.disabled" @click="add">
67
+ <LpIcon name="lucide:plus" :size="14" />{{ text.add }}
68
+ </LpButton>
69
+ </div>
70
+ <div v-for="({ item, key }, index) in rows" :key="key" data-lp-repeater-row class="flex min-w-0 items-start gap-2">
71
+ <div class="min-w-0 flex-1">
72
+ <slot :item="item" :index="index" :disabled="field.disabled" :update="(next: T) => list.update(index, next)" :remove="() => remove(index)" />
73
+ </div>
74
+ <LpButton variant="ghost" size="sm" square :disabled="field.disabled" :aria-label="text.remove.replace('{index}', String(index + 1))" @click="remove(index)">
75
+ <LpIcon name="lucide:x" :size="14" />
76
+ </LpButton>
77
+ </div>
78
+ <div v-if="!rows.length" class="text-xs text-muted"><slot name="empty">{{ text.empty }}</slot></div>
79
+ </div>
80
+ </template>