@agent-native/core 0.106.0 → 0.106.2
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 +12 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/a2a/artifact-response.ts +84 -0
- package/corpus/core/src/agent/thread-data-builder.ts +1 -1
- package/corpus/core/src/application-state/index.ts +2 -0
- package/corpus/core/src/application-state/script-helpers.ts +12 -0
- package/corpus/core/src/application-state/store.ts +38 -0
- package/corpus/core/src/client/review/ReviewCommentComposer.tsx +10 -3
- package/corpus/core/src/integrations/webhook-handler.ts +41 -5
- package/corpus/core/src/server/agent-chat-plugin.ts +7 -2
- package/corpus/templates/clips/app/components/capture-install-options.tsx +60 -5
- package/corpus/templates/clips/app/components/library/library-layout.tsx +9 -1
- package/corpus/templates/clips/app/hooks/use-desktop-promo.ts +4 -4
- package/corpus/templates/clips/app/i18n/ar-SA.ts +1 -0
- package/corpus/templates/clips/app/i18n/de-DE.ts +1 -0
- package/corpus/templates/clips/app/i18n/en-US.ts +1 -0
- package/corpus/templates/clips/app/i18n/es-ES.ts +1 -0
- package/corpus/templates/clips/app/i18n/fr-FR.ts +1 -0
- package/corpus/templates/clips/app/i18n/hi-IN.ts +1 -0
- package/corpus/templates/clips/app/i18n/ja-JP.ts +1 -0
- package/corpus/templates/clips/app/i18n/ko-KR.ts +1 -0
- package/corpus/templates/clips/app/i18n/pt-BR.ts +1 -0
- package/corpus/templates/clips/app/i18n/zh-CN.ts +1 -0
- package/corpus/templates/clips/app/i18n/zh-TW.ts +1 -0
- package/corpus/templates/clips/app/lib/capture-install-options.ts +89 -4
- package/corpus/templates/clips/app/routes/_app.dictate.tsx +10 -1
- package/corpus/templates/clips/app/routes/record.tsx +1 -0
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +7 -0
- package/corpus/templates/clips/changelog/2026-07-16-the-desktop-app-button-now-shows-open-desktop-app-and-launch.md +6 -0
- package/corpus/templates/clips/desktop/src-tauri/Cargo.toml +5 -0
- package/corpus/templates/clips/desktop/src-tauri/capabilities/default.json +1 -0
- package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +41 -6
- package/corpus/templates/clips/desktop/src-tauri/tauri.conf.json +5 -0
- package/corpus/templates/content/.agents/skills/content/SKILL.md +31 -0
- package/corpus/templates/content/changelog/2026-07-16-slack-corrections-now-preserve-newer-content-values-unless-y.md +6 -0
- package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +22 -0
- package/corpus/templates/design/AGENTS.md +16 -0
- package/corpus/templates/design/actions/cancel-node-rewrite-request.ts +54 -0
- package/corpus/templates/design/actions/propose-node-rewrite.ts +290 -0
- package/corpus/templates/design/actions/resolve-node-rewrite.ts +257 -0
- package/corpus/templates/design/actions/view-screen.ts +98 -2
- package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +71 -1
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +19 -0
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +33 -0
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +194 -0
- package/corpus/templates/design/app/components/design/bridge/hit-test.bridge.ts +21 -4
- package/corpus/templates/design/app/components/design/design-canvas/iframe-events.ts +18 -0
- package/corpus/templates/design/app/components/design/multi-screen/types.ts +4 -0
- package/corpus/templates/design/app/components/visual-editor/NodeRewriteProposal.tsx +638 -0
- package/corpus/templates/design/app/components/visual-editor/ReviewCanvasPins.tsx +535 -54
- package/corpus/templates/design/app/components/visual-editor/index.ts +5 -1
- package/corpus/templates/design/app/components/visual-editor/review-canvas-state.ts +21 -3
- package/corpus/templates/design/app/i18n/ar-SA.ts +35 -0
- package/corpus/templates/design/app/i18n/de-DE.ts +35 -0
- package/corpus/templates/design/app/i18n/es-ES.ts +35 -0
- package/corpus/templates/design/app/i18n/fr-FR.ts +35 -0
- package/corpus/templates/design/app/i18n/hi-IN.ts +35 -0
- package/corpus/templates/design/app/i18n/ja-JP.ts +35 -0
- package/corpus/templates/design/app/i18n/ko-KR.ts +35 -0
- package/corpus/templates/design/app/i18n/pt-BR.ts +35 -0
- package/corpus/templates/design/app/i18n/zh-CN.ts +35 -0
- package/corpus/templates/design/app/i18n/zh-TW.ts +32 -0
- package/corpus/templates/design/app/i18n-data.ts +32 -0
- package/corpus/templates/design/app/lib/node-reprompt.ts +110 -0
- package/corpus/templates/design/changelog/2026-07-16-design-editing-and-review-are-now-more-predictable.md +6 -0
- package/corpus/templates/design/server/lib/reprompt-action-guard.ts +107 -0
- package/corpus/templates/design/server/plugins/agent-chat.ts +9 -1
- package/corpus/templates/design/shared/code-layer.ts +15 -0
- package/corpus/templates/design/shared/node-rewrite.ts +213 -0
- package/corpus/templates/design/shared/review-anchor.ts +26 -3
- package/dist/a2a/artifact-response.d.ts +9 -0
- package/dist/a2a/artifact-response.d.ts.map +1 -1
- package/dist/a2a/artifact-response.js +68 -0
- package/dist/a2a/artifact-response.js.map +1 -1
- package/dist/agent/thread-data-builder.js +1 -1
- package/dist/agent/thread-data-builder.js.map +1 -1
- package/dist/application-state/index.d.ts +2 -2
- package/dist/application-state/index.d.ts.map +1 -1
- package/dist/application-state/index.js +2 -2
- package/dist/application-state/index.js.map +1 -1
- package/dist/application-state/script-helpers.d.ts +1 -0
- package/dist/application-state/script-helpers.d.ts.map +1 -1
- package/dist/application-state/script-helpers.js +7 -1
- package/dist/application-state/script-helpers.js.map +1 -1
- package/dist/application-state/store.d.ts +1 -0
- package/dist/application-state/store.d.ts.map +1 -1
- package/dist/application-state/store.js +28 -0
- package/dist/application-state/store.js.map +1 -1
- package/dist/client/review/ReviewCommentComposer.d.ts +4 -1
- package/dist/client/review/ReviewCommentComposer.d.ts.map +1 -1
- package/dist/client/review/ReviewCommentComposer.js +3 -3
- package/dist/client/review/ReviewCommentComposer.js.map +1 -1
- package/dist/integrations/webhook-handler.d.ts.map +1 -1
- package/dist/integrations/webhook-handler.js +24 -5
- package/dist/integrations/webhook-handler.js.map +1 -1
- package/dist/notifications/routes.d.ts +2 -2
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +3 -1
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/package.json +1 -1
|
@@ -92,6 +92,7 @@ export type CanvasContextMenuAction =
|
|
|
92
92
|
| "add-auto-layout"
|
|
93
93
|
| "suggest-auto-layout"
|
|
94
94
|
| "create-component"
|
|
95
|
+
| "reprompt"
|
|
95
96
|
| "go-to-main-component"
|
|
96
97
|
| "swap-instance"
|
|
97
98
|
| "detach-instance"
|
|
@@ -135,6 +136,7 @@ export type CanvasContextMenuActionHandler = (
|
|
|
135
136
|
|
|
136
137
|
export interface CanvasContextMenuLabels {
|
|
137
138
|
selectLayer: string;
|
|
139
|
+
reprompt: string;
|
|
138
140
|
pasteHere: string;
|
|
139
141
|
selectAll: string;
|
|
140
142
|
zoomToFit: string;
|
|
@@ -231,6 +233,10 @@ export interface CanvasContextMenuProps {
|
|
|
231
233
|
selectedCount?: number;
|
|
232
234
|
layerCandidates?: readonly CanvasLayerHitCandidate[];
|
|
233
235
|
onSelectLayer?: (candidate: CanvasLayerHitCandidate) => void;
|
|
236
|
+
onRepromptLayer?: (
|
|
237
|
+
candidate: CanvasLayerHitCandidate,
|
|
238
|
+
details: CanvasContextMenuActionDetails,
|
|
239
|
+
) => void;
|
|
234
240
|
hasClipboard?: boolean;
|
|
235
241
|
hasPropsClipboard?: boolean;
|
|
236
242
|
hasAnimationClipboard?: boolean;
|
|
@@ -261,6 +267,7 @@ export interface CanvasContextMenuProps {
|
|
|
261
267
|
canAddAutoLayout?: boolean;
|
|
262
268
|
canSuggestAutoLayout?: boolean;
|
|
263
269
|
canCreateComponent?: boolean;
|
|
270
|
+
canReprompt?: boolean;
|
|
264
271
|
// Whether the current selection IS a component instance — gates the
|
|
265
272
|
// whole Go to main component / Swap instance / Detach instance cluster on
|
|
266
273
|
// (rather than showing them permanently disabled for non-instance
|
|
@@ -330,6 +337,7 @@ export interface CanvasContextMenuProps {
|
|
|
330
337
|
onAddAutoLayout?: CanvasContextMenuActionHandler;
|
|
331
338
|
onSuggestAutoLayout?: CanvasContextMenuActionHandler;
|
|
332
339
|
onCreateComponent?: CanvasContextMenuActionHandler;
|
|
340
|
+
onReprompt?: CanvasContextMenuActionHandler;
|
|
333
341
|
onGoToMainComponent?: CanvasContextMenuActionHandler;
|
|
334
342
|
onSwapInstance?: CanvasContextMenuActionHandler;
|
|
335
343
|
onDetachInstance?: CanvasContextMenuActionHandler;
|
|
@@ -361,6 +369,7 @@ export interface CanvasContextMenuProps {
|
|
|
361
369
|
|
|
362
370
|
const DEFAULT_LABELS: CanvasContextMenuLabels = {
|
|
363
371
|
selectLayer: "Select layer",
|
|
372
|
+
reprompt: "Regenerate…",
|
|
364
373
|
pasteHere: "Paste here",
|
|
365
374
|
selectAll: "Select all",
|
|
366
375
|
zoomToFit: "Zoom to fit",
|
|
@@ -481,6 +490,7 @@ export const CanvasContextMenu = forwardRef<
|
|
|
481
490
|
selectedCount = 0,
|
|
482
491
|
layerCandidates = [],
|
|
483
492
|
onSelectLayer,
|
|
493
|
+
onRepromptLayer,
|
|
484
494
|
hasClipboard = false,
|
|
485
495
|
hasPropsClipboard = false,
|
|
486
496
|
hasAnimationClipboard = false,
|
|
@@ -500,6 +510,7 @@ export const CanvasContextMenu = forwardRef<
|
|
|
500
510
|
canAddAutoLayout = selectedCount > 0,
|
|
501
511
|
canSuggestAutoLayout = false,
|
|
502
512
|
canCreateComponent = selectedCount > 0,
|
|
513
|
+
canReprompt = selectedCount > 0 || layerCandidates.length > 0,
|
|
503
514
|
isComponentInstance = false,
|
|
504
515
|
canGoToMainComponent = isComponentInstance,
|
|
505
516
|
canSwapInstance = isComponentInstance,
|
|
@@ -540,6 +551,7 @@ export const CanvasContextMenu = forwardRef<
|
|
|
540
551
|
onAddAutoLayout,
|
|
541
552
|
onSuggestAutoLayout,
|
|
542
553
|
onCreateComponent,
|
|
554
|
+
onReprompt,
|
|
543
555
|
onGoToMainComponent,
|
|
544
556
|
onSwapInstance,
|
|
545
557
|
onDetachInstance,
|
|
@@ -624,6 +636,7 @@ export const CanvasContextMenu = forwardRef<
|
|
|
624
636
|
"add-auto-layout": onAddAutoLayout,
|
|
625
637
|
"suggest-auto-layout": onSuggestAutoLayout,
|
|
626
638
|
"create-component": onCreateComponent,
|
|
639
|
+
reprompt: onReprompt,
|
|
627
640
|
"go-to-main-component": onGoToMainComponent,
|
|
628
641
|
"swap-instance": onSwapInstance,
|
|
629
642
|
"detach-instance": onDetachInstance,
|
|
@@ -654,6 +667,7 @@ export const CanvasContextMenu = forwardRef<
|
|
|
654
667
|
onCopyAsSvg,
|
|
655
668
|
onCopyProps,
|
|
656
669
|
onCreateComponent,
|
|
670
|
+
onReprompt,
|
|
657
671
|
onDetachInstance,
|
|
658
672
|
onFlipHorizontal,
|
|
659
673
|
onFlipVertical,
|
|
@@ -772,6 +786,62 @@ export const CanvasContextMenu = forwardRef<
|
|
|
772
786
|
<CanvasMenuSeparator />
|
|
773
787
|
</>
|
|
774
788
|
) : null}
|
|
789
|
+
{canReprompt && (onReprompt || onRepromptLayer) ? (
|
|
790
|
+
<>
|
|
791
|
+
<ContextMenuGroup>
|
|
792
|
+
{layerCandidates.length > 1 && onRepromptLayer ? (
|
|
793
|
+
<ContextMenuSub>
|
|
794
|
+
<ContextMenuSubTrigger className={MENU_SUB_TRIGGER_CLASS}>
|
|
795
|
+
{labels.reprompt}
|
|
796
|
+
</ContextMenuSubTrigger>
|
|
797
|
+
<ContextMenuSubContent
|
|
798
|
+
className={cn(MENU_CONTENT_CLASS, "w-56")}
|
|
799
|
+
>
|
|
800
|
+
{layerCandidates.map((candidate) => (
|
|
801
|
+
<CanvasLayerCandidateItem
|
|
802
|
+
key={`reprompt:${candidate.key}`}
|
|
803
|
+
candidate={candidate}
|
|
804
|
+
onSelect={(event) => {
|
|
805
|
+
onRepromptLayer(candidate, {
|
|
806
|
+
action: "reprompt",
|
|
807
|
+
point,
|
|
808
|
+
selectedCount,
|
|
809
|
+
originalEvent: event,
|
|
810
|
+
});
|
|
811
|
+
handleOpenChange(false);
|
|
812
|
+
}}
|
|
813
|
+
/>
|
|
814
|
+
))}
|
|
815
|
+
</ContextMenuSubContent>
|
|
816
|
+
</ContextMenuSub>
|
|
817
|
+
) : (
|
|
818
|
+
<CanvasMenuItem
|
|
819
|
+
hidden={isHiddenAction("reprompt")}
|
|
820
|
+
disabled={
|
|
821
|
+
!canReprompt ||
|
|
822
|
+
(!onReprompt &&
|
|
823
|
+
!(onRepromptLayer && layerCandidates.length === 1))
|
|
824
|
+
}
|
|
825
|
+
label={labels.reprompt}
|
|
826
|
+
onSelect={(event) => {
|
|
827
|
+
const candidate = layerCandidates[0];
|
|
828
|
+
if (!onReprompt && onRepromptLayer && candidate) {
|
|
829
|
+
onRepromptLayer(candidate, {
|
|
830
|
+
action: "reprompt",
|
|
831
|
+
point,
|
|
832
|
+
selectedCount,
|
|
833
|
+
originalEvent: event,
|
|
834
|
+
});
|
|
835
|
+
return;
|
|
836
|
+
}
|
|
837
|
+
runAction("reprompt", event);
|
|
838
|
+
}}
|
|
839
|
+
/>
|
|
840
|
+
)}
|
|
841
|
+
</ContextMenuGroup>
|
|
842
|
+
<CanvasMenuSeparator />
|
|
843
|
+
</>
|
|
844
|
+
) : null}
|
|
775
845
|
{hasSelection ? (
|
|
776
846
|
<>
|
|
777
847
|
{/* LIVE-VERIFIED Figma "with selection" canvas menu. */}
|
|
@@ -1083,7 +1153,7 @@ function CanvasLayerCandidateItem({
|
|
|
1083
1153
|
onSelect,
|
|
1084
1154
|
}: {
|
|
1085
1155
|
candidate: CanvasLayerHitCandidate;
|
|
1086
|
-
onSelect: () => void;
|
|
1156
|
+
onSelect: (event: Event) => void;
|
|
1087
1157
|
}) {
|
|
1088
1158
|
const tag = candidate.info.tagName.toLowerCase();
|
|
1089
1159
|
const Icon = candidate.info.componentName
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
type PenPath,
|
|
25
25
|
type PenPoint,
|
|
26
26
|
} from "@shared/pen-path";
|
|
27
|
+
import { sourceContentHash } from "@shared/source-workspace";
|
|
27
28
|
import { IconPlugConnectedX, IconRefresh } from "@tabler/icons-react";
|
|
28
29
|
import {
|
|
29
30
|
useCallback,
|
|
@@ -43,6 +44,7 @@ import { Button } from "@/components/ui/button";
|
|
|
43
44
|
import {
|
|
44
45
|
DrawOverlay as SharedDrawOverlay,
|
|
45
46
|
ReviewCanvasPins,
|
|
47
|
+
type RepromptDraftRequest,
|
|
46
48
|
type ReviewFocusRequest,
|
|
47
49
|
} from "@/components/visual-editor";
|
|
48
50
|
import { sendToDesignAgentChatAndConfirm } from "@/lib/agent-chat";
|
|
@@ -556,6 +558,11 @@ interface DesignCanvasProps {
|
|
|
556
558
|
previewFrameId?: string;
|
|
557
559
|
/** Human-readable label for comment-pin prompts. */
|
|
558
560
|
commentContextLabel?: string;
|
|
561
|
+
/** Opens an ephemeral, pre-anchored regenerate composer for this screen. */
|
|
562
|
+
repromptDraftRequest?: RepromptDraftRequest | null;
|
|
563
|
+
onRepromptDraftConsumed?: (nonce: number) => void;
|
|
564
|
+
/** Marks the one base canvas used for pending rewrite previews. */
|
|
565
|
+
nodeRewriteCanvasTarget?: boolean;
|
|
559
566
|
/**
|
|
560
567
|
* Called when a link inside the prototype points to another screen (a
|
|
561
568
|
* relative href or `data-screen`). Lets the editor switch the active screen
|
|
@@ -1053,6 +1060,9 @@ export function DesignCanvas({
|
|
|
1053
1060
|
commentContextId,
|
|
1054
1061
|
screenId,
|
|
1055
1062
|
previewFrameId,
|
|
1063
|
+
repromptDraftRequest,
|
|
1064
|
+
onRepromptDraftConsumed,
|
|
1065
|
+
nodeRewriteCanvasTarget = false,
|
|
1056
1066
|
onPrototypeNavigate,
|
|
1057
1067
|
motionTracks,
|
|
1058
1068
|
motionDefaultEase,
|
|
@@ -4027,6 +4037,9 @@ export function DesignCanvas({
|
|
|
4027
4037
|
const iframeElement = (
|
|
4028
4038
|
<div
|
|
4029
4039
|
data-review-canvas-id={reviewCanvasId}
|
|
4040
|
+
data-node-rewrite-canvas-target={
|
|
4041
|
+
nodeRewriteCanvasTarget ? "true" : undefined
|
|
4042
|
+
}
|
|
4030
4043
|
className="design-canvas-iframe-wrapper relative inline-block ring-1 ring-border/60 shadow-[0_0_0_1px_rgba(0,0,0,0.04),0_8px_24px_-12px_rgba(0,0,0,0.45)]"
|
|
4031
4044
|
onDragEnter={handleWrapperDragEnter}
|
|
4032
4045
|
onDragOver={handleWrapperDragOver}
|
|
@@ -4548,6 +4561,12 @@ export function DesignCanvas({
|
|
|
4548
4561
|
onDispatchCommentToAgent={onDispatchCommentToAgent}
|
|
4549
4562
|
onSendThreadToAgent={onSendThreadToAgent}
|
|
4550
4563
|
sendingThreadId={reviewSendingThreadId}
|
|
4564
|
+
sourceType={
|
|
4565
|
+
sourceType ?? (externalPreviewUrl ? "localhost" : "inline")
|
|
4566
|
+
}
|
|
4567
|
+
sourceVersionHash={sourceContentHash(content)}
|
|
4568
|
+
repromptDraftRequest={repromptDraftRequest}
|
|
4569
|
+
onRepromptDraftConsumed={onRepromptDraftConsumed}
|
|
4551
4570
|
/>
|
|
4552
4571
|
) : null}
|
|
4553
4572
|
</div>
|
|
@@ -398,6 +398,8 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
|
|
|
398
398
|
hiddenScreenIds = EMPTY_SCREEN_IDS,
|
|
399
399
|
lockedScreenIds = EMPTY_SCREEN_IDS,
|
|
400
400
|
fullViewScreenIds,
|
|
401
|
+
pendingReviewScreenIds = EMPTY_SCREEN_IDS,
|
|
402
|
+
onReviewPendingScreen,
|
|
401
403
|
interactMode = false,
|
|
402
404
|
activeScreenHasHoveredChild = false,
|
|
403
405
|
hoveredChildScreenId,
|
|
@@ -525,6 +527,10 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
|
|
|
525
527
|
() => new Set(lockedScreenIds),
|
|
526
528
|
[lockedScreenIds],
|
|
527
529
|
);
|
|
530
|
+
const pendingReviewScreenIdSet = useMemo(
|
|
531
|
+
() => new Set(pendingReviewScreenIds),
|
|
532
|
+
[pendingReviewScreenIds],
|
|
533
|
+
);
|
|
528
534
|
const renderedScreens = useMemo(
|
|
529
535
|
() => screens.filter((screen) => !hiddenScreenIdSet.has(screen.id)),
|
|
530
536
|
[hiddenScreenIdSet, screens],
|
|
@@ -7609,6 +7615,8 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
|
|
|
7609
7615
|
!isBreakpointSelectionTarget(screen)
|
|
7610
7616
|
}
|
|
7611
7617
|
showFullView={fullViewIdSet.has(screen.id)}
|
|
7618
|
+
pendingReview={pendingReviewScreenIdSet.has(screen.id)}
|
|
7619
|
+
onReviewPendingScreen={onReviewPendingScreen}
|
|
7612
7620
|
interactMode={interactMode}
|
|
7613
7621
|
isDirectlyHovered={screen.id === directlyHoveredScreenId}
|
|
7614
7622
|
isFileDragOver={
|
|
@@ -8898,6 +8906,8 @@ interface ScreenProps {
|
|
|
8898
8906
|
isSelected: boolean;
|
|
8899
8907
|
isTopScreen: boolean;
|
|
8900
8908
|
showFullView: boolean;
|
|
8909
|
+
pendingReview: boolean;
|
|
8910
|
+
onReviewPendingScreen?: (screenId: string) => void;
|
|
8901
8911
|
interactMode: boolean;
|
|
8902
8912
|
isDirectlyHovered: boolean;
|
|
8903
8913
|
/** True while a native OS file drag is hovering this frame (Figma parity §1). */
|
|
@@ -8966,6 +8976,8 @@ const Screen = memo(function Screen({
|
|
|
8966
8976
|
isSelected,
|
|
8967
8977
|
isTopScreen,
|
|
8968
8978
|
showFullView,
|
|
8979
|
+
pendingReview,
|
|
8980
|
+
onReviewPendingScreen,
|
|
8969
8981
|
interactMode,
|
|
8970
8982
|
isDirectlyHovered,
|
|
8971
8983
|
isFileDragOver,
|
|
@@ -9174,6 +9186,27 @@ const Screen = memo(function Screen({
|
|
|
9174
9186
|
>
|
|
9175
9187
|
{display}
|
|
9176
9188
|
</span>
|
|
9189
|
+
{pendingReview && onReviewPendingScreen ? (
|
|
9190
|
+
<button
|
|
9191
|
+
type="button"
|
|
9192
|
+
data-node-rewrite-review-badge
|
|
9193
|
+
className="flex h-5 shrink-0 items-center gap-1 rounded-full border border-border bg-background/95 px-1.5 !text-[9px] font-medium text-foreground shadow-sm hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
9194
|
+
title={t("designEditor.nodeRewrite.reviewCandidate")}
|
|
9195
|
+
aria-label={t("designEditor.nodeRewrite.reviewCandidate")}
|
|
9196
|
+
onClick={(event) => {
|
|
9197
|
+
event.preventDefault();
|
|
9198
|
+
event.stopPropagation();
|
|
9199
|
+
onReviewPendingScreen(screen.id);
|
|
9200
|
+
}}
|
|
9201
|
+
onMouseDown={(event) => {
|
|
9202
|
+
event.preventDefault();
|
|
9203
|
+
event.stopPropagation();
|
|
9204
|
+
}}
|
|
9205
|
+
>
|
|
9206
|
+
<span className="size-1.5 rounded-full bg-primary" />
|
|
9207
|
+
{t("designEditor.nodeRewrite.reviewCandidate")}
|
|
9208
|
+
</button>
|
|
9209
|
+
) : null}
|
|
9177
9210
|
{metadata.source === "fusion" ? (
|
|
9178
9211
|
<span
|
|
9179
9212
|
data-frame-source-badge="fusion"
|
|
@@ -2168,6 +2168,17 @@ declare var __RUNTIME_LAYER_SNAPSHOT_ENABLED__: boolean;
|
|
|
2168
2168
|
|
|
2169
2169
|
var selectedEl: Element | null = null;
|
|
2170
2170
|
var hoveredEl: Element | null = null;
|
|
2171
|
+
type NodeHtmlPreviewSession = {
|
|
2172
|
+
proposalId: string;
|
|
2173
|
+
originalElement: Element;
|
|
2174
|
+
originalOuterHTML: string;
|
|
2175
|
+
startMarker: Comment;
|
|
2176
|
+
endMarker: Comment;
|
|
2177
|
+
currentElement: Element;
|
|
2178
|
+
selectedWasInside: boolean;
|
|
2179
|
+
hoveredWasInside: boolean;
|
|
2180
|
+
};
|
|
2181
|
+
var activeNodeHtmlPreview: NodeHtmlPreviewSession | null = null;
|
|
2171
2182
|
// Last element an "element-hover" message was actually posted for. Lets
|
|
2172
2183
|
// the shield's pointermove handler skip getLightElementInfo's two
|
|
2173
2184
|
// getComputedStyle calls plus the postMessage on every one of the dozens
|
|
@@ -5120,6 +5131,178 @@ declare var __RUNTIME_LAYER_SNAPSHOT_ENABLED__: boolean;
|
|
|
5120
5131
|
return null;
|
|
5121
5132
|
}
|
|
5122
5133
|
|
|
5134
|
+
function parseNodeHtmlPreviewElement(html: string): Element | null {
|
|
5135
|
+
var trimmed = html.trim();
|
|
5136
|
+
if (/^<body(?:\s|>)/i.test(trimmed)) {
|
|
5137
|
+
var parsedDocument = new DOMParser().parseFromString(
|
|
5138
|
+
"<!doctype html><html><head></head>" + trimmed + "</html>", // i18n-ignore parser scaffold
|
|
5139
|
+
"text/html",
|
|
5140
|
+
);
|
|
5141
|
+
return parsedDocument.body;
|
|
5142
|
+
}
|
|
5143
|
+
var template = document.createElement("template");
|
|
5144
|
+
template.innerHTML = html;
|
|
5145
|
+
var element = template.content.firstElementChild;
|
|
5146
|
+
if (!element || template.content.childElementCount !== 1) return null;
|
|
5147
|
+
for (
|
|
5148
|
+
var child = template.content.firstChild;
|
|
5149
|
+
child;
|
|
5150
|
+
child = child.nextSibling
|
|
5151
|
+
) {
|
|
5152
|
+
if (child === element) continue;
|
|
5153
|
+
if (child.nodeType !== 3 || String(child.textContent || "").trim()) {
|
|
5154
|
+
return null;
|
|
5155
|
+
}
|
|
5156
|
+
}
|
|
5157
|
+
return element;
|
|
5158
|
+
}
|
|
5159
|
+
|
|
5160
|
+
function resolveNodeHtmlPreviewTarget(target: unknown): Element | null {
|
|
5161
|
+
if (!target || typeof target !== "object") return null;
|
|
5162
|
+
var nodeId = (target as { nodeId?: unknown }).nodeId;
|
|
5163
|
+
if (typeof nodeId === "string" && nodeId) {
|
|
5164
|
+
try {
|
|
5165
|
+
var nodeMatch = document.querySelector(
|
|
5166
|
+
'[data-agent-native-node-id="' + escapeAttribute(nodeId) + '"]',
|
|
5167
|
+
);
|
|
5168
|
+
if (nodeMatch && !isLayerInteractionBlocked(nodeMatch)) {
|
|
5169
|
+
return nodeMatch;
|
|
5170
|
+
}
|
|
5171
|
+
} catch (_err) {}
|
|
5172
|
+
}
|
|
5173
|
+
var selector = (target as { selector?: unknown }).selector;
|
|
5174
|
+
if (typeof selector !== "string" || !selector) return null;
|
|
5175
|
+
try {
|
|
5176
|
+
var selectorMatch = document.querySelector(selector);
|
|
5177
|
+
return selectorMatch && !isLayerInteractionBlocked(selectorMatch)
|
|
5178
|
+
? selectorMatch
|
|
5179
|
+
: null;
|
|
5180
|
+
} catch (_err) {
|
|
5181
|
+
return null;
|
|
5182
|
+
}
|
|
5183
|
+
}
|
|
5184
|
+
|
|
5185
|
+
function postNodeHtmlPreviewApplied(proposalId: string): void {
|
|
5186
|
+
(window.parent as Window).postMessage(
|
|
5187
|
+
{
|
|
5188
|
+
type: "agent-native:node-html-preview-applied",
|
|
5189
|
+
proposalId: proposalId,
|
|
5190
|
+
},
|
|
5191
|
+
"*",
|
|
5192
|
+
);
|
|
5193
|
+
}
|
|
5194
|
+
|
|
5195
|
+
function replaceNodeHtmlPreviewElement(
|
|
5196
|
+
session: NodeHtmlPreviewSession,
|
|
5197
|
+
nextElement: Element,
|
|
5198
|
+
): boolean {
|
|
5199
|
+
var parent = session.startMarker.parentNode;
|
|
5200
|
+
if (!parent || session.endMarker.parentNode !== parent) return false;
|
|
5201
|
+
var cursor = session.startMarker.nextSibling;
|
|
5202
|
+
while (cursor && cursor !== session.endMarker) {
|
|
5203
|
+
var next = cursor.nextSibling;
|
|
5204
|
+
parent.removeChild(cursor);
|
|
5205
|
+
cursor = next;
|
|
5206
|
+
}
|
|
5207
|
+
if (cursor !== session.endMarker) return false;
|
|
5208
|
+
nextElement.setAttribute(
|
|
5209
|
+
"data-agent-native-node-rewrite-proposal",
|
|
5210
|
+
session.proposalId,
|
|
5211
|
+
);
|
|
5212
|
+
parent.insertBefore(nextElement, session.endMarker);
|
|
5213
|
+
session.currentElement = nextElement;
|
|
5214
|
+
if (session.selectedWasInside) selectedEl = nextElement;
|
|
5215
|
+
if (session.hoveredWasInside) hoveredEl = nextElement;
|
|
5216
|
+
refreshOverlays();
|
|
5217
|
+
return true;
|
|
5218
|
+
}
|
|
5219
|
+
|
|
5220
|
+
function restoreActiveNodeHtmlPreview(proposalId?: string): boolean {
|
|
5221
|
+
var session = activeNodeHtmlPreview;
|
|
5222
|
+
if (!session || (proposalId && session.proposalId !== proposalId)) {
|
|
5223
|
+
return false;
|
|
5224
|
+
}
|
|
5225
|
+
activeNodeHtmlPreview = null;
|
|
5226
|
+
var parent = session.startMarker.parentNode;
|
|
5227
|
+
if (!parent || session.endMarker.parentNode !== parent) return false;
|
|
5228
|
+
var cursor = session.startMarker.nextSibling;
|
|
5229
|
+
while (cursor && cursor !== session.endMarker) {
|
|
5230
|
+
var next = cursor.nextSibling;
|
|
5231
|
+
parent.removeChild(cursor);
|
|
5232
|
+
cursor = next;
|
|
5233
|
+
}
|
|
5234
|
+
if (cursor !== session.endMarker) return false;
|
|
5235
|
+
parent.insertBefore(session.originalElement, session.endMarker);
|
|
5236
|
+
parent.removeChild(session.startMarker);
|
|
5237
|
+
parent.removeChild(session.endMarker);
|
|
5238
|
+
if (session.selectedWasInside) selectedEl = session.originalElement;
|
|
5239
|
+
if (session.hoveredWasInside) hoveredEl = session.originalElement;
|
|
5240
|
+
refreshOverlays();
|
|
5241
|
+
return session.originalElement.outerHTML === session.originalOuterHTML;
|
|
5242
|
+
}
|
|
5243
|
+
|
|
5244
|
+
function applyNodeHtmlPreview(data: {
|
|
5245
|
+
proposalId?: unknown;
|
|
5246
|
+
target?: unknown;
|
|
5247
|
+
html?: unknown;
|
|
5248
|
+
}): void {
|
|
5249
|
+
var proposalId = data.proposalId;
|
|
5250
|
+
if (
|
|
5251
|
+
typeof proposalId !== "string" ||
|
|
5252
|
+
!proposalId ||
|
|
5253
|
+
typeof data.html !== "string"
|
|
5254
|
+
) {
|
|
5255
|
+
return;
|
|
5256
|
+
}
|
|
5257
|
+
var nextElement = parseNodeHtmlPreviewElement(data.html);
|
|
5258
|
+
if (!nextElement) return;
|
|
5259
|
+
if (
|
|
5260
|
+
activeNodeHtmlPreview &&
|
|
5261
|
+
activeNodeHtmlPreview.proposalId === proposalId
|
|
5262
|
+
) {
|
|
5263
|
+
if (replaceNodeHtmlPreviewElement(activeNodeHtmlPreview, nextElement)) {
|
|
5264
|
+
postNodeHtmlPreviewApplied(proposalId);
|
|
5265
|
+
}
|
|
5266
|
+
return;
|
|
5267
|
+
}
|
|
5268
|
+
if (activeNodeHtmlPreview) restoreActiveNodeHtmlPreview();
|
|
5269
|
+
var target = resolveNodeHtmlPreviewTarget(data.target);
|
|
5270
|
+
if (!target || !target.parentNode || target === document.documentElement) {
|
|
5271
|
+
return;
|
|
5272
|
+
}
|
|
5273
|
+
var originalOuterHTML = target.outerHTML;
|
|
5274
|
+
nextElement.setAttribute(
|
|
5275
|
+
"data-agent-native-node-rewrite-proposal",
|
|
5276
|
+
proposalId,
|
|
5277
|
+
);
|
|
5278
|
+
var startMarker = document.createComment(
|
|
5279
|
+
"agent-native:node-html-preview:start",
|
|
5280
|
+
);
|
|
5281
|
+
var endMarker = document.createComment(
|
|
5282
|
+
"agent-native:node-html-preview:end",
|
|
5283
|
+
);
|
|
5284
|
+
var parent = target.parentNode;
|
|
5285
|
+
var selectedWasInside = !!selectedEl && target.contains(selectedEl);
|
|
5286
|
+
var hoveredWasInside = !!hoveredEl && target.contains(hoveredEl);
|
|
5287
|
+
parent.insertBefore(startMarker, target);
|
|
5288
|
+
parent.insertBefore(endMarker, target.nextSibling);
|
|
5289
|
+
parent.replaceChild(nextElement, target);
|
|
5290
|
+
activeNodeHtmlPreview = {
|
|
5291
|
+
proposalId: proposalId,
|
|
5292
|
+
originalElement: target,
|
|
5293
|
+
originalOuterHTML: originalOuterHTML,
|
|
5294
|
+
startMarker: startMarker,
|
|
5295
|
+
endMarker: endMarker,
|
|
5296
|
+
currentElement: nextElement,
|
|
5297
|
+
selectedWasInside: selectedWasInside,
|
|
5298
|
+
hoveredWasInside: hoveredWasInside,
|
|
5299
|
+
};
|
|
5300
|
+
if (selectedWasInside) selectedEl = nextElement;
|
|
5301
|
+
if (hoveredWasInside) hoveredEl = nextElement;
|
|
5302
|
+
refreshOverlays();
|
|
5303
|
+
postNodeHtmlPreviewApplied(proposalId);
|
|
5304
|
+
}
|
|
5305
|
+
|
|
5123
5306
|
// Host-driven Layers-panel moves must never inherit findRuntimeTarget's
|
|
5124
5307
|
// selected-element shortcut or first-match querySelector behavior. Runtime
|
|
5125
5308
|
// React trees routinely repeat classes and component markup, so a selector
|
|
@@ -11070,6 +11253,7 @@ declare var __RUNTIME_LAYER_SNAPSHOT_ENABLED__: boolean;
|
|
|
11070
11253
|
return;
|
|
11071
11254
|
}
|
|
11072
11255
|
if (e.data.type === "replace-document-content") {
|
|
11256
|
+
activeNodeHtmlPreview = null;
|
|
11073
11257
|
replaceRuntimeDocument(
|
|
11074
11258
|
e.data.content,
|
|
11075
11259
|
e.data.forceFullDocument ? "" : e.data.selectedSelector,
|
|
@@ -11079,6 +11263,16 @@ declare var __RUNTIME_LAYER_SNAPSHOT_ENABLED__: boolean;
|
|
|
11079
11263
|
);
|
|
11080
11264
|
return;
|
|
11081
11265
|
}
|
|
11266
|
+
if (e.data.type === "node-html-preview") {
|
|
11267
|
+
if (e.data.operation === "restore") {
|
|
11268
|
+
if (typeof e.data.proposalId === "string") {
|
|
11269
|
+
restoreActiveNodeHtmlPreview(e.data.proposalId);
|
|
11270
|
+
}
|
|
11271
|
+
} else if (e.data.operation === "preview") {
|
|
11272
|
+
applyNodeHtmlPreview(e.data);
|
|
11273
|
+
}
|
|
11274
|
+
return;
|
|
11275
|
+
}
|
|
11082
11276
|
if (e.data.type === "delete-element") {
|
|
11083
11277
|
removeRuntimeTarget(e.data.selector, e.data.selectorCandidates);
|
|
11084
11278
|
return;
|
|
@@ -739,9 +739,20 @@
|
|
|
739
739
|
): Element | null {
|
|
740
740
|
var element = elementFromEditorPoint(clientX, clientY);
|
|
741
741
|
if (!element) return null;
|
|
742
|
-
|
|
742
|
+
var identifiedAncestor = element.closest(
|
|
743
743
|
"[data-agent-native-node-id],[data-code-layer-id],[data-layer-id],[data-builder-id],[id]",
|
|
744
744
|
);
|
|
745
|
+
if (
|
|
746
|
+
identifiedAncestor &&
|
|
747
|
+
identifiedAncestor !== document.body &&
|
|
748
|
+
identifiedAncestor !== document.documentElement
|
|
749
|
+
) {
|
|
750
|
+
return identifiedAncestor;
|
|
751
|
+
}
|
|
752
|
+
if (element === document.body || element === document.documentElement) {
|
|
753
|
+
return null;
|
|
754
|
+
}
|
|
755
|
+
return element;
|
|
745
756
|
}
|
|
746
757
|
|
|
747
758
|
function reviewNodeElements(nodeIds: string[]): Record<string, Element> {
|
|
@@ -808,14 +819,20 @@
|
|
|
808
819
|
reviewPointX,
|
|
809
820
|
reviewPointY,
|
|
810
821
|
);
|
|
822
|
+
var reviewPointNodeId = reviewPointElement
|
|
823
|
+
? getNodeId(reviewPointElement)
|
|
824
|
+
: "";
|
|
825
|
+
var reviewPointSelector =
|
|
826
|
+
reviewPointElement && !reviewPointNodeId
|
|
827
|
+
? buildSourceEquivalentSelector(reviewPointElement)
|
|
828
|
+
: "";
|
|
811
829
|
try {
|
|
812
830
|
(window.parent as Window).postMessage(
|
|
813
831
|
{
|
|
814
832
|
type: "agent-native:review-anchor-at-point-result",
|
|
815
833
|
correlationId: reviewPointCorrelationId,
|
|
816
|
-
nodeId:
|
|
817
|
-
|
|
818
|
-
: undefined,
|
|
834
|
+
nodeId: reviewPointNodeId || undefined,
|
|
835
|
+
targetSelector: reviewPointSelector || undefined,
|
|
819
836
|
layerName:
|
|
820
837
|
reviewPointElement?.getAttribute(
|
|
821
838
|
"data-agent-native-layer-name",
|
|
@@ -23,3 +23,21 @@ export interface IframeContextMenuPayload {
|
|
|
23
23
|
info?: ElementInfo | null;
|
|
24
24
|
layerCandidates?: CanvasLayerHitCandidate[];
|
|
25
25
|
}
|
|
26
|
+
|
|
27
|
+
export interface IframeNodeHtmlPreviewTarget {
|
|
28
|
+
nodeId?: string;
|
|
29
|
+
selector?: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface IframeNodeHtmlPreviewMessage {
|
|
33
|
+
type: "node-html-preview";
|
|
34
|
+
proposalId: string;
|
|
35
|
+
target: IframeNodeHtmlPreviewTarget;
|
|
36
|
+
operation: "preview" | "restore";
|
|
37
|
+
html?: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface IframeNodeHtmlPreviewAppliedPayload {
|
|
41
|
+
type: "agent-native:node-html-preview-applied";
|
|
42
|
+
proposalId: string;
|
|
43
|
+
}
|
|
@@ -130,6 +130,10 @@ export interface MultiScreenCanvasProps {
|
|
|
130
130
|
* transformed directly from the overview canvas. */
|
|
131
131
|
lockedScreenIds?: ReadonlySet<string> | readonly string[];
|
|
132
132
|
fullViewScreenIds?: string[];
|
|
133
|
+
/** Screens with generated candidates waiting for explicit review. */
|
|
134
|
+
pendingReviewScreenIds?: ReadonlySet<string> | readonly string[];
|
|
135
|
+
/** Opens candidate review for one pending screen. */
|
|
136
|
+
onReviewPendingScreen?: (screenId: string) => void;
|
|
133
137
|
/** Lets every live frame receive native pointer interaction while the
|
|
134
138
|
* overview camera and frame chrome remain available. */
|
|
135
139
|
interactMode?: boolean;
|