@leavepulse/ui 0.43.4 → 0.45.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 +121 -7
- package/dist/assets/{LpCommandPalette-B-0Est4Z.css → LpCommandPalette-nGNnzXqQ.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/{LpRollingText-CR1mb0Vt.css → LpRollingText-BGnE6q9j.css} +3 -0
- package/dist/assets/{LpShortcutsDialog-C6YoQ8_M.css → LpShortcutsDialog-CqYX3yy6.css} +28 -7
- package/dist/assets/{LpSkeleton-D7xU8IPV.css → LpSkeleton-H3Z5dEIk.css} +4 -1
- package/dist/assets/{LpTable-BgPLJOXa.css → LpTable-CPwWxTJS.css} +49 -9
- package/dist/chunks/ContextMenuItems-BtKU7074.js +124 -0
- package/dist/chunks/{LayoutCanvas-Dd20boUG.js → LayoutCanvas-BkaGXTjx.js} +26 -9
- package/dist/chunks/{LayoutNode-DGpZA9LX.js → LayoutNode-B3_9E1Xa.js} +28 -12
- package/dist/chunks/{LpActionBar-BlvtGB2P.js → LpActionBar-CnfFVIwC.js} +26 -12
- package/dist/chunks/{LpAddressInput-B-Zvxsn7.js → LpAddressInput-BwX8uo4_.js} +54 -49
- package/dist/chunks/{LpAlert-BAYHDSS1.js → LpAlert-B6ilrM7T.js} +16 -9
- package/dist/chunks/{LpAppShell-BGQVIY-3.js → LpAppShell-C53_RaGF.js} +53 -26
- package/dist/chunks/{LpAutocomplete-DExlIZe_.js → LpAutocomplete-C8IgSMsi.js} +52 -24
- package/dist/chunks/{LpAvatar-B3-xAOH3.js → LpAvatar-C1XStdOo.js} +19 -10
- package/dist/chunks/LpBreadcrumbs-CQJd73Gm.js +95 -0
- package/dist/chunks/{LpButton-5VXXCjwF.js → LpButton-CKSwC6Mu.js} +45 -15
- package/dist/chunks/{LpCalendar-B7Ko5RdR.js → LpCalendar-DrA2McTU.js} +1 -1
- package/dist/chunks/{LpCard-BhI1N_vL.js → LpCard-C2IvucmX.js} +1 -1
- package/dist/chunks/{LpCheckbox-CVccKYaH.js → LpCheckbox-Bkj13CbW.js} +8 -4
- package/dist/chunks/{LpCodeBlock-Bo0B4TFR.js → LpCodeBlock-ca7ANFyW.js} +49 -17
- package/dist/chunks/{LpColorPicker-BlXea7LM.js → LpColorPicker-zz4VGkG4.js} +75 -26
- package/dist/chunks/{LpConfirmDialog-Q-bxff8z.js → LpConfirmDialog-DCw5jR1t.js} +59 -17
- package/dist/chunks/LpConfirmHost-CbywMpMP.js +49 -0
- package/dist/chunks/LpContextMenu-BqkAYa9X.js +69 -0
- package/dist/chunks/LpDatePicker-DuusgT69.js +195 -0
- package/dist/chunks/LpDateRangePicker-DHeuznfC.js +208 -0
- package/dist/chunks/{LpDisclosure-ChQYmjlR.js → LpDisclosure-Cc23-JOT.js} +1 -1
- package/dist/chunks/{LpDrawer-BZ6k3hvo.js → LpDrawer-Dt4aB4Fr.js} +65 -28
- package/dist/chunks/{LpDropdownMenu-DJpoqRCb.js → LpDropdownMenu-DdJGQzPn.js} +2 -1
- package/dist/chunks/{LpEmptyState-Dsdqz1Wj.js → LpEmptyState-BJbZXC8D.js} +1 -1
- package/dist/chunks/LpFieldNotice-wtieLUTj.js +64 -0
- package/dist/chunks/{LpFileTree-_5vFBgaK.js → LpFileTree-CNurOvkV.js} +25 -10
- package/dist/chunks/{LpFileTreeNode-BdcIYKIE.js → LpFileTreeNode-D_qRRdsH.js} +3 -3
- package/dist/chunks/LpFormField-CtVYj6tO.js +101 -0
- package/dist/chunks/{LpIcon-CCnX5_2j.js → LpIcon-DYtaid0K.js} +20 -6
- package/dist/chunks/{LpInput-9EXWUM9B.js → LpInput-D-YGQbEv.js} +58 -20
- package/dist/chunks/{LpLightbox-2sYVMY-S.js → LpLightbox-DSDahF23.js} +148 -61
- package/dist/chunks/{LpLink-DCND-zyu.js → LpLink-Krkjhe_y.js} +15 -6
- package/dist/chunks/{LpLogViewer-CaRy5MeS.js → LpLogViewer-KypbgOyo.js} +300 -72
- package/dist/chunks/{LpMapPicker-ul4oYno6.js → LpMapPicker-Cc84LaM3.js} +39 -14
- package/dist/chunks/{LpMediaGallery-FF-NquIo.js → LpMediaGallery-YKr-cQPN.js} +7 -4
- package/dist/chunks/{LpModal-Bt0pQCI_.js → LpModal-DMMDQHAu.js} +52 -29
- package/dist/chunks/{LpModalNav-YaifHrXC.js → LpModalNav-BVPDyIup.js} +10 -7
- package/dist/chunks/{LpNotificationBell-DyGGsMAM.js → LpNotificationBell-CCwyJP5C.js} +79 -33
- package/dist/chunks/{LpNumberField-CWuX08iX.js → LpNumberField-B77O-z28.js} +21 -8
- 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-BcDlo3r_.js} +31 -20
- package/dist/chunks/{LpPasswordInput--sjYCkLS.js → LpPasswordInput-eKzQhbQP.js} +11 -8
- package/dist/chunks/LpPhoneInput-BCbrrhgE.js +336 -0
- package/dist/chunks/{LpPie-D6OnzwlJ.js → LpPie-BEJ2SfI6.js} +84 -28
- package/dist/chunks/{LpPopover-8268UmlC.js → LpPopover-DCKeqiVn.js} +5 -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/LpRangeCalendar-DZuaRV0W.js +331 -0
- package/dist/chunks/{LpRollingText-CM5gkSeF.js → LpRollingText-DB7upf-5.js} +1 -1
- package/dist/chunks/{LpScrollArea-D8xyKXcF.js → LpScrollArea-Bry1fdOM.js} +14 -2
- package/dist/chunks/{LpSection-aM6J_u51.js → LpSection-tKEH0jYf.js} +1 -1
- package/dist/chunks/{LpSegmented-fV0Sk92p.js → LpSegmented-C09EEam2.js} +8 -4
- package/dist/chunks/{LpSelect-ANIVtrpM.js → LpSelect-DNIL6MB9.js} +50 -31
- package/dist/chunks/{LpSidebar-ClBUwoEz.js → LpSidebar-CQNB0-yU.js} +30 -22
- package/dist/chunks/{LpSidebarNav-llOcs_Fn.js → LpSidebarNav-kx-LdqNU.js} +16 -11
- 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-B-7udBRP.js} +2 -2
- package/dist/chunks/{LpStepper-Bk-XaQYU.js → LpStepper-C7XiVKZj.js} +34 -19
- package/dist/chunks/{LpSwitch-Blizvqyt.js → LpSwitch-OrcOJX9m.js} +41 -27
- package/dist/chunks/LpTableFilter-BV8PpLM9.js +158 -0
- package/dist/chunks/{LpTableOfContents-CjvxPMpU.js → LpTableOfContents-BUcAfGPQ.js} +36 -41
- package/dist/chunks/{LpTabs-Cefe_lys.js → LpTabs-29iW1XOx.js} +20 -6
- package/dist/chunks/LpTagsInput-D1SuqbhB.js +300 -0
- package/dist/chunks/LpTextarea-uuScWo6-.js +77 -0
- package/dist/chunks/LpThemeProvider-Be4r2TQX.js +35 -0
- package/dist/chunks/LpThemeSwitcher-B4aVPbNC.js +166 -0
- package/dist/chunks/{LpTilt-DuyKbpkA.js → LpTilt-B7KHX1zH.js} +2 -2
- package/dist/chunks/{LpTimeField-K6nAGboX.js → LpTimeField-Cqe7fXnh.js} +14 -8
- package/dist/chunks/{LpToaster-gDB1EaU3.js → LpToaster-DpJvoCOh.js} +94 -31
- package/dist/chunks/{LpTooltip-hCLPAqMG.js → LpTooltip-CXVKcOXT.js} +14 -6
- package/dist/chunks/LpTooltipProvider-CftjV7Xc.js +25 -0
- package/dist/chunks/{LpTopologyCanvas-Cm1L39uL.js → LpTopologyCanvas-6ozNrQKh.js} +8 -2
- package/dist/chunks/{LpUptimeBar-DvAMno0S.js → LpUptimeBar-ugcv25xj.js} +44 -15
- package/dist/chunks/icons-CkA0njzm.js +43 -0
- package/dist/chunks/{LpThemeSwitcher-Cue-myST.js → useTheme-DJm1JSsY.js} +215 -260
- 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/LpCalendar.vue.js +1 -1
- package/dist/components/LpCard.vue.js +1 -1
- package/dist/components/LpChart.vue.d.ts +47 -3
- package/dist/components/LpChart.vue.js +377 -97
- 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.d.ts +2 -2
- package/dist/components/LpColorPicker.vue.js +1 -1
- package/dist/components/LpCommandPalette.vue.d.ts +14 -3
- package/dist/components/LpCommandPalette.vue.js +142 -77
- 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/LpDateRangePicker.vue.d.ts +60 -0
- package/dist/components/LpDateRangePicker.vue.js +4 -0
- package/dist/components/LpDisclosure.vue.js +1 -1
- package/dist/components/LpDrawer.vue.d.ts +10 -0
- package/dist/components/LpDrawer.vue.js +1 -1
- package/dist/components/LpDropdownMenu.vue.js +1 -1
- package/dist/components/LpDropzone.vue.js +23 -7
- package/dist/components/LpEmptyState.vue.js +1 -1
- package/dist/components/LpFieldNotice.vue.d.ts +8 -0
- package/dist/components/LpFieldNotice.vue.js +4 -0
- 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 +13 -1
- package/dist/components/LpFormField.vue.js +1 -1
- package/dist/components/LpIcon.vue.d.ts +0 -1
- package/dist/components/LpIcon.vue.js +1 -1
- package/dist/components/LpImageEditor.vue.js +93 -58
- package/dist/components/LpInput.vue.d.ts +22 -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 +72 -3
- 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.d.ts +13 -0
- 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.d.ts +1 -1
- package/dist/components/LpProgress.vue.js +1 -1
- package/dist/components/LpRadioGroup.vue.js +1 -1
- package/dist/components/LpRangeCalendar.vue.d.ts +51 -0
- package/dist/components/LpRangeCalendar.vue.js +4 -0
- package/dist/components/LpRollingText.vue.d.ts +1 -1
- package/dist/components/LpRollingText.vue.js +1 -1
- package/dist/components/LpScrollArea.vue.d.ts +2 -2
- package/dist/components/LpScrollArea.vue.js +1 -1
- package/dist/components/LpSection.vue.d.ts +1 -1
- package/dist/components/LpSection.vue.js +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 +7 -1
- package/dist/components/LpShortcutsDialog.vue.js +60 -15
- 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/LpStepper.vue.js +1 -1
- package/dist/components/LpSwitch.vue.js +1 -1
- package/dist/components/LpTable.vue.d.ts +107 -3
- package/dist/components/LpTable.vue.js +540 -128
- package/dist/components/LpTableFilter.vue.d.ts +31 -0
- package/dist/components/LpTableFilter.vue.js +4 -0
- 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/LpTagsInput.vue.d.ts +77 -0
- package/dist/components/LpTagsInput.vue.js +4 -0
- 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 +15 -2
- 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 +42 -6
- 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.js +3 -0
- 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/dateRange.d.ts +43 -0
- package/dist/components/dateRange.js +76 -0
- package/dist/components/exportData.d.ts +58 -0
- package/dist/components/exportData.js +165 -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/logSearch.d.ts +18 -0
- package/dist/components/logSearch.js +36 -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/phone.d.ts +41 -0
- package/dist/components/phone.js +80 -0
- package/dist/components/sidebar.d.ts +7 -1
- package/dist/components/tableFilter.d.ts +36 -0
- package/dist/components/tableFilter.js +84 -0
- package/dist/components/tableSort.d.ts +8 -0
- package/dist/components/tableSort.js +31 -0
- package/dist/components/tags.d.ts +20 -0
- package/dist/components/tags.js +37 -0
- package/dist/composables/useField.d.ts +38 -0
- package/dist/composables/useField.js +45 -0
- package/dist/composables/useFieldNotice.d.ts +17 -0
- package/dist/composables/useFieldNotice.js +28 -0
- package/dist/composables/useForm.d.ts +53 -0
- package/dist/composables/useForm.js +207 -0
- package/dist/composables/useFormDraft.d.ts +10 -3
- package/dist/composables/useFormDraft.js +9 -14
- package/dist/composables/useHotkeys.d.ts +81 -5
- package/dist/composables/useHotkeys.js +223 -25
- package/dist/composables/useInputFilter.d.ts +17 -0
- package/dist/composables/useInputFilter.js +47 -10
- package/dist/composables/useInputMask.d.ts +59 -0
- package/dist/composables/useInputMask.js +170 -0
- package/dist/composables/useLpConfig.d.ts +24 -0
- package/dist/composables/useLpConfig.js +44 -0
- package/dist/composables/usePaintSelect.d.ts +22 -0
- package/dist/composables/usePaintSelect.js +169 -0
- package/dist/composables/useRovingFocus.js +7 -0
- package/dist/composables/useShift.js +7 -2
- 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/icons-all.d.ts +1 -0
- package/dist/icons-all.js +3 -0
- package/dist/icons.d.ts +14 -1
- package/dist/index.d.ts +60 -4
- package/dist/index.js +245 -141
- package/dist/kit-icons.d.ts +2 -0
- 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/backdrop.d.ts +12 -0
- package/dist/theme/presets.d.ts +0 -2
- package/dist/theme/useTheme.d.ts +32 -9
- package/package.json +18 -8
- package/src/component-names.ts +9 -7
- package/src/components/ContextMenuItems.vue +88 -0
- package/src/components/LayoutCanvas.vue +26 -6
- package/src/components/LayoutNode.vue +30 -4
- package/src/components/LpActionBar.vue +31 -8
- 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 +47 -10
- package/src/components/LpAvatar.vue +20 -6
- package/src/components/LpBreadcrumbs.vue +65 -41
- package/src/components/LpButton.vue +60 -14
- package/src/components/LpChart.vue +351 -28
- package/src/components/LpCheckbox.vue +7 -3
- package/src/components/LpCodeBlock.vue +50 -14
- package/src/components/LpColorPicker.vue +73 -10
- package/src/components/LpCommandPalette.vue +115 -20
- package/src/components/LpConfirmDialog.vue +68 -17
- package/src/components/LpConfirmHost.vue +59 -0
- package/src/components/LpContextMenu.vue +15 -116
- package/src/components/LpDatePicker.vue +104 -68
- package/src/components/LpDateRangePicker.vue +224 -0
- package/src/components/LpDrawer.vue +56 -19
- package/src/components/LpDropdownMenu.vue +1 -0
- package/src/components/LpDropzone.vue +21 -4
- package/src/components/LpFieldNotice.vue +65 -0
- package/src/components/LpFileTree.vue +33 -7
- package/src/components/LpFormField.vue +59 -7
- package/src/components/LpIcon.vue +22 -4
- package/src/components/LpImageEditor.vue +96 -57
- package/src/components/LpInput.vue +62 -11
- package/src/components/LpLightbox.vue +140 -29
- package/src/components/LpLink.vue +24 -13
- package/src/components/LpLogViewer.vue +311 -39
- package/src/components/LpMapPicker.vue +36 -13
- package/src/components/LpMediaGallery.vue +8 -2
- package/src/components/LpModal.vue +54 -28
- package/src/components/LpModalNav.vue +5 -2
- package/src/components/LpNotificationBell.vue +77 -23
- 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 +224 -39
- package/src/components/LpPie.vue +102 -20
- package/src/components/LpPopover.vue +4 -0
- package/src/components/LpProgress.vue +5 -3
- package/src/components/LpRadioGroup.vue +9 -2
- package/src/components/LpRangeCalendar.vue +365 -0
- package/src/components/LpRollingText.vue +3 -0
- package/src/components/LpScrollArea.vue +22 -2
- package/src/components/LpSegmented.vue +12 -2
- package/src/components/LpSelect.vue +0 -0
- package/src/components/LpShortcutsDialog.vue +83 -9
- 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/LpStepper.vue +23 -10
- package/src/components/LpSwitch.vue +31 -8
- package/src/components/LpTable.vue +668 -90
- package/src/components/LpTableFilter.vue +175 -0
- package/src/components/LpTableOfContents.vue +50 -32
- package/src/components/LpTabs.vue +23 -6
- package/src/components/LpTagsInput.vue +364 -0
- package/src/components/LpTextarea.vue +44 -6
- package/src/components/LpThemeProvider.vue +41 -0
- package/src/components/LpThemeSwitcher.vue +76 -33
- package/src/components/LpTilt.vue +2 -2
- package/src/components/LpTimeField.vue +14 -3
- package/src/components/LpToaster.vue +115 -27
- package/src/components/LpTooltip.vue +29 -5
- package/src/components/LpTooltipProvider.vue +24 -0
- package/src/components/LpTopologyCanvas.vue +19 -2
- package/src/components/LpUptimeBar.vue +46 -8
- package/src/components/chart.ts +82 -8
- package/src/components/codeHighlight.ts +111 -15
- package/src/components/color.ts +30 -9
- package/src/components/commandSearch.ts +6 -0
- package/src/components/confirm.ts +58 -0
- package/src/components/countries.ts +12 -0
- package/src/components/dateRange.ts +134 -0
- package/src/components/exportData.ts +228 -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/logSearch.ts +46 -0
- package/src/components/modalDepth.ts +48 -6
- package/src/components/otp.ts +16 -0
- package/src/components/phone.ts +140 -0
- package/src/components/sidebar.ts +7 -1
- package/src/components/tableFilter.ts +122 -0
- package/src/components/tableSort.ts +37 -0
- package/src/components/tags.ts +62 -0
- package/src/composables/useField.ts +83 -0
- package/src/composables/useFieldNotice.ts +59 -0
- package/src/composables/useForm.ts +314 -0
- package/src/composables/useFormDraft.ts +25 -20
- package/src/composables/useHotkeys.ts +355 -28
- package/src/composables/useInputFilter.ts +77 -14
- package/src/composables/useInputMask.ts +254 -0
- package/src/composables/useLpConfig.ts +87 -0
- package/src/composables/usePaintSelect.ts +243 -0
- package/src/composables/useRovingFocus.ts +11 -0
- package/src/composables/useShift.ts +13 -2
- package/src/composables/useTilt.ts +5 -6
- package/src/composables/useToast.ts +56 -4
- package/src/composables/useZoomPan.ts +6 -6
- package/src/iconSubset.d.mts +10 -0
- package/src/iconSubset.mjs +51 -0
- package/src/icons-all.ts +10 -0
- package/src/icons.ts +59 -8
- package/src/index.ts +73 -4
- package/src/kit-icons.ts +5 -0
- package/src/layout/tree.ts +30 -0
- package/src/layout/useLayout.ts +68 -18
- package/src/nuxt.ts +87 -17
- package/src/runtime/config.plugin.ts +14 -0
- package/src/runtime/theme.plugin.ts +43 -23
- package/src/theme/backdrop.ts +69 -0
- package/src/theme/presets.ts +6 -64
- package/src/theme/useTheme.ts +206 -100
- package/src/tokens/tokens.css +46 -0
- 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/LpPhoneInput-BDSKVl_z.js +0 -209
- package/dist/chunks/LpTextarea-t7F6gv8E.js +0 -47
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,71 @@
|
|
|
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)
|
|
21
|
+
* icons which lucide icons render in the server pass and ship in the
|
|
22
|
+
* main bundle: "scan" (default) finds "lucide:*" literals in the
|
|
23
|
+
* app's source, "all" registers the whole set, "kit" only the
|
|
24
|
+
* kit's own, or a list of names. Anything else still renders,
|
|
25
|
+
* from a lazily loaded chunk of the bundled collection.
|
|
15
26
|
*/
|
|
16
|
-
import {
|
|
27
|
+
import { readFileSync } from "node:fs"
|
|
28
|
+
import { createRequire } from "node:module"
|
|
29
|
+
import { addComponent, addPlugin, addPluginTemplate, addTemplate, createResolver, defineNuxtModule } from "@nuxt/kit"
|
|
17
30
|
import { COMPONENT_NAMES } from "./component-names"
|
|
31
|
+
import { namesInDirs, subset } from "./iconSubset.mjs"
|
|
18
32
|
|
|
19
33
|
export interface LeavepulseUiOptions {
|
|
20
34
|
/** Register the SSR theme plugin. Disable to wire theming yourself. */
|
|
21
35
|
theme?: boolean
|
|
22
|
-
/**
|
|
36
|
+
/** Theme name to fall back to when nothing is saved (default "Dark"). */
|
|
23
37
|
defaultTheme?: string
|
|
38
|
+
/** Module path whose default export is the app's TokenSet[]. */
|
|
39
|
+
themes?: string
|
|
40
|
+
/** Provide NuxtLink as the link component for kit navigation (default true). */
|
|
41
|
+
link?: boolean
|
|
42
|
+
/** Component names to leave unregistered. */
|
|
43
|
+
exclude?: string[]
|
|
44
|
+
/** Lucide icons registered up front (default "scan"). */
|
|
45
|
+
icons?: "scan" | "all" | "kit" | string[]
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function iconsPlugin(mode: LeavepulseUiOptions["icons"], srcDir: string): string {
|
|
49
|
+
if (mode === "kit") return ""
|
|
50
|
+
if (mode === "all") return 'import "@leavepulse/ui/icons-all"\n'
|
|
51
|
+
const lucide = JSON.parse(readFileSync(createRequire(import.meta.url).resolve("@iconify-json/lucide/icons.json"), "utf8"))
|
|
52
|
+
const names = Array.isArray(mode) ? mode.map((n) => n.replace(/^lucide:/, "")) : namesInDirs([srcDir])
|
|
53
|
+
return `import { registerIconCollection } from "@leavepulse/ui"\nregisterIconCollection(${JSON.stringify(subset(lucide, names))})\n`
|
|
24
54
|
}
|
|
25
55
|
|
|
26
56
|
export default defineNuxtModule<LeavepulseUiOptions>({
|
|
27
57
|
meta: { name: "@leavepulse/ui", configKey: "leavepulseUi" },
|
|
28
|
-
defaults: { theme: true },
|
|
29
|
-
setup(
|
|
58
|
+
defaults: { theme: true, link: true, icons: "scan" },
|
|
59
|
+
setup(
|
|
60
|
+
options: LeavepulseUiOptions,
|
|
61
|
+
nuxt: {
|
|
62
|
+
options: {
|
|
63
|
+
runtimeConfig: { public: Record<string, unknown> }
|
|
64
|
+
alias: Record<string, string>
|
|
65
|
+
srcDir: string
|
|
66
|
+
}
|
|
67
|
+
hook: (
|
|
68
|
+
name: "prepare:types",
|
|
69
|
+
fn: (options: { references: { path: string }[] }) => void,
|
|
70
|
+
) => void
|
|
71
|
+
},
|
|
72
|
+
) {
|
|
73
|
+
const resolver = createResolver(import.meta.url)
|
|
74
|
+
const skip = new Set(options.exclude ?? [])
|
|
30
75
|
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).
|
|
76
|
+
if (skip.has(name)) continue
|
|
77
|
+
// Each component's own dist chunk rather than the barrel, so the app
|
|
78
|
+
// ships only the components it uses (and their real deps).
|
|
36
79
|
addComponent({
|
|
37
80
|
name,
|
|
38
81
|
export: "default",
|
|
@@ -40,18 +83,45 @@ export default defineNuxtModule<LeavepulseUiOptions>({
|
|
|
40
83
|
})
|
|
41
84
|
}
|
|
42
85
|
|
|
86
|
+
const icons = iconsPlugin(options.icons, nuxt.options.srcDir)
|
|
87
|
+
if (icons) {
|
|
88
|
+
addPluginTemplate({
|
|
89
|
+
filename: "leavepulse-ui-icons.mjs",
|
|
90
|
+
mode: "all",
|
|
91
|
+
getContents: () => `${icons}import { defineNuxtPlugin } from "#app"\nexport default defineNuxtPlugin(() => {})\n`,
|
|
92
|
+
})
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (options.link !== false) {
|
|
96
|
+
addPlugin({ src: resolver.resolve("./runtime/config.plugin"), mode: "all" })
|
|
97
|
+
}
|
|
98
|
+
|
|
43
99
|
if (options.theme === false) return
|
|
44
100
|
|
|
45
|
-
|
|
46
|
-
|
|
101
|
+
const themes = addTemplate({
|
|
102
|
+
filename: "leavepulse-ui-themes.mjs",
|
|
103
|
+
getContents: () =>
|
|
104
|
+
options.themes
|
|
105
|
+
? `export { default } from ${JSON.stringify(options.themes)}\n`
|
|
106
|
+
: "export default []\n",
|
|
107
|
+
})
|
|
108
|
+
nuxt.options.alias["#lp-ui-themes"] = themes.dst
|
|
109
|
+
const themeTypes = addTemplate({
|
|
110
|
+
filename: "types/leavepulse-ui-themes.d.ts",
|
|
111
|
+
getContents: () =>
|
|
112
|
+
'declare module "#lp-ui-themes" {\n const themes: import("@leavepulse/ui").TokenSet[]\n export default themes\n}\n',
|
|
113
|
+
})
|
|
114
|
+
nuxt.hook("prepare:types", ({ references }) => {
|
|
115
|
+
references.push({ path: themeTypes.dst })
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
// Read from runtimeConfig rather than closed over, so the options survive
|
|
119
|
+
// the build into the server bundle.
|
|
47
120
|
nuxt.options.runtimeConfig.public.leavepulseUi = {
|
|
48
|
-
...(nuxt.options.runtimeConfig.public.leavepulseUi ?? {}),
|
|
121
|
+
...((nuxt.options.runtimeConfig.public.leavepulseUi as Record<string, unknown> | undefined) ?? {}),
|
|
49
122
|
defaultTheme: options.defaultTheme,
|
|
50
123
|
}
|
|
51
124
|
|
|
52
|
-
addPlugin({
|
|
53
|
-
src: createResolver(import.meta.url).resolve("./runtime/theme.plugin"),
|
|
54
|
-
mode: "all",
|
|
55
|
-
})
|
|
125
|
+
addPlugin({ src: resolver.resolve("./runtime/theme.plugin"), mode: "all" })
|
|
56
126
|
},
|
|
57
127
|
})
|
|
@@ -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
|
-
|
|
24
|
-
leavepulse,
|
|
20
|
+
dark,
|
|
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) ?? dark
|
|
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
|
})
|
package/src/theme/backdrop.ts
CHANGED
|
@@ -49,3 +49,72 @@ export function detectBackdropFilter(
|
|
|
49
49
|
root.toggleAttribute(NO_BACKDROP_ATTR, !usable)
|
|
50
50
|
return usable
|
|
51
51
|
}
|
|
52
|
+
|
|
53
|
+
/*
|
|
54
|
+
* Glass without backdrop-filter. Where the engine cannot blur what lies under
|
|
55
|
+
* a panel (the flag above), it can still blur an ordinary element, so a panel
|
|
56
|
+
* can be frosted by painting a blurred copy of what is under it, as long as
|
|
57
|
+
* that is known. In an app that paints its own wallpaper (a launcher, a shell)
|
|
58
|
+
* it is: the consumer hands the wallpaper over as a CSS `background` value,
|
|
59
|
+
* and every `.lp-glass-overlay` draws it, blurred and aligned to the viewport,
|
|
60
|
+
* beneath its tint. Live content under the panel stays sharp; the wallpaper,
|
|
61
|
+
* which is most of what glass shows, reads as frosted.
|
|
62
|
+
*
|
|
63
|
+
* The copy is placed by the panel's position on screen, which overlays animate
|
|
64
|
+
* and drawers drag, so while any glass panel is mounted its offset is kept in
|
|
65
|
+
* CSS variables (`--lp-gx`, `--lp-gy`) once a frame. Nothing runs where the
|
|
66
|
+
* real blur works or no backdrop was given.
|
|
67
|
+
*/
|
|
68
|
+
export const GLASS_BACKDROP_ATTR = "data-lp-glass-backdrop"
|
|
69
|
+
|
|
70
|
+
let tracking = 0
|
|
71
|
+
let observer: MutationObserver | undefined
|
|
72
|
+
|
|
73
|
+
function trackPanels() {
|
|
74
|
+
const panels = document.querySelectorAll<HTMLElement>(".lp-glass-overlay")
|
|
75
|
+
for (const panel of panels) {
|
|
76
|
+
const rect = panel.getBoundingClientRect()
|
|
77
|
+
const x = `${Math.round(rect.left)}px`
|
|
78
|
+
const y = `${Math.round(rect.top)}px`
|
|
79
|
+
if (panel.style.getPropertyValue("--lp-gx") !== x) panel.style.setProperty("--lp-gx", x)
|
|
80
|
+
if (panel.style.getPropertyValue("--lp-gy") !== y) panel.style.setProperty("--lp-gy", y)
|
|
81
|
+
}
|
|
82
|
+
tracking = panels.length ? requestAnimationFrame(trackPanels) : 0
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function startTracking() {
|
|
86
|
+
if (!tracking && document.querySelector(".lp-glass-overlay")) tracking = requestAnimationFrame(trackPanels)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Give glass panels a wallpaper to frost where backdrop-filter does not work:
|
|
91
|
+
* `setGlassBackdrop("url(/bg.jpg) center / cover no-repeat, #0b0f14")`, the
|
|
92
|
+
* same value the app paints behind itself. `filter` replaces the default blur,
|
|
93
|
+
* e.g. `"none"` for a wallpaper that was blurred ahead of time, which is
|
|
94
|
+
* cheaper on an engine that blurs on the CPU. `null` turns it off.
|
|
95
|
+
*/
|
|
96
|
+
export function setGlassBackdrop(
|
|
97
|
+
background: string | null,
|
|
98
|
+
options: { filter?: string; root?: HTMLElement } = {},
|
|
99
|
+
): void {
|
|
100
|
+
if (typeof document === "undefined") return
|
|
101
|
+
const root = options.root ?? document.documentElement
|
|
102
|
+
if (!background) {
|
|
103
|
+
root.removeAttribute(GLASS_BACKDROP_ATTR)
|
|
104
|
+
root.style.removeProperty("--lp-glass-backdrop")
|
|
105
|
+
root.style.removeProperty("--lp-glass-backdrop-filter")
|
|
106
|
+
observer?.disconnect()
|
|
107
|
+
observer = undefined
|
|
108
|
+
return
|
|
109
|
+
}
|
|
110
|
+
root.setAttribute(GLASS_BACKDROP_ATTR, "")
|
|
111
|
+
root.style.setProperty("--lp-glass-backdrop", background)
|
|
112
|
+
if (options.filter) root.style.setProperty("--lp-glass-backdrop-filter", options.filter)
|
|
113
|
+
else root.style.removeProperty("--lp-glass-backdrop-filter")
|
|
114
|
+
if (!root.hasAttribute(NO_BACKDROP_ATTR) || typeof MutationObserver === "undefined") return
|
|
115
|
+
if (!observer) {
|
|
116
|
+
observer = new MutationObserver(startTracking)
|
|
117
|
+
observer.observe(document.body, { childList: true, subtree: true })
|
|
118
|
+
}
|
|
119
|
+
startTracking()
|
|
120
|
+
}
|
package/src/theme/presets.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { TokenSet } from "./tokens"
|
|
2
2
|
|
|
3
3
|
/*
|
|
4
4
|
* Built-in theme presets — plain TokenSet objects (JSON). These ARE the themes;
|
|
@@ -14,13 +14,12 @@ const interFont = {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
/*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* and this near-black neutral became "Onyx" to free that label up.
|
|
17
|
+
* The kit's dark theme, a near-black neutral. It was displayed as "Onyx" while
|
|
18
|
+
* the LeavePulse site theme held the "Dark" label; with that theme gone the
|
|
19
|
+
* label is back here.
|
|
21
20
|
*/
|
|
22
21
|
export const dark: TokenSet = {
|
|
23
|
-
name: "
|
|
22
|
+
name: "Dark",
|
|
24
23
|
mode: "dark",
|
|
25
24
|
colors: {
|
|
26
25
|
surface: "#080b0d",
|
|
@@ -120,63 +119,6 @@ export const lime: TokenSet = {
|
|
|
120
119
|
},
|
|
121
120
|
}
|
|
122
121
|
|
|
123
|
-
/*
|
|
124
|
-
* Glass skin — frosted panels with backdrop blur, a faint top-down highlight
|
|
125
|
-
* overlay, a layered drop shadow and an inset highlight line. Opt a theme into
|
|
126
|
-
* it by setting its `surface` axis to this (the LeavePulse site uses it).
|
|
127
|
-
*/
|
|
128
|
-
const glassSurface: SurfaceTokens = {
|
|
129
|
-
borderWidth: "1px",
|
|
130
|
-
panelBlur: "10px",
|
|
131
|
-
panelSaturate: "120%",
|
|
132
|
-
panelOverlay:
|
|
133
|
-
"linear-gradient(180deg, rgba(255, 255, 255, 0.06), rgba(255, 255, 255, 0.01))",
|
|
134
|
-
panelShadow: "0 20px 60px rgba(0, 0, 0, 0.35)",
|
|
135
|
-
panelInset: "inset 0 1px 0 rgba(255, 255, 255, 0.08)",
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/*
|
|
139
|
-
* LeavePulse site theme — the colours the website shipped before the kit
|
|
140
|
-
* migration (deep navy surfaces, cyan brand, teal accent), with the glass skin.
|
|
141
|
-
* Distinct from `dark` (which is a near-black neutral) so the site keeps its
|
|
142
|
-
* look when it switches its CSS-var dictionary over to the kit.
|
|
143
|
-
*/
|
|
144
|
-
export const leavepulse: TokenSet = {
|
|
145
|
-
name: "Dark",
|
|
146
|
-
mode: "dark",
|
|
147
|
-
colors: {
|
|
148
|
-
surface: "#020618",
|
|
149
|
-
surfaceRaised: "#0b1222",
|
|
150
|
-
surfaceSoft: "rgba(11, 18, 34, 0.7)",
|
|
151
|
-
ink: "#f3f6ff",
|
|
152
|
-
inkInverse: "#0b1222",
|
|
153
|
-
muted: "#94a3bf",
|
|
154
|
-
mutedStrong: "#cad5e2",
|
|
155
|
-
brand: "#00bcff",
|
|
156
|
-
brandHover: "#19c3ff",
|
|
157
|
-
brandSoft: "rgba(0, 188, 255, 0.2)",
|
|
158
|
-
action: "#44c2ad",
|
|
159
|
-
actionHover: "#56d3be",
|
|
160
|
-
actionSoft: "rgba(68, 194, 173, 0.14)",
|
|
161
|
-
accent: "#d36a2c",
|
|
162
|
-
accentHover: "#da824e",
|
|
163
|
-
accentSoft: "rgba(211, 106, 44, 0.14)",
|
|
164
|
-
danger: "#f87171",
|
|
165
|
-
dangerHover: "#fca5a5",
|
|
166
|
-
dangerSoft: "rgba(248, 113, 113, 0.14)",
|
|
167
|
-
line: "#1c2740",
|
|
168
|
-
lineStrong: "rgba(255, 255, 255, 0.15)",
|
|
169
|
-
ring: "rgba(0, 188, 255, 0.35)",
|
|
170
|
-
},
|
|
171
|
-
shape: { ...sharedShape, radiusControl: 12 },
|
|
172
|
-
density: { ...sharedDensity },
|
|
173
|
-
font: {
|
|
174
|
-
sans: '"Inter", "IBM Plex Sans", "Segoe UI", sans-serif',
|
|
175
|
-
mono: '"JetBrains Mono", "SF Mono", ui-monospace, monospace',
|
|
176
|
-
},
|
|
177
|
-
surface: glassSurface,
|
|
178
|
-
}
|
|
179
|
-
|
|
180
122
|
export const rose: TokenSet = {
|
|
181
123
|
name: "Rose",
|
|
182
124
|
mode: "dark",
|
|
@@ -305,5 +247,5 @@ export const nord: TokenSet = {
|
|
|
305
247
|
font: { ...interFont },
|
|
306
248
|
}
|
|
307
249
|
|
|
308
|
-
export const presets = { dark, light, lime,
|
|
250
|
+
export const presets = { dark, light, lime, rose, amber, violet, nord } as const
|
|
309
251
|
export type PresetName = keyof typeof presets
|