@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
|
@@ -1,7 +1,13 @@
|
|
|
1
|
-
import { shallowReactive, computed, toValue, onMounted, onBeforeUnmount } from "vue";
|
|
1
|
+
import { shallowReactive, ref, computed, toValue, getCurrentInstance, onMounted, onBeforeUnmount } from "vue";
|
|
2
|
+
import { topModalElement } from "../components/modalDepth.js";
|
|
2
3
|
const isAppleKeyboard = typeof navigator !== "undefined" && /Mac|iPhone|iPad|iPod/.test(navigator.platform || "");
|
|
3
|
-
function
|
|
4
|
-
|
|
4
|
+
function useAppleKeyboard() {
|
|
5
|
+
const apple = ref(false);
|
|
6
|
+
onMounted(() => apple.value = isAppleKeyboard);
|
|
7
|
+
return apple;
|
|
8
|
+
}
|
|
9
|
+
function appleModifierLabel(key, apple = isAppleKeyboard) {
|
|
10
|
+
if (!apple) return key;
|
|
5
11
|
if (key === "Ctrl") return "⌘";
|
|
6
12
|
if (key === "Alt") return "⌥";
|
|
7
13
|
return key;
|
|
@@ -24,59 +30,182 @@ function isTextEntry(target) {
|
|
|
24
30
|
}
|
|
25
31
|
return false;
|
|
26
32
|
}
|
|
27
|
-
|
|
33
|
+
const MODIFIER_KEYS = /* @__PURE__ */ new Set(["control", "meta", "shift", "alt"]);
|
|
34
|
+
function matchesHotkey(event, binding) {
|
|
35
|
+
if (binding.key === void 0) return false;
|
|
36
|
+
const key = binding.key.toLowerCase();
|
|
28
37
|
const ctrlHeld = event.ctrlKey || event.metaKey;
|
|
29
|
-
|
|
30
|
-
if (
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
38
|
+
const wantsCtrl = Boolean(binding.ctrl) || key === "control" || key === "meta";
|
|
39
|
+
if (ctrlHeld !== wantsCtrl) return false;
|
|
40
|
+
const symbol = key.length === 1 && key.toLowerCase() === key.toUpperCase();
|
|
41
|
+
const shiftFree = key === "shift" || binding.shift === void 0 && symbol;
|
|
42
|
+
if (!shiftFree && event.shiftKey !== Boolean(binding.shift)) return false;
|
|
43
|
+
if (key !== "alt" && event.altKey !== Boolean(binding.alt)) return false;
|
|
44
|
+
if (MODIFIER_KEYS.has(key)) return event.key.toLowerCase() === key;
|
|
45
|
+
return event.key.toLowerCase() === key || binding.code !== void 0 && event.code === binding.code;
|
|
46
|
+
}
|
|
47
|
+
function hotkeySteps(binding) {
|
|
48
|
+
const raw = binding.sequence;
|
|
49
|
+
if (raw === void 0) {
|
|
50
|
+
if (binding.key === void 0) return [];
|
|
51
|
+
const { key, code, ctrl, shift, alt } = binding;
|
|
52
|
+
return [{ key, code, ctrl, shift, alt }];
|
|
53
|
+
}
|
|
54
|
+
const list = typeof raw === "string" ? raw.trim().split(/\s+/) : raw;
|
|
55
|
+
return list.map((step) => typeof step === "string" ? { key: step } : step);
|
|
56
|
+
}
|
|
57
|
+
function sequenceProgress(presses, binding) {
|
|
58
|
+
const steps = hotkeySteps(binding);
|
|
59
|
+
if (!steps.length || presses.length > steps.length) return null;
|
|
60
|
+
for (let i = 0; i < presses.length; i++) {
|
|
61
|
+
if (!matchesHotkey(presses[i], steps[i])) return null;
|
|
62
|
+
}
|
|
63
|
+
return presses.length === steps.length ? "full" : "prefix";
|
|
64
|
+
}
|
|
65
|
+
const STATE_KEY = /* @__PURE__ */ Symbol.for("@leavepulse/ui:hotkeys");
|
|
66
|
+
const g = globalThis;
|
|
67
|
+
const state = g[STATE_KEY] ??= {
|
|
68
|
+
mounted: shallowReactive(/* @__PURE__ */ new Set()),
|
|
69
|
+
order: 0,
|
|
70
|
+
listening: false
|
|
71
|
+
};
|
|
72
|
+
const mounted = state.mounted;
|
|
37
73
|
function inScope(target, scope) {
|
|
38
74
|
const el = toValue(scope);
|
|
39
75
|
if (!el) return true;
|
|
40
76
|
const node = target instanceof Node ? target : null;
|
|
41
77
|
return !!node && (el === node || el.contains(node));
|
|
42
78
|
}
|
|
43
|
-
function
|
|
44
|
-
|
|
79
|
+
function topLayer() {
|
|
80
|
+
const layers = document.querySelectorAll("[data-dismissable-layer]");
|
|
81
|
+
return layers[layers.length - 1] ?? null;
|
|
82
|
+
}
|
|
83
|
+
function insideOf(entry, layer) {
|
|
84
|
+
const scope = toValue(entry.scope);
|
|
85
|
+
const node = scope ?? entry.host();
|
|
86
|
+
return !!node && layer.contains(node);
|
|
87
|
+
}
|
|
88
|
+
const DEFAULT_TIMEOUT = 1e3;
|
|
89
|
+
const pressed = [];
|
|
90
|
+
let held = [];
|
|
91
|
+
let holdTimer;
|
|
92
|
+
const pendingKeys = ref([]);
|
|
93
|
+
const pendingHotkey = computed(() => pendingKeys.value);
|
|
94
|
+
function snapshot(event) {
|
|
95
|
+
const { key, code, ctrlKey, metaKey, shiftKey, altKey } = event;
|
|
96
|
+
return { key, code, ctrlKey, metaKey, shiftKey, altKey };
|
|
97
|
+
}
|
|
98
|
+
function eligible(event) {
|
|
45
99
|
const inTextEntry = isTextEntry(event.target);
|
|
100
|
+
const blocker = event.key === "Escape" ? topLayer() : topModalElement();
|
|
46
101
|
const entries = [...mounted].sort(
|
|
47
102
|
(a, b) => Number(toValue(b.priority) || 0) - Number(toValue(a.priority) || 0) || b.order - a.order
|
|
48
103
|
);
|
|
104
|
+
const out = [];
|
|
49
105
|
for (const entry of entries) {
|
|
50
106
|
if (toValue(entry.enabled) === false || !inScope(event.target, entry.scope)) continue;
|
|
107
|
+
const covered = !!blocker && !insideOf(entry, blocker);
|
|
51
108
|
for (const binding of entry.read()) {
|
|
52
109
|
if (inTextEntry && !binding.allowInInput) continue;
|
|
53
|
-
if (
|
|
54
|
-
if (binding.
|
|
110
|
+
if (event.repeat && binding.repeat === false) continue;
|
|
111
|
+
if (covered && !binding.overLayers) continue;
|
|
112
|
+
if (binding.when && !binding.when(event)) continue;
|
|
113
|
+
out.push(binding);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return out;
|
|
117
|
+
}
|
|
118
|
+
function run(candidates) {
|
|
119
|
+
for (const { binding, event } of candidates) {
|
|
120
|
+
if (binding.handler(event) !== false) return true;
|
|
121
|
+
}
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
function resetSequence() {
|
|
125
|
+
clearTimeout(holdTimer);
|
|
126
|
+
holdTimer = void 0;
|
|
127
|
+
pressed.length = 0;
|
|
128
|
+
held = [];
|
|
129
|
+
pendingKeys.value = [];
|
|
130
|
+
}
|
|
131
|
+
function flushHeld() {
|
|
132
|
+
const waiting = held;
|
|
133
|
+
resetSequence();
|
|
134
|
+
run(waiting);
|
|
135
|
+
}
|
|
136
|
+
function onKeydown(event) {
|
|
137
|
+
if (event.isComposing || event.defaultPrevented) return;
|
|
138
|
+
if (pressed.length && MODIFIER_KEYS.has(event.key.toLowerCase())) return;
|
|
139
|
+
if (pressed.length && event.key === "Escape") {
|
|
140
|
+
resetSequence();
|
|
141
|
+
}
|
|
142
|
+
const presses = [...pressed, snapshot(event)];
|
|
143
|
+
const bindings = eligible(event);
|
|
144
|
+
const full = [];
|
|
145
|
+
let waitFor = 0;
|
|
146
|
+
for (const binding of bindings) {
|
|
147
|
+
const progress = sequenceProgress(presses, binding);
|
|
148
|
+
if (progress === "full") full.push({ binding, event });
|
|
149
|
+
else if (progress === "prefix") waitFor = Math.max(waitFor, binding.timeout ?? DEFAULT_TIMEOUT);
|
|
150
|
+
}
|
|
151
|
+
if (waitFor) {
|
|
152
|
+
clearTimeout(holdTimer);
|
|
153
|
+
pressed.push(snapshot(event));
|
|
154
|
+
held = full;
|
|
155
|
+
pendingKeys.value = pressed.map(pressLabel);
|
|
156
|
+
holdTimer = setTimeout(flushHeld, waitFor);
|
|
157
|
+
event.preventDefault();
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
if (full.length) {
|
|
161
|
+
resetSequence();
|
|
162
|
+
if (run(full)) {
|
|
55
163
|
event.preventDefault();
|
|
56
164
|
return;
|
|
57
165
|
}
|
|
58
166
|
}
|
|
167
|
+
if (pressed.length) {
|
|
168
|
+
flushHeld();
|
|
169
|
+
onKeydown(event);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
function pressLabel(press) {
|
|
173
|
+
return chordOf({
|
|
174
|
+
key: press.key,
|
|
175
|
+
ctrl: press.ctrlKey || press.metaKey,
|
|
176
|
+
alt: press.altKey,
|
|
177
|
+
shift: press.shiftKey && press.key.length !== 1
|
|
178
|
+
});
|
|
59
179
|
}
|
|
60
180
|
function useHotkeys(bindings, options = {}) {
|
|
181
|
+
const instance = getCurrentInstance();
|
|
61
182
|
const entry = {
|
|
62
183
|
read: () => toValue(bindings),
|
|
63
184
|
scope: options.scope,
|
|
64
185
|
enabled: options.enabled,
|
|
65
186
|
priority: options.priority,
|
|
66
|
-
order: ++
|
|
187
|
+
order: ++state.order,
|
|
188
|
+
host: () => {
|
|
189
|
+
const el = instance?.vnode.el;
|
|
190
|
+
return el instanceof Node ? el : null;
|
|
191
|
+
}
|
|
67
192
|
};
|
|
68
193
|
onMounted(() => {
|
|
69
194
|
mounted.add(entry);
|
|
70
|
-
|
|
195
|
+
warnConflicts();
|
|
196
|
+
if (!state.listening) {
|
|
71
197
|
window.addEventListener("keydown", onKeydown);
|
|
72
|
-
|
|
198
|
+
window.addEventListener("blur", resetSequence);
|
|
199
|
+
state.listening = true;
|
|
73
200
|
}
|
|
74
201
|
});
|
|
75
202
|
onBeforeUnmount(() => {
|
|
76
203
|
mounted.delete(entry);
|
|
77
|
-
if (!mounted.size && listening) {
|
|
204
|
+
if (!mounted.size && state.listening) {
|
|
78
205
|
window.removeEventListener("keydown", onKeydown);
|
|
79
|
-
|
|
206
|
+
window.removeEventListener("blur", resetSequence);
|
|
207
|
+
state.listening = false;
|
|
208
|
+
resetSequence();
|
|
80
209
|
}
|
|
81
210
|
});
|
|
82
211
|
}
|
|
@@ -92,20 +221,82 @@ const KEY_NAMES = {
|
|
|
92
221
|
arrowleft: "←",
|
|
93
222
|
arrowright: "→"
|
|
94
223
|
};
|
|
224
|
+
function chordOf(step) {
|
|
225
|
+
const key = step.key.toLowerCase();
|
|
226
|
+
const name = KEY_NAMES[key] ?? (key.length === 1 || /^f\d+$/.test(key) ? key.toUpperCase() : step.key);
|
|
227
|
+
return [step.ctrl && "Ctrl", step.alt && "Alt", step.shift && "Shift", name].filter(Boolean).join("+");
|
|
228
|
+
}
|
|
95
229
|
function comboOf(binding) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
230
|
+
return hotkeySteps(binding).map(chordOf).join(" ");
|
|
231
|
+
}
|
|
232
|
+
function signatureOf(binding) {
|
|
233
|
+
return hotkeySteps(binding).map((step) => {
|
|
234
|
+
const key = step.key.toLowerCase();
|
|
235
|
+
const symbol = key.length === 1 && key === key.toUpperCase();
|
|
236
|
+
const shift = step.shift === void 0 && symbol ? "*" : String(Boolean(step.shift));
|
|
237
|
+
return `${Boolean(step.ctrl)}:${Boolean(step.alt)}:${shift}:${key}`;
|
|
238
|
+
}).join(" ");
|
|
239
|
+
}
|
|
240
|
+
function findHotkeyConflicts(groups) {
|
|
241
|
+
const scopeIds = /* @__PURE__ */ new Map();
|
|
242
|
+
const seen = /* @__PURE__ */ new Map();
|
|
243
|
+
groups.forEach((group, owner) => {
|
|
244
|
+
if (!scopeIds.has(group.scope)) scopeIds.set(group.scope, scopeIds.size);
|
|
245
|
+
for (const binding of group.bindings) {
|
|
246
|
+
if (binding.when || !hotkeySteps(binding).length) continue;
|
|
247
|
+
const id = `${group.priority}|${scopeIds.get(group.scope)}|${signatureOf(binding)}`;
|
|
248
|
+
const slot = seen.get(id) ?? {
|
|
249
|
+
combo: binding.help?.combo ?? comboOf(binding),
|
|
250
|
+
labels: [],
|
|
251
|
+
owners: /* @__PURE__ */ new Set(),
|
|
252
|
+
priority: group.priority
|
|
253
|
+
};
|
|
254
|
+
slot.owners.add(owner);
|
|
255
|
+
if (binding.help && !slot.labels.includes(binding.help.label)) slot.labels.push(binding.help.label);
|
|
256
|
+
seen.set(id, slot);
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
return [...seen.values()].filter((slot) => slot.owners.size > 1).map(({ combo, labels, priority }) => ({ combo, labels, priority }));
|
|
260
|
+
}
|
|
261
|
+
const hotkeyConflicts = computed(
|
|
262
|
+
() => findHotkeyConflicts(
|
|
263
|
+
[...mounted].filter((entry) => toValue(entry.enabled) !== false).map((entry) => ({
|
|
264
|
+
bindings: entry.read(),
|
|
265
|
+
priority: Number(toValue(entry.priority) || 0),
|
|
266
|
+
scope: toValue(entry.scope) ?? null
|
|
267
|
+
}))
|
|
268
|
+
)
|
|
269
|
+
);
|
|
270
|
+
const warned = /* @__PURE__ */ new Set();
|
|
271
|
+
function isDev() {
|
|
272
|
+
try {
|
|
273
|
+
return process.env.NODE_ENV !== "production";
|
|
274
|
+
} catch {
|
|
275
|
+
return false;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
function warnConflicts() {
|
|
279
|
+
if (!isDev()) return;
|
|
280
|
+
for (const conflict of hotkeyConflicts.value) {
|
|
281
|
+
const id = `${conflict.priority}|${conflict.combo}`;
|
|
282
|
+
if (warned.has(id)) continue;
|
|
283
|
+
warned.add(id);
|
|
284
|
+
console.warn(
|
|
285
|
+
`[@leavepulse/ui] ${conflict.combo} is bound more than once at priority ${conflict.priority}` + (conflict.labels.length ? ` (${conflict.labels.join(", ")})` : "") + "; only the most recently mounted one runs unless it declines."
|
|
286
|
+
);
|
|
287
|
+
}
|
|
99
288
|
}
|
|
100
289
|
const activeShortcuts = computed(() => {
|
|
101
290
|
const groups = /* @__PURE__ */ new Map();
|
|
291
|
+
const clashing = new Set(hotkeyConflicts.value.map((c) => c.combo));
|
|
102
292
|
for (const entry of mounted) {
|
|
103
293
|
if (toValue(entry.enabled) === false) continue;
|
|
104
294
|
for (const binding of entry.read()) {
|
|
105
295
|
if (!binding.help) continue;
|
|
106
296
|
const combo = binding.help.combo ?? comboOf(binding);
|
|
107
297
|
const entries = groups.get(binding.help.group) ?? [];
|
|
108
|
-
|
|
298
|
+
const conflict = clashing.has(combo) || void 0;
|
|
299
|
+
if (!entries.some((e) => e.combo === combo)) entries.push({ combo, label: binding.help.label, conflict });
|
|
109
300
|
groups.set(binding.help.group, entries);
|
|
110
301
|
}
|
|
111
302
|
}
|
|
@@ -127,7 +318,14 @@ function mergeShortcutGroups(...lists) {
|
|
|
127
318
|
export {
|
|
128
319
|
activeShortcuts,
|
|
129
320
|
appleModifierLabel,
|
|
321
|
+
findHotkeyConflicts,
|
|
322
|
+
hotkeyConflicts,
|
|
323
|
+
hotkeySteps,
|
|
130
324
|
isAppleKeyboard,
|
|
325
|
+
matchesHotkey,
|
|
131
326
|
mergeShortcutGroups,
|
|
327
|
+
pendingHotkey,
|
|
328
|
+
sequenceProgress,
|
|
329
|
+
useAppleKeyboard,
|
|
132
330
|
useHotkeys
|
|
133
331
|
};
|
|
@@ -5,9 +5,26 @@ export interface UseInputFilterOptions {
|
|
|
5
5
|
/** RegExp/string the full value must match to be valid. Validation only. */
|
|
6
6
|
pattern?: MaybeRefOrGetter<RegExp | string | undefined>;
|
|
7
7
|
}
|
|
8
|
+
/**
|
|
9
|
+
* Anchor a pattern to the whole string, like HTML's `pattern` attribute. The
|
|
10
|
+
* source is wrapped, never edited: anchors the caller wrote stay valid inside
|
|
11
|
+
* the group, while trimming a trailing `$` broke an escaped `\$` into an
|
|
12
|
+
* unterminated group.
|
|
13
|
+
*/
|
|
14
|
+
export declare function anchorPattern(p: RegExp | string): RegExp;
|
|
15
|
+
/**
|
|
16
|
+
* `text` with every disallowed character removed, and where `caret` lands once
|
|
17
|
+
* the characters before it that were removed are gone.
|
|
18
|
+
*/
|
|
19
|
+
export declare function stripDisallowed(text: string, charRe: RegExp, caret?: number): {
|
|
20
|
+
text: string;
|
|
21
|
+
caret: number;
|
|
22
|
+
};
|
|
8
23
|
export declare function useInputFilter(options?: UseInputFilterOptions): {
|
|
9
24
|
isInvalid: (value: string | undefined) => boolean;
|
|
10
25
|
onBeforeInput: (event: InputEvent) => void;
|
|
26
|
+
onInput: (event: Event) => void;
|
|
27
|
+
onCompositionEnd: (event: CompositionEvent) => void;
|
|
11
28
|
onPaste: (event: ClipboardEvent) => void;
|
|
12
29
|
patternRe: import("vue").ComputedRef<RegExp | undefined>;
|
|
13
30
|
restrict: import("vue").ComputedRef<RegExp | undefined>;
|
|
@@ -1,23 +1,38 @@
|
|
|
1
1
|
import { computed, toValue } from "vue";
|
|
2
|
-
function
|
|
3
|
-
if (p instanceof RegExp) {
|
|
4
|
-
const src = p.source.replace(/^\^/, "").replace(/\$$/, "");
|
|
5
|
-
return new RegExp(`^(?:${src})$`, p.flags.replace(/[gy]/g, ""));
|
|
6
|
-
}
|
|
2
|
+
function anchorPattern(p) {
|
|
3
|
+
if (p instanceof RegExp) return new RegExp(`^(?:${p.source})$`, p.flags.replace(/[gy]/g, ""));
|
|
7
4
|
return new RegExp(`^(?:${p})$`);
|
|
8
5
|
}
|
|
9
|
-
function
|
|
6
|
+
function charTester(charRe) {
|
|
10
7
|
const re = new RegExp(charRe.source, charRe.flags.replace(/[gy]/g, ""));
|
|
8
|
+
return (ch) => re.test(ch);
|
|
9
|
+
}
|
|
10
|
+
function allAllowed(text, charRe) {
|
|
11
|
+
const ok = charTester(charRe);
|
|
11
12
|
for (const ch of text) {
|
|
12
|
-
if (!
|
|
13
|
+
if (!ok(ch)) return false;
|
|
13
14
|
}
|
|
14
15
|
return true;
|
|
15
16
|
}
|
|
17
|
+
function stripDisallowed(text, charRe, caret = text.length) {
|
|
18
|
+
const ok = charTester(charRe);
|
|
19
|
+
let kept = "";
|
|
20
|
+
let at = 0;
|
|
21
|
+
let offset = 0;
|
|
22
|
+
for (const ch of text) {
|
|
23
|
+
if (ok(ch)) {
|
|
24
|
+
kept += ch;
|
|
25
|
+
if (offset < caret) at += ch.length;
|
|
26
|
+
}
|
|
27
|
+
offset += ch.length;
|
|
28
|
+
}
|
|
29
|
+
return { text: kept, caret: at };
|
|
30
|
+
}
|
|
16
31
|
function useInputFilter(options = {}) {
|
|
17
32
|
const restrict = computed(() => toValue(options.restrict));
|
|
18
33
|
const patternRe = computed(() => {
|
|
19
34
|
const p = toValue(options.pattern);
|
|
20
|
-
return p === void 0 ? void 0 :
|
|
35
|
+
return p === void 0 ? void 0 : anchorPattern(p);
|
|
21
36
|
});
|
|
22
37
|
function isInvalid(value) {
|
|
23
38
|
const re = patternRe.value;
|
|
@@ -27,18 +42,40 @@ function useInputFilter(options = {}) {
|
|
|
27
42
|
function onBeforeInput(event) {
|
|
28
43
|
const re = restrict.value;
|
|
29
44
|
if (!re || event.isComposing) return;
|
|
30
|
-
const data = event.data;
|
|
45
|
+
const data = event.data ?? event.dataTransfer?.getData("text") ?? null;
|
|
31
46
|
if (data == null) return;
|
|
32
47
|
if (!allAllowed(data, re)) event.preventDefault();
|
|
33
48
|
}
|
|
49
|
+
function sanitize(target) {
|
|
50
|
+
const re = restrict.value;
|
|
51
|
+
if (!re) return false;
|
|
52
|
+
if (!(target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement)) return false;
|
|
53
|
+
const { text, caret } = stripDisallowed(target.value, re, target.selectionStart ?? target.value.length);
|
|
54
|
+
if (text === target.value) return false;
|
|
55
|
+
target.value = text;
|
|
56
|
+
try {
|
|
57
|
+
target.setSelectionRange(caret, caret);
|
|
58
|
+
} catch {
|
|
59
|
+
}
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
function onInput(event) {
|
|
63
|
+
if (event.isComposing) return;
|
|
64
|
+
sanitize(event.target);
|
|
65
|
+
}
|
|
66
|
+
function onCompositionEnd(event) {
|
|
67
|
+
if (sanitize(event.target)) event.target?.dispatchEvent(new Event("input", { bubbles: true }));
|
|
68
|
+
}
|
|
34
69
|
function onPaste(event) {
|
|
35
70
|
const re = restrict.value;
|
|
36
71
|
if (!re) return;
|
|
37
72
|
const text = event.clipboardData?.getData("text") ?? "";
|
|
38
73
|
if (text && !allAllowed(text, re)) event.preventDefault();
|
|
39
74
|
}
|
|
40
|
-
return { isInvalid, onBeforeInput, onPaste, patternRe, restrict };
|
|
75
|
+
return { isInvalid, onBeforeInput, onInput, onCompositionEnd, onPaste, patternRe, restrict };
|
|
41
76
|
}
|
|
42
77
|
export {
|
|
78
|
+
anchorPattern,
|
|
79
|
+
stripDisallowed,
|
|
43
80
|
useInputFilter
|
|
44
81
|
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { type MaybeRefOrGetter } from "vue";
|
|
2
|
+
export type MaskToken = RegExp | {
|
|
3
|
+
pattern: RegExp;
|
|
4
|
+
transform?: (ch: string) => string;
|
|
5
|
+
};
|
|
6
|
+
export type MaskTokens = Record<string, MaskToken>;
|
|
7
|
+
export type MaskSpec = string | readonly string[] | ((raw: string) => string);
|
|
8
|
+
export declare const DEFAULT_MASK_TOKENS: MaskTokens;
|
|
9
|
+
type Slot = {
|
|
10
|
+
literal: string;
|
|
11
|
+
} | {
|
|
12
|
+
test: (ch: string) => boolean;
|
|
13
|
+
transform: (ch: string) => string;
|
|
14
|
+
};
|
|
15
|
+
export interface MaskResult {
|
|
16
|
+
masked: string;
|
|
17
|
+
raw: string;
|
|
18
|
+
/** Caret offset in `masked`. */
|
|
19
|
+
caret: number;
|
|
20
|
+
/** Every token of the mask is filled. */
|
|
21
|
+
complete: boolean;
|
|
22
|
+
}
|
|
23
|
+
export interface MaskOptions {
|
|
24
|
+
mask: MaskSpec;
|
|
25
|
+
tokens?: MaskTokens;
|
|
26
|
+
/**
|
|
27
|
+
* Caret position: an offset into `input`, or with `fromRaw` the number of raw
|
|
28
|
+
* characters before it. Defaults to the end.
|
|
29
|
+
*/
|
|
30
|
+
caret?: number;
|
|
31
|
+
/** `input` holds raw characters only; literals in it are never consumed as mask literals. */
|
|
32
|
+
fromRaw?: boolean;
|
|
33
|
+
}
|
|
34
|
+
export declare function parseMask(mask: string, tokens?: MaskTokens): Slot[];
|
|
35
|
+
/** Format `input` through a mask and map the caret into the result. */
|
|
36
|
+
export declare function applyMask(input: string, options: MaskOptions): MaskResult;
|
|
37
|
+
/**
|
|
38
|
+
* The value after deleting one accepted character next to a collapsed caret,
|
|
39
|
+
* skipping over literals, or null when there is nothing to delete that way.
|
|
40
|
+
*/
|
|
41
|
+
export declare function maskDelete(value: string, caret: number, direction: "backward" | "forward", options: Omit<MaskOptions, "caret" | "fromRaw">): MaskResult | null;
|
|
42
|
+
export interface UseInputMaskOptions {
|
|
43
|
+
mask: MaybeRefOrGetter<MaskSpec | undefined>;
|
|
44
|
+
tokens?: MaybeRefOrGetter<MaskTokens | undefined>;
|
|
45
|
+
/** Called with every value the user produces. */
|
|
46
|
+
onChange?: (masked: string, raw: string, complete: boolean) => void;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Bind `onBeforeInput`, `onInput` and `onCompositionEnd` to the input, and show
|
|
50
|
+
* `format(model).masked` as its value.
|
|
51
|
+
*/
|
|
52
|
+
export declare function useInputMask(options: UseInputMaskOptions): {
|
|
53
|
+
active: import("vue").ComputedRef<boolean>;
|
|
54
|
+
format: (value: string | null | undefined) => MaskResult;
|
|
55
|
+
onBeforeInput: (event: InputEvent) => void;
|
|
56
|
+
onInput: (event: Event) => void;
|
|
57
|
+
onCompositionEnd: (event: CompositionEvent) => void;
|
|
58
|
+
};
|
|
59
|
+
export {};
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { computed, toValue } from "vue";
|
|
2
|
+
const DEFAULT_MASK_TOKENS = {
|
|
3
|
+
"0": /\d/,
|
|
4
|
+
a: new RegExp("\\p{L}", "u"),
|
|
5
|
+
A: { pattern: new RegExp("\\p{L}", "u"), transform: (ch) => ch.toLocaleUpperCase() },
|
|
6
|
+
"*": /[\p{L}\d]/u
|
|
7
|
+
};
|
|
8
|
+
function tester(token) {
|
|
9
|
+
const pattern = token instanceof RegExp ? token : token.pattern;
|
|
10
|
+
const re = new RegExp(pattern.source, pattern.flags.replace(/[gy]/g, ""));
|
|
11
|
+
const transform = token instanceof RegExp ? void 0 : token.transform;
|
|
12
|
+
return { test: (ch) => re.test(ch), transform: transform ?? ((ch) => ch) };
|
|
13
|
+
}
|
|
14
|
+
function parseMask(mask, tokens = DEFAULT_MASK_TOKENS) {
|
|
15
|
+
const slots = [];
|
|
16
|
+
const chars = Array.from(mask);
|
|
17
|
+
for (let i = 0; i < chars.length; i++) {
|
|
18
|
+
const ch = chars[i];
|
|
19
|
+
if (ch === "\\" && i + 1 < chars.length) {
|
|
20
|
+
slots.push({ literal: chars[++i] });
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
const token = tokens[ch];
|
|
24
|
+
slots.push(token ? tester(token) : { literal: ch });
|
|
25
|
+
}
|
|
26
|
+
return slots;
|
|
27
|
+
}
|
|
28
|
+
function run(slots, input, caret, fromRaw) {
|
|
29
|
+
const tokenStarts = [];
|
|
30
|
+
const tokenEnds = [];
|
|
31
|
+
const tokenOffsets = [];
|
|
32
|
+
let out = "";
|
|
33
|
+
let raw = "";
|
|
34
|
+
let pending = "";
|
|
35
|
+
let si = 0;
|
|
36
|
+
let offset = 0;
|
|
37
|
+
let before = 0;
|
|
38
|
+
let overflow = false;
|
|
39
|
+
for (const ch of input) {
|
|
40
|
+
const at2 = offset;
|
|
41
|
+
offset += ch.length;
|
|
42
|
+
if (si >= slots.length) {
|
|
43
|
+
if (slots.some((s) => "test" in s && s.test(ch))) overflow = true;
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
while (si < slots.length) {
|
|
47
|
+
const slot = slots[si];
|
|
48
|
+
if ("literal" in slot) {
|
|
49
|
+
pending += slot.literal;
|
|
50
|
+
si++;
|
|
51
|
+
if (!fromRaw && slot.literal === ch) break;
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
if (slot.test(ch)) {
|
|
55
|
+
const value = slot.transform(ch);
|
|
56
|
+
out += pending;
|
|
57
|
+
pending = "";
|
|
58
|
+
tokenStarts.push(out.length);
|
|
59
|
+
out += value;
|
|
60
|
+
tokenEnds.push(out.length);
|
|
61
|
+
raw += value;
|
|
62
|
+
tokenOffsets.push(at2);
|
|
63
|
+
si++;
|
|
64
|
+
if (fromRaw ? raw.length <= caret : at2 < caret) before++;
|
|
65
|
+
}
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
const rest = slots.slice(si);
|
|
70
|
+
const complete = !rest.some((s) => "test" in s);
|
|
71
|
+
if (complete && out) out += pending + rest.map((s) => "literal" in s ? s.literal : "").join("");
|
|
72
|
+
const at = before === 0 ? tokenStarts[0] ?? 0 : tokenEnds[before - 1];
|
|
73
|
+
return {
|
|
74
|
+
masked: out,
|
|
75
|
+
raw,
|
|
76
|
+
caret: complete && before === tokenEnds.length ? out.length : at,
|
|
77
|
+
complete,
|
|
78
|
+
overflow,
|
|
79
|
+
tokenOffsets
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function resolve(options, input, caret) {
|
|
83
|
+
const tokens = options.tokens ?? DEFAULT_MASK_TOKENS;
|
|
84
|
+
const fromRaw = !!options.fromRaw;
|
|
85
|
+
const { mask } = options;
|
|
86
|
+
if (typeof mask === "string") return run(parseMask(mask, tokens), input, caret, fromRaw);
|
|
87
|
+
if (typeof mask === "function") {
|
|
88
|
+
let current = mask("");
|
|
89
|
+
let result = run(parseMask(current, tokens), input, caret, fromRaw);
|
|
90
|
+
for (let i = 0; i < 4; i++) {
|
|
91
|
+
const next = mask(result.raw);
|
|
92
|
+
if (next === current) break;
|
|
93
|
+
current = next;
|
|
94
|
+
result = run(parseMask(current, tokens), input, caret, fromRaw);
|
|
95
|
+
}
|
|
96
|
+
return result;
|
|
97
|
+
}
|
|
98
|
+
let last;
|
|
99
|
+
for (const m of mask) {
|
|
100
|
+
last = run(parseMask(m, tokens), input, caret, fromRaw);
|
|
101
|
+
if (!last.overflow) return last;
|
|
102
|
+
}
|
|
103
|
+
return last ?? run([], input, caret, fromRaw);
|
|
104
|
+
}
|
|
105
|
+
function applyMask(input, options) {
|
|
106
|
+
const caret = options.caret ?? (options.fromRaw ? Number.POSITIVE_INFINITY : input.length);
|
|
107
|
+
const { masked, raw, caret: at, complete } = resolve(options, input, caret);
|
|
108
|
+
return { masked, raw, caret: at, complete };
|
|
109
|
+
}
|
|
110
|
+
function maskDelete(value, caret, direction, options) {
|
|
111
|
+
const { tokenOffsets, raw } = resolve(options, value, caret);
|
|
112
|
+
const index = direction === "backward" ? tokenOffsets.filter((o) => o < caret).length - 1 : tokenOffsets.findIndex((o) => o >= caret);
|
|
113
|
+
if (index < 0) return null;
|
|
114
|
+
const chars = Array.from(raw);
|
|
115
|
+
chars.splice(index, 1);
|
|
116
|
+
return applyMask(chars.join(""), { ...options, caret: index, fromRaw: true });
|
|
117
|
+
}
|
|
118
|
+
function useInputMask(options) {
|
|
119
|
+
const spec = computed(() => {
|
|
120
|
+
const mask = toValue(options.mask);
|
|
121
|
+
return mask === void 0 || mask === "" ? void 0 : { mask, tokens: toValue(options.tokens) };
|
|
122
|
+
});
|
|
123
|
+
function format(value) {
|
|
124
|
+
const s = spec.value;
|
|
125
|
+
const text = value ?? "";
|
|
126
|
+
return s ? applyMask(text, s) : { masked: text, raw: text, caret: text.length, complete: true };
|
|
127
|
+
}
|
|
128
|
+
function commit(el, result) {
|
|
129
|
+
if (el.value !== result.masked) el.value = result.masked;
|
|
130
|
+
if (el.ownerDocument.activeElement === el) {
|
|
131
|
+
try {
|
|
132
|
+
el.setSelectionRange(result.caret, result.caret);
|
|
133
|
+
} catch {
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
options.onChange?.(result.masked, result.raw, result.complete);
|
|
137
|
+
}
|
|
138
|
+
function onBeforeInput(event) {
|
|
139
|
+
const s = spec.value;
|
|
140
|
+
const el = event.target;
|
|
141
|
+
if (!s || event.isComposing || !(el instanceof HTMLInputElement)) return;
|
|
142
|
+
const backward = event.inputType === "deleteContentBackward";
|
|
143
|
+
if (!backward && event.inputType !== "deleteContentForward") return;
|
|
144
|
+
const start = el.selectionStart;
|
|
145
|
+
if (start === null || start !== el.selectionEnd) return;
|
|
146
|
+
event.preventDefault();
|
|
147
|
+
const result = maskDelete(el.value, start, backward ? "backward" : "forward", s);
|
|
148
|
+
if (result) commit(el, result);
|
|
149
|
+
}
|
|
150
|
+
function reformat(el) {
|
|
151
|
+
const s = spec.value;
|
|
152
|
+
if (!s) return;
|
|
153
|
+
commit(el, applyMask(el.value, { ...s, caret: el.selectionStart ?? el.value.length }));
|
|
154
|
+
}
|
|
155
|
+
function onInput(event) {
|
|
156
|
+
if (event.isComposing || !(event.target instanceof HTMLInputElement)) return;
|
|
157
|
+
reformat(event.target);
|
|
158
|
+
}
|
|
159
|
+
function onCompositionEnd(event) {
|
|
160
|
+
if (event.target instanceof HTMLInputElement) reformat(event.target);
|
|
161
|
+
}
|
|
162
|
+
return { active: computed(() => !!spec.value), format, onBeforeInput, onInput, onCompositionEnd };
|
|
163
|
+
}
|
|
164
|
+
export {
|
|
165
|
+
DEFAULT_MASK_TOKENS,
|
|
166
|
+
applyMask,
|
|
167
|
+
maskDelete,
|
|
168
|
+
parseMask,
|
|
169
|
+
useInputMask
|
|
170
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type App, type Component, type ComputedRef, type InjectionKey, type MaybeRefOrGetter } from "vue";
|
|
2
|
+
export type LabelScope = Record<string, string>;
|
|
3
|
+
export interface LpConfig {
|
|
4
|
+
/** Component rendered for internal links (RouterLink, NuxtLink). Plain `<a>` when unset. */
|
|
5
|
+
linkComponent?: Component | string;
|
|
6
|
+
/** Text overrides by scope: `{ lightbox: { previous: "Back" } }`. */
|
|
7
|
+
labels?: Partial<Record<string, Partial<LabelScope>>>;
|
|
8
|
+
}
|
|
9
|
+
export declare const LP_CONFIG: InjectionKey<MaybeRefOrGetter<LpConfig>>;
|
|
10
|
+
/** Provide kit configuration to every component below the caller. */
|
|
11
|
+
export declare function provideLpConfig(config: MaybeRefOrGetter<LpConfig>): void;
|
|
12
|
+
/** Install the configuration app-wide: `app.use(lpConfig({ ... }))`. */
|
|
13
|
+
export declare function lpConfig(config: MaybeRefOrGetter<LpConfig>): {
|
|
14
|
+
install: (app: App) => void;
|
|
15
|
+
};
|
|
16
|
+
export declare function mergeConfig(outer: LpConfig, inner: LpConfig): LpConfig;
|
|
17
|
+
export declare function useLpConfig(): ComputedRef<LpConfig>;
|
|
18
|
+
/**
|
|
19
|
+
* The labels a component renders: its own `labels` prop over the configured
|
|
20
|
+
* scope over its defaults.
|
|
21
|
+
*/
|
|
22
|
+
export declare function useLabels<T extends LabelScope>(scope: string, defaults: T, own?: () => Partial<T> | undefined): ComputedRef<T>;
|
|
23
|
+
/** The link component to render for an internal destination. */
|
|
24
|
+
export declare function useLinkComponent(): ComputedRef<Component | string>;
|