gloomberb 0.16.3 → 0.16.4
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/package.json +4 -1
- package/src/api-client/askg.ts +43 -0
- package/src/api-client/auth.ts +15 -0
- package/src/api-client/beneficial-owners.ts +4 -0
- package/src/api-client/chat.ts +19 -0
- package/src/api-client/company-kpis.ts +14 -2
- package/src/api-client/data.ts +34 -16
- package/src/api-client/index.ts +12 -0
- package/src/api-client/normalizers.ts +27 -0
- package/src/api-client/paths.ts +88 -23
- package/src/api-client/request.ts +2 -1
- package/src/api-client/research-activity.ts +31 -0
- package/src/api-client/socket.ts +39 -8
- package/src/api-client/types.ts +57 -1
- package/src/api-client/upgrade-experiment.ts +90 -0
- package/src/app/global-shortcuts.ts +11 -1
- package/src/app/keybindings/actions.ts +10 -0
- package/src/app/pane-runtime/index.tsx +8 -0
- package/src/app/pane-runtime/pane-template-runtime.ts +5 -0
- package/src/app/pane-runtime/plugin-bindings.ts +65 -25
- package/src/app/pane-runtime/ticker-inspector-runtime.ts +12 -0
- package/src/app/pane-runtime/ticker-open-runtime.ts +18 -1
- package/src/app/runtime/desktop-deeplink.ts +5 -0
- package/src/app/star-prompt/model.ts +98 -0
- package/src/app/star-prompt/runtime.ts +41 -0
- package/src/app/star-prompt/status-line.tsx +190 -0
- package/src/app.tsx +13 -7
- package/src/architecture/core-builtin-allowlist.json +70 -0
- package/src/brokers/signed-in/adapter.ts +33 -2
- package/src/brokers/signed-in/client.ts +10 -0
- package/src/brokers/signed-in/sign-in-dialog.tsx +23 -9
- package/src/brokers/signed-in/sign-in.ts +62 -5
- package/src/capabilities/registry.ts +8 -1
- package/src/capabilities/types.ts +2 -0
- package/src/cli/commands/crypto-hints.ts +12 -4
- package/src/cli/commands/market.ts +359 -99
- package/src/cli/commands/options-chain.ts +172 -0
- package/src/cli/commands/options-leaps.ts +422 -0
- package/src/cli/commands/overview.ts +164 -26
- package/src/cli/commands/search.ts +29 -8
- package/src/cli/commands/system.ts +99 -19
- package/src/cli/commands/themes.ts +64 -0
- package/src/cli/commands/ticker.ts +62 -30
- package/src/cli/desktop-pane-shot.ts +97 -16
- package/src/cli/errors.ts +25 -2
- package/src/cli/freshness.ts +7 -4
- package/src/cli/fx-pair.ts +57 -0
- package/src/cli/help.ts +14 -1
- package/src/cli/index-roots.ts +51 -0
- package/src/cli/index.ts +9 -6
- package/src/cli/listing-arg.ts +211 -3
- package/src/cli/not-a-ticker.ts +37 -0
- package/src/cli/options.ts +50 -6
- package/src/cli/pane-functions/capabilities.ts +8 -2
- package/src/cli/pane-functions/catalog.ts +13 -2
- package/src/cli/pane-functions/data.ts +36 -5
- package/src/cli/pane-functions/dom.ts +21 -13
- package/src/cli/pane-functions/freshness.ts +205 -26
- package/src/cli/pane-functions/function-help.ts +67 -22
- package/src/cli/pane-functions/headless.ts +5 -4
- package/src/cli/pane-functions/index.ts +3 -0
- package/src/cli/pane-functions/market-session.ts +133 -0
- package/src/cli/pane-functions/options.ts +15 -4
- package/src/cli/pane-functions/report-notices.ts +63 -0
- package/src/cli/pane-functions/report.ts +4 -0
- package/src/cli/pane-functions/resolver.ts +4 -6
- package/src/cli/pane-functions/screenshot-evidence.ts +2 -0
- package/src/cli/pane-functions/screenshot.ts +105 -23
- package/src/cli/registry.ts +2 -1
- package/src/cli/result.ts +50 -13
- package/src/cli/row-window.ts +76 -0
- package/src/cli/scroll-truncation.ts +34 -0
- package/src/components/chart/composite/composite-chart.tsx +43 -4
- package/src/components/chart/composite/legend.tsx +39 -6
- package/src/components/chart/composite/rasterizer.ts +64 -4
- package/src/components/chart/composite/series-cues.ts +71 -0
- package/src/components/chart/composite/text-renderer.ts +16 -8
- package/src/components/chart/composite/types.ts +3 -0
- package/src/components/command-bar/commands/direct/index.ts +9 -1
- package/src/components/command-bar/commands/plugin/items.ts +3 -1
- package/src/components/command-bar/commands/registry.ts +7 -0
- package/src/components/command-bar/layout-items/focused-pane.ts +38 -0
- package/src/components/command-bar/pane-templates/workflow.ts +5 -0
- package/src/components/command-bar/routes/root/command-items.ts +2 -0
- package/src/components/command-bar/routes/root/plugin-turn-on.ts +92 -0
- package/src/components/command-bar/routes/root/results.ts +40 -10
- package/src/components/command-bar/routes/root/runtime.ts +8 -0
- package/src/components/command-bar/routes/root/search-providers.ts +97 -14
- package/src/components/command-bar/surface/index.tsx +18 -4
- package/src/components/command-bar/theme-picker.tsx +48 -13
- package/src/components/command-bar/workflow/ops.ts +5 -3
- package/src/components/data-table/view.tsx +28 -9
- package/src/components/layout/floating-pane.tsx +6 -2
- package/src/components/layout/market-summary.ts +23 -9
- package/src/components/layout/pane/content.tsx +46 -29
- package/src/components/layout/pane/cycle-order.ts +2 -11
- package/src/components/layout/pane/header.tsx +2 -1
- package/src/components/layout/pane/title.ts +1 -1
- package/src/components/layout/presentation.ts +22 -0
- package/src/components/layout/shell/active-drag.ts +1 -1
- package/src/components/layout/shell/drag/index.ts +4 -0
- package/src/components/layout/shell/drag/live.ts +76 -5
- package/src/components/layout/shell/drag/runtime.ts +8 -8
- package/src/components/layout/shell/index.tsx +47 -6
- package/src/components/layout/shell/layout-state.ts +5 -11
- package/src/components/layout/shell/menu.ts +28 -1
- package/src/components/layout/shell/pane/actions.ts +2 -1
- package/src/components/layout/shell/pane/layers.tsx +51 -10
- package/src/components/layout/shell/pane/management-shortcuts.ts +5 -0
- package/src/components/layout/shell/pane/new-layout.ts +116 -0
- package/src/components/layout/shell/shortcuts.ts +5 -2
- package/src/components/layout/shell/visible-layout.ts +44 -1
- package/src/components/layout/status-bar.tsx +4 -1
- package/src/components/markdown-text.tsx +9 -5
- package/src/components/metric-treemap/heat-surface.tsx +27 -8
- package/src/components/metric-treemap/heat-tiles.ts +48 -17
- package/src/components/onboarding/onboarding-frame.tsx +33 -10
- package/src/components/onboarding/onboarding-wizard.tsx +49 -40
- package/src/components/onboarding/portfolio-step/positions-panel.tsx +5 -2
- package/src/components/onboarding/pro-step-layout.ts +86 -0
- package/src/components/onboarding/use-onboarding-upgrade.ts +6 -2
- package/src/components/ui/button.tsx +10 -0
- package/src/components/ui/data-table/index.tsx +38 -0
- package/src/components/ui/data-table/types.ts +8 -1
- package/src/components/ui/data-table/visible-range.ts +2 -0
- package/src/components/ui/icon.tsx +11 -2
- package/src/components/ui/index.ts +1 -1
- package/src/core/connection-health.ts +1 -1
- package/src/core/state/app/layout-reducer.ts +89 -3
- package/src/core/state/app/state.ts +8 -5
- package/src/core/state/app/types.ts +13 -2
- package/src/data/config/layout.ts +55 -21
- package/src/data/config/store/fold-panes.ts +149 -0
- package/src/data/config/store/migrations.ts +7 -0
- package/src/data/config/store/node.ts +27 -6
- package/src/data/config/store/normalize.ts +37 -3
- package/src/i18n/es.ts +14 -1
- package/src/i18n/ja.ts +14 -1
- package/src/i18n/ko.ts +14 -1
- package/src/i18n/zh-cn.ts +14 -1
- package/src/i18n/zh-tw.ts +14 -1
- package/src/layout/desks.ts +1 -2
- package/src/layout/pane-layout-move.ts +264 -0
- package/src/layout/pane-manager/hidden-panes.ts +160 -0
- package/src/layout/pane-manager/index.ts +1 -0
- package/src/market-data/coordinator/entries.ts +7 -1
- package/src/market-data/coordinator/quotes.ts +2 -2
- package/src/market-data/market/freshness.ts +118 -18
- package/src/market-data/market/status.ts +40 -0
- package/src/market-data/options-alternatives.ts +69 -0
- package/src/market-data/quotes/contributions.ts +19 -2
- package/src/market-data/quotes/metadata.ts +16 -0
- package/src/market-data/quotes/screener-live-quotes.ts +56 -5
- package/src/plugins/builtin/account-management/keyboard.ts +3 -0
- package/src/plugins/builtin/account-management/model.ts +1 -0
- package/src/plugins/builtin/account-management/navigation.ts +1 -1
- package/src/plugins/builtin/account-management/pane.tsx +31 -4
- package/src/plugins/builtin/alerts/quotes.ts +3 -0
- package/src/plugins/builtin/analytics/risk-headless.ts +3 -1
- package/src/plugins/builtin/analytics/risk-model.ts +37 -8
- package/src/plugins/builtin/analytics/risk-pane.tsx +8 -4
- package/src/plugins/builtin/backtest/pane.tsx +1 -1
- package/src/plugins/builtin/broker-manager/detail.tsx +4 -0
- package/src/plugins/builtin/broker-manager/index.tsx +7 -3
- package/src/plugins/builtin/broker-manager/model.ts +8 -0
- package/src/plugins/builtin/broker-manager/pane-actions.tsx +8 -2
- package/src/plugins/builtin/broker-manager/sign-in-end.ts +82 -0
- package/src/plugins/builtin/broker-manager/table.ts +5 -0
- package/src/plugins/builtin/builtin-plugin-meta.ts +121 -11
- package/src/plugins/builtin/chart-composer/pane.tsx +1 -1
- package/src/plugins/builtin/chat/channels.ts +34 -36
- package/src/plugins/builtin/chat/command-bar.ts +138 -0
- package/src/plugins/builtin/chat/composer-commands.ts +21 -1
- package/src/plugins/builtin/chat/content/composer-runtime.ts +11 -1
- package/src/plugins/builtin/chat/content/footer.tsx +5 -3
- package/src/plugins/builtin/chat/content/index.tsx +21 -1
- package/src/plugins/builtin/chat/content/mentions.ts +2 -1
- package/src/plugins/builtin/chat/content/user-map.ts +3 -1
- package/src/plugins/builtin/chat/controller/index.ts +48 -0
- package/src/plugins/builtin/chat/conversations.ts +256 -0
- package/src/plugins/builtin/chat/discord-command.ts +91 -0
- package/src/plugins/builtin/chat/edit-window.ts +12 -6
- package/src/plugins/builtin/chat/ghost-user.ts +14 -0
- package/src/plugins/builtin/chat/index.tsx +40 -2
- package/src/plugins/builtin/chat/layout.ts +2 -0
- package/src/plugins/builtin/chat/message/desktop.tsx +2 -1
- package/src/plugins/builtin/chat/message/header.tsx +24 -15
- package/src/plugins/builtin/chat/message/profile-popover.tsx +2 -1
- package/src/plugins/builtin/chat/message/render-state.ts +3 -0
- package/src/plugins/builtin/chat/pane-requests.ts +60 -0
- package/src/plugins/builtin/chat/pane-state.ts +32 -2
- package/src/plugins/builtin/chat/pane.tsx +8 -0
- package/src/plugins/builtin/cloud/askg/controller.ts +112 -4
- package/src/plugins/builtin/cloud/askg/conversation-store.ts +21 -0
- package/src/plugins/builtin/cloud/askg/manifest.ts +1 -0
- package/src/plugins/builtin/cloud/askg/model.ts +129 -70
- package/src/plugins/builtin/cloud/askg/pane.tsx +772 -377
- package/src/plugins/builtin/cloud/askg/protocol.ts +40 -2
- package/src/plugins/builtin/cloud/askg/tool-display.ts +437 -0
- package/src/plugins/builtin/cloud/askg/tool-timeline.tsx +403 -0
- package/src/plugins/builtin/cloud/company-picker.tsx +1 -9
- package/src/plugins/builtin/cloud/mcp-connect/command.ts +24 -0
- package/src/plugins/builtin/cloud/mcp-connect/dialog.tsx +360 -0
- package/src/plugins/builtin/cloud/mcp-connect/model.ts +135 -0
- package/src/plugins/builtin/cloud/mcp-connect/sections.ts +62 -0
- package/src/plugins/builtin/cloud/plugin.tsx +36 -1
- package/src/plugins/builtin/cloud/starter-symbols.ts +8 -0
- package/src/plugins/builtin/cloud/terminal-relay/acm-tab.tsx +89 -0
- package/src/plugins/builtin/cloud/terminal-relay/client.ts +97 -0
- package/src/plugins/builtin/cloud/terminal-relay/connect-section.tsx +57 -0
- package/src/plugins/builtin/cloud/terminal-relay/engine.ts +666 -0
- package/src/plugins/builtin/cloud/terminal-relay/grants.ts +137 -0
- package/src/plugins/builtin/cloud/terminal-relay/host.tsx +81 -0
- package/src/plugins/builtin/cloud/terminal-relay/indicator.tsx +82 -0
- package/src/plugins/builtin/cloud/terminal-relay/manifest.ts +234 -0
- package/src/plugins/builtin/cloud/terminal-relay/policy.ts +153 -0
- package/src/plugins/builtin/cloud/terminal-relay/prompts.tsx +168 -0
- package/src/plugins/builtin/cloud/terminal-relay/redact.ts +73 -0
- package/src/plugins/builtin/cloud/terminal-relay/summary.ts +62 -0
- package/src/plugins/builtin/cloud/upgrade-dialog.tsx +26 -2
- package/src/plugins/builtin/cloud/upgrade-personalization.ts +57 -0
- package/src/plugins/builtin/cloud/upgrade-tickers.ts +124 -0
- package/src/plugins/builtin/comment-letters/client.ts +1 -3
- package/src/plugins/builtin/company-kpis/client.ts +23 -8
- package/src/plugins/builtin/company-kpis/headless.ts +3 -1
- package/src/plugins/builtin/company-kpis/pane.tsx +15 -7
- package/src/plugins/builtin/company-kpis/screenshot-evidence.ts +10 -3
- package/src/plugins/builtin/composite-plugins.ts +107 -64
- package/src/plugins/builtin/credit-boards/cdx-pane.tsx +4 -4
- package/src/plugins/builtin/credit-boards/index.tsx +21 -21
- package/src/plugins/builtin/credit-boards/model.ts +0 -1
- package/src/plugins/builtin/credit-boards/pane.tsx +30 -0
- package/src/plugins/builtin/credit-boards/sovr-pane.tsx +4 -4
- package/src/plugins/builtin/debt-maturities/client.ts +37 -9
- package/src/plugins/builtin/debt-maturities/headless.ts +3 -1
- package/src/plugins/builtin/debt-maturities/pane.tsx +5 -4
- package/src/plugins/builtin/dividend-yield/index.tsx +1 -1
- package/src/plugins/builtin/dividend-yield/pane.tsx +1 -1
- package/src/plugins/builtin/earnings-calls/data.ts +28 -7
- package/src/plugins/builtin/earnings-calls/headless.ts +3 -2
- package/src/plugins/builtin/earnings-calls/pane.tsx +10 -5
- package/src/plugins/builtin/econ/calendar-model.ts +42 -17
- package/src/plugins/builtin/econ/detail-view.tsx +2 -2
- package/src/plugins/builtin/econ/index.tsx +68 -22
- package/src/plugins/builtin/econ-statistics/headless.ts +12 -2
- package/src/plugins/builtin/econ-statistics/pane.tsx +1 -1
- package/src/plugins/builtin/econ-statistics/view.ts +17 -0
- package/src/plugins/builtin/executives/data.ts +17 -6
- package/src/plugins/builtin/executives/pane.tsx +16 -7
- package/src/plugins/builtin/filing-events/pane.tsx +22 -5
- package/src/plugins/builtin/fx-matrix/freshness.ts +65 -0
- package/src/plugins/builtin/fx-matrix/index.tsx +22 -1
- package/src/plugins/builtin/fx-matrix/pairs.ts +1 -1
- package/src/plugins/builtin/fx-matrix/settings.ts +42 -2
- package/src/plugins/builtin/gpu/headless.ts +9 -3
- package/src/plugins/builtin/gpu/model.ts +14 -5
- package/src/plugins/builtin/help/index.tsx +1 -0
- package/src/plugins/builtin/holders/beneficial-client.ts +29 -7
- package/src/plugins/builtin/holders/beneficial-view.tsx +7 -3
- package/src/plugins/builtin/holders/headless.ts +6 -1
- package/src/plugins/builtin/holders/pane.tsx +3 -0
- package/src/plugins/builtin/insider/index.tsx +4 -4
- package/src/plugins/builtin/iv-history/charts.tsx +21 -7
- package/src/plugins/builtin/iv-history/client.ts +12 -2
- package/src/plugins/builtin/iv-history/format.ts +33 -2
- package/src/plugins/builtin/iv-history/headless.ts +22 -10
- package/src/plugins/builtin/iv-history/index.tsx +3 -3
- package/src/plugins/builtin/iv-history/model.ts +61 -13
- package/src/plugins/builtin/iv-history/pane.tsx +11 -3
- package/src/plugins/builtin/iv-history/screen-pane.tsx +42 -18
- package/src/plugins/builtin/jobs/pane.tsx +1 -1
- package/src/plugins/builtin/kelly-sizer/headless.ts +149 -0
- package/src/plugins/builtin/kelly-sizer/history.ts +80 -0
- package/src/plugins/builtin/kelly-sizer/index.tsx +2 -0
- package/src/plugins/builtin/kelly-sizer/pane.tsx +109 -39
- package/src/plugins/builtin/kelly-sizer/sections.tsx +14 -0
- package/src/plugins/builtin/kelly-sizer/types.ts +9 -1
- package/src/plugins/builtin/layout-manager/index.tsx +9 -1
- package/src/plugins/builtin/macro-day/client.ts +24 -0
- package/src/plugins/builtin/macro-day/headless.ts +11 -8
- package/src/plugins/builtin/macro-day/index.tsx +3 -0
- package/src/plugins/builtin/macro-day/model.ts +11 -6
- package/src/plugins/builtin/macro-day/pane.tsx +12 -8
- package/src/plugins/builtin/macro-day/release-table.ts +40 -0
- package/src/plugins/builtin/macro-day/releases.ts +62 -44
- package/src/plugins/builtin/market-heatmap/data.ts +25 -5
- package/src/plugins/builtin/market-heatmap/evidence.ts +90 -0
- package/src/plugins/builtin/market-heatmap/index.tsx +144 -63
- package/src/plugins/builtin/market-heatmap/model.ts +94 -3
- package/src/plugins/builtin/market-heatmap/portfolio.ts +12 -2
- package/src/plugins/builtin/market-movers/headless.ts +31 -4
- package/src/plugins/builtin/market-movers/index.tsx +8 -1
- package/src/plugins/builtin/market-movers/model.ts +71 -17
- package/src/plugins/builtin/market-movers/table.ts +50 -23
- package/src/plugins/builtin/news/headless.ts +9 -2
- package/src/plugins/builtin/news/wire/news/footer.ts +10 -0
- package/src/plugins/builtin/openfda/client.ts +1 -1
- package/src/plugins/builtin/options/carry.ts +95 -0
- package/src/plugins/builtin/options/index.tsx +58 -5
- package/src/plugins/builtin/options/strike-window.ts +183 -0
- package/src/plugins/builtin/options/table.ts +55 -3
- package/src/plugins/builtin/options/types.ts +8 -1
- package/src/plugins/builtin/options/view.tsx +161 -12
- package/src/plugins/builtin/options-positioning/headless.ts +4 -2
- package/src/plugins/builtin/options-scenario/charts.tsx +2 -2
- package/src/plugins/builtin/options-scenario/client.ts +73 -17
- package/src/plugins/builtin/options-scenario/headless.ts +71 -24
- package/src/plugins/builtin/options-scenario/hedge.ts +284 -0
- package/src/plugins/builtin/options-scenario/index.tsx +9 -2
- package/src/plugins/builtin/options-scenario/model.ts +33 -0
- package/src/plugins/builtin/options-scenario/pane.tsx +40 -16
- package/src/plugins/builtin/pe-band/model.ts +2 -2
- package/src/plugins/builtin/pe-band/report-dates.ts +11 -7
- package/src/plugins/builtin/perps/equity-row.tsx +8 -5
- package/src/plugins/builtin/perps/model.ts +16 -5
- package/src/plugins/builtin/plugin-marketplace/model.ts +64 -21
- package/src/plugins/builtin/plugin-marketplace/packs.ts +118 -0
- package/src/plugins/builtin/plugin-marketplace/pane.tsx +344 -32
- package/src/plugins/builtin/plugin-marketplace/store.ts +7 -1
- package/src/plugins/builtin/plugin-module.ts +87 -4
- package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +71 -36
- package/src/plugins/builtin/portfolio-list/cli/render.ts +87 -18
- package/src/plugins/builtin/portfolio-list/cli/shared.ts +2 -16
- package/src/plugins/builtin/portfolio-list/headless.ts +38 -7
- package/src/plugins/builtin/realized-vol/headless.ts +3 -0
- package/src/plugins/builtin/realized-vol/pane.tsx +1 -1
- package/src/plugins/builtin/research/corporate-actions-pane.tsx +2 -2
- package/src/plugins/builtin/research/equity-diagnostic-pane.tsx +1 -1
- package/src/plugins/builtin/revenue-breakdown/client.ts +13 -6
- package/src/plugins/builtin/revenue-breakdown/headless.ts +4 -1
- package/src/plugins/builtin/revenue-breakdown/pane.tsx +7 -4
- package/src/plugins/builtin/reverse-dcf/headless.ts +5 -1
- package/src/plugins/builtin/reverse-dcf/pane.tsx +1 -1
- package/src/plugins/builtin/risk-factors/data.ts +23 -9
- package/src/plugins/builtin/risk-factors/headless.ts +5 -2
- package/src/plugins/builtin/risk-factors/pane.tsx +6 -5
- package/src/plugins/builtin/seasonality/pane.tsx +1 -1
- package/src/plugins/builtin/sec/index.tsx +5 -5
- package/src/plugins/builtin/sectors/client.ts +10 -2
- package/src/plugins/builtin/sectors/headless.ts +35 -6
- package/src/plugins/builtin/sectors/index.tsx +18 -1
- package/src/plugins/builtin/sectors/sector-model.ts +150 -41
- package/src/plugins/builtin/shared/command-tab.ts +51 -0
- package/src/plugins/builtin/shared/headless-market-data.ts +33 -1
- package/src/plugins/builtin/shared/members-menu.tsx +4 -4
- package/src/plugins/builtin/shared/report-freshness.ts +50 -2
- package/src/plugins/builtin/shared/ticker-request.ts +25 -1
- package/src/plugins/builtin/shared/use-quote-board.ts +25 -5
- package/src/plugins/builtin/shared/volatility/options.ts +1 -46
- package/src/plugins/builtin/short-interest/index.tsx +19 -4
- package/src/plugins/builtin/short-interest/surface.tsx +4 -4
- package/src/plugins/builtin/short-volume/index.tsx +1 -10
- package/src/plugins/builtin/supply-chain/model.ts +1 -1
- package/src/plugins/builtin/ticker-detail/headless.ts +43 -21
- package/src/plugins/builtin/ticker-detail/pane.tsx +4 -5
- package/src/plugins/builtin/ticker-detail/quote-monitor/card.tsx +94 -6
- package/src/plugins/builtin/treasury-auctions/cache.ts +5 -2
- package/src/plugins/builtin/treasury-auctions/client.ts +22 -8
- package/src/plugins/builtin/treasury-auctions/headless.ts +40 -4
- package/src/plugins/builtin/treasury-auctions/index.tsx +11 -9
- package/src/plugins/builtin/treasury-auctions/model.ts +197 -30
- package/src/plugins/builtin/treasury-auctions/pane.tsx +35 -11
- package/src/plugins/builtin/treasury-auctions/types.ts +11 -1
- package/src/plugins/builtin/vol-surface/charts.tsx +1 -3
- package/src/plugins/builtin/vol-surface/client.ts +6 -2
- package/src/plugins/builtin/vol-surface/evidence.ts +11 -6
- package/src/plugins/builtin/vol-surface/headless.ts +124 -20
- package/src/plugins/builtin/vol-surface/model.ts +23 -11
- package/src/plugins/builtin/vol-surface/pane.tsx +38 -27
- package/src/plugins/builtin/vol-surface/tables.ts +124 -0
- package/src/plugins/builtin/world-indices/client.ts +22 -4
- package/src/plugins/builtin/world-indices/headless.ts +54 -27
- package/src/plugins/builtin/world-indices/model.ts +4 -2
- package/src/plugins/builtin/world-indices/table.tsx +13 -2
- package/src/plugins/builtin/world-venue-map/geo-series.ts +1 -1
- package/src/plugins/builtin/world-venue-map/index.ts +1 -1
- package/src/plugins/builtin/yield-curve/index.tsx +1 -1
- package/src/plugins/builtin-editorial.ts +126 -0
- package/src/plugins/catalog-backend.ts +16 -9
- package/src/plugins/catalog-browser.ts +127 -63
- package/src/plugins/catalog-manifest.ts +73 -40
- package/src/plugins/catalog-ui.ts +26 -6
- package/src/plugins/extracted-plugins.ts +7 -1
- package/src/plugins/ownership.ts +150 -7
- package/src/plugins/plugin-functions.ts +54 -0
- package/src/plugins/plugin-off.ts +36 -0
- package/src/plugins/registry/host-actions.ts +16 -0
- package/src/plugins/registry/index.ts +84 -24
- package/src/plugins/registry/plugin-state.ts +25 -1
- package/src/plugins/runtime/context.tsx +29 -0
- package/src/react/input.ts +48 -1
- package/src/remote/app-host.tsx +5 -0
- package/src/remote/controller.ts +3 -53
- package/src/remote/matching.ts +69 -0
- package/src/remote/schema.ts +1 -1
- package/src/remote/semantic-tree.tsx +14 -0
- package/src/remote/types.ts +2 -0
- package/src/renderers/dom/desktop/icons.tsx +14 -0
- package/src/renderers/dom/desktop/query-bar.tsx +59 -32
- package/src/renderers/dom/host/box.tsx +1 -1
- package/src/renderers/dom/host/drag-shield.ts +17 -6
- package/src/renderers/dom/host/live-frame.ts +10 -2
- package/src/renderers/dom/input-host.tsx +6 -1
- package/src/renderers/dom/styles.css +13 -0
- package/src/renderers/electrobun/bun/desktop/backend.ts +5 -1
- package/src/renderers/electrobun/bun/desktop/detached-windows.ts +12 -1
- package/src/renderers/electrobun/bun/desktop/initialization.ts +2 -1
- package/src/renderers/electrobun/shared/protocol.ts +2 -0
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -1
- package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +101 -5
- package/src/renderers/electrobun/view/main.tsx +4 -1
- package/src/renderers/opentui/input-host.tsx +6 -1
- package/src/renderers/opentui/start.tsx +9 -0
- package/src/shares/portable-layout.ts +16 -6
- package/src/sources/gloomberb-cloud/index.ts +19 -10
- package/src/sources/gloomberb-cloud/normalizers.ts +4 -1
- package/src/sources/listing-symbols.ts +11 -5
- package/src/sources/provider-errors.ts +88 -3
- package/src/sources/provider-router/cached-routes.ts +8 -4
- package/src/sources/provider-router/financial-routes.ts +11 -5
- package/src/sources/provider-router/financials.ts +42 -15
- package/src/sources/provider-router/history.ts +27 -11
- package/src/sources/provider-router/index.ts +1 -1
- package/src/sources/provider-router/primary.ts +23 -5
- package/src/sources/sec-edgar.ts +68 -8
- package/src/sync/core-contributors.ts +4 -3
- package/src/test-support/cli-context.ts +2 -1
- package/src/test-support/data-provider.ts +34 -0
- package/src/test-support/shell-pane-keys.tsx +1 -0
- package/src/theme/series-colors.ts +46 -0
- package/src/theme/themes.ts +149 -0
- package/src/tickers/search/index.ts +22 -2
- package/src/tickers/search/ranking.ts +45 -1
- package/src/tickers/search/types.ts +3 -1
- package/src/time-series/resolve.ts +1 -14
- package/src/types/config.ts +61 -1
- package/src/types/headless.ts +11 -0
- package/src/types/instrument.ts +8 -0
- package/src/types/plugin.ts +49 -3
- package/src/ui/host.tsx +8 -4
- package/src/ui/index.tsx +2 -0
- package/src/utils/cli-output.ts +14 -1
- package/src/utils/exchanges.ts +13 -0
- package/src/utils/format.ts +2 -1
- package/src/utils/fx-market-hours.ts +34 -0
- package/src/utils/option-expiry.ts +126 -0
- package/src/utils/price-history.ts +39 -6
- package/src/utils/rpc-timeout-error.ts +6 -2
- package/src/utils/sec-eps-basis.ts +159 -30
- package/src/utils/sec.ts +38 -34
- package/src/utils/throttled-fetch.ts +51 -22
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
type ShortcutDisplayMode,
|
|
16
16
|
} from "../../../utils/shortcut-labels";
|
|
17
17
|
import { PANE_MANAGEMENT_ACCELERATORS, type PaneManagementAccelerators } from "./shortcuts";
|
|
18
|
-
import { t } from "../../../i18n";
|
|
18
|
+
import { t, tf } from "../../../i18n";
|
|
19
19
|
import { displayWidth } from "../../../utils/format";
|
|
20
20
|
import { fireAndForget } from "../../../utils/fire-and-forget";
|
|
21
21
|
|
|
@@ -42,6 +42,14 @@ export interface PaneMenuQuickSetting {
|
|
|
42
42
|
toggle: () => void;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
/** Move to New Layout and Move Back as the pane menu offers them; either may be absent. */
|
|
46
|
+
export interface PaneMenuLayoutMove {
|
|
47
|
+
/** Absent when the pane is alone in its layout. */
|
|
48
|
+
moveToNewLayout?: () => void;
|
|
49
|
+
/** Present when the pane was moved here from another layout. */
|
|
50
|
+
moveBack?: { layoutName: string; onSelect: () => void };
|
|
51
|
+
}
|
|
52
|
+
|
|
45
53
|
/**
|
|
46
54
|
* The pane's own actions at the top of its menu: every footer hint with its
|
|
47
55
|
* key, a footer shortcut such as `!`, then what the pane's kit controls add
|
|
@@ -93,6 +101,7 @@ export function menuForPane(
|
|
|
93
101
|
quickSettings: PaneMenuQuickSetting[] = [],
|
|
94
102
|
fullscreen?: { active: boolean; toggle: () => void },
|
|
95
103
|
paneItems: ContextMenuItem[] = [],
|
|
104
|
+
layoutMove: PaneMenuLayoutMove = {},
|
|
96
105
|
): ContextMenuItem[] {
|
|
97
106
|
const baseActions: ContextMenuItem[] = [...paneItems];
|
|
98
107
|
if (baseActions.length > 0) baseActions.push(contextMenuDivider("pane:own-actions-divider"));
|
|
@@ -147,6 +156,24 @@ export function menuForPane(
|
|
|
147
156
|
});
|
|
148
157
|
}
|
|
149
158
|
|
|
159
|
+
if (layoutMove.moveToNewLayout) {
|
|
160
|
+
baseActions.push({
|
|
161
|
+
id: "move-to-new-layout",
|
|
162
|
+
label: "Move to New Layout",
|
|
163
|
+
accelerator: accelerators.newLayout,
|
|
164
|
+
onSelect: layoutMove.moveToNewLayout,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
if (layoutMove.moveBack) {
|
|
168
|
+
baseActions.push({
|
|
169
|
+
id: "move-back",
|
|
170
|
+
label: tf("Move Back to {layout}", { layout: layoutMove.moveBack.layoutName }),
|
|
171
|
+
// The shortcut moves a pane back only when it is alone, where Move to New Layout is not offered.
|
|
172
|
+
accelerator: layoutMove.moveToNewLayout ? undefined : accelerators.newLayout,
|
|
173
|
+
onSelect: layoutMove.moveBack.onSelect,
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
150
177
|
if (pane.floating) {
|
|
151
178
|
baseActions.push({
|
|
152
179
|
id: "dock",
|
|
@@ -172,7 +172,8 @@ export function useShellPaneActions({
|
|
|
172
172
|
paneTypes: pluginRegistry.panes,
|
|
173
173
|
apply: persistLayout,
|
|
174
174
|
notify: pluginRegistry.notify,
|
|
175
|
-
|
|
175
|
+
// Back through the shell's save, which puts hidden panes back too.
|
|
176
|
+
onRevert: () => persistLayout(visibleLayout),
|
|
176
177
|
});
|
|
177
178
|
return true;
|
|
178
179
|
}, [contentHeight, persistLayout, pluginRegistry, visibleLayout, width]);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { memo, useCallback, useMemo, useRef } from "react";
|
|
1
|
+
import { memo, useCallback, useMemo, useRef, type RefObject } from "react";
|
|
2
2
|
import { Box, type BoxRenderable, type LiveBoxFrame } from "../../../../ui";
|
|
3
3
|
import { resolveOccludedPaneIds } from "../pane-occlusion";
|
|
4
4
|
import type {
|
|
@@ -9,8 +9,8 @@ import type {
|
|
|
9
9
|
ResolvedPane,
|
|
10
10
|
} from "../../../../layout/pane-manager";
|
|
11
11
|
import { colors } from "../../../../theme/colors";
|
|
12
|
-
import { constrainFloatingRectToBounds } from "../drag";
|
|
13
|
-
import { useLiveBoxFrame, useLiveDrag, type LiveDragGeometry, type LiveDragStore } from "../drag/live";
|
|
12
|
+
import { constrainFloatingRectToBounds, sameRect } from "../drag";
|
|
13
|
+
import { useLiveBoxFrame, useLiveDrag, useLiveResizeRect, type LiveDragGeometry, type LiveDragStore } from "../drag/live";
|
|
14
14
|
import { pathKey } from "../../window-edit/mode";
|
|
15
15
|
import { FloatingPaneWrapper } from "../../floating-pane";
|
|
16
16
|
import { PaneContent } from "../../pane/content";
|
|
@@ -207,7 +207,16 @@ const FloatingPaneFrame = memo(function FloatingPaneFrame({
|
|
|
207
207
|
getPaneQuickSettings,
|
|
208
208
|
actions,
|
|
209
209
|
zIndex,
|
|
210
|
-
|
|
210
|
+
frameRef,
|
|
211
|
+
contentPinned = false,
|
|
212
|
+
}: PaneLayerProps & {
|
|
213
|
+
rect: FloatingRect;
|
|
214
|
+
zIndex: number;
|
|
215
|
+
/** Desktop: the frame a resize sizes outside React. */
|
|
216
|
+
frameRef?: RefObject<BoxRenderable | null>;
|
|
217
|
+
/** Desktop: a resize is under way, so the content keeps the size it last rendered at. */
|
|
218
|
+
contentPinned?: boolean;
|
|
219
|
+
}) {
|
|
211
220
|
const paneId = pane.instance.instanceId;
|
|
212
221
|
const quickSettings = usePaneQuickSettings(getPaneQuickSettings, paneId);
|
|
213
222
|
const nativeMove = nativePaneChrome && movable;
|
|
@@ -252,6 +261,7 @@ const FloatingPaneFrame = memo(function FloatingPaneFrame({
|
|
|
252
261
|
onResizeMouseDown={nativeMove ? (event) => actions.floatResizeStart(paneId, rect, event) : undefined}
|
|
253
262
|
onResizeMouseDrag={nativeMove ? actions.drag : undefined}
|
|
254
263
|
onResizeMouseDragEnd={nativeMove ? actions.drag : undefined}
|
|
264
|
+
frameRef={frameRef}
|
|
255
265
|
>
|
|
256
266
|
<PaneFooterKeys paneId={paneId} footer={footer} focused={focused} />
|
|
257
267
|
<PaneContent
|
|
@@ -265,6 +275,7 @@ const FloatingPaneFrame = memo(function FloatingPaneFrame({
|
|
|
265
275
|
inView={inView}
|
|
266
276
|
onClose={actions.close}
|
|
267
277
|
closePane={actions.close}
|
|
278
|
+
pinned={contentPinned}
|
|
268
279
|
/>
|
|
269
280
|
</FloatingPaneWrapper>
|
|
270
281
|
);
|
|
@@ -278,8 +289,11 @@ const FloatingPaneFrame = memo(function FloatingPaneFrame({
|
|
|
278
289
|
* On the desktop a move never renders: the pane's layer is promoted at the
|
|
279
290
|
* press and each frame of the move only writes its transform (see
|
|
280
291
|
* `useLiveBoxFrame`), so nothing inside it re-renders, lays out or repaints
|
|
281
|
-
* until the release commits the new position. A resize
|
|
282
|
-
*
|
|
292
|
+
* until the release commits the new position. A resize writes the frame's
|
|
293
|
+
* size the same way, on the same layer, and the header, body and footer
|
|
294
|
+
* stretch with it; the content keeps its size and renders at the new one a
|
|
295
|
+
* few times a second (`useLiveResizeRect`). Every terminal frame redraws it
|
|
296
|
+
* at the drag's rect.
|
|
283
297
|
*/
|
|
284
298
|
const FloatingPaneLayer = memo(function FloatingPaneLayer({
|
|
285
299
|
live,
|
|
@@ -293,13 +307,20 @@ const FloatingPaneLayer = memo(function FloatingPaneLayer({
|
|
|
293
307
|
const slide = frame.nativePaneChrome;
|
|
294
308
|
const selectRedraw = useCallback((geometry: LiveDragGeometry) => {
|
|
295
309
|
if (geometry.floating?.paneId !== paneId) return null;
|
|
296
|
-
// A desktop move follows
|
|
297
|
-
if (slide && geometry.paneDrag?.paneId === paneId) return null;
|
|
310
|
+
// A desktop move or resize follows by restyling the pane instead.
|
|
311
|
+
if (slide && (geometry.paneDrag?.paneId === paneId || geometry.paneResize?.paneId === paneId)) return null;
|
|
298
312
|
return geometry.floating.rect;
|
|
299
313
|
}, [paneId, slide]);
|
|
300
314
|
const dragRect = useLiveDrag(live, selectRedraw);
|
|
315
|
+
const selectResizing = useCallback((geometry: LiveDragGeometry) => (
|
|
316
|
+
slide && geometry.paneResize?.paneId === paneId
|
|
317
|
+
), [paneId, slide]);
|
|
318
|
+
const resizing = useLiveDrag(live, selectResizing);
|
|
301
319
|
const layerRef = useRef<BoxRenderable | null>(null);
|
|
302
320
|
const frameOf = useMemo(() => (slide ? (geometry: LiveDragGeometry): LiveBoxFrame | null => {
|
|
321
|
+
// A resize keeps the pane on its own layer too: the panes it uncovers or
|
|
322
|
+
// covers never repaint, only the pane does.
|
|
323
|
+
if (geometry.paneResize?.paneId === paneId) return { dx: 0, dy: 0 };
|
|
303
324
|
if (geometry.paneDrag?.paneId !== paneId) return null;
|
|
304
325
|
const moving = geometry.floating?.paneId === paneId ? geometry.floating.rect : null;
|
|
305
326
|
// Promoted from the press, so the first move already only slides it.
|
|
@@ -308,8 +329,28 @@ const FloatingPaneLayer = memo(function FloatingPaneLayer({
|
|
|
308
329
|
return { dx: at.x - rect.x, dy: at.y - rect.y };
|
|
309
330
|
} : null), [contentHeight, paneId, rect.x, rect.y, slide, width]);
|
|
310
331
|
useLiveBoxFrame(live, layerRef, frameOf);
|
|
311
|
-
const
|
|
312
|
-
const
|
|
332
|
+
const frameRef = useRef<BoxRenderable | null>(null);
|
|
333
|
+
const sizeOf = useMemo(() => (slide ? (geometry: LiveDragGeometry): LiveBoxFrame | null => {
|
|
334
|
+
if (geometry.paneResize?.paneId !== paneId || geometry.floating?.paneId !== paneId) return null;
|
|
335
|
+
const at = constrainFloatingRectToBounds(geometry.floating.rect, width, contentHeight);
|
|
336
|
+
return { width: at.width, height: at.height };
|
|
337
|
+
} : null), [contentHeight, paneId, slide, width]);
|
|
338
|
+
useLiveBoxFrame(live, frameRef, sizeOf);
|
|
339
|
+
const resizeRect = useLiveResizeRect(live, paneId, slide);
|
|
340
|
+
const preview = dragRect
|
|
341
|
+
? constrainFloatingRectToBounds(dragRect, width, contentHeight)
|
|
342
|
+
: resizeRect && !sameRect(resizeRect, rect)
|
|
343
|
+
? constrainFloatingRectToBounds(resizeRect, width, contentHeight)
|
|
344
|
+
: rect;
|
|
345
|
+
const content = (
|
|
346
|
+
<FloatingPaneFrame
|
|
347
|
+
{...frame}
|
|
348
|
+
rect={preview}
|
|
349
|
+
zIndex={zIndex}
|
|
350
|
+
frameRef={slide ? frameRef : undefined}
|
|
351
|
+
contentPinned={resizing}
|
|
352
|
+
/>
|
|
353
|
+
);
|
|
313
354
|
if (!slide) return content;
|
|
314
355
|
return (
|
|
315
356
|
<Box
|
|
@@ -33,6 +33,7 @@ interface ShellPaneManagementShortcutOptions {
|
|
|
33
33
|
startWindowMode(paneId?: string, mode?: WindowEditMode): void;
|
|
34
34
|
toggleFocusedPaneFullscreen(): boolean;
|
|
35
35
|
toggleFocusedPaneFloating(): boolean;
|
|
36
|
+
toggleFocusedPaneNewLayout(): boolean;
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
export function useShellPaneManagementShortcuts({
|
|
@@ -54,6 +55,7 @@ export function useShellPaneManagementShortcuts({
|
|
|
54
55
|
startWindowMode,
|
|
55
56
|
toggleFocusedPaneFullscreen,
|
|
56
57
|
toggleFocusedPaneFloating,
|
|
58
|
+
toggleFocusedPaneNewLayout,
|
|
57
59
|
}: ShellPaneManagementShortcutOptions): void {
|
|
58
60
|
const doubleEscapeCloseRef = useRef(createDoubleEscapeCloseState());
|
|
59
61
|
const keybindings = useKeybindings();
|
|
@@ -153,6 +155,9 @@ export function useShellPaneManagementShortcuts({
|
|
|
153
155
|
case "toggle-floating":
|
|
154
156
|
handled = toggleFocusedPaneFloating();
|
|
155
157
|
break;
|
|
158
|
+
case "new-layout":
|
|
159
|
+
handled = toggleFocusedPaneNewLayout();
|
|
160
|
+
break;
|
|
156
161
|
case "pop-out":
|
|
157
162
|
handled = popOutFocusedPane();
|
|
158
163
|
break;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { useCallback, type Dispatch } from "react";
|
|
2
|
+
import { formatAdvertisedChord, type ResolvedKeybindings } from "../../../../app/keybindings";
|
|
3
|
+
import { tf } from "../../../../i18n";
|
|
4
|
+
import {
|
|
5
|
+
createSavedLayoutId,
|
|
6
|
+
paneMoveBackTarget,
|
|
7
|
+
paneNewLayoutBlock,
|
|
8
|
+
type PaneMoveBackTarget,
|
|
9
|
+
type PaneNewLayoutBlock,
|
|
10
|
+
} from "../../../../layout/pane-layout-move";
|
|
11
|
+
import type { PluginRegistry } from "../../../../plugins/registry";
|
|
12
|
+
import { resolveTickerForPane, type AppAction, type AppState } from "../../../../state/app/context";
|
|
13
|
+
import { findPaneInstance } from "../../../../types/config";
|
|
14
|
+
import type { ShortcutDisplayMode } from "../../../../utils/shortcut-labels";
|
|
15
|
+
import { getBasePaneDisplayTitle } from "../../pane/title";
|
|
16
|
+
import type { PaneMenuLayoutMove } from "../menu";
|
|
17
|
+
|
|
18
|
+
const BLOCK_MESSAGES: Partial<Record<PaneNewLayoutBlock, string>> = {
|
|
19
|
+
"only-pane": "Already the only pane in this layout",
|
|
20
|
+
"no-ticker": "Select a ticker in the list this pane follows first",
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
// The first move of a session says how to undo it; after that the layout tab is enough.
|
|
24
|
+
let moveBackHintShown = false;
|
|
25
|
+
|
|
26
|
+
interface UseShellPaneLayoutMovesOptions {
|
|
27
|
+
closePaneMenu: () => void;
|
|
28
|
+
dispatch: Dispatch<AppAction>;
|
|
29
|
+
keybindings: ResolvedKeybindings;
|
|
30
|
+
/** Leaves anything that shows this pane over the layout, such as fullscreen, before it moves. */
|
|
31
|
+
leavePane: (paneId: string) => void;
|
|
32
|
+
pluginRegistry: PluginRegistry;
|
|
33
|
+
shortcutDisplayMode: ShortcutDisplayMode;
|
|
34
|
+
stateRef: { current: AppState };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Move to New Layout and Move Back for the shell's pane menu, its shortcut
|
|
39
|
+
* and the command bar. The layout work is in `layout/pane-layout-move`.
|
|
40
|
+
*/
|
|
41
|
+
export function useShellPaneLayoutMoves({
|
|
42
|
+
closePaneMenu,
|
|
43
|
+
dispatch,
|
|
44
|
+
keybindings,
|
|
45
|
+
leavePane,
|
|
46
|
+
pluginRegistry,
|
|
47
|
+
shortcutDisplayMode,
|
|
48
|
+
stateRef,
|
|
49
|
+
}: UseShellPaneLayoutMovesOptions) {
|
|
50
|
+
const blockFor = useCallback((paneId: string): PaneNewLayoutBlock | null => {
|
|
51
|
+
const state = stateRef.current;
|
|
52
|
+
return paneNewLayoutBlock(state.config.layout, paneId, (instanceId) => resolveTickerForPane(state, instanceId));
|
|
53
|
+
}, [stateRef]);
|
|
54
|
+
|
|
55
|
+
const moveBackTargetFor = useCallback(
|
|
56
|
+
(paneId: string): PaneMoveBackTarget | null => paneMoveBackTarget(stateRef.current.config, paneId),
|
|
57
|
+
[stateRef],
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
const movePaneToNewLayout = useCallback((paneId: string): boolean => {
|
|
61
|
+
const block = blockFor(paneId);
|
|
62
|
+
if (block === "missing" || block === "detached") return false;
|
|
63
|
+
const blockMessage = block ? BLOCK_MESSAGES[block] : undefined;
|
|
64
|
+
if (blockMessage) {
|
|
65
|
+
pluginRegistry.notify({ body: blockMessage, type: "info" });
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
const state = stateRef.current;
|
|
69
|
+
const instance = findPaneInstance(state.config.layout, paneId);
|
|
70
|
+
if (!instance) return false;
|
|
71
|
+
const def = pluginRegistry.panes.get(instance.paneId);
|
|
72
|
+
const name = (def ? getBasePaneDisplayTitle(state, instance, def, pluginRegistry.panes) : instance.title)?.trim()
|
|
73
|
+
|| instance.paneId;
|
|
74
|
+
closePaneMenu();
|
|
75
|
+
leavePane(paneId);
|
|
76
|
+
dispatch({ type: "MOVE_PANE_TO_NEW_LAYOUT", paneId, name, sourceLayoutId: createSavedLayoutId() });
|
|
77
|
+
if (!moveBackHintShown) {
|
|
78
|
+
moveBackHintShown = true;
|
|
79
|
+
const shortcut = formatAdvertisedChord(keybindings, "pane-new-layout", shortcutDisplayMode);
|
|
80
|
+
pluginRegistry.notify({
|
|
81
|
+
body: shortcut
|
|
82
|
+
? tf("Moved to a layout of its own. {shortcut} moves it back.", { shortcut })
|
|
83
|
+
: "Moved to a layout of its own. Move Back in its menu returns it.",
|
|
84
|
+
type: "info",
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
return true;
|
|
88
|
+
}, [blockFor, closePaneMenu, dispatch, keybindings, leavePane, pluginRegistry, shortcutDisplayMode, stateRef]);
|
|
89
|
+
|
|
90
|
+
const movePaneBack = useCallback((paneId: string): boolean => {
|
|
91
|
+
if (!moveBackTargetFor(paneId)) return false;
|
|
92
|
+
closePaneMenu();
|
|
93
|
+
leavePane(paneId);
|
|
94
|
+
dispatch({ type: "MOVE_PANE_BACK", paneId });
|
|
95
|
+
return true;
|
|
96
|
+
}, [closePaneMenu, dispatch, leavePane, moveBackTargetFor]);
|
|
97
|
+
|
|
98
|
+
/** The shortcut: a pane alone in the layout it was moved to goes back, any other gets a layout of its own. */
|
|
99
|
+
const togglePaneNewLayout = useCallback((paneId: string | null): boolean => {
|
|
100
|
+
if (!paneId) return false;
|
|
101
|
+
if (blockFor(paneId) === "only-pane" && movePaneBack(paneId)) return true;
|
|
102
|
+
return movePaneToNewLayout(paneId);
|
|
103
|
+
}, [blockFor, movePaneBack, movePaneToNewLayout]);
|
|
104
|
+
|
|
105
|
+
/** What the pane menu offers: Move to New Layout unless the pane is alone, Move Back when it came from elsewhere. */
|
|
106
|
+
const paneLayoutMoveMenu = useCallback((paneId: string): PaneMenuLayoutMove => {
|
|
107
|
+
const block = blockFor(paneId);
|
|
108
|
+
const back = moveBackTargetFor(paneId);
|
|
109
|
+
return {
|
|
110
|
+
...(block === null || block === "no-ticker" ? { moveToNewLayout: () => { movePaneToNewLayout(paneId); } } : {}),
|
|
111
|
+
...(back ? { moveBack: { layoutName: back.name, onSelect: () => { movePaneBack(paneId); } } } : {}),
|
|
112
|
+
};
|
|
113
|
+
}, [blockFor, moveBackTargetFor, movePaneBack, movePaneToNewLayout]);
|
|
114
|
+
|
|
115
|
+
return { movePaneBack, movePaneToNewLayout, paneLayoutMoveMenu, togglePaneNewLayout };
|
|
116
|
+
}
|
|
@@ -12,6 +12,7 @@ export type PaneManagementShortcut =
|
|
|
12
12
|
| "menu"
|
|
13
13
|
| "settings"
|
|
14
14
|
| "toggle-fullscreen"
|
|
15
|
+
| "new-layout"
|
|
15
16
|
| "toggle-floating"
|
|
16
17
|
| "pop-out"
|
|
17
18
|
| "copy-screenshot"
|
|
@@ -28,6 +29,7 @@ const PANE_ACTION_TO_SHORTCUT: Partial<Record<CoreKeybindingActionId, PaneManage
|
|
|
28
29
|
"pane-menu": "menu",
|
|
29
30
|
"pane-settings": "settings",
|
|
30
31
|
"pane-fullscreen": "toggle-fullscreen",
|
|
32
|
+
"pane-new-layout": "new-layout",
|
|
31
33
|
"pane-float": "toggle-floating",
|
|
32
34
|
"pane-pop-out": "pop-out",
|
|
33
35
|
"pane-screenshot": "copy-screenshot",
|
|
@@ -42,7 +44,7 @@ const PANE_ACTION_TO_SHORTCUT: Partial<Record<CoreKeybindingActionId, PaneManage
|
|
|
42
44
|
};
|
|
43
45
|
|
|
44
46
|
export type PaneManagementAccelerators = Record<
|
|
45
|
-
"menu" | "settings" | "fullscreen" | "toggleFloating" | "popOut" | "copyScreenshot" | "exportCsv" | "share" | "close"
|
|
47
|
+
"menu" | "settings" | "fullscreen" | "newLayout" | "toggleFloating" | "popOut" | "copyScreenshot" | "exportCsv" | "share" | "close"
|
|
46
48
|
| "closeAllFloating" | "layoutGallery" | "gridlockAll" | "windowMode" | "windowResizeMode",
|
|
47
49
|
string | undefined
|
|
48
50
|
>;
|
|
@@ -53,6 +55,7 @@ export function paneManagementAccelerators(keybindings: ResolvedKeybindings): Pa
|
|
|
53
55
|
menu: menuAcceleratorFor(keybindings, "pane-menu"),
|
|
54
56
|
settings: menuAcceleratorFor(keybindings, "pane-settings"),
|
|
55
57
|
fullscreen: menuAcceleratorFor(keybindings, "pane-fullscreen"),
|
|
58
|
+
newLayout: menuAcceleratorFor(keybindings, "pane-new-layout"),
|
|
56
59
|
toggleFloating: menuAcceleratorFor(keybindings, "pane-float"),
|
|
57
60
|
popOut: menuAcceleratorFor(keybindings, "pane-pop-out"),
|
|
58
61
|
copyScreenshot: menuAcceleratorFor(keybindings, "pane-screenshot"),
|
|
@@ -98,7 +101,7 @@ export function inputCaptureAllowsPaneManagementShortcut(
|
|
|
98
101
|
// A screenshot does not edit the field that captured input. Keep it available
|
|
99
102
|
// from composers (ASKG, chat, etc.) on both desktop modifier layouts.
|
|
100
103
|
if (shortcut === "copy-screenshot") return event.ctrl || event.meta || event.super === true;
|
|
101
|
-
if (shortcut === "toggle-fullscreen") return event.meta || event.super === true;
|
|
104
|
+
if (shortcut === "toggle-fullscreen" || shortcut === "new-layout") return event.meta || event.super === true;
|
|
102
105
|
if (shortcut !== "close" && shortcut !== "close-all-floating") return false;
|
|
103
106
|
return event.meta || event.super || event.targetEditable !== true;
|
|
104
107
|
}
|
|
@@ -1,8 +1,22 @@
|
|
|
1
1
|
import {
|
|
2
2
|
removeUnavailablePaneTypes,
|
|
3
|
+
restoreHiddenPanes,
|
|
3
4
|
type PaneTypeAvailability,
|
|
4
5
|
} from "../../../layout/pane-manager";
|
|
5
|
-
import type {
|
|
6
|
+
import type { PluginRegistry } from "../../../plugins/registry";
|
|
7
|
+
import type { LayoutConfig, PaneInstanceConfig } from "../../../types/config";
|
|
8
|
+
|
|
9
|
+
/** The pane types of every plugin that is switched off. */
|
|
10
|
+
export function collectDisabledPaneIds(
|
|
11
|
+
pluginRegistry: Pick<PluginRegistry, "getPluginPaneIds">,
|
|
12
|
+
disabledPlugins: readonly string[],
|
|
13
|
+
): Set<string> {
|
|
14
|
+
const paneIds = new Set<string>();
|
|
15
|
+
for (const pluginId of new Set(disabledPlugins)) {
|
|
16
|
+
for (const paneId of pluginRegistry.getPluginPaneIds(pluginId)) paneIds.add(paneId);
|
|
17
|
+
}
|
|
18
|
+
return paneIds;
|
|
19
|
+
}
|
|
6
20
|
|
|
7
21
|
export function resolveShellVisibleLayout(
|
|
8
22
|
layout: LayoutConfig,
|
|
@@ -15,3 +29,32 @@ export function resolveShellVisibleLayout(
|
|
|
15
29
|
{ disabledPaneIds },
|
|
16
30
|
);
|
|
17
31
|
}
|
|
32
|
+
|
|
33
|
+
/** A pane the shell leaves off screen: its plugin is off, or nothing registered its type. */
|
|
34
|
+
function isShellHiddenPane(
|
|
35
|
+
instance: PaneInstanceConfig,
|
|
36
|
+
disabledPaneIds: ReadonlySet<string>,
|
|
37
|
+
registeredPaneIds: PaneTypeAvailability,
|
|
38
|
+
): boolean {
|
|
39
|
+
const registered = typeof registeredPaneIds === "function"
|
|
40
|
+
? !!registeredPaneIds(instance.paneId)
|
|
41
|
+
: registeredPaneIds.has(instance.paneId);
|
|
42
|
+
return !registered || disabledPaneIds.has(instance.paneId);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* What to save after an edit made on the visible layout: the edit, with every
|
|
47
|
+
* pane the shell hid put back from the saved layout.
|
|
48
|
+
*/
|
|
49
|
+
export function restoreShellHiddenPanes(
|
|
50
|
+
saved: LayoutConfig,
|
|
51
|
+
edited: LayoutConfig,
|
|
52
|
+
disabledPaneIds: ReadonlySet<string>,
|
|
53
|
+
registeredPaneIds: PaneTypeAvailability,
|
|
54
|
+
): LayoutConfig {
|
|
55
|
+
return restoreHiddenPanes(
|
|
56
|
+
saved,
|
|
57
|
+
edited,
|
|
58
|
+
(instance) => isShellHiddenPane(instance, disabledPaneIds, registeredPaneIds),
|
|
59
|
+
);
|
|
60
|
+
}
|
|
@@ -13,6 +13,7 @@ import { blendHex, hoverBg } from "../../theme/colors";
|
|
|
13
13
|
import { t, tf } from "../../i18n";
|
|
14
14
|
import { useThemeColors } from "../../theme/theme-context";
|
|
15
15
|
import { useAppDispatch, useAppSelector } from "../../state/app/context";
|
|
16
|
+
import { useAppChromeShown } from "./presentation";
|
|
16
17
|
import { useViewport } from "../../react/input";
|
|
17
18
|
import {
|
|
18
19
|
advertisedChord,
|
|
@@ -53,6 +54,7 @@ import {
|
|
|
53
54
|
useClaimedStatusWidgetColumns,
|
|
54
55
|
usePublishStatusWidgetRoom,
|
|
55
56
|
} from "./status-widget-space";
|
|
57
|
+
import { StarPromptStatusLine } from "../../app/star-prompt/status-line";
|
|
56
58
|
|
|
57
59
|
type StatusBarEvent = { stopPropagation?: () => void; preventDefault?: () => void };
|
|
58
60
|
type HoveredControl = string | null;
|
|
@@ -145,7 +147,7 @@ export function StatusBar({ onOpenChangelog }: { onOpenChangelog?: (version: str
|
|
|
145
147
|
const { width: termWidth } = useViewport();
|
|
146
148
|
const layouts = useAppSelector((state) => state.config.layouts);
|
|
147
149
|
const activeLayoutIdx = useAppSelector((state) => state.config.activeLayoutIndex);
|
|
148
|
-
const statusBarVisible =
|
|
150
|
+
const statusBarVisible = useAppChromeShown().statusBar;
|
|
149
151
|
const layout = useAppSelector((state) => state.config.layout);
|
|
150
152
|
const { transientLayout } = useTransientLayout();
|
|
151
153
|
const [hoveredControl, setHoveredControl] = useState<string | null>(null);
|
|
@@ -498,6 +500,7 @@ function TerminalStatusBar({
|
|
|
498
500
|
{showTidyWindows && <TerminalTidyWindows {...props} />}
|
|
499
501
|
<Box flexGrow={1} minWidth={0} />
|
|
500
502
|
<StatusBarSummary nativePaneChrome={false} {...props} />
|
|
503
|
+
<StarPromptStatusLine />
|
|
501
504
|
<PluginSlot name="status:widget" />
|
|
502
505
|
<StatusBarFeedback nativePaneChrome={false} {...props} />
|
|
503
506
|
</Box>
|
|
@@ -30,23 +30,27 @@ interface ParsedLine {
|
|
|
30
30
|
indent?: number;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
// A backslash escapes the punctuation markdown would read ("\\*" is a star), and
|
|
34
|
+
// an italic span may hold a bold one ("*covers **96%** of value*").
|
|
33
35
|
const INLINE_RE =
|
|
34
|
-
/(
|
|
36
|
+
/(\\(?<escaped>[\\`*_~#>[\]()-])|\*\*(?<bold>[^*]+)\*\*|(?<!\*)\*(?!\*)(?<italic>(?:[^*]|\*\*[^*]+\*\*)+?)\*(?!\*)|`(?<code>[^`]+)`|~~(?<strike>[^~]+)~~)/g;
|
|
35
37
|
|
|
36
38
|
function parseInlineMarkdown(text: string): StyledSegment[] {
|
|
37
39
|
const segments: StyledSegment[] = [];
|
|
38
40
|
let cursor = 0;
|
|
39
41
|
|
|
40
|
-
INLINE_RE.
|
|
42
|
+
const pattern = new RegExp(INLINE_RE.source, "g");
|
|
41
43
|
let match: RegExpExecArray | null;
|
|
42
|
-
while ((match =
|
|
44
|
+
while ((match = pattern.exec(text)) !== null) {
|
|
43
45
|
if (match.index > cursor) {
|
|
44
46
|
segments.push({ text: text.slice(cursor, match.index) });
|
|
45
47
|
}
|
|
46
|
-
if (match.groups?.
|
|
48
|
+
if (match.groups?.escaped != null) {
|
|
49
|
+
segments.push({ text: match.groups.escaped });
|
|
50
|
+
} else if (match.groups?.bold != null) {
|
|
47
51
|
segments.push({ text: match.groups.bold, bold: true });
|
|
48
52
|
} else if (match.groups?.italic != null) {
|
|
49
|
-
|
|
53
|
+
for (const inner of parseInlineMarkdown(match.groups.italic)) segments.push({ ...inner, italic: true });
|
|
50
54
|
} else if (match.groups?.code != null) {
|
|
51
55
|
segments.push({ text: match.groups.code, code: true });
|
|
52
56
|
} else if (match.groups?.strike != null) {
|
|
@@ -209,6 +209,17 @@ function useItemsById<T>(scene: MetricTreemapScene<T>, items: readonly MetricTre
|
|
|
209
209
|
|
|
210
210
|
const VISIBLE_FADE_DISTANCE = 0.03;
|
|
211
211
|
|
|
212
|
+
/** Text up a tall tile reads bottom to top, as a chart's vertical axis title does; the move sits right of the ticker. */
|
|
213
|
+
const VERTICAL_LABEL_STYLE: CSSProperties = {
|
|
214
|
+
position: "relative",
|
|
215
|
+
display: "block",
|
|
216
|
+
flexShrink: 0,
|
|
217
|
+
maxHeight: "100%",
|
|
218
|
+
overflow: "hidden",
|
|
219
|
+
writingMode: "vertical-rl",
|
|
220
|
+
transform: "rotate(180deg)",
|
|
221
|
+
};
|
|
222
|
+
|
|
212
223
|
const DomHeatTile = memo(function DomHeatTile({
|
|
213
224
|
id, rect, canvasWidth, canvasHeight, gap, label, value, valueSuffix, background, foreground,
|
|
214
225
|
selected, reducedMotion, glide, pulseCount, events,
|
|
@@ -230,7 +241,10 @@ const DomHeatTile = memo(function DomHeatTile({
|
|
|
230
241
|
events: SurfaceEvents;
|
|
231
242
|
}) {
|
|
232
243
|
const text = heatTileLabelPx(rect.width - gap * 2, rect.height - gap * 2, label, value);
|
|
233
|
-
const shownValue = heatTileValueWithSuffix(value, valueSuffix, {
|
|
244
|
+
const shownValue = heatTileValueWithSuffix(value, valueSuffix, {
|
|
245
|
+
width: (text.vertical ? rect.height : rect.width) - gap * 2,
|
|
246
|
+
valuePx: text.valuePx,
|
|
247
|
+
});
|
|
234
248
|
// Where this tile sat before the last relayout, kept to slide it from there.
|
|
235
249
|
const placedRef = useRef(rect);
|
|
236
250
|
const glideRef = useRef<{ dx: number; dy: number; count: number }>({ dx: 0, dy: 0, count: 0 });
|
|
@@ -305,13 +319,23 @@ const DomHeatTile = memo(function DomHeatTile({
|
|
|
305
319
|
const lineStyle: CSSProperties = {
|
|
306
320
|
position: "relative",
|
|
307
321
|
display: "block",
|
|
308
|
-
maxWidth: "100%",
|
|
322
|
+
maxWidth: text.vertical ? undefined : "100%",
|
|
309
323
|
overflow: "hidden",
|
|
310
324
|
whiteSpace: "nowrap",
|
|
311
325
|
textAlign: "center",
|
|
312
326
|
letterSpacing: 0,
|
|
313
327
|
color: foreground,
|
|
314
328
|
};
|
|
329
|
+
const lines = (
|
|
330
|
+
<>
|
|
331
|
+
{text.tier !== "none" && (
|
|
332
|
+
<Text style={{ ...lineStyle, fontSize: text.tickerPx, fontWeight: 700, lineHeight: 1.12 }}>{label}</Text>
|
|
333
|
+
)}
|
|
334
|
+
{text.tier === "full" && value && (
|
|
335
|
+
<Text style={{ ...lineStyle, fontSize: text.valuePx, fontWeight: 500, lineHeight: 1.12 }}>{shownValue}</Text>
|
|
336
|
+
)}
|
|
337
|
+
</>
|
|
338
|
+
);
|
|
315
339
|
return (
|
|
316
340
|
<Box
|
|
317
341
|
data-gloom-role="heat-tile"
|
|
@@ -347,12 +371,7 @@ const DomHeatTile = memo(function DomHeatTile({
|
|
|
347
371
|
}}
|
|
348
372
|
/>
|
|
349
373
|
)}
|
|
350
|
-
{text.
|
|
351
|
-
<Text style={{ ...lineStyle, fontSize: text.tickerPx, fontWeight: 700, lineHeight: 1.12 }}>{label}</Text>
|
|
352
|
-
)}
|
|
353
|
-
{text.tier === "full" && value && (
|
|
354
|
-
<Text style={{ ...lineStyle, fontSize: text.valuePx, fontWeight: 500, lineHeight: 1.12 }}>{shownValue}</Text>
|
|
355
|
-
)}
|
|
374
|
+
{text.vertical ? <Box style={VERTICAL_LABEL_STYLE}>{lines}</Box> : lines}
|
|
356
375
|
</Box>
|
|
357
376
|
);
|
|
358
377
|
});
|
|
@@ -11,11 +11,16 @@ export interface HeatTileLabel {
|
|
|
11
11
|
/** Font sizes in px, for the desktop and the web. */
|
|
12
12
|
tickerPx: number;
|
|
13
13
|
valuePx: number;
|
|
14
|
+
/** The label runs up the tile: it fits only along a tall tile's length. */
|
|
15
|
+
vertical: boolean;
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
/** Advance of one monospace glyph, in em. */
|
|
17
19
|
const MONO_CHAR_EM = 0.62;
|
|
20
|
+
/** The margin either side of the text while it has room to grow. */
|
|
18
21
|
const TILE_PAD_X_PX = 3;
|
|
22
|
+
/** The margin it gives way to rather than drop below its smallest size. */
|
|
23
|
+
const MIN_TILE_PAD_X_PX = 1;
|
|
19
24
|
const TILE_PAD_Y_PX = 2;
|
|
20
25
|
const MAX_TICKER_PX = 26;
|
|
21
26
|
const MIN_TICKER_PX = 9;
|
|
@@ -27,36 +32,62 @@ const LINE_HEIGHT = 1.12;
|
|
|
27
32
|
/** Text grows with the tile's area, not just its width, so a long thin tile stays calm. */
|
|
28
33
|
const AREA_FONT_DIVISOR = 4.4;
|
|
29
34
|
|
|
30
|
-
const NO_LABEL: HeatTileLabel = { tier: "none", tickerPx: 0, valuePx: 0 };
|
|
35
|
+
const NO_LABEL: HeatTileLabel = { tier: "none", tickerPx: 0, valuePx: 0, vertical: false };
|
|
31
36
|
|
|
32
|
-
|
|
33
|
-
|
|
37
|
+
/**
|
|
38
|
+
* The largest font size at which text `ems` glyph advances long crosses
|
|
39
|
+
* `width` with the full margin. Rather than drop below `floor`, the text takes
|
|
40
|
+
* the margin, down to the narrowest one.
|
|
41
|
+
*/
|
|
42
|
+
function sizeAcross(width: number, ems: number, floor: number): number {
|
|
43
|
+
const size = (width - TILE_PAD_X_PX * 2) / ems;
|
|
44
|
+
if (size >= floor) return size;
|
|
45
|
+
return (width - MIN_TILE_PAD_X_PX * 2) / ems >= floor ? floor : size;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** The label laid across a `width` by `height` box. */
|
|
49
|
+
function fitLabel(width: number, height: number, ticker: string, value: string | null): HeatTileLabel {
|
|
50
|
+
const roomWidth = width - MIN_TILE_PAD_X_PX * 2;
|
|
34
51
|
const innerHeight = height - TILE_PAD_Y_PX * 2;
|
|
35
|
-
if (
|
|
36
|
-
const byWidth = innerWidth / (ticker.length * MONO_CHAR_EM);
|
|
52
|
+
if (roomWidth <= 0 || innerHeight <= 0 || ticker.length === 0) return NO_LABEL;
|
|
37
53
|
// Area caps big tiles only; a small one may still use the smallest readable size.
|
|
38
54
|
const byArea = Math.max(MIN_FULL_TICKER_PX, Math.sqrt(width * height) / AREA_FONT_DIVISOR);
|
|
39
|
-
const
|
|
55
|
+
const lines = innerHeight / LINE_HEIGHT;
|
|
40
56
|
|
|
41
57
|
if (value) {
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
58
|
+
const tickerPx = Math.min(
|
|
59
|
+
MAX_TICKER_PX,
|
|
60
|
+
byArea,
|
|
61
|
+
sizeAcross(width, ticker.length * MONO_CHAR_EM, MIN_FULL_TICKER_PX),
|
|
62
|
+
sizeAcross(width, value.length * MONO_CHAR_EM * VALUE_SCALE, MIN_FULL_TICKER_PX),
|
|
63
|
+
// Both lines stacked, with the move at its own floor when the ticker is small.
|
|
64
|
+
lines / (1 + VALUE_SCALE),
|
|
65
|
+
lines - MIN_VALUE_PX,
|
|
66
|
+
);
|
|
45
67
|
const valuePx = Math.max(MIN_VALUE_PX, tickerPx * VALUE_SCALE);
|
|
46
|
-
if (
|
|
47
|
-
tickerPx
|
|
48
|
-
&& value.length * MONO_CHAR_EM * valuePx <= innerWidth
|
|
49
|
-
&& (tickerPx + valuePx) * LINE_HEIGHT <= innerHeight
|
|
50
|
-
) {
|
|
51
|
-
return { tier: "full", tickerPx, valuePx };
|
|
68
|
+
if (tickerPx >= MIN_FULL_TICKER_PX && value.length * MONO_CHAR_EM * valuePx <= roomWidth) {
|
|
69
|
+
return { tier: "full", tickerPx, valuePx, vertical: false };
|
|
52
70
|
}
|
|
53
71
|
}
|
|
54
72
|
|
|
55
|
-
const tickerPx = Math.min(
|
|
56
|
-
if (tickerPx >= MIN_TICKER_PX) return { tier: "ticker", tickerPx, valuePx: 0 };
|
|
73
|
+
const tickerPx = Math.min(MAX_TICKER_PX, byArea, sizeAcross(width, ticker.length * MONO_CHAR_EM, MIN_TICKER_PX), lines);
|
|
74
|
+
if (tickerPx >= MIN_TICKER_PX) return { tier: "ticker", tickerPx, valuePx: 0, vertical: false };
|
|
57
75
|
return NO_LABEL;
|
|
58
76
|
}
|
|
59
77
|
|
|
78
|
+
/**
|
|
79
|
+
* The label is laid across the tile where it fits that way, and otherwise up
|
|
80
|
+
* a tall tile, so a tile the layout stood on end is labelled as it would be
|
|
81
|
+
* lying down: a tall tile narrower than its ticker still carries it. A flat
|
|
82
|
+
* strip too short for a line stays blank rather than show a letter on its side.
|
|
83
|
+
*/
|
|
84
|
+
export function heatTileLabelPx(width: number, height: number, ticker: string, value: string | null): HeatTileLabel {
|
|
85
|
+
const across = fitLabel(width, height, ticker, value);
|
|
86
|
+
if (across.tier !== "none" || height <= width) return across;
|
|
87
|
+
const along = fitLabel(height, width, ticker, value);
|
|
88
|
+
return along.tier === "none" ? NO_LABEL : { ...along, vertical: true };
|
|
89
|
+
}
|
|
90
|
+
|
|
60
91
|
/**
|
|
61
92
|
* The move with its qualifier (an after-hours move's AH) where that still fits
|
|
62
93
|
* at the size the move alone was given, else the move alone. The qualifier
|