gloomberb 0.10.0 → 0.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (353) hide show
  1. package/package.json +8 -1
  2. package/src/api-client/auth.ts +1 -0
  3. package/src/api-client/index.test.ts +359 -108
  4. package/src/api-client/index.ts +24 -13
  5. package/src/api-client/socket.ts +70 -35
  6. package/src/api-client/types.ts +1 -1
  7. package/src/app/language-observer.test.tsx +82 -0
  8. package/src/app/language-observer.tsx +13 -0
  9. package/src/app/pane-runtime/index.tsx +2 -2
  10. package/src/app/pane-runtime/pane-settings-runtime.tsx +2 -2
  11. package/src/app/pane-runtime/pane-template-runtime.ts +2 -2
  12. package/src/app/pane-runtime/plugin-bindings.ts +2 -2
  13. package/src/app/pane-runtime/ticker-open-runtime.ts +2 -2
  14. package/src/app/runtime/broker-import.ts +2 -2
  15. package/src/app/runtime/plugin-bindings.ts +2 -2
  16. package/src/app/runtime/startup.ts +2 -2
  17. package/src/app.tsx +16 -7
  18. package/src/brokers/account-cache.ts +6 -6
  19. package/src/brokers/broker-ticker-sync.ts +3 -3
  20. package/src/brokers/remote-broker-adapter.ts +2 -2
  21. package/src/brokers/sync-broker-instance.ts +5 -6
  22. package/src/cli/commands/api.ts +3 -6
  23. package/src/cli/commands/automation.ts +7 -15
  24. package/src/cli/commands/market.ts +26 -61
  25. package/src/cli/commands/overview.ts +34 -45
  26. package/src/cli/commands/search.ts +25 -27
  27. package/src/cli/commands/system.ts +27 -57
  28. package/src/cli/commands/ticker.ts +62 -63
  29. package/src/cli/context.test.ts +63 -0
  30. package/src/cli/context.ts +15 -1
  31. package/src/cli/index.ts +1 -1
  32. package/src/cli/pane-functions/data.ts +2 -19
  33. package/src/cli/pane-functions/index.ts +26 -25
  34. package/src/cli/pane-functions/report.ts +1 -1
  35. package/src/cli/pane-functions/screenshot.ts +3 -3
  36. package/src/cli/scoped-context.ts +41 -0
  37. package/src/components/chart/composite/composite-chart.test.tsx +615 -18
  38. package/src/components/chart/composite/composite-chart.tsx +179 -79
  39. package/src/components/chart/composite/format.test.ts +20 -7
  40. package/src/components/chart/composite/index.ts +0 -21
  41. package/src/components/chart/composite/interactions.test.ts +90 -3
  42. package/src/components/chart/composite/interactions.ts +189 -24
  43. package/src/components/chart/composite/price-series.ts +0 -2
  44. package/src/components/chart/composite/rasterizer.ts +10 -9
  45. package/src/components/chart/composite/renderers.test.ts +108 -2
  46. package/src/components/chart/composite/scene.test.ts +36 -0
  47. package/src/components/chart/composite/scene.ts +5 -2
  48. package/src/components/chart/composite/text-renderer.ts +37 -25
  49. package/src/components/chart/composite/time-axis.test.ts +243 -0
  50. package/src/components/chart/composite/time-axis.ts +608 -0
  51. package/src/components/chart/composite/types.ts +12 -1
  52. package/src/components/chart/core/data.ts +2 -159
  53. package/src/components/chart/core/date-window.ts +6 -225
  54. package/src/components/chart/core/palette.ts +1 -12
  55. package/src/components/chart/core/pointer.ts +0 -142
  56. package/src/components/chart/core/types.ts +1 -58
  57. package/src/components/chart/cursor-motion.ts +2 -4
  58. package/src/components/chart/indicators/types.ts +0 -9
  59. package/src/components/chart/market-session.ts +0 -11
  60. package/src/components/chart/native/kitty/protocol.ts +1 -1
  61. package/src/components/chart/native/raster/layout.ts +3 -10
  62. package/src/components/chart/static/chart/axis-overlays.test.tsx +64 -0
  63. package/src/components/chart/static/chart/axis-overlays.tsx +59 -14
  64. package/src/components/chart/static/chart/surface.tsx +1 -2
  65. package/src/components/command-bar/action-runtime.ts +2 -2
  66. package/src/components/command-bar/commands/direct/index.ts +1 -1
  67. package/src/components/command-bar/panel/body.tsx +2 -2
  68. package/src/components/command-bar/panel/index.tsx +11 -9
  69. package/src/components/command-bar/routes/ticker-search/actions.ts +2 -2
  70. package/src/components/command-bar/surface/index.tsx +2 -2
  71. package/src/components/command-bar/workflow/body.tsx +3 -3
  72. package/src/components/command-bar/workflow/collection-actions.ts +2 -2
  73. package/src/components/command-bar/workflow/coordinator.ts +2 -2
  74. package/src/components/command-bar/workflow/field-row.tsx +25 -11
  75. package/src/components/command-bar/workflow/tickers.ts +2 -2
  76. package/src/components/feed-data-table/stack-view.test.tsx +28 -36
  77. package/src/components/feed-data-table/stack-view.tsx +3 -1
  78. package/src/components/layout/detached-pane-shell.tsx +6 -6
  79. package/src/components/layout/header.tsx +13 -9
  80. package/src/components/layout/pane/content.test.tsx +42 -3
  81. package/src/components/layout/pane/content.tsx +3 -1
  82. package/src/components/layout/pane/footer/index.test.tsx +45 -2
  83. package/src/components/layout/pane/footer/registration.tsx +3 -1
  84. package/src/components/layout/shell/index.tsx +1 -2
  85. package/src/components/layout/shell/native/surfaces.ts +1 -1
  86. package/src/components/layout/shell/native/window-state.ts +1 -1
  87. package/src/components/layout/status-bar.tsx +12 -8
  88. package/src/components/layout/window-controls.tsx +8 -6
  89. package/src/components/onboarding/onboarding-wizard.tsx +3 -1
  90. package/src/components/pane-settings-dialog/desktop.tsx +0 -2
  91. package/src/components/pane-settings-dialog.tsx +0 -2
  92. package/src/components/pane-template-wizard.tsx +10 -9
  93. package/src/components/price-performance.tsx +2 -113
  94. package/src/components/price-sparkline/model.ts +15 -17
  95. package/src/components/price-sparkline/view.tsx +8 -7
  96. package/src/components/speedometer-gauge/desktop.tsx +2 -1
  97. package/src/components/speedometer-gauge/index.tsx +0 -2
  98. package/src/components/speedometer-gauge/terminal.tsx +24 -5
  99. package/src/components/ticker/badge/index.tsx +1 -18
  100. package/src/components/ui/data-table/opentui/index.tsx +3 -3
  101. package/src/components/ui/frame.tsx +1 -2
  102. package/src/components/ui/page-stack-view.test.tsx +126 -0
  103. package/src/components/ui/page-stack-view.tsx +24 -12
  104. package/src/components/ui/tabs.tsx +7 -3
  105. package/src/components/ui/ui.test.tsx +23 -2
  106. package/src/components/use-external-link-footer.ts +4 -2
  107. package/src/core/app-service-ports.ts +46 -0
  108. package/src/core/app-services.test.ts +66 -0
  109. package/src/core/app-services.ts +17 -15
  110. package/src/data/config/chart-settings.ts +3 -10
  111. package/src/data/config/store/index.test.ts +99 -2
  112. package/src/data/config/store/migrations.ts +278 -0
  113. package/src/data/config/store/normalize.ts +44 -186
  114. package/src/data/resource-store.ts +73 -12
  115. package/src/data/sqlite/cache.test.ts +104 -15
  116. package/src/i18n/index.test.ts +17 -0
  117. package/src/i18n/index.ts +23 -6
  118. package/src/i18n/ja.ts +13 -0
  119. package/src/i18n/ko.ts +13 -0
  120. package/src/i18n/react.ts +6 -0
  121. package/src/i18n/zh-cn.ts +13 -0
  122. package/src/i18n/zh-tw.ts +13 -0
  123. package/src/market-data/coordinator/auxiliary.ts +7 -3
  124. package/src/market-data/coordinator/chart.ts +1 -1
  125. package/src/market-data/coordinator/index.test.ts +26 -0
  126. package/src/market-data/coordinator/index.ts +11 -5
  127. package/src/market-data/coordinator/quotes.ts +4 -40
  128. package/src/market-data/coordinator/subscriptions.test.ts +89 -1
  129. package/src/market-data/hooks.tsx +47 -1
  130. package/src/market-data/market/status.ts +6 -6
  131. package/src/market-data/performance.ts +1 -1
  132. package/src/market-data/quote-subscription-target.test.ts +37 -0
  133. package/src/market-data/quote-subscription-target.ts +60 -0
  134. package/src/market-data/quotes/freshness.ts +1 -0
  135. package/src/market-data/quotes/resolution.ts +4 -0
  136. package/src/market-data/request-types.ts +3 -3
  137. package/src/news/aggregator.test.ts +97 -1
  138. package/src/news/aggregator.ts +100 -57
  139. package/src/news/hooks.test.tsx +64 -0
  140. package/src/news/hooks.ts +18 -25
  141. package/src/plugins/builtin/account-management/footer.ts +4 -2
  142. package/src/plugins/builtin/account-management/pane.tsx +9 -4
  143. package/src/plugins/builtin/ai/agent-history.ts +11 -7
  144. package/src/plugins/builtin/ai/ask-ai-detail-tab.tsx +0 -5
  145. package/src/plugins/builtin/ai/ask-ai.test.tsx +3 -4
  146. package/src/plugins/builtin/ai/index.test.ts +2 -2
  147. package/src/plugins/builtin/ai/index.tsx +10 -11
  148. package/src/plugins/builtin/ai/pane-settings.ts +1 -1
  149. package/src/plugins/builtin/ai/pi/runtime.ts +6 -5
  150. package/src/plugins/builtin/ai/providers.ts +1 -9
  151. package/src/plugins/builtin/ai/runner.ts +0 -6
  152. package/src/plugins/builtin/ai/screener/footer.ts +4 -1
  153. package/src/plugins/builtin/ai/screener/pane.test.tsx +9 -9
  154. package/src/plugins/builtin/ai/workspace/model.ts +2 -27
  155. package/src/plugins/builtin/ai/workspace/pane.tsx +2 -2
  156. package/src/plugins/builtin/analytics/metrics.ts +1 -7
  157. package/src/plugins/builtin/broker-manager/detail.tsx +3 -2
  158. package/src/plugins/builtin/broker-manager/index.tsx +4 -2
  159. package/src/plugins/builtin/chart-composer/editor/controller.ts +643 -0
  160. package/src/plugins/builtin/chart-composer/editor/desktop-view.tsx +134 -0
  161. package/src/plugins/builtin/chart-composer/editor/model.test.ts +85 -0
  162. package/src/plugins/builtin/chart-composer/editor/model.ts +292 -0
  163. package/src/plugins/builtin/chart-composer/editor/opentui-view.tsx +108 -0
  164. package/src/plugins/builtin/chart-composer/editor.tsx +65 -947
  165. package/src/plugins/builtin/chart-composer/index.tsx +0 -6
  166. package/src/plugins/builtin/chart-composer/pane.tsx +69 -36
  167. package/src/plugins/builtin/chart-composer/presets.ts +1 -19
  168. package/src/plugins/builtin/chart-composer/settings.ts +1 -1
  169. package/src/plugins/builtin/chat/content/composer-runtime.ts +1 -1
  170. package/src/plugins/builtin/chat/content/shortcuts.ts +0 -1
  171. package/src/plugins/builtin/chat/controller/fetch.ts +8 -2
  172. package/src/plugins/builtin/chat/controller/persistence.ts +2 -0
  173. package/src/plugins/builtin/chat/controller/session.test.ts +25 -0
  174. package/src/plugins/builtin/chat/controller/session.ts +2 -0
  175. package/src/plugins/builtin/chat/controller/state.ts +7 -0
  176. package/src/plugins/builtin/chat/controller.test.ts +73 -20
  177. package/src/plugins/builtin/chat/message/desktop.tsx +2 -0
  178. package/src/plugins/builtin/cloud-tweets/footer.ts +9 -28
  179. package/src/plugins/builtin/cloud-tweets/pane.tsx +0 -5
  180. package/src/plugins/builtin/cloud-tweets/table.tsx +12 -17
  181. package/src/plugins/builtin/correlation/compute.ts +4 -10
  182. package/src/plugins/builtin/econ/index.tsx +17 -19
  183. package/src/plugins/builtin/holders/types.ts +0 -1
  184. package/src/plugins/builtin/insider/index.tsx +6 -31
  185. package/src/plugins/builtin/news/index.tsx +5 -7
  186. package/src/plugins/builtin/news/wire/breaking/pane.test.tsx +6 -8
  187. package/src/plugins/builtin/news/wire/news/footer.ts +10 -11
  188. package/src/plugins/builtin/news/wire/read-state.test.ts +7 -0
  189. package/src/plugins/builtin/news/wire/read-state.ts +18 -28
  190. package/src/plugins/builtin/news/wire/rss/parser.ts +1 -11
  191. package/src/plugins/builtin/options/footer.test.ts +115 -0
  192. package/src/plugins/builtin/options/footer.ts +110 -0
  193. package/src/plugins/builtin/options/live-quotes.test.ts +238 -0
  194. package/src/plugins/builtin/options/live-quotes.ts +147 -0
  195. package/src/plugins/builtin/options/view.test.tsx +71 -1
  196. package/src/plugins/builtin/options/view.tsx +39 -24
  197. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +103 -117
  198. package/src/plugins/builtin/portfolio-list/cli/render.ts +11 -5
  199. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +120 -135
  200. package/src/plugins/builtin/portfolio-list/header.tsx +9 -4
  201. package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +6 -1
  202. package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +4 -2
  203. package/src/plugins/builtin/research/corporate-actions-pane.tsx +24 -52
  204. package/src/plugins/builtin/sec/filing-content.test.ts +41 -0
  205. package/src/plugins/builtin/sec/filing-content.ts +94 -0
  206. package/src/plugins/builtin/sec/index.tsx +21 -104
  207. package/src/plugins/builtin/sectors/sector-model.ts +1 -7
  208. package/src/plugins/builtin/shared/cloud-upgrade.ts +1 -0
  209. package/src/plugins/builtin/shared/pane-footer.ts +82 -0
  210. package/src/plugins/builtin/shared/read-state.ts +64 -3
  211. package/src/plugins/builtin/substack/read-state.ts +16 -41
  212. package/src/plugins/builtin/thirteenf/pane.tsx +24 -73
  213. package/src/plugins/builtin/ticker-detail/quote-monitor/index.tsx +10 -10
  214. package/src/plugins/builtin/yield-curve/index.tsx +11 -9
  215. package/src/plugins/ibkr/dialogs.tsx +3 -3
  216. package/src/plugins/ibkr/gateway/fundamentals.ts +1 -1
  217. package/src/plugins/ibkr/gateway/history-requests.ts +2 -2
  218. package/src/plugins/ibkr/gateway/history.ts +2 -2
  219. package/src/plugins/ibkr/gateway/selection.ts +2 -2
  220. package/src/plugins/ibkr/gateway/service/index.ts +2 -2
  221. package/src/plugins/ibkr/gateway/service/native.ts +2 -2
  222. package/src/plugins/plugin-persistence.ts +3 -4
  223. package/src/plugins/prediction-markets/controller/keyboard.ts +1 -1
  224. package/src/plugins/prediction-markets/controller/live-updates.ts +6 -5
  225. package/src/plugins/prediction-markets/detail/book.tsx +2 -2
  226. package/src/plugins/prediction-markets/detail/outcomes.tsx +3 -1
  227. package/src/plugins/prediction-markets/detail/pane.tsx +3 -1
  228. package/src/plugins/prediction-markets/detail/trades.tsx +3 -3
  229. package/src/plugins/registry/context.ts +3 -4
  230. package/src/plugins/registry/index.ts +5 -6
  231. package/src/react/input.test.ts +126 -3
  232. package/src/react/input.ts +120 -1
  233. package/src/remote/app-host.tsx +2 -13
  234. package/src/renderers/electrobun/bun/desktop/backend-requests.ts +44 -60
  235. package/src/renderers/electrobun/bun/desktop/capability-bridge.ts +15 -13
  236. package/src/renderers/electrobun/bun/desktop/host-requests.ts +26 -22
  237. package/src/renderers/electrobun/bun/desktop/http-fetch.ts +5 -1
  238. package/src/renderers/electrobun/bun/desktop/initialization.ts +11 -6
  239. package/src/renderers/electrobun/bun/desktop/media.ts +5 -3
  240. package/src/renderers/electrobun/bun/desktop/plugin-state.ts +21 -22
  241. package/src/renderers/electrobun/bun/desktop/window-controls.ts +3 -1
  242. package/src/renderers/electrobun/bun/desktop/workspace/requests.ts +18 -18
  243. package/src/renderers/electrobun/bun/index.ts +123 -83
  244. package/src/renderers/electrobun/shared/protocol.ts +146 -7
  245. package/src/renderers/electrobun/view/app-services.ts +5 -8
  246. package/src/renderers/electrobun/view/backend-rpc.ts +18 -8
  247. package/src/renderers/electrobun/view/broker-remote-client.ts +2 -2
  248. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +5 -22
  249. package/src/renderers/electrobun/view/config-host.ts +1 -1
  250. package/src/renderers/electrobun/view/context-menu.ts +1 -17
  251. package/src/renderers/electrobun/view/data-table/index.tsx +0 -1
  252. package/src/renderers/electrobun/view/data-table/row.tsx +0 -4
  253. package/src/renderers/electrobun/view/desktop/control-styles.ts +37 -34
  254. package/src/renderers/electrobun/view/desktop/controls.tsx +36 -33
  255. package/src/renderers/electrobun/view/desktop/list-view.tsx +15 -12
  256. package/src/renderers/electrobun/view/desktop/popover.tsx +2 -3
  257. package/src/renderers/electrobun/view/dialog-host.tsx +2 -3
  258. package/src/renderers/electrobun/view/fatal-screen.tsx +0 -1
  259. package/src/renderers/electrobun/view/host/box.tsx +0 -1
  260. package/src/renderers/electrobun/view/host/chart-surface.tsx +0 -1
  261. package/src/renderers/electrobun/view/host/input.tsx +0 -1
  262. package/src/renderers/electrobun/view/host/media-surface.tsx +0 -1
  263. package/src/renderers/electrobun/view/host/native.ts +0 -1
  264. package/src/renderers/electrobun/view/host/scroll-box.tsx +0 -1
  265. package/src/renderers/electrobun/view/host/tabs.tsx +0 -1
  266. package/src/renderers/electrobun/view/host/text.tsx +0 -1
  267. package/src/renderers/electrobun/view/http-fetch.ts +3 -11
  268. package/src/renderers/electrobun/view/input-host.tsx +10 -53
  269. package/src/renderers/electrobun/view/key-event.ts +0 -1
  270. package/src/renderers/electrobun/view/main.tsx +3 -3
  271. package/src/renderers/electrobun/view/native-renderer.ts +0 -1
  272. package/src/renderers/electrobun/view/native-stubs/backend-rpc.ts +13 -1
  273. package/src/renderers/electrobun/view/native-stubs/chart/surface-manager.ts +11 -0
  274. package/src/renderers/electrobun/view/native-stubs/native-stubs.test.ts +47 -0
  275. package/src/renderers/electrobun/view/remote/asset-data-client.ts +6 -44
  276. package/src/renderers/electrobun/view/remote/persistence.ts +6 -2
  277. package/src/renderers/electrobun/view/remote/quote-subscription-registry.test.ts +86 -0
  278. package/src/renderers/electrobun/view/remote/quote-subscription-registry.ts +72 -0
  279. package/src/renderers/electrobun/view/remote/ticker-repository.ts +2 -2
  280. package/src/renderers/electrobun/view/toast-host.tsx +0 -1
  281. package/src/renderers/electrobun/view/ui-host.tsx +1 -2
  282. package/src/renderers/electrobun/view/update-host.ts +1 -1
  283. package/src/renderers/opentui/chart-surface.tsx +2 -1
  284. package/src/renderers/opentui/dialog-host.tsx +20 -4
  285. package/src/renderers/opentui/image/loader.ts +12 -2
  286. package/src/renderers/opentui/input-host.tsx +7 -49
  287. package/src/renderers/opentui/start.tsx +2 -0
  288. package/src/sources/gloomberb-cloud/history-quality.ts +44 -0
  289. package/src/sources/gloomberb-cloud/index.test.ts +173 -0
  290. package/src/sources/gloomberb-cloud/index.ts +42 -20
  291. package/src/sources/gloomberb-cloud/normalizers.ts +9 -3
  292. package/src/sources/provider-router/cache.ts +1 -1
  293. package/src/sources/provider-router/document-routes.ts +10 -5
  294. package/src/sources/provider-router/financials.test.ts +14 -0
  295. package/src/sources/provider-router/financials.ts +6 -1
  296. package/src/sources/provider-router/history.test.ts +163 -1
  297. package/src/sources/provider-router/history.ts +278 -347
  298. package/src/sources/provider-router/index.ts +2 -2
  299. package/src/sources/provider-router/routing.test.ts +39 -0
  300. package/src/sources/provider-router/routing.ts +24 -11
  301. package/src/sources/provider-router/supplemental.ts +37 -17
  302. package/src/sources/sec-edgar/content.ts +2 -12
  303. package/src/sources/sec-edgar.ts +2 -13
  304. package/src/sources/yahoo-finance/history.ts +2 -2
  305. package/src/sources/yahoo-finance/options.ts +5 -0
  306. package/src/sources/yahoo-finance.ts +2 -2
  307. package/src/state/app/bootstrap.ts +2 -2
  308. package/src/state/app/context/index.tsx +2 -2
  309. package/src/state/hooks/quote-streaming.ts +66 -1
  310. package/src/state/hooks/session-snapshot.ts +2 -2
  311. package/src/state/selectors.ts +0 -9
  312. package/src/sync/controller.test.ts +98 -0
  313. package/src/sync/controller.ts +29 -5
  314. package/src/sync/react.ts +2 -2
  315. package/src/sync/types.ts +2 -2
  316. package/src/theme/colors.test.ts +10 -0
  317. package/src/theme/colors.ts +75 -78
  318. package/src/theme/theme-context.test.tsx +67 -0
  319. package/src/theme/theme-context.tsx +9 -5
  320. package/src/tickers/open-target.ts +2 -2
  321. package/src/tickers/search/upsert.ts +2 -2
  322. package/src/time-series/alignment.ts +0 -7
  323. package/src/time-series/chart-data.ts +145 -0
  324. package/src/time-series/date-window.ts +44 -0
  325. package/src/time-series/history-window.ts +21 -0
  326. package/src/time-series/hooks.test.ts +59 -0
  327. package/src/time-series/hooks.ts +33 -12
  328. package/src/time-series/market-resolution.ts +2 -2
  329. package/src/time-series/market.ts +1 -1
  330. package/src/time-series/range.ts +9 -0
  331. package/src/{components/chart/core → time-series}/resolution.ts +3 -102
  332. package/src/time-series/resolve.test.ts +203 -1
  333. package/src/time-series/resolve.ts +96 -18
  334. package/src/time-series/spec-studies.test.ts +15 -0
  335. package/src/time-series/spec.ts +2 -2
  336. package/src/time-series/studies.ts +5 -2
  337. package/src/time-series/types.ts +3 -1
  338. package/src/time-series/use-chart-resolution.test.tsx +358 -0
  339. package/src/time-series/use-chart-resolution.ts +46 -4
  340. package/src/types/broker.ts +2 -2
  341. package/src/types/data-provider.ts +3 -3
  342. package/src/types/financials.ts +12 -0
  343. package/src/types/plugin.ts +2 -2
  344. package/src/ui/context-menu.tsx +3 -2
  345. package/src/ui/dialog.tsx +2 -2
  346. package/src/utils/html-entities.ts +3 -5
  347. package/src/utils/main-thread-monitor.ts +1 -1
  348. package/src/utils/price-history.ts +5 -5
  349. package/src/version.ts +3 -1
  350. package/src/components/chart/core/viewport.test.ts +0 -8
  351. package/src/components/chart/core/viewport.ts +0 -24
  352. package/src/time-series/index.ts +0 -14
  353. /package/src/{components/chart/core → time-series}/resolution.test.ts +0 -0
@@ -1,6 +1,6 @@
1
1
  import type { Dispatch } from "react";
2
2
  import type { AppAction, AppState } from "../../../state/app/context";
3
- import type { TickerRepository } from "../../../data/ticker-repository";
3
+ import type { AppTickerRepositoryPort } from "../../../core/app-service-ports";
4
4
  import type { PluginRegistry } from "../../../plugins/registry";
5
5
  import { isManualPortfolio } from "../../../plugins/builtin/portfolio-list/mutations";
6
6
  import type { DataProvider } from "../../../types/data-provider";
@@ -10,7 +10,7 @@ import { parseTickerListInput } from "../../../tickers/list";
10
10
 
11
11
  export interface SharedWorkflowDeps {
12
12
  dataProvider: DataProvider;
13
- tickerRepository: TickerRepository;
13
+ tickerRepository: AppTickerRepositoryPort;
14
14
  pluginRegistry: PluginRegistry;
15
15
  dispatch: Dispatch<AppAction>;
16
16
  getState: () => AppState;
@@ -3,52 +3,44 @@ import { act } from "react";
3
3
  import { testRender } from "../../renderers/opentui/test-utils";
4
4
  import { AppContext, PaneInstanceProvider, createInitialState } from "../../state/app/context";
5
5
  import { createDefaultConfig } from "../../types/config";
6
- import { Box, Text } from "../../ui";
7
6
  import { FeedDataTableStackView } from "./stack-view";
7
+ import { setLanguage } from "../../i18n";
8
8
 
9
9
  let testSetup: Awaited<ReturnType<typeof testRender>> | undefined;
10
10
 
11
11
  afterEach(async () => {
12
12
  await act(async () => testSetup?.renderer.destroy());
13
13
  testSetup = undefined;
14
+ setLanguage("en");
14
15
  });
15
16
 
16
- test("delegates root key handling", async () => {
17
- let keyHits = 0;
18
- const state = createInitialState(createDefaultConfig("/tmp/gloomberb-feed-table-test"));
19
- await act(async () => {
20
- testSetup = await testRender(
21
- <AppContext value={{ state, dispatch: () => {} }}>
22
- <PaneInstanceProvider paneId="portfolio-list:main">
23
- <FeedDataTableStackView
24
- width={80}
25
- height={12}
26
- focused
27
- items={[]}
28
- selectedIdx={0}
29
- onSelect={() => {}}
30
- rootBefore={<Box height={1}><Text>Feed controls</Text></Box>}
31
- onRootKeyDown={(event) => {
32
- if (event.name !== "f") return false;
33
- keyHits += 1;
34
- return true;
35
- }}
36
- />
37
- </PaneInstanceProvider>
38
- </AppContext>,
39
- { width: 80, height: 12 },
40
- );
41
- await testSetup.renderOnce();
42
- });
17
+ test("rebuilds translated columns when the app language changes", async () => {
18
+ const state = createInitialState(createDefaultConfig("/tmp/gloomberb-feed-table-language"));
19
+ const items = [{ id: "story", eyebrow: "Wire", title: "Story", timestamp: "2026-01-01" }];
20
+ testSetup = await testRender(
21
+ <AppContext value={{ state, dispatch: () => {} }}>
22
+ <PaneInstanceProvider paneId="news:test">
23
+ <FeedDataTableStackView
24
+ width={80}
25
+ height={8}
26
+ focused
27
+ items={items}
28
+ selectedIdx={0}
29
+ onSelect={() => {}}
30
+ sourceLabel="Source"
31
+ titleLabel="Headline"
32
+ />
33
+ </PaneInstanceProvider>
34
+ </AppContext>,
35
+ { width: 80, height: 8 },
36
+ );
37
+ await act(async () => testSetup?.renderOnce());
38
+ expect(testSetup.captureCharFrame()).toContain("Source");
43
39
 
44
40
  await act(async () => {
45
- (testSetup!.renderer.keyInput as any).emit("keypress", {
46
- name: "f", sequence: "f", eventType: "press",
47
- ctrl: false, meta: false, option: false, shift: false, repeated: false,
48
- preventDefault() {}, stopPropagation() {},
49
- });
50
- await testSetup!.renderOnce();
41
+ setLanguage("zh-CN");
42
+ await testSetup?.renderOnce();
43
+ await testSetup?.renderOnce();
51
44
  });
52
-
53
- expect(keyHits).toBe(1);
45
+ expect(testSetup.captureCharFrame()).toContain("来源");
54
46
  });
@@ -2,6 +2,7 @@ import { Box, ScrollBox, Text } from "../../ui";
2
2
  import { TextAttributes, type ScrollBoxRenderable } from "../../ui";
3
3
  import { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from "react";
4
4
  import { t } from "../../i18n";
5
+ import { useAppLanguage } from "../../i18n/react";
5
6
  import { displayWidth, formatTimeAgo } from "../../utils/format";
6
7
  import { colors } from "../../theme/colors";
7
8
  import { isPlainKey } from "../../utils/keyboard";
@@ -148,6 +149,7 @@ export function FeedDataTableStackView({
148
149
  onOpenItem,
149
150
  onOpenItemIdChange,
150
151
  }: FeedDataTableStackViewProps) {
152
+ const language = useAppLanguage();
151
153
  const [sortPreference, setSortPreference] = useState<SortPreference>({
152
154
  columnId: "time",
153
155
  direction: "desc",
@@ -157,7 +159,7 @@ export function FeedDataTableStackView({
157
159
  const detailTextWidth = Math.max(width - 2, 12);
158
160
  const columns = useMemo(
159
161
  () => buildColumns(width, t(sourceLabel), t(titleLabel), items),
160
- [items, sourceLabel, titleLabel, width],
162
+ [items, language, sourceLabel, titleLabel, width],
161
163
  );
162
164
  const sortedRows = useMemo(() => {
163
165
  return sortIndexedStackRows(items, sortPreference, compareRows);
@@ -6,7 +6,7 @@ import { useAppDispatch, useAppSelector } from "../../state/app/context";
6
6
  import type { DesktopWindowBridge } from "../../types/desktop-window";
7
7
  import { findPaneInstance } from "../../types/config";
8
8
  import type { PluginRegistry } from "../../plugins/registry";
9
- import { colors, floatingPaneBg, floatingPaneTitleBg, paneTitleText } from "../../theme/colors";
9
+ import { floatingPaneBg, floatingPaneTitleBg, paneTitleText } from "../../theme/colors";
10
10
  import { useThemeColors } from "../../theme/theme-context";
11
11
  import { hasPaneFooterContent, PaneFooterBar, PaneFooterProvider } from "./pane/footer";
12
12
  import { PaneBodyFrame, getPaneWindowAttributes } from "./pane/frame";
@@ -32,7 +32,7 @@ function stopMouse(event?: { stopPropagation?: () => void; preventDefault?: () =
32
32
  }
33
33
 
34
34
  export function DetachedPaneShell({ pluginRegistry, desktopWindowBridge }: DetachedPaneShellProps) {
35
- useThemeColors();
35
+ const colors = useThemeColors();
36
36
  const dispatch = useAppDispatch();
37
37
  const rendererHost = useRendererHost();
38
38
  const config = useAppSelector((state) => state.config);
@@ -134,8 +134,8 @@ export function DetachedPaneShell({ pluginRegistry, desktopWindowBridge }: Detac
134
134
  const reserveFooter = shouldReservePaneFooter(nativePaneChrome, showFooter);
135
135
  const renderFooter = reserveFooter || showFooter;
136
136
  const headerHeightRows = titleBarOverlay ? TITLEBAR_OVERLAY_HEIGHT_PX / cellHeightPx : 1;
137
- const background = floatingPaneBg(focused);
138
- const titleBackground = floatingPaneTitleBg(focused);
137
+ const background = floatingPaneBg(focused, colors);
138
+ const titleBackground = floatingPaneTitleBg(focused, colors);
139
139
  const bodyFrame = resolvePaneBodyFrame({
140
140
  width,
141
141
  height,
@@ -184,11 +184,11 @@ export function DetachedPaneShell({ pluginRegistry, desktopWindowBridge }: Detac
184
184
  style={{ position: "relative" }}
185
185
  >
186
186
  <Box flexGrow={1} minWidth={0} overflow="hidden">
187
- <Text fg={paneTitleText(focused, true)} selectable={false} data-gloom-role="pane-title">{title}</Text>
187
+ <Text fg={paneTitleText(focused, true, colors)} selectable={false} data-gloom-role="pane-title">{title}</Text>
188
188
  </Box>
189
189
  {hasPaneSettings && (
190
190
  <Text
191
- fg={paneTitleText(focused, true)}
191
+ fg={paneTitleText(focused, true, colors)}
192
192
  selectable={false}
193
193
  className="electrobun-webkit-app-region-no-drag"
194
194
  data-gloom-role="pane-action"
@@ -1,6 +1,6 @@
1
1
  import { Box, SpinnerMark, Text, TextAttributes, useRendererHost, useUiCapabilities } from "../../ui";
2
2
  import { useCallback, useEffect, type ReactNode } from "react";
3
- import { blendHex, colors, priceColor } from "../../theme/colors";
3
+ import { blendHex, priceColor } from "../../theme/colors";
4
4
  import { useThemeColors } from "../../theme/theme-context";
5
5
  import { useAppActive } from "../../state/app/activity";
6
6
  import { useAppDispatch, useAppSelector } from "../../state/app/context";
@@ -26,21 +26,24 @@ const UPDATE_NOTICE_DURATION_MS = 5_000;
26
26
 
27
27
  function DesktopHeaderPill({
28
28
  children,
29
- backgroundColor = blendHex(colors.header, colors.bg, 0.28),
30
- borderColor = blendHex(colors.border, colors.headerText, 0.22),
29
+ backgroundColor,
30
+ borderColor,
31
31
  }: {
32
32
  children: ReactNode;
33
33
  backgroundColor?: string;
34
34
  borderColor?: string;
35
35
  }) {
36
+ const colors = useThemeColors();
37
+ const resolvedBackgroundColor = backgroundColor ?? blendHex(colors.header, colors.bg, 0.28);
38
+ const resolvedBorderColor = borderColor ?? blendHex(colors.border, colors.headerText, 0.22);
36
39
  return (
37
40
  <Box
38
41
  height={1}
39
42
  flexDirection="row"
40
43
  alignItems="center"
41
- backgroundColor={backgroundColor}
44
+ backgroundColor={resolvedBackgroundColor}
42
45
  style={{
43
- border: `1px solid ${borderColor}`,
46
+ border: `1px solid ${resolvedBorderColor}`,
44
47
  borderRadius: 5,
45
48
  paddingInline: 6,
46
49
  }}
@@ -51,6 +54,7 @@ function DesktopHeaderPill({
51
54
  }
52
55
 
53
56
  function UpdateStatus() {
57
+ const colors = useThemeColors();
54
58
  const dispatch = useAppDispatch();
55
59
  const updateAvailable = useAppSelector(selectUpdateAvailable);
56
60
  const updateProgress = useAppSelector(selectUpdateProgress);
@@ -91,7 +95,7 @@ function UpdateStatus() {
91
95
  return <Text fg={colors.headerText}>{t(updateProgress.message ?? "Update installed, restart to apply")}</Text>;
92
96
  }
93
97
  if (updateProgress.phase === "error") {
94
- return <Text fg={colors.headerText}>{tf("Update failed: {error}", { error: updateProgress.error })}</Text>;
98
+ return <Text fg={colors.headerText}>{tf("Update failed: {error}", { error: updateProgress.error ?? "Unknown error" })}</Text>;
95
99
  }
96
100
  }
97
101
 
@@ -130,7 +134,7 @@ function UpdateStatus() {
130
134
  }
131
135
 
132
136
  export function Header() {
133
- useThemeColors();
137
+ const colors = useThemeColors();
134
138
  const rendererHost = useRendererHost();
135
139
  const baseCurrency = useAppSelector(selectBaseCurrency);
136
140
  const appActive = useAppActive();
@@ -153,7 +157,7 @@ export function Header() {
153
157
  }, [appActive]);
154
158
 
155
159
  const activeSpyQuote = getActiveQuoteDisplay(spyQuote);
156
- const spyColor = activeSpyQuote ? priceColor(activeSpyQuote.change) : colors.headerText;
160
+ const spyColor = activeSpyQuote ? priceColor(activeSpyQuote.change, colors) : colors.headerText;
157
161
  const spyText = activeSpyQuote
158
162
  ? `SPY ${formatMarketPrice(activeSpyQuote.price, { assetCategory: "ETF" })} ${formatPercentRaw(activeSpyQuote.changePercent)}`
159
163
  : "SPY —";
@@ -166,7 +170,7 @@ export function Header() {
166
170
  // Market status
167
171
  const mktState = spyQuote?.marketState;
168
172
  const mktLabel = mktState ? t(marketStateLabel(mktState)) : "";
169
- const mktColor = mktState ? marketStateColor(mktState) : colors.headerText;
173
+ const mktColor = mktState ? marketStateColor(mktState, colors) : colors.headerText;
170
174
 
171
175
  if (titleBarOverlay) {
172
176
  return (
@@ -2,6 +2,7 @@ import { afterEach, describe, expect, test } from "bun:test";
2
2
  import { act, type Dispatch } from "react";
3
3
  import { testRender } from "../../../renderers/opentui/test-utils";
4
4
  import { AppProvider, useAppDispatch, type AppAction } from "../../../state/app/context";
5
+ import { setLanguage, t } from "../../../i18n";
5
6
  import { applyTheme, colors } from "../../../theme/colors";
6
7
  import { getTheme } from "../../../theme/themes";
7
8
  import { createDefaultConfig } from "../../../types/config";
@@ -19,15 +20,22 @@ function ThemeColorProbe() {
19
20
  return <text>{colors.textBright}</text>;
20
21
  }
21
22
 
23
+ function LanguageProbe() {
24
+ return <text>{t("Done")}</text>;
25
+ }
26
+
22
27
  describe("PaneContent", () => {
23
- afterEach(() => {
24
- testSetup?.renderer.destroy();
28
+ afterEach(async () => {
29
+ if (testSetup) {
30
+ await act(async () => testSetup?.renderer.destroy());
31
+ }
25
32
  testSetup = undefined;
26
33
  capturedDispatch = null;
27
34
  applyTheme("amber");
35
+ setLanguage("en");
28
36
  });
29
37
 
30
- test("rerenders memoized pane bodies when the theme preview changes", async () => {
38
+ test("rerenders legacy pane colors when the theme preview changes", async () => {
31
39
  const config = {
32
40
  ...createDefaultConfig("/tmp/gloomberb-test"),
33
41
  theme: "amber",
@@ -61,4 +69,35 @@ describe("PaneContent", () => {
61
69
  expect(frame).toContain(getTheme("green").textBright);
62
70
  expect(frame).not.toContain(getTheme("amber").textBright);
63
71
  });
72
+
73
+ test("rerenders pane bodies when the app language changes", async () => {
74
+ const config = createDefaultConfig("/tmp/gloomberb-language-test");
75
+
76
+ testSetup = await testRender(
77
+ <AppProvider config={config}>
78
+ <PaneContent
79
+ component={LanguageProbe}
80
+ paneId="language:test"
81
+ paneType="test"
82
+ focused
83
+ width={24}
84
+ height={4}
85
+ />
86
+ </AppProvider>,
87
+ { width: 32, height: 6 },
88
+ );
89
+
90
+ await testSetup.renderOnce();
91
+ expect(testSetup.captureCharFrame()).toContain("Done");
92
+
93
+ await act(async () => {
94
+ setLanguage("zh-CN");
95
+ await testSetup!.renderOnce();
96
+ });
97
+ await testSetup.renderOnce();
98
+
99
+ const frame = testSetup.captureCharFrame();
100
+ expect(frame).toContain("完成");
101
+ expect(frame).not.toContain("Done");
102
+ });
64
103
  });
@@ -1,7 +1,8 @@
1
1
  import { memo, useCallback } from "react";
2
+ import { useAppLanguage } from "../../../i18n/react";
2
3
  import { PaneInstanceProvider } from "../../../state/app/context";
3
- import { PaneKeyboardScrollController } from "../../../state/pane-scroll-registry";
4
4
  import { useThemeColors } from "../../../theme/theme-context";
5
+ import { PaneKeyboardScrollController } from "../../../state/pane-scroll-registry";
5
6
  import type { PaneDef } from "../../../types/plugin";
6
7
  import { Box } from "../../../ui";
7
8
 
@@ -24,6 +25,7 @@ export const PaneContent = memo(function PaneContent({
24
25
  height,
25
26
  onClose,
26
27
  }: PaneContentProps) {
28
+ useAppLanguage();
27
29
  useThemeColors();
28
30
  const close = useCallback(() => {
29
31
  onClose?.(paneId);
@@ -8,14 +8,16 @@ import {
8
8
  usePaneFooter,
9
9
  } from "./index";
10
10
  import { useExternalLinkFooter } from "../../../use-external-link-footer";
11
+ import { setLanguage, t } from "../../../../i18n";
11
12
 
12
13
  let testSetup: Awaited<ReturnType<typeof testRender>> | undefined;
13
14
 
14
- afterEach(() => {
15
+ afterEach(async () => {
15
16
  if (testSetup) {
16
- testSetup.renderer.destroy();
17
+ await act(async () => testSetup?.renderer.destroy());
17
18
  testSetup = undefined;
18
19
  }
20
+ setLanguage("en");
19
21
  });
20
22
 
21
23
  function Registration({
@@ -54,6 +56,26 @@ function ExternalLinkRegistration() {
54
56
  return null;
55
57
  }
56
58
 
59
+ function TranslatedRegistration() {
60
+ usePaneFooter("translated", () => ({
61
+ info: [{ id: "state", parts: [{ text: t("Open"), tone: "value" }] }],
62
+ }), []);
63
+ return null;
64
+ }
65
+
66
+ function TranslatedFooterHarness() {
67
+ return (
68
+ <PaneFooterProvider>
69
+ {(footer) => (
70
+ <Box width={40} height={1}>
71
+ <TranslatedRegistration />
72
+ <PaneFooterBar footer={footer} focused width={40} />
73
+ </Box>
74
+ )}
75
+ </PaneFooterProvider>
76
+ );
77
+ }
78
+
57
79
  function FooterHarness({
58
80
  focused = false,
59
81
  onRefresh,
@@ -89,6 +111,27 @@ function ExternalLinkFooterHarness() {
89
111
  }
90
112
 
91
113
  describe("PaneFooterBar", () => {
114
+ test("rebuilds translated registrations when the app language changes", async () => {
115
+ testSetup = await testRender(<TranslatedFooterHarness />, { width: 40, height: 1 });
116
+ await act(async () => {
117
+ await testSetup?.renderOnce();
118
+ await testSetup?.renderOnce();
119
+ });
120
+ expect(testSetup.captureCharFrame()).toContain("Open");
121
+
122
+ await act(async () => {
123
+ setLanguage("zh-CN");
124
+ await Promise.resolve();
125
+ });
126
+ await act(async () => {
127
+ await testSetup?.renderOnce();
128
+ await testSetup?.renderOnce();
129
+ await Promise.resolve();
130
+ await testSetup?.renderOnce();
131
+ });
132
+ expect(testSetup.captureCharFrame()).toContain("打开");
133
+ });
134
+
92
135
  test("hides hints on inactive footers but keeps info visible", async () => {
93
136
  testSetup = await testRender(<FooterHarness />, { width: 64, height: 1 });
94
137
  await act(async () => {
@@ -17,6 +17,7 @@ import {
17
17
  type PaneFooterRegistration,
18
18
  type PaneHint,
19
19
  } from "./model";
20
+ import { useAppLanguage } from "../../../../i18n/react";
20
21
 
21
22
  const usePaneFooterRegistrationEffect =
22
23
  typeof document === "undefined" ? useEffect : useLayoutEffect;
@@ -86,6 +87,7 @@ export function usePaneFooter(
86
87
  factory: () => PaneFooterRegistration | null | undefined,
87
88
  deps: DependencyList,
88
89
  ) {
90
+ const language = useAppLanguage();
89
91
  const context = useContext(PaneFooterContext);
90
92
  const previousRegistrationRef = useRef<PaneFooterRegistration | null>(null);
91
93
 
@@ -103,7 +105,7 @@ export function usePaneFooter(
103
105
  previousRegistrationRef.current = nextRegistration;
104
106
  context.register(registrationId, nextRegistration);
105
107
  // eslint-disable-next-line react-hooks/exhaustive-deps
106
- }, [context, registrationId, ...deps]);
108
+ }, [context, language, registrationId, ...deps]);
107
109
  }
108
110
 
109
111
  export function usePaneHints(
@@ -28,7 +28,6 @@ import {
28
28
  selectLayout,
29
29
  selectStatusBarVisible,
30
30
  } from "../../../state/selectors-ui";
31
- import { colors } from "../../../theme/colors";
32
31
  import { useThemeColors } from "../../../theme/theme-context";
33
32
  import { getPaneDisplayTitle } from "../pane/title";
34
33
  import { getShortcutDisplayMode } from "../../../utils/shortcut-labels";
@@ -90,7 +89,7 @@ export function Shell({
90
89
  desktopDockPreview,
91
90
  commandBarNativeOccluder = null,
92
91
  }: ShellProps) {
93
- useThemeColors();
92
+ const colors = useThemeColors();
94
93
  const dispatch = useAppDispatch();
95
94
  const config = useAppSelector((state) => state.config);
96
95
  const paneState = useAppSelector((state) => state.paneState);
@@ -14,7 +14,7 @@ import {
14
14
  resolveNativeDockDividers,
15
15
  type DividerPreviewState,
16
16
  } from "./window-state";
17
- import type { WindowEditDockMovePreview } from "../../window-edit/mode";
17
+ import type { WindowEditDockMovePreview } from "../../window-edit/presentation";
18
18
 
19
19
  interface ShellNativeSurfaceMenuState {
20
20
  paneId: string;
@@ -3,7 +3,7 @@ import type { NativeOccluder, NativePaneLayer } from "../../../chart/native/surf
3
3
  import { DEFAULT_HEADER_HEIGHT } from "../chrome";
4
4
  import type { DragPreview, HoverOverlay } from "../drag";
5
5
  import { MENU_Z_INDEX } from "../menu";
6
- import type { WindowEditDockMovePreview } from "../../window-edit/mode";
6
+ import type { WindowEditDockMovePreview } from "../../window-edit/presentation";
7
7
 
8
8
  export interface FloatingPreviewRect {
9
9
  paneId: string;
@@ -1,6 +1,6 @@
1
1
  import { Box, Span, Text, TextAttributes, contextMenuDivider, useContextMenu, useUiCapabilities } from "../../ui";
2
2
  import { useCallback, useEffect, useState } from "react";
3
- import { blendHex, colors, hoverBg } from "../../theme/colors";
3
+ import { blendHex, hoverBg } from "../../theme/colors";
4
4
  import { t, tf } from "../../i18n";
5
5
  import { useThemeColors } from "../../theme/theme-context";
6
6
  import { useAppDispatch, useAppSelector } from "../../state/app/context";
@@ -55,7 +55,6 @@ function truncate(text: string, width: number): string {
55
55
  }
56
56
 
57
57
  export function StatusBar() {
58
- useThemeColors();
59
58
  const { nativePaneChrome, nativeContextMenu } = useUiCapabilities();
60
59
  const { showContextMenu } = useContextMenu();
61
60
  const registry = getSharedRegistry();
@@ -255,6 +254,7 @@ function NativeStatusBar({
255
254
  showGridlockTip,
256
255
  ...props
257
256
  }: StatusBarViewProps) {
257
+ const colors = useThemeColors();
258
258
  return (
259
259
  <Box
260
260
  flexDirection="row"
@@ -271,9 +271,9 @@ function NativeStatusBar({
271
271
  paddingInline: 8,
272
272
  }}
273
273
  >
274
- <StatusBarLayoutControl activeLayoutIdx={activeLayoutIdx} nativePaneChrome {...props} />
274
+ <StatusBarLayoutControl nativePaneChrome {...props} />
275
275
  {showGridlockTip && <NativeGridlockTip {...props} />}
276
- <StatusBarWidgets {...props} />
276
+ <StatusBarWidgets />
277
277
  </Box>
278
278
  );
279
279
  }
@@ -284,6 +284,7 @@ function TerminalStatusBar({
284
284
  showGridlockTip,
285
285
  ...props
286
286
  }: StatusBarViewProps) {
287
+ const colors = useThemeColors();
287
288
  return (
288
289
  <Box
289
290
  flexDirection="row"
@@ -295,9 +296,9 @@ function TerminalStatusBar({
295
296
  void openLayoutContextMenu(activeLayoutIdx, event);
296
297
  }}
297
298
  >
298
- <StatusBarLayoutControl activeLayoutIdx={activeLayoutIdx} nativePaneChrome={false} {...props} />
299
+ <StatusBarLayoutControl nativePaneChrome={false} {...props} />
299
300
  {showGridlockTip && <TerminalGridlockTip {...props} />}
300
- <StatusBarWidgets {...props} />
301
+ <StatusBarWidgets />
301
302
  </Box>
302
303
  );
303
304
  }
@@ -360,11 +361,12 @@ function CommandBarHint({
360
361
  }: Pick<StatusBarViewProps, "hoveredControl" | "openCommandBar" | "setHoveredControl"> & {
361
362
  nativePaneChrome: boolean;
362
363
  }) {
364
+ const colors = useThemeColors();
363
365
  const hovered = hoveredControl === "command-bar";
364
366
  return (
365
367
  <Text
366
368
  fg={hovered ? colors.text : colors.textDim}
367
- {...(!nativePaneChrome ? { bg: hovered ? hoverBg() : undefined } : {})}
369
+ {...(!nativePaneChrome ? { bg: hovered ? hoverBg(colors) : undefined } : {})}
368
370
  onMouseOver={() => setHoveredControl((current) => (current === "command-bar" ? current : "command-bar"))}
369
371
  onMouseDown={openCommandBar}
370
372
  {...(nativePaneChrome ? { "data-gloom-interactive": "true" } : {})}
@@ -380,6 +382,7 @@ function NativeGridlockTip({
380
382
  hoveredControl,
381
383
  setHoveredControl,
382
384
  }: Pick<StatusBarViewProps, "dismissGridlockTip" | "handleGridlockTip" | "hoveredControl" | "setHoveredControl">) {
385
+ const colors = useThemeColors();
383
386
  return (
384
387
  <Box paddingLeft={2} flexShrink={0} flexDirection="row" alignItems="center" gap={1}>
385
388
  <Text fg={colors.textDim}>{t("Snapped a window?")}</Text>
@@ -410,12 +413,13 @@ function TerminalGridlockTip({
410
413
  hoveredControl,
411
414
  setHoveredControl,
412
415
  }: Pick<StatusBarViewProps, "dismissGridlockTip" | "handleGridlockTip" | "hoveredControl" | "setHoveredControl">) {
416
+ const colors = useThemeColors();
413
417
  return (
414
418
  <Box paddingLeft={1} flexShrink={0} flexDirection="row">
415
419
  <Text fg={colors.textDim}>{t("Snapped a window?")}</Text>
416
420
  <Box width={1} />
417
421
  <Box
418
- backgroundColor={hoveredControl === "gridlock-tip" ? hoverBg() : colors.header}
422
+ backgroundColor={hoveredControl === "gridlock-tip" ? hoverBg(colors) : colors.header}
419
423
  onMouseOver={() => setHoveredControl((current) => (current === "gridlock-tip" ? current : "gridlock-tip"))}
420
424
  onMouseDown={handleGridlockTip}
421
425
  >
@@ -1,6 +1,7 @@
1
1
  import { Box, useRendererHost } from "../../ui";
2
2
  import { useCallback } from "react";
3
3
  import { t } from "../../i18n";
4
+ import { useAppLanguage } from "../../i18n/react";
4
5
  import { TITLEBAR_OVERLAY_HEIGHT_PX } from "./titlebar-overlay";
5
6
 
6
7
  const WINDOWS_CONTROL_SIZE_PX = TITLEBAR_OVERLAY_HEIGHT_PX;
@@ -10,11 +11,11 @@ type WindowControlAction = "minimize" | "toggle-maximize" | "close";
10
11
 
11
12
  const WINDOWS_CONTROLS: Array<{
12
13
  action: WindowControlAction;
13
- label: string;
14
+ labelKey: string;
14
15
  }> = [
15
- { action: "minimize", label: t("Minimize") },
16
- { action: "toggle-maximize", label: t("Maximize") },
17
- { action: "close", label: t("Close") },
16
+ { action: "minimize", labelKey: "Minimize" },
17
+ { action: "toggle-maximize", labelKey: "Maximize" },
18
+ { action: "close", labelKey: "Close" },
18
19
  ];
19
20
 
20
21
  function stopMouse(event: { stopPropagation?: () => void; preventDefault?: () => void }) {
@@ -51,6 +52,7 @@ interface WindowControlsProps {
51
52
  }
52
53
 
53
54
  export function WindowControls({ windowKind = "main" }: WindowControlsProps) {
55
+ useAppLanguage();
54
56
  const rendererHost = useRendererHost();
55
57
 
56
58
  const controlWindow = useCallback((action: WindowControlAction, event: { stopPropagation?: () => void; preventDefault?: () => void }) => {
@@ -88,8 +90,8 @@ export function WindowControls({ windowKind = "main" }: WindowControlsProps) {
88
90
  data-window-control-action={control.action}
89
91
  data-gloom-interactive="true"
90
92
  role="button"
91
- aria-label={control.label}
92
- title={control.label}
93
+ aria-label={t(control.labelKey)}
94
+ title={t(control.labelKey)}
93
95
  onMouseDown={(event: { stopPropagation?: () => void; preventDefault?: () => void }) => controlWindow(control.action, event)}
94
96
  >
95
97
  <WindowControlIcon action={control.action} />
@@ -3,6 +3,7 @@ import { Box, Text, type InputRenderable } from "../../ui";
3
3
  import { useViewport } from "../../react/input";
4
4
  import { colors, applyTheme } from "../../theme/colors";
5
5
  import { t } from "../../i18n";
6
+ import { useAppLanguage } from "../../i18n/react";
6
7
  import { getThemeIds } from "../../theme/themes";
7
8
  import type { AppConfig } from "../../types/config";
8
9
  import type { PluginRegistry } from "../../plugins/registry";
@@ -32,6 +33,7 @@ interface OnboardingWizardProps {
32
33
  }
33
34
 
34
35
  export function OnboardingWizard({ config, pluginRegistry, onComplete }: OnboardingWizardProps) {
36
+ const language = useAppLanguage();
35
37
  const { width: termWidth, height: termHeight } = useViewport();
36
38
  const [step, setStep] = useState<OnboardingStep>("welcome");
37
39
  const [themeIdx, setThemeIdx] = useState(0);
@@ -67,7 +69,7 @@ export function OnboardingWizard({ config, pluginRegistry, onComplete }: Onboard
67
69
  });
68
70
  }
69
71
  return choices;
70
- }, [brokerOptions]);
72
+ }, [brokerOptions, language]);
71
73
 
72
74
  const activeBrokerFields = useMemo((): BrokerConfigField[] => {
73
75
  if (!selectedBrokerId) return [];
@@ -1,5 +1,3 @@
1
- /// <reference lib="dom" />
2
-
3
1
  import { Box, Text } from "../../ui";
4
2
  import type { ReactNode } from "react";
5
3
  import type { PaneSettingField } from "../../types/plugin";
@@ -1,5 +1,3 @@
1
- /// <reference lib="dom" />
2
-
3
1
  import { useUiHost } from "../ui";
4
2
  import { type AlertContext, useDialog, useDialogKeyboard } from "../ui/dialog";
5
3
  import { useEffect, useRef, useState } from "react";