@leavepulse/ui 0.68.0 → 0.70.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -0
- package/dist/assets/LoaderMark-DxBV2iDJ.css +43 -0
- package/dist/assets/LpActivityLine-B3EwNQEB.css +33 -0
- package/dist/assets/{LpCommandPalette-DxyjhYn_.css → LpCommandPalette-u-zOxKWa.css} +21 -31
- package/dist/assets/LpDock-Cbh0wQUv.css +17 -0
- package/dist/assets/{LpDropzone-Qb8k7cg4.css → LpDropzone-Bb1vBTeU.css} +12 -17
- package/dist/assets/{LpImageEditor-CElPDzpF.css → LpImageEditor-XM5bAziW.css} +6 -6
- package/dist/assets/LpLogViewer-BDNW6P52.css +38 -0
- package/dist/assets/{LpPalettePreview-CJmAKgYW.css → LpPalettePreview-B9VKDrvA.css} +2 -7
- package/dist/assets/LpShinyText-D69cBYDR.css +61 -0
- package/dist/assets/LpStatus-430OGTZY.css +17 -0
- package/dist/assets/LpStepMark-Drvx33Vg.css +10 -0
- package/dist/assets/{LpTable-BPERfJIk.css → LpTable-DHxEQ_-3.css} +19 -19
- package/dist/assets/LpTabs-BJ-nrJuI.css +18 -0
- package/dist/assets/LpTextReveal-DjI1MsDS.css +35 -0
- package/dist/assets/LpTypewriter-CXAm9Nca.css +27 -0
- package/dist/chunks/AttentionDot-DCBf4aWg.js +25 -0
- package/dist/chunks/{ContextMenuItems-B7XFHksm.js → ContextMenuItems-B5uE8Znw.js} +1 -1
- package/dist/chunks/{DropzoneLinkField-CjkrpDqO.js → DropzoneLinkField-Bw8Flkhk.js} +2 -2
- package/dist/chunks/FieldWrapper-BiennROB.js +43 -0
- package/dist/chunks/{LayoutCanvas-DF9CovaK.js → LayoutCanvas-BsJIzhdd.js} +1 -1
- package/dist/chunks/{LayoutNode-D9bIFzk0.js → LayoutNode-DJVhkSGk.js} +6 -8
- package/dist/chunks/LegendSwatch-BhRjrtzv.js +18 -0
- package/dist/chunks/LoaderMark-C1dubiKn.js +85 -0
- package/dist/chunks/{LpActionBar-MPKMu3pz.js → LpActionBar-CzOFar5t.js} +14 -20
- package/dist/chunks/LpActivityLine-CJvzrNpj.js +95 -0
- package/dist/chunks/{LpAddressInput-DG0BTqdH.js → LpAddressInput-CNnLTDZg.js} +7 -7
- package/dist/chunks/LpAlert-C5igj802.js +119 -0
- package/dist/chunks/{LpAppShell-DPh1756q.js → LpAppShell-CEUAB8kK.js} +15 -16
- package/dist/chunks/{LpAutocomplete-Dgn6hw3p.js → LpAutocomplete-D92niDHE.js} +15 -32
- package/dist/chunks/{LpAvatar-Bs0Fb1lC.js → LpAvatar-CLPl-qOF.js} +18 -6
- package/dist/chunks/LpBadge-HOEPBYmi.js +126 -0
- package/dist/chunks/LpBreadcrumbs-DYoPc3P4.js +144 -0
- package/dist/chunks/{LpButton-DNR-YAq5.js → LpButton-CVxBfGjd.js} +12 -4
- package/dist/chunks/{LpCalendar-BLya39Fh.js → LpCalendar-pVL91-Pl.js} +1 -1
- package/dist/chunks/{LpCard-Bf71NXZq.js → LpCard-CqKLnEhl.js} +18 -8
- package/dist/chunks/{LpCheckbox-Da5oZPHo.js → LpCheckbox-DHc2bHDe.js} +9 -6
- package/dist/chunks/{LpCodeBlock-lLbmslfs.js → LpCodeBlock-BGsQhxw8.js} +24 -32
- package/dist/chunks/LpCodeDisplay-CIKKT2iW.js +189 -0
- package/dist/chunks/LpCollapse-CWS9M_lm.js +115 -0
- package/dist/chunks/{LpColorPicker-DtEfBAcK.js → LpColorPicker-DFugXNUi.js} +10 -5
- package/dist/chunks/{LpConfirmDialog-D7s4jakB.js → LpConfirmDialog-CfGCux8m.js} +3 -3
- package/dist/chunks/{LpConfirmHost-DrYI5y1K.js → LpConfirmHost-exB7JmcO.js} +1 -1
- package/dist/chunks/{LpContextMenu-CRnjoqSt.js → LpContextMenu-COwOwRgI.js} +13 -5
- package/dist/chunks/LpCopyButton-DzHjnFs0.js +133 -0
- package/dist/chunks/LpCountdown-Dtq1ihlJ.js +231 -0
- package/dist/chunks/LpDataList-B-5nHfNw.js +120 -0
- package/dist/chunks/LpDatePicker-BUe1VUC0.js +168 -0
- package/dist/chunks/LpDateRangePicker-C_k65vGR.js +126 -0
- package/dist/chunks/{LpDisclosure-6AplYBub.js → LpDisclosure-DOarzlAG.js} +22 -11
- package/dist/chunks/{LpDrawer-Q4SOxM4s.js → LpDrawer-DGNKRsGq.js} +9 -4
- package/dist/chunks/{LpDropdownMenu-DWTt0ooM.js → LpDropdownMenu-CRgrhdAH.js} +10 -5
- package/dist/chunks/LpEditable-DTqLt2lT.js +236 -0
- package/dist/chunks/{LpEmptyState-om1UnFjV.js → LpEmptyState-KTKipws2.js} +1 -1
- package/dist/chunks/{LpFieldNotice-CHuDeLjc.js → LpFieldNotice-CurbNuXI.js} +1 -1
- package/dist/chunks/{LpFileTree-CW24YsVX.js → LpFileTree-DMISXVHC.js} +5 -3
- package/dist/chunks/{LpFileTreeNode-BXhTHaKW.js → LpFileTreeNode-CPXB_Yy3.js} +42 -55
- package/dist/chunks/{LpFormField-DPb47HEm.js → LpFormField-BWwgm1E4.js} +23 -9
- package/dist/chunks/LpFrame-BVQCQLDI.js +155 -0
- package/dist/chunks/LpGauge-Bk8TwJj0.js +204 -0
- package/dist/chunks/LpGlowBorder-B8V-QzIl.js +40 -0
- package/dist/chunks/{LpHintExample-C1eKYdeL.js → LpHintExample-9Py0wc-L.js} +11 -34
- package/dist/chunks/{LpHintLayer-7UOdWQG3.js → LpHintLayer-p4hqzdyA.js} +27 -14
- package/dist/chunks/{LpHints-BUtBp9-w.js → LpHints-CCrhRfy9.js} +3 -3
- package/dist/chunks/LpHoverCard-spGxyw7T.js +130 -0
- package/dist/chunks/{LpIcon-6tSrZ3Zy.js → LpIcon-HJP5xMz4.js} +1 -1
- package/dist/chunks/LpIdenticon-BzdC_qz9.js +63 -0
- package/dist/chunks/{LpInfraNode-Ds_8SZgN.js → LpInfraNode-CUC3t4na.js} +39 -25
- package/dist/chunks/{LpInput-CUyr6PIE.js → LpInput-CDuwODJG.js} +44 -18
- package/dist/chunks/{LpLightbox-B9J8rzsj.js → LpLightbox-XJ0LpTcZ.js} +69 -69
- package/dist/chunks/LpLoader-DjJEX8hL.js +92 -0
- package/dist/chunks/{LpLogViewer-4QFc-sVN.js → LpLogViewer-elZHbj85.js} +225 -129
- package/dist/chunks/LpMagnetic-CtXKLa2Y.js +62 -0
- package/dist/chunks/{LpMapPicker-BTbkFeSG.js → LpMapPicker-BtIl7NOM.js} +34 -31
- package/dist/chunks/LpMasonry--k0571qG.js +185 -0
- package/dist/chunks/{LpMediaGallery-CuPcscx3.js → LpMediaGallery-D5swlmZ_.js} +3 -3
- package/dist/chunks/{LpModal-hk1noDcr.js → LpModal-eBMt2Fqn.js} +8 -3
- package/dist/chunks/{LpModalNav-DQd2keZm.js → LpModalNav-D4Z0wVHR.js} +4 -4
- package/dist/chunks/{LpNotificationBell-X84PJIxD.js → LpNotificationBell-DPZmP5dM.js} +32 -48
- package/dist/chunks/LpNumberField-B9k-h2HE.js +140 -0
- package/dist/chunks/{LpNumberFlow-z4WPZcZu.js → LpNumberFlow-Cfyh033Q.js} +8 -28
- package/dist/chunks/{LpOtpInput-PbeNJ5In.js → LpOtpInput-CeBPsM7D.js} +2 -1
- package/dist/chunks/{LpPagination-Bx-VG4Ag.js → LpPagination-VNCX6pFC.js} +37 -6
- package/dist/chunks/{LpPalettePreview-CFav_7co.js → LpPalettePreview-BNB8T_MY.js} +1 -1
- package/dist/chunks/{LpPasswordInput-CbnXitAS.js → LpPasswordInput-DTV18FIh.js} +20 -20
- package/dist/chunks/{LpPhoneInput-DP69HONS.js → LpPhoneInput-C60tx1tC.js} +12 -7
- package/dist/chunks/{LpPie-yLF9-aDR.js → LpPie-CFuV7pZv.js} +158 -47
- package/dist/chunks/LpPipeline-D81yh_NX.js +329 -0
- package/dist/chunks/{LpPopover-DVnkHaOu.js → LpPopover-BEIcqb9p.js} +8 -3
- package/dist/chunks/{LpProgress-CA86wxXu.js → LpProgress-CE-m5OpD.js} +23 -63
- package/dist/chunks/LpQuota-2Sw_gqcJ.js +162 -0
- package/dist/chunks/{LpRadioGroup-8S5hf8lE.js → LpRadioGroup-CGBr5nIp.js} +1 -1
- package/dist/chunks/{LpRangeCalendar-ByQi-WUz.js → LpRangeCalendar-c5qj7YcC.js} +1 -1
- package/dist/chunks/{LpRangeSlider-C1yF9-nP.js → LpRangeSlider-Dv6lNvHY.js} +6 -2
- package/dist/chunks/LpRelativeTime-CKzVqAo9.js +73 -0
- package/dist/chunks/LpRepeater-D0VjmD6y.js +140 -0
- package/dist/chunks/LpRevealOnScroll-DcQjexLy.js +76 -0
- package/dist/chunks/LpScramble-TDO5Kdou.js +85 -0
- package/dist/chunks/LpSecretField-DMfdJ1cQ.js +307 -0
- package/dist/chunks/{LpSection-BmRXe6ZP.js → LpSection-BW4xJ-Li.js} +1 -1
- package/dist/chunks/{LpSegmented-CW3bFHM4.js → LpSegmented-BO99Sr4m.js} +11 -14
- package/dist/chunks/{LpSelect-BCyDYoih.js → LpSelect-B4f_yRi5.js} +93 -108
- package/dist/chunks/LpShaderBackdrop-Bote0iuy.js +332 -0
- package/dist/chunks/LpShinyText-DX2ajtWq.js +48 -0
- package/dist/chunks/{LpSidebar-DfIiS-lB.js → LpSidebar-D-M0Y_7U.js} +5 -3
- package/dist/chunks/{LpSidebarNav-C5FDNI0t.js → LpSidebarNav-DF-TYxOV.js} +3 -3
- package/dist/chunks/{LpSlider-Cuzmrd7p.js → LpSlider-DuoRpOrH.js} +6 -2
- package/dist/chunks/{LpSparkline-DXT4KrSi.js → LpSparkline-CExIRDb3.js} +32 -27
- package/dist/chunks/LpSpotlight-4F3NeUMY.js +41 -0
- package/dist/chunks/{LpStat-iBMF5QNk.js → LpStat-B2ix1Q7t.js} +38 -35
- package/dist/chunks/LpStatus-C7kx5PKE.js +86 -0
- package/dist/chunks/LpStepMark-DK-5BKAt.js +101 -0
- package/dist/chunks/LpStepper-DRFfdJaq.js +76 -0
- package/dist/chunks/{LpSwap-D82jiecV.js → LpSwap-DzE6M3Mg.js} +1 -1
- package/dist/chunks/LpSwitch-DrzKrZZV.js +112 -0
- package/dist/chunks/{LpTableFilter-CuIbgdW0.js → LpTableFilter-DyvHGbOk.js} +3 -2
- package/dist/chunks/{LpTableOfContents-C_4VBktT.js → LpTableOfContents-rYvo8z5T.js} +34 -21
- package/dist/chunks/{LpTagsInput-DiXrpYeE.js → LpTagsInput-DgpBFRV2.js} +68 -71
- package/dist/chunks/LpTextReveal-CtAnOUkp.js +140 -0
- package/dist/chunks/{LpTextarea-xoQd5Lnp.js → LpTextarea-DiWjeVoJ.js} +12 -11
- package/dist/chunks/{LpThemeProvider-CQ2jC9TA.js → LpThemeProvider-DcbfOxsU.js} +1 -1
- package/dist/chunks/LpThemeStudio-DguwHdGt.js +416 -0
- package/dist/chunks/LpThemeStudioSection-BwhqYDLf.js +20 -0
- package/dist/chunks/LpThemeSwitcher-D5uz0MhK.js +278 -0
- package/dist/chunks/{LpTimeField-MFgAsNc5.js → LpTimeField-BFQVf_PW.js} +13 -5
- package/dist/chunks/{LpToaster-C4zE9zB7.js → LpToaster-Wv9ksj4q.js} +49 -82
- package/dist/chunks/{LpTooltip-suFCM34F.js → LpTooltip-Cz8SQwRt.js} +8 -3
- package/dist/chunks/{LpTopologyCanvas-6ozNrQKh.js → LpTopologyCanvas-ZhKthfgz.js} +1 -1
- package/dist/chunks/{LpTour-BUp3Jt2e.js → LpTour-NfRJNEIP.js} +24 -18
- package/dist/chunks/LpTruncate-D_5Pfv5B.js +112 -0
- package/dist/chunks/LpTypewriter-BCL_a6wE.js +159 -0
- package/dist/chunks/{LpUptimeBar-B6kHw4Cj.js → LpUptimeBar-DWegV2p6.js} +9 -8
- package/dist/chunks/{LpVideoBackdrop-qWRYBOTQ.js → LpVideoBackdrop-DS1wGv-X.js} +7 -8
- package/dist/chunks/{MenuTitle-obgek0B7.js → MenuTitle-BjQZX8tQ.js} +1 -1
- package/dist/chunks/OptionContent-CmYUUeWj.js +40 -0
- package/dist/chunks/PickerField-CHRS1h7K.js +116 -0
- package/dist/chunks/RevealToggle-C-KzaQGJ.js +65 -0
- package/dist/chunks/StepConnector-37OgEOXA.js +41 -0
- package/dist/chunks/TourCard-BXuVHsfn.js +123 -0
- package/dist/chunks/backdrop-Dkf2vM81.js +59 -0
- package/dist/chunks/{icons-DVhZ_plB.js → icons-4IywzkHk.js} +1 -1
- package/dist/chunks/{useTheme-2qHG8NEU.js → useTheme-BOV_-AiY.js} +9 -65
- package/dist/component-names.d.ts +1 -1
- package/dist/components/AttentionDot.vue.d.ts +9 -0
- package/dist/components/AttentionDot.vue.js +4 -0
- package/dist/components/ContextMenuItems.vue.js +1 -1
- package/dist/components/DropzoneLinkField.vue.js +1 -1
- package/dist/components/FieldWrapper.vue.d.ts +25 -0
- package/dist/components/FieldWrapper.vue.js +4 -0
- package/dist/components/LayoutCanvas.vue.js +1 -1
- package/dist/components/LayoutNode.vue.d.ts +4 -4
- package/dist/components/LayoutNode.vue.js +1 -1
- package/dist/components/LegendSwatch.vue.d.ts +6 -0
- package/dist/components/LegendSwatch.vue.js +4 -0
- package/dist/components/LoaderMark.vue.d.ts +12 -0
- package/dist/components/LoaderMark.vue.js +4 -0
- package/dist/components/LpActionBar.vue.js +1 -1
- package/dist/components/LpActivityLine.vue.d.ts +58 -0
- package/dist/components/LpActivityLine.vue.js +4 -0
- package/dist/components/LpAddressInput.vue.js +1 -1
- package/dist/components/LpAlert.vue.d.ts +2 -2
- package/dist/components/LpAlert.vue.js +1 -1
- package/dist/components/LpAppShell.vue.d.ts +8 -7
- package/dist/components/LpAppShell.vue.js +1 -1
- package/dist/components/LpAutocomplete.vue.js +1 -1
- package/dist/components/LpAvatar.vue.d.ts +16 -0
- package/dist/components/LpAvatar.vue.js +1 -1
- package/dist/components/LpBadge.vue.d.ts +19 -5
- package/dist/components/LpBadge.vue.js +1 -1
- package/dist/components/LpBreadcrumbs.vue.js +1 -1
- package/dist/components/LpButton.vue.d.ts +2 -2
- package/dist/components/LpButton.vue.js +1 -1
- package/dist/components/LpCalendar.vue.js +1 -1
- package/dist/components/LpCard.vue.d.ts +24 -0
- package/dist/components/LpCard.vue.js +1 -1
- package/dist/components/LpChart.vue.d.ts +10 -0
- package/dist/components/LpChart.vue.js +122 -142
- package/dist/components/LpCheckbox.vue.d.ts +2 -2
- package/dist/components/LpCheckbox.vue.js +1 -1
- package/dist/components/LpCodeBlock.vue.js +1 -1
- package/dist/components/LpCodeDisplay.vue.d.ts +89 -0
- package/dist/components/LpCodeDisplay.vue.js +4 -0
- package/dist/components/LpCollapse.vue.d.ts +58 -0
- package/dist/components/LpCollapse.vue.js +4 -0
- package/dist/components/LpColorPicker.vue.d.ts +2 -2
- package/dist/components/LpColorPicker.vue.js +1 -1
- package/dist/components/LpCommandPalette.vue.js +34 -23
- package/dist/components/LpConfirmDialog.vue.js +1 -1
- package/dist/components/LpConfirmHost.vue.js +1 -1
- package/dist/components/LpContextMenu.vue.js +1 -1
- package/dist/components/LpCopyButton.vue.d.ts +82 -0
- package/dist/components/LpCopyButton.vue.js +4 -0
- package/dist/components/LpCountdown.vue.d.ts +100 -0
- package/dist/components/LpCountdown.vue.js +4 -0
- package/dist/components/LpDataList.vue.d.ts +66 -0
- package/dist/components/LpDataList.vue.js +4 -0
- package/dist/components/LpDatePicker.vue.d.ts +1 -1
- package/dist/components/LpDatePicker.vue.js +1 -1
- package/dist/components/LpDateRangePicker.vue.d.ts +1 -1
- package/dist/components/LpDateRangePicker.vue.js +1 -1
- package/dist/components/LpDisclosure.vue.js +1 -1
- package/dist/components/LpDock.vue.d.ts +74 -0
- package/dist/components/LpDock.vue.js +204 -0
- package/dist/components/LpDrawer.vue.js +1 -1
- package/dist/components/LpDropdownMenu.vue.js +1 -1
- package/dist/components/LpDropzone.vue.d.ts +8 -1
- package/dist/components/LpDropzone.vue.js +36 -15
- package/dist/components/LpEditable.vue.d.ts +85 -0
- package/dist/components/LpEditable.vue.js +4 -0
- package/dist/components/LpEmptyState.vue.js +1 -1
- package/dist/components/LpFieldNotice.vue.js +1 -1
- package/dist/components/LpFileTree.vue.js +1 -1
- package/dist/components/LpFileTreeNode.vue.js +1 -1
- package/dist/components/LpFormField.vue.js +1 -1
- package/dist/components/LpFrame.vue.d.ts +22 -0
- package/dist/components/LpFrame.vue.js +4 -0
- package/dist/components/LpGauge.vue.d.ts +116 -0
- package/dist/components/LpGauge.vue.js +4 -0
- package/dist/components/LpGlowBorder.vue.d.ts +47 -0
- package/dist/components/LpGlowBorder.vue.js +4 -0
- package/dist/components/LpHintExample.vue.d.ts +2 -2
- package/dist/components/LpHintExample.vue.js +1 -1
- package/dist/components/LpHintLayer.vue.js +1 -1
- package/dist/components/LpHints.vue.js +1 -1
- package/dist/components/LpHoverCard.vue.d.ts +60 -0
- package/dist/components/LpHoverCard.vue.js +4 -0
- package/dist/components/LpIcon.vue.js +1 -1
- package/dist/components/LpIdenticon.vue.d.ts +37 -0
- package/dist/components/LpIdenticon.vue.js +4 -0
- package/dist/components/LpImageEditor.vue.js +13 -19
- package/dist/components/LpInfraNode.vue.js +1 -1
- package/dist/components/LpInput.vue.d.ts +10 -0
- package/dist/components/LpInput.vue.js +1 -1
- package/dist/components/LpLightbox.vue.js +1 -1
- package/dist/components/LpLoader.vue.d.ts +106 -0
- package/dist/components/LpLoader.vue.js +4 -0
- package/dist/components/LpLogViewer.vue.js +1 -1
- package/dist/components/LpMagnetic.vue.d.ts +28 -0
- package/dist/components/LpMagnetic.vue.js +4 -0
- package/dist/components/LpMapPicker.vue.js +1 -1
- package/dist/components/LpMasonry.vue.d.ts +42 -0
- package/dist/components/LpMasonry.vue.js +4 -0
- package/dist/components/LpMediaGallery.vue.js +1 -1
- package/dist/components/LpModal.vue.js +1 -1
- package/dist/components/LpModalNav.vue.js +1 -1
- package/dist/components/LpNotificationBell.vue.d.ts +15 -6
- package/dist/components/LpNotificationBell.vue.js +1 -1
- package/dist/components/LpNumberField.vue.d.ts +57 -0
- package/dist/components/LpNumberField.vue.js +1 -1
- package/dist/components/LpNumberFlow.vue.js +1 -1
- package/dist/components/LpOtpInput.vue.d.ts +12 -4
- package/dist/components/LpOtpInput.vue.js +1 -1
- package/dist/components/LpPagination.vue.js +1 -1
- package/dist/components/LpPaletteFacts.vue.js +1 -1
- package/dist/components/LpPaletteHeader.vue.js +2 -2
- package/dist/components/LpPalettePreview.vue.js +1 -1
- package/dist/components/LpPaletteStats.vue.js +1 -1
- package/dist/components/LpPasswordInput.vue.d.ts +12 -1
- package/dist/components/LpPasswordInput.vue.js +1 -1
- package/dist/components/LpPhoneInput.vue.js +1 -1
- package/dist/components/LpPie.vue.d.ts +3 -1
- package/dist/components/LpPie.vue.js +1 -1
- package/dist/components/LpPipeline.vue.d.ts +91 -0
- package/dist/components/LpPipeline.vue.js +4 -0
- package/dist/components/LpPopover.vue.d.ts +2 -2
- package/dist/components/LpPopover.vue.js +1 -1
- package/dist/components/LpProgress.vue.d.ts +11 -4
- package/dist/components/LpProgress.vue.js +1 -1
- package/dist/components/LpQuota.vue.d.ts +68 -0
- package/dist/components/LpQuota.vue.js +4 -0
- package/dist/components/LpRadioGroup.vue.js +1 -1
- package/dist/components/LpRangeCalendar.vue.js +1 -1
- package/dist/components/LpRangeSlider.vue.js +1 -1
- package/dist/components/LpRelativeTime.vue.d.ts +41 -0
- package/dist/components/LpRelativeTime.vue.js +4 -0
- package/dist/components/LpRepeater.vue.d.ts +48 -0
- package/dist/components/LpRepeater.vue.js +4 -0
- package/dist/components/LpRevealOnScroll.vue.d.ts +67 -0
- package/dist/components/LpRevealOnScroll.vue.js +4 -0
- package/dist/components/LpRollingText.vue.d.ts +1 -1
- package/dist/components/LpScramble.vue.d.ts +55 -0
- package/dist/components/LpScramble.vue.js +4 -0
- package/dist/components/LpScrollArea.vue.d.ts +1 -1
- package/dist/components/LpSecretField.vue.d.ts +108 -0
- package/dist/components/LpSecretField.vue.js +4 -0
- package/dist/components/LpSection.vue.js +1 -1
- package/dist/components/LpSegmented.vue.js +1 -1
- package/dist/components/LpSelect.vue.d.ts +2 -0
- package/dist/components/LpSelect.vue.js +1 -1
- package/dist/components/LpShaderBackdrop.vue.d.ts +39 -0
- package/dist/components/LpShaderBackdrop.vue.js +4 -0
- package/dist/components/LpShinyText.vue.d.ts +39 -0
- package/dist/components/LpShinyText.vue.js +4 -0
- package/dist/components/LpShortcutsDialog.vue.js +1 -1
- package/dist/components/LpSidebar.vue.js +1 -1
- package/dist/components/LpSidebarNav.vue.js +1 -1
- package/dist/components/LpSlider.vue.js +1 -1
- package/dist/components/LpSparkline.vue.d.ts +4 -3
- package/dist/components/LpSparkline.vue.js +1 -1
- package/dist/components/LpSpotlight.vue.d.ts +37 -0
- package/dist/components/LpSpotlight.vue.js +4 -0
- package/dist/components/LpStat.vue.js +1 -1
- package/dist/components/LpStatus.vue.d.ts +65 -0
- package/dist/components/LpStatus.vue.js +4 -0
- package/dist/components/LpStepMark.vue.d.ts +31 -0
- package/dist/components/LpStepMark.vue.js +4 -0
- package/dist/components/LpStepper.vue.js +1 -1
- package/dist/components/LpSwap.vue.js +1 -1
- package/dist/components/LpSwitch.vue.d.ts +2 -2
- package/dist/components/LpSwitch.vue.js +1 -1
- package/dist/components/LpTable.vue.js +104 -120
- package/dist/components/LpTableFilter.vue.js +1 -1
- package/dist/components/LpTableOfContents.vue.d.ts +6 -1
- package/dist/components/LpTableOfContents.vue.js +1 -1
- package/dist/components/LpTabs.vue.d.ts +5 -5
- package/dist/components/LpTabs.vue.js +25 -33
- package/dist/components/LpTagsInput.vue.js +1 -1
- package/dist/components/LpTextReveal.vue.d.ts +58 -0
- package/dist/components/LpTextReveal.vue.js +4 -0
- package/dist/components/LpTextarea.vue.js +1 -1
- package/dist/components/LpThemeProvider.vue.js +1 -1
- package/dist/components/LpThemeStudio.vue.d.ts +54 -0
- package/dist/components/LpThemeStudio.vue.js +4 -0
- package/dist/components/LpThemeStudioSection.vue.d.ts +16 -0
- package/dist/components/LpThemeStudioSection.vue.js +4 -0
- package/dist/components/LpThemeSwitcher.vue.d.ts +32 -1
- package/dist/components/LpThemeSwitcher.vue.js +1 -1
- package/dist/components/LpTimeField.vue.d.ts +2 -0
- package/dist/components/LpTimeField.vue.js +1 -1
- package/dist/components/LpToaster.vue.js +1 -1
- package/dist/components/LpTooltip.vue.d.ts +2 -2
- package/dist/components/LpTooltip.vue.js +1 -1
- package/dist/components/LpTopologyCanvas.vue.js +1 -1
- package/dist/components/LpTour.vue.js +1 -1
- package/dist/components/LpTruncate.vue.d.ts +34 -0
- package/dist/components/LpTruncate.vue.js +4 -0
- package/dist/components/LpTypewriter.vue.d.ts +61 -0
- package/dist/components/LpTypewriter.vue.js +4 -0
- package/dist/components/LpUptimeBar.vue.js +1 -1
- package/dist/components/LpVideoBackdrop.vue.js +1 -1
- package/dist/components/MenuTitle.vue.js +1 -1
- package/dist/components/OptionContent.vue.d.ts +7 -0
- package/dist/components/OptionContent.vue.js +4 -0
- package/dist/components/PickerField.vue.d.ts +43 -0
- package/dist/components/PickerField.vue.js +4 -0
- package/dist/components/RevealToggle.vue.d.ts +21 -0
- package/dist/components/RevealToggle.vue.js +4 -0
- package/dist/components/StepConnector.vue.d.ts +19 -0
- package/dist/components/StepConnector.vue.js +4 -0
- package/dist/components/TourCard.vue.js +1 -1
- package/dist/components/badge.d.ts +1 -0
- package/dist/components/badge.js +4 -0
- package/dist/components/chart.d.ts +5 -1
- package/dist/components/chart.js +2 -21
- package/dist/components/dateRange.d.ts +11 -0
- package/dist/components/dateRange.js +12 -0
- package/dist/components/dock.d.ts +19 -0
- package/dist/components/dock.js +16 -0
- package/dist/components/dropdown.d.ts +10 -1
- package/dist/components/dropdown.js +7 -2
- package/dist/components/fieldText.d.ts +38 -0
- package/dist/components/fieldText.js +53 -0
- package/dist/components/fileTree.d.ts +7 -3
- package/dist/components/fileTree.js +12 -18
- package/dist/components/format.d.ts +41 -0
- package/dist/components/format.js +67 -0
- package/dist/components/identicon.d.ts +38 -0
- package/dist/components/identicon.js +85 -0
- package/dist/components/masonry.d.ts +32 -0
- package/dist/components/masonry.js +40 -0
- package/dist/components/menuWhen.js +1 -1
- package/dist/components/meter.d.ts +64 -0
- package/dist/components/meter.js +53 -0
- package/dist/components/otp.d.ts +1 -1
- package/dist/components/otp.js +7 -2
- package/dist/components/pipeline.d.ts +55 -0
- package/dist/components/pipeline.js +51 -0
- package/dist/components/quota.d.ts +57 -0
- package/dist/components/quota.js +40 -0
- package/dist/components/relativeTime.d.ts +24 -0
- package/dist/components/relativeTime.js +56 -0
- package/dist/components/reveal.d.ts +18 -0
- package/dist/components/reveal.js +32 -0
- package/dist/components/scramble.d.ts +68 -0
- package/dist/components/scramble.js +58 -0
- package/dist/components/shaderBackdrop.d.ts +20 -0
- package/dist/components/shaderBackdrop.js +156 -0
- package/dist/components/slider.d.ts +5 -0
- package/dist/components/slider.js +24 -0
- package/dist/components/slotText.d.ts +2 -0
- package/dist/components/slotText.js +9 -0
- package/dist/components/status.d.ts +14 -0
- package/dist/components/status.js +22 -0
- package/dist/components/tableFacets.d.ts +8 -0
- package/dist/components/tableFacets.js +19 -0
- package/dist/components/textSplit.d.ts +17 -0
- package/dist/components/textSplit.js +24 -0
- package/dist/components/timeSpan.d.ts +78 -0
- package/dist/components/timeSpan.js +85 -0
- package/dist/components/tone.d.ts +43 -0
- package/dist/components/tone.js +82 -0
- package/dist/components/tour.js +3 -2
- package/dist/components/typewriter.d.ts +36 -0
- package/dist/components/typewriter.js +53 -0
- package/dist/components/videoBackdrop.js +5 -6
- package/dist/composables/easing.d.ts +22 -1
- package/dist/composables/easing.js +42 -1
- package/dist/composables/pseudoLocale.d.ts +15 -0
- package/dist/composables/pseudoLocale.js +96 -0
- package/dist/composables/scroll.js +5 -3
- package/dist/composables/useClipboard.d.ts +4 -1
- package/dist/composables/useClipboard.js +12 -2
- package/dist/composables/useField.d.ts +8 -0
- package/dist/composables/useField.js +5 -0
- package/dist/composables/useForm.js +19 -5
- package/dist/composables/useHintSystem.d.ts +4 -0
- package/dist/composables/useHintSystem.js +33 -1
- package/dist/composables/useHints.js +9 -3
- package/dist/composables/useInView.d.ts +11 -0
- package/dist/composables/useInView.js +39 -0
- package/dist/composables/useLoadingGate.d.ts +8 -0
- package/dist/composables/useLoadingGate.js +38 -0
- package/dist/composables/useLpConfig.d.ts +10 -0
- package/dist/composables/useLpConfig.js +11 -1
- package/dist/composables/useMediaQuery.js +3 -1
- package/dist/composables/useNow.d.ts +16 -0
- package/dist/composables/useNow.js +39 -0
- package/dist/composables/usePersisted.js +14 -7
- package/dist/composables/usePillTransition.d.ts +5 -2
- package/dist/composables/usePillTransition.js +4 -3
- package/dist/composables/usePointerFrame.d.ts +18 -0
- package/dist/composables/usePointerFrame.js +31 -0
- package/dist/composables/useReducedMotion.d.ts +2 -0
- package/dist/composables/useReducedMotion.js +7 -0
- package/dist/composables/useRepeater.d.ts +17 -0
- package/dist/composables/useRepeater.js +31 -0
- package/dist/composables/useResizeObserver.d.ts +8 -0
- package/dist/composables/useResizeObserver.js +33 -0
- package/dist/composables/useRevealedValue.d.ts +31 -0
- package/dist/composables/useRevealedValue.js +26 -0
- package/dist/composables/useScramble.d.ts +42 -0
- package/dist/composables/useScramble.js +76 -0
- package/dist/composables/useShift.js +2 -10
- package/dist/composables/useSpotlight.d.ts +18 -0
- package/dist/composables/useSpotlight.js +53 -0
- package/dist/composables/useTilt.js +26 -18
- package/dist/composables/useTween.d.ts +43 -0
- package/dist/composables/useTween.js +69 -0
- package/dist/composables/useView.d.ts +18 -0
- package/dist/composables/useView.js +61 -0
- package/dist/icons-all.js +1 -1
- package/dist/index.d.ts +98 -1
- package/dist/index.js +262 -104
- package/dist/theme/define.d.ts +12 -0
- package/dist/theme/studio.d.ts +90 -0
- package/package.json +5 -2
- package/src/component-names.ts +33 -0
- package/src/components/AttentionDot.vue +27 -0
- package/src/components/FieldWrapper.vue +38 -0
- package/src/components/LayoutNode.vue +5 -9
- package/src/components/LegendSwatch.vue +15 -0
- package/src/components/LoaderMark.vue +90 -0
- package/src/components/LpActionBar.vue +12 -20
- package/src/components/LpActivityLine.vue +186 -0
- package/src/components/LpAlert.vue +54 -24
- package/src/components/LpAppShell.vue +7 -11
- package/src/components/LpAutocomplete.vue +16 -14
- package/src/components/LpAvatar.vue +17 -2
- package/src/components/LpBadge.vue +77 -13
- package/src/components/LpBreadcrumbs.vue +101 -35
- package/src/components/LpButton.vue +15 -3
- package/src/components/LpCard.vue +30 -7
- package/src/components/LpChart.vue +152 -156
- package/src/components/LpCheckbox.vue +10 -4
- package/src/components/LpCodeBlock.vue +11 -19
- package/src/components/LpCodeDisplay.vue +228 -0
- package/src/components/LpCollapse.vue +162 -0
- package/src/components/LpColorPicker.vue +10 -1
- package/src/components/LpCommandPalette.vue +38 -24
- package/src/components/LpContextMenu.vue +10 -1
- package/src/components/LpCopyButton.vue +185 -0
- package/src/components/LpCountdown.vue +308 -0
- package/src/components/LpDataList.vue +154 -0
- package/src/components/LpDatePicker.vue +53 -104
- package/src/components/LpDateRangePicker.vue +49 -95
- package/src/components/LpDisclosure.vue +58 -36
- package/src/components/LpDock.vue +274 -0
- package/src/components/LpDrawer.vue +10 -1
- package/src/components/LpDropdownMenu.vue +10 -1
- package/src/components/LpDropzone.vue +34 -13
- package/src/components/LpEditable.vue +293 -0
- package/src/components/LpFileTree.vue +5 -1
- package/src/components/LpFileTreeNode.vue +25 -50
- package/src/components/LpFormField.vue +22 -3
- package/src/components/LpFrame.vue +200 -0
- package/src/components/LpGauge.vue +287 -0
- package/src/components/LpGlowBorder.vue +60 -0
- package/src/components/LpHintExample.vue +14 -38
- package/src/components/LpHintLayer.vue +13 -3
- package/src/components/LpHoverCard.vue +175 -0
- package/src/components/LpIdenticon.vue +69 -0
- package/src/components/LpImageEditor.vue +15 -18
- package/src/components/LpInfraNode.vue +27 -16
- package/src/components/LpInput.vue +30 -16
- package/src/components/LpLightbox.vue +44 -23
- package/src/components/LpLoader.vue +145 -0
- package/src/components/LpLogViewer.vue +311 -82
- package/src/components/LpMagnetic.vue +97 -0
- package/src/components/LpMapPicker.vue +26 -28
- package/src/components/LpMasonry.vue +247 -0
- package/src/components/LpModal.vue +10 -1
- package/src/components/LpNotificationBell.vue +33 -49
- package/src/components/LpNumberField.vue +79 -14
- package/src/components/LpNumberFlow.vue +10 -35
- package/src/components/LpOtpInput.vue +7 -2
- package/src/components/LpPagination.vue +38 -4
- package/src/components/LpPalettePreview.vue +2 -7
- package/src/components/LpPasswordInput.vue +16 -14
- package/src/components/LpPhoneInput.vue +12 -3
- package/src/components/LpPie.vue +197 -36
- package/src/components/LpPipeline.vue +366 -0
- package/src/components/LpPopover.vue +10 -1
- package/src/components/LpProgress.vue +22 -84
- package/src/components/LpQuota.vue +197 -0
- package/src/components/LpRangeSlider.vue +5 -1
- package/src/components/LpRelativeTime.vue +90 -0
- package/src/components/LpRepeater.vue +80 -0
- package/src/components/LpRevealOnScroll.vue +125 -0
- package/src/components/LpScramble.vue +107 -0
- package/src/components/LpSecretField.vue +313 -0
- package/src/components/LpSegmented.vue +3 -10
- package/src/components/LpSelect.vue +78 -64
- package/src/components/LpShaderBackdrop.vue +434 -0
- package/src/components/LpShinyText.vue +139 -0
- package/src/components/LpSidebar.vue +2 -0
- package/src/components/LpSlider.vue +5 -1
- package/src/components/LpSparkline.vue +55 -37
- package/src/components/LpSpotlight.vue +51 -0
- package/src/components/LpStat.vue +6 -2
- package/src/components/LpStatus.vue +127 -0
- package/src/components/LpStepMark.vue +138 -0
- package/src/components/LpStepper.vue +37 -43
- package/src/components/LpSwap.vue +2 -2
- package/src/components/LpSwitch.vue +15 -22
- package/src/components/LpTable.vue +47 -63
- package/src/components/LpTableFilter.vue +1 -0
- package/src/components/LpTableOfContents.vue +53 -29
- package/src/components/LpTabs.vue +10 -21
- package/src/components/LpTagsInput.vue +53 -37
- package/src/components/LpTextReveal.vue +236 -0
- package/src/components/LpTextarea.vue +11 -11
- package/src/components/LpThemeStudio.vue +216 -0
- package/src/components/LpThemeStudioSection.vue +16 -0
- package/src/components/LpThemeSwitcher.vue +156 -47
- package/src/components/LpTimeField.vue +9 -1
- package/src/components/LpToaster.vue +63 -83
- package/src/components/LpTooltip.vue +10 -1
- package/src/components/LpTour.vue +24 -13
- package/src/components/LpTruncate.vue +135 -0
- package/src/components/LpTypewriter.vue +236 -0
- package/src/components/LpUptimeBar.vue +6 -5
- package/src/components/LpVideoBackdrop.vue +15 -13
- package/src/components/OptionContent.vue +17 -0
- package/src/components/PickerField.vue +58 -0
- package/src/components/RevealToggle.vue +51 -0
- package/src/components/StepConnector.vue +54 -0
- package/src/components/TourCard.vue +29 -16
- package/src/components/badge.ts +8 -0
- package/src/components/chart.ts +8 -23
- package/src/components/dateRange.ts +25 -0
- package/src/components/dock.ts +31 -0
- package/src/components/dropdown.ts +15 -3
- package/src/components/fieldText.ts +95 -0
- package/src/components/fileTree.ts +19 -21
- package/src/components/format.ts +136 -0
- package/src/components/identicon.ts +160 -0
- package/src/components/masonry.ts +73 -0
- package/src/components/meter.ts +122 -0
- package/src/components/otp.ts +14 -3
- package/src/components/pipeline.ts +101 -0
- package/src/components/quota.ts +111 -0
- package/src/components/relativeTime.ts +118 -0
- package/src/components/reveal.ts +56 -0
- package/src/components/scramble.ts +138 -0
- package/src/components/shaderBackdrop.ts +208 -0
- package/src/components/slider.ts +30 -0
- package/src/components/slotText.ts +13 -0
- package/src/components/status.ts +46 -0
- package/src/components/tableFacets.ts +25 -0
- package/src/components/textSplit.ts +55 -0
- package/src/components/timeSpan.ts +183 -0
- package/src/components/tone.ts +144 -0
- package/src/components/tour.ts +3 -2
- package/src/components/typewriter.ts +104 -0
- package/src/components/videoBackdrop.ts +7 -6
- package/src/composables/easing.ts +66 -1
- package/src/composables/pseudoLocale.ts +105 -0
- package/src/composables/scroll.ts +6 -3
- package/src/composables/useClipboard.ts +25 -3
- package/src/composables/useField.ts +12 -0
- package/src/composables/useForm.ts +27 -6
- package/src/composables/useHintSystem.ts +40 -0
- package/src/composables/useHints.ts +14 -3
- package/src/composables/useInView.ts +61 -0
- package/src/composables/useLoadingGate.ts +63 -0
- package/src/composables/useLpConfig.ts +20 -1
- package/src/composables/useMediaQuery.ts +6 -2
- package/src/composables/useNow.ts +84 -0
- package/src/composables/usePersisted.ts +19 -8
- package/src/composables/usePillTransition.ts +21 -13
- package/src/composables/usePointerFrame.ts +72 -0
- package/src/composables/useReducedMotion.ts +22 -0
- package/src/composables/useRepeater.ts +44 -0
- package/src/composables/useResizeObserver.ts +59 -0
- package/src/composables/useRevealedValue.ts +84 -0
- package/src/composables/useScramble.ts +152 -0
- package/src/composables/useShift.ts +10 -16
- package/src/composables/useSpotlight.ts +82 -0
- package/src/composables/useTilt.ts +40 -23
- package/src/composables/useTween.ts +149 -0
- package/src/composables/useView.ts +93 -0
- package/src/index.css +1 -0
- package/src/index.ts +143 -1
- package/src/kit-icons.ts +1 -1
- package/src/theme/define.ts +65 -0
- package/src/theme/studio.ts +202 -0
- package/src/tokens/effects.css +151 -0
- package/src/tokens/tokens.css +131 -39
- package/src/tokens/utilities.css +81 -0
- package/dist/assets/LpTabs-Bk7v4bZz.css +0 -18
- package/dist/chunks/LpAlert-BdvxvcWE.js +0 -85
- package/dist/chunks/LpBadge-Fe0D1bYx.js +0 -62
- package/dist/chunks/LpBreadcrumbs-rzOKkLiI.js +0 -98
- package/dist/chunks/LpDatePicker-BMfM454Y.js +0 -243
- package/dist/chunks/LpDateRangePicker-CNb9X3eL.js +0 -195
- package/dist/chunks/LpNumberField-DO1ufKvE.js +0 -107
- package/dist/chunks/LpStepper-C2slwObu.js +0 -90
- package/dist/chunks/LpSwitch-CZy9_IoA.js +0 -132
- package/dist/chunks/LpThemeSwitcher-CDoziW0z.js +0 -166
- package/dist/chunks/TourCard-BKI7X9-r.js +0 -105
package/src/components/LpPie.vue
CHANGED
|
@@ -23,7 +23,9 @@ export default { inheritAttrs: false }
|
|
|
23
23
|
import { computed, onBeforeUnmount, ref, watch } from "vue"
|
|
24
24
|
import { easeTravel, prefersReducedMotion } from "../composables/easing"
|
|
25
25
|
import { useReveal } from "../composables/useReveal"
|
|
26
|
+
import { lerp, mixColor, useTween } from "../composables/useTween"
|
|
26
27
|
import { arcPath, calloutLabels, resolveSlices, formatTick, type PieSlice } from "./chart"
|
|
28
|
+
import LegendSwatch from "./LegendSwatch.vue"
|
|
27
29
|
import LpContextMenu, { type ContextMenuItemDef } from "./LpContextMenu.vue"
|
|
28
30
|
import LpEmptyState from "./LpEmptyState.vue"
|
|
29
31
|
import LpNumberFlow from "./LpNumberFlow.vue"
|
|
@@ -278,9 +280,25 @@ const inner = computed(() =>
|
|
|
278
280
|
* from. The pad is taken off each slice's own sweep and only when there is more
|
|
279
281
|
* than one slice — a lone slice with a gap would be a circle with a nick in it.
|
|
280
282
|
*/
|
|
283
|
+
/*
|
|
284
|
+
* A slice is the same slice across data changes when it keeps its label. The
|
|
285
|
+
* index is no identity: a category inserted at the front would hand every
|
|
286
|
+
* other slice its neighbour's place, and the arcs would trade colours as they
|
|
287
|
+
* moved. The occurrence count only separates two slices that share a label.
|
|
288
|
+
*/
|
|
289
|
+
const sliceKeys = computed(() => {
|
|
290
|
+
const seen = new Map<string, number>()
|
|
291
|
+
return resolved.value.slices.map((s) => {
|
|
292
|
+
const n = seen.get(s.label) ?? 0
|
|
293
|
+
seen.set(s.label, n + 1)
|
|
294
|
+
return `${s.isOther ? "other" : "slice"}:${s.label}#${n}`
|
|
295
|
+
})
|
|
296
|
+
})
|
|
297
|
+
|
|
281
298
|
const arcs = computed(() =>
|
|
282
|
-
arcAngles.value.map(({ slice, start, end, mid }) => ({
|
|
299
|
+
arcAngles.value.map(({ slice, start, end, mid, index }) => ({
|
|
283
300
|
...slice,
|
|
301
|
+
key: sliceKeys.value[index],
|
|
284
302
|
d: arcPath(cx.value, cy.value, outer.value, inner.value, start, end, props.cornerRadius),
|
|
285
303
|
/*
|
|
286
304
|
* Push along the slice's own bisector, so it moves straight out of the
|
|
@@ -367,6 +385,143 @@ const sweepPath = computed(() => {
|
|
|
367
385
|
return arcPath(cx.value, cy.value, radius, 0, start, start + Math.PI * 2 * sweep.value)
|
|
368
386
|
})
|
|
369
387
|
|
|
388
|
+
/*
|
|
389
|
+
* What is DRAWN, as opposed to what is: each slice's span as fractions of the
|
|
390
|
+
* circle, travelling from the last data to the new.
|
|
391
|
+
*
|
|
392
|
+
* Interpolated as cumulative edges, not as sizes. Two neighbours share an edge
|
|
393
|
+
* at both ends of the move, so they share it at every frame between — a slice
|
|
394
|
+
* that grows pushes the next one round rather than overlapping it, and the
|
|
395
|
+
* circle stays closed throughout. A new slice opens from a zero-width sliver at
|
|
396
|
+
* the edge where it will sit; a removed one closes onto the edge its
|
|
397
|
+
* neighbours meet at, and is dropped once it has.
|
|
398
|
+
*
|
|
399
|
+
* Only the drawing moves. Hit areas, callouts, the legend and every event keep
|
|
400
|
+
* reading `arcs`, the data as it now is: a click mid-move lands on the slice
|
|
401
|
+
* the reader is aiming at, which is where it is going, and callouts laid out
|
|
402
|
+
* per frame would reshuffle their stacked labels as the slices slid.
|
|
403
|
+
*/
|
|
404
|
+
interface Wedge {
|
|
405
|
+
key: string
|
|
406
|
+
from: number
|
|
407
|
+
to: number
|
|
408
|
+
color: string
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
const wedges = computed<Wedge[]>(() => {
|
|
412
|
+
let at = 0
|
|
413
|
+
return resolved.value.slices.map((s, i) => {
|
|
414
|
+
const w = { key: sliceKeys.value[i], from: at, to: at + s.fraction, color: s.color }
|
|
415
|
+
at = w.to
|
|
416
|
+
return w
|
|
417
|
+
})
|
|
418
|
+
})
|
|
419
|
+
|
|
420
|
+
const mixWedges = (from: Wedge[], to: Wedge[], t: number): Wedge[] => {
|
|
421
|
+
const before = new Map(from.map((w) => [w.key, w]))
|
|
422
|
+
const after = new Map(to.map((w) => [w.key, w]))
|
|
423
|
+
const out: Wedge[] = []
|
|
424
|
+
|
|
425
|
+
// Entering slices open at the far edge of the nearest earlier slice that was
|
|
426
|
+
// already drawn — exactly where the slice after them used to start.
|
|
427
|
+
let edge = 0
|
|
428
|
+
for (const w of to) {
|
|
429
|
+
const was = before.get(w.key)
|
|
430
|
+
const a = was ?? { from: edge, to: edge, color: w.color }
|
|
431
|
+
if (was) edge = was.to
|
|
432
|
+
out.push({
|
|
433
|
+
key: w.key,
|
|
434
|
+
from: lerp(a.from, w.from, t),
|
|
435
|
+
to: lerp(a.to, w.to, t),
|
|
436
|
+
color: mixColor(a.color, w.color, t),
|
|
437
|
+
})
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// Leaving slices close onto the edge their surviving predecessor will end
|
|
441
|
+
// at, and keep their place in the order so the drawing stays in sequence.
|
|
442
|
+
edge = 0
|
|
443
|
+
let slot = 0
|
|
444
|
+
for (const w of from) {
|
|
445
|
+
const next = after.get(w.key)
|
|
446
|
+
if (next) {
|
|
447
|
+
edge = next.to
|
|
448
|
+
slot = out.findIndex((o) => o.key === w.key) + 1
|
|
449
|
+
continue
|
|
450
|
+
}
|
|
451
|
+
out.splice(slot++, 0, {
|
|
452
|
+
key: w.key,
|
|
453
|
+
from: lerp(w.from, edge, t),
|
|
454
|
+
to: lerp(w.to, edge, t),
|
|
455
|
+
color: w.color,
|
|
456
|
+
})
|
|
457
|
+
}
|
|
458
|
+
return out
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/*
|
|
462
|
+
* The sweep and the tween never overlap: while the circle is still to open
|
|
463
|
+
* (not yet scrolled to, or closed again for a load) a change simply lands, and
|
|
464
|
+
* the data that follows sweeps in like the first.
|
|
465
|
+
*/
|
|
466
|
+
const shownWedges = useTween(() => wedges.value, mixWedges, {
|
|
467
|
+
enabled: () => props.animate && sweep.value >= 1,
|
|
468
|
+
})
|
|
469
|
+
|
|
470
|
+
/*
|
|
471
|
+
* The legend's figures count to their new values, and a figure's text changes
|
|
472
|
+
* width as it goes ("8.13k" is wider than "12k"): the legend column, and the
|
|
473
|
+
* circle and everything beside it, shook on every frame. Each figure keeps the
|
|
474
|
+
* width of the widest text it passes through between the old value and the new
|
|
475
|
+
* one, measured in characters of its monospace font.
|
|
476
|
+
*/
|
|
477
|
+
const figureChars = ref(0)
|
|
478
|
+
watch(
|
|
479
|
+
() => arcs.value.map((a) => [a.key, props.showPercent ? a.fraction : a.value] as const),
|
|
480
|
+
(next, prev) => {
|
|
481
|
+
const text = props.showPercent ? pct : fmt
|
|
482
|
+
const before = new Map(prev ?? [])
|
|
483
|
+
let widest = 0
|
|
484
|
+
for (const [key, to] of next) {
|
|
485
|
+
const from = before.get(key) ?? to
|
|
486
|
+
for (let k = 0; k <= 8; k++) widest = Math.max(widest, text(lerp(from, to, k / 8)).length)
|
|
487
|
+
}
|
|
488
|
+
figureChars.value = widest
|
|
489
|
+
},
|
|
490
|
+
{ immediate: true },
|
|
491
|
+
)
|
|
492
|
+
|
|
493
|
+
const drawn = computed(() => {
|
|
494
|
+
const indexOf = new Map(arcs.value.map((a, i) => [a.key, i]))
|
|
495
|
+
const pad = arcs.value.length > 1 ? (props.padAngle * Math.PI) / 180 : 0
|
|
496
|
+
const TURN = Math.PI * 2
|
|
497
|
+
return shownWedges.value
|
|
498
|
+
.filter((w) => w.to - w.from > 1e-5)
|
|
499
|
+
.map((w) => {
|
|
500
|
+
const sweepAngle = (w.to - w.from) * TURN
|
|
501
|
+
const start = -Math.PI / 2 + w.from * TURN
|
|
502
|
+
const gap = Math.min(pad, sweepAngle * 0.5)
|
|
503
|
+
const mid = start + sweepAngle / 2
|
|
504
|
+
return {
|
|
505
|
+
key: w.key,
|
|
506
|
+
/* -1 for a slice on its way out: no longer data, so never lifted. */
|
|
507
|
+
index: indexOf.get(w.key) ?? -1,
|
|
508
|
+
color: w.color,
|
|
509
|
+
d: arcPath(
|
|
510
|
+
cx.value,
|
|
511
|
+
cy.value,
|
|
512
|
+
outer.value,
|
|
513
|
+
inner.value,
|
|
514
|
+
start + gap / 2,
|
|
515
|
+
start + sweepAngle - gap / 2,
|
|
516
|
+
props.cornerRadius,
|
|
517
|
+
),
|
|
518
|
+
lift: `translate(${(Math.cos(mid) * props.hoverOffset).toFixed(2)} ${(
|
|
519
|
+
Math.sin(mid) * props.hoverOffset
|
|
520
|
+
).toFixed(2)})`,
|
|
521
|
+
}
|
|
522
|
+
})
|
|
523
|
+
})
|
|
524
|
+
|
|
370
525
|
const callouts = computed(() =>
|
|
371
526
|
props.labels
|
|
372
527
|
? calloutLabels(
|
|
@@ -808,20 +963,20 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
|
|
|
808
963
|
nothing. -->
|
|
809
964
|
<g :clip-path="animate ? `url(#${sweepId}-sweep)` : undefined">
|
|
810
965
|
<path
|
|
811
|
-
v-for="
|
|
812
|
-
:key="
|
|
813
|
-
:d="
|
|
814
|
-
:fill="
|
|
966
|
+
v-for="w in drawn"
|
|
967
|
+
:key="w.key"
|
|
968
|
+
:d="w.d"
|
|
969
|
+
:fill="w.color"
|
|
815
970
|
class="pointer-events-none transition-[transform,opacity] duration-medium ease-[var(--ease-emphasized)] motion-reduce:transition-none"
|
|
816
|
-
:transform="active ===
|
|
817
|
-
:opacity="dimmed(
|
|
971
|
+
:transform="w.index >= 0 && active === w.index ? w.lift : undefined"
|
|
972
|
+
:opacity="dimmed(w.index) ? 0.28 : 1"
|
|
818
973
|
/>
|
|
819
974
|
</g>
|
|
820
975
|
|
|
821
976
|
<!-- Invisible, unmoving, and on top: the actual hit area. -->
|
|
822
977
|
<path
|
|
823
978
|
v-for="(a, i) in arcs"
|
|
824
|
-
:key="`hit-${
|
|
979
|
+
:key="`hit-${a.key}`"
|
|
825
980
|
:d="a.d"
|
|
826
981
|
fill="transparent"
|
|
827
982
|
class="cursor-pointer"
|
|
@@ -899,34 +1054,40 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
|
|
|
899
1054
|
|
|
900
1055
|
<!-- The legend is the same control surface as the circle: identical
|
|
901
1056
|
modifiers, and slivers too small to hit are reachable here. -->
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
:
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
1057
|
+
<!-- Eases when the figures need more room or less. -->
|
|
1058
|
+
<LpShift v-if="legendShown" axis="width" class="min-w-0">
|
|
1059
|
+
<div class="flex min-w-0 flex-col gap-1.5" @pointerup="endDrag">
|
|
1060
|
+
<button
|
|
1061
|
+
v-for="(a, i) in arcs"
|
|
1062
|
+
:key="a.key"
|
|
1063
|
+
type="button"
|
|
1064
|
+
class="group flex cursor-pointer items-center gap-2 rounded-inner px-1 py-0.5 text-xs outline-none transition-[opacity,background-color] duration-fast focus-visible:ring-2 focus-visible:ring-ring"
|
|
1065
|
+
:class="[dimmed(i) ? 'opacity-45' : '', isSelected(i) ? 'bg-surface-soft' : '']"
|
|
1066
|
+
:aria-pressed="isSelected(i)"
|
|
1067
|
+
@pointerenter="onSlicePointerEnter(i)"
|
|
1068
|
+
@pointerleave="onSlicePointerLeave(i)"
|
|
1069
|
+
@pointerdown="onSlicePointerDown(i, $event)"
|
|
1070
|
+
@click="onLegendClick(i, $event)"
|
|
1071
|
+
@focus="active = i"
|
|
1072
|
+
@blur="active === i && (active = -1)"
|
|
1073
|
+
@contextmenu="onSliceContextMenu(i)"
|
|
1074
|
+
>
|
|
1075
|
+
<LegendSwatch :color="a.color" />
|
|
1076
|
+
<span class="truncate text-muted-strong group-hover:text-ink">{{ a.label }}</span>
|
|
1077
|
+
<!-- What the bucket stands for, so a fold is never a silent loss. -->
|
|
1078
|
+
<span v-if="a.isOther" class="shrink-0 text-muted">({{ a.count }})</span>
|
|
1079
|
+
<!-- Counts to the new figure, on the same beat as its slice resizing. -->
|
|
1080
|
+
<LpNumberFlow
|
|
1081
|
+
class="ml-auto shrink-0 pl-2 text-right font-mono tabular-nums text-muted"
|
|
1082
|
+
:style="{ minWidth: `calc(${figureChars}ch + 0.5rem)` }"
|
|
1083
|
+
:value="showPercent ? a.fraction : a.value"
|
|
1084
|
+
:duration="360"
|
|
1085
|
+
:format="showPercent ? pct : fmt"
|
|
1086
|
+
:animate-on-mount="false"
|
|
1087
|
+
/>
|
|
1088
|
+
</button>
|
|
1089
|
+
</div>
|
|
1090
|
+
</LpShift>
|
|
930
1091
|
</div>
|
|
931
1092
|
</LpContextMenu>
|
|
932
1093
|
</LpSwap>
|
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
// The consumer's `class` is merged into the root's own (below) rather than
|
|
3
|
+
// appended to it, so opt out of the automatic pass-through that would add it
|
|
4
|
+
// a second time, unmerged.
|
|
5
|
+
export default { inheritAttrs: false }
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<script setup lang="ts">
|
|
9
|
+
/*
|
|
10
|
+
* A run of jobs and the state each one is in: a deploy, a CI workflow, a
|
|
11
|
+
* server being provisioned.
|
|
12
|
+
*
|
|
13
|
+
* Not a wizard. LpStepper answers "where am I in a form", with one current
|
|
14
|
+
* step and everything before it done; here every step has its own state —
|
|
15
|
+
* three can pass, one fail and the rest never run — and the viewer is
|
|
16
|
+
* watching rather than driving. So the pieces are the ones a process monitor
|
|
17
|
+
* needs: a glyph per state (LpStepMark), how long each job took (ticking
|
|
18
|
+
* while it runs, from `startedAt`, without the app re-sending it), the line
|
|
19
|
+
* between steps filled up to where the run got and broken where it stopped,
|
|
20
|
+
* and a step's inside (its sub-jobs, its log) folded under it.
|
|
21
|
+
*
|
|
22
|
+
* <LpPipeline :steps="run.jobs" follow />
|
|
23
|
+
* <LpPipeline :steps="stages" orientation="horizontal" compact />
|
|
24
|
+
*
|
|
25
|
+
* Each change of state is announced politely ("Deploy: failed"), so a screen
|
|
26
|
+
* reader user learns about the run the way a sighted one glances at it.
|
|
27
|
+
*/
|
|
28
|
+
import { computed, nextTick, ref, useId, useSlots, watch } from "vue"
|
|
29
|
+
import { prefersReducedMotion } from "../composables/easing"
|
|
30
|
+
import { useLabels } from "../composables/useLpConfig"
|
|
31
|
+
import { useMergedAttrs } from "../composables/useMergedClass"
|
|
32
|
+
import { useNow } from "../composables/useNow"
|
|
33
|
+
import LpCollapse from "./LpCollapse.vue"
|
|
34
|
+
import LpIcon from "./LpIcon.vue"
|
|
35
|
+
import LpRollingText from "./LpRollingText.vue"
|
|
36
|
+
import LpShift from "./LpShift.vue"
|
|
37
|
+
import LpStepMark from "./LpStepMark.vue"
|
|
38
|
+
import LpTooltip from "./LpTooltip.vue"
|
|
39
|
+
import StepConnector from "./StepConnector.vue"
|
|
40
|
+
import {
|
|
41
|
+
childProgress,
|
|
42
|
+
connectorFilled,
|
|
43
|
+
currentStepIndex,
|
|
44
|
+
stepElapsed,
|
|
45
|
+
stepKey,
|
|
46
|
+
type PipelineStep,
|
|
47
|
+
type StepStatus,
|
|
48
|
+
} from "./pipeline"
|
|
49
|
+
import { DEFAULT_UNIT_LABELS, formatElapsed, toEpoch, type TimeUnitLabels } from "./timeSpan"
|
|
50
|
+
import { TONES } from "./tone"
|
|
51
|
+
|
|
52
|
+
export type PipelineLabels = Record<StepStatus, string> & {
|
|
53
|
+
showDetails: string
|
|
54
|
+
hideDetails: string
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const props = withDefaults(
|
|
58
|
+
defineProps<{
|
|
59
|
+
steps: PipelineStep[]
|
|
60
|
+
/**
|
|
61
|
+
* `vertical` (default) is the job list: room for descriptions, durations
|
|
62
|
+
* and folded sub-steps. `horizontal` is the strip across a card or a
|
|
63
|
+
* header, where the run is read at a glance.
|
|
64
|
+
*/
|
|
65
|
+
orientation?: "horizontal" | "vertical"
|
|
66
|
+
/**
|
|
67
|
+
* Smaller marks, no descriptions. Horizontal and compact is marks and
|
|
68
|
+
* lines only, each step named in a tooltip — a run in a table cell.
|
|
69
|
+
*/
|
|
70
|
+
compact?: boolean
|
|
71
|
+
/** Number the pending marks, for a run whose order is part of its meaning. */
|
|
72
|
+
numbered?: boolean
|
|
73
|
+
/**
|
|
74
|
+
* Keep the current step (see `currentStepIndex`) scrolled into view as the
|
|
75
|
+
* run advances: a long job list, or a horizontal strip wider than its box.
|
|
76
|
+
*/
|
|
77
|
+
follow?: boolean
|
|
78
|
+
/**
|
|
79
|
+
* Open a step on its own when it starts running or fails, if it has
|
|
80
|
+
* something inside, and fold it again when it passes. That is the step the
|
|
81
|
+
* viewer would open next anyway; a step the viewer opened stays open.
|
|
82
|
+
*/
|
|
83
|
+
autoExpand?: boolean
|
|
84
|
+
/** Announce status changes to screen readers. A nested pipeline turns it off so its parent speaks once. */
|
|
85
|
+
announce?: boolean
|
|
86
|
+
labels?: Partial<PipelineLabels>
|
|
87
|
+
}>(),
|
|
88
|
+
{ orientation: "vertical", autoExpand: true, announce: true },
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
/** Keys of the open steps. Works uncontrolled; bind it to keep it in the app. */
|
|
92
|
+
const expanded = defineModel<string[]>("expanded", { default: () => [] })
|
|
93
|
+
|
|
94
|
+
defineSlots<{
|
|
95
|
+
/** Inside an expanded step, under its sub-steps: a log tail, a link to the run, an error. */
|
|
96
|
+
detail?: (props: { step: PipelineStep; index: number }) => unknown
|
|
97
|
+
}>()
|
|
98
|
+
|
|
99
|
+
const text = useLabels<PipelineLabels>(
|
|
100
|
+
"pipeline",
|
|
101
|
+
{
|
|
102
|
+
pending: "Pending",
|
|
103
|
+
running: "Running",
|
|
104
|
+
success: "Passed",
|
|
105
|
+
failed: "Failed",
|
|
106
|
+
skipped: "Skipped",
|
|
107
|
+
cancelled: "Cancelled",
|
|
108
|
+
showDetails: "Show details",
|
|
109
|
+
hideDetails: "Hide details",
|
|
110
|
+
},
|
|
111
|
+
() => props.labels,
|
|
112
|
+
)
|
|
113
|
+
const units = useLabels<TimeUnitLabels>("time", DEFAULT_UNIT_LABELS)
|
|
114
|
+
|
|
115
|
+
const slots = useSlots()
|
|
116
|
+
const vertical = computed(() => props.orientation === "vertical")
|
|
117
|
+
const markSize = computed(() => (props.compact ? "sm" : "md"))
|
|
118
|
+
|
|
119
|
+
/* The clock only runs while a step is running on its own timestamps. */
|
|
120
|
+
const ticking = computed(() =>
|
|
121
|
+
props.steps.some((s) => s.status === "running" && s.duration === undefined && !Number.isNaN(toEpoch(s.startedAt))),
|
|
122
|
+
)
|
|
123
|
+
const now = useNow(ticking)
|
|
124
|
+
|
|
125
|
+
const elapsed = (step: PipelineStep) => {
|
|
126
|
+
const ms = stepElapsed(step, now.value)
|
|
127
|
+
return ms === null ? "" : formatElapsed(ms, units.value)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const progressText = (step: PipelineStep) => {
|
|
131
|
+
const p = childProgress(step)
|
|
132
|
+
return p ? `${p.done}/${p.total}` : ""
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/* A job that has not started has no log yet; its sub-steps are still worth a look. */
|
|
136
|
+
const expandable = (step: PipelineStep) =>
|
|
137
|
+
vertical.value && (!!step.steps?.length || (!!slots.detail && step.status !== "pending"))
|
|
138
|
+
const isOpen = (step: PipelineStep, i: number) => expanded.value.includes(stepKey(step, i))
|
|
139
|
+
|
|
140
|
+
function toggle(step: PipelineStep, i: number) {
|
|
141
|
+
const key = stepKey(step, i)
|
|
142
|
+
// Touched by the viewer: theirs now, not the pipeline's to fold away.
|
|
143
|
+
autoOpened.delete(key)
|
|
144
|
+
expanded.value = isOpen(step, i) ? expanded.value.filter((k) => k !== key) : [...expanded.value, key]
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/*
|
|
148
|
+
* The fill of the line leaving a step: travelled in the colour of what
|
|
149
|
+
* happened (passed, skipped), flowing while the step runs, empty where the
|
|
150
|
+
* run stopped or has not reached.
|
|
151
|
+
*/
|
|
152
|
+
const FILL: Partial<Record<StepStatus, string>> = {
|
|
153
|
+
success: TONES.success.bg,
|
|
154
|
+
skipped: "bg-line-strong",
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const statusText = (step: PipelineStep) => {
|
|
158
|
+
const time = elapsed(step)
|
|
159
|
+
return time ? `${text.value[step.status]}, ${time}` : text.value[step.status]
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/* ── Announcements and auto-expansion: both react to a step CHANGING state. */
|
|
163
|
+
const announcement = ref("")
|
|
164
|
+
let seen = new Map<string, StepStatus>()
|
|
165
|
+
/* Steps the pipeline opened itself — the only ones it may close again. */
|
|
166
|
+
const autoOpened = new Set<string>()
|
|
167
|
+
|
|
168
|
+
watch(
|
|
169
|
+
() => props.steps.map((s, i) => [stepKey(s, i), s.status] as const),
|
|
170
|
+
(pairs, old) => {
|
|
171
|
+
const next = new Map(pairs)
|
|
172
|
+
if (old) {
|
|
173
|
+
const opened: string[] = []
|
|
174
|
+
const closed: string[] = []
|
|
175
|
+
const said: string[] = []
|
|
176
|
+
props.steps.forEach((step, i) => {
|
|
177
|
+
const key = stepKey(step, i)
|
|
178
|
+
const before = seen.get(key)
|
|
179
|
+
if (before === undefined || before === step.status) return
|
|
180
|
+
said.push(`${step.label}: ${text.value[step.status]}`)
|
|
181
|
+
if (!props.autoExpand) return
|
|
182
|
+
if ((step.status === "running" || step.status === "failed") && expandable(step)) opened.push(key)
|
|
183
|
+
else if (connectorFilled(step.status) && autoOpened.has(key)) closed.push(key)
|
|
184
|
+
})
|
|
185
|
+
if (said.length && props.announce) announcement.value = said.join(". ")
|
|
186
|
+
const fresh = opened.filter((k) => !expanded.value.includes(k))
|
|
187
|
+
fresh.forEach((k) => autoOpened.add(k))
|
|
188
|
+
closed.forEach((k) => autoOpened.delete(k))
|
|
189
|
+
if (fresh.length || closed.length) {
|
|
190
|
+
expanded.value = [...expanded.value.filter((k) => !closed.includes(k)), ...fresh]
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
seen = next
|
|
194
|
+
},
|
|
195
|
+
{ immediate: true },
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
/* ── Following the current step. */
|
|
199
|
+
const uid = useId()
|
|
200
|
+
const items: Array<Element | null> = []
|
|
201
|
+
const bindItem = (i: number) => (el: unknown) => { items[i] = el instanceof Element ? el : null }
|
|
202
|
+
const current = computed(() => currentStepIndex(props.steps))
|
|
203
|
+
|
|
204
|
+
watch(current, async (i) => {
|
|
205
|
+
if (!props.follow || i < 0) return
|
|
206
|
+
await nextTick()
|
|
207
|
+
items[i]?.scrollIntoView({
|
|
208
|
+
block: "nearest",
|
|
209
|
+
inline: "center",
|
|
210
|
+
behavior: prefersReducedMotion() ? "auto" : "smooth",
|
|
211
|
+
})
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
const { class: rootClass, attrs: rest } = useMergedAttrs(() =>
|
|
215
|
+
vertical.value
|
|
216
|
+
? "flex w-full min-w-0 flex-col"
|
|
217
|
+
: `flex w-full min-w-0 items-start overflow-x-auto ${props.compact ? "gap-1.5 py-1" : "gap-3 pb-1"}`,
|
|
218
|
+
)
|
|
219
|
+
</script>
|
|
220
|
+
|
|
221
|
+
<template>
|
|
222
|
+
<div class="contents">
|
|
223
|
+
<ol :class="rootClass" v-bind="rest">
|
|
224
|
+
<li
|
|
225
|
+
v-for="(step, i) in steps"
|
|
226
|
+
:key="stepKey(step, i)"
|
|
227
|
+
:ref="bindItem(i)"
|
|
228
|
+
:aria-current="i === current ? 'step' : undefined"
|
|
229
|
+
:class="vertical
|
|
230
|
+
? 'grid grid-cols-[auto_minmax(0,1fr)] gap-x-3'
|
|
231
|
+
: 'flex min-w-0 flex-1 items-start last:flex-none ' + (compact ? 'min-w-6 gap-1.5' : 'min-w-28 gap-3')"
|
|
232
|
+
>
|
|
233
|
+
<!-- ── Vertical: mark and line in a rail, the job beside it. -->
|
|
234
|
+
<template v-if="vertical">
|
|
235
|
+
<div class="flex flex-col items-center">
|
|
236
|
+
<LpStepMark
|
|
237
|
+
:status="step.status"
|
|
238
|
+
:size="markSize"
|
|
239
|
+
:number="numbered ? i + 1 : undefined"
|
|
240
|
+
:icon="step.icon"
|
|
241
|
+
:class="compact ? 'mt-0.5' : 'mt-px'"
|
|
242
|
+
/>
|
|
243
|
+
<StepConnector
|
|
244
|
+
v-if="i < steps.length - 1"
|
|
245
|
+
orientation="vertical"
|
|
246
|
+
:filled="connectorFilled(step.status)"
|
|
247
|
+
:fill="FILL[step.status] ?? TONES.success.bg"
|
|
248
|
+
:flowing="step.status === 'running'"
|
|
249
|
+
class="my-1 min-h-3"
|
|
250
|
+
/>
|
|
251
|
+
</div>
|
|
252
|
+
|
|
253
|
+
<div class="min-w-0" :class="i < steps.length - 1 ? (compact ? 'pb-2' : 'pb-4') : ''">
|
|
254
|
+
<component
|
|
255
|
+
:is="expandable(step) ? 'button' : 'div'"
|
|
256
|
+
:type="expandable(step) ? 'button' : undefined"
|
|
257
|
+
:aria-expanded="expandable(step) ? isOpen(step, i) : undefined"
|
|
258
|
+
:aria-controls="expandable(step) ? `${uid}-${i}` : undefined"
|
|
259
|
+
class="group/row flex w-full min-w-0 items-start gap-2 rounded-control text-left"
|
|
260
|
+
:class="expandable(step) && '-mx-1.5 -my-0.5 w-[calc(100%+0.75rem)] px-1.5 py-0.5 transition-colors duration-(--duration-fast) hover:bg-surface-soft focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none'"
|
|
261
|
+
@click="expandable(step) && toggle(step, i)"
|
|
262
|
+
>
|
|
263
|
+
<span class="flex min-w-0 flex-1 flex-col">
|
|
264
|
+
<span
|
|
265
|
+
class="truncate transition-colors duration-(--duration-medium)"
|
|
266
|
+
:class="[compact ? 'text-xs' : 'text-sm', step.status === 'pending' || step.status === 'skipped' ? 'text-muted' : 'text-ink', step.status === 'running' && 'font-medium']"
|
|
267
|
+
>
|
|
268
|
+
{{ step.label }}
|
|
269
|
+
<span class="sr-only">({{ statusText(step) }})</span>
|
|
270
|
+
</span>
|
|
271
|
+
<span v-if="step.description && !compact" class="truncate text-xs text-muted">{{ step.description }}</span>
|
|
272
|
+
</span>
|
|
273
|
+
<span
|
|
274
|
+
class="flex shrink-0 items-center gap-2 font-mono text-xs tabular-nums"
|
|
275
|
+
:class="step.status === 'failed' ? TONES.danger.text : 'text-muted'"
|
|
276
|
+
aria-hidden="true"
|
|
277
|
+
>
|
|
278
|
+
<span v-if="progressText(step)" class="text-muted">{{ progressText(step) }}</span>
|
|
279
|
+
<LpShift axis="width">
|
|
280
|
+
<LpRollingText v-if="elapsed(step)" :value="elapsed(step)" align="end" :duration="200" />
|
|
281
|
+
</LpShift>
|
|
282
|
+
<LpIcon
|
|
283
|
+
v-if="expandable(step)"
|
|
284
|
+
name="lucide:chevron-down"
|
|
285
|
+
:size="14"
|
|
286
|
+
class="text-muted transition-transform duration-(--duration-medium) ease-(--ease-emphasized) motion-reduce:transition-none"
|
|
287
|
+
:class="isOpen(step, i) && 'rotate-180'"
|
|
288
|
+
/>
|
|
289
|
+
</span>
|
|
290
|
+
</component>
|
|
291
|
+
|
|
292
|
+
<LpCollapse :open="expandable(step) && isOpen(step, i)">
|
|
293
|
+
<div :id="`${uid}-${i}`" class="flex flex-col gap-2 pt-2">
|
|
294
|
+
<LpPipeline
|
|
295
|
+
v-if="step.steps?.length"
|
|
296
|
+
:steps="step.steps"
|
|
297
|
+
compact
|
|
298
|
+
:announce="false"
|
|
299
|
+
:auto-expand="false"
|
|
300
|
+
:labels="labels"
|
|
301
|
+
class="rounded-card border border-line bg-surface-soft/40 px-3 py-2"
|
|
302
|
+
/>
|
|
303
|
+
<slot name="detail" :step="step" :index="i" />
|
|
304
|
+
</div>
|
|
305
|
+
</LpCollapse>
|
|
306
|
+
</div>
|
|
307
|
+
</template>
|
|
308
|
+
|
|
309
|
+
<!-- ── Horizontal: mark, words, then the line to the next step. -->
|
|
310
|
+
<template v-else>
|
|
311
|
+
<LpTooltip v-if="compact" :content="`${step.label}: ${statusText(step)}`">
|
|
312
|
+
<span
|
|
313
|
+
tabindex="0"
|
|
314
|
+
class="inline-flex rounded-pill focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none"
|
|
315
|
+
>
|
|
316
|
+
<LpStepMark
|
|
317
|
+
:status="step.status"
|
|
318
|
+
size="sm"
|
|
319
|
+
:number="numbered ? i + 1 : undefined"
|
|
320
|
+
:icon="step.icon"
|
|
321
|
+
/>
|
|
322
|
+
<span class="sr-only">{{ step.label }} ({{ statusText(step) }})</span>
|
|
323
|
+
</span>
|
|
324
|
+
</LpTooltip>
|
|
325
|
+
<template v-else>
|
|
326
|
+
<LpStepMark
|
|
327
|
+
:status="step.status"
|
|
328
|
+
:size="markSize"
|
|
329
|
+
:number="numbered ? i + 1 : undefined"
|
|
330
|
+
:icon="step.icon"
|
|
331
|
+
/>
|
|
332
|
+
<span class="flex min-w-0 shrink flex-col">
|
|
333
|
+
<span
|
|
334
|
+
class="truncate text-sm transition-colors duration-(--duration-medium)"
|
|
335
|
+
:class="[step.status === 'pending' || step.status === 'skipped' ? 'text-muted' : 'text-ink', step.status === 'running' && 'font-medium']"
|
|
336
|
+
>
|
|
337
|
+
{{ step.label }}
|
|
338
|
+
<span class="sr-only">({{ statusText(step) }})</span>
|
|
339
|
+
</span>
|
|
340
|
+
<span
|
|
341
|
+
class="flex h-4 items-center gap-1.5 font-mono text-[11px] tabular-nums"
|
|
342
|
+
:class="step.status === 'failed' ? TONES.danger.text : 'text-muted'"
|
|
343
|
+
aria-hidden="true"
|
|
344
|
+
>
|
|
345
|
+
<LpShift axis="width">
|
|
346
|
+
<LpRollingText :value="elapsed(step) || text[step.status]" align="start" :duration="200" />
|
|
347
|
+
</LpShift>
|
|
348
|
+
<span v-if="progressText(step)">· {{ progressText(step) }}</span>
|
|
349
|
+
</span>
|
|
350
|
+
</span>
|
|
351
|
+
</template>
|
|
352
|
+
<StepConnector
|
|
353
|
+
v-if="i < steps.length - 1"
|
|
354
|
+
:filled="connectorFilled(step.status)"
|
|
355
|
+
:fill="FILL[step.status] ?? TONES.success.bg"
|
|
356
|
+
:flowing="step.status === 'running'"
|
|
357
|
+
class="min-w-4 self-start"
|
|
358
|
+
:class="compact ? 'mt-[7px]' : 'mt-[11px]'"
|
|
359
|
+
/>
|
|
360
|
+
</template>
|
|
361
|
+
</li>
|
|
362
|
+
</ol>
|
|
363
|
+
<span v-if="announce" class="sr-only" aria-live="polite" aria-atomic="true">{{ announcement }}</span>
|
|
364
|
+
</div>
|
|
365
|
+
</template>
|
|
366
|
+
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
import { computed } from "vue"
|
|
9
9
|
import { mergeClass } from "../composables/useMergedClass"
|
|
10
10
|
import { POPOVER_PANEL } from "./dropdown"
|
|
11
|
+
import { useOutsideGuard, usePortalTarget } from "../composables/useView"
|
|
11
12
|
|
|
12
13
|
const props = withDefaults(
|
|
13
14
|
defineProps<{
|
|
@@ -31,6 +32,12 @@ const open = defineModel<boolean>("open")
|
|
|
31
32
|
const panel = computed(() =>
|
|
32
33
|
mergeClass(POPOVER_PANEL, "z-(--z-popover) w-64 rounded-card p-3 text-sm text-ink outline-none", props.panelClass),
|
|
33
34
|
)
|
|
35
|
+
|
|
36
|
+
// Overlays open in the window this component renders in (an LpFrame's, inside one).
|
|
37
|
+
const portalTo = usePortalTarget()
|
|
38
|
+
// What happens in another document (the page around a frame, or a frame in
|
|
39
|
+
// the page) is not "outside" for this layer.
|
|
40
|
+
const guardOutside = useOutsideGuard()
|
|
34
41
|
</script>
|
|
35
42
|
|
|
36
43
|
<template>
|
|
@@ -38,8 +45,10 @@ const panel = computed(() =>
|
|
|
38
45
|
<PopoverTrigger as-child>
|
|
39
46
|
<slot name="trigger" />
|
|
40
47
|
</PopoverTrigger>
|
|
41
|
-
<PopoverPortal>
|
|
48
|
+
<PopoverPortal :to="portalTo">
|
|
42
49
|
<PopoverContent
|
|
50
|
+
@interact-outside="guardOutside"
|
|
51
|
+
@escape-key-down="guardOutside"
|
|
43
52
|
:collision-padding="8"
|
|
44
53
|
:side="side"
|
|
45
54
|
:align="align"
|