gloomberb 0.5.1 → 0.6.0

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 (500) hide show
  1. package/README.md +91 -11
  2. package/package.json +12 -5
  3. package/src/app.tsx +414 -191
  4. package/src/architecture/import-boundaries.test.ts +118 -0
  5. package/src/assets/gloomberb-logo.png +0 -0
  6. package/src/assets/gloomberb-logo.svg +73 -0
  7. package/src/brokers/account-cache.ts +157 -0
  8. package/src/brokers/profile-form.test.ts +73 -0
  9. package/src/brokers/profile-form.ts +109 -0
  10. package/src/brokers/remote-broker-adapter.ts +91 -0
  11. package/src/brokers/sync-broker-instance.test.ts +124 -1
  12. package/src/brokers/sync-broker-instance.ts +113 -17
  13. package/src/capabilities/factories.ts +100 -0
  14. package/src/capabilities/index.ts +4 -0
  15. package/src/capabilities/registry.test.ts +137 -0
  16. package/src/capabilities/registry.ts +131 -0
  17. package/src/capabilities/service-capabilities.ts +27 -0
  18. package/src/capabilities/types.ts +84 -0
  19. package/src/cli/commands/ticker.ts +11 -3
  20. package/src/cli/context.ts +19 -13
  21. package/src/cli/helpers.ts +1 -0
  22. package/src/cli/types.ts +2 -2
  23. package/src/components/chart/chart-controller.ts +4 -24
  24. package/src/components/chart/chart-data.ts +3 -14
  25. package/src/components/chart/chart-indicator-selector.tsx +28 -6
  26. package/src/components/chart/chart-pane-settings.ts +15 -28
  27. package/src/components/chart/chart-renderer.ts +74 -99
  28. package/src/components/chart/chart-resolution.ts +10 -10
  29. package/src/components/chart/chart-scroll.test.ts +6 -5
  30. package/src/components/chart/chart-scroll.ts +2 -2
  31. package/src/components/chart/chart-types.ts +0 -1
  32. package/src/components/chart/chart-viewport.ts +2 -1
  33. package/src/components/chart/chart.test.ts +37 -0
  34. package/src/components/chart/comparison-chart-data.ts +3 -17
  35. package/src/components/chart/comparison-chart-renderer.test.ts +27 -4
  36. package/src/components/chart/comparison-chart-renderer.ts +1 -1
  37. package/src/components/chart/comparison-stock-chart.tsx +304 -108
  38. package/src/components/chart/cursor-motion.ts +3 -2
  39. package/src/components/chart/indicators/bands.test.ts +0 -14
  40. package/src/components/chart/indicators/moving-averages.test.ts +0 -15
  41. package/src/components/chart/indicators/options.ts +3 -3
  42. package/src/components/chart/indicators/oscillators.test.ts +0 -21
  43. package/src/components/chart/indicators/types.ts +1 -2
  44. package/src/components/chart/native/chart-rasterizer.ts +37 -44
  45. package/src/components/chart/native/kitty-adapter.ts +2 -5
  46. package/src/components/chart/native/kitty-manager.ts +1 -1
  47. package/src/components/chart/native/kitty-protocol.ts +0 -1
  48. package/src/components/chart/native/kitty-support.ts +1 -1
  49. package/src/components/chart/native/kitty.test.ts +30 -13
  50. package/src/components/chart/native/renderer-selection.ts +1 -1
  51. package/src/components/chart/native/surface-manager.ts +1 -1
  52. package/src/components/chart/static-chart-surface.test.tsx +51 -0
  53. package/src/components/chart/static-chart-surface.tsx +191 -0
  54. package/src/components/chart/stock-chart-renderer-switch.test.tsx +242 -35
  55. package/src/components/chart/stock-chart.tsx +438 -141
  56. package/src/components/command-bar/__snapshots__/command-bar.test.tsx.snap +4 -4
  57. package/src/components/command-bar/command-bar.test.tsx +269 -20
  58. package/src/components/command-bar/command-bar.tsx +830 -353
  59. package/src/components/command-bar/command-registry.ts +10 -20
  60. package/src/components/command-bar/helpers.test.ts +1 -1
  61. package/src/components/command-bar/helpers.ts +9 -11
  62. package/src/components/command-bar/pane-template-display.ts +4 -8
  63. package/src/components/command-bar/root-shortcuts.ts +12 -11
  64. package/src/components/command-bar/view-model.test.ts +8 -42
  65. package/src/components/command-bar/view-model.ts +8 -36
  66. package/src/components/command-bar/workflow-ops.test.ts +76 -2
  67. package/src/components/command-bar/workflow-ops.ts +40 -9
  68. package/src/components/command-bar/workflow-types.ts +2 -1
  69. package/src/components/data-table-stack-view.test.tsx +206 -0
  70. package/src/components/data-table-stack-view.tsx +152 -0
  71. package/src/components/data-table-view.test.tsx +188 -0
  72. package/src/components/data-table-view.tsx +279 -0
  73. package/src/components/feed-data-table-stack-view.test.tsx +225 -0
  74. package/src/components/feed-data-table-stack-view.tsx +365 -0
  75. package/src/components/index.ts +26 -31
  76. package/src/components/layout/detached-pane-shell.tsx +185 -0
  77. package/src/components/layout/floating-pane.tsx +87 -14
  78. package/src/components/layout/header.tsx +139 -49
  79. package/src/components/layout/pane-content.tsx +40 -0
  80. package/src/components/layout/pane-footer.test.tsx +195 -0
  81. package/src/components/layout/pane-footer.tsx +410 -0
  82. package/src/components/layout/pane-header.test.tsx +39 -0
  83. package/src/components/layout/pane-header.tsx +192 -14
  84. package/src/components/layout/pane-sizing.ts +9 -10
  85. package/src/components/layout/pane-title.ts +35 -0
  86. package/src/components/layout/pane.tsx +52 -11
  87. package/src/components/layout/shell.test.tsx +315 -107
  88. package/src/components/layout/shell.tsx +1010 -368
  89. package/src/components/layout/status-bar.test.tsx +17 -10
  90. package/src/components/layout/status-bar.tsx +367 -100
  91. package/src/components/layout/titlebar-overlay.ts +2 -0
  92. package/src/components/markdown-editor.tsx +29 -14
  93. package/src/components/markdown-text.tsx +25 -24
  94. package/src/components/onboarding/onboarding-wizard.test.tsx +8 -3
  95. package/src/components/onboarding/onboarding-wizard.tsx +347 -473
  96. package/src/components/pane-settings-dialog.tsx +521 -89
  97. package/src/components/pane-template-wizard.test.tsx +1 -1
  98. package/src/components/pane-template-wizard.tsx +38 -37
  99. package/src/components/price-selector-dialog.tsx +22 -21
  100. package/src/components/ticker-badge-list.tsx +53 -0
  101. package/src/components/ticker-badge-text.test.tsx +44 -1
  102. package/src/components/ticker-badge-text.tsx +78 -38
  103. package/src/components/ticker-badge.tsx +28 -7
  104. package/src/components/ticker-list-table-view.tsx +248 -0
  105. package/src/components/ticker-list-table.test.tsx +47 -1
  106. package/src/components/ticker-list-table.tsx +212 -41
  107. package/src/components/toggle-list.tsx +114 -8
  108. package/src/components/ui/button.tsx +24 -16
  109. package/src/components/ui/choice-dialog.tsx +89 -0
  110. package/src/components/ui/data-table.tsx +313 -114
  111. package/src/components/ui/external-link.tsx +52 -13
  112. package/src/components/ui/fields.tsx +44 -30
  113. package/src/components/ui/frame.tsx +24 -57
  114. package/src/components/ui/index.ts +15 -50
  115. package/src/components/ui/list-view.tsx +65 -25
  116. package/src/components/ui/loading.tsx +5 -60
  117. package/src/components/ui/message-composer.test.tsx +81 -0
  118. package/src/components/ui/message-composer.tsx +139 -0
  119. package/src/components/ui/multi-select-dialog.tsx +100 -32
  120. package/src/components/ui/multi-select.ts +112 -0
  121. package/src/components/ui/native-select.tsx +120 -0
  122. package/src/components/ui/page-stack-view.tsx +49 -19
  123. package/src/components/ui/remote-image.tsx +75 -0
  124. package/src/components/ui/row-value-cache.test.ts +17 -0
  125. package/src/components/ui/row-value-cache.ts +41 -0
  126. package/src/components/ui/shortcut-hint.tsx +55 -0
  127. package/src/components/ui/status.tsx +12 -67
  128. package/src/components/ui/table-layout.ts +59 -0
  129. package/src/components/ui/tabs.tsx +249 -27
  130. package/src/components/ui/toggle.tsx +19 -127
  131. package/src/components/ui/ui.test.tsx +266 -53
  132. package/src/components/use-double-click-activation.ts +7 -2
  133. package/src/components/use-external-link-footer.ts +79 -0
  134. package/src/core/app-services.ts +95 -0
  135. package/src/core/state/app-state.ts +886 -0
  136. package/src/{state → core/state}/session-persistence.ts +7 -6
  137. package/src/data/config-layout.ts +225 -0
  138. package/src/data/config-store-node.ts +390 -0
  139. package/src/data/config-store.test.ts +72 -0
  140. package/src/data/config-store.ts +35 -478
  141. package/src/data/sqlite-json.ts +2 -5
  142. package/src/data/sqlite-retry.ts +1 -0
  143. package/src/index.tsx +2 -68
  144. package/src/market-data/coordinator-subscriptions.test.ts +125 -0
  145. package/src/market-data/coordinator.test.ts +73 -4
  146. package/src/market-data/coordinator.ts +190 -24
  147. package/src/market-data/hooks.test.tsx +1 -1
  148. package/src/market-data/hooks.tsx +109 -87
  149. package/src/market-data/query-store.ts +3 -3
  150. package/src/market-data/request-types.test.ts +0 -14
  151. package/src/market-data/result-types.ts +1 -0
  152. package/src/news/aggregator.test.ts +267 -0
  153. package/src/news/aggregator.ts +452 -0
  154. package/src/news/hooks.ts +39 -0
  155. package/src/news/ticker-symbols.ts +21 -0
  156. package/src/news/types.ts +77 -0
  157. package/src/notifications/app-notifier.ts +21 -10
  158. package/src/pane-settings.test.ts +0 -2
  159. package/src/plugins/builtin/ai/ask-ai-detail-tab.tsx +124 -134
  160. package/src/plugins/builtin/ai/gloomberb-cli.ts +14 -13
  161. package/src/plugins/builtin/ai/providers.ts +1 -9
  162. package/src/plugins/builtin/ai/runner.ts +41 -5
  163. package/src/plugins/builtin/ai/screener-pane.test.tsx +37 -55
  164. package/src/plugins/builtin/ai/screener-pane.tsx +231 -276
  165. package/src/plugins/builtin/ai/settings.ts +0 -1
  166. package/src/plugins/builtin/ai/utils.ts +1 -71
  167. package/src/plugins/builtin/alerts/alert-engine.test.ts +1 -38
  168. package/src/plugins/builtin/alerts/index.test.tsx +61 -82
  169. package/src/plugins/builtin/alerts/index.tsx +263 -155
  170. package/src/plugins/builtin/alerts/types.ts +7 -0
  171. package/src/plugins/builtin/analytics/index.test.tsx +13 -8
  172. package/src/plugins/builtin/analytics/index.tsx +78 -120
  173. package/src/plugins/builtin/analytics/metrics.test.ts +0 -4
  174. package/src/plugins/builtin/ask-ai.test.tsx +55 -54
  175. package/src/plugins/builtin/broker-manager/index.test.tsx +168 -0
  176. package/src/plugins/builtin/broker-manager/index.tsx +759 -0
  177. package/src/plugins/builtin/broker-manager/model.test.ts +107 -0
  178. package/src/plugins/builtin/broker-manager/model.ts +142 -0
  179. package/src/plugins/builtin/chat-controller.test.ts +129 -0
  180. package/src/plugins/builtin/chat-controller.ts +85 -14
  181. package/src/plugins/builtin/chat.test.tsx +283 -36
  182. package/src/plugins/builtin/chat.tsx +363 -170
  183. package/src/plugins/builtin/cloud-auth-actions.tsx +72 -0
  184. package/src/plugins/builtin/cloud-tweets.tsx +896 -0
  185. package/src/plugins/builtin/comparison-chart.test.tsx +46 -57
  186. package/src/plugins/builtin/comparison-chart.tsx +11 -11
  187. package/src/plugins/builtin/correlation/compute.test.ts +0 -17
  188. package/src/plugins/builtin/correlation/index.tsx +51 -46
  189. package/src/plugins/builtin/correlation/settings.ts +1 -2
  190. package/src/plugins/builtin/debug.tsx +99 -70
  191. package/src/plugins/builtin/earnings/earnings-cache.test.ts +2 -2
  192. package/src/plugins/builtin/earnings/earnings-cache.ts +12 -3
  193. package/src/plugins/builtin/earnings/earnings-data.test.ts +42 -11
  194. package/src/plugins/builtin/earnings/earnings-data.ts +70 -5
  195. package/src/plugins/builtin/earnings/index.tsx +187 -94
  196. package/src/plugins/builtin/econ/calendar-source.ts +9 -116
  197. package/src/plugins/builtin/econ/fred-client.test.ts +1 -14
  198. package/src/plugins/builtin/econ/fred-series-map.ts +1 -0
  199. package/src/plugins/builtin/econ/index.tsx +236 -421
  200. package/src/plugins/builtin/econ/types.ts +1 -0
  201. package/src/plugins/builtin/fx-matrix/index.tsx +43 -45
  202. package/src/plugins/builtin/fx-matrix/pairs.ts +1 -0
  203. package/src/plugins/builtin/help.test.tsx +120 -60
  204. package/src/plugins/builtin/help.tsx +266 -82
  205. package/src/plugins/builtin/holders/index.test.ts +45 -0
  206. package/src/plugins/builtin/holders/index.tsx +949 -0
  207. package/src/plugins/builtin/insider/index.tsx +207 -253
  208. package/src/plugins/builtin/insider/insider-data.test.ts +1 -11
  209. package/src/plugins/builtin/insider/insider-data.ts +1 -0
  210. package/src/plugins/builtin/layout-manager.tsx +12 -40
  211. package/src/plugins/builtin/market-movers/index.tsx +70 -144
  212. package/src/plugins/builtin/market-movers/screener.test.ts +0 -18
  213. package/src/plugins/builtin/news-wire/breaking-notifications.test.ts +98 -0
  214. package/src/plugins/builtin/news-wire/breaking-notifications.ts +110 -0
  215. package/src/plugins/builtin/news-wire/breaking-pane.tsx +157 -0
  216. package/src/plugins/builtin/news-wire/categories.ts +114 -0
  217. package/src/plugins/builtin/news-wire/default-feeds.ts +3 -0
  218. package/src/plugins/builtin/news-wire/digest-store.ts +44 -0
  219. package/src/plugins/builtin/news-wire/feed-config.test.ts +90 -0
  220. package/src/plugins/builtin/news-wire/feed-config.ts +216 -0
  221. package/src/plugins/builtin/news-wire/feed-pane.tsx +21 -0
  222. package/src/plugins/builtin/news-wire/hash.ts +9 -0
  223. package/src/plugins/builtin/news-wire/index.tsx +92 -0
  224. package/src/plugins/builtin/news-wire/industry-pane.tsx +140 -0
  225. package/src/plugins/builtin/news-wire/news-detail-view.tsx +256 -0
  226. package/src/plugins/builtin/news-wire/news-footer.ts +28 -0
  227. package/src/plugins/builtin/news-wire/news-preset-pane.tsx +94 -0
  228. package/src/plugins/builtin/news-wire/news-query-presets.ts +40 -0
  229. package/src/plugins/builtin/news-wire/news-table.test.tsx +206 -0
  230. package/src/plugins/builtin/news-wire/news-table.tsx +296 -0
  231. package/src/plugins/builtin/news-wire/persisted-articles.ts +92 -0
  232. package/src/plugins/builtin/news-wire/read-state.test.ts +30 -0
  233. package/src/plugins/builtin/news-wire/read-state.ts +76 -0
  234. package/src/plugins/builtin/news-wire/rss-parser.test.ts +184 -0
  235. package/src/plugins/builtin/news-wire/rss-parser.ts +213 -0
  236. package/src/plugins/builtin/news-wire/rss-source.test.ts +159 -0
  237. package/src/plugins/builtin/news-wire/rss-source.ts +181 -0
  238. package/src/plugins/builtin/news-wire/top-pane.tsx +21 -0
  239. package/src/plugins/builtin/news.tsx +98 -25
  240. package/src/plugins/builtin/notes-files.ts +51 -10
  241. package/src/plugins/builtin/notes.tsx +332 -131
  242. package/src/plugins/builtin/options.test.tsx +185 -0
  243. package/src/plugins/builtin/options.tsx +346 -206
  244. package/src/plugins/builtin/plugin-groups.ts +92 -0
  245. package/src/plugins/builtin/portfolio-list/header.tsx +72 -37
  246. package/src/plugins/builtin/portfolio-list/index.tsx +25 -42
  247. package/src/plugins/builtin/portfolio-list/metrics.ts +1 -1
  248. package/src/plugins/builtin/portfolio-list/pane.tsx +246 -164
  249. package/src/plugins/builtin/portfolio-list/settings.ts +19 -51
  250. package/src/plugins/builtin/portfolio-list/summary.tsx +21 -16
  251. package/src/plugins/builtin/portfolio-list/table.tsx +66 -25
  252. package/src/plugins/builtin/portfolio-list/use-throttled-cursor-symbol.test.tsx +1 -1
  253. package/src/plugins/builtin/portfolio-list/use-throttled-cursor-symbol.ts +1 -1
  254. package/src/plugins/builtin/portfolio-list.test.ts +60 -1
  255. package/src/plugins/builtin/portfolio-list.test.tsx +122 -55
  256. package/src/plugins/builtin/quote-monitor.test.tsx +2 -27
  257. package/src/plugins/builtin/research/index.tsx +724 -0
  258. package/src/plugins/builtin/sec.tsx +67 -19
  259. package/src/plugins/builtin/sectors/index.tsx +42 -80
  260. package/src/plugins/builtin/sectors/sector-data.ts +1 -0
  261. package/src/plugins/builtin/ticker-detail/chart-tab.tsx +25 -39
  262. package/src/plugins/builtin/ticker-detail/financials-tab.tsx +108 -58
  263. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +383 -271
  264. package/src/plugins/builtin/ticker-detail/pane.tsx +135 -49
  265. package/src/plugins/builtin/ticker-detail/quote-monitor.tsx +43 -27
  266. package/src/plugins/builtin/ticker-detail/settings.ts +3 -6
  267. package/src/plugins/builtin/ticker-detail-chart-tab-switch.test.tsx +16 -10
  268. package/src/plugins/builtin/ticker-detail.test.tsx +156 -33
  269. package/src/plugins/builtin/ticker-surface.ts +68 -0
  270. package/src/plugins/builtin/world-indices/index.tsx +44 -82
  271. package/src/plugins/builtin/world-indices/indices.ts +1 -0
  272. package/src/plugins/builtin/yahoo.ts +55 -1
  273. package/src/plugins/builtin/yield-curve/index.tsx +87 -145
  274. package/src/plugins/builtin/yield-curve/treasury-data.ts +6 -77
  275. package/src/plugins/catalog-ui.test.ts +24 -0
  276. package/src/plugins/catalog-ui.ts +44 -0
  277. package/src/plugins/catalog.ts +2 -50
  278. package/src/plugins/ibkr/__snapshots__/trade-tab.test.tsx.snap +5 -5
  279. package/src/plugins/ibkr/account-cache.test.ts +15 -14
  280. package/src/plugins/ibkr/account-cache.ts +15 -120
  281. package/src/plugins/ibkr/broker-adapter.ts +67 -0
  282. package/src/plugins/ibkr/config.test.ts +0 -18
  283. package/src/plugins/ibkr/dialogs.tsx +14 -56
  284. package/src/plugins/ibkr/flex.test.ts +57 -2
  285. package/src/plugins/ibkr/flex.ts +116 -12
  286. package/src/plugins/ibkr/gateway-helpers.ts +8 -3
  287. package/src/plugins/ibkr/gateway-service-native.ts +2381 -0
  288. package/src/plugins/ibkr/gateway-service.test.ts +47 -9
  289. package/src/plugins/ibkr/gateway-service.ts +264 -2235
  290. package/src/plugins/ibkr/gateway-types.ts +27 -0
  291. package/src/plugins/ibkr/index.test.tsx +3 -11
  292. package/src/plugins/ibkr/index.tsx +1 -0
  293. package/src/plugins/ibkr/price-normalization.test.ts +1 -6
  294. package/src/plugins/ibkr/price-normalization.ts +1 -0
  295. package/src/plugins/ibkr/trade-badge.tsx +6 -5
  296. package/src/plugins/ibkr/trade-tab.test.tsx +2 -2
  297. package/src/plugins/ibkr/trade-tab.tsx +164 -117
  298. package/src/plugins/ibkr/trading-pane.tsx +117 -83
  299. package/src/plugins/pane-manager.test.ts +3 -1
  300. package/src/plugins/pane-manager.ts +93 -19
  301. package/src/plugins/plugin-runtime.test.tsx +176 -74
  302. package/src/plugins/plugin-runtime.tsx +228 -10
  303. package/src/plugins/prediction-markets/cache.ts +49 -0
  304. package/src/plugins/prediction-markets/categories.ts +0 -10
  305. package/src/plugins/prediction-markets/chart.test.tsx +1 -1
  306. package/src/plugins/prediction-markets/chart.tsx +21 -20
  307. package/src/plugins/prediction-markets/cli.ts +1 -0
  308. package/src/plugins/prediction-markets/controller-data.ts +135 -89
  309. package/src/plugins/prediction-markets/controller.ts +37 -108
  310. package/src/plugins/prediction-markets/detail/book.tsx +23 -22
  311. package/src/plugins/prediction-markets/detail/outcomes.tsx +33 -32
  312. package/src/plugins/prediction-markets/detail/overview.tsx +17 -12
  313. package/src/plugins/prediction-markets/detail/pane.tsx +59 -45
  314. package/src/plugins/prediction-markets/detail/rules.tsx +22 -7
  315. package/src/plugins/prediction-markets/detail/shared.tsx +3 -2
  316. package/src/plugins/prediction-markets/detail/trades.tsx +12 -11
  317. package/src/plugins/prediction-markets/detail.test.tsx +1 -1
  318. package/src/plugins/prediction-markets/keyboard.ts +1 -0
  319. package/src/plugins/prediction-markets/launch.test.ts +1 -1
  320. package/src/plugins/prediction-markets/launch.ts +1 -1
  321. package/src/plugins/prediction-markets/metrics.ts +25 -12
  322. package/src/plugins/prediction-markets/pane.test.tsx +16 -7
  323. package/src/plugins/prediction-markets/pane.tsx +180 -82
  324. package/src/plugins/prediction-markets/plugin.test.tsx +37 -45
  325. package/src/plugins/prediction-markets/services/fetch.ts +27 -10
  326. package/src/plugins/prediction-markets/services/kalshi-adapter.ts +20 -3
  327. package/src/plugins/prediction-markets/services/polymarket-adapter.ts +29 -11
  328. package/src/plugins/prediction-markets/settings.ts +0 -5
  329. package/src/plugins/prediction-markets/test-helpers.tsx +19 -44
  330. package/src/plugins/registry.test.ts +307 -0
  331. package/src/plugins/registry.ts +293 -82
  332. package/src/react/input.ts +53 -0
  333. package/src/react/plugins/plugin-slot.tsx +21 -0
  334. package/src/react/use-raf-callback.ts +44 -0
  335. package/src/renderers/electrobun/bun/application-menu-click.test.ts +41 -0
  336. package/src/renderers/electrobun/bun/application-menu-click.ts +55 -0
  337. package/src/renderers/electrobun/bun/application-menu.ts +118 -0
  338. package/src/renderers/electrobun/bun/context-menu-click.test.ts +67 -0
  339. package/src/renderers/electrobun/bun/context-menu-click.ts +61 -0
  340. package/src/renderers/electrobun/bun/context-menu-normalize.test.ts +52 -0
  341. package/src/renderers/electrobun/bun/context-menu-normalize.ts +67 -0
  342. package/src/renderers/electrobun/bun/core-capabilities.ts +328 -0
  343. package/src/renderers/electrobun/bun/desktop-workspace.test.ts +63 -0
  344. package/src/renderers/electrobun/bun/desktop-workspace.ts +162 -0
  345. package/src/renderers/electrobun/bun/index.ts +1149 -0
  346. package/src/renderers/electrobun/bun/window-frame.test.ts +40 -0
  347. package/src/renderers/electrobun/bun/window-frame.ts +46 -0
  348. package/src/renderers/electrobun/shared/protocol.ts +72 -0
  349. package/src/renderers/electrobun/view/ai-host.ts +93 -0
  350. package/src/renderers/electrobun/view/app-services.ts +348 -0
  351. package/src/renderers/electrobun/view/application-menu-bridge.ts +12 -0
  352. package/src/renderers/electrobun/view/backend-rpc.ts +173 -0
  353. package/src/renderers/electrobun/view/broker-remote-client.ts +154 -0
  354. package/src/renderers/electrobun/view/config-host.ts +35 -0
  355. package/src/renderers/electrobun/view/context-menu.test.ts +140 -0
  356. package/src/renderers/electrobun/view/context-menu.ts +164 -0
  357. package/src/renderers/electrobun/view/data-table.tsx +773 -0
  358. package/src/renderers/electrobun/view/desktop-controls.tsx +651 -0
  359. package/src/renderers/electrobun/view/desktop-window-bridge.ts +59 -0
  360. package/src/renderers/electrobun/view/desktop-window-snapshot.test.ts +57 -0
  361. package/src/renderers/electrobun/view/desktop-window-snapshot.ts +41 -0
  362. package/src/renderers/electrobun/view/dialog-host.tsx +62 -0
  363. package/src/renderers/electrobun/view/http-fetch.ts +113 -0
  364. package/src/renderers/electrobun/view/input-host.tsx +65 -0
  365. package/src/renderers/electrobun/view/key-event.test.ts +34 -0
  366. package/src/renderers/electrobun/view/key-event.ts +134 -0
  367. package/src/renderers/electrobun/view/main.tsx +104 -0
  368. package/src/renderers/electrobun/view/native-renderer.ts +110 -0
  369. package/src/renderers/electrobun/view/native-stubs/chart-kitty-support.ts +9 -0
  370. package/src/renderers/electrobun/view/native-stubs/chart-surface-manager.ts +25 -0
  371. package/src/renderers/electrobun/view/native-stubs/chart-surface-sync.ts +1 -0
  372. package/src/renderers/electrobun/view/notes-files.ts +56 -0
  373. package/src/renderers/electrobun/view/resource-store.test.ts +44 -0
  374. package/src/renderers/electrobun/view/resource-store.ts +106 -0
  375. package/src/renderers/electrobun/view/rpc-codec.ts +42 -0
  376. package/src/renderers/electrobun/view/scrollbar-activity.ts +23 -0
  377. package/src/renderers/electrobun/view/toast-host.tsx +65 -0
  378. package/src/renderers/electrobun/view/ui-host.tsx +1490 -0
  379. package/src/renderers/electrobun/view/update-host.ts +38 -0
  380. package/src/renderers/opentui/dialog-host.test.tsx +44 -0
  381. package/src/renderers/opentui/dialog-host.tsx +56 -0
  382. package/src/renderers/opentui/host.tsx +134 -0
  383. package/src/renderers/opentui/input-host.tsx +24 -0
  384. package/src/renderers/opentui/start.tsx +71 -0
  385. package/src/renderers/opentui/test-utils.tsx +76 -0
  386. package/src/renderers/opentui/toast-host.tsx +10 -0
  387. package/src/renderers/opentui/ui-host.tsx +97 -0
  388. package/src/sources/gloomberb-cloud.test.ts +288 -17
  389. package/src/sources/gloomberb-cloud.ts +176 -9
  390. package/src/sources/provider-errors.ts +1 -0
  391. package/src/sources/provider-router.test.ts +220 -81
  392. package/src/sources/provider-router.ts +294 -111
  393. package/src/sources/sec-edgar.ts +19 -6
  394. package/src/sources/yahoo-finance.test.ts +0 -5
  395. package/src/sources/yahoo-finance.ts +420 -11
  396. package/src/state/app-activity.ts +7 -7
  397. package/src/state/app-bootstrap.ts +114 -40
  398. package/src/state/app-context-selector.test.tsx +70 -1
  399. package/src/state/app-context.test.ts +71 -3
  400. package/src/state/app-context.test.tsx +14 -7
  401. package/src/state/app-context.tsx +205 -869
  402. package/src/state/config-save-scheduler.ts +35 -0
  403. package/src/state/persist-scheduler.test.ts +67 -0
  404. package/src/state/persist-scheduler.ts +69 -0
  405. package/src/state/selectors-ui.ts +55 -0
  406. package/src/state/selectors.ts +15 -71
  407. package/src/state/session-persistence.test.ts +1 -1
  408. package/src/state/ticker-refresh-queue.ts +52 -3
  409. package/src/state/use-inline-tickers.ts +18 -16
  410. package/src/state/use-quote-streaming.test.ts +0 -6
  411. package/src/state/use-quote-streaming.test.tsx +1 -1
  412. package/src/state/use-quote-streaming.ts +3 -2
  413. package/src/state/use-session-snapshot.ts +32 -17
  414. package/src/test-support/plugin-runtime.ts +149 -0
  415. package/src/theme/color-utils.ts +1 -0
  416. package/src/theme/colors.ts +16 -0
  417. package/src/types/broker.ts +16 -1
  418. package/src/types/capability-route-source.ts +23 -0
  419. package/src/types/config.test.ts +23 -0
  420. package/src/types/config.ts +145 -10
  421. package/src/types/context-menu.ts +95 -0
  422. package/src/types/data-provider.ts +34 -3
  423. package/src/types/desktop-menu.ts +13 -0
  424. package/src/types/desktop-window.ts +29 -0
  425. package/src/types/financials.ts +123 -2
  426. package/src/types/instrument.ts +1 -0
  427. package/src/types/news-source.ts +9 -0
  428. package/src/types/persistence.ts +1 -0
  429. package/src/types/plugin.ts +32 -8
  430. package/src/ui/ascii-font.ts +85 -0
  431. package/src/ui/context-menu.test.ts +94 -0
  432. package/src/ui/context-menu.tsx +433 -0
  433. package/src/ui/dialog.tsx +55 -0
  434. package/src/ui/host.tsx +361 -0
  435. package/src/ui/index.tsx +126 -0
  436. package/src/ui/toast.tsx +40 -0
  437. package/src/updater.test.ts +69 -0
  438. package/src/updater.ts +61 -18
  439. package/src/utils/api-client.test.ts +99 -9
  440. package/src/utils/api-client.ts +378 -18
  441. package/src/utils/back-navigation.ts +6 -0
  442. package/src/utils/cli-output.ts +1 -0
  443. package/src/utils/currency-units.test.ts +1 -6
  444. package/src/utils/currency-units.ts +1 -0
  445. package/src/utils/debug-log.ts +68 -0
  446. package/src/utils/dom-screenshot.ts +326 -0
  447. package/src/utils/exchange-rate-map.ts +1 -0
  448. package/src/utils/exchanges.ts +214 -0
  449. package/src/utils/format.test.ts +7 -0
  450. package/src/utils/format.ts +1 -0
  451. package/src/utils/fuzzy-search.ts +1 -0
  452. package/src/utils/html-entities.test.ts +8 -0
  453. package/src/utils/html-entities.ts +32 -0
  454. package/src/utils/http-transport.ts +11 -0
  455. package/src/utils/main-thread-monitor.ts +127 -0
  456. package/src/utils/perf-marks.ts +54 -0
  457. package/src/utils/quote-freshness.ts +27 -50
  458. package/src/utils/quote-resolution.test.ts +5 -5
  459. package/src/utils/quote-resolution.ts +0 -1
  460. package/src/utils/quote-time.ts +1 -5
  461. package/src/utils/sec.test.ts +0 -12
  462. package/src/utils/selection-clipboard.ts +14 -6
  463. package/src/utils/shortcut-labels.test.ts +20 -0
  464. package/src/utils/shortcut-labels.ts +67 -0
  465. package/src/utils/slugify.ts +1 -0
  466. package/src/utils/terminal-input-reset.ts +1 -0
  467. package/src/utils/text-wrap.ts +82 -0
  468. package/src/utils/throttled-fetch.test.ts +19 -0
  469. package/src/utils/throttled-fetch.ts +11 -9
  470. package/src/utils/ticker-list.test.ts +1 -7
  471. package/src/utils/ticker-list.ts +1 -0
  472. package/src/utils/timestamp.ts +29 -0
  473. package/src/utils/tweet-text.test.ts +13 -0
  474. package/src/utils/tweet-text.ts +18 -0
  475. package/src/utils/url.ts +11 -0
  476. package/src/version.ts +1 -1
  477. package/src/components/chart/chart-control-hint.tsx +0 -39
  478. package/src/components/detail-feed-view.test.tsx +0 -180
  479. package/src/components/detail-feed-view.tsx +0 -531
  480. package/src/components/layout/pixel-mouse-mode.test.ts +0 -122
  481. package/src/components/layout/pixel-mouse.test.ts +0 -40
  482. package/src/components/spinner.tsx +0 -2
  483. package/src/components/tab-bar.tsx +0 -17
  484. package/src/components/ui/multi-select-chips.tsx +0 -69
  485. package/src/plugins/builtin/ai/index.test.tsx +0 -139
  486. package/src/plugins/builtin/ask-ai.tsx +0 -9
  487. package/src/plugins/builtin/correlation/plugin.test.ts +0 -44
  488. package/src/plugins/builtin/correlation/settings.test.ts +0 -34
  489. package/src/plugins/builtin/econ/calendar-source.test.ts +0 -219
  490. package/src/plugins/builtin/econ/fred-client.ts +0 -79
  491. package/src/plugins/builtin/fred-settings.ts +0 -10
  492. package/src/plugins/builtin/options-availability.test.tsx +0 -179
  493. package/src/plugins/builtin/options-availability.ts +0 -158
  494. package/src/plugins/builtin/portfolio-list/metrics.test.ts +0 -61
  495. package/src/plugins/builtin/yield-curve/treasury-data.test.ts +0 -212
  496. package/src/plugins/prediction-markets/status.ts +0 -24
  497. package/src/plugins/prediction-markets/table.tsx +0 -87
  498. package/src/utils/quote-time.test.ts +0 -22
  499. package/src/utils/selection-clipboard.test.ts +0 -43
  500. package/src/utils/terminal-input-reset.test.ts +0 -50
@@ -1,8 +1,12 @@
1
1
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
2
- import { type InputRenderable, type ScrollBoxRenderable } from "@opentui/core";
3
- import { useKeyboard } from "@opentui/react";
2
+ import { type InputRenderable, type ScrollBoxRenderable } from "../../ui";
3
+ import { useShortcut, useViewport } from "../../react/input";
4
4
  import { usePaneInstance } from "../../state/app-context";
5
- import { usePluginPaneState, usePluginState } from "../plugin-runtime";
5
+ import {
6
+ useDebouncedPluginPaneState,
7
+ usePluginPaneState,
8
+ usePluginState,
9
+ } from "../plugin-runtime";
6
10
  import { getAdjacentPredictionCategoryId } from "./categories";
7
11
  import { usePredictionMarketsDataState } from "./controller-data";
8
12
  import { resolvePredictionKeyboardCommand } from "./keyboard";
@@ -29,6 +33,7 @@ import type {
29
33
  } from "./types";
30
34
 
31
35
  const KEYBOARD_DETAIL_LOAD_DELAY_MS = 140;
36
+ const SELECTION_PERSIST_DEBOUNCE_MS = 300;
32
37
 
33
38
  export function usePredictionMarketsController({
34
39
  focused,
@@ -71,11 +76,18 @@ export function usePredictionMarketsController({
71
76
  );
72
77
  const [historyRange, setHistoryRange] =
73
78
  usePluginPaneState<PredictionHistoryRange>("historyRange", "1M");
74
- const [selectedRowKey, setSelectedRowKey] = usePluginPaneState<
75
- string | null
76
- >("selectedRowKey", null);
79
+ const [selectedRowKey, setSelectedRowKey] =
80
+ useDebouncedPluginPaneState<string | null>(
81
+ "selectedRowKey",
82
+ null,
83
+ SELECTION_PERSIST_DEBOUNCE_MS,
84
+ );
77
85
  const [selectedDetailMarketKey, setSelectedDetailMarketKey] =
78
- usePluginPaneState<string | null>("selectedDetailMarketKey", null);
86
+ useDebouncedPluginPaneState<string | null>(
87
+ "selectedDetailMarketKey",
88
+ null,
89
+ SELECTION_PERSIST_DEBOUNCE_MS,
90
+ );
79
91
  const defaultSortPreference = useMemo(
80
92
  () => getDefaultPredictionSort(paneSettings.defaultBrowseTab),
81
93
  [paneSettings.defaultBrowseTab],
@@ -91,10 +103,10 @@ export function usePredictionMarketsController({
91
103
  null,
92
104
  );
93
105
 
94
- const [hoveredIdx, setHoveredIdx] = useState<number | null>(null);
95
106
  const [detailOpen, setDetailOpen] = useState(false);
96
107
  const [searchFocused, setSearchFocused] = useState(false);
97
108
  const [initialParamsApplied, setInitialParamsApplied] = useState(false);
109
+ const appViewport = useViewport();
98
110
 
99
111
  const scrollRef = useRef<ScrollBoxRenderable>(null);
100
112
  const headerScrollRef = useRef<ScrollBoxRenderable>(null);
@@ -131,22 +143,6 @@ export function usePredictionMarketsController({
131
143
  watchlistSet,
132
144
  });
133
145
 
134
- const syncHeaderScroll = useCallback(() => {
135
- const bodyScrollBox = scrollRef.current;
136
- const headerScrollBox = headerScrollRef.current;
137
- if (
138
- bodyScrollBox &&
139
- headerScrollBox &&
140
- headerScrollBox.scrollLeft !== bodyScrollBox.scrollLeft
141
- ) {
142
- headerScrollBox.scrollLeft = bodyScrollBox.scrollLeft;
143
- }
144
- }, []);
145
-
146
- const onBodyScrollActivity = useCallback(() => {
147
- syncHeaderScroll();
148
- }, [syncHeaderScroll]);
149
-
150
146
  useEffect(() => {
151
147
  if (paneSettings.hideTabs && venueScope !== paneSettings.lockedVenueScope) {
152
148
  setVenueScope(paneSettings.lockedVenueScope);
@@ -213,7 +209,6 @@ export function usePredictionMarketsController({
213
209
  if (previousFilterResetKey == null) {
214
210
  return;
215
211
  }
216
- setHoveredIdx(null);
217
212
  const scrollBox = scrollRef.current;
218
213
  if (scrollBox) {
219
214
  scrollBox.scrollTop = 0;
@@ -304,18 +299,22 @@ export function usePredictionMarketsController({
304
299
  if (data.selectedIndex < 0) return;
305
300
  const scrollBox = scrollRef.current;
306
301
  if (!scrollBox?.viewport) return;
302
+ const viewportHeight = Math.max(
303
+ 1,
304
+ Math.min(scrollBox.viewport.height, Math.ceil(appViewport.height)),
305
+ );
307
306
  if (data.selectedIndex < scrollBox.scrollTop) {
308
307
  scrollBox.scrollTop = data.selectedIndex;
309
308
  } else if (
310
309
  data.selectedIndex >=
311
- scrollBox.scrollTop + scrollBox.viewport.height
310
+ scrollBox.scrollTop + viewportHeight
312
311
  ) {
313
312
  scrollBox.scrollTop = Math.max(
314
313
  0,
315
- data.selectedIndex - scrollBox.viewport.height + 1,
314
+ data.selectedIndex - viewportHeight + 1,
316
315
  );
317
316
  }
318
- }, [data.selectedIndex]);
317
+ }, [appViewport.height, data.selectedIndex]);
319
318
 
320
319
  useEffect(() => {
321
320
  if (!searchFocused) return;
@@ -352,9 +351,11 @@ export function usePredictionMarketsController({
352
351
  data.actions.setNextDetailLoadDelay(
353
352
  options?.debounceDetail ? KEYBOARD_DETAIL_LOAD_DELAY_MS : 0,
354
353
  );
355
- setSelectedRowKey(rowKey);
354
+ setSelectedRowKey(rowKey, {
355
+ immediate: !options?.debounceDetail || selectedRowKey == null,
356
+ });
356
357
  },
357
- [data.actions, setSelectedRowKey],
358
+ [data.actions, selectedRowKey, setSelectedRowKey],
358
359
  );
359
360
 
360
361
  const openSelectedRow = useCallback(
@@ -363,8 +364,8 @@ export function usePredictionMarketsController({
363
364
  if (!row) return;
364
365
  setSearchFocused(false);
365
366
  data.actions.setNextDetailLoadDelay(0);
366
- setSelectedRowKey(row.key);
367
- setSelectedDetailMarketKey(row.focusMarketKey);
367
+ setSelectedRowKey(row.key, { immediate: true });
368
+ setSelectedDetailMarketKey(row.focusMarketKey, { immediate: true });
368
369
  setDetailOpen(true);
369
370
  },
370
371
  [data.actions, data.visibleRows, setSelectedDetailMarketKey, setSelectedRowKey],
@@ -383,8 +384,8 @@ export function usePredictionMarketsController({
383
384
  setSelectedDetailMarketKey(null);
384
385
  return;
385
386
  }
386
- setSelectedRowKey(row.key);
387
- setSelectedDetailMarketKey(marketKey);
387
+ setSelectedRowKey(row.key, { immediate: true });
388
+ setSelectedDetailMarketKey(marketKey, { immediate: true });
388
389
  setDetailOpen(true);
389
390
  },
390
391
  [
@@ -396,37 +397,11 @@ export function usePredictionMarketsController({
396
397
  ],
397
398
  );
398
399
 
399
- const clearSelection = useCallback(() => {
400
- data.actions.setNextDetailLoadDelay(0);
401
- setDetailOpen(false);
402
- setSelectedRowKey(null);
403
- setSelectedDetailMarketKey(null);
404
- }, [
405
- data.actions,
406
- setDetailOpen,
407
- setSelectedDetailMarketKey,
408
- setSelectedRowKey,
409
- ]);
410
-
411
400
  const closeDetail = useCallback(() => {
412
401
  setDetailOpen(false);
413
402
  setSearchFocused(false);
414
403
  }, []);
415
404
 
416
- const openDetail = useCallback(() => {
417
- if (!data.selectedRow) return;
418
- if (
419
- !selectedDetailMarketKey ||
420
- !data.selectedRow.markets.some(
421
- (market) => market.key === selectedDetailMarketKey,
422
- )
423
- ) {
424
- setSelectedDetailMarketKey(data.selectedRow.focusMarketKey);
425
- }
426
- setDetailOpen(true);
427
- setSearchFocused(false);
428
- }, [data.selectedRow, selectedDetailMarketKey, setSelectedDetailMarketKey]);
429
-
430
405
  const setVenue = useCallback(
431
406
  (nextVenueScope: string) => {
432
407
  const typed = nextVenueScope as PredictionVenueScope;
@@ -512,8 +487,6 @@ export function usePredictionMarketsController({
512
487
  }) => {
513
488
  if (!focused) return;
514
489
  const command = resolvePredictionKeyboardCommand(event);
515
- const key = event.name?.toLowerCase();
516
- const isEnter = key === "enter" || key === "return";
517
490
 
518
491
  if (searchFocused) {
519
492
  if (command === "escape") {
@@ -571,39 +544,6 @@ export function usePredictionMarketsController({
571
544
  return;
572
545
  }
573
546
 
574
- if (isEnter && data.selectedRow) {
575
- event.stopPropagation?.();
576
- event.preventDefault?.();
577
- openDetail();
578
- return;
579
- }
580
-
581
- if (command === "move-down") {
582
- event.stopPropagation?.();
583
- event.preventDefault?.();
584
- if (data.visibleRows.length === 0) return;
585
- const nextIndex =
586
- data.selectedIndex >= 0
587
- ? Math.min(data.selectedIndex + 1, data.visibleRows.length - 1)
588
- : 0;
589
- setBrowseSelection(data.visibleRows[nextIndex]!.key, {
590
- debounceDetail: true,
591
- });
592
- return;
593
- }
594
-
595
- if (command === "move-up") {
596
- event.stopPropagation?.();
597
- event.preventDefault?.();
598
- if (data.visibleRows.length === 0) return;
599
- const nextIndex =
600
- data.selectedIndex >= 0 ? Math.max(data.selectedIndex - 1, 0) : 0;
601
- setBrowseSelection(data.visibleRows[nextIndex]!.key, {
602
- debounceDetail: true,
603
- });
604
- return;
605
- }
606
-
607
547
  if (!paneSettings.hideTabs && command === "previous-venue-tab") {
608
548
  event.stopPropagation?.();
609
549
  event.preventDefault?.();
@@ -662,27 +602,23 @@ export function usePredictionMarketsController({
662
602
  categoryId,
663
603
  cycleDetailOutcome,
664
604
  detailOpen,
665
- data.selectedIndex,
666
605
  data.selectedRow,
667
606
  data.sortedOutcomeMarkets.length,
668
- data.visibleRows,
669
607
  detailTab,
670
608
  effectiveVenueScope,
671
609
  focusSearch,
672
610
  focused,
673
- openDetail,
674
611
  paneSettings.hideTabs,
675
612
  scrollDetailBy,
676
613
  searchFocused,
677
614
  selectBrowseTab,
678
615
  selectCategory,
679
- setBrowseSelection,
680
616
  setVenue,
681
617
  toggleWatchlist,
682
618
  ],
683
619
  );
684
620
 
685
- useKeyboard(handleKeyboard);
621
+ useShortcut(handleKeyboard);
686
622
 
687
623
  const searchPending = searchQuery.trim() !== data.debouncedSearchQuery.trim();
688
624
  const searchLoading =
@@ -703,7 +639,6 @@ export function usePredictionMarketsController({
703
639
  effectiveVenueScope,
704
640
  headerScrollRef,
705
641
  historyRange,
706
- hoveredIdx,
707
642
  lastRefreshAt: data.lastRefreshAt,
708
643
  scrollRef,
709
644
  searchFocused,
@@ -711,6 +646,7 @@ export function usePredictionMarketsController({
711
646
  searchLoading,
712
647
  searchQuery,
713
648
  selectedRow: data.selectedRow,
649
+ selectedIndex: data.selectedIndex,
714
650
  selectedSummary: data.selectedSummary,
715
651
  sortPreference,
716
652
  transportState: data.transportState,
@@ -720,10 +656,8 @@ export function usePredictionMarketsController({
720
656
  actions: {
721
657
  blurSearch,
722
658
  closeDetail,
723
- clearSelection,
724
659
  focusSearch,
725
660
  handleSortHeaderClick,
726
- openDetail,
727
661
  openSelectedRow,
728
662
  previewOrder,
729
663
  selectBrowseTab,
@@ -732,14 +666,9 @@ export function usePredictionMarketsController({
732
666
  setDetailTab,
733
667
  setBrowseSelection,
734
668
  setHistoryRange,
735
- setHoveredIdx,
736
669
  setSearchQuery,
737
670
  setVenue,
738
671
  toggleWatchlist,
739
672
  },
740
- layout: {
741
- onBodyScrollActivity,
742
- syncHeaderScroll,
743
- },
744
673
  };
745
674
  }
@@ -1,4 +1,5 @@
1
- import { TextAttributes } from "@opentui/core";
1
+ import { Box, Text } from "../../../ui";
2
+ import { TextAttributes } from "../../../ui";
2
3
  import { colors } from "../../../theme/colors";
3
4
  import { formatNumber, padTo } from "../../../utils/format";
4
5
  import { formatPredictionProbability } from "../metrics";
@@ -18,19 +19,19 @@ function BookTable({
18
19
  onSelect: (level: PredictionBookLevel) => void;
19
20
  }) {
20
21
  return (
21
- <box flexDirection="column" flexGrow={1}>
22
- <box height={1}>
23
- <text fg={colors.textBright} attributes={TextAttributes.BOLD}>
22
+ <Box flexDirection="column" flexGrow={1}>
23
+ <Box height={1}>
24
+ <Text fg={colors.textBright} attributes={TextAttributes.BOLD}>
24
25
  {title}
25
- </text>
26
- </box>
27
- <box height={1}>
28
- <text fg={colors.textDim}>
26
+ </Text>
27
+ </Box>
28
+ <Box height={1}>
29
+ <Text fg={colors.textDim}>
29
30
  {padTo("PRICE", 8)} {padTo("SIZE", 10)}
30
- </text>
31
- </box>
31
+ </Text>
32
+ </Box>
32
33
  {levels.slice(0, 10).map((level) => (
33
- <box
34
+ <Box
34
35
  key={`${title}:${level.price}:${level.size}`}
35
36
  height={1}
36
37
  onMouseDown={(event) => {
@@ -38,13 +39,13 @@ function BookTable({
38
39
  onSelect(level);
39
40
  }}
40
41
  >
41
- <text fg={colors.text}>
42
+ <Text fg={colors.text}>
42
43
  {`${padTo(formatPredictionProbability(level.price), 8)} ${padTo(formatNumber(level.size, 0), 10, "right")}`}
43
- </text>
44
- </box>
44
+ </Text>
45
+ </Box>
45
46
  ))}
46
- {levels.length === 0 && <text fg={colors.textDim}>No levels.</text>}
47
- </box>
47
+ {levels.length === 0 && <Text fg={colors.textDim}>No levels.</Text>}
48
+ </Box>
48
49
  );
49
50
  }
50
51
 
@@ -56,8 +57,8 @@ export function PredictionMarketBookView({
56
57
  onPreviewOrder: (intent: PredictionOrderPreviewIntent) => void;
57
58
  }) {
58
59
  return (
59
- <box flexDirection="column" gap={1}>
60
- <box flexDirection="row" gap={2}>
60
+ <Box flexDirection="column" gap={1}>
61
+ <Box flexDirection="row" gap={2}>
61
62
  <BookTable
62
63
  title="YES Bids"
63
64
  levels={detail.book.yesBids}
@@ -84,8 +85,8 @@ export function PredictionMarketBookView({
84
85
  })
85
86
  }
86
87
  />
87
- </box>
88
- <box flexDirection="row" gap={2}>
88
+ </Box>
89
+ <Box flexDirection="row" gap={2}>
89
90
  <BookTable
90
91
  title="NO Bids"
91
92
  levels={detail.book.noBids}
@@ -112,7 +113,7 @@ export function PredictionMarketBookView({
112
113
  })
113
114
  }
114
115
  />
115
- </box>
116
- </box>
116
+ </Box>
117
+ </Box>
117
118
  );
118
119
  }
@@ -1,4 +1,5 @@
1
- import { TextAttributes } from "@opentui/core";
1
+ import { Box, Text } from "../../../ui";
2
+ import { TextAttributes } from "../../../ui";
2
3
  import { colors } from "../../../theme/colors";
3
4
  import { padTo } from "../../../utils/format";
4
5
  import {
@@ -26,29 +27,29 @@ export function PredictionMarketOutcomesView({
26
27
  const labelWidth = Math.max(detailWidth - 22, 12);
27
28
 
28
29
  return (
29
- <box flexDirection="column">
30
- <box height={1}>
31
- <text fg={colors.textBright} attributes={TextAttributes.BOLD}>
30
+ <Box flexDirection="column">
31
+ <Box height={1}>
32
+ <Text fg={colors.textBright} attributes={TextAttributes.BOLD}>
32
33
  Outcomes
33
- </text>
34
- </box>
34
+ </Text>
35
+ </Box>
35
36
 
36
- <box flexDirection="row" height={1}>
37
- <box width={labelWidth + 1}>
38
- <text fg={colors.textDim}>{padTo("TARGET", labelWidth)}</text>
39
- </box>
40
- <box width={8}>
41
- <text fg={colors.textDim}>{padTo("ODDS", 7, "right")}</text>
42
- </box>
43
- <box width={13}>
44
- <text fg={colors.textDim}>{padTo("24H VOL", 12, "right")}</text>
45
- </box>
46
- </box>
37
+ <Box flexDirection="row" height={1}>
38
+ <Box width={labelWidth + 1}>
39
+ <Text fg={colors.textDim}>{padTo("TARGET", labelWidth)}</Text>
40
+ </Box>
41
+ <Box width={8}>
42
+ <Text fg={colors.textDim}>{padTo("ODDS", 7, "right")}</Text>
43
+ </Box>
44
+ <Box width={13}>
45
+ <Text fg={colors.textDim}>{padTo("24H VOL", 12, "right")}</Text>
46
+ </Box>
47
+ </Box>
47
48
 
48
49
  {sortedOutcomes.map((market, index) => {
49
50
  const selected = market.key === selectedMarketKey;
50
51
  return (
51
- <box
52
+ <Box
52
53
  key={market.key}
53
54
  flexDirection="row"
54
55
  height={1}
@@ -58,16 +59,16 @@ export function PredictionMarketOutcomesView({
58
59
  onSelectMarket(market.key);
59
60
  }}
60
61
  >
61
- <box width={labelWidth + 1}>
62
- <text
62
+ <Box width={labelWidth + 1}>
63
+ <Text
63
64
  fg={selected ? colors.selectedText : colors.text}
64
65
  attributes={selected ? TextAttributes.BOLD : 0}
65
66
  >
66
67
  {padTo(market.marketLabel, labelWidth)}
67
- </text>
68
- </box>
69
- <box width={8}>
70
- <text
68
+ </Text>
69
+ </Box>
70
+ <Box width={8}>
71
+ <Text
71
72
  fg={
72
73
  selected
73
74
  ? colors.selectedText
@@ -76,10 +77,10 @@ export function PredictionMarketOutcomesView({
76
77
  }
77
78
  >
78
79
  {padTo(formatPredictionPercent(market.yesPrice), 7, "right")}
79
- </text>
80
- </box>
81
- <box width={13}>
82
- <text fg={selected ? colors.selectedText : colors.textDim}>
80
+ </Text>
81
+ </Box>
82
+ <Box width={13}>
83
+ <Text fg={selected ? colors.selectedText : colors.textDim}>
83
84
  {padTo(
84
85
  formatPredictionMetric(
85
86
  market.volume24h,
@@ -88,11 +89,11 @@ export function PredictionMarketOutcomesView({
88
89
  12,
89
90
  "right",
90
91
  )}
91
- </text>
92
- </box>
93
- </box>
92
+ </Text>
93
+ </Box>
94
+ </Box>
94
95
  );
95
96
  })}
96
- </box>
97
+ </Box>
97
98
  );
98
99
  }
@@ -1,4 +1,5 @@
1
- import { TextAttributes } from "@opentui/core";
1
+ import { Box, Text } from "../../../ui";
2
+ import { TextAttributes } from "../../../ui";
2
3
  import { colors } from "../../../theme/colors";
3
4
  import { formatPercentRaw } from "../../../utils/format";
4
5
  import { PredictionMarketChart } from "../chart";
@@ -30,8 +31,10 @@ export function PredictionMarketOverviewView({
30
31
  selectedRow: PredictionListRow | null;
31
32
  summary: PredictionMarketSummary;
32
33
  }) {
34
+ const textWidth = Math.max(detailWidth, 12);
35
+
33
36
  return (
34
- <box flexDirection="column" gap={1}>
37
+ <Box flexDirection="column" gap={1}>
35
38
  {selectedRow?.kind === "group" && (
36
39
  <PredictionMarketOutcomesView
37
40
  detailWidth={detailWidth}
@@ -52,22 +55,24 @@ export function PredictionMarketOverviewView({
52
55
  maxLength={Math.max(detailWidth - 8, 12)}
53
56
  />
54
57
  {summary.description && (
55
- <box flexDirection="column">
56
- <text fg={colors.textBright} attributes={TextAttributes.BOLD}>
58
+ <Box flexDirection="column" width={textWidth}>
59
+ <Text fg={colors.textBright} attributes={TextAttributes.BOLD}>
57
60
  Description
58
- </text>
59
- <text fg={colors.text}>{summary.description}</text>
60
- </box>
61
+ </Text>
62
+ <Text fg={colors.text} width={textWidth} wrapMode="word" wrapText>
63
+ {summary.description}
64
+ </Text>
65
+ </Box>
61
66
  )}
62
- <box height={1}>
63
- <text fg={colors.textDim}>
67
+ <Box height={1}>
68
+ <Text fg={colors.textDim}>
64
69
  {detail?.history &&
65
70
  detail.history.length > 1 &&
66
71
  summary.yesPrice != null
67
72
  ? `Range move ${formatPercentRaw((((detail.history[detail.history.length - 1]?.close ?? summary.yesPrice) - (detail.history[0]?.close ?? summary.yesPrice)) / Math.max(detail.history[0]?.close ?? summary.yesPrice, 0.0001)) * 100)}`
68
73
  : "No extended move data."}
69
- </text>
70
- </box>
71
- </box>
74
+ </Text>
75
+ </Box>
76
+ </Box>
72
77
  );
73
78
  }