@leavepulse/ui 0.43.3 → 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-DH7sPcKP.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 -10
- package/dist/components/LpCommandPalette.vue.js +88 -78
- 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/commandSearch.d.ts +0 -1
- package/dist/components/commandSearch.js +1 -17
- 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 +33 -3
- package/dist/index.js +185 -139
- 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 +36 -25
- 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/commandSearch.ts +0 -17
- 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 +38 -3
- 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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { computed, ref, type ComputedRef, type CSSProperties, type Ref } from "vue"
|
|
1
|
+
import { computed, ref, toValue, type ComputedRef, type CSSProperties, type MaybeRefOrGetter, type Ref } from "vue"
|
|
2
2
|
|
|
3
3
|
/*
|
|
4
4
|
* useZoomPan — zoom + pan for a single element inside a viewport, the way an
|
|
@@ -15,8 +15,8 @@ import { computed, ref, type ComputedRef, type CSSProperties, type Ref } from "v
|
|
|
15
15
|
export interface UseZoomPanOptions {
|
|
16
16
|
/** Smallest allowed scale. Default 1 (fit — never shrink past the viewport). */
|
|
17
17
|
min?: number
|
|
18
|
-
/** Largest allowed scale. Default 8. */
|
|
19
|
-
max?: number
|
|
18
|
+
/** Largest allowed scale. Default 8. Read on every change, so it may be a getter. */
|
|
19
|
+
max?: MaybeRefOrGetter<number | undefined>
|
|
20
20
|
/** Multiplier per wheel notch. Default 1.15. */
|
|
21
21
|
step?: number
|
|
22
22
|
/** Scale that a double-click/tap toggles to, from `min`. Default 2. */
|
|
@@ -62,7 +62,7 @@ export interface UseZoomPan {
|
|
|
62
62
|
|
|
63
63
|
export function useZoomPan(options: UseZoomPanOptions = {}): UseZoomPan {
|
|
64
64
|
const min = options.min ?? 1
|
|
65
|
-
const
|
|
65
|
+
const maxOf = () => toValue(options.max) ?? 8
|
|
66
66
|
const step = options.step ?? 1.15
|
|
67
67
|
const zoomedScale = options.zoomedScale ?? 2
|
|
68
68
|
|
|
@@ -104,7 +104,7 @@ export function useZoomPan(options: UseZoomPanOptions = {}): UseZoomPan {
|
|
|
104
104
|
|
|
105
105
|
/** Zoom to `next`, holding the viewport-relative point `px,py` in place. */
|
|
106
106
|
function zoomAbout(next: number, px: number, py: number) {
|
|
107
|
-
const clamped = clamp(next, min,
|
|
107
|
+
const clamped = clamp(next, min, maxOf())
|
|
108
108
|
if (clamped === scale.value) return
|
|
109
109
|
// Where the cursor sits in content space before the change; solving for the
|
|
110
110
|
// same content point after gives the translate that keeps it under the
|
|
@@ -215,7 +215,7 @@ export function useZoomPan(options: UseZoomPanOptions = {}): UseZoomPan {
|
|
|
215
215
|
|
|
216
216
|
function setView(view: { x: number; y: number; scale?: number }) {
|
|
217
217
|
if (view.scale !== undefined) {
|
|
218
|
-
scale.value = Math.min(
|
|
218
|
+
scale.value = Math.min(maxOf(), Math.max(min, view.scale))
|
|
219
219
|
}
|
|
220
220
|
x.value = view.x
|
|
221
221
|
y.value = view.y
|
package/src/index.ts
CHANGED
|
@@ -36,6 +36,7 @@ export { default as LpCalendar } from "./components/LpCalendar.vue"
|
|
|
36
36
|
export { default as LpCard } from "./components/LpCard.vue"
|
|
37
37
|
export { default as LpChart } from "./components/LpChart.vue"
|
|
38
38
|
export type { ChartPointEvent } from "./components/LpChart.vue"
|
|
39
|
+
export type { ChartText } from "./components/LpChart.vue"
|
|
39
40
|
export {
|
|
40
41
|
CHART_PALETTE,
|
|
41
42
|
axisTicks,
|
|
@@ -43,9 +44,12 @@ export {
|
|
|
43
44
|
niceScale,
|
|
44
45
|
} from "./components/chart"
|
|
45
46
|
export type { ChartAxis, ChartPoint, ChartSeries } from "./components/chart"
|
|
47
|
+
export { chartSummary, markerIndex } from "./components/chart"
|
|
48
|
+
export type { ChartMarker, ChartThreshold } from "./components/chart"
|
|
46
49
|
export { default as LpCheckbox } from "./components/LpCheckbox.vue"
|
|
47
50
|
export { default as LpCodeBlock } from "./components/LpCodeBlock.vue"
|
|
48
51
|
export type { CodeLang } from "./components/codeHighlight"
|
|
52
|
+
export { tokenizeLines } from "./components/codeHighlight"
|
|
49
53
|
export { default as LpColorPicker } from "./components/LpColorPicker.vue"
|
|
50
54
|
export type { ColorPickerLabels } from "./components/LpColorPicker.vue"
|
|
51
55
|
export {
|
|
@@ -65,9 +69,13 @@ export {
|
|
|
65
69
|
export type { ColorFormat, Hsv, Rgb } from "./components/color"
|
|
66
70
|
export { default as LpCommandPalette } from "./components/LpCommandPalette.vue"
|
|
67
71
|
export type { Command, PaletteLabels } from "./components/LpCommandPalette.vue"
|
|
68
|
-
export { parseCommandQuery, rankCommandItems
|
|
72
|
+
export { parseCommandQuery, rankCommandItems } from "./components/commandSearch"
|
|
69
73
|
export type { CommandSearchTerms, SearchableCommand } from "./components/commandSearch"
|
|
70
74
|
export { default as LpConfirmDialog } from "./components/LpConfirmDialog.vue"
|
|
75
|
+
export type { ConfirmLabels } from "./components/LpConfirmDialog.vue"
|
|
76
|
+
export { default as LpConfirmHost } from "./components/LpConfirmHost.vue"
|
|
77
|
+
export { confirm, useConfirm } from "./components/confirm"
|
|
78
|
+
export type { ConfirmOptions } from "./components/confirm"
|
|
71
79
|
export { default as LpContextMenu } from "./components/LpContextMenu.vue"
|
|
72
80
|
export type { ContextMenuItemDef } from "./components/LpContextMenu.vue"
|
|
73
81
|
export { default as LpDatePicker } from "./components/LpDatePicker.vue"
|
|
@@ -80,6 +88,7 @@ export { default as LpDropzone } from "./components/LpDropzone.vue"
|
|
|
80
88
|
export { default as LpEmptyState } from "./components/LpEmptyState.vue"
|
|
81
89
|
export { default as LpFileTree } from "./components/LpFileTree.vue"
|
|
82
90
|
export type { FileTreeSummary } from "./components/LpFileTree.vue"
|
|
91
|
+
export type { FileTreeLabels } from "./components/LpFileTree.vue"
|
|
83
92
|
export type { CheckState, FileNode, NodeStats } from "./components/fileTree"
|
|
84
93
|
export {
|
|
85
94
|
ancestorIds,
|
|
@@ -100,11 +109,13 @@ export { default as LpInfraNode } from "./components/LpInfraNode.vue"
|
|
|
100
109
|
export type { InfraNodeData } from "./components/LpInfraNode.vue"
|
|
101
110
|
export { default as LpInput } from "./components/LpInput.vue"
|
|
102
111
|
export { default as LpLightbox } from "./components/LpLightbox.vue"
|
|
112
|
+
export type { LightboxLabels } from "./components/LpLightbox.vue"
|
|
103
113
|
export type { LightboxItem } from "./components/lightbox"
|
|
104
114
|
export { fileNameOf } from "./components/lightbox"
|
|
105
115
|
export { default as LpLink } from "./components/LpLink.vue"
|
|
106
116
|
export { default as LpLogViewer } from "./components/LpLogViewer.vue"
|
|
107
117
|
export type { LogLevel, LogLine } from "./components/LpLogViewer.vue"
|
|
118
|
+
export type { LogViewerLabels } from "./components/LpLogViewer.vue"
|
|
108
119
|
export { default as LpMediaGallery } from "./components/LpMediaGallery.vue"
|
|
109
120
|
export { default as LpModal } from "./components/LpModal.vue"
|
|
110
121
|
export { default as LpModalNav } from "./components/LpModalNav.vue"
|
|
@@ -121,11 +132,12 @@ export { default as LpPagination } from "./components/LpPagination.vue"
|
|
|
121
132
|
export { default as LpPasswordInput } from "./components/LpPasswordInput.vue"
|
|
122
133
|
export { default as LpPie } from "./components/LpPie.vue"
|
|
123
134
|
export type { SliceEvent } from "./components/LpPie.vue"
|
|
135
|
+
export type { PieText } from "./components/LpPie.vue"
|
|
124
136
|
export { resolveSlices } from "./components/chart"
|
|
125
137
|
export type { PieSlice, ResolvedSlice } from "./components/chart"
|
|
126
138
|
export { default as LpPhoneInput } from "./components/LpPhoneInput.vue"
|
|
127
139
|
export type { PhoneDetail } from "./components/LpPhoneInput.vue"
|
|
128
|
-
export { flagEmoji, loadCountries, matchCountryByValue } from "./components/countries"
|
|
140
|
+
export { filterCountries, flagEmoji, loadCountries, matchCountryByValue } from "./components/countries"
|
|
129
141
|
export type { Country } from "./components/countries"
|
|
130
142
|
export { default as LpPopover } from "./components/LpPopover.vue"
|
|
131
143
|
export { default as LpProgress } from "./components/LpProgress.vue"
|
|
@@ -154,6 +166,8 @@ export type { Step } from "./components/LpStepper.vue"
|
|
|
154
166
|
export { default as LpSwitch } from "./components/LpSwitch.vue"
|
|
155
167
|
export { default as LpTable } from "./components/LpTable.vue"
|
|
156
168
|
export type { SortState, TableColumn, TablePage, TableQuery } from "./components/LpTable.vue"
|
|
169
|
+
export type { TableLabels } from "./components/LpTable.vue"
|
|
170
|
+
export { compareValues } from "./components/tableSort"
|
|
157
171
|
export { default as LpTableOfContents } from "./components/LpTableOfContents.vue"
|
|
158
172
|
export type { TocLink } from "./components/LpTableOfContents.vue"
|
|
159
173
|
export { default as LpTabs } from "./components/LpTabs.vue"
|
|
@@ -163,6 +177,7 @@ export { default as LpThemeSwitcher } from "./components/LpThemeSwitcher.vue"
|
|
|
163
177
|
export { default as LpTilt } from "./components/LpTilt.vue"
|
|
164
178
|
export { default as LpToaster } from "./components/LpToaster.vue"
|
|
165
179
|
export { default as LpTooltip } from "./components/LpTooltip.vue"
|
|
180
|
+
export { default as LpTooltipProvider } from "./components/LpTooltipProvider.vue"
|
|
166
181
|
export { default as LpTopologyCanvas } from "./components/LpTopologyCanvas.vue"
|
|
167
182
|
export type {
|
|
168
183
|
CanvasViewport,
|
|
@@ -237,9 +252,16 @@ export {
|
|
|
237
252
|
mergeShortcutGroups,
|
|
238
253
|
} from "./composables/useHotkeys"
|
|
239
254
|
export type { HotkeyBinding, HotkeyHelp, ShortcutEntry, ShortcutGroup } from "./composables/useHotkeys"
|
|
255
|
+
export { matchesHotkey, useAppleKeyboard } from "./composables/useHotkeys"
|
|
256
|
+
export { anyModalOpen, topModalElement, useModalLayer } from "./components/modalDepth"
|
|
257
|
+
export type { ModalLayer, ModalLayerOptions } from "./components/modalDepth"
|
|
240
258
|
export { provideGlass, useGlass } from "./composables/useGlass"
|
|
259
|
+
export { LP_CONFIG, lpConfig, mergeConfig, provideLpConfig, useLabels, useLinkComponent, useLpConfig } from "./composables/useLpConfig"
|
|
260
|
+
export type { LabelScope, LpConfig } from "./composables/useLpConfig"
|
|
241
261
|
export { useMergedClass, useMergedAttrs, mergeClass } from "./composables/useMergedClass"
|
|
242
|
-
export { useInputFilter } from "./composables/useInputFilter"
|
|
262
|
+
export { anchorPattern, stripDisallowed, useInputFilter } from "./composables/useInputFilter"
|
|
263
|
+
export { LP_FIELD, fieldMessageId, provideField, useField, useFieldControl } from "./composables/useField"
|
|
264
|
+
export type { FieldContext, FieldControlState } from "./composables/useField"
|
|
243
265
|
export type { UseInputFilterOptions } from "./composables/useInputFilter"
|
|
244
266
|
export { easeOut, easeTravel, easingToken, prefersReducedMotion } from "./composables/easing"
|
|
245
267
|
export { useReveal } from "./composables/useReveal"
|
|
@@ -265,3 +287,16 @@ export type {
|
|
|
265
287
|
ToastOptions,
|
|
266
288
|
ToastVariant,
|
|
267
289
|
} from "./composables/useToast"
|
|
290
|
+
export type { ToastPromiseMessages } from "./composables/useToast"
|
|
291
|
+
export {
|
|
292
|
+
cacheSystemThemes,
|
|
293
|
+
normalizeTheme,
|
|
294
|
+
prefersDarkScheme,
|
|
295
|
+
themeEntries,
|
|
296
|
+
} from "./theme/useTheme"
|
|
297
|
+
export type { SystemThemes, UseTheme } from "./theme/useTheme"
|
|
298
|
+
export { layoutController } from "./layout/useLayout"
|
|
299
|
+
export type { LayoutController } from "./layout/useLayout"
|
|
300
|
+
export { default as LpThemeProvider } from "./components/LpThemeProvider.vue"
|
|
301
|
+
export { isInternalHref, resolveLink } from "./components/link"
|
|
302
|
+
export type { LinkTarget, ResolvedLink } from "./components/link"
|
package/src/layout/tree.ts
CHANGED
|
@@ -37,6 +37,13 @@ export type LayoutNode = Leaf | Split
|
|
|
37
37
|
let uid = 0
|
|
38
38
|
const nid = () => `lp-n${uid++}`
|
|
39
39
|
|
|
40
|
+
// Keep fresh ids clear of ids restored from a snapshot.
|
|
41
|
+
function claimId(id: string): string {
|
|
42
|
+
const n = /^lp-n(\d+)$/.exec(id)
|
|
43
|
+
if (n) uid = Math.max(uid, Number(n[1]) + 1)
|
|
44
|
+
return id
|
|
45
|
+
}
|
|
46
|
+
|
|
40
47
|
function leaf(block: string): Leaf {
|
|
41
48
|
return { kind: "leaf", id: nid(), blocks: [block], active: 0, size: 1 }
|
|
42
49
|
}
|
|
@@ -286,3 +293,26 @@ export function deserializeLayout(data: SerializedNode): Split {
|
|
|
286
293
|
}
|
|
287
294
|
return reactive(hydrate(data) as Split)
|
|
288
295
|
}
|
|
296
|
+
|
|
297
|
+
// ── history snapshots ────────────────────────────────────────
|
|
298
|
+
// Like serializeLayout, but keeping node ids: restoring an undo step with
|
|
299
|
+
// fresh ids remounted every block and threw away its local state.
|
|
300
|
+
type SnapshotNode =
|
|
301
|
+
| { kind: "leaf"; id: string; blocks: string[]; active: number; size: number }
|
|
302
|
+
| { kind: "split"; id: string; dir: Dir; size: number; children: SnapshotNode[] }
|
|
303
|
+
|
|
304
|
+
export function snapshotLayout(root: Split): string {
|
|
305
|
+
const strip = (n: LayoutNode): SnapshotNode =>
|
|
306
|
+
n.kind === "leaf"
|
|
307
|
+
? { kind: "leaf", id: n.id, blocks: [...n.blocks], active: n.active, size: n.size }
|
|
308
|
+
: { kind: "split", id: n.id, dir: n.dir, size: n.size, children: n.children.map(strip) }
|
|
309
|
+
return JSON.stringify(strip(root))
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
export function restoreLayout(snapshot: string): Split {
|
|
313
|
+
const hydrate = (n: SnapshotNode): LayoutNode =>
|
|
314
|
+
n.kind === "leaf"
|
|
315
|
+
? { kind: "leaf", id: claimId(n.id), blocks: [...n.blocks], active: n.active, size: n.size }
|
|
316
|
+
: { kind: "split", id: claimId(n.id), dir: n.dir, size: n.size, children: n.children.map(hydrate) }
|
|
317
|
+
return reactive(hydrate(JSON.parse(snapshot) as SnapshotNode) as Split)
|
|
318
|
+
}
|
package/src/layout/useLayout.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { computed, ref, shallowRef, type Ref } from "vue"
|
|
1
|
+
import { computed, ref, shallowRef, watch, type Ref } from "vue"
|
|
2
2
|
import {
|
|
3
3
|
addLeaf,
|
|
4
4
|
addTab,
|
|
@@ -10,8 +10,10 @@ import {
|
|
|
10
10
|
removeLeaf,
|
|
11
11
|
reorderTab,
|
|
12
12
|
resizeAt,
|
|
13
|
+
restoreLayout,
|
|
13
14
|
setActiveTab,
|
|
14
15
|
serializeLayout,
|
|
16
|
+
snapshotLayout,
|
|
15
17
|
type Side,
|
|
16
18
|
type Split,
|
|
17
19
|
} from "./tree"
|
|
@@ -22,13 +24,34 @@ import {
|
|
|
22
24
|
* tree.ts is a pile of pure-ish mutators; this composable is the ergonomic
|
|
23
25
|
* surface a consumer actually wires to UI: it owns the reactive tree, snapshots
|
|
24
26
|
* every structural edit for undo/redo, and exposes save/load/reset against a
|
|
25
|
-
* serialized form.
|
|
26
|
-
*
|
|
27
|
+
* serialized form. A <LayoutCanvas v-model> bound to this tree finds the
|
|
28
|
+
* controller through `layoutController`, so drag-move, tab close/reorder and
|
|
29
|
+
* divider resizes land in history with no extra wiring.
|
|
27
30
|
*
|
|
28
|
-
* History holds
|
|
29
|
-
* can't smuggle stale reactive nodes back in
|
|
31
|
+
* History holds snapshots (plain JSON with node ids), not live trees, so an
|
|
32
|
+
* undo can't smuggle stale reactive nodes back in, yet blocks keep their
|
|
33
|
+
* identity and are not remounted.
|
|
30
34
|
*/
|
|
31
35
|
|
|
36
|
+
/** The edits a canvas performs, routed through history when a controller owns the tree. */
|
|
37
|
+
export interface LayoutController {
|
|
38
|
+
move: (movingId: string, targetId: string, side: Side) => void
|
|
39
|
+
removeBlock: (leafId: string, index: number) => void
|
|
40
|
+
reorderTab: (leafId: string, from: number, to: number) => void
|
|
41
|
+
setActive: (leafId: string, index: number) => void
|
|
42
|
+
resize: (parent: Split, index: number, deltaFraction: number) => void
|
|
43
|
+
/** Bracket a continuous resize gesture so it records one history step. */
|
|
44
|
+
beginResize: () => void
|
|
45
|
+
endResize: () => void
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const controllers = new WeakMap<Split, LayoutController>()
|
|
49
|
+
|
|
50
|
+
/** The controller managing `tree`, if a useLayout() owns it. */
|
|
51
|
+
export function layoutController(tree: Split): LayoutController | undefined {
|
|
52
|
+
return controllers.get(tree)
|
|
53
|
+
}
|
|
54
|
+
|
|
32
55
|
export interface UseLayoutOptions {
|
|
33
56
|
/** Initial block ids, left-to-right, when no saved layout is loaded. */
|
|
34
57
|
initial: string[]
|
|
@@ -57,6 +80,8 @@ export interface UseLayout {
|
|
|
57
80
|
remove: (leafId: string) => void
|
|
58
81
|
move: (movingId: string, targetId: string, side: Side) => void
|
|
59
82
|
resize: (parent: Split, index: number, deltaFraction: number) => void
|
|
83
|
+
beginResize: () => void
|
|
84
|
+
endResize: () => void
|
|
60
85
|
undo: () => void
|
|
61
86
|
redo: () => void
|
|
62
87
|
/** Replace the whole layout from a flat block list. */
|
|
@@ -77,19 +102,43 @@ export function useLayout(options: UseLayoutOptions): UseLayout {
|
|
|
77
102
|
const canUndo = computed(() => past.value.length > 0)
|
|
78
103
|
const canRedo = computed(() => future.value.length > 0)
|
|
79
104
|
|
|
80
|
-
const snapshot = () =>
|
|
105
|
+
const snapshot = () => snapshotLayout(layout.value)
|
|
106
|
+
|
|
107
|
+
function push(before: string) {
|
|
108
|
+
if (before === snapshot()) return
|
|
109
|
+
past.value.push(before)
|
|
110
|
+
if (past.value.length > limit) past.value.shift()
|
|
111
|
+
future.value = []
|
|
112
|
+
}
|
|
81
113
|
|
|
82
114
|
// Capture the pre-edit state, run the structural change, drop any redo branch.
|
|
83
115
|
function record(mutate: () => void) {
|
|
84
116
|
const before = snapshot()
|
|
85
117
|
mutate()
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
118
|
+
push(before)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
let resizeStart: string | null = null
|
|
122
|
+
|
|
123
|
+
const controller: LayoutController = {
|
|
124
|
+
move: (movingId, targetId, side) => record(() => moveLeaf(layout.value, movingId, targetId, side)),
|
|
125
|
+
removeBlock: (leafId, index) => record(() => removeBlock(layout.value, leafId, index)),
|
|
126
|
+
reorderTab: (leafId, from, to) => record(() => reorderTab(layout.value, leafId, from, to)),
|
|
127
|
+
setActive: (leafId, index) => setActiveTab(layout.value, leafId, index),
|
|
128
|
+
resize: (parent, index, delta) => resizeAt(parent, index, delta),
|
|
129
|
+
beginResize: () => {
|
|
130
|
+
resizeStart = snapshot()
|
|
131
|
+
},
|
|
132
|
+
endResize: () => {
|
|
133
|
+
if (resizeStart !== null) push(resizeStart)
|
|
134
|
+
resizeStart = null
|
|
135
|
+
},
|
|
89
136
|
}
|
|
90
137
|
|
|
138
|
+
watch(layout, (tree) => controllers.set(tree, controller), { immediate: true, flush: "sync" })
|
|
139
|
+
|
|
91
140
|
function restore(serialized: string) {
|
|
92
|
-
layout.value =
|
|
141
|
+
layout.value = restoreLayout(serialized)
|
|
93
142
|
}
|
|
94
143
|
|
|
95
144
|
return {
|
|
@@ -99,16 +148,17 @@ export function useLayout(options: UseLayoutOptions): UseLayout {
|
|
|
99
148
|
canRedo,
|
|
100
149
|
add: (block, side) => record(() => addLeaf(layout.value, block, side)),
|
|
101
150
|
addTab: (leafId, block) => record(() => addTab(layout.value, leafId, block)),
|
|
102
|
-
setActive:
|
|
103
|
-
reorderTab:
|
|
104
|
-
removeBlock:
|
|
151
|
+
setActive: controller.setActive,
|
|
152
|
+
reorderTab: controller.reorderTab,
|
|
153
|
+
removeBlock: controller.removeBlock,
|
|
105
154
|
remove: (leafId) => record(() => removeLeaf(layout.value, leafId)),
|
|
106
|
-
move:
|
|
107
|
-
record(() => moveLeaf(layout.value, movingId, targetId, side)),
|
|
155
|
+
move: controller.move,
|
|
108
156
|
// Resize fires continuously during a divider drag; recording every frame
|
|
109
|
-
// would flood history
|
|
110
|
-
//
|
|
111
|
-
resize:
|
|
157
|
+
// would flood history. The canvas brackets its gestures with
|
|
158
|
+
// beginResize/endResize, which records the whole drag as one step.
|
|
159
|
+
resize: controller.resize,
|
|
160
|
+
beginResize: controller.beginResize,
|
|
161
|
+
endResize: controller.endResize,
|
|
112
162
|
undo: () => {
|
|
113
163
|
const prev = past.value.pop()
|
|
114
164
|
if (prev === undefined) return
|
package/src/nuxt.ts
CHANGED
|
@@ -11,28 +11,52 @@
|
|
|
11
11
|
*
|
|
12
12
|
* Options (nuxt.config `leavepulseUi`):
|
|
13
13
|
* theme false to skip the theme plugin entirely (default: true)
|
|
14
|
-
* defaultTheme
|
|
14
|
+
* defaultTheme theme name used when the visitor has no saved theme
|
|
15
|
+
* themes path of a module whose default export is the app's own
|
|
16
|
+
* TokenSet[] (e.g. "~/themes"), so SSR can paint and fall back
|
|
17
|
+
* to custom themes, not only the built-in presets
|
|
18
|
+
* link false to skip providing NuxtLink as the kit's link component
|
|
19
|
+
* exclude component names not to auto-register (e.g. ["LayoutCanvas"]
|
|
20
|
+
* when the app has its own component of that name)
|
|
15
21
|
*/
|
|
16
|
-
import { addComponent, addPlugin, createResolver, defineNuxtModule } from "@nuxt/kit"
|
|
22
|
+
import { addComponent, addPlugin, addTemplate, createResolver, defineNuxtModule } from "@nuxt/kit"
|
|
17
23
|
import { COMPONENT_NAMES } from "./component-names"
|
|
18
24
|
|
|
19
25
|
export interface LeavepulseUiOptions {
|
|
20
26
|
/** Register the SSR theme plugin. Disable to wire theming yourself. */
|
|
21
27
|
theme?: boolean
|
|
22
|
-
/**
|
|
28
|
+
/** Theme name to fall back to when nothing is saved (default "Dark"). */
|
|
23
29
|
defaultTheme?: string
|
|
30
|
+
/** Module path whose default export is the app's TokenSet[]. */
|
|
31
|
+
themes?: string
|
|
32
|
+
/** Provide NuxtLink as the link component for kit navigation (default true). */
|
|
33
|
+
link?: boolean
|
|
34
|
+
/** Component names to leave unregistered. */
|
|
35
|
+
exclude?: string[]
|
|
24
36
|
}
|
|
25
37
|
|
|
26
38
|
export default defineNuxtModule<LeavepulseUiOptions>({
|
|
27
39
|
meta: { name: "@leavepulse/ui", configKey: "leavepulseUi" },
|
|
28
|
-
defaults: { theme: true },
|
|
29
|
-
setup(
|
|
40
|
+
defaults: { theme: true, link: true },
|
|
41
|
+
setup(
|
|
42
|
+
options: LeavepulseUiOptions,
|
|
43
|
+
nuxt: {
|
|
44
|
+
options: {
|
|
45
|
+
runtimeConfig: { public: Record<string, unknown> }
|
|
46
|
+
alias: Record<string, string>
|
|
47
|
+
}
|
|
48
|
+
hook: (
|
|
49
|
+
name: "prepare:types",
|
|
50
|
+
fn: (options: { references: { path: string }[] }) => void,
|
|
51
|
+
) => void
|
|
52
|
+
},
|
|
53
|
+
) {
|
|
54
|
+
const resolver = createResolver(import.meta.url)
|
|
55
|
+
const skip = new Set(options.exclude ?? [])
|
|
30
56
|
for (const name of COMPONENT_NAMES) {
|
|
31
|
-
|
|
32
|
-
//
|
|
33
|
-
//
|
|
34
|
-
// app actually uses (plus their real deps — e.g. @vue-flow only when a
|
|
35
|
-
// canvas component is used).
|
|
57
|
+
if (skip.has(name)) continue
|
|
58
|
+
// Each component's own dist chunk rather than the barrel, so the app
|
|
59
|
+
// ships only the components it uses (and their real deps).
|
|
36
60
|
addComponent({
|
|
37
61
|
name,
|
|
38
62
|
export: "default",
|
|
@@ -40,18 +64,36 @@ export default defineNuxtModule<LeavepulseUiOptions>({
|
|
|
40
64
|
})
|
|
41
65
|
}
|
|
42
66
|
|
|
67
|
+
if (options.link !== false) {
|
|
68
|
+
addPlugin({ src: resolver.resolve("./runtime/config.plugin"), mode: "all" })
|
|
69
|
+
}
|
|
70
|
+
|
|
43
71
|
if (options.theme === false) return
|
|
44
72
|
|
|
45
|
-
|
|
46
|
-
|
|
73
|
+
const themes = addTemplate({
|
|
74
|
+
filename: "leavepulse-ui-themes.mjs",
|
|
75
|
+
getContents: () =>
|
|
76
|
+
options.themes
|
|
77
|
+
? `export { default } from ${JSON.stringify(options.themes)}\n`
|
|
78
|
+
: "export default []\n",
|
|
79
|
+
})
|
|
80
|
+
nuxt.options.alias["#lp-ui-themes"] = themes.dst
|
|
81
|
+
const themeTypes = addTemplate({
|
|
82
|
+
filename: "types/leavepulse-ui-themes.d.ts",
|
|
83
|
+
getContents: () =>
|
|
84
|
+
'declare module "#lp-ui-themes" {\n const themes: import("@leavepulse/ui").TokenSet[]\n export default themes\n}\n',
|
|
85
|
+
})
|
|
86
|
+
nuxt.hook("prepare:types", ({ references }) => {
|
|
87
|
+
references.push({ path: themeTypes.dst })
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
// Read from runtimeConfig rather than closed over, so the options survive
|
|
91
|
+
// the build into the server bundle.
|
|
47
92
|
nuxt.options.runtimeConfig.public.leavepulseUi = {
|
|
48
|
-
...(nuxt.options.runtimeConfig.public.leavepulseUi ?? {}),
|
|
93
|
+
...((nuxt.options.runtimeConfig.public.leavepulseUi as Record<string, unknown> | undefined) ?? {}),
|
|
49
94
|
defaultTheme: options.defaultTheme,
|
|
50
95
|
}
|
|
51
96
|
|
|
52
|
-
addPlugin({
|
|
53
|
-
src: createResolver(import.meta.url).resolve("./runtime/theme.plugin"),
|
|
54
|
-
mode: "all",
|
|
55
|
-
})
|
|
97
|
+
addPlugin({ src: resolver.resolve("./runtime/theme.plugin"), mode: "all" })
|
|
56
98
|
},
|
|
57
99
|
})
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Nuxt runtime plugin: provides the kit configuration app-wide, with NuxtLink
|
|
3
|
+
* as the link component, so navigation pieces (LpLink, LpButton with `to`,
|
|
4
|
+
* LpBreadcrumbs, LpSidebar items) navigate client-side without an `as` on
|
|
5
|
+
* every call site. Registered by the kit's Nuxt module.
|
|
6
|
+
*/
|
|
7
|
+
import { LP_CONFIG, type LpConfig } from "@leavepulse/ui"
|
|
8
|
+
import { NuxtLink } from "#components"
|
|
9
|
+
import { defineNuxtPlugin } from "#imports"
|
|
10
|
+
|
|
11
|
+
export default defineNuxtPlugin((nuxtApp) => {
|
|
12
|
+
const config: LpConfig = { linkComponent: NuxtLink }
|
|
13
|
+
nuxtApp.vueApp.provide(LP_CONFIG, config)
|
|
14
|
+
})
|
|
@@ -1,54 +1,74 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Nuxt runtime plugin
|
|
2
|
+
* Nuxt runtime plugin: paints the user's theme during SSR, so a reload shows
|
|
3
3
|
* the right colours in the first frame instead of flashing the default.
|
|
4
4
|
*
|
|
5
|
-
* Registered automatically by the kit's Nuxt module
|
|
6
|
-
* plugin of its own. Opt out (or point it at custom themes) via nuxt.config:
|
|
5
|
+
* Registered automatically by the kit's Nuxt module. Options (nuxt.config):
|
|
7
6
|
*
|
|
8
7
|
* leavepulseUi: { theme: false } // no theme handling at all
|
|
9
|
-
* leavepulseUi: { defaultTheme: "Nord" } // different fallback
|
|
8
|
+
* leavepulseUi: { defaultTheme: "Nord" } // different fallback theme
|
|
9
|
+
* leavepulseUi: { themes: "~/themes" } // module exporting the app's own themes
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* holds the full token values, including themes the server cannot name — keeps
|
|
17
|
-
* winning.
|
|
11
|
+
* The kit mirrors the chosen theme's NAME into the `lp-theme` cookie, which
|
|
12
|
+
* unlike localStorage travels with the request. The server resolves it against
|
|
13
|
+
* the built-in presets plus the app's themes and inlines that theme's variables
|
|
14
|
+
* into <head>. On the client useTheme().init() still restores localStorage,
|
|
15
|
+
* which holds the full token values and keeps winning.
|
|
18
16
|
*/
|
|
19
17
|
// Through the barrel, not "../theme/…": this file is compiled by the consuming
|
|
20
18
|
// app, where the barrel resolves to the same dist instance the components use.
|
|
21
|
-
// A relative path would load a second copy of the theme singleton.
|
|
22
19
|
import {
|
|
23
|
-
bootstrapTheme,
|
|
24
20
|
leavepulse,
|
|
25
21
|
presets,
|
|
26
22
|
THEME_COOKIE,
|
|
27
23
|
themeFromCookie,
|
|
28
24
|
themeToCssRule,
|
|
25
|
+
useTheme,
|
|
29
26
|
type TokenSet,
|
|
30
27
|
} from "@leavepulse/ui"
|
|
31
|
-
import
|
|
28
|
+
import appThemes from "#lp-ui-themes"
|
|
29
|
+
import {
|
|
30
|
+
defineNuxtPlugin,
|
|
31
|
+
useCookie,
|
|
32
|
+
useHead,
|
|
33
|
+
useRequestEvent,
|
|
34
|
+
useRequestHeaders,
|
|
35
|
+
useRuntimeConfig,
|
|
36
|
+
} from "#imports"
|
|
37
|
+
|
|
38
|
+
const HINT = "sec-ch-prefers-color-scheme"
|
|
32
39
|
|
|
33
40
|
export default defineNuxtPlugin(() => {
|
|
34
41
|
const options = (useRuntimeConfig().public.leavepulseUi ?? {}) as {
|
|
35
42
|
defaultTheme?: string
|
|
36
43
|
}
|
|
37
44
|
|
|
38
|
-
const themes = Object.values(presets) as TokenSet[]
|
|
39
|
-
const fallback =
|
|
40
|
-
themes.find((theme) => theme.name === options.defaultTheme) ?? leavepulse
|
|
45
|
+
const themes = [...(appThemes as TokenSet[]), ...(Object.values(presets) as TokenSet[])]
|
|
46
|
+
const fallback = themes.find((theme) => theme.name === options.defaultTheme) ?? leavepulse
|
|
41
47
|
|
|
42
|
-
|
|
43
|
-
|
|
48
|
+
// Raw value: themeFromCookie decodes safely itself, a throwing decode here
|
|
49
|
+
// would turn a malformed cookie into a 500 on every request.
|
|
50
|
+
const cookie = useCookie<string | null>(THEME_COOKIE, {
|
|
51
|
+
readonly: true,
|
|
52
|
+
decode: (value: string) => value,
|
|
53
|
+
})
|
|
54
|
+
let prefersDark: boolean | undefined
|
|
55
|
+
if (import.meta.server) {
|
|
56
|
+
const hint = useRequestHeaders([HINT])[HINT]
|
|
57
|
+
if (hint) prefersDark = hint.includes("dark")
|
|
58
|
+
// Ask the browser for the OS colour scheme from the next request on, so a
|
|
59
|
+
// visitor following the OS gets the right theme server-side as well.
|
|
60
|
+
useRequestEvent()?.node.res.setHeader("Accept-CH", "Sec-CH-Prefers-Color-Scheme")
|
|
61
|
+
}
|
|
62
|
+
const initial = themeFromCookie(cookie.value, themes, { prefersDark }) ?? fallback
|
|
44
63
|
|
|
45
64
|
useHead({
|
|
65
|
+
htmlAttrs: { "data-theme-mode": initial.mode },
|
|
46
66
|
style: [{ id: "lp-ui-theme", innerHTML: themeToCssRule(initial) }],
|
|
47
67
|
})
|
|
48
68
|
|
|
49
|
-
// `initial` as the fallback
|
|
50
|
-
//
|
|
69
|
+
// `initial` as the fallback, so a visitor who only has the cookie keeps the
|
|
70
|
+
// theme the server just painted and the shared state starts from it.
|
|
51
71
|
if (import.meta.client) {
|
|
52
|
-
|
|
72
|
+
useTheme().init(initial)
|
|
53
73
|
}
|
|
54
74
|
})
|