gloomberb 0.11.2 → 0.12.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 (531) hide show
  1. package/README.md +7 -4
  2. package/README.zh-CN.md +4 -2
  3. package/package.json +28 -1
  4. package/src/api-client/auth.ts +10 -0
  5. package/src/api-client/data.ts +108 -1
  6. package/src/api-client/index.test.ts +127 -0
  7. package/src/api-client/index.ts +134 -1
  8. package/src/api-client/normalizers.ts +39 -0
  9. package/src/api-client/paths.ts +85 -1
  10. package/src/api-client/types.ts +220 -0
  11. package/src/app/pane-runtime/index.tsx +15 -12
  12. package/src/app/pane-runtime/layout-placement.test.ts +27 -0
  13. package/src/app/pane-runtime/layout-placement.ts +13 -0
  14. package/src/app/pane-runtime/plugin-bindings.ts +62 -0
  15. package/src/app.tsx +60 -18
  16. package/src/architecture/browser-entry-graph.test.ts +96 -0
  17. package/src/brokers/profile-form.test.ts +25 -27
  18. package/src/brokers/test-broker.ts +68 -0
  19. package/src/capabilities/chart-series.ts +3 -2
  20. package/src/cli/commands/market.ts +2 -2
  21. package/src/cli/commands/plugins.ts +39 -11
  22. package/src/cli/desktop-pane-shot.ts +285 -16
  23. package/src/cli/index.ts +1 -1
  24. package/src/cli/pane-functions/capabilities.ts +61 -31
  25. package/src/cli/pane-functions/catalog.ts +16 -4
  26. package/src/cli/pane-functions/discovery.ts +1 -0
  27. package/src/cli/pane-functions/headless.test.ts +247 -0
  28. package/src/cli/pane-functions/headless.ts +423 -0
  29. package/src/cli/pane-functions/index.test.ts +9 -0
  30. package/src/cli/pane-functions/index.ts +6 -2
  31. package/src/cli/pane-functions/options.ts +27 -2
  32. package/src/cli/pane-functions/report.ts +4 -0
  33. package/src/cli/pane-functions/resolver.ts +26 -8
  34. package/src/cli/pane-functions/screenshot.test.ts +76 -0
  35. package/src/cli/pane-functions/screenshot.ts +236 -20
  36. package/src/cli/registry.ts +0 -22
  37. package/src/cli/restore-plugins.ts +34 -0
  38. package/src/cli/result.ts +7 -10
  39. package/src/components/chart/{static/chart → composite}/axis-overlays.test.tsx +3 -3
  40. package/src/components/chart/{static/chart → composite}/axis-overlays.tsx +6 -11
  41. package/src/components/chart/{static/chart → composite}/bitmap.ts +17 -3
  42. package/src/components/chart/composite/composite-chart.test.tsx +68 -20
  43. package/src/components/chart/composite/composite-chart.tsx +301 -204
  44. package/src/components/chart/composite/format.ts +8 -2
  45. package/src/components/chart/composite/interactions.test.ts +68 -102
  46. package/src/components/chart/composite/interactions.ts +214 -264
  47. package/src/components/chart/composite/price-axis-labels.test.ts +21 -0
  48. package/src/components/chart/{price-axis-labels.tsx → composite/price-axis-labels.tsx} +9 -4
  49. package/src/components/chart/composite/scene.ts +57 -3
  50. package/src/components/chart/composite/text-renderer.ts +3 -2
  51. package/src/components/chart/composite/time-scale.ts +138 -57
  52. package/src/components/chart/composite/types.ts +25 -1
  53. package/src/components/chart/core/data.ts +9 -13
  54. package/src/components/chart/core/date-window.ts +7 -1
  55. package/src/components/chart/core/pointer.ts +3 -0
  56. package/src/components/chart/core/types.ts +0 -45
  57. package/src/components/chart/native/chart-rasterizer.ts +0 -1
  58. package/src/components/chart/native/kitty/index.test.ts +0 -188
  59. package/src/components/chart/native/raster/crosshair.ts +6 -5
  60. package/src/components/chart/native/raster/primitives.ts +0 -23
  61. package/src/components/chart/native/renderer-selection.ts +81 -31
  62. package/src/components/chart/static/{chart/surface.test.tsx → chart-surface.test.tsx} +28 -80
  63. package/src/components/chart/static/chart-surface.tsx +150 -0
  64. package/src/components/chart/static/index.ts +8 -0
  65. package/src/components/chart/static/multi-line-chart-surface.tsx +51 -166
  66. package/src/components/chart/static/scatter-chart-surface.test.ts +30 -0
  67. package/src/components/chart/static/scatter-chart-surface.tsx +135 -34
  68. package/src/components/chart/static/series.ts +49 -0
  69. package/src/components/command-bar/action-runtime.ts +1 -3
  70. package/src/components/command-bar/assist/model.test.ts +17 -2
  71. package/src/components/command-bar/assist/model.ts +40 -9
  72. package/src/components/command-bar/commands/direct/index.ts +1 -1
  73. package/src/components/command-bar/commands/direct/runtime.ts +1 -1
  74. package/src/components/command-bar/commands/registry.ts +0 -11
  75. package/src/components/command-bar/helpers.test.ts +2 -2
  76. package/src/components/command-bar/helpers.ts +2 -6
  77. package/src/components/command-bar/keyboard-shortcuts.ts +0 -11
  78. package/src/components/command-bar/list/badge.test.ts +54 -0
  79. package/src/components/command-bar/list/badge.ts +62 -0
  80. package/src/components/command-bar/list/model.test.ts +103 -0
  81. package/src/components/command-bar/list/model.ts +61 -4
  82. package/src/components/command-bar/list/view.test.tsx +113 -0
  83. package/src/components/command-bar/list/view.tsx +147 -131
  84. package/src/components/command-bar/pane-templates/workflow.ts +1 -1
  85. package/src/components/command-bar/panel/body.tsx +51 -65
  86. package/src/components/command-bar/panel/index.tsx +48 -13
  87. package/src/components/command-bar/panel/layout.test.ts +139 -0
  88. package/src/components/command-bar/panel/layout.ts +65 -28
  89. package/src/components/command-bar/panel/native-surface.ts +24 -0
  90. package/src/components/command-bar/panel/prompt-binding.ts +54 -0
  91. package/src/components/command-bar/panel/runtime.ts +6 -3
  92. package/src/components/command-bar/panel/state.ts +41 -7
  93. package/src/components/command-bar/panel/types.ts +7 -1
  94. package/src/components/command-bar/routes/root/provider-search.ts +34 -15
  95. package/src/components/command-bar/routes/root/results.test.ts +161 -0
  96. package/src/components/command-bar/routes/root/results.ts +30 -28
  97. package/src/components/command-bar/routes/root/runtime.ts +37 -20
  98. package/src/components/command-bar/routes/root/search-providers.test.tsx +224 -0
  99. package/src/components/command-bar/routes/root/search-providers.ts +205 -0
  100. package/src/components/command-bar/routes/root/selection.ts +1 -12
  101. package/src/components/command-bar/routes/root/shortcuts.test.ts +8 -8
  102. package/src/components/command-bar/routes/ticker-search/actions.ts +10 -9
  103. package/src/components/command-bar/routes/ticker-search/results.test.ts +54 -1
  104. package/src/components/command-bar/routes/ticker-search/results.ts +60 -19
  105. package/src/components/command-bar/routes/ticker-search/route.ts +1 -0
  106. package/src/components/command-bar/routing/actions.ts +1 -81
  107. package/src/components/command-bar/routing/launch-request.ts +1 -1
  108. package/src/components/command-bar/routing/list-state.ts +6 -21
  109. package/src/components/command-bar/selection-runtime.ts +1 -1
  110. package/src/components/command-bar/surface/assist.test.tsx +14 -10
  111. package/src/components/command-bar/surface/environment.ts +8 -1
  112. package/src/components/command-bar/surface/index.test.tsx +84 -68
  113. package/src/components/command-bar/surface/index.tsx +33 -36
  114. package/src/components/command-bar/surface/test-harness.tsx +15 -3
  115. package/src/components/command-bar/theme-picker.tsx +43 -15
  116. package/src/components/command-bar/view-model.test.ts +53 -8
  117. package/src/components/command-bar/view-model.ts +43 -14
  118. package/src/components/command-bar/workflow/tickers.ts +1 -0
  119. package/src/components/command-bar/workflow/types.ts +1 -1
  120. package/src/components/data-table/export.test.ts +21 -0
  121. package/src/components/data-table/export.ts +21 -0
  122. package/src/components/data-table/view.test.tsx +45 -6
  123. package/src/components/data-table/view.tsx +55 -9
  124. package/src/components/index.ts +10 -2
  125. package/src/components/input-search-bar.test.tsx +36 -2
  126. package/src/components/input-search-bar.tsx +18 -1
  127. package/src/components/layout/header.test.tsx +57 -10
  128. package/src/components/layout/header.tsx +292 -149
  129. package/src/components/layout/market-summary.test.ts +81 -0
  130. package/src/components/layout/market-summary.ts +109 -0
  131. package/src/components/layout/shell/chrome.ts +96 -1
  132. package/src/components/layout/shell/index.tsx +11 -3
  133. package/src/components/layout/shell/menu.ts +9 -0
  134. package/src/components/layout/shell/pane/actions.ts +29 -0
  135. package/src/components/layout/shell/pane/management-shortcuts.ts +5 -0
  136. package/src/components/layout/shell/shortcuts.ts +3 -0
  137. package/src/components/layout/status-bar.test.tsx +9 -8
  138. package/src/components/layout/status-bar.tsx +85 -54
  139. package/src/components/onboarding/onboarding-frame.tsx +2 -26
  140. package/src/components/price-sparkline/index.ts +61 -34
  141. package/src/components/price-sparkline/view.tsx +1 -1
  142. package/src/components/sign-in-gate.test.tsx +128 -0
  143. package/src/components/sign-in-gate.tsx +149 -0
  144. package/src/components/speedometer-gauge/desktop.tsx +2 -12
  145. package/src/components/ticker/badge/list.tsx +17 -3
  146. package/src/components/ticker/list-table-view.tsx +6 -3
  147. package/src/components/ui/data-table/index.tsx +22 -4
  148. package/src/components/ui/data-table/opentui/index.tsx +165 -120
  149. package/src/components/ui/frame.tsx +28 -0
  150. package/src/components/ui/index.ts +3 -0
  151. package/src/components/ui/native-select.tsx +20 -10
  152. package/src/components/ui/select-button.tsx +138 -0
  153. package/src/components/ui/status.tsx +2 -2
  154. package/src/components/ui/table-layout.ts +1 -1
  155. package/src/components/use-double-click-activation.ts +7 -3
  156. package/src/core/app-services.ts +3 -3
  157. package/src/data/config/chart-settings.ts +4 -4
  158. package/src/data/config/layout.ts +12 -6
  159. package/src/data/config/store/index.test.ts +97 -0
  160. package/src/data/config/store/migrations.ts +41 -0
  161. package/src/data/config/store/normalize.ts +5 -3
  162. package/src/i18n/es.ts +6 -2
  163. package/src/i18n/ja.ts +6 -2
  164. package/src/i18n/ko.ts +6 -2
  165. package/src/i18n/zh-cn.ts +6 -2
  166. package/src/i18n/zh-tw.ts +6 -2
  167. package/src/layout-marketplace/gallery-terminal.tsx +126 -96
  168. package/src/layout-marketplace/gallery.test.tsx +65 -1
  169. package/src/layout-marketplace/pane-imagery.ts +1 -0
  170. package/src/layout-marketplace/payload.test.ts +17 -0
  171. package/src/layout-marketplace/payload.ts +40 -5
  172. package/src/market-data/coordinator/index.ts +3 -2
  173. package/src/market-data/coordinator/quotes.ts +173 -66
  174. package/src/market-data/coordinator/subscriptions.test.ts +215 -37
  175. package/src/pane-settings.ts +1 -1
  176. package/src/plugins/builtin/analytics/pane-model.ts +1 -1
  177. package/src/plugins/builtin/analytics/view.tsx +1 -1
  178. package/src/plugins/builtin/broker-manager/index.test.tsx +3 -2
  179. package/src/plugins/builtin/broker-manager/model.test.ts +2 -2
  180. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +16 -2
  181. package/src/plugins/builtin/chart-composer/cli-options.ts +12 -9
  182. package/src/plugins/builtin/chart-composer/pane.tsx +22 -8
  183. package/src/plugins/builtin/chart-composer/settings.ts +2 -13
  184. package/src/plugins/builtin/chat/content/composer.tsx +8 -4
  185. package/src/plugins/builtin/cloud/auth-dialog.tsx +14 -228
  186. package/src/plugins/builtin/cloud/auth-form.tsx +277 -0
  187. package/src/plugins/builtin/cloud/plugin.tsx +1 -0
  188. package/src/plugins/builtin/composite-plugins.ts +16 -1
  189. package/src/plugins/builtin/correlation/relationship/model.ts +1 -1
  190. package/src/plugins/builtin/correlation/relationship/pane.tsx +2 -6
  191. package/src/plugins/builtin/correlation/relationship/view-model.ts +2 -2
  192. package/src/plugins/builtin/credit-conditions/index.test.tsx +12 -6
  193. package/src/plugins/builtin/credit-conditions/index.tsx +2 -21
  194. package/src/plugins/builtin/dividend-yield/index.tsx +1 -0
  195. package/src/plugins/builtin/dividend-yield/pane.tsx +1 -1
  196. package/src/plugins/builtin/earnings/index.tsx +1 -0
  197. package/src/plugins/builtin/earnings-calls/data.ts +223 -0
  198. package/src/plugins/builtin/earnings-calls/format.ts +49 -0
  199. package/src/plugins/builtin/earnings-calls/index.tsx +69 -0
  200. package/src/plugins/builtin/earnings-calls/pane.tsx +756 -0
  201. package/src/plugins/builtin/earnings-calls/prose.test.ts +36 -0
  202. package/src/plugins/builtin/earnings-calls/prose.ts +59 -0
  203. package/src/plugins/builtin/earnings-calls/transcript-view.tsx +334 -0
  204. package/src/plugins/builtin/econ/detail-view.tsx +1 -2
  205. package/src/plugins/builtin/econ/fred-series-map.ts +16 -1
  206. package/src/plugins/builtin/econ/index.tsx +3 -1
  207. package/src/plugins/builtin/econ-statistics/cache.ts +4 -0
  208. package/src/plugins/builtin/econ-statistics/client.ts +92 -0
  209. package/src/plugins/builtin/econ-statistics/defs.ts +66 -0
  210. package/src/plugins/builtin/econ-statistics/detail.tsx +154 -0
  211. package/src/plugins/builtin/econ-statistics/headless.test.ts +54 -0
  212. package/src/plugins/builtin/econ-statistics/headless.ts +171 -0
  213. package/src/plugins/builtin/econ-statistics/index.tsx +54 -0
  214. package/src/plugins/builtin/econ-statistics/pane.tsx +356 -0
  215. package/src/plugins/builtin/econ-statistics/stats.ts +522 -0
  216. package/src/plugins/builtin/econ-statistics/transform.test.ts +86 -0
  217. package/src/plugins/builtin/econ-statistics/transform.ts +85 -0
  218. package/src/plugins/builtin/econ-statistics/trend.ts +57 -0
  219. package/src/plugins/builtin/econ-statistics/view.ts +90 -0
  220. package/src/plugins/builtin/fear-greed/charts.tsx +7 -18
  221. package/src/plugins/builtin/fear-greed/data.ts +6 -1
  222. package/src/plugins/builtin/futures/index.tsx +1 -0
  223. package/src/plugins/builtin/fx-matrix/index.tsx +1 -0
  224. package/src/plugins/builtin/help/index.tsx +4 -0
  225. package/src/plugins/builtin/holders/index.tsx +1 -0
  226. package/src/plugins/builtin/insider/index.tsx +1 -0
  227. package/src/plugins/builtin/ipo-calendar/index.tsx +1 -0
  228. package/src/plugins/builtin/kelly-sizer/pane.tsx +1 -1
  229. package/src/plugins/builtin/kelly-sizer/sections.tsx +2 -3
  230. package/src/plugins/builtin/market-halts/index.tsx +1 -0
  231. package/src/plugins/builtin/market-movers/index.tsx +1 -0
  232. package/src/plugins/builtin/market-valuation/align.ts +122 -0
  233. package/src/plugins/builtin/market-valuation/cache.ts +32 -0
  234. package/src/plugins/builtin/market-valuation/chart-projection.ts +217 -0
  235. package/src/plugins/builtin/market-valuation/chart-series.ts +89 -0
  236. package/src/plugins/builtin/market-valuation/client.test.ts +141 -0
  237. package/src/plugins/builtin/market-valuation/client.ts +116 -0
  238. package/src/plugins/builtin/market-valuation/defs.ts +251 -0
  239. package/src/plugins/builtin/market-valuation/detail.tsx +159 -0
  240. package/src/plugins/builtin/market-valuation/headless.test.ts +58 -0
  241. package/src/plugins/builtin/market-valuation/headless.ts +170 -0
  242. package/src/plugins/builtin/market-valuation/index.tsx +64 -0
  243. package/src/plugins/builtin/market-valuation/indicators.ts +422 -0
  244. package/src/plugins/builtin/market-valuation/model.test.ts +350 -0
  245. package/src/plugins/builtin/market-valuation/model.ts +8 -0
  246. package/src/plugins/builtin/market-valuation/pane.test.tsx +247 -0
  247. package/src/plugins/builtin/market-valuation/pane.tsx +344 -0
  248. package/src/plugins/builtin/market-valuation/series.ts +12 -0
  249. package/src/plugins/builtin/market-valuation/settings.ts +38 -0
  250. package/src/plugins/builtin/market-valuation/sources.ts +130 -0
  251. package/src/plugins/builtin/market-valuation/trend.ts +89 -0
  252. package/src/plugins/builtin/market-valuation/view.ts +137 -0
  253. package/src/plugins/builtin/market-valuation/zone-scale/desktop.tsx +123 -0
  254. package/src/plugins/builtin/market-valuation/zone-scale/index.tsx +12 -0
  255. package/src/plugins/builtin/market-valuation/zone-scale/model.ts +60 -0
  256. package/src/plugins/builtin/market-valuation/zone-scale/terminal.tsx +94 -0
  257. package/src/plugins/builtin/news/wire/breaking/filters.test.ts +99 -0
  258. package/src/plugins/builtin/news/wire/breaking/filters.ts +110 -0
  259. package/src/plugins/builtin/news/wire/breaking/notifications.test.ts +157 -53
  260. package/src/plugins/builtin/news/wire/breaking/notifications.ts +91 -25
  261. package/src/plugins/builtin/news/wire/index.tsx +31 -44
  262. package/src/plugins/builtin/options/analytics.test.ts +83 -0
  263. package/src/plugins/builtin/options/analytics.ts +110 -0
  264. package/src/plugins/builtin/options/index.tsx +18 -2
  265. package/src/plugins/builtin/options/table.ts +121 -51
  266. package/src/plugins/builtin/options/types.ts +22 -15
  267. package/src/plugins/builtin/options/view.test.tsx +53 -1
  268. package/src/plugins/builtin/options/view.tsx +92 -41
  269. package/src/plugins/builtin/plugin-marketplace/feed.ts +80 -0
  270. package/src/plugins/builtin/plugin-marketplace/index.tsx +31 -0
  271. package/src/plugins/builtin/plugin-marketplace/model.test.ts +200 -0
  272. package/src/plugins/builtin/plugin-marketplace/model.ts +204 -0
  273. package/src/plugins/builtin/plugin-marketplace/pane.tsx +385 -0
  274. package/src/plugins/builtin/plugin-marketplace/store.ts +46 -0
  275. package/src/plugins/builtin/plugin-module.test.ts +2 -4
  276. package/src/plugins/builtin/plugin-module.ts +9 -8
  277. package/src/plugins/builtin/portfolio-list/index.tsx +1 -0
  278. package/src/plugins/builtin/research/index.tsx +4 -0
  279. package/src/plugins/builtin/research-search/command-bar-search.test.ts +81 -0
  280. package/src/plugins/builtin/research-search/command-bar-search.ts +175 -0
  281. package/src/plugins/builtin/research-search/data.ts +109 -0
  282. package/src/plugins/builtin/research-search/document-view.test.tsx +75 -0
  283. package/src/plugins/builtin/research-search/document-view.tsx +254 -0
  284. package/src/plugins/builtin/research-search/filter-bar.tsx +62 -0
  285. package/src/plugins/builtin/research-search/focus-handoff.ts +47 -0
  286. package/src/plugins/builtin/research-search/index.tsx +85 -0
  287. package/src/plugins/builtin/research-search/model.test.ts +40 -0
  288. package/src/plugins/builtin/research-search/model.ts +291 -0
  289. package/src/plugins/builtin/research-search/pane.test.tsx +241 -0
  290. package/src/plugins/builtin/research-search/pane.tsx +678 -0
  291. package/src/plugins/builtin/research-search/saved-view.tsx +171 -0
  292. package/src/plugins/builtin/research-search/snippet-text.tsx +35 -0
  293. package/src/plugins/builtin/research-search/snippet.test.ts +78 -0
  294. package/src/plugins/builtin/research-search/snippet.ts +134 -0
  295. package/src/plugins/builtin/scanner/flow-model.test.ts +11 -1
  296. package/src/plugins/builtin/scanner/flow-model.ts +29 -1
  297. package/src/plugins/builtin/scanner/flow-pane.tsx +78 -22
  298. package/src/plugins/builtin/scanner/index.ts +2 -0
  299. package/src/plugins/builtin/sec/index.tsx +1 -0
  300. package/src/plugins/builtin/sectors/index.tsx +1 -0
  301. package/src/plugins/builtin/shared/series-cache.ts +93 -0
  302. package/src/plugins/builtin/short-interest/index.tsx +1 -0
  303. package/src/plugins/builtin/short-interest/pane.tsx +1 -1
  304. package/src/plugins/builtin/thirteenf/index.tsx +1 -0
  305. package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +3 -5
  306. package/src/plugins/builtin/ticker-detail/index.tsx +2 -14
  307. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +1 -1
  308. package/src/plugins/builtin/treasury-auctions/index.tsx +1 -0
  309. package/src/plugins/builtin/volatility/index.tsx +1 -1
  310. package/src/plugins/builtin/world-indices/index.tsx +1 -0
  311. package/src/plugins/builtin/world-venue-map/index.ts +27 -0
  312. package/src/plugins/builtin/world-venue-map/map.desktop.test.tsx +106 -0
  313. package/src/plugins/builtin/world-venue-map/map.tsx +481 -0
  314. package/src/plugins/builtin/world-venue-map/model.test.ts +85 -0
  315. package/src/plugins/builtin/world-venue-map/model.ts +268 -0
  316. package/src/plugins/builtin/world-venue-map/pane.tsx +300 -0
  317. package/src/plugins/builtin/world-venue-map/world-outlines.ts +2 -0
  318. package/src/plugins/builtin/yield-curve/index.tsx +1 -1
  319. package/src/plugins/bundle.test.ts +109 -0
  320. package/src/plugins/bundle.ts +139 -0
  321. package/src/plugins/catalog-backend.ts +6 -44
  322. package/src/plugins/catalog-browser.test.ts +1 -0
  323. package/src/plugins/catalog-browser.ts +12 -0
  324. package/src/plugins/catalog-manifest.test.ts +43 -0
  325. package/src/plugins/catalog-manifest.ts +92 -0
  326. package/src/plugins/catalog-ui.ts +20 -4
  327. package/src/plugins/catalog.ts +9 -2
  328. package/src/plugins/current-target.ts +28 -0
  329. package/src/plugins/host-contract.ts +37 -0
  330. package/src/plugins/host-link.ts +158 -0
  331. package/src/plugins/host-modules.ts +61 -0
  332. package/src/plugins/loader.ts +41 -22
  333. package/src/plugins/ownership.ts +1 -0
  334. package/src/plugins/prediction-markets/index.tsx +1 -0
  335. package/src/plugins/registry/context.ts +3 -0
  336. package/src/plugins/registry/contributions.ts +27 -0
  337. package/src/plugins/registry/index.test.ts +25 -0
  338. package/src/plugins/registry/index.ts +8 -0
  339. package/src/plugins/registry/pane-settings.test.ts +53 -0
  340. package/src/plugins/registry/pane-settings.ts +29 -3
  341. package/src/plugins/seed.test.ts +83 -0
  342. package/src/plugins/seed.ts +80 -0
  343. package/src/public/broker.ts +31 -0
  344. package/src/public/market-data.ts +9 -0
  345. package/src/public/pane-hooks.ts +57 -0
  346. package/src/public/public-api.test.ts +285 -0
  347. package/src/public/react.ts +62 -0
  348. package/src/public/test-support.ts +23 -0
  349. package/src/public/time-series.ts +8 -0
  350. package/src/public/utils.ts +77 -0
  351. package/src/remote/layout-helpers.ts +6 -8
  352. package/src/remote/resources.ts +2 -0
  353. package/src/remote/schema.ts +1 -0
  354. package/src/remote/semantic-tree.test.tsx +105 -0
  355. package/src/remote/semantic-tree.tsx +53 -35
  356. package/src/renderers/browser/main.tsx +6 -0
  357. package/src/renderers/browser/ui-host.tsx +11 -0
  358. package/src/renderers/cloudflare/worker.test.ts +19 -0
  359. package/src/renderers/cloudflare/worker.ts +1 -1
  360. package/src/renderers/electrobun/bun/desktop/host-requests.ts +9 -2
  361. package/src/renderers/electrobun/bun/external-plugins.ts +140 -0
  362. package/src/renderers/electrobun/bun/index.ts +6 -2
  363. package/src/renderers/electrobun/shared/protocol.ts +25 -0
  364. package/src/renderers/electrobun/view/build-assets.ts +0 -1
  365. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +51 -1
  366. package/src/renderers/electrobun/view/external-plugins.test.ts +45 -0
  367. package/src/renderers/electrobun/view/external-plugins.ts +63 -0
  368. package/src/renderers/electrobun/view/host/ascii-text.test.ts +48 -0
  369. package/src/renderers/electrobun/view/host/ascii-text.ts +11 -1
  370. package/src/renderers/electrobun/view/host/chart-surface.tsx +38 -32
  371. package/src/renderers/electrobun/view/host/mouse.ts +16 -2
  372. package/src/renderers/electrobun/view/main.tsx +27 -2
  373. package/src/renderers/electrobun/view/styles.css +5 -0
  374. package/src/renderers/electrobun/view/toast-host.tsx +18 -0
  375. package/src/renderers/electrobun/view/ui-host.tsx +3 -0
  376. package/src/renderers/opentui/chart-surface.tsx +5 -1
  377. package/src/renderers/opentui/host.tsx +20 -2
  378. package/src/renderers/opentui/interaction-performance.test.ts +79 -0
  379. package/src/renderers/opentui/interaction-performance.ts +188 -0
  380. package/src/renderers/opentui/start.tsx +26 -1
  381. package/src/renderers/opentui/test-utils.tsx +13 -0
  382. package/src/renderers/opentui/toast-host.tsx +26 -2
  383. package/src/renderers/opentui/ui-host.tsx +1 -0
  384. package/src/sources/provider-router/search.test.ts +191 -0
  385. package/src/sources/provider-router/search.ts +92 -39
  386. package/src/state/app/context/index.tsx +2 -0
  387. package/src/state/app/context/selector.test.tsx +33 -1
  388. package/src/state/hooks/quote-streaming.test.tsx +93 -0
  389. package/src/state/hooks/quote-streaming.ts +106 -30
  390. package/src/state/pane-table-export-registry.ts +50 -0
  391. package/src/theme/color-utils.ts +1 -1
  392. package/src/theme/colors.ts +50 -0
  393. package/src/theme/themes.test.ts +15 -2
  394. package/src/theme/themes.ts +19 -1
  395. package/src/tickers/search/index.test.ts +26 -0
  396. package/src/tickers/search/index.ts +42 -17
  397. package/src/tickers/search/ranking.ts +14 -0
  398. package/src/time-series/chart-data.test.ts +216 -0
  399. package/src/time-series/range.ts +12 -0
  400. package/src/time-series/resolution.test.ts +25 -26
  401. package/src/time-series/resolution.ts +44 -25
  402. package/src/time-series/resolve.ts +7 -0
  403. package/src/time-series/spec.ts +5 -5
  404. package/src/time-series/types.ts +3 -1
  405. package/src/time-series/use-chart-resolution.ts +5 -0
  406. package/src/types/config.ts +123 -3
  407. package/src/types/data-provider.ts +11 -0
  408. package/src/types/headless.ts +161 -0
  409. package/src/types/plugin.ts +104 -20
  410. package/src/ui/host.tsx +19 -1
  411. package/src/ui/index.tsx +1 -0
  412. package/src/ui/toast.tsx +8 -4
  413. package/src/utils/csv.test.ts +13 -0
  414. package/src/utils/csv.ts +37 -0
  415. package/src/utils/format.ts +35 -0
  416. package/src/utils/fuzzy-search.test.ts +94 -0
  417. package/src/utils/fuzzy-search.ts +81 -22
  418. package/src/utils/save-text-file.test.ts +24 -0
  419. package/src/utils/save-text-file.ts +36 -0
  420. package/src/utils/shortcut-labels.ts +14 -0
  421. package/src/components/chart/core/axis-format.ts +0 -157
  422. package/src/components/chart/core/index.test.ts +0 -1075
  423. package/src/components/chart/core/projection.ts +0 -357
  424. package/src/components/chart/core/render-utils.ts +0 -4
  425. package/src/components/chart/core/renderer.ts +0 -244
  426. package/src/components/chart/core/scene.ts +0 -180
  427. package/src/components/chart/core/time-axis.ts +0 -330
  428. package/src/components/chart/cursor-motion.ts +0 -47
  429. package/src/components/chart/indicators/types.ts +0 -26
  430. package/src/components/chart/market-session.ts +0 -176
  431. package/src/components/chart/multi-line/renderer.test.ts +0 -83
  432. package/src/components/chart/multi-line/renderer.ts +0 -161
  433. package/src/components/chart/multi-line/scene.ts +0 -188
  434. package/src/components/chart/native/raster/layout.ts +0 -129
  435. package/src/components/chart/native/raster/price-chart.ts +0 -244
  436. package/src/components/chart/rendering/chart-draw.ts +0 -270
  437. package/src/components/chart/rendering/geometry.ts +0 -95
  438. package/src/components/chart/rendering/pixel-buffer.ts +0 -267
  439. package/src/components/chart/scatter-chart-renderer.test.ts +0 -31
  440. package/src/components/chart/scatter-chart-renderer.ts +0 -223
  441. package/src/components/chart/static/chart/surface.tsx +0 -358
  442. package/src/components/command-bar/routes/root/article-results.test.ts +0 -83
  443. package/src/components/command-bar/routes/root/article-results.ts +0 -55
  444. package/src/plugins/builtin/news/wire/article-search.test.ts +0 -72
  445. package/src/plugins/builtin/news/wire/article-search.ts +0 -140
  446. package/src/plugins/builtin/substack/api/auth.ts +0 -185
  447. package/src/plugins/builtin/substack/api/cache.ts +0 -82
  448. package/src/plugins/builtin/substack/api/loaders.ts +0 -170
  449. package/src/plugins/builtin/substack/api/store.ts +0 -186
  450. package/src/plugins/builtin/substack/api/types.ts +0 -42
  451. package/src/plugins/builtin/substack/api.test.ts +0 -298
  452. package/src/plugins/builtin/substack/article-detail.tsx +0 -397
  453. package/src/plugins/builtin/substack/article-stack.tsx +0 -133
  454. package/src/plugins/builtin/substack/content.ts +0 -478
  455. package/src/plugins/builtin/substack/feed-tabs.tsx +0 -44
  456. package/src/plugins/builtin/substack/index.tsx +0 -49
  457. package/src/plugins/builtin/substack/login-view.tsx +0 -126
  458. package/src/plugins/builtin/substack/model.test.ts +0 -155
  459. package/src/plugins/builtin/substack/normalize.ts +0 -343
  460. package/src/plugins/builtin/substack/pane-footer.ts +0 -52
  461. package/src/plugins/builtin/substack/pane-state.ts +0 -170
  462. package/src/plugins/builtin/substack/pane.tsx +0 -547
  463. package/src/plugins/builtin/substack/read-state.ts +0 -30
  464. package/src/plugins/builtin/substack/table.ts +0 -111
  465. package/src/plugins/builtin/substack/types.ts +0 -71
  466. package/src/plugins/builtin/substack/utils.ts +0 -131
  467. package/src/plugins/builtin/ticker-detail/data-panes/provider-search.tsx +0 -229
  468. package/src/plugins/ibkr/account-cache.test.ts +0 -102
  469. package/src/plugins/ibkr/account-cache.ts +0 -24
  470. package/src/plugins/ibkr/broker-adapter.ts +0 -286
  471. package/src/plugins/ibkr/config.test.ts +0 -79
  472. package/src/plugins/ibkr/config.ts +0 -250
  473. package/src/plugins/ibkr/dialogs.tsx +0 -40
  474. package/src/plugins/ibkr/flex/index.test.ts +0 -264
  475. package/src/plugins/ibkr/flex/index.ts +0 -367
  476. package/src/plugins/ibkr/flex/statement-client.ts +0 -235
  477. package/src/plugins/ibkr/fundamental-parser.ts +0 -149
  478. package/src/plugins/ibkr/gateway/account-loaders.ts +0 -266
  479. package/src/plugins/ibkr/gateway/account-summary.ts +0 -164
  480. package/src/plugins/ibkr/gateway/client-lock.ts +0 -154
  481. package/src/plugins/ibkr/gateway/connection-events.ts +0 -114
  482. package/src/plugins/ibkr/gateway/connection.ts +0 -152
  483. package/src/plugins/ibkr/gateway/contracts.ts +0 -132
  484. package/src/plugins/ibkr/gateway/fundamentals.ts +0 -83
  485. package/src/plugins/ibkr/gateway/helpers.ts +0 -33
  486. package/src/plugins/ibkr/gateway/history-requests.ts +0 -158
  487. package/src/plugins/ibkr/gateway/history.ts +0 -120
  488. package/src/plugins/ibkr/gateway/instrument-lookup.ts +0 -117
  489. package/src/plugins/ibkr/gateway/market-data.ts +0 -345
  490. package/src/plugins/ibkr/gateway/order-execution.ts +0 -218
  491. package/src/plugins/ibkr/gateway/orders.ts +0 -63
  492. package/src/plugins/ibkr/gateway/price-normalization.test.ts +0 -44
  493. package/src/plugins/ibkr/gateway/price-normalization.ts +0 -50
  494. package/src/plugins/ibkr/gateway/quote-stream-controller.ts +0 -203
  495. package/src/plugins/ibkr/gateway/quote-stream.ts +0 -171
  496. package/src/plugins/ibkr/gateway/selection.ts +0 -51
  497. package/src/plugins/ibkr/gateway/service/index.test.ts +0 -675
  498. package/src/plugins/ibkr/gateway/service/index.ts +0 -429
  499. package/src/plugins/ibkr/gateway/service/lifecycle.ts +0 -191
  500. package/src/plugins/ibkr/gateway/service/manager.ts +0 -52
  501. package/src/plugins/ibkr/gateway/service/market-data.ts +0 -48
  502. package/src/plugins/ibkr/gateway/service/native-loader.ts +0 -12
  503. package/src/plugins/ibkr/gateway/service/native.ts +0 -543
  504. package/src/plugins/ibkr/gateway/timeouts.ts +0 -13
  505. package/src/plugins/ibkr/gateway/types.ts +0 -27
  506. package/src/plugins/ibkr/index.test.tsx +0 -162
  507. package/src/plugins/ibkr/index.tsx +0 -159
  508. package/src/plugins/ibkr/instance-selection.test.ts +0 -120
  509. package/src/plugins/ibkr/instance-selection.ts +0 -36
  510. package/src/plugins/ibkr/portfolio-performance.test.ts +0 -32
  511. package/src/plugins/ibkr/portfolio-performance.ts +0 -129
  512. package/src/plugins/ibkr/trade/badge.tsx +0 -28
  513. package/src/plugins/ibkr/trade/dialogs.tsx +0 -44
  514. package/src/plugins/ibkr/trade/preview-panel.tsx +0 -130
  515. package/src/plugins/ibkr/trade/tab/actions.tsx +0 -443
  516. package/src/plugins/ibkr/trade/tab/field-editors.tsx +0 -79
  517. package/src/plugins/ibkr/trade/tab/footer.ts +0 -53
  518. package/src/plugins/ibkr/trade/tab/header.tsx +0 -167
  519. package/src/plugins/ibkr/trade/tab/index.test.tsx +0 -178
  520. package/src/plugins/ibkr/trade/tab/index.tsx +0 -298
  521. package/src/plugins/ibkr/trade/tab/model.ts +0 -159
  522. package/src/plugins/ibkr/trade/tab/order-request.ts +0 -64
  523. package/src/plugins/ibkr/trade/tab/shortcuts.ts +0 -89
  524. package/src/plugins/ibkr/trade/tab/state-sync.ts +0 -86
  525. package/src/plugins/ibkr/trade/ticket-panel.tsx +0 -301
  526. package/src/plugins/ibkr/trade/utils.test.ts +0 -175
  527. package/src/plugins/ibkr/trade/utils.ts +0 -144
  528. package/src/plugins/ibkr/trading/pane-view.tsx +0 -237
  529. package/src/plugins/ibkr/trading/pane.tsx +0 -332
  530. package/src/plugins/ibkr/trading/state.test.ts +0 -109
  531. package/src/plugins/ibkr/trading/state.ts +0 -335
@@ -10,6 +10,8 @@ import {
10
10
  FUTURES_CONTRACTS,
11
11
  FUTURES_SECTOR_LABELS,
12
12
  } from "../futures/contracts";
13
+ import { INDICATORS as VALUATION_INDICATORS } from "../market-valuation/indicators";
14
+ import { MARKET_VALUATION_CAPABILITY_ID } from "../market-valuation/chart-series";
13
15
  import { TREASURY_MATURITIES } from "../yield-curve/treasury-data";
14
16
  import { fieldCategory, type SeriesCatalogInstrument } from "./series-catalog";
15
17
 
@@ -23,7 +25,8 @@ export type CatalogSourceId =
23
25
  | "crypto"
24
26
  | "fred"
25
27
  | "futures"
26
- | "treasury";
28
+ | "treasury"
29
+ | "valuation";
27
30
 
28
31
  export type CatalogFilterId =
29
32
  | "all"
@@ -31,7 +34,8 @@ export type CatalogFilterId =
31
34
  | "options"
32
35
  | "crypto"
33
36
  | "fred"
34
- | "futures";
37
+ | "futures"
38
+ | "valuation";
35
39
 
36
40
  export interface CatalogSeriesRow {
37
41
  id: string;
@@ -53,6 +57,7 @@ export const CATALOG_FILTERS: ReadonlyArray<{ id: CatalogFilterId; label: string
53
57
  { id: "crypto", label: "Crypto" },
54
58
  { id: "fred", label: "FRED" },
55
59
  { id: "futures", label: "Futures" },
60
+ { id: "valuation", label: "Valuation" },
56
61
  ];
57
62
 
58
63
  const FILTER_SOURCES: Record<CatalogFilterId, ReadonlySet<CatalogSourceId> | null> = {
@@ -62,6 +67,7 @@ const FILTER_SOURCES: Record<CatalogFilterId, ReadonlySet<CatalogSourceId> | nul
62
67
  crypto: new Set(["crypto"]),
63
68
  fred: new Set(["fred", "treasury"]),
64
69
  futures: new Set(["futures"]),
70
+ valuation: new Set(["valuation"]),
65
71
  };
66
72
 
67
73
  const CRYPTO_CATALOG: ReadonlyArray<{ symbol: string; name: string }> = [
@@ -321,6 +327,14 @@ const STATIC_CATALOG_INVENTORY: readonly CatalogSeriesRow[] = [
321
327
  expression: `UST:${entry.maturity}`,
322
328
  url: `https://fred.stlouisfed.org/series/${entry.seriesId}`,
323
329
  })),
330
+ ...VALUATION_INDICATORS.map((entry) => row({
331
+ id: `valuation:${entry.id}`,
332
+ label: entry.label,
333
+ source: "Gloom Cloud",
334
+ sourceId: "valuation",
335
+ kind: "Valuation",
336
+ expression: `CAP:${MARKET_VALUATION_CAPABILITY_ID}:${entry.id}`,
337
+ })),
324
338
  ...FUTURES_CONTRACTS.map((entry) => row({
325
339
  id: `fut:${entry.code}`,
326
340
  label: `${entry.name} (${entry.code})`,
@@ -1,4 +1,10 @@
1
1
  import type { NormalizedPaneFunctionOptions } from "../../../cli/pane-functions/capabilities";
2
+ import {
3
+ CHART_RESOLUTIONS,
4
+ TIME_RANGES,
5
+ type ChartResolution,
6
+ type TimeRange,
7
+ } from "../../../time-series/range";
2
8
  import {
3
9
  coerceSeriesTransformForStyle,
4
10
  normalizeChartSpec,
@@ -7,20 +13,17 @@ import type { ChartSeriesSpec, ChartSpec, SeriesPeriod } from "../../../time-ser
7
13
 
8
14
  const PRICE_CAPABILITIES = new Set(["price-chart", "intraday-price-chart", "price-comparison"]);
9
15
 
10
- function chartRange(options: NormalizedPaneFunctionOptions): ChartSpec["viewport"]["range"] | null {
16
+ function chartRange(options: NormalizedPaneFunctionOptions): TimeRange | null {
11
17
  const value = options.rangePreset ?? options.range;
12
- return value === "1D" || value === "1W" || value === "1M" || value === "3M"
13
- || value === "6M" || value === "1Y" || value === "5Y" || value === "ALL"
14
- ? value
18
+ return typeof value === "string" && (TIME_RANGES as readonly string[]).includes(value)
19
+ ? value as TimeRange
15
20
  : null;
16
21
  }
17
22
 
18
- function chartResolution(options: NormalizedPaneFunctionOptions): ChartSpec["viewport"]["resolution"] | null {
23
+ function chartResolution(options: NormalizedPaneFunctionOptions): ChartResolution | null {
19
24
  const value = options.chartResolution ?? options.resolution;
20
- return value === "auto" || value === "1m" || value === "5m" || value === "15m"
21
- || value === "30m" || value === "45m" || value === "1h" || value === "1d"
22
- || value === "1wk" || value === "1mo"
23
- ? value
25
+ return typeof value === "string" && (CHART_RESOLUTIONS as readonly string[]).includes(value)
26
+ ? value as ChartResolution
24
27
  : null;
25
28
  }
26
29
 
@@ -14,7 +14,10 @@ import { CompositeChart } from "../../../components/chart/composite";
14
14
  import type { PaneProps, TickerResearchTabProps } from "../../../types/plugin";
15
15
  import type { ChartResolution, TimeRange } from "../../../components/chart/core/types";
16
16
  import type { ChartSpec, ResolvedSeries } from "../../../time-series/types";
17
- import { getSupportedChartResolutionsForViewport } from "../../../time-series/resolution";
17
+ import {
18
+ getSupportedChartResolutionsForViewport,
19
+ type ManualChartResolution,
20
+ } from "../../../time-series/resolution";
18
21
  import { useResolvedChartSpec } from "../../../time-series/hooks";
19
22
  import { chartSeriesSourceKey } from "../../../capabilities";
20
23
  import { useShortcut } from "../../../react/input";
@@ -68,6 +71,9 @@ import { isPlainKey } from "../../../utils/keyboard";
68
71
 
69
72
  const RANGE_TABS = RANGES.map((range, index) => ({ label: `${index + 1}:${range}`, value: range }));
70
73
  const AUTO_VIEWPORT_DEBOUNCE_MS = 350;
74
+ /** Bar pitch AUTO aims for; the coarser neighbour wins ties so bars stay readable. */
75
+ const AUTO_RESOLUTION_BAR_PIXELS = 7;
76
+ const MINIMUM_AUTO_RESOLUTION_POINTS = 60;
71
77
 
72
78
  interface RuntimeChartViewport {
73
79
  start: Date;
@@ -137,7 +143,7 @@ function ChartComposerSurface({
137
143
  const dialog = useDialog();
138
144
  const dispatch = useAppDispatch();
139
145
  const isDesktopWeb = useUiHost().kind === "desktop-web";
140
- const { publicSharing } = useUiCapabilities();
146
+ const { publicSharing, cellWidthPx = 8 } = useUiCapabilities();
141
147
  const paneId = usePaneInstanceId();
142
148
  const liveStreaming = useLiveStreamingSetting();
143
149
  const dialogOpen = useDialogState((state) => state.isOpen);
@@ -179,15 +185,24 @@ function ChartComposerSurface({
179
185
  const activeRuntimeViewport = runtimeViewportState?.key === authoredViewportKey
180
186
  ? runtimeViewportState
181
187
  : null;
182
- const targetPointCount = Math.max(60, Math.floor(width * 1.25));
188
+ const targetPointCount = Math.max(
189
+ MINIMUM_AUTO_RESOLUTION_POINTS,
190
+ Math.round((width * cellWidthPx) / AUTO_RESOLUTION_BAR_PIXELS),
191
+ );
192
+ // The loaded resolution is the tie-breaker for the next AUTO pick, so a
193
+ // small zoom keeps the bars it already has. Read from the previous render:
194
+ // the resolver only consults it when the viewport moves.
195
+ const currentResolutionRef = useRef<ManualChartResolution | null>(null);
183
196
  const resolution = useResolvedChartSpec(spec, {
184
197
  autoViewport: spec.viewport.resolution === "auto"
185
198
  ? activeRuntimeViewport?.adaptiveViewport
186
199
  : null,
187
200
  requestViewport: activeRuntimeViewport?.requestViewport,
188
201
  targetPointCount,
202
+ currentResolution: currentResolutionRef.current,
189
203
  liveStreaming: liveStreaming && (liveWhenUnfocused || focused),
190
204
  });
205
+ currentResolutionRef.current = resolution.resolution ?? currentResolutionRef.current;
191
206
  const availableResolutions = useMemo<ChartResolution[]>(() => {
192
207
  if (!resolution.resolutionSupport) {
193
208
  if (!resolution.loading) return RESOLUTIONS;
@@ -320,9 +335,8 @@ function ChartComposerSurface({
320
335
  }, [authoredViewportKey, persistedInteractionViewport, setStoredInteractionViewport]);
321
336
  const handleChartViewportChange = useCallback((
322
337
  next: { start: Date; end: Date } | null,
323
- interaction: "pan" | "reset" | "sync" | "zoom",
338
+ _interaction: "pan" | "reset" | "zoom",
324
339
  ) => {
325
- if (interaction === "sync") return;
326
340
  if (runtimeViewportTimerRef.current !== null) {
327
341
  clearTimeout(runtimeViewportTimerRef.current);
328
342
  runtimeViewportTimerRef.current = null;
@@ -339,9 +353,9 @@ function ChartComposerSurface({
339
353
  if (!Number.isFinite(start) || !Number.isFinite(end) || start > end) return;
340
354
  const viewport = { start: new Date(start), end: new Date(end) };
341
355
  requestViewportRef.current = viewport;
342
- if (interaction === "zoom" && spec.viewport.resolution === "auto") {
343
- adaptiveViewportRef.current = viewport;
344
- }
356
+ // A pan can leave the window a provider serves at the current resolution
357
+ // just as a zoom can, so both re-pick.
358
+ if (spec.viewport.resolution === "auto") adaptiveViewportRef.current = viewport;
345
359
  runtimeViewportTimerRef.current = globalThis.setTimeout(() => {
346
360
  runtimeViewportTimerRef.current = null;
347
361
  const requestViewport = requestViewportRef.current;
@@ -1,4 +1,5 @@
1
1
  import type { ChartResolution, TimeRange } from "../../../components/chart/core/types";
2
+ import { CHART_RESOLUTIONS, TIME_RANGES as CHART_RANGES } from "../../../time-series/range";
2
3
  import type {
3
4
  PaneSettingField,
4
5
  PaneSettingOption,
@@ -33,19 +34,7 @@ import {
33
34
  parseChartSpecOr,
34
35
  } from "./chart-spec";
35
36
 
36
- export const CHART_RANGES: TimeRange[] = ["1D", "1W", "1M", "3M", "6M", "1Y", "5Y", "ALL"];
37
- export const CHART_RESOLUTIONS: ChartResolution[] = [
38
- "auto",
39
- "1m",
40
- "5m",
41
- "15m",
42
- "30m",
43
- "45m",
44
- "1h",
45
- "1d",
46
- "1wk",
47
- "1mo",
48
- ];
37
+ export { CHART_RANGES, CHART_RESOLUTIONS };
49
38
 
50
39
  export const CHART_STUDY_OPTIONS: Array<PaneSettingOption & { value: BuiltinStudySelection }> = [
51
40
  { value: "volume", label: "Volume", description: "Volume columns in a lower panel." },
@@ -1,7 +1,7 @@
1
- import { Box, Text, TextAttributes, type TextareaRenderable } from "../../../../ui";
1
+ import { Box, Text, TextAttributes, useCommandBarShortcut, type TextareaRenderable } from "../../../../ui";
2
2
  import { getMessageComposerBlockHeight, MessageComposer } from "../../../../components/ui";
3
3
  import { colors } from "../../../../theme/colors";
4
- import { t } from "../../../../i18n";
4
+ import { t, tf } from "../../../../i18n";
5
5
  import { truncateToDisplayWidth } from "../../../../utils/format";
6
6
  import type { ChatMessage } from "../../../../api-client";
7
7
  import { InlineAuthActions } from "../../cloud/auth-actions";
@@ -130,8 +130,10 @@ export function ChatComposerArea({
130
130
  onMentionSelect,
131
131
  user,
132
132
  }: ChatComposerAreaProps) {
133
+ const commandBarShortcut = useCommandBarShortcut();
133
134
  if (!canSend) {
134
- const fitLine = (value: string) => truncateToDisplayWidth(t(value), contentWidth);
135
+ const fitText = (value: string) => truncateToDisplayWidth(value, contentWidth);
136
+ const fitLine = (value: string) => fitText(t(value));
135
137
  return (
136
138
  <Box width={contentWidth} height={2} flexDirection="column">
137
139
  {!user && !hasSavedSession ? (
@@ -147,7 +149,9 @@ export function ChatComposerArea({
147
149
  ) : (
148
150
  <>
149
151
  <Text fg={colors.positive}>{fitLine("Verify your email to send messages.")}</Text>
150
- <Text fg={colors.textDim}>{fitLine("Ctrl+P, then Resend Verification Email")}</Text>
152
+ <Text fg={colors.textDim}>
153
+ {fitText(tf("{shortcut}, then Resend Verification Email", { shortcut: commandBarShortcut }))}
154
+ </Text>
151
155
  </>
152
156
  )}
153
157
  </Box>
@@ -2,34 +2,16 @@
2
2
  * Shared email/password auth dialog plus the request bridge that lets commands
3
3
  * (which run outside the React tree) open it. `AuthDialogHost` is mounted by
4
4
  * the shell for the life of the app and owns the actual dialog, mirroring the
5
- * QR sign-in dialog host.
5
+ * QR sign-in dialog host. The form body itself lives in `auth-form`, which the
6
+ * hosted terminal's sign-in gate reuses.
6
7
  */
7
- import { useCallback, useState } from "react";
8
- import { apiClient, type AuthUser } from "../../../api-client";
9
- import { Button, Spinner, TextField } from "../../../components";
8
+ import { useEffect, useRef, useState } from "react";
9
+ import type { AuthUser } from "../../../api-client";
10
10
  import { DialogFrame } from "../../../components/ui/frame";
11
- import { t, tf } from "../../../i18n";
12
11
  import { useAppLanguage } from "../../../i18n/react";
13
- import { colors } from "../../../theme/colors";
14
- import { Box, Text, TextAttributes } from "../../../ui";
15
- import { useDialog, useDialogKeyboard, type PromptContext } from "../../../ui/dialog";
16
- import { isPlainKey } from "../../../utils/keyboard";
17
- import { useEffect, useRef } from "react";
18
- import {
19
- advanceAccountField,
20
- classifyAccountError,
21
- performEmailAuth,
22
- validateAccountEmail,
23
- validateAccountPassword,
24
- type AccountMode,
25
- type AccountSubmitError,
26
- } from "./auth-model";
27
-
28
- const FIELD_WIDTH = 42;
29
-
30
- type AuthField = "email" | "password";
31
-
32
- type ResetState = "idle" | "sending" | "sent";
12
+ import { useDialog, type PromptContext } from "../../../ui/dialog";
13
+ import { AuthForm, authFormTitle } from "./auth-form";
14
+ import type { AccountMode } from "./auth-model";
33
15
 
34
16
  export function AuthDialog({
35
17
  initialMode,
@@ -38,211 +20,15 @@ export function AuthDialog({
38
20
  }: PromptContext<AuthUser | undefined> & { initialMode: AccountMode }) {
39
21
  useAppLanguage();
40
22
  const [mode, setMode] = useState<AccountMode>(initialMode);
41
- const [email, setEmail] = useState("");
42
- const [password, setPassword] = useState("");
43
- const [activeField, setActiveField] = useState<AuthField>("email");
44
- const [showPassword, setShowPassword] = useState(false);
45
- const [submitting, setSubmitting] = useState(false);
46
- const [validationError, setValidationError] = useState<string | null>(null);
47
- const [submitError, setSubmitError] = useState<AccountSubmitError | null>(null);
48
- const [resetState, setResetState] = useState<ResetState>("idle");
49
- const attemptRef = useRef(0);
50
-
51
- const clearErrors = useCallback(() => {
52
- setValidationError(null);
53
- setSubmitError(null);
54
- }, []);
55
-
56
- useEffect(() => () => {
57
- // Unmounting abandons any in-flight attempt so a late response can't set state.
58
- attemptRef.current += 1;
59
- }, []);
60
-
61
- const switchMode = useCallback((nextMode: AccountMode) => {
62
- attemptRef.current += 1;
63
- setMode(nextMode);
64
- setSubmitting(false);
65
- setPassword("");
66
- setResetState("idle");
67
- clearErrors();
68
- setActiveField(email.trim() ? "password" : "email");
69
- }, [clearErrors, email]);
70
-
71
- const requestReset = useCallback(() => {
72
- if (submitting || resetState === "sending") return;
73
- const trimmedEmail = email.trim();
74
- const emailError = validateAccountEmail(trimmedEmail);
75
- if (emailError) {
76
- setActiveField("email");
77
- setValidationError(emailError);
78
- return;
79
- }
80
- setResetState("sending");
81
- clearErrors();
82
- void apiClient.requestPasswordReset(trimmedEmail)
83
- .then(() => setResetState("sent"))
84
- .catch(() => {
85
- setResetState("idle");
86
- setSubmitError({ message: t("Could not send the reset email."), kind: "retry" });
87
- });
88
- }, [clearErrors, email, resetState, submitting]);
89
-
90
- const submit = useCallback(() => {
91
- if (submitting) return;
92
- const trimmedEmail = email.trim();
93
- const emailError = validateAccountEmail(trimmedEmail);
94
- if (emailError) {
95
- setActiveField("email");
96
- setValidationError(emailError);
97
- return;
98
- }
99
- const passwordError = validateAccountPassword(password, mode);
100
- if (passwordError) {
101
- setActiveField("password");
102
- setValidationError(passwordError);
103
- return;
104
- }
105
-
106
- const attemptId = attemptRef.current + 1;
107
- attemptRef.current = attemptId;
108
- setSubmitting(true);
109
- clearErrors();
110
- void (async () => {
111
- try {
112
- const user = await performEmailAuth(mode, trimmedEmail, password);
113
- if (attemptRef.current !== attemptId) return;
114
- resolve(user);
115
- } catch (error) {
116
- if (attemptRef.current !== attemptId) return;
117
- setSubmitting(false);
118
- setSubmitError(classifyAccountError(error, mode));
119
- }
120
- })();
121
- }, [clearErrors, email, mode, password, resolve, submitting]);
122
-
123
- const submitField = useCallback(() => {
124
- const advance = advanceAccountField({
125
- mode,
126
- email: email.trim(),
127
- password,
128
- fieldIdx: activeField === "email" ? 0 : 1,
129
- });
130
- if (advance.action === "invalid") {
131
- setValidationError(advance.message);
132
- return;
133
- }
134
- if (advance.action === "next-field") {
135
- setValidationError(null);
136
- setActiveField("password");
137
- return;
138
- }
139
- submit();
140
- }, [activeField, email, mode, password, submit]);
141
-
142
- useDialogKeyboard((event) => {
143
- if (event.name === "escape") {
144
- event.stopPropagation?.();
145
- dismiss();
146
- return;
147
- }
148
- const forward = isPlainKey(event, "tab") || (!event.targetEditable && isPlainKey(event, "down", "j"));
149
- const backward = !event.targetEditable && isPlainKey(event, "up", "k");
150
- if (forward || backward) {
151
- event.preventDefault?.();
152
- event.stopPropagation?.();
153
- setActiveField(forward ? "password" : "email");
154
- }
155
- }, { allowEditable: true });
156
-
157
- const switchToLogin = submitError?.kind === "switch-to-login";
158
- const error = validationError ?? submitError?.message ?? null;
159
23
 
160
24
  return (
161
- <DialogFrame title={mode === "login" ? t("Log in to Gloom Cloud") : t("Create your free Gloom Cloud account")}>
162
- <Box flexDirection="column" gap={1}>
163
- <TextField
164
- label={t("Email")}
165
- value={email}
166
- placeholder="email@example.com"
167
- focused={activeField === "email" && !submitting}
168
- width={FIELD_WIDTH}
169
- type="email"
170
- autoComplete="email"
171
- onMouseDown={() => setActiveField("email")}
172
- onChange={(value) => {
173
- setEmail(value);
174
- setResetState("idle");
175
- clearErrors();
176
- }}
177
- onSubmit={submitField}
178
- />
179
- <Box flexDirection="column">
180
- <Box height={1} width={FIELD_WIDTH} flexDirection="row" justifyContent="space-between">
181
- <Text
182
- fg={activeField === "password" ? colors.textBright : colors.textDim}
183
- attributes={activeField === "password" ? TextAttributes.BOLD : 0}
184
- >
185
- {t("Password")}
186
- </Text>
187
- <Box onMouseDown={() => setShowPassword((current) => !current)}>
188
- <Text fg={colors.textMuted}>{showPassword ? t("hide") : t("show")}</Text>
189
- </Box>
190
- </Box>
191
- <TextField
192
- value={password}
193
- placeholder={mode === "signup" ? t("At least 8 characters") : t("Your password")}
194
- focused={activeField === "password" && !submitting}
195
- width={FIELD_WIDTH}
196
- type={showPassword ? "text" : "password"}
197
- autoComplete={mode === "signup" ? "new-password" : "current-password"}
198
- onMouseDown={() => setActiveField("password")}
199
- onChange={(value) => {
200
- setPassword(value);
201
- clearErrors();
202
- }}
203
- onSubmit={submitField}
204
- />
205
- </Box>
206
- <Box flexDirection="column" minHeight={2} width={FIELD_WIDTH}>
207
- {submitting ? (
208
- <Spinner label={mode === "signup" ? t("Creating your account...") : t("Signing you in...")} />
209
- ) : resetState === "sending" ? (
210
- <Spinner label={t("Sending reset link...")} />
211
- ) : error ? (
212
- <Text fg={colors.negative} wrapText>{error}</Text>
213
- ) : resetState === "sent" ? (
214
- <Text fg={colors.positive} wrapText>
215
- {tf("Reset link sent to {email}. Check your inbox.", { email: email.trim() })}
216
- </Text>
217
- ) : mode === "signup" ? (
218
- <Text fg={colors.textMuted} wrapText>{t("We'll email you a verification link.")}</Text>
219
- ) : null}
220
- </Box>
221
- <Box flexDirection="row" justifyContent="space-between" width={FIELD_WIDTH}>
222
- <Button
223
- label={switchToLogin || mode === "signup" ? t("Log in instead") : t("Sign up instead")}
224
- variant="ghost"
225
- disabled={submitting}
226
- onPress={() => switchMode(mode === "login" ? "signup" : "login")}
227
- />
228
- <Button
229
- label={mode === "login" ? t("Log In") : t("Create Account")}
230
- variant="primary"
231
- disabled={submitting}
232
- onPress={submit}
233
- />
234
- </Box>
235
- {mode === "login" && (
236
- <Box flexDirection="row" width={FIELD_WIDTH}>
237
- <Button
238
- label={t("Forgot password?")}
239
- variant="ghost"
240
- disabled={submitting || resetState === "sending"}
241
- onPress={requestReset}
242
- />
243
- </Box>
244
- )}
245
- </Box>
25
+ <DialogFrame title={authFormTitle(mode)}>
26
+ <AuthForm
27
+ initialMode={initialMode}
28
+ onModeChange={setMode}
29
+ onSignedIn={resolve}
30
+ onEscape={dismiss}
31
+ />
246
32
  </DialogFrame>
247
33
  );
248
34
  }