@leavepulse/ui 0.69.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.js +107 -138
- 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/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 +143 -154
- 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 +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 +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/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
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
export default { inheritAttrs: false }
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<script setup lang="ts">
|
|
6
|
+
/*
|
|
7
|
+
* LpMagnetic — leans what it wraps toward a nearby pointer and lets it spring
|
|
8
|
+
* back when the pointer leaves.
|
|
9
|
+
*
|
|
10
|
+
* <LpMagnetic><LpButton size="lg">Play</LpButton></LpMagnetic>
|
|
11
|
+
*
|
|
12
|
+
* For the one or two primary actions of a screen (the launcher's Play): the
|
|
13
|
+
* button meets the cursor a little way, which makes it feel like the obvious
|
|
14
|
+
* target. On every button it turns a toolbar into jelly, so keep it rare.
|
|
15
|
+
*
|
|
16
|
+
* The field reaches `reach` px past the element's edge. The position is read
|
|
17
|
+
* once per animation frame from a single listener on its window
|
|
18
|
+
* (usePointerFrame) and written to the `translate` property directly, so
|
|
19
|
+
* nothing re-renders. Mouse only; reduced
|
|
20
|
+
* motion leaves the element still. Layout is untouched: the wrapper keeps its
|
|
21
|
+
* place and only its paint moves.
|
|
22
|
+
*/
|
|
23
|
+
import { onBeforeUnmount, onMounted, ref } from "vue"
|
|
24
|
+
import { useMergedAttrs } from "../composables/useMergedClass"
|
|
25
|
+
import { usePointerFrame } from "../composables/usePointerFrame"
|
|
26
|
+
import { magneticOffset } from "./dock"
|
|
27
|
+
|
|
28
|
+
const props = withDefaults(
|
|
29
|
+
defineProps<{
|
|
30
|
+
/** How far past the element's edge, in px, the pull is felt. */
|
|
31
|
+
reach?: number
|
|
32
|
+
/** Fraction of the pointer's distance the element travels, 0–1. Small is better. */
|
|
33
|
+
strength?: number
|
|
34
|
+
/** Keep the wrapper, turn the pull off. */
|
|
35
|
+
disabled?: boolean
|
|
36
|
+
}>(),
|
|
37
|
+
{ reach: 60, strength: 0.25, disabled: false },
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
const { class: classes, attrs: rest } = useMergedAttrs(() => "inline-block")
|
|
41
|
+
|
|
42
|
+
const el = ref<HTMLElement | null>(null)
|
|
43
|
+
let held = false
|
|
44
|
+
|
|
45
|
+
function paint(lastX: number, lastY: number) {
|
|
46
|
+
const node = el.value
|
|
47
|
+
if (!node) return
|
|
48
|
+
const rect = node.getBoundingClientRect()
|
|
49
|
+
const dx = lastX - (rect.left + rect.width / 2)
|
|
50
|
+
const dy = lastY - (rect.top + rect.height / 2)
|
|
51
|
+
// The field is measured from the edge, so a wide button pulls from as far
|
|
52
|
+
// away along its length as a square one does.
|
|
53
|
+
const reach = props.reach + Math.max(rect.width, rect.height) / 2
|
|
54
|
+
const { x, y } = props.disabled ? { x: 0, y: 0 } : magneticOffset(dx, dy, reach, props.strength)
|
|
55
|
+
const pulling = x !== 0 || y !== 0
|
|
56
|
+
if (!pulling && !held) return
|
|
57
|
+
held = pulling
|
|
58
|
+
// Following: short and direct. Letting go: the settle curve, whose slight
|
|
59
|
+
// overshoot is the spring back.
|
|
60
|
+
node.style.transition = pulling
|
|
61
|
+
? "translate 120ms ease-out"
|
|
62
|
+
: "translate var(--duration-slow) var(--ease-settle)"
|
|
63
|
+
node.style.translate = pulling ? `${x.toFixed(1)}px ${y.toFixed(1)}px` : ""
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// `disabled` is not a dropped move here: the paint turns the pull off, so an
|
|
67
|
+
// element held when it is disabled still springs back.
|
|
68
|
+
const pointer = usePointerFrame({ paint })
|
|
69
|
+
const onMove = (event: PointerEvent) => void pointer.move(event)
|
|
70
|
+
|
|
71
|
+
// The pointer leaving the window sends no further moves, so the element would
|
|
72
|
+
// stay leaning toward a cursor that is gone.
|
|
73
|
+
function onOut(event: PointerEvent) {
|
|
74
|
+
if (event.relatedTarget || !held) return
|
|
75
|
+
pointer.moveTo(Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// The window the element actually lives in: inside LpFrame that is the
|
|
79
|
+
// frame's, and the pointer events over it never reach the page's own window.
|
|
80
|
+
let host: Window | null = null
|
|
81
|
+
|
|
82
|
+
onMounted(() => {
|
|
83
|
+
host = el.value?.ownerDocument.defaultView ?? window
|
|
84
|
+
host.addEventListener("pointermove", onMove, { passive: true })
|
|
85
|
+
host.addEventListener("pointerout", onOut, { passive: true })
|
|
86
|
+
})
|
|
87
|
+
onBeforeUnmount(() => {
|
|
88
|
+
host?.removeEventListener("pointermove", onMove)
|
|
89
|
+
host?.removeEventListener("pointerout", onOut)
|
|
90
|
+
})
|
|
91
|
+
</script>
|
|
92
|
+
|
|
93
|
+
<template>
|
|
94
|
+
<div ref="el" :class="classes" v-bind="rest">
|
|
95
|
+
<slot />
|
|
96
|
+
</div>
|
|
97
|
+
</template>
|
|
@@ -20,12 +20,14 @@ export default { inheritAttrs: false }
|
|
|
20
20
|
* layer first and swaps the tile pyramid only once the animation lands, which
|
|
21
21
|
* is how the zoom reads as continuous instead of as a hard cut between levels.
|
|
22
22
|
*/
|
|
23
|
-
import { computed, onBeforeUnmount,
|
|
23
|
+
import { computed, onBeforeUnmount, ref, watch } from "vue"
|
|
24
24
|
import { prefersReducedMotion } from "../composables/easing"
|
|
25
25
|
import { type LatLon, OSM_TILES, type TileSource, project, tileUrl, unproject } from "./address"
|
|
26
26
|
import LpIcon from "./LpIcon.vue"
|
|
27
|
+
import LpLoader from "./LpLoader.vue"
|
|
27
28
|
import { useMergedAttrs } from "../composables/useMergedClass"
|
|
28
29
|
import { useLabels } from "../composables/useLpConfig"
|
|
30
|
+
import { useResizeObserver } from "../composables/useResizeObserver"
|
|
29
31
|
|
|
30
32
|
const props = withDefaults(
|
|
31
33
|
defineProps<{
|
|
@@ -538,26 +540,19 @@ watch(
|
|
|
538
540
|
},
|
|
539
541
|
)
|
|
540
542
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
if (!
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
return
|
|
552
|
-
}
|
|
553
|
-
reanchor()
|
|
554
|
-
refreshTiles()
|
|
555
|
-
})
|
|
556
|
-
observer.observe(el)
|
|
543
|
+
useResizeObserver(viewport, (entry) => {
|
|
544
|
+
if (!entry) return
|
|
545
|
+
viewWidth.value = entry.contentRect.width
|
|
546
|
+
viewHeight.value = entry.contentRect.height
|
|
547
|
+
if (!layers.value.length) {
|
|
548
|
+
pushLayer()
|
|
549
|
+
return
|
|
550
|
+
}
|
|
551
|
+
reanchor()
|
|
552
|
+
refreshTiles()
|
|
557
553
|
})
|
|
558
554
|
|
|
559
555
|
onBeforeUnmount(() => {
|
|
560
|
-
observer?.disconnect()
|
|
561
556
|
clearTimeout(zoomTimer)
|
|
562
557
|
clearTimeout(pruneTimer)
|
|
563
558
|
stopGlide()
|
|
@@ -672,21 +667,24 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
|
|
|
672
667
|
:disabled="disabled || locating"
|
|
673
668
|
:title="text.locate"
|
|
674
669
|
:aria-label="text.locate"
|
|
670
|
+
:aria-busy="locating || undefined"
|
|
675
671
|
@click="locate"
|
|
676
672
|
>
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
/>
|
|
673
|
+
<!-- At once, since it takes the crosshair's place; silent, since the
|
|
674
|
+
button's aria-busy already says it. -->
|
|
675
|
+
<LpLoader v-if="locating" size="inline" :delay="0" aria-hidden="true" class="text-[16px]" />
|
|
676
|
+
<LpIcon v-else name="lucide:crosshair" :size="16" />
|
|
682
677
|
</button>
|
|
683
678
|
</div>
|
|
684
679
|
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
680
|
+
<!-- Driven by `active` so cached tiles show nothing and a pan does not
|
|
681
|
+
blink it. Silent: tiles load on every pan and zoom, and announcing
|
|
682
|
+
each batch would only be noise. -->
|
|
683
|
+
<LpLoader
|
|
684
|
+
:active="loadingTiles"
|
|
685
|
+
size="inline"
|
|
686
|
+
aria-hidden="true"
|
|
687
|
+
class="pointer-events-none absolute left-2 top-2 text-[16px] text-white/70 drop-shadow-[0_1px_2px_rgba(0,0,0,0.6)]"
|
|
690
688
|
/>
|
|
691
689
|
|
|
692
690
|
<p
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
export default { inheritAttrs: false }
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<script setup lang="ts" generic="T">
|
|
6
|
+
/*
|
|
7
|
+
* LpMasonry — items of different heights packed into columns without the
|
|
8
|
+
* ragged gaps a grid leaves: memo cards, screenshots, mod tiles.
|
|
9
|
+
*
|
|
10
|
+
* <LpMasonry :items="memos" item-key="id" :min-column-width="240">
|
|
11
|
+
* <template #default="{ item }"><LpCard>{{ item.text }}</LpCard></template>
|
|
12
|
+
* </LpMasonry>
|
|
13
|
+
*
|
|
14
|
+
* Why positioned, not CSS columns: `column-count` fills column by column, so
|
|
15
|
+
* the first items run down the left edge and adding one item reflows
|
|
16
|
+
* everything. Here each item goes, in order, into the shortest column, so the
|
|
17
|
+
* newest content stays at the top and an appended item leaves the rest alone.
|
|
18
|
+
*
|
|
19
|
+
* Every item is measured (one ResizeObserver for all of them) and placed with
|
|
20
|
+
* the `translate` property, so a change of column count, an item growing, or one being
|
|
21
|
+
* added or removed makes the others glide to their new places rather than
|
|
22
|
+
* jump; the container's height eases along. Items arrive with a short
|
|
23
|
+
* staggered entrance the first time the block is seen (useReveal), and later
|
|
24
|
+
* additions fade in where they land. Reduced motion places everything at once.
|
|
25
|
+
*
|
|
26
|
+
* DOM order is the items' order, which is also the reading order for
|
|
27
|
+
* keyboard and screen readers.
|
|
28
|
+
*/
|
|
29
|
+
import { computed, onBeforeUnmount, onMounted, reactive, ref, watch } from "vue"
|
|
30
|
+
import { easingToken, prefersReducedMotion } from "../composables/easing"
|
|
31
|
+
import { useMergedAttrs } from "../composables/useMergedClass"
|
|
32
|
+
import { useReveal } from "../composables/useReveal"
|
|
33
|
+
import { masonryColumnCount, placeMasonry } from "./masonry"
|
|
34
|
+
import { staggerDelay } from "./reveal"
|
|
35
|
+
|
|
36
|
+
const props = withDefaults(
|
|
37
|
+
defineProps<{
|
|
38
|
+
items: T[]
|
|
39
|
+
/** Field (or function) giving each item a stable identity, so it keeps its element across changes. */
|
|
40
|
+
itemKey?: keyof T | ((item: T, index: number) => string | number)
|
|
41
|
+
/**
|
|
42
|
+
* Fixed column count, or a table of minimum container widths to counts
|
|
43
|
+
* (`{ 0: 1, 560: 2, 900: 3 }`). Omit to fit as many `minColumnWidth`
|
|
44
|
+
* columns as the container allows — the right default, because a masonry
|
|
45
|
+
* usually lives in a panel whose width the viewport does not decide.
|
|
46
|
+
*/
|
|
47
|
+
columns?: number | Record<number, number>
|
|
48
|
+
/** Narrowest a column may get when the count is derived from the width. */
|
|
49
|
+
minColumnWidth?: number
|
|
50
|
+
/** Upper bound for the derived count. */
|
|
51
|
+
maxColumns?: number
|
|
52
|
+
/** Space between items, in px, both ways. */
|
|
53
|
+
gap?: number
|
|
54
|
+
/** Play the entrance when the block is first seen. Off shows it as is. */
|
|
55
|
+
entrance?: boolean
|
|
56
|
+
}>(),
|
|
57
|
+
{ minColumnWidth: 240, gap: 16, entrance: true },
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
defineSlots<{
|
|
61
|
+
default?(props: { item: T; index: number }): unknown
|
|
62
|
+
}>()
|
|
63
|
+
|
|
64
|
+
const { class: classes, attrs: rest } = useMergedAttrs(
|
|
65
|
+
() => "relative w-full transition-[height] duration-(--duration-slow) ease-(--ease-emphasized)",
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
function keyOf(item: T, index: number): string | number {
|
|
69
|
+
const key = props.itemKey
|
|
70
|
+
if (typeof key === "function") return key(item, index)
|
|
71
|
+
if (key != null) return item[key] as string | number
|
|
72
|
+
return index
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const keys = computed(() => props.items.map((item, index) => keyOf(item, index)))
|
|
76
|
+
|
|
77
|
+
// ── measuring ─────────────────────────────────────────────
|
|
78
|
+
|
|
79
|
+
const root = ref<HTMLElement | null>(null)
|
|
80
|
+
const width = ref(0)
|
|
81
|
+
const heights = reactive(new Map<string | number, number>())
|
|
82
|
+
const elements = new Map<string | number, HTMLElement>()
|
|
83
|
+
const keyByElement = new WeakMap<Element, string | number>()
|
|
84
|
+
|
|
85
|
+
let observer: ResizeObserver | null = null
|
|
86
|
+
|
|
87
|
+
function heightOf(entry: ResizeObserverEntry): number {
|
|
88
|
+
const box = entry.borderBoxSize?.[0]
|
|
89
|
+
return box ? box.blockSize : (entry.target as HTMLElement).offsetHeight
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function setItem(key: string | number, el: unknown) {
|
|
93
|
+
const previous = elements.get(key)
|
|
94
|
+
if (el instanceof HTMLElement) {
|
|
95
|
+
if (previous === el) return
|
|
96
|
+
if (previous) observer?.unobserve(previous)
|
|
97
|
+
elements.set(key, el)
|
|
98
|
+
keyByElement.set(el, key)
|
|
99
|
+
heights.set(key, el.offsetHeight)
|
|
100
|
+
observer?.observe(el)
|
|
101
|
+
} else if (previous && !keys.value.includes(key)) {
|
|
102
|
+
// Gone from the items (its element may still be fading out): stop
|
|
103
|
+
// measuring it. A re-added key gets a fresh element and a fresh entry.
|
|
104
|
+
observer?.unobserve(previous)
|
|
105
|
+
elements.delete(key)
|
|
106
|
+
heights.delete(key)
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
onMounted(() => {
|
|
111
|
+
if (typeof ResizeObserver === "undefined") {
|
|
112
|
+
width.value = root.value?.clientWidth ?? 0
|
|
113
|
+
return
|
|
114
|
+
}
|
|
115
|
+
observer = new ResizeObserver((entries) => {
|
|
116
|
+
for (const entry of entries) {
|
|
117
|
+
if (entry.target === root.value) {
|
|
118
|
+
width.value = entry.contentRect.width
|
|
119
|
+
continue
|
|
120
|
+
}
|
|
121
|
+
const key = keyByElement.get(entry.target)
|
|
122
|
+
if (key !== undefined) heights.set(key, heightOf(entry))
|
|
123
|
+
}
|
|
124
|
+
})
|
|
125
|
+
if (root.value) {
|
|
126
|
+
width.value = root.value.clientWidth
|
|
127
|
+
observer.observe(root.value)
|
|
128
|
+
}
|
|
129
|
+
for (const el of elements.values()) observer.observe(el)
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
onBeforeUnmount(() => observer?.disconnect())
|
|
133
|
+
|
|
134
|
+
// ── layout ────────────────────────────────────────────────
|
|
135
|
+
|
|
136
|
+
const count = computed(() =>
|
|
137
|
+
masonryColumnCount(width.value, {
|
|
138
|
+
columns: props.columns,
|
|
139
|
+
minColumnWidth: props.minColumnWidth,
|
|
140
|
+
maxColumns: props.maxColumns,
|
|
141
|
+
gap: props.gap,
|
|
142
|
+
}),
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
const layout = computed(() =>
|
|
146
|
+
placeMasonry(
|
|
147
|
+
keys.value.map((key) => heights.get(key) ?? 0),
|
|
148
|
+
count.value,
|
|
149
|
+
width.value,
|
|
150
|
+
props.gap,
|
|
151
|
+
),
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
const position = computed(() => {
|
|
155
|
+
const map = new Map<string | number, { x: number; y: number }>()
|
|
156
|
+
keys.value.forEach((key, index) => map.set(key, { x: layout.value.x[index]!, y: layout.value.y[index]! }))
|
|
157
|
+
return map
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
// An item glides only once it has been placed: a new one must appear where it
|
|
161
|
+
// belongs, not fly in from the top-left corner where it was first measured.
|
|
162
|
+
const placed = reactive(new Set<string | number>())
|
|
163
|
+
const ready = computed(() => width.value > 0)
|
|
164
|
+
|
|
165
|
+
watch(
|
|
166
|
+
[layout, ready],
|
|
167
|
+
() => {
|
|
168
|
+
if (!ready.value) return
|
|
169
|
+
requestAnimationFrame(() => {
|
|
170
|
+
for (const key of keys.value) placed.add(key)
|
|
171
|
+
for (const key of placed) if (!keys.value.includes(key)) placed.delete(key)
|
|
172
|
+
})
|
|
173
|
+
},
|
|
174
|
+
{ flush: "post" },
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
function itemStyle(key: string | number) {
|
|
178
|
+
const at = position.value.get(key)
|
|
179
|
+
return {
|
|
180
|
+
width: `${layout.value.columnWidth}px`,
|
|
181
|
+
// `translate`, not `transform`: TransitionGroup runs its own FLIP on any
|
|
182
|
+
// child whose transition names `transform`, and that FLIP clears the inline
|
|
183
|
+
// transform when it finishes — every item landed in the top-left corner.
|
|
184
|
+
translate: at ? `${at.x}px ${at.y}px` : undefined,
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// ── entrance ──────────────────────────────────────────────
|
|
189
|
+
|
|
190
|
+
const { el: revealEl, revealed } = useReveal({ immediate: () => !props.entrance, threshold: 0.05 })
|
|
191
|
+
watch(root, (node) => (revealEl.value = node))
|
|
192
|
+
|
|
193
|
+
const hidden = computed(() => !ready.value || !revealed.value)
|
|
194
|
+
|
|
195
|
+
watch(
|
|
196
|
+
() => ready.value && revealed.value,
|
|
197
|
+
(go) => {
|
|
198
|
+
if (!go || !props.entrance || prefersReducedMotion()) return
|
|
199
|
+
const easing = easingToken("ease-emphasized")
|
|
200
|
+
// Stagger by the order items are placed in, which reads top to bottom.
|
|
201
|
+
keys.value.forEach((key, index) => {
|
|
202
|
+
const el = elements.get(key)
|
|
203
|
+
el?.firstElementChild?.animate?.(
|
|
204
|
+
[
|
|
205
|
+
{ opacity: 0, transform: "translate3d(0, 12px, 0)" },
|
|
206
|
+
{ opacity: 1, transform: "none" },
|
|
207
|
+
],
|
|
208
|
+
{ duration: 460, delay: staggerDelay(index, 0, 40, 12), easing, fill: "backwards" },
|
|
209
|
+
)
|
|
210
|
+
})
|
|
211
|
+
},
|
|
212
|
+
{ flush: "post" },
|
|
213
|
+
)
|
|
214
|
+
</script>
|
|
215
|
+
|
|
216
|
+
<template>
|
|
217
|
+
<div
|
|
218
|
+
ref="root"
|
|
219
|
+
:class="classes"
|
|
220
|
+
role="list"
|
|
221
|
+
:style="{ height: `${layout.height}px`, opacity: hidden ? 0 : undefined }"
|
|
222
|
+
v-bind="rest"
|
|
223
|
+
>
|
|
224
|
+
<TransitionGroup
|
|
225
|
+
enter-active-class="transition-[opacity,scale] duration-(--duration-slow) ease-(--ease-emphasized)"
|
|
226
|
+
enter-from-class="opacity-0 scale-95"
|
|
227
|
+
leave-active-class="transition-[opacity,scale] duration-(--duration-medium) ease-(--ease-emphasized)"
|
|
228
|
+
leave-to-class="opacity-0 scale-95"
|
|
229
|
+
>
|
|
230
|
+
<div
|
|
231
|
+
v-for="(item, index) in items"
|
|
232
|
+
:key="keys[index]"
|
|
233
|
+
:ref="(el) => setItem(keys[index]!, el)"
|
|
234
|
+
role="listitem"
|
|
235
|
+
class="absolute top-0 left-0"
|
|
236
|
+
:class="placed.has(keys[index]!) && 'transition-[translate] duration-(--duration-slow) ease-(--ease-emphasized)'"
|
|
237
|
+
:style="itemStyle(keys[index]!)"
|
|
238
|
+
>
|
|
239
|
+
<!-- The inner box takes the entrance, so its transform never fights
|
|
240
|
+
the placement transform on the outer one. -->
|
|
241
|
+
<div>
|
|
242
|
+
<slot :item="item" :index="index" />
|
|
243
|
+
</div>
|
|
244
|
+
</div>
|
|
245
|
+
</TransitionGroup>
|
|
246
|
+
</div>
|
|
247
|
+
</template>
|
|
@@ -17,6 +17,7 @@ import { useModalLayer } from "./modalDepth"
|
|
|
17
17
|
import { CLOSE_ICON } from "./dropdown"
|
|
18
18
|
import LpIcon from "./LpIcon.vue"
|
|
19
19
|
import LpScrollArea from "./LpScrollArea.vue"
|
|
20
|
+
import { useOutsideGuard, usePortalTarget } from "../composables/useView"
|
|
20
21
|
|
|
21
22
|
/*
|
|
22
23
|
* Stacking depth, so a dialog opened FROM a dialog sits above the one that
|
|
@@ -122,6 +123,7 @@ function close() {
|
|
|
122
123
|
defineExpose({ close })
|
|
123
124
|
|
|
124
125
|
function onEscape(event: KeyboardEvent) {
|
|
126
|
+
guardOutside(event)
|
|
125
127
|
if (!props.dismissible) event.preventDefault()
|
|
126
128
|
}
|
|
127
129
|
|
|
@@ -136,6 +138,7 @@ function onEscape(event: KeyboardEvent) {
|
|
|
136
138
|
* attribute and every click behaves exactly as before.
|
|
137
139
|
*/
|
|
138
140
|
const onInteractOutside = (event: Event) => {
|
|
141
|
+
guardOutside(event)
|
|
139
142
|
if (!props.dismissible) return event.preventDefault()
|
|
140
143
|
const target = event.target
|
|
141
144
|
if (target instanceof Element && target.closest("[data-lp-modal-aside]")) {
|
|
@@ -285,11 +288,17 @@ watch(
|
|
|
285
288
|
},
|
|
286
289
|
{ flush: "post" },
|
|
287
290
|
)
|
|
291
|
+
|
|
292
|
+
// Overlays open in the window this component renders in (an LpFrame's, inside one).
|
|
293
|
+
const portalTo = usePortalTarget()
|
|
294
|
+
// What happens in another document (the page around a frame, or a frame in
|
|
295
|
+
// the page) is not "outside" for this layer.
|
|
296
|
+
const guardOutside = useOutsideGuard()
|
|
288
297
|
</script>
|
|
289
298
|
|
|
290
299
|
<template>
|
|
291
300
|
<DialogRoot :open="open" @update:open="onOpenChange">
|
|
292
|
-
<DialogPortal>
|
|
301
|
+
<DialogPortal :to="portalTo">
|
|
293
302
|
<DialogOverlay
|
|
294
303
|
:class="{ 'lp-scrim--light': frosted, 'lp-scrim--nested': layer.nested, 'lp-scrim--covered': layer.covered }"
|
|
295
304
|
class="lp-scrim fixed inset-0 data-[state=open]:animate-[fade-in_var(--duration-medium)_var(--ease-emphasized)] data-[state=closed]:animate-[fade-out_120ms_ease]"
|
|
@@ -8,18 +8,21 @@
|
|
|
8
8
|
* `select`. Mirrors the kit convention (cf. LpSidebar): data in, events out,
|
|
9
9
|
* no data fetching inside.
|
|
10
10
|
*/
|
|
11
|
-
import { computed, getCurrentInstance
|
|
11
|
+
import { computed, getCurrentInstance } from "vue"
|
|
12
12
|
import { useLabels } from "../composables/useLpConfig"
|
|
13
|
+
import { useNow } from "../composables/useNow"
|
|
13
14
|
import LpBadge from "./LpBadge.vue"
|
|
14
15
|
import LpButton from "./LpButton.vue"
|
|
15
16
|
import LpContextMenu, { type ContextMenuItemDef } from "./LpContextMenu.vue"
|
|
16
17
|
import LpEmptyState from "./LpEmptyState.vue"
|
|
17
18
|
import LpIcon from "./LpIcon.vue"
|
|
18
19
|
import LpPopover from "./LpPopover.vue"
|
|
20
|
+
import LpRelativeTime from "./LpRelativeTime.vue"
|
|
19
21
|
import LpRollingText from "./LpRollingText.vue"
|
|
20
22
|
import LpScrollArea from "./LpScrollArea.vue"
|
|
21
23
|
import LpSkeleton from "./LpSkeleton.vue"
|
|
22
24
|
import LpShift from "./LpShift.vue"
|
|
25
|
+
import { toneLook, type ToneName } from "./tone"
|
|
23
26
|
|
|
24
27
|
export interface NotificationItem {
|
|
25
28
|
id: string
|
|
@@ -35,7 +38,7 @@ export interface NotificationItem {
|
|
|
35
38
|
* consumers were mapping their own types onto raw palette classes, which is
|
|
36
39
|
* the one place a theme cannot follow them.
|
|
37
40
|
*/
|
|
38
|
-
tone?:
|
|
41
|
+
tone?: ToneName
|
|
39
42
|
/** Optional deep link; the row becomes clickable when set. */
|
|
40
43
|
link?: string
|
|
41
44
|
/** ISO-8601 creation time; rendered as a relative label. */
|
|
@@ -63,10 +66,17 @@ export interface NotificationLabels {
|
|
|
63
66
|
unread?: string
|
|
64
67
|
/** Screen-reader marker on an unread row. */
|
|
65
68
|
unreadItem?: string
|
|
66
|
-
/**
|
|
69
|
+
/**
|
|
70
|
+
* No longer read: times are worded by Intl in the app's locale. Still
|
|
71
|
+
* accepted so existing label objects keep type-checking.
|
|
72
|
+
* @deprecated
|
|
73
|
+
*/
|
|
67
74
|
justNow?: string
|
|
75
|
+
/** @deprecated See `justNow`. */
|
|
68
76
|
minutes?: string
|
|
77
|
+
/** @deprecated See `justNow`. */
|
|
69
78
|
hours?: string
|
|
79
|
+
/** @deprecated See `justNow`. */
|
|
70
80
|
days?: string
|
|
71
81
|
}
|
|
72
82
|
|
|
@@ -85,8 +95,9 @@ const props = withDefaults(
|
|
|
85
95
|
/** Translations for the strings the bell renders itself. */
|
|
86
96
|
labels?: NotificationLabels
|
|
87
97
|
/**
|
|
88
|
-
* Formats `item.createdAt` for display. Defaults to a
|
|
89
|
-
*
|
|
98
|
+
* Formats `item.createdAt` for display. Defaults to a narrow relative time
|
|
99
|
+
* in the app's locale ("now", "5m ago", "3h ago"); pass your own to word
|
|
100
|
+
* it differently.
|
|
90
101
|
*/
|
|
91
102
|
formatTime?: (iso: string) => string
|
|
92
103
|
}>(),
|
|
@@ -109,10 +120,6 @@ const text = useLabels(
|
|
|
109
120
|
ariaLabel: "",
|
|
110
121
|
unread: "{count} unread",
|
|
111
122
|
unreadItem: "Unread",
|
|
112
|
-
justNow: "just now",
|
|
113
|
-
minutes: "{n}m",
|
|
114
|
-
hours: "{n}h",
|
|
115
|
-
days: "{n}d",
|
|
116
123
|
},
|
|
117
124
|
() => props.labels,
|
|
118
125
|
)
|
|
@@ -152,14 +159,6 @@ const buttonLabel = computed(() =>
|
|
|
152
159
|
hasUnread.value ? `${l.value.ariaLabel}, ${l.value.unread.replace("{count}", String(unread.value))}` : l.value.ariaLabel,
|
|
153
160
|
)
|
|
154
161
|
|
|
155
|
-
/** Icon tints for an unread row, keyed by the item's category tone. */
|
|
156
|
-
const TONE_CLASS: Record<string, string> = {
|
|
157
|
-
brand: "bg-brand-soft text-brand",
|
|
158
|
-
action: "bg-action-soft text-action",
|
|
159
|
-
danger: "bg-danger-soft text-danger",
|
|
160
|
-
accent: "bg-accent-soft text-accent",
|
|
161
|
-
muted: "bg-surface-soft text-muted-strong",
|
|
162
|
-
}
|
|
163
162
|
|
|
164
163
|
/*
|
|
165
164
|
* Which optional actions the consumer actually handles. A button for an event
|
|
@@ -199,8 +198,11 @@ const contextMenu = computed<ContextMenuItemDef[]>(() => {
|
|
|
199
198
|
return items
|
|
200
199
|
})
|
|
201
200
|
|
|
201
|
+
// Picking an item goes somewhere (a page, a dialog, a tour step), so the feed
|
|
202
|
+
// steps out of the way: left open it would cover what the item just opened.
|
|
202
203
|
function onSelect(item: NotificationItem) {
|
|
203
204
|
if (!item.read) emit("markRead", item.id)
|
|
205
|
+
open.value = false
|
|
204
206
|
emit("select", item)
|
|
205
207
|
}
|
|
206
208
|
|
|
@@ -226,7 +228,7 @@ function rowMenu(item: NotificationItem): ContextMenuItemDef[] {
|
|
|
226
228
|
actions.push({
|
|
227
229
|
label: l.value.open,
|
|
228
230
|
icon: "lucide:external-link",
|
|
229
|
-
onSelect: () =>
|
|
231
|
+
onSelect: () => onSelect(item),
|
|
230
232
|
})
|
|
231
233
|
}
|
|
232
234
|
actions.push({
|
|
@@ -239,35 +241,14 @@ function rowMenu(item: NotificationItem): ContextMenuItemDef[] {
|
|
|
239
241
|
return actions
|
|
240
242
|
}
|
|
241
243
|
|
|
242
|
-
//
|
|
243
|
-
//
|
|
244
|
-
//
|
|
245
|
-
//
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
onMounted(() => {
|
|
251
|
-
now.value = Date.now()
|
|
252
|
-
clock = setInterval(() => (now.value = Date.now()), 30_000)
|
|
253
|
-
})
|
|
254
|
-
onBeforeUnmount(() => clearInterval(clock))
|
|
255
|
-
|
|
256
|
-
function timeAgo(iso?: string): string {
|
|
257
|
-
if (!iso || now.value === null) return ""
|
|
258
|
-
if (props.formatTime) return props.formatTime(iso)
|
|
259
|
-
const then = new Date(iso).getTime()
|
|
260
|
-
if (Number.isNaN(then)) return ""
|
|
261
|
-
const secs = Math.max(0, Math.round((now.value - then) / 1000))
|
|
262
|
-
const n = (template: string, value: number) => template.replace("{n}", String(value))
|
|
263
|
-
if (secs < 45) return l.value.justNow
|
|
264
|
-
const mins = Math.round(secs / 60)
|
|
265
|
-
if (mins < 60) return n(l.value.minutes, mins)
|
|
266
|
-
const hrs = Math.round(mins / 60)
|
|
267
|
-
if (hrs < 24) return n(l.value.hours, hrs)
|
|
268
|
-
const days = Math.round(hrs / 24)
|
|
269
|
-
if (days < 7) return n(l.value.days, days)
|
|
270
|
-
return new Date(then).toLocaleDateString()
|
|
244
|
+
// A `formatTime` prop takes over the row's time entirely; it is re-asked twice
|
|
245
|
+
// a minute so its "5m" keeps moving. Without one, the row renders
|
|
246
|
+
// LpRelativeTime, which words the time through Intl in the app's locale and
|
|
247
|
+
// wakes only when its own text would change.
|
|
248
|
+
const customNow = useNow(() => !!props.formatTime, { nextIn: () => 30_000 })
|
|
249
|
+
function customTime(iso: string): string {
|
|
250
|
+
void customNow.value
|
|
251
|
+
return props.formatTime ? props.formatTime(iso) : ""
|
|
271
252
|
}
|
|
272
253
|
</script>
|
|
273
254
|
|
|
@@ -371,7 +352,7 @@ function timeAgo(iso?: string): string {
|
|
|
371
352
|
it is still unread. -->
|
|
372
353
|
<span
|
|
373
354
|
class="grid size-7 shrink-0 place-items-center rounded-control"
|
|
374
|
-
:class="item.read ? 'bg-surface-soft text-muted' :
|
|
355
|
+
:class="item.read ? 'bg-surface-soft text-muted' : toneLook(item.tone, 'brand').chip"
|
|
375
356
|
>
|
|
376
357
|
<LpIcon :name="item.icon || 'lucide:bell'" :size="15" />
|
|
377
358
|
</span>
|
|
@@ -387,7 +368,10 @@ function timeAgo(iso?: string): string {
|
|
|
387
368
|
{{ item.body }}
|
|
388
369
|
</span>
|
|
389
370
|
<span v-if="item.createdAt" class="mt-0.5 block text-[11px] text-muted/70">
|
|
390
|
-
{{
|
|
371
|
+
<template v-if="formatTime">{{ customTime(item.createdAt) }}</template>
|
|
372
|
+
<!-- The row is itself a button or link, so the exact date goes
|
|
373
|
+
to the native title rather than a focusable tooltip. -->
|
|
374
|
+
<LpRelativeTime v-else :date="item.createdAt" format="narrow" :tooltip="false" />
|
|
391
375
|
</span>
|
|
392
376
|
</span>
|
|
393
377
|
</component>
|