nudge-ui 0.2.0 → 0.2.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/bin/nudge-ui.mjs +3 -1
- package/dist/cli/agentCommand.d.ts +8 -0
- package/dist/cli/agentCommand.js +59 -0
- package/dist/client.mjs +872 -12
- package/dist/hosts/astro/astroRuntimeConfig.js +1 -1
- package/dist/hosts/astro/clientTransport.js +60 -11
- package/dist/hosts/next/sidecar.d.ts +4 -0
- package/dist/hosts/next/sidecar.js +49 -6
- package/dist/hosts/next/wrapper.js +30 -2
- package/dist/hosts/projectBridge.d.ts +20 -0
- package/dist/hosts/projectBridge.js +97 -0
- package/dist/hosts/static/cli.d.ts +1 -1
- package/dist/hosts/static/cli.js +6 -1
- package/dist/hosts/static/manifest.d.ts +1 -1
- package/dist/hosts/static/manifest.js +1 -1
- package/dist/hosts/static/server.js +44 -3
- package/dist/hosts/vite/vite.d.ts +5 -1
- package/dist/hosts/vite/vite.js +78 -14
- package/dist/inspector/agent/McpConnectionDialog.d.ts +2 -2
- package/dist/inspector/agent/McpConnectionDialog.js +11 -35
- package/dist/inspector/agent/client.d.ts +10 -3
- package/dist/inspector/agent/client.js +80 -9
- package/dist/inspector/agent/connectionStatus.js +3 -3
- package/dist/inspector/agent/httpTransport.d.ts +2 -0
- package/dist/inspector/agent/httpTransport.js +37 -17
- package/dist/inspector/agent/protocol.d.ts +8 -3
- package/dist/inspector/agent/protocol.js +1 -1
- package/dist/inspector/agent/verification.d.ts +1 -1
- package/dist/inspector/agent/verification.js +69 -12
- package/dist/inspector/canvas/CanvasCard.d.ts +5 -3
- package/dist/inspector/canvas/CanvasCard.js +181 -91
- package/dist/inspector/canvas/CanvasElementOverlay.js +246 -52
- package/dist/inspector/canvas/CanvasToolbar.d.ts +12 -0
- package/dist/inspector/canvas/CanvasToolbar.js +24 -0
- package/dist/inspector/canvas/CanvasWorkspace.d.ts +4 -1
- package/dist/inspector/canvas/CanvasWorkspace.js +392 -73
- package/dist/inspector/canvas/activeCanvasDocument.d.ts +5 -0
- package/dist/inspector/canvas/activeCanvasDocument.js +23 -0
- package/dist/inspector/canvas/canvasResize.d.ts +30 -0
- package/dist/inspector/canvas/canvasResize.js +52 -0
- package/dist/inspector/canvas/canvasStore.d.ts +30 -6
- package/dist/inspector/canvas/canvasStore.js +128 -61
- package/dist/inspector/canvas/frameProtocol.d.ts +69 -5
- package/dist/inspector/canvas/frameProtocol.js +56 -2
- package/dist/inspector/canvas/keyboardShortcuts.d.ts +3 -0
- package/dist/inspector/canvas/keyboardShortcuts.js +14 -0
- package/dist/inspector/canvas/projection.d.ts +7 -0
- package/dist/inspector/canvas/projection.js +118 -25
- package/dist/inspector/canvas/rendererBootstrap.js +29 -29
- package/dist/inspector/canvas/rendererElementSelector.js +341 -30
- package/dist/inspector/canvas/rendererMessageRouter.d.ts +11 -0
- package/dist/inspector/canvas/rendererMessageRouter.js +43 -0
- package/dist/inspector/canvas/rendererSelectionProxy.js +6 -2
- package/dist/inspector/canvas/sessionStore.d.ts +1 -0
- package/dist/inspector/canvas/sessionStore.js +12 -4
- package/dist/inspector/canvas/staleChangeDetector.js +16 -14
- package/dist/inspector/changes/changesLog.js +31 -1
- package/dist/inspector/changes/managedStyleProjection.d.ts +1 -1
- package/dist/inspector/changes/managedStyleProjection.js +3 -3
- package/dist/inspector/changes/structuralTypes.d.ts +4 -0
- package/dist/inspector/clientManifest.d.ts +5 -0
- package/dist/inspector/clientManifest.js +11 -0
- package/dist/inspector/componentSemantics/adapterRegistry.js +4 -3
- package/dist/inspector/componentSemantics/runtimeBridge.d.ts +2 -2
- package/dist/inspector/componentSemantics/runtimeBridge.js +16 -3
- package/dist/inspector/index.d.ts +2 -0
- package/dist/inspector/index.js +74 -24
- package/dist/inspector/inline-text/inlineTextDiagnostics.d.ts +10 -0
- package/dist/inspector/inline-text/inlineTextDiagnostics.js +65 -0
- package/dist/inspector/inline-text/inlineTextEditor.d.ts +3 -5
- package/dist/inspector/inline-text/inlineTextEditor.js +74 -206
- package/dist/inspector/inline-text/inlineTextFeedback.d.ts +5 -0
- package/dist/inspector/inline-text/inlineTextFeedback.js +27 -0
- package/dist/inspector/inline-text/inlineTextLifecycle.js +2 -0
- package/dist/inspector/inline-text/textEditChange.d.ts +14 -0
- package/dist/inspector/inline-text/textEditChange.js +165 -0
- package/dist/inspector/inspection/selectionProperty.d.ts +1 -0
- package/dist/inspector/inspection/selectionProperty.js +1 -0
- package/dist/inspector/overlay/selectedGeometry.js +21 -2
- package/dist/inspector/overlay/spacingGestures.d.ts +45 -0
- package/dist/inspector/overlay/spacingGestures.js +353 -0
- package/dist/inspector/overlay/structuralGestures.d.ts +2 -2
- package/dist/inspector/overlay/structuralGestures.js +12 -10
- package/dist/inspector/projection/managedStylesheet.js +4 -1
- package/dist/inspector/projection/renderedInstance.d.ts +2 -0
- package/dist/inspector/projection/renderedInstance.js +5 -1
- package/dist/inspector/projection/structuralProjection.d.ts +2 -0
- package/dist/inspector/projection/structuralProjection.js +85 -1
- package/dist/inspector/projection/structuralProjectionBoundary.js +17 -1
- package/dist/inspector/projection/textProjection.d.ts +2 -0
- package/dist/inspector/projection/textProjection.js +10 -4
- package/dist/inspector/prompt/clipboardHandoff.d.ts +1 -1
- package/dist/inspector/prompt/clipboardHandoff.js +3 -3
- package/dist/inspector/prompt/generatePrompt.d.ts +2 -1
- package/dist/inspector/prompt/generatePrompt.js +19 -2
- package/dist/inspector/runtime/editorShell.d.ts +2 -0
- package/dist/inspector/runtime/editorShell.js +4 -0
- package/dist/inspector/runtime/runtimeConfig.d.ts +4 -0
- package/dist/inspector/runtime/runtimeConfig.js +4 -0
- package/dist/inspector/selection/selectionStore.js +2 -0
- package/dist/inspector/settings/SettingsDialog.js +10 -0
- package/dist/inspector/shell/AppShell.js +5 -1
- package/dist/inspector/shell/ChangesLog.js +8 -4
- package/dist/inspector/shell/CopyPromptButton.js +95 -19
- package/dist/inspector/shell/EmptyState.js +1 -1
- package/dist/inspector/shell/InspectorShell.d.ts +0 -1
- package/dist/inspector/shell/InspectorShell.js +37 -38
- package/dist/inspector/shell/PeekOriginalButton.d.ts +7 -0
- package/dist/inspector/shell/PeekOriginalButton.js +57 -0
- package/dist/inspector/shell/PeekOriginalIcon.d.ts +7 -0
- package/dist/inspector/shell/PeekOriginalIcon.js +9 -0
- package/dist/inspector/shell/originalPreview.d.ts +9 -0
- package/dist/inspector/shell/originalPreview.js +61 -0
- package/dist/inspector/shell/shortcuts.d.ts +3 -0
- package/dist/inspector/shell/shortcuts.js +15 -0
- package/dist/inspector/sketch/SketchChanges.d.ts +2 -0
- package/dist/inspector/sketch/SketchChanges.js +72 -0
- package/dist/inspector/sketch/SketchEditor.d.ts +21 -0
- package/dist/inspector/sketch/SketchEditor.js +402 -0
- package/dist/inspector/sketch/SketchEntryButton.d.ts +4 -0
- package/dist/inspector/sketch/SketchEntryButton.js +11 -0
- package/dist/inspector/sketch/SketchFrameOverlay.d.ts +11 -0
- package/dist/inspector/sketch/SketchFrameOverlay.js +119 -0
- package/dist/inspector/sketch/SketchLayersPanel.d.ts +2 -0
- package/dist/inspector/sketch/SketchLayersPanel.js +63 -0
- package/dist/inspector/sketch/SketchOverlay.d.ts +19 -0
- package/dist/inspector/sketch/SketchOverlay.js +420 -0
- package/dist/inspector/sketch/SketchPromptPanel.d.ts +15 -0
- package/dist/inspector/sketch/SketchPromptPanel.js +18 -0
- package/dist/inspector/sketch/SketchWorkspace.d.ts +13 -0
- package/dist/inspector/sketch/SketchWorkspace.js +152 -0
- package/dist/inspector/sketch/capture.d.ts +55 -0
- package/dist/inspector/sketch/capture.js +350 -0
- package/dist/inspector/sketch/freehand.d.ts +13 -0
- package/dist/inspector/sketch/freehand.js +64 -0
- package/dist/inspector/sketch/geometry.d.ts +17 -0
- package/dist/inspector/sketch/geometry.js +98 -0
- package/dist/inspector/sketch/handoff.d.ts +21 -0
- package/dist/inspector/sketch/handoff.js +72 -0
- package/dist/inspector/sketch/interaction.d.ts +21 -0
- package/dist/inspector/sketch/interaction.js +98 -0
- package/dist/inspector/sketch/model.d.ts +104 -0
- package/dist/inspector/sketch/model.js +282 -0
- package/dist/inspector/sketch/persistence.d.ts +21 -0
- package/dist/inspector/sketch/persistence.js +205 -0
- package/dist/inspector/sketch/raster.d.ts +22 -0
- package/dist/inspector/sketch/raster.js +203 -0
- package/dist/inspector/sketch/sketchNote.d.ts +10 -0
- package/dist/inspector/sketch/sketchNote.js +30 -0
- package/dist/inspector/sketch/store.d.ts +47 -0
- package/dist/inspector/sketch/store.js +409 -0
- package/dist/inspector/styleEditors/BorderEditor.js +15 -19
- package/dist/inspector/styleEditors/BorderRadiusEditor.js +6 -6
- package/dist/inspector/styleEditors/BoxShadowEditor.js +12 -1
- package/dist/inspector/styleEditors/ColorPicker.js +11 -36
- package/dist/inspector/styleEditors/GapField.d.ts +3 -2
- package/dist/inspector/styleEditors/GapField.js +2 -2
- package/dist/inspector/styleEditors/GridSection.js +1 -1
- package/dist/inspector/styleEditors/LayoutSection.js +11 -8
- package/dist/inspector/styleEditors/SpacingBox.js +23 -30
- package/dist/inspector/styleEditors/layoutPreviewState.d.ts +5 -0
- package/dist/inspector/styleEditors/layoutPreviewState.js +19 -0
- package/dist/inspector/styleEditors/layoutValue.js +3 -0
- package/dist/inspector/styleEditors/nudgeValue.d.ts +11 -0
- package/dist/inspector/styleEditors/nudgeValue.js +91 -5
- package/dist/inspector/styleEditors/stylePresence.d.ts +7 -0
- package/dist/inspector/styleEditors/stylePresence.js +22 -0
- package/dist/inspector/styleEditors/textRelevance.d.ts +3 -0
- package/dist/inspector/styleEditors/textRelevance.js +35 -0
- package/dist/inspector/styleEditors/useFieldVisibility.d.ts +6 -0
- package/dist/inspector/styleEditors/useFieldVisibility.js +26 -0
- package/dist/inspector/tokens/TokenField.js +111 -7
- package/dist/inspector/tokens/editActions.d.ts +2 -0
- package/dist/inspector/tokens/editActions.js +2 -2
- package/dist/inspector/tokens/resolution/cssomCollector.d.ts +1 -1
- package/dist/inspector/tokens/resolution/cssomCollector.js +9 -5
- package/dist/inspector/tokens/resolution/ruleMatching.d.ts +40 -0
- package/dist/inspector/tokens/resolution/ruleMatching.js +423 -0
- package/dist/inspector/tokens/resolution/selectorSemantics.d.ts +19 -3
- package/dist/inspector/tokens/resolution/selectorSemantics.js +378 -4
- package/dist/inspector/tokens/resolution.d.ts +3 -26
- package/dist/inspector/tokens/resolution.js +44 -735
- package/dist/inspector/tokens/tokenAvailability.d.ts +18 -0
- package/dist/inspector/tokens/tokenAvailability.js +204 -0
- package/dist/inspector/ui/Button.d.ts +1 -1
- package/dist/inspector/ui/SideValuesField.js +2 -2
- package/dist/inspector/ui/StatusCallout.d.ts +4 -1
- package/dist/inspector/ui/StatusCallout.js +2 -2
- package/dist/inspector/ui/styles.js +13 -11
- package/dist/internal/agent-protocol.d.ts +65 -1
- package/dist/internal/agent-protocol.js +183 -3
- package/dist/nudge-ui.mjs +261 -57
- package/dist/transport/editor.d.ts +28 -0
- package/dist/transport/editor.js +132 -0
- package/dist/transport/index.d.ts +1 -0
- package/dist/transport/index.js +1 -0
- package/dist/transport/routes.d.ts +7 -0
- package/dist/transport/routes.js +7 -0
- package/package.json +3 -1
- package/dist/inspector/shell/panelLayout.d.ts +0 -2
- package/dist/inspector/shell/panelLayout.js +0 -29
|
@@ -1,16 +1,19 @@
|
|
|
1
|
-
import { PROTOCOL_VERSION, getRendererIdentity, sendToParent, } from "./frameProtocol.js";
|
|
1
|
+
import { PROTOCOL_VERSION, getRendererIdentity, sendToParent, isKeyboardShortcutCode, } from "./frameProtocol.js";
|
|
2
2
|
import { findClosestAnchor, isEligibleNavigation, hasDifferentRoute, shouldPreserveNativeLinkActivation, } from "./linkEligibility.js";
|
|
3
3
|
import { readBorderWidths, readMargins } from "../overlay/overlayGeometry.js";
|
|
4
4
|
import { installInteractionStyles } from "../overlay/interactionStyles.js";
|
|
5
5
|
import { createFrameThrottle } from "../overlay/frameThrottle.js";
|
|
6
6
|
import { createCidIndex } from "./rendererCidIndex.js";
|
|
7
7
|
import { isNudgeUiDev } from "../runtime/devFlag.js";
|
|
8
|
-
import { isEditableEvent } from "../shell/shortcuts.js";
|
|
8
|
+
import { isEditableEvent, isInspectorToggleShortcut, isSendPromptShortcut } from "../shell/shortcuts.js";
|
|
9
9
|
import { resolveSelectionTarget, selectionTargetMode } from "../selection/selectionTarget.js";
|
|
10
10
|
import { escapeCssString } from "../projection/cssEscapes.js";
|
|
11
11
|
import { blockApplicationClick, isApplicationActivationClick } from "../overlay/clickPolicy.js";
|
|
12
|
+
import { EMPTY_TEXT_PROJECTION_ATTR } from "../projection/textProjection.js";
|
|
13
|
+
import { getSpacingAffordanceAtPoint, toSpacingDescriptor, } from "../overlay/spacingGestures.js";
|
|
12
14
|
const REACT_FIBER_KEY = /^__reactFiber\$/;
|
|
13
15
|
const REACT_INTERNAL_KEY = /^__reactInternalInstance\$/;
|
|
16
|
+
const HOVER_SCROLL_SETTLE_DELAY = 150;
|
|
14
17
|
function findFiber(el) {
|
|
15
18
|
const keys = Object.keys(el);
|
|
16
19
|
for (const key of keys) {
|
|
@@ -84,15 +87,63 @@ export function installRendererElementSelector() {
|
|
|
84
87
|
const removeInteractionStyles = installInteractionStyles();
|
|
85
88
|
const listenerCleanup = [];
|
|
86
89
|
let disposed = false;
|
|
90
|
+
let interactionsSuspended = false;
|
|
91
|
+
let scrolling = false;
|
|
92
|
+
let scrollSettleTimer = null;
|
|
93
|
+
let activeHoverElement = null;
|
|
94
|
+
let lastHoverPoint = null;
|
|
87
95
|
function trackListener(target, type, listener, options) {
|
|
88
96
|
const eventListener = (event) => listener(event);
|
|
89
97
|
target.addEventListener(type, eventListener, options);
|
|
90
98
|
listenerCleanup.push(() => target.removeEventListener(type, eventListener, options));
|
|
91
99
|
}
|
|
92
100
|
const cidIndex = createCidIndex(document);
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
101
|
+
const initialCursor = document.documentElement.style.getPropertyValue("cursor");
|
|
102
|
+
const initialCursorPriority = document.documentElement.style.getPropertyPriority("cursor");
|
|
103
|
+
let appliedRootCursor = null;
|
|
104
|
+
let spacingCursor = null;
|
|
105
|
+
function clearSpacingCursor() {
|
|
106
|
+
const active = spacingCursor;
|
|
107
|
+
spacingCursor = null;
|
|
108
|
+
if (active
|
|
109
|
+
&& active.element.style.getPropertyValue("cursor") === active.appliedValue
|
|
110
|
+
&& active.element.style.getPropertyPriority("cursor") === "important") {
|
|
111
|
+
if (active.previousValue) {
|
|
112
|
+
active.element.style.setProperty("cursor", active.previousValue, active.previousPriority);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
active.element.style.removeProperty("cursor");
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (appliedRootCursor !== null
|
|
119
|
+
&& document.documentElement.style.getPropertyValue("cursor") === appliedRootCursor) {
|
|
120
|
+
if (initialCursor) {
|
|
121
|
+
document.documentElement.style.setProperty("cursor", initialCursor, initialCursorPriority);
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
document.documentElement.style.removeProperty("cursor");
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
appliedRootCursor = null;
|
|
128
|
+
}
|
|
129
|
+
function setSpacingCursor(element, cursor) {
|
|
130
|
+
if (spacingCursor?.element !== element) {
|
|
131
|
+
clearSpacingCursor();
|
|
132
|
+
spacingCursor = {
|
|
133
|
+
element,
|
|
134
|
+
previousValue: element.style.getPropertyValue("cursor"),
|
|
135
|
+
previousPriority: element.style.getPropertyPriority("cursor"),
|
|
136
|
+
appliedValue: cursor,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
spacingCursor.appliedValue = cursor;
|
|
141
|
+
}
|
|
142
|
+
element.style.setProperty("cursor", cursor, "important");
|
|
143
|
+
document.documentElement.style.setProperty("cursor", cursor);
|
|
144
|
+
appliedRootCursor = cursor;
|
|
145
|
+
}
|
|
146
|
+
function reportHover(pending) {
|
|
96
147
|
const { element, clear } = pending;
|
|
97
148
|
const identity = getRendererIdentity();
|
|
98
149
|
if (!identity)
|
|
@@ -101,6 +152,17 @@ export function installRendererElementSelector() {
|
|
|
101
152
|
const selector = buildSelector(element);
|
|
102
153
|
const src = element.getAttribute("data-src") ?? "";
|
|
103
154
|
const rect = clear ? null : element.getBoundingClientRect();
|
|
155
|
+
const rawSpacing = !clear && pending.point
|
|
156
|
+
? getSpacingAffordanceAtPoint(document, pending.point.x, pending.point.y)
|
|
157
|
+
: null;
|
|
158
|
+
const spacing = rawSpacing && rawSpacing.element === element ? rawSpacing : null;
|
|
159
|
+
if (spacing) {
|
|
160
|
+
setSpacingCursor(spacing.element, spacing.cursor);
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
clearSpacingCursor();
|
|
164
|
+
}
|
|
165
|
+
activeHoverElement = clear ? null : element;
|
|
104
166
|
const msg = {
|
|
105
167
|
type: "element-hover",
|
|
106
168
|
protocolVersion: PROTOCOL_VERSION,
|
|
@@ -118,10 +180,49 @@ export function installRendererElementSelector() {
|
|
|
118
180
|
: null,
|
|
119
181
|
margins: rect ? readMargins(element) : null,
|
|
120
182
|
borders: rect ? readBorderWidths(element) : null,
|
|
183
|
+
point: pending.point,
|
|
184
|
+
spacing: spacing ? toSpacingDescriptor(spacing) : null,
|
|
121
185
|
...identity,
|
|
122
186
|
};
|
|
123
187
|
sendToParent(msg);
|
|
188
|
+
}
|
|
189
|
+
const hoverUpdate = createFrameThrottle((pending) => {
|
|
190
|
+
if (disposed || scrolling)
|
|
191
|
+
return;
|
|
192
|
+
reportHover(pending);
|
|
124
193
|
});
|
|
194
|
+
function clearActiveHover() {
|
|
195
|
+
hoverUpdate.cancel();
|
|
196
|
+
clearSpacingCursor();
|
|
197
|
+
const element = activeHoverElement;
|
|
198
|
+
activeHoverElement = null;
|
|
199
|
+
if (element)
|
|
200
|
+
reportHover({ element, clear: true, point: null });
|
|
201
|
+
}
|
|
202
|
+
function resumeHoverAfterScroll() {
|
|
203
|
+
scrollSettleTimer = null;
|
|
204
|
+
scrolling = false;
|
|
205
|
+
if (disposed || interactionsSuspended || !lastHoverPoint)
|
|
206
|
+
return;
|
|
207
|
+
const target = document.elementFromPoint?.(lastHoverPoint.x, lastHoverPoint.y);
|
|
208
|
+
const element = resolveSelectionTarget(target, lastHoverPoint.mode);
|
|
209
|
+
if (!element)
|
|
210
|
+
return;
|
|
211
|
+
hoverUpdate.schedule({
|
|
212
|
+
element,
|
|
213
|
+
clear: false,
|
|
214
|
+
point: { x: lastHoverPoint.x, y: lastHoverPoint.y },
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
function suppressHoverDuringScroll() {
|
|
218
|
+
if (disposed || interactionsSuspended)
|
|
219
|
+
return;
|
|
220
|
+
scrolling = true;
|
|
221
|
+
clearActiveHover();
|
|
222
|
+
if (scrollSettleTimer !== null)
|
|
223
|
+
window.clearTimeout(scrollSettleTimer);
|
|
224
|
+
scrollSettleTimer = window.setTimeout(resumeHoverAfterScroll, HOVER_SCROLL_SETTLE_DELAY);
|
|
225
|
+
}
|
|
125
226
|
let measurePointerOverPage = false;
|
|
126
227
|
let measureAltKey = false;
|
|
127
228
|
function updateMeasureState(altKey, pointerOverPage) {
|
|
@@ -144,6 +245,8 @@ export function installRendererElementSelector() {
|
|
|
144
245
|
sendToParent(msg);
|
|
145
246
|
}
|
|
146
247
|
trackListener(document, "mouseover", (event) => {
|
|
248
|
+
if (interactionsSuspended)
|
|
249
|
+
return;
|
|
147
250
|
updateMeasureState(event.altKey, true);
|
|
148
251
|
const target = event.target;
|
|
149
252
|
if (!(target instanceof Element))
|
|
@@ -151,11 +254,66 @@ export function installRendererElementSelector() {
|
|
|
151
254
|
const el = resolveSelectionTarget(target, selectionTargetMode(event));
|
|
152
255
|
if (!el)
|
|
153
256
|
return;
|
|
154
|
-
|
|
257
|
+
lastHoverPoint = { x: event.clientX, y: event.clientY, mode: selectionTargetMode(event) };
|
|
258
|
+
if (scrolling)
|
|
259
|
+
return;
|
|
260
|
+
hoverUpdate.schedule({ element: el, clear: false, point: { x: event.clientX, y: event.clientY } });
|
|
155
261
|
}, true);
|
|
262
|
+
trackListener(window, "scroll", suppressHoverDuringScroll, true);
|
|
156
263
|
let pendingDrag = null;
|
|
157
264
|
let dragging = false;
|
|
265
|
+
let lastDragPoint = null;
|
|
158
266
|
let lastSelected = null;
|
|
267
|
+
trackListener(window, "nudge-ui:open", () => {
|
|
268
|
+
const identity = getRendererIdentity();
|
|
269
|
+
if (!identity)
|
|
270
|
+
return;
|
|
271
|
+
const message = {
|
|
272
|
+
type: "inspector-open-request",
|
|
273
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
274
|
+
...identity,
|
|
275
|
+
};
|
|
276
|
+
sendToParent(message);
|
|
277
|
+
});
|
|
278
|
+
trackListener(window, "message", (event) => {
|
|
279
|
+
if (event.origin !== window.location.origin || event.source !== window.parent)
|
|
280
|
+
return;
|
|
281
|
+
const identity = getRendererIdentity();
|
|
282
|
+
const message = event.data;
|
|
283
|
+
if (!identity || !message
|
|
284
|
+
|| message.protocolVersion !== PROTOCOL_VERSION
|
|
285
|
+
|| message.projectId !== identity.projectId
|
|
286
|
+
|| message.workspaceId !== identity.workspaceId
|
|
287
|
+
|| message.cardId !== identity.cardId)
|
|
288
|
+
return;
|
|
289
|
+
if (message.type === "measure-modifier" && typeof message.altKey === "boolean") {
|
|
290
|
+
updateMeasureState(message.altKey, measurePointerOverPage);
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
if (message.type !== "inspector-interaction-state" || typeof message.open !== "boolean")
|
|
294
|
+
return;
|
|
295
|
+
const interactionsEnabled = message.interactionsEnabled === undefined
|
|
296
|
+
? message.open
|
|
297
|
+
: message.interactionsEnabled === true;
|
|
298
|
+
interactionsSuspended = !interactionsEnabled;
|
|
299
|
+
if (message.open) {
|
|
300
|
+
document.documentElement.setAttribute("data-nudge-ui-panel", "open");
|
|
301
|
+
}
|
|
302
|
+
else {
|
|
303
|
+
document.documentElement.removeAttribute("data-nudge-ui-panel");
|
|
304
|
+
}
|
|
305
|
+
if (interactionsSuspended) {
|
|
306
|
+
cancelActiveDrag();
|
|
307
|
+
hoverUpdate.cancel();
|
|
308
|
+
clearSpacingCursor();
|
|
309
|
+
if (scrollSettleTimer !== null)
|
|
310
|
+
window.clearTimeout(scrollSettleTimer);
|
|
311
|
+
scrollSettleTimer = null;
|
|
312
|
+
scrolling = false;
|
|
313
|
+
activeHoverElement = null;
|
|
314
|
+
updateMeasureState(false, false);
|
|
315
|
+
}
|
|
316
|
+
});
|
|
159
317
|
const dragMoveUpdate = createFrameThrottle((point) => {
|
|
160
318
|
if (disposed)
|
|
161
319
|
return;
|
|
@@ -165,18 +323,86 @@ export function installRendererElementSelector() {
|
|
|
165
323
|
const msg = { type: "element-drag-move", protocolVersion: PROTOCOL_VERSION, point, ...identity };
|
|
166
324
|
sendToParent(msg);
|
|
167
325
|
});
|
|
326
|
+
function sendDragEnd(point, cancelled) {
|
|
327
|
+
if (!dragging || !point)
|
|
328
|
+
return;
|
|
329
|
+
const identity = getRendererIdentity();
|
|
330
|
+
if (!identity)
|
|
331
|
+
return;
|
|
332
|
+
const msg = {
|
|
333
|
+
type: "element-drag-end",
|
|
334
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
335
|
+
point,
|
|
336
|
+
...(cancelled ? { cancelled: true } : {}),
|
|
337
|
+
...identity,
|
|
338
|
+
};
|
|
339
|
+
sendToParent(msg);
|
|
340
|
+
}
|
|
341
|
+
function cancelActiveDrag() {
|
|
342
|
+
dragMoveUpdate.cancel();
|
|
343
|
+
sendDragEnd(lastDragPoint, true);
|
|
344
|
+
pendingDrag = null;
|
|
345
|
+
dragging = false;
|
|
346
|
+
}
|
|
168
347
|
trackListener(document, "mousedown", (event) => {
|
|
348
|
+
if (interactionsSuspended)
|
|
349
|
+
return;
|
|
169
350
|
if (event.button !== 0)
|
|
170
351
|
return;
|
|
171
352
|
const element = resolveSelectionTarget(event.target, selectionTargetMode(event));
|
|
172
353
|
if (!element)
|
|
173
354
|
return;
|
|
355
|
+
const spacingAffordance = getSpacingAffordanceAtPoint(document, event.clientX, event.clientY);
|
|
356
|
+
const spacing = spacingAffordance?.element === element
|
|
357
|
+
? toSpacingDescriptor(spacingAffordance)
|
|
358
|
+
: null;
|
|
359
|
+
const identity = getRendererIdentity();
|
|
360
|
+
// A spacing drag owns the pointer gesture. Do not start an inline-text
|
|
361
|
+
// attempt for the same down event; padding and gaps are intentionally not
|
|
362
|
+
// editable text targets.
|
|
363
|
+
if (identity && !spacing) {
|
|
364
|
+
const emptyProjectionId = event.target instanceof Element
|
|
365
|
+
? event.target.closest(`[${EMPTY_TEXT_PROJECTION_ATTR}]`)?.getAttribute(EMPTY_TEXT_PROJECTION_ATTR) ?? undefined
|
|
366
|
+
: undefined;
|
|
367
|
+
const message = {
|
|
368
|
+
type: "inline-text-intent",
|
|
369
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
370
|
+
intent: emptyProjectionId && event.detail >= 2 ? "double-click" : "pointer-down",
|
|
371
|
+
cid: element.getAttribute("data-cid"),
|
|
372
|
+
src: element.getAttribute("data-src") ?? "",
|
|
373
|
+
elementId: cidIndex.elementId(element),
|
|
374
|
+
point: { x: event.clientX, y: event.clientY },
|
|
375
|
+
clickCount: event.detail,
|
|
376
|
+
emptyProjectionId,
|
|
377
|
+
...identity,
|
|
378
|
+
};
|
|
379
|
+
sendToParent(message);
|
|
380
|
+
}
|
|
174
381
|
lastSelected = element;
|
|
175
|
-
pendingDrag = {
|
|
382
|
+
pendingDrag = {
|
|
383
|
+
element,
|
|
384
|
+
point: { x: event.clientX, y: event.clientY },
|
|
385
|
+
spacing,
|
|
386
|
+
};
|
|
387
|
+
lastDragPoint = { x: event.clientX, y: event.clientY };
|
|
176
388
|
}, true);
|
|
177
389
|
trackListener(document, "mousemove", (event) => {
|
|
178
|
-
if (!pendingDrag)
|
|
390
|
+
if (!pendingDrag) {
|
|
391
|
+
if (interactionsSuspended)
|
|
392
|
+
return;
|
|
393
|
+
const target = event.target;
|
|
394
|
+
if (target instanceof Element) {
|
|
395
|
+
const mode = selectionTargetMode(event);
|
|
396
|
+
const element = resolveSelectionTarget(target, mode);
|
|
397
|
+
if (element) {
|
|
398
|
+
lastHoverPoint = { x: event.clientX, y: event.clientY, mode };
|
|
399
|
+
if (scrolling)
|
|
400
|
+
return;
|
|
401
|
+
hoverUpdate.schedule({ element, clear: false, point: { x: event.clientX, y: event.clientY } });
|
|
402
|
+
}
|
|
403
|
+
}
|
|
179
404
|
return;
|
|
405
|
+
}
|
|
180
406
|
if (!dragging && Math.hypot(event.clientX - pendingDrag.point.x, event.clientY - pendingDrag.point.y) < 6)
|
|
181
407
|
return;
|
|
182
408
|
const identity = getRendererIdentity();
|
|
@@ -184,12 +410,16 @@ export function installRendererElementSelector() {
|
|
|
184
410
|
return;
|
|
185
411
|
event.preventDefault();
|
|
186
412
|
const point = { x: event.clientX, y: event.clientY };
|
|
413
|
+
lastDragPoint = point;
|
|
187
414
|
if (!dragging) {
|
|
188
415
|
dragging = true;
|
|
189
416
|
const msg = {
|
|
190
417
|
type: "element-drag-start", protocolVersion: PROTOCOL_VERSION,
|
|
191
418
|
cid: pendingDrag.element.getAttribute("data-cid"), src: pendingDrag.element.getAttribute("data-src") ?? "",
|
|
192
|
-
elementId: cidIndex.elementId(pendingDrag.element), point,
|
|
419
|
+
elementId: cidIndex.elementId(pendingDrag.element), point,
|
|
420
|
+
startPoint: pendingDrag.point,
|
|
421
|
+
spacing: pendingDrag.spacing,
|
|
422
|
+
...identity,
|
|
193
423
|
};
|
|
194
424
|
sendToParent(msg);
|
|
195
425
|
}
|
|
@@ -200,25 +430,68 @@ export function installRendererElementSelector() {
|
|
|
200
430
|
function finishDrag(event) {
|
|
201
431
|
dragMoveUpdate.cancel();
|
|
202
432
|
if (dragging) {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
type: "element-drag-end", protocolVersion: PROTOCOL_VERSION,
|
|
208
|
-
point: { x: event.clientX, y: event.clientY }, ...identity,
|
|
209
|
-
};
|
|
210
|
-
sendToParent(msg);
|
|
211
|
-
}
|
|
433
|
+
event.preventDefault();
|
|
434
|
+
const point = { x: event.clientX, y: event.clientY };
|
|
435
|
+
lastDragPoint = point;
|
|
436
|
+
sendDragEnd(point, false);
|
|
212
437
|
}
|
|
213
438
|
pendingDrag = null;
|
|
214
439
|
dragging = false;
|
|
215
440
|
}
|
|
216
441
|
trackListener(document, "mouseup", finishDrag, true);
|
|
442
|
+
function forwardKeyboardShortcut(event, phase) {
|
|
443
|
+
const code = isKeyboardShortcutCode(event.code) ? event.code : null;
|
|
444
|
+
if (!code)
|
|
445
|
+
return false;
|
|
446
|
+
if (code === "KeyS") {
|
|
447
|
+
if (phase !== "keydown" || !isSendPromptShortcut(event))
|
|
448
|
+
return false;
|
|
449
|
+
}
|
|
450
|
+
else if (code !== "Backslash" && interactionsSuspended) {
|
|
451
|
+
return false;
|
|
452
|
+
}
|
|
453
|
+
if (phase === "keydown") {
|
|
454
|
+
if (code !== "KeyS" && (event.repeat || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey || isEditableEvent(event)))
|
|
455
|
+
return false;
|
|
456
|
+
}
|
|
457
|
+
else if (code !== "Backslash") {
|
|
458
|
+
return false;
|
|
459
|
+
}
|
|
460
|
+
const identity = getRendererIdentity();
|
|
461
|
+
if (!identity)
|
|
462
|
+
return false;
|
|
463
|
+
const message = {
|
|
464
|
+
type: "keyboard-shortcut",
|
|
465
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
466
|
+
phase,
|
|
467
|
+
code,
|
|
468
|
+
...identity,
|
|
469
|
+
};
|
|
470
|
+
sendToParent(message);
|
|
471
|
+
return phase === "keydown";
|
|
472
|
+
}
|
|
217
473
|
trackListener(document, "keydown", (event) => {
|
|
218
|
-
if (event.key === "Alt")
|
|
219
|
-
updateMeasureState(true, measurePointerOverPage);
|
|
220
474
|
if (isEditableEvent(event))
|
|
221
475
|
return;
|
|
476
|
+
if (forwardKeyboardShortcut(event, "keydown"))
|
|
477
|
+
event.preventDefault();
|
|
478
|
+
if (isInspectorToggleShortcut(event)) {
|
|
479
|
+
const identity = getRendererIdentity();
|
|
480
|
+
if (!identity)
|
|
481
|
+
return;
|
|
482
|
+
event.preventDefault();
|
|
483
|
+
const msg = {
|
|
484
|
+
type: "inspector-toggle-request",
|
|
485
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
486
|
+
...identity,
|
|
487
|
+
};
|
|
488
|
+
sendToParent(msg);
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
if (interactionsSuspended)
|
|
492
|
+
return;
|
|
493
|
+
if (event.key === "Alt")
|
|
494
|
+
updateMeasureState(true, measurePointerOverPage);
|
|
222
495
|
const scrollKey = event.code === "Space"
|
|
223
496
|
|| event.key === "ArrowUp"
|
|
224
497
|
|| event.key === "ArrowDown"
|
|
@@ -242,6 +515,8 @@ export function installRendererElementSelector() {
|
|
|
242
515
|
}
|
|
243
516
|
if (event.key === "Escape" || event.key === "Esc") {
|
|
244
517
|
event.preventDefault();
|
|
518
|
+
cancelActiveDrag();
|
|
519
|
+
clearSpacingCursor();
|
|
245
520
|
lastSelected = null;
|
|
246
521
|
const identity = getRendererIdentity();
|
|
247
522
|
if (!identity)
|
|
@@ -280,20 +555,27 @@ export function installRendererElementSelector() {
|
|
|
280
555
|
sendToParent(msg);
|
|
281
556
|
}, true);
|
|
282
557
|
trackListener(document, "keyup", (event) => {
|
|
558
|
+
forwardKeyboardShortcut(event, "keyup");
|
|
283
559
|
if (event.key === "Alt")
|
|
284
560
|
updateMeasureState(false, measurePointerOverPage);
|
|
285
561
|
}, true);
|
|
286
562
|
trackListener(window, "blur", () => {
|
|
563
|
+
cancelActiveDrag();
|
|
287
564
|
updateMeasureState(false, false);
|
|
288
565
|
});
|
|
289
566
|
trackListener(document, "mouseout", (event) => {
|
|
567
|
+
if (interactionsSuspended)
|
|
568
|
+
return;
|
|
290
569
|
const target = event.target;
|
|
291
570
|
if (!(target instanceof HTMLElement))
|
|
292
571
|
return;
|
|
293
572
|
const related = event.relatedTarget;
|
|
294
573
|
if (!(related instanceof Node) || !document.contains(related)) {
|
|
295
574
|
updateMeasureState(event.altKey, false);
|
|
575
|
+
lastHoverPoint = null;
|
|
296
576
|
}
|
|
577
|
+
if (scrolling)
|
|
578
|
+
return;
|
|
297
579
|
if (related instanceof Node && (target.contains(related) || target === related))
|
|
298
580
|
return;
|
|
299
581
|
if (!(target instanceof Element))
|
|
@@ -303,19 +585,42 @@ export function installRendererElementSelector() {
|
|
|
303
585
|
return;
|
|
304
586
|
if (resolveSelectionTarget(related, selectionTargetMode(event)))
|
|
305
587
|
return;
|
|
306
|
-
|
|
588
|
+
clearSpacingCursor();
|
|
589
|
+
hoverUpdate.schedule({ element: el, clear: true, point: null });
|
|
590
|
+
}, true);
|
|
591
|
+
trackListener(document, "dblclick", (event) => {
|
|
592
|
+
if (interactionsSuspended)
|
|
593
|
+
return;
|
|
594
|
+
const element = resolveSelectionTarget(event.target, selectionTargetMode(event));
|
|
595
|
+
const identity = getRendererIdentity();
|
|
596
|
+
if (!element || !identity)
|
|
597
|
+
return;
|
|
598
|
+
blockApplicationClick(event);
|
|
599
|
+
const message = {
|
|
600
|
+
type: "inline-text-intent",
|
|
601
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
602
|
+
intent: "double-click",
|
|
603
|
+
cid: element.getAttribute("data-cid"),
|
|
604
|
+
src: element.getAttribute("data-src") ?? "",
|
|
605
|
+
elementId: cidIndex.elementId(element),
|
|
606
|
+
point: { x: event.clientX, y: event.clientY },
|
|
607
|
+
emptyProjectionId: event.target instanceof Element
|
|
608
|
+
? event.target.closest(`[${EMPTY_TEXT_PROJECTION_ATTR}]`)?.getAttribute(EMPTY_TEXT_PROJECTION_ATTR) ?? undefined
|
|
609
|
+
: undefined,
|
|
610
|
+
...identity,
|
|
611
|
+
};
|
|
612
|
+
sendToParent(message);
|
|
307
613
|
}, true);
|
|
308
614
|
trackListener(document, "click", (event) => {
|
|
615
|
+
if (interactionsSuspended)
|
|
616
|
+
return;
|
|
309
617
|
const target = event.target;
|
|
310
618
|
if (!(target instanceof Element))
|
|
311
619
|
return;
|
|
312
620
|
// Defer to navigation-intent when the user clicked a navigable same-origin
|
|
313
|
-
// anchor that points to a different route.
|
|
314
|
-
//
|
|
315
|
-
//
|
|
316
|
-
// we must NOT stop propagation here. Left to its own default the click would
|
|
317
|
-
// perform a full-frame navigation inside the iframe; the navigation-intent
|
|
318
|
-
// handler calls preventDefault once it has gathered the anchor href.
|
|
621
|
+
// anchor that points to a different route. The later listener reports the
|
|
622
|
+
// intent to the controller while leaving native or framework navigation in
|
|
623
|
+
// charge of the live application document.
|
|
319
624
|
const anchor = findClosestAnchor(target);
|
|
320
625
|
if (anchor && isEligibleNavigation(anchor, event) && hasDifferentRoute(anchor)) {
|
|
321
626
|
return;
|
|
@@ -361,18 +666,24 @@ export function installRendererElementSelector() {
|
|
|
361
666
|
return () => {
|
|
362
667
|
if (disposed)
|
|
363
668
|
return;
|
|
669
|
+
cancelActiveDrag();
|
|
364
670
|
disposed = true;
|
|
365
671
|
installed = false;
|
|
366
672
|
hoverUpdate.cancel();
|
|
367
|
-
|
|
673
|
+
if (scrollSettleTimer !== null)
|
|
674
|
+
window.clearTimeout(scrollSettleTimer);
|
|
675
|
+
scrollSettleTimer = null;
|
|
368
676
|
for (const cleanup of listenerCleanup)
|
|
369
677
|
cleanup();
|
|
370
678
|
listenerCleanup.length = 0;
|
|
371
679
|
removeInteractionStyles();
|
|
372
|
-
pendingDrag = null;
|
|
373
|
-
dragging = false;
|
|
374
680
|
lastSelected = null;
|
|
681
|
+
activeHoverElement = null;
|
|
682
|
+
lastHoverPoint = null;
|
|
683
|
+
scrolling = false;
|
|
375
684
|
measurePointerOverPage = false;
|
|
376
685
|
measureAltKey = false;
|
|
686
|
+
document.documentElement.removeAttribute("data-nudge-ui-panel");
|
|
687
|
+
clearSpacingCursor();
|
|
377
688
|
};
|
|
378
689
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type FrameIdentity, type FrameProtocolMessage } from "./frameProtocol.js";
|
|
2
|
+
export interface CanvasRendererMessage {
|
|
3
|
+
cardId: string;
|
|
4
|
+
iframe: HTMLIFrameElement;
|
|
5
|
+
identity: FrameIdentity;
|
|
6
|
+
message: FrameProtocolMessage;
|
|
7
|
+
}
|
|
8
|
+
type CanvasRendererMessageListener = (event: CanvasRendererMessage) => void;
|
|
9
|
+
/** Subscribes to same-origin messages from registered Canvas renderer frames. */
|
|
10
|
+
export declare function subscribeCanvasRendererMessages(listener: CanvasRendererMessageListener): () => void;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { isRendererMessageFor, PROTOCOL_VERSION, } from "./frameProtocol.js";
|
|
2
|
+
import { findCanvasFrameBySource, PROJECT_ID, WORKSPACE_ID } from "./projection.js";
|
|
3
|
+
const listeners = new Set();
|
|
4
|
+
function routeRendererMessage(event) {
|
|
5
|
+
if (event.origin !== window.location.origin || !event.data || typeof event.data !== "object")
|
|
6
|
+
return;
|
|
7
|
+
const frame = findCanvasFrameBySource(event.source);
|
|
8
|
+
if (!frame)
|
|
9
|
+
return;
|
|
10
|
+
const identity = {
|
|
11
|
+
projectId: PROJECT_ID,
|
|
12
|
+
workspaceId: WORKSPACE_ID,
|
|
13
|
+
cardId: frame.cardId,
|
|
14
|
+
};
|
|
15
|
+
// SAFETY: The object guard above makes the optional discriminator fields safe to inspect.
|
|
16
|
+
const candidate = event.data;
|
|
17
|
+
if (candidate.type === "renderer-hello") {
|
|
18
|
+
if (candidate.protocolVersion !== PROTOCOL_VERSION)
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
else if (!isRendererMessageFor(event.data, identity)) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const routed = {
|
|
25
|
+
...frame,
|
|
26
|
+
identity,
|
|
27
|
+
// SAFETY: Subscribers narrow the discriminated protocol union before reading message-specific fields.
|
|
28
|
+
message: event.data,
|
|
29
|
+
};
|
|
30
|
+
for (const listener of listeners)
|
|
31
|
+
listener(routed);
|
|
32
|
+
}
|
|
33
|
+
/** Subscribes to same-origin messages from registered Canvas renderer frames. */
|
|
34
|
+
export function subscribeCanvasRendererMessages(listener) {
|
|
35
|
+
if (listeners.size === 0)
|
|
36
|
+
window.addEventListener("message", routeRendererMessage);
|
|
37
|
+
listeners.add(listener);
|
|
38
|
+
return () => {
|
|
39
|
+
listeners.delete(listener);
|
|
40
|
+
if (listeners.size === 0)
|
|
41
|
+
window.removeEventListener("message", routeRendererMessage);
|
|
42
|
+
};
|
|
43
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getSelectedElements, setSelectedElement, toggleSelectedElement } from "../selection/selectionStore.js";
|
|
2
2
|
import { selectCard } from "./canvasStore.js";
|
|
3
3
|
import { RENDERER_ELEMENT_ID_ATTR } from "./rendererCidIndex.js";
|
|
4
|
+
import { inspectComponentTargets } from "../componentSemantics/index.js";
|
|
4
5
|
function isHtmlElementInDocument(node, doc) {
|
|
5
6
|
const frameWindow = doc.defaultView;
|
|
6
7
|
return frameWindow !== null && node instanceof frameWindow.HTMLElement;
|
|
@@ -26,7 +27,9 @@ function findClickedElement(doc, elementId, cid, src) {
|
|
|
26
27
|
if (candidates.length !== 1)
|
|
27
28
|
return null;
|
|
28
29
|
const candidate = candidates[0] ?? null;
|
|
29
|
-
if (!candidate
|
|
30
|
+
if (!candidate
|
|
31
|
+
|| candidate.getAttribute("data-cid") !== cid
|
|
32
|
+
|| (candidate.getAttribute("data-src") ?? "") !== src)
|
|
30
33
|
return null;
|
|
31
34
|
return isHtmlElementInDocument(candidate, doc) ? candidate : null;
|
|
32
35
|
}
|
|
@@ -38,6 +41,7 @@ export function handleElementClick(msg, iframe, cardId) {
|
|
|
38
41
|
selectCard(cardId);
|
|
39
42
|
return;
|
|
40
43
|
}
|
|
44
|
+
const componentTargets = inspectComponentTargets(el);
|
|
41
45
|
const selected = {
|
|
42
46
|
cid: msg.cid,
|
|
43
47
|
src: el.getAttribute("data-src") ?? msg.src,
|
|
@@ -46,7 +50,7 @@ export function handleElementClick(msg, iframe, cardId) {
|
|
|
46
50
|
line: msg.line,
|
|
47
51
|
column: 0,
|
|
48
52
|
domElement: el,
|
|
49
|
-
componentTargets
|
|
53
|
+
componentTargets,
|
|
50
54
|
};
|
|
51
55
|
// setSelectedElement must run before any side effect that could reload the
|
|
52
56
|
// host page, otherwise the selection would be discarded by the unload.
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { getWorkspaceChanges } from "../changes/workspaceChanges.js";
|
|
2
2
|
import { loadWorkspaceChanges } from "../changes/changesLog.js";
|
|
3
3
|
import { deserializeChange, isSerializableChange, serializeChange, } from "../changes/codecs.js";
|
|
4
|
-
import { getCanvasMode, getCanvasCards, getCanvasComparisonGroups, getBoardCamera, setBoardCamera, hydrateCanvasStore, removeCanvasCard, } from "./canvasStore.js";
|
|
4
|
+
import { getCanvasMode, getCanvasCards, getCanvasComparisonGroups, getFocusedCardId, getBoardCamera, setBoardCamera, hydrateCanvasStore, removeCanvasCard, } from "./canvasStore.js";
|
|
5
5
|
import { applyRules } from "../projection/managedStylesheet.js";
|
|
6
6
|
import { clearWorkspace as clearWorkspaceLog } from "../changes/changesLog.js";
|
|
7
7
|
import { removeManagedSheet } from "../projection/managedStylesheet.js";
|
|
8
|
-
import { clearInspectorLayout } from "../shell/panelLayout.js";
|
|
9
8
|
import { setSelectedElement } from "../selection/selectionStore.js";
|
|
10
9
|
import { canWriteWorkspace } from "./workspaceLease.js";
|
|
11
10
|
import { isStructuralChange, resetStructuralDeleteProjection, } from "../projection/structuralProjection.js";
|
|
@@ -121,6 +120,7 @@ function buildSession() {
|
|
|
121
120
|
})),
|
|
122
121
|
})),
|
|
123
122
|
camera: { x: camera.x, y: camera.y, zoom: camera.zoom },
|
|
123
|
+
focusedCardId: getFocusedCardId(),
|
|
124
124
|
changes: serializableChanges,
|
|
125
125
|
structuralChanges: workspace.structuralChanges.map((change) => ({ ...change })),
|
|
126
126
|
clipboardHandoff: getClipboardHandoffSnapshot(),
|
|
@@ -330,7 +330,16 @@ export function hydrateSession() {
|
|
|
330
330
|
y: cameraRaw.y,
|
|
331
331
|
zoom: cameraRaw.zoom,
|
|
332
332
|
};
|
|
333
|
-
|
|
333
|
+
const focusedCardId = s.focusedCardId === undefined || s.focusedCardId === null
|
|
334
|
+
? null
|
|
335
|
+
: typeof s.focusedCardId === "string" && cardsById.has(s.focusedCardId)
|
|
336
|
+
? s.focusedCardId
|
|
337
|
+
: undefined;
|
|
338
|
+
if (focusedCardId === undefined) {
|
|
339
|
+
safeDiscard();
|
|
340
|
+
return { restored: false, changeCount: 0 };
|
|
341
|
+
}
|
|
342
|
+
hydrateCanvasStore(s.mode, serializableCards, camera, serializableComparisonGroups, focusedCardId);
|
|
334
343
|
// Structural intent and instance evidence become visible atomically. The
|
|
335
344
|
// projection layer preserves structural-first document application order.
|
|
336
345
|
loadWorkspaceChanges(deserializedChanges, structuralChanges);
|
|
@@ -366,7 +375,6 @@ export function clearSession() {
|
|
|
366
375
|
resetStructuralDeleteProjection();
|
|
367
376
|
removeManagedSheet();
|
|
368
377
|
setSelectedElement(null);
|
|
369
|
-
clearInspectorLayout();
|
|
370
378
|
for (const card of getCanvasCards()) {
|
|
371
379
|
removeCanvasCard(card.id);
|
|
372
380
|
}
|