@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
|
@@ -24,7 +24,8 @@ export default { inheritAttrs: false }
|
|
|
24
24
|
*/
|
|
25
25
|
import { computed, reactive, ref, watch } from "vue"
|
|
26
26
|
import { useClipboard } from "../composables/useClipboard"
|
|
27
|
-
import { type CodeLang,
|
|
27
|
+
import { type CodeLang, tokenizeLines } from "./codeHighlight"
|
|
28
|
+
import { useLabels } from "../composables/useLpConfig"
|
|
28
29
|
import LpIcon from "./LpIcon.vue"
|
|
29
30
|
import { useMergedAttrs } from "../composables/useMergedClass"
|
|
30
31
|
|
|
@@ -49,6 +50,7 @@ const props = withDefaults(
|
|
|
49
50
|
height?: string
|
|
50
51
|
/** Auto-collapse a leading import/package block (no markers needed). */
|
|
51
52
|
foldImports?: boolean
|
|
53
|
+
labels?: Partial<Record<"unlock" | "lock" | "copy" | "copied" | "imports" | "details" | "lines", string>>
|
|
52
54
|
}>(),
|
|
53
55
|
{
|
|
54
56
|
lang: "plain",
|
|
@@ -66,6 +68,21 @@ const emit = defineEmits<{
|
|
|
66
68
|
(e: "update:locked", value: boolean): void
|
|
67
69
|
}>()
|
|
68
70
|
|
|
71
|
+
const text = useLabels(
|
|
72
|
+
"codeBlock",
|
|
73
|
+
{
|
|
74
|
+
unlock: "Unlock to edit",
|
|
75
|
+
lock: "Lock (read-only)",
|
|
76
|
+
copy: "Copy code",
|
|
77
|
+
copied: "Copied",
|
|
78
|
+
imports: "imports",
|
|
79
|
+
details: "details",
|
|
80
|
+
/** `{n}` is replaced by the count. */
|
|
81
|
+
lines: "({n} lines)",
|
|
82
|
+
},
|
|
83
|
+
() => props.labels,
|
|
84
|
+
)
|
|
85
|
+
|
|
69
86
|
const code = computed(() => props.modelValue ?? "")
|
|
70
87
|
const rawLines = computed(() => code.value.replace(/\n$/, "").split("\n"))
|
|
71
88
|
|
|
@@ -114,7 +131,7 @@ const segments = computed<Segment[]>(() => {
|
|
|
114
131
|
flushPlain()
|
|
115
132
|
const lines: NumberedLine[] = []
|
|
116
133
|
for (let k = start; k < realEnd; k++) lines.push({ n: k + 1, text: src[k] })
|
|
117
|
-
out.push({ kind: "fold", id: foldId++, label:
|
|
134
|
+
out.push({ kind: "fold", id: foldId++, label: text.value.imports, defaultOpen: false, lines })
|
|
118
135
|
i = realEnd
|
|
119
136
|
}
|
|
120
137
|
}
|
|
@@ -126,7 +143,7 @@ const segments = computed<Segment[]>(() => {
|
|
|
126
143
|
flushPlain()
|
|
127
144
|
const rest = startMatch[1] ?? ""
|
|
128
145
|
const defaultOpen = /\bopen\b/.test(rest)
|
|
129
|
-
const label = rest.replace(/\bopen\b/, "").trim() ||
|
|
146
|
+
const label = rest.replace(/\bopen\b/, "").trim() || text.value.details
|
|
130
147
|
const lines: NumberedLine[] = []
|
|
131
148
|
i++
|
|
132
149
|
for (; i < src.length; i++) {
|
|
@@ -143,6 +160,7 @@ const segments = computed<Segment[]>(() => {
|
|
|
143
160
|
})
|
|
144
161
|
|
|
145
162
|
const hasFolds = computed(() => segments.value.some((s) => s.kind === "fold"))
|
|
163
|
+
const editing = computed(() => !props.locked && !hasFolds.value)
|
|
146
164
|
|
|
147
165
|
// Per-region open state, keyed by fold id, defaulting to each region's declared
|
|
148
166
|
// open flag. Reset when the set of folds changes.
|
|
@@ -159,9 +177,21 @@ function toggleFold(id: number) {
|
|
|
159
177
|
openState[id] = !openState[id]
|
|
160
178
|
}
|
|
161
179
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
180
|
+
/* Highlighted once for the whole snippet, so a block comment that spans lines
|
|
181
|
+
is coloured as one; looked up by the line's 1-based number. */
|
|
182
|
+
const highlighted = computed(() => tokenizeLines(rawLines.value, props.lang))
|
|
183
|
+
function tokens(n: number) {
|
|
184
|
+
return highlighted.value[n - 1] ?? []
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/* The textarea is the scroller while editing; the highlighted copy under it
|
|
188
|
+
follows, or the caret drifts over the wrong text on a long line. */
|
|
189
|
+
const preEl = ref<HTMLElement | null>(null)
|
|
190
|
+
function syncScroll(e: Event) {
|
|
191
|
+
const area = e.target as HTMLTextAreaElement
|
|
192
|
+
if (!preEl.value) return
|
|
193
|
+
preEl.value.scrollLeft = area.scrollLeft
|
|
194
|
+
preEl.value.scrollTop = area.scrollTop
|
|
165
195
|
}
|
|
166
196
|
|
|
167
197
|
// Copied text is the real code with marker lines removed (so it pastes clean),
|
|
@@ -214,7 +244,7 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
|
|
|
214
244
|
v-if="lockToggle"
|
|
215
245
|
type="button"
|
|
216
246
|
class="group/lock flex items-center gap-1 rounded px-1.5 py-1 outline-none transition-colors duration-[var(--duration-fast)] hover:text-ink focus-visible:ring-2 focus-visible:ring-ring"
|
|
217
|
-
:aria-label="locked ?
|
|
247
|
+
:aria-label="locked ? text.unlock : text.lock"
|
|
218
248
|
@click="toggleLock"
|
|
219
249
|
>
|
|
220
250
|
<LpIcon
|
|
@@ -227,7 +257,7 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
|
|
|
227
257
|
v-if="copyable"
|
|
228
258
|
type="button"
|
|
229
259
|
class="group/copy flex items-center gap-1 rounded px-1.5 py-1 outline-none transition-colors duration-[var(--duration-fast)] hover:text-ink focus-visible:ring-2 focus-visible:ring-ring"
|
|
230
|
-
:aria-label="copied ?
|
|
260
|
+
:aria-label="copied ? text.copied : text.copy"
|
|
231
261
|
@click="copy"
|
|
232
262
|
>
|
|
233
263
|
<LpIcon
|
|
@@ -245,7 +275,7 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
|
|
|
245
275
|
<div
|
|
246
276
|
class="lp-scrollbar-none relative"
|
|
247
277
|
:style="height ? { height } : undefined"
|
|
248
|
-
:class="height ? 'overflow-auto' : ''"
|
|
278
|
+
:class="height ? (editing ? 'overflow-hidden' : 'overflow-auto') : ''"
|
|
249
279
|
>
|
|
250
280
|
<!-- Editable overlay: only when unlocked and there are no folds. -->
|
|
251
281
|
<textarea
|
|
@@ -253,12 +283,18 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
|
|
|
253
283
|
:value="code"
|
|
254
284
|
spellcheck="false"
|
|
255
285
|
class="lp-scrollbar-none absolute inset-0 size-full resize-none overflow-auto whitespace-pre bg-transparent p-3 leading-relaxed text-transparent caret-brand outline-none"
|
|
256
|
-
:class="[wrap ? 'whitespace-pre-wrap break-words' : 'whitespace-pre', lineNumbers ? 'pl-
|
|
286
|
+
:class="[wrap ? 'whitespace-pre-wrap break-words' : 'whitespace-pre', lineNumbers ? 'pl-13' : '']"
|
|
257
287
|
@input="onInput"
|
|
288
|
+
@scroll="syncScroll"
|
|
258
289
|
/>
|
|
259
290
|
<pre
|
|
291
|
+
ref="preEl"
|
|
260
292
|
class="lp-scrollbar-none m-0 overflow-auto p-3 leading-relaxed"
|
|
261
|
-
:class="[
|
|
293
|
+
:class="[
|
|
294
|
+
wrap ? 'whitespace-pre-wrap break-words' : 'whitespace-pre',
|
|
295
|
+
editing ? 'pointer-events-none' : '',
|
|
296
|
+
editing && height ? 'h-full overflow-hidden' : '',
|
|
297
|
+
]"
|
|
262
298
|
><code class="block"><template
|
|
263
299
|
v-for="(seg, s) in segments"
|
|
264
300
|
:key="s"
|
|
@@ -271,7 +307,7 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
|
|
|
271
307
|
class="mr-3 inline-block w-7 select-none text-right text-muted/60"
|
|
272
308
|
aria-hidden="true"
|
|
273
309
|
>{{ ln.n }}</span><span
|
|
274
|
-
v-for="(tok, j) in tokens(ln.
|
|
310
|
+
v-for="(tok, j) in tokens(ln.n)"
|
|
275
311
|
:key="j"
|
|
276
312
|
:class="tok.cls"
|
|
277
313
|
>{{ tok.text }}</span></span></template><!-- Fold region --><template
|
|
@@ -288,7 +324,7 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
|
|
|
288
324
|
/><span class="select-none">{{ openState[seg.id] ? seg.label : seg.label + ' …' }}</span><span
|
|
289
325
|
v-if="!openState[seg.id]"
|
|
290
326
|
class="select-none text-muted/50"
|
|
291
|
-
>
|
|
327
|
+
>{{ text.lines.replace("{n}", String(seg.lines.length)) }}</span></button><template
|
|
292
328
|
v-if="openState[seg.id]"
|
|
293
329
|
><span
|
|
294
330
|
v-for="ln in seg.lines"
|
|
@@ -299,7 +335,7 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
|
|
|
299
335
|
class="mr-3 inline-block w-7 select-none text-right text-muted/60"
|
|
300
336
|
aria-hidden="true"
|
|
301
337
|
>{{ ln.n }}</span><span
|
|
302
|
-
v-for="(tok, j) in tokens(ln.
|
|
338
|
+
v-for="(tok, j) in tokens(ln.n)"
|
|
303
339
|
:key="j"
|
|
304
340
|
:class="tok.cls"
|
|
305
341
|
>{{ tok.text }}</span></span></template></template></template></code></pre>
|
|
@@ -36,7 +36,9 @@ import {
|
|
|
36
36
|
PopoverRoot,
|
|
37
37
|
PopoverTrigger,
|
|
38
38
|
} from "reka-ui"
|
|
39
|
-
import { computed, ref, watch } from "vue"
|
|
39
|
+
import { computed, nextTick, ref, watch } from "vue"
|
|
40
|
+
import { prefersReducedMotion } from "../composables/easing"
|
|
41
|
+
import { useFieldControl } from "../composables/useField"
|
|
40
42
|
import {
|
|
41
43
|
clampHsv,
|
|
42
44
|
DEFAULT_SWATCHES,
|
|
@@ -52,6 +54,7 @@ import { useClipboard } from "../composables/useClipboard"
|
|
|
52
54
|
import { POPOVER_PANEL } from "./dropdown"
|
|
53
55
|
import LpContextMenu, { type ContextMenuItemDef } from "./LpContextMenu.vue"
|
|
54
56
|
import LpIcon from "./LpIcon.vue"
|
|
57
|
+
import LpRollingText from "./LpRollingText.vue"
|
|
55
58
|
|
|
56
59
|
/**
|
|
57
60
|
* Every user-facing string the picker renders on its own — the menu items, the
|
|
@@ -271,7 +274,9 @@ function trackPointer(e: PointerEvent, onMove: (x: number, y: number) => void) {
|
|
|
271
274
|
|
|
272
275
|
const onFieldPointer = (e: PointerEvent) =>
|
|
273
276
|
trackPointer(e, (x, y) => set({ s: x, v: 1 - y }))
|
|
274
|
-
|
|
277
|
+
// 360° is 0° again, so the far edge of the rail would throw the thumb back to
|
|
278
|
+
// the start; it stops just short instead, as End does.
|
|
279
|
+
const onHuePointer = (e: PointerEvent) => trackPointer(e, (x) => set({ h: Math.min(x * 360, 359.9) }))
|
|
275
280
|
const onAlphaPointer = (e: PointerEvent) => trackPointer(e, (x) => set({ a: x }))
|
|
276
281
|
|
|
277
282
|
/* ── keyboard ─────────────────────────────────────
|
|
@@ -303,11 +308,13 @@ function step(e: KeyboardEvent, axis: "sv" | "h" | "a") {
|
|
|
303
308
|
}
|
|
304
309
|
|
|
305
310
|
/* ── text field ───────────────────────────────────
|
|
306
|
-
Typed text is parsed on every keystroke
|
|
307
|
-
a real colour,
|
|
308
|
-
|
|
309
|
-
|
|
311
|
+
Typed text is parsed on every keystroke and previews as soon as it resolves
|
|
312
|
+
to a real colour, but is only committed (`change`) on Enter or when the field
|
|
313
|
+
loses focus: "#3b8" and "#3b82" are valid colours on the way to "#3b82f6",
|
|
314
|
+
and committing each one handed listeners three colours nobody chose. The
|
|
315
|
+
field shows what is typed while it has focus and the value once it doesn't. */
|
|
310
316
|
const typed = ref<string | null>(null)
|
|
317
|
+
let typedChange = false
|
|
311
318
|
const inputValue = computed(() => typed.value ?? current.value)
|
|
312
319
|
|
|
313
320
|
function onInput(e: Event) {
|
|
@@ -318,11 +325,19 @@ function onInput(e: Event) {
|
|
|
318
325
|
const next = rgbToHsv(rgb)
|
|
319
326
|
if (next.s === 0) next.h = hsv.value.h
|
|
320
327
|
if (next.v === 0) next.s = hsv.value.s
|
|
321
|
-
set(props.alpha ? next : { ...next, a: 1 }
|
|
328
|
+
set(props.alpha ? next : { ...next, a: 1 })
|
|
329
|
+
typedChange = true
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function commitTyped() {
|
|
333
|
+
if (!typedChange) return
|
|
334
|
+
typedChange = false
|
|
335
|
+
emit("change", current.value)
|
|
322
336
|
}
|
|
323
337
|
|
|
324
338
|
function onInputBlur() {
|
|
325
339
|
typed.value = null
|
|
340
|
+
commitTyped()
|
|
326
341
|
}
|
|
327
342
|
|
|
328
343
|
function pickSwatch(value: string) {
|
|
@@ -463,8 +478,12 @@ function remember(value: string) {
|
|
|
463
478
|
// Remember on close rather than on every commit: the colour a person leaves the
|
|
464
479
|
// popover on is the one they chose, while the ones they passed through on the
|
|
465
480
|
// way are not history, they are the search for it.
|
|
481
|
+
// Only a colour that changed while the popover was open: opening it to look,
|
|
482
|
+
// or to copy the value out, is not a choice worth recording.
|
|
483
|
+
let openedOn = ""
|
|
466
484
|
watch(open, (isOpen, was) => {
|
|
467
|
-
if (
|
|
485
|
+
if (isOpen) openedOn = current.value
|
|
486
|
+
else if (was && current.value !== openedOn) remember(current.value)
|
|
468
487
|
})
|
|
469
488
|
|
|
470
489
|
/**
|
|
@@ -537,9 +556,28 @@ async function pasteColor() {
|
|
|
537
556
|
* emit the picker would display rgb() while the app still stored hex, and the
|
|
538
557
|
* next thing to read that value would disagree with the screen.
|
|
539
558
|
*/
|
|
559
|
+
/*
|
|
560
|
+
* A format switch rewrites the whole text in place ("#3b82f6" becomes
|
|
561
|
+
* "rgb(59 130 246)"), so the new value rolls in over the field the way the
|
|
562
|
+
* kit's other changing labels do. An <input> cannot animate its own text, so
|
|
563
|
+
* a rolling copy lies over it for the length of the roll; it only ever moves
|
|
564
|
+
* on a format switch, never while a colour is being dragged.
|
|
565
|
+
*/
|
|
566
|
+
const ROLL_MS = 320
|
|
567
|
+
const rollText = ref(current.value)
|
|
568
|
+
const rolling = ref(false)
|
|
569
|
+
let rollTimer: ReturnType<typeof setTimeout> | undefined
|
|
570
|
+
|
|
540
571
|
function setFormat(f: ColorFormat) {
|
|
541
572
|
if (activeFormat.value === f) return
|
|
573
|
+
rollText.value = inputValue.value
|
|
542
574
|
activeFormat.value = f
|
|
575
|
+
if (!prefersReducedMotion()) {
|
|
576
|
+
rolling.value = true
|
|
577
|
+
void nextTick(() => (rollText.value = current.value))
|
|
578
|
+
if (rollTimer) clearTimeout(rollTimer)
|
|
579
|
+
rollTimer = setTimeout(() => (rolling.value = false), ROLL_MS + 40)
|
|
580
|
+
}
|
|
543
581
|
typed.value = null
|
|
544
582
|
emit("update:modelValue", current.value)
|
|
545
583
|
emit("change", current.value)
|
|
@@ -573,6 +611,12 @@ const menuItems = computed<ContextMenuItemDef[]>(() => {
|
|
|
573
611
|
: builtin
|
|
574
612
|
})
|
|
575
613
|
|
|
614
|
+
const field = useFieldControl(() => ({
|
|
615
|
+
wrapped: false,
|
|
616
|
+
invalid: props.invalid,
|
|
617
|
+
disabled: props.disabled,
|
|
618
|
+
}))
|
|
619
|
+
|
|
576
620
|
defineExpose({ open })
|
|
577
621
|
</script>
|
|
578
622
|
|
|
@@ -592,12 +636,15 @@ defineExpose({ open })
|
|
|
592
636
|
<PopoverTrigger as-child>
|
|
593
637
|
<button
|
|
594
638
|
type="button"
|
|
595
|
-
:
|
|
639
|
+
:id="field.id"
|
|
640
|
+
:disabled="field.disabled"
|
|
596
641
|
:aria-label="ariaLabel"
|
|
642
|
+
:aria-invalid="field.invalid || undefined"
|
|
643
|
+
:aria-describedby="field.describedBy"
|
|
597
644
|
class="group inline-flex w-full items-center gap-2 rounded-control border bg-surface-soft px-2 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"
|
|
598
645
|
:class="[
|
|
599
646
|
triggerSize[size],
|
|
600
|
-
invalid ? 'border-danger focus-visible:ring-danger-soft' : 'border-line focus-visible:border-brand',
|
|
647
|
+
field.invalid ? 'border-danger focus-visible:ring-danger-soft' : 'border-line focus-visible:border-brand',
|
|
601
648
|
]"
|
|
602
649
|
>
|
|
603
650
|
<!-- The swatch sits on the checkerboard so a transparent colour looks
|
|
@@ -628,6 +675,7 @@ defineExpose({ open })
|
|
|
628
675
|
|
|
629
676
|
<PopoverPortal>
|
|
630
677
|
<PopoverContent
|
|
678
|
+
:collision-padding="8"
|
|
631
679
|
:side="side"
|
|
632
680
|
:align="align"
|
|
633
681
|
:side-offset="6"
|
|
@@ -645,6 +693,9 @@ defineExpose({ open })
|
|
|
645
693
|
role="slider"
|
|
646
694
|
:tabindex="disabled ? -1 : 0"
|
|
647
695
|
:aria-label="l.saturation"
|
|
696
|
+
:aria-valuemin="0"
|
|
697
|
+
:aria-valuemax="100"
|
|
698
|
+
:aria-valuenow="Math.round(hsv.s * 100)"
|
|
648
699
|
:aria-valuetext="fill(l.saturationValueText, { s: Math.round(hsv.s * 100), v: Math.round(hsv.v * 100) })"
|
|
649
700
|
class="relative h-36 w-full cursor-crosshair touch-none overflow-hidden rounded-control outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring"
|
|
650
701
|
:style="fieldStyle"
|
|
@@ -719,6 +770,15 @@ defineExpose({ open })
|
|
|
719
770
|
class="size-4 shrink-0 rounded-[5px] border border-line"
|
|
720
771
|
:style="{ backgroundColor: previewCss }"
|
|
721
772
|
/>
|
|
773
|
+
<span class="relative flex min-w-0 flex-1 items-center">
|
|
774
|
+
<LpRollingText
|
|
775
|
+
v-show="rolling"
|
|
776
|
+
:value="rollText"
|
|
777
|
+
:duration="ROLL_MS"
|
|
778
|
+
align="start"
|
|
779
|
+
aria-hidden="true"
|
|
780
|
+
class="pointer-events-none absolute inset-0 font-mono text-xs text-ink"
|
|
781
|
+
/>
|
|
722
782
|
<input
|
|
723
783
|
:value="inputValue"
|
|
724
784
|
:disabled="disabled"
|
|
@@ -727,9 +787,12 @@ defineExpose({ open })
|
|
|
727
787
|
autocomplete="off"
|
|
728
788
|
:aria-label="l.value"
|
|
729
789
|
class="min-w-0 flex-1 select-text bg-transparent font-mono text-xs text-ink outline-none placeholder:text-muted"
|
|
790
|
+
:class="rolling ? 'text-transparent' : ''"
|
|
730
791
|
@input="onInput"
|
|
792
|
+
@keydown.enter="commitTyped"
|
|
731
793
|
@blur="onInputBlur"
|
|
732
794
|
/>
|
|
795
|
+
</span>
|
|
733
796
|
</div>
|
|
734
797
|
|
|
735
798
|
<!-- Recent sits ABOVE the presets because it is the row that
|
|
@@ -44,6 +44,7 @@ import { useGlass } from "../composables/useGlass"
|
|
|
44
44
|
import { useClipboard } from "../composables/useClipboard"
|
|
45
45
|
import { useHotkeys } from "../composables/useHotkeys"
|
|
46
46
|
import { useModalLayer } from "./modalDepth"
|
|
47
|
+
import { useLabels } from "../composables/useLpConfig"
|
|
47
48
|
import { parseCommandQuery, rankCommandItems } from "./commandSearch"
|
|
48
49
|
|
|
49
50
|
export interface Command {
|
|
@@ -87,7 +88,7 @@ export interface Command {
|
|
|
87
88
|
* `onSelect` still runs when the mode opens, so a command can both act and
|
|
88
89
|
* drill in.
|
|
89
90
|
*/
|
|
90
|
-
children?: Command[] | ((query: string) => Command[] | Promise<Command[]>)
|
|
91
|
+
children?: Command[] | ((query: string, signal: AbortSignal) => Command[] | Promise<Command[]>)
|
|
91
92
|
/** Placeholder while inside this command's mode. */
|
|
92
93
|
childPlaceholder?: string
|
|
93
94
|
/**
|
|
@@ -121,7 +122,7 @@ export interface Command {
|
|
|
121
122
|
}
|
|
122
123
|
|
|
123
124
|
/** Footer hints and the mode chip, spelled out so an app can translate them. */
|
|
124
|
-
export
|
|
125
|
+
export type PaletteLabels = {
|
|
125
126
|
navigate: string
|
|
126
127
|
select: string
|
|
127
128
|
close: string
|
|
@@ -144,6 +145,11 @@ export interface PaletteLabels {
|
|
|
144
145
|
* text is never displayed. Kept so existing `labels` objects still type-check.
|
|
145
146
|
*/
|
|
146
147
|
noPreview?: string
|
|
148
|
+
/** Accessible name and description of the dialog, read by screen readers only. */
|
|
149
|
+
title?: string
|
|
150
|
+
description?: string
|
|
151
|
+
/** The key hint printed beside the box and in the footer. */
|
|
152
|
+
esc?: string
|
|
147
153
|
}
|
|
148
154
|
|
|
149
155
|
const props = withDefaults(
|
|
@@ -175,6 +181,12 @@ const props = withDefaults(
|
|
|
175
181
|
* so a stored history never resurrects a command that has gone away.
|
|
176
182
|
*/
|
|
177
183
|
recent?: string[]
|
|
184
|
+
/**
|
|
185
|
+
* Let the palette keep the history itself, in localStorage under this key:
|
|
186
|
+
* every top-level command run is remembered, newest first. Ignored while
|
|
187
|
+
* `recent` is bound, which stays the way to store it somewhere else.
|
|
188
|
+
*/
|
|
189
|
+
recentKey?: string
|
|
178
190
|
/** How many recent commands to surface. */
|
|
179
191
|
recentLimit?: number
|
|
180
192
|
/** Headings the palette adds itself. */
|
|
@@ -229,9 +241,10 @@ const props = withDefaults(
|
|
|
229
241
|
)
|
|
230
242
|
|
|
231
243
|
const frosted = useGlass(() => props.glass)
|
|
232
|
-
const {
|
|
244
|
+
const contentRef = ref<{ $el: HTMLElement } | null>(null)
|
|
245
|
+
const { claim, release, layer } = useModalLayer({ element: () => contentRef.value?.$el })
|
|
233
246
|
|
|
234
|
-
const DEFAULT_LABELS: PaletteLabels = {
|
|
247
|
+
const DEFAULT_LABELS: Required<PaletteLabels> = {
|
|
235
248
|
navigate: "navigate",
|
|
236
249
|
select: "select",
|
|
237
250
|
close: "close",
|
|
@@ -245,9 +258,12 @@ const DEFAULT_LABELS: PaletteLabels = {
|
|
|
245
258
|
copyLink: "Copy link",
|
|
246
259
|
linkCopied: "Link copied",
|
|
247
260
|
noPreview: "No preview",
|
|
261
|
+
title: "Command palette",
|
|
262
|
+
description: "Search and run a command.",
|
|
263
|
+
esc: "esc",
|
|
248
264
|
}
|
|
249
265
|
|
|
250
|
-
const text =
|
|
266
|
+
const text = useLabels("palette", DEFAULT_LABELS, () => props.labels)
|
|
251
267
|
|
|
252
268
|
const emit = defineEmits<{
|
|
253
269
|
(e: "update:open", value: boolean): void
|
|
@@ -330,15 +346,42 @@ const selectedActions = computed(() => actionsOf(flat.value[selectedIndex.value]
|
|
|
330
346
|
* actions it keeps that default.
|
|
331
347
|
*/
|
|
332
348
|
function onTab(event: KeyboardEvent) {
|
|
333
|
-
|
|
334
|
-
|
|
349
|
+
// Without actions Tab stays Tab, so the trail chips and a Retry button are
|
|
350
|
+
// still reachable from the keyboard.
|
|
335
351
|
if (event.shiftKey) return
|
|
336
352
|
const c = flat.value[selectedIndex.value]
|
|
337
353
|
const actions = selectedActions.value
|
|
338
354
|
if (!c || !actions.length) return
|
|
355
|
+
event.preventDefault()
|
|
356
|
+
event.stopPropagation()
|
|
339
357
|
enter({ id: `${c.id}:actions`, label: c.label, icon: c.icon, children: actions })
|
|
340
358
|
}
|
|
341
359
|
|
|
360
|
+
/*
|
|
361
|
+
* A mode holds the command it was entered through, and a static `children`
|
|
362
|
+
* list is a snapshot of that moment. When the app rebuilds its commands (a
|
|
363
|
+
* theme list whose tick follows the active theme), the open mode is matched
|
|
364
|
+
* to the new commands by id along its path and takes their children, so a
|
|
365
|
+
* `keepOpen` pick inside it shows its own effect.
|
|
366
|
+
*/
|
|
367
|
+
watch(
|
|
368
|
+
() => props.commands,
|
|
369
|
+
(commands) => {
|
|
370
|
+
if (!trail.value.length) return
|
|
371
|
+
let level: Command[] = commands
|
|
372
|
+
const next: Command[] = []
|
|
373
|
+
for (const step of trail.value) {
|
|
374
|
+
const fresh = level.find((c) => c.id === step.id)
|
|
375
|
+
if (!fresh) return
|
|
376
|
+
next.push(fresh)
|
|
377
|
+
level = Array.isArray(fresh.children) ? fresh.children : []
|
|
378
|
+
}
|
|
379
|
+
trail.value = next
|
|
380
|
+
const last = next[next.length - 1]
|
|
381
|
+
if (last && Array.isArray(last.children)) modeItems.value = last.children
|
|
382
|
+
},
|
|
383
|
+
)
|
|
384
|
+
|
|
342
385
|
function enter(c: Command) {
|
|
343
386
|
trailState.value = [...trailState.value, { query: query.value, selectedId: selectedId.value }]
|
|
344
387
|
trail.value = [...trail.value, c]
|
|
@@ -392,7 +435,7 @@ function fetcher(): ((q: string, signal: AbortSignal) => Command[] | Promise<Com
|
|
|
392
435
|
const current = mode.value
|
|
393
436
|
if (current) {
|
|
394
437
|
return typeof current.children === "function"
|
|
395
|
-
?
|
|
438
|
+
? current.children
|
|
396
439
|
: null
|
|
397
440
|
}
|
|
398
441
|
return props.search ?? null
|
|
@@ -486,11 +529,36 @@ const fetched = computed<Command[]>(() => {
|
|
|
486
529
|
* Only on the root's empty query: once someone types, or drills into a mode,
|
|
487
530
|
* relevance is the better order and a duplicated row is just noise.
|
|
488
531
|
*/
|
|
532
|
+
const RECENT_KEEP = 20
|
|
533
|
+
const ownRecent = ref<string[]>([])
|
|
534
|
+
watch(
|
|
535
|
+
() => props.recentKey,
|
|
536
|
+
(key) => {
|
|
537
|
+
if (!key || typeof localStorage === "undefined") return
|
|
538
|
+
try {
|
|
539
|
+
const stored: unknown = JSON.parse(localStorage.getItem(key) ?? "[]")
|
|
540
|
+
ownRecent.value = Array.isArray(stored) ? stored.filter((v): v is string => typeof v === "string") : []
|
|
541
|
+
} catch {
|
|
542
|
+
ownRecent.value = []
|
|
543
|
+
}
|
|
544
|
+
},
|
|
545
|
+
{ immediate: true },
|
|
546
|
+
)
|
|
547
|
+
function remember(id: string) {
|
|
548
|
+
const key = props.recentKey
|
|
549
|
+
if (!key || props.recent) return
|
|
550
|
+
ownRecent.value = [id, ...ownRecent.value.filter((v) => v !== id)].slice(0, RECENT_KEEP)
|
|
551
|
+
try {
|
|
552
|
+
localStorage.setItem(key, JSON.stringify(ownRecent.value))
|
|
553
|
+
} catch {}
|
|
554
|
+
}
|
|
555
|
+
const recentIds = computed(() => props.recent ?? (props.recentKey ? ownRecent.value : []))
|
|
556
|
+
|
|
489
557
|
const recentItems = computed<Command[]>(() => {
|
|
490
|
-
if (mode.value || query.value.trim() || !
|
|
558
|
+
if (mode.value || query.value.trim() || !recentIds.value.length) return []
|
|
491
559
|
const byId = new Map(props.commands.map((c) => [c.id, c]))
|
|
492
560
|
const out: Command[] = []
|
|
493
|
-
for (const id of
|
|
561
|
+
for (const id of recentIds.value) {
|
|
494
562
|
const c = byId.get(id)
|
|
495
563
|
if (c && !c.disabled && !out.includes(c)) out.push(c)
|
|
496
564
|
if (out.length >= props.recentLimit) break
|
|
@@ -578,6 +646,18 @@ const paragraphs = computed(() =>
|
|
|
578
646
|
.filter(Boolean),
|
|
579
647
|
)
|
|
580
648
|
|
|
649
|
+
/*
|
|
650
|
+
* The row's description heads the pane only when it says something the body
|
|
651
|
+
* does not: a command whose full text opens with its description (or is it)
|
|
652
|
+
* would otherwise print the same sentences twice, once small and once large.
|
|
653
|
+
*/
|
|
654
|
+
const paneDescription = computed(() => {
|
|
655
|
+
const description = active.value?.description?.trim()
|
|
656
|
+
if (!description) return undefined
|
|
657
|
+
const body = paragraphs.value.join(" ")
|
|
658
|
+
return body.startsWith(description) ? undefined : description
|
|
659
|
+
})
|
|
660
|
+
|
|
581
661
|
/** Stagger between paragraphs, capped so a long section does not trickle in. */
|
|
582
662
|
const STAGGER_MS = 45
|
|
583
663
|
const STAGGER_MAX = 10
|
|
@@ -599,8 +679,11 @@ watch(
|
|
|
599
679
|
else viewport.scrollTop = 0
|
|
600
680
|
},
|
|
601
681
|
)
|
|
682
|
+
// Rows ask for their index several times per render; a lookup keeps that O(1)
|
|
683
|
+
// instead of a scan of the whole list per row.
|
|
684
|
+
const flatIndex = computed(() => new Map(flat.value.map((c, i) => [c, i])))
|
|
602
685
|
function flatIndexOf(c: Command): number {
|
|
603
|
-
return
|
|
686
|
+
return flatIndex.value.get(c) ?? -1
|
|
604
687
|
}
|
|
605
688
|
|
|
606
689
|
// ── highlight ────────────────────────────────────────────────
|
|
@@ -689,6 +772,9 @@ function movePage(direction: -1 | 1) {
|
|
|
689
772
|
function onPaletteKeydown(event: KeyboardEvent) {
|
|
690
773
|
if (event.isComposing) return
|
|
691
774
|
if (!(["ArrowDown", "ArrowUp", "Home", "End", "PageDown", "PageUp"] as string[]).includes(event.key)) return
|
|
775
|
+
// Home and End belong to the caret while there is text to move it through.
|
|
776
|
+
const typing = event.target instanceof HTMLInputElement && event.target.value !== ""
|
|
777
|
+
if (typing && (event.key === "Home" || event.key === "End")) return
|
|
692
778
|
event.preventDefault()
|
|
693
779
|
event.stopPropagation()
|
|
694
780
|
if (event.key === "ArrowDown") moveDown()
|
|
@@ -750,11 +836,16 @@ function run(c: Command | undefined) {
|
|
|
750
836
|
return
|
|
751
837
|
}
|
|
752
838
|
emit("run", c.id, c)
|
|
839
|
+
if (!mode.value) remember(c.id)
|
|
753
840
|
if (c.keepOpen) {
|
|
754
841
|
// Back to the top of a fresh list: the query that found this command is
|
|
755
842
|
// spent, and leaving it would hide whatever the action just changed.
|
|
756
843
|
query.value = ""
|
|
757
|
-
|
|
844
|
+
// Inside a mode the highlight stays on what was just picked, so trying
|
|
845
|
+
// themes one after another is a matter of the arrow keys; at the root the
|
|
846
|
+
// list it came from is gone and the top is the honest place to land.
|
|
847
|
+
if (mode.value) void nextTick(() => select(Math.max(0, flat.value.findIndex((x) => x.id === c.id))))
|
|
848
|
+
else select(0)
|
|
758
849
|
inputRef.value?.focus()
|
|
759
850
|
return
|
|
760
851
|
}
|
|
@@ -828,6 +919,8 @@ useHotkeys(() =>
|
|
|
828
919
|
code: "KeyK",
|
|
829
920
|
ctrl: true,
|
|
830
921
|
allowInInput: true,
|
|
922
|
+
overLayers: true,
|
|
923
|
+
repeat: false,
|
|
831
924
|
handler: () => emit("update:open", !props.open),
|
|
832
925
|
},
|
|
833
926
|
]
|
|
@@ -844,6 +937,7 @@ useHotkeys(() =>
|
|
|
844
937
|
:style="{ zIndex: layer.scrim }"
|
|
845
938
|
/>
|
|
846
939
|
<DialogContent
|
|
940
|
+
ref="contentRef"
|
|
847
941
|
class="lp-cmd-dialog fixed left-1/2 top-[12vh] flex max-h-[76vh] -translate-x-1/2 flex-col overflow-hidden rounded-card border border-line shadow-panel outline-none data-[state=open]:animate-[pop-in_160ms_var(--ease-emphasized)] data-[state=closed]:animate-[pop-out_130ms_ease]"
|
|
848
942
|
:class="[frosted ? (layer.nested ? 'lp-glass-overlay--nested' : 'lp-glass-overlay') : 'bg-surface-raised', previewPane && 'lp-cmd-split']"
|
|
849
943
|
:style="{ zIndex: layer.panel }"
|
|
@@ -851,8 +945,8 @@ useHotkeys(() =>
|
|
|
851
945
|
@open-auto-focus.prevent
|
|
852
946
|
@keydown.capture="onPaletteKeydown"
|
|
853
947
|
>
|
|
854
|
-
<DialogTitle class="sr-only">
|
|
855
|
-
<DialogDescription class="sr-only">
|
|
948
|
+
<DialogTitle class="sr-only">{{ text.title }}</DialogTitle>
|
|
949
|
+
<DialogDescription class="sr-only">{{ text.description }}</DialogDescription>
|
|
856
950
|
|
|
857
951
|
<!-- Filter. The trail sits inside the box as chips, the way a scoped
|
|
858
952
|
search reads everywhere else: what you type is filtered by what is
|
|
@@ -895,7 +989,7 @@ useHotkeys(() =>
|
|
|
895
989
|
@keydown.esc="onEscape"
|
|
896
990
|
@keydown.tab="onTab"
|
|
897
991
|
/>
|
|
898
|
-
<kbd class="shrink-0 rounded border border-line px-1.5 py-0.5 text-[10px] text-muted">esc</kbd>
|
|
992
|
+
<kbd class="shrink-0 rounded border border-line px-1.5 py-0.5 text-[10px] text-muted">{{ text.esc }}</kbd>
|
|
899
993
|
</div>
|
|
900
994
|
|
|
901
995
|
<!-- Results -->
|
|
@@ -1024,8 +1118,8 @@ useHotkeys(() =>
|
|
|
1024
1118
|
<LpIcon v-if="active.icon" :name="active.icon" :size="16" class="shrink-0 text-muted" />
|
|
1025
1119
|
<h3 class="min-w-0 text-base font-semibold">{{ active.label }}</h3>
|
|
1026
1120
|
</div>
|
|
1027
|
-
<p v-if="
|
|
1028
|
-
{{
|
|
1121
|
+
<p v-if="paneDescription" class="lp-cmd-para mt-0.5 text-xs text-muted">
|
|
1122
|
+
{{ paneDescription }}
|
|
1029
1123
|
</p>
|
|
1030
1124
|
<p
|
|
1031
1125
|
v-for="(para, i) in paragraphs"
|
|
@@ -1045,9 +1139,10 @@ useHotkeys(() =>
|
|
|
1045
1139
|
</Transition>
|
|
1046
1140
|
</div>
|
|
1047
1141
|
|
|
1048
|
-
<!-- Footer hints
|
|
1142
|
+
<!-- Footer hints. Keyboard-only, so a touch screen without a keyboard
|
|
1143
|
+
gets the row back for results. -->
|
|
1049
1144
|
<div
|
|
1050
|
-
class="flex shrink-0 items-center gap-4 border-t border-line px-4 py-2.5 text-[11px] text-muted"
|
|
1145
|
+
class="flex shrink-0 items-center gap-4 border-t border-line px-4 py-2.5 text-[11px] text-muted [@media(hover:none)_and_(pointer:coarse)]:hidden"
|
|
1051
1146
|
>
|
|
1052
1147
|
<span class="flex items-center gap-1">
|
|
1053
1148
|
<kbd class="rounded border border-line px-1 text-[10px]">↑</kbd>
|
|
@@ -1069,7 +1164,7 @@ useHotkeys(() =>
|
|
|
1069
1164
|
{{ text.back }}
|
|
1070
1165
|
</span>
|
|
1071
1166
|
<span class="ml-auto flex items-center gap-1">
|
|
1072
|
-
<kbd class="rounded border border-line px-1 text-[10px]">esc</kbd>
|
|
1167
|
+
<kbd class="rounded border border-line px-1 text-[10px]">{{ text.esc }}</kbd>
|
|
1073
1168
|
{{ text.close }}
|
|
1074
1169
|
</span>
|
|
1075
1170
|
</div>
|