gloomberb 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -1
- package/patches/@opentui%2Fcore@0.1.90.patch +48 -24
- package/src/app.tsx +9 -6
- 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 +70 -0
- 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 +17 -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-stock-chart.tsx +62 -77
- package/src/components/chart/native/kitty.test.ts +23 -0
- package/src/components/chart/native/surface-visibility.ts +48 -0
- package/src/components/chart/static-chart-surface.tsx +28 -4
- package/src/components/chart/stock-chart.test.ts +0 -16
- package/src/components/chart/stock-chart.tsx +52 -71
- package/src/components/chart/time-axis-label.tsx +43 -0
- package/src/components/command-bar/command-bar.test.tsx +71 -8
- package/src/components/command-bar/command-bar.tsx +388 -713
- package/src/components/command-bar/confirm-body.tsx +51 -0
- package/src/components/command-bar/list-model.ts +77 -0
- package/src/components/command-bar/view-model.ts +0 -19
- package/src/components/command-bar/workflow-ops.ts +4 -0
- 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 +6 -2
- package/src/components/layout/floating-pane.tsx +30 -2
- package/src/components/layout/header.tsx +10 -7
- 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 +26 -4
- package/src/components/layout/pane-header.tsx +5 -5
- package/src/components/layout/pane-keyboard-scroll.test.tsx +226 -0
- package/src/components/layout/shell.test.tsx +66 -22
- package/src/components/layout/shell.tsx +13 -6
- 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 +558 -0
- package/src/components/table-view-shared.tsx +158 -0
- package/src/components/ticker-list-table-view.tsx +42 -72
- package/src/components/ui/confirm-dialog.tsx +66 -0
- package/src/components/ui/data-table.tsx +18 -10
- package/src/components/ui/index.ts +0 -1
- package/src/components/ui/page-stack-view.tsx +39 -10
- package/src/components/ui/remote-image.tsx +15 -40
- package/src/components/ui/table-layout.test.ts +16 -0
- package/src/components/ui/table-layout.ts +10 -3
- package/src/components/ui/ui.test.tsx +100 -20
- package/src/core/state/app-state.ts +6 -3
- package/src/market-data/coordinator.test.ts +1 -1
- package/src/market-data/coordinator.ts +0 -1
- package/src/news/aggregator.ts +0 -3
- 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 +0 -3
- 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 +105 -0
- package/src/plugins/builtin/chat-controller.ts +75 -6
- package/src/plugins/builtin/chat.test.tsx +6 -6
- package/src/plugins/builtin/chat.tsx +29 -20
- package/src/plugins/builtin/cloud-tweets.tsx +0 -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 +478 -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.tsx +10 -15
- package/src/plugins/builtin/insider/index.tsx +22 -89
- package/src/plugins/builtin/market-movers/index.tsx +1 -1
- package/src/plugins/builtin/news-wire/index.tsx +41 -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 +18 -55
- package/src/plugins/builtin/options.test.tsx +58 -2
- package/src/plugins/builtin/options.tsx +108 -49
- package/src/plugins/builtin/plugin-groups.ts +2 -0
- package/src/plugins/builtin/portfolio-list/cli/commands.ts +1 -1
- package/src/plugins/builtin/research/index.tsx +5 -21
- 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 +36 -28
- package/src/plugins/builtin/ticker-detail-chart-tab-switch.test.tsx +69 -4
- package/src/plugins/builtin/ticker-detail.test.tsx +102 -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 +56 -5
- package/src/plugins/ibkr/trade-tab.tsx +13 -11
- package/src/plugins/pane-manager.ts +0 -13
- package/src/plugins/plugin-runtime.test.tsx +6 -6
- package/src/plugins/plugin-runtime.tsx +13 -8
- package/src/plugins/prediction-markets/cli.ts +0 -1
- package/src/plugins/prediction-markets/controller-data.ts +0 -2
- 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 +10 -39
- package/src/react/input.ts +11 -2
- package/src/renderers/electrobun/view/data-table.tsx +28 -6
- package/src/renderers/electrobun/view/desktop-controls.tsx +34 -20
- package/src/renderers/electrobun/view/dialog-host.tsx +11 -1
- package/src/renderers/electrobun/view/input-host.tsx +123 -12
- package/src/renderers/electrobun/view/key-event.ts +1 -1
- package/src/renderers/electrobun/view/styles.css +331 -0
- package/src/renderers/electrobun/view/ui-host.tsx +22 -3
- package/src/renderers/opentui/chart-surface.tsx +179 -0
- package/src/renderers/opentui/host.tsx +6 -0
- package/src/renderers/opentui/image-loader.test.ts +25 -0
- package/src/renderers/opentui/image-loader.ts +105 -0
- package/src/renderers/opentui/image-surface.tsx +266 -0
- package/src/renderers/opentui/input-host.tsx +45 -6
- package/src/renderers/opentui/start.tsx +48 -30
- package/src/renderers/opentui/test-utils.tsx +17 -0
- package/src/renderers/opentui/ui-host.tsx +7 -3
- package/src/sources/provider-router.ts +0 -4
- package/src/state/app-context.test.ts +45 -0
- package/src/state/app-context.tsx +4 -0
- package/src/state/pane-scroll-registry.tsx +254 -0
- package/src/state/use-inline-tickers.test.tsx +73 -0
- package/src/state/use-inline-tickers.ts +7 -1
- package/src/test-support/plugin-runtime.ts +3 -2
- package/src/theme/colors.ts +12 -3
- 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/data-provider.ts +0 -1
- package/src/types/plugin.ts +0 -2
- package/src/ui/host.tsx +4 -0
- package/src/ui/index.tsx +9 -1
- package/src/utils/back-navigation.ts +24 -1
- 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
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { afterEach, describe, expect, test } from "bun:test";
|
|
2
2
|
import { TextAttributes } from "@opentui/core";
|
|
3
|
-
import { testRender } from "../../renderers/opentui/test-utils";
|
|
4
|
-
import { DialogProvider } from "@opentui-ui/dialog/react";
|
|
3
|
+
import { TestDialogProvider, testRender } from "../../renderers/opentui/test-utils";
|
|
5
4
|
import type { ReactNode } from "react";
|
|
6
5
|
import { act, createElement, useReducer } from "react";
|
|
7
6
|
import { AppContext, appReducer, createInitialState } from "../../state/app-context";
|
|
@@ -76,7 +75,7 @@ function createShellPluginRegistry(options?: {
|
|
|
76
75
|
openPaneSettingsFn: () => {},
|
|
77
76
|
openCommandBar: () => {},
|
|
78
77
|
updateLayoutFn: () => {},
|
|
79
|
-
|
|
78
|
+
hidePane: () => {},
|
|
80
79
|
} as unknown as PluginRegistry;
|
|
81
80
|
}
|
|
82
81
|
|
|
@@ -114,7 +113,7 @@ function createBrokerPortfolioRegistry(): PluginRegistry {
|
|
|
114
113
|
openPaneSettingsFn: () => {},
|
|
115
114
|
openCommandBar: () => {},
|
|
116
115
|
updateLayoutFn: () => {},
|
|
117
|
-
|
|
116
|
+
hidePane: () => {},
|
|
118
117
|
focusPaneFn: () => {},
|
|
119
118
|
pinTicker: () => {},
|
|
120
119
|
navigateTicker: () => {},
|
|
@@ -337,9 +336,9 @@ function ChartShellHarness({
|
|
|
337
336
|
|
|
338
337
|
return (
|
|
339
338
|
<AppContext value={{ state, dispatch }}>
|
|
340
|
-
<
|
|
339
|
+
<TestDialogProvider>
|
|
341
340
|
<Shell pluginRegistry={pluginRegistry} />
|
|
342
|
-
</
|
|
341
|
+
</TestDialogProvider>
|
|
343
342
|
</AppContext>
|
|
344
343
|
);
|
|
345
344
|
}
|
|
@@ -613,9 +612,9 @@ describe("Shell", () => {
|
|
|
613
612
|
|
|
614
613
|
testSetup = await testRender(
|
|
615
614
|
<AppContext value={{ state, dispatch: () => {} }}>
|
|
616
|
-
<
|
|
615
|
+
<TestDialogProvider>
|
|
617
616
|
<Shell pluginRegistry={pluginRegistry} />
|
|
618
|
-
</
|
|
617
|
+
</TestDialogProvider>
|
|
619
618
|
</AppContext>,
|
|
620
619
|
{ width: 40, height: 10 },
|
|
621
620
|
);
|
|
@@ -655,7 +654,7 @@ describe("Shell", () => {
|
|
|
655
654
|
|
|
656
655
|
testSetup = await testRender(
|
|
657
656
|
<AppContext value={{ state, dispatch: () => {} }}>
|
|
658
|
-
<
|
|
657
|
+
<TestDialogProvider>
|
|
659
658
|
<Shell
|
|
660
659
|
pluginRegistry={pluginRegistry}
|
|
661
660
|
desktopWindowBridge={{
|
|
@@ -665,7 +664,7 @@ describe("Shell", () => {
|
|
|
665
664
|
subscribeDockPreview: () => () => {},
|
|
666
665
|
}}
|
|
667
666
|
/>
|
|
668
|
-
</
|
|
667
|
+
</TestDialogProvider>
|
|
669
668
|
</AppContext>,
|
|
670
669
|
{ width: 40, height: 10 },
|
|
671
670
|
);
|
|
@@ -704,9 +703,9 @@ describe("Shell", () => {
|
|
|
704
703
|
|
|
705
704
|
testSetup = await testRender(
|
|
706
705
|
<AppContext value={{ state, dispatch: () => {} }}>
|
|
707
|
-
<
|
|
706
|
+
<TestDialogProvider>
|
|
708
707
|
<Shell pluginRegistry={pluginRegistry} />
|
|
709
|
-
</
|
|
708
|
+
</TestDialogProvider>
|
|
710
709
|
</AppContext>,
|
|
711
710
|
{ width: 40, height: 10 },
|
|
712
711
|
);
|
|
@@ -823,9 +822,9 @@ describe("Shell", () => {
|
|
|
823
822
|
setSharedRegistryForTests(pluginRegistry);
|
|
824
823
|
|
|
825
824
|
testSetup = await testRender(
|
|
826
|
-
<
|
|
825
|
+
<TestDialogProvider>
|
|
827
826
|
<BrokerShellHarness pluginRegistry={pluginRegistry} />
|
|
828
|
-
</
|
|
827
|
+
</TestDialogProvider>,
|
|
829
828
|
{ width: 100, height: 24 },
|
|
830
829
|
);
|
|
831
830
|
|
|
@@ -916,9 +915,9 @@ describe("Shell", () => {
|
|
|
916
915
|
|
|
917
916
|
testSetup = await testRender(
|
|
918
917
|
<AppContext value={{ state, dispatch: (action) => actions.push(action) }}>
|
|
919
|
-
<
|
|
918
|
+
<TestDialogProvider>
|
|
920
919
|
<Shell pluginRegistry={createShellPluginRegistry()} />
|
|
921
|
-
</
|
|
920
|
+
</TestDialogProvider>
|
|
922
921
|
</AppContext>,
|
|
923
922
|
{ width: 40, height: 10 },
|
|
924
923
|
);
|
|
@@ -946,6 +945,7 @@ describe("Shell", () => {
|
|
|
946
945
|
dockRoot: { kind: "pane" as const, instanceId: "portfolio-list:main" },
|
|
947
946
|
instances: [{ ...mainPane }, { ...detailPane }],
|
|
948
947
|
floating: [{ instanceId: "ticker-detail:main", x: 4, y: 2, width: 30, height: 8 }],
|
|
948
|
+
detached: [],
|
|
949
949
|
};
|
|
950
950
|
const state = {
|
|
951
951
|
...createInitialState({
|
|
@@ -959,9 +959,9 @@ describe("Shell", () => {
|
|
|
959
959
|
|
|
960
960
|
testSetup = await testRender(
|
|
961
961
|
<AppContext value={{ state, dispatch: (action) => actions.push(action) }}>
|
|
962
|
-
<
|
|
962
|
+
<TestDialogProvider>
|
|
963
963
|
<Shell pluginRegistry={createShellPluginRegistry()} />
|
|
964
|
-
</
|
|
964
|
+
</TestDialogProvider>
|
|
965
965
|
</AppContext>,
|
|
966
966
|
{ width: 40, height: 12 },
|
|
967
967
|
);
|
|
@@ -989,6 +989,7 @@ describe("Shell", () => {
|
|
|
989
989
|
dockRoot: { kind: "pane" as const, instanceId: "portfolio-list:main" },
|
|
990
990
|
instances: [{ ...mainPane }, { ...detailPane }],
|
|
991
991
|
floating: [{ instanceId: "ticker-detail:main", x: 4, y: 2, width: 30, height: 8 }],
|
|
992
|
+
detached: [],
|
|
992
993
|
};
|
|
993
994
|
const state = {
|
|
994
995
|
...createInitialState({
|
|
@@ -1002,9 +1003,9 @@ describe("Shell", () => {
|
|
|
1002
1003
|
|
|
1003
1004
|
testSetup = await testRender(
|
|
1004
1005
|
<AppContext value={{ state, dispatch: (action) => actions.push(action) }}>
|
|
1005
|
-
<
|
|
1006
|
+
<TestDialogProvider>
|
|
1006
1007
|
<Shell pluginRegistry={createShellPluginRegistry()} />
|
|
1007
|
-
</
|
|
1008
|
+
</TestDialogProvider>
|
|
1008
1009
|
</AppContext>,
|
|
1009
1010
|
{ width: 40, height: 12 },
|
|
1010
1011
|
);
|
|
@@ -1020,6 +1021,49 @@ describe("Shell", () => {
|
|
|
1020
1021
|
expect(updateLayout?.layout.floating).toEqual([]);
|
|
1021
1022
|
});
|
|
1022
1023
|
|
|
1024
|
+
test("closes the focused floating pane with Ctrl+W while plugin input is captured", async () => {
|
|
1025
|
+
const config = createDefaultConfig("/tmp/gloomberb-shell-test");
|
|
1026
|
+
const mainPane = config.layout.instances.find((instance) => instance.instanceId === "portfolio-list:main");
|
|
1027
|
+
const detailPane = config.layout.instances.find((instance) => instance.instanceId === "ticker-detail:main");
|
|
1028
|
+
if (!mainPane || !detailPane) throw new Error("missing default panes");
|
|
1029
|
+
|
|
1030
|
+
const mixedLayout = {
|
|
1031
|
+
dockRoot: { kind: "pane" as const, instanceId: "portfolio-list:main" },
|
|
1032
|
+
instances: [{ ...mainPane }, { ...detailPane }],
|
|
1033
|
+
floating: [{ instanceId: "ticker-detail:main", x: 4, y: 2, width: 30, height: 8 }],
|
|
1034
|
+
detached: [],
|
|
1035
|
+
};
|
|
1036
|
+
const state = {
|
|
1037
|
+
...createInitialState({
|
|
1038
|
+
...config,
|
|
1039
|
+
layout: cloneLayout(mixedLayout),
|
|
1040
|
+
layouts: [{ name: "Default", layout: cloneLayout(mixedLayout) }],
|
|
1041
|
+
}),
|
|
1042
|
+
focusedPaneId: "ticker-detail:main",
|
|
1043
|
+
inputCaptured: true,
|
|
1044
|
+
};
|
|
1045
|
+
const actions: Array<any> = [];
|
|
1046
|
+
|
|
1047
|
+
testSetup = await testRender(
|
|
1048
|
+
<AppContext value={{ state, dispatch: (action) => actions.push(action) }}>
|
|
1049
|
+
<TestDialogProvider>
|
|
1050
|
+
<Shell pluginRegistry={createShellPluginRegistry()} />
|
|
1051
|
+
</TestDialogProvider>
|
|
1052
|
+
</AppContext>,
|
|
1053
|
+
{ width: 40, height: 12 },
|
|
1054
|
+
);
|
|
1055
|
+
|
|
1056
|
+
await testSetup.renderOnce();
|
|
1057
|
+
await act(async () => {
|
|
1058
|
+
testSetup!.mockInput.pressKey("w", { ctrl: true });
|
|
1059
|
+
await testSetup!.renderOnce();
|
|
1060
|
+
});
|
|
1061
|
+
|
|
1062
|
+
const updateLayout = actions.find((action) => action.type === "UPDATE_LAYOUT");
|
|
1063
|
+
expect(updateLayout?.layout.instances.map((instance: { instanceId: string }) => instance.instanceId)).toEqual(["portfolio-list:main"]);
|
|
1064
|
+
expect(updateLayout?.layout.floating).toEqual([]);
|
|
1065
|
+
});
|
|
1066
|
+
|
|
1023
1067
|
test("keeps a floating pane at the preview rect after a free drag release", () => {
|
|
1024
1068
|
const config = createDefaultConfig("/tmp/gloomberb-shell-drag-test");
|
|
1025
1069
|
const detailPane = config.layout.instances.find((instance) => instance.instanceId === "ticker-detail:main");
|
|
@@ -1153,7 +1197,7 @@ describe("Shell", () => {
|
|
|
1153
1197
|
|
|
1154
1198
|
testSetup = await testRender(
|
|
1155
1199
|
<AppContext value={{ state, dispatch: () => {} }}>
|
|
1156
|
-
<
|
|
1200
|
+
<TestDialogProvider>
|
|
1157
1201
|
<Shell pluginRegistry={createShellPluginRegistry({
|
|
1158
1202
|
tickerDetailComponent: ({ width, height }) => (
|
|
1159
1203
|
<box flexDirection="column" width={width} height={height}>
|
|
@@ -1164,7 +1208,7 @@ describe("Shell", () => {
|
|
|
1164
1208
|
</box>
|
|
1165
1209
|
),
|
|
1166
1210
|
})} />
|
|
1167
|
-
</
|
|
1211
|
+
</TestDialogProvider>
|
|
1168
1212
|
</AppContext>,
|
|
1169
1213
|
{ width: 40, height: 12 },
|
|
1170
1214
|
);
|
|
@@ -9,7 +9,6 @@ import {
|
|
|
9
9
|
MIN_FLOAT_HEIGHT,
|
|
10
10
|
MIN_FLOAT_WIDTH,
|
|
11
11
|
applyDrop,
|
|
12
|
-
findDockLeaf,
|
|
13
12
|
floatAtRect,
|
|
14
13
|
floatPane,
|
|
15
14
|
getDockDividerLayouts,
|
|
@@ -22,7 +21,6 @@ import {
|
|
|
22
21
|
resolveDocked,
|
|
23
22
|
resolveFloating,
|
|
24
23
|
simulateDrop,
|
|
25
|
-
swapPanes,
|
|
26
24
|
type DockDividerLayout,
|
|
27
25
|
type DockLeafLayout,
|
|
28
26
|
type DropTarget,
|
|
@@ -218,6 +216,14 @@ export function resolvePaneManagementShortcut(
|
|
|
218
216
|
return null;
|
|
219
217
|
}
|
|
220
218
|
|
|
219
|
+
function inputCaptureAllowsPaneManagementShortcut(
|
|
220
|
+
shortcut: PaneManagementShortcut,
|
|
221
|
+
event: Pick<KeyEventLike, "meta" | "super" | "targetEditable">,
|
|
222
|
+
): boolean {
|
|
223
|
+
if (shortcut !== "close") return false;
|
|
224
|
+
return event.meta || event.super || event.targetEditable !== true;
|
|
225
|
+
}
|
|
226
|
+
|
|
221
227
|
export function resolveAppHeaderHeightCells(options: { titleBarOverlay?: boolean; cellHeightPx?: number }): number {
|
|
222
228
|
if (!options.titleBarOverlay || !options.cellHeightPx || options.cellHeightPx <= 0) return DEFAULT_HEADER_HEIGHT;
|
|
223
229
|
return TITLEBAR_OVERLAY_HEIGHT_PX / options.cellHeightPx;
|
|
@@ -588,8 +594,8 @@ function resolveHeaderHitAreas(
|
|
|
588
594
|
actionStart: number | null;
|
|
589
595
|
closeStart: number | null;
|
|
590
596
|
} {
|
|
591
|
-
//
|
|
592
|
-
let rightEdge = options.focused ? width - 2 : width;
|
|
597
|
+
// Focused panes and all floating panes render ┌─...─┐, adding 2 chars on each side.
|
|
598
|
+
let rightEdge = options.focused || options.floating ? width - 2 : width;
|
|
593
599
|
let closeStart: number | null = null;
|
|
594
600
|
let actionStart: number | null = null;
|
|
595
601
|
|
|
@@ -966,7 +972,8 @@ export function Shell({ pluginRegistry, desktopWindowBridge, desktopDockPreview
|
|
|
966
972
|
}
|
|
967
973
|
|
|
968
974
|
const shortcut = resolvePaneManagementShortcut(event);
|
|
969
|
-
if (!shortcut || dragRef.current || overlayOpen
|
|
975
|
+
if (!shortcut || dragRef.current || overlayOpen) return;
|
|
976
|
+
if (inputCaptured && !inputCaptureAllowsPaneManagementShortcut(shortcut, event)) return;
|
|
970
977
|
|
|
971
978
|
let handled = false;
|
|
972
979
|
switch (shortcut) {
|
|
@@ -1701,7 +1708,7 @@ export function Shell({ pluginRegistry, desktopWindowBridge, desktopDockPreview
|
|
|
1701
1708
|
"data-active": active ? "true" : "false",
|
|
1702
1709
|
style: { "--divider-color": active ? colors.borderFocused : colors.border } as any,
|
|
1703
1710
|
} : {})}
|
|
1704
|
-
onMouseDown={nativePaneChrome ? (event) => startNativeDividerDrag(divider, event) : undefined}
|
|
1711
|
+
onMouseDown={nativePaneChrome ? (event: ShellMouseEvent) => startNativeDividerDrag(divider, event) : undefined}
|
|
1705
1712
|
onMouseDrag={nativePaneChrome ? handleNativeDrag : undefined}
|
|
1706
1713
|
onMouseDragEnd={nativePaneChrome ? handleNativeDrag : undefined}
|
|
1707
1714
|
/>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AsciiText, Box,
|
|
1
|
+
import { AsciiText, Box, Span, Strong, Text, Underline, useUiHost } from "../../ui";
|
|
2
2
|
import { useState, useCallback, useEffect, useRef, useMemo, type RefObject } from "react";
|
|
3
3
|
import { useShortcut, useViewport } from "../../react/input";
|
|
4
4
|
import { TextAttributes } from "../../ui";
|
|
@@ -963,7 +963,6 @@ function PortfolioStep({
|
|
|
963
963
|
|
|
964
964
|
// broker-fields: dynamically render fields from the broker's configSchema
|
|
965
965
|
if (!selectedBrokerId) return null;
|
|
966
|
-
const currentField = brokerFields[brokerFieldIdx];
|
|
967
966
|
const values = brokerValues[selectedBrokerId] ?? {};
|
|
968
967
|
|
|
969
968
|
return (
|
|
@@ -9,7 +9,7 @@ import type {
|
|
|
9
9
|
PaneSettingTextField,
|
|
10
10
|
} from "../types/plugin";
|
|
11
11
|
import type { PluginRegistry } from "../plugins/registry";
|
|
12
|
-
import { colors } from "../theme/colors";
|
|
12
|
+
import { blendHex, colors } from "../theme/colors";
|
|
13
13
|
import { Button, DialogFrame, ListView, MultiSelectDialogContent, TextField } from "./ui";
|
|
14
14
|
import { NativeSelect, openNativeSelect, type NativeSelectElement } from "./ui/native-select";
|
|
15
15
|
|
|
@@ -80,6 +80,14 @@ function desktopText(weight?: number) {
|
|
|
80
80
|
return weight ? { ...DESKTOP_TEXT_STYLE, fontWeight: weight } : DESKTOP_TEXT_STYLE;
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
function desktopSubtleSurface(): string {
|
|
84
|
+
return blendHex(colors.panel, colors.bg, 0.22);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function desktopHoverSurface(): string {
|
|
88
|
+
return blendHex(colors.bg, colors.borderFocused, 0.08);
|
|
89
|
+
}
|
|
90
|
+
|
|
83
91
|
function DesktopDialogSurface({
|
|
84
92
|
title,
|
|
85
93
|
subtitle,
|
|
@@ -149,7 +157,7 @@ function DesktopSwitch({
|
|
|
149
157
|
flexDirection="row"
|
|
150
158
|
alignItems="center"
|
|
151
159
|
justifyContent={checked ? "flex-end" : "flex-start"}
|
|
152
|
-
backgroundColor={checked ? colors.selected :
|
|
160
|
+
backgroundColor={checked ? colors.selected : desktopSubtleSurface()}
|
|
153
161
|
onMouseDown={(event: any) => {
|
|
154
162
|
event.stopPropagation?.();
|
|
155
163
|
event.preventDefault?.();
|
|
@@ -182,7 +190,7 @@ function DesktopValuePill({ value }: { value: string }) {
|
|
|
182
190
|
<Box
|
|
183
191
|
flexDirection="row"
|
|
184
192
|
alignItems="center"
|
|
185
|
-
backgroundColor=
|
|
193
|
+
backgroundColor={desktopSubtleSurface()}
|
|
186
194
|
style={{
|
|
187
195
|
border: `1px solid ${colors.border}`,
|
|
188
196
|
borderRadius: 6,
|
|
@@ -236,7 +244,7 @@ function DesktopSettingsRow({
|
|
|
236
244
|
<Box
|
|
237
245
|
flexDirection="column"
|
|
238
246
|
minHeight={field.description ? undefined : 2}
|
|
239
|
-
backgroundColor={hovered || selected ?
|
|
247
|
+
backgroundColor={hovered || selected ? desktopHoverSurface() : "transparent"}
|
|
240
248
|
onMouseMove={onHover}
|
|
241
249
|
onMouseDown={field.type === "select" ? undefined : (event: any) => {
|
|
242
250
|
event.stopPropagation?.();
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { afterEach, describe, expect, test } from "bun:test";
|
|
2
2
|
import { act } from "react";
|
|
3
|
-
import { testRender } from "../renderers/opentui/test-utils";
|
|
4
|
-
import { DialogProvider } from "@opentui-ui/dialog/react";
|
|
3
|
+
import { TestDialogProvider, testRender } from "../renderers/opentui/test-utils";
|
|
5
4
|
import { PaneTemplateTextareaStep } from "./pane-template-wizard";
|
|
6
5
|
|
|
7
6
|
let testSetup: Awaited<ReturnType<typeof testRender>> | undefined;
|
|
@@ -18,7 +17,7 @@ describe("PaneTemplateTextareaStep", () => {
|
|
|
18
17
|
let resolved = "";
|
|
19
18
|
|
|
20
19
|
testSetup = await testRender(
|
|
21
|
-
<
|
|
20
|
+
<TestDialogProvider>
|
|
22
21
|
<PaneTemplateTextareaStep
|
|
23
22
|
resolve={(value) => { resolved = value; }}
|
|
24
23
|
dialogId="textarea-test"
|
|
@@ -30,7 +29,7 @@ describe("PaneTemplateTextareaStep", () => {
|
|
|
30
29
|
defaultValue: "Find cash-generative semiconductor suppliers",
|
|
31
30
|
}}
|
|
32
31
|
/>
|
|
33
|
-
</
|
|
32
|
+
</TestDialogProvider>,
|
|
34
33
|
{ width: 80, height: 16 },
|
|
35
34
|
);
|
|
36
35
|
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { afterEach, describe, expect, test } from "bun:test";
|
|
2
|
+
import { act } from "react";
|
|
3
|
+
import { testRender } from "../renderers/opentui/test-utils";
|
|
4
|
+
import { colors } from "../theme/colors";
|
|
5
|
+
import { SpeedometerGauge, type SpeedometerSegment } from "./speedometer-gauge";
|
|
6
|
+
|
|
7
|
+
let testSetup: Awaited<ReturnType<typeof testRender>> | undefined;
|
|
8
|
+
|
|
9
|
+
afterEach(async () => {
|
|
10
|
+
if (!testSetup) return;
|
|
11
|
+
await act(async () => {
|
|
12
|
+
testSetup!.renderer.destroy();
|
|
13
|
+
});
|
|
14
|
+
testSetup = undefined;
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
const segments: SpeedometerSegment[] = [
|
|
18
|
+
{ from: 0, to: 24.999, label: "EXTREME FEAR", color: colors.negative },
|
|
19
|
+
{ from: 25, to: 44.999, label: "FEAR", color: colors.warning },
|
|
20
|
+
{ from: 45, to: 55, label: "NEUTRAL", color: colors.neutral },
|
|
21
|
+
{ from: 55.001, to: 75, label: "GREED", color: colors.positive },
|
|
22
|
+
{ from: 75.001, to: 100, label: "EXTREME GREED", color: colors.positive },
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
describe("SpeedometerGauge", () => {
|
|
26
|
+
test("keeps the terminal fallback compact in wide panes", async () => {
|
|
27
|
+
testSetup = await testRender(
|
|
28
|
+
<SpeedometerGauge value={67} valueLabel="GREED" width={120} segments={segments} />,
|
|
29
|
+
{ width: 124, height: 14 },
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
await act(async () => {
|
|
33
|
+
await testSetup!.renderOnce();
|
|
34
|
+
await testSetup!.renderOnce();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const frame = testSetup.captureCharFrame();
|
|
38
|
+
expect(frame).toContain("Current reading GREED");
|
|
39
|
+
expect(frame).toContain("67");
|
|
40
|
+
|
|
41
|
+
const labelLine = frame.split("\n").find((line) => line.includes("EXT FEAR") && line.includes("EXT GREED"));
|
|
42
|
+
expect(labelLine).toBeTruthy();
|
|
43
|
+
expect(labelLine!.indexOf("EXT GREED") - labelLine!.indexOf("EXT FEAR")).toBeLessThanOrEqual(58);
|
|
44
|
+
});
|
|
45
|
+
});
|