@leavepulse/ui 0.43.4 → 0.45.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +121 -7
- package/dist/assets/{LpCommandPalette-B-0Est4Z.css → LpCommandPalette-nGNnzXqQ.css} +21 -21
- package/dist/assets/{LpDropzone-BBoWvi-J.css → LpDropzone-i4BdMi1H.css} +12 -12
- package/dist/assets/{LpImageEditor-Ct7Y3aNu.css → LpImageEditor-CbMA82g8.css} +6 -6
- package/dist/assets/{LpRollingText-CR1mb0Vt.css → LpRollingText-BGnE6q9j.css} +3 -0
- package/dist/assets/{LpShortcutsDialog-C6YoQ8_M.css → LpShortcutsDialog-CqYX3yy6.css} +28 -7
- package/dist/assets/{LpSkeleton-D7xU8IPV.css → LpSkeleton-H3Z5dEIk.css} +4 -1
- package/dist/assets/{LpTable-BgPLJOXa.css → LpTable-CPwWxTJS.css} +49 -9
- package/dist/chunks/ContextMenuItems-BtKU7074.js +124 -0
- package/dist/chunks/{LayoutCanvas-Dd20boUG.js → LayoutCanvas-BkaGXTjx.js} +26 -9
- package/dist/chunks/{LayoutNode-DGpZA9LX.js → LayoutNode-B3_9E1Xa.js} +28 -12
- package/dist/chunks/{LpActionBar-BlvtGB2P.js → LpActionBar-CnfFVIwC.js} +26 -12
- package/dist/chunks/{LpAddressInput-B-Zvxsn7.js → LpAddressInput-BwX8uo4_.js} +54 -49
- package/dist/chunks/{LpAlert-BAYHDSS1.js → LpAlert-B6ilrM7T.js} +16 -9
- package/dist/chunks/{LpAppShell-BGQVIY-3.js → LpAppShell-C53_RaGF.js} +53 -26
- package/dist/chunks/{LpAutocomplete-DExlIZe_.js → LpAutocomplete-C8IgSMsi.js} +52 -24
- package/dist/chunks/{LpAvatar-B3-xAOH3.js → LpAvatar-C1XStdOo.js} +19 -10
- package/dist/chunks/LpBreadcrumbs-CQJd73Gm.js +95 -0
- package/dist/chunks/{LpButton-5VXXCjwF.js → LpButton-CKSwC6Mu.js} +45 -15
- package/dist/chunks/{LpCalendar-B7Ko5RdR.js → LpCalendar-DrA2McTU.js} +1 -1
- package/dist/chunks/{LpCard-BhI1N_vL.js → LpCard-C2IvucmX.js} +1 -1
- package/dist/chunks/{LpCheckbox-CVccKYaH.js → LpCheckbox-Bkj13CbW.js} +8 -4
- package/dist/chunks/{LpCodeBlock-Bo0B4TFR.js → LpCodeBlock-ca7ANFyW.js} +49 -17
- package/dist/chunks/{LpColorPicker-BlXea7LM.js → LpColorPicker-zz4VGkG4.js} +75 -26
- package/dist/chunks/{LpConfirmDialog-Q-bxff8z.js → LpConfirmDialog-DCw5jR1t.js} +59 -17
- package/dist/chunks/LpConfirmHost-CbywMpMP.js +49 -0
- package/dist/chunks/LpContextMenu-BqkAYa9X.js +69 -0
- package/dist/chunks/LpDatePicker-DuusgT69.js +195 -0
- package/dist/chunks/LpDateRangePicker-DHeuznfC.js +208 -0
- package/dist/chunks/{LpDisclosure-ChQYmjlR.js → LpDisclosure-Cc23-JOT.js} +1 -1
- package/dist/chunks/{LpDrawer-BZ6k3hvo.js → LpDrawer-Dt4aB4Fr.js} +65 -28
- package/dist/chunks/{LpDropdownMenu-DJpoqRCb.js → LpDropdownMenu-DdJGQzPn.js} +2 -1
- package/dist/chunks/{LpEmptyState-Dsdqz1Wj.js → LpEmptyState-BJbZXC8D.js} +1 -1
- package/dist/chunks/LpFieldNotice-wtieLUTj.js +64 -0
- package/dist/chunks/{LpFileTree-_5vFBgaK.js → LpFileTree-CNurOvkV.js} +25 -10
- package/dist/chunks/{LpFileTreeNode-BdcIYKIE.js → LpFileTreeNode-D_qRRdsH.js} +3 -3
- package/dist/chunks/LpFormField-CtVYj6tO.js +101 -0
- package/dist/chunks/{LpIcon-CCnX5_2j.js → LpIcon-DYtaid0K.js} +20 -6
- package/dist/chunks/{LpInput-9EXWUM9B.js → LpInput-D-YGQbEv.js} +58 -20
- package/dist/chunks/{LpLightbox-2sYVMY-S.js → LpLightbox-DSDahF23.js} +148 -61
- package/dist/chunks/{LpLink-DCND-zyu.js → LpLink-Krkjhe_y.js} +15 -6
- package/dist/chunks/{LpLogViewer-CaRy5MeS.js → LpLogViewer-KypbgOyo.js} +300 -72
- package/dist/chunks/{LpMapPicker-ul4oYno6.js → LpMapPicker-Cc84LaM3.js} +39 -14
- package/dist/chunks/{LpMediaGallery-FF-NquIo.js → LpMediaGallery-YKr-cQPN.js} +7 -4
- package/dist/chunks/{LpModal-Bt0pQCI_.js → LpModal-DMMDQHAu.js} +52 -29
- package/dist/chunks/{LpModalNav-YaifHrXC.js → LpModalNav-BVPDyIup.js} +10 -7
- package/dist/chunks/{LpNotificationBell-DyGGsMAM.js → LpNotificationBell-CCwyJP5C.js} +79 -33
- package/dist/chunks/{LpNumberField-CWuX08iX.js → LpNumberField-B77O-z28.js} +21 -8
- package/dist/chunks/{LpNumberFlow-amWYaeuA.js → LpNumberFlow-z4WPZcZu.js} +22 -12
- package/dist/chunks/{LpOtpInput-y2v-pmiN.js → LpOtpInput-CziPF3Oq.js} +37 -8
- package/dist/chunks/{LpPagination-5FxjmmB5.js → LpPagination-BcDlo3r_.js} +31 -20
- package/dist/chunks/{LpPasswordInput--sjYCkLS.js → LpPasswordInput-eKzQhbQP.js} +11 -8
- package/dist/chunks/LpPhoneInput-BCbrrhgE.js +336 -0
- package/dist/chunks/{LpPie-D6OnzwlJ.js → LpPie-BEJ2SfI6.js} +84 -28
- package/dist/chunks/{LpPopover-8268UmlC.js → LpPopover-DCKeqiVn.js} +5 -2
- package/dist/chunks/{LpProgress-Btq5W4Ut.js → LpProgress-CBU1iI69.js} +5 -4
- package/dist/chunks/{LpRadioGroup-xPIuVDO_.js → LpRadioGroup-DmEW0l78.js} +9 -2
- package/dist/chunks/LpRangeCalendar-DZuaRV0W.js +331 -0
- package/dist/chunks/{LpRollingText-CM5gkSeF.js → LpRollingText-DB7upf-5.js} +1 -1
- package/dist/chunks/{LpScrollArea-D8xyKXcF.js → LpScrollArea-Bry1fdOM.js} +14 -2
- package/dist/chunks/{LpSection-aM6J_u51.js → LpSection-tKEH0jYf.js} +1 -1
- package/dist/chunks/{LpSegmented-fV0Sk92p.js → LpSegmented-C09EEam2.js} +8 -4
- package/dist/chunks/{LpSelect-ANIVtrpM.js → LpSelect-DNIL6MB9.js} +50 -31
- package/dist/chunks/{LpSidebar-ClBUwoEz.js → LpSidebar-CQNB0-yU.js} +30 -22
- package/dist/chunks/{LpSidebarNav-llOcs_Fn.js → LpSidebarNav-kx-LdqNU.js} +16 -11
- package/dist/chunks/{LpSkeleton-CTI-vBgW.js → LpSkeleton-BB6XIV-w.js} +1 -1
- package/dist/chunks/{LpSlider-BwNIBkAK.js → LpSlider-Cuzmrd7p.js} +7 -2
- package/dist/chunks/{LpSparkline-C6xQ2dwv.js → LpSparkline-CB80N8SJ.js} +11 -4
- package/dist/chunks/{LpStat-CQaW8R--.js → LpStat-B-7udBRP.js} +2 -2
- package/dist/chunks/{LpStepper-Bk-XaQYU.js → LpStepper-C7XiVKZj.js} +34 -19
- package/dist/chunks/{LpSwitch-Blizvqyt.js → LpSwitch-OrcOJX9m.js} +41 -27
- package/dist/chunks/LpTableFilter-BV8PpLM9.js +158 -0
- package/dist/chunks/{LpTableOfContents-CjvxPMpU.js → LpTableOfContents-BUcAfGPQ.js} +36 -41
- package/dist/chunks/{LpTabs-Cefe_lys.js → LpTabs-29iW1XOx.js} +20 -6
- package/dist/chunks/LpTagsInput-D1SuqbhB.js +300 -0
- package/dist/chunks/LpTextarea-uuScWo6-.js +77 -0
- package/dist/chunks/LpThemeProvider-Be4r2TQX.js +35 -0
- package/dist/chunks/LpThemeSwitcher-B4aVPbNC.js +166 -0
- package/dist/chunks/{LpTilt-DuyKbpkA.js → LpTilt-B7KHX1zH.js} +2 -2
- package/dist/chunks/{LpTimeField-K6nAGboX.js → LpTimeField-Cqe7fXnh.js} +14 -8
- package/dist/chunks/{LpToaster-gDB1EaU3.js → LpToaster-DpJvoCOh.js} +94 -31
- package/dist/chunks/{LpTooltip-hCLPAqMG.js → LpTooltip-CXVKcOXT.js} +14 -6
- package/dist/chunks/LpTooltipProvider-CftjV7Xc.js +25 -0
- package/dist/chunks/{LpTopologyCanvas-Cm1L39uL.js → LpTopologyCanvas-6ozNrQKh.js} +8 -2
- package/dist/chunks/{LpUptimeBar-DvAMno0S.js → LpUptimeBar-ugcv25xj.js} +44 -15
- package/dist/chunks/icons-CkA0njzm.js +43 -0
- package/dist/chunks/{LpThemeSwitcher-Cue-myST.js → useTheme-DJm1JSsY.js} +215 -260
- package/dist/component-names.d.ts +1 -1
- package/dist/components/ContextMenuItems.vue.d.ts +8 -0
- package/dist/components/ContextMenuItems.vue.js +4 -0
- package/dist/components/LayoutCanvas.vue.js +1 -1
- package/dist/components/LayoutNode.vue.d.ts +4 -0
- package/dist/components/LayoutNode.vue.js +1 -1
- package/dist/components/LpActionBar.vue.d.ts +3 -0
- package/dist/components/LpActionBar.vue.js +1 -1
- package/dist/components/LpAddressInput.vue.d.ts +1 -1
- package/dist/components/LpAddressInput.vue.js +1 -1
- package/dist/components/LpAlert.vue.d.ts +9 -0
- package/dist/components/LpAlert.vue.js +1 -1
- package/dist/components/LpAppShell.vue.d.ts +10 -0
- package/dist/components/LpAppShell.vue.js +1 -1
- package/dist/components/LpAutocomplete.vue.d.ts +31 -6
- package/dist/components/LpAutocomplete.vue.js +1 -1
- package/dist/components/LpAvatar.vue.d.ts +3 -3
- package/dist/components/LpAvatar.vue.js +1 -1
- package/dist/components/LpBadge.vue.d.ts +2 -2
- package/dist/components/LpBreadcrumbs.vue.d.ts +13 -9
- package/dist/components/LpBreadcrumbs.vue.js +1 -1
- package/dist/components/LpButton.vue.d.ts +35 -98
- package/dist/components/LpButton.vue.js +1 -1
- package/dist/components/LpCalendar.vue.js +1 -1
- package/dist/components/LpCard.vue.js +1 -1
- package/dist/components/LpChart.vue.d.ts +47 -3
- package/dist/components/LpChart.vue.js +377 -97
- package/dist/components/LpCheckbox.vue.js +1 -1
- package/dist/components/LpCodeBlock.vue.d.ts +2 -0
- package/dist/components/LpCodeBlock.vue.js +1 -1
- package/dist/components/LpColorPicker.vue.d.ts +2 -2
- package/dist/components/LpColorPicker.vue.js +1 -1
- package/dist/components/LpCommandPalette.vue.d.ts +14 -3
- package/dist/components/LpCommandPalette.vue.js +142 -77
- package/dist/components/LpConfirmDialog.vue.d.ts +15 -3
- package/dist/components/LpConfirmDialog.vue.js +1 -1
- package/dist/components/LpConfirmHost.vue.d.ts +9 -0
- package/dist/components/LpConfirmHost.vue.js +4 -0
- package/dist/components/LpContextMenu.vue.d.ts +3 -5
- package/dist/components/LpContextMenu.vue.js +1 -1
- package/dist/components/LpDatePicker.vue.d.ts +24 -6
- package/dist/components/LpDatePicker.vue.js +1 -1
- package/dist/components/LpDateRangePicker.vue.d.ts +60 -0
- package/dist/components/LpDateRangePicker.vue.js +4 -0
- package/dist/components/LpDisclosure.vue.js +1 -1
- package/dist/components/LpDrawer.vue.d.ts +10 -0
- package/dist/components/LpDrawer.vue.js +1 -1
- package/dist/components/LpDropdownMenu.vue.js +1 -1
- package/dist/components/LpDropzone.vue.js +23 -7
- package/dist/components/LpEmptyState.vue.js +1 -1
- package/dist/components/LpFieldNotice.vue.d.ts +8 -0
- package/dist/components/LpFieldNotice.vue.js +4 -0
- package/dist/components/LpFileTree.vue.d.ts +11 -2
- package/dist/components/LpFileTree.vue.js +1 -1
- package/dist/components/LpFileTreeNode.vue.js +1 -1
- package/dist/components/LpFormField.vue.d.ts +13 -1
- package/dist/components/LpFormField.vue.js +1 -1
- package/dist/components/LpIcon.vue.d.ts +0 -1
- package/dist/components/LpIcon.vue.js +1 -1
- package/dist/components/LpImageEditor.vue.js +93 -58
- package/dist/components/LpInput.vue.d.ts +22 -3
- package/dist/components/LpInput.vue.js +1 -1
- package/dist/components/LpLightbox.vue.d.ts +17 -0
- package/dist/components/LpLightbox.vue.js +1 -1
- package/dist/components/LpLink.vue.d.ts +11 -11
- package/dist/components/LpLink.vue.js +1 -1
- package/dist/components/LpLogViewer.vue.d.ts +72 -3
- package/dist/components/LpLogViewer.vue.js +1 -1
- package/dist/components/LpMapPicker.vue.d.ts +4 -4
- package/dist/components/LpMapPicker.vue.js +1 -1
- package/dist/components/LpMediaGallery.vue.js +1 -1
- package/dist/components/LpModal.vue.d.ts +16 -6
- package/dist/components/LpModal.vue.js +1 -1
- package/dist/components/LpModalNav.vue.d.ts +0 -1
- package/dist/components/LpModalNav.vue.js +1 -1
- package/dist/components/LpNotificationBell.vue.d.ts +11 -2
- package/dist/components/LpNotificationBell.vue.js +1 -1
- package/dist/components/LpNumberField.vue.d.ts +2 -0
- package/dist/components/LpNumberField.vue.js +1 -1
- package/dist/components/LpNumberFlow.vue.js +1 -1
- package/dist/components/LpOtpInput.vue.js +1 -1
- package/dist/components/LpPagination.vue.d.ts +2 -0
- package/dist/components/LpPagination.vue.js +1 -1
- package/dist/components/LpPasswordInput.vue.js +1 -1
- package/dist/components/LpPhoneInput.vue.d.ts +13 -0
- package/dist/components/LpPhoneInput.vue.js +1 -1
- package/dist/components/LpPie.vue.d.ts +21 -2
- package/dist/components/LpPie.vue.js +1 -1
- package/dist/components/LpPopover.vue.d.ts +2 -0
- package/dist/components/LpPopover.vue.js +1 -1
- package/dist/components/LpProgress.vue.d.ts +1 -1
- package/dist/components/LpProgress.vue.js +1 -1
- package/dist/components/LpRadioGroup.vue.js +1 -1
- package/dist/components/LpRangeCalendar.vue.d.ts +51 -0
- package/dist/components/LpRangeCalendar.vue.js +4 -0
- package/dist/components/LpRollingText.vue.d.ts +1 -1
- package/dist/components/LpRollingText.vue.js +1 -1
- package/dist/components/LpScrollArea.vue.d.ts +2 -2
- package/dist/components/LpScrollArea.vue.js +1 -1
- package/dist/components/LpSection.vue.d.ts +1 -1
- package/dist/components/LpSection.vue.js +1 -1
- package/dist/components/LpSegmented.vue.d.ts +5 -0
- package/dist/components/LpSegmented.vue.js +1 -1
- package/dist/components/LpSelect.vue.d.ts +1 -0
- package/dist/components/LpSelect.vue.js +1 -1
- package/dist/components/LpShortcutsDialog.vue.d.ts +7 -1
- package/dist/components/LpShortcutsDialog.vue.js +60 -15
- package/dist/components/LpSidebar.vue.d.ts +6 -2
- package/dist/components/LpSidebar.vue.js +1 -1
- package/dist/components/LpSidebarNav.vue.js +1 -1
- package/dist/components/LpSkeleton.vue.js +1 -1
- package/dist/components/LpSlider.vue.js +1 -1
- package/dist/components/LpSparkline.vue.d.ts +1 -0
- package/dist/components/LpSparkline.vue.js +1 -1
- package/dist/components/LpStat.vue.js +1 -1
- package/dist/components/LpStepper.vue.js +1 -1
- package/dist/components/LpSwitch.vue.js +1 -1
- package/dist/components/LpTable.vue.d.ts +107 -3
- package/dist/components/LpTable.vue.js +540 -128
- package/dist/components/LpTableFilter.vue.d.ts +31 -0
- package/dist/components/LpTableFilter.vue.js +4 -0
- package/dist/components/LpTableOfContents.vue.d.ts +4 -2
- package/dist/components/LpTableOfContents.vue.js +1 -1
- package/dist/components/LpTabs.vue.d.ts +2 -0
- package/dist/components/LpTabs.vue.js +1 -1
- package/dist/components/LpTagsInput.vue.d.ts +77 -0
- package/dist/components/LpTagsInput.vue.js +4 -0
- package/dist/components/LpTextarea.vue.d.ts +19 -6
- package/dist/components/LpTextarea.vue.js +1 -1
- package/dist/components/LpThemeProvider.vue.d.ts +22 -0
- package/dist/components/LpThemeProvider.vue.js +4 -0
- package/dist/components/LpThemeSwitcher.vue.d.ts +15 -2
- package/dist/components/LpThemeSwitcher.vue.js +1 -1
- package/dist/components/LpTilt.vue.js +1 -1
- package/dist/components/LpTimeField.vue.js +1 -1
- package/dist/components/LpToaster.vue.d.ts +6 -1
- package/dist/components/LpToaster.vue.js +1 -1
- package/dist/components/LpTooltip.vue.d.ts +1 -2
- package/dist/components/LpTooltip.vue.js +1 -1
- package/dist/components/LpTooltipProvider.vue.d.ts +22 -0
- package/dist/components/LpTooltipProvider.vue.js +4 -0
- package/dist/components/LpTopologyCanvas.vue.js +1 -1
- package/dist/components/LpUptimeBar.vue.d.ts +4 -0
- package/dist/components/LpUptimeBar.vue.js +1 -1
- package/dist/components/chart.d.ts +32 -1
- package/dist/components/chart.js +42 -6
- package/dist/components/codeHighlight.d.ts +6 -0
- package/dist/components/codeHighlight.js +92 -20
- package/dist/components/color.d.ts +1 -1
- package/dist/components/color.js +20 -9
- package/dist/components/commandSearch.js +3 -0
- package/dist/components/confirm.d.ts +25 -0
- package/dist/components/confirm.js +26 -0
- package/dist/components/countries.d.ts +6 -0
- package/dist/components/countries.js +7 -0
- package/dist/components/dateRange.d.ts +43 -0
- package/dist/components/dateRange.js +76 -0
- package/dist/components/exportData.d.ts +58 -0
- package/dist/components/exportData.js +165 -0
- package/dist/components/fileTree.js +16 -7
- package/dist/components/imageCrop.d.ts +42 -0
- package/dist/components/imageCrop.js +47 -0
- package/dist/components/link.d.ts +12 -0
- package/dist/components/link.js +19 -0
- package/dist/components/logSearch.d.ts +18 -0
- package/dist/components/logSearch.js +36 -0
- package/dist/components/modalDepth.d.ts +18 -2
- package/dist/components/modalDepth.js +17 -5
- package/dist/components/otp.d.ts +5 -0
- package/dist/components/otp.js +10 -0
- package/dist/components/phone.d.ts +41 -0
- package/dist/components/phone.js +80 -0
- package/dist/components/sidebar.d.ts +7 -1
- package/dist/components/tableFilter.d.ts +36 -0
- package/dist/components/tableFilter.js +84 -0
- package/dist/components/tableSort.d.ts +8 -0
- package/dist/components/tableSort.js +31 -0
- package/dist/components/tags.d.ts +20 -0
- package/dist/components/tags.js +37 -0
- package/dist/composables/useField.d.ts +38 -0
- package/dist/composables/useField.js +45 -0
- package/dist/composables/useFieldNotice.d.ts +17 -0
- package/dist/composables/useFieldNotice.js +28 -0
- package/dist/composables/useForm.d.ts +53 -0
- package/dist/composables/useForm.js +207 -0
- package/dist/composables/useFormDraft.d.ts +10 -3
- package/dist/composables/useFormDraft.js +9 -14
- package/dist/composables/useHotkeys.d.ts +81 -5
- package/dist/composables/useHotkeys.js +223 -25
- package/dist/composables/useInputFilter.d.ts +17 -0
- package/dist/composables/useInputFilter.js +47 -10
- package/dist/composables/useInputMask.d.ts +59 -0
- package/dist/composables/useInputMask.js +170 -0
- package/dist/composables/useLpConfig.d.ts +24 -0
- package/dist/composables/useLpConfig.js +44 -0
- package/dist/composables/usePaintSelect.d.ts +22 -0
- package/dist/composables/usePaintSelect.js +169 -0
- package/dist/composables/useRovingFocus.js +7 -0
- package/dist/composables/useShift.js +7 -2
- package/dist/composables/useTilt.d.ts +2 -2
- package/dist/composables/useTilt.js +5 -6
- package/dist/composables/useToast.d.ts +20 -0
- package/dist/composables/useToast.js +28 -4
- package/dist/composables/useZoomPan.d.ts +3 -3
- package/dist/composables/useZoomPan.js +4 -4
- package/dist/icons-all.d.ts +1 -0
- package/dist/icons-all.js +3 -0
- package/dist/icons.d.ts +14 -1
- package/dist/index.d.ts +60 -4
- package/dist/index.js +245 -141
- package/dist/kit-icons.d.ts +2 -0
- package/dist/layout/tree.d.ts +2 -0
- package/dist/layout/tree.js +16 -1
- package/dist/layout/useLayout.d.ts +15 -0
- package/dist/layout/useLayout.js +41 -14
- package/dist/theme/backdrop.d.ts +12 -0
- package/dist/theme/presets.d.ts +0 -2
- package/dist/theme/useTheme.d.ts +32 -9
- package/package.json +18 -8
- package/src/component-names.ts +9 -7
- package/src/components/ContextMenuItems.vue +88 -0
- package/src/components/LayoutCanvas.vue +26 -6
- package/src/components/LayoutNode.vue +30 -4
- package/src/components/LpActionBar.vue +31 -8
- package/src/components/LpAddressInput.vue +57 -41
- package/src/components/LpAlert.vue +16 -3
- package/src/components/LpAppShell.vue +45 -12
- package/src/components/LpAutocomplete.vue +47 -10
- package/src/components/LpAvatar.vue +20 -6
- package/src/components/LpBreadcrumbs.vue +65 -41
- package/src/components/LpButton.vue +60 -14
- package/src/components/LpChart.vue +351 -28
- package/src/components/LpCheckbox.vue +7 -3
- package/src/components/LpCodeBlock.vue +50 -14
- package/src/components/LpColorPicker.vue +73 -10
- package/src/components/LpCommandPalette.vue +115 -20
- package/src/components/LpConfirmDialog.vue +68 -17
- package/src/components/LpConfirmHost.vue +59 -0
- package/src/components/LpContextMenu.vue +15 -116
- package/src/components/LpDatePicker.vue +104 -68
- package/src/components/LpDateRangePicker.vue +224 -0
- package/src/components/LpDrawer.vue +56 -19
- package/src/components/LpDropdownMenu.vue +1 -0
- package/src/components/LpDropzone.vue +21 -4
- package/src/components/LpFieldNotice.vue +65 -0
- package/src/components/LpFileTree.vue +33 -7
- package/src/components/LpFormField.vue +59 -7
- package/src/components/LpIcon.vue +22 -4
- package/src/components/LpImageEditor.vue +96 -57
- package/src/components/LpInput.vue +62 -11
- package/src/components/LpLightbox.vue +140 -29
- package/src/components/LpLink.vue +24 -13
- package/src/components/LpLogViewer.vue +311 -39
- package/src/components/LpMapPicker.vue +36 -13
- package/src/components/LpMediaGallery.vue +8 -2
- package/src/components/LpModal.vue +54 -28
- package/src/components/LpModalNav.vue +5 -2
- package/src/components/LpNotificationBell.vue +77 -23
- package/src/components/LpNumberField.vue +21 -6
- package/src/components/LpNumberFlow.vue +26 -10
- package/src/components/LpOtpInput.vue +43 -8
- package/src/components/LpPagination.vue +23 -7
- package/src/components/LpPasswordInput.vue +4 -1
- package/src/components/LpPhoneInput.vue +224 -39
- package/src/components/LpPie.vue +102 -20
- package/src/components/LpPopover.vue +4 -0
- package/src/components/LpProgress.vue +5 -3
- package/src/components/LpRadioGroup.vue +9 -2
- package/src/components/LpRangeCalendar.vue +365 -0
- package/src/components/LpRollingText.vue +3 -0
- package/src/components/LpScrollArea.vue +22 -2
- package/src/components/LpSegmented.vue +12 -2
- package/src/components/LpSelect.vue +0 -0
- package/src/components/LpShortcutsDialog.vue +83 -9
- package/src/components/LpSidebar.vue +14 -9
- package/src/components/LpSidebarNav.vue +17 -5
- package/src/components/LpSkeleton.vue +4 -1
- package/src/components/LpSlider.vue +7 -1
- package/src/components/LpSparkline.vue +11 -3
- package/src/components/LpStepper.vue +23 -10
- package/src/components/LpSwitch.vue +31 -8
- package/src/components/LpTable.vue +668 -90
- package/src/components/LpTableFilter.vue +175 -0
- package/src/components/LpTableOfContents.vue +50 -32
- package/src/components/LpTabs.vue +23 -6
- package/src/components/LpTagsInput.vue +364 -0
- package/src/components/LpTextarea.vue +44 -6
- package/src/components/LpThemeProvider.vue +41 -0
- package/src/components/LpThemeSwitcher.vue +76 -33
- package/src/components/LpTilt.vue +2 -2
- package/src/components/LpTimeField.vue +14 -3
- package/src/components/LpToaster.vue +115 -27
- package/src/components/LpTooltip.vue +29 -5
- package/src/components/LpTooltipProvider.vue +24 -0
- package/src/components/LpTopologyCanvas.vue +19 -2
- package/src/components/LpUptimeBar.vue +46 -8
- package/src/components/chart.ts +82 -8
- package/src/components/codeHighlight.ts +111 -15
- package/src/components/color.ts +30 -9
- package/src/components/commandSearch.ts +6 -0
- package/src/components/confirm.ts +58 -0
- package/src/components/countries.ts +12 -0
- package/src/components/dateRange.ts +134 -0
- package/src/components/exportData.ts +228 -0
- package/src/components/fileTree.ts +19 -7
- package/src/components/imageCrop.ts +107 -0
- package/src/components/link.ts +34 -0
- package/src/components/logSearch.ts +46 -0
- package/src/components/modalDepth.ts +48 -6
- package/src/components/otp.ts +16 -0
- package/src/components/phone.ts +140 -0
- package/src/components/sidebar.ts +7 -1
- package/src/components/tableFilter.ts +122 -0
- package/src/components/tableSort.ts +37 -0
- package/src/components/tags.ts +62 -0
- package/src/composables/useField.ts +83 -0
- package/src/composables/useFieldNotice.ts +59 -0
- package/src/composables/useForm.ts +314 -0
- package/src/composables/useFormDraft.ts +25 -20
- package/src/composables/useHotkeys.ts +355 -28
- package/src/composables/useInputFilter.ts +77 -14
- package/src/composables/useInputMask.ts +254 -0
- package/src/composables/useLpConfig.ts +87 -0
- package/src/composables/usePaintSelect.ts +243 -0
- package/src/composables/useRovingFocus.ts +11 -0
- package/src/composables/useShift.ts +13 -2
- package/src/composables/useTilt.ts +5 -6
- package/src/composables/useToast.ts +56 -4
- package/src/composables/useZoomPan.ts +6 -6
- package/src/iconSubset.d.mts +10 -0
- package/src/iconSubset.mjs +51 -0
- package/src/icons-all.ts +10 -0
- package/src/icons.ts +59 -8
- package/src/index.ts +73 -4
- package/src/kit-icons.ts +5 -0
- package/src/layout/tree.ts +30 -0
- package/src/layout/useLayout.ts +68 -18
- package/src/nuxt.ts +87 -17
- package/src/runtime/config.plugin.ts +14 -0
- package/src/runtime/theme.plugin.ts +43 -23
- package/src/theme/backdrop.ts +69 -0
- package/src/theme/presets.ts +6 -64
- package/src/theme/useTheme.ts +206 -100
- package/src/tokens/tokens.css +46 -0
- package/dist/chunks/LpBreadcrumbs-p4jHe_V-.js +0 -62
- package/dist/chunks/LpContextMenu-CwW1QXe_.js +0 -217
- package/dist/chunks/LpDatePicker-CwOToxGq.js +0 -164
- package/dist/chunks/LpFormField-CazBc2-a.js +0 -62
- package/dist/chunks/LpPhoneInput-BDSKVl_z.js +0 -209
- package/dist/chunks/LpTextarea-t7F6gv8E.js +0 -47
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
export default { inheritAttrs: false }
|
|
3
|
+
|
|
4
|
+
export interface RangeCalendarLabels extends Record<string, string> {
|
|
5
|
+
previous: string
|
|
6
|
+
next: string
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/** How a range changed: picked by two clicks, or an end reshaped. */
|
|
10
|
+
export type RangeChange = { via: "pick" | "drag" | "keyboard" }
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<script setup lang="ts">
|
|
14
|
+
/*
|
|
15
|
+
* Inline range calendar (reka RangeCalendar). Like LpCalendar the model is ISO
|
|
16
|
+
* strings, here `{ start, end }`, both inclusive. A range is emitted only once
|
|
17
|
+
* both ends are picked: the half-picked state lives inside the calendar, so a
|
|
18
|
+
* consumer never sees a range with a missing end.
|
|
19
|
+
*
|
|
20
|
+
* Ranges can be pressed out the way text is selected on a phone: drag across
|
|
21
|
+
* days to pick one, or grab either end of a finished range and drag it, across
|
|
22
|
+
* rows and into the other month; dragging past the other end flips them. Shift+arrows move the
|
|
23
|
+
* focused end from the keyboard. A reshape emits with `{ via: "drag" }` (or
|
|
24
|
+
* "keyboard"), so a popover around the calendar can stay open while the user
|
|
25
|
+
* fine-tunes instead of closing on the first nudge.
|
|
26
|
+
*/
|
|
27
|
+
import { type DateValue, getLocalTimeZone, today } from "@internationalized/date"
|
|
28
|
+
import {
|
|
29
|
+
type DateRange as RekaRange,
|
|
30
|
+
RangeCalendarCell,
|
|
31
|
+
RangeCalendarCellTrigger,
|
|
32
|
+
RangeCalendarGrid,
|
|
33
|
+
RangeCalendarGridBody,
|
|
34
|
+
RangeCalendarGridHead,
|
|
35
|
+
RangeCalendarGridRow,
|
|
36
|
+
RangeCalendarHeadCell,
|
|
37
|
+
RangeCalendarHeader,
|
|
38
|
+
RangeCalendarHeading,
|
|
39
|
+
RangeCalendarNext,
|
|
40
|
+
RangeCalendarPrev,
|
|
41
|
+
RangeCalendarRoot,
|
|
42
|
+
} from "reka-ui"
|
|
43
|
+
import { computed, nextTick, onBeforeUnmount, onMounted, ref, shallowRef, watch } from "vue"
|
|
44
|
+
import { useLabels } from "../composables/useLpConfig"
|
|
45
|
+
import { useMergedAttrs } from "../composables/useMergedClass"
|
|
46
|
+
import { type DateRange, normalizeRange, parseIsoDay, reshapeRange } from "./dateRange"
|
|
47
|
+
import LpIcon from "./LpIcon.vue"
|
|
48
|
+
|
|
49
|
+
const props = withDefaults(
|
|
50
|
+
defineProps<{
|
|
51
|
+
/** Selected range, ISO "YYYY-MM-DD" ends (v-model). */
|
|
52
|
+
modelValue?: DateRange
|
|
53
|
+
min?: string
|
|
54
|
+
max?: string
|
|
55
|
+
/** Days that cannot be picked at all. */
|
|
56
|
+
isDisabled?: (iso: string) => boolean
|
|
57
|
+
/** Days a range may not include (struck through, and a range cannot span them). */
|
|
58
|
+
isDateUnavailable?: (iso: string) => boolean
|
|
59
|
+
/** Months shown side by side. */
|
|
60
|
+
months?: number
|
|
61
|
+
/** Longest allowed range, in days. */
|
|
62
|
+
maximumDays?: number
|
|
63
|
+
locale?: string
|
|
64
|
+
weekdayFormat?: "narrow" | "short" | "long"
|
|
65
|
+
labels?: Partial<RangeCalendarLabels>
|
|
66
|
+
}>(),
|
|
67
|
+
{ months: 1, weekdayFormat: "short" },
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
const emit = defineEmits<{
|
|
71
|
+
(e: "update:modelValue", value: DateRange, change: RangeChange): void
|
|
72
|
+
}>()
|
|
73
|
+
|
|
74
|
+
const text = useLabels<RangeCalendarLabels>(
|
|
75
|
+
"rangeCalendar",
|
|
76
|
+
{ previous: "Previous month", next: "Next month" },
|
|
77
|
+
() => props.labels,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
function toReka(range: DateRange | undefined): RekaRange {
|
|
81
|
+
const r = normalizeRange(range)
|
|
82
|
+
return { start: parseIsoDay(r?.start), end: parseIsoDay(r?.end) }
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const draft = shallowRef<RekaRange>(toReka(props.modelValue))
|
|
86
|
+
watch(
|
|
87
|
+
() => [props.modelValue?.start, props.modelValue?.end],
|
|
88
|
+
() => {
|
|
89
|
+
draft.value = toReka(props.modelValue)
|
|
90
|
+
},
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
const placeholder = shallowRef<DateValue>(draft.value.start ?? today(getLocalTimeZone()))
|
|
94
|
+
|
|
95
|
+
function onUpdate(v: RekaRange | null) {
|
|
96
|
+
draft.value = v ?? { start: undefined, end: undefined }
|
|
97
|
+
if (v?.start && v.end) emit("update:modelValue", { start: v.start.toString(), end: v.end.toString() }, { via: "pick" })
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const committed = computed(() => normalizeRange(props.modelValue))
|
|
101
|
+
|
|
102
|
+
/** Whether a day may sit inside a reshaped range. */
|
|
103
|
+
function allowed(iso: string): boolean {
|
|
104
|
+
const day = parseIsoDay(iso)
|
|
105
|
+
if (!day) return false
|
|
106
|
+
if (minValue.value && day.compare(minValue.value) < 0) return false
|
|
107
|
+
if (maxValue.value && day.compare(maxValue.value) > 0) return false
|
|
108
|
+
return !(props.isDisabled?.(iso) ?? false)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function reshape(anchor: string, moving: string): DateRange | null {
|
|
112
|
+
return reshapeRange(anchor, moving, {
|
|
113
|
+
allowed,
|
|
114
|
+
unavailable: props.isDateUnavailable,
|
|
115
|
+
maximumDays: props.maximumDays,
|
|
116
|
+
})
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const root = ref<HTMLElement | null>(null)
|
|
120
|
+
|
|
121
|
+
/*
|
|
122
|
+
* Press-and-drag, the way a phone selects text. A press on either end of the
|
|
123
|
+
* range drags that end; a press anywhere else starts a new range that follows
|
|
124
|
+
* the pointer. A mouse or pen drags at once. A finger has to hold still for
|
|
125
|
+
* HOLD_MS first, so an ordinary swipe still scrolls the page; after that the
|
|
126
|
+
* page stops scrolling and the finger selects. A press that never moves stays
|
|
127
|
+
* an ordinary click for reka.
|
|
128
|
+
*/
|
|
129
|
+
const HOLD_MS = 320
|
|
130
|
+
const SLOP_PX = 8
|
|
131
|
+
|
|
132
|
+
/** The day the range pivots around while the pointer moves. */
|
|
133
|
+
let anchor: string | null = null
|
|
134
|
+
let pointerId = -1
|
|
135
|
+
let armed = false
|
|
136
|
+
let held = false
|
|
137
|
+
let dragged = false
|
|
138
|
+
let swallowClick = false
|
|
139
|
+
let lastDay = ""
|
|
140
|
+
let startX = 0
|
|
141
|
+
let startY = 0
|
|
142
|
+
let holdTimer: ReturnType<typeof setTimeout> | undefined
|
|
143
|
+
const dragging = ref(false)
|
|
144
|
+
|
|
145
|
+
function cellAt(x: number, y: number): HTMLElement | null {
|
|
146
|
+
const hit = document.elementFromPoint(x, y)
|
|
147
|
+
const cell = hit?.closest<HTMLElement>("[data-reka-calendar-cell-trigger]")
|
|
148
|
+
if (!cell || !root.value?.contains(cell)) return null
|
|
149
|
+
if (cell.hasAttribute("data-outside-view") || cell.hasAttribute("data-disabled")) return null
|
|
150
|
+
return cell
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function reset() {
|
|
154
|
+
if (holdTimer) clearTimeout(holdTimer)
|
|
155
|
+
holdTimer = undefined
|
|
156
|
+
anchor = null
|
|
157
|
+
armed = false
|
|
158
|
+
held = false
|
|
159
|
+
dragged = false
|
|
160
|
+
dragging.value = false
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function onPointerDown(e: PointerEvent) {
|
|
164
|
+
if (e.button !== 0) return
|
|
165
|
+
const cell = (e.target as Element | null)?.closest<HTMLElement>("[data-reka-calendar-cell-trigger]")
|
|
166
|
+
const day = cell?.dataset.value
|
|
167
|
+
if (!cell || !day || cell.hasAttribute("data-disabled") || cell.hasAttribute("data-unavailable")) return
|
|
168
|
+
reset()
|
|
169
|
+
const range = committed.value
|
|
170
|
+
const onEdge = !!range && (day === range.start || day === range.end)
|
|
171
|
+
anchor = onEdge && range ? (day === range.start ? range.end : range.start) : day
|
|
172
|
+
pointerId = e.pointerId
|
|
173
|
+
lastDay = day
|
|
174
|
+
startX = e.clientX
|
|
175
|
+
startY = e.clientY
|
|
176
|
+
// A finger on an end drags at once: the end cells don't pan the page
|
|
177
|
+
// (touch-none), so there is no swipe to tell it apart from.
|
|
178
|
+
if (e.pointerType !== "touch" || onEdge) {
|
|
179
|
+
armed = true
|
|
180
|
+
return
|
|
181
|
+
}
|
|
182
|
+
holdTimer = setTimeout(() => {
|
|
183
|
+
holdTimer = undefined
|
|
184
|
+
armed = true
|
|
185
|
+
held = true
|
|
186
|
+
dragging.value = true
|
|
187
|
+
draft.value = toReka({ start: day, end: day })
|
|
188
|
+
navigator.vibrate?.(8)
|
|
189
|
+
}, HOLD_MS)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function onPointerMove(e: PointerEvent) {
|
|
193
|
+
if (anchor === null || e.pointerId !== pointerId) return
|
|
194
|
+
if (!armed) {
|
|
195
|
+
// Moved before the hold landed: that is a scroll, not a selection.
|
|
196
|
+
if (Math.hypot(e.clientX - startX, e.clientY - startY) > SLOP_PX) reset()
|
|
197
|
+
return
|
|
198
|
+
}
|
|
199
|
+
const day = cellAt(e.clientX, e.clientY)?.dataset.value
|
|
200
|
+
if (!day || day === lastDay) return
|
|
201
|
+
const next = reshape(anchor, day)
|
|
202
|
+
if (!next) return
|
|
203
|
+
lastDay = day
|
|
204
|
+
if (!dragged) {
|
|
205
|
+
dragged = true
|
|
206
|
+
dragging.value = true
|
|
207
|
+
// Capture keeps the drag alive past the grid's edge. A pointer the browser
|
|
208
|
+
// no longer tracks cannot be captured, and the drag works without it.
|
|
209
|
+
try {
|
|
210
|
+
root.value?.setPointerCapture(e.pointerId)
|
|
211
|
+
} catch {}
|
|
212
|
+
}
|
|
213
|
+
draft.value = toReka(next)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function onPointerUp(e: PointerEvent) {
|
|
217
|
+
if (anchor === null || e.pointerId !== pointerId) return
|
|
218
|
+
const finished = dragged || held
|
|
219
|
+
if (root.value?.hasPointerCapture(e.pointerId)) root.value.releasePointerCapture(e.pointerId)
|
|
220
|
+
reset()
|
|
221
|
+
if (!finished || e.type === "pointercancel") {
|
|
222
|
+
if (finished) draft.value = toReka(props.modelValue)
|
|
223
|
+
return
|
|
224
|
+
}
|
|
225
|
+
// The click that follows would read as "start a new range"; it is swallowed.
|
|
226
|
+
swallowClick = true
|
|
227
|
+
setTimeout(() => (swallowClick = false), 0)
|
|
228
|
+
const { start, end } = draft.value
|
|
229
|
+
if (start && end) emit("update:modelValue", { start: start.toString(), end: end.toString() }, { via: "drag" })
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function onClickCapture(e: MouseEvent) {
|
|
233
|
+
if (!swallowClick) return
|
|
234
|
+
swallowClick = false
|
|
235
|
+
e.stopPropagation()
|
|
236
|
+
e.preventDefault()
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Once a hold has turned a finger into a selection, the page must not scroll
|
|
240
|
+
// under it. Only a non-passive touchmove can say so mid-gesture.
|
|
241
|
+
function onTouchMove(e: TouchEvent) {
|
|
242
|
+
if (armed && anchor !== null) e.preventDefault()
|
|
243
|
+
}
|
|
244
|
+
function onContextMenu(e: Event) {
|
|
245
|
+
if (held || dragging.value) e.preventDefault()
|
|
246
|
+
}
|
|
247
|
+
onMounted(() => root.value?.addEventListener("touchmove", onTouchMove, { passive: false }))
|
|
248
|
+
onBeforeUnmount(() => {
|
|
249
|
+
root.value?.removeEventListener("touchmove", onTouchMove)
|
|
250
|
+
reset()
|
|
251
|
+
})
|
|
252
|
+
|
|
253
|
+
const STEP: Record<string, number> = { ArrowLeft: -1, ArrowRight: 1, ArrowUp: -7, ArrowDown: 7 }
|
|
254
|
+
|
|
255
|
+
function onKeydownCapture(e: KeyboardEvent) {
|
|
256
|
+
const step = STEP[e.key]
|
|
257
|
+
const range = committed.value
|
|
258
|
+
if (!e.shiftKey || step === undefined || !range) return
|
|
259
|
+
const day = (e.target as HTMLElement | null)?.dataset?.value
|
|
260
|
+
if (!day || (day !== range.start && day !== range.end)) return
|
|
261
|
+
const moved = parseIsoDay(day)?.add({ days: step }).toString()
|
|
262
|
+
if (!moved) return
|
|
263
|
+
e.preventDefault()
|
|
264
|
+
e.stopPropagation()
|
|
265
|
+
const other = day === range.start ? range.end : range.start
|
|
266
|
+
const next = reshape(other, moved)
|
|
267
|
+
if (!next) return
|
|
268
|
+
placeholder.value = parseIsoDay(moved) ?? placeholder.value
|
|
269
|
+
emit("update:modelValue", next, { via: "keyboard" })
|
|
270
|
+
void nextTick(() => root.value?.querySelector<HTMLElement>(`[data-value="${moved}"]:not([data-outside-view])`)?.focus())
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const minValue = computed(() => parseIsoDay(props.min))
|
|
274
|
+
const maxValue = computed(() => parseIsoDay(props.max))
|
|
275
|
+
const disabledFor = (date: DateValue) => props.isDisabled?.(date.toString()) ?? false
|
|
276
|
+
const unavailableFor = (date: DateValue) => props.isDateUnavailable?.(date.toString()) ?? false
|
|
277
|
+
|
|
278
|
+
const navBtn =
|
|
279
|
+
"flex size-8 items-center justify-center rounded-control text-muted outline-none transition-[color,background-color,scale] duration-[var(--duration-fast)] ease-[var(--ease-emphasized)] hover:bg-surface-soft hover:text-ink active:scale-90 motion-reduce:active:scale-100 focus-visible:ring-2 focus-visible:ring-ring"
|
|
280
|
+
|
|
281
|
+
const { class: rootClass, attrs: rest } = useMergedAttrs(
|
|
282
|
+
"inline-block rounded-card border border-line bg-surface-raised p-3",
|
|
283
|
+
)
|
|
284
|
+
</script>
|
|
285
|
+
|
|
286
|
+
<template>
|
|
287
|
+
<RangeCalendarRoot
|
|
288
|
+
v-slot="{ weekDays, grid }"
|
|
289
|
+
:ref="(c) => (root = (c as { $el?: HTMLElement } | null)?.$el ?? null)"
|
|
290
|
+
v-model:placeholder="placeholder"
|
|
291
|
+
:model-value="draft"
|
|
292
|
+
:min-value="minValue"
|
|
293
|
+
:max-value="maxValue"
|
|
294
|
+
:is-date-disabled="disabledFor"
|
|
295
|
+
:is-date-unavailable="unavailableFor"
|
|
296
|
+
:number-of-months="months"
|
|
297
|
+
:maximum-days="maximumDays"
|
|
298
|
+
:locale="locale"
|
|
299
|
+
:weekday-format="weekdayFormat"
|
|
300
|
+
prevent-deselect
|
|
301
|
+
paged-navigation
|
|
302
|
+
fixed-weeks
|
|
303
|
+
:class="rootClass"
|
|
304
|
+
v-bind="rest"
|
|
305
|
+
:data-dragging="dragging || undefined"
|
|
306
|
+
@update:model-value="onUpdate"
|
|
307
|
+
@pointerdown="onPointerDown"
|
|
308
|
+
@pointermove="onPointerMove"
|
|
309
|
+
@pointerup="onPointerUp"
|
|
310
|
+
@pointercancel="onPointerUp"
|
|
311
|
+
@click.capture="onClickCapture"
|
|
312
|
+
@contextmenu="onContextMenu"
|
|
313
|
+
@keydown.capture="onKeydownCapture"
|
|
314
|
+
>
|
|
315
|
+
<RangeCalendarHeader class="mb-2 flex items-center justify-between gap-2">
|
|
316
|
+
<RangeCalendarPrev :class="navBtn" :aria-label="text.previous">
|
|
317
|
+
<LpIcon name="lucide:chevron-left" :size="16" />
|
|
318
|
+
</RangeCalendarPrev>
|
|
319
|
+
<RangeCalendarHeading class="text-sm font-semibold text-ink" />
|
|
320
|
+
<RangeCalendarNext :class="navBtn" :aria-label="text.next">
|
|
321
|
+
<LpIcon name="lucide:chevron-right" :size="16" />
|
|
322
|
+
</RangeCalendarNext>
|
|
323
|
+
</RangeCalendarHeader>
|
|
324
|
+
|
|
325
|
+
<div class="flex gap-4">
|
|
326
|
+
<RangeCalendarGrid
|
|
327
|
+
v-for="month in grid"
|
|
328
|
+
:key="month.value.toString()"
|
|
329
|
+
class="border-collapse select-none"
|
|
330
|
+
>
|
|
331
|
+
<RangeCalendarGridHead>
|
|
332
|
+
<RangeCalendarGridRow class="mb-1 flex">
|
|
333
|
+
<RangeCalendarHeadCell
|
|
334
|
+
v-for="day in weekDays"
|
|
335
|
+
:key="day"
|
|
336
|
+
class="w-9 text-center text-[11px] font-medium text-muted"
|
|
337
|
+
>
|
|
338
|
+
{{ day }}
|
|
339
|
+
</RangeCalendarHeadCell>
|
|
340
|
+
</RangeCalendarGridRow>
|
|
341
|
+
</RangeCalendarGridHead>
|
|
342
|
+
<RangeCalendarGridBody>
|
|
343
|
+
<RangeCalendarGridRow v-for="(weekDates, i) in month.rows" :key="`w-${i}`" class="flex">
|
|
344
|
+
<RangeCalendarCell
|
|
345
|
+
v-for="weekDate in weekDates"
|
|
346
|
+
:key="weekDate.toString()"
|
|
347
|
+
:date="weekDate"
|
|
348
|
+
class="py-0.5"
|
|
349
|
+
>
|
|
350
|
+
<!-- Inside the range the pill joins its neighbours (no gap, no
|
|
351
|
+
rounding); the two ends keep the solid brand pill. The
|
|
352
|
+
preview while picking is lighter: with maximumDays reka
|
|
353
|
+
highlights the whole reachable window, not the range. -->
|
|
354
|
+
<RangeCalendarCellTrigger
|
|
355
|
+
:day="weekDate"
|
|
356
|
+
:month="month.value"
|
|
357
|
+
class="flex h-8 w-9 items-center justify-center rounded-control text-sm text-ink outline-none transition-[color,background-color] duration-[var(--duration-fast)] hover:bg-surface-soft focus-visible:ring-2 focus-visible:ring-ring data-[outside-view]:text-muted/40 data-[today]:font-semibold data-[today]:not-data-[selected]:text-brand data-[selected]:rounded-none data-[selected]:bg-brand-soft data-[highlighted]:rounded-none data-[highlighted]:bg-brand-soft/60 data-[selection-start]:rounded-l-control data-[highlighted-start]:rounded-l-control data-[selection-end]:rounded-r-control data-[highlighted-end]:rounded-r-control data-[selection-start]:bg-brand data-[selection-start]:font-semibold data-[selection-start]:text-ink-inverse data-[selection-end]:bg-brand data-[selection-end]:font-semibold data-[selection-end]:text-ink-inverse data-[outside-view]:data-[selected]:bg-transparent data-[outside-view]:data-[highlighted]:bg-transparent data-[disabled]:pointer-events-none data-[disabled]:opacity-35 data-[unavailable]:pointer-events-none data-[unavailable]:line-through data-[unavailable]:opacity-35 data-[selection-start]:cursor-grab data-[selection-end]:cursor-grab data-[selection-start]:touch-none data-[selection-end]:touch-none [-webkit-touch-callout:none] in-data-[dragging]:cursor-grabbing"
|
|
358
|
+
/>
|
|
359
|
+
</RangeCalendarCell>
|
|
360
|
+
</RangeCalendarGridRow>
|
|
361
|
+
</RangeCalendarGridBody>
|
|
362
|
+
</RangeCalendarGrid>
|
|
363
|
+
</div>
|
|
364
|
+
</RangeCalendarRoot>
|
|
365
|
+
</template>
|
|
@@ -55,6 +55,21 @@ const viewportEl = computed<HTMLElement | null>(
|
|
|
55
55
|
)
|
|
56
56
|
defineExpose({ viewportEl })
|
|
57
57
|
|
|
58
|
+
/*
|
|
59
|
+
* The viewport is focusable so the keyboard can scroll it, and Chrome marks it
|
|
60
|
+
* :focus-visible as soon as any key is pressed after a click inside, so the
|
|
61
|
+
* browser's white outline framed the whole page on the first shortcut. The
|
|
62
|
+
* ring is kept for focus that arrived by Tab and dropped for focus a pointer
|
|
63
|
+
* put there.
|
|
64
|
+
*/
|
|
65
|
+
const pointerFocus = ref(false)
|
|
66
|
+
function onViewportPointerDown() {
|
|
67
|
+
pointerFocus.value = true
|
|
68
|
+
}
|
|
69
|
+
function onViewportBlur() {
|
|
70
|
+
pointerFocus.value = false
|
|
71
|
+
}
|
|
72
|
+
|
|
58
73
|
// `opacity-0` + the hidden-state fade is what keeps the bar invisible at rest:
|
|
59
74
|
// with force-mount the element stays in the DOM, so a one-shot fade-out alone
|
|
60
75
|
// would snap back to visible once the animation finished.
|
|
@@ -241,10 +256,15 @@ function onThumbPointerDown() {
|
|
|
241
256
|
|
|
242
257
|
<ScrollAreaViewport
|
|
243
258
|
ref="viewportRef"
|
|
244
|
-
class="w-full min-h-0 min-w-0 flex-1 [&>div]:!block [&>div]:!min-w-0"
|
|
245
|
-
:class="
|
|
259
|
+
class="w-full min-h-0 min-w-0 flex-1 rounded-[inherit] outline-none [&>div]:!block [&>div]:!min-w-0"
|
|
260
|
+
:class="[
|
|
261
|
+
instant ? '' : 'scroll-smooth motion-reduce:scroll-auto',
|
|
262
|
+
pointerFocus ? '' : 'focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset',
|
|
263
|
+
]"
|
|
246
264
|
:style="fade ? { maskImage: fadeMask, WebkitMaskImage: fadeMask } : undefined"
|
|
247
265
|
@scroll.passive="onViewportScroll"
|
|
266
|
+
@pointerdown="onViewportPointerDown"
|
|
267
|
+
@focusout="(e: FocusEvent) => e.target === e.currentTarget && onViewportBlur()"
|
|
248
268
|
>
|
|
249
269
|
<div :class="contentClass">
|
|
250
270
|
<slot />
|
|
@@ -16,6 +16,7 @@ export default { inheritAttrs: false }
|
|
|
16
16
|
import { Motion } from "motion-v"
|
|
17
17
|
import { ToggleGroupItem, ToggleGroupRoot } from "reka-ui"
|
|
18
18
|
import { useId } from "vue"
|
|
19
|
+
import { useFieldControl } from "../composables/useField"
|
|
19
20
|
import { useMergedAttrs } from "../composables/useMergedClass"
|
|
20
21
|
import { usePillTransition } from "../composables/usePillTransition"
|
|
21
22
|
import LpIcon from "./LpIcon.vue"
|
|
@@ -25,6 +26,11 @@ export interface SegmentedOption {
|
|
|
25
26
|
label?: string
|
|
26
27
|
/** Optional iconify name shown before the label (or alone, icon-only). */
|
|
27
28
|
icon?: string
|
|
29
|
+
/**
|
|
30
|
+
* Accessible name for an icon-only segment. Without it the raw `value` is
|
|
31
|
+
* announced, which is an identifier rather than words.
|
|
32
|
+
*/
|
|
33
|
+
ariaLabel?: string
|
|
28
34
|
}
|
|
29
35
|
|
|
30
36
|
const props = withDefaults(
|
|
@@ -66,6 +72,8 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(() =>
|
|
|
66
72
|
].join(" "),
|
|
67
73
|
)
|
|
68
74
|
|
|
75
|
+
const field = useFieldControl(() => ({ wrapped: false, disabled: props.disabled }))
|
|
76
|
+
|
|
69
77
|
const pillId = `lp-segmented-${useId()}`
|
|
70
78
|
const pillTransition = usePillTransition()
|
|
71
79
|
</script>
|
|
@@ -74,7 +82,9 @@ const pillTransition = usePillTransition()
|
|
|
74
82
|
<ToggleGroupRoot
|
|
75
83
|
:model-value="modelValue"
|
|
76
84
|
type="single"
|
|
77
|
-
:disabled="disabled"
|
|
85
|
+
:disabled="field.disabled"
|
|
86
|
+
:aria-labelledby="field.labelId"
|
|
87
|
+
:aria-describedby="field.describedBy"
|
|
78
88
|
:rovingFocus="true"
|
|
79
89
|
:class="rootClass"
|
|
80
90
|
v-bind="rest"
|
|
@@ -84,7 +94,7 @@ const pillTransition = usePillTransition()
|
|
|
84
94
|
v-for="opt in options"
|
|
85
95
|
:key="opt.value"
|
|
86
96
|
:value="opt.value"
|
|
87
|
-
:aria-label="opt.label ? undefined : opt.value"
|
|
97
|
+
:aria-label="opt.ariaLabel ?? (opt.label ? undefined : opt.value)"
|
|
88
98
|
class="relative inline-flex h-full items-center justify-center gap-1.5 rounded-md px-3 font-medium outline-none transition-colors duration-[var(--duration-fast)] ease-[var(--ease-emphasized)] focus-visible:ring-2 focus-visible:ring-ring data-[state=on]:text-ink data-[state=off]:text-muted data-[state=off]:hover:text-ink disabled:cursor-not-allowed disabled:opacity-55"
|
|
89
99
|
:class="block ? 'flex-1' : ''"
|
|
90
100
|
>
|
|
Binary file
|
|
@@ -10,7 +10,10 @@
|
|
|
10
10
|
* of the same title merge, and a combo is listed once.
|
|
11
11
|
*
|
|
12
12
|
* Combos are written the way they read ("Ctrl+Shift+M", "Ctrl++", "←→↑↓") and
|
|
13
|
-
* split on "+" into one <kbd> each
|
|
13
|
+
* split on "+" into one <kbd> each; spaces separate the steps of a sequence
|
|
14
|
+
* ("G I" reads "G then I"). In `live` mode an entry whose keys another mounted
|
|
15
|
+
* binding also answers carries a marker, so a clash shows up where people
|
|
16
|
+
* look for keys rather than only in the console.
|
|
14
17
|
*/
|
|
15
18
|
import { computed } from "vue"
|
|
16
19
|
import LpModal from "./LpModal.vue"
|
|
@@ -18,8 +21,11 @@ import {
|
|
|
18
21
|
activeShortcuts,
|
|
19
22
|
appleModifierLabel,
|
|
20
23
|
mergeShortcutGroups,
|
|
24
|
+
useAppleKeyboard,
|
|
25
|
+
useHotkeys,
|
|
21
26
|
type ShortcutGroup,
|
|
22
27
|
} from "../composables/useHotkeys"
|
|
28
|
+
import { useLabels } from "../composables/useLpConfig"
|
|
23
29
|
|
|
24
30
|
const props = withDefaults(
|
|
25
31
|
defineProps<{
|
|
@@ -31,21 +37,54 @@ const props = withDefaults(
|
|
|
31
37
|
description?: string
|
|
32
38
|
/** Frosted glass panel, passed to LpModal. Follows `provideGlass` when unset. */
|
|
33
39
|
glass?: boolean
|
|
40
|
+
/**
|
|
41
|
+
* A key that toggles the reference, e.g. "F1". Bound only while the dialog
|
|
42
|
+
* is mounted, also inside inputs and over other overlays, and the browser's
|
|
43
|
+
* own use of the key (Chrome opens its help page on F1) is suppressed.
|
|
44
|
+
*/
|
|
45
|
+
hotkey?: string
|
|
34
46
|
}>(),
|
|
35
|
-
{ open: false, groups: () => [], live: false, title:
|
|
47
|
+
{ open: false, groups: () => [], live: false, title: undefined, glass: undefined },
|
|
36
48
|
)
|
|
37
49
|
|
|
50
|
+
const text = useLabels("shortcuts", {
|
|
51
|
+
title: "Keyboard shortcuts",
|
|
52
|
+
then: "then",
|
|
53
|
+
conflict: "Also bound elsewhere: only one of them runs",
|
|
54
|
+
group: "General",
|
|
55
|
+
})
|
|
56
|
+
const apple = useAppleKeyboard()
|
|
57
|
+
|
|
38
58
|
/*
|
|
39
59
|
* One key per "+", except a "+" that is the key itself: "Ctrl++" is Ctrl and
|
|
40
60
|
* plus, not Ctrl and two blanks.
|
|
41
61
|
*/
|
|
42
|
-
function keysOf(
|
|
43
|
-
return
|
|
62
|
+
function keysOf(chord: string): string[] {
|
|
63
|
+
return chord.split(/\+(?!$)/)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function stepsOf(combo: string): string[] {
|
|
67
|
+
return combo.trim().split(/\s+/)
|
|
44
68
|
}
|
|
45
69
|
|
|
46
70
|
const shown = computed(() => (props.live ? mergeShortcutGroups(props.groups, activeShortcuts.value) : props.groups))
|
|
47
71
|
|
|
48
72
|
const emit = defineEmits<{ (e: "update:open", value: boolean): void }>()
|
|
73
|
+
|
|
74
|
+
useHotkeys(() =>
|
|
75
|
+
props.hotkey
|
|
76
|
+
? [
|
|
77
|
+
{
|
|
78
|
+
key: props.hotkey,
|
|
79
|
+
allowInInput: true,
|
|
80
|
+
overLayers: true,
|
|
81
|
+
repeat: false,
|
|
82
|
+
help: { group: text.value.group, label: props.title ?? text.value.title },
|
|
83
|
+
handler: () => emit("update:open", !props.open),
|
|
84
|
+
},
|
|
85
|
+
]
|
|
86
|
+
: [],
|
|
87
|
+
)
|
|
49
88
|
</script>
|
|
50
89
|
|
|
51
90
|
<template>
|
|
@@ -53,7 +92,7 @@ const emit = defineEmits<{ (e: "update:open", value: boolean): void }>()
|
|
|
53
92
|
:glass="props.glass"
|
|
54
93
|
:open="props.open"
|
|
55
94
|
size="lg"
|
|
56
|
-
:title="props.title"
|
|
95
|
+
:title="props.title ?? text.title"
|
|
57
96
|
:description="props.description"
|
|
58
97
|
@update:open="(value: boolean) => emit('update:open', value)"
|
|
59
98
|
>
|
|
@@ -62,11 +101,23 @@ const emit = defineEmits<{ (e: "update:open", value: boolean): void }>()
|
|
|
62
101
|
<h3>{{ group.title }}</h3>
|
|
63
102
|
<dl>
|
|
64
103
|
<div v-for="entry in group.entries" :key="entry.combo" class="shortcut-row">
|
|
65
|
-
<dt>
|
|
104
|
+
<dt>
|
|
105
|
+
{{ entry.label }}
|
|
106
|
+
<span
|
|
107
|
+
v-if="entry.conflict"
|
|
108
|
+
class="shortcut-conflict"
|
|
109
|
+
role="img"
|
|
110
|
+
:aria-label="text.conflict"
|
|
111
|
+
:title="text.conflict"
|
|
112
|
+
>!</span>
|
|
113
|
+
</dt>
|
|
66
114
|
<dd>
|
|
67
|
-
<
|
|
68
|
-
{{
|
|
69
|
-
|
|
115
|
+
<template v-for="(step, stepIndex) in stepsOf(entry.combo)" :key="`${step}-${stepIndex}`">
|
|
116
|
+
<span v-if="stepIndex" class="shortcut-then">{{ text.then }}</span>
|
|
117
|
+
<kbd v-for="(key, index) in keysOf(step)" :key="`${key}-${index}`">
|
|
118
|
+
{{ appleModifierLabel(key.trim(), apple) }}
|
|
119
|
+
</kbd>
|
|
120
|
+
</template>
|
|
70
121
|
</dd>
|
|
71
122
|
</div>
|
|
72
123
|
</dl>
|
|
@@ -114,6 +165,29 @@ const emit = defineEmits<{ (e: "update:open", value: boolean): void }>()
|
|
|
114
165
|
min-width: 0;
|
|
115
166
|
}
|
|
116
167
|
|
|
168
|
+
.shortcut-conflict {
|
|
169
|
+
display: inline-flex;
|
|
170
|
+
width: 14px;
|
|
171
|
+
height: 14px;
|
|
172
|
+
margin-left: 6px;
|
|
173
|
+
align-items: center;
|
|
174
|
+
justify-content: center;
|
|
175
|
+
border-radius: 999px;
|
|
176
|
+
background: var(--color-danger-soft);
|
|
177
|
+
color: var(--color-danger);
|
|
178
|
+
font-size: 0.6rem;
|
|
179
|
+
font-weight: 700;
|
|
180
|
+
vertical-align: middle;
|
|
181
|
+
cursor: help;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.shortcut-then {
|
|
185
|
+
align-self: center;
|
|
186
|
+
padding: 0 2px;
|
|
187
|
+
color: var(--color-muted);
|
|
188
|
+
font-size: 0.68rem;
|
|
189
|
+
}
|
|
190
|
+
|
|
117
191
|
.shortcut-row dd {
|
|
118
192
|
display: flex;
|
|
119
193
|
flex-shrink: 0;
|