@leavepulse/ui 0.70.1 → 0.71.1
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 +91 -0
- package/dist/assets/{LpCommandPalette-u-zOxKWa.css → LpCommandPalette-DgPZX0us.css} +24 -17
- package/dist/assets/{LpPaletteFacts-B9FdVmIO.css → LpPaletteFacts-CVNh5ICn.css} +16 -16
- package/dist/assets/{LpPaletteStats-ClE-37MK.css → LpPaletteStats-ZiZmR6vz.css} +5 -5
- package/dist/assets/{LpTable-DHxEQ_-3.css → LpTable-DHvorDiU.css} +19 -19
- package/dist/assets/LpTabs-CO3EcsNV.css +18 -0
- package/dist/chunks/{ContextMenuItems-6kxEivBI.js → ContextMenuItems-eS7qx9gD.js} +1 -1
- package/dist/chunks/{DropzoneLinkField-Bw8Flkhk.js → DropzoneLinkField-DkFhdfEJ.js} +2 -2
- package/dist/chunks/{FieldWrapper-BiennROB.js → FieldWrapper-YzbvvC3M.js} +1 -1
- package/dist/chunks/{LayoutCanvas-BsJIzhdd.js → LayoutCanvas-Ba4A9QC5.js} +1 -1
- package/dist/chunks/{LayoutNode-DJVhkSGk.js → LayoutNode-CTTTLMDM.js} +1 -1
- package/dist/chunks/{LpActionBar-CzOFar5t.js → LpActionBar-B7anGlkI.js} +2 -2
- package/dist/chunks/{LpAddressInput-Chv_Xf8q.js → LpAddressInput-CD0bzrt-.js} +7 -7
- package/dist/chunks/{LpAlert-C5igj802.js → LpAlert-BHi7ARqu.js} +1 -1
- package/dist/chunks/{LpAppShell-BiWByLmt.js → LpAppShell-1RmBp6xQ.js} +3 -3
- package/dist/chunks/{LpAutocomplete-D92niDHE.js → LpAutocomplete-DDqe2M5g.js} +5 -2
- package/dist/chunks/{LpAvatar-CLPl-qOF.js → LpAvatar-DqfKCIdr.js} +1 -1
- package/dist/chunks/{LpBadge-BBq1Er9T.js → LpBadge-C8fKEmTF.js} +1 -1
- package/dist/chunks/{LpBreadcrumbs-JKEi_yFF.js → LpBreadcrumbs-DhcoStFa.js} +1 -1
- package/dist/chunks/{LpButton-CVxBfGjd.js → LpButton-BQDAFXBd.js} +3 -0
- package/dist/chunks/{LpCalendar-pVL91-Pl.js → LpCalendar-NmrA47J9.js} +1 -1
- package/dist/chunks/{LpCheckbox-DHc2bHDe.js → LpCheckbox-BoOuLnGB.js} +5 -2
- package/dist/chunks/{LpCodeBlock-BGsQhxw8.js → LpCodeBlock-Czu-fq1M.js} +2 -2
- package/dist/chunks/{LpCodeDisplay-CbJMs-IK.js → LpCodeDisplay-BK2FHbtM.js} +5 -5
- package/dist/chunks/{LpColorPicker-B7HSIFmn.js → LpColorPicker-Ee1DZiRd.js} +2 -2
- package/dist/chunks/LpCommandScope-ubtWDMa0.js +53 -0
- package/dist/chunks/{LpConfirmDialog-CfGCux8m.js → LpConfirmDialog-i15pulMT.js} +3 -3
- package/dist/chunks/{LpConfirmHost-exB7JmcO.js → LpConfirmHost-D0oGavtd.js} +1 -1
- package/dist/chunks/{LpContextMenu-Cj96ENDC.js → LpContextMenu-DXpFJjlO.js} +13 -3
- package/dist/chunks/{LpCopyButton-DzHjnFs0.js → LpCopyButton-Dmq7DmFw.js} +3 -3
- package/dist/chunks/{LpCountdown-BQnmB4gq.js → LpCountdown-DTdMF8DL.js} +1 -1
- package/dist/chunks/{LpDataList-CHNYQw7h.js → LpDataList-CFPtSsBB.js} +3 -3
- package/dist/chunks/{LpDatePicker-ac1_6o5P.js → LpDatePicker-cC9K-Pk8.js} +4 -4
- package/dist/chunks/{LpDateRangePicker-B15gYrZJ.js → LpDateRangePicker-BVQKPbvo.js} +2 -2
- package/dist/chunks/{LpDisclosure-DOarzlAG.js → LpDisclosure-hRnX3FWL.js} +4 -1
- package/dist/chunks/{LpDrawer-DGNKRsGq.js → LpDrawer-u4rxnuR-.js} +1 -1
- package/dist/chunks/{LpDropdownMenu-R4aYVtVV.js → LpDropdownMenu-BgZ0Z_Im.js} +13 -3
- package/dist/chunks/{LpEditable-Ws3DNQHn.js → LpEditable-CjxuOVh_.js} +2 -2
- package/dist/chunks/{LpEmptyState-KTKipws2.js → LpEmptyState-CKFTtQgJ.js} +1 -1
- package/dist/chunks/{LpFieldNotice-CurbNuXI.js → LpFieldNotice-CPI8EwtU.js} +1 -1
- package/dist/chunks/{LpFileTree-DDNg34tJ.js → LpFileTree-BH0gNlSJ.js} +2 -2
- package/dist/chunks/{LpFileTreeNode-DmPuYNZ_.js → LpFileTreeNode-gPVB1oXM.js} +4 -4
- package/dist/chunks/{LpFormField-BWwgm1E4.js → LpFormField-gRASfyj2.js} +4 -1
- package/dist/chunks/{LpGauge-C14Z9503.js → LpGauge-BdjPGnqw.js} +1 -1
- package/dist/chunks/{LpHintLayer-HvwUA5Ec.js → LpHintLayer-C2asBIfs.js} +2 -2
- package/dist/chunks/{LpHints-DxbPKOzQ.js → LpHints-CNZQ76JV.js} +3 -3
- package/dist/chunks/{LpIcon-HJP5xMz4.js → LpIcon-DkP-9mzK.js} +1 -1
- package/dist/chunks/{LpInfraNode-D64hywJI.js → LpInfraNode-yTh4-5qa.js} +2 -2
- package/dist/chunks/{LpInput-CDuwODJG.js → LpInput-2H-5ILOB.js} +5 -2
- package/dist/chunks/{LpLightbox-XJ0LpTcZ.js → LpLightbox-lAt5uIfx.js} +2 -2
- package/dist/chunks/{LpLogViewer-DKK4ySZl.js → LpLogViewer-x78YfhJf.js} +5 -5
- package/dist/chunks/{LpMapPicker-BtIl7NOM.js → LpMapPicker-Dp5RSCi9.js} +1 -1
- package/dist/chunks/{LpMediaGallery-rmI1DjKN.js → LpMediaGallery-D92oJfY_.js} +3 -3
- package/dist/chunks/{LpModal-eBMt2Fqn.js → LpModal-CpH0bNo7.js} +1 -1
- package/dist/chunks/{LpModalNav-DiyFCHiZ.js → LpModalNav-BH4ANQGJ.js} +4 -4
- package/dist/chunks/{LpNotificationBell-D-WhE5m2.js → LpNotificationBell-BdUQqZhs.js} +6 -6
- package/dist/chunks/{LpNumberField-B9k-h2HE.js → LpNumberField-DZY3Z670.js} +4 -1
- package/dist/chunks/{LpNumberFlow-Cfyh033Q.js → LpNumberFlow-5khYxsfX.js} +6 -3
- package/dist/chunks/{LpPagination-VNCX6pFC.js → LpPagination-DbeACavM.js} +1 -1
- package/dist/chunks/LpPaletteTheme-CqWNRwHE.js +104 -0
- package/dist/chunks/{LpPasswordInput-GL2KOFK8.js → LpPasswordInput-BzAZsf5V.js} +4 -2
- package/dist/chunks/{LpPhoneInput-C60tx1tC.js → LpPhoneInput-BMpd-0QR.js} +2 -2
- package/dist/chunks/{LpPie-BgXZ3xmm.js → LpPie-DdFSTbGE.js} +4 -4
- package/dist/chunks/{LpPipeline-B31h41Mu.js → LpPipeline-zjEM1Lwc.js} +3 -3
- package/dist/chunks/{LpProgress-CE-m5OpD.js → LpProgress-BX33EKkN.js} +1 -1
- package/dist/chunks/{LpQuota-DaL8TgNe.js → LpQuota-DqNv1yjs.js} +2 -2
- package/dist/chunks/{LpRadioGroup-CGBr5nIp.js → LpRadioGroup-CsXeV9Ct.js} +4 -1
- package/dist/chunks/{LpRangeCalendar-c5qj7YcC.js → LpRangeCalendar-l-0nSFmY.js} +1 -1
- package/dist/chunks/{LpRangeSlider-Dv6lNvHY.js → LpRangeSlider-CM-0ZITZ.js} +3 -0
- package/dist/chunks/{LpRelativeTime-yin9uQP7.js → LpRelativeTime-UM8EkfrN.js} +1 -1
- package/dist/chunks/{LpRepeater-D0S7jjwr.js → LpRepeater-OvzByE5L.js} +2 -2
- package/dist/chunks/{LpSecretField-CfWyHv9m.js → LpSecretField-DwQiPOko.js} +9 -7
- package/dist/chunks/{LpSection-BW4xJ-Li.js → LpSection-DcQsieHG.js} +1 -1
- package/dist/chunks/{LpSegmented-BO99Sr4m.js → LpSegmented-D2VST0o3.js} +4 -1
- package/dist/chunks/{LpSelect-C_8cJtj6.js → LpSelect-DYX2-u5A.js} +36 -6
- package/dist/chunks/{LpSidebar-CZRXtvem.js → LpSidebar-D44peKq2.js} +3 -3
- package/dist/chunks/{LpSidebarNav-DBg1U1oW.js → LpSidebarNav--VwkXO_a.js} +3 -3
- package/dist/chunks/{LpSlider-DuoRpOrH.js → LpSlider-DxYoCJJO.js} +3 -0
- package/dist/chunks/{LpStat-DFKlPJgy.js → LpStat-DIsQfbeD.js} +3 -3
- package/dist/chunks/{LpStatus-BsGLrpor.js → LpStatus-BQU1TUsv.js} +1 -1
- package/dist/chunks/{LpStepMark-TrzOioa9.js → LpStepMark-CXa7DJy_.js} +1 -1
- package/dist/chunks/{LpStepper-BbnS5jUr.js → LpStepper-C9RM_yTG.js} +1 -1
- package/dist/chunks/{LpSwitch-DrzKrZZV.js → LpSwitch-bGZxUDSx.js} +3 -0
- package/dist/chunks/{LpTableFilter-DyvHGbOk.js → LpTableFilter-CTZMqFDU.js} +2 -2
- package/dist/chunks/{LpTableOfContents-rYvo8z5T.js → LpTableOfContents-CraicEs4.js} +2 -2
- package/dist/chunks/{LpTagsInput-DZg80W-B.js → LpTagsInput-DrjmrOge.js} +8 -5
- package/dist/chunks/{LpTextarea-DiWjeVoJ.js → LpTextarea-BbYqmG1S.js} +4 -1
- package/dist/chunks/{LpThemeStudio-DxVZMtzN.js → LpThemeStudio-B2nPaG-h.js} +18 -14
- package/dist/chunks/{LpThemeSwitcher-CadVBTBn.js → LpThemeSwitcher-C0A5sg_E.js} +5 -3
- package/dist/chunks/{LpTimeField-BFQVf_PW.js → LpTimeField-DQ8WvPr2.js} +4 -1
- package/dist/chunks/{LpToaster-Wv9ksj4q.js → LpToaster-BTTl_wuy.js} +2 -2
- package/dist/chunks/{LpTooltip-Cz8SQwRt.js → LpTooltip-BcBvIx4z.js} +23 -5
- package/dist/chunks/{LpTopologyCanvas-C17A1XCb.js → LpTopologyCanvas-B0wEvAoq.js} +1 -1
- package/dist/chunks/{LpTour-CY2bFXge.js → LpTour-BgCfNlaW.js} +1 -1
- package/dist/chunks/{LpTruncate-D_5Pfv5B.js → LpTruncate-TcqfkyJM.js} +2 -2
- package/dist/chunks/{LpUptimeBar-Tew1Ykx4.js → LpUptimeBar-DRadGq4Y.js} +136 -47
- package/dist/chunks/{MenuTitle-BjQZX8tQ.js → MenuTitle-Dab3EGOp.js} +1 -1
- package/dist/chunks/{OptionContent-CmYUUeWj.js → OptionContent-DPzNsybd.js} +1 -1
- package/dist/chunks/PalettePreviewBoundary-B0Hhu3Yw.js +20 -0
- package/dist/chunks/{PickerField-DoHv0WMH.js → PickerField-DwLw7j0L.js} +1 -1
- package/dist/chunks/{RevealToggle-C-KzaQGJ.js → RevealToggle-BVFM_FAU.js} +3 -3
- package/dist/chunks/{TourCard-BJ8i7dk0.js → TourCard--2IfgnUU.js} +2 -2
- package/dist/chunks/icons-CLu1iR1j.js +43 -0
- package/dist/chunks/palette-BiY7yQZL.js +29 -0
- package/dist/component-names.d.ts +1 -1
- package/dist/components/ContextMenuItems.vue.js +1 -1
- package/dist/components/DropzoneLinkField.vue.js +1 -1
- package/dist/components/FieldWrapper.vue.js +1 -1
- package/dist/components/LayoutCanvas.vue.js +1 -1
- package/dist/components/LayoutNode.vue.js +1 -1
- 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 +3 -3
- package/dist/components/LpAlert.vue.js +1 -1
- package/dist/components/LpAppShell.vue.js +1 -1
- package/dist/components/LpAutocomplete.vue.d.ts +7 -1
- package/dist/components/LpAutocomplete.vue.js +1 -1
- package/dist/components/LpAvatar.vue.js +1 -1
- package/dist/components/LpBadge.vue.d.ts +2 -2
- package/dist/components/LpBadge.vue.js +1 -1
- package/dist/components/LpBreadcrumbs.vue.js +1 -1
- package/dist/components/LpButton.vue.d.ts +4 -0
- package/dist/components/LpButton.vue.js +1 -1
- package/dist/components/LpCalendar.vue.js +1 -1
- package/dist/components/LpChart.vue.js +2 -2
- package/dist/components/LpCheckbox.vue.d.ts +8 -1
- package/dist/components/LpCheckbox.vue.js +1 -1
- package/dist/components/LpCodeBlock.vue.js +1 -1
- package/dist/components/LpCodeDisplay.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 +43 -7
- package/dist/components/LpCommandPalette.vue.js +451 -126
- package/dist/components/LpCommandScope.vue.d.ts +28 -0
- package/dist/components/LpCommandScope.vue.js +4 -0
- package/dist/components/LpConfirmDialog.vue.js +1 -1
- package/dist/components/LpConfirmHost.vue.js +1 -1
- package/dist/components/LpContextMenu.vue.d.ts +5 -1
- package/dist/components/LpContextMenu.vue.js +1 -1
- package/dist/components/LpCopyButton.vue.d.ts +1 -1
- package/dist/components/LpCopyButton.vue.js +1 -1
- package/dist/components/LpCountdown.vue.js +1 -1
- package/dist/components/LpDataList.vue.js +1 -1
- package/dist/components/LpDatePicker.vue.js +1 -1
- package/dist/components/LpDateRangePicker.vue.js +1 -1
- package/dist/components/LpDisclosure.vue.d.ts +4 -0
- package/dist/components/LpDisclosure.vue.js +1 -1
- package/dist/components/LpDock.vue.js +2 -2
- package/dist/components/LpDrawer.vue.js +1 -1
- package/dist/components/LpDropdownMenu.vue.d.ts +5 -1
- package/dist/components/LpDropdownMenu.vue.js +1 -1
- package/dist/components/LpDropzone.vue.js +2 -2
- package/dist/components/LpEditable.vue.js +1 -1
- package/dist/components/LpEmptyState.vue.js +1 -1
- package/dist/components/LpFieldNotice.vue.js +1 -1
- package/dist/components/LpFileTree.vue.d.ts +1 -1
- package/dist/components/LpFileTree.vue.js +1 -1
- package/dist/components/LpFileTreeNode.vue.js +1 -1
- package/dist/components/LpFormField.vue.js +1 -1
- package/dist/components/LpGauge.vue.js +1 -1
- package/dist/components/LpHintLayer.vue.js +1 -1
- package/dist/components/LpHints.vue.js +1 -1
- package/dist/components/LpIcon.vue.js +1 -1
- package/dist/components/LpImageEditor.vue.js +3 -2
- package/dist/components/LpInfraNode.vue.js +1 -1
- package/dist/components/LpInput.vue.d.ts +6 -0
- package/dist/components/LpInput.vue.js +1 -1
- package/dist/components/LpLightbox.vue.js +1 -1
- package/dist/components/LpLoader.vue.d.ts +1 -1
- package/dist/components/LpLogViewer.vue.js +1 -1
- package/dist/components/LpMapPicker.vue.js +1 -1
- package/dist/components/LpMediaGallery.vue.d.ts +2 -2
- package/dist/components/LpMediaGallery.vue.js +1 -1
- package/dist/components/LpModal.vue.js +1 -1
- package/dist/components/LpModalNav.vue.js +1 -1
- package/dist/components/LpNotificationBell.vue.js +1 -1
- package/dist/components/LpNumberField.vue.d.ts +6 -0
- package/dist/components/LpNumberField.vue.js +1 -1
- package/dist/components/LpNumberFlow.vue.js +1 -1
- package/dist/components/LpPagination.vue.js +1 -1
- package/dist/components/LpPaletteFacts.vue.d.ts +1 -0
- package/dist/components/LpPaletteFacts.vue.js +40 -26
- package/dist/components/LpPaletteHeader.vue.js +2 -2
- package/dist/components/LpPaletteStats.vue.d.ts +1 -0
- package/dist/components/LpPaletteStats.vue.js +45 -21
- package/dist/components/LpPaletteTheme.vue.d.ts +7 -0
- package/dist/components/LpPaletteTheme.vue.js +4 -0
- package/dist/components/LpPasswordInput.vue.js +1 -1
- package/dist/components/LpPhoneInput.vue.js +1 -1
- package/dist/components/LpPie.vue.js +1 -1
- package/dist/components/LpPipeline.vue.js +1 -1
- package/dist/components/LpProgress.vue.d.ts +1 -1
- package/dist/components/LpProgress.vue.js +1 -1
- package/dist/components/LpQuota.vue.js +1 -1
- package/dist/components/LpRadioGroup.vue.d.ts +6 -1
- package/dist/components/LpRadioGroup.vue.js +1 -1
- package/dist/components/LpRangeCalendar.vue.js +1 -1
- package/dist/components/LpRangeSlider.vue.d.ts +6 -0
- package/dist/components/LpRangeSlider.vue.js +1 -1
- package/dist/components/LpRelativeTime.vue.js +1 -1
- package/dist/components/LpRepeater.vue.js +1 -1
- package/dist/components/LpSecretField.vue.js +1 -1
- package/dist/components/LpSection.vue.js +1 -1
- package/dist/components/LpSegmented.vue.d.ts +6 -0
- package/dist/components/LpSegmented.vue.js +1 -1
- package/dist/components/LpSelect.vue.d.ts +3 -0
- package/dist/components/LpSelect.vue.js +1 -1
- package/dist/components/LpShinyText.vue.d.ts +1 -1
- package/dist/components/LpShortcutsDialog.vue.js +1 -1
- package/dist/components/LpSidebar.vue.js +1 -1
- package/dist/components/LpSidebarNav.vue.js +1 -1
- package/dist/components/LpSlider.vue.d.ts +6 -0
- package/dist/components/LpSlider.vue.js +1 -1
- package/dist/components/LpStat.vue.js +1 -1
- package/dist/components/LpStatus.vue.js +1 -1
- package/dist/components/LpStepMark.vue.js +1 -1
- package/dist/components/LpStepper.vue.js +1 -1
- package/dist/components/LpSwitch.vue.d.ts +6 -0
- package/dist/components/LpSwitch.vue.js +1 -1
- package/dist/components/LpTable.vue.d.ts +6 -0
- package/dist/components/LpTable.vue.js +74 -35
- package/dist/components/LpTableFilter.vue.js +1 -1
- package/dist/components/LpTableOfContents.vue.js +1 -1
- package/dist/components/LpTabs.vue.d.ts +1 -1
- package/dist/components/LpTabs.vue.js +14 -5
- package/dist/components/LpTagsInput.vue.d.ts +6 -0
- package/dist/components/LpTagsInput.vue.js +1 -1
- package/dist/components/LpTextarea.vue.d.ts +8 -1
- package/dist/components/LpTextarea.vue.js +1 -1
- package/dist/components/LpThemeStudio.vue.js +1 -1
- package/dist/components/LpThemeSwitcher.vue.js +1 -1
- package/dist/components/LpTimeField.vue.d.ts +6 -0
- package/dist/components/LpTimeField.vue.js +1 -1
- package/dist/components/LpToaster.vue.js +1 -1
- package/dist/components/LpTooltip.vue.js +1 -1
- package/dist/components/LpTopologyCanvas.vue.js +1 -1
- package/dist/components/LpTour.vue.js +1 -1
- package/dist/components/LpTruncate.vue.js +1 -1
- package/dist/components/LpUptimeBar.vue.d.ts +18 -9
- package/dist/components/LpUptimeBar.vue.js +1 -1
- package/dist/components/MenuTitle.vue.js +1 -1
- package/dist/components/OptionContent.vue.js +1 -1
- package/dist/components/PalettePreviewBoundary.vue.d.ts +13 -0
- package/dist/components/PalettePreviewBoundary.vue.js +4 -0
- package/dist/components/PickerField.vue.js +1 -1
- package/dist/components/RevealToggle.vue.js +1 -1
- package/dist/components/TourCard.vue.js +1 -1
- package/dist/components/commandPalette.d.ts +33 -0
- package/dist/components/commandPalette.js +21 -1
- package/dist/components/commandSearch.d.ts +5 -0
- package/dist/components/commandSearch.js +22 -2
- package/dist/components/format.d.ts +7 -0
- package/dist/components/format.js +4 -0
- package/dist/components/menuWhen.js +1 -1
- package/dist/components/uptimeBar.d.ts +45 -0
- package/dist/components/uptimeBar.js +51 -0
- package/dist/composables/scroll.d.ts +5 -0
- package/dist/composables/scroll.js +7 -0
- package/dist/composables/useField.d.ts +4 -0
- package/dist/composables/useField.js +3 -0
- package/dist/composables/usePaletteCommands.d.ts +61 -0
- package/dist/composables/usePaletteCommands.js +226 -0
- package/dist/composables/useReveal.js +21 -0
- package/dist/composables/useView.js +5 -1
- package/dist/icons-all.js +1 -1
- package/dist/index.d.ts +14 -1
- package/dist/index.js +101 -85
- package/dist/theme/palette.d.ts +9 -0
- package/dist/theme/studio.d.ts +12 -1
- package/package.json +1 -1
- package/src/component-names.ts +2 -0
- package/src/components/LpAutocomplete.vue +6 -1
- package/src/components/LpButton.vue +5 -1
- package/src/components/LpCheckbox.vue +7 -2
- package/src/components/LpCommandPalette.vue +263 -29
- package/src/components/LpCommandScope.vue +35 -0
- package/src/components/LpContextMenu.vue +13 -2
- package/src/components/LpDisclosure.vue +5 -1
- package/src/components/LpDropdownMenu.vue +13 -2
- package/src/components/LpFormField.vue +3 -0
- package/src/components/LpInput.vue +6 -1
- package/src/components/LpNumberField.vue +6 -1
- package/src/components/LpNumberFlow.vue +12 -2
- package/src/components/LpPaletteFacts.vue +11 -6
- package/src/components/LpPaletteStats.vue +12 -5
- package/src/components/LpPaletteTheme.vue +48 -0
- package/src/components/LpPasswordInput.vue +3 -0
- package/src/components/LpRadioGroup.vue +4 -1
- package/src/components/LpRangeSlider.vue +6 -1
- package/src/components/LpSecretField.vue +3 -0
- package/src/components/LpSegmented.vue +6 -1
- package/src/components/LpSelect.vue +41 -2
- package/src/components/LpSlider.vue +6 -1
- package/src/components/LpSwitch.vue +6 -1
- package/src/components/LpTable.vue +35 -2
- package/src/components/LpTableOfContents.vue +2 -4
- package/src/components/LpTabs.vue +7 -0
- package/src/components/LpTagsInput.vue +6 -1
- package/src/components/LpTextarea.vue +7 -2
- package/src/components/LpThemeStudio.vue +7 -5
- package/src/components/LpThemeSwitcher.vue +3 -0
- package/src/components/LpTimeField.vue +6 -1
- package/src/components/LpTooltip.vue +23 -1
- package/src/components/LpUptimeBar.vue +69 -41
- package/src/components/PalettePreviewBoundary.vue +5 -0
- package/src/components/commandPalette.ts +22 -1
- package/src/components/commandSearch.ts +23 -1
- package/src/components/format.ts +10 -0
- package/src/components/uptimeBar.ts +98 -0
- package/src/composables/scroll.ts +11 -0
- package/src/composables/useField.ts +7 -0
- package/src/composables/usePaletteCommands.ts +226 -0
- package/src/composables/useReveal.ts +29 -0
- package/src/composables/useView.ts +5 -1
- package/src/index.ts +18 -1
- package/src/kit-icons.ts +1 -1
- package/src/theme/palette.ts +26 -0
- package/src/theme/studio.ts +15 -8
- package/dist/assets/LpTabs-BJ-nrJuI.css +0 -18
- package/dist/chunks/icons-4IywzkHk.js +0 -43
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* The arithmetic behind LpUptimeBar, kept pure so the corners are tested
|
|
3
|
+
* without a DOM: what share of the time was up, how that figure is printed,
|
|
4
|
+
* and how a slice's span reads in its tooltip.
|
|
5
|
+
*/
|
|
6
|
+
import { toEpoch } from "./timeSpan"
|
|
7
|
+
|
|
8
|
+
export type UptimeStatus = "operational" | "degraded" | "down" | "maintenance" | "empty"
|
|
9
|
+
|
|
10
|
+
export type UptimeMoment = Date | string | number
|
|
11
|
+
|
|
12
|
+
/** Something that happened inside a slice: a restart, a deploy, an alert. */
|
|
13
|
+
export interface UptimeEvent {
|
|
14
|
+
text: string
|
|
15
|
+
at?: UptimeMoment
|
|
16
|
+
status?: UptimeStatus
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface UptimeSegment {
|
|
20
|
+
/** Health of this slice. `empty` renders a faded placeholder (no data). */
|
|
21
|
+
status: UptimeStatus
|
|
22
|
+
/** Optional rich tooltip body; falls back to a humanised status. */
|
|
23
|
+
label?: string
|
|
24
|
+
/** When the slice begins and ends. Shown in the tooltip, and weights the uptime figure. */
|
|
25
|
+
start?: UptimeMoment
|
|
26
|
+
end?: UptimeMoment
|
|
27
|
+
/**
|
|
28
|
+
* Time spent in each state inside the slice, in ms. With it the figure
|
|
29
|
+
* counts real time rather than slices (one bad minute in a day no longer
|
|
30
|
+
* costs the whole day), and the tooltip says how long each state lasted.
|
|
31
|
+
*/
|
|
32
|
+
durations?: Partial<Record<Exclude<UptimeStatus, "empty">, number>>
|
|
33
|
+
/** What happened in the slice, a line each in the tooltip. */
|
|
34
|
+
events?: UptimeEvent[]
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const UP: ReadonlySet<UptimeStatus> = new Set(["operational", "maintenance"])
|
|
38
|
+
|
|
39
|
+
/** Worst first: the order a tooltip lists the time a slice spent in each state. */
|
|
40
|
+
export const UPTIME_SEVERITY: readonly Exclude<UptimeStatus, "empty">[] = ["down", "degraded", "maintenance", "operational"]
|
|
41
|
+
|
|
42
|
+
function span(seg: UptimeSegment): number | null {
|
|
43
|
+
if (seg.start === undefined || seg.end === undefined) return null
|
|
44
|
+
const ms = toEpoch(seg.end) - toEpoch(seg.start)
|
|
45
|
+
return Number.isFinite(ms) && ms > 0 ? ms : null
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Percent of the tracked time that was up (operational or planned
|
|
50
|
+
* maintenance). Slices with `durations` count their real minutes; the rest
|
|
51
|
+
* count by their span when every one of them has a span, and as one slice
|
|
52
|
+
* each otherwise. Empty slices are not tracked. Null when nothing is.
|
|
53
|
+
*/
|
|
54
|
+
export function uptimeShare(segments: readonly UptimeSegment[]): number | null {
|
|
55
|
+
const tracked = segments.filter((s) => s.status !== "empty")
|
|
56
|
+
const bySpan = tracked.every((s) => s.durations || span(s) !== null)
|
|
57
|
+
let up = 0
|
|
58
|
+
let total = 0
|
|
59
|
+
for (const seg of tracked) {
|
|
60
|
+
if (seg.durations) {
|
|
61
|
+
for (const [status, ms] of Object.entries(seg.durations)) {
|
|
62
|
+
if (!ms || ms < 0) continue
|
|
63
|
+
total += ms
|
|
64
|
+
if (UP.has(status as UptimeStatus)) up += ms
|
|
65
|
+
}
|
|
66
|
+
continue
|
|
67
|
+
}
|
|
68
|
+
const weight = bySpan ? (span(seg) ?? 0) : 1
|
|
69
|
+
total += weight
|
|
70
|
+
if (UP.has(seg.status)) up += weight
|
|
71
|
+
}
|
|
72
|
+
return total > 0 ? (up / total) * 100 : null
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* The figure and its decimal places: trailing zeros trimmed (100, 99.9), and
|
|
77
|
+
* never rounded up to 100 while some time was down — 99.999 prints as 99.99,
|
|
78
|
+
* because "100%" over an outage reads as no outage at all.
|
|
79
|
+
*/
|
|
80
|
+
export function uptimeFigure(pct: number): { value: number; decimals: number } {
|
|
81
|
+
let value = Number(pct.toFixed(2))
|
|
82
|
+
if (pct < 100 && value >= 100) value = 99.99
|
|
83
|
+
const decimals = Number.isInteger(value) ? 0 : String(value).split(".")[1].length
|
|
84
|
+
return { value, decimals }
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** "26 Oct, 12:00 – 12:15", the date written once when both ends share a day. */
|
|
88
|
+
export function uptimeRange(start: UptimeMoment, end: UptimeMoment | undefined, locale?: string): string {
|
|
89
|
+
const from = toEpoch(start)
|
|
90
|
+
if (!Number.isFinite(from)) return ""
|
|
91
|
+
const full = new Intl.DateTimeFormat(locale, { day: "numeric", month: "short", hour: "2-digit", minute: "2-digit" })
|
|
92
|
+
if (end === undefined) return full.format(from)
|
|
93
|
+
const to = toEpoch(end)
|
|
94
|
+
if (!Number.isFinite(to)) return full.format(from)
|
|
95
|
+
const sameDay = new Date(from).toDateString() === new Date(to).toDateString()
|
|
96
|
+
const tail = sameDay ? new Intl.DateTimeFormat(locale, { hour: "2-digit", minute: "2-digit" }) : full
|
|
97
|
+
return `${full.format(from)} – ${tail.format(to)}`
|
|
98
|
+
}
|
|
@@ -26,6 +26,17 @@ export function scrollParent(el: Element | null | undefined, { axis = "y", self
|
|
|
26
26
|
return null
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Whether `el`'s scroller (or the page) has no more room to scroll down.
|
|
31
|
+
* `slack` absorbs the pixel a rounded-up scrollHeight can sit above the sum.
|
|
32
|
+
*/
|
|
33
|
+
export function atScrollEnd(el: Element | null | undefined, slack = 2): boolean {
|
|
34
|
+
if (!el) return false
|
|
35
|
+
const box = scrollParent(el) ?? (el.ownerDocument.scrollingElement as HTMLElement | null)
|
|
36
|
+
if (!box) return true
|
|
37
|
+
return box.scrollTop + box.clientHeight >= box.scrollHeight - slack
|
|
38
|
+
}
|
|
39
|
+
|
|
29
40
|
export interface ScrollToElementOptions {
|
|
30
41
|
/** `nearest` scrolls only when the element is out of view. */
|
|
31
42
|
block?: "nearest" | "center" | "start"
|
|
@@ -9,6 +9,10 @@ import type { FieldNoticeOptions } from "./useFieldNotice"
|
|
|
9
9
|
*/
|
|
10
10
|
export interface FieldContext {
|
|
11
11
|
id: string
|
|
12
|
+
/** Human-readable name shared by controls and contextual commands. */
|
|
13
|
+
label?: string
|
|
14
|
+
hint?: string
|
|
15
|
+
error?: string
|
|
12
16
|
/** Id of the visible label, for controls a `<label for>` cannot name (groups). */
|
|
13
17
|
labelId?: string
|
|
14
18
|
describedBy?: string
|
|
@@ -74,6 +78,9 @@ export function useFieldControl(
|
|
|
74
78
|
return {
|
|
75
79
|
id: state.id ?? field?.id,
|
|
76
80
|
labelId: field?.labelId,
|
|
81
|
+
label: field?.label,
|
|
82
|
+
hint: field?.hint,
|
|
83
|
+
error: field?.error,
|
|
77
84
|
describedBy: field?.describedBy,
|
|
78
85
|
invalid: !!state.invalid || !!field?.invalid,
|
|
79
86
|
required: !!state.required || !!field?.required,
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { computed, getCurrentInstance, h, inject, onMounted, onUpdated, onScopeDispose, provide, ref, shallowReactive, shallowRef, toValue, useId, type Component, type Directive, type InjectionKey, type MaybeRefOrGetter } from "vue"
|
|
2
|
+
import type { Command } from "../components/LpCommandPalette.vue"
|
|
3
|
+
import { provideField, useField } from "./useField"
|
|
4
|
+
import { useLabels } from "./useLpConfig"
|
|
5
|
+
|
|
6
|
+
export interface PaletteRegistration {
|
|
7
|
+
commands: () => readonly Command[]
|
|
8
|
+
priority: number
|
|
9
|
+
/** Discovered from a component rather than written by the app: an id clash numbers it instead of hiding it. */
|
|
10
|
+
automatic?: boolean
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function uniqueCommands(commands: readonly Command[]): Command[] {
|
|
14
|
+
const found = new Map<string, Command>()
|
|
15
|
+
for (const command of commands) if (!found.has(command.id)) found.set(command.id, command)
|
|
16
|
+
return [...found.values()]
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/*
|
|
20
|
+
* A discovered command is keyed by its scope and label, not by a generated id:
|
|
21
|
+
* `useId` follows mount order, so a pin or a recent entry on a field pointed at
|
|
22
|
+
* another field (or nothing) once the page mounted its parts differently. Two
|
|
23
|
+
* fields with one label in one scope would then share an id, so the second and
|
|
24
|
+
* later get `~2`, `~3` in mount order instead of the second vanishing. A manual
|
|
25
|
+
* definition with the same id still replaces the discovered one.
|
|
26
|
+
*/
|
|
27
|
+
function numbered(entries: readonly PaletteRegistration[]): Command[] {
|
|
28
|
+
const manual = new Set<string>()
|
|
29
|
+
const seen = new Map<string, number>()
|
|
30
|
+
const out: Command[] = []
|
|
31
|
+
for (const entry of entries) {
|
|
32
|
+
for (const command of entry.commands()) {
|
|
33
|
+
if (!entry.automatic) {
|
|
34
|
+
manual.add(command.id)
|
|
35
|
+
out.push(command)
|
|
36
|
+
continue
|
|
37
|
+
}
|
|
38
|
+
if (manual.has(command.id)) continue
|
|
39
|
+
const count = (seen.get(command.id) ?? 0) + 1
|
|
40
|
+
seen.set(command.id, count)
|
|
41
|
+
if (count === 1) {
|
|
42
|
+
out.push(command)
|
|
43
|
+
continue
|
|
44
|
+
}
|
|
45
|
+
const id = `${command.id}~${count}`
|
|
46
|
+
out.push({ ...command, id, actions: command.actions?.map(action => ({ ...action, id: action.id.replace(command.id, id) })) })
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return uniqueCommands(out)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** One registry per application/provider; never shared between SSR requests. */
|
|
53
|
+
export function createPaletteRegistry() {
|
|
54
|
+
const entries = shallowReactive(new Map<symbol, PaletteRegistration>())
|
|
55
|
+
const commands = computed(() => numbered([...entries.values()].sort((a, b) => b.priority - a.priority)))
|
|
56
|
+
return {
|
|
57
|
+
commands,
|
|
58
|
+
register(entry: PaletteRegistration) {
|
|
59
|
+
const key = Symbol()
|
|
60
|
+
entries.set(key, entry)
|
|
61
|
+
return () => { entries.delete(key) }
|
|
62
|
+
},
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
export type PaletteRegistry = ReturnType<typeof createPaletteRegistry>
|
|
66
|
+
|
|
67
|
+
export interface PaletteScope {
|
|
68
|
+
registry: PaletteRegistry
|
|
69
|
+
id: string
|
|
70
|
+
label: string
|
|
71
|
+
depth: number
|
|
72
|
+
enabled: boolean
|
|
73
|
+
discover: boolean
|
|
74
|
+
}
|
|
75
|
+
const SCOPE: InjectionKey<PaletteScope> = Symbol.for("lp-palette-scope")
|
|
76
|
+
const BLOCKED: InjectionKey<boolean> = Symbol.for("lp-palette-blocked")
|
|
77
|
+
const scopeElements = new WeakMap<Element, PaletteScope>()
|
|
78
|
+
export function bindPaletteScopeElement(element: Element, scope: PaletteScope) { scopeElements.set(element, scope) }
|
|
79
|
+
export const usePaletteScope = () => inject(SCOPE, null)
|
|
80
|
+
export const providePaletteScope = (scope: PaletteScope) => provide(SCOPE, scope)
|
|
81
|
+
/** Preview controls and compound controls must not discover their own implementation. */
|
|
82
|
+
export function suppressPaletteDiscovery() { provide(BLOCKED, true) }
|
|
83
|
+
|
|
84
|
+
export function usePaletteCommands(commands: MaybeRefOrGetter<readonly Command[]>, options: { automatic?: boolean; scope?: PaletteScope } = {}) {
|
|
85
|
+
const scope = options.scope ?? usePaletteScope()
|
|
86
|
+
const blocked = inject(BLOCKED, false)
|
|
87
|
+
if (!scope || blocked) return
|
|
88
|
+
const unregister = scope.registry.register({
|
|
89
|
+
automatic: options.automatic,
|
|
90
|
+
priority: scope.depth * 100 + (options.automatic ? 0 : 10),
|
|
91
|
+
commands: () => scope.enabled && (!options.automatic || scope.discover)
|
|
92
|
+
? toValue(commands).map(command => ({
|
|
93
|
+
...command,
|
|
94
|
+
group: command.group ?? scope.label,
|
|
95
|
+
// A discovered "Save" or "Restart" says nothing on its own: typing the
|
|
96
|
+
// page or card it sits in ("settings save") has to find it.
|
|
97
|
+
keywords: options.automatic ? [...(command.keywords ?? []), scope.label] : command.keywords,
|
|
98
|
+
})) : [],
|
|
99
|
+
})
|
|
100
|
+
onScopeDispose(unregister)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Manual definitions override a discovered command without changing its place. */
|
|
104
|
+
export function mergePaletteCommands(discovered: readonly Command[], manual: readonly Command[]): Command[] {
|
|
105
|
+
const overrides = new Map(manual.map(command => [command.id, command]))
|
|
106
|
+
return uniqueCommands([...discovered.map(command => overrides.get(command.id) ?? command), ...manual])
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export type PaletteControlOptions = false | { id?: string; label?: string; description?: string; keywords?: string[] }
|
|
110
|
+
|
|
111
|
+
export interface PaletteTargetOptions { id: string; label: string; description?: string; keywords?: string[]; action?: "click" | "focus" }
|
|
112
|
+
const targets = new WeakMap<HTMLElement, { update: (value: PaletteTargetOptions) => void; stop: () => void }>()
|
|
113
|
+
/** Native/custom markup opt-in; editing values still goes through the component's own binding. */
|
|
114
|
+
export const vPalette: Directive<HTMLElement, PaletteTargetOptions> = {
|
|
115
|
+
mounted(el, binding) {
|
|
116
|
+
if (el.closest("[data-lp-command-preview]")) return
|
|
117
|
+
const owner = binding.instance?.$ as { provides?: Record<symbol, unknown> } | undefined
|
|
118
|
+
const ancestor = el.closest("[data-lp-command-scope]")
|
|
119
|
+
const scope = (ancestor && scopeElements.get(ancestor)) ?? owner?.provides?.[SCOPE as symbol] as PaletteScope | undefined
|
|
120
|
+
if (!scope) return
|
|
121
|
+
const value = shallowRef(binding.value)
|
|
122
|
+
const stop = scope.registry.register({ priority: scope.depth * 100 + 10, commands: () => scope.enabled ? [{
|
|
123
|
+
id: `${scope.id}/${value.value.id}`, label: value.value.label,
|
|
124
|
+
description: value.value.description, keywords: value.value.keywords, group: scope.label,
|
|
125
|
+
disabled: el.matches(":disabled,[aria-disabled=true]"),
|
|
126
|
+
afterClose: () => {
|
|
127
|
+
if (!el.isConnected || el.matches(":disabled,[aria-disabled=true]")) return
|
|
128
|
+
el.scrollIntoView({ block: "nearest" })
|
|
129
|
+
if (value.value.action === "click") el.click()
|
|
130
|
+
else el.focus({ preventScroll: true })
|
|
131
|
+
},
|
|
132
|
+
}] : [] })
|
|
133
|
+
targets.set(el, { stop, update: next => { value.value = { ...next } } })
|
|
134
|
+
},
|
|
135
|
+
updated(el, binding) { targets.get(el)?.update(binding.value) },
|
|
136
|
+
unmounted(el) { targets.get(el)?.stop(); targets.delete(el) },
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export function usePaletteAction(options: { label?: () => string | undefined; element: () => HTMLElement | null | undefined; disabled?: () => boolean }) {
|
|
140
|
+
const instance = getCurrentInstance()
|
|
141
|
+
const scope = usePaletteScope()
|
|
142
|
+
if (!instance || !scope || inject(BLOCKED, false)) return
|
|
143
|
+
const domLabel = ref("")
|
|
144
|
+
const syncLabel = () => { domLabel.value = options.element()?.textContent?.trim() ?? "" }
|
|
145
|
+
onMounted(syncLabel)
|
|
146
|
+
onUpdated(syncLabel)
|
|
147
|
+
usePaletteCommands(() => {
|
|
148
|
+
const config = instance.props.palette as PaletteControlOptions | undefined
|
|
149
|
+
const label = (config || {}).label ?? options.label?.() ?? domLabel.value
|
|
150
|
+
if (config === false || !label) return []
|
|
151
|
+
return [{
|
|
152
|
+
id: `${scope.id}/${config?.id ?? label}`, label, description: config?.description,
|
|
153
|
+
keywords: config?.keywords, disabled: options.disabled?.(),
|
|
154
|
+
afterClose: () => { if (!options.disabled?.()) options.element()?.click() },
|
|
155
|
+
}]
|
|
156
|
+
}, { automatic: true })
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export function usePaletteControl(options: {
|
|
160
|
+
label?: () => string | undefined
|
|
161
|
+
disabled?: () => boolean
|
|
162
|
+
invalid?: () => boolean
|
|
163
|
+
available?: () => boolean
|
|
164
|
+
ownsChildren?: boolean
|
|
165
|
+
editorProps?: () => Record<string, unknown>
|
|
166
|
+
} = {}) {
|
|
167
|
+
const instance = getCurrentInstance()
|
|
168
|
+
const scope = usePaletteScope()
|
|
169
|
+
const blocked = inject(BLOCKED, false)
|
|
170
|
+
if (options.ownsChildren) suppressPaletteDiscovery()
|
|
171
|
+
if (!instance || !scope || blocked) return
|
|
172
|
+
const text = useLabels("paletteControl", { focus: "Go to field" })
|
|
173
|
+
const field = useField()
|
|
174
|
+
const settings = () => (instance.attrs.palette ?? instance.props.palette) as PaletteControlOptions | undefined
|
|
175
|
+
const label = () => (settings() || {}).label ?? options.label?.() ?? field?.value.label
|
|
176
|
+
?? instance.attrs["aria-label"] as string | undefined
|
|
177
|
+
const error = () => instance.props.error as string | undefined ?? field?.value.error
|
|
178
|
+
const hint = () => instance.props.hint as string | undefined ?? field?.value.hint
|
|
179
|
+
const writable = () => !!(instance.vnode.props?.["onUpdate:modelValue"] || instance.vnode.props?.["onUpdate:model-value"] || instance.props.action)
|
|
180
|
+
const focus = () => {
|
|
181
|
+
const el = instance.proxy?.$el as HTMLElement | undefined
|
|
182
|
+
const target = el?.matches?.('input,button,textarea,select,[tabindex="0"]') ? el
|
|
183
|
+
: el?.querySelector<HTMLElement>('input:not([type="hidden"]),button,textarea,select,[tabindex="0"]')
|
|
184
|
+
target?.scrollIntoView({ block: "nearest" })
|
|
185
|
+
target?.focus({ preventScroll: true })
|
|
186
|
+
}
|
|
187
|
+
const Editor: Component = {
|
|
188
|
+
name: "PaletteControlEditor",
|
|
189
|
+
setup() {
|
|
190
|
+
suppressPaletteDiscovery()
|
|
191
|
+
const editorId = `lp-palette-editor-${useId()}`
|
|
192
|
+
provideField(computed(() => ({
|
|
193
|
+
id: editorId, label: label(), labelId: `${editorId}-label`,
|
|
194
|
+
describedBy: error() || hint() ? `${editorId}-message` : undefined,
|
|
195
|
+
required: !!(field?.value.required ?? instance.props.required),
|
|
196
|
+
disabled: !!options.disabled?.(), invalid: !!options.invalid?.(),
|
|
197
|
+
})))
|
|
198
|
+
return () => {
|
|
199
|
+
const raw = { ...instance.vnode.props, ...instance.props, ...options.editorProps?.() }
|
|
200
|
+
for (const key of Object.keys(raw)) if (key === "ref" || key === "key" || key.startsWith("onVnode")) delete raw[key]
|
|
201
|
+
return h("div", { class: "flex flex-col gap-3" }, [
|
|
202
|
+
h(raw.label ? "h3" : "label", { id: `${editorId}-label`, for: raw.label ? undefined : editorId, class: "text-sm font-semibold text-ink" }, label()),
|
|
203
|
+
h(instance.type as Component, {
|
|
204
|
+
...raw, id: undefined, name: undefined, form: undefined, autofocus: undefined, palette: false,
|
|
205
|
+
disabled: options.disabled?.() || !writable(), invalid: options.invalid?.(),
|
|
206
|
+
required: field?.value.required ?? instance.props.required,
|
|
207
|
+
"aria-label": label(), class: "w-full", style: undefined,
|
|
208
|
+
}, instance.slots),
|
|
209
|
+
error() || hint() ? h("p", { id: `${editorId}-message`, class: error() ? "text-xs text-danger" : "text-xs text-muted", role: error() ? "alert" : undefined }, error() || hint()) : null,
|
|
210
|
+
])
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
}
|
|
214
|
+
usePaletteCommands(() => {
|
|
215
|
+
const config = settings()
|
|
216
|
+
const name = label()
|
|
217
|
+
if (config === false || !name || options.available?.() === false) return []
|
|
218
|
+
const id = `${scope.id}/${config?.id ?? (instance.attrs.id as string | undefined) ?? name}`
|
|
219
|
+
return [{
|
|
220
|
+
id, label: name, description: config?.description, keywords: config?.keywords,
|
|
221
|
+
disabled: options.disabled?.(), previewComponent: Editor, editInPreview: writable(),
|
|
222
|
+
afterClose: writable() ? undefined : focus,
|
|
223
|
+
actions: [{ id: `${id}/focus`, label: text.value.focus, description: name, icon: "lucide:focus", afterClose: focus }],
|
|
224
|
+
}]
|
|
225
|
+
}, { automatic: true })
|
|
226
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { onBeforeUnmount, ref, toValue, watch, type MaybeRefOrGetter, type Ref } from "vue"
|
|
2
2
|
import { prefersReducedMotion } from "./easing"
|
|
3
|
+
import { atScrollEnd } from "./scroll"
|
|
3
4
|
|
|
4
5
|
/*
|
|
5
6
|
* "Has this element actually been SEEN yet?"
|
|
@@ -67,10 +68,16 @@ export function useReveal(options: UseRevealOptions = {}): UseReveal {
|
|
|
67
68
|
const revealed = ref(typeof window === "undefined")
|
|
68
69
|
|
|
69
70
|
let observer: IntersectionObserver | null = null
|
|
71
|
+
let edge: IntersectionObserver | null = null
|
|
72
|
+
let onScroll: (() => void) | null = null
|
|
70
73
|
|
|
71
74
|
function stop() {
|
|
72
75
|
observer?.disconnect()
|
|
73
76
|
observer = null
|
|
77
|
+
edge?.disconnect()
|
|
78
|
+
edge = null
|
|
79
|
+
if (onScroll) window.removeEventListener("scroll", onScroll, true)
|
|
80
|
+
onScroll = null
|
|
74
81
|
}
|
|
75
82
|
|
|
76
83
|
function reveal() {
|
|
@@ -103,6 +110,28 @@ export function useReveal(options: UseRevealOptions = {}): UseReveal {
|
|
|
103
110
|
{ threshold, rootMargin },
|
|
104
111
|
)
|
|
105
112
|
observer.observe(node)
|
|
113
|
+
|
|
114
|
+
/*
|
|
115
|
+
* The margin shrinks the viewport from below, so the last element of a
|
|
116
|
+
* page sits in that strip for good: there is no more scroll to lift it
|
|
117
|
+
* out, and its count-up never started (a figure at the bottom of a
|
|
118
|
+
* dashboard stayed at 0). On screen with nowhere left to scroll is an
|
|
119
|
+
* arrival too.
|
|
120
|
+
*/
|
|
121
|
+
let onScreen = false
|
|
122
|
+
const check = () => {
|
|
123
|
+
if (onScreen && atScrollEnd(node)) reveal()
|
|
124
|
+
}
|
|
125
|
+
edge = new IntersectionObserver(
|
|
126
|
+
(entries) => {
|
|
127
|
+
onScreen = entries.some((entry) => entry.isIntersecting)
|
|
128
|
+
check()
|
|
129
|
+
},
|
|
130
|
+
{ threshold },
|
|
131
|
+
)
|
|
132
|
+
edge.observe(node)
|
|
133
|
+
onScroll = check
|
|
134
|
+
window.addEventListener("scroll", onScroll, { capture: true, passive: true })
|
|
106
135
|
},
|
|
107
136
|
{ immediate: true, flush: "post" },
|
|
108
137
|
)
|
|
@@ -60,7 +60,10 @@ const FORWARDED = ["pointerdown", "pointerup", "click", "focusin", "keydown"] as
|
|
|
60
60
|
|
|
61
61
|
export function forwardViewEvents(from: Document, to: Document): () => void {
|
|
62
62
|
const forward = (event: Event) => {
|
|
63
|
-
if (event.type === "keydown"
|
|
63
|
+
if (event.type === "keydown") {
|
|
64
|
+
const key = event as KeyboardEvent
|
|
65
|
+
if (key.defaultPrevented || (key.key !== "Escape" && !key.ctrlKey && !key.metaKey)) return
|
|
66
|
+
}
|
|
64
67
|
const Copy = event.constructor as new (type: string, init: Event) => Event
|
|
65
68
|
const copy = new Copy(event.type, event) as Marked
|
|
66
69
|
copy[ORIGIN] = from
|
|
@@ -68,6 +71,7 @@ export function forwardViewEvents(from: Document, to: Document): () => void {
|
|
|
68
71
|
Object.defineProperty(copy, "target", { value: event.target })
|
|
69
72
|
copy.composedPath = () => path
|
|
70
73
|
to.dispatchEvent(copy)
|
|
74
|
+
if (copy.defaultPrevented) event.preventDefault()
|
|
71
75
|
}
|
|
72
76
|
for (const type of FORWARDED) from.addEventListener(type, forward)
|
|
73
77
|
return () => {
|
package/src/index.ts
CHANGED
|
@@ -452,7 +452,7 @@ export { TONE_ALIASES, TONES, toneLook, toneOf } from "./components/tone"
|
|
|
452
452
|
export type { Tone, ToneLook, ToneName } from "./components/tone"
|
|
453
453
|
export { formatAmount, quotaSegments, quotaState } from "./components/quota"
|
|
454
454
|
export type { QuotaPart, QuotaSegment, QuotaState, QuotaUnit } from "./components/quota"
|
|
455
|
-
export { compactNumber, formatBytes } from "./components/format"
|
|
455
|
+
export { compactNumber, decimalMark, formatBytes } from "./components/format"
|
|
456
456
|
export type { CompactNumberOptions, FormatBytesOptions } from "./components/format"
|
|
457
457
|
export { STATUS_LABELS, STATUS_LOOK } from "./components/status"
|
|
458
458
|
export type { StatusKind, StatusLook } from "./components/status"
|
|
@@ -555,3 +555,20 @@ export { default as LpGlowBorder } from "./components/LpGlowBorder.vue"
|
|
|
555
555
|
export { default as LpMagnetic } from "./components/LpMagnetic.vue"
|
|
556
556
|
export { spotlightPoint, useSpotlight } from "./composables/useSpotlight"
|
|
557
557
|
export type { UseSpotlight, UseSpotlightOptions } from "./composables/useSpotlight"
|
|
558
|
+
|
|
559
|
+
export { default as LpCommandScope } from "./components/LpCommandScope.vue"
|
|
560
|
+
export { createPaletteRegistry, usePaletteCommands, mergePaletteCommands } from "./composables/usePaletteCommands"
|
|
561
|
+
export type { PaletteRegistry, PaletteControlOptions } from "./composables/usePaletteCommands"
|
|
562
|
+
export { PALETTE_MODES } from "./components/commandPalette"
|
|
563
|
+
export type { PaletteMode } from "./components/commandPalette"
|
|
564
|
+
export { searchCommandItems, swapCommandLayout } from "./components/commandSearch"
|
|
565
|
+
export type { CommandPrompt } from "./components/LpCommandPalette.vue"
|
|
566
|
+
|
|
567
|
+
export { usePaletteTheme } from "./theme/palette"
|
|
568
|
+
export { default as LpPaletteTheme } from "./components/LpPaletteTheme.vue"
|
|
569
|
+
|
|
570
|
+
export { vPalette } from "./composables/usePaletteCommands"
|
|
571
|
+
export type { PaletteTargetOptions } from "./composables/usePaletteCommands"
|
|
572
|
+
export { menuPaletteCommands } from "./components/commandPalette"
|
|
573
|
+
|
|
574
|
+
export type { PreviewableThemeStudio } from "./theme/studio"
|