@agent-native/core 0.84.10 → 0.84.13
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/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +48 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/durable-background.ts +30 -0
- package/corpus/core/src/agent/production-agent.ts +34 -6
- package/corpus/core/src/agent/run-manager.ts +45 -2
- package/corpus/core/src/agent/run-store.ts +29 -6
- package/corpus/core/src/chat-threads/store.ts +2 -0
- package/corpus/core/src/cli/skills.ts +10 -6
- package/corpus/core/src/client/AssistantChat.tsx +40 -9
- package/corpus/core/src/client/agent-chat-adapter.ts +23 -2
- package/corpus/core/src/client/chat/run-recovery.tsx +52 -44
- package/corpus/core/src/client/chat/tool-call-display.tsx +7 -2
- package/corpus/core/src/client/require-session.tsx +20 -1
- package/corpus/core/src/client/sharing/ShareButton.tsx +9 -3
- package/corpus/core/src/collab/storage.ts +40 -5
- package/corpus/core/src/server/agent-chat-plugin.ts +1 -0
- package/corpus/core/src/server/auth.ts +6 -0
- package/corpus/core/src/shared/streaming-text-smoothing.ts +10 -5
- package/corpus/templates/assets/.agents/skills/logo-composite/SKILL.md +7 -6
- package/corpus/templates/assets/AGENTS.md +15 -0
- package/corpus/templates/assets/actions/_helpers.ts +3 -1
- package/corpus/templates/assets/actions/create-generation-preset.ts +12 -1
- package/corpus/templates/assets/actions/generate-asset.ts +5 -1
- package/corpus/templates/assets/actions/generate-image-batch.ts +6 -1
- package/corpus/templates/assets/actions/generate-image.ts +18 -11
- package/corpus/templates/assets/actions/open-asset-picker.ts +4 -2
- package/corpus/templates/assets/actions/update-generation-preset.ts +16 -3
- package/corpus/templates/assets/app/i18n/zh-TW.ts +3 -0
- package/corpus/templates/assets/app/i18n-data.ts +30 -0
- package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +42 -7
- package/corpus/templates/assets/app/routes/library.tsx +4 -2
- package/corpus/templates/assets/changelog/2026-07-01-generation-presets-can-now-composite-your-brand-s-canonical-.md +6 -0
- package/corpus/templates/assets/changelog/2026-07-01-tagging-a-preset-now-briefs-the-agent-on-that-preset-s-aesth.md +6 -0
- package/corpus/templates/assets/server/lib/preset-chat-context.ts +118 -0
- package/corpus/templates/assets/server/plugins/agent-chat.ts +5 -0
- package/corpus/templates/assets/shared/api.ts +1 -0
- package/corpus/templates/clips/app/components/library/recording-card.tsx +14 -4
- package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +10 -12
- package/corpus/templates/clips/app/hooks/use-library.ts +7 -4
- package/corpus/templates/clips/app/lib/recording-status.ts +32 -0
- package/corpus/templates/clips/changelog/2026-07-01-dictation-keeps-listening-through-natural-pauses-and-gives-c.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-01-redoing-a-paused-desktop-recording-no-longer-leaves-the-recording-controls-disabled.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-01-stalled-clip-uploads-now-update-in-the-library-and-surface-as-failed.md +6 -0
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +36 -18
- package/corpus/templates/clips/desktop/src/lib/voice-dictation.ts +99 -27
- package/corpus/templates/clips/desktop/src/overlays/flow-bar.tsx +4 -43
- package/corpus/templates/clips/desktop/src/overlays/toolbar.tsx +3 -0
- package/corpus/templates/clips/desktop/src/styles.css +5 -48
- package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +4 -5
- package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +15 -6
- package/corpus/templates/design/AGENTS.md +8 -4
- package/corpus/templates/design/actions/create-design.ts +1 -0
- package/corpus/templates/design/actions/duplicate-design.ts +3 -1
- package/corpus/templates/design/actions/edit-design.ts +43 -13
- package/corpus/templates/design/actions/export-html.ts +4 -2
- package/corpus/templates/design/actions/export-pdf.ts +3 -1
- package/corpus/templates/design/actions/export-svg.ts +4 -2
- package/corpus/templates/design/actions/export-zip.ts +10 -3
- package/corpus/templates/design/actions/generate-design.ts +5 -1
- package/corpus/templates/design/actions/present-design-variants.ts +17 -12
- package/corpus/templates/design/actions/update-file.ts +68 -17
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +3 -2
- package/corpus/templates/design/app/components/design/EditPanel.tsx +35 -3
- package/corpus/templates/design/app/components/design/MotionDock.tsx +46 -11
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +80 -30
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +60 -10
- package/corpus/templates/design/app/components/design/canvas-primitive-style.ts +2 -0
- package/corpus/templates/design/app/components/design/inspector/InspectorAiActions.tsx +4 -0
- package/corpus/templates/design/app/hooks/use-question-flow.ts +2 -2
- package/corpus/templates/design/app/hooks/useAgentEditRequest.ts +2 -2
- package/corpus/templates/design/app/i18n-data.ts +1 -1
- package/corpus/templates/design/app/pages/DesignEditor.tsx +493 -109
- package/corpus/templates/design/app/pages/VisualEdit.tsx +4 -16
- package/corpus/templates/design/changelog/2026-07-01-org-members-can-see-design-projects-created-in-their-workspace.md +6 -0
- package/corpus/templates/design/e2e/helpers.ts +2 -2
- package/corpus/templates/design/server/plugins/db.ts +9 -0
- package/dist/agent/durable-background.d.ts +3 -0
- package/dist/agent/durable-background.d.ts.map +1 -1
- package/dist/agent/durable-background.js +19 -0
- package/dist/agent/durable-background.js.map +1 -1
- package/dist/agent/production-agent.d.ts +1 -0
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +29 -6
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-manager.d.ts.map +1 -1
- package/dist/agent/run-manager.js +40 -2
- package/dist/agent/run-manager.js.map +1 -1
- package/dist/agent/run-store.d.ts.map +1 -1
- package/dist/agent/run-store.js +28 -6
- package/dist/agent/run-store.js.map +1 -1
- package/dist/chat-threads/store.d.ts +1 -0
- package/dist/chat-threads/store.d.ts.map +1 -1
- package/dist/chat-threads/store.js +2 -0
- package/dist/chat-threads/store.js.map +1 -1
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +10 -6
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +10 -0
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +26 -8
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +21 -2
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/chat/run-recovery.d.ts.map +1 -1
- package/dist/client/chat/run-recovery.js +15 -10
- package/dist/client/chat/run-recovery.js.map +1 -1
- package/dist/client/chat/tool-call-display.d.ts +1 -0
- package/dist/client/chat/tool-call-display.d.ts.map +1 -1
- package/dist/client/chat/tool-call-display.js +3 -2
- package/dist/client/chat/tool-call-display.js.map +1 -1
- package/dist/client/require-session.d.ts +14 -0
- package/dist/client/require-session.d.ts.map +1 -1
- package/dist/client/require-session.js +19 -1
- package/dist/client/require-session.js.map +1 -1
- package/dist/client/sharing/ShareButton.d.ts +4 -2
- package/dist/client/sharing/ShareButton.d.ts.map +1 -1
- package/dist/client/sharing/ShareButton.js +3 -1
- package/dist/client/sharing/ShareButton.js.map +1 -1
- package/dist/collab/routes.d.ts +2 -2
- package/dist/collab/storage.d.ts.map +1 -1
- package/dist/collab/storage.js +31 -5
- package/dist/collab/storage.js.map +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +2 -2
- package/dist/notifications/routes.d.ts +2 -2
- package/dist/observability/routes.d.ts +5 -5
- package/dist/progress/routes.d.ts +1 -1
- package/dist/resources/handlers.d.ts +3 -3
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +1 -1
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +7 -0
- package/dist/server/auth.js.map +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/shared/streaming-text-smoothing.d.ts.map +1 -1
- package/dist/shared/streaming-text-smoothing.js +8 -5
- package/dist/shared/streaming-text-smoothing.js.map +1 -1
- package/package.json +1 -1
|
@@ -117,6 +117,14 @@ export interface MotionDockProps {
|
|
|
117
117
|
canvasIframeRef?: React.RefObject<HTMLIFrameElement | null>;
|
|
118
118
|
/** Whether the parent autosave mutation is in flight. */
|
|
119
119
|
applying?: boolean;
|
|
120
|
+
/** Controlled auto-keyframe state. */
|
|
121
|
+
autoKeyframe?: boolean;
|
|
122
|
+
/** Called when the auto-keyframe toggle changes. */
|
|
123
|
+
onAutoKeyframeChange?: (enabled: boolean) => void;
|
|
124
|
+
/** Controlled playhead position, normalized to [0, 1]. */
|
|
125
|
+
playhead?: number;
|
|
126
|
+
/** Called whenever the playhead moves. */
|
|
127
|
+
onPlayheadChange?: (t: number) => void;
|
|
120
128
|
/**
|
|
121
129
|
* The currently-selected canvas element, if any. Required to create the FIRST
|
|
122
130
|
* track for a layer: the picker animates this node's
|
|
@@ -139,6 +147,10 @@ export function MotionDock({
|
|
|
139
147
|
onDurationChange,
|
|
140
148
|
canvasIframeRef,
|
|
141
149
|
applying = false,
|
|
150
|
+
autoKeyframe: autoKeyframeProp,
|
|
151
|
+
onAutoKeyframeChange,
|
|
152
|
+
playhead: playheadProp,
|
|
153
|
+
onPlayheadChange,
|
|
142
154
|
selectedTarget = null,
|
|
143
155
|
}: MotionDockProps) {
|
|
144
156
|
// Controlled / uncontrolled open state.
|
|
@@ -153,13 +165,36 @@ export function MotionDock({
|
|
|
153
165
|
);
|
|
154
166
|
|
|
155
167
|
// Playhead position: normalised [0, 1].
|
|
156
|
-
const [playhead, setPlayhead] = useState(0);
|
|
168
|
+
const [playhead, setPlayhead] = useState(playheadProp ?? 0);
|
|
157
169
|
const [playing, setPlaying] = useState(false);
|
|
158
170
|
const playRafRef = useRef<number | null>(null);
|
|
159
171
|
const playStartRef = useRef<{ wallMs: number; startT: number } | null>(null);
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
172
|
+
useEffect(() => {
|
|
173
|
+
if (playheadProp === undefined) return;
|
|
174
|
+
setPlayhead(Math.max(0, Math.min(1, playheadProp)));
|
|
175
|
+
}, [playheadProp]);
|
|
176
|
+
|
|
177
|
+
// Auto-keyframe mode: inspector/style edits create keyframes at the playhead.
|
|
178
|
+
const [autoKeyframeInternal, setAutoKeyframeInternal] = useState(false);
|
|
179
|
+
const autoKeyframe = autoKeyframeProp ?? autoKeyframeInternal;
|
|
180
|
+
const setAutoKeyframe = useCallback(
|
|
181
|
+
(next: boolean | ((current: boolean) => boolean)) => {
|
|
182
|
+
const resolved =
|
|
183
|
+
typeof next === "function"
|
|
184
|
+
? (next as (current: boolean) => boolean)(autoKeyframe)
|
|
185
|
+
: next;
|
|
186
|
+
setAutoKeyframeInternal(resolved);
|
|
187
|
+
onAutoKeyframeChange?.(resolved);
|
|
188
|
+
},
|
|
189
|
+
[autoKeyframe, onAutoKeyframeChange],
|
|
190
|
+
);
|
|
191
|
+
const setPlayheadValue = useCallback(
|
|
192
|
+
(next: number) => {
|
|
193
|
+
setPlayhead(next);
|
|
194
|
+
onPlayheadChange?.(next);
|
|
195
|
+
},
|
|
196
|
+
[onPlayheadChange],
|
|
197
|
+
);
|
|
163
198
|
|
|
164
199
|
// Dock height (resizable via the top drag handle).
|
|
165
200
|
const [dockHeight, setDockHeight] = useState(DEFAULT_DOCK_HEIGHT);
|
|
@@ -235,7 +270,7 @@ export function MotionDock({
|
|
|
235
270
|
if (!playStartRef.current) return;
|
|
236
271
|
const elapsed = now - playStartRef.current.wallMs;
|
|
237
272
|
const t = Math.min(1, playStartRef.current.startT + elapsed / durationMs);
|
|
238
|
-
|
|
273
|
+
setPlayheadValue(t);
|
|
239
274
|
sendPreview(t);
|
|
240
275
|
if (t < 1) {
|
|
241
276
|
playRafRef.current = requestAnimationFrame(tick);
|
|
@@ -244,7 +279,7 @@ export function MotionDock({
|
|
|
244
279
|
}
|
|
245
280
|
};
|
|
246
281
|
playRafRef.current = requestAnimationFrame(tick);
|
|
247
|
-
}, [durationMs, playhead, sendPreview, stopPlayback]);
|
|
282
|
+
}, [durationMs, playhead, sendPreview, setPlayheadValue, stopPlayback]);
|
|
248
283
|
|
|
249
284
|
useEffect(() => {
|
|
250
285
|
return () => {
|
|
@@ -263,10 +298,10 @@ export function MotionDock({
|
|
|
263
298
|
(e.target as HTMLElement).setPointerCapture(e.pointerId);
|
|
264
299
|
const rect = trackAreaRef.current.getBoundingClientRect();
|
|
265
300
|
const t = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));
|
|
266
|
-
|
|
301
|
+
setPlayheadValue(t);
|
|
267
302
|
sendPreview(t);
|
|
268
303
|
},
|
|
269
|
-
[sendPreview, stopPlayback],
|
|
304
|
+
[sendPreview, setPlayheadValue, stopPlayback],
|
|
270
305
|
);
|
|
271
306
|
|
|
272
307
|
const handleRulerPointerMove = useCallback(
|
|
@@ -274,10 +309,10 @@ export function MotionDock({
|
|
|
274
309
|
if (!isDraggingPlayhead.current || !trackAreaRef.current) return;
|
|
275
310
|
const rect = trackAreaRef.current.getBoundingClientRect();
|
|
276
311
|
const t = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));
|
|
277
|
-
|
|
312
|
+
setPlayheadValue(t);
|
|
278
313
|
sendPreview(t);
|
|
279
314
|
},
|
|
280
|
-
[sendPreview],
|
|
315
|
+
[sendPreview, setPlayheadValue],
|
|
281
316
|
);
|
|
282
317
|
|
|
283
318
|
const handleRulerPointerUp = useCallback(() => {
|
|
@@ -493,7 +528,7 @@ export function MotionDock({
|
|
|
493
528
|
className="size-6 shrink-0"
|
|
494
529
|
onClick={() => {
|
|
495
530
|
stopPlayback();
|
|
496
|
-
|
|
531
|
+
setPlayheadValue(0);
|
|
497
532
|
sendPreview(0);
|
|
498
533
|
}}
|
|
499
534
|
aria-label="Reset playhead"
|
|
@@ -186,7 +186,11 @@ interface MultiScreenCanvasProps {
|
|
|
186
186
|
screenId: string,
|
|
187
187
|
primitive: CanvasPrimitiveInsert,
|
|
188
188
|
) => boolean | string;
|
|
189
|
-
onPrimitiveCreated?: (
|
|
189
|
+
onPrimitiveCreated?: (
|
|
190
|
+
screenId: string,
|
|
191
|
+
nodeId: string,
|
|
192
|
+
options?: { nextTool?: "move" | "pen" },
|
|
193
|
+
) => void;
|
|
190
194
|
onPrimitiveReparent?: (args: {
|
|
191
195
|
sourceNodeId: string;
|
|
192
196
|
sourceScreenId: string;
|
|
@@ -1505,7 +1509,7 @@ export function MultiScreenCanvas({
|
|
|
1505
1509
|
setTransformBadge(null);
|
|
1506
1510
|
}, [clearSelectionRequest, updateSelectedDraftIds, updateSelectedIds]);
|
|
1507
1511
|
|
|
1508
|
-
// Center the lineup
|
|
1512
|
+
// Center the lineup when the screen footprint changes so new frames stay reachable.
|
|
1509
1513
|
useEffect(() => {
|
|
1510
1514
|
if (!surfaceRef.current || screens.length === 0) return;
|
|
1511
1515
|
const rect = surfaceRef.current.getBoundingClientRect();
|
|
@@ -1529,11 +1533,26 @@ export function MultiScreenCanvas({
|
|
|
1529
1533
|
);
|
|
1530
1534
|
const totalWidth = bounds?.width ?? SCREEN_WIDTH;
|
|
1531
1535
|
const totalHeight = bounds?.height ?? SCREEN_CARD_HEIGHT;
|
|
1532
|
-
|
|
1533
|
-
|
|
1536
|
+
// Leave a Figma-like board gutter beside the last frame for quick drops/draws,
|
|
1537
|
+
// and fit tall single frames so lower canvas interactions remain reachable.
|
|
1538
|
+
const widthFitScale =
|
|
1539
|
+
screens.length > 1 && totalWidth > 0
|
|
1540
|
+
? Math.max(0.1, (rect.width - 180) / totalWidth)
|
|
1541
|
+
: scale;
|
|
1542
|
+
const heightFitScale =
|
|
1543
|
+
totalHeight > 0 ? Math.max(0.1, (rect.height - 96) / totalHeight) : scale;
|
|
1544
|
+
const nextScale = Math.min(scale, widthFitScale, heightFitScale);
|
|
1545
|
+
if (nextScale < scale) {
|
|
1546
|
+
const nextZoom = nextScale * 100;
|
|
1547
|
+
zoomRef.current = nextZoom;
|
|
1548
|
+
setCanvasZoom(nextZoom);
|
|
1549
|
+
onZoomChange?.(nextZoom);
|
|
1550
|
+
}
|
|
1551
|
+
const visualLeft = Math.max(24, (rect.width - totalWidth * nextScale) / 2);
|
|
1552
|
+
const visualTop = Math.max(24, (rect.height - totalHeight * nextScale) / 2);
|
|
1534
1553
|
const nextPan = {
|
|
1535
|
-
x: visualLeft - SURFACE_PADDING *
|
|
1536
|
-
y: visualTop - SURFACE_PADDING *
|
|
1554
|
+
x: visualLeft - SURFACE_PADDING * nextScale,
|
|
1555
|
+
y: visualTop - SURFACE_PADDING * nextScale,
|
|
1537
1556
|
};
|
|
1538
1557
|
panRef.current = nextPan;
|
|
1539
1558
|
setPan(nextPan);
|
|
@@ -2517,9 +2536,11 @@ export function MultiScreenCanvas({
|
|
|
2517
2536
|
updateSelectedIds(() => state.baseSelectedIds);
|
|
2518
2537
|
updateSelectedDraftIds(() => state.baseSelectedDraftIds);
|
|
2519
2538
|
} else if (state.type === "pen-node") {
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2539
|
+
const restoredPath = state.pathBefore
|
|
2540
|
+
? clonePenPath(state.pathBefore)
|
|
2541
|
+
: null;
|
|
2542
|
+
activePenPathRef.current = restoredPath;
|
|
2543
|
+
setActivePenPath(restoredPath);
|
|
2523
2544
|
setPenGesturePreview(null);
|
|
2524
2545
|
setPenPointer(null);
|
|
2525
2546
|
setPenCloseHover(false);
|
|
@@ -2792,10 +2813,10 @@ export function MultiScreenCanvas({
|
|
|
2792
2813
|
});
|
|
2793
2814
|
const persisted = handler(boardPrimitive);
|
|
2794
2815
|
if (!persisted) return null;
|
|
2795
|
-
// Return
|
|
2796
|
-
//
|
|
2816
|
+
// Return the board file id so the caller can run the same selection
|
|
2817
|
+
// and text-edit activation path used by regular screen primitives.
|
|
2797
2818
|
return {
|
|
2798
|
-
frameId: "__board__",
|
|
2819
|
+
frameId: boardFileId ?? "__board__",
|
|
2799
2820
|
nodeId:
|
|
2800
2821
|
(typeof persisted === "string"
|
|
2801
2822
|
? persisted
|
|
@@ -2836,6 +2857,7 @@ export function MultiScreenCanvas({
|
|
|
2836
2857
|
};
|
|
2837
2858
|
},
|
|
2838
2859
|
[
|
|
2860
|
+
boardFileId,
|
|
2839
2861
|
getScreenMetadata,
|
|
2840
2862
|
getTargetFrameForDraft,
|
|
2841
2863
|
metadataById,
|
|
@@ -2845,7 +2867,11 @@ export function MultiScreenCanvas({
|
|
|
2845
2867
|
);
|
|
2846
2868
|
|
|
2847
2869
|
const commitDraftPrimitive = useCallback(
|
|
2848
|
-
(
|
|
2870
|
+
(
|
|
2871
|
+
nextDraft: DraftPrimitive,
|
|
2872
|
+
preferredFrameId?: string,
|
|
2873
|
+
options?: { nextTool?: "move" | "pen" },
|
|
2874
|
+
) => {
|
|
2849
2875
|
const persisted = persistDraftPrimitive(nextDraft, preferredFrameId);
|
|
2850
2876
|
if (persisted) {
|
|
2851
2877
|
updateDraftPrimitives((current) =>
|
|
@@ -2853,9 +2879,9 @@ export function MultiScreenCanvas({
|
|
|
2853
2879
|
);
|
|
2854
2880
|
updateSelectedDraftIds(() => []);
|
|
2855
2881
|
updateSelectedIds(() => []);
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
}
|
|
2882
|
+
onPrimitiveCreated?.(persisted.frameId, persisted.nodeId, {
|
|
2883
|
+
nextTool: options?.nextTool,
|
|
2884
|
+
});
|
|
2859
2885
|
return;
|
|
2860
2886
|
}
|
|
2861
2887
|
|
|
@@ -2937,9 +2963,10 @@ export function MultiScreenCanvas({
|
|
|
2937
2963
|
stroke: toolProps?.stroke,
|
|
2938
2964
|
strokeWidth: toolProps?.strokeWidth,
|
|
2939
2965
|
}),
|
|
2966
|
+
undefined,
|
|
2967
|
+
{ nextTool: "pen" },
|
|
2940
2968
|
);
|
|
2941
2969
|
clearActivePenPath();
|
|
2942
|
-
onActiveToolChange?.("pen");
|
|
2943
2970
|
},
|
|
2944
2971
|
[clearActivePenPath, commitDraftPrimitive, onActiveToolChange, toolProps],
|
|
2945
2972
|
);
|
|
@@ -3041,9 +3068,10 @@ export function MultiScreenCanvas({
|
|
|
3041
3068
|
pathBefore: pathSnapshot,
|
|
3042
3069
|
hasMoved: false,
|
|
3043
3070
|
};
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
);
|
|
3071
|
+
const initialPath = appendPenNode(pathSnapshot, createCornerNode(anchor));
|
|
3072
|
+
activePenPathRef.current = initialPath;
|
|
3073
|
+
setActivePenPath(initialPath);
|
|
3074
|
+
setPenGesturePreview(initialPath);
|
|
3047
3075
|
setPenPointer(null);
|
|
3048
3076
|
setPenCloseHover(false);
|
|
3049
3077
|
setIsDragging(true);
|
|
@@ -3071,7 +3099,10 @@ export function MultiScreenCanvas({
|
|
|
3071
3099
|
: handlePoint,
|
|
3072
3100
|
)
|
|
3073
3101
|
: createCornerNode(state.anchor);
|
|
3074
|
-
|
|
3102
|
+
const nextPath = appendPenNode(state.pathBefore, node);
|
|
3103
|
+
activePenPathRef.current = nextPath;
|
|
3104
|
+
setActivePenPath(nextPath);
|
|
3105
|
+
setPenGesturePreview(nextPath);
|
|
3075
3106
|
};
|
|
3076
3107
|
|
|
3077
3108
|
const handleMouseUp = (ev: MouseEvent) => {
|
|
@@ -3090,7 +3121,9 @@ export function MultiScreenCanvas({
|
|
|
3090
3121
|
: handlePoint,
|
|
3091
3122
|
)
|
|
3092
3123
|
: createCornerNode(state.anchor);
|
|
3093
|
-
|
|
3124
|
+
const nextPath = appendPenNode(state.pathBefore, node);
|
|
3125
|
+
activePenPathRef.current = nextPath;
|
|
3126
|
+
setActivePenPath(nextPath);
|
|
3094
3127
|
setPenGesturePreview(null);
|
|
3095
3128
|
setPenPointer(null);
|
|
3096
3129
|
setPenCloseHover(false);
|
|
@@ -3101,6 +3134,7 @@ export function MultiScreenCanvas({
|
|
|
3101
3134
|
const cancelPenGesture = () => {
|
|
3102
3135
|
const state = dragState.current;
|
|
3103
3136
|
if (state?.type === "pen-node") {
|
|
3137
|
+
activePenPathRef.current = state.pathBefore;
|
|
3104
3138
|
setActivePenPath(state.pathBefore);
|
|
3105
3139
|
}
|
|
3106
3140
|
setPenGesturePreview(null);
|
|
@@ -4730,6 +4764,20 @@ export function MultiScreenCanvas({
|
|
|
4730
4764
|
frameGeometry[screen.id] ?? getInitialFrameGeometry(index, metadata),
|
|
4731
4765
|
};
|
|
4732
4766
|
});
|
|
4767
|
+
const topScreenId =
|
|
4768
|
+
selectedIds.find((id) =>
|
|
4769
|
+
canvasFrames.some(({ screen }) => screen.id === id),
|
|
4770
|
+
) ??
|
|
4771
|
+
(activeId && canvasFrames.some(({ screen }) => screen.id === activeId)
|
|
4772
|
+
? activeId
|
|
4773
|
+
: canvasFrames[0]?.screen.id);
|
|
4774
|
+
const renderCanvasFrames =
|
|
4775
|
+
topScreenId && canvasFrames.some(({ screen }) => screen.id === topScreenId)
|
|
4776
|
+
? [
|
|
4777
|
+
...canvasFrames.filter(({ screen }) => screen.id !== topScreenId),
|
|
4778
|
+
...canvasFrames.filter(({ screen }) => screen.id === topScreenId),
|
|
4779
|
+
]
|
|
4780
|
+
: canvasFrames;
|
|
4733
4781
|
const screenContentById = useMemo(() => {
|
|
4734
4782
|
if (!renderScreenContent) return new Map<string, ReactNode>();
|
|
4735
4783
|
return new Map(
|
|
@@ -4910,7 +4958,7 @@ export function MultiScreenCanvas({
|
|
|
4910
4958
|
);
|
|
4911
4959
|
})()}
|
|
4912
4960
|
|
|
4913
|
-
{
|
|
4961
|
+
{renderCanvasFrames.map(({ screen, metadata, geometry }) => {
|
|
4914
4962
|
return (
|
|
4915
4963
|
<Screen
|
|
4916
4964
|
key={screen.id}
|
|
@@ -7031,13 +7079,6 @@ function draftPrimitiveToInsert(
|
|
|
7031
7079
|
x: Math.round((point.x - frameGeometry.x) * scaleX),
|
|
7032
7080
|
y: Math.round((point.y - frameGeometry.y) * scaleY),
|
|
7033
7081
|
});
|
|
7034
|
-
const localGeometry = {
|
|
7035
|
-
...draft.geometry,
|
|
7036
|
-
x: Math.round((draft.geometry.x - frameGeometry.x) * scaleX),
|
|
7037
|
-
y: Math.round((draft.geometry.y - frameGeometry.y) * scaleY),
|
|
7038
|
-
width: Math.max(1, Math.round(draft.geometry.width * scaleX)),
|
|
7039
|
-
height: Math.max(1, Math.round(draft.geometry.height * scaleY)),
|
|
7040
|
-
};
|
|
7041
7082
|
const scaledPenPath = draft.penPath
|
|
7042
7083
|
? scalePenPathToGeometry(draft.penPath, frameGeometry, {
|
|
7043
7084
|
x: 0,
|
|
@@ -7046,6 +7087,15 @@ function draftPrimitiveToInsert(
|
|
|
7046
7087
|
height: metadata?.height ?? frameGeometry.height,
|
|
7047
7088
|
})
|
|
7048
7089
|
: undefined;
|
|
7090
|
+
const localGeometry = scaledPenPath
|
|
7091
|
+
? getPenPathGeometry(scaledPenPath)
|
|
7092
|
+
: {
|
|
7093
|
+
...draft.geometry,
|
|
7094
|
+
x: Math.round((draft.geometry.x - frameGeometry.x) * scaleX),
|
|
7095
|
+
y: Math.round((draft.geometry.y - frameGeometry.y) * scaleY),
|
|
7096
|
+
width: Math.max(1, Math.round(draft.geometry.width * scaleX)),
|
|
7097
|
+
height: Math.max(1, Math.round(draft.geometry.height * scaleY)),
|
|
7098
|
+
};
|
|
7049
7099
|
return {
|
|
7050
7100
|
kind: draft.kind,
|
|
7051
7101
|
nodeId: draft.id,
|
|
@@ -58,6 +58,8 @@ declare var __DESIGN_CANVAS_BOARD_SURFACE__: boolean;
|
|
|
58
58
|
);
|
|
59
59
|
chromeTransitionStyle.textContent =
|
|
60
60
|
'[data-agent-native-edit-overlay="selection"]{transition:border-width 150ms ease-out}' +
|
|
61
|
+
'[data-agent-native-empty-text-editing="true"] [data-agent-native-edit-overlay="selection"]{display:none!important}' +
|
|
62
|
+
"[data-agent-native-text-editing]{outline:none!important;outline-offset:0!important}" +
|
|
61
63
|
"[data-agent-native-edge-handle],[data-agent-native-edit-handle],[data-agent-native-rotate-handle]{transition:width 150ms ease-out,height 150ms ease-out,border-width 150ms ease-out,top 150ms ease-out,bottom 150ms ease-out,left 150ms ease-out,right 150ms ease-out}" +
|
|
62
64
|
"[data-agent-native-spacing-line]{position:absolute;display:none;pointer-events:none;border-radius:999px}" +
|
|
63
65
|
"[data-agent-native-spacing-region]{position:absolute;display:none;box-sizing:border-box;pointer-events:auto;background-size:6px 6px}" +
|
|
@@ -2402,12 +2404,24 @@ declare var __DESIGN_CANVAS_BOARD_SURFACE__: boolean;
|
|
|
2402
2404
|
}
|
|
2403
2405
|
|
|
2404
2406
|
function refreshOverlays(): void {
|
|
2407
|
+
var textEditingEl =
|
|
2408
|
+
activeTextEditEl ||
|
|
2409
|
+
(document.querySelector(
|
|
2410
|
+
"[data-agent-native-text-editing]",
|
|
2411
|
+
) as HTMLElement | null);
|
|
2405
2412
|
if (hoveredEl && hoveredEl !== selectedEl) {
|
|
2406
2413
|
positionOverlay(highlightOverlay, hoveredEl);
|
|
2407
2414
|
} else {
|
|
2408
2415
|
highlightOverlay.style.display = "none";
|
|
2409
2416
|
}
|
|
2410
|
-
if (
|
|
2417
|
+
if (textEditingEl) {
|
|
2418
|
+
if (activeTextEditEl === textEditingEl) {
|
|
2419
|
+
updateTextEditingChrome(textEditingEl, "", "");
|
|
2420
|
+
}
|
|
2421
|
+
if (!hasTextCharacters(textEditingEl)) {
|
|
2422
|
+
hideSelectionOverlay();
|
|
2423
|
+
}
|
|
2424
|
+
} else if (selectedEl) {
|
|
2411
2425
|
positionOverlay(selectionOverlay, selectedEl);
|
|
2412
2426
|
} else {
|
|
2413
2427
|
hideParentAutoLayoutOverlay();
|
|
@@ -2819,9 +2833,15 @@ declare var __DESIGN_CANVAS_BOARD_SURFACE__: boolean;
|
|
|
2819
2833
|
originalMinWidth: string,
|
|
2820
2834
|
originalMinHeight: string,
|
|
2821
2835
|
): void {
|
|
2822
|
-
target.style.outline = "";
|
|
2823
|
-
target.style.
|
|
2836
|
+
target.style.outline = "none";
|
|
2837
|
+
target.style.outlineStyle = "none";
|
|
2838
|
+
target.style.outlineWidth = "0px";
|
|
2839
|
+
target.style.outlineColor = "transparent";
|
|
2840
|
+
target.style.outlineOffset = "0px";
|
|
2824
2841
|
if (hasTextCharacters(target)) {
|
|
2842
|
+
document.documentElement.removeAttribute(
|
|
2843
|
+
"data-agent-native-empty-text-editing",
|
|
2844
|
+
);
|
|
2825
2845
|
target.style.minWidth = originalMinWidth;
|
|
2826
2846
|
target.style.minHeight = originalMinHeight;
|
|
2827
2847
|
positionOverlay(selectionOverlay, target);
|
|
@@ -2830,6 +2850,10 @@ declare var __DESIGN_CANVAS_BOARD_SURFACE__: boolean;
|
|
|
2830
2850
|
}
|
|
2831
2851
|
target.style.minWidth = originalMinWidth || "1px";
|
|
2832
2852
|
target.style.minHeight = originalMinHeight || "1em";
|
|
2853
|
+
document.documentElement.setAttribute(
|
|
2854
|
+
"data-agent-native-empty-text-editing",
|
|
2855
|
+
"true",
|
|
2856
|
+
);
|
|
2833
2857
|
hideSelectionOverlay();
|
|
2834
2858
|
setSelectionOverlayResizeChromeVisible(false);
|
|
2835
2859
|
}
|
|
@@ -5021,24 +5045,37 @@ declare var __DESIGN_CANVAS_BOARD_SURFACE__: boolean;
|
|
|
5021
5045
|
// code-layer node rather than a runtime-only descendant (which would emit a
|
|
5022
5046
|
// brittle body > div:nth-of-type(...) selector that never resolves).
|
|
5023
5047
|
selectedEl = selectionTargetForHit(target) || target;
|
|
5048
|
+
var programmaticTextEdit =
|
|
5049
|
+
!!e &&
|
|
5050
|
+
(e as unknown as { agentNativeProgrammaticTextEdit?: boolean })
|
|
5051
|
+
.agentNativeProgrammaticTextEdit === true;
|
|
5024
5052
|
var originalText = target.textContent || "";
|
|
5025
5053
|
var originalHtml = target.innerHTML || "";
|
|
5026
5054
|
var originalMinWidth = target.style.minWidth;
|
|
5027
5055
|
var originalMinHeight = target.style.minHeight;
|
|
5028
5056
|
var originalBorderColor = target.style.borderColor;
|
|
5057
|
+
var originalOutline = target.style.outline;
|
|
5058
|
+
var originalOutlineOffset = target.style.outlineOffset;
|
|
5029
5059
|
var committed = false;
|
|
5030
5060
|
activeTextEditEl = target;
|
|
5031
5061
|
target.setAttribute("contenteditable", "true");
|
|
5032
5062
|
target.setAttribute("data-agent-native-text-editing", "true");
|
|
5033
5063
|
target.style.cursor = "text";
|
|
5034
5064
|
target.style.borderColor = "transparent";
|
|
5065
|
+
target.style.outline = "none";
|
|
5066
|
+
target.style.outlineStyle = "none";
|
|
5067
|
+
target.style.outlineWidth = "0px";
|
|
5068
|
+
target.style.outlineColor = "transparent";
|
|
5069
|
+
target.style.outlineOffset = "0px";
|
|
5035
5070
|
setTextEditingPointerPassthrough(true);
|
|
5036
5071
|
updateTextEditingChrome(target, originalMinWidth, originalMinHeight);
|
|
5037
|
-
|
|
5038
|
-
|
|
5039
|
-
|
|
5040
|
-
|
|
5041
|
-
|
|
5072
|
+
if (!programmaticTextEdit) {
|
|
5073
|
+
postElementSelect(target, e);
|
|
5074
|
+
(window.parent as Window).postMessage(
|
|
5075
|
+
{ type: "element-dblclick-text", payload: getElementInfo(target) },
|
|
5076
|
+
"*",
|
|
5077
|
+
);
|
|
5078
|
+
}
|
|
5042
5079
|
postTextEditingState(target, true);
|
|
5043
5080
|
|
|
5044
5081
|
function finish(commit) {
|
|
@@ -5053,9 +5090,12 @@ declare var __DESIGN_CANVAS_BOARD_SURFACE__: boolean;
|
|
|
5053
5090
|
document.removeEventListener("selectionchange", onSelectionChange);
|
|
5054
5091
|
target.removeAttribute("contenteditable");
|
|
5055
5092
|
target.removeAttribute("data-agent-native-text-editing");
|
|
5093
|
+
document.documentElement.removeAttribute(
|
|
5094
|
+
"data-agent-native-empty-text-editing",
|
|
5095
|
+
);
|
|
5056
5096
|
target.style.cursor = "";
|
|
5057
|
-
target.style.outline =
|
|
5058
|
-
target.style.outlineOffset =
|
|
5097
|
+
target.style.outline = originalOutline;
|
|
5098
|
+
target.style.outlineOffset = originalOutlineOffset;
|
|
5059
5099
|
target.style.minWidth = originalMinWidth;
|
|
5060
5100
|
target.style.minHeight = originalMinHeight;
|
|
5061
5101
|
target.style.borderColor = originalBorderColor;
|
|
@@ -5077,6 +5117,15 @@ declare var __DESIGN_CANVAS_BOARD_SURFACE__: boolean;
|
|
|
5077
5117
|
}
|
|
5078
5118
|
|
|
5079
5119
|
function onBlur() {
|
|
5120
|
+
if (programmaticTextEdit && !(target.textContent || "").trim()) {
|
|
5121
|
+
window.setTimeout(function () {
|
|
5122
|
+
if (committed || (target.textContent || "").trim()) return;
|
|
5123
|
+
target.focus();
|
|
5124
|
+
updateTextEditingChrome(target, originalMinWidth, originalMinHeight);
|
|
5125
|
+
postTextEditingState(target, true);
|
|
5126
|
+
}, 0);
|
|
5127
|
+
return;
|
|
5128
|
+
}
|
|
5080
5129
|
finish(true);
|
|
5081
5130
|
}
|
|
5082
5131
|
|
|
@@ -5302,6 +5351,7 @@ declare var __DESIGN_CANVAS_BOARD_SURFACE__: boolean;
|
|
|
5302
5351
|
clientX: bteCenterX,
|
|
5303
5352
|
clientY: bteCenterY,
|
|
5304
5353
|
target: textTarget,
|
|
5354
|
+
agentNativeProgrammaticTextEdit: true,
|
|
5305
5355
|
preventDefault: function () {},
|
|
5306
5356
|
stopPropagation: function () {},
|
|
5307
5357
|
stopImmediatePropagation: function () {},
|
|
@@ -248,6 +248,8 @@ export function canvasPrimitiveReactStyle(
|
|
|
248
248
|
// For text kind, clear fill-as-background since text uses `color`
|
|
249
249
|
if (kind === "text") {
|
|
250
250
|
style.background = "transparent";
|
|
251
|
+
style.outline = "none";
|
|
252
|
+
style.outlineOffset = 0;
|
|
251
253
|
}
|
|
252
254
|
|
|
253
255
|
return style;
|
|
@@ -25,6 +25,8 @@ export interface InspectorAiActionsProps {
|
|
|
25
25
|
fileId?: string;
|
|
26
26
|
/** Active file name (e.g. "index.html"). */
|
|
27
27
|
filename?: string;
|
|
28
|
+
/** Localhost-backed source file, when the selected screen comes from a local app. */
|
|
29
|
+
routeSourceFile?: string;
|
|
28
30
|
/** The design id. */
|
|
29
31
|
designId?: string;
|
|
30
32
|
/** When false, the controls are disabled. */
|
|
@@ -43,6 +45,7 @@ export function InspectorAiActions({
|
|
|
43
45
|
sourceId,
|
|
44
46
|
fileId,
|
|
45
47
|
filename,
|
|
48
|
+
routeSourceFile,
|
|
46
49
|
designId,
|
|
47
50
|
canEdit,
|
|
48
51
|
}: InspectorAiActionsProps) {
|
|
@@ -57,6 +60,7 @@ export function InspectorAiActions({
|
|
|
57
60
|
sourceId,
|
|
58
61
|
fileId,
|
|
59
62
|
filename,
|
|
63
|
+
routeSourceFile,
|
|
60
64
|
designId,
|
|
61
65
|
};
|
|
62
66
|
const disabled = !canEdit || !request.trim();
|
|
@@ -41,7 +41,7 @@ export function useQuestionFlow(
|
|
|
41
41
|
formattedAnswers,
|
|
42
42
|
"",
|
|
43
43
|
designId
|
|
44
|
-
?
|
|
44
|
+
? 'Now continue the design. Honor any answer about variations: if the user asked to explore options, call present-design-variants with 2-5 concise directions using label, description, accentColor, and feature bullets; omit large content HTML when needed because the action can render compact representative screens - wait for their chat pick, delete the unchosen variant screens, call get-design-snapshot with fileId for the kept screen, then call edit-design on that same fileId in a bounded pass. Use mode "replace-file" when expanding the representative placeholder into the full chosen direction. Do not call generate-design after a variant pick. Stop after the first successful edit-design save. Otherwise call generate-design with one complete, renderable index.html first. Do not ask another question unless a required decision is still genuinely missing.'
|
|
45
45
|
: "Now continue the design. Honor any answer about variations: use variants only if requested; otherwise generate one polished direction.",
|
|
46
46
|
]
|
|
47
47
|
.filter(Boolean)
|
|
@@ -79,7 +79,7 @@ export function useQuestionFlow(
|
|
|
79
79
|
formattedAnswers,
|
|
80
80
|
"",
|
|
81
81
|
designId
|
|
82
|
-
?
|
|
82
|
+
? 'Now continue the design. Honor any answer about variations: if the user asked to explore options, call present-design-variants with 2-5 concise directions using label, description, accentColor, and feature bullets; omit large content HTML when needed because the action can render compact representative screens - wait for their chat pick, delete the unchosen variant screens, call get-design-snapshot with fileId for the kept screen, then call edit-design on that same fileId in a bounded pass. Use mode "replace-file" when expanding the representative placeholder into the full chosen direction. Do not call generate-design after a variant pick. Stop after the first successful edit-design save. Otherwise call generate-design with one complete, renderable index.html first. Do not ask another question unless a required decision is still genuinely missing.'
|
|
83
83
|
: "Now continue the design. Honor any answer about variations: use variants only if requested; otherwise generate one polished direction.",
|
|
84
84
|
]
|
|
85
85
|
.filter(Boolean)
|
|
@@ -26,7 +26,7 @@ export interface AgentEditRequestArgs {
|
|
|
26
26
|
* same pattern used by the tweaks panel (DesignEditor.tsx ~5293) and the
|
|
27
27
|
* extensions panel context builder (DesignExtensionsPanel.tsx ~120-131).
|
|
28
28
|
*/
|
|
29
|
-
function buildEditContext(args: AgentEditRequestArgs): string {
|
|
29
|
+
export function buildEditContext(args: AgentEditRequestArgs): string {
|
|
30
30
|
const lines: string[] = [];
|
|
31
31
|
|
|
32
32
|
if (args.designId) {
|
|
@@ -77,7 +77,7 @@ function buildEditContext(args: AgentEditRequestArgs): string {
|
|
|
77
77
|
* Builds the full pasteable prompt string (visible message + context block)
|
|
78
78
|
* for use in the "Copy prompt" flow.
|
|
79
79
|
*/
|
|
80
|
-
function buildFullPrompt(args: AgentEditRequestArgs): string {
|
|
80
|
+
export function buildFullPrompt(args: AgentEditRequestArgs): string {
|
|
81
81
|
const context = buildEditContext(args);
|
|
82
82
|
return `${args.message}\n\n---\n${context}`;
|
|
83
83
|
}
|
|
@@ -291,7 +291,7 @@ const enUS = {
|
|
|
291
291
|
clickToRename: "Click to rename",
|
|
292
292
|
collaborators: "Collaborators",
|
|
293
293
|
share: "Share",
|
|
294
|
-
signUpToSave: "Sign up to save",
|
|
294
|
+
signUpToSave: "Sign up free to save",
|
|
295
295
|
signUpToSaveDescription:
|
|
296
296
|
"Sign up for a free account to save designs, screen layouts, and generate new ones.",
|
|
297
297
|
signUpToShare: "Sign up to share",
|