@leavepulse/ui 0.70.0 → 0.71.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.
Files changed (345) hide show
  1. package/README.md +103 -0
  2. package/dist/assets/{LpCommandPalette-u-zOxKWa.css → LpCommandPalette-DgPZX0us.css} +24 -17
  3. package/dist/assets/{LpPaletteFacts-B9FdVmIO.css → LpPaletteFacts-CVNh5ICn.css} +16 -16
  4. package/dist/assets/{LpPaletteStats-ClE-37MK.css → LpPaletteStats-ZiZmR6vz.css} +5 -5
  5. package/dist/assets/LpRepeater-C1Cw27hj.css +21 -0
  6. package/dist/assets/{LpRollingText-BGnE6q9j.css → LpRollingText-dyOXedGO.css} +7 -0
  7. package/dist/assets/{LpTable-DHxEQ_-3.css → LpTable-DHvorDiU.css} +19 -19
  8. package/dist/assets/LpTabs-CO3EcsNV.css +18 -0
  9. package/dist/chunks/{ContextMenuItems-B5uE8Znw.js → ContextMenuItems-eS7qx9gD.js} +11 -5
  10. package/dist/chunks/{DropzoneLinkField-Bw8Flkhk.js → DropzoneLinkField-DkFhdfEJ.js} +2 -2
  11. package/dist/chunks/{FieldWrapper-BiennROB.js → FieldWrapper-YzbvvC3M.js} +1 -1
  12. package/dist/chunks/{LayoutCanvas-BsJIzhdd.js → LayoutCanvas-Ba4A9QC5.js} +1 -1
  13. package/dist/chunks/{LayoutNode-DJVhkSGk.js → LayoutNode-CTTTLMDM.js} +1 -1
  14. package/dist/chunks/{LpActionBar-CzOFar5t.js → LpActionBar-B7anGlkI.js} +2 -2
  15. package/dist/chunks/{LpAddressInput-CNnLTDZg.js → LpAddressInput-CD0bzrt-.js} +7 -7
  16. package/dist/chunks/{LpAlert-C5igj802.js → LpAlert-BHi7ARqu.js} +1 -1
  17. package/dist/chunks/{LpAppShell-CEUAB8kK.js → LpAppShell-1RmBp6xQ.js} +3 -3
  18. package/dist/chunks/{LpAutocomplete-D92niDHE.js → LpAutocomplete-DDqe2M5g.js} +5 -2
  19. package/dist/chunks/{LpAvatar-CLPl-qOF.js → LpAvatar-DqfKCIdr.js} +1 -1
  20. package/dist/chunks/{LpBadge-HOEPBYmi.js → LpBadge-C8fKEmTF.js} +2 -2
  21. package/dist/chunks/{LpBreadcrumbs-DYoPc3P4.js → LpBreadcrumbs-DhcoStFa.js} +2 -2
  22. package/dist/chunks/{LpButton-CVxBfGjd.js → LpButton-BQDAFXBd.js} +3 -0
  23. package/dist/chunks/{LpCalendar-pVL91-Pl.js → LpCalendar-NmrA47J9.js} +1 -1
  24. package/dist/chunks/{LpCheckbox-DHc2bHDe.js → LpCheckbox-BoOuLnGB.js} +5 -2
  25. package/dist/chunks/{LpCodeBlock-BGsQhxw8.js → LpCodeBlock-Czu-fq1M.js} +2 -2
  26. package/dist/chunks/{LpCodeDisplay-CIKKT2iW.js → LpCodeDisplay-BK2FHbtM.js} +6 -6
  27. package/dist/chunks/{LpColorPicker-DFugXNUi.js → LpColorPicker-Ee1DZiRd.js} +3 -3
  28. package/dist/chunks/LpCommandScope-ubtWDMa0.js +53 -0
  29. package/dist/chunks/{LpConfirmDialog-CfGCux8m.js → LpConfirmDialog-i15pulMT.js} +3 -3
  30. package/dist/chunks/{LpConfirmHost-exB7JmcO.js → LpConfirmHost-D0oGavtd.js} +1 -1
  31. package/dist/chunks/{LpContextMenu-COwOwRgI.js → LpContextMenu-DXpFJjlO.js} +17 -6
  32. package/dist/chunks/{LpCopyButton-DzHjnFs0.js → LpCopyButton-Dmq7DmFw.js} +3 -3
  33. package/dist/chunks/{LpCountdown-Dtq1ihlJ.js → LpCountdown-DTdMF8DL.js} +2 -2
  34. package/dist/chunks/{LpDataList-B-5nHfNw.js → LpDataList-CFPtSsBB.js} +7 -6
  35. package/dist/chunks/{LpDatePicker-BUe1VUC0.js → LpDatePicker-cC9K-Pk8.js} +7 -6
  36. package/dist/chunks/{LpDateRangePicker-C_k65vGR.js → LpDateRangePicker-BVQKPbvo.js} +5 -4
  37. package/dist/chunks/{LpDisclosure-DOarzlAG.js → LpDisclosure-hRnX3FWL.js} +4 -1
  38. package/dist/chunks/{LpDrawer-DGNKRsGq.js → LpDrawer-u4rxnuR-.js} +1 -1
  39. package/dist/chunks/{LpDropdownMenu-CRgrhdAH.js → LpDropdownMenu-BgZ0Z_Im.js} +17 -4
  40. package/dist/chunks/{LpEditable-DTqLt2lT.js → LpEditable-CjxuOVh_.js} +7 -5
  41. package/dist/chunks/{LpEmptyState-KTKipws2.js → LpEmptyState-CKFTtQgJ.js} +1 -1
  42. package/dist/chunks/{LpFieldNotice-CurbNuXI.js → LpFieldNotice-CPI8EwtU.js} +1 -1
  43. package/dist/chunks/{LpFileTree-DMISXVHC.js → LpFileTree-BH0gNlSJ.js} +2 -2
  44. package/dist/chunks/{LpFileTreeNode-CPXB_Yy3.js → LpFileTreeNode-gPVB1oXM.js} +4 -4
  45. package/dist/chunks/{LpFormField-BWwgm1E4.js → LpFormField-gRASfyj2.js} +4 -1
  46. package/dist/chunks/{LpGauge-Bk8TwJj0.js → LpGauge-BdjPGnqw.js} +2 -2
  47. package/dist/chunks/{LpHintLayer-p4hqzdyA.js → LpHintLayer-C2asBIfs.js} +2 -2
  48. package/dist/chunks/{LpHints-CCrhRfy9.js → LpHints-CNZQ76JV.js} +3 -3
  49. package/dist/chunks/{LpIcon-HJP5xMz4.js → LpIcon-DkP-9mzK.js} +1 -1
  50. package/dist/chunks/{LpInfraNode-CUC3t4na.js → LpInfraNode-yTh4-5qa.js} +2 -2
  51. package/dist/chunks/{LpInput-CDuwODJG.js → LpInput-2H-5ILOB.js} +5 -2
  52. package/dist/chunks/{LpLightbox-XJ0LpTcZ.js → LpLightbox-lAt5uIfx.js} +2 -2
  53. package/dist/chunks/{LpLogViewer-elZHbj85.js → LpLogViewer-x78YfhJf.js} +5 -5
  54. package/dist/chunks/{LpMapPicker-BtIl7NOM.js → LpMapPicker-Dp5RSCi9.js} +1 -1
  55. package/dist/chunks/{LpMediaGallery-D5swlmZ_.js → LpMediaGallery-D92oJfY_.js} +3 -3
  56. package/dist/chunks/{LpModal-eBMt2Fqn.js → LpModal-CpH0bNo7.js} +1 -1
  57. package/dist/chunks/{LpModalNav-D4Z0wVHR.js → LpModalNav-BH4ANQGJ.js} +4 -4
  58. package/dist/chunks/{LpNotificationBell-DPZmP5dM.js → LpNotificationBell-BdUQqZhs.js} +8 -8
  59. package/dist/chunks/{LpNumberField-B9k-h2HE.js → LpNumberField-DZY3Z670.js} +4 -1
  60. package/dist/chunks/{LpNumberFlow-Cfyh033Q.js → LpNumberFlow-5khYxsfX.js} +6 -3
  61. package/dist/chunks/{LpPagination-VNCX6pFC.js → LpPagination-DbeACavM.js} +1 -1
  62. package/dist/chunks/LpPaletteTheme-CqWNRwHE.js +104 -0
  63. package/dist/chunks/{LpPasswordInput-DTV18FIh.js → LpPasswordInput-BzAZsf5V.js} +14 -8
  64. package/dist/chunks/{LpPhoneInput-C60tx1tC.js → LpPhoneInput-BMpd-0QR.js} +2 -2
  65. package/dist/chunks/{LpPie-CFuV7pZv.js → LpPie-DdFSTbGE.js} +5 -5
  66. package/dist/chunks/{LpPipeline-D81yh_NX.js → LpPipeline-zjEM1Lwc.js} +4 -4
  67. package/dist/chunks/{LpPopover-BEIcqb9p.js → LpPopover-DmZ3wUtP.js} +6 -5
  68. package/dist/chunks/{LpProgress-CE-m5OpD.js → LpProgress-BX33EKkN.js} +1 -1
  69. package/dist/chunks/{LpQuota-2Sw_gqcJ.js → LpQuota-DqNv1yjs.js} +3 -3
  70. package/dist/chunks/{LpRadioGroup-CGBr5nIp.js → LpRadioGroup-CsXeV9Ct.js} +4 -1
  71. package/dist/chunks/{LpRangeCalendar-c5qj7YcC.js → LpRangeCalendar-l-0nSFmY.js} +1 -1
  72. package/dist/chunks/{LpRangeSlider-Dv6lNvHY.js → LpRangeSlider-CM-0ZITZ.js} +3 -0
  73. package/dist/chunks/{LpRelativeTime-CKzVqAo9.js → LpRelativeTime-UM8EkfrN.js} +2 -2
  74. package/dist/chunks/LpRepeater-OvzByE5L.js +180 -0
  75. package/dist/chunks/{LpRollingText-DB7upf-5.js → LpRollingText-DiL717LK.js} +4 -3
  76. package/dist/chunks/{LpSecretField-DMfdJ1cQ.js → LpSecretField-DwQiPOko.js} +27 -16
  77. package/dist/chunks/{LpSection-BW4xJ-Li.js → LpSection-DcQsieHG.js} +1 -1
  78. package/dist/chunks/{LpSegmented-BO99Sr4m.js → LpSegmented-D2VST0o3.js} +4 -1
  79. package/dist/chunks/{LpSelect-B4f_yRi5.js → LpSelect-DYX2-u5A.js} +43 -18
  80. package/dist/chunks/{LpSidebar-D-M0Y_7U.js → LpSidebar-D44peKq2.js} +3 -3
  81. package/dist/chunks/{LpSidebarNav-DF-TYxOV.js → LpSidebarNav--VwkXO_a.js} +3 -3
  82. package/dist/chunks/{LpSlider-DuoRpOrH.js → LpSlider-DxYoCJJO.js} +3 -0
  83. package/dist/chunks/{LpStat-B2ix1Q7t.js → LpStat-DIsQfbeD.js} +3 -3
  84. package/dist/chunks/{LpStatus-C7kx5PKE.js → LpStatus-BQU1TUsv.js} +2 -2
  85. package/dist/chunks/{LpStepMark-DK-5BKAt.js → LpStepMark-CXa7DJy_.js} +2 -2
  86. package/dist/chunks/{LpStepper-DRFfdJaq.js → LpStepper-C9RM_yTG.js} +1 -1
  87. package/dist/chunks/{LpSwitch-DrzKrZZV.js → LpSwitch-bGZxUDSx.js} +3 -0
  88. package/dist/chunks/{LpTableFilter-DyvHGbOk.js → LpTableFilter-CTZMqFDU.js} +2 -2
  89. package/dist/chunks/{LpTableOfContents-rYvo8z5T.js → LpTableOfContents-CraicEs4.js} +2 -2
  90. package/dist/chunks/{LpTagsInput-DgpBFRV2.js → LpTagsInput-DrjmrOge.js} +8 -5
  91. package/dist/chunks/{LpTextarea-DiWjeVoJ.js → LpTextarea-BbYqmG1S.js} +4 -1
  92. package/dist/chunks/{LpThemeStudio-DguwHdGt.js → LpThemeStudio-B2nPaG-h.js} +18 -14
  93. package/dist/chunks/{LpThemeSwitcher-D5uz0MhK.js → LpThemeSwitcher-C0A5sg_E.js} +6 -4
  94. package/dist/chunks/{LpTimeField-BFQVf_PW.js → LpTimeField-DQ8WvPr2.js} +4 -1
  95. package/dist/chunks/{LpToaster-Wv9ksj4q.js → LpToaster-BTTl_wuy.js} +2 -2
  96. package/dist/chunks/{LpTooltip-Cz8SQwRt.js → LpTooltip-BcBvIx4z.js} +23 -5
  97. package/dist/chunks/{LpTopologyCanvas-ZhKthfgz.js → LpTopologyCanvas-B0wEvAoq.js} +1 -1
  98. package/dist/chunks/{LpTour-NfRJNEIP.js → LpTour-BgCfNlaW.js} +1 -1
  99. package/dist/chunks/{LpTruncate-D_5Pfv5B.js → LpTruncate-TcqfkyJM.js} +2 -2
  100. package/dist/chunks/{LpUptimeBar-DWegV2p6.js → LpUptimeBar-DRadGq4Y.js} +136 -47
  101. package/dist/chunks/{MenuTitle-BjQZX8tQ.js → MenuTitle-Dab3EGOp.js} +1 -1
  102. package/dist/chunks/{OptionContent-CmYUUeWj.js → OptionContent-DPzNsybd.js} +1 -1
  103. package/dist/chunks/PalettePreviewBoundary-B0Hhu3Yw.js +20 -0
  104. package/dist/chunks/{PickerField-CHRS1h7K.js → PickerField-DwLw7j0L.js} +26 -17
  105. package/dist/chunks/{RevealToggle-C-KzaQGJ.js → RevealToggle-BVFM_FAU.js} +3 -3
  106. package/dist/chunks/{TourCard-BXuVHsfn.js → TourCard--2IfgnUU.js} +3 -3
  107. package/dist/chunks/icons-CLu1iR1j.js +43 -0
  108. package/dist/chunks/palette-BiY7yQZL.js +29 -0
  109. package/dist/component-names.d.ts +1 -1
  110. package/dist/components/ContextMenuItems.vue.js +1 -1
  111. package/dist/components/DropzoneLinkField.vue.js +1 -1
  112. package/dist/components/FieldWrapper.vue.js +1 -1
  113. package/dist/components/LayoutCanvas.vue.js +1 -1
  114. package/dist/components/LayoutNode.vue.js +1 -1
  115. package/dist/components/LpActionBar.vue.js +1 -1
  116. package/dist/components/LpAddressInput.vue.d.ts +1 -1
  117. package/dist/components/LpAddressInput.vue.js +1 -1
  118. package/dist/components/LpAlert.vue.d.ts +3 -3
  119. package/dist/components/LpAlert.vue.js +1 -1
  120. package/dist/components/LpAppShell.vue.js +1 -1
  121. package/dist/components/LpAutocomplete.vue.d.ts +7 -1
  122. package/dist/components/LpAutocomplete.vue.js +1 -1
  123. package/dist/components/LpAvatar.vue.js +1 -1
  124. package/dist/components/LpBadge.vue.d.ts +2 -2
  125. package/dist/components/LpBadge.vue.js +1 -1
  126. package/dist/components/LpBreadcrumbs.vue.js +1 -1
  127. package/dist/components/LpButton.vue.d.ts +4 -0
  128. package/dist/components/LpButton.vue.js +1 -1
  129. package/dist/components/LpCalendar.vue.js +1 -1
  130. package/dist/components/LpChart.vue.js +27 -25
  131. package/dist/components/LpCheckbox.vue.d.ts +8 -1
  132. package/dist/components/LpCheckbox.vue.js +1 -1
  133. package/dist/components/LpCodeBlock.vue.js +1 -1
  134. package/dist/components/LpCodeDisplay.vue.js +1 -1
  135. package/dist/components/LpColorPicker.vue.d.ts +2 -2
  136. package/dist/components/LpColorPicker.vue.js +1 -1
  137. package/dist/components/LpCommandPalette.vue.d.ts +43 -7
  138. package/dist/components/LpCommandPalette.vue.js +451 -126
  139. package/dist/components/LpCommandScope.vue.d.ts +28 -0
  140. package/dist/components/LpCommandScope.vue.js +4 -0
  141. package/dist/components/LpConfirmDialog.vue.js +1 -1
  142. package/dist/components/LpConfirmHost.vue.js +1 -1
  143. package/dist/components/LpContextMenu.vue.d.ts +5 -1
  144. package/dist/components/LpContextMenu.vue.js +1 -1
  145. package/dist/components/LpCopyButton.vue.d.ts +1 -1
  146. package/dist/components/LpCopyButton.vue.js +1 -1
  147. package/dist/components/LpCountdown.vue.js +1 -1
  148. package/dist/components/LpDataList.vue.js +1 -1
  149. package/dist/components/LpDatePicker.vue.d.ts +2 -0
  150. package/dist/components/LpDatePicker.vue.js +1 -1
  151. package/dist/components/LpDateRangePicker.vue.d.ts +2 -0
  152. package/dist/components/LpDateRangePicker.vue.js +1 -1
  153. package/dist/components/LpDisclosure.vue.d.ts +4 -0
  154. package/dist/components/LpDisclosure.vue.js +1 -1
  155. package/dist/components/LpDock.vue.js +2 -2
  156. package/dist/components/LpDrawer.vue.js +1 -1
  157. package/dist/components/LpDropdownMenu.vue.d.ts +5 -1
  158. package/dist/components/LpDropdownMenu.vue.js +1 -1
  159. package/dist/components/LpDropzone.vue.js +2 -2
  160. package/dist/components/LpEditable.vue.js +1 -1
  161. package/dist/components/LpEmptyState.vue.js +1 -1
  162. package/dist/components/LpFieldNotice.vue.js +1 -1
  163. package/dist/components/LpFileTree.vue.d.ts +1 -1
  164. package/dist/components/LpFileTree.vue.js +1 -1
  165. package/dist/components/LpFileTreeNode.vue.js +1 -1
  166. package/dist/components/LpFormField.vue.js +1 -1
  167. package/dist/components/LpGauge.vue.js +1 -1
  168. package/dist/components/LpHintLayer.vue.js +1 -1
  169. package/dist/components/LpHints.vue.js +1 -1
  170. package/dist/components/LpIcon.vue.js +1 -1
  171. package/dist/components/LpImageEditor.vue.js +3 -2
  172. package/dist/components/LpInfraNode.vue.js +1 -1
  173. package/dist/components/LpInput.vue.d.ts +6 -0
  174. package/dist/components/LpInput.vue.js +1 -1
  175. package/dist/components/LpLightbox.vue.js +1 -1
  176. package/dist/components/LpLoader.vue.d.ts +1 -1
  177. package/dist/components/LpLogViewer.vue.js +1 -1
  178. package/dist/components/LpMapPicker.vue.js +1 -1
  179. package/dist/components/LpMediaGallery.vue.d.ts +2 -2
  180. package/dist/components/LpMediaGallery.vue.js +1 -1
  181. package/dist/components/LpModal.vue.js +1 -1
  182. package/dist/components/LpModalNav.vue.js +1 -1
  183. package/dist/components/LpNotificationBell.vue.js +1 -1
  184. package/dist/components/LpNumberField.vue.d.ts +6 -0
  185. package/dist/components/LpNumberField.vue.js +1 -1
  186. package/dist/components/LpNumberFlow.vue.js +1 -1
  187. package/dist/components/LpPagination.vue.js +1 -1
  188. package/dist/components/LpPaletteFacts.vue.d.ts +1 -0
  189. package/dist/components/LpPaletteFacts.vue.js +40 -26
  190. package/dist/components/LpPaletteHeader.vue.js +2 -2
  191. package/dist/components/LpPaletteStats.vue.d.ts +1 -0
  192. package/dist/components/LpPaletteStats.vue.js +45 -21
  193. package/dist/components/LpPaletteTheme.vue.d.ts +7 -0
  194. package/dist/components/LpPaletteTheme.vue.js +4 -0
  195. package/dist/components/LpPasswordInput.vue.d.ts +7 -1
  196. package/dist/components/LpPasswordInput.vue.js +1 -1
  197. package/dist/components/LpPhoneInput.vue.js +1 -1
  198. package/dist/components/LpPie.vue.js +1 -1
  199. package/dist/components/LpPipeline.vue.js +1 -1
  200. package/dist/components/LpPopover.vue.js +1 -1
  201. package/dist/components/LpProgress.vue.d.ts +1 -1
  202. package/dist/components/LpProgress.vue.js +1 -1
  203. package/dist/components/LpQuota.vue.js +1 -1
  204. package/dist/components/LpRadioGroup.vue.d.ts +6 -1
  205. package/dist/components/LpRadioGroup.vue.js +1 -1
  206. package/dist/components/LpRangeCalendar.vue.js +1 -1
  207. package/dist/components/LpRangeSlider.vue.d.ts +6 -0
  208. package/dist/components/LpRangeSlider.vue.js +1 -1
  209. package/dist/components/LpRelativeTime.vue.js +1 -1
  210. package/dist/components/LpRepeater.vue.js +1 -1
  211. package/dist/components/LpRollingText.vue.d.ts +2 -0
  212. package/dist/components/LpRollingText.vue.js +1 -1
  213. package/dist/components/LpSecretField.vue.js +1 -1
  214. package/dist/components/LpSection.vue.js +1 -1
  215. package/dist/components/LpSegmented.vue.d.ts +6 -0
  216. package/dist/components/LpSegmented.vue.js +1 -1
  217. package/dist/components/LpSelect.vue.d.ts +3 -0
  218. package/dist/components/LpSelect.vue.js +1 -1
  219. package/dist/components/LpShinyText.vue.d.ts +1 -1
  220. package/dist/components/LpShortcutsDialog.vue.js +1 -1
  221. package/dist/components/LpSidebar.vue.js +1 -1
  222. package/dist/components/LpSidebarNav.vue.js +1 -1
  223. package/dist/components/LpSlider.vue.d.ts +6 -0
  224. package/dist/components/LpSlider.vue.js +1 -1
  225. package/dist/components/LpStat.vue.js +1 -1
  226. package/dist/components/LpStatus.vue.js +1 -1
  227. package/dist/components/LpStepMark.vue.js +1 -1
  228. package/dist/components/LpStepper.vue.js +1 -1
  229. package/dist/components/LpSwitch.vue.d.ts +6 -0
  230. package/dist/components/LpSwitch.vue.js +1 -1
  231. package/dist/components/LpTable.vue.d.ts +6 -0
  232. package/dist/components/LpTable.vue.js +74 -35
  233. package/dist/components/LpTableFilter.vue.js +1 -1
  234. package/dist/components/LpTableOfContents.vue.js +1 -1
  235. package/dist/components/LpTabs.vue.d.ts +1 -1
  236. package/dist/components/LpTabs.vue.js +15 -6
  237. package/dist/components/LpTagsInput.vue.d.ts +6 -0
  238. package/dist/components/LpTagsInput.vue.js +1 -1
  239. package/dist/components/LpTextarea.vue.d.ts +8 -1
  240. package/dist/components/LpTextarea.vue.js +1 -1
  241. package/dist/components/LpThemeStudio.vue.js +1 -1
  242. package/dist/components/LpThemeSwitcher.vue.js +1 -1
  243. package/dist/components/LpTimeField.vue.d.ts +6 -0
  244. package/dist/components/LpTimeField.vue.js +1 -1
  245. package/dist/components/LpToaster.vue.js +1 -1
  246. package/dist/components/LpTooltip.vue.js +1 -1
  247. package/dist/components/LpTopologyCanvas.vue.js +1 -1
  248. package/dist/components/LpTour.vue.js +1 -1
  249. package/dist/components/LpTruncate.vue.js +1 -1
  250. package/dist/components/LpUptimeBar.vue.d.ts +18 -9
  251. package/dist/components/LpUptimeBar.vue.js +1 -1
  252. package/dist/components/MenuTitle.vue.js +1 -1
  253. package/dist/components/OptionContent.vue.js +1 -1
  254. package/dist/components/PalettePreviewBoundary.vue.d.ts +13 -0
  255. package/dist/components/PalettePreviewBoundary.vue.js +4 -0
  256. package/dist/components/PickerField.vue.d.ts +5 -3
  257. package/dist/components/PickerField.vue.js +1 -1
  258. package/dist/components/RevealToggle.vue.js +1 -1
  259. package/dist/components/TourCard.vue.js +1 -1
  260. package/dist/components/commandPalette.d.ts +33 -0
  261. package/dist/components/commandPalette.js +21 -1
  262. package/dist/components/commandSearch.d.ts +5 -0
  263. package/dist/components/commandSearch.js +22 -2
  264. package/dist/components/format.d.ts +7 -0
  265. package/dist/components/format.js +4 -0
  266. package/dist/components/menuWhen.js +1 -1
  267. package/dist/components/uptimeBar.d.ts +45 -0
  268. package/dist/components/uptimeBar.js +51 -0
  269. package/dist/composables/scroll.d.ts +5 -0
  270. package/dist/composables/scroll.js +7 -0
  271. package/dist/composables/useField.d.ts +9 -0
  272. package/dist/composables/useField.js +24 -1
  273. package/dist/composables/useForm.js +13 -4
  274. package/dist/composables/usePaletteCommands.d.ts +61 -0
  275. package/dist/composables/usePaletteCommands.js +220 -0
  276. package/dist/composables/useReveal.js +21 -0
  277. package/dist/composables/useView.js +9 -2
  278. package/dist/icons-all.js +1 -1
  279. package/dist/index.d.ts +14 -1
  280. package/dist/index.js +103 -87
  281. package/dist/theme/palette.d.ts +9 -0
  282. package/dist/theme/studio.d.ts +12 -1
  283. package/package.json +4 -1
  284. package/src/component-names.ts +2 -0
  285. package/src/components/ContextMenuItems.vue +5 -2
  286. package/src/components/LpAutocomplete.vue +6 -1
  287. package/src/components/LpButton.vue +5 -1
  288. package/src/components/LpChart.vue +19 -17
  289. package/src/components/LpCheckbox.vue +7 -2
  290. package/src/components/LpCommandPalette.vue +263 -29
  291. package/src/components/LpCommandScope.vue +35 -0
  292. package/src/components/LpContextMenu.vue +17 -5
  293. package/src/components/LpDataList.vue +2 -2
  294. package/src/components/LpDatePicker.vue +2 -0
  295. package/src/components/LpDateRangePicker.vue +2 -0
  296. package/src/components/LpDisclosure.vue +5 -1
  297. package/src/components/LpDropdownMenu.vue +14 -3
  298. package/src/components/LpEditable.vue +3 -1
  299. package/src/components/LpFormField.vue +3 -0
  300. package/src/components/LpInput.vue +6 -1
  301. package/src/components/LpNumberField.vue +6 -1
  302. package/src/components/LpNumberFlow.vue +12 -2
  303. package/src/components/LpPaletteFacts.vue +11 -6
  304. package/src/components/LpPaletteStats.vue +12 -5
  305. package/src/components/LpPaletteTheme.vue +48 -0
  306. package/src/components/LpPasswordInput.vue +13 -5
  307. package/src/components/LpPopover.vue +4 -0
  308. package/src/components/LpRadioGroup.vue +4 -1
  309. package/src/components/LpRangeSlider.vue +6 -1
  310. package/src/components/LpRepeater.vue +64 -13
  311. package/src/components/LpRollingText.vue +12 -1
  312. package/src/components/LpSecretField.vue +18 -8
  313. package/src/components/LpSegmented.vue +6 -1
  314. package/src/components/LpSelect.vue +44 -10
  315. package/src/components/LpSlider.vue +6 -1
  316. package/src/components/LpSwitch.vue +6 -1
  317. package/src/components/LpTable.vue +35 -2
  318. package/src/components/LpTableOfContents.vue +2 -4
  319. package/src/components/LpTabs.vue +7 -0
  320. package/src/components/LpTagsInput.vue +6 -1
  321. package/src/components/LpTextarea.vue +7 -2
  322. package/src/components/LpThemeStudio.vue +7 -5
  323. package/src/components/LpThemeSwitcher.vue +3 -0
  324. package/src/components/LpTimeField.vue +6 -1
  325. package/src/components/LpTooltip.vue +23 -1
  326. package/src/components/LpUptimeBar.vue +69 -41
  327. package/src/components/PalettePreviewBoundary.vue +5 -0
  328. package/src/components/PickerField.vue +5 -4
  329. package/src/components/commandPalette.ts +22 -1
  330. package/src/components/commandSearch.ts +23 -1
  331. package/src/components/format.ts +10 -0
  332. package/src/components/uptimeBar.ts +98 -0
  333. package/src/composables/scroll.ts +11 -0
  334. package/src/composables/useField.ts +33 -1
  335. package/src/composables/useForm.ts +14 -5
  336. package/src/composables/usePaletteCommands.ts +220 -0
  337. package/src/composables/useReveal.ts +29 -0
  338. package/src/composables/useView.ts +8 -1
  339. package/src/index.ts +18 -1
  340. package/src/kit-icons.ts +1 -1
  341. package/src/theme/palette.ts +26 -0
  342. package/src/theme/studio.ts +15 -8
  343. package/dist/assets/LpTabs-BJ-nrJuI.css +0 -18
  344. package/dist/chunks/LpRepeater-D0VjmD6y.js +0 -140
  345. package/dist/chunks/icons-4IywzkHk.js +0 -43
@@ -4,8 +4,10 @@ import { useFieldControl } from "../composables/useField"
4
4
  import { useLabels } from "../composables/useLpConfig"
5
5
  import { useMergedAttrs } from "../composables/useMergedClass"
6
6
  import { useRepeater, type RepeaterItemKey } from "../composables/useRepeater"
7
+ import { usePrefersReducedMotion } from "../composables/useReducedMotion"
7
8
  import LpButton from "./LpButton.vue"
8
9
  import LpIcon from "./LpIcon.vue"
10
+ import LpShift from "./LpShift.vue"
9
11
 
10
12
  defineOptions({ inheritAttrs: false })
11
13
  const props = defineProps<{
@@ -33,11 +35,31 @@ const list = useRepeater({
33
35
  disabled: () => field.value.disabled,
34
36
  })
35
37
  const { rows } = list
36
- const root = ref<HTMLElement | null>(null)
38
+ const rowsHost = ref<HTMLElement | null>(null)
39
+ const reducedMotion = usePrefersReducedMotion()
37
40
  const addButton = ref<InstanceType<typeof LpButton> | null>(null)
38
41
  const focusable = 'input:not([type="hidden"]):not([disabled]), textarea:not([disabled]), select:not([disabled]), button:not([disabled]), [tabindex="0"], [contenteditable="true"]'
39
42
  function focusRow(index: number) {
40
- root.value?.querySelectorAll<HTMLElement>("[data-lp-repeater-row]")[index]?.querySelector<HTMLElement>(focusable)?.focus()
43
+ rowAt(index)?.querySelector<HTMLElement>(focusable)?.focus({ preventScroll: true })
44
+ }
45
+ function rowAt(index: number): HTMLElement | undefined {
46
+ return Array.from(rowsHost.value?.children ?? []).filter((node): node is HTMLElement =>
47
+ node.hasAttribute("data-lp-repeater-row") && !node.hasAttribute("inert"),
48
+ )[index]
49
+ }
50
+ function beforeLeave(el: Element) {
51
+ const row = el as HTMLElement
52
+ row.style.width = `${row.offsetWidth}px`
53
+ row.style.top = `${row.offsetTop}px`
54
+ row.setAttribute("inert", "")
55
+ row.setAttribute("aria-hidden", "true")
56
+ }
57
+ function beforeEnter(el: Element) {
58
+ const row = el as HTMLElement
59
+ row.removeAttribute("inert")
60
+ row.removeAttribute("aria-hidden")
61
+ row.style.removeProperty("top")
62
+ row.style.removeProperty("width")
41
63
  }
42
64
  async function add() {
43
65
  if (field.value.disabled) return
@@ -47,34 +69,63 @@ async function add() {
47
69
  }
48
70
  async function remove(index: number) {
49
71
  if (field.value.disabled) return
50
- const row = root.value?.querySelectorAll<HTMLElement>("[data-lp-repeater-row]")[index]
72
+ const row = rowAt(index)
51
73
  const restore = row?.contains(row.ownerDocument.activeElement)
52
74
  list.remove(index)
53
75
  if (!restore) return
54
76
  await nextTick()
55
77
  if (model.value.length) focusRow(Math.min(index, model.value.length - 1))
56
- else (addButton.value?.$el as HTMLElement | undefined)?.focus()
78
+ else (addButton.value?.$el as HTMLElement | undefined)?.focus({ preventScroll: true })
57
79
  }
58
80
  defineExpose({ add, remove, update: list.update })
59
81
  const { class: rootClass, attrs: rest } = useMergedAttrs("flex min-w-0 flex-col gap-2")
60
82
  </script>
61
83
 
62
84
  <template>
63
- <div ref="root" v-bind="rest" :class="rootClass">
85
+ <div v-bind="rest" :class="rootClass">
64
86
  <div class="flex items-center justify-between gap-2">
65
87
  <span v-if="label" class="text-sm font-medium text-ink">{{ label }}</span>
66
88
  <LpButton ref="addButton" size="xs" variant="ghost" :disabled="field.disabled" @click="add">
67
89
  <LpIcon name="lucide:plus" :size="14" />{{ text.add }}
68
90
  </LpButton>
69
91
  </div>
70
- <div v-for="({ item, key }, index) in rows" :key="key" data-lp-repeater-row class="flex min-w-0 items-start gap-2">
71
- <div class="min-w-0 flex-1">
72
- <slot :item="item" :index="index" :disabled="field.disabled" :update="(next: T) => list.update(index, next)" :remove="() => remove(index)" />
92
+ <LpShift axis="height">
93
+ <div ref="rowsHost" class="relative flex min-w-0 flex-col gap-2">
94
+ <TransitionGroup name="lp-repeater" :css="!reducedMotion" @before-enter="beforeEnter" @before-leave="beforeLeave">
95
+ <div v-for="({ item, key }, index) in rows" :key="key" data-lp-repeater-row class="flex min-w-0 items-start gap-2">
96
+ <div class="min-w-0 flex-1">
97
+ <slot :item="item" :index="index" :disabled="field.disabled" :update="(next: T) => list.update(index, next)" :remove="() => remove(index)" />
98
+ </div>
99
+ <LpButton variant="ghost" size="sm" square :disabled="field.disabled" :aria-label="text.remove.replace('{index}', String(index + 1))" @click="remove(index)">
100
+ <LpIcon name="lucide:x" :size="14" />
101
+ </LpButton>
102
+ </div>
103
+ <div v-if="!rows.length" key="empty" class="text-xs text-muted"><slot name="empty">{{ text.empty }}</slot></div>
104
+ </TransitionGroup>
73
105
  </div>
74
- <LpButton variant="ghost" size="sm" square :disabled="field.disabled" :aria-label="text.remove.replace('{index}', String(index + 1))" @click="remove(index)">
75
- <LpIcon name="lucide:x" :size="14" />
76
- </LpButton>
77
- </div>
78
- <div v-if="!rows.length" class="text-xs text-muted"><slot name="empty">{{ text.empty }}</slot></div>
106
+ </LpShift>
79
107
  </div>
80
108
  </template>
109
+
110
+ <style>
111
+ .lp-repeater-move,
112
+ .lp-repeater-enter-active,
113
+ .lp-repeater-leave-active {
114
+ transition: transform var(--duration-fast) var(--ease-emphasized), opacity var(--duration-fast) var(--ease-emphasized);
115
+ }
116
+ .lp-repeater-leave-active {
117
+ position: absolute;
118
+ }
119
+ .lp-repeater-enter-from,
120
+ .lp-repeater-leave-to {
121
+ opacity: 0;
122
+ transform: translateY(-0.5rem);
123
+ }
124
+ @media (prefers-reduced-motion: reduce) {
125
+ .lp-repeater-move,
126
+ .lp-repeater-enter-active,
127
+ .lp-repeater-leave-active {
128
+ transition: none;
129
+ }
130
+ }
131
+ </style>
@@ -35,6 +35,8 @@ const props = withDefaults(
35
35
  * width — a value that grows shouldn't shove its neighbours.
36
36
  */
37
37
  align?: "start" | "center" | "end"
38
+ /** Wrap to the available width instead of keeping a single line. */
39
+ wrap?: boolean
38
40
  }>(),
39
41
  { mode: "slide", direction: "up", duration: 320, align: "center" },
40
42
  )
@@ -63,7 +65,7 @@ const style = computed(() => ({
63
65
  <template>
64
66
  <span
65
67
  class="lp-roll relative inline-flex overflow-hidden align-bottom"
66
- :class="justify"
68
+ :class="[justify, wrap && 'lp-roll--wrap']"
67
69
  :style="style"
68
70
  >
69
71
  <Transition :name="name">
@@ -93,6 +95,15 @@ const style = computed(() => ({
93
95
  backface-visibility: hidden;
94
96
  }
95
97
 
98
+ .lp-roll--wrap {
99
+ max-width: 100%;
100
+ }
101
+
102
+ .lp-roll--wrap .lp-roll__item {
103
+ white-space: normal;
104
+ overflow-wrap: anywhere;
105
+ }
106
+
96
107
  /* The outgoing copy leaves the flow so the incoming one keeps the baseline. */
97
108
  .lp-roll-up-leave-active,
98
109
  .lp-roll-down-leave-active,
@@ -12,6 +12,7 @@ export interface SecretFieldLabels extends Record<string, string> {
12
12
  </script>
13
13
 
14
14
  <script setup lang="ts">
15
+ import { suppressPaletteDiscovery } from "../composables/usePaletteCommands"
15
16
  /*
16
17
  * A value someone must be able to read and copy but should not have on screen
17
18
  * by default: an API key, a bot token, a webhook secret, a recovery code.
@@ -37,6 +38,7 @@ import { computed, onBeforeUnmount, onMounted, ref, useId, watch } from "vue"
37
38
  import { prefersReducedMotion } from "../composables/easing"
38
39
  import { useScramble } from "../composables/useScramble"
39
40
  import { useLabels } from "../composables/useLpConfig"
41
+ import { useFieldControl } from "../composables/useField"
40
42
  import { mergeClass } from "../composables/useMergedClass"
41
43
  import FieldWrapper from "./FieldWrapper.vue"
42
44
  import LpButton from "./LpButton.vue"
@@ -91,7 +93,11 @@ const emit = defineEmits<{
91
93
  }>()
92
94
 
93
95
  /** Shown or hidden; bind it to drive the reveal from outside. */
94
- const revealed = defineModel<boolean>("revealed", { default: false })
96
+ const revealedModel = defineModel<boolean>("revealed", { default: false })
97
+ const revealed = computed({
98
+ get: () => props.revealable && revealedModel.value,
99
+ set: (value: boolean) => { revealedModel.value = value },
100
+ })
95
101
 
96
102
  const text = useLabels<SecretFieldLabels>(
97
103
  "secretField",
@@ -107,6 +113,7 @@ const text = useLabels<SecretFieldLabels>(
107
113
  )
108
114
 
109
115
  const secret = computed(() => (props.input ? props.modelValue : props.value) ?? "")
116
+ const control = useFieldControl(() => ({ wrapped: false, disabled: props.disabled }))
110
117
 
111
118
  // Revealing decrypts the value into place, and a new value (a regenerated key)
112
119
  // decrypts over the old one: the change is seen happening, not just swapped.
@@ -167,11 +174,13 @@ const shell = computed(() =>
167
174
  mergeClass(
168
175
  "relative flex w-full items-center gap-1 overflow-hidden rounded-control border bg-surface-soft text-ink transition-colors duration-(--duration-fast)",
169
176
  props.error ? "border-danger" : "border-line",
170
- props.disabled ? "opacity-55" : "",
177
+ control.value.disabled ? "opacity-55" : "",
171
178
  props.wrap ? "py-1.5" : "",
172
179
  { sm: "min-h-(--size-control-sm) pl-2.5 pr-1 text-xs", md: "min-h-(--size-control-md) pl-3 pr-1.5 text-sm", lg: "min-h-(--size-control-lg) pl-3.5 pr-1.5 text-sm" }[props.size],
173
180
  ),
174
181
  )
182
+
183
+ suppressPaletteDiscovery()
175
184
  </script>
176
185
 
177
186
  <template>
@@ -184,7 +193,8 @@ const shell = computed(() =>
184
193
  class="[&_input]:font-mono"
185
194
  :model-value="modelValue"
186
195
  :placeholder="placeholder"
187
- :disabled="disabled"
196
+ :disabled="control.disabled"
197
+ :revealable="revealable"
188
198
  :label="label"
189
199
  :hint="hint"
190
200
  :error="error"
@@ -199,7 +209,7 @@ const shell = computed(() =>
199
209
  :value="secret"
200
210
  size="xs"
201
211
  class="size-7"
202
- :disabled="disabled"
212
+ :disabled="control.disabled"
203
213
  @copied="(t: string) => emit('copied', t)"
204
214
  />
205
215
  <slot name="actions" />
@@ -212,7 +222,7 @@ const shell = computed(() =>
212
222
  :aria-label="text.regenerate"
213
223
  :title="text.regenerate"
214
224
  :action="regenerate"
215
- :disabled="disabled"
225
+ :disabled="control.disabled"
216
226
  >
217
227
  <LpIcon name="lucide:refresh-cw" :size="iconSize" />
218
228
  </LpButton>
@@ -264,7 +274,7 @@ const shell = computed(() =>
264
274
  :icon-size="iconSize"
265
275
  :show-label="text.show"
266
276
  :hide-label="text.hide"
267
- :disabled="disabled"
277
+ :disabled="control.disabled"
268
278
  :controls="id"
269
279
  class="size-7"
270
280
  />
@@ -273,7 +283,7 @@ const shell = computed(() =>
273
283
  :value="secret"
274
284
  :size="copySize"
275
285
  class="size-7 text-muted hover:text-ink"
276
- :disabled="disabled"
286
+ :disabled="control.disabled"
277
287
  @copied="(t: string) => emit('copied', t)"
278
288
  />
279
289
  <slot name="actions" />
@@ -284,7 +294,7 @@ const shell = computed(() =>
284
294
  square
285
295
  class="size-7 text-muted hover:text-ink"
286
296
  :action="regenerate"
287
- :disabled="disabled"
297
+ :disabled="control.disabled"
288
298
  >
289
299
  <LpIcon name="lucide:refresh-cw" :size="iconSize" />
290
300
  </LpButton>
@@ -6,6 +6,7 @@ export default { inheritAttrs: false }
6
6
  </script>
7
7
 
8
8
  <script setup lang="ts">
9
+ import { usePaletteControl, type PaletteControlOptions } from "../composables/usePaletteCommands"
9
10
  /*
10
11
  * Segmented control — a compact bar of mutually-exclusive options with a sliding
11
12
  * pill marking the selection (iOS-style). Built on reka ToggleGroup for the
@@ -36,6 +37,8 @@ export interface SegmentedOption extends LpOptionBase<string> {
36
37
 
37
38
  const props = withDefaults(
38
39
  defineProps<{
40
+ /** Contextual palette metadata; false excludes this control. */
41
+ palette?: PaletteControlOptions
39
42
  modelValue?: string
40
43
  options: SegmentedOption[]
41
44
  size?: "sm" | "md" | "lg"
@@ -49,7 +52,7 @@ const props = withDefaults(
49
52
  */
50
53
  hoverFollow?: boolean
51
54
  }>(),
52
- { size: "md", block: false, hoverFollow: true },
55
+ { palette: undefined, size: "md", block: false, hoverFollow: true },
53
56
  )
54
57
 
55
58
  const emit = defineEmits<{
@@ -106,6 +109,8 @@ function releaseFocusAfterPointer(event: PointerEvent) {
106
109
  const target = event.currentTarget
107
110
  if (target instanceof HTMLElement) target.blur()
108
111
  }
112
+
113
+ usePaletteControl({ disabled: () => field.value.disabled })
109
114
  </script>
110
115
 
111
116
  <template>
@@ -16,6 +16,7 @@ export type SelectLabels = {
16
16
  </script>
17
17
 
18
18
  <script setup lang="ts" generic="V extends SelectValue = string">
19
+ import { usePaletteControl, type PaletteControlOptions } from "../composables/usePaletteCommands"
19
20
  /*
20
21
  * One select to rule them all — built on reka-ui Combobox.
21
22
  * `searchable` opts into the filter input; without it, it's a plain select.
@@ -36,7 +37,7 @@ import {
36
37
  ComboboxViewport,
37
38
  } from "reka-ui"
38
39
  import { computed, nextTick, reactive, ref, useAttrs, useId, watch } from "vue"
39
- import { useFieldControl } from "../composables/useField"
40
+ import { useFieldBlur, useFieldControl } from "../composables/useField"
40
41
  import { useLabels } from "../composables/useLpConfig"
41
42
  import { useMergedAttrs } from "../composables/useMergedClass"
42
43
  import { OPTION_ITEM, optionStagger, POPOVER_PANEL } from "./dropdown"
@@ -61,6 +62,8 @@ type Model = V | V[] | undefined
61
62
 
62
63
  const props = withDefaults(
63
64
  defineProps<{
65
+ /** Contextual palette metadata; false excludes this control. */
66
+ palette?: PaletteControlOptions
64
67
  modelValue?: Model
65
68
  options: SelectOption<V>[]
66
69
  placeholder?: string
@@ -90,7 +93,7 @@ const props = withDefaults(
90
93
  selected?: SelectSelection | (SelectSelection | null | undefined)[] | null
91
94
  labels?: Partial<SelectLabels>
92
95
  }>(),
93
- {
96
+ { palette: undefined,
94
97
  searchable: false,
95
98
  multiple: false,
96
99
  clearable: false,
@@ -173,16 +176,42 @@ function onOpenChange(open: boolean) {
173
176
  isOpen.value = open
174
177
  query.value = ""
175
178
  }
179
+ async function openFromKeyboard(event: KeyboardEvent) {
180
+ if (field.value.disabled || isOpen.value || !["ArrowDown", "ArrowUp"].includes(event.key)) return
181
+ event.preventDefault()
182
+ event.stopPropagation()
183
+ const trigger = event.currentTarget as HTMLElement
184
+ trigger.click()
185
+ await nextTick()
186
+ const panel = trigger.ownerDocument.getElementById(trigger.getAttribute("aria-controls") ?? "")
187
+ const search = panel?.querySelector<HTMLInputElement>('input:not([disabled])')
188
+ const items = panel?.querySelectorAll<HTMLElement>('[role="option"]:not([data-disabled])')
189
+ const selected = panel?.querySelector<HTMLElement>('[role="option"][aria-selected="true"]:not([data-disabled])')
190
+ const target = search ?? selected ?? (event.key === "ArrowUp" ? items?.[items.length - 1] : items?.[0])
191
+ target?.focus()
192
+ }
176
193
 
177
194
  // Leaving the field, not moving between its parts: the trigger and the list
178
195
  // are marked with one id, because the list is portalled away from the trigger
179
196
  // and a check on the trigger alone either missed the search box or took a
180
197
  // step into it for leaving.
181
- const partOf = `lp-select-${useId()}`
182
- function onFocusOut(event: FocusEvent) {
183
- const next = event.relatedTarget as Element | null
184
- const inside = !!next && typeof next.closest === "function" && !!next.closest(`[data-lp-select-part="${partOf}"]`)
185
- if (!inside) emit("blur", event)
198
+ const { partId, onFocusOut } = useFieldBlur((event) => emit("blur", event))
199
+ const triggerRef = ref<{ $el: HTMLElement } | null>(null)
200
+
201
+ /*
202
+ * A pick closes the list while the chosen option still holds focus, then the
203
+ * option is removed and focus falls to the body: the field looked left, and
204
+ * the next arrow key went to the page (inside the palette's editor it went
205
+ * nowhere). Focus dropped by a closed list goes back to the trigger instead,
206
+ * and that is not leaving the field, so no blur is reported for it.
207
+ */
208
+ function onListFocusOut(event: FocusEvent) {
209
+ const trigger = triggerRef.value?.$el
210
+ if (isOpen.value || event.relatedTarget || !trigger?.isConnected) {
211
+ onFocusOut(event)
212
+ return
213
+ }
214
+ trigger.focus({ preventScroll: true })
186
215
  }
187
216
 
188
217
  /*
@@ -373,6 +402,8 @@ const portalTo = usePortalTarget()
373
402
  // What happens in another document (the page around a frame, or a frame in
374
403
  // the page) is not "outside" for this layer.
375
404
  const guardOutside = useOutsideGuard()
405
+
406
+ usePaletteControl({ disabled: () => field.value.disabled, invalid: () => field.value.invalid, editorProps: () => ({ selected: props.multiple ? modelList.value.map((value, index) => shown(value, index)) : current.value }) })
376
407
  </script>
377
408
 
378
409
  <template>
@@ -396,7 +427,7 @@ const guardOutside = useOutsideGuard()
396
427
  @update:open="onOpenChange"
397
428
  >
398
429
  <ComboboxAnchor
399
- :data-lp-select-part="partOf"
430
+ :data-lp-field-part="partId"
400
431
  @focusout="onFocusOut"
401
432
  :class="[
402
433
  anchorHeight,
@@ -413,7 +444,10 @@ const guardOutside = useOutsideGuard()
413
444
  being cut short. -->
414
445
  <span :id="valueId" hidden>{{ valueText }}</span>
415
446
  <ComboboxTrigger
447
+ ref="triggerRef"
416
448
  :id="field.id"
449
+ :tabindex="field.disabled ? -1 : 0"
450
+ @keydown="openFromKeyboard"
417
451
  v-bind="triggerName"
418
452
  :aria-invalid="field.invalid || undefined"
419
453
  :aria-describedby="field.describedBy"
@@ -528,8 +562,8 @@ const guardOutside = useOutsideGuard()
528
562
 
529
563
  <ComboboxPortal :to="portalTo">
530
564
  <ComboboxContent
531
- :data-lp-select-part="partOf"
532
- @focusout="onFocusOut"
565
+ :data-lp-field-part="partId"
566
+ @focusout="onListFocusOut"
533
567
  @interact-outside="guardOutside"
534
568
  @escape-key-down="guardOutside"
535
569
  position="popper"
@@ -6,6 +6,7 @@ export default { inheritAttrs: false }
6
6
  </script>
7
7
 
8
8
  <script setup lang="ts">
9
+ import { usePaletteControl, type PaletteControlOptions } from "../composables/usePaletteCommands"
9
10
  // Single-value slider (reka Slider). reka models value as an array; we expose
10
11
  // a plain number for the common single-thumb case. Themed via tokens.
11
12
  import { SliderRange, SliderRoot, SliderThumb, SliderTrack } from "reka-ui"
@@ -15,6 +16,8 @@ import { SLIDER_GLIDE, useSliderDrag } from "./slider"
15
16
 
16
17
  const props = withDefaults(
17
18
  defineProps<{
19
+ /** Contextual palette metadata; false excludes this control. */
20
+ palette?: PaletteControlOptions
18
21
  modelValue?: number
19
22
  min?: number
20
23
  max?: number
@@ -23,7 +26,7 @@ const props = withDefaults(
23
26
  /** Accessible name for the thumb when there's no visible label. */
24
27
  ariaLabel?: string
25
28
  }>(),
26
- { modelValue: 0, min: 0, max: 100, step: 1 },
29
+ { palette: undefined, modelValue: 0, min: 0, max: 100, step: 1 },
27
30
  )
28
31
 
29
32
  const emit = defineEmits<{
@@ -47,6 +50,8 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
47
50
  `relative flex h-5 w-full touch-none select-none items-center data-[disabled]:opacity-55 ${SLIDER_GLIDE}`,
48
51
  )
49
52
  const { dragging, onPointerDown } = useSliderDrag()
53
+
54
+ usePaletteControl({ disabled: () => field.value.disabled })
50
55
  </script>
51
56
 
52
57
  <template>
@@ -6,6 +6,7 @@ export default { inheritAttrs: false }
6
6
  </script>
7
7
 
8
8
  <script setup lang="ts">
9
+ import { usePaletteControl, type PaletteControlOptions } from "../composables/usePaletteCommands"
9
10
  import { computed, useId, useSlots } from "vue"
10
11
  import { SwitchRoot, SwitchThumb } from "reka-ui"
11
12
  import { useFieldControl } from "../composables/useField"
@@ -15,6 +16,8 @@ import { useMergedAttrs } from "../composables/useMergedClass"
15
16
 
16
17
  const props = withDefaults(
17
18
  defineProps<{
19
+ /** Contextual palette metadata; false excludes this control. */
20
+ palette?: PaletteControlOptions
18
21
  modelValue?: boolean
19
22
  disabled?: boolean
20
23
  label?: string
@@ -34,7 +37,7 @@ const props = withDefaults(
34
37
  */
35
38
  action?: (value: boolean) => unknown
36
39
  }>(),
37
- { labelPosition: "end" },
40
+ { palette: undefined, labelPosition: "end" },
38
41
  )
39
42
  const emit = defineEmits<{
40
43
  (e: "update:modelValue", value: boolean): void
@@ -79,6 +82,8 @@ const describedBy = computed(
79
82
  function onUpdate(value: boolean) {
80
83
  void set(value)
81
84
  }
85
+
86
+ usePaletteControl({ label: () => props.label, disabled: () => field.value.disabled || pending.value, editorProps: () => ({ action: undefined, 'onUpdate:modelValue': onUpdate }) })
82
87
  </script>
83
88
 
84
89
  <template>
@@ -5,7 +5,10 @@ export default { inheritAttrs: false }
5
5
  </script>
6
6
 
7
7
  <script setup lang="ts" generic="T extends Record<string, unknown>">
8
- import { computed, nextTick, onBeforeUnmount, onMounted, ref, shallowRef, useAttrs, watch } from "vue"
8
+ import { computed, h, nextTick, onBeforeUnmount, onMounted, ref, shallowRef, useAttrs, useId, watch } from "vue"
9
+ import { suppressPaletteDiscovery, usePaletteCommands, usePaletteScope } from "../composables/usePaletteCommands"
10
+ import { menuPaletteCommands } from "./commandPalette"
11
+ import LpDataList from "./LpDataList.vue"
9
12
  import LpCheckbox from "./LpCheckbox.vue"
10
13
  import LpContextMenu, { type ContextMenuItemDef } from "./LpContextMenu.vue"
11
14
  import LpEmptyState from "./LpEmptyState.vue"
@@ -157,6 +160,8 @@ type RowKey = string | number
157
160
 
158
161
  const props = withDefaults(
159
162
  defineProps<{
163
+ /** Publish loaded rows and existing row actions to the enclosing command scope. */
164
+ palette?: false | { id?: string; label?: string; labelKey?: keyof T }
160
165
  columns: TableColumn<T>[]
161
166
  /** The rows, for a table that holds its data. Ignored when `load` is set. */
162
167
  rows?: T[]
@@ -245,7 +250,7 @@ const props = withDefaults(
245
250
  */
246
251
  allMatching?: boolean
247
252
  }>(),
248
- {
253
+ { palette: undefined,
249
254
  rows: () => [],
250
255
  pageSize: 25,
251
256
  skeletonRows: 5,
@@ -1075,6 +1080,34 @@ onBeforeUnmount(() => {
1075
1080
  const barInsetTop = computed(() =>
1076
1081
  props.stickyHeader && headHeight.value ? `${headHeight.value}px` : undefined,
1077
1082
  )
1083
+
1084
+ const paletteScope = usePaletteScope()
1085
+ const paletteId = useId()
1086
+ suppressPaletteDiscovery()
1087
+ usePaletteCommands(() => {
1088
+ if (props.palette === false) return []
1089
+ const name = props.palette?.label ?? attrs["aria-label"] as string | undefined
1090
+ if (!name) return []
1091
+ const id = `${paletteScope?.id}/${props.palette?.id ?? paletteId}`
1092
+ return [{
1093
+ id, label: name, icon: "lucide:table", children: [
1094
+ ...menuPaletteCommands(tableMenu(), `${id}/table`),
1095
+ ...displayRows.value.map((row, index) => {
1096
+ const menu = resolveRowMenu(props.rowMenu?.(row))
1097
+ const rowId = `${id}/row/${keyFor(row, index)}`
1098
+ const labelKey = props.palette && props.palette.labelKey || props.columns[0]?.key
1099
+ return {
1100
+ id: rowId, label: menu.title ?? String(labelKey ? row[labelKey] ?? keyFor(row, index) : keyFor(row, index)),
1101
+ description: menu.subtitle, icon: menu.icon ?? "lucide:rows-3", image: menu.image,
1102
+ onSelect: () => emit("rowClick", row), actions: menuPaletteCommands(menu.items, rowId),
1103
+ previewComponent: { setup: () => () => h(LpDataList, { items: props.columns.map(column => ({
1104
+ label: column.label, value: typeof row[column.key] === "object" ? null : String(row[column.key] ?? ""),
1105
+ })) }) },
1106
+ }
1107
+ }),
1108
+ ],
1109
+ }]
1110
+ }, { automatic: true })
1078
1111
  </script>
1079
1112
 
1080
1113
  <template>
@@ -12,7 +12,7 @@
12
12
  import { Motion } from "motion-v"
13
13
  import { computed, onBeforeUnmount, onMounted, ref, useId, watch } from "vue"
14
14
  import { useLabels } from "../composables/useLpConfig"
15
- import { scrollParent } from "../composables/scroll"
15
+ import { atScrollEnd, scrollParent } from "../composables/scroll"
16
16
  import { usePillTransition } from "../composables/usePillTransition"
17
17
 
18
18
  export interface TocLink {
@@ -112,9 +112,7 @@ function setup() {
112
112
  const line = Math.max(props.offset, view / 4)
113
113
  for (const el of headings) if (el.getBoundingClientRect().top - top <= line + 1) current = el.id
114
114
  const scrolled = scroller ? scroller.scrollTop : window.scrollY
115
- const end = scroller
116
- ? scroller.scrollTop + scroller.clientHeight >= scroller.scrollHeight - 2
117
- : window.scrollY + window.innerHeight >= document.documentElement.scrollHeight - 2
115
+ const end = atScrollEnd(headings[0])
118
116
  if (scrolled > 0 && end) current = headings[headings.length - 1]!.id
119
117
  activeId.value = current
120
118
  }
@@ -1,4 +1,5 @@
1
1
  <script setup lang="ts">
2
+ import { usePaletteCommands, usePaletteScope } from "../composables/usePaletteCommands"
2
3
  import { Motion } from "motion-v"
3
4
  import { TabsContent, TabsList, TabsRoot, TabsTrigger } from "reka-ui"
4
5
  import { computed, nextTick, ref, useId, watch } from "vue"
@@ -152,6 +153,12 @@ function releaseFocusAfterPointer(event: PointerEvent) {
152
153
  const target = event.currentTarget
153
154
  if (target instanceof HTMLElement) target.blur()
154
155
  }
156
+
157
+ const paletteScope = usePaletteScope()
158
+ usePaletteCommands(() => props.items.map(item => ({
159
+ id: `${paletteScope?.id}/tabs/${pillId}/${item.value}`, label: props.label ? `${props.label}: ${item.label}` : item.label,
160
+ icon: item.icon, disabled: item.disabled, onSelect: () => select(item.value),
161
+ })), { automatic: true })
155
162
  </script>
156
163
 
157
164
  <template>
@@ -13,6 +13,7 @@ export type TagsInputLabels = {
13
13
  </script>
14
14
 
15
15
  <script setup lang="ts">
16
+ import { usePaletteControl, type PaletteControlOptions } from "../composables/usePaletteCommands"
16
17
  /*
17
18
  * Free-form list of short values: emails, labels, hostnames. Typing a
18
19
  * delimiter or Enter turns the text into a tag, a paste is split into many,
@@ -56,6 +57,8 @@ import { useOutsideGuard, usePortalTarget } from "../composables/useView"
56
57
 
57
58
  const props = withDefaults(
58
59
  defineProps<{
60
+ /** Contextual palette metadata; false excludes this control. */
61
+ palette?: PaletteControlOptions
59
62
  modelValue?: string[]
60
63
  placeholder?: string
61
64
  /** Characters (or a RegExp) that end a tag while typing and split a paste. */
@@ -99,7 +102,7 @@ const props = withDefaults(
99
102
  /** Box height and text size, as LpInput. */
100
103
  size?: "sm" | "md" | "lg"
101
104
  }>(),
102
- {
105
+ { palette: undefined,
103
106
  modelValue: () => [],
104
107
  delimiter: () => [",", "\n", "\t"],
105
108
  duplicates: "reject",
@@ -424,6 +427,8 @@ const portalTo = usePortalTarget()
424
427
  // What happens in another document (the page around a frame, or a frame in
425
428
  // the page) is not "outside" for this layer.
426
429
  const guardOutside = useOutsideGuard()
430
+
431
+ usePaletteControl({ label: () => props.label, disabled: () => field.value.disabled, invalid: () => field.value.invalid, editorProps: () => ({ label: undefined, hint: undefined, error: undefined }) })
427
432
  </script>
428
433
 
429
434
  <template>
@@ -3,12 +3,15 @@ export default { inheritAttrs: false }
3
3
  </script>
4
4
 
5
5
  <script setup lang="ts">
6
+ import { usePaletteControl, type PaletteControlOptions } from "../composables/usePaletteCommands"
6
7
  import { computed, useAttrs } from "vue"
7
8
  import { useFieldControl } from "../composables/useField"
8
9
  import { mergeClass } from "../composables/useMergedClass"
9
10
  import FieldWrapper from "./FieldWrapper.vue"
10
11
 
11
- const props = defineProps<{
12
+ const props = withDefaults(defineProps<{
13
+ /** Contextual palette metadata; false excludes this control. */
14
+ palette?: PaletteControlOptions
12
15
  modelValue?: string
13
16
  placeholder?: string
14
17
  rows?: number
@@ -22,7 +25,7 @@ const props = defineProps<{
22
25
  * the <textarea> for native validation.
23
26
  */
24
27
  required?: boolean
25
- }>()
28
+ }>(), { palette: undefined })
26
29
 
27
30
  defineEmits<{ (e: "update:modelValue", value: string): void }>()
28
31
 
@@ -53,6 +56,8 @@ const textareaClass = computed(() =>
53
56
  hasField.value ? "" : (attrs.class as string),
54
57
  ),
55
58
  )
59
+
60
+ usePaletteControl({ label: () => props.label, disabled: () => field.value.disabled, invalid: () => field.value.invalid, editorProps: () => ({ label: undefined, hint: undefined, error: undefined }) })
56
61
  </script>
57
62
 
58
63
  <template>