@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
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
export default { inheritAttrs: false }
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<script setup lang="ts">
|
|
6
|
+
/*
|
|
7
|
+
* Range field + popover: presets on one side, a range calendar on the other.
|
|
8
|
+
* The model is `{ start, end }` of ISO days, like LpDatePicker's single day.
|
|
9
|
+
* Picking the second end or a preset fills the field and closes the popover.
|
|
10
|
+
* Two months sit side by side where there is room, one on a phone.
|
|
11
|
+
*/
|
|
12
|
+
import { PopoverContent, PopoverPortal, PopoverRoot, PopoverTrigger } from "reka-ui"
|
|
13
|
+
import { computed, onBeforeUnmount, onMounted, ref, useAttrs } from "vue"
|
|
14
|
+
import { useFieldControl } from "../composables/useField"
|
|
15
|
+
import { useLabels } from "../composables/useLpConfig"
|
|
16
|
+
import { mergeClass } from "../composables/useMergedClass"
|
|
17
|
+
import {
|
|
18
|
+
clampRange,
|
|
19
|
+
type DateRange,
|
|
20
|
+
type DateRangePreset,
|
|
21
|
+
defaultRangePresets,
|
|
22
|
+
formatRange,
|
|
23
|
+
normalizeRange,
|
|
24
|
+
sameRange,
|
|
25
|
+
} from "./dateRange"
|
|
26
|
+
import { POPOVER_PANEL } from "./dropdown"
|
|
27
|
+
import LpIcon from "./LpIcon.vue"
|
|
28
|
+
import LpRollingText from "./LpRollingText.vue"
|
|
29
|
+
import LpRangeCalendar, { type RangeChange } from "./LpRangeCalendar.vue"
|
|
30
|
+
|
|
31
|
+
export interface DateRangePickerLabels extends Record<string, string> {
|
|
32
|
+
placeholder: string
|
|
33
|
+
clear: string
|
|
34
|
+
presets: string
|
|
35
|
+
today: string
|
|
36
|
+
last7: string
|
|
37
|
+
last30: string
|
|
38
|
+
thisMonth: string
|
|
39
|
+
lastMonth: string
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const props = withDefaults(
|
|
43
|
+
defineProps<{
|
|
44
|
+
/** Selected range (v-model). */
|
|
45
|
+
modelValue?: DateRange
|
|
46
|
+
placeholder?: string
|
|
47
|
+
min?: string
|
|
48
|
+
max?: string
|
|
49
|
+
isDisabled?: (iso: string) => boolean
|
|
50
|
+
isDateUnavailable?: (iso: string) => boolean
|
|
51
|
+
/** Longest allowed range, in days. */
|
|
52
|
+
maximumDays?: number
|
|
53
|
+
/** Shortcut ranges; an empty list hides them. Defaults to the built-in set. */
|
|
54
|
+
presets?: DateRangePreset[]
|
|
55
|
+
clearable?: boolean
|
|
56
|
+
disabled?: boolean
|
|
57
|
+
invalid?: boolean
|
|
58
|
+
size?: "sm" | "md" | "lg"
|
|
59
|
+
locale?: string
|
|
60
|
+
/** Intl format for the displayed ends. */
|
|
61
|
+
format?: Intl.DateTimeFormatOptions
|
|
62
|
+
labels?: Partial<DateRangePickerLabels>
|
|
63
|
+
}>(),
|
|
64
|
+
{ size: "md" },
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
const emit = defineEmits<{
|
|
68
|
+
(e: "update:modelValue", value: DateRange | undefined): void
|
|
69
|
+
}>()
|
|
70
|
+
|
|
71
|
+
const text = useLabels<DateRangePickerLabels>(
|
|
72
|
+
"dateRangePicker",
|
|
73
|
+
{
|
|
74
|
+
placeholder: "Pick a date range",
|
|
75
|
+
clear: "Clear",
|
|
76
|
+
presets: "Presets",
|
|
77
|
+
today: "Today",
|
|
78
|
+
last7: "Last 7 days",
|
|
79
|
+
last30: "Last 30 days",
|
|
80
|
+
thisMonth: "This month",
|
|
81
|
+
lastMonth: "Last month",
|
|
82
|
+
},
|
|
83
|
+
() => props.labels,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
const open = ref(false)
|
|
87
|
+
const value = computed(() => normalizeRange(props.modelValue))
|
|
88
|
+
const display = computed(() => (value.value ? formatRange(value.value, props.locale, props.format) : ""))
|
|
89
|
+
|
|
90
|
+
const presetList = computed<DateRangePreset[]>(() => {
|
|
91
|
+
return props.presets ?? defaultRangePresets(text.value)
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
/*
|
|
95
|
+
* A range picked on the calendar keeps the popover open: the field already
|
|
96
|
+
* shows it, and the user can still pull either end before clicking away.
|
|
97
|
+
* Closing on the second click left no moment to adjust. A preset is a whole
|
|
98
|
+
* answer, so it closes.
|
|
99
|
+
*/
|
|
100
|
+
function pick(range: DateRange, change?: RangeChange) {
|
|
101
|
+
emit("update:modelValue", range)
|
|
102
|
+
if (!change) open.value = false
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function pickPreset(preset: DateRangePreset) {
|
|
106
|
+
const range = clampRange(preset.range(), props.min, props.max)
|
|
107
|
+
if (range) pick(range)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function presetFits(preset: DateRangePreset): boolean {
|
|
111
|
+
return !!clampRange(preset.range(), props.min, props.max)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const wide = ref(false)
|
|
115
|
+
let query: MediaQueryList | undefined
|
|
116
|
+
const onQuery = () => {
|
|
117
|
+
wide.value = !!query?.matches
|
|
118
|
+
}
|
|
119
|
+
onMounted(() => {
|
|
120
|
+
query = window.matchMedia("(min-width: 640px)")
|
|
121
|
+
onQuery()
|
|
122
|
+
query.addEventListener("change", onQuery)
|
|
123
|
+
})
|
|
124
|
+
onBeforeUnmount(() => query?.removeEventListener("change", onQuery))
|
|
125
|
+
|
|
126
|
+
const shellSize = {
|
|
127
|
+
sm: "h-(--size-control-sm) text-xs",
|
|
128
|
+
md: "h-(--size-control-md) text-sm",
|
|
129
|
+
lg: "h-(--size-control-lg) text-sm",
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const attrs = useAttrs()
|
|
133
|
+
const field = useFieldControl(() => ({
|
|
134
|
+
wrapped: false,
|
|
135
|
+
id: typeof attrs.id === "string" ? attrs.id : undefined,
|
|
136
|
+
invalid: props.invalid,
|
|
137
|
+
disabled: props.disabled,
|
|
138
|
+
}))
|
|
139
|
+
const showClear = computed(() => props.clearable && !!value.value && !field.value.disabled)
|
|
140
|
+
</script>
|
|
141
|
+
|
|
142
|
+
<template>
|
|
143
|
+
<div :class="mergeClass('relative w-full', attrs.class as string)" :style="attrs.style as never">
|
|
144
|
+
<PopoverRoot v-model:open="open">
|
|
145
|
+
<PopoverTrigger as-child>
|
|
146
|
+
<button
|
|
147
|
+
v-bind="{ ...attrs, class: undefined, style: undefined }"
|
|
148
|
+
:id="field.id"
|
|
149
|
+
type="button"
|
|
150
|
+
:disabled="field.disabled"
|
|
151
|
+
:aria-invalid="field.invalid || undefined"
|
|
152
|
+
:aria-describedby="field.describedBy"
|
|
153
|
+
class="group flex w-full items-center gap-2 rounded-control border bg-surface-soft px-3 text-left text-ink outline-none transition-colors duration-[var(--duration-fast)] focus-visible:ring-2 focus-visible:ring-ring data-[state=open]:border-brand disabled:cursor-not-allowed disabled:opacity-55"
|
|
154
|
+
:class="[
|
|
155
|
+
shellSize[size],
|
|
156
|
+
field.invalid ? 'border-danger focus-visible:ring-danger-soft' : 'border-line focus-visible:border-brand',
|
|
157
|
+
]"
|
|
158
|
+
>
|
|
159
|
+
<LpIcon name="lucide:calendar-range" :size="16" class="shrink-0 text-muted" />
|
|
160
|
+
<LpRollingText
|
|
161
|
+
:value="display || placeholder || text.placeholder"
|
|
162
|
+
align="start"
|
|
163
|
+
class="min-w-0 flex-1"
|
|
164
|
+
:class="display ? '' : 'text-muted'"
|
|
165
|
+
/>
|
|
166
|
+
<span v-if="showClear" class="w-[15px] shrink-0" aria-hidden="true" />
|
|
167
|
+
<LpIcon
|
|
168
|
+
name="lucide:chevron-down"
|
|
169
|
+
:size="15"
|
|
170
|
+
class="shrink-0 text-muted transition-transform duration-[var(--duration-fast)] ease-[var(--ease-emphasized)] group-data-[state=open]:rotate-180 motion-reduce:transition-none"
|
|
171
|
+
/>
|
|
172
|
+
</button>
|
|
173
|
+
</PopoverTrigger>
|
|
174
|
+
<PopoverPortal>
|
|
175
|
+
<PopoverContent
|
|
176
|
+
:side-offset="6"
|
|
177
|
+
align="start"
|
|
178
|
+
:collision-padding="8"
|
|
179
|
+
:class="[POPOVER_PANEL, 'z-(--z-popover) flex max-w-[calc(100vw-1rem)] flex-col rounded-card p-0 outline-none sm:flex-row']"
|
|
180
|
+
>
|
|
181
|
+
<div
|
|
182
|
+
v-if="presetList.length"
|
|
183
|
+
role="group"
|
|
184
|
+
:aria-label="text.presets"
|
|
185
|
+
class="flex gap-1 overflow-x-auto border-b border-line p-2 sm:w-40 sm:flex-col sm:overflow-visible sm:border-r sm:border-b-0"
|
|
186
|
+
>
|
|
187
|
+
<button
|
|
188
|
+
v-for="(preset, i) in presetList"
|
|
189
|
+
:key="`${i}:${preset.label}`"
|
|
190
|
+
type="button"
|
|
191
|
+
:disabled="!presetFits(preset)"
|
|
192
|
+
:aria-pressed="sameRange(value, preset.range())"
|
|
193
|
+
class="shrink-0 rounded-control px-2.5 py-1.5 text-left text-sm whitespace-nowrap text-muted outline-none transition-colors duration-[var(--duration-fast)] hover:bg-surface-soft hover:text-ink focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-40 aria-pressed:bg-brand-soft aria-pressed:text-ink"
|
|
194
|
+
@click="pickPreset(preset)"
|
|
195
|
+
>
|
|
196
|
+
{{ preset.label }}
|
|
197
|
+
</button>
|
|
198
|
+
</div>
|
|
199
|
+
<LpRangeCalendar
|
|
200
|
+
:model-value="value"
|
|
201
|
+
:min="min"
|
|
202
|
+
:max="max"
|
|
203
|
+
:is-disabled="isDisabled"
|
|
204
|
+
:is-date-unavailable="isDateUnavailable"
|
|
205
|
+
:maximum-days="maximumDays"
|
|
206
|
+
:months="wide ? 2 : 1"
|
|
207
|
+
:locale="locale"
|
|
208
|
+
class="border-0 bg-transparent"
|
|
209
|
+
@update:model-value="pick"
|
|
210
|
+
/>
|
|
211
|
+
</PopoverContent>
|
|
212
|
+
</PopoverPortal>
|
|
213
|
+
</PopoverRoot>
|
|
214
|
+
<button
|
|
215
|
+
v-if="showClear"
|
|
216
|
+
type="button"
|
|
217
|
+
:aria-label="text.clear"
|
|
218
|
+
class="absolute top-1/2 right-[calc(0.75rem+15px+0.5rem)] flex -translate-y-1/2 items-center rounded-sm text-muted outline-none transition-colors hover:text-ink focus-visible:ring-2 focus-visible:ring-ring"
|
|
219
|
+
@click="emit('update:modelValue', undefined)"
|
|
220
|
+
>
|
|
221
|
+
<LpIcon name="lucide:x" :size="15" />
|
|
222
|
+
</button>
|
|
223
|
+
</div>
|
|
224
|
+
</template>
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { ref as sharedRef } from "vue"
|
|
2
|
+
import { ref as sharedRef, type Ref } from "vue"
|
|
3
3
|
|
|
4
|
-
// One pull at a time across every edge-open drawer on the page
|
|
5
|
-
|
|
4
|
+
// One pull at a time across every edge-open drawer on the page, pinned to a
|
|
5
|
+
// global symbol so a barrel and a deep import still share it.
|
|
6
|
+
const EDGE_KEY = Symbol.for("@leavepulse/ui:drawer-edge-owner")
|
|
7
|
+
type GlobalWithEdge = typeof globalThis & { [EDGE_KEY]?: Ref<symbol | null> }
|
|
8
|
+
const edgeOwner = ((globalThis as GlobalWithEdge)[EDGE_KEY] ??= sharedRef<symbol | null>(null))
|
|
6
9
|
</script>
|
|
7
10
|
|
|
8
11
|
<script setup lang="ts">
|
|
@@ -32,6 +35,7 @@ import {
|
|
|
32
35
|
import { computed, onBeforeUnmount, ref, useSlots, watch } from "vue"
|
|
33
36
|
import { CLOSE_ICON } from "./dropdown"
|
|
34
37
|
import { useGlass } from "../composables/useGlass"
|
|
38
|
+
import { useLabels } from "../composables/useLpConfig"
|
|
35
39
|
import LpIcon from "./LpIcon.vue"
|
|
36
40
|
import LpScrollArea from "./LpScrollArea.vue"
|
|
37
41
|
import { anyModalOpen, useModalLayer } from "./modalDepth"
|
|
@@ -109,6 +113,9 @@ const props = withDefaults(
|
|
|
109
113
|
* `provideGlass`, and without one it is off.
|
|
110
114
|
*/
|
|
111
115
|
glass?: boolean
|
|
116
|
+
/** Accessible name for a drawer without a visible `title`. */
|
|
117
|
+
ariaLabel?: string
|
|
118
|
+
labels?: Partial<{ close: string }>
|
|
112
119
|
}>(),
|
|
113
120
|
{
|
|
114
121
|
side: "right",
|
|
@@ -124,6 +131,7 @@ const props = withDefaults(
|
|
|
124
131
|
)
|
|
125
132
|
|
|
126
133
|
const frosted = useGlass(() => props.glass)
|
|
134
|
+
const text = useLabels("drawer", { close: "Close" }, () => props.labels)
|
|
127
135
|
|
|
128
136
|
const emit = defineEmits<{
|
|
129
137
|
(e: "update:open", value: boolean): void
|
|
@@ -148,7 +156,8 @@ const SIZES = { sm: 22, md: 28, lg: 36, xl: 48 } // rem along the main axis
|
|
|
148
156
|
* settings drawer) claimed those same rungs and the tie went to DOM order —
|
|
149
157
|
* the drawer, portalled later on reopen, covered the dialog it had opened.
|
|
150
158
|
*/
|
|
151
|
-
const {
|
|
159
|
+
const contentRef = ref<{ $el: HTMLElement } | null>(null)
|
|
160
|
+
const { claim, release, layer } = useModalLayer({ element: () => contentRef.value?.$el })
|
|
152
161
|
watch(() => props.open, (open) => (open ? claim() : release()), { immediate: true })
|
|
153
162
|
onBeforeUnmount(release)
|
|
154
163
|
|
|
@@ -179,36 +188,60 @@ const sizeStyle = computed(() => {
|
|
|
179
188
|
return isHorizontal.value ? { width: len } : { height: len }
|
|
180
189
|
})
|
|
181
190
|
|
|
191
|
+
// Resolve a CSS length to px against the viewport. Anything it cannot read
|
|
192
|
+
// (calc(), min()) comes back NaN for the caller to fall back on.
|
|
193
|
+
function toPx(css: string): number {
|
|
194
|
+
const n = Number.parseFloat(css)
|
|
195
|
+
if (css.endsWith("rem")) {
|
|
196
|
+
const root = typeof document === "undefined" ? 16 : Number.parseFloat(getComputedStyle(document.documentElement).fontSize) || 16
|
|
197
|
+
return n * root
|
|
198
|
+
}
|
|
199
|
+
if (css.endsWith("vw")) return (n / 100) * window.innerWidth
|
|
200
|
+
if (css.endsWith("vh")) return (n / 100) * window.innerHeight
|
|
201
|
+
if (css.endsWith("px") || /^[\d.]+$/.test(css.trim())) return n
|
|
202
|
+
return Number.NaN
|
|
203
|
+
}
|
|
204
|
+
|
|
182
205
|
// Drag the inner edge to resize. For a right drawer the panel grows as the
|
|
183
|
-
// pointer moves left (width = viewportRight − clientX); mirror for left.
|
|
206
|
+
// pointer moves left (width = viewportRight − clientX); mirror for left. The
|
|
207
|
+
// pointer is captured, so a release over an iframe or outside the window still
|
|
208
|
+
// ends the drag, and a cancelled touch ends it too.
|
|
209
|
+
let endResize: (() => void) | null = null
|
|
210
|
+
|
|
184
211
|
function startResize(e: PointerEvent) {
|
|
185
212
|
if (!props.resizable || !isHorizontal.value) return
|
|
186
213
|
e.preventDefault()
|
|
214
|
+
endResize?.()
|
|
215
|
+
const grip = e.currentTarget instanceof HTMLElement ? e.currentTarget : null
|
|
216
|
+
grip?.setPointerCapture(e.pointerId)
|
|
187
217
|
const fromRight = dir.value === "right"
|
|
188
|
-
const toPx = (css: string) => {
|
|
189
|
-
// Resolve rem/vw to px against the viewport for clamping.
|
|
190
|
-
if (css.endsWith("rem")) return Number.parseFloat(css) * 16
|
|
191
|
-
if (css.endsWith("vw")) return (Number.parseFloat(css) / 100) * window.innerWidth
|
|
192
|
-
return Number.parseFloat(css)
|
|
193
|
-
}
|
|
194
218
|
const min = toPx(props.minSize)
|
|
195
219
|
const max = toPx(props.maxSize)
|
|
196
220
|
const onMove = (ev: PointerEvent) => {
|
|
221
|
+
if (ev.pointerId !== e.pointerId) return
|
|
197
222
|
const raw = fromRight ? window.innerWidth - ev.clientX : ev.clientX
|
|
198
|
-
resizedPx.value = Math.max(min, Math.min(max, raw))
|
|
223
|
+
resizedPx.value = Math.max(Number.isNaN(min) ? 0 : min, Math.min(Number.isNaN(max) ? Infinity : max, raw))
|
|
199
224
|
}
|
|
200
|
-
const
|
|
225
|
+
const end = () => {
|
|
201
226
|
window.removeEventListener("pointermove", onMove)
|
|
202
|
-
window.removeEventListener("pointerup",
|
|
227
|
+
window.removeEventListener("pointerup", end)
|
|
228
|
+
window.removeEventListener("pointercancel", end)
|
|
229
|
+
grip?.removeEventListener("lostpointercapture", end)
|
|
203
230
|
document.body.style.userSelect = ""
|
|
204
231
|
document.body.style.cursor = ""
|
|
232
|
+
endResize = null
|
|
205
233
|
}
|
|
234
|
+
endResize = end
|
|
206
235
|
document.body.style.userSelect = "none"
|
|
207
236
|
document.body.style.cursor = "ew-resize"
|
|
208
237
|
window.addEventListener("pointermove", onMove)
|
|
209
|
-
window.addEventListener("pointerup",
|
|
238
|
+
window.addEventListener("pointerup", end)
|
|
239
|
+
window.addEventListener("pointercancel", end)
|
|
240
|
+
grip?.addEventListener("lostpointercapture", end)
|
|
210
241
|
}
|
|
211
242
|
|
|
243
|
+
onBeforeUnmount(() => endResize?.())
|
|
244
|
+
|
|
212
245
|
const slots = useSlots()
|
|
213
246
|
const hasHeader = computed(() => Boolean(props.title || slots.title))
|
|
214
247
|
|
|
@@ -281,9 +314,9 @@ watch(
|
|
|
281
314
|
// Resolve the panel's main-axis size in px to map drag distance → progress.
|
|
282
315
|
function panelPx(): number {
|
|
283
316
|
const vw = typeof window === "undefined" ? 0 : window.innerWidth
|
|
284
|
-
|
|
285
|
-
const cap = props.width ?
|
|
286
|
-
return Math.min(vw * 0.94, Number.isFinite(cap) ? cap :
|
|
317
|
+
const preset = toPx(`${SIZES[props.size]}rem`)
|
|
318
|
+
const cap = props.width ? toPx(props.width) : preset
|
|
319
|
+
return Math.min(vw * 0.94, Number.isFinite(cap) ? cap : preset)
|
|
287
320
|
}
|
|
288
321
|
|
|
289
322
|
function edgeEnabled(): boolean {
|
|
@@ -479,6 +512,8 @@ const previewStyle = computed(() => {
|
|
|
479
512
|
:class="{ 'lp-scrim--light': frosted, 'lp-scrim--nested': layer.nested }"
|
|
480
513
|
/>
|
|
481
514
|
<DrawerContent
|
|
515
|
+
ref="contentRef"
|
|
516
|
+
v-bind="description ? {} : { 'aria-describedby': undefined }"
|
|
482
517
|
:class="contentClass"
|
|
483
518
|
:style="[sizeStyle, { zIndex: layer.panel }]"
|
|
484
519
|
:data-vaul-animate="handingOff || skipOpenSlide ? 'false' : undefined"
|
|
@@ -498,6 +533,8 @@ const previewStyle = computed(() => {
|
|
|
498
533
|
/>
|
|
499
534
|
</div>
|
|
500
535
|
|
|
536
|
+
<DrawerTitle v-if="!hasHeader && ariaLabel" class="sr-only">{{ ariaLabel }}</DrawerTitle>
|
|
537
|
+
|
|
501
538
|
<!-- Drag handle: a pill the user grabs; vaul wires the drag to it. -->
|
|
502
539
|
<DrawerHandle
|
|
503
540
|
v-if="showHandle"
|
|
@@ -519,7 +556,7 @@ const previewStyle = computed(() => {
|
|
|
519
556
|
</div>
|
|
520
557
|
<DrawerClose
|
|
521
558
|
class="group flex shrink-0 items-center rounded-md p-1 text-muted outline-none transition-colors duration-[var(--duration-fast)] hover:text-ink focus-visible:ring-2 focus-visible:ring-ring"
|
|
522
|
-
aria-label="
|
|
559
|
+
:aria-label="text.close"
|
|
523
560
|
>
|
|
524
561
|
<LpIcon
|
|
525
562
|
name="lucide:x"
|
|
@@ -23,7 +23,7 @@ export default { inheritAttrs: false }
|
|
|
23
23
|
* invisible to a keyboard: nothing focusable, nothing that Enter activates, and
|
|
24
24
|
* the file dialog unreachable without a mouse.
|
|
25
25
|
*/
|
|
26
|
-
import { onBeforeUnmount, onMounted, ref } from "vue"
|
|
26
|
+
import { onBeforeUnmount, onMounted, ref, watch } from "vue"
|
|
27
27
|
import { useMergedAttrs } from "../composables/useMergedClass"
|
|
28
28
|
import { useReveal } from "../composables/useReveal"
|
|
29
29
|
import LpIcon from "./LpIcon.vue"
|
|
@@ -168,17 +168,34 @@ function onPicked(event: Event) {
|
|
|
168
168
|
}
|
|
169
169
|
|
|
170
170
|
function windowPaste(event: ClipboardEvent) {
|
|
171
|
-
|
|
171
|
+
// Already taken by the zone itself, which the paste bubbled up from.
|
|
172
|
+
if (props.disabled || event.defaultPrevented) return
|
|
172
173
|
const target = event.target as HTMLElement | null
|
|
173
174
|
// A paste aimed at somewhere you can type belongs to that thing.
|
|
174
175
|
if (target?.closest("input, textarea, [contenteditable]")) return
|
|
175
176
|
onPaste(event)
|
|
176
177
|
}
|
|
177
178
|
|
|
179
|
+
let listening = false
|
|
180
|
+
function listen(on: boolean) {
|
|
181
|
+
if (on === listening || typeof window === "undefined") return
|
|
182
|
+
listening = on
|
|
183
|
+
if (on) window.addEventListener("paste", windowPaste)
|
|
184
|
+
else window.removeEventListener("paste", windowPaste)
|
|
185
|
+
}
|
|
186
|
+
let mounted = false
|
|
178
187
|
onMounted(() => {
|
|
179
|
-
|
|
188
|
+
mounted = true
|
|
189
|
+
listen(props.pasteTarget)
|
|
190
|
+
})
|
|
191
|
+
watch(
|
|
192
|
+
() => props.pasteTarget,
|
|
193
|
+
(on) => mounted && listen(on),
|
|
194
|
+
)
|
|
195
|
+
onBeforeUnmount(() => {
|
|
196
|
+
mounted = false
|
|
197
|
+
listen(false)
|
|
180
198
|
})
|
|
181
|
-
onBeforeUnmount(() => window.removeEventListener("paste", windowPaste))
|
|
182
199
|
|
|
183
200
|
defineExpose({ browse: () => input.value?.click() })
|
|
184
201
|
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/*
|
|
3
|
+
* The floating note from useFieldNotice: anchored under the nearest
|
|
4
|
+
* `relative` box, over whatever sits below it (usually the hint), so it never
|
|
5
|
+
* moves the layout. It slides in, slides out, and nudges sideways when the
|
|
6
|
+
* same note is raised again while showing.
|
|
7
|
+
*/
|
|
8
|
+
import { ref, watch } from "vue"
|
|
9
|
+
import { prefersReducedMotion } from "../composables/easing"
|
|
10
|
+
import type { FieldNotice } from "../composables/useFieldNotice"
|
|
11
|
+
import LpIcon from "./LpIcon.vue"
|
|
12
|
+
|
|
13
|
+
const props = defineProps<{
|
|
14
|
+
notice: FieldNotice
|
|
15
|
+
id?: string
|
|
16
|
+
}>()
|
|
17
|
+
|
|
18
|
+
const el = ref<HTMLElement | null>(null)
|
|
19
|
+
|
|
20
|
+
watch(
|
|
21
|
+
() => props.notice.seq.value,
|
|
22
|
+
(_, before) => {
|
|
23
|
+
if (before === undefined || !el.value || prefersReducedMotion()) return
|
|
24
|
+
el.value.animate(
|
|
25
|
+
[
|
|
26
|
+
{ transform: "translateX(0)" },
|
|
27
|
+
{ transform: "translateX(-3px)" },
|
|
28
|
+
{ transform: "translateX(3px)" },
|
|
29
|
+
{ transform: "translateX(0)" },
|
|
30
|
+
],
|
|
31
|
+
{ duration: 240, easing: "ease-out" },
|
|
32
|
+
)
|
|
33
|
+
},
|
|
34
|
+
)
|
|
35
|
+
</script>
|
|
36
|
+
|
|
37
|
+
<template>
|
|
38
|
+
<Transition
|
|
39
|
+
enter-active-class="transition-[opacity,translate] duration-fast ease-[var(--ease-emphasized)] motion-reduce:transition-none"
|
|
40
|
+
leave-active-class="transition-[opacity,translate] duration-fast ease-out motion-reduce:transition-none"
|
|
41
|
+
enter-from-class="-translate-y-1 opacity-0"
|
|
42
|
+
leave-to-class="-translate-y-1 opacity-0"
|
|
43
|
+
>
|
|
44
|
+
<div
|
|
45
|
+
v-if="notice.message.value"
|
|
46
|
+
:id="id"
|
|
47
|
+
ref="el"
|
|
48
|
+
role="status"
|
|
49
|
+
class="pointer-events-none absolute top-full left-0 z-20 mt-1.5 flex max-w-full items-center gap-1.5 rounded-control border px-2 py-1 text-xs shadow-sm"
|
|
50
|
+
:class="
|
|
51
|
+
notice.tone.value === 'danger'
|
|
52
|
+
? 'border-danger/40 bg-surface-raised bg-[linear-gradient(var(--color-danger-soft),var(--color-danger-soft))] text-danger'
|
|
53
|
+
: 'border-line bg-surface-raised text-ink'
|
|
54
|
+
"
|
|
55
|
+
>
|
|
56
|
+
<LpIcon
|
|
57
|
+
:name="notice.tone.value === 'danger' ? 'lucide:circle-alert' : 'lucide:info'"
|
|
58
|
+
:size="13"
|
|
59
|
+
class="shrink-0"
|
|
60
|
+
:class="notice.tone.value === 'danger' ? '' : 'text-muted'"
|
|
61
|
+
/>
|
|
62
|
+
<span class="truncate">{{ notice.message.value }}</span>
|
|
63
|
+
</div>
|
|
64
|
+
</Transition>
|
|
65
|
+
</template>
|
|
@@ -38,10 +38,21 @@ import LpEmptyState from "./LpEmptyState.vue"
|
|
|
38
38
|
import LpFileTreeNode from "./LpFileTreeNode.vue"
|
|
39
39
|
import LpScrollArea from "./LpScrollArea.vue"
|
|
40
40
|
import { useMergedAttrs } from "../composables/useMergedClass"
|
|
41
|
+
import { useLabels } from "../composables/useLpConfig"
|
|
41
42
|
|
|
42
43
|
export type { FileNode } from "./fileTree"
|
|
43
44
|
|
|
44
45
|
/** Rolled-up stats for the ticked entries — what a backup picker summarises. */
|
|
46
|
+
export interface FileTreeLabels {
|
|
47
|
+
[key: string]: string
|
|
48
|
+
empty: string
|
|
49
|
+
emptyDescription: string
|
|
50
|
+
file: string
|
|
51
|
+
files: string
|
|
52
|
+
folder: string
|
|
53
|
+
folders: string
|
|
54
|
+
}
|
|
55
|
+
|
|
45
56
|
export interface FileTreeSummary {
|
|
46
57
|
/** Ticked files (directories excluded — they're containers, not payload). */
|
|
47
58
|
files: number
|
|
@@ -84,6 +95,7 @@ const props = withDefaults(
|
|
|
84
95
|
/** Empty-state copy when `nodes` is empty. */
|
|
85
96
|
emptyLabel?: string
|
|
86
97
|
emptyDescription?: string
|
|
98
|
+
labels?: Partial<FileTreeLabels>
|
|
87
99
|
}>(),
|
|
88
100
|
{
|
|
89
101
|
sort: true,
|
|
@@ -93,8 +105,6 @@ const props = withDefaults(
|
|
|
93
105
|
showModified: false,
|
|
94
106
|
loading: false,
|
|
95
107
|
skeletonRows: 8,
|
|
96
|
-
emptyLabel: "No files",
|
|
97
|
-
emptyDescription: "This folder is empty.",
|
|
98
108
|
},
|
|
99
109
|
)
|
|
100
110
|
|
|
@@ -131,6 +141,19 @@ watch(
|
|
|
131
141
|
},
|
|
132
142
|
)
|
|
133
143
|
|
|
144
|
+
const text = useLabels<FileTreeLabels>(
|
|
145
|
+
"fileTree",
|
|
146
|
+
{
|
|
147
|
+
empty: "No files",
|
|
148
|
+
emptyDescription: "This folder is empty.",
|
|
149
|
+
file: "file",
|
|
150
|
+
files: "files",
|
|
151
|
+
folder: "folder",
|
|
152
|
+
folders: "folders",
|
|
153
|
+
},
|
|
154
|
+
() => props.labels,
|
|
155
|
+
)
|
|
156
|
+
|
|
134
157
|
const loadingSet = computed(() => new Set(props.loadingIds ?? []))
|
|
135
158
|
|
|
136
159
|
// Same controlled/uncontrolled deal as `expanded`.
|
|
@@ -229,7 +252,7 @@ const summary = computed<FileTreeSummary>(() => {
|
|
|
229
252
|
}
|
|
230
253
|
})
|
|
231
254
|
|
|
232
|
-
watch(summary, (value) => emit("summary", value), {
|
|
255
|
+
watch(summary, (value) => emit("summary", value), { immediate: true })
|
|
233
256
|
|
|
234
257
|
function setChecked(next: Set<string>) {
|
|
235
258
|
checkedIds.value = next
|
|
@@ -350,6 +373,9 @@ function expand(node: FileNode) {
|
|
|
350
373
|
|
|
351
374
|
function collapse(node: FileNode) {
|
|
352
375
|
if (!openIds.value.has(node.id)) return
|
|
376
|
+
// A fetch that failed left `children` unset; collapsing lets the next open
|
|
377
|
+
// ask again instead of showing an empty folder forever.
|
|
378
|
+
if (node.children === undefined && !loadingSet.value.has(node.id)) requested.delete(node.id)
|
|
353
379
|
const next = new Set(openIds.value)
|
|
354
380
|
next.delete(node.id)
|
|
355
381
|
setExpanded(next)
|
|
@@ -506,8 +532,8 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
|
|
|
506
532
|
<LpEmptyState
|
|
507
533
|
v-else-if="!roots.length"
|
|
508
534
|
icon="lucide:folder-search"
|
|
509
|
-
:title="emptyLabel"
|
|
510
|
-
:description="emptyDescription"
|
|
535
|
+
:title="emptyLabel ?? text.empty"
|
|
536
|
+
:description="emptyDescription ?? text.emptyDescription"
|
|
511
537
|
/>
|
|
512
538
|
|
|
513
539
|
<!-- h-full so the tree fills whatever box the caller gave it and the scroll
|
|
@@ -558,9 +584,9 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
|
|
|
558
584
|
class="shrink-0 border-t border-line px-2 py-1.5 text-xs text-muted"
|
|
559
585
|
>
|
|
560
586
|
<slot name="summary" v-bind="summary">
|
|
561
|
-
{{ summary.files }} {{ summary.files === 1 ?
|
|
587
|
+
{{ summary.files }} {{ summary.files === 1 ? text.file : text.files }}<template
|
|
562
588
|
v-if="summary.dirs"
|
|
563
|
-
>, {{ summary.dirs }} {{ summary.dirs === 1 ?
|
|
589
|
+
>, {{ summary.dirs }} {{ summary.dirs === 1 ? text.folder : text.folders }}</template>
|
|
564
590
|
<template v-if="summary.bytes !== undefined"> · {{ summary.sizeLabel }}</template>
|
|
565
591
|
</slot>
|
|
566
592
|
</div>
|