gloomberb 0.16.2 → 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/package.json +1 -1
- package/src/brokers/account-cache.ts +45 -0
- package/src/cli/command-options.ts +74 -0
- package/src/cli/commands/command-utils.ts +29 -0
- package/src/cli/commands/market.ts +170 -54
- package/src/cli/commands/overview.ts +62 -19
- package/src/cli/commands/ticker.ts +138 -43
- package/src/cli/desktop-pane-shot.ts +3 -0
- package/src/cli/help.ts +26 -6
- package/src/cli/history-rows.ts +187 -15
- package/src/cli/index.ts +12 -7
- package/src/cli/options.ts +5 -1
- package/src/cli/pane-functions/capabilities.ts +5 -0
- package/src/cli/pane-functions/dom.ts +69 -16
- package/src/cli/pane-functions/function-help.ts +4 -2
- package/src/cli/pane-functions/headless.ts +163 -31
- package/src/cli/pane-functions/index.ts +9 -2
- package/src/cli/pane-functions/report.ts +8 -1
- package/src/cli/pane-functions/resolver.ts +28 -2
- package/src/cli/pane-functions/screenshot.ts +4 -0
- package/src/cli/registry.ts +6 -3
- package/src/cli/report-tables.ts +460 -0
- package/src/cli/result.ts +13 -3
- package/src/components/data-table/export.ts +6 -51
- package/src/components/data-table/view.tsx +3 -1
- 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/native/pointer-runtime.ts +13 -13
- package/src/components/layout/shell/native/surfaces.ts +30 -14
- package/src/components/layout/shell/pane/layers.tsx +419 -179
- package/src/components/layout/shell/terminal-pointer-runtime.ts +18 -18
- package/src/components/layout/shell/window-mode/overlays.tsx +12 -4
- 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/market-data/market/freshness.ts +45 -0
- package/src/market-data/quotes/freshness.ts +5 -0
- package/src/plugins/builtin/analytics/pane-model.ts +10 -6
- package/src/plugins/builtin/attention/pane.tsx +1 -1
- package/src/plugins/builtin/catalysts/detail.tsx +1 -1
- package/src/plugins/builtin/company-attention/pane.tsx +1 -1
- 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 +26 -5
- package/src/plugins/builtin/holders/pane.tsx +22 -13
- package/src/plugins/builtin/holders/report-header.ts +46 -5
- package/src/plugins/builtin/kelly-sizer/pane.tsx +12 -6
- package/src/plugins/builtin/kelly-sizer/portfolio.ts +25 -0
- package/src/plugins/builtin/members/pane.tsx +10 -0
- package/src/plugins/builtin/perps/pane.tsx +1 -1
- package/src/plugins/builtin/portfolio-list/account-metrics.ts +16 -1
- package/src/plugins/builtin/portfolio-list/allocation.ts +3 -0
- package/src/plugins/builtin/portfolio-list/cached-account.ts +18 -9
- package/src/plugins/builtin/portfolio-list/cli/render.ts +2 -0
- package/src/plugins/builtin/portfolio-list/headless.ts +2 -0
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +7 -4
- package/src/plugins/builtin/portfolio-list/summary/index.tsx +22 -4
- package/src/plugins/builtin/portfolio-list/summary/live-accounts.ts +11 -1
- package/src/plugins/builtin/research/relative-valuation-model.ts +7 -3
- package/src/plugins/builtin/reverse-dcf/model.ts +2 -1
- package/src/plugins/builtin/shared/members-menu.tsx +260 -0
- package/src/plugins/builtin/short-volume/pane.tsx +1 -1
- package/src/plugins/builtin/social-mentions/pane.tsx +1 -1
- package/src/plugins/builtin/themes/pane.tsx +3 -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 +20 -4
- package/src/plugins/builtin/ticker-detail/overview/model.ts +9 -4
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +3 -2
- package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +2 -0
- package/src/plugins/builtin/world-venue-map/basemap.ts +18 -0
- package/src/plugins/builtin/world-venue-map/country-labels.ts +78 -0
- package/src/plugins/builtin/world-venue-map/geo-svg.tsx +2 -1
- package/src/plugins/builtin/world-venue-map/index.ts +5 -5
- package/src/plugins/builtin/world-venue-map/layered-pane.tsx +27 -14
- package/src/plugins/builtin/world-venue-map/layers.ts +68 -10
- package/src/plugins/builtin/world-venue-map/map.tsx +198 -62
- package/src/plugins/builtin/world-venue-map/model.ts +16 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/index.chunk.ts +3 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/labels.chunk.ts +244 -0
- package/src/plugins/builtin/world-venue-map/pane.tsx +16 -10
- package/src/renderers/browser/app-services.ts +3 -1
- package/src/renderers/dom/data-table/dom.ts +31 -0
- package/src/renderers/dom/data-table/index.tsx +5 -0
- package/src/renderers/dom/host/box.tsx +113 -17
- package/src/renderers/dom/host/drag-shield.ts +24 -0
- 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 +13 -5
- 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/cli-pane-shot-entry.tsx +3 -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/ui-host.tsx +2 -5
- package/src/renderers/opentui/ui-host.tsx +7 -1
- package/src/sources/gloomberb-cloud/normalizers.ts +16 -20
- package/src/sources/provider-router/batches.ts +3 -3
- package/src/sources/provider-router/financial-routes.ts +2 -2
- package/src/sources/provider-router/financials.ts +70 -7
- package/src/sources/provider-router/primary.ts +2 -2
- package/src/state/pane-scroll-registry.tsx +67 -35
- package/src/test-support/margin-account.ts +108 -0
- package/src/time-series/resolution.ts +15 -0
- package/src/types/financials.ts +32 -3
- package/src/ui/host.tsx +12 -0
- package/src/ui/index.tsx +8 -3
- package/src/ui/scroll-box-axis.ts +26 -0
- package/src/utils/currency-units.ts +8 -3
- package/src/utils/depositary-receipt.ts +54 -10
- package/src/utils/display-number.ts +63 -0
- package/src/utils/fundamentals.ts +17 -1
- package/src/utils/price-history-integrity.ts +19 -6
|
@@ -6,7 +6,6 @@ import {
|
|
|
6
6
|
type MutableRefObject,
|
|
7
7
|
type SetStateAction,
|
|
8
8
|
} from "react";
|
|
9
|
-
import { useRafCallback } from "../../../../react/use-raf-callback";
|
|
10
9
|
import {
|
|
11
10
|
type DockDividerLayout,
|
|
12
11
|
type DockGeometryOptions,
|
|
@@ -24,6 +23,7 @@ import {
|
|
|
24
23
|
} from "./index";
|
|
25
24
|
import type { ActionMenuState } from "../action-menu-overlay";
|
|
26
25
|
import type { DividerPreviewState } from "../native/window-state";
|
|
26
|
+
import { createLiveDragStore, IDLE_DRAG, type LiveDragStore } from "./live";
|
|
27
27
|
import type { WindowEditState } from "../../window-edit/mode";
|
|
28
28
|
import { useShellActiveDrag } from "../active-drag";
|
|
29
29
|
import { useShellNativePointerRuntime } from "../native/pointer-runtime";
|
|
@@ -58,6 +58,9 @@ export interface ShellMouseEvent {
|
|
|
58
58
|
button?: number;
|
|
59
59
|
preciseX?: number;
|
|
60
60
|
preciseY?: number;
|
|
61
|
+
/** Desktop: where the browser predicts the pointer a moment later, for drawing only. */
|
|
62
|
+
predictedX?: number;
|
|
63
|
+
predictedY?: number;
|
|
61
64
|
/** Whether a later handler has claimed this pointer interaction. */
|
|
62
65
|
isDefaultPrevented?: () => boolean;
|
|
63
66
|
stopPropagation: () => void;
|
|
@@ -71,88 +74,97 @@ export interface VisibleFloatingPane {
|
|
|
71
74
|
|
|
72
75
|
export interface ShellDragRuntimeState {
|
|
73
76
|
cancelActiveDrag: () => void;
|
|
74
|
-
dividerPreview: DividerPreviewState | null;
|
|
75
|
-
dividerPreviewRef: MutableRefObject<DividerPreviewState | null>;
|
|
76
|
-
dockPreview: DragPreview | null;
|
|
77
|
-
dockPreviewRef: MutableRefObject<DragPreview | null>;
|
|
78
|
-
dragCursor: { x: number; y: number } | null;
|
|
79
|
-
dragFloatingRect: { paneId: string; rect: FloatingRect } | null;
|
|
80
77
|
dragRef: MutableRefObject<DragMode | null>;
|
|
81
78
|
hasActiveDrag: () => boolean;
|
|
82
|
-
|
|
79
|
+
/** Positions that follow the pointer, outside React state. */
|
|
80
|
+
live: LiveDragStore;
|
|
81
|
+
/** The tiled pane whose drop grid is under the pointer. */
|
|
82
|
+
setHoverTarget: (targetId: string | null) => void;
|
|
83
|
+
startDrag: (drag: DragMode) => void;
|
|
83
84
|
updateDividerPreview: (next: DividerPreviewState | null) => void;
|
|
84
85
|
updateDockPreview: (next: DragPreview | null) => void;
|
|
85
86
|
updateDragFloatingRect: (next: { paneId: string; rect: FloatingRect } | null) => void;
|
|
86
87
|
}
|
|
87
88
|
|
|
89
|
+
function sameRect(a: LayoutBounds, b: LayoutBounds): boolean {
|
|
90
|
+
return a.x === b.x && a.y === b.y && a.width === b.width && a.height === b.height;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function sameDragPreview(a: DragPreview | null, b: DragPreview | null): boolean {
|
|
94
|
+
if (a === b) return true;
|
|
95
|
+
if (!a || !b || a.kind !== b.kind || !sameRect(a.rect, b.rect)) return false;
|
|
96
|
+
if (a.kind === "snap" && b.kind === "snap") return a.position === b.position;
|
|
97
|
+
if (a.kind === "dock" && b.kind === "dock") {
|
|
98
|
+
const [x, y] = [a.target, b.target];
|
|
99
|
+
if (x.kind === "frame" && y.kind === "frame") return x.edge === y.edge;
|
|
100
|
+
if (x.kind === "leaf" && y.kind === "leaf") return x.targetId === y.targetId && x.position === y.position;
|
|
101
|
+
}
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
|
|
88
105
|
export function useShellDragRuntimeState({
|
|
89
106
|
contentHeight,
|
|
90
|
-
|
|
107
|
+
nativePaneChrome,
|
|
91
108
|
width,
|
|
92
109
|
}: {
|
|
93
110
|
contentHeight: number;
|
|
94
|
-
|
|
111
|
+
nativePaneChrome: boolean;
|
|
95
112
|
width: number;
|
|
96
113
|
}): ShellDragRuntimeState {
|
|
97
114
|
const dragRef = useRef<DragMode | null>(null);
|
|
98
|
-
const [
|
|
99
|
-
const pendingDragFloatingRectRef = useRef<{ paneId: string; rect: FloatingRect } | null>(null);
|
|
100
|
-
const [dragCursor, setDragCursor] = useState<{ x: number; y: number } | null>(null);
|
|
101
|
-
const [dividerPreview, setDividerPreview] = useState<DividerPreviewState | null>(null);
|
|
102
|
-
const [dockPreview, setDockPreview] = useState<DragPreview | null>(null);
|
|
103
|
-
const dividerPreviewRef = useRef<DividerPreviewState | null>(null);
|
|
104
|
-
const dockPreviewRef = useRef<DragPreview | null>(null);
|
|
105
|
-
const flushDragFloatingRect = useRafCallback(() => {
|
|
106
|
-
setDragFloatingRect(pendingDragFloatingRectRef.current);
|
|
107
|
-
});
|
|
115
|
+
const [live] = useState(createLiveDragStore);
|
|
108
116
|
|
|
109
117
|
const updateDragFloatingRect = useCallback((next: { paneId: string; rect: FloatingRect } | null) => {
|
|
110
|
-
const
|
|
118
|
+
const current = live.get();
|
|
119
|
+
const floating = next
|
|
111
120
|
? { paneId: next.paneId, rect: constrainFloatingRectToBounds(next.rect, width, contentHeight) }
|
|
112
121
|
: null;
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
122
|
+
// A desktop pane on the move follows by restyling itself (`move`); its
|
|
123
|
+
// start and end, a resize and every terminal frame redraw through React.
|
|
124
|
+
const follows = nativePaneChrome
|
|
125
|
+
&& floating !== null
|
|
126
|
+
&& current.floating?.paneId === floating.paneId
|
|
127
|
+
&& current.paneDrag?.paneId === floating.paneId;
|
|
128
|
+
if (follows) live.move({ floating });
|
|
129
|
+
else live.set({ floating });
|
|
130
|
+
}, [contentHeight, live, nativePaneChrome, width]);
|
|
131
|
+
|
|
132
|
+
const setHoverTarget = useCallback((targetId: string | null) => {
|
|
133
|
+
live.set({ hoverTargetId: targetId });
|
|
134
|
+
}, [live]);
|
|
124
135
|
|
|
125
136
|
const updateDividerPreview = useCallback((next: DividerPreviewState | null) => {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
137
|
+
const current = live.get().divider;
|
|
138
|
+
// The desktop divider follows by restyling itself; React hears only that it started or ended.
|
|
139
|
+
if (nativePaneChrome && next && current?.pathKey === next.pathKey) live.move({ divider: next });
|
|
140
|
+
else live.set({ divider: next });
|
|
141
|
+
}, [live, nativePaneChrome]);
|
|
129
142
|
|
|
130
143
|
const updateDockPreview = useCallback((next: DragPreview | null) => {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
144
|
+
// Recomputed on every move; only a different target is news.
|
|
145
|
+
if (sameDragPreview(live.get().dockPreview, next)) return;
|
|
146
|
+
live.set({ dockPreview: next });
|
|
147
|
+
}, [live]);
|
|
148
|
+
|
|
149
|
+
const startDrag = useCallback((drag: DragMode) => {
|
|
150
|
+
dragRef.current = drag;
|
|
151
|
+
live.set({ paneDrag: drag.type === "pane-drag" ? { paneId: drag.paneId, mode: drag.mode } : null });
|
|
152
|
+
}, [live]);
|
|
134
153
|
|
|
135
154
|
const cancelActiveDrag = useCallback(() => {
|
|
136
155
|
dragRef.current = null;
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
updateDividerPreview(null);
|
|
140
|
-
updateDockPreview(null);
|
|
141
|
-
}, [updateDividerPreview, updateDockPreview, updateDragFloatingRect]);
|
|
156
|
+
live.set(IDLE_DRAG);
|
|
157
|
+
}, [live]);
|
|
142
158
|
|
|
143
159
|
const hasActiveDrag = useCallback(() => dragRef.current != null, []);
|
|
144
160
|
|
|
145
161
|
return {
|
|
146
162
|
cancelActiveDrag,
|
|
147
|
-
dividerPreview,
|
|
148
|
-
dividerPreviewRef,
|
|
149
|
-
dockPreview,
|
|
150
|
-
dockPreviewRef,
|
|
151
|
-
dragCursor,
|
|
152
|
-
dragFloatingRect,
|
|
153
163
|
dragRef,
|
|
154
164
|
hasActiveDrag,
|
|
155
|
-
|
|
165
|
+
live,
|
|
166
|
+
setHoverTarget,
|
|
167
|
+
startDrag,
|
|
156
168
|
updateDividerPreview,
|
|
157
169
|
updateDockPreview,
|
|
158
170
|
updateDragFloatingRect,
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { CSSProperties } from "react";
|
|
2
|
+
import { WEB_CELL_HEIGHT, WEB_CELL_WIDTH } from "../../../../theme/font-scale";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Desktop: draws a box laid out at the shell's corner at cell (x, y) with a
|
|
6
|
+
* transform, so placing it somewhere else never lays anything out.
|
|
7
|
+
*/
|
|
8
|
+
export function placeStyle(x: number, y: number): CSSProperties {
|
|
9
|
+
return { transform: `translate3d(${x * WEB_CELL_WIDTH}px, ${y * WEB_CELL_HEIGHT}px, 0)` };
|
|
10
|
+
}
|
|
@@ -41,11 +41,10 @@ import { tickerLinkMenuItems } from "./ticker-link-menu";
|
|
|
41
41
|
import {
|
|
42
42
|
makeSnapGuides,
|
|
43
43
|
resolveExternalDockPreview,
|
|
44
|
-
resolveHoverOverlay,
|
|
45
44
|
} from "./drag";
|
|
46
45
|
import { resolveAppHeaderHeightCells } from "./chrome";
|
|
47
46
|
import { useShellWindowMode } from "./window-mode";
|
|
48
|
-
import {
|
|
47
|
+
import { ShellNativeSurfaceSync } from "./native/surfaces";
|
|
49
48
|
import { ShellWindowModeOverlays } from "./window-mode/overlays";
|
|
50
49
|
import { ShellPaneLayers } from "./pane/layers";
|
|
51
50
|
import { paneMenuButtonAnchor, ShellActionMenuOverlay, type ActionMenuState } from "./action-menu-overlay";
|
|
@@ -134,10 +133,6 @@ export function Shell({
|
|
|
134
133
|
const layout = useAppSelector((state) => state.config.layout);
|
|
135
134
|
const dialogOpen = useDialogState((dialog) => dialog.isOpen);
|
|
136
135
|
const [hoveredPaneId, setHoveredPaneId] = useState<string | null>(null);
|
|
137
|
-
const setHoveredPaneIfChanged = useCallback((paneId: string | null) => {
|
|
138
|
-
if (commandBarOpen) return;
|
|
139
|
-
setHoveredPaneId((current) => (current === paneId ? current : paneId));
|
|
140
|
-
}, [commandBarOpen]);
|
|
141
136
|
const [menuState, setMenuState] = useState<ActionMenuState | null>(null);
|
|
142
137
|
const [transientFocusLayoutState, setTransientFocusLayoutState] = useState<TransientFocusLayoutState | null>(null);
|
|
143
138
|
const transientFocusLayoutStateRef = useRef<TransientFocusLayoutState | null>(null);
|
|
@@ -165,21 +160,20 @@ export function Shell({
|
|
|
165
160
|
if (commandBarOpen) setHoveredPaneId(null);
|
|
166
161
|
}, [commandBarOpen]);
|
|
167
162
|
|
|
168
|
-
const dragRuntime = useShellDragRuntimeState({
|
|
169
|
-
contentHeight,
|
|
170
|
-
throttleFloatingPreview: nativePaneChrome,
|
|
171
|
-
width,
|
|
172
|
-
});
|
|
163
|
+
const dragRuntime = useShellDragRuntimeState({ contentHeight, nativePaneChrome, width });
|
|
173
164
|
const {
|
|
174
165
|
cancelActiveDrag,
|
|
175
|
-
dividerPreview,
|
|
176
|
-
dockPreview,
|
|
177
|
-
dragCursor,
|
|
178
|
-
dragFloatingRect,
|
|
179
|
-
dragRef,
|
|
180
166
|
hasActiveDrag,
|
|
167
|
+
live,
|
|
181
168
|
} = dragRuntime;
|
|
182
169
|
|
|
170
|
+
// A pane dragged across other headers is not hovering them: re-rendering
|
|
171
|
+
// the layout for their menu buttons would only cost frames.
|
|
172
|
+
const setHoveredPaneIfChanged = useCallback((paneId: string | null) => {
|
|
173
|
+
if (commandBarOpen || hasActiveDrag()) return;
|
|
174
|
+
setHoveredPaneId((current) => (current === paneId ? current : paneId));
|
|
175
|
+
}, [commandBarOpen, hasActiveDrag]);
|
|
176
|
+
|
|
183
177
|
const { disabledPaneIds, visibleLayout } = useShellVisibleLayout({
|
|
184
178
|
disabledPlugins: config.disabledPlugins,
|
|
185
179
|
layout,
|
|
@@ -261,9 +255,10 @@ export function Shell({
|
|
|
261
255
|
pluginRegistry,
|
|
262
256
|
width,
|
|
263
257
|
});
|
|
264
|
-
|
|
258
|
+
// Read when the terminal draws a frame, so a pane on the move is covered where it is now.
|
|
259
|
+
const resolveCursorOcclusionRects = useCallback(() => resolveShellCursorOcclusionRects({
|
|
265
260
|
contentHeight,
|
|
266
|
-
dragFloatingRect,
|
|
261
|
+
dragFloatingRect: live.get().floating,
|
|
267
262
|
nativePaneChrome,
|
|
268
263
|
overlayOpen,
|
|
269
264
|
transientFocusActive,
|
|
@@ -271,7 +266,7 @@ export function Shell({
|
|
|
271
266
|
width,
|
|
272
267
|
}), [
|
|
273
268
|
contentHeight,
|
|
274
|
-
|
|
269
|
+
live,
|
|
275
270
|
nativePaneChrome,
|
|
276
271
|
overlayOpen,
|
|
277
272
|
transientFocusActive,
|
|
@@ -279,7 +274,7 @@ export function Shell({
|
|
|
279
274
|
width,
|
|
280
275
|
]);
|
|
281
276
|
useShellCursorOcclusionGuard({
|
|
282
|
-
|
|
277
|
+
resolveOcclusionRects: resolveCursorOcclusionRects,
|
|
283
278
|
shellRef,
|
|
284
279
|
});
|
|
285
280
|
|
|
@@ -460,29 +455,6 @@ export function Shell({
|
|
|
460
455
|
() => resolveExternalDockPreview(desktopDockPreview, bounds),
|
|
461
456
|
[bounds, desktopDockPreview],
|
|
462
457
|
);
|
|
463
|
-
const activePaneDrag = dragRef.current?.type === "pane-drag" ? dragRef.current : null;
|
|
464
|
-
const activeHoverOverlay = activePaneDrag && dragCursor
|
|
465
|
-
? resolveHoverOverlay(dragCursor.x, dragCursor.y, dockLeafLayouts, activePaneDrag.paneId)
|
|
466
|
-
: null;
|
|
467
|
-
const effectiveDockPreview = dockPreview ?? externalDockPreview;
|
|
468
|
-
useShellNativeSurfaceWindowState({
|
|
469
|
-
activeHoverOverlay,
|
|
470
|
-
activePaneDrag,
|
|
471
|
-
appHeaderHeight,
|
|
472
|
-
commandBarNativeOccluder,
|
|
473
|
-
contentHeight,
|
|
474
|
-
dialogOpen,
|
|
475
|
-
dividerPreview,
|
|
476
|
-
dockDividerLayouts: screenDividerLayouts,
|
|
477
|
-
dockedPanes: screenDockedPanes,
|
|
478
|
-
dragFloatingRect,
|
|
479
|
-
effectiveDockPreview,
|
|
480
|
-
menuState,
|
|
481
|
-
nativeWindowModePanelRect,
|
|
482
|
-
visibleFloatingPanes: screenFloatingPanes,
|
|
483
|
-
width,
|
|
484
|
-
windowModeDockMovePreview,
|
|
485
|
-
});
|
|
486
458
|
|
|
487
459
|
const titleState = useMemo(
|
|
488
460
|
() => ({ config, paneState }) as Parameters<typeof resolveTickerForPane>[0],
|
|
@@ -824,12 +796,27 @@ export function Shell({
|
|
|
824
796
|
</Box>
|
|
825
797
|
</Box>
|
|
826
798
|
|
|
799
|
+
<ShellNativeSurfaceSync
|
|
800
|
+
appHeaderHeight={appHeaderHeight}
|
|
801
|
+
commandBarNativeOccluder={commandBarNativeOccluder}
|
|
802
|
+
contentHeight={contentHeight}
|
|
803
|
+
dialogOpen={dialogOpen}
|
|
804
|
+
dockDividerLayouts={screenDividerLayouts}
|
|
805
|
+
dockedPanes={screenDockedPanes}
|
|
806
|
+
dockLeafLayouts={dockLeafLayouts}
|
|
807
|
+
externalDockPreview={externalDockPreview}
|
|
808
|
+
live={live}
|
|
809
|
+
menuState={menuState}
|
|
810
|
+
nativeWindowModePanelRect={nativeWindowModePanelRect}
|
|
811
|
+
visibleFloatingPanes={screenFloatingPanes}
|
|
812
|
+
width={width}
|
|
813
|
+
windowModeDockMovePreview={windowModeDockMovePreview}
|
|
814
|
+
/>
|
|
815
|
+
|
|
827
816
|
<ShellPaneLayers
|
|
828
817
|
contentHeight={contentHeight}
|
|
829
|
-
dividerPreview={dividerPreview}
|
|
830
818
|
dockDividerLayouts={dockDividerLayouts}
|
|
831
819
|
dockLeafLayouts={dockLeafLayouts}
|
|
832
|
-
dragFloatingRect={dragFloatingRect}
|
|
833
820
|
focusedPaneId={focusedPaneId}
|
|
834
821
|
getPaneTitle={getPaneTitle}
|
|
835
822
|
getPaneQuickSettings={getPaneQuickSettings}
|
|
@@ -845,6 +832,7 @@ export function Shell({
|
|
|
845
832
|
handleNativePaneMouseDown={handleNativePaneMouseDown}
|
|
846
833
|
handlePaneAction={handlePaneAction}
|
|
847
834
|
hoveredPaneId={hoveredPaneId}
|
|
835
|
+
live={live}
|
|
848
836
|
menuPaneId={menuState?.paneId ?? null}
|
|
849
837
|
nativeContextMenu={nativeContextMenu}
|
|
850
838
|
nativePaneChrome={nativePaneChrome}
|
|
@@ -868,9 +856,9 @@ export function Shell({
|
|
|
868
856
|
contentHeight={contentHeight}
|
|
869
857
|
dockGeometryOptions={dockGeometryOptions}
|
|
870
858
|
dockLeafLayouts={screenDockLeafLayouts}
|
|
871
|
-
dragFloatingRect={dragFloatingRect}
|
|
872
859
|
focusedPaneId={focusedPaneId}
|
|
873
860
|
getPaneTitle={getPaneTitle}
|
|
861
|
+
live={live}
|
|
874
862
|
menuOpen={!!menuState}
|
|
875
863
|
nativePaneChrome={nativePaneChrome}
|
|
876
864
|
nativeWindowModePanelRect={nativeWindowModePanelRect}
|
|
@@ -883,11 +871,9 @@ export function Shell({
|
|
|
883
871
|
/>
|
|
884
872
|
|
|
885
873
|
<ShellDragOverlays
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
dragFloatingRect={dragFloatingRect}
|
|
890
|
-
effectiveDockPreview={effectiveDockPreview}
|
|
874
|
+
dockLeafLayouts={dockLeafLayouts}
|
|
875
|
+
externalDockPreview={externalDockPreview}
|
|
876
|
+
live={live}
|
|
891
877
|
/>
|
|
892
878
|
|
|
893
879
|
<ShellActionMenuOverlay
|
|
@@ -42,7 +42,7 @@ export function useShellNativePointerRuntime({
|
|
|
42
42
|
commandBarOpen = false,
|
|
43
43
|
}: UseShellNativePointerRuntimeOptions) {
|
|
44
44
|
const {
|
|
45
|
-
|
|
45
|
+
startDrag,
|
|
46
46
|
updateDividerPreview,
|
|
47
47
|
updateDragFloatingRect,
|
|
48
48
|
} = dragRuntime;
|
|
@@ -87,17 +87,17 @@ export function useShellNativePointerRuntime({
|
|
|
87
87
|
|
|
88
88
|
const pointer = getShellPointer(event);
|
|
89
89
|
focusNativePane(paneId);
|
|
90
|
-
|
|
90
|
+
startDrag({
|
|
91
91
|
type: "pane-drag",
|
|
92
92
|
paneId,
|
|
93
93
|
mode: "floating",
|
|
94
94
|
startX: pointer.x,
|
|
95
95
|
startY: pointer.y,
|
|
96
96
|
origRect: { x: rect.x, y: rect.y, width: rect.width, height: rect.height },
|
|
97
|
-
};
|
|
97
|
+
});
|
|
98
98
|
updateDragFloatingRect({ paneId, rect: { x: rect.x, y: rect.y, width: rect.width, height: rect.height } });
|
|
99
99
|
event.preventDefault();
|
|
100
|
-
}, [commandBarOpen,
|
|
100
|
+
}, [commandBarOpen, focusNativePane, getShellPointer, nativePaneChrome, startDrag, transientFocusActive, updateDragFloatingRect, windowMode]);
|
|
101
101
|
|
|
102
102
|
const startNativeDockedDrag = useCallback((paneId: string, rect: LayoutBounds, event: ShellMouseEvent) => {
|
|
103
103
|
if (!nativePaneChrome) return;
|
|
@@ -108,16 +108,16 @@ export function useShellNativePointerRuntime({
|
|
|
108
108
|
|
|
109
109
|
const pointer = getShellPointer(event);
|
|
110
110
|
focusNativePane(paneId);
|
|
111
|
-
|
|
111
|
+
startDrag({
|
|
112
112
|
type: "pane-drag",
|
|
113
113
|
paneId,
|
|
114
114
|
mode: "docked",
|
|
115
115
|
startX: pointer.x,
|
|
116
116
|
startY: pointer.y,
|
|
117
117
|
origRect: { x: rect.x, y: rect.y, width: rect.width, height: rect.height },
|
|
118
|
-
};
|
|
118
|
+
});
|
|
119
119
|
event.preventDefault();
|
|
120
|
-
}, [commandBarOpen,
|
|
120
|
+
}, [commandBarOpen, focusNativePane, getShellPointer, nativePaneChrome, startDrag, transientFocusActive, windowMode]);
|
|
121
121
|
|
|
122
122
|
const startNativeFloatResize = useCallback((paneId: string, rect: FloatingRect, event: ShellMouseEvent) => {
|
|
123
123
|
if (!nativePaneChrome) return;
|
|
@@ -130,17 +130,17 @@ export function useShellNativePointerRuntime({
|
|
|
130
130
|
} else {
|
|
131
131
|
focusNativePane(paneId);
|
|
132
132
|
}
|
|
133
|
-
|
|
133
|
+
startDrag({
|
|
134
134
|
type: "float-resize",
|
|
135
135
|
paneId,
|
|
136
136
|
startX: pointer.x,
|
|
137
137
|
startY: pointer.y,
|
|
138
138
|
origRect: { x: rect.x, y: rect.y, width: rect.width, height: rect.height },
|
|
139
|
-
};
|
|
139
|
+
});
|
|
140
140
|
updateDragFloatingRect({ paneId, rect: { x: rect.x, y: rect.y, width: rect.width, height: rect.height } });
|
|
141
141
|
event.stopPropagation();
|
|
142
142
|
event.preventDefault();
|
|
143
|
-
}, [commandBarOpen,
|
|
143
|
+
}, [commandBarOpen, focusNativePane, getShellPointer, nativePaneChrome, selectWindowModePane, startDrag, transientFocusActive, updateDragFloatingRect, windowMode]);
|
|
144
144
|
|
|
145
145
|
const startNativeDividerDrag = useCallback((divider: DockDividerLayout, event: ShellMouseEvent) => {
|
|
146
146
|
if (!nativePaneChrome) return;
|
|
@@ -152,7 +152,7 @@ export function useShellNativePointerRuntime({
|
|
|
152
152
|
setMenuState(null);
|
|
153
153
|
setHoveredMenuItemId(null);
|
|
154
154
|
}
|
|
155
|
-
|
|
155
|
+
startDrag({
|
|
156
156
|
type: "divider",
|
|
157
157
|
path: divider.path,
|
|
158
158
|
axis: divider.axis,
|
|
@@ -160,7 +160,7 @@ export function useShellNativePointerRuntime({
|
|
|
160
160
|
startY: pointer.y,
|
|
161
161
|
startRatio: divider.ratio,
|
|
162
162
|
bounds: divider.bounds,
|
|
163
|
-
};
|
|
163
|
+
});
|
|
164
164
|
updateDividerPreview({
|
|
165
165
|
pathKey: divider.path.join("."),
|
|
166
166
|
rect: divider.rect,
|
|
@@ -168,7 +168,7 @@ export function useShellNativePointerRuntime({
|
|
|
168
168
|
});
|
|
169
169
|
event.stopPropagation();
|
|
170
170
|
event.preventDefault();
|
|
171
|
-
}, [commandBarOpen,
|
|
171
|
+
}, [commandBarOpen, getShellPointer, menuState, nativePaneChrome, setHoveredMenuItemId, setMenuState, startDrag, transientFocusActive, updateDividerPreview]);
|
|
172
172
|
|
|
173
173
|
const handlePaneAction = useCallback((paneId: string, rect: LayoutBounds, event: ShellMouseEvent) => {
|
|
174
174
|
if (commandBarOpen) return;
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import { useEffect, useMemo } from "react";
|
|
2
2
|
import type {
|
|
3
3
|
DockDividerLayout,
|
|
4
|
+
DockLeafLayout,
|
|
4
5
|
FloatingRect,
|
|
5
6
|
LayoutBounds,
|
|
6
7
|
ResolvedPane,
|
|
7
8
|
} from "../../../../layout/pane-manager";
|
|
8
9
|
import { useNativeRenderer } from "../../../../ui";
|
|
9
10
|
import type { DragPreview } from "../drag";
|
|
11
|
+
import { IDLE_DRAG, useLiveDrag, useLiveHoverOverlay, type LiveDragGeometry, type LiveDragStore } from "../drag/live";
|
|
10
12
|
import {
|
|
11
13
|
buildNativeTransientOccluders,
|
|
12
14
|
buildNativeWindowState,
|
|
13
15
|
resolveNativeDockDividers,
|
|
14
|
-
type DividerPreviewState,
|
|
15
16
|
} from "./window-state";
|
|
16
17
|
import type { WindowEditDockMovePreview } from "../../window-edit/presentation";
|
|
17
18
|
|
|
@@ -24,18 +25,18 @@ interface ShellNativeSurfaceMenuState {
|
|
|
24
25
|
maxRows?: number;
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
interface
|
|
28
|
-
activeHoverOverlay: Parameters<typeof buildNativeTransientOccluders>[0]["activeHoverOverlay"];
|
|
29
|
-
activePaneDrag: { paneId: string; mode: "docked" | "floating" } | null;
|
|
28
|
+
interface ShellNativeSurfaceSyncProps {
|
|
30
29
|
appHeaderHeight: number;
|
|
31
30
|
commandBarNativeOccluder: LayoutBounds | null;
|
|
32
31
|
contentHeight: number;
|
|
33
32
|
dialogOpen: boolean;
|
|
34
|
-
dividerPreview: DividerPreviewState | null;
|
|
35
33
|
dockDividerLayouts: DockDividerLayout[];
|
|
36
34
|
dockedPanes: ResolvedPane[];
|
|
37
|
-
|
|
38
|
-
|
|
35
|
+
/** The tiled panes a moving pane can be dropped on. */
|
|
36
|
+
dockLeafLayouts: DockLeafLayout[];
|
|
37
|
+
/** A pane from another window over this one's edge. */
|
|
38
|
+
externalDockPreview: DragPreview | null;
|
|
39
|
+
live: LiveDragStore;
|
|
39
40
|
menuState: ShellNativeSurfaceMenuState | null;
|
|
40
41
|
nativeWindowModePanelRect: LayoutBounds | null;
|
|
41
42
|
visibleFloatingPanes: Array<{ pane: ResolvedPane; rect: FloatingRect }>;
|
|
@@ -43,26 +44,40 @@ interface UseShellNativeSurfaceWindowStateOptions {
|
|
|
43
44
|
windowModeDockMovePreview: WindowEditDockMovePreview | null;
|
|
44
45
|
}
|
|
45
46
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
const NO_LEAVES: DockLeafLayout[] = [];
|
|
48
|
+
const selectAll = (geometry: LiveDragGeometry) => geometry;
|
|
49
|
+
const selectIdle = () => IDLE_DRAG;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Keeps the native image surfaces clear of the layout. A component of its own,
|
|
53
|
+
* so following a drag redraws nothing but this.
|
|
54
|
+
*/
|
|
55
|
+
export function ShellNativeSurfaceSync({
|
|
49
56
|
appHeaderHeight,
|
|
50
57
|
commandBarNativeOccluder,
|
|
51
58
|
contentHeight,
|
|
52
59
|
dialogOpen,
|
|
53
|
-
dividerPreview,
|
|
54
60
|
dockDividerLayouts,
|
|
55
61
|
dockedPanes,
|
|
56
|
-
|
|
57
|
-
|
|
62
|
+
dockLeafLayouts,
|
|
63
|
+
externalDockPreview,
|
|
64
|
+
live,
|
|
58
65
|
menuState,
|
|
59
66
|
nativeWindowModePanelRect,
|
|
60
67
|
visibleFloatingPanes,
|
|
61
68
|
width,
|
|
62
69
|
windowModeDockMovePreview,
|
|
63
|
-
}:
|
|
70
|
+
}: ShellNativeSurfaceSyncProps): null {
|
|
64
71
|
// Only terminal hosts draw kitty images that need to stay clear of the layout.
|
|
65
72
|
const nativeSurfaceManager = useNativeRenderer().nativeSurfaceManager;
|
|
73
|
+
const {
|
|
74
|
+
paneDrag: activePaneDrag,
|
|
75
|
+
floating: dragFloatingRect,
|
|
76
|
+
divider: dividerPreview,
|
|
77
|
+
dockPreview,
|
|
78
|
+
} = useLiveDrag(live, nativeSurfaceManager ? selectAll : selectIdle);
|
|
79
|
+
const effectiveDockPreview = dockPreview ?? externalDockPreview;
|
|
80
|
+
const activeHoverOverlay = useLiveHoverOverlay(live, nativeSurfaceManager ? dockLeafLayouts : NO_LEAVES);
|
|
66
81
|
const nativeTransientOccluders = useMemo(() => buildNativeTransientOccluders({
|
|
67
82
|
activeHoverOverlay,
|
|
68
83
|
activePaneDrag,
|
|
@@ -124,4 +139,5 @@ export function useShellNativeSurfaceWindowState({
|
|
|
124
139
|
useEffect(() => {
|
|
125
140
|
nativeSurfaceManager?.setWindowState(nativeWindowState);
|
|
126
141
|
}, [nativeSurfaceManager, nativeWindowState]);
|
|
142
|
+
return null;
|
|
127
143
|
}
|