@leavepulse/ui 0.69.0 → 0.70.1

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 +49 -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/LpRepeater-C1Cw27hj.css +21 -0
  11. package/dist/assets/{LpRollingText-BGnE6q9j.css → LpRollingText-dyOXedGO.css} +7 -0
  12. package/dist/assets/LpShinyText-D69cBYDR.css +61 -0
  13. package/dist/assets/LpStatus-430OGTZY.css +17 -0
  14. package/dist/assets/LpStepMark-Drvx33Vg.css +10 -0
  15. package/dist/assets/{LpTable-BPERfJIk.css → LpTable-DHxEQ_-3.css} +19 -19
  16. package/dist/assets/LpTabs-BJ-nrJuI.css +18 -0
  17. package/dist/assets/LpTextReveal-DjI1MsDS.css +35 -0
  18. package/dist/assets/LpTypewriter-CXAm9Nca.css +27 -0
  19. package/dist/chunks/AttentionDot-DCBf4aWg.js +25 -0
  20. package/dist/chunks/{ContextMenuItems-B7XFHksm.js → ContextMenuItems-6kxEivBI.js} +11 -5
  21. package/dist/chunks/{DropzoneLinkField-CjkrpDqO.js → DropzoneLinkField-Bw8Flkhk.js} +2 -2
  22. package/dist/chunks/FieldWrapper-BiennROB.js +43 -0
  23. package/dist/chunks/{LayoutCanvas-DF9CovaK.js → LayoutCanvas-BsJIzhdd.js} +1 -1
  24. package/dist/chunks/{LayoutNode-D9bIFzk0.js → LayoutNode-DJVhkSGk.js} +6 -8
  25. package/dist/chunks/LegendSwatch-BhRjrtzv.js +18 -0
  26. package/dist/chunks/LoaderMark-C1dubiKn.js +85 -0
  27. package/dist/chunks/{LpActionBar-MPKMu3pz.js → LpActionBar-CzOFar5t.js} +14 -20
  28. package/dist/chunks/LpActivityLine-CJvzrNpj.js +95 -0
  29. package/dist/chunks/{LpAddressInput-DG0BTqdH.js → LpAddressInput-Chv_Xf8q.js} +7 -7
  30. package/dist/chunks/LpAlert-C5igj802.js +119 -0
  31. package/dist/chunks/{LpAppShell-DPh1756q.js → LpAppShell-BiWByLmt.js} +15 -16
  32. package/dist/chunks/{LpAutocomplete-Dgn6hw3p.js → LpAutocomplete-D92niDHE.js} +15 -32
  33. package/dist/chunks/{LpAvatar-Bs0Fb1lC.js → LpAvatar-CLPl-qOF.js} +18 -6
  34. package/dist/chunks/LpBadge-BBq1Er9T.js +126 -0
  35. package/dist/chunks/LpBreadcrumbs-JKEi_yFF.js +144 -0
  36. package/dist/chunks/{LpButton-DNR-YAq5.js → LpButton-CVxBfGjd.js} +12 -4
  37. package/dist/chunks/{LpCalendar-BLya39Fh.js → LpCalendar-pVL91-Pl.js} +1 -1
  38. package/dist/chunks/{LpCard-Bf71NXZq.js → LpCard-CqKLnEhl.js} +18 -8
  39. package/dist/chunks/{LpCheckbox-Da5oZPHo.js → LpCheckbox-DHc2bHDe.js} +9 -6
  40. package/dist/chunks/{LpCodeBlock-lLbmslfs.js → LpCodeBlock-BGsQhxw8.js} +24 -32
  41. package/dist/chunks/LpCodeDisplay-CbJMs-IK.js +189 -0
  42. package/dist/chunks/LpCollapse-CWS9M_lm.js +115 -0
  43. package/dist/chunks/{LpColorPicker-DtEfBAcK.js → LpColorPicker-B7HSIFmn.js} +11 -6
  44. package/dist/chunks/{LpConfirmDialog-D7s4jakB.js → LpConfirmDialog-CfGCux8m.js} +3 -3
  45. package/dist/chunks/{LpConfirmHost-DrYI5y1K.js → LpConfirmHost-exB7JmcO.js} +1 -1
  46. package/dist/chunks/{LpContextMenu-CRnjoqSt.js → LpContextMenu-Cj96ENDC.js} +16 -7
  47. package/dist/chunks/LpCopyButton-DzHjnFs0.js +133 -0
  48. package/dist/chunks/LpCountdown-BQnmB4gq.js +231 -0
  49. package/dist/chunks/LpDataList-CHNYQw7h.js +121 -0
  50. package/dist/chunks/LpDatePicker-ac1_6o5P.js +169 -0
  51. package/dist/chunks/LpDateRangePicker-B15gYrZJ.js +127 -0
  52. package/dist/chunks/{LpDisclosure-6AplYBub.js → LpDisclosure-DOarzlAG.js} +22 -11
  53. package/dist/chunks/{LpDrawer-Q4SOxM4s.js → LpDrawer-DGNKRsGq.js} +9 -4
  54. package/dist/chunks/{LpDropdownMenu-DWTt0ooM.js → LpDropdownMenu-R4aYVtVV.js} +14 -6
  55. package/dist/chunks/LpEditable-Ws3DNQHn.js +238 -0
  56. package/dist/chunks/{LpEmptyState-om1UnFjV.js → LpEmptyState-KTKipws2.js} +1 -1
  57. package/dist/chunks/{LpFieldNotice-CHuDeLjc.js → LpFieldNotice-CurbNuXI.js} +1 -1
  58. package/dist/chunks/{LpFileTree-CW24YsVX.js → LpFileTree-DDNg34tJ.js} +5 -3
  59. package/dist/chunks/{LpFileTreeNode-BXhTHaKW.js → LpFileTreeNode-DmPuYNZ_.js} +42 -55
  60. package/dist/chunks/{LpFormField-DPb47HEm.js → LpFormField-BWwgm1E4.js} +23 -9
  61. package/dist/chunks/LpFrame-BVQCQLDI.js +155 -0
  62. package/dist/chunks/LpGauge-C14Z9503.js +204 -0
  63. package/dist/chunks/LpGlowBorder-B8V-QzIl.js +40 -0
  64. package/dist/chunks/{LpHintExample-C1eKYdeL.js → LpHintExample-9Py0wc-L.js} +11 -34
  65. package/dist/chunks/{LpHintLayer-7UOdWQG3.js → LpHintLayer-HvwUA5Ec.js} +27 -14
  66. package/dist/chunks/{LpHints-BUtBp9-w.js → LpHints-DxbPKOzQ.js} +3 -3
  67. package/dist/chunks/LpHoverCard-spGxyw7T.js +130 -0
  68. package/dist/chunks/{LpIcon-6tSrZ3Zy.js → LpIcon-HJP5xMz4.js} +1 -1
  69. package/dist/chunks/LpIdenticon-BzdC_qz9.js +63 -0
  70. package/dist/chunks/{LpInfraNode-Ds_8SZgN.js → LpInfraNode-D64hywJI.js} +39 -25
  71. package/dist/chunks/{LpInput-CUyr6PIE.js → LpInput-CDuwODJG.js} +44 -18
  72. package/dist/chunks/{LpLightbox-B9J8rzsj.js → LpLightbox-XJ0LpTcZ.js} +69 -69
  73. package/dist/chunks/LpLoader-DjJEX8hL.js +92 -0
  74. package/dist/chunks/{LpLogViewer-4QFc-sVN.js → LpLogViewer-DKK4ySZl.js} +225 -129
  75. package/dist/chunks/LpMagnetic-CtXKLa2Y.js +62 -0
  76. package/dist/chunks/{LpMapPicker-BTbkFeSG.js → LpMapPicker-BtIl7NOM.js} +34 -31
  77. package/dist/chunks/LpMasonry--k0571qG.js +185 -0
  78. package/dist/chunks/{LpMediaGallery-CuPcscx3.js → LpMediaGallery-rmI1DjKN.js} +3 -3
  79. package/dist/chunks/{LpModal-hk1noDcr.js → LpModal-eBMt2Fqn.js} +8 -3
  80. package/dist/chunks/{LpModalNav-DQd2keZm.js → LpModalNav-DiyFCHiZ.js} +4 -4
  81. package/dist/chunks/{LpNotificationBell-X84PJIxD.js → LpNotificationBell-D-WhE5m2.js} +32 -48
  82. package/dist/chunks/LpNumberField-B9k-h2HE.js +140 -0
  83. package/dist/chunks/{LpNumberFlow-z4WPZcZu.js → LpNumberFlow-Cfyh033Q.js} +8 -28
  84. package/dist/chunks/{LpOtpInput-PbeNJ5In.js → LpOtpInput-CeBPsM7D.js} +2 -1
  85. package/dist/chunks/{LpPagination-Bx-VG4Ag.js → LpPagination-VNCX6pFC.js} +37 -6
  86. package/dist/chunks/{LpPalettePreview-CFav_7co.js → LpPalettePreview-BNB8T_MY.js} +1 -1
  87. package/dist/chunks/{LpPasswordInput-CbnXitAS.js → LpPasswordInput-GL2KOFK8.js} +26 -22
  88. package/dist/chunks/{LpPhoneInput-DP69HONS.js → LpPhoneInput-C60tx1tC.js} +12 -7
  89. package/dist/chunks/{LpPie-yLF9-aDR.js → LpPie-BgXZ3xmm.js} +159 -48
  90. package/dist/chunks/LpPipeline-B31h41Mu.js +329 -0
  91. package/dist/chunks/{LpPopover-DVnkHaOu.js → LpPopover-DmZ3wUtP.js} +13 -7
  92. package/dist/chunks/{LpProgress-CA86wxXu.js → LpProgress-CE-m5OpD.js} +23 -63
  93. package/dist/chunks/LpQuota-DaL8TgNe.js +162 -0
  94. package/dist/chunks/{LpRadioGroup-8S5hf8lE.js → LpRadioGroup-CGBr5nIp.js} +1 -1
  95. package/dist/chunks/{LpRangeCalendar-ByQi-WUz.js → LpRangeCalendar-c5qj7YcC.js} +1 -1
  96. package/dist/chunks/{LpRangeSlider-C1yF9-nP.js → LpRangeSlider-Dv6lNvHY.js} +6 -2
  97. package/dist/chunks/LpRelativeTime-yin9uQP7.js +73 -0
  98. package/dist/chunks/LpRepeater-D0S7jjwr.js +180 -0
  99. package/dist/chunks/LpRevealOnScroll-DcQjexLy.js +76 -0
  100. package/dist/chunks/{LpRollingText-DB7upf-5.js → LpRollingText-DiL717LK.js} +4 -3
  101. package/dist/chunks/LpScramble-TDO5Kdou.js +85 -0
  102. package/dist/chunks/LpSecretField-CfWyHv9m.js +316 -0
  103. package/dist/chunks/{LpSection-BmRXe6ZP.js → LpSection-BW4xJ-Li.js} +1 -1
  104. package/dist/chunks/{LpSegmented-CW3bFHM4.js → LpSegmented-BO99Sr4m.js} +11 -14
  105. package/dist/chunks/{LpSelect-BCyDYoih.js → LpSelect-C_8cJtj6.js} +91 -111
  106. package/dist/chunks/LpShaderBackdrop-Bote0iuy.js +332 -0
  107. package/dist/chunks/LpShinyText-DX2ajtWq.js +48 -0
  108. package/dist/chunks/{LpSidebar-DfIiS-lB.js → LpSidebar-CZRXtvem.js} +5 -3
  109. package/dist/chunks/{LpSidebarNav-C5FDNI0t.js → LpSidebarNav-DBg1U1oW.js} +3 -3
  110. package/dist/chunks/{LpSlider-Cuzmrd7p.js → LpSlider-DuoRpOrH.js} +6 -2
  111. package/dist/chunks/{LpSparkline-DXT4KrSi.js → LpSparkline-CExIRDb3.js} +32 -27
  112. package/dist/chunks/LpSpotlight-4F3NeUMY.js +41 -0
  113. package/dist/chunks/{LpStat-iBMF5QNk.js → LpStat-DFKlPJgy.js} +38 -35
  114. package/dist/chunks/LpStatus-BsGLrpor.js +86 -0
  115. package/dist/chunks/LpStepMark-TrzOioa9.js +101 -0
  116. package/dist/chunks/LpStepper-BbnS5jUr.js +76 -0
  117. package/dist/chunks/{LpSwap-D82jiecV.js → LpSwap-DzE6M3Mg.js} +1 -1
  118. package/dist/chunks/LpSwitch-DrzKrZZV.js +112 -0
  119. package/dist/chunks/{LpTableFilter-CuIbgdW0.js → LpTableFilter-DyvHGbOk.js} +3 -2
  120. package/dist/chunks/{LpTableOfContents-C_4VBktT.js → LpTableOfContents-rYvo8z5T.js} +34 -21
  121. package/dist/chunks/{LpTagsInput-DiXrpYeE.js → LpTagsInput-DZg80W-B.js} +68 -71
  122. package/dist/chunks/LpTextReveal-CtAnOUkp.js +140 -0
  123. package/dist/chunks/{LpTextarea-xoQd5Lnp.js → LpTextarea-DiWjeVoJ.js} +12 -11
  124. package/dist/chunks/{LpThemeProvider-CQ2jC9TA.js → LpThemeProvider-DcbfOxsU.js} +1 -1
  125. package/dist/chunks/LpThemeStudio-DxVZMtzN.js +416 -0
  126. package/dist/chunks/LpThemeStudioSection-BwhqYDLf.js +20 -0
  127. package/dist/chunks/LpThemeSwitcher-CadVBTBn.js +278 -0
  128. package/dist/chunks/{LpTimeField-MFgAsNc5.js → LpTimeField-BFQVf_PW.js} +13 -5
  129. package/dist/chunks/{LpToaster-C4zE9zB7.js → LpToaster-Wv9ksj4q.js} +49 -82
  130. package/dist/chunks/{LpTooltip-suFCM34F.js → LpTooltip-Cz8SQwRt.js} +8 -3
  131. package/dist/chunks/{LpTopologyCanvas-6ozNrQKh.js → LpTopologyCanvas-C17A1XCb.js} +1 -1
  132. package/dist/chunks/{LpTour-BUp3Jt2e.js → LpTour-CY2bFXge.js} +24 -18
  133. package/dist/chunks/LpTruncate-D_5Pfv5B.js +112 -0
  134. package/dist/chunks/LpTypewriter-BCL_a6wE.js +159 -0
  135. package/dist/chunks/{LpUptimeBar-B6kHw4Cj.js → LpUptimeBar-Tew1Ykx4.js} +10 -9
  136. package/dist/chunks/{LpVideoBackdrop-qWRYBOTQ.js → LpVideoBackdrop-DS1wGv-X.js} +7 -8
  137. package/dist/chunks/{MenuTitle-obgek0B7.js → MenuTitle-BjQZX8tQ.js} +1 -1
  138. package/dist/chunks/OptionContent-CmYUUeWj.js +40 -0
  139. package/dist/chunks/PickerField-DoHv0WMH.js +125 -0
  140. package/dist/chunks/RevealToggle-C-KzaQGJ.js +65 -0
  141. package/dist/chunks/StepConnector-37OgEOXA.js +41 -0
  142. package/dist/chunks/TourCard-BJ8i7dk0.js +123 -0
  143. package/dist/chunks/backdrop-Dkf2vM81.js +59 -0
  144. package/dist/chunks/{icons-DVhZ_plB.js → icons-4IywzkHk.js} +1 -1
  145. package/dist/chunks/{useTheme-2qHG8NEU.js → useTheme-BOV_-AiY.js} +9 -65
  146. package/dist/component-names.d.ts +1 -1
  147. package/dist/components/AttentionDot.vue.d.ts +9 -0
  148. package/dist/components/AttentionDot.vue.js +4 -0
  149. package/dist/components/ContextMenuItems.vue.js +1 -1
  150. package/dist/components/DropzoneLinkField.vue.js +1 -1
  151. package/dist/components/FieldWrapper.vue.d.ts +25 -0
  152. package/dist/components/FieldWrapper.vue.js +4 -0
  153. package/dist/components/LayoutCanvas.vue.js +1 -1
  154. package/dist/components/LayoutNode.vue.d.ts +4 -4
  155. package/dist/components/LayoutNode.vue.js +1 -1
  156. package/dist/components/LegendSwatch.vue.d.ts +6 -0
  157. package/dist/components/LegendSwatch.vue.js +4 -0
  158. package/dist/components/LoaderMark.vue.d.ts +12 -0
  159. package/dist/components/LoaderMark.vue.js +4 -0
  160. package/dist/components/LpActionBar.vue.js +1 -1
  161. package/dist/components/LpActivityLine.vue.d.ts +58 -0
  162. package/dist/components/LpActivityLine.vue.js +4 -0
  163. package/dist/components/LpAddressInput.vue.js +1 -1
  164. package/dist/components/LpAlert.vue.d.ts +2 -2
  165. package/dist/components/LpAlert.vue.js +1 -1
  166. package/dist/components/LpAppShell.vue.d.ts +8 -7
  167. package/dist/components/LpAppShell.vue.js +1 -1
  168. package/dist/components/LpAutocomplete.vue.js +1 -1
  169. package/dist/components/LpAvatar.vue.d.ts +16 -0
  170. package/dist/components/LpAvatar.vue.js +1 -1
  171. package/dist/components/LpBadge.vue.d.ts +19 -5
  172. package/dist/components/LpBadge.vue.js +1 -1
  173. package/dist/components/LpBreadcrumbs.vue.js +1 -1
  174. package/dist/components/LpButton.vue.d.ts +2 -2
  175. package/dist/components/LpButton.vue.js +1 -1
  176. package/dist/components/LpCalendar.vue.js +1 -1
  177. package/dist/components/LpCard.vue.d.ts +24 -0
  178. package/dist/components/LpCard.vue.js +1 -1
  179. package/dist/components/LpChart.vue.js +131 -160
  180. package/dist/components/LpCheckbox.vue.d.ts +2 -2
  181. package/dist/components/LpCheckbox.vue.js +1 -1
  182. package/dist/components/LpCodeBlock.vue.js +1 -1
  183. package/dist/components/LpCodeDisplay.vue.d.ts +89 -0
  184. package/dist/components/LpCodeDisplay.vue.js +4 -0
  185. package/dist/components/LpCollapse.vue.d.ts +58 -0
  186. package/dist/components/LpCollapse.vue.js +4 -0
  187. package/dist/components/LpColorPicker.vue.d.ts +2 -2
  188. package/dist/components/LpColorPicker.vue.js +1 -1
  189. package/dist/components/LpCommandPalette.vue.js +34 -23
  190. package/dist/components/LpConfirmDialog.vue.js +1 -1
  191. package/dist/components/LpConfirmHost.vue.js +1 -1
  192. package/dist/components/LpContextMenu.vue.js +1 -1
  193. package/dist/components/LpCopyButton.vue.d.ts +82 -0
  194. package/dist/components/LpCopyButton.vue.js +4 -0
  195. package/dist/components/LpCountdown.vue.d.ts +100 -0
  196. package/dist/components/LpCountdown.vue.js +4 -0
  197. package/dist/components/LpDataList.vue.d.ts +66 -0
  198. package/dist/components/LpDataList.vue.js +4 -0
  199. package/dist/components/LpDatePicker.vue.d.ts +3 -1
  200. package/dist/components/LpDatePicker.vue.js +1 -1
  201. package/dist/components/LpDateRangePicker.vue.d.ts +3 -1
  202. package/dist/components/LpDateRangePicker.vue.js +1 -1
  203. package/dist/components/LpDisclosure.vue.js +1 -1
  204. package/dist/components/LpDock.vue.d.ts +74 -0
  205. package/dist/components/LpDock.vue.js +204 -0
  206. package/dist/components/LpDrawer.vue.js +1 -1
  207. package/dist/components/LpDropdownMenu.vue.js +1 -1
  208. package/dist/components/LpDropzone.vue.d.ts +8 -1
  209. package/dist/components/LpDropzone.vue.js +36 -15
  210. package/dist/components/LpEditable.vue.d.ts +85 -0
  211. package/dist/components/LpEditable.vue.js +4 -0
  212. package/dist/components/LpEmptyState.vue.js +1 -1
  213. package/dist/components/LpFieldNotice.vue.js +1 -1
  214. package/dist/components/LpFileTree.vue.js +1 -1
  215. package/dist/components/LpFileTreeNode.vue.js +1 -1
  216. package/dist/components/LpFormField.vue.js +1 -1
  217. package/dist/components/LpFrame.vue.d.ts +22 -0
  218. package/dist/components/LpFrame.vue.js +4 -0
  219. package/dist/components/LpGauge.vue.d.ts +116 -0
  220. package/dist/components/LpGauge.vue.js +4 -0
  221. package/dist/components/LpGlowBorder.vue.d.ts +47 -0
  222. package/dist/components/LpGlowBorder.vue.js +4 -0
  223. package/dist/components/LpHintExample.vue.d.ts +2 -2
  224. package/dist/components/LpHintExample.vue.js +1 -1
  225. package/dist/components/LpHintLayer.vue.js +1 -1
  226. package/dist/components/LpHints.vue.js +1 -1
  227. package/dist/components/LpHoverCard.vue.d.ts +60 -0
  228. package/dist/components/LpHoverCard.vue.js +4 -0
  229. package/dist/components/LpIcon.vue.js +1 -1
  230. package/dist/components/LpIdenticon.vue.d.ts +37 -0
  231. package/dist/components/LpIdenticon.vue.js +4 -0
  232. package/dist/components/LpImageEditor.vue.js +13 -19
  233. package/dist/components/LpInfraNode.vue.js +1 -1
  234. package/dist/components/LpInput.vue.d.ts +10 -0
  235. package/dist/components/LpInput.vue.js +1 -1
  236. package/dist/components/LpLightbox.vue.js +1 -1
  237. package/dist/components/LpLoader.vue.d.ts +106 -0
  238. package/dist/components/LpLoader.vue.js +4 -0
  239. package/dist/components/LpLogViewer.vue.js +1 -1
  240. package/dist/components/LpMagnetic.vue.d.ts +28 -0
  241. package/dist/components/LpMagnetic.vue.js +4 -0
  242. package/dist/components/LpMapPicker.vue.js +1 -1
  243. package/dist/components/LpMasonry.vue.d.ts +42 -0
  244. package/dist/components/LpMasonry.vue.js +4 -0
  245. package/dist/components/LpMediaGallery.vue.js +1 -1
  246. package/dist/components/LpModal.vue.js +1 -1
  247. package/dist/components/LpModalNav.vue.js +1 -1
  248. package/dist/components/LpNotificationBell.vue.d.ts +15 -6
  249. package/dist/components/LpNotificationBell.vue.js +1 -1
  250. package/dist/components/LpNumberField.vue.d.ts +57 -0
  251. package/dist/components/LpNumberField.vue.js +1 -1
  252. package/dist/components/LpNumberFlow.vue.js +1 -1
  253. package/dist/components/LpOtpInput.vue.d.ts +12 -4
  254. package/dist/components/LpOtpInput.vue.js +1 -1
  255. package/dist/components/LpPagination.vue.js +1 -1
  256. package/dist/components/LpPaletteFacts.vue.js +2 -2
  257. package/dist/components/LpPaletteHeader.vue.js +2 -2
  258. package/dist/components/LpPalettePreview.vue.js +1 -1
  259. package/dist/components/LpPaletteStats.vue.js +2 -2
  260. package/dist/components/LpPasswordInput.vue.d.ts +19 -2
  261. package/dist/components/LpPasswordInput.vue.js +1 -1
  262. package/dist/components/LpPhoneInput.vue.js +1 -1
  263. package/dist/components/LpPie.vue.d.ts +3 -1
  264. package/dist/components/LpPie.vue.js +1 -1
  265. package/dist/components/LpPipeline.vue.d.ts +91 -0
  266. package/dist/components/LpPipeline.vue.js +4 -0
  267. package/dist/components/LpPopover.vue.d.ts +2 -2
  268. package/dist/components/LpPopover.vue.js +1 -1
  269. package/dist/components/LpProgress.vue.d.ts +11 -4
  270. package/dist/components/LpProgress.vue.js +1 -1
  271. package/dist/components/LpQuota.vue.d.ts +68 -0
  272. package/dist/components/LpQuota.vue.js +4 -0
  273. package/dist/components/LpRadioGroup.vue.js +1 -1
  274. package/dist/components/LpRangeCalendar.vue.js +1 -1
  275. package/dist/components/LpRangeSlider.vue.js +1 -1
  276. package/dist/components/LpRelativeTime.vue.d.ts +41 -0
  277. package/dist/components/LpRelativeTime.vue.js +4 -0
  278. package/dist/components/LpRepeater.vue.d.ts +48 -0
  279. package/dist/components/LpRepeater.vue.js +4 -0
  280. package/dist/components/LpRevealOnScroll.vue.d.ts +67 -0
  281. package/dist/components/LpRevealOnScroll.vue.js +4 -0
  282. package/dist/components/LpRollingText.vue.d.ts +3 -1
  283. package/dist/components/LpRollingText.vue.js +1 -1
  284. package/dist/components/LpScramble.vue.d.ts +55 -0
  285. package/dist/components/LpScramble.vue.js +4 -0
  286. package/dist/components/LpScrollArea.vue.d.ts +1 -1
  287. package/dist/components/LpSecretField.vue.d.ts +108 -0
  288. package/dist/components/LpSecretField.vue.js +4 -0
  289. package/dist/components/LpSection.vue.js +1 -1
  290. package/dist/components/LpSegmented.vue.js +1 -1
  291. package/dist/components/LpSelect.vue.d.ts +2 -0
  292. package/dist/components/LpSelect.vue.js +1 -1
  293. package/dist/components/LpShaderBackdrop.vue.d.ts +39 -0
  294. package/dist/components/LpShaderBackdrop.vue.js +4 -0
  295. package/dist/components/LpShinyText.vue.d.ts +39 -0
  296. package/dist/components/LpShinyText.vue.js +4 -0
  297. package/dist/components/LpShortcutsDialog.vue.js +1 -1
  298. package/dist/components/LpSidebar.vue.js +1 -1
  299. package/dist/components/LpSidebarNav.vue.js +1 -1
  300. package/dist/components/LpSlider.vue.js +1 -1
  301. package/dist/components/LpSparkline.vue.d.ts +4 -3
  302. package/dist/components/LpSparkline.vue.js +1 -1
  303. package/dist/components/LpSpotlight.vue.d.ts +37 -0
  304. package/dist/components/LpSpotlight.vue.js +4 -0
  305. package/dist/components/LpStat.vue.js +1 -1
  306. package/dist/components/LpStatus.vue.d.ts +65 -0
  307. package/dist/components/LpStatus.vue.js +4 -0
  308. package/dist/components/LpStepMark.vue.d.ts +31 -0
  309. package/dist/components/LpStepMark.vue.js +4 -0
  310. package/dist/components/LpStepper.vue.js +1 -1
  311. package/dist/components/LpSwap.vue.js +1 -1
  312. package/dist/components/LpSwitch.vue.d.ts +2 -2
  313. package/dist/components/LpSwitch.vue.js +1 -1
  314. package/dist/components/LpTable.vue.js +104 -120
  315. package/dist/components/LpTableFilter.vue.js +1 -1
  316. package/dist/components/LpTableOfContents.vue.d.ts +6 -1
  317. package/dist/components/LpTableOfContents.vue.js +1 -1
  318. package/dist/components/LpTabs.vue.d.ts +5 -5
  319. package/dist/components/LpTabs.vue.js +25 -33
  320. package/dist/components/LpTagsInput.vue.js +1 -1
  321. package/dist/components/LpTextReveal.vue.d.ts +58 -0
  322. package/dist/components/LpTextReveal.vue.js +4 -0
  323. package/dist/components/LpTextarea.vue.js +1 -1
  324. package/dist/components/LpThemeProvider.vue.js +1 -1
  325. package/dist/components/LpThemeStudio.vue.d.ts +54 -0
  326. package/dist/components/LpThemeStudio.vue.js +4 -0
  327. package/dist/components/LpThemeStudioSection.vue.d.ts +16 -0
  328. package/dist/components/LpThemeStudioSection.vue.js +4 -0
  329. package/dist/components/LpThemeSwitcher.vue.d.ts +32 -1
  330. package/dist/components/LpThemeSwitcher.vue.js +1 -1
  331. package/dist/components/LpTimeField.vue.d.ts +2 -0
  332. package/dist/components/LpTimeField.vue.js +1 -1
  333. package/dist/components/LpToaster.vue.js +1 -1
  334. package/dist/components/LpTooltip.vue.d.ts +2 -2
  335. package/dist/components/LpTooltip.vue.js +1 -1
  336. package/dist/components/LpTopologyCanvas.vue.js +1 -1
  337. package/dist/components/LpTour.vue.js +1 -1
  338. package/dist/components/LpTruncate.vue.d.ts +34 -0
  339. package/dist/components/LpTruncate.vue.js +4 -0
  340. package/dist/components/LpTypewriter.vue.d.ts +61 -0
  341. package/dist/components/LpTypewriter.vue.js +4 -0
  342. package/dist/components/LpUptimeBar.vue.js +1 -1
  343. package/dist/components/LpVideoBackdrop.vue.js +1 -1
  344. package/dist/components/MenuTitle.vue.js +1 -1
  345. package/dist/components/OptionContent.vue.d.ts +7 -0
  346. package/dist/components/OptionContent.vue.js +4 -0
  347. package/dist/components/PickerField.vue.d.ts +45 -0
  348. package/dist/components/PickerField.vue.js +4 -0
  349. package/dist/components/RevealToggle.vue.d.ts +21 -0
  350. package/dist/components/RevealToggle.vue.js +4 -0
  351. package/dist/components/StepConnector.vue.d.ts +19 -0
  352. package/dist/components/StepConnector.vue.js +4 -0
  353. package/dist/components/TourCard.vue.js +1 -1
  354. package/dist/components/badge.d.ts +1 -0
  355. package/dist/components/badge.js +4 -0
  356. package/dist/components/chart.d.ts +5 -1
  357. package/dist/components/chart.js +2 -21
  358. package/dist/components/dateRange.d.ts +11 -0
  359. package/dist/components/dateRange.js +12 -0
  360. package/dist/components/dock.d.ts +19 -0
  361. package/dist/components/dock.js +16 -0
  362. package/dist/components/dropdown.d.ts +10 -1
  363. package/dist/components/dropdown.js +7 -2
  364. package/dist/components/fieldText.d.ts +38 -0
  365. package/dist/components/fieldText.js +53 -0
  366. package/dist/components/fileTree.d.ts +7 -3
  367. package/dist/components/fileTree.js +12 -18
  368. package/dist/components/format.d.ts +41 -0
  369. package/dist/components/format.js +67 -0
  370. package/dist/components/identicon.d.ts +38 -0
  371. package/dist/components/identicon.js +85 -0
  372. package/dist/components/masonry.d.ts +32 -0
  373. package/dist/components/masonry.js +40 -0
  374. package/dist/components/menuWhen.js +1 -1
  375. package/dist/components/meter.d.ts +64 -0
  376. package/dist/components/meter.js +53 -0
  377. package/dist/components/otp.d.ts +1 -1
  378. package/dist/components/otp.js +7 -2
  379. package/dist/components/pipeline.d.ts +55 -0
  380. package/dist/components/pipeline.js +51 -0
  381. package/dist/components/quota.d.ts +57 -0
  382. package/dist/components/quota.js +40 -0
  383. package/dist/components/relativeTime.d.ts +24 -0
  384. package/dist/components/relativeTime.js +56 -0
  385. package/dist/components/reveal.d.ts +18 -0
  386. package/dist/components/reveal.js +32 -0
  387. package/dist/components/scramble.d.ts +68 -0
  388. package/dist/components/scramble.js +58 -0
  389. package/dist/components/shaderBackdrop.d.ts +20 -0
  390. package/dist/components/shaderBackdrop.js +156 -0
  391. package/dist/components/slider.d.ts +5 -0
  392. package/dist/components/slider.js +24 -0
  393. package/dist/components/slotText.d.ts +2 -0
  394. package/dist/components/slotText.js +9 -0
  395. package/dist/components/status.d.ts +14 -0
  396. package/dist/components/status.js +22 -0
  397. package/dist/components/tableFacets.d.ts +8 -0
  398. package/dist/components/tableFacets.js +19 -0
  399. package/dist/components/textSplit.d.ts +17 -0
  400. package/dist/components/textSplit.js +24 -0
  401. package/dist/components/timeSpan.d.ts +78 -0
  402. package/dist/components/timeSpan.js +85 -0
  403. package/dist/components/tone.d.ts +43 -0
  404. package/dist/components/tone.js +82 -0
  405. package/dist/components/tour.js +3 -2
  406. package/dist/components/typewriter.d.ts +36 -0
  407. package/dist/components/typewriter.js +53 -0
  408. package/dist/components/videoBackdrop.js +5 -6
  409. package/dist/composables/easing.d.ts +22 -1
  410. package/dist/composables/easing.js +42 -1
  411. package/dist/composables/pseudoLocale.d.ts +15 -0
  412. package/dist/composables/pseudoLocale.js +96 -0
  413. package/dist/composables/scroll.js +5 -3
  414. package/dist/composables/useClipboard.d.ts +4 -1
  415. package/dist/composables/useClipboard.js +12 -2
  416. package/dist/composables/useField.d.ts +13 -0
  417. package/dist/composables/useField.js +26 -1
  418. package/dist/composables/useForm.js +32 -9
  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 +64 -0
  451. package/dist/icons-all.js +1 -1
  452. package/dist/index.d.ts +98 -1
  453. package/dist/index.js +263 -105
  454. package/dist/theme/define.d.ts +12 -0
  455. package/dist/theme/studio.d.ts +90 -0
  456. package/package.json +8 -2
  457. package/src/component-names.ts +33 -0
  458. package/src/components/AttentionDot.vue +27 -0
  459. package/src/components/ContextMenuItems.vue +5 -2
  460. package/src/components/FieldWrapper.vue +38 -0
  461. package/src/components/LayoutNode.vue +5 -9
  462. package/src/components/LegendSwatch.vue +15 -0
  463. package/src/components/LoaderMark.vue +90 -0
  464. package/src/components/LpActionBar.vue +12 -20
  465. package/src/components/LpActivityLine.vue +186 -0
  466. package/src/components/LpAlert.vue +54 -24
  467. package/src/components/LpAppShell.vue +7 -11
  468. package/src/components/LpAutocomplete.vue +16 -14
  469. package/src/components/LpAvatar.vue +17 -2
  470. package/src/components/LpBadge.vue +77 -13
  471. package/src/components/LpBreadcrumbs.vue +101 -35
  472. package/src/components/LpButton.vue +15 -3
  473. package/src/components/LpCard.vue +30 -7
  474. package/src/components/LpChart.vue +162 -171
  475. package/src/components/LpCheckbox.vue +10 -4
  476. package/src/components/LpCodeBlock.vue +11 -19
  477. package/src/components/LpCodeDisplay.vue +228 -0
  478. package/src/components/LpCollapse.vue +162 -0
  479. package/src/components/LpColorPicker.vue +10 -1
  480. package/src/components/LpCommandPalette.vue +38 -24
  481. package/src/components/LpContextMenu.vue +13 -3
  482. package/src/components/LpCopyButton.vue +185 -0
  483. package/src/components/LpCountdown.vue +308 -0
  484. package/src/components/LpDataList.vue +154 -0
  485. package/src/components/LpDatePicker.vue +55 -104
  486. package/src/components/LpDateRangePicker.vue +51 -95
  487. package/src/components/LpDisclosure.vue +58 -36
  488. package/src/components/LpDock.vue +274 -0
  489. package/src/components/LpDrawer.vue +10 -1
  490. package/src/components/LpDropdownMenu.vue +11 -2
  491. package/src/components/LpDropzone.vue +34 -13
  492. package/src/components/LpEditable.vue +295 -0
  493. package/src/components/LpFileTree.vue +5 -1
  494. package/src/components/LpFileTreeNode.vue +25 -50
  495. package/src/components/LpFormField.vue +22 -3
  496. package/src/components/LpFrame.vue +200 -0
  497. package/src/components/LpGauge.vue +287 -0
  498. package/src/components/LpGlowBorder.vue +60 -0
  499. package/src/components/LpHintExample.vue +9 -32
  500. package/src/components/LpHintLayer.vue +13 -3
  501. package/src/components/LpHoverCard.vue +175 -0
  502. package/src/components/LpIdenticon.vue +69 -0
  503. package/src/components/LpImageEditor.vue +15 -18
  504. package/src/components/LpInfraNode.vue +27 -16
  505. package/src/components/LpInput.vue +30 -16
  506. package/src/components/LpLightbox.vue +44 -23
  507. package/src/components/LpLoader.vue +145 -0
  508. package/src/components/LpLogViewer.vue +311 -82
  509. package/src/components/LpMagnetic.vue +97 -0
  510. package/src/components/LpMapPicker.vue +26 -28
  511. package/src/components/LpMasonry.vue +247 -0
  512. package/src/components/LpModal.vue +10 -1
  513. package/src/components/LpNotificationBell.vue +33 -49
  514. package/src/components/LpNumberField.vue +79 -14
  515. package/src/components/LpNumberFlow.vue +10 -35
  516. package/src/components/LpOtpInput.vue +7 -2
  517. package/src/components/LpPagination.vue +38 -4
  518. package/src/components/LpPalettePreview.vue +2 -7
  519. package/src/components/LpPasswordInput.vue +25 -18
  520. package/src/components/LpPhoneInput.vue +12 -3
  521. package/src/components/LpPie.vue +197 -36
  522. package/src/components/LpPipeline.vue +366 -0
  523. package/src/components/LpPopover.vue +14 -1
  524. package/src/components/LpProgress.vue +22 -84
  525. package/src/components/LpQuota.vue +197 -0
  526. package/src/components/LpRangeSlider.vue +5 -1
  527. package/src/components/LpRelativeTime.vue +90 -0
  528. package/src/components/LpRepeater.vue +131 -0
  529. package/src/components/LpRevealOnScroll.vue +125 -0
  530. package/src/components/LpRollingText.vue +12 -1
  531. package/src/components/LpScramble.vue +107 -0
  532. package/src/components/LpSecretField.vue +320 -0
  533. package/src/components/LpSegmented.vue +3 -10
  534. package/src/components/LpSelect.vue +74 -65
  535. package/src/components/LpShaderBackdrop.vue +434 -0
  536. package/src/components/LpShinyText.vue +139 -0
  537. package/src/components/LpSidebar.vue +2 -0
  538. package/src/components/LpSlider.vue +5 -1
  539. package/src/components/LpSparkline.vue +55 -37
  540. package/src/components/LpSpotlight.vue +51 -0
  541. package/src/components/LpStat.vue +6 -2
  542. package/src/components/LpStatus.vue +127 -0
  543. package/src/components/LpStepMark.vue +138 -0
  544. package/src/components/LpStepper.vue +37 -43
  545. package/src/components/LpSwap.vue +2 -2
  546. package/src/components/LpSwitch.vue +15 -22
  547. package/src/components/LpTable.vue +47 -63
  548. package/src/components/LpTableFilter.vue +1 -0
  549. package/src/components/LpTableOfContents.vue +53 -29
  550. package/src/components/LpTabs.vue +10 -21
  551. package/src/components/LpTagsInput.vue +53 -37
  552. package/src/components/LpTextReveal.vue +236 -0
  553. package/src/components/LpTextarea.vue +11 -11
  554. package/src/components/LpThemeStudio.vue +216 -0
  555. package/src/components/LpThemeStudioSection.vue +16 -0
  556. package/src/components/LpThemeSwitcher.vue +156 -47
  557. package/src/components/LpTimeField.vue +9 -1
  558. package/src/components/LpToaster.vue +63 -83
  559. package/src/components/LpTooltip.vue +10 -1
  560. package/src/components/LpTour.vue +24 -13
  561. package/src/components/LpTruncate.vue +135 -0
  562. package/src/components/LpTypewriter.vue +236 -0
  563. package/src/components/LpUptimeBar.vue +6 -5
  564. package/src/components/LpVideoBackdrop.vue +15 -13
  565. package/src/components/OptionContent.vue +17 -0
  566. package/src/components/PickerField.vue +59 -0
  567. package/src/components/RevealToggle.vue +51 -0
  568. package/src/components/StepConnector.vue +54 -0
  569. package/src/components/TourCard.vue +29 -16
  570. package/src/components/badge.ts +8 -0
  571. package/src/components/chart.ts +8 -23
  572. package/src/components/dateRange.ts +25 -0
  573. package/src/components/dock.ts +31 -0
  574. package/src/components/dropdown.ts +15 -3
  575. package/src/components/fieldText.ts +95 -0
  576. package/src/components/fileTree.ts +19 -21
  577. package/src/components/format.ts +136 -0
  578. package/src/components/identicon.ts +160 -0
  579. package/src/components/masonry.ts +73 -0
  580. package/src/components/meter.ts +122 -0
  581. package/src/components/otp.ts +14 -3
  582. package/src/components/pipeline.ts +101 -0
  583. package/src/components/quota.ts +111 -0
  584. package/src/components/relativeTime.ts +118 -0
  585. package/src/components/reveal.ts +56 -0
  586. package/src/components/scramble.ts +138 -0
  587. package/src/components/shaderBackdrop.ts +208 -0
  588. package/src/components/slider.ts +30 -0
  589. package/src/components/slotText.ts +13 -0
  590. package/src/components/status.ts +46 -0
  591. package/src/components/tableFacets.ts +25 -0
  592. package/src/components/textSplit.ts +55 -0
  593. package/src/components/timeSpan.ts +183 -0
  594. package/src/components/tone.ts +144 -0
  595. package/src/components/tour.ts +3 -2
  596. package/src/components/typewriter.ts +104 -0
  597. package/src/components/videoBackdrop.ts +7 -6
  598. package/src/composables/easing.ts +66 -1
  599. package/src/composables/pseudoLocale.ts +105 -0
  600. package/src/composables/scroll.ts +6 -3
  601. package/src/composables/useClipboard.ts +25 -3
  602. package/src/composables/useField.ts +38 -1
  603. package/src/composables/useForm.ts +41 -11
  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 +96 -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
@@ -35,16 +35,18 @@ import {
35
35
  ComboboxTrigger,
36
36
  ComboboxViewport,
37
37
  } from "reka-ui"
38
- import { computed, nextTick, onBeforeUnmount, reactive, ref, watch } from "vue"
39
- import { useFieldControl } from "../composables/useField"
38
+ import { computed, nextTick, reactive, ref, useAttrs, useId, watch } from "vue"
39
+ import { useFieldBlur, useFieldControl } from "../composables/useField"
40
40
  import { useLabels } from "../composables/useLpConfig"
41
41
  import { useMergedAttrs } from "../composables/useMergedClass"
42
- import { OPTION_ITEM, POPOVER_PANEL } from "./dropdown"
42
+ import { OPTION_ITEM, optionStagger, POPOVER_PANEL } from "./dropdown"
43
43
  import LpIcon from "./LpIcon.vue"
44
+ import OptionContent from "./OptionContent.vue"
44
45
  import LpRollingText from "./LpRollingText.vue"
45
- import LpShift from "./LpShift.vue"
46
46
  import type { LpOptionBase, OptionSelection } from "./options"
47
47
  import { fitChips, toggledValues } from "./select"
48
+ import { useOutsideGuard, usePortalTarget } from "../composables/useView"
49
+ import { useResizeObserver } from "../composables/useResizeObserver"
48
50
 
49
51
  export type SelectValue = string | number
50
52
 
@@ -143,6 +145,8 @@ const emit = defineEmits<{
143
145
  (e: "change", value: V): void
144
146
  // Search input text (for `v-model:searchTerm` / server-side search).
145
147
  (e: "update:searchTerm", value: string): void
148
+ /** Focus left the whole field (not into its own list or clear button). */
149
+ (e: "blur", event: FocusEvent): void
146
150
  }>()
147
151
 
148
152
  // Server-side search is active when the parent binds searchTerm.
@@ -164,10 +168,33 @@ const query = computed<string>({
164
168
  // This is not enough on its own: reka seeds the box on *select*, not on open,
165
169
  // so the next opening filters before this runs. `reset-search-term-on-select`
166
170
  // below is what stops the seeding; this keeps a stale term from surviving.
167
- function onOpenChange(_open: boolean) {
171
+ const isOpen = ref(false)
172
+ function onOpenChange(open: boolean) {
173
+ isOpen.value = open
168
174
  query.value = ""
169
175
  }
170
176
 
177
+ // Leaving the field, not moving between its parts: the trigger and the list
178
+ // are marked with one id, because the list is portalled away from the trigger
179
+ // and a check on the trigger alone either missed the search box or took a
180
+ // step into it for leaving.
181
+ const { partId, onFocusOut } = useFieldBlur((event) => emit("blur", event))
182
+
183
+ /*
184
+ * The trigger's name. reka hard-codes aria-label="Show popup" on it, which hid
185
+ * the field's label and the chosen value; aria-labelledby outranks aria-label,
186
+ * so inside a labelled field the name is the label plus the value. On its own,
187
+ * the consumer's aria-label, else the value or placeholder.
188
+ */
189
+ const attrs = useAttrs()
190
+ const valueId = `lp-select-${useId()}-value`
191
+ const valueText = computed(() => (chips.value.length ? chipNames.value : displayLabel.value || placeholderText.value))
192
+ const triggerName = computed(() =>
193
+ field.value.labelId
194
+ ? { "aria-labelledby": `${field.value.labelId} ${valueId}`, "aria-label": undefined }
195
+ : { "aria-label": (attrs["aria-label"] as string | undefined) ?? valueText.value },
196
+ )
197
+
171
198
  // reka's Combobox forbids an empty-string item value (it reserves "" for
172
199
  // "cleared"). An empty-string option is legitimate for us (e.g. "Any edition"),
173
200
  // so we encode "" to a sentinel for reka and decode it back at the boundary —
@@ -271,6 +298,12 @@ const displayLabel = computed(() => {
271
298
  return current.value?.label ?? ""
272
299
  })
273
300
 
301
+ // What makes the shown pick "another one": its name, hint and picture together.
302
+ const rollKey = computed(() => {
303
+ const c = current.value
304
+ return c ? [c.label, c.hint ?? "", c.image ?? c.icon ?? ""].join("\u0000") : `\u0000${placeholderText.value}`
305
+ })
306
+
274
307
  /*
275
308
  * Chips collapse to "+N" when the row runs out of room. Every chip is drawn a
276
309
  * second time in an invisible probe row at its natural width; the visible row
@@ -296,16 +329,8 @@ function measure() {
296
329
  )
297
330
  }
298
331
 
299
- let rowObserver: ResizeObserver | null = null
300
- watch(chipRow, (row) => {
301
- rowObserver?.disconnect()
302
- rowObserver = null
303
- if (!row || typeof ResizeObserver === "undefined") return
304
- rowObserver = new ResizeObserver(() => measure())
305
- rowObserver.observe(row)
306
- })
332
+ useResizeObserver(chipRow, () => measure())
307
333
  watch(chips, () => void nextTick(measure), { flush: "post", deep: true })
308
- onBeforeUnmount(() => rowObserver?.disconnect())
309
334
 
310
335
  const shownChips = computed(() => chips.value.slice(0, fit.value))
311
336
  const hiddenCount = computed(() => modelList.value.length - shownChips.value.length)
@@ -334,8 +359,15 @@ function onUpdate(value: unknown) {
334
359
  }
335
360
 
336
361
  function clear() {
362
+ if (field.value.disabled) return
337
363
  emit("update:modelValue", (props.multiple ? [] : undefined) as Model)
338
364
  }
365
+
366
+ // Overlays open in the window this component renders in (an LpFrame's, inside one).
367
+ const portalTo = usePortalTarget()
368
+ // What happens in another document (the page around a frame, or a frame in
369
+ // the page) is not "outside" for this layer.
370
+ const guardOutside = useOutsideGuard()
339
371
  </script>
340
372
 
341
373
  <template>
@@ -349,6 +381,7 @@ function clear() {
349
381
  :model-value="comboModel"
350
382
  :multiple="multiple"
351
383
  :disabled="field.disabled"
384
+ :required="field.required"
352
385
  :ignore-filter="true"
353
386
  :reset-search-term-on-select="false"
354
387
  :reset-search-term-on-blur="false"
@@ -358,9 +391,12 @@ function clear() {
358
391
  @update:open="onOpenChange"
359
392
  >
360
393
  <ComboboxAnchor
394
+ :data-lp-field-part="partId"
395
+ @focusout="onFocusOut"
361
396
  :class="[
362
397
  anchorHeight,
363
- 'group flex w-full items-center gap-2 rounded-control border bg-surface-soft px-3 text-sm text-ink transition-colors duration-[var(--duration-fast)] focus-within:ring-2 data-[disabled]:cursor-not-allowed data-[disabled]:opacity-55',
398
+ 'group flex w-full items-center gap-2 rounded-control border bg-surface-soft px-3 text-sm text-ink transition-colors duration-[var(--duration-fast)] focus-within:ring-2',
399
+ field.disabled && 'cursor-not-allowed opacity-55',
364
400
  field.invalid
365
401
  ? 'border-danger focus-within:border-danger focus-within:ring-danger-soft'
366
402
  : 'border-line focus-within:border-brand focus-within:ring-ring',
@@ -370,8 +406,10 @@ function clear() {
370
406
  will not go narrower than its content without it, so a long
371
407
  placeholder stretched the whole field past the viewport instead of
372
408
  being cut short. -->
409
+ <span :id="valueId" hidden>{{ valueText }}</span>
373
410
  <ComboboxTrigger
374
411
  :id="field.id"
412
+ v-bind="triggerName"
375
413
  :aria-invalid="field.invalid || undefined"
376
414
  :aria-describedby="field.describedBy"
377
415
  class="flex min-w-0 flex-1 items-center gap-2 outline-none"
@@ -429,52 +467,28 @@ function clear() {
429
467
  </span>
430
468
  </span>
431
469
  <template v-else>
432
- <!-- The pick's picture or icon eases in beside the name; the box it
433
- sits in grows rather than shoving the name over in one frame. -->
434
- <LpShift axis="width" class="shrink-0">
435
- <Transition
436
- mode="out-in"
437
- enter-active-class="transition-[opacity,scale] duration-[var(--duration-fast)] motion-reduce:transition-none"
438
- leave-active-class="transition-[opacity,scale] duration-[var(--duration-fast)] motion-reduce:transition-none"
439
- enter-from-class="scale-75 opacity-0"
440
- leave-to-class="scale-75 opacity-0"
441
- >
470
+ <!-- The pick turns over as one piece: its picture, name and hint
471
+ leave together and the next ones arrive together. Animated
472
+ apart (a fading picture, a rolling name, a cross-faded hint)
473
+ they ran at three speeds, and for a moment the old hint stood
474
+ beside the new one and shoved the row. -->
475
+ <LpRollingText :value="rollKey" align="start" class="min-w-0 flex-1">
476
+ <span class="flex min-w-0 items-center gap-2">
442
477
  <img
443
478
  v-if="current?.image"
444
- :key="current.image"
445
479
  :src="current.image"
446
480
  alt=""
447
- class="block size-5 rounded-full object-cover"
481
+ class="block size-5 shrink-0 rounded-full object-cover"
448
482
  />
449
- <LpIcon
450
- v-else-if="current?.icon"
451
- :key="current.icon"
452
- :name="current.icon"
453
- :size="16"
454
- class="block text-muted"
455
- />
456
- </Transition>
457
- </LpShift>
458
- <!-- The choice rolls in rather than swapping, as the kit's other
459
- changing labels do. -->
460
- <LpRollingText
461
- :value="displayLabel || placeholderText"
462
- align="start"
463
- class="min-w-0"
464
- :class="displayLabel ? '' : 'text-muted'"
465
- />
466
- <Transition
467
- enter-active-class="transition-opacity duration-[var(--duration-fast)] motion-reduce:transition-none"
468
- leave-active-class="transition-opacity duration-[var(--duration-fast)] motion-reduce:transition-none"
469
- enter-from-class="opacity-0"
470
- leave-to-class="opacity-0"
471
- >
472
- <span v-if="current?.hint" :key="current.hint" class="min-w-0 truncate text-muted">{{ current.hint }}</span>
473
- </Transition>
483
+ <LpIcon v-else-if="current?.icon" :name="current.icon" :size="16" class="block shrink-0 text-muted" />
484
+ <span class="min-w-0 truncate" :class="displayLabel ? '' : 'text-muted'">{{ displayLabel || placeholderText }}</span>
485
+ <span v-if="current?.hint" class="min-w-0 truncate text-muted">{{ current.hint }}</span>
486
+ </span>
487
+ </LpRollingText>
474
488
  </template>
475
489
  </ComboboxTrigger>
476
490
  <button
477
- v-if="clearable && hasValue"
491
+ v-if="clearable && hasValue && !field.disabled"
478
492
  type="button"
479
493
  class="group flex shrink-0 items-center text-muted outline-none transition-colors duration-[var(--duration-fast)] hover:text-ink"
480
494
  :aria-label="labels.clear"
@@ -507,8 +521,12 @@ function clear() {
507
521
  </ComboboxTrigger>
508
522
  </ComboboxAnchor>
509
523
 
510
- <ComboboxPortal>
524
+ <ComboboxPortal :to="portalTo">
511
525
  <ComboboxContent
526
+ :data-lp-field-part="partId"
527
+ @focusout="onFocusOut"
528
+ @interact-outside="guardOutside"
529
+ @escape-key-down="guardOutside"
512
530
  position="popper"
513
531
  :side-offset="6"
514
532
  :class="[POPOVER_PANEL, 'z-(--z-popover) max-h-72 w-(--reka-combobox-trigger-width) overflow-hidden']"
@@ -535,19 +553,10 @@ function clear() {
535
553
  :key="String(opt.value)"
536
554
  :value="encode(opt.value)"
537
555
  :disabled="opt.disabled"
538
- :style="{ animationDelay: `${Math.min(i, 12) * 22}ms` }"
556
+ :style="optionStagger(i)"
539
557
  :class="[OPTION_ITEM, 'justify-between data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50']"
540
558
  >
541
- <span class="flex min-w-0 items-center gap-2.5">
542
- <img v-if="opt.image" :src="opt.image" alt="" class="size-6 shrink-0 rounded-full object-cover" />
543
- <LpIcon v-else-if="opt.icon" :name="opt.icon" :size="16" class="shrink-0 text-muted" />
544
- <span class="flex min-w-0 flex-col">
545
- <span class="truncate">{{ opt.label }}</span>
546
- <span v-if="opt.description" class="truncate text-xs text-muted">
547
- {{ opt.description }}
548
- </span>
549
- </span>
550
- </span>
559
+ <OptionContent :option="opt" />
551
560
  <ComboboxItemIndicator class="flex shrink-0 items-center text-brand">
552
561
  <LpIcon name="lucide:check" :size="16" />
553
562
  </ComboboxItemIndicator>
@@ -0,0 +1,434 @@
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 slowly moving decorative background, drawn on the GPU: behind a sign-in
11
+ * screen, a hero, an empty state, a launcher's home. It fills the box it is
12
+ * put in (`absolute inset-0`, so position the parent) and takes no pointer
13
+ * events.
14
+ *
15
+ * <section class="relative">
16
+ * <LpShaderBackdrop preset="aurora" />
17
+ * …content…
18
+ * </section>
19
+ *
20
+ * Looks (`preset`, see shaderBackdrop.ts): `aurora` (flowing bands of light),
21
+ * `silk` (folded sheen), `grain` (drifting colour under film grain), `dots`
22
+ * (a dot grid with a travelling ripple). All are coloured from the theme's
23
+ * tokens and follow a theme change, blending to the new colours.
24
+ *
25
+ * What makes it safe to drop in anywhere:
26
+ * - A CSS still of the same look is always underneath. It is what shows
27
+ * while the first frame is drawn, and instead of the canvas where WebGL is
28
+ * missing, software-only, loses its context, or cannot keep up (judged on
29
+ * the first second of frames) — the cases that occur on WebKitGTK, where the
30
+ * kit's desktop shells run. The page looks the same; it only stops moving.
31
+ * - Reduced motion gets the still, without creating a GL context at all.
32
+ * - It draws only while someone can see it: off-screen (IntersectionObserver),
33
+ * in a hidden tab, or `paused`, the loop stops. Frames are capped (`fps`),
34
+ * since a background gains nothing from 120 a second.
35
+ * - Unmounting releases the GL context, so a page that mounts and unmounts
36
+ * backdrops does not run into the browser's limit on live contexts.
37
+ */
38
+ import { computed, onBeforeUnmount, onMounted, ref, watch } from "vue"
39
+ import { parseColor } from "./color"
40
+ import { approach, frameDue, FRAGMENT_HEADER, PRESETS, tooSlow, VERTEX_SHADER, type ShaderPreset, type Vec3 } from "./shaderBackdrop"
41
+ import { isBrokenBackdropEngine } from "../theme/backdrop"
42
+ import { durationToken } from "../composables/easing"
43
+ import { useInView } from "../composables/useInView"
44
+ import { useMergedAttrs } from "../composables/useMergedClass"
45
+ import { usePrefersReducedMotion } from "../composables/useReducedMotion"
46
+ import { useResizeObserver } from "../composables/useResizeObserver"
47
+
48
+ const props = withDefaults(
49
+ defineProps<{
50
+ preset?: ShaderPreset
51
+ /** How strongly the theme colours show over the surface, 0–1. Lower for a backdrop under body text. */
52
+ intensity?: number
53
+ /** Motion speed; 1 is a calm drift, 0.5 half as fast. */
54
+ speed?: number
55
+ /** Frame cap. 30 is smooth for slow motion and half the work of 60. */
56
+ fps?: number
57
+ /** Hold the current frame. */
58
+ paused?: boolean
59
+ /** Always show the CSS still, never start WebGL: for a low-power mode or a screenshot. */
60
+ still?: boolean
61
+ }>(),
62
+ { preset: "aurora", intensity: 0.7, speed: 1, fps: 30, paused: false, still: false },
63
+ )
64
+
65
+ const emit = defineEmits<{
66
+ /** WebGL could not be used (missing, too slow, context lost); the still is showing. Useful to log, not to act on. */
67
+ (e: "fallback", reason: "unavailable" | "slow" | "lost" | "compile"): void
68
+ }>()
69
+
70
+ /*
71
+ * Whether anyone can see it (on screen, in a visible tab) and whether the OS
72
+ * asks for less motion are the kit's own questions (useInView,
73
+ * usePrefersReducedMotion); the root element is the one watched.
74
+ */
75
+ const { el: root, inView } = useInView()
76
+ const reduced = usePrefersReducedMotion()
77
+ const canvas = ref<HTMLCanvasElement | null>(null)
78
+ /** Bumped whenever a context is released: a canvas whose context was lost cannot get a new one. */
79
+ const canvasKey = ref(0)
80
+
81
+ const failed = ref(false)
82
+ /** The canvas holds a finished frame of the current look and is faded in over the still. */
83
+ const shown = ref(false)
84
+
85
+ const wantGl = computed(() => !props.still && !reduced.value && !failed.value)
86
+ const animating = computed(() => !props.paused && inView.value)
87
+
88
+ /*
89
+ * WebKitGTK composites on the CPU more often than not. There the canvas is
90
+ * drawn at one device pixel per CSS pixel and at most 24 frames a second,
91
+ * which keeps the look and halves the cost again.
92
+ */
93
+ const weakEngine = typeof navigator !== "undefined" && isBrokenBackdropEngine()
94
+
95
+ const fallbackStyle = computed(() => ({ background: PRESETS[props.preset].fallback, opacity: Math.min(1, clamp01(props.intensity) * 1.15) }))
96
+
97
+ function clamp01(n: number) {
98
+ return Math.max(0, Math.min(1, n))
99
+ }
100
+
101
+ // ── Theme colours ───────────────────────────────────────────────────────────
102
+
103
+ const TOKENS = ["surface", "brand", "accent", "action", "ink"] as const
104
+ type Palette = Record<(typeof TOKENS)[number], Vec3>
105
+
106
+ let probe: HTMLSpanElement | null = null
107
+ let paint: CanvasRenderingContext2D | null = null
108
+
109
+ /*
110
+ * A token's colour as numbers. The computed `color` of a probe styled with
111
+ * the variable resolves any scoped override and any colour syntax a theme
112
+ * uses; rgb() is parsed directly, and anything newer (color(), oklch()) is
113
+ * handed to a 2D canvas, which converts whatever the engine itself accepts.
114
+ */
115
+ function tokenColor(name: string): Vec3 {
116
+ if (!probe || !root.value) return [0, 0, 0]
117
+ probe.style.color = `var(--color-${name})`
118
+ const css = getComputedStyle(probe).color
119
+ const rgb = parseColor(css)
120
+ if (rgb) return [rgb.r / 255, rgb.g / 255, rgb.b / 255]
121
+ paint ??= document.createElement("canvas").getContext("2d", { willReadFrequently: true })
122
+ if (!paint) return [0, 0, 0]
123
+ paint.clearRect(0, 0, 1, 1)
124
+ paint.fillStyle = "#000"
125
+ paint.fillStyle = css
126
+ paint.fillRect(0, 0, 1, 1)
127
+ const [r, g, b] = paint.getImageData(0, 0, 1, 1).data
128
+ return [r / 255, g / 255, b / 255]
129
+ }
130
+
131
+ function readPalette(): Palette {
132
+ const out = {} as Palette
133
+ for (const name of TOKENS) out[name] = tokenColor(name)
134
+ return out
135
+ }
136
+
137
+ let target: Palette | null = null
138
+ let current: Palette | null = null
139
+
140
+ function refreshPalette() {
141
+ target = readPalette()
142
+ // Mid-animation the loop blends toward it; otherwise there is no next frame to blend in, so it lands now.
143
+ if (!current || !running) {
144
+ current = { ...target }
145
+ drawFrame()
146
+ }
147
+ }
148
+
149
+ // ── GL ──────────────────────────────────────────────────────────────────────
150
+
151
+ let gl: WebGLRenderingContext | null = null
152
+ let program: WebGLProgram | null = null
153
+ let buffer: WebGLBuffer | null = null
154
+ let uniforms: Record<string, WebGLUniformLocation | null> = {}
155
+
156
+ function compile(type: number, source: string): WebGLShader | null {
157
+ if (!gl) return null
158
+ const shader = gl.createShader(type)
159
+ if (!shader) return null
160
+ gl.shaderSource(shader, source)
161
+ gl.compileShader(shader)
162
+ if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
163
+ gl.deleteShader(shader)
164
+ return null
165
+ }
166
+ return shader
167
+ }
168
+
169
+ function useProgram(preset: ShaderPreset): boolean {
170
+ if (!gl) return false
171
+ if (program) gl.deleteProgram(program)
172
+ program = null
173
+ const vs = compile(gl.VERTEX_SHADER, VERTEX_SHADER)
174
+ const fs = compile(gl.FRAGMENT_SHADER, FRAGMENT_HEADER + PRESETS[preset].fragment)
175
+ if (!vs || !fs) return false
176
+ const next = gl.createProgram()
177
+ if (!next) return false
178
+ gl.attachShader(next, vs)
179
+ gl.attachShader(next, fs)
180
+ gl.linkProgram(next)
181
+ // Linked programs keep what they need; the shader objects can go.
182
+ gl.deleteShader(vs)
183
+ gl.deleteShader(fs)
184
+ if (!gl.getProgramParameter(next, gl.LINK_STATUS)) {
185
+ gl.deleteProgram(next)
186
+ return false
187
+ }
188
+ program = next
189
+ gl.useProgram(program)
190
+ const at = gl.getAttribLocation(program, "p")
191
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer)
192
+ gl.enableVertexAttribArray(at)
193
+ gl.vertexAttribPointer(at, 2, gl.FLOAT, false, 0, 0)
194
+ uniforms = {}
195
+ for (const name of ["u_res", "u_time", "u_px", "u_k", "u_bg", "u_brand", "u_accent", "u_action", "u_ink"]) {
196
+ uniforms[name] = gl.getUniformLocation(program, name)
197
+ }
198
+ sizeCanvas()
199
+ return true
200
+ }
201
+
202
+ let pixelRatio = 1
203
+
204
+ function sizeCanvas() {
205
+ const el = canvas.value
206
+ if (!el) return
207
+ const dpr = Math.min(weakEngine ? 1 : 2, window.devicePixelRatio || 1)
208
+ pixelRatio = dpr * PRESETS[props.preset].scale
209
+ const w = Math.max(1, Math.round(el.clientWidth * pixelRatio))
210
+ const h = Math.max(1, Math.round(el.clientHeight * pixelRatio))
211
+ if (el.width !== w || el.height !== h) {
212
+ el.width = w
213
+ el.height = h
214
+ }
215
+ gl?.viewport(0, 0, w, h)
216
+ }
217
+
218
+ let time = 0
219
+
220
+ function drawFrame() {
221
+ if (!gl || !program || !current || !canvas.value) return
222
+ const c = current
223
+ gl.uniform2f(uniforms.u_res, canvas.value.width, canvas.value.height)
224
+ gl.uniform1f(uniforms.u_time, time)
225
+ gl.uniform1f(uniforms.u_px, pixelRatio)
226
+ gl.uniform1f(uniforms.u_k, clamp01(props.intensity))
227
+ gl.uniform3fv(uniforms.u_bg, c.surface)
228
+ gl.uniform3fv(uniforms.u_brand, c.brand)
229
+ gl.uniform3fv(uniforms.u_accent, c.accent)
230
+ gl.uniform3fv(uniforms.u_action, c.action)
231
+ gl.uniform3fv(uniforms.u_ink, c.ink)
232
+ gl.drawArrays(gl.TRIANGLES, 0, 3)
233
+ }
234
+
235
+ function giveUp(reason: "unavailable" | "slow" | "lost" | "compile") {
236
+ failed.value = true
237
+ emit("fallback", reason)
238
+ }
239
+
240
+ function onContextLost() {
241
+ release()
242
+ giveUp("lost")
243
+ }
244
+
245
+ function start() {
246
+ const el = canvas.value
247
+ if (!el || gl) return
248
+ /*
249
+ * `failIfMajorPerformanceCaveat` refuses a software rasteriser outright:
250
+ * a CPU-drawn full-screen shader is exactly the load a backdrop must not
251
+ * put on a machine that has no GPU to spare.
252
+ */
253
+ const context = el.getContext("webgl", {
254
+ alpha: false,
255
+ antialias: false,
256
+ depth: false,
257
+ stencil: false,
258
+ preserveDrawingBuffer: false,
259
+ powerPreference: "low-power",
260
+ failIfMajorPerformanceCaveat: true,
261
+ })
262
+ if (!context) return giveUp("unavailable")
263
+ gl = context
264
+ el.addEventListener("webglcontextlost", onContextLost)
265
+ buffer = gl.createBuffer()
266
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer)
267
+ // One triangle that covers the whole viewport: cheaper than a quad, no seam.
268
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 3, -1, -1, 3]), gl.STATIC_DRAW)
269
+ if (!useProgram(props.preset)) {
270
+ release()
271
+ return giveUp("compile")
272
+ }
273
+ intervals = []
274
+ refreshPalette()
275
+ drawFrame()
276
+ shown.value = true
277
+ sync()
278
+ }
279
+
280
+ /** Free the context and everything on it; the next start gets a fresh canvas. */
281
+ function release() {
282
+ stop()
283
+ shown.value = false
284
+ const el = canvas.value
285
+ el?.removeEventListener("webglcontextlost", onContextLost)
286
+ if (gl) {
287
+ if (program) gl.deleteProgram(program)
288
+ if (buffer) gl.deleteBuffer(buffer)
289
+ gl.getExtension("WEBGL_lose_context")?.loseContext()
290
+ canvasKey.value++
291
+ }
292
+ gl = null
293
+ program = null
294
+ buffer = null
295
+ current = null
296
+ }
297
+
298
+ // ── Loop ────────────────────────────────────────────────────────────────────
299
+
300
+ let frame = 0
301
+ let running = false
302
+ let last = 0
303
+ let intervals: number[] = []
304
+
305
+ function tick(now: number) {
306
+ frame = requestAnimationFrame(tick)
307
+ const cap = weakEngine ? Math.min(props.fps, 24) : props.fps
308
+ if (!frameDue(now, last, cap)) return
309
+ const dt = last ? now - last : 0
310
+ last = now
311
+ // A long gap (a stalled tab) is skipped over, not caught up on.
312
+ time += (Math.min(dt, 100) / 1000) * props.speed
313
+ if (current && target) {
314
+ const k = Math.min(1, dt / 160)
315
+ for (const name of TOKENS) current[name] = approach(current[name], target[name], k)
316
+ }
317
+ drawFrame()
318
+ // The first second of drawing decides whether the engine can carry it.
319
+ if (dt > 0 && dt < 500 && intervals.length < 30) {
320
+ intervals.push(dt)
321
+ if (tooSlow(intervals, cap)) {
322
+ release()
323
+ giveUp("slow")
324
+ }
325
+ }
326
+ }
327
+
328
+ function stop() {
329
+ running = false
330
+ if (frame) cancelAnimationFrame(frame)
331
+ frame = 0
332
+ }
333
+
334
+ function sync() {
335
+ if (gl && animating.value) {
336
+ if (running) return
337
+ running = true
338
+ last = 0
339
+ frame = requestAnimationFrame(tick)
340
+ } else stop()
341
+ }
342
+
343
+ // ── Observers ───────────────────────────────────────────────────────────────
344
+
345
+ let themeObserver: MutationObserver | undefined
346
+ let schemeQuery: MediaQueryList | undefined
347
+
348
+ useResizeObserver(root, () => {
349
+ sizeCanvas()
350
+ drawFrame()
351
+ })
352
+
353
+ onMounted(() => {
354
+ probe = document.createElement("span")
355
+ probe.style.display = "none"
356
+ root.value?.appendChild(probe)
357
+
358
+ // Themes are applied as variables and attributes on <html>; a scheme switch can also come from the OS.
359
+ themeObserver = new MutationObserver(() => {
360
+ if (gl) refreshPalette()
361
+ })
362
+ themeObserver.observe(document.documentElement, { attributes: true, attributeFilter: ["style", "class", "data-theme", "data-theme-mode"] })
363
+ schemeQuery = window.matchMedia?.("(prefers-color-scheme: dark)")
364
+ schemeQuery?.addEventListener("change", refreshPalette)
365
+
366
+ if (wantGl.value) start()
367
+ })
368
+
369
+ watch(wantGl, (on) => {
370
+ if (on) requestAnimationFrame(start)
371
+ else release()
372
+ })
373
+ watch(animating, sync)
374
+
375
+ /*
376
+ * A new look fades the canvas out to the still of the new look (which has
377
+ * crossfaded in underneath), swaps the shader there, and fades back in.
378
+ */
379
+ let swapTimer = 0
380
+ watch(
381
+ () => props.preset,
382
+ (preset) => {
383
+ if (!gl) return
384
+ shown.value = false
385
+ window.clearTimeout(swapTimer)
386
+ swapTimer = window.setTimeout(() => {
387
+ if (!gl) return
388
+ if (!useProgram(preset)) {
389
+ release()
390
+ return giveUp("compile")
391
+ }
392
+ drawFrame()
393
+ shown.value = true
394
+ }, durationToken("duration-medium"))
395
+ },
396
+ )
397
+ watch(
398
+ () => props.intensity,
399
+ () => {
400
+ if (!running) drawFrame()
401
+ },
402
+ )
403
+
404
+ onBeforeUnmount(() => {
405
+ window.clearTimeout(swapTimer)
406
+ release()
407
+ themeObserver?.disconnect()
408
+ schemeQuery?.removeEventListener("change", refreshPalette)
409
+ probe?.remove()
410
+ })
411
+
412
+ const { class: rootClass, attrs: rest } = useMergedAttrs("pointer-events-none absolute inset-0 overflow-hidden bg-surface")
413
+ </script>
414
+
415
+ <template>
416
+ <div ref="root" :class="rootClass" v-bind="rest" aria-hidden="true" :data-mode="shown ? 'gl' : 'css'">
417
+ <Transition
418
+ enter-active-class="transition-opacity duration-medium ease-out motion-reduce:transition-none"
419
+ leave-active-class="transition-opacity duration-medium ease-out motion-reduce:transition-none"
420
+ enter-from-class="opacity-0"
421
+ leave-to-class="opacity-0"
422
+ >
423
+ <div :key="preset" class="absolute inset-0">
424
+ <div class="absolute inset-0 transition-opacity duration-medium" :style="fallbackStyle" />
425
+ </div>
426
+ </Transition>
427
+ <canvas
428
+ :key="canvasKey"
429
+ ref="canvas"
430
+ class="absolute inset-0 size-full transition-opacity duration-medium ease-out"
431
+ :class="shown ? 'opacity-100' : 'opacity-0'"
432
+ />
433
+ </div>
434
+ </template>