@leavepulse/ui 0.43.4 → 0.44.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 +75 -7
- package/dist/assets/{LpCommandPalette-B-0Est4Z.css → LpCommandPalette-DCP5g2ik.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/{LpShortcutsDialog-C6YoQ8_M.css → LpShortcutsDialog-ChUyU7oV.css} +7 -7
- package/dist/assets/{LpSkeleton-D7xU8IPV.css → LpSkeleton-H3Z5dEIk.css} +4 -1
- package/dist/assets/{LpTable-BgPLJOXa.css → LpTable-DDQNdf86.css} +9 -9
- package/dist/chunks/ContextMenuItems-CrfeNPWT.js +123 -0
- package/dist/chunks/{LayoutCanvas-Dd20boUG.js → LayoutCanvas-D-jPOAvg.js} +26 -9
- package/dist/chunks/{LayoutNode-DGpZA9LX.js → LayoutNode-D8Xy9N-o.js} +20 -8
- package/dist/chunks/{LpActionBar-BlvtGB2P.js → LpActionBar-BbwCF6l5.js} +24 -10
- package/dist/chunks/{LpAddressInput-B-Zvxsn7.js → LpAddressInput-BrOqkZqg.js} +53 -48
- package/dist/chunks/{LpAlert-BAYHDSS1.js → LpAlert-DkOIjsbq.js} +15 -8
- package/dist/chunks/{LpAppShell-BGQVIY-3.js → LpAppShell-BUKPcHco.js} +51 -24
- package/dist/chunks/{LpAutocomplete-DExlIZe_.js → LpAutocomplete-DxV3Y9h4.js} +50 -23
- package/dist/chunks/{LpAvatar-B3-xAOH3.js → LpAvatar-ClBbEYZN.js} +17 -8
- package/dist/chunks/LpBreadcrumbs-B8IJgFIc.js +95 -0
- package/dist/chunks/{LpButton-5VXXCjwF.js → LpButton-kqJBHIIb.js} +44 -14
- package/dist/chunks/{LpCard-BhI1N_vL.js → LpCard-CpRByR0q.js} +1 -1
- package/dist/chunks/{LpCheckbox-CVccKYaH.js → LpCheckbox-DpqchzH4.js} +7 -3
- package/dist/chunks/{LpCodeBlock-Bo0B4TFR.js → LpCodeBlock-DeHJPq7p.js} +48 -16
- package/dist/chunks/{LpColorPicker-BlXea7LM.js → LpColorPicker-Bhf1qxhB.js} +32 -9
- package/dist/chunks/{LpConfirmDialog-Q-bxff8z.js → LpConfirmDialog-CIUOSnWo.js} +58 -16
- package/dist/chunks/LpConfirmHost-CDm0Wtpv.js +49 -0
- package/dist/chunks/LpContextMenu-DQw5dGfG.js +68 -0
- package/dist/chunks/LpDatePicker-Drirx1AK.js +191 -0
- package/dist/chunks/{LpDrawer-BZ6k3hvo.js → LpDrawer-bScx-KMO.js} +63 -26
- package/dist/chunks/{LpFileTree-_5vFBgaK.js → LpFileTree-CSI_5SK2.js} +23 -8
- package/dist/chunks/{LpFileTreeNode-BdcIYKIE.js → LpFileTreeNode-B4MiSQX2.js} +2 -2
- package/dist/chunks/LpFormField-CIk5qosh.js +87 -0
- package/dist/chunks/{LpInput-9EXWUM9B.js → LpInput-C0e8y8_d.js} +26 -11
- package/dist/chunks/{LpLightbox-2sYVMY-S.js → LpLightbox-Mr0W_6HK.js} +147 -60
- package/dist/chunks/{LpLink-DCND-zyu.js → LpLink-Krkjhe_y.js} +15 -6
- package/dist/chunks/{LpLogViewer-CaRy5MeS.js → LpLogViewer-YBOaFnc_.js} +68 -34
- package/dist/chunks/{LpMapPicker-ul4oYno6.js → LpMapPicker-NUzS9e37.js} +38 -13
- package/dist/chunks/{LpMediaGallery-FF-NquIo.js → LpMediaGallery-DfJmMW0I.js} +6 -3
- package/dist/chunks/{LpModal-Bt0pQCI_.js → LpModal-DPwGKBPv.js} +49 -26
- package/dist/chunks/{LpModalNav-YaifHrXC.js → LpModalNav-DPg5H9f3.js} +9 -6
- package/dist/chunks/{LpNotificationBell-DyGGsMAM.js → LpNotificationBell-t5yn-siX.js} +58 -24
- package/dist/chunks/{LpNumberField-CWuX08iX.js → LpNumberField-DWnQKktS.js} +20 -7
- 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-DFngX7Xo.js} +30 -19
- package/dist/chunks/{LpPasswordInput--sjYCkLS.js → LpPasswordInput-CWVDuBJ5.js} +10 -7
- package/dist/chunks/{LpPhoneInput-BDSKVl_z.js → LpPhoneInput-CD-ZTeSd.js} +57 -33
- package/dist/chunks/{LpPie-D6OnzwlJ.js → LpPie-BLco31Nx.js} +78 -21
- package/dist/chunks/{LpPopover-8268UmlC.js → LpPopover-p_e_shN3.js} +4 -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/{LpSegmented-fV0Sk92p.js → LpSegmented-Dejd7cIx.js} +7 -3
- package/dist/chunks/{LpSelect-ANIVtrpM.js → LpSelect-DrRD9I7L.js} +40 -18
- package/dist/chunks/{LpSidebar-ClBUwoEz.js → LpSidebar-BgwUNWpJ.js} +30 -22
- package/dist/chunks/{LpSidebarNav-llOcs_Fn.js → LpSidebarNav-Bqxz8aWT.js} +14 -9
- 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-dXtyrdX9.js} +1 -1
- package/dist/chunks/{LpSwitch-Blizvqyt.js → LpSwitch-B1aLKulj.js} +40 -26
- package/dist/chunks/{LpTableOfContents-CjvxPMpU.js → LpTableOfContents-BUcAfGPQ.js} +36 -41
- package/dist/chunks/{LpTabs-Cefe_lys.js → LpTabs-_qMVaZJ6.js} +19 -5
- package/dist/chunks/LpTextarea-yP8hGedR.js +77 -0
- package/dist/chunks/LpThemeProvider-Wjm7Tuit.js +35 -0
- package/dist/chunks/LpThemeSwitcher-CKLc10KZ.js +169 -0
- package/dist/chunks/{LpTilt-DuyKbpkA.js → LpTilt-B7KHX1zH.js} +2 -2
- package/dist/chunks/{LpTimeField-K6nAGboX.js → LpTimeField-C5HRgS5H.js} +13 -7
- package/dist/chunks/{LpToaster-gDB1EaU3.js → LpToaster--oT6lfhL.js} +57 -28
- package/dist/chunks/{LpTooltip-hCLPAqMG.js → LpTooltip-CBdzeKNf.js} +13 -6
- package/dist/chunks/LpTooltipProvider-CftjV7Xc.js +25 -0
- package/dist/chunks/{LpTopologyCanvas-Cm1L39uL.js → LpTopologyCanvas-DocsLal3.js} +6 -1
- package/dist/chunks/{LpUptimeBar-DvAMno0S.js → LpUptimeBar-DLtxOMRy.js} +43 -14
- package/dist/chunks/{LpThemeSwitcher-Cue-myST.js → useTheme-C8JHUlPM.js} +173 -215
- 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/LpCard.vue.js +1 -1
- package/dist/components/LpChart.vue.d.ts +31 -2
- package/dist/components/LpChart.vue.js +317 -95
- 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.js +1 -1
- package/dist/components/LpCommandPalette.vue.d.ts +8 -3
- package/dist/components/LpCommandPalette.vue.js +86 -72
- 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/LpDrawer.vue.d.ts +10 -0
- package/dist/components/LpDrawer.vue.js +1 -1
- package/dist/components/LpDropzone.vue.js +22 -6
- 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 +9 -0
- package/dist/components/LpFormField.vue.js +1 -1
- package/dist/components/LpImageEditor.vue.js +92 -57
- package/dist/components/LpInput.vue.d.ts +3 -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 +20 -2
- 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.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.js +1 -1
- package/dist/components/LpRadioGroup.vue.js +1 -1
- package/dist/components/LpSection.vue.d.ts +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 +1 -1
- package/dist/components/LpShortcutsDialog.vue.js +11 -8
- 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/LpSwitch.vue.js +1 -1
- package/dist/components/LpTable.vue.d.ts +23 -1
- package/dist/components/LpTable.vue.js +74 -36
- 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/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 +13 -0
- 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 +39 -4
- 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/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/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/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/sidebar.d.ts +7 -1
- package/dist/components/tableSort.d.ts +8 -0
- package/dist/components/tableSort.js +31 -0
- package/dist/composables/useField.d.ts +34 -0
- package/dist/composables/useField.js +45 -0
- package/dist/composables/useFormDraft.d.ts +10 -3
- package/dist/composables/useFormDraft.js +9 -14
- package/dist/composables/useHotkeys.d.ts +17 -1
- package/dist/composables/useHotkeys.js +55 -18
- package/dist/composables/useInputFilter.d.ts +17 -0
- package/dist/composables/useInputFilter.js +47 -10
- package/dist/composables/useLpConfig.d.ts +24 -0
- package/dist/composables/useLpConfig.js +44 -0
- package/dist/composables/useRovingFocus.js +7 -0
- 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/index.d.ts +32 -2
- package/dist/index.js +184 -137
- 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/useTheme.d.ts +32 -9
- package/package.json +8 -7
- package/src/component-names.ts +5 -7
- package/src/components/ContextMenuItems.vue +88 -0
- package/src/components/LayoutCanvas.vue +26 -6
- package/src/components/LayoutNode.vue +19 -2
- package/src/components/LpActionBar.vue +30 -7
- 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 +46 -10
- package/src/components/LpAvatar.vue +19 -5
- package/src/components/LpBreadcrumbs.vue +65 -41
- package/src/components/LpButton.vue +59 -13
- package/src/components/LpChart.vue +272 -28
- package/src/components/LpCheckbox.vue +7 -3
- package/src/components/LpCodeBlock.vue +50 -14
- package/src/components/LpColorPicker.vue +39 -9
- package/src/components/LpCommandPalette.vue +34 -13
- package/src/components/LpConfirmDialog.vue +68 -17
- package/src/components/LpConfirmHost.vue +59 -0
- package/src/components/LpContextMenu.vue +14 -115
- package/src/components/LpDatePicker.vue +99 -68
- package/src/components/LpDrawer.vue +56 -19
- package/src/components/LpDropzone.vue +21 -4
- package/src/components/LpFileTree.vue +33 -7
- package/src/components/LpFormField.vue +30 -7
- package/src/components/LpImageEditor.vue +96 -57
- package/src/components/LpInput.vue +18 -7
- package/src/components/LpLightbox.vue +140 -29
- package/src/components/LpLink.vue +24 -13
- package/src/components/LpLogViewer.vue +86 -17
- package/src/components/LpMapPicker.vue +36 -13
- package/src/components/LpMediaGallery.vue +8 -2
- package/src/components/LpModal.vue +53 -27
- package/src/components/LpModalNav.vue +5 -2
- package/src/components/LpNotificationBell.vue +63 -17
- 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 +53 -27
- package/src/components/LpPie.vue +94 -15
- package/src/components/LpPopover.vue +3 -0
- package/src/components/LpProgress.vue +5 -3
- package/src/components/LpRadioGroup.vue +9 -2
- package/src/components/LpSegmented.vue +12 -2
- package/src/components/LpSelect.vue +0 -0
- package/src/components/LpShortcutsDialog.vue +8 -3
- 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/LpSwitch.vue +30 -7
- package/src/components/LpTable.vue +91 -32
- package/src/components/LpTableOfContents.vue +50 -32
- package/src/components/LpTabs.vue +23 -6
- package/src/components/LpTextarea.vue +44 -6
- package/src/components/LpThemeProvider.vue +41 -0
- package/src/components/LpThemeSwitcher.vue +64 -17
- package/src/components/LpTilt.vue +2 -2
- package/src/components/LpTimeField.vue +14 -3
- package/src/components/LpToaster.vue +66 -26
- package/src/components/LpTooltip.vue +22 -5
- package/src/components/LpTooltipProvider.vue +24 -0
- package/src/components/LpTopologyCanvas.vue +12 -1
- package/src/components/LpUptimeBar.vue +46 -8
- package/src/components/chart.ts +77 -5
- package/src/components/codeHighlight.ts +111 -15
- package/src/components/color.ts +30 -9
- package/src/components/confirm.ts +58 -0
- package/src/components/countries.ts +12 -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/modalDepth.ts +48 -6
- package/src/components/otp.ts +16 -0
- package/src/components/sidebar.ts +7 -1
- package/src/components/tableSort.ts +37 -0
- package/src/composables/useField.ts +79 -0
- package/src/composables/useFormDraft.ts +25 -20
- package/src/composables/useHotkeys.ts +89 -18
- package/src/composables/useInputFilter.ts +77 -14
- package/src/composables/useLpConfig.ts +87 -0
- package/src/composables/useRovingFocus.ts +11 -0
- package/src/composables/useTilt.ts +5 -6
- package/src/composables/useToast.ts +56 -4
- package/src/composables/useZoomPan.ts +6 -6
- package/src/index.ts +37 -2
- package/src/layout/tree.ts +30 -0
- package/src/layout/useLayout.ts +68 -18
- package/src/nuxt.ts +59 -17
- package/src/runtime/config.plugin.ts +14 -0
- package/src/runtime/theme.plugin.ts +42 -22
- package/src/theme/useTheme.ts +206 -100
- 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/LpTextarea-t7F6gv8E.js +0 -47
|
@@ -38,10 +38,21 @@ import LpEmptyState from "./LpEmptyState.vue"
|
|
|
38
38
|
import LpFileTreeNode from "./LpFileTreeNode.vue"
|
|
39
39
|
import LpScrollArea from "./LpScrollArea.vue"
|
|
40
40
|
import { useMergedAttrs } from "../composables/useMergedClass"
|
|
41
|
+
import { useLabels } from "../composables/useLpConfig"
|
|
41
42
|
|
|
42
43
|
export type { FileNode } from "./fileTree"
|
|
43
44
|
|
|
44
45
|
/** Rolled-up stats for the ticked entries — what a backup picker summarises. */
|
|
46
|
+
export interface FileTreeLabels {
|
|
47
|
+
[key: string]: string
|
|
48
|
+
empty: string
|
|
49
|
+
emptyDescription: string
|
|
50
|
+
file: string
|
|
51
|
+
files: string
|
|
52
|
+
folder: string
|
|
53
|
+
folders: string
|
|
54
|
+
}
|
|
55
|
+
|
|
45
56
|
export interface FileTreeSummary {
|
|
46
57
|
/** Ticked files (directories excluded — they're containers, not payload). */
|
|
47
58
|
files: number
|
|
@@ -84,6 +95,7 @@ const props = withDefaults(
|
|
|
84
95
|
/** Empty-state copy when `nodes` is empty. */
|
|
85
96
|
emptyLabel?: string
|
|
86
97
|
emptyDescription?: string
|
|
98
|
+
labels?: Partial<FileTreeLabels>
|
|
87
99
|
}>(),
|
|
88
100
|
{
|
|
89
101
|
sort: true,
|
|
@@ -93,8 +105,6 @@ const props = withDefaults(
|
|
|
93
105
|
showModified: false,
|
|
94
106
|
loading: false,
|
|
95
107
|
skeletonRows: 8,
|
|
96
|
-
emptyLabel: "No files",
|
|
97
|
-
emptyDescription: "This folder is empty.",
|
|
98
108
|
},
|
|
99
109
|
)
|
|
100
110
|
|
|
@@ -131,6 +141,19 @@ watch(
|
|
|
131
141
|
},
|
|
132
142
|
)
|
|
133
143
|
|
|
144
|
+
const text = useLabels<FileTreeLabels>(
|
|
145
|
+
"fileTree",
|
|
146
|
+
{
|
|
147
|
+
empty: "No files",
|
|
148
|
+
emptyDescription: "This folder is empty.",
|
|
149
|
+
file: "file",
|
|
150
|
+
files: "files",
|
|
151
|
+
folder: "folder",
|
|
152
|
+
folders: "folders",
|
|
153
|
+
},
|
|
154
|
+
() => props.labels,
|
|
155
|
+
)
|
|
156
|
+
|
|
134
157
|
const loadingSet = computed(() => new Set(props.loadingIds ?? []))
|
|
135
158
|
|
|
136
159
|
// Same controlled/uncontrolled deal as `expanded`.
|
|
@@ -229,7 +252,7 @@ const summary = computed<FileTreeSummary>(() => {
|
|
|
229
252
|
}
|
|
230
253
|
})
|
|
231
254
|
|
|
232
|
-
watch(summary, (value) => emit("summary", value), {
|
|
255
|
+
watch(summary, (value) => emit("summary", value), { immediate: true })
|
|
233
256
|
|
|
234
257
|
function setChecked(next: Set<string>) {
|
|
235
258
|
checkedIds.value = next
|
|
@@ -350,6 +373,9 @@ function expand(node: FileNode) {
|
|
|
350
373
|
|
|
351
374
|
function collapse(node: FileNode) {
|
|
352
375
|
if (!openIds.value.has(node.id)) return
|
|
376
|
+
// A fetch that failed left `children` unset; collapsing lets the next open
|
|
377
|
+
// ask again instead of showing an empty folder forever.
|
|
378
|
+
if (node.children === undefined && !loadingSet.value.has(node.id)) requested.delete(node.id)
|
|
353
379
|
const next = new Set(openIds.value)
|
|
354
380
|
next.delete(node.id)
|
|
355
381
|
setExpanded(next)
|
|
@@ -506,8 +532,8 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
|
|
|
506
532
|
<LpEmptyState
|
|
507
533
|
v-else-if="!roots.length"
|
|
508
534
|
icon="lucide:folder-search"
|
|
509
|
-
:title="emptyLabel"
|
|
510
|
-
:description="emptyDescription"
|
|
535
|
+
:title="emptyLabel ?? text.empty"
|
|
536
|
+
:description="emptyDescription ?? text.emptyDescription"
|
|
511
537
|
/>
|
|
512
538
|
|
|
513
539
|
<!-- h-full so the tree fills whatever box the caller gave it and the scroll
|
|
@@ -558,9 +584,9 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
|
|
|
558
584
|
class="shrink-0 border-t border-line px-2 py-1.5 text-xs text-muted"
|
|
559
585
|
>
|
|
560
586
|
<slot name="summary" v-bind="summary">
|
|
561
|
-
{{ summary.files }} {{ summary.files === 1 ?
|
|
587
|
+
{{ summary.files }} {{ summary.files === 1 ? text.file : text.files }}<template
|
|
562
588
|
v-if="summary.dirs"
|
|
563
|
-
>, {{ summary.dirs }} {{ summary.dirs === 1 ?
|
|
589
|
+
>, {{ summary.dirs }} {{ summary.dirs === 1 ? text.folder : text.folders }}</template>
|
|
564
590
|
<template v-if="summary.bytes !== undefined"> · {{ summary.sizeLabel }}</template>
|
|
565
591
|
</slot>
|
|
566
592
|
</div>
|
|
@@ -16,18 +16,41 @@ export default { inheritAttrs: false }
|
|
|
16
16
|
* eased box, so the thing being typed into never moves.
|
|
17
17
|
*/
|
|
18
18
|
import { Label } from "reka-ui"
|
|
19
|
-
import { useId } from "vue"
|
|
19
|
+
import { computed, useId, useSlots } from "vue"
|
|
20
20
|
import LpShift from "./LpShift.vue"
|
|
21
|
+
import { fieldMessageId, provideField } from "../composables/useField"
|
|
21
22
|
import { useMergedAttrs } from "../composables/useMergedClass"
|
|
22
23
|
|
|
23
|
-
defineProps<{
|
|
24
|
+
const props = defineProps<{
|
|
24
25
|
label?: string
|
|
25
26
|
hint?: string
|
|
26
27
|
error?: string
|
|
27
28
|
required?: boolean
|
|
29
|
+
/** Id of the control; generated when unset. The label points at it. */
|
|
30
|
+
id?: string
|
|
31
|
+
invalid?: boolean
|
|
32
|
+
disabled?: boolean
|
|
28
33
|
}>()
|
|
29
34
|
|
|
30
|
-
const
|
|
35
|
+
const generated = useId()
|
|
36
|
+
const id = computed(() => props.id ?? generated)
|
|
37
|
+
const messageId = computed(() => fieldMessageId(id.value))
|
|
38
|
+
const slots = useSlots()
|
|
39
|
+
const hasMessage = computed(() => !!props.error || !!props.hint || !!slots.hint)
|
|
40
|
+
|
|
41
|
+
// The control inside reads its id, description and states from here, so the
|
|
42
|
+
// label, the message line and aria-invalid stay tied to it without the
|
|
43
|
+
// consumer threading ids by hand.
|
|
44
|
+
provideField(
|
|
45
|
+
computed(() => ({
|
|
46
|
+
id: id.value,
|
|
47
|
+
labelId: props.label ? `${id.value}-label` : undefined,
|
|
48
|
+
describedBy: hasMessage.value ? messageId.value : undefined,
|
|
49
|
+
invalid: !!props.invalid || !!props.error,
|
|
50
|
+
required: !!props.required,
|
|
51
|
+
disabled: !!props.disabled,
|
|
52
|
+
})),
|
|
53
|
+
)
|
|
31
54
|
|
|
32
55
|
// The field stacks label and control with a fixed gap; a denser form needs that gap smaller.
|
|
33
56
|
const { class: rootClass, attrs: rest } = useMergedAttrs(
|
|
@@ -44,12 +67,12 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
|
|
|
44
67
|
<div
|
|
45
68
|
:class="rootClass"
|
|
46
69
|
v-bind="rest">
|
|
47
|
-
<Label v-if="label" :for="id" class="text-sm font-medium text-ink">
|
|
70
|
+
<Label v-if="label" :id="`${id}-label`" :for="id" class="text-sm font-medium text-ink">
|
|
48
71
|
{{ label }}
|
|
49
72
|
<span v-if="required" class="text-danger">*</span>
|
|
50
73
|
</Label>
|
|
51
74
|
|
|
52
|
-
<slot :id="id" />
|
|
75
|
+
<slot :id="id" :describedBy="hasMessage ? messageId : undefined" />
|
|
53
76
|
|
|
54
77
|
<!-- Swapping hint→error changes the text but not the height, so the eased
|
|
55
78
|
box only ever moves when a message appears or clears.
|
|
@@ -60,12 +83,12 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
|
|
|
60
83
|
leave every message-less field a row taller than before — and would be
|
|
61
84
|
a step the easing could not cover, since it exists even at height 0. -->
|
|
62
85
|
<LpShift axis="height">
|
|
63
|
-
<p v-if="error" class="pt-1.5 text-xs text-danger">{{ error }}</p>
|
|
86
|
+
<p v-if="error" :id="messageId" class="pt-1.5 text-xs text-danger">{{ error }}</p>
|
|
64
87
|
<!-- The hint is a slot as well as a prop: most are a sentence, but some
|
|
65
88
|
carry a link or a unit in <code>, and a prop can only be text. Callers
|
|
66
89
|
had been reaching for `#hint` on the assumption it existed — it
|
|
67
90
|
rendered nothing, so the explanation silently went missing. -->
|
|
68
|
-
<p v-else-if="hint || $slots.hint" class="pt-1.5 text-xs text-muted">
|
|
91
|
+
<p v-else-if="hint || $slots.hint" :id="messageId" class="pt-1.5 text-xs text-muted">
|
|
69
92
|
<slot name="hint">{{ hint }}</slot>
|
|
70
93
|
</p>
|
|
71
94
|
</LpShift>
|
|
@@ -24,6 +24,8 @@ export default { inheritAttrs: false }
|
|
|
24
24
|
* already know from every avatar cropper.
|
|
25
25
|
*/
|
|
26
26
|
import { computed, onBeforeUnmount, ref, shallowRef, watch } from "vue"
|
|
27
|
+
import { useLabels } from "../composables/useLpConfig"
|
|
28
|
+
import { coverScale, cropGeometry, isSideways } from "./imageCrop"
|
|
27
29
|
import { useHotkeys } from "../composables/useHotkeys"
|
|
28
30
|
import { useReveal } from "../composables/useReveal"
|
|
29
31
|
import { useZoomPan } from "../composables/useZoomPan"
|
|
@@ -81,15 +83,18 @@ const props = withDefaults(
|
|
|
81
83
|
// mount. An editor inside a dialog that opens a minute later still draws.
|
|
82
84
|
const { el: revealAnchor, revealed } = useReveal({ immediate: () => !props.animate })
|
|
83
85
|
|
|
84
|
-
const text =
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
86
|
+
const text = useLabels(
|
|
87
|
+
"imageEditor",
|
|
88
|
+
{
|
|
89
|
+
rotateLeft: "Rotate left",
|
|
90
|
+
rotateRight: "Rotate right",
|
|
91
|
+
zoomIn: "Zoom in",
|
|
92
|
+
zoomOut: "Zoom out",
|
|
93
|
+
reset: "Reset",
|
|
94
|
+
canvas: "Crop area — arrows pan, +/− zoom, R rotates, Alt+wheel turns freely",
|
|
95
|
+
},
|
|
96
|
+
() => props.labels,
|
|
97
|
+
)
|
|
93
98
|
|
|
94
99
|
const ASPECTS: Record<string, number | null> = {
|
|
95
100
|
free: null,
|
|
@@ -105,7 +110,24 @@ const rotation = ref(0)
|
|
|
105
110
|
const viewport = ref<HTMLElement | null>(null)
|
|
106
111
|
const zoom = useZoomPan({ min: 1, max: 6 })
|
|
107
112
|
|
|
108
|
-
|
|
113
|
+
const frameSize = ref<{ width: number; height: number } | null>(null)
|
|
114
|
+
let frameObserver: ResizeObserver | null = null
|
|
115
|
+
|
|
116
|
+
watch(viewport, (el) => {
|
|
117
|
+
zoom.setViewport(el)
|
|
118
|
+
frameObserver?.disconnect()
|
|
119
|
+
frameObserver = null
|
|
120
|
+
if (!el) return
|
|
121
|
+
// Fractional, not clientWidth: a rounded-down frame left a hairline of
|
|
122
|
+
// background showing along the edges of a turned picture.
|
|
123
|
+
frameSize.value = { width: el.clientWidth, height: el.clientHeight }
|
|
124
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
125
|
+
frameObserver = new ResizeObserver(([entry]) => {
|
|
126
|
+
frameSize.value = { width: entry.contentRect.width, height: entry.contentRect.height }
|
|
127
|
+
})
|
|
128
|
+
frameObserver.observe(el)
|
|
129
|
+
}
|
|
130
|
+
})
|
|
109
131
|
|
|
110
132
|
/** Which way up it ends, 0-270, whatever the accumulated angle. */
|
|
111
133
|
const upright = computed(() => ((rotation.value % 360) + 360) % 360)
|
|
@@ -114,14 +136,24 @@ const upright = computed(() => ((rotation.value % 360) + 360) % 360)
|
|
|
114
136
|
* back to where it started is not an edit, however far the dial travelled. */
|
|
115
137
|
const edited = computed(() => upright.value !== 0 || zoom.scale.value !== 1)
|
|
116
138
|
|
|
139
|
+
// Each file gets a generation: a slow decode of an earlier file must neither
|
|
140
|
+
// replace the current picture nor leak the bitmap it produced.
|
|
141
|
+
let generation = 0
|
|
142
|
+
|
|
117
143
|
watch(
|
|
118
144
|
() => props.file,
|
|
119
145
|
async (file) => {
|
|
120
146
|
revoke()
|
|
121
147
|
rotation.value = 0
|
|
122
148
|
zoom.reset()
|
|
149
|
+
const mine = ++generation
|
|
123
150
|
objectUrl.value = URL.createObjectURL(file)
|
|
124
|
-
|
|
151
|
+
const decoded = await decode(file, objectUrl.value)
|
|
152
|
+
if (mine !== generation) {
|
|
153
|
+
if (decoded instanceof ImageBitmap) decoded.close()
|
|
154
|
+
return
|
|
155
|
+
}
|
|
156
|
+
source.value = decoded
|
|
125
157
|
},
|
|
126
158
|
{ immediate: true },
|
|
127
159
|
)
|
|
@@ -172,7 +204,11 @@ function revoke() {
|
|
|
172
204
|
source.value = null
|
|
173
205
|
}
|
|
174
206
|
|
|
175
|
-
onBeforeUnmount(
|
|
207
|
+
onBeforeUnmount(() => {
|
|
208
|
+
generation++
|
|
209
|
+
revoke()
|
|
210
|
+
frameObserver?.disconnect()
|
|
211
|
+
})
|
|
176
212
|
|
|
177
213
|
function rotate(by: number) {
|
|
178
214
|
// Accumulated, never wrapped to 0-359. Normalising made the fourth quarter
|
|
@@ -218,7 +254,9 @@ const boxRatio = computed(() => {
|
|
|
218
254
|
if (ratio) return ratio
|
|
219
255
|
const size = sourceSize.value
|
|
220
256
|
if (!size) return 1
|
|
221
|
-
|
|
257
|
+
// Snapped to the nearest quarter: a few degrees of levelling must not flip a
|
|
258
|
+
// landscape frame to portrait.
|
|
259
|
+
const turned = isSideways(rotation.value)
|
|
222
260
|
const w = turned ? size.height : size.width
|
|
223
261
|
const h = turned ? size.width : size.height
|
|
224
262
|
return w / h
|
|
@@ -226,7 +264,31 @@ const boxRatio = computed(() => {
|
|
|
226
264
|
|
|
227
265
|
const frameStyle = computed(() => ({ aspectRatio: String(boxRatio.value) }))
|
|
228
266
|
|
|
267
|
+
/*
|
|
268
|
+
* The picture is sized to cover the frame AFTER its turn, and centred. Filling
|
|
269
|
+
* the frame with object-cover and then rotating the element left empty bands
|
|
270
|
+
* on any non-square frame turned sideways, and at a free angle bare corners.
|
|
271
|
+
*/
|
|
272
|
+
const sized = computed(() => {
|
|
273
|
+
const size = sourceSize.value
|
|
274
|
+
const frame = frameSize.value
|
|
275
|
+
if (!size || !frame || !frame.width || !frame.height) return null
|
|
276
|
+
const cover = coverScale(size.width, size.height, frame.width, frame.height, rotation.value)
|
|
277
|
+
const width = size.width * cover
|
|
278
|
+
const height = size.height * cover
|
|
279
|
+
return {
|
|
280
|
+
width: `${width}px`,
|
|
281
|
+
height: `${height}px`,
|
|
282
|
+
left: "50%",
|
|
283
|
+
top: "50%",
|
|
284
|
+
marginLeft: `${-width / 2}px`,
|
|
285
|
+
marginTop: `${-height / 2}px`,
|
|
286
|
+
maxWidth: "none",
|
|
287
|
+
}
|
|
288
|
+
})
|
|
289
|
+
|
|
229
290
|
const imageStyle = computed(() => ({
|
|
291
|
+
...sized.value,
|
|
230
292
|
...zoom.style.value,
|
|
231
293
|
// Rotation sits innermost, after the composable's scale and translate, so a
|
|
232
294
|
// drag still moves the picture the way the pointer went once it is turned.
|
|
@@ -254,51 +316,31 @@ async function exportImage(): Promise<Blob | null> {
|
|
|
254
316
|
if (!picture || !size || !frame) return null
|
|
255
317
|
if (!edited.value && props.aspect === "free") return null
|
|
256
318
|
|
|
257
|
-
//
|
|
258
|
-
//
|
|
259
|
-
//
|
|
260
|
-
const
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
// `offset` is in content pixels — the same space the cover scale maps from —
|
|
272
|
-
// so it converts with `cover`, not with the zoomed scale.
|
|
273
|
-
const centreX = clamp(
|
|
274
|
-
uprightW / 2 - zoom.offset.value.x / cover,
|
|
275
|
-
cropW / 2,
|
|
276
|
-
uprightW - cropW / 2,
|
|
277
|
-
)
|
|
278
|
-
const centreY = clamp(
|
|
279
|
-
uprightH / 2 - zoom.offset.value.y / cover,
|
|
280
|
-
cropH / 2,
|
|
281
|
-
uprightH - cropH / 2,
|
|
282
|
-
)
|
|
283
|
-
|
|
284
|
-
const scale = Math.min(1, props.maxEdge / Math.max(cropW, cropH))
|
|
319
|
+
// The crop in upright space, from the same geometry the preview is drawn
|
|
320
|
+
// with, then the whole source drawn through one transform: no per-quarter
|
|
321
|
+
// special cases, and a free angle comes out as it looked on screen.
|
|
322
|
+
const crop = cropGeometry({
|
|
323
|
+
sourceWidth: size.width,
|
|
324
|
+
sourceHeight: size.height,
|
|
325
|
+
frameWidth: frameSize.value?.width ?? frame.clientWidth,
|
|
326
|
+
frameHeight: frameSize.value?.height ?? frame.clientHeight,
|
|
327
|
+
rotation: rotation.value,
|
|
328
|
+
scale: zoom.scale.value,
|
|
329
|
+
offset: zoom.offset.value,
|
|
330
|
+
})
|
|
331
|
+
|
|
332
|
+
const scale = Math.min(1, props.maxEdge / Math.max(crop.width, crop.height))
|
|
285
333
|
const canvas = document.createElement("canvas")
|
|
286
|
-
canvas.width = Math.max(1, Math.round(
|
|
287
|
-
canvas.height = Math.max(1, Math.round(
|
|
334
|
+
canvas.width = Math.max(1, Math.round(crop.width * scale))
|
|
335
|
+
canvas.height = Math.max(1, Math.round(crop.height * scale))
|
|
288
336
|
const ctx = canvas.getContext("2d")
|
|
289
337
|
if (!ctx) return null
|
|
290
338
|
|
|
291
339
|
ctx.translate(canvas.width / 2, canvas.height / 2)
|
|
292
|
-
ctx.rotate((upright.value * Math.PI) / 180)
|
|
293
340
|
ctx.scale(scale, scale)
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
const readH = turned ? cropW : cropH
|
|
298
|
-
const readX = (turned ? centreY : centreX) - readW / 2
|
|
299
|
-
const readY = (turned ? centreX : centreY) - readH / 2
|
|
300
|
-
|
|
301
|
-
ctx.drawImage(picture, readX, readY, readW, readH, -readW / 2, -readH / 2, readW, readH)
|
|
341
|
+
ctx.translate(-crop.centre.x, -crop.centre.y)
|
|
342
|
+
ctx.rotate((rotation.value * Math.PI) / 180)
|
|
343
|
+
ctx.drawImage(picture, -size.width / 2, -size.height / 2)
|
|
302
344
|
|
|
303
345
|
return await new Promise<Blob | null>((resolve) =>
|
|
304
346
|
canvas.toBlob(resolve, outputType.value, props.quality),
|
|
@@ -312,10 +354,6 @@ const outputType = computed(() => {
|
|
|
312
354
|
return ENCODABLE.has(props.file.type) ? props.file.type : "image/png"
|
|
313
355
|
})
|
|
314
356
|
|
|
315
|
-
function clamp(value: number, low: number, high: number) {
|
|
316
|
-
return Math.min(Math.max(value, low), Math.max(low, high))
|
|
317
|
-
}
|
|
318
|
-
|
|
319
357
|
/*
|
|
320
358
|
* The wheel.
|
|
321
359
|
*
|
|
@@ -425,8 +463,9 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
|
|
|
425
463
|
:src="objectUrl"
|
|
426
464
|
alt=""
|
|
427
465
|
draggable="false"
|
|
428
|
-
class="lp-editor__image absolute
|
|
466
|
+
class="lp-editor__image absolute select-none motion-reduce:transition-none"
|
|
429
467
|
:class="[
|
|
468
|
+
sized ? '' : 'inset-0 size-full object-cover',
|
|
430
469
|
zoom.panning.value ? 'cursor-grabbing' : 'cursor-grab',
|
|
431
470
|
animate && !revealed ? 'lp-editor__image--waiting' : '',
|
|
432
471
|
]"
|
|
@@ -5,6 +5,7 @@ export default { inheritAttrs: false }
|
|
|
5
5
|
<script setup lang="ts">
|
|
6
6
|
import { tv, type VariantProps } from "tailwind-variants"
|
|
7
7
|
import { computed, ref, useAttrs, useSlots } from "vue"
|
|
8
|
+
import { useFieldControl } from "../composables/useField"
|
|
8
9
|
import { useInputFilter } from "../composables/useInputFilter"
|
|
9
10
|
import { mergeClass } from "../composables/useMergedClass"
|
|
10
11
|
import LpFormField from "./LpFormField.vue"
|
|
@@ -78,7 +79,7 @@ const props = withDefaults(
|
|
|
78
79
|
|
|
79
80
|
defineEmits<{ (e: "update:modelValue", value: string): void }>()
|
|
80
81
|
|
|
81
|
-
const { isInvalid, onBeforeInput, onPaste } = useInputFilter({
|
|
82
|
+
const { isInvalid, onBeforeInput, onInput: filterInput, onCompositionEnd, onPaste } = useInputFilter({
|
|
82
83
|
pattern: () => props.pattern,
|
|
83
84
|
restrict: () => props.restrict,
|
|
84
85
|
})
|
|
@@ -93,9 +94,15 @@ const hasTrailing = computed(() => !!slots.trailing)
|
|
|
93
94
|
const hasField = computed(
|
|
94
95
|
() => !!props.label || !!props.hint || !!props.error,
|
|
95
96
|
)
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
97
|
+
const field = useFieldControl(() => ({
|
|
98
|
+
wrapped: hasField.value,
|
|
99
|
+
hasMessage: !!props.error || !!props.hint,
|
|
100
|
+
id: typeof attrs.id === "string" ? attrs.id : undefined,
|
|
101
|
+
invalid: props.invalid || !!props.error || patternInvalid.value,
|
|
102
|
+
required: props.required,
|
|
103
|
+
disabled: props.disabled,
|
|
104
|
+
}))
|
|
105
|
+
const isInvalidState = computed(() => field.value.invalid)
|
|
99
106
|
const shellClass = computed(() =>
|
|
100
107
|
shell({ size: props.size, invalid: isInvalidState.value }),
|
|
101
108
|
)
|
|
@@ -126,6 +133,7 @@ defineExpose({
|
|
|
126
133
|
:hint="hasField ? hint : undefined"
|
|
127
134
|
:error="hasField ? error : undefined"
|
|
128
135
|
:required="hasField ? required : undefined"
|
|
136
|
+
:id="hasField ? field.id : undefined"
|
|
129
137
|
:class="hasField ? rootClass : undefined"
|
|
130
138
|
:style="hasField ? rootStyle : undefined"
|
|
131
139
|
>
|
|
@@ -140,12 +148,14 @@ defineExpose({
|
|
|
140
148
|
<input
|
|
141
149
|
ref="inputEl"
|
|
142
150
|
v-bind="inputAttrs"
|
|
151
|
+
:id="field.id"
|
|
143
152
|
:type="type"
|
|
144
153
|
:value="modelValue"
|
|
145
154
|
:placeholder="placeholder"
|
|
146
|
-
:disabled="disabled"
|
|
147
|
-
:required="required || undefined"
|
|
155
|
+
:disabled="field.disabled"
|
|
156
|
+
:required="field.required || undefined"
|
|
148
157
|
:aria-invalid="isInvalidState || undefined"
|
|
158
|
+
:aria-describedby="field.describedBy"
|
|
149
159
|
:class="[
|
|
150
160
|
'lp-autofill min-w-0 flex-1 self-stretch bg-transparent outline-none placeholder:text-muted',
|
|
151
161
|
hasLeading ? 'pl-2' : padX[size ?? 'md'],
|
|
@@ -153,7 +163,8 @@ defineExpose({
|
|
|
153
163
|
]"
|
|
154
164
|
@beforeinput="onBeforeInput"
|
|
155
165
|
@paste="onPaste"
|
|
156
|
-
@
|
|
166
|
+
@compositionend="onCompositionEnd"
|
|
167
|
+
@input="filterInput($event); $emit('update:modelValue', ($event.target as HTMLInputElement).value)"
|
|
157
168
|
/>
|
|
158
169
|
<slot name="trailing" />
|
|
159
170
|
</div>
|