@leavepulse/ui 0.43.4 → 0.44.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 +75 -7
- package/dist/assets/{LpCommandPalette-B-0Est4Z.css → LpCommandPalette-DCP5g2ik.css} +21 -21
- package/dist/assets/{LpDropzone-BBoWvi-J.css → LpDropzone-i4BdMi1H.css} +12 -12
- package/dist/assets/{LpImageEditor-Ct7Y3aNu.css → LpImageEditor-CbMA82g8.css} +6 -6
- package/dist/assets/{LpShortcutsDialog-C6YoQ8_M.css → LpShortcutsDialog-ChUyU7oV.css} +7 -7
- package/dist/assets/{LpSkeleton-D7xU8IPV.css → LpSkeleton-H3Z5dEIk.css} +4 -1
- package/dist/assets/{LpTable-BgPLJOXa.css → LpTable-DDQNdf86.css} +9 -9
- package/dist/chunks/ContextMenuItems-CrfeNPWT.js +123 -0
- package/dist/chunks/{LayoutCanvas-Dd20boUG.js → LayoutCanvas-D-jPOAvg.js} +26 -9
- package/dist/chunks/{LayoutNode-DGpZA9LX.js → LayoutNode-D8Xy9N-o.js} +20 -8
- package/dist/chunks/{LpActionBar-BlvtGB2P.js → LpActionBar-BbwCF6l5.js} +24 -10
- package/dist/chunks/{LpAddressInput-B-Zvxsn7.js → LpAddressInput-BrOqkZqg.js} +53 -48
- package/dist/chunks/{LpAlert-BAYHDSS1.js → LpAlert-DkOIjsbq.js} +15 -8
- package/dist/chunks/{LpAppShell-BGQVIY-3.js → LpAppShell-BUKPcHco.js} +51 -24
- package/dist/chunks/{LpAutocomplete-DExlIZe_.js → LpAutocomplete-DxV3Y9h4.js} +50 -23
- package/dist/chunks/{LpAvatar-B3-xAOH3.js → LpAvatar-ClBbEYZN.js} +17 -8
- package/dist/chunks/LpBreadcrumbs-B8IJgFIc.js +95 -0
- package/dist/chunks/{LpButton-5VXXCjwF.js → LpButton-kqJBHIIb.js} +44 -14
- package/dist/chunks/{LpCard-BhI1N_vL.js → LpCard-CpRByR0q.js} +1 -1
- package/dist/chunks/{LpCheckbox-CVccKYaH.js → LpCheckbox-DpqchzH4.js} +7 -3
- package/dist/chunks/{LpCodeBlock-Bo0B4TFR.js → LpCodeBlock-DeHJPq7p.js} +48 -16
- package/dist/chunks/{LpColorPicker-BlXea7LM.js → LpColorPicker-Bhf1qxhB.js} +32 -9
- package/dist/chunks/{LpConfirmDialog-Q-bxff8z.js → LpConfirmDialog-CIUOSnWo.js} +58 -16
- package/dist/chunks/LpConfirmHost-CDm0Wtpv.js +49 -0
- package/dist/chunks/LpContextMenu-DQw5dGfG.js +68 -0
- package/dist/chunks/LpDatePicker-Drirx1AK.js +191 -0
- package/dist/chunks/{LpDrawer-BZ6k3hvo.js → LpDrawer-bScx-KMO.js} +63 -26
- package/dist/chunks/{LpFileTree-_5vFBgaK.js → LpFileTree-CSI_5SK2.js} +23 -8
- package/dist/chunks/{LpFileTreeNode-BdcIYKIE.js → LpFileTreeNode-B4MiSQX2.js} +2 -2
- package/dist/chunks/LpFormField-CIk5qosh.js +87 -0
- package/dist/chunks/{LpInput-9EXWUM9B.js → LpInput-C0e8y8_d.js} +26 -11
- package/dist/chunks/{LpLightbox-2sYVMY-S.js → LpLightbox-Mr0W_6HK.js} +147 -60
- package/dist/chunks/{LpLink-DCND-zyu.js → LpLink-Krkjhe_y.js} +15 -6
- package/dist/chunks/{LpLogViewer-CaRy5MeS.js → LpLogViewer-YBOaFnc_.js} +68 -34
- package/dist/chunks/{LpMapPicker-ul4oYno6.js → LpMapPicker-NUzS9e37.js} +38 -13
- package/dist/chunks/{LpMediaGallery-FF-NquIo.js → LpMediaGallery-DfJmMW0I.js} +6 -3
- package/dist/chunks/{LpModal-Bt0pQCI_.js → LpModal-DPwGKBPv.js} +49 -26
- package/dist/chunks/{LpModalNav-YaifHrXC.js → LpModalNav-DPg5H9f3.js} +9 -6
- package/dist/chunks/{LpNotificationBell-DyGGsMAM.js → LpNotificationBell-t5yn-siX.js} +58 -24
- package/dist/chunks/{LpNumberField-CWuX08iX.js → LpNumberField-DWnQKktS.js} +20 -7
- package/dist/chunks/{LpNumberFlow-amWYaeuA.js → LpNumberFlow-z4WPZcZu.js} +22 -12
- package/dist/chunks/{LpOtpInput-y2v-pmiN.js → LpOtpInput-CziPF3Oq.js} +37 -8
- package/dist/chunks/{LpPagination-5FxjmmB5.js → LpPagination-DFngX7Xo.js} +30 -19
- package/dist/chunks/{LpPasswordInput--sjYCkLS.js → LpPasswordInput-CWVDuBJ5.js} +10 -7
- package/dist/chunks/{LpPhoneInput-BDSKVl_z.js → LpPhoneInput-CD-ZTeSd.js} +57 -33
- package/dist/chunks/{LpPie-D6OnzwlJ.js → LpPie-BLco31Nx.js} +78 -21
- package/dist/chunks/{LpPopover-8268UmlC.js → LpPopover-p_e_shN3.js} +4 -2
- package/dist/chunks/{LpProgress-Btq5W4Ut.js → LpProgress-CBU1iI69.js} +5 -4
- package/dist/chunks/{LpRadioGroup-xPIuVDO_.js → LpRadioGroup-DmEW0l78.js} +9 -2
- package/dist/chunks/{LpSegmented-fV0Sk92p.js → LpSegmented-Dejd7cIx.js} +7 -3
- package/dist/chunks/{LpSelect-ANIVtrpM.js → LpSelect-DrRD9I7L.js} +40 -18
- package/dist/chunks/{LpSidebar-ClBUwoEz.js → LpSidebar-BgwUNWpJ.js} +30 -22
- package/dist/chunks/{LpSidebarNav-llOcs_Fn.js → LpSidebarNav-Bqxz8aWT.js} +14 -9
- package/dist/chunks/{LpSkeleton-CTI-vBgW.js → LpSkeleton-BB6XIV-w.js} +1 -1
- package/dist/chunks/{LpSlider-BwNIBkAK.js → LpSlider-Cuzmrd7p.js} +7 -2
- package/dist/chunks/{LpSparkline-C6xQ2dwv.js → LpSparkline-CB80N8SJ.js} +11 -4
- package/dist/chunks/{LpStat-CQaW8R--.js → LpStat-dXtyrdX9.js} +1 -1
- package/dist/chunks/{LpSwitch-Blizvqyt.js → LpSwitch-B1aLKulj.js} +40 -26
- package/dist/chunks/{LpTableOfContents-CjvxPMpU.js → LpTableOfContents-BUcAfGPQ.js} +36 -41
- package/dist/chunks/{LpTabs-Cefe_lys.js → LpTabs-_qMVaZJ6.js} +19 -5
- package/dist/chunks/LpTextarea-yP8hGedR.js +77 -0
- package/dist/chunks/LpThemeProvider-Wjm7Tuit.js +35 -0
- package/dist/chunks/LpThemeSwitcher-CKLc10KZ.js +169 -0
- package/dist/chunks/{LpTilt-DuyKbpkA.js → LpTilt-B7KHX1zH.js} +2 -2
- package/dist/chunks/{LpTimeField-K6nAGboX.js → LpTimeField-C5HRgS5H.js} +13 -7
- package/dist/chunks/{LpToaster-gDB1EaU3.js → LpToaster--oT6lfhL.js} +57 -28
- package/dist/chunks/{LpTooltip-hCLPAqMG.js → LpTooltip-CBdzeKNf.js} +13 -6
- package/dist/chunks/LpTooltipProvider-CftjV7Xc.js +25 -0
- package/dist/chunks/{LpTopologyCanvas-Cm1L39uL.js → LpTopologyCanvas-DocsLal3.js} +6 -1
- package/dist/chunks/{LpUptimeBar-DvAMno0S.js → LpUptimeBar-DLtxOMRy.js} +43 -14
- package/dist/chunks/{LpThemeSwitcher-Cue-myST.js → useTheme-C8JHUlPM.js} +173 -215
- package/dist/component-names.d.ts +1 -1
- package/dist/components/ContextMenuItems.vue.d.ts +8 -0
- package/dist/components/ContextMenuItems.vue.js +4 -0
- package/dist/components/LayoutCanvas.vue.js +1 -1
- package/dist/components/LayoutNode.vue.d.ts +4 -0
- package/dist/components/LayoutNode.vue.js +1 -1
- package/dist/components/LpActionBar.vue.d.ts +3 -0
- package/dist/components/LpActionBar.vue.js +1 -1
- package/dist/components/LpAddressInput.vue.d.ts +1 -1
- package/dist/components/LpAddressInput.vue.js +1 -1
- package/dist/components/LpAlert.vue.d.ts +9 -0
- package/dist/components/LpAlert.vue.js +1 -1
- package/dist/components/LpAppShell.vue.d.ts +10 -0
- package/dist/components/LpAppShell.vue.js +1 -1
- package/dist/components/LpAutocomplete.vue.d.ts +31 -6
- package/dist/components/LpAutocomplete.vue.js +1 -1
- package/dist/components/LpAvatar.vue.d.ts +3 -3
- package/dist/components/LpAvatar.vue.js +1 -1
- package/dist/components/LpBadge.vue.d.ts +2 -2
- package/dist/components/LpBreadcrumbs.vue.d.ts +13 -9
- package/dist/components/LpBreadcrumbs.vue.js +1 -1
- package/dist/components/LpButton.vue.d.ts +35 -98
- package/dist/components/LpButton.vue.js +1 -1
- package/dist/components/LpCard.vue.js +1 -1
- package/dist/components/LpChart.vue.d.ts +31 -2
- package/dist/components/LpChart.vue.js +317 -95
- package/dist/components/LpCheckbox.vue.js +1 -1
- package/dist/components/LpCodeBlock.vue.d.ts +2 -0
- package/dist/components/LpCodeBlock.vue.js +1 -1
- package/dist/components/LpColorPicker.vue.js +1 -1
- package/dist/components/LpCommandPalette.vue.d.ts +8 -3
- package/dist/components/LpCommandPalette.vue.js +86 -72
- package/dist/components/LpConfirmDialog.vue.d.ts +15 -3
- package/dist/components/LpConfirmDialog.vue.js +1 -1
- package/dist/components/LpConfirmHost.vue.d.ts +9 -0
- package/dist/components/LpConfirmHost.vue.js +4 -0
- package/dist/components/LpContextMenu.vue.d.ts +3 -5
- package/dist/components/LpContextMenu.vue.js +1 -1
- package/dist/components/LpDatePicker.vue.d.ts +24 -6
- package/dist/components/LpDatePicker.vue.js +1 -1
- package/dist/components/LpDrawer.vue.d.ts +10 -0
- package/dist/components/LpDrawer.vue.js +1 -1
- package/dist/components/LpDropzone.vue.js +22 -6
- package/dist/components/LpFileTree.vue.d.ts +11 -2
- package/dist/components/LpFileTree.vue.js +1 -1
- package/dist/components/LpFileTreeNode.vue.js +1 -1
- package/dist/components/LpFormField.vue.d.ts +9 -0
- package/dist/components/LpFormField.vue.js +1 -1
- package/dist/components/LpImageEditor.vue.js +92 -57
- package/dist/components/LpInput.vue.d.ts +3 -3
- package/dist/components/LpInput.vue.js +1 -1
- package/dist/components/LpLightbox.vue.d.ts +17 -0
- package/dist/components/LpLightbox.vue.js +1 -1
- package/dist/components/LpLink.vue.d.ts +11 -11
- package/dist/components/LpLink.vue.js +1 -1
- package/dist/components/LpLogViewer.vue.d.ts +20 -2
- package/dist/components/LpLogViewer.vue.js +1 -1
- package/dist/components/LpMapPicker.vue.d.ts +4 -4
- package/dist/components/LpMapPicker.vue.js +1 -1
- package/dist/components/LpMediaGallery.vue.js +1 -1
- package/dist/components/LpModal.vue.d.ts +16 -6
- package/dist/components/LpModal.vue.js +1 -1
- package/dist/components/LpModalNav.vue.d.ts +0 -1
- package/dist/components/LpModalNav.vue.js +1 -1
- package/dist/components/LpNotificationBell.vue.d.ts +11 -2
- package/dist/components/LpNotificationBell.vue.js +1 -1
- package/dist/components/LpNumberField.vue.d.ts +2 -0
- package/dist/components/LpNumberField.vue.js +1 -1
- package/dist/components/LpNumberFlow.vue.js +1 -1
- package/dist/components/LpOtpInput.vue.js +1 -1
- package/dist/components/LpPagination.vue.d.ts +2 -0
- package/dist/components/LpPagination.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 +21 -2
- package/dist/components/LpPie.vue.js +1 -1
- package/dist/components/LpPopover.vue.d.ts +2 -0
- package/dist/components/LpPopover.vue.js +1 -1
- package/dist/components/LpProgress.vue.js +1 -1
- package/dist/components/LpRadioGroup.vue.js +1 -1
- package/dist/components/LpSection.vue.d.ts +1 -1
- package/dist/components/LpSegmented.vue.d.ts +5 -0
- package/dist/components/LpSegmented.vue.js +1 -1
- package/dist/components/LpSelect.vue.d.ts +1 -0
- package/dist/components/LpSelect.vue.js +1 -1
- package/dist/components/LpShortcutsDialog.vue.d.ts +1 -1
- package/dist/components/LpShortcutsDialog.vue.js +11 -8
- package/dist/components/LpSidebar.vue.d.ts +6 -2
- package/dist/components/LpSidebar.vue.js +1 -1
- package/dist/components/LpSidebarNav.vue.js +1 -1
- package/dist/components/LpSkeleton.vue.js +1 -1
- package/dist/components/LpSlider.vue.js +1 -1
- package/dist/components/LpSparkline.vue.d.ts +1 -0
- package/dist/components/LpSparkline.vue.js +1 -1
- package/dist/components/LpStat.vue.js +1 -1
- package/dist/components/LpSwitch.vue.js +1 -1
- package/dist/components/LpTable.vue.d.ts +23 -1
- package/dist/components/LpTable.vue.js +74 -36
- package/dist/components/LpTableOfContents.vue.d.ts +4 -2
- package/dist/components/LpTableOfContents.vue.js +1 -1
- package/dist/components/LpTabs.vue.d.ts +2 -0
- package/dist/components/LpTabs.vue.js +1 -1
- package/dist/components/LpTextarea.vue.d.ts +19 -6
- package/dist/components/LpTextarea.vue.js +1 -1
- package/dist/components/LpThemeProvider.vue.d.ts +22 -0
- package/dist/components/LpThemeProvider.vue.js +4 -0
- package/dist/components/LpThemeSwitcher.vue.d.ts +13 -0
- package/dist/components/LpThemeSwitcher.vue.js +1 -1
- package/dist/components/LpTilt.vue.js +1 -1
- package/dist/components/LpTimeField.vue.js +1 -1
- package/dist/components/LpToaster.vue.d.ts +6 -1
- package/dist/components/LpToaster.vue.js +1 -1
- package/dist/components/LpTooltip.vue.d.ts +1 -2
- package/dist/components/LpTooltip.vue.js +1 -1
- package/dist/components/LpTooltipProvider.vue.d.ts +22 -0
- package/dist/components/LpTooltipProvider.vue.js +4 -0
- package/dist/components/LpTopologyCanvas.vue.js +1 -1
- package/dist/components/LpUptimeBar.vue.d.ts +4 -0
- package/dist/components/LpUptimeBar.vue.js +1 -1
- package/dist/components/chart.d.ts +32 -1
- package/dist/components/chart.js +39 -4
- package/dist/components/codeHighlight.d.ts +6 -0
- package/dist/components/codeHighlight.js +92 -20
- package/dist/components/color.d.ts +1 -1
- package/dist/components/color.js +20 -9
- package/dist/components/confirm.d.ts +25 -0
- package/dist/components/confirm.js +26 -0
- package/dist/components/countries.d.ts +6 -0
- package/dist/components/countries.js +7 -0
- package/dist/components/fileTree.js +16 -7
- package/dist/components/imageCrop.d.ts +42 -0
- package/dist/components/imageCrop.js +47 -0
- package/dist/components/link.d.ts +12 -0
- package/dist/components/link.js +19 -0
- package/dist/components/modalDepth.d.ts +18 -2
- package/dist/components/modalDepth.js +17 -5
- package/dist/components/otp.d.ts +5 -0
- package/dist/components/otp.js +10 -0
- package/dist/components/sidebar.d.ts +7 -1
- package/dist/components/tableSort.d.ts +8 -0
- package/dist/components/tableSort.js +31 -0
- package/dist/composables/useField.d.ts +34 -0
- package/dist/composables/useField.js +45 -0
- package/dist/composables/useFormDraft.d.ts +10 -3
- package/dist/composables/useFormDraft.js +9 -14
- package/dist/composables/useHotkeys.d.ts +17 -1
- package/dist/composables/useHotkeys.js +55 -18
- package/dist/composables/useInputFilter.d.ts +17 -0
- package/dist/composables/useInputFilter.js +47 -10
- package/dist/composables/useLpConfig.d.ts +24 -0
- package/dist/composables/useLpConfig.js +44 -0
- package/dist/composables/useRovingFocus.js +7 -0
- package/dist/composables/useTilt.d.ts +2 -2
- package/dist/composables/useTilt.js +5 -6
- package/dist/composables/useToast.d.ts +20 -0
- package/dist/composables/useToast.js +28 -4
- package/dist/composables/useZoomPan.d.ts +3 -3
- package/dist/composables/useZoomPan.js +4 -4
- package/dist/index.d.ts +32 -2
- package/dist/index.js +184 -137
- package/dist/layout/tree.d.ts +2 -0
- package/dist/layout/tree.js +16 -1
- package/dist/layout/useLayout.d.ts +15 -0
- package/dist/layout/useLayout.js +41 -14
- package/dist/theme/useTheme.d.ts +32 -9
- package/package.json +8 -7
- package/src/component-names.ts +5 -7
- package/src/components/ContextMenuItems.vue +88 -0
- package/src/components/LayoutCanvas.vue +26 -6
- package/src/components/LayoutNode.vue +19 -2
- package/src/components/LpActionBar.vue +30 -7
- package/src/components/LpAddressInput.vue +57 -41
- package/src/components/LpAlert.vue +16 -3
- package/src/components/LpAppShell.vue +45 -12
- package/src/components/LpAutocomplete.vue +46 -10
- package/src/components/LpAvatar.vue +19 -5
- package/src/components/LpBreadcrumbs.vue +65 -41
- package/src/components/LpButton.vue +59 -13
- package/src/components/LpChart.vue +272 -28
- package/src/components/LpCheckbox.vue +7 -3
- package/src/components/LpCodeBlock.vue +50 -14
- package/src/components/LpColorPicker.vue +39 -9
- package/src/components/LpCommandPalette.vue +34 -13
- package/src/components/LpConfirmDialog.vue +68 -17
- package/src/components/LpConfirmHost.vue +59 -0
- package/src/components/LpContextMenu.vue +14 -115
- package/src/components/LpDatePicker.vue +99 -68
- package/src/components/LpDrawer.vue +56 -19
- package/src/components/LpDropzone.vue +21 -4
- package/src/components/LpFileTree.vue +33 -7
- package/src/components/LpFormField.vue +30 -7
- package/src/components/LpImageEditor.vue +96 -57
- package/src/components/LpInput.vue +18 -7
- package/src/components/LpLightbox.vue +140 -29
- package/src/components/LpLink.vue +24 -13
- package/src/components/LpLogViewer.vue +86 -17
- package/src/components/LpMapPicker.vue +36 -13
- package/src/components/LpMediaGallery.vue +8 -2
- package/src/components/LpModal.vue +53 -27
- package/src/components/LpModalNav.vue +5 -2
- package/src/components/LpNotificationBell.vue +63 -17
- package/src/components/LpNumberField.vue +21 -6
- package/src/components/LpNumberFlow.vue +26 -10
- package/src/components/LpOtpInput.vue +43 -8
- package/src/components/LpPagination.vue +23 -7
- package/src/components/LpPasswordInput.vue +4 -1
- package/src/components/LpPhoneInput.vue +53 -27
- package/src/components/LpPie.vue +94 -15
- package/src/components/LpPopover.vue +3 -0
- package/src/components/LpProgress.vue +5 -3
- package/src/components/LpRadioGroup.vue +9 -2
- package/src/components/LpSegmented.vue +12 -2
- package/src/components/LpSelect.vue +0 -0
- package/src/components/LpShortcutsDialog.vue +8 -3
- package/src/components/LpSidebar.vue +14 -9
- package/src/components/LpSidebarNav.vue +17 -5
- package/src/components/LpSkeleton.vue +4 -1
- package/src/components/LpSlider.vue +7 -1
- package/src/components/LpSparkline.vue +11 -3
- package/src/components/LpSwitch.vue +30 -7
- package/src/components/LpTable.vue +91 -32
- package/src/components/LpTableOfContents.vue +50 -32
- package/src/components/LpTabs.vue +23 -6
- package/src/components/LpTextarea.vue +44 -6
- package/src/components/LpThemeProvider.vue +41 -0
- package/src/components/LpThemeSwitcher.vue +64 -17
- package/src/components/LpTilt.vue +2 -2
- package/src/components/LpTimeField.vue +14 -3
- package/src/components/LpToaster.vue +66 -26
- package/src/components/LpTooltip.vue +22 -5
- package/src/components/LpTooltipProvider.vue +24 -0
- package/src/components/LpTopologyCanvas.vue +12 -1
- package/src/components/LpUptimeBar.vue +46 -8
- package/src/components/chart.ts +77 -5
- package/src/components/codeHighlight.ts +111 -15
- package/src/components/color.ts +30 -9
- package/src/components/confirm.ts +58 -0
- package/src/components/countries.ts +12 -0
- package/src/components/fileTree.ts +19 -7
- package/src/components/imageCrop.ts +107 -0
- package/src/components/link.ts +34 -0
- package/src/components/modalDepth.ts +48 -6
- package/src/components/otp.ts +16 -0
- package/src/components/sidebar.ts +7 -1
- package/src/components/tableSort.ts +37 -0
- package/src/composables/useField.ts +79 -0
- package/src/composables/useFormDraft.ts +25 -20
- package/src/composables/useHotkeys.ts +89 -18
- package/src/composables/useInputFilter.ts +77 -14
- package/src/composables/useLpConfig.ts +87 -0
- package/src/composables/useRovingFocus.ts +11 -0
- package/src/composables/useTilt.ts +5 -6
- package/src/composables/useToast.ts +56 -4
- package/src/composables/useZoomPan.ts +6 -6
- package/src/index.ts +37 -2
- package/src/layout/tree.ts +30 -0
- package/src/layout/useLayout.ts +68 -18
- package/src/nuxt.ts +59 -17
- package/src/runtime/config.plugin.ts +14 -0
- package/src/runtime/theme.plugin.ts +42 -22
- package/src/theme/useTheme.ts +206 -100
- package/dist/chunks/LpBreadcrumbs-p4jHe_V-.js +0 -62
- package/dist/chunks/LpContextMenu-CwW1QXe_.js +0 -217
- package/dist/chunks/LpDatePicker-CwOToxGq.js +0 -164
- package/dist/chunks/LpFormField-CazBc2-a.js +0 -62
- package/dist/chunks/LpTextarea-t7F6gv8E.js +0 -47
package/dist/layout/tree.js
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { reactive } from "vue";
|
|
2
2
|
let uid = 0;
|
|
3
3
|
const nid = () => `lp-n${uid++}`;
|
|
4
|
+
function claimId(id) {
|
|
5
|
+
const n = /^lp-n(\d+)$/.exec(id);
|
|
6
|
+
if (n) uid = Math.max(uid, Number(n[1]) + 1);
|
|
7
|
+
return id;
|
|
8
|
+
}
|
|
4
9
|
function leaf(block) {
|
|
5
10
|
return { kind: "leaf", id: nid(), blocks: [block], active: 0, size: 1 };
|
|
6
11
|
}
|
|
@@ -173,6 +178,14 @@ function deserializeLayout(data) {
|
|
|
173
178
|
};
|
|
174
179
|
return reactive(hydrate(data));
|
|
175
180
|
}
|
|
181
|
+
function snapshotLayout(root) {
|
|
182
|
+
const strip = (n) => n.kind === "leaf" ? { kind: "leaf", id: n.id, blocks: [...n.blocks], active: n.active, size: n.size } : { kind: "split", id: n.id, dir: n.dir, size: n.size, children: n.children.map(strip) };
|
|
183
|
+
return JSON.stringify(strip(root));
|
|
184
|
+
}
|
|
185
|
+
function restoreLayout(snapshot) {
|
|
186
|
+
const hydrate = (n) => n.kind === "leaf" ? { kind: "leaf", id: claimId(n.id), blocks: [...n.blocks], active: n.active, size: n.size } : { kind: "split", id: claimId(n.id), dir: n.dir, size: n.size, children: n.children.map(hydrate) };
|
|
187
|
+
return reactive(hydrate(JSON.parse(snapshot)));
|
|
188
|
+
}
|
|
176
189
|
export {
|
|
177
190
|
addLeaf,
|
|
178
191
|
addTab,
|
|
@@ -187,6 +200,8 @@ export {
|
|
|
187
200
|
removeLeaf,
|
|
188
201
|
reorderTab,
|
|
189
202
|
resizeAt,
|
|
203
|
+
restoreLayout,
|
|
190
204
|
serializeLayout,
|
|
191
|
-
setActiveTab
|
|
205
|
+
setActiveTab,
|
|
206
|
+
snapshotLayout
|
|
192
207
|
};
|
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
import { type Ref } from "vue";
|
|
2
2
|
import { type Side, type Split } from "./tree";
|
|
3
|
+
/** The edits a canvas performs, routed through history when a controller owns the tree. */
|
|
4
|
+
export interface LayoutController {
|
|
5
|
+
move: (movingId: string, targetId: string, side: Side) => void;
|
|
6
|
+
removeBlock: (leafId: string, index: number) => void;
|
|
7
|
+
reorderTab: (leafId: string, from: number, to: number) => void;
|
|
8
|
+
setActive: (leafId: string, index: number) => void;
|
|
9
|
+
resize: (parent: Split, index: number, deltaFraction: number) => void;
|
|
10
|
+
/** Bracket a continuous resize gesture so it records one history step. */
|
|
11
|
+
beginResize: () => void;
|
|
12
|
+
endResize: () => void;
|
|
13
|
+
}
|
|
14
|
+
/** The controller managing `tree`, if a useLayout() owns it. */
|
|
15
|
+
export declare function layoutController(tree: Split): LayoutController | undefined;
|
|
3
16
|
export interface UseLayoutOptions {
|
|
4
17
|
/** Initial block ids, left-to-right, when no saved layout is loaded. */
|
|
5
18
|
initial: string[];
|
|
@@ -27,6 +40,8 @@ export interface UseLayout {
|
|
|
27
40
|
remove: (leafId: string) => void;
|
|
28
41
|
move: (movingId: string, targetId: string, side: Side) => void;
|
|
29
42
|
resize: (parent: Split, index: number, deltaFraction: number) => void;
|
|
43
|
+
beginResize: () => void;
|
|
44
|
+
endResize: () => void;
|
|
30
45
|
undo: () => void;
|
|
31
46
|
redo: () => void;
|
|
32
47
|
/** Replace the whole layout from a flat block list. */
|
package/dist/layout/useLayout.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
import { shallowRef, computed, ref } from "vue";
|
|
2
|
-
import { makeLayout, countBlocks, serializeLayout, resizeAt, setActiveTab,
|
|
1
|
+
import { shallowRef, computed, ref, watch } from "vue";
|
|
2
|
+
import { makeLayout, countBlocks, serializeLayout, resizeAt, setActiveTab, snapshotLayout, restoreLayout, reorderTab, removeBlock, moveLeaf, deserializeLayout, removeLeaf, addTab, addLeaf } from "./tree.js";
|
|
3
|
+
const controllers = /* @__PURE__ */ new WeakMap();
|
|
4
|
+
function layoutController(tree) {
|
|
5
|
+
return controllers.get(tree);
|
|
6
|
+
}
|
|
3
7
|
function useLayout(options) {
|
|
4
8
|
const limit = options.historyLimit ?? 50;
|
|
5
9
|
const layout = shallowRef(makeLayout(options.initial));
|
|
@@ -8,16 +12,36 @@ function useLayout(options) {
|
|
|
8
12
|
const future = ref([]);
|
|
9
13
|
const canUndo = computed(() => past.value.length > 0);
|
|
10
14
|
const canRedo = computed(() => future.value.length > 0);
|
|
11
|
-
const snapshot = () =>
|
|
12
|
-
function
|
|
13
|
-
|
|
14
|
-
mutate();
|
|
15
|
+
const snapshot = () => snapshotLayout(layout.value);
|
|
16
|
+
function push(before) {
|
|
17
|
+
if (before === snapshot()) return;
|
|
15
18
|
past.value.push(before);
|
|
16
19
|
if (past.value.length > limit) past.value.shift();
|
|
17
20
|
future.value = [];
|
|
18
21
|
}
|
|
22
|
+
function record(mutate) {
|
|
23
|
+
const before = snapshot();
|
|
24
|
+
mutate();
|
|
25
|
+
push(before);
|
|
26
|
+
}
|
|
27
|
+
let resizeStart = null;
|
|
28
|
+
const controller = {
|
|
29
|
+
move: (movingId, targetId, side) => record(() => moveLeaf(layout.value, movingId, targetId, side)),
|
|
30
|
+
removeBlock: (leafId, index) => record(() => removeBlock(layout.value, leafId, index)),
|
|
31
|
+
reorderTab: (leafId, from, to) => record(() => reorderTab(layout.value, leafId, from, to)),
|
|
32
|
+
setActive: (leafId, index) => setActiveTab(layout.value, leafId, index),
|
|
33
|
+
resize: (parent, index, delta) => resizeAt(parent, index, delta),
|
|
34
|
+
beginResize: () => {
|
|
35
|
+
resizeStart = snapshot();
|
|
36
|
+
},
|
|
37
|
+
endResize: () => {
|
|
38
|
+
if (resizeStart !== null) push(resizeStart);
|
|
39
|
+
resizeStart = null;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
watch(layout, (tree) => controllers.set(tree, controller), { immediate: true, flush: "sync" });
|
|
19
43
|
function restore(serialized) {
|
|
20
|
-
layout.value =
|
|
44
|
+
layout.value = restoreLayout(serialized);
|
|
21
45
|
}
|
|
22
46
|
return {
|
|
23
47
|
layout,
|
|
@@ -26,15 +50,17 @@ function useLayout(options) {
|
|
|
26
50
|
canRedo,
|
|
27
51
|
add: (block, side) => record(() => addLeaf(layout.value, block, side)),
|
|
28
52
|
addTab: (leafId, block) => record(() => addTab(layout.value, leafId, block)),
|
|
29
|
-
setActive:
|
|
30
|
-
reorderTab:
|
|
31
|
-
removeBlock:
|
|
53
|
+
setActive: controller.setActive,
|
|
54
|
+
reorderTab: controller.reorderTab,
|
|
55
|
+
removeBlock: controller.removeBlock,
|
|
32
56
|
remove: (leafId) => record(() => removeLeaf(layout.value, leafId)),
|
|
33
|
-
move:
|
|
57
|
+
move: controller.move,
|
|
34
58
|
// Resize fires continuously during a divider drag; recording every frame
|
|
35
|
-
// would flood history
|
|
36
|
-
//
|
|
37
|
-
resize:
|
|
59
|
+
// would flood history. The canvas brackets its gestures with
|
|
60
|
+
// beginResize/endResize, which records the whole drag as one step.
|
|
61
|
+
resize: controller.resize,
|
|
62
|
+
beginResize: controller.beginResize,
|
|
63
|
+
endResize: controller.endResize,
|
|
38
64
|
undo: () => {
|
|
39
65
|
const prev = past.value.pop();
|
|
40
66
|
if (prev === void 0) return;
|
|
@@ -57,5 +83,6 @@ function useLayout(options) {
|
|
|
57
83
|
};
|
|
58
84
|
}
|
|
59
85
|
export {
|
|
86
|
+
layoutController,
|
|
60
87
|
useLayout
|
|
61
88
|
};
|
package/dist/theme/useTheme.d.ts
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
import { type ComputedRef, type DeepReadonly, type Ref } from "vue";
|
|
2
2
|
import { type TokenSet } from "./tokens";
|
|
3
|
+
/** A light/dark pair followed by the operating system's colour scheme. */
|
|
4
|
+
export interface SystemThemes {
|
|
5
|
+
light: TokenSet;
|
|
6
|
+
dark: TokenSet;
|
|
7
|
+
}
|
|
8
|
+
/** Whether the OS asks for dark. True where it cannot be asked (server, old engines). */
|
|
9
|
+
export declare function prefersDarkScheme(): boolean;
|
|
10
|
+
/** Every CSS variable a theme sets, in application order. */
|
|
11
|
+
export declare function themeEntries(input: TokenSet): [string, string][];
|
|
3
12
|
export declare function applyTheme(theme: TokenSet, root?: HTMLElement): void;
|
|
4
13
|
/** Point a circular theme reveal expands from (viewport px). */
|
|
5
14
|
export interface RevealOrigin {
|
|
@@ -11,31 +20,45 @@ export declare function serializeTheme(theme: TokenSet): string;
|
|
|
11
20
|
export declare function themeToCssVars(theme: TokenSet): string;
|
|
12
21
|
/** Render a theme as a complete CSS rule (default selector `:root`). */
|
|
13
22
|
export declare function themeToCssRule(theme: TokenSet, selector?: string): string;
|
|
14
|
-
|
|
23
|
+
export declare function normalizeTheme(raw: Partial<TokenSet> & {
|
|
24
|
+
name?: string;
|
|
25
|
+
}): TokenSet;
|
|
26
|
+
/** Parse + validate a theme JSON; throws on a malformed shape. */
|
|
15
27
|
export declare function parseTheme(json: string): TokenSet;
|
|
16
28
|
export declare function bootstrapTheme(fallback: TokenSet): TokenSet;
|
|
17
29
|
export declare function cacheTheme(theme: TokenSet): void;
|
|
30
|
+
/** Persist "follow the OS" with the pair it switches between. */
|
|
31
|
+
export declare function cacheSystemThemes(system: SystemThemes): void;
|
|
18
32
|
export declare const THEME_COOKIE = "lp-theme";
|
|
19
33
|
/**
|
|
20
34
|
* Resolve a theme name (as read from the `lp-theme` cookie) against a set of
|
|
21
35
|
* known themes. Returns `null` when the name is absent or unknown, so the caller
|
|
22
36
|
* can fall back to its own default.
|
|
23
37
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
38
|
+
* Accepts both a raw and an already-decoded value: frameworks differ on whether
|
|
39
|
+
* their cookie helpers decode, and a name containing `%` must not throw.
|
|
40
|
+
* A "follow the OS" cookie resolves to its dark member unless `prefersDark` is
|
|
41
|
+
* false (pass it from the `Sec-CH-Prefers-Color-Scheme` request header).
|
|
26
42
|
*/
|
|
27
|
-
export declare function themeFromCookie(cookieValue: string | null | undefined, themes: readonly TokenSet[]
|
|
43
|
+
export declare function themeFromCookie(cookieValue: string | null | undefined, themes: readonly TokenSet[], options?: {
|
|
44
|
+
prefersDark?: boolean;
|
|
45
|
+
}): TokenSet | null;
|
|
28
46
|
export interface UseTheme {
|
|
29
47
|
/** The active theme, kept in sync by the kit. Null until hydrated (SSR/first
|
|
30
|
-
* paint)
|
|
48
|
+
* paint), reactive, so a switcher binds straight to it. */
|
|
31
49
|
current: DeepReadonly<Ref<TokenSet | null>>;
|
|
32
50
|
/** The active theme's name (""="not yet hydrated"). */
|
|
33
51
|
currentName: ComputedRef<string>;
|
|
34
|
-
/**
|
|
35
|
-
|
|
52
|
+
/** True while the theme follows the OS colour scheme (see setSystem). */
|
|
53
|
+
system: ComputedRef<boolean>;
|
|
54
|
+
/** Set + persist a theme (with the circular reveal). Stops following the OS. */
|
|
36
55
|
setTheme: (theme: TokenSet, origin?: RevealOrigin) => void;
|
|
37
|
-
/**
|
|
38
|
-
*
|
|
56
|
+
/**
|
|
57
|
+
* Follow the OS colour scheme, switching between `themes.light` and
|
|
58
|
+
* `themes.dark` as it changes. Persisted like any other choice.
|
|
59
|
+
*/
|
|
60
|
+
setSystem: (themes: SystemThemes, origin?: RevealOrigin) => void;
|
|
61
|
+
/** Seed the fallback (used when nothing is cached) and hydrate now. */
|
|
39
62
|
init: (fallback: TokenSet) => TokenSet;
|
|
40
63
|
apply: (theme: TokenSet) => void;
|
|
41
64
|
applyWithTransition: (theme: TokenSet, origin?: RevealOrigin) => void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@leavepulse/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.44.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "LeavePulse token-driven Vue component kit.",
|
|
6
6
|
"repository": {
|
|
@@ -28,10 +28,11 @@
|
|
|
28
28
|
"./scrollbar.css": "./src/tokens/scrollbar.css",
|
|
29
29
|
"./canvas.css": "./src/canvas.css",
|
|
30
30
|
"./package.json": "./package.json",
|
|
31
|
-
"./dist
|
|
31
|
+
"./dist/*.js": {
|
|
32
32
|
"types": "./dist/*.d.ts",
|
|
33
|
-
"default": "./dist
|
|
34
|
-
}
|
|
33
|
+
"default": "./dist/*.js"
|
|
34
|
+
},
|
|
35
|
+
"./dist/*": "./dist/*"
|
|
35
36
|
},
|
|
36
37
|
"publishConfig": {
|
|
37
38
|
"registry": "https://registry.npmjs.org",
|
|
@@ -40,7 +41,7 @@
|
|
|
40
41
|
"sideEffects": [
|
|
41
42
|
"**/*.css",
|
|
42
43
|
"**/icons.ts",
|
|
43
|
-
"**/
|
|
44
|
+
"**/chunks/LpIcon-*.js"
|
|
44
45
|
],
|
|
45
46
|
"scripts": {
|
|
46
47
|
"dev": "vite",
|
|
@@ -52,14 +53,14 @@
|
|
|
52
53
|
"test": "bun test",
|
|
53
54
|
"release": "npm version patch -m \"chore: release v%s\" && git push --follow-tags",
|
|
54
55
|
"release:minor": "npm version minor -m \"chore: release v%s\" && git push --follow-tags",
|
|
55
|
-
"release:major": "npm version major -m \"chore: release v%s\" && git push --follow-tags"
|
|
56
|
+
"release:major": "npm version major -m \"chore: release v%s\" && git push --follow-tags",
|
|
57
|
+
"check:pack": "node scripts/check-pack.mjs"
|
|
56
58
|
},
|
|
57
59
|
"peerDependencies": {
|
|
58
60
|
"@iconify-json/lucide": "^1.2.0",
|
|
59
61
|
"@iconify/vue": "^5.0.0",
|
|
60
62
|
"@internationalized/date": "^3.5.0",
|
|
61
63
|
"@nuxt/kit": "^3.0.0 || ^4.0.0",
|
|
62
|
-
"@vueuse/core": "^12.0.0 || ^13.0.0 || ^14.0.0",
|
|
63
64
|
"motion-v": "^2.2.0",
|
|
64
65
|
"reka-ui": "^2.9.0",
|
|
65
66
|
"tailwind-variants": "^3.0.0",
|
package/src/component-names.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
/* AUTO-GENERATED by scripts/gen-component-names.mjs — do not edit.
|
|
2
2
|
* The full list of kit component names, kept in sync with the component files
|
|
3
|
-
* so the Nuxt module (./nuxt) auto-registers every component including new ones. */
|
|
3
|
+
* so the Nuxt module (./nuxt) auto-registers every exported component including new ones. */
|
|
4
4
|
export const COMPONENT_NAMES = [
|
|
5
5
|
"LayoutCanvas",
|
|
6
|
-
"LayoutNode",
|
|
7
6
|
"LpActionBar",
|
|
8
7
|
"LpAddressInput",
|
|
9
8
|
"LpAlert",
|
|
@@ -21,6 +20,7 @@ export const COMPONENT_NAMES = [
|
|
|
21
20
|
"LpColorPicker",
|
|
22
21
|
"LpCommandPalette",
|
|
23
22
|
"LpConfirmDialog",
|
|
23
|
+
"LpConfirmHost",
|
|
24
24
|
"LpContextMenu",
|
|
25
25
|
"LpDatePicker",
|
|
26
26
|
"LpDisclosure",
|
|
@@ -30,13 +30,11 @@ export const COMPONENT_NAMES = [
|
|
|
30
30
|
"LpDropzone",
|
|
31
31
|
"LpEmptyState",
|
|
32
32
|
"LpFileTree",
|
|
33
|
-
"LpFileTreeNode",
|
|
34
33
|
"LpFormField",
|
|
35
34
|
"LpIcon",
|
|
36
35
|
"LpImageEditor",
|
|
37
36
|
"LpInfraNode",
|
|
38
37
|
"LpInput",
|
|
39
|
-
"LpLaneNode",
|
|
40
38
|
"LpLightbox",
|
|
41
39
|
"LpLink",
|
|
42
40
|
"LpLogViewer",
|
|
@@ -65,7 +63,6 @@ export const COMPONENT_NAMES = [
|
|
|
65
63
|
"LpShift",
|
|
66
64
|
"LpShortcutsDialog",
|
|
67
65
|
"LpSidebar",
|
|
68
|
-
"LpSidebarNav",
|
|
69
66
|
"LpSkeleton",
|
|
70
67
|
"LpSlider",
|
|
71
68
|
"LpSparkline",
|
|
@@ -76,12 +73,13 @@ export const COMPONENT_NAMES = [
|
|
|
76
73
|
"LpTableOfContents",
|
|
77
74
|
"LpTabs",
|
|
78
75
|
"LpTextarea",
|
|
76
|
+
"LpThemeProvider",
|
|
79
77
|
"LpThemeSwitcher",
|
|
80
78
|
"LpTilt",
|
|
81
79
|
"LpTimeField",
|
|
82
80
|
"LpToaster",
|
|
83
81
|
"LpTooltip",
|
|
82
|
+
"LpTooltipProvider",
|
|
84
83
|
"LpTopologyCanvas",
|
|
85
|
-
"LpUptimeBar"
|
|
86
|
-
"LpWaypointEdge"
|
|
84
|
+
"LpUptimeBar"
|
|
87
85
|
] as const
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/*
|
|
3
|
+
* The rows of an LpContextMenu panel, rendering itself for every submenu so
|
|
4
|
+
* `children` nests to any depth. Internal: not exported.
|
|
5
|
+
*/
|
|
6
|
+
import {
|
|
7
|
+
ContextMenuCheckboxItem,
|
|
8
|
+
ContextMenuItem,
|
|
9
|
+
ContextMenuPortal,
|
|
10
|
+
ContextMenuSeparator,
|
|
11
|
+
ContextMenuSub,
|
|
12
|
+
ContextMenuSubContent,
|
|
13
|
+
ContextMenuSubTrigger,
|
|
14
|
+
} from "reka-ui"
|
|
15
|
+
import type { ContextMenuItemDef } from "./LpContextMenu.vue"
|
|
16
|
+
import LpIcon from "./LpIcon.vue"
|
|
17
|
+
|
|
18
|
+
defineOptions({ name: "ContextMenuItems" })
|
|
19
|
+
|
|
20
|
+
defineProps<{
|
|
21
|
+
items: ContextMenuItemDef[]
|
|
22
|
+
panel: string
|
|
23
|
+
}>()
|
|
24
|
+
|
|
25
|
+
const ITEM =
|
|
26
|
+
"group/item flex cursor-pointer select-none items-center gap-2 rounded-md px-2.5 py-1.5 text-sm outline-none transition-[background-color,color] duration-[var(--duration-fast)] data-[disabled]:pointer-events-none data-[disabled]:opacity-45 data-[highlighted]:bg-brand-soft"
|
|
27
|
+
const ICON =
|
|
28
|
+
"transition-transform duration-[var(--duration-fast)] ease-[var(--ease-emphasized)] group-data-[highlighted]/item:translate-x-0.5"
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<template>
|
|
32
|
+
<template v-for="(item, i) in items" :key="i">
|
|
33
|
+
<ContextMenuSeparator v-if="item.separatorBefore" class="my-1 h-px bg-line" />
|
|
34
|
+
|
|
35
|
+
<ContextMenuSub v-if="item.children?.length">
|
|
36
|
+
<ContextMenuSubTrigger
|
|
37
|
+
:class="[ITEM, 'justify-between text-ink data-[highlighted]:text-brand data-[state=open]:bg-brand-soft data-[state=open]:text-brand']"
|
|
38
|
+
:disabled="item.disabled"
|
|
39
|
+
>
|
|
40
|
+
<span class="flex items-center gap-2">
|
|
41
|
+
<LpIcon v-if="item.icon" :name="item.icon" :size="15" :class="ICON" />
|
|
42
|
+
{{ item.label }}
|
|
43
|
+
</span>
|
|
44
|
+
<LpIcon name="lucide:chevron-right" :size="14" class="text-muted" />
|
|
45
|
+
</ContextMenuSubTrigger>
|
|
46
|
+
<ContextMenuPortal>
|
|
47
|
+
<ContextMenuSubContent :class="panel" :side-offset="2" :align-offset="-4">
|
|
48
|
+
<ContextMenuItems :items="item.children" :panel="panel" />
|
|
49
|
+
</ContextMenuSubContent>
|
|
50
|
+
</ContextMenuPortal>
|
|
51
|
+
</ContextMenuSub>
|
|
52
|
+
|
|
53
|
+
<!-- Tick-box item: a real checkbox item, so assistive tech hears its state.
|
|
54
|
+
`@select.prevent` keeps the menu open, since these come in lists where
|
|
55
|
+
several are set in one visit. The tick occupies a fixed slot so
|
|
56
|
+
unticked rows stay aligned with ticked ones. -->
|
|
57
|
+
<ContextMenuCheckboxItem
|
|
58
|
+
v-else-if="item.checked !== undefined"
|
|
59
|
+
:model-value="item.checked"
|
|
60
|
+
:class="[ITEM, 'justify-between text-ink data-[highlighted]:text-brand']"
|
|
61
|
+
:disabled="item.disabled"
|
|
62
|
+
@select.prevent="item.onSelect?.()"
|
|
63
|
+
>
|
|
64
|
+
<span class="flex items-center gap-2">
|
|
65
|
+
<LpIcon
|
|
66
|
+
:name="item.checked ? 'lucide:check' : 'lucide:minus'"
|
|
67
|
+
:size="15"
|
|
68
|
+
:class="[ICON, item.checked ? '' : 'opacity-25']"
|
|
69
|
+
/>
|
|
70
|
+
{{ item.label }}
|
|
71
|
+
</span>
|
|
72
|
+
<kbd v-if="item.shortcut" class="text-xs text-muted">{{ item.shortcut }}</kbd>
|
|
73
|
+
</ContextMenuCheckboxItem>
|
|
74
|
+
|
|
75
|
+
<ContextMenuItem
|
|
76
|
+
v-else
|
|
77
|
+
:class="[ITEM, 'justify-between', item.danger ? 'text-danger data-[highlighted]:bg-danger-soft data-[highlighted]:text-danger' : 'text-ink data-[highlighted]:text-brand']"
|
|
78
|
+
:disabled="item.disabled"
|
|
79
|
+
@select="item.onSelect?.()"
|
|
80
|
+
>
|
|
81
|
+
<span class="flex items-center gap-2">
|
|
82
|
+
<LpIcon v-if="item.icon" :name="item.icon" :size="15" :class="ICON" />
|
|
83
|
+
{{ item.label }}
|
|
84
|
+
</span>
|
|
85
|
+
<kbd v-if="item.shortcut" class="text-xs text-muted">{{ item.shortcut }}</kbd>
|
|
86
|
+
</ContextMenuItem>
|
|
87
|
+
</template>
|
|
88
|
+
</template>
|
|
@@ -22,7 +22,8 @@ import {
|
|
|
22
22
|
type Split,
|
|
23
23
|
} from "../layout/tree"
|
|
24
24
|
import type { BlockRegistry } from "../layout/registry"
|
|
25
|
-
import {
|
|
25
|
+
import { layoutController, type LayoutController } from "../layout/useLayout"
|
|
26
|
+
import { computed, ref } from "vue"
|
|
26
27
|
|
|
27
28
|
const props = defineProps<{
|
|
28
29
|
modelValue: Split
|
|
@@ -42,13 +43,30 @@ defineSlots<{
|
|
|
42
43
|
|
|
43
44
|
const dragId = ref<string | null>(null)
|
|
44
45
|
|
|
46
|
+
// A tree owned by useLayout() is edited through its controller, so every edit
|
|
47
|
+
// lands in undo history; a bare tree is mutated directly as before.
|
|
48
|
+
const edits = computed<LayoutController>(() => {
|
|
49
|
+
const tree = props.modelValue
|
|
50
|
+
return (
|
|
51
|
+
layoutController(tree) ?? {
|
|
52
|
+
move: (movingId, targetId, side) => moveLeaf(tree, movingId, targetId, side),
|
|
53
|
+
removeBlock: (leafId, index) => removeBlock(tree, leafId, index),
|
|
54
|
+
reorderTab: (leafId, from, to) => reorderTab(tree, leafId, from, to),
|
|
55
|
+
setActive: (leafId, index) => setActiveTab(tree, leafId, index),
|
|
56
|
+
resize: (parent, index, delta) => resizeAt(parent, index, delta),
|
|
57
|
+
beginResize: () => {},
|
|
58
|
+
endResize: () => {},
|
|
59
|
+
}
|
|
60
|
+
)
|
|
61
|
+
})
|
|
62
|
+
|
|
45
63
|
function onDrop(targetId: string, side: Side) {
|
|
46
|
-
if (dragId.value)
|
|
64
|
+
if (dragId.value) edits.value.move(dragId.value, targetId, side)
|
|
47
65
|
dragId.value = null
|
|
48
66
|
}
|
|
49
67
|
|
|
50
68
|
function onResize(parent: Split, index: number, delta: number) {
|
|
51
|
-
|
|
69
|
+
edits.value.resize(parent, index, delta)
|
|
52
70
|
}
|
|
53
71
|
</script>
|
|
54
72
|
|
|
@@ -63,10 +81,12 @@ function onResize(parent: Split, index: number, delta: number) {
|
|
|
63
81
|
@dragstart="(id) => (dragId = id)"
|
|
64
82
|
@dragend="dragId = null"
|
|
65
83
|
@drop="onDrop"
|
|
66
|
-
@set-active="(leafId, i) =>
|
|
67
|
-
@remove-block="(leafId, i) => removeBlock(
|
|
68
|
-
@reorder-tab="(leafId, from, to) => reorderTab(
|
|
84
|
+
@set-active="(leafId, i) => edits.setActive(leafId, i)"
|
|
85
|
+
@remove-block="(leafId, i) => edits.removeBlock(leafId, i)"
|
|
86
|
+
@reorder-tab="(leafId, from, to) => edits.reorderTab(leafId, from, to)"
|
|
69
87
|
@resize="onResize"
|
|
88
|
+
@resize-start="edits.beginResize()"
|
|
89
|
+
@resize-end="edits.endResize()"
|
|
70
90
|
>
|
|
71
91
|
<template #block="slotProps">
|
|
72
92
|
<slot name="block" v-bind="slotProps" />
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { Motion } from "motion-v"
|
|
3
|
-
import { computed, ref } from "vue"
|
|
3
|
+
import { computed, onBeforeUnmount, ref } from "vue"
|
|
4
4
|
import type { LayoutNode, Leaf, Side, Split } from "../layout/tree"
|
|
5
5
|
import type { BlockRegistry } from "../layout/registry"
|
|
6
6
|
import { blockTitle } from "../layout/registry"
|
|
@@ -21,6 +21,8 @@ const emit = defineEmits<{
|
|
|
21
21
|
(e: "remove-block", leafId: string, index: number): void
|
|
22
22
|
(e: "reorder-tab", leafId: string, from: number, to: number): void
|
|
23
23
|
(e: "resize", parent: Split, index: number, deltaFraction: number): void
|
|
24
|
+
(e: "resize-start"): void
|
|
25
|
+
(e: "resize-end"): void
|
|
24
26
|
}>()
|
|
25
27
|
|
|
26
28
|
// Explicit slot shape so the recursive #block pass-through types cleanly.
|
|
@@ -97,10 +99,18 @@ function onDragOver(ev: DragEvent) {
|
|
|
97
99
|
else hoverSide.value = "center"
|
|
98
100
|
}
|
|
99
101
|
|
|
102
|
+
let stopSplitter: (() => void) | null = null
|
|
103
|
+
onBeforeUnmount(() => stopSplitter?.())
|
|
104
|
+
|
|
100
105
|
function startSplitter(ev: PointerEvent, parent: Split, index: number) {
|
|
101
106
|
ev.preventDefault()
|
|
102
|
-
const
|
|
107
|
+
const handle = ev.currentTarget as HTMLElement
|
|
108
|
+
const host = handle.parentElement
|
|
103
109
|
if (!host) return
|
|
110
|
+
// Capture keeps the moves coming when the pointer crosses an iframe or leaves
|
|
111
|
+
// the window; pointercancel (a touch the browser took over) ends it too.
|
|
112
|
+
handle.setPointerCapture?.(ev.pointerId)
|
|
113
|
+
emit("resize-start")
|
|
104
114
|
const rect = host.getBoundingClientRect()
|
|
105
115
|
const horizontal = parent.dir === "row"
|
|
106
116
|
const span = horizontal ? rect.width : rect.height
|
|
@@ -114,9 +124,14 @@ function startSplitter(ev: PointerEvent, parent: Split, index: number) {
|
|
|
114
124
|
const up = () => {
|
|
115
125
|
window.removeEventListener("pointermove", move)
|
|
116
126
|
window.removeEventListener("pointerup", up)
|
|
127
|
+
window.removeEventListener("pointercancel", up)
|
|
128
|
+
stopSplitter = null
|
|
129
|
+
emit("resize-end")
|
|
117
130
|
}
|
|
131
|
+
stopSplitter = up
|
|
118
132
|
window.addEventListener("pointermove", move)
|
|
119
133
|
window.addEventListener("pointerup", up)
|
|
134
|
+
window.addEventListener("pointercancel", up)
|
|
120
135
|
}
|
|
121
136
|
</script>
|
|
122
137
|
|
|
@@ -141,6 +156,8 @@ function startSplitter(ev: PointerEvent, parent: Split, index: number) {
|
|
|
141
156
|
@remove-block="(l, idx) => emit('remove-block', l, idx)"
|
|
142
157
|
@reorder-tab="(l, from, to) => emit('reorder-tab', l, from, to)"
|
|
143
158
|
@resize="(p, idx, d) => emit('resize', p, idx, d)"
|
|
159
|
+
@resize-start="emit('resize-start')"
|
|
160
|
+
@resize-end="emit('resize-end')"
|
|
144
161
|
>
|
|
145
162
|
<template #block="slotProps">
|
|
146
163
|
<slot name="block" v-bind="slotProps" />
|
|
@@ -20,7 +20,8 @@
|
|
|
20
20
|
* name rather than `alertdialog` — it is a landmark you can Tab into, not a
|
|
21
21
|
* thing demanding an answer before anything else can happen.
|
|
22
22
|
*/
|
|
23
|
-
import { computed,
|
|
23
|
+
import { computed, onBeforeUnmount, ref, useSlots, watch } from "vue"
|
|
24
|
+
import { useLabels } from "../composables/useLpConfig"
|
|
24
25
|
import { useBarStack } from "./actionBar"
|
|
25
26
|
import { CLOSE_ICON } from "./dropdown"
|
|
26
27
|
import LpButton from "./LpButton.vue"
|
|
@@ -85,6 +86,7 @@ const props = withDefaults(
|
|
|
85
86
|
maxWidth?: string
|
|
86
87
|
/** Accessible name for the landmark. Falls back to `title`. */
|
|
87
88
|
ariaLabel?: string
|
|
89
|
+
labels?: Partial<{ dismiss: string }>
|
|
88
90
|
}>(),
|
|
89
91
|
{
|
|
90
92
|
open: true,
|
|
@@ -100,6 +102,7 @@ const emit = defineEmits<{
|
|
|
100
102
|
}>()
|
|
101
103
|
|
|
102
104
|
const slots = useSlots()
|
|
105
|
+
const text = useLabels("actionBar", { dismiss: "Dismiss" }, () => props.labels)
|
|
103
106
|
|
|
104
107
|
// The last action is the primary one unless the caller has said otherwise; the
|
|
105
108
|
// rest default to `ghost` so a bar with three buttons still has one obvious
|
|
@@ -154,19 +157,39 @@ const stackOffset = computed(() => {
|
|
|
154
157
|
return offset()
|
|
155
158
|
})
|
|
156
159
|
|
|
160
|
+
/*
|
|
161
|
+
* The height is watched, not measured once: a description that wraps after a
|
|
162
|
+
* rotation, or content swapped while the bar is up, changes it, and the bars
|
|
163
|
+
* above would overlap this one.
|
|
164
|
+
*/
|
|
165
|
+
let observer: ResizeObserver | null = null
|
|
166
|
+
|
|
157
167
|
watch(
|
|
158
168
|
() => props.open,
|
|
159
|
-
|
|
169
|
+
(isOpen) => {
|
|
170
|
+
// Nothing on the server ever unregisters, so registering there would leak
|
|
171
|
+
// one slot per rendered request into every later page.
|
|
172
|
+
if (typeof window === "undefined") return
|
|
160
173
|
if (!isOpen) {
|
|
161
174
|
unregister()
|
|
162
175
|
return
|
|
163
176
|
}
|
|
164
177
|
register()
|
|
165
|
-
await nextTick()
|
|
166
|
-
if (root.value) setHeight(root.value.getBoundingClientRect().height)
|
|
167
178
|
},
|
|
168
179
|
{ immediate: true },
|
|
169
180
|
)
|
|
181
|
+
|
|
182
|
+
watch(root, (el) => {
|
|
183
|
+
observer?.disconnect()
|
|
184
|
+
observer = null
|
|
185
|
+
if (!el) return
|
|
186
|
+
setHeight(el.getBoundingClientRect().height)
|
|
187
|
+
if (typeof ResizeObserver === "undefined") return
|
|
188
|
+
observer = new ResizeObserver(() => setHeight(el.getBoundingClientRect().height))
|
|
189
|
+
observer.observe(el)
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
onBeforeUnmount(() => observer?.disconnect())
|
|
170
193
|
</script>
|
|
171
194
|
|
|
172
195
|
<template>
|
|
@@ -194,9 +217,9 @@ watch(
|
|
|
194
217
|
ref="root"
|
|
195
218
|
role="region"
|
|
196
219
|
:aria-label="ariaLabel ?? title"
|
|
197
|
-
class="pointer-events-none fixed inset-x-0 bottom-0
|
|
220
|
+
class="pointer-events-none fixed inset-x-0 bottom-0 flex justify-center transition-[translate] duration-[var(--duration-medium)] ease-[var(--ease-emphasized)] motion-reduce:transition-none"
|
|
198
221
|
:class="width === 'full' ? '' : 'p-3 sm:p-4'"
|
|
199
|
-
:style="{ translate: `0 -${stackOffset}px
|
|
222
|
+
:style="{ translate: `0 -${stackOffset}px`, zIndex: 'calc(var(--z-overlay) - 1)' }"
|
|
200
223
|
>
|
|
201
224
|
<div
|
|
202
225
|
class="lp-skin-panel pointer-events-auto flex items-center gap-3 border-solid bg-surface-overlay"
|
|
@@ -261,7 +284,7 @@ watch(
|
|
|
261
284
|
<button
|
|
262
285
|
v-if="dismissible"
|
|
263
286
|
type="button"
|
|
264
|
-
aria-label="
|
|
287
|
+
:aria-label="text.dismiss"
|
|
265
288
|
class="group -mr-1 flex size-8 shrink-0 items-center justify-center rounded-control text-muted outline-none transition-colors duration-[var(--duration-fast)] hover:text-ink focus-visible:ring-2 focus-visible:ring-ring"
|
|
266
289
|
@click="dismiss"
|
|
267
290
|
>
|