gloomberb 0.18.3 → 0.18.5

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