@leavepulse/ui 0.77.2 → 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-sYMvYzcY.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-DOu7FN5P.js → LpAutocomplete-DkY6CSyD.js} +26 -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 +18 -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
@@ -67,7 +67,7 @@ import { hints } from "../composables/useHints"
67
67
  import { useHotkeys } from "../composables/useHotkeys"
68
68
  import { useLabels } from "../composables/useLpConfig"
69
69
  import { useMediaQuery } from "../composables/useMediaQuery"
70
- import { useView, viewDocument, viewWindow } from "../composables/useView"
70
+ import { isElement, useView, viewDocument, viewWindow } from "../composables/useView"
71
71
  import { scrollToElement } from "../composables/scroll"
72
72
  import { PANEL_SURFACE } from "./dropdown"
73
73
  import TourCard from "./TourCard.vue"
@@ -160,7 +160,7 @@ const reference = {
160
160
  }
161
161
  const last = computed(() => index.value >= props.steps.length - 1)
162
162
  const progress = computed(() => labels.value.progress.replace("{n}", String(index.value + 1)).replace("{total}", String(props.steps.length)))
163
- const smooth = () => !prefersReducedMotion()
163
+ const smooth = () => !prefersReducedMotion(win())
164
164
 
165
165
  function resolve(raw: TourStep["target"]): Element | null {
166
166
  if (!raw) return null
@@ -194,7 +194,7 @@ function controlRadius(): number {
194
194
  const probe = doc().createElement("div")
195
195
  probe.style.cssText = "position:absolute;visibility:hidden;border-top-left-radius:var(--radius-control)"
196
196
  doc().body.append(probe)
197
- const px = parseFloat(getComputedStyle(probe).borderTopLeftRadius)
197
+ const px = parseFloat(win().getComputedStyle(probe).borderTopLeftRadius)
198
198
  probe.remove()
199
199
  return Number.isFinite(px) ? px : 8
200
200
  }
@@ -241,7 +241,7 @@ function glideTo(el: Element | null) {
241
241
  target.value = el
242
242
  gliding.value = true
243
243
  clearTimeout(glide)
244
- glide = window.setTimeout(() => (gliding.value = false), durationToken("duration-medium") + 40)
244
+ glide = window.setTimeout(() => (gliding.value = false), durationToken("duration-medium", undefined, doc()) + 40)
245
245
  }
246
246
 
247
247
  function measure() {
@@ -367,12 +367,14 @@ function dismiss() {
367
367
 
368
368
  function onTargetClick(event: Event) {
369
369
  if (!step.value?.try || !target.value) return
370
- if (event.target instanceof Node && target.value.contains(event.target)) setTimeout(next, TRY_SETTLE_MS)
370
+ if (isElement(event.target) && target.value.contains(event.target)) setTimeout(next, TRY_SETTLE_MS)
371
371
  }
372
372
 
373
373
  watch(
374
374
  open,
375
375
  (value) => {
376
+ // The server has no page to walk, and this runs there on setup.
377
+ if (typeof document === "undefined") return
376
378
  if (value) {
377
379
  direction = 1
378
380
  box.value = null
@@ -25,6 +25,7 @@ export default { inheritAttrs: false }
25
25
  *
26
26
  * A truncated value becomes focusable, so the tip is reachable by keyboard too.
27
27
  */
28
+ import { nodeWindow } from "../composables/useView"
28
29
  import { computed, nextTick, onMounted, ref, watch } from "vue"
29
30
  import { useMergedAttrs } from "../composables/useMergedClass"
30
31
  import { useResizeObserver } from "../composables/useResizeObserver"
@@ -57,8 +58,8 @@ const drawn = ref(props.text)
57
58
 
58
59
  let canvas: CanvasRenderingContext2D | null = null
59
60
  function measurer(el: HTMLElement): (s: string) => number {
60
- canvas ??= document.createElement("canvas").getContext("2d")
61
- const style = getComputedStyle(el)
61
+ canvas ??= el.ownerDocument.createElement("canvas").getContext("2d")
62
+ const style = nodeWindow(el).getComputedStyle(el)
62
63
  // Built from the longhands: Firefox leaves the `font` shorthand empty in
63
64
  // computed styles.
64
65
  if (canvas) canvas.font = `${style.fontStyle} ${style.fontWeight} ${style.fontSize} ${style.fontFamily}`
@@ -86,7 +87,7 @@ useResizeObserver(box, () => measure())
86
87
  onMounted(() => {
87
88
  measure()
88
89
  // Web fonts land after mount and change every width.
89
- void document.fonts?.ready.then(() => measure())
90
+ void box.value?.ownerDocument.fonts?.ready.then(() => measure())
90
91
  })
91
92
  watch(
92
93
  () => [props.text, props.lines, props.middle, props.tail],
@@ -29,6 +29,7 @@ export default { inheritAttrs: false }
29
29
  * is on screen and pauses while it is off screen or the tab is hidden. Under
30
30
  * reduced motion whole strings appear and swap without typing.
31
31
  */
32
+ import { isElement } from "../composables/useView"
32
33
  import { computed, onBeforeUnmount, ref, watch } from "vue"
33
34
  import { prefersReducedMotion } from "../composables/easing"
34
35
  import { useInView } from "../composables/useInView"
@@ -95,7 +96,7 @@ const idle = computed(() => state.value.phase === "holding" || state.value.phase
95
96
  const { el: revealEl, revealed } = useReveal({ immediate: () => props.play !== undefined })
96
97
  const { el: viewEl, inView } = useInView()
97
98
  const setRoot = (node: unknown) => {
98
- const element = node instanceof Element ? node : null
99
+ const element = isElement(node) ? node : null
99
100
  revealEl.value = element
100
101
  viewEl.value = element
101
102
  }
@@ -32,8 +32,11 @@ export default { inheritAttrs: false }
32
32
  * loop decodes one stream. Both play the same `src`: a URL the media element
33
33
  * fetches by range, or an object URL of a file already in memory.
34
34
  */
35
+ import { clamp } from "../composables/clamp"
35
36
  import { computed, onBeforeUnmount, onMounted, ref, watch } from "vue"
36
37
  import { easeTravel, prefersReducedMotion } from "../composables/easing"
38
+ import { usePrefersReducedMotion } from "../composables/useReducedMotion"
39
+ import { useView } from "../composables/useView"
37
40
  import { useInView } from "../composables/useInView"
38
41
  import { useMergedAttrs } from "../composables/useMergedClass"
39
42
  import { isNativeLoop, planLoop, seamProgress, seamReached } from "./videoBackdrop"
@@ -101,7 +104,12 @@ const throttle = ref(1)
101
104
  */
102
105
  const SLOWEST_RATE = 1 / 16
103
106
 
104
- const reducedMotion = ref(prefersReducedMotion())
107
+ // Read now as well: the live query reports only after mount, and a first paint
108
+ // must not start a video the viewer asked not to see.
109
+ const view = useView()
110
+ const reducedMotion = ref(prefersReducedMotion(view.value?.window))
111
+ const liveMotion = usePrefersReducedMotion()
112
+ watch(liveMotion, (reduced) => (reducedMotion.value = reduced))
105
113
  /*
106
114
  * Unseen: the tab is hidden or the backdrop is off screen. A video decoding
107
115
  * frames under the fold spends as much as one in view, and a page of them
@@ -305,21 +313,11 @@ watch(
305
313
  },
306
314
  )
307
315
 
308
- function onMotionChange(event: MediaQueryListEvent) {
309
- reducedMotion.value = event.matches
310
- }
311
- let motionQuery: MediaQueryList | null = null
312
-
313
- onMounted(() => {
314
- applyRate()
315
- motionQuery = window.matchMedia("(prefers-reduced-motion: reduce)")
316
- motionQuery.addEventListener("change", onMotionChange)
317
- })
316
+ onMounted(applyRate)
318
317
 
319
318
  onBeforeUnmount(() => {
320
319
  if (frame) cancelAnimationFrame(frame)
321
320
  if (ramp) cancelAnimationFrame(ramp)
322
- motionQuery?.removeEventListener("change", onMotionChange)
323
321
  })
324
322
 
325
323
  function layerStyle(index: 0 | 1) {
@@ -380,7 +378,7 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
380
378
  </div>
381
379
  <div
382
380
  class="absolute inset-0 bg-black transition-opacity duration-[var(--duration-medium)] ease-[var(--ease-emphasized)] motion-reduce:transition-none"
383
- :style="{ opacity: Math.min(1, Math.max(0, dim)) }"
381
+ :style="{ opacity: clamp(dim, 0, 1) }"
384
382
  />
385
383
  </div>
386
384
  </template>
@@ -0,0 +1,373 @@
1
+ <script lang="ts">
2
+ export default { inheritAttrs: false }
3
+ </script>
4
+
5
+ <script setup lang="ts">
6
+ /*
7
+ * A floating panel over the page that the page keeps working under: a log
8
+ * tail beside a dashboard, a console, a reference next to a form. Move it by
9
+ * its title bar, resize it by its edges, drop it on a screen edge to dock it.
10
+ *
11
+ * <LpWindow v-model:open="logs" title="Logs" persist="logs">
12
+ * <LpLogViewer :lines="lines" />
13
+ * </LpWindow>
14
+ *
15
+ * Different from the neighbours on purpose:
16
+ * - LpModal and LpDrawer take the page away until they close; this does not:
17
+ * no scrim, no focus trap, and it stays out of the modal stack.
18
+ * - LpLayoutCanvas tiles blocks into a page; a window sits over one.
19
+ *
20
+ * Not a window manager: no minimising, no taskbar. Raising, docking and
21
+ * snapping are what it takes for a few panels to live together.
22
+ *
23
+ * Geometry is kept apart from what is applied. A window saved on a wide screen
24
+ * is fitted to a smaller one, and gets its own place back on the wide one.
25
+ *
26
+ * Keyboard: the title bar takes focus; arrows move, Shift+arrows resize, Enter
27
+ * fills the view, Escape anywhere in the window closes it.
28
+ */
29
+ import IconCloseButton from "./IconCloseButton.vue"
30
+ import { computed, nextTick, onBeforeUnmount, onMounted, ref, shallowRef, useId, watch } from "vue"
31
+ import { startPointerDrag } from "../composables/pointerDrag"
32
+ import { useCloseGuard, type CloseGuard } from "../composables/useCloseGuard"
33
+ import { useGlass } from "../composables/useGlass"
34
+ import { useLabels } from "../composables/useLpConfig"
35
+ import { useMergedAttrs } from "../composables/useMergedClass"
36
+ import { usePersisted } from "../composables/usePersisted"
37
+ import { usePrefersReducedMotion } from "../composables/useReducedMotion"
38
+ import { usePortalTarget, useView, viewWindow } from "../composables/useView"
39
+ import {
40
+ WINDOW_DOCKS,
41
+ clampRect,
42
+ dockAt,
43
+ dockedRect,
44
+ isWindowRect,
45
+ resizeRect,
46
+ snapRect,
47
+ useWindowLayer,
48
+ type WindowDock,
49
+ type WindowEdge,
50
+ type WindowRect,
51
+ type WindowViewport,
52
+ } from "../composables/windowing"
53
+ import { CLOSE_ICON } from "./dropdown"
54
+ import LpIcon from "./LpIcon.vue"
55
+
56
+ const DEFAULT_SIZE = { width: 420, height: 320 }
57
+ const KEY_STEP = 16
58
+ const SNAP_THRESHOLD = 8
59
+ /** How near a screen edge the pointer must come to offer a dock. */
60
+ const DOCK_EDGE = 12
61
+ const EDGES: WindowEdge[] = ["n", "s", "e", "w", "ne", "nw", "se", "sw"]
62
+ const EDGE_CLASS: Record<WindowEdge, string> = {
63
+ n: "inset-x-2 -top-1 h-2 cursor-ns-resize",
64
+ s: "inset-x-2 -bottom-1 h-2 cursor-ns-resize",
65
+ e: "inset-y-2 -right-1 w-2 cursor-ew-resize",
66
+ w: "inset-y-2 -left-1 w-2 cursor-ew-resize",
67
+ ne: "-right-1 -top-1 size-3 cursor-nesw-resize",
68
+ nw: "-left-1 -top-1 size-3 cursor-nwse-resize",
69
+ se: "-bottom-1 -right-1 size-3 cursor-nwse-resize",
70
+ sw: "-bottom-1 -left-1 size-3 cursor-nesw-resize",
71
+ }
72
+
73
+ const props = withDefaults(
74
+ defineProps<{
75
+ title?: string
76
+ /** Accessible name for a window without a visible `title`. */
77
+ ariaLabel?: string
78
+ /** Where it first opens, and at what size. Centred when unset. */
79
+ defaultRect?: Partial<WindowRect>
80
+ minWidth?: number
81
+ minHeight?: number
82
+ /** Share of the view (0–1) a docked side takes. */
83
+ dockFraction?: number
84
+ resizable?: boolean
85
+ /** Offer docking when dragged to a screen edge. */
86
+ dockable?: boolean
87
+ /** Pull toward the view's edges and other windows while moving. */
88
+ snap?: boolean
89
+ closable?: boolean
90
+ /** Remember place, size and dock under this key, across visits (see `usePersisted`). */
91
+ persist?: string
92
+ /** Something would be lost by closing: `true` asks first, a function asks the app. */
93
+ guard?: CloseGuard
94
+ /** Frosted glass instead of a solid panel. Unset follows `provideGlass`. */
95
+ glass?: boolean
96
+ labels?: Partial<{ close: string; move: string }>
97
+ }>(),
98
+ {
99
+ minWidth: 240,
100
+ minHeight: 160,
101
+ dockFraction: 0.5,
102
+ resizable: true,
103
+ dockable: true,
104
+ snap: true,
105
+ closable: true,
106
+ glass: undefined,
107
+ },
108
+ )
109
+
110
+ const open = defineModel<boolean>("open", { default: false })
111
+ const emit = defineEmits<{
112
+ /** After a move, resize or dock ends: where the window now stands. */
113
+ (e: "change", value: { rect: WindowRect; dock: WindowDock | null }): void
114
+ }>()
115
+
116
+ const text = useLabels("window", { close: "Close", move: "Move window" }, () => props.labels)
117
+ const frosted = useGlass(() => props.glass)
118
+ const portalTo = usePortalTarget()
119
+ const view = useView()
120
+ const titleId = useId()
121
+
122
+ interface Placement {
123
+ rect: WindowRect | null
124
+ dock: WindowDock | null
125
+ }
126
+ const validPlacement = (value: unknown): value is Placement => {
127
+ const saved = value as Placement | null
128
+ return (
129
+ !!saved &&
130
+ (saved.rect === null || isWindowRect(saved.rect)) &&
131
+ (saved.dock === null || WINDOW_DOCKS.includes(saved.dock))
132
+ )
133
+ }
134
+ const placement = usePersisted<Placement>(() => props.persist && `lp-window:${props.persist}`, { rect: null, dock: null }, {
135
+ validate: validPlacement,
136
+ })
137
+
138
+ const viewport = shallowRef<WindowViewport>({ width: 0, height: 0 })
139
+ const bounds = computed(() => ({ minWidth: props.minWidth, minHeight: props.minHeight }))
140
+
141
+ function firstRect(): WindowRect {
142
+ const width = props.defaultRect?.width ?? DEFAULT_SIZE.width
143
+ const height = props.defaultRect?.height ?? DEFAULT_SIZE.height
144
+ return {
145
+ x: props.defaultRect?.x ?? Math.round((viewport.value.width - width) / 2),
146
+ y: props.defaultRect?.y ?? Math.round((viewport.value.height - height) / 2),
147
+ width,
148
+ height,
149
+ }
150
+ }
151
+
152
+ /* What is drawn; `placement` keeps what was asked for. */
153
+ const applied = computed<WindowRect>(() => {
154
+ const { rect, dock } = placement.value
155
+ if (dock) return dockedRect(dock, viewport.value, props.dockFraction)
156
+ return clampRect(rect ?? firstRect(), viewport.value, bounds.value)
157
+ })
158
+
159
+ const layer = useWindowLayer(() => (open.value ? applied.value : null))
160
+ const panel = ref<HTMLElement | null>(null)
161
+ const moving = ref(false)
162
+ const offeredDock = ref<WindowDock | null>(null)
163
+ const ghost = computed(() => (offeredDock.value ? dockedRect(offeredDock.value, viewport.value, props.dockFraction) : null))
164
+
165
+ function measure() {
166
+ const win = viewWindow(view.value)
167
+ viewport.value = { width: win.innerWidth, height: win.innerHeight }
168
+ }
169
+
170
+ // Teleported on the client only: the server has no view to place it in.
171
+ const mounted = ref(false)
172
+ onMounted(() => (mounted.value = true))
173
+
174
+ function commit() {
175
+ emit("change", { rect: applied.value, dock: placement.value.dock })
176
+ }
177
+
178
+ let stopDrag: (() => void) | null = null
179
+
180
+ function onTitlePointerDown(event: PointerEvent) {
181
+ if (event.button !== 0 || (event.target as Element).closest?.("button, a, input")) return
182
+ layer.raise()
183
+ const startX = event.clientX
184
+ const startY = event.clientY
185
+ const { dock } = placement.value
186
+ // Leaving a dock restores the window's own size, under the pointer.
187
+ const start = dock ? { ...(placement.value.rect ?? firstRect()), x: startX - KEY_STEP, y: startY - KEY_STEP } : applied.value
188
+ let dragged = false
189
+ moving.value = true
190
+ stopDrag = startPointerDrag(event, {
191
+ move: (ev) => {
192
+ dragged = true
193
+ const moved = { ...start, x: start.x + ev.clientX - startX, y: start.y + ev.clientY - startY }
194
+ const snapped = props.snap ? snapRect(moved, viewport.value, layer.others(), SNAP_THRESHOLD) : moved
195
+ placement.value = { rect: clampRect(snapped, viewport.value, bounds.value), dock: null }
196
+ offeredDock.value = props.dockable ? dockAt(ev.clientX, ev.clientY, viewport.value, DOCK_EDGE) : null
197
+ },
198
+ end: (completed) => {
199
+ moving.value = false
200
+ stopDrag = null
201
+ const chosen = offeredDock.value
202
+ offeredDock.value = null
203
+ if (completed && chosen) placement.value = { rect: placement.value.rect, dock: chosen }
204
+ if (dragged) commit()
205
+ },
206
+ })
207
+ }
208
+
209
+ function onEdgePointerDown(event: PointerEvent, edge: WindowEdge) {
210
+ if (event.button !== 0) return
211
+ layer.raise()
212
+ const start = applied.value
213
+ const startX = event.clientX
214
+ const startY = event.clientY
215
+ moving.value = true
216
+ stopDrag = startPointerDrag(event, {
217
+ move: (ev) => {
218
+ const rect = resizeRect(start, edge, ev.clientX - startX, ev.clientY - startY, viewport.value, bounds.value)
219
+ placement.value = { rect, dock: null }
220
+ },
221
+ end: () => {
222
+ moving.value = false
223
+ stopDrag = null
224
+ commit()
225
+ },
226
+ })
227
+ }
228
+
229
+ function toggleFull() {
230
+ if (!props.dockable) return
231
+ placement.value = { rect: placement.value.rect ?? applied.value, dock: placement.value.dock === "full" ? null : "full" }
232
+ commit()
233
+ }
234
+
235
+ function onTitleKeydown(event: KeyboardEvent) {
236
+ if (event.target !== event.currentTarget) return
237
+ if (event.key === "Enter") {
238
+ event.preventDefault()
239
+ toggleFull()
240
+ return
241
+ }
242
+ const dx = event.key === "ArrowRight" ? KEY_STEP : event.key === "ArrowLeft" ? -KEY_STEP : 0
243
+ const dy = event.key === "ArrowDown" ? KEY_STEP : event.key === "ArrowUp" ? -KEY_STEP : 0
244
+ if (!dx && !dy) return
245
+ event.preventDefault()
246
+ const rect = applied.value
247
+ const next = event.shiftKey && props.resizable
248
+ ? resizeRect(rect, "se", dx, dy, viewport.value, bounds.value)
249
+ : { ...rect, x: rect.x + dx, y: rect.y + dy }
250
+ placement.value = { rect: clampRect(next, viewport.value, bounds.value), dock: null }
251
+ commit()
252
+ }
253
+
254
+ const { allowClose } = useCloseGuard(() => props.guard, () => open.value)
255
+
256
+ async function close() {
257
+ if (await allowClose()) open.value = false
258
+ }
259
+
260
+ function onKeydown(event: KeyboardEvent) {
261
+ if (event.key !== "Escape" || !props.closable || event.defaultPrevented) return
262
+ event.preventDefault()
263
+ void close()
264
+ }
265
+
266
+ defineExpose({ close, raise: () => layer.raise() })
267
+
268
+ let returnTo: HTMLElement | null = null
269
+
270
+ watch(
271
+ [open, mounted],
272
+ async ([isOpen, ready], _, onCleanup) => {
273
+ if (!ready) return
274
+ if (!isOpen) {
275
+ stopDrag?.()
276
+ layer.release()
277
+ returnTo?.focus?.({ preventScroll: true })
278
+ returnTo = null
279
+ return
280
+ }
281
+ const win = viewWindow(view.value)
282
+ measure()
283
+ win.addEventListener("resize", measure)
284
+ onCleanup(() => win.removeEventListener("resize", measure))
285
+ layer.raise()
286
+ returnTo = win.document.activeElement as HTMLElement | null
287
+ await nextTick()
288
+ panel.value?.focus({ preventScroll: true })
289
+ },
290
+ { immediate: true },
291
+ )
292
+
293
+ onBeforeUnmount(() => {
294
+ stopDrag?.()
295
+ layer.release()
296
+ })
297
+
298
+ const reduced = usePrefersReducedMotion()
299
+ const animate = computed(() => !moving.value && !reduced.value)
300
+ const { class: panelClass, attrs: rest } = useMergedAttrs(() =>
301
+ [
302
+ "fixed flex min-h-0 min-w-0 flex-col rounded-card border border-line shadow-panel outline-none",
303
+ frosted.value ? "lp-glass-overlay" : "bg-surface-raised",
304
+ placement.value.dock === "full" ? "rounded-none" : "",
305
+ ].join(" "),
306
+ )
307
+
308
+ const px = (rect: WindowRect) => ({
309
+ left: `${rect.x}px`,
310
+ top: `${rect.y}px`,
311
+ width: `${rect.width}px`,
312
+ height: `${rect.height}px`,
313
+ })
314
+ </script>
315
+
316
+ <template>
317
+ <Teleport v-if="mounted && open" :to="portalTo">
318
+ <div
319
+ v-if="ghost"
320
+ data-lp-window-ghost
321
+ class="pointer-events-none fixed rounded-card border-2 border-brand bg-brand/10"
322
+ :style="{ ...px(ghost), zIndex: layer.z.value }"
323
+ />
324
+ <section
325
+ v-bind="rest"
326
+ ref="panel"
327
+ role="dialog"
328
+ aria-modal="false"
329
+ :aria-label="title ? undefined : ariaLabel"
330
+ :aria-labelledby="title ? titleId : undefined"
331
+ tabindex="-1"
332
+ :class="panelClass"
333
+ :data-dock="placement.dock ?? undefined"
334
+ :style="{
335
+ ...px(applied),
336
+ zIndex: layer.z.value,
337
+ transition: animate ? 'left var(--duration-fast), top var(--duration-fast), width var(--duration-fast), height var(--duration-fast)' : 'none',
338
+ }"
339
+ @pointerdown.capture="layer.raise()"
340
+ @focusin="layer.raise()"
341
+ @keydown="onKeydown"
342
+ >
343
+ <header
344
+ tabindex="0"
345
+ :aria-label="`${text.move}: ${title ?? ariaLabel ?? ''}`"
346
+ class="flex shrink-0 cursor-move touch-none select-none items-center gap-2 rounded-t-card px-3 py-2 outline-none focus-visible:ring-2 focus-visible:ring-ring"
347
+ @pointerdown="onTitlePointerDown"
348
+ @dblclick="toggleFull"
349
+ @keydown="onTitleKeydown"
350
+ >
351
+ <span :id="titleId" class="min-w-0 flex-1 truncate text-sm font-semibold text-ink">
352
+ <slot name="title">{{ title }}</slot>
353
+ </span>
354
+ <slot name="actions" />
355
+ <IconCloseButton v-if="closable" :label="text.close" @click="close" />
356
+ </header>
357
+ <div class="min-h-0 min-w-0 flex-1 overflow-auto">
358
+ <slot :close="close" />
359
+ </div>
360
+ <template v-if="resizable">
361
+ <div
362
+ v-for="edge in EDGES"
363
+ :key="edge"
364
+ aria-hidden="true"
365
+ :data-lp-window-edge="edge"
366
+ class="absolute touch-none"
367
+ :class="EDGE_CLASS[edge]"
368
+ @pointerdown="onEdgePointerDown($event, edge)"
369
+ />
370
+ </template>
371
+ </section>
372
+ </Teleport>
373
+ </template>
@@ -0,0 +1,116 @@
1
+ <script setup lang="ts">
2
+ /*
3
+ * The menu for useWorkspaces: which layout is showing, the others, and making,
4
+ * copying, renaming and deleting them.
5
+ *
6
+ * const spaces = useWorkspaces({ initial: ["logs", "chart"], persist: "main" })
7
+ * <LpWorkspaceSwitcher :workspaces="spaces" />
8
+ * <LayoutCanvas v-model="spaces.controller.layout.value" :blocks="blocks" />
9
+ *
10
+ * Only the menu: an app with its own place for this (the palette, a settings
11
+ * page) calls useWorkspaces directly and leaves this out.
12
+ */
13
+ import { computed, nextTick, ref } from "vue"
14
+ import { useLabels } from "../composables/useLpConfig"
15
+ import type { UseWorkspaces } from "../layout/useWorkspaces"
16
+ import LpButton from "./LpButton.vue"
17
+ import LpDropdownMenu, { type MenuItem } from "./LpDropdownMenu.vue"
18
+ import LpInput from "./LpInput.vue"
19
+ import LpModal from "./LpModal.vue"
20
+
21
+ const props = defineProps<{
22
+ workspaces: UseWorkspaces
23
+ labels?: Partial<{
24
+ menu: string
25
+ create: string
26
+ duplicate: string
27
+ rename: string
28
+ remove: string
29
+ name: string
30
+ save: string
31
+ cancel: string
32
+ required: string
33
+ }>
34
+ }>()
35
+
36
+ const text = useLabels(
37
+ "workspaces",
38
+ {
39
+ menu: "Workspaces",
40
+ create: "New workspace",
41
+ duplicate: "Duplicate",
42
+ rename: "Rename",
43
+ remove: "Delete",
44
+ name: "Name",
45
+ save: "Save",
46
+ cancel: "Cancel",
47
+ required: "Enter a name",
48
+ },
49
+ () => props.labels,
50
+ )
51
+
52
+ const activeName = computed(() => {
53
+ const { workspaces, activeId } = props.workspaces
54
+ return workspaces.value.find((space) => space.id === activeId.value)?.name ?? ""
55
+ })
56
+
57
+ const naming = ref<"create" | "rename" | null>(null)
58
+ const draft = ref("")
59
+ const tried = ref(false)
60
+ const nameError = computed(() => (tried.value && !draft.value.trim() ? text.value.required : undefined))
61
+
62
+ async function ask(mode: "create" | "rename") {
63
+ // After the menu has let go of focus, so the dialog's own focus is the one that stays.
64
+ await nextTick()
65
+ draft.value = mode === "rename" ? activeName.value : ""
66
+ tried.value = false
67
+ naming.value = mode
68
+ }
69
+
70
+ function confirm() {
71
+ tried.value = true
72
+ const name = draft.value.trim()
73
+ if (!name) return
74
+ if (naming.value === "create") props.workspaces.create(name)
75
+ else props.workspaces.rename(props.workspaces.activeId.value, name)
76
+ naming.value = null
77
+ }
78
+
79
+ const items = computed<MenuItem[]>(() => {
80
+ const spaces = props.workspaces
81
+ return [
82
+ ...spaces.workspaces.value.map((space) => ({
83
+ label: space.name,
84
+ icon: space.id === spaces.activeId.value ? "lucide:check" : undefined,
85
+ onSelect: () => spaces.switchTo(space.id),
86
+ })),
87
+ { label: text.value.create, icon: "lucide:plus", separatorBefore: true, onSelect: () => void ask("create") },
88
+ { label: text.value.duplicate, icon: "lucide:copy", onSelect: () => void spaces.duplicate() },
89
+ { label: text.value.rename, icon: "lucide:pencil", onSelect: () => void ask("rename") },
90
+ {
91
+ label: text.value.remove,
92
+ icon: "lucide:trash-2",
93
+ danger: true,
94
+ disabled: spaces.workspaces.value.length <= 1,
95
+ onSelect: () => spaces.remove(spaces.activeId.value),
96
+ },
97
+ ]
98
+ })
99
+ </script>
100
+
101
+ <template>
102
+ <LpDropdownMenu :items="items" :palette="false">
103
+ <template #trigger>
104
+ <LpButton variant="ghost" size="sm" :aria-label="`${text.menu}: ${activeName}`">{{ activeName }}</LpButton>
105
+ </template>
106
+ </LpDropdownMenu>
107
+ <LpModal :open="naming !== null" :title="naming === 'create' ? text.create : text.rename" size="sm" @update:open="naming = null">
108
+ <form id="lp-workspace-name" @submit.prevent="confirm">
109
+ <LpInput v-model="draft" :label="text.name" :error="nameError" />
110
+ </form>
111
+ <template #footer>
112
+ <LpButton variant="ghost" @click="naming = null">{{ text.cancel }}</LpButton>
113
+ <LpButton type="submit" form="lp-workspace-name">{{ text.save }}</LpButton>
114
+ </template>
115
+ </LpModal>
116
+ </template>
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import { useAttrs } from "vue"
3
- import { useFieldBlur, type useFieldControl } from "../composables/useField"
3
+ import { mergeDescribedBy, useFieldBlur, type useFieldControl } from "../composables/useField"
4
4
  import { mergeClass } from "../composables/useMergedClass"
5
5
  import { PICKER_CLEAR, PICKER_PRESET, PICKER_PRESETS, PICKER_SIZE, PICKER_TRIGGER, pickerTone } from "./calendar"
6
6
  import LpIcon from "./LpIcon.vue"
@@ -36,7 +36,7 @@ const attrs = useAttrs()
36
36
  type="button"
37
37
  :disabled="field.disabled"
38
38
  :aria-invalid="field.invalid || undefined"
39
- :aria-describedby="field.describedBy"
39
+ :aria-describedby="mergeDescribedBy(attrs['aria-describedby'], field.describedBy)"
40
40
  :class="[PICKER_TRIGGER, PICKER_SIZE[size], pickerTone(field.invalid)]"
41
41
  >
42
42
  <LpIcon :name="icon" :size="16" class="shrink-0 text-muted" />
@@ -0,0 +1,10 @@
1
+ <script setup lang="ts">
2
+ /* The track of a slider and the filled part of it, one thumb or two. */
3
+ import { SliderRange, SliderTrack } from "reka-ui"
4
+ </script>
5
+
6
+ <template>
7
+ <SliderTrack class="relative h-1.5 grow overflow-hidden rounded-pill bg-surface-soft">
8
+ <SliderRange class="absolute h-full rounded-pill bg-brand" />
9
+ </SliderTrack>
10
+ </template>
@@ -1,3 +1,5 @@
1
+ import { clamp } from "../composables/clamp"
2
+
1
3
  /*
2
4
  * Postal-address types, tile maths and the pluggable geocoder behind
3
5
  * LpAddressInput / LpMapPicker.
@@ -232,7 +234,7 @@ export const MAX_LATITUDE = 85.05112878
232
234
 
233
235
  export function project(lat: number, lon: number, zoom: number, tileSize = 256) {
234
236
  const size = tileSize * 2 ** zoom
235
- const clamped = Math.max(-MAX_LATITUDE, Math.min(MAX_LATITUDE, lat))
237
+ const clamped = clamp(lat, -MAX_LATITUDE, MAX_LATITUDE)
236
238
  const sin = Math.sin((clamped * Math.PI) / 180)
237
239
  return {
238
240
  x: ((lon + 180) / 360) * size,