nudge-ui 0.2.0 → 0.2.2
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 +878 -11
- package/dist/hosts/astro/astroRuntimeConfig.js +1 -1
- package/dist/hosts/astro/clientTransport.js +63 -11
- package/dist/hosts/astro/integration.d.ts +2 -2
- package/dist/hosts/astro/integration.js +4 -3
- package/dist/hosts/environment.d.ts +15 -0
- package/dist/hosts/environment.js +16 -0
- package/dist/hosts/next/sidecar.d.ts +4 -0
- package/dist/hosts/next/sidecar.js +56 -7
- package/dist/hosts/next/wrapper.d.ts +2 -0
- package/dist/hosts/next/wrapper.js +32 -3
- package/dist/hosts/projectBridge.d.ts +21 -0
- package/dist/hosts/projectBridge.js +98 -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 +3 -1
- package/dist/hosts/static/server.js +45 -3
- package/dist/hosts/vite/vite.d.ts +6 -1
- package/dist/hosts/vite/vite.js +82 -15
- package/dist/inspector/agent/McpConnectionDialog.d.ts +5 -4
- package/dist/inspector/agent/McpConnectionDialog.js +20 -37
- package/dist/inspector/agent/client.d.ts +16 -3
- package/dist/inspector/agent/client.js +114 -11
- package/dist/inspector/agent/connectionStatus.d.ts +3 -3
- package/dist/inspector/agent/connectionStatus.js +11 -4
- package/dist/inspector/agent/httpTransport.d.ts +8 -0
- package/dist/inspector/agent/httpTransport.js +78 -18
- package/dist/inspector/agent/protocol.d.ts +11 -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 +288 -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 +410 -72
- 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 +82 -5
- package/dist/inspector/canvas/frameProtocol.js +63 -2
- package/dist/inspector/canvas/keyboardShortcuts.d.ts +4 -0
- package/dist/inspector/canvas/keyboardShortcuts.js +16 -0
- package/dist/inspector/canvas/linkEligibility.d.ts +0 -5
- package/dist/inspector/canvas/linkEligibility.js +0 -29
- package/dist/inspector/canvas/projection.d.ts +7 -0
- package/dist/inspector/canvas/projection.js +118 -25
- package/dist/inspector/canvas/rendererBootstrap.js +42 -29
- package/dist/inspector/canvas/rendererElementSelector.d.ts +1 -1
- package/dist/inspector/canvas/rendererElementSelector.js +385 -58
- 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/changes/workspaceChanges.d.ts +4 -0
- package/dist/inspector/changes/workspaceChanges.js +29 -3
- package/dist/inspector/clientManifest.d.ts +7 -0
- package/dist/inspector/clientManifest.js +12 -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 +80 -32
- 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/DomNavigator.d.ts +10 -0
- package/dist/inspector/overlay/DomNavigator.js +40 -0
- package/dist/inspector/overlay/InspectorOverlay.js +6 -2
- package/dist/inspector/overlay/clickPolicy.d.ts +18 -2
- package/dist/inspector/overlay/clickPolicy.js +34 -3
- package/dist/inspector/overlay/elementSelector.d.ts +1 -1
- package/dist/inspector/overlay/elementSelector.js +18 -7
- package/dist/inspector/overlay/selectedGeometry.js +21 -2
- package/dist/inspector/overlay/spacingGestures.d.ts +45 -0
- package/dist/inspector/overlay/spacingGestures.js +351 -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 +5 -1
- package/dist/inspector/runtime/runtimeConfig.js +4 -0
- package/dist/inspector/selection/hierarchy.d.ts +6 -0
- package/dist/inspector/selection/hierarchy.js +8 -0
- package/dist/inspector/selection/selectionStore.js +2 -0
- package/dist/inspector/settings/SettingsDialog.d.ts +1 -1
- package/dist/inspector/settings/SettingsDialog.js +12 -2
- package/dist/inspector/shell/AppShell.js +5 -1
- package/dist/inspector/shell/ChangesLog.js +26 -22
- package/dist/inspector/shell/CopyPromptButton.js +102 -19
- package/dist/inspector/shell/EmptyState.js +1 -1
- package/dist/inspector/shell/InspectorShell.d.ts +0 -1
- package/dist/inspector/shell/InspectorShell.js +38 -42
- 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 +434 -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 +31 -33
- 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 +93 -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 +130 -7
- package/dist/inspector/tokens/TokensPanel.js +2 -1
- package/dist/inspector/tokens/dragPointerLock.d.ts +8 -0
- package/dist/inspector/tokens/dragPointerLock.js +70 -0
- 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/Disclosure.d.ts +22 -0
- package/dist/inspector/ui/Disclosure.js +13 -0
- 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/dragCursor.d.ts +8 -0
- package/dist/inspector/ui/dragCursor.js +21 -0
- package/dist/inspector/ui/styles.js +21 -17
- package/dist/internal/agent-protocol.d.ts +65 -1
- package/dist/internal/agent-protocol.js +183 -3
- package/dist/nudge-ui.mjs +276 -58
- package/dist/transport/editor.d.ts +47 -0
- package/dist/transport/editor.js +163 -0
- package/dist/transport/index.d.ts +1 -0
- package/dist/transport/index.js +1 -0
- package/dist/transport/routes.d.ts +10 -0
- package/dist/transport/routes.js +10 -0
- package/package.json +3 -1
- package/dist/inspector/shell/DomNavigation.d.ts +0 -8
- package/dist/inspector/shell/DomNavigation.js +0 -30
- package/dist/inspector/shell/panelLayout.d.ts +0 -2
- package/dist/inspector/shell/panelLayout.js +0 -29
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
import { PROTOCOL_VERSION, getRendererIdentity, sendToParent, } from "./frameProtocol.js";
|
|
2
|
-
import { findClosestAnchor, isEligibleNavigation, hasDifferentRoute, shouldPreserveNativeLinkActivation, } from "./linkEligibility.js";
|
|
1
|
+
import { PROTOCOL_VERSION, getRendererIdentity, sendToParent, isKeyboardShortcutCode, } from "./frameProtocol.js";
|
|
3
2
|
import { readBorderWidths, readMargins } from "../overlay/overlayGeometry.js";
|
|
4
3
|
import { installInteractionStyles } from "../overlay/interactionStyles.js";
|
|
5
4
|
import { createFrameThrottle } from "../overlay/frameThrottle.js";
|
|
6
5
|
import { createCidIndex } from "./rendererCidIndex.js";
|
|
7
6
|
import { isNudgeUiDev } from "../runtime/devFlag.js";
|
|
8
|
-
import { isEditableEvent } from "../shell/shortcuts.js";
|
|
7
|
+
import { isEditableEvent, isInspectorToggleShortcut, isSendPromptShortcut } from "../shell/shortcuts.js";
|
|
9
8
|
import { resolveSelectionTarget, selectionTargetMode } from "../selection/selectionTarget.js";
|
|
10
9
|
import { escapeCssString } from "../projection/cssEscapes.js";
|
|
11
|
-
import { blockApplicationClick,
|
|
10
|
+
import { APPLICATION_GESTURE_EVENTS, blockApplicationClick, blockApplicationGesture, isInlineEditorTarget, isUserClick, } from "../overlay/clickPolicy.js";
|
|
11
|
+
import { EMPTY_TEXT_PROJECTION_ATTR } from "../projection/textProjection.js";
|
|
12
|
+
import { getSpacingAffordanceAtPoint, toSpacingDescriptor, } from "../overlay/spacingGestures.js";
|
|
12
13
|
const REACT_FIBER_KEY = /^__reactFiber\$/;
|
|
13
14
|
const REACT_INTERNAL_KEY = /^__reactInternalInstance\$/;
|
|
15
|
+
const HOVER_SCROLL_SETTLE_DELAY = 150;
|
|
14
16
|
function findFiber(el) {
|
|
15
17
|
const keys = Object.keys(el);
|
|
16
18
|
for (const key of keys) {
|
|
@@ -75,24 +77,73 @@ export function buildSelector(el) {
|
|
|
75
77
|
}
|
|
76
78
|
let installed = false;
|
|
77
79
|
const noopDisposal = () => undefined;
|
|
78
|
-
export function installRendererElementSelector() {
|
|
80
|
+
export function installRendererElementSelector(acceptsClick = isUserClick) {
|
|
79
81
|
if (!isNudgeUiDev())
|
|
80
82
|
return noopDisposal;
|
|
81
83
|
if (installed)
|
|
82
84
|
return noopDisposal;
|
|
83
85
|
installed = true;
|
|
84
|
-
|
|
86
|
+
let removeInteractionStyles = installInteractionStyles();
|
|
85
87
|
const listenerCleanup = [];
|
|
86
88
|
let disposed = false;
|
|
89
|
+
let interactionsSuspended = false;
|
|
90
|
+
let scrolling = false;
|
|
91
|
+
let scrollSettleTimer = null;
|
|
92
|
+
let activeHoverElement = null;
|
|
93
|
+
let suppressHoverDuringSpacingDrag = false;
|
|
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 || suppressHoverDuringSpacingDrag)
|
|
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 || suppressHoverDuringSpacingDrag || !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,39 +245,189 @@ 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);
|
|
251
|
+
if (suppressHoverDuringSpacingDrag)
|
|
252
|
+
return;
|
|
148
253
|
const target = event.target;
|
|
149
254
|
if (!(target instanceof Element))
|
|
150
255
|
return;
|
|
151
256
|
const el = resolveSelectionTarget(target, selectionTargetMode(event));
|
|
152
257
|
if (!el)
|
|
153
258
|
return;
|
|
154
|
-
|
|
259
|
+
lastHoverPoint = { x: event.clientX, y: event.clientY, mode: selectionTargetMode(event) };
|
|
260
|
+
if (scrolling)
|
|
261
|
+
return;
|
|
262
|
+
hoverUpdate.schedule({ element: el, clear: false, point: { x: event.clientX, y: event.clientY } });
|
|
155
263
|
}, true);
|
|
264
|
+
trackListener(window, "scroll", suppressHoverDuringScroll, true);
|
|
156
265
|
let pendingDrag = null;
|
|
157
266
|
let dragging = false;
|
|
267
|
+
let lastDragPoint = null;
|
|
158
268
|
let lastSelected = null;
|
|
159
|
-
|
|
269
|
+
trackListener(window, "nudge-ui:open", () => {
|
|
270
|
+
const identity = getRendererIdentity();
|
|
271
|
+
if (!identity)
|
|
272
|
+
return;
|
|
273
|
+
const message = {
|
|
274
|
+
type: "inspector-open-request",
|
|
275
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
276
|
+
...identity,
|
|
277
|
+
};
|
|
278
|
+
sendToParent(message);
|
|
279
|
+
});
|
|
280
|
+
trackListener(window, "message", (event) => {
|
|
281
|
+
if (event.origin !== window.location.origin || event.source !== window.parent)
|
|
282
|
+
return;
|
|
283
|
+
const identity = getRendererIdentity();
|
|
284
|
+
const message = event.data;
|
|
285
|
+
if (!identity || !message
|
|
286
|
+
|| message.protocolVersion !== PROTOCOL_VERSION
|
|
287
|
+
|| message.projectId !== identity.projectId
|
|
288
|
+
|| message.workspaceId !== identity.workspaceId
|
|
289
|
+
|| message.cardId !== identity.cardId)
|
|
290
|
+
return;
|
|
291
|
+
if (message.type === "measure-modifier" && typeof message.altKey === "boolean") {
|
|
292
|
+
updateMeasureState(message.altKey, measurePointerOverPage);
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
if (message.type !== "inspector-interaction-state" || typeof message.open !== "boolean")
|
|
296
|
+
return;
|
|
297
|
+
const interactionsEnabled = message.interactionsEnabled === undefined
|
|
298
|
+
? message.open
|
|
299
|
+
: message.interactionsEnabled === true;
|
|
300
|
+
interactionsSuspended = !interactionsEnabled;
|
|
301
|
+
if (message.open) {
|
|
302
|
+
document.documentElement.setAttribute("data-nudge-ui-panel", "open");
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
document.documentElement.removeAttribute("data-nudge-ui-panel");
|
|
306
|
+
}
|
|
307
|
+
if (interactionsSuspended) {
|
|
308
|
+
cancelActiveDrag();
|
|
309
|
+
clearActiveHover();
|
|
310
|
+
if (scrollSettleTimer !== null)
|
|
311
|
+
window.clearTimeout(scrollSettleTimer);
|
|
312
|
+
scrollSettleTimer = null;
|
|
313
|
+
scrolling = false;
|
|
314
|
+
updateMeasureState(false, false);
|
|
315
|
+
removeInteractionStyles?.();
|
|
316
|
+
removeInteractionStyles = null;
|
|
317
|
+
}
|
|
318
|
+
else {
|
|
319
|
+
removeInteractionStyles ??= installInteractionStyles();
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
const dragMoveUpdate = createFrameThrottle((drag) => {
|
|
160
323
|
if (disposed)
|
|
161
324
|
return;
|
|
162
325
|
const identity = getRendererIdentity();
|
|
163
|
-
if (!
|
|
326
|
+
if (!drag || !identity)
|
|
164
327
|
return;
|
|
165
|
-
const msg = {
|
|
328
|
+
const msg = {
|
|
329
|
+
type: "element-drag-move",
|
|
330
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
331
|
+
point: drag.point,
|
|
332
|
+
shiftKey: drag.shiftKey,
|
|
333
|
+
...identity,
|
|
334
|
+
};
|
|
166
335
|
sendToParent(msg);
|
|
167
336
|
});
|
|
337
|
+
function sendDragEnd(point, cancelled, shiftKey = false) {
|
|
338
|
+
if (!dragging || !point)
|
|
339
|
+
return;
|
|
340
|
+
const identity = getRendererIdentity();
|
|
341
|
+
if (!identity)
|
|
342
|
+
return;
|
|
343
|
+
const msg = {
|
|
344
|
+
type: "element-drag-end",
|
|
345
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
346
|
+
point,
|
|
347
|
+
shiftKey,
|
|
348
|
+
...(cancelled ? { cancelled: true } : {}),
|
|
349
|
+
...identity,
|
|
350
|
+
};
|
|
351
|
+
sendToParent(msg);
|
|
352
|
+
}
|
|
353
|
+
function cancelActiveDrag() {
|
|
354
|
+
dragMoveUpdate.cancel();
|
|
355
|
+
sendDragEnd(lastDragPoint, true);
|
|
356
|
+
pendingDrag = null;
|
|
357
|
+
dragging = false;
|
|
358
|
+
suppressHoverDuringSpacingDrag = false;
|
|
359
|
+
}
|
|
168
360
|
trackListener(document, "mousedown", (event) => {
|
|
361
|
+
if (interactionsSuspended)
|
|
362
|
+
return;
|
|
169
363
|
if (event.button !== 0)
|
|
170
364
|
return;
|
|
171
365
|
const element = resolveSelectionTarget(event.target, selectionTargetMode(event));
|
|
172
366
|
if (!element)
|
|
173
367
|
return;
|
|
368
|
+
const spacingAffordance = getSpacingAffordanceAtPoint(document, event.clientX, event.clientY);
|
|
369
|
+
const spacing = spacingAffordance?.element === element
|
|
370
|
+
? toSpacingDescriptor(spacingAffordance)
|
|
371
|
+
: null;
|
|
372
|
+
if (spacing) {
|
|
373
|
+
suppressHoverDuringSpacingDrag = true;
|
|
374
|
+
hoverUpdate.cancel();
|
|
375
|
+
lastHoverPoint = null;
|
|
376
|
+
}
|
|
377
|
+
const identity = getRendererIdentity();
|
|
378
|
+
// A spacing drag owns the pointer gesture. Do not start an inline-text
|
|
379
|
+
// attempt for the same down event; padding and gaps are intentionally not
|
|
380
|
+
// editable text targets.
|
|
381
|
+
if (identity && !spacing) {
|
|
382
|
+
const emptyProjectionId = event.target instanceof Element
|
|
383
|
+
? event.target.closest(`[${EMPTY_TEXT_PROJECTION_ATTR}]`)?.getAttribute(EMPTY_TEXT_PROJECTION_ATTR) ?? undefined
|
|
384
|
+
: undefined;
|
|
385
|
+
const message = {
|
|
386
|
+
type: "inline-text-intent",
|
|
387
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
388
|
+
intent: emptyProjectionId && event.detail >= 2 ? "double-click" : "pointer-down",
|
|
389
|
+
cid: element.getAttribute("data-cid"),
|
|
390
|
+
src: element.getAttribute("data-src") ?? "",
|
|
391
|
+
elementId: cidIndex.elementId(element),
|
|
392
|
+
point: { x: event.clientX, y: event.clientY },
|
|
393
|
+
clickCount: event.detail,
|
|
394
|
+
emptyProjectionId,
|
|
395
|
+
...identity,
|
|
396
|
+
};
|
|
397
|
+
sendToParent(message);
|
|
398
|
+
}
|
|
174
399
|
lastSelected = element;
|
|
175
|
-
pendingDrag = {
|
|
400
|
+
pendingDrag = {
|
|
401
|
+
element,
|
|
402
|
+
point: { x: event.clientX, y: event.clientY },
|
|
403
|
+
spacing,
|
|
404
|
+
};
|
|
405
|
+
lastDragPoint = { x: event.clientX, y: event.clientY };
|
|
176
406
|
}, true);
|
|
407
|
+
for (const type of APPLICATION_GESTURE_EVENTS) {
|
|
408
|
+
trackListener(document, type, (event) => {
|
|
409
|
+
if (interactionsSuspended || !acceptsClick(event) || isInlineEditorTarget(event.target))
|
|
410
|
+
return;
|
|
411
|
+
blockApplicationGesture(event);
|
|
412
|
+
}, true);
|
|
413
|
+
}
|
|
177
414
|
trackListener(document, "mousemove", (event) => {
|
|
178
|
-
if (!pendingDrag)
|
|
415
|
+
if (!pendingDrag) {
|
|
416
|
+
if (interactionsSuspended)
|
|
417
|
+
return;
|
|
418
|
+
const target = event.target;
|
|
419
|
+
if (target instanceof Element) {
|
|
420
|
+
const mode = selectionTargetMode(event);
|
|
421
|
+
const element = resolveSelectionTarget(target, mode);
|
|
422
|
+
if (element) {
|
|
423
|
+
lastHoverPoint = { x: event.clientX, y: event.clientY, mode };
|
|
424
|
+
if (scrolling)
|
|
425
|
+
return;
|
|
426
|
+
hoverUpdate.schedule({ element, clear: false, point: { x: event.clientX, y: event.clientY } });
|
|
427
|
+
}
|
|
428
|
+
}
|
|
179
429
|
return;
|
|
430
|
+
}
|
|
180
431
|
if (!dragging && Math.hypot(event.clientX - pendingDrag.point.x, event.clientY - pendingDrag.point.y) < 6)
|
|
181
432
|
return;
|
|
182
433
|
const identity = getRendererIdentity();
|
|
@@ -184,41 +435,93 @@ export function installRendererElementSelector() {
|
|
|
184
435
|
return;
|
|
185
436
|
event.preventDefault();
|
|
186
437
|
const point = { x: event.clientX, y: event.clientY };
|
|
438
|
+
lastDragPoint = point;
|
|
187
439
|
if (!dragging) {
|
|
188
440
|
dragging = true;
|
|
189
441
|
const msg = {
|
|
190
442
|
type: "element-drag-start", protocolVersion: PROTOCOL_VERSION,
|
|
191
443
|
cid: pendingDrag.element.getAttribute("data-cid"), src: pendingDrag.element.getAttribute("data-src") ?? "",
|
|
192
|
-
elementId: cidIndex.elementId(pendingDrag.element), point,
|
|
444
|
+
elementId: cidIndex.elementId(pendingDrag.element), point,
|
|
445
|
+
startPoint: pendingDrag.point,
|
|
446
|
+
spacing: pendingDrag.spacing,
|
|
447
|
+
shiftKey: event.shiftKey,
|
|
448
|
+
...identity,
|
|
193
449
|
};
|
|
194
450
|
sendToParent(msg);
|
|
195
451
|
}
|
|
196
452
|
else {
|
|
197
|
-
dragMoveUpdate.schedule(point);
|
|
453
|
+
dragMoveUpdate.schedule({ point, shiftKey: event.shiftKey });
|
|
198
454
|
}
|
|
199
455
|
}, true);
|
|
200
456
|
function finishDrag(event) {
|
|
201
457
|
dragMoveUpdate.cancel();
|
|
202
458
|
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
|
-
}
|
|
459
|
+
event.preventDefault();
|
|
460
|
+
const point = { x: event.clientX, y: event.clientY };
|
|
461
|
+
lastDragPoint = point;
|
|
462
|
+
sendDragEnd(point, false, event.shiftKey);
|
|
212
463
|
}
|
|
213
464
|
pendingDrag = null;
|
|
214
465
|
dragging = false;
|
|
466
|
+
suppressHoverDuringSpacingDrag = false;
|
|
215
467
|
}
|
|
216
468
|
trackListener(document, "mouseup", finishDrag, true);
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
469
|
+
function forwardKeyboardShortcut(event, phase) {
|
|
470
|
+
const code = isKeyboardShortcutCode(event.code) ? event.code : null;
|
|
471
|
+
if (!code)
|
|
472
|
+
return false;
|
|
473
|
+
if (code === "KeyS") {
|
|
474
|
+
if (phase !== "keydown" || !isSendPromptShortcut(event))
|
|
475
|
+
return false;
|
|
476
|
+
}
|
|
477
|
+
else if (code !== "Backslash" && interactionsSuspended) {
|
|
478
|
+
return false;
|
|
479
|
+
}
|
|
480
|
+
if (phase === "keydown") {
|
|
481
|
+
if (code !== "KeyS" && (event.repeat || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey || isEditableEvent(event)))
|
|
482
|
+
return false;
|
|
483
|
+
}
|
|
484
|
+
else if (code !== "Backslash") {
|
|
485
|
+
return false;
|
|
486
|
+
}
|
|
487
|
+
const identity = getRendererIdentity();
|
|
488
|
+
if (!identity)
|
|
489
|
+
return false;
|
|
490
|
+
const message = {
|
|
491
|
+
type: "keyboard-shortcut",
|
|
492
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
493
|
+
phase,
|
|
494
|
+
code,
|
|
495
|
+
...identity,
|
|
496
|
+
};
|
|
497
|
+
sendToParent(message);
|
|
498
|
+
return phase === "keydown";
|
|
499
|
+
}
|
|
500
|
+
// Global tool shortcuts need to run before application capture handlers on
|
|
501
|
+
// the iframe document. A page-level window handler can otherwise stop the
|
|
502
|
+
// event before it reaches the document listener.
|
|
503
|
+
trackListener(window, "keydown", (event) => {
|
|
220
504
|
if (isEditableEvent(event))
|
|
221
505
|
return;
|
|
506
|
+
if (forwardKeyboardShortcut(event, "keydown"))
|
|
507
|
+
event.preventDefault();
|
|
508
|
+
if (isInspectorToggleShortcut(event)) {
|
|
509
|
+
const identity = getRendererIdentity();
|
|
510
|
+
if (!identity)
|
|
511
|
+
return;
|
|
512
|
+
event.preventDefault();
|
|
513
|
+
const msg = {
|
|
514
|
+
type: "inspector-toggle-request",
|
|
515
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
516
|
+
...identity,
|
|
517
|
+
};
|
|
518
|
+
sendToParent(msg);
|
|
519
|
+
return;
|
|
520
|
+
}
|
|
521
|
+
if (interactionsSuspended)
|
|
522
|
+
return;
|
|
523
|
+
if (event.key === "Alt")
|
|
524
|
+
updateMeasureState(true, measurePointerOverPage);
|
|
222
525
|
const scrollKey = event.code === "Space"
|
|
223
526
|
|| event.key === "ArrowUp"
|
|
224
527
|
|| event.key === "ArrowDown"
|
|
@@ -242,6 +545,8 @@ export function installRendererElementSelector() {
|
|
|
242
545
|
}
|
|
243
546
|
if (event.key === "Escape" || event.key === "Esc") {
|
|
244
547
|
event.preventDefault();
|
|
548
|
+
cancelActiveDrag();
|
|
549
|
+
clearSpacingCursor();
|
|
245
550
|
lastSelected = null;
|
|
246
551
|
const identity = getRendererIdentity();
|
|
247
552
|
if (!identity)
|
|
@@ -279,21 +584,28 @@ export function installRendererElementSelector() {
|
|
|
279
584
|
};
|
|
280
585
|
sendToParent(msg);
|
|
281
586
|
}, true);
|
|
282
|
-
trackListener(
|
|
587
|
+
trackListener(window, "keyup", (event) => {
|
|
588
|
+
forwardKeyboardShortcut(event, "keyup");
|
|
283
589
|
if (event.key === "Alt")
|
|
284
590
|
updateMeasureState(false, measurePointerOverPage);
|
|
285
591
|
}, true);
|
|
286
592
|
trackListener(window, "blur", () => {
|
|
593
|
+
cancelActiveDrag();
|
|
287
594
|
updateMeasureState(false, false);
|
|
288
595
|
});
|
|
289
596
|
trackListener(document, "mouseout", (event) => {
|
|
597
|
+
if (interactionsSuspended)
|
|
598
|
+
return;
|
|
290
599
|
const target = event.target;
|
|
291
600
|
if (!(target instanceof HTMLElement))
|
|
292
601
|
return;
|
|
293
602
|
const related = event.relatedTarget;
|
|
294
603
|
if (!(related instanceof Node) || !document.contains(related)) {
|
|
295
604
|
updateMeasureState(event.altKey, false);
|
|
605
|
+
lastHoverPoint = null;
|
|
296
606
|
}
|
|
607
|
+
if (scrolling)
|
|
608
|
+
return;
|
|
297
609
|
if (related instanceof Node && (target.contains(related) || target === related))
|
|
298
610
|
return;
|
|
299
611
|
if (!(target instanceof Element))
|
|
@@ -303,40 +615,47 @@ export function installRendererElementSelector() {
|
|
|
303
615
|
return;
|
|
304
616
|
if (resolveSelectionTarget(related, selectionTargetMode(event)))
|
|
305
617
|
return;
|
|
306
|
-
|
|
618
|
+
clearSpacingCursor();
|
|
619
|
+
hoverUpdate.schedule({ element: el, clear: true, point: null });
|
|
620
|
+
}, true);
|
|
621
|
+
trackListener(document, "dblclick", (event) => {
|
|
622
|
+
if (interactionsSuspended)
|
|
623
|
+
return;
|
|
624
|
+
const element = resolveSelectionTarget(event.target, selectionTargetMode(event));
|
|
625
|
+
const identity = getRendererIdentity();
|
|
626
|
+
if (!element || !identity)
|
|
627
|
+
return;
|
|
628
|
+
blockApplicationClick(event);
|
|
629
|
+
const message = {
|
|
630
|
+
type: "inline-text-intent",
|
|
631
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
632
|
+
intent: "double-click",
|
|
633
|
+
cid: element.getAttribute("data-cid"),
|
|
634
|
+
src: element.getAttribute("data-src") ?? "",
|
|
635
|
+
elementId: cidIndex.elementId(element),
|
|
636
|
+
point: { x: event.clientX, y: event.clientY },
|
|
637
|
+
emptyProjectionId: event.target instanceof Element
|
|
638
|
+
? event.target.closest(`[${EMPTY_TEXT_PROJECTION_ATTR}]`)?.getAttribute(EMPTY_TEXT_PROJECTION_ATTR) ?? undefined
|
|
639
|
+
: undefined,
|
|
640
|
+
...identity,
|
|
641
|
+
};
|
|
642
|
+
sendToParent(message);
|
|
307
643
|
}, true);
|
|
308
644
|
trackListener(document, "click", (event) => {
|
|
645
|
+
if (interactionsSuspended || !acceptsClick(event))
|
|
646
|
+
return;
|
|
309
647
|
const target = event.target;
|
|
310
648
|
if (!(target instanceof Element))
|
|
311
649
|
return;
|
|
312
|
-
//
|
|
313
|
-
//
|
|
314
|
-
// should create (or focus) a sibling card rather than selecting the anchor
|
|
315
|
-
// itself. The navigation-intent listener is registered AFTER this one, so
|
|
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.
|
|
319
|
-
const anchor = findClosestAnchor(target);
|
|
320
|
-
if (anchor && isEligibleNavigation(anchor, event) && hasDifferentRoute(anchor)) {
|
|
321
|
-
return;
|
|
322
|
-
}
|
|
323
|
-
// Command/Ctrl+Shift-click is the deliberate escape hatch for running
|
|
324
|
-
// the application action. All other selected canvas clicks are editing
|
|
325
|
-
// gestures and must not reach the rendered application.
|
|
326
|
-
if (isApplicationActivationClick(event))
|
|
327
|
-
return;
|
|
328
|
-
const preserveNativeLink = anchor
|
|
329
|
-
? shouldPreserveNativeLinkActivation(anchor, event)
|
|
330
|
-
: false;
|
|
650
|
+
// Design-tool clicks are editing gestures and must not reach the
|
|
651
|
+
// rendered application; the Select tool is how the app receives them.
|
|
331
652
|
const el = resolveSelectionTarget(target, selectionTargetMode(event));
|
|
332
653
|
if (!el) {
|
|
333
|
-
|
|
334
|
-
blockApplicationClick(event);
|
|
654
|
+
blockApplicationClick(event);
|
|
335
655
|
return;
|
|
336
656
|
}
|
|
337
657
|
lastSelected = el;
|
|
338
|
-
|
|
339
|
-
blockApplicationClick(event);
|
|
658
|
+
blockApplicationClick(event);
|
|
340
659
|
const cid = el.getAttribute("data-cid");
|
|
341
660
|
const selector = buildSelector(el);
|
|
342
661
|
const { file, line, component, src } = getFiberInfo(el);
|
|
@@ -361,18 +680,26 @@ export function installRendererElementSelector() {
|
|
|
361
680
|
return () => {
|
|
362
681
|
if (disposed)
|
|
363
682
|
return;
|
|
683
|
+
cancelActiveDrag();
|
|
364
684
|
disposed = true;
|
|
365
685
|
installed = false;
|
|
366
686
|
hoverUpdate.cancel();
|
|
367
|
-
|
|
687
|
+
if (scrollSettleTimer !== null)
|
|
688
|
+
window.clearTimeout(scrollSettleTimer);
|
|
689
|
+
scrollSettleTimer = null;
|
|
368
690
|
for (const cleanup of listenerCleanup)
|
|
369
691
|
cleanup();
|
|
370
692
|
listenerCleanup.length = 0;
|
|
371
|
-
removeInteractionStyles();
|
|
372
|
-
|
|
373
|
-
dragging = false;
|
|
693
|
+
removeInteractionStyles?.();
|
|
694
|
+
removeInteractionStyles = null;
|
|
374
695
|
lastSelected = null;
|
|
696
|
+
activeHoverElement = null;
|
|
697
|
+
lastHoverPoint = null;
|
|
698
|
+
scrolling = false;
|
|
699
|
+
suppressHoverDuringSpacingDrag = false;
|
|
375
700
|
measurePointerOverPage = false;
|
|
376
701
|
measureAltKey = false;
|
|
702
|
+
document.documentElement.removeAttribute("data-nudge-ui-panel");
|
|
703
|
+
clearSpacingCursor();
|
|
377
704
|
};
|
|
378
705
|
}
|
|
@@ -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
|
+
}
|