nudge-ui 0.2.3 → 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/dist/client.mjs +17 -9
- package/dist/inspector/agent/verification.d.ts +4 -6
- package/dist/inspector/agent/verification.js +60 -16
- package/dist/inspector/canvas/CanvasCard.js +2 -0
- package/dist/inspector/canvas/CanvasElementOverlay.js +17 -3
- package/dist/inspector/canvas/CanvasWorkspace.js +46 -66
- package/dist/inspector/canvas/frameScrollbarStyles.d.ts +3 -0
- package/dist/inspector/canvas/frameScrollbarStyles.js +21 -0
- package/dist/inspector/changes/changesLog.d.ts +3 -1
- package/dist/inspector/changes/changesLog.js +8 -0
- package/dist/inspector/changes/codecs.d.ts +1 -0
- package/dist/inspector/changes/codecs.js +10 -1
- package/dist/inspector/changes/draftChanges.d.ts +2 -0
- package/dist/inspector/changes/draftChanges.js +4 -0
- package/dist/inspector/changes/editModel.d.ts +10 -0
- package/dist/inspector/changes/editModel.js +9 -2
- package/dist/inspector/changes/types.d.ts +7 -0
- package/dist/inspector/comments/element.js +10 -3
- 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/iterations/capture.js +2 -1
- package/dist/inspector/projection/renderedInstance.d.ts +15 -2
- package/dist/inspector/projection/renderedInstance.js +53 -6
- package/dist/inspector/projection/structuralProjection.js +2 -2
- package/dist/inspector/projection/textProjection.js +56 -11
- package/dist/inspector/prompt/clipboardHandoff.d.ts +5 -0
- package/dist/inspector/prompt/clipboardHandoff.js +5 -0
- package/dist/inspector/prompt/generatePrompt.js +5 -1
- package/dist/inspector/selection/sourceSite.d.ts +12 -0
- package/dist/inspector/selection/sourceSite.js +28 -0
- package/dist/inspector/shell/CopyPromptButton.js +49 -7
- package/dist/inspector/styleEditors/BackgroundEditor.js +1 -1
- package/dist/inspector/tokens/TokenField.js +6 -4
- package/dist/inspector/tokens/editActions.js +6 -0
- package/dist/inspector/ui/styles.js +1 -1
- package/dist/inspector/workspace/sentItems.d.ts +19 -0
- package/dist/inspector/workspace/sentItems.js +51 -0
- package/package.json +2 -2
|
@@ -1,4 +1,4 @@
|
|
|
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
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";
|
|
@@ -15,7 +15,8 @@ import { getStructuralChanges, subscribeStructuralChanges } from "../projection/
|
|
|
15
15
|
import { getNudgeUiRuntimeConfig } from "../runtime/runtimeConfig.js";
|
|
16
16
|
import { getAgentClient, useAgentClient } from "../agent/client.js";
|
|
17
17
|
import { createAgentPresentationAdapter } from "../canvas/agentPresentation.js";
|
|
18
|
-
import { verifyAndReconcileAgentDispatch } from "../agent/verification.js";
|
|
18
|
+
import { captureHandoffOwner, getAgentDispatch, verifyAndReconcileAgentDispatch, } from "../agent/verification.js";
|
|
19
|
+
import { clearSentItems, getSentItems, sentItemCount } from "../workspace/sentItems.js";
|
|
19
20
|
import { getClipboardHandoffRevision, getLastClipboardReconciledCount, subscribeClipboardHandoff, } from "../prompt/clipboardHandoff.js";
|
|
20
21
|
import { useSketches, settleSketchDispatch } from "../sketch/store.js";
|
|
21
22
|
import { SketchLayersPanel } from "../sketch/SketchLayersPanel.js";
|
|
@@ -47,7 +48,9 @@ export function CopyPromptButton({ settingsOpen: controlledSettingsOpen, setting
|
|
|
47
48
|
const [preparing, setPreparing] = useState(false);
|
|
48
49
|
const handoffBusy = useRef(false);
|
|
49
50
|
const [saveMessage, setSaveMessage] = useState(null);
|
|
50
|
-
const [
|
|
51
|
+
const [agentOutcome, setAgentOutcome] = useState(null);
|
|
52
|
+
const [clipboardPhase, setClipboardPhase] = useState("idle");
|
|
53
|
+
const [undoClear, setUndoClear] = useState(null);
|
|
51
54
|
const [sketchFallback, setSketchFallback] = useState(null);
|
|
52
55
|
const [localSettingsOpen, setLocalSettingsOpen] = useState(false);
|
|
53
56
|
const [localSettingsSection, setLocalSettingsSection] = useState("instructions");
|
|
@@ -85,6 +88,7 @@ export function CopyPromptButton({ settingsOpen: controlledSettingsOpen, setting
|
|
|
85
88
|
if (agent.state !== "completed" || revision === undefined)
|
|
86
89
|
return;
|
|
87
90
|
let active = true;
|
|
91
|
+
const dispatch = getAgentDispatch(revision);
|
|
88
92
|
void verifyAndReconcileAgentDispatch(revision)
|
|
89
93
|
.then(async (removed) => {
|
|
90
94
|
for (const [, iframe] of getRegisteredFrames()) {
|
|
@@ -99,7 +103,7 @@ export function CopyPromptButton({ settingsOpen: controlledSettingsOpen, setting
|
|
|
99
103
|
const latest = agentRef.current;
|
|
100
104
|
if (latest.request?.changeRevision !== revision || latest.state !== "completed")
|
|
101
105
|
return;
|
|
102
|
-
|
|
106
|
+
setAgentOutcome({ removed, dispatch });
|
|
103
107
|
})
|
|
104
108
|
.catch(() => {
|
|
105
109
|
if (!active)
|
|
@@ -107,7 +111,7 @@ export function CopyPromptButton({ settingsOpen: controlledSettingsOpen, setting
|
|
|
107
111
|
const latest = agentRef.current;
|
|
108
112
|
if (latest.request?.changeRevision !== revision || latest.state !== "completed")
|
|
109
113
|
return;
|
|
110
|
-
|
|
114
|
+
setAgentOutcome({ removed: 0, dispatch });
|
|
111
115
|
});
|
|
112
116
|
return () => {
|
|
113
117
|
active = false;
|
|
@@ -227,7 +231,9 @@ export function CopyPromptButton({ settingsOpen: controlledSettingsOpen, setting
|
|
|
227
231
|
setSaveMessage(error instanceof Error ? error.message : "The HTML iteration could not be saved.");
|
|
228
232
|
return;
|
|
229
233
|
}
|
|
230
|
-
|
|
234
|
+
setAgentOutcome(null);
|
|
235
|
+
setUndoClear(null);
|
|
236
|
+
setClipboardPhase("idle");
|
|
231
237
|
setSketchFallback(null);
|
|
232
238
|
const outcome = await deliverHandoff(prepared, runtimeConfig.projectId, canSend ? agentClient : null);
|
|
233
239
|
if (outcome.kind === "sketch-failed") {
|
|
@@ -237,6 +243,39 @@ export function CopyPromptButton({ settingsOpen: controlledSettingsOpen, setting
|
|
|
237
243
|
if (outcome.kind === "sent")
|
|
238
244
|
return;
|
|
239
245
|
setCopied(true);
|
|
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);
|
|
240
279
|
}
|
|
241
280
|
useEffect(() => {
|
|
242
281
|
function onKeydown(event) {
|
|
@@ -285,7 +324,10 @@ export function CopyPromptButton({ settingsOpen: controlledSettingsOpen, setting
|
|
|
285
324
|
openMcpConnection();
|
|
286
325
|
}
|
|
287
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] }));
|
|
288
|
-
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,
|
|
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: () => {
|
|
289
331
|
void copyHandoff(sketchFallback.handoff).then(() => setSketchFallback(null)).catch(() => undefined);
|
|
290
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() })] }));
|
|
291
333
|
}
|
|
@@ -26,7 +26,7 @@ export function BackgroundEditor(props) {
|
|
|
26
26
|
const elements = selection?.domElements ?? [el];
|
|
27
27
|
const source = readBackgroundLayers((property, fallback) => getStateStyleValue(el, property, fallback));
|
|
28
28
|
const base = source.at(-1);
|
|
29
|
-
const authoredColor = props.tokenRow?.property === "background-color"
|
|
29
|
+
const authoredColor = props.tokenRow?.property === "background-color" || props.tokenRow?.property === "background"
|
|
30
30
|
? props.tokenRow.authored ?? props.tokenRow.declaredValue : undefined;
|
|
31
31
|
if (base?.baseColor && authoredColor) {
|
|
32
32
|
const table = Object.fromEntries((props.entries ?? getNudgeUiTokenEntries()).map((entry) => [entry.name, entry]));
|
|
@@ -104,11 +104,13 @@ function primaryFontFamily(value) {
|
|
|
104
104
|
return value.trim();
|
|
105
105
|
}
|
|
106
106
|
function rgbToHex(value) {
|
|
107
|
-
const
|
|
108
|
-
|
|
107
|
+
const rgb = value.match(/^rgba?\(\s*(\d+(?:\.\d+)?)\D+(\d+(?:\.\d+)?)\D+(\d+(?:\.\d+)?)/i);
|
|
108
|
+
const srgb = rgb ? null : value.match(/^color\(\s*srgb\s+([\d.e+-]+)\s+([\d.e+-]+)\s+([\d.e+-]+)/i);
|
|
109
|
+
const channels = rgb ? [rgb[1], rgb[2], rgb[3]].map(Number) : srgb ? [srgb[1], srgb[2], srgb[3]].map((part) => Number(part) * 255) : null;
|
|
110
|
+
if (!channels || channels.some((channel) => !Number.isFinite(channel)))
|
|
109
111
|
return null;
|
|
110
|
-
return `#${
|
|
111
|
-
.map((
|
|
112
|
+
return `#${channels
|
|
113
|
+
.map((channel) => Math.max(0, Math.min(255, Math.round(channel))).toString(16).padStart(2, "0"))
|
|
112
114
|
.join("")}`;
|
|
113
115
|
}
|
|
114
116
|
export function colorValueToHex(value) {
|
|
@@ -42,6 +42,10 @@ function sourceFields(el) {
|
|
|
42
42
|
file: parsed.file,
|
|
43
43
|
line: parsed.line,
|
|
44
44
|
column: parsed.column,
|
|
45
|
+
sourceEvidence: {
|
|
46
|
+
tagName: normalizeRuntimeTag(el.tagName),
|
|
47
|
+
props: boundRuntimeEvidence(el.getAttribute("data-cprops")),
|
|
48
|
+
},
|
|
45
49
|
};
|
|
46
50
|
}
|
|
47
51
|
export { getPendingRules, getChangesList as getChangeRecords, clearActiveDraft as resetPendingRules } from "../changes/changesLog.js";
|
|
@@ -87,6 +91,7 @@ export function swapTokens(target, changes) {
|
|
|
87
91
|
newToken: change.newToken,
|
|
88
92
|
source: { file: source.file, line: source.line, component: cid },
|
|
89
93
|
runtimeEvidence: source.runtimeEvidence,
|
|
94
|
+
sourceEvidence: source.sourceEvidence,
|
|
90
95
|
state,
|
|
91
96
|
...scopePlan.get(el),
|
|
92
97
|
};
|
|
@@ -155,6 +160,7 @@ function buildStyleRecord(el, scopePlan, { property, value, oldRawValue, metadat
|
|
|
155
160
|
oldRawValue: (oldRawValue ?? getStateStyleValue(el, property)) || undefined,
|
|
156
161
|
source: { file: source.file, line: source.line, component: cid },
|
|
157
162
|
runtimeEvidence: source.runtimeEvidence,
|
|
163
|
+
sourceEvidence: source.sourceEvidence,
|
|
158
164
|
state,
|
|
159
165
|
...scopePlan.get(el),
|
|
160
166
|
};
|
|
@@ -18,7 +18,7 @@ const inspectorPopoverStyles = ".inspector-popover__positioner {\n z-index: 30;
|
|
|
18
18
|
const sideValuesFieldStyles = ".side-values {\n display: flex;\n min-width: 0;\n flex-direction: column;\n gap: var(--space-8);\n}\n\n.side-values__header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n}\n\n.side-values__label {\n min-width: 0;\n color: var(--text-secondary);\n font-size: var(--font-size-base);\n line-height: 1.25;\n}\n\n.side-values__linked {\n min-width: 0;\n}\n\n.side-values__value-row {\n display: grid;\n min-width: 0;\n grid-template-columns: minmax(0, 1fr) auto;\n align-items: center;\n gap: var(--space-8);\n}\n\n.side-values[data-expanded=\"true\"] .side-values__value-row {\n align-items: start;\n}\n\n.side-values__linked-row {\n grid-template-columns: auto minmax(0, 1fr) auto;\n}\n\n.side-values__linked-row--no-label {\n grid-template-columns: minmax(0, 1fr) auto;\n}\n\n.side-values__linked-row .side-values__label {\n white-space: nowrap;\n}\n\n.side-values__pairs {\n display: grid;\n min-width: 0;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: var(--space-8);\n}\n\n.side-values__grid {\n display: grid;\n min-width: 0;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n grid-template-areas:\n \"left top\"\n \"right bottom\";\n gap: var(--space-8);\n}\n\n.side-values__grid [data-side=\"left\"] {\n grid-area: left;\n}\n\n.side-values__grid [data-side=\"right\"] {\n grid-area: right;\n}\n\n.side-values__grid [data-side=\"top\"] {\n grid-area: top;\n}\n\n.side-values__grid [data-side=\"bottom\"] {\n grid-area: bottom;\n}\n\n.side-values__grid[data-layout=\"corners\"] {\n grid-template-areas:\n \"top-left top-right\"\n \"bottom-left bottom-right\";\n}\n\n.side-values__grid[data-layout=\"corners\"] [data-side=\"top\"] {\n grid-area: top-left;\n}\n\n.side-values__grid[data-layout=\"corners\"] [data-side=\"right\"] {\n grid-area: top-right;\n}\n\n.side-values__grid[data-layout=\"corners\"] [data-side=\"bottom\"] {\n grid-area: bottom-right;\n}\n\n.side-values__grid[data-layout=\"corners\"] [data-side=\"left\"] {\n grid-area: bottom-left;\n}\n\n.side-values__side {\n color: var(--text-muted);\n}\n\n.side-values__icon {\n width: var(--icon-size-small);\n height: var(--icon-size-small);\n flex: 0 0 var(--icon-size-small);\n fill: none;\n stroke: currentColor;\n stroke-linecap: round;\n stroke-linejoin: round;\n stroke-width: var(--icon-stroke-width);\n}\n\n.side-values__axis-icon {\n color: var(--text-secondary);\n}\n\n.side-values__side-icon {\n color: var(--text-secondary);\n}\n\n.side-values__icon-emphasis,\n.side-values__icon-emphasis path {\n stroke-width: var(--icon-stroke-width);\n}\n\n.side-values__control {\n display: flex;\n align-self: stretch;\n min-width: 0;\n flex: 1 1 auto;\n}\n";
|
|
19
19
|
const tooltipStyles = ".tooltip__trigger {\n display: inline-flex;\n}\n\n.tooltip__trigger[data-tooltip-trigger-disabled] > * {\n pointer-events: none;\n}\n\n.tooltip__positioner {\n z-index: 35;\n pointer-events: auto;\n}\n\n.tooltip__popup {\n position: relative;\n display: inline-flex;\n align-items: center;\n gap: var(--space-8);\n width: max-content;\n max-width: min(320px, calc(100vw - var(--space-24)));\n padding: var(--space-4) var(--space-8);\n border: 0;\n border-radius: var(--radius-8);\n background: var(--surface-raised-2x);\n box-shadow: var(--shadow-popup);\n color: var(--text-primary);\n font-family: var(--font-family);\n font-size: var(--font-size-base);\n font-weight: var(--font-weight-base);\n line-height: 1.3;\n}\n\n.tooltip__popup[data-open] {\n animation: tooltip-enter 150ms ease-out;\n}\n\n@keyframes tooltip-enter {\n from {\n transform: scale(0.9);\n }\n to {\n transform: scale(1);\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .tooltip__popup[data-open] {\n animation: none;\n }\n}\n\n.tooltip__content {\n min-width: 0;\n position: relative;\n z-index: 1;\n}\n\n.tooltip__shortcut {\n flex: 0 0 auto;\n position: relative;\n z-index: 1;\n color: var(--text-secondary);\n font: inherit;\n line-height: inherit;\n white-space: nowrap;\n}\n";
|
|
20
20
|
const inlineStyleWarningStyles = ".inline-style-warning {\n display: inline-flex;\n flex: 0 0 auto;\n align-items: center;\n justify-content: center;\n width: var(--icon-size-small);\n height: var(--icon-size-small);\n padding: 0;\n border: 0;\n border-radius: 50%;\n background: var(--warning, #b45309);\n color: var(--surface-raised-2x);\n font-size: 11px;\n font-weight: 700;\n line-height: 1;\n cursor: help;\n}\n\n.inline-style-warning:focus-visible {\n outline: 0;\n box-shadow: 0 0 0 2px var(--accent);\n}\n\n.inline-style-warning__symbol {\n display: block;\n line-height: 1;\n}\n";
|
|
21
|
-
const inspectorShellStyles = ":host { --panel-width: min(320px, 100vw); }\n\n.panel {\n position: fixed;\n inset: 0 0 0 auto;\n z-index: 2;\n width: var(--panel-width);\n height: 100dvh;\n overflow: auto;\n background: var(--surface-panel);\n color: var(--text-primary);\n border: 0;\n border-left: 1px solid var(--border-subtle);\n border-radius: var(--radius-0);\n font-family: var(--font-family);\n font-size: var(--font-size-base);\n line-height: 1.35;\n display: flex;\n flex-direction: column;\n pointer-events: auto;\n cursor: default;\n scrollbar-color: var(--border-strong) transparent;\n scrollbar-width: thin;\n}\n\n.panel[data-open=\"false\"] {\n display: none;\n}\n\n.panel__restore {\n position: fixed;\n top: max(12px, env(safe-area-inset-top));\n right: max(12px, env(safe-area-inset-right));\n z-index: calc(var(--z-index) + 1);\n display: flex;\n align-items: center;\n justify-content: center;\n width: calc(var(--control-height-large) + (var(--space-4) * 2));\n height: calc(var(--control-height-large) + (var(--space-4) * 2));\n padding: var(--space-4);\n border-radius: var(--radius-12);\n background: var(--surface-raised-2x);\n box-shadow: var(--shadow-popup);\n pointer-events: auto;\n animation: panel-restore-in 160ms ease-out;\n}\n\n.panel__restore-button.icon-button {\n width: 100%;\n height: 100%;\n}\n\n@keyframes panel-restore-in {\n from { opacity: 0; transform: translateX(8px); }\n to { opacity: 1; transform: translateX(0); }\n}\n\n.scope__warning {\n color: var(--warning-text);\n font-weight: 500;\n}\n\n.panel__tabs {\n display: flex;\n flex-direction: column;\n gap: var(--space-8);\n padding: var(--space-12) var(--space-24);\n border-bottom: 1px solid var(--border-subtle);\n}\n\n.panel__header-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-8);\n width: 100%;\n}\n\n.panel__header-actions,\n.panel__copy-row {\n display: flex;\n align-items: center;\n}\n\n.panel__header-actions {\n min-width: 0;\n gap: var(--space-4);\n}\n\n.panel__copy-row {\n gap: var(--space-8);\n}\n\n.panel__header-divider {\n width: 1px;\n height: var(--control-height-large);\n margin: 0 var(--space-4);\n background: var(--border-subtle);\n}\n\n.panel__copy-row {\n width: 100%;\n}\n\n.copy-prompt__stack {\n width: 100%;\n min-width: 0;\n}\n\n.copy-prompt__main.button {\n width: 100%;\n position: relative;\n}\n\n.copy-prompt__menu {\n width: max(var(--anchor-width), 280px);\n max-width: calc(100vw - 24px);\n}\n\n.copy-prompt__menu-item {\n display: flex;\n align-items: flex-start;\n gap: var(--space-8);\n padding: var(--space-8);\n border-radius: var(--radius-4);\n color: var(--text-primary);\n font-size: var(--font-size-base);\n line-height: 1.4;\n cursor: pointer;\n outline: 0;\n}\n\n.copy-prompt__menu-item[data-highlighted] {\n background: var(--surface-control);\n}\n\n.copy-prompt__menu-icon {\n flex: 0 0 auto;\n color: var(--text-secondary);\n}\n\n.copy-prompt__menu-icon--live {\n color: var(--accent);\n}\n\n.copy-prompt__menu-content {\n display: flex;\n flex: 1;\n flex-direction: column;\n gap: var(--space-4);\n min-width: 0;\n}\n\n.copy-prompt__menu-title {\n font-weight: var(--font-weight-base);\n}\n\n.copy-prompt__menu-description {\n color: var(--text-secondary);\n overflow-wrap: anywhere;\n}\n\n.copy-prompt__menu-description code {\n font-family: var(--font-mono);\n}\n\n.agent-status-button {\n position: relative;\n}\n\n.agent-status-button__avatars {\n display: inline-flex;\n align-items: center;\n}\n\n.agent-status-button__avatar {\n width: 20px;\n height: 20px;\n display: block;\n background: var(--surface-raised-2x);\n border-radius: 50%;\n box-shadow: 0 0 0 1px var(--border-subtle);\n padding: 2px;\n}\n\n.agent-status-button__avatar svg {\n width: 100%;\n height: 100%;\n display: block;\n}\n\n.agent-status-button__avatar + .agent-status-button__avatar {\n margin-left: calc(var(--space-4) * -1);\n}\n\n.agent-status-button__dot {\n position: absolute;\n top: 50%;\n right: 3px;\n width: 6px;\n height: 6px;\n transform: translateY(-50%);\n border-radius: 50%;\n background: var(--text-muted);\n}\n\n.agent-status-button[data-mcp-listening=\"true\"] .agent-status-button__dot {\n background: var(--success);\n}\n\n.copy-prompt__hint {\n margin: var(--space-8) 0 0;\n color: var(--text-secondary);\n font-size: var(--font-size-small);\n line-height: 1.4;\n}\n\n.copy-prompt__hint--centered {\n text-align: center;\n}\n\n.copy-prompt__hint--implemented {\n font-size: var(--font-size-base);\n}\n\n.copy-prompt__hint code {\n font-family: var(--font-mono);\n}\n\n.copy-prompt__agent-status {\n margin-top: var(--space-8);\n}\n\n.copy-prompt__agent-status-content {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-8);\n}\n\n.copy-prompt__agent-status-content > span {\n min-width: 0;\n}\n\n.copy-prompt__agent-status-content .button--quiet {\n flex: 0 0 auto;\n color: inherit;\n}\n\n.copy-prompt__sketch-fallback {\n display: grid;\n gap: var(--space-8);\n margin-top: var(--space-8);\n}\n\n.panel__body {\n min-height: auto;\n padding: 0 20px 28px;\n background: var(--surface-panel);\n color: var(--text-secondary);\n overflow: visible;\n flex: 0 0 auto;\n}\n\n.panel__body:has(.empty-state) {\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n min-height: 0;\n}\n\n.panel::-webkit-scrollbar {\n width: 6px;\n}\n\n.panel::-webkit-scrollbar-thumb {\n background: var(--border-strong);\n border-radius: var(--radius-pill);\n}\n\n.selection {\n display: flex;\n flex-direction: column;\n gap: var(--space-8);\n padding: 14px 0 16px;\n border-bottom: 1px solid var(--border-subtle);\n}\n\n.selection--without-scope-callout {\n border-bottom: 0;\n}\n\n.selection__summary {\n display: grid;\n gap: 2px;\n}\n\n.selection__count {\n color: var(--text-primary);\n font-weight: 600;\n}\n\n.style-state {\n grid-template-columns: var(--label-column) minmax(0, 1fr);\n column-gap: var(--space-8);\n}\n\n.scope {\n margin-top: var(--space-8);\n}\n\n.scope__action {\n margin-top: 0;\n}\n\n.scope__unlinked,\n.scope__linked {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-8);\n}\n\n.style-editors {\n margin-top: 0;\n background: var(--surface-panel);\n border-top: 0;\n padding-top: 0;\n}\n\n.component-props__source {\n color: var(--text-muted-subtle);\n font-size: 10px;\n font-weight: 650;\n letter-spacing: 0.06em;\n text-transform: uppercase;\n}\n\n.component-props .field-row__label {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.inline-text-diagnostic {\n margin-top: 12px;\n font-weight: 400;\n}\n\n.style-editors__title {\n color: var(--text-muted);\n margin-bottom: 8px;\n font-weight: 600;\n}\n\n.empty-state + .changes {\n margin-top: auto;\n}\n\n.changes__empty {\n color: var(--text-muted-subtle);\n}\n\n.editor {\n margin: 0;\n padding: var(--space-8) 0;\n background: var(--surface-panel);\n border: 0;\n border-bottom: 1px solid var(--border-subtle);\n border-radius: 0;\n display: flex;\n flex-direction: column;\n gap: var(--space-8);\n}\n\n.editor__title {\n color: var(--text-primary);\n font-size: var(--font-size-base);\n font-weight: var(--font-weight-label);\n letter-spacing: -0.02em;\n min-height: var(--control-height-large);\n display: flex;\n align-items: center;\n justify-content: space-between;\n text-transform: none;\n}\n\n.editor__title-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n}\n\n.editor__title-row .editor__title {\n margin-bottom: 0;\n}\n";
|
|
21
|
+
const inspectorShellStyles = ":host { --panel-width: min(320px, 100vw); }\n\n.panel {\n position: fixed;\n inset: 0 0 0 auto;\n z-index: 2;\n width: var(--panel-width);\n height: 100dvh;\n overflow: auto;\n background: var(--surface-panel);\n color: var(--text-primary);\n border: 0;\n border-left: 1px solid var(--border-subtle);\n border-radius: var(--radius-0);\n font-family: var(--font-family);\n font-size: var(--font-size-base);\n line-height: 1.35;\n display: flex;\n flex-direction: column;\n pointer-events: auto;\n cursor: default;\n scrollbar-color: var(--border-strong) transparent;\n scrollbar-width: thin;\n}\n\n.panel[data-open=\"false\"] {\n display: none;\n}\n\n.panel__restore {\n position: fixed;\n top: max(12px, env(safe-area-inset-top));\n right: max(12px, env(safe-area-inset-right));\n z-index: calc(var(--z-index) + 1);\n display: flex;\n align-items: center;\n justify-content: center;\n width: calc(var(--control-height-large) + (var(--space-4) * 2));\n height: calc(var(--control-height-large) + (var(--space-4) * 2));\n padding: var(--space-4);\n border-radius: var(--radius-12);\n background: var(--surface-raised-2x);\n box-shadow: var(--shadow-popup);\n pointer-events: auto;\n animation: panel-restore-in 160ms ease-out;\n}\n\n.panel__restore-button.icon-button {\n width: 100%;\n height: 100%;\n}\n\n@keyframes panel-restore-in {\n from { opacity: 0; transform: translateX(8px); }\n to { opacity: 1; transform: translateX(0); }\n}\n\n.scope__warning {\n color: var(--warning-text);\n font-weight: 500;\n}\n\n.panel__tabs {\n display: flex;\n flex-direction: column;\n gap: var(--space-8);\n padding: var(--space-12) var(--space-24);\n border-bottom: 1px solid var(--border-subtle);\n}\n\n.panel__header-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-8);\n width: 100%;\n}\n\n.panel__header-actions,\n.panel__copy-row {\n display: flex;\n align-items: center;\n}\n\n.panel__header-actions {\n min-width: 0;\n gap: var(--space-4);\n}\n\n.panel__copy-row {\n gap: var(--space-8);\n}\n\n.panel__header-divider {\n width: 1px;\n height: var(--control-height-large);\n margin: 0 var(--space-4);\n background: var(--border-subtle);\n}\n\n.panel__copy-row {\n width: 100%;\n}\n\n.copy-prompt__stack {\n width: 100%;\n min-width: 0;\n}\n\n.copy-prompt__main.button {\n width: 100%;\n position: relative;\n}\n\n.copy-prompt__menu {\n width: max(var(--anchor-width), 280px);\n max-width: calc(100vw - 24px);\n}\n\n.copy-prompt__menu-item {\n display: flex;\n align-items: flex-start;\n gap: var(--space-8);\n padding: var(--space-8);\n border-radius: var(--radius-4);\n color: var(--text-primary);\n font-size: var(--font-size-base);\n line-height: 1.4;\n cursor: pointer;\n outline: 0;\n}\n\n.copy-prompt__menu-item[data-highlighted] {\n background: var(--surface-control);\n}\n\n.copy-prompt__menu-icon {\n flex: 0 0 auto;\n color: var(--text-secondary);\n}\n\n.copy-prompt__menu-icon--live {\n color: var(--accent);\n}\n\n.copy-prompt__menu-content {\n display: flex;\n flex: 1;\n flex-direction: column;\n gap: var(--space-4);\n min-width: 0;\n}\n\n.copy-prompt__menu-title {\n font-weight: var(--font-weight-base);\n}\n\n.copy-prompt__menu-description {\n color: var(--text-secondary);\n overflow-wrap: anywhere;\n}\n\n.copy-prompt__menu-description code {\n font-family: var(--font-mono);\n}\n\n.agent-status-button {\n position: relative;\n}\n\n.agent-status-button__avatars {\n display: inline-flex;\n align-items: center;\n}\n\n.agent-status-button__avatar {\n width: 20px;\n height: 20px;\n display: block;\n background: var(--surface-raised-2x);\n border-radius: 50%;\n box-shadow: 0 0 0 1px var(--border-subtle);\n padding: 2px;\n}\n\n.agent-status-button__avatar svg {\n width: 100%;\n height: 100%;\n display: block;\n}\n\n.agent-status-button__avatar + .agent-status-button__avatar {\n margin-left: calc(var(--space-4) * -1);\n}\n\n.agent-status-button__dot {\n position: absolute;\n top: 50%;\n right: 3px;\n width: 6px;\n height: 6px;\n transform: translateY(-50%);\n border-radius: 50%;\n background: var(--text-muted);\n}\n\n.agent-status-button[data-mcp-listening=\"true\"] .agent-status-button__dot {\n background: var(--success);\n}\n\n.copy-prompt__hint {\n margin: var(--space-8) 0 0;\n color: var(--text-secondary);\n font-size: var(--font-size-small);\n line-height: 1.4;\n}\n\n.copy-prompt__hint--centered {\n text-align: center;\n}\n\n.copy-prompt__hint--implemented {\n font-size: var(--font-size-base);\n}\n\n.copy-prompt__hint-action {\n padding: 0;\n border: 0;\n background: none;\n color: inherit;\n font: inherit;\n text-decoration: underline;\n text-underline-offset: 2px;\n cursor: pointer;\n}\n\n.copy-prompt__hint-action:hover {\n color: var(--text-primary);\n}\n\n.copy-prompt__hint-action:focus-visible {\n border-radius: var(--radius-4);\n outline: 2px solid var(--accent);\n outline-offset: 2px;\n}\n\n.copy-prompt__hint code {\n font-family: var(--font-mono);\n}\n\n.copy-prompt__agent-status {\n margin-top: var(--space-8);\n}\n\n.copy-prompt__agent-status-content {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-8);\n}\n\n.copy-prompt__agent-status-content > span {\n min-width: 0;\n}\n\n.copy-prompt__agent-status-content .button--quiet {\n flex: 0 0 auto;\n color: inherit;\n}\n\n.copy-prompt__sketch-fallback {\n display: grid;\n gap: var(--space-8);\n margin-top: var(--space-8);\n}\n\n.panel__body {\n min-height: auto;\n padding: 0 20px 28px;\n background: var(--surface-panel);\n color: var(--text-secondary);\n overflow: visible;\n flex: 0 0 auto;\n}\n\n.panel__body:has(.empty-state) {\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n min-height: 0;\n}\n\n.panel::-webkit-scrollbar {\n width: 6px;\n}\n\n.panel::-webkit-scrollbar-thumb {\n background: var(--border-strong);\n border-radius: var(--radius-pill);\n}\n\n.selection {\n display: flex;\n flex-direction: column;\n gap: var(--space-8);\n padding: 14px 0 16px;\n border-bottom: 1px solid var(--border-subtle);\n}\n\n.selection--without-scope-callout {\n border-bottom: 0;\n}\n\n.selection__summary {\n display: grid;\n gap: 2px;\n}\n\n.selection__count {\n color: var(--text-primary);\n font-weight: 600;\n}\n\n.style-state {\n grid-template-columns: var(--label-column) minmax(0, 1fr);\n column-gap: var(--space-8);\n}\n\n.scope {\n margin-top: var(--space-8);\n}\n\n.scope__action {\n margin-top: 0;\n}\n\n.scope__unlinked,\n.scope__linked {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-8);\n}\n\n.style-editors {\n margin-top: 0;\n background: var(--surface-panel);\n border-top: 0;\n padding-top: 0;\n}\n\n.component-props__source {\n color: var(--text-muted-subtle);\n font-size: 10px;\n font-weight: 650;\n letter-spacing: 0.06em;\n text-transform: uppercase;\n}\n\n.component-props .field-row__label {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.inline-text-diagnostic {\n margin-top: 12px;\n font-weight: 400;\n}\n\n.style-editors__title {\n color: var(--text-muted);\n margin-bottom: 8px;\n font-weight: 600;\n}\n\n.empty-state + .changes {\n margin-top: auto;\n}\n\n.changes__empty {\n color: var(--text-muted-subtle);\n}\n\n.editor {\n margin: 0;\n padding: var(--space-8) 0;\n background: var(--surface-panel);\n border: 0;\n border-bottom: 1px solid var(--border-subtle);\n border-radius: 0;\n display: flex;\n flex-direction: column;\n gap: var(--space-8);\n}\n\n.editor__title {\n color: var(--text-primary);\n font-size: var(--font-size-base);\n font-weight: var(--font-weight-label);\n letter-spacing: -0.02em;\n min-height: var(--control-height-large);\n display: flex;\n align-items: center;\n justify-content: space-between;\n text-transform: none;\n}\n\n.editor__title-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n}\n\n.editor__title-row .editor__title {\n margin-bottom: 0;\n}\n";
|
|
22
22
|
const inspectorOverlayStyles = ".hover-outline,\n.selected-outline {\n position: fixed;\n pointer-events: none;\n outline-offset: -2px;\n}\n\n.measurement-overlay {\n position: fixed;\n inset: 0;\n z-index: 0;\n overflow: visible;\n pointer-events: none;\n}\n\n.alignment-guide {\n stroke: rgb(59 130 246 / 46%);\n stroke-dasharray: 3 4;\n stroke-width: 1;\n vector-effect: non-scaling-stroke;\n}\n\n.measurement-ruler {\n stroke: #ef4444;\n stroke-width: 1;\n vector-effect: non-scaling-stroke;\n}\n\n.measurement-projection {\n stroke: #ef4444;\n stroke-dasharray: 4 4;\n stroke-width: 1;\n vector-effect: non-scaling-stroke;\n}\n\n.measurement-label {\n fill: #fff;\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;\n font-size: 12px;\n font-weight: 600;\n}\n\n.measurement-label-chip {\n fill: #ef4444;\n}\n\n.dom-drop-line {\n z-index: 4;\n height: 3px;\n margin-top: -1px;\n border-radius: 999px;\n background: #3b82f6;\n box-shadow: 0 0 0 1px rgb(255 255 255 / 80%);\n}\n\n.dom-drop-target {\n z-index: 3;\n box-sizing: border-box;\n border: 1px solid rgb(59 130 246 / 72%);\n border-radius: 4px;\n background: rgb(59 130 246 / 5%);\n}\n\n.hover-outline {\n outline: 2px solid var(--accent);\n}\n\n.selected-outline {\n outline: 2px solid var(--accent);\n}\n\n.hover-margin-fill {\n background: rgb(59 130 246 / 14%);\n}\n\n.hover-margin {\n border-color: rgb(59 130 246 / 52%);\n border-style: dotted;\n border-width: 0;\n opacity: 0.72;\n}\n\n.hover-margin[data-axis=\"horizontal\"] {\n border-top-width: 1px;\n}\n\n.hover-margin[data-axis=\"vertical\"] {\n border-left-width: 1px;\n}\n\n.dom-navigator,\n.dom-navigator-preview {\n position: fixed;\n pointer-events: none;\n}\n\n.dom-navigator {\n display: flex;\n align-items: center;\n min-height: var(--control-height-small);\n border-radius: var(--radius-4);\n background: var(--accent);\n color: var(--surface-raised-2x);\n z-index: 2;\n pointer-events: auto;\n font-family: var(--font-family);\n font-size: var(--font-size-base);\n}\n\n.dom-navigator__trigger,\n.dom-navigator__item {\n appearance: none;\n display: flex;\n align-items: center;\n gap: var(--space-4);\n border: 0;\n color: var(--text-primary);\n cursor: pointer;\n font: inherit;\n white-space: nowrap;\n}\n\n.dom-navigator__trigger {\n min-height: var(--control-height-small);\n justify-content: center;\n width: var(--control-height-small);\n padding: 0;\n border-radius: var(--radius-4);\n background: transparent;\n color: var(--surface-raised-2x);\n box-shadow: none;\n}\n\n.dom-navigator__label {\n padding-right: var(--space-8);\n white-space: nowrap;\n}\n\n.dom-navigator__positioner {\n z-index: 2;\n pointer-events: auto;\n}\n\n.dom-navigator__menu {\n display: grid;\n min-width: 140px;\n padding: var(--space-4);\n gap: var(--space-4);\n border: 0;\n border-radius: var(--radius-8);\n background: var(--surface-raised-2x);\n box-shadow: var(--shadow-popup);\n}\n\n.dom-navigator__item {\n width: 100%;\n min-height: var(--control-height-small);\n padding: 0 var(--space-8);\n border-color: transparent;\n border-radius: var(--radius-4);\n background: transparent;\n text-align: left;\n font-family: var(--font-family);\n font-size: var(--font-size-base);\n}\n\n.dom-navigator__trigger:hover {\n background: var(--surface-well);\n color: var(--surface-raised-2x);\n}\n\n.dom-navigator__trigger:focus-visible {\n background: var(--surface-well);\n color: var(--surface-raised-2x);\n outline: 1px solid currentColor;\n outline-offset: -3px;\n}\n\n.dom-navigator__item:hover,\n.dom-navigator__item:focus-visible {\n background: var(--surface-well);\n outline: 0;\n}\n\n.dom-navigator__item--selected {\n background: var(--accent-surface);\n}\n\n.dom-navigator-preview {\n z-index: 1;\n outline: 2px solid var(--accent);\n outline-offset: -2px;\n}\n";
|
|
23
23
|
const emptyStateStyles = ".empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: var(--space-40) var(--space-0) var(--space-24);\n min-height: 70dvh;\n text-align: center;\n color: var(--text-secondary);\n}\n\n.empty-state__icon { display: block; width: min(100%, 182px); height: auto; margin-bottom: var(--space-16); }\n.empty-state__title { margin: 0; color: var(--text-primary); font-size: var(--font-size-base); font-weight: var(--font-weight-base); }\n.empty-state--canvas {\n align-items: stretch;\n justify-content: flex-start;\n min-height: 0;\n padding-top: var(--space-24);\n text-align: left;\n}\n\n.empty-state__canvas .empty-state__title {\n margin-bottom: var(--space-24);\n font-weight: var(--font-weight-label);\n}\n\n.empty-state__canvas p {\n display: flex;\n align-items: flex-start;\n gap: var(--space-12);\n margin: 0 0 var(--space-20);\n line-height: 1.5;\n}\n\n.empty-state__canvas p:last-child { margin-bottom: 0; }\n.empty-state__canvas svg { width: 20px; height: 20px; margin-top: 2px; flex-shrink: 0; }\n.empty-state__live-badge {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: 0 0 20px;\n height: 20px;\n margin-top: 2px;\n border-radius: var(--radius-4);\n background: var(--accent-surface);\n color: var(--accent);\n}\n.empty-state__live-badge svg { width: 12px; height: 12px; margin-top: 0; }\n.empty-state__canvas strong { display: block; color: var(--text-primary); font-weight: var(--font-weight-label); }\n.empty-state__shortcuts { width: 100%; margin-top: var(--space-32); text-align: left; }\n.empty-state__shortcuts .disclosure__panel { padding-top: var(--space-16); }\n.empty-state__shortcut-list { display: grid; gap: var(--space-8); margin: var(--space-0); padding: var(--space-0); list-style: none; }\n.empty-state__shortcut { display: flex; align-items: center; justify-content: space-between; gap: var(--space-8); min-height: var(--control-height-small); color: var(--text-secondary); }\n.empty-state__shortcut-keys { display: inline-flex; align-items: center; gap: var(--space-4); color: var(--text-muted); }\n.empty-state__shortcut-keys kbd { display: inline-flex; align-items: center; justify-content: center; min-width: var(--control-height-small); height: var(--control-height-small); padding: var(--space-0) var(--space-8); border-radius: var(--radius-4); background: var(--surface-raised-2x); color: var(--text-primary); font-family: var(--font-family); font-size: var(--font-size-small); box-shadow: var(--shadow-control); }\n.empty-state__shortcut-keys > span { color: var(--text-muted-subtle); font-size: var(--font-size-small); }\n";
|
|
24
24
|
const styleEditorStyles = "/* Shared chrome for style-editor sections. */\n.layout,\n.spacing,\n.typography,\n.border,\n.property,\n.color {\n display: flex;\n flex-direction: column;\n gap: var(--space-8);\n background: var(--surface-panel);\n}\n\n.appearance {\n gap: var(--space-12);\n}\n\n.appearance__fields {\n display: grid;\n grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto;\n gap: var(--space-8);\n}\n\n.appearance__field {\n display: flex;\n min-width: 0;\n flex-direction: column;\n gap: var(--space-8);\n}\n\n.appearance__field-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-8);\n}\n\n.appearance__field-label {\n min-width: 0;\n color: var(--text-secondary);\n font-size: var(--font-size-base);\n line-height: 1.25;\n}\n\n.border-radius-editor__main {\n display: flex;\n min-width: 0;\n flex-direction: column;\n gap: var(--space-8);\n}\n\n.border-radius-editor--embedded {\n display: contents;\n}\n\n.border-radius-editor--embedded > .border-radius-editor__main {\n grid-column: 2;\n}\n\n.border-radius-editor--embedded > .border-radius-editor__toggle {\n grid-column: 3;\n align-self: end;\n}\n\n.border-radius__grouped-row {\n display: grid;\n min-width: 0;\n grid-template-columns: minmax(0, 1fr) auto;\n align-items: stretch;\n gap: var(--space-8);\n}\n\n.border-radius__grouped-row > .control-surface {\n min-width: 0;\n}\n\n.border-radius-editor__individuals {\n grid-column: 1 / span 2;\n min-width: 0;\n}\n\n.opacity-editor__effective {\n flex: 0 0 auto;\n color: var(--text-secondary);\n font-size: var(--font-size-base);\n}\n\n.box-shadow-editor__layers,\n.box-shadow-editor__layer {\n display: grid;\n gap: var(--space-8);\n}\n\n.box-shadow-editor__dimensions {\n display: grid;\n grid-template-columns: repeat(4, minmax(0, 1fr));\n gap: var(--space-4);\n}\n\n.box-shadow-editor__layer {\n grid-template-columns: minmax(0, 1fr) var(--control-height-large);\n align-items: center;\n}\n\n.box-shadow-editor__layer + .box-shadow-editor__layer {\n padding-top: var(--space-12);\n border-top: 1px solid var(--border-subtle);\n}\n\n.box-shadow-editor__remove {\n grid-column: 2;\n grid-row: 1;\n}\n\n.box-shadow-editor__color {\n grid-column: 1;\n}\n\n.box-shadow-editor__dimensions > .control-surface {\n --control-surface-padding: 2px 4px;\n}\n\n.box-shadow-editor__dimensions .token-field {\n gap: var(--space-4);\n}\n";
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type ChangeRecord } from "../changes/changesLog.js";
|
|
2
|
+
import type { StructuralChange } from "../changes/structuralTypes.js";
|
|
3
|
+
import { type HandoffSnapshot } from "../agent/verification.js";
|
|
4
|
+
import { type ElementComment } from "../comments/store.js";
|
|
5
|
+
import type { DraftTarget } from "../drafts/model.js";
|
|
6
|
+
/** Handed-off work that verification has not confirmed and the user has not changed since. */
|
|
7
|
+
export interface SentItems {
|
|
8
|
+
readonly draftId: string;
|
|
9
|
+
readonly changes: readonly ChangeRecord[];
|
|
10
|
+
readonly structuralChanges: readonly StructuralChange[];
|
|
11
|
+
readonly comments: readonly ElementComment[];
|
|
12
|
+
}
|
|
13
|
+
export declare function getSentItems(draftId: string, target: DraftTarget, agentDispatch: HandoffSnapshot | null): SentItems;
|
|
14
|
+
export declare function sentItemCount(items: SentItems): number;
|
|
15
|
+
/**
|
|
16
|
+
* Removes sent items from the active draft as one undoable edit. Returns a
|
|
17
|
+
* restore callback, or null when the draft is not active or nothing changed.
|
|
18
|
+
*/
|
|
19
|
+
export declare function clearSentItems(items: SentItems): (() => void) | null;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { changeKey } from "../changes/model.js";
|
|
2
|
+
import { commitDraftContents } from "../changes/changesLog.js";
|
|
3
|
+
import { getActiveDraftChanges, getDraftChanges } from "../changes/draftChanges.js";
|
|
4
|
+
import { unchangedHandoffRecords } from "../agent/verification.js";
|
|
5
|
+
import { getClipboardHandoffRecords } from "../prompt/clipboardHandoff.js";
|
|
6
|
+
import { getComments, getCommentsForTarget, removeComment, saveComment } from "../comments/store.js";
|
|
7
|
+
export function getSentItems(draftId, target, agentDispatch) {
|
|
8
|
+
const clipboard = getClipboardHandoffRecords(draftId);
|
|
9
|
+
const agent = agentDispatch?.owner.draftId === draftId
|
|
10
|
+
? unchangedHandoffRecords(agentDispatch)
|
|
11
|
+
: { changes: [], structuralChanges: [] };
|
|
12
|
+
const changes = new Map([...clipboard.changes, ...agent.changes].map((change) => [changeKey(change), change]));
|
|
13
|
+
const structuralChanges = new Map([...clipboard.structuralChanges, ...agent.structuralChanges].map((change) => [change.id, change]));
|
|
14
|
+
return {
|
|
15
|
+
draftId,
|
|
16
|
+
changes: [...changes.values()],
|
|
17
|
+
structuralChanges: [...structuralChanges.values()],
|
|
18
|
+
comments: getCommentsForTarget(target).filter((comment) => comment.handedOff),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export function sentItemCount(items) {
|
|
22
|
+
return items.changes.length + items.structuralChanges.length + items.comments.length;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Removes sent items from the active draft as one undoable edit. Returns a
|
|
26
|
+
* restore callback, or null when the draft is not active or nothing changed.
|
|
27
|
+
*/
|
|
28
|
+
export function clearSentItems(items) {
|
|
29
|
+
const current = getActiveDraftChanges();
|
|
30
|
+
if (current.draftId !== items.draftId || sentItemCount(items) === 0)
|
|
31
|
+
return null;
|
|
32
|
+
const keys = new Set(items.changes.map(changeKey));
|
|
33
|
+
const ids = new Set(items.structuralChanges.map((change) => change.id));
|
|
34
|
+
const draftChanged = items.changes.length + items.structuralChanges.length > 0;
|
|
35
|
+
if (draftChanged && !commitDraftContents(current.changes.filter((change) => !keys.has(changeKey(change))), current.structuralChanges.filter((change) => !ids.has(change.id))))
|
|
36
|
+
return null;
|
|
37
|
+
for (const comment of items.comments)
|
|
38
|
+
removeComment(comment.id);
|
|
39
|
+
return () => {
|
|
40
|
+
const draft = getDraftChanges(items.draftId);
|
|
41
|
+
if (draftChanged && getActiveDraftChanges().draftId === items.draftId) {
|
|
42
|
+
const present = new Set(draft.changes.map(changeKey));
|
|
43
|
+
const presentIds = new Set(draft.structuralChanges.map((change) => change.id));
|
|
44
|
+
commitDraftContents([...draft.changes, ...items.changes.filter((change) => !present.has(changeKey(change)))], [...draft.structuralChanges, ...items.structuralChanges.filter((change) => !presentIds.has(change.id))]);
|
|
45
|
+
}
|
|
46
|
+
const existing = new Set(getComments().map((comment) => comment.id));
|
|
47
|
+
for (const comment of items.comments)
|
|
48
|
+
if (!existing.has(comment.id))
|
|
49
|
+
saveComment(comment);
|
|
50
|
+
};
|
|
51
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nudge-ui",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.2.4",
|
|
4
|
+
"description": "A design panel for your codebase. Development only.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|