@leavepulse/ui 0.77.3 → 0.78.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 (597) hide show
  1. package/README.md +68 -0
  2. package/dist/assets/{LpCommandPalette-DOIZHw-g.css → LpCommandPalette-DDJKICKh.css} +19 -19
  3. package/dist/assets/{LpDock-Cbh0wQUv.css → LpDock-Dw82tWVD.css} +3 -3
  4. package/dist/assets/{LpDropzone-B_qRq1-R.css → LpDropzone-DNbh_NFJ.css} +10 -10
  5. package/dist/assets/{LpImageEditor-XM5bAziW.css → LpImageEditor-Bgu20XLs.css} +6 -6
  6. package/dist/assets/{LpTable-Bv-EcQs7.css → LpTable-CCk0ZHo7.css} +19 -19
  7. package/dist/assets/LpTabs-Bh7a-Bdl.css +18 -0
  8. package/dist/chunks/AppShellContextNav-C6Ho2mof.js +49 -0
  9. package/dist/chunks/ChartRangeSelector-HO0sMMz6.js +129 -0
  10. package/dist/chunks/{ContextMenuItems-BXumicbh.js → ContextMenuItems-DmaKSJVv.js} +1 -1
  11. package/dist/chunks/{DropzoneLinkField-C-9BCGJn.js → DropzoneLinkField-DXIr0eFz.js} +2 -2
  12. package/dist/chunks/{FieldWrapper-CORPzo9s.js → FieldWrapper-DnuMTrqW.js} +1 -1
  13. package/dist/chunks/IconCloseButton-COZEsa9u.js +29 -0
  14. package/dist/chunks/{LayoutCanvas-CNOAUk7D.js → LayoutCanvas-CZKOltfA.js} +1 -1
  15. package/dist/chunks/{LayoutNode-DF5BMN0J.js → LayoutNode-D2f7v683.js} +45 -45
  16. package/dist/chunks/{LpActionBar-BP1ld7-S.js → LpActionBar-BGMk5KoG.js} +3 -3
  17. package/dist/chunks/{LpActivityLine-CJvzrNpj.js → LpActivityLine-Ea-t5Vza.js} +4 -2
  18. package/dist/chunks/{LpAddressInput-E8KtwU7-.js → LpAddressInput-ZqoZ-N2Y.js} +12 -11
  19. package/dist/chunks/{LpAlert-n5XPAZfv.js → LpAlert-CjvTZIKF.js} +3 -3
  20. package/dist/chunks/LpAppShell-BNAVTQsY.js +582 -0
  21. package/dist/chunks/{LpAutocomplete-C-SpPfBG.js → LpAutocomplete-DkY6CSyD.js} +24 -42
  22. package/dist/chunks/{LpAvatar-Cg6Az3wz.js → LpAvatar-cQVsNk6F.js} +2 -2
  23. package/dist/chunks/{LpBadge-wUYLN4U9.js → LpBadge-D5QQdDQ_.js} +2 -2
  24. package/dist/chunks/{LpBottomNav-CbNQQPuL.js → LpBottomNav-zxLGGbjm.js} +9 -2
  25. package/dist/chunks/{LpBreadcrumbs-DPdbth-c.js → LpBreadcrumbs-CIIBsygI.js} +4 -3
  26. package/dist/chunks/{LpButton-CFb44IjC.js → LpButton-DSHioIfD.js} +5 -4
  27. package/dist/chunks/{LpCalendar-CuoWks-0.js → LpCalendar-D4-LVjfF.js} +1 -1
  28. package/dist/chunks/{LpCard-r13WRqox.js → LpCard-BPtYXwnT.js} +1 -1
  29. package/dist/chunks/{LpCheckbox-Cs4SHaHX.js → LpCheckbox-D6RuDW4X.js} +38 -16
  30. package/dist/chunks/{LpCodeBlock-DRC8VbXW.js → LpCodeBlock-DuzmnIHl.js} +19 -41
  31. package/dist/chunks/{LpCodeDisplay-CE9TxCA4.js → LpCodeDisplay-CO8fngxa.js} +5 -5
  32. package/dist/chunks/{LpCollapse-CWS9M_lm.js → LpCollapse-DrAw5DBZ.js} +5 -4
  33. package/dist/chunks/{LpColorPicker-1y1QJHZR.js → LpColorPicker-BxAHEnR5.js} +11 -12
  34. package/dist/chunks/{LpCommandScope-CtUhJe8T.js → LpCommandScope-DRUvHiX7.js} +1 -1
  35. package/dist/chunks/{LpConfirmDialog-DlD45Bi_.js → LpConfirmDialog-6oCIJTDa.js} +3 -3
  36. package/dist/chunks/{LpConfirmHost-BIWjBLmI.js → LpConfirmHost-DgHvfT6s.js} +1 -1
  37. package/dist/chunks/{LpContextMenu-rx2tCjwk.js → LpContextMenu--eMGIql6.js} +13 -15
  38. package/dist/chunks/{LpContextSwitcher-Dwh6dyID.js → LpContextSwitcher-1C1tExdl.js} +2 -2
  39. package/dist/chunks/{LpCopyButton-xF7wFVoU.js → LpCopyButton-7EOSIuwa.js} +3 -3
  40. package/dist/chunks/{LpCountdown-DgeY3cLG.js → LpCountdown-DVl7vXI1.js} +4 -3
  41. package/dist/chunks/{LpDataList-Jxyl9H5w.js → LpDataList-DgBeM01y.js} +13 -4
  42. package/dist/chunks/{LpDatePicker-CA0QTfBC.js → LpDatePicker-DwSDY0mt.js} +12 -18
  43. package/dist/chunks/{LpDateRangePicker-u3J51xXk.js → LpDateRangePicker-CNQXdTVv.js} +10 -16
  44. package/dist/chunks/{LpDisclosure-Cpa7Hc5T.js → LpDisclosure-DG7JCo-d.js} +2 -2
  45. package/dist/chunks/{LpDrawer-CrG8t_KP.js → LpDrawer-Bt9UUqt_.js} +61 -61
  46. package/dist/chunks/{LpDropdownMenu-Dl7Z4ZhS.js → LpDropdownMenu-CLzxIOgM.js} +9 -17
  47. package/dist/chunks/{LpEditable-Cy6GLbFx.js → LpEditable-DVT0Rh8F.js} +9 -6
  48. package/dist/chunks/{LpEmptyState-EQHiRYhG.js → LpEmptyState-DurPF001.js} +1 -1
  49. package/dist/chunks/{LpFieldNotice-CzQ2_5rQ.js → LpFieldNotice-DJ10cYIo.js} +1 -1
  50. package/dist/chunks/LpFileTree-BSx1kBoV.js +735 -0
  51. package/dist/chunks/{LpFileTreeNode-cT6BIWvz.js → LpFileTreeNode-4dVmFHb3.js} +116 -34
  52. package/dist/chunks/{LpFormField-Ch69Jd-X.js → LpFormField-BKYn9dyP.js} +3 -3
  53. package/dist/chunks/{LpFrame-BVQCQLDI.js → LpFrame-Bv5Fphte.js} +25 -11
  54. package/dist/chunks/{LpHintExample-9Py0wc-L.js → LpHintExample-YzCXiSUp.js} +1 -1
  55. package/dist/chunks/{LpHintLayer-CgObdUsM.js → LpHintLayer-BeKRsRon.js} +2 -2
  56. package/dist/chunks/{LpHints-Bz-BlaSl.js → LpHints-qf3xYsza.js} +3 -3
  57. package/dist/chunks/{LpHoverCard-spGxyw7T.js → LpHoverCard-DanH3Nz1.js} +23 -5
  58. package/dist/chunks/{LpIcon--5WSb3jJ.js → LpIcon-C6JpQ5td.js} +6 -3
  59. package/dist/chunks/{LpIdenticon-BzdC_qz9.js → LpIdenticon-Dbbr4fvt.js} +2 -1
  60. package/dist/chunks/{LpInfraNode-46XOCkfq.js → LpInfraNode-BAU40Km2.js} +2 -2
  61. package/dist/chunks/{LpInput-Tw-yxT4I.js → LpInput-DL6HEJdi.js} +16 -28
  62. package/dist/chunks/LpInspector-CuoMAhiw.js +209 -0
  63. package/dist/chunks/{LpLightbox-B95yu22B.js → LpLightbox-xvpQ64MM.js} +57 -32
  64. package/dist/chunks/{LpLoader-DVwkOmt9.js → LpLoader-Bf1yZwaU.js} +1 -1
  65. package/dist/chunks/LpLogInspector-6cNnXqp4.js +119 -0
  66. package/dist/chunks/{LpLogViewer-ngqkns4m.js → LpLogViewer-Dvb1E9_G.js} +234 -53
  67. package/dist/chunks/{LpMapPicker-DRGgh89B.js → LpMapPicker-D5_YLLBC.js} +4 -3
  68. package/dist/chunks/{LpMasonry--k0571qG.js → LpMasonry-DPYekFxs.js} +8 -5
  69. package/dist/chunks/{LpMediaGallery-Bkram-MO.js → LpMediaGallery-Df-tiWeq.js} +3 -3
  70. package/dist/chunks/{LpModal-CoGhLTyH.js → LpModal-DrtQ_1A2.js} +11 -13
  71. package/dist/chunks/{LpModalNav-BGvs2y5Q.js → LpModalNav-DkmGCnZE.js} +11 -37
  72. package/dist/chunks/{LpNotificationBell-B0034Lk-.js → LpNotificationBell-D_wklO1m.js} +9 -9
  73. package/dist/chunks/{LpNumberField-e0IBkWU1.js → LpNumberField-CNHsmSDZ.js} +7 -16
  74. package/dist/chunks/{LpOtpInput-CeBPsM7D.js → LpOtpInput-BRpLBbOD.js} +2 -2
  75. package/dist/chunks/{LpPagination-BIIiYHXR.js → LpPagination-snQ020xQ.js} +6 -4
  76. package/dist/chunks/{LpPaletteTheme-DiLYKQiZ.js → LpPaletteTheme-dVtxHx-F.js} +4 -4
  77. package/dist/chunks/{LpPasswordInput-BkHKQDhM.js → LpPasswordInput-B-zD6tUS.js} +2 -2
  78. package/dist/chunks/{LpPhoneInput-CETEp5W7.js → LpPhoneInput-BSL7NX4z.js} +15 -26
  79. package/dist/chunks/{LpPie-DrZepi0p.js → LpPie-9t_guO49.js} +22 -21
  80. package/dist/chunks/{LpPipeline-B3aOVOkV.js → LpPipeline-rjXvEDRJ.js} +16 -7
  81. package/dist/chunks/{LpPopover-DmZ3wUtP.js → LpPopover-BQSuxtai.js} +10 -1
  82. package/dist/chunks/{LpProgress-Yr6ONG5t.js → LpProgress-D_MSjowb.js} +2 -1
  83. package/dist/chunks/{LpQuota-Dk2MyI2Z.js → LpQuota-CgWPgdVt.js} +1 -1
  84. package/dist/chunks/{LpRadioGroup-ggaPL92T.js → LpRadioGroup-BrazjLY_.js} +4 -4
  85. package/dist/chunks/{LpRangeCalendar-CYYUYqJ7.js → LpRangeCalendar-BrqlGZzE.js} +1 -1
  86. package/dist/chunks/{LpRangeSlider-CM-0ZITZ.js → LpRangeSlider-fz61tzc-.js} +5 -9
  87. package/dist/chunks/{LpRelativeTime-DwgCb5-8.js → LpRelativeTime-BovUk8MP.js} +1 -1
  88. package/dist/chunks/{LpRepeater-D7ZmnIYd.js → LpRepeater-BkJHSPI1.js} +3 -3
  89. package/dist/chunks/{LpRevealOnScroll-DcQjexLy.js → LpRevealOnScroll-CPwyiQAr.js} +1 -1
  90. package/dist/chunks/{LpScramble-Bn9OoOtC.js → LpScramble-DsE77iVp.js} +1 -1
  91. package/dist/chunks/{LpScrollArea-MyEnVB_5.js → LpScrollArea-ay4Xo_hg.js} +22 -10
  92. package/dist/chunks/{LpSecretField-BbmqM9ye.js → LpSecretField-DBvU6iAw.js} +10 -9
  93. package/dist/chunks/{LpSection-DFK_uoJE.js → LpSection-BfteipxU.js} +1 -1
  94. package/dist/chunks/{LpSegmented-CeACsMMA.js → LpSegmented-DbEJhbv-.js} +8 -10
  95. package/dist/chunks/{LpSelect-Cxq4yBGd.js → LpSelect-Y-iuSymW.js} +47 -30
  96. package/dist/chunks/{LpShaderBackdrop-Bote0iuy.js → LpShaderBackdrop-wQygYb5h.js} +13 -10
  97. package/dist/chunks/{LpShift-CCq7dofl.js → LpShift-DAgS_d2x.js} +18 -15
  98. package/dist/chunks/{LpSidebar-DzE1783C.js → LpSidebar-kSkpPh3-.js} +74 -87
  99. package/dist/chunks/{LpSidebarNav-DE3PhXVP.js → LpSidebarNav-C2mvqrY2.js} +8 -6
  100. package/dist/chunks/{LpSidebarRow-BRYhNDSo.js → LpSidebarRow-eRP4Q31q.js} +6 -5
  101. package/dist/chunks/{LpSlider-DxYoCJJO.js → LpSlider-A4ixovgS.js} +5 -9
  102. package/dist/chunks/{LpSpotlight-4F3NeUMY.js → LpSpotlight-DwxkhFgR.js} +2 -1
  103. package/dist/chunks/{LpStat-f2LfDCJ4.js → LpStat-pMNZgFcq.js} +2 -2
  104. package/dist/chunks/{LpStatus-DglxttQ7.js → LpStatus-DGJFwk5F.js} +2 -2
  105. package/dist/chunks/{LpStepMark-DpzKVyh8.js → LpStepMark-Dw2MRTrt.js} +2 -2
  106. package/dist/chunks/{LpStepper-DpsocBNJ.js → LpStepper-DNnh7lCu.js} +1 -1
  107. package/dist/chunks/{LpSwap-C96c0LWh.js → LpSwap-M7nFeW3C.js} +1 -1
  108. package/dist/chunks/{LpSwitch-BnXd1llc.js → LpSwitch-DnC2-0aV.js} +3 -3
  109. package/dist/chunks/{LpTabFace-DPCwKkH2.js → LpTabFace-DQoV8mQG.js} +2 -2
  110. package/dist/chunks/{LpTableFilter-CiVBpaq0.js → LpTableFilter-DgARTsA1.js} +4 -4
  111. package/dist/chunks/{LpTableOfContents-BN5zvpnx.js → LpTableOfContents-CKkWEK6R.js} +14 -9
  112. package/dist/chunks/{LpTagsInput-C-mDG648.js → LpTagsInput-Dt0mteSj.js} +19 -27
  113. package/dist/chunks/{LpTextarea-TE-yZv2U.js → LpTextarea-Co0b9PVx.js} +8 -16
  114. package/dist/chunks/LpThemeProvider-XK6ZeWAE.js +81 -0
  115. package/dist/chunks/{LpThemeStudio-BpORDvH6.js → LpThemeStudio-DzYfE-5k.js} +12 -195
  116. package/dist/chunks/{LpThemeSwitcher-BnEn_mvf.js → LpThemeSwitcher-CFLkdbBL.js} +8 -6
  117. package/dist/chunks/{LpTimeField-BawSVsmt.js → LpTimeField-DeOcKWJq.js} +6 -9
  118. package/dist/chunks/{LpToaster-IwTXjbbU.js → LpToaster-QFj0P-5m.js} +10 -8
  119. package/dist/chunks/{LpTooltip-BcBvIx4z.js → LpTooltip-BJf3lZMq.js} +51 -19
  120. package/dist/chunks/LpTopologyCanvas-BOHHHZ_6.js +673 -0
  121. package/dist/chunks/{LpTour-BZq-mUMv.js → LpTour-ClKYhx4h.js} +7 -5
  122. package/dist/chunks/{LpTruncate-CflAIwiJ.js → LpTruncate-C6u3gjc6.js} +6 -5
  123. package/dist/chunks/{LpTypewriter-BCL_a6wE.js → LpTypewriter-CZIzpdbe.js} +2 -1
  124. package/dist/chunks/{LpUptimeBar-DqNvvMBK.js → LpUptimeBar-BnYmR2rj.js} +3 -3
  125. package/dist/chunks/{LpVideoBackdrop-DS1wGv-X.js → LpVideoBackdrop-Ct4St4ZL.js} +10 -13
  126. package/dist/chunks/LpWindow-B8YSRVTH.js +297 -0
  127. package/dist/chunks/LpWorkspaceSwitcher-D0e9upAy.js +139 -0
  128. package/dist/chunks/{MenuTitle-BmCNNTKH.js → MenuTitle-Bh5dAdV1.js} +1 -1
  129. package/dist/chunks/{OptionContent-22UT8zLn.js → OptionContent-CGb8QlHA.js} +1 -1
  130. package/dist/chunks/{PickerField-Bfh8id3d.js → PickerField-BM1dyafh.js} +4 -4
  131. package/dist/chunks/{RevealToggle-BEit1n6Z.js → RevealToggle-CCPDE8Mv.js} +3 -3
  132. package/dist/chunks/SliderRail-DhPREa_R.js +18 -0
  133. package/dist/chunks/{TourCard-DNclH3u_.js → TourCard-DAzTYfav.js} +4 -4
  134. package/dist/chunks/{icons-DMITlfw5.js → icons-CYfcpSDS.js} +26 -10
  135. package/dist/component-names.d.ts +1 -1
  136. package/dist/components/AppShellContextNav.vue.d.ts +13 -0
  137. package/dist/components/AppShellContextNav.vue.js +4 -0
  138. package/dist/components/ChartRangeSelector.vue.d.ts +21 -0
  139. package/dist/components/ChartRangeSelector.vue.js +4 -0
  140. package/dist/components/ContextMenuItems.vue.js +1 -1
  141. package/dist/components/DropzoneLinkField.vue.d.ts +2 -2
  142. package/dist/components/DropzoneLinkField.vue.js +1 -1
  143. package/dist/components/FieldWrapper.vue.js +1 -1
  144. package/dist/components/IconCloseButton.vue.d.ts +7 -0
  145. package/dist/components/IconCloseButton.vue.js +4 -0
  146. package/dist/components/LayoutCanvas.vue.js +1 -1
  147. package/dist/components/LayoutNode.vue.js +1 -1
  148. package/dist/components/LpActionBar.vue.js +1 -1
  149. package/dist/components/LpActivityLine.vue.js +1 -1
  150. package/dist/components/LpAddressInput.vue.js +1 -1
  151. package/dist/components/LpAlert.vue.js +1 -1
  152. package/dist/components/LpAppShell.vue.d.ts +110 -2
  153. package/dist/components/LpAppShell.vue.js +1 -1
  154. package/dist/components/LpAutocomplete.vue.js +1 -1
  155. package/dist/components/LpAvatar.vue.js +1 -1
  156. package/dist/components/LpBadge.vue.js +1 -1
  157. package/dist/components/LpBottomNav.vue.d.ts +5 -0
  158. package/dist/components/LpBottomNav.vue.js +1 -1
  159. package/dist/components/LpBreadcrumbs.vue.js +1 -1
  160. package/dist/components/LpButton.vue.d.ts +14 -2
  161. package/dist/components/LpButton.vue.js +1 -1
  162. package/dist/components/LpCalendar.vue.js +1 -1
  163. package/dist/components/LpCard.vue.js +1 -1
  164. package/dist/components/LpChart.vue.d.ts +74 -2
  165. package/dist/components/LpChart.vue.js +326 -85
  166. package/dist/components/LpCheckbox.vue.d.ts +6 -2
  167. package/dist/components/LpCheckbox.vue.js +1 -1
  168. package/dist/components/LpCodeBlock.vue.js +1 -1
  169. package/dist/components/LpCodeDisplay.vue.js +1 -1
  170. package/dist/components/LpCollapse.vue.js +1 -1
  171. package/dist/components/LpColorPicker.vue.js +1 -1
  172. package/dist/components/LpCommandPalette.vue.d.ts +8 -0
  173. package/dist/components/LpCommandPalette.vue.js +107 -56
  174. package/dist/components/LpCommandScope.vue.js +1 -1
  175. package/dist/components/LpConfirmDialog.vue.js +1 -1
  176. package/dist/components/LpConfirmHost.vue.js +1 -1
  177. package/dist/components/LpContextMenu.vue.js +1 -1
  178. package/dist/components/LpContextSwitcher.vue.js +1 -1
  179. package/dist/components/LpCopyButton.vue.js +1 -1
  180. package/dist/components/LpCountdown.vue.js +1 -1
  181. package/dist/components/LpDataList.vue.d.ts +1 -1
  182. package/dist/components/LpDataList.vue.js +1 -1
  183. package/dist/components/LpDatePicker.vue.d.ts +3 -15
  184. package/dist/components/LpDatePicker.vue.js +1 -1
  185. package/dist/components/LpDateRangePicker.vue.d.ts +3 -13
  186. package/dist/components/LpDateRangePicker.vue.js +1 -1
  187. package/dist/components/LpDisclosure.vue.js +1 -1
  188. package/dist/components/LpDock.vue.js +21 -18
  189. package/dist/components/LpDrawer.vue.d.ts +1 -1
  190. package/dist/components/LpDrawer.vue.js +1 -1
  191. package/dist/components/LpDropdownMenu.vue.js +1 -1
  192. package/dist/components/LpDropzone.vue.js +14 -11
  193. package/dist/components/LpEditable.vue.js +1 -1
  194. package/dist/components/LpEmptyState.vue.js +1 -1
  195. package/dist/components/LpFieldNotice.vue.js +1 -1
  196. package/dist/components/LpFileTree.vue.d.ts +96 -6
  197. package/dist/components/LpFileTree.vue.js +1 -1
  198. package/dist/components/LpFileTreeNode.vue.d.ts +48 -0
  199. package/dist/components/LpFileTreeNode.vue.js +1 -1
  200. package/dist/components/LpFormField.vue.js +1 -1
  201. package/dist/components/LpFrame.vue.js +1 -1
  202. package/dist/components/LpGauge.vue.d.ts +1 -1
  203. package/dist/components/LpHintExample.vue.js +1 -1
  204. package/dist/components/LpHintLayer.vue.js +1 -1
  205. package/dist/components/LpHints.vue.js +1 -1
  206. package/dist/components/LpHoverCard.vue.js +1 -1
  207. package/dist/components/LpIcon.vue.d.ts +2 -0
  208. package/dist/components/LpIcon.vue.js +1 -1
  209. package/dist/components/LpIdenticon.vue.js +1 -1
  210. package/dist/components/LpImageEditor.vue.js +7 -6
  211. package/dist/components/LpInfraNode.vue.js +1 -1
  212. package/dist/components/LpInput.vue.d.ts +1 -1
  213. package/dist/components/LpInput.vue.js +1 -1
  214. package/dist/components/LpInspector.vue.d.ts +87 -0
  215. package/dist/components/LpInspector.vue.js +4 -0
  216. package/dist/components/LpLightbox.vue.d.ts +8 -0
  217. package/dist/components/LpLightbox.vue.js +1 -1
  218. package/dist/components/LpLoader.vue.d.ts +1 -1
  219. package/dist/components/LpLoader.vue.js +1 -1
  220. package/dist/components/LpLogInspector.vue.d.ts +18 -0
  221. package/dist/components/LpLogInspector.vue.js +4 -0
  222. package/dist/components/LpLogViewer.vue.d.ts +93 -0
  223. package/dist/components/LpLogViewer.vue.js +1 -1
  224. package/dist/components/LpMapPicker.vue.js +1 -1
  225. package/dist/components/LpMasonry.vue.js +1 -1
  226. package/dist/components/LpMediaGallery.vue.js +1 -1
  227. package/dist/components/LpModal.vue.d.ts +4 -2
  228. package/dist/components/LpModal.vue.js +1 -1
  229. package/dist/components/LpModalNav.vue.d.ts +5 -5
  230. package/dist/components/LpModalNav.vue.js +1 -1
  231. package/dist/components/LpNotificationBell.vue.d.ts +2 -2
  232. package/dist/components/LpNotificationBell.vue.js +1 -1
  233. package/dist/components/LpNumberField.vue.js +1 -1
  234. package/dist/components/LpOtpInput.vue.js +1 -1
  235. package/dist/components/LpPagination.vue.js +1 -1
  236. package/dist/components/LpPaletteFacts.vue.js +1 -1
  237. package/dist/components/LpPaletteHeader.vue.js +2 -2
  238. package/dist/components/LpPaletteTheme.vue.js +1 -1
  239. package/dist/components/LpPasswordInput.vue.js +1 -1
  240. package/dist/components/LpPhoneInput.vue.js +1 -1
  241. package/dist/components/LpPie.vue.d.ts +2 -2
  242. package/dist/components/LpPie.vue.js +1 -1
  243. package/dist/components/LpPipeline.vue.d.ts +4 -0
  244. package/dist/components/LpPipeline.vue.js +1 -1
  245. package/dist/components/LpPopover.vue.d.ts +7 -3
  246. package/dist/components/LpPopover.vue.js +1 -1
  247. package/dist/components/LpProgress.vue.d.ts +1 -1
  248. package/dist/components/LpProgress.vue.js +1 -1
  249. package/dist/components/LpQuota.vue.js +1 -1
  250. package/dist/components/LpRadioGroup.vue.js +1 -1
  251. package/dist/components/LpRangeCalendar.vue.js +1 -1
  252. package/dist/components/LpRangeSlider.vue.js +1 -1
  253. package/dist/components/LpRelativeTime.vue.js +1 -1
  254. package/dist/components/LpRepeater.vue.js +1 -1
  255. package/dist/components/LpRevealOnScroll.vue.js +1 -1
  256. package/dist/components/LpScramble.vue.js +1 -1
  257. package/dist/components/LpScrollArea.vue.js +1 -1
  258. package/dist/components/LpSecretField.vue.js +1 -1
  259. package/dist/components/LpSection.vue.js +1 -1
  260. package/dist/components/LpSegmented.vue.js +1 -1
  261. package/dist/components/LpSelect.vue.js +1 -1
  262. package/dist/components/LpShaderBackdrop.vue.js +1 -1
  263. package/dist/components/LpShift.vue.js +1 -1
  264. package/dist/components/LpShortcutsDialog.vue.js +1 -1
  265. package/dist/components/LpSidebar.vue.d.ts +1 -1
  266. package/dist/components/LpSidebar.vue.js +1 -1
  267. package/dist/components/LpSidebarNav.vue.js +1 -1
  268. package/dist/components/LpSidebarRow.vue.js +1 -1
  269. package/dist/components/LpSlider.vue.js +1 -1
  270. package/dist/components/LpSparkline.vue.d.ts +1 -1
  271. package/dist/components/LpSpotlight.vue.js +1 -1
  272. package/dist/components/LpStat.vue.js +1 -1
  273. package/dist/components/LpStatus.vue.js +1 -1
  274. package/dist/components/LpStepMark.vue.js +1 -1
  275. package/dist/components/LpStepper.vue.js +1 -1
  276. package/dist/components/LpSwap.vue.js +1 -1
  277. package/dist/components/LpSwitch.vue.js +1 -1
  278. package/dist/components/LpTabFace.vue.js +1 -1
  279. package/dist/components/LpTable.vue.d.ts +132 -0
  280. package/dist/components/LpTable.vue.js +547 -135
  281. package/dist/components/LpTableFilter.vue.js +1 -1
  282. package/dist/components/LpTableOfContents.vue.js +1 -1
  283. package/dist/components/LpTabs.vue.js +6 -5
  284. package/dist/components/LpTagsInput.vue.js +1 -1
  285. package/dist/components/LpTextarea.vue.js +1 -1
  286. package/dist/components/LpThemeProvider.vue.d.ts +2 -0
  287. package/dist/components/LpThemeProvider.vue.js +1 -1
  288. package/dist/components/LpThemeStudio.vue.js +1 -1
  289. package/dist/components/LpThemeSwitcher.vue.js +1 -1
  290. package/dist/components/LpTimeField.vue.js +1 -1
  291. package/dist/components/LpToaster.vue.js +1 -1
  292. package/dist/components/LpTooltip.vue.js +1 -1
  293. package/dist/components/LpTopologyCanvas.vue.d.ts +131 -5
  294. package/dist/components/LpTopologyCanvas.vue.js +1 -1
  295. package/dist/components/LpTour.vue.js +1 -1
  296. package/dist/components/LpTruncate.vue.js +1 -1
  297. package/dist/components/LpTypewriter.vue.js +1 -1
  298. package/dist/components/LpUptimeBar.vue.js +1 -1
  299. package/dist/components/LpVideoBackdrop.vue.js +1 -1
  300. package/dist/components/LpWindow.vue.d.ts +99 -0
  301. package/dist/components/LpWindow.vue.js +4 -0
  302. package/dist/components/LpWorkspaceSwitcher.vue.d.ts +18 -0
  303. package/dist/components/LpWorkspaceSwitcher.vue.js +4 -0
  304. package/dist/components/MenuTitle.vue.js +1 -1
  305. package/dist/components/OptionContent.vue.js +1 -1
  306. package/dist/components/PickerField.vue.d.ts +2 -2
  307. package/dist/components/PickerField.vue.js +1 -1
  308. package/dist/components/RevealToggle.vue.js +1 -1
  309. package/dist/components/SliderRail.vue.d.ts +3 -0
  310. package/dist/components/SliderRail.vue.js +4 -0
  311. package/dist/components/TourCard.vue.js +1 -1
  312. package/dist/components/address.js +2 -1
  313. package/dist/components/appShell.d.ts +36 -0
  314. package/dist/components/appShell.js +30 -0
  315. package/dist/components/calendar.d.ts +12 -3
  316. package/dist/components/calendar.js +2 -5
  317. package/dist/components/chart.d.ts +21 -0
  318. package/dist/components/chart.js +4 -3
  319. package/dist/components/chartWindow.d.ts +57 -0
  320. package/dist/components/chartWindow.js +136 -0
  321. package/dist/components/color.js +1 -1
  322. package/dist/components/commandPalette.d.ts +16 -2
  323. package/dist/components/commandPalette.js +39 -4
  324. package/dist/components/controlSize.d.ts +5 -0
  325. package/dist/components/controlSize.js +8 -0
  326. package/dist/components/dropdown.d.ts +5 -0
  327. package/dist/components/dropdown.js +2 -0
  328. package/dist/components/exportData.d.ts +6 -1
  329. package/dist/components/exportData.js +25 -18
  330. package/dist/components/fileTree.d.ts +67 -0
  331. package/dist/components/fileTree.js +141 -1
  332. package/dist/components/identicon.js +3 -2
  333. package/dist/components/logTools.d.ts +93 -0
  334. package/dist/components/logTools.js +210 -0
  335. package/dist/components/menuWhen.js +1 -1
  336. package/dist/components/meter.js +2 -1
  337. package/dist/components/pipeline.d.ts +2 -0
  338. package/dist/components/pipeline.js +5 -0
  339. package/dist/components/relativeTime.js +2 -1
  340. package/dist/components/reveal.js +2 -1
  341. package/dist/components/select.d.ts +5 -0
  342. package/dist/components/select.js +10 -0
  343. package/dist/components/sidebar.d.ts +1 -0
  344. package/dist/components/tableFeatures.d.ts +58 -0
  345. package/dist/components/tableFeatures.js +87 -0
  346. package/dist/components/topologyGraph.d.ts +164 -0
  347. package/dist/components/topologyGraph.js +416 -0
  348. package/dist/components/tour.js +5 -3
  349. package/dist/components/videoBackdrop.js +7 -6
  350. package/dist/composables/clamp.d.ts +2 -0
  351. package/dist/composables/clamp.js +4 -0
  352. package/dist/composables/devWarn.d.ts +3 -0
  353. package/dist/composables/devWarn.js +14 -0
  354. package/dist/composables/easing.d.ts +13 -4
  355. package/dist/composables/easing.js +16 -10
  356. package/dist/composables/overlayHistory.js +14 -1
  357. package/dist/composables/pointerDrag.d.ts +15 -0
  358. package/dist/composables/pointerDrag.js +40 -0
  359. package/dist/composables/propCheck.d.ts +10 -0
  360. package/dist/composables/propCheck.js +78 -0
  361. package/dist/composables/realm.d.ts +6 -0
  362. package/dist/composables/realm.js +23 -0
  363. package/dist/composables/scroll.js +4 -2
  364. package/dist/composables/scrollMemory.d.ts +12 -1
  365. package/dist/composables/scrollMemory.js +36 -12
  366. package/dist/composables/spatialNav.js +2 -1
  367. package/dist/composables/textEntry.d.ts +17 -0
  368. package/dist/composables/textEntry.js +19 -0
  369. package/dist/composables/useAsyncTask.d.ts +6 -0
  370. package/dist/composables/useChartSync.d.ts +5 -0
  371. package/dist/composables/useChartSync.js +33 -0
  372. package/dist/composables/useCloseGuard.d.ts +3 -1
  373. package/dist/composables/useCloseGuard.js +6 -3
  374. package/dist/composables/useCommands.d.ts +50 -0
  375. package/dist/composables/useCommands.js +66 -0
  376. package/dist/composables/useField.d.ts +37 -0
  377. package/dist/composables/useField.js +27 -2
  378. package/dist/composables/useFitScale.js +4 -1
  379. package/dist/composables/useFormDraft.d.ts +13 -2
  380. package/dist/composables/useFormDraft.js +17 -9
  381. package/dist/composables/useHintSystem.js +2 -2
  382. package/dist/composables/useHotkeys.js +11 -32
  383. package/dist/composables/useInView.js +2 -1
  384. package/dist/composables/useInputFilter.js +7 -5
  385. package/dist/composables/useInputMask.js +5 -3
  386. package/dist/composables/useLinkedView.d.ts +97 -0
  387. package/dist/composables/useLinkedView.js +139 -0
  388. package/dist/composables/useOptimisticToggle.d.ts +3 -1
  389. package/dist/composables/useOptimisticToggle.js +2 -1
  390. package/dist/composables/useOverlayHistory.d.ts +7 -0
  391. package/dist/composables/useOverlayHistory.js +16 -2
  392. package/dist/composables/usePaintSelect.js +18 -14
  393. package/dist/composables/usePaletteCommands.d.ts +7 -0
  394. package/dist/composables/usePaletteCommands.js +12 -1
  395. package/dist/composables/usePersisted.d.ts +10 -0
  396. package/dist/composables/usePersisted.js +1 -1
  397. package/dist/composables/usePillTransition.d.ts +2 -2
  398. package/dist/composables/usePillTransition.js +5 -5
  399. package/dist/composables/useResizeObserver.js +2 -1
  400. package/dist/composables/useReveal.js +2 -1
  401. package/dist/composables/useRovingFocus.d.ts +2 -2
  402. package/dist/composables/useRovingFocus.js +9 -11
  403. package/dist/composables/useScramble.js +7 -1
  404. package/dist/composables/useShift.js +8 -6
  405. package/dist/composables/useTilt.js +2 -1
  406. package/dist/composables/useTween.js +9 -5
  407. package/dist/composables/useView.d.ts +1 -0
  408. package/dist/composables/useView.js +14 -2
  409. package/dist/composables/useZoomPan.js +2 -4
  410. package/dist/composables/windowing.d.ts +40 -0
  411. package/dist/composables/windowing.js +118 -0
  412. package/dist/icons-all.js +1 -1
  413. package/dist/icons.d.ts +4 -0
  414. package/dist/index.d.ts +30 -5
  415. package/dist/index.js +310 -264
  416. package/dist/layout/tree.js +19 -15
  417. package/dist/layout/useLayout.d.ts +2 -0
  418. package/dist/layout/useLayout.js +5 -1
  419. package/dist/layout/useWorkspaces.d.ts +52 -0
  420. package/dist/layout/useWorkspaces.js +140 -0
  421. package/dist/{chunks/backdrop-Dkf2vM81.js → theme/backdrop.js} +5 -5
  422. package/dist/theme/config.js +25 -0
  423. package/dist/theme/define.js +61 -0
  424. package/dist/{chunks/palette-Co8tSASo.js → theme/palette.js} +2 -2
  425. package/dist/theme/presets.js +239 -0
  426. package/dist/theme/studio.js +134 -0
  427. package/dist/theme/tokens.js +63 -0
  428. package/dist/theme/useTheme.d.ts +3 -2
  429. package/dist/theme/useTheme.js +325 -0
  430. package/package.json +8 -1
  431. package/src/component-names.ts +5 -1
  432. package/src/components/AppShellContextNav.vue +44 -0
  433. package/src/components/ChartRangeSelector.vue +120 -0
  434. package/src/components/IconCloseButton.vue +21 -0
  435. package/src/components/LayoutCanvas.vue +3 -0
  436. package/src/components/LayoutNode.vue +37 -38
  437. package/src/components/LpActivityLine.vue +4 -2
  438. package/src/components/LpAddressInput.vue +3 -3
  439. package/src/components/LpAppShell.vue +362 -24
  440. package/src/components/LpAutocomplete.vue +13 -30
  441. package/src/components/LpBottomNav.vue +9 -1
  442. package/src/components/LpBreadcrumbs.vue +2 -1
  443. package/src/components/LpButton.vue +11 -4
  444. package/src/components/LpChart.vue +336 -37
  445. package/src/components/LpCheckbox.vue +43 -9
  446. package/src/components/LpCodeBlock.vue +17 -23
  447. package/src/components/LpCollapse.vue +5 -4
  448. package/src/components/LpColorPicker.vue +8 -9
  449. package/src/components/LpCommandPalette.vue +133 -50
  450. package/src/components/LpContextMenu.vue +15 -13
  451. package/src/components/LpCountdown.vue +2 -1
  452. package/src/components/LpDataList.vue +13 -1
  453. package/src/components/LpDatePicker.vue +5 -17
  454. package/src/components/LpDateRangePicker.vue +5 -16
  455. package/src/components/LpDock.vue +25 -16
  456. package/src/components/LpDrawer.vue +70 -61
  457. package/src/components/LpDropdownMenu.vue +6 -10
  458. package/src/components/LpDropzone.vue +12 -7
  459. package/src/components/LpEditable.vue +6 -2
  460. package/src/components/LpFileTree.vue +507 -66
  461. package/src/components/LpFileTreeNode.vue +106 -5
  462. package/src/components/LpFormField.vue +1 -1
  463. package/src/components/LpFrame.vue +33 -13
  464. package/src/components/LpHoverCard.vue +30 -5
  465. package/src/components/LpIcon.vue +6 -2
  466. package/src/components/LpIdenticon.vue +2 -1
  467. package/src/components/LpImageEditor.vue +5 -2
  468. package/src/components/LpInput.vue +15 -23
  469. package/src/components/LpInspector.vue +197 -0
  470. package/src/components/LpLightbox.vue +74 -29
  471. package/src/components/LpLogInspector.vue +85 -0
  472. package/src/components/LpLogViewer.vue +239 -29
  473. package/src/components/LpMapPicker.vue +2 -1
  474. package/src/components/LpMasonry.vue +8 -5
  475. package/src/components/LpModal.vue +12 -12
  476. package/src/components/LpModalNav.vue +2 -21
  477. package/src/components/LpNumberField.vue +6 -15
  478. package/src/components/LpOtpInput.vue +2 -2
  479. package/src/components/LpPagination.vue +5 -3
  480. package/src/components/LpPhoneInput.vue +8 -19
  481. package/src/components/LpPie.vue +25 -23
  482. package/src/components/LpPipeline.vue +14 -1
  483. package/src/components/LpPopover.vue +23 -2
  484. package/src/components/LpProgress.vue +2 -1
  485. package/src/components/LpRadioGroup.vue +2 -2
  486. package/src/components/LpRangeSlider.vue +5 -6
  487. package/src/components/LpRevealOnScroll.vue +1 -1
  488. package/src/components/LpScrollArea.vue +28 -11
  489. package/src/components/LpSecretField.vue +2 -1
  490. package/src/components/LpSegmented.vue +6 -8
  491. package/src/components/LpSelect.vue +54 -24
  492. package/src/components/LpShaderBackdrop.vue +12 -9
  493. package/src/components/LpShift.vue +18 -15
  494. package/src/components/LpSidebar.vue +77 -74
  495. package/src/components/LpSidebarNav.vue +3 -2
  496. package/src/components/LpSidebarRow.vue +2 -1
  497. package/src/components/LpSlider.vue +5 -6
  498. package/src/components/LpSpotlight.vue +2 -1
  499. package/src/components/LpSwitch.vue +5 -3
  500. package/src/components/LpTable.vue +609 -93
  501. package/src/components/LpTableFilter.vue +1 -1
  502. package/src/components/LpTableOfContents.vue +16 -9
  503. package/src/components/LpTabs.vue +2 -1
  504. package/src/components/LpTagsInput.vue +12 -19
  505. package/src/components/LpTextarea.vue +5 -11
  506. package/src/components/LpThemeProvider.vue +29 -13
  507. package/src/components/LpTimeField.vue +4 -7
  508. package/src/components/LpToaster.vue +7 -6
  509. package/src/components/LpTooltip.vue +62 -18
  510. package/src/components/LpTopologyCanvas.vue +567 -42
  511. package/src/components/LpTour.vue +7 -5
  512. package/src/components/LpTruncate.vue +4 -3
  513. package/src/components/LpTypewriter.vue +2 -1
  514. package/src/components/LpVideoBackdrop.vue +11 -13
  515. package/src/components/LpWindow.vue +373 -0
  516. package/src/components/LpWorkspaceSwitcher.vue +116 -0
  517. package/src/components/PickerField.vue +2 -2
  518. package/src/components/SliderRail.vue +10 -0
  519. package/src/components/address.ts +3 -1
  520. package/src/components/appShell.ts +74 -0
  521. package/src/components/calendar.ts +12 -5
  522. package/src/components/chart.ts +27 -3
  523. package/src/components/chartWindow.ts +198 -0
  524. package/src/components/color.ts +2 -1
  525. package/src/components/commandPalette.ts +66 -5
  526. package/src/components/controlSize.ts +6 -0
  527. package/src/components/dropdown.ts +3 -0
  528. package/src/components/exportData.ts +33 -18
  529. package/src/components/fileTree.ts +215 -0
  530. package/src/components/identicon.ts +4 -2
  531. package/src/components/logTools.ts +298 -0
  532. package/src/components/meter.ts +2 -1
  533. package/src/components/pipeline.ts +6 -0
  534. package/src/components/relativeTime.ts +2 -1
  535. package/src/components/reveal.ts +3 -1
  536. package/src/components/select.ts +14 -0
  537. package/src/components/sidebar.ts +1 -0
  538. package/src/components/tableFeatures.ts +149 -0
  539. package/src/components/topologyGraph.ts +655 -0
  540. package/src/components/tour.ts +5 -3
  541. package/src/components/videoBackdrop.ts +7 -6
  542. package/src/composables/clamp.ts +2 -0
  543. package/src/composables/devWarn.ts +19 -0
  544. package/src/composables/easing.ts +37 -12
  545. package/src/composables/overlayHistory.ts +24 -0
  546. package/src/composables/pointerDrag.ts +54 -0
  547. package/src/composables/propCheck.ts +90 -0
  548. package/src/composables/realm.ts +25 -0
  549. package/src/composables/scroll.ts +4 -2
  550. package/src/composables/scrollMemory.ts +56 -14
  551. package/src/composables/spatialNav.ts +2 -1
  552. package/src/composables/textEntry.ts +33 -0
  553. package/src/composables/useAsyncTask.ts +6 -0
  554. package/src/composables/useChartSync.ts +52 -0
  555. package/src/composables/useCloseGuard.ts +22 -10
  556. package/src/composables/useCommands.ts +123 -0
  557. package/src/composables/useField.ts +41 -2
  558. package/src/composables/useFitScale.ts +4 -1
  559. package/src/composables/useFormDraft.ts +38 -14
  560. package/src/composables/useHintSystem.ts +2 -2
  561. package/src/composables/useHotkeys.ts +19 -48
  562. package/src/composables/useInView.ts +2 -1
  563. package/src/composables/useInputFilter.ts +8 -5
  564. package/src/composables/useInputMask.ts +8 -3
  565. package/src/composables/useLinkedView.ts +222 -0
  566. package/src/composables/useOptimisticToggle.ts +7 -1
  567. package/src/composables/useOverlayHistory.ts +20 -0
  568. package/src/composables/usePaintSelect.ts +20 -14
  569. package/src/composables/usePaletteCommands.ts +13 -0
  570. package/src/composables/usePersisted.ts +10 -0
  571. package/src/composables/usePillTransition.ts +9 -6
  572. package/src/composables/useResizeObserver.ts +2 -1
  573. package/src/composables/useReveal.ts +2 -1
  574. package/src/composables/useRovingFocus.ts +11 -14
  575. package/src/composables/useScramble.ts +12 -1
  576. package/src/composables/useShift.ts +8 -6
  577. package/src/composables/useTilt.ts +2 -1
  578. package/src/composables/useTween.ts +10 -5
  579. package/src/composables/useView.ts +17 -3
  580. package/src/composables/useZoomPan.ts +2 -5
  581. package/src/composables/windowing.ts +190 -0
  582. package/src/icons.ts +27 -6
  583. package/src/index.ts +41 -4
  584. package/src/kit-icons.ts +1 -1
  585. package/src/layout/tree.ts +31 -16
  586. package/src/layout/useLayout.ts +6 -0
  587. package/src/layout/useWorkspaces.ts +234 -0
  588. package/src/nuxt.ts +9 -1
  589. package/src/runtime/propCheck.plugin.ts +10 -0
  590. package/src/theme/studio.ts +7 -5
  591. package/src/theme/useTheme.ts +89 -15
  592. package/src/tokens/tokens.css +8 -1
  593. package/dist/assets/LpTabs-CJ0rYQbx.css +0 -18
  594. package/dist/chunks/LpAppShell-Dgejipzz.js +0 -319
  595. package/dist/chunks/LpFileTree-CooHinsC.js +0 -425
  596. package/dist/chunks/LpThemeProvider-8MG6yqU9.js +0 -640
  597. package/dist/chunks/LpTopologyCanvas-B1gIbS0n.js +0 -298
@@ -16,6 +16,8 @@ export type SelectLabels = {
16
16
  </script>
17
17
 
18
18
  <script setup lang="ts" generic="V extends SelectValue = string">
19
+ import IconCloseButton from "./IconCloseButton.vue"
20
+ import { CONTROL_SIZE } from "./controlSize"
19
21
  import { usePaletteControl, type PaletteControlOptions } from "../composables/usePaletteCommands"
20
22
  /*
21
23
  * One select to rule them all — built on reka-ui Combobox.
@@ -37,7 +39,7 @@ import {
37
39
  ComboboxViewport,
38
40
  } from "reka-ui"
39
41
  import { computed, nextTick, reactive, ref, useAttrs, useId, watch } from "vue"
40
- import { useFieldBlur, useFieldControl } from "../composables/useField"
42
+ import { useFieldBlur, useFieldControl, mergeDescribedBy } from "../composables/useField"
41
43
  import { useLabels } from "../composables/useLpConfig"
42
44
  import { useMergedAttrs } from "../composables/useMergedClass"
43
45
  import { OPTION_ITEM, optionStagger, POPOVER_PANEL } from "./dropdown"
@@ -45,8 +47,8 @@ import LpIcon from "./LpIcon.vue"
45
47
  import OptionContent from "./OptionContent.vue"
46
48
  import LpRollingText from "./LpRollingText.vue"
47
49
  import type { LpOptionBase, OptionSelection } from "./options"
48
- import { fitChips, toggledValues } from "./select"
49
- import { useOutsideGuard, usePortalTarget } from "../composables/useView"
50
+ import { evictOldest, fitChips, toggledValues } from "./select"
51
+ import { nodeWindow, useOutsideGuard, usePortalTarget } from "../composables/useView"
50
52
  import { useResizeObserver } from "../composables/useResizeObserver"
51
53
 
52
54
  export type SelectValue = string | number
@@ -105,11 +107,7 @@ const props = withDefaults(
105
107
  )
106
108
 
107
109
  /* The text steps with the height, as in every other kit field: a small select beside a small input read a size larger. */
108
- const SIZE_HEIGHT = {
109
- sm: "h-(--size-control-sm) text-xs",
110
- md: "h-(--size-control-md) text-sm",
111
- lg: "h-(--size-control-lg) text-sm",
112
- } as const
110
+ const SIZE_HEIGHT = CONTROL_SIZE
113
111
  const anchorHeight = computed(() => SIZE_HEIGHT[props.size])
114
112
 
115
113
  const field = useFieldControl(() => ({
@@ -189,7 +187,38 @@ async function openFromKeyboard(event: KeyboardEvent) {
189
187
  const items = panel?.querySelectorAll<HTMLElement>('[role="option"]:not([data-disabled])')
190
188
  const selected = panel?.querySelector<HTMLElement>('[role="option"][aria-selected="true"]:not([data-disabled])')
191
189
  const target = search ?? selected ?? (event.key === "ArrowUp" ? items?.[items.length - 1] : items?.[0])
192
- target?.focus()
190
+ // Something else may have kept the list shut: nothing to move into then.
191
+ if (isOpen.value) target?.focus()
192
+ }
193
+
194
+ /*
195
+ * reka reads the arrow keys from the search box. A list without one takes focus
196
+ * on an option, where its own handling put focus straight back on the option
197
+ * the list opened on, so that was all a keyboard could ever pick. Taken here,
198
+ * ahead of it.
199
+ */
200
+ const LIST_KEYS = ["ArrowDown", "ArrowUp", "Home", "End", "Enter"]
201
+
202
+ function moveInList(event: KeyboardEvent) {
203
+ if (props.searchable || serverSide.value || !LIST_KEYS.includes(event.key)) return
204
+ const list = event.currentTarget as HTMLElement
205
+ const items = Array.from(list.querySelectorAll<HTMLElement>('[role="option"]:not([data-disabled])'))
206
+ if (!items.length) return
207
+ event.preventDefault()
208
+ event.stopPropagation()
209
+ const at = items.indexOf(list.ownerDocument.activeElement as HTMLElement)
210
+ if (event.key === "Enter") {
211
+ items[at]?.click()
212
+ return
213
+ }
214
+ const last = items.length - 1
215
+ const next = {
216
+ ArrowDown: at === last ? 0 : at + 1,
217
+ ArrowUp: at <= 0 ? last : at - 1,
218
+ Home: 0,
219
+ End: last,
220
+ }[event.key]
221
+ items[next ?? 0]?.focus()
193
222
  }
194
223
 
195
224
  // Leaving the field, not moving between its parts: the trigger and the list
@@ -219,7 +248,9 @@ function onListFocusOut(event: FocusEvent) {
219
248
  * The trigger's name. reka hard-codes aria-label="Show popup" on it, which hid
220
249
  * the field's label and the chosen value; aria-labelledby outranks aria-label,
221
250
  * so inside a labelled field the name is the label plus the value. On its own,
222
- * the consumer's aria-label, else the value or placeholder.
251
+ * the consumer's aria-label plus the value, else the value or placeholder: the
252
+ * name has to hold the text the button shows, or a voice user who says what
253
+ * they see ("click Alpha") cannot reach it (WCAG 2.5.3).
223
254
  */
224
255
  const attrs = useAttrs()
225
256
  const valueId = `lp-select-${useId()}-value`
@@ -227,7 +258,7 @@ const valueText = computed(() => (chips.value.length ? chipNames.value : display
227
258
  const triggerName = computed(() =>
228
259
  field.value.labelId
229
260
  ? { "aria-labelledby": `${field.value.labelId} ${valueId}`, "aria-label": undefined }
230
- : { "aria-label": (attrs["aria-label"] as string | undefined) ?? valueText.value },
261
+ : { "aria-label": [attrs["aria-label"] as string | undefined, valueText.value].filter(Boolean).join(", ") },
231
262
  )
232
263
 
233
264
  // reka's Combobox forbids an empty-string item value (it reserves "" for
@@ -281,6 +312,7 @@ const filtered = computed(() => {
281
312
  type Shown = { label: string; hint?: string; image?: string; icon?: string }
282
313
 
283
314
  const remembered = reactive(new Map<SelectValue, Shown>())
315
+ const REMEMBERED_LIMIT = 500
284
316
 
285
317
  function fromOption(o: SelectOption<V>): Shown {
286
318
  return { label: o.label, hint: o.description, image: o.image, icon: o.icon }
@@ -291,6 +323,7 @@ function remember(values: readonly SelectValue[]) {
291
323
  const o = props.options.find((x) => x.value === v)
292
324
  if (o) remembered.set(v, fromOption(o))
293
325
  }
326
+ evictOldest(remembered, new Set(values), REMEMBERED_LIMIT)
294
327
  }
295
328
 
296
329
  const modelList = computed<V[]>(() => {
@@ -355,7 +388,7 @@ function measure() {
355
388
  if (!row || !probe) return
356
389
  const kids = Array.from(probe.children) as HTMLElement[]
357
390
  const more = kids.pop()
358
- const gap = Number.parseFloat(getComputedStyle(probe).columnGap) || 0
391
+ const gap = Number.parseFloat(nodeWindow(probe).getComputedStyle(probe).columnGap) || 0
359
392
  fit.value = fitChips(
360
393
  kids.map((k) => k.offsetWidth),
361
394
  row.clientWidth,
@@ -365,6 +398,9 @@ function measure() {
365
398
  }
366
399
 
367
400
  useResizeObserver(chipRow, () => measure())
401
+ // The chips can change width while the row keeps its own: a web font arriving,
402
+ // a theme. The probe is as wide as they are, so it notices.
403
+ useResizeObserver(probeRow, () => measure())
368
404
  watch(chips, () => void nextTick(measure), { flush: "post", deep: true })
369
405
 
370
406
  const shownChips = computed(() => chips.value.slice(0, fit.value))
@@ -451,7 +487,7 @@ usePaletteControl({ disabled: () => field.value.disabled, invalid: () => field.v
451
487
  @keydown="openFromKeyboard"
452
488
  v-bind="triggerName"
453
489
  :aria-invalid="field.invalid || undefined"
454
- :aria-describedby="field.describedBy"
490
+ :aria-describedby="mergeDescribedBy(rootAttrs['aria-describedby'], field.describedBy)"
455
491
  class="flex min-w-0 flex-1 items-center gap-2 outline-none"
456
492
  >
457
493
  <!-- Several picks read as chips (picture + name) that collapse into
@@ -527,20 +563,13 @@ usePaletteControl({ disabled: () => field.value.disabled, invalid: () => field.v
527
563
  </LpRollingText>
528
564
  </template>
529
565
  </ComboboxTrigger>
530
- <button
566
+ <IconCloseButton
531
567
  v-if="clearable && hasValue && !field.disabled"
532
- type="button"
533
- class="group flex shrink-0 items-center text-muted outline-none transition-colors duration-[var(--duration-fast)] hover:text-ink"
534
- :aria-label="labels.clear"
568
+ inline
569
+ :label="labels.clear"
535
570
  @pointerdown.prevent
536
571
  @click="clear"
537
- >
538
- <LpIcon
539
- name="lucide:x"
540
- :size="16"
541
- class="transition-transform duration-200 ease-[var(--ease-emphasized)] group-hover:rotate-90 group-active:scale-90 motion-reduce:group-hover:rotate-0"
542
- />
543
- </button>
572
+ />
544
573
  <!-- A second way in for the pointer only: the main trigger already owns
545
574
  focus and the accessible name, so this one stays out of the tab order
546
575
  and the accessibility tree. -->
@@ -565,6 +594,7 @@ usePaletteControl({ disabled: () => field.value.disabled, invalid: () => field.v
565
594
  <ComboboxContent
566
595
  :data-lp-field-part="partId"
567
596
  @focusout="onListFocusOut"
597
+ @keydown.capture="moveInList"
568
598
  @interact-outside="guardOutside"
569
599
  @escape-key-down="guardOutside"
570
600
  position="popper"
@@ -35,6 +35,8 @@ export default { inheritAttrs: false }
35
35
  * - Unmounting releases the GL context, so a page that mounts and unmounts
36
36
  * backdrops does not run into the browser's limit on live contexts.
37
37
  */
38
+ import { clamp } from "../composables/clamp"
39
+ import { nodeWindow } from "../composables/useView"
38
40
  import { computed, onBeforeUnmount, onMounted, ref, watch } from "vue"
39
41
  import { parseColor } from "./color"
40
42
  import { approach, frameDue, FRAGMENT_HEADER, PRESETS, tooSlow, VERTEX_SHADER, type ShaderPreset, type Vec3 } from "./shaderBackdrop"
@@ -95,7 +97,7 @@ const weakEngine = typeof navigator !== "undefined" && isBrokenBackdropEngine()
95
97
  const fallbackStyle = computed(() => ({ background: PRESETS[props.preset].fallback, opacity: Math.min(1, clamp01(props.intensity) * 1.15) }))
96
98
 
97
99
  function clamp01(n: number) {
98
- return Math.max(0, Math.min(1, n))
100
+ return clamp(n, 0, 1)
99
101
  }
100
102
 
101
103
  // ── Theme colours ───────────────────────────────────────────────────────────
@@ -115,10 +117,10 @@ let paint: CanvasRenderingContext2D | null = null
115
117
  function tokenColor(name: string): Vec3 {
116
118
  if (!probe || !root.value) return [0, 0, 0]
117
119
  probe.style.color = `var(--color-${name})`
118
- const css = getComputedStyle(probe).color
120
+ const css = nodeWindow(probe).getComputedStyle(probe).color
119
121
  const rgb = parseColor(css)
120
122
  if (rgb) return [rgb.r / 255, rgb.g / 255, rgb.b / 255]
121
- paint ??= document.createElement("canvas").getContext("2d", { willReadFrequently: true })
123
+ paint ??= probe.ownerDocument.createElement("canvas").getContext("2d", { willReadFrequently: true })
122
124
  if (!paint) return [0, 0, 0]
123
125
  paint.clearRect(0, 0, 1, 1)
124
126
  paint.fillStyle = "#000"
@@ -204,7 +206,7 @@ let pixelRatio = 1
204
206
  function sizeCanvas() {
205
207
  const el = canvas.value
206
208
  if (!el) return
207
- const dpr = Math.min(weakEngine ? 1 : 2, window.devicePixelRatio || 1)
209
+ const dpr = Math.min(weakEngine ? 1 : 2, nodeWindow(el).devicePixelRatio || 1)
208
210
  pixelRatio = dpr * PRESETS[props.preset].scale
209
211
  const w = Math.max(1, Math.round(el.clientWidth * pixelRatio))
210
212
  const h = Math.max(1, Math.round(el.clientHeight * pixelRatio))
@@ -351,16 +353,17 @@ useResizeObserver(root, () => {
351
353
  })
352
354
 
353
355
  onMounted(() => {
354
- probe = document.createElement("span")
356
+ const page = root.value?.ownerDocument ?? document
357
+ probe = page.createElement("span")
355
358
  probe.style.display = "none"
356
359
  root.value?.appendChild(probe)
357
360
 
358
361
  // Themes are applied as variables and attributes on <html>; a scheme switch can also come from the OS.
359
- themeObserver = new MutationObserver(() => {
362
+ themeObserver = new (nodeWindow(page).MutationObserver)(() => {
360
363
  if (gl) refreshPalette()
361
364
  })
362
- themeObserver.observe(document.documentElement, { attributes: true, attributeFilter: ["style", "class", "data-theme", "data-theme-mode"] })
363
- schemeQuery = window.matchMedia?.("(prefers-color-scheme: dark)")
365
+ themeObserver.observe(page.documentElement, { attributes: true, attributeFilter: ["style", "class", "data-theme", "data-theme-mode"] })
366
+ schemeQuery = nodeWindow(page).matchMedia?.("(prefers-color-scheme: dark)")
364
367
  schemeQuery?.addEventListener("change", refreshPalette)
365
368
 
366
369
  if (wantGl.value) start()
@@ -391,7 +394,7 @@ watch(
391
394
  }
392
395
  drawFrame()
393
396
  shown.value = true
394
- }, durationToken("duration-medium"))
397
+ }, durationToken("duration-medium", undefined, root.value ?? undefined))
395
398
  },
396
399
  )
397
400
  watch(
@@ -25,6 +25,7 @@
25
25
  * The mechanism — measure the natural size, pin it in pixels, tween — lives in
26
26
  * `useShift`, and LpModal drives its panel with the same composable.
27
27
  */
28
+ import { isElement, isHTMLElement, nodeWindow } from "../composables/useView"
28
29
  import { computed, onBeforeUnmount, watch } from "vue"
29
30
  import { prefersReducedMotion } from "../composables/easing"
30
31
  import { useShift, type ShiftAxis } from "../composables/useShift"
@@ -99,6 +100,7 @@ const transitionClass = computed(() => TRANSITION_CLASS[props.axis])
99
100
  const PRESENCE_MS = 200
100
101
  const MOVE_MS = 160
101
102
  const EASE = "cubic-bezier(0.2, 0, 0, 1)"
103
+ const SVG_NS = "http://www.w3.org/2000/svg"
102
104
  const GHOST = "data-lp-shift-ghost"
103
105
 
104
106
  interface Seen {
@@ -120,7 +122,7 @@ function rememberSoon(box: HTMLElement, wait = PRESENCE_MS + 80) {
120
122
  }
121
123
 
122
124
  function elementsOf(box: HTMLElement): Element[] {
123
- return [...box.querySelectorAll("*")].filter((node) => !node.closest(`[${GHOST}]`) && !(node instanceof SVGElement && !(node instanceof SVGSVGElement)))
125
+ return [...box.querySelectorAll("*")].filter((node) => !node.closest(`[${GHOST}]`) && !(node.namespaceURI === SVG_NS && node.localName !== "svg"))
124
126
  }
125
127
 
126
128
  function remember(box: HTMLElement) {
@@ -142,7 +144,7 @@ function remember(box: HTMLElement) {
142
144
  // override that animation's transform, and the marker would pop instead of
143
145
  // sliding.
144
146
  function inFlow(node: Element): boolean {
145
- const position = getComputedStyle(node).position
147
+ const position = nodeWindow(node).getComputedStyle(node).position
146
148
  return position !== "absolute" && position !== "fixed"
147
149
  }
148
150
 
@@ -150,7 +152,7 @@ function inFlow(node: Element): boolean {
150
152
  // actions, a list re-keyed after a reload) is not a change anyone sees, so the
151
153
  // pair is left alone rather than flashing out and in.
152
154
  function signature(node: Node): string | undefined {
153
- return node instanceof Element ? node.outerHTML : undefined
155
+ return isElement(node) ? node.outerHTML : undefined
154
156
  }
155
157
 
156
158
  function unchanged(records: MutationRecord[]): Set<Node> {
@@ -172,7 +174,7 @@ const offset = () => (props.anchor === "end" ? -6 : 6)
172
174
 
173
175
  function ghost(box: HTMLElement, node: Element) {
174
176
  const at = seen.get(node)
175
- if (!at || !at.flow || !(node instanceof HTMLElement) || node.hasAttribute(GHOST) || at.width === 0) return
177
+ if (!at || !at.flow || !isHTMLElement(node) || node.hasAttribute(GHOST) || at.width === 0) return
176
178
  const copy = node.cloneNode(true) as HTMLElement
177
179
  copy.setAttribute(GHOST, "")
178
180
  copy.setAttribute("aria-hidden", "true")
@@ -207,7 +209,7 @@ function ghost(box: HTMLElement, node: Element) {
207
209
  }
208
210
 
209
211
  function arrive(node: Element) {
210
- if (!(node instanceof HTMLElement) || node.hasAttribute(GHOST) || !inFlow(node)) return
212
+ if (!isHTMLElement(node) || node.hasAttribute(GHOST) || !inFlow(node)) return
211
213
  node.animate(
212
214
  [
213
215
  { opacity: 0, transform: `translateX(${offset()}px) scale(0.96)`, filter: "blur(2px)" },
@@ -219,7 +221,7 @@ function arrive(node: Element) {
219
221
 
220
222
  function glide(node: Element) {
221
223
  const was = seen.get(node)
222
- if (!was || !(node instanceof HTMLElement)) return
224
+ if (!was || !isHTMLElement(node)) return
223
225
  const now = node.getBoundingClientRect()
224
226
  const dx = was.x - now.left
225
227
  const dy = was.y - now.top
@@ -236,25 +238,26 @@ watch(
236
238
  presenceSize = undefined
237
239
  if (!box || !on) return
238
240
  remember(box)
239
- presenceObserver = new MutationObserver((records) => {
241
+ const win = nodeWindow(box)
242
+ presenceObserver = new win.MutationObserver((records) => {
240
243
  const real = records.filter(
241
244
  (r) =>
242
- ![...r.addedNodes, ...r.removedNodes].every((n) => n instanceof Element && n.hasAttribute(GHOST)),
245
+ ![...r.addedNodes, ...r.removedNodes].every((n) => isElement(n) && n.hasAttribute(GHOST)),
243
246
  )
244
- if (real.length && !prefersReducedMotion()) {
247
+ if (real.length && !prefersReducedMotion(win)) {
245
248
  const added = new Set<Node>()
246
249
  const same = unchanged(real)
247
250
  for (const record of real) {
248
- record.removedNodes.forEach((node) => node instanceof Element && !same.has(node) && ghost(box, node))
251
+ record.removedNodes.forEach((node) => isElement(node) && !same.has(node) && ghost(box, node))
249
252
  record.addedNodes.forEach((node) => {
250
253
  added.add(node)
251
- if (node instanceof Element && !same.has(node)) arrive(node)
254
+ if (isElement(node) && !same.has(node)) arrive(node)
252
255
  })
253
256
  }
254
257
  // Measured in the next frame, which still comes before the paint: by
255
258
  // then the box has taken the classes the change gave it (held to its
256
259
  // edge), and the place an element lands is the one it will keep.
257
- const parents = real.map((r) => r.target).filter((t): t is Element => t instanceof Element && !t.hasAttribute(GHOST))
260
+ const parents = real.map((r) => r.target).filter((t): t is Element => isElement(t) && !t.hasAttribute(GHOST))
258
261
  requestAnimationFrame(() => {
259
262
  for (const parent of parents) for (const child of parent.children) if (!added.has(child)) glide(child)
260
263
  })
@@ -262,9 +265,9 @@ watch(
262
265
  rememberSoon(box)
263
266
  })
264
267
  presenceObserver.observe(box, { childList: true, subtree: true })
265
- presenceSize = new ResizeObserver(() => rememberSoon(box, 60))
268
+ presenceSize = new win.ResizeObserver(() => rememberSoon(box, 60))
266
269
  presenceSize.observe(box)
267
- void document.fonts?.ready.then(() => rememberSoon(box, 0))
270
+ void box.ownerDocument.fonts?.ready.then(() => rememberSoon(box, 0))
268
271
  },
269
272
  { flush: "post" },
270
273
  )
@@ -274,7 +277,7 @@ watch(
274
277
  // resize, every child glides from where it was last seen.
275
278
  watch(resizing, (now) => {
276
279
  const box = el.value
277
- if (!now || !box || !presenceObserver || prefersReducedMotion()) return
280
+ if (!now || !box || !presenceObserver || prefersReducedMotion(nodeWindow(box))) return
278
281
  requestAnimationFrame(() => {
279
282
  for (const child of box.children) if (!child.hasAttribute(GHOST)) glide(child)
280
283
  })
@@ -13,8 +13,10 @@
13
13
  * auto-closes the drawer. With `responsive` off the component renders exactly
14
14
  * the static <nav> it always has — existing call sites are unaffected.
15
15
  */
16
- import { computed, nextTick, ref, useId } from "vue"
16
+ import { clamp } from "../composables/clamp"
17
+ import { computed, nextTick, onBeforeUnmount, ref, useId } from "vue"
17
18
  import { parseCombo, useHotkeys } from "../composables/useHotkeys"
19
+ import { startPointerDrag } from "../composables/pointerDrag"
18
20
  import { usePersisted } from "../composables/usePersisted"
19
21
  import { useLabels } from "../composables/useLpConfig"
20
22
  import LpDrawer from "./LpDrawer.vue"
@@ -123,7 +125,7 @@ const props = withDefaults(
123
125
  persist?: string
124
126
  /**
125
127
  * Fold collapsible groups automatically once the nav has more than this
126
- * many rows, counting headings and items alike.
128
+ * many rows, counting headings, items and the pages under them alike.
127
129
  *
128
130
  * The reason is the reader, not the pixels: a short nav is taken in at a
129
131
  * glance, a long one has to be searched, and searching a list you did not
@@ -310,9 +312,12 @@ const ownCollapsed = usePersisted<string[] | null>(
310
312
  { validate: (value): value is string[] | null => value === null || (Array.isArray(value) && value.every((k) => typeof k === "string")) },
311
313
  )
312
314
 
313
- /** Headings + items: what the eye actually has to walk past. */
314
- const navLength = computed(
315
- () => groups.value.reduce((n, g) => n + g.items.length + (g.title ? 1 : 0), 0),
315
+ /** Headings, items and their pages: what the eye actually has to walk past. */
316
+ const navLength = computed(() =>
317
+ groups.value.reduce(
318
+ (n, g) => n + (g.title ? 1 : 0) + g.items.reduce((rows, i) => rows + 1 + (i.children?.length ?? 0), 0),
319
+ 0,
320
+ ),
316
321
  )
317
322
 
318
323
  /*
@@ -340,7 +345,9 @@ function toggleSection(key: string, collapsed: boolean) {
340
345
  const next = collapsed
341
346
  ? [...new Set([...collapsedKeys.value, key])]
342
347
  : collapsedKeys.value.filter((k) => k !== key)
343
- ownCollapsed.value = next
348
+ // A bound value is the app's: storing it too would surface a stale choice
349
+ // the day the binding goes. The same goes for compact and pins below.
350
+ if (props.collapsed === undefined) ownCollapsed.value = next
344
351
  emit("update:collapsed", next)
345
352
  }
346
353
 
@@ -351,7 +358,7 @@ function toggleSection(key: string, collapsed: boolean) {
351
358
  const ownCompact = usePersisted<boolean>(() => props.persist && `lp-sidebar:${props.persist}:compact`, false)
352
359
  const isCompact = computed(() => props.compact ?? ownCompact.value)
353
360
  function setCompact(value: boolean) {
354
- ownCompact.value = value
361
+ if (props.compact === undefined) ownCompact.value = value
355
362
  emit("update:compact", value)
356
363
  }
357
364
 
@@ -370,12 +377,20 @@ const env = computed(() => {
370
377
 
371
378
  const DEFAULT_WIDTH = 240
372
379
  const COMPACT_WIDTH = 64
373
- const ownWidth = usePersisted<number>(() => props.resizable && props.persist && `lp-sidebar:${props.persist}:width`, DEFAULT_WIDTH)
380
+ const ownWidth = usePersisted<number>(() => props.resizable && props.persist && `lp-sidebar:${props.persist}:width`, DEFAULT_WIDTH, {
381
+ validate: (value): value is number => typeof value === "number" && Number.isFinite(value),
382
+ })
374
383
  const dragging = ref(false)
375
384
 
385
+ /*
386
+ * The bounds apply to what is drawn, not to what is kept: a width remembered
387
+ * under other bounds fits today's, and comes back if they widen again.
388
+ */
389
+ const boundedWidth = (width: number) => clamp(width, props.minWidth, props.maxWidth)
390
+
376
391
  const railWidth = computed(() => {
377
392
  if (isCompact.value) return `${COMPACT_WIDTH}px`
378
- if (props.resizable) return `${ownWidth.value}px`
393
+ if (props.resizable) return `${boundedWidth(ownWidth.value)}px`
379
394
  return props.width
380
395
  })
381
396
 
@@ -385,34 +400,32 @@ const railWidth = computed(() => {
385
400
  * useful, and the icon rail is the honest form of "narrow".
386
401
  */
387
402
  const FOLD_AT = 132
403
+ let stopResize: (() => void) | null = null
404
+ onBeforeUnmount(() => stopResize?.())
405
+
388
406
  function startResize(event: PointerEvent) {
389
407
  if (event.button !== 0) return
390
- const handle = event.currentTarget as HTMLElement
391
- handle.setPointerCapture(event.pointerId)
392
408
  const from = event.clientX
393
- const start = isCompact.value ? COMPACT_WIDTH : ownWidth.value
409
+ const start = isCompact.value ? COMPACT_WIDTH : boundedWidth(ownWidth.value)
394
410
  dragging.value = true
395
- const move = (e: PointerEvent) => {
396
- const wanted = start + (e.clientX - from)
397
- if (wanted < FOLD_AT) {
398
- // Folded by dragging: the width it unfolds to is the one it had, not
399
- // the narrowest the drag passed through on its way down.
400
- if (!isCompact.value) setCompact(true)
401
- if (start !== COMPACT_WIDTH) ownWidth.value = start
402
- return
403
- }
404
- if (isCompact.value) setCompact(false)
405
- ownWidth.value = Math.round(Math.min(props.maxWidth, Math.max(props.minWidth, wanted)))
406
- }
407
- const stop = () => {
408
- dragging.value = false
409
- handle.removeEventListener("pointermove", move)
410
- handle.removeEventListener("pointerup", stop)
411
- handle.removeEventListener("pointercancel", stop)
412
- }
413
- handle.addEventListener("pointermove", move)
414
- handle.addEventListener("pointerup", stop)
415
- handle.addEventListener("pointercancel", stop)
411
+ stopResize = startPointerDrag(event, {
412
+ move(e) {
413
+ const wanted = start + (e.clientX - from)
414
+ if (wanted < FOLD_AT) {
415
+ // Folded by dragging: the width it unfolds to is the one it had, not
416
+ // the narrowest the drag passed through on its way down.
417
+ if (!isCompact.value) setCompact(true)
418
+ if (start !== COMPACT_WIDTH) ownWidth.value = start
419
+ return
420
+ }
421
+ if (isCompact.value) setCompact(false)
422
+ ownWidth.value = Math.round(boundedWidth(wanted))
423
+ },
424
+ end() {
425
+ dragging.value = false
426
+ stopResize = null
427
+ },
428
+ })
416
429
  }
417
430
  const railEl = ref<HTMLElement | null>(null)
418
431
  async function searchFromCompact() {
@@ -451,7 +464,7 @@ const pinnedItems = computed<SidebarItem[]>(() =>
451
464
  )
452
465
  function togglePin(id: string) {
453
466
  const next = pinnedIds.value.includes(id) ? pinnedIds.value.filter((k) => k !== id) : [...pinnedIds.value, id]
454
- ownPinned.value = next
467
+ if (props.pinned === undefined) ownPinned.value = next
455
468
  emit("update:pinned", next)
456
469
  }
457
470
 
@@ -495,6 +508,32 @@ const chromeClass = computed(() =>
495
508
  // Vue can't auto-inherit a consumer-passed `class`. Take attrs over manually and
496
509
  // land them on the desktop rail (where a layout class like `shrink-0` belongs).
497
510
  defineOptions({ inheritAttrs: false })
511
+
512
+ // The rail and the drawer draw the same list and the same search over it.
513
+ const navBinds = computed(() => ({
514
+ groups: groups.value,
515
+ pinnable: props.pinnable,
516
+ pinned: pinnedItems.value,
517
+ previewDelay: props.previewDelay,
518
+ labels: text.value,
519
+ itemActive,
520
+ loading: props.loading,
521
+ skeletonRows: props.skeletonRows,
522
+ skeletonHeader: props.skeletonHeader,
523
+ collapsedKeys: collapsedKeys.value,
524
+ hoverFollow: props.hoverFollow,
525
+ onActivate: activate,
526
+ onToggleSection: toggleSection,
527
+ onTogglePin: togglePin,
528
+ }))
529
+ const searchField = computed(() => ({
530
+ size: "sm" as const,
531
+ icon: "lucide:search",
532
+ clearable: true,
533
+ class: "mb-2 shrink-0",
534
+ placeholder: placeholder.value,
535
+ "aria-label": placeholder.value,
536
+ }))
498
537
  </script>
499
538
 
500
539
  <template>
@@ -558,30 +597,12 @@ defineOptions({ inheritAttrs: false })
558
597
  <LpInput
559
598
  v-if="searchable && !isCompact"
560
599
  v-model="query"
561
- size="sm"
562
- icon="lucide:search"
563
- clearable
564
- class="mb-2 shrink-0"
565
- :placeholder="placeholder"
566
- :aria-label="placeholder"
600
+ v-bind="searchField"
567
601
  />
568
602
  <LpSidebarNav
569
- :groups="groups"
603
+ v-bind="navBinds"
570
604
  :pill-id="railPillId"
571
605
  :compact="isCompact"
572
- :pinnable="pinnable"
573
- :pinned="pinnedItems"
574
- :preview-delay="previewDelay"
575
- :labels="text"
576
- :item-active="itemActive"
577
- :loading="loading"
578
- :skeleton-rows="skeletonRows"
579
- :skeleton-header="skeletonHeader"
580
- :collapsed-keys="collapsedKeys"
581
- :hover-follow="hoverFollow"
582
- @activate="activate"
583
- @toggle-section="toggleSection"
584
- @toggle-pin="togglePin"
585
606
  >
586
607
  <template v-if="$slots.item" #item="slotProps">
587
608
  <slot name="item" v-bind="slotProps" />
@@ -660,29 +681,11 @@ defineOptions({ inheritAttrs: false })
660
681
  <LpInput
661
682
  v-if="searchable"
662
683
  v-model="query"
663
- size="sm"
664
- icon="lucide:search"
665
- clearable
666
- class="mb-2 shrink-0"
667
- :placeholder="placeholder"
668
- :aria-label="placeholder"
684
+ v-bind="searchField"
669
685
  />
670
686
  <LpSidebarNav
671
- :groups="groups"
687
+ v-bind="navBinds"
672
688
  :pill-id="drawerPillId"
673
- :pinnable="pinnable"
674
- :pinned="pinnedItems"
675
- :preview-delay="previewDelay"
676
- :labels="text"
677
- :item-active="itemActive"
678
- :loading="loading"
679
- :skeleton-rows="skeletonRows"
680
- :skeleton-header="skeletonHeader"
681
- :collapsed-keys="collapsedKeys"
682
- :hover-follow="hoverFollow"
683
- @activate="activate"
684
- @toggle-section="toggleSection"
685
- @toggle-pin="togglePin"
686
689
  >
687
690
  <template v-if="$slots.item" #item="slotProps">
688
691
  <slot name="item" v-bind="slotProps" />
@@ -149,7 +149,8 @@ let typedAt = 0
149
149
  function onKey(event: KeyboardEvent) {
150
150
  const box = event.currentTarget as HTMLElement
151
151
  const list = [...box.querySelectorAll<HTMLElement>("[data-lp-nav-row]")].filter((r) => r.offsetParent !== null)
152
- const at = list.indexOf(document.activeElement as HTMLElement)
152
+ // The rows' own document: inside an LpFrame the page's only knows the iframe.
153
+ const at = list.indexOf(box.ownerDocument.activeElement as HTMLElement)
153
154
  if (at < 0) return
154
155
  const row = list[at]!
155
156
  const go = (i: number) => {
@@ -270,7 +271,7 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
270
271
  @activate="activate"
271
272
  />
272
273
  </div>
273
- <template v-for="(section, si) in groups" :key="si">
274
+ <template v-for="(section, si) in groups" :key="sectionKey(section) || si">
274
275
  <!-- Compact, a group that folds is one icon: its pages open in the card
275
276
  beside it, as a page's own pages do. A hundred initials in a column
276
277
  would be no nav at all. -->
@@ -9,6 +9,7 @@
9
9
  * sidebar it is the row's name (and the pages under it), since the row shows
10
10
  * only an icon; with a `preview` it is a glance at the page before going there.
11
11
  */
12
+ import { clamp } from "../composables/clamp"
12
13
  import { Motion } from "motion-v"
13
14
  import { computed, onBeforeUnmount, ref, watch } from "vue"
14
15
  import { useLocale } from "../composables/useLocale"
@@ -164,7 +165,7 @@ const delay = computed(() => (props.compact && !props.item.preview ? 250 : props
164
165
  <span
165
166
  v-if="typeof item.busy === 'number'"
166
167
  class="block h-full rounded-pill bg-brand transition-[width] duration-(--duration-medium) ease-[var(--ease-emphasized)]"
167
- :style="{ width: `${Math.round(Math.min(1, Math.max(0, item.busy)) * 100)}%` }"
168
+ :style="{ width: `${Math.round(clamp(item.busy, 0, 1) * 100)}%` }"
168
169
  />
169
170
  <span v-else class="lp-sweep absolute inset-y-0 left-0 w-2/5 rounded-pill bg-brand" />
170
171
  </span>