@leavepulse/ui 0.68.0 → 0.70.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -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/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-B5uE8Znw.js} +1 -1
- 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-CNnLTDZg.js} +7 -7
- package/dist/chunks/LpAlert-C5igj802.js +119 -0
- package/dist/chunks/{LpAppShell-DPh1756q.js → LpAppShell-CEUAB8kK.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-HOEPBYmi.js +126 -0
- package/dist/chunks/LpBreadcrumbs-DYoPc3P4.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-CIKKT2iW.js +189 -0
- package/dist/chunks/LpCollapse-CWS9M_lm.js +115 -0
- package/dist/chunks/{LpColorPicker-DtEfBAcK.js → LpColorPicker-DFugXNUi.js} +10 -5
- 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-COwOwRgI.js} +13 -5
- package/dist/chunks/LpCopyButton-DzHjnFs0.js +133 -0
- package/dist/chunks/LpCountdown-Dtq1ihlJ.js +231 -0
- package/dist/chunks/LpDataList-B-5nHfNw.js +120 -0
- package/dist/chunks/LpDatePicker-BUe1VUC0.js +168 -0
- package/dist/chunks/LpDateRangePicker-C_k65vGR.js +126 -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-CRgrhdAH.js} +10 -5
- package/dist/chunks/LpEditable-DTqLt2lT.js +236 -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-DMISXVHC.js} +5 -3
- package/dist/chunks/{LpFileTreeNode-BXhTHaKW.js → LpFileTreeNode-CPXB_Yy3.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-Bk8TwJj0.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-p4hqzdyA.js} +27 -14
- package/dist/chunks/{LpHints-BUtBp9-w.js → LpHints-CCrhRfy9.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-CUC3t4na.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-elZHbj85.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-D5swlmZ_.js} +3 -3
- package/dist/chunks/{LpModal-hk1noDcr.js → LpModal-eBMt2Fqn.js} +8 -3
- package/dist/chunks/{LpModalNav-DQd2keZm.js → LpModalNav-D4Z0wVHR.js} +4 -4
- package/dist/chunks/{LpNotificationBell-X84PJIxD.js → LpNotificationBell-DPZmP5dM.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-DTV18FIh.js} +20 -20
- package/dist/chunks/{LpPhoneInput-DP69HONS.js → LpPhoneInput-C60tx1tC.js} +12 -7
- package/dist/chunks/{LpPie-yLF9-aDR.js → LpPie-CFuV7pZv.js} +158 -47
- package/dist/chunks/LpPipeline-D81yh_NX.js +329 -0
- package/dist/chunks/{LpPopover-DVnkHaOu.js → LpPopover-BEIcqb9p.js} +8 -3
- package/dist/chunks/{LpProgress-CA86wxXu.js → LpProgress-CE-m5OpD.js} +23 -63
- package/dist/chunks/LpQuota-2Sw_gqcJ.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-CKzVqAo9.js +73 -0
- package/dist/chunks/LpRepeater-D0VjmD6y.js +140 -0
- package/dist/chunks/LpRevealOnScroll-DcQjexLy.js +76 -0
- package/dist/chunks/LpScramble-TDO5Kdou.js +85 -0
- package/dist/chunks/LpSecretField-DMfdJ1cQ.js +307 -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-B4f_yRi5.js} +93 -108
- package/dist/chunks/LpShaderBackdrop-Bote0iuy.js +332 -0
- package/dist/chunks/LpShinyText-DX2ajtWq.js +48 -0
- package/dist/chunks/{LpSidebar-DfIiS-lB.js → LpSidebar-D-M0Y_7U.js} +5 -3
- package/dist/chunks/{LpSidebarNav-C5FDNI0t.js → LpSidebarNav-DF-TYxOV.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-B2ix1Q7t.js} +38 -35
- package/dist/chunks/LpStatus-C7kx5PKE.js +86 -0
- package/dist/chunks/LpStepMark-DK-5BKAt.js +101 -0
- package/dist/chunks/LpStepper-DRFfdJaq.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-DgpBFRV2.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-DguwHdGt.js +416 -0
- package/dist/chunks/LpThemeStudioSection-BwhqYDLf.js +20 -0
- package/dist/chunks/LpThemeSwitcher-D5uz0MhK.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-ZhKthfgz.js} +1 -1
- package/dist/chunks/{LpTour-BUp3Jt2e.js → LpTour-NfRJNEIP.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-DWegV2p6.js} +9 -8
- 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-CHRS1h7K.js +116 -0
- package/dist/chunks/RevealToggle-C-KzaQGJ.js +65 -0
- package/dist/chunks/StepConnector-37OgEOXA.js +41 -0
- package/dist/chunks/TourCard-BXuVHsfn.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.d.ts +10 -0
- package/dist/components/LpChart.vue.js +122 -142
- 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 +1 -1
- package/dist/components/LpDatePicker.vue.js +1 -1
- package/dist/components/LpDateRangePicker.vue.d.ts +1 -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 +1 -1
- package/dist/components/LpPaletteHeader.vue.js +2 -2
- package/dist/components/LpPalettePreview.vue.js +1 -1
- package/dist/components/LpPaletteStats.vue.js +1 -1
- package/dist/components/LpPasswordInput.vue.d.ts +12 -1
- 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 +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 +43 -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 +8 -0
- package/dist/composables/useField.js +5 -0
- package/dist/composables/useForm.js +19 -5
- package/dist/composables/useHintSystem.d.ts +4 -0
- package/dist/composables/useHintSystem.js +33 -1
- package/dist/composables/useHints.js +9 -3
- 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 +61 -0
- package/dist/icons-all.js +1 -1
- package/dist/index.d.ts +98 -1
- package/dist/index.js +262 -104
- package/dist/theme/define.d.ts +12 -0
- package/dist/theme/studio.d.ts +90 -0
- package/package.json +5 -2
- package/src/component-names.ts +33 -0
- package/src/components/AttentionDot.vue +27 -0
- 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 +152 -156
- 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 +10 -1
- 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 +53 -104
- package/src/components/LpDateRangePicker.vue +49 -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 +10 -1
- package/src/components/LpDropzone.vue +34 -13
- package/src/components/LpEditable.vue +293 -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 +14 -38
- 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 +16 -14
- 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 +10 -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 +80 -0
- package/src/components/LpRevealOnScroll.vue +125 -0
- package/src/components/LpScramble.vue +107 -0
- package/src/components/LpSecretField.vue +313 -0
- package/src/components/LpSegmented.vue +3 -10
- package/src/components/LpSelect.vue +78 -64
- 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 +58 -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 +12 -0
- package/src/composables/useForm.ts +27 -6
- package/src/composables/useHintSystem.ts +40 -0
- package/src/composables/useHints.ts +14 -3
- 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 +93 -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,
|
|
38
|
+
import { computed, nextTick, reactive, ref, useAttrs, useId, watch } from "vue"
|
|
39
39
|
import { 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,38 @@ 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 partOf = `lp-select-${useId()}`
|
|
182
|
+
function onFocusOut(event: FocusEvent) {
|
|
183
|
+
const next = event.relatedTarget as Element | null
|
|
184
|
+
const inside = !!next && typeof next.closest === "function" && !!next.closest(`[data-lp-select-part="${partOf}"]`)
|
|
185
|
+
if (!inside) emit("blur", event)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/*
|
|
189
|
+
* The trigger's name. reka hard-codes aria-label="Show popup" on it, which hid
|
|
190
|
+
* the field's label and the chosen value; aria-labelledby outranks aria-label,
|
|
191
|
+
* so inside a labelled field the name is the label plus the value. On its own,
|
|
192
|
+
* the consumer's aria-label, else the value or placeholder.
|
|
193
|
+
*/
|
|
194
|
+
const attrs = useAttrs()
|
|
195
|
+
const valueId = `lp-select-${useId()}-value`
|
|
196
|
+
const valueText = computed(() => (chips.value.length ? chipNames.value : displayLabel.value || placeholderText.value))
|
|
197
|
+
const triggerName = computed(() =>
|
|
198
|
+
field.value.labelId
|
|
199
|
+
? { "aria-labelledby": `${field.value.labelId} ${valueId}`, "aria-label": undefined }
|
|
200
|
+
: { "aria-label": (attrs["aria-label"] as string | undefined) ?? valueText.value },
|
|
201
|
+
)
|
|
202
|
+
|
|
171
203
|
// reka's Combobox forbids an empty-string item value (it reserves "" for
|
|
172
204
|
// "cleared"). An empty-string option is legitimate for us (e.g. "Any edition"),
|
|
173
205
|
// so we encode "" to a sentinel for reka and decode it back at the boundary —
|
|
@@ -271,6 +303,12 @@ const displayLabel = computed(() => {
|
|
|
271
303
|
return current.value?.label ?? ""
|
|
272
304
|
})
|
|
273
305
|
|
|
306
|
+
// What makes the shown pick "another one": its name, hint and picture together.
|
|
307
|
+
const rollKey = computed(() => {
|
|
308
|
+
const c = current.value
|
|
309
|
+
return c ? [c.label, c.hint ?? "", c.image ?? c.icon ?? ""].join("\u0000") : `\u0000${placeholderText.value}`
|
|
310
|
+
})
|
|
311
|
+
|
|
274
312
|
/*
|
|
275
313
|
* Chips collapse to "+N" when the row runs out of room. Every chip is drawn a
|
|
276
314
|
* second time in an invisible probe row at its natural width; the visible row
|
|
@@ -296,16 +334,8 @@ function measure() {
|
|
|
296
334
|
)
|
|
297
335
|
}
|
|
298
336
|
|
|
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
|
-
})
|
|
337
|
+
useResizeObserver(chipRow, () => measure())
|
|
307
338
|
watch(chips, () => void nextTick(measure), { flush: "post", deep: true })
|
|
308
|
-
onBeforeUnmount(() => rowObserver?.disconnect())
|
|
309
339
|
|
|
310
340
|
const shownChips = computed(() => chips.value.slice(0, fit.value))
|
|
311
341
|
const hiddenCount = computed(() => modelList.value.length - shownChips.value.length)
|
|
@@ -334,8 +364,15 @@ function onUpdate(value: unknown) {
|
|
|
334
364
|
}
|
|
335
365
|
|
|
336
366
|
function clear() {
|
|
367
|
+
if (field.value.disabled) return
|
|
337
368
|
emit("update:modelValue", (props.multiple ? [] : undefined) as Model)
|
|
338
369
|
}
|
|
370
|
+
|
|
371
|
+
// Overlays open in the window this component renders in (an LpFrame's, inside one).
|
|
372
|
+
const portalTo = usePortalTarget()
|
|
373
|
+
// What happens in another document (the page around a frame, or a frame in
|
|
374
|
+
// the page) is not "outside" for this layer.
|
|
375
|
+
const guardOutside = useOutsideGuard()
|
|
339
376
|
</script>
|
|
340
377
|
|
|
341
378
|
<template>
|
|
@@ -349,6 +386,7 @@ function clear() {
|
|
|
349
386
|
:model-value="comboModel"
|
|
350
387
|
:multiple="multiple"
|
|
351
388
|
:disabled="field.disabled"
|
|
389
|
+
:required="field.required"
|
|
352
390
|
:ignore-filter="true"
|
|
353
391
|
:reset-search-term-on-select="false"
|
|
354
392
|
:reset-search-term-on-blur="false"
|
|
@@ -358,9 +396,12 @@ function clear() {
|
|
|
358
396
|
@update:open="onOpenChange"
|
|
359
397
|
>
|
|
360
398
|
<ComboboxAnchor
|
|
399
|
+
:data-lp-select-part="partOf"
|
|
400
|
+
@focusout="onFocusOut"
|
|
361
401
|
:class="[
|
|
362
402
|
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
|
|
403
|
+
'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',
|
|
404
|
+
field.disabled && 'cursor-not-allowed opacity-55',
|
|
364
405
|
field.invalid
|
|
365
406
|
? 'border-danger focus-within:border-danger focus-within:ring-danger-soft'
|
|
366
407
|
: 'border-line focus-within:border-brand focus-within:ring-ring',
|
|
@@ -370,8 +411,10 @@ function clear() {
|
|
|
370
411
|
will not go narrower than its content without it, so a long
|
|
371
412
|
placeholder stretched the whole field past the viewport instead of
|
|
372
413
|
being cut short. -->
|
|
414
|
+
<span :id="valueId" hidden>{{ valueText }}</span>
|
|
373
415
|
<ComboboxTrigger
|
|
374
416
|
:id="field.id"
|
|
417
|
+
v-bind="triggerName"
|
|
375
418
|
:aria-invalid="field.invalid || undefined"
|
|
376
419
|
:aria-describedby="field.describedBy"
|
|
377
420
|
class="flex min-w-0 flex-1 items-center gap-2 outline-none"
|
|
@@ -429,52 +472,28 @@ function clear() {
|
|
|
429
472
|
</span>
|
|
430
473
|
</span>
|
|
431
474
|
<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
|
-
>
|
|
475
|
+
<!-- The pick turns over as one piece: its picture, name and hint
|
|
476
|
+
leave together and the next ones arrive together. Animated
|
|
477
|
+
apart (a fading picture, a rolling name, a cross-faded hint)
|
|
478
|
+
they ran at three speeds, and for a moment the old hint stood
|
|
479
|
+
beside the new one and shoved the row. -->
|
|
480
|
+
<LpRollingText :value="rollKey" align="start" class="min-w-0 flex-1">
|
|
481
|
+
<span class="flex min-w-0 items-center gap-2">
|
|
442
482
|
<img
|
|
443
483
|
v-if="current?.image"
|
|
444
|
-
:key="current.image"
|
|
445
484
|
:src="current.image"
|
|
446
485
|
alt=""
|
|
447
|
-
class="block size-5 rounded-full object-cover"
|
|
448
|
-
/>
|
|
449
|
-
<LpIcon
|
|
450
|
-
v-else-if="current?.icon"
|
|
451
|
-
:key="current.icon"
|
|
452
|
-
:name="current.icon"
|
|
453
|
-
:size="16"
|
|
454
|
-
class="block text-muted"
|
|
486
|
+
class="block size-5 shrink-0 rounded-full object-cover"
|
|
455
487
|
/>
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
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>
|
|
488
|
+
<LpIcon v-else-if="current?.icon" :name="current.icon" :size="16" class="block shrink-0 text-muted" />
|
|
489
|
+
<span class="min-w-0 truncate" :class="displayLabel ? '' : 'text-muted'">{{ displayLabel || placeholderText }}</span>
|
|
490
|
+
<span v-if="current?.hint" class="min-w-0 truncate text-muted">{{ current.hint }}</span>
|
|
491
|
+
</span>
|
|
492
|
+
</LpRollingText>
|
|
474
493
|
</template>
|
|
475
494
|
</ComboboxTrigger>
|
|
476
495
|
<button
|
|
477
|
-
v-if="clearable && hasValue"
|
|
496
|
+
v-if="clearable && hasValue && !field.disabled"
|
|
478
497
|
type="button"
|
|
479
498
|
class="group flex shrink-0 items-center text-muted outline-none transition-colors duration-[var(--duration-fast)] hover:text-ink"
|
|
480
499
|
:aria-label="labels.clear"
|
|
@@ -507,8 +526,12 @@ function clear() {
|
|
|
507
526
|
</ComboboxTrigger>
|
|
508
527
|
</ComboboxAnchor>
|
|
509
528
|
|
|
510
|
-
<ComboboxPortal>
|
|
529
|
+
<ComboboxPortal :to="portalTo">
|
|
511
530
|
<ComboboxContent
|
|
531
|
+
:data-lp-select-part="partOf"
|
|
532
|
+
@focusout="onFocusOut"
|
|
533
|
+
@interact-outside="guardOutside"
|
|
534
|
+
@escape-key-down="guardOutside"
|
|
512
535
|
position="popper"
|
|
513
536
|
:side-offset="6"
|
|
514
537
|
:class="[POPOVER_PANEL, 'z-(--z-popover) max-h-72 w-(--reka-combobox-trigger-width) overflow-hidden']"
|
|
@@ -535,19 +558,10 @@ function clear() {
|
|
|
535
558
|
:key="String(opt.value)"
|
|
536
559
|
:value="encode(opt.value)"
|
|
537
560
|
:disabled="opt.disabled"
|
|
538
|
-
:style="
|
|
561
|
+
:style="optionStagger(i)"
|
|
539
562
|
:class="[OPTION_ITEM, 'justify-between data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50']"
|
|
540
563
|
>
|
|
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>
|
|
564
|
+
<OptionContent :option="opt" />
|
|
551
565
|
<ComboboxItemIndicator class="flex shrink-0 items-center text-brand">
|
|
552
566
|
<LpIcon name="lucide:check" :size="16" />
|
|
553
567
|
</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>
|