nudge-ui 0.2.2 → 0.2.4
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/README.md +164 -46
- package/dist/client.mjs +260 -61
- package/dist/css/value-semantics/colorSemantics.d.ts +4 -0
- package/dist/css/value-semantics/colorSemantics.js +17 -0
- package/dist/hosts/astro/astroRuntimeConfig.js +1 -0
- package/dist/hosts/astro/clientTransport.js +38 -32
- package/dist/hosts/astro/integration.js +5 -1
- package/dist/hosts/astro/markdownIdentity.d.ts +28 -0
- package/dist/hosts/astro/markdownIdentity.js +81 -0
- package/dist/hosts/next/manifest.js +1 -1
- package/dist/hosts/next/sidecar.js +5 -1
- package/dist/hosts/static/manifest.js +1 -1
- package/dist/hosts/static/server.js +3 -0
- package/dist/hosts/vite/vite.d.ts +3 -0
- package/dist/hosts/vite/vite.js +24 -4
- package/dist/inspector/agent/McpConnectionDialog.js +13 -19
- package/dist/inspector/agent/activity.d.ts +18 -0
- package/dist/inspector/agent/activity.js +70 -0
- package/dist/inspector/agent/client.d.ts +2 -0
- package/dist/inspector/agent/client.js +29 -1
- package/dist/inspector/agent/connectionStatus.js +1 -1
- package/dist/inspector/agent/httpTransport.js +9 -2
- package/dist/inspector/agent/protocol.d.ts +6 -3
- package/dist/inspector/agent/protocol.js +1 -1
- package/dist/inspector/agent/verification.d.ts +15 -7
- package/dist/inspector/agent/verification.js +113 -41
- package/dist/inspector/canvas/AgentActivityOverlay.d.ts +13 -0
- package/dist/inspector/canvas/AgentActivityOverlay.js +111 -0
- package/dist/inspector/canvas/CanvasCard.d.ts +9 -2
- package/dist/inspector/canvas/CanvasCard.js +135 -38
- package/dist/inspector/canvas/CanvasElementOverlay.js +166 -16
- package/dist/inspector/canvas/CanvasToolIcons.d.ts +10 -0
- package/dist/inspector/canvas/CanvasToolIcons.js +20 -0
- package/dist/inspector/canvas/CanvasToolbar.js +8 -4
- package/dist/inspector/canvas/CanvasWorkspace.js +270 -122
- package/dist/inspector/canvas/StaleChangeIndicator.js +3 -13
- package/dist/inspector/canvas/agentPresentation.d.ts +8 -8
- package/dist/inspector/canvas/agentPresentation.js +64 -52
- package/dist/inspector/canvas/canvasGestures.d.ts +1 -1
- package/dist/inspector/canvas/canvasGestures.js +1 -1
- package/dist/inspector/canvas/canvasStore.d.ts +46 -82
- package/dist/inspector/canvas/canvasStore.js +251 -284
- package/dist/inspector/canvas/frameContent.d.ts +21 -0
- package/dist/inspector/canvas/frameContent.js +44 -0
- package/dist/inspector/canvas/frameProtocol.d.ts +21 -4
- package/dist/inspector/canvas/frameProtocol.js +3 -3
- package/dist/inspector/canvas/frameScrollbarStyles.d.ts +3 -0
- package/dist/inspector/canvas/frameScrollbarStyles.js +21 -0
- package/dist/inspector/canvas/keyboardShortcuts.d.ts +3 -1
- package/dist/inspector/canvas/keyboardShortcuts.js +4 -4
- package/dist/inspector/canvas/layout.d.ts +52 -0
- package/dist/inspector/canvas/layout.js +106 -0
- package/dist/inspector/canvas/projection.d.ts +15 -5
- package/dist/inspector/canvas/projection.js +69 -13
- package/dist/inspector/canvas/rendererBootstrap.js +32 -4
- package/dist/inspector/canvas/rendererElementSelector.js +47 -6
- package/dist/inspector/canvas/rendererStylesheet.js +2 -2
- package/dist/inspector/canvas/resizeHandleScale.js +1 -1
- package/dist/inspector/canvas/sessionStore.d.ts +11 -26
- package/dist/inspector/canvas/sessionStore.js +43 -183
- package/dist/inspector/canvas/staleChangeDetector.js +9 -3
- package/dist/inspector/canvas/useCanvasLayoutAnimation.d.ts +5 -0
- package/dist/inspector/canvas/useCanvasLayoutAnimation.js +107 -0
- package/dist/inspector/canvas/viewStore.d.ts +38 -0
- package/dist/inspector/canvas/viewStore.js +104 -0
- package/dist/inspector/canvas/wheelPan.d.ts +8 -0
- package/dist/inspector/canvas/wheelPan.js +8 -0
- package/dist/inspector/changes/changesLog.d.ts +9 -6
- package/dist/inspector/changes/changesLog.js +48 -32
- package/dist/inspector/changes/codecs.d.ts +1 -0
- package/dist/inspector/changes/codecs.js +10 -1
- package/dist/inspector/changes/draftChanges.d.ts +58 -0
- package/dist/inspector/changes/draftChanges.js +304 -0
- package/dist/inspector/changes/editModel.d.ts +10 -0
- package/dist/inspector/changes/editModel.js +9 -2
- package/dist/inspector/changes/previewDiagnostics.d.ts +4 -2
- package/dist/inspector/changes/previewDiagnostics.js +11 -25
- package/dist/inspector/changes/types.d.ts +7 -0
- package/dist/inspector/clientManifest.d.ts +1 -1
- package/dist/inspector/comments/CommentsOverlay.d.ts +2 -0
- package/dist/inspector/comments/CommentsOverlay.js +250 -0
- package/dist/inspector/comments/element.d.ts +6 -0
- package/dist/inspector/comments/element.js +54 -0
- package/dist/inspector/comments/store.d.ts +29 -0
- package/dist/inspector/comments/store.js +121 -0
- package/dist/inspector/comments/verification.d.ts +5 -0
- package/dist/inspector/comments/verification.js +52 -0
- package/dist/inspector/componentSemantics/adapterRegistry.d.ts +6 -1
- package/dist/inspector/componentSemantics/adapterRegistry.js +23 -1
- package/dist/inspector/componentSemantics/reactRuntime.d.ts +2 -1
- package/dist/inspector/componentSemantics/reactRuntime.js +38 -0
- package/dist/inspector/componentSemantics/runtimeBridge.d.ts +4 -2
- package/dist/inspector/componentSemantics/runtimeBridge.js +17 -0
- package/dist/inspector/componentSemantics/types.d.ts +11 -0
- package/dist/inspector/drafts/model.d.ts +35 -0
- package/dist/inspector/drafts/model.js +45 -0
- package/dist/inspector/drafts/store.d.ts +28 -0
- package/dist/inspector/drafts/store.js +231 -0
- package/dist/inspector/index.js +20 -27
- package/dist/inspector/inline-text/inlineTextEditor.js +7 -0
- package/dist/inspector/inspection/useBrowserCssInspection.js +15 -1
- package/dist/inspector/iterations/capture.d.ts +2 -0
- package/dist/inspector/iterations/capture.js +174 -0
- package/dist/inspector/iterations/client.d.ts +7 -0
- package/dist/inspector/iterations/client.js +52 -0
- package/dist/inspector/iterations/coordinator.d.ts +15 -0
- package/dist/inspector/iterations/coordinator.js +130 -0
- package/dist/inspector/iterations/prompt.d.ts +3 -0
- package/dist/inspector/iterations/prompt.js +26 -0
- package/dist/inspector/overlay/DomNavigator.js +21 -15
- package/dist/inspector/overlay/interactionStyles.js +3 -1
- package/dist/inspector/overlay/spacingGestures.d.ts +13 -1
- package/dist/inspector/overlay/spacingGestures.js +82 -5
- package/dist/inspector/projection/{workspaceProjection.d.ts → draftProjection.d.ts} +6 -6
- package/dist/inspector/projection/{workspaceProjection.js → draftProjection.js} +4 -4
- package/dist/inspector/projection/renderedInstance.d.ts +17 -3
- package/dist/inspector/projection/renderedInstance.js +62 -11
- package/dist/inspector/projection/structuralProjection.d.ts +2 -1
- package/dist/inspector/projection/structuralProjection.js +21 -17
- package/dist/inspector/projection/textProjection.d.ts +2 -1
- package/dist/inspector/projection/textProjection.js +64 -15
- package/dist/inspector/prompt/PromptSettingsDialog.js +1 -5
- package/dist/inspector/prompt/clipboardHandoff.d.ts +15 -18
- package/dist/inspector/prompt/clipboardHandoff.js +97 -143
- package/dist/inspector/prompt/generatePrompt.d.ts +4 -1
- package/dist/inspector/prompt/generatePrompt.js +22 -17
- package/dist/inspector/runtime/runtimeConfig.d.ts +9 -0
- package/dist/inspector/runtime/runtimeConfig.js +24 -0
- package/dist/inspector/selection/sourceSite.d.ts +12 -0
- package/dist/inspector/selection/sourceSite.js +28 -0
- package/dist/inspector/settings/SettingsDialog.js +21 -8
- package/dist/inspector/shell/AgentStatusButton.d.ts +11 -0
- package/dist/inspector/shell/AgentStatusButton.js +36 -0
- package/dist/inspector/shell/AppShell.js +4 -2
- package/dist/inspector/shell/ChangesLog.js +46 -26
- package/dist/inspector/shell/CopyPromptButton.js +184 -93
- package/dist/inspector/shell/EmptyState.js +9 -8
- package/dist/inspector/shell/InspectorShell.js +13 -21
- package/dist/inspector/shell/PeekOriginalButton.js +24 -23
- package/dist/inspector/shell/originalPreview.js +5 -5
- package/dist/inspector/shell/shortcuts.d.ts +3 -0
- package/dist/inspector/shell/shortcuts.js +11 -0
- package/dist/inspector/sketch/SketchEditor.js +14 -14
- package/dist/inspector/sketch/SketchEntryButton.js +1 -1
- package/dist/inspector/sketch/SketchFrameOverlay.d.ts +3 -1
- package/dist/inspector/sketch/SketchFrameOverlay.js +11 -8
- package/dist/inspector/sketch/SketchLayersPanel.js +13 -5
- package/dist/inspector/sketch/SketchOverlay.js +7 -7
- package/dist/inspector/sketch/SketchWorkspace.js +18 -12
- package/dist/inspector/sketch/interaction.d.ts +1 -0
- package/dist/inspector/sketch/interaction.js +8 -4
- package/dist/inspector/sketch/model.d.ts +5 -0
- package/dist/inspector/sketch/model.js +6 -2
- package/dist/inspector/sketch/raster.d.ts +1 -2
- package/dist/inspector/sketch/raster.js +68 -4
- package/dist/inspector/styleEditors/BackgroundEditor.d.ts +4 -0
- package/dist/inspector/styleEditors/BackgroundEditor.js +195 -0
- package/dist/inspector/styleEditors/BorderEditor.js +49 -78
- package/dist/inspector/styleEditors/BorderRadiusEditor.js +6 -1
- package/dist/inspector/styleEditors/BoxShadowEditor.d.ts +1 -2
- package/dist/inspector/styleEditors/BoxShadowEditor.js +132 -4
- package/dist/inspector/styleEditors/ColorPicker.d.ts +5 -1
- package/dist/inspector/styleEditors/ColorPicker.js +10 -4
- package/dist/inspector/styleEditors/GapField.js +3 -5
- package/dist/inspector/styleEditors/GridChildSection.d.ts +1 -1
- package/dist/inspector/styleEditors/GridChildSection.js +18 -9
- package/dist/inspector/styleEditors/GridPicker.d.ts +1 -1
- package/dist/inspector/styleEditors/GridPicker.js +8 -2
- package/dist/inspector/styleEditors/GridSection.js +1 -1
- package/dist/inspector/styleEditors/GridValueField.js +19 -14
- package/dist/inspector/styleEditors/ImageBackgroundEditor.d.ts +18 -0
- package/dist/inspector/styleEditors/ImageBackgroundEditor.js +118 -0
- package/dist/inspector/styleEditors/LayoutBlockedIndicator.d.ts +2 -2
- package/dist/inspector/styleEditors/LayoutBlockedIndicator.js +3 -3
- package/dist/inspector/styleEditors/LayoutComboField.js +6 -4
- package/dist/inspector/styleEditors/LayoutDropdown.js +6 -3
- package/dist/inspector/styleEditors/LayoutSection.js +32 -11
- package/dist/inspector/styleEditors/SpacingBox.js +7 -5
- package/dist/inspector/styleEditors/Typography.js +11 -3
- package/dist/inspector/styleEditors/backgroundLayers.d.ts +24 -0
- package/dist/inspector/styleEditors/backgroundLayers.js +51 -0
- package/dist/inspector/styleEditors/gradientValue.d.ts +17 -0
- package/dist/inspector/styleEditors/gradientValue.js +114 -0
- package/dist/inspector/styleEditors/inlineAuthored.d.ts +10 -0
- package/dist/inspector/styleEditors/inlineAuthored.js +114 -0
- package/dist/inspector/styleEditors/layoutValue.d.ts +0 -8
- package/dist/inspector/styleEditors/layoutValue.js +0 -42
- package/dist/inspector/styleEditors/nudgeValue.d.ts +2 -2
- package/dist/inspector/styleEditors/nudgeValue.js +36 -8
- package/dist/inspector/tokens/TokenField.d.ts +7 -0
- package/dist/inspector/tokens/TokenField.js +35 -25
- package/dist/inspector/tokens/TokenLabel.js +5 -14
- package/dist/inspector/tokens/editActions.d.ts +1 -1
- package/dist/inspector/tokens/editActions.js +7 -1
- package/dist/inspector/ui/AtRuleContext.js +4 -6
- package/dist/inspector/ui/Button.d.ts +6 -2
- package/dist/inspector/ui/Button.js +4 -3
- package/dist/inspector/ui/ControlSurface.d.ts +2 -2
- package/dist/inspector/ui/ControlSurface.js +4 -3
- package/dist/inspector/ui/InlineStyleWarning.d.ts +11 -0
- package/dist/inspector/ui/InlineStyleWarning.js +13 -0
- package/dist/inspector/ui/InspectorPopover.d.ts +2 -1
- package/dist/inspector/ui/InspectorPopover.js +4 -5
- package/dist/inspector/ui/PopoverListbox.d.ts +2 -1
- package/dist/inspector/ui/PopoverListbox.js +8 -7
- package/dist/inspector/ui/SegmentedControl.d.ts +2 -1
- package/dist/inspector/ui/SegmentedControl.js +2 -2
- package/dist/inspector/ui/Select.d.ts +6 -1
- package/dist/inspector/ui/Select.js +7 -11
- package/dist/inspector/ui/SideValuesField.js +1 -1
- package/dist/inspector/ui/Tooltip.d.ts +26 -0
- package/dist/inspector/ui/Tooltip.js +32 -0
- package/dist/inspector/ui/classNames.d.ts +2 -0
- package/dist/inspector/ui/classNames.js +4 -0
- package/dist/inspector/ui/customCursors.d.ts +23 -0
- package/dist/inspector/ui/customCursors.js +122 -0
- package/dist/inspector/ui/dragCursor.d.ts +0 -2
- package/dist/inspector/ui/dragCursor.js +2 -10
- package/dist/inspector/ui/portalContainer.d.ts +2 -0
- package/dist/inspector/ui/portalContainer.js +6 -0
- package/dist/inspector/ui/styles.js +29 -21
- package/dist/inspector/workspace/commands.d.ts +9 -0
- package/dist/inspector/workspace/commands.js +82 -0
- package/dist/inspector/workspace/controller.d.ts +4 -0
- package/dist/inspector/workspace/controller.js +66 -0
- package/dist/inspector/workspace/handoff.d.ts +42 -0
- package/dist/inspector/workspace/handoff.js +115 -0
- package/dist/inspector/workspace/sentItems.d.ts +19 -0
- package/dist/inspector/workspace/sentItems.js +51 -0
- package/dist/inspector/workspace/timeline.d.ts +30 -0
- package/dist/inspector/workspace/timeline.js +108 -0
- package/dist/internal/agent-protocol.d.ts +19 -2
- package/dist/internal/agent-protocol.js +13 -0
- package/dist/nudge-ui.mjs +558 -311
- package/dist/project/artifacts.d.ts +13 -0
- package/dist/project/artifacts.js +253 -0
- package/dist/transport/artifacts.d.ts +8 -0
- package/dist/transport/artifacts.js +9 -0
- package/dist/transport/editor.js +3 -1
- package/dist/transport/routes.d.ts +2 -0
- package/dist/transport/routes.js +2 -0
- package/package.json +7 -3
- package/dist/inspector/changes/workspaceChanges.d.ts +0 -47
- package/dist/inspector/changes/workspaceChanges.js +0 -265
|
@@ -1,33 +1,56 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { Menu } from "@base-ui/react/menu";
|
|
3
|
+
import { iterationId } from "../canvas/frameContent.js";
|
|
2
4
|
import { useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
3
|
-
import { IconCheck, IconCopy, IconPlugConnected, IconSend, } from "@tabler/icons-react";
|
|
5
|
+
import { IconArtboard, IconBoltFilled, IconCheck, IconChevronDown, IconCopy, IconPlugConnected, IconSend, } from "@tabler/icons-react";
|
|
4
6
|
import { useChanges } from "../changes/changesLog.js";
|
|
5
|
-
import {
|
|
6
|
-
import { copyToClipboard } from "../prompt/copyToClipboard.js";
|
|
7
|
+
import { countPromptChanges } from "../prompt/generatePrompt.js";
|
|
7
8
|
import { loadCustomInstructions, saveCustomInstructions } from "../prompt/promptSettings.js";
|
|
8
9
|
import { getAgentConnectionStatus } from "../agent/connectionStatus.js";
|
|
9
10
|
import { SettingsDialog } from "../settings/SettingsDialog.js";
|
|
10
11
|
import { Button } from "../ui/Button.js";
|
|
12
|
+
import { portalContainer } from "../ui/portalContainer.js";
|
|
11
13
|
import { StatusCallout } from "../ui/StatusCallout.js";
|
|
12
14
|
import { getStructuralChanges, subscribeStructuralChanges } from "../projection/structuralProjection.js";
|
|
13
15
|
import { getNudgeUiRuntimeConfig } from "../runtime/runtimeConfig.js";
|
|
14
|
-
import {
|
|
16
|
+
import { getAgentClient, useAgentClient } from "../agent/client.js";
|
|
15
17
|
import { createAgentPresentationAdapter } from "../canvas/agentPresentation.js";
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
18
|
+
import { captureHandoffOwner, getAgentDispatch, verifyAndReconcileAgentDispatch, } from "../agent/verification.js";
|
|
19
|
+
import { clearSentItems, getSentItems, sentItemCount } from "../workspace/sentItems.js";
|
|
20
|
+
import { getClipboardHandoffRevision, getLastClipboardReconciledCount, subscribeClipboardHandoff, } from "../prompt/clipboardHandoff.js";
|
|
21
|
+
import { useSketches, settleSketchDispatch } from "../sketch/store.js";
|
|
20
22
|
import { SketchLayersPanel } from "../sketch/SketchLayersPanel.js";
|
|
21
23
|
import { isSendPromptShortcut, SEND_PROMPT_HOTKEY_EVENT } from "./shortcuts.js";
|
|
24
|
+
import { getFocusedCardId, getSelectedCardId, useCanvasCards, useFocusedCardId, useSelectedCardId } from "../canvas/canvasStore.js";
|
|
25
|
+
import { getEditableCardId, sketchBelongsToCard, useDrafts } from "../drafts/store.js";
|
|
26
|
+
import { copyHandoff, deliverHandoff, prepareHandoff, prepareIterationImplementationPrompt } from "../workspace/handoff.js";
|
|
27
|
+
import { copyToClipboard } from "../prompt/copyToClipboard.js";
|
|
28
|
+
import { useFrameComments } from "../comments/store.js";
|
|
29
|
+
import { reconcileComments } from "../comments/verification.js";
|
|
30
|
+
import { getRegisteredFrames } from "../canvas/projection.js";
|
|
22
31
|
export function CopyPromptButton({ settingsOpen: controlledSettingsOpen, settingsSection: controlledSettingsSection, onOpenSettings, onSettingsOpenChange, } = {}) {
|
|
23
32
|
const changes = useChanges();
|
|
33
|
+
const comments = useFrameComments();
|
|
34
|
+
useDrafts();
|
|
24
35
|
const sketches = useSketches();
|
|
25
|
-
const
|
|
36
|
+
const selectedDraftCardId = useSelectedCardId();
|
|
37
|
+
const focusedDraftCardId = useFocusedCardId();
|
|
38
|
+
const activeDraftCardId = getEditableCardId(selectedDraftCardId, focusedDraftCardId);
|
|
39
|
+
const canvasCards = useCanvasCards();
|
|
40
|
+
const activeContent = canvasCards.find((card) => card.id === activeDraftCardId)?.content;
|
|
41
|
+
const activeArtifactId = iterationId(activeContent);
|
|
42
|
+
const visibleSketches = sketches.filter((item) => sketchBelongsToCard(item.document, activeDraftCardId));
|
|
43
|
+
const pendingSketches = visibleSketches.filter((item) => item.status === "pending");
|
|
26
44
|
const structuralChanges = useSyncExternalStore(subscribeStructuralChanges, getStructuralChanges, getStructuralChanges);
|
|
27
45
|
useSyncExternalStore(subscribeClipboardHandoff, getClipboardHandoffRevision, getClipboardHandoffRevision);
|
|
28
46
|
const reconciledCount = getLastClipboardReconciledCount();
|
|
29
47
|
const [copied, setCopied] = useState(false);
|
|
30
|
-
const [
|
|
48
|
+
const [preparing, setPreparing] = useState(false);
|
|
49
|
+
const handoffBusy = useRef(false);
|
|
50
|
+
const [saveMessage, setSaveMessage] = useState(null);
|
|
51
|
+
const [agentOutcome, setAgentOutcome] = useState(null);
|
|
52
|
+
const [clipboardPhase, setClipboardPhase] = useState("idle");
|
|
53
|
+
const [undoClear, setUndoClear] = useState(null);
|
|
31
54
|
const [sketchFallback, setSketchFallback] = useState(null);
|
|
32
55
|
const [localSettingsOpen, setLocalSettingsOpen] = useState(false);
|
|
33
56
|
const [localSettingsSection, setLocalSettingsSection] = useState("instructions");
|
|
@@ -39,8 +62,13 @@ export function CopyPromptButton({ settingsOpen: controlledSettingsOpen, setting
|
|
|
39
62
|
const agent = useAgentClient(runtimeConfig.projectId, agentClient);
|
|
40
63
|
const agentRef = useRef(agent);
|
|
41
64
|
agentRef.current = agent;
|
|
42
|
-
const hasChanges = changes
|
|
43
|
-
|
|
65
|
+
const hasChanges = Boolean(activeArtifactId) || countPromptChanges(changes, structuralChanges, pendingSketches.length) + comments.length > 0;
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
if (!copied)
|
|
68
|
+
return;
|
|
69
|
+
const timer = window.setTimeout(() => setCopied(false), 1500);
|
|
70
|
+
return () => window.clearTimeout(timer);
|
|
71
|
+
}, [copied]);
|
|
44
72
|
useEffect(() => {
|
|
45
73
|
setCustomInstructions(loadCustomInstructions(runtimeConfig.projectId));
|
|
46
74
|
}, [runtimeConfig.projectId]);
|
|
@@ -60,14 +88,22 @@ export function CopyPromptButton({ settingsOpen: controlledSettingsOpen, setting
|
|
|
60
88
|
if (agent.state !== "completed" || revision === undefined)
|
|
61
89
|
return;
|
|
62
90
|
let active = true;
|
|
91
|
+
const dispatch = getAgentDispatch(revision);
|
|
63
92
|
void verifyAndReconcileAgentDispatch(revision)
|
|
93
|
+
.then(async (removed) => {
|
|
94
|
+
for (const [, iframe] of getRegisteredFrames()) {
|
|
95
|
+
if (iframe.contentDocument)
|
|
96
|
+
await reconcileComments(iframe.contentDocument);
|
|
97
|
+
}
|
|
98
|
+
return removed;
|
|
99
|
+
})
|
|
64
100
|
.then((removed) => {
|
|
65
101
|
if (!active)
|
|
66
102
|
return;
|
|
67
103
|
const latest = agentRef.current;
|
|
68
104
|
if (latest.request?.changeRevision !== revision || latest.state !== "completed")
|
|
69
105
|
return;
|
|
70
|
-
|
|
106
|
+
setAgentOutcome({ removed, dispatch });
|
|
71
107
|
})
|
|
72
108
|
.catch(() => {
|
|
73
109
|
if (!active)
|
|
@@ -75,7 +111,7 @@ export function CopyPromptButton({ settingsOpen: controlledSettingsOpen, setting
|
|
|
75
111
|
const latest = agentRef.current;
|
|
76
112
|
if (latest.request?.changeRevision !== revision || latest.state !== "completed")
|
|
77
113
|
return;
|
|
78
|
-
|
|
114
|
+
setAgentOutcome({ removed: 0, dispatch });
|
|
79
115
|
});
|
|
80
116
|
return () => {
|
|
81
117
|
active = false;
|
|
@@ -95,95 +131,151 @@ export function CopyPromptButton({ settingsOpen: controlledSettingsOpen, setting
|
|
|
95
131
|
&& !connecting
|
|
96
132
|
&& !working;
|
|
97
133
|
const canSend = agent.paired && agent.listenerActive && !working;
|
|
98
|
-
const
|
|
134
|
+
const changeCount = countPromptChanges(changes, structuralChanges, canSend ? pendingSketches.length : 0) + comments.length;
|
|
135
|
+
const disabled = preparing || connecting || working || (!canConnect && !hasChanges);
|
|
99
136
|
const agentStatus = getAgentConnectionStatus(agent);
|
|
100
137
|
const statusAction = agentStatus.action;
|
|
101
|
-
const label =
|
|
102
|
-
? "
|
|
103
|
-
:
|
|
104
|
-
? "
|
|
105
|
-
:
|
|
106
|
-
? "
|
|
107
|
-
:
|
|
108
|
-
? "
|
|
109
|
-
:
|
|
110
|
-
? "
|
|
111
|
-
:
|
|
138
|
+
const label = preparing
|
|
139
|
+
? "Saving iteration…"
|
|
140
|
+
: copied
|
|
141
|
+
? "Copied!"
|
|
142
|
+
: connecting
|
|
143
|
+
? "Connecting…"
|
|
144
|
+
: working
|
|
145
|
+
? "Agent working…"
|
|
146
|
+
: canConnect && !activeArtifactId
|
|
147
|
+
? "Connect agent"
|
|
148
|
+
: canSend && !activeArtifactId
|
|
149
|
+
? "Send prompt"
|
|
150
|
+
: "Copy prompt";
|
|
112
151
|
const icon = copied
|
|
113
152
|
? _jsx(IconCheck, { size: "var(--icon-size-small)", stroke: 1.8, "aria-hidden": "true" })
|
|
114
|
-
: canConnect || connecting
|
|
153
|
+
: !activeArtifactId && (canConnect || connecting)
|
|
115
154
|
? _jsx(IconPlugConnected, { size: "var(--icon-size-small)", stroke: 1.8, "aria-hidden": "true" })
|
|
116
|
-
: canSend || working
|
|
155
|
+
: !activeArtifactId && (canSend || working)
|
|
117
156
|
? _jsx(IconSend, { size: "var(--icon-size-small)", stroke: 1.8, "aria-hidden": "true" })
|
|
118
157
|
: _jsx(IconCopy, { size: "var(--icon-size-small)", stroke: "var(--icon-stroke-width)", "aria-hidden": "true" });
|
|
119
158
|
async function onClick() {
|
|
120
|
-
if (disabled)
|
|
121
|
-
return;
|
|
122
|
-
if (canConnect) {
|
|
123
|
-
await agentClient.connect();
|
|
159
|
+
if (disabled || handoffBusy.current)
|
|
124
160
|
return;
|
|
161
|
+
handoffBusy.current = true;
|
|
162
|
+
setPreparing(Boolean(activeArtifactId) && !canConnect);
|
|
163
|
+
try {
|
|
164
|
+
await handoff();
|
|
125
165
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
const
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
});
|
|
149
|
-
if (response) {
|
|
150
|
-
if (sketchHandoff) {
|
|
151
|
-
await markSketchesHandingOff(sketchHandoff.entries.map((entry) => ({ id: entry.id, revision: entry.revision })), revision, sketchHandoff.localBatchId, response.request.requestId);
|
|
152
|
-
}
|
|
153
|
-
return;
|
|
166
|
+
finally {
|
|
167
|
+
handoffBusy.current = false;
|
|
168
|
+
setPreparing(false);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
async function copyIterationPrompt(target) {
|
|
172
|
+
if (!activeArtifactId || disabled || handoffBusy.current)
|
|
173
|
+
return;
|
|
174
|
+
handoffBusy.current = true;
|
|
175
|
+
setCopied(false);
|
|
176
|
+
setPreparing(true);
|
|
177
|
+
try {
|
|
178
|
+
const request = {
|
|
179
|
+
cardId: getEditableCardId(getSelectedCardId(), getFocusedCardId()),
|
|
180
|
+
hints: { framework: runtimeConfig.framework, stylingSystem: runtimeConfig.stylingSystem },
|
|
181
|
+
customInstructions,
|
|
182
|
+
pendingSketches,
|
|
183
|
+
};
|
|
184
|
+
if (target === "application") {
|
|
185
|
+
const prompt = await prepareIterationImplementationPrompt(request);
|
|
186
|
+
try {
|
|
187
|
+
await copyToClipboard(prompt);
|
|
154
188
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
discardAgentDispatch(revision);
|
|
158
|
-
const latestAgent = agentClient.getSnapshot();
|
|
159
|
-
setSketchFallback({
|
|
160
|
-
prompt: text,
|
|
161
|
-
error: latestAgent.request?.error
|
|
162
|
-
?? latestAgent.error
|
|
163
|
-
?? "The agent did not accept the sketch attachments.",
|
|
164
|
-
});
|
|
165
|
-
return;
|
|
189
|
+
catch {
|
|
190
|
+
throw new Error("The iteration was saved, but the prompt could not be copied. Try again.");
|
|
166
191
|
}
|
|
167
192
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
await
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
});
|
|
176
|
-
return;
|
|
193
|
+
else {
|
|
194
|
+
const prepared = await prepareHandoff(request);
|
|
195
|
+
try {
|
|
196
|
+
await copyHandoff(prepared);
|
|
197
|
+
}
|
|
198
|
+
catch {
|
|
199
|
+
throw new Error("The iteration was saved, but the prompt could not be copied. Try again.");
|
|
177
200
|
}
|
|
178
201
|
}
|
|
179
|
-
|
|
202
|
+
setSaveMessage(null);
|
|
203
|
+
setCopied(true);
|
|
204
|
+
}
|
|
205
|
+
catch (error) {
|
|
206
|
+
setSaveMessage(error instanceof Error ? error.message : "The prompt could not be copied. Try again.");
|
|
207
|
+
}
|
|
208
|
+
finally {
|
|
209
|
+
handoffBusy.current = false;
|
|
210
|
+
setPreparing(false);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
async function handoff() {
|
|
214
|
+
if (disabled)
|
|
215
|
+
return;
|
|
216
|
+
if (canConnect) {
|
|
217
|
+
await agentClient.connect();
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
let prepared;
|
|
221
|
+
try {
|
|
222
|
+
prepared = await prepareHandoff({
|
|
223
|
+
cardId: getEditableCardId(getSelectedCardId(), getFocusedCardId()),
|
|
224
|
+
hints: { framework: runtimeConfig.framework, stylingSystem: runtimeConfig.stylingSystem },
|
|
225
|
+
customInstructions,
|
|
226
|
+
pendingSketches,
|
|
227
|
+
});
|
|
228
|
+
setSaveMessage(null);
|
|
180
229
|
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
230
|
+
catch (error) {
|
|
231
|
+
setSaveMessage(error instanceof Error ? error.message : "The HTML iteration could not be saved.");
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
setAgentOutcome(null);
|
|
235
|
+
setUndoClear(null);
|
|
236
|
+
setClipboardPhase("idle");
|
|
237
|
+
setSketchFallback(null);
|
|
238
|
+
const outcome = await deliverHandoff(prepared, runtimeConfig.projectId, canSend ? agentClient : null);
|
|
239
|
+
if (outcome.kind === "sketch-failed") {
|
|
240
|
+
setSketchFallback({ handoff: outcome.handoff, error: outcome.error });
|
|
241
|
+
return;
|
|
184
242
|
}
|
|
243
|
+
if (outcome.kind === "sent")
|
|
244
|
+
return;
|
|
185
245
|
setCopied(true);
|
|
186
|
-
|
|
246
|
+
setClipboardPhase("copied");
|
|
247
|
+
}
|
|
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
|
+
const handoffOwner = captureHandoffOwner(activeDraftCardId);
|
|
271
|
+
const sentItems = getSentItems(handoffOwner.draftId, handoffOwner.target, agentOutcome?.dispatch ?? null);
|
|
272
|
+
const remainingCount = sentItemCount(sentItems);
|
|
273
|
+
const showImplemented = (agentOutcome?.removed ?? 0) > 0 || reconciledCount > 0
|
|
274
|
+
|| (remainingCount > 0 && (agentOutcome !== null || clipboardPhase === "returned"));
|
|
275
|
+
function clearRemaining() {
|
|
276
|
+
const restore = clearSentItems(sentItems);
|
|
277
|
+
if (restore)
|
|
278
|
+
setUndoClear(() => restore);
|
|
187
279
|
}
|
|
188
280
|
useEffect(() => {
|
|
189
281
|
function onKeydown(event) {
|
|
@@ -231,12 +323,11 @@ export function CopyPromptButton({ settingsOpen: controlledSettingsOpen, setting
|
|
|
231
323
|
}
|
|
232
324
|
openMcpConnection();
|
|
233
325
|
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
}).catch(() => undefined);
|
|
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: activeArtifactId ? undefined : onClick, children: [icon, label, changeCount > 0 ? (_jsx("span", { className: "copy-prompt__change-count", "data-test": "copy-prompt-change-count", children: changeCount })) : null, activeArtifactId ? _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: [activeArtifactId ? (_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: [_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" })] })] })] }) }) })] }, activeDraftCardId)) : promptButton, _jsx(SketchLayersPanel, {}), 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, undoClear ? (_jsxs("p", { className: "copy-prompt__hint copy-prompt__hint--centered copy-prompt__hint--implemented", "data-test": "handoff-cleared-hint", role: "status", children: ["Cleared stale edits.", " ", _jsx("button", { type: "button", className: "copy-prompt__hint-action", "data-test": "handoff-undo-clear", onClick: () => {
|
|
328
|
+
undoClear();
|
|
329
|
+
setUndoClear(null);
|
|
330
|
+
}, children: "Undo" })] })) : 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: () => {
|
|
331
|
+
void copyHandoff(sketchFallback.handoff).then(() => setSketchFallback(null)).catch(() => undefined);
|
|
241
332
|
}, 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() })] }));
|
|
242
333
|
}
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
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
|
+
import { useCanvasPresentation } from "../canvas/viewStore.js";
|
|
4
|
+
import { Disclosure } from "../ui/Disclosure.js";
|
|
2
5
|
import gridIllustration from "../ui/assets/grid.svg";
|
|
3
|
-
|
|
4
|
-
if (typeof navigator === "undefined")
|
|
5
|
-
return false;
|
|
6
|
-
return /Mac|iPhone|iPad|iPod/.test(navigator.platform || navigator.userAgent);
|
|
7
|
-
}
|
|
6
|
+
import { getPlatformModifierKey, isMacPlatform } from "./shortcuts.js";
|
|
8
7
|
export function EmptyState() {
|
|
8
|
+
const presentation = useCanvasPresentation();
|
|
9
|
+
const canvas = presentation === "canvas";
|
|
9
10
|
const macPlatform = isMacPlatform();
|
|
10
|
-
const modifierKey =
|
|
11
|
+
const modifierKey = getPlatformModifierKey();
|
|
11
12
|
const modifierName = macPlatform ? "Command" : "Control";
|
|
12
13
|
const optionKey = macPlatform ? "⌥" : "Alt";
|
|
13
14
|
const optionName = macPlatform ? "Option" : "Alt";
|
|
14
|
-
return (_jsxs("div", { className: "empty-state"
|
|
15
|
+
return (_jsxs("div", { className: `empty-state${canvas ? " empty-state--canvas" : ""}`, "data-test": "empty-state", children: [canvas ? (_jsxs("div", { className: "empty-state__canvas", "data-test": "canvas-intro", children: [_jsx("h2", { className: "empty-state__title", children: "Using the canvas" }), _jsxs("p", { children: [_jsx("span", { className: "empty-state__live-badge", children: _jsx(IconBoltFilled, { "aria-hidden": "true" }) }), _jsxs("span", { children: [_jsx("strong", { children: "Live app" }), "A view of your real running app"] })] }), _jsxs("p", { children: [_jsx(IconArtboard, { "aria-hidden": "true" }), _jsxs("span", { children: [_jsx("strong", { children: "HTML iterations" }), "Unlinked from live app for isolated changes. Ask your agent to implement in live app once ready."] })] }), _jsxs("p", { children: [_jsx(IconSparkles, { "aria-hidden": "true" }), _jsxs("span", { children: [_jsx("strong", { children: "Agent with MCP" }), "Ask your agent to: lay out flows, show page states and create iterations."] })] })] })) : (_jsxs(_Fragment, { children: [_jsx("img", { className: "empty-state__icon", src: gridIllustration, alt: "", "aria-hidden": "true" }), _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: !canvas, 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)] }));
|
|
15
16
|
}
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useMemo, useState } from "react";
|
|
3
|
-
import { IconLayoutSidebarRight
|
|
3
|
+
import { IconLayoutSidebarRight } from "@tabler/icons-react";
|
|
4
4
|
import { useInspectorOpen, toggleInspector, 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";
|
|
8
8
|
import { resolveSelectionFromElement } from "../selection/resolveSelection.js";
|
|
9
|
+
import { AgentStatusButton } from "./AgentStatusButton.js";
|
|
9
10
|
import { SpacingBox } from "../styleEditors/SpacingBox.js";
|
|
10
11
|
import { Typography } from "../styleEditors/Typography.js";
|
|
11
12
|
import { isTextRelevant } from "../styleEditors/textRelevance.js";
|
|
13
|
+
import { BackgroundEditor } from "../styleEditors/BackgroundEditor.js";
|
|
12
14
|
import { ColorPicker } from "../styleEditors/ColorPicker.js";
|
|
13
15
|
import { BorderEditor } from "../styleEditors/BorderEditor.js";
|
|
14
16
|
import { AppearanceSection } from "../styleEditors/AppearanceSection.js";
|
|
@@ -25,12 +27,11 @@ import { StatusCallout } from "../ui/StatusCallout.js";
|
|
|
25
27
|
import { IconButton } from "../ui/IconButton.js";
|
|
26
28
|
import { UI_STYLES } from "../ui/styles.js";
|
|
27
29
|
import { getActiveStyleState, setActiveStyleState } from "./styleState.js";
|
|
28
|
-
import { isEditableEvent } from "./shortcuts.js";
|
|
30
|
+
import { getInspectorToggleShortcutLabel, isEditableEvent } from "./shortcuts.js";
|
|
29
31
|
import { formatInspectorLabel } from "../ui/labels.js";
|
|
30
32
|
import { FieldRow } from "../ui/FieldRow.js";
|
|
31
33
|
import { Select } from "../ui/Select.js";
|
|
32
|
-
import {
|
|
33
|
-
import { hasWriteLease } from "../canvas/workspaceLease.js";
|
|
34
|
+
import { clearSelectedFrameChanges } from "../canvas/sessionStore.js";
|
|
34
35
|
import { useFocusedCardId, useSelectedCardId, } from "../canvas/canvasStore.js";
|
|
35
36
|
import { getActiveCanvasFrame } from "../canvas/activeCanvasDocument.js";
|
|
36
37
|
import { getElementWindow } from "../runtime/domRealm.js";
|
|
@@ -46,10 +47,8 @@ import { intersectTokenEntries } from "../inspection/selectionProperty.js";
|
|
|
46
47
|
import { isNudgeUiDev } from "../runtime/devFlag.js";
|
|
47
48
|
import { isDemoRuntime } from "../runtime/runtimeConfig.js";
|
|
48
49
|
import { SketchWorkspace } from "../sketch/SketchWorkspace.js";
|
|
49
|
-
import {
|
|
50
|
-
import {
|
|
51
|
-
import { clearSketchesForProject } from "../sketch/store.js";
|
|
52
|
-
import { closeSketchNote } from "../sketch/sketchNote.js";
|
|
50
|
+
import { useSketchInteractionActive } from "../sketch/interaction.js";
|
|
51
|
+
import { Tooltip } from "../ui/Tooltip.js";
|
|
53
52
|
function findFirstTokenRow(rows, properties) {
|
|
54
53
|
for (const property of properties) {
|
|
55
54
|
const row = findTokenRow(rows, property);
|
|
@@ -231,19 +230,12 @@ export function InspectorShell() {
|
|
|
231
230
|
setSettingsOpen(true);
|
|
232
231
|
}
|
|
233
232
|
function clearInspectorSession() {
|
|
234
|
-
|
|
235
|
-
clearRestoreCount();
|
|
236
|
-
if (!hasWriteLease())
|
|
237
|
-
return;
|
|
238
|
-
cancelSketchInteraction();
|
|
239
|
-
closeSketchNote();
|
|
240
|
-
clearSketchClipboardHandoff();
|
|
241
|
-
void clearSketchesForProject(runtimeConfig.projectId).catch(() => undefined);
|
|
233
|
+
clearSelectedFrameChanges();
|
|
242
234
|
}
|
|
243
|
-
return (_jsxs(_Fragment, { children: [_jsx("style", { "data-test": "inspector-styles", children: 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(IconButton, { variant: "quiet", label: "Collapse inspector", "data-test": "collapse-inspector", disabled: sketchActive, style: { marginLeft: "-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
235
|
+
return (_jsxs(_Fragment, { children: [_jsx("style", { "data-test": "inspector-styles", children: 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
|
+
cancelInlineTextEdit();
|
|
237
|
+
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: [isMultiSelection || 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: [isMultiSelection ? (_jsx("div", { className: "selection__summary", "data-test": "multi-selection-summary", children: _jsxs("span", { className: "selection__count", children: [selectedElements.length, " elements selected"] }) })) : null, 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: () => {
|
|
247
239
|
const overrideId = relinkElement(selected.domElement);
|
|
248
240
|
if (overrideId)
|
|
249
241
|
discardChangesForInstanceOverride(overrideId);
|
|
@@ -260,5 +252,5 @@ export function InspectorShell() {
|
|
|
260
252
|
return;
|
|
261
253
|
setActiveStyleState(nextState);
|
|
262
254
|
setStyleState(nextState);
|
|
263
|
-
} }) })) : null] })) : null, !isMultiSelection ? _jsx(ComponentPropsSection, { selected: selected }) : null, selectionEditable ? (_jsx(AtRuleContextProvider, { rows: tokenRows, children: _jsxs("div", { className: "style-editors", "data-test": "style-editors", children: [_jsx(LayoutSection, { element: selected, selection: styleSelection, entries: tokenEntries, tokenRows: tokenRows }, `layout-${styleState}`), _jsx(SpacingBox, { element: selected, selection: styleSelection, entries: tokenEntries, tokenRows: tokenRows }, `spacing-${styleState}`), _jsx(AppearanceSection, { element: selected, selection: styleSelection, entries: tokenEntries, tokenRows: tokenRows }, `appearance-${styleState}`), showText ? _jsxs(_Fragment, { children: [_jsx(Typography, { element: selected, selection: styleSelection, entries: tokenEntries, tokenRows: tokenRows }, `type-${styleState}`), _jsx(ColorPicker, { element: selected, selection: styleSelection, property: "color", entries: tokenEntries, tokenRow: findTokenRow(tokenRows, "color") }, `color-${styleState}`)] }) : null, _jsx(
|
|
255
|
+
} }) })) : null] })) : null, !isMultiSelection ? _jsx(ComponentPropsSection, { selected: selected }) : null, selectionEditable ? (_jsx(AtRuleContextProvider, { rows: tokenRows, children: _jsxs("div", { className: "style-editors", "data-test": "style-editors", children: [_jsx(LayoutSection, { element: selected, selection: styleSelection, entries: tokenEntries, tokenRows: tokenRows }, `layout-${styleState}`), _jsx(SpacingBox, { element: selected, selection: styleSelection, entries: tokenEntries, tokenRows: tokenRows }, `spacing-${styleState}`), _jsx(AppearanceSection, { element: selected, selection: styleSelection, entries: tokenEntries, tokenRows: tokenRows }, `appearance-${styleState}`), showText ? _jsxs(_Fragment, { children: [_jsx(Typography, { element: selected, selection: styleSelection, entries: tokenEntries, tokenRows: tokenRows }, `type-${styleState}`), _jsx(ColorPicker, { element: selected, selection: styleSelection, property: "color", entries: tokenEntries, tokenRow: findTokenRow(tokenRows, "color") }, `color-${styleState}`)] }) : null, _jsx(BackgroundEditor, { element: selected, selection: styleSelection, entries: tokenEntries, tokenRow: backgroundTokenRow }, `background-${styleState}`), _jsx(BorderEditor, { element: selected, selection: styleSelection, entries: tokenEntries, tokenRows: tokenRows }, `border-${styleState}`), _jsx(BoxShadowEditor, { element: selected, selection: styleSelection, entries: tokenEntries, tokenRows: tokenRows }, `box-shadow-${styleState}`)] }) })) : (_jsx(StatusCallout, { tone: "neutral", "data-test": "multi-selection-uneditable", children: "These repeated items are indistinguishable, so Nudge UI cannot safely target only part of the group. Select every repeated item to edit them together." }))] })) : (_jsx(EmptyState, {})), _jsx(ChangesLog, { onClearSession: clearInspectorSession })] })] }), sketchEnabled ? (_jsx(SketchWorkspace, { hostElement: sketchHost, projectId: runtimeConfig.projectId })) : null, !isOpen ? (_jsx("div", { className: "panel__restore", children: _jsx(Tooltip, { children: _jsx(IconButton, { variant: "quiet", label: "Show inspector", className: "panel__restore-button", "data-test": "show-inspector", onClick: () => setInspectorOpen(true), children: _jsx(IconLayoutSidebarRight, { size: "var(--icon-size-small)", stroke: "var(--icon-stroke-width)", "aria-hidden": "true" }) }) }) })) : null] }));
|
|
264
256
|
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useSyncExternalStore } from "react";
|
|
3
3
|
import { IconButton } from "../ui/IconButton.js";
|
|
4
|
+
import { Tooltip } from "../ui/Tooltip.js";
|
|
4
5
|
import { PeekOriginalIcon } from "./PeekOriginalIcon.js";
|
|
5
|
-
import {
|
|
6
|
+
import { draftChangeStore } from "../changes/draftChanges.js";
|
|
6
7
|
import { setOriginalPreviewActive, useOriginalPreviewActive, } from "./originalPreview.js";
|
|
7
|
-
function
|
|
8
|
-
return useSyncExternalStore(
|
|
9
|
-
const snapshot =
|
|
8
|
+
function useDraftChangeCount() {
|
|
9
|
+
return useSyncExternalStore(draftChangeStore.subscribe, () => {
|
|
10
|
+
const snapshot = draftChangeStore.getSnapshot();
|
|
10
11
|
return snapshot.changes.length + snapshot.structuralChanges.length;
|
|
11
12
|
}, () => 0);
|
|
12
13
|
}
|
|
@@ -17,7 +18,7 @@ function useWorkspaceChangeCount() {
|
|
|
17
18
|
*/
|
|
18
19
|
export function PeekOriginalButton() {
|
|
19
20
|
const active = useOriginalPreviewActive();
|
|
20
|
-
const changeCount =
|
|
21
|
+
const changeCount = useDraftChangeCount();
|
|
21
22
|
const disabled = changeCount === 0;
|
|
22
23
|
useEffect(() => {
|
|
23
24
|
if (!active)
|
|
@@ -35,23 +36,23 @@ export function PeekOriginalButton() {
|
|
|
35
36
|
useEffect(() => () => {
|
|
36
37
|
setOriginalPreviewActive(false);
|
|
37
38
|
}, []);
|
|
38
|
-
return (_jsx(
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
setOriginalPreviewActive(true);
|
|
45
|
-
}, onPointerUp: () => setOriginalPreviewActive(false), onPointerCancel: () => setOriginalPreviewActive(false), onLostPointerCapture: () => setOriginalPreviewActive(false), onKeyDown: (event) => {
|
|
46
|
-
if (disabled || event.repeat)
|
|
47
|
-
return;
|
|
48
|
-
if (event.key === " " || event.key === "Enter")
|
|
39
|
+
return (_jsx(Tooltip, { content: disabled ? "No changes to preview" : "Hold to view original", shortcut: disabled ? undefined : "\\", stableTrigger: true, children: _jsx(IconButton, { variant: "quiet", "data-test": "peek-original-button", label: "Hold to view original", "aria-pressed": active, "data-active": active ? "true" : "false", disabled: disabled, onPointerDown: (event) => {
|
|
40
|
+
if (disabled)
|
|
41
|
+
return;
|
|
42
|
+
if (event.pointerType === "mouse" && event.button !== 0)
|
|
43
|
+
return;
|
|
44
|
+
event.currentTarget.setPointerCapture?.(event.pointerId);
|
|
49
45
|
setOriginalPreviewActive(true);
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
46
|
+
}, onPointerUp: () => setOriginalPreviewActive(false), onPointerCancel: () => setOriginalPreviewActive(false), onLostPointerCapture: () => setOriginalPreviewActive(false), onKeyDown: (event) => {
|
|
47
|
+
if (disabled || event.repeat)
|
|
48
|
+
return;
|
|
49
|
+
if (event.key === " " || event.key === "Enter")
|
|
50
|
+
setOriginalPreviewActive(true);
|
|
51
|
+
}, onKeyUp: (event) => {
|
|
52
|
+
if (event.key === " " || event.key === "Enter")
|
|
53
|
+
setOriginalPreviewActive(false);
|
|
54
|
+
}, onBlur: () => setOriginalPreviewActive(false), onContextMenu: (event) => {
|
|
55
|
+
if (active)
|
|
56
|
+
event.preventDefault();
|
|
57
|
+
}, children: _jsx(PeekOriginalIcon, {}) }) }));
|
|
57
58
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useSyncExternalStore } from "react";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { draftChangeStore } from "../changes/draftChanges.js";
|
|
3
|
+
import { applyHostDraftProjection, compileDraftProjection, } from "../projection/draftProjection.js";
|
|
4
4
|
import { isEditorShellDocument } from "../runtime/editorShell.js";
|
|
5
5
|
let previewingOriginal = false;
|
|
6
6
|
const listeners = new Set();
|
|
@@ -29,8 +29,8 @@ function notifyOriginalPreviewListeners() {
|
|
|
29
29
|
function applyEmptyHostProjection() {
|
|
30
30
|
if (isEditorShellDocument())
|
|
31
31
|
return;
|
|
32
|
-
const { revision } =
|
|
33
|
-
|
|
32
|
+
const { revision } = draftChangeStore.getSnapshot();
|
|
33
|
+
applyHostDraftProjection({
|
|
34
34
|
sourceRevision: revision,
|
|
35
35
|
managedStyles: { rules: [], css: "" },
|
|
36
36
|
instanceOverrides: [],
|
|
@@ -42,7 +42,7 @@ function applyEmptyHostProjection() {
|
|
|
42
42
|
function applyCanonicalHostProjection() {
|
|
43
43
|
if (isEditorShellDocument())
|
|
44
44
|
return;
|
|
45
|
-
|
|
45
|
+
applyHostDraftProjection(compileDraftProjection(draftChangeStore.getSnapshot()));
|
|
46
46
|
}
|
|
47
47
|
/**
|
|
48
48
|
* Hold-to-view-original (NUD-30). While active the host document shows the
|