@agent-native/core 0.84.38 → 0.84.40
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 +2 -2
- package/corpus/core/CHANGELOG.md +12 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/action-continuation-guidance.ts +38 -0
- package/corpus/core/src/agent/production-agent.ts +209 -4
- package/corpus/core/src/agent/run-loop-with-resume.ts +128 -16
- package/corpus/core/src/agent/types.ts +8 -0
- package/corpus/core/src/client/agent-chat-adapter.ts +2 -40
- package/corpus/templates/design/app/components/design/CodeWorkbenchHost.tsx +486 -341
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +13 -0
- package/corpus/templates/design/app/components/design/DesignImportPanel.tsx +76 -58
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +6 -0
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +80 -8
- package/corpus/templates/design/app/i18n/zh-TW.ts +2 -2
- package/corpus/templates/design/app/i18n-data.ts +22 -30
- package/corpus/templates/design/app/lib/design-import.ts +42 -0
- package/corpus/templates/design/app/pages/DesignEditor.tsx +180 -109
- package/corpus/templates/design/changelog/2026-07-01-code-workspace-now-opens-a-vs-code-like-editor-with-real-cod.md +6 -0
- package/corpus/templates/design/changelog/2026-07-01-import-is-more-compact-local-app-setup-is-clearer-and-figma.md +6 -0
- package/corpus/templates/design/package.json +1 -0
- package/dist/agent/action-continuation-guidance.d.ts +3 -0
- package/dist/agent/action-continuation-guidance.d.ts.map +1 -0
- package/dist/agent/action-continuation-guidance.js +38 -0
- package/dist/agent/action-continuation-guidance.js.map +1 -0
- package/dist/agent/production-agent.d.ts +6 -2
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +160 -4
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-loop-with-resume.d.ts.map +1 -1
- package/dist/agent/run-loop-with-resume.js +69 -18
- package/dist/agent/run-loop-with-resume.js.map +1 -1
- package/dist/agent/types.d.ts +2 -0
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +2 -39
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +2 -2
- package/dist/observability/routes.d.ts +5 -5
- package/package.json +1 -1
|
@@ -373,6 +373,7 @@ interface DesignCanvasProps {
|
|
|
373
373
|
}) => void;
|
|
374
374
|
onElementDblClickText?: (info: ElementInfo) => void;
|
|
375
375
|
onIframeHotkey?: (event: IframeHotkeyPayload) => void;
|
|
376
|
+
onFigmaClipboardPaste?: (event: IframeFigmaClipboardPastePayload) => void;
|
|
376
377
|
onIframeContextMenu?: (event: IframeContextMenuPayload) => void;
|
|
377
378
|
onEditorDragStateChange?: (active: boolean) => void;
|
|
378
379
|
onVisualStructureChange?: (
|
|
@@ -612,6 +613,10 @@ export interface IframeHotkeyPayload {
|
|
|
612
613
|
repeat: boolean;
|
|
613
614
|
}
|
|
614
615
|
|
|
616
|
+
export interface IframeFigmaClipboardPastePayload {
|
|
617
|
+
content: string;
|
|
618
|
+
}
|
|
619
|
+
|
|
615
620
|
export interface IframeContextMenuPayload {
|
|
616
621
|
clientX: number;
|
|
617
622
|
clientY: number;
|
|
@@ -653,6 +658,7 @@ export function DesignCanvas({
|
|
|
653
658
|
onTextEditingStateChange,
|
|
654
659
|
onElementDblClickText,
|
|
655
660
|
onIframeHotkey,
|
|
661
|
+
onFigmaClipboardPaste,
|
|
656
662
|
onIframeContextMenu,
|
|
657
663
|
onEditorDragStateChange,
|
|
658
664
|
onVisualStructureChange,
|
|
@@ -1168,6 +1174,12 @@ export function DesignCanvas({
|
|
|
1168
1174
|
});
|
|
1169
1175
|
return;
|
|
1170
1176
|
}
|
|
1177
|
+
if (e.data.type === "figma-clipboard-paste") {
|
|
1178
|
+
const content =
|
|
1179
|
+
typeof e.data.content === "string" ? e.data.content : "";
|
|
1180
|
+
if (content) onFigmaClipboardPaste?.({ content });
|
|
1181
|
+
return;
|
|
1182
|
+
}
|
|
1171
1183
|
if (e.data.type === "element-contextmenu") {
|
|
1172
1184
|
const clientX = Number(e.data.clientX);
|
|
1173
1185
|
const clientY = Number(e.data.clientY);
|
|
@@ -1291,6 +1303,7 @@ export function DesignCanvas({
|
|
|
1291
1303
|
onTextEditingStateChange,
|
|
1292
1304
|
onElementDblClickText,
|
|
1293
1305
|
onIframeHotkey,
|
|
1306
|
+
onFigmaClipboardPaste,
|
|
1294
1307
|
onIframeContextMenu,
|
|
1295
1308
|
onEditorDragStateChange,
|
|
1296
1309
|
onVisualStructureChange,
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
IconChevronRight,
|
|
6
6
|
IconCircleCheck,
|
|
7
7
|
IconCode,
|
|
8
|
+
IconCopy,
|
|
8
9
|
IconHtml,
|
|
9
10
|
IconUpload,
|
|
10
11
|
} from "@tabler/icons-react";
|
|
@@ -23,6 +24,13 @@ import { Badge } from "@/components/ui/badge";
|
|
|
23
24
|
import { Button } from "@/components/ui/button";
|
|
24
25
|
import { Textarea } from "@/components/ui/textarea";
|
|
25
26
|
import { sendToDesignAgentChat } from "@/lib/agent-chat";
|
|
27
|
+
import {
|
|
28
|
+
getFigmaClipboardContent,
|
|
29
|
+
importResultSummary,
|
|
30
|
+
looksLikeStandaloneHtml,
|
|
31
|
+
VISUAL_EDIT_CONNECT_COMMAND,
|
|
32
|
+
type ImportResult,
|
|
33
|
+
} from "@/lib/design-import";
|
|
26
34
|
import { cn } from "@/lib/utils";
|
|
27
35
|
|
|
28
36
|
import type { DesignExtensionSlotContext } from "./DesignExtensionsPanel";
|
|
@@ -31,31 +39,7 @@ interface DesignImportPanelProps {
|
|
|
31
39
|
context: Pick<DesignExtensionSlotContext, "designId" | "viewMode">;
|
|
32
40
|
}
|
|
33
41
|
|
|
34
|
-
|
|
35
|
-
designId?: string;
|
|
36
|
-
files?: Array<{ id: string; filename: string }>;
|
|
37
|
-
warnings?: string[];
|
|
38
|
-
error?: string;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
type ImportMode = "figma-paste" | "fig-file" | "html";
|
|
42
|
-
|
|
43
|
-
function hasFigmaPayload(html: string): boolean {
|
|
44
|
-
return /\(figmeta\)|\(figma\)|data-metadata=|data-buffer=/i.test(html);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function looksLikeHtml(value: string): boolean {
|
|
48
|
-
return /<(html|body|main|section|div|article|header|footer|button|img)\b/i.test(
|
|
49
|
-
value,
|
|
50
|
-
);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function resultSummary(result: ImportResult | undefined, fallback: string) {
|
|
54
|
-
const count = result?.files?.length ?? 0;
|
|
55
|
-
if (count === 0) return fallback;
|
|
56
|
-
if (count === 1) return `Imported ${result!.files![0]!.filename}.`;
|
|
57
|
-
return `Imported ${count} screens.`;
|
|
58
|
-
}
|
|
42
|
+
type ImportMode = "figma-paste" | "fig-file" | "html" | "local-app";
|
|
59
43
|
|
|
60
44
|
export function DesignImportPanel({ context }: DesignImportPanelProps) {
|
|
61
45
|
const t = useT();
|
|
@@ -78,7 +62,7 @@ export function DesignImportPanel({ context }: DesignImportPanelProps) {
|
|
|
78
62
|
queryClient.invalidateQueries({ queryKey: ["action", "get-design"] }),
|
|
79
63
|
queryClient.invalidateQueries({ queryKey: ["action"] }),
|
|
80
64
|
]);
|
|
81
|
-
toast.success(
|
|
65
|
+
toast.success(importResultSummary(result, fallback));
|
|
82
66
|
if (result?.warnings?.length) {
|
|
83
67
|
toast.warning(t("designEditor.import.warningsToast"), {
|
|
84
68
|
description: result.warnings[0],
|
|
@@ -91,7 +75,7 @@ export function DesignImportPanel({ context }: DesignImportPanelProps) {
|
|
|
91
75
|
|
|
92
76
|
const importHtmlString = useCallback(
|
|
93
77
|
(content: string, originalName?: string) => {
|
|
94
|
-
if (!
|
|
78
|
+
if (!looksLikeStandaloneHtml(content)) {
|
|
95
79
|
toast.error(t("designEditor.import.errors.notHtml"));
|
|
96
80
|
return;
|
|
97
81
|
}
|
|
@@ -129,13 +113,14 @@ export function DesignImportPanel({ context }: DesignImportPanelProps) {
|
|
|
129
113
|
const text = event.clipboardData.getData("text/plain");
|
|
130
114
|
const content = html || text;
|
|
131
115
|
if (!content) return;
|
|
132
|
-
|
|
116
|
+
const figmaContent = getFigmaClipboardContent(event.clipboardData);
|
|
117
|
+
if (figmaContent) {
|
|
133
118
|
event.preventDefault();
|
|
134
119
|
importSource.mutate(
|
|
135
120
|
{
|
|
136
121
|
designId: context.designId,
|
|
137
122
|
sourceType: "figma-paste-html",
|
|
138
|
-
content,
|
|
123
|
+
content: figmaContent,
|
|
139
124
|
originalName: "figma-paste.html",
|
|
140
125
|
},
|
|
141
126
|
{
|
|
@@ -157,7 +142,7 @@ export function DesignImportPanel({ context }: DesignImportPanelProps) {
|
|
|
157
142
|
);
|
|
158
143
|
return;
|
|
159
144
|
}
|
|
160
|
-
if (
|
|
145
|
+
if (looksLikeStandaloneHtml(content)) {
|
|
161
146
|
event.preventDefault();
|
|
162
147
|
importHtmlString(content, "pasted-html.html");
|
|
163
148
|
}
|
|
@@ -233,23 +218,32 @@ export function DesignImportPanel({ context }: DesignImportPanelProps) {
|
|
|
233
218
|
toast.success(t("designEditor.import.visualEditSent"));
|
|
234
219
|
}, [t]);
|
|
235
220
|
|
|
221
|
+
const copyVisualEditCommand = useCallback(async () => {
|
|
222
|
+
try {
|
|
223
|
+
await navigator.clipboard.writeText(VISUAL_EDIT_CONNECT_COMMAND);
|
|
224
|
+
toast.success(t("designEditor.copied"));
|
|
225
|
+
} catch {
|
|
226
|
+
toast.error(t("designEditor.toasts.clipboardBlocked"));
|
|
227
|
+
}
|
|
228
|
+
}, [t]);
|
|
229
|
+
|
|
236
230
|
const busy = importSource.isPending || uploading;
|
|
237
231
|
|
|
238
232
|
return (
|
|
239
233
|
<div className="flex min-h-0 flex-1 flex-col bg-background">
|
|
240
|
-
<div className="flex h-
|
|
234
|
+
<div className="flex h-14 shrink-0 items-center border-b border-border/60 px-3.5">
|
|
241
235
|
<div className="min-w-0">
|
|
242
|
-
<h3 className="truncate text-
|
|
236
|
+
<h3 className="truncate text-base font-semibold tracking-tight text-foreground">
|
|
243
237
|
{t("designEditor.import.title")}
|
|
244
238
|
</h3>
|
|
245
|
-
<p className="mt-0.5 truncate text-
|
|
239
|
+
<p className="mt-0.5 truncate text-[11px] text-muted-foreground">
|
|
246
240
|
{"Bring source screens into this design" /* i18n-ignore */}
|
|
247
241
|
</p>
|
|
248
242
|
</div>
|
|
249
243
|
</div>
|
|
250
244
|
|
|
251
|
-
<div className="design-inspector-scroll min-h-0 flex-1 overflow-y-auto overscroll-contain px-
|
|
252
|
-
<div className="space-y-
|
|
245
|
+
<div className="design-inspector-scroll min-h-0 flex-1 overflow-y-auto overscroll-contain px-3.5 pb-4 pt-3">
|
|
246
|
+
<div className="space-y-0.5">
|
|
253
247
|
<ImportSourceRow
|
|
254
248
|
id="figma-paste-import"
|
|
255
249
|
icon={<IconBrandFigma className="size-3.5" />}
|
|
@@ -264,10 +258,11 @@ export function DesignImportPanel({ context }: DesignImportPanelProps) {
|
|
|
264
258
|
)
|
|
265
259
|
}
|
|
266
260
|
>
|
|
267
|
-
<div className="p-2
|
|
261
|
+
<div className="p-2">
|
|
268
262
|
<div
|
|
269
263
|
role="textbox"
|
|
270
264
|
tabIndex={0}
|
|
265
|
+
data-hotkeys-scope="text"
|
|
271
266
|
aria-label={t("designEditor.import.figmaPasteTarget")}
|
|
272
267
|
onPaste={handlePaste}
|
|
273
268
|
className={cn(
|
|
@@ -290,7 +285,7 @@ export function DesignImportPanel({ context }: DesignImportPanelProps) {
|
|
|
290
285
|
setActiveMode((mode) => (mode === "fig-file" ? null : "fig-file"))
|
|
291
286
|
}
|
|
292
287
|
>
|
|
293
|
-
<div className="space-y-2 p-2
|
|
288
|
+
<div className="space-y-2 p-2">
|
|
294
289
|
<input
|
|
295
290
|
ref={fileInputRef}
|
|
296
291
|
type="file"
|
|
@@ -330,7 +325,7 @@ export function DesignImportPanel({ context }: DesignImportPanelProps) {
|
|
|
330
325
|
setActiveMode((mode) => (mode === "html" ? null : "html"))
|
|
331
326
|
}
|
|
332
327
|
>
|
|
333
|
-
<div className="space-y-2 p-2
|
|
328
|
+
<div className="space-y-2 p-2">
|
|
334
329
|
<Textarea
|
|
335
330
|
value={htmlText}
|
|
336
331
|
onChange={(event) => setHtmlText(event.target.value)}
|
|
@@ -369,11 +364,11 @@ export function DesignImportPanel({ context }: DesignImportPanelProps) {
|
|
|
369
364
|
</ImportSourceRow>
|
|
370
365
|
</div>
|
|
371
366
|
|
|
372
|
-
<div className="mt-
|
|
373
|
-
<p className="mb-
|
|
367
|
+
<div className="mt-4 border-t border-border/60 pt-3">
|
|
368
|
+
<p className="mb-1.5 text-[11px] font-medium text-muted-foreground">
|
|
374
369
|
{"More sources" /* i18n-ignore */}
|
|
375
370
|
</p>
|
|
376
|
-
<div className="space-y-
|
|
371
|
+
<div className="space-y-0.5">
|
|
377
372
|
<CompactSourceRow
|
|
378
373
|
icon={<IconBrandGithub className="size-3.5" />}
|
|
379
374
|
title={t("designEditor.import.githubTitle")}
|
|
@@ -382,24 +377,47 @@ export function DesignImportPanel({ context }: DesignImportPanelProps) {
|
|
|
382
377
|
}
|
|
383
378
|
badge={t("designEditor.import.comingSoon")}
|
|
384
379
|
/>
|
|
385
|
-
<
|
|
380
|
+
<ImportSourceRow
|
|
381
|
+
id="local-app-import"
|
|
386
382
|
icon={<IconCode className="size-3.5" />}
|
|
387
383
|
title={t("designEditor.import.localTitle")}
|
|
388
|
-
description={
|
|
389
|
-
|
|
384
|
+
description={t("designEditor.import.localDescription")}
|
|
385
|
+
isOpen={activeMode === "local-app"}
|
|
386
|
+
onToggle={() =>
|
|
387
|
+
setActiveMode((mode) =>
|
|
388
|
+
mode === "local-app" ? null : "local-app",
|
|
389
|
+
)
|
|
390
390
|
}
|
|
391
|
-
|
|
392
|
-
|
|
391
|
+
>
|
|
392
|
+
<div className="space-y-2 p-2">
|
|
393
|
+
<p className="text-[11px] leading-snug text-muted-foreground">
|
|
394
|
+
{t("designEditor.import.visualEditGuidance")}
|
|
395
|
+
</p>
|
|
396
|
+
<div className="flex items-center gap-1.5 rounded-md border border-border/70 bg-muted/40 p-1.5">
|
|
397
|
+
<code className="min-w-0 flex-1 truncate font-mono text-[10px] leading-5 text-foreground/80">
|
|
398
|
+
{VISUAL_EDIT_CONNECT_COMMAND}
|
|
399
|
+
</code>
|
|
400
|
+
<Button
|
|
401
|
+
type="button"
|
|
402
|
+
size="sm"
|
|
403
|
+
variant="ghost"
|
|
404
|
+
className="h-6 shrink-0 px-1.5 text-[10px]"
|
|
405
|
+
onClick={copyVisualEditCommand}
|
|
406
|
+
>
|
|
407
|
+
<IconCopy className="size-3" />
|
|
408
|
+
{"Copy" /* i18n-ignore */}
|
|
409
|
+
</Button>
|
|
410
|
+
</div>
|
|
393
411
|
<Button
|
|
394
412
|
size="sm"
|
|
395
|
-
variant="
|
|
396
|
-
className="h-7
|
|
413
|
+
variant="outline"
|
|
414
|
+
className="h-7 w-full justify-center text-[11px]"
|
|
397
415
|
onClick={askVisualEdit}
|
|
398
416
|
>
|
|
399
417
|
{t("designEditor.import.useVisualEditNow")}
|
|
400
418
|
</Button>
|
|
401
|
-
|
|
402
|
-
|
|
419
|
+
</div>
|
|
420
|
+
</ImportSourceRow>
|
|
403
421
|
</div>
|
|
404
422
|
</div>
|
|
405
423
|
|
|
@@ -448,24 +466,24 @@ function ImportSourceRow({
|
|
|
448
466
|
aria-controls={id}
|
|
449
467
|
onClick={onToggle}
|
|
450
468
|
className={cn(
|
|
451
|
-
"group flex w-full cursor-pointer items-center gap-
|
|
469
|
+
"group flex w-full cursor-pointer items-center gap-2.5 rounded-md px-2 py-1.5 text-left transition-colors hover:bg-accent/60 active:bg-accent",
|
|
452
470
|
isOpen && "bg-accent/45",
|
|
453
471
|
)}
|
|
454
472
|
>
|
|
455
|
-
<span className="flex size-
|
|
473
|
+
<span className="flex size-8 shrink-0 items-center justify-center rounded-md border border-border/70 bg-muted/70 text-muted-foreground transition-colors group-hover:border-border group-hover:bg-muted">
|
|
456
474
|
{icon}
|
|
457
475
|
</span>
|
|
458
476
|
<span className="min-w-0 flex-1">
|
|
459
|
-
<span className="block truncate text-
|
|
477
|
+
<span className="block truncate text-[13px] font-medium leading-tight text-foreground">
|
|
460
478
|
{title}
|
|
461
479
|
</span>
|
|
462
|
-
<span className="mt-0.5 line-clamp-1 text-
|
|
480
|
+
<span className="mt-0.5 line-clamp-1 text-[11px] leading-snug text-muted-foreground">
|
|
463
481
|
{description}
|
|
464
482
|
</span>
|
|
465
483
|
</span>
|
|
466
484
|
<IconChevronRight
|
|
467
485
|
className={cn(
|
|
468
|
-
"size-
|
|
486
|
+
"size-3.5 shrink-0 text-muted-foreground transition-transform",
|
|
469
487
|
isOpen && "rotate-90",
|
|
470
488
|
)}
|
|
471
489
|
/>
|
|
@@ -473,7 +491,7 @@ function ImportSourceRow({
|
|
|
473
491
|
{isOpen ? (
|
|
474
492
|
<div
|
|
475
493
|
id={id}
|
|
476
|
-
className="mb-
|
|
494
|
+
className="mb-1.5 mt-1 overflow-hidden rounded-md border border-border/70 bg-background/70"
|
|
477
495
|
>
|
|
478
496
|
{children}
|
|
479
497
|
</div>
|
|
@@ -496,13 +514,13 @@ function CompactSourceRow({
|
|
|
496
514
|
action?: ReactNode;
|
|
497
515
|
}) {
|
|
498
516
|
return (
|
|
499
|
-
<div className="flex items-center gap-2 rounded-md px-2 py-
|
|
517
|
+
<div className="flex items-center gap-2 rounded-md px-2 py-1.5 text-left opacity-85">
|
|
500
518
|
<span className="flex size-8 shrink-0 items-center justify-center rounded-md border border-border/60 bg-muted/50 text-muted-foreground">
|
|
501
519
|
{icon}
|
|
502
520
|
</span>
|
|
503
521
|
<span className="min-w-0 flex-1">
|
|
504
522
|
<span className="flex items-center gap-1.5">
|
|
505
|
-
<span className="truncate text-
|
|
523
|
+
<span className="truncate text-[13px] font-medium text-foreground">
|
|
506
524
|
{title}
|
|
507
525
|
</span>
|
|
508
526
|
<Badge variant="secondary" className="h-4 px-1 text-[9px]">
|
|
@@ -53,6 +53,7 @@ import {
|
|
|
53
53
|
LIGHTWEIGHT_HIT_TEST_BRIDGE_SCRIPT,
|
|
54
54
|
appendHitTestResponder,
|
|
55
55
|
type IframeContextMenuPayload,
|
|
56
|
+
type IframeFigmaClipboardPastePayload,
|
|
56
57
|
type IframeHotkeyPayload,
|
|
57
58
|
} from "./DesignCanvas";
|
|
58
59
|
import {
|
|
@@ -323,6 +324,9 @@ interface MultiScreenCanvasProps {
|
|
|
323
324
|
onBoardElementClear?: () => void;
|
|
324
325
|
onBoardElementDblClickText?: (info: ElementInfo) => void;
|
|
325
326
|
onBoardIframeHotkey?: (event: IframeHotkeyPayload) => void;
|
|
327
|
+
onBoardFigmaClipboardPaste?: (
|
|
328
|
+
event: IframeFigmaClipboardPastePayload,
|
|
329
|
+
) => void;
|
|
326
330
|
onBoardIframeContextMenu?: (event: IframeContextMenuPayload) => void;
|
|
327
331
|
onBoardTextEditingStateChange?: (state: {
|
|
328
332
|
active: boolean;
|
|
@@ -1142,6 +1146,7 @@ export function MultiScreenCanvas({
|
|
|
1142
1146
|
onBoardElementClear,
|
|
1143
1147
|
onBoardElementDblClickText,
|
|
1144
1148
|
onBoardIframeHotkey,
|
|
1149
|
+
onBoardFigmaClipboardPaste,
|
|
1145
1150
|
onBoardIframeContextMenu,
|
|
1146
1151
|
onBoardTextEditingStateChange,
|
|
1147
1152
|
boardClearSelectionRequest,
|
|
@@ -4949,6 +4954,7 @@ export function MultiScreenCanvas({
|
|
|
4949
4954
|
onElementHover={onBoardElementHover ?? (() => {})}
|
|
4950
4955
|
onClearSelection={onBoardElementClear}
|
|
4951
4956
|
onIframeHotkey={onBoardIframeHotkey}
|
|
4957
|
+
onFigmaClipboardPaste={onBoardFigmaClipboardPaste}
|
|
4952
4958
|
onIframeContextMenu={onBoardIframeContextMenu}
|
|
4953
4959
|
onVisualStructureChange={onBoardVisualStructureChange}
|
|
4954
4960
|
onVisualStyleChange={onBoardVisualStyleChange}
|
|
@@ -4965,26 +4965,98 @@ declare var __DESIGN_CANVAS_BOARD_SURFACE__: boolean;
|
|
|
4965
4965
|
true,
|
|
4966
4966
|
);
|
|
4967
4967
|
|
|
4968
|
+
var pendingPlainPasteHotkeyTimer: number | null = null;
|
|
4969
|
+
|
|
4970
|
+
function clearPendingPlainPasteHotkey() {
|
|
4971
|
+
if (pendingPlainPasteHotkeyTimer === null) return;
|
|
4972
|
+
window.clearTimeout(pendingPlainPasteHotkeyTimer);
|
|
4973
|
+
pendingPlainPasteHotkeyTimer = null;
|
|
4974
|
+
}
|
|
4975
|
+
|
|
4976
|
+
function postDesignHotkey(payload) {
|
|
4977
|
+
(window.parent as Window).postMessage(
|
|
4978
|
+
{
|
|
4979
|
+
type: "design-hotkey",
|
|
4980
|
+
key: payload.key,
|
|
4981
|
+
code: payload.code,
|
|
4982
|
+
metaKey: !!payload.metaKey,
|
|
4983
|
+
ctrlKey: !!payload.ctrlKey,
|
|
4984
|
+
shiftKey: !!payload.shiftKey,
|
|
4985
|
+
altKey: !!payload.altKey,
|
|
4986
|
+
repeat: !!payload.repeat,
|
|
4987
|
+
},
|
|
4988
|
+
"*",
|
|
4989
|
+
);
|
|
4990
|
+
}
|
|
4991
|
+
|
|
4968
4992
|
document.addEventListener(
|
|
4969
4993
|
"keydown",
|
|
4970
4994
|
function (e) {
|
|
4971
4995
|
if (!shouldForwardDesignHotkey(e)) return;
|
|
4996
|
+
var key = e.key;
|
|
4997
|
+
var normalized = key && key.length === 1 ? key.toLowerCase() : key;
|
|
4998
|
+
var primary = e.metaKey || e.ctrlKey;
|
|
4999
|
+
var plainPasteHotkey =
|
|
5000
|
+
primary && normalized === "v" && !e.altKey && !e.shiftKey;
|
|
4972
5001
|
if (e.key === "Escape" && cancelActiveBridgeDrag()) {
|
|
4973
5002
|
stopNativeInteraction(e);
|
|
4974
5003
|
return;
|
|
4975
5004
|
}
|
|
5005
|
+
var payload = {
|
|
5006
|
+
key: e.key,
|
|
5007
|
+
code: e.code,
|
|
5008
|
+
metaKey: !!e.metaKey,
|
|
5009
|
+
ctrlKey: !!e.ctrlKey,
|
|
5010
|
+
shiftKey: !!e.shiftKey,
|
|
5011
|
+
altKey: !!e.altKey,
|
|
5012
|
+
repeat: !!e.repeat,
|
|
5013
|
+
};
|
|
5014
|
+
if (plainPasteHotkey) {
|
|
5015
|
+
clearPendingPlainPasteHotkey();
|
|
5016
|
+
pendingPlainPasteHotkeyTimer = window.setTimeout(function () {
|
|
5017
|
+
pendingPlainPasteHotkeyTimer = null;
|
|
5018
|
+
postDesignHotkey(payload);
|
|
5019
|
+
}, 0);
|
|
5020
|
+
return;
|
|
5021
|
+
}
|
|
4976
5022
|
stopNativeInteraction(e);
|
|
4977
5023
|
if (e.key === "Escape") clearRuntimeSelection();
|
|
5024
|
+
postDesignHotkey(payload);
|
|
5025
|
+
},
|
|
5026
|
+
true,
|
|
5027
|
+
);
|
|
5028
|
+
|
|
5029
|
+
function hasFigmaClipboardPayload(value) {
|
|
5030
|
+
return /<[^>]+\sdata-(metadata|buffer)=["'][^"']*\((figmeta|figma)\)[^"']*["']/i.test(
|
|
5031
|
+
String(value || ""),
|
|
5032
|
+
);
|
|
5033
|
+
}
|
|
5034
|
+
|
|
5035
|
+
function getFigmaClipboardContent(data) {
|
|
5036
|
+
if (!data || !data.getData) return "";
|
|
5037
|
+
var html = data.getData("text/html") || "";
|
|
5038
|
+
if (hasFigmaClipboardPayload(html)) return html;
|
|
5039
|
+
var text = data.getData("text/plain") || "";
|
|
5040
|
+
return hasFigmaClipboardPayload(text) ? text : "";
|
|
5041
|
+
}
|
|
5042
|
+
|
|
5043
|
+
document.addEventListener(
|
|
5044
|
+
"paste",
|
|
5045
|
+
function (e) {
|
|
5046
|
+
if (
|
|
5047
|
+
(activeTextEditEl && e.target && activeTextEditEl.contains(e.target)) ||
|
|
5048
|
+
isEditorTypingTarget(e.target)
|
|
5049
|
+
) {
|
|
5050
|
+
return;
|
|
5051
|
+
}
|
|
5052
|
+
var content = getFigmaClipboardContent(e.clipboardData);
|
|
5053
|
+
clearPendingPlainPasteHotkey();
|
|
5054
|
+
if (!content) return;
|
|
5055
|
+
stopNativeInteraction(e);
|
|
4978
5056
|
(window.parent as Window).postMessage(
|
|
4979
5057
|
{
|
|
4980
|
-
type: "
|
|
4981
|
-
|
|
4982
|
-
code: e.code,
|
|
4983
|
-
metaKey: !!e.metaKey,
|
|
4984
|
-
ctrlKey: !!e.ctrlKey,
|
|
4985
|
-
shiftKey: !!e.shiftKey,
|
|
4986
|
-
altKey: !!e.altKey,
|
|
4987
|
-
repeat: !!e.repeat,
|
|
5058
|
+
type: "figma-clipboard-paste",
|
|
5059
|
+
content: content,
|
|
4988
5060
|
},
|
|
4989
5061
|
"*",
|
|
4990
5062
|
);
|
|
@@ -294,9 +294,9 @@ const messages = {
|
|
|
294
294
|
githubTitle: "GitHub",
|
|
295
295
|
githubDescription: "即將推出:直接從儲存庫匯入螢幕和元件。",
|
|
296
296
|
localTitle: "本機 app / VS Code",
|
|
297
|
-
localDescription: "
|
|
297
|
+
localDescription: "使用 visual-edit 連接執行中的本機 app。",
|
|
298
298
|
visualEditGuidance:
|
|
299
|
-
"
|
|
299
|
+
"啟動 app,在 app repo 中執行下方命令,然後請代理使用 visual-edit skill 新增 URL 螢幕。",
|
|
300
300
|
useVisualEditNow: "立即使用 visual-edit",
|
|
301
301
|
comingSoon: "即將推出",
|
|
302
302
|
warningsToast: "匯入完成但有警告",
|
|
@@ -301,10 +301,9 @@ const enUS = {
|
|
|
301
301
|
githubDescription:
|
|
302
302
|
"Coming soon: import screens and components directly from a repository.",
|
|
303
303
|
localTitle: "Local app / VS Code",
|
|
304
|
-
localDescription:
|
|
305
|
-
"Coming soon: connect a running local app and import URL-backed screens.",
|
|
304
|
+
localDescription: "Connect a running local app with visual-edit.",
|
|
306
305
|
visualEditGuidance:
|
|
307
|
-
"
|
|
306
|
+
"Start your app, run the command below from the app repo, then ask the agent to use the visual-edit skill to add URL-backed screens.",
|
|
308
307
|
useVisualEditNow: "Use visual-edit now",
|
|
309
308
|
comingSoon: "Coming soon",
|
|
310
309
|
warningsToast: "Import completed with warnings",
|
|
@@ -10116,9 +10115,9 @@ const designImportOverrides = {
|
|
|
10116
10115
|
githubTitle: "GitHub",
|
|
10117
10116
|
githubDescription: "即將推出:直接從儲存庫匯入螢幕和元件。",
|
|
10118
10117
|
localTitle: "本機 app / VS Code",
|
|
10119
|
-
localDescription: "
|
|
10118
|
+
localDescription: "使用 visual-edit 連接執行中的本機 app。",
|
|
10120
10119
|
visualEditGuidance:
|
|
10121
|
-
"
|
|
10120
|
+
"啟動 app,在 app repo 中執行下方命令,然後請代理使用 visual-edit skill 新增 URL 螢幕。",
|
|
10122
10121
|
useVisualEditNow: "立即使用 visual-edit",
|
|
10123
10122
|
comingSoon: "即將推出",
|
|
10124
10123
|
warningsToast: "匯入完成但有警告",
|
|
@@ -10158,9 +10157,9 @@ const designImportOverrides = {
|
|
|
10158
10157
|
githubTitle: "GitHub",
|
|
10159
10158
|
githubDescription: "即将推出:直接从仓库导入屏幕和组件。",
|
|
10160
10159
|
localTitle: "本地 app / VS Code",
|
|
10161
|
-
localDescription: "
|
|
10160
|
+
localDescription: "使用 visual-edit 连接正在运行的本地 app。",
|
|
10162
10161
|
visualEditGuidance:
|
|
10163
|
-
"
|
|
10162
|
+
"启动 app,在 app repo 中运行下方命令,然后让代理使用 visual-edit skill 添加 URL 屏幕。",
|
|
10164
10163
|
useVisualEditNow: "立即使用 visual-edit",
|
|
10165
10164
|
comingSoon: "即将推出",
|
|
10166
10165
|
warningsToast: "导入完成但有警告",
|
|
@@ -10202,10 +10201,9 @@ const designImportOverrides = {
|
|
|
10202
10201
|
githubDescription:
|
|
10203
10202
|
"Próximamente: importar pantallas y componentes directamente desde un repositorio.",
|
|
10204
10203
|
localTitle: "App local / VS Code",
|
|
10205
|
-
localDescription:
|
|
10206
|
-
"Próximamente: conectar una app local en ejecución e importar pantallas con URL.",
|
|
10204
|
+
localDescription: "Conecta una app local en ejecución con visual-edit.",
|
|
10207
10205
|
visualEditGuidance:
|
|
10208
|
-
"
|
|
10206
|
+
"Inicia tu app, ejecuta el comando siguiente desde el repo de la app y luego pide al agente que use la skill visual-edit para añadir pantallas con URL.",
|
|
10209
10207
|
useVisualEditNow: "Usar visual-edit ahora",
|
|
10210
10208
|
comingSoon: "Próximamente",
|
|
10211
10209
|
warningsToast: "La importación terminó con advertencias",
|
|
@@ -10248,9 +10246,9 @@ const designImportOverrides = {
|
|
|
10248
10246
|
"Bientôt : importer des écrans et composants directement depuis un dépôt.",
|
|
10249
10247
|
localTitle: "App locale / VS Code",
|
|
10250
10248
|
localDescription:
|
|
10251
|
-
"
|
|
10249
|
+
"Connectez une app locale en cours d’exécution avec visual-edit.",
|
|
10252
10250
|
visualEditGuidance:
|
|
10253
|
-
"
|
|
10251
|
+
"Lancez votre app, exécutez la commande ci-dessous depuis le dépôt de l’app, puis demandez à l’agent d’utiliser la skill visual-edit pour ajouter des écrans par URL.",
|
|
10254
10252
|
useVisualEditNow: "Utiliser visual-edit maintenant",
|
|
10255
10253
|
comingSoon: "Bientôt",
|
|
10256
10254
|
warningsToast: "Import terminé avec avertissements",
|
|
@@ -10292,10 +10290,9 @@ const designImportOverrides = {
|
|
|
10292
10290
|
githubDescription:
|
|
10293
10291
|
"Demnächst: Bildschirme und Komponenten direkt aus einem Repository importieren.",
|
|
10294
10292
|
localTitle: "Lokale App / VS Code",
|
|
10295
|
-
localDescription:
|
|
10296
|
-
"Demnächst: eine laufende lokale App verbinden und URL-basierte Bildschirme importieren.",
|
|
10293
|
+
localDescription: "Verbinde eine laufende lokale App mit visual-edit.",
|
|
10297
10294
|
visualEditGuidance:
|
|
10298
|
-
"
|
|
10295
|
+
"Starte deine App, führe den folgenden Befehl im App-Repo aus und bitte den Agenten dann, die visual-edit-Skill zu verwenden, um URL-basierte Bildschirme hinzuzufügen.",
|
|
10299
10296
|
useVisualEditNow: "visual-edit jetzt verwenden",
|
|
10300
10297
|
comingSoon: "Demnächst",
|
|
10301
10298
|
warningsToast: "Import mit Warnungen abgeschlossen",
|
|
@@ -10337,10 +10334,9 @@ const designImportOverrides = {
|
|
|
10337
10334
|
githubDescription:
|
|
10338
10335
|
"近日対応: リポジトリから画面とコンポーネントを直接インポートします。",
|
|
10339
10336
|
localTitle: "ローカル app / VS Code",
|
|
10340
|
-
localDescription:
|
|
10341
|
-
"近日対応: 実行中のローカル app に接続し、URL ベースの画面をインポートします。",
|
|
10337
|
+
localDescription: "visual-edit で実行中のローカル app に接続します。",
|
|
10342
10338
|
visualEditGuidance:
|
|
10343
|
-
"
|
|
10339
|
+
"app を起動し、app repo で下のコマンドを実行してから、エージェントに visual-edit skill で URL ベースの画面を追加するよう依頼してください。",
|
|
10344
10340
|
useVisualEditNow: "visual-edit を今すぐ使う",
|
|
10345
10341
|
comingSoon: "近日対応",
|
|
10346
10342
|
warningsToast: "警告付きでインポートが完了しました",
|
|
@@ -10382,10 +10378,9 @@ const designImportOverrides = {
|
|
|
10382
10378
|
githubDescription:
|
|
10383
10379
|
"곧 제공: 저장소에서 화면과 컴포넌트를 직접 가져옵니다.",
|
|
10384
10380
|
localTitle: "로컬 app / VS Code",
|
|
10385
|
-
localDescription:
|
|
10386
|
-
"곧 제공: 실행 중인 로컬 app을 연결하고 URL 기반 화면을 가져옵니다.",
|
|
10381
|
+
localDescription: "visual-edit로 실행 중인 로컬 app을 연결합니다.",
|
|
10387
10382
|
visualEditGuidance:
|
|
10388
|
-
"
|
|
10383
|
+
"app을 시작하고 app repo에서 아래 명령을 실행한 다음, 에이전트에게 visual-edit skill로 URL 기반 화면을 추가해 달라고 요청하세요.",
|
|
10389
10384
|
useVisualEditNow: "지금 visual-edit 사용",
|
|
10390
10385
|
comingSoon: "곧 제공",
|
|
10391
10386
|
warningsToast: "경고와 함께 가져오기가 완료되었습니다",
|
|
@@ -10427,10 +10422,9 @@ const designImportOverrides = {
|
|
|
10427
10422
|
githubDescription:
|
|
10428
10423
|
"Em breve: importe telas e componentes diretamente de um repositório.",
|
|
10429
10424
|
localTitle: "App local / VS Code",
|
|
10430
|
-
localDescription:
|
|
10431
|
-
"Em breve: conecte um app local em execução e importe telas por URL.",
|
|
10425
|
+
localDescription: "Conecte um app local em execução com visual-edit.",
|
|
10432
10426
|
visualEditGuidance:
|
|
10433
|
-
"
|
|
10427
|
+
"Inicie seu app, execute o comando abaixo no repo do app e depois peça ao agente para usar a skill visual-edit para adicionar telas por URL.",
|
|
10434
10428
|
useVisualEditNow: "Usar visual-edit agora",
|
|
10435
10429
|
comingSoon: "Em breve",
|
|
10436
10430
|
warningsToast: "Importação concluída com avisos",
|
|
@@ -10472,10 +10466,9 @@ const designImportOverrides = {
|
|
|
10472
10466
|
githubDescription:
|
|
10473
10467
|
"जल्द आ रहा है: repository से screens और components सीधे import करें।",
|
|
10474
10468
|
localTitle: "स्थानीय app / VS Code",
|
|
10475
|
-
localDescription:
|
|
10476
|
-
"जल्द आ रहा है: चल रहे local app को connect करके URL-backed screens import करें।",
|
|
10469
|
+
localDescription: "चल रहे local app को visual-edit से connect करें।",
|
|
10477
10470
|
visualEditGuidance:
|
|
10478
|
-
"
|
|
10471
|
+
"अपना app शुरू करें, app repo से नीचे वाला command चलाएँ, फिर agent से visual-edit skill इस्तेमाल करके URL-backed screens जोड़ने को कहें।",
|
|
10479
10472
|
useVisualEditNow: "अभी visual-edit इस्तेमाल करें",
|
|
10480
10473
|
comingSoon: "जल्द आ रहा है",
|
|
10481
10474
|
warningsToast: "Import warnings के साथ पूरा हुआ",
|
|
@@ -10516,10 +10509,9 @@ const designImportOverrides = {
|
|
|
10516
10509
|
githubTitle: "GitHub",
|
|
10517
10510
|
githubDescription: "قريبا: استيراد الشاشات والمكونات مباشرة من مستودع.",
|
|
10518
10511
|
localTitle: "تطبيق محلي / VS Code",
|
|
10519
|
-
localDescription:
|
|
10520
|
-
"قريبا: توصيل تطبيق محلي قيد التشغيل واستيراد شاشات مدعومة بروابط URL.",
|
|
10512
|
+
localDescription: "وصّل تطبيقا محليا قيد التشغيل باستخدام visual-edit.",
|
|
10521
10513
|
visualEditGuidance:
|
|
10522
|
-
"
|
|
10514
|
+
"شغّل التطبيق، ثم نفّذ الأمر أدناه من مستودع التطبيق، وبعدها اطلب من الوكيل استخدام مهارة visual-edit لإضافة شاشات مدعومة بروابط URL.",
|
|
10523
10515
|
useVisualEditNow: "استخدم visual-edit الآن",
|
|
10524
10516
|
comingSoon: "قريبا",
|
|
10525
10517
|
warningsToast: "اكتمل الاستيراد مع تحذيرات",
|