nudge-ui 0.2.4 → 0.2.5
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/dist/cli/agentCommand.js +4 -28
- package/dist/client.mjs +863 -213
- package/dist/hosts/next/wrapper.js +1 -7
- package/dist/hosts/projectBridge.js +3 -17
- package/dist/inspector/agent/McpConnectionDialog.js +7 -3
- package/dist/inspector/agent/activity.d.ts +1 -1
- package/dist/inspector/agent/activity.js +3 -2
- package/dist/inspector/agent/client.d.ts +2 -2
- package/dist/inspector/agent/client.js +28 -29
- package/dist/inspector/agent/connectionStatus.d.ts +3 -1
- package/dist/inspector/agent/connectionStatus.js +25 -0
- package/dist/inspector/agent/httpTransport.js +31 -147
- package/dist/inspector/agent/protocol.d.ts +1 -1
- package/dist/inspector/agent/protocol.js +1 -1
- package/dist/inspector/agent/verification.d.ts +1 -1
- package/dist/inspector/agent/verification.js +7 -4
- package/dist/inspector/boot.d.ts +3 -0
- package/dist/inspector/boot.js +297 -0
- package/dist/inspector/canvas/AgentActivityOverlay.d.ts +2 -1
- package/dist/inspector/canvas/AgentActivityOverlay.js +6 -3
- package/dist/inspector/canvas/CanvasCard.js +21 -12
- package/dist/inspector/canvas/CanvasElementOverlay.js +82 -127
- package/dist/inspector/canvas/CanvasToolbar.js +2 -1
- package/dist/inspector/canvas/CanvasWorkspace.js +74 -97
- package/dist/inspector/canvas/LockedWorkspaceNotice.d.ts +3 -2
- package/dist/inspector/canvas/LockedWorkspaceNotice.js +10 -6
- package/dist/inspector/canvas/PageCard.d.ts +10 -0
- package/dist/inspector/canvas/PageCard.js +51 -0
- package/dist/inspector/canvas/SketchToolOptions.d.ts +5 -0
- package/dist/inspector/canvas/SketchToolOptions.js +86 -0
- package/dist/inspector/canvas/StaleChangeIndicator.d.ts +1 -1
- package/dist/inspector/canvas/StaleChangeIndicator.js +1 -1
- package/dist/inspector/canvas/ToolOptionsDrawer.d.ts +21 -0
- package/dist/inspector/canvas/ToolOptionsDrawer.js +77 -0
- package/dist/inspector/canvas/activeCanvasDocument.d.ts +3 -2
- package/dist/inspector/canvas/assets/eraser.svg +28 -0
- package/dist/inspector/canvas/assets/pen.svg +25 -0
- package/dist/inspector/canvas/canvasFrame.d.ts +16 -0
- package/dist/inspector/canvas/canvasFrame.js +10 -0
- package/dist/inspector/canvas/canvasGestures.d.ts +0 -1
- package/dist/inspector/canvas/canvasGestures.js +0 -6
- package/dist/inspector/canvas/canvasStore.d.ts +6 -0
- package/dist/inspector/canvas/canvasStore.js +36 -1
- package/dist/inspector/canvas/frameConnection.d.ts +48 -0
- package/dist/inspector/canvas/frameConnection.js +73 -0
- package/dist/inspector/canvas/frameProtocol.d.ts +18 -1
- package/dist/inspector/canvas/frameProtocol.js +36 -0
- package/dist/inspector/canvas/pageSurface.d.ts +11 -0
- package/dist/inspector/canvas/pageSurface.js +34 -0
- package/dist/inspector/canvas/projection.d.ts +19 -9
- package/dist/inspector/canvas/projection.js +58 -31
- package/dist/inspector/canvas/rendererBootstrap.js +4 -1
- package/dist/inspector/canvas/rendererElementSelector.js +9 -1
- package/dist/inspector/canvas/rendererMessageRouter.d.ts +4 -5
- package/dist/inspector/canvas/rendererMessageRouter.js +12 -16
- package/dist/inspector/canvas/rendererSelectionProxy.d.ts +7 -1
- package/dist/inspector/canvas/rendererSelectionProxy.js +8 -36
- package/dist/inspector/canvas/rendererStylesheet.js +15 -0
- package/dist/inspector/canvas/sessionStore.d.ts +2 -2
- package/dist/inspector/canvas/sessionStore.js +12 -9
- package/dist/inspector/canvas/staleChangeDetector.d.ts +1 -1
- package/dist/inspector/canvas/staleChangeDetector.js +10 -22
- package/dist/inspector/changes/codecs.d.ts +1 -0
- package/dist/inspector/changes/codecs.js +20 -5
- package/dist/inspector/changes/draftPreview.d.ts +12 -0
- package/dist/inspector/changes/draftPreview.js +133 -0
- package/dist/inspector/changes/editModel.d.ts +8 -0
- package/dist/inspector/changes/editModel.js +8 -2
- package/dist/inspector/changes/managedStyleProjection.js +2 -1
- package/dist/inspector/changes/previewDiagnostics.js +1 -1
- package/dist/inspector/changes/types.d.ts +11 -1
- package/dist/inspector/comments/CommentsOverlay.js +18 -16
- package/dist/inspector/comments/store.js +3 -2
- package/dist/inspector/comments/verification.js +1 -1
- package/dist/inspector/componentSemantics/ComponentPropsSection.js +2 -1
- package/dist/inspector/componentSemantics/changeAction.js +1 -1
- package/dist/inspector/componentSemantics/textBinding.d.ts +1 -2
- package/dist/inspector/componentSemantics/textBinding.js +4 -45
- package/dist/inspector/drafts/draftStore.d.ts +109 -0
- package/dist/inspector/drafts/draftStore.js +451 -0
- package/dist/inspector/drafts/model.d.ts +9 -1
- package/dist/inspector/drafts/model.js +5 -1
- package/dist/inspector/drafts/store.d.ts +53 -15
- package/dist/inspector/drafts/store.js +143 -169
- package/dist/inspector/index.d.ts +2 -4
- package/dist/inspector/index.js +2 -264
- package/dist/inspector/inline-text/inlineTextEditor.d.ts +1 -1
- package/dist/inspector/inline-text/inlineTextEditor.js +1 -2
- package/dist/inspector/inline-text/textEditChange.d.ts +1 -1
- package/dist/inspector/inspection/bridge.d.ts +1 -1
- package/dist/inspector/inspection/bridge.js +2 -1
- package/dist/inspector/inspection/browserCssInspection.d.ts +8 -0
- package/dist/inspector/inspection/browserCssInspection.js +28 -6
- package/dist/inspector/inspection/inspectionSnapshot.d.ts +6 -0
- package/dist/inspector/inspection/inspectionSnapshot.js +10 -0
- package/dist/inspector/inspection/performanceDiagnostics.d.ts +18 -0
- package/dist/inspector/inspection/performanceDiagnostics.js +31 -0
- package/dist/inspector/inspection/useBrowserCssInspection.js +17 -38
- package/dist/inspector/iterations/capture.d.ts +2 -1
- package/dist/inspector/iterations/client.d.ts +2 -1
- package/dist/inspector/iterations/coordinator.d.ts +4 -3
- package/dist/inspector/iterations/coordinator.js +5 -3
- package/dist/inspector/iterations/prompt.js +9 -8
- package/dist/inspector/overlay/interactionStyles.js +17 -0
- package/dist/inspector/pageInspector.d.ts +42 -0
- package/dist/inspector/pageInspector.js +342 -0
- package/dist/inspector/projection/draftProjection.d.ts +10 -2
- package/dist/inspector/projection/draftProjection.js +9 -1
- package/dist/inspector/projection/managedStylesheet.js +24 -4
- package/dist/inspector/projection/renderedInstance.js +7 -1
- package/dist/inspector/projection/structuralProjection.d.ts +0 -9
- package/dist/inspector/projection/structuralProjection.js +14 -44
- package/dist/inspector/projection/textProjection.d.ts +8 -2
- package/dist/inspector/projection/textProjection.js +21 -13
- package/dist/inspector/prompt/clipboardHandoff.d.ts +9 -0
- package/dist/inspector/prompt/clipboardHandoff.js +42 -16
- package/dist/inspector/prompt/generatePrompt.d.ts +1 -1
- package/dist/inspector/prompt/generatePrompt.js +243 -147
- package/dist/inspector/prompt/promptDocument.d.ts +3 -0
- package/dist/inspector/prompt/promptDocument.js +8 -0
- package/dist/inspector/prompt/promptSettings.js +7 -5
- package/dist/inspector/runtime/inspectorStorage.d.ts +17 -0
- package/dist/inspector/runtime/inspectorStorage.js +42 -0
- package/dist/inspector/runtime/ownedStylesheets.d.ts +20 -0
- package/dist/inspector/runtime/ownedStylesheets.js +72 -0
- package/dist/inspector/runtime/runtimeConfig.d.ts +4 -0
- package/dist/inspector/runtime/runtimeConfig.js +10 -1
- package/dist/inspector/runtime/runtimeIdentityClaims.d.ts +29 -0
- package/dist/inspector/runtime/runtimeIdentityClaims.js +188 -0
- package/dist/inspector/runtime/staticHtmlRuntimeIdentity.d.ts +15 -0
- package/dist/inspector/runtime/staticHtmlRuntimeIdentity.js +113 -29
- package/dist/inspector/selection/editScope.d.ts +1 -0
- package/dist/inspector/selection/editScope.js +13 -2
- package/dist/inspector/shell/AgentStatusButton.js +2 -2
- package/dist/inspector/shell/AppShell.js +6 -2
- package/dist/inspector/shell/ChangesLog.js +27 -9
- package/dist/inspector/shell/CopyPromptButton.js +60 -54
- package/dist/inspector/shell/EmptyState.js +3 -3
- package/dist/inspector/shell/InspectorShell.d.ts +0 -3
- package/dist/inspector/shell/InspectorShell.js +21 -13
- package/dist/inspector/shell/PeekOriginalButton.js +3 -3
- package/dist/inspector/shell/interactionStatePreview.d.ts +9 -0
- package/dist/inspector/shell/interactionStatePreview.js +112 -0
- package/dist/inspector/shell/originalPreview.d.ts +3 -2
- package/dist/inspector/shell/originalPreview.js +10 -37
- package/dist/inspector/shell/stateValue.js +2 -3
- package/dist/inspector/sketch/SketchEditor.js +5 -4
- package/dist/inspector/sketch/SketchFrameOverlay.d.ts +2 -1
- package/dist/inspector/sketch/SketchFrameOverlay.js +5 -4
- package/dist/inspector/sketch/SketchOverlay.d.ts +3 -5
- package/dist/inspector/sketch/SketchOverlay.js +139 -263
- package/dist/inspector/sketch/SketchPromptPanel.d.ts +1 -1
- package/dist/inspector/sketch/SketchPromptPanel.js +8 -1
- package/dist/inspector/sketch/SketchThumbnail.d.ts +5 -0
- package/dist/inspector/sketch/SketchThumbnail.js +18 -0
- package/dist/inspector/sketch/SketchWorkspace.d.ts +1 -2
- package/dist/inspector/sketch/SketchWorkspace.js +69 -34
- package/dist/inspector/sketch/capture.js +19 -3
- package/dist/inspector/sketch/copySketch.d.ts +10 -0
- package/dist/inspector/sketch/copySketch.js +52 -0
- package/dist/inspector/sketch/drawingTools.d.ts +17 -0
- package/dist/inspector/sketch/drawingTools.js +47 -0
- package/dist/inspector/sketch/frameHeading.d.ts +9 -0
- package/dist/inspector/sketch/frameHeading.js +30 -0
- package/dist/inspector/sketch/freehand.js +3 -3
- package/dist/inspector/sketch/geometry.d.ts +6 -0
- package/dist/inspector/sketch/geometry.js +19 -0
- package/dist/inspector/sketch/history.d.ts +30 -0
- package/dist/inspector/sketch/history.js +58 -0
- package/dist/inspector/sketch/interaction.d.ts +1 -3
- package/dist/inspector/sketch/interaction.js +6 -9
- package/dist/inspector/sketch/model.d.ts +35 -1
- package/dist/inspector/sketch/model.js +116 -61
- package/dist/inspector/sketch/persistence.d.ts +14 -0
- package/dist/inspector/sketch/persistence.js +63 -7
- package/dist/inspector/sketch/raster.d.ts +6 -2
- package/dist/inspector/sketch/raster.js +43 -17
- package/dist/inspector/sketch/store.d.ts +1 -1
- package/dist/inspector/sketch/store.js +1 -1
- package/dist/inspector/sketch/videoFrames.d.ts +6 -0
- package/dist/inspector/sketch/videoFrames.js +81 -0
- package/dist/inspector/styleEditors/BackgroundEditor.js +2 -1
- package/dist/inspector/styleEditors/BorderEditor.js +30 -130
- package/dist/inspector/styleEditors/BorderRadiusEditor.js +8 -3
- package/dist/inspector/styleEditors/ImageBackgroundEditor.js +1 -1
- package/dist/inspector/styleEditors/LayoutSection.js +2 -2
- package/dist/inspector/styleEditors/borderModel.d.ts +42 -0
- package/dist/inspector/styleEditors/borderModel.js +114 -0
- package/dist/inspector/styleEditors/layoutValue.js +2 -3
- package/dist/inspector/tokens/TokenField.js +34 -3
- package/dist/inspector/tokens/TokensPanel.js +2 -1
- package/dist/inspector/tokens/editActions.d.ts +3 -3
- package/dist/inspector/tokens/editActions.js +9 -3
- package/dist/inspector/tokens/resolution/containerQueryEvaluator.d.ts +15 -0
- package/dist/inspector/tokens/resolution/containerQueryEvaluator.js +86 -0
- package/dist/inspector/tokens/resolution/cssomCollector.js +44 -9
- package/dist/inspector/tokens/resolution/nestedSelectors.d.ts +6 -0
- package/dist/inspector/tokens/resolution/nestedSelectors.js +67 -0
- package/dist/inspector/tokens/resolution/ruleMatching.js +23 -4
- package/dist/inspector/tokens/resolution.d.ts +6 -3
- package/dist/inspector/tokens/resolution.js +91 -112
- package/dist/inspector/tokens/tokenEdits.d.ts +1 -1
- package/dist/inspector/tokens/tokenEdits.js +1 -1
- package/dist/inspector/ui/InlineStyleWarning.js +2 -2
- package/dist/inspector/ui/InspectorStyle.d.ts +8 -0
- package/dist/inspector/ui/InspectorStyle.js +26 -0
- package/dist/inspector/ui/PopoverListbox.d.ts +2 -1
- package/dist/inspector/ui/PopoverListbox.js +3 -3
- package/dist/inspector/ui/Toast.d.ts +14 -0
- package/dist/inspector/ui/Toast.js +30 -0
- package/dist/inspector/ui/assets/canvasIllustration.d.ts +2 -0
- package/dist/inspector/ui/assets/canvasIllustration.js +21 -0
- package/dist/inspector/ui/assets/gridIllustration.d.ts +2 -0
- package/dist/inspector/ui/assets/{grid.svg → gridIllustration.js} +3 -2
- package/dist/inspector/ui/customCursors.d.ts +5 -0
- package/dist/inspector/ui/customCursors.js +32 -6
- package/dist/inspector/ui/styles.js +12 -10
- package/dist/inspector/workspace/commands.js +1 -2
- package/dist/inspector/workspace/controller.js +1 -2
- package/dist/inspector/workspace/handoff.js +3 -2
- package/dist/inspector/workspace/sentItems.d.ts +3 -6
- package/dist/inspector/workspace/sentItems.js +6 -24
- package/dist/inspector/workspace/timeline.d.ts +24 -10
- package/dist/inspector/workspace/timeline.js +118 -96
- package/dist/internal/agent-protocol.d.ts +50 -13
- package/dist/internal/agent-protocol.js +145 -19
- package/dist/nudge-ui.mjs +81 -65
- package/dist/project/mcpPackage.d.ts +8 -0
- package/dist/project/mcpPackage.js +60 -0
- package/package.json +12 -2
- package/dist/inspector/canvas/measurementProjection.d.ts +0 -8
- package/dist/inspector/canvas/measurementProjection.js +0 -16
- package/dist/inspector/changes/changesLog.d.ts +0 -49
- package/dist/inspector/changes/changesLog.js +0 -255
- package/dist/inspector/changes/draftChanges.d.ts +0 -58
- package/dist/inspector/changes/draftChanges.js +0 -304
- package/dist/inspector/conformance/projection.d.ts +0 -2
- package/dist/inspector/conformance/projection.js +0 -3
- package/dist/inspector/inline-text/textChangeBoundary.d.ts +0 -6
- package/dist/inspector/inline-text/textChangeBoundary.js +0 -1
- package/dist/inspector/overlay/InspectorOverlay.d.ts +0 -5
- package/dist/inspector/overlay/InspectorOverlay.js +0 -332
- package/dist/inspector/overlay/elementSelector.d.ts +0 -1
- package/dist/inspector/overlay/elementSelector.js +0 -111
- package/dist/inspector/sketch/SketchChanges.d.ts +0 -2
- package/dist/inspector/sketch/SketchChanges.js +0 -72
- package/dist/inspector/sketch/SketchEntryButton.d.ts +0 -4
- package/dist/inspector/sketch/SketchEntryButton.js +0 -11
- package/dist/inspector/sketch/SketchLayersPanel.d.ts +0 -2
- package/dist/inspector/sketch/SketchLayersPanel.js +0 -71
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
import { draftIdForCard } from "../drafts/store.js";
|
|
2
|
-
import { isPreviewableChange, isTokenChange, } from "../changes/
|
|
1
|
+
import { draftIdForCard, getActiveDraftChanges } from "../drafts/store.js";
|
|
2
|
+
import { isPreviewableChange, isTokenChange, } from "../changes/types.js";
|
|
3
3
|
import { changeKey } from "../changes/model.js";
|
|
4
4
|
import { beginPreviewAttempt, clearPreviewDiagnostics, getHostPreviewDocument, notifyPreviewDiagnostics, publishPreviewDiagnostic, } from "../changes/previewDiagnostics.js";
|
|
5
|
-
import { getActiveDraftChanges } from "../changes/draftChanges.js";
|
|
6
5
|
import { getCanvasPreviewDocument, getRegisteredFrames } from "./projection.js";
|
|
7
|
-
import {
|
|
6
|
+
import { subscribeCanvasRendererMessages } from "./rendererMessageRouter.js";
|
|
8
7
|
import { getCanvasCards } from "./canvasStore.js";
|
|
9
8
|
import { getCanvasMode } from "./viewStore.js";
|
|
10
|
-
import { isRendererMessageFor } from "./frameProtocol.js";
|
|
11
9
|
import { getNudgeUiRuntimeConfig } from "../runtime/runtimeConfig.js";
|
|
12
10
|
const VERIFICATION_TIMEOUT_MS = 5000;
|
|
13
11
|
const STALE_CHECK_DEBOUNCE_MS = 100;
|
|
@@ -15,6 +13,7 @@ let verificationTimer = null;
|
|
|
15
13
|
let debounceTimer = null;
|
|
16
14
|
let pendingChanges = null;
|
|
17
15
|
let pendingAttempts = new Map();
|
|
16
|
+
let stopFrameReady = null;
|
|
18
17
|
function checkSelectorInDocument(doc, selector) {
|
|
19
18
|
try {
|
|
20
19
|
return doc.querySelectorAll(selector).length > 0;
|
|
@@ -189,22 +188,10 @@ export function startStaleDetection(changes) {
|
|
|
189
188
|
verificationTimer = null;
|
|
190
189
|
notifyPreviewDiagnostics();
|
|
191
190
|
}, VERIFICATION_TIMEOUT_MS);
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
return;
|
|
197
|
-
const msg = event.data;
|
|
198
|
-
const frame = findCanvasFrameBySource(event.source);
|
|
199
|
-
if (!frame || !isRendererMessageFor(msg, {
|
|
200
|
-
projectId: PROJECT_ID,
|
|
201
|
-
workspaceId: WORKSPACE_ID,
|
|
202
|
-
cardId: frame.cardId,
|
|
203
|
-
}) || msg.type !== "frame-ready")
|
|
204
|
-
return;
|
|
205
|
-
if (!pendingChanges)
|
|
206
|
-
return;
|
|
207
|
-
scheduleStaleCheck();
|
|
191
|
+
stopFrameReady ??= subscribeCanvasRendererMessages(({ message }) => {
|
|
192
|
+
if (message.type === "frame-ready" && pendingChanges)
|
|
193
|
+
scheduleStaleCheck();
|
|
194
|
+
});
|
|
208
195
|
}
|
|
209
196
|
export function cancelStaleDetection() {
|
|
210
197
|
if (verificationTimer) {
|
|
@@ -217,7 +204,8 @@ export function cancelStaleDetection() {
|
|
|
217
204
|
}
|
|
218
205
|
pendingChanges = null;
|
|
219
206
|
pendingAttempts = new Map();
|
|
220
|
-
|
|
207
|
+
stopFrameReady?.();
|
|
208
|
+
stopFrameReady = null;
|
|
221
209
|
notifyPreviewDiagnostics();
|
|
222
210
|
}
|
|
223
211
|
export function isVerificationPending() {
|
|
@@ -34,6 +34,7 @@ export interface SerializableElementChange {
|
|
|
34
34
|
runtimeEvidence?: NonNullable<ElementChangeRecord["runtimeEvidence"]>;
|
|
35
35
|
sourceEvidence?: NonNullable<ElementChangeRecord["sourceEvidence"]>;
|
|
36
36
|
scope?: EditScope;
|
|
37
|
+
sourceInstanceCount?: number;
|
|
37
38
|
instanceOverride?: RenderedInstanceOverride;
|
|
38
39
|
state?: NonNullable<ElementChangeRecord["state"]>;
|
|
39
40
|
}
|
|
@@ -16,7 +16,7 @@ export function isSerializableElementChangeValue(value) {
|
|
|
16
16
|
|| !hasOnlyKeys(value, [
|
|
17
17
|
"kind", "cid", "file", "line", "column", "selector", "property",
|
|
18
18
|
"sourceProperty", "sourceAuthoredValue", "oldToken", "newToken", "rawValue",
|
|
19
|
-
"oldRawValue", "source", "runtimeEvidence", "sourceEvidence", "scope", "instanceOverride", "state",
|
|
19
|
+
"oldRawValue", "source", "runtimeEvidence", "sourceEvidence", "scope", "sourceInstanceCount", "instanceOverride", "state",
|
|
20
20
|
])
|
|
21
21
|
|| (value.kind !== undefined && value.kind !== "element")
|
|
22
22
|
|| typeof value.cid !== "string"
|
|
@@ -35,6 +35,7 @@ export function isSerializableElementChangeValue(value) {
|
|
|
35
35
|
|| (value.runtimeEvidence !== undefined && !isRuntimeElementEvidenceValue(value.runtimeEvidence))
|
|
36
36
|
|| (value.sourceEvidence !== undefined && !isSourceElementEvidenceValue(value.sourceEvidence))
|
|
37
37
|
|| !isEditScopeValue(value.scope)
|
|
38
|
+
|| (value.sourceInstanceCount !== undefined && (!Number.isSafeInteger(value.sourceInstanceCount) || value.sourceInstanceCount < 1))
|
|
38
39
|
|| (value.instanceOverride !== undefined && value.scope !== "rendered-instance")
|
|
39
40
|
|| (value.scope === "rendered-instance" && !isRenderedInstanceOverride(value.instanceOverride))
|
|
40
41
|
|| (value.state !== undefined && !isElementStateValue(value.state))) {
|
|
@@ -118,6 +119,7 @@ export function serializeElementChange(change) {
|
|
|
118
119
|
runtimeEvidence: change.runtimeEvidence ? { ...change.runtimeEvidence } : undefined,
|
|
119
120
|
sourceEvidence: change.sourceEvidence ? { ...change.sourceEvidence } : undefined,
|
|
120
121
|
scope: change.scope === "rendered-instance" ? "rendered-instance" : "source-site",
|
|
122
|
+
...(change.sourceInstanceCount !== undefined ? { sourceInstanceCount: change.sourceInstanceCount } : {}),
|
|
121
123
|
instanceOverride: change.scope === "rendered-instance" ? change.instanceOverride : undefined,
|
|
122
124
|
state: change.state,
|
|
123
125
|
};
|
|
@@ -163,6 +165,9 @@ export function serializeTextContentChange(change) {
|
|
|
163
165
|
props: change.target.props,
|
|
164
166
|
ariaLabel: change.target.ariaLabel,
|
|
165
167
|
beforeText: change.target.beforeText,
|
|
168
|
+
...(change.target.tagName !== undefined ? { tagName: change.target.tagName } : {}),
|
|
169
|
+
...(change.target.elementId !== undefined ? { elementId: change.target.elementId } : {}),
|
|
170
|
+
...(change.target.domPath !== undefined ? { domPath: change.target.domPath } : {}),
|
|
166
171
|
...(change.target.textNodePath?.length
|
|
167
172
|
? { textNodePath: [...change.target.textNodePath] }
|
|
168
173
|
: {}),
|
|
@@ -204,6 +209,7 @@ export function deserializeElementChange(serialized) {
|
|
|
204
209
|
runtimeEvidence: serialized.runtimeEvidence ? { ...serialized.runtimeEvidence } : undefined,
|
|
205
210
|
sourceEvidence: serialized.sourceEvidence ? { ...serialized.sourceEvidence } : undefined,
|
|
206
211
|
scope: serialized.scope ?? "source-site",
|
|
212
|
+
...(serialized.sourceInstanceCount !== undefined ? { sourceInstanceCount: serialized.sourceInstanceCount } : {}),
|
|
207
213
|
instanceOverride: serialized.scope === "rendered-instance" ? serialized.instanceOverride : undefined,
|
|
208
214
|
state: serialized.state,
|
|
209
215
|
};
|
|
@@ -248,6 +254,9 @@ export function deserializeTextContentChange(serialized) {
|
|
|
248
254
|
props: serialized.target.props,
|
|
249
255
|
ariaLabel: serialized.target.ariaLabel,
|
|
250
256
|
beforeText: serialized.target.beforeText,
|
|
257
|
+
...(serialized.target.tagName !== undefined ? { tagName: serialized.target.tagName } : {}),
|
|
258
|
+
...(serialized.target.elementId !== undefined ? { elementId: serialized.target.elementId } : {}),
|
|
259
|
+
...(serialized.target.domPath !== undefined ? { domPath: serialized.target.domPath } : {}),
|
|
251
260
|
...(serialized.target.textNodePath?.length
|
|
252
261
|
? { textNodePath: [...serialized.target.textNodePath] }
|
|
253
262
|
: {}),
|
|
@@ -327,18 +336,24 @@ function isComponentInvocationEvidenceValue(value) {
|
|
|
327
336
|
}
|
|
328
337
|
function isRuntimeElementEvidenceValue(value) {
|
|
329
338
|
return isRecord(value)
|
|
330
|
-
&& hasOnlyKeys(value, ["reason", "tagName", "text", "props", "ariaLabel"])
|
|
339
|
+
&& hasOnlyKeys(value, ["reason", "tagName", "text", "props", "ariaLabel", "domPath", "elementId"])
|
|
331
340
|
&& (value.reason === undefined || value.reason === "runtime-created" || value.reason === "unannotated")
|
|
332
341
|
&& typeof value.tagName === "string"
|
|
333
342
|
&& (typeof value.text === "string" || value.text === null)
|
|
334
343
|
&& (typeof value.props === "string" || value.props === null)
|
|
335
|
-
&& (typeof value.ariaLabel === "string" || value.ariaLabel === null)
|
|
344
|
+
&& (typeof value.ariaLabel === "string" || value.ariaLabel === null)
|
|
345
|
+
&& (value.domPath === undefined || typeof value.domPath === "string" || value.domPath === null)
|
|
346
|
+
&& (value.elementId === undefined || typeof value.elementId === "string" || value.elementId === null);
|
|
336
347
|
}
|
|
337
348
|
function isSourceElementEvidenceValue(value) {
|
|
338
349
|
return isRecord(value)
|
|
339
|
-
&& hasOnlyKeys(value, ["tagName", "props"])
|
|
350
|
+
&& hasOnlyKeys(value, ["tagName", "props", "text", "ariaLabel", "domPath", "elementId"])
|
|
340
351
|
&& typeof value.tagName === "string"
|
|
341
|
-
&& (typeof value.props === "string" || value.props === null)
|
|
352
|
+
&& (typeof value.props === "string" || value.props === null)
|
|
353
|
+
&& (value.text === undefined || typeof value.text === "string" || value.text === null)
|
|
354
|
+
&& (value.ariaLabel === undefined || typeof value.ariaLabel === "string" || value.ariaLabel === null)
|
|
355
|
+
&& (value.domPath === undefined || typeof value.domPath === "string" || value.domPath === null)
|
|
356
|
+
&& (value.elementId === undefined || typeof value.elementId === "string" || value.elementId === null);
|
|
342
357
|
}
|
|
343
358
|
function isTokenRefValue(value) {
|
|
344
359
|
if (value === null)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { DraftChangesSnapshot, DraftProjectionEvent } from "../drafts/draftStore.js";
|
|
2
|
+
/** The host document's preview of the active draft. */
|
|
3
|
+
export interface DraftPreview {
|
|
4
|
+
project(snapshot: DraftChangesSnapshot, event: DraftProjectionEvent): void;
|
|
5
|
+
dispose(): void;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Projects the active draft into the host document and verifies the managed
|
|
9
|
+
* CSS off the commit path (0044). Verification re-checks the full surviving
|
|
10
|
+
* set: a new rule can change cascade or specificity for earlier changes.
|
|
11
|
+
*/
|
|
12
|
+
export declare function createDraftPreview(readActive: () => DraftChangesSnapshot): DraftPreview;
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { getSelectedElement } from "../selection/selectionStore.js";
|
|
2
|
+
import { changeKey } from "./model.js";
|
|
3
|
+
import { verifyManagedStyleProjection } from "./managedStyleProjection.js";
|
|
4
|
+
import { isPreviewableChange } from "./types.js";
|
|
5
|
+
import { beginPreviewAttempt, clearPreviewDiagnostics, getHostPreviewDocument, publishPreviewDiagnostic, } from "./previewDiagnostics.js";
|
|
6
|
+
import { clearStructuralProjectionReports, pruneStructuralProjectionReports } from "../projection/structuralProjection.js";
|
|
7
|
+
import { applyHostDraftProjection, compileDraftProjection } from "../projection/draftProjection.js";
|
|
8
|
+
import { isEditorShellDocument } from "../runtime/editorShell.js";
|
|
9
|
+
import { isOriginalPreviewActive, subscribeOriginalPreview } from "../shell/originalPreview.js";
|
|
10
|
+
/**
|
|
11
|
+
* Projects the active draft into the host document and verifies the managed
|
|
12
|
+
* CSS off the commit path (0044). Verification re-checks the full surviving
|
|
13
|
+
* set: a new rule can change cascade or specificity for earlier changes.
|
|
14
|
+
*/
|
|
15
|
+
export function createDraftPreview(readActive) {
|
|
16
|
+
let pendingTargets = new Map();
|
|
17
|
+
let handle = null;
|
|
18
|
+
function reapply(snapshot) {
|
|
19
|
+
// While hold-to-view-original is active the host document intentionally
|
|
20
|
+
// shows the page without inspector changes. Releasing re-projects.
|
|
21
|
+
if (isOriginalPreviewActive())
|
|
22
|
+
return;
|
|
23
|
+
if (!isEditorShellDocument())
|
|
24
|
+
applyHostDraftProjection(compileDraftProjection(snapshot));
|
|
25
|
+
}
|
|
26
|
+
function flushVerification() {
|
|
27
|
+
handle = null;
|
|
28
|
+
// Probing the original preview would report the held-back changes as
|
|
29
|
+
// conflicts. Keep the pending targets; releasing re-verifies them.
|
|
30
|
+
if (isOriginalPreviewActive())
|
|
31
|
+
return;
|
|
32
|
+
const targets = pendingTargets;
|
|
33
|
+
pendingTargets = new Map();
|
|
34
|
+
// The editor shell has no application document. Renderer diagnostics are
|
|
35
|
+
// owned by renderer projection reports.
|
|
36
|
+
if (targets.size === 0 || isEditorShellDocument())
|
|
37
|
+
return;
|
|
38
|
+
const current = readActive();
|
|
39
|
+
const attempt = beginPreviewAttempt(getHostPreviewDocument(), current.revision);
|
|
40
|
+
if (!attempt)
|
|
41
|
+
return;
|
|
42
|
+
for (const change of current.changes) {
|
|
43
|
+
if (!isPreviewableChange(change))
|
|
44
|
+
continue;
|
|
45
|
+
const key = changeKey(change);
|
|
46
|
+
if (!targets.has(key))
|
|
47
|
+
continue;
|
|
48
|
+
const result = verifyManagedStyleProjection(change, targets.get(key) ?? null);
|
|
49
|
+
if (result)
|
|
50
|
+
publishPreviewDiagnostic(attempt, key, result);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function scheduleVerification() {
|
|
54
|
+
if (handle !== null)
|
|
55
|
+
return;
|
|
56
|
+
const view = typeof window !== "undefined" ? window : undefined;
|
|
57
|
+
if (view && typeof view.requestIdleCallback === "function") {
|
|
58
|
+
handle = view.requestIdleCallback(flushVerification, { timeout: 200 });
|
|
59
|
+
}
|
|
60
|
+
else if (view && typeof view.requestAnimationFrame === "function") {
|
|
61
|
+
handle = view.requestAnimationFrame(flushVerification);
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
handle = setTimeout(flushVerification, 0);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function markForVerification(snapshot, verificationTargets) {
|
|
68
|
+
const selectedElement = getSelectedElement()?.domElement ?? null;
|
|
69
|
+
let added = false;
|
|
70
|
+
for (const key of snapshot.changes.map(changeKey)) {
|
|
71
|
+
if (!pendingTargets.has(key))
|
|
72
|
+
added = true;
|
|
73
|
+
// Keep the latest commit context for a merged key. The element may be in
|
|
74
|
+
// an iframe, so this is also the document for verification.
|
|
75
|
+
pendingTargets.set(key, verificationTargets?.get(key) ?? selectedElement);
|
|
76
|
+
}
|
|
77
|
+
if (added)
|
|
78
|
+
scheduleVerification();
|
|
79
|
+
}
|
|
80
|
+
const stopOriginalPreview = subscribeOriginalPreview(() => {
|
|
81
|
+
if (isEditorShellDocument())
|
|
82
|
+
return;
|
|
83
|
+
const snapshot = readActive();
|
|
84
|
+
if (isOriginalPreviewActive()) {
|
|
85
|
+
applyHostDraftProjection({
|
|
86
|
+
sourceRevision: snapshot.revision,
|
|
87
|
+
managedStyles: { rules: [], css: "" },
|
|
88
|
+
instanceOverrides: [],
|
|
89
|
+
structuralChanges: [],
|
|
90
|
+
textContentChanges: [],
|
|
91
|
+
componentOverrides: [],
|
|
92
|
+
});
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
reapply(snapshot);
|
|
96
|
+
// A flush during the hold kept its targets without scheduling, so marking
|
|
97
|
+
// alone would find every key present and schedule nothing.
|
|
98
|
+
markForVerification(snapshot);
|
|
99
|
+
if (pendingTargets.size > 0)
|
|
100
|
+
scheduleVerification();
|
|
101
|
+
});
|
|
102
|
+
return {
|
|
103
|
+
project(snapshot, event) {
|
|
104
|
+
switch (event.kind) {
|
|
105
|
+
case "edit":
|
|
106
|
+
reapply(snapshot);
|
|
107
|
+
markForVerification(snapshot, event.verificationTargets);
|
|
108
|
+
return;
|
|
109
|
+
case "reconcile":
|
|
110
|
+
reapply(snapshot);
|
|
111
|
+
pruneStructuralProjectionReports(event.structuralIds);
|
|
112
|
+
markForVerification(snapshot);
|
|
113
|
+
return;
|
|
114
|
+
case "switch":
|
|
115
|
+
pendingTargets.clear();
|
|
116
|
+
reapply(snapshot);
|
|
117
|
+
markForVerification(snapshot);
|
|
118
|
+
return;
|
|
119
|
+
case "reset":
|
|
120
|
+
// A deferred verification must not inspect a new record with the
|
|
121
|
+
// selection context of the cleared one.
|
|
122
|
+
pendingTargets.clear();
|
|
123
|
+
clearPreviewDiagnostics();
|
|
124
|
+
clearStructuralProjectionReports();
|
|
125
|
+
reapply(snapshot);
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
dispose() {
|
|
129
|
+
stopOriginalPreview();
|
|
130
|
+
pendingTargets.clear();
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
}
|
|
@@ -18,6 +18,10 @@ export interface RenderedInstanceRef {
|
|
|
18
18
|
text: string | null;
|
|
19
19
|
/** An accessible name can distinguish icon-only repeated controls. */
|
|
20
20
|
ariaLabel?: string | null;
|
|
21
|
+
/** Rendered facts used to reattach generated identities after reload. */
|
|
22
|
+
tagName?: string;
|
|
23
|
+
domPath?: string | null;
|
|
24
|
+
elementId?: string | null;
|
|
21
25
|
/**
|
|
22
26
|
* The component invocation whose entire output is this element. Present
|
|
23
27
|
* only when evidence alone cannot tell identical outputs apart.
|
|
@@ -50,6 +54,10 @@ export interface TextProjectionTarget {
|
|
|
50
54
|
props: string | null;
|
|
51
55
|
ariaLabel: string | null;
|
|
52
56
|
beforeText: string;
|
|
57
|
+
/** Optional prompt details; never used to resolve or group text targets. */
|
|
58
|
+
tagName?: string;
|
|
59
|
+
elementId?: string | null;
|
|
60
|
+
domPath?: string | null;
|
|
53
61
|
/** Document-local evidence for a text node inside safe mixed markup. */
|
|
54
62
|
textNodePath?: readonly number[];
|
|
55
63
|
}
|
|
@@ -14,13 +14,16 @@ export function isRenderedInstanceRef(value) {
|
|
|
14
14
|
|| typeof source.cid !== "string"
|
|
15
15
|
|| typeof source.src !== "string"
|
|
16
16
|
|| !isRecord(locator)
|
|
17
|
-
|| !hasOnlyKeys(locator, ["kind", "occurrence", "props", "text", "ariaLabel", "invocation"]))
|
|
17
|
+
|| !hasOnlyKeys(locator, ["kind", "occurrence", "props", "text", "ariaLabel", "tagName", "domPath", "elementId", "invocation"]))
|
|
18
18
|
return false;
|
|
19
19
|
return locator.kind === "evidence"
|
|
20
20
|
&& Number.isSafeInteger(locator.occurrence) && locator.occurrence >= 0
|
|
21
21
|
&& (typeof locator.props === "string" || locator.props === null)
|
|
22
22
|
&& (typeof locator.text === "string" || locator.text === null)
|
|
23
23
|
&& (locator.ariaLabel === undefined || typeof locator.ariaLabel === "string" || locator.ariaLabel === null)
|
|
24
|
+
&& (locator.tagName === undefined || typeof locator.tagName === "string")
|
|
25
|
+
&& (locator.domPath === undefined || typeof locator.domPath === "string" || locator.domPath === null)
|
|
26
|
+
&& (locator.elementId === undefined || typeof locator.elementId === "string" || locator.elementId === null)
|
|
24
27
|
&& (locator.invocation === undefined || isInvocationRef(locator.invocation));
|
|
25
28
|
}
|
|
26
29
|
export function isRenderedInstanceOverride(value) {
|
|
@@ -46,7 +49,7 @@ export function isStyleRuleContextValue(value) {
|
|
|
46
49
|
}
|
|
47
50
|
export function isTextProjectionTargetValue(value) {
|
|
48
51
|
if (!isRecord(value)
|
|
49
|
-
|| !hasOnlyKeys(value, ["sourceSite", "occurrence", "props", "ariaLabel", "beforeText", "textNodePath"])) {
|
|
52
|
+
|| !hasOnlyKeys(value, ["sourceSite", "occurrence", "props", "ariaLabel", "beforeText", "textNodePath", "tagName", "elementId", "domPath"])) {
|
|
50
53
|
return false;
|
|
51
54
|
}
|
|
52
55
|
const occurrence = value.occurrence;
|
|
@@ -58,6 +61,9 @@ export function isTextProjectionTargetValue(value) {
|
|
|
58
61
|
|| (typeof props !== "string" && props !== null)
|
|
59
62
|
|| (typeof ariaLabel !== "string" && ariaLabel !== null)
|
|
60
63
|
|| typeof beforeText !== "string"
|
|
64
|
+
|| (value.tagName !== undefined && typeof value.tagName !== "string")
|
|
65
|
+
|| (value.elementId !== undefined && value.elementId !== null && typeof value.elementId !== "string")
|
|
66
|
+
|| (value.domPath !== undefined && value.domPath !== null && typeof value.domPath !== "string")
|
|
61
67
|
|| (textNodePath !== undefined
|
|
62
68
|
&& (!Array.isArray(textNodePath)
|
|
63
69
|
|| textNodePath.length === 0
|
|
@@ -2,6 +2,7 @@ import { verifyPreview } from "../projection/managedStylesheet.js";
|
|
|
2
2
|
import { getSelectedElement } from "../selection/selectionStore.js";
|
|
3
3
|
import { instanceSelector } from "../projection/renderedInstance.js";
|
|
4
4
|
import { selectorForInteractionState } from "../shell/styleState.js";
|
|
5
|
+
import { selectorForInteractionStatePreview } from "../shell/interactionStatePreview.js";
|
|
5
6
|
import { isComponentChange, isTextContentChange, isTokenChange, } from "./types.js";
|
|
6
7
|
import { tokenReference } from "./model.js";
|
|
7
8
|
function requestedStyleValue(change) {
|
|
@@ -81,7 +82,7 @@ export function verifyManagedStyleProjection(change, selectedElement, ownerDocum
|
|
|
81
82
|
let targets = [];
|
|
82
83
|
try {
|
|
83
84
|
const selector = selectorForManagedChange(change);
|
|
84
|
-
targets = selector ? Array.from(ownerDocument.querySelectorAll(selector)) : [];
|
|
85
|
+
targets = selector ? Array.from(ownerDocument.querySelectorAll(selectorForInteractionStatePreview(selector))) : [];
|
|
85
86
|
}
|
|
86
87
|
catch {
|
|
87
88
|
targets = [];
|
|
@@ -4,7 +4,7 @@ import type { EditScope, RenderedInstanceOverride, StyleRuleContext, TextContent
|
|
|
4
4
|
/** Bounded rendered facts retained for one element without an authored source location. */
|
|
5
5
|
export interface RuntimeElementEvidence {
|
|
6
6
|
/**
|
|
7
|
-
* Why the
|
|
7
|
+
* Why the element has no authored source location.
|
|
8
8
|
* Omitted by legacy records, which are all runtime-created DOM.
|
|
9
9
|
*/
|
|
10
10
|
reason?: "runtime-created" | "unannotated";
|
|
@@ -12,11 +12,19 @@ export interface RuntimeElementEvidence {
|
|
|
12
12
|
text: string | null;
|
|
13
13
|
props: string | null;
|
|
14
14
|
ariaLabel: string | null;
|
|
15
|
+
/** Nearest-ancestor selector path; omitted by records captured before it existed. */
|
|
16
|
+
domPath?: string | null;
|
|
17
|
+
elementId?: string | null;
|
|
15
18
|
}
|
|
16
19
|
/** Bounded authored facts for one annotated element. */
|
|
17
20
|
export interface SourceElementEvidence {
|
|
18
21
|
tagName: string;
|
|
19
22
|
props: string | null;
|
|
23
|
+
/** Rendered identification details; omitted by older saved changes. */
|
|
24
|
+
text?: string | null;
|
|
25
|
+
ariaLabel?: string | null;
|
|
26
|
+
domPath?: string | null;
|
|
27
|
+
elementId?: string | null;
|
|
20
28
|
}
|
|
21
29
|
export interface ElementChangeRecord {
|
|
22
30
|
kind?: "element";
|
|
@@ -45,6 +53,8 @@ export interface ElementChangeRecord {
|
|
|
45
53
|
/** Authored facts that relocate the source site after its position shifts. */
|
|
46
54
|
sourceEvidence?: SourceElementEvidence;
|
|
47
55
|
scope?: EditScope;
|
|
56
|
+
/** Matching rendered items when captured; presentation only, absent in older edits. */
|
|
57
|
+
sourceInstanceCount?: number;
|
|
48
58
|
/** Durable, controller-owned target for one rendered output. */
|
|
49
59
|
instanceOverride?: RenderedInstanceOverride;
|
|
50
60
|
state?: "base" | "hover" | "active" | "focus" | "focus-visible" | "disabled";
|
|
@@ -4,7 +4,9 @@ import { IconCheck, IconTrash } from "@tabler/icons-react";
|
|
|
4
4
|
import { useCanvasMode } from "../canvas/viewStore.js";
|
|
5
5
|
import { getRegisteredFrames } from "../canvas/projection.js";
|
|
6
6
|
import { subscribeCanvasRendererMessages } from "../canvas/rendererMessageRouter.js";
|
|
7
|
-
import {
|
|
7
|
+
import { measureFrameViewport, toViewportPoint } from "../canvas/frameConnection.js";
|
|
8
|
+
import { canvasFrameElement } from "../canvas/canvasFrame.js";
|
|
9
|
+
import { getElementComputedStyle } from "../runtime/domRealm.js";
|
|
8
10
|
import { captureRenderedInstance } from "../projection/renderedInstance.js";
|
|
9
11
|
import { IconButton } from "../ui/IconButton.js";
|
|
10
12
|
import { TextInput } from "../ui/TextInput.js";
|
|
@@ -12,21 +14,21 @@ import { commentFingerprint, commentViewport, resolveCommentElement } from "./el
|
|
|
12
14
|
import { commentRoute, getCommentClearRevision, isCommentToolActive, removeComment, saveComment, subscribeComments, useComments, useCommentToolActive } from "./store.js";
|
|
13
15
|
import { isReadingCommentSource, readCommentSource, reconcileComments } from "./verification.js";
|
|
14
16
|
const styles = ".comment-pin {\n position: fixed;\n z-index: 10;\n display: grid;\n place-items: center;\n width: var(--icon-size-large);\n height: var(--icon-size-large);\n padding: 0;\n border: 2px solid var(--surface-raised-2x);\n border-radius: 50%;\n background: var(--accent);\n box-shadow: var(--shadow-popup);\n cursor: pointer;\n pointer-events: auto;\n}\n\n.comment-editor-backdrop {\n position: fixed;\n inset: 0;\n z-index: 11;\n pointer-events: auto;\n}\n\n.comment-editor {\n position: fixed;\n z-index: 12;\n display: flex;\n align-items: center;\n gap: var(--space-4);\n width: min(384px, calc(100vw - 16px));\n box-sizing: border-box;\n padding: var(--space-8);\n border-radius: var(--radius-12);\n background: var(--surface-raised-2x);\n box-shadow: var(--shadow-popup);\n pointer-events: auto;\n}\n\n.comment-editor .text-input { flex: 1; min-width: 0; padding-inline: var(--space-8); }\n.comment-editor__error { position: absolute; top: 100%; left: 0; padding: var(--space-8); background: var(--surface-raised-2x); color: var(--text-primary); border-radius: var(--radius-control); }\n";
|
|
17
|
+
import { InspectorStyle } from "../ui/InspectorStyle.js";
|
|
15
18
|
function sameAnchor(left, right) {
|
|
16
19
|
return left?.left === right?.left && left?.top === right?.top;
|
|
17
20
|
}
|
|
18
21
|
function anchorFor(iframe, element) {
|
|
19
22
|
if (!element.isConnected || iframe.contentDocument !== element.ownerDocument)
|
|
20
23
|
return null;
|
|
21
|
-
// Focus view keeps
|
|
22
|
-
|
|
24
|
+
// Focus view keeps real frames mounted, but their pins must stay hidden.
|
|
25
|
+
const frameElement = canvasFrameElement(iframe);
|
|
26
|
+
if (frameElement && getElementComputedStyle(frameElement).visibility !== "visible")
|
|
23
27
|
return null;
|
|
24
|
-
const frame = iframe
|
|
28
|
+
const frame = measureFrameViewport(iframe);
|
|
25
29
|
const rect = element.getBoundingClientRect();
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
const top = frame.top + rect.top * scale;
|
|
29
|
-
if (top < frame.top || top > frame.bottom || left < frame.left || left > frame.right)
|
|
30
|
+
const { x: left, y: top } = toViewportPoint(frame, { x: rect.right, y: rect.top });
|
|
31
|
+
if (top < frame.top || top > frame.top + frame.height || left < frame.left || left > frame.left + frame.width)
|
|
30
32
|
return null;
|
|
31
33
|
return { left, top };
|
|
32
34
|
}
|
|
@@ -75,17 +77,17 @@ export function CommentsOverlay() {
|
|
|
75
77
|
window.addEventListener("keydown", dismissOnEscape, true);
|
|
76
78
|
return () => window.removeEventListener("keydown", dismissOnEscape, true);
|
|
77
79
|
}, [draft]);
|
|
78
|
-
useEffect(() => subscribeCanvasRendererMessages(({
|
|
80
|
+
useEffect(() => subscribeCanvasRendererMessages(({ frame, message }) => {
|
|
79
81
|
if (message.type === "element-click" && isCommentToolActive()) {
|
|
80
|
-
const element =
|
|
81
|
-
if (element
|
|
82
|
-
openDraft({ element, iframe });
|
|
83
|
-
}
|
|
82
|
+
const element = frame.element(message);
|
|
83
|
+
if (element)
|
|
84
|
+
openDraft({ element, iframe: frame.iframe });
|
|
84
85
|
}
|
|
85
86
|
if (message.type === "element-deselect")
|
|
86
87
|
setDraft(null);
|
|
87
|
-
|
|
88
|
-
|
|
88
|
+
const frameDocument = frame.document();
|
|
89
|
+
if (message.type === "frame-ready" && frameDocument) {
|
|
90
|
+
void reconcileComments(frameDocument).catch(() => undefined);
|
|
89
91
|
}
|
|
90
92
|
}), []);
|
|
91
93
|
useEffect(() => {
|
|
@@ -239,7 +241,7 @@ export function CommentsOverlay() {
|
|
|
239
241
|
}
|
|
240
242
|
if (mode !== "canvas")
|
|
241
243
|
return null;
|
|
242
|
-
return _jsxs(_Fragment, { children: [_jsx(
|
|
244
|
+
return _jsxs(_Fragment, { children: [_jsx(InspectorStyle, { css: styles }), comments.flatMap((comment) => [...anchors].filter(([key]) => key.startsWith(`${comment.id}:`)).map(([key, anchor]) => (_jsx("button", { type: "button", className: "comment-pin", "data-test": "comment-pin", "aria-label": `Comment: ${comment.note}`, title: comment.note, style: anchor, onClick: () => {
|
|
243
245
|
const bound = bindings.current.get(key);
|
|
244
246
|
if (bound)
|
|
245
247
|
openDraft({ ...bound, existing: comment });
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { inspectorStorage } from "../runtime/inspectorStorage.js";
|
|
1
2
|
import { useSyncExternalStore } from "react";
|
|
2
3
|
import { isRenderedInstanceRef } from "../changes/editModel.js";
|
|
3
4
|
import { useCanvasCards, useFocusedCardId, useSelectedCardId } from "../canvas/canvasStore.js";
|
|
@@ -29,7 +30,7 @@ export function getComments() {
|
|
|
29
30
|
loadedKey = key;
|
|
30
31
|
loadedDemo = demo;
|
|
31
32
|
try {
|
|
32
|
-
const saved = demo ? [] : JSON.parse(
|
|
33
|
+
const saved = demo ? [] : JSON.parse(inspectorStorage()?.getItem(key) ?? "[]");
|
|
33
34
|
comments = Array.isArray(saved) ? saved.filter(isComment) : [];
|
|
34
35
|
}
|
|
35
36
|
catch {
|
|
@@ -51,7 +52,7 @@ function publish(next) {
|
|
|
51
52
|
comments = next;
|
|
52
53
|
if (getNudgeUiRuntimeConfig().demo !== true) {
|
|
53
54
|
try {
|
|
54
|
-
|
|
55
|
+
inspectorStorage()?.setItem(storageKey(), JSON.stringify(next));
|
|
55
56
|
}
|
|
56
57
|
catch { }
|
|
57
58
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getDraftChanges } from "../
|
|
1
|
+
import { getDraftChanges } from "../drafts/store.js";
|
|
2
2
|
import { documentTarget, targetKey } from "../drafts/model.js";
|
|
3
3
|
import { isCanvasProjectionRevisionCurrent, projectDraftToDocument } from "../canvas/projection.js";
|
|
4
4
|
import { commentFingerprint, commentViewport, resolveCommentElement } from "./element.js";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { isComponentChange
|
|
2
|
+
import { isComponentChange } from "../changes/types.js";
|
|
3
|
+
import { useChanges } from "../drafts/store.js";
|
|
3
4
|
import { FieldRow } from "../ui/FieldRow.js";
|
|
4
5
|
import { Select } from "../ui/Select.js";
|
|
5
6
|
import { SegmentedControl } from "../ui/SegmentedControl.js";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { appendChange } from "../
|
|
1
|
+
import { appendChange } from "../drafts/store.js";
|
|
2
2
|
import { createComponentPropChange } from "./changeModel.js";
|
|
3
3
|
export { createComponentPropChange } from "./changeModel.js";
|
|
4
4
|
export function setComponentProp(target, prop, value) {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { ComponentChangeTarget, EditableComponentTarget } from "./types.js";
|
|
2
|
-
import type { TextProjectionTarget } from "../
|
|
3
|
-
import type { TextBindingEvidence, TextProjectionScope } from "../inline-text/textChangeBoundary.js";
|
|
2
|
+
import type { TextBindingEvidence, TextProjectionScope, TextProjectionTarget } from "../changes/editModel.js";
|
|
4
3
|
/** The order used when more than one visible prop has the same value. */
|
|
5
4
|
export declare const VISIBLE_TEXT_PROP_PRIORITY: readonly ["children", "label", "text", "caption", "description", "title"];
|
|
6
5
|
export type TextEditRejectionReason = "no-text" | "no-binding" | "ambiguous-binding" | "editing-active" | "unsafe-target";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { callsiteMultiplicity, editableComponentTargets, inspectComponentTargets, } from "./adapterRegistry.js";
|
|
2
|
-
import { captureTextProjectionTarget, resolveTextProjectionTextNode, textProjectionSelector, } from "../projection/textProjection.js";
|
|
2
|
+
import { captureTextProjectionTarget, hasSafeMixedDescendants, isInApplicationEditingHost, isUnsafeTextHost, resolveTextProjectionTextNode, textProjectionSelector, } from "../projection/textProjection.js";
|
|
3
3
|
/** The order used when more than one visible prop has the same value. */
|
|
4
4
|
export const VISIBLE_TEXT_PROP_PRIORITY = [
|
|
5
5
|
"children",
|
|
@@ -17,24 +17,6 @@ const STRUCTURAL_TEXT_PROPS = new Set([
|
|
|
17
17
|
"role",
|
|
18
18
|
"style",
|
|
19
19
|
]);
|
|
20
|
-
const UNSAFE_TEXT_TAGS = new Set(["SCRIPT", "STYLE", "TEXTAREA", "OPTION"]);
|
|
21
|
-
const UNSAFE_MIXED_DESCENDANT_TAGS = new Set([
|
|
22
|
-
...UNSAFE_TEXT_TAGS,
|
|
23
|
-
"INPUT",
|
|
24
|
-
"SELECT",
|
|
25
|
-
"BUTTON",
|
|
26
|
-
"A",
|
|
27
|
-
"B",
|
|
28
|
-
"STRONG",
|
|
29
|
-
"I",
|
|
30
|
-
"EM",
|
|
31
|
-
"U",
|
|
32
|
-
"MARK",
|
|
33
|
-
"CODE",
|
|
34
|
-
"S",
|
|
35
|
-
"DEL",
|
|
36
|
-
"INS",
|
|
37
|
-
]);
|
|
38
20
|
function isStructuralTextProp(name) {
|
|
39
21
|
return STRUCTURAL_TEXT_PROPS.has(name)
|
|
40
22
|
|| name.startsWith("data")
|
|
@@ -62,9 +44,6 @@ function isApplicationEditingTextNode(element, textNode) {
|
|
|
62
44
|
&& editingHost.getAttribute("contenteditable") !== "false"
|
|
63
45
|
&& (editingHost === element || element.contains(editingHost) || editingHost.contains(element));
|
|
64
46
|
}
|
|
65
|
-
function isUnsafeSemanticHost(element) {
|
|
66
|
-
return UNSAFE_TEXT_TAGS.has(element.tagName);
|
|
67
|
-
}
|
|
68
47
|
function isVisibleTextProp(name) {
|
|
69
48
|
return VISIBLE_TEXT_PROP_PRIORITY.some((candidate) => candidate === name);
|
|
70
49
|
}
|
|
@@ -107,33 +86,13 @@ function textNodesFor(element) {
|
|
|
107
86
|
return nodes;
|
|
108
87
|
}
|
|
109
88
|
function isSafeRenderedTextHost(element, textNode) {
|
|
110
|
-
if (
|
|
111
|
-
return false;
|
|
112
|
-
const editingHost = element.closest("[contenteditable]");
|
|
113
|
-
if (editingHost
|
|
114
|
-
&& editingHost.getAttribute("data-inline-editor") !== "true"
|
|
115
|
-
&& editingHost.getAttribute("contenteditable") !== "false")
|
|
89
|
+
if (isUnsafeTextHost(element) || isInApplicationEditingHost(element))
|
|
116
90
|
return false;
|
|
117
91
|
if (element.children.length === 0) {
|
|
118
92
|
const directTextNodes = Array.from(element.childNodes).filter((node) => node.nodeType === 3);
|
|
119
93
|
return directTextNodes.length === 1 && directTextNodes[0] === textNode;
|
|
120
94
|
}
|
|
121
|
-
|
|
122
|
-
return false;
|
|
123
|
-
// A line break is layout structure, not rich text content. When the exact
|
|
124
|
-
// text node is captured, wrapping that node leaves the <br> in place and
|
|
125
|
-
// preserves both lines. Other inline formatting remains rejected because
|
|
126
|
-
// replacing text inside it would silently flatten authored markup.
|
|
127
|
-
for (const descendant of Array.from(element.querySelectorAll("*"))) {
|
|
128
|
-
if (UNSAFE_MIXED_DESCENDANT_TAGS.has(descendant.tagName))
|
|
129
|
-
return false;
|
|
130
|
-
const descendantEditingHost = descendant.closest("[contenteditable]");
|
|
131
|
-
if (descendantEditingHost
|
|
132
|
-
&& descendantEditingHost.getAttribute("data-inline-editor") !== "true"
|
|
133
|
-
&& descendantEditingHost.getAttribute("contenteditable") !== "false")
|
|
134
|
-
return false;
|
|
135
|
-
}
|
|
136
|
-
return true;
|
|
95
|
+
return element.contains(textNode) && hasSafeMixedDescendants(element);
|
|
137
96
|
}
|
|
138
97
|
function textNodeAtPoint(element, point) {
|
|
139
98
|
const nodes = textNodesFor(element);
|
|
@@ -383,7 +342,7 @@ export function resolveTextBinding(element, point) {
|
|
|
383
342
|
// markup is intentionally not included: a confident semantic component
|
|
384
343
|
// binding may still own a nested text node, while rendered fallback keeps
|
|
385
344
|
// its stricter direct-leaf requirement.
|
|
386
|
-
if (
|
|
345
|
+
if (isUnsafeTextHost(element)) {
|
|
387
346
|
return {
|
|
388
347
|
kind: "rejected",
|
|
389
348
|
reason: "unsafe-target",
|