gloomberb 0.18.2 → 0.18.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (954) hide show
  1. package/README.md +8 -8
  2. package/README.zh-CN.md +11 -11
  3. package/bin/{gloomberb → gloom} +3 -1
  4. package/package.json +6 -2
  5. package/patches/electrobun@1.18.1.patch +106 -5
  6. package/src/account/checkout-handoff.tsx +225 -0
  7. package/src/account/device-signin-dialog.tsx +2 -2
  8. package/src/account/device-signin.ts +2 -2
  9. package/src/account/upgrade-dialog.tsx +1 -1
  10. package/src/api-client/askg.ts +2 -2
  11. package/src/api-client/auth.ts +2 -2
  12. package/src/api-client/central-bank-rates.ts +6 -0
  13. package/src/api-client/collections.ts +5 -1
  14. package/src/api-client/cot.ts +2 -0
  15. package/src/api-client/crypto-etf-flows.ts +37 -0
  16. package/src/api-client/crypto-markets.ts +60 -0
  17. package/src/api-client/data.ts +99 -5
  18. package/src/api-client/doe.ts +15 -0
  19. package/src/api-client/equity-screener.ts +28 -0
  20. package/src/api-client/exchange-announcements.ts +38 -0
  21. package/src/api-client/fund-facts.ts +39 -0
  22. package/src/api-client/futures-curve.ts +9 -1
  23. package/src/api-client/hiring.ts +301 -0
  24. package/src/api-client/index.ts +24 -5
  25. package/src/api-client/market-discovery.ts +14 -0
  26. package/src/api-client/members.ts +6 -0
  27. package/src/api-client/mna.ts +6 -0
  28. package/src/api-client/paths.ts +18 -1
  29. package/src/api-client/request.ts +26 -7
  30. package/src/api-client/short-side-publications.ts +37 -0
  31. package/src/api-client/socket.ts +64 -4
  32. package/src/api-client/swap-curve.ts +35 -0
  33. package/src/api-client/telemetry.ts +17 -0
  34. package/src/api-client/themes.ts +7 -1
  35. package/src/api-client/types.ts +90 -2
  36. package/src/app/global-shortcuts.ts +1 -16
  37. package/src/app/pane-runtime/plugin-bindings.ts +9 -2
  38. package/src/app/runtime/desktop-deeplink.ts +5 -5
  39. package/src/app/runtime/plugin-bindings.ts +2 -2
  40. package/src/app/runtime/startup.ts +13 -0
  41. package/src/app/runtime/update.ts +28 -8
  42. package/src/app/star-prompt/status-line.tsx +2 -2
  43. package/src/architecture/core-builtin-allowlist.json +5 -2
  44. package/src/architecture/pane-tabs-allowlist.json +65 -0
  45. package/src/architecture/ui-literals-allowlist.json +3 -3
  46. package/src/architecture/ui-tokens-allowlist.json +1 -1
  47. package/src/brokers/broker-portfolio-sync.ts +37 -0
  48. package/src/brokers/directory.ts +11 -0
  49. package/src/brokers/logos.ts +3 -1
  50. package/src/brokers/signed-in/adapter.ts +304 -26
  51. package/src/brokers/signed-in/client.ts +14 -2
  52. package/src/brokers/signed-in/connect.ts +10 -2
  53. package/src/brokers/sync-broker-instance.ts +9 -1
  54. package/src/capabilities/chart-series.ts +22 -6
  55. package/src/cli/bank-section.ts +1 -1
  56. package/src/cli/base-converter.ts +23 -14
  57. package/src/cli/central-bank-events.ts +1 -1
  58. package/src/cli/command-options.ts +59 -4
  59. package/src/cli/commands/api.ts +9 -6
  60. package/src/cli/commands/broker.ts +2 -2
  61. package/src/cli/commands/command-utils.ts +2 -2
  62. package/src/cli/commands/crypto-hints.ts +7 -20
  63. package/src/cli/commands/fred-series.ts +4 -2
  64. package/src/cli/commands/keybindings.ts +2 -2
  65. package/src/cli/commands/market.ts +1189 -296
  66. package/src/cli/commands/news-hints.ts +2 -2
  67. package/src/cli/commands/news-search.ts +59 -6
  68. package/src/cli/commands/options-leaps.ts +41 -26
  69. package/src/cli/commands/overview.ts +121 -48
  70. package/src/cli/commands/plugins.ts +9 -9
  71. package/src/cli/commands/remote.ts +13 -10
  72. package/src/cli/commands/search.ts +64 -44
  73. package/src/cli/commands/system.ts +27 -19
  74. package/src/cli/commands/themes.ts +1 -1
  75. package/src/cli/commands/ticker.ts +272 -70
  76. package/src/cli/context.ts +3 -2
  77. package/src/cli/desktop-pane-shot-view.ts +2 -2
  78. package/src/cli/desktop-pane-shot.ts +1 -1
  79. package/src/cli/earnings-calendar.ts +4 -4
  80. package/src/cli/entry.ts +18 -1
  81. package/src/cli/errors.ts +20 -2
  82. package/src/cli/exit-codes.ts +1 -1
  83. package/src/cli/export-source.ts +10 -4
  84. package/src/cli/freshness.ts +2 -8
  85. package/src/cli/fx-forward.ts +130 -0
  86. package/src/cli/fx-pair.ts +10 -9
  87. package/src/cli/glossary.ts +64 -20
  88. package/src/cli/help.ts +20 -14
  89. package/src/cli/history-export.ts +126 -0
  90. package/src/cli/history-rows.ts +196 -43
  91. package/src/cli/index-roots.ts +5 -45
  92. package/src/cli/index.ts +32 -18
  93. package/src/cli/issuer-membership.ts +103 -0
  94. package/src/cli/known-gaps.ts +118 -25
  95. package/src/cli/listing-arg.ts +315 -43
  96. package/src/cli/name-entries.ts +73 -22
  97. package/src/cli/native-smoke.ts +2 -0
  98. package/src/cli/not-a-ticker.ts +19 -9
  99. package/src/cli/opentui-libc.ts +5 -0
  100. package/src/cli/options.ts +12 -0
  101. package/src/cli/pane-functions/capabilities.ts +77 -20
  102. package/src/cli/pane-functions/catalog.ts +40 -23
  103. package/src/cli/pane-functions/discovery.ts +1 -1
  104. package/src/cli/pane-functions/dom.ts +12 -8
  105. package/src/cli/pane-functions/financial-ratio-shot.ts +2 -2
  106. package/src/cli/pane-functions/freshness.ts +174 -23
  107. package/src/cli/pane-functions/function-help.ts +66 -27
  108. package/src/cli/pane-functions/headless.ts +48 -16
  109. package/src/cli/pane-functions/index.ts +82 -21
  110. package/src/cli/pane-functions/options.ts +22 -2
  111. package/src/cli/pane-functions/report-notices.ts +12 -4
  112. package/src/cli/pane-functions/report.ts +5 -5
  113. package/src/cli/pane-functions/resolver.ts +65 -14
  114. package/src/cli/pane-functions/screenshot-assessment.ts +322 -0
  115. package/src/cli/pane-functions/screenshot-bridge.ts +152 -0
  116. package/src/cli/pane-functions/screenshot-chart-evidence.ts +396 -0
  117. package/src/cli/pane-functions/screenshot-data-evidence.ts +383 -0
  118. package/src/cli/pane-functions/screenshot-evidence.ts +1 -1
  119. package/src/cli/pane-functions/screenshot-payload.ts +453 -0
  120. package/src/cli/pane-functions/screenshot-render.ts +316 -0
  121. package/src/cli/pane-functions/screenshot-types.ts +162 -0
  122. package/src/cli/pane-functions/shot-options.ts +8 -3
  123. package/src/cli/peso-dollar-rates.ts +79 -0
  124. package/src/cli/quote-answer.ts +38 -3
  125. package/src/cli/report-tables.ts +190 -27
  126. package/src/cli/restore-plugins.ts +29 -14
  127. package/src/cli/result.ts +122 -25
  128. package/src/cli/series-search.ts +5 -5
  129. package/src/cli/statement-filings.ts +19 -0
  130. package/src/cli/suffixed-listing-rows.ts +49 -0
  131. package/src/cli/symbol-args.ts +50 -15
  132. package/src/cli/symbol-cells.ts +120 -0
  133. package/src/cli/symbol-list.ts +226 -60
  134. package/src/cli/symbol-rows.ts +131 -25
  135. package/src/cli/ticker-resolution.ts +108 -11
  136. package/src/cli/treasury-yields.ts +5 -5
  137. package/src/cli/types.ts +2 -0
  138. package/src/cli/uncovered-instrument.ts +3 -3
  139. package/src/cli/unknown-command.ts +6 -6
  140. package/src/components/chart/composite/chart-layout.ts +131 -0
  141. package/src/components/chart/composite/composite-chart.tsx +387 -21
  142. package/src/components/chart/composite/drawing-store.ts +26 -6
  143. package/src/components/chart/composite/interactions.ts +9 -3
  144. package/src/components/chart/composite/legend.tsx +75 -3
  145. package/src/components/chart/composite/levels.ts +5 -0
  146. package/src/components/chart/composite/panel-gestures.ts +41 -0
  147. package/src/components/chart/composite/panel-labels.ts +2 -1
  148. package/src/components/chart/composite/panel-surface.tsx +316 -11
  149. package/src/components/chart/composite/price-axis-labels.tsx +27 -3
  150. package/src/components/chart/composite/rasterizer.ts +44 -19
  151. package/src/components/chart/composite/scene.ts +16 -4
  152. package/src/components/chart/composite/text-renderer.ts +48 -21
  153. package/src/components/chart/composite/toolbar.tsx +52 -5
  154. package/src/components/chart/composite/types.ts +19 -0
  155. package/src/components/chart/composite/use-composite-chart-keyboard.ts +120 -13
  156. package/src/components/chart/composite/use-composite-value-scales.ts +44 -0
  157. package/src/components/chart/composite/use-composite-viewport.ts +12 -3
  158. package/src/components/chart/composite/value-scale.ts +149 -0
  159. package/src/components/chart/composite/volume-profile-paint.ts +6 -3
  160. package/src/components/chart/core/pointer.ts +2 -0
  161. package/src/components/chart-table/index.ts +2 -0
  162. package/src/components/chart-table/read.tsx +74 -0
  163. package/src/components/command-bar/commands/collection-list.ts +41 -19
  164. package/src/components/command-bar/commands/collection.ts +9 -3
  165. package/src/components/command-bar/commands/direct/index.ts +1 -1
  166. package/src/components/command-bar/commands/direct/runtime.ts +3 -2
  167. package/src/components/command-bar/pane-templates/items.ts +59 -6
  168. package/src/components/command-bar/pane-templates/workflow.ts +10 -1
  169. package/src/components/command-bar/routes/root/command-items.ts +32 -6
  170. package/src/components/command-bar/routes/root/plugin-install.ts +1 -1
  171. package/src/components/command-bar/routes/root/provider-search.ts +42 -11
  172. package/src/components/command-bar/routes/root/results.ts +18 -4
  173. package/src/components/command-bar/routes/root/runtime.ts +15 -3
  174. package/src/components/command-bar/routes/root/search-providers.ts +25 -2
  175. package/src/components/command-bar/routes/root/selection.ts +6 -1
  176. package/src/components/command-bar/routes/root/shortcut-feedback.ts +4 -1
  177. package/src/components/command-bar/routes/root/shortcuts.ts +30 -3
  178. package/src/components/command-bar/routes/ticker-search/results.ts +73 -4
  179. package/src/components/command-bar/selection-runtime.ts +50 -10
  180. package/src/components/command-bar/surface/index.tsx +24 -2
  181. package/src/components/command-bar/view-model.ts +7 -0
  182. package/src/components/command-bar/workflow/broker.ts +2 -2
  183. package/src/components/command-bar/workflow/collection-actions.ts +46 -7
  184. package/src/components/command-bar/workflow/collection-ticker.ts +32 -4
  185. package/src/components/command-bar/workflow/fields.ts +8 -2
  186. package/src/components/command-bar/workflow/ops.ts +18 -4
  187. package/src/components/command-bar/workflow/portfolio-position.ts +53 -4
  188. package/src/components/command-bar/workflow/submit.ts +3 -2
  189. package/src/components/command-bar/workflow/tickers.ts +5 -1
  190. package/src/components/company-logo.tsx +39 -0
  191. package/src/components/data-table/sections.ts +4 -2
  192. package/src/components/data-table/view.tsx +23 -3
  193. package/src/components/form-modal/confirm.tsx +2 -1
  194. package/src/components/form-modal/request.ts +5 -0
  195. package/src/components/form-modal/routes.ts +4 -1
  196. package/src/components/index.ts +13 -6
  197. package/src/components/layout/detached-pane-shell.tsx +1 -0
  198. package/src/components/layout/floating-pane.tsx +1 -0
  199. package/src/components/layout/header.tsx +234 -60
  200. package/src/components/layout/market-summary.ts +9 -6
  201. package/src/components/layout/pane/capture-status.ts +1 -1
  202. package/src/components/layout/pane/footer/model.ts +11 -5
  203. package/src/components/layout/pane/header.tsx +10 -3
  204. package/src/components/layout/pane/index.tsx +1 -0
  205. package/src/components/layout/pane/pane-tabs.tsx +9 -1
  206. package/src/components/layout/shell/chrome.ts +19 -6
  207. package/src/components/layout/shell/index.tsx +2 -1
  208. package/src/components/layout/shell/pane/layers.tsx +19 -1
  209. package/src/components/layout/status-bar.tsx +2 -2
  210. package/src/components/market-board/index.tsx +11 -3
  211. package/src/components/onboarding/onboarding-wizard.tsx +1 -0
  212. package/src/components/onboarding/portfolio-step/broker-setup-panel.tsx +2 -2
  213. package/src/components/onboarding/wizard-broker-sync.ts +4 -1
  214. package/src/components/pane-settings-dialog/desktop.tsx +20 -7
  215. package/src/components/pane-settings-dialog/tui.tsx +17 -9
  216. package/src/components/pane-settings-dialog/value.ts +8 -1
  217. package/src/components/pane-settings-dialog.tsx +44 -13
  218. package/src/components/sign-in-code-panel.tsx +27 -19
  219. package/src/components/ui/column-grid.tsx +48 -4
  220. package/src/components/ui/country-flag-art.tsx +180 -0
  221. package/src/components/ui/country-flag.tsx +118 -12
  222. package/src/components/ui/data-table/opentui/index.tsx +61 -2
  223. package/src/components/ui/data-table/opentui/model.ts +109 -2
  224. package/src/components/ui/data-table/types.ts +1 -1
  225. package/src/components/ui/display.tsx +5 -1
  226. package/src/components/ui/index.ts +3 -1
  227. package/src/components/ui/logo-mark.tsx +11 -2
  228. package/src/components/ui/query-bar.tsx +1 -1
  229. package/src/components/ui/row-notes.ts +79 -0
  230. package/src/components/ui/stat-grid.tsx +28 -3
  231. package/src/components/ui/status.tsx +3 -1
  232. package/src/core/app-services.ts +4 -0
  233. package/src/core/state/app/layout.ts +4 -4
  234. package/src/data/cached-query.ts +8 -1
  235. package/src/data/config/chart-settings.ts +3 -3
  236. package/src/data/config/home.ts +10 -2
  237. package/src/data/config/layout.ts +4 -1
  238. package/src/data/config/store/node.ts +4 -0
  239. package/src/data/config/store/normalize.ts +13 -3
  240. package/src/data/config/store/portfolio-as-of-column.ts +2 -2
  241. package/src/data/json-storage.ts +2 -0
  242. package/src/data/saved-copies.ts +84 -0
  243. package/src/docs/snapshot.json +65 -32
  244. package/src/i18n/es.ts +51 -12
  245. package/src/i18n/ja.ts +51 -12
  246. package/src/i18n/ko.ts +51 -12
  247. package/src/i18n/zh-cn.ts +51 -12
  248. package/src/i18n/zh-tw.ts +51 -12
  249. package/src/layout/desks.ts +1 -1
  250. package/src/layout/launch-layout.ts +1 -1
  251. package/src/layout/pane-manager/floating-actions.ts +5 -3
  252. package/src/layout/pane-manager/floating.ts +43 -1
  253. package/src/layout/pane-manager/index.ts +2 -0
  254. package/src/layout/selected-ticker.ts +74 -0
  255. package/src/market-data/depositary-pair.ts +251 -0
  256. package/src/market-data/futures-board.ts +1 -1
  257. package/src/market-data/futures-contract.ts +124 -40
  258. package/src/market-data/fx-closes.ts +17 -2
  259. package/src/market-data/hooks.tsx +19 -11
  260. package/src/market-data/market/change-basis.ts +49 -7
  261. package/src/market-data/market/freshness.ts +34 -5
  262. package/src/market-data/market/period-return.ts +163 -0
  263. package/src/market-data/market/trading-sessions.ts +13 -0
  264. package/src/market-data/market/year-to-date.ts +8 -13
  265. package/src/market-data/performance.ts +20 -14
  266. package/src/market-data/perpetual-premium.ts +32 -0
  267. package/src/market-data/published-apac-sessions.ts +2 -1
  268. package/src/market-data/published-futures-sessions.ts +69 -0
  269. package/src/market-data/quotes/contributions.ts +5 -1
  270. package/src/market-data/quotes/freshness.ts +42 -0
  271. package/src/market-data/quotes/intraday-bar.ts +37 -0
  272. package/src/market-data/quotes/regular-session-valuation.ts +13 -8
  273. package/src/market-data/quotes/resolution.ts +4 -2
  274. package/src/market-data/tax-equivalent.ts +1 -1
  275. package/src/market-data/ticker-price-returns.ts +3 -1
  276. package/src/news/aggregator.ts +5 -1
  277. package/src/news/news-model.ts +4 -0
  278. package/src/news/types.ts +11 -0
  279. package/src/notifications/app-notifier.ts +1 -1
  280. package/src/plugins/auto-update.ts +2 -2
  281. package/src/plugins/builtin/account-management/index.tsx +1 -0
  282. package/src/plugins/builtin/account-management/pane.tsx +9 -8
  283. package/src/plugins/builtin/alerts/alert-engine.ts +30 -18
  284. package/src/plugins/builtin/alerts/calendar-events.ts +378 -0
  285. package/src/plugins/builtin/alerts/cli.ts +485 -76
  286. package/src/plugins/builtin/alerts/command.ts +5 -10
  287. package/src/plugins/builtin/alerts/event-rows.ts +9 -5
  288. package/src/plugins/builtin/alerts/events-pane.tsx +71 -56
  289. package/src/plugins/builtin/alerts/events.ts +108 -5
  290. package/src/plugins/builtin/alerts/fired-log.ts +78 -0
  291. package/src/plugins/builtin/alerts/format.ts +2 -1
  292. package/src/plugins/builtin/alerts/headless.ts +100 -39
  293. package/src/plugins/builtin/alerts/history-pane.tsx +105 -62
  294. package/src/plugins/builtin/alerts/history-rows.ts +89 -0
  295. package/src/plugins/builtin/alerts/index.tsx +45 -18
  296. package/src/plugins/builtin/alerts/iv-level.ts +365 -0
  297. package/src/plugins/builtin/alerts/levels.ts +3 -3
  298. package/src/plugins/builtin/alerts/pane.tsx +97 -29
  299. package/src/plugins/builtin/alerts/price.ts +35 -0
  300. package/src/plugins/builtin/alerts/quotes.ts +24 -0
  301. package/src/plugins/builtin/alerts/research-builder.ts +84 -11
  302. package/src/plugins/builtin/alerts/research-rules.ts +77 -3
  303. package/src/plugins/builtin/alerts/scheduled-check.ts +206 -32
  304. package/src/plugins/builtin/alerts/scheduled-sources.ts +26 -3
  305. package/src/plugins/builtin/alerts/scheduled.ts +188 -29
  306. package/src/plugins/builtin/alerts/storage.ts +13 -10
  307. package/src/plugins/builtin/alerts/targets.ts +12 -3
  308. package/src/plugins/builtin/analytics/index.tsx +8 -2
  309. package/src/plugins/builtin/analytics/metrics.ts +1 -1
  310. package/src/plugins/builtin/analytics/risk-book.ts +215 -0
  311. package/src/plugins/builtin/analytics/risk-client.ts +13 -6
  312. package/src/plugins/builtin/analytics/risk-headless.ts +55 -21
  313. package/src/plugins/builtin/analytics/risk-math.ts +6 -3
  314. package/src/plugins/builtin/analytics/risk-model.ts +297 -104
  315. package/src/plugins/builtin/analytics/risk-options.ts +17 -2
  316. package/src/plugins/builtin/analytics/risk-pane.tsx +107 -43
  317. package/src/plugins/builtin/attention/pane.tsx +22 -16
  318. package/src/plugins/builtin/awards/headless.ts +7 -3
  319. package/src/plugins/builtin/awards/model.ts +18 -0
  320. package/src/plugins/builtin/awards/pane.tsx +12 -9
  321. package/src/plugins/builtin/backtest/export.ts +1 -1
  322. package/src/plugins/builtin/backtest/headless.ts +3 -3
  323. package/src/plugins/builtin/backtest/rules.ts +41 -5
  324. package/src/plugins/builtin/broker-manager/add-flow.tsx +12 -7
  325. package/src/plugins/builtin/broker-manager/detail.tsx +47 -19
  326. package/src/plugins/builtin/broker-manager/footer.ts +27 -11
  327. package/src/plugins/builtin/broker-manager/index.tsx +21 -12
  328. package/src/plugins/builtin/broker-manager/keyboard.ts +1 -1
  329. package/src/plugins/builtin/broker-manager/model.ts +12 -2
  330. package/src/plugins/builtin/broker-manager/pane-actions.tsx +183 -57
  331. package/src/plugins/builtin/broker-manager/table.ts +28 -12
  332. package/src/plugins/builtin/broker-trading/account-picker.tsx +2 -1
  333. package/src/plugins/builtin/broker-trading/chart-levels.ts +82 -13
  334. package/src/plugins/builtin/broker-trading/controller.ts +45 -13
  335. package/src/plugins/builtin/broker-trading/dock.tsx +24 -4
  336. package/src/plugins/builtin/broker-trading/headless.ts +2 -1
  337. package/src/plugins/builtin/broker-trading/index.tsx +7 -1
  338. package/src/plugins/builtin/broker-trading/linked-orders.ts +148 -0
  339. package/src/plugins/builtin/broker-trading/order-feed.ts +75 -7
  340. package/src/plugins/builtin/broker-trading/orders.tsx +109 -31
  341. package/src/plugins/builtin/broker-trading/overview-orders.tsx +9 -3
  342. package/src/plugins/builtin/broker-trading/pane-model.ts +30 -2
  343. package/src/plugins/builtin/broker-trading/pane.tsx +115 -26
  344. package/src/plugins/builtin/broker-trading/ticket-parts.tsx +36 -7
  345. package/src/plugins/builtin/broker-trading/ticket.tsx +122 -36
  346. package/src/plugins/builtin/buildout/cells.tsx +4 -0
  347. package/src/plugins/builtin/buildout/detail/index.tsx +5 -1
  348. package/src/plugins/builtin/buildout/detail/ui.tsx +7 -4
  349. package/src/plugins/builtin/buildout/pane/index.tsx +34 -18
  350. package/src/plugins/builtin/buildout/pane/status.tsx +0 -4
  351. package/src/plugins/builtin/builtin-plugin-meta.ts +1 -1
  352. package/src/plugins/builtin/catalysts/client.ts +2 -2
  353. package/src/plugins/builtin/catalysts/detail.tsx +3 -2
  354. package/src/plugins/builtin/catalysts/index.tsx +1 -1
  355. package/src/plugins/builtin/catalysts/model.ts +49 -4
  356. package/src/plugins/builtin/catalysts/pane.tsx +9 -11
  357. package/src/plugins/builtin/central-bank-rates/client.ts +5 -0
  358. package/src/plugins/builtin/central-bank-rates/headless.ts +36 -10
  359. package/src/plugins/builtin/central-bank-rates/model.ts +33 -8
  360. package/src/plugins/builtin/changelog/index.tsx +1 -0
  361. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +1 -0
  362. package/src/plugins/builtin/chart-composer/chart-spec-edit.ts +2 -1
  363. package/src/plugins/builtin/chart-composer/chart-spec.ts +7 -0
  364. package/src/plugins/builtin/chart-composer/cli-options.ts +2 -5
  365. package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +2 -1
  366. package/src/plugins/builtin/chart-composer/editor/controller.ts +2 -0
  367. package/src/plugins/builtin/chart-composer/editor.tsx +4 -1
  368. package/src/plugins/builtin/chart-composer/headless-schema.ts +28 -26
  369. package/src/plugins/builtin/chart-composer/headless.ts +253 -35
  370. package/src/plugins/builtin/chart-composer/index.tsx +12 -2
  371. package/src/plugins/builtin/chart-composer/leverage-overlay.ts +142 -0
  372. package/src/plugins/builtin/chart-composer/pane.tsx +128 -28
  373. package/src/plugins/builtin/chart-composer/series-catalog.ts +1 -0
  374. package/src/plugins/builtin/chart-composer/series-expression.ts +65 -6
  375. package/src/plugins/builtin/chart-composer/session-history.ts +15 -21
  376. package/src/plugins/builtin/chart-composer/session-range.ts +4 -2
  377. package/src/plugins/builtin/chart-composer/settings.ts +31 -19
  378. package/src/plugins/builtin/chart-composer/use-series-catalog.ts +5 -6
  379. package/src/plugins/builtin/chart-composer/viewport-labels.ts +18 -8
  380. package/src/plugins/builtin/chat/attachments/model.ts +3 -1
  381. package/src/plugins/builtin/chat/content/index.tsx +1 -1
  382. package/src/plugins/builtin/chat/pane-links/open.ts +1 -1
  383. package/src/plugins/builtin/chat/people.ts +1 -1
  384. package/src/plugins/builtin/clinical-trials/client.ts +5 -2
  385. package/src/plugins/builtin/clinical-trials/model.ts +13 -4
  386. package/src/plugins/builtin/clinical-trials/pane.tsx +32 -12
  387. package/src/plugins/builtin/clinical-trials/ticker-sponsor.ts +17 -0
  388. package/src/plugins/builtin/cloud/askg/controller.ts +1 -1
  389. package/src/plugins/builtin/cloud/askg/lock-note.ts +1 -1
  390. package/src/plugins/builtin/cloud/askg/tool-display.ts +1 -1
  391. package/src/plugins/builtin/cloud/auth-commands.ts +3 -3
  392. package/src/plugins/builtin/cloud/team/pane-sections.tsx +105 -47
  393. package/src/plugins/builtin/cloud/team/pane-ui.tsx +42 -4
  394. package/src/plugins/builtin/cloud/team/pane.tsx +204 -64
  395. package/src/plugins/builtin/cloud/thesis/store.ts +45 -22
  396. package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
  397. package/src/plugins/builtin/commodities-energy/index.tsx +29 -2
  398. package/src/plugins/builtin/commodities-energy/view-state.ts +2 -0
  399. package/src/plugins/builtin/commodity-balances/pane.tsx +14 -8
  400. package/src/plugins/builtin/company-attention/app-rank.tsx +11 -10
  401. package/src/plugins/builtin/company-attention/building-model.ts +222 -0
  402. package/src/plugins/builtin/company-attention/building.tsx +172 -0
  403. package/src/plugins/builtin/company-attention/client.ts +117 -1
  404. package/src/plugins/builtin/company-attention/evidence.ts +16 -3
  405. package/src/plugins/builtin/company-attention/headless.ts +101 -5
  406. package/src/plugins/builtin/company-attention/index.tsx +6 -3
  407. package/src/plugins/builtin/company-attention/model.ts +33 -7
  408. package/src/plugins/builtin/company-attention/moves-model.ts +253 -0
  409. package/src/plugins/builtin/company-attention/moves.tsx +159 -0
  410. package/src/plugins/builtin/company-attention/pane.tsx +89 -31
  411. package/src/plugins/builtin/company-attention/signals-model.ts +229 -0
  412. package/src/plugins/builtin/company-attention/signals.tsx +160 -0
  413. package/src/plugins/builtin/company-kpis/headless.ts +3 -2
  414. package/src/plugins/builtin/company-kpis/model.ts +2 -2
  415. package/src/plugins/builtin/company-kpis/pane.tsx +5 -4
  416. package/src/plugins/builtin/composite-plugins.ts +2 -1
  417. package/src/plugins/builtin/congress-trades/headless.ts +1 -1
  418. package/src/plugins/builtin/connections/index.ts +1 -0
  419. package/src/plugins/builtin/correlation/headless-schema.ts +3 -2
  420. package/src/plugins/builtin/correlation/headless.ts +7 -4
  421. package/src/plugins/builtin/correlation/relationship/model.ts +1 -0
  422. package/src/plugins/builtin/correlation/settings.ts +1 -0
  423. package/src/plugins/builtin/cot/headless.ts +28 -6
  424. package/src/plugins/builtin/cot/model.ts +12 -0
  425. package/src/plugins/builtin/cot/pane.tsx +7 -5
  426. package/src/plugins/builtin/cpi/headless.ts +5 -1
  427. package/src/plugins/builtin/cpi/pane.tsx +11 -9
  428. package/src/plugins/builtin/credit-boards/model.ts +2 -0
  429. package/src/plugins/builtin/credit-documents/headless.ts +1 -1
  430. package/src/plugins/builtin/credit-documents/pane.tsx +8 -7
  431. package/src/plugins/builtin/crypto-board/client.ts +86 -0
  432. package/src/plugins/builtin/crypto-board/defi-view.tsx +218 -0
  433. package/src/plugins/builtin/crypto-board/defi.ts +239 -0
  434. package/src/plugins/builtin/crypto-board/headless.ts +117 -6
  435. package/src/plugins/builtin/crypto-board/index.tsx +8 -3
  436. package/src/plugins/builtin/crypto-board/model.ts +40 -8
  437. package/src/plugins/builtin/crypto-board/pane.tsx +55 -21
  438. package/src/plugins/builtin/crypto-board/series.ts +19 -1
  439. package/src/plugins/builtin/crypto-etf-flows/client.ts +60 -0
  440. package/src/plugins/builtin/crypto-etf-flows/headless.ts +132 -0
  441. package/src/plugins/builtin/crypto-etf-flows/index.tsx +44 -0
  442. package/src/plugins/builtin/crypto-etf-flows/model.ts +121 -0
  443. package/src/plugins/builtin/crypto-etf-flows/pane.tsx +193 -0
  444. package/src/plugins/builtin/debt-maturities/pane.tsx +4 -3
  445. package/src/plugins/builtin/debug/index.tsx +1 -0
  446. package/src/plugins/builtin/dividend-yield/index.tsx +1 -1
  447. package/src/plugins/builtin/docs/index.tsx +1 -1
  448. package/src/plugins/builtin/docs/pane.tsx +2 -2
  449. package/src/plugins/builtin/docs/targets.ts +1 -1
  450. package/src/plugins/builtin/doe/client.ts +5 -1
  451. package/src/plugins/builtin/doe/headless.ts +12 -6
  452. package/src/plugins/builtin/doe/model.ts +43 -6
  453. package/src/plugins/builtin/doe/pane.tsx +19 -12
  454. package/src/plugins/builtin/earnings/board-model.ts +13 -6
  455. package/src/plugins/builtin/earnings/board-table.ts +4 -1
  456. package/src/plugins/builtin/earnings/board.tsx +253 -50
  457. package/src/plugins/builtin/earnings/calendar-model.ts +188 -0
  458. package/src/plugins/builtin/earnings/calendar.tsx +338 -0
  459. package/src/plugins/builtin/earnings/client.ts +4 -3
  460. package/src/plugins/builtin/earnings/headless.ts +53 -15
  461. package/src/plugins/builtin/earnings/history-model.ts +53 -36
  462. package/src/plugins/builtin/earnings/index.tsx +15 -22
  463. package/src/plugins/builtin/earnings/model.ts +17 -12
  464. package/src/plugins/builtin/earnings/scope.ts +89 -0
  465. package/src/plugins/builtin/earnings-calls/calendar.tsx +310 -0
  466. package/src/plugins/builtin/earnings-calls/data.ts +146 -2
  467. package/src/plugins/builtin/earnings-calls/headless.ts +151 -9
  468. package/src/plugins/builtin/earnings-calls/index.tsx +3 -3
  469. package/src/plugins/builtin/earnings-calls/lock-note.ts +1 -1
  470. package/src/plugins/builtin/earnings-calls/pane.tsx +149 -31
  471. package/src/plugins/builtin/earnings-calls/upcoming.ts +195 -0
  472. package/src/plugins/builtin/earnings-ripple/pane.tsx +10 -5
  473. package/src/plugins/builtin/econ/calendar-model.ts +132 -20
  474. package/src/plugins/builtin/econ/detail-view.tsx +48 -10
  475. package/src/plugins/builtin/econ/fred-catalog.ts +23 -6
  476. package/src/plugins/builtin/econ/fred-series-map.ts +4 -0
  477. package/src/plugins/builtin/econ/index.tsx +112 -25
  478. package/src/plugins/builtin/econ/print-watch.ts +2 -1
  479. package/src/plugins/builtin/econ/types.ts +32 -1
  480. package/src/plugins/builtin/econ-statistics/client.ts +16 -3
  481. package/src/plugins/builtin/econ-statistics/defs.ts +4 -0
  482. package/src/plugins/builtin/econ-statistics/detail.tsx +2 -2
  483. package/src/plugins/builtin/econ-statistics/headless.ts +13 -2
  484. package/src/plugins/builtin/econ-statistics/index.tsx +3 -3
  485. package/src/plugins/builtin/econ-statistics/pane.tsx +2 -1
  486. package/src/plugins/builtin/econ-statistics/stats.ts +103 -0
  487. package/src/plugins/builtin/econ-statistics/view.ts +16 -1
  488. package/src/plugins/builtin/equity-screener/client.ts +21 -3
  489. package/src/plugins/builtin/equity-screener/headless.ts +77 -5
  490. package/src/plugins/builtin/equity-screener/live.ts +1 -1
  491. package/src/plugins/builtin/equity-screener/model.ts +34 -0
  492. package/src/plugins/builtin/equity-screener/pane.tsx +148 -106
  493. package/src/plugins/builtin/equity-screener/screen-check.ts +90 -0
  494. package/src/plugins/builtin/equity-screener/ticker-check.tsx +148 -0
  495. package/src/plugins/builtin/estimate-revisions/headless.ts +3 -1
  496. package/src/plugins/builtin/estimate-revisions/lock-note.ts +3 -3
  497. package/src/plugins/builtin/estimate-revisions/model.ts +8 -10
  498. package/src/plugins/builtin/exposure/headless.ts +51 -6
  499. package/src/plugins/builtin/exposure/index.tsx +28 -2
  500. package/src/plugins/builtin/exposure/model.ts +7 -0
  501. package/src/plugins/builtin/exposure/pane.tsx +16 -10
  502. package/src/plugins/builtin/fear-greed/index.tsx +1 -1
  503. package/src/plugins/builtin/filing-events/index.tsx +1 -1
  504. package/src/plugins/builtin/futures/model.ts +10 -9
  505. package/src/plugins/builtin/futures/returns.ts +8 -36
  506. package/src/plugins/builtin/futures/table.tsx +1 -1
  507. package/src/plugins/builtin/futures-curve/client.ts +40 -9
  508. package/src/plugins/builtin/futures-curve/headless.ts +39 -17
  509. package/src/plugins/builtin/futures-curve/model.ts +258 -69
  510. package/src/plugins/builtin/futures-curve/pane.tsx +46 -17
  511. package/src/plugins/builtin/fx-matrix/client.ts +15 -8
  512. package/src/plugins/builtin/fx-matrix/headless.ts +32 -14
  513. package/src/plugins/builtin/fx-matrix/index.tsx +13 -11
  514. package/src/plugins/builtin/fx-matrix/live-legs.ts +22 -0
  515. package/src/plugins/builtin/fx-matrix/settings.ts +2 -1
  516. package/src/plugins/builtin/gpu/board.tsx +4 -1
  517. package/src/plugins/builtin/gpu/changes.tsx +10 -10
  518. package/src/plugins/builtin/gpu/equities.tsx +4 -1
  519. package/src/plugins/builtin/gpu/headless.ts +9 -4
  520. package/src/plugins/builtin/gpu/history.tsx +4 -2
  521. package/src/plugins/builtin/gpu/pane.tsx +5 -3
  522. package/src/plugins/builtin/help/index.tsx +13 -3
  523. package/src/plugins/builtin/holders/beneficial-model.ts +8 -11
  524. package/src/plugins/builtin/holders/beneficial-report.ts +6 -5
  525. package/src/plugins/builtin/holders/beneficial-view.tsx +7 -3
  526. package/src/plugins/builtin/holders/client.ts +15 -2
  527. package/src/plugins/builtin/holders/format.ts +28 -17
  528. package/src/plugins/builtin/holders/headless.ts +48 -8
  529. package/src/plugins/builtin/holders/index-holders.ts +264 -0
  530. package/src/plugins/builtin/holders/pane.tsx +79 -15
  531. package/src/plugins/builtin/holders/report-rows.ts +35 -7
  532. package/src/plugins/builtin/holders/table-model.ts +2 -1
  533. package/src/plugins/builtin/holders/thirteenf-match.ts +3 -1
  534. package/src/plugins/builtin/holders/treemap.tsx +2 -2
  535. package/src/plugins/builtin/insider/base-values.ts +11 -7
  536. package/src/plugins/builtin/insider/client.ts +3 -0
  537. package/src/plugins/builtin/insider/headless.ts +20 -7
  538. package/src/plugins/builtin/insider/index.tsx +17 -8
  539. package/src/plugins/builtin/insider/issuer.ts +34 -4
  540. package/src/plugins/builtin/insider/signals-client.ts +3 -3
  541. package/src/plugins/builtin/insider/signals.tsx +1 -1
  542. package/src/plugins/builtin/insider/table-model.ts +35 -13
  543. package/src/plugins/builtin/insider/table.tsx +5 -2
  544. package/src/plugins/builtin/ipo-calendar/pane.tsx +7 -4
  545. package/src/plugins/builtin/iv-history/client.ts +20 -0
  546. package/src/plugins/builtin/iv-history/events.ts +145 -0
  547. package/src/plugins/builtin/iv-history/format.ts +3 -0
  548. package/src/plugins/builtin/iv-history/headless.ts +91 -7
  549. package/src/plugins/builtin/iv-history/index.tsx +1 -1
  550. package/src/plugins/builtin/iv-history/model.ts +13 -4
  551. package/src/plugins/builtin/iv-history/series.ts +3 -1
  552. package/src/plugins/builtin/jobs/lock-note.ts +1 -1
  553. package/src/plugins/builtin/jobs/model.ts +4 -15
  554. package/src/plugins/builtin/jobs/pane.tsx +7 -5
  555. package/src/plugins/builtin/jobs/share-bars.tsx +11 -5
  556. package/src/plugins/builtin/jodi/pane.tsx +14 -8
  557. package/src/plugins/builtin/layout-manager/index.tsx +1 -0
  558. package/src/plugins/builtin/macro-day/headless.ts +20 -7
  559. package/src/plugins/builtin/macro-day/index.tsx +3 -2
  560. package/src/plugins/builtin/macro-day/model.ts +29 -8
  561. package/src/plugins/builtin/macro-day/pane.tsx +46 -10
  562. package/src/plugins/builtin/macro-day/releases.ts +55 -13
  563. package/src/plugins/builtin/market-heatmap/data.ts +9 -2
  564. package/src/plugins/builtin/market-heatmap/evidence.ts +1 -1
  565. package/src/plugins/builtin/market-heatmap/headless.ts +9 -6
  566. package/src/plugins/builtin/market-heatmap/index.tsx +3 -3
  567. package/src/plugins/builtin/market-heatmap/model.ts +10 -7
  568. package/src/plugins/builtin/market-movers/client.ts +36 -21
  569. package/src/plugins/builtin/market-movers/headless.ts +8 -2
  570. package/src/plugins/builtin/market-movers/index.tsx +16 -10
  571. package/src/plugins/builtin/market-movers/screener.ts +33 -11
  572. package/src/plugins/builtin/market-movers/session-body.tsx +4 -2
  573. package/src/plugins/builtin/market-movers/session-table.ts +4 -2
  574. package/src/plugins/builtin/market-movers/table.ts +4 -1
  575. package/src/plugins/builtin/market-valuation/headless.ts +2 -0
  576. package/src/plugins/builtin/market-valuation/view.ts +5 -0
  577. package/src/plugins/builtin/members/headless.ts +6 -5
  578. package/src/plugins/builtin/members/pane.tsx +11 -4
  579. package/src/plugins/builtin/mna/client.ts +1 -0
  580. package/src/plugins/builtin/mna/detail.tsx +20 -32
  581. package/src/plugins/builtin/mna/distress/detail.tsx +16 -4
  582. package/src/plugins/builtin/mna/distress/model.ts +3 -2
  583. package/src/plugins/builtin/mna/distress/pane.tsx +7 -4
  584. package/src/plugins/builtin/mna/headless.ts +6 -13
  585. package/src/plugins/builtin/mna/model.ts +93 -15
  586. package/src/plugins/builtin/mna/pane.tsx +5 -4
  587. package/src/plugins/builtin/news/headless.ts +12 -6
  588. package/src/plugins/builtin/news/index.tsx +10 -1
  589. package/src/plugins/builtin/news/wire/index.tsx +3 -2
  590. package/src/plugins/builtin/news/wire/news/command-bar-search.ts +26 -10
  591. package/src/plugins/builtin/news/wire/news/query-presets.ts +6 -2
  592. package/src/plugins/builtin/news/wire/rss/cli.ts +3 -3
  593. package/src/plugins/builtin/notes/cli.ts +50 -15
  594. package/src/plugins/builtin/notes/export.ts +17 -6
  595. package/src/plugins/builtin/notes/files.ts +16 -5
  596. package/src/plugins/builtin/openfda/pane.tsx +1 -1
  597. package/src/plugins/builtin/options/carry.ts +2 -2
  598. package/src/plugins/builtin/options/enrichment-model.ts +10 -9
  599. package/src/plugins/builtin/options/index.tsx +1 -1
  600. package/src/plugins/builtin/options/model-spot.ts +70 -4
  601. package/src/plugins/builtin/options/view.tsx +51 -23
  602. package/src/plugins/builtin/options-calculator/headless.ts +46 -7
  603. package/src/plugins/builtin/options-calculator/pane.tsx +3 -2
  604. package/src/plugins/builtin/options-positioning/headless.ts +11 -3
  605. package/src/plugins/builtin/options-positioning/model.ts +24 -0
  606. package/src/plugins/builtin/options-positioning/pane.tsx +10 -12
  607. package/src/plugins/builtin/options-scenario/client.ts +142 -29
  608. package/src/plugins/builtin/options-scenario/collar.ts +8 -6
  609. package/src/plugins/builtin/options-scenario/csp-screen-headless.ts +127 -0
  610. package/src/plugins/builtin/options-scenario/csp-screen-pane.tsx +165 -0
  611. package/src/plugins/builtin/options-scenario/csp-screen.ts +258 -0
  612. package/src/plugins/builtin/options-scenario/csp.ts +101 -21
  613. package/src/plugins/builtin/options-scenario/headless.ts +49 -21
  614. package/src/plugins/builtin/options-scenario/hedge.ts +20 -14
  615. package/src/plugins/builtin/options-scenario/index.tsx +28 -3
  616. package/src/plugins/builtin/options-scenario/model.ts +13 -0
  617. package/src/plugins/builtin/options-scenario/pane.tsx +22 -10
  618. package/src/plugins/builtin/perps/equity-row.tsx +11 -3
  619. package/src/plugins/builtin/perps/freshness.ts +8 -5
  620. package/src/plugins/builtin/perps/headless.ts +3 -1
  621. package/src/plugins/builtin/perps/list-perpetuals.ts +25 -4
  622. package/src/plugins/builtin/perps/live-rows.ts +161 -0
  623. package/src/plugins/builtin/perps/markets-section.tsx +154 -0
  624. package/src/plugins/builtin/perps/pane.tsx +36 -17
  625. package/src/plugins/builtin/perps/venue-markets.ts +96 -0
  626. package/src/plugins/builtin/plugin-marketplace/index.tsx +2 -1
  627. package/src/plugins/builtin/plugin-marketplace/pane.tsx +145 -60
  628. package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +78 -27
  629. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +158 -141
  630. package/src/plugins/builtin/portfolio-list/cli/render.ts +49 -20
  631. package/src/plugins/builtin/portfolio-list/cli/shared.ts +3 -3
  632. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +29 -24
  633. package/src/plugins/builtin/portfolio-list/headless.ts +6 -3
  634. package/src/plugins/builtin/portfolio-list/income.ts +13 -2
  635. package/src/plugins/builtin/portfolio-list/index.tsx +9 -2
  636. package/src/plugins/builtin/portfolio-list/pane/index.tsx +21 -8
  637. package/src/plugins/builtin/portfolio-list/pane/purchase-date-fx.ts +46 -0
  638. package/src/plugins/builtin/portfolio-list/summary/live-accounts.ts +16 -9
  639. package/src/plugins/builtin/portfolio-list/summary/totals.ts +2 -15
  640. package/src/plugins/builtin/power/client.ts +6 -3
  641. package/src/plugins/builtin/power/evidence.ts +22 -7
  642. package/src/plugins/builtin/power/gas.tsx +5 -1
  643. package/src/plugins/builtin/power/pane.tsx +44 -32
  644. package/src/plugins/builtin/power/prices.tsx +10 -3
  645. package/src/plugins/builtin/research/analyst-headless.ts +25 -8
  646. package/src/plugins/builtin/research/analyst-model.ts +68 -3
  647. package/src/plugins/builtin/research/corporate-actions-pane.tsx +63 -14
  648. package/src/plugins/builtin/research/event-model.ts +3 -1
  649. package/src/plugins/builtin/research/event-sources.ts +12 -4
  650. package/src/plugins/builtin/research/index.tsx +2 -1
  651. package/src/plugins/builtin/research/relative-valuation-basis.ts +58 -0
  652. package/src/plugins/builtin/research/relative-valuation-columns.ts +31 -2
  653. package/src/plugins/builtin/research/relative-valuation-currency.ts +12 -5
  654. package/src/plugins/builtin/research/relative-valuation-headless.ts +84 -26
  655. package/src/plugins/builtin/research/relative-valuation-model.ts +88 -19
  656. package/src/plugins/builtin/research/relative-valuation-pane.tsx +76 -9
  657. package/src/plugins/builtin/research/relative-valuation-peers.ts +1 -1
  658. package/src/plugins/builtin/reverse-dcf/client.ts +2 -1
  659. package/src/plugins/builtin/reverse-dcf/model.ts +10 -5
  660. package/src/plugins/builtin/risk-factors/index.tsx +2 -2
  661. package/src/plugins/builtin/scanner/lock-note.ts +1 -1
  662. package/src/plugins/builtin/seasonality/client.ts +2 -1
  663. package/src/plugins/builtin/sec/forms.ts +13 -0
  664. package/src/plugins/builtin/sec/fund-abroad.ts +32 -0
  665. package/src/plugins/builtin/sec/fund-facts.ts +68 -8
  666. package/src/plugins/builtin/sec/headless.ts +85 -8
  667. package/src/plugins/builtin/sec/index.tsx +58 -12
  668. package/src/plugins/builtin/sectors/client.ts +6 -4
  669. package/src/plugins/builtin/sectors/sector-model.ts +11 -15
  670. package/src/plugins/builtin/series-inventory.ts +2 -0
  671. package/src/plugins/builtin/shared/broker-reconnect.ts +107 -22
  672. package/src/plugins/builtin/shared/cloud-resource.ts +15 -2
  673. package/src/plugins/builtin/shared/cloud-upgrade.ts +34 -6
  674. package/src/plugins/builtin/shared/earnings-calendar.ts +375 -0
  675. package/src/plugins/builtin/{earnings/estimate-basis.ts → shared/earnings-estimate-basis.ts} +1 -1
  676. package/src/plugins/builtin/shared/earnings-report.ts +3 -3
  677. package/src/plugins/builtin/shared/fx-rate-freshness.ts +23 -1
  678. package/src/plugins/builtin/shared/job-posting.ts +129 -0
  679. package/src/plugins/builtin/shared/pro-lock-note.ts +3 -3
  680. package/src/plugins/builtin/shared/report-freshness.ts +3 -0
  681. package/src/plugins/builtin/shared/research-trading.tsx +23 -0
  682. package/src/plugins/builtin/shared/series-cache.ts +2 -0
  683. package/src/plugins/builtin/shared/series-list-detail.tsx +3 -1
  684. package/src/plugins/builtin/shared/ticker-surface.ts +2 -1
  685. package/src/plugins/builtin/shared/volatility/options.ts +2 -1
  686. package/src/plugins/builtin/short-interest/client.ts +2 -0
  687. package/src/plugins/builtin/short-interest/headless.ts +41 -12
  688. package/src/plugins/builtin/short-interest/index.tsx +23 -1
  689. package/src/plugins/builtin/short-interest/model.ts +70 -19
  690. package/src/plugins/builtin/short-interest/pane.tsx +19 -2
  691. package/src/plugins/builtin/short-interest/publications-client.ts +82 -0
  692. package/src/plugins/builtin/short-interest/publications-headless.ts +29 -0
  693. package/src/plugins/builtin/short-interest/publications-model.ts +50 -0
  694. package/src/plugins/builtin/short-interest/publications-pane.tsx +66 -0
  695. package/src/plugins/builtin/short-interest/schedule.ts +35 -2
  696. package/src/plugins/builtin/short-interest/surface.tsx +11 -4
  697. package/src/plugins/builtin/short-interest/types.ts +9 -0
  698. package/src/plugins/builtin/short-interest/watch-client.ts +14 -8
  699. package/src/plugins/builtin/short-interest/watch-model.ts +12 -25
  700. package/src/plugins/builtin/short-interest/watch-pane.tsx +5 -1
  701. package/src/plugins/builtin/social-mentions/client.ts +2 -1
  702. package/src/plugins/builtin/supply-chain/flow.tsx +33 -9
  703. package/src/plugins/builtin/supply-chain/model.ts +51 -3
  704. package/src/plugins/builtin/supply-chain/pane.tsx +78 -39
  705. package/src/plugins/builtin/supply-chain/row-evidence.tsx +1 -1
  706. package/src/plugins/builtin/themes/headless.ts +8 -5
  707. package/src/plugins/builtin/themes/model.ts +14 -4
  708. package/src/plugins/builtin/themes/pane.tsx +24 -5
  709. package/src/plugins/builtin/thirteenf/headless.ts +5 -5
  710. package/src/plugins/builtin/thirteenf/signals.ts +3 -1
  711. package/src/plugins/builtin/ticker-detail/adr-pair/headless.ts +123 -0
  712. package/src/plugins/builtin/ticker-detail/adr-pair/model.ts +132 -0
  713. package/src/plugins/builtin/ticker-detail/adr-pair/tab.tsx +87 -0
  714. package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +40 -26
  715. package/src/plugins/builtin/ticker-detail/data-panes/history-bars.ts +8 -4
  716. package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +67 -3
  717. package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +112 -5
  718. package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +17 -2
  719. package/src/plugins/builtin/ticker-detail/financials/aggregation.ts +21 -7
  720. package/src/plugins/builtin/ticker-detail/financials/model.ts +36 -1
  721. package/src/plugins/builtin/ticker-detail/financials/offerings.ts +56 -0
  722. package/src/plugins/builtin/ticker-detail/financials/ratios.ts +62 -13
  723. package/src/plugins/builtin/ticker-detail/financials/tab.tsx +30 -4
  724. package/src/plugins/builtin/ticker-detail/headless-schema.ts +14 -2
  725. package/src/plugins/builtin/ticker-detail/headless.ts +148 -35
  726. package/src/plugins/builtin/ticker-detail/index.tsx +37 -5
  727. package/src/plugins/builtin/ticker-detail/overview/model.ts +65 -10
  728. package/src/plugins/builtin/ticker-detail/overview/pane.tsx +9 -1
  729. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +68 -11
  730. package/src/plugins/builtin/ticker-detail/pane.tsx +11 -0
  731. package/src/plugins/builtin/ticker-detail/quote-footer.ts +8 -3
  732. package/src/plugins/builtin/ticker-detail/research-tabs.ts +11 -0
  733. package/src/plugins/builtin/vol-surface/client.ts +28 -7
  734. package/src/plugins/builtin/vol-surface/headless.ts +43 -15
  735. package/src/plugins/builtin/vol-surface/model.ts +34 -12
  736. package/src/plugins/builtin/vol-surface/pane.tsx +33 -13
  737. package/src/plugins/builtin/vol-surface/stored.ts +34 -3
  738. package/src/plugins/builtin/vol-surface/tables.ts +14 -0
  739. package/src/plugins/builtin/volatility/model.ts +5 -10
  740. package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +4 -3
  741. package/src/plugins/builtin/world-venue-map/basemap.ts +3 -1
  742. package/src/plugins/builtin/world-venue-map/chokepoint-chart.ts +40 -0
  743. package/src/plugins/builtin/world-venue-map/evidence.ts +1 -1
  744. package/src/plugins/builtin/world-venue-map/geo-series.ts +90 -11
  745. package/src/plugins/builtin/world-venue-map/headless.ts +1 -1
  746. package/src/plugins/builtin/world-venue-map/index.ts +3 -26
  747. package/src/plugins/builtin/world-venue-map/layers.ts +1 -1
  748. package/src/plugins/builtin/world-venue-map/map.tsx +2 -1
  749. package/src/plugins/builtin/world-venue-map/pane.tsx +4 -2
  750. package/src/plugins/builtin/world-venue-map/venue-header.tsx +15 -4
  751. package/src/plugins/builtin/yield-curve/client.ts +25 -0
  752. package/src/plugins/builtin/yield-curve/curves.ts +7 -4
  753. package/src/plugins/builtin/yield-curve/headless.ts +38 -4
  754. package/src/plugins/builtin/yield-curve/history.ts +4 -3
  755. package/src/plugins/builtin/yield-curve/index.tsx +12 -6
  756. package/src/plugins/builtin/yield-curve/swaps-model.ts +93 -0
  757. package/src/plugins/builtin/yield-curve/swaps.tsx +99 -0
  758. package/src/plugins/bundle.ts +1 -1
  759. package/src/plugins/catalog-browser.ts +2 -1
  760. package/src/plugins/compat.ts +3 -3
  761. package/src/plugins/dependencies.ts +75 -14
  762. package/src/plugins/extracted-plugins.ts +132 -34
  763. package/src/plugins/host-link.ts +149 -34
  764. package/src/plugins/installer.ts +35 -10
  765. package/src/plugins/loader.ts +206 -38
  766. package/src/plugins/manager-node.ts +2 -2
  767. package/src/plugins/marketplace/deactivation.ts +22 -0
  768. package/src/plugins/marketplace/model.ts +2 -2
  769. package/src/plugins/marketplace/packs.ts +1 -1
  770. package/src/plugins/ownership.ts +1 -1
  771. package/src/plugins/peer-retry.ts +155 -0
  772. package/src/plugins/registry/contributions.ts +3 -1
  773. package/src/plugins/registry/index.ts +4 -3
  774. package/src/plugins/registry/plugin-state.ts +3 -0
  775. package/src/plugins/seed-notice.ts +20 -0
  776. package/src/plugins/shortcut-argument.ts +39 -0
  777. package/src/portfolio/allocation.ts +1 -1
  778. package/src/portfolio/collection-name.ts +31 -0
  779. package/src/portfolio/column-values.ts +10 -8
  780. package/src/portfolio/cost-fx.ts +296 -19
  781. package/src/portfolio/manual-lots.ts +75 -0
  782. package/src/portfolio/mutations.ts +60 -22
  783. package/src/portfolio/suffixed-listings.ts +209 -0
  784. package/src/portfolio/totals-currency.ts +24 -0
  785. package/src/public/__snapshots__/public-api.test.ts.snap +14 -0
  786. package/src/public/time-series.ts +11 -8
  787. package/src/remote/schema.ts +1 -1
  788. package/src/renderers/browser/config-host.ts +3 -0
  789. package/src/renderers/browser/main.tsx +23 -3
  790. package/src/renderers/dom/boot-frame-page.ts +187 -0
  791. package/src/renderers/dom/boot-frame.ts +237 -0
  792. package/src/renderers/dom/build-assets.ts +46 -8
  793. package/src/renderers/dom/desktop/controls.tsx +1 -1
  794. package/src/renderers/dom/desktop/query-bar.tsx +2 -0
  795. package/src/renderers/dom/dom-ui-host.tsx +4 -29
  796. package/src/renderers/dom/host/ascii-text.ts +16 -2
  797. package/src/renderers/dom/host/box.tsx +43 -2
  798. package/src/renderers/dom/host/chart-surface.tsx +2 -0
  799. package/src/renderers/dom/host/hls.chunk.ts +3 -0
  800. package/src/renderers/dom/host/image-surface.tsx +49 -0
  801. package/src/renderers/dom/host/media-surface.tsx +24 -18
  802. package/src/renderers/dom/host/mouse.ts +30 -0
  803. package/src/renderers/dom/host/size-observer.ts +1 -1
  804. package/src/renderers/dom/host/style.ts +1 -1
  805. package/src/renderers/dom/host/tabs.tsx +16 -5
  806. package/src/renderers/dom/host/top-surface.ts +127 -0
  807. package/src/renderers/dom/styles.css +115 -0
  808. package/src/renderers/dom/test-utils.tsx +2 -1
  809. package/src/renderers/electrobun/bun/application-menu/index.ts +3 -3
  810. package/src/renderers/electrobun/bun/core-capabilities.ts +9 -1
  811. package/src/renderers/electrobun/bun/desktop/backend-requests.ts +3 -0
  812. package/src/renderers/electrobun/bun/desktop/backend.ts +56 -3
  813. package/src/renderers/electrobun/bun/desktop/detached-windows.ts +1 -1
  814. package/src/renderers/electrobun/bun/desktop/host-requests.ts +9 -3
  815. package/src/renderers/electrobun/bun/desktop/initialization.ts +81 -18
  816. package/src/renderers/electrobun/bun/desktop/update.ts +210 -30
  817. package/src/renderers/electrobun/bun/external-plugins.ts +29 -7
  818. package/src/renderers/electrobun/bun/index.ts +11 -1
  819. package/src/renderers/electrobun/bun/window/boot-frame.ts +67 -0
  820. package/src/renderers/electrobun/bun/window/create.ts +4 -1
  821. package/src/renderers/electrobun/shared/boot-frame.ts +7 -0
  822. package/src/renderers/electrobun/shared/protocol.ts +6 -1
  823. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -1
  824. package/src/renderers/electrobun/view/config-host.ts +3 -0
  825. package/src/renderers/electrobun/view/fatal-screen.tsx +1 -1
  826. package/src/renderers/electrobun/view/main.tsx +30 -4
  827. package/src/renderers/electrobun/view/news-source.ts +9 -7
  828. package/src/renderers/electrobun/view/remote/asset-data-client.ts +9 -2
  829. package/src/renderers/electrobun/view/ui-host.tsx +1 -1
  830. package/src/renderers/opentui/browser-open.ts +88 -0
  831. package/src/renderers/opentui/host.tsx +5 -14
  832. package/src/renderers/opentui/image/loader.ts +3 -2
  833. package/src/renderers/opentui/native-smoke.ts +10 -1
  834. package/src/renderers/opentui/pane-image/index.ts +2 -1
  835. package/src/renderers/opentui/render-lib.ts +253 -0
  836. package/src/renderers/opentui/render-timing-smoke.ts +1 -1
  837. package/src/renderers/opentui/start.tsx +8 -1
  838. package/src/renderers/share/layout-view.tsx +2 -2
  839. package/src/renderers/share/main.tsx +4 -4
  840. package/src/renderers/share/view.tsx +1 -1
  841. package/src/series/resolve.ts +22 -6
  842. package/src/series/standalone.ts +30 -2
  843. package/src/series/types.ts +8 -1
  844. package/src/shares/api.ts +4 -1
  845. package/src/shares/pane.ts +1 -1
  846. package/src/sources/gloomberb-cloud/fred-series.ts +46 -1
  847. package/src/sources/gloomberb-cloud/index.ts +39 -16
  848. package/src/sources/gloomberb-cloud/news.ts +39 -0
  849. package/src/sources/gloomberb-cloud/normalizers.ts +14 -1
  850. package/src/sources/gloomberb-cloud/perpetuals.ts +49 -1
  851. package/src/sources/listing-symbols.ts +37 -0
  852. package/src/sources/provider-errors.ts +16 -2
  853. package/src/sources/provider-router/financial-routes.ts +21 -3
  854. package/src/sources/provider-router/financials.ts +15 -2
  855. package/src/sources/provider-router/history.ts +30 -8
  856. package/src/sources/provider-router/index.ts +16 -0
  857. package/src/sources/provider-router/primary.ts +1 -1
  858. package/src/state/app/bootstrap.ts +23 -0
  859. package/src/state/hooks/inline-tickers.ts +30 -5
  860. package/src/sync/controller.ts +1 -1
  861. package/src/sync/core-contributors.ts +46 -14
  862. package/src/team/collections-sync.ts +2 -1
  863. package/src/team/collections.ts +178 -17
  864. package/src/telemetry/crash-reports.ts +21 -4
  865. package/src/telemetry/update-failures-node.ts +59 -0
  866. package/src/telemetry/update-failures.ts +307 -0
  867. package/src/test-support/builtin-panes.ts +1 -1
  868. package/src/theme/colors.ts +3 -30
  869. package/src/theme/ui-tokens.ts +37 -1
  870. package/src/tickers/company-name-listing.ts +215 -36
  871. package/src/tickers/company-name.ts +43 -0
  872. package/src/tickers/index-roots.ts +47 -0
  873. package/src/tickers/instrument-label.ts +5 -1
  874. package/src/tickers/listing-fate.ts +30 -0
  875. package/src/tickers/metadata.ts +10 -0
  876. package/src/tickers/perpetual-listing.ts +5 -2
  877. package/src/tickers/search/home-listing.ts +75 -0
  878. package/src/tickers/search/index.ts +76 -27
  879. package/src/tickers/search/ranking.ts +54 -4
  880. package/src/tickers/search/upsert.ts +29 -0
  881. package/src/tickers/terminal-codes.ts +416 -40
  882. package/src/time-series/bar-aggregation.ts +243 -0
  883. package/src/time-series/base-series.ts +307 -0
  884. package/src/time-series/chart-bounds.ts +349 -0
  885. package/src/time-series/chart-seed.ts +142 -0
  886. package/src/time-series/economic.ts +5 -0
  887. package/src/time-series/fundamentals.ts +18 -3
  888. package/src/time-series/history-acquisition.ts +499 -0
  889. package/src/time-series/leverage.ts +100 -0
  890. package/src/time-series/market-resolution.ts +4 -2
  891. package/src/time-series/market.ts +2 -1
  892. package/src/time-series/price-comparison.ts +175 -30
  893. package/src/time-series/range.ts +9 -1
  894. package/src/time-series/resolution.ts +174 -16
  895. package/src/time-series/resolve-context.ts +157 -0
  896. package/src/time-series/resolve.ts +126 -1577
  897. package/src/time-series/series-name.ts +38 -0
  898. package/src/time-series/series-presentation.ts +208 -0
  899. package/src/time-series/spec.ts +11 -6
  900. package/src/time-series/studies.ts +109 -12
  901. package/src/time-series/tail-reconcile.ts +121 -0
  902. package/src/time-series/types.ts +29 -2
  903. package/src/time-series/use-chart-resolution.ts +4 -5
  904. package/src/types/broker.ts +10 -0
  905. package/src/types/config.ts +14 -0
  906. package/src/types/data-provider.ts +20 -0
  907. package/src/types/exchange-rate.ts +6 -0
  908. package/src/types/financials.ts +104 -7
  909. package/src/types/headless.ts +83 -6
  910. package/src/types/instrument.ts +3 -0
  911. package/src/types/issuer-listings.ts +28 -0
  912. package/src/types/plugin.ts +65 -8
  913. package/src/types/price-history.ts +2 -0
  914. package/src/types/ticker.ts +13 -0
  915. package/src/types/trading.ts +59 -1
  916. package/src/ui/ascii-font.ts +13 -1
  917. package/src/ui/host.tsx +6 -1
  918. package/src/updater/command-names.ts +175 -0
  919. package/src/updater/failure.ts +163 -0
  920. package/src/updater/index.ts +97 -28
  921. package/src/utils/calendar-date.ts +32 -15
  922. package/src/utils/cash-runway.ts +241 -0
  923. package/src/utils/central-banks.ts +42 -0
  924. package/src/utils/cli-output.ts +259 -80
  925. package/src/utils/contract-month.ts +16 -0
  926. package/src/utils/crypto-pair.ts +61 -3
  927. package/src/utils/currency-pair.ts +26 -0
  928. package/src/utils/currency-units.ts +29 -0
  929. package/src/utils/datetime-format.ts +10 -0
  930. package/src/utils/debug-log.ts +1 -1
  931. package/src/utils/decimal-comma.ts +39 -6
  932. package/src/utils/exchange-announcements.ts +71 -0
  933. package/src/utils/exchange-rate-snapshot.ts +10 -0
  934. package/src/utils/financial-statements.ts +83 -4
  935. package/src/utils/format.ts +34 -16
  936. package/src/utils/fundamentals.ts +150 -34
  937. package/src/utils/fx-market-hours.ts +10 -1
  938. package/src/utils/latest-financial-period.ts +8 -0
  939. package/src/utils/linux-libc.ts +54 -0
  940. package/src/utils/market-capitalization.ts +111 -15
  941. package/src/utils/max-drawdown.ts +64 -0
  942. package/src/utils/network-failure.ts +83 -0
  943. package/src/utils/option-expiry.ts +139 -7
  944. package/src/utils/price-earnings.ts +11 -5
  945. package/src/utils/price-history.ts +18 -8
  946. package/src/utils/price-window.ts +131 -0
  947. package/src/utils/release-date.ts +47 -0
  948. package/src/utils/sec.ts +71 -0
  949. package/src/utils/throttled-fetch.ts +11 -4
  950. package/src/utils/trailing-eps.ts +67 -0
  951. package/src/utils/typed-text.ts +21 -0
  952. package/src/utils/utc-time.ts +24 -1
  953. package/src/version.ts +6 -0
  954. package/src/cli/pane-functions/screenshot.ts +0 -2122
@@ -59,6 +59,31 @@ export interface KeyboardToolDrag {
59
59
  end: ChartDrawingPoint;
60
60
  }
61
61
 
62
+ /** The chart's own layout: its tool bar, its legend and its panels' heights. */
63
+ export interface CompositeChartLayoutControls {
64
+ /** The bar is saved hidden; it still opens while a tool is in hand. */
65
+ toolbarHidden: boolean;
66
+ toggleToolbar: () => void;
67
+ /** The legend has more than one series, so it can fold to its first. */
68
+ legendCollapsible: boolean;
69
+ legendCollapsed: boolean;
70
+ toggleLegend: () => void;
71
+ /** Two or more panels share the plot, so the keys can move the line between them. */
72
+ panelsResizable: boolean;
73
+ stepTopPanel: (direction: 1 | -1) => void;
74
+ /** Heights were set by hand. */
75
+ panelHeightsSet: boolean;
76
+ resetPanelHeights: () => void;
77
+ /** A panel has the whole plot. */
78
+ panelMaximized: boolean;
79
+ restorePanels: () => void;
80
+ }
81
+
82
+ /** Shift with one of the arrows, and no other modifier. */
83
+ function isShiftedArrow(event: { name?: string; shift?: boolean; ctrl?: boolean; meta?: boolean; alt?: boolean }, ...names: string[]): boolean {
84
+ return event.shift === true && !event.ctrl && !event.meta && !event.alt && names.includes(event.name ?? "");
85
+ }
86
+
62
87
  /** Shift and a letter, whether or not the terminal reports the shift itself. */
63
88
  function isShiftedLetter(event: { name?: string; shift?: boolean; ctrl?: boolean; meta?: boolean; alt?: boolean }, letter: string): boolean {
64
89
  if (event.ctrl || event.meta || event.alt) return false;
@@ -76,6 +101,7 @@ export function useCompositeChartKeyboard({
76
101
  pin,
77
102
  onActivate,
78
103
  timePick,
104
+ pricePick,
79
105
  levels,
80
106
  visibleLegendSeries,
81
107
  visibleSeriesIds,
@@ -83,6 +109,7 @@ export function useCompositeChartKeyboard({
83
109
  isSeriesToggleable,
84
110
  navigationFrame,
85
111
  activeUserViewport,
112
+ scaledByHand,
86
113
  panViewportByRatio,
87
114
  zoomViewport,
88
115
  setViewportRange,
@@ -94,6 +121,7 @@ export function useCompositeChartKeyboard({
94
121
  addDrawing,
95
122
  removeDrawing,
96
123
  pickDrawColor,
124
+ layout,
97
125
  }: {
98
126
  focused: boolean;
99
127
  interactive: boolean;
@@ -106,6 +134,7 @@ export function useCompositeChartKeyboard({
106
134
  pin: { pinned: boolean; toggle: () => void } | null;
107
135
  onActivate: CompositeChartProps["onActivate"];
108
136
  timePick: CompositeChartProps["timePick"];
137
+ pricePick: CompositeChartProps["pricePick"];
109
138
  levels: CompositeChartProps["levels"];
110
139
  visibleLegendSeries: ResolvedSeries[];
111
140
  visibleSeriesIds: ReadonlySet<string>;
@@ -113,6 +142,8 @@ export function useCompositeChartKeyboard({
113
142
  isSeriesToggleable: CompositeChartProps["isSeriesToggleable"];
114
143
  navigationFrame: CompositeNavigationFrame | null;
115
144
  activeUserViewport: CompositeViewportRange | null;
145
+ /** A value axis was stretched or squeezed by hand, which `resetViewport` also fits again. */
146
+ scaledByHand: boolean;
116
147
  panViewportByRatio: (shiftRatio: number) => void;
117
148
  zoomViewport: (zoomFactor: number, anchorRatio?: number) => void;
118
149
  setViewportRange: (range: CompositeViewportRange) => void;
@@ -124,6 +155,7 @@ export function useCompositeChartKeyboard({
124
155
  addDrawing: (drawing: ChartDrawing) => void;
125
156
  removeDrawing: () => void;
126
157
  pickDrawColor: (color: string) => void;
158
+ layout: CompositeChartLayoutControls;
127
159
  }) {
128
160
  const [legendKeyboardIndex, setLegendKeyboardIndex] = useState<number | null>(null);
129
161
  const [armedTool, setArmedTool] = useState<ChartToolKind | null>(null);
@@ -187,8 +219,8 @@ export function useCompositeChartKeyboard({
187
219
  if (wasFocusedRef.current && !focused) setEntered(false);
188
220
  wasFocusedRef.current = focused;
189
221
  }, [focused]);
190
- // A time is picked with the arrows and Enter.
191
- const picking = !!timePick;
222
+ // A time or a price is picked with the arrows and Enter.
223
+ const picking = !!timePick || !!pricePick;
192
224
  useEffect(() => {
193
225
  if (picking) setEntered(true);
194
226
  }, [picking]);
@@ -287,6 +319,8 @@ export function useCompositeChartKeyboard({
287
319
  };
288
320
  const stepLegend = (direction: -1 | 1) => {
289
321
  onActivate?.();
322
+ // The series stepped to must be on screen.
323
+ if (layout.legendCollapsed) layout.toggleLegend();
290
324
  setLegendKeyboardIndex((current) => (
291
325
  current === null
292
326
  ? direction > 0 ? 0 : visibleLegendSeries.length - 1
@@ -298,9 +332,9 @@ export function useCompositeChartKeyboard({
298
332
  onActivate?.();
299
333
  onToggleSeries?.(legendEntry.id);
300
334
  };
301
- /** A level at the keyboard cursor's price, or the last price without a cursor. */
302
- const addLevelAtCursor = () => {
303
- if (!levels?.onEdit || !levelHost || !scene) return;
335
+ /** The levels' series price at the keyboard cursor, or the last price without a cursor. */
336
+ const priceAtCursor = (): number | null => {
337
+ if (!levels || !levelHost || !scene) return null;
304
338
  const { panel, domain } = levelHost;
305
339
  const date = keyboardCursorDateRef.current ?? scene.dates.at(-1) ?? null;
306
340
  // The levels' own series, not whichever one the panel lists first.
@@ -308,8 +342,13 @@ export function useCompositeChartKeyboard({
308
342
  const value = (date ? resolveMeasureValueAt(pricePanel, date.getTime()) : null)
309
343
  ?? (panel.lastPrice?.seriesId === levels.seriesId ? panel.lastPrice.value : null)
310
344
  ?? unprojectCompositeValue(0.5, domain);
311
- if (value === null) return;
312
- const rounded = roundLevelValue(value, domain);
345
+ return value === null ? null : roundLevelValue(value, domain);
346
+ };
347
+ /** A level at the keyboard cursor's price, or the last price without a cursor. */
348
+ const addLevelAtCursor = () => {
349
+ if (!levels?.onEdit) return;
350
+ const rounded = priceAtCursor();
351
+ if (rounded === null) return;
313
352
  onActivate?.();
314
353
  // Enter again at the same cursor picks the level already there.
315
354
  const existing = levelItems.find((level) => level.editable && level.value === rounded);
@@ -342,7 +381,8 @@ export function useCompositeChartKeyboard({
342
381
  setSelectedLevelId(ordered[next]!.id);
343
382
  };
344
383
  const removeSelectedLevel = () => {
345
- if (!selectedLevel?.editable) return;
384
+ // An order's line moves here; it is cancelled where the order is.
385
+ if (!selectedLevel?.editable || selectedLevel.draggable) return;
346
386
  levels?.onEdit?.({ kind: "remove", id: selectedLevel.id });
347
387
  setSelectedLevelId(null);
348
388
  };
@@ -403,6 +443,13 @@ export function useCompositeChartKeyboard({
403
443
  else chartActionsRef.current.pick();
404
444
  return;
405
445
  }
446
+ // Esc ends a price pick even with nothing drawn yet; Enter needs a price at the cursor.
447
+ if (pricePick && (scene || isPlainKey(event, "escape")) && isPlainKey(event, "return", "enter", "escape")) {
448
+ consume();
449
+ if (event.name === "escape") pricePick.onCancel();
450
+ else chartActionsRef.current.pickPrice();
451
+ return;
452
+ }
406
453
  if (zoned && !entered && isPlainKey(event, "down", "return", "enter")) {
407
454
  consume();
408
455
  enterChart();
@@ -424,7 +471,7 @@ export function useCompositeChartKeyboard({
424
471
  stepLevel(event.name === "[" ? -1 : 1);
425
472
  return;
426
473
  }
427
- if (toolsActive && selectedLevel?.editable && levelsEditable && isPlainKey(event, "backspace")) {
474
+ if (toolsActive && selectedLevel?.editable && !selectedLevel.draggable && levelsEditable && isPlainKey(event, "backspace", "delete")) {
428
475
  consume();
429
476
  removeSelectedLevel();
430
477
  return;
@@ -453,6 +500,21 @@ export function useCompositeChartKeyboard({
453
500
  setKeyboardPlacement((current) => current && moveKeyboardPlacement(current, { level }));
454
501
  return;
455
502
  }
503
+ if (toolsActive && isShiftedLetter(event, "t")) {
504
+ consume();
505
+ layout.toggleToolbar();
506
+ return;
507
+ }
508
+ if (legendKeysActive && layout.legendCollapsible && isShiftedLetter(event, "l")) {
509
+ consume();
510
+ layout.toggleLegend();
511
+ return;
512
+ }
513
+ if (toolsActive && layout.panelsResizable && isShiftedArrow(event, "up", "down")) {
514
+ consume();
515
+ layout.stepTopPanel(event.name === "up" ? 1 : -1);
516
+ return;
517
+ }
456
518
  if (isPlainKey(event, "[", "]") && (drawingKeysActive || legendKeysActive)) {
457
519
  consume();
458
520
  const direction = event.name === "[" ? -1 : 1;
@@ -579,6 +641,10 @@ export function useCompositeChartKeyboard({
579
641
  const date = keyboardCursorDateRef.current ?? scene?.dates.at(-1) ?? null;
580
642
  if (date) timePick?.onPick(date);
581
643
  },
644
+ pickPrice: () => {
645
+ const value = priceAtCursor();
646
+ if (value !== null) pricePick?.onPick(value);
647
+ },
582
648
  start: armedTool === "level" ? addLevelAtCursor : startKeyboardPlacement,
583
649
  finish: finishKeyboardPlacement,
584
650
  stepLevel,
@@ -596,6 +662,7 @@ export function useCompositeChartKeyboard({
596
662
  },
597
663
  leave: leaveChart,
598
664
  togglePin: () => pin?.toggle(),
665
+ layout,
599
666
  };
600
667
  const chartActionsRef = useRef(chartActions);
601
668
  chartActionsRef.current = chartActions;
@@ -608,17 +675,27 @@ export function useCompositeChartKeyboard({
608
675
  const armedHints = armedTool ? KEYBOARD_TOOL_HINTS[armedTool] : null;
609
676
  const placing = !!keyboardPlacement;
610
677
  const legendEntryVisible = !!legendEntry && visibleSeriesIds.has(legendEntry.id);
611
- const resettable = !!activeUserViewport;
612
- const timePickLabel = timePick?.label ?? null;
678
+ const resettable = !!activeUserViewport || scaledByHand;
679
+ const timePickLabel = timePick?.label ?? (levelHost ? pricePick?.label : null) ?? null;
680
+ const pickingPrice = !timePick && !!pricePick;
613
681
  const levelActionHint = selectedLevel?.actionable && levels?.action ? levels.action : null;
614
682
  const levelToolKeys = toolsActive && armedTool === "level" && levelsEditable;
615
- const canDeleteLevel = toolsActive && levelsEditable && !!selectedLevel?.editable;
683
+ const canDeleteLevel = toolsActive && levelsEditable && !!selectedLevel?.editable && !selectedLevel.draggable;
616
684
  const pinState = pin ? pin.pinned : null;
685
+ // Hidden as it shows: a saved hidden bar is open while a tool is in hand.
686
+ const toolbarHidden = layout.toolbarHidden && armedTool === null;
687
+ const {
688
+ legendCollapsible,
689
+ legendCollapsed,
690
+ panelsResizable,
691
+ panelHeightsSet,
692
+ panelMaximized,
693
+ } = layout;
617
694
  usePaneFooter(keyboardId, () => {
618
695
  if (!keyboardActive || !scene) return null;
619
696
  const hints: PaneHint[] = [];
620
697
  if (timePickLabel) {
621
- hints.push({ id: "chart-pick", key: "Enter", label: timePickLabel, onPress: () => chartActionsRef.current.pick() });
698
+ hints.push({ id: "chart-pick", key: "Enter", label: timePickLabel, onPress: () => pickingPrice ? chartActionsRef.current.pickPrice() : chartActionsRef.current.pick() });
622
699
  } else if (toolsActive && armedHints) {
623
700
  hints.push(placing
624
701
  ? { id: "chart-tool", key: "Enter", label: armedHints.finish, title: armedHints.finishTitle, onPress: () => chartActionsRef.current.finish() }
@@ -686,6 +763,29 @@ export function useCompositeChartKeyboard({
686
763
  });
687
764
  }
688
765
  if (resettable) menu.push({ id: "chart-reset", label: "Reset Zoom", accelerator: "0", onSelect: () => chartActionsRef.current.reset() });
766
+ menu.push({
767
+ id: "chart-toolbar",
768
+ label: toolbarHidden ? "Show Drawing Tools" : "Hide Drawing Tools",
769
+ accelerator: "Shift+T",
770
+ onSelect: () => chartActionsRef.current.layout.toggleToolbar(),
771
+ });
772
+ if (panelsResizable) {
773
+ menu.push({ id: "chart-panel-taller", label: "Taller Top Panel", accelerator: "Shift+Up", onSelect: () => chartActionsRef.current.layout.stepTopPanel(1) });
774
+ menu.push({ id: "chart-panel-shorter", label: "Shorter Top Panel", accelerator: "Shift+Down", onSelect: () => chartActionsRef.current.layout.stepTopPanel(-1) });
775
+ }
776
+ if (panelMaximized) {
777
+ menu.push({ id: "chart-panels-restore", label: "Show All Panels", onSelect: () => chartActionsRef.current.layout.restorePanels() });
778
+ } else if (panelHeightsSet) {
779
+ menu.push({ id: "chart-panels-reset", label: "Reset Panel Heights", onSelect: () => chartActionsRef.current.layout.resetPanelHeights() });
780
+ }
781
+ }
782
+ if (legendKeysActive && legendCollapsible) {
783
+ menu.push({
784
+ id: "chart-legend",
785
+ label: legendCollapsed ? "Expand Legend" : "Collapse Legend",
786
+ accelerator: "Shift+L",
787
+ onSelect: () => chartActionsRef.current.layout.toggleLegend(),
788
+ });
689
789
  }
690
790
  if (legendKeysActive && anyLegendToggleable && !drawingKeysActive) {
691
791
  menu.push({ id: "chart-series-next", label: "Next Series", accelerator: "]", onSelect: () => chartActionsRef.current.stepLegend(1) });
@@ -706,6 +806,7 @@ export function useCompositeChartKeyboard({
706
806
  !!scene,
707
807
  selectedDrawingId,
708
808
  timePickLabel,
809
+ pickingPrice,
709
810
  levelActionHint,
710
811
  levelToolKeys,
711
812
  levelItems.length,
@@ -713,6 +814,12 @@ export function useCompositeChartKeyboard({
713
814
  levelsEditable,
714
815
  toolsActive,
715
816
  pinState,
817
+ toolbarHidden,
818
+ legendCollapsible,
819
+ legendCollapsed,
820
+ panelsResizable,
821
+ panelHeightsSet,
822
+ panelMaximized,
716
823
  ]);
717
824
 
718
825
  return {
@@ -0,0 +1,44 @@
1
+ import { useCallback, useRef, useState } from "react";
2
+ import type { CompositeAxisSide } from "./types";
3
+ import { NO_VALUE_SCALES, valueScaleSlot, type CompositeValueRange, type CompositeValueScales } from "./value-scale";
4
+
5
+ /**
6
+ * The chart's manual value scales: set by a drag or the wheel on an axis, or
7
+ * a drag on the plot of a panel already scaled by hand; cleared per panel or
8
+ * all at once, and whenever `resetKey` changes (in the same render, so a new
9
+ * view never draws in the old one's scale).
10
+ */
11
+ export function useCompositeValueScales(resetKey: unknown) {
12
+ const [state, setState] = useState<{ resetKey: unknown; scales: CompositeValueScales }>(() => ({ resetKey, scales: NO_VALUE_SCALES }));
13
+ const resetKeyRef = useRef(resetKey);
14
+ resetKeyRef.current = resetKey;
15
+ const scales = Object.is(state.resetKey, resetKey) ? state.scales : NO_VALUE_SCALES;
16
+ const update = useCallback((change: (scales: CompositeValueScales) => CompositeValueScales) => {
17
+ setState((current) => {
18
+ const key = resetKeyRef.current;
19
+ const fresh = Object.is(current.resetKey, key);
20
+ const base = fresh ? current.scales : NO_VALUE_SCALES;
21
+ const next = change(base);
22
+ return fresh && next === base ? current : { resetKey: key, scales: next };
23
+ });
24
+ }, []);
25
+ const setValueScale = useCallback((panelId: string, side: CompositeAxisSide, key: string, range: CompositeValueRange) => {
26
+ const slot = valueScaleSlot(panelId, side);
27
+ update((current) => {
28
+ const previous = current[slot];
29
+ if (previous && previous.key === key && previous.min === range.min && previous.max === range.max) return current;
30
+ return { ...current, [slot]: { key, min: range.min, max: range.max } };
31
+ });
32
+ }, [update]);
33
+ const resetPanelValueScale = useCallback((panelId: string) => {
34
+ update((current) => {
35
+ const slots = (["left", "right"] as const).map((side) => valueScaleSlot(panelId, side)).filter((slot) => slot in current);
36
+ if (slots.length === 0) return current;
37
+ const next = { ...current };
38
+ for (const slot of slots) delete next[slot];
39
+ return Object.keys(next).length === 0 ? NO_VALUE_SCALES : next;
40
+ });
41
+ }, [update]);
42
+ const resetValueScales = useCallback(() => update(() => NO_VALUE_SCALES), [update]);
43
+ return { valueScales: scales, setValueScale, resetPanelValueScale, resetValueScales };
44
+ }
@@ -99,9 +99,13 @@ export function useCompositeViewport({
99
99
  );
100
100
  }, [onViewportChange, userViewportEnd, userViewportStart]);
101
101
 
102
+ // Counts authored views, so what belongs to one (values scaled by hand) can
103
+ // go with it; `authoredViewportChanged` covers the render before it counts.
104
+ const [authoredGeneration, setAuthoredGeneration] = useState(0);
102
105
  useEffect(() => {
103
106
  previousAuthoredViewportRef.current = viewport ?? null;
104
107
  previousViewportResetKeyRef.current = viewportResetKey;
108
+ if (authoredViewportChanged) setAuthoredGeneration((generation) => generation + 1);
105
109
  if (authoredViewportChanged && userViewport) {
106
110
  viewportInteractionRef.current = "reset";
107
111
  setUserViewport(null);
@@ -154,8 +158,13 @@ export function useCompositeViewport({
154
158
  if (!positions) return;
155
159
  panViewport(shiftRatio * Math.max(positions.end - positions.start, Number.EPSILON));
156
160
  }, [effectiveViewport, navigationFrame, panViewport]);
157
- const zoomViewport = useCallback((zoomFactor: number, anchorRatio = 1) => {
158
- navigate("zoom", (base, frame) => zoomCompositeViewport(frame, base, zoomFactor, anchorRatio));
161
+ /** A gesture (a drag on the time axis) zooms from the view and frame it started in, by its whole travel so far. */
162
+ const zoomViewport = useCallback((
163
+ zoomFactor: number,
164
+ anchorRatio = 1,
165
+ gesture?: { frame: CompositeNavigationFrame; from: CompositeViewportRange },
166
+ ) => {
167
+ navigate("zoom", (base, frame) => zoomCompositeViewport(frame, base, zoomFactor, anchorRatio), gesture);
159
168
  }, [navigate]);
160
169
  const setViewportRange = useCallback((range: CompositeViewportRange) => {
161
170
  navigate("zoom", (_base, frame) => fitCompositeViewport(frame, range));
@@ -165,7 +174,7 @@ export function useCompositeViewport({
165
174
  setUserViewport(null);
166
175
  }, []);
167
176
  return {
168
- navigationFrame, activeUserViewport, effectiveViewport,
177
+ navigationFrame, activeUserViewport, effectiveViewport, authoredViewportChanged, authoredGeneration,
169
178
  panViewport, panViewportByRatio, zoomViewport, setViewportRange, resetViewport,
170
179
  };
171
180
  }
@@ -0,0 +1,149 @@
1
+ import type { PanelScale, ResolvedSeries } from "../../../time-series/types";
2
+ import type { CompositeAxisSide } from "./types";
3
+ import { clamp } from "../../../utils/math";
4
+
5
+ /** What a value axis shows, in its own values. */
6
+ export interface CompositeValueRange {
7
+ min: number;
8
+ max: number;
9
+ }
10
+
11
+ /**
12
+ * A value axis stretched or squeezed by hand, and what it plots: a range set
13
+ * for one listing's prices means nothing for another's, so it holds only
14
+ * while the axis plots the same series in the same unit and scale.
15
+ */
16
+ export interface CompositeManualValueScale extends CompositeValueRange {
17
+ key: string;
18
+ }
19
+
20
+ /** Manual value scales by panel and side (`valueScaleSlot`). */
21
+ export type CompositeValueScales = Readonly<Record<string, CompositeManualValueScale>>;
22
+
23
+ export const NO_VALUE_SCALES: CompositeValueScales = Object.freeze({});
24
+
25
+ export function valueScaleSlot(panelId: string, side: CompositeAxisSide): string {
26
+ return `${panelId}\u0000${side}`;
27
+ }
28
+
29
+ /** Identifies what an axis plots, for `CompositeManualValueScale.key`. */
30
+ export function valueScaleKey(scale: PanelScale, axisSeries: readonly ResolvedSeries[]): string {
31
+ return [
32
+ scale,
33
+ ...axisSeries.map((entry) => [entry.id, entry.label, entry.unit, entry.listing?.symbol ?? ""].join("\u0001")),
34
+ ].join("\u0000");
35
+ }
36
+
37
+ /** Pixels of drag along an axis that stretch or squeeze it by a factor of e. */
38
+ const AXIS_DRAG_PIXELS_PER_E = 200;
39
+ /** The finest and coarsest a linear axis may get, against the size of the values it shows. */
40
+ const MIN_LINEAR_SPAN_RATIO = 1e-9;
41
+ const MAX_LINEAR_SPAN = 1e15;
42
+ /** The same for a log axis, in natural-log units. */
43
+ const MIN_LOG_SPAN = 1e-9;
44
+ const MAX_LOG_SPAN = 60;
45
+
46
+ /**
47
+ * How much a drag of `deltaPx` along an axis multiplies the span it shows.
48
+ * Down a value axis or right along the time axis shows more (a factor above
49
+ * one), the other way less, and the way back undoes it exactly.
50
+ */
51
+ export function resolveAxisDragSpanFactor(deltaPx: number): number {
52
+ return Number.isFinite(deltaPx) ? Math.exp(deltaPx / AXIS_DRAG_PIXELS_PER_E) : 1;
53
+ }
54
+
55
+ function toAxis(value: number, scale: PanelScale): number {
56
+ return scale === "log" ? Math.log(value) : value;
57
+ }
58
+
59
+ function fromAxis(value: number, scale: PanelScale): number {
60
+ return scale === "log" ? Math.exp(value) : value;
61
+ }
62
+
63
+ /** The range as top and bottom in the axis's own space: values, or their logs. */
64
+ function axisEnds(range: CompositeValueRange, scale: PanelScale): { top: number; bottom: number } | null {
65
+ if (scale === "log" && (range.min <= 0 || range.max <= 0)) return null;
66
+ const top = toAxis(range.max, scale);
67
+ const bottom = toAxis(range.min, scale);
68
+ return Number.isFinite(top) && Number.isFinite(bottom) && top > bottom ? { top, bottom } : null;
69
+ }
70
+
71
+ function rangeFromEnds(top: number, bottom: number, scale: PanelScale): CompositeValueRange {
72
+ return { min: fromAxis(bottom, scale), max: fromAxis(top, scale) };
73
+ }
74
+
75
+ /**
76
+ * The range after multiplying its span by `spanFactor` (above one shows more)
77
+ * around the value at `anchorRatio`, 0 the top of the panel and 1 the bottom,
78
+ * which stays where it is. A log axis stretches in its own, logarithmic space.
79
+ */
80
+ export function zoomValueRange(
81
+ range: CompositeValueRange,
82
+ scale: PanelScale,
83
+ spanFactor: number,
84
+ anchorRatio: number,
85
+ ): CompositeValueRange {
86
+ const ends = axisEnds(range, scale);
87
+ if (!ends || !(spanFactor > 0) || !Number.isFinite(spanFactor)) return range;
88
+ const ratio = clamp(Number.isFinite(anchorRatio) ? anchorRatio : 0.5, 0, 1);
89
+ const span = ends.top - ends.bottom;
90
+ const anchor = ends.top - span * ratio;
91
+ const nextSpan = scale === "log"
92
+ ? clamp(span * spanFactor, MIN_LOG_SPAN, MAX_LOG_SPAN)
93
+ : clamp(span * spanFactor, Math.max(Math.abs(anchor), Number.MIN_VALUE) * MIN_LINEAR_SPAN_RATIO, MAX_LINEAR_SPAN);
94
+ const top = anchor + nextSpan * ratio;
95
+ return rangeFromEnds(top, top - nextSpan, scale);
96
+ }
97
+
98
+ /**
99
+ * The range moved with a drag of `deltaRatio` of the panel's height, positive
100
+ * downward: what was under the pointer stays under it.
101
+ */
102
+ export function panValueRange(
103
+ range: CompositeValueRange,
104
+ scale: PanelScale,
105
+ deltaRatio: number,
106
+ ): CompositeValueRange {
107
+ const ends = axisEnds(range, scale);
108
+ if (!ends || !Number.isFinite(deltaRatio) || deltaRatio === 0) return range;
109
+ const shift = (ends.top - ends.bottom) * deltaRatio;
110
+ return rangeFromEnds(ends.top + shift, ends.bottom + shift, scale);
111
+ }
112
+
113
+ /** A manual range holds while some of the data is in it; pushed clear of the data it fits the data again. */
114
+ export function manualValueRangeApplies(
115
+ manual: CompositeValueRange,
116
+ data: CompositeValueRange,
117
+ scale: PanelScale,
118
+ ): boolean {
119
+ const ends = axisEnds(manual, scale);
120
+ return !!ends && manual.max > data.min && manual.min < data.max;
121
+ }
122
+
123
+ /**
124
+ * Keeps an end of a segment that leaves the band from `minY` to `maxY` on the
125
+ * band's edge, along the segment: what is drawn of it inside stays exact and
126
+ * nothing is drawn far outside. Null when it misses the band.
127
+ */
128
+ export function clipSegmentToBand(
129
+ x0: number,
130
+ y0: number,
131
+ x1: number,
132
+ y1: number,
133
+ minY: number,
134
+ maxY: number,
135
+ ): [number, number, number, number] | null {
136
+ if ((y0 < minY && y1 < minY) || (y0 > maxY && y1 > maxY)) return null;
137
+ if (y0 >= minY && y0 <= maxY && y1 >= minY && y1 <= maxY) return [x0, y0, x1, y1];
138
+ const at = (y: number) => {
139
+ const t = (y - y0) / (y1 - y0);
140
+ return x0 + (x1 - x0) * t;
141
+ };
142
+ let startX = x0;
143
+ let startY = y0;
144
+ let endX = x1;
145
+ let endY = y1;
146
+ if (startY < minY) { startX = at(minY); startY = minY; } else if (startY > maxY) { startX = at(maxY); startY = maxY; }
147
+ if (endY < minY) { endX = at(minY); endY = minY; } else if (endY > maxY) { endX = at(maxY); endY = maxY; }
148
+ return [startX, startY, endX, endY];
149
+ }
@@ -27,7 +27,8 @@ export function paintVolumeProfile(
27
27
  row.volume > (profile.rows[best]?.volume ?? -1) ? index : best
28
28
  ), 0);
29
29
  profile.rows.forEach((row, index) => {
30
- if (row.volume <= 0) return;
30
+ // Rows a hand-scaled axis leaves off the panel are not piled on its edge.
31
+ if (row.volume <= 0 || row.highRatio > 1 || row.lowRatio < 0) return;
31
32
  const top = Math.round(clamp(row.highRatio, 0, 1) * maxY);
32
33
  const edge = Math.round(clamp(row.lowRatio, 0, 1) * maxY);
33
34
  // A pixel between rows keeps tall bars apart; thin ones would vanish.
@@ -36,7 +37,8 @@ export function paintVolumeProfile(
36
37
  const opacity = index === pocRow ? POC_OPACITY : row.valueArea ? VALUE_AREA_OPACITY : OUTSIDE_OPACITY;
37
38
  fillRect(data, width, height, width - length, top, width - 1, bottom, color, opacity);
38
39
  });
39
- const y = Math.round(clamp(profile.pocRatio, 0, 1) * maxY);
40
+ if (profile.pocRatio < 0 || profile.pocRatio > 1) return;
41
+ const y = Math.round(profile.pocRatio * maxY);
40
42
  for (let x = 0; x < width; x += 5) {
41
43
  fillRect(data, width, height, x, y, Math.min(x + 1, width - 1), y, color, 0.7);
42
44
  }
@@ -57,13 +59,14 @@ export function writeVolumeProfileText(
57
59
  const volumes = new Array<number>(height).fill(0);
58
60
  const valueArea = new Array<boolean>(height).fill(false);
59
61
  for (const row of profile.rows) {
62
+ if (row.highRatio > 1 || row.lowRatio < 0) continue;
60
63
  const line = clamp(Math.round(((row.highRatio + row.lowRatio) / 2) * (height - 1)), 0, height - 1);
61
64
  volumes[line]! += row.volume;
62
65
  if (row.valueArea) valueArea[line] = true;
63
66
  }
64
67
  const peak = Math.max(...volumes);
65
68
  if (peak <= 0) return;
66
- const pocLine = clamp(Math.round(profile.pocRatio * (height - 1)), 0, height - 1);
69
+ const pocLine = profile.pocRatio < 0 || profile.pocRatio > 1 ? -1 : Math.round(profile.pocRatio * (height - 1));
67
70
  const maxLength = Math.max(1, Math.floor(width * PROFILE_WIDTH_RATIO));
68
71
  volumes.forEach((volume, line) => {
69
72
  if (volume <= 0) return;
@@ -21,6 +21,8 @@ export interface ChartMouseEvent {
21
21
  y: number;
22
22
  /** DOM target on the desktop host; absent in the terminal. */
23
23
  target?: { closest?: (selector: string) => unknown } | null;
24
+ /** The press's click count on the desktop host (2 on a double click); absent in the terminal. */
25
+ detail?: number;
24
26
  preciseX?: number;
25
27
  preciseY?: number;
26
28
  pixelX?: number;
@@ -6,6 +6,8 @@ export {
6
6
  fitChartTableColumns,
7
7
  } from "./layout";
8
8
  export type { ChartBandMode, ChartTableLayout } from "./layout";
9
+ export { ChartRead, useChartReadRows } from "./read";
10
+ export type { ChartReadProps } from "./read";
9
11
  export { useChartTableSelection } from "./selection";
10
12
  export type { ChartTableSelection } from "./selection";
11
13
  export { formatBpAxis, formatCompactAxis, formatPercentAxis, spanAxisFormatter, spanDigits } from "./axis";
@@ -0,0 +1,74 @@
1
+ import { useThemeColors } from "../../theme/theme-context";
2
+ import { Box, Text, useUiCapabilities } from "../../ui";
3
+ import { displayWidth, truncateToDisplayWidth } from "../../utils/format";
4
+ import { wrapTextLines } from "../../utils/text-wrap";
5
+ import { ClippedText } from "../ui/display";
6
+
7
+ /** The terminal wraps a read onto at most this many rows; a longer one ends in an ellipsis on the last. */
8
+ export const CHART_READ_MAX_ROWS = 3;
9
+ /** The read's inset on each side, as on the query bar and the legend above it. */
10
+ const READ_INSET = 1;
11
+
12
+ /**
13
+ * The terminal's lines for a read under a chart at a pane `width`: the whole
14
+ * sentence on one row when it fits, otherwise wrapped at words onto up to
15
+ * `CHART_READ_MAX_ROWS` rows. None when there is no read or no room for one.
16
+ */
17
+ export function chartReadLines(text: string | null | undefined, width: number): string[] {
18
+ const room = Math.floor(width) - 2 * READ_INSET;
19
+ const read = text?.trim();
20
+ if (!read || room <= 0) return [];
21
+ if (displayWidth(read) <= room) return [read];
22
+ const lines = wrapTextLines(read, room);
23
+ if (lines.length <= CHART_READ_MAX_ROWS) return lines;
24
+ return [
25
+ ...lines.slice(0, CHART_READ_MAX_ROWS - 1),
26
+ truncateToDisplayWidth(lines.slice(CHART_READ_MAX_ROWS - 1).join(" "), room),
27
+ ];
28
+ }
29
+
30
+ /**
31
+ * The rows the longest of these reads needs under a chart at a pane `width`
32
+ * (none when none has one). A pane puts it in `minRows` so the band does not
33
+ * flip between a chart and a strip as the selection moves between a short
34
+ * read and a long one. The desktop and the web cut a read by CSS on one row.
35
+ */
36
+ export function useChartReadRows(texts: ReadonlyArray<string | null | undefined>, width: number): number {
37
+ const { nativePaneChrome } = useUiCapabilities();
38
+ let rows = 0;
39
+ for (const text of texts) {
40
+ const lines = chartReadLines(text, width).length;
41
+ rows = Math.max(rows, nativePaneChrome ? Math.min(1, lines) : lines);
42
+ }
43
+ return rows;
44
+ }
45
+
46
+ export interface ChartReadProps {
47
+ /** The plain sentence worked out from the numbers, as the server wrote it. */
48
+ text: string | null | undefined;
49
+ /** The pane's width: the read sits one cell in from each edge. */
50
+ width: number;
51
+ }
52
+
53
+ /**
54
+ * The plain read under a chart's axis. In the terminal the whole sentence is
55
+ * wrapped onto up to `CHART_READ_MAX_ROWS` rows (take its rows from the chart
56
+ * with `useChartReadRows`); the desktop and the web keep one row and cut it
57
+ * by CSS where its box ends.
58
+ */
59
+ export function ChartRead({ text, width }: ChartReadProps) {
60
+ const colors = useThemeColors();
61
+ const { nativePaneChrome } = useUiCapabilities();
62
+ const lines = chartReadLines(text, width);
63
+ if (lines.length === 0) return null;
64
+ if (nativePaneChrome) {
65
+ return <Box height={1} paddingX={READ_INSET}><ClippedText fg={colors.textMuted} text={text!.trim()} width={width - 2 * READ_INSET} /></Box>;
66
+ }
67
+ return (
68
+ <Box flexDirection="column" height={lines.length} flexShrink={0}>
69
+ {lines.map((line, index) => (
70
+ <Box key={index} height={1} paddingX={READ_INSET}><Text fg={colors.textMuted}>{line}</Text></Box>
71
+ ))}
72
+ </Box>
73
+ );
74
+ }