@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
@@ -0,0 +1,175 @@
1
+ <script setup lang="ts">
2
+ /*
3
+ * A preview card that opens when the pointer rests on something: a username
4
+ * that shows the profile, a server name that shows its status, a link that
5
+ * shows where it goes. Reading it costs a pause, not a click and a back.
6
+ *
7
+ * <LpHoverCard>
8
+ * <template #trigger><a href="/u/ada">@ada</a></template>
9
+ * <ProfilePreview id="ada" />
10
+ * </LpHoverCard>
11
+ *
12
+ * Different from the neighbours on purpose:
13
+ * - LpTooltip names or explains a control in a line of text; this holds a
14
+ * small layout (avatar, stats, actions) and waits longer before opening, so
15
+ * passing over a list of names does not flash a card at every row.
16
+ * - LpPopover opens on a click and is a place to DO something; a hover card is
17
+ * a glance, and everything in it must also be reachable without it (the
18
+ * trigger usually links to the full page).
19
+ *
20
+ * Behaviour, built on reka's HoverCard:
21
+ * - Opens after `openDelay` on hover, and at once on keyboard focus of the
22
+ * trigger, so it is not a mouse-only feature.
23
+ * - Stays open while the pointer travels to the card and over it, so a link
24
+ * or a button inside can be used; closes `closeDelay` after it leaves.
25
+ * - Touch has no hover. With `touch="hold"` a press-and-hold opens the card
26
+ * (and that press does not also follow the link); a tap elsewhere closes it.
27
+ * `touch="none"` leaves touch alone, for triggers where a hold means
28
+ * something else (a drag handle, a context menu).
29
+ */
30
+ import {
31
+ HoverCardArrow,
32
+ HoverCardContent,
33
+ HoverCardPortal,
34
+ HoverCardRoot,
35
+ HoverCardTrigger,
36
+ } from "reka-ui"
37
+ import { computed, onBeforeUnmount, watch } from "vue"
38
+ import { mergeClass } from "../composables/useMergedClass"
39
+ import { useOutsideGuard, usePortalTarget } from "../composables/useView"
40
+ import { POPOVER_PANEL } from "./dropdown"
41
+
42
+ const props = withDefaults(
43
+ defineProps<{
44
+ side?: "top" | "right" | "bottom" | "left"
45
+ align?: "start" | "center" | "end"
46
+ sideOffset?: number
47
+ /**
48
+ * Milliseconds the pointer rests before the card opens. Longer than a
49
+ * tooltip's on purpose: a card is big, and one that opens while the
50
+ * pointer is only passing by covers what the reader was heading for.
51
+ */
52
+ openDelay?: number
53
+ /** Milliseconds after the pointer leaves before it closes: room to cross the gap to the card. */
54
+ closeDelay?: number
55
+ /** A small pointer from the card to its trigger, for a trigger in a dense row where the card could belong to a neighbour. */
56
+ arrow?: boolean
57
+ /** Touch: `hold` opens on press-and-hold; `none` leaves touch to the trigger. */
58
+ touch?: "hold" | "none"
59
+ /** How long a touch must be held to open, in ms. */
60
+ holdDelay?: number
61
+ /** Turn the card off: the trigger stays and behaves as itself. */
62
+ disabled?: boolean
63
+ /** Extra classes for the card (width, padding). Merged, so `w-80 p-0` replaces the defaults. */
64
+ panelClass?: string
65
+ }>(),
66
+ {
67
+ side: "bottom",
68
+ align: "center",
69
+ sideOffset: 8,
70
+ openDelay: 500,
71
+ closeDelay: 200,
72
+ arrow: false,
73
+ touch: "hold",
74
+ holdDelay: 450,
75
+ disabled: false,
76
+ },
77
+ )
78
+
79
+ // Controllable (v-model:open). Always held here, also uncontrolled, because a
80
+ // touch hold opens the card from outside reka's own hover handling.
81
+ const open = defineModel<boolean>("open", { default: false })
82
+
83
+ const panel = computed(() =>
84
+ mergeClass(POPOVER_PANEL, "z-(--z-popover) w-72 rounded-card p-4 text-sm text-ink outline-none", props.panelClass),
85
+ )
86
+
87
+ const portalTo = usePortalTarget()
88
+ const guardOutside = useOutsideGuard()
89
+
90
+ /*
91
+ * Press-and-hold. A hold that drifts is a scroll, not a hold, so moving past
92
+ * a few pixels cancels it. Once it has opened the card, the click the finger
93
+ * produces on lifting is swallowed: the reader asked for the preview, not for
94
+ * the link under it.
95
+ */
96
+ const SLOP = 8
97
+ let holdTimer = 0
98
+ let start = { x: 0, y: 0 }
99
+ let held = false
100
+
101
+ function cancelHold() {
102
+ window.clearTimeout(holdTimer)
103
+ holdTimer = 0
104
+ }
105
+
106
+ function onPointerDown(event: PointerEvent) {
107
+ if (event.pointerType !== "touch" || props.touch !== "hold" || props.disabled) return
108
+ held = false
109
+ start = { x: event.clientX, y: event.clientY }
110
+ cancelHold()
111
+ holdTimer = window.setTimeout(() => {
112
+ holdTimer = 0
113
+ held = true
114
+ open.value = true
115
+ }, props.holdDelay)
116
+ }
117
+
118
+ function onPointerMove(event: PointerEvent) {
119
+ if (!holdTimer) return
120
+ if (Math.hypot(event.clientX - start.x, event.clientY - start.y) > SLOP) cancelHold()
121
+ }
122
+
123
+ function onClickCapture(event: MouseEvent) {
124
+ if (!held) return
125
+ held = false
126
+ event.preventDefault()
127
+ event.stopPropagation()
128
+ }
129
+
130
+ // A long press would otherwise also bring up the system's own menu for the link.
131
+ function onContextMenu(event: Event) {
132
+ if (holdTimer || held) event.preventDefault()
133
+ }
134
+
135
+ watch(
136
+ () => props.disabled,
137
+ (off) => {
138
+ if (off) open.value = false
139
+ },
140
+ )
141
+
142
+ onBeforeUnmount(cancelHold)
143
+ </script>
144
+
145
+ <template>
146
+ <slot v-if="disabled" name="trigger" />
147
+ <HoverCardRoot v-else v-model:open="open" :open-delay="openDelay" :close-delay="closeDelay">
148
+ <HoverCardTrigger
149
+ as-child
150
+ :class="touch === 'hold' ? '[-webkit-touch-callout:none]' : undefined"
151
+ @pointerdown="onPointerDown"
152
+ @pointermove="onPointerMove"
153
+ @pointerup="cancelHold"
154
+ @pointercancel="cancelHold"
155
+ @click.capture="onClickCapture"
156
+ @contextmenu="onContextMenu"
157
+ >
158
+ <slot name="trigger" />
159
+ </HoverCardTrigger>
160
+ <HoverCardPortal :to="portalTo">
161
+ <HoverCardContent
162
+ :side="side"
163
+ :align="align"
164
+ :side-offset="sideOffset"
165
+ :collision-padding="8"
166
+ :class="panel"
167
+ @pointer-down-outside="guardOutside"
168
+ @escape-key-down="guardOutside"
169
+ >
170
+ <slot :close="() => (open = false)" />
171
+ <HoverCardArrow v-if="arrow" :width="14" :height="7" class="fill-surface-raised" />
172
+ </HoverCardContent>
173
+ </HoverCardPortal>
174
+ </HoverCardRoot>
175
+ </template>
@@ -0,0 +1,69 @@
1
+ <script lang="ts">
2
+ // The consumer's `class` is merged into the root's own (below) rather than
3
+ // appended to it, so opt out of the automatic pass-through that would add it
4
+ // a second time, unmerged.
5
+ export default { inheritAttrs: false }
6
+ </script>
7
+
8
+ <script setup lang="ts">
9
+ /*
10
+ * A face for something that has no picture: a mirrored pixel pattern and a
11
+ * colour, both derived from `seed` (an id, a username, a key's fingerprint).
12
+ * The same seed draws the same identicon everywhere, so people learn to
13
+ * recognise it the way they recognise an avatar.
14
+ *
15
+ * It fills the box it is put in (an LpAvatar sizes it through `identicon`);
16
+ * give it a size class of its own anywhere else. The pattern is generated by
17
+ * `identicon()` in identicon.ts, which a canvas, a favicon or a notification
18
+ * icon can call directly.
19
+ */
20
+ import { computed } from "vue"
21
+ import { identicon, identiconRects } from "./identicon"
22
+ import { useMergedAttrs } from "../composables/useMergedClass"
23
+
24
+ const props = withDefaults(
25
+ defineProps<{
26
+ /** What the picture is derived from. Use something stable: an id outlives a renamed username. */
27
+ seed: string
28
+ /** Cells per side: 5 is the familiar look, 7 gives busier shapes for large sizes. */
29
+ grid?: number
30
+ /**
31
+ * `tint` lays a pale wash of the shape's own hue behind it, mixed into the
32
+ * theme's soft surface so it sits right on dark and light alike; `none`
33
+ * leaves the box behind it showing.
34
+ */
35
+ background?: "tint" | "none"
36
+ /** Empty margin around the grid as a share of the side; more for a round crop. */
37
+ padding?: number
38
+ /** Accessible name. Unset, the picture is decorative: the name is usually written next to it. */
39
+ label?: string
40
+ }>(),
41
+ { grid: 5, background: "tint", padding: 0.14 },
42
+ )
43
+
44
+ const icon = computed(() => identicon(props.seed, { grid: props.grid }))
45
+ const rects = computed(() => identiconRects(icon.value.cells))
46
+ const pad = computed(() => props.grid * Math.max(0, Math.min(0.4, props.padding)))
47
+ const view = computed(() => props.grid + pad.value * 2)
48
+ const wash = computed(() => `color-mix(in oklab, ${icon.value.color} 16%, var(--color-surface-soft))`)
49
+
50
+ const { class: rootClass, attrs: rest } = useMergedAttrs("block size-full")
51
+ </script>
52
+
53
+ <template>
54
+ <svg
55
+ :class="rootClass"
56
+ v-bind="rest"
57
+ :viewBox="`0 0 ${view} ${view}`"
58
+ shape-rendering="crispEdges"
59
+ :role="label ? 'img' : undefined"
60
+ :aria-label="label"
61
+ :aria-hidden="label ? undefined : 'true'"
62
+ >
63
+ <rect v-if="background === 'tint'" :width="view" :height="view" :style="{ fill: wash }" class="transition-[fill] duration-medium motion-reduce:transition-none" />
64
+ <!-- Keyed by seed: a new seed is a new face, faded in rather than snapped. -->
65
+ <g :key="seed" :fill="icon.color" class="animate-[fade-in_var(--duration-medium)_ease] motion-reduce:animate-none">
66
+ <rect v-for="(r, i) in rects" :key="i" :x="r.x + pad" :y="r.y + pad" :width="r.w" height="1" />
67
+ </g>
68
+ </svg>
69
+ </template>
@@ -48,6 +48,7 @@ import LpButton from "./LpButton.vue"
48
48
  import LpContextMenu, { type ContextMenuItemDef } from "./LpContextMenu.vue"
49
49
  import LpIcon from "./LpIcon.vue"
50
50
  import { useMergedAttrs } from "../composables/useMergedClass"
51
+ import { useResizeObserver } from "../composables/useResizeObserver"
51
52
 
52
53
  const props = withDefaults(
53
54
  defineProps<{
@@ -144,23 +145,20 @@ const viewport = ref<HTMLElement | null>(null)
144
145
  const zoom = useZoomPan({ min: 1, max: 6 })
145
146
 
146
147
  const frameSize = ref<{ width: number; height: number } | null>(null)
147
- let frameObserver: ResizeObserver | null = null
148
-
149
- watch(viewport, (el) => {
150
- zoom.setViewport(el)
151
- frameObserver?.disconnect()
152
- frameObserver = null
153
- if (!el) return
154
- // Fractional, not clientWidth: a rounded-down frame left a hairline of
155
- // background showing along the edges of a turned picture.
156
- frameSize.value = { width: el.clientWidth, height: el.clientHeight }
157
- if (typeof ResizeObserver !== "undefined") {
158
- frameObserver = new ResizeObserver(([entry]) => {
159
- frameSize.value = { width: entry.contentRect.width, height: entry.contentRect.height }
160
- })
161
- frameObserver.observe(el)
162
- }
163
- })
148
+
149
+ watch(viewport, (el) => zoom.setViewport(el))
150
+ // Fractional, not clientWidth: a rounded-down frame left a hairline of
151
+ // background showing along the edges of a turned picture. The first, rounded
152
+ // reading only holds the frame until the observer's first report.
153
+ useResizeObserver(
154
+ viewport,
155
+ (entry, el) => {
156
+ frameSize.value = entry
157
+ ? { width: entry.contentRect.width, height: entry.contentRect.height }
158
+ : { width: el.clientWidth, height: el.clientHeight }
159
+ },
160
+ { immediate: true },
161
+ )
164
162
 
165
163
  /** Which way up it ends, 0-270, whatever the accumulated angle. */
166
164
  const upright = computed(() => ((rotation.value % 360) + 360) % 360)
@@ -296,7 +294,6 @@ function revoke() {
296
294
  onBeforeUnmount(() => {
297
295
  generation++
298
296
  revoke()
299
- frameObserver?.disconnect()
300
297
  })
301
298
 
302
299
  function rotate(by: number) {
@@ -10,6 +10,8 @@
10
10
  */
11
11
  import { Handle, Position } from "@vue-flow/core"
12
12
  import { computed } from "vue"
13
+ import LpBadge from "./LpBadge.vue"
14
+ import LpStatus from "./LpStatus.vue"
13
15
 
14
16
  export interface InfraNodeData {
15
17
  name: string
@@ -174,10 +176,12 @@ const accentLine = computed(
174
176
  <div class="flex items-center gap-[7px]">
175
177
  <span class="text-[13px] text-[var(--accent)]">{{ icon }}</span>
176
178
  <span class="flex-1 truncate text-[13px] font-semibold text-ink">{{ data.name }}</span>
177
- <span
179
+ <!-- The kit's status light: a live host breathes, a lost one is a steady red. -->
180
+ <LpStatus
178
181
  v-if="data.online !== undefined"
179
- class="size-[7px] rounded-full"
180
- :class="data.online ? 'bg-action shadow-[0_0_6px_var(--color-action)]' : 'bg-danger'"
182
+ :state="data.online ? 'online' : 'down'"
183
+ :pulse="data.online"
184
+ hide-label
181
185
  />
182
186
  </div>
183
187
  <div class="mt-1.5 flex items-center justify-between">
@@ -190,32 +194,39 @@ const accentLine = computed(
190
194
  v-if="data.firewallCount || data.serviceCount !== undefined || data.staleFor"
191
195
  class="mt-1.5 flex items-center gap-1.5"
192
196
  >
193
- <span
197
+ <!-- LpBadge's small chip, with the card's own 9px type: at the badge's
198
+ 11px three of them (a firewall count, a service count, an age)
199
+ overflow a 168px card. -->
200
+ <LpBadge
194
201
  v-if="data.firewallCount"
195
- class="inline-flex items-center gap-1 rounded-pill bg-danger-soft px-1.5 py-0.5 text-[9px] font-medium text-danger"
202
+ tone="danger"
203
+ size="sm"
204
+ class="text-[9px]"
196
205
  :title="fill(text.firewallRules, { n: data.firewallCount! })"
197
206
  >
198
- <span>⛨</span>{{ data.firewallCount }}
199
- </span>
200
- <span
207
+ ⛨ {{ data.firewallCount }}
208
+ </LpBadge>
209
+ <LpBadge
201
210
  v-if="data.serviceCount !== undefined"
202
- class="inline-flex items-center gap-1 rounded-pill bg-surface-soft px-1.5 py-0.5 text-[9px] font-medium text-muted"
203
- :class="data.staleFor ? 'line-through decoration-danger/70' : ''"
211
+ size="sm"
212
+ class="text-[9px] text-muted"
204
213
  :title="
205
214
  data.staleFor
206
215
  ? fill(text.servicesStale, { n: data.serviceCount!, age: data.staleFor })
207
216
  : fill(text.services, { n: data.serviceCount! })
208
217
  "
209
218
  >
210
- <span>◇</span>{{ data.serviceCount }}
211
- </span>
212
- <span
219
+ <span :class="data.staleFor ? 'line-through decoration-danger/70' : ''">◇ {{ data.serviceCount }}</span>
220
+ </LpBadge>
221
+ <LpBadge
213
222
  v-if="data.staleFor"
214
- class="inline-flex items-center gap-1 rounded-pill bg-danger-soft px-1.5 py-0.5 text-[9px] font-medium text-danger"
223
+ tone="danger"
224
+ size="sm"
225
+ class="text-[9px]"
215
226
  :title="fill(text.noContact, { age: data.staleFor })"
216
227
  >
217
- <span>⚠</span>{{ data.staleFor }} {{ text.old }}
218
- </span>
228
+ ⚠ {{ data.staleFor }} {{ text.old }}
229
+ </LpBadge>
219
230
  </div>
220
231
  </div>
221
232
  </div>
@@ -6,10 +6,11 @@ export default { inheritAttrs: false }
6
6
  import { tv, type VariantProps } from "tailwind-variants"
7
7
  import { computed, ref, useAttrs, useSlots } from "vue"
8
8
  import { useFieldControl } from "../composables/useField"
9
+ import { useLabels } from "../composables/useLpConfig"
9
10
  import { useInputFilter } from "../composables/useInputFilter"
10
11
  import { DEFAULT_MASK_TOKENS, useInputMask, type MaskSpec, type MaskTokens } from "../composables/useInputMask"
11
12
  import { mergeClass } from "../composables/useMergedClass"
12
- import LpFormField from "./LpFormField.vue"
13
+ import FieldWrapper from "./FieldWrapper.vue"
13
14
  import LpIcon from "./LpIcon.vue"
14
15
 
15
16
  // Single source of truth for the field shell — bare input and adorned input
@@ -57,6 +58,9 @@ const props = withDefaults(
57
58
  hint?: string
58
59
  error?: string
59
60
  icon?: string
61
+ /** Show an accessible clear button, returning focus to the input. */
62
+ clearable?: boolean
63
+ labels?: Partial<{ clear: string }>
60
64
  /**
61
65
  * Marks the label with the required indicator. The attribute still reaches
62
66
  * the underlying <input> for native validation; this only makes the field
@@ -130,7 +134,7 @@ const patternInvalid = computed(() => isInvalid(props.modelValue))
130
134
  const slots = useSlots()
131
135
  const attrs = useAttrs()
132
136
  const hasLeading = computed(() => !!slots.leading || !!props.icon)
133
- const hasTrailing = computed(() => !!slots.trailing)
137
+ const hasTrailing = computed(() => !!slots.trailing || showClear.value)
134
138
  const hasField = computed(
135
139
  () => !!props.label || !!props.hint || !!props.error,
136
140
  )
@@ -142,6 +146,8 @@ const field = useFieldControl(() => ({
142
146
  required: props.required,
143
147
  disabled: props.disabled,
144
148
  }))
149
+ const text = useLabels("input", { clear: "Clear" }, () => props.labels)
150
+ const showClear = computed(() => props.clearable && !!props.modelValue && !field.value.disabled && (attrs.readonly === undefined || attrs.readonly === false))
145
151
  const isInvalidState = computed(() => field.value.invalid)
146
152
  const shellClass = computed(() =>
147
153
  shell({ size: props.size, invalid: isInvalidState.value }),
@@ -150,14 +156,18 @@ const shellClass = computed(() =>
150
156
  // class/style belong to the wrapper (so `<LpInput class="...">` lays out the
151
157
  // whole field); every other attr (autocomplete, name, @keyup, inputmode…) goes
152
158
  // to the real <input>.
153
- const rootClass = computed(() => attrs.class)
154
- const rootStyle = computed(() => attrs.style)
155
159
  const inputAttrs = computed(() => {
156
160
  const { class: _c, style: _s, ...rest } = attrs
157
161
  return rest
158
162
  })
159
163
 
160
164
  const inputEl = ref<HTMLInputElement | null>(null)
165
+ function clear() {
166
+ if (!showClear.value) return
167
+ emit("update:modelValue", "")
168
+ if (masking.active.value) emit("update:raw", "")
169
+ inputEl.value?.focus()
170
+ }
161
171
  defineExpose({
162
172
  focus: (options?: FocusOptions) => inputEl.value?.focus(options),
163
173
  blur: () => inputEl.value?.blur(),
@@ -167,20 +177,20 @@ defineExpose({
167
177
  </script>
168
178
 
169
179
  <template>
170
- <component
171
- :is="hasField ? LpFormField : 'div'"
172
- :label="hasField ? label : undefined"
173
- :hint="hasField ? hint : undefined"
174
- :error="hasField ? error : undefined"
175
- :required="hasField ? required : undefined"
176
- :id="hasField ? field.id : undefined"
177
- :class="hasField ? rootClass : 'contents'"
178
- :style="hasField ? rootStyle : undefined"
180
+ <FieldWrapper
181
+ :wrapped="hasField"
182
+ :id="field.id"
183
+ :label="label"
184
+ :hint="hint"
185
+ :error="error"
186
+ :required="required"
187
+ :class="attrs.class"
188
+ :style="attrs.style"
179
189
  >
180
190
  <div
181
191
  data-lp-ring-owner
182
- :class="mergeClass(shellClass, hasLeading ? 'pl-2.5' : '', hasTrailing ? 'pr-1.5' : '', hasField ? '' : (rootClass as string))"
183
- :style="hasField ? undefined : rootStyle"
192
+ :class="mergeClass(shellClass, hasLeading ? 'pl-2.5' : '', hasTrailing ? 'pr-1.5' : '', hasField ? '' : (attrs.class as string))"
193
+ :style="hasField ? undefined : attrs.style"
184
194
  >
185
195
  <span v-if="hasLeading" class="flex shrink-0 items-center text-muted">
186
196
  <slot name="leading"><LpIcon v-if="icon" :name="icon" :size="16" /></slot>
@@ -198,6 +208,7 @@ defineExpose({
198
208
  :aria-describedby="field.describedBy"
199
209
  :class="[
200
210
  'lp-autofill min-w-0 flex-1 self-stretch bg-transparent outline-none placeholder:text-muted',
211
+ clearable && '[&::-webkit-search-cancel-button]:hidden',
201
212
  hasLeading ? 'pl-2' : padX[size ?? 'md'],
202
213
  hasTrailing ? '' : padX[size ?? 'md'],
203
214
  ]"
@@ -207,6 +218,9 @@ defineExpose({
207
218
  @input="onInputEvent"
208
219
  />
209
220
  <slot name="trailing" />
221
+ <button v-if="showClear" type="button" :aria-label="text.clear" class="shrink-0 rounded-inner p-1 text-muted outline-none transition-colors hover:text-ink focus-visible:ring-2 focus-visible:ring-ring" @pointerdown.prevent @click="clear">
222
+ <LpIcon name="lucide:x" :size="size === 'sm' ? 12 : 16" />
223
+ </button>
210
224
  </div>
211
- </component>
225
+ </FieldWrapper>
212
226
  </template>
@@ -25,8 +25,11 @@ import { computed, nextTick, onBeforeUnmount, ref, watch } from "vue"
25
25
  import { useLabels } from "../composables/useLpConfig"
26
26
  import { useZoomPan } from "../composables/useZoomPan"
27
27
  import { fileNameOf, type LightboxItem } from "./lightbox"
28
+ import LpCopyButton from "./LpCopyButton.vue"
28
29
  import LpIcon from "./LpIcon.vue"
30
+ import LpLoader from "./LpLoader.vue"
29
31
  import { useModalLayer } from "./modalDepth"
32
+ import { useOutsideGuard, usePortalTarget } from "../composables/useView"
30
33
 
31
34
  export type LightboxLabels = {
32
35
  viewer: string
@@ -380,20 +383,22 @@ async function download() {
380
383
  }
381
384
  }
382
385
 
383
- async function copy() {
384
- const target = item.value
385
- if (!target) return
386
- try {
387
- const response = await fetch(target.src)
388
- const blob = await response.blob()
389
- // Clipboard only takes PNG; re-encode anything else through a canvas.
390
- const png =
391
- blob.type === "image/png" ? blob : await reencodeToPng(await createImageBitmap(blob))
392
- await navigator.clipboard.write([new ClipboardItem({ "image/png": png })])
393
- emit("copy", target, true)
394
- } catch {
395
- emit("copy", target, false)
396
- }
386
+ /*
387
+ * The copy button (LpCopyButton) asks for the image when clicked: fetched then,
388
+ * not for every image paged past, and reported against the item that was on
389
+ * screen at the click even if the viewer pages on while it loads.
390
+ */
391
+ let copyTarget: LightboxItem | undefined
392
+ async function imageToCopy(): Promise<Blob> {
393
+ const target = (copyTarget = item.value)
394
+ if (!target) throw new Error("No image")
395
+ const response = await fetch(target.src)
396
+ const blob = await response.blob()
397
+ // Clipboard only takes PNG; re-encode anything else through a canvas.
398
+ return blob.type === "image/png" ? blob : reencodeToPng(await createImageBitmap(blob))
399
+ }
400
+ function copyDone(ok: boolean) {
401
+ if (copyTarget) emit("copy", copyTarget, ok)
397
402
  }
398
403
 
399
404
  async function reencodeToPng(bitmap: ImageBitmap): Promise<Blob> {
@@ -430,11 +435,17 @@ const BTN =
430
435
  */
431
436
  const ARROW =
432
437
  "absolute top-1/2 z-10 flex size-11 -translate-y-1/2 items-center justify-center rounded-pill bg-black/45 text-white/75 ring-1 ring-white/0 outline-none backdrop-blur-sm transition-[background-color,scale,color,box-shadow] duration-[var(--duration-fast)] ease-[var(--ease-emphasized)] hover:bg-white/20 hover:text-white hover:ring-white/30 hover:scale-110 active:scale-95 focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-0 motion-reduce:transition-none motion-reduce:hover:scale-100 motion-reduce:active:scale-100"
438
+
439
+ // Overlays open in the window this component renders in (an LpFrame's, inside one).
440
+ const portalTo = usePortalTarget()
441
+ // What happens in another document (the page around a frame, or a frame in
442
+ // the page) is not "outside" for this layer.
443
+ const guardOutside = useOutsideGuard()
433
444
  </script>
434
445
 
435
446
  <template>
436
447
  <DialogRoot :open="open" @update:open="(v) => emit('update:open', v)">
437
- <DialogPortal>
448
+ <DialogPortal :to="portalTo">
438
449
  <!-- Not `lp-scrim--nested` even over another layer: a lightbox wants its
439
450
  full dark backdrop around the picture, not the lighter nested tint.
440
451
  The blur is handed up the stack like every scrim's. -->
@@ -444,6 +455,8 @@ const ARROW =
444
455
  :style="{ zIndex: layer.scrim }"
445
456
  />
446
457
  <DialogContent
458
+ @interact-outside="guardOutside"
459
+ @escape-key-down="guardOutside"
447
460
  ref="contentRef"
448
461
  class="fixed inset-0 flex flex-col outline-none data-[state=open]:animate-[lightbox-in_var(--duration-medium)_var(--ease-emphasized)] data-[state=closed]:animate-[lightbox-out_140ms_cubic-bezier(0.4,0,1,1)] motion-reduce:animate-none"
449
462
  :style="{ zIndex: layer.panel }"
@@ -483,9 +496,15 @@ const ARROW =
483
496
  >
484
497
  <LpIcon name="lucide:rotate-cw" :size="18" />
485
498
  </button>
486
- <button v-if="copyable" :class="BTN" type="button" :title="text.copy" @click="copy">
487
- <LpIcon name="lucide:copy" :size="18" />
488
- </button>
499
+ <LpCopyButton
500
+ v-if="copyable"
501
+ :value="imageToCopy"
502
+ :icon-size="18"
503
+ :class="BTN"
504
+ :labels="{ copy: text.copy }"
505
+ @copied="copyDone(true)"
506
+ @error="copyDone(false)"
507
+ />
489
508
  <button
490
509
  v-if="downloadable"
491
510
  :class="BTN"
@@ -561,11 +580,13 @@ const ARROW =
561
580
  @error="((failed = true), (loading = false))"
562
581
  />
563
582
 
564
- <LpIcon
565
- v-if="loading && !failed && !covered(current)"
566
- name="lucide:loader-circle"
567
- :size="28"
568
- class="absolute animate-spin text-white/50"
583
+ <!-- Mounted throughout and driven by `active`, so a cached image that
584
+ loads at once shows no spinner and a slow one keeps it long
585
+ enough not to blink. -->
586
+ <LpLoader
587
+ :active="loading && !failed && !covered(current)"
588
+ size="inline"
589
+ class="absolute text-[28px] text-white/50"
569
590
  />
570
591
 
571
592
  <button