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.
- package/README.md +7 -4
- package/README.zh-CN.md +4 -2
- package/package.json +28 -1
- package/src/api-client/auth.ts +10 -0
- package/src/api-client/data.ts +108 -1
- package/src/api-client/index.test.ts +127 -0
- package/src/api-client/index.ts +134 -1
- package/src/api-client/normalizers.ts +39 -0
- package/src/api-client/paths.ts +85 -1
- package/src/api-client/types.ts +220 -0
- package/src/app/pane-runtime/index.tsx +15 -12
- package/src/app/pane-runtime/layout-placement.test.ts +27 -0
- package/src/app/pane-runtime/layout-placement.ts +13 -0
- package/src/app/pane-runtime/plugin-bindings.ts +62 -0
- package/src/app.tsx +60 -18
- package/src/architecture/browser-entry-graph.test.ts +96 -0
- package/src/brokers/profile-form.test.ts +25 -27
- package/src/brokers/test-broker.ts +68 -0
- package/src/capabilities/chart-series.ts +3 -2
- package/src/cli/commands/market.ts +2 -2
- package/src/cli/commands/plugins.ts +39 -11
- package/src/cli/desktop-pane-shot.ts +285 -16
- package/src/cli/index.ts +1 -1
- package/src/cli/pane-functions/capabilities.ts +61 -31
- package/src/cli/pane-functions/catalog.ts +16 -4
- package/src/cli/pane-functions/discovery.ts +1 -0
- package/src/cli/pane-functions/headless.test.ts +247 -0
- package/src/cli/pane-functions/headless.ts +423 -0
- package/src/cli/pane-functions/index.test.ts +9 -0
- package/src/cli/pane-functions/index.ts +6 -2
- package/src/cli/pane-functions/options.ts +27 -2
- package/src/cli/pane-functions/report.ts +4 -0
- package/src/cli/pane-functions/resolver.ts +26 -8
- package/src/cli/pane-functions/screenshot.test.ts +76 -0
- package/src/cli/pane-functions/screenshot.ts +236 -20
- package/src/cli/registry.ts +0 -22
- package/src/cli/restore-plugins.ts +34 -0
- package/src/cli/result.ts +7 -10
- package/src/components/chart/{static/chart → composite}/axis-overlays.test.tsx +3 -3
- package/src/components/chart/{static/chart → composite}/axis-overlays.tsx +6 -11
- package/src/components/chart/{static/chart → composite}/bitmap.ts +17 -3
- package/src/components/chart/composite/composite-chart.test.tsx +68 -20
- package/src/components/chart/composite/composite-chart.tsx +301 -204
- package/src/components/chart/composite/format.ts +8 -2
- package/src/components/chart/composite/interactions.test.ts +68 -102
- package/src/components/chart/composite/interactions.ts +214 -264
- package/src/components/chart/composite/price-axis-labels.test.ts +21 -0
- package/src/components/chart/{price-axis-labels.tsx → composite/price-axis-labels.tsx} +9 -4
- package/src/components/chart/composite/scene.ts +57 -3
- package/src/components/chart/composite/text-renderer.ts +3 -2
- package/src/components/chart/composite/time-scale.ts +138 -57
- package/src/components/chart/composite/types.ts +25 -1
- package/src/components/chart/core/data.ts +9 -13
- package/src/components/chart/core/date-window.ts +7 -1
- package/src/components/chart/core/pointer.ts +3 -0
- package/src/components/chart/core/types.ts +0 -45
- package/src/components/chart/native/chart-rasterizer.ts +0 -1
- package/src/components/chart/native/kitty/index.test.ts +0 -188
- package/src/components/chart/native/raster/crosshair.ts +6 -5
- package/src/components/chart/native/raster/primitives.ts +0 -23
- package/src/components/chart/native/renderer-selection.ts +81 -31
- package/src/components/chart/static/{chart/surface.test.tsx → chart-surface.test.tsx} +28 -80
- package/src/components/chart/static/chart-surface.tsx +150 -0
- package/src/components/chart/static/index.ts +8 -0
- package/src/components/chart/static/multi-line-chart-surface.tsx +51 -166
- package/src/components/chart/static/scatter-chart-surface.test.ts +30 -0
- package/src/components/chart/static/scatter-chart-surface.tsx +135 -34
- package/src/components/chart/static/series.ts +49 -0
- package/src/components/command-bar/action-runtime.ts +1 -3
- package/src/components/command-bar/assist/model.test.ts +17 -2
- package/src/components/command-bar/assist/model.ts +40 -9
- package/src/components/command-bar/commands/direct/index.ts +1 -1
- package/src/components/command-bar/commands/direct/runtime.ts +1 -1
- package/src/components/command-bar/commands/registry.ts +0 -11
- package/src/components/command-bar/helpers.test.ts +2 -2
- package/src/components/command-bar/helpers.ts +2 -6
- package/src/components/command-bar/keyboard-shortcuts.ts +0 -11
- package/src/components/command-bar/list/badge.test.ts +54 -0
- package/src/components/command-bar/list/badge.ts +62 -0
- package/src/components/command-bar/list/model.test.ts +103 -0
- package/src/components/command-bar/list/model.ts +61 -4
- package/src/components/command-bar/list/view.test.tsx +113 -0
- package/src/components/command-bar/list/view.tsx +147 -131
- package/src/components/command-bar/pane-templates/workflow.ts +1 -1
- package/src/components/command-bar/panel/body.tsx +51 -65
- package/src/components/command-bar/panel/index.tsx +48 -13
- package/src/components/command-bar/panel/layout.test.ts +139 -0
- package/src/components/command-bar/panel/layout.ts +65 -28
- package/src/components/command-bar/panel/native-surface.ts +24 -0
- package/src/components/command-bar/panel/prompt-binding.ts +54 -0
- package/src/components/command-bar/panel/runtime.ts +6 -3
- package/src/components/command-bar/panel/state.ts +41 -7
- package/src/components/command-bar/panel/types.ts +7 -1
- package/src/components/command-bar/routes/root/provider-search.ts +34 -15
- package/src/components/command-bar/routes/root/results.test.ts +161 -0
- package/src/components/command-bar/routes/root/results.ts +30 -28
- package/src/components/command-bar/routes/root/runtime.ts +37 -20
- package/src/components/command-bar/routes/root/search-providers.test.tsx +224 -0
- package/src/components/command-bar/routes/root/search-providers.ts +205 -0
- package/src/components/command-bar/routes/root/selection.ts +1 -12
- package/src/components/command-bar/routes/root/shortcuts.test.ts +8 -8
- package/src/components/command-bar/routes/ticker-search/actions.ts +10 -9
- package/src/components/command-bar/routes/ticker-search/results.test.ts +54 -1
- package/src/components/command-bar/routes/ticker-search/results.ts +60 -19
- package/src/components/command-bar/routes/ticker-search/route.ts +1 -0
- package/src/components/command-bar/routing/actions.ts +1 -81
- package/src/components/command-bar/routing/launch-request.ts +1 -1
- package/src/components/command-bar/routing/list-state.ts +6 -21
- package/src/components/command-bar/selection-runtime.ts +1 -1
- package/src/components/command-bar/surface/assist.test.tsx +14 -10
- package/src/components/command-bar/surface/environment.ts +8 -1
- package/src/components/command-bar/surface/index.test.tsx +84 -68
- package/src/components/command-bar/surface/index.tsx +33 -36
- package/src/components/command-bar/surface/test-harness.tsx +15 -3
- package/src/components/command-bar/theme-picker.tsx +43 -15
- package/src/components/command-bar/view-model.test.ts +53 -8
- package/src/components/command-bar/view-model.ts +43 -14
- package/src/components/command-bar/workflow/tickers.ts +1 -0
- package/src/components/command-bar/workflow/types.ts +1 -1
- package/src/components/data-table/export.test.ts +21 -0
- package/src/components/data-table/export.ts +21 -0
- package/src/components/data-table/view.test.tsx +45 -6
- package/src/components/data-table/view.tsx +55 -9
- package/src/components/index.ts +10 -2
- package/src/components/input-search-bar.test.tsx +36 -2
- package/src/components/input-search-bar.tsx +18 -1
- package/src/components/layout/header.test.tsx +57 -10
- package/src/components/layout/header.tsx +292 -149
- package/src/components/layout/market-summary.test.ts +81 -0
- package/src/components/layout/market-summary.ts +109 -0
- package/src/components/layout/shell/chrome.ts +96 -1
- package/src/components/layout/shell/index.tsx +11 -3
- package/src/components/layout/shell/menu.ts +9 -0
- package/src/components/layout/shell/pane/actions.ts +29 -0
- package/src/components/layout/shell/pane/management-shortcuts.ts +5 -0
- package/src/components/layout/shell/shortcuts.ts +3 -0
- package/src/components/layout/status-bar.test.tsx +9 -8
- package/src/components/layout/status-bar.tsx +85 -54
- package/src/components/onboarding/onboarding-frame.tsx +2 -26
- package/src/components/price-sparkline/index.ts +61 -34
- package/src/components/price-sparkline/view.tsx +1 -1
- package/src/components/sign-in-gate.test.tsx +128 -0
- package/src/components/sign-in-gate.tsx +149 -0
- package/src/components/speedometer-gauge/desktop.tsx +2 -12
- package/src/components/ticker/badge/list.tsx +17 -3
- package/src/components/ticker/list-table-view.tsx +6 -3
- package/src/components/ui/data-table/index.tsx +22 -4
- package/src/components/ui/data-table/opentui/index.tsx +165 -120
- package/src/components/ui/frame.tsx +28 -0
- package/src/components/ui/index.ts +3 -0
- package/src/components/ui/native-select.tsx +20 -10
- package/src/components/ui/select-button.tsx +138 -0
- package/src/components/ui/status.tsx +2 -2
- package/src/components/ui/table-layout.ts +1 -1
- package/src/components/use-double-click-activation.ts +7 -3
- package/src/core/app-services.ts +3 -3
- package/src/data/config/chart-settings.ts +4 -4
- package/src/data/config/layout.ts +12 -6
- package/src/data/config/store/index.test.ts +97 -0
- package/src/data/config/store/migrations.ts +41 -0
- package/src/data/config/store/normalize.ts +5 -3
- package/src/i18n/es.ts +6 -2
- package/src/i18n/ja.ts +6 -2
- package/src/i18n/ko.ts +6 -2
- package/src/i18n/zh-cn.ts +6 -2
- package/src/i18n/zh-tw.ts +6 -2
- package/src/layout-marketplace/gallery-terminal.tsx +126 -96
- package/src/layout-marketplace/gallery.test.tsx +65 -1
- package/src/layout-marketplace/pane-imagery.ts +1 -0
- package/src/layout-marketplace/payload.test.ts +17 -0
- package/src/layout-marketplace/payload.ts +40 -5
- package/src/market-data/coordinator/index.ts +3 -2
- package/src/market-data/coordinator/quotes.ts +173 -66
- package/src/market-data/coordinator/subscriptions.test.ts +215 -37
- package/src/pane-settings.ts +1 -1
- package/src/plugins/builtin/analytics/pane-model.ts +1 -1
- package/src/plugins/builtin/analytics/view.tsx +1 -1
- package/src/plugins/builtin/broker-manager/index.test.tsx +3 -2
- package/src/plugins/builtin/broker-manager/model.test.ts +2 -2
- package/src/plugins/builtin/chart-composer/catalog-inventory.ts +16 -2
- package/src/plugins/builtin/chart-composer/cli-options.ts +12 -9
- package/src/plugins/builtin/chart-composer/pane.tsx +22 -8
- package/src/plugins/builtin/chart-composer/settings.ts +2 -13
- package/src/plugins/builtin/chat/content/composer.tsx +8 -4
- package/src/plugins/builtin/cloud/auth-dialog.tsx +14 -228
- package/src/plugins/builtin/cloud/auth-form.tsx +277 -0
- package/src/plugins/builtin/cloud/plugin.tsx +1 -0
- package/src/plugins/builtin/composite-plugins.ts +16 -1
- package/src/plugins/builtin/correlation/relationship/model.ts +1 -1
- package/src/plugins/builtin/correlation/relationship/pane.tsx +2 -6
- package/src/plugins/builtin/correlation/relationship/view-model.ts +2 -2
- package/src/plugins/builtin/credit-conditions/index.test.tsx +12 -6
- package/src/plugins/builtin/credit-conditions/index.tsx +2 -21
- package/src/plugins/builtin/dividend-yield/index.tsx +1 -0
- package/src/plugins/builtin/dividend-yield/pane.tsx +1 -1
- package/src/plugins/builtin/earnings/index.tsx +1 -0
- package/src/plugins/builtin/earnings-calls/data.ts +223 -0
- package/src/plugins/builtin/earnings-calls/format.ts +49 -0
- package/src/plugins/builtin/earnings-calls/index.tsx +69 -0
- package/src/plugins/builtin/earnings-calls/pane.tsx +756 -0
- package/src/plugins/builtin/earnings-calls/prose.test.ts +36 -0
- package/src/plugins/builtin/earnings-calls/prose.ts +59 -0
- package/src/plugins/builtin/earnings-calls/transcript-view.tsx +334 -0
- package/src/plugins/builtin/econ/detail-view.tsx +1 -2
- package/src/plugins/builtin/econ/fred-series-map.ts +16 -1
- package/src/plugins/builtin/econ/index.tsx +3 -1
- package/src/plugins/builtin/econ-statistics/cache.ts +4 -0
- package/src/plugins/builtin/econ-statistics/client.ts +92 -0
- package/src/plugins/builtin/econ-statistics/defs.ts +66 -0
- package/src/plugins/builtin/econ-statistics/detail.tsx +154 -0
- package/src/plugins/builtin/econ-statistics/headless.test.ts +54 -0
- package/src/plugins/builtin/econ-statistics/headless.ts +171 -0
- package/src/plugins/builtin/econ-statistics/index.tsx +54 -0
- package/src/plugins/builtin/econ-statistics/pane.tsx +356 -0
- package/src/plugins/builtin/econ-statistics/stats.ts +522 -0
- package/src/plugins/builtin/econ-statistics/transform.test.ts +86 -0
- package/src/plugins/builtin/econ-statistics/transform.ts +85 -0
- package/src/plugins/builtin/econ-statistics/trend.ts +57 -0
- package/src/plugins/builtin/econ-statistics/view.ts +90 -0
- package/src/plugins/builtin/fear-greed/charts.tsx +7 -18
- package/src/plugins/builtin/fear-greed/data.ts +6 -1
- package/src/plugins/builtin/futures/index.tsx +1 -0
- package/src/plugins/builtin/fx-matrix/index.tsx +1 -0
- package/src/plugins/builtin/help/index.tsx +4 -0
- package/src/plugins/builtin/holders/index.tsx +1 -0
- package/src/plugins/builtin/insider/index.tsx +1 -0
- package/src/plugins/builtin/ipo-calendar/index.tsx +1 -0
- package/src/plugins/builtin/kelly-sizer/pane.tsx +1 -1
- package/src/plugins/builtin/kelly-sizer/sections.tsx +2 -3
- package/src/plugins/builtin/market-halts/index.tsx +1 -0
- package/src/plugins/builtin/market-movers/index.tsx +1 -0
- package/src/plugins/builtin/market-valuation/align.ts +122 -0
- package/src/plugins/builtin/market-valuation/cache.ts +32 -0
- package/src/plugins/builtin/market-valuation/chart-projection.ts +217 -0
- package/src/plugins/builtin/market-valuation/chart-series.ts +89 -0
- package/src/plugins/builtin/market-valuation/client.test.ts +141 -0
- package/src/plugins/builtin/market-valuation/client.ts +116 -0
- package/src/plugins/builtin/market-valuation/defs.ts +251 -0
- package/src/plugins/builtin/market-valuation/detail.tsx +159 -0
- package/src/plugins/builtin/market-valuation/headless.test.ts +58 -0
- package/src/plugins/builtin/market-valuation/headless.ts +170 -0
- package/src/plugins/builtin/market-valuation/index.tsx +64 -0
- package/src/plugins/builtin/market-valuation/indicators.ts +422 -0
- package/src/plugins/builtin/market-valuation/model.test.ts +350 -0
- package/src/plugins/builtin/market-valuation/model.ts +8 -0
- package/src/plugins/builtin/market-valuation/pane.test.tsx +247 -0
- package/src/plugins/builtin/market-valuation/pane.tsx +344 -0
- package/src/plugins/builtin/market-valuation/series.ts +12 -0
- package/src/plugins/builtin/market-valuation/settings.ts +38 -0
- package/src/plugins/builtin/market-valuation/sources.ts +130 -0
- package/src/plugins/builtin/market-valuation/trend.ts +89 -0
- package/src/plugins/builtin/market-valuation/view.ts +137 -0
- package/src/plugins/builtin/market-valuation/zone-scale/desktop.tsx +123 -0
- package/src/plugins/builtin/market-valuation/zone-scale/index.tsx +12 -0
- package/src/plugins/builtin/market-valuation/zone-scale/model.ts +60 -0
- package/src/plugins/builtin/market-valuation/zone-scale/terminal.tsx +94 -0
- package/src/plugins/builtin/news/wire/breaking/filters.test.ts +99 -0
- package/src/plugins/builtin/news/wire/breaking/filters.ts +110 -0
- package/src/plugins/builtin/news/wire/breaking/notifications.test.ts +157 -53
- package/src/plugins/builtin/news/wire/breaking/notifications.ts +91 -25
- package/src/plugins/builtin/news/wire/index.tsx +31 -44
- package/src/plugins/builtin/options/analytics.test.ts +83 -0
- package/src/plugins/builtin/options/analytics.ts +110 -0
- package/src/plugins/builtin/options/index.tsx +18 -2
- package/src/plugins/builtin/options/table.ts +121 -51
- package/src/plugins/builtin/options/types.ts +22 -15
- package/src/plugins/builtin/options/view.test.tsx +53 -1
- package/src/plugins/builtin/options/view.tsx +92 -41
- package/src/plugins/builtin/plugin-marketplace/feed.ts +80 -0
- package/src/plugins/builtin/plugin-marketplace/index.tsx +31 -0
- package/src/plugins/builtin/plugin-marketplace/model.test.ts +200 -0
- package/src/plugins/builtin/plugin-marketplace/model.ts +204 -0
- package/src/plugins/builtin/plugin-marketplace/pane.tsx +385 -0
- package/src/plugins/builtin/plugin-marketplace/store.ts +46 -0
- package/src/plugins/builtin/plugin-module.test.ts +2 -4
- package/src/plugins/builtin/plugin-module.ts +9 -8
- package/src/plugins/builtin/portfolio-list/index.tsx +1 -0
- package/src/plugins/builtin/research/index.tsx +4 -0
- package/src/plugins/builtin/research-search/command-bar-search.test.ts +81 -0
- package/src/plugins/builtin/research-search/command-bar-search.ts +175 -0
- package/src/plugins/builtin/research-search/data.ts +109 -0
- package/src/plugins/builtin/research-search/document-view.test.tsx +75 -0
- package/src/plugins/builtin/research-search/document-view.tsx +254 -0
- package/src/plugins/builtin/research-search/filter-bar.tsx +62 -0
- package/src/plugins/builtin/research-search/focus-handoff.ts +47 -0
- package/src/plugins/builtin/research-search/index.tsx +85 -0
- package/src/plugins/builtin/research-search/model.test.ts +40 -0
- package/src/plugins/builtin/research-search/model.ts +291 -0
- package/src/plugins/builtin/research-search/pane.test.tsx +241 -0
- package/src/plugins/builtin/research-search/pane.tsx +678 -0
- package/src/plugins/builtin/research-search/saved-view.tsx +171 -0
- package/src/plugins/builtin/research-search/snippet-text.tsx +35 -0
- package/src/plugins/builtin/research-search/snippet.test.ts +78 -0
- package/src/plugins/builtin/research-search/snippet.ts +134 -0
- package/src/plugins/builtin/scanner/flow-model.test.ts +11 -1
- package/src/plugins/builtin/scanner/flow-model.ts +29 -1
- package/src/plugins/builtin/scanner/flow-pane.tsx +78 -22
- package/src/plugins/builtin/scanner/index.ts +2 -0
- package/src/plugins/builtin/sec/index.tsx +1 -0
- package/src/plugins/builtin/sectors/index.tsx +1 -0
- package/src/plugins/builtin/shared/series-cache.ts +93 -0
- package/src/plugins/builtin/short-interest/index.tsx +1 -0
- package/src/plugins/builtin/short-interest/pane.tsx +1 -1
- package/src/plugins/builtin/thirteenf/index.tsx +1 -0
- package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +3 -5
- package/src/plugins/builtin/ticker-detail/index.tsx +2 -14
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +1 -1
- package/src/plugins/builtin/treasury-auctions/index.tsx +1 -0
- package/src/plugins/builtin/volatility/index.tsx +1 -1
- package/src/plugins/builtin/world-indices/index.tsx +1 -0
- package/src/plugins/builtin/world-venue-map/index.ts +27 -0
- package/src/plugins/builtin/world-venue-map/map.desktop.test.tsx +106 -0
- package/src/plugins/builtin/world-venue-map/map.tsx +481 -0
- package/src/plugins/builtin/world-venue-map/model.test.ts +85 -0
- package/src/plugins/builtin/world-venue-map/model.ts +268 -0
- package/src/plugins/builtin/world-venue-map/pane.tsx +300 -0
- package/src/plugins/builtin/world-venue-map/world-outlines.ts +2 -0
- package/src/plugins/builtin/yield-curve/index.tsx +1 -1
- package/src/plugins/bundle.test.ts +109 -0
- package/src/plugins/bundle.ts +139 -0
- package/src/plugins/catalog-backend.ts +6 -44
- package/src/plugins/catalog-browser.test.ts +1 -0
- package/src/plugins/catalog-browser.ts +12 -0
- package/src/plugins/catalog-manifest.test.ts +43 -0
- package/src/plugins/catalog-manifest.ts +92 -0
- package/src/plugins/catalog-ui.ts +20 -4
- package/src/plugins/catalog.ts +9 -2
- package/src/plugins/current-target.ts +28 -0
- package/src/plugins/host-contract.ts +37 -0
- package/src/plugins/host-link.ts +158 -0
- package/src/plugins/host-modules.ts +61 -0
- package/src/plugins/loader.ts +41 -22
- package/src/plugins/ownership.ts +1 -0
- package/src/plugins/prediction-markets/index.tsx +1 -0
- package/src/plugins/registry/context.ts +3 -0
- package/src/plugins/registry/contributions.ts +27 -0
- package/src/plugins/registry/index.test.ts +25 -0
- package/src/plugins/registry/index.ts +8 -0
- package/src/plugins/registry/pane-settings.test.ts +53 -0
- package/src/plugins/registry/pane-settings.ts +29 -3
- package/src/plugins/seed.test.ts +83 -0
- package/src/plugins/seed.ts +80 -0
- package/src/public/broker.ts +31 -0
- package/src/public/market-data.ts +9 -0
- package/src/public/pane-hooks.ts +57 -0
- package/src/public/public-api.test.ts +285 -0
- package/src/public/react.ts +62 -0
- package/src/public/test-support.ts +23 -0
- package/src/public/time-series.ts +8 -0
- package/src/public/utils.ts +77 -0
- package/src/remote/layout-helpers.ts +6 -8
- package/src/remote/resources.ts +2 -0
- package/src/remote/schema.ts +1 -0
- package/src/remote/semantic-tree.test.tsx +105 -0
- package/src/remote/semantic-tree.tsx +53 -35
- package/src/renderers/browser/main.tsx +6 -0
- package/src/renderers/browser/ui-host.tsx +11 -0
- package/src/renderers/cloudflare/worker.test.ts +19 -0
- package/src/renderers/cloudflare/worker.ts +1 -1
- package/src/renderers/electrobun/bun/desktop/host-requests.ts +9 -2
- package/src/renderers/electrobun/bun/external-plugins.ts +140 -0
- package/src/renderers/electrobun/bun/index.ts +6 -2
- package/src/renderers/electrobun/shared/protocol.ts +25 -0
- package/src/renderers/electrobun/view/build-assets.ts +0 -1
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +51 -1
- package/src/renderers/electrobun/view/external-plugins.test.ts +45 -0
- package/src/renderers/electrobun/view/external-plugins.ts +63 -0
- package/src/renderers/electrobun/view/host/ascii-text.test.ts +48 -0
- package/src/renderers/electrobun/view/host/ascii-text.ts +11 -1
- package/src/renderers/electrobun/view/host/chart-surface.tsx +38 -32
- package/src/renderers/electrobun/view/host/mouse.ts +16 -2
- package/src/renderers/electrobun/view/main.tsx +27 -2
- package/src/renderers/electrobun/view/styles.css +5 -0
- package/src/renderers/electrobun/view/toast-host.tsx +18 -0
- package/src/renderers/electrobun/view/ui-host.tsx +3 -0
- package/src/renderers/opentui/chart-surface.tsx +5 -1
- package/src/renderers/opentui/host.tsx +20 -2
- package/src/renderers/opentui/interaction-performance.test.ts +79 -0
- package/src/renderers/opentui/interaction-performance.ts +188 -0
- package/src/renderers/opentui/start.tsx +26 -1
- package/src/renderers/opentui/test-utils.tsx +13 -0
- package/src/renderers/opentui/toast-host.tsx +26 -2
- package/src/renderers/opentui/ui-host.tsx +1 -0
- package/src/sources/provider-router/search.test.ts +191 -0
- package/src/sources/provider-router/search.ts +92 -39
- package/src/state/app/context/index.tsx +2 -0
- package/src/state/app/context/selector.test.tsx +33 -1
- package/src/state/hooks/quote-streaming.test.tsx +93 -0
- package/src/state/hooks/quote-streaming.ts +106 -30
- package/src/state/pane-table-export-registry.ts +50 -0
- package/src/theme/color-utils.ts +1 -1
- package/src/theme/colors.ts +50 -0
- package/src/theme/themes.test.ts +15 -2
- package/src/theme/themes.ts +19 -1
- package/src/tickers/search/index.test.ts +26 -0
- package/src/tickers/search/index.ts +42 -17
- package/src/tickers/search/ranking.ts +14 -0
- package/src/time-series/chart-data.test.ts +216 -0
- package/src/time-series/range.ts +12 -0
- package/src/time-series/resolution.test.ts +25 -26
- package/src/time-series/resolution.ts +44 -25
- package/src/time-series/resolve.ts +7 -0
- package/src/time-series/spec.ts +5 -5
- package/src/time-series/types.ts +3 -1
- package/src/time-series/use-chart-resolution.ts +5 -0
- package/src/types/config.ts +123 -3
- package/src/types/data-provider.ts +11 -0
- package/src/types/headless.ts +161 -0
- package/src/types/plugin.ts +104 -20
- package/src/ui/host.tsx +19 -1
- package/src/ui/index.tsx +1 -0
- package/src/ui/toast.tsx +8 -4
- package/src/utils/csv.test.ts +13 -0
- package/src/utils/csv.ts +37 -0
- package/src/utils/format.ts +35 -0
- package/src/utils/fuzzy-search.test.ts +94 -0
- package/src/utils/fuzzy-search.ts +81 -22
- package/src/utils/save-text-file.test.ts +24 -0
- package/src/utils/save-text-file.ts +36 -0
- package/src/utils/shortcut-labels.ts +14 -0
- package/src/components/chart/core/axis-format.ts +0 -157
- package/src/components/chart/core/index.test.ts +0 -1075
- package/src/components/chart/core/projection.ts +0 -357
- package/src/components/chart/core/render-utils.ts +0 -4
- package/src/components/chart/core/renderer.ts +0 -244
- package/src/components/chart/core/scene.ts +0 -180
- package/src/components/chart/core/time-axis.ts +0 -330
- package/src/components/chart/cursor-motion.ts +0 -47
- package/src/components/chart/indicators/types.ts +0 -26
- package/src/components/chart/market-session.ts +0 -176
- package/src/components/chart/multi-line/renderer.test.ts +0 -83
- package/src/components/chart/multi-line/renderer.ts +0 -161
- package/src/components/chart/multi-line/scene.ts +0 -188
- package/src/components/chart/native/raster/layout.ts +0 -129
- package/src/components/chart/native/raster/price-chart.ts +0 -244
- package/src/components/chart/rendering/chart-draw.ts +0 -270
- package/src/components/chart/rendering/geometry.ts +0 -95
- package/src/components/chart/rendering/pixel-buffer.ts +0 -267
- package/src/components/chart/scatter-chart-renderer.test.ts +0 -31
- package/src/components/chart/scatter-chart-renderer.ts +0 -223
- package/src/components/chart/static/chart/surface.tsx +0 -358
- package/src/components/command-bar/routes/root/article-results.test.ts +0 -83
- package/src/components/command-bar/routes/root/article-results.ts +0 -55
- package/src/plugins/builtin/news/wire/article-search.test.ts +0 -72
- package/src/plugins/builtin/news/wire/article-search.ts +0 -140
- package/src/plugins/builtin/substack/api/auth.ts +0 -185
- package/src/plugins/builtin/substack/api/cache.ts +0 -82
- package/src/plugins/builtin/substack/api/loaders.ts +0 -170
- package/src/plugins/builtin/substack/api/store.ts +0 -186
- package/src/plugins/builtin/substack/api/types.ts +0 -42
- package/src/plugins/builtin/substack/api.test.ts +0 -298
- package/src/plugins/builtin/substack/article-detail.tsx +0 -397
- package/src/plugins/builtin/substack/article-stack.tsx +0 -133
- package/src/plugins/builtin/substack/content.ts +0 -478
- package/src/plugins/builtin/substack/feed-tabs.tsx +0 -44
- package/src/plugins/builtin/substack/index.tsx +0 -49
- package/src/plugins/builtin/substack/login-view.tsx +0 -126
- package/src/plugins/builtin/substack/model.test.ts +0 -155
- package/src/plugins/builtin/substack/normalize.ts +0 -343
- package/src/plugins/builtin/substack/pane-footer.ts +0 -52
- package/src/plugins/builtin/substack/pane-state.ts +0 -170
- package/src/plugins/builtin/substack/pane.tsx +0 -547
- package/src/plugins/builtin/substack/read-state.ts +0 -30
- package/src/plugins/builtin/substack/table.ts +0 -111
- package/src/plugins/builtin/substack/types.ts +0 -71
- package/src/plugins/builtin/substack/utils.ts +0 -131
- package/src/plugins/builtin/ticker-detail/data-panes/provider-search.tsx +0 -229
- package/src/plugins/ibkr/account-cache.test.ts +0 -102
- package/src/plugins/ibkr/account-cache.ts +0 -24
- package/src/plugins/ibkr/broker-adapter.ts +0 -286
- package/src/plugins/ibkr/config.test.ts +0 -79
- package/src/plugins/ibkr/config.ts +0 -250
- package/src/plugins/ibkr/dialogs.tsx +0 -40
- package/src/plugins/ibkr/flex/index.test.ts +0 -264
- package/src/plugins/ibkr/flex/index.ts +0 -367
- package/src/plugins/ibkr/flex/statement-client.ts +0 -235
- package/src/plugins/ibkr/fundamental-parser.ts +0 -149
- package/src/plugins/ibkr/gateway/account-loaders.ts +0 -266
- package/src/plugins/ibkr/gateway/account-summary.ts +0 -164
- package/src/plugins/ibkr/gateway/client-lock.ts +0 -154
- package/src/plugins/ibkr/gateway/connection-events.ts +0 -114
- package/src/plugins/ibkr/gateway/connection.ts +0 -152
- package/src/plugins/ibkr/gateway/contracts.ts +0 -132
- package/src/plugins/ibkr/gateway/fundamentals.ts +0 -83
- package/src/plugins/ibkr/gateway/helpers.ts +0 -33
- package/src/plugins/ibkr/gateway/history-requests.ts +0 -158
- package/src/plugins/ibkr/gateway/history.ts +0 -120
- package/src/plugins/ibkr/gateway/instrument-lookup.ts +0 -117
- package/src/plugins/ibkr/gateway/market-data.ts +0 -345
- package/src/plugins/ibkr/gateway/order-execution.ts +0 -218
- package/src/plugins/ibkr/gateway/orders.ts +0 -63
- package/src/plugins/ibkr/gateway/price-normalization.test.ts +0 -44
- package/src/plugins/ibkr/gateway/price-normalization.ts +0 -50
- package/src/plugins/ibkr/gateway/quote-stream-controller.ts +0 -203
- package/src/plugins/ibkr/gateway/quote-stream.ts +0 -171
- package/src/plugins/ibkr/gateway/selection.ts +0 -51
- package/src/plugins/ibkr/gateway/service/index.test.ts +0 -675
- package/src/plugins/ibkr/gateway/service/index.ts +0 -429
- package/src/plugins/ibkr/gateway/service/lifecycle.ts +0 -191
- package/src/plugins/ibkr/gateway/service/manager.ts +0 -52
- package/src/plugins/ibkr/gateway/service/market-data.ts +0 -48
- package/src/plugins/ibkr/gateway/service/native-loader.ts +0 -12
- package/src/plugins/ibkr/gateway/service/native.ts +0 -543
- package/src/plugins/ibkr/gateway/timeouts.ts +0 -13
- package/src/plugins/ibkr/gateway/types.ts +0 -27
- package/src/plugins/ibkr/index.test.tsx +0 -162
- package/src/plugins/ibkr/index.tsx +0 -159
- package/src/plugins/ibkr/instance-selection.test.ts +0 -120
- package/src/plugins/ibkr/instance-selection.ts +0 -36
- package/src/plugins/ibkr/portfolio-performance.test.ts +0 -32
- package/src/plugins/ibkr/portfolio-performance.ts +0 -129
- package/src/plugins/ibkr/trade/badge.tsx +0 -28
- package/src/plugins/ibkr/trade/dialogs.tsx +0 -44
- package/src/plugins/ibkr/trade/preview-panel.tsx +0 -130
- package/src/plugins/ibkr/trade/tab/actions.tsx +0 -443
- package/src/plugins/ibkr/trade/tab/field-editors.tsx +0 -79
- package/src/plugins/ibkr/trade/tab/footer.ts +0 -53
- package/src/plugins/ibkr/trade/tab/header.tsx +0 -167
- package/src/plugins/ibkr/trade/tab/index.test.tsx +0 -178
- package/src/plugins/ibkr/trade/tab/index.tsx +0 -298
- package/src/plugins/ibkr/trade/tab/model.ts +0 -159
- package/src/plugins/ibkr/trade/tab/order-request.ts +0 -64
- package/src/plugins/ibkr/trade/tab/shortcuts.ts +0 -89
- package/src/plugins/ibkr/trade/tab/state-sync.ts +0 -86
- package/src/plugins/ibkr/trade/ticket-panel.tsx +0 -301
- package/src/plugins/ibkr/trade/utils.test.ts +0 -175
- package/src/plugins/ibkr/trade/utils.ts +0 -144
- package/src/plugins/ibkr/trading/pane-view.tsx +0 -237
- package/src/plugins/ibkr/trading/pane.tsx +0 -332
- package/src/plugins/ibkr/trading/state.test.ts +0 -109
- package/src/plugins/ibkr/trading/state.ts +0 -335
|
@@ -13,14 +13,27 @@ import {
|
|
|
13
13
|
commandBarText,
|
|
14
14
|
} from "../../../theme/colors";
|
|
15
15
|
import { useThemeColors } from "../../../theme/theme-context";
|
|
16
|
+
import { t } from "../../../i18n";
|
|
17
|
+
import type { ListScreenState } from "../list/model";
|
|
16
18
|
import { CommandBarPanelBody } from "./body";
|
|
19
|
+
import { NATIVE_COMMAND_SURFACE, nativeCommandSurfaceBorder } from "./native-surface";
|
|
20
|
+
import { publishCommandBarPrompt } from "./prompt-binding";
|
|
17
21
|
import type { CommandBarPanelProps } from "./types";
|
|
18
22
|
|
|
19
23
|
const COMMAND_BAR_OVERLAY_Z_INDEX = 2_147_483_646;
|
|
20
24
|
const COMMAND_BAR_PANEL_Z_INDEX = 2_147_483_647;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The root screen keeps the closed prompt's own words. Opening the bar puts the
|
|
28
|
+
* caret in the same input the header was already showing, so changing the
|
|
29
|
+
* placeholder underneath it read as the control being swapped out. Nested
|
|
30
|
+
* screens are a different screen and say so.
|
|
31
|
+
*/
|
|
32
|
+
function resolvePromptPlaceholder(listState: ListScreenState): string {
|
|
33
|
+
if (listState.kind === "root") return t("Search or run a command");
|
|
34
|
+
if (listState.title === "Security Description") return t("Search tickers");
|
|
35
|
+
return t("Filter");
|
|
36
|
+
}
|
|
24
37
|
|
|
25
38
|
export function CommandBarPanel({
|
|
26
39
|
bodyHeight,
|
|
@@ -29,6 +42,7 @@ export function CommandBarPanel({
|
|
|
29
42
|
contentPadding,
|
|
30
43
|
currentRoute,
|
|
31
44
|
getWorkflowInputRef,
|
|
45
|
+
hasChromeRow,
|
|
32
46
|
labelWidth,
|
|
33
47
|
listBodyHeight,
|
|
34
48
|
nativeListRows,
|
|
@@ -58,7 +72,6 @@ export function CommandBarPanel({
|
|
|
58
72
|
panelBounds,
|
|
59
73
|
queryDisplayWidth,
|
|
60
74
|
rootGhostSuffix,
|
|
61
|
-
rootQueryLength,
|
|
62
75
|
rootShortcutFeedback,
|
|
63
76
|
selectedScrollRowIndex,
|
|
64
77
|
termHeight,
|
|
@@ -95,6 +108,24 @@ export function CommandBarPanel({
|
|
|
95
108
|
}
|
|
96
109
|
}, [listBodyHeight, nativeListScrollRef, selectedScrollRowIndex, visibleListState?.kind, visibleListState?.query]);
|
|
97
110
|
|
|
111
|
+
// The header prompt is the bar's input while a list screen is showing. A
|
|
112
|
+
// workflow owns its own fields, so it publishes nothing and the prompt goes
|
|
113
|
+
// quiet rather than taking focus from them.
|
|
114
|
+
useLayoutEffect(() => {
|
|
115
|
+
if (!visibleListState) {
|
|
116
|
+
publishCommandBarPrompt(null);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
publishCommandBarPrompt({
|
|
120
|
+
screenKey: `${visibleListState.kind}:${visibleListState.title}`,
|
|
121
|
+
query: visibleListState.query,
|
|
122
|
+
placeholder: resolvePromptPlaceholder(visibleListState),
|
|
123
|
+
ghostSuffix: visibleListState.kind === "root" ? rootGhostSuffix : null,
|
|
124
|
+
onQueryChange,
|
|
125
|
+
});
|
|
126
|
+
}, [onQueryChange, rootGhostSuffix, visibleListState]);
|
|
127
|
+
useLayoutEffect(() => () => publishCommandBarPrompt(null), []);
|
|
128
|
+
|
|
98
129
|
useLayoutEffect(() => {
|
|
99
130
|
onNativeOccluderChange?.(nativeOccluderRect);
|
|
100
131
|
return () => {
|
|
@@ -109,12 +140,14 @@ export function CommandBarPanel({
|
|
|
109
140
|
]);
|
|
110
141
|
|
|
111
142
|
return (
|
|
143
|
+
// The click-away overlay starts where the sheet does: the header above it
|
|
144
|
+
// holds the bar's input, and a click there must reach it, not close the bar.
|
|
112
145
|
<Box
|
|
113
146
|
position="absolute"
|
|
114
|
-
top={
|
|
147
|
+
top={panelBounds.y}
|
|
115
148
|
left={0}
|
|
116
149
|
width={termWidth}
|
|
117
|
-
height={termHeight}
|
|
150
|
+
height={Math.max(0, termHeight - panelBounds.y)}
|
|
118
151
|
zIndex={nativePaneChrome ? COMMAND_BAR_OVERLAY_Z_INDEX : 100}
|
|
119
152
|
onMouseDown={(event: any) => {
|
|
120
153
|
event.stopPropagation?.();
|
|
@@ -124,7 +157,7 @@ export function CommandBarPanel({
|
|
|
124
157
|
>
|
|
125
158
|
<Box
|
|
126
159
|
position="absolute"
|
|
127
|
-
top={
|
|
160
|
+
top={0}
|
|
128
161
|
left={panelBounds.x}
|
|
129
162
|
width={panelBounds.width}
|
|
130
163
|
height={panelBounds.height}
|
|
@@ -136,10 +169,14 @@ export function CommandBarPanel({
|
|
|
136
169
|
}}
|
|
137
170
|
data-gloom-role="command-bar-panel"
|
|
138
171
|
style={nativePaneChrome ? {
|
|
139
|
-
|
|
140
|
-
|
|
172
|
+
// The lower half of the control the header input opens: rounded and
|
|
173
|
+
// bordered along its three free edges, open where the input sits.
|
|
174
|
+
border: `1px solid ${nativeCommandSurfaceBorder(colors)}`,
|
|
175
|
+
borderTopWidth: 0,
|
|
176
|
+
borderRadius: `0 0 ${NATIVE_COMMAND_SURFACE.radiusPx}px ${NATIVE_COMMAND_SURFACE.radiusPx}px`,
|
|
177
|
+
boxShadow: NATIVE_COMMAND_SURFACE.shadow,
|
|
141
178
|
overflow: "hidden",
|
|
142
|
-
padding: `${
|
|
179
|
+
padding: `${NATIVE_COMMAND_SURFACE.paddingYPx}px ${NATIVE_COMMAND_SURFACE.paddingXPx}px`,
|
|
143
180
|
} : undefined}
|
|
144
181
|
>
|
|
145
182
|
<CommandBarPanelBody
|
|
@@ -149,6 +186,7 @@ export function CommandBarPanel({
|
|
|
149
186
|
contentPadding={contentPadding}
|
|
150
187
|
currentRoute={currentRoute}
|
|
151
188
|
getWorkflowInputRef={getWorkflowInputRef}
|
|
189
|
+
hasChromeRow={hasChromeRow}
|
|
152
190
|
labelWidth={labelWidth}
|
|
153
191
|
listBodyHeight={listBodyHeight}
|
|
154
192
|
nativeListRows={nativeListRows}
|
|
@@ -167,7 +205,6 @@ export function CommandBarPanel({
|
|
|
167
205
|
onMultiSelectSelect={onMultiSelectSelect}
|
|
168
206
|
onMultiSelectToggle={onMultiSelectToggle}
|
|
169
207
|
onNativeSelectRef={onNativeSelectRef}
|
|
170
|
-
onQueryChange={onQueryChange}
|
|
171
208
|
onThemeCommit={onThemeCommit}
|
|
172
209
|
onThemePreview={onThemePreview}
|
|
173
210
|
onWorkflowActiveTextareaSync={onWorkflowActiveTextareaSync}
|
|
@@ -185,8 +222,6 @@ export function CommandBarPanel({
|
|
|
185
222
|
panelBg,
|
|
186
223
|
}}
|
|
187
224
|
queryDisplayWidth={queryDisplayWidth}
|
|
188
|
-
rootGhostSuffix={rootGhostSuffix}
|
|
189
|
-
rootQueryLength={rootQueryLength}
|
|
190
225
|
rootShortcutFeedback={rootShortcutFeedback}
|
|
191
226
|
themePickerActive={themePickerActive}
|
|
192
227
|
themePickerFilter={themePickerFilter}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import { resolveAppHeaderHeightCells, resolveHeaderPromptGeometry } from "../../layout/shell/chrome";
|
|
3
|
+
import { resolveCommandBarPanelLayout } from "./layout";
|
|
4
|
+
|
|
5
|
+
const BASE = {
|
|
6
|
+
cellHeightPx: 0,
|
|
7
|
+
cellWidthPx: 0,
|
|
8
|
+
currentRoute: null,
|
|
9
|
+
hasRootFeedback: false,
|
|
10
|
+
hasVisibleListState: true,
|
|
11
|
+
nativeListRowCount: 8,
|
|
12
|
+
nativePaneChrome: false,
|
|
13
|
+
showCustomMultiSelectPicker: false,
|
|
14
|
+
themePickerActive: false,
|
|
15
|
+
themePickerRowCount: 0,
|
|
16
|
+
titleBarOverlay: undefined as boolean | undefined,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const DESKTOP = {
|
|
20
|
+
...BASE,
|
|
21
|
+
cellHeightPx: 18,
|
|
22
|
+
cellWidthPx: 8,
|
|
23
|
+
nativePaneChrome: true,
|
|
24
|
+
nativeWindowChrome: true,
|
|
25
|
+
titleBarOverlay: true,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
describe("command bar sheet geometry", () => {
|
|
29
|
+
/**
|
|
30
|
+
* The sheet is the header prompt expanding downward: same left edge, same
|
|
31
|
+
* width, top edge on the header's bottom edge. Any drift between the two
|
|
32
|
+
* reads as a banner, or a floating window, hanging near the prompt.
|
|
33
|
+
*
|
|
34
|
+
* The widths are pinned because the header now spends columns on the market
|
|
35
|
+
* cluster as well as the update status, and the sheet pays for them: a
|
|
36
|
+
* change there silently narrows every result row.
|
|
37
|
+
*/
|
|
38
|
+
test("shares the prompt's left edge and width on every window size", () => {
|
|
39
|
+
const expectedWidths: Record<number, number> = { 46: 40, 80: 49, 120: 63, 200: 96 };
|
|
40
|
+
for (const termWidth of [46, 80, 120, 200]) {
|
|
41
|
+
const layout = resolveCommandBarPanelLayout({ ...BASE, termHeight: 40, termWidth });
|
|
42
|
+
const prompt = resolveHeaderPromptGeometry({ termWidth });
|
|
43
|
+
expect(prompt.width).toBe(expectedWidths[termWidth]!);
|
|
44
|
+
expect(prompt.left + prompt.width + prompt.marketColumns).toBeLessThanOrEqual(termWidth);
|
|
45
|
+
expect(layout.panelBounds).toEqual({
|
|
46
|
+
x: prompt.left,
|
|
47
|
+
y: resolveAppHeaderHeightCells({}),
|
|
48
|
+
width: prompt.width,
|
|
49
|
+
height: layout.panelBounds.height,
|
|
50
|
+
});
|
|
51
|
+
expect(layout.nativeOccluderRect).toEqual({
|
|
52
|
+
x: prompt.left,
|
|
53
|
+
y: 0,
|
|
54
|
+
width: prompt.width,
|
|
55
|
+
height: layout.panelBounds.height,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// A titlebar-overlay header is 28px tall, so its height in cells is fractional.
|
|
60
|
+
const desktop = resolveCommandBarPanelLayout({ ...DESKTOP, termHeight: 40, termWidth: 200 });
|
|
61
|
+
const desktopPrompt = resolveHeaderPromptGeometry({
|
|
62
|
+
nativePaneChrome: true,
|
|
63
|
+
nativeWindowChrome: true,
|
|
64
|
+
termWidth: 200,
|
|
65
|
+
titleBarOverlay: true,
|
|
66
|
+
});
|
|
67
|
+
expect(desktop.panelBounds.x).toBe(desktopPrompt.left);
|
|
68
|
+
expect(desktop.panelBounds.width).toBe(desktopPrompt.width);
|
|
69
|
+
expect(desktop.panelBounds.y).toBeCloseTo(28 / 18, 6);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* The selection bar is the row box, padding included, so the columns have
|
|
74
|
+
* to add back up to the sheet: nothing capped short of it, nothing past it.
|
|
75
|
+
*/
|
|
76
|
+
test("fills the sheet with the results columns", () => {
|
|
77
|
+
const terminal = resolveCommandBarPanelLayout({ ...BASE, termHeight: 40, termWidth: 200 });
|
|
78
|
+
expect(terminal.queryDisplayWidth + terminal.contentPadding * 2).toBe(terminal.panelBounds.width);
|
|
79
|
+
expect(terminal.labelWidth + terminal.trailingWidth).toBe(terminal.resultsInnerWidth);
|
|
80
|
+
expect(terminal.trailingWidth).toBe(12);
|
|
81
|
+
|
|
82
|
+
const desktop = resolveCommandBarPanelLayout({ ...DESKTOP, termHeight: 40, termWidth: 200 });
|
|
83
|
+
expect(desktop.queryDisplayWidth + desktop.contentPadding * 2 + desktop.nativePanelPaddingColumns)
|
|
84
|
+
.toBe(desktop.panelBounds.width);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* A 24-row terminal keeps its 16 rows; from there the list takes about
|
|
89
|
+
* 55% of the window, up to 26 rows, so a tall window shows more of a
|
|
90
|
+
* multi-line document list. The chrome row and its blank line come out of
|
|
91
|
+
* the same budget, so the sheet's footprint does not grow when they show.
|
|
92
|
+
*/
|
|
93
|
+
test("grows with the window past 24 rows and caps at 26", () => {
|
|
94
|
+
const expected: Array<[number, number]> = [[24, 16], [40, 22], [60, 26]];
|
|
95
|
+
for (const [termHeight, bodyHeight] of expected) {
|
|
96
|
+
const plain = resolveCommandBarPanelLayout({ ...BASE, termHeight, termWidth: 120 });
|
|
97
|
+
expect(plain.bodyHeight).toBe(bodyHeight);
|
|
98
|
+
expect(plain.hasChromeRow).toBe(false);
|
|
99
|
+
expect(plain.panelBounds.height).toBe(bodyHeight + 2);
|
|
100
|
+
|
|
101
|
+
const withChrome = resolveCommandBarPanelLayout({ ...BASE, hasRootFeedback: true, termHeight, termWidth: 120 });
|
|
102
|
+
expect(withChrome.hasChromeRow).toBe(true);
|
|
103
|
+
expect(withChrome.panelBounds.height).toBe(withChrome.bodyHeight + 4);
|
|
104
|
+
expect(withChrome.panelBounds.height).toBeLessThanOrEqual(plain.panelBounds.height);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* The theme picker keeps its own rows rather than a list state, so it has to
|
|
110
|
+
* hand the layout a count of its own. Without one it was excluded from the
|
|
111
|
+
* compact path entirely and the sheet opened at full height over a dozen
|
|
112
|
+
* themes.
|
|
113
|
+
*/
|
|
114
|
+
test("sizes the desktop sheet to the theme picker's own rows", () => {
|
|
115
|
+
const picker = (themePickerRowCount: number) => resolveCommandBarPanelLayout({
|
|
116
|
+
...DESKTOP,
|
|
117
|
+
hasVisibleListState: false,
|
|
118
|
+
termHeight: 60,
|
|
119
|
+
termWidth: 200,
|
|
120
|
+
themePickerActive: true,
|
|
121
|
+
themePickerRowCount,
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
expect(picker(4).bodyHeight).toBe(4);
|
|
125
|
+
expect(picker(1).bodyHeight).toBe(1);
|
|
126
|
+
// More themes than the sheet can hold falls back to the full budget and scrolls.
|
|
127
|
+
expect(picker(200).bodyHeight).toBe(picker(200).baseBodyHeight);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
/** The bottom rows of a short terminal stay clear at every sheet height. */
|
|
131
|
+
test("never reaches the last terminal row", () => {
|
|
132
|
+
for (const termHeight of [18, 24, 40]) {
|
|
133
|
+
for (const hasRootFeedback of [false, true]) {
|
|
134
|
+
const layout = resolveCommandBarPanelLayout({ ...BASE, hasRootFeedback, termHeight, termWidth: 80 });
|
|
135
|
+
expect(layout.panelBounds.y + layout.panelBounds.height).toBeLessThan(termHeight - 1);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
});
|
|
@@ -1,13 +1,30 @@
|
|
|
1
1
|
import type { LayoutBounds } from "../../../plugins/pane-manager";
|
|
2
|
-
import { resolveAppHeaderHeightCells } from "../../layout/shell/chrome";
|
|
2
|
+
import { resolveAppHeaderHeightCells, resolveHeaderPromptGeometry } from "../../layout/shell/chrome";
|
|
3
3
|
import { estimateWorkflowBodyRows } from "../workflow/fields";
|
|
4
|
+
import { NATIVE_COMMAND_SURFACE } from "./native-surface";
|
|
4
5
|
import type { CommandBarRoute } from "../workflow/types";
|
|
5
6
|
|
|
7
|
+
const BODY_MIN_ROWS = 9;
|
|
8
|
+
const BODY_MAX_ROWS = 26;
|
|
9
|
+
/** Rows a short window keeps regardless of its share, so 24-row terminals lose nothing. */
|
|
10
|
+
const BODY_SHORT_WINDOW_ROWS = 16;
|
|
11
|
+
/** Share of the window a tall one gives the list; multi-line document rows need the room. */
|
|
12
|
+
const BODY_HEIGHT_SHARE = 0.55;
|
|
13
|
+
/** Rows of the app that stay visible under the sheet on the terminal. */
|
|
14
|
+
const TERMINAL_BOTTOM_CLEARANCE = 6;
|
|
15
|
+
const DESKTOP_BOTTOM_CLEARANCE = 4;
|
|
16
|
+
/** One padding row above the list and one below. */
|
|
17
|
+
const SHEET_PADDING_ROWS = 2;
|
|
18
|
+
/** The chrome row plus the blank line that separates it from the first heading. */
|
|
19
|
+
const CHROME_ROWS = 2;
|
|
20
|
+
|
|
6
21
|
export interface CommandBarPanelLayout {
|
|
7
22
|
barWidth: number;
|
|
8
23
|
baseBodyHeight: number;
|
|
9
24
|
bodyHeight: number;
|
|
10
25
|
contentPadding: number;
|
|
26
|
+
/** True when the sheet opens with a chrome row (back link, feedback) above the list. */
|
|
27
|
+
hasChromeRow: boolean;
|
|
11
28
|
listBodyHeight: number;
|
|
12
29
|
nativeOccluderRect: LayoutBounds;
|
|
13
30
|
nativePanelPaddingColumns: number;
|
|
@@ -23,67 +40,84 @@ export function resolveCommandBarPanelLayout({
|
|
|
23
40
|
cellHeightPx,
|
|
24
41
|
cellWidthPx,
|
|
25
42
|
currentRoute,
|
|
43
|
+
hasRootFeedback,
|
|
26
44
|
hasVisibleListState,
|
|
27
45
|
nativeListRowCount,
|
|
28
46
|
nativePaneChrome,
|
|
47
|
+
nativeWindowChrome,
|
|
29
48
|
showCustomMultiSelectPicker,
|
|
30
49
|
termHeight,
|
|
31
50
|
termWidth,
|
|
32
51
|
themePickerActive,
|
|
52
|
+
themePickerRowCount,
|
|
33
53
|
titleBarOverlay,
|
|
34
54
|
}: {
|
|
35
55
|
cellHeightPx: number;
|
|
36
56
|
cellWidthPx: number;
|
|
37
57
|
currentRoute: CommandBarRoute | null;
|
|
58
|
+
hasRootFeedback: boolean;
|
|
38
59
|
hasVisibleListState: boolean;
|
|
39
60
|
nativeListRowCount: number;
|
|
40
61
|
nativePaneChrome: boolean;
|
|
62
|
+
nativeWindowChrome?: boolean;
|
|
41
63
|
showCustomMultiSelectPicker: boolean;
|
|
42
64
|
termHeight: number;
|
|
43
65
|
termWidth: number;
|
|
44
66
|
themePickerActive: boolean;
|
|
67
|
+
themePickerRowCount: number;
|
|
45
68
|
titleBarOverlay: boolean | undefined;
|
|
46
69
|
}): CommandBarPanelLayout {
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
: Math.max(42, Math.min(72, termWidth - 8, Math.floor(termWidth * 0.68)));
|
|
50
|
-
const baseBodyHeight = Math.min(16, Math.max(9, termHeight - 9));
|
|
70
|
+
const prompt = resolveHeaderPromptGeometry({ nativePaneChrome, nativeWindowChrome, termWidth, titleBarOverlay });
|
|
71
|
+
const barWidth = prompt.width;
|
|
51
72
|
const contentPadding = nativePaneChrome ? 1 : 3;
|
|
73
|
+
const nativePanelPaddingColumns = nativePaneChrome
|
|
74
|
+
? Math.ceil((NATIVE_COMMAND_SURFACE.paddingXPx * 2) / Math.max(1, cellWidthPx))
|
|
75
|
+
: 0;
|
|
76
|
+
const nativePanelPaddingRows = nativePaneChrome
|
|
77
|
+
? Math.ceil((NATIVE_COMMAND_SURFACE.paddingYPx * 2) / Math.max(1, cellHeightPx))
|
|
78
|
+
: 0;
|
|
79
|
+
// A nested screen shows its back link; the root shows shortcut feedback when
|
|
80
|
+
// there is any. Otherwise the list starts right under the padding row.
|
|
81
|
+
const hasChromeRow = currentRoute !== null || hasRootFeedback;
|
|
82
|
+
const paddingRows = nativePaneChrome ? nativePanelPaddingRows : SHEET_PADDING_ROWS;
|
|
83
|
+
const chromeRows = hasChromeRow ? CHROME_ROWS : 0;
|
|
84
|
+
const bottomClearance = nativePaneChrome ? DESKTOP_BOTTOM_CLEARANCE : TERMINAL_BOTTOM_CLEARANCE;
|
|
85
|
+
// Budgeted for a sheet without a chrome row; the row and its blank line are
|
|
86
|
+
// paid out of the list, so the sheet's footprint does not jump when a typed
|
|
87
|
+
// prefix brings feedback or a nested screen brings its back link.
|
|
88
|
+
const listBudget = Math.max(
|
|
89
|
+
BODY_MIN_ROWS,
|
|
90
|
+
Math.min(
|
|
91
|
+
BODY_MAX_ROWS,
|
|
92
|
+
termHeight - bottomClearance - paddingRows,
|
|
93
|
+
Math.max(BODY_SHORT_WINDOW_ROWS, Math.floor(termHeight * BODY_HEIGHT_SHARE)),
|
|
94
|
+
),
|
|
95
|
+
);
|
|
96
|
+
const baseBodyHeight = Math.max(BODY_MIN_ROWS, listBudget - chromeRows);
|
|
52
97
|
const workflowBodyHeight = currentRoute?.kind === "workflow"
|
|
53
98
|
? Math.min(
|
|
54
|
-
Math.max(
|
|
99
|
+
Math.max(BODY_MIN_ROWS, termHeight - bottomClearance - paddingRows - chromeRows),
|
|
55
100
|
Math.max(7, estimateWorkflowBodyRows(currentRoute)),
|
|
56
101
|
)
|
|
57
102
|
: baseBodyHeight;
|
|
103
|
+
// The theme picker keeps its own rows rather than a list state, so it reports
|
|
104
|
+
// a count of its own; without one the sheet used to open at full height over
|
|
105
|
+
// a dozen themes.
|
|
106
|
+
const compactRowCount = themePickerActive ? themePickerRowCount : nativeListRowCount;
|
|
58
107
|
const shouldUseCompactListHeight = nativePaneChrome
|
|
59
|
-
&& hasVisibleListState
|
|
60
|
-
&& !themePickerActive
|
|
108
|
+
&& (hasVisibleListState || themePickerActive)
|
|
61
109
|
&& !showCustomMultiSelectPicker;
|
|
62
110
|
const listBodyHeight = shouldUseCompactListHeight
|
|
63
|
-
? Math.min(baseBodyHeight, Math.max(1,
|
|
111
|
+
? Math.min(baseBodyHeight, Math.max(1, compactRowCount))
|
|
64
112
|
: baseBodyHeight;
|
|
65
113
|
const bodyHeight = currentRoute?.kind === "workflow"
|
|
66
114
|
? workflowBodyHeight
|
|
67
115
|
: shouldUseCompactListHeight
|
|
68
116
|
? listBodyHeight
|
|
69
117
|
: baseBodyHeight;
|
|
70
|
-
const
|
|
71
|
-
? Math.ceil((14 * 2) / Math.max(1, cellWidthPx))
|
|
72
|
-
: 0;
|
|
73
|
-
const nativePanelPaddingRows = nativePaneChrome
|
|
74
|
-
? Math.ceil((14 * 2) / Math.max(1, cellHeightPx))
|
|
75
|
-
: 0;
|
|
76
|
-
const nativeBodyChromeRows = (currentRoute?.kind === "workflow"
|
|
77
|
-
|| currentRoute?.kind === "confirm"
|
|
78
|
-
|| showCustomMultiSelectPicker)
|
|
79
|
-
? 1
|
|
80
|
-
: currentRoute ? 3 : 2;
|
|
81
|
-
const barHeight = nativePaneChrome
|
|
82
|
-
? bodyHeight + nativeBodyChromeRows + nativePanelPaddingRows
|
|
83
|
-
: bodyHeight + 7;
|
|
84
|
-
const barLeft = Math.max(4, Math.floor((termWidth - barWidth) / 2));
|
|
85
|
-
const barTop = Math.max(1, Math.floor((termHeight - barHeight) / 2));
|
|
118
|
+
const barHeight = bodyHeight + paddingRows + chromeRows;
|
|
86
119
|
const appHeaderHeight = resolveAppHeaderHeightCells({ titleBarOverlay, cellHeightPx });
|
|
120
|
+
const barTop = appHeaderHeight;
|
|
87
121
|
const resultsInnerWidth = Math.max(12, barWidth - nativePanelPaddingColumns - contentPadding * 2);
|
|
88
122
|
const trailingWidth = Math.max(8, Math.min(12, Math.floor(resultsInnerWidth * 0.18)));
|
|
89
123
|
const labelWidth = Math.max(10, resultsInnerWidth - trailingWidth);
|
|
@@ -94,16 +128,19 @@ export function resolveCommandBarPanelLayout({
|
|
|
94
128
|
baseBodyHeight,
|
|
95
129
|
bodyHeight,
|
|
96
130
|
contentPadding,
|
|
131
|
+
hasChromeRow,
|
|
97
132
|
listBodyHeight,
|
|
133
|
+
// Occluder coordinates are relative to the content area, which starts where
|
|
134
|
+
// the sheet does, so the sheet's own top is the content origin.
|
|
98
135
|
nativeOccluderRect: {
|
|
99
|
-
x:
|
|
100
|
-
y:
|
|
136
|
+
x: prompt.left,
|
|
137
|
+
y: 0,
|
|
101
138
|
width: barWidth,
|
|
102
139
|
height: barHeight,
|
|
103
140
|
},
|
|
104
141
|
nativePanelPaddingColumns,
|
|
105
142
|
panelBounds: {
|
|
106
|
-
x:
|
|
143
|
+
x: prompt.left,
|
|
107
144
|
y: barTop,
|
|
108
145
|
width: barWidth,
|
|
109
146
|
height: barHeight,
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { blendHex, commandBarPanelBg, type ThemeColors } from "../../../theme/colors";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Desktop metrics for the command surface, which is one control in two boxes:
|
|
5
|
+
* the header input on top, the sheet hanging under it. They share a radius, a
|
|
6
|
+
* shadow and a border so the pair reads as one rounded rectangle that grew
|
|
7
|
+
* downward, rather than an input with a panel parked below it. The input keeps
|
|
8
|
+
* the top corners, the sheet the bottom ones, and neither draws the edge they
|
|
9
|
+
* meet on.
|
|
10
|
+
*/
|
|
11
|
+
export const NATIVE_COMMAND_SURFACE = {
|
|
12
|
+
paddingXPx: 14,
|
|
13
|
+
paddingYPx: 14,
|
|
14
|
+
radiusPx: 8,
|
|
15
|
+
shadow: "0 10px 18px color-mix(in srgb, var(--gloom-bg) 34%, transparent)",
|
|
16
|
+
} as const;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Hairline around the surface. Lifted off the panel fill rather than the
|
|
20
|
+
* header, which is the one thing the two halves do not have in common.
|
|
21
|
+
*/
|
|
22
|
+
export function nativeCommandSurfaceBorder(palette: ThemeColors): string {
|
|
23
|
+
return blendHex(commandBarPanelBg(palette), palette.textBright, 0.16);
|
|
24
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { useSyncExternalStore } from "react";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* What the header prompt needs to act as the command bar's input while the bar
|
|
5
|
+
* is open. Published by the panel, read by the header.
|
|
6
|
+
*
|
|
7
|
+
* A store rather than app state or context: the header and the command bar are
|
|
8
|
+
* siblings, and the query of a nested screen (a picker, pane settings) lives in
|
|
9
|
+
* the bar's own route stack, not in app state, so `state.commandBarQuery` alone
|
|
10
|
+
* cannot drive the input.
|
|
11
|
+
*/
|
|
12
|
+
export interface CommandBarPromptBinding {
|
|
13
|
+
/** Changes per screen so the input remounts with a fresh buffer. */
|
|
14
|
+
screenKey: string;
|
|
15
|
+
query: string;
|
|
16
|
+
placeholder: string;
|
|
17
|
+
/** Completion drawn after the typed text on the root screen, e.g. the ticker after "QQ". */
|
|
18
|
+
ghostSuffix: string | null;
|
|
19
|
+
onQueryChange: (query: string) => void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
let binding: CommandBarPromptBinding | null = null;
|
|
23
|
+
const listeners = new Set<() => void>();
|
|
24
|
+
|
|
25
|
+
function sameBinding(a: CommandBarPromptBinding | null, b: CommandBarPromptBinding | null): boolean {
|
|
26
|
+
if (a === b) return true;
|
|
27
|
+
if (!a || !b) return false;
|
|
28
|
+
return a.screenKey === b.screenKey
|
|
29
|
+
&& a.query === b.query
|
|
30
|
+
&& a.placeholder === b.placeholder
|
|
31
|
+
&& a.ghostSuffix === b.ghostSuffix
|
|
32
|
+
&& a.onQueryChange === b.onQueryChange;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function publishCommandBarPrompt(next: CommandBarPromptBinding | null): void {
|
|
36
|
+
if (sameBinding(binding, next)) return;
|
|
37
|
+
binding = next;
|
|
38
|
+
for (const listener of listeners) listener();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function subscribe(listener: () => void): () => void {
|
|
42
|
+
listeners.add(listener);
|
|
43
|
+
return () => {
|
|
44
|
+
listeners.delete(listener);
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function getSnapshot(): CommandBarPromptBinding | null {
|
|
49
|
+
return binding;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function useCommandBarPromptBinding(): CommandBarPromptBinding | null {
|
|
53
|
+
return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
54
|
+
}
|
|
@@ -54,6 +54,7 @@ interface CommandBarPanelRuntimeOptions {
|
|
|
54
54
|
moveWorkflowFocus: (delta: number) => void;
|
|
55
55
|
nativeListScrollRef: RefObject<ScrollBoxRenderable | null>;
|
|
56
56
|
nativePaneChrome: boolean;
|
|
57
|
+
nativeWindowChrome?: boolean;
|
|
57
58
|
onNativeOccluderChange?: (rect: LayoutBounds | null) => void;
|
|
58
59
|
openWorkflowFieldPicker: OpenWorkflowFieldPicker;
|
|
59
60
|
persistConfig: (nextConfig: AppState["config"]) => void;
|
|
@@ -62,7 +63,6 @@ interface CommandBarPanelRuntimeOptions {
|
|
|
62
63
|
resetAssist: () => boolean;
|
|
63
64
|
rootGhostSuffix: string | null;
|
|
64
65
|
rootModeKind: string;
|
|
65
|
-
rootQueryLength: number;
|
|
66
66
|
rootShortcutFeedback: string | null;
|
|
67
67
|
routeListState: ListScreenState | null;
|
|
68
68
|
setActiveListQuery: (query: string) => void;
|
|
@@ -107,6 +107,7 @@ export function useCommandBarPanelRuntime({
|
|
|
107
107
|
moveWorkflowFocus,
|
|
108
108
|
nativeListScrollRef,
|
|
109
109
|
nativePaneChrome,
|
|
110
|
+
nativeWindowChrome,
|
|
110
111
|
onNativeOccluderChange,
|
|
111
112
|
openWorkflowFieldPicker,
|
|
112
113
|
persistConfig,
|
|
@@ -115,7 +116,6 @@ export function useCommandBarPanelRuntime({
|
|
|
115
116
|
resetAssist,
|
|
116
117
|
rootGhostSuffix,
|
|
117
118
|
rootModeKind,
|
|
118
|
-
rootQueryLength,
|
|
119
119
|
rootShortcutFeedback,
|
|
120
120
|
routeListState,
|
|
121
121
|
setActiveListQuery,
|
|
@@ -212,12 +212,15 @@ export function useCommandBarPanelRuntime({
|
|
|
212
212
|
cellWidthPx,
|
|
213
213
|
currentRoute,
|
|
214
214
|
nativePaneChrome,
|
|
215
|
+
nativeWindowChrome,
|
|
216
|
+
rootShortcutFeedback,
|
|
215
217
|
routeListState,
|
|
216
218
|
setRootSelectedIdx,
|
|
217
219
|
showCustomMultiSelectPicker,
|
|
218
220
|
termHeight,
|
|
219
221
|
termWidth,
|
|
220
222
|
themePickerActive,
|
|
223
|
+
themePickerFilter,
|
|
221
224
|
titleBarOverlay,
|
|
222
225
|
updateTopRoute,
|
|
223
226
|
visibleListStateRef,
|
|
@@ -240,6 +243,7 @@ export function useCommandBarPanelRuntime({
|
|
|
240
243
|
contentPadding: panelLayout.contentPadding,
|
|
241
244
|
currentRoute,
|
|
242
245
|
getWorkflowInputRef,
|
|
246
|
+
hasChromeRow: panelLayout.hasChromeRow,
|
|
243
247
|
labelWidth: panelLayout.labelWidth,
|
|
244
248
|
listBodyHeight: panelLayout.listBodyHeight,
|
|
245
249
|
nativeListRows,
|
|
@@ -269,7 +273,6 @@ export function useCommandBarPanelRuntime({
|
|
|
269
273
|
panelBounds: panelLayout.panelBounds,
|
|
270
274
|
queryDisplayWidth: panelLayout.queryDisplayWidth,
|
|
271
275
|
rootGhostSuffix,
|
|
272
|
-
rootQueryLength,
|
|
273
276
|
rootShortcutFeedback,
|
|
274
277
|
selectedScrollRowIndex,
|
|
275
278
|
termHeight,
|