gloomberb 0.18.2 → 0.18.4

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 (954) hide show
  1. package/README.md +8 -8
  2. package/README.zh-CN.md +11 -11
  3. package/bin/{gloomberb → gloom} +3 -1
  4. package/package.json +6 -2
  5. package/patches/electrobun@1.18.1.patch +106 -5
  6. package/src/account/checkout-handoff.tsx +225 -0
  7. package/src/account/device-signin-dialog.tsx +2 -2
  8. package/src/account/device-signin.ts +2 -2
  9. package/src/account/upgrade-dialog.tsx +1 -1
  10. package/src/api-client/askg.ts +2 -2
  11. package/src/api-client/auth.ts +2 -2
  12. package/src/api-client/central-bank-rates.ts +6 -0
  13. package/src/api-client/collections.ts +5 -1
  14. package/src/api-client/cot.ts +2 -0
  15. package/src/api-client/crypto-etf-flows.ts +37 -0
  16. package/src/api-client/crypto-markets.ts +60 -0
  17. package/src/api-client/data.ts +99 -5
  18. package/src/api-client/doe.ts +15 -0
  19. package/src/api-client/equity-screener.ts +28 -0
  20. package/src/api-client/exchange-announcements.ts +38 -0
  21. package/src/api-client/fund-facts.ts +39 -0
  22. package/src/api-client/futures-curve.ts +9 -1
  23. package/src/api-client/hiring.ts +301 -0
  24. package/src/api-client/index.ts +24 -5
  25. package/src/api-client/market-discovery.ts +14 -0
  26. package/src/api-client/members.ts +6 -0
  27. package/src/api-client/mna.ts +6 -0
  28. package/src/api-client/paths.ts +18 -1
  29. package/src/api-client/request.ts +26 -7
  30. package/src/api-client/short-side-publications.ts +37 -0
  31. package/src/api-client/socket.ts +64 -4
  32. package/src/api-client/swap-curve.ts +35 -0
  33. package/src/api-client/telemetry.ts +17 -0
  34. package/src/api-client/themes.ts +7 -1
  35. package/src/api-client/types.ts +90 -2
  36. package/src/app/global-shortcuts.ts +1 -16
  37. package/src/app/pane-runtime/plugin-bindings.ts +9 -2
  38. package/src/app/runtime/desktop-deeplink.ts +5 -5
  39. package/src/app/runtime/plugin-bindings.ts +2 -2
  40. package/src/app/runtime/startup.ts +13 -0
  41. package/src/app/runtime/update.ts +28 -8
  42. package/src/app/star-prompt/status-line.tsx +2 -2
  43. package/src/architecture/core-builtin-allowlist.json +5 -2
  44. package/src/architecture/pane-tabs-allowlist.json +65 -0
  45. package/src/architecture/ui-literals-allowlist.json +3 -3
  46. package/src/architecture/ui-tokens-allowlist.json +1 -1
  47. package/src/brokers/broker-portfolio-sync.ts +37 -0
  48. package/src/brokers/directory.ts +11 -0
  49. package/src/brokers/logos.ts +3 -1
  50. package/src/brokers/signed-in/adapter.ts +304 -26
  51. package/src/brokers/signed-in/client.ts +14 -2
  52. package/src/brokers/signed-in/connect.ts +10 -2
  53. package/src/brokers/sync-broker-instance.ts +9 -1
  54. package/src/capabilities/chart-series.ts +22 -6
  55. package/src/cli/bank-section.ts +1 -1
  56. package/src/cli/base-converter.ts +23 -14
  57. package/src/cli/central-bank-events.ts +1 -1
  58. package/src/cli/command-options.ts +59 -4
  59. package/src/cli/commands/api.ts +9 -6
  60. package/src/cli/commands/broker.ts +2 -2
  61. package/src/cli/commands/command-utils.ts +2 -2
  62. package/src/cli/commands/crypto-hints.ts +7 -20
  63. package/src/cli/commands/fred-series.ts +4 -2
  64. package/src/cli/commands/keybindings.ts +2 -2
  65. package/src/cli/commands/market.ts +1189 -296
  66. package/src/cli/commands/news-hints.ts +2 -2
  67. package/src/cli/commands/news-search.ts +59 -6
  68. package/src/cli/commands/options-leaps.ts +41 -26
  69. package/src/cli/commands/overview.ts +121 -48
  70. package/src/cli/commands/plugins.ts +9 -9
  71. package/src/cli/commands/remote.ts +13 -10
  72. package/src/cli/commands/search.ts +64 -44
  73. package/src/cli/commands/system.ts +27 -19
  74. package/src/cli/commands/themes.ts +1 -1
  75. package/src/cli/commands/ticker.ts +272 -70
  76. package/src/cli/context.ts +3 -2
  77. package/src/cli/desktop-pane-shot-view.ts +2 -2
  78. package/src/cli/desktop-pane-shot.ts +1 -1
  79. package/src/cli/earnings-calendar.ts +4 -4
  80. package/src/cli/entry.ts +18 -1
  81. package/src/cli/errors.ts +20 -2
  82. package/src/cli/exit-codes.ts +1 -1
  83. package/src/cli/export-source.ts +10 -4
  84. package/src/cli/freshness.ts +2 -8
  85. package/src/cli/fx-forward.ts +130 -0
  86. package/src/cli/fx-pair.ts +10 -9
  87. package/src/cli/glossary.ts +64 -20
  88. package/src/cli/help.ts +20 -14
  89. package/src/cli/history-export.ts +126 -0
  90. package/src/cli/history-rows.ts +196 -43
  91. package/src/cli/index-roots.ts +5 -45
  92. package/src/cli/index.ts +32 -18
  93. package/src/cli/issuer-membership.ts +103 -0
  94. package/src/cli/known-gaps.ts +118 -25
  95. package/src/cli/listing-arg.ts +315 -43
  96. package/src/cli/name-entries.ts +73 -22
  97. package/src/cli/native-smoke.ts +2 -0
  98. package/src/cli/not-a-ticker.ts +19 -9
  99. package/src/cli/opentui-libc.ts +5 -0
  100. package/src/cli/options.ts +12 -0
  101. package/src/cli/pane-functions/capabilities.ts +77 -20
  102. package/src/cli/pane-functions/catalog.ts +40 -23
  103. package/src/cli/pane-functions/discovery.ts +1 -1
  104. package/src/cli/pane-functions/dom.ts +12 -8
  105. package/src/cli/pane-functions/financial-ratio-shot.ts +2 -2
  106. package/src/cli/pane-functions/freshness.ts +174 -23
  107. package/src/cli/pane-functions/function-help.ts +66 -27
  108. package/src/cli/pane-functions/headless.ts +48 -16
  109. package/src/cli/pane-functions/index.ts +82 -21
  110. package/src/cli/pane-functions/options.ts +22 -2
  111. package/src/cli/pane-functions/report-notices.ts +12 -4
  112. package/src/cli/pane-functions/report.ts +5 -5
  113. package/src/cli/pane-functions/resolver.ts +65 -14
  114. package/src/cli/pane-functions/screenshot-assessment.ts +322 -0
  115. package/src/cli/pane-functions/screenshot-bridge.ts +152 -0
  116. package/src/cli/pane-functions/screenshot-chart-evidence.ts +396 -0
  117. package/src/cli/pane-functions/screenshot-data-evidence.ts +383 -0
  118. package/src/cli/pane-functions/screenshot-evidence.ts +1 -1
  119. package/src/cli/pane-functions/screenshot-payload.ts +453 -0
  120. package/src/cli/pane-functions/screenshot-render.ts +316 -0
  121. package/src/cli/pane-functions/screenshot-types.ts +162 -0
  122. package/src/cli/pane-functions/shot-options.ts +8 -3
  123. package/src/cli/peso-dollar-rates.ts +79 -0
  124. package/src/cli/quote-answer.ts +38 -3
  125. package/src/cli/report-tables.ts +190 -27
  126. package/src/cli/restore-plugins.ts +29 -14
  127. package/src/cli/result.ts +122 -25
  128. package/src/cli/series-search.ts +5 -5
  129. package/src/cli/statement-filings.ts +19 -0
  130. package/src/cli/suffixed-listing-rows.ts +49 -0
  131. package/src/cli/symbol-args.ts +50 -15
  132. package/src/cli/symbol-cells.ts +120 -0
  133. package/src/cli/symbol-list.ts +226 -60
  134. package/src/cli/symbol-rows.ts +131 -25
  135. package/src/cli/ticker-resolution.ts +108 -11
  136. package/src/cli/treasury-yields.ts +5 -5
  137. package/src/cli/types.ts +2 -0
  138. package/src/cli/uncovered-instrument.ts +3 -3
  139. package/src/cli/unknown-command.ts +6 -6
  140. package/src/components/chart/composite/chart-layout.ts +131 -0
  141. package/src/components/chart/composite/composite-chart.tsx +387 -21
  142. package/src/components/chart/composite/drawing-store.ts +26 -6
  143. package/src/components/chart/composite/interactions.ts +9 -3
  144. package/src/components/chart/composite/legend.tsx +75 -3
  145. package/src/components/chart/composite/levels.ts +5 -0
  146. package/src/components/chart/composite/panel-gestures.ts +41 -0
  147. package/src/components/chart/composite/panel-labels.ts +2 -1
  148. package/src/components/chart/composite/panel-surface.tsx +316 -11
  149. package/src/components/chart/composite/price-axis-labels.tsx +27 -3
  150. package/src/components/chart/composite/rasterizer.ts +44 -19
  151. package/src/components/chart/composite/scene.ts +16 -4
  152. package/src/components/chart/composite/text-renderer.ts +48 -21
  153. package/src/components/chart/composite/toolbar.tsx +52 -5
  154. package/src/components/chart/composite/types.ts +19 -0
  155. package/src/components/chart/composite/use-composite-chart-keyboard.ts +120 -13
  156. package/src/components/chart/composite/use-composite-value-scales.ts +44 -0
  157. package/src/components/chart/composite/use-composite-viewport.ts +12 -3
  158. package/src/components/chart/composite/value-scale.ts +149 -0
  159. package/src/components/chart/composite/volume-profile-paint.ts +6 -3
  160. package/src/components/chart/core/pointer.ts +2 -0
  161. package/src/components/chart-table/index.ts +2 -0
  162. package/src/components/chart-table/read.tsx +74 -0
  163. package/src/components/command-bar/commands/collection-list.ts +41 -19
  164. package/src/components/command-bar/commands/collection.ts +9 -3
  165. package/src/components/command-bar/commands/direct/index.ts +1 -1
  166. package/src/components/command-bar/commands/direct/runtime.ts +3 -2
  167. package/src/components/command-bar/pane-templates/items.ts +59 -6
  168. package/src/components/command-bar/pane-templates/workflow.ts +10 -1
  169. package/src/components/command-bar/routes/root/command-items.ts +32 -6
  170. package/src/components/command-bar/routes/root/plugin-install.ts +1 -1
  171. package/src/components/command-bar/routes/root/provider-search.ts +42 -11
  172. package/src/components/command-bar/routes/root/results.ts +18 -4
  173. package/src/components/command-bar/routes/root/runtime.ts +15 -3
  174. package/src/components/command-bar/routes/root/search-providers.ts +25 -2
  175. package/src/components/command-bar/routes/root/selection.ts +6 -1
  176. package/src/components/command-bar/routes/root/shortcut-feedback.ts +4 -1
  177. package/src/components/command-bar/routes/root/shortcuts.ts +30 -3
  178. package/src/components/command-bar/routes/ticker-search/results.ts +73 -4
  179. package/src/components/command-bar/selection-runtime.ts +50 -10
  180. package/src/components/command-bar/surface/index.tsx +24 -2
  181. package/src/components/command-bar/view-model.ts +7 -0
  182. package/src/components/command-bar/workflow/broker.ts +2 -2
  183. package/src/components/command-bar/workflow/collection-actions.ts +46 -7
  184. package/src/components/command-bar/workflow/collection-ticker.ts +32 -4
  185. package/src/components/command-bar/workflow/fields.ts +8 -2
  186. package/src/components/command-bar/workflow/ops.ts +18 -4
  187. package/src/components/command-bar/workflow/portfolio-position.ts +53 -4
  188. package/src/components/command-bar/workflow/submit.ts +3 -2
  189. package/src/components/command-bar/workflow/tickers.ts +5 -1
  190. package/src/components/company-logo.tsx +39 -0
  191. package/src/components/data-table/sections.ts +4 -2
  192. package/src/components/data-table/view.tsx +23 -3
  193. package/src/components/form-modal/confirm.tsx +2 -1
  194. package/src/components/form-modal/request.ts +5 -0
  195. package/src/components/form-modal/routes.ts +4 -1
  196. package/src/components/index.ts +13 -6
  197. package/src/components/layout/detached-pane-shell.tsx +1 -0
  198. package/src/components/layout/floating-pane.tsx +1 -0
  199. package/src/components/layout/header.tsx +234 -60
  200. package/src/components/layout/market-summary.ts +9 -6
  201. package/src/components/layout/pane/capture-status.ts +1 -1
  202. package/src/components/layout/pane/footer/model.ts +11 -5
  203. package/src/components/layout/pane/header.tsx +10 -3
  204. package/src/components/layout/pane/index.tsx +1 -0
  205. package/src/components/layout/pane/pane-tabs.tsx +9 -1
  206. package/src/components/layout/shell/chrome.ts +19 -6
  207. package/src/components/layout/shell/index.tsx +2 -1
  208. package/src/components/layout/shell/pane/layers.tsx +19 -1
  209. package/src/components/layout/status-bar.tsx +2 -2
  210. package/src/components/market-board/index.tsx +11 -3
  211. package/src/components/onboarding/onboarding-wizard.tsx +1 -0
  212. package/src/components/onboarding/portfolio-step/broker-setup-panel.tsx +2 -2
  213. package/src/components/onboarding/wizard-broker-sync.ts +4 -1
  214. package/src/components/pane-settings-dialog/desktop.tsx +20 -7
  215. package/src/components/pane-settings-dialog/tui.tsx +17 -9
  216. package/src/components/pane-settings-dialog/value.ts +8 -1
  217. package/src/components/pane-settings-dialog.tsx +44 -13
  218. package/src/components/sign-in-code-panel.tsx +27 -19
  219. package/src/components/ui/column-grid.tsx +48 -4
  220. package/src/components/ui/country-flag-art.tsx +180 -0
  221. package/src/components/ui/country-flag.tsx +118 -12
  222. package/src/components/ui/data-table/opentui/index.tsx +61 -2
  223. package/src/components/ui/data-table/opentui/model.ts +109 -2
  224. package/src/components/ui/data-table/types.ts +1 -1
  225. package/src/components/ui/display.tsx +5 -1
  226. package/src/components/ui/index.ts +3 -1
  227. package/src/components/ui/logo-mark.tsx +11 -2
  228. package/src/components/ui/query-bar.tsx +1 -1
  229. package/src/components/ui/row-notes.ts +79 -0
  230. package/src/components/ui/stat-grid.tsx +28 -3
  231. package/src/components/ui/status.tsx +3 -1
  232. package/src/core/app-services.ts +4 -0
  233. package/src/core/state/app/layout.ts +4 -4
  234. package/src/data/cached-query.ts +8 -1
  235. package/src/data/config/chart-settings.ts +3 -3
  236. package/src/data/config/home.ts +10 -2
  237. package/src/data/config/layout.ts +4 -1
  238. package/src/data/config/store/node.ts +4 -0
  239. package/src/data/config/store/normalize.ts +13 -3
  240. package/src/data/config/store/portfolio-as-of-column.ts +2 -2
  241. package/src/data/json-storage.ts +2 -0
  242. package/src/data/saved-copies.ts +84 -0
  243. package/src/docs/snapshot.json +65 -32
  244. package/src/i18n/es.ts +51 -12
  245. package/src/i18n/ja.ts +51 -12
  246. package/src/i18n/ko.ts +51 -12
  247. package/src/i18n/zh-cn.ts +51 -12
  248. package/src/i18n/zh-tw.ts +51 -12
  249. package/src/layout/desks.ts +1 -1
  250. package/src/layout/launch-layout.ts +1 -1
  251. package/src/layout/pane-manager/floating-actions.ts +5 -3
  252. package/src/layout/pane-manager/floating.ts +43 -1
  253. package/src/layout/pane-manager/index.ts +2 -0
  254. package/src/layout/selected-ticker.ts +74 -0
  255. package/src/market-data/depositary-pair.ts +251 -0
  256. package/src/market-data/futures-board.ts +1 -1
  257. package/src/market-data/futures-contract.ts +124 -40
  258. package/src/market-data/fx-closes.ts +17 -2
  259. package/src/market-data/hooks.tsx +19 -11
  260. package/src/market-data/market/change-basis.ts +49 -7
  261. package/src/market-data/market/freshness.ts +34 -5
  262. package/src/market-data/market/period-return.ts +163 -0
  263. package/src/market-data/market/trading-sessions.ts +13 -0
  264. package/src/market-data/market/year-to-date.ts +8 -13
  265. package/src/market-data/performance.ts +20 -14
  266. package/src/market-data/perpetual-premium.ts +32 -0
  267. package/src/market-data/published-apac-sessions.ts +2 -1
  268. package/src/market-data/published-futures-sessions.ts +69 -0
  269. package/src/market-data/quotes/contributions.ts +5 -1
  270. package/src/market-data/quotes/freshness.ts +42 -0
  271. package/src/market-data/quotes/intraday-bar.ts +37 -0
  272. package/src/market-data/quotes/regular-session-valuation.ts +13 -8
  273. package/src/market-data/quotes/resolution.ts +4 -2
  274. package/src/market-data/tax-equivalent.ts +1 -1
  275. package/src/market-data/ticker-price-returns.ts +3 -1
  276. package/src/news/aggregator.ts +5 -1
  277. package/src/news/news-model.ts +4 -0
  278. package/src/news/types.ts +11 -0
  279. package/src/notifications/app-notifier.ts +1 -1
  280. package/src/plugins/auto-update.ts +2 -2
  281. package/src/plugins/builtin/account-management/index.tsx +1 -0
  282. package/src/plugins/builtin/account-management/pane.tsx +9 -8
  283. package/src/plugins/builtin/alerts/alert-engine.ts +30 -18
  284. package/src/plugins/builtin/alerts/calendar-events.ts +378 -0
  285. package/src/plugins/builtin/alerts/cli.ts +485 -76
  286. package/src/plugins/builtin/alerts/command.ts +5 -10
  287. package/src/plugins/builtin/alerts/event-rows.ts +9 -5
  288. package/src/plugins/builtin/alerts/events-pane.tsx +71 -56
  289. package/src/plugins/builtin/alerts/events.ts +108 -5
  290. package/src/plugins/builtin/alerts/fired-log.ts +78 -0
  291. package/src/plugins/builtin/alerts/format.ts +2 -1
  292. package/src/plugins/builtin/alerts/headless.ts +100 -39
  293. package/src/plugins/builtin/alerts/history-pane.tsx +105 -62
  294. package/src/plugins/builtin/alerts/history-rows.ts +89 -0
  295. package/src/plugins/builtin/alerts/index.tsx +45 -18
  296. package/src/plugins/builtin/alerts/iv-level.ts +365 -0
  297. package/src/plugins/builtin/alerts/levels.ts +3 -3
  298. package/src/plugins/builtin/alerts/pane.tsx +97 -29
  299. package/src/plugins/builtin/alerts/price.ts +35 -0
  300. package/src/plugins/builtin/alerts/quotes.ts +24 -0
  301. package/src/plugins/builtin/alerts/research-builder.ts +84 -11
  302. package/src/plugins/builtin/alerts/research-rules.ts +77 -3
  303. package/src/plugins/builtin/alerts/scheduled-check.ts +206 -32
  304. package/src/plugins/builtin/alerts/scheduled-sources.ts +26 -3
  305. package/src/plugins/builtin/alerts/scheduled.ts +188 -29
  306. package/src/plugins/builtin/alerts/storage.ts +13 -10
  307. package/src/plugins/builtin/alerts/targets.ts +12 -3
  308. package/src/plugins/builtin/analytics/index.tsx +8 -2
  309. package/src/plugins/builtin/analytics/metrics.ts +1 -1
  310. package/src/plugins/builtin/analytics/risk-book.ts +215 -0
  311. package/src/plugins/builtin/analytics/risk-client.ts +13 -6
  312. package/src/plugins/builtin/analytics/risk-headless.ts +55 -21
  313. package/src/plugins/builtin/analytics/risk-math.ts +6 -3
  314. package/src/plugins/builtin/analytics/risk-model.ts +297 -104
  315. package/src/plugins/builtin/analytics/risk-options.ts +17 -2
  316. package/src/plugins/builtin/analytics/risk-pane.tsx +107 -43
  317. package/src/plugins/builtin/attention/pane.tsx +22 -16
  318. package/src/plugins/builtin/awards/headless.ts +7 -3
  319. package/src/plugins/builtin/awards/model.ts +18 -0
  320. package/src/plugins/builtin/awards/pane.tsx +12 -9
  321. package/src/plugins/builtin/backtest/export.ts +1 -1
  322. package/src/plugins/builtin/backtest/headless.ts +3 -3
  323. package/src/plugins/builtin/backtest/rules.ts +41 -5
  324. package/src/plugins/builtin/broker-manager/add-flow.tsx +12 -7
  325. package/src/plugins/builtin/broker-manager/detail.tsx +47 -19
  326. package/src/plugins/builtin/broker-manager/footer.ts +27 -11
  327. package/src/plugins/builtin/broker-manager/index.tsx +21 -12
  328. package/src/plugins/builtin/broker-manager/keyboard.ts +1 -1
  329. package/src/plugins/builtin/broker-manager/model.ts +12 -2
  330. package/src/plugins/builtin/broker-manager/pane-actions.tsx +183 -57
  331. package/src/plugins/builtin/broker-manager/table.ts +28 -12
  332. package/src/plugins/builtin/broker-trading/account-picker.tsx +2 -1
  333. package/src/plugins/builtin/broker-trading/chart-levels.ts +82 -13
  334. package/src/plugins/builtin/broker-trading/controller.ts +45 -13
  335. package/src/plugins/builtin/broker-trading/dock.tsx +24 -4
  336. package/src/plugins/builtin/broker-trading/headless.ts +2 -1
  337. package/src/plugins/builtin/broker-trading/index.tsx +7 -1
  338. package/src/plugins/builtin/broker-trading/linked-orders.ts +148 -0
  339. package/src/plugins/builtin/broker-trading/order-feed.ts +75 -7
  340. package/src/plugins/builtin/broker-trading/orders.tsx +109 -31
  341. package/src/plugins/builtin/broker-trading/overview-orders.tsx +9 -3
  342. package/src/plugins/builtin/broker-trading/pane-model.ts +30 -2
  343. package/src/plugins/builtin/broker-trading/pane.tsx +115 -26
  344. package/src/plugins/builtin/broker-trading/ticket-parts.tsx +36 -7
  345. package/src/plugins/builtin/broker-trading/ticket.tsx +122 -36
  346. package/src/plugins/builtin/buildout/cells.tsx +4 -0
  347. package/src/plugins/builtin/buildout/detail/index.tsx +5 -1
  348. package/src/plugins/builtin/buildout/detail/ui.tsx +7 -4
  349. package/src/plugins/builtin/buildout/pane/index.tsx +34 -18
  350. package/src/plugins/builtin/buildout/pane/status.tsx +0 -4
  351. package/src/plugins/builtin/builtin-plugin-meta.ts +1 -1
  352. package/src/plugins/builtin/catalysts/client.ts +2 -2
  353. package/src/plugins/builtin/catalysts/detail.tsx +3 -2
  354. package/src/plugins/builtin/catalysts/index.tsx +1 -1
  355. package/src/plugins/builtin/catalysts/model.ts +49 -4
  356. package/src/plugins/builtin/catalysts/pane.tsx +9 -11
  357. package/src/plugins/builtin/central-bank-rates/client.ts +5 -0
  358. package/src/plugins/builtin/central-bank-rates/headless.ts +36 -10
  359. package/src/plugins/builtin/central-bank-rates/model.ts +33 -8
  360. package/src/plugins/builtin/changelog/index.tsx +1 -0
  361. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +1 -0
  362. package/src/plugins/builtin/chart-composer/chart-spec-edit.ts +2 -1
  363. package/src/plugins/builtin/chart-composer/chart-spec.ts +7 -0
  364. package/src/plugins/builtin/chart-composer/cli-options.ts +2 -5
  365. package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +2 -1
  366. package/src/plugins/builtin/chart-composer/editor/controller.ts +2 -0
  367. package/src/plugins/builtin/chart-composer/editor.tsx +4 -1
  368. package/src/plugins/builtin/chart-composer/headless-schema.ts +28 -26
  369. package/src/plugins/builtin/chart-composer/headless.ts +253 -35
  370. package/src/plugins/builtin/chart-composer/index.tsx +12 -2
  371. package/src/plugins/builtin/chart-composer/leverage-overlay.ts +142 -0
  372. package/src/plugins/builtin/chart-composer/pane.tsx +128 -28
  373. package/src/plugins/builtin/chart-composer/series-catalog.ts +1 -0
  374. package/src/plugins/builtin/chart-composer/series-expression.ts +65 -6
  375. package/src/plugins/builtin/chart-composer/session-history.ts +15 -21
  376. package/src/plugins/builtin/chart-composer/session-range.ts +4 -2
  377. package/src/plugins/builtin/chart-composer/settings.ts +31 -19
  378. package/src/plugins/builtin/chart-composer/use-series-catalog.ts +5 -6
  379. package/src/plugins/builtin/chart-composer/viewport-labels.ts +18 -8
  380. package/src/plugins/builtin/chat/attachments/model.ts +3 -1
  381. package/src/plugins/builtin/chat/content/index.tsx +1 -1
  382. package/src/plugins/builtin/chat/pane-links/open.ts +1 -1
  383. package/src/plugins/builtin/chat/people.ts +1 -1
  384. package/src/plugins/builtin/clinical-trials/client.ts +5 -2
  385. package/src/plugins/builtin/clinical-trials/model.ts +13 -4
  386. package/src/plugins/builtin/clinical-trials/pane.tsx +32 -12
  387. package/src/plugins/builtin/clinical-trials/ticker-sponsor.ts +17 -0
  388. package/src/plugins/builtin/cloud/askg/controller.ts +1 -1
  389. package/src/plugins/builtin/cloud/askg/lock-note.ts +1 -1
  390. package/src/plugins/builtin/cloud/askg/tool-display.ts +1 -1
  391. package/src/plugins/builtin/cloud/auth-commands.ts +3 -3
  392. package/src/plugins/builtin/cloud/team/pane-sections.tsx +105 -47
  393. package/src/plugins/builtin/cloud/team/pane-ui.tsx +42 -4
  394. package/src/plugins/builtin/cloud/team/pane.tsx +204 -64
  395. package/src/plugins/builtin/cloud/thesis/store.ts +45 -22
  396. package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
  397. package/src/plugins/builtin/commodities-energy/index.tsx +29 -2
  398. package/src/plugins/builtin/commodities-energy/view-state.ts +2 -0
  399. package/src/plugins/builtin/commodity-balances/pane.tsx +14 -8
  400. package/src/plugins/builtin/company-attention/app-rank.tsx +11 -10
  401. package/src/plugins/builtin/company-attention/building-model.ts +222 -0
  402. package/src/plugins/builtin/company-attention/building.tsx +172 -0
  403. package/src/plugins/builtin/company-attention/client.ts +117 -1
  404. package/src/plugins/builtin/company-attention/evidence.ts +16 -3
  405. package/src/plugins/builtin/company-attention/headless.ts +101 -5
  406. package/src/plugins/builtin/company-attention/index.tsx +6 -3
  407. package/src/plugins/builtin/company-attention/model.ts +33 -7
  408. package/src/plugins/builtin/company-attention/moves-model.ts +253 -0
  409. package/src/plugins/builtin/company-attention/moves.tsx +159 -0
  410. package/src/plugins/builtin/company-attention/pane.tsx +89 -31
  411. package/src/plugins/builtin/company-attention/signals-model.ts +229 -0
  412. package/src/plugins/builtin/company-attention/signals.tsx +160 -0
  413. package/src/plugins/builtin/company-kpis/headless.ts +3 -2
  414. package/src/plugins/builtin/company-kpis/model.ts +2 -2
  415. package/src/plugins/builtin/company-kpis/pane.tsx +5 -4
  416. package/src/plugins/builtin/composite-plugins.ts +2 -1
  417. package/src/plugins/builtin/congress-trades/headless.ts +1 -1
  418. package/src/plugins/builtin/connections/index.ts +1 -0
  419. package/src/plugins/builtin/correlation/headless-schema.ts +3 -2
  420. package/src/plugins/builtin/correlation/headless.ts +7 -4
  421. package/src/plugins/builtin/correlation/relationship/model.ts +1 -0
  422. package/src/plugins/builtin/correlation/settings.ts +1 -0
  423. package/src/plugins/builtin/cot/headless.ts +28 -6
  424. package/src/plugins/builtin/cot/model.ts +12 -0
  425. package/src/plugins/builtin/cot/pane.tsx +7 -5
  426. package/src/plugins/builtin/cpi/headless.ts +5 -1
  427. package/src/plugins/builtin/cpi/pane.tsx +11 -9
  428. package/src/plugins/builtin/credit-boards/model.ts +2 -0
  429. package/src/plugins/builtin/credit-documents/headless.ts +1 -1
  430. package/src/plugins/builtin/credit-documents/pane.tsx +8 -7
  431. package/src/plugins/builtin/crypto-board/client.ts +86 -0
  432. package/src/plugins/builtin/crypto-board/defi-view.tsx +218 -0
  433. package/src/plugins/builtin/crypto-board/defi.ts +239 -0
  434. package/src/plugins/builtin/crypto-board/headless.ts +117 -6
  435. package/src/plugins/builtin/crypto-board/index.tsx +8 -3
  436. package/src/plugins/builtin/crypto-board/model.ts +40 -8
  437. package/src/plugins/builtin/crypto-board/pane.tsx +55 -21
  438. package/src/plugins/builtin/crypto-board/series.ts +19 -1
  439. package/src/plugins/builtin/crypto-etf-flows/client.ts +60 -0
  440. package/src/plugins/builtin/crypto-etf-flows/headless.ts +132 -0
  441. package/src/plugins/builtin/crypto-etf-flows/index.tsx +44 -0
  442. package/src/plugins/builtin/crypto-etf-flows/model.ts +121 -0
  443. package/src/plugins/builtin/crypto-etf-flows/pane.tsx +193 -0
  444. package/src/plugins/builtin/debt-maturities/pane.tsx +4 -3
  445. package/src/plugins/builtin/debug/index.tsx +1 -0
  446. package/src/plugins/builtin/dividend-yield/index.tsx +1 -1
  447. package/src/plugins/builtin/docs/index.tsx +1 -1
  448. package/src/plugins/builtin/docs/pane.tsx +2 -2
  449. package/src/plugins/builtin/docs/targets.ts +1 -1
  450. package/src/plugins/builtin/doe/client.ts +5 -1
  451. package/src/plugins/builtin/doe/headless.ts +12 -6
  452. package/src/plugins/builtin/doe/model.ts +43 -6
  453. package/src/plugins/builtin/doe/pane.tsx +19 -12
  454. package/src/plugins/builtin/earnings/board-model.ts +13 -6
  455. package/src/plugins/builtin/earnings/board-table.ts +4 -1
  456. package/src/plugins/builtin/earnings/board.tsx +253 -50
  457. package/src/plugins/builtin/earnings/calendar-model.ts +188 -0
  458. package/src/plugins/builtin/earnings/calendar.tsx +338 -0
  459. package/src/plugins/builtin/earnings/client.ts +4 -3
  460. package/src/plugins/builtin/earnings/headless.ts +53 -15
  461. package/src/plugins/builtin/earnings/history-model.ts +53 -36
  462. package/src/plugins/builtin/earnings/index.tsx +15 -22
  463. package/src/plugins/builtin/earnings/model.ts +17 -12
  464. package/src/plugins/builtin/earnings/scope.ts +89 -0
  465. package/src/plugins/builtin/earnings-calls/calendar.tsx +310 -0
  466. package/src/plugins/builtin/earnings-calls/data.ts +146 -2
  467. package/src/plugins/builtin/earnings-calls/headless.ts +151 -9
  468. package/src/plugins/builtin/earnings-calls/index.tsx +3 -3
  469. package/src/plugins/builtin/earnings-calls/lock-note.ts +1 -1
  470. package/src/plugins/builtin/earnings-calls/pane.tsx +149 -31
  471. package/src/plugins/builtin/earnings-calls/upcoming.ts +195 -0
  472. package/src/plugins/builtin/earnings-ripple/pane.tsx +10 -5
  473. package/src/plugins/builtin/econ/calendar-model.ts +132 -20
  474. package/src/plugins/builtin/econ/detail-view.tsx +48 -10
  475. package/src/plugins/builtin/econ/fred-catalog.ts +23 -6
  476. package/src/plugins/builtin/econ/fred-series-map.ts +4 -0
  477. package/src/plugins/builtin/econ/index.tsx +112 -25
  478. package/src/plugins/builtin/econ/print-watch.ts +2 -1
  479. package/src/plugins/builtin/econ/types.ts +32 -1
  480. package/src/plugins/builtin/econ-statistics/client.ts +16 -3
  481. package/src/plugins/builtin/econ-statistics/defs.ts +4 -0
  482. package/src/plugins/builtin/econ-statistics/detail.tsx +2 -2
  483. package/src/plugins/builtin/econ-statistics/headless.ts +13 -2
  484. package/src/plugins/builtin/econ-statistics/index.tsx +3 -3
  485. package/src/plugins/builtin/econ-statistics/pane.tsx +2 -1
  486. package/src/plugins/builtin/econ-statistics/stats.ts +103 -0
  487. package/src/plugins/builtin/econ-statistics/view.ts +16 -1
  488. package/src/plugins/builtin/equity-screener/client.ts +21 -3
  489. package/src/plugins/builtin/equity-screener/headless.ts +77 -5
  490. package/src/plugins/builtin/equity-screener/live.ts +1 -1
  491. package/src/plugins/builtin/equity-screener/model.ts +34 -0
  492. package/src/plugins/builtin/equity-screener/pane.tsx +148 -106
  493. package/src/plugins/builtin/equity-screener/screen-check.ts +90 -0
  494. package/src/plugins/builtin/equity-screener/ticker-check.tsx +148 -0
  495. package/src/plugins/builtin/estimate-revisions/headless.ts +3 -1
  496. package/src/plugins/builtin/estimate-revisions/lock-note.ts +3 -3
  497. package/src/plugins/builtin/estimate-revisions/model.ts +8 -10
  498. package/src/plugins/builtin/exposure/headless.ts +51 -6
  499. package/src/plugins/builtin/exposure/index.tsx +28 -2
  500. package/src/plugins/builtin/exposure/model.ts +7 -0
  501. package/src/plugins/builtin/exposure/pane.tsx +16 -10
  502. package/src/plugins/builtin/fear-greed/index.tsx +1 -1
  503. package/src/plugins/builtin/filing-events/index.tsx +1 -1
  504. package/src/plugins/builtin/futures/model.ts +10 -9
  505. package/src/plugins/builtin/futures/returns.ts +8 -36
  506. package/src/plugins/builtin/futures/table.tsx +1 -1
  507. package/src/plugins/builtin/futures-curve/client.ts +40 -9
  508. package/src/plugins/builtin/futures-curve/headless.ts +39 -17
  509. package/src/plugins/builtin/futures-curve/model.ts +258 -69
  510. package/src/plugins/builtin/futures-curve/pane.tsx +46 -17
  511. package/src/plugins/builtin/fx-matrix/client.ts +15 -8
  512. package/src/plugins/builtin/fx-matrix/headless.ts +32 -14
  513. package/src/plugins/builtin/fx-matrix/index.tsx +13 -11
  514. package/src/plugins/builtin/fx-matrix/live-legs.ts +22 -0
  515. package/src/plugins/builtin/fx-matrix/settings.ts +2 -1
  516. package/src/plugins/builtin/gpu/board.tsx +4 -1
  517. package/src/plugins/builtin/gpu/changes.tsx +10 -10
  518. package/src/plugins/builtin/gpu/equities.tsx +4 -1
  519. package/src/plugins/builtin/gpu/headless.ts +9 -4
  520. package/src/plugins/builtin/gpu/history.tsx +4 -2
  521. package/src/plugins/builtin/gpu/pane.tsx +5 -3
  522. package/src/plugins/builtin/help/index.tsx +13 -3
  523. package/src/plugins/builtin/holders/beneficial-model.ts +8 -11
  524. package/src/plugins/builtin/holders/beneficial-report.ts +6 -5
  525. package/src/plugins/builtin/holders/beneficial-view.tsx +7 -3
  526. package/src/plugins/builtin/holders/client.ts +15 -2
  527. package/src/plugins/builtin/holders/format.ts +28 -17
  528. package/src/plugins/builtin/holders/headless.ts +48 -8
  529. package/src/plugins/builtin/holders/index-holders.ts +264 -0
  530. package/src/plugins/builtin/holders/pane.tsx +79 -15
  531. package/src/plugins/builtin/holders/report-rows.ts +35 -7
  532. package/src/plugins/builtin/holders/table-model.ts +2 -1
  533. package/src/plugins/builtin/holders/thirteenf-match.ts +3 -1
  534. package/src/plugins/builtin/holders/treemap.tsx +2 -2
  535. package/src/plugins/builtin/insider/base-values.ts +11 -7
  536. package/src/plugins/builtin/insider/client.ts +3 -0
  537. package/src/plugins/builtin/insider/headless.ts +20 -7
  538. package/src/plugins/builtin/insider/index.tsx +17 -8
  539. package/src/plugins/builtin/insider/issuer.ts +34 -4
  540. package/src/plugins/builtin/insider/signals-client.ts +3 -3
  541. package/src/plugins/builtin/insider/signals.tsx +1 -1
  542. package/src/plugins/builtin/insider/table-model.ts +35 -13
  543. package/src/plugins/builtin/insider/table.tsx +5 -2
  544. package/src/plugins/builtin/ipo-calendar/pane.tsx +7 -4
  545. package/src/plugins/builtin/iv-history/client.ts +20 -0
  546. package/src/plugins/builtin/iv-history/events.ts +145 -0
  547. package/src/plugins/builtin/iv-history/format.ts +3 -0
  548. package/src/plugins/builtin/iv-history/headless.ts +91 -7
  549. package/src/plugins/builtin/iv-history/index.tsx +1 -1
  550. package/src/plugins/builtin/iv-history/model.ts +13 -4
  551. package/src/plugins/builtin/iv-history/series.ts +3 -1
  552. package/src/plugins/builtin/jobs/lock-note.ts +1 -1
  553. package/src/plugins/builtin/jobs/model.ts +4 -15
  554. package/src/plugins/builtin/jobs/pane.tsx +7 -5
  555. package/src/plugins/builtin/jobs/share-bars.tsx +11 -5
  556. package/src/plugins/builtin/jodi/pane.tsx +14 -8
  557. package/src/plugins/builtin/layout-manager/index.tsx +1 -0
  558. package/src/plugins/builtin/macro-day/headless.ts +20 -7
  559. package/src/plugins/builtin/macro-day/index.tsx +3 -2
  560. package/src/plugins/builtin/macro-day/model.ts +29 -8
  561. package/src/plugins/builtin/macro-day/pane.tsx +46 -10
  562. package/src/plugins/builtin/macro-day/releases.ts +55 -13
  563. package/src/plugins/builtin/market-heatmap/data.ts +9 -2
  564. package/src/plugins/builtin/market-heatmap/evidence.ts +1 -1
  565. package/src/plugins/builtin/market-heatmap/headless.ts +9 -6
  566. package/src/plugins/builtin/market-heatmap/index.tsx +3 -3
  567. package/src/plugins/builtin/market-heatmap/model.ts +10 -7
  568. package/src/plugins/builtin/market-movers/client.ts +36 -21
  569. package/src/plugins/builtin/market-movers/headless.ts +8 -2
  570. package/src/plugins/builtin/market-movers/index.tsx +16 -10
  571. package/src/plugins/builtin/market-movers/screener.ts +33 -11
  572. package/src/plugins/builtin/market-movers/session-body.tsx +4 -2
  573. package/src/plugins/builtin/market-movers/session-table.ts +4 -2
  574. package/src/plugins/builtin/market-movers/table.ts +4 -1
  575. package/src/plugins/builtin/market-valuation/headless.ts +2 -0
  576. package/src/plugins/builtin/market-valuation/view.ts +5 -0
  577. package/src/plugins/builtin/members/headless.ts +6 -5
  578. package/src/plugins/builtin/members/pane.tsx +11 -4
  579. package/src/plugins/builtin/mna/client.ts +1 -0
  580. package/src/plugins/builtin/mna/detail.tsx +20 -32
  581. package/src/plugins/builtin/mna/distress/detail.tsx +16 -4
  582. package/src/plugins/builtin/mna/distress/model.ts +3 -2
  583. package/src/plugins/builtin/mna/distress/pane.tsx +7 -4
  584. package/src/plugins/builtin/mna/headless.ts +6 -13
  585. package/src/plugins/builtin/mna/model.ts +93 -15
  586. package/src/plugins/builtin/mna/pane.tsx +5 -4
  587. package/src/plugins/builtin/news/headless.ts +12 -6
  588. package/src/plugins/builtin/news/index.tsx +10 -1
  589. package/src/plugins/builtin/news/wire/index.tsx +3 -2
  590. package/src/plugins/builtin/news/wire/news/command-bar-search.ts +26 -10
  591. package/src/plugins/builtin/news/wire/news/query-presets.ts +6 -2
  592. package/src/plugins/builtin/news/wire/rss/cli.ts +3 -3
  593. package/src/plugins/builtin/notes/cli.ts +50 -15
  594. package/src/plugins/builtin/notes/export.ts +17 -6
  595. package/src/plugins/builtin/notes/files.ts +16 -5
  596. package/src/plugins/builtin/openfda/pane.tsx +1 -1
  597. package/src/plugins/builtin/options/carry.ts +2 -2
  598. package/src/plugins/builtin/options/enrichment-model.ts +10 -9
  599. package/src/plugins/builtin/options/index.tsx +1 -1
  600. package/src/plugins/builtin/options/model-spot.ts +70 -4
  601. package/src/plugins/builtin/options/view.tsx +51 -23
  602. package/src/plugins/builtin/options-calculator/headless.ts +46 -7
  603. package/src/plugins/builtin/options-calculator/pane.tsx +3 -2
  604. package/src/plugins/builtin/options-positioning/headless.ts +11 -3
  605. package/src/plugins/builtin/options-positioning/model.ts +24 -0
  606. package/src/plugins/builtin/options-positioning/pane.tsx +10 -12
  607. package/src/plugins/builtin/options-scenario/client.ts +142 -29
  608. package/src/plugins/builtin/options-scenario/collar.ts +8 -6
  609. package/src/plugins/builtin/options-scenario/csp-screen-headless.ts +127 -0
  610. package/src/plugins/builtin/options-scenario/csp-screen-pane.tsx +165 -0
  611. package/src/plugins/builtin/options-scenario/csp-screen.ts +258 -0
  612. package/src/plugins/builtin/options-scenario/csp.ts +101 -21
  613. package/src/plugins/builtin/options-scenario/headless.ts +49 -21
  614. package/src/plugins/builtin/options-scenario/hedge.ts +20 -14
  615. package/src/plugins/builtin/options-scenario/index.tsx +28 -3
  616. package/src/plugins/builtin/options-scenario/model.ts +13 -0
  617. package/src/plugins/builtin/options-scenario/pane.tsx +22 -10
  618. package/src/plugins/builtin/perps/equity-row.tsx +11 -3
  619. package/src/plugins/builtin/perps/freshness.ts +8 -5
  620. package/src/plugins/builtin/perps/headless.ts +3 -1
  621. package/src/plugins/builtin/perps/list-perpetuals.ts +25 -4
  622. package/src/plugins/builtin/perps/live-rows.ts +161 -0
  623. package/src/plugins/builtin/perps/markets-section.tsx +154 -0
  624. package/src/plugins/builtin/perps/pane.tsx +36 -17
  625. package/src/plugins/builtin/perps/venue-markets.ts +96 -0
  626. package/src/plugins/builtin/plugin-marketplace/index.tsx +2 -1
  627. package/src/plugins/builtin/plugin-marketplace/pane.tsx +145 -60
  628. package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +78 -27
  629. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +158 -141
  630. package/src/plugins/builtin/portfolio-list/cli/render.ts +49 -20
  631. package/src/plugins/builtin/portfolio-list/cli/shared.ts +3 -3
  632. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +29 -24
  633. package/src/plugins/builtin/portfolio-list/headless.ts +6 -3
  634. package/src/plugins/builtin/portfolio-list/income.ts +13 -2
  635. package/src/plugins/builtin/portfolio-list/index.tsx +9 -2
  636. package/src/plugins/builtin/portfolio-list/pane/index.tsx +21 -8
  637. package/src/plugins/builtin/portfolio-list/pane/purchase-date-fx.ts +46 -0
  638. package/src/plugins/builtin/portfolio-list/summary/live-accounts.ts +16 -9
  639. package/src/plugins/builtin/portfolio-list/summary/totals.ts +2 -15
  640. package/src/plugins/builtin/power/client.ts +6 -3
  641. package/src/plugins/builtin/power/evidence.ts +22 -7
  642. package/src/plugins/builtin/power/gas.tsx +5 -1
  643. package/src/plugins/builtin/power/pane.tsx +44 -32
  644. package/src/plugins/builtin/power/prices.tsx +10 -3
  645. package/src/plugins/builtin/research/analyst-headless.ts +25 -8
  646. package/src/plugins/builtin/research/analyst-model.ts +68 -3
  647. package/src/plugins/builtin/research/corporate-actions-pane.tsx +63 -14
  648. package/src/plugins/builtin/research/event-model.ts +3 -1
  649. package/src/plugins/builtin/research/event-sources.ts +12 -4
  650. package/src/plugins/builtin/research/index.tsx +2 -1
  651. package/src/plugins/builtin/research/relative-valuation-basis.ts +58 -0
  652. package/src/plugins/builtin/research/relative-valuation-columns.ts +31 -2
  653. package/src/plugins/builtin/research/relative-valuation-currency.ts +12 -5
  654. package/src/plugins/builtin/research/relative-valuation-headless.ts +84 -26
  655. package/src/plugins/builtin/research/relative-valuation-model.ts +88 -19
  656. package/src/plugins/builtin/research/relative-valuation-pane.tsx +76 -9
  657. package/src/plugins/builtin/research/relative-valuation-peers.ts +1 -1
  658. package/src/plugins/builtin/reverse-dcf/client.ts +2 -1
  659. package/src/plugins/builtin/reverse-dcf/model.ts +10 -5
  660. package/src/plugins/builtin/risk-factors/index.tsx +2 -2
  661. package/src/plugins/builtin/scanner/lock-note.ts +1 -1
  662. package/src/plugins/builtin/seasonality/client.ts +2 -1
  663. package/src/plugins/builtin/sec/forms.ts +13 -0
  664. package/src/plugins/builtin/sec/fund-abroad.ts +32 -0
  665. package/src/plugins/builtin/sec/fund-facts.ts +68 -8
  666. package/src/plugins/builtin/sec/headless.ts +85 -8
  667. package/src/plugins/builtin/sec/index.tsx +58 -12
  668. package/src/plugins/builtin/sectors/client.ts +6 -4
  669. package/src/plugins/builtin/sectors/sector-model.ts +11 -15
  670. package/src/plugins/builtin/series-inventory.ts +2 -0
  671. package/src/plugins/builtin/shared/broker-reconnect.ts +107 -22
  672. package/src/plugins/builtin/shared/cloud-resource.ts +15 -2
  673. package/src/plugins/builtin/shared/cloud-upgrade.ts +34 -6
  674. package/src/plugins/builtin/shared/earnings-calendar.ts +375 -0
  675. package/src/plugins/builtin/{earnings/estimate-basis.ts → shared/earnings-estimate-basis.ts} +1 -1
  676. package/src/plugins/builtin/shared/earnings-report.ts +3 -3
  677. package/src/plugins/builtin/shared/fx-rate-freshness.ts +23 -1
  678. package/src/plugins/builtin/shared/job-posting.ts +129 -0
  679. package/src/plugins/builtin/shared/pro-lock-note.ts +3 -3
  680. package/src/plugins/builtin/shared/report-freshness.ts +3 -0
  681. package/src/plugins/builtin/shared/research-trading.tsx +23 -0
  682. package/src/plugins/builtin/shared/series-cache.ts +2 -0
  683. package/src/plugins/builtin/shared/series-list-detail.tsx +3 -1
  684. package/src/plugins/builtin/shared/ticker-surface.ts +2 -1
  685. package/src/plugins/builtin/shared/volatility/options.ts +2 -1
  686. package/src/plugins/builtin/short-interest/client.ts +2 -0
  687. package/src/plugins/builtin/short-interest/headless.ts +41 -12
  688. package/src/plugins/builtin/short-interest/index.tsx +23 -1
  689. package/src/plugins/builtin/short-interest/model.ts +70 -19
  690. package/src/plugins/builtin/short-interest/pane.tsx +19 -2
  691. package/src/plugins/builtin/short-interest/publications-client.ts +82 -0
  692. package/src/plugins/builtin/short-interest/publications-headless.ts +29 -0
  693. package/src/plugins/builtin/short-interest/publications-model.ts +50 -0
  694. package/src/plugins/builtin/short-interest/publications-pane.tsx +66 -0
  695. package/src/plugins/builtin/short-interest/schedule.ts +35 -2
  696. package/src/plugins/builtin/short-interest/surface.tsx +11 -4
  697. package/src/plugins/builtin/short-interest/types.ts +9 -0
  698. package/src/plugins/builtin/short-interest/watch-client.ts +14 -8
  699. package/src/plugins/builtin/short-interest/watch-model.ts +12 -25
  700. package/src/plugins/builtin/short-interest/watch-pane.tsx +5 -1
  701. package/src/plugins/builtin/social-mentions/client.ts +2 -1
  702. package/src/plugins/builtin/supply-chain/flow.tsx +33 -9
  703. package/src/plugins/builtin/supply-chain/model.ts +51 -3
  704. package/src/plugins/builtin/supply-chain/pane.tsx +78 -39
  705. package/src/plugins/builtin/supply-chain/row-evidence.tsx +1 -1
  706. package/src/plugins/builtin/themes/headless.ts +8 -5
  707. package/src/plugins/builtin/themes/model.ts +14 -4
  708. package/src/plugins/builtin/themes/pane.tsx +24 -5
  709. package/src/plugins/builtin/thirteenf/headless.ts +5 -5
  710. package/src/plugins/builtin/thirteenf/signals.ts +3 -1
  711. package/src/plugins/builtin/ticker-detail/adr-pair/headless.ts +123 -0
  712. package/src/plugins/builtin/ticker-detail/adr-pair/model.ts +132 -0
  713. package/src/plugins/builtin/ticker-detail/adr-pair/tab.tsx +87 -0
  714. package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +40 -26
  715. package/src/plugins/builtin/ticker-detail/data-panes/history-bars.ts +8 -4
  716. package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +67 -3
  717. package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +112 -5
  718. package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +17 -2
  719. package/src/plugins/builtin/ticker-detail/financials/aggregation.ts +21 -7
  720. package/src/plugins/builtin/ticker-detail/financials/model.ts +36 -1
  721. package/src/plugins/builtin/ticker-detail/financials/offerings.ts +56 -0
  722. package/src/plugins/builtin/ticker-detail/financials/ratios.ts +62 -13
  723. package/src/plugins/builtin/ticker-detail/financials/tab.tsx +30 -4
  724. package/src/plugins/builtin/ticker-detail/headless-schema.ts +14 -2
  725. package/src/plugins/builtin/ticker-detail/headless.ts +148 -35
  726. package/src/plugins/builtin/ticker-detail/index.tsx +37 -5
  727. package/src/plugins/builtin/ticker-detail/overview/model.ts +65 -10
  728. package/src/plugins/builtin/ticker-detail/overview/pane.tsx +9 -1
  729. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +68 -11
  730. package/src/plugins/builtin/ticker-detail/pane.tsx +11 -0
  731. package/src/plugins/builtin/ticker-detail/quote-footer.ts +8 -3
  732. package/src/plugins/builtin/ticker-detail/research-tabs.ts +11 -0
  733. package/src/plugins/builtin/vol-surface/client.ts +28 -7
  734. package/src/plugins/builtin/vol-surface/headless.ts +43 -15
  735. package/src/plugins/builtin/vol-surface/model.ts +34 -12
  736. package/src/plugins/builtin/vol-surface/pane.tsx +33 -13
  737. package/src/plugins/builtin/vol-surface/stored.ts +34 -3
  738. package/src/plugins/builtin/vol-surface/tables.ts +14 -0
  739. package/src/plugins/builtin/volatility/model.ts +5 -10
  740. package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +4 -3
  741. package/src/plugins/builtin/world-venue-map/basemap.ts +3 -1
  742. package/src/plugins/builtin/world-venue-map/chokepoint-chart.ts +40 -0
  743. package/src/plugins/builtin/world-venue-map/evidence.ts +1 -1
  744. package/src/plugins/builtin/world-venue-map/geo-series.ts +90 -11
  745. package/src/plugins/builtin/world-venue-map/headless.ts +1 -1
  746. package/src/plugins/builtin/world-venue-map/index.ts +3 -26
  747. package/src/plugins/builtin/world-venue-map/layers.ts +1 -1
  748. package/src/plugins/builtin/world-venue-map/map.tsx +2 -1
  749. package/src/plugins/builtin/world-venue-map/pane.tsx +4 -2
  750. package/src/plugins/builtin/world-venue-map/venue-header.tsx +15 -4
  751. package/src/plugins/builtin/yield-curve/client.ts +25 -0
  752. package/src/plugins/builtin/yield-curve/curves.ts +7 -4
  753. package/src/plugins/builtin/yield-curve/headless.ts +38 -4
  754. package/src/plugins/builtin/yield-curve/history.ts +4 -3
  755. package/src/plugins/builtin/yield-curve/index.tsx +12 -6
  756. package/src/plugins/builtin/yield-curve/swaps-model.ts +93 -0
  757. package/src/plugins/builtin/yield-curve/swaps.tsx +99 -0
  758. package/src/plugins/bundle.ts +1 -1
  759. package/src/plugins/catalog-browser.ts +2 -1
  760. package/src/plugins/compat.ts +3 -3
  761. package/src/plugins/dependencies.ts +75 -14
  762. package/src/plugins/extracted-plugins.ts +132 -34
  763. package/src/plugins/host-link.ts +149 -34
  764. package/src/plugins/installer.ts +35 -10
  765. package/src/plugins/loader.ts +206 -38
  766. package/src/plugins/manager-node.ts +2 -2
  767. package/src/plugins/marketplace/deactivation.ts +22 -0
  768. package/src/plugins/marketplace/model.ts +2 -2
  769. package/src/plugins/marketplace/packs.ts +1 -1
  770. package/src/plugins/ownership.ts +1 -1
  771. package/src/plugins/peer-retry.ts +155 -0
  772. package/src/plugins/registry/contributions.ts +3 -1
  773. package/src/plugins/registry/index.ts +4 -3
  774. package/src/plugins/registry/plugin-state.ts +3 -0
  775. package/src/plugins/seed-notice.ts +20 -0
  776. package/src/plugins/shortcut-argument.ts +39 -0
  777. package/src/portfolio/allocation.ts +1 -1
  778. package/src/portfolio/collection-name.ts +31 -0
  779. package/src/portfolio/column-values.ts +10 -8
  780. package/src/portfolio/cost-fx.ts +296 -19
  781. package/src/portfolio/manual-lots.ts +75 -0
  782. package/src/portfolio/mutations.ts +60 -22
  783. package/src/portfolio/suffixed-listings.ts +209 -0
  784. package/src/portfolio/totals-currency.ts +24 -0
  785. package/src/public/__snapshots__/public-api.test.ts.snap +14 -0
  786. package/src/public/time-series.ts +11 -8
  787. package/src/remote/schema.ts +1 -1
  788. package/src/renderers/browser/config-host.ts +3 -0
  789. package/src/renderers/browser/main.tsx +23 -3
  790. package/src/renderers/dom/boot-frame-page.ts +187 -0
  791. package/src/renderers/dom/boot-frame.ts +237 -0
  792. package/src/renderers/dom/build-assets.ts +46 -8
  793. package/src/renderers/dom/desktop/controls.tsx +1 -1
  794. package/src/renderers/dom/desktop/query-bar.tsx +2 -0
  795. package/src/renderers/dom/dom-ui-host.tsx +4 -29
  796. package/src/renderers/dom/host/ascii-text.ts +16 -2
  797. package/src/renderers/dom/host/box.tsx +43 -2
  798. package/src/renderers/dom/host/chart-surface.tsx +2 -0
  799. package/src/renderers/dom/host/hls.chunk.ts +3 -0
  800. package/src/renderers/dom/host/image-surface.tsx +49 -0
  801. package/src/renderers/dom/host/media-surface.tsx +24 -18
  802. package/src/renderers/dom/host/mouse.ts +30 -0
  803. package/src/renderers/dom/host/size-observer.ts +1 -1
  804. package/src/renderers/dom/host/style.ts +1 -1
  805. package/src/renderers/dom/host/tabs.tsx +16 -5
  806. package/src/renderers/dom/host/top-surface.ts +127 -0
  807. package/src/renderers/dom/styles.css +115 -0
  808. package/src/renderers/dom/test-utils.tsx +2 -1
  809. package/src/renderers/electrobun/bun/application-menu/index.ts +3 -3
  810. package/src/renderers/electrobun/bun/core-capabilities.ts +9 -1
  811. package/src/renderers/electrobun/bun/desktop/backend-requests.ts +3 -0
  812. package/src/renderers/electrobun/bun/desktop/backend.ts +56 -3
  813. package/src/renderers/electrobun/bun/desktop/detached-windows.ts +1 -1
  814. package/src/renderers/electrobun/bun/desktop/host-requests.ts +9 -3
  815. package/src/renderers/electrobun/bun/desktop/initialization.ts +81 -18
  816. package/src/renderers/electrobun/bun/desktop/update.ts +210 -30
  817. package/src/renderers/electrobun/bun/external-plugins.ts +29 -7
  818. package/src/renderers/electrobun/bun/index.ts +11 -1
  819. package/src/renderers/electrobun/bun/window/boot-frame.ts +67 -0
  820. package/src/renderers/electrobun/bun/window/create.ts +4 -1
  821. package/src/renderers/electrobun/shared/boot-frame.ts +7 -0
  822. package/src/renderers/electrobun/shared/protocol.ts +6 -1
  823. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -1
  824. package/src/renderers/electrobun/view/config-host.ts +3 -0
  825. package/src/renderers/electrobun/view/fatal-screen.tsx +1 -1
  826. package/src/renderers/electrobun/view/main.tsx +30 -4
  827. package/src/renderers/electrobun/view/news-source.ts +9 -7
  828. package/src/renderers/electrobun/view/remote/asset-data-client.ts +9 -2
  829. package/src/renderers/electrobun/view/ui-host.tsx +1 -1
  830. package/src/renderers/opentui/browser-open.ts +88 -0
  831. package/src/renderers/opentui/host.tsx +5 -14
  832. package/src/renderers/opentui/image/loader.ts +3 -2
  833. package/src/renderers/opentui/native-smoke.ts +10 -1
  834. package/src/renderers/opentui/pane-image/index.ts +2 -1
  835. package/src/renderers/opentui/render-lib.ts +253 -0
  836. package/src/renderers/opentui/render-timing-smoke.ts +1 -1
  837. package/src/renderers/opentui/start.tsx +8 -1
  838. package/src/renderers/share/layout-view.tsx +2 -2
  839. package/src/renderers/share/main.tsx +4 -4
  840. package/src/renderers/share/view.tsx +1 -1
  841. package/src/series/resolve.ts +22 -6
  842. package/src/series/standalone.ts +30 -2
  843. package/src/series/types.ts +8 -1
  844. package/src/shares/api.ts +4 -1
  845. package/src/shares/pane.ts +1 -1
  846. package/src/sources/gloomberb-cloud/fred-series.ts +46 -1
  847. package/src/sources/gloomberb-cloud/index.ts +39 -16
  848. package/src/sources/gloomberb-cloud/news.ts +39 -0
  849. package/src/sources/gloomberb-cloud/normalizers.ts +14 -1
  850. package/src/sources/gloomberb-cloud/perpetuals.ts +49 -1
  851. package/src/sources/listing-symbols.ts +37 -0
  852. package/src/sources/provider-errors.ts +16 -2
  853. package/src/sources/provider-router/financial-routes.ts +21 -3
  854. package/src/sources/provider-router/financials.ts +15 -2
  855. package/src/sources/provider-router/history.ts +30 -8
  856. package/src/sources/provider-router/index.ts +16 -0
  857. package/src/sources/provider-router/primary.ts +1 -1
  858. package/src/state/app/bootstrap.ts +23 -0
  859. package/src/state/hooks/inline-tickers.ts +30 -5
  860. package/src/sync/controller.ts +1 -1
  861. package/src/sync/core-contributors.ts +46 -14
  862. package/src/team/collections-sync.ts +2 -1
  863. package/src/team/collections.ts +178 -17
  864. package/src/telemetry/crash-reports.ts +21 -4
  865. package/src/telemetry/update-failures-node.ts +59 -0
  866. package/src/telemetry/update-failures.ts +307 -0
  867. package/src/test-support/builtin-panes.ts +1 -1
  868. package/src/theme/colors.ts +3 -30
  869. package/src/theme/ui-tokens.ts +37 -1
  870. package/src/tickers/company-name-listing.ts +215 -36
  871. package/src/tickers/company-name.ts +43 -0
  872. package/src/tickers/index-roots.ts +47 -0
  873. package/src/tickers/instrument-label.ts +5 -1
  874. package/src/tickers/listing-fate.ts +30 -0
  875. package/src/tickers/metadata.ts +10 -0
  876. package/src/tickers/perpetual-listing.ts +5 -2
  877. package/src/tickers/search/home-listing.ts +75 -0
  878. package/src/tickers/search/index.ts +76 -27
  879. package/src/tickers/search/ranking.ts +54 -4
  880. package/src/tickers/search/upsert.ts +29 -0
  881. package/src/tickers/terminal-codes.ts +416 -40
  882. package/src/time-series/bar-aggregation.ts +243 -0
  883. package/src/time-series/base-series.ts +307 -0
  884. package/src/time-series/chart-bounds.ts +349 -0
  885. package/src/time-series/chart-seed.ts +142 -0
  886. package/src/time-series/economic.ts +5 -0
  887. package/src/time-series/fundamentals.ts +18 -3
  888. package/src/time-series/history-acquisition.ts +499 -0
  889. package/src/time-series/leverage.ts +100 -0
  890. package/src/time-series/market-resolution.ts +4 -2
  891. package/src/time-series/market.ts +2 -1
  892. package/src/time-series/price-comparison.ts +175 -30
  893. package/src/time-series/range.ts +9 -1
  894. package/src/time-series/resolution.ts +174 -16
  895. package/src/time-series/resolve-context.ts +157 -0
  896. package/src/time-series/resolve.ts +126 -1577
  897. package/src/time-series/series-name.ts +38 -0
  898. package/src/time-series/series-presentation.ts +208 -0
  899. package/src/time-series/spec.ts +11 -6
  900. package/src/time-series/studies.ts +109 -12
  901. package/src/time-series/tail-reconcile.ts +121 -0
  902. package/src/time-series/types.ts +29 -2
  903. package/src/time-series/use-chart-resolution.ts +4 -5
  904. package/src/types/broker.ts +10 -0
  905. package/src/types/config.ts +14 -0
  906. package/src/types/data-provider.ts +20 -0
  907. package/src/types/exchange-rate.ts +6 -0
  908. package/src/types/financials.ts +104 -7
  909. package/src/types/headless.ts +83 -6
  910. package/src/types/instrument.ts +3 -0
  911. package/src/types/issuer-listings.ts +28 -0
  912. package/src/types/plugin.ts +65 -8
  913. package/src/types/price-history.ts +2 -0
  914. package/src/types/ticker.ts +13 -0
  915. package/src/types/trading.ts +59 -1
  916. package/src/ui/ascii-font.ts +13 -1
  917. package/src/ui/host.tsx +6 -1
  918. package/src/updater/command-names.ts +175 -0
  919. package/src/updater/failure.ts +163 -0
  920. package/src/updater/index.ts +97 -28
  921. package/src/utils/calendar-date.ts +32 -15
  922. package/src/utils/cash-runway.ts +241 -0
  923. package/src/utils/central-banks.ts +42 -0
  924. package/src/utils/cli-output.ts +259 -80
  925. package/src/utils/contract-month.ts +16 -0
  926. package/src/utils/crypto-pair.ts +61 -3
  927. package/src/utils/currency-pair.ts +26 -0
  928. package/src/utils/currency-units.ts +29 -0
  929. package/src/utils/datetime-format.ts +10 -0
  930. package/src/utils/debug-log.ts +1 -1
  931. package/src/utils/decimal-comma.ts +39 -6
  932. package/src/utils/exchange-announcements.ts +71 -0
  933. package/src/utils/exchange-rate-snapshot.ts +10 -0
  934. package/src/utils/financial-statements.ts +83 -4
  935. package/src/utils/format.ts +34 -16
  936. package/src/utils/fundamentals.ts +150 -34
  937. package/src/utils/fx-market-hours.ts +10 -1
  938. package/src/utils/latest-financial-period.ts +8 -0
  939. package/src/utils/linux-libc.ts +54 -0
  940. package/src/utils/market-capitalization.ts +111 -15
  941. package/src/utils/max-drawdown.ts +64 -0
  942. package/src/utils/network-failure.ts +83 -0
  943. package/src/utils/option-expiry.ts +139 -7
  944. package/src/utils/price-earnings.ts +11 -5
  945. package/src/utils/price-history.ts +18 -8
  946. package/src/utils/price-window.ts +131 -0
  947. package/src/utils/release-date.ts +47 -0
  948. package/src/utils/sec.ts +71 -0
  949. package/src/utils/throttled-fetch.ts +11 -4
  950. package/src/utils/trailing-eps.ts +67 -0
  951. package/src/utils/typed-text.ts +21 -0
  952. package/src/utils/utc-time.ts +24 -1
  953. package/src/version.ts +6 -0
  954. package/src/cli/pane-functions/screenshot.ts +0 -2122
@@ -1,16 +1,27 @@
1
- import { useCallback, useEffect, useId, useMemo, useRef, useState, useSyncExternalStore } from "react";
1
+ import { useCallback, useEffect, useId, useMemo, useRef, useState, useSyncExternalStore, type ReactNode } from "react";
2
2
  import { useCompositeChartKeyboard } from "./use-composite-chart-keyboard";
3
3
  import { useCompositeViewport } from "./use-composite-viewport";
4
4
  import { CompositePanelSurface } from "./panel-surface";
5
5
  import { MINIMUM_AXIS_LABEL_WIDTH, compositeAxisLabelWidth } from "./panel-labels";
6
- import { isVerticalWheelDirection } from "./panel-gestures";
6
+ import { AXIS_DOUBLE_PRESS_MS, isVerticalWheelDirection } from "./panel-gestures";
7
7
  import { type ChartToolSpan, CHART_DRAWING_COLORS, isDrawingTool, type ChartDrawing } from "./tools";
8
8
  import { ChartDrawingStore, NO_DRAWINGS } from "./drawing-store";
9
9
  import { CompositeLegend } from "./legend";
10
10
  import { ChartToolbar, CHART_TOOLBAR_WIDTH } from "./toolbar";
11
11
  import { AsciiText, Box, ChartSurface, Text, useUiCapabilities, type BoxRenderable } from "../../../ui";
12
+ import { Button } from "../../ui/button";
12
13
  import { useLiveStretch } from "../../../ui/live-stretch";
13
- import { useOptionalPaneInstanceId } from "../../../state/app/context";
14
+ import { useOptionalPaneInstanceId, usePaneSettingValue } from "../../../state/app/context";
15
+ import {
16
+ CHART_LAYOUT_SETTING_KEY,
17
+ NO_CHART_LAYOUT,
18
+ draggedPanelWeights,
19
+ minimumPanelRows,
20
+ parseChartLayoutPrefs,
21
+ patchChartLayout,
22
+ stepTopPanel,
23
+ type ChartLayoutPrefs,
24
+ } from "./chart-layout";
14
25
  import { usePaneFocused } from "../../../state/app/activity";
15
26
  import { useTabCursorLink } from "../../../state/app/tab-cursor";
16
27
  import { useThemeColors, useThemeId } from "../../../theme/theme-context";
@@ -27,7 +38,14 @@ import { useChartViewResetListener } from "../core/view-reset";
27
38
  import { useShowChartTextFallback } from "../native/use-chart-text-fallback";
28
39
  import { StaticXAxisLabels, StaticXMarkerLabels, StaticXMarkerOverlay } from "./axis-overlays";
29
40
  import { formatCompositeCursorAxisDate } from "./format";
30
- import { resolveCompositeWheelPan, resolveCompositeWheelZoom } from "./interactions";
41
+ import {
42
+ resolveCompositeWheelPan,
43
+ resolveCompositeWheelZoom,
44
+ type CompositeNavigationFrame,
45
+ type CompositeViewportRange,
46
+ } from "./interactions";
47
+ import { NO_VALUE_SCALES, resolveAxisDragSpanFactor } from "./value-scale";
48
+ import { useCompositeValueScales } from "./use-composite-value-scales";
31
49
  import { COMPOSITE_RIGHT_OFFSET_RATIO } from "./time-scale";
32
50
  import {
33
51
  allocateCompositePanelHeights,
@@ -81,6 +99,10 @@ const holdsNothing = () => false;
81
99
  */
82
100
  const DESKTOP_FULL_ROW = { width: "100%" } as const;
83
101
  const DESKTOP_PLOT_COLUMN = { flex: "1 1 0px", width: "auto", minWidth: 0 } as const;
102
+ /** The button on a panel that has the whole plot. */
103
+ const RESTORE_PANELS_LABEL = "All panels";
104
+ /** The time axis row where a drag on it zooms time. */
105
+ const TIME_AXIS_ROW = { ...DESKTOP_FULL_ROW, cursor: "ew-resize" } as const;
84
106
 
85
107
  /** Default-palette series in the theme's own palette, where it has one; the same list otherwise. */
86
108
  function useThemedSeriesList(list: ResolvedSeries[], themeId: string): ResolvedSeries[];
@@ -106,11 +128,42 @@ function centeredLines(text: string, width: number): string[] {
106
128
  return lines;
107
129
  }
108
130
 
131
+ type ChartLayoutUpdate = (update: (layout: ChartLayoutPrefs) => ChartLayoutPrefs) => void;
132
+ type ChartLayoutChild = (layout: ChartLayoutPrefs, update: ChartLayoutUpdate) => ReactNode;
133
+
134
+ /** A chart in a pane keeps its layout in the pane's settings, read as it renders so it never paints twice. */
135
+ function PaneChartLayout({ paneInstanceId, children }: { paneInstanceId: string; children: ChartLayoutChild }) {
136
+ const [stored, setStored] = usePaneSettingValue<unknown>(CHART_LAYOUT_SETTING_KEY, undefined, paneInstanceId);
137
+ const layout = useMemo(() => parseChartLayoutPrefs(stored), [stored]);
138
+ const update = useCallback<ChartLayoutUpdate>((change) => {
139
+ setStored((current: unknown) => {
140
+ const previous = parseChartLayoutPrefs(current);
141
+ const next = change(previous);
142
+ if (next === previous) return current;
143
+ return next === NO_CHART_LAYOUT ? undefined : next;
144
+ });
145
+ }, [setStored]);
146
+ return <>{children(layout, update)}</>;
147
+ }
148
+
149
+ /** A chart outside a pane (a share page) keeps its layout while it is mounted. */
150
+ function LocalChartLayout({ children }: { children: ChartLayoutChild }) {
151
+ const [layout, setLayout] = useState<ChartLayoutPrefs>(NO_CHART_LAYOUT);
152
+ const update = useCallback<ChartLayoutUpdate>((change) => setLayout(change), []);
153
+ return <>{children(layout, update)}</>;
154
+ }
155
+
109
156
  export function CompositeChart(props: CompositeChartProps) {
110
157
  const themeId = useThemeId();
111
158
  const series = useThemedSeriesList(props.series, themeId);
112
159
  const legendSeries = useThemedSeriesList(props.legendSeries, themeId);
113
- return <ThemedCompositeChart {...props} series={series} legendSeries={legendSeries} />;
160
+ const paneInstanceId = useOptionalPaneInstanceId();
161
+ const chart: ChartLayoutChild = (layout, update) => (
162
+ <ThemedCompositeChart {...props} series={series} legendSeries={legendSeries} chartLayout={layout} onChartLayoutChange={update} />
163
+ );
164
+ return paneInstanceId
165
+ ? <PaneChartLayout paneInstanceId={paneInstanceId}>{chart}</PaneChartLayout>
166
+ : <LocalChartLayout>{chart}</LocalChartLayout>;
114
167
  }
115
168
 
116
169
  function ThemedCompositeChart({
@@ -145,11 +198,15 @@ function ThemedCompositeChart({
145
198
  onCursorDateChange,
146
199
  onViewportChange,
147
200
  onActivate,
201
+ onPress,
148
202
  onToggleSeries,
149
203
  isSeriesToggleable,
150
204
  timePick,
205
+ pricePick,
151
206
  levels,
152
- }: CompositeChartProps) {
207
+ chartLayout,
208
+ onChartLayoutChange,
209
+ }: CompositeChartProps & { chartLayout: ChartLayoutPrefs; onChartLayoutChange: ChartLayoutUpdate }) {
153
210
  const activeThemeColors = useThemeColors();
154
211
  const { cellWidthPx = 8, cellHeightPx = 18, pixelRatio = 1, fractionalViewport = false } = useUiCapabilities();
155
212
  const isDesktopWeb = useUiCapabilities().nativePaneChrome === true;
@@ -234,14 +291,24 @@ function ThemedCompositeChart({
234
291
  return assignSeriesLineCues(cueSourceRef.current);
235
292
  }, [cueKey]);
236
293
  const {
237
- navigationFrame, activeUserViewport, effectiveViewport,
294
+ navigationFrame, activeUserViewport, effectiveViewport, authoredViewportChanged, authoredGeneration,
238
295
  panViewport, panViewportByRatio, zoomViewport, setViewportRange, resetViewport,
239
296
  } = useCompositeViewport({
240
297
  viewport, viewportResetKey, visibleSeries, marketTimelineSeries,
241
298
  allowHistoricalBackfill, onViewportChange,
242
299
  });
300
+ // Values scaled by hand belong to the view they were scaled in: a new
301
+ // authored view (another range, another listing) fits them again.
302
+ const { valueScales: heldValueScales, setValueScale, resetPanelValueScale, resetValueScales } = useCompositeValueScales(authoredGeneration);
303
+ const valueScales = authoredViewportChanged ? NO_VALUE_SCALES : heldValueScales;
304
+ const scaledByHand = valueScales !== NO_VALUE_SCALES && Object.keys(valueScales).length > 0;
305
+ // `0`, Reset Zoom and choosing the range again put both axes back.
306
+ const resetView = useCallback(() => {
307
+ resetViewport();
308
+ resetValueScales();
309
+ }, [resetValueScales, resetViewport]);
243
310
  // The pane's range control asks for this when its selected range is chosen again.
244
- useChartViewResetListener(resetViewport, interactive && navigable);
311
+ useChartViewResetListener(resetView, interactive);
245
312
  const timeAxisRows = showTimeAxis ? 1 : 0;
246
313
  const xMarkers = xAxis?.markers ?? NO_X_MARKERS;
247
314
  const xMarkerRows = xMarkers.some((marker) => marker.label) ? 1 : 0;
@@ -283,6 +350,7 @@ function ThemedCompositeChart({
283
350
  clipToViewport,
284
351
  timelineSeries: marketTimelineSeries,
285
352
  rightOffsetRatio,
353
+ valueScales,
286
354
  });
287
355
  }, [
288
356
  clipToViewport,
@@ -293,6 +361,7 @@ function ThemedCompositeChart({
293
361
  panelSeries,
294
362
  panels,
295
363
  rightOffsetRatio,
364
+ valueScales,
296
365
  ]);
297
366
  // Gutters follow the axes the scene actually built. Reading the series list
298
367
  // instead drops a gutter the moment its series has no observation in view,
@@ -313,22 +382,43 @@ function ThemedCompositeChart({
313
382
  const availableAxisWidth = axisCount > 0
314
383
  ? Math.max(0, Math.floor((totalWidth - minimumPlotWidth) / axisCount) - 1)
315
384
  : 0;
385
+ // Heights a drag is setting, shown before they are kept.
386
+ const [draftPanelWeights, setDraftPanelWeights] = useState<Readonly<Record<string, number>> | null>(null);
387
+ const panelWeights = draftPanelWeights ?? chartLayout.panelWeights;
388
+ useEffect(() => setDraftPanelWeights(null), [chartLayout.panelWeights]);
389
+ // A panel given the whole plot, while the chart still has it and another.
390
+ const maximizedPanelId = projectedScene && projectedScene.panels.length > 1
391
+ && projectedScene.panels.some((panel) => panel.id === chartLayout.maximizedPanelId)
392
+ ? chartLayout.maximizedPanelId ?? null
393
+ : null;
316
394
  const layoutPanels = useMemo<CompositePanelScene[] | null>(() => {
317
395
  if (!projectedScene) return null;
318
396
  const panelSpecById = new Map(panels.map((panel) => [panel.id, panel] as const));
397
+ const shown = maximizedPanelId
398
+ ? projectedScene.panels.filter((panel) => panel.id === maximizedPanelId)
399
+ : projectedScene.panels;
319
400
  const panelHeights = allocateCompositePanelHeights(
320
- projectedScene.panels.map((panel) => ({
401
+ shown.map((panel) => ({
321
402
  id: panel.id,
322
- height: panelSpecById.get(panel.id)?.height,
403
+ height: panelWeights?.[panel.id] ?? panelSpecById.get(panel.id)?.height,
323
404
  })),
324
405
  plotHeight,
325
406
  );
326
407
  // Terminal labels snap to rows; a fractional viewport places them exactly.
327
- return projectedScene.panels.map((panel) => {
408
+ return shown.map((panel) => {
328
409
  const resized = resizeCompositePanel(panel, panelHeights.get(panel.id) ?? 1, !fractionalViewport);
329
410
  return lineCues.size > 0 ? { ...resized, lineCues } : resized;
330
411
  });
331
- }, [fractionalViewport, lineCues, panels, plotHeight, projectedScene]);
412
+ }, [fractionalViewport, lineCues, maximizedPanelId, panelWeights, panels, plotHeight, projectedScene]);
413
+ // What a resize starts from: each shown panel's rows, and the weights they share.
414
+ const panelLayoutRef = useRef<{ rows: { id: string; rows: number; weight: number }[]; weightTotal: number }>({ rows: [], weightTotal: 0 });
415
+ {
416
+ const rows = (layoutPanels ?? []).map((panel) => {
417
+ const weight = panelWeights?.[panel.id] ?? panels.find((spec) => spec.id === panel.id)?.height;
418
+ return { id: panel.id, rows: panel.height, weight: typeof weight === "number" && Number.isFinite(weight) && weight > 0 ? weight : 1 };
419
+ });
420
+ panelLayoutRef.current = { rows, weightTotal: rows.reduce((sum, entry) => sum + entry.weight, 0) };
421
+ }
332
422
  // Static overview charts also pin the latest price with cursor precision.
333
423
  const includeCursorLabels = interactive || cursorDate !== undefined || !!scenePanels?.some((panel) => panel.lastPrice);
334
424
  const includeSeriesTags = isDesktopWeb && (interactive || cursorDate !== undefined);
@@ -368,9 +458,11 @@ function ThemedCompositeChart({
368
458
  width: plotWidth,
369
459
  height: layoutPanels.reduce((sum, panel) => sum + panel.height, 0),
370
460
  panels: layoutPanels,
461
+ // A panel with the whole plot still leaves the legend every series' value.
462
+ ...(maximizedPanelId ? { cursorPanels: projectedScene.panels } : {}),
371
463
  };
372
464
  return downsampleCompositeChartScene(laidOut, downsampleWidth);
373
- }, [downsampleWidth, layoutPanels, plotWidth, projectedScene]);
465
+ }, [downsampleWidth, layoutPanels, maximizedPanelId, plotWidth, projectedScene]);
374
466
  const resolvedCursorTimestamp = resolvedCursorDate?.getTime() ?? null;
375
467
  const normalizedCursorTimestamp = resolvedCursorTimestamp !== null && Number.isFinite(resolvedCursorTimestamp)
376
468
  ? resolvedCursorTimestamp
@@ -486,6 +578,94 @@ function ThemedCompositeChart({
486
578
  if (date) link.pin(compositeCursorAsOf(baseScene, date));
487
579
  }, [baseScene, link]);
488
580
 
581
+ // The layout the user leaves the chart in: kept with the pane, through the
582
+ // latest values, so a handler bound once still acts on what is on screen.
583
+ const layoutStateRef = useRef({ chartLayout, maximizedPanelId, onChartLayoutChange });
584
+ layoutStateRef.current = { chartLayout, maximizedPanelId, onChartLayoutChange };
585
+ const patchLayout = useCallback((patch: ChartLayoutPrefs | ((layout: ChartLayoutPrefs) => ChartLayoutPrefs)) => {
586
+ layoutStateRef.current.onChartLayoutChange((layout) => patchChartLayout(layout, typeof patch === "function" ? patch(layout) : patch));
587
+ }, []);
588
+ // The tool in hand, read when the bar is toggled (the keyboard hook below holds it).
589
+ const toolInHandRef = useRef<{ armed: boolean; putDown: () => void }>({ armed: false, putDown: () => {} });
590
+ // Shift+T and the chevrons act on the bar as it shows: a bar open only for
591
+ // the tool in hand folds again, the tool put down, and stays hidden.
592
+ const toggleToolbar = useCallback(() => {
593
+ const tool = toolInHandRef.current;
594
+ const hidden = layoutStateRef.current.chartLayout.toolbarHidden === true && !tool.armed;
595
+ if (!hidden && tool.armed) tool.putDown();
596
+ patchLayout({ toolbarHidden: !hidden });
597
+ }, [patchLayout]);
598
+ const toggleLegendCollapsed = useCallback(() => patchLayout((layout) => ({ legendCollapsed: !layout.legendCollapsed })), [patchLayout]);
599
+ const resetPanelHeights = useCallback(() => {
600
+ setDraftPanelWeights(null);
601
+ patchLayout({ panelWeights: undefined });
602
+ }, [patchLayout]);
603
+ const resetPanelMaximized = useCallback(() => patchLayout({ maximizedPanelId: undefined }), [patchLayout]);
604
+ const togglePanelMaximized = useCallback((panelId: string) => {
605
+ const maximized = layoutStateRef.current.maximizedPanelId;
606
+ patchLayout({ maximizedPanelId: maximized === panelId ? undefined : panelId });
607
+ }, [patchLayout]);
608
+ // A panel given the whole plot is let go once the chart no longer has it, so
609
+ // it never comes back maximized, and when a panel is added beside it, so the
610
+ // new one shows. The chart's panels are the ones it is given and the ones
611
+ // its series bring; a panel whose data is loading is still given.
612
+ const chartPanelIds = useMemo(() => {
613
+ const ids = new Set(panels.map((panel) => panel.id));
614
+ for (const panel of projectedScene?.panels ?? []) ids.add(panel.id);
615
+ return [...ids].join("\u0000");
616
+ }, [panels, projectedScene]);
617
+ const seenPanelIdsRef = useRef<readonly string[] | null>(null);
618
+ const savedMaximizedPanelId = chartLayout.maximizedPanelId;
619
+ const chartDrawn = projectedScene !== null;
620
+ useEffect(() => {
621
+ const ids = chartPanelIds ? chartPanelIds.split("\u0000") : [];
622
+ const previous = seenPanelIdsRef.current;
623
+ seenPanelIdsRef.current = ids;
624
+ if (!savedMaximizedPanelId) return;
625
+ const gone = chartDrawn && !ids.includes(savedMaximizedPanelId);
626
+ const added = !!previous && previous.length > 1 && previous.includes(savedMaximizedPanelId)
627
+ && ids.some((id) => !previous.includes(id));
628
+ if (gone || added) patchLayout({ maximizedPanelId: undefined });
629
+ }, [chartDrawn, chartPanelIds, patchLayout, savedMaximizedPanelId]);
630
+ // Shift+Up and Shift+Down: the top panel a row taller or shorter.
631
+ const stepTopPanelRows = useCallback((direction: 1 | -1) => {
632
+ const { rows } = panelLayoutRef.current;
633
+ const plotRows = rows.reduce((sum, entry) => sum + entry.rows, 0);
634
+ const weight = stepTopPanel(rows, direction, minimumPanelRows(plotRows, rows.length));
635
+ const top = rows[0];
636
+ if (weight === null || !top) return;
637
+ patchLayout((layout) => ({ panelWeights: { ...layout.panelWeights, [top.id]: weight } }));
638
+ }, [patchLayout]);
639
+ const legendCollapsible = showLegend && visibleLegendSeries.length > 1;
640
+ const legendCollapsed = legendCollapsible && chartLayout.legendCollapsed === true;
641
+ const projectedPanelCount = projectedScene?.panels.length ?? 0;
642
+ const layoutControls = useMemo(() => ({
643
+ toolbarHidden: chartLayout.toolbarHidden === true,
644
+ toggleToolbar,
645
+ legendCollapsible,
646
+ legendCollapsed,
647
+ toggleLegend: toggleLegendCollapsed,
648
+ panelsResizable: (layoutPanels?.length ?? 0) > 1,
649
+ stepTopPanel: stepTopPanelRows,
650
+ panelHeightsSet: projectedPanelCount > 1 && !!chartLayout.panelWeights,
651
+ resetPanelHeights,
652
+ panelMaximized: !!maximizedPanelId,
653
+ restorePanels: resetPanelMaximized,
654
+ }), [
655
+ chartLayout.panelWeights,
656
+ chartLayout.toolbarHidden,
657
+ layoutPanels?.length,
658
+ legendCollapsed,
659
+ legendCollapsible,
660
+ maximizedPanelId,
661
+ projectedPanelCount,
662
+ resetPanelHeights,
663
+ resetPanelMaximized,
664
+ stepTopPanelRows,
665
+ toggleLegendCollapsed,
666
+ toggleToolbar,
667
+ ]);
668
+
489
669
  const {
490
670
  armedTool,
491
671
  armTool,
@@ -508,6 +688,7 @@ function ThemedCompositeChart({
508
688
  pin: pinnable ? { pinned: pinnedCursor, toggle: togglePin } : null,
509
689
  onActivate,
510
690
  timePick,
691
+ pricePick,
511
692
  levels,
512
693
  visibleLegendSeries,
513
694
  visibleSeriesIds,
@@ -515,10 +696,11 @@ function ThemedCompositeChart({
515
696
  isSeriesToggleable,
516
697
  navigationFrame,
517
698
  activeUserViewport,
699
+ scaledByHand,
518
700
  panViewportByRatio,
519
701
  zoomViewport,
520
702
  setViewportRange,
521
- resetViewport,
703
+ resetViewport: resetView,
522
704
  drawings,
523
705
  selectedDrawingId,
524
706
  setSelectedDrawingId,
@@ -526,7 +708,17 @@ function ThemedCompositeChart({
526
708
  addDrawing,
527
709
  removeDrawing,
528
710
  pickDrawColor,
711
+ layout: layoutControls,
529
712
  });
713
+ toolInHandRef.current = { armed: armedTool !== null, putDown: () => armTool(null) };
714
+ const pressFromPointer = useCallback(() => {
715
+ onPress?.();
716
+ activateFromPointer();
717
+ }, [activateFromPointer, onPress]);
718
+ const pressPlot = useCallback(() => {
719
+ cancelKeyboardPlacement();
720
+ onPress?.();
721
+ }, [cancelKeyboardPlacement, onPress]);
530
722
  const handleEmptyMouseScroll = useCallback((event: ChartMouseEvent) => {
531
723
  const scroll = event.scroll;
532
724
  if (!interactive || !navigationFrame || !scroll) return;
@@ -553,6 +745,116 @@ function ThemedCompositeChart({
553
745
  zoomViewport,
554
746
  ]);
555
747
 
748
+ // The time axis under the pointer: a drag zooms time from the newest bar
749
+ // in view, in (left) or out (right), as +/- do; a double click resets it.
750
+ const timeScalable = interactive && navigable && !!navigationFrame && !xAxis;
751
+ const timeAxisGestureRef = useRef<{
752
+ startColumn: number;
753
+ frame: CompositeNavigationFrame;
754
+ from: CompositeViewportRange;
755
+ moved: boolean;
756
+ } | null>(null);
757
+ const lastTimeAxisPressRef = useRef<number | null>(null);
758
+ const latestTimeAxisRef = useRef({ navigationFrame, effectiveViewport, resetViewport, zoomViewport, activateFromPointer, cellWidthPx });
759
+ latestTimeAxisRef.current = { navigationFrame, effectiveViewport, resetViewport, zoomViewport, activateFromPointer, cellWidthPx };
760
+ const timeAxisGestures = useMemo(() => {
761
+ if (!timeScalable) return undefined;
762
+ const column = (event: ChartMouseEvent) => typeof event.preciseX === "number" ? event.preciseX : event.x;
763
+ const release = () => {
764
+ timeAxisGestureRef.current = null;
765
+ };
766
+ return {
767
+ onMouseDown: (event: ChartMouseEvent) => {
768
+ const latest = latestTimeAxisRef.current;
769
+ latest.activateFromPointer();
770
+ consumeChartMouseEvent(event);
771
+ const now = Date.now();
772
+ const last = lastTimeAxisPressRef.current;
773
+ const double = typeof event.detail === "number"
774
+ ? event.detail >= 2
775
+ : last !== null && now - last < AXIS_DOUBLE_PRESS_MS;
776
+ if (double) {
777
+ lastTimeAxisPressRef.current = null;
778
+ timeAxisGestureRef.current = null;
779
+ latest.resetViewport();
780
+ return;
781
+ }
782
+ lastTimeAxisPressRef.current = now;
783
+ timeAxisGestureRef.current = latest.navigationFrame && latest.effectiveViewport
784
+ ? { startColumn: column(event), frame: latest.navigationFrame, from: latest.effectiveViewport, moved: false }
785
+ : null;
786
+ },
787
+ onMouseDrag: (event: ChartMouseEvent) => {
788
+ const gesture = timeAxisGestureRef.current;
789
+ if (!gesture) return;
790
+ consumeChartMouseEvent(event);
791
+ const latest = latestTimeAxisRef.current;
792
+ const deltaPx = (column(event) - gesture.startColumn) * latest.cellWidthPx;
793
+ if (!gesture.moved && Math.abs(deltaPx) < 1) return;
794
+ gesture.moved = true;
795
+ lastTimeAxisPressRef.current = null;
796
+ latest.zoomViewport(1 / resolveAxisDragSpanFactor(deltaPx), 1, { frame: gesture.frame, from: gesture.from });
797
+ },
798
+ onMouseUp: release,
799
+ onMouseDragEnd: release,
800
+ };
801
+ }, [timeScalable]);
802
+
803
+ // The line between two panels on the desktop and the web: a drag moves it a
804
+ // row at a time, the panel above taking what the one below gives, and a
805
+ // double click puts back the split the chart was made with.
806
+ const [resizingPanelIndex, setResizingPanelIndex] = useState<number | null>(null);
807
+ const panelResizeRef = useRef<{
808
+ index: number;
809
+ startPixelY: number;
810
+ rows: { id: string; rows: number }[];
811
+ weightTotal: number;
812
+ weights: Readonly<Record<string, number>> | null;
813
+ } | null>(null);
814
+ const latestPanelResizeRef = useRef({ activateFromPointer, cellHeightPx });
815
+ latestPanelResizeRef.current = { activateFromPointer, cellHeightPx };
816
+ const panelsResizableByPointer = interactive && isDesktopWeb && !maximizedPanelId && (layoutPanels?.length ?? 0) > 1;
817
+ const panelDividerGestures = useMemo(() => {
818
+ if (!panelsResizableByPointer) return null;
819
+ const release = () => {
820
+ const gesture = panelResizeRef.current;
821
+ panelResizeRef.current = null;
822
+ setResizingPanelIndex(null);
823
+ const weights = gesture?.weights;
824
+ if (weights) patchLayout((layout) => ({ panelWeights: { ...layout.panelWeights, ...weights } }));
825
+ };
826
+ return (index: number) => ({
827
+ onMouseDown: (event: ChartMouseEvent) => {
828
+ latestPanelResizeRef.current.activateFromPointer();
829
+ consumeChartMouseEvent(event);
830
+ if ((event.detail ?? 0) >= 2) {
831
+ panelResizeRef.current = null;
832
+ setResizingPanelIndex(null);
833
+ resetPanelHeights();
834
+ return;
835
+ }
836
+ const { rows, weightTotal } = panelLayoutRef.current;
837
+ panelResizeRef.current = { index, startPixelY: event.pixelY ?? 0, rows, weightTotal, weights: null };
838
+ setResizingPanelIndex(index);
839
+ },
840
+ onMouseDrag: (event: ChartMouseEvent) => {
841
+ const gesture = panelResizeRef.current;
842
+ if (!gesture) return;
843
+ consumeChartMouseEvent(event);
844
+ const deltaRows = ((event.pixelY ?? gesture.startPixelY) - gesture.startPixelY) / Math.max(1, latestPanelResizeRef.current.cellHeightPx);
845
+ const plotRows = gesture.rows.reduce((sum, entry) => sum + entry.rows, 0);
846
+ // Back where it started, or never a row away, the line saves nothing.
847
+ const weights = draggedPanelWeights(gesture, gesture.index, deltaRows, minimumPanelRows(plotRows, gesture.rows.length));
848
+ gesture.weights = weights;
849
+ setDraftPanelWeights(weights
850
+ ? (current) => ({ ...(current ?? layoutStateRef.current.chartLayout.panelWeights), ...weights })
851
+ : null);
852
+ },
853
+ onMouseUp: release,
854
+ onMouseDragEnd: release,
855
+ });
856
+ }, [panelsResizableByPointer, patchLayout, resetPanelHeights]);
857
+
556
858
  const leftPadding = leftAxisWidth + (leftAxisWidth ? axisGap : 0);
557
859
  const rightPadding = rightAxisWidth + (rightAxisWidth ? axisGap : 0);
558
860
  // The axis's ticks do not move with the cursor, so they are laid out once per chart, not per move.
@@ -597,7 +899,7 @@ function ThemedCompositeChart({
597
899
  accessoryWidth={legendAccessoryWidth}
598
900
  formatValue={formatValue}
599
901
  showLatestChangePercent={showLatestChangePercent}
600
- onActivate={activateFromPointer}
902
+ onActivate={pressFromPointer}
601
903
  onToggleSeries={onToggleSeries}
602
904
  isSeriesToggleable={isSeriesToggleable}
603
905
  keyboardIndex={legendKeyboardIndex}
@@ -659,6 +961,9 @@ function ThemedCompositeChart({
659
961
  // drawing. A chart outside a pane (a share page) keeps them.
660
962
  const toolbarWanted = paneFocused !== false || armedTool !== null || pointerDragging || toolSpan !== null;
661
963
  const showToolbar = interactive && navigable && toolbarWanted && plotWidth > CHART_TOOLBAR_WIDTH + 4;
964
+ // Hidden, the bar folds to the button that brings it back, and opens again
965
+ // while a tool picked from the keys is in hand, so the plot says which one.
966
+ const toolbarFolded = showToolbar && chartLayout.toolbarHidden === true && armedTool === null;
662
967
  // Bars shorter than a day carry a time of day the cursor reads out.
663
968
  const intradayBars = scene.timeZone !== undefined || visibleSeries.some((entry) => (
664
969
  !!entry.historyResolution && isIntradayResolution(entry.historyResolution)
@@ -716,12 +1021,17 @@ function ThemedCompositeChart({
716
1021
  accessoryWidth={legendAccessoryWidth}
717
1022
  formatValue={formatValue}
718
1023
  showLatestChangePercent={showLatestChangePercent}
719
- onActivate={activateFromPointer}
1024
+ onActivate={pressFromPointer}
720
1025
  onToggleSeries={onToggleSeries}
721
1026
  isSeriesToggleable={isSeriesToggleable}
722
1027
  keyboardIndex={legendKeyboardIndex}
723
1028
  rows={legendRows}
724
1029
  onWantedRowsChange={setLegendWantedRows}
1030
+ collapsed={legendCollapsed}
1031
+ onToggleCollapsed={legendCollapsible && interactive ? () => {
1032
+ pressFromPointer();
1033
+ toggleLegendCollapsed();
1034
+ } : undefined}
725
1035
  />
726
1036
  ) : null}
727
1037
  {showToolbar ? (
@@ -733,16 +1043,56 @@ function ThemedCompositeChart({
733
1043
  drawColor={drawColor}
734
1044
  showColors={isDrawingTool(armedTool) || !!selectedDrawingId}
735
1045
  levelTool={levelsEditable}
1046
+ folded={toolbarFolded}
1047
+ onToggleFolded={() => {
1048
+ pressFromPointer();
1049
+ toggleToolbar();
1050
+ }}
736
1051
  onArmTool={(tool) => {
737
- activateFromPointer();
1052
+ pressFromPointer();
738
1053
  armTool(tool);
739
1054
  }}
740
1055
  onPickColor={(color) => {
741
- activateFromPointer();
1056
+ pressFromPointer();
742
1057
  pickDrawColor(color);
743
1058
  }}
744
1059
  />
745
1060
  ) : null}
1061
+ {maximizedPanelId && interactive ? (
1062
+ // A panel with the whole plot says so at its corner, as a value axis
1063
+ // scaled by hand does at its foot, and that is the way back.
1064
+ <Box
1065
+ position="absolute"
1066
+ left={leftPadding + Math.max(0, plotWidth - RESTORE_PANELS_LABEL.length - 1)}
1067
+ top={legendRows}
1068
+ width={RESTORE_PANELS_LABEL.length}
1069
+ height={1}
1070
+ zIndex={30}
1071
+ style={isDesktopWeb
1072
+ ? {
1073
+ left: "auto",
1074
+ right: `calc(${rightPadding} * var(--cell-w) + var(--gloom-space-xs))`,
1075
+ top: `calc(${legendRows} * var(--cell-h) + var(--gloom-space-xs))`,
1076
+ width: "auto",
1077
+ height: "auto",
1078
+ }
1079
+ : undefined}
1080
+ data-gloom-role="composite-chart-panels-restore"
1081
+ >
1082
+ <Button
1083
+ label="Show All Panels"
1084
+ displayLabel={RESTORE_PANELS_LABEL}
1085
+ title="One panel has the chart. Show every panel again (or double-click the plot)."
1086
+ variant="secondary"
1087
+ compact
1088
+ stopPropagation
1089
+ onPress={() => {
1090
+ pressFromPointer();
1091
+ resetPanelMaximized();
1092
+ }}
1093
+ />
1094
+ </Box>
1095
+ ) : null}
746
1096
  {paneInstanceId ? (
747
1097
  <ChartDrawingStore
748
1098
  paneInstanceId={paneInstanceId}
@@ -750,7 +1100,7 @@ function ThemedCompositeChart({
750
1100
  onRestore={setDrawings}
751
1101
  />
752
1102
  ) : null}
753
- {scene.panels.map((panel) => (
1103
+ {scene.panels.map((panel, index) => (
754
1104
  <CompositePanelSurface
755
1105
  key={panel.id}
756
1106
  panel={panel}
@@ -782,12 +1132,20 @@ function ThemedCompositeChart({
782
1132
  onToolSpanChange={setToolSpan}
783
1133
  onDragActiveChange={setPointerDragging}
784
1134
  keyboardToolDrag={keyboardToolDrag?.panelId === panel.id ? keyboardToolDrag : null}
785
- onPointerPress={cancelKeyboardPlacement}
1135
+ onPointerPress={pressPlot}
786
1136
  showTextFallback={showTextFallback}
787
1137
  onPickTime={timePick?.onPick}
1138
+ onPickPrice={pricePick?.onPick}
788
1139
  levels={levelHost?.panel.id === panel.id ? levels ?? null : null}
789
1140
  selectedLevelId={selectedLevelId}
790
1141
  onSelectLevel={setSelectedLevelId}
1142
+ valueScalable={interactive}
1143
+ onSetValueScale={setValueScale}
1144
+ onResetValueScale={resetPanelValueScale}
1145
+ dividerAbove={index > 0 && panelDividerGestures
1146
+ ? { active: resizingPanelIndex === index, gestures: panelDividerGestures(index) }
1147
+ : null}
1148
+ onToggleMaximized={interactive && navigable && projectedPanelCount > 1 ? () => togglePanelMaximized(panel.id) : undefined}
791
1149
  />
792
1150
  ))}
793
1151
  {watermarkScale ? (
@@ -827,7 +1185,15 @@ function ThemedCompositeChart({
827
1185
  </Box>
828
1186
  ) : null}
829
1187
  {timeAxisLayout ? (
830
- <Box flexDirection="row" width={totalWidth} height={1} style={isDesktopWeb ? DESKTOP_FULL_ROW : undefined}>
1188
+ <Box
1189
+ flexDirection="row"
1190
+ width={totalWidth}
1191
+ height={1}
1192
+ style={isDesktopWeb ? timeAxisGestures ? TIME_AXIS_ROW : DESKTOP_FULL_ROW : undefined}
1193
+ {...timeAxisGestures}
1194
+ data-gloom-interactive={timeAxisGestures ? "true" : undefined}
1195
+ data-gloom-role="composite-chart-time-scale"
1196
+ >
831
1197
  {leftPadding > 0 ? <Box width={leftPadding} /> : null}
832
1198
  <StaticXAxisLabels
833
1199
  labels={xAxis?.ticks ? [] : xAxis?.labels ? [...xAxis.labels] : [timeAxisLayout.text]}
@@ -1,4 +1,4 @@
1
- import { useEffect, useRef } from "react";
1
+ import { useCallback, useEffect, useRef } from "react";
2
2
  import { usePaneSettingValue } from "../../../state/app/context";
3
3
  import { CHART_DRAWINGS_SETTING_KEY, parseChartDrawings, type ChartDrawing } from "./tools";
4
4
 
@@ -40,6 +40,12 @@ export function ChartDrawingStore({
40
40
  if (restoredRef.current === null) {
41
41
  restoredRef.current = parseChartDrawings(stored);
42
42
  }
43
+ // What the settings hold, so removing the last drawing is told even when the
44
+ // pane opened with none: it is not "nothing to say" but "the stored one is gone".
45
+ const writtenRef = useRef<readonly ChartDrawing[]>(restoredRef.current);
46
+ const pendingRef = useRef<readonly ChartDrawing[] | null>(null);
47
+ const setStoredRef = useRef(setStored);
48
+ setStoredRef.current = setStored;
43
49
 
44
50
  useEffect(() => {
45
51
  const restored = restoredRef.current;
@@ -47,13 +53,27 @@ export function ChartDrawingStore({
47
53
  // Restoring once on mount: later writes must not scroll back in time.
48
54
  }, []);
49
55
 
56
+ const write = useCallback((next: readonly ChartDrawing[]) => {
57
+ pendingRef.current = null;
58
+ writtenRef.current = next;
59
+ setStoredRef.current(next);
60
+ }, []);
61
+
50
62
  useEffect(() => {
51
- const restored = restoredRef.current ?? NO_DRAWINGS;
52
- if (drawings === restored) return;
53
- if (drawings.length === 0 && restored.length === 0) return;
54
- const timer = setTimeout(() => setStored(drawings), DRAWING_PERSIST_DELAY_MS);
63
+ // Untouched, or still waiting for the restore above: nothing of the user's to write.
64
+ if (drawings === NO_DRAWINGS || drawings === writtenRef.current || (drawings.length === 0 && writtenRef.current.length === 0)) {
65
+ pendingRef.current = null;
66
+ return;
67
+ }
68
+ pendingRef.current = drawings;
69
+ const timer = setTimeout(() => write(drawings), DRAWING_PERSIST_DELAY_MS);
55
70
  return () => clearTimeout(timer);
56
- }, [drawings, setStored]);
71
+ }, [drawings, write]);
72
+
73
+ // A change made just before the chart goes away (a tab switch) is still saved.
74
+ useEffect(() => () => {
75
+ if (pendingRef.current) write(pendingRef.current);
76
+ }, [write]);
57
77
 
58
78
  return null;
59
79
  }