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,7 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { useMemo, useSyncExternalStore } from "react";
|
|
2
|
+
import { useMemo, useState, useSyncExternalStore } from "react";
|
|
3
3
|
import { IconArrowBackUp } from "@tabler/icons-react";
|
|
4
|
-
import { isComponentChange, isElementChange, isTextContentChange, isTokenChange,
|
|
4
|
+
import { isComponentChange, isElementChange, isTextContentChange, isTokenChange, } from "../changes/types.js";
|
|
5
|
+
import { useChanges, revertChange } from "../drafts/store.js";
|
|
5
6
|
import { StaleChangeIndicator } from "../canvas/StaleChangeIndicator.js";
|
|
6
7
|
import { Button } from "../ui/Button.js";
|
|
7
8
|
import { Disclosure } from "../ui/Disclosure.js";
|
|
@@ -11,8 +12,8 @@ import { presentChange } from "../changes/presentation.js";
|
|
|
11
12
|
import { getStructuralChanges, getStructuralChangeDiagnostics, getStructuralDiagnosticRevision, revertStructuralChange, subscribeStructuralChanges, subscribeStructuralDiagnostics, } from "../projection/structuralProjection.js";
|
|
12
13
|
import { getRenderedInstanceChangeDiagnostics, getRenderedInstanceDiagnosticRevision, subscribeRenderedInstanceDiagnostics, } from "../projection/renderedInstance.js";
|
|
13
14
|
import { getTextContentChangeDiagnostics, getTextProjectionDiagnosticRevision, subscribeTextProjectionDiagnostics, } from "../projection/textProjection.js";
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
15
|
+
import { removeSketch, useSketchStore } from "../sketch/store.js";
|
|
16
|
+
import { StatusCallout } from "../ui/StatusCallout.js";
|
|
16
17
|
import { useFrameComments } from "../comments/store.js";
|
|
17
18
|
import { countPromptChanges } from "../prompt/generatePrompt.js";
|
|
18
19
|
function groupChanges(changes) {
|
|
@@ -75,8 +76,25 @@ function changeActionLabel(change, presentation) {
|
|
|
75
76
|
return "Changed text";
|
|
76
77
|
return `Changed ${presentation.propertyLabel}`;
|
|
77
78
|
}
|
|
78
|
-
function RevertButton({ dataTest, dataProperty, onClick, }) {
|
|
79
|
-
return (_jsx(Tooltip, { content:
|
|
79
|
+
function RevertButton({ dataTest, dataProperty, onClick, disabled, label = "Revert change", tooltip = "Revert", }) {
|
|
80
|
+
return (_jsx(Tooltip, { content: tooltip, stableTrigger: true, children: _jsx(IconButton, { variant: "quiet", size: "compact", className: "changes__revert", "data-test": dataTest, "data-property": dataProperty, label: label, disabled: disabled, onClick: onClick, children: _jsx(IconArrowBackUp, { size: "var(--icon-size-small)", stroke: "var(--icon-stroke-width)", "aria-hidden": "true" }) }) }));
|
|
81
|
+
}
|
|
82
|
+
function SketchChangeRow({ item }) {
|
|
83
|
+
const [error, setError] = useState(null);
|
|
84
|
+
const note = item.document.description.trim()
|
|
85
|
+
|| item.document.annotations?.map((annotation) => annotation.description).join("; ");
|
|
86
|
+
const busy = item.status === "dispatching" || item.status === "handing-off";
|
|
87
|
+
async function remove() {
|
|
88
|
+
setError(null);
|
|
89
|
+
try {
|
|
90
|
+
if (!await removeSketch(item.document.id))
|
|
91
|
+
setError("The sketch could not be removed yet.");
|
|
92
|
+
}
|
|
93
|
+
catch (cause) {
|
|
94
|
+
setError(cause instanceof Error ? cause.message : "The sketch could not be removed.");
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return (_jsxs("div", { className: "changes__group", children: [_jsxs("div", { className: "changes__row changes__row--sketch", "data-test": "sketch-row", "data-sketch-id": item.document.id, children: [_jsxs("div", { className: "changes__summary", children: [_jsx("span", { className: "changes__target", children: "Sketch" }), note ? _jsx("span", { className: "changes__action", title: note, children: note }) : null] }), _jsx(RevertButton, { dataTest: "sketch-revert", label: "Remove sketch", tooltip: "Remove sketch", disabled: busy, onClick: () => void remove() })] }), error ? _jsx(StatusCallout, { tone: "warning", role: "status", children: error }) : null] }));
|
|
80
98
|
}
|
|
81
99
|
export function ChangesLog({ onClearSession }) {
|
|
82
100
|
const changes = useChanges();
|
|
@@ -103,8 +121,8 @@ export function ChangesLog({ onClearSession }) {
|
|
|
103
121
|
const textDiagnostics = change.kind === "text-content"
|
|
104
122
|
? getTextContentChangeDiagnostics(change.id)
|
|
105
123
|
: [];
|
|
106
|
-
return (_jsxs("div", { className: "changes__row", "data-test": "change-row", "data-property": presentation.property, children: [_jsx("span", { className: "changes__target", "data-test": "change-target", children: changeTargetLabel(change, presentation) }), _jsx("span", { className: "changes__action", "data-test": "change-action", children: changeActionLabel(change, presentation) }), _jsxs("span", { className: "changes__metadata", "aria-hidden": "true", children: [_jsx("span", { className: "changes__prop", children: presentation.propertyLabel }), _jsxs("span", { className: "changes__value", children: [_jsx("span", { className: "changes__before", children: presentation.before }), _jsx("span", { className: "changes__arrow", children: "\u2192" }), _jsx("span", { className: "changes__after", children: presentation.after })] }), presentation.scope ? (_jsx("span", { className: "changes__scope", "data-test": "change-scope", children: presentation.scope === "source-site" ? "All outputs at source site" : "This rendered item only" })) : null, presentation.evidence ? (_jsx("span", { className: "changes__evidence", "data-test": "change-evidence", children: presentation.evidence })) : null, _jsx(StaleChangeIndicator, { change: change }), instanceDiagnostics.map((diagnostic) => (_jsxs("span", { className: "changes__diagnostic", "data-test": "instance-diagnostic", "data-document": diagnostic.document, "data-status": diagnostic.status, children: [diagnostic.document, ": ", diagnostic.status] }, `${diagnostic.document}:${diagnostic.status}`))), textDiagnostics.map((diagnostic) => (_jsxs("span", { className: "changes__diagnostic", "data-test": "text-projection-diagnostic", "data-document": diagnostic.document, "data-status": diagnostic.status, children: [diagnostic.document, ": ", diagnostic.status] }, `${diagnostic.document}:${diagnostic.status}`)))] }), _jsx(RevertButton, { dataTest: "change-revert", dataProperty: presentation.property, onClick: () => revertChange(change) })] }, `${group.key}\u0000${presentation.property}\u0000${i}`));
|
|
107
|
-
}) }, group.key))), structuralChanges.map((change) => (_jsx("div", { className: "changes__group", "data-test": "dom-change", "data-cid": change.target.sourceSite.cid, children: _jsxs("div", { className: "changes__row", "data-test": "dom-change-row", "data-action": change.kind, children: [_jsx("span", { className: "changes__target", "data-test": "structural-target", children: change.target.sourceSite.cid }), _jsx("span", { className: "changes__action", "data-test": "structural-action", children: change.kind === "move" ? "Moved" : "Deleted" }), _jsxs("span", { className: "changes__metadata", "aria-hidden": "true", children: [_jsxs("span", { className: "changes__source-site", "data-test": "structural-source-site", children: ["Source site: ", change.target.sourceSite.cid] }), _jsx("span", { className: "changes__prop", children: change.kind === "move" ? "Move in DOM" : "Delete from DOM" }), _jsxs("span", { className: "changes__value", children: [_jsx("span", { className: "changes__before", children: change.kind === "move"
|
|
124
|
+
return (_jsxs("div", { className: "changes__row", "data-test": "change-row", "data-property": presentation.property, children: [_jsxs("div", { className: "changes__summary", children: [_jsx("span", { className: "changes__target", "data-test": "change-target", children: changeTargetLabel(change, presentation) }), _jsx("span", { className: "changes__action", "data-test": "change-action", children: changeActionLabel(change, presentation) })] }), _jsxs("span", { className: "changes__metadata", "aria-hidden": "true", children: [_jsx("span", { className: "changes__prop", children: presentation.propertyLabel }), _jsxs("span", { className: "changes__value", children: [_jsx("span", { className: "changes__before", children: presentation.before }), _jsx("span", { className: "changes__arrow", children: "\u2192" }), _jsx("span", { className: "changes__after", children: presentation.after })] }), presentation.scope ? (_jsx("span", { className: "changes__scope", "data-test": "change-scope", children: presentation.scope === "source-site" ? "All outputs at source site" : "This rendered item only" })) : null, presentation.evidence ? (_jsx("span", { className: "changes__evidence", "data-test": "change-evidence", children: presentation.evidence })) : null, _jsx(StaleChangeIndicator, { change: change }), instanceDiagnostics.map((diagnostic) => (_jsxs("span", { className: "changes__diagnostic", "data-test": "instance-diagnostic", "data-document": diagnostic.document, "data-status": diagnostic.status, children: [diagnostic.document, ": ", diagnostic.status] }, `${diagnostic.document}:${diagnostic.status}`))), textDiagnostics.map((diagnostic) => (_jsxs("span", { className: "changes__diagnostic", "data-test": "text-projection-diagnostic", "data-document": diagnostic.document, "data-status": diagnostic.status, children: [diagnostic.document, ": ", diagnostic.status] }, `${diagnostic.document}:${diagnostic.status}`)))] }), _jsx(RevertButton, { dataTest: "change-revert", dataProperty: presentation.property, onClick: () => revertChange(change) })] }, `${group.key}\u0000${presentation.property}\u0000${i}`));
|
|
125
|
+
}) }, group.key))), structuralChanges.map((change) => (_jsx("div", { className: "changes__group", "data-test": "dom-change", "data-cid": change.target.sourceSite.cid, children: _jsxs("div", { className: "changes__row", "data-test": "dom-change-row", "data-action": change.kind, children: [_jsxs("div", { className: "changes__summary", children: [_jsx("span", { className: "changes__target", "data-test": "structural-target", children: change.target.sourceSite.cid }), _jsx("span", { className: "changes__action", "data-test": "structural-action", children: change.kind === "move" ? "Moved" : "Deleted" })] }), _jsxs("span", { className: "changes__metadata", "aria-hidden": "true", children: [_jsxs("span", { className: "changes__source-site", "data-test": "structural-source-site", children: ["Source site: ", change.target.sourceSite.cid] }), _jsx("span", { className: "changes__prop", children: change.kind === "move" ? "Move in DOM" : "Delete from DOM" }), _jsxs("span", { className: "changes__value", children: [_jsx("span", { className: "changes__before", children: change.kind === "move"
|
|
108
126
|
? structuralParentIdentityKey(change.source.parent) === structuralParentIdentityKey(change.destination.parent)
|
|
109
127
|
? `${change.presentation.sourceParentTag} position ${change.presentation.fromIndex + 1}`
|
|
110
128
|
: `${structuralParentLabel(change, "source")} position ${change.presentation.fromIndex + 1}`
|
|
@@ -112,5 +130,5 @@ export function ChangesLog({ onClearSession }) {
|
|
|
112
130
|
? structuralParentIdentityKey(change.source.parent) === structuralParentIdentityKey(change.destination.parent)
|
|
113
131
|
? `${change.presentation.destinationParentTag} position ${change.presentation.toIndex + 1}`
|
|
114
132
|
: `${structuralParentLabel(change, "destination")} position ${change.presentation.toIndex + 1}`
|
|
115
|
-
: "Removed" })] }), _jsx("span", { className: "changes__scope", "data-test": "structural-scope", children: "This rendered item only" }), getStructuralChangeDiagnostics(change.id).map((diagnostic) => (_jsx("span", { className: "changes__diagnostic", "data-test": "structural-diagnostic", "data-document": diagnostic.document, "data-status": diagnostic.status, "data-reason": diagnostic.reason, children: structuralDiagnosticText(diagnostic) }, `${diagnostic.document}:${diagnostic.status}:${diagnostic.reason ?? ""}`)))] }), _jsx(RevertButton, { dataTest: "dom-change-revert", onClick: () => revertStructuralChange(change.id) })] }) }, change.id))), _jsx(
|
|
133
|
+
: "Removed" })] }), _jsx("span", { className: "changes__scope", "data-test": "structural-scope", children: "This rendered item only" }), getStructuralChangeDiagnostics(change.id).map((diagnostic) => (_jsx("span", { className: "changes__diagnostic", "data-test": "structural-diagnostic", "data-document": diagnostic.document, "data-status": diagnostic.status, "data-reason": diagnostic.reason, children: structuralDiagnosticText(diagnostic) }, `${diagnostic.document}:${diagnostic.status}:${diagnostic.reason ?? ""}`)))] }), _jsx(RevertButton, { dataTest: "dom-change-revert", onClick: () => revertStructuralChange(change.id) })] }) }, change.id))), sketches.map((item) => _jsx(SketchChangeRow, { item: item }, `${item.document.id}:${item.document.revision}`)), sketchStore.error ? _jsx(StatusCallout, { tone: "warning", "data-test": "sketch-storage-error", children: sketchStore.error }) : null] })) }) : null, onClearSession ? (_jsx("div", { className: "changes__session-action", "data-test": "session-actions", children: _jsx(Button, { variant: "secondary", type: "button", "data-test": "clear-session", onClick: onClearSession, children: "Clear Changes" }) })) : null] }));
|
|
116
134
|
}
|
|
@@ -2,11 +2,11 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
2
2
|
import { Menu } from "@base-ui/react/menu";
|
|
3
3
|
import { iterationId } from "../canvas/frameContent.js";
|
|
4
4
|
import { useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
5
|
-
import { IconArtboard, IconBoltFilled, IconCheck, IconChevronDown, IconCopy, IconPlugConnected, IconSend, } from "@tabler/icons-react";
|
|
6
|
-
import { useChanges } from "../
|
|
5
|
+
import { IconArtboard, IconBoltFilled, IconCheck, IconChevronDown, IconCopy, IconPencil, IconPlugConnected, IconSend, IconX, } from "@tabler/icons-react";
|
|
6
|
+
import { useChanges } from "../drafts/store.js";
|
|
7
7
|
import { countPromptChanges } from "../prompt/generatePrompt.js";
|
|
8
8
|
import { loadCustomInstructions, saveCustomInstructions } from "../prompt/promptSettings.js";
|
|
9
|
-
import {
|
|
9
|
+
import { useAgentConnectionStatus } from "../agent/connectionStatus.js";
|
|
10
10
|
import { SettingsDialog } from "../settings/SettingsDialog.js";
|
|
11
11
|
import { Button } from "../ui/Button.js";
|
|
12
12
|
import { portalContainer } from "../ui/portalContainer.js";
|
|
@@ -18,8 +18,12 @@ import { createAgentPresentationAdapter } from "../canvas/agentPresentation.js";
|
|
|
18
18
|
import { captureHandoffOwner, getAgentDispatch, verifyAndReconcileAgentDispatch, } from "../agent/verification.js";
|
|
19
19
|
import { clearSentItems, getSentItems, sentItemCount } from "../workspace/sentItems.js";
|
|
20
20
|
import { getClipboardHandoffRevision, getLastClipboardReconciledCount, subscribeClipboardHandoff, } from "../prompt/clipboardHandoff.js";
|
|
21
|
-
import { useSketches, settleSketchDispatch } from "../sketch/store.js";
|
|
22
|
-
import {
|
|
21
|
+
import { removeSketch, useSketches, settleSketchDispatch } from "../sketch/store.js";
|
|
22
|
+
import { SketchThumbnail } from "../sketch/SketchThumbnail.js";
|
|
23
|
+
import { copySketchImageOnRequest } from "../sketch/copySketch.js";
|
|
24
|
+
import { closeSketchNote } from "../sketch/sketchNote.js";
|
|
25
|
+
import { IconButton } from "../ui/IconButton.js";
|
|
26
|
+
import { showToast } from "../ui/Toast.js";
|
|
23
27
|
import { isSendPromptShortcut, SEND_PROMPT_HOTKEY_EVENT } from "./shortcuts.js";
|
|
24
28
|
import { getFocusedCardId, getSelectedCardId, useCanvasCards, useFocusedCardId, useSelectedCardId } from "../canvas/canvasStore.js";
|
|
25
29
|
import { getEditableCardId, sketchBelongsToCard, useDrafts } from "../drafts/store.js";
|
|
@@ -49,8 +53,6 @@ export function CopyPromptButton({ settingsOpen: controlledSettingsOpen, setting
|
|
|
49
53
|
const handoffBusy = useRef(false);
|
|
50
54
|
const [saveMessage, setSaveMessage] = useState(null);
|
|
51
55
|
const [agentOutcome, setAgentOutcome] = useState(null);
|
|
52
|
-
const [clipboardPhase, setClipboardPhase] = useState("idle");
|
|
53
|
-
const [undoClear, setUndoClear] = useState(null);
|
|
54
56
|
const [sketchFallback, setSketchFallback] = useState(null);
|
|
55
57
|
const [localSettingsOpen, setLocalSettingsOpen] = useState(false);
|
|
56
58
|
const [localSettingsSection, setLocalSettingsSection] = useState("instructions");
|
|
@@ -124,16 +126,20 @@ export function CopyPromptButton({ settingsOpen: controlledSettingsOpen, setting
|
|
|
124
126
|
void settleSketchDispatch(request.changeRevision, request.status, request.requestId, request.clientDispatchId).catch(() => undefined);
|
|
125
127
|
}, [agent.request?.changeRevision, agent.request?.requestId, agent.request?.clientDispatchId, agent.request?.sketches, agent.request?.status]);
|
|
126
128
|
const connecting = agent.state === "pairing";
|
|
129
|
+
const delivered = agent.state === "delivered" || agent.request?.status === "delivered";
|
|
127
130
|
const working = agent.state === "working" || agent.request?.status === "working";
|
|
128
131
|
const canConnect = agent.companionReachable
|
|
129
132
|
&& agent.listenerActive
|
|
130
133
|
&& !agent.paired
|
|
131
134
|
&& !connecting
|
|
132
|
-
&& !working
|
|
133
|
-
|
|
135
|
+
&& !working
|
|
136
|
+
&& !delivered;
|
|
137
|
+
const canSend = agent.paired && agent.listenerActive && !working && !delivered;
|
|
134
138
|
const changeCount = countPromptChanges(changes, structuralChanges, canSend ? pendingSketches.length : 0) + comments.length;
|
|
135
|
-
|
|
136
|
-
const
|
|
139
|
+
// The badge counts every pending sketch, including ones copied separately from the menu.
|
|
140
|
+
const badgeCount = countPromptChanges(changes, structuralChanges, pendingSketches.length) + comments.length;
|
|
141
|
+
const disabled = preparing || connecting || working || delivered || (!canConnect && !hasChanges);
|
|
142
|
+
const agentStatus = useAgentConnectionStatus(agent);
|
|
137
143
|
const statusAction = agentStatus.action;
|
|
138
144
|
const label = preparing
|
|
139
145
|
? "Saving iteration…"
|
|
@@ -141,18 +147,20 @@ export function CopyPromptButton({ settingsOpen: controlledSettingsOpen, setting
|
|
|
141
147
|
? "Copied!"
|
|
142
148
|
: connecting
|
|
143
149
|
? "Connecting…"
|
|
144
|
-
:
|
|
145
|
-
? "
|
|
146
|
-
:
|
|
147
|
-
? "
|
|
148
|
-
:
|
|
149
|
-
? "
|
|
150
|
-
:
|
|
150
|
+
: delivered
|
|
151
|
+
? "Awaiting agent…"
|
|
152
|
+
: working
|
|
153
|
+
? "Agent working…"
|
|
154
|
+
: canConnect && !activeArtifactId
|
|
155
|
+
? "Connect agent"
|
|
156
|
+
: canSend && !activeArtifactId
|
|
157
|
+
? "Send prompt"
|
|
158
|
+
: "Copy prompt";
|
|
151
159
|
const icon = copied
|
|
152
160
|
? _jsx(IconCheck, { size: "var(--icon-size-small)", stroke: 1.8, "aria-hidden": "true" })
|
|
153
161
|
: !activeArtifactId && (canConnect || connecting)
|
|
154
162
|
? _jsx(IconPlugConnected, { size: "var(--icon-size-small)", stroke: 1.8, "aria-hidden": "true" })
|
|
155
|
-
: !activeArtifactId && (canSend || working)
|
|
163
|
+
: !activeArtifactId && (canSend || working || delivered)
|
|
156
164
|
? _jsx(IconSend, { size: "var(--icon-size-small)", stroke: 1.8, "aria-hidden": "true" })
|
|
157
165
|
: _jsx(IconCopy, { size: "var(--icon-size-small)", stroke: "var(--icon-stroke-width)", "aria-hidden": "true" });
|
|
158
166
|
async function onClick() {
|
|
@@ -232,8 +240,6 @@ export function CopyPromptButton({ settingsOpen: controlledSettingsOpen, setting
|
|
|
232
240
|
return;
|
|
233
241
|
}
|
|
234
242
|
setAgentOutcome(null);
|
|
235
|
-
setUndoClear(null);
|
|
236
|
-
setClipboardPhase("idle");
|
|
237
243
|
setSketchFallback(null);
|
|
238
244
|
const outcome = await deliverHandoff(prepared, runtimeConfig.projectId, canSend ? agentClient : null);
|
|
239
245
|
if (outcome.kind === "sketch-failed") {
|
|
@@ -243,39 +249,14 @@ export function CopyPromptButton({ settingsOpen: controlledSettingsOpen, setting
|
|
|
243
249
|
if (outcome.kind === "sent")
|
|
244
250
|
return;
|
|
245
251
|
setCopied(true);
|
|
246
|
-
setClipboardPhase("copied");
|
|
247
252
|
}
|
|
248
|
-
useEffect(() => {
|
|
249
|
-
if (clipboardPhase !== "copied" && clipboardPhase !== "away")
|
|
250
|
-
return;
|
|
251
|
-
// Focus moving into a canvas frame is not a return from the agent.
|
|
252
|
-
const onBlur = () => {
|
|
253
|
-
if (!(document.activeElement instanceof HTMLIFrameElement))
|
|
254
|
-
setClipboardPhase("away");
|
|
255
|
-
};
|
|
256
|
-
const onFocus = () => setClipboardPhase((phase) => phase === "away" ? "returned" : phase);
|
|
257
|
-
window.addEventListener("blur", onBlur);
|
|
258
|
-
window.addEventListener("focus", onFocus);
|
|
259
|
-
return () => {
|
|
260
|
-
window.removeEventListener("blur", onBlur);
|
|
261
|
-
window.removeEventListener("focus", onFocus);
|
|
262
|
-
};
|
|
263
|
-
}, [clipboardPhase]);
|
|
264
|
-
useEffect(() => {
|
|
265
|
-
if (!undoClear)
|
|
266
|
-
return;
|
|
267
|
-
const timer = window.setTimeout(() => setUndoClear(null), 10_000);
|
|
268
|
-
return () => window.clearTimeout(timer);
|
|
269
|
-
}, [undoClear]);
|
|
270
253
|
const handoffOwner = captureHandoffOwner(activeDraftCardId);
|
|
271
254
|
const sentItems = getSentItems(handoffOwner.draftId, handoffOwner.target, agentOutcome?.dispatch ?? null);
|
|
272
255
|
const remainingCount = sentItemCount(sentItems);
|
|
273
256
|
const showImplemented = (agentOutcome?.removed ?? 0) > 0 || reconciledCount > 0
|
|
274
|
-
|| (remainingCount > 0 &&
|
|
257
|
+
|| (remainingCount > 0 && agentOutcome !== null);
|
|
275
258
|
function clearRemaining() {
|
|
276
|
-
|
|
277
|
-
if (restore)
|
|
278
|
-
setUndoClear(() => restore);
|
|
259
|
+
clearSentItems(sentItems);
|
|
279
260
|
}
|
|
280
261
|
useEffect(() => {
|
|
281
262
|
function onKeydown(event) {
|
|
@@ -323,11 +304,36 @@ export function CopyPromptButton({ settingsOpen: controlledSettingsOpen, setting
|
|
|
323
304
|
}
|
|
324
305
|
openMcpConnection();
|
|
325
306
|
}
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
307
|
+
async function deleteSketch(sketchId) {
|
|
308
|
+
try {
|
|
309
|
+
if (!await removeSketch(sketchId)) {
|
|
310
|
+
showToast({ tone: "error", title: "Sketch not deleted", description: "This sketch is being sent and cannot be deleted yet." });
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
closeSketchNote();
|
|
314
|
+
}
|
|
315
|
+
catch (error) {
|
|
316
|
+
showToast({ tone: "error", title: "Sketch not deleted", description: error instanceof Error ? error.message : "The sketch could not be deleted." });
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
const hasMenu = Boolean(activeArtifactId) || visibleSketches.length > 0;
|
|
320
|
+
const styleEditLabel = canConnect ? "Connect agent" : canSend ? "Send style edit prompt" : "Copy style edit prompt";
|
|
321
|
+
const styleEditDescription = canConnect
|
|
322
|
+
? "Pair an agent first"
|
|
323
|
+
: canSend
|
|
324
|
+
? "Send to the connected agent"
|
|
325
|
+
: "Edits made in the inspector";
|
|
326
|
+
const promptButton = (_jsxs(Button, { variant: "primary", className: "copy-prompt__main", "data-test": "copy-prompt", type: "button", disabled: disabled, "data-copied": copied ? "true" : "false", "data-agent-state": agent.state, "aria-busy": preparing || working || connecting ? "true" : undefined, onClick: hasMenu ? undefined : onClick, children: [icon, label, badgeCount > 0 ? (_jsx("span", { className: "copy-prompt__change-count", "data-test": "copy-prompt-change-count", children: badgeCount })) : null, hasMenu ? _jsx(IconChevronDown, { size: "var(--icon-size-small)", stroke: "var(--icon-stroke-width)", "aria-hidden": "true" }) : null] }));
|
|
327
|
+
return (_jsxs("div", { className: "copy-prompt__stack", "data-test": "copy-prompt-control", children: [hasMenu ? (_jsxs(Menu.Root, { modal: false, children: [_jsx(Menu.Trigger, { render: promptButton }), _jsx(Menu.Portal, { container: portalContainer(), children: _jsx(Menu.Positioner, { className: "inspector-popover__positioner", side: "bottom", align: "start", sideOffset: 6, children: _jsxs(Menu.Popup, { className: "inspector-popover__popup copy-prompt__menu", "data-test": "copy-prompt-menu", children: [activeArtifactId ? (_jsxs(_Fragment, { children: [_jsxs(Menu.Item, { className: "copy-prompt__menu-item", "data-test": "copy-iteration-prompt", label: "Copy iteration prompt", onClick: () => void copyIterationPrompt("iteration"), children: [_jsx(IconArtboard, { className: "copy-prompt__menu-icon", size: "var(--icon-size-small)", stroke: "var(--icon-stroke-width)", "aria-hidden": "true" }), _jsxs("span", { className: "copy-prompt__menu-content", children: [_jsx("span", { className: "copy-prompt__menu-title", children: "Copy iteration prompt" }), _jsx("span", { className: "copy-prompt__menu-description", children: "Continue editing this HTML iteration." })] })] }), _jsxs(Menu.Item, { className: "copy-prompt__menu-item", "data-test": "copy-iteration-implementation", label: "Copy prompt for live app", onClick: () => void copyIterationPrompt("application"), children: [_jsx(IconBoltFilled, { className: "copy-prompt__menu-icon copy-prompt__menu-icon--live", size: "var(--icon-size-small)", "aria-hidden": "true" }), _jsxs("span", { className: "copy-prompt__menu-content", children: [_jsx("span", { className: "copy-prompt__menu-title", children: "Copy prompt for live app" }), _jsx("span", { className: "copy-prompt__menu-description", children: "Implement design in real app" })] })] })] })) : (_jsxs(Menu.Item, { className: "copy-prompt__menu-item", "data-test": "copy-style-edit-prompt", label: styleEditLabel, disabled: !canConnect && changeCount === 0, onClick: () => void onClick(), children: [canConnect
|
|
328
|
+
? _jsx(IconPlugConnected, { className: "copy-prompt__menu-icon", size: "var(--icon-size-small)", stroke: "var(--icon-stroke-width)", "aria-hidden": "true" })
|
|
329
|
+
: canSend
|
|
330
|
+
? _jsx(IconSend, { className: "copy-prompt__menu-icon", size: "var(--icon-size-small)", stroke: "var(--icon-stroke-width)", "aria-hidden": "true" })
|
|
331
|
+
: _jsx(IconPencil, { className: "copy-prompt__menu-icon", size: "var(--icon-size-small)", stroke: "var(--icon-stroke-width)", "aria-hidden": "true" }), _jsxs("span", { className: "copy-prompt__menu-content", children: [_jsx("span", { className: "copy-prompt__menu-title", children: styleEditLabel }), _jsx("span", { className: "copy-prompt__menu-description", children: styleEditDescription })] })] })), visibleSketches.length > 0 ? _jsx(Menu.Separator, { className: "copy-prompt__menu-separator" }) : null, visibleSketches.map((item, index) => {
|
|
332
|
+
const busy = item.status === "dispatching" || item.status === "handing-off";
|
|
333
|
+
return (_jsxs("div", { className: "copy-prompt__menu-row", children: [_jsxs(Menu.Item, { className: "copy-prompt__menu-item copy-prompt__menu-item--sketch", "data-test": "copy-sketch", "data-sketch-id": item.document.id, label: `Copy Sketch ${index + 1}`, disabled: busy, onClick: () => void copySketchImageOnRequest(item.document.annotatedImage), children: [_jsx(SketchThumbnail, { item: item }), _jsxs("span", { className: "copy-prompt__menu-content", children: [_jsxs("span", { className: "copy-prompt__menu-title", children: ["Copy Sketch ", index + 1] }), item.document.description ? (_jsx("span", { className: "copy-prompt__menu-description copy-prompt__menu-description--truncate", children: item.document.description })) : null] })] }), _jsx(IconButton, { className: "copy-prompt__menu-delete", variant: "quiet", size: "compact", label: `Delete Sketch ${index + 1}`, "data-test": "copy-sketch-delete", disabled: busy, onClick: () => void deleteSketch(item.document.id), children: _jsx(IconX, { size: "var(--icon-size-small)", "aria-hidden": "true" }) })] }, item.document.id));
|
|
334
|
+
})] }) }) })] }, activeDraftCardId)) : promptButton, statusAction || agentStatus.kind === "connected-not-listening" ? (_jsx(StatusCallout, { className: "copy-prompt__agent-status", tone: agentStatus.tone, "data-test": "agent-connection-status", children: _jsxs("div", { className: "copy-prompt__agent-status-content", children: [_jsx("span", { role: "status", children: agentStatus.label }), statusAction ? (_jsx(Button, { size: "compact", variant: "quiet", "data-test": "agent-status-action", "data-action": statusAction.kind, type: "button", onClick: () => void handleAgentStatusAction(), children: statusAction.label })) : null] }) })) : null, showImplemented ? (_jsxs("p", { className: "copy-prompt__hint copy-prompt__hint--centered copy-prompt__hint--implemented", "data-test": "handoff-implemented-hint", role: "status", children: ["Changes implemented.", remainingCount > 0 ? (_jsxs(_Fragment, { children: [" ", _jsx("button", { type: "button", className: "copy-prompt__hint-action", "data-test": "handoff-clear-remaining", onClick: clearRemaining, children: "Clear stale edits" })] })) : null] })) : null, saveMessage ? (_jsx("p", { className: "copy-prompt__hint copy-prompt__hint--centered", "data-test": "iteration-save-hint", role: "status", children: saveMessage })) : null, sketchFallback ? (_jsxs(StatusCallout, { className: "copy-prompt__sketch-fallback", tone: "warning", "data-test": "sketch-dispatch-error", children: [_jsx("span", { children: sketchFallback.error }), _jsx(Button, { size: "compact", variant: "secondary", type: "button", "data-test": "sketch-copy-fallback", onClick: () => {
|
|
335
|
+
void copyHandoff(sketchFallback.handoff).then(() => {
|
|
336
|
+
setSketchFallback(null);
|
|
337
|
+
}).catch(() => undefined);
|
|
332
338
|
}, children: "Copy prompt" })] })) : null, _jsx(SettingsDialog, { open: settingsOpen, initialSection: settingsSection, value: customInstructions, onValueChange: handleCustomInstructionsChange, onOpenChange: setSettingsOpen, projectId: runtimeConfig.projectId, origin: window.location.origin, snapshot: agent, onConnect: () => agentClient.connect(), onTakeOver: () => agentClient.takeOver(), onDisconnect: () => agentClient.disconnect(), onCheckAgain: () => agentClient.checkConnection() })] }));
|
|
333
339
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { IconArtboard, IconBoltFilled, IconSparkles } from "@tabler/icons-react";
|
|
3
2
|
import { useCanvasPresentation } from "../canvas/viewStore.js";
|
|
4
3
|
import { Disclosure } from "../ui/Disclosure.js";
|
|
5
|
-
import
|
|
4
|
+
import { CANVAS_ILLUSTRATION_SVG } from "../ui/assets/canvasIllustration.js";
|
|
5
|
+
import { GRID_ILLUSTRATION_SVG } from "../ui/assets/gridIllustration.js";
|
|
6
6
|
import { getPlatformModifierKey, isMacPlatform } from "./shortcuts.js";
|
|
7
7
|
export function EmptyState() {
|
|
8
8
|
const presentation = useCanvasPresentation();
|
|
@@ -12,5 +12,5 @@ export function EmptyState() {
|
|
|
12
12
|
const modifierName = macPlatform ? "Command" : "Control";
|
|
13
13
|
const optionKey = macPlatform ? "⌥" : "Alt";
|
|
14
14
|
const optionName = macPlatform ? "Option" : "Alt";
|
|
15
|
-
return (_jsxs("div", { className:
|
|
15
|
+
return (_jsxs("div", { className: "empty-state", "data-test": "empty-state", children: [canvas ? (_jsxs(_Fragment, { children: [_jsx("span", { className: "empty-state__icon", "aria-hidden": "true", dangerouslySetInnerHTML: { __html: CANVAS_ILLUSTRATION_SVG } }), _jsxs("p", { className: "empty-state__hint", "data-test": "canvas-intro", children: ["Hold ", _jsx("kbd", { children: "A" }), " to click links and open them as new pages on the canvas."] })] })) : (_jsxs(_Fragment, { children: [_jsx("span", { className: "empty-state__icon", "aria-hidden": "true", dangerouslySetInnerHTML: { __html: GRID_ILLUSTRATION_SVG } }), _jsx("h2", { className: "empty-state__title", children: "Select an element to edit" })] })), _jsx(Disclosure, { className: "empty-state__shortcuts", title: "Keyboard shortcuts", triggerDataTest: "empty-state-shortcuts-toggle", defaultOpen: true, children: _jsxs("ul", { className: "empty-state__shortcut-list", children: [_jsxs("li", { className: "empty-state__shortcut", "data-test": "empty-state-shortcut", children: [_jsx("span", { children: "Nudge" }), _jsxs("span", { className: "empty-state__shortcut-keys", "aria-label": "Arrow keys", children: [_jsx("kbd", { children: "\u2191" }), _jsx("kbd", { children: "\u2193" }), _jsx("kbd", { children: "\u2190" }), _jsx("kbd", { children: "\u2192" })] })] }), _jsxs("li", { className: "empty-state__shortcut", "data-test": "empty-state-shortcut", children: [_jsx("span", { children: "Big Nudge (8px)" }), _jsxs("span", { className: "empty-state__shortcut-keys", "aria-label": "Shift plus arrow keys", children: [_jsx("kbd", { children: "Shift" }), _jsx("span", { "aria-hidden": "true", children: "+" }), _jsx("kbd", { children: "Arrow" })] })] }), _jsxs("li", { className: "empty-state__shortcut", "data-test": "empty-state-shortcut", children: [_jsx("span", { children: "Select deeper" }), _jsxs("span", { className: "empty-state__shortcut-keys", "aria-label": `${modifierName} plus click`, children: [_jsx("kbd", { children: modifierKey }), _jsx("span", { "aria-hidden": "true", children: "+" }), _jsx("kbd", { children: "Click" })] })] }), _jsxs("li", { className: "empty-state__shortcut", "data-test": "empty-state-shortcut", children: [_jsx("span", { children: "Measure" }), _jsxs("span", { className: "empty-state__shortcut-keys", "aria-label": `${optionName} plus hover`, children: [_jsx("kbd", { children: optionKey }), _jsx("span", { "aria-hidden": "true", children: "+" }), _jsx("kbd", { children: "Hover" })] })] }), _jsxs("li", { className: "empty-state__shortcut", "data-test": "empty-state-shortcut", children: [_jsx("span", { children: "Hide UI" }), _jsxs("span", { className: "empty-state__shortcut-keys", "aria-label": `${modifierName} plus backslash`, children: [_jsx("kbd", { children: modifierKey }), _jsx("span", { "aria-hidden": "true", children: "+" }), _jsx("kbd", { children: "\\" })] })] }), _jsxs("li", { className: "empty-state__shortcut", "data-test": "empty-state-shortcut", children: [_jsx("span", { children: "Hold to view original" }), _jsx("span", { className: "empty-state__shortcut-keys", "aria-label": "Backslash", children: _jsx("kbd", { children: "\\" }) })] }), _jsxs("li", { className: "empty-state__shortcut", "data-test": "empty-state-shortcut", children: [_jsx("span", { children: "Undo" }), _jsxs("span", { className: "empty-state__shortcut-keys", "aria-label": `${modifierName} plus Z`, children: [_jsx("kbd", { children: modifierKey }), _jsx("span", { "aria-hidden": "true", children: "+" }), _jsx("kbd", { children: "Z" })] })] }), _jsxs("li", { className: "empty-state__shortcut", "data-test": "empty-state-shortcut", children: [_jsx("span", { children: "Deselect" }), _jsx("span", { className: "empty-state__shortcut-keys", children: _jsx("kbd", { children: "Esc" }) })] })] }) }, presentation)] }));
|
|
16
16
|
}
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import type { ReactElement } from "react";
|
|
2
|
-
import { toggleInspector, setInspectorOpen } from "./openStore.js";
|
|
3
2
|
declare global {
|
|
4
3
|
interface Window {
|
|
5
4
|
MutationObserver: typeof MutationObserver;
|
|
6
5
|
}
|
|
7
6
|
}
|
|
8
|
-
export { toggleInspector, setInspectorOpen };
|
|
9
|
-
export type { SelectedElement } from "../selection/selectionStore.js";
|
|
10
7
|
export declare function InspectorShell(): ReactElement;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useMemo, useState } from "react";
|
|
2
|
+
import { useEffect, useMemo, useState, useSyncExternalStore } from "react";
|
|
3
3
|
import { IconLayoutSidebarRight } from "@tabler/icons-react";
|
|
4
|
-
import { useInspectorOpen,
|
|
4
|
+
import { useInspectorOpen, setInspectorOpen } from "./openStore.js";
|
|
5
5
|
import { useSelectedElement, useSelectedElements, setSelectedElement, removeSelectedElement, } from "../selection/selectionStore.js";
|
|
6
6
|
import { findTokenRow } from "../styleEditors/rowLookup.js";
|
|
7
7
|
import { useBrowserCssInspection } from "../inspection/useBrowserCssInspection.js";
|
|
@@ -17,7 +17,7 @@ import { AppearanceSection } from "../styleEditors/AppearanceSection.js";
|
|
|
17
17
|
import { BoxShadowEditor } from "../styleEditors/BoxShadowEditor.js";
|
|
18
18
|
import { LayoutSection } from "../styleEditors/LayoutSection.js";
|
|
19
19
|
import { ChangesLog } from "./ChangesLog.js";
|
|
20
|
-
import { discardChangesForInstanceOverride, undo, redo } from "../
|
|
20
|
+
import { discardChangesForInstanceOverride, undo, redo } from "../drafts/store.js";
|
|
21
21
|
import { countSourceSiteMatches, getEditScope, relinkElement, sourceSiteSelector, unlinkElement } from "../selection/editScope.js";
|
|
22
22
|
import { canEditStyles } from "../tokens/editActions.js";
|
|
23
23
|
import { Button } from "../ui/Button.js";
|
|
@@ -27,6 +27,7 @@ import { StatusCallout } from "../ui/StatusCallout.js";
|
|
|
27
27
|
import { IconButton } from "../ui/IconButton.js";
|
|
28
28
|
import { UI_STYLES } from "../ui/styles.js";
|
|
29
29
|
import { getActiveStyleState, setActiveStyleState } from "./styleState.js";
|
|
30
|
+
import { useInteractionStatePreview } from "./interactionStatePreview.js";
|
|
30
31
|
import { getInspectorToggleShortcutLabel, isEditableEvent } from "./shortcuts.js";
|
|
31
32
|
import { formatInspectorLabel } from "../ui/labels.js";
|
|
32
33
|
import { FieldRow } from "../ui/FieldRow.js";
|
|
@@ -34,6 +35,8 @@ import { Select } from "../ui/Select.js";
|
|
|
34
35
|
import { clearSelectedFrameChanges } from "../canvas/sessionStore.js";
|
|
35
36
|
import { useFocusedCardId, useSelectedCardId, } from "../canvas/canvasStore.js";
|
|
36
37
|
import { getActiveCanvasFrame } from "../canvas/activeCanvasDocument.js";
|
|
38
|
+
import { canvasFrameHost } from "../canvas/canvasFrame.js";
|
|
39
|
+
import { getFrameRegistryVersion, subscribeFrameRegistry } from "../canvas/projection.js";
|
|
37
40
|
import { getElementWindow } from "../runtime/domRealm.js";
|
|
38
41
|
import { deleteElement, nudgeElement } from "../overlay/structuralGestures.js";
|
|
39
42
|
import { AtRuleContextProvider } from "../ui/AtRuleContext.js";
|
|
@@ -45,10 +48,11 @@ import { EmptyState } from "./EmptyState.js";
|
|
|
45
48
|
import { createStyleSelection } from "../selection/styleSelection.js";
|
|
46
49
|
import { intersectTokenEntries } from "../inspection/selectionProperty.js";
|
|
47
50
|
import { isNudgeUiDev } from "../runtime/devFlag.js";
|
|
48
|
-
import { isDemoRuntime } from "../runtime/runtimeConfig.js";
|
|
51
|
+
import { isDemoRuntime, isNudgeUiFeatureEnabled } from "../runtime/runtimeConfig.js";
|
|
49
52
|
import { SketchWorkspace } from "../sketch/SketchWorkspace.js";
|
|
50
53
|
import { useSketchInteractionActive } from "../sketch/interaction.js";
|
|
51
54
|
import { Tooltip } from "../ui/Tooltip.js";
|
|
55
|
+
import { InspectorStyle } from "../ui/InspectorStyle.js";
|
|
52
56
|
function findFirstTokenRow(rows, properties) {
|
|
53
57
|
for (const property of properties) {
|
|
54
58
|
const row = findTokenRow(rows, property);
|
|
@@ -62,7 +66,6 @@ function findFirstTokenRow(rows, properties) {
|
|
|
62
66
|
}
|
|
63
67
|
return null;
|
|
64
68
|
}
|
|
65
|
-
export { toggleInspector, setInspectorOpen };
|
|
66
69
|
function nodeMatchesSelector(node, selector) {
|
|
67
70
|
if (!selector || node.nodeType !== node.ELEMENT_NODE)
|
|
68
71
|
return false;
|
|
@@ -88,11 +91,14 @@ function scopeMutationAffectsSelection(records, selected) {
|
|
|
88
91
|
export function InspectorShell() {
|
|
89
92
|
const isOpen = useInspectorOpen();
|
|
90
93
|
const runtimeConfig = useNudgeUiRuntimeConfig();
|
|
91
|
-
const sketchEnabled = isNudgeUiDev()
|
|
94
|
+
const sketchEnabled = isNudgeUiDev()
|
|
95
|
+
&& !runtimeConfig.inspectionUnavailableReason
|
|
96
|
+
&& (!isDemoRuntime() || isNudgeUiFeatureEnabled(runtimeConfig.features, "sketch"));
|
|
92
97
|
const sketchActive = useSketchInteractionActive();
|
|
93
98
|
const selectedCardId = useSelectedCardId();
|
|
94
99
|
const focusedCardId = useFocusedCardId();
|
|
95
|
-
|
|
100
|
+
useSyncExternalStore(subscribeFrameRegistry, getFrameRegistryVersion);
|
|
101
|
+
const sketchHost = selectedCardId || focusedCardId ? canvasFrameHost(getActiveCanvasFrame()) : null;
|
|
96
102
|
const selected = useSelectedElement();
|
|
97
103
|
const selectedElements = useSelectedElements();
|
|
98
104
|
const inlineTextFeedback = getInlineTextFeedback(useInlineTextDiagnostic());
|
|
@@ -100,6 +106,7 @@ export function InspectorShell() {
|
|
|
100
106
|
const [settingsSection, setSettingsSection] = useState("instructions");
|
|
101
107
|
const [scopeRevision, refreshScope] = useState(0);
|
|
102
108
|
const [styleState, setStyleState] = useState(getActiveStyleState());
|
|
109
|
+
useInteractionStatePreview(selectedElements.length === 1 ? selectedElements[0].domElement : null, styleState);
|
|
103
110
|
const cssInspection = useBrowserCssInspection(selectedElements, styleState);
|
|
104
111
|
const isMultiSelection = selectedElements.length > 1;
|
|
105
112
|
useEffect(() => {
|
|
@@ -144,7 +151,7 @@ export function InspectorShell() {
|
|
|
144
151
|
return () => observers.forEach((observer) => observer.disconnect());
|
|
145
152
|
}, [selectedElements, scopeRevision]);
|
|
146
153
|
useEffect(() => {
|
|
147
|
-
if (sketchActive)
|
|
154
|
+
if (sketchActive || runtimeConfig.inspectionUnavailableReason)
|
|
148
155
|
return;
|
|
149
156
|
function onKeydown(event) {
|
|
150
157
|
if (isInlineTextEditingActive())
|
|
@@ -197,7 +204,7 @@ export function InspectorShell() {
|
|
|
197
204
|
}
|
|
198
205
|
window.addEventListener("keydown", onKeydown);
|
|
199
206
|
return () => window.removeEventListener("keydown", onKeydown);
|
|
200
|
-
}, [isMultiSelection, selected, sketchActive]);
|
|
207
|
+
}, [isMultiSelection, selected, sketchActive, runtimeConfig.inspectionUnavailableReason]);
|
|
201
208
|
const inspectionSnapshot = cssInspection.element;
|
|
202
209
|
const styleSelection = useMemo(() => createStyleSelection(selectedElements, cssInspection.elements, selected), [cssInspection.elements, selected, selectedElements]);
|
|
203
210
|
const selectionEditable = useMemo(() => styleSelection ? canEditStyles(styleSelection.target) : false, [scopeRevision, styleSelection]);
|
|
@@ -205,7 +212,7 @@ export function InspectorShell() {
|
|
|
205
212
|
const tokenRows = useMemo(() => styleSelection ? [...styleSelection.primaryRows] : [], [styleSelection]);
|
|
206
213
|
const availableInteractionStates = inspectionSnapshot?.availableStates ?? [];
|
|
207
214
|
const showText = selectedElements.length > 0 && selectedElements.every((element, index) => isTextRelevant(element.domElement, cssInspection.elements[index]?.properties ?? []));
|
|
208
|
-
const showInteractionState = !isMultiSelection && availableInteractionStates.length >
|
|
215
|
+
const showInteractionState = !isMultiSelection && availableInteractionStates.length > 1;
|
|
209
216
|
const paintedBackgroundRow = findFirstTokenRow(tokenRows, ["background-color", "background"]);
|
|
210
217
|
const backgroundTokenRow = useMemo(() => {
|
|
211
218
|
if (!selected)
|
|
@@ -230,12 +237,13 @@ export function InspectorShell() {
|
|
|
230
237
|
setSettingsOpen(true);
|
|
231
238
|
}
|
|
232
239
|
function clearInspectorSession() {
|
|
233
|
-
|
|
240
|
+
// Sketch persistence failures are reported by the sketch store in the panel.
|
|
241
|
+
void clearSelectedFrameChanges().catch(() => undefined);
|
|
234
242
|
}
|
|
235
|
-
return (_jsxs(_Fragment, { children: [_jsx(
|
|
243
|
+
return (_jsxs(_Fragment, { children: [_jsx(InspectorStyle, { testId: "inspector-styles", css: UI_STYLES }), _jsxs("div", { className: "panel", "data-open": isOpen ? "true" : "false", children: [_jsxs("div", { className: "panel__tabs", "aria-label": "Inspector controls", children: [_jsxs("div", { className: "panel__header-row", "data-test": "inspect-tab", children: [_jsx(Tooltip, { content: "Hide inspector", shortcut: getInspectorToggleShortcutLabel(), stableTrigger: true, children: _jsx(IconButton, { variant: "quiet", label: "Collapse inspector", "data-test": "collapse-inspector", disabled: sketchActive, style: { marginLeft: "calc(var(--space-8) * -1)" }, onClick: () => {
|
|
236
244
|
cancelInlineTextEdit();
|
|
237
245
|
setInspectorOpen(false);
|
|
238
|
-
}, children: _jsx(IconLayoutSidebarRight, { size: "var(--icon-size-small)", stroke: 1.8, "aria-hidden": "true" }) }) }), _jsxs("div", { className: "panel__header-actions", children: [_jsx(PeekOriginalButton, {}), _jsx(AgentStatusButton, { onOpenSettings: openSettings })] })] }), _jsx("div", { className: "panel__copy-row", children: _jsx(CopyPromptButton, { settingsOpen: settingsOpen, settingsSection: settingsSection, onOpenSettings: openSettings, onSettingsOpenChange: setSettingsOpen }) })] }), _jsxs("div", { className: "panel__body", children: [inlineTextFeedback ? (_jsx(StatusCallout, { tone: "danger", className: "inline-text-diagnostic", "data-test": "inline-text-diagnostic", role: "status", "aria-live": "polite", "aria-atomic": "true", children: _jsx("span", { children: inlineTextFeedback.message }) })) : null, selected ? (_jsxs(_Fragment, { children: [
|
|
246
|
+
}, children: _jsx(IconLayoutSidebarRight, { size: "var(--icon-size-small)", stroke: 1.8, "aria-hidden": "true" }) }) }), _jsxs("div", { className: "panel__header-actions", children: [_jsx(PeekOriginalButton, {}), _jsx(AgentStatusButton, { onOpenSettings: openSettings })] })] }), _jsx("div", { className: "panel__copy-row", children: _jsx(CopyPromptButton, { settingsOpen: settingsOpen, settingsSection: settingsSection, onOpenSettings: openSettings, onSettingsOpenChange: setSettingsOpen }) })] }), _jsxs("div", { className: "panel__body", children: [inlineTextFeedback ? (_jsx(StatusCallout, { tone: "danger", className: "inline-text-diagnostic", "data-test": "inline-text-diagnostic", role: "status", "aria-live": "polite", "aria-atomic": "true", children: _jsx("span", { children: inlineTextFeedback.message }) })) : null, runtimeConfig.inspectionUnavailableReason ? (_jsxs(StatusCallout, { tone: "danger", "data-test": "page-inspection-error", role: "status", children: ["Can\u2019t load Nudge on this page due to ", runtimeConfig.inspectionUnavailableReason, "."] })) : selected ? (_jsxs(_Fragment, { children: [showInteractionState || hasEditScopeCallout ? (_jsxs("div", { className: `selection${hasEditScopeCallout ? "" : " selection--without-scope-callout"}`, "data-test": "selection", "data-selected-cid": selected.cid, "data-selected-src": selected.src, "data-selected-count": selectedElements.length, children: [hasEditScopeCallout ? (_jsx(StatusCallout, { tone: editScope === "rendered-instance" ? "neutral" : "accent", "data-test": "edit-scope", "data-lost": "false", children: editScope === "rendered-instance" ? (_jsxs("div", { className: "scope__unlinked", children: [_jsx("span", { children: "Element unlinked" }), _jsx(Button, { size: "compact", className: "scope__action", "data-test": "relink-element", onClick: () => {
|
|
239
247
|
const overrideId = relinkElement(selected.domElement);
|
|
240
248
|
if (overrideId)
|
|
241
249
|
discardChangesForInstanceOverride(overrideId);
|
|
@@ -3,11 +3,11 @@ import { useEffect, useSyncExternalStore } from "react";
|
|
|
3
3
|
import { IconButton } from "../ui/IconButton.js";
|
|
4
4
|
import { Tooltip } from "../ui/Tooltip.js";
|
|
5
5
|
import { PeekOriginalIcon } from "./PeekOriginalIcon.js";
|
|
6
|
-
import {
|
|
6
|
+
import { getActiveDraftChanges, subscribeActiveDraftChanges } from "../drafts/store.js";
|
|
7
7
|
import { setOriginalPreviewActive, useOriginalPreviewActive, } from "./originalPreview.js";
|
|
8
8
|
function useDraftChangeCount() {
|
|
9
|
-
return useSyncExternalStore(
|
|
10
|
-
const snapshot =
|
|
9
|
+
return useSyncExternalStore(subscribeActiveDraftChanges, () => {
|
|
10
|
+
const snapshot = getActiveDraftChanges();
|
|
11
11
|
return snapshot.changes.length + snapshot.structuralChanges.length;
|
|
12
12
|
}, () => 0);
|
|
13
13
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type InteractionState } from "./styleState.js";
|
|
2
|
+
/** Matches native interaction states and the Inspector's temporary CSS state. */
|
|
3
|
+
export declare function selectorForInteractionStatePreview(selector: string): string;
|
|
4
|
+
/**
|
|
5
|
+
* Projects CSS interaction states into the selected element's document.
|
|
6
|
+
* This previews styles without dispatching events or changing application state.
|
|
7
|
+
*/
|
|
8
|
+
export declare function startInteractionStatePreview(element: HTMLElement, state: InteractionState): () => void;
|
|
9
|
+
export declare function useInteractionStatePreview(element: HTMLElement | null, state: InteractionState): void;
|