gloomberb 0.6.1 → 0.7.1
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 +1 -1
- package/patches/@opentui%2Fcore@0.1.90.patch +48 -24
- package/src/app.tsx +158 -57
- package/src/capabilities/factories.ts +3 -0
- package/src/cli/registry.test.ts +0 -1
- package/src/components/chart/chart-controller.ts +0 -1
- package/src/components/chart/chart-data.ts +1 -31
- package/src/components/chart/chart-renderer.ts +94 -12
- package/src/components/chart/chart-resolution.test.ts +0 -36
- package/src/components/chart/chart-resolution.ts +0 -27
- package/src/components/chart/chart.test.ts +60 -45
- package/src/components/chart/comparison-chart-data.test.ts +1 -5
- package/src/components/chart/comparison-chart-data.ts +1 -4
- package/src/components/chart/comparison-chart-renderer.test.ts +26 -0
- package/src/components/chart/comparison-chart-renderer.ts +13 -6
- package/src/components/chart/comparison-stock-chart.tsx +63 -39
- package/src/components/chart/price-axis-labels.tsx +114 -0
- package/src/components/chart/static-chart-surface.tsx +30 -4
- package/src/components/chart/stock-chart.test.ts +0 -16
- package/src/components/chart/stock-chart.tsx +69 -41
- package/src/components/chart/time-axis-label.tsx +120 -0
- package/src/components/command-bar/__snapshots__/command-bar.test.tsx.snap +0 -28
- package/src/components/command-bar/command-bar.test.tsx +182 -36
- package/src/components/command-bar/command-bar.tsx +943 -1016
- package/src/components/command-bar/command-registry.ts +0 -10
- package/src/components/command-bar/confirm-body.tsx +51 -0
- package/src/components/command-bar/helpers.ts +2 -5
- package/src/components/command-bar/list-model.ts +76 -0
- package/src/components/command-bar/theme-picker.tsx +254 -0
- package/src/components/command-bar/view-model.test.ts +4 -4
- package/src/components/command-bar/view-model.ts +1 -20
- package/src/components/command-bar/workflow-ops.ts +4 -0
- package/src/components/command-bar/workflow-types.ts +1 -2
- package/src/components/data-table-stack-view.test.tsx +39 -4
- package/src/components/data-table-stack-view.tsx +11 -104
- package/src/components/data-table-view.tsx +43 -79
- package/src/components/feed-data-table-stack-view.tsx +10 -17
- package/src/components/feed-stack-controller.ts +39 -0
- package/src/components/index.ts +5 -1
- package/src/components/layout/detached-pane-shell.tsx +29 -10
- package/src/components/layout/floating-pane.tsx +35 -4
- package/src/components/layout/header.tsx +12 -7
- package/src/components/layout/pane-content.test.tsx +64 -0
- package/src/components/layout/pane-content.tsx +2 -0
- package/src/components/layout/pane-cycle-order.test.ts +30 -0
- package/src/components/layout/pane-cycle-order.ts +32 -0
- package/src/components/layout/pane-footer.tsx +11 -4
- package/src/components/layout/pane-header.tsx +5 -5
- package/src/components/layout/pane-sizing.ts +9 -2
- package/src/components/layout/pane-title.ts +4 -1
- package/src/components/layout/pane.tsx +11 -5
- package/src/components/layout/shell.test.tsx +264 -22
- package/src/components/layout/shell.tsx +46 -8
- package/src/components/layout/status-bar.tsx +2 -0
- package/src/components/onboarding/onboarding-wizard.tsx +1 -2
- package/src/components/pane-settings-dialog.tsx +12 -4
- package/src/components/pane-template-wizard.test.tsx +3 -4
- package/src/components/speedometer-gauge.test.tsx +45 -0
- package/src/components/speedometer-gauge.tsx +562 -0
- package/src/components/table-view-shared.tsx +218 -0
- package/src/components/ticker-list-table-view.tsx +57 -73
- package/src/components/ticker-list-table.test.tsx +82 -1
- package/src/components/ticker-list-table.tsx +22 -9
- package/src/components/ui/confirm-dialog.tsx +66 -0
- package/src/components/ui/data-table.tsx +30 -19
- package/src/components/ui/frame.tsx +2 -0
- package/src/components/ui/index.ts +0 -1
- package/src/components/ui/page-stack-view.tsx +39 -10
- package/src/components/ui/table-layout.test.ts +42 -0
- package/src/components/ui/table-layout.ts +49 -4
- package/src/components/ui/tabs.tsx +34 -1
- package/src/components/ui/ui.test.tsx +168 -21
- package/src/core/state/app-state.ts +10 -17
- package/src/market-data/coordinator.test.ts +76 -1
- package/src/market-data/coordinator.ts +218 -49
- package/src/news/aggregator.test.ts +49 -1
- package/src/news/aggregator.ts +48 -3
- package/src/news/hooks.ts +6 -2
- package/src/plugins/builtin/ai/ask-ai-detail-tab.tsx +46 -16
- package/src/plugins/builtin/ai/providers.ts +0 -17
- package/src/plugins/builtin/ai/screener-pane.test.tsx +3 -4
- package/src/plugins/builtin/ai/screener-pane.tsx +3 -5
- package/src/plugins/builtin/analytics/index.tsx +1 -18
- package/src/plugins/builtin/ask-ai.test.tsx +89 -2
- package/src/plugins/builtin/broker-manager/index.test.tsx +2 -2
- package/src/plugins/builtin/broker-manager/index.tsx +19 -36
- package/src/plugins/builtin/chat-controller.test.ts +188 -1
- package/src/plugins/builtin/chat-controller.ts +537 -220
- package/src/plugins/builtin/chat.test.tsx +431 -13
- package/src/plugins/builtin/chat.tsx +1134 -227
- package/src/plugins/builtin/cloud-tweets.tsx +1 -1
- package/src/plugins/builtin/comparison-chart.test.tsx +53 -2
- package/src/plugins/builtin/comparison-chart.tsx +11 -5
- package/src/plugins/builtin/correlation/index.tsx +1 -6
- package/src/plugins/builtin/debug.tsx +1 -3
- package/src/plugins/builtin/econ/index.tsx +1 -2
- package/src/plugins/builtin/fear-greed/fear-greed-data.test.ts +72 -0
- package/src/plugins/builtin/fear-greed/fear-greed-data.ts +366 -0
- package/src/plugins/builtin/fear-greed/index.tsx +587 -0
- package/src/plugins/builtin/fx-matrix/index.tsx +2 -2
- package/src/plugins/builtin/help.test.tsx +2 -2
- package/src/plugins/builtin/help.tsx +2 -2
- package/src/plugins/builtin/holders/index.test.ts +13 -1
- package/src/plugins/builtin/holders/index.tsx +64 -29
- package/src/plugins/builtin/insider/index.tsx +22 -89
- package/src/plugins/builtin/market-movers/index.tsx +13 -19
- package/src/plugins/builtin/market-movers/screener.test.ts +39 -1
- package/src/plugins/builtin/market-movers/screener.ts +70 -17
- package/src/plugins/builtin/news-wire/breaking-pane.tsx +3 -2
- package/src/plugins/builtin/news-wire/index.tsx +41 -2
- package/src/plugins/builtin/news-wire/industry-pane.tsx +4 -18
- package/src/plugins/builtin/news-wire/news-detail-view.tsx +46 -4
- package/src/plugins/builtin/news-wire/news-preset-pane.tsx +3 -2
- package/src/plugins/builtin/news-wire/news-table.tsx +11 -11
- package/src/plugins/builtin/news.tsx +4 -16
- package/src/plugins/builtin/notes.tsx +19 -55
- package/src/plugins/builtin/options.test.tsx +58 -2
- package/src/plugins/builtin/options.tsx +110 -65
- package/src/plugins/builtin/plugin-groups.ts +2 -0
- package/src/plugins/builtin/portfolio-list/cli/commands.ts +1 -1
- package/src/plugins/builtin/portfolio-list/pane.tsx +16 -39
- package/src/plugins/builtin/research/index.test.ts +94 -0
- package/src/plugins/builtin/research/index.tsx +164 -33
- package/src/plugins/builtin/sec-filing-display.tsx +84 -0
- package/src/plugins/builtin/sec.tsx +13 -66
- package/src/plugins/builtin/sectors/index.tsx +1 -1
- package/src/plugins/builtin/ticker-detail/chart-tab.tsx +0 -1
- package/src/plugins/builtin/ticker-detail/index.tsx +0 -1
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +0 -1
- package/src/plugins/builtin/ticker-detail/pane.tsx +28 -22
- package/src/plugins/builtin/ticker-detail-chart-tab-switch.test.tsx +3 -4
- package/src/plugins/builtin/ticker-detail.test.tsx +38 -0
- package/src/plugins/builtin/world-indices/index.tsx +1 -1
- package/src/plugins/builtin/yield-curve/index.tsx +1 -1
- package/src/plugins/ibkr/broker-adapter.ts +1 -3
- package/src/plugins/ibkr/gateway-service-native.ts +1 -5
- package/src/plugins/ibkr/gateway-service.ts +1 -1
- package/src/plugins/ibkr/index.test.tsx +0 -2
- package/src/plugins/ibkr/trade-tab.test.tsx +3 -4
- package/src/plugins/pane-manager.ts +0 -13
- package/src/plugins/plugin-runtime.test.tsx +40 -6
- package/src/plugins/plugin-runtime.tsx +20 -10
- package/src/plugins/prediction-markets/cli.ts +0 -1
- package/src/plugins/prediction-markets/controller-data.ts +0 -2
- package/src/plugins/prediction-markets/controller.ts +0 -15
- package/src/plugins/prediction-markets/detail/pane.tsx +1 -0
- package/src/plugins/prediction-markets/pane.test.tsx +3 -11
- package/src/plugins/prediction-markets/test-helpers.tsx +1 -1
- package/src/plugins/registry.ts +13 -42
- package/src/plugins/ticker-navigation.test.ts +66 -0
- package/src/plugins/ticker-navigation.ts +44 -0
- package/src/react/input.ts +2 -1
- package/src/renderers/electrobun/bun/index.ts +32 -11
- package/src/renderers/electrobun/bun/window-focus.ts +37 -0
- package/src/renderers/electrobun/shared/protocol.ts +7 -1
- package/src/renderers/electrobun/view/app-services.ts +88 -31
- package/src/renderers/electrobun/view/backend-rpc.ts +15 -0
- package/src/renderers/electrobun/view/data-table.tsx +138 -101
- package/src/renderers/electrobun/view/desktop-controls.tsx +42 -20
- package/src/renderers/electrobun/view/desktop-window-bridge.ts +12 -1
- package/src/renderers/electrobun/view/dialog-host.tsx +13 -1
- package/src/renderers/electrobun/view/input-host.tsx +74 -10
- package/src/renderers/electrobun/view/key-event.ts +1 -1
- package/src/renderers/electrobun/view/main.tsx +18 -1
- package/src/renderers/electrobun/view/styles.css +329 -0
- package/src/renderers/electrobun/view/toast-host.tsx +29 -3
- package/src/renderers/electrobun/view/ui-host.tsx +42 -0
- package/src/renderers/opentui/chart-surface.tsx +179 -0
- package/src/renderers/opentui/input-host.tsx +1 -1
- package/src/renderers/opentui/start.tsx +48 -30
- package/src/renderers/opentui/test-utils.tsx +17 -0
- package/src/renderers/opentui/ui-host.tsx +5 -2
- package/src/sources/gloomberb-cloud.test.ts +86 -1
- package/src/sources/gloomberb-cloud.ts +117 -21
- package/src/sources/provider-router.test.ts +122 -0
- package/src/sources/provider-router.ts +198 -15
- package/src/sources/yahoo-finance.test.ts +44 -0
- package/src/sources/yahoo-finance.ts +6 -0
- package/src/state/app-bootstrap.ts +20 -7
- package/src/state/app-context-selector.test.tsx +189 -4
- package/src/state/app-context.test.ts +65 -0
- package/src/state/app-context.tsx +48 -16
- package/src/state/use-inline-tickers.test.tsx +73 -0
- package/src/state/use-inline-tickers.ts +19 -10
- package/src/test-support/plugin-runtime.ts +3 -2
- package/src/theme/colors.test.ts +75 -0
- package/src/theme/colors.ts +76 -6
- package/src/theme/theme-context.tsx +26 -0
- package/src/theme/themes.test.ts +23 -1
- package/src/theme/themes.ts +115 -0
- package/src/types/broker.ts +1 -1
- package/src/types/capability-route-source.ts +1 -0
- package/src/types/data-provider.ts +15 -2
- package/src/types/desktop-window.ts +6 -0
- package/src/types/financials.ts +2 -0
- package/src/types/plugin.ts +1 -3
- package/src/ui/host.tsx +7 -0
- package/src/utils/api-client.test.ts +32 -0
- package/src/utils/api-client.ts +119 -18
- package/src/utils/back-navigation.ts +24 -1
- package/src/utils/double-escape-close.test.ts +33 -0
- package/src/utils/double-escape-close.ts +40 -0
- package/src/utils/throttled-fetch.test.ts +22 -0
- package/src/utils/throttled-fetch.ts +3 -1
- package/src/utils/ticker-search.ts +53 -9
- package/src/version.ts +1 -1
- package/src/plugins/builtin/news-wire/feed-pane.tsx +0 -21
- package/src/plugins/builtin/news-wire/top-pane.tsx +0 -21
|
@@ -9,6 +9,7 @@ import { ShortcutHint } from "../ui";
|
|
|
9
9
|
import { saveConfig } from "../../data/config-store";
|
|
10
10
|
import { getSharedMarketData } from "../../plugins/registry";
|
|
11
11
|
import { colors } from "../../theme/colors";
|
|
12
|
+
import { useThemeColors } from "../../theme/theme-context";
|
|
12
13
|
import { formatCompact } from "../../utils/format";
|
|
13
14
|
import { formatMarketPriceWithCurrency } from "../../utils/market-format";
|
|
14
15
|
import { useChartQueries, useChartQuery } from "../../market-data/hooks";
|
|
@@ -27,7 +28,7 @@ import {
|
|
|
27
28
|
getKeyboardPanCellCount,
|
|
28
29
|
resolveDragPanOffset,
|
|
29
30
|
} from "./chart-scroll";
|
|
30
|
-
import {
|
|
31
|
+
import { projectChartData, resolveBarSize, resolveStableOhlcProjectionOptions, type ProjectedChartPoint } from "./chart-data";
|
|
31
32
|
import {
|
|
32
33
|
buildPresetDateWindow,
|
|
33
34
|
buildVisibleDateWindow,
|
|
@@ -82,7 +83,6 @@ import {
|
|
|
82
83
|
} from "./chart-viewport";
|
|
83
84
|
import {
|
|
84
85
|
buildChartScene,
|
|
85
|
-
formatAxisCell,
|
|
86
86
|
formatCursorAxisValue,
|
|
87
87
|
getActivePointIndex,
|
|
88
88
|
getPointTerminalColumn,
|
|
@@ -127,6 +127,8 @@ import {
|
|
|
127
127
|
} from "./native/surface-visibility";
|
|
128
128
|
import type { PricePoint, TickerFinancials } from "../../types/financials";
|
|
129
129
|
import type { TickerRecord } from "../../types/ticker";
|
|
130
|
+
import { TimeAxisLabel } from "./time-axis-label";
|
|
131
|
+
import { PriceAxisLabels } from "./price-axis-labels";
|
|
130
132
|
|
|
131
133
|
const MODE_CHIPS: Record<ChartRenderMode, string> = {
|
|
132
134
|
area: "A",
|
|
@@ -173,7 +175,6 @@ interface StockChartProps {
|
|
|
173
175
|
}
|
|
174
176
|
|
|
175
177
|
interface ResolvedStockChartProps extends StockChartProps {
|
|
176
|
-
symbol: string | null;
|
|
177
178
|
ticker: TickerRecord | null;
|
|
178
179
|
financials: TickerFinancials | null;
|
|
179
180
|
}
|
|
@@ -726,14 +727,6 @@ function isSeriesAcceptedForRequest(
|
|
|
726
727
|
return windowPoints.length >= minimumPointCount;
|
|
727
728
|
}
|
|
728
729
|
|
|
729
|
-
function canRenderAutoViewForWindow(
|
|
730
|
-
render: AutoRenderedView | null,
|
|
731
|
-
requestedWindow: DateWindowRange | null | undefined,
|
|
732
|
-
): render is AutoRenderedView {
|
|
733
|
-
if (!render || !requestedWindow?.start || !requestedWindow.end) return false;
|
|
734
|
-
return getWindowPoints(render.data, requestedWindow).length > 0;
|
|
735
|
-
}
|
|
736
|
-
|
|
737
730
|
export function resolveAutoDisplayState(options: {
|
|
738
731
|
shouldUseRenderedAutoView: boolean;
|
|
739
732
|
renderedAutoView: AutoRenderedView | null;
|
|
@@ -772,13 +765,6 @@ export function resolveAutoDisplayState(options: {
|
|
|
772
765
|
};
|
|
773
766
|
}
|
|
774
767
|
|
|
775
|
-
export function resolveVisibleChartDateWindow(
|
|
776
|
-
points: readonly Pick<PricePoint, "date">[],
|
|
777
|
-
preferredWindow: DateWindowRange | null | undefined,
|
|
778
|
-
): DateWindowRange | null {
|
|
779
|
-
return getDateWindowBounds(getPointDates(points)) ?? preferredWindow ?? null;
|
|
780
|
-
}
|
|
781
|
-
|
|
782
768
|
function buildDateWindowFromIndices(dates: readonly Date[], startIdx: number, endIdx: number): DateWindowRange | null {
|
|
783
769
|
if (dates.length === 0 || endIdx <= startIdx) return null;
|
|
784
770
|
return {
|
|
@@ -1430,8 +1416,8 @@ function buildIndicatorProjectionKey(options: {
|
|
|
1430
1416
|
}
|
|
1431
1417
|
|
|
1432
1418
|
export function StockChart(props: StockChartProps) {
|
|
1433
|
-
const {
|
|
1434
|
-
return <ResolvedStockChart {...props}
|
|
1419
|
+
const { ticker, financials } = usePaneTicker();
|
|
1420
|
+
return <ResolvedStockChart {...props} ticker={ticker} financials={financials} />;
|
|
1435
1421
|
}
|
|
1436
1422
|
|
|
1437
1423
|
export const ResolvedStockChart = memo(function ResolvedStockChart({
|
|
@@ -1448,10 +1434,10 @@ export const ResolvedStockChart = memo(function ResolvedStockChart({
|
|
|
1448
1434
|
showVolume: showVolumeOverride,
|
|
1449
1435
|
footerControls,
|
|
1450
1436
|
footerHints,
|
|
1451
|
-
symbol,
|
|
1452
1437
|
ticker,
|
|
1453
1438
|
financials,
|
|
1454
1439
|
}: ResolvedStockChartProps) {
|
|
1440
|
+
const themeColors = useThemeColors();
|
|
1455
1441
|
const renderer = useNativeRenderer();
|
|
1456
1442
|
const { canvasCharts, cellWidthPx = 8, cellHeightPx = 18, pixelRatio = 1 } = useUiCapabilities();
|
|
1457
1443
|
const dispatch = useAppDispatch();
|
|
@@ -1514,6 +1500,7 @@ export const ResolvedStockChart = memo(function ResolvedStockChart({
|
|
|
1514
1500
|
const lastCanvasBaseBitmapRef = useRef<{ key: string; bitmap: NativeChartBitmap } | null>(null);
|
|
1515
1501
|
const displayCursorRef = useRef<DisplayCursorState>(EMPTY_DISPLAY_CURSOR);
|
|
1516
1502
|
const targetCursorRef = useRef<DisplayCursorState>(EMPTY_DISPLAY_CURSOR);
|
|
1503
|
+
const mouseCrosshairDisabledRef = useRef(false);
|
|
1517
1504
|
const cursorMotionKindRef = useRef<ChartCursorMotionKind>("discrete");
|
|
1518
1505
|
const animationFrameRef = useRef<number | null>(null);
|
|
1519
1506
|
const pendingCanonicalResetRef = useRef(1);
|
|
@@ -2906,6 +2893,11 @@ export const ResolvedStockChart = memo(function ResolvedStockChart({
|
|
|
2906
2893
|
if (!interactive) return;
|
|
2907
2894
|
|
|
2908
2895
|
switch (key) {
|
|
2896
|
+
case "escape":
|
|
2897
|
+
mouseCrosshairDisabledRef.current = true;
|
|
2898
|
+
updateDisplayCursorTarget(EMPTY_DISPLAY_CURSOR, "discrete");
|
|
2899
|
+
commitSelectionCursor({ cursorX: null, cursorY: null });
|
|
2900
|
+
return;
|
|
2909
2901
|
case "left":
|
|
2910
2902
|
if (event.shift) {
|
|
2911
2903
|
if (effectiveResolution === "auto") {
|
|
@@ -2923,6 +2915,7 @@ export const ResolvedStockChart = memo(function ResolvedStockChart({
|
|
|
2923
2915
|
return { ...cleared, panOffset: current.panOffset + panStep };
|
|
2924
2916
|
});
|
|
2925
2917
|
} else {
|
|
2918
|
+
mouseCrosshairDisabledRef.current = false;
|
|
2926
2919
|
cursorMotionKindRef.current = "discrete";
|
|
2927
2920
|
const pointCount = projection.points.length;
|
|
2928
2921
|
const currentIndex = pointCount <= 0
|
|
@@ -2974,6 +2967,7 @@ export const ResolvedStockChart = memo(function ResolvedStockChart({
|
|
|
2974
2967
|
return cleared.panOffset === nextPanOffset ? cleared : { ...cleared, panOffset: nextPanOffset };
|
|
2975
2968
|
});
|
|
2976
2969
|
} else {
|
|
2970
|
+
mouseCrosshairDisabledRef.current = false;
|
|
2977
2971
|
cursorMotionKindRef.current = "discrete";
|
|
2978
2972
|
const pointCount = projection.points.length;
|
|
2979
2973
|
const currentIndex = pointCount <= 0
|
|
@@ -3021,15 +3015,24 @@ export const ResolvedStockChart = memo(function ResolvedStockChart({
|
|
|
3021
3015
|
: 0;
|
|
3022
3016
|
const trend = rawChange < 0 ? "negative" : rawChange > 0 ? "positive" : "neutral";
|
|
3023
3017
|
return resolveChartPalette({
|
|
3024
|
-
bg:
|
|
3025
|
-
border:
|
|
3026
|
-
borderFocused:
|
|
3027
|
-
text:
|
|
3028
|
-
textDim:
|
|
3029
|
-
positive:
|
|
3030
|
-
negative:
|
|
3018
|
+
bg: themeColors.bg,
|
|
3019
|
+
border: themeColors.border,
|
|
3020
|
+
borderFocused: themeColors.borderFocused,
|
|
3021
|
+
text: themeColors.text,
|
|
3022
|
+
textDim: themeColors.textDim,
|
|
3023
|
+
positive: themeColors.positive,
|
|
3024
|
+
negative: themeColors.negative,
|
|
3031
3025
|
}, trend);
|
|
3032
|
-
}, [
|
|
3026
|
+
}, [
|
|
3027
|
+
chartWindow.points,
|
|
3028
|
+
themeColors.bg,
|
|
3029
|
+
themeColors.border,
|
|
3030
|
+
themeColors.borderFocused,
|
|
3031
|
+
themeColors.negative,
|
|
3032
|
+
themeColors.positive,
|
|
3033
|
+
themeColors.text,
|
|
3034
|
+
themeColors.textDim,
|
|
3035
|
+
]);
|
|
3033
3036
|
|
|
3034
3037
|
const cursorX = viewState.cursorX !== null ? clamp(viewState.cursorX, 0, chartWidth - 1) : null;
|
|
3035
3038
|
const cursorY = viewState.cursorY !== null ? clamp(viewState.cursorY, 0, chartHeight - 1) : null;
|
|
@@ -3058,6 +3061,19 @@ export const ResolvedStockChart = memo(function ResolvedStockChart({
|
|
|
3058
3061
|
colors: chartColors,
|
|
3059
3062
|
timeAxisDates,
|
|
3060
3063
|
}), [axisMode, chartColors, chartHeight, chartWidth, compact, projection.effectiveMode, projection.points, selectionCursorX, selectionCursorY, showVolume, timeAxisDates, volumeHeight]);
|
|
3064
|
+
const displayScene = useMemo(() => buildChartScene(projection.points, {
|
|
3065
|
+
width: chartWidth,
|
|
3066
|
+
height: chartHeight,
|
|
3067
|
+
showVolume: showVolume && !compact,
|
|
3068
|
+
volumeHeight,
|
|
3069
|
+
cursorX: displayCursorX,
|
|
3070
|
+
cursorY: displayCursorY,
|
|
3071
|
+
mode: projection.effectiveMode,
|
|
3072
|
+
axisMode,
|
|
3073
|
+
colors: chartColors,
|
|
3074
|
+
timeAxisDates,
|
|
3075
|
+
indicators,
|
|
3076
|
+
}), [axisMode, chartColors, chartHeight, chartWidth, compact, displayCursorX, displayCursorY, indicators, projection.effectiveMode, projection.points, showVolume, timeAxisDates, volumeHeight]);
|
|
3061
3077
|
const snappedSelectionCursorX = selectionScene
|
|
3062
3078
|
? getPointTerminalColumn(selectionScene.activeIdx, projection.points.length, chartWidth, projection.effectiveMode)
|
|
3063
3079
|
: null;
|
|
@@ -3419,6 +3435,8 @@ export const ResolvedStockChart = memo(function ResolvedStockChart({
|
|
|
3419
3435
|
: null;
|
|
3420
3436
|
const isUpdating = !compact && (renderBodyState.updating || boundsBodyState.updating);
|
|
3421
3437
|
const timeAxisLabel = selectionScene?.timeLabels ?? staticResult.timeLabels;
|
|
3438
|
+
const cursorTimeAxisColumn = hasDisplayCursor ? displayScene?.cursorColumn ?? null : null;
|
|
3439
|
+
const cursorTimeAxisDate = hasDisplayCursor ? displayScene?.dateAtCursor ?? null : null;
|
|
3422
3440
|
const timeAxisBox = (
|
|
3423
3441
|
<Box
|
|
3424
3442
|
height={1}
|
|
@@ -3426,7 +3444,15 @@ export const ResolvedStockChart = memo(function ResolvedStockChart({
|
|
|
3426
3444
|
overflow="hidden"
|
|
3427
3445
|
data-gloom-role="chart-time-axis"
|
|
3428
3446
|
>
|
|
3429
|
-
<
|
|
3447
|
+
<TimeAxisLabel
|
|
3448
|
+
timeLabels={timeAxisLabel}
|
|
3449
|
+
width={chartWidth}
|
|
3450
|
+
cursorColumn={cursorTimeAxisColumn}
|
|
3451
|
+
cursorPixelX={hasDisplayCursor ? displayCursor.pixelX : null}
|
|
3452
|
+
cursorDate={cursorTimeAxisDate}
|
|
3453
|
+
dates={timeAxisDates}
|
|
3454
|
+
cursorColor={chartColors.crosshairColor}
|
|
3455
|
+
/>
|
|
3430
3456
|
</Box>
|
|
3431
3457
|
);
|
|
3432
3458
|
const chartFooterHints = useMemo<PaneHint[]>(() => {
|
|
@@ -3573,6 +3599,7 @@ export const ResolvedStockChart = memo(function ResolvedStockChart({
|
|
|
3573
3599
|
|
|
3574
3600
|
const handlePlotMove = (event: ChartMouseEvent) => {
|
|
3575
3601
|
if (!interactive || compact) return;
|
|
3602
|
+
if (mouseCrosshairDisabledRef.current) return;
|
|
3576
3603
|
const localPointer = getLocalPlotPointer(event, plotRef.current, renderer);
|
|
3577
3604
|
if (!localPointer) return;
|
|
3578
3605
|
const selectionCursor = resolveSelectionCursor(localPointer, projection.points.length, chartWidth, projection.effectiveMode);
|
|
@@ -3594,6 +3621,7 @@ export const ResolvedStockChart = memo(function ResolvedStockChart({
|
|
|
3594
3621
|
if (compact) return;
|
|
3595
3622
|
if (!interactive) onActivate?.();
|
|
3596
3623
|
focusPaneForMouseInteraction(event);
|
|
3624
|
+
mouseCrosshairDisabledRef.current = false;
|
|
3597
3625
|
const localPointer = getLocalPlotPointer(event, plotRef.current, renderer);
|
|
3598
3626
|
if (!localPointer) return;
|
|
3599
3627
|
const selectionCursor = resolveSelectionCursor(localPointer, projection.points.length, chartWidth, projection.effectiveMode);
|
|
@@ -3618,6 +3646,7 @@ export const ResolvedStockChart = memo(function ResolvedStockChart({
|
|
|
3618
3646
|
|
|
3619
3647
|
const handlePlotDrag = (event: ChartMouseEvent) => {
|
|
3620
3648
|
if (compact || (!interactive && !dragRef.current)) return;
|
|
3649
|
+
if (mouseCrosshairDisabledRef.current && !dragRef.current) return;
|
|
3621
3650
|
const localPointer = getLocalPlotPointer(event, plotRef.current, renderer);
|
|
3622
3651
|
if (localPointer) {
|
|
3623
3652
|
const selectionCursor = resolveSelectionCursor(localPointer, projection.points.length, chartWidth, projection.effectiveMode);
|
|
@@ -3938,17 +3967,16 @@ export const ResolvedStockChart = memo(function ResolvedStockChart({
|
|
|
3938
3967
|
);
|
|
3939
3968
|
|
|
3940
3969
|
const axisBox = (
|
|
3941
|
-
<
|
|
3942
|
-
{
|
|
3943
|
-
|
|
3944
|
-
|
|
3945
|
-
|
|
3946
|
-
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
|
|
3950
|
-
|
|
3951
|
-
</Box>
|
|
3970
|
+
<PriceAxisLabels
|
|
3971
|
+
axisLabels={axisLabels}
|
|
3972
|
+
axisWidth={axisWidth}
|
|
3973
|
+
axisSectionWidth={axisSectionWidth}
|
|
3974
|
+
height={chartHeight}
|
|
3975
|
+
cursorRow={cursorRow}
|
|
3976
|
+
cursorPixelY={hasDisplayCursor ? displayCursor.pixelY : null}
|
|
3977
|
+
cursorLabel={cursorAxisLabel}
|
|
3978
|
+
cursorColor={chartColors.crosshairColor}
|
|
3979
|
+
/>
|
|
3952
3980
|
);
|
|
3953
3981
|
|
|
3954
3982
|
if (compact) {
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { useMemo } from "react";
|
|
2
|
+
import { Box, Span, Text, useUiCapabilities } from "../../ui";
|
|
3
|
+
import { colors } from "../../theme/colors";
|
|
4
|
+
import { buildCursorTimeAxisSegments } from "./chart-renderer";
|
|
5
|
+
|
|
6
|
+
interface TimeAxisLabelProps {
|
|
7
|
+
timeLabels: string;
|
|
8
|
+
width: number;
|
|
9
|
+
cursorColumn: number | null;
|
|
10
|
+
cursorPixelX?: number | null;
|
|
11
|
+
cursorDate: Date | string | number | null;
|
|
12
|
+
dates: Array<Date | string | number>;
|
|
13
|
+
cursorColor: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface CursorTimeAxisOverlay {
|
|
17
|
+
baseText: string;
|
|
18
|
+
label: string | null;
|
|
19
|
+
leftPercent: number | null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function clamp(value: number, min: number, max: number): number {
|
|
23
|
+
return Math.max(min, Math.min(max, value));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function buildCursorTimeAxisOverlay({
|
|
27
|
+
segments,
|
|
28
|
+
width,
|
|
29
|
+
cursorPixelX,
|
|
30
|
+
cellWidthPx,
|
|
31
|
+
}: {
|
|
32
|
+
segments: ReturnType<typeof buildCursorTimeAxisSegments>;
|
|
33
|
+
width: number;
|
|
34
|
+
cursorPixelX: number | null | undefined;
|
|
35
|
+
cellWidthPx: number;
|
|
36
|
+
}): CursorTimeAxisOverlay {
|
|
37
|
+
const baseText = segments
|
|
38
|
+
.map((segment) => (segment.highlighted ? " ".repeat(segment.text.length) : segment.text))
|
|
39
|
+
.join("")
|
|
40
|
+
.padEnd(width)
|
|
41
|
+
.slice(0, width);
|
|
42
|
+
const label = segments.find((segment) => segment.highlighted)?.text ?? null;
|
|
43
|
+
const pixelWidth = Math.max(width * cellWidthPx, 1);
|
|
44
|
+
let leftPercent: number | null = null;
|
|
45
|
+
if (label && cursorPixelX !== null && cursorPixelX !== undefined && Number.isFinite(cursorPixelX) && pixelWidth > 1) {
|
|
46
|
+
const halfLabelWidth = Math.min((label.length * cellWidthPx) / 2, (pixelWidth - 1) / 2);
|
|
47
|
+
const leftPx = clamp(cursorPixelX, halfLabelWidth, Math.max(pixelWidth - halfLabelWidth, halfLabelWidth));
|
|
48
|
+
leftPercent = (leftPx / Math.max(pixelWidth - 1, 1)) * 100;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return { baseText, label, leftPercent };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function TimeAxisLabel({
|
|
55
|
+
timeLabels,
|
|
56
|
+
width,
|
|
57
|
+
cursorColumn,
|
|
58
|
+
cursorPixelX = null,
|
|
59
|
+
cursorDate,
|
|
60
|
+
dates,
|
|
61
|
+
cursorColor,
|
|
62
|
+
}: TimeAxisLabelProps) {
|
|
63
|
+
const { cellWidthPx = 8, fractionalViewport = false } = useUiCapabilities();
|
|
64
|
+
const segments = useMemo(() => buildCursorTimeAxisSegments({
|
|
65
|
+
timeLabels,
|
|
66
|
+
width,
|
|
67
|
+
cursorColumn,
|
|
68
|
+
cursorDate,
|
|
69
|
+
dates,
|
|
70
|
+
}), [cursorColumn, cursorDate, dates, timeLabels, width]);
|
|
71
|
+
const overlay = useMemo(() => buildCursorTimeAxisOverlay({
|
|
72
|
+
segments,
|
|
73
|
+
width,
|
|
74
|
+
cursorPixelX,
|
|
75
|
+
cellWidthPx,
|
|
76
|
+
}), [cellWidthPx, cursorPixelX, segments, width]);
|
|
77
|
+
|
|
78
|
+
if (fractionalViewport && overlay.label && overlay.leftPercent !== null) {
|
|
79
|
+
return (
|
|
80
|
+
<Box
|
|
81
|
+
width={width}
|
|
82
|
+
height={1}
|
|
83
|
+
overflow="hidden"
|
|
84
|
+
style={{ position: "relative" }}
|
|
85
|
+
>
|
|
86
|
+
<Text fg={colors.textDim} style={{ whiteSpace: "pre" }}>
|
|
87
|
+
{overlay.baseText}
|
|
88
|
+
</Text>
|
|
89
|
+
<Text
|
|
90
|
+
fg={cursorColor}
|
|
91
|
+
bg={colors.bg}
|
|
92
|
+
style={{
|
|
93
|
+
position: "absolute",
|
|
94
|
+
left: `${overlay.leftPercent}%`,
|
|
95
|
+
top: 0,
|
|
96
|
+
transform: "translateX(-50%)",
|
|
97
|
+
whiteSpace: "pre",
|
|
98
|
+
pointerEvents: "none",
|
|
99
|
+
zIndex: 1,
|
|
100
|
+
}}
|
|
101
|
+
>
|
|
102
|
+
{overlay.label}
|
|
103
|
+
</Text>
|
|
104
|
+
</Box>
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return (
|
|
109
|
+
<Text style={{ whiteSpace: "pre" }}>
|
|
110
|
+
{segments.map((segment, index) => (
|
|
111
|
+
<Span
|
|
112
|
+
key={index}
|
|
113
|
+
fg={segment.highlighted ? cursorColor : colors.textDim}
|
|
114
|
+
>
|
|
115
|
+
{segment.text}
|
|
116
|
+
</Span>
|
|
117
|
+
))}
|
|
118
|
+
</Text>
|
|
119
|
+
);
|
|
120
|
+
}
|
|
@@ -25,34 +25,6 @@ exports[`CommandBar renders the default layout with opencode-style chrome 1`] =
|
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
|
|
28
|
-
"
|
|
29
|
-
`;
|
|
30
|
-
|
|
31
|
-
exports[`CommandBar renders theme prefix results in the root query 1`] = `
|
|
32
|
-
"
|
|
33
|
-
|
|
34
|
-
Commands
|
|
35
|
-
TH
|
|
36
|
-
|
|
37
|
-
Themes
|
|
38
|
-
Amber current
|
|
39
|
-
Green Phosphor
|
|
40
|
-
Cyan
|
|
41
|
-
Red Phosphor
|
|
42
|
-
Blue Phosphor
|
|
43
|
-
Purple Phosphor
|
|
44
|
-
Hot Pink
|
|
45
|
-
White Phosphor
|
|
46
|
-
Tokyo Night
|
|
47
|
-
Solarized Dark
|
|
48
|
-
Dracula
|
|
49
|
-
Nord
|
|
50
|
-
Monokai
|
|
51
|
-
Catppuccin Mocha
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
28
|
"
|
|
57
29
|
`;
|
|
58
30
|
|