gloomberb 0.16.1 → 0.16.3
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 +2 -1
- package/package.json +2 -1
- package/src/api-client/beneficial-owners.ts +92 -0
- package/src/api-client/data.ts +26 -8
- package/src/api-client/errors.ts +12 -0
- package/src/api-client/geo.ts +363 -0
- package/src/api-client/index.ts +2 -0
- package/src/api-client/market-discovery.ts +10 -0
- package/src/api-client/paths.ts +30 -1
- package/src/api-client/perps.ts +37 -0
- package/src/api-client/request.ts +5 -2
- package/src/api-client/types.ts +2 -0
- package/src/brokers/account-cache.ts +69 -0
- package/src/cli/command-options.ts +74 -0
- package/src/cli/commands/command-utils.ts +37 -0
- package/src/cli/commands/crypto-hints.ts +75 -0
- package/src/cli/commands/market.ts +560 -136
- package/src/cli/commands/overview.ts +136 -48
- package/src/cli/commands/ticker.ts +220 -67
- package/src/cli/desktop-pane-shot.ts +37 -4
- package/src/cli/freshness.ts +61 -0
- package/src/cli/help.ts +27 -6
- package/src/cli/helpers.ts +4 -8
- package/src/cli/history-rows.ts +187 -15
- package/src/cli/index.ts +23 -8
- package/src/cli/listing-arg.ts +321 -0
- package/src/cli/options.ts +5 -1
- package/src/cli/pane-functions/access-gate.ts +42 -0
- package/src/cli/pane-functions/capabilities.ts +5 -0
- package/src/cli/pane-functions/catalog.ts +28 -1
- package/src/cli/pane-functions/data.ts +3 -1
- package/src/cli/pane-functions/dom.ts +87 -16
- package/src/cli/pane-functions/freshness.ts +400 -0
- package/src/cli/pane-functions/function-help.ts +31 -22
- package/src/cli/pane-functions/headless.ts +201 -41
- package/src/cli/pane-functions/index.ts +24 -6
- package/src/cli/pane-functions/options.ts +3 -0
- package/src/cli/pane-functions/report.ts +12 -1
- package/src/cli/pane-functions/resolver.ts +63 -9
- package/src/cli/pane-functions/screenshot-evidence.ts +2 -0
- package/src/cli/pane-functions/screenshot.ts +11 -3
- package/src/cli/registry.ts +6 -3
- package/src/cli/report-tables.ts +460 -0
- package/src/cli/result.ts +53 -29
- package/src/cli/ticker-resolution.ts +7 -5
- package/src/components/chart/composite/composite-chart.tsx +88 -2536
- package/src/components/chart/composite/drawing-store.ts +59 -0
- package/src/components/chart/composite/legend.tsx +319 -0
- package/src/components/chart/composite/panel-bitmap.ts +139 -0
- package/src/components/chart/composite/panel-gestures.ts +59 -0
- package/src/components/chart/composite/panel-labels.ts +107 -0
- package/src/components/chart/composite/panel-surface.tsx +876 -0
- package/src/components/chart/composite/tool-catalog.ts +98 -0
- package/src/components/chart/composite/toolbar.tsx +186 -0
- package/src/components/chart/composite/tools.ts +8 -0
- package/src/components/chart/composite/use-composite-chart-keyboard.ts +703 -0
- package/src/components/chart/composite/use-composite-viewport.ts +143 -0
- package/src/components/command-bar/list/model.ts +5 -0
- package/src/components/command-bar/list/view.tsx +16 -3
- package/src/components/command-bar/pane-templates/workflow.ts +1 -0
- package/src/components/command-bar/routes/ticker-search/actions.ts +5 -0
- package/src/components/command-bar/workflow/ops.ts +1 -1
- package/src/components/command-bar/workflow/tickers.ts +6 -0
- package/src/components/data-table/export.ts +6 -51
- package/src/components/data-table/view.tsx +32 -11
- package/src/components/feedback-dialog.tsx +2 -1
- package/src/components/form-modal/field-row.tsx +2 -2
- package/src/components/layout/detached-pane-shell.tsx +6 -3
- package/src/components/layout/pane/content.tsx +23 -10
- package/src/components/layout/pane/error-boundary.tsx +103 -0
- package/src/components/layout/pane/footer/registration.tsx +68 -23
- package/src/components/layout/pane/header.tsx +11 -11
- package/src/components/layout/shell/active-drag.ts +67 -35
- package/src/components/layout/shell/cursor-occlusion.ts +6 -5
- package/src/components/layout/shell/drag/index.ts +12 -7
- package/src/components/layout/shell/drag/live.ts +122 -0
- package/src/components/layout/shell/drag/overlays.tsx +179 -35
- package/src/components/layout/shell/drag/runtime.ts +62 -50
- package/src/components/layout/shell/drag/slide.ts +10 -0
- package/src/components/layout/shell/index.tsx +37 -51
- package/src/components/layout/shell/menu.ts +2 -1
- package/src/components/layout/shell/native/pointer-runtime.ts +13 -13
- package/src/components/layout/shell/native/surfaces.ts +30 -14
- package/src/components/layout/shell/pane/actions.ts +2 -1
- package/src/components/layout/shell/pane/layers.tsx +419 -168
- package/src/components/layout/shell/terminal-pointer-runtime.ts +18 -18
- package/src/components/layout/shell/window-mode/overlays.tsx +12 -4
- package/src/components/metric-treemap/heat-surface.tsx +43 -16
- package/src/components/metric-treemap/heat-tiles.ts +18 -0
- package/src/components/metric-treemap/layout.ts +2 -0
- package/src/components/onboarding/onboarding-keyboard.ts +311 -0
- package/src/components/onboarding/onboarding-wizard.tsx +101 -788
- package/src/components/onboarding/use-onboarding-broker-form.ts +263 -0
- package/src/components/onboarding/use-onboarding-progress.ts +298 -0
- package/src/components/onboarding/use-onboarding-upgrade.ts +83 -0
- package/src/components/ticker/list-table-view.tsx +13 -1
- package/src/components/ui/fields.tsx +8 -0
- package/src/components/ui/range-track.tsx +10 -3
- package/src/components/ui/status.tsx +8 -2
- package/src/components/ui/tabs.tsx +7 -4
- package/src/components/ui/text-prompt-dialog.tsx +4 -2
- package/src/data/config/store/normalize.ts +17 -1
- package/src/data/json-persistence.ts +17 -3
- package/src/data/json-storage.ts +2 -0
- package/src/data/memory-resource-store.ts +46 -0
- package/src/i18n/es.ts +19 -1
- package/src/i18n/ja.ts +19 -1
- package/src/i18n/ko.ts +19 -1
- package/src/i18n/zh-cn.ts +19 -1
- package/src/i18n/zh-tw.ts +19 -1
- package/src/market-data/coordinator/chart.ts +1 -1
- package/src/market-data/coordinator/quotes.ts +23 -4
- package/src/market-data/fx-closes.ts +72 -0
- package/src/market-data/market/freshness.ts +123 -6
- package/src/market-data/market/session-close-note.ts +57 -0
- package/src/market-data/market/status.ts +151 -0
- package/src/market-data/published-apac-sessions.ts +66 -0
- package/src/market-data/quotes/contributions.ts +2 -0
- package/src/market-data/quotes/freshness.ts +5 -0
- package/src/market-data/quotes/resolution.ts +2 -0
- package/src/market-data/quotes/screener-live-quotes.ts +49 -4
- package/src/plugins/builtin/account-management/pane.tsx +4 -0
- package/src/plugins/builtin/alerts/cli.ts +10 -5
- package/src/plugins/builtin/alerts/index.tsx +1 -0
- package/src/plugins/builtin/analytics/metrics.ts +8 -3
- package/src/plugins/builtin/analytics/pane-model.ts +10 -6
- package/src/plugins/builtin/analytics/risk-client.ts +191 -66
- package/src/plugins/builtin/analytics/risk-fx.ts +102 -0
- package/src/plugins/builtin/analytics/risk-headless.ts +19 -13
- package/src/plugins/builtin/analytics/risk-model.ts +45 -17
- package/src/plugins/builtin/analytics/risk-pane.tsx +1 -0
- package/src/plugins/builtin/analytics/risk-test-data.ts +25 -1
- package/src/plugins/builtin/attention/headless.ts +6 -4
- package/src/plugins/builtin/attention/index.tsx +1 -1
- package/src/plugins/builtin/attention/pane.tsx +2 -2
- package/src/plugins/builtin/awards/headless.ts +1 -0
- package/src/plugins/builtin/awards/pane.tsx +1 -1
- package/src/plugins/builtin/backtest/headless.ts +1 -0
- package/src/plugins/builtin/bond-calculator/headless.ts +1 -0
- package/src/plugins/builtin/buildout/index.tsx +1 -0
- package/src/plugins/builtin/catalysts/detail.tsx +1 -1
- package/src/plugins/builtin/catalysts/headless.ts +3 -1
- package/src/plugins/builtin/cds/headless.ts +2 -0
- package/src/plugins/builtin/central-bank-rates/headless.ts +1 -0
- package/src/plugins/builtin/chart-composer/headless.ts +38 -3
- package/src/plugins/builtin/chart-composer/index.tsx +3 -1
- package/src/plugins/builtin/chart-composer/series-expression.ts +18 -2
- package/src/plugins/builtin/chat/channels.ts +19 -3
- package/src/plugins/builtin/chat/content/composer-runtime.ts +28 -13
- package/src/plugins/builtin/chat/content/footer.tsx +15 -6
- package/src/plugins/builtin/chat/content/index.tsx +120 -21
- package/src/plugins/builtin/chat/content/new-dm-dialog.tsx +261 -113
- package/src/plugins/builtin/chat/content/transcript.tsx +20 -2
- package/src/plugins/builtin/chat/direct-messages.ts +200 -0
- package/src/plugins/builtin/chat/index.tsx +1 -0
- package/src/plugins/builtin/chat/message/desktop.tsx +3 -0
- package/src/plugins/builtin/chat/message/header.tsx +16 -6
- package/src/plugins/builtin/chat/message/inline-tokens.tsx +72 -32
- package/src/plugins/builtin/chat/message/profile-popover.tsx +96 -12
- package/src/plugins/builtin/chat/message/terminal.tsx +3 -0
- package/src/plugins/builtin/chat/message/types.ts +14 -2
- package/src/plugins/builtin/chat/profile-popover.ts +18 -13
- package/src/plugins/builtin/clinical-trials/index.tsx +1 -0
- package/src/plugins/builtin/cloud/askg/executor.ts +2 -1
- package/src/plugins/builtin/cloud/plugin.tsx +1 -0
- package/src/plugins/builtin/cloud/team/module.tsx +1 -0
- package/src/plugins/builtin/cloud/thesis/module.tsx +1 -0
- package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
- package/src/plugins/builtin/comment-letters/index.tsx +1 -0
- package/src/plugins/builtin/company-attention/headless.ts +5 -1
- package/src/plugins/builtin/company-attention/pane.tsx +2 -2
- package/src/plugins/builtin/company-kpis/headless.ts +1 -0
- package/src/plugins/builtin/congress-trades/headless.ts +1 -0
- package/src/plugins/builtin/correlation/compute.ts +59 -16
- package/src/plugins/builtin/correlation/geo.ts +34 -0
- package/src/plugins/builtin/correlation/headless-schema.ts +4 -1
- package/src/plugins/builtin/correlation/headless.ts +42 -8
- package/src/plugins/builtin/correlation/history.ts +2 -0
- package/src/plugins/builtin/correlation/index.tsx +68 -14
- package/src/plugins/builtin/correlation/matrix/model.ts +17 -2
- package/src/plugins/builtin/correlation/matrix/selection.ts +5 -3
- package/src/plugins/builtin/correlation/relationship/model.ts +1 -1
- package/src/plugins/builtin/correlation/relationship/pane.tsx +4 -2
- package/src/plugins/builtin/correlation/relationship/view-model.ts +16 -1
- package/src/plugins/builtin/correlation/settings.ts +1 -1
- package/src/plugins/builtin/cot/headless.ts +6 -3
- package/src/plugins/builtin/cot/index.tsx +3 -3
- package/src/plugins/builtin/cot/model.ts +36 -3
- package/src/plugins/builtin/cpi/headless.ts +4 -0
- package/src/plugins/builtin/credit-boards/headless.ts +2 -0
- package/src/plugins/builtin/credit-conditions/headless.ts +1 -0
- package/src/plugins/builtin/credit-documents/gauge.tsx +5 -8
- package/src/plugins/builtin/credit-documents/headless.ts +2 -0
- package/src/plugins/builtin/crypto-board/headless.ts +3 -0
- package/src/plugins/builtin/custom-view/loader.ts +1 -1
- package/src/plugins/builtin/debt-maturities/headless.ts +4 -0
- package/src/plugins/builtin/dividend-yield/headless.ts +1 -0
- package/src/plugins/builtin/doe/headless.ts +7 -0
- package/src/plugins/builtin/doe/range-bar.tsx +7 -37
- package/src/plugins/builtin/earnings/headless.ts +5 -0
- package/src/plugins/builtin/earnings-calls/headless.ts +1 -0
- package/src/plugins/builtin/earnings-ripple/client.ts +91 -18
- package/src/plugins/builtin/earnings-ripple/headless.ts +28 -8
- package/src/plugins/builtin/earnings-ripple/index.tsx +2 -2
- package/src/plugins/builtin/earnings-ripple/model.ts +97 -7
- package/src/plugins/builtin/earnings-ripple/pane.tsx +148 -23
- package/src/plugins/builtin/econ/index.tsx +1 -0
- package/src/plugins/builtin/econ-statistics/headless.ts +2 -0
- package/src/plugins/builtin/equity-screener/headless.ts +2 -0
- package/src/plugins/builtin/estimate-revisions/headless.ts +1 -0
- package/src/plugins/builtin/executives/index.tsx +1 -0
- package/src/plugins/builtin/exposure/headless.ts +3 -1
- package/src/plugins/builtin/fear-greed/headless.ts +2 -0
- package/src/plugins/builtin/filing-events/index.tsx +1 -0
- package/src/plugins/builtin/futures-curve/client.ts +12 -3
- package/src/plugins/builtin/futures-curve/headless.ts +39 -10
- package/src/plugins/builtin/futures-curve/index.tsx +3 -3
- package/src/plugins/builtin/futures-curve/model.ts +188 -4
- package/src/plugins/builtin/futures-curve/pane.tsx +51 -9
- package/src/plugins/builtin/gpu/headless.ts +7 -3
- package/src/plugins/builtin/gpu/ladder.tsx +26 -30
- package/src/plugins/builtin/gpu/model.ts +27 -1
- package/src/plugins/builtin/holders/beneficial-client.ts +209 -0
- package/src/plugins/builtin/holders/beneficial-model.ts +279 -0
- package/src/plugins/builtin/holders/beneficial-report.ts +126 -0
- package/src/plugins/builtin/holders/beneficial-view.tsx +241 -0
- package/src/plugins/builtin/holders/client.ts +3 -6
- package/src/plugins/builtin/holders/format.ts +31 -1
- package/src/plugins/builtin/holders/headless.ts +161 -6
- package/src/plugins/builtin/holders/index.tsx +10 -3
- package/src/plugins/builtin/holders/pane.tsx +42 -16
- package/src/plugins/builtin/holders/report-header.ts +136 -0
- package/src/plugins/builtin/holders/table-model.ts +20 -5
- package/src/plugins/builtin/holders/thirteenf-match.ts +29 -1
- package/src/plugins/builtin/holders/types.ts +2 -1
- package/src/plugins/builtin/insider/headless.ts +2 -0
- package/src/plugins/builtin/ipo-calendar/headless.ts +1 -0
- package/src/plugins/builtin/iv-history/headless.ts +4 -1
- package/src/plugins/builtin/jobs/headless.ts +1 -0
- package/src/plugins/builtin/kelly-sizer/index.tsx +1 -0
- package/src/plugins/builtin/kelly-sizer/pane.tsx +12 -6
- package/src/plugins/builtin/kelly-sizer/portfolio.ts +25 -0
- package/src/plugins/builtin/macro-day/headless.ts +2 -0
- package/src/plugins/builtin/market-halts/index.tsx +1 -0
- package/src/plugins/builtin/market-heatmap/data.ts +2 -0
- package/src/plugins/builtin/market-heatmap/headless.ts +135 -0
- package/src/plugins/builtin/market-heatmap/index.tsx +39 -46
- package/src/plugins/builtin/market-heatmap/model.ts +146 -0
- package/src/plugins/builtin/market-heatmap/portfolio.ts +23 -4
- package/src/plugins/builtin/market-movers/headless.ts +2 -0
- package/src/plugins/builtin/market-valuation/headless.ts +2 -0
- package/src/plugins/builtin/members/client.ts +20 -3
- package/src/plugins/builtin/members/headless.ts +5 -3
- package/src/plugins/builtin/members/model.ts +10 -2
- package/src/plugins/builtin/members/pane.tsx +23 -6
- package/src/plugins/builtin/mna/distress/headless.ts +1 -0
- package/src/plugins/builtin/mna/headless.ts +1 -0
- package/src/plugins/builtin/money-markets/headless.ts +1 -0
- package/src/plugins/builtin/news/headless.ts +2 -0
- package/src/plugins/builtin/news/wire/index.tsx +8 -1
- package/src/plugins/builtin/notes/cli.ts +14 -6
- package/src/plugins/builtin/notes/index.tsx +1 -0
- package/src/plugins/builtin/openfda/index.tsx +1 -0
- package/src/plugins/builtin/options-calculator/headless.ts +2 -0
- package/src/plugins/builtin/options-positioning/headless.ts +3 -0
- package/src/plugins/builtin/options-scenario/headless.ts +5 -0
- package/src/plugins/builtin/pe-band/client.ts +48 -3
- package/src/plugins/builtin/pe-band/headless.ts +25 -7
- package/src/plugins/builtin/pe-band/model.ts +92 -16
- package/src/plugins/builtin/pe-band/pane.tsx +33 -16
- package/src/plugins/builtin/perps/client.ts +50 -3
- package/src/plugins/builtin/perps/headless.ts +144 -16
- package/src/plugins/builtin/perps/index.tsx +6 -6
- package/src/plugins/builtin/perps/model.ts +189 -12
- package/src/plugins/builtin/perps/pane.tsx +249 -48
- package/src/plugins/builtin/portfolio-list/account-metrics.ts +16 -1
- package/src/plugins/builtin/portfolio-list/allocation.ts +248 -0
- package/src/plugins/builtin/portfolio-list/cached-account.ts +42 -0
- package/src/plugins/builtin/portfolio-list/cell-version.ts +19 -1
- package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +328 -29
- package/src/plugins/builtin/portfolio-list/cli/render.ts +232 -39
- package/src/plugins/builtin/portfolio-list/cli/shared.ts +67 -2
- package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +35 -31
- package/src/plugins/builtin/portfolio-list/column-values.ts +124 -47
- package/src/plugins/builtin/portfolio-list/headless.ts +100 -16
- package/src/plugins/builtin/portfolio-list/index.tsx +14 -3
- package/src/plugins/builtin/portfolio-list/live-valuation.ts +7 -5
- package/src/plugins/builtin/portfolio-list/mutations.ts +55 -1
- package/src/plugins/builtin/portfolio-list/pane/data.ts +6 -0
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +53 -16
- package/src/plugins/builtin/portfolio-list/settings.ts +33 -2
- package/src/plugins/builtin/portfolio-list/summary/index.tsx +46 -5
- package/src/plugins/builtin/portfolio-list/summary/live-accounts.ts +11 -1
- package/src/plugins/builtin/portfolio-list/summary/totals.ts +26 -7
- package/src/plugins/builtin/power/headless.ts +3 -1
- package/src/plugins/builtin/rate-path/headless.ts +2 -0
- package/src/plugins/builtin/realized-vol/headless.ts +2 -0
- package/src/plugins/builtin/relative-rotation/headless.ts +2 -0
- package/src/plugins/builtin/research/analyst-headless.ts +3 -0
- package/src/plugins/builtin/research/events-headless.ts +2 -0
- package/src/plugins/builtin/research/headless.ts +2 -0
- package/src/plugins/builtin/research/index.tsx +1 -0
- package/src/plugins/builtin/research/relative-valuation-headless.ts +10 -5
- package/src/plugins/builtin/research/relative-valuation-model.ts +18 -6
- package/src/plugins/builtin/research/relative-valuation-pane.tsx +3 -3
- package/src/plugins/builtin/research-search/index.tsx +1 -0
- package/src/plugins/builtin/revenue-breakdown/headless.ts +2 -0
- package/src/plugins/builtin/reverse-dcf/headless.ts +2 -0
- package/src/plugins/builtin/reverse-dcf/model.ts +2 -1
- package/src/plugins/builtin/risk-factors/headless.ts +2 -0
- package/src/plugins/builtin/scanner/flow-history.ts +2 -13
- package/src/plugins/builtin/scanner/headless.ts +14 -0
- package/src/plugins/builtin/seasonality/headless.ts +2 -0
- package/src/plugins/builtin/sec/command-bar-search.ts +14 -4
- package/src/plugins/builtin/sec/filing-content.ts +42 -17
- package/src/plugins/builtin/sec/forms.ts +12 -0
- package/src/plugins/builtin/sec/headless.ts +2 -0
- package/src/plugins/builtin/sectors/client.ts +1 -0
- package/src/plugins/builtin/sectors/headless.ts +9 -1
- package/src/plugins/builtin/sectors/sector-model.ts +2 -0
- package/src/plugins/builtin/shared/crypto-pair.ts +14 -0
- package/src/plugins/builtin/shared/locked-rows.tsx +1 -1
- package/src/plugins/builtin/shared/members-menu.tsx +260 -0
- package/src/plugins/builtin/shared/report-freshness.ts +57 -0
- package/src/plugins/builtin/shared/research-cells.tsx +4 -9
- package/src/plugins/builtin/short-interest/headless.ts +2 -0
- package/src/plugins/builtin/short-interest/watch-headless.ts +1 -0
- package/src/plugins/builtin/short-volume/headless.ts +1 -0
- package/src/plugins/builtin/short-volume/pane.tsx +1 -1
- package/src/plugins/builtin/social-mentions/headless.ts +1 -0
- package/src/plugins/builtin/social-mentions/pane.tsx +1 -1
- package/src/plugins/builtin/supply-chain/headless.ts +7 -1
- package/src/plugins/builtin/supply-chain/index.tsx +10 -1
- package/src/plugins/builtin/supply-chain/model.ts +27 -2
- package/src/plugins/builtin/supply-chain/pane.tsx +71 -32
- package/src/plugins/builtin/themes/headless.ts +3 -0
- package/src/plugins/builtin/themes/pane.tsx +3 -0
- package/src/plugins/builtin/thirteenf/headless.ts +110 -25
- package/src/plugins/builtin/thirteenf/report-notes.ts +149 -0
- package/src/plugins/builtin/ticker-detail/financials/aggregation.ts +4 -0
- package/src/plugins/builtin/ticker-detail/financials/model.ts +25 -2
- package/src/plugins/builtin/ticker-detail/headless.ts +27 -5
- package/src/plugins/builtin/ticker-detail/index.tsx +1 -0
- package/src/plugins/builtin/ticker-detail/overview/model.ts +17 -5
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +27 -26
- package/src/plugins/builtin/time-sales/headless.ts +5 -1
- package/src/plugins/builtin/treasury-auctions/headless.ts +1 -0
- package/src/plugins/builtin/volatility/headless.ts +6 -1
- package/src/plugins/builtin/world-indices/headless.ts +2 -0
- package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +159 -0
- package/src/plugins/builtin/world-venue-map/basemap.ts +232 -0
- package/src/plugins/builtin/world-venue-map/client.ts +45 -0
- package/src/plugins/builtin/world-venue-map/country-labels.ts +78 -0
- package/src/plugins/builtin/world-venue-map/entity-detail.tsx +147 -0
- package/src/plugins/builtin/world-venue-map/entity-table.ts +59 -0
- package/src/plugins/builtin/world-venue-map/evidence.ts +77 -0
- package/src/plugins/builtin/world-venue-map/feed.ts +293 -0
- package/src/plugins/builtin/world-venue-map/geo-draw.tsx +248 -0
- package/src/plugins/builtin/world-venue-map/geo-series.ts +142 -0
- package/src/plugins/builtin/world-venue-map/geo-svg.tsx +448 -0
- package/src/plugins/builtin/world-venue-map/headless.ts +146 -0
- package/src/plugins/builtin/world-venue-map/ids.ts +1 -0
- package/src/plugins/builtin/world-venue-map/index.ts +69 -6
- package/src/plugins/builtin/world-venue-map/layered-pane.tsx +565 -0
- package/src/plugins/builtin/world-venue-map/layers.ts +406 -0
- package/src/plugins/builtin/world-venue-map/map-symbols.ts +220 -0
- package/src/plugins/builtin/world-venue-map/map.tsx +557 -85
- package/src/plugins/builtin/world-venue-map/model.ts +23 -4
- package/src/plugins/builtin/world-venue-map/natural-earth/index.chunk.ts +202 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/labels.chunk.ts +244 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/world-50m.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/pane.tsx +35 -44
- package/src/plugins/builtin/world-venue-map/use-geo.ts +55 -0
- package/src/plugins/builtin/world-venue-map/venue-header.tsx +32 -0
- package/src/plugins/builtin/yield-curve/headless.ts +16 -0
- package/src/plugins/loader.ts +13 -1
- package/src/plugins/registry/pane-settings.ts +1 -0
- package/src/renderers/browser/app-services.ts +3 -1
- package/src/renderers/dom/build-assets.ts +81 -3
- package/src/renderers/dom/data-table/dom.ts +31 -0
- package/src/renderers/dom/data-table/index.tsx +5 -0
- package/src/renderers/dom/data-table/row.tsx +2 -0
- package/src/renderers/dom/desktop/controls.tsx +7 -3
- package/src/renderers/dom/desktop/list-view.tsx +35 -10
- package/src/renderers/dom/desktop/popover.tsx +73 -14
- package/src/renderers/dom/host/box.tsx +113 -17
- package/src/renderers/dom/host/drag-shield.ts +24 -0
- package/src/renderers/dom/host/input.tsx +14 -3
- package/src/renderers/dom/host/live-frame.ts +54 -0
- package/src/renderers/dom/host/mouse.ts +8 -1
- package/src/renderers/dom/host/scroll-box.tsx +6 -5
- package/src/renderers/dom/host/tabs.tsx +3 -2
- package/src/renderers/dom/styles.css +16 -9
- package/src/renderers/electrobun/bun/desktop/backend-requests.ts +7 -0
- package/src/renderers/electrobun/bun/desktop/backend.ts +2 -0
- package/src/renderers/electrobun/bun/desktop/initialization.ts +13 -0
- package/src/renderers/electrobun/shared/protocol.ts +10 -1
- package/src/renderers/electrobun/view/backend-rpc.ts +10 -4
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +4 -0
- package/src/renderers/electrobun/view/host/native.ts +0 -10
- package/src/renderers/electrobun/view/host/window-move.ts +28 -0
- package/src/renderers/electrobun/view/remote/persistence.ts +15 -2
- package/src/renderers/electrobun/view/rpc-timeout.ts +14 -3
- package/src/renderers/electrobun/view/ui-host.tsx +2 -5
- package/src/renderers/opentui/host.tsx +5 -0
- package/src/renderers/opentui/ui-host.tsx +7 -1
- package/src/sources/gloomberb-cloud/index.ts +25 -4
- package/src/sources/gloomberb-cloud/normalizers.ts +43 -23
- package/src/sources/provider-router/batches.ts +3 -3
- package/src/sources/provider-router/cached-routes.ts +4 -1
- package/src/sources/provider-router/financial-routes.ts +2 -2
- package/src/sources/provider-router/financials.ts +76 -12
- package/src/sources/provider-router/history.ts +15 -10
- package/src/sources/provider-router/primary.ts +2 -2
- package/src/sources/sec-registrant.ts +75 -0
- package/src/state/app/context/index.tsx +24 -8
- package/src/state/hooks/quote-streaming.ts +41 -26
- package/src/state/pane-scroll-registry.tsx +67 -35
- package/src/sync/core-contributors.ts +4 -0
- package/src/telemetry/crash-reports.ts +4 -1
- package/src/test-support/cli-context.ts +10 -2
- package/src/test-support/margin-account.ts +108 -0
- package/src/theme/heat-colors.ts +266 -84
- package/src/time-series/resolution.ts +15 -0
- package/src/time-series/resolve.ts +1 -1
- package/src/time-series/use-chart-resolution.ts +1 -1
- package/src/types/context-menu.ts +6 -0
- package/src/types/data-provider.ts +2 -0
- package/src/types/financials.ts +35 -3
- package/src/types/headless.ts +79 -2
- package/src/types/plugin.ts +20 -1
- package/src/types/ticker.ts +15 -0
- package/src/ui/host.tsx +26 -0
- package/src/ui/index.tsx +8 -3
- package/src/ui/scroll-box-axis.ts +26 -0
- package/src/updater/index.ts +9 -11
- package/src/utils/async-deadline.ts +21 -0
- package/src/utils/cli-output.ts +5 -1
- package/src/utils/crypto-pair.ts +41 -0
- package/src/utils/currency-units.ts +19 -0
- package/src/utils/depositary-receipt.ts +70 -0
- package/src/utils/display-number.ts +63 -0
- package/src/utils/exchanges.ts +72 -0
- package/src/utils/fire-and-forget.ts +24 -0
- package/src/utils/format.ts +13 -0
- package/src/utils/fundamentals.ts +17 -1
- package/src/utils/price-earnings.ts +70 -3
- package/src/utils/price-history-integrity.ts +19 -6
- package/src/utils/price-history.ts +58 -13
- package/src/utils/rpc-timeout-error.ts +27 -0
- package/src/utils/sec.ts +13 -1
- package/src/utils/utc-time.ts +79 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { CloudWorldVenuePayload } from "../../../api-client";
|
|
2
|
+
import { colors } from "../../../theme/colors";
|
|
3
|
+
import { Box, Text, TextAttributes } from "../../../ui";
|
|
4
|
+
import { formatVenueCountdown, formatVenueLocalTime, venueRemainingSeconds } from "./model";
|
|
5
|
+
|
|
6
|
+
export function SelectedVenueHeader({
|
|
7
|
+
venue,
|
|
8
|
+
checkedAt,
|
|
9
|
+
now,
|
|
10
|
+
width,
|
|
11
|
+
}: {
|
|
12
|
+
venue: CloudWorldVenuePayload | null;
|
|
13
|
+
checkedAt: number;
|
|
14
|
+
now: number;
|
|
15
|
+
width: number;
|
|
16
|
+
}) {
|
|
17
|
+
if (!venue) return <Box height={2} />;
|
|
18
|
+
const remaining = formatVenueCountdown(venueRemainingSeconds(venue, checkedAt, now));
|
|
19
|
+
const state = venue.isOpen ? "OPEN" : "CLOSED";
|
|
20
|
+
const transition = remaining ? `${venue.isOpen ? "closes" : "opens"} ${remaining}` : "";
|
|
21
|
+
return (
|
|
22
|
+
<Box flexDirection="column" height={2} width={width} paddingX={1}>
|
|
23
|
+
<Box flexDirection="row" justifyContent="space-between" width="100%">
|
|
24
|
+
<Text fg={colors.textBright} attributes={TextAttributes.BOLD}>{venue.mic}</Text>
|
|
25
|
+
<Text fg={venue.isOpen ? colors.positive : colors.textDim}>{state}</Text>
|
|
26
|
+
</Box>
|
|
27
|
+
<Text fg={colors.textMuted}>
|
|
28
|
+
{`${venue.city}, ${venue.country} · ${formatVenueLocalTime(venue.timezone, now)}${transition ? ` · ${transition}` : ""}`}
|
|
29
|
+
</Text>
|
|
30
|
+
</Box>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
@@ -52,6 +52,18 @@ const defaultDependencies: Required<YieldCurveHeadlessDependencies> = {
|
|
|
52
52
|
|
|
53
53
|
const bp = (value: number | null) => value == null ? null : Math.round(value * 100);
|
|
54
54
|
|
|
55
|
+
/** The official publisher of each curve, as docs/research-data.md lists them. */
|
|
56
|
+
const CURVE_PUBLISHERS: Record<CurveId, string> = {
|
|
57
|
+
us: "US Treasury",
|
|
58
|
+
"us-real": "US Treasury",
|
|
59
|
+
"us-breakeven": "US Treasury",
|
|
60
|
+
"eu-aaa": "ECB",
|
|
61
|
+
de: "Bundesbank",
|
|
62
|
+
gb: "Bank of England",
|
|
63
|
+
jp: "Japan Ministry of Finance",
|
|
64
|
+
ca: "Bank of Canada",
|
|
65
|
+
};
|
|
66
|
+
|
|
55
67
|
export function createYieldCurveHeadless(
|
|
56
68
|
dependencies: YieldCurveHeadlessDependencies = defaultDependencies,
|
|
57
69
|
): HeadlessPaneDefinition<"rows"> {
|
|
@@ -80,6 +92,7 @@ export function createYieldCurveHeadless(
|
|
|
80
92
|
if (args.options.tab === "world") {
|
|
81
93
|
const rows = await loadWorld(context);
|
|
82
94
|
return {
|
|
95
|
+
freshness: { source: "Government bond publishers", status: "not-a-feed", basis: "daily curves" },
|
|
83
96
|
columns: WORLD_COLUMNS,
|
|
84
97
|
rows: rows.map((row) => ({ market: row.market, twoYear: row.twoYear, tenYear: row.tenYear, thirtyYear: row.thirtyYear,
|
|
85
98
|
twosTensBasisPoints: bp(row.twosTens), tenYearChangeBasisPoints: bp(row.tenYearChange), asOf: row.asOf })),
|
|
@@ -105,6 +118,9 @@ export function createYieldCurveHeadless(
|
|
|
105
118
|
const spread = (id: string) => bp(spreads.find((entry) => entry.id === id)?.value ?? null);
|
|
106
119
|
const twosTens = spread("2s10s");
|
|
107
120
|
return {
|
|
121
|
+
// Each curve is its official publisher's daily close; a past date is a historical curve, not a feed.
|
|
122
|
+
freshness: { source: CURVE_PUBLISHERS[curve], status: "not-a-feed",
|
|
123
|
+
...(requestedDate ? { basis: "historical curve" } : { basis: "daily curve", cadence: "daily" }) },
|
|
108
124
|
...(comparePoints ? { columns: COMPARE_COLUMNS } : {}),
|
|
109
125
|
rows: rows.map((point) => {
|
|
110
126
|
const compare = compareAt(point.maturity);
|
package/src/plugins/loader.ts
CHANGED
|
@@ -204,6 +204,18 @@ export function pluginsMissingHostExports(): string[] {
|
|
|
204
204
|
/** Bun's wording when an import does not resolve, from a native import. */
|
|
205
205
|
const UNRESOLVED_MODULE = /Cannot find (?:module|package) '([^']+)'/;
|
|
206
206
|
|
|
207
|
+
/**
|
|
208
|
+
* The specifier an import failed to resolve. Bun puts it on the error as
|
|
209
|
+
* `specifier`; the message is only a fallback, because from Bun 1.4 it names
|
|
210
|
+
* the package alone ("Cannot find package 'peer' imported from …" for
|
|
211
|
+
* `peer/bridge`), and the subpath decides whether the peer has the file.
|
|
212
|
+
*/
|
|
213
|
+
export function unresolvedSpecifier(err: unknown, message: string): string | undefined {
|
|
214
|
+
const specifier = (err as { specifier?: unknown } | null)?.specifier;
|
|
215
|
+
if (typeof specifier === "string" && specifier) return specifier;
|
|
216
|
+
return UNRESOLVED_MODULE.exec(message)?.[1];
|
|
217
|
+
}
|
|
218
|
+
|
|
207
219
|
/** Imported at another commit earlier in this process, with files besides the entry that Bun keeps. */
|
|
208
220
|
function hasStaleModules(pluginDir: string, commit: string | null): boolean {
|
|
209
221
|
if (!importedCommits.has(pluginDir) || importedCommits.get(pluginDir) === commit) return false;
|
|
@@ -300,7 +312,7 @@ export async function loadExternalPlugin(
|
|
|
300
312
|
// A sibling plugin it imports that is linked now but was not when this
|
|
301
313
|
// process first resolved it. Bun keeps that failure until a restart, which
|
|
302
314
|
// is all the plugin needs: not a crash.
|
|
303
|
-
const unresolved =
|
|
315
|
+
const unresolved = unresolvedSpecifier(err, message);
|
|
304
316
|
if (unresolved && isLinkedPeerModule(pluginDir, unresolved)) {
|
|
305
317
|
loaderLog.info(`${directory} loads after a restart: ${message}`);
|
|
306
318
|
return { ...base, plugin: placeholder, needsRestart: true };
|
|
@@ -44,6 +44,7 @@ export function resolveRegistryPaneQuickSettings(
|
|
|
44
44
|
return resolved.paneDef.quickSettings.flatMap((quickSetting): ResolvedRegistryPaneQuickSetting[] => {
|
|
45
45
|
const field = resolved.settingsDef.fields.find((candidate) => candidate.key === quickSetting.key);
|
|
46
46
|
if (!field) return [];
|
|
47
|
+
if (quickSetting.visible && !quickSetting.visible(resolved.context)) return [];
|
|
47
48
|
if (quickSetting.onValue != null) {
|
|
48
49
|
if (field.type !== "select") return [];
|
|
49
50
|
const onValue = quickSetting.onValue;
|
|
@@ -5,6 +5,7 @@ import { createAppRuntime } from "../../core/app-runtime";
|
|
|
5
5
|
import { createGloomberbCloudCapabilities, createGloomberbCloudProvider } from "../../sources/gloomberb-cloud";
|
|
6
6
|
import { AssetDataRouter } from "../../sources/provider-router";
|
|
7
7
|
import { JsonPersistence } from "../../data/json-persistence";
|
|
8
|
+
import { isBrokerAccountSnapshotKey } from "../../brokers/account-cache";
|
|
8
9
|
import { JsonTickerRepository } from "../../data/json-ticker-repository";
|
|
9
10
|
|
|
10
11
|
export function createBrowserAppServices({ config, plugins, externalPlugins }: AppServicesFactoryOptions) {
|
|
@@ -15,7 +16,8 @@ export function createBrowserAppServices({ config, plugins, externalPlugins }: A
|
|
|
15
16
|
);
|
|
16
17
|
return createAppRuntime({
|
|
17
18
|
config, plugins, externalPlugins, dataProvider,
|
|
18
|
-
|
|
19
|
+
// Broker account snapshots are kept with the positions, so a reload keeps the account's equity and cash.
|
|
20
|
+
persistence: new JsonPersistence(localStorage, { keepResource: isBrokerAccountSnapshotKey }),
|
|
19
21
|
tickerRepository: new JsonTickerRepository(localStorage),
|
|
20
22
|
configure({ pluginRegistry, newsService }) {
|
|
21
23
|
dataProvider.attachRegistry(pluginRegistry);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { readFile, writeFile } from "fs/promises";
|
|
2
|
-
import { join, relative } from "path";
|
|
2
|
+
import { dirname, join, relative, resolve } from "path";
|
|
3
|
+
import type { BunPlugin } from "bun";
|
|
3
4
|
import { TITLEBAR_OVERLAY_HEIGHT_PX } from "../../components/layout/titlebar-overlay";
|
|
4
5
|
|
|
5
6
|
/** Imports whose path ends with the first entry resolve to the second, relative to the view directory. */
|
|
@@ -27,6 +28,13 @@ interface ViewBundleOptions {
|
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
const ELECTROBUN_VIEW_DIR = join(process.cwd(), "src", "renderers", "electrobun", "view");
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Where the world map finds its land data, relative to the map's
|
|
34
|
+
* `basemap.ts`. Only view bundles define it, so the terminal binary, which
|
|
35
|
+
* never draws that map, leaves the data out.
|
|
36
|
+
*/
|
|
37
|
+
export const WORLD_MAP_DATA_SPECIFIER = "./natural-earth/index.chunk.js";
|
|
30
38
|
const DOM_RENDERER_DIR = join(process.cwd(), "src", "renderers", "dom");
|
|
31
39
|
|
|
32
40
|
export function electrobunViewPath(...parts: string[]): string {
|
|
@@ -50,6 +58,7 @@ export async function buildViewBundle({
|
|
|
50
58
|
failureMessage,
|
|
51
59
|
missingEntryMessage,
|
|
52
60
|
}: ViewBundleOptions): Promise<{ script: string; stylesheet: string | null }> {
|
|
61
|
+
const chunks = new Map<string, string>();
|
|
53
62
|
const result = await Bun.build({
|
|
54
63
|
entrypoints: [entrypoint],
|
|
55
64
|
outdir,
|
|
@@ -58,8 +67,15 @@ export async function buildViewBundle({
|
|
|
58
67
|
splitting: false,
|
|
59
68
|
sourcemap,
|
|
60
69
|
minify: true,
|
|
61
|
-
define: {
|
|
62
|
-
|
|
70
|
+
define: {
|
|
71
|
+
"process.env.NODE_ENV": "\"production\"",
|
|
72
|
+
__GLOOM_WORLD_MAP_DATA__: JSON.stringify(WORLD_MAP_DATA_SPECIFIER),
|
|
73
|
+
...define,
|
|
74
|
+
},
|
|
75
|
+
plugins: [
|
|
76
|
+
lazyChunkPlugin(outdir, outdir, chunks),
|
|
77
|
+
...(aliasRules.length > 0 ? [electrobunViewAliasPlugin(aliasRules)] : []),
|
|
78
|
+
],
|
|
63
79
|
});
|
|
64
80
|
|
|
65
81
|
if (!result.success) {
|
|
@@ -69,6 +85,7 @@ export async function buildViewBundle({
|
|
|
69
85
|
|
|
70
86
|
const script = result.outputs.find((output) => output.kind === "entry-point" && output.path.endsWith(".js"));
|
|
71
87
|
if (!script) throw new Error(missingEntryMessage);
|
|
88
|
+
await buildLazyChunks(outdir, chunks, failureMessage);
|
|
72
89
|
|
|
73
90
|
const stylesheet = result.outputs.find((output) => output.path.endsWith(".css"))?.path ?? null;
|
|
74
91
|
if (stylesheet) await writeFile(stylesheet, withTitlebarOverlayHeight(await readFile(stylesheet, "utf8")));
|
|
@@ -122,6 +139,67 @@ ${bootstrapScript}
|
|
|
122
139
|
`;
|
|
123
140
|
}
|
|
124
141
|
|
|
142
|
+
/**
|
|
143
|
+
* The view bundle is one file (no splitting), so a module reached through
|
|
144
|
+
* `import()` would land in it. A module named `*.chunk.ts` and imported as
|
|
145
|
+
* `import("./path/name.chunk.js")` instead ships as its own file at that path
|
|
146
|
+
* next to the importing bundle, fetched the first time it is asked for: large
|
|
147
|
+
* data only some panes draw, such as the world map's coastlines. The terminal
|
|
148
|
+
* and the tests run the source, where the same `import()` loads the module.
|
|
149
|
+
*/
|
|
150
|
+
function lazyChunkPlugin(rootOutdir: string, emitDir: string, chunks: Map<string, string>): BunPlugin {
|
|
151
|
+
return {
|
|
152
|
+
name: "lazy-chunks",
|
|
153
|
+
setup(build) {
|
|
154
|
+
build.onResolve({ filter: /\.chunk(\.js|\.ts)?$/ }, (args) => {
|
|
155
|
+
if (args.kind.startsWith("entry-point") || /[\\/]node_modules[\\/]/.test(args.importer)) return undefined;
|
|
156
|
+
if (args.kind !== "dynamic-import") {
|
|
157
|
+
throw new Error(`${args.path} is a lazy chunk; load it with import() (from ${args.importer})`);
|
|
158
|
+
}
|
|
159
|
+
if (!args.path.startsWith("./") || !args.path.endsWith(".chunk.js")) {
|
|
160
|
+
throw new Error(`Lazy chunk ${args.path} must be imported as "./<path>.chunk.js" (from ${args.importer})`);
|
|
161
|
+
}
|
|
162
|
+
const source = resolve(dirname(args.importer), args.path.replace(/\.js$/, ".ts"));
|
|
163
|
+
const output = resolve(emitDir, args.path);
|
|
164
|
+
if (relative(rootOutdir, output).startsWith("..")) throw new Error(`Lazy chunk ${args.path} would land outside ${rootOutdir}`);
|
|
165
|
+
const existing = chunks.get(output);
|
|
166
|
+
if (existing && existing !== source) throw new Error(`Two lazy chunks emit ${output}: ${existing} and ${source}`);
|
|
167
|
+
chunks.set(output, source);
|
|
168
|
+
return { path: args.path, external: true };
|
|
169
|
+
});
|
|
170
|
+
},
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/** Builds each lazy chunk on its own, and the chunks those load in turn. */
|
|
175
|
+
async function buildLazyChunks(rootOutdir: string, chunks: Map<string, string>, failureMessage: string): Promise<void> {
|
|
176
|
+
const built = new Set<string>();
|
|
177
|
+
let pending = [...chunks.entries()];
|
|
178
|
+
while (pending.length) {
|
|
179
|
+
const nested = new Map<string, string>();
|
|
180
|
+
for (const [output, source] of pending) {
|
|
181
|
+
if (built.has(output)) continue;
|
|
182
|
+
built.add(output);
|
|
183
|
+
const result = await Bun.build({
|
|
184
|
+
entrypoints: [source],
|
|
185
|
+
outdir: dirname(output),
|
|
186
|
+
naming: relative(dirname(output), output),
|
|
187
|
+
target: "browser",
|
|
188
|
+
format: "esm",
|
|
189
|
+
splitting: false,
|
|
190
|
+
sourcemap: "none",
|
|
191
|
+
minify: true,
|
|
192
|
+
plugins: [lazyChunkPlugin(rootOutdir, dirname(output), nested)],
|
|
193
|
+
});
|
|
194
|
+
if (!result.success) {
|
|
195
|
+
const details = result.logs.map((log) => log.message).filter(Boolean).join("\n");
|
|
196
|
+
throw new Error(`${failureMessage}: lazy chunk ${source}\n${details}`);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
pending = [...nested.entries()];
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
125
203
|
function electrobunViewAliasPlugin(aliasRules: AliasRule[]) {
|
|
126
204
|
return {
|
|
127
205
|
name: "electrobun-view-aliases",
|
|
@@ -143,6 +143,24 @@ export function useScrollBoxHandle(
|
|
|
143
143
|
get scrollWidth() {
|
|
144
144
|
return toCellX(elementRef.current?.scrollWidth ?? 0);
|
|
145
145
|
},
|
|
146
|
+
// Whole rows are rounded, so the scroll keys read the ends in pixels.
|
|
147
|
+
get scrollTopPx() {
|
|
148
|
+
return options.headerOnly ? 0 : Math.max(0, elementRef.current?.scrollTop ?? 0);
|
|
149
|
+
},
|
|
150
|
+
get scrollHeightPx() {
|
|
151
|
+
const element = elementRef.current;
|
|
152
|
+
if (!element) return 0;
|
|
153
|
+
return options.headerOnly ? tableHeaderPx() : Math.max(0, element.scrollHeight - (options.viewportTopInsetPx ?? 0));
|
|
154
|
+
},
|
|
155
|
+
get viewportPx() {
|
|
156
|
+
const element = elementRef.current;
|
|
157
|
+
return {
|
|
158
|
+
width: Math.max(0, element?.clientWidth ?? 0),
|
|
159
|
+
height: options.headerOnly
|
|
160
|
+
? tableHeaderPx()
|
|
161
|
+
: Math.max(0, (element?.clientHeight ?? 0) - (options.viewportTopInsetPx ?? 0)),
|
|
162
|
+
};
|
|
163
|
+
},
|
|
146
164
|
get viewport() {
|
|
147
165
|
const element = elementRef.current;
|
|
148
166
|
if (options.headerOnly) {
|
|
@@ -161,6 +179,19 @@ export function useScrollBoxHandle(
|
|
|
161
179
|
},
|
|
162
180
|
horizontalScrollBar,
|
|
163
181
|
verticalScrollBar,
|
|
182
|
+
scrollToPixels(target: number | { x?: number; y?: number }, y?: number) {
|
|
183
|
+
const element = elementRef.current;
|
|
184
|
+
if (!element || options.headerOnly) return;
|
|
185
|
+
if (typeof target === "number") {
|
|
186
|
+
element.scrollTop = Math.max(0, target);
|
|
187
|
+
if (typeof y === "number") element.scrollLeft = Math.max(0, y);
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
element.scrollTo({
|
|
191
|
+
left: Math.max(0, target.x ?? element.scrollLeft),
|
|
192
|
+
top: Math.max(0, target.y ?? element.scrollTop),
|
|
193
|
+
});
|
|
194
|
+
},
|
|
164
195
|
scrollTo(target: number | { x?: number; y?: number }, y?: number) {
|
|
165
196
|
const element = elementRef.current;
|
|
166
197
|
if (!element) return;
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
} from "react";
|
|
12
12
|
import { EmptyState } from "../../../components/ui/status";
|
|
13
13
|
import { usePaneInstance } from "../../../state/app/context";
|
|
14
|
+
import { useRegisterPaneScrollBox } from "../../../state/pane-scroll-registry";
|
|
14
15
|
import { useRafCallback } from "../../../react/use-raf-callback";
|
|
15
16
|
import { measurePerf } from "../../../utils/perf-marks";
|
|
16
17
|
import type {
|
|
@@ -284,6 +285,10 @@ export function WebDataTable<T, C extends DataTableColumn = DataTableColumn>({
|
|
|
284
285
|
bodyVertical.bar,
|
|
285
286
|
{ viewportTopInsetPx: headerPx },
|
|
286
287
|
);
|
|
288
|
+
// The terminal table body is a ScrollBox the pane scroll keys already reach;
|
|
289
|
+
// this is the same for the desktop one. A table with a cursor takes the keys
|
|
290
|
+
// first, so only a table without one is scrolled by them.
|
|
291
|
+
useRegisterPaneScrollBox(scrollRef, { enabled: true });
|
|
287
292
|
|
|
288
293
|
useEffect(() => {
|
|
289
294
|
headerHorizontal.bar.visible = false;
|
|
@@ -353,6 +353,8 @@ function WebDataTableRowInner<
|
|
|
353
353
|
<div
|
|
354
354
|
key={column.id}
|
|
355
355
|
data-gloom-role="data-table-cell"
|
|
356
|
+
// The instant behind a shortened time ("Wed 11:27"), so a rendered-view report can print it whole.
|
|
357
|
+
data-gloom-cell-instant={cell.value instanceof Date && Number.isFinite(cell.value.getTime()) ? cell.value.toISOString() : undefined}
|
|
356
358
|
style={{
|
|
357
359
|
minWidth: 0,
|
|
358
360
|
position: freezeFirstColumn && columnIndex === 0 ? "sticky" : undefined,
|
|
@@ -345,8 +345,10 @@ export function WebTextField({
|
|
|
345
345
|
focusedBackgroundColor={plain ? "transparent" : resolvedBackgroundColor}
|
|
346
346
|
cursorColor={colors.textBright}
|
|
347
347
|
style={{
|
|
348
|
-
|
|
349
|
-
|
|
348
|
+
// A framed field keeps its text one cell off the frame; a plain one
|
|
349
|
+
// sits flush in the row or band that holds it.
|
|
350
|
+
paddingLeft: plain ? 0 : "var(--cell-w)",
|
|
351
|
+
paddingRight: plain ? 0 : "var(--cell-w)",
|
|
350
352
|
borderRadius: plain ? 0 : CONTROL_RADIUS,
|
|
351
353
|
// The field is taller than a cell, so the input takes the inner
|
|
352
354
|
// height and centers its text on the box's own line.
|
|
@@ -581,8 +583,10 @@ export function WebDialogFrame({
|
|
|
581
583
|
</Box>
|
|
582
584
|
{children}
|
|
583
585
|
{footer && (
|
|
586
|
+
// Sized by its line, not one cell: a cell-high box with this padding
|
|
587
|
+
// left the key line hanging out of its bottom.
|
|
584
588
|
<Box
|
|
585
|
-
|
|
589
|
+
flexShrink={0}
|
|
586
590
|
style={{
|
|
587
591
|
borderTop: `1px solid ${panelBorder(colors)}`,
|
|
588
592
|
paddingTop: 8,
|
|
@@ -5,6 +5,7 @@ import { TextAttributes } from "../../../ui";
|
|
|
5
5
|
import type { ListRowState, ListViewItem, ListViewProps } from "../../../components/ui/list-view";
|
|
6
6
|
import { blendHex, hoverBg, type ThemeColors } from "../../../theme/colors";
|
|
7
7
|
import { useThemeColors } from "../../../theme/theme-context";
|
|
8
|
+
import { WEB_CELL_HEIGHT } from "../../../theme/font-scale";
|
|
8
9
|
import { isInsideDialogSurface } from "../host/focus-scope";
|
|
9
10
|
import { isEditableKeyboardTarget } from "../key-event";
|
|
10
11
|
import {
|
|
@@ -58,6 +59,10 @@ function DefaultDesktopRow({
|
|
|
58
59
|
);
|
|
59
60
|
}
|
|
60
61
|
|
|
62
|
+
const FRAMED_LIST_PADDING_PX = 4;
|
|
63
|
+
/** What a framed list adds above and below its rows: padding and a 1px border on each side. */
|
|
64
|
+
const FRAMED_LIST_CHROME_PX = 2 * (FRAMED_LIST_PADDING_PX + 1);
|
|
65
|
+
|
|
61
66
|
function listRowStyle(selected: boolean, disabled: boolean, colors: ThemeColors): CSSProperties {
|
|
62
67
|
return {
|
|
63
68
|
borderRadius: CONTROL_RADIUS,
|
|
@@ -109,6 +114,16 @@ export function WebListView({
|
|
|
109
114
|
const tabStopIndex = selectedIndex >= 0 && items[selectedIndex] && !items[selectedIndex].disabled
|
|
110
115
|
? selectedIndex : items.findIndex((item) => !item.disabled);
|
|
111
116
|
const effectiveSurface = surface ?? (scrollable ? "framed" : "plain");
|
|
117
|
+
// `height` counts terminal rows. A list that is not meant to scroll takes
|
|
118
|
+
// only the rows it has, up to that many; one with more rows than that
|
|
119
|
+
// scrolls inside the height instead of drawing over whatever follows it.
|
|
120
|
+
const rowsHeight = items.length === 0 ? 1 : items.length * rowHeight + (items.length - 1) * rowGap;
|
|
121
|
+
const overflowsHeight = !scrollable && height != null && rowsHeight > height;
|
|
122
|
+
const scrolls = scrollable || overflowsHeight;
|
|
123
|
+
// The frame's padding and border sit outside the rows it was asked to hold.
|
|
124
|
+
const scrollHeight = overflowsHeight
|
|
125
|
+
? `${height * WEB_CELL_HEIGHT + (effectiveSurface === "plain" ? 0 : FRAMED_LIST_CHROME_PX)}px`
|
|
126
|
+
: height;
|
|
112
127
|
const frameStyle = effectiveSurface === "plain"
|
|
113
128
|
? {
|
|
114
129
|
border: "none",
|
|
@@ -119,12 +134,12 @@ export function WebListView({
|
|
|
119
134
|
: {
|
|
120
135
|
border: `1px solid ${panelBorder(colors)}`,
|
|
121
136
|
borderRadius: CONTROL_RADIUS,
|
|
122
|
-
padding:
|
|
137
|
+
padding: FRAMED_LIST_PADDING_PX,
|
|
123
138
|
backgroundColor: subtlePanelFill(colors),
|
|
124
139
|
};
|
|
125
140
|
|
|
126
141
|
useEffect(() => {
|
|
127
|
-
if (!
|
|
142
|
+
if (!scrolls || !autoScrollToIndex || activeScrollIndex < 0) return;
|
|
128
143
|
const scrollBox = scrollRef.current;
|
|
129
144
|
if (!scrollBox) return;
|
|
130
145
|
const safeIndex = Math.min(activeScrollIndex, items.length - 1);
|
|
@@ -136,16 +151,16 @@ export function WebListView({
|
|
|
136
151
|
} else if (rowBottom > scrollBox.scrollTop + viewportHeight) {
|
|
137
152
|
scrollBox.scrollTo(rowBottom - viewportHeight);
|
|
138
153
|
}
|
|
139
|
-
}, [activeScrollIndex, autoScrollToIndex, items.length, rowHeight, rowStride,
|
|
154
|
+
}, [activeScrollIndex, autoScrollToIndex, items.length, rowHeight, rowStride, scrolls]);
|
|
140
155
|
|
|
141
156
|
useEffect(() => {
|
|
142
|
-
if (!
|
|
157
|
+
if (!scrolls) return;
|
|
143
158
|
const scrollBox = scrollRef.current;
|
|
144
159
|
if (!scrollBox) return;
|
|
145
160
|
if (scrollBox.verticalScrollBar) {
|
|
146
161
|
scrollBox.verticalScrollBar.visible = items.length * rowStride - rowGap > (scrollBox.viewport?.height ?? 0);
|
|
147
162
|
}
|
|
148
|
-
}, [items.length, height, flexGrow, rowGap, rowStride,
|
|
163
|
+
}, [items.length, height, flexGrow, rowGap, rowStride, scrolls]);
|
|
149
164
|
|
|
150
165
|
// The dialog or pane around the list moves its cursor (j/k, Home/End). A row
|
|
151
166
|
// Tab or a press left focused follows it, or Space and Enter would act on the
|
|
@@ -156,8 +171,8 @@ export function WebListView({
|
|
|
156
171
|
const active = document.activeElement;
|
|
157
172
|
if (!list || !active || !list.contains(active) || isEditableKeyboardTarget(active)) return;
|
|
158
173
|
const row = list.querySelectorAll<HTMLElement>('[role="option"]')[selectedIndex];
|
|
159
|
-
if (row && !row.contains(active)) row.focus({ preventScroll:
|
|
160
|
-
}, [listDomId,
|
|
174
|
+
if (row && !row.contains(active)) row.focus({ preventScroll: scrolls });
|
|
175
|
+
}, [listDomId, scrolls, selectedIndex]);
|
|
161
176
|
|
|
162
177
|
const rows = items.length === 0
|
|
163
178
|
? (
|
|
@@ -233,11 +248,21 @@ export function WebListView({
|
|
|
233
248
|
});
|
|
234
249
|
|
|
235
250
|
return (
|
|
236
|
-
<Box
|
|
237
|
-
{
|
|
251
|
+
<Box
|
|
252
|
+
id={listDomId}
|
|
253
|
+
flexDirection="column"
|
|
254
|
+
height={scrollable ? height : undefined}
|
|
255
|
+
// A list sized by its container gives up height to it, and scrolls.
|
|
256
|
+
minHeight={scrollable && height == null ? 0 : undefined}
|
|
257
|
+
flexGrow={flexGrow}
|
|
258
|
+
gap={1}
|
|
259
|
+
role="listbox"
|
|
260
|
+
aria-label={remoteLabel}
|
|
261
|
+
>
|
|
262
|
+
{scrolls ? (
|
|
238
263
|
<ScrollBox
|
|
239
264
|
ref={scrollRef}
|
|
240
|
-
height={
|
|
265
|
+
height={scrollHeight}
|
|
241
266
|
flexGrow={flexGrow}
|
|
242
267
|
scrollY
|
|
243
268
|
focusable={false}
|
|
@@ -2,12 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
import { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
4
4
|
import { createPortal } from "react-dom";
|
|
5
|
-
import type { HostPopoverProps } from "../../../ui";
|
|
5
|
+
import type { BoxRenderable, HostPopoverProps } from "../../../ui";
|
|
6
6
|
import { blendHex } from "../../../theme/colors";
|
|
7
|
+
import { WEB_CELL_HEIGHT, WEB_CELL_WIDTH } from "../../../theme/font-scale";
|
|
7
8
|
import { useThemeColors } from "../../../theme/theme-context";
|
|
8
9
|
|
|
9
10
|
const VIEWPORT_MARGIN = 10;
|
|
11
|
+
/** How far a popover kept inside its pane stays off the pane's edge. */
|
|
12
|
+
const PANE_MARGIN = 4;
|
|
10
13
|
const POPOVER_GAP = 6;
|
|
14
|
+
const PANE_SELECTOR = '[data-gloom-role="pane-window"], [data-gloom-role="detached-pane-window"]';
|
|
11
15
|
/** `.gloom-popover` in styles.css: above dialogs and toasts. */
|
|
12
16
|
const POPOVER_Z_INDEX = 10_001;
|
|
13
17
|
|
|
@@ -21,6 +25,51 @@ function cssSize(value: number | string | undefined): number | string | undefine
|
|
|
21
25
|
return typeof value === "number" ? `${value}px` : value;
|
|
22
26
|
}
|
|
23
27
|
|
|
28
|
+
interface Edges {
|
|
29
|
+
left: number;
|
|
30
|
+
top: number;
|
|
31
|
+
right: number;
|
|
32
|
+
bottom: number;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Where an anchor element is now, in viewport pixels. Null once it is gone
|
|
37
|
+
* from the page (a removed message), so the popover falls back to its trigger.
|
|
38
|
+
*/
|
|
39
|
+
function anchorEdges(anchor: BoxRenderable): Edges | null {
|
|
40
|
+
const rect = anchor.getBoundingClientRect?.();
|
|
41
|
+
if (rect) {
|
|
42
|
+
if (rect.width === 0 && rect.height === 0) return null;
|
|
43
|
+
return { left: rect.x, top: rect.y, right: rect.x + rect.width, bottom: rect.y + rect.height };
|
|
44
|
+
}
|
|
45
|
+
const bounds = anchor.absoluteBounds;
|
|
46
|
+
if (!bounds) return null;
|
|
47
|
+
return {
|
|
48
|
+
left: bounds.x * WEB_CELL_WIDTH,
|
|
49
|
+
top: bounds.y * WEB_CELL_HEIGHT,
|
|
50
|
+
right: (bounds.x + bounds.width) * WEB_CELL_WIDTH,
|
|
51
|
+
bottom: (bounds.y + bounds.height) * WEB_CELL_HEIGHT,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** The area a popover must stay in: the window, and for `pane` the pane that holds its trigger too. */
|
|
56
|
+
function placementEdges(wrapper: Element | null, boundary: HostPopoverProps["boundary"]): Edges {
|
|
57
|
+
const viewport = {
|
|
58
|
+
left: VIEWPORT_MARGIN,
|
|
59
|
+
top: VIEWPORT_MARGIN,
|
|
60
|
+
right: window.innerWidth - VIEWPORT_MARGIN,
|
|
61
|
+
bottom: window.innerHeight - VIEWPORT_MARGIN,
|
|
62
|
+
};
|
|
63
|
+
const pane = boundary === "pane" ? wrapper?.closest(PANE_SELECTOR)?.getBoundingClientRect() : null;
|
|
64
|
+
if (!pane) return viewport;
|
|
65
|
+
return {
|
|
66
|
+
left: Math.max(viewport.left, pane.left + PANE_MARGIN),
|
|
67
|
+
top: Math.max(viewport.top, pane.top + PANE_MARGIN),
|
|
68
|
+
right: Math.min(viewport.right, pane.right - PANE_MARGIN),
|
|
69
|
+
bottom: Math.min(viewport.bottom, pane.bottom - PANE_MARGIN),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
24
73
|
/**
|
|
25
74
|
* The popover is portalled to <body>, so its z-index only competes in the root
|
|
26
75
|
* stacking context. A trigger inside a surface stacked above the popover layer
|
|
@@ -45,6 +94,10 @@ export function WebPopover({
|
|
|
45
94
|
trigger,
|
|
46
95
|
children,
|
|
47
96
|
anchorPoint,
|
|
97
|
+
anchor,
|
|
98
|
+
boundary = "viewport",
|
|
99
|
+
onPointerEnter,
|
|
100
|
+
onPointerLeave,
|
|
48
101
|
placement = "bottom-start",
|
|
49
102
|
minWidth = 280,
|
|
50
103
|
maxWidth = "min(420px, calc(100vw - 20px))",
|
|
@@ -59,18 +112,19 @@ export function WebPopover({
|
|
|
59
112
|
const [zIndex, setZIndex] = useState<number | undefined>(undefined);
|
|
60
113
|
|
|
61
114
|
const updatePosition = useCallback(() => {
|
|
62
|
-
const
|
|
115
|
+
const wrapper = anchorRef.current;
|
|
63
116
|
const popover = popoverRef.current;
|
|
64
|
-
if (!
|
|
117
|
+
if (!wrapper || !popover) return;
|
|
65
118
|
|
|
66
119
|
const popoverRect = popover.getBoundingClientRect();
|
|
67
|
-
const triggerRect =
|
|
120
|
+
const triggerRect = wrapper.getBoundingClientRect();
|
|
121
|
+
const elementEdges = anchor ? anchorEdges(anchor) : null;
|
|
68
122
|
// Keyboard-driven popovers can intentionally omit a visible trigger. In
|
|
69
123
|
// that case the anchor wrapper still inherits a line-height, so its DOM
|
|
70
124
|
// rect is not truly empty even though there is nothing useful to anchor to.
|
|
71
125
|
// Center these unanchored menus; explicit pointer/footer coordinates still
|
|
72
126
|
// take precedence below.
|
|
73
|
-
if (!anchorPoint && (trigger == null || (triggerRect.width === 0 && triggerRect.height === 0))) {
|
|
127
|
+
if (!elementEdges && !anchorPoint && (trigger == null || (triggerRect.width === 0 && triggerRect.height === 0))) {
|
|
74
128
|
setPosition({
|
|
75
129
|
left: Math.max(
|
|
76
130
|
VIEWPORT_MARGIN,
|
|
@@ -90,28 +144,26 @@ export function WebPopover({
|
|
|
90
144
|
});
|
|
91
145
|
return;
|
|
92
146
|
}
|
|
93
|
-
const anchorRect = anchorPoint
|
|
147
|
+
const anchorRect = elementEdges ?? (anchorPoint
|
|
94
148
|
? {
|
|
95
149
|
left: anchorPoint.x,
|
|
96
150
|
right: anchorPoint.x,
|
|
97
151
|
top: anchorPoint.y,
|
|
98
152
|
bottom: anchorPoint.y,
|
|
99
153
|
}
|
|
100
|
-
: triggerRect;
|
|
154
|
+
: triggerRect);
|
|
155
|
+
const edges = placementEdges(wrapper, boundary);
|
|
101
156
|
const preferredLeft = placement === "bottom-end"
|
|
102
157
|
? anchorRect.right - popoverRect.width
|
|
103
158
|
: anchorRect.left;
|
|
104
|
-
const left = Math.max(
|
|
105
|
-
VIEWPORT_MARGIN,
|
|
106
|
-
Math.min(preferredLeft, window.innerWidth - popoverRect.width - VIEWPORT_MARGIN),
|
|
107
|
-
);
|
|
159
|
+
const left = Math.max(edges.left, Math.min(preferredLeft, edges.right - popoverRect.width));
|
|
108
160
|
const below = anchorRect.bottom + POPOVER_GAP;
|
|
109
161
|
const above = anchorRect.top - popoverRect.height - POPOVER_GAP;
|
|
110
|
-
const top = below + popoverRect.height <=
|
|
162
|
+
const top = below + popoverRect.height <= edges.bottom
|
|
111
163
|
? below
|
|
112
|
-
: Math.max(
|
|
164
|
+
: Math.max(edges.top, above);
|
|
113
165
|
setPosition({ left, top, visible: true });
|
|
114
|
-
}, [anchorPoint, placement, trigger]);
|
|
166
|
+
}, [anchor, anchorPoint, boundary, placement, trigger]);
|
|
115
167
|
|
|
116
168
|
useLayoutEffect(() => {
|
|
117
169
|
if (!open) {
|
|
@@ -123,10 +175,15 @@ export function WebPopover({
|
|
|
123
175
|
const frame = window.requestAnimationFrame(updatePosition);
|
|
124
176
|
window.addEventListener("resize", updatePosition);
|
|
125
177
|
document.addEventListener("scroll", updatePosition, true);
|
|
178
|
+
// New content (a hover card swapped to another name) can change the size
|
|
179
|
+
// the placement was worked out for.
|
|
180
|
+
const resizeObserver = typeof ResizeObserver === "function" ? new ResizeObserver(updatePosition) : null;
|
|
181
|
+
if (popoverRef.current) resizeObserver?.observe(popoverRef.current);
|
|
126
182
|
return () => {
|
|
127
183
|
window.cancelAnimationFrame(frame);
|
|
128
184
|
window.removeEventListener("resize", updatePosition);
|
|
129
185
|
document.removeEventListener("scroll", updatePosition, true);
|
|
186
|
+
resizeObserver?.disconnect();
|
|
130
187
|
};
|
|
131
188
|
}, [open, updatePosition]);
|
|
132
189
|
|
|
@@ -181,6 +238,8 @@ export function WebPopover({
|
|
|
181
238
|
tabIndex={-1}
|
|
182
239
|
onMouseDown={(event) => event.stopPropagation()}
|
|
183
240
|
onClick={(event) => event.stopPropagation()}
|
|
241
|
+
onMouseEnter={onPointerEnter}
|
|
242
|
+
onMouseLeave={onPointerLeave}
|
|
184
243
|
style={{
|
|
185
244
|
left: position.left,
|
|
186
245
|
top: position.top,
|