gloomberb 0.10.0 → 0.10.2

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 (353) hide show
  1. package/package.json +8 -1
  2. package/src/api-client/auth.ts +1 -0
  3. package/src/api-client/index.test.ts +359 -108
  4. package/src/api-client/index.ts +24 -13
  5. package/src/api-client/socket.ts +70 -35
  6. package/src/api-client/types.ts +1 -1
  7. package/src/app/language-observer.test.tsx +82 -0
  8. package/src/app/language-observer.tsx +13 -0
  9. package/src/app/pane-runtime/index.tsx +2 -2
  10. package/src/app/pane-runtime/pane-settings-runtime.tsx +2 -2
  11. package/src/app/pane-runtime/pane-template-runtime.ts +2 -2
  12. package/src/app/pane-runtime/plugin-bindings.ts +2 -2
  13. package/src/app/pane-runtime/ticker-open-runtime.ts +2 -2
  14. package/src/app/runtime/broker-import.ts +2 -2
  15. package/src/app/runtime/plugin-bindings.ts +2 -2
  16. package/src/app/runtime/startup.ts +2 -2
  17. package/src/app.tsx +16 -7
  18. package/src/brokers/account-cache.ts +6 -6
  19. package/src/brokers/broker-ticker-sync.ts +3 -3
  20. package/src/brokers/remote-broker-adapter.ts +2 -2
  21. package/src/brokers/sync-broker-instance.ts +5 -6
  22. package/src/cli/commands/api.ts +3 -6
  23. package/src/cli/commands/automation.ts +7 -15
  24. package/src/cli/commands/market.ts +26 -61
  25. package/src/cli/commands/overview.ts +34 -45
  26. package/src/cli/commands/search.ts +25 -27
  27. package/src/cli/commands/system.ts +27 -57
  28. package/src/cli/commands/ticker.ts +62 -63
  29. package/src/cli/context.test.ts +63 -0
  30. package/src/cli/context.ts +15 -1
  31. package/src/cli/index.ts +1 -1
  32. package/src/cli/pane-functions/data.ts +2 -19
  33. package/src/cli/pane-functions/index.ts +26 -25
  34. package/src/cli/pane-functions/report.ts +1 -1
  35. package/src/cli/pane-functions/screenshot.ts +3 -3
  36. package/src/cli/scoped-context.ts +41 -0
  37. package/src/components/chart/composite/composite-chart.test.tsx +615 -18
  38. package/src/components/chart/composite/composite-chart.tsx +179 -79
  39. package/src/components/chart/composite/format.test.ts +20 -7
  40. package/src/components/chart/composite/index.ts +0 -21
  41. package/src/components/chart/composite/interactions.test.ts +90 -3
  42. package/src/components/chart/composite/interactions.ts +189 -24
  43. package/src/components/chart/composite/price-series.ts +0 -2
  44. package/src/components/chart/composite/rasterizer.ts +10 -9
  45. package/src/components/chart/composite/renderers.test.ts +108 -2
  46. package/src/components/chart/composite/scene.test.ts +36 -0
  47. package/src/components/chart/composite/scene.ts +5 -2
  48. package/src/components/chart/composite/text-renderer.ts +37 -25
  49. package/src/components/chart/composite/time-axis.test.ts +243 -0
  50. package/src/components/chart/composite/time-axis.ts +608 -0
  51. package/src/components/chart/composite/types.ts +12 -1
  52. package/src/components/chart/core/data.ts +2 -159
  53. package/src/components/chart/core/date-window.ts +6 -225
  54. package/src/components/chart/core/palette.ts +1 -12
  55. package/src/components/chart/core/pointer.ts +0 -142
  56. package/src/components/chart/core/types.ts +1 -58
  57. package/src/components/chart/cursor-motion.ts +2 -4
  58. package/src/components/chart/indicators/types.ts +0 -9
  59. package/src/components/chart/market-session.ts +0 -11
  60. package/src/components/chart/native/kitty/protocol.ts +1 -1
  61. package/src/components/chart/native/raster/layout.ts +3 -10
  62. package/src/components/chart/static/chart/axis-overlays.test.tsx +64 -0
  63. package/src/components/chart/static/chart/axis-overlays.tsx +59 -14
  64. package/src/components/chart/static/chart/surface.tsx +1 -2
  65. package/src/components/command-bar/action-runtime.ts +2 -2
  66. package/src/components/command-bar/commands/direct/index.ts +1 -1
  67. package/src/components/command-bar/panel/body.tsx +2 -2
  68. package/src/components/command-bar/panel/index.tsx +11 -9
  69. package/src/components/command-bar/routes/ticker-search/actions.ts +2 -2
  70. package/src/components/command-bar/surface/index.tsx +2 -2
  71. package/src/components/command-bar/workflow/body.tsx +3 -3
  72. package/src/components/command-bar/workflow/collection-actions.ts +2 -2
  73. package/src/components/command-bar/workflow/coordinator.ts +2 -2
  74. package/src/components/command-bar/workflow/field-row.tsx +25 -11
  75. package/src/components/command-bar/workflow/tickers.ts +2 -2
  76. package/src/components/feed-data-table/stack-view.test.tsx +28 -36
  77. package/src/components/feed-data-table/stack-view.tsx +3 -1
  78. package/src/components/layout/detached-pane-shell.tsx +6 -6
  79. package/src/components/layout/header.tsx +13 -9
  80. package/src/components/layout/pane/content.test.tsx +42 -3
  81. package/src/components/layout/pane/content.tsx +3 -1
  82. package/src/components/layout/pane/footer/index.test.tsx +45 -2
  83. package/src/components/layout/pane/footer/registration.tsx +3 -1
  84. package/src/components/layout/shell/index.tsx +1 -2
  85. package/src/components/layout/shell/native/surfaces.ts +1 -1
  86. package/src/components/layout/shell/native/window-state.ts +1 -1
  87. package/src/components/layout/status-bar.tsx +12 -8
  88. package/src/components/layout/window-controls.tsx +8 -6
  89. package/src/components/onboarding/onboarding-wizard.tsx +3 -1
  90. package/src/components/pane-settings-dialog/desktop.tsx +0 -2
  91. package/src/components/pane-settings-dialog.tsx +0 -2
  92. package/src/components/pane-template-wizard.tsx +10 -9
  93. package/src/components/price-performance.tsx +2 -113
  94. package/src/components/price-sparkline/model.ts +15 -17
  95. package/src/components/price-sparkline/view.tsx +8 -7
  96. package/src/components/speedometer-gauge/desktop.tsx +2 -1
  97. package/src/components/speedometer-gauge/index.tsx +0 -2
  98. package/src/components/speedometer-gauge/terminal.tsx +24 -5
  99. package/src/components/ticker/badge/index.tsx +1 -18
  100. package/src/components/ui/data-table/opentui/index.tsx +3 -3
  101. package/src/components/ui/frame.tsx +1 -2
  102. package/src/components/ui/page-stack-view.test.tsx +126 -0
  103. package/src/components/ui/page-stack-view.tsx +24 -12
  104. package/src/components/ui/tabs.tsx +7 -3
  105. package/src/components/ui/ui.test.tsx +23 -2
  106. package/src/components/use-external-link-footer.ts +4 -2
  107. package/src/core/app-service-ports.ts +46 -0
  108. package/src/core/app-services.test.ts +66 -0
  109. package/src/core/app-services.ts +17 -15
  110. package/src/data/config/chart-settings.ts +3 -10
  111. package/src/data/config/store/index.test.ts +99 -2
  112. package/src/data/config/store/migrations.ts +278 -0
  113. package/src/data/config/store/normalize.ts +44 -186
  114. package/src/data/resource-store.ts +73 -12
  115. package/src/data/sqlite/cache.test.ts +104 -15
  116. package/src/i18n/index.test.ts +17 -0
  117. package/src/i18n/index.ts +23 -6
  118. package/src/i18n/ja.ts +13 -0
  119. package/src/i18n/ko.ts +13 -0
  120. package/src/i18n/react.ts +6 -0
  121. package/src/i18n/zh-cn.ts +13 -0
  122. package/src/i18n/zh-tw.ts +13 -0
  123. package/src/market-data/coordinator/auxiliary.ts +7 -3
  124. package/src/market-data/coordinator/chart.ts +1 -1
  125. package/src/market-data/coordinator/index.test.ts +26 -0
  126. package/src/market-data/coordinator/index.ts +11 -5
  127. package/src/market-data/coordinator/quotes.ts +4 -40
  128. package/src/market-data/coordinator/subscriptions.test.ts +89 -1
  129. package/src/market-data/hooks.tsx +47 -1
  130. package/src/market-data/market/status.ts +6 -6
  131. package/src/market-data/performance.ts +1 -1
  132. package/src/market-data/quote-subscription-target.test.ts +37 -0
  133. package/src/market-data/quote-subscription-target.ts +60 -0
  134. package/src/market-data/quotes/freshness.ts +1 -0
  135. package/src/market-data/quotes/resolution.ts +4 -0
  136. package/src/market-data/request-types.ts +3 -3
  137. package/src/news/aggregator.test.ts +97 -1
  138. package/src/news/aggregator.ts +100 -57
  139. package/src/news/hooks.test.tsx +64 -0
  140. package/src/news/hooks.ts +18 -25
  141. package/src/plugins/builtin/account-management/footer.ts +4 -2
  142. package/src/plugins/builtin/account-management/pane.tsx +9 -4
  143. package/src/plugins/builtin/ai/agent-history.ts +11 -7
  144. package/src/plugins/builtin/ai/ask-ai-detail-tab.tsx +0 -5
  145. package/src/plugins/builtin/ai/ask-ai.test.tsx +3 -4
  146. package/src/plugins/builtin/ai/index.test.ts +2 -2
  147. package/src/plugins/builtin/ai/index.tsx +10 -11
  148. package/src/plugins/builtin/ai/pane-settings.ts +1 -1
  149. package/src/plugins/builtin/ai/pi/runtime.ts +6 -5
  150. package/src/plugins/builtin/ai/providers.ts +1 -9
  151. package/src/plugins/builtin/ai/runner.ts +0 -6
  152. package/src/plugins/builtin/ai/screener/footer.ts +4 -1
  153. package/src/plugins/builtin/ai/screener/pane.test.tsx +9 -9
  154. package/src/plugins/builtin/ai/workspace/model.ts +2 -27
  155. package/src/plugins/builtin/ai/workspace/pane.tsx +2 -2
  156. package/src/plugins/builtin/analytics/metrics.ts +1 -7
  157. package/src/plugins/builtin/broker-manager/detail.tsx +3 -2
  158. package/src/plugins/builtin/broker-manager/index.tsx +4 -2
  159. package/src/plugins/builtin/chart-composer/editor/controller.ts +643 -0
  160. package/src/plugins/builtin/chart-composer/editor/desktop-view.tsx +134 -0
  161. package/src/plugins/builtin/chart-composer/editor/model.test.ts +85 -0
  162. package/src/plugins/builtin/chart-composer/editor/model.ts +292 -0
  163. package/src/plugins/builtin/chart-composer/editor/opentui-view.tsx +108 -0
  164. package/src/plugins/builtin/chart-composer/editor.tsx +65 -947
  165. package/src/plugins/builtin/chart-composer/index.tsx +0 -6
  166. package/src/plugins/builtin/chart-composer/pane.tsx +69 -36
  167. package/src/plugins/builtin/chart-composer/presets.ts +1 -19
  168. package/src/plugins/builtin/chart-composer/settings.ts +1 -1
  169. package/src/plugins/builtin/chat/content/composer-runtime.ts +1 -1
  170. package/src/plugins/builtin/chat/content/shortcuts.ts +0 -1
  171. package/src/plugins/builtin/chat/controller/fetch.ts +8 -2
  172. package/src/plugins/builtin/chat/controller/persistence.ts +2 -0
  173. package/src/plugins/builtin/chat/controller/session.test.ts +25 -0
  174. package/src/plugins/builtin/chat/controller/session.ts +2 -0
  175. package/src/plugins/builtin/chat/controller/state.ts +7 -0
  176. package/src/plugins/builtin/chat/controller.test.ts +73 -20
  177. package/src/plugins/builtin/chat/message/desktop.tsx +2 -0
  178. package/src/plugins/builtin/cloud-tweets/footer.ts +9 -28
  179. package/src/plugins/builtin/cloud-tweets/pane.tsx +0 -5
  180. package/src/plugins/builtin/cloud-tweets/table.tsx +12 -17
  181. package/src/plugins/builtin/correlation/compute.ts +4 -10
  182. package/src/plugins/builtin/econ/index.tsx +17 -19
  183. package/src/plugins/builtin/holders/types.ts +0 -1
  184. package/src/plugins/builtin/insider/index.tsx +6 -31
  185. package/src/plugins/builtin/news/index.tsx +5 -7
  186. package/src/plugins/builtin/news/wire/breaking/pane.test.tsx +6 -8
  187. package/src/plugins/builtin/news/wire/news/footer.ts +10 -11
  188. package/src/plugins/builtin/news/wire/read-state.test.ts +7 -0
  189. package/src/plugins/builtin/news/wire/read-state.ts +18 -28
  190. package/src/plugins/builtin/news/wire/rss/parser.ts +1 -11
  191. package/src/plugins/builtin/options/footer.test.ts +115 -0
  192. package/src/plugins/builtin/options/footer.ts +110 -0
  193. package/src/plugins/builtin/options/live-quotes.test.ts +238 -0
  194. package/src/plugins/builtin/options/live-quotes.ts +147 -0
  195. package/src/plugins/builtin/options/view.test.tsx +71 -1
  196. package/src/plugins/builtin/options/view.tsx +39 -24
  197. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +103 -117
  198. package/src/plugins/builtin/portfolio-list/cli/render.ts +11 -5
  199. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +120 -135
  200. package/src/plugins/builtin/portfolio-list/header.tsx +9 -4
  201. package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +6 -1
  202. package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +4 -2
  203. package/src/plugins/builtin/research/corporate-actions-pane.tsx +24 -52
  204. package/src/plugins/builtin/sec/filing-content.test.ts +41 -0
  205. package/src/plugins/builtin/sec/filing-content.ts +94 -0
  206. package/src/plugins/builtin/sec/index.tsx +21 -104
  207. package/src/plugins/builtin/sectors/sector-model.ts +1 -7
  208. package/src/plugins/builtin/shared/cloud-upgrade.ts +1 -0
  209. package/src/plugins/builtin/shared/pane-footer.ts +82 -0
  210. package/src/plugins/builtin/shared/read-state.ts +64 -3
  211. package/src/plugins/builtin/substack/read-state.ts +16 -41
  212. package/src/plugins/builtin/thirteenf/pane.tsx +24 -73
  213. package/src/plugins/builtin/ticker-detail/quote-monitor/index.tsx +10 -10
  214. package/src/plugins/builtin/yield-curve/index.tsx +11 -9
  215. package/src/plugins/ibkr/dialogs.tsx +3 -3
  216. package/src/plugins/ibkr/gateway/fundamentals.ts +1 -1
  217. package/src/plugins/ibkr/gateway/history-requests.ts +2 -2
  218. package/src/plugins/ibkr/gateway/history.ts +2 -2
  219. package/src/plugins/ibkr/gateway/selection.ts +2 -2
  220. package/src/plugins/ibkr/gateway/service/index.ts +2 -2
  221. package/src/plugins/ibkr/gateway/service/native.ts +2 -2
  222. package/src/plugins/plugin-persistence.ts +3 -4
  223. package/src/plugins/prediction-markets/controller/keyboard.ts +1 -1
  224. package/src/plugins/prediction-markets/controller/live-updates.ts +6 -5
  225. package/src/plugins/prediction-markets/detail/book.tsx +2 -2
  226. package/src/plugins/prediction-markets/detail/outcomes.tsx +3 -1
  227. package/src/plugins/prediction-markets/detail/pane.tsx +3 -1
  228. package/src/plugins/prediction-markets/detail/trades.tsx +3 -3
  229. package/src/plugins/registry/context.ts +3 -4
  230. package/src/plugins/registry/index.ts +5 -6
  231. package/src/react/input.test.ts +126 -3
  232. package/src/react/input.ts +120 -1
  233. package/src/remote/app-host.tsx +2 -13
  234. package/src/renderers/electrobun/bun/desktop/backend-requests.ts +44 -60
  235. package/src/renderers/electrobun/bun/desktop/capability-bridge.ts +15 -13
  236. package/src/renderers/electrobun/bun/desktop/host-requests.ts +26 -22
  237. package/src/renderers/electrobun/bun/desktop/http-fetch.ts +5 -1
  238. package/src/renderers/electrobun/bun/desktop/initialization.ts +11 -6
  239. package/src/renderers/electrobun/bun/desktop/media.ts +5 -3
  240. package/src/renderers/electrobun/bun/desktop/plugin-state.ts +21 -22
  241. package/src/renderers/electrobun/bun/desktop/window-controls.ts +3 -1
  242. package/src/renderers/electrobun/bun/desktop/workspace/requests.ts +18 -18
  243. package/src/renderers/electrobun/bun/index.ts +123 -83
  244. package/src/renderers/electrobun/shared/protocol.ts +146 -7
  245. package/src/renderers/electrobun/view/app-services.ts +5 -8
  246. package/src/renderers/electrobun/view/backend-rpc.ts +18 -8
  247. package/src/renderers/electrobun/view/broker-remote-client.ts +2 -2
  248. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +5 -22
  249. package/src/renderers/electrobun/view/config-host.ts +1 -1
  250. package/src/renderers/electrobun/view/context-menu.ts +1 -17
  251. package/src/renderers/electrobun/view/data-table/index.tsx +0 -1
  252. package/src/renderers/electrobun/view/data-table/row.tsx +0 -4
  253. package/src/renderers/electrobun/view/desktop/control-styles.ts +37 -34
  254. package/src/renderers/electrobun/view/desktop/controls.tsx +36 -33
  255. package/src/renderers/electrobun/view/desktop/list-view.tsx +15 -12
  256. package/src/renderers/electrobun/view/desktop/popover.tsx +2 -3
  257. package/src/renderers/electrobun/view/dialog-host.tsx +2 -3
  258. package/src/renderers/electrobun/view/fatal-screen.tsx +0 -1
  259. package/src/renderers/electrobun/view/host/box.tsx +0 -1
  260. package/src/renderers/electrobun/view/host/chart-surface.tsx +0 -1
  261. package/src/renderers/electrobun/view/host/input.tsx +0 -1
  262. package/src/renderers/electrobun/view/host/media-surface.tsx +0 -1
  263. package/src/renderers/electrobun/view/host/native.ts +0 -1
  264. package/src/renderers/electrobun/view/host/scroll-box.tsx +0 -1
  265. package/src/renderers/electrobun/view/host/tabs.tsx +0 -1
  266. package/src/renderers/electrobun/view/host/text.tsx +0 -1
  267. package/src/renderers/electrobun/view/http-fetch.ts +3 -11
  268. package/src/renderers/electrobun/view/input-host.tsx +10 -53
  269. package/src/renderers/electrobun/view/key-event.ts +0 -1
  270. package/src/renderers/electrobun/view/main.tsx +3 -3
  271. package/src/renderers/electrobun/view/native-renderer.ts +0 -1
  272. package/src/renderers/electrobun/view/native-stubs/backend-rpc.ts +13 -1
  273. package/src/renderers/electrobun/view/native-stubs/chart/surface-manager.ts +11 -0
  274. package/src/renderers/electrobun/view/native-stubs/native-stubs.test.ts +47 -0
  275. package/src/renderers/electrobun/view/remote/asset-data-client.ts +6 -44
  276. package/src/renderers/electrobun/view/remote/persistence.ts +6 -2
  277. package/src/renderers/electrobun/view/remote/quote-subscription-registry.test.ts +86 -0
  278. package/src/renderers/electrobun/view/remote/quote-subscription-registry.ts +72 -0
  279. package/src/renderers/electrobun/view/remote/ticker-repository.ts +2 -2
  280. package/src/renderers/electrobun/view/toast-host.tsx +0 -1
  281. package/src/renderers/electrobun/view/ui-host.tsx +1 -2
  282. package/src/renderers/electrobun/view/update-host.ts +1 -1
  283. package/src/renderers/opentui/chart-surface.tsx +2 -1
  284. package/src/renderers/opentui/dialog-host.tsx +20 -4
  285. package/src/renderers/opentui/image/loader.ts +12 -2
  286. package/src/renderers/opentui/input-host.tsx +7 -49
  287. package/src/renderers/opentui/start.tsx +2 -0
  288. package/src/sources/gloomberb-cloud/history-quality.ts +44 -0
  289. package/src/sources/gloomberb-cloud/index.test.ts +173 -0
  290. package/src/sources/gloomberb-cloud/index.ts +42 -20
  291. package/src/sources/gloomberb-cloud/normalizers.ts +9 -3
  292. package/src/sources/provider-router/cache.ts +1 -1
  293. package/src/sources/provider-router/document-routes.ts +10 -5
  294. package/src/sources/provider-router/financials.test.ts +14 -0
  295. package/src/sources/provider-router/financials.ts +6 -1
  296. package/src/sources/provider-router/history.test.ts +163 -1
  297. package/src/sources/provider-router/history.ts +278 -347
  298. package/src/sources/provider-router/index.ts +2 -2
  299. package/src/sources/provider-router/routing.test.ts +39 -0
  300. package/src/sources/provider-router/routing.ts +24 -11
  301. package/src/sources/provider-router/supplemental.ts +37 -17
  302. package/src/sources/sec-edgar/content.ts +2 -12
  303. package/src/sources/sec-edgar.ts +2 -13
  304. package/src/sources/yahoo-finance/history.ts +2 -2
  305. package/src/sources/yahoo-finance/options.ts +5 -0
  306. package/src/sources/yahoo-finance.ts +2 -2
  307. package/src/state/app/bootstrap.ts +2 -2
  308. package/src/state/app/context/index.tsx +2 -2
  309. package/src/state/hooks/quote-streaming.ts +66 -1
  310. package/src/state/hooks/session-snapshot.ts +2 -2
  311. package/src/state/selectors.ts +0 -9
  312. package/src/sync/controller.test.ts +98 -0
  313. package/src/sync/controller.ts +29 -5
  314. package/src/sync/react.ts +2 -2
  315. package/src/sync/types.ts +2 -2
  316. package/src/theme/colors.test.ts +10 -0
  317. package/src/theme/colors.ts +75 -78
  318. package/src/theme/theme-context.test.tsx +67 -0
  319. package/src/theme/theme-context.tsx +9 -5
  320. package/src/tickers/open-target.ts +2 -2
  321. package/src/tickers/search/upsert.ts +2 -2
  322. package/src/time-series/alignment.ts +0 -7
  323. package/src/time-series/chart-data.ts +145 -0
  324. package/src/time-series/date-window.ts +44 -0
  325. package/src/time-series/history-window.ts +21 -0
  326. package/src/time-series/hooks.test.ts +59 -0
  327. package/src/time-series/hooks.ts +33 -12
  328. package/src/time-series/market-resolution.ts +2 -2
  329. package/src/time-series/market.ts +1 -1
  330. package/src/time-series/range.ts +9 -0
  331. package/src/{components/chart/core → time-series}/resolution.ts +3 -102
  332. package/src/time-series/resolve.test.ts +203 -1
  333. package/src/time-series/resolve.ts +96 -18
  334. package/src/time-series/spec-studies.test.ts +15 -0
  335. package/src/time-series/spec.ts +2 -2
  336. package/src/time-series/studies.ts +5 -2
  337. package/src/time-series/types.ts +3 -1
  338. package/src/time-series/use-chart-resolution.test.tsx +358 -0
  339. package/src/time-series/use-chart-resolution.ts +46 -4
  340. package/src/types/broker.ts +2 -2
  341. package/src/types/data-provider.ts +3 -3
  342. package/src/types/financials.ts +12 -0
  343. package/src/types/plugin.ts +2 -2
  344. package/src/ui/context-menu.tsx +3 -2
  345. package/src/ui/dialog.tsx +2 -2
  346. package/src/utils/html-entities.ts +3 -5
  347. package/src/utils/main-thread-monitor.ts +1 -1
  348. package/src/utils/price-history.ts +5 -5
  349. package/src/version.ts +3 -1
  350. package/src/components/chart/core/viewport.test.ts +0 -8
  351. package/src/components/chart/core/viewport.ts +0 -24
  352. package/src/time-series/index.ts +0 -14
  353. /package/src/{components/chart/core → time-series}/resolution.test.ts +0 -0
@@ -1,11 +1,5 @@
1
- import type { PricePoint, Quote } from "../../../types/financials";
2
- import { isQuoteStaleForCurrentSession } from "../../../market-data/quotes/freshness";
3
- import { hasLikelyQuoteUnitMismatch } from "../../../utils/currency-units";
4
- import {
5
- CHART_RESOLUTION_STEP_MS,
6
- type ManualChartResolution,
7
- } from "./resolution";
8
-
1
+ export { appendLiveQuotePoint } from "../../../time-series/chart-data";
2
+ export type { AppendLiveQuotePointOptions } from "../../../time-series/chart-data";
9
3
  export {
10
4
  bucketOhlcSeries,
11
5
  projectChartData,
@@ -17,154 +11,3 @@ export type {
17
11
  ProjectChartDataOptions,
18
12
  ProjectedChartPoint,
19
13
  } from "./projection";
20
-
21
- const MAX_LIVE_QUOTE_TAIL_AGE_MS = 7 * 24 * 60 * 60_000;
22
- const MAX_LIVE_QUOTE_CLOCK_SKEW_MS = 5 * 60_000;
23
- const MAX_INTRADAY_BAR_INTERVAL_MS = 6 * 60 * 60_000;
24
- const MIN_LIVE_QUOTE_TAIL_GAP_MS = 5 * 60_000;
25
- const MS_DAY = 86400_000;
26
-
27
- export type AppendLiveQuotePointOptions =
28
- | {
29
- now?: number;
30
- mode?: "scalar";
31
- }
32
- | {
33
- now?: number;
34
- mode: "ohlc";
35
- resolution: ManualChartResolution;
36
- };
37
-
38
- function coerceDate(value: Date | string | number): Date {
39
- return value instanceof Date ? value : new Date(value);
40
- }
41
-
42
- function getPointTime(point: Pick<PricePoint, "date">): number {
43
- return coerceDate(point.date as Date | string | number).getTime();
44
- }
45
-
46
- function getActiveQuotePrice(quote: Quote): number {
47
- if ((quote.marketState === "PRE" || quote.marketState === "PREPRE") && quote.preMarketPrice != null) {
48
- return quote.preMarketPrice;
49
- }
50
- if ((quote.marketState === "POST" || quote.marketState === "POSTPOST") && quote.postMarketPrice != null) {
51
- return quote.postMarketPrice;
52
- }
53
- return quote.price;
54
- }
55
-
56
- function quoteBelongsToLatestBar(
57
- latestTime: number,
58
- quoteTime: number,
59
- resolution: ManualChartResolution,
60
- ): boolean {
61
- if (quoteTime < latestTime) return false;
62
- if (resolution === "1mo") {
63
- const latestDate = new Date(latestTime);
64
- const quoteDate = new Date(quoteTime);
65
- return latestDate.getUTCFullYear() === quoteDate.getUTCFullYear()
66
- && latestDate.getUTCMonth() === quoteDate.getUTCMonth();
67
- }
68
- return quoteTime - latestTime < CHART_RESOLUTION_STEP_MS[resolution];
69
- }
70
-
71
- function finiteOrFallback(value: number | undefined, fallback: number): number {
72
- return typeof value === "number" && Number.isFinite(value) ? value : fallback;
73
- }
74
-
75
- function mergeQuoteIntoLatestBar(latest: PricePoint, quotePrice: number): PricePoint {
76
- const open = finiteOrFallback(latest.open, latest.close);
77
- const high = finiteOrFallback(latest.high, Math.max(open, latest.close));
78
- const low = finiteOrFallback(latest.low, Math.min(open, latest.close));
79
- return {
80
- ...latest,
81
- open,
82
- high: Math.max(high, open, latest.close, quotePrice),
83
- low: Math.min(low, open, latest.close, quotePrice),
84
- close: quotePrice,
85
- };
86
- }
87
-
88
- export function appendLiveQuotePoint(
89
- points: PricePoint[],
90
- quote: Quote | null | undefined,
91
- options: AppendLiveQuotePointOptions = {},
92
- ): PricePoint[] {
93
- const now = options.now ?? Date.now();
94
- if (!quote || isQuoteStaleForCurrentSession(quote, now)) return points;
95
-
96
- const quoteTime = quote.lastUpdated;
97
- const quotePrice = getActiveQuotePrice(quote);
98
- if (
99
- !Number.isFinite(quoteTime)
100
- || !Number.isFinite(quotePrice)
101
- || quotePrice <= 0
102
- || quoteTime > now + MAX_LIVE_QUOTE_CLOCK_SKEW_MS
103
- || now - quoteTime > MAX_LIVE_QUOTE_TAIL_AGE_MS
104
- ) {
105
- return points;
106
- }
107
-
108
- const latest = points.at(-1);
109
- if (!latest) return points;
110
-
111
- const latestTime = getPointTime(latest);
112
- if (!Number.isFinite(latestTime) || quoteTime < latestTime) return points;
113
-
114
- const previous = points.at(-2);
115
- const latestInterval = previous ? latestTime - getPointTime(previous) : Number.NaN;
116
- if (
117
- latestInterval > 0
118
- && latestInterval <= MAX_INTRADAY_BAR_INTERVAL_MS
119
- && quoteTime - latestTime > Math.max(MIN_LIVE_QUOTE_TAIL_GAP_MS, latestInterval * 3)
120
- ) {
121
- return points;
122
- }
123
-
124
- const latestClose = latest.close;
125
- if (hasLikelyQuoteUnitMismatch(
126
- { currency: quote.currency, price: latestClose },
127
- { currency: quote.currency, price: quotePrice },
128
- )) {
129
- return points;
130
- }
131
-
132
- if (options.mode === "ohlc") {
133
- if (quoteBelongsToLatestBar(latestTime, quoteTime, options.resolution)) {
134
- const merged = mergeQuoteIntoLatestBar(latest, quotePrice);
135
- return [...points.slice(0, -1), merged];
136
- }
137
- return [
138
- ...points,
139
- {
140
- date: new Date(quoteTime),
141
- open: quotePrice,
142
- high: quotePrice,
143
- low: quotePrice,
144
- close: quotePrice,
145
- },
146
- ];
147
- }
148
-
149
- if (quoteTime === latestTime) return points;
150
-
151
- return [
152
- ...points,
153
- {
154
- date: new Date(quoteTime),
155
- close: quotePrice,
156
- },
157
- ];
158
- }
159
-
160
- /**
161
- * Given the visible time span in milliseconds, return a generic bar size label
162
- * for fetching higher-resolution data, or null if the base data is sufficient.
163
- */
164
- export function resolveBarSize(visibleTimeSpanMs: number): string | null {
165
- if (visibleTimeSpanMs < MS_DAY) return "5m";
166
- if (visibleTimeSpanMs < 3 * MS_DAY) return "15m";
167
- if (visibleTimeSpanMs < 28 * MS_DAY) return "1h";
168
- if (visibleTimeSpanMs < 90 * MS_DAY) return "1d";
169
- return null;
170
- }
@@ -1,8 +1,9 @@
1
1
  import type { PricePoint } from "../../../types/financials";
2
- import { clampChartZoom, getVisiblePointCount } from "./viewport";
3
- import { TIME_RANGES, type ChartDateWindow, type TimeRange, type VisibleWindow } from "./types";
2
+ import type { TimeRange, VisibleWindow } from "./types";
3
+ import type { DateWindowRange } from "../../../time-series/date-window";
4
+ import { subtractTimeRange } from "../../../time-series/date-window";
4
5
 
5
- export interface VisibleDateWindow {
6
+ interface VisibleDateWindow {
6
7
  start: Date | null;
7
8
  end: Date | null;
8
9
  dates: Date[];
@@ -11,60 +12,6 @@ export interface VisibleDateWindow {
11
12
  totalDates: number;
12
13
  }
13
14
 
14
- export interface DateWindowRange extends ChartDateWindow {}
15
-
16
- export interface DateWindowViewport {
17
- panOffset: number;
18
- zoomLevel: number;
19
- }
20
-
21
- export function subtractTimeRange(endDate: Date, range: TimeRange): Date {
22
- const startDate = new Date(endDate);
23
- switch (range) {
24
- case "1D":
25
- startDate.setDate(startDate.getDate() - 1);
26
- break;
27
- case "1W":
28
- startDate.setDate(startDate.getDate() - 7);
29
- break;
30
- case "1M":
31
- startDate.setMonth(startDate.getMonth() - 1);
32
- break;
33
- case "3M":
34
- startDate.setMonth(startDate.getMonth() - 3);
35
- break;
36
- case "6M":
37
- startDate.setMonth(startDate.getMonth() - 6);
38
- break;
39
- case "1Y":
40
- startDate.setFullYear(startDate.getFullYear() - 1);
41
- break;
42
- case "5Y":
43
- startDate.setFullYear(startDate.getFullYear() - 5);
44
- break;
45
- case "ALL":
46
- startDate.setFullYear(startDate.getFullYear() - 50);
47
- break;
48
- }
49
- return startDate;
50
- }
51
-
52
- export function isDateWindowWithinTimeRange(startDate: Date, endDate: Date, maxRange: TimeRange): boolean {
53
- if (maxRange === "ALL") return true;
54
- return startDate.getTime() >= subtractTimeRange(endDate, maxRange).getTime();
55
- }
56
-
57
- export function getTimeRangeForDateWindow(
58
- window: DateWindowRange | null,
59
- ): TimeRange {
60
- if (!window?.start || !window.end) return "ALL";
61
- return TIME_RANGES.find((candidate) => isDateWindowWithinTimeRange(window.start!, window.end!, candidate)) ?? "ALL";
62
- }
63
-
64
- function clamp(value: number, min: number, max: number): number {
65
- return Math.max(min, Math.min(max, value));
66
- }
67
-
68
15
  function coerceDate(value: Date | string | number): Date {
69
16
  return value instanceof Date ? value : new Date(value);
70
17
  }
@@ -149,29 +96,10 @@ function resolveMinimumPointWindow(
149
96
  return { startIdx, endIdx };
150
97
  }
151
98
 
152
- export function getPointDates(points: readonly Pick<PricePoint, "date">[]): Date[] {
99
+ function getPointDates(points: readonly Pick<PricePoint, "date">[]): Date[] {
153
100
  return points.map((point) => coerceDate(point.date as Date | string | number));
154
101
  }
155
102
 
156
- export function getDateWindowBounds(dates: readonly Date[]): DateWindowRange | null {
157
- if (dates.length === 0) return null;
158
- return {
159
- start: dates[0] ?? null,
160
- end: dates[dates.length - 1] ?? null,
161
- };
162
- }
163
-
164
- export function getMinimumDateStepMs(dates: readonly Date[]): number {
165
- let minimum = Number.POSITIVE_INFINITY;
166
- for (let index = 1; index < dates.length; index += 1) {
167
- const delta = dates[index]!.getTime() - dates[index - 1]!.getTime();
168
- if (delta > 0 && delta < minimum) {
169
- minimum = delta;
170
- }
171
- }
172
- return Number.isFinite(minimum) ? minimum : 1;
173
- }
174
-
175
103
  export function buildPresetDateWindow(dates: readonly Date[], presetRange: TimeRange): DateWindowRange | null {
176
104
  if (dates.length === 0) return null;
177
105
  if (presetRange === "ALL") {
@@ -191,134 +119,7 @@ export function buildPresetDateWindow(dates: readonly Date[], presetRange: TimeR
191
119
  };
192
120
  }
193
121
 
194
- export function sameDateWindow(
195
- left: DateWindowRange | null | undefined,
196
- right: DateWindowRange | null | undefined,
197
- toleranceMs = 1,
198
- ): boolean {
199
- if (!left?.start || !left.end || !right?.start || !right.end) {
200
- return left?.start === right?.start && left?.end === right?.end;
201
- }
202
- return Math.abs(left.start.getTime() - right.start.getTime()) <= toleranceMs
203
- && Math.abs(left.end.getTime() - right.end.getTime()) <= toleranceMs;
204
- }
205
-
206
- export function clampDateWindowToBounds(
207
- window: DateWindowRange | null | undefined,
208
- bounds: DateWindowRange | null | undefined,
209
- minimumSpanMs = 1,
210
- ): DateWindowRange | null {
211
- const normalizedWindow = normalizeDateWindowRange(window);
212
- const normalizedBounds = normalizeDateWindowRange(bounds);
213
- if (!normalizedWindow || !normalizedBounds) return null;
214
-
215
- const availableSpanMs = Math.max(normalizedBounds.endMs - normalizedBounds.startMs, 0);
216
- const effectiveMinimumSpanMs = availableSpanMs === 0
217
- ? 0
218
- : Math.min(Math.max(minimumSpanMs, 1), availableSpanMs);
219
- const requestedSpanMs = Math.max(normalizedWindow.endMs - normalizedWindow.startMs, 0);
220
- const targetSpanMs = Math.min(
221
- Math.max(requestedSpanMs, effectiveMinimumSpanMs),
222
- availableSpanMs,
223
- );
224
-
225
- if (availableSpanMs === 0 || targetSpanMs === 0) {
226
- return {
227
- start: new Date(normalizedBounds.startMs),
228
- end: new Date(normalizedBounds.endMs),
229
- };
230
- }
231
-
232
- if (targetSpanMs >= availableSpanMs) {
233
- return {
234
- start: new Date(normalizedBounds.startMs),
235
- end: new Date(normalizedBounds.endMs),
236
- };
237
- }
238
-
239
- let startMs: number;
240
- let endMs: number;
241
-
242
- if (requestedSpanMs < targetSpanMs) {
243
- const centerMs = normalizedWindow.startMs + (requestedSpanMs / 2);
244
- startMs = centerMs - (targetSpanMs / 2);
245
- endMs = centerMs + (targetSpanMs / 2);
246
- } else {
247
- startMs = normalizedWindow.startMs;
248
- endMs = normalizedWindow.startMs + targetSpanMs;
249
- }
250
-
251
- if (startMs < normalizedBounds.startMs) {
252
- startMs = normalizedBounds.startMs;
253
- endMs = startMs + targetSpanMs;
254
- } else if (endMs > normalizedBounds.endMs) {
255
- endMs = normalizedBounds.endMs;
256
- startMs = endMs - targetSpanMs;
257
- }
258
-
259
- return {
260
- start: new Date(startMs),
261
- end: new Date(endMs),
262
- };
263
- }
264
-
265
- export function shiftDateWindow(
266
- window: DateWindowRange | null | undefined,
267
- shiftRatio: number,
268
- ): DateWindowRange | null {
269
- const normalizedWindow = normalizeDateWindowRange(window);
270
- if (!normalizedWindow) return null;
271
-
272
- const spanMs = Math.max(normalizedWindow.endMs - normalizedWindow.startMs, 1);
273
- const shiftMs = spanMs * shiftRatio;
274
-
275
- return {
276
- start: new Date(normalizedWindow.startMs - shiftMs),
277
- end: new Date(normalizedWindow.endMs - shiftMs),
278
- };
279
- }
280
-
281
- function getCanonicalVisiblePointCount(dates: readonly Date[], presetRange: TimeRange): number {
282
- if (dates.length === 0) return 0;
283
- if (presetRange === "ALL") return dates.length;
284
- const endDate = dates[dates.length - 1]!;
285
- const threshold = subtractTimeRange(endDate, presetRange).getTime();
286
- const firstVisibleIndex = dates.findIndex((date) => date.getTime() >= threshold);
287
- if (firstVisibleIndex < 0) return dates.length;
288
- return Math.max(dates.length - firstVisibleIndex, 1);
289
- }
290
-
291
- export function getCanonicalZoomLevel(dates: readonly Date[], presetRange: TimeRange): number {
292
- if (dates.length === 0) return 1;
293
- const visibleCount = getCanonicalVisiblePointCount(dates, presetRange);
294
- return clampChartZoom(dates.length, dates.length / Math.max(visibleCount, 1));
295
- }
296
-
297
- export function buildVisibleDateWindow(
298
- dates: readonly Date[],
299
- panOffset: number,
300
- zoomLevel: number,
301
- ): VisibleDateWindow {
302
- if (dates.length === 0) {
303
- return { start: null, end: null, dates: [], startIdx: 0, endIdx: 0, totalDates: 0 };
304
- }
305
- const visibleCount = getVisiblePointCount(dates.length, zoomLevel);
306
- const maxPan = Math.max(dates.length - visibleCount, 0);
307
- const pan = clamp(panOffset, 0, maxPan);
308
- const endIdx = dates.length - pan;
309
- const startIdx = Math.max(endIdx - visibleCount, 0);
310
- const visibleDates = dates.slice(startIdx, endIdx);
311
- return {
312
- start: visibleDates[0] ?? null,
313
- end: visibleDates[visibleDates.length - 1] ?? null,
314
- dates: visibleDates,
315
- startIdx,
316
- endIdx,
317
- totalDates: dates.length,
318
- };
319
- }
320
-
321
- export function buildVisibleDateWindowFromRange(
122
+ function buildVisibleDateWindowFromRange(
322
123
  dates: readonly Date[],
323
124
  window: DateWindowRange | null | undefined,
324
125
  minimumPoints = 2,
@@ -352,26 +153,6 @@ export function buildVisibleDateWindowFromRange(
352
153
  };
353
154
  }
354
155
 
355
- export function resolveViewportForDateWindow(
356
- dates: readonly Date[],
357
- window: DateWindowRange | null | undefined,
358
- minimumPoints = 2,
359
- ): DateWindowViewport | null {
360
- if (dates.length === 0) return null;
361
- const visibleWindow = buildVisibleDateWindowFromRange(dates, window, minimumPoints);
362
- if (visibleWindow.dates.length === 0) return null;
363
-
364
- const visibleCount = Math.max(visibleWindow.dates.length, 1);
365
- const zoomLevel = clampChartZoom(dates.length, dates.length / visibleCount);
366
- const maxPanOffset = Math.max(dates.length - visibleCount, 0);
367
- const panOffset = clamp(dates.length - visibleWindow.endIdx, 0, maxPanOffset);
368
-
369
- return {
370
- panOffset,
371
- zoomLevel,
372
- };
373
- }
374
-
375
156
  export function getVisibleWindowForDateRange(
376
157
  points: readonly PricePoint[],
377
158
  window: DateWindowRange | null | undefined,
@@ -1,4 +1,5 @@
1
1
  import type { ChartColors } from "./types";
2
+ import { blendHex } from "../../../theme/color-utils";
2
3
 
3
4
  interface ChartPaletteInput {
4
5
  bg: string;
@@ -17,18 +18,6 @@ export interface ResolvedChartPalette extends ChartColors {
17
18
  wickDown: string;
18
19
  }
19
20
 
20
- function blendHex(a: string, b: string, ratio: number): string {
21
- const parse = (hex: string) => {
22
- const h = hex.replace("#", "");
23
- return [parseInt(h.slice(0, 2), 16), parseInt(h.slice(2, 4), 16), parseInt(h.slice(4, 6), 16)] as const;
24
- };
25
-
26
- const [ar, ag, ab] = parse(a);
27
- const [br, bg, bb] = parse(b);
28
- const mix = (x: number, y: number) => Math.round(x + (y - x) * ratio).toString(16).padStart(2, "0");
29
- return `#${mix(ar, br)}${mix(ag, bg)}${mix(ab, bb)}`;
30
- }
31
-
32
21
  export function resolveChartPalette(
33
22
  baseColors: ChartPaletteInput,
34
23
  trend: "positive" | "negative" | "neutral" = "positive",
@@ -1,5 +1,4 @@
1
1
  import type { NativeRendererHost as CliRenderer } from "../../../ui";
2
- import { sameCursorPosition, type ChartCursorMotionKind } from "../cursor-motion";
3
2
 
4
3
  type RendererMetricsHost = Pick<CliRenderer, "resolution" | "terminalWidth" | "terminalHeight">;
5
4
 
@@ -36,8 +35,6 @@ export interface ChartMouseEvent {
36
35
  };
37
36
  }
38
37
 
39
- export type MouseInteractionEvent = Pick<ChartMouseEvent, "stopPropagation" | "preventDefault">;
40
-
41
38
  export function consumeChartMouseEvent(event: Pick<ChartMouseEvent, "stopPropagation" | "preventDefault">): void {
42
39
  event.stopPropagation?.();
43
40
  event.preventDefault?.();
@@ -51,46 +48,10 @@ export interface LocalPlotPointer {
51
48
  hasPixelPrecision: boolean;
52
49
  }
53
50
 
54
- export interface DisplayCursorState {
55
- cellX: number | null;
56
- cellY: number | null;
57
- pixelX: number | null;
58
- pixelY: number | null;
59
- }
60
-
61
- export const EMPTY_DISPLAY_CURSOR: DisplayCursorState = {
62
- cellX: null,
63
- cellY: null,
64
- pixelX: null,
65
- pixelY: null,
66
- };
67
-
68
- export const PIXEL_CURSOR_SNAP_DISTANCE = 0.5;
69
-
70
- const globalAnimationFrame = globalThis as typeof globalThis & {
71
- requestAnimationFrame?: (callback: (timestamp: number) => void) => number;
72
- cancelAnimationFrame?: (handle: number) => void;
73
- };
74
-
75
51
  function clamp(value: number, min: number, max: number): number {
76
52
  return Math.max(min, Math.min(max, value));
77
53
  }
78
54
 
79
- export function requestAnimationFrameSafe(callback: (timestamp: number) => void): number {
80
- if (typeof globalAnimationFrame.requestAnimationFrame === "function") {
81
- return globalAnimationFrame.requestAnimationFrame(callback);
82
- }
83
- return globalThis.setTimeout(() => callback(Date.now()), 16) as unknown as number;
84
- }
85
-
86
- export function cancelAnimationFrameSafe(handle: number) {
87
- if (typeof globalAnimationFrame.cancelAnimationFrame === "function") {
88
- globalAnimationFrame.cancelAnimationFrame(handle);
89
- return;
90
- }
91
- clearTimeout(handle);
92
- }
93
-
94
55
  function getRendererCellMetrics(renderer: RendererMetricsHost) {
95
56
  if (!renderer.resolution) return null;
96
57
  const cellWidth = renderer.resolution.width / Math.max(renderer.terminalWidth, 1);
@@ -129,47 +90,6 @@ function getPlotBounds(renderable: PlotRenderableLike | null): { x: number; y: n
129
90
  return { x, y, width: size.width, height: size.height };
130
91
  }
131
92
 
132
- export function getRenderablePixelSize(
133
- renderable: RenderableSizeLike | null,
134
- renderer: RendererMetricsHost,
135
- ) {
136
- const metrics = getRendererCellMetrics(renderer);
137
- const size = getRenderableSize(renderable);
138
- if (!size || !metrics) return null;
139
- return {
140
- pixelWidth: Math.max(size.width * metrics.cellWidth, 1),
141
- pixelHeight: Math.max(size.height * metrics.cellHeight, 1),
142
- };
143
- }
144
-
145
- export function projectCellCursorToLocalPixels(
146
- cellX: number,
147
- cellY: number,
148
- renderable: RenderableSizeLike | null,
149
- renderer: RendererMetricsHost,
150
- ): { pixelX: number; pixelY: number } | null {
151
- const pixelSize = getRenderablePixelSize(renderable, renderer);
152
- const size = getRenderableSize(renderable);
153
- if (!size || !pixelSize) return null;
154
-
155
- return {
156
- pixelX: size.width <= 1
157
- ? 0
158
- : clamp(
159
- (cellX / Math.max(size.width - 1, 1)) * Math.max(pixelSize.pixelWidth - 1, 0),
160
- 0,
161
- Math.max(pixelSize.pixelWidth - 1, 0),
162
- ),
163
- pixelY: size.height <= 1
164
- ? 0
165
- : clamp(
166
- (cellY / Math.max(size.height - 1, 1)) * Math.max(pixelSize.pixelHeight - 1, 0),
167
- 0,
168
- Math.max(pixelSize.pixelHeight - 1, 0),
169
- ),
170
- };
171
- }
172
-
173
93
  export function scaleLocalPixelCoordinate(value: number | null, sourceExtent: number, targetExtent: number): number | null {
174
94
  if (value === null) return null;
175
95
  if (targetExtent <= 1) return 0;
@@ -183,55 +103,6 @@ export function scaleLocalPixelCoordinate(value: number | null, sourceExtent: nu
183
103
  );
184
104
  }
185
105
 
186
- export function toCursorPosition(x: number | null, y: number | null) {
187
- return { x, y };
188
- }
189
-
190
- export function sameDisplayCursorState(
191
- left: DisplayCursorState,
192
- right: DisplayCursorState,
193
- cellEpsilon = 0,
194
- pixelEpsilon = 0,
195
- ): boolean {
196
- return sameCursorPosition(toCursorPosition(left.cellX, left.cellY), toCursorPosition(right.cellX, right.cellY), cellEpsilon)
197
- && sameCursorPosition(toCursorPosition(left.pixelX, left.pixelY), toCursorPosition(right.pixelX, right.pixelY), pixelEpsilon);
198
- }
199
-
200
- export function buildDisplayCursorState(
201
- cellX: number | null,
202
- cellY: number | null,
203
- renderable: RenderableSizeLike | null,
204
- renderer: RendererMetricsHost,
205
- pixelX: number | null = null,
206
- pixelY: number | null = null,
207
- ): DisplayCursorState {
208
- if (cellX === null || cellY === null) return EMPTY_DISPLAY_CURSOR;
209
- if (pixelX !== null && pixelY !== null) {
210
- return { cellX, cellY, pixelX, pixelY };
211
- }
212
- const derivedPixels = projectCellCursorToLocalPixels(cellX, cellY, renderable, renderer);
213
- return {
214
- cellX,
215
- cellY,
216
- pixelX: derivedPixels?.pixelX ?? null,
217
- pixelY: derivedPixels?.pixelY ?? null,
218
- };
219
- }
220
-
221
- export function resolveSelectionDisplayCursorState(
222
- cursorX: number | null,
223
- cursorY: number | null,
224
- fallbackCursorX: number | null,
225
- fallbackCursorY: number | null,
226
- renderable: RenderableSizeLike | null,
227
- renderer: RendererMetricsHost,
228
- ): DisplayCursorState {
229
- const resolvedCursorX = cursorY === null ? (fallbackCursorX ?? cursorX) : cursorX;
230
- const resolvedCursorY = cursorY ?? fallbackCursorY;
231
- if (resolvedCursorX === null) return EMPTY_DISPLAY_CURSOR;
232
- return buildDisplayCursorState(resolvedCursorX, resolvedCursorY, renderable, renderer);
233
- }
234
-
235
106
  export function getLocalPlotPointer(
236
107
  event: ChartMouseEvent,
237
108
  renderable: PlotRenderableLike | null,
@@ -305,16 +176,3 @@ export function getGlobalMouseX(
305
176
  if (event.pixelX === undefined || !metrics) return event.x;
306
177
  return event.pixelX / metrics.cellWidth;
307
178
  }
308
-
309
- export function resolveCursorMotionKind(
310
- event: ChartMouseEvent,
311
- renderer: RendererMetricsHost,
312
- ): ChartCursorMotionKind {
313
- return event.pixelX !== undefined && event.pixelY !== undefined && getRendererCellMetrics(renderer)
314
- ? "pixel"
315
- : "cell";
316
- }
317
-
318
- export function buildBlankPlotLines(width: number, height: number): string[] {
319
- return Array.from({ length: height }, () => " ".repeat(width));
320
- }