@leavepulse/ui 0.77.2 → 0.78.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 +68 -0
- package/dist/assets/{LpCommandPalette-DOIZHw-g.css → LpCommandPalette-DDJKICKh.css} +19 -19
- package/dist/assets/{LpDock-Cbh0wQUv.css → LpDock-Dw82tWVD.css} +3 -3
- package/dist/assets/{LpDropzone-B_qRq1-R.css → LpDropzone-DNbh_NFJ.css} +10 -10
- package/dist/assets/{LpImageEditor-XM5bAziW.css → LpImageEditor-Bgu20XLs.css} +6 -6
- package/dist/assets/{LpTable-Bv-EcQs7.css → LpTable-CCk0ZHo7.css} +19 -19
- package/dist/assets/LpTabs-Bh7a-Bdl.css +18 -0
- package/dist/chunks/AppShellContextNav-C6Ho2mof.js +49 -0
- package/dist/chunks/ChartRangeSelector-HO0sMMz6.js +129 -0
- package/dist/chunks/{ContextMenuItems-BXumicbh.js → ContextMenuItems-DmaKSJVv.js} +1 -1
- package/dist/chunks/{DropzoneLinkField-C-9BCGJn.js → DropzoneLinkField-DXIr0eFz.js} +2 -2
- package/dist/chunks/{FieldWrapper-CORPzo9s.js → FieldWrapper-DnuMTrqW.js} +1 -1
- package/dist/chunks/IconCloseButton-COZEsa9u.js +29 -0
- package/dist/chunks/{LayoutCanvas-CNOAUk7D.js → LayoutCanvas-CZKOltfA.js} +1 -1
- package/dist/chunks/{LayoutNode-DF5BMN0J.js → LayoutNode-D2f7v683.js} +45 -45
- package/dist/chunks/{LpActionBar-BP1ld7-S.js → LpActionBar-BGMk5KoG.js} +3 -3
- package/dist/chunks/{LpActivityLine-CJvzrNpj.js → LpActivityLine-Ea-t5Vza.js} +4 -2
- package/dist/chunks/{LpAddressInput-sYMvYzcY.js → LpAddressInput-ZqoZ-N2Y.js} +12 -11
- package/dist/chunks/{LpAlert-n5XPAZfv.js → LpAlert-CjvTZIKF.js} +3 -3
- package/dist/chunks/LpAppShell-BNAVTQsY.js +582 -0
- package/dist/chunks/{LpAutocomplete-DOu7FN5P.js → LpAutocomplete-DkY6CSyD.js} +26 -42
- package/dist/chunks/{LpAvatar-Cg6Az3wz.js → LpAvatar-cQVsNk6F.js} +2 -2
- package/dist/chunks/{LpBadge-wUYLN4U9.js → LpBadge-D5QQdDQ_.js} +2 -2
- package/dist/chunks/{LpBottomNav-CbNQQPuL.js → LpBottomNav-zxLGGbjm.js} +9 -2
- package/dist/chunks/{LpBreadcrumbs-DPdbth-c.js → LpBreadcrumbs-CIIBsygI.js} +4 -3
- package/dist/chunks/{LpButton-CFb44IjC.js → LpButton-DSHioIfD.js} +5 -4
- package/dist/chunks/{LpCalendar-CuoWks-0.js → LpCalendar-D4-LVjfF.js} +1 -1
- package/dist/chunks/{LpCard-r13WRqox.js → LpCard-BPtYXwnT.js} +1 -1
- package/dist/chunks/{LpCheckbox-Cs4SHaHX.js → LpCheckbox-D6RuDW4X.js} +38 -16
- package/dist/chunks/{LpCodeBlock-DRC8VbXW.js → LpCodeBlock-DuzmnIHl.js} +19 -41
- package/dist/chunks/{LpCodeDisplay-CE9TxCA4.js → LpCodeDisplay-CO8fngxa.js} +5 -5
- package/dist/chunks/{LpCollapse-CWS9M_lm.js → LpCollapse-DrAw5DBZ.js} +5 -4
- package/dist/chunks/{LpColorPicker-1y1QJHZR.js → LpColorPicker-BxAHEnR5.js} +11 -12
- package/dist/chunks/{LpCommandScope-CtUhJe8T.js → LpCommandScope-DRUvHiX7.js} +1 -1
- package/dist/chunks/{LpConfirmDialog-DlD45Bi_.js → LpConfirmDialog-6oCIJTDa.js} +3 -3
- package/dist/chunks/{LpConfirmHost-BIWjBLmI.js → LpConfirmHost-DgHvfT6s.js} +1 -1
- package/dist/chunks/{LpContextMenu-rx2tCjwk.js → LpContextMenu--eMGIql6.js} +13 -15
- package/dist/chunks/{LpContextSwitcher-Dwh6dyID.js → LpContextSwitcher-1C1tExdl.js} +2 -2
- package/dist/chunks/{LpCopyButton-xF7wFVoU.js → LpCopyButton-7EOSIuwa.js} +3 -3
- package/dist/chunks/{LpCountdown-DgeY3cLG.js → LpCountdown-DVl7vXI1.js} +4 -3
- package/dist/chunks/{LpDataList-Jxyl9H5w.js → LpDataList-DgBeM01y.js} +13 -4
- package/dist/chunks/{LpDatePicker-CA0QTfBC.js → LpDatePicker-DwSDY0mt.js} +12 -18
- package/dist/chunks/{LpDateRangePicker-u3J51xXk.js → LpDateRangePicker-CNQXdTVv.js} +10 -16
- package/dist/chunks/{LpDisclosure-Cpa7Hc5T.js → LpDisclosure-DG7JCo-d.js} +2 -2
- package/dist/chunks/{LpDrawer-CrG8t_KP.js → LpDrawer-Bt9UUqt_.js} +61 -61
- package/dist/chunks/{LpDropdownMenu-Dl7Z4ZhS.js → LpDropdownMenu-CLzxIOgM.js} +9 -17
- package/dist/chunks/{LpEditable-Cy6GLbFx.js → LpEditable-DVT0Rh8F.js} +9 -6
- package/dist/chunks/{LpEmptyState-EQHiRYhG.js → LpEmptyState-DurPF001.js} +1 -1
- package/dist/chunks/{LpFieldNotice-CzQ2_5rQ.js → LpFieldNotice-DJ10cYIo.js} +1 -1
- package/dist/chunks/LpFileTree-BSx1kBoV.js +735 -0
- package/dist/chunks/{LpFileTreeNode-cT6BIWvz.js → LpFileTreeNode-4dVmFHb3.js} +116 -34
- package/dist/chunks/{LpFormField-Ch69Jd-X.js → LpFormField-BKYn9dyP.js} +3 -3
- package/dist/chunks/{LpFrame-BVQCQLDI.js → LpFrame-Bv5Fphte.js} +25 -11
- package/dist/chunks/{LpHintExample-9Py0wc-L.js → LpHintExample-YzCXiSUp.js} +1 -1
- package/dist/chunks/{LpHintLayer-CgObdUsM.js → LpHintLayer-BeKRsRon.js} +2 -2
- package/dist/chunks/{LpHints-Bz-BlaSl.js → LpHints-qf3xYsza.js} +3 -3
- package/dist/chunks/{LpHoverCard-spGxyw7T.js → LpHoverCard-DanH3Nz1.js} +23 -5
- package/dist/chunks/{LpIcon--5WSb3jJ.js → LpIcon-C6JpQ5td.js} +6 -3
- package/dist/chunks/{LpIdenticon-BzdC_qz9.js → LpIdenticon-Dbbr4fvt.js} +2 -1
- package/dist/chunks/{LpInfraNode-46XOCkfq.js → LpInfraNode-BAU40Km2.js} +2 -2
- package/dist/chunks/{LpInput-Tw-yxT4I.js → LpInput-DL6HEJdi.js} +16 -28
- package/dist/chunks/LpInspector-CuoMAhiw.js +209 -0
- package/dist/chunks/{LpLightbox-B95yu22B.js → LpLightbox-xvpQ64MM.js} +57 -32
- package/dist/chunks/{LpLoader-DVwkOmt9.js → LpLoader-Bf1yZwaU.js} +1 -1
- package/dist/chunks/LpLogInspector-6cNnXqp4.js +119 -0
- package/dist/chunks/{LpLogViewer-ngqkns4m.js → LpLogViewer-Dvb1E9_G.js} +234 -53
- package/dist/chunks/{LpMapPicker-DRGgh89B.js → LpMapPicker-D5_YLLBC.js} +4 -3
- package/dist/chunks/{LpMasonry--k0571qG.js → LpMasonry-DPYekFxs.js} +8 -5
- package/dist/chunks/{LpMediaGallery-Bkram-MO.js → LpMediaGallery-Df-tiWeq.js} +3 -3
- package/dist/chunks/{LpModal-CoGhLTyH.js → LpModal-DrtQ_1A2.js} +11 -13
- package/dist/chunks/{LpModalNav-BGvs2y5Q.js → LpModalNav-DkmGCnZE.js} +11 -37
- package/dist/chunks/{LpNotificationBell-B0034Lk-.js → LpNotificationBell-D_wklO1m.js} +9 -9
- package/dist/chunks/{LpNumberField-e0IBkWU1.js → LpNumberField-CNHsmSDZ.js} +7 -16
- package/dist/chunks/{LpOtpInput-CeBPsM7D.js → LpOtpInput-BRpLBbOD.js} +2 -2
- package/dist/chunks/{LpPagination-BIIiYHXR.js → LpPagination-snQ020xQ.js} +6 -4
- package/dist/chunks/{LpPaletteTheme-DiLYKQiZ.js → LpPaletteTheme-dVtxHx-F.js} +4 -4
- package/dist/chunks/{LpPasswordInput-BkHKQDhM.js → LpPasswordInput-B-zD6tUS.js} +2 -2
- package/dist/chunks/{LpPhoneInput-CETEp5W7.js → LpPhoneInput-BSL7NX4z.js} +15 -26
- package/dist/chunks/{LpPie-DrZepi0p.js → LpPie-9t_guO49.js} +22 -21
- package/dist/chunks/{LpPipeline-B3aOVOkV.js → LpPipeline-rjXvEDRJ.js} +16 -7
- package/dist/chunks/{LpPopover-DmZ3wUtP.js → LpPopover-BQSuxtai.js} +10 -1
- package/dist/chunks/{LpProgress-Yr6ONG5t.js → LpProgress-D_MSjowb.js} +2 -1
- package/dist/chunks/{LpQuota-Dk2MyI2Z.js → LpQuota-CgWPgdVt.js} +1 -1
- package/dist/chunks/{LpRadioGroup-ggaPL92T.js → LpRadioGroup-BrazjLY_.js} +4 -4
- package/dist/chunks/{LpRangeCalendar-CYYUYqJ7.js → LpRangeCalendar-BrqlGZzE.js} +1 -1
- package/dist/chunks/{LpRangeSlider-CM-0ZITZ.js → LpRangeSlider-fz61tzc-.js} +5 -9
- package/dist/chunks/{LpRelativeTime-DwgCb5-8.js → LpRelativeTime-BovUk8MP.js} +1 -1
- package/dist/chunks/{LpRepeater-D7ZmnIYd.js → LpRepeater-BkJHSPI1.js} +3 -3
- package/dist/chunks/{LpRevealOnScroll-DcQjexLy.js → LpRevealOnScroll-CPwyiQAr.js} +1 -1
- package/dist/chunks/{LpScramble-Bn9OoOtC.js → LpScramble-DsE77iVp.js} +1 -1
- package/dist/chunks/{LpScrollArea-MyEnVB_5.js → LpScrollArea-ay4Xo_hg.js} +22 -10
- package/dist/chunks/{LpSecretField-BbmqM9ye.js → LpSecretField-DBvU6iAw.js} +10 -9
- package/dist/chunks/{LpSection-DFK_uoJE.js → LpSection-BfteipxU.js} +1 -1
- package/dist/chunks/{LpSegmented-CeACsMMA.js → LpSegmented-DbEJhbv-.js} +8 -10
- package/dist/chunks/{LpSelect-Cxq4yBGd.js → LpSelect-Y-iuSymW.js} +47 -30
- package/dist/chunks/{LpShaderBackdrop-Bote0iuy.js → LpShaderBackdrop-wQygYb5h.js} +13 -10
- package/dist/chunks/{LpShift-CCq7dofl.js → LpShift-DAgS_d2x.js} +18 -15
- package/dist/chunks/{LpSidebar-DzE1783C.js → LpSidebar-kSkpPh3-.js} +74 -87
- package/dist/chunks/{LpSidebarNav-DE3PhXVP.js → LpSidebarNav-C2mvqrY2.js} +8 -6
- package/dist/chunks/{LpSidebarRow-BRYhNDSo.js → LpSidebarRow-eRP4Q31q.js} +6 -5
- package/dist/chunks/{LpSlider-DxYoCJJO.js → LpSlider-A4ixovgS.js} +5 -9
- package/dist/chunks/{LpSpotlight-4F3NeUMY.js → LpSpotlight-DwxkhFgR.js} +2 -1
- package/dist/chunks/{LpStat-f2LfDCJ4.js → LpStat-pMNZgFcq.js} +2 -2
- package/dist/chunks/{LpStatus-DglxttQ7.js → LpStatus-DGJFwk5F.js} +2 -2
- package/dist/chunks/{LpStepMark-DpzKVyh8.js → LpStepMark-Dw2MRTrt.js} +2 -2
- package/dist/chunks/{LpStepper-DpsocBNJ.js → LpStepper-DNnh7lCu.js} +1 -1
- package/dist/chunks/{LpSwap-C96c0LWh.js → LpSwap-M7nFeW3C.js} +1 -1
- package/dist/chunks/{LpSwitch-BnXd1llc.js → LpSwitch-DnC2-0aV.js} +3 -3
- package/dist/chunks/{LpTabFace-DPCwKkH2.js → LpTabFace-DQoV8mQG.js} +2 -2
- package/dist/chunks/{LpTableFilter-CiVBpaq0.js → LpTableFilter-DgARTsA1.js} +4 -4
- package/dist/chunks/{LpTableOfContents-BN5zvpnx.js → LpTableOfContents-CKkWEK6R.js} +14 -9
- package/dist/chunks/{LpTagsInput-C-mDG648.js → LpTagsInput-Dt0mteSj.js} +19 -27
- package/dist/chunks/{LpTextarea-TE-yZv2U.js → LpTextarea-Co0b9PVx.js} +8 -16
- package/dist/chunks/LpThemeProvider-XK6ZeWAE.js +81 -0
- package/dist/chunks/{LpThemeStudio-BpORDvH6.js → LpThemeStudio-DzYfE-5k.js} +12 -195
- package/dist/chunks/{LpThemeSwitcher-BnEn_mvf.js → LpThemeSwitcher-CFLkdbBL.js} +8 -6
- package/dist/chunks/{LpTimeField-BawSVsmt.js → LpTimeField-DeOcKWJq.js} +6 -9
- package/dist/chunks/{LpToaster-IwTXjbbU.js → LpToaster-QFj0P-5m.js} +10 -8
- package/dist/chunks/{LpTooltip-BcBvIx4z.js → LpTooltip-BJf3lZMq.js} +51 -19
- package/dist/chunks/LpTopologyCanvas-BOHHHZ_6.js +673 -0
- package/dist/chunks/{LpTour-BZq-mUMv.js → LpTour-ClKYhx4h.js} +7 -5
- package/dist/chunks/{LpTruncate-CflAIwiJ.js → LpTruncate-C6u3gjc6.js} +6 -5
- package/dist/chunks/{LpTypewriter-BCL_a6wE.js → LpTypewriter-CZIzpdbe.js} +2 -1
- package/dist/chunks/{LpUptimeBar-DqNvvMBK.js → LpUptimeBar-BnYmR2rj.js} +3 -3
- package/dist/chunks/{LpVideoBackdrop-DS1wGv-X.js → LpVideoBackdrop-Ct4St4ZL.js} +10 -13
- package/dist/chunks/LpWindow-B8YSRVTH.js +297 -0
- package/dist/chunks/LpWorkspaceSwitcher-D0e9upAy.js +139 -0
- package/dist/chunks/{MenuTitle-BmCNNTKH.js → MenuTitle-Bh5dAdV1.js} +1 -1
- package/dist/chunks/{OptionContent-22UT8zLn.js → OptionContent-CGb8QlHA.js} +1 -1
- package/dist/chunks/{PickerField-Bfh8id3d.js → PickerField-BM1dyafh.js} +4 -4
- package/dist/chunks/{RevealToggle-BEit1n6Z.js → RevealToggle-CCPDE8Mv.js} +3 -3
- package/dist/chunks/SliderRail-DhPREa_R.js +18 -0
- package/dist/chunks/{TourCard-DNclH3u_.js → TourCard-DAzTYfav.js} +4 -4
- package/dist/chunks/{icons-DMITlfw5.js → icons-CYfcpSDS.js} +26 -10
- package/dist/component-names.d.ts +1 -1
- package/dist/components/AppShellContextNav.vue.d.ts +13 -0
- package/dist/components/AppShellContextNav.vue.js +4 -0
- package/dist/components/ChartRangeSelector.vue.d.ts +21 -0
- package/dist/components/ChartRangeSelector.vue.js +4 -0
- package/dist/components/ContextMenuItems.vue.js +1 -1
- package/dist/components/DropzoneLinkField.vue.d.ts +2 -2
- package/dist/components/DropzoneLinkField.vue.js +1 -1
- package/dist/components/FieldWrapper.vue.js +1 -1
- package/dist/components/IconCloseButton.vue.d.ts +7 -0
- package/dist/components/IconCloseButton.vue.js +4 -0
- package/dist/components/LayoutCanvas.vue.js +1 -1
- package/dist/components/LayoutNode.vue.js +1 -1
- package/dist/components/LpActionBar.vue.js +1 -1
- package/dist/components/LpActivityLine.vue.js +1 -1
- package/dist/components/LpAddressInput.vue.js +1 -1
- package/dist/components/LpAlert.vue.js +1 -1
- package/dist/components/LpAppShell.vue.d.ts +110 -2
- package/dist/components/LpAppShell.vue.js +1 -1
- package/dist/components/LpAutocomplete.vue.js +1 -1
- package/dist/components/LpAvatar.vue.js +1 -1
- package/dist/components/LpBadge.vue.js +1 -1
- package/dist/components/LpBottomNav.vue.d.ts +5 -0
- package/dist/components/LpBottomNav.vue.js +1 -1
- package/dist/components/LpBreadcrumbs.vue.js +1 -1
- package/dist/components/LpButton.vue.d.ts +14 -2
- package/dist/components/LpButton.vue.js +1 -1
- package/dist/components/LpCalendar.vue.js +1 -1
- package/dist/components/LpCard.vue.js +1 -1
- package/dist/components/LpChart.vue.d.ts +74 -2
- package/dist/components/LpChart.vue.js +326 -85
- package/dist/components/LpCheckbox.vue.d.ts +6 -2
- package/dist/components/LpCheckbox.vue.js +1 -1
- package/dist/components/LpCodeBlock.vue.js +1 -1
- package/dist/components/LpCodeDisplay.vue.js +1 -1
- package/dist/components/LpCollapse.vue.js +1 -1
- package/dist/components/LpColorPicker.vue.js +1 -1
- package/dist/components/LpCommandPalette.vue.d.ts +8 -0
- package/dist/components/LpCommandPalette.vue.js +107 -56
- package/dist/components/LpCommandScope.vue.js +1 -1
- 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/LpContextSwitcher.vue.js +1 -1
- package/dist/components/LpCopyButton.vue.js +1 -1
- package/dist/components/LpCountdown.vue.js +1 -1
- package/dist/components/LpDataList.vue.d.ts +1 -1
- package/dist/components/LpDataList.vue.js +1 -1
- package/dist/components/LpDatePicker.vue.d.ts +3 -15
- package/dist/components/LpDatePicker.vue.js +1 -1
- package/dist/components/LpDateRangePicker.vue.d.ts +3 -13
- package/dist/components/LpDateRangePicker.vue.js +1 -1
- package/dist/components/LpDisclosure.vue.js +1 -1
- package/dist/components/LpDock.vue.js +21 -18
- package/dist/components/LpDrawer.vue.d.ts +1 -1
- package/dist/components/LpDrawer.vue.js +1 -1
- package/dist/components/LpDropdownMenu.vue.js +1 -1
- package/dist/components/LpDropzone.vue.js +14 -11
- package/dist/components/LpEditable.vue.js +1 -1
- package/dist/components/LpEmptyState.vue.js +1 -1
- package/dist/components/LpFieldNotice.vue.js +1 -1
- package/dist/components/LpFileTree.vue.d.ts +96 -6
- package/dist/components/LpFileTree.vue.js +1 -1
- package/dist/components/LpFileTreeNode.vue.d.ts +48 -0
- package/dist/components/LpFileTreeNode.vue.js +1 -1
- package/dist/components/LpFormField.vue.js +1 -1
- package/dist/components/LpFrame.vue.js +1 -1
- package/dist/components/LpGauge.vue.d.ts +1 -1
- 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.js +1 -1
- package/dist/components/LpIcon.vue.d.ts +2 -0
- package/dist/components/LpIcon.vue.js +1 -1
- package/dist/components/LpIdenticon.vue.js +1 -1
- package/dist/components/LpImageEditor.vue.js +7 -6
- package/dist/components/LpInfraNode.vue.js +1 -1
- package/dist/components/LpInput.vue.d.ts +1 -1
- package/dist/components/LpInput.vue.js +1 -1
- package/dist/components/LpInspector.vue.d.ts +87 -0
- package/dist/components/LpInspector.vue.js +4 -0
- package/dist/components/LpLightbox.vue.d.ts +8 -0
- package/dist/components/LpLightbox.vue.js +1 -1
- package/dist/components/LpLoader.vue.d.ts +1 -1
- package/dist/components/LpLoader.vue.js +1 -1
- package/dist/components/LpLogInspector.vue.d.ts +18 -0
- package/dist/components/LpLogInspector.vue.js +4 -0
- package/dist/components/LpLogViewer.vue.d.ts +93 -0
- package/dist/components/LpLogViewer.vue.js +1 -1
- package/dist/components/LpMapPicker.vue.js +1 -1
- package/dist/components/LpMasonry.vue.js +1 -1
- package/dist/components/LpMediaGallery.vue.js +1 -1
- package/dist/components/LpModal.vue.d.ts +4 -2
- package/dist/components/LpModal.vue.js +1 -1
- package/dist/components/LpModalNav.vue.d.ts +5 -5
- package/dist/components/LpModalNav.vue.js +1 -1
- package/dist/components/LpNotificationBell.vue.d.ts +2 -2
- package/dist/components/LpNotificationBell.vue.js +1 -1
- package/dist/components/LpNumberField.vue.js +1 -1
- 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/LpPaletteTheme.vue.js +1 -1
- package/dist/components/LpPasswordInput.vue.js +1 -1
- package/dist/components/LpPhoneInput.vue.js +1 -1
- package/dist/components/LpPie.vue.d.ts +2 -2
- package/dist/components/LpPie.vue.js +1 -1
- package/dist/components/LpPipeline.vue.d.ts +4 -0
- package/dist/components/LpPipeline.vue.js +1 -1
- package/dist/components/LpPopover.vue.d.ts +7 -3
- package/dist/components/LpPopover.vue.js +1 -1
- package/dist/components/LpProgress.vue.d.ts +1 -1
- package/dist/components/LpProgress.vue.js +1 -1
- package/dist/components/LpQuota.vue.js +1 -1
- 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.js +1 -1
- package/dist/components/LpRepeater.vue.js +1 -1
- package/dist/components/LpRevealOnScroll.vue.js +1 -1
- package/dist/components/LpScramble.vue.js +1 -1
- package/dist/components/LpScrollArea.vue.js +1 -1
- package/dist/components/LpSecretField.vue.js +1 -1
- package/dist/components/LpSection.vue.js +1 -1
- package/dist/components/LpSegmented.vue.js +1 -1
- package/dist/components/LpSelect.vue.js +1 -1
- package/dist/components/LpShaderBackdrop.vue.js +1 -1
- package/dist/components/LpShift.vue.js +1 -1
- package/dist/components/LpShortcutsDialog.vue.js +1 -1
- package/dist/components/LpSidebar.vue.d.ts +1 -1
- package/dist/components/LpSidebar.vue.js +1 -1
- package/dist/components/LpSidebarNav.vue.js +1 -1
- package/dist/components/LpSidebarRow.vue.js +1 -1
- package/dist/components/LpSlider.vue.js +1 -1
- package/dist/components/LpSparkline.vue.d.ts +1 -1
- package/dist/components/LpSpotlight.vue.js +1 -1
- package/dist/components/LpStat.vue.js +1 -1
- package/dist/components/LpStatus.vue.js +1 -1
- package/dist/components/LpStepMark.vue.js +1 -1
- package/dist/components/LpStepper.vue.js +1 -1
- package/dist/components/LpSwap.vue.js +1 -1
- package/dist/components/LpSwitch.vue.js +1 -1
- package/dist/components/LpTabFace.vue.js +1 -1
- package/dist/components/LpTable.vue.d.ts +132 -0
- package/dist/components/LpTable.vue.js +547 -135
- package/dist/components/LpTableFilter.vue.js +1 -1
- package/dist/components/LpTableOfContents.vue.js +1 -1
- package/dist/components/LpTabs.vue.js +6 -5
- package/dist/components/LpTagsInput.vue.js +1 -1
- package/dist/components/LpTextarea.vue.js +1 -1
- package/dist/components/LpThemeProvider.vue.d.ts +2 -0
- package/dist/components/LpThemeProvider.vue.js +1 -1
- package/dist/components/LpThemeStudio.vue.js +1 -1
- package/dist/components/LpThemeSwitcher.vue.js +1 -1
- package/dist/components/LpTimeField.vue.js +1 -1
- package/dist/components/LpToaster.vue.js +1 -1
- package/dist/components/LpTooltip.vue.js +1 -1
- package/dist/components/LpTopologyCanvas.vue.d.ts +131 -5
- package/dist/components/LpTopologyCanvas.vue.js +1 -1
- package/dist/components/LpTour.vue.js +1 -1
- package/dist/components/LpTruncate.vue.js +1 -1
- package/dist/components/LpTypewriter.vue.js +1 -1
- package/dist/components/LpUptimeBar.vue.js +1 -1
- package/dist/components/LpVideoBackdrop.vue.js +1 -1
- package/dist/components/LpWindow.vue.d.ts +99 -0
- package/dist/components/LpWindow.vue.js +4 -0
- package/dist/components/LpWorkspaceSwitcher.vue.d.ts +18 -0
- package/dist/components/LpWorkspaceSwitcher.vue.js +4 -0
- package/dist/components/MenuTitle.vue.js +1 -1
- package/dist/components/OptionContent.vue.js +1 -1
- package/dist/components/PickerField.vue.d.ts +2 -2
- package/dist/components/PickerField.vue.js +1 -1
- package/dist/components/RevealToggle.vue.js +1 -1
- package/dist/components/SliderRail.vue.d.ts +3 -0
- package/dist/components/SliderRail.vue.js +4 -0
- package/dist/components/TourCard.vue.js +1 -1
- package/dist/components/address.js +2 -1
- package/dist/components/appShell.d.ts +36 -0
- package/dist/components/appShell.js +30 -0
- package/dist/components/calendar.d.ts +12 -3
- package/dist/components/calendar.js +2 -5
- package/dist/components/chart.d.ts +21 -0
- package/dist/components/chart.js +4 -3
- package/dist/components/chartWindow.d.ts +57 -0
- package/dist/components/chartWindow.js +136 -0
- package/dist/components/color.js +1 -1
- package/dist/components/commandPalette.d.ts +16 -2
- package/dist/components/commandPalette.js +39 -4
- package/dist/components/controlSize.d.ts +5 -0
- package/dist/components/controlSize.js +8 -0
- package/dist/components/dropdown.d.ts +5 -0
- package/dist/components/dropdown.js +2 -0
- package/dist/components/exportData.d.ts +6 -1
- package/dist/components/exportData.js +25 -18
- package/dist/components/fileTree.d.ts +67 -0
- package/dist/components/fileTree.js +141 -1
- package/dist/components/identicon.js +3 -2
- package/dist/components/logTools.d.ts +93 -0
- package/dist/components/logTools.js +210 -0
- package/dist/components/menuWhen.js +1 -1
- package/dist/components/meter.js +2 -1
- package/dist/components/pipeline.d.ts +2 -0
- package/dist/components/pipeline.js +5 -0
- package/dist/components/relativeTime.js +2 -1
- package/dist/components/reveal.js +2 -1
- package/dist/components/select.d.ts +5 -0
- package/dist/components/select.js +10 -0
- package/dist/components/sidebar.d.ts +1 -0
- package/dist/components/tableFeatures.d.ts +58 -0
- package/dist/components/tableFeatures.js +87 -0
- package/dist/components/topologyGraph.d.ts +164 -0
- package/dist/components/topologyGraph.js +416 -0
- package/dist/components/tour.js +5 -3
- package/dist/components/videoBackdrop.js +7 -6
- package/dist/composables/clamp.d.ts +2 -0
- package/dist/composables/clamp.js +4 -0
- package/dist/composables/devWarn.d.ts +3 -0
- package/dist/composables/devWarn.js +14 -0
- package/dist/composables/easing.d.ts +13 -4
- package/dist/composables/easing.js +16 -10
- package/dist/composables/overlayHistory.js +14 -1
- package/dist/composables/pointerDrag.d.ts +15 -0
- package/dist/composables/pointerDrag.js +40 -0
- package/dist/composables/propCheck.d.ts +10 -0
- package/dist/composables/propCheck.js +78 -0
- package/dist/composables/realm.d.ts +6 -0
- package/dist/composables/realm.js +23 -0
- package/dist/composables/scroll.js +4 -2
- package/dist/composables/scrollMemory.d.ts +12 -1
- package/dist/composables/scrollMemory.js +36 -12
- package/dist/composables/spatialNav.js +2 -1
- package/dist/composables/textEntry.d.ts +17 -0
- package/dist/composables/textEntry.js +19 -0
- package/dist/composables/useAsyncTask.d.ts +6 -0
- package/dist/composables/useChartSync.d.ts +5 -0
- package/dist/composables/useChartSync.js +33 -0
- package/dist/composables/useCloseGuard.d.ts +3 -1
- package/dist/composables/useCloseGuard.js +6 -3
- package/dist/composables/useCommands.d.ts +50 -0
- package/dist/composables/useCommands.js +66 -0
- package/dist/composables/useField.d.ts +37 -0
- package/dist/composables/useField.js +27 -2
- package/dist/composables/useFitScale.js +4 -1
- package/dist/composables/useFormDraft.d.ts +13 -2
- package/dist/composables/useFormDraft.js +17 -9
- package/dist/composables/useHintSystem.js +2 -2
- package/dist/composables/useHotkeys.js +11 -32
- package/dist/composables/useInView.js +2 -1
- package/dist/composables/useInputFilter.js +7 -5
- package/dist/composables/useInputMask.js +5 -3
- package/dist/composables/useLinkedView.d.ts +97 -0
- package/dist/composables/useLinkedView.js +139 -0
- package/dist/composables/useOptimisticToggle.d.ts +3 -1
- package/dist/composables/useOptimisticToggle.js +2 -1
- package/dist/composables/useOverlayHistory.d.ts +7 -0
- package/dist/composables/useOverlayHistory.js +16 -2
- package/dist/composables/usePaintSelect.js +18 -14
- package/dist/composables/usePaletteCommands.d.ts +7 -0
- package/dist/composables/usePaletteCommands.js +12 -1
- package/dist/composables/usePersisted.d.ts +10 -0
- package/dist/composables/usePersisted.js +1 -1
- package/dist/composables/usePillTransition.d.ts +2 -2
- package/dist/composables/usePillTransition.js +5 -5
- package/dist/composables/useResizeObserver.js +2 -1
- package/dist/composables/useReveal.js +2 -1
- package/dist/composables/useRovingFocus.d.ts +2 -2
- package/dist/composables/useRovingFocus.js +9 -11
- package/dist/composables/useScramble.js +7 -1
- package/dist/composables/useShift.js +8 -6
- package/dist/composables/useTilt.js +2 -1
- package/dist/composables/useTween.js +9 -5
- package/dist/composables/useView.d.ts +1 -0
- package/dist/composables/useView.js +14 -2
- package/dist/composables/useZoomPan.js +2 -4
- package/dist/composables/windowing.d.ts +40 -0
- package/dist/composables/windowing.js +118 -0
- package/dist/icons-all.js +1 -1
- package/dist/icons.d.ts +4 -0
- package/dist/index.d.ts +30 -5
- package/dist/index.js +310 -264
- package/dist/layout/tree.js +19 -15
- package/dist/layout/useLayout.d.ts +2 -0
- package/dist/layout/useLayout.js +5 -1
- package/dist/layout/useWorkspaces.d.ts +52 -0
- package/dist/layout/useWorkspaces.js +140 -0
- package/dist/{chunks/backdrop-Dkf2vM81.js → theme/backdrop.js} +5 -5
- package/dist/theme/config.js +25 -0
- package/dist/theme/define.js +61 -0
- package/dist/{chunks/palette-Co8tSASo.js → theme/palette.js} +2 -2
- package/dist/theme/presets.js +239 -0
- package/dist/theme/studio.js +134 -0
- package/dist/theme/tokens.js +63 -0
- package/dist/theme/useTheme.d.ts +3 -2
- package/dist/theme/useTheme.js +325 -0
- package/package.json +8 -1
- package/src/component-names.ts +5 -1
- package/src/components/AppShellContextNav.vue +44 -0
- package/src/components/ChartRangeSelector.vue +120 -0
- package/src/components/IconCloseButton.vue +21 -0
- package/src/components/LayoutCanvas.vue +3 -0
- package/src/components/LayoutNode.vue +37 -38
- package/src/components/LpActivityLine.vue +4 -2
- package/src/components/LpAddressInput.vue +3 -3
- package/src/components/LpAppShell.vue +362 -24
- package/src/components/LpAutocomplete.vue +18 -30
- package/src/components/LpBottomNav.vue +9 -1
- package/src/components/LpBreadcrumbs.vue +2 -1
- package/src/components/LpButton.vue +11 -4
- package/src/components/LpChart.vue +336 -37
- package/src/components/LpCheckbox.vue +43 -9
- package/src/components/LpCodeBlock.vue +17 -23
- package/src/components/LpCollapse.vue +5 -4
- package/src/components/LpColorPicker.vue +8 -9
- package/src/components/LpCommandPalette.vue +133 -50
- package/src/components/LpContextMenu.vue +15 -13
- package/src/components/LpCountdown.vue +2 -1
- package/src/components/LpDataList.vue +13 -1
- package/src/components/LpDatePicker.vue +5 -17
- package/src/components/LpDateRangePicker.vue +5 -16
- package/src/components/LpDock.vue +25 -16
- package/src/components/LpDrawer.vue +70 -61
- package/src/components/LpDropdownMenu.vue +6 -10
- package/src/components/LpDropzone.vue +12 -7
- package/src/components/LpEditable.vue +6 -2
- package/src/components/LpFileTree.vue +507 -66
- package/src/components/LpFileTreeNode.vue +106 -5
- package/src/components/LpFormField.vue +1 -1
- package/src/components/LpFrame.vue +33 -13
- package/src/components/LpHoverCard.vue +30 -5
- package/src/components/LpIcon.vue +6 -2
- package/src/components/LpIdenticon.vue +2 -1
- package/src/components/LpImageEditor.vue +5 -2
- package/src/components/LpInput.vue +15 -23
- package/src/components/LpInspector.vue +197 -0
- package/src/components/LpLightbox.vue +74 -29
- package/src/components/LpLogInspector.vue +85 -0
- package/src/components/LpLogViewer.vue +239 -29
- package/src/components/LpMapPicker.vue +2 -1
- package/src/components/LpMasonry.vue +8 -5
- package/src/components/LpModal.vue +12 -12
- package/src/components/LpModalNav.vue +2 -21
- package/src/components/LpNumberField.vue +6 -15
- package/src/components/LpOtpInput.vue +2 -2
- package/src/components/LpPagination.vue +5 -3
- package/src/components/LpPhoneInput.vue +8 -19
- package/src/components/LpPie.vue +25 -23
- package/src/components/LpPipeline.vue +14 -1
- package/src/components/LpPopover.vue +23 -2
- package/src/components/LpProgress.vue +2 -1
- package/src/components/LpRadioGroup.vue +2 -2
- package/src/components/LpRangeSlider.vue +5 -6
- package/src/components/LpRevealOnScroll.vue +1 -1
- package/src/components/LpScrollArea.vue +28 -11
- package/src/components/LpSecretField.vue +2 -1
- package/src/components/LpSegmented.vue +6 -8
- package/src/components/LpSelect.vue +54 -24
- package/src/components/LpShaderBackdrop.vue +12 -9
- package/src/components/LpShift.vue +18 -15
- package/src/components/LpSidebar.vue +77 -74
- package/src/components/LpSidebarNav.vue +3 -2
- package/src/components/LpSidebarRow.vue +2 -1
- package/src/components/LpSlider.vue +5 -6
- package/src/components/LpSpotlight.vue +2 -1
- package/src/components/LpSwitch.vue +5 -3
- package/src/components/LpTable.vue +609 -93
- package/src/components/LpTableFilter.vue +1 -1
- package/src/components/LpTableOfContents.vue +16 -9
- package/src/components/LpTabs.vue +2 -1
- package/src/components/LpTagsInput.vue +12 -19
- package/src/components/LpTextarea.vue +5 -11
- package/src/components/LpThemeProvider.vue +29 -13
- package/src/components/LpTimeField.vue +4 -7
- package/src/components/LpToaster.vue +7 -6
- package/src/components/LpTooltip.vue +62 -18
- package/src/components/LpTopologyCanvas.vue +567 -42
- package/src/components/LpTour.vue +7 -5
- package/src/components/LpTruncate.vue +4 -3
- package/src/components/LpTypewriter.vue +2 -1
- package/src/components/LpVideoBackdrop.vue +11 -13
- package/src/components/LpWindow.vue +373 -0
- package/src/components/LpWorkspaceSwitcher.vue +116 -0
- package/src/components/PickerField.vue +2 -2
- package/src/components/SliderRail.vue +10 -0
- package/src/components/address.ts +3 -1
- package/src/components/appShell.ts +74 -0
- package/src/components/calendar.ts +12 -5
- package/src/components/chart.ts +27 -3
- package/src/components/chartWindow.ts +198 -0
- package/src/components/color.ts +2 -1
- package/src/components/commandPalette.ts +66 -5
- package/src/components/controlSize.ts +6 -0
- package/src/components/dropdown.ts +3 -0
- package/src/components/exportData.ts +33 -18
- package/src/components/fileTree.ts +215 -0
- package/src/components/identicon.ts +4 -2
- package/src/components/logTools.ts +298 -0
- package/src/components/meter.ts +2 -1
- package/src/components/pipeline.ts +6 -0
- package/src/components/relativeTime.ts +2 -1
- package/src/components/reveal.ts +3 -1
- package/src/components/select.ts +14 -0
- package/src/components/sidebar.ts +1 -0
- package/src/components/tableFeatures.ts +149 -0
- package/src/components/topologyGraph.ts +655 -0
- package/src/components/tour.ts +5 -3
- package/src/components/videoBackdrop.ts +7 -6
- package/src/composables/clamp.ts +2 -0
- package/src/composables/devWarn.ts +19 -0
- package/src/composables/easing.ts +37 -12
- package/src/composables/overlayHistory.ts +24 -0
- package/src/composables/pointerDrag.ts +54 -0
- package/src/composables/propCheck.ts +90 -0
- package/src/composables/realm.ts +25 -0
- package/src/composables/scroll.ts +4 -2
- package/src/composables/scrollMemory.ts +56 -14
- package/src/composables/spatialNav.ts +2 -1
- package/src/composables/textEntry.ts +33 -0
- package/src/composables/useAsyncTask.ts +6 -0
- package/src/composables/useChartSync.ts +52 -0
- package/src/composables/useCloseGuard.ts +22 -10
- package/src/composables/useCommands.ts +123 -0
- package/src/composables/useField.ts +41 -2
- package/src/composables/useFitScale.ts +4 -1
- package/src/composables/useFormDraft.ts +38 -14
- package/src/composables/useHintSystem.ts +2 -2
- package/src/composables/useHotkeys.ts +19 -48
- package/src/composables/useInView.ts +2 -1
- package/src/composables/useInputFilter.ts +8 -5
- package/src/composables/useInputMask.ts +8 -3
- package/src/composables/useLinkedView.ts +222 -0
- package/src/composables/useOptimisticToggle.ts +7 -1
- package/src/composables/useOverlayHistory.ts +20 -0
- package/src/composables/usePaintSelect.ts +20 -14
- package/src/composables/usePaletteCommands.ts +13 -0
- package/src/composables/usePersisted.ts +10 -0
- package/src/composables/usePillTransition.ts +9 -6
- package/src/composables/useResizeObserver.ts +2 -1
- package/src/composables/useReveal.ts +2 -1
- package/src/composables/useRovingFocus.ts +11 -14
- package/src/composables/useScramble.ts +12 -1
- package/src/composables/useShift.ts +8 -6
- package/src/composables/useTilt.ts +2 -1
- package/src/composables/useTween.ts +10 -5
- package/src/composables/useView.ts +17 -3
- package/src/composables/useZoomPan.ts +2 -5
- package/src/composables/windowing.ts +190 -0
- package/src/icons.ts +27 -6
- package/src/index.ts +41 -4
- package/src/kit-icons.ts +1 -1
- package/src/layout/tree.ts +31 -16
- package/src/layout/useLayout.ts +6 -0
- package/src/layout/useWorkspaces.ts +234 -0
- package/src/nuxt.ts +9 -1
- package/src/runtime/propCheck.plugin.ts +10 -0
- package/src/theme/studio.ts +7 -5
- package/src/theme/useTheme.ts +89 -15
- package/src/tokens/tokens.css +8 -1
- package/dist/assets/LpTabs-CJ0rYQbx.css +0 -18
- package/dist/chunks/LpAppShell-Dgejipzz.js +0 -319
- package/dist/chunks/LpFileTree-CooHinsC.js +0 -425
- package/dist/chunks/LpThemeProvider-8MG6yqU9.js +0 -640
- package/dist/chunks/LpTopologyCanvas-B1gIbS0n.js +0 -298
|
@@ -7,13 +7,22 @@ export default { inheritAttrs: false }
|
|
|
7
7
|
|
|
8
8
|
<script setup lang="ts">
|
|
9
9
|
/*
|
|
10
|
-
* Full application shell: a
|
|
11
|
-
*
|
|
10
|
+
* Full application shell: the side navigation rail, a top header bar and the
|
|
11
|
+
* page, which is what scrolls.
|
|
12
|
+
*
|
|
13
|
+
* By default the page is the document: it scrolls the window, and the rail,
|
|
14
|
+
* the header and the bottom bar are sticky beside and above it. So everything
|
|
15
|
+
* a browser does with a long page keeps working — a full-page screenshot,
|
|
16
|
+
* printing, the phone's address bar folding away, pull to refresh, a tap on
|
|
17
|
+
* the status bar. `scroll="region"` keeps the older frame instead: the shell
|
|
18
|
+
* is exactly the viewport and the page scrolls inside main (LpScrollArea),
|
|
19
|
+
* which suits a shell embedded in a page of its own. A `fullBleed` page is
|
|
20
|
+
* held to the viewport in either.
|
|
12
21
|
*
|
|
13
22
|
* It owns the things every product's cabinet/console layout was re-implementing
|
|
14
23
|
* by hand — and getting subtly wrong:
|
|
15
|
-
* - the rail is full viewport height and never scrolls with the page
|
|
16
|
-
*
|
|
24
|
+
* - the rail is full viewport height and never scrolls with the page, so the
|
|
25
|
+
* sidebar footer stays pinned;
|
|
17
26
|
* - a responsive burger that drives LpSidebar's mobile drawer;
|
|
18
27
|
* - a default `isActive` (path prefix-match) and a default page title derived
|
|
19
28
|
* from the nav items, so the header title and the active pill never drift.
|
|
@@ -30,10 +39,28 @@ export default { inheritAttrs: false }
|
|
|
30
39
|
* #header-title (override the computed title), and the default slot (page body).
|
|
31
40
|
* Overlays that aren't part of the frame (command palette, toaster) live in the
|
|
32
41
|
* host next to <LpAppShell>.
|
|
42
|
+
*
|
|
43
|
+
* Every option below is off until asked for, and the shell's markup without
|
|
44
|
+
* them is what it always was: `headerCollapse`, `backToTop`, `density`,
|
|
45
|
+
* `pageTransition`, `safeArea`, the #aside region and `adaptiveNav`.
|
|
33
46
|
*/
|
|
34
|
-
import { computed, onMounted, ref, useId, watch } from "vue"
|
|
47
|
+
import { computed, nextTick, onBeforeUnmount, onMounted, ref, useId, useSlots, watch } from "vue"
|
|
48
|
+
import { easingToken, durationToken, prefersReducedMotion } from "../composables/easing"
|
|
35
49
|
import { useLabels } from "../composables/useLpConfig"
|
|
36
50
|
import { useScrollMemory } from "../composables/scrollMemory"
|
|
51
|
+
import { nodeWindow, useView, viewWindow } from "../composables/useView"
|
|
52
|
+
import AppShellContextNav from "./AppShellContextNav.vue"
|
|
53
|
+
import {
|
|
54
|
+
contextNavItems,
|
|
55
|
+
DENSITY_CLASS,
|
|
56
|
+
headerCollapsedAfter,
|
|
57
|
+
NAV_BREAKPOINT_PX,
|
|
58
|
+
resolveNavMode,
|
|
59
|
+
type AdaptiveNav,
|
|
60
|
+
type NavBreakpoint,
|
|
61
|
+
type NavMode,
|
|
62
|
+
type ShellDensity,
|
|
63
|
+
} from "./appShell"
|
|
37
64
|
import LpBottomNav from "./LpBottomNav.vue"
|
|
38
65
|
import LpContextSwitcher from "./LpContextSwitcher.vue"
|
|
39
66
|
import LpButton from "./LpButton.vue"
|
|
@@ -46,6 +73,9 @@ import { mergeClass, useMergedAttrs } from "../composables/useMergedClass"
|
|
|
46
73
|
|
|
47
74
|
export type { SidebarItem, SidebarSection } from "./sidebar"
|
|
48
75
|
|
|
76
|
+
/* Past this much scrolled the way back up is worth a button. */
|
|
77
|
+
const BACK_TO_TOP_AFTER_PX = 600
|
|
78
|
+
|
|
49
79
|
const props = withDefaults(
|
|
50
80
|
defineProps<{
|
|
51
81
|
/** Flat items, or sections for grouped nav. Forwarded to LpSidebar. */
|
|
@@ -91,10 +121,19 @@ const props = withDefaults(
|
|
|
91
121
|
* (for a canvas / map / graph that fills the viewport and pans internally).
|
|
92
122
|
*/
|
|
93
123
|
fullBleed?: boolean
|
|
124
|
+
/**
|
|
125
|
+
* What scrolls. `"document"` (the default): the window, with the rail,
|
|
126
|
+
* header and bottom bar sticky; a page that filled main with `h-full`
|
|
127
|
+
* grows with its content now, so a page meant to fill the screen asks for
|
|
128
|
+
* `min-h-[calc(100dvh-4rem)]` or `fullBleed`. `"region"`: the shell is
|
|
129
|
+
* the viewport and the page scrolls inside main. Read once: changing it
|
|
130
|
+
* remounts the page.
|
|
131
|
+
*/
|
|
132
|
+
scroll?: "document" | "region"
|
|
94
133
|
/** Loading skeleton for the nav. */
|
|
95
134
|
loading?: boolean
|
|
96
135
|
/** Text overrides: the burger's name and the skip link. */
|
|
97
|
-
labels?: Partial<{ openMenu: string; skipToContent: string }>
|
|
136
|
+
labels?: Partial<{ openMenu: string; skipToContent: string; backToTop: string; aside: string; contextNav: string }>
|
|
98
137
|
/** Icon-only rail (v-model:compact). Forwarded to LpSidebar. */
|
|
99
138
|
compact?: boolean
|
|
100
139
|
/** The person sizes the rail and folds it to icons. Forwarded to LpSidebar. */
|
|
@@ -123,14 +162,50 @@ const props = withDefaults(
|
|
|
123
162
|
/**
|
|
124
163
|
* On phones, the main pages along the bottom instead of the burger, with
|
|
125
164
|
* "More" for the rest (it opens the drawer). `true` takes the first four
|
|
126
|
-
* pages, a number that many, a list of ids those pages.
|
|
165
|
+
* pages, a number that many, a list of ids those pages. Top-level pages
|
|
166
|
+
* only: an id from `children` is ignored, and such a page stays behind "More".
|
|
127
167
|
*/
|
|
128
168
|
bottomNav?: boolean | number | string[]
|
|
169
|
+
/**
|
|
170
|
+
* The header leaves as the page scrolls down and returns on the way up,
|
|
171
|
+
* giving a small screen its height back. A keyboard user tabbing into it
|
|
172
|
+
* brings it back too. A full-bleed page owns its scrolling, so the header
|
|
173
|
+
* stays there.
|
|
174
|
+
*/
|
|
175
|
+
headerCollapse?: boolean
|
|
176
|
+
/** A button back to the top of a long page; a number sets how far down it appears, in px. */
|
|
177
|
+
backToTop?: boolean | number
|
|
178
|
+
/** How tight the page sits in main. Unset keeps the shell's own padding. */
|
|
179
|
+
density?: ShellDensity
|
|
180
|
+
/**
|
|
181
|
+
* A new `path` fades the page and the header's title and actions in as one,
|
|
182
|
+
* on the same clock, so actions arriving by teleport do not land apart from
|
|
183
|
+
* their page. Nothing is remounted. Skipped under reduced motion.
|
|
184
|
+
*/
|
|
185
|
+
pageTransition?: boolean
|
|
186
|
+
/**
|
|
187
|
+
* Keep the header and the page's end clear of a notch and a home bar
|
|
188
|
+
* (`viewport-fit=cover`). The bottom bar always does.
|
|
189
|
+
*/
|
|
190
|
+
safeArea?: boolean
|
|
191
|
+
/** Tailwind breakpoint below which the #aside region is hidden. Defaults to `mobileBreakpoint`. */
|
|
192
|
+
asideBreakpoint?: NavBreakpoint
|
|
193
|
+
/** Classes for the #aside region, its width above all. */
|
|
194
|
+
asideClass?: string
|
|
195
|
+
/**
|
|
196
|
+
* One model for the navigation across widths; see `NavMode`. Below
|
|
197
|
+
* `mobileBreakpoint` it is `bottomNav` or the drawer, as ever; this adds the
|
|
198
|
+
* fold to icons in between and the row of sub-pages where the rail is gone.
|
|
199
|
+
* A `compact` the app controls wins, and a person folding the rail by hand
|
|
200
|
+
* holds until the width crosses into another mode.
|
|
201
|
+
*/
|
|
202
|
+
adaptiveNav?: AdaptiveNav
|
|
129
203
|
}>(),
|
|
130
204
|
{
|
|
131
205
|
mobileBreakpoint: "lg",
|
|
132
206
|
divider: true,
|
|
133
207
|
contentClass: "mx-auto w-full max-w-6xl",
|
|
208
|
+
scroll: "document",
|
|
134
209
|
// Unset, not false: an absent boolean would hand the sidebar "expanded"
|
|
135
210
|
// and override the state it remembers.
|
|
136
211
|
compact: undefined,
|
|
@@ -144,6 +219,8 @@ const emit = defineEmits<{
|
|
|
144
219
|
(e: "update:compact", value: boolean): void
|
|
145
220
|
(e: "update:pinned", ids: string[]): void
|
|
146
221
|
(e: "update:context", id: string): void
|
|
222
|
+
/** The navigation the width settled on, with `adaptiveNav` or without. */
|
|
223
|
+
(e: "nav-mode", mode: NavMode): void
|
|
147
224
|
}>()
|
|
148
225
|
|
|
149
226
|
const switching = computed(() => (props.contexts?.length ?? 0) > 1)
|
|
@@ -153,11 +230,16 @@ const flatItems = computed<SidebarItem[]>(() =>
|
|
|
153
230
|
(props.sections ? props.sections.flatMap((s) => s.items) : (props.items ?? [])).flatMap((i) => [i, ...(i.children ?? [])]),
|
|
154
231
|
)
|
|
155
232
|
|
|
233
|
+
// Compared in one spelling, so "/billing/" and "//billing" are "/billing".
|
|
234
|
+
const SLASH_RUN = /\/{2,}/g
|
|
235
|
+
const TRAILING_SLASH = /(?<=.)\/$/
|
|
236
|
+
const cleanPath = computed(() => props.path?.replace(SLASH_RUN, "/").replace(TRAILING_SLASH, ""))
|
|
237
|
+
|
|
156
238
|
// Default active test: exact match for "/", prefix match (on a segment
|
|
157
239
|
// boundary) otherwise — so "/billing" doesn't light up on "/billing-x".
|
|
158
240
|
function matchesPath(item: SidebarItem): boolean {
|
|
159
|
-
if (item.id === "/") return
|
|
160
|
-
return
|
|
241
|
+
if (item.id === "/") return cleanPath.value === "/"
|
|
242
|
+
return cleanPath.value === item.id || cleanPath.value!.startsWith(`${item.id}/`)
|
|
161
243
|
}
|
|
162
244
|
|
|
163
245
|
// Only the LONGEST match lights up. A parent whose id prefixes its children —
|
|
@@ -193,7 +275,7 @@ const pageTitle = computed(() => {
|
|
|
193
275
|
const drawerOpen = defineModel<boolean>("open", { default: false })
|
|
194
276
|
const text = useLabels(
|
|
195
277
|
"appShell",
|
|
196
|
-
{ openMenu: "Open menu", skipToContent: "Skip to content" },
|
|
278
|
+
{ openMenu: "Open menu", skipToContent: "Skip to content", backToTop: "Back to top", aside: "Details", contextNav: "In this section" },
|
|
197
279
|
() => props.labels,
|
|
198
280
|
)
|
|
199
281
|
|
|
@@ -204,27 +286,218 @@ const text = useLabels(
|
|
|
204
286
|
* A full-bleed page owns its scrolling, so the shell leaves it alone.
|
|
205
287
|
*/
|
|
206
288
|
const scrollArea = ref<{ viewportEl: HTMLElement | null } | null>(null)
|
|
289
|
+
const asideArea = ref<{ viewportEl: HTMLElement | null } | null>(null)
|
|
290
|
+
const pageEl = ref<HTMLElement | null>(null)
|
|
207
291
|
const bleedId = `lp-shell-bleed-${useId()}`
|
|
208
292
|
const mounted = ref(false)
|
|
209
293
|
onMounted(() => (mounted.value = true))
|
|
210
294
|
const bleeding = computed(() => props.fullBleed && mounted.value)
|
|
295
|
+
const documentScroll = props.scroll !== "region"
|
|
296
|
+
// The window scrolls the page; a full-bleed page holds the shell to the viewport.
|
|
297
|
+
const windowScrolls = computed(() => documentScroll && !props.fullBleed)
|
|
211
298
|
const mainId = `lp-main-${useId()}`
|
|
212
299
|
|
|
213
300
|
// Focus instead of following the hash, which a router would treat as a navigation.
|
|
301
|
+
const mainEl = ref<HTMLElement | null>(null)
|
|
214
302
|
function skipToMain() {
|
|
215
|
-
|
|
303
|
+
mainEl.value?.focus()
|
|
216
304
|
}
|
|
217
305
|
|
|
218
306
|
watch(
|
|
219
307
|
() => props.path,
|
|
220
308
|
() => {
|
|
221
309
|
if (drawerOpen.value) drawerOpen.value = false
|
|
310
|
+
headerCollapsed.value = false
|
|
222
311
|
},
|
|
223
312
|
)
|
|
313
|
+
function pageScroller(): HTMLElement | null | undefined {
|
|
314
|
+
if (bleeding.value) return null
|
|
315
|
+
if (!documentScroll) return scrollArea.value?.viewportEl
|
|
316
|
+
return (pageEl.value?.ownerDocument.scrollingElement as HTMLElement | null | undefined) ?? null
|
|
317
|
+
}
|
|
224
318
|
useScrollMemory(
|
|
225
|
-
|
|
319
|
+
pageScroller,
|
|
226
320
|
() => props.path,
|
|
227
321
|
() => props.hash,
|
|
322
|
+
"",
|
|
323
|
+
// The sticky header covers the top of the window; a region starts below it.
|
|
324
|
+
() => (documentScroll && !bleeding.value ? (headerEl.value?.offsetHeight ?? 0) : 0),
|
|
325
|
+
)
|
|
326
|
+
// The side region keeps its own place on the same address.
|
|
327
|
+
useScrollMemory(
|
|
328
|
+
() => asideArea.value?.viewportEl,
|
|
329
|
+
() => props.path,
|
|
330
|
+
() => undefined,
|
|
331
|
+
"aside:",
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
const headerCollapsed = ref(false)
|
|
335
|
+
const scrolledFar = ref(false)
|
|
336
|
+
const backToTopAfter = computed(() => (typeof props.backToTop === "number" ? props.backToTop : BACK_TO_TOP_AFTER_PX))
|
|
337
|
+
let lastTop = 0
|
|
338
|
+
|
|
339
|
+
function onScrolled(top: number, max: number) {
|
|
340
|
+
if (!props.headerCollapse && !props.backToTop) return
|
|
341
|
+
if (props.headerCollapse) headerCollapsed.value = headerCollapsedAfter(headerCollapsed.value, lastTop, top, max)
|
|
342
|
+
scrolledFar.value = top > backToTopAfter.value
|
|
343
|
+
lastTop = top
|
|
344
|
+
}
|
|
345
|
+
function onMainScroll(event: Event) {
|
|
346
|
+
const view = event.target as HTMLElement
|
|
347
|
+
onScrolled(view.scrollTop, view.scrollHeight - view.clientHeight)
|
|
348
|
+
}
|
|
349
|
+
function onWindowScroll() {
|
|
350
|
+
const view = pageScroller()
|
|
351
|
+
if (view) onScrolled(view.scrollTop, view.scrollHeight - view.clientHeight)
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
const headerHidden = computed(() => headerCollapsed.value && !bleeding.value)
|
|
355
|
+
const HEADER_HEIGHT = "4rem"
|
|
356
|
+
const headerHeight = computed(() => (props.safeArea ? `calc(${HEADER_HEIGHT} + env(safe-area-inset-top))` : HEADER_HEIGHT))
|
|
357
|
+
|
|
358
|
+
/*
|
|
359
|
+
* A full-bleed page shrinks the document to the viewport, which loses the
|
|
360
|
+
* place; it is taken back on the way out, unless the page changed in between.
|
|
361
|
+
*
|
|
362
|
+
* No scroll-padding-top on the document for the sticky header: with it the
|
|
363
|
+
* browser counts the header as covered by itself, and a control in it taking
|
|
364
|
+
* focus scrolled the page (by 350 px, measured). Anchors get the header's
|
|
365
|
+
* height from scroll memory instead.
|
|
366
|
+
*/
|
|
367
|
+
let bleedTop: number | undefined
|
|
368
|
+
watch(
|
|
369
|
+
() => props.path,
|
|
370
|
+
() => (bleedTop = undefined),
|
|
371
|
+
)
|
|
372
|
+
watch(bleeding, (bleed) => {
|
|
373
|
+
if (!documentScroll) return
|
|
374
|
+
const view = pageEl.value?.ownerDocument.scrollingElement
|
|
375
|
+
if (!view) return
|
|
376
|
+
if (bleed) bleedTop = view.scrollTop
|
|
377
|
+
else if (bleedTop !== undefined) {
|
|
378
|
+
const top = bleedTop
|
|
379
|
+
bleedTop = undefined
|
|
380
|
+
void nextTick(() => view.scrollTo({ top, behavior: "instant" }))
|
|
381
|
+
}
|
|
382
|
+
})
|
|
383
|
+
let releaseDocument: (() => void) | undefined
|
|
384
|
+
onMounted(() => {
|
|
385
|
+
if (!documentScroll || !pageEl.value) return
|
|
386
|
+
const win = nodeWindow(pageEl.value)
|
|
387
|
+
win.addEventListener("scroll", onWindowScroll, { passive: true })
|
|
388
|
+
releaseDocument = () => win.removeEventListener("scroll", onWindowScroll)
|
|
389
|
+
})
|
|
390
|
+
onBeforeUnmount(() => releaseDocument?.())
|
|
391
|
+
|
|
392
|
+
function scrollToTop() {
|
|
393
|
+
const view = pageScroller()
|
|
394
|
+
if (!view) return
|
|
395
|
+
view.scrollTo({ top: 0, behavior: prefersReducedMotion(nodeWindow(view)) ? "instant" : "smooth" })
|
|
396
|
+
// The button is about to leave, and focus must not leave with it.
|
|
397
|
+
mainEl.value?.focus()
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
const headerClass = computed(() =>
|
|
401
|
+
mergeClass(
|
|
402
|
+
"relative flex h-16 shrink-0 items-center gap-3 border-b border-line bg-surface px-4 md:px-6",
|
|
403
|
+
windowScrolls.value && `${STICKY} top-0`,
|
|
404
|
+
props.headerCollapse &&
|
|
405
|
+
(windowScrolls.value ? "transition-transform" : "transition-[margin-top]") + " duration-[var(--duration-medium)] ease-[var(--ease-settle)]",
|
|
406
|
+
props.safeArea &&
|
|
407
|
+
"h-[calc(4rem+env(safe-area-inset-top))] pt-[env(safe-area-inset-top)] pl-[max(1rem,env(safe-area-inset-left))] pr-[max(1rem,env(safe-area-inset-right))] md:pl-[max(1.5rem,env(safe-area-inset-left))] md:pr-[max(1.5rem,env(safe-area-inset-right))]",
|
|
408
|
+
),
|
|
409
|
+
)
|
|
410
|
+
const pageClass = computed(() =>
|
|
411
|
+
mergeClass(
|
|
412
|
+
DENSITY_CLASS[props.density ?? "comfortable"],
|
|
413
|
+
props.contentClass,
|
|
414
|
+
props.safeArea && !props.bottomNav && "pb-[calc(1.5rem+env(safe-area-inset-bottom))]",
|
|
415
|
+
),
|
|
416
|
+
)
|
|
417
|
+
|
|
418
|
+
// Fades on one clock, read from the page's own tokens. Post flush: a teleported
|
|
419
|
+
// action arrives with the render that brought the page.
|
|
420
|
+
const headerEl = ref<HTMLElement | null>(null)
|
|
421
|
+
const bleedEl = ref<HTMLElement | null>(null)
|
|
422
|
+
watch(
|
|
423
|
+
() => props.path,
|
|
424
|
+
() => {
|
|
425
|
+
const content = bleeding.value ? bleedEl.value : documentScroll ? pageEl.value : scrollArea.value?.viewportEl
|
|
426
|
+
if (!props.pageTransition || !content || prefersReducedMotion(nodeWindow(content))) return
|
|
427
|
+
const timing = { duration: durationToken("duration-medium", undefined, content), easing: easingToken("ease-settle", undefined, content) }
|
|
428
|
+
// Title and actions; the burger is the frame, not the page.
|
|
429
|
+
const header = headerEl.value?.querySelectorAll(":scope > :not(button)") ?? []
|
|
430
|
+
for (const el of [content, ...header]) el.animate({ opacity: [0, 1] }, timing)
|
|
431
|
+
},
|
|
432
|
+
{ flush: "post" },
|
|
433
|
+
)
|
|
434
|
+
|
|
435
|
+
const slots = useSlots()
|
|
436
|
+
const hasAside = computed(() => !!slots.aside)
|
|
437
|
+
const ASIDE_VISIBLE: Record<NavBreakpoint, string> = {
|
|
438
|
+
sm: "hidden sm:flex",
|
|
439
|
+
md: "hidden md:flex",
|
|
440
|
+
lg: "hidden lg:flex",
|
|
441
|
+
xl: "hidden xl:flex",
|
|
442
|
+
"2xl": "hidden 2xl:flex",
|
|
443
|
+
}
|
|
444
|
+
const asideClasses = computed(() =>
|
|
445
|
+
mergeClass(
|
|
446
|
+
"min-h-0 w-80 flex-col border-l border-line bg-surface",
|
|
447
|
+
windowScrolls.value &&
|
|
448
|
+
"sticky top-(--lp-shell-top) h-[calc(100dvh-var(--lp-shell-top))] self-start transition-[top,height] duration-[var(--duration-medium)] ease-[var(--ease-settle)]",
|
|
449
|
+
ASIDE_VISIBLE[props.asideBreakpoint ?? props.mobileBreakpoint],
|
|
450
|
+
props.asideClass,
|
|
451
|
+
),
|
|
452
|
+
)
|
|
453
|
+
|
|
454
|
+
/*
|
|
455
|
+
* The aside takes a grid column rather than a wrapper around main: a wrapper
|
|
456
|
+
* that comes and goes with the slot would remount the page. Header, the
|
|
457
|
+
* sub-page row and the bottom bar span both columns.
|
|
458
|
+
*/
|
|
459
|
+
const columnClass = computed(() => (hasAside.value ? "grid min-w-0 flex-1 grid-cols-[minmax(0,1fr)_auto]" : "flex min-w-0 flex-1 flex-col"))
|
|
460
|
+
const columnStyle = computed(() => ({
|
|
461
|
+
...(hasAside.value ? { gridTemplateRows: `auto ${contextVisible.value ? "auto " : ""}minmax(0,1fr) auto` } : {}),
|
|
462
|
+
...(windowScrolls.value ? { "--lp-shell-top": shellTop.value } : {}),
|
|
463
|
+
}))
|
|
464
|
+
const spanClass = computed(() => (hasAside.value ? "col-span-2" : undefined))
|
|
465
|
+
|
|
466
|
+
// One width rather than a media query per breakpoint: those report one by one,
|
|
467
|
+
// so a jump across two passed through a mode the window was never in.
|
|
468
|
+
const view = useView()
|
|
469
|
+
const width = ref(0)
|
|
470
|
+
const measureWidth = () => (width.value = viewWindow(view.value).innerWidth)
|
|
471
|
+
onMounted(() => {
|
|
472
|
+
measureWidth()
|
|
473
|
+
viewWindow(view.value).addEventListener("resize", measureWidth)
|
|
474
|
+
})
|
|
475
|
+
onBeforeUnmount(() => viewWindow(view.value).removeEventListener("resize", measureWidth))
|
|
476
|
+
|
|
477
|
+
// Before mount there is no width: a server render is the plain rail.
|
|
478
|
+
const navMode = computed<NavMode>(() =>
|
|
479
|
+
mounted.value
|
|
480
|
+
? resolveNavMode((breakpoint) => width.value >= NAV_BREAKPOINT_PX[breakpoint], {
|
|
481
|
+
mobileBreakpoint: props.mobileBreakpoint,
|
|
482
|
+
bottomNav: !!props.bottomNav,
|
|
483
|
+
compactBelow: props.adaptiveNav?.compactBelow,
|
|
484
|
+
})
|
|
485
|
+
: "rail",
|
|
486
|
+
)
|
|
487
|
+
watch(navMode, (mode) => emit("nav-mode", mode))
|
|
488
|
+
|
|
489
|
+
// What a person chose by hand, for as long as the width stays in this mode.
|
|
490
|
+
const handCompact = ref<boolean | undefined>()
|
|
491
|
+
watch(navMode, () => (handCompact.value = undefined))
|
|
492
|
+
const railCompact = computed(() => props.compact ?? handCompact.value ?? (navMode.value === "compact" ? true : undefined))
|
|
493
|
+
function onCompact(value: boolean) {
|
|
494
|
+
if (props.adaptiveNav) handCompact.value = value
|
|
495
|
+
emit("update:compact", value)
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
const contextItems = computed(() => (props.adaptiveNav?.contextNav ? contextNavItems(topItems.value, activeTest.value) : []))
|
|
499
|
+
const contextVisible = computed(
|
|
500
|
+
() => (navMode.value === "bottom" || navMode.value === "drawer") && (contextItems.value.length > 0 || (!!slots["context-nav"] && !!props.adaptiveNav?.contextNav)),
|
|
228
501
|
)
|
|
229
502
|
|
|
230
503
|
function onSelect(item: SidebarItem) {
|
|
@@ -260,11 +533,33 @@ function onBottom(item: SidebarItem) {
|
|
|
260
533
|
|
|
261
534
|
// Expose the burger trigger so a host can omit its own header entirely.
|
|
262
535
|
const _openDrawer = () => (drawerOpen.value = true)
|
|
263
|
-
defineExpose({ openDrawer: _openDrawer })
|
|
536
|
+
defineExpose({ openDrawer: _openDrawer, navMode })
|
|
264
537
|
|
|
265
|
-
//
|
|
266
|
-
|
|
267
|
-
|
|
538
|
+
// In region mode the shell claims the full viewport height, which is wrong when it is embedded in a page that already has a header of its own.
|
|
539
|
+
// The document mode clips sideways with `clip`, not `hidden`: a hidden overflow would make the root the sticky children's scroller.
|
|
540
|
+
const { class: rootClass, attrs: rest } = useMergedAttrs(() =>
|
|
541
|
+
windowScrolls.value ? "flex min-h-dvh overflow-x-clip bg-surface text-ink" : "flex h-dvh overflow-hidden bg-surface text-ink",
|
|
542
|
+
)
|
|
543
|
+
|
|
544
|
+
/*
|
|
545
|
+
* What stays in view while the window scrolls the page. The header sits on
|
|
546
|
+
* top; the row of sub-pages and the aside sit under it, following it out
|
|
547
|
+
* when it collapses (--lp-shell-top is how much of the header is showing).
|
|
548
|
+
*/
|
|
549
|
+
const STICKY = "sticky z-(--z-sticky)"
|
|
550
|
+
const railClass = computed(() => (windowScrolls.value ? "sticky top-0 flex h-dvh shrink-0 self-start" : "contents"))
|
|
551
|
+
const shellTop = computed(() => (headerHidden.value ? "0px" : headerHeight.value))
|
|
552
|
+
const BACK_TO_TOP_ABOVE_BAR: Record<NavBreakpoint, string> = {
|
|
553
|
+
sm: "bottom-[calc(4.5rem+env(safe-area-inset-bottom))] sm:bottom-[calc(1rem+env(safe-area-inset-bottom))]",
|
|
554
|
+
md: "bottom-[calc(4.5rem+env(safe-area-inset-bottom))] md:bottom-[calc(1rem+env(safe-area-inset-bottom))]",
|
|
555
|
+
lg: "bottom-[calc(4.5rem+env(safe-area-inset-bottom))] lg:bottom-[calc(1rem+env(safe-area-inset-bottom))]",
|
|
556
|
+
xl: "bottom-[calc(4.5rem+env(safe-area-inset-bottom))] xl:bottom-[calc(1rem+env(safe-area-inset-bottom))]",
|
|
557
|
+
"2xl": "bottom-[calc(4.5rem+env(safe-area-inset-bottom))] 2xl:bottom-[calc(1rem+env(safe-area-inset-bottom))]",
|
|
558
|
+
}
|
|
559
|
+
const backToTopClass = computed(() =>
|
|
560
|
+
windowScrolls.value
|
|
561
|
+
? ["fixed right-6 z-(--z-sticky)", props.bottomNav ? BACK_TO_TOP_ABOVE_BAR[props.mobileBreakpoint] : "bottom-[calc(1rem+env(safe-area-inset-bottom))]"]
|
|
562
|
+
: "absolute bottom-[calc(1rem+env(safe-area-inset-bottom))] right-6",
|
|
268
563
|
)
|
|
269
564
|
</script>
|
|
270
565
|
|
|
@@ -279,6 +574,10 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
|
|
|
279
574
|
>
|
|
280
575
|
{{ text.skipToContent }}
|
|
281
576
|
</a>
|
|
577
|
+
<!-- The rail's own box: a viewport-tall sticky column while the window
|
|
578
|
+
scrolls the page, and no box at all (contents) in the region frame,
|
|
579
|
+
where the rail is the frame's full height already. -->
|
|
580
|
+
<div :class="railClass">
|
|
282
581
|
<LpSidebar
|
|
283
582
|
:model-value="modelValue"
|
|
284
583
|
:items="items"
|
|
@@ -292,7 +591,7 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
|
|
|
292
591
|
:loading="loading"
|
|
293
592
|
:collapsed="collapsed"
|
|
294
593
|
:auto-collapse-after="autoCollapseAfter"
|
|
295
|
-
:compact="
|
|
594
|
+
:compact="railCompact"
|
|
296
595
|
:resizable="resizable"
|
|
297
596
|
:pinnable="pinnable"
|
|
298
597
|
:pinned="pinned"
|
|
@@ -303,7 +602,7 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
|
|
|
303
602
|
:hints="hints"
|
|
304
603
|
class="shrink-0"
|
|
305
604
|
@update:model-value="onModel"
|
|
306
|
-
@update:compact="
|
|
605
|
+
@update:compact="onCompact"
|
|
307
606
|
@update:pinned="(v) => emit('update:pinned', v)"
|
|
308
607
|
@update:open="(v) => (drawerOpen = v)"
|
|
309
608
|
@update:collapsed="(v) => emit('update:collapsed', v)"
|
|
@@ -334,9 +633,10 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
|
|
|
334
633
|
<slot name="sidebar-item" v-bind="slotProps" />
|
|
335
634
|
</template>
|
|
336
635
|
</LpSidebar>
|
|
636
|
+
</div>
|
|
337
637
|
|
|
338
638
|
<!-- Main column: header + the single scroll region. -->
|
|
339
|
-
<div class="
|
|
639
|
+
<div :class="columnClass" :style="columnStyle">
|
|
340
640
|
<!-- `relative` so a consumer can centre something — section tabs, a
|
|
341
641
|
search box — against the WHOLE bar. Centring it inside the title
|
|
342
642
|
block instead makes its position depend on how wide the actions are,
|
|
@@ -344,7 +644,10 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
|
|
|
344
644
|
59 px off centre with two actions and 77 px with three, which reads
|
|
345
645
|
as the navigation drifting rather than the page changing. -->
|
|
346
646
|
<header
|
|
347
|
-
|
|
647
|
+
ref="headerEl"
|
|
648
|
+
:class="[headerClass, spanClass]"
|
|
649
|
+
:style="headerHidden ? (windowScrolls ? { transform: 'translateY(-100%)' } : { marginTop: `calc(-1 * ${headerHeight})` }) : undefined"
|
|
650
|
+
@focusin="headerCollapsed = false"
|
|
348
651
|
>
|
|
349
652
|
<LpButton
|
|
350
653
|
:class="burgerClass"
|
|
@@ -398,26 +701,61 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
|
|
|
398
701
|
tab going from a full-bleed page to a padded one cut instead of
|
|
399
702
|
playing its transition, and lost the page's state. Until mount the
|
|
400
703
|
page stays in the scroll region, which is what a server render has. -->
|
|
401
|
-
<
|
|
402
|
-
<
|
|
704
|
+
<template v-if="contextVisible">
|
|
705
|
+
<slot name="context-nav" :items="contextItems" :mode="navMode">
|
|
706
|
+
<AppShellContextNav
|
|
707
|
+
:class="[spanClass, windowScrolls && `${STICKY} top-(--lp-shell-top) transition-[top] duration-[var(--duration-medium)] ease-[var(--ease-settle)]`]"
|
|
708
|
+
:items="contextItems"
|
|
709
|
+
:is-active="activeTest"
|
|
710
|
+
:label="text.contextNav"
|
|
711
|
+
@select="onBottom"
|
|
712
|
+
/>
|
|
713
|
+
</slot>
|
|
714
|
+
</template>
|
|
715
|
+
<main ref="mainEl" :id="mainId" tabindex="-1" :data-lp-density="density" :class="['flex min-h-0 flex-1 flex-col outline-none', backToTop && 'relative']">
|
|
716
|
+
<div ref="bleedEl" v-show="bleeding" :id="bleedId" class="min-h-0 flex-1 overflow-hidden" />
|
|
717
|
+
<div v-if="documentScroll" v-show="!bleeding" ref="pageEl" :class="['flex-1', pageClass]">
|
|
718
|
+
<Teleport :to="`#${bleedId}`" :disabled="!bleeding" defer>
|
|
719
|
+
<slot />
|
|
720
|
+
</Teleport>
|
|
721
|
+
</div>
|
|
403
722
|
<LpScrollArea
|
|
723
|
+
v-else
|
|
404
724
|
v-show="!bleeding"
|
|
405
725
|
ref="scrollArea"
|
|
406
726
|
class="min-h-0 flex-1"
|
|
407
|
-
:content-class="
|
|
727
|
+
:content-class="pageClass"
|
|
728
|
+
@scroll="onMainScroll"
|
|
408
729
|
>
|
|
409
730
|
<Teleport :to="`#${bleedId}`" :disabled="!bleeding" defer>
|
|
410
731
|
<slot />
|
|
411
732
|
</Teleport>
|
|
412
733
|
</LpScrollArea>
|
|
734
|
+
<LpButton
|
|
735
|
+
v-if="backToTop && scrolledFar && !bleeding"
|
|
736
|
+
:class="backToTopClass"
|
|
737
|
+
variant="outline"
|
|
738
|
+
size="sm"
|
|
739
|
+
square
|
|
740
|
+
:aria-label="text.backToTop"
|
|
741
|
+
@click="scrollToTop"
|
|
742
|
+
>
|
|
743
|
+
<LpIcon name="lucide:arrow-up" :size="16" />
|
|
744
|
+
</LpButton>
|
|
413
745
|
</main>
|
|
746
|
+
<aside v-if="hasAside" :aria-label="text.aside" :class="asideClasses">
|
|
747
|
+
<LpScrollArea ref="asideArea" class="min-h-0 flex-1" content-class="p-4">
|
|
748
|
+
<slot name="aside" />
|
|
749
|
+
</LpScrollArea>
|
|
750
|
+
</aside>
|
|
414
751
|
<LpBottomNav
|
|
415
752
|
v-if="bottomNav"
|
|
416
|
-
:class="burgerHidden[mobileBreakpoint]"
|
|
753
|
+
:class="[burgerHidden[mobileBreakpoint], spanClass, windowScrolls && `${STICKY} bottom-0`]"
|
|
417
754
|
:items="bottomItems"
|
|
418
755
|
:is-active="activeTest"
|
|
419
756
|
more
|
|
420
757
|
:more-active="moreActive"
|
|
758
|
+
:more-expanded="drawerOpen"
|
|
421
759
|
@select="onBottom"
|
|
422
760
|
@more="drawerOpen = true"
|
|
423
761
|
/>
|
|
@@ -10,6 +10,8 @@ export type AutocompleteLabels = {
|
|
|
10
10
|
</script>
|
|
11
11
|
|
|
12
12
|
<script setup lang="ts">
|
|
13
|
+
import IconCloseButton from "./IconCloseButton.vue"
|
|
14
|
+
import { CONTROL_SIZE } from "./controlSize"
|
|
13
15
|
import { usePaletteControl, type PaletteControlOptions } from "../composables/usePaletteCommands"
|
|
14
16
|
/*
|
|
15
17
|
* Free-text autocomplete — a text field that suggests as you type but never
|
|
@@ -33,11 +35,11 @@ import {
|
|
|
33
35
|
ComboboxRoot,
|
|
34
36
|
ComboboxViewport,
|
|
35
37
|
} from "reka-ui"
|
|
36
|
-
import { computed, nextTick, ref,
|
|
37
|
-
import {
|
|
38
|
+
import { computed, nextTick, ref, useId, watch } from "vue"
|
|
39
|
+
import { useAttrsField, mergeDescribedBy } from "../composables/useField"
|
|
38
40
|
import { useInputFilter } from "../composables/useInputFilter"
|
|
39
41
|
import { useLabels } from "../composables/useLpConfig"
|
|
40
|
-
import { CLOSE_ICON, OPTION_ITEM, optionStagger, POPOVER_PANEL } from "./dropdown"
|
|
42
|
+
import { CLOSE_ICON, OPTION_ITEM, optionStagger, COMBOBOX_PANEL, POPOVER_PANEL } from "./dropdown"
|
|
41
43
|
import LpIcon from "./LpIcon.vue"
|
|
42
44
|
import OptionContent from "./OptionContent.vue"
|
|
43
45
|
import type { LpOptionBase, OptionSelection } from "./options"
|
|
@@ -115,18 +117,12 @@ const text = computed<string>({
|
|
|
115
117
|
|
|
116
118
|
// class/style lay out the whole control; every other attr (name, autocomplete,
|
|
117
119
|
// @blur, @keydown…) belongs to the text <input>.
|
|
118
|
-
const attrs = useAttrs()
|
|
119
120
|
const inputAttrs = computed(() => {
|
|
120
121
|
const { class: _c, style: _s, ...rest } = attrs
|
|
121
122
|
return rest
|
|
122
123
|
})
|
|
123
124
|
|
|
124
|
-
const field =
|
|
125
|
-
wrapped: false,
|
|
126
|
-
id: typeof attrs.id === "string" ? attrs.id : undefined,
|
|
127
|
-
invalid: props.invalid || isInvalid(props.modelValue),
|
|
128
|
-
disabled: props.disabled,
|
|
129
|
-
}))
|
|
125
|
+
const { attrs, field } = useAttrsField(() => ({ invalid: props.invalid || isInvalid(props.modelValue), disabled: props.disabled }))
|
|
130
126
|
const isInvalidState = computed(() => field.value.invalid)
|
|
131
127
|
const labels = useLabels<AutocompleteLabels>(
|
|
132
128
|
"autocomplete",
|
|
@@ -179,7 +175,7 @@ watch(
|
|
|
179
175
|
// reader is told who it is through a description.
|
|
180
176
|
const selectedId = useId()
|
|
181
177
|
const describedBy = computed(() =>
|
|
182
|
-
[field.value.describedBy, showSelected.value ? selectedId : undefined
|
|
178
|
+
mergeDescribedBy(attrs["aria-describedby"], field.value.describedBy, showSelected.value ? selectedId : undefined),
|
|
183
179
|
)
|
|
184
180
|
|
|
185
181
|
// Threshold met AND something to show → the list is allowed to open.
|
|
@@ -210,11 +206,7 @@ function onOpenChange(next: boolean) {
|
|
|
210
206
|
|
|
211
207
|
const hasValue = computed(() => (props.modelValue ?? "").length > 0)
|
|
212
208
|
|
|
213
|
-
const anchorSize =
|
|
214
|
-
sm: "h-(--size-control-sm) text-xs",
|
|
215
|
-
md: "h-(--size-control-md) text-sm",
|
|
216
|
-
lg: "h-(--size-control-lg) text-sm",
|
|
217
|
-
}
|
|
209
|
+
const anchorSize = CONTROL_SIZE
|
|
218
210
|
|
|
219
211
|
function onInput(event: Event) {
|
|
220
212
|
filterInput(event)
|
|
@@ -373,31 +365,27 @@ usePaletteControl({ disabled: () => field.value.disabled, invalid: () => field.v
|
|
|
373
365
|
</span>
|
|
374
366
|
</Transition>
|
|
375
367
|
</div>
|
|
376
|
-
<
|
|
368
|
+
<IconCloseButton
|
|
377
369
|
v-if="clearable && hasValue && !field.disabled"
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
:aria-label="labels.clear"
|
|
370
|
+
inline
|
|
371
|
+
:label="labels.clear"
|
|
381
372
|
@pointerdown.prevent
|
|
382
373
|
@click="clear"
|
|
383
|
-
|
|
384
|
-
<LpIcon
|
|
385
|
-
name="lucide:x"
|
|
386
|
-
:size="16"
|
|
387
|
-
:class="CLOSE_ICON"
|
|
388
|
-
/>
|
|
389
|
-
</button>
|
|
374
|
+
/>
|
|
390
375
|
</ComboboxAnchor>
|
|
391
376
|
|
|
377
|
+
<!-- A press on the list keeps focus in the field. Otherwise the field
|
|
378
|
+
blurs before the click lands, and a host that settles its text on
|
|
379
|
+
blur (back to the last pick) empties the list under the pointer: the
|
|
380
|
+
option clicked is gone and the choice is lost. -->
|
|
392
381
|
<ComboboxPortal :to="portalTo">
|
|
393
382
|
<ComboboxContent
|
|
394
383
|
@interact-outside="guardOutside"
|
|
395
384
|
@escape-key-down="guardOutside"
|
|
396
|
-
|
|
397
|
-
position="popper"
|
|
398
|
-
:side-offset="6"
|
|
385
|
+
v-bind="COMBOBOX_PANEL"
|
|
399
386
|
:class="[POPOVER_PANEL, 'z-(--z-popover) max-h-72 w-(--reka-combobox-trigger-width) overflow-hidden']"
|
|
400
387
|
@open-auto-focus.prevent
|
|
388
|
+
@mousedown.prevent
|
|
401
389
|
>
|
|
402
390
|
<ComboboxViewport class="max-h-72 overflow-y-auto p-1">
|
|
403
391
|
<div v-if="loading" class="px-3 py-4 text-center text-sm italic text-muted">
|