@leavepulse/ui 0.77.3 → 0.78.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +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-CLLhd3WB.js} +2 -2
- package/dist/chunks/FieldLeading-mr81aEAP.js +27 -0
- 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-E8KtwU7-.js → LpAddressInput-BSS49jpm.js} +12 -11
- package/dist/chunks/{LpAlert-n5XPAZfv.js → LpAlert-CjvTZIKF.js} +3 -3
- package/dist/chunks/LpAppShell-BKbYCHkx.js +601 -0
- package/dist/chunks/{LpAutocomplete-C-SpPfBG.js → LpAutocomplete-DkY6CSyD.js} +24 -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-DBqy4RLd.js} +19 -41
- package/dist/chunks/{LpCodeDisplay-CE9TxCA4.js → LpCodeDisplay-D3BUAhV1.js} +5 -5
- package/dist/chunks/{LpCollapse-CWS9M_lm.js → LpCollapse-DrAw5DBZ.js} +5 -4
- package/dist/chunks/{LpColorPicker-1y1QJHZR.js → LpColorPicker-COHzV68R.js} +11 -12
- package/dist/chunks/{LpCommandScope-CtUhJe8T.js → LpCommandScope-DRUvHiX7.js} +1 -1
- package/dist/chunks/{LpConfirmDialog-DlD45Bi_.js → LpConfirmDialog-CnrmzkuN.js} +3 -3
- package/dist/chunks/{LpConfirmHost-BIWjBLmI.js → LpConfirmHost-CwbObVGH.js} +1 -1
- package/dist/chunks/{LpContextMenu-rx2tCjwk.js → LpContextMenu-Bx_IhQDS.js} +17 -19
- package/dist/chunks/{LpContextSwitcher-Dwh6dyID.js → LpContextSwitcher-1C1tExdl.js} +2 -2
- package/dist/chunks/{LpCopyButton-xF7wFVoU.js → LpCopyButton-sAMvWeLP.js} +3 -3
- package/dist/chunks/{LpCountdown-DgeY3cLG.js → LpCountdown-DVl7vXI1.js} +4 -3
- package/dist/chunks/{LpDataList-Jxyl9H5w.js → LpDataList-CaVfsozH.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-DXNQFpAA.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-C-rJKzEQ.js +735 -0
- package/dist/chunks/{LpFileTreeNode-cT6BIWvz.js → LpFileTreeNode-BgYn4U1J.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-CHE9jAJG.js} +29 -11
- 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-Bb5nbuFY.js} +19 -2
- package/dist/chunks/{LpInput-Tw-yxT4I.js → LpInput-D0O6dpuA.js} +32 -47
- package/dist/chunks/LpInspector-DO3fTCQ1.js +209 -0
- package/dist/chunks/{LpLaneNode-HtnQf2FF.js → LpLaneNode-Bqcdm8Rf.js} +19 -1
- package/dist/chunks/{LpLightbox-B95yu22B.js → LpLightbox-CtDTQV01.js} +57 -32
- package/dist/chunks/{LpLoader-DVwkOmt9.js → LpLoader-Bf1yZwaU.js} +1 -1
- package/dist/chunks/LpLogInspector-BdQlX6S-.js +119 -0
- package/dist/chunks/{LpLogViewer-ngqkns4m.js → LpLogViewer-umCZBapN.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-BYEwySoF.js} +3 -3
- package/dist/chunks/{LpModal-CoGhLTyH.js → LpModal-DDvrSAnf.js} +11 -13
- package/dist/chunks/{LpModalNav-BGvs2y5Q.js → LpModalNav-gOi1Giz1.js} +11 -37
- package/dist/chunks/{LpNotificationBell-B0034Lk-.js → LpNotificationBell-DUbVyK6R.js} +9 -9
- package/dist/chunks/{LpNumberField-e0IBkWU1.js → LpNumberField-Csg-1Zh_.js} +25 -20
- package/dist/chunks/{LpOtpInput-CeBPsM7D.js → LpOtpInput-BRpLBbOD.js} +2 -2
- package/dist/chunks/LpPageScrollbar-D2O0xhJw.js +164 -0
- package/dist/chunks/{LpPagination-BIIiYHXR.js → LpPagination-snQ020xQ.js} +6 -4
- package/dist/chunks/{LpPaletteTheme-DiLYKQiZ.js → LpPaletteTheme-BIXpZLGe.js} +4 -4
- package/dist/chunks/{LpPasswordInput-BkHKQDhM.js → LpPasswordInput-D4HPhqfV.js} +2 -2
- package/dist/chunks/{LpPhoneInput-CETEp5W7.js → LpPhoneInput-BSL7NX4z.js} +15 -26
- package/dist/chunks/{LpPie-DrZepi0p.js → LpPie-oVNHjsKD.js} +22 -21
- package/dist/chunks/{LpPipeline-B3aOVOkV.js → LpPipeline-BSXT6oUJ.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-0zI-44ve.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-CqvwfZs2.js} +31 -22
- package/dist/chunks/{LpSecretField-BbmqM9ye.js → LpSecretField-B2roc4Iz.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/{LpServiceNode-D8uJ8sGk.js → LpServiceNode-Cln2ntdw.js} +17 -0
- 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-DDNJzb69.js} +74 -87
- package/dist/chunks/{LpSidebarNav-DE3PhXVP.js → LpSidebarNav-CE0jQS8i.js} +8 -6
- package/dist/chunks/{LpSidebarRow-BRYhNDSo.js → LpSidebarRow-DOTg1txp.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-DPjc6_fX.js} +19 -6
- 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-B_XMOeAh.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-ChU0_Ga8.js} +12 -195
- package/dist/chunks/{LpThemeSwitcher-BnEn_mvf.js → LpThemeSwitcher-DmCZ21P_.js} +8 -6
- package/dist/chunks/{LpTimeField-BawSVsmt.js → LpTimeField-DeOcKWJq.js} +6 -9
- package/dist/chunks/{LpToaster-IwTXjbbU.js → LpToaster-Ct_ZOhCh.js} +10 -8
- package/dist/chunks/{LpTooltip-BcBvIx4z.js → LpTooltip-Bz_rrq5S.js} +56 -24
- package/dist/chunks/LpTopologyCanvas-jqz1KCq2.js +678 -0
- package/dist/chunks/{LpTour-BZq-mUMv.js → LpTour-ClKYhx4h.js} +7 -5
- package/dist/chunks/{LpTruncate-CflAIwiJ.js → LpTruncate-ellq9RYM.js} +6 -5
- package/dist/chunks/{LpTypewriter-BCL_a6wE.js → LpTypewriter-CZIzpdbe.js} +2 -1
- package/dist/chunks/{LpUptimeBar-DqNvvMBK.js → LpUptimeBar-BoxcCDVY.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-BeNHCLd5.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-D_iyrB8d.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/FieldLeading.vue.d.ts +16 -0
- package/dist/components/FieldLeading.vue.js +4 -0
- 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 +125 -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.d.ts +11 -2
- 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/LpLaneNode.vue.d.ts +2 -3
- package/dist/components/LpLaneNode.vue.js +1 -1
- 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.d.ts +13 -2
- package/dist/components/LpNumberField.vue.js +1 -1
- package/dist/components/LpOtpInput.vue.js +1 -1
- package/dist/components/LpPageScrollbar.vue.d.ts +10 -0
- package/dist/components/LpPageScrollbar.vue.js +4 -0
- 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/LpServiceNode.vue.d.ts +8 -2
- package/dist/components/LpServiceNode.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.d.ts +16 -0
- 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/scrollbar.d.ts +34 -0
- package/dist/components/scrollbar.js +47 -0
- 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 +89 -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 +16 -3
- 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 +31 -5
- package/dist/index.js +312 -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 +6 -1
- package/src/components/AppShellContextNav.vue +44 -0
- package/src/components/ChartRangeSelector.vue +120 -0
- package/src/components/FieldLeading.vue +17 -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 +385 -24
- package/src/components/LpAutocomplete.vue +13 -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 +22 -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 +37 -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/LpInfraNode.vue +4 -3
- package/src/components/LpInput.vue +19 -26
- package/src/components/LpInspector.vue +197 -0
- package/src/components/LpLaneNode.vue +5 -1
- 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 +13 -16
- package/src/components/LpOtpInput.vue +2 -2
- package/src/components/LpPageScrollbar.vue +195 -0
- 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 +55 -34
- package/src/components/LpSecretField.vue +2 -1
- package/src/components/LpSegmented.vue +6 -8
- package/src/components/LpSelect.vue +54 -24
- package/src/components/LpServiceNode.vue +4 -2
- 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/LpStat.vue +25 -5
- 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 +69 -18
- package/src/components/LpTopologyCanvas.vue +569 -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/scrollbar.ts +71 -0
- 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 +105 -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 +18 -2
- 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 +42 -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,14 +39,33 @@ 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"
|
|
40
67
|
import LpIcon from "./LpIcon.vue"
|
|
68
|
+
import LpPageScrollbar from "./LpPageScrollbar.vue"
|
|
41
69
|
import LpScrollArea from "./LpScrollArea.vue"
|
|
42
70
|
import LpShift from "./LpShift.vue"
|
|
43
71
|
import LpSidebar from "./LpSidebar.vue"
|
|
@@ -46,6 +74,9 @@ import { mergeClass, useMergedAttrs } from "../composables/useMergedClass"
|
|
|
46
74
|
|
|
47
75
|
export type { SidebarItem, SidebarSection } from "./sidebar"
|
|
48
76
|
|
|
77
|
+
/* Past this much scrolled the way back up is worth a button. */
|
|
78
|
+
const BACK_TO_TOP_AFTER_PX = 600
|
|
79
|
+
|
|
49
80
|
const props = withDefaults(
|
|
50
81
|
defineProps<{
|
|
51
82
|
/** Flat items, or sections for grouped nav. Forwarded to LpSidebar. */
|
|
@@ -91,10 +122,26 @@ const props = withDefaults(
|
|
|
91
122
|
* (for a canvas / map / graph that fills the viewport and pans internally).
|
|
92
123
|
*/
|
|
93
124
|
fullBleed?: boolean
|
|
125
|
+
/**
|
|
126
|
+
* What scrolls. `"document"` (the default): the window, with the rail,
|
|
127
|
+
* header and bottom bar sticky; a page that filled main with `h-full`
|
|
128
|
+
* grows with its content now, so a page meant to fill the screen asks for
|
|
129
|
+
* `min-h-[calc(100dvh-4rem)]` or `fullBleed`. `"region"`: the shell is
|
|
130
|
+
* the viewport and the page scrolls inside main. Read once: changing it
|
|
131
|
+
* remounts the page.
|
|
132
|
+
*/
|
|
133
|
+
scroll?: "document" | "region"
|
|
134
|
+
/**
|
|
135
|
+
* While the document scrolls, draw the kit's overlay bar for it
|
|
136
|
+
* (LpPageScrollbar) under the header and above the bottom bar, in place of
|
|
137
|
+
* the browser's, which takes width from the page. `false` keeps the
|
|
138
|
+
* browser's. Where the browser's bars float anyway (phones) it draws none.
|
|
139
|
+
*/
|
|
140
|
+
pageScrollbar?: boolean
|
|
94
141
|
/** Loading skeleton for the nav. */
|
|
95
142
|
loading?: boolean
|
|
96
143
|
/** Text overrides: the burger's name and the skip link. */
|
|
97
|
-
labels?: Partial<{ openMenu: string; skipToContent: string }>
|
|
144
|
+
labels?: Partial<{ openMenu: string; skipToContent: string; backToTop: string; aside: string; contextNav: string }>
|
|
98
145
|
/** Icon-only rail (v-model:compact). Forwarded to LpSidebar. */
|
|
99
146
|
compact?: boolean
|
|
100
147
|
/** The person sizes the rail and folds it to icons. Forwarded to LpSidebar. */
|
|
@@ -123,14 +170,51 @@ const props = withDefaults(
|
|
|
123
170
|
/**
|
|
124
171
|
* On phones, the main pages along the bottom instead of the burger, with
|
|
125
172
|
* "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.
|
|
173
|
+
* pages, a number that many, a list of ids those pages. Top-level pages
|
|
174
|
+
* only: an id from `children` is ignored, and such a page stays behind "More".
|
|
127
175
|
*/
|
|
128
176
|
bottomNav?: boolean | number | string[]
|
|
177
|
+
/**
|
|
178
|
+
* The header leaves as the page scrolls down and returns on the way up,
|
|
179
|
+
* giving a small screen its height back. A keyboard user tabbing into it
|
|
180
|
+
* brings it back too. A full-bleed page owns its scrolling, so the header
|
|
181
|
+
* stays there.
|
|
182
|
+
*/
|
|
183
|
+
headerCollapse?: boolean
|
|
184
|
+
/** A button back to the top of a long page; a number sets how far down it appears, in px. */
|
|
185
|
+
backToTop?: boolean | number
|
|
186
|
+
/** How tight the page sits in main. Unset keeps the shell's own padding. */
|
|
187
|
+
density?: ShellDensity
|
|
188
|
+
/**
|
|
189
|
+
* A new `path` fades the page and the header's title and actions in as one,
|
|
190
|
+
* on the same clock, so actions arriving by teleport do not land apart from
|
|
191
|
+
* their page. Nothing is remounted. Skipped under reduced motion.
|
|
192
|
+
*/
|
|
193
|
+
pageTransition?: boolean
|
|
194
|
+
/**
|
|
195
|
+
* Keep the header and the page's end clear of a notch and a home bar
|
|
196
|
+
* (`viewport-fit=cover`). The bottom bar always does.
|
|
197
|
+
*/
|
|
198
|
+
safeArea?: boolean
|
|
199
|
+
/** Tailwind breakpoint below which the #aside region is hidden. Defaults to `mobileBreakpoint`. */
|
|
200
|
+
asideBreakpoint?: NavBreakpoint
|
|
201
|
+
/** Classes for the #aside region, its width above all. */
|
|
202
|
+
asideClass?: string
|
|
203
|
+
/**
|
|
204
|
+
* One model for the navigation across widths; see `NavMode`. Below
|
|
205
|
+
* `mobileBreakpoint` it is `bottomNav` or the drawer, as ever; this adds the
|
|
206
|
+
* fold to icons in between and the row of sub-pages where the rail is gone.
|
|
207
|
+
* A `compact` the app controls wins, and a person folding the rail by hand
|
|
208
|
+
* holds until the width crosses into another mode.
|
|
209
|
+
*/
|
|
210
|
+
adaptiveNav?: AdaptiveNav
|
|
129
211
|
}>(),
|
|
130
212
|
{
|
|
131
213
|
mobileBreakpoint: "lg",
|
|
132
214
|
divider: true,
|
|
133
215
|
contentClass: "mx-auto w-full max-w-6xl",
|
|
216
|
+
scroll: "document",
|
|
217
|
+
pageScrollbar: true,
|
|
134
218
|
// Unset, not false: an absent boolean would hand the sidebar "expanded"
|
|
135
219
|
// and override the state it remembers.
|
|
136
220
|
compact: undefined,
|
|
@@ -144,6 +228,8 @@ const emit = defineEmits<{
|
|
|
144
228
|
(e: "update:compact", value: boolean): void
|
|
145
229
|
(e: "update:pinned", ids: string[]): void
|
|
146
230
|
(e: "update:context", id: string): void
|
|
231
|
+
/** The navigation the width settled on, with `adaptiveNav` or without. */
|
|
232
|
+
(e: "nav-mode", mode: NavMode): void
|
|
147
233
|
}>()
|
|
148
234
|
|
|
149
235
|
const switching = computed(() => (props.contexts?.length ?? 0) > 1)
|
|
@@ -153,11 +239,16 @@ const flatItems = computed<SidebarItem[]>(() =>
|
|
|
153
239
|
(props.sections ? props.sections.flatMap((s) => s.items) : (props.items ?? [])).flatMap((i) => [i, ...(i.children ?? [])]),
|
|
154
240
|
)
|
|
155
241
|
|
|
242
|
+
// Compared in one spelling, so "/billing/" and "//billing" are "/billing".
|
|
243
|
+
const SLASH_RUN = /\/{2,}/g
|
|
244
|
+
const TRAILING_SLASH = /(?<=.)\/$/
|
|
245
|
+
const cleanPath = computed(() => props.path?.replace(SLASH_RUN, "/").replace(TRAILING_SLASH, ""))
|
|
246
|
+
|
|
156
247
|
// Default active test: exact match for "/", prefix match (on a segment
|
|
157
248
|
// boundary) otherwise — so "/billing" doesn't light up on "/billing-x".
|
|
158
249
|
function matchesPath(item: SidebarItem): boolean {
|
|
159
|
-
if (item.id === "/") return
|
|
160
|
-
return
|
|
250
|
+
if (item.id === "/") return cleanPath.value === "/"
|
|
251
|
+
return cleanPath.value === item.id || cleanPath.value!.startsWith(`${item.id}/`)
|
|
161
252
|
}
|
|
162
253
|
|
|
163
254
|
// Only the LONGEST match lights up. A parent whose id prefixes its children —
|
|
@@ -193,7 +284,7 @@ const pageTitle = computed(() => {
|
|
|
193
284
|
const drawerOpen = defineModel<boolean>("open", { default: false })
|
|
194
285
|
const text = useLabels(
|
|
195
286
|
"appShell",
|
|
196
|
-
{ openMenu: "Open menu", skipToContent: "Skip to content" },
|
|
287
|
+
{ openMenu: "Open menu", skipToContent: "Skip to content", backToTop: "Back to top", aside: "Details", contextNav: "In this section" },
|
|
197
288
|
() => props.labels,
|
|
198
289
|
)
|
|
199
290
|
|
|
@@ -204,27 +295,230 @@ const text = useLabels(
|
|
|
204
295
|
* A full-bleed page owns its scrolling, so the shell leaves it alone.
|
|
205
296
|
*/
|
|
206
297
|
const scrollArea = ref<{ viewportEl: HTMLElement | null } | null>(null)
|
|
298
|
+
const asideArea = ref<{ viewportEl: HTMLElement | null } | null>(null)
|
|
299
|
+
const pageEl = ref<HTMLElement | null>(null)
|
|
207
300
|
const bleedId = `lp-shell-bleed-${useId()}`
|
|
208
301
|
const mounted = ref(false)
|
|
209
302
|
onMounted(() => (mounted.value = true))
|
|
210
303
|
const bleeding = computed(() => props.fullBleed && mounted.value)
|
|
304
|
+
const documentScroll = props.scroll !== "region"
|
|
305
|
+
// The window scrolls the page; a full-bleed page holds the shell to the viewport.
|
|
306
|
+
const windowScrolls = computed(() => documentScroll && !props.fullBleed)
|
|
211
307
|
const mainId = `lp-main-${useId()}`
|
|
212
308
|
|
|
213
309
|
// Focus instead of following the hash, which a router would treat as a navigation.
|
|
310
|
+
const mainEl = ref<HTMLElement | null>(null)
|
|
214
311
|
function skipToMain() {
|
|
215
|
-
|
|
312
|
+
mainEl.value?.focus()
|
|
216
313
|
}
|
|
217
314
|
|
|
218
315
|
watch(
|
|
219
316
|
() => props.path,
|
|
220
317
|
() => {
|
|
221
318
|
if (drawerOpen.value) drawerOpen.value = false
|
|
319
|
+
headerCollapsed.value = false
|
|
222
320
|
},
|
|
223
321
|
)
|
|
322
|
+
function pageScroller(): HTMLElement | null | undefined {
|
|
323
|
+
if (bleeding.value) return null
|
|
324
|
+
if (!documentScroll) return scrollArea.value?.viewportEl
|
|
325
|
+
return (pageEl.value?.ownerDocument.scrollingElement as HTMLElement | null | undefined) ?? null
|
|
326
|
+
}
|
|
224
327
|
useScrollMemory(
|
|
225
|
-
|
|
328
|
+
pageScroller,
|
|
226
329
|
() => props.path,
|
|
227
330
|
() => props.hash,
|
|
331
|
+
"",
|
|
332
|
+
// The sticky header covers the top of the window; a region starts below it.
|
|
333
|
+
() => (documentScroll && !bleeding.value ? (headerEl.value?.offsetHeight ?? 0) : 0),
|
|
334
|
+
)
|
|
335
|
+
// The side region keeps its own place on the same address.
|
|
336
|
+
useScrollMemory(
|
|
337
|
+
() => asideArea.value?.viewportEl,
|
|
338
|
+
() => props.path,
|
|
339
|
+
() => undefined,
|
|
340
|
+
"aside:",
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
const headerCollapsed = ref(false)
|
|
344
|
+
const scrolledFar = ref(false)
|
|
345
|
+
const backToTopAfter = computed(() => (typeof props.backToTop === "number" ? props.backToTop : BACK_TO_TOP_AFTER_PX))
|
|
346
|
+
let lastTop = 0
|
|
347
|
+
|
|
348
|
+
function onScrolled(top: number, max: number) {
|
|
349
|
+
if (!props.headerCollapse && !props.backToTop) return
|
|
350
|
+
if (props.headerCollapse) headerCollapsed.value = headerCollapsedAfter(headerCollapsed.value, lastTop, top, max)
|
|
351
|
+
scrolledFar.value = top > backToTopAfter.value
|
|
352
|
+
lastTop = top
|
|
353
|
+
}
|
|
354
|
+
function onMainScroll(event: Event) {
|
|
355
|
+
const view = event.target as HTMLElement
|
|
356
|
+
onScrolled(view.scrollTop, view.scrollHeight - view.clientHeight)
|
|
357
|
+
}
|
|
358
|
+
function onWindowScroll() {
|
|
359
|
+
const view = pageScroller()
|
|
360
|
+
if (view) onScrolled(view.scrollTop, view.scrollHeight - view.clientHeight)
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
const headerHidden = computed(() => headerCollapsed.value && !bleeding.value)
|
|
364
|
+
const HEADER_HEIGHT = "4rem"
|
|
365
|
+
const headerHeight = computed(() => (props.safeArea ? `calc(${HEADER_HEIGHT} + env(safe-area-inset-top))` : HEADER_HEIGHT))
|
|
366
|
+
|
|
367
|
+
/*
|
|
368
|
+
* A full-bleed page shrinks the document to the viewport, which loses the
|
|
369
|
+
* place; it is taken back on the way out, unless the page changed in between.
|
|
370
|
+
*
|
|
371
|
+
* No scroll-padding-top on the document for the sticky header: with it the
|
|
372
|
+
* browser counts the header as covered by itself, and a control in it taking
|
|
373
|
+
* focus scrolled the page (by 350 px, measured). Anchors get the header's
|
|
374
|
+
* height from scroll memory instead.
|
|
375
|
+
*/
|
|
376
|
+
let bleedTop: number | undefined
|
|
377
|
+
watch(
|
|
378
|
+
() => props.path,
|
|
379
|
+
() => (bleedTop = undefined),
|
|
380
|
+
)
|
|
381
|
+
watch(bleeding, (bleed) => {
|
|
382
|
+
if (!documentScroll) return
|
|
383
|
+
const view = pageEl.value?.ownerDocument.scrollingElement
|
|
384
|
+
if (!view) return
|
|
385
|
+
if (bleed) bleedTop = view.scrollTop
|
|
386
|
+
else if (bleedTop !== undefined) {
|
|
387
|
+
const top = bleedTop
|
|
388
|
+
bleedTop = undefined
|
|
389
|
+
void nextTick(() => view.scrollTo({ top, behavior: "instant" }))
|
|
390
|
+
}
|
|
391
|
+
})
|
|
392
|
+
// The bottom bar's height, for the page's scrollbar to stop above it (0 where it is hidden).
|
|
393
|
+
const bottomBarEl = ref<{ $el: HTMLElement } | null>(null)
|
|
394
|
+
const bottomBarHeight = ref(0)
|
|
395
|
+
let bottomBarSize: ResizeObserver | undefined
|
|
396
|
+
onMounted(() => {
|
|
397
|
+
const el = bottomBarEl.value?.$el
|
|
398
|
+
if (!el || el.nodeType !== 1) return
|
|
399
|
+
bottomBarSize = new (nodeWindow(el).ResizeObserver)(() => (bottomBarHeight.value = el.offsetHeight))
|
|
400
|
+
bottomBarSize.observe(el)
|
|
401
|
+
})
|
|
402
|
+
onBeforeUnmount(() => bottomBarSize?.disconnect())
|
|
403
|
+
|
|
404
|
+
let releaseDocument: (() => void) | undefined
|
|
405
|
+
onMounted(() => {
|
|
406
|
+
if (!documentScroll || !pageEl.value) return
|
|
407
|
+
const win = nodeWindow(pageEl.value)
|
|
408
|
+
win.addEventListener("scroll", onWindowScroll, { passive: true })
|
|
409
|
+
releaseDocument = () => win.removeEventListener("scroll", onWindowScroll)
|
|
410
|
+
})
|
|
411
|
+
onBeforeUnmount(() => releaseDocument?.())
|
|
412
|
+
|
|
413
|
+
function scrollToTop() {
|
|
414
|
+
const view = pageScroller()
|
|
415
|
+
if (!view) return
|
|
416
|
+
view.scrollTo({ top: 0, behavior: prefersReducedMotion(nodeWindow(view)) ? "instant" : "smooth" })
|
|
417
|
+
// The button is about to leave, and focus must not leave with it.
|
|
418
|
+
mainEl.value?.focus()
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
const headerClass = computed(() =>
|
|
422
|
+
mergeClass(
|
|
423
|
+
"relative flex h-16 shrink-0 items-center gap-3 border-b border-line bg-surface px-4 md:px-6",
|
|
424
|
+
windowScrolls.value && `${STICKY} top-0`,
|
|
425
|
+
props.headerCollapse &&
|
|
426
|
+
(windowScrolls.value ? "transition-transform" : "transition-[margin-top]") + " duration-[var(--duration-medium)] ease-[var(--ease-settle)]",
|
|
427
|
+
props.safeArea &&
|
|
428
|
+
"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))]",
|
|
429
|
+
),
|
|
430
|
+
)
|
|
431
|
+
const pageClass = computed(() =>
|
|
432
|
+
mergeClass(
|
|
433
|
+
DENSITY_CLASS[props.density ?? "comfortable"],
|
|
434
|
+
props.contentClass,
|
|
435
|
+
props.safeArea && !props.bottomNav && "pb-[calc(1.5rem+env(safe-area-inset-bottom))]",
|
|
436
|
+
),
|
|
437
|
+
)
|
|
438
|
+
|
|
439
|
+
// Fades on one clock, read from the page's own tokens. Post flush: a teleported
|
|
440
|
+
// action arrives with the render that brought the page.
|
|
441
|
+
const headerEl = ref<HTMLElement | null>(null)
|
|
442
|
+
const bleedEl = ref<HTMLElement | null>(null)
|
|
443
|
+
watch(
|
|
444
|
+
() => props.path,
|
|
445
|
+
() => {
|
|
446
|
+
const content = bleeding.value ? bleedEl.value : documentScroll ? pageEl.value : scrollArea.value?.viewportEl
|
|
447
|
+
if (!props.pageTransition || !content || prefersReducedMotion(nodeWindow(content))) return
|
|
448
|
+
const timing = { duration: durationToken("duration-medium", undefined, content), easing: easingToken("ease-settle", undefined, content) }
|
|
449
|
+
// Title and actions; the burger is the frame, not the page.
|
|
450
|
+
const header = headerEl.value?.querySelectorAll(":scope > :not(button)") ?? []
|
|
451
|
+
for (const el of [content, ...header]) el.animate({ opacity: [0, 1] }, timing)
|
|
452
|
+
},
|
|
453
|
+
{ flush: "post" },
|
|
454
|
+
)
|
|
455
|
+
|
|
456
|
+
const slots = useSlots()
|
|
457
|
+
const hasAside = computed(() => !!slots.aside)
|
|
458
|
+
const ASIDE_VISIBLE: Record<NavBreakpoint, string> = {
|
|
459
|
+
sm: "hidden sm:flex",
|
|
460
|
+
md: "hidden md:flex",
|
|
461
|
+
lg: "hidden lg:flex",
|
|
462
|
+
xl: "hidden xl:flex",
|
|
463
|
+
"2xl": "hidden 2xl:flex",
|
|
464
|
+
}
|
|
465
|
+
const asideClasses = computed(() =>
|
|
466
|
+
mergeClass(
|
|
467
|
+
"min-h-0 w-80 flex-col border-l border-line bg-surface",
|
|
468
|
+
windowScrolls.value &&
|
|
469
|
+
"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)]",
|
|
470
|
+
ASIDE_VISIBLE[props.asideBreakpoint ?? props.mobileBreakpoint],
|
|
471
|
+
props.asideClass,
|
|
472
|
+
),
|
|
473
|
+
)
|
|
474
|
+
|
|
475
|
+
/*
|
|
476
|
+
* The aside takes a grid column rather than a wrapper around main: a wrapper
|
|
477
|
+
* that comes and goes with the slot would remount the page. Header, the
|
|
478
|
+
* sub-page row and the bottom bar span both columns.
|
|
479
|
+
*/
|
|
480
|
+
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"))
|
|
481
|
+
const columnStyle = computed(() => ({
|
|
482
|
+
...(hasAside.value ? { gridTemplateRows: `auto ${contextVisible.value ? "auto " : ""}minmax(0,1fr) auto` } : {}),
|
|
483
|
+
...(windowScrolls.value ? { "--lp-shell-top": shellTop.value } : {}),
|
|
484
|
+
}))
|
|
485
|
+
const spanClass = computed(() => (hasAside.value ? "col-span-2" : undefined))
|
|
486
|
+
|
|
487
|
+
// One width rather than a media query per breakpoint: those report one by one,
|
|
488
|
+
// so a jump across two passed through a mode the window was never in.
|
|
489
|
+
const view = useView()
|
|
490
|
+
const width = ref(0)
|
|
491
|
+
const measureWidth = () => (width.value = viewWindow(view.value).innerWidth)
|
|
492
|
+
onMounted(() => {
|
|
493
|
+
measureWidth()
|
|
494
|
+
viewWindow(view.value).addEventListener("resize", measureWidth)
|
|
495
|
+
})
|
|
496
|
+
onBeforeUnmount(() => viewWindow(view.value).removeEventListener("resize", measureWidth))
|
|
497
|
+
|
|
498
|
+
// Before mount there is no width: a server render is the plain rail.
|
|
499
|
+
const navMode = computed<NavMode>(() =>
|
|
500
|
+
mounted.value
|
|
501
|
+
? resolveNavMode((breakpoint) => width.value >= NAV_BREAKPOINT_PX[breakpoint], {
|
|
502
|
+
mobileBreakpoint: props.mobileBreakpoint,
|
|
503
|
+
bottomNav: !!props.bottomNav,
|
|
504
|
+
compactBelow: props.adaptiveNav?.compactBelow,
|
|
505
|
+
})
|
|
506
|
+
: "rail",
|
|
507
|
+
)
|
|
508
|
+
watch(navMode, (mode) => emit("nav-mode", mode))
|
|
509
|
+
|
|
510
|
+
// What a person chose by hand, for as long as the width stays in this mode.
|
|
511
|
+
const handCompact = ref<boolean | undefined>()
|
|
512
|
+
watch(navMode, () => (handCompact.value = undefined))
|
|
513
|
+
const railCompact = computed(() => props.compact ?? handCompact.value ?? (navMode.value === "compact" ? true : undefined))
|
|
514
|
+
function onCompact(value: boolean) {
|
|
515
|
+
if (props.adaptiveNav) handCompact.value = value
|
|
516
|
+
emit("update:compact", value)
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
const contextItems = computed(() => (props.adaptiveNav?.contextNav ? contextNavItems(topItems.value, activeTest.value) : []))
|
|
520
|
+
const contextVisible = computed(
|
|
521
|
+
() => (navMode.value === "bottom" || navMode.value === "drawer") && (contextItems.value.length > 0 || (!!slots["context-nav"] && !!props.adaptiveNav?.contextNav)),
|
|
228
522
|
)
|
|
229
523
|
|
|
230
524
|
function onSelect(item: SidebarItem) {
|
|
@@ -260,11 +554,33 @@ function onBottom(item: SidebarItem) {
|
|
|
260
554
|
|
|
261
555
|
// Expose the burger trigger so a host can omit its own header entirely.
|
|
262
556
|
const _openDrawer = () => (drawerOpen.value = true)
|
|
263
|
-
defineExpose({ openDrawer: _openDrawer })
|
|
557
|
+
defineExpose({ openDrawer: _openDrawer, navMode })
|
|
558
|
+
|
|
559
|
+
// 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.
|
|
560
|
+
// The document mode clips sideways with `clip`, not `hidden`: a hidden overflow would make the root the sticky children's scroller.
|
|
561
|
+
const { class: rootClass, attrs: rest } = useMergedAttrs(() =>
|
|
562
|
+
windowScrolls.value ? "flex min-h-dvh overflow-x-clip bg-surface text-ink" : "flex h-dvh overflow-hidden bg-surface text-ink",
|
|
563
|
+
)
|
|
264
564
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
565
|
+
/*
|
|
566
|
+
* What stays in view while the window scrolls the page. The header sits on
|
|
567
|
+
* top; the row of sub-pages and the aside sit under it, following it out
|
|
568
|
+
* when it collapses (--lp-shell-top is how much of the header is showing).
|
|
569
|
+
*/
|
|
570
|
+
const STICKY = "sticky z-(--z-sticky)"
|
|
571
|
+
const railClass = computed(() => (windowScrolls.value ? "sticky top-0 flex h-dvh shrink-0 self-start" : "contents"))
|
|
572
|
+
const shellTop = computed(() => (headerHidden.value ? "0px" : headerHeight.value))
|
|
573
|
+
const BACK_TO_TOP_ABOVE_BAR: Record<NavBreakpoint, string> = {
|
|
574
|
+
sm: "bottom-[calc(4.5rem+env(safe-area-inset-bottom))] sm:bottom-[calc(1rem+env(safe-area-inset-bottom))]",
|
|
575
|
+
md: "bottom-[calc(4.5rem+env(safe-area-inset-bottom))] md:bottom-[calc(1rem+env(safe-area-inset-bottom))]",
|
|
576
|
+
lg: "bottom-[calc(4.5rem+env(safe-area-inset-bottom))] lg:bottom-[calc(1rem+env(safe-area-inset-bottom))]",
|
|
577
|
+
xl: "bottom-[calc(4.5rem+env(safe-area-inset-bottom))] xl:bottom-[calc(1rem+env(safe-area-inset-bottom))]",
|
|
578
|
+
"2xl": "bottom-[calc(4.5rem+env(safe-area-inset-bottom))] 2xl:bottom-[calc(1rem+env(safe-area-inset-bottom))]",
|
|
579
|
+
}
|
|
580
|
+
const backToTopClass = computed(() =>
|
|
581
|
+
windowScrolls.value
|
|
582
|
+
? ["fixed right-6 z-(--z-sticky)", props.bottomNav ? BACK_TO_TOP_ABOVE_BAR[props.mobileBreakpoint] : "bottom-[calc(1rem+env(safe-area-inset-bottom))]"]
|
|
583
|
+
: "absolute bottom-[calc(1rem+env(safe-area-inset-bottom))] right-6",
|
|
268
584
|
)
|
|
269
585
|
</script>
|
|
270
586
|
|
|
@@ -279,6 +595,10 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
|
|
|
279
595
|
>
|
|
280
596
|
{{ text.skipToContent }}
|
|
281
597
|
</a>
|
|
598
|
+
<!-- The rail's own box: a viewport-tall sticky column while the window
|
|
599
|
+
scrolls the page, and no box at all (contents) in the region frame,
|
|
600
|
+
where the rail is the frame's full height already. -->
|
|
601
|
+
<div :class="railClass">
|
|
282
602
|
<LpSidebar
|
|
283
603
|
:model-value="modelValue"
|
|
284
604
|
:items="items"
|
|
@@ -292,7 +612,7 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
|
|
|
292
612
|
:loading="loading"
|
|
293
613
|
:collapsed="collapsed"
|
|
294
614
|
:auto-collapse-after="autoCollapseAfter"
|
|
295
|
-
:compact="
|
|
615
|
+
:compact="railCompact"
|
|
296
616
|
:resizable="resizable"
|
|
297
617
|
:pinnable="pinnable"
|
|
298
618
|
:pinned="pinned"
|
|
@@ -303,7 +623,7 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
|
|
|
303
623
|
:hints="hints"
|
|
304
624
|
class="shrink-0"
|
|
305
625
|
@update:model-value="onModel"
|
|
306
|
-
@update:compact="
|
|
626
|
+
@update:compact="onCompact"
|
|
307
627
|
@update:pinned="(v) => emit('update:pinned', v)"
|
|
308
628
|
@update:open="(v) => (drawerOpen = v)"
|
|
309
629
|
@update:collapsed="(v) => emit('update:collapsed', v)"
|
|
@@ -334,9 +654,10 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
|
|
|
334
654
|
<slot name="sidebar-item" v-bind="slotProps" />
|
|
335
655
|
</template>
|
|
336
656
|
</LpSidebar>
|
|
657
|
+
</div>
|
|
337
658
|
|
|
338
659
|
<!-- Main column: header + the single scroll region. -->
|
|
339
|
-
<div class="
|
|
660
|
+
<div :class="columnClass" :style="columnStyle">
|
|
340
661
|
<!-- `relative` so a consumer can centre something — section tabs, a
|
|
341
662
|
search box — against the WHOLE bar. Centring it inside the title
|
|
342
663
|
block instead makes its position depend on how wide the actions are,
|
|
@@ -344,7 +665,10 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
|
|
|
344
665
|
59 px off centre with two actions and 77 px with three, which reads
|
|
345
666
|
as the navigation drifting rather than the page changing. -->
|
|
346
667
|
<header
|
|
347
|
-
|
|
668
|
+
ref="headerEl"
|
|
669
|
+
:class="[headerClass, spanClass]"
|
|
670
|
+
:style="headerHidden ? (windowScrolls ? { transform: 'translateY(-100%)' } : { marginTop: `calc(-1 * ${headerHeight})` }) : undefined"
|
|
671
|
+
@focusin="headerCollapsed = false"
|
|
348
672
|
>
|
|
349
673
|
<LpButton
|
|
350
674
|
:class="burgerClass"
|
|
@@ -398,26 +722,63 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
|
|
|
398
722
|
tab going from a full-bleed page to a padded one cut instead of
|
|
399
723
|
playing its transition, and lost the page's state. Until mount the
|
|
400
724
|
page stays in the scroll region, which is what a server render has. -->
|
|
401
|
-
<
|
|
402
|
-
<
|
|
725
|
+
<template v-if="contextVisible">
|
|
726
|
+
<slot name="context-nav" :items="contextItems" :mode="navMode">
|
|
727
|
+
<AppShellContextNav
|
|
728
|
+
:class="[spanClass, windowScrolls && `${STICKY} top-(--lp-shell-top) transition-[top] duration-[var(--duration-medium)] ease-[var(--ease-settle)]`]"
|
|
729
|
+
:items="contextItems"
|
|
730
|
+
:is-active="activeTest"
|
|
731
|
+
:label="text.contextNav"
|
|
732
|
+
@select="onBottom"
|
|
733
|
+
/>
|
|
734
|
+
</slot>
|
|
735
|
+
</template>
|
|
736
|
+
<main ref="mainEl" :id="mainId" tabindex="-1" :data-lp-density="density" :class="['flex min-h-0 flex-1 flex-col outline-none', backToTop && 'relative']">
|
|
737
|
+
<div ref="bleedEl" v-show="bleeding" :id="bleedId" class="min-h-0 flex-1 overflow-hidden" />
|
|
738
|
+
<div v-if="documentScroll" v-show="!bleeding" ref="pageEl" :class="['flex-1', pageClass]">
|
|
739
|
+
<Teleport :to="`#${bleedId}`" :disabled="!bleeding" defer>
|
|
740
|
+
<slot />
|
|
741
|
+
</Teleport>
|
|
742
|
+
</div>
|
|
403
743
|
<LpScrollArea
|
|
744
|
+
v-else
|
|
404
745
|
v-show="!bleeding"
|
|
405
746
|
ref="scrollArea"
|
|
406
747
|
class="min-h-0 flex-1"
|
|
407
|
-
:content-class="
|
|
748
|
+
:content-class="pageClass"
|
|
749
|
+
@scroll="onMainScroll"
|
|
408
750
|
>
|
|
409
751
|
<Teleport :to="`#${bleedId}`" :disabled="!bleeding" defer>
|
|
410
752
|
<slot />
|
|
411
753
|
</Teleport>
|
|
412
754
|
</LpScrollArea>
|
|
755
|
+
<LpButton
|
|
756
|
+
v-if="backToTop && scrolledFar && !bleeding"
|
|
757
|
+
:class="backToTopClass"
|
|
758
|
+
variant="outline"
|
|
759
|
+
size="sm"
|
|
760
|
+
square
|
|
761
|
+
:aria-label="text.backToTop"
|
|
762
|
+
@click="scrollToTop"
|
|
763
|
+
>
|
|
764
|
+
<LpIcon name="lucide:arrow-up" :size="16" />
|
|
765
|
+
</LpButton>
|
|
413
766
|
</main>
|
|
767
|
+
<aside v-if="hasAside" :aria-label="text.aside" :class="asideClasses">
|
|
768
|
+
<LpScrollArea ref="asideArea" class="min-h-0 flex-1" content-class="p-4">
|
|
769
|
+
<slot name="aside" />
|
|
770
|
+
</LpScrollArea>
|
|
771
|
+
</aside>
|
|
772
|
+
<LpPageScrollbar v-if="windowScrolls && pageScrollbar" top="var(--lp-shell-top)" :bottom="`${bottomBarHeight}px`" />
|
|
414
773
|
<LpBottomNav
|
|
415
774
|
v-if="bottomNav"
|
|
416
|
-
|
|
775
|
+
ref="bottomBarEl"
|
|
776
|
+
:class="[burgerHidden[mobileBreakpoint], spanClass, windowScrolls && `${STICKY} bottom-0`]"
|
|
417
777
|
:items="bottomItems"
|
|
418
778
|
:is-active="activeTest"
|
|
419
779
|
more
|
|
420
780
|
:more-active="moreActive"
|
|
781
|
+
:more-expanded="drawerOpen"
|
|
421
782
|
@select="onBottom"
|
|
422
783
|
@more="drawerOpen = true"
|
|
423
784
|
/>
|
|
@@ -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,20 +365,13 @@ 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
|
|
|
392
377
|
<!-- A press on the list keeps focus in the field. Otherwise the field
|
|
@@ -397,9 +382,7 @@ usePaletteControl({ disabled: () => field.value.disabled, invalid: () => field.v
|
|
|
397
382
|
<ComboboxContent
|
|
398
383
|
@interact-outside="guardOutside"
|
|
399
384
|
@escape-key-down="guardOutside"
|
|
400
|
-
|
|
401
|
-
position="popper"
|
|
402
|
-
:side-offset="6"
|
|
385
|
+
v-bind="COMBOBOX_PANEL"
|
|
403
386
|
:class="[POPOVER_PANEL, 'z-(--z-popover) max-h-72 w-(--reka-combobox-trigger-width) overflow-hidden']"
|
|
404
387
|
@open-auto-focus.prevent
|
|
405
388
|
@mousedown.prevent
|