@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,10 +16,15 @@ export default { inheritAttrs: false }
16
16
  * every series at that index at once, so comparing series is one hover, not one
17
17
  * hover per line.
18
18
  */
19
+ import { clamp } from "../composables/clamp"
19
20
  import { Motion } from "motion-v"
20
- import { computed, ref, shallowRef, watch, onMounted } from "vue"
21
+ import { computed, nextTick, ref, shallowRef, useId, watch, onMounted } from "vue"
22
+ import { useChartSync } from "../composables/useChartSync"
21
23
  import { useLabels } from "../composables/useLpConfig"
22
- import { easeTravel, prefersReducedMotion } from "../composables/easing"
24
+ import { easeTravel } from "../composables/easing"
25
+ import { usePrefersReducedMotion } from "../composables/useReducedMotion"
26
+ import { startPointerDrag } from "../composables/pointerDrag"
27
+ import { nodeWindow } from "../composables/useView"
23
28
  import { usePillTransition } from "../composables/usePillTransition"
24
29
  import { useReveal } from "../composables/useReveal"
25
30
  import { lerp, mixValues, resample, useTween } from "../composables/useTween"
@@ -44,10 +49,23 @@ import {
44
49
  xLabelIndices,
45
50
  yAt,
46
51
  type Box,
52
+ type ChartAnnotation,
53
+ type ChartBand,
47
54
  type ChartMarker,
48
55
  type ChartSeries,
49
56
  type ChartThreshold,
50
57
  } from "./chart"
58
+ import ChartRangeSelector from "./ChartRangeSelector.vue"
59
+ import {
60
+ ZOOM_STEP,
61
+ chartView,
62
+ clampRange,
63
+ slotOf,
64
+ sourceOf,
65
+ zoomRange,
66
+ type ChartDownsample,
67
+ type ChartRange,
68
+ } from "./chartWindow"
51
69
  import { PANEL_SURFACE } from "./dropdown"
52
70
  import LegendSwatch from "./LegendSwatch.vue"
53
71
  import LpContextMenu, { type ContextMenuItemDef } from "./LpContextMenu.vue"
@@ -72,6 +90,12 @@ export interface ChartText {
72
90
  point: string
73
91
  /** Header of the label column in a CSV export. */
74
92
  xColumn: string
93
+ /** Name of the overview's left edge, for assistive tech. */
94
+ rangeStart: string
95
+ /** Name of the overview's right edge. */
96
+ rangeEnd: string
97
+ /** The button that shows the whole series again. */
98
+ resetZoom: string
75
99
  }
76
100
 
77
101
  export interface ChartExportOptions {
@@ -151,6 +175,36 @@ const props = withDefaults(
151
175
  thresholds?: ChartThreshold[]
152
176
  /** Vertical markers at x positions (deploys, incidents). */
153
177
  markers?: ChartMarker[]
178
+ /** Stretches of the x axis, drawn under the data (maintenance, incidents). */
179
+ bands?: ChartBand[]
180
+ /** Notes pinned to single readings. */
181
+ annotations?: ChartAnnotation[]
182
+ /**
183
+ * The window of the data on show, by point index (`v-model:range`). Unset
184
+ * and null are the whole series. Exports and `dataTable` always hold all of it.
185
+ */
186
+ range?: ChartRange | null
187
+ /** The overview under the plot, for moving and resizing the window. */
188
+ rangeSelector?: boolean
189
+ /**
190
+ * Zoom on the plot: drag across it, Ctrl+wheel or pinch, the + and - keys.
191
+ * Double click, 0 or the reset button show the whole series.
192
+ */
193
+ zoomable?: boolean
194
+ /**
195
+ * Thin a series longer than the plot is wide, for line and area charts.
196
+ * `minmax` keeps each bucket's extremes, so a one-point spike survives;
197
+ * `lttb` keeps the shape of a smooth curve and can lose one. Off by default.
198
+ * Curves are drawn straight while thinned: `smooth` would overshoot.
199
+ */
200
+ downsample?: ChartDownsample | false
201
+ /** Points to thin to. Defaults to one a pixel of the chart's width. */
202
+ maxPoints?: number
203
+ /**
204
+ * Charts of one group mark the same x label on hover. Matched by label, so
205
+ * they may hold different windows of the same timeline.
206
+ */
207
+ syncGroup?: string
154
208
  /** Accessible name for the plot. Defaults to a generated summary. */
155
209
  ariaLabel?: string
156
210
  /** Render the data as a visually hidden table for screen readers. */
@@ -178,6 +232,9 @@ const props = withDefaults(
178
232
  animate: true,
179
233
  thresholds: () => [],
180
234
  markers: () => [],
235
+ bands: () => [],
236
+ annotations: () => [],
237
+ range: undefined,
181
238
  dataTable: false,
182
239
  sample: true,
183
240
  },
@@ -185,7 +242,16 @@ const props = withDefaults(
185
242
 
186
243
  const strings = useLabels<ChartText>(
187
244
  "chart",
188
- { empty: "No data", loading: "Loading", rightAxis: "Measured on the right axis", point: "Point", xColumn: "Label" },
245
+ {
246
+ empty: "No data",
247
+ loading: "Loading",
248
+ rightAxis: "Measured on the right axis",
249
+ point: "Point",
250
+ xColumn: "Label",
251
+ rangeStart: "Start of the range",
252
+ rangeEnd: "End of the range",
253
+ resetZoom: "Show all",
254
+ },
189
255
  () => props.text,
190
256
  )
191
257
 
@@ -194,6 +260,8 @@ const emit = defineEmits<{
194
260
  (e: "pointClick", payload: ChartPointEvent): void
195
261
  /** Right-click on a point/bar, fired before `menuItems` is consulted. */
196
262
  (e: "pointContextMenu", payload: ChartPointEvent): void
263
+ /** The window moved; null is the whole series. */
264
+ (e: "update:range", range: ChartRange | null): void
197
265
  }>()
198
266
 
199
267
  // ── size ───────────────────────────────────────
@@ -211,7 +279,7 @@ const width = ref(0)
211
279
  */
212
280
  const { el: revealAnchor, revealed } = useReveal({ immediate: () => !props.animate })
213
281
  // SMIL ignores the reduced-motion media query, so the wipe is skipped here.
214
- const reduced = ref(false)
282
+ const reduced = usePrefersReducedMotion()
215
283
  const still = computed(() => !props.animate || reduced.value)
216
284
  const drawing = computed(() => !still.value && revealed.value)
217
285
 
@@ -219,7 +287,6 @@ onMounted(() => {
219
287
  // One element, two observers: hand the composable the same node rather than
220
288
  // wrapping the chart in a spare div just to carry a second ref.
221
289
  revealAnchor.value = root.value
222
- reduced.value = prefersReducedMotion()
223
290
  })
224
291
  useResizeObserver(root, (entry, el) => (width.value = entry ? entry.contentRect.width : el.clientWidth), {
225
292
  immediate: true,
@@ -233,7 +300,7 @@ const toggleSeries = (id: string) => {
233
300
  if (next.has(id)) next.delete(id)
234
301
  else next.add(id)
235
302
  // Never hide the last visible series — an empty plot reads as broken.
236
- if (next.size < source.value.length) hidden.value = next
303
+ if (allSeries.value.some((s) => !next.has(s.id))) hidden.value = next
237
304
  }
238
305
 
239
306
  const SAMPLE_POINTS = 12
@@ -251,24 +318,78 @@ const source = computed<ChartSeries[]>(() => {
251
318
  })
252
319
 
253
320
  // Identity is position plus name, so two series sharing a name stay separate.
254
- const allSeries = computed(() =>
321
+ const fullSeries = computed(() =>
255
322
  normalise(source.value).map((s, i) => ({ ...s, id: `${i}:${s.name}` })),
256
323
  )
324
+ const fullCount = computed(() => pointCount(fullSeries.value))
325
+ const fullLabels = computed(() => resolveLabels(source.value, props.labels, fullCount.value))
326
+
327
+ /*
328
+ * The window and the thinning sit between the data and everything drawn. Past
329
+ * this point a mark's index is a slot of `view`; `sourceOf` and `slotOf` cross
330
+ * back to the data. Slots follow the chart's own width and not the plot's: the
331
+ * plot's gutters come from the scale, which comes from these very values.
332
+ */
333
+ const ownRange = shallowRef<ChartRange | null>(null)
334
+ const range = computed(() => clampRange(props.range === undefined ? ownRange.value : props.range, fullCount.value))
335
+
336
+ const view = computed(() =>
337
+ chartView(
338
+ fullSeries.value.map((s) => s.values),
339
+ fullCount.value,
340
+ range.value,
341
+ props.type === "bar" ? false : props.downsample,
342
+ props.maxPoints ?? Math.floor(width.value),
343
+ ),
344
+ )
345
+ const narrowed = computed(() => range.value !== null || view.value.indices !== null)
346
+
347
+ /* What the chart works from: the same objects as the data when nothing narrows it. */
348
+ const allSeries = computed(() =>
349
+ narrowed.value ? fullSeries.value.map((s, i) => ({ ...s, values: view.value.values[i] })) : fullSeries.value,
350
+ )
351
+
352
+ function setRange(next: ChartRange | null) {
353
+ ownRange.value = next
354
+ emit("update:range", next)
355
+ }
356
+
357
+ /*
358
+ * A zoom follows the hand, so it lands at once: easing would slide the curve
359
+ * under the pointer. The flag only has to cover the watchers of this flush.
360
+ */
361
+ let rangeMoving = false
362
+ watch(
363
+ () => `${range.value?.start}:${range.value?.end}`,
364
+ () => {
365
+ rangeMoving = true
366
+ void nextTick(() => (rangeMoving = false))
367
+ },
368
+ { flush: "sync" },
369
+ )
257
370
  const visible = computed(() => allSeries.value.filter((s) => !hidden.value.has(s.id)))
258
371
 
259
372
  // A series asked to start hidden is hidden once, when it first appears: the
260
373
  // legend owns it from then on, and a data refresh must not switch it back off.
374
+ // That state lives as long as the series does: one that goes away takes it
375
+ // along, so a new series in its place starts from its own `hidden`. An empty
376
+ // list is data still on its way, not every series removed.
261
377
  const seeded = new Set<string>()
262
378
  watch(
263
379
  () => props.series.map((s, i) => [`${i}:${s.name}`, !!s.hidden] as const),
264
380
  (entries) => {
265
- let next: Set<string> | null = null
381
+ if (!entries.length) return
382
+ const ids = new Set<string>(entries.map(([id]) => id))
383
+ for (const id of seeded) if (!ids.has(id)) seeded.delete(id)
384
+ const kept = [...hidden.value].filter((id) => ids.has(id))
385
+ const next = new Set(kept)
266
386
  for (const [id, off] of entries) {
267
387
  if (seeded.has(id)) continue
268
388
  seeded.add(id)
269
- if (off) (next ??= new Set(hidden.value)).add(id)
389
+ if (off) next.add(id)
270
390
  }
271
- if (next && next.size < entries.length) hidden.value = next
391
+ const allowed = next.size < entries.length ? next : new Set(kept)
392
+ if (allowed.size !== hidden.value.size || [...allowed].some((id) => !hidden.value.has(id))) hidden.value = allowed
272
393
  },
273
394
  { immediate: true },
274
395
  )
@@ -302,7 +423,7 @@ const SETTLE_MS = 260
302
423
  const settle = {
303
424
  duration: SETTLE_MS,
304
425
  ease: easeTravel,
305
- enabled: () => props.animate,
426
+ enabled: () => props.animate && !rangeMoving,
306
427
  }
307
428
 
308
429
  /*
@@ -386,7 +507,7 @@ const drawnSeries = useTween(() => targetDrawn.value, mixDrawn, {
386
507
  * itself in on its own entrance — a morph from readings nobody saw would
387
508
  * only muddy it.
388
509
  */
389
- enabled: () => props.animate && revealed.value && !!svgEl.value,
510
+ enabled: () => props.animate && !rangeMoving && revealed.value && !!svgEl.value,
390
511
  })
391
512
 
392
513
  /** The drawn copy of each current series, by id, for marks built from `visible`. */
@@ -397,11 +518,16 @@ const drawnById = computed(() => {
397
518
  })
398
519
 
399
520
  const count = computed(() => pointCount(allSeries.value))
400
- const labels = computed(() => resolveLabels(source.value, props.labels, count.value))
521
+ const labels = computed(() =>
522
+ narrowed.value
523
+ ? Array.from({ length: count.value }, (_, slot) => fullLabels.value[sourceOf(view.value, slot)] ?? "")
524
+ : fullLabels.value,
525
+ )
401
526
  const banded = computed(() => props.type === "bar")
402
527
 
528
+ // The whole data, not the window: a gap zoomed into is a gap, not an empty chart.
403
529
  const hasData = computed(() =>
404
- allSeries.value.some((s) => s.values.some((v) => v != null)),
530
+ fullSeries.value.some((s) => s.values.some((v) => v != null)),
405
531
  )
406
532
 
407
533
  /* Data to interact with: present, and not about to be replaced by the load in
@@ -692,7 +818,7 @@ const xLabels = computed(() =>
692
818
  // ── marks ──────────────────────────────────────
693
819
  const baseY = computed(() =>
694
820
  yAt(
695
- Math.max(scale.value.min, Math.min(scale.value.max, 0)),
821
+ clamp(0, scale.value.min, scale.value.max),
696
822
  scale.value.min,
697
823
  scale.value.max,
698
824
  box.value,
@@ -707,19 +833,21 @@ const baseY = computed(() =>
707
833
  * it falls out of the plot while the remaining series keep their place, which is
708
834
  * what "stop showing this one" should look like.
709
835
  */
836
+ const curve = computed(() => (view.value.indices ? 0 : props.smooth))
837
+
710
838
  const lines = computed(() =>
711
839
  drawnSeries.value.map((s) => {
712
840
  const g = geoOf(s)
713
841
  // A series leaving the data collapses exactly as one being hidden does.
714
842
  const p = presenceOf(s.id) * s.enter
715
843
  // Values pulled toward the axis floor, so the curve flattens into it.
716
- const base = Math.min(Math.max(0, g.min), g.max)
844
+ const base = clamp(0, g.min, g.max)
717
845
  const values = p === 1 ? s.values : s.values.map((v) => (v == null ? null : base + (v - base) * p))
718
846
  return {
719
847
  ...s,
720
848
  values,
721
- d: linePath(values, g, props.smooth),
722
- fill: props.type === "area" ? areaPath(values, g, props.smooth) : "",
849
+ d: linePath(values, g, curve.value),
850
+ fill: props.type === "area" ? areaPath(values, g, curve.value) : "",
723
851
  /* A dashed series is a reference level (a budget, a target), not a
724
852
  measurement — dotting it implies readings that aren't there. */
725
853
  points: props.showPoints && !s.dashed,
@@ -782,7 +910,7 @@ const bars = computed(() => {
782
910
  } else {
783
911
  const sc = scaleOf(s)
784
912
  const top = yAt(v, sc.min, sc.max, box.value)
785
- const base = yAt(Math.max(sc.min, Math.min(sc.max, 0)), sc.min, sc.max, box.value)
913
+ const base = yAt(clamp(0, sc.min, sc.max), sc.min, sc.max, box.value)
786
914
  y = Math.min(top, base)
787
915
  h = Math.abs(top - base)
788
916
  }
@@ -837,6 +965,42 @@ const bars = computed(() => {
837
965
  const active = ref(-1)
838
966
  const pointer = ref({ x: 0, y: 0 })
839
967
 
968
+ /* The hover of another chart in the group, as a slot of this one. */
969
+ const { peerLabel, publish } = useChartSync(() => props.syncGroup)
970
+ const labelIndex = computed(() => (props.syncGroup ? new Map(fullLabels.value.map((label, i) => [label, i])) : null))
971
+ const peerSlot = computed(() => {
972
+ const source = peerLabel.value == null ? undefined : labelIndex.value?.get(peerLabel.value)
973
+ return source === undefined ? -1 : slotOf(view.value, source)
974
+ })
975
+ const crosshair = computed(() => (active.value >= 0 ? active.value : peerSlot.value))
976
+ watch(active, (slot) => publish(slot >= 0 ? (labels.value[slot] ?? null) : null))
977
+
978
+ /* Past this many px a press on the plot is a selection, not a click. */
979
+ const SELECT_SLOP = 4
980
+ let swallowClick = false
981
+ const selection = ref<{ from: number; to: number } | null>(null)
982
+
983
+ const onPointerDown = (e: PointerEvent) => {
984
+ if (!props.zoomable || e.button !== 0) return
985
+ const el = e.currentTarget as SVGElement
986
+ const offset = (ev: PointerEvent) => ev.clientX - el.getBoundingClientRect().left
987
+ const pressedAt = offset(e)
988
+ startPointerDrag(e, {
989
+ move(ev) {
990
+ const x = offset(ev)
991
+ if (Math.abs(x - pressedAt) > SELECT_SLOP) selection.value = { from: pressedAt, to: x }
992
+ },
993
+ end(completed) {
994
+ const picked = selection.value
995
+ selection.value = null
996
+ if (!completed || !picked) return
997
+ swallowClick = true
998
+ const ends = [picked.from, picked.to].map((x) => sourceOf(view.value, nearestIndex(x, geo.value)))
999
+ setRange(clampRange({ start: ends[0], end: ends[1] }, fullCount.value))
1000
+ },
1001
+ })
1002
+ }
1003
+
840
1004
  const onMove = (e: PointerEvent) => {
841
1005
  keyboard.value = false
842
1006
  const el = e.currentTarget as SVGElement
@@ -846,12 +1010,36 @@ const onMove = (e: PointerEvent) => {
846
1010
  active.value = nearestIndex(x, geo.value)
847
1011
  }
848
1012
 
1013
+ const selectionBox = computed(() => {
1014
+ if (!selection.value) return null
1015
+ const right = box.value.width - box.value.right
1016
+ const [from, to] = [selection.value.from, selection.value.to].map((x) => clamp(x, box.value.left, right))
1017
+ return { x: Math.min(from, to), width: Math.abs(to - from) }
1018
+ })
1019
+
1020
+ function zoomBy(factor: number, anchor: number) {
1021
+ setRange(zoomRange(range.value, fullCount.value, anchor, factor))
1022
+ }
1023
+
1024
+ /* Plain wheel stays the page's: a chart in a dashboard must not trap scrolling. */
1025
+ const onWheel = (e: WheelEvent) => {
1026
+ if (!props.zoomable || !e.ctrlKey || !ready.value) return
1027
+ e.preventDefault()
1028
+ const rect = (e.currentTarget as SVGElement).getBoundingClientRect()
1029
+ const plot = plotWidth(box.value) || 1
1030
+ zoomBy(e.deltaY < 0 ? ZOOM_STEP : 1 / ZOOM_STEP, (e.clientX - rect.left - box.value.left) / plot)
1031
+ }
1032
+
1033
+ const resetZoom = () => {
1034
+ if (range.value) setRange(null)
1035
+ }
1036
+
849
1037
  const onLeave = () => {
850
1038
  active.value = -1
851
1039
  }
852
1040
 
853
1041
  const pointEvent = (originalEvent: MouseEvent): ChartPointEvent => ({
854
- index: active.value,
1042
+ index: sourceOf(view.value, active.value),
855
1043
  label: labels.value[active.value] ?? "",
856
1044
  values: allSeries.value.map((s) => s.values[active.value] ?? null),
857
1045
  originalEvent,
@@ -860,6 +1048,10 @@ const pointEvent = (originalEvent: MouseEvent): ChartPointEvent => ({
860
1048
  /* A tap fires pointerleave before click, which has already cleared the hover,
861
1049
  so the index comes from the click itself. */
862
1050
  const onClick = (e: MouseEvent) => {
1051
+ if (swallowClick) {
1052
+ swallowClick = false
1053
+ return
1054
+ }
863
1055
  const rect = (e.currentTarget as SVGElement).getBoundingClientRect()
864
1056
  active.value = nearestIndex(e.clientX - rect.left, geo.value)
865
1057
  if (active.value < 0) return
@@ -891,19 +1083,19 @@ const onContextMenu = (e: MouseEvent) => {
891
1083
  }
892
1084
 
893
1085
  const activeX = computed(() =>
894
- active.value < 0 ? 0 : xAt(active.value, count.value, box.value, banded.value),
1086
+ crosshair.value < 0 ? 0 : xAt(crosshair.value, count.value, box.value, banded.value),
895
1087
  )
896
1088
 
897
1089
  /** Dots on the crosshair — one per visible series that has a value here. */
898
1090
  const activePoints = computed(() => {
899
- if (active.value < 0) return []
1091
+ if (crosshair.value < 0) return []
900
1092
  return visible.value
901
- .map((s) => ({ s, v: s.values[active.value] }))
1093
+ .map((s) => ({ s, v: s.values[crosshair.value] }))
902
1094
  .filter((r): r is { s: (typeof visible.value)[number]; v: number } => r.v != null)
903
1095
  .map(({ s, v }) => {
904
1096
  const sc = scaleOf(s)
905
1097
  // The dot rides the curve as drawn; the figure is the reading itself.
906
- const at = drawnById.value.get(s.id)?.values[active.value] ?? v
1098
+ const at = drawnById.value.get(s.id)?.values[crosshair.value] ?? v
907
1099
  return {
908
1100
  color: s.color,
909
1101
  id: s.id,
@@ -971,7 +1163,7 @@ watch(
971
1163
  },
972
1164
  )
973
1165
 
974
- const clipId = `lp-chart-${Math.random().toString(36).slice(2, 9)}`
1166
+ const clipId = `lp-chart-${useId()}`
975
1167
 
976
1168
  /*
977
1169
  * The gradient id for a series, with the series NAME reduced to id-safe
@@ -1015,7 +1207,7 @@ const thresholdMarks = computed(() =>
1015
1207
 
1016
1208
  const markerMarks = computed(() =>
1017
1209
  props.markers.flatMap((m, i) => {
1018
- const index = markerIndex(m.at, labels.value, count.value)
1210
+ const index = slotOf(view.value, markerIndex(m.at, fullLabels.value, fullCount.value))
1019
1211
  if (index < 0 || width.value <= 0) return []
1020
1212
  return [
1021
1213
  {
@@ -1028,6 +1220,47 @@ const markerMarks = computed(() =>
1028
1220
  }),
1029
1221
  )
1030
1222
 
1223
+ /* A source point's x, held to the plot when the window has left it behind. */
1224
+ const xOfSource = (source: number): number => {
1225
+ if (source < view.value.start) return box.value.left
1226
+ if (source > view.value.end) return box.value.width - box.value.right
1227
+ return xAt(slotOf(view.value, source), count.value, box.value, banded.value)
1228
+ }
1229
+
1230
+ const bandMarks = computed(() =>
1231
+ props.bands.flatMap((b, i) => {
1232
+ const ends = [markerIndex(b.from, fullLabels.value, fullCount.value), markerIndex(b.to, fullLabels.value, fullCount.value)]
1233
+ if (ends.some((end) => end < 0) || width.value <= 0) return []
1234
+ const from = Math.min(...ends)
1235
+ const to = Math.max(...ends)
1236
+ if (to < view.value.start || from > view.value.end) return []
1237
+ const x = xOfSource(from)
1238
+ return [{ key: i, x, width: xOfSource(to) - x, label: b.label, color: b.color ?? "var(--color-line-strong)" }]
1239
+ }),
1240
+ )
1241
+
1242
+ const annotationMarks = computed(() =>
1243
+ props.annotations.flatMap((a, i) => {
1244
+ const source = markerIndex(a.at, fullLabels.value, fullCount.value)
1245
+ const slot = slotOf(view.value, source)
1246
+ const lead = fullSeries.value.find((s) => !hidden.value.has(s.id) && s.values[source] != null)
1247
+ const value = a.value ?? lead?.values[source]
1248
+ if (slot < 0 || value == null || width.value <= 0) return []
1249
+ const sc = (a.value == null ? lead?.axis : a.axis) === "right" && rightScale.value ? rightScale.value : scale.value
1250
+ const x = xAt(slot, count.value, box.value, banded.value)
1251
+ return [
1252
+ {
1253
+ key: i,
1254
+ x,
1255
+ y: yAt(value, sc.min, sc.max, box.value),
1256
+ label: a.label,
1257
+ color: a.color ?? "var(--color-ink)",
1258
+ anchor: x > box.value.width - CARD_W ? ("end" as const) : ("start" as const),
1259
+ },
1260
+ ]
1261
+ }),
1262
+ )
1263
+
1031
1264
  // ── keyboard & assistive text ──────────────────
1032
1265
  const summary = computed(
1033
1266
  () => props.ariaLabel ?? chartSummary(visible.value, labels.value, fmtSeries, props.title),
@@ -1058,11 +1291,23 @@ const onKeydown = (e: KeyboardEvent) => {
1058
1291
  case " ":
1059
1292
  if (active.value < 0) return
1060
1293
  e.preventDefault()
1061
- emit("pointClick", pointEvent(new MouseEvent("click")))
1294
+ emit("pointClick", pointEvent(new (nodeWindow(e.target as Node).MouseEvent)("click")))
1062
1295
  return
1063
1296
  case "Escape":
1064
1297
  active.value = -1
1065
1298
  return
1299
+ case "+":
1300
+ case "=":
1301
+ case "-":
1302
+ if (!props.zoomable) return
1303
+ e.preventDefault()
1304
+ zoomBy(e.key === "-" ? 1 / ZOOM_STEP : ZOOM_STEP, active.value < 0 ? 0.5 : active.value / last)
1305
+ return
1306
+ case "0":
1307
+ if (!props.zoomable) return
1308
+ e.preventDefault()
1309
+ resetZoom()
1310
+ return
1066
1311
  default:
1067
1312
  return
1068
1313
  }
@@ -1095,13 +1340,13 @@ const readout = computed(() =>
1095
1340
  const svgEl = ref<SVGSVGElement | null>(null)
1096
1341
 
1097
1342
  function exportCsv(options: ChartExportOptions & CsvOptions = {}): string {
1098
- const rows = labels.value.map((label, i) => ({ label, i }))
1343
+ const rows = fullLabels.value.map((label, i) => ({ label, i }))
1099
1344
  const csv = toCsv(rows, [
1100
1345
  { key: "label", label: strings.value.xColumn },
1101
- ...allSeries.value.map((s) => ({ key: s.id, label: s.name, value: (r: { i: number }) => s.values[r.i] })),
1346
+ ...fullSeries.value.map((s) => ({ key: s.id, label: s.name, value: (r: { i: number }) => s.values[r.i] })),
1102
1347
  ], options)
1103
1348
  if (options.download !== false) {
1104
- downloadFile(`${fileStem(options.filename ?? props.title, "chart")}.csv`, csv, "text/csv;charset=utf-8")
1349
+ downloadFile(`${fileStem(options.filename ?? props.title, "chart")}.csv`, csv, "text/csv;charset=utf-8", svgEl.value?.ownerDocument)
1105
1350
  }
1106
1351
  return csv
1107
1352
  }
@@ -1114,8 +1359,8 @@ function exportCsv(options: ChartExportOptions & CsvOptions = {}): string {
1114
1359
  */
1115
1360
  async function exportPng(options: ChartExportOptions & { scale?: number; background?: string } = {}): Promise<Blob | null> {
1116
1361
  const svg = svgEl.value
1117
- if (!svg || typeof document === "undefined") return null
1118
- const style = getComputedStyle(root.value ?? svg)
1362
+ if (!svg) return null
1363
+ const style = nodeWindow(svg).getComputedStyle(root.value ?? svg)
1119
1364
  const font = style.fontFamily
1120
1365
  const ink = style.getPropertyValue("--color-ink").trim() || style.color
1121
1366
  const muted = style.getPropertyValue("--color-muted-strong").trim() || style.color
@@ -1151,7 +1396,7 @@ async function exportPng(options: ChartExportOptions & { scale?: number; backgro
1151
1396
  return y ? y + 8 : 0
1152
1397
  },
1153
1398
  })
1154
- if (options.download !== false) downloadFile(`${fileStem(options.filename ?? props.title, "chart")}.png`, blob)
1399
+ if (options.download !== false) downloadFile(`${fileStem(options.filename ?? props.title, "chart")}.png`, blob, undefined, svgEl.value?.ownerDocument)
1155
1400
  return blob
1156
1401
  }
1157
1402
 
@@ -1295,9 +1540,12 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
1295
1540
  :height="height"
1296
1541
  class="block overflow-visible touch-none select-none"
1297
1542
  aria-hidden="true"
1543
+ @pointerdown="onPointerDown"
1298
1544
  @pointermove="onMove"
1299
1545
  @pointerleave="onLeave"
1300
1546
  @click="onClick"
1547
+ @dblclick="zoomable && resetZoom()"
1548
+ @wheel="onWheel"
1301
1549
  @contextmenu="onContextMenu"
1302
1550
  >
1303
1551
  <defs>
@@ -1399,6 +1647,12 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
1399
1647
  opacity="0.5"
1400
1648
  />
1401
1649
 
1650
+ <!-- stretches of the x axis sit under the data -->
1651
+ <g v-for="b in bandMarks" :key="`x-band-${b.key}`">
1652
+ <rect :x="b.x" :y="box.top" :width="b.width" :height="plotHeight(box)" :fill="b.color" opacity="0.1" />
1653
+ <text v-if="b.label" :x="b.x + 4" :y="box.top + 9" class="text-[10px]" :fill="b.color">{{ b.label }}</text>
1654
+ </g>
1655
+
1402
1656
  <!-- threshold bands sit under the data -->
1403
1657
  <rect
1404
1658
  v-for="t in thresholdMarks.filter((m) => m.height > 0)"
@@ -1496,8 +1750,32 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
1496
1750
  </text>
1497
1751
  </g>
1498
1752
 
1753
+ <g v-for="a in annotationMarks" :key="`a-${a.key}`">
1754
+ <circle :cx="a.x" :cy="a.y" r="3.5" :fill="a.color" stroke="var(--color-surface)" stroke-width="1.5" />
1755
+ <text
1756
+ :x="a.anchor === 'end' ? a.x - 6 : a.x + 6"
1757
+ :y="a.y - 6"
1758
+ :text-anchor="a.anchor"
1759
+ class="text-[10px]"
1760
+ :fill="a.color"
1761
+ >
1762
+ {{ a.label }}
1763
+ </text>
1764
+ </g>
1765
+
1766
+ <rect
1767
+ v-if="selectionBox"
1768
+ data-lp-chart-selection
1769
+ :x="selectionBox.x"
1770
+ :y="box.top"
1771
+ :width="selectionBox.width"
1772
+ :height="plotHeight(box)"
1773
+ fill="var(--color-brand)"
1774
+ opacity="0.15"
1775
+ />
1776
+
1499
1777
  <!-- crosshair -->
1500
- <g v-if="active >= 0 && type !== 'bar'">
1778
+ <g v-if="crosshair >= 0 && type !== 'bar'">
1501
1779
  <line
1502
1780
  :x1="activeX"
1503
1781
  :x2="activeX"
@@ -1572,23 +1850,44 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
1572
1850
  </LpShift>
1573
1851
  </Motion>
1574
1852
 
1853
+ <button
1854
+ v-if="zoomable && range && ready"
1855
+ type="button"
1856
+ class="absolute right-1 top-1 rounded-inner bg-surface-raised px-2 py-0.5 text-[11px] text-muted-strong outline-none hover:text-ink focus-visible:ring-2 focus-visible:ring-ring"
1857
+ @click="resetZoom"
1858
+ >
1859
+ {{ strings.resetZoom }}
1860
+ </button>
1861
+
1575
1862
  <span class="sr-only" aria-live="polite">{{ readout }}</span>
1576
1863
  </div>
1577
1864
  </LpContextMenu>
1578
1865
 
1866
+ <ChartRangeSelector
1867
+ v-if="rangeSelector && ready && width > 0"
1868
+ :values="(fullSeries.find((s) => s.values.some((v) => v != null))?.values ?? [])"
1869
+ :count="fullCount"
1870
+ :range="range"
1871
+ :width="width"
1872
+ :labels="fullLabels"
1873
+ :start-label="strings.rangeStart"
1874
+ :end-label="strings.rangeEnd"
1875
+ @change="setRange"
1876
+ />
1877
+
1579
1878
  <div v-if="dataTable && ready" class="sr-only">
1580
1879
  <table>
1581
1880
  <caption v-if="title">{{ title }}</caption>
1582
1881
  <thead>
1583
1882
  <tr>
1584
1883
  <th scope="col"></th>
1585
- <th v-for="s in allSeries" :key="s.id" scope="col">{{ s.name }}</th>
1884
+ <th v-for="s in fullSeries" :key="s.id" scope="col">{{ s.name }}</th>
1586
1885
  </tr>
1587
1886
  </thead>
1588
1887
  <tbody>
1589
- <tr v-for="(label, i) in labels" :key="i">
1888
+ <tr v-for="(label, i) in fullLabels" :key="i">
1590
1889
  <th scope="row">{{ label }}</th>
1591
- <td v-for="s in allSeries" :key="s.id">
1890
+ <td v-for="s in fullSeries" :key="s.id">
1592
1891
  {{ s.values[i] == null ? "—" : fmtSeries(s, s.values[i] as number) }}
1593
1892
  </td>
1594
1893
  </tr>