gloomberb 0.7.2 → 0.7.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +79 -132
- package/package.json +1 -1
- package/src/app.tsx +73 -67
- package/src/components/chart/chart-data.ts +7 -2
- package/src/components/chart/chart-pane-settings.ts +7 -4
- package/src/components/chart/chart-renderer.ts +158 -47
- package/src/components/chart/chart-types.ts +20 -2
- package/src/components/chart/chart.test.ts +179 -13
- package/src/components/chart/comparison-chart-renderer.test.ts +14 -30
- package/src/components/chart/comparison-chart-renderer.ts +50 -11
- package/src/components/chart/comparison-stock-chart.tsx +129 -129
- package/src/components/chart/market-session.ts +187 -0
- package/src/components/chart/native/chart-rasterizer.ts +108 -19
- package/src/components/chart/price-axis-labels.tsx +25 -9
- package/src/components/chart/stock-chart-renderer-switch.test.tsx +97 -1
- package/src/components/chart/stock-chart.tsx +95 -49
- package/src/components/chart/time-axis-label.tsx +56 -2
- package/src/components/command-bar/command-bar.test.tsx +446 -120
- package/src/components/command-bar/command-bar.tsx +535 -384
- package/src/components/command-bar/command-registry.ts +16 -6
- package/src/components/command-bar/list-model.ts +8 -4
- package/src/components/command-bar/root-shortcuts.ts +4 -5
- package/src/components/command-bar/view-model.test.ts +21 -0
- package/src/components/command-bar/view-model.ts +17 -4
- package/src/components/command-bar/workflow-ops.ts +11 -32
- package/src/components/data-table-view.test.tsx +24 -1
- package/src/components/data-table-view.tsx +3 -2
- package/src/components/feed-data-table-stack-view.tsx +3 -2
- package/src/components/layout/detached-pane-shell.tsx +2 -2
- package/src/components/layout/floating-pane.tsx +9 -2
- package/src/components/layout/pane-footer.tsx +1 -1
- package/src/components/layout/pane-header.tsx +4 -2
- package/src/components/layout/pane-sizing.ts +12 -0
- package/src/components/layout/pane.tsx +24 -2
- package/src/components/layout/shell.tsx +24 -10
- package/src/components/layout/status-bar.test.tsx +4 -1
- package/src/components/layout/status-bar.tsx +4 -24
- package/src/components/markdown-text.tsx +53 -8
- package/src/components/onboarding/onboarding-wizard.tsx +7 -6
- package/src/components/pane-settings-dialog.tsx +9 -6
- package/src/components/pane-template-wizard.tsx +3 -2
- package/src/components/price-selector-dialog.tsx +3 -2
- package/src/components/price-sparkline-view.tsx +463 -0
- package/src/components/price-sparkline.ts +46 -0
- package/src/components/table-view-shared.tsx +21 -3
- package/src/components/ticker-list-table-view.tsx +3 -2
- package/src/components/ticker-list-table.tsx +15 -66
- package/src/components/toggle-list.tsx +3 -3
- package/src/components/ui/choice-dialog.tsx +3 -2
- package/src/components/ui/multi-select-dialog.tsx +3 -2
- package/src/components/ui/native-select.tsx +3 -3
- package/src/core/state/app-state.ts +210 -80
- package/src/core/state/session-persistence.ts +25 -0
- package/src/data/config-store-node.ts +113 -25
- package/src/data/config-store.test.ts +65 -3
- package/src/data/plugin-state-store.ts +39 -13
- package/src/data/sqlite-cache.test.ts +13 -0
- package/src/market-data/coordinator-subscriptions.test.ts +102 -18
- package/src/market-data/coordinator.test.ts +122 -2
- package/src/market-data/coordinator.ts +200 -56
- package/src/market-data/hooks.test.tsx +31 -0
- package/src/market-data/hooks.tsx +1 -0
- package/src/news/aggregator.test.ts +41 -0
- package/src/news/aggregator.ts +61 -9
- package/src/plugins/builtin/ai/ask-ai-detail-tab.tsx +25 -6
- package/src/plugins/builtin/ai/screener-pane.tsx +3 -0
- package/src/plugins/builtin/ai/settings.ts +3 -0
- package/src/plugins/builtin/broker-manager/index.tsx +4 -3
- package/src/plugins/builtin/chat-controller.test.ts +398 -17
- package/src/plugins/builtin/chat-controller.ts +263 -48
- package/src/plugins/builtin/chat.test.tsx +312 -6
- package/src/plugins/builtin/chat.tsx +245 -66
- package/src/plugins/builtin/comparison-chart.test.tsx +117 -3
- package/src/plugins/builtin/correlation/colors.test.ts +39 -0
- package/src/plugins/builtin/correlation/colors.ts +87 -0
- package/src/plugins/builtin/correlation/index.test.tsx +151 -0
- package/src/plugins/builtin/correlation/index.tsx +92 -21
- package/src/plugins/builtin/debug.tsx +4 -3
- package/src/plugins/builtin/econ/index.tsx +3 -2
- package/src/plugins/builtin/help.test.tsx +2 -2
- package/src/plugins/builtin/holders/index.tsx +25 -13
- package/src/plugins/builtin/layout-manager.tsx +1 -7
- package/src/plugins/builtin/market-movers/index.tsx +72 -40
- package/src/plugins/builtin/news-wire/breaking-pane.test.tsx +156 -0
- package/src/plugins/builtin/news-wire/breaking-pane.tsx +0 -90
- package/src/plugins/builtin/news-wire/index.tsx +1 -3
- package/src/plugins/builtin/news-wire/news-detail-view.tsx +3 -2
- package/src/plugins/builtin/news-wire/news-preset-pane.tsx +4 -1
- package/src/plugins/builtin/news-wire/persisted-articles.ts +7 -1
- package/src/plugins/builtin/options.tsx +9 -17
- package/src/plugins/builtin/portfolio-list/cli/commands.ts +6 -10
- package/src/plugins/builtin/portfolio-list/metrics.ts +13 -2
- package/src/plugins/builtin/portfolio-list/mutations.ts +17 -0
- package/src/plugins/builtin/portfolio-list/pane.tsx +139 -23
- package/src/plugins/builtin/portfolio-list/quick-add.tsx +422 -0
- package/src/plugins/builtin/portfolio-list/settings.ts +20 -12
- package/src/plugins/builtin/portfolio-list/table.tsx +3 -3
- package/src/plugins/builtin/portfolio-list.test.tsx +311 -9
- package/src/plugins/builtin/quote-monitor.test.tsx +158 -25
- package/src/plugins/builtin/sectors/index.tsx +275 -43
- package/src/plugins/builtin/sectors/sector-data.ts +41 -1
- package/src/plugins/builtin/ticker-detail/chart-tab.tsx +3 -2
- package/src/plugins/builtin/ticker-detail/index.tsx +30 -9
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +25 -15
- package/src/plugins/builtin/ticker-detail/pane.tsx +18 -7
- package/src/plugins/builtin/ticker-detail/quote-monitor.tsx +445 -63
- package/src/plugins/builtin/ticker-detail/settings.ts +84 -3
- package/src/plugins/builtin/ticker-detail.test.tsx +2 -2
- package/src/plugins/builtin/world-indices/index.tsx +58 -19
- package/src/plugins/ibkr/trading-pane.tsx +3 -2
- package/src/plugins/plugin-runtime.tsx +2 -2
- package/src/plugins/prediction-markets/settings.ts +4 -0
- package/src/plugins/registry.test.ts +55 -0
- package/src/plugins/registry.ts +11 -4
- package/src/plugins/ticker-navigation.test.ts +35 -5
- package/src/plugins/ticker-navigation.ts +16 -22
- package/src/renderers/electrobun/bun/application-menu-click.test.ts +9 -0
- package/src/renderers/electrobun/bun/application-menu-click.ts +7 -4
- package/src/renderers/electrobun/bun/application-menu.ts +6 -1
- package/src/renderers/electrobun/bun/desktop-workspace.ts +47 -29
- package/src/renderers/electrobun/bun/index.ts +52 -13
- package/src/renderers/electrobun/view/app-services.ts +51 -9
- package/src/renderers/electrobun/view/backend-rpc.ts +5 -8
- package/src/renderers/electrobun/view/desktop-controls.tsx +4 -4
- package/src/renderers/electrobun/view/main.tsx +0 -16
- package/src/renderers/electrobun/view/styles.css +23 -21
- package/src/renderers/electrobun/view/ui-host.tsx +6 -4
- package/src/renderers/opentui/host.tsx +2 -1
- package/src/renderers/opentui/start.tsx +1 -1
- package/src/renderers/opentui/test-utils.tsx +6 -5
- package/src/sources/gloomberb-cloud.test.ts +55 -2
- package/src/sources/gloomberb-cloud.ts +180 -29
- package/src/sources/provider-router.test.ts +567 -10
- package/src/sources/provider-router.ts +323 -93
- package/src/sources/yahoo-finance.test.ts +37 -0
- package/src/sources/yahoo-finance.ts +48 -2
- package/src/state/app-bootstrap.test.ts +50 -23
- package/src/state/app-bootstrap.ts +29 -13
- package/src/state/app-context.test.ts +113 -0
- package/src/state/app-context.tsx +8 -4
- package/src/state/session-persistence.test.ts +5 -3
- package/src/state/use-inline-tickers.ts +3 -0
- package/src/state/use-quote-streaming.ts +11 -0
- package/src/theme/colors.ts +13 -14
- package/src/types/config.ts +9 -4
- package/src/types/data-provider.ts +5 -1
- package/src/types/financials.ts +1 -0
- package/src/types/plugin.ts +8 -1
- package/src/ui/context-menu.tsx +4 -4
- package/src/utils/api-client.test.ts +248 -0
- package/src/utils/api-client.ts +178 -26
- package/src/utils/exchanges.test.ts +16 -0
- package/src/utils/exchanges.ts +33 -0
- package/src/utils/fuzzy-search.ts +12 -1
- package/src/utils/keyboard.ts +31 -0
- package/src/utils/options.ts +1 -1
- package/src/utils/price-history.test.ts +28 -1
- package/src/utils/price-history.ts +16 -0
- package/src/utils/quote-freshness.test.ts +150 -0
- package/src/utils/quote-freshness.ts +42 -1
- package/src/utils/quote-resolution.ts +2 -0
- package/src/utils/quote-time.test.ts +34 -0
- package/src/utils/quote-time.ts +18 -5
- package/src/utils/ticker-search.test.ts +2 -2
- package/src/utils/ticker-search.ts +48 -1
- package/src/version.ts +1 -1
- package/src/plugins/builtin/news-wire/digest-store.ts +0 -44
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Box, Span, Text, TextAttributes, contextMenuDivider, useContextMenu, useUiCapabilities } from "../../ui";
|
|
2
2
|
import { useCallback, useEffect, useState } from "react";
|
|
3
|
-
import { colors, hoverBg } from "../../theme/colors";
|
|
3
|
+
import { blendHex, colors, hoverBg } from "../../theme/colors";
|
|
4
4
|
import { useThemeColors } from "../../theme/theme-context";
|
|
5
|
-
import { useAppDispatch, useAppSelector
|
|
5
|
+
import { useAppDispatch, useAppSelector } from "../../state/app-context";
|
|
6
6
|
import {
|
|
7
7
|
selectActiveLayoutIndex,
|
|
8
8
|
selectGridlockTipSequence,
|
|
@@ -10,9 +10,6 @@ import {
|
|
|
10
10
|
selectSavedLayouts,
|
|
11
11
|
selectStatusBarVisible,
|
|
12
12
|
} from "../../state/selectors-ui";
|
|
13
|
-
import {
|
|
14
|
-
getExtendedHoursInfo,
|
|
15
|
-
} from "../../utils/market-status";
|
|
16
13
|
import { getSharedRegistry } from "../../plugins/registry";
|
|
17
14
|
import { gridlockAllPanes } from "../../plugins/pane-manager";
|
|
18
15
|
import { notifyGridlockComplete } from "../../plugins/gridlock-notification";
|
|
@@ -35,8 +32,6 @@ type LayoutTabItem = {
|
|
|
35
32
|
type StatusBarViewProps = {
|
|
36
33
|
activeLayoutIdx: number;
|
|
37
34
|
dismissGridlockTip: (event?: StatusBarEvent) => void;
|
|
38
|
-
extColor: string;
|
|
39
|
-
extText: string;
|
|
40
35
|
handleGridlockTip: (event?: StatusBarEvent) => void;
|
|
41
36
|
handleLayoutSelect: (value: string) => void;
|
|
42
37
|
hasMultipleLayouts: boolean;
|
|
@@ -47,7 +42,6 @@ type StatusBarViewProps = {
|
|
|
47
42
|
openLayoutContextMenu: (index: number, event: any) => void | Promise<unknown>;
|
|
48
43
|
setHoveredControl: SetHoveredControl;
|
|
49
44
|
showGridlockTip: boolean;
|
|
50
|
-
symbol: string | null | undefined;
|
|
51
45
|
};
|
|
52
46
|
|
|
53
47
|
function truncate(text: string, width: number): string {
|
|
@@ -68,14 +62,8 @@ export function StatusBar() {
|
|
|
68
62
|
const statusBarVisible = useAppSelector(selectStatusBarVisible);
|
|
69
63
|
const gridlockTipVisible = useAppSelector(selectGridlockTipVisible);
|
|
70
64
|
const gridlockTipSequence = useAppSelector(selectGridlockTipSequence);
|
|
71
|
-
const { symbol, financials: focusedFinancials } = useFocusedTicker();
|
|
72
65
|
const [hoveredControl, setHoveredControl] = useState<string | null>(null);
|
|
73
66
|
|
|
74
|
-
// Extended hours info for selected ticker
|
|
75
|
-
const extInfo = getExtendedHoursInfo(focusedFinancials?.quote);
|
|
76
|
-
const extText = extInfo?.text ?? "";
|
|
77
|
-
const extColor = extInfo?.color ?? colors.textDim;
|
|
78
|
-
|
|
79
67
|
const hasMultipleLayouts = layouts.length > 1;
|
|
80
68
|
const showGridlockTip = gridlockTipVisible && !!registry;
|
|
81
69
|
const layoutTabs = layouts.map((layout, index) => ({
|
|
@@ -211,8 +199,6 @@ export function StatusBar() {
|
|
|
211
199
|
const viewProps: StatusBarViewProps = {
|
|
212
200
|
activeLayoutIdx,
|
|
213
201
|
dismissGridlockTip,
|
|
214
|
-
extColor,
|
|
215
|
-
extText,
|
|
216
202
|
handleGridlockTip,
|
|
217
203
|
handleLayoutSelect,
|
|
218
204
|
hasMultipleLayouts,
|
|
@@ -223,7 +209,6 @@ export function StatusBar() {
|
|
|
223
209
|
openLayoutContextMenu,
|
|
224
210
|
setHoveredControl,
|
|
225
211
|
showGridlockTip,
|
|
226
|
-
symbol,
|
|
227
212
|
};
|
|
228
213
|
|
|
229
214
|
if (nativePaneChrome) {
|
|
@@ -251,7 +236,7 @@ function NativeStatusBar({
|
|
|
251
236
|
}}
|
|
252
237
|
style={{
|
|
253
238
|
borderTop: `1px solid ${colors.border}`,
|
|
254
|
-
boxShadow:
|
|
239
|
+
boxShadow: `inset 0 1px 0 ${blendHex(colors.panel, colors.textBright, 0.03)}`,
|
|
255
240
|
paddingInline: 8,
|
|
256
241
|
}}
|
|
257
242
|
>
|
|
@@ -416,15 +401,10 @@ function TerminalGridlockTip({
|
|
|
416
401
|
);
|
|
417
402
|
}
|
|
418
403
|
|
|
419
|
-
function StatusBarWidgets(
|
|
404
|
+
function StatusBarWidgets() {
|
|
420
405
|
return (
|
|
421
406
|
<>
|
|
422
407
|
<Box flexGrow={1} />
|
|
423
|
-
{extText && (
|
|
424
|
-
<Box paddingRight={1}>
|
|
425
|
-
<Text fg={extColor}>{symbol} {extText}</Text>
|
|
426
|
-
</Box>
|
|
427
|
-
)}
|
|
428
408
|
<PluginSlot name="status:widget" />
|
|
429
409
|
</>
|
|
430
410
|
);
|
|
@@ -87,9 +87,32 @@ function parseLine(line: string): ParsedLine {
|
|
|
87
87
|
return { segments: parseInlineMarkdown(line) };
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
function
|
|
90
|
+
function wrappedTextStyle() {
|
|
91
|
+
return {
|
|
92
|
+
minWidth: 0,
|
|
93
|
+
whiteSpace: "pre-wrap",
|
|
94
|
+
overflowWrap: "anywhere",
|
|
95
|
+
} as const;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function wrappedInlineTextStyle() {
|
|
99
|
+
return {
|
|
100
|
+
...wrappedTextStyle(),
|
|
101
|
+
display: "inline",
|
|
102
|
+
} as const;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function SegmentSpan({ segment, wrap = false }: { segment: StyledSegment; wrap?: boolean }) {
|
|
106
|
+
const wrapProps = wrap
|
|
107
|
+
? {
|
|
108
|
+
wrapText: true,
|
|
109
|
+
wrapMode: "word",
|
|
110
|
+
style: wrappedInlineTextStyle(),
|
|
111
|
+
}
|
|
112
|
+
: {};
|
|
113
|
+
|
|
91
114
|
if (segment.code) {
|
|
92
|
-
return <Span fg={colors.textDim}>{segment.text}</Span>;
|
|
115
|
+
return <Span fg={colors.textDim} {...wrapProps}>{segment.text}</Span>;
|
|
93
116
|
}
|
|
94
117
|
const attrs =
|
|
95
118
|
(segment.bold ? TextAttributes.BOLD : 0) |
|
|
@@ -99,6 +122,7 @@ function SegmentSpan({ segment }: { segment: StyledSegment }) {
|
|
|
99
122
|
<Span
|
|
100
123
|
fg={segment.color ?? undefined}
|
|
101
124
|
attributes={attrs || undefined}
|
|
125
|
+
{...wrapProps}
|
|
102
126
|
>
|
|
103
127
|
{segment.text}
|
|
104
128
|
</Span>
|
|
@@ -124,6 +148,15 @@ function MarkdownLine({
|
|
|
124
148
|
}) {
|
|
125
149
|
const indent = parsed.indent ?? 0;
|
|
126
150
|
const indentStr = indent > 0 ? " ".repeat(indent) : "";
|
|
151
|
+
const shouldWrap = lineWidth != null;
|
|
152
|
+
const textWrapProps = shouldWrap
|
|
153
|
+
? {
|
|
154
|
+
width: lineWidth,
|
|
155
|
+
wrapText: true,
|
|
156
|
+
wrapMode: "word",
|
|
157
|
+
style: wrappedTextStyle(),
|
|
158
|
+
}
|
|
159
|
+
: {};
|
|
127
160
|
|
|
128
161
|
// Check if any segment contains ticker symbols
|
|
129
162
|
const fullText = parsed.segments.map((s) => s.text).join("");
|
|
@@ -133,10 +166,10 @@ function MarkdownLine({
|
|
|
133
166
|
if (!hasTickers) {
|
|
134
167
|
// Simple case: no tickers, render as styled text
|
|
135
168
|
return (
|
|
136
|
-
<Text fg={textColor}>
|
|
169
|
+
<Text fg={textColor} {...textWrapProps}>
|
|
137
170
|
{indentStr}
|
|
138
171
|
{parsed.segments.map((segment, i) => (
|
|
139
|
-
<SegmentSpan key={i} segment={segment} />
|
|
172
|
+
<SegmentSpan key={i} segment={segment} wrap={shouldWrap} />
|
|
140
173
|
))}
|
|
141
174
|
</Text>
|
|
142
175
|
);
|
|
@@ -153,16 +186,28 @@ function MarkdownLine({
|
|
|
153
186
|
if (token.kind === "text") {
|
|
154
187
|
if (!token.value) return null;
|
|
155
188
|
return (
|
|
156
|
-
<Text
|
|
157
|
-
|
|
189
|
+
<Text
|
|
190
|
+
key={`${segIdx}:${tokIdx}`}
|
|
191
|
+
fg={textColor}
|
|
192
|
+
{...(shouldWrap
|
|
193
|
+
? { wrapText: true, wrapMode: "word", style: wrappedTextStyle() }
|
|
194
|
+
: {})}
|
|
195
|
+
>
|
|
196
|
+
<SegmentSpan segment={{ ...segment, text: token.value }} wrap={shouldWrap} />
|
|
158
197
|
</Text>
|
|
159
198
|
);
|
|
160
199
|
}
|
|
161
200
|
const entry = catalog[token.symbol];
|
|
162
201
|
if (!entry || entry.status === "missing") {
|
|
163
202
|
return (
|
|
164
|
-
<Text
|
|
165
|
-
|
|
203
|
+
<Text
|
|
204
|
+
key={`${segIdx}:${tokIdx}`}
|
|
205
|
+
fg={textColor}
|
|
206
|
+
{...(shouldWrap
|
|
207
|
+
? { wrapText: true, wrapMode: "word", style: wrappedTextStyle() }
|
|
208
|
+
: {})}
|
|
209
|
+
>
|
|
210
|
+
<SegmentSpan segment={{ ...segment, text: token.value }} wrap={shouldWrap} />
|
|
166
211
|
</Text>
|
|
167
212
|
);
|
|
168
213
|
}
|
|
@@ -12,6 +12,7 @@ import { resolveBrokerConfigFields, type BrokerAdapter, type BrokerConfigField }
|
|
|
12
12
|
import { buildBrokerProfileConfig, validateBrokerProfileValues } from "../../brokers/profile-form";
|
|
13
13
|
import { createBrokerInstanceId } from "../../utils/broker-instances";
|
|
14
14
|
import { isBackNavigationKey, isPlainEscape } from "../../utils/back-navigation";
|
|
15
|
+
import { isPlainKey } from "../../utils/keyboard";
|
|
15
16
|
import { detectShortcutPlatform, formatPrimaryShortcut, getShortcutDisplayMode } from "../../utils/shortcut-labels";
|
|
16
17
|
import { syncBrokerInstance } from "../../brokers/sync-broker-instance";
|
|
17
18
|
import { debugLog } from "../../utils/debug-log";
|
|
@@ -528,24 +529,24 @@ export function OnboardingWizard({ config, pluginRegistry, onComplete }: Onboard
|
|
|
528
529
|
|
|
529
530
|
// --- Step-specific controls ---
|
|
530
531
|
if (step === "theme") {
|
|
531
|
-
if (event
|
|
532
|
+
if (isPlainKey(event, "up", "k")) {
|
|
532
533
|
setThemeIdx((i) => Math.max(0, i - 1));
|
|
533
|
-
} else if (event
|
|
534
|
+
} else if (isPlainKey(event, "down", "j")) {
|
|
534
535
|
setThemeIdx((i) => Math.min(themeIds.length - 1, i + 1));
|
|
535
536
|
}
|
|
536
537
|
} else if (step === "portfolio" && portfolioSub === "choose") {
|
|
537
|
-
if (event
|
|
538
|
+
if (isPlainKey(event, "up", "k")) {
|
|
538
539
|
setPortfolioOptionIdx((i) => Math.max(0, i - 1));
|
|
539
|
-
} else if (event
|
|
540
|
+
} else if (isPlainKey(event, "down", "j")) {
|
|
540
541
|
setPortfolioOptionIdx((i) => Math.min(portfolioChoices.length - 1, i + 1));
|
|
541
542
|
}
|
|
542
543
|
} else if (step === "portfolio" && portfolioSub === "broker-fields" && selectedBrokerId) {
|
|
543
544
|
const currentField = activeBrokerFields[brokerFieldIdx];
|
|
544
545
|
if (currentField?.type === "select") {
|
|
545
546
|
const optionCount = currentField.options?.length ?? 0;
|
|
546
|
-
if (event
|
|
547
|
+
if (isPlainKey(event, "up", "k")) {
|
|
547
548
|
setBrokerSelectIdx((index) => Math.max(0, index - 1));
|
|
548
|
-
} else if (event
|
|
549
|
+
} else if (isPlainKey(event, "down", "j")) {
|
|
549
550
|
setBrokerSelectIdx((index) => Math.min(optionCount - 1, index + 1));
|
|
550
551
|
}
|
|
551
552
|
}
|
|
@@ -10,6 +10,7 @@ import type {
|
|
|
10
10
|
} from "../types/plugin";
|
|
11
11
|
import type { PluginRegistry } from "../plugins/registry";
|
|
12
12
|
import { blendHex, colors } from "../theme/colors";
|
|
13
|
+
import { isPlainKey } from "../utils/keyboard";
|
|
13
14
|
import { Button, DialogFrame, ListView, MultiSelectDialogContent, TextField } from "./ui";
|
|
14
15
|
import { NativeSelect, openNativeSelect, type NativeSelectElement } from "./ui/native-select";
|
|
15
16
|
|
|
@@ -167,7 +168,9 @@ function DesktopSwitch({
|
|
|
167
168
|
style={{
|
|
168
169
|
border: `1px solid ${checked ? colors.borderFocused : colors.border}`,
|
|
169
170
|
borderRadius: 999,
|
|
170
|
-
boxShadow: checked
|
|
171
|
+
boxShadow: checked
|
|
172
|
+
? `inset 0 1px 0 ${blendHex(colors.selected, colors.textBright, 0.1)}`
|
|
173
|
+
: `inset 0 1px 0 ${blendHex(colors.bg, colors.textBright, 0.05)}`,
|
|
171
174
|
cursor: "pointer",
|
|
172
175
|
paddingInline: 2,
|
|
173
176
|
}}
|
|
@@ -178,7 +181,7 @@ function DesktopSwitch({
|
|
|
178
181
|
backgroundColor={checked ? colors.selectedText : colors.textMuted}
|
|
179
182
|
style={{
|
|
180
183
|
borderRadius: 999,
|
|
181
|
-
boxShadow:
|
|
184
|
+
boxShadow: `0 1px 2px ${blendHex(colors.panel, colors.bg, 0.35)}`,
|
|
182
185
|
}}
|
|
183
186
|
/>
|
|
184
187
|
</Box>
|
|
@@ -333,8 +336,8 @@ function useSelectFieldDialogController({
|
|
|
333
336
|
|
|
334
337
|
useDialogKeyboard((event) => {
|
|
335
338
|
event.stopPropagation();
|
|
336
|
-
if (event
|
|
337
|
-
else if (event
|
|
339
|
+
if (isPlainKey(event, "up", "k")) setSelectedIndex((index) => Math.max(0, index - 1));
|
|
340
|
+
else if (isPlainKey(event, "down", "j")) setSelectedIndex((index) => Math.min(field.options.length - 1, index + 1));
|
|
338
341
|
else if (event.name === "escape") dismiss();
|
|
339
342
|
else if (event.name === "enter" || event.name === "return" || isSpaceKey(event)) {
|
|
340
343
|
const option = field.options[selectedIndex];
|
|
@@ -716,8 +719,8 @@ export function PaneSettingsDialogContent({
|
|
|
716
719
|
|
|
717
720
|
useDialogKeyboard((event) => {
|
|
718
721
|
event.stopPropagation();
|
|
719
|
-
if (event
|
|
720
|
-
else if (event
|
|
722
|
+
if (isPlainKey(event, "up", "k")) setSelectedIndex((index) => Math.max(0, index - 1));
|
|
723
|
+
else if (isPlainKey(event, "down", "j")) setSelectedIndex((index) => Math.min(fields.length - 1, index + 1));
|
|
721
724
|
else if (event.name === "escape") dismiss();
|
|
722
725
|
else if (event.name === "enter" || event.name === "return" || isSpaceKey(event)) {
|
|
723
726
|
void openFieldEditor(fields[selectedIndex]).catch(() => {});
|
|
@@ -4,6 +4,7 @@ import { type InputRenderable, type TextareaRenderable } from "../ui";
|
|
|
4
4
|
import { type AlertContext, type PromptContext, useDialogKeyboard } from "../ui/dialog";
|
|
5
5
|
import type { WizardStep } from "../types/plugin";
|
|
6
6
|
import { colors } from "../theme/colors";
|
|
7
|
+
import { isPlainKey } from "../utils/keyboard";
|
|
7
8
|
import { DialogFrame, ListView, TextField } from "./ui";
|
|
8
9
|
|
|
9
10
|
export function PaneTemplateInfoStep({
|
|
@@ -165,9 +166,9 @@ export function PaneTemplateSelectStep({
|
|
|
165
166
|
|
|
166
167
|
useDialogKeyboard((event) => {
|
|
167
168
|
event.stopPropagation();
|
|
168
|
-
if (event
|
|
169
|
+
if (isPlainKey(event, "up", "k")) {
|
|
169
170
|
setSelectedIndex((index) => Math.max(0, index - 1));
|
|
170
|
-
} else if (event
|
|
171
|
+
} else if (isPlainKey(event, "down", "j")) {
|
|
171
172
|
setSelectedIndex((index) => Math.min(options.length - 1, index + 1));
|
|
172
173
|
} else if (event.name === "return" || event.name === "enter") {
|
|
173
174
|
resolve(options[selectedIndex]?.value ?? "");
|
|
@@ -8,6 +8,7 @@ import { colors } from "../theme/colors";
|
|
|
8
8
|
import { formatMarketPrice } from "../utils/market-format";
|
|
9
9
|
import { DialogFrame, ListView, NumberField } from "./ui";
|
|
10
10
|
import { padTo } from "../utils/format";
|
|
11
|
+
import { isPlainKey } from "../utils/keyboard";
|
|
11
12
|
|
|
12
13
|
interface PricePreset {
|
|
13
14
|
label: string;
|
|
@@ -98,9 +99,9 @@ export function PriceSelectorDialog({
|
|
|
98
99
|
}
|
|
99
100
|
|
|
100
101
|
if (mode === "list") {
|
|
101
|
-
if (event
|
|
102
|
+
if (isPlainKey(event, "up", "k")) {
|
|
102
103
|
setIndex((current) => Math.max(0, current - 1));
|
|
103
|
-
} else if (event
|
|
104
|
+
} else if (isPlainKey(event, "down", "j")) {
|
|
104
105
|
if (index < presets.length - 1) {
|
|
105
106
|
setIndex((current) => current + 1);
|
|
106
107
|
} else {
|