@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
package/src/theme/useTheme.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import { computed, readonly, shallowRef, type ComputedRef, type DeepReadonly, type Ref } from "vue"
|
|
8
8
|
import { easingToken, prefersReducedMotion } from "../composables/easing"
|
|
9
9
|
import { detectBackdropFilter } from "./backdrop"
|
|
10
|
+
import { dark as darkPreset, light as lightPreset } from "./presets"
|
|
10
11
|
import {
|
|
11
12
|
COLOR_VARS,
|
|
12
13
|
DEFAULT_SURFACE,
|
|
@@ -24,57 +25,134 @@ import {
|
|
|
24
25
|
|
|
25
26
|
const CACHE_KEY = "leavepulse-ui-theme"
|
|
26
27
|
|
|
28
|
+
/** A light/dark pair followed by the operating system's colour scheme. */
|
|
29
|
+
export interface SystemThemes {
|
|
30
|
+
light: TokenSet
|
|
31
|
+
dark: TokenSet
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
type Cached = { theme: TokenSet; system?: undefined } | { system: SystemThemes; theme?: undefined }
|
|
35
|
+
|
|
27
36
|
// ── self-managed theme state (singleton) ─────────────────────────────────
|
|
28
|
-
// The kit owns the active theme
|
|
29
|
-
//
|
|
30
|
-
//
|
|
31
|
-
// cache on the client. SSR-safe: hydration only touches localStorage in a
|
|
32
|
-
// browser; on the server `current` stays null until the client mounts.
|
|
37
|
+
// The kit owns the active theme, like an i18n locale, so every consumer shares
|
|
38
|
+
// one source of truth. Lazily hydrated from the cache on the client; on the
|
|
39
|
+
// server `current` stays null.
|
|
33
40
|
const _current = shallowRef<TokenSet | null>(null)
|
|
41
|
+
const _system = shallowRef<SystemThemes | null>(null)
|
|
34
42
|
let _hydrated = false
|
|
35
|
-
|
|
36
|
-
// The fallback used when nothing is cached yet. Consumers can override it via
|
|
37
|
-
// initTheme(fallback); defaults to whatever the first apply() sets.
|
|
38
43
|
let _fallback: TokenSet | null = null
|
|
39
44
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
45
|
+
const DARK_QUERY = "(prefers-color-scheme: dark)"
|
|
46
|
+
let _media: MediaQueryList | null = null
|
|
47
|
+
|
|
48
|
+
/** Whether the OS asks for dark. True where it cannot be asked (server, old engines). */
|
|
49
|
+
export function prefersDarkScheme(): boolean {
|
|
50
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return true
|
|
51
|
+
return window.matchMedia(DARK_QUERY).matches || !window.matchMedia("(prefers-color-scheme: light)").matches
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function pick(system: SystemThemes, dark = prefersDarkScheme()): TokenSet {
|
|
55
|
+
return dark ? system.dark : system.light
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function onSchemeChange(event: MediaQueryListEvent): void {
|
|
59
|
+
const system = _system.value
|
|
60
|
+
if (!system) return
|
|
61
|
+
const theme = pick(system, event.matches)
|
|
62
|
+
applyTheme(theme)
|
|
63
|
+
_current.value = theme
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function followSystem(system: SystemThemes | null): void {
|
|
67
|
+
_system.value = system
|
|
68
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return
|
|
69
|
+
if (system && !_media) {
|
|
70
|
+
_media = window.matchMedia(DARK_QUERY)
|
|
71
|
+
_media.addEventListener("change", onSchemeChange)
|
|
72
|
+
} else if (!system && _media) {
|
|
73
|
+
_media.removeEventListener("change", onSchemeChange)
|
|
74
|
+
_media = null
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function readCache(): Cached | null {
|
|
43
79
|
try {
|
|
44
80
|
const cached = localStorage.getItem(CACHE_KEY)
|
|
45
|
-
if (cached)
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
return
|
|
81
|
+
if (!cached) return null
|
|
82
|
+
const raw = JSON.parse(cached) as { system?: { light?: unknown; dark?: unknown } }
|
|
83
|
+
if (raw && typeof raw === "object" && raw.system) {
|
|
84
|
+
return {
|
|
85
|
+
system: {
|
|
86
|
+
light: parseTheme(JSON.stringify(raw.system.light)),
|
|
87
|
+
dark: parseTheme(JSON.stringify(raw.system.dark)),
|
|
88
|
+
},
|
|
89
|
+
}
|
|
49
90
|
}
|
|
91
|
+
return { theme: parseTheme(cached) }
|
|
50
92
|
} catch {
|
|
51
|
-
|
|
93
|
+
return null
|
|
52
94
|
}
|
|
53
|
-
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function hydrateOnce(): void {
|
|
98
|
+
if (_hydrated || typeof window === "undefined") return
|
|
99
|
+
_hydrated = true
|
|
100
|
+
const cached = readCache()
|
|
101
|
+
if (cached?.system) {
|
|
102
|
+
followSystem(cached.system)
|
|
103
|
+
_current.value = pick(cached.system)
|
|
104
|
+
writeThemeCookie(systemCookieValue(cached.system))
|
|
105
|
+
} else if (cached?.theme) {
|
|
106
|
+
_current.value = cached.theme
|
|
107
|
+
writeThemeCookie(cached.theme.name)
|
|
108
|
+
} else if (_fallback) {
|
|
54
109
|
_current.value = _fallback
|
|
55
|
-
|
|
110
|
+
} else {
|
|
111
|
+
return
|
|
56
112
|
}
|
|
113
|
+
applyTheme(_current.value)
|
|
57
114
|
}
|
|
58
115
|
|
|
59
|
-
|
|
116
|
+
/*
|
|
117
|
+
* Tokens defined in terms of other tokens. A custom property holding `var()` is
|
|
118
|
+
* resolved where it is declared, so the stylesheet's `:root` copies only ever
|
|
119
|
+
* see the root theme. Re-declaring them next to a theme makes a theme applied
|
|
120
|
+
* to a subtree (applyTheme(theme, el), themeToCssRule(theme, ".x")) carry them.
|
|
121
|
+
*/
|
|
122
|
+
const DERIVED_VARS: readonly (readonly [string, string])[] = [
|
|
123
|
+
["--color-surface-overlay", "color-mix(in srgb, var(--color-surface-raised) 94%, transparent)"],
|
|
124
|
+
["--color-node-compute", "var(--color-action)"],
|
|
125
|
+
["--color-node-transit", "var(--color-accent)"],
|
|
126
|
+
["--color-node-edge", "var(--color-brand)"],
|
|
127
|
+
["--color-node-unknown", "var(--color-line-strong)"],
|
|
128
|
+
]
|
|
129
|
+
|
|
130
|
+
/** Every CSS variable a theme sets, in application order. */
|
|
131
|
+
export function themeEntries(input: TokenSet): [string, string][] {
|
|
132
|
+
const theme = normalizeTheme(input)
|
|
133
|
+
const out: [string, string][] = []
|
|
60
134
|
for (const [key, cssVar] of Object.entries(COLOR_VARS)) {
|
|
61
|
-
|
|
135
|
+
out.push([cssVar, theme.colors[key as keyof ColorTokens]])
|
|
62
136
|
}
|
|
63
137
|
for (const [key, cssVar] of Object.entries(SHAPE_VARS)) {
|
|
64
|
-
|
|
138
|
+
out.push([cssVar, `${theme.shape[key as keyof ShapeTokens]}px`])
|
|
65
139
|
}
|
|
66
140
|
for (const [key, cssVar] of Object.entries(DENSITY_VARS)) {
|
|
67
|
-
|
|
141
|
+
out.push([cssVar, `${theme.density[key as keyof DensityTokens]}px`])
|
|
68
142
|
}
|
|
69
143
|
for (const [key, cssVar] of Object.entries(FONT_VARS)) {
|
|
70
|
-
|
|
144
|
+
out.push([cssVar, theme.font[key as keyof FontTokens]])
|
|
71
145
|
}
|
|
72
|
-
// Skin axis is optional; fall back to a flat default so themes saved before
|
|
73
|
-
// it existed still paint correctly.
|
|
74
146
|
const surface = theme.surface ?? DEFAULT_SURFACE
|
|
75
147
|
for (const [key, cssVar] of Object.entries(SURFACE_VARS)) {
|
|
76
|
-
|
|
148
|
+
out.push([cssVar, surface[key as keyof SurfaceTokens]])
|
|
77
149
|
}
|
|
150
|
+
for (const [cssVar, value] of DERIVED_VARS) out.push([cssVar, value])
|
|
151
|
+
return out
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export function applyTheme(theme: TokenSet, root: HTMLElement = document.documentElement): void {
|
|
155
|
+
for (const [cssVar, value] of themeEntries(theme)) root.style.setProperty(cssVar, value)
|
|
78
156
|
root.dataset.themeMode = theme.mode
|
|
79
157
|
root.style.colorScheme = theme.mode
|
|
80
158
|
// Engine capability, not theme data — but this is the one path every consumer
|
|
@@ -157,24 +235,9 @@ export function serializeTheme(theme: TokenSet): string {
|
|
|
157
235
|
* applyTheme — no duplicated values, the TokenSet stays the single source.
|
|
158
236
|
*/
|
|
159
237
|
export function themeToCssVars(theme: TokenSet): string {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
}
|
|
164
|
-
for (const [key, cssVar] of Object.entries(SHAPE_VARS)) {
|
|
165
|
-
decls.push(`${cssVar}: ${theme.shape[key as keyof ShapeTokens]}px`)
|
|
166
|
-
}
|
|
167
|
-
for (const [key, cssVar] of Object.entries(DENSITY_VARS)) {
|
|
168
|
-
decls.push(`${cssVar}: ${theme.density[key as keyof DensityTokens]}px`)
|
|
169
|
-
}
|
|
170
|
-
for (const [key, cssVar] of Object.entries(FONT_VARS)) {
|
|
171
|
-
decls.push(`${cssVar}: ${theme.font[key as keyof FontTokens]}`)
|
|
172
|
-
}
|
|
173
|
-
const surface = theme.surface ?? DEFAULT_SURFACE
|
|
174
|
-
for (const [key, cssVar] of Object.entries(SURFACE_VARS)) {
|
|
175
|
-
decls.push(`${cssVar}: ${surface[key as keyof SurfaceTokens]}`)
|
|
176
|
-
}
|
|
177
|
-
return decls.join("; ")
|
|
238
|
+
return themeEntries(theme)
|
|
239
|
+
.map(([cssVar, value]) => `${cssVar}: ${value}`)
|
|
240
|
+
.join("; ")
|
|
178
241
|
}
|
|
179
242
|
|
|
180
243
|
/** Render a theme as a complete CSS rule (default selector `:root`). */
|
|
@@ -182,33 +245,43 @@ export function themeToCssRule(theme: TokenSet, selector = ":root"): string {
|
|
|
182
245
|
return `${selector} { color-scheme: ${theme.mode}; ${themeToCssVars(theme)}; }`
|
|
183
246
|
}
|
|
184
247
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
248
|
+
/*
|
|
249
|
+
* Fill every axis a theme leaves out from the built-in preset of the same mode.
|
|
250
|
+
* Themes are stored by consumers and live longer than a kit version: a theme
|
|
251
|
+
* saved before a token existed would otherwise write `undefined` into that
|
|
252
|
+
* variable and blank out every utility that reads it.
|
|
253
|
+
*/
|
|
254
|
+
export function normalizeTheme(raw: Partial<TokenSet> & { name?: string }): TokenSet {
|
|
255
|
+
const mode = raw.mode === "light" ? "light" : "dark"
|
|
256
|
+
const base = mode === "light" ? lightPreset : darkPreset
|
|
257
|
+
return {
|
|
258
|
+
name: typeof raw.name === "string" ? raw.name : base.name,
|
|
259
|
+
mode,
|
|
260
|
+
colors: { ...base.colors, ...raw.colors },
|
|
261
|
+
shape: { ...base.shape, ...raw.shape },
|
|
262
|
+
density: { ...base.density, ...raw.density },
|
|
263
|
+
font: { ...base.font, ...raw.font },
|
|
264
|
+
surface: raw.surface ? { ...DEFAULT_SURFACE, ...raw.surface } : undefined,
|
|
265
|
+
}
|
|
188
266
|
}
|
|
189
267
|
|
|
190
|
-
/** Parse +
|
|
268
|
+
/** Parse + validate a theme JSON; throws on a malformed shape. */
|
|
191
269
|
export function parseTheme(json: string): TokenSet {
|
|
192
270
|
const raw = JSON.parse(json) as Partial<TokenSet>
|
|
193
271
|
if (!raw || typeof raw !== "object" || !raw.colors || !raw.shape || !raw.density) {
|
|
194
272
|
throw new Error("Invalid theme: missing colors/shape/density")
|
|
195
273
|
}
|
|
196
|
-
|
|
197
|
-
return { ...raw, font: raw.font ?? DEFAULT_FONT } as TokenSet
|
|
274
|
+
return normalizeTheme(raw)
|
|
198
275
|
}
|
|
199
276
|
|
|
200
277
|
// ── anti-flash bootstrap ─────────────────────────────────────
|
|
201
278
|
// Call once before mount with your default theme; paints the cached theme (if
|
|
202
279
|
// any) synchronously so the first frame already matches the saved look.
|
|
203
280
|
export function bootstrapTheme(fallback: TokenSet): TokenSet {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
} catch {
|
|
209
|
-
/* ignore, use fallback */
|
|
210
|
-
}
|
|
211
|
-
applyTheme(theme)
|
|
281
|
+
const cached = typeof window === "undefined" ? null : readCache()
|
|
282
|
+
const theme = cached?.system ? pick(cached.system) : (cached?.theme ?? fallback)
|
|
283
|
+
if (cached?.system) followSystem(cached.system)
|
|
284
|
+
if (typeof document !== "undefined") applyTheme(theme)
|
|
212
285
|
return theme
|
|
213
286
|
}
|
|
214
287
|
|
|
@@ -216,62 +289,97 @@ export function cacheTheme(theme: TokenSet): void {
|
|
|
216
289
|
try {
|
|
217
290
|
localStorage.setItem(CACHE_KEY, serializeTheme(theme))
|
|
218
291
|
} catch {
|
|
219
|
-
/* storage unavailable
|
|
292
|
+
/* storage unavailable, non-fatal */
|
|
220
293
|
}
|
|
221
294
|
writeThemeCookie(theme.name)
|
|
222
295
|
}
|
|
223
296
|
|
|
297
|
+
/** Persist "follow the OS" with the pair it switches between. */
|
|
298
|
+
export function cacheSystemThemes(system: SystemThemes): void {
|
|
299
|
+
try {
|
|
300
|
+
localStorage.setItem(CACHE_KEY, JSON.stringify({ system }))
|
|
301
|
+
} catch {
|
|
302
|
+
/* storage unavailable, non-fatal */
|
|
303
|
+
}
|
|
304
|
+
writeThemeCookie(systemCookieValue(system))
|
|
305
|
+
}
|
|
306
|
+
|
|
224
307
|
/*
|
|
225
|
-
* SSR handoff. localStorage is invisible to the server, so
|
|
226
|
-
*
|
|
227
|
-
*
|
|
228
|
-
* inline the user's real theme in the first frame (see themeFromCookie).
|
|
229
|
-
*
|
|
230
|
-
* Only the NAME is stored: a full TokenSet is ~1KB of JSON that would be sent on
|
|
231
|
-
* every request. The server resolves the name against the themes it knows, and
|
|
232
|
-
* localStorage stays the client's source of truth for the full token values.
|
|
308
|
+
* SSR handoff. localStorage is invisible to the server, so the theme NAME rides
|
|
309
|
+
* along in a cookie and the server resolves it against the themes it knows
|
|
310
|
+
* (see themeFromCookie). "Follow the OS" is stored as `system:<light>|<dark>`.
|
|
233
311
|
*/
|
|
234
312
|
export const THEME_COOKIE = "lp-theme"
|
|
313
|
+
const SYSTEM_PREFIX = "system:"
|
|
235
314
|
|
|
236
315
|
const COOKIE_MAX_AGE = 60 * 60 * 24 * 365
|
|
237
316
|
|
|
238
|
-
function
|
|
317
|
+
function systemCookieValue(system: SystemThemes): string {
|
|
318
|
+
return `${SYSTEM_PREFIX}${system.light.name}|${system.dark.name}`
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function writeThemeCookie(value: string): void {
|
|
239
322
|
if (typeof document === "undefined") return
|
|
240
|
-
// lax: the theme must survive a top-level navigation (which is what SSR
|
|
241
|
-
// renders) without riding cross-site subrequests.
|
|
242
323
|
document.cookie =
|
|
243
|
-
`${THEME_COOKIE}=${encodeURIComponent(
|
|
324
|
+
`${THEME_COOKIE}=${encodeURIComponent(value)}` +
|
|
244
325
|
`; path=/; max-age=${COOKIE_MAX_AGE}; samesite=lax`
|
|
245
326
|
}
|
|
246
327
|
|
|
328
|
+
function safeDecode(value: string): string {
|
|
329
|
+
try {
|
|
330
|
+
return decodeURIComponent(value)
|
|
331
|
+
} catch {
|
|
332
|
+
return value
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
247
336
|
/**
|
|
248
337
|
* Resolve a theme name (as read from the `lp-theme` cookie) against a set of
|
|
249
338
|
* known themes. Returns `null` when the name is absent or unknown, so the caller
|
|
250
339
|
* can fall back to its own default.
|
|
251
340
|
*
|
|
252
|
-
*
|
|
253
|
-
*
|
|
341
|
+
* Accepts both a raw and an already-decoded value: frameworks differ on whether
|
|
342
|
+
* their cookie helpers decode, and a name containing `%` must not throw.
|
|
343
|
+
* A "follow the OS" cookie resolves to its dark member unless `prefersDark` is
|
|
344
|
+
* false (pass it from the `Sec-CH-Prefers-Color-Scheme` request header).
|
|
254
345
|
*/
|
|
255
346
|
export function themeFromCookie(
|
|
256
347
|
cookieValue: string | null | undefined,
|
|
257
348
|
themes: readonly TokenSet[],
|
|
349
|
+
options: { prefersDark?: boolean } = {},
|
|
258
350
|
): TokenSet | null {
|
|
259
351
|
if (!cookieValue) return null
|
|
260
|
-
const
|
|
261
|
-
|
|
352
|
+
const find = (name: string) => themes.find((theme) => theme.name === name) ?? null
|
|
353
|
+
for (const value of [cookieValue, safeDecode(cookieValue)]) {
|
|
354
|
+
if (value.startsWith(SYSTEM_PREFIX)) {
|
|
355
|
+
const [lightName = "", darkName = ""] = value.slice(SYSTEM_PREFIX.length).split("|")
|
|
356
|
+
const wanted = options.prefersDark === false ? lightName : darkName
|
|
357
|
+
const found = find(wanted)
|
|
358
|
+
if (found) return found
|
|
359
|
+
continue
|
|
360
|
+
}
|
|
361
|
+
const found = find(value)
|
|
362
|
+
if (found) return found
|
|
363
|
+
}
|
|
364
|
+
return null
|
|
262
365
|
}
|
|
263
366
|
|
|
264
367
|
export interface UseTheme {
|
|
265
368
|
/** The active theme, kept in sync by the kit. Null until hydrated (SSR/first
|
|
266
|
-
* paint)
|
|
369
|
+
* paint), reactive, so a switcher binds straight to it. */
|
|
267
370
|
current: DeepReadonly<Ref<TokenSet | null>>
|
|
268
371
|
/** The active theme's name (""="not yet hydrated"). */
|
|
269
372
|
currentName: ComputedRef<string>
|
|
270
|
-
/**
|
|
271
|
-
|
|
373
|
+
/** True while the theme follows the OS colour scheme (see setSystem). */
|
|
374
|
+
system: ComputedRef<boolean>
|
|
375
|
+
/** Set + persist a theme (with the circular reveal). Stops following the OS. */
|
|
272
376
|
setTheme: (theme: TokenSet, origin?: RevealOrigin) => void
|
|
273
|
-
/**
|
|
274
|
-
*
|
|
377
|
+
/**
|
|
378
|
+
* Follow the OS colour scheme, switching between `themes.light` and
|
|
379
|
+
* `themes.dark` as it changes. Persisted like any other choice.
|
|
380
|
+
*/
|
|
381
|
+
setSystem: (themes: SystemThemes, origin?: RevealOrigin) => void
|
|
382
|
+
/** Seed the fallback (used when nothing is cached) and hydrate now. */
|
|
275
383
|
init: (fallback: TokenSet) => TokenSet
|
|
276
384
|
apply: (theme: TokenSet) => void
|
|
277
385
|
applyWithTransition: (theme: TokenSet, origin?: RevealOrigin) => void
|
|
@@ -281,14 +389,10 @@ export interface UseTheme {
|
|
|
281
389
|
}
|
|
282
390
|
|
|
283
391
|
export function useTheme(): UseTheme {
|
|
284
|
-
// Lazily hydrate the singleton the first time anyone asks (client only).
|
|
285
392
|
hydrateOnce()
|
|
286
393
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
const setTheme = (theme: TokenSet, origin?: RevealOrigin) => {
|
|
290
|
-
if (origin) applyThemeWithTransition(theme, origin)
|
|
291
|
-
else applyThemeWithTransition(theme)
|
|
394
|
+
const commit = (theme: TokenSet) => {
|
|
395
|
+
followSystem(null)
|
|
292
396
|
cacheTheme(theme)
|
|
293
397
|
_current.value = theme
|
|
294
398
|
}
|
|
@@ -296,29 +400,31 @@ export function useTheme(): UseTheme {
|
|
|
296
400
|
return {
|
|
297
401
|
current: readonly(_current),
|
|
298
402
|
currentName: computed(() => _current.value?.name ?? ""),
|
|
299
|
-
|
|
403
|
+
system: computed(() => _system.value !== null),
|
|
404
|
+
setTheme: (theme, origin) => {
|
|
405
|
+
applyThemeWithTransition(theme, origin)
|
|
406
|
+
commit(theme)
|
|
407
|
+
},
|
|
408
|
+
setSystem: (themes, origin) => {
|
|
409
|
+
const theme = pick(themes)
|
|
410
|
+
applyThemeWithTransition(theme, origin)
|
|
411
|
+
followSystem(themes)
|
|
412
|
+
cacheSystemThemes(themes)
|
|
413
|
+
_current.value = theme
|
|
414
|
+
},
|
|
300
415
|
init: (fallback: TokenSet) => {
|
|
301
416
|
_fallback = fallback
|
|
302
|
-
|
|
303
|
-
if (!_current.value)
|
|
304
|
-
_current.value = bootstrapTheme(fallback)
|
|
305
|
-
}
|
|
417
|
+
hydrateOnce()
|
|
418
|
+
if (!_current.value) _current.value = bootstrapTheme(fallback)
|
|
306
419
|
return _current.value
|
|
307
420
|
},
|
|
308
421
|
apply: (theme: TokenSet) => {
|
|
309
422
|
applyTheme(theme)
|
|
310
|
-
|
|
311
|
-
_current.value = theme
|
|
423
|
+
commit(theme)
|
|
312
424
|
},
|
|
313
|
-
/**
|
|
314
|
-
* Apply + cache a theme with the circular reveal animation. Pass the click
|
|
315
|
-
* point (e.g. from a toggle's `event`) as `origin` so the circle grows from
|
|
316
|
-
* the button; omit it to reveal from the viewport centre.
|
|
317
|
-
*/
|
|
318
425
|
applyWithTransition: (theme: TokenSet, origin?: RevealOrigin) => {
|
|
319
426
|
applyThemeWithTransition(theme, origin)
|
|
320
|
-
|
|
321
|
-
_current.value = theme
|
|
427
|
+
commit(theme)
|
|
322
428
|
},
|
|
323
429
|
serialize: serializeTheme,
|
|
324
430
|
parse: parseTheme,
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import { defineComponent, openBlock, createElementBlock, mergeProps, unref, Fragment, renderList, createBlock, createCommentVNode, resolveDynamicComponent, withCtx, createTextVNode, toDisplayString, normalizeClass } from "vue";
|
|
2
|
-
import { _ as _sfc_main$1 } from "./LpIcon-CCnX5_2j.js";
|
|
3
|
-
import { useMergedAttrs } from "../composables/useMergedClass.js";
|
|
4
|
-
const __default__ = { inheritAttrs: false };
|
|
5
|
-
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
6
|
-
...__default__,
|
|
7
|
-
__name: "LpBreadcrumbs",
|
|
8
|
-
props: {
|
|
9
|
-
items: {},
|
|
10
|
-
as: { default: "a" }
|
|
11
|
-
},
|
|
12
|
-
emits: ["navigate"],
|
|
13
|
-
setup(__props) {
|
|
14
|
-
const { class: rootClass, attrs: rest } = useMergedAttrs(
|
|
15
|
-
"flex items-center gap-1.5 text-sm"
|
|
16
|
-
);
|
|
17
|
-
return (_ctx, _cache) => {
|
|
18
|
-
return openBlock(), createElementBlock("nav", mergeProps({ class: unref(rootClass) }, unref(rest), { "aria-label": "Breadcrumb" }), [
|
|
19
|
-
(openBlock(true), createElementBlock(Fragment, null, renderList(__props.items, (item, i) => {
|
|
20
|
-
return openBlock(), createElementBlock(Fragment, { key: i }, [
|
|
21
|
-
i > 0 ? (openBlock(), createBlock(_sfc_main$1, {
|
|
22
|
-
key: 0,
|
|
23
|
-
name: "lucide:chevron-right",
|
|
24
|
-
size: 14,
|
|
25
|
-
class: "text-muted"
|
|
26
|
-
})) : createCommentVNode("", true),
|
|
27
|
-
(item.href || item.to) && i < __props.items.length - 1 ? (openBlock(), createBlock(resolveDynamicComponent(__props.as), {
|
|
28
|
-
key: 1,
|
|
29
|
-
href: __props.as === "a" ? item.href : void 0,
|
|
30
|
-
to: __props.as === "a" ? void 0 : item.to,
|
|
31
|
-
class: "inline-flex items-center gap-1.5 rounded-xs text-muted outline-none transition-colors duration-[var(--duration-fast)] hover:text-ink focus-visible:ring-2 focus-visible:ring-ring",
|
|
32
|
-
onClick: ($event) => _ctx.$emit("navigate", item, i)
|
|
33
|
-
}, {
|
|
34
|
-
default: withCtx(() => [
|
|
35
|
-
item.icon ? (openBlock(), createBlock(_sfc_main$1, {
|
|
36
|
-
key: 0,
|
|
37
|
-
name: item.icon,
|
|
38
|
-
size: 14
|
|
39
|
-
}, null, 8, ["name"])) : createCommentVNode("", true),
|
|
40
|
-
createTextVNode(" " + toDisplayString(item.label), 1)
|
|
41
|
-
]),
|
|
42
|
-
_: 2
|
|
43
|
-
}, 1032, ["href", "to", "onClick"])) : (openBlock(), createElementBlock("span", {
|
|
44
|
-
key: 2,
|
|
45
|
-
class: normalizeClass(["inline-flex items-center gap-1.5", i === __props.items.length - 1 ? "text-ink" : "text-muted"])
|
|
46
|
-
}, [
|
|
47
|
-
item.icon ? (openBlock(), createBlock(_sfc_main$1, {
|
|
48
|
-
key: 0,
|
|
49
|
-
name: item.icon,
|
|
50
|
-
size: 14
|
|
51
|
-
}, null, 8, ["name"])) : createCommentVNode("", true),
|
|
52
|
-
createTextVNode(" " + toDisplayString(item.label), 1)
|
|
53
|
-
], 2))
|
|
54
|
-
], 64);
|
|
55
|
-
}), 128))
|
|
56
|
-
], 16);
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
export {
|
|
61
|
-
_sfc_main as _
|
|
62
|
-
};
|