@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.
- package/README.md +49 -0
- package/dist/assets/LoaderMark-DxBV2iDJ.css +43 -0
- package/dist/assets/LpActivityLine-B3EwNQEB.css +33 -0
- package/dist/assets/{LpCommandPalette-DxyjhYn_.css → LpCommandPalette-u-zOxKWa.css} +21 -31
- package/dist/assets/LpDock-Cbh0wQUv.css +17 -0
- package/dist/assets/{LpDropzone-Qb8k7cg4.css → LpDropzone-Bb1vBTeU.css} +12 -17
- package/dist/assets/{LpImageEditor-CElPDzpF.css → LpImageEditor-XM5bAziW.css} +6 -6
- package/dist/assets/LpLogViewer-BDNW6P52.css +38 -0
- package/dist/assets/{LpPalettePreview-CJmAKgYW.css → LpPalettePreview-B9VKDrvA.css} +2 -7
- package/dist/assets/LpRepeater-C1Cw27hj.css +21 -0
- package/dist/assets/{LpRollingText-BGnE6q9j.css → LpRollingText-dyOXedGO.css} +7 -0
- package/dist/assets/LpShinyText-D69cBYDR.css +61 -0
- package/dist/assets/LpStatus-430OGTZY.css +17 -0
- package/dist/assets/LpStepMark-Drvx33Vg.css +10 -0
- package/dist/assets/{LpTable-BPERfJIk.css → LpTable-DHxEQ_-3.css} +19 -19
- package/dist/assets/LpTabs-BJ-nrJuI.css +18 -0
- package/dist/assets/LpTextReveal-DjI1MsDS.css +35 -0
- package/dist/assets/LpTypewriter-CXAm9Nca.css +27 -0
- package/dist/chunks/AttentionDot-DCBf4aWg.js +25 -0
- package/dist/chunks/{ContextMenuItems-B7XFHksm.js → ContextMenuItems-6kxEivBI.js} +11 -5
- package/dist/chunks/{DropzoneLinkField-CjkrpDqO.js → DropzoneLinkField-Bw8Flkhk.js} +2 -2
- package/dist/chunks/FieldWrapper-BiennROB.js +43 -0
- package/dist/chunks/{LayoutCanvas-DF9CovaK.js → LayoutCanvas-BsJIzhdd.js} +1 -1
- package/dist/chunks/{LayoutNode-D9bIFzk0.js → LayoutNode-DJVhkSGk.js} +6 -8
- package/dist/chunks/LegendSwatch-BhRjrtzv.js +18 -0
- package/dist/chunks/LoaderMark-C1dubiKn.js +85 -0
- package/dist/chunks/{LpActionBar-MPKMu3pz.js → LpActionBar-CzOFar5t.js} +14 -20
- package/dist/chunks/LpActivityLine-CJvzrNpj.js +95 -0
- package/dist/chunks/{LpAddressInput-DG0BTqdH.js → LpAddressInput-Chv_Xf8q.js} +7 -7
- package/dist/chunks/LpAlert-C5igj802.js +119 -0
- package/dist/chunks/{LpAppShell-DPh1756q.js → LpAppShell-BiWByLmt.js} +15 -16
- package/dist/chunks/{LpAutocomplete-Dgn6hw3p.js → LpAutocomplete-D92niDHE.js} +15 -32
- package/dist/chunks/{LpAvatar-Bs0Fb1lC.js → LpAvatar-CLPl-qOF.js} +18 -6
- package/dist/chunks/LpBadge-BBq1Er9T.js +126 -0
- package/dist/chunks/LpBreadcrumbs-JKEi_yFF.js +144 -0
- package/dist/chunks/{LpButton-DNR-YAq5.js → LpButton-CVxBfGjd.js} +12 -4
- package/dist/chunks/{LpCalendar-BLya39Fh.js → LpCalendar-pVL91-Pl.js} +1 -1
- package/dist/chunks/{LpCard-Bf71NXZq.js → LpCard-CqKLnEhl.js} +18 -8
- package/dist/chunks/{LpCheckbox-Da5oZPHo.js → LpCheckbox-DHc2bHDe.js} +9 -6
- package/dist/chunks/{LpCodeBlock-lLbmslfs.js → LpCodeBlock-BGsQhxw8.js} +24 -32
- package/dist/chunks/LpCodeDisplay-CbJMs-IK.js +189 -0
- package/dist/chunks/LpCollapse-CWS9M_lm.js +115 -0
- package/dist/chunks/{LpColorPicker-DtEfBAcK.js → LpColorPicker-B7HSIFmn.js} +11 -6
- package/dist/chunks/{LpConfirmDialog-D7s4jakB.js → LpConfirmDialog-CfGCux8m.js} +3 -3
- package/dist/chunks/{LpConfirmHost-DrYI5y1K.js → LpConfirmHost-exB7JmcO.js} +1 -1
- package/dist/chunks/{LpContextMenu-CRnjoqSt.js → LpContextMenu-Cj96ENDC.js} +16 -7
- package/dist/chunks/LpCopyButton-DzHjnFs0.js +133 -0
- package/dist/chunks/LpCountdown-BQnmB4gq.js +231 -0
- package/dist/chunks/LpDataList-CHNYQw7h.js +121 -0
- package/dist/chunks/LpDatePicker-ac1_6o5P.js +169 -0
- package/dist/chunks/LpDateRangePicker-B15gYrZJ.js +127 -0
- package/dist/chunks/{LpDisclosure-6AplYBub.js → LpDisclosure-DOarzlAG.js} +22 -11
- package/dist/chunks/{LpDrawer-Q4SOxM4s.js → LpDrawer-DGNKRsGq.js} +9 -4
- package/dist/chunks/{LpDropdownMenu-DWTt0ooM.js → LpDropdownMenu-R4aYVtVV.js} +14 -6
- package/dist/chunks/LpEditable-Ws3DNQHn.js +238 -0
- package/dist/chunks/{LpEmptyState-om1UnFjV.js → LpEmptyState-KTKipws2.js} +1 -1
- package/dist/chunks/{LpFieldNotice-CHuDeLjc.js → LpFieldNotice-CurbNuXI.js} +1 -1
- package/dist/chunks/{LpFileTree-CW24YsVX.js → LpFileTree-DDNg34tJ.js} +5 -3
- package/dist/chunks/{LpFileTreeNode-BXhTHaKW.js → LpFileTreeNode-DmPuYNZ_.js} +42 -55
- package/dist/chunks/{LpFormField-DPb47HEm.js → LpFormField-BWwgm1E4.js} +23 -9
- package/dist/chunks/LpFrame-BVQCQLDI.js +155 -0
- package/dist/chunks/LpGauge-C14Z9503.js +204 -0
- package/dist/chunks/LpGlowBorder-B8V-QzIl.js +40 -0
- package/dist/chunks/{LpHintExample-C1eKYdeL.js → LpHintExample-9Py0wc-L.js} +11 -34
- package/dist/chunks/{LpHintLayer-7UOdWQG3.js → LpHintLayer-HvwUA5Ec.js} +27 -14
- package/dist/chunks/{LpHints-BUtBp9-w.js → LpHints-DxbPKOzQ.js} +3 -3
- package/dist/chunks/LpHoverCard-spGxyw7T.js +130 -0
- package/dist/chunks/{LpIcon-6tSrZ3Zy.js → LpIcon-HJP5xMz4.js} +1 -1
- package/dist/chunks/LpIdenticon-BzdC_qz9.js +63 -0
- package/dist/chunks/{LpInfraNode-Ds_8SZgN.js → LpInfraNode-D64hywJI.js} +39 -25
- package/dist/chunks/{LpInput-CUyr6PIE.js → LpInput-CDuwODJG.js} +44 -18
- package/dist/chunks/{LpLightbox-B9J8rzsj.js → LpLightbox-XJ0LpTcZ.js} +69 -69
- package/dist/chunks/LpLoader-DjJEX8hL.js +92 -0
- package/dist/chunks/{LpLogViewer-4QFc-sVN.js → LpLogViewer-DKK4ySZl.js} +225 -129
- package/dist/chunks/LpMagnetic-CtXKLa2Y.js +62 -0
- package/dist/chunks/{LpMapPicker-BTbkFeSG.js → LpMapPicker-BtIl7NOM.js} +34 -31
- package/dist/chunks/LpMasonry--k0571qG.js +185 -0
- package/dist/chunks/{LpMediaGallery-CuPcscx3.js → LpMediaGallery-rmI1DjKN.js} +3 -3
- package/dist/chunks/{LpModal-hk1noDcr.js → LpModal-eBMt2Fqn.js} +8 -3
- package/dist/chunks/{LpModalNav-DQd2keZm.js → LpModalNav-DiyFCHiZ.js} +4 -4
- package/dist/chunks/{LpNotificationBell-X84PJIxD.js → LpNotificationBell-D-WhE5m2.js} +32 -48
- package/dist/chunks/LpNumberField-B9k-h2HE.js +140 -0
- package/dist/chunks/{LpNumberFlow-z4WPZcZu.js → LpNumberFlow-Cfyh033Q.js} +8 -28
- package/dist/chunks/{LpOtpInput-PbeNJ5In.js → LpOtpInput-CeBPsM7D.js} +2 -1
- package/dist/chunks/{LpPagination-Bx-VG4Ag.js → LpPagination-VNCX6pFC.js} +37 -6
- package/dist/chunks/{LpPalettePreview-CFav_7co.js → LpPalettePreview-BNB8T_MY.js} +1 -1
- package/dist/chunks/{LpPasswordInput-CbnXitAS.js → LpPasswordInput-GL2KOFK8.js} +26 -22
- package/dist/chunks/{LpPhoneInput-DP69HONS.js → LpPhoneInput-C60tx1tC.js} +12 -7
- package/dist/chunks/{LpPie-yLF9-aDR.js → LpPie-BgXZ3xmm.js} +159 -48
- package/dist/chunks/LpPipeline-B31h41Mu.js +329 -0
- package/dist/chunks/{LpPopover-DVnkHaOu.js → LpPopover-DmZ3wUtP.js} +13 -7
- package/dist/chunks/{LpProgress-CA86wxXu.js → LpProgress-CE-m5OpD.js} +23 -63
- package/dist/chunks/LpQuota-DaL8TgNe.js +162 -0
- package/dist/chunks/{LpRadioGroup-8S5hf8lE.js → LpRadioGroup-CGBr5nIp.js} +1 -1
- package/dist/chunks/{LpRangeCalendar-ByQi-WUz.js → LpRangeCalendar-c5qj7YcC.js} +1 -1
- package/dist/chunks/{LpRangeSlider-C1yF9-nP.js → LpRangeSlider-Dv6lNvHY.js} +6 -2
- package/dist/chunks/LpRelativeTime-yin9uQP7.js +73 -0
- package/dist/chunks/LpRepeater-D0S7jjwr.js +180 -0
- package/dist/chunks/LpRevealOnScroll-DcQjexLy.js +76 -0
- package/dist/chunks/{LpRollingText-DB7upf-5.js → LpRollingText-DiL717LK.js} +4 -3
- package/dist/chunks/LpScramble-TDO5Kdou.js +85 -0
- package/dist/chunks/LpSecretField-CfWyHv9m.js +316 -0
- package/dist/chunks/{LpSection-BmRXe6ZP.js → LpSection-BW4xJ-Li.js} +1 -1
- package/dist/chunks/{LpSegmented-CW3bFHM4.js → LpSegmented-BO99Sr4m.js} +11 -14
- package/dist/chunks/{LpSelect-BCyDYoih.js → LpSelect-C_8cJtj6.js} +91 -111
- package/dist/chunks/LpShaderBackdrop-Bote0iuy.js +332 -0
- package/dist/chunks/LpShinyText-DX2ajtWq.js +48 -0
- package/dist/chunks/{LpSidebar-DfIiS-lB.js → LpSidebar-CZRXtvem.js} +5 -3
- package/dist/chunks/{LpSidebarNav-C5FDNI0t.js → LpSidebarNav-DBg1U1oW.js} +3 -3
- package/dist/chunks/{LpSlider-Cuzmrd7p.js → LpSlider-DuoRpOrH.js} +6 -2
- package/dist/chunks/{LpSparkline-DXT4KrSi.js → LpSparkline-CExIRDb3.js} +32 -27
- package/dist/chunks/LpSpotlight-4F3NeUMY.js +41 -0
- package/dist/chunks/{LpStat-iBMF5QNk.js → LpStat-DFKlPJgy.js} +38 -35
- package/dist/chunks/LpStatus-BsGLrpor.js +86 -0
- package/dist/chunks/LpStepMark-TrzOioa9.js +101 -0
- package/dist/chunks/LpStepper-BbnS5jUr.js +76 -0
- package/dist/chunks/{LpSwap-D82jiecV.js → LpSwap-DzE6M3Mg.js} +1 -1
- package/dist/chunks/LpSwitch-DrzKrZZV.js +112 -0
- package/dist/chunks/{LpTableFilter-CuIbgdW0.js → LpTableFilter-DyvHGbOk.js} +3 -2
- package/dist/chunks/{LpTableOfContents-C_4VBktT.js → LpTableOfContents-rYvo8z5T.js} +34 -21
- package/dist/chunks/{LpTagsInput-DiXrpYeE.js → LpTagsInput-DZg80W-B.js} +68 -71
- package/dist/chunks/LpTextReveal-CtAnOUkp.js +140 -0
- package/dist/chunks/{LpTextarea-xoQd5Lnp.js → LpTextarea-DiWjeVoJ.js} +12 -11
- package/dist/chunks/{LpThemeProvider-CQ2jC9TA.js → LpThemeProvider-DcbfOxsU.js} +1 -1
- package/dist/chunks/LpThemeStudio-DxVZMtzN.js +416 -0
- package/dist/chunks/LpThemeStudioSection-BwhqYDLf.js +20 -0
- package/dist/chunks/LpThemeSwitcher-CadVBTBn.js +278 -0
- package/dist/chunks/{LpTimeField-MFgAsNc5.js → LpTimeField-BFQVf_PW.js} +13 -5
- package/dist/chunks/{LpToaster-C4zE9zB7.js → LpToaster-Wv9ksj4q.js} +49 -82
- package/dist/chunks/{LpTooltip-suFCM34F.js → LpTooltip-Cz8SQwRt.js} +8 -3
- package/dist/chunks/{LpTopologyCanvas-6ozNrQKh.js → LpTopologyCanvas-C17A1XCb.js} +1 -1
- package/dist/chunks/{LpTour-BUp3Jt2e.js → LpTour-CY2bFXge.js} +24 -18
- package/dist/chunks/LpTruncate-D_5Pfv5B.js +112 -0
- package/dist/chunks/LpTypewriter-BCL_a6wE.js +159 -0
- package/dist/chunks/{LpUptimeBar-B6kHw4Cj.js → LpUptimeBar-Tew1Ykx4.js} +10 -9
- package/dist/chunks/{LpVideoBackdrop-qWRYBOTQ.js → LpVideoBackdrop-DS1wGv-X.js} +7 -8
- package/dist/chunks/{MenuTitle-obgek0B7.js → MenuTitle-BjQZX8tQ.js} +1 -1
- package/dist/chunks/OptionContent-CmYUUeWj.js +40 -0
- package/dist/chunks/PickerField-DoHv0WMH.js +125 -0
- package/dist/chunks/RevealToggle-C-KzaQGJ.js +65 -0
- package/dist/chunks/StepConnector-37OgEOXA.js +41 -0
- package/dist/chunks/TourCard-BJ8i7dk0.js +123 -0
- package/dist/chunks/backdrop-Dkf2vM81.js +59 -0
- package/dist/chunks/{icons-DVhZ_plB.js → icons-4IywzkHk.js} +1 -1
- package/dist/chunks/{useTheme-2qHG8NEU.js → useTheme-BOV_-AiY.js} +9 -65
- package/dist/component-names.d.ts +1 -1
- package/dist/components/AttentionDot.vue.d.ts +9 -0
- package/dist/components/AttentionDot.vue.js +4 -0
- package/dist/components/ContextMenuItems.vue.js +1 -1
- package/dist/components/DropzoneLinkField.vue.js +1 -1
- package/dist/components/FieldWrapper.vue.d.ts +25 -0
- package/dist/components/FieldWrapper.vue.js +4 -0
- package/dist/components/LayoutCanvas.vue.js +1 -1
- package/dist/components/LayoutNode.vue.d.ts +4 -4
- package/dist/components/LayoutNode.vue.js +1 -1
- package/dist/components/LegendSwatch.vue.d.ts +6 -0
- package/dist/components/LegendSwatch.vue.js +4 -0
- package/dist/components/LoaderMark.vue.d.ts +12 -0
- package/dist/components/LoaderMark.vue.js +4 -0
- package/dist/components/LpActionBar.vue.js +1 -1
- package/dist/components/LpActivityLine.vue.d.ts +58 -0
- package/dist/components/LpActivityLine.vue.js +4 -0
- package/dist/components/LpAddressInput.vue.js +1 -1
- package/dist/components/LpAlert.vue.d.ts +2 -2
- package/dist/components/LpAlert.vue.js +1 -1
- package/dist/components/LpAppShell.vue.d.ts +8 -7
- package/dist/components/LpAppShell.vue.js +1 -1
- package/dist/components/LpAutocomplete.vue.js +1 -1
- package/dist/components/LpAvatar.vue.d.ts +16 -0
- package/dist/components/LpAvatar.vue.js +1 -1
- package/dist/components/LpBadge.vue.d.ts +19 -5
- package/dist/components/LpBadge.vue.js +1 -1
- package/dist/components/LpBreadcrumbs.vue.js +1 -1
- package/dist/components/LpButton.vue.d.ts +2 -2
- package/dist/components/LpButton.vue.js +1 -1
- package/dist/components/LpCalendar.vue.js +1 -1
- package/dist/components/LpCard.vue.d.ts +24 -0
- package/dist/components/LpCard.vue.js +1 -1
- package/dist/components/LpChart.vue.js +131 -160
- package/dist/components/LpCheckbox.vue.d.ts +2 -2
- package/dist/components/LpCheckbox.vue.js +1 -1
- package/dist/components/LpCodeBlock.vue.js +1 -1
- package/dist/components/LpCodeDisplay.vue.d.ts +89 -0
- package/dist/components/LpCodeDisplay.vue.js +4 -0
- package/dist/components/LpCollapse.vue.d.ts +58 -0
- package/dist/components/LpCollapse.vue.js +4 -0
- package/dist/components/LpColorPicker.vue.d.ts +2 -2
- package/dist/components/LpColorPicker.vue.js +1 -1
- package/dist/components/LpCommandPalette.vue.js +34 -23
- package/dist/components/LpConfirmDialog.vue.js +1 -1
- package/dist/components/LpConfirmHost.vue.js +1 -1
- package/dist/components/LpContextMenu.vue.js +1 -1
- package/dist/components/LpCopyButton.vue.d.ts +82 -0
- package/dist/components/LpCopyButton.vue.js +4 -0
- package/dist/components/LpCountdown.vue.d.ts +100 -0
- package/dist/components/LpCountdown.vue.js +4 -0
- package/dist/components/LpDataList.vue.d.ts +66 -0
- package/dist/components/LpDataList.vue.js +4 -0
- package/dist/components/LpDatePicker.vue.d.ts +3 -1
- package/dist/components/LpDatePicker.vue.js +1 -1
- package/dist/components/LpDateRangePicker.vue.d.ts +3 -1
- package/dist/components/LpDateRangePicker.vue.js +1 -1
- package/dist/components/LpDisclosure.vue.js +1 -1
- package/dist/components/LpDock.vue.d.ts +74 -0
- package/dist/components/LpDock.vue.js +204 -0
- package/dist/components/LpDrawer.vue.js +1 -1
- package/dist/components/LpDropdownMenu.vue.js +1 -1
- package/dist/components/LpDropzone.vue.d.ts +8 -1
- package/dist/components/LpDropzone.vue.js +36 -15
- package/dist/components/LpEditable.vue.d.ts +85 -0
- package/dist/components/LpEditable.vue.js +4 -0
- package/dist/components/LpEmptyState.vue.js +1 -1
- package/dist/components/LpFieldNotice.vue.js +1 -1
- package/dist/components/LpFileTree.vue.js +1 -1
- package/dist/components/LpFileTreeNode.vue.js +1 -1
- package/dist/components/LpFormField.vue.js +1 -1
- package/dist/components/LpFrame.vue.d.ts +22 -0
- package/dist/components/LpFrame.vue.js +4 -0
- package/dist/components/LpGauge.vue.d.ts +116 -0
- package/dist/components/LpGauge.vue.js +4 -0
- package/dist/components/LpGlowBorder.vue.d.ts +47 -0
- package/dist/components/LpGlowBorder.vue.js +4 -0
- package/dist/components/LpHintExample.vue.d.ts +2 -2
- package/dist/components/LpHintExample.vue.js +1 -1
- package/dist/components/LpHintLayer.vue.js +1 -1
- package/dist/components/LpHints.vue.js +1 -1
- package/dist/components/LpHoverCard.vue.d.ts +60 -0
- package/dist/components/LpHoverCard.vue.js +4 -0
- package/dist/components/LpIcon.vue.js +1 -1
- package/dist/components/LpIdenticon.vue.d.ts +37 -0
- package/dist/components/LpIdenticon.vue.js +4 -0
- package/dist/components/LpImageEditor.vue.js +13 -19
- package/dist/components/LpInfraNode.vue.js +1 -1
- package/dist/components/LpInput.vue.d.ts +10 -0
- package/dist/components/LpInput.vue.js +1 -1
- package/dist/components/LpLightbox.vue.js +1 -1
- package/dist/components/LpLoader.vue.d.ts +106 -0
- package/dist/components/LpLoader.vue.js +4 -0
- package/dist/components/LpLogViewer.vue.js +1 -1
- package/dist/components/LpMagnetic.vue.d.ts +28 -0
- package/dist/components/LpMagnetic.vue.js +4 -0
- package/dist/components/LpMapPicker.vue.js +1 -1
- package/dist/components/LpMasonry.vue.d.ts +42 -0
- package/dist/components/LpMasonry.vue.js +4 -0
- package/dist/components/LpMediaGallery.vue.js +1 -1
- package/dist/components/LpModal.vue.js +1 -1
- package/dist/components/LpModalNav.vue.js +1 -1
- package/dist/components/LpNotificationBell.vue.d.ts +15 -6
- package/dist/components/LpNotificationBell.vue.js +1 -1
- package/dist/components/LpNumberField.vue.d.ts +57 -0
- package/dist/components/LpNumberField.vue.js +1 -1
- package/dist/components/LpNumberFlow.vue.js +1 -1
- package/dist/components/LpOtpInput.vue.d.ts +12 -4
- package/dist/components/LpOtpInput.vue.js +1 -1
- package/dist/components/LpPagination.vue.js +1 -1
- package/dist/components/LpPaletteFacts.vue.js +2 -2
- package/dist/components/LpPaletteHeader.vue.js +2 -2
- package/dist/components/LpPalettePreview.vue.js +1 -1
- package/dist/components/LpPaletteStats.vue.js +2 -2
- package/dist/components/LpPasswordInput.vue.d.ts +19 -2
- package/dist/components/LpPasswordInput.vue.js +1 -1
- package/dist/components/LpPhoneInput.vue.js +1 -1
- package/dist/components/LpPie.vue.d.ts +3 -1
- package/dist/components/LpPie.vue.js +1 -1
- package/dist/components/LpPipeline.vue.d.ts +91 -0
- package/dist/components/LpPipeline.vue.js +4 -0
- package/dist/components/LpPopover.vue.d.ts +2 -2
- package/dist/components/LpPopover.vue.js +1 -1
- package/dist/components/LpProgress.vue.d.ts +11 -4
- package/dist/components/LpProgress.vue.js +1 -1
- package/dist/components/LpQuota.vue.d.ts +68 -0
- package/dist/components/LpQuota.vue.js +4 -0
- package/dist/components/LpRadioGroup.vue.js +1 -1
- package/dist/components/LpRangeCalendar.vue.js +1 -1
- package/dist/components/LpRangeSlider.vue.js +1 -1
- package/dist/components/LpRelativeTime.vue.d.ts +41 -0
- package/dist/components/LpRelativeTime.vue.js +4 -0
- package/dist/components/LpRepeater.vue.d.ts +48 -0
- package/dist/components/LpRepeater.vue.js +4 -0
- package/dist/components/LpRevealOnScroll.vue.d.ts +67 -0
- package/dist/components/LpRevealOnScroll.vue.js +4 -0
- package/dist/components/LpRollingText.vue.d.ts +3 -1
- package/dist/components/LpRollingText.vue.js +1 -1
- package/dist/components/LpScramble.vue.d.ts +55 -0
- package/dist/components/LpScramble.vue.js +4 -0
- package/dist/components/LpScrollArea.vue.d.ts +1 -1
- package/dist/components/LpSecretField.vue.d.ts +108 -0
- package/dist/components/LpSecretField.vue.js +4 -0
- package/dist/components/LpSection.vue.js +1 -1
- package/dist/components/LpSegmented.vue.js +1 -1
- package/dist/components/LpSelect.vue.d.ts +2 -0
- package/dist/components/LpSelect.vue.js +1 -1
- package/dist/components/LpShaderBackdrop.vue.d.ts +39 -0
- package/dist/components/LpShaderBackdrop.vue.js +4 -0
- package/dist/components/LpShinyText.vue.d.ts +39 -0
- package/dist/components/LpShinyText.vue.js +4 -0
- package/dist/components/LpShortcutsDialog.vue.js +1 -1
- package/dist/components/LpSidebar.vue.js +1 -1
- package/dist/components/LpSidebarNav.vue.js +1 -1
- package/dist/components/LpSlider.vue.js +1 -1
- package/dist/components/LpSparkline.vue.d.ts +4 -3
- package/dist/components/LpSparkline.vue.js +1 -1
- package/dist/components/LpSpotlight.vue.d.ts +37 -0
- package/dist/components/LpSpotlight.vue.js +4 -0
- package/dist/components/LpStat.vue.js +1 -1
- package/dist/components/LpStatus.vue.d.ts +65 -0
- package/dist/components/LpStatus.vue.js +4 -0
- package/dist/components/LpStepMark.vue.d.ts +31 -0
- package/dist/components/LpStepMark.vue.js +4 -0
- package/dist/components/LpStepper.vue.js +1 -1
- package/dist/components/LpSwap.vue.js +1 -1
- package/dist/components/LpSwitch.vue.d.ts +2 -2
- package/dist/components/LpSwitch.vue.js +1 -1
- package/dist/components/LpTable.vue.js +104 -120
- package/dist/components/LpTableFilter.vue.js +1 -1
- package/dist/components/LpTableOfContents.vue.d.ts +6 -1
- package/dist/components/LpTableOfContents.vue.js +1 -1
- package/dist/components/LpTabs.vue.d.ts +5 -5
- package/dist/components/LpTabs.vue.js +25 -33
- package/dist/components/LpTagsInput.vue.js +1 -1
- package/dist/components/LpTextReveal.vue.d.ts +58 -0
- package/dist/components/LpTextReveal.vue.js +4 -0
- package/dist/components/LpTextarea.vue.js +1 -1
- package/dist/components/LpThemeProvider.vue.js +1 -1
- package/dist/components/LpThemeStudio.vue.d.ts +54 -0
- package/dist/components/LpThemeStudio.vue.js +4 -0
- package/dist/components/LpThemeStudioSection.vue.d.ts +16 -0
- package/dist/components/LpThemeStudioSection.vue.js +4 -0
- package/dist/components/LpThemeSwitcher.vue.d.ts +32 -1
- package/dist/components/LpThemeSwitcher.vue.js +1 -1
- package/dist/components/LpTimeField.vue.d.ts +2 -0
- package/dist/components/LpTimeField.vue.js +1 -1
- package/dist/components/LpToaster.vue.js +1 -1
- package/dist/components/LpTooltip.vue.d.ts +2 -2
- package/dist/components/LpTooltip.vue.js +1 -1
- package/dist/components/LpTopologyCanvas.vue.js +1 -1
- package/dist/components/LpTour.vue.js +1 -1
- package/dist/components/LpTruncate.vue.d.ts +34 -0
- package/dist/components/LpTruncate.vue.js +4 -0
- package/dist/components/LpTypewriter.vue.d.ts +61 -0
- package/dist/components/LpTypewriter.vue.js +4 -0
- package/dist/components/LpUptimeBar.vue.js +1 -1
- package/dist/components/LpVideoBackdrop.vue.js +1 -1
- package/dist/components/MenuTitle.vue.js +1 -1
- package/dist/components/OptionContent.vue.d.ts +7 -0
- package/dist/components/OptionContent.vue.js +4 -0
- package/dist/components/PickerField.vue.d.ts +45 -0
- package/dist/components/PickerField.vue.js +4 -0
- package/dist/components/RevealToggle.vue.d.ts +21 -0
- package/dist/components/RevealToggle.vue.js +4 -0
- package/dist/components/StepConnector.vue.d.ts +19 -0
- package/dist/components/StepConnector.vue.js +4 -0
- package/dist/components/TourCard.vue.js +1 -1
- package/dist/components/badge.d.ts +1 -0
- package/dist/components/badge.js +4 -0
- package/dist/components/chart.d.ts +5 -1
- package/dist/components/chart.js +2 -21
- package/dist/components/dateRange.d.ts +11 -0
- package/dist/components/dateRange.js +12 -0
- package/dist/components/dock.d.ts +19 -0
- package/dist/components/dock.js +16 -0
- package/dist/components/dropdown.d.ts +10 -1
- package/dist/components/dropdown.js +7 -2
- package/dist/components/fieldText.d.ts +38 -0
- package/dist/components/fieldText.js +53 -0
- package/dist/components/fileTree.d.ts +7 -3
- package/dist/components/fileTree.js +12 -18
- package/dist/components/format.d.ts +41 -0
- package/dist/components/format.js +67 -0
- package/dist/components/identicon.d.ts +38 -0
- package/dist/components/identicon.js +85 -0
- package/dist/components/masonry.d.ts +32 -0
- package/dist/components/masonry.js +40 -0
- package/dist/components/menuWhen.js +1 -1
- package/dist/components/meter.d.ts +64 -0
- package/dist/components/meter.js +53 -0
- package/dist/components/otp.d.ts +1 -1
- package/dist/components/otp.js +7 -2
- package/dist/components/pipeline.d.ts +55 -0
- package/dist/components/pipeline.js +51 -0
- package/dist/components/quota.d.ts +57 -0
- package/dist/components/quota.js +40 -0
- package/dist/components/relativeTime.d.ts +24 -0
- package/dist/components/relativeTime.js +56 -0
- package/dist/components/reveal.d.ts +18 -0
- package/dist/components/reveal.js +32 -0
- package/dist/components/scramble.d.ts +68 -0
- package/dist/components/scramble.js +58 -0
- package/dist/components/shaderBackdrop.d.ts +20 -0
- package/dist/components/shaderBackdrop.js +156 -0
- package/dist/components/slider.d.ts +5 -0
- package/dist/components/slider.js +24 -0
- package/dist/components/slotText.d.ts +2 -0
- package/dist/components/slotText.js +9 -0
- package/dist/components/status.d.ts +14 -0
- package/dist/components/status.js +22 -0
- package/dist/components/tableFacets.d.ts +8 -0
- package/dist/components/tableFacets.js +19 -0
- package/dist/components/textSplit.d.ts +17 -0
- package/dist/components/textSplit.js +24 -0
- package/dist/components/timeSpan.d.ts +78 -0
- package/dist/components/timeSpan.js +85 -0
- package/dist/components/tone.d.ts +43 -0
- package/dist/components/tone.js +82 -0
- package/dist/components/tour.js +3 -2
- package/dist/components/typewriter.d.ts +36 -0
- package/dist/components/typewriter.js +53 -0
- package/dist/components/videoBackdrop.js +5 -6
- package/dist/composables/easing.d.ts +22 -1
- package/dist/composables/easing.js +42 -1
- package/dist/composables/pseudoLocale.d.ts +15 -0
- package/dist/composables/pseudoLocale.js +96 -0
- package/dist/composables/scroll.js +5 -3
- package/dist/composables/useClipboard.d.ts +4 -1
- package/dist/composables/useClipboard.js +12 -2
- package/dist/composables/useField.d.ts +13 -0
- package/dist/composables/useField.js +26 -1
- package/dist/composables/useForm.js +32 -9
- package/dist/composables/useInView.d.ts +11 -0
- package/dist/composables/useInView.js +39 -0
- package/dist/composables/useLoadingGate.d.ts +8 -0
- package/dist/composables/useLoadingGate.js +38 -0
- package/dist/composables/useLpConfig.d.ts +10 -0
- package/dist/composables/useLpConfig.js +11 -1
- package/dist/composables/useMediaQuery.js +3 -1
- package/dist/composables/useNow.d.ts +16 -0
- package/dist/composables/useNow.js +39 -0
- package/dist/composables/usePersisted.js +14 -7
- package/dist/composables/usePillTransition.d.ts +5 -2
- package/dist/composables/usePillTransition.js +4 -3
- package/dist/composables/usePointerFrame.d.ts +18 -0
- package/dist/composables/usePointerFrame.js +31 -0
- package/dist/composables/useReducedMotion.d.ts +2 -0
- package/dist/composables/useReducedMotion.js +7 -0
- package/dist/composables/useRepeater.d.ts +17 -0
- package/dist/composables/useRepeater.js +31 -0
- package/dist/composables/useResizeObserver.d.ts +8 -0
- package/dist/composables/useResizeObserver.js +33 -0
- package/dist/composables/useRevealedValue.d.ts +31 -0
- package/dist/composables/useRevealedValue.js +26 -0
- package/dist/composables/useScramble.d.ts +42 -0
- package/dist/composables/useScramble.js +76 -0
- package/dist/composables/useShift.js +2 -10
- package/dist/composables/useSpotlight.d.ts +18 -0
- package/dist/composables/useSpotlight.js +53 -0
- package/dist/composables/useTilt.js +26 -18
- package/dist/composables/useTween.d.ts +43 -0
- package/dist/composables/useTween.js +69 -0
- package/dist/composables/useView.d.ts +18 -0
- package/dist/composables/useView.js +64 -0
- package/dist/icons-all.js +1 -1
- package/dist/index.d.ts +98 -1
- package/dist/index.js +263 -105
- package/dist/theme/define.d.ts +12 -0
- package/dist/theme/studio.d.ts +90 -0
- package/package.json +8 -2
- package/src/component-names.ts +33 -0
- package/src/components/AttentionDot.vue +27 -0
- package/src/components/ContextMenuItems.vue +5 -2
- package/src/components/FieldWrapper.vue +38 -0
- package/src/components/LayoutNode.vue +5 -9
- package/src/components/LegendSwatch.vue +15 -0
- package/src/components/LoaderMark.vue +90 -0
- package/src/components/LpActionBar.vue +12 -20
- package/src/components/LpActivityLine.vue +186 -0
- package/src/components/LpAlert.vue +54 -24
- package/src/components/LpAppShell.vue +7 -11
- package/src/components/LpAutocomplete.vue +16 -14
- package/src/components/LpAvatar.vue +17 -2
- package/src/components/LpBadge.vue +77 -13
- package/src/components/LpBreadcrumbs.vue +101 -35
- package/src/components/LpButton.vue +15 -3
- package/src/components/LpCard.vue +30 -7
- package/src/components/LpChart.vue +162 -171
- package/src/components/LpCheckbox.vue +10 -4
- package/src/components/LpCodeBlock.vue +11 -19
- package/src/components/LpCodeDisplay.vue +228 -0
- package/src/components/LpCollapse.vue +162 -0
- package/src/components/LpColorPicker.vue +10 -1
- package/src/components/LpCommandPalette.vue +38 -24
- package/src/components/LpContextMenu.vue +13 -3
- package/src/components/LpCopyButton.vue +185 -0
- package/src/components/LpCountdown.vue +308 -0
- package/src/components/LpDataList.vue +154 -0
- package/src/components/LpDatePicker.vue +55 -104
- package/src/components/LpDateRangePicker.vue +51 -95
- package/src/components/LpDisclosure.vue +58 -36
- package/src/components/LpDock.vue +274 -0
- package/src/components/LpDrawer.vue +10 -1
- package/src/components/LpDropdownMenu.vue +11 -2
- package/src/components/LpDropzone.vue +34 -13
- package/src/components/LpEditable.vue +295 -0
- package/src/components/LpFileTree.vue +5 -1
- package/src/components/LpFileTreeNode.vue +25 -50
- package/src/components/LpFormField.vue +22 -3
- package/src/components/LpFrame.vue +200 -0
- package/src/components/LpGauge.vue +287 -0
- package/src/components/LpGlowBorder.vue +60 -0
- package/src/components/LpHintExample.vue +9 -32
- package/src/components/LpHintLayer.vue +13 -3
- package/src/components/LpHoverCard.vue +175 -0
- package/src/components/LpIdenticon.vue +69 -0
- package/src/components/LpImageEditor.vue +15 -18
- package/src/components/LpInfraNode.vue +27 -16
- package/src/components/LpInput.vue +30 -16
- package/src/components/LpLightbox.vue +44 -23
- package/src/components/LpLoader.vue +145 -0
- package/src/components/LpLogViewer.vue +311 -82
- package/src/components/LpMagnetic.vue +97 -0
- package/src/components/LpMapPicker.vue +26 -28
- package/src/components/LpMasonry.vue +247 -0
- package/src/components/LpModal.vue +10 -1
- package/src/components/LpNotificationBell.vue +33 -49
- package/src/components/LpNumberField.vue +79 -14
- package/src/components/LpNumberFlow.vue +10 -35
- package/src/components/LpOtpInput.vue +7 -2
- package/src/components/LpPagination.vue +38 -4
- package/src/components/LpPalettePreview.vue +2 -7
- package/src/components/LpPasswordInput.vue +25 -18
- package/src/components/LpPhoneInput.vue +12 -3
- package/src/components/LpPie.vue +197 -36
- package/src/components/LpPipeline.vue +366 -0
- package/src/components/LpPopover.vue +14 -1
- package/src/components/LpProgress.vue +22 -84
- package/src/components/LpQuota.vue +197 -0
- package/src/components/LpRangeSlider.vue +5 -1
- package/src/components/LpRelativeTime.vue +90 -0
- package/src/components/LpRepeater.vue +131 -0
- package/src/components/LpRevealOnScroll.vue +125 -0
- package/src/components/LpRollingText.vue +12 -1
- package/src/components/LpScramble.vue +107 -0
- package/src/components/LpSecretField.vue +320 -0
- package/src/components/LpSegmented.vue +3 -10
- package/src/components/LpSelect.vue +74 -65
- package/src/components/LpShaderBackdrop.vue +434 -0
- package/src/components/LpShinyText.vue +139 -0
- package/src/components/LpSidebar.vue +2 -0
- package/src/components/LpSlider.vue +5 -1
- package/src/components/LpSparkline.vue +55 -37
- package/src/components/LpSpotlight.vue +51 -0
- package/src/components/LpStat.vue +6 -2
- package/src/components/LpStatus.vue +127 -0
- package/src/components/LpStepMark.vue +138 -0
- package/src/components/LpStepper.vue +37 -43
- package/src/components/LpSwap.vue +2 -2
- package/src/components/LpSwitch.vue +15 -22
- package/src/components/LpTable.vue +47 -63
- package/src/components/LpTableFilter.vue +1 -0
- package/src/components/LpTableOfContents.vue +53 -29
- package/src/components/LpTabs.vue +10 -21
- package/src/components/LpTagsInput.vue +53 -37
- package/src/components/LpTextReveal.vue +236 -0
- package/src/components/LpTextarea.vue +11 -11
- package/src/components/LpThemeStudio.vue +216 -0
- package/src/components/LpThemeStudioSection.vue +16 -0
- package/src/components/LpThemeSwitcher.vue +156 -47
- package/src/components/LpTimeField.vue +9 -1
- package/src/components/LpToaster.vue +63 -83
- package/src/components/LpTooltip.vue +10 -1
- package/src/components/LpTour.vue +24 -13
- package/src/components/LpTruncate.vue +135 -0
- package/src/components/LpTypewriter.vue +236 -0
- package/src/components/LpUptimeBar.vue +6 -5
- package/src/components/LpVideoBackdrop.vue +15 -13
- package/src/components/OptionContent.vue +17 -0
- package/src/components/PickerField.vue +59 -0
- package/src/components/RevealToggle.vue +51 -0
- package/src/components/StepConnector.vue +54 -0
- package/src/components/TourCard.vue +29 -16
- package/src/components/badge.ts +8 -0
- package/src/components/chart.ts +8 -23
- package/src/components/dateRange.ts +25 -0
- package/src/components/dock.ts +31 -0
- package/src/components/dropdown.ts +15 -3
- package/src/components/fieldText.ts +95 -0
- package/src/components/fileTree.ts +19 -21
- package/src/components/format.ts +136 -0
- package/src/components/identicon.ts +160 -0
- package/src/components/masonry.ts +73 -0
- package/src/components/meter.ts +122 -0
- package/src/components/otp.ts +14 -3
- package/src/components/pipeline.ts +101 -0
- package/src/components/quota.ts +111 -0
- package/src/components/relativeTime.ts +118 -0
- package/src/components/reveal.ts +56 -0
- package/src/components/scramble.ts +138 -0
- package/src/components/shaderBackdrop.ts +208 -0
- package/src/components/slider.ts +30 -0
- package/src/components/slotText.ts +13 -0
- package/src/components/status.ts +46 -0
- package/src/components/tableFacets.ts +25 -0
- package/src/components/textSplit.ts +55 -0
- package/src/components/timeSpan.ts +183 -0
- package/src/components/tone.ts +144 -0
- package/src/components/tour.ts +3 -2
- package/src/components/typewriter.ts +104 -0
- package/src/components/videoBackdrop.ts +7 -6
- package/src/composables/easing.ts +66 -1
- package/src/composables/pseudoLocale.ts +105 -0
- package/src/composables/scroll.ts +6 -3
- package/src/composables/useClipboard.ts +25 -3
- package/src/composables/useField.ts +38 -1
- package/src/composables/useForm.ts +41 -11
- package/src/composables/useInView.ts +61 -0
- package/src/composables/useLoadingGate.ts +63 -0
- package/src/composables/useLpConfig.ts +20 -1
- package/src/composables/useMediaQuery.ts +6 -2
- package/src/composables/useNow.ts +84 -0
- package/src/composables/usePersisted.ts +19 -8
- package/src/composables/usePillTransition.ts +21 -13
- package/src/composables/usePointerFrame.ts +72 -0
- package/src/composables/useReducedMotion.ts +22 -0
- package/src/composables/useRepeater.ts +44 -0
- package/src/composables/useResizeObserver.ts +59 -0
- package/src/composables/useRevealedValue.ts +84 -0
- package/src/composables/useScramble.ts +152 -0
- package/src/composables/useShift.ts +10 -16
- package/src/composables/useSpotlight.ts +82 -0
- package/src/composables/useTilt.ts +40 -23
- package/src/composables/useTween.ts +149 -0
- package/src/composables/useView.ts +96 -0
- package/src/index.css +1 -0
- package/src/index.ts +143 -1
- package/src/kit-icons.ts +1 -1
- package/src/theme/define.ts +65 -0
- package/src/theme/studio.ts +202 -0
- package/src/tokens/effects.css +151 -0
- package/src/tokens/tokens.css +131 -39
- package/src/tokens/utilities.css +81 -0
- package/dist/assets/LpTabs-Bk7v4bZz.css +0 -18
- package/dist/chunks/LpAlert-BdvxvcWE.js +0 -85
- package/dist/chunks/LpBadge-Fe0D1bYx.js +0 -62
- package/dist/chunks/LpBreadcrumbs-rzOKkLiI.js +0 -98
- package/dist/chunks/LpDatePicker-BMfM454Y.js +0 -243
- package/dist/chunks/LpDateRangePicker-CNb9X3eL.js +0 -195
- package/dist/chunks/LpNumberField-DO1ufKvE.js +0 -107
- package/dist/chunks/LpStepper-C2slwObu.js +0 -90
- package/dist/chunks/LpSwitch-CZy9_IoA.js +0 -132
- package/dist/chunks/LpThemeSwitcher-CDoziW0z.js +0 -166
- 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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
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
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
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="
|
|
556
|
+
:style="optionStagger(i)"
|
|
539
557
|
:class="[OPTION_ITEM, 'justify-between data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50']"
|
|
540
558
|
>
|
|
541
|
-
<
|
|
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>
|