@agent-native/core 0.163.4 → 0.164.3

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.
Files changed (228) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/app/components/agents/FeatureFlagsFleetPanel.tsx +78 -19
  3. package/corpus/templates/analytics/app/hooks/use-dashboard-chat-context.ts +29 -0
  4. package/corpus/templates/analytics/app/lib/use-auto-focus-select.ts +4 -4
  5. package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/index.tsx +3 -0
  6. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +6 -0
  7. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +1 -2
  8. package/corpus/templates/analytics/app/routes/_index.tsx +3 -2
  9. package/corpus/templates/analytics/app/routes/adhoc.$id.tsx +7 -2
  10. package/corpus/templates/analytics/app/routes/dashboard.tsx +3 -2
  11. package/corpus/templates/analytics/app/routes/overview.tsx +3 -2
  12. package/corpus/templates/analytics/app/routes/traffic.tsx +3 -2
  13. package/corpus/templates/analytics/changelog/2026-08-18-verify-cross-app-feature-flag-changes.md +6 -0
  14. package/corpus/templates/analytics/netlify.toml +2 -0
  15. package/corpus/templates/analytics/server/lib/workspace-feature-flags.ts +196 -48
  16. package/corpus/templates/analytics/server/plugins/feature-flags.ts +5 -0
  17. package/corpus/templates/analytics/shared/feature-flags.ts +10 -0
  18. package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +5 -1
  19. package/corpus/templates/assets/app/routes/brand-kits._index.tsx +4 -1
  20. package/corpus/templates/assets/app/routes/libraries.tsx +4 -1
  21. package/corpus/templates/assets/app/routes/picker.tsx +4 -1
  22. package/corpus/templates/assets/netlify.toml +2 -0
  23. package/corpus/templates/brain/netlify.toml +2 -0
  24. package/corpus/templates/calendar/app/components/calendar/DayView.tsx +2 -1
  25. package/corpus/templates/calendar/changelog/2026-08-19-calendar-page-loads-stay-fast-after-idle-periods.md +6 -0
  26. package/corpus/templates/calendar/netlify.toml +2 -0
  27. package/corpus/templates/chat/netlify.toml +2 -0
  28. package/corpus/templates/clips/app/components/player/player-controls.tsx +3 -3
  29. package/corpus/templates/clips/app/components/player/reaction-emojis.ts +12 -0
  30. package/corpus/templates/clips/app/components/player/reactions-tray.tsx +90 -9
  31. package/corpus/templates/clips/app/components/player/scrubber.tsx +43 -10
  32. package/corpus/templates/clips/app/components/player/video-player.tsx +105 -15
  33. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +1 -2
  34. package/corpus/templates/clips/app/routes/_app.wispr.tsx +2 -1
  35. package/corpus/templates/clips/app/routes/_index.tsx +7 -3
  36. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +13 -8
  37. package/corpus/templates/clips/app/routes/share.$shareId.tsx +15 -8
  38. package/corpus/templates/clips/netlify.toml +2 -0
  39. package/corpus/templates/clips/server/routes/[...page].head.ts +5 -0
  40. package/corpus/templates/content/netlify.toml +2 -0
  41. package/corpus/templates/design/.agents/skills/design-editor-architecture/SKILL.md +103 -0
  42. package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +2 -1
  43. package/corpus/templates/design/AGENTS.md +3 -1
  44. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +3 -2
  45. package/corpus/templates/design/app/components/design/editor/AgentNativeMenuMark.tsx +25 -0
  46. package/corpus/templates/design/app/components/design/editor/DesignBottomToolbar.tsx +411 -0
  47. package/corpus/templates/design/app/components/design/editor/DesignCollaborators.tsx +153 -0
  48. package/corpus/templates/design/app/components/design/editor/DesignWorkspaceRail.tsx +231 -0
  49. package/corpus/templates/design/app/components/design/editor/MakeRealDialog.tsx +223 -0
  50. package/corpus/templates/design/app/components/design/editor/PendingScreenDeletionDialog.tsx +58 -0
  51. package/corpus/templates/design/app/components/design/editor/PendingVisualStyleWarningDialog.tsx +56 -0
  52. package/corpus/templates/design/app/components/design/editor/ReadOnlyEditorPanel.tsx +23 -0
  53. package/corpus/templates/design/app/components/design/editor/SaveTemplateDialog.tsx +161 -0
  54. package/corpus/templates/design/app/components/design/editor/toolbar-controls.tsx +185 -0
  55. package/corpus/templates/design/app/pages/DesignEditor.tsx +20913 -0
  56. package/corpus/templates/design/app/pages/design-editor/command-types.ts +120 -0
  57. package/corpus/templates/design/app/pages/design-editor/commands/README.md +193 -0
  58. package/corpus/templates/design/app/pages/design-editor/commands/add-auto-layout.ts +416 -0
  59. package/corpus/templates/design/app/pages/design-editor/commands/add-screen.ts +112 -0
  60. package/corpus/templates/design/app/pages/design-editor/commands/align-selection.ts +183 -0
  61. package/corpus/templates/design/app/pages/design-editor/commands/apply-design-editor-command.ts +243 -0
  62. package/corpus/templates/design/app/pages/design-editor/commands/apply-file-content-update.ts +236 -0
  63. package/corpus/templates/design/app/pages/design-editor/commands/apply-local-content-update.ts +304 -0
  64. package/corpus/templates/design/app/pages/design-editor/commands/apply-pending-visual-styles-with-agent.ts +376 -0
  65. package/corpus/templates/design/app/pages/design-editor/commands/apply-to-source.ts +132 -0
  66. package/corpus/templates/design/app/pages/design-editor/commands/can-move-layer.ts +117 -0
  67. package/corpus/templates/design/app/pages/design-editor/commands/change-selected-z-index.ts +212 -0
  68. package/corpus/templates/design/app/pages/design-editor/commands/commit-relative-style-delta-to-selected-layers.ts +176 -0
  69. package/corpus/templates/design/app/pages/design-editor/commands/commit-styles-to-selected-layers.ts +175 -0
  70. package/corpus/templates/design/app/pages/design-editor/commands/commit-visual-styles.ts +710 -0
  71. package/corpus/templates/design/app/pages/design-editor/commands/confirm-make-real.ts +99 -0
  72. package/corpus/templates/design/app/pages/design-editor/commands/copy-as-figma-svg.ts +95 -0
  73. package/corpus/templates/design/app/pages/design-editor/commands/copy-selection.ts +156 -0
  74. package/corpus/templates/design/app/pages/design-editor/commands/create-primitive.ts +291 -0
  75. package/corpus/templates/design/app/pages/design-editor/commands/create-screen-frame.ts +131 -0
  76. package/corpus/templates/design/app/pages/design-editor/commands/cross-screen-element-drop.ts +577 -0
  77. package/corpus/templates/design/app/pages/design-editor/commands/delete-files.ts +364 -0
  78. package/corpus/templates/design/app/pages/design-editor/commands/delete-selection.ts +521 -0
  79. package/corpus/templates/design/app/pages/design-editor/commands/detach-instance-menu-action.ts +88 -0
  80. package/corpus/templates/design/app/pages/design-editor/commands/distribute-selection.ts +114 -0
  81. package/corpus/templates/design/app/pages/design-editor/commands/download-all-screens-pdf.ts +116 -0
  82. package/corpus/templates/design/app/pages/design-editor/commands/download-pdf.ts +103 -0
  83. package/corpus/templates/design/app/pages/design-editor/commands/download-svg.ts +159 -0
  84. package/corpus/templates/design/app/pages/design-editor/commands/duplicate-screen.ts +201 -0
  85. package/corpus/templates/design/app/pages/design-editor/commands/duplicate-selection.ts +279 -0
  86. package/corpus/templates/design/app/pages/design-editor/commands/editor-paste.ts +81 -0
  87. package/corpus/templates/design/app/pages/design-editor/commands/enter-hotkey.ts +155 -0
  88. package/corpus/templates/design/app/pages/design-editor/commands/enter-single-screen.ts +168 -0
  89. package/corpus/templates/design/app/pages/design-editor/commands/escape-hotkey.ts +212 -0
  90. package/corpus/templates/design/app/pages/design-editor/commands/frame-selection.ts +119 -0
  91. package/corpus/templates/design/app/pages/design-editor/commands/geometry-commit.ts +169 -0
  92. package/corpus/templates/design/app/pages/design-editor/commands/get-selected-layer-snapshots.ts +177 -0
  93. package/corpus/templates/design/app/pages/design-editor/commands/group-selection.ts +127 -0
  94. package/corpus/templates/design/app/pages/design-editor/commands/iframe-context-menu.ts +121 -0
  95. package/corpus/templates/design/app/pages/design-editor/commands/import-figma-clipboard-into-design.ts +119 -0
  96. package/corpus/templates/design/app/pages/design-editor/commands/layer-marquee-selection-change.ts +163 -0
  97. package/corpus/templates/design/app/pages/design-editor/commands/layer-move-to-screen.ts +331 -0
  98. package/corpus/templates/design/app/pages/design-editor/commands/layer-move.ts +517 -0
  99. package/corpus/templates/design/app/pages/design-editor/commands/layer-rename.ts +247 -0
  100. package/corpus/templates/design/app/pages/design-editor/commands/layer-selection-change.ts +161 -0
  101. package/corpus/templates/design/app/pages/design-editor/commands/mode-change.ts +122 -0
  102. package/corpus/templates/design/app/pages/design-editor/commands/nudge-selection.ts +213 -0
  103. package/corpus/templates/design/app/pages/design-editor/commands/overview-primitive-reparent.ts +318 -0
  104. package/corpus/templates/design/app/pages/design-editor/commands/paste-copied-screens.ts +114 -0
  105. package/corpus/templates/design/app/pages/design-editor/commands/paste-over-selection.ts +70 -0
  106. package/corpus/templates/design/app/pages/design-editor/commands/paste-selection.ts +436 -0
  107. package/corpus/templates/design/app/pages/design-editor/commands/paste-to-replace.ts +135 -0
  108. package/corpus/templates/design/app/pages/design-editor/commands/pasted-image-files.ts +209 -0
  109. package/corpus/templates/design/app/pages/design-editor/commands/persist-frame-geometry-save.ts +113 -0
  110. package/corpus/templates/design/app/pages/design-editor/commands/persist-tweak-save.ts +160 -0
  111. package/corpus/templates/design/app/pages/design-editor/commands/primitive-created.ts +168 -0
  112. package/corpus/templates/design/app/pages/design-editor/commands/record-pending-live-layer-state-edit.ts +149 -0
  113. package/corpus/templates/design/app/pages/design-editor/commands/record-pending-live-structure-edit.ts +200 -0
  114. package/corpus/templates/design/app/pages/design-editor/commands/record-pending-live-text-edit.ts +152 -0
  115. package/corpus/templates/design/app/pages/design-editor/commands/record-pending-visual-style-edit.ts +247 -0
  116. package/corpus/templates/design/app/pages/design-editor/commands/redo.ts +1086 -0
  117. package/corpus/templates/design/app/pages/design-editor/commands/render-png-blob.ts +200 -0
  118. package/corpus/templates/design/app/pages/design-editor/commands/save-file-content.ts +207 -0
  119. package/corpus/templates/design/app/pages/design-editor/commands/screen-element-select.ts +262 -0
  120. package/corpus/templates/design/app/pages/design-editor/commands/screen-text-content-change.ts +216 -0
  121. package/corpus/templates/design/app/pages/design-editor/commands/screen-visual-duplicate-change.ts +108 -0
  122. package/corpus/templates/design/app/pages/design-editor/commands/screen-visual-structure-change.ts +280 -0
  123. package/corpus/templates/design/app/pages/design-editor/commands/screen-visual-style-change.ts +151 -0
  124. package/corpus/templates/design/app/pages/design-editor/commands/send-overview-annotations.ts +88 -0
  125. package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-move-semantic-handoff.ts +122 -0
  126. package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-semantic-handoff.ts +143 -0
  127. package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-state-semantic-handoff.ts +115 -0
  128. package/corpus/templates/design/app/pages/design-editor/commands/start-retry-generation.ts +152 -0
  129. package/corpus/templates/design/app/pages/design-editor/commands/start-sidebar-resize.ts +99 -0
  130. package/corpus/templates/design/app/pages/design-editor/commands/style-change.ts +152 -0
  131. package/corpus/templates/design/app/pages/design-editor/commands/styles-change.ts +155 -0
  132. package/corpus/templates/design/app/pages/design-editor/commands/suggest-auto-layout.ts +125 -0
  133. package/corpus/templates/design/app/pages/design-editor/commands/text-content-change.ts +201 -0
  134. package/corpus/templates/design/app/pages/design-editor/commands/tidy-up.ts +123 -0
  135. package/corpus/templates/design/app/pages/design-editor/commands/toggle-layer-hidden.ts +167 -0
  136. package/corpus/templates/design/app/pages/design-editor/commands/toggle-layer-locked.ts +175 -0
  137. package/corpus/templates/design/app/pages/design-editor/commands/toggle-motion-keyframe.ts +99 -0
  138. package/corpus/templates/design/app/pages/design-editor/commands/tweak-prompt-submit.ts +84 -0
  139. package/corpus/templates/design/app/pages/design-editor/commands/undo.ts +906 -0
  140. package/corpus/templates/design/app/pages/design-editor/commands/ungroup-selection.ts +170 -0
  141. package/corpus/templates/design/app/pages/design-editor/commands/visual-duplicate-change.ts +119 -0
  142. package/corpus/templates/design/app/pages/design-editor/commands/visual-structure-change.ts +274 -0
  143. package/corpus/templates/design/app/pages/design-editor/commands/write-frame-geometry-snapshot.ts +99 -0
  144. package/corpus/templates/design/app/pages/design-editor/derive/design-breakpoints.ts +56 -0
  145. package/corpus/templates/design/app/pages/design-editor/derive/overview-screens.ts +146 -0
  146. package/corpus/templates/design/app/pages/design-editor/domains/use-tweaks.ts +326 -0
  147. package/corpus/templates/design/app/pages/design-editor/editor-constants.ts +54 -0
  148. package/corpus/templates/design/app/pages/design-editor/editor-helpers.ts +183 -0
  149. package/corpus/templates/design/app/pages/design-editor/effects/adopt-db-file-content.ts +270 -0
  150. package/corpus/templates/design/app/pages/design-editor/effects/mirror-selection-to-agent-chat.ts +134 -0
  151. package/corpus/templates/design/app/pages/design-editor/effects/motion-autosave.ts +335 -0
  152. package/corpus/templates/design/app/pages/design-editor/effects/observe-collab-text.ts +183 -0
  153. package/corpus/templates/design/app/pages/design-editor/effects/publish-agent-selection-context.ts +252 -0
  154. package/corpus/templates/design/app/pages/design-editor/effects/resume-pending-generation.ts +178 -0
  155. package/corpus/templates/design/app/pages/design-editor/effects/seed-collab-content.ts +157 -0
  156. package/corpus/templates/design/app/pages/design-editor/preview-html.ts +19 -0
  157. package/corpus/templates/design/app/routes/examples.tsx +2 -1
  158. package/corpus/templates/design/netlify.toml +2 -0
  159. package/corpus/templates/design/shared/board-file.ts +2 -1
  160. package/corpus/templates/dispatch/netlify.toml +2 -0
  161. package/corpus/templates/forms/app/routes/_index.tsx +3 -2
  162. package/corpus/templates/forms/netlify.toml +2 -0
  163. package/corpus/templates/mail/app/routes/_index.tsx +3 -2
  164. package/corpus/templates/mail/netlify.toml +2 -0
  165. package/corpus/templates/plan/netlify.toml +2 -0
  166. package/corpus/templates/slides/netlify.toml +2 -0
  167. package/corpus/templates/tasks/app/routes/_index.tsx +2 -1
  168. package/dist/agent/engine/builder-engine.d.ts +6 -4
  169. package/dist/agent/engine/builder-engine.js +91 -26
  170. package/dist/agent/engine/registry.js +16 -0
  171. package/dist/cli/code-agent-agent-tools.d.ts +2 -0
  172. package/dist/cli/code-agent-agent-tools.js +188 -0
  173. package/dist/cli/code-agent-collaboration.d.ts +34 -0
  174. package/dist/cli/code-agent-collaboration.js +104 -0
  175. package/dist/cli/code-agent-executor.js +6 -0
  176. package/dist/cli/code-agent-schedules.d.ts +54 -0
  177. package/dist/cli/code-agent-schedules.js +198 -0
  178. package/dist/client/AgentPanel.js +1 -1
  179. package/dist/client/ConnectBuilderCard.js +5 -2
  180. package/dist/client/EnvironmentBadge.js +6 -5
  181. package/dist/client/chat/run-recovery.js +3 -2
  182. package/dist/client/chat/tool-call-display.js +2 -3
  183. package/dist/client/components/CodeRequiredDialog.js +4 -2
  184. package/dist/client/i18n.js +5 -4
  185. package/dist/client/settings/SettingsPanel.js +1 -1
  186. package/dist/client/settings/VoiceTranscriptionSection.js +1 -1
  187. package/dist/client/settings/useBuilderStatus.d.ts +6 -1
  188. package/dist/client/settings/useBuilderStatus.js +22 -33
  189. package/dist/client/transcription/BuilderTranscriptionCta.js +1 -1
  190. package/dist/code-agents/index.d.ts +2 -0
  191. package/dist/code-agents/index.js +2 -0
  192. package/dist/collab/awareness.d.ts +2 -2
  193. package/dist/collab/routes.d.ts +1 -1
  194. package/dist/deploy/build.js +10 -4
  195. package/dist/localization/shared.d.ts +2 -0
  196. package/dist/localization/shared.js +5 -0
  197. package/dist/mcp-client/oauth-client.d.ts +1 -0
  198. package/dist/mcp-client/oauth-client.js +50 -1
  199. package/dist/notifications/routes.d.ts +3 -3
  200. package/dist/observability/routes.d.ts +1 -1
  201. package/dist/provider-api/actions/provider-api.d.ts +2 -2
  202. package/dist/server/auth-marketing-locales.d.ts +7 -0
  203. package/dist/server/auth-marketing-locales.js +1322 -0
  204. package/dist/server/auth-marketing.d.ts +1 -0
  205. package/dist/server/auth-marketing.js +35 -6
  206. package/dist/server/auth.js +4 -17
  207. package/dist/server/builder-browser.d.ts +22 -0
  208. package/dist/server/builder-browser.js +77 -1
  209. package/dist/server/builder-oauth.d.ts +50 -0
  210. package/dist/server/builder-oauth.js +263 -0
  211. package/dist/server/core-routes-plugin.d.ts +11 -0
  212. package/dist/server/core-routes-plugin.js +291 -415
  213. package/dist/server/credential-provider.d.ts +1 -1
  214. package/dist/server/credential-provider.js +1 -1
  215. package/dist/server/csrf.js +2 -2
  216. package/dist/server/onboarding-html.js +52 -120
  217. package/dist/server/ssr-handler.js +13 -4
  218. package/dist/settings/store.d.ts +9 -0
  219. package/dist/settings/store.js +19 -0
  220. package/dist/shared/cache-control.d.ts +22 -0
  221. package/dist/shared/cache-control.js +25 -0
  222. package/dist/shared/index.d.ts +1 -0
  223. package/dist/shared/index.js +1 -0
  224. package/dist/templates/chat/netlify.toml +2 -0
  225. package/docs/content/deployment.mdx +2 -0
  226. package/docs/content/multi-app-workspace.mdx +1 -1
  227. package/package.json +2 -2
  228. package/src/templates/chat/netlify.toml +2 -0
@@ -0,0 +1,364 @@
1
+ import { useActionMutation } from "@agent-native/core/client/hooks";
2
+ import type { CanvasFrameGeometryById } from "@shared/canvas-frames";
3
+ import type { QueryClient } from "@tanstack/react-query";
4
+ import type { Dispatch, RefObject, SetStateAction } from "react";
5
+ import { toast } from "sonner";
6
+
7
+ import type { ElementInfo } from "@/components/design/types";
8
+ import type { ClipboardContentLineage } from "@/lib/clipboard-content-lineage";
9
+ import { cloneCanvasFrameGeometry } from "@/pages/design-editor/design-data-geometry-utils";
10
+ import type { UndoRedoOrderKind } from "@/pages/design-editor/editor-state";
11
+ import type {
12
+ ContentHistoryChange,
13
+ ContentHistoryEntry,
14
+ FileCreationHistoryEntry,
15
+ FileDeletionHistoryEntry,
16
+ GeometryHistoryEntry,
17
+ GeometryHistorySelection,
18
+ } from "@/pages/design-editor/history";
19
+ import {
20
+ MAX_DESIGN_UNDO_STACK,
21
+ filterFileDeletionHistoryEntry,
22
+ getContentHistoryChanges,
23
+ pruneFileCreationHistoryStack,
24
+ pruneGeometryHistoryEntryForDeletedFiles,
25
+ removeRecentUndoRedoOrderKinds,
26
+ } from "@/pages/design-editor/history";
27
+ import type { DesignFile } from "@/pages/design-editor/types";
28
+
29
+ export interface DeleteFilesArgs {
30
+ activeFile: DesignFile;
31
+ canvasFrameGeometryById: CanvasFrameGeometryById;
32
+ clearRedoStacks: () => void;
33
+ clipboardPasteRedoStackRef: RefObject<ContentHistoryChange[]>;
34
+ clipboardPasteUndoStackRef: RefObject<ContentHistoryChange[]>;
35
+ contentRedoSelectionStackRef: RefObject<
36
+ (GeometryHistorySelection | undefined)[]
37
+ >;
38
+ contentRedoStackRef: RefObject<ContentHistoryEntry[]>;
39
+ contentUndoSelectionStackRef: RefObject<
40
+ (GeometryHistorySelection | undefined)[]
41
+ >;
42
+ contentUndoStackRef: RefObject<ContentHistoryEntry[]>;
43
+ deleteFileMutation: ReturnType<
44
+ typeof useActionMutation<undefined, undefined, "delete-file">
45
+ >;
46
+ fileCreationRedoStackRef: RefObject<FileCreationHistoryEntry[]>;
47
+ fileCreationUndoStackRef: RefObject<FileCreationHistoryEntry[]>;
48
+ fileDeletionUndoStackRef: RefObject<FileDeletionHistoryEntry[]>;
49
+ fileHistoryMutationPendingRef: RefObject<boolean>;
50
+ files: DesignFile[];
51
+ geometryRedoStackRef: RefObject<GeometryHistoryEntry[]>;
52
+ geometryUndoStackRef: RefObject<GeometryHistoryEntry[]>;
53
+ historyOrderRef: RefObject<UndoRedoOrderKind[]>;
54
+ id: string | undefined;
55
+ latestClipboardMutationContentRef: RefObject<
56
+ Map<string, ClipboardContentLineage>
57
+ >;
58
+ localContentRedoStackRef: RefObject<ContentHistoryChange[]>;
59
+ localContentUndoStackRef: RefObject<ContentHistoryChange[]>;
60
+ queryClient: QueryClient;
61
+ redoOrderRef: RefObject<UndoRedoOrderKind[]>;
62
+ setActiveFileId: Dispatch<SetStateAction<string | null>>;
63
+ setSelectedElement: Dispatch<SetStateAction<ElementInfo | null>>;
64
+ setSelectedLayerIdsState: Dispatch<SetStateAction<string[]>>;
65
+ syncUndoRedoState: () => void;
66
+ t: (key: string, options?: Record<string, unknown>) => string;
67
+ writeFrameGeometrySnapshot: (
68
+ geometryById: CanvasFrameGeometryById,
69
+ options?: { syncViewportFrameIds?: string[]; pinHeightFrameIds?: string[] },
70
+ ) => void;
71
+ }
72
+
73
+ export function runDeleteFiles(
74
+ {
75
+ activeFile,
76
+ canvasFrameGeometryById,
77
+ clearRedoStacks,
78
+ clipboardPasteRedoStackRef,
79
+ clipboardPasteUndoStackRef,
80
+ contentRedoSelectionStackRef,
81
+ contentRedoStackRef,
82
+ contentUndoSelectionStackRef,
83
+ contentUndoStackRef,
84
+ deleteFileMutation,
85
+ fileCreationRedoStackRef,
86
+ fileCreationUndoStackRef,
87
+ fileDeletionUndoStackRef,
88
+ fileHistoryMutationPendingRef,
89
+ files,
90
+ geometryRedoStackRef,
91
+ geometryUndoStackRef,
92
+ historyOrderRef,
93
+ id,
94
+ latestClipboardMutationContentRef,
95
+ localContentRedoStackRef,
96
+ localContentUndoStackRef,
97
+ queryClient,
98
+ redoOrderRef,
99
+ setActiveFileId,
100
+ setSelectedElement,
101
+ setSelectedLayerIdsState,
102
+ syncUndoRedoState,
103
+ t,
104
+ writeFrameGeometrySnapshot,
105
+ }: DeleteFilesArgs,
106
+ filesToDelete: DesignFile[],
107
+ options?: {
108
+ // U12 fix: undoFileCreation pushes the just-undone create onto the
109
+ // file-creation REDO stack, then calls this function to soft-delete
110
+ // the same file it just pushed for. Without this flag the filename-
111
+ // keyed prune below (which exists to drop a redo entry when its file
112
+ // is hard-deleted directly, NOT via undo) would immediately remove
113
+ // the entry undoFileCreation just pushed, leaving redo permanently
114
+ // empty after every screen-create/duplicate undo.
115
+ skipFileCreationRedoPrune?: boolean;
116
+ // A user-confirmed screen deletion is a normal editor operation, not
117
+ // an irreversible special case. Capture the complete rows + frame
118
+ // geometry and add one grouped undo entry after every delete succeeds.
119
+ recordDeletionHistory?: boolean;
120
+ onMutationSettled?: (
121
+ deletedFiles: DesignFile[],
122
+ failedFiles: DesignFile[],
123
+ ) => void;
124
+ },
125
+ ) {
126
+ if (!filesToDelete.length) return;
127
+ const deleteIds = new Set(filesToDelete.map((file) => file.id));
128
+ const nextActiveFile = files.find((file) => !deleteIds.has(file.id));
129
+ const nextGeometry = cloneCanvasFrameGeometry(canvasFrameGeometryById);
130
+ const deletionHistoryEntry: FileDeletionHistoryEntry | null =
131
+ options?.recordDeletionHistory
132
+ ? {
133
+ files: filesToDelete.map((file) => ({
134
+ ...file,
135
+ geometry: canvasFrameGeometryById[file.id],
136
+ })),
137
+ }
138
+ : null;
139
+ if (deletionHistoryEntry) {
140
+ clearRedoStacks();
141
+ fileHistoryMutationPendingRef.current = true;
142
+ syncUndoRedoState();
143
+ }
144
+ filesToDelete.forEach((file) => {
145
+ delete nextGeometry[file.id];
146
+ });
147
+
148
+ const nextGeometryUndoStack: GeometryHistoryEntry[] = [];
149
+ let removedGeometryUndoEntries = 0;
150
+ geometryUndoStackRef.current.forEach((entry) => {
151
+ const pruned = pruneGeometryHistoryEntryForDeletedFiles(entry, deleteIds);
152
+ if (!pruned) {
153
+ removedGeometryUndoEntries += 1;
154
+ return;
155
+ }
156
+ nextGeometryUndoStack.push(pruned);
157
+ });
158
+ geometryUndoStackRef.current = nextGeometryUndoStack;
159
+ historyOrderRef.current = removeRecentUndoRedoOrderKinds(
160
+ historyOrderRef.current,
161
+ "geometry",
162
+ removedGeometryUndoEntries,
163
+ );
164
+
165
+ const nextGeometryRedoStack: GeometryHistoryEntry[] = [];
166
+ let removedGeometryRedoEntries = 0;
167
+ geometryRedoStackRef.current.forEach((entry) => {
168
+ const pruned = pruneGeometryHistoryEntryForDeletedFiles(entry, deleteIds);
169
+ if (!pruned) {
170
+ removedGeometryRedoEntries += 1;
171
+ return;
172
+ }
173
+ nextGeometryRedoStack.push(pruned);
174
+ });
175
+ geometryRedoStackRef.current = nextGeometryRedoStack;
176
+ redoOrderRef.current = removeRecentUndoRedoOrderKinds(
177
+ redoOrderRef.current,
178
+ "geometry",
179
+ removedGeometryRedoEntries,
180
+ );
181
+
182
+ // Selection-restore stacks are index-aligned with their matching
183
+ // content stack (see contentUndoSelectionStackRef's doc comment) —
184
+ // iterate with the index so a dropped entry (remainingChanges.length
185
+ // === 0) drops its selection snapshot too, keeping both arrays in sync.
186
+ const nextContentUndoStack: ContentHistoryEntry[] = [];
187
+ const nextContentUndoSelectionStack: (
188
+ | GeometryHistorySelection
189
+ | undefined
190
+ )[] = [];
191
+ let removedContentUndoEntries = 0;
192
+ contentUndoStackRef.current.forEach((entry, index) => {
193
+ const remainingChanges = getContentHistoryChanges(entry).filter(
194
+ (change) => !deleteIds.has(change.fileId),
195
+ );
196
+ if (remainingChanges.length === 0) {
197
+ removedContentUndoEntries += 1;
198
+ return;
199
+ }
200
+ nextContentUndoStack.push(
201
+ remainingChanges.length === 1
202
+ ? remainingChanges[0]
203
+ : { changes: remainingChanges },
204
+ );
205
+ nextContentUndoSelectionStack.push(
206
+ contentUndoSelectionStackRef.current[index],
207
+ );
208
+ });
209
+ contentUndoStackRef.current = nextContentUndoStack;
210
+ contentUndoSelectionStackRef.current = nextContentUndoSelectionStack;
211
+ historyOrderRef.current = removeRecentUndoRedoOrderKinds(
212
+ historyOrderRef.current,
213
+ "file-content",
214
+ removedContentUndoEntries,
215
+ );
216
+ const nextContentRedoStack: ContentHistoryEntry[] = [];
217
+ const nextContentRedoSelectionStack: (
218
+ | GeometryHistorySelection
219
+ | undefined
220
+ )[] = [];
221
+ let removedContentRedoEntries = 0;
222
+ contentRedoStackRef.current.forEach((entry, index) => {
223
+ const remainingChanges = getContentHistoryChanges(entry).filter(
224
+ (change) => !deleteIds.has(change.fileId),
225
+ );
226
+ if (remainingChanges.length === 0) {
227
+ removedContentRedoEntries += 1;
228
+ return;
229
+ }
230
+ nextContentRedoStack.push(
231
+ remainingChanges.length === 1
232
+ ? remainingChanges[0]
233
+ : { changes: remainingChanges },
234
+ );
235
+ nextContentRedoSelectionStack.push(
236
+ contentRedoSelectionStackRef.current[index],
237
+ );
238
+ });
239
+ contentRedoStackRef.current = nextContentRedoStack;
240
+ contentRedoSelectionStackRef.current = nextContentRedoSelectionStack;
241
+ redoOrderRef.current = removeRecentUndoRedoOrderKinds(
242
+ redoOrderRef.current,
243
+ "file-content",
244
+ removedContentRedoEntries,
245
+ );
246
+ localContentUndoStackRef.current = localContentUndoStackRef.current.filter(
247
+ (change) => !deleteIds.has(change.fileId),
248
+ );
249
+ localContentRedoStackRef.current = localContentRedoStackRef.current.filter(
250
+ (change) => !deleteIds.has(change.fileId),
251
+ );
252
+
253
+ // U12: a file-created entry is resolved by filename at undo/redo time
254
+ // (it doesn't carry an id, since the id isn't known until the create
255
+ // mutation resolves), so prune it here by filename when the file it
256
+ // refers to is being hard-deleted directly.
257
+ const deletedFilenames = new Set(filesToDelete.map((file) => file.filename));
258
+ const prunedFileCreationUndo = pruneFileCreationHistoryStack(
259
+ fileCreationUndoStackRef.current,
260
+ deletedFilenames,
261
+ );
262
+ fileCreationUndoStackRef.current = prunedFileCreationUndo.stack;
263
+ historyOrderRef.current = removeRecentUndoRedoOrderKinds(
264
+ historyOrderRef.current,
265
+ "file-created",
266
+ prunedFileCreationUndo.removed,
267
+ );
268
+ // U12 fix: undoFileCreation calls performDeleteFiles to soft-delete the
269
+ // file it is undoing AFTER pushing that same entry onto the redo stack
270
+ // (so redo can recreate it). Pruning the redo stack by filename here
271
+ // would immediately drop the entry undoFileCreation just pushed —
272
+ // redo would never survive an undo. skipFileCreationRedoPrune lets
273
+ // that caller opt out; every other caller (direct hard-delete from the
274
+ // overview/panel) still gets the filename-keyed prune so a redo entry
275
+ // pointing at a since-hard-deleted file cannot resurrect it.
276
+ const prunedFileCreationRedo = pruneFileCreationHistoryStack(
277
+ fileCreationRedoStackRef.current,
278
+ deletedFilenames,
279
+ { skip: options?.skipFileCreationRedoPrune },
280
+ );
281
+ fileCreationRedoStackRef.current = prunedFileCreationRedo.stack;
282
+ redoOrderRef.current = removeRecentUndoRedoOrderKinds(
283
+ redoOrderRef.current,
284
+ "file-created",
285
+ prunedFileCreationRedo.removed,
286
+ );
287
+
288
+ writeFrameGeometrySnapshot(nextGeometry);
289
+ queryClient.setQueryData(["action", "get-design", { id }], (old: any) => {
290
+ if (!old || typeof old !== "object" || !Array.isArray(old.files)) {
291
+ return old;
292
+ }
293
+ return {
294
+ ...old,
295
+ files: old.files.filter((file: DesignFile) => !deleteIds.has(file.id)),
296
+ };
297
+ });
298
+
299
+ if (activeFile && deleteIds.has(activeFile.id) && nextActiveFile) {
300
+ setActiveFileId(nextActiveFile.id);
301
+ }
302
+ setSelectedElement(null);
303
+ setSelectedLayerIdsState([]);
304
+
305
+ void Promise.allSettled(
306
+ filesToDelete.map((file) =>
307
+ deleteFileMutation.mutateAsync({ id: file.id } as any),
308
+ ),
309
+ ).then((results) => {
310
+ const deletedFiles = filesToDelete.filter((_, index) => {
311
+ const result = results[index];
312
+ return (
313
+ result?.status === "fulfilled" &&
314
+ (result.value as { deleted?: boolean } | undefined)?.deleted !== false
315
+ );
316
+ });
317
+ const deletedIds = new Set(deletedFiles.map((file) => file.id));
318
+ const failedFiles = filesToDelete.filter(
319
+ (file) => !deletedIds.has(file.id),
320
+ );
321
+
322
+ if (deletionHistoryEntry && deletedFiles.length > 0) {
323
+ fileDeletionUndoStackRef.current = [
324
+ ...fileDeletionUndoStackRef.current.slice(-(MAX_DESIGN_UNDO_STACK - 1)),
325
+ filterFileDeletionHistoryEntry(deletionHistoryEntry, deletedIds),
326
+ ];
327
+ historyOrderRef.current = [
328
+ ...historyOrderRef.current.slice(-(MAX_DESIGN_UNDO_STACK - 1)),
329
+ "file-deleted",
330
+ ];
331
+ }
332
+
333
+ const rejected = results.find(
334
+ (result): result is PromiseRejectedResult => result.status === "rejected",
335
+ );
336
+ if (failedFiles.length > 0) {
337
+ queryClient.invalidateQueries({
338
+ queryKey: ["action", "get-design"],
339
+ });
340
+ if (rejected) {
341
+ toast.error(
342
+ rejected.reason instanceof Error
343
+ ? rejected.reason.message
344
+ : t("common.genericError"),
345
+ );
346
+ }
347
+ }
348
+
349
+ if (deletionHistoryEntry) {
350
+ fileHistoryMutationPendingRef.current = false;
351
+ clipboardPasteUndoStackRef.current = [];
352
+ clipboardPasteRedoStackRef.current = [];
353
+ latestClipboardMutationContentRef.current.clear();
354
+ }
355
+ options?.onMutationSettled?.(deletedFiles, failedFiles);
356
+ syncUndoRedoState();
357
+ });
358
+
359
+ // File-backed screen deletion is not a geometry-only edit. The screen rows
360
+ // are hard-deleted, so suppress MultiScreenCanvas' local frame-history
361
+ // entry; otherwise undo would restore geometry for files that no longer
362
+ // exist.
363
+ syncUndoRedoState();
364
+ }