@agent-native/core 0.84.56 → 0.84.58
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 +14 -0
- package/corpus/core/docs/content/locales/ar-SA/template-analytics.mdx +2 -0
- package/corpus/core/docs/content/locales/ar-SA/template-clips.mdx +2 -0
- package/corpus/core/docs/content/locales/de-DE/template-analytics.mdx +2 -0
- package/corpus/core/docs/content/locales/de-DE/template-clips.mdx +2 -0
- package/corpus/core/docs/content/locales/es-ES/template-analytics.mdx +2 -0
- package/corpus/core/docs/content/locales/es-ES/template-clips.mdx +2 -0
- package/corpus/core/docs/content/locales/fr-FR/template-analytics.mdx +2 -0
- package/corpus/core/docs/content/locales/fr-FR/template-clips.mdx +2 -0
- package/corpus/core/docs/content/locales/hi-IN/template-analytics.mdx +2 -0
- package/corpus/core/docs/content/locales/hi-IN/template-clips.mdx +2 -0
- package/corpus/core/docs/content/locales/ja-JP/template-analytics.mdx +2 -0
- package/corpus/core/docs/content/locales/ja-JP/template-clips.mdx +2 -0
- package/corpus/core/docs/content/locales/ko-KR/template-analytics.mdx +2 -0
- package/corpus/core/docs/content/locales/ko-KR/template-clips.mdx +2 -0
- package/corpus/core/docs/content/locales/pt-BR/template-analytics.mdx +2 -0
- package/corpus/core/docs/content/locales/pt-BR/template-clips.mdx +2 -0
- package/corpus/core/docs/content/locales/zh-CN/template-analytics.mdx +2 -0
- package/corpus/core/docs/content/locales/zh-CN/template-clips.mdx +2 -0
- package/corpus/core/docs/content/locales/zh-TW/template-analytics.mdx +2 -0
- package/corpus/core/docs/content/locales/zh-TW/template-clips.mdx +2 -0
- package/corpus/core/docs/content/template-analytics.mdx +2 -0
- package/corpus/core/docs/content/template-clips.mdx +22 -10
- package/corpus/core/docs/content/tracking.mdx +2 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/action.ts +11 -0
- package/corpus/core/src/agent/production-agent.ts +24 -46
- package/corpus/core/src/client/AssistantChat.tsx +69 -12
- package/corpus/core/src/client/MultiTabAssistantChat.tsx +1 -1
- package/corpus/core/src/client/conversation/use-near-bottom-autoscroll.ts +45 -2
- package/corpus/core/src/coding-tools/run-code.ts +1 -0
- package/corpus/core/src/integrations/webhook-handler.ts +10 -9
- package/corpus/core/src/server/action-discovery.ts +3 -0
- package/corpus/core/src/server/credential-provider.ts +11 -6
- package/corpus/templates/analytics/.agents/skills/session-replay/SKILL.md +8 -0
- package/corpus/templates/analytics/AGENTS.md +5 -0
- package/corpus/templates/analytics/actions/create-session-replay-agent-link.ts +31 -0
- package/corpus/templates/analytics/app/i18n/zh-TW.ts +2 -0
- package/corpus/templates/analytics/app/i18n-data.ts +20 -0
- package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +65 -3
- package/corpus/templates/analytics/changelog/2026-07-02-session-replays-can-be-copied-as-temporary-private-links-for-agents.md +6 -0
- package/corpus/templates/analytics/server/handlers/session-replay.ts +78 -0
- package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +29 -0
- package/corpus/templates/analytics/server/lib/session-replay-agent-context.ts +313 -0
- package/corpus/templates/analytics/server/lib/session-replay.ts +198 -3
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +9 -1
- package/corpus/templates/analytics/server/routes/[...page].get.ts +104 -1
- package/corpus/templates/analytics/server/routes/api/session-replay/agent-context.json.get.ts +48 -0
- package/corpus/templates/analytics/server/routes/api/session-replay/agent-events.json.get.ts +63 -0
- package/corpus/templates/analytics/shared/session-replay-agent-access.ts +10 -0
- package/corpus/templates/clips/.agents/skills/video-sharing/SKILL.md +14 -8
- package/corpus/templates/clips/AGENTS.md +3 -2
- package/corpus/templates/clips/actions/create-recording-agent-link.ts +90 -0
- package/corpus/templates/clips/app/components/player/share-dialog.tsx +43 -46
- package/corpus/templates/clips/app/components/sharing/share-ui.tsx +5 -3
- package/corpus/templates/clips/app/i18n/ar-SA.ts +1 -1
- package/corpus/templates/clips/app/i18n/de-DE.ts +1 -1
- package/corpus/templates/clips/app/i18n/en-US.ts +1 -1
- package/corpus/templates/clips/app/i18n/es-ES.ts +1 -1
- package/corpus/templates/clips/app/i18n/fr-FR.ts +1 -1
- package/corpus/templates/clips/app/i18n/hi-IN.ts +1 -1
- package/corpus/templates/clips/app/i18n/ja-JP.ts +1 -1
- package/corpus/templates/clips/app/i18n/ko-KR.ts +1 -1
- package/corpus/templates/clips/app/i18n/pt-BR.ts +1 -1
- package/corpus/templates/clips/app/i18n/zh-CN.ts +1 -1
- package/corpus/templates/clips/app/i18n/zh-TW.ts +1 -1
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +100 -46
- package/corpus/templates/clips/changelog/2026-07-02-private-recordings-can-be-shared-with-agents-through-temporary-links-without-making-them-public.md +6 -0
- package/corpus/templates/clips/server/lib/public-agent-context.ts +26 -13
- package/corpus/templates/clips/server/routes/api/agent-context.json.get.ts +2 -1
- package/corpus/templates/clips/server/routes/api/agent-frame.jpg.get.ts +2 -1
- package/corpus/templates/clips/server/routes/api/agent-transcript.json.get.ts +2 -1
- package/corpus/templates/clips/server/routes/api/public-recording.get.ts +7 -2
- package/corpus/templates/clips/shared/agent-context.ts +5 -0
- package/corpus/templates/design/actions/list-design-extensions.ts +2 -2
- package/corpus/templates/design/app/components/design/CodeWorkbenchHost.tsx +11 -89
- package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +314 -181
- package/corpus/templates/design/app/components/design/DesignImportPanel.tsx +92 -134
- package/corpus/templates/design/app/components/design/EditPanel.tsx +93 -19
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +18 -26
- package/corpus/templates/design/app/components/design/TokensPanel.tsx +220 -192
- package/corpus/templates/design/app/components/design/code-workbench-theme.ts +150 -0
- package/corpus/templates/design/app/i18n/zh-TW.ts +5 -7
- package/corpus/templates/design/app/i18n-data.ts +61 -77
- package/corpus/templates/design/app/lib/design-import.ts +4 -1
- package/corpus/templates/design/app/pages/DesignEditor.tsx +97 -48
- package/corpus/templates/design/changelog/2026-07-02-design-inspector-and-canvas-controls-stay-consistent-when-se.md +6 -0
- package/corpus/templates/design/changelog/2026-07-02-fixed-a-crash-when-opening-the-code-editor.md +6 -0
- package/corpus/templates/design/changelog/2026-07-02-fixed-motion-drawer-open-transition.md +6 -0
- package/corpus/templates/design/changelog/2026-07-02-improved-design-assets-panel.md +6 -0
- package/dist/action.d.ts +8 -0
- package/dist/action.d.ts.map +1 -1
- package/dist/action.js +3 -0
- package/dist/action.js.map +1 -1
- package/dist/agent/production-agent.d.ts +10 -11
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +21 -44
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +1 -0
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +61 -11
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +1 -1
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/conversation/use-near-bottom-autoscroll.d.ts.map +1 -1
- package/dist/client/conversation/use-near-bottom-autoscroll.js +43 -2
- package/dist/client/conversation/use-near-bottom-autoscroll.js.map +1 -1
- package/dist/coding-tools/run-code.d.ts.map +1 -1
- package/dist/coding-tools/run-code.js +1 -0
- package/dist/coding-tools/run-code.js.map +1 -1
- package/dist/collab/routes.d.ts +2 -2
- package/dist/integrations/webhook-handler.d.ts +1 -0
- package/dist/integrations/webhook-handler.d.ts.map +1 -1
- package/dist/integrations/webhook-handler.js +9 -9
- package/dist/integrations/webhook-handler.js.map +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +3 -3
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/server/action-discovery.d.ts.map +1 -1
- package/dist/server/action-discovery.js +3 -0
- package/dist/server/action-discovery.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/credential-provider.d.ts +4 -0
- package/dist/server/credential-provider.d.ts.map +1 -1
- package/dist/server/credential-provider.js +13 -7
- package/dist/server/credential-provider.js.map +1 -1
- package/docs/content/locales/ar-SA/template-analytics.mdx +2 -0
- package/docs/content/locales/ar-SA/template-clips.mdx +2 -0
- package/docs/content/locales/de-DE/template-analytics.mdx +2 -0
- package/docs/content/locales/de-DE/template-clips.mdx +2 -0
- package/docs/content/locales/es-ES/template-analytics.mdx +2 -0
- package/docs/content/locales/es-ES/template-clips.mdx +2 -0
- package/docs/content/locales/fr-FR/template-analytics.mdx +2 -0
- package/docs/content/locales/fr-FR/template-clips.mdx +2 -0
- package/docs/content/locales/hi-IN/template-analytics.mdx +2 -0
- package/docs/content/locales/hi-IN/template-clips.mdx +2 -0
- package/docs/content/locales/ja-JP/template-analytics.mdx +2 -0
- package/docs/content/locales/ja-JP/template-clips.mdx +2 -0
- package/docs/content/locales/ko-KR/template-analytics.mdx +2 -0
- package/docs/content/locales/ko-KR/template-clips.mdx +2 -0
- package/docs/content/locales/pt-BR/template-analytics.mdx +2 -0
- package/docs/content/locales/pt-BR/template-clips.mdx +2 -0
- package/docs/content/locales/zh-CN/template-analytics.mdx +2 -0
- package/docs/content/locales/zh-CN/template-clips.mdx +2 -0
- package/docs/content/locales/zh-TW/template-analytics.mdx +2 -0
- package/docs/content/locales/zh-TW/template-clips.mdx +2 -0
- package/docs/content/template-analytics.mdx +2 -0
- package/docs/content/template-clips.mdx +22 -10
- package/docs/content/tracking.mdx +2 -0
- package/package.json +1 -1
|
@@ -10,25 +10,18 @@ import {
|
|
|
10
10
|
IconUpload,
|
|
11
11
|
} from "@tabler/icons-react";
|
|
12
12
|
import { useQueryClient } from "@tanstack/react-query";
|
|
13
|
-
import {
|
|
14
|
-
useCallback,
|
|
15
|
-
useRef,
|
|
16
|
-
useState,
|
|
17
|
-
type ClipboardEvent,
|
|
18
|
-
type ReactNode,
|
|
19
|
-
} from "react";
|
|
13
|
+
import { useCallback, useRef, useState, type ReactNode } from "react";
|
|
20
14
|
import { useNavigate } from "react-router";
|
|
21
15
|
import { toast } from "sonner";
|
|
22
16
|
|
|
23
17
|
import { Badge } from "@/components/ui/badge";
|
|
24
18
|
import { Button } from "@/components/ui/button";
|
|
25
19
|
import { Textarea } from "@/components/ui/textarea";
|
|
26
|
-
import { sendToDesignAgentChat } from "@/lib/agent-chat";
|
|
27
20
|
import {
|
|
28
|
-
getFigmaClipboardContent,
|
|
29
21
|
importResultSummary,
|
|
30
22
|
looksLikeStandaloneHtml,
|
|
31
23
|
VISUAL_EDIT_CONNECT_COMMAND,
|
|
24
|
+
VISUAL_EDIT_INSTALL_COMMAND,
|
|
32
25
|
type ImportResult,
|
|
33
26
|
} from "@/lib/design-import";
|
|
34
27
|
import { cn } from "@/lib/utils";
|
|
@@ -107,49 +100,6 @@ export function DesignImportPanel({ context }: DesignImportPanelProps) {
|
|
|
107
100
|
[context.designId, finishImport, importSource, t],
|
|
108
101
|
);
|
|
109
102
|
|
|
110
|
-
const handlePaste = useCallback(
|
|
111
|
-
(event: ClipboardEvent<HTMLDivElement>) => {
|
|
112
|
-
const html = event.clipboardData.getData("text/html");
|
|
113
|
-
const text = event.clipboardData.getData("text/plain");
|
|
114
|
-
const content = html || text;
|
|
115
|
-
if (!content) return;
|
|
116
|
-
const figmaContent = getFigmaClipboardContent(event.clipboardData);
|
|
117
|
-
if (figmaContent) {
|
|
118
|
-
event.preventDefault();
|
|
119
|
-
importSource.mutate(
|
|
120
|
-
{
|
|
121
|
-
designId: context.designId,
|
|
122
|
-
sourceType: "figma-paste-html",
|
|
123
|
-
content: figmaContent,
|
|
124
|
-
originalName: "figma-paste.html",
|
|
125
|
-
},
|
|
126
|
-
{
|
|
127
|
-
onSuccess: (result: unknown) => {
|
|
128
|
-
void finishImport(
|
|
129
|
-
result as ImportResult,
|
|
130
|
-
t("designEditor.import.figmaSuccess"),
|
|
131
|
-
);
|
|
132
|
-
},
|
|
133
|
-
onError: (error: unknown) => {
|
|
134
|
-
toast.error(t("designEditor.import.errors.figmaPasteFailed"), {
|
|
135
|
-
description:
|
|
136
|
-
error instanceof Error
|
|
137
|
-
? error.message
|
|
138
|
-
: t("common.genericError"),
|
|
139
|
-
});
|
|
140
|
-
},
|
|
141
|
-
},
|
|
142
|
-
);
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
if (looksLikeStandaloneHtml(content)) {
|
|
146
|
-
event.preventDefault();
|
|
147
|
-
importHtmlString(content, "pasted-html.html");
|
|
148
|
-
}
|
|
149
|
-
},
|
|
150
|
-
[context.designId, finishImport, importHtmlString, importSource, t],
|
|
151
|
-
);
|
|
152
|
-
|
|
153
103
|
const uploadFile = useCallback(
|
|
154
104
|
async (file: File) => {
|
|
155
105
|
setUploading(true);
|
|
@@ -210,46 +160,36 @@ export function DesignImportPanel({ context }: DesignImportPanelProps) {
|
|
|
210
160
|
[importHtmlString],
|
|
211
161
|
);
|
|
212
162
|
|
|
213
|
-
const
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
toast.success(t("designEditor.copied"));
|
|
225
|
-
} catch {
|
|
226
|
-
toast.error(t("designEditor.toasts.clipboardBlocked"));
|
|
227
|
-
}
|
|
228
|
-
}, [t]);
|
|
163
|
+
const copyVisualEditCommand = useCallback(
|
|
164
|
+
async (command: string) => {
|
|
165
|
+
try {
|
|
166
|
+
await navigator.clipboard.writeText(command);
|
|
167
|
+
toast.success(t("designEditor.copied"));
|
|
168
|
+
} catch {
|
|
169
|
+
toast.error(t("designEditor.toasts.clipboardBlocked"));
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
[t],
|
|
173
|
+
);
|
|
229
174
|
|
|
230
175
|
const busy = importSource.isPending || uploading;
|
|
231
176
|
|
|
232
177
|
return (
|
|
233
178
|
<div className="flex min-h-0 flex-1 flex-col bg-background">
|
|
234
|
-
<div className="flex h-
|
|
235
|
-
<
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
</h3>
|
|
239
|
-
<p className="mt-0.5 truncate text-[11px] text-muted-foreground">
|
|
240
|
-
{"Bring source screens into this design" /* i18n-ignore */}
|
|
241
|
-
</p>
|
|
242
|
-
</div>
|
|
179
|
+
<div className="flex min-h-8 shrink-0 items-center border-b border-border/60 px-3">
|
|
180
|
+
<h3 className="min-w-0 flex-1 truncate text-xs font-semibold text-foreground">
|
|
181
|
+
{t("designEditor.import.title")}
|
|
182
|
+
</h3>
|
|
243
183
|
</div>
|
|
244
184
|
|
|
245
|
-
<div className="design-inspector-scroll min-h-0 flex-1 overflow-y-auto overscroll-contain px-3
|
|
185
|
+
<div className="design-inspector-scroll min-h-0 flex-1 overflow-y-auto overscroll-contain px-3 pb-4 pt-3">
|
|
246
186
|
<div className="space-y-0.5">
|
|
247
187
|
<ImportSourceRow
|
|
248
188
|
id="figma-paste-import"
|
|
249
189
|
icon={<IconBrandFigma className="size-3.5" />}
|
|
250
190
|
title={t("designEditor.import.figmaPasteTitle")}
|
|
251
191
|
description={
|
|
252
|
-
"Copy a frame in Figma, then paste
|
|
192
|
+
"Copy a frame in Figma, then paste into the canvas." /* i18n-ignore */
|
|
253
193
|
}
|
|
254
194
|
isOpen={activeMode === "figma-paste"}
|
|
255
195
|
onToggle={() =>
|
|
@@ -258,20 +198,13 @@ export function DesignImportPanel({ context }: DesignImportPanelProps) {
|
|
|
258
198
|
)
|
|
259
199
|
}
|
|
260
200
|
>
|
|
261
|
-
<div className="p-2">
|
|
262
|
-
<
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
className={cn(
|
|
269
|
-
"flex min-h-24 cursor-text items-center justify-center rounded-md border border-dashed border-border bg-muted/30 px-3 py-4 text-center text-xs text-muted-foreground outline-none transition-colors",
|
|
270
|
-
"focus:border-primary/60 focus:bg-background focus:ring-2 focus:ring-primary/15",
|
|
271
|
-
)}
|
|
272
|
-
>
|
|
273
|
-
{t("designEditor.import.figmaPasteTarget")}
|
|
274
|
-
</div>
|
|
201
|
+
<div className="space-y-1.5 p-2 text-[11px] leading-snug text-muted-foreground">
|
|
202
|
+
<p>{t("designEditor.import.figmaPasteDescription")}</p>
|
|
203
|
+
<p>
|
|
204
|
+
{
|
|
205
|
+
"Click the canvas first, then paste with the same shortcut you use for copied Design content." /* i18n-ignore */
|
|
206
|
+
}
|
|
207
|
+
</p>
|
|
275
208
|
</div>
|
|
276
209
|
</ImportSourceRow>
|
|
277
210
|
|
|
@@ -362,6 +295,46 @@ export function DesignImportPanel({ context }: DesignImportPanelProps) {
|
|
|
362
295
|
</div>
|
|
363
296
|
</div>
|
|
364
297
|
</ImportSourceRow>
|
|
298
|
+
|
|
299
|
+
<ImportSourceRow
|
|
300
|
+
id="local-app-import"
|
|
301
|
+
icon={<IconCode className="size-3.5" />}
|
|
302
|
+
title={t("designEditor.import.localTitle")}
|
|
303
|
+
description={t("designEditor.import.localDescription")}
|
|
304
|
+
isOpen={activeMode === "local-app"}
|
|
305
|
+
onToggle={() =>
|
|
306
|
+
setActiveMode((mode) =>
|
|
307
|
+
mode === "local-app" ? null : "local-app",
|
|
308
|
+
)
|
|
309
|
+
}
|
|
310
|
+
>
|
|
311
|
+
<div className="space-y-2 p-2">
|
|
312
|
+
<p className="text-[11px] leading-snug text-muted-foreground">
|
|
313
|
+
{t("designEditor.import.visualEditGuidance")}{" "}
|
|
314
|
+
<a
|
|
315
|
+
href="/docs/template-design"
|
|
316
|
+
target="_blank"
|
|
317
|
+
rel="noreferrer"
|
|
318
|
+
className="font-medium text-foreground underline-offset-2 hover:underline"
|
|
319
|
+
>
|
|
320
|
+
{"Read the visual-edit docs." /* i18n-ignore */}
|
|
321
|
+
</a>
|
|
322
|
+
</p>
|
|
323
|
+
<VisualEditCommandRow
|
|
324
|
+
command={VISUAL_EDIT_INSTALL_COMMAND}
|
|
325
|
+
onCopy={copyVisualEditCommand}
|
|
326
|
+
/>
|
|
327
|
+
<VisualEditCommandRow
|
|
328
|
+
command={VISUAL_EDIT_CONNECT_COMMAND}
|
|
329
|
+
onCopy={copyVisualEditCommand}
|
|
330
|
+
/>
|
|
331
|
+
<p className="text-[10px] leading-snug text-muted-foreground">
|
|
332
|
+
{
|
|
333
|
+
"Replace <port> with the running app's local port." /* i18n-ignore */
|
|
334
|
+
}
|
|
335
|
+
</p>
|
|
336
|
+
</div>
|
|
337
|
+
</ImportSourceRow>
|
|
365
338
|
</div>
|
|
366
339
|
|
|
367
340
|
<div className="mt-4 border-t border-border/60 pt-3">
|
|
@@ -377,47 +350,6 @@ export function DesignImportPanel({ context }: DesignImportPanelProps) {
|
|
|
377
350
|
}
|
|
378
351
|
badge={t("designEditor.import.comingSoon")}
|
|
379
352
|
/>
|
|
380
|
-
<ImportSourceRow
|
|
381
|
-
id="local-app-import"
|
|
382
|
-
icon={<IconCode className="size-3.5" />}
|
|
383
|
-
title={t("designEditor.import.localTitle")}
|
|
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
|
-
}
|
|
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>
|
|
411
|
-
<Button
|
|
412
|
-
size="sm"
|
|
413
|
-
variant="outline"
|
|
414
|
-
className="h-7 w-full justify-center text-[11px]"
|
|
415
|
-
onClick={askVisualEdit}
|
|
416
|
-
>
|
|
417
|
-
{t("designEditor.import.useVisualEditNow")}
|
|
418
|
-
</Button>
|
|
419
|
-
</div>
|
|
420
|
-
</ImportSourceRow>
|
|
421
353
|
</div>
|
|
422
354
|
</div>
|
|
423
355
|
|
|
@@ -441,6 +373,32 @@ export function DesignImportPanel({ context }: DesignImportPanelProps) {
|
|
|
441
373
|
);
|
|
442
374
|
}
|
|
443
375
|
|
|
376
|
+
function VisualEditCommandRow({
|
|
377
|
+
command,
|
|
378
|
+
onCopy,
|
|
379
|
+
}: {
|
|
380
|
+
command: string;
|
|
381
|
+
onCopy: (command: string) => void;
|
|
382
|
+
}) {
|
|
383
|
+
return (
|
|
384
|
+
<div className="flex items-center gap-1.5 rounded-md border border-border/70 bg-muted/40 p-1.5">
|
|
385
|
+
<code className="min-w-0 flex-1 truncate font-mono text-[10px] leading-5 text-foreground/80">
|
|
386
|
+
{command}
|
|
387
|
+
</code>
|
|
388
|
+
<Button
|
|
389
|
+
type="button"
|
|
390
|
+
size="sm"
|
|
391
|
+
variant="ghost"
|
|
392
|
+
aria-label={"Copy command" /* i18n-ignore */}
|
|
393
|
+
className="h-6 shrink-0 px-1.5 text-[10px]"
|
|
394
|
+
onClick={() => onCopy(command)}
|
|
395
|
+
>
|
|
396
|
+
<IconCopy className="size-3" />
|
|
397
|
+
</Button>
|
|
398
|
+
</div>
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
|
|
444
402
|
function ImportSourceRow({
|
|
445
403
|
id,
|
|
446
404
|
icon,
|
|
@@ -138,7 +138,7 @@ import type { StatesPanelProps } from "./StatesPanel";
|
|
|
138
138
|
import { TweaksPanelContent } from "./TweaksPanel";
|
|
139
139
|
import type { ElementInfo } from "./types";
|
|
140
140
|
|
|
141
|
-
export type InspectorTab = "design" | "tweaks"
|
|
141
|
+
export type InspectorTab = "design" | "tweaks";
|
|
142
142
|
|
|
143
143
|
const MIXED_VALUE = "Mixed";
|
|
144
144
|
|
|
@@ -206,6 +206,7 @@ function mixedElementFromSelection(
|
|
|
206
206
|
interface EditPanelProps {
|
|
207
207
|
selectedElement: ElementInfo | null;
|
|
208
208
|
selectedElements?: ElementInfo[];
|
|
209
|
+
selectedScreenGeometry?: ScreenGeometrySelection | null;
|
|
209
210
|
pageStyles?: Record<string, string>;
|
|
210
211
|
zoom?: number;
|
|
211
212
|
headerTrailing?: ReactNode;
|
|
@@ -216,7 +217,6 @@ interface EditPanelProps {
|
|
|
216
217
|
tweakValues?: Record<string, string | number | boolean>;
|
|
217
218
|
onTweakChange?: (id: string, value: string | number | boolean) => void;
|
|
218
219
|
onRequestTweaks?: (anchor: HTMLElement) => void;
|
|
219
|
-
extensionsPanel?: ReactNode;
|
|
220
220
|
onStyleChange: (property: string, value: string) => void;
|
|
221
221
|
onStylesChange?: (styles: Record<string, string>) => void;
|
|
222
222
|
onExport?: (settings: ExportSettingsValue[]) => void;
|
|
@@ -288,6 +288,15 @@ interface EditPanelProps {
|
|
|
288
288
|
aiActions?: ReactNode;
|
|
289
289
|
}
|
|
290
290
|
|
|
291
|
+
export interface ScreenGeometrySelection {
|
|
292
|
+
id: string;
|
|
293
|
+
title: string;
|
|
294
|
+
x: number;
|
|
295
|
+
y: number;
|
|
296
|
+
width: number;
|
|
297
|
+
height: number;
|
|
298
|
+
}
|
|
299
|
+
|
|
291
300
|
/**
|
|
292
301
|
* Data backing the "Inspect code" popover. The parent resolves the selected
|
|
293
302
|
* node's HTML and (for real-app sources) its source file location.
|
|
@@ -2959,16 +2968,87 @@ function SelectionHeader({
|
|
|
2959
2968
|
);
|
|
2960
2969
|
}
|
|
2961
2970
|
|
|
2971
|
+
function ScreenSelectionHeader({
|
|
2972
|
+
screen,
|
|
2973
|
+
}: {
|
|
2974
|
+
screen: ScreenGeometrySelection;
|
|
2975
|
+
}) {
|
|
2976
|
+
return (
|
|
2977
|
+
<div className="flex min-h-8 shrink-0 items-center justify-between gap-2 border-b border-border/90 px-3">
|
|
2978
|
+
<div className="flex min-w-0 items-center gap-1.5 text-left text-[13px] font-semibold text-foreground">
|
|
2979
|
+
<IconFrame className="size-3.5 shrink-0 text-muted-foreground" />
|
|
2980
|
+
<span className="truncate">{screen.title}</span>
|
|
2981
|
+
</div>
|
|
2982
|
+
</div>
|
|
2983
|
+
);
|
|
2984
|
+
}
|
|
2985
|
+
|
|
2986
|
+
function ScreenGeometryProperties({
|
|
2987
|
+
screen,
|
|
2988
|
+
}: {
|
|
2989
|
+
screen: ScreenGeometrySelection;
|
|
2990
|
+
}) {
|
|
2991
|
+
const t = useT();
|
|
2992
|
+
const noop = useCallback(() => {}, []);
|
|
2993
|
+
|
|
2994
|
+
return (
|
|
2995
|
+
<PanelSection title={t("editPanel.sections.positionLayout")}>
|
|
2996
|
+
<div className="space-y-1.5">
|
|
2997
|
+
<SubsectionLabel>{t("editPanel.labels.position")}</SubsectionLabel>
|
|
2998
|
+
<div className="grid grid-cols-2 gap-2">
|
|
2999
|
+
<ScrubInput
|
|
3000
|
+
label="X"
|
|
3001
|
+
value={Math.round(screen.x)}
|
|
3002
|
+
onChange={noop}
|
|
3003
|
+
unit="px"
|
|
3004
|
+
disabled
|
|
3005
|
+
inputClassName="h-6"
|
|
3006
|
+
/>
|
|
3007
|
+
<ScrubInput
|
|
3008
|
+
label="Y"
|
|
3009
|
+
value={Math.round(screen.y)}
|
|
3010
|
+
onChange={noop}
|
|
3011
|
+
unit="px"
|
|
3012
|
+
disabled
|
|
3013
|
+
inputClassName="h-6"
|
|
3014
|
+
/>
|
|
3015
|
+
</div>
|
|
3016
|
+
</div>
|
|
3017
|
+
<div className="space-y-1.5">
|
|
3018
|
+
<SubsectionLabel>
|
|
3019
|
+
{"Size" /* i18n-ignore design inspector label */}
|
|
3020
|
+
</SubsectionLabel>
|
|
3021
|
+
<div className="grid grid-cols-2 gap-2">
|
|
3022
|
+
<ScrubInput
|
|
3023
|
+
label="W"
|
|
3024
|
+
value={Math.round(screen.width)}
|
|
3025
|
+
onChange={noop}
|
|
3026
|
+
unit="px"
|
|
3027
|
+
disabled
|
|
3028
|
+
inputClassName="h-6"
|
|
3029
|
+
/>
|
|
3030
|
+
<ScrubInput
|
|
3031
|
+
label="H"
|
|
3032
|
+
value={Math.round(screen.height)}
|
|
3033
|
+
onChange={noop}
|
|
3034
|
+
unit="px"
|
|
3035
|
+
disabled
|
|
3036
|
+
inputClassName="h-6"
|
|
3037
|
+
/>
|
|
3038
|
+
</div>
|
|
3039
|
+
</div>
|
|
3040
|
+
</PanelSection>
|
|
3041
|
+
);
|
|
3042
|
+
}
|
|
3043
|
+
|
|
2962
3044
|
function InspectorTabsHeader({
|
|
2963
3045
|
activeTab,
|
|
2964
3046
|
onActiveTabChange,
|
|
2965
3047
|
trailing,
|
|
2966
|
-
showExtensions,
|
|
2967
3048
|
}: {
|
|
2968
3049
|
activeTab: InspectorTab;
|
|
2969
3050
|
onActiveTabChange: (tab: InspectorTab) => void;
|
|
2970
3051
|
trailing?: ReactNode;
|
|
2971
|
-
showExtensions?: boolean;
|
|
2972
3052
|
}) {
|
|
2973
3053
|
const t = useT();
|
|
2974
3054
|
|
|
@@ -2991,14 +3071,6 @@ function InspectorTabsHeader({
|
|
|
2991
3071
|
>
|
|
2992
3072
|
{t("designEditor.tweaks")}
|
|
2993
3073
|
</TabsTrigger>
|
|
2994
|
-
{showExtensions ? (
|
|
2995
|
-
<TabsTrigger
|
|
2996
|
-
value="extensions"
|
|
2997
|
-
className="h-6 rounded-md px-1.5 !text-[11px] font-semibold text-muted-foreground shadow-none transition-colors hover:text-foreground data-[state=active]:bg-[var(--design-editor-panel-raised-bg)] data-[state=active]:text-foreground data-[state=active]:shadow-none"
|
|
2998
|
-
>
|
|
2999
|
-
{"Extensions" /* i18n-ignore design inspector tab */}
|
|
3000
|
-
</TabsTrigger>
|
|
3001
|
-
) : null}
|
|
3002
3074
|
</TabsList>
|
|
3003
3075
|
</Tabs>
|
|
3004
3076
|
{trailing ? <div className="shrink-0">{trailing}</div> : null}
|
|
@@ -6859,6 +6931,7 @@ export function ComponentSection({
|
|
|
6859
6931
|
export function EditPanel({
|
|
6860
6932
|
selectedElement,
|
|
6861
6933
|
selectedElements,
|
|
6934
|
+
selectedScreenGeometry,
|
|
6862
6935
|
pageStyles = {},
|
|
6863
6936
|
headerTrailing,
|
|
6864
6937
|
width = 256,
|
|
@@ -6868,7 +6941,6 @@ export function EditPanel({
|
|
|
6868
6941
|
tweakValues = {},
|
|
6869
6942
|
onTweakChange,
|
|
6870
6943
|
onRequestTweaks,
|
|
6871
|
-
extensionsPanel,
|
|
6872
6944
|
onStyleChange,
|
|
6873
6945
|
onStylesChange,
|
|
6874
6946
|
onExport,
|
|
@@ -6978,7 +7050,6 @@ export function EditPanel({
|
|
|
6978
7050
|
activeTab={activeTab}
|
|
6979
7051
|
onActiveTabChange={handleActiveTabChange}
|
|
6980
7052
|
trailing={headerTrailing}
|
|
6981
|
-
showExtensions={!!extensionsPanel}
|
|
6982
7053
|
/>
|
|
6983
7054
|
|
|
6984
7055
|
{activeTab === "design" ? (
|
|
@@ -6999,6 +7070,9 @@ export function EditPanel({
|
|
|
6999
7070
|
: undefined
|
|
7000
7071
|
}
|
|
7001
7072
|
/>
|
|
7073
|
+
{!inspectorElement && selectedScreenGeometry ? (
|
|
7074
|
+
<ScreenSelectionHeader screen={selectedScreenGeometry} />
|
|
7075
|
+
) : null}
|
|
7002
7076
|
|
|
7003
7077
|
<div
|
|
7004
7078
|
className="design-inspector-scroll min-h-0 flex-1 overflow-y-auto overscroll-contain"
|
|
@@ -7093,7 +7167,11 @@ export function EditPanel({
|
|
|
7093
7167
|
</div>
|
|
7094
7168
|
) : null}
|
|
7095
7169
|
|
|
7096
|
-
{!inspectorElement && (
|
|
7170
|
+
{!inspectorElement && selectedScreenGeometry ? (
|
|
7171
|
+
<ScreenGeometryProperties screen={selectedScreenGeometry} />
|
|
7172
|
+
) : null}
|
|
7173
|
+
|
|
7174
|
+
{!inspectorElement && !selectedScreenGeometry && (
|
|
7097
7175
|
<PageProperties
|
|
7098
7176
|
styles={pageStyles}
|
|
7099
7177
|
onStyleChange={onStyleChange}
|
|
@@ -7263,10 +7341,6 @@ export function EditPanel({
|
|
|
7263
7341
|
/>
|
|
7264
7342
|
</div>
|
|
7265
7343
|
</div>
|
|
7266
|
-
) : activeTab === "extensions" && extensionsPanel ? (
|
|
7267
|
-
<div className="flex min-h-0 flex-1 flex-col overflow-hidden">
|
|
7268
|
-
{extensionsPanel}
|
|
7269
|
-
</div>
|
|
7270
7344
|
) : null}
|
|
7271
7345
|
</div>
|
|
7272
7346
|
);
|
|
@@ -409,10 +409,6 @@ const DRAG_THRESHOLD = 3;
|
|
|
409
409
|
const FRAME_LABEL_HEIGHT = 28;
|
|
410
410
|
const FRAME_HEADER_BUTTON_OUTSIDE_WIDTH = 260;
|
|
411
411
|
const FRAME_HEADER_BUTTON_RESERVE = 116;
|
|
412
|
-
const FRAME_HEADER_DIMENSIONS_WIDTH = 72;
|
|
413
|
-
const FRAME_HEADER_TITLE_CHAR_WIDTH = 6.5;
|
|
414
|
-
const FRAME_HEADER_MIN_TITLE_WIDTH = 28;
|
|
415
|
-
const FRAME_HEADER_MAX_TITLE_WIDTH = 180;
|
|
416
412
|
const TRANSFORM_BADGE_OFFSET = 12;
|
|
417
413
|
const TRANSFORM_BADGE_EDGE_PADDING = 8;
|
|
418
414
|
const TRANSFORM_BADGE_HEIGHT = 28;
|
|
@@ -433,7 +429,7 @@ const CHROME_OPACITY_TRANSITION = "opacity 150ms ease-out";
|
|
|
433
429
|
const CHROME_BORDER_SETTLE_TRANSITION = `inset ${CHROME_SETTLE_MS}ms ease-out, border-width ${CHROME_SETTLE_MS}ms ease-out, border-radius ${CHROME_SETTLE_MS}ms ease-out, ${CHROME_OPACITY_TRANSITION}`;
|
|
434
430
|
const SELECTION_BOX_SETTLE_TRANSITION = `border-width ${CHROME_SETTLE_MS}ms ease-out, border-radius ${CHROME_SETTLE_MS}ms ease-out, ${CHROME_OPACITY_TRANSITION}`;
|
|
435
431
|
const CHROME_HANDLE_SETTLE_TRANSITION = `width ${CHROME_SETTLE_MS}ms ease-out, height ${CHROME_SETTLE_MS}ms ease-out, border-width ${CHROME_SETTLE_MS}ms ease-out, top ${CHROME_SETTLE_MS}ms ease-out, bottom ${CHROME_SETTLE_MS}ms ease-out, left ${CHROME_SETTLE_MS}ms ease-out, right ${CHROME_SETTLE_MS}ms ease-out, ${CHROME_OPACITY_TRANSITION}`;
|
|
436
|
-
// Frame header (name +
|
|
432
|
+
// Frame header (name + "Full view" button) is counter-scaled via
|
|
437
433
|
// transform to stay a fixed screen size; ease that scale on zoom-settle. opacity
|
|
438
434
|
// is included so the button's hover-fade (transition-opacity) keeps working.
|
|
439
435
|
const CHROME_LABEL_SETTLE_TRANSITION = `transform ${CHROME_SETTLE_MS}ms ease-out, ${CHROME_OPACITY_TRANSITION}`;
|
|
@@ -474,6 +470,14 @@ export function shouldBoardSurfaceCapturePointerEvents(args: {
|
|
|
474
470
|
);
|
|
475
471
|
}
|
|
476
472
|
|
|
473
|
+
export function shouldShowFrameFullViewButton(args: {
|
|
474
|
+
emphasized: boolean;
|
|
475
|
+
showFullView?: boolean;
|
|
476
|
+
childHoverActive?: boolean;
|
|
477
|
+
}) {
|
|
478
|
+
return args.emphasized || !!args.showFullView || !!args.childHoverActive;
|
|
479
|
+
}
|
|
480
|
+
|
|
477
481
|
export function getBoardSurfaceLayerStyle(args: {
|
|
478
482
|
geometry: FrameGeometry;
|
|
479
483
|
interactive: boolean;
|
|
@@ -5676,10 +5680,16 @@ const Screen = memo(function Screen({
|
|
|
5676
5680
|
(directlyHovered || isDirectlyHovered) &&
|
|
5677
5681
|
!creationToolActive &&
|
|
5678
5682
|
!canvasGestureActive;
|
|
5683
|
+
const childHoverActive =
|
|
5684
|
+
hasHoveredChild && !creationToolActive && !canvasGestureActive;
|
|
5679
5685
|
const suppressFrameChromeForChild =
|
|
5680
5686
|
hasHoveredChild && !directlyHovered && !isDirectlyHovered;
|
|
5681
5687
|
const emphasized = isSelected || frameDirectlyHovered;
|
|
5682
|
-
const fullViewVisible =
|
|
5688
|
+
const fullViewVisible = shouldShowFrameFullViewButton({
|
|
5689
|
+
emphasized,
|
|
5690
|
+
showFullView,
|
|
5691
|
+
childHoverActive,
|
|
5692
|
+
});
|
|
5683
5693
|
const activeOrEmphasized = isActive || emphasized;
|
|
5684
5694
|
const selectionOutlined = isSelected && !groupSelected;
|
|
5685
5695
|
const showHoverChrome =
|
|
@@ -5712,16 +5722,6 @@ const Screen = memo(function Screen({
|
|
|
5712
5722
|
64,
|
|
5713
5723
|
frameScreenWidth - (fullViewOutsideFrame ? 8 : FRAME_HEADER_BUTTON_RESERVE),
|
|
5714
5724
|
);
|
|
5715
|
-
const estimatedTitleWidth = clamp(
|
|
5716
|
-
display.length * FRAME_HEADER_TITLE_CHAR_WIDTH,
|
|
5717
|
-
FRAME_HEADER_MIN_TITLE_WIDTH,
|
|
5718
|
-
FRAME_HEADER_MAX_TITLE_WIDTH,
|
|
5719
|
-
);
|
|
5720
|
-
const showDimensions =
|
|
5721
|
-
frameScreenWidth >=
|
|
5722
|
-
estimatedTitleWidth +
|
|
5723
|
-
FRAME_HEADER_DIMENSIONS_WIDTH +
|
|
5724
|
-
(fullViewOutsideFrame ? 16 : FRAME_HEADER_BUTTON_RESERVE);
|
|
5725
5725
|
const fullViewMaxWidth = fullViewOutsideFrame
|
|
5726
5726
|
? 120
|
|
5727
5727
|
: Math.max(84, Math.min(180, frameScreenWidth * 0.46));
|
|
@@ -5806,14 +5806,6 @@ const Screen = memo(function Screen({
|
|
|
5806
5806
|
>
|
|
5807
5807
|
{display}
|
|
5808
5808
|
</span>
|
|
5809
|
-
{showDimensions ? (
|
|
5810
|
-
<span
|
|
5811
|
-
data-frame-dimensions
|
|
5812
|
-
className="hidden shrink-0 text-[10px] tabular-nums text-muted-foreground/70 sm:inline"
|
|
5813
|
-
>
|
|
5814
|
-
{previewViewport.displayWidth} x {previewViewport.displayHeight}
|
|
5815
|
-
</span>
|
|
5816
|
-
) : null}
|
|
5817
5809
|
</div>
|
|
5818
5810
|
<button
|
|
5819
5811
|
type="button"
|
|
@@ -6551,12 +6543,12 @@ interface BoundsRect {
|
|
|
6551
6543
|
bottom: number;
|
|
6552
6544
|
}
|
|
6553
6545
|
|
|
6554
|
-
interface ScreenViewportSize {
|
|
6546
|
+
export interface ScreenViewportSize {
|
|
6555
6547
|
width: number;
|
|
6556
6548
|
height: number;
|
|
6557
6549
|
}
|
|
6558
6550
|
|
|
6559
|
-
function getInitialFrameGeometry(
|
|
6551
|
+
export function getInitialFrameGeometry(
|
|
6560
6552
|
index: number,
|
|
6561
6553
|
metadata?: ScreenViewportSize,
|
|
6562
6554
|
): FrameGeometry {
|