@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
|
@@ -67,11 +67,13 @@ import { hints } from "../composables/useHints"
|
|
|
67
67
|
import { useHotkeys } from "../composables/useHotkeys"
|
|
68
68
|
import { useLabels } from "../composables/useLpConfig"
|
|
69
69
|
import { useMediaQuery } from "../composables/useMediaQuery"
|
|
70
|
+
import { useView, viewDocument, viewWindow } from "../composables/useView"
|
|
70
71
|
import { scrollToElement } from "../composables/scroll"
|
|
71
72
|
import { PANEL_SURFACE } from "./dropdown"
|
|
72
73
|
import TourCard from "./TourCard.vue"
|
|
73
74
|
import type { Box } from "../composables/spatialNav"
|
|
74
75
|
import { holeClip, holeOf, panelsAround } from "./tour"
|
|
76
|
+
import { usePortalTarget } from "../composables/useView"
|
|
75
77
|
|
|
76
78
|
const props = withDefaults(
|
|
77
79
|
defineProps<{
|
|
@@ -111,6 +113,10 @@ const SETTLE_MS = 1000
|
|
|
111
113
|
const CARD_ROOM = 200
|
|
112
114
|
|
|
113
115
|
const wide = useMediaQuery("(min-width: 640px)")
|
|
116
|
+
// The window the tour walks: the page's, or an LpFrame's when it runs in one.
|
|
117
|
+
const view = useView()
|
|
118
|
+
const win = () => viewWindow(view.value)
|
|
119
|
+
const doc = () => viewDocument(view.value)
|
|
114
120
|
const sampled = ref(false)
|
|
115
121
|
const step = computed<TourStep | undefined>(() => {
|
|
116
122
|
const raw = props.steps[index.value]
|
|
@@ -161,7 +167,7 @@ function resolve(raw: TourStep["target"]): Element | null {
|
|
|
161
167
|
try {
|
|
162
168
|
if (typeof raw === "function") return raw()
|
|
163
169
|
if (typeof raw !== "string") return raw.isConnected ? raw : null
|
|
164
|
-
return hints.element(raw) ??
|
|
170
|
+
return hints.element(raw) ?? doc().querySelector(raw)
|
|
165
171
|
} catch {
|
|
166
172
|
return null
|
|
167
173
|
}
|
|
@@ -185,9 +191,9 @@ function waitFor(raw: TourStep["target"], mine: number): Promise<Element | null>
|
|
|
185
191
|
// or calc(), which parseFloat would misread (0.5rem → 0.5px), so the browser
|
|
186
192
|
// resolves it on a throwaway element.
|
|
187
193
|
function controlRadius(): number {
|
|
188
|
-
const probe =
|
|
194
|
+
const probe = doc().createElement("div")
|
|
189
195
|
probe.style.cssText = "position:absolute;visibility:hidden;border-top-left-radius:var(--radius-control)"
|
|
190
|
-
|
|
196
|
+
doc().body.append(probe)
|
|
191
197
|
const px = parseFloat(getComputedStyle(probe).borderTopLeftRadius)
|
|
192
198
|
probe.remove()
|
|
193
199
|
return Number.isFinite(px) ? px : 8
|
|
@@ -201,7 +207,7 @@ const pause = (ms: number) => new Promise<void>((done) => setTimeout(done, ms))
|
|
|
201
207
|
// to land. Endless animations (a pulse, a spinner) never land and are left out.
|
|
202
208
|
async function settled(el: Element): Promise<void> {
|
|
203
209
|
await new Promise(requestAnimationFrame)
|
|
204
|
-
const moving =
|
|
210
|
+
const moving = doc().getAnimations().filter((animation) => {
|
|
205
211
|
const node = animation.effect instanceof KeyframeEffect ? animation.effect.target : null
|
|
206
212
|
const end = Number(animation.effect?.getComputedTiming().endTime)
|
|
207
213
|
return !!node && (node.contains(el) || el.contains(node)) && Number.isFinite(end)
|
|
@@ -239,7 +245,7 @@ function glideTo(el: Element | null) {
|
|
|
239
245
|
}
|
|
240
246
|
|
|
241
247
|
function measure() {
|
|
242
|
-
viewport.value = { width:
|
|
248
|
+
viewport.value = { width: win().innerWidth, height: win().innerHeight }
|
|
243
249
|
const el = target.value
|
|
244
250
|
if (!el) {
|
|
245
251
|
box.value = null
|
|
@@ -371,13 +377,13 @@ watch(
|
|
|
371
377
|
direction = 1
|
|
372
378
|
box.value = null
|
|
373
379
|
radius.value = controlRadius()
|
|
374
|
-
|
|
375
|
-
|
|
380
|
+
doc().addEventListener("click", onTargetClick, true)
|
|
381
|
+
doc().addEventListener("contextmenu", onTargetClick, true)
|
|
376
382
|
frame ||= requestAnimationFrame(track)
|
|
377
383
|
void show()
|
|
378
384
|
} else {
|
|
379
|
-
|
|
380
|
-
|
|
385
|
+
doc().removeEventListener("click", onTargetClick, true)
|
|
386
|
+
doc().removeEventListener("contextmenu", onTargetClick, true)
|
|
381
387
|
end()
|
|
382
388
|
}
|
|
383
389
|
},
|
|
@@ -389,8 +395,8 @@ watch(index, () => {
|
|
|
389
395
|
})
|
|
390
396
|
|
|
391
397
|
onBeforeUnmount(() => {
|
|
392
|
-
|
|
393
|
-
|
|
398
|
+
doc().removeEventListener("click", onTargetClick, true)
|
|
399
|
+
doc().removeEventListener("contextmenu", onTargetClick, true)
|
|
394
400
|
if (open.value) end()
|
|
395
401
|
})
|
|
396
402
|
|
|
@@ -408,10 +414,13 @@ useHotkeys(
|
|
|
408
414
|
// and reka switches off pointer events on every older one, the card included
|
|
409
415
|
// when it carries over from the step before. The tour sits above all of them.
|
|
410
416
|
const CARD = `${PANEL_SURFACE} pointer-events-auto! rounded-card w-80 max-w-[calc(100vw-24px)] p-4 text-sm text-ink outline-none`
|
|
417
|
+
|
|
418
|
+
// Overlays open in the window this component renders in (an LpFrame's, inside one).
|
|
419
|
+
const portalTo = usePortalTarget()
|
|
411
420
|
</script>
|
|
412
421
|
|
|
413
422
|
<template>
|
|
414
|
-
<Teleport to="
|
|
423
|
+
<Teleport :to="portalTo">
|
|
415
424
|
<Transition
|
|
416
425
|
enter-active-class="transition-opacity duration-[var(--duration-medium)] ease-[var(--ease-emphasized)] motion-reduce:transition-none"
|
|
417
426
|
leave-active-class="lp-tour-gone transition-opacity duration-[var(--duration-medium)] ease-out motion-reduce:transition-none"
|
|
@@ -444,7 +453,7 @@ const CARD = `${PANEL_SURFACE} pointer-events-auto! rounded-card w-80 max-w-[cal
|
|
|
444
453
|
|
|
445
454
|
<PopoverRoot v-if="wide" :open="open && ready">
|
|
446
455
|
<PopoverAnchor :reference="reference" />
|
|
447
|
-
<PopoverPortal>
|
|
456
|
+
<PopoverPortal :to="portalTo">
|
|
448
457
|
<PopoverContent
|
|
449
458
|
:side="side"
|
|
450
459
|
:side-offset="12"
|
|
@@ -452,6 +461,7 @@ const CARD = `${PANEL_SURFACE} pointer-events-auto! rounded-card w-80 max-w-[cal
|
|
|
452
461
|
update-position-strategy="always"
|
|
453
462
|
:trap-focus="false"
|
|
454
463
|
:class="[CARD, 'z-[calc(var(--z-tour)+1)] data-[state=open]:animate-[popover-in_var(--duration-medium)_var(--ease-emphasized)] data-[state=closed]:animate-[popover-out_var(--duration-fast)_ease-out] motion-reduce:animate-none']"
|
|
464
|
+
:data-lp-glide-position="gliding || undefined"
|
|
455
465
|
role="dialog"
|
|
456
466
|
:aria-label="step?.title"
|
|
457
467
|
@pointerdown.stop
|
|
@@ -481,3 +491,4 @@ const CARD = `${PANEL_SURFACE} pointer-events-auto! rounded-card w-80 max-w-[cal
|
|
|
481
491
|
</Transition>
|
|
482
492
|
</Teleport>
|
|
483
493
|
</template>
|
|
494
|
+
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
export default { inheritAttrs: false }
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<script setup lang="ts">
|
|
6
|
+
/*
|
|
7
|
+
* Text that may not fit: cut with an ellipsis, and the whole of it in a tip —
|
|
8
|
+
* but only when something was actually cut. A tip that repeats the text you
|
|
9
|
+
* can already read in full is noise, and a list of names where every row
|
|
10
|
+
* pops one up teaches people to ignore them.
|
|
11
|
+
*
|
|
12
|
+
* <LpTruncate :text="server.name" />
|
|
13
|
+
* <LpTruncate :text="description" :lines="2" />
|
|
14
|
+
* <LpTruncate :text="commitHash" middle :tail="6" copyable />
|
|
15
|
+
*
|
|
16
|
+
* Whether it was cut is measured, not guessed: a ResizeObserver re-checks when
|
|
17
|
+
* the box resizes (a sidebar collapsing, a column dragged), so the tip appears
|
|
18
|
+
* and disappears with the layout.
|
|
19
|
+
*
|
|
20
|
+
* `middle` cuts out of the middle instead (`/home/u…/report.pdf`), for ids,
|
|
21
|
+
* paths and hashes, whose two ends are what people compare. The browser has
|
|
22
|
+
* no CSS for that, so the longest fitting cut is found by measuring with the
|
|
23
|
+
* element's own font (see `middleTruncate`). Assistive tech always gets the
|
|
24
|
+
* full text: the cut version is only drawn.
|
|
25
|
+
*
|
|
26
|
+
* A truncated value becomes focusable, so the tip is reachable by keyboard too.
|
|
27
|
+
*/
|
|
28
|
+
import { computed, nextTick, onMounted, ref, watch } from "vue"
|
|
29
|
+
import { useMergedAttrs } from "../composables/useMergedClass"
|
|
30
|
+
import { useResizeObserver } from "../composables/useResizeObserver"
|
|
31
|
+
import LpCopyButton from "./LpCopyButton.vue"
|
|
32
|
+
import LpTooltip from "./LpTooltip.vue"
|
|
33
|
+
import { middleTruncate } from "./fieldText"
|
|
34
|
+
|
|
35
|
+
const props = withDefaults(
|
|
36
|
+
defineProps<{
|
|
37
|
+
text: string
|
|
38
|
+
/** Lines before the cut. Ignored with `middle`, which is one line by nature. */
|
|
39
|
+
lines?: number
|
|
40
|
+
/** Cut from the middle, keeping both ends. */
|
|
41
|
+
middle?: boolean
|
|
42
|
+
/** With `middle`: how many characters the end keeps. Unset splits evenly. */
|
|
43
|
+
tail?: number
|
|
44
|
+
/** A copy button after the text, for values people paste elsewhere. */
|
|
45
|
+
copyable?: boolean
|
|
46
|
+
/** Where the tip opens. */
|
|
47
|
+
side?: "top" | "right" | "bottom" | "left"
|
|
48
|
+
/** Never show the tip, even when cut (the full text is shown elsewhere). */
|
|
49
|
+
noTooltip?: boolean
|
|
50
|
+
}>(),
|
|
51
|
+
{ lines: 1, side: "top" },
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
const box = ref<HTMLElement | null>(null)
|
|
55
|
+
const truncated = ref(false)
|
|
56
|
+
const drawn = ref(props.text)
|
|
57
|
+
|
|
58
|
+
let canvas: CanvasRenderingContext2D | null = null
|
|
59
|
+
function measurer(el: HTMLElement): (s: string) => number {
|
|
60
|
+
canvas ??= document.createElement("canvas").getContext("2d")
|
|
61
|
+
const style = getComputedStyle(el)
|
|
62
|
+
// Built from the longhands: Firefox leaves the `font` shorthand empty in
|
|
63
|
+
// computed styles.
|
|
64
|
+
if (canvas) canvas.font = `${style.fontStyle} ${style.fontWeight} ${style.fontSize} ${style.fontFamily}`
|
|
65
|
+
const spacing = Number.parseFloat(style.letterSpacing) || 0
|
|
66
|
+
return (s) => (canvas ? canvas.measureText(s).width + spacing * Array.from(s).length : 0)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function measure() {
|
|
70
|
+
const el = box.value
|
|
71
|
+
if (!el) return
|
|
72
|
+
if (props.middle) {
|
|
73
|
+
const width = el.clientWidth
|
|
74
|
+
if (!width) return
|
|
75
|
+
const widthOf = measurer(el)
|
|
76
|
+
// Half a pixel of slack: canvas and layout round sub-pixels differently.
|
|
77
|
+
const fit = middleTruncate(props.text, (s) => widthOf(s) <= width - 0.5, { tail: props.tail })
|
|
78
|
+
drawn.value = fit
|
|
79
|
+
truncated.value = fit !== props.text
|
|
80
|
+
return
|
|
81
|
+
}
|
|
82
|
+
truncated.value = props.lines > 1 ? el.scrollHeight > el.clientHeight + 1 : el.scrollWidth > el.clientWidth + 0.5
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
useResizeObserver(box, () => measure())
|
|
86
|
+
onMounted(() => {
|
|
87
|
+
measure()
|
|
88
|
+
// Web fonts land after mount and change every width.
|
|
89
|
+
void document.fonts?.ready.then(() => measure())
|
|
90
|
+
})
|
|
91
|
+
watch(
|
|
92
|
+
() => [props.text, props.lines, props.middle, props.tail],
|
|
93
|
+
async () => {
|
|
94
|
+
drawn.value = props.text
|
|
95
|
+
await nextTick()
|
|
96
|
+
measure()
|
|
97
|
+
},
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
const clampStyle = computed(() =>
|
|
101
|
+
!props.middle && props.lines > 1
|
|
102
|
+
? { display: "-webkit-box", WebkitBoxOrient: "vertical" as const, WebkitLineClamp: props.lines, overflow: "hidden" }
|
|
103
|
+
: undefined,
|
|
104
|
+
)
|
|
105
|
+
const boxClass = computed(() =>
|
|
106
|
+
props.middle ? "block overflow-hidden whitespace-pre" : props.lines > 1 ? "break-words" : "block truncate",
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
const { class: rootClass, attrs: rest } = useMergedAttrs(() => "inline-flex min-w-0 max-w-full items-center gap-1 align-bottom")
|
|
110
|
+
</script>
|
|
111
|
+
|
|
112
|
+
<template>
|
|
113
|
+
<span :class="rootClass" v-bind="rest">
|
|
114
|
+
<LpTooltip :content="text" :side="side" :disabled="noTooltip || !truncated">
|
|
115
|
+
<span
|
|
116
|
+
ref="box"
|
|
117
|
+
class="min-w-0 flex-1 rounded-[2px] outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
118
|
+
:class="boxClass"
|
|
119
|
+
:style="clampStyle"
|
|
120
|
+
:tabindex="truncated && !noTooltip ? 0 : undefined"
|
|
121
|
+
>
|
|
122
|
+
<template v-if="middle">
|
|
123
|
+
<span aria-hidden="true">{{ drawn }}</span>
|
|
124
|
+
<!-- The full text, invisible and flat, gives the box its natural
|
|
125
|
+
width; without it the box would shrink to the cut text and
|
|
126
|
+
never grow back when room opens up. -->
|
|
127
|
+
<span aria-hidden="true" class="invisible block h-0">{{ text }}</span>
|
|
128
|
+
<span class="sr-only">{{ text }}</span>
|
|
129
|
+
</template>
|
|
130
|
+
<template v-else>{{ text }}</template>
|
|
131
|
+
</span>
|
|
132
|
+
</LpTooltip>
|
|
133
|
+
<LpCopyButton v-if="copyable" :value="text" size="xs" class="-my-1 size-6 shrink-0 text-muted" />
|
|
134
|
+
</span>
|
|
135
|
+
</template>
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
// The root class is merged with the consumer's (useMergedAttrs).
|
|
3
|
+
export default { inheritAttrs: false }
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
<script setup lang="ts">
|
|
7
|
+
/*
|
|
8
|
+
* Text typed out a character at a time, optionally cycling through several
|
|
9
|
+
* strings: type, hold, erase, type the next.
|
|
10
|
+
*
|
|
11
|
+
* For a line that suggests rather than states: the examples a search box can
|
|
12
|
+
* take ("Search servers", "Search logs", "Search people"), a hero line naming
|
|
13
|
+
* what a product does, a terminal-styled empty state. Not for anything the
|
|
14
|
+
* reader has to read to continue: it makes them wait for it.
|
|
15
|
+
*
|
|
16
|
+
* <LpTypewriter text="Hello, operator." />
|
|
17
|
+
* <LpTypewriter :text="['servers', 'logs', 'people']" loop />
|
|
18
|
+
*
|
|
19
|
+
* Keystrokes are uneven and pause after punctuation, so it reads as typing and
|
|
20
|
+
* not as a progress bar. Erasing stops at what the next string shares with the
|
|
21
|
+
* current one ("Search logs" to "Search people" erases only "logs").
|
|
22
|
+
*
|
|
23
|
+
* The box reserves the size of the longest string, so the line it sits in
|
|
24
|
+
* does not jump as characters come and go. `reserve` off lets it take the
|
|
25
|
+
* width of what is typed, for text that runs on in a sentence.
|
|
26
|
+
*
|
|
27
|
+
* Screen readers hear whole strings, never characters: a polite live region
|
|
28
|
+
* gets each string once it is fully typed. It starts typing the first time it
|
|
29
|
+
* is on screen and pauses while it is off screen or the tab is hidden. Under
|
|
30
|
+
* reduced motion whole strings appear and swap without typing.
|
|
31
|
+
*/
|
|
32
|
+
import { computed, onBeforeUnmount, ref, watch } from "vue"
|
|
33
|
+
import { prefersReducedMotion } from "../composables/easing"
|
|
34
|
+
import { useInView } from "../composables/useInView"
|
|
35
|
+
import { useMergedAttrs } from "../composables/useMergedClass"
|
|
36
|
+
import { useReveal } from "../composables/useReveal"
|
|
37
|
+
import { graphemes } from "./scramble"
|
|
38
|
+
import { typewriterNext, typewriterStart, type TypewriterState } from "./typewriter"
|
|
39
|
+
|
|
40
|
+
const props = withDefaults(
|
|
41
|
+
defineProps<{
|
|
42
|
+
/** One string, or several to cycle through. */
|
|
43
|
+
text: string | string[]
|
|
44
|
+
/** Ms per character, before the natural unevenness. */
|
|
45
|
+
speed?: number
|
|
46
|
+
/** Ms per erased character. */
|
|
47
|
+
eraseSpeed?: number
|
|
48
|
+
/** Ms a finished string stays before it is erased. */
|
|
49
|
+
hold?: number
|
|
50
|
+
/** Ms before the first keystroke, once it is on screen. */
|
|
51
|
+
startDelay?: number
|
|
52
|
+
/** After the last string, start over from the first. Without it the last string stays. */
|
|
53
|
+
loop?: boolean
|
|
54
|
+
/** Show the caret. */
|
|
55
|
+
caret?: boolean
|
|
56
|
+
/** Reserve the longest string's size so the surroundings hold still. */
|
|
57
|
+
reserve?: boolean
|
|
58
|
+
/** Hold it until true. Leave unset to start the first time it is on screen. */
|
|
59
|
+
play?: boolean
|
|
60
|
+
/** Element to render. */
|
|
61
|
+
as?: string
|
|
62
|
+
}>(),
|
|
63
|
+
{
|
|
64
|
+
speed: 55,
|
|
65
|
+
eraseSpeed: 28,
|
|
66
|
+
hold: 1800,
|
|
67
|
+
startDelay: 0,
|
|
68
|
+
loop: false,
|
|
69
|
+
caret: true,
|
|
70
|
+
reserve: true,
|
|
71
|
+
play: undefined,
|
|
72
|
+
as: "span",
|
|
73
|
+
},
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
const emit = defineEmits<{
|
|
77
|
+
/** A string has been typed out in full. */
|
|
78
|
+
typed: [index: number, text: string]
|
|
79
|
+
/** The last string is typed and nothing more will happen (never fires with `loop`). */
|
|
80
|
+
finished: []
|
|
81
|
+
}>()
|
|
82
|
+
|
|
83
|
+
const { class: rootClass, attrs: rest } = useMergedAttrs(
|
|
84
|
+
() => "lp-typewriter relative inline-grid whitespace-pre-wrap align-bottom",
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
const strings = computed(() => (Array.isArray(props.text) ? props.text : [props.text]))
|
|
88
|
+
const split = computed(() => strings.value.map((s) => graphemes(s)))
|
|
89
|
+
|
|
90
|
+
const state = ref<TypewriterState>(typewriterStart())
|
|
91
|
+
const visible = computed(() => (split.value[state.value.index] ?? []).slice(0, state.value.length).join(""))
|
|
92
|
+
const announced = ref(strings.value[0] ?? "")
|
|
93
|
+
const idle = computed(() => state.value.phase === "holding" || state.value.phase === "done")
|
|
94
|
+
|
|
95
|
+
const { el: revealEl, revealed } = useReveal({ immediate: () => props.play !== undefined })
|
|
96
|
+
const { el: viewEl, inView } = useInView()
|
|
97
|
+
const setRoot = (node: unknown) => {
|
|
98
|
+
const element = node instanceof Element ? node : null
|
|
99
|
+
revealEl.value = element
|
|
100
|
+
viewEl.value = element
|
|
101
|
+
}
|
|
102
|
+
const running = computed(() => (props.play ?? revealed.value) && inView.value)
|
|
103
|
+
|
|
104
|
+
let timer: ReturnType<typeof setTimeout> | undefined
|
|
105
|
+
// Time left on the step a pause interrupted, so going off screen mid-hold and
|
|
106
|
+
// back does not restart the hold from zero or skip it.
|
|
107
|
+
let pendingWait: number | null = null
|
|
108
|
+
let dueAt = 0
|
|
109
|
+
let started = false
|
|
110
|
+
|
|
111
|
+
function schedule(wait: number) {
|
|
112
|
+
clearTimeout(timer)
|
|
113
|
+
timer = undefined
|
|
114
|
+
if (!Number.isFinite(wait)) return
|
|
115
|
+
pendingWait = wait
|
|
116
|
+
if (!running.value) return
|
|
117
|
+
dueAt = performance.now() + wait
|
|
118
|
+
timer = setTimeout(tick, wait)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function tick() {
|
|
122
|
+
timer = undefined
|
|
123
|
+
pendingWait = null
|
|
124
|
+
const options = { speed: props.speed, eraseSpeed: props.eraseSpeed, hold: props.hold, loop: props.loop }
|
|
125
|
+
let step = typewriterNext(state.value, split.value, options)
|
|
126
|
+
if (prefersReducedMotion()) {
|
|
127
|
+
// Whole strings: run the keystrokes of this phase at once and keep only
|
|
128
|
+
// the waits that are holds.
|
|
129
|
+
let guard = 0
|
|
130
|
+
while (step.typed === undefined && Number.isFinite(step.wait) && guard++ < 10_000) {
|
|
131
|
+
step = typewriterNext(step.state, split.value, options)
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
state.value = step.state
|
|
135
|
+
if (step.typed !== undefined) {
|
|
136
|
+
const text = strings.value[step.typed] ?? ""
|
|
137
|
+
announced.value = text
|
|
138
|
+
emit("typed", step.typed, text)
|
|
139
|
+
if (step.state.phase === "done") emit("finished")
|
|
140
|
+
}
|
|
141
|
+
if (step.wait === 0) return tick()
|
|
142
|
+
schedule(step.wait)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
watch(
|
|
146
|
+
running,
|
|
147
|
+
(now) => {
|
|
148
|
+
if (!now) {
|
|
149
|
+
if (timer) pendingWait = Math.max(0, dueAt - performance.now())
|
|
150
|
+
clearTimeout(timer)
|
|
151
|
+
timer = undefined
|
|
152
|
+
return
|
|
153
|
+
}
|
|
154
|
+
if (!started) {
|
|
155
|
+
started = true
|
|
156
|
+
return schedule(prefersReducedMotion() ? 0 : props.startDelay)
|
|
157
|
+
}
|
|
158
|
+
if (pendingWait !== null) schedule(pendingWait)
|
|
159
|
+
},
|
|
160
|
+
{ immediate: true },
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
// New strings: erase back to what the new first string shares, then type it.
|
|
164
|
+
watch(
|
|
165
|
+
() => strings.value.join("\u0000"),
|
|
166
|
+
() => {
|
|
167
|
+
if (!started) return
|
|
168
|
+
const index = Math.min(state.value.index, split.value.length - 1)
|
|
169
|
+
state.value = { index: Math.max(0, index), length: Math.min(state.value.length, split.value[index]?.length ?? 0), phase: "erasing", to: 0 }
|
|
170
|
+
schedule(props.eraseSpeed)
|
|
171
|
+
},
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
watch(
|
|
175
|
+
() => props.loop,
|
|
176
|
+
(loop) => {
|
|
177
|
+
if (loop && state.value.phase === "done") {
|
|
178
|
+
state.value = { ...state.value, phase: "holding" }
|
|
179
|
+
schedule(props.hold)
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
onBeforeUnmount(() => clearTimeout(timer))
|
|
185
|
+
</script>
|
|
186
|
+
|
|
187
|
+
<template>
|
|
188
|
+
<component :is="as" :ref="setRoot" :class="rootClass" v-bind="rest">
|
|
189
|
+
<span class="sr-only" aria-live="polite">{{ announced }}</span>
|
|
190
|
+
<!-- The zero-width space keeps a baseline while nothing is typed yet, so
|
|
191
|
+
the empty box does not sink below the text around it. -->
|
|
192
|
+
<span aria-hidden="true" class="[grid-area:1/1]"
|
|
193
|
+
>​{{ visible
|
|
194
|
+
}}<span
|
|
195
|
+
v-if="caret"
|
|
196
|
+
class="lp-typewriter__caret"
|
|
197
|
+
:class="idle ? 'lp-typewriter__caret--blink' : ''"
|
|
198
|
+
/></span>
|
|
199
|
+
<template v-if="reserve">
|
|
200
|
+
<span v-for="(s, i) in strings" :key="i" aria-hidden="true" class="invisible [grid-area:1/1]"
|
|
201
|
+
>{{ s }}<span v-if="caret" class="lp-typewriter__caret"
|
|
202
|
+
/></span>
|
|
203
|
+
</template>
|
|
204
|
+
</component>
|
|
205
|
+
</template>
|
|
206
|
+
|
|
207
|
+
<style>
|
|
208
|
+
.lp-typewriter__caret {
|
|
209
|
+
display: inline-block;
|
|
210
|
+
width: 0.08em;
|
|
211
|
+
min-width: 2px;
|
|
212
|
+
height: 1.05em;
|
|
213
|
+
margin-inline-start: 0.06em;
|
|
214
|
+
vertical-align: -0.15em;
|
|
215
|
+
border-radius: 1px;
|
|
216
|
+
background: var(--color-brand);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/* Solid while keys are moving, blinking while it waits: the same cue a real
|
|
220
|
+
text field gives about whether input is happening. */
|
|
221
|
+
.lp-typewriter__caret--blink {
|
|
222
|
+
animation: lp-typewriter-blink 1.06s step-end infinite;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
@keyframes lp-typewriter-blink {
|
|
226
|
+
50% {
|
|
227
|
+
opacity: 0;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
@media (prefers-reduced-motion: reduce) {
|
|
232
|
+
.lp-typewriter__caret--blink {
|
|
233
|
+
animation: none;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
</style>
|
|
@@ -12,6 +12,7 @@ import LpRollingText from "./LpRollingText.vue"
|
|
|
12
12
|
import LpSkeleton from "./LpSkeleton.vue"
|
|
13
13
|
import LpSwap from "./LpSwap.vue"
|
|
14
14
|
import LpTooltip from "./LpTooltip.vue"
|
|
15
|
+
import { TONES } from "./tone"
|
|
15
16
|
import { useMergedAttrs } from "../composables/useMergedClass"
|
|
16
17
|
import { useLabels } from "../composables/useLpConfig"
|
|
17
18
|
|
|
@@ -64,11 +65,11 @@ const props = withDefaults(
|
|
|
64
65
|
* made the whole row look faded rather than calm.)
|
|
65
66
|
*/
|
|
66
67
|
const defaultColor: Record<UptimeStatus, string> = {
|
|
67
|
-
operational:
|
|
68
|
-
degraded:
|
|
69
|
-
down:
|
|
70
|
-
maintenance:
|
|
71
|
-
empty:
|
|
68
|
+
operational: TONES.success.color,
|
|
69
|
+
degraded: TONES.warning.color,
|
|
70
|
+
down: TONES.danger.color,
|
|
71
|
+
maintenance: TONES.brand.color,
|
|
72
|
+
empty: TONES.neutral.soft,
|
|
72
73
|
}
|
|
73
74
|
|
|
74
75
|
/* Only "no data yet" is held back; a real reading is always full strength. */
|
|
@@ -21,12 +21,12 @@ export default { inheritAttrs: false }
|
|
|
21
21
|
* paced on its own media clock, so a clip whose last frame does not match
|
|
22
22
|
* its first still loops without a visible cut.
|
|
23
23
|
* - Speed (`rate`) and a darkening veil (`dim`) for text laid over it.
|
|
24
|
-
* - Pausing where motion is unwanted: `paused`, a hidden tab,
|
|
25
|
-
* system's reduced-motion setting, which shows the first frame of the
|
|
24
|
+
* - Pausing where motion is unwanted: `paused`, a hidden tab, scrolled off
|
|
25
|
+
* screen, and the system's reduced-motion setting, which shows the first frame of the
|
|
26
26
|
* stretch instead (`playWithReducedMotion` overrides it).
|
|
27
27
|
* - Easing in and out of a pause (`easePlayback`): the picture slows to a
|
|
28
28
|
* standstill and gathers speed again instead of freezing and lurching. A
|
|
29
|
-
* hidden tab and reduced motion still stop at once.
|
|
29
|
+
* hidden tab, a backdrop scrolled away and reduced motion still stop at once.
|
|
30
30
|
*
|
|
31
31
|
* The second element exists only while there is a seam to blend, so a plain
|
|
32
32
|
* loop decodes one stream. Both play the same `src`: a URL the media element
|
|
@@ -34,6 +34,7 @@ export default { inheritAttrs: false }
|
|
|
34
34
|
*/
|
|
35
35
|
import { computed, onBeforeUnmount, onMounted, ref, watch } from "vue"
|
|
36
36
|
import { easeTravel, prefersReducedMotion } from "../composables/easing"
|
|
37
|
+
import { useInView } from "../composables/useInView"
|
|
37
38
|
import { useMergedAttrs } from "../composables/useMergedClass"
|
|
38
39
|
import { isNativeLoop, planLoop, seamProgress, seamReached } from "./videoBackdrop"
|
|
39
40
|
|
|
@@ -101,7 +102,13 @@ const throttle = ref(1)
|
|
|
101
102
|
const SLOWEST_RATE = 1 / 16
|
|
102
103
|
|
|
103
104
|
const reducedMotion = ref(prefersReducedMotion())
|
|
104
|
-
|
|
105
|
+
/*
|
|
106
|
+
* Unseen: the tab is hidden or the backdrop is off screen. A video decoding
|
|
107
|
+
* frames under the fold spends as much as one in view, and a page of them
|
|
108
|
+
* (a hero, then panels further down) runs them all at once.
|
|
109
|
+
*/
|
|
110
|
+
const { el: root, inView } = useInView()
|
|
111
|
+
const unseen = computed(() => !inView.value)
|
|
105
112
|
|
|
106
113
|
const plan = computed(() =>
|
|
107
114
|
planLoop(duration.value, { start: props.start, end: props.end, crossfade: props.crossfade }),
|
|
@@ -109,7 +116,7 @@ const plan = computed(() =>
|
|
|
109
116
|
const native = computed(() => isNativeLoop(plan.value, duration.value))
|
|
110
117
|
const blended = computed(() => plan.value.fade > 0)
|
|
111
118
|
const still = computed(() => reducedMotion.value && !props.playWithReducedMotion)
|
|
112
|
-
const playing = computed(() => ready.value && !props.paused && !
|
|
119
|
+
const playing = computed(() => ready.value && !props.paused && !unseen.value && !still.value)
|
|
113
120
|
|
|
114
121
|
function element(index: 0 | 1) {
|
|
115
122
|
return index === 0 ? first.value : second.value
|
|
@@ -253,8 +260,8 @@ function sync() {
|
|
|
253
260
|
rampTo(1, easing)
|
|
254
261
|
return
|
|
255
262
|
}
|
|
256
|
-
// Nobody
|
|
257
|
-
if (!running.value ||
|
|
263
|
+
// Nobody watches a hidden tab or a backdrop off screen, and a still is asked for outright: all stop at once.
|
|
264
|
+
if (!running.value || unseen.value || still.value || !easing) {
|
|
258
265
|
rampTo(throttle.value, 0)
|
|
259
266
|
stopElements()
|
|
260
267
|
return
|
|
@@ -301,23 +308,18 @@ watch(
|
|
|
301
308
|
function onMotionChange(event: MediaQueryListEvent) {
|
|
302
309
|
reducedMotion.value = event.matches
|
|
303
310
|
}
|
|
304
|
-
function onVisibility() {
|
|
305
|
-
pageHidden.value = document.hidden
|
|
306
|
-
}
|
|
307
311
|
let motionQuery: MediaQueryList | null = null
|
|
308
312
|
|
|
309
313
|
onMounted(() => {
|
|
310
314
|
applyRate()
|
|
311
315
|
motionQuery = window.matchMedia("(prefers-reduced-motion: reduce)")
|
|
312
316
|
motionQuery.addEventListener("change", onMotionChange)
|
|
313
|
-
document.addEventListener("visibilitychange", onVisibility)
|
|
314
317
|
})
|
|
315
318
|
|
|
316
319
|
onBeforeUnmount(() => {
|
|
317
320
|
if (frame) cancelAnimationFrame(frame)
|
|
318
321
|
if (ramp) cancelAnimationFrame(ramp)
|
|
319
322
|
motionQuery?.removeEventListener("change", onMotionChange)
|
|
320
|
-
document.removeEventListener("visibilitychange", onVisibility)
|
|
321
323
|
})
|
|
322
324
|
|
|
323
325
|
function layerStyle(index: 0 | 1) {
|
|
@@ -339,7 +341,7 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
|
|
|
339
341
|
</script>
|
|
340
342
|
|
|
341
343
|
<template>
|
|
342
|
-
<div :class="rootClass" aria-hidden="true" v-bind="rest">
|
|
344
|
+
<div ref="root" :class="rootClass" aria-hidden="true" v-bind="rest">
|
|
343
345
|
<!-- Under the video, which fades in over it: removing a still laid on top
|
|
344
346
|
would flash the page between the two. -->
|
|
345
347
|
<img v-if="poster" class="absolute inset-0 size-full" :style="{ objectFit: fit }" :src="poster" alt="" />
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { LpOptionBase } from "./options"
|
|
3
|
+
import LpIcon from "./LpIcon.vue"
|
|
4
|
+
|
|
5
|
+
defineProps<{ option: LpOptionBase<string | number> }>()
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<template>
|
|
9
|
+
<span class="flex min-w-0 items-center gap-2.5">
|
|
10
|
+
<img v-if="option.image" :src="option.image" alt="" class="size-6 shrink-0 rounded-full object-cover" />
|
|
11
|
+
<LpIcon v-else-if="option.icon" :name="option.icon" :size="16" class="shrink-0 text-muted" />
|
|
12
|
+
<span class="flex min-w-0 flex-col">
|
|
13
|
+
<span class="truncate">{{ option.label ?? option.value }}</span>
|
|
14
|
+
<span v-if="option.description" class="truncate text-xs text-muted">{{ option.description }}</span>
|
|
15
|
+
</span>
|
|
16
|
+
</span>
|
|
17
|
+
</template>
|