@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
@@ -1,4 +1,7 @@
1
1
  <script setup lang="ts">
2
+ import { useId } from "vue"
3
+ import { menuPaletteCommands } from "./commandPalette"
4
+ import { usePaletteCommands, usePaletteScope, type PaletteControlOptions } from "../composables/usePaletteCommands"
2
5
  /*
3
6
  * Right-click context menu (reka ContextMenu). Same items as LpDropdownMenu,
4
7
  * drawn by the same renderer: nested submenus (`children`), tick-box items and
@@ -14,7 +17,7 @@ import { HINT_SIGNALS, noteContextTarget } from "../composables/useHintSystem"
14
17
  import ContextMenuItems from "./ContextMenuItems.vue"
15
18
  import MenuTitle from "./MenuTitle.vue"
16
19
  import { POPOVER_PANEL } from "./dropdown"
17
- import { useOutsideGuard, usePortalTarget } from "../composables/useView"
20
+ import { useOutsideGuard, usePortalTarget, useView, viewDocument } from "../composables/useView"
18
21
 
19
22
  export interface ContextMenuItemDef {
20
23
  label: string
@@ -39,7 +42,8 @@ export interface ContextMenuItemDef {
39
42
  checked?: boolean
40
43
  }
41
44
 
42
- const props = defineProps<{
45
+ const props = withDefaults(defineProps<{
46
+ palette?: PaletteControlOptions
43
47
  items: ContextMenuItemDef[]
44
48
  /**
45
49
  * Keep the reka menu mounted even while `items` is momentarily empty. Use when
@@ -64,7 +68,7 @@ const props = defineProps<{
64
68
  * menus that only hold generic items (a whole table without row actions).
65
69
  */
66
70
  noHint?: boolean
67
- }>()
71
+ }>(), { palette: undefined })
68
72
 
69
73
  // With no items the trigger is disabled, so the element keeps the browser's
70
74
  // native context menu. Lets callers wrap unconditionally and pass [] to opt out
@@ -81,12 +85,13 @@ const PANEL = `${POPOVER_PANEL} z-(--z-popover) min-w-48 p-1 outline-none`
81
85
  // selection if the menu action left the text as it was.
82
86
  type TextField = HTMLInputElement | HTMLTextAreaElement
83
87
  const SELECTABLE = new Set(["text", "search", "url", "tel", "password"])
88
+ const view = useView()
84
89
  let field: { el: TextField; value: string; start: number; end: number } | null = null
85
90
 
86
91
  function rememberField() {
87
- const el = document.activeElement
92
+ const el = viewDocument(view.value).activeElement
88
93
  const text =
89
- el instanceof HTMLTextAreaElement || (el instanceof HTMLInputElement && SELECTABLE.has(el.type))
94
+ el?.tagName === "TEXTAREA" || (el?.tagName === "INPUT" && SELECTABLE.has((el as HTMLInputElement).type))
90
95
  field = text
91
96
  ? { el: el as TextField, value: (el as TextField).value, start: (el as TextField).selectionStart ?? 0, end: (el as TextField).selectionEnd ?? 0 }
92
97
  : null
@@ -145,6 +150,13 @@ const portalTo = usePortalTarget()
145
150
  // What happens in another document (the page around a frame, or a frame in
146
151
  // the page) is not "outside" for this layer.
147
152
  const guardOutside = useOutsideGuard()
153
+
154
+ const paletteScope = usePaletteScope()
155
+ const paletteId = useId()
156
+ usePaletteCommands(() => props.palette === false || !props.title || !props.items.length ? [] : [{
157
+ id: `${paletteScope?.id}/${props.palette?.id ?? paletteId}`, label: props.palette?.label ?? props.title,
158
+ children: menuPaletteCommands(props.items, `${paletteScope?.id}/${props.palette?.id ?? paletteId}`),
159
+ }], { automatic: true })
148
160
  </script>
149
161
 
150
162
  <template>
@@ -128,7 +128,7 @@ const pad = computed(() => (props.size === "sm" ? "py-1.5 text-xs" : "py-2.5 tex
128
128
  </LpTooltip>
129
129
  </dt>
130
130
  <dd class="flex min-w-0 items-center gap-1.5 text-ink" :class="item.mono ? 'font-mono' : ''">
131
- <span class="min-w-0 break-words">
131
+ <span class="min-w-0 flex-1 [overflow-wrap:anywhere]">
132
132
  <slot
133
133
  v-if="slots[`value-${keyOf(item)}`] || slots.value"
134
134
  :name="slots[`value-${keyOf(item)}`] ? `value-${keyOf(item)}` : 'value'"
@@ -136,7 +136,7 @@ const pad = computed(() => (props.size === "sm" ? "py-1.5 text-xs" : "py-2.5 tex
136
136
  :value="item.value"
137
137
  />
138
138
  <span v-else-if="isEmpty(item.value)" class="text-muted">{{ text.empty }}</span>
139
- <LpRollingText v-else-if="rolls(item.value)" :value="item.value!" align="start" />
139
+ <LpRollingText v-else-if="rolls(item.value)" :value="item.value!" align="start" wrap />
140
140
  <template v-else>{{ item.value }}</template>
141
141
  </span>
142
142
  <!-- Quiet until the row is hovered or focused; always there on touch,
@@ -87,6 +87,7 @@ const props = withDefaults(
87
87
 
88
88
  const emit = defineEmits<{
89
89
  (e: "update:modelValue", value: string | undefined): void
90
+ (e: "blur", event: FocusEvent): void
90
91
  }>()
91
92
 
92
93
  const open = ref(false)
@@ -197,6 +198,7 @@ const presetOptions = computed(() => presetList.value.map((preset) => ({
197
198
  :presets="presetOptions"
198
199
  presets-class="sm:w-36"
199
200
  @clear="clear"
201
+ @blur="emit('blur', $event)"
200
202
  >
201
203
  <div class="flex flex-col">
202
204
  <LpCalendar
@@ -69,6 +69,7 @@ const props = withDefaults(
69
69
 
70
70
  const emit = defineEmits<{
71
71
  (e: "update:modelValue", value: DateRange | undefined): void
72
+ (e: "blur", event: FocusEvent): void
72
73
  }>()
73
74
 
74
75
  const text = useLabels<DateRangePickerLabels>(
@@ -157,6 +158,7 @@ const presetOptions = computed(() => presetList.value.map((preset) => ({
157
158
  :presets="presetOptions"
158
159
  presets-class="sm:w-40"
159
160
  @clear="emit('update:modelValue', undefined)"
161
+ @blur="emit('blur', $event)"
160
162
  >
161
163
  <LpRangeCalendar
162
164
  :model-value="value"
@@ -6,6 +6,7 @@ export default { inheritAttrs: false }
6
6
  </script>
7
7
 
8
8
  <script setup lang="ts">
9
+ import { usePaletteAction, type PaletteControlOptions } from "../composables/usePaletteCommands"
9
10
  /*
10
11
  * Collapsible "show more" section built on reka Collapsible. The trigger is a
11
12
  * full-width row with a chevron that rotates open; the body folds open and shut
@@ -31,6 +32,7 @@ import { useMergedAttrs } from "../composables/useMergedClass"
31
32
 
32
33
  const props = withDefaults(
33
34
  defineProps<{
35
+ palette?: PaletteControlOptions
34
36
  /** Controlled open state. Omit to let the component own it (with `defaultOpen`). */
35
37
  open?: boolean
36
38
  defaultOpen?: boolean
@@ -45,7 +47,7 @@ const props = withDefaults(
45
47
  */
46
48
  scrollIntoView?: boolean
47
49
  }>(),
48
- { defaultOpen: false, scrollIntoView: false },
50
+ { palette: undefined, defaultOpen: false, scrollIntoView: false },
49
51
  )
50
52
 
51
53
  const emit = defineEmits<{ (e: "update:open", value: boolean): void }>()
@@ -113,6 +115,8 @@ function onToggle(value: boolean) {
113
115
  const { class: rootClass, attrs: rest } = useMergedAttrs(
114
116
  "shrink-0 overflow-hidden rounded-control border border-line bg-surface-soft",
115
117
  )
118
+
119
+ usePaletteAction({ label: () => props.label, element: () => (root.value?.$el as HTMLElement | undefined)?.querySelector<HTMLElement>("button"), disabled: () => false })
116
120
  </script>
117
121
 
118
122
  <template>
@@ -1,4 +1,7 @@
1
1
  <script setup lang="ts">
2
+ import { useId } from "vue"
3
+ import { menuPaletteCommands } from "./commandPalette"
4
+ import { usePaletteCommands, usePaletteScope, type PaletteControlOptions } from "../composables/usePaletteCommands"
2
5
  /*
3
6
  * A menu opened from a button (usually a row's "…"). Its items are the same
4
7
  * shape as LpContextMenu's and are drawn by the same renderer, so one array
@@ -17,7 +20,8 @@ import { useOutsideGuard, usePortalTarget } from "../composables/useView"
17
20
  /** A dropdown item: the context-menu item shape, kept under its old name. */
18
21
  export type MenuItem = ContextMenuItemDef
19
22
 
20
- const props = defineProps<{
23
+ const props = withDefaults(defineProps<{
24
+ palette?: PaletteControlOptions
21
25
  items: MenuItem[]
22
26
  /** A heading naming what the menu acts on; see LpContextMenu's `title`. */
23
27
  title?: string
@@ -29,7 +33,7 @@ const props = defineProps<{
29
33
  * menu). Opening it then counts toward the hint system's right-click tip.
30
34
  */
31
35
  rightClickToo?: boolean
32
- }>()
36
+ }>(), { palette: undefined })
33
37
 
34
38
  const PANEL = `${POPOVER_PANEL} z-(--z-popover) min-w-44 p-1 outline-none`
35
39
 
@@ -42,10 +46,17 @@ const portalTo = usePortalTarget()
42
46
  // What happens in another document (the page around a frame, or a frame in
43
47
  // the page) is not "outside" for this layer.
44
48
  const guardOutside = useOutsideGuard()
49
+
50
+ const paletteScope = usePaletteScope()
51
+ const paletteId = useId()
52
+ usePaletteCommands(() => props.palette === false || !props.title || !props.items.length ? [] : [{
53
+ id: `${paletteScope?.id}/${props.palette?.id ?? paletteId}`, label: props.palette?.label ?? props.title,
54
+ children: menuPaletteCommands(props.items, `${paletteScope?.id}/${props.palette?.id ?? paletteId}`),
55
+ }], { automatic: true })
45
56
  </script>
46
57
 
47
58
  <template>
48
- <DropdownMenuRoot @update:open="opened">
59
+ <DropdownMenuRoot :modal="false" @update:open="opened">
49
60
  <DropdownMenuTrigger as-child>
50
61
  <slot name="trigger" />
51
62
  </DropdownMenuTrigger>
@@ -129,7 +129,7 @@ function cancel() {
129
129
 
130
130
  let committing = false
131
131
  async function commit(refocus: boolean) {
132
- if (!editing.value || committing) return
132
+ if (!editing.value || committing || !interactive.value) return
133
133
  const value = props.trim ? draft.value.trim() : draft.value
134
134
  if (value === props.modelValue) {
135
135
  notice.clear()
@@ -273,6 +273,8 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(() => "relative inline-
273
273
  :aria-invalid="(notice.tone.value === 'danger' && !!notice.message.value) || undefined"
274
274
  :placeholder="placeholder"
275
275
  :maxlength="maxlength"
276
+ :disabled="disabled"
277
+ :readonly="readonly"
276
278
  :rows="multiline ? 1 : undefined"
277
279
  class="col-start-1 row-start-1 w-full min-w-0 resize-none overflow-hidden bg-transparent text-ink outline-none placeholder:text-muted"
278
280
  :class="PAD[size]"
@@ -49,6 +49,9 @@ const noticeId = computed(() => `${id.value}-notice`)
49
49
  provideField(
50
50
  computed(() => ({
51
51
  id: id.value,
52
+ label: props.label,
53
+ hint: props.hint,
54
+ error: props.error,
52
55
  labelId: props.label ? `${id.value}-label` : undefined,
53
56
  describedBy:
54
57
  [hasMessage.value ? messageId.value : "", notice.message.value ? noticeId.value : ""]
@@ -3,6 +3,7 @@ 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 { tv, type VariantProps } from "tailwind-variants"
7
8
  import { computed, ref, useAttrs, useSlots } from "vue"
8
9
  import { useFieldControl } from "../composables/useField"
@@ -46,6 +47,8 @@ type InputVariants = VariantProps<typeof shell>
46
47
 
47
48
  const props = withDefaults(
48
49
  defineProps<{
50
+ /** Contextual palette metadata; false excludes this control. */
51
+ palette?: PaletteControlOptions
49
52
  modelValue?: string
50
53
  size?: InputVariants["size"]
51
54
  invalid?: boolean
@@ -87,7 +90,7 @@ const props = withDefaults(
87
90
  /** Extra or replacement mask tokens, one-character RegExps by key. */
88
91
  maskTokens?: MaskTokens
89
92
  }>(),
90
- { type: "text", size: "md" },
93
+ { palette: undefined, type: "text", size: "md" },
91
94
  )
92
95
 
93
96
  const emit = defineEmits<{
@@ -174,6 +177,8 @@ defineExpose({
174
177
  select: () => inputEl.value?.select(),
175
178
  input: inputEl,
176
179
  })
180
+
181
+ usePaletteControl({ label: () => props.label, disabled: () => field.value.disabled, invalid: () => field.value.invalid, available: () => !['password', 'hidden'].includes(props.type), editorProps: () => ({ label: undefined, hint: undefined, error: undefined }) })
177
182
  </script>
178
183
 
179
184
  <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
  // Numeric input with stepper buttons (reka NumberField). Themed via tokens.
10
11
  import {
11
12
  NumberFieldDecrement,
@@ -25,6 +26,8 @@ export interface NumberFieldLabels extends Record<string, string> {
25
26
  }
26
27
 
27
28
  const props = withDefaults(defineProps<{
29
+ /** Contextual palette metadata; false excludes this control. */
30
+ palette?: PaletteControlOptions
28
31
  // null = empty field (reka's native state); consumers that need a number
29
32
  // should default it themselves, the field doesn't invent a value.
30
33
  modelValue?: number | null
@@ -67,7 +70,7 @@ const props = withDefaults(defineProps<{
67
70
  /** Control height, matching LpInput. */
68
71
  size?: "sm" | "md" | "lg"
69
72
  labels?: Partial<NumberFieldLabels>
70
- }>(), { size: "md", stepSnapping: true, steppers: true, focusOnChange: true })
73
+ }>(), { palette: undefined, size: "md", stepSnapping: true, steppers: true, focusOnChange: true })
71
74
 
72
75
  // The value is committed when the field loses focus or Enter is pressed, and on
73
76
  // every step, not on each keystroke: "1." or "-" is not a number yet, and a
@@ -131,6 +134,8 @@ const rootClass = useMergedClass(() =>
131
134
  : "border-line focus-within:border-brand focus-within:ring-ring",
132
135
  ].join(" "),
133
136
  )
137
+
138
+ usePaletteControl({ disabled: () => field.value.disabled, invalid: () => field.value.invalid })
134
139
  </script>
135
140
 
136
141
  <template>
@@ -28,6 +28,8 @@
28
28
  */
29
29
  import { computed, onBeforeUnmount, ref, watch } from "vue"
30
30
  import { easeOut, prefersReducedMotion } from "../composables/easing"
31
+ import { useLocale } from "../composables/useLocale"
32
+ import { decimalMark } from "./format"
31
33
  import { useRevealedValue } from "../composables/useRevealedValue"
32
34
  import { compactNumber } from "./format"
33
35
 
@@ -222,6 +224,14 @@ const { el: revealAnchor, target } = useRevealedValue(() => props.value, {
222
224
  watch(target, travel)
223
225
  onBeforeUnmount(stop)
224
226
 
227
+ /*
228
+ * The app's locale (reka's ConfigProvider) when the counter has none of its
229
+ * own, the same rule the dates follow: a Russian app read "4,594" otherwise.
230
+ */
231
+ const locale = useLocale(() => props.locale)
232
+ // Only the grouped form is written in the locale; the others always use ".".
233
+ const fractionMark = computed(() => (props.grouped && !props.format && !props.compact ? decimalMark(locale.value) : "."))
234
+
225
235
  const formatted = computed(() => formatAt(round(displayed.value), !settled.value))
226
236
 
227
237
  // Rounded first by the caller: every branch should render the shape the
@@ -246,7 +256,7 @@ function formatAt(v: number, padded: boolean): string {
246
256
  }
247
257
  const pad = padded ? Math.max(1, padTo.value) : 1
248
258
  if (props.grouped)
249
- return v.toLocaleString(props.locale, {
259
+ return v.toLocaleString(locale.value, {
250
260
  minimumFractionDigits: props.decimals,
251
261
  maximumFractionDigits: props.decimals,
252
262
  minimumIntegerDigits: pad,
@@ -294,7 +304,7 @@ interface Cell {
294
304
  */
295
305
  const cells = computed<Cell[]>(() => {
296
306
  const chars = [...formatted.value]
297
- const dot = chars.indexOf(".")
307
+ const dot = chars.indexOf(fractionMark.value)
298
308
  const intEnd = dot === -1 ? chars.length : dot
299
309
 
300
310
  const isDigit = (c: string) => {
@@ -20,11 +20,14 @@
20
20
  import HighlightText from "./HighlightText.vue"
21
21
  import LpIcon from "./LpIcon.vue"
22
22
  import LpRollingText from "./LpRollingText.vue"
23
+ import LpSkeleton from "./LpSkeleton.vue"
23
24
  import type { PaletteFact } from "./commandPalette"
25
+ import { computed } from "vue"
24
26
 
25
- withDefaults(
27
+ const props = withDefaults(
26
28
  defineProps<{
27
29
  items: PaletteFact[]
30
+ loading?: boolean
28
31
  /** Small heading over the list. */
29
32
  title?: string
30
33
  /** Plain rows instead of soft tiles, for a list read as text. */
@@ -32,6 +35,7 @@ withDefaults(
32
35
  }>(),
33
36
  { plain: false },
34
37
  )
38
+ const shown = computed(() => props.loading && !props.items.length ? Array.from({ length: 3 }, () => ({ label: "", value: "—" } as PaletteFact)) : props.items)
35
39
 
36
40
  defineSlots<{
37
41
  value?: (props: { item: PaletteFact; index: number }) => unknown
@@ -39,11 +43,11 @@ defineSlots<{
39
43
  </script>
40
44
 
41
45
  <template>
42
- <section class="lp-palette-facts" :class="{ 'lp-palette-facts--plain': plain }">
46
+ <section class="lp-palette-facts" :aria-busy="loading || undefined" :class="{ 'lp-palette-facts--plain': plain }">
43
47
  <p v-if="title" class="lp-palette-facts__title">{{ title }}</p>
44
48
  <ul class="lp-palette-facts__list">
45
49
  <li
46
- v-for="(item, index) in items"
50
+ v-for="(item, index) in shown"
47
51
  :key="index"
48
52
  class="lp-palette-facts__row"
49
53
  :class="{ 'is-current': item.current }"
@@ -52,15 +56,16 @@ defineSlots<{
52
56
  <span v-if="item.color" class="lp-palette-facts__dot" :style="{ background: item.color }" />
53
57
  <LpIcon v-else-if="item.icon" :name="item.icon" :size="15" class="lp-palette-facts__icon" />
54
58
  <span class="lp-palette-facts__label">
55
- <span class="lp-palette-facts__name"><HighlightText :text="item.label" /></span>
59
+ <span class="lp-palette-facts__name"><LpSkeleton v-if="loading && !item.label" class="h-3 w-24" /><HighlightText v-else :text="item.label" /></span>
56
60
  <span v-if="item.hint?.length" class="lp-palette-facts__hint"><HighlightText :text="item.hint" /></span>
57
61
  </span>
58
62
  <span
59
- v-if="item.value !== undefined && item.value !== '' || $slots.value"
63
+ v-if="loading || item.value !== undefined && item.value !== '' || $slots.value"
60
64
  class="lp-palette-facts__value"
61
65
  :class="{ 'lp-palette-facts__value--mono': item.mono }"
62
66
  >
63
- <slot name="value" :item="item" :index="index">
67
+ <LpSkeleton v-if="loading" class="h-3 w-16 max-w-full" />
68
+ <slot v-else name="value" :item="item" :index="index">
64
69
  <LpRollingText v-if="item.value !== undefined" :value="item.value" align="end" />
65
70
  </slot>
66
71
  </span>
@@ -13,23 +13,29 @@
13
13
  */
14
14
  import LpNumberFlow from "./LpNumberFlow.vue"
15
15
  import LpRollingText from "./LpRollingText.vue"
16
+ import LpSkeleton from "./LpSkeleton.vue"
16
17
  import type { PaletteStat } from "./commandPalette"
18
+ import { computed } from "vue"
17
19
 
18
- withDefaults(
20
+ const props = withDefaults(
19
21
  defineProps<{
20
22
  items: PaletteStat[]
23
+ loading?: boolean
21
24
  /** Tiles per row. */
22
25
  columns?: 2 | 3 | 4
23
26
  }>(),
24
27
  { columns: 2 },
25
28
  )
29
+ const shown = computed(() => props.loading && !props.items.length ? Array.from({ length: props.columns }, () => ({ label: "", value: "—" } as PaletteStat)) : props.items)
26
30
  </script>
27
31
 
28
32
  <template>
29
- <dl class="lp-palette-stats" :style="{ gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))` }">
30
- <div v-for="(item, index) in items" :key="`${item.label}-${index}`" class="lp-palette-stats__tile">
31
- <dt>{{ item.label }}</dt>
32
- <dd>
33
+ <dl class="lp-palette-stats" :aria-busy="loading || undefined" :style="{ gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))` }">
34
+ <div v-for="(item, index) in shown" :key="`${item.label}-${index}`" class="lp-palette-stats__tile">
35
+ <dt><LpSkeleton v-if="loading && !item.label" class="my-1 h-2 w-20" /><template v-else>{{ item.label }}</template></dt>
36
+ <dd class="relative">
37
+ <LpSkeleton v-if="loading" class="absolute top-1/2 h-[1em] w-16 max-w-full -translate-y-1/2" />
38
+ <span :class="loading && 'invisible'" :aria-hidden="loading || undefined">
33
39
  <LpNumberFlow
34
40
  v-if="typeof item.value === 'number'"
35
41
  :value="item.value"
@@ -40,6 +46,7 @@ withDefaults(
40
46
  grouped
41
47
  />
42
48
  <LpRollingText v-else :value="item.value" align="start" />
49
+ </span>
43
50
  </dd>
44
51
  </div>
45
52
  </dl>
@@ -0,0 +1,48 @@
1
+ <script setup lang="ts">
2
+ import { computed, ref } from "vue"
3
+ import type { StudioState, PreviewableThemeStudio } from "../theme/studio"
4
+ import { useLabels } from "../composables/useLpConfig"
5
+ import { suppressPaletteDiscovery } from "../composables/usePaletteCommands"
6
+ import LpThemeStudio from "./LpThemeStudio.vue"
7
+ import LpThemeProvider from "./LpThemeProvider.vue"
8
+ import LpButton from "./LpButton.vue"
9
+ import LpInput from "./LpInput.vue"
10
+
11
+ const props = defineProps<{ studio: PreviewableThemeStudio }>()
12
+ suppressPaletteDiscovery()
13
+ const text = useLabels("paletteTheme", { title: "Theme", apply: "Apply theme", revert: "Revert draft", sample: "Preview", action: "Continue", placeholder: "A field in this theme" })
14
+ const snapshot = ref({ ...props.studio.state.value })
15
+ const state = ref<StudioState>({ ...snapshot.value })
16
+ const preview = computed(() => props.studio.preview(state.value))
17
+ const changed = computed(() => JSON.stringify(state.value) !== JSON.stringify(snapshot.value))
18
+ const draft: PreviewableThemeStudio = {
19
+ state, themes: props.studio.themes, system: props.studio.system,
20
+ theme: computed(() => preview.value.theme), exported: computed(() => preview.value.exported), changed,
21
+ brand: computed({ get: () => preview.value.theme.colors.brand, set: brand => { state.value = { ...state.value, brand } } }),
22
+ pickTheme: theme => { state.value = { ...state.value, theme } },
23
+ tune: patch => { state.value = { ...state.value, ...patch } },
24
+ reset: () => { state.value = { ...snapshot.value } },
25
+ preview: props.studio.preview,
26
+ }
27
+ function apply() {
28
+ const { theme, ...tuning } = state.value
29
+ props.studio.pickTheme(theme)
30
+ props.studio.tune(tuning)
31
+ snapshot.value = { ...state.value }
32
+ }
33
+ </script>
34
+
35
+ <template>
36
+ <div class="flex min-w-0 flex-col gap-4">
37
+ <div class="sticky top-0 z-10 flex gap-2 border-b border-line bg-surface-overlay pb-3">
38
+ <LpButton :disabled="!changed" @click="apply">{{ text.apply }}</LpButton>
39
+ <LpButton variant="ghost" :disabled="!changed" @click="draft.reset()">{{ text.revert }}</LpButton>
40
+ </div>
41
+ <LpThemeProvider :theme="preview.theme" class="flex flex-col gap-3 rounded-card border border-line p-4">
42
+ <span class="text-sm font-semibold">{{ text.sample }}</span>
43
+ <LpInput :placeholder="text.placeholder" readonly :tabindex="-1" />
44
+ <LpButton :tabindex="-1">{{ text.action }}</LpButton>
45
+ </LpThemeProvider>
46
+ <LpThemeStudio :studio="draft" :labels="{ reset: text.revert }" />
47
+ </div>
48
+ </template>
@@ -8,20 +8,24 @@ export interface PasswordInputLabels extends Record<string, string> {
8
8
  </script>
9
9
 
10
10
  <script setup lang="ts">
11
+ import { suppressPaletteDiscovery } from "../composables/usePaletteCommands"
11
12
  // Password field = LpInput + a show/hide toggle in its trailing slot.
12
13
  // No duplicated field styling — the shell lives in LpInput.
13
14
  // LpSecretField's input form is this same field: it drives `visible` (to hide
14
15
  // again on a timer) and puts its copy button in `actions`.
15
16
  import { ref } from "vue"
17
+ import { useFieldControl } from "../composables/useField"
16
18
  import { useLabels } from "../composables/useLpConfig"
17
19
  import LpInput from "./LpInput.vue"
18
20
  import RevealToggle from "./RevealToggle.vue"
19
21
 
20
- const props = defineProps<{
22
+ const props = withDefaults(defineProps<{
21
23
  modelValue?: string
22
24
  placeholder?: string
23
25
  invalid?: boolean
24
26
  disabled?: boolean
27
+ /** Offer the show/hide button. When false, the field stays masked. */
28
+ revealable?: boolean
25
29
  // Field wrapping mirrors LpInput: passing any of these wraps the control in
26
30
  // LpFormField, so a password field labels itself like every other field.
27
31
  label?: string
@@ -31,10 +35,11 @@ const props = defineProps<{
31
35
  /** Control height, as on LpInput. */
32
36
  size?: "sm" | "md" | "lg"
33
37
  labels?: Partial<PasswordInputLabels>
34
- }>()
38
+ }>(), { revealable: true })
35
39
  defineEmits<{ (e: "update:modelValue", value: string): void }>()
36
40
  /** Whether the text shows; bind it to reveal or hide from outside. */
37
41
  const visible = defineModel<boolean>("visible", { default: false })
42
+ const field = useFieldControl(() => ({ wrapped: false, disabled: props.disabled }))
38
43
 
39
44
  const text = useLabels<PasswordInputLabels>(
40
45
  "passwordInput",
@@ -47,6 +52,8 @@ defineExpose({
47
52
  blur: () => inner.value?.blur(),
48
53
  select: () => inner.value?.select(),
49
54
  })
55
+
56
+ suppressPaletteDiscovery()
50
57
  </script>
51
58
 
52
59
  <template>
@@ -54,10 +61,10 @@ defineExpose({
54
61
  ref="inner"
55
62
  v-bind="$attrs"
56
63
  :model-value="modelValue"
57
- :type="visible ? 'text' : 'password'"
64
+ :type="revealable && visible ? 'text' : 'password'"
58
65
  :placeholder="placeholder"
59
66
  :invalid="invalid"
60
- :disabled="disabled"
67
+ :disabled="field.disabled"
61
68
  :label="label"
62
69
  :hint="hint"
63
70
  :error="error"
@@ -71,11 +78,12 @@ defineExpose({
71
78
  <!-- Sized to the icon with a hair of padding, as the field's other
72
79
  trailing controls are, rather than to a full square button. -->
73
80
  <RevealToggle
81
+ v-if="revealable"
74
82
  v-model="visible"
75
83
  :icon-size="size === 'sm' ? 14 : 16"
76
84
  :show-label="text.show"
77
85
  :hide-label="text.hide"
78
- :disabled="disabled"
86
+ :disabled="field.disabled"
79
87
  class="size-auto rounded-inner p-1 hover:bg-transparent"
80
88
  />
81
89
  </template>
@@ -10,6 +10,9 @@ import { mergeClass } from "../composables/useMergedClass"
10
10
  import { POPOVER_PANEL } from "./dropdown"
11
11
  import { useOutsideGuard, usePortalTarget } from "../composables/useView"
12
12
 
13
+ // The trigger owns its attributes through the slot; fallthrough tags the panel.
14
+ defineOptions({ inheritAttrs: false })
15
+
13
16
  const props = withDefaults(
14
17
  defineProps<{
15
18
  side?: "top" | "right" | "bottom" | "left"
@@ -47,6 +50,7 @@ const guardOutside = useOutsideGuard()
47
50
  </PopoverTrigger>
48
51
  <PopoverPortal :to="portalTo">
49
52
  <PopoverContent
53
+ v-bind="$attrs"
50
54
  @interact-outside="guardOutside"
51
55
  @escape-key-down="guardOutside"
52
56
  :collision-padding="8"
@@ -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 { RadioGroupIndicator, RadioGroupItem, RadioGroupRoot } from "reka-ui"
10
11
  import { useId } from "vue"
11
12
  import { useFieldControl } from "../composables/useField"
@@ -21,7 +22,7 @@ export interface RadioOption extends LpOptionBase<string> {
21
22
  // a disabled option stays visible but cannot be picked. For anything richer
22
23
  // (badges, custom layout) pass <LpRadio> children in the default slot instead —
23
24
  // they share the same RadioGroupRoot, so selection still flows through v-model.
24
- const props = defineProps<{ modelValue?: string; options?: RadioOption[]; disabled?: boolean }>()
25
+ const props = withDefaults(defineProps<{ palette?: PaletteControlOptions; modelValue?: string; options?: RadioOption[]; disabled?: boolean }>(), { palette: undefined })
25
26
  defineEmits<{ (e: "update:modelValue", value: string): void }>()
26
27
 
27
28
  const field = useFieldControl(() => ({ wrapped: false, disabled: props.disabled }))
@@ -31,6 +32,8 @@ const uid = useId()
31
32
  const { class: rootClass, attrs: rest } = useMergedAttrs(
32
33
  "flex flex-col gap-2",
33
34
  )
35
+
36
+ usePaletteControl({ disabled: () => field.value.disabled })
34
37
  </script>
35
38
 
36
39
  <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
  /*
10
11
  * Two thumbs on one track: a range rather than a value. A price "from – to",
11
12
  * a stretch of a clip to loop, a span of years. The model is `[low, high]`;
@@ -20,6 +21,8 @@ import { SLIDER_GLIDE, useSliderDrag } from "./slider"
20
21
 
21
22
  const props = withDefaults(
22
23
  defineProps<{
24
+ /** Contextual palette metadata; false excludes this control. */
25
+ palette?: PaletteControlOptions
23
26
  modelValue?: [number, number]
24
27
  min?: number
25
28
  max?: number
@@ -32,7 +35,7 @@ const props = withDefaults(
32
35
  /** Label over each thumb while it is in use: `(value) => "1:05"`. */
33
36
  format?: (value: number) => string
34
37
  }>(),
35
- { modelValue: () => [0, 100], min: 0, max: 100, step: 1, minGap: 0 },
38
+ { palette: undefined, modelValue: () => [0, 100], min: 0, max: 100, step: 1, minGap: 0 },
36
39
  )
37
40
 
38
41
  const emit = defineEmits<{
@@ -65,6 +68,8 @@ const thumbClass =
65
68
  "group/thumb relative block size-4 rounded-pill border-2 border-brand bg-surface shadow outline-none transition-transform duration-[var(--duration-fast)] ease-[var(--ease-emphasized)] hover:scale-110 active:scale-95 focus-visible:ring-2 focus-visible:ring-ring motion-reduce:hover:scale-100 motion-reduce:active:scale-100"
66
69
  const labelClass =
67
70
  "pointer-events-none absolute bottom-full left-1/2 mb-1.5 -translate-x-1/2 translate-y-0.5 rounded-control bg-surface-raised px-1.5 py-0.5 text-[11px] whitespace-nowrap text-ink tabular-nums opacity-0 shadow-sm transition-[opacity,translate] duration-[var(--duration-fast)] ease-[var(--ease-emphasized)] group-hover/thumb:translate-y-0 group-hover/thumb:opacity-100 group-focus-visible/thumb:translate-y-0 group-focus-visible/thumb:opacity-100 group-active/thumb:translate-y-0 group-active/thumb:opacity-100 motion-reduce:transition-none"
71
+
72
+ usePaletteControl({ disabled: () => field.value.disabled })
68
73
  </script>
69
74
 
70
75
  <template>