@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
@@ -1,5 +1,5 @@
1
- import { useReducedMotion } from "motion-v"
2
1
  import { computed, type ComputedRef } from "vue"
2
+ import { usePrefersReducedMotion } from "./useReducedMotion"
3
3
 
4
4
  /*
5
5
  * Shared motion-v transition for an element that FLIES to a new position rather
@@ -8,27 +8,32 @@ import { computed, type ComputedRef } from "vue"
8
8
  * tooltip trailing the cursor. One spring per feel keeps them consistent, and
9
9
  * every preset collapses to an instant move when the OS prefers reduced motion.
10
10
  *
11
- * Two feels, because the two jobs want opposite things:
11
+ * Three feels, because the jobs want different things:
12
12
  *
13
- * "pill" — snappy. The move is a direct answer to a click, so it should read
14
- * as already-arrived: high stiffness, almost no visible travel.
15
- * "float" — trailing. The element chases a continuously moving pointer, so it
16
- * wants perceptible lag and a soft landing; a pill-stiff spring
17
- * tracks the cursor so exactly that it reads as jitter, not motion.
13
+ * "pill" — snappy. The move is a direct answer to a click, so it should read
14
+ * as already-arrived: high stiffness, almost no visible travel.
15
+ * "float" — trailing. The element chases a continuously moving pointer, so it
16
+ * wants perceptible lag and a soft landing; a pill-stiff spring
17
+ * tracks the cursor so exactly that it reads as jitter, not motion.
18
+ * "layout" — a box resizing or a block moving to a new place (motion-v
19
+ * `layout`): LpTabs' panel height, a block dropped in LayoutCanvas.
20
+ * As quick as the pill, a touch more damped and lighter, so a
21
+ * large box lands without a wobble at its edge.
18
22
  */
19
23
  export type PillTransition =
20
24
  | { duration: number }
21
- | { type: "spring"; stiffness: number; damping: number }
25
+ | { type: "spring"; stiffness: number; damping: number; mass?: number }
22
26
 
23
- export type PillFeel = "pill" | "float"
27
+ export type PillFeel = "pill" | "float" | "layout"
24
28
 
25
- const SPRING: Record<PillFeel, { type: "spring"; stiffness: number; damping: number }> = {
29
+ const SPRING: Record<PillFeel, { type: "spring"; stiffness: number; damping: number; mass?: number }> = {
26
30
  pill: { type: "spring", stiffness: 520, damping: 40 },
27
31
  float: { type: "spring", stiffness: 210, damping: 26 },
32
+ layout: { type: "spring", stiffness: 520, damping: 42, mass: 0.9 },
28
33
  }
29
34
 
30
35
  export function usePillTransition(feel: PillFeel = "pill"): ComputedRef<PillTransition> {
31
- const reduceMotion = useReducedMotion()
36
+ const reduceMotion = usePrefersReducedMotion()
32
37
  return computed<PillTransition>(() =>
33
38
  reduceMotion.value ? { duration: 0 } : SPRING[feel],
34
39
  )
@@ -51,7 +56,10 @@ export function usePillTransition(feel: PillFeel = "pill"): ComputedRef<PillTran
51
56
  * matched by feel and kept beside their motion-v counterparts so that a change
52
57
  * to one is an obvious prompt to check the other.
53
58
  */
54
- const STEP_SPRING: Record<PillFeel, { stiffness: number; damping: number }> = {
59
+ /** The feels a pointer follower uses; "layout" is a motion-v layout move only. */
60
+ export type StepFeel = Exclude<PillFeel, "layout">
61
+
62
+ const STEP_SPRING: Record<StepFeel, { stiffness: number; damping: number }> = {
55
63
  // Critically damped: reaches the target quickly, never past it.
56
64
  pill: { stiffness: 420, damping: 41 },
57
65
  float: { stiffness: 260, damping: 32 },
@@ -67,7 +75,7 @@ export interface SpringState {
67
75
  export function springStep(
68
76
  state: SpringState,
69
77
  target: number,
70
- feel: PillFeel = "float",
78
+ feel: StepFeel = "float",
71
79
  /** Frame time in seconds; clamped so a backgrounded tab can't explode it. */
72
80
  dt = 1 / 60,
73
81
  ): SpringState {
@@ -0,0 +1,72 @@
1
+ import { onScopeDispose, toValue, type MaybeRefOrGetter } from "vue"
2
+ import { prefersReducedMotion } from "./easing"
3
+
4
+ /*
5
+ * The scaffolding of a decoration that follows the pointer (LpMagnetic's
6
+ * pull, the spotlight glow, LpTilt's lean): take the latest pointer position,
7
+ * and paint from it once per animation frame.
8
+ *
9
+ * pointermove fires faster than frames, and a re-render per event for a
10
+ * decoration is the kind of cost the launcher on WebKitGTK actually feels. So
11
+ * nothing here is reactive: `move` records the position and asks for a frame,
12
+ * `paint` runs in that frame with the latest one, and writes straight to the
13
+ * element (a style property, a custom property). The three effects had this
14
+ * written out each, with the same filters in slightly different orders.
15
+ *
16
+ * Who listens is the caller's: the spotlight listens on its own element, the
17
+ * magnet on its window (its field reaches past its edges), the tilt through
18
+ * handlers its consumer binds. They all feed `move`.
19
+ *
20
+ * Touch and pen are ignored unless `anyPointer`: there is no hover to follow,
21
+ * and an effect that jumps to wherever a finger landed reads as a pressed
22
+ * state that is not one. Reduced motion and `disabled` drop moves entirely.
23
+ */
24
+ export interface PointerFrameOptions {
25
+ /** Paint with the latest pointer position, in client coordinates. */
26
+ paint: (x: number, y: number) => void
27
+ /** Drop moves while true; the caller decides what "off" looks like. */
28
+ disabled?: MaybeRefOrGetter<boolean | undefined>
29
+ /** Follow touch and pen too, not only a mouse. */
30
+ anyPointer?: boolean
31
+ }
32
+
33
+ export interface PointerFrame {
34
+ /** Feed a pointer event. False when it was dropped (touch, reduced motion, disabled). */
35
+ move: (event: PointerEvent) => boolean
36
+ /** Paint at a given position on the next frame, as if the pointer were there (a pointer that left the window). */
37
+ moveTo: (x: number, y: number) => void
38
+ /** Drop a frame that has been asked for but not painted yet. */
39
+ cancel: () => void
40
+ }
41
+
42
+ export function usePointerFrame(options: PointerFrameOptions): PointerFrame {
43
+ let frame = 0
44
+ let lastX = 0
45
+ let lastY = 0
46
+
47
+ const run = () => {
48
+ frame = 0
49
+ options.paint(lastX, lastY)
50
+ }
51
+
52
+ const moveTo = (x: number, y: number) => {
53
+ lastX = x
54
+ lastY = y
55
+ if (!frame) frame = requestAnimationFrame(run)
56
+ }
57
+
58
+ const move = (event: PointerEvent): boolean => {
59
+ if (!options.anyPointer && event.pointerType !== "mouse") return false
60
+ if (toValue(options.disabled) || prefersReducedMotion()) return false
61
+ moveTo(event.clientX, event.clientY)
62
+ return true
63
+ }
64
+
65
+ const cancel = () => {
66
+ if (frame) cancelAnimationFrame(frame)
67
+ frame = 0
68
+ }
69
+
70
+ onScopeDispose(cancel)
71
+ return { move, moveTo, cancel }
72
+ }
@@ -0,0 +1,22 @@
1
+ import type { Ref } from "vue"
2
+ import { useMediaQuery } from "./useMediaQuery"
3
+
4
+ /*
5
+ * `prefersReducedMotion()` as a ref, for a component that has to RE-RENDER
6
+ * when the setting changes mid-session (a spring that becomes an instant move,
7
+ * a tilt that goes flat), not just read it when an animation starts.
8
+ *
9
+ * The kit had two sources for this question: the plain function in easing.ts
10
+ * and motion-v's `useReducedMotion`, picked per file. Both read the same media
11
+ * query, so this is the one reactive answer and the function stays the one
12
+ * point-in-time answer. motion-v's hook adds nothing the kit needs: motion-v
13
+ * does not consult it for its own layout animations (every caller had to turn
14
+ * a spring into `{ duration: 0 }` itself), and it reads the page's window, where
15
+ * this asks the window the component renders in (an LpFrame's, say).
16
+ *
17
+ * False until mounted, like every media query here, so a server render and the
18
+ * hydrating client agree; nothing animates before mount anyway.
19
+ */
20
+ export function usePrefersReducedMotion(): Ref<boolean> {
21
+ return useMediaQuery("(prefers-reduced-motion: reduce)")
22
+ }
@@ -0,0 +1,44 @@
1
+ import { computed, toRaw } from "vue"
2
+
3
+ export type RepeaterItemKey<T> = keyof T | ((item: T) => string | number)
4
+
5
+ /** Keys live beside the model: unsaved rows need identity without adding fields to a DTO. */
6
+ export function useRepeater<T extends object>(options: {
7
+ value: () => T[]
8
+ set: (items: T[]) => void
9
+ createItem: () => T
10
+ itemKey: () => RepeaterItemKey<T> | undefined
11
+ disabled: () => boolean
12
+ }) {
13
+ const keys = new WeakMap<object, string>()
14
+ let sequence = 0
15
+
16
+ function keyFor(item: T): string {
17
+ const key = options.itemKey()
18
+ const explicit = typeof key === "function" ? key(item) : key === undefined ? undefined : item[key]
19
+ if (explicit !== undefined && explicit !== null) return `item:${typeof explicit}:${String(explicit)}`
20
+ const raw = toRaw(item)
21
+ if (!keys.has(raw)) keys.set(raw, `local:${sequence++}`)
22
+ return keys.get(raw)!
23
+ }
24
+
25
+ const rows = computed(() => options.value().map((item) => ({ item, key: keyFor(item) })))
26
+
27
+ function add() {
28
+ if (!options.disabled()) options.set([...options.value(), options.createItem()])
29
+ }
30
+
31
+ function remove(index: number) {
32
+ if (options.disabled() || index < 0 || index >= options.value().length) return
33
+ options.set(options.value().filter((_, i) => i !== index))
34
+ }
35
+
36
+ function update(index: number, item: T) {
37
+ const previous = options.value()[index]
38
+ if (options.disabled() || previous === undefined) return
39
+ keys.set(toRaw(item), keyFor(previous))
40
+ options.set(options.value().map((value, i) => i === index ? item : value))
41
+ }
42
+
43
+ return { rows, add, remove, update }
44
+ }
@@ -0,0 +1,59 @@
1
+ import { onScopeDispose, toValue, watch, type MaybeRefOrGetter } from "vue"
2
+
3
+ /*
4
+ * "Tell me when this element changes size", for as long as the component lives.
5
+ *
6
+ * A dozen components wrote the same scaffolding around a ResizeObserver: a
7
+ * variable for it, a guard for engines without one (old WebKitGTK, tests),
8
+ * disconnect-and-reobserve when the element ref changes, disconnect on unmount.
9
+ * Each copy got one of those slightly different, and a missing guard is a crash
10
+ * rather than a style difference. This is that scaffolding once.
11
+ *
12
+ * `target` is a ref or a getter, so the observed element can be a template ref,
13
+ * a component's exposed element or something found from one (the scroll
14
+ * viewport around a table); a new element is observed in place of the old one
15
+ * and `null` stops observing. `immediate` also calls back right when an element
16
+ * is attached, without an entry, for components that must measure before the
17
+ * first paint: the observer's own first report arrives a frame later.
18
+ */
19
+ export interface UseResizeObserverOptions extends ResizeObserverOptions {
20
+ /** Call back once as soon as an element is attached (with no entry), not only on the first report. */
21
+ immediate?: boolean
22
+ }
23
+
24
+ export function useResizeObserver(
25
+ target: MaybeRefOrGetter<Element | null | undefined>,
26
+ callback: (entry: ResizeObserverEntry | undefined, el: Element) => void,
27
+ options: UseResizeObserverOptions = {},
28
+ ): { stop: () => void } {
29
+ const { immediate = false, ...observe } = options
30
+ let observer: ResizeObserver | undefined
31
+
32
+ const disconnect = () => {
33
+ observer?.disconnect()
34
+ observer = undefined
35
+ }
36
+
37
+ const stopWatch = watch(
38
+ () => toValue(target),
39
+ (el) => {
40
+ disconnect()
41
+ if (!el) return
42
+ if (immediate) callback(undefined, el)
43
+ if (typeof ResizeObserver === "undefined") return
44
+ observer = new ResizeObserver((entries) => {
45
+ const entry = entries[entries.length - 1]
46
+ if (entry) callback(entry, el)
47
+ })
48
+ observer.observe(el, observe)
49
+ },
50
+ { immediate: true, flush: "post" },
51
+ )
52
+
53
+ const stop = () => {
54
+ stopWatch()
55
+ disconnect()
56
+ }
57
+ onScopeDispose(stop)
58
+ return { stop }
59
+ }
@@ -0,0 +1,84 @@
1
+ import { computed, ref, toValue, watch, type MaybeRefOrGetter, type Ref } from "vue"
2
+ import { easeOut } from "./easing"
3
+ import { useReveal } from "./useReveal"
4
+ import { lerp, useTween } from "./useTween"
5
+
6
+ /*
7
+ * A number that waits to be seen before it moves to its value.
8
+ *
9
+ * A meter that fills (LpProgress, LpGauge, LpQuota) or a figure that counts up
10
+ * (LpNumberFlow) is showing a quantity being measured, and that only works if
11
+ * the reader sees the sweep. So the number is held at its starting point until
12
+ * the element is revealed (useReveal), then let go to the real value; every
13
+ * change after that goes straight through. Each of those components used to
14
+ * carry this hold-and-release by hand, and they disagreed in the corners: what
15
+ * a value change before the reveal does, and what the server renders.
16
+ */
17
+
18
+ export interface UseRevealedValueOptions {
19
+ /** Where the number starts while held: 0 for a bar, the floor for a gauge. */
20
+ from?: MaybeRefOrGetter<number>
21
+ /** False shows the value at once, with nothing held. */
22
+ animateOnMount?: MaybeRefOrGetter<boolean>
23
+ /**
24
+ * Also tween `shown` toward the target over this many ms (eased out), for a
25
+ * component that draws from one interpolated number. Omitted, `shown` is the
26
+ * target itself, for a component that animates in CSS or through LpNumberFlow.
27
+ */
28
+ duration?: MaybeRefOrGetter<number>
29
+ /**
30
+ * Whether a change that arrives before the reveal waits too (default) or
31
+ * goes through at once. A meter waits, so its first sweep is still seen;
32
+ * LpNumberFlow lets it through, because a figure that changes while the user
33
+ * is on the page is news whether or not it is in view.
34
+ */
35
+ holdChanges?: boolean
36
+ }
37
+
38
+ export interface UseRevealedValue {
39
+ /** Attach to the element whose appearance releases the value. */
40
+ el: Ref<Element | null>
41
+ /** False until that element has been seen. */
42
+ revealed: Ref<boolean>
43
+ /** The value released so far: `from` while held, then the source. */
44
+ target: Readonly<Ref<number>>
45
+ /** What to draw: `target`, tweened when a `duration` is given. */
46
+ shown: Readonly<Ref<number>>
47
+ }
48
+
49
+ export function useRevealedValue(
50
+ value: () => number,
51
+ options: UseRevealedValueOptions = {},
52
+ ): UseRevealedValue {
53
+ const animate = () => toValue(options.animateOnMount) ?? true
54
+ const { el, revealed } = useReveal({ immediate: () => !animate() })
55
+
56
+ /*
57
+ * The server has no viewport, so useReveal reports it revealed; releasing
58
+ * there would render the final value and the client, which starts held,
59
+ * would hydrate a different one. The server renders the starting point and
60
+ * the client releases it once the element is seen.
61
+ */
62
+ const canRelease = () => !animate() || typeof window !== "undefined"
63
+
64
+ const target = ref(animate() ? (toValue(options.from) ?? 0) : value())
65
+
66
+ watch(
67
+ revealed,
68
+ (seen) => {
69
+ if (seen && canRelease()) target.value = value()
70
+ },
71
+ { immediate: true },
72
+ )
73
+ watch(value, (v) => {
74
+ if (revealed.value || options.holdChanges === false) target.value = v
75
+ })
76
+
77
+ const duration = options.duration
78
+ const shown =
79
+ duration === undefined
80
+ ? computed(() => target.value)
81
+ : useTween(() => target.value, lerp, { duration: () => toValue(duration), ease: easeOut })
82
+
83
+ return { el, revealed, target, shown }
84
+ }
@@ -0,0 +1,152 @@
1
+ import { computed, onScopeDispose, shallowRef, toValue, watch, type ComputedRef, type MaybeRefOrGetter, type ShallowRef } from "vue"
2
+ import {
3
+ planScramble,
4
+ scrambleFrame,
5
+ settledCells,
6
+ SCRAMBLE_GLYPHS,
7
+ type Random,
8
+ type ScrambleCell,
9
+ type ScrambleFrameCell,
10
+ } from "../components/scramble"
11
+ import { prefersReducedMotion } from "./easing"
12
+
13
+ /*
14
+ * A value that "decrypts" into place: each position churns through random
15
+ * glyphs and settles on its character.
16
+ *
17
+ * For values that are revealed rather than read: an API key shown after a
18
+ * click, a hash arriving from a job, a code a user is about to copy. The churn
19
+ * says "this was just produced" in a way a plain swap does not.
20
+ *
21
+ * The composable owns the clock; the frames themselves come from the pure
22
+ * functions in components/scramble.ts. It hands back CELLS rather than only a
23
+ * string, because a component that wants the width to hold still needs to know
24
+ * which character each position will end as (LpScramble sizes each cell by it).
25
+ */
26
+
27
+ export interface UseScrambleOptions {
28
+ /** Travel time in ms. */
29
+ duration?: MaybeRefOrGetter<number | undefined>
30
+ /** See ScrambleOptions.order. */
31
+ order?: MaybeRefOrGetter<"sequential" | "together" | undefined>
32
+ /** Glyph pool. */
33
+ glyphs?: MaybeRefOrGetter<string | undefined>
34
+ /** Characters that never churn. Whitespace by default. */
35
+ keep?: (char: string) => boolean
36
+ /**
37
+ * How often a churning position draws a new glyph, in ms. Every frame is too
38
+ * fast to read as anything but noise; ~50 ms looks like a display cycling.
39
+ */
40
+ tick?: number
41
+ /** Scramble when the source changes. Off: a change lands at once and only `play()` scrambles. */
42
+ onChange?: MaybeRefOrGetter<boolean | undefined>
43
+ /**
44
+ * What shows before the first `play()`: the value (`settled`) or a static
45
+ * mask of glyphs (`masked`), for a value that should decrypt on first sight
46
+ * rather than flash its plain text first.
47
+ */
48
+ start?: "settled" | "masked"
49
+ /** Inject for reproducible frames (tests, screenshots). */
50
+ random?: Random
51
+ /** Called when a run lands. */
52
+ onDone?: () => void
53
+ }
54
+
55
+ export interface UseScramble {
56
+ /** The positions as they are drawn now. */
57
+ cells: Readonly<ShallowRef<ScrambleFrameCell[]>>
58
+ /** The same as one string. */
59
+ text: ComputedRef<string>
60
+ /** A run is in progress. */
61
+ running: Readonly<ShallowRef<boolean>>
62
+ /** Scramble from what is shown now into the source value (into itself when unchanged). */
63
+ play: () => void
64
+ /** Land at once on the source value. */
65
+ settle: () => void
66
+ }
67
+
68
+ export function useScramble(source: MaybeRefOrGetter<string>, options: UseScrambleOptions = {}): UseScramble {
69
+ const random = options.random ?? Math.random
70
+ const tick = options.tick ?? 50
71
+ const glyphs = () => toValue(options.glyphs) || SCRAMBLE_GLYPHS
72
+
73
+ const initial = toValue(source)
74
+ const cells = shallowRef<ScrambleFrameCell[]>(
75
+ options.start === "masked"
76
+ ? scrambleFrame(planScramble(initial, initial, { duration: 1, keep: options.keep }, random), 0, random, glyphs())
77
+ : settledCells(initial),
78
+ )
79
+ const running = shallowRef(false)
80
+ const text = computed(() => cells.value.map((cell) => cell.char).join(""))
81
+
82
+ let frame = 0
83
+ let plan: ScrambleCell[] = []
84
+ let started = 0
85
+ let lastRoll = 0
86
+
87
+ const stopFrame = () => {
88
+ if (frame && typeof cancelAnimationFrame !== "undefined") cancelAnimationFrame(frame)
89
+ frame = 0
90
+ }
91
+
92
+ function settle() {
93
+ stopFrame()
94
+ cells.value = settledCells(toValue(source))
95
+ if (running.value) {
96
+ running.value = false
97
+ options.onDone?.()
98
+ }
99
+ }
100
+
101
+ function step(now: number) {
102
+ const elapsed = now - started
103
+ const duration = Math.max(1, toValue(options.duration) ?? 900)
104
+ if (elapsed >= duration) return settle()
105
+ if (now - lastRoll >= tick) {
106
+ lastRoll = now
107
+ cells.value = scrambleFrame(plan, elapsed, random, glyphs())
108
+ } else {
109
+ // Between re-rolls only the positions that just landed change, so the
110
+ // settle front moves smoothly while the churn keeps its own rate.
111
+ const shown = cells.value
112
+ let changed = false
113
+ const next = shown.map((cell, i) => {
114
+ const p = plan[i]
115
+ if (!cell.settled && p && (p.fixed || elapsed >= p.settleAt)) {
116
+ changed = true
117
+ return { char: p.final, sizer: p.final, settled: true }
118
+ }
119
+ return cell
120
+ })
121
+ if (changed) cells.value = next
122
+ }
123
+ frame = requestAnimationFrame(step)
124
+ }
125
+
126
+ function play() {
127
+ const to = toValue(source)
128
+ const duration = toValue(options.duration) ?? 900
129
+ if (prefersReducedMotion() || duration <= 0 || typeof requestAnimationFrame === "undefined") return settle()
130
+ stopFrame()
131
+ // From what is DRAWN: a change that lands mid-run carries on from the
132
+ // positions as they are, instead of snapping back to the old value first.
133
+ const from = cells.value.map((cell) => cell.sizer).join("")
134
+ plan = planScramble(from, to, { duration, order: toValue(options.order), keep: options.keep }, random)
135
+ started = performance.now()
136
+ lastRoll = -Infinity
137
+ running.value = true
138
+ frame = requestAnimationFrame(step)
139
+ }
140
+
141
+ watch(
142
+ () => toValue(source),
143
+ () => {
144
+ if (toValue(options.onChange) === false) settle()
145
+ else play()
146
+ },
147
+ )
148
+
149
+ onScopeDispose(stopFrame)
150
+
151
+ return { cells, text, running, play, settle }
152
+ }
@@ -180,22 +180,16 @@ export function useShift(
180
180
  const fromWidth = lastWidth
181
181
  const tops = readScroll()
182
182
 
183
- // Measured with any cap lifted, then the clamp is left to CSS. A `max-*`
184
- // from a class makes the element report the clipped figure once the cap
185
- // bites, and pinning that would hold the box short of the content it now
186
- // has to fit.
187
- if (wantsHeight()) {
188
- node.style.height = ""
189
- node.style.maxHeight = "none"
190
- }
191
- if (wantsWidth()) {
192
- node.style.width = ""
193
- node.style.maxWidth = "none"
194
- }
183
+ // Measured where the box will settle: free of the pinned size, but with
184
+ // its `max-*` in place. The target used to be read with the cap lifted
185
+ // while the settled size was read with it, so a box whose content is
186
+ // wider than its cap never matched its own target: every render started
187
+ // another tween and it never came to rest (a breadcrumb trail too wide for
188
+ // its bar re-animated some sixty times a second).
189
+ if (wantsHeight()) node.style.height = ""
190
+ if (wantsWidth()) node.style.width = ""
195
191
  const toHeight = wantsHeight() ? node.offsetHeight : 0
196
192
  const toWidth = wantsWidth() ? node.offsetWidth : 0
197
- if (wantsHeight()) node.style.maxHeight = ""
198
- if (wantsWidth()) node.style.maxWidth = ""
199
193
  restoreScroll(tops)
200
194
  lastHeight = toHeight
201
195
  lastWidth = toWidth
@@ -239,8 +233,8 @@ export function useShift(
239
233
  // clearing it let the box spread to the window's edges.
240
234
  if (wantsHeight()) node.style.height = ""
241
235
  if (wantsWidth()) node.style.width = ""
242
- // Re-read rather than trusting the target: a `max-*` may have clamped the
243
- // box short of it, and the next tween has to start from where it sits.
236
+ // Re-read rather than trusting the target: the layout around may have
237
+ // moved meanwhile, and the next tween has to start from where it sits.
244
238
  lastHeight = node.offsetHeight
245
239
  lastWidth = node.offsetWidth
246
240
  }, wait)
@@ -0,0 +1,82 @@
1
+ import { onBeforeUnmount, ref, toValue, watch, type MaybeRefOrGetter, type Ref } from "vue"
2
+ import { usePointerFrame } from "./usePointerFrame"
3
+
4
+ /*
5
+ * Drives the `.lp-spotlight` glow (tokens/effects.css): writes the pointer
6
+ * position into custom properties on the element and marks it while the
7
+ * pointer is inside.
8
+ *
9
+ * Writes go straight to the element's style, not through a reactive binding,
10
+ * one per animation frame with the latest position (usePointerFrame, shared
11
+ * with LpMagnetic and useTilt). Touch and pen are ignored: a glow that jumps
12
+ * to wherever a finger landed reads as a pressed state that is not one.
13
+ * Reduced motion turns it off rather than freezing it.
14
+ */
15
+
16
+ export interface UseSpotlightOptions {
17
+ /** Switch the effect off without unbinding — the listeners stay, nothing is drawn. */
18
+ disabled?: MaybeRefOrGetter<boolean | undefined>
19
+ }
20
+
21
+ export interface UseSpotlight {
22
+ /** Attach to the element carrying `.lp-spotlight`. */
23
+ el: Ref<HTMLElement | null>
24
+ }
25
+
26
+ /** Pointer position relative to a rect, in px, as the CSS custom properties want it. */
27
+ export function spotlightPoint(rect: { left: number; top: number }, clientX: number, clientY: number) {
28
+ return { x: `${Math.round(clientX - rect.left)}px`, y: `${Math.round(clientY - rect.top)}px` }
29
+ }
30
+
31
+ export function useSpotlight(options: UseSpotlightOptions = {}): UseSpotlight {
32
+ const el = ref<HTMLElement | null>(null)
33
+
34
+ const pointer = usePointerFrame({
35
+ disabled: options.disabled,
36
+ paint: (clientX, clientY) => {
37
+ const node = el.value
38
+ if (!node) return
39
+ const { x, y } = spotlightPoint(node.getBoundingClientRect(), clientX, clientY)
40
+ node.style.setProperty("--lp-spot-x", x)
41
+ node.style.setProperty("--lp-spot-y", y)
42
+ },
43
+ })
44
+
45
+ function onMove(event: PointerEvent) {
46
+ if (pointer.move(event)) el.value?.setAttribute("data-lp-spot", "")
47
+ }
48
+
49
+ function onLeave() {
50
+ el.value?.removeAttribute("data-lp-spot")
51
+ }
52
+
53
+ function detach(node: HTMLElement) {
54
+ node.removeEventListener("pointermove", onMove)
55
+ node.removeEventListener("pointerleave", onLeave)
56
+ node.removeAttribute("data-lp-spot")
57
+ }
58
+
59
+ watch(
60
+ el,
61
+ (node, previous) => {
62
+ if (previous) detach(previous)
63
+ if (!node) return
64
+ node.addEventListener("pointermove", onMove, { passive: true })
65
+ node.addEventListener("pointerleave", onLeave, { passive: true })
66
+ },
67
+ { flush: "post" },
68
+ )
69
+
70
+ watch(
71
+ () => toValue(options.disabled),
72
+ (disabled) => {
73
+ if (disabled) onLeave()
74
+ },
75
+ )
76
+
77
+ onBeforeUnmount(() => {
78
+ if (el.value) detach(el.value)
79
+ })
80
+
81
+ return { el }
82
+ }