gloomberb 0.16.0 → 0.16.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (691) hide show
  1. package/README.md +2 -1
  2. package/package.json +2 -1
  3. package/src/api-client/beneficial-owners.ts +92 -0
  4. package/src/api-client/data.ts +44 -11
  5. package/src/api-client/errors.ts +12 -0
  6. package/src/api-client/geo.ts +363 -0
  7. package/src/api-client/index.ts +5 -0
  8. package/src/api-client/market-discovery.ts +10 -0
  9. package/src/api-client/members.ts +26 -0
  10. package/src/api-client/paths.ts +30 -1
  11. package/src/api-client/perps.ts +41 -0
  12. package/src/api-client/request.ts +5 -2
  13. package/src/api-client/types.ts +9 -1
  14. package/src/app/global-shortcuts.ts +14 -6
  15. package/src/app/keybindings/actions.ts +1 -1
  16. package/src/app/runtime/update.ts +38 -2
  17. package/src/app.tsx +10 -6
  18. package/src/brokers/account-cache.ts +24 -0
  19. package/src/cli/commands/command-utils.ts +8 -0
  20. package/src/cli/commands/crypto-hints.ts +75 -0
  21. package/src/cli/commands/market.ts +414 -106
  22. package/src/cli/commands/overview.ts +77 -32
  23. package/src/cli/commands/ticker.ts +101 -43
  24. package/src/cli/desktop-pane-shot.ts +34 -4
  25. package/src/cli/freshness.ts +61 -0
  26. package/src/cli/help.ts +1 -0
  27. package/src/cli/helpers.ts +4 -8
  28. package/src/cli/index.ts +12 -2
  29. package/src/cli/listing-arg.ts +321 -0
  30. package/src/cli/pane-functions/access-gate.ts +42 -0
  31. package/src/cli/pane-functions/catalog.ts +28 -1
  32. package/src/cli/pane-functions/data.ts +3 -1
  33. package/src/cli/pane-functions/dom.ts +20 -2
  34. package/src/cli/pane-functions/freshness.ts +400 -0
  35. package/src/cli/pane-functions/function-help.ts +36 -22
  36. package/src/cli/pane-functions/headless.ts +39 -11
  37. package/src/cli/pane-functions/index.ts +15 -4
  38. package/src/cli/pane-functions/options.ts +3 -0
  39. package/src/cli/pane-functions/report.ts +4 -0
  40. package/src/cli/pane-functions/resolver.ts +35 -7
  41. package/src/cli/pane-functions/screenshot-evidence.ts +2 -0
  42. package/src/cli/pane-functions/screenshot.ts +7 -3
  43. package/src/cli/result.ts +41 -27
  44. package/src/cli/ticker-resolution.ts +7 -5
  45. package/src/components/chart/composite/composite-chart.tsx +88 -2536
  46. package/src/components/chart/composite/drawing-store.ts +59 -0
  47. package/src/components/chart/composite/legend.tsx +319 -0
  48. package/src/components/chart/composite/panel-bitmap.ts +139 -0
  49. package/src/components/chart/composite/panel-gestures.ts +59 -0
  50. package/src/components/chart/composite/panel-labels.ts +107 -0
  51. package/src/components/chart/composite/panel-surface.tsx +876 -0
  52. package/src/components/chart/composite/tool-catalog.ts +98 -0
  53. package/src/components/chart/composite/toolbar.tsx +186 -0
  54. package/src/components/chart/composite/tools.ts +8 -0
  55. package/src/components/chart/composite/use-composite-chart-keyboard.ts +703 -0
  56. package/src/components/chart/composite/use-composite-viewport.ts +143 -0
  57. package/src/components/command-bar/commands/collection.ts +5 -1
  58. package/src/components/command-bar/list/model.ts +5 -0
  59. package/src/components/command-bar/list/view.tsx +16 -3
  60. package/src/components/command-bar/pane-templates/workflow.ts +1 -0
  61. package/src/components/command-bar/routes/root/command-items.ts +9 -2
  62. package/src/components/command-bar/routes/root/plugin-install.ts +2 -2
  63. package/src/components/command-bar/routes/root/provider-search.ts +19 -5
  64. package/src/components/command-bar/routes/root/runtime.ts +14 -5
  65. package/src/components/command-bar/routes/ticker-search/actions.ts +5 -0
  66. package/src/components/command-bar/routes/ticker-search/results.ts +31 -5
  67. package/src/components/command-bar/routes/ticker-search/route.ts +2 -2
  68. package/src/components/command-bar/routing/actions.ts +2 -0
  69. package/src/components/command-bar/selection-runtime.ts +38 -0
  70. package/src/components/command-bar/surface/index.tsx +7 -2
  71. package/src/components/command-bar/workflow/ops.ts +1 -1
  72. package/src/components/command-bar/workflow/tickers.ts +6 -0
  73. package/src/components/data-table/view.tsx +29 -10
  74. package/src/components/feedback-dialog.tsx +2 -1
  75. package/src/components/form-modal/field-row.tsx +2 -2
  76. package/src/components/index.ts +2 -2
  77. package/src/components/layout/detached-pane-shell.tsx +6 -3
  78. package/src/components/layout/floating-pane.tsx +6 -0
  79. package/src/components/layout/header.tsx +24 -7
  80. package/src/components/layout/missing-pane.tsx +2 -2
  81. package/src/components/layout/pane/content.tsx +23 -10
  82. package/src/components/layout/pane/error-boundary.tsx +103 -0
  83. package/src/components/layout/pane/footer/registration.tsx +68 -23
  84. package/src/components/layout/pane/header.tsx +61 -28
  85. package/src/components/layout/pane/index.tsx +6 -0
  86. package/src/components/layout/pane/title.ts +31 -7
  87. package/src/components/layout/shell/drag/index.ts +6 -5
  88. package/src/components/layout/shell/drag/runtime.ts +3 -0
  89. package/src/components/layout/shell/index.tsx +6 -0
  90. package/src/components/layout/shell/menu.ts +2 -1
  91. package/src/components/layout/shell/pane/actions.ts +2 -1
  92. package/src/components/layout/shell/pane/layers.tsx +29 -10
  93. package/src/components/layout/shell/terminal-pointer-runtime.ts +24 -3
  94. package/src/components/layout/shell/ticker-link-menu.ts +23 -9
  95. package/src/components/metric-treemap/heat-surface.tsx +745 -0
  96. package/src/components/metric-treemap/heat-tiles.ts +228 -0
  97. package/src/components/metric-treemap/index.tsx +2 -0
  98. package/src/components/metric-treemap/layout.ts +8 -0
  99. package/src/components/metric-treemap/scene.ts +432 -0
  100. package/src/components/onboarding/onboarding-keyboard.ts +311 -0
  101. package/src/components/onboarding/onboarding-wizard.tsx +101 -788
  102. package/src/components/onboarding/use-onboarding-broker-form.ts +263 -0
  103. package/src/components/onboarding/use-onboarding-progress.ts +298 -0
  104. package/src/components/onboarding/use-onboarding-upgrade.ts +83 -0
  105. package/src/components/pane-settings-dialog/field-dialogs.tsx +1 -0
  106. package/src/components/ticker/list-table-view.tsx +13 -1
  107. package/src/components/toggle-list.tsx +38 -12
  108. package/src/components/ui/country-flag-art.tsx +449 -0
  109. package/src/components/ui/country-flag.tsx +41 -0
  110. package/src/components/ui/data-table/types.ts +13 -0
  111. package/src/components/ui/fields.tsx +8 -0
  112. package/src/components/ui/icon.tsx +2 -0
  113. package/src/components/ui/index.ts +4 -0
  114. package/src/components/ui/multi-select/dialog.tsx +108 -22
  115. package/src/components/ui/range-track.tsx +53 -0
  116. package/src/components/ui/status.tsx +8 -2
  117. package/src/components/ui/tabs.tsx +11 -4
  118. package/src/components/ui/text-prompt-dialog.tsx +4 -2
  119. package/src/core/state/app/types.ts +10 -1
  120. package/src/data/config/store/normalize.ts +17 -1
  121. package/src/i18n/es.ts +24 -4
  122. package/src/i18n/ja.ts +24 -4
  123. package/src/i18n/ko.ts +24 -4
  124. package/src/i18n/zh-cn.ts +24 -4
  125. package/src/i18n/zh-tw.ts +24 -4
  126. package/src/layout/ticker-navigation.ts +28 -2
  127. package/src/market-data/coordinator/chart.ts +1 -1
  128. package/src/market-data/coordinator/quotes.ts +23 -4
  129. package/src/market-data/fx-closes.ts +72 -0
  130. package/src/market-data/market/freshness.ts +78 -6
  131. package/src/market-data/market/session-close-note.ts +57 -0
  132. package/src/market-data/market/status.ts +151 -0
  133. package/src/market-data/published-apac-sessions.ts +66 -0
  134. package/src/market-data/quotes/contributions.ts +8 -0
  135. package/src/market-data/quotes/freshness.ts +36 -0
  136. package/src/market-data/quotes/resolution.ts +24 -8
  137. package/src/market-data/quotes/screener-live-quotes.ts +49 -4
  138. package/src/market-data/quotes/time.ts +16 -0
  139. package/src/plugins/builtin/account-management/pane.tsx +4 -0
  140. package/src/plugins/builtin/alerts/cli.ts +10 -5
  141. package/src/plugins/builtin/alerts/index.tsx +1 -0
  142. package/src/plugins/builtin/analytics/metrics.ts +8 -3
  143. package/src/plugins/builtin/analytics/risk-client.ts +330 -79
  144. package/src/plugins/builtin/analytics/risk-fx.ts +102 -0
  145. package/src/plugins/builtin/analytics/risk-headless.ts +61 -49
  146. package/src/plugins/builtin/analytics/risk-math.ts +33 -13
  147. package/src/plugins/builtin/analytics/risk-model.ts +282 -64
  148. package/src/plugins/builtin/analytics/risk-pane.tsx +62 -30
  149. package/src/plugins/builtin/analytics/risk-test-data.ts +206 -0
  150. package/src/plugins/builtin/attention/headless.ts +6 -4
  151. package/src/plugins/builtin/attention/index.tsx +1 -1
  152. package/src/plugins/builtin/attention/pane.tsx +1 -1
  153. package/src/plugins/builtin/awards/headless.ts +1 -0
  154. package/src/plugins/builtin/awards/pane.tsx +1 -1
  155. package/src/plugins/builtin/backtest/headless.ts +1 -0
  156. package/src/plugins/builtin/bond-calculator/headless.ts +1 -0
  157. package/src/plugins/builtin/buildout/cells.tsx +15 -12
  158. package/src/plugins/builtin/buildout/detail/company.tsx +3 -3
  159. package/src/plugins/builtin/buildout/detail/index.tsx +0 -1
  160. package/src/plugins/builtin/buildout/detail/intel.tsx +6 -6
  161. package/src/plugins/builtin/buildout/detail/site.tsx +4 -7
  162. package/src/plugins/builtin/buildout/detail/ui.tsx +0 -19
  163. package/src/plugins/builtin/buildout/index.tsx +1 -0
  164. package/src/plugins/builtin/catalysts/headless.ts +3 -1
  165. package/src/plugins/builtin/catalysts/index.tsx +2 -2
  166. package/src/plugins/builtin/catalysts/pane.tsx +3 -1
  167. package/src/plugins/builtin/cds/headless.ts +2 -0
  168. package/src/plugins/builtin/cds/index.tsx +1 -0
  169. package/src/plugins/builtin/central-bank-rates/headless.ts +1 -0
  170. package/src/plugins/builtin/chart-composer/headless.ts +38 -3
  171. package/src/plugins/builtin/chart-composer/index.tsx +3 -1
  172. package/src/plugins/builtin/chart-composer/series-expression.ts +18 -2
  173. package/src/plugins/builtin/chat/channels.ts +19 -3
  174. package/src/plugins/builtin/chat/content/composer-runtime.ts +28 -13
  175. package/src/plugins/builtin/chat/content/footer.tsx +15 -6
  176. package/src/plugins/builtin/chat/content/index.tsx +120 -21
  177. package/src/plugins/builtin/chat/content/new-dm-dialog.tsx +261 -113
  178. package/src/plugins/builtin/chat/content/transcript.tsx +20 -2
  179. package/src/plugins/builtin/chat/direct-messages.ts +200 -0
  180. package/src/plugins/builtin/chat/index.tsx +1 -0
  181. package/src/plugins/builtin/chat/message/desktop.tsx +3 -0
  182. package/src/plugins/builtin/chat/message/header.tsx +16 -6
  183. package/src/plugins/builtin/chat/message/inline-tokens.tsx +72 -32
  184. package/src/plugins/builtin/chat/message/profile-popover.tsx +96 -12
  185. package/src/plugins/builtin/chat/message/terminal.tsx +3 -0
  186. package/src/plugins/builtin/chat/message/types.ts +14 -2
  187. package/src/plugins/builtin/chat/profile-popover.ts +18 -13
  188. package/src/plugins/builtin/clinical-trials/index.tsx +1 -0
  189. package/src/plugins/builtin/cloud/askg/executor.ts +2 -1
  190. package/src/plugins/builtin/cloud/plugin.tsx +1 -0
  191. package/src/plugins/builtin/cloud/team/module.tsx +1 -0
  192. package/src/plugins/builtin/cloud/thesis/module.tsx +1 -0
  193. package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
  194. package/src/plugins/builtin/comment-letters/index.tsx +1 -0
  195. package/src/plugins/builtin/company-attention/headless.ts +5 -1
  196. package/src/plugins/builtin/company-attention/pane.tsx +1 -1
  197. package/src/plugins/builtin/company-kpis/headless.ts +1 -0
  198. package/src/plugins/builtin/congress-trades/headless.ts +1 -0
  199. package/src/plugins/builtin/correlation/compute.ts +59 -16
  200. package/src/plugins/builtin/correlation/geo.ts +34 -0
  201. package/src/plugins/builtin/correlation/headless-schema.ts +4 -1
  202. package/src/plugins/builtin/correlation/headless.ts +42 -8
  203. package/src/plugins/builtin/correlation/history.ts +2 -0
  204. package/src/plugins/builtin/correlation/index.tsx +68 -14
  205. package/src/plugins/builtin/correlation/matrix/model.ts +17 -2
  206. package/src/plugins/builtin/correlation/matrix/selection.ts +5 -3
  207. package/src/plugins/builtin/correlation/relationship/model.ts +1 -1
  208. package/src/plugins/builtin/correlation/relationship/pane.tsx +4 -2
  209. package/src/plugins/builtin/correlation/relationship/view-model.ts +16 -1
  210. package/src/plugins/builtin/correlation/settings.ts +1 -1
  211. package/src/plugins/builtin/cot/headless.ts +6 -3
  212. package/src/plugins/builtin/cot/index.tsx +3 -3
  213. package/src/plugins/builtin/cot/model.ts +36 -3
  214. package/src/plugins/builtin/cpi/headless.ts +4 -0
  215. package/src/plugins/builtin/credit-boards/headless.ts +2 -0
  216. package/src/plugins/builtin/credit-conditions/headless.ts +1 -0
  217. package/src/plugins/builtin/credit-documents/gauge.tsx +5 -8
  218. package/src/plugins/builtin/credit-documents/headless.ts +2 -0
  219. package/src/plugins/builtin/crypto-board/headless.ts +3 -0
  220. package/src/plugins/builtin/custom-view/loader.ts +1 -1
  221. package/src/plugins/builtin/debt-maturities/headless.ts +4 -0
  222. package/src/plugins/builtin/debt-maturities/wall-bar.tsx +14 -41
  223. package/src/plugins/builtin/dividend-yield/client.ts +4 -2
  224. package/src/plugins/builtin/dividend-yield/headless.ts +1 -0
  225. package/src/plugins/builtin/doe/headless.ts +7 -0
  226. package/src/plugins/builtin/doe/range-bar.tsx +7 -37
  227. package/src/plugins/builtin/earnings/client.ts +2 -2
  228. package/src/plugins/builtin/earnings/headless.ts +5 -0
  229. package/src/plugins/builtin/earnings-calls/headless.ts +1 -0
  230. package/src/plugins/builtin/earnings-calls/index.tsx +1 -0
  231. package/src/plugins/builtin/earnings-ripple/client.ts +91 -18
  232. package/src/plugins/builtin/earnings-ripple/headless.ts +28 -8
  233. package/src/plugins/builtin/earnings-ripple/index.tsx +2 -2
  234. package/src/plugins/builtin/earnings-ripple/model.ts +97 -7
  235. package/src/plugins/builtin/earnings-ripple/pane.tsx +148 -23
  236. package/src/plugins/builtin/econ/index.tsx +1 -0
  237. package/src/plugins/builtin/econ-statistics/headless.ts +2 -0
  238. package/src/plugins/builtin/equity-screener/headless.ts +2 -0
  239. package/src/plugins/builtin/estimate-revisions/headless.ts +1 -0
  240. package/src/plugins/builtin/executives/index.tsx +1 -0
  241. package/src/plugins/builtin/exposure/headless.ts +3 -1
  242. package/src/plugins/builtin/fear-greed/headless.ts +2 -0
  243. package/src/plugins/builtin/filing-events/index.tsx +1 -0
  244. package/src/plugins/builtin/futures-curve/client.ts +12 -3
  245. package/src/plugins/builtin/futures-curve/headless.ts +39 -10
  246. package/src/plugins/builtin/futures-curve/index.tsx +3 -3
  247. package/src/plugins/builtin/futures-curve/model.ts +188 -4
  248. package/src/plugins/builtin/futures-curve/pane.tsx +51 -9
  249. package/src/plugins/builtin/fx-matrix/direction.ts +81 -0
  250. package/src/plugins/builtin/fx-matrix/index.tsx +71 -33
  251. package/src/plugins/builtin/fx-matrix/live-legs.ts +17 -0
  252. package/src/plugins/builtin/fx-matrix/pairs.ts +68 -14
  253. package/src/plugins/builtin/fx-matrix/settings.ts +62 -0
  254. package/src/plugins/builtin/gpu/headless.ts +7 -3
  255. package/src/plugins/builtin/gpu/ladder.tsx +26 -30
  256. package/src/plugins/builtin/gpu/model.ts +27 -1
  257. package/src/plugins/builtin/holders/beneficial-client.ts +209 -0
  258. package/src/plugins/builtin/holders/beneficial-model.ts +279 -0
  259. package/src/plugins/builtin/holders/beneficial-report.ts +126 -0
  260. package/src/plugins/builtin/holders/beneficial-view.tsx +241 -0
  261. package/src/plugins/builtin/holders/headless.ts +139 -5
  262. package/src/plugins/builtin/holders/index.tsx +10 -3
  263. package/src/plugins/builtin/holders/pane.tsx +20 -3
  264. package/src/plugins/builtin/holders/report-header.ts +95 -0
  265. package/src/plugins/builtin/holders/table-model.ts +20 -5
  266. package/src/plugins/builtin/holders/thirteenf-match.ts +29 -1
  267. package/src/plugins/builtin/holders/types.ts +2 -1
  268. package/src/plugins/builtin/insider/headless.ts +2 -0
  269. package/src/plugins/builtin/ipo-calendar/headless.ts +1 -0
  270. package/src/plugins/builtin/iv-history/headless.ts +4 -1
  271. package/src/plugins/builtin/jobs/headless.ts +1 -0
  272. package/src/plugins/builtin/jobs/index.tsx +1 -0
  273. package/src/plugins/builtin/jobs/share-bars.tsx +5 -28
  274. package/src/plugins/builtin/kelly-sizer/index.tsx +1 -0
  275. package/src/plugins/builtin/macro-day/headless.ts +2 -0
  276. package/src/plugins/builtin/market-halts/index.tsx +1 -0
  277. package/src/plugins/builtin/market-heatmap/data.ts +30 -2
  278. package/src/plugins/builtin/market-heatmap/headless.ts +135 -0
  279. package/src/plugins/builtin/market-heatmap/index.tsx +245 -81
  280. package/src/plugins/builtin/market-heatmap/live.ts +88 -0
  281. package/src/plugins/builtin/market-heatmap/model.ts +146 -0
  282. package/src/plugins/builtin/market-heatmap/portfolio.ts +50 -11
  283. package/src/plugins/builtin/market-movers/client.ts +3 -2
  284. package/src/plugins/builtin/market-movers/headless.ts +10 -1
  285. package/src/plugins/builtin/market-movers/screener.ts +18 -5
  286. package/src/plugins/builtin/market-valuation/headless.ts +2 -0
  287. package/src/plugins/builtin/members/client.ts +53 -0
  288. package/src/plugins/builtin/members/headless.ts +35 -0
  289. package/src/plugins/builtin/members/index.tsx +20 -0
  290. package/src/plugins/builtin/members/model.ts +68 -0
  291. package/src/plugins/builtin/members/pane.tsx +175 -0
  292. package/src/plugins/builtin/mna/distress/headless.ts +1 -0
  293. package/src/plugins/builtin/mna/headless.ts +1 -0
  294. package/src/plugins/builtin/mna/index.tsx +2 -1
  295. package/src/plugins/builtin/mna/pane.tsx +5 -2
  296. package/src/plugins/builtin/money-markets/headless.ts +1 -0
  297. package/src/plugins/builtin/news/headless.ts +2 -0
  298. package/src/plugins/builtin/news/wire/index.tsx +8 -1
  299. package/src/plugins/builtin/notes/cli.ts +14 -6
  300. package/src/plugins/builtin/notes/index.tsx +1 -0
  301. package/src/plugins/builtin/openfda/index.tsx +1 -0
  302. package/src/plugins/builtin/options/index.tsx +2 -1
  303. package/src/plugins/builtin/options-calculator/headless.ts +2 -0
  304. package/src/plugins/builtin/options-positioning/headless.ts +3 -0
  305. package/src/plugins/builtin/options-scenario/headless.ts +5 -0
  306. package/src/plugins/builtin/pe-band/client.ts +74 -2
  307. package/src/plugins/builtin/pe-band/headless.ts +26 -8
  308. package/src/plugins/builtin/pe-band/model.ts +102 -22
  309. package/src/plugins/builtin/pe-band/pane.tsx +34 -16
  310. package/src/plugins/builtin/pe-band/report-dates.ts +78 -0
  311. package/src/plugins/builtin/perps/client.ts +66 -5
  312. package/src/plugins/builtin/perps/equity-identity.ts +16 -0
  313. package/src/plugins/builtin/perps/equity-row.tsx +6 -4
  314. package/src/plugins/builtin/perps/headless.ts +144 -16
  315. package/src/plugins/builtin/perps/index.tsx +6 -6
  316. package/src/plugins/builtin/perps/model.ts +189 -12
  317. package/src/plugins/builtin/perps/pane.tsx +248 -47
  318. package/src/plugins/builtin/plugin-marketplace/activation.ts +19 -0
  319. package/src/plugins/builtin/plugin-marketplace/pane.tsx +2 -2
  320. package/src/plugins/builtin/plugin-marketplace/store.ts +2 -0
  321. package/src/plugins/builtin/portfolio-list/allocation.ts +245 -0
  322. package/src/plugins/builtin/portfolio-list/cached-account.ts +33 -0
  323. package/src/plugins/builtin/portfolio-list/cell-version.ts +19 -1
  324. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +328 -29
  325. package/src/plugins/builtin/portfolio-list/cli/render.ts +230 -39
  326. package/src/plugins/builtin/portfolio-list/cli/shared.ts +67 -2
  327. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +35 -31
  328. package/src/plugins/builtin/portfolio-list/column-values.ts +124 -47
  329. package/src/plugins/builtin/portfolio-list/headless.ts +98 -16
  330. package/src/plugins/builtin/portfolio-list/index.tsx +14 -3
  331. package/src/plugins/builtin/portfolio-list/live-valuation.ts +7 -5
  332. package/src/plugins/builtin/portfolio-list/mutations.ts +55 -1
  333. package/src/plugins/builtin/portfolio-list/pane/data.ts +6 -0
  334. package/src/plugins/builtin/portfolio-list/pane/index.tsx +47 -13
  335. package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +43 -2
  336. package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +48 -5
  337. package/src/plugins/builtin/portfolio-list/settings.ts +33 -2
  338. package/src/plugins/builtin/portfolio-list/summary/index.tsx +24 -1
  339. package/src/plugins/builtin/portfolio-list/summary/totals.ts +26 -7
  340. package/src/plugins/builtin/power/headless.ts +3 -1
  341. package/src/plugins/builtin/rate-path/headless.ts +2 -0
  342. package/src/plugins/builtin/realized-vol/headless.ts +2 -0
  343. package/src/plugins/builtin/relative-rotation/headless.ts +2 -0
  344. package/src/plugins/builtin/research/analyst-headless.ts +3 -0
  345. package/src/plugins/builtin/research/events-headless.ts +2 -0
  346. package/src/plugins/builtin/research/headless.ts +2 -0
  347. package/src/plugins/builtin/research/index.tsx +1 -0
  348. package/src/plugins/builtin/research/relative-valuation-headless.ts +10 -5
  349. package/src/plugins/builtin/research/relative-valuation-model.ts +11 -3
  350. package/src/plugins/builtin/research/relative-valuation-pane.tsx +3 -3
  351. package/src/plugins/builtin/research-search/index.tsx +1 -0
  352. package/src/plugins/builtin/revenue-breakdown/headless.ts +2 -0
  353. package/src/plugins/builtin/reverse-dcf/headless.ts +2 -0
  354. package/src/plugins/builtin/risk-factors/headless.ts +2 -0
  355. package/src/plugins/builtin/scanner/flow-history.ts +2 -13
  356. package/src/plugins/builtin/scanner/headless.ts +14 -0
  357. package/src/plugins/builtin/scanner/hilo-bars.tsx +12 -70
  358. package/src/plugins/builtin/scanner/hilo-model.ts +0 -18
  359. package/src/plugins/builtin/seasonality/headless.ts +2 -0
  360. package/src/plugins/builtin/sec/command-bar-search.ts +14 -4
  361. package/src/plugins/builtin/sec/filing-content.ts +42 -17
  362. package/src/plugins/builtin/sec/forms.ts +12 -0
  363. package/src/plugins/builtin/sec/headless.ts +2 -0
  364. package/src/plugins/builtin/sectors/client.ts +1 -0
  365. package/src/plugins/builtin/sectors/headless.ts +9 -1
  366. package/src/plugins/builtin/sectors/move-bar.tsx +10 -32
  367. package/src/plugins/builtin/sectors/sector-model.ts +2 -0
  368. package/src/plugins/builtin/shared/crypto-pair.ts +14 -0
  369. package/src/plugins/builtin/shared/locked-rows.tsx +1 -1
  370. package/src/plugins/builtin/shared/report-freshness.ts +57 -0
  371. package/src/plugins/builtin/shared/research-cells.tsx +4 -9
  372. package/src/plugins/builtin/short-interest/headless.ts +2 -0
  373. package/src/plugins/builtin/short-interest/watch-headless.ts +1 -0
  374. package/src/plugins/builtin/short-volume/headless.ts +1 -0
  375. package/src/plugins/builtin/social-mentions/headless.ts +1 -0
  376. package/src/plugins/builtin/social-mentions/index.tsx +1 -1
  377. package/src/plugins/builtin/supply-chain/headless.ts +7 -1
  378. package/src/plugins/builtin/supply-chain/index.tsx +10 -1
  379. package/src/plugins/builtin/supply-chain/model.ts +27 -2
  380. package/src/plugins/builtin/supply-chain/pane.tsx +71 -32
  381. package/src/plugins/builtin/themes/headless.ts +3 -0
  382. package/src/plugins/builtin/thirteenf/headless.ts +110 -25
  383. package/src/plugins/builtin/thirteenf/index.tsx +2 -1
  384. package/src/plugins/builtin/thirteenf/report-notes.ts +149 -0
  385. package/src/plugins/builtin/ticker-detail/headless.ts +7 -1
  386. package/src/plugins/builtin/ticker-detail/index.tsx +1 -0
  387. package/src/plugins/builtin/ticker-detail/overview/components.tsx +5 -60
  388. package/src/plugins/builtin/ticker-detail/overview/model.ts +9 -2
  389. package/src/plugins/builtin/ticker-detail/overview/pane.tsx +1 -1
  390. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +26 -26
  391. package/src/plugins/builtin/ticker-detail/pane.tsx +1 -1
  392. package/src/plugins/builtin/ticker-detail/quote-footer.ts +7 -1
  393. package/src/plugins/builtin/ticker-detail/quote-monitor/card.tsx +20 -4
  394. package/src/plugins/builtin/ticker-detail/quote-monitor/index.tsx +2 -2
  395. package/src/plugins/builtin/time-sales/headless.ts +5 -1
  396. package/src/plugins/builtin/treasury-auctions/headless.ts +1 -0
  397. package/src/plugins/builtin/vol-surface/index.tsx +1 -1
  398. package/src/plugins/builtin/volatility/headless.ts +6 -1
  399. package/src/plugins/builtin/world-indices/headless.ts +2 -0
  400. package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +157 -0
  401. package/src/plugins/builtin/world-venue-map/basemap.ts +214 -0
  402. package/src/plugins/builtin/world-venue-map/client.ts +45 -0
  403. package/src/plugins/builtin/world-venue-map/entity-detail.tsx +147 -0
  404. package/src/plugins/builtin/world-venue-map/entity-table.ts +59 -0
  405. package/src/plugins/builtin/world-venue-map/evidence.ts +77 -0
  406. package/src/plugins/builtin/world-venue-map/feed.ts +293 -0
  407. package/src/plugins/builtin/world-venue-map/geo-draw.tsx +248 -0
  408. package/src/plugins/builtin/world-venue-map/geo-series.ts +142 -0
  409. package/src/plugins/builtin/world-venue-map/geo-svg.tsx +447 -0
  410. package/src/plugins/builtin/world-venue-map/headless.ts +146 -0
  411. package/src/plugins/builtin/world-venue-map/ids.ts +1 -0
  412. package/src/plugins/builtin/world-venue-map/index.ts +67 -4
  413. package/src/plugins/builtin/world-venue-map/layered-pane.tsx +552 -0
  414. package/src/plugins/builtin/world-venue-map/layers.ts +348 -0
  415. package/src/plugins/builtin/world-venue-map/map-symbols.ts +220 -0
  416. package/src/plugins/builtin/world-venue-map/map.tsx +381 -45
  417. package/src/plugins/builtin/world-venue-map/model.ts +7 -4
  418. package/src/plugins/builtin/world-venue-map/natural-earth/index.chunk.ts +199 -0
  419. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n00.chunk.ts +4 -0
  420. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n15.chunk.ts +4 -0
  421. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n30.chunk.ts +4 -0
  422. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n45.chunk.ts +4 -0
  423. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n60.chunk.ts +4 -0
  424. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n75.chunk.ts +4 -0
  425. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s15.chunk.ts +4 -0
  426. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s30.chunk.ts +4 -0
  427. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s60.chunk.ts +4 -0
  428. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n00.chunk.ts +4 -0
  429. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n15.chunk.ts +4 -0
  430. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n30.chunk.ts +4 -0
  431. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n45.chunk.ts +4 -0
  432. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n60.chunk.ts +4 -0
  433. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n75.chunk.ts +4 -0
  434. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s15.chunk.ts +4 -0
  435. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s30.chunk.ts +4 -0
  436. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s45.chunk.ts +4 -0
  437. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n00.chunk.ts +4 -0
  438. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n15.chunk.ts +4 -0
  439. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n30.chunk.ts +4 -0
  440. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n45.chunk.ts +4 -0
  441. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n60.chunk.ts +4 -0
  442. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n75.chunk.ts +4 -0
  443. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s15.chunk.ts +4 -0
  444. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s30.chunk.ts +4 -0
  445. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s45.chunk.ts +4 -0
  446. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s60.chunk.ts +4 -0
  447. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n00.chunk.ts +4 -0
  448. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n15.chunk.ts +4 -0
  449. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n30.chunk.ts +4 -0
  450. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n45.chunk.ts +4 -0
  451. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n60.chunk.ts +4 -0
  452. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n75.chunk.ts +4 -0
  453. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s15.chunk.ts +4 -0
  454. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s30.chunk.ts +4 -0
  455. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s60.chunk.ts +4 -0
  456. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n00.chunk.ts +4 -0
  457. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n15.chunk.ts +4 -0
  458. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n30.chunk.ts +4 -0
  459. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n45.chunk.ts +4 -0
  460. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n60.chunk.ts +4 -0
  461. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n75.chunk.ts +4 -0
  462. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s15.chunk.ts +4 -0
  463. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s30.chunk.ts +4 -0
  464. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s60.chunk.ts +4 -0
  465. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n00.chunk.ts +4 -0
  466. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n15.chunk.ts +4 -0
  467. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n30.chunk.ts +4 -0
  468. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n45.chunk.ts +4 -0
  469. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n60.chunk.ts +4 -0
  470. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n75.chunk.ts +4 -0
  471. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075s45.chunk.ts +4 -0
  472. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n00.chunk.ts +4 -0
  473. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n15.chunk.ts +4 -0
  474. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n30.chunk.ts +4 -0
  475. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n45.chunk.ts +4 -0
  476. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n60.chunk.ts +4 -0
  477. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n75.chunk.ts +4 -0
  478. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090s15.chunk.ts +4 -0
  479. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n00.chunk.ts +4 -0
  480. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n15.chunk.ts +4 -0
  481. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n30.chunk.ts +4 -0
  482. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n45.chunk.ts +4 -0
  483. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n60.chunk.ts +4 -0
  484. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n75.chunk.ts +4 -0
  485. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s15.chunk.ts +4 -0
  486. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s30.chunk.ts +4 -0
  487. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s45.chunk.ts +4 -0
  488. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n00.chunk.ts +4 -0
  489. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n15.chunk.ts +4 -0
  490. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n30.chunk.ts +4 -0
  491. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n45.chunk.ts +4 -0
  492. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n60.chunk.ts +4 -0
  493. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s15.chunk.ts +4 -0
  494. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s30.chunk.ts +4 -0
  495. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s45.chunk.ts +4 -0
  496. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n00.chunk.ts +4 -0
  497. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n15.chunk.ts +4 -0
  498. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n30.chunk.ts +4 -0
  499. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n45.chunk.ts +4 -0
  500. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n60.chunk.ts +4 -0
  501. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n75.chunk.ts +4 -0
  502. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s15.chunk.ts +4 -0
  503. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s30.chunk.ts +4 -0
  504. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s45.chunk.ts +4 -0
  505. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n00.chunk.ts +4 -0
  506. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n15.chunk.ts +4 -0
  507. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n45.chunk.ts +4 -0
  508. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n60.chunk.ts +4 -0
  509. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n75.chunk.ts +4 -0
  510. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s15.chunk.ts +4 -0
  511. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s30.chunk.ts +4 -0
  512. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s45.chunk.ts +4 -0
  513. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s60.chunk.ts +4 -0
  514. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n00.chunk.ts +4 -0
  515. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n15.chunk.ts +4 -0
  516. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n45.chunk.ts +4 -0
  517. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n60.chunk.ts +4 -0
  518. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s15.chunk.ts +4 -0
  519. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s30.chunk.ts +4 -0
  520. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s45.chunk.ts +4 -0
  521. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s60.chunk.ts +4 -0
  522. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n00.chunk.ts +4 -0
  523. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n15.chunk.ts +4 -0
  524. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n30.chunk.ts +4 -0
  525. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n45.chunk.ts +4 -0
  526. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n60.chunk.ts +4 -0
  527. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n75.chunk.ts +4 -0
  528. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s15.chunk.ts +4 -0
  529. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s30.chunk.ts +4 -0
  530. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s45.chunk.ts +4 -0
  531. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n00.chunk.ts +4 -0
  532. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n15.chunk.ts +4 -0
  533. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n30.chunk.ts +4 -0
  534. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n60.chunk.ts +4 -0
  535. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n75.chunk.ts +4 -0
  536. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030s30.chunk.ts +4 -0
  537. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030s60.chunk.ts +4 -0
  538. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n30.chunk.ts +4 -0
  539. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n45.chunk.ts +4 -0
  540. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n60.chunk.ts +4 -0
  541. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n75.chunk.ts +4 -0
  542. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s15.chunk.ts +4 -0
  543. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s30.chunk.ts +4 -0
  544. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s60.chunk.ts +4 -0
  545. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n00.chunk.ts +4 -0
  546. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n30.chunk.ts +4 -0
  547. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n45.chunk.ts +4 -0
  548. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n60.chunk.ts +4 -0
  549. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n75.chunk.ts +4 -0
  550. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s15.chunk.ts +4 -0
  551. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s30.chunk.ts +4 -0
  552. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s45.chunk.ts +4 -0
  553. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s60.chunk.ts +4 -0
  554. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n00.chunk.ts +4 -0
  555. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n15.chunk.ts +4 -0
  556. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n30.chunk.ts +4 -0
  557. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n45.chunk.ts +4 -0
  558. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n60.chunk.ts +4 -0
  559. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n75.chunk.ts +4 -0
  560. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s15.chunk.ts +4 -0
  561. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s30.chunk.ts +4 -0
  562. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s45.chunk.ts +4 -0
  563. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s60.chunk.ts +4 -0
  564. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n00.chunk.ts +4 -0
  565. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n15.chunk.ts +4 -0
  566. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n30.chunk.ts +4 -0
  567. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n45.chunk.ts +4 -0
  568. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n60.chunk.ts +4 -0
  569. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n75.chunk.ts +4 -0
  570. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s15.chunk.ts +4 -0
  571. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s30.chunk.ts +4 -0
  572. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s45.chunk.ts +4 -0
  573. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s60.chunk.ts +4 -0
  574. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n00.chunk.ts +4 -0
  575. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n15.chunk.ts +4 -0
  576. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n30.chunk.ts +4 -0
  577. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n45.chunk.ts +4 -0
  578. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n60.chunk.ts +4 -0
  579. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n75.chunk.ts +4 -0
  580. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105s15.chunk.ts +4 -0
  581. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n00.chunk.ts +4 -0
  582. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n15.chunk.ts +4 -0
  583. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n30.chunk.ts +4 -0
  584. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n45.chunk.ts +4 -0
  585. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n60.chunk.ts +4 -0
  586. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n75.chunk.ts +4 -0
  587. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120s30.chunk.ts +4 -0
  588. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n30.chunk.ts +4 -0
  589. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n45.chunk.ts +4 -0
  590. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n60.chunk.ts +4 -0
  591. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n75.chunk.ts +4 -0
  592. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135s30.chunk.ts +4 -0
  593. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150n45.chunk.ts +4 -0
  594. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150n60.chunk.ts +4 -0
  595. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150s15.chunk.ts +4 -0
  596. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150s30.chunk.ts +4 -0
  597. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n00.chunk.ts +4 -0
  598. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n15.chunk.ts +4 -0
  599. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n45.chunk.ts +4 -0
  600. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n60.chunk.ts +4 -0
  601. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165s15.chunk.ts +4 -0
  602. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165s30.chunk.ts +4 -0
  603. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n00.chunk.ts +4 -0
  604. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n15.chunk.ts +4 -0
  605. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n45.chunk.ts +4 -0
  606. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n60.chunk.ts +4 -0
  607. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s15.chunk.ts +4 -0
  608. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s30.chunk.ts +4 -0
  609. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s45.chunk.ts +4 -0
  610. package/src/plugins/builtin/world-venue-map/natural-earth/world-50m.chunk.ts +4 -0
  611. package/src/plugins/builtin/world-venue-map/pane.tsx +28 -43
  612. package/src/plugins/builtin/world-venue-map/use-geo.ts +55 -0
  613. package/src/plugins/builtin/world-venue-map/venue-header.tsx +32 -0
  614. package/src/plugins/builtin/yield-curve/headless.ts +16 -0
  615. package/src/plugins/catalog-browser.ts +2 -0
  616. package/src/plugins/catalog-manifest.ts +1 -0
  617. package/src/plugins/catalog-ui.ts +3 -1
  618. package/src/plugins/catalog.ts +1 -1
  619. package/src/plugins/host-link.ts +33 -1
  620. package/src/plugins/installer.ts +48 -12
  621. package/src/plugins/loader.ts +30 -3
  622. package/src/plugins/manager-node.ts +15 -5
  623. package/src/plugins/registry/index.ts +1 -1
  624. package/src/plugins/registry/pane-settings.ts +26 -7
  625. package/src/public/__snapshots__/public-api.test.ts.snap +2 -0
  626. package/src/renderers/dom/build-assets.ts +81 -3
  627. package/src/renderers/dom/data-table/row.tsx +52 -16
  628. package/src/renderers/dom/desktop/controls.tsx +7 -3
  629. package/src/renderers/dom/desktop/icons.tsx +1 -0
  630. package/src/renderers/dom/desktop/list-view.tsx +35 -10
  631. package/src/renderers/dom/desktop/popover.tsx +73 -14
  632. package/src/renderers/dom/host/box.tsx +69 -26
  633. package/src/renderers/dom/host/input.tsx +14 -3
  634. package/src/renderers/dom/host/tabs.tsx +37 -1
  635. package/src/renderers/dom/styles.css +41 -7
  636. package/src/renderers/electrobun/bun/desktop/backend-requests.ts +11 -6
  637. package/src/renderers/electrobun/bun/desktop/backend.ts +1 -0
  638. package/src/renderers/electrobun/bun/desktop/update.ts +181 -87
  639. package/src/renderers/electrobun/bun/index.ts +73 -6
  640. package/src/renderers/electrobun/bun/window/remembered-frame.ts +122 -0
  641. package/src/renderers/electrobun/shared/protocol.ts +3 -0
  642. package/src/renderers/electrobun/view/backend-rpc.ts +10 -4
  643. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +3 -1
  644. package/src/renderers/electrobun/view/main.tsx +7 -1
  645. package/src/renderers/electrobun/view/renderer-window-error.ts +18 -0
  646. package/src/renderers/electrobun/view/rpc-timeout.ts +14 -3
  647. package/src/renderers/electrobun/view/update-host.ts +45 -21
  648. package/src/renderers/opentui/host.tsx +5 -0
  649. package/src/sources/gloomberb-cloud/index.ts +25 -4
  650. package/src/sources/gloomberb-cloud/normalizers.ts +36 -5
  651. package/src/sources/provider-router/cached-routes.ts +4 -1
  652. package/src/sources/provider-router/financials.ts +11 -8
  653. package/src/sources/provider-router/history.ts +15 -10
  654. package/src/sources/sec-registrant.ts +75 -0
  655. package/src/state/app/context/index.tsx +24 -8
  656. package/src/state/hooks/quote-streaming.ts +41 -26
  657. package/src/sync/core-contributors.ts +4 -0
  658. package/src/telemetry/benign-window-error.ts +7 -0
  659. package/src/telemetry/crash-reports-dom.ts +2 -0
  660. package/src/telemetry/crash-reports.ts +4 -1
  661. package/src/test-support/cli-context.ts +10 -2
  662. package/src/test-support/daily-nav.ts +25 -0
  663. package/src/theme/heat-colors.ts +357 -2
  664. package/src/tickers/instrument-kind.ts +34 -7
  665. package/src/tickers/search/asset-classes.ts +24 -9
  666. package/src/tickers/search/index.ts +44 -11
  667. package/src/tickers/search/ranking.ts +23 -3
  668. package/src/time-series/resolve.ts +1 -1
  669. package/src/time-series/use-chart-resolution.ts +1 -1
  670. package/src/types/context-menu.ts +6 -0
  671. package/src/types/data-provider.ts +2 -0
  672. package/src/types/financials.ts +5 -0
  673. package/src/types/headless.ts +79 -2
  674. package/src/types/plugin.ts +38 -6
  675. package/src/types/ticker.ts +15 -0
  676. package/src/ui/context-menu.tsx +1 -0
  677. package/src/ui/host.tsx +16 -0
  678. package/src/updater/index.ts +38 -13
  679. package/src/utils/async-deadline.ts +21 -0
  680. package/src/utils/cli-output.ts +5 -1
  681. package/src/utils/crypto-pair.ts +41 -0
  682. package/src/utils/currency-units.ts +14 -0
  683. package/src/utils/depositary-receipt.ts +26 -0
  684. package/src/utils/exchanges.ts +72 -0
  685. package/src/utils/fire-and-forget.ts +24 -0
  686. package/src/utils/format.ts +13 -0
  687. package/src/utils/price-earnings.ts +70 -3
  688. package/src/utils/price-history.ts +58 -13
  689. package/src/utils/rpc-timeout-error.ts +27 -0
  690. package/src/utils/sec.ts +13 -1
  691. package/src/utils/utc-time.ts +79 -0
@@ -1,10 +1,15 @@
1
1
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
2
2
  import { Box, useUiCapabilities } from "../../../ui";
3
3
  import {
4
- buildMetricTreemapNavigationTiles,
4
+ buildHeatTreemapScene,
5
5
  findMetricTreemapNeighbor,
6
+ formatHeatTileMove,
7
+ heatTreemapCanvas,
8
+ HeatTreemapSurface,
9
+ settleTreemapLayoutItems,
10
+ } from "../../../components/metric-treemap";
11
+ import {
6
12
  loadingText,
7
- MetricTreemapSurface,
8
13
  PaneStatusBody,
9
14
  Tabs,
10
15
  unavailableText,
@@ -20,11 +25,11 @@ import { useShortcut } from "../../../react/input";
20
25
  import { TICKER_RESEARCH_PANE_ID } from "../../../types/config";
21
26
  import type { GloomPlugin, PaneProps, PaneSettingField } from "../../../types/plugin";
22
27
  import type { TickerRecord } from "../../../types/ticker";
23
- import { tf } from "../../../i18n";
28
+ import { t, tf } from "../../../i18n";
24
29
  import { priceColor } from "../../../theme/colors";
25
- import { formatCompact, formatCurrency, formatPercentRaw } from "../../../utils/format";
30
+ import { clipToDisplayWidth, formatCompact, formatCurrency, formatPercentRaw } from "../../../utils/format";
26
31
  import { isPlainKey } from "../../../utils/keyboard";
27
- import { useAppSelector, usePaneAppConfig, usePaneSettingValue } from "../../../state/app/context";
32
+ import { useAppSelector, usePaneAppConfig, usePaneSettingValue, usePaneStateValue } from "../../../state/app/context";
28
33
  import { usePluginTickerActions } from "../../runtime";
29
34
  import { useLiveQuoteEntries } from "../../../state/hooks/quote-streaming";
30
35
  import { useFxRatesMap, useTickerFinancialsMap } from "../../../market-data/hooks";
@@ -39,21 +44,27 @@ import { resolvePortfolioTotalsCurrency } from "../portfolio-list/metrics";
39
44
  import { useThrottledMemo } from "../portfolio-list/use-throttled-memo";
40
45
  import { PORTFOLIO_REORDER_THROTTLE_MS } from "../portfolio-list/use-throttled-ticker-order";
41
46
  import {
47
+ MARKET_HEATMAP_REQUEST_COUNT,
42
48
  MARKET_HEATMAP_UNIVERSES,
43
49
  fetchMarketHeatmap,
44
50
  resetMarketHeatmapCache,
45
51
  type MarketHeatmapUniverseId,
46
52
  } from "./data";
47
53
  import {
54
+ HEATMAP_COLLECTION_KIND_STATE_KEY,
48
55
  PORTFOLIO_HEATMAP_TAB,
49
56
  buildPortfolioHeatmapAssets,
50
57
  fallbackHeatmapCollectionId,
51
58
  heatmapCollectionLabel,
52
59
  heatmapFollowsCollection,
60
+ heatmapSizeBy,
61
+ heatmapSizeByApplies,
62
+ heatmapSizeWeight,
53
63
  heatmapTabId,
54
64
  isRemoteHeatmapUniverse,
55
65
  useLinkedHeatmapCollection,
56
66
  type HeatmapBoardAsset,
67
+ type HeatmapSizeBy,
57
68
  } from "./portfolio";
58
69
  import { useAutoRefresh, useUpdatedAgo } from "../../../react/auto-refresh";
59
70
  import {
@@ -61,13 +72,31 @@ import {
61
72
  useLiveStreamingSetting,
62
73
  withLiveStreamingSetting,
63
74
  } from "../../../state/hooks/live-streaming";
75
+ import type { QuoteSubscriptionTarget } from "../../../types/data-provider";
76
+ import {
77
+ buildHeatmapQuoteTargets,
78
+ liveHeatmapWeight,
79
+ rankHeatmapQuoteWeights,
80
+ useSettledValue,
81
+ } from "./live";
82
+ import { marketHeatmapHeadless } from "./headless";
83
+ import { heatmapMove, resolveHeatmapGrouping, sizeWeightedMove, type HeatmapGrouping } from "./model";
64
84
  import {
65
- buildScreenerQuoteTargets,
66
85
  overlayScreenerQuoteEntries,
67
86
  resolveScreenerQuoteFeedStatus,
68
87
  } from "../../../market-data/quotes/screener-live-quotes";
69
88
 
70
89
  const NO_ASSETS: HeatmapBoardAsset[] = [];
90
+ const NO_TARGETS: QuoteSubscriptionTarget[] = [];
91
+ const SNAPSHOT_REFRESH_MS = 60_000;
92
+ const LAYOUT_THROTTLE_MS = 5_000;
93
+ /** A size change below this share of a tile's area is not worth moving it. */
94
+ const LAYOUT_TOLERANCE = 0.005;
95
+ const TERMINAL_PAINT_THROTTLE_MS = 250;
96
+ const SELECTION_STREAM_SETTLE_MS = 1_500;
97
+ const TOOLTIP_NAME_WIDTH = 28;
98
+ const SIZE_BY_SETTING_KEY = "sizeBy";
99
+ const SQRT_SIZE_VALUE: HeatmapSizeBy = "sqrt-market-cap";
71
100
  const NO_BOARD = { assets: NO_ASSETS, omitted: 0 };
72
101
  const EMPTY_TICKERS: TickerRecord[] = [];
73
102
  const NO_CURRENCIES: string[] = [];
@@ -102,46 +131,97 @@ function sizeLabel(asset: HeatmapBoardAsset): string | null {
102
131
  return `${label} ${formatMoneyCompact(asset.size, asset.sizeCurrency ?? asset.currency)}`;
103
132
  }
104
133
 
105
- function buildItems(assets: HeatmapBoardAsset[]): Array<MetricTreemapItem<HeatmapBoardAsset>> {
106
- return assets.map((asset) => ({
134
+ /** Marks a pre-market or after-hours move, which is measured from the regular close. */
135
+ function sessionMark(asset: HeatmapBoardAsset): string | null {
136
+ if (asset.extendedSession === "PRE") return "PM";
137
+ if (asset.extendedSession === "POST") return "AH";
138
+ return null;
139
+ }
140
+
141
+ function formatMove(asset: HeatmapBoardAsset, change: number | null): string {
142
+ const mark = sessionMark(asset);
143
+ return change == null ? "—" : mark ? `${formatPercentRaw(change)} ${mark}` : formatPercentRaw(change);
144
+ }
145
+
146
+ /**
147
+ * The size transform applies to each name before groups sum them, so a
148
+ * sector's block is the sum of its transformed names. A board that already
149
+ * carries a weight (a portfolio or watchlist) applied it when it was built.
150
+ */
151
+ function buildLayoutItems(
152
+ snapshot: readonly HeatmapBoardAsset[],
153
+ live: readonly HeatmapBoardAsset[],
154
+ grouping: HeatmapGrouping,
155
+ sizeBy: HeatmapSizeBy,
156
+ ): Array<MetricTreemapItem<HeatmapBoardAsset>> {
157
+ return snapshot.map((asset, index) => ({
107
158
  id: asset.symbol,
108
159
  label: asset.symbol,
109
- weight: asset.weight ?? asset.size ?? 0,
110
- colorValue: asset.hasChange ? asset.changePercent : null,
111
- // No change data is not a flat session; 0.00% would be a made-up number.
112
- primaryText: asset.hasChange ? formatPercentRaw(asset.changePercent) : "—",
113
- secondaryText: sizeLabel(asset),
114
- tertiaryText: asset.volume != null ? `Vol ${formatCompact(asset.volume)}` : asset.exchange || null,
160
+ weight: asset.weight != null
161
+ ? liveHeatmapWeight(asset, live[index] ?? asset)
162
+ : heatmapSizeWeight(liveHeatmapWeight(asset, live[index] ?? asset), sizeBy),
163
+ group: grouping === "flat" ? undefined : asset.sector ?? null,
164
+ subgroup: grouping === "sector-industry" ? asset.industry ?? null : undefined,
115
165
  data: asset,
116
166
  }));
117
167
  }
118
168
 
119
169
  /**
120
- * A tile that clips "$1.0T" into "$1.0" reads as a real, wrong number, so a
121
- * metric that does not fit its tile is dropped instead of truncated. Layout
122
- * depends on weights alone, so re-rendering with shorter text keeps the same
123
- * geometry.
170
+ * The overlay hands back the same asset object while its quote is unchanged,
171
+ * so a tile's text is formatted once per tick of that name, not once per
172
+ * frame for all 500.
124
173
  */
125
- function fitItemsToTiles(
126
- items: Array<MetricTreemapItem<HeatmapBoardAsset>>,
127
- tiles: Array<{ item: { id: string }; width: number; height: number }>,
128
- ): Array<MetricTreemapItem<HeatmapBoardAsset>> {
129
- const tileById = new Map(tiles.map((tile) => [tile.item.id, tile]));
130
- return items.map((item) => {
131
- const tile = tileById.get(item.id);
132
- if (!tile) return item;
133
- // Mirrors the terminal tile's own padding: one cell of border, one of gutter.
134
- const innerWidth = Math.max(1, Math.floor(tile.width) - (tile.width > 2 ? 1 : 0) - 1);
135
- const fits = (text: string | null | undefined) => (
136
- text != null && text.length <= innerWidth ? text : null
137
- );
138
- return {
139
- ...item,
140
- primaryText: fits(item.primaryText),
141
- secondaryText: fits(item.secondaryText),
142
- tertiaryText: fits(item.tertiaryText),
143
- };
144
- });
174
+ const paintItemCache = new WeakMap<HeatmapBoardAsset, MetricTreemapItem<HeatmapBoardAsset>>();
175
+
176
+ function paintItem(asset: HeatmapBoardAsset): MetricTreemapItem<HeatmapBoardAsset> {
177
+ const cached = paintItemCache.get(asset);
178
+ if (cached) return cached;
179
+ const change = heatmapMove(asset);
180
+ const details = [
181
+ asset.price > 0 ? formatCurrency(asset.price, asset.currency) : null,
182
+ sizeLabel(asset),
183
+ asset.volume != null ? `Vol ${formatCompact(asset.volume)}` : null,
184
+ ].filter((part): part is string => !!part);
185
+ // The move closes the line, so a long name gives way instead of hiding it.
186
+ const name = asset.name && asset.name !== asset.symbol ? clipToDisplayWidth(asset.name, TOOLTIP_NAME_WIDTH) : null;
187
+ const item: MetricTreemapItem<HeatmapBoardAsset> = {
188
+ id: asset.symbol,
189
+ label: asset.symbol,
190
+ weight: asset.weight ?? asset.size ?? 0,
191
+ colorValue: change,
192
+ primaryText: formatHeatTileMove(change),
193
+ primaryTextSuffix: sessionMark(asset),
194
+ tooltip: [
195
+ [asset.symbol, name, formatMove(asset, change)].filter(Boolean).join(" · "),
196
+ ...(details.length > 0 ? [details.join(" · ")] : []),
197
+ ],
198
+ data: asset,
199
+ };
200
+ paintItemCache.set(asset, item);
201
+ return item;
202
+ }
203
+
204
+ function buildPaintItems(assets: readonly HeatmapBoardAsset[]): Array<MetricTreemapItem<HeatmapBoardAsset>> {
205
+ return assets.map(paintItem);
206
+ }
207
+
208
+ function otherSummary(items: readonly MetricTreemapItem<HeatmapBoardAsset>[]): string {
209
+ return tf("{count} names", { count: items.length });
210
+ }
211
+
212
+ function otherTooltip(items: readonly MetricTreemapItem<HeatmapBoardAsset>[]): string[] {
213
+ const move = sizeWeightedMove(items.map((item) => item.data));
214
+ return [
215
+ tf("Other · {count} smaller names", { count: items.length }),
216
+ ...(move != null ? [`${formatPercentRaw(move)} ${t("cap-weighted")}`] : []),
217
+ ];
218
+ }
219
+
220
+ function useSettledLayoutItems<T>(items: readonly MetricTreemapItem<T>[]): readonly MetricTreemapItem<T>[] {
221
+ const settledRef = useRef<readonly MetricTreemapItem<T>[] | null>(null);
222
+ const settled = settleTreemapLayoutItems(settledRef.current, items, LAYOUT_TOLERANCE);
223
+ settledRef.current = settled;
224
+ return settled;
145
225
  }
146
226
 
147
227
  function MarketHeatmapPane({ focused, width, height }: PaneProps) {
@@ -151,6 +231,8 @@ function MarketHeatmapPane({ focused, width, height }: PaneProps) {
151
231
  // A pane setting, not private pane state, so the settings dialog can show it.
152
232
  const [universeSetting, setActiveUniverse] = usePaneSettingValue<string>("universe", "us-equity");
153
233
  const [linkPortfolio] = usePaneSettingValue<boolean>("linkPortfolio", false);
234
+ const [sizeBySetting] = usePaneSettingValue<string>(SIZE_BY_SETTING_KEY, SQRT_SIZE_VALUE);
235
+ const sizeBy = heatmapSizeBy(sizeBySetting);
154
236
  const activeUniverse = heatmapTabId(universeSetting);
155
237
  const portfolioTab = activeUniverse === PORTFOLIO_HEATMAP_TAB;
156
238
  const config = usePaneAppConfig();
@@ -158,6 +240,7 @@ function MarketHeatmapPane({ focused, width, height }: PaneProps) {
158
240
  const linkedPortfolio = useLinkedHeatmapCollection();
159
241
  const collectionId = linkedPortfolio.collectionId ?? fallbackHeatmapCollectionId(config);
160
242
  const collectionKind = getCollectionTypeFromConfig(config, collectionId);
243
+ const [, publishCollectionKind] = usePaneStateValue<string>(HEATMAP_COLLECTION_KIND_STATE_KEY, "");
161
244
  const portfolioLabel = heatmapCollectionLabel(config, collectionId);
162
245
  const universeTabs = useMemo(() => [
163
246
  ...MARKET_HEATMAP_UNIVERSES.map((universe) => ({ label: universe.label, value: universe.id })),
@@ -197,10 +280,11 @@ function MarketHeatmapPane({ focused, width, height }: PaneProps) {
197
280
  kind: collectionKind,
198
281
  currency: boardCurrency,
199
282
  exchangeRates,
283
+ sizeBy,
200
284
  })
201
285
  : NO_BOARD),
202
286
  [financials],
203
- [boardCurrency, collectionId, collectionKind, collectionTickers, exchangeRates, financials.size],
287
+ [boardCurrency, collectionId, collectionKind, collectionTickers, exchangeRates, financials.size, sizeBy],
204
288
  PORTFOLIO_REORDER_THROTTLE_MS,
205
289
  );
206
290
  const portfolioAssets = portfolioBoard.assets;
@@ -234,11 +318,24 @@ function MarketHeatmapPane({ focused, width, height }: PaneProps) {
234
318
  });
235
319
 
236
320
  const chartHeight = Math.max(1, height - (tabsInHeader ? 0 : 1));
237
- const chartWidth = Math.max(1, width - 2);
238
- const cellAspect = Math.max(0.5, Math.min(4, cellHeightPx / Math.max(1, cellWidthPx)));
321
+ const canvas = useMemo(
322
+ () => heatTreemapCanvas(width, chartHeight, { nativePaneChrome, cellWidthPx, cellHeightPx }),
323
+ [cellHeightPx, cellWidthPx, chartHeight, nativePaneChrome, width],
324
+ );
325
+
326
+ // Stream weights by market-cap rank, fixed for this load of the board.
327
+ const quoteWeightsRef = useRef<{ tab: string; weights: Map<string, number> } | null>(null);
328
+ const quoteWeights = useMemo(() => {
329
+ const previous = quoteWeightsRef.current?.tab === activeUniverse ? quoteWeightsRef.current.weights : null;
330
+ const weights = rankHeatmapQuoteWeights(boardAssets, previous);
331
+ quoteWeightsRef.current = { tab: activeUniverse, weights };
332
+ return weights;
333
+ }, [activeUniverse, boardAssets]);
334
+ const streamSelection = useSettledValue(selectedSymbol, SELECTION_STREAM_SETTLE_MS);
335
+ // With streaming off the board refreshes from snapshots only: no 500-name poll on top of them.
239
336
  const quoteTargets = useMemo(
240
- () => buildScreenerQuoteTargets(boardAssets, selectedSymbol),
241
- [boardAssets, selectedSymbol],
337
+ () => (liveStreaming ? buildHeatmapQuoteTargets(boardAssets, quoteWeights, streamSelection) : NO_TARGETS),
338
+ [boardAssets, liveStreaming, quoteWeights, streamSelection],
242
339
  );
243
340
  const {
244
341
  entries: liveQuoteEntries,
@@ -249,7 +346,7 @@ function MarketHeatmapPane({ focused, width, height }: PaneProps) {
249
346
  liveStreaming,
250
347
  });
251
348
  const resolvedAssets = useMemo(
252
- () => overlayScreenerQuoteEntries(boardAssets, liveQuoteEntries),
349
+ () => overlayScreenerQuoteEntries(boardAssets, liveQuoteEntries, { extendedSessions: true }),
253
350
  [boardAssets, liveQuoteEntries],
254
351
  );
255
352
  const feedStatus = useMemo(
@@ -259,21 +356,45 @@ function MarketHeatmapPane({ focused, width, height }: PaneProps) {
259
356
  }),
260
357
  [freshnessNow, liveQuoteEntries, quoteTargets, subscriptionStartedAt],
261
358
  );
262
- const items = useMemo(() => buildItems(resolvedAssets), [resolvedAssets]);
263
- const navigationTiles = useMemo(
264
- () => buildMetricTreemapNavigationTiles(items, chartWidth, chartHeight, cellAspect, nativePaneChrome ? "float" : "integer"),
265
- [cellAspect, chartHeight, chartWidth, items, nativePaneChrome],
359
+
360
+ // Sizes follow live prices at most every LAYOUT_THROTTLE_MS and only past
361
+ // LAYOUT_TOLERANCE; a new snapshot relays out at once. Ticks only recolour.
362
+ const grouping = useMemo(
363
+ () => resolveHeatmapGrouping(boardAssets, activeUniverse === "us-equity"),
364
+ [activeUniverse, boardAssets],
266
365
  );
267
- // Desktop tiles ellipsize, which is visible; terminal cells clip silently.
268
- const displayItems = useMemo(
269
- () => (nativePaneChrome ? items : fitItemsToTiles(items, navigationTiles)),
270
- [items, nativePaneChrome, navigationTiles],
366
+ const layoutAssets = useThrottledMemo(
367
+ () => resolvedAssets,
368
+ [resolvedAssets],
369
+ [boardAssets],
370
+ LAYOUT_THROTTLE_MS,
271
371
  );
272
- const selectedIdx = selectedSymbol
273
- ? resolvedAssets.findIndex((asset) => asset.symbol === selectedSymbol)
274
- : -1;
275
- const activeIdx = selectedIdx >= 0 ? selectedIdx : (resolvedAssets.length > 0 ? 0 : -1);
276
- const selectedAsset = activeIdx >= 0 ? resolvedAssets[activeIdx] ?? null : null;
372
+ const layoutItems = useSettledLayoutItems(
373
+ useMemo(() => buildLayoutItems(boardAssets, layoutAssets, grouping, sizeBy), [boardAssets, grouping, layoutAssets, sizeBy]),
374
+ );
375
+ // The board on screen seeds the next layout's order, so a refresh nudges tiles instead of reshuffling them.
376
+ const sceneRef = useRef<{ tab: string; scene: ReturnType<typeof buildHeatTreemapScene<HeatmapBoardAsset>> } | null>(null);
377
+ const scene = useMemo(() => {
378
+ const previous = sceneRef.current?.tab === activeUniverse ? sceneRef.current.scene : null;
379
+ const next = buildHeatTreemapScene(layoutItems, canvas, previous);
380
+ sceneRef.current = { tab: activeUniverse, scene: next };
381
+ return next;
382
+ }, [activeUniverse, canvas, layoutItems]);
383
+ // The terminal repaints whole cells: colours there move at most four times a second.
384
+ const paintAssets = useThrottledMemo(
385
+ () => resolvedAssets,
386
+ [resolvedAssets],
387
+ [boardAssets],
388
+ nativePaneChrome ? 0 : TERMINAL_PAINT_THROTTLE_MS,
389
+ );
390
+ const paintItems = useMemo(() => buildPaintItems(paintAssets), [paintAssets]);
391
+ const visibleTiles = scene.tiles;
392
+ const selectedTileIndex = selectedSymbol ? visibleTiles.findIndex((tile) => tile.item.id === selectedSymbol) : -1;
393
+ const activeIdx = selectedTileIndex >= 0 ? selectedTileIndex : (visibleTiles.length > 0 ? 0 : -1);
394
+ const activeSymbol = activeIdx >= 0 ? visibleTiles[activeIdx]!.item.id : null;
395
+ const selectedAsset = activeSymbol
396
+ ? resolvedAssets.find((asset) => asset.symbol === activeSymbol) ?? null
397
+ : null;
277
398
 
278
399
  const loadUniverse = useCallback(async (universe: MarketHeatmapUniverseId, options?: { forceRefresh?: boolean }) => {
279
400
  fetchGenRef.current += 1;
@@ -283,7 +404,7 @@ function MarketHeatmapPane({ focused, width, height }: PaneProps) {
283
404
 
284
405
  try {
285
406
  const result = await fetchMarketHeatmap(universe, {
286
- count: 96,
407
+ count: MARKET_HEATMAP_REQUEST_COUNT[universe],
287
408
  forceRefresh: options?.forceRefresh,
288
409
  });
289
410
  if (fetchGenRef.current !== gen) return;
@@ -314,6 +435,11 @@ function MarketHeatmapPane({ focused, width, height }: PaneProps) {
314
435
  setSelectedSymbol(null);
315
436
  }, [collectionId, linkPortfolio, setActiveUniverse]);
316
437
 
438
+ // The header shows the square-root control only where it changes the board.
439
+ useEffect(() => {
440
+ publishCollectionKind(collectionKind ?? "");
441
+ }, [collectionKind, publishCollectionKind]);
442
+
317
443
  // The financials map only reads the cache; this fills it for the list on screen.
318
444
  useEffect(() => {
319
445
  if (!portfolioTab) return;
@@ -321,10 +447,12 @@ function MarketHeatmapPane({ focused, width, height }: PaneProps) {
321
447
  // Keyed by the symbols: another ticker's record changing does not reload the list.
322
448
  }, [collectionId, collectionKind, collectionSymbolsKey, portfolioTab]);
323
449
 
450
+ // Only drawn tiles are selectable; a name folded into Other hands the selection to the first tile.
324
451
  useEffect(() => {
325
- if (selectedSymbol && boardAssets.some((asset) => asset.symbol === selectedSymbol)) return;
326
- setSelectedSymbol(boardAssets[0]?.symbol ?? null);
327
- }, [boardAssets, selectedSymbol]);
452
+ if (selectedSymbol && visibleTiles.some((tile) => tile.item.id === selectedSymbol)) return;
453
+ const first = visibleTiles[0]?.item.id ?? null;
454
+ if (first !== selectedSymbol) setSelectedSymbol(first);
455
+ }, [selectedSymbol, visibleTiles]);
328
456
 
329
457
  const refresh = useCallback(() => {
330
458
  if (portfolioTab) {
@@ -359,15 +487,16 @@ function MarketHeatmapPane({ focused, width, height }: PaneProps) {
359
487
  pinTicker(symbol, { floating: true, paneType: TICKER_RESEARCH_PANE_ID });
360
488
  }, [pinTicker]);
361
489
 
490
+ // j and k walk the tiles in reading order: sector by sector, largest first.
362
491
  const selectIndex = useCallback((index: number) => {
363
- const asset = boardAssets[index];
364
- if (asset) setSelectedSymbol(asset.symbol);
365
- }, [boardAssets]);
492
+ const tile = visibleTiles[index];
493
+ if (tile) setSelectedSymbol(tile.item.id);
494
+ }, [visibleTiles]);
366
495
 
367
496
  const selectNeighbor = useCallback((direction: MetricTreemapDirection) => {
368
- const target = findMetricTreemapNeighbor(navigationTiles, selectedSymbol, direction);
369
- if (target) setSelectedSymbol(target.item.data.symbol);
370
- }, [navigationTiles, selectedSymbol]);
497
+ const target = findMetricTreemapNeighbor(visibleTiles, activeSymbol, direction);
498
+ if (target) setSelectedSymbol(target.item.id);
499
+ }, [activeSymbol, visibleTiles]);
371
500
 
372
501
  useShortcut((event) => {
373
502
  if (!focused) return;
@@ -405,7 +534,7 @@ function MarketHeatmapPane({ focused, width, height }: PaneProps) {
405
534
  if (isPlainKey(event, "j")) {
406
535
  event.preventDefault();
407
536
  event.stopPropagation();
408
- selectIndex(Math.min((activeIdx >= 0 ? activeIdx : 0) + 1, boardAssets.length - 1));
537
+ selectIndex(Math.min((activeIdx >= 0 ? activeIdx : 0) + 1, visibleTiles.length - 1));
409
538
  return;
410
539
  }
411
540
  if (isPlainKey(event, "k")) {
@@ -446,7 +575,8 @@ function MarketHeatmapPane({ focused, width, height }: PaneProps) {
446
575
  });
447
576
 
448
577
  const updated = useUpdatedAgo(!portfolioTab && loadedUniverse === activeUniverse ? lastUpdated : null);
449
- useAutoRefresh(lastUpdated, autoRefresh);
578
+ // The snapshot carries sizes and every name the stream does not; the server caches it for a minute.
579
+ useAutoRefresh(lastUpdated, autoRefresh, { intervalMs: SNAPSHOT_REFRESH_MS });
450
580
 
451
581
  usePaneStatusFooter({ registrationId: "market-heatmap-retained", stale: hasBoard && stale && !portfolioTab });
452
582
  usePaneNoticeFooter({
@@ -463,13 +593,20 @@ function MarketHeatmapPane({ focused, width, height }: PaneProps) {
463
593
  id: "selected",
464
594
  parts: [
465
595
  { text: selectedAsset.symbol, tone: "label" as const },
466
- { text: formatCurrency(selectedAsset.price, selectedAsset.currency), tone: "value" as const },
467
596
  {
468
- text: selectedAsset.hasChange ? formatPercentRaw(selectedAsset.changePercent) : "—",
597
+ text: heatmapMove(selectedAsset) == null ? "—" : formatPercentRaw(heatmapMove(selectedAsset)!),
469
598
  tone: "value" as const,
470
- color: selectedAsset.hasChange ? priceColor(selectedAsset.changePercent) : undefined,
599
+ color: heatmapMove(selectedAsset) == null ? undefined : priceColor(heatmapMove(selectedAsset)!),
471
600
  bold: true,
472
601
  },
602
+ ...(sessionMark(selectedAsset) ? [{ text: sessionMark(selectedAsset)!, tone: "muted" as const }] : []),
603
+ ...(selectedAsset.price > 0
604
+ ? [{ text: formatCurrency(selectedAsset.price, selectedAsset.currency), tone: "value" as const }]
605
+ : []),
606
+ ...(sizeLabel(selectedAsset) ? [{ text: sizeLabel(selectedAsset)!, tone: "muted" as const }] : []),
607
+ ...(selectedAsset.volume != null
608
+ ? [{ text: `Vol ${formatCompact(selectedAsset.volume)}`, tone: "muted" as const }]
609
+ : []),
473
610
  ],
474
611
  }] : []),
475
612
  ...(updated ? [{
@@ -509,14 +646,17 @@ function MarketHeatmapPane({ focused, width, height }: PaneProps) {
509
646
  empty={!hasBoard}
510
647
  emptyTitle={portfolioTab ? EMPTY_PORTFOLIO_TITLE : EMPTY_TITLE}
511
648
  >
512
- <MetricTreemapSurface
513
- items={displayItems}
649
+ <HeatTreemapSurface
650
+ scene={scene}
651
+ items={paintItems}
514
652
  width={width}
515
653
  height={chartHeight}
516
- selectedId={selectedSymbol}
517
- onSelect={(item) => setSelectedSymbol(item.data.symbol)}
518
- onActivate={(item) => openSymbol(item.data.symbol)}
654
+ selectedId={activeSymbol}
655
+ onSelect={(item) => setSelectedSymbol(item.id)}
656
+ onActivate={(item) => openSymbol(item.id)}
519
657
  emptyStateTitle={portfolioTab ? EMPTY_PORTFOLIO_TITLE : EMPTY_TITLE}
658
+ otherTooltip={otherTooltip}
659
+ otherSummary={otherSummary}
520
660
  />
521
661
  </PaneStatusBody>
522
662
  </Box>
@@ -527,7 +667,7 @@ export const marketHeatmapPlugin: GloomPlugin = {
527
667
  id: "market-heatmap",
528
668
  name: "Market Heatmap",
529
669
  version: "1.0.0",
530
- description: "Largest US stocks and ETFs, or the portfolio pane's list, sized by market cap or position and colored by daily move",
670
+ description: "Largest US stocks and ETFs, or the portfolio pane's list, sized by the square root of market cap or by position value and colored by daily move",
531
671
  toggleable: true,
532
672
  targets: ["cli", "tui", "desktop", "web"],
533
673
 
@@ -541,13 +681,27 @@ export const marketHeatmapPlugin: GloomPlugin = {
541
681
  name: "Market Heatmap",
542
682
  icon: "H",
543
683
  component: MarketHeatmapPane,
684
+ headless: marketHeatmapHeadless,
544
685
  defaultPosition: "right",
545
686
  defaultMode: "floating",
546
687
  defaultFloatingSize: { width: 110, height: 36 },
547
- quickSettings: [LIVE_STREAMING_QUICK_SETTING],
688
+ quickSettings: [
689
+ LIVE_STREAMING_QUICK_SETTING,
690
+ {
691
+ type: "toggle",
692
+ key: SIZE_BY_SETTING_KEY,
693
+ icon: "sqrt",
694
+ onValue: SQRT_SIZE_VALUE,
695
+ label: "Size by square root of market cap",
696
+ visible: (context) => heatmapSizeByApplies(context.settings.universe, context.paneState[HEATMAP_COLLECTION_KIND_STATE_KEY]),
697
+ },
698
+ ],
548
699
  settings: (context) => withLiveStreamingSetting({
549
700
  title: "Market Heatmap Settings",
550
- values: { linkPortfolio: context.settings.linkPortfolio === true },
701
+ values: {
702
+ linkPortfolio: context.settings.linkPortfolio === true,
703
+ [SIZE_BY_SETTING_KEY]: heatmapSizeBy(context.settings[SIZE_BY_SETTING_KEY]),
704
+ },
551
705
  fields: [
552
706
  {
553
707
  key: "universe",
@@ -561,6 +715,16 @@ export const marketHeatmapPlugin: GloomPlugin = {
561
715
  { value: PORTFOLIO_HEATMAP_TAB, label: "Portfolio pane list" },
562
716
  ],
563
717
  },
718
+ {
719
+ key: SIZE_BY_SETTING_KEY,
720
+ label: "Size by",
721
+ type: "select",
722
+ options: [
723
+ { value: "market-cap", label: "Market cap" },
724
+ { value: SQRT_SIZE_VALUE, label: "Square root of market cap" },
725
+ ],
726
+ description: "Square root gives mid-size names room next to the largest. A portfolio is always sized by position value.",
727
+ },
564
728
  {
565
729
  key: "linkPortfolio",
566
730
  label: "Link to portfolio",
@@ -577,7 +741,7 @@ export const marketHeatmapPlugin: GloomPlugin = {
577
741
  id: "market-heatmap-pane",
578
742
  paneId: "market-heatmap",
579
743
  label: "Market Heatmap",
580
- description: "Largest US stocks and ETFs, or the portfolio pane's list, sized by market cap or position and colored by daily move.",
744
+ description: "Largest US stocks and ETFs, or the portfolio pane's list, sized by the square root of market cap or by position value and colored by daily move.",
581
745
  keywords: ["heatmap", "market", "largest", "top", "stocks", "etf", "portfolio", "watchlist", "screener"],
582
746
  shortcut: { prefix: "HM" },
583
747
  },
@@ -0,0 +1,88 @@
1
+ import { useEffect, useState } from "react";
2
+ import type { QuoteSubscriptionTarget } from "../../../types/data-provider";
3
+ import type { HeatmapBoardAsset } from "./portfolio";
4
+
5
+ /** The board never asks to stream more than this; the server caps lower for most tiers. */
6
+ export const HEATMAP_MAX_QUOTE_TARGETS = 500;
7
+
8
+ /**
9
+ * Stream priority by market-cap rank. A connection over its tier's symbol cap
10
+ * keeps its highest-priority targets (the cloud realtime service ranks by
11
+ * weight plus selected and visible bonuses and breaks ties alphabetically), so
12
+ * every rank gets its own weight and the largest names stay live whatever the
13
+ * cap. The weights stay at or under the client's off-screen ceiling of 10
14
+ * (`OFFSCREEN_QUOTE_WEIGHT`), so covering the pane rewrites no weight and the
15
+ * server evicts and admits nothing.
16
+ */
17
+ function heatmapQuoteWeight(rank: number): number {
18
+ return Math.max(0.02, Math.round((10 - rank * 0.02) * 100) / 100);
19
+ }
20
+
21
+ function sizeOf(asset: HeatmapBoardAsset): number {
22
+ return asset.weight ?? asset.size ?? 0;
23
+ }
24
+
25
+ /**
26
+ * Weights for this load of a board. A name keeps the weight it was first
27
+ * given, so a snapshot refresh that reorders two neighbours re-sends nothing;
28
+ * a new name takes the weight of its rank.
29
+ */
30
+ export function rankHeatmapQuoteWeights(
31
+ assets: readonly HeatmapBoardAsset[],
32
+ previous: ReadonlyMap<string, number> | null,
33
+ ): Map<string, number> {
34
+ const ranked = [...assets].sort((left, right) => sizeOf(right) - sizeOf(left) || left.symbol.localeCompare(right.symbol));
35
+ const weights = new Map<string, number>();
36
+ ranked.forEach((asset, rank) => {
37
+ weights.set(asset.symbol, previous?.get(asset.symbol) ?? heatmapQuoteWeight(rank));
38
+ });
39
+ return weights;
40
+ }
41
+
42
+ /**
43
+ * The board's stream targets: the largest names first, at most
44
+ * `HEATMAP_MAX_QUOTE_TARGETS`. No `visible` hint: a treemap shows every tile
45
+ * at once, the hint would only add a bonus that changes when the pane is
46
+ * covered, and a tile without it is paced at about once a second, which is
47
+ * all a colour needs. Only the settled selection is marked selected.
48
+ */
49
+ export function buildHeatmapQuoteTargets(
50
+ assets: readonly HeatmapBoardAsset[],
51
+ weights: ReadonlyMap<string, number>,
52
+ selectedSymbol: string | null,
53
+ ): QuoteSubscriptionTarget[] {
54
+ return [...assets]
55
+ .sort((left, right) => (weights.get(right.symbol) ?? 0) - (weights.get(left.symbol) ?? 0)
56
+ || left.symbol.localeCompare(right.symbol))
57
+ .slice(0, HEATMAP_MAX_QUOTE_TARGETS)
58
+ .map((asset) => ({
59
+ symbol: asset.symbol,
60
+ exchange: asset.exchange,
61
+ surface: "screener",
62
+ weight: weights.get(asset.symbol) ?? 0,
63
+ ...(asset.symbol === selectedSymbol ? { selected: true } : {}),
64
+ }));
65
+ }
66
+
67
+ /**
68
+ * The tile area follows the live price: market cap scales with it until the
69
+ * next snapshot brings a fresh cap. Boards sized by something else (a
70
+ * position's value) already move with their own data.
71
+ */
72
+ export function liveHeatmapWeight(snapshot: HeatmapBoardAsset, live: HeatmapBoardAsset): number {
73
+ const base = sizeOf(snapshot);
74
+ if (snapshot.weight != null || live === snapshot) return base;
75
+ if (!(snapshot.price > 0) || !(typeof live.price === "number" && live.price > 0)) return base;
76
+ return base * live.price / snapshot.price;
77
+ }
78
+
79
+ /** Selection as the stream sees it: only once it rests, so sweeping the pointer across tiles does not churn subscriptions. */
80
+ export function useSettledValue<T>(value: T, delayMs: number): T {
81
+ const [settled, setSettled] = useState(value);
82
+ useEffect(() => {
83
+ if (Object.is(settled, value)) return;
84
+ const timer = setTimeout(() => setSettled(value), delayMs);
85
+ return () => clearTimeout(timer);
86
+ }, [delayMs, settled, value]);
87
+ return settled;
88
+ }