@agent-native/core 0.163.4 → 0.164.1

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 (200) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/app/hooks/use-dashboard-chat-context.ts +29 -0
  3. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +1 -2
  4. package/corpus/templates/analytics/netlify.toml +2 -0
  5. package/corpus/templates/assets/netlify.toml +2 -0
  6. package/corpus/templates/brain/netlify.toml +2 -0
  7. package/corpus/templates/calendar/app/components/calendar/DayView.tsx +2 -1
  8. package/corpus/templates/calendar/changelog/2026-08-19-calendar-page-loads-stay-fast-after-idle-periods.md +6 -0
  9. package/corpus/templates/calendar/netlify.toml +2 -0
  10. package/corpus/templates/chat/netlify.toml +2 -0
  11. package/corpus/templates/clips/app/components/player/player-controls.tsx +3 -3
  12. package/corpus/templates/clips/app/components/player/reaction-emojis.ts +12 -0
  13. package/corpus/templates/clips/app/components/player/reactions-tray.tsx +90 -9
  14. package/corpus/templates/clips/app/components/player/scrubber.tsx +43 -10
  15. package/corpus/templates/clips/app/components/player/video-player.tsx +105 -15
  16. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +1 -2
  17. package/corpus/templates/clips/app/routes/_index.tsx +10 -2
  18. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +13 -8
  19. package/corpus/templates/clips/app/routes/share.$shareId.tsx +15 -8
  20. package/corpus/templates/clips/netlify.toml +2 -0
  21. package/corpus/templates/clips/server/routes/[...page].head.ts +5 -0
  22. package/corpus/templates/content/netlify.toml +2 -0
  23. package/corpus/templates/design/.agents/skills/design-editor-architecture/SKILL.md +103 -0
  24. package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +2 -1
  25. package/corpus/templates/design/AGENTS.md +3 -1
  26. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +3 -2
  27. package/corpus/templates/design/app/components/design/editor/AgentNativeMenuMark.tsx +25 -0
  28. package/corpus/templates/design/app/components/design/editor/DesignBottomToolbar.tsx +411 -0
  29. package/corpus/templates/design/app/components/design/editor/DesignCollaborators.tsx +153 -0
  30. package/corpus/templates/design/app/components/design/editor/DesignWorkspaceRail.tsx +231 -0
  31. package/corpus/templates/design/app/components/design/editor/MakeRealDialog.tsx +223 -0
  32. package/corpus/templates/design/app/components/design/editor/PendingScreenDeletionDialog.tsx +58 -0
  33. package/corpus/templates/design/app/components/design/editor/PendingVisualStyleWarningDialog.tsx +56 -0
  34. package/corpus/templates/design/app/components/design/editor/ReadOnlyEditorPanel.tsx +23 -0
  35. package/corpus/templates/design/app/components/design/editor/SaveTemplateDialog.tsx +161 -0
  36. package/corpus/templates/design/app/components/design/editor/toolbar-controls.tsx +185 -0
  37. package/corpus/templates/design/app/pages/DesignEditor.tsx +20913 -0
  38. package/corpus/templates/design/app/pages/design-editor/command-types.ts +120 -0
  39. package/corpus/templates/design/app/pages/design-editor/commands/README.md +193 -0
  40. package/corpus/templates/design/app/pages/design-editor/commands/add-auto-layout.ts +416 -0
  41. package/corpus/templates/design/app/pages/design-editor/commands/add-screen.ts +112 -0
  42. package/corpus/templates/design/app/pages/design-editor/commands/align-selection.ts +183 -0
  43. package/corpus/templates/design/app/pages/design-editor/commands/apply-design-editor-command.ts +243 -0
  44. package/corpus/templates/design/app/pages/design-editor/commands/apply-file-content-update.ts +236 -0
  45. package/corpus/templates/design/app/pages/design-editor/commands/apply-local-content-update.ts +304 -0
  46. package/corpus/templates/design/app/pages/design-editor/commands/apply-pending-visual-styles-with-agent.ts +376 -0
  47. package/corpus/templates/design/app/pages/design-editor/commands/apply-to-source.ts +132 -0
  48. package/corpus/templates/design/app/pages/design-editor/commands/can-move-layer.ts +117 -0
  49. package/corpus/templates/design/app/pages/design-editor/commands/change-selected-z-index.ts +212 -0
  50. package/corpus/templates/design/app/pages/design-editor/commands/commit-relative-style-delta-to-selected-layers.ts +176 -0
  51. package/corpus/templates/design/app/pages/design-editor/commands/commit-styles-to-selected-layers.ts +175 -0
  52. package/corpus/templates/design/app/pages/design-editor/commands/commit-visual-styles.ts +710 -0
  53. package/corpus/templates/design/app/pages/design-editor/commands/confirm-make-real.ts +99 -0
  54. package/corpus/templates/design/app/pages/design-editor/commands/copy-as-figma-svg.ts +95 -0
  55. package/corpus/templates/design/app/pages/design-editor/commands/copy-selection.ts +156 -0
  56. package/corpus/templates/design/app/pages/design-editor/commands/create-primitive.ts +291 -0
  57. package/corpus/templates/design/app/pages/design-editor/commands/create-screen-frame.ts +131 -0
  58. package/corpus/templates/design/app/pages/design-editor/commands/cross-screen-element-drop.ts +577 -0
  59. package/corpus/templates/design/app/pages/design-editor/commands/delete-files.ts +364 -0
  60. package/corpus/templates/design/app/pages/design-editor/commands/delete-selection.ts +521 -0
  61. package/corpus/templates/design/app/pages/design-editor/commands/detach-instance-menu-action.ts +88 -0
  62. package/corpus/templates/design/app/pages/design-editor/commands/distribute-selection.ts +114 -0
  63. package/corpus/templates/design/app/pages/design-editor/commands/download-all-screens-pdf.ts +116 -0
  64. package/corpus/templates/design/app/pages/design-editor/commands/download-pdf.ts +103 -0
  65. package/corpus/templates/design/app/pages/design-editor/commands/download-svg.ts +159 -0
  66. package/corpus/templates/design/app/pages/design-editor/commands/duplicate-screen.ts +201 -0
  67. package/corpus/templates/design/app/pages/design-editor/commands/duplicate-selection.ts +279 -0
  68. package/corpus/templates/design/app/pages/design-editor/commands/editor-paste.ts +81 -0
  69. package/corpus/templates/design/app/pages/design-editor/commands/enter-hotkey.ts +155 -0
  70. package/corpus/templates/design/app/pages/design-editor/commands/enter-single-screen.ts +168 -0
  71. package/corpus/templates/design/app/pages/design-editor/commands/escape-hotkey.ts +212 -0
  72. package/corpus/templates/design/app/pages/design-editor/commands/frame-selection.ts +119 -0
  73. package/corpus/templates/design/app/pages/design-editor/commands/geometry-commit.ts +169 -0
  74. package/corpus/templates/design/app/pages/design-editor/commands/get-selected-layer-snapshots.ts +177 -0
  75. package/corpus/templates/design/app/pages/design-editor/commands/group-selection.ts +127 -0
  76. package/corpus/templates/design/app/pages/design-editor/commands/iframe-context-menu.ts +121 -0
  77. package/corpus/templates/design/app/pages/design-editor/commands/import-figma-clipboard-into-design.ts +119 -0
  78. package/corpus/templates/design/app/pages/design-editor/commands/layer-marquee-selection-change.ts +163 -0
  79. package/corpus/templates/design/app/pages/design-editor/commands/layer-move-to-screen.ts +331 -0
  80. package/corpus/templates/design/app/pages/design-editor/commands/layer-move.ts +517 -0
  81. package/corpus/templates/design/app/pages/design-editor/commands/layer-rename.ts +247 -0
  82. package/corpus/templates/design/app/pages/design-editor/commands/layer-selection-change.ts +161 -0
  83. package/corpus/templates/design/app/pages/design-editor/commands/mode-change.ts +122 -0
  84. package/corpus/templates/design/app/pages/design-editor/commands/nudge-selection.ts +213 -0
  85. package/corpus/templates/design/app/pages/design-editor/commands/overview-primitive-reparent.ts +318 -0
  86. package/corpus/templates/design/app/pages/design-editor/commands/paste-copied-screens.ts +114 -0
  87. package/corpus/templates/design/app/pages/design-editor/commands/paste-over-selection.ts +70 -0
  88. package/corpus/templates/design/app/pages/design-editor/commands/paste-selection.ts +436 -0
  89. package/corpus/templates/design/app/pages/design-editor/commands/paste-to-replace.ts +135 -0
  90. package/corpus/templates/design/app/pages/design-editor/commands/pasted-image-files.ts +209 -0
  91. package/corpus/templates/design/app/pages/design-editor/commands/persist-frame-geometry-save.ts +113 -0
  92. package/corpus/templates/design/app/pages/design-editor/commands/persist-tweak-save.ts +160 -0
  93. package/corpus/templates/design/app/pages/design-editor/commands/primitive-created.ts +168 -0
  94. package/corpus/templates/design/app/pages/design-editor/commands/record-pending-live-layer-state-edit.ts +149 -0
  95. package/corpus/templates/design/app/pages/design-editor/commands/record-pending-live-structure-edit.ts +200 -0
  96. package/corpus/templates/design/app/pages/design-editor/commands/record-pending-live-text-edit.ts +152 -0
  97. package/corpus/templates/design/app/pages/design-editor/commands/record-pending-visual-style-edit.ts +247 -0
  98. package/corpus/templates/design/app/pages/design-editor/commands/redo.ts +1086 -0
  99. package/corpus/templates/design/app/pages/design-editor/commands/render-png-blob.ts +200 -0
  100. package/corpus/templates/design/app/pages/design-editor/commands/save-file-content.ts +207 -0
  101. package/corpus/templates/design/app/pages/design-editor/commands/screen-element-select.ts +262 -0
  102. package/corpus/templates/design/app/pages/design-editor/commands/screen-text-content-change.ts +216 -0
  103. package/corpus/templates/design/app/pages/design-editor/commands/screen-visual-duplicate-change.ts +108 -0
  104. package/corpus/templates/design/app/pages/design-editor/commands/screen-visual-structure-change.ts +280 -0
  105. package/corpus/templates/design/app/pages/design-editor/commands/screen-visual-style-change.ts +151 -0
  106. package/corpus/templates/design/app/pages/design-editor/commands/send-overview-annotations.ts +88 -0
  107. package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-move-semantic-handoff.ts +122 -0
  108. package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-semantic-handoff.ts +143 -0
  109. package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-state-semantic-handoff.ts +115 -0
  110. package/corpus/templates/design/app/pages/design-editor/commands/start-retry-generation.ts +152 -0
  111. package/corpus/templates/design/app/pages/design-editor/commands/start-sidebar-resize.ts +99 -0
  112. package/corpus/templates/design/app/pages/design-editor/commands/style-change.ts +152 -0
  113. package/corpus/templates/design/app/pages/design-editor/commands/styles-change.ts +155 -0
  114. package/corpus/templates/design/app/pages/design-editor/commands/suggest-auto-layout.ts +125 -0
  115. package/corpus/templates/design/app/pages/design-editor/commands/text-content-change.ts +201 -0
  116. package/corpus/templates/design/app/pages/design-editor/commands/tidy-up.ts +123 -0
  117. package/corpus/templates/design/app/pages/design-editor/commands/toggle-layer-hidden.ts +167 -0
  118. package/corpus/templates/design/app/pages/design-editor/commands/toggle-layer-locked.ts +175 -0
  119. package/corpus/templates/design/app/pages/design-editor/commands/toggle-motion-keyframe.ts +99 -0
  120. package/corpus/templates/design/app/pages/design-editor/commands/tweak-prompt-submit.ts +84 -0
  121. package/corpus/templates/design/app/pages/design-editor/commands/undo.ts +906 -0
  122. package/corpus/templates/design/app/pages/design-editor/commands/ungroup-selection.ts +170 -0
  123. package/corpus/templates/design/app/pages/design-editor/commands/visual-duplicate-change.ts +119 -0
  124. package/corpus/templates/design/app/pages/design-editor/commands/visual-structure-change.ts +274 -0
  125. package/corpus/templates/design/app/pages/design-editor/commands/write-frame-geometry-snapshot.ts +99 -0
  126. package/corpus/templates/design/app/pages/design-editor/derive/design-breakpoints.ts +56 -0
  127. package/corpus/templates/design/app/pages/design-editor/derive/overview-screens.ts +146 -0
  128. package/corpus/templates/design/app/pages/design-editor/domains/use-tweaks.ts +326 -0
  129. package/corpus/templates/design/app/pages/design-editor/editor-constants.ts +54 -0
  130. package/corpus/templates/design/app/pages/design-editor/editor-helpers.ts +183 -0
  131. package/corpus/templates/design/app/pages/design-editor/effects/adopt-db-file-content.ts +270 -0
  132. package/corpus/templates/design/app/pages/design-editor/effects/mirror-selection-to-agent-chat.ts +134 -0
  133. package/corpus/templates/design/app/pages/design-editor/effects/motion-autosave.ts +335 -0
  134. package/corpus/templates/design/app/pages/design-editor/effects/observe-collab-text.ts +183 -0
  135. package/corpus/templates/design/app/pages/design-editor/effects/publish-agent-selection-context.ts +252 -0
  136. package/corpus/templates/design/app/pages/design-editor/effects/resume-pending-generation.ts +178 -0
  137. package/corpus/templates/design/app/pages/design-editor/effects/seed-collab-content.ts +157 -0
  138. package/corpus/templates/design/app/pages/design-editor/preview-html.ts +19 -0
  139. package/corpus/templates/design/netlify.toml +2 -0
  140. package/corpus/templates/design/shared/board-file.ts +2 -1
  141. package/corpus/templates/dispatch/netlify.toml +2 -0
  142. package/corpus/templates/forms/netlify.toml +2 -0
  143. package/corpus/templates/mail/netlify.toml +2 -0
  144. package/corpus/templates/plan/netlify.toml +2 -0
  145. package/corpus/templates/slides/netlify.toml +2 -0
  146. package/dist/agent/engine/builder-engine.d.ts +6 -4
  147. package/dist/agent/engine/builder-engine.js +91 -26
  148. package/dist/agent/engine/registry.js +16 -0
  149. package/dist/cli/code-agent-agent-tools.d.ts +2 -0
  150. package/dist/cli/code-agent-agent-tools.js +188 -0
  151. package/dist/cli/code-agent-collaboration.d.ts +34 -0
  152. package/dist/cli/code-agent-collaboration.js +104 -0
  153. package/dist/cli/code-agent-executor.js +6 -0
  154. package/dist/cli/code-agent-schedules.d.ts +54 -0
  155. package/dist/cli/code-agent-schedules.js +198 -0
  156. package/dist/client/AgentPanel.js +1 -1
  157. package/dist/client/ConnectBuilderCard.js +5 -2
  158. package/dist/client/EnvironmentBadge.js +6 -5
  159. package/dist/client/chat/run-recovery.js +3 -2
  160. package/dist/client/chat/tool-call-display.js +2 -3
  161. package/dist/client/components/CodeRequiredDialog.js +4 -2
  162. package/dist/client/i18n.js +5 -4
  163. package/dist/client/settings/SettingsPanel.js +1 -1
  164. package/dist/client/settings/VoiceTranscriptionSection.js +1 -1
  165. package/dist/client/settings/useBuilderStatus.d.ts +6 -1
  166. package/dist/client/settings/useBuilderStatus.js +22 -33
  167. package/dist/client/transcription/BuilderTranscriptionCta.js +1 -1
  168. package/dist/code-agents/index.d.ts +2 -0
  169. package/dist/code-agents/index.js +2 -0
  170. package/dist/collab/routes.d.ts +1 -1
  171. package/dist/localization/shared.d.ts +2 -0
  172. package/dist/localization/shared.js +5 -0
  173. package/dist/mcp-client/oauth-client.d.ts +1 -0
  174. package/dist/mcp-client/oauth-client.js +50 -1
  175. package/dist/observability/routes.d.ts +1 -1
  176. package/dist/progress/routes.d.ts +1 -1
  177. package/dist/provider-api/actions/provider-api.d.ts +2 -2
  178. package/dist/resources/handlers.d.ts +1 -1
  179. package/dist/server/auth-marketing-locales.d.ts +7 -0
  180. package/dist/server/auth-marketing-locales.js +1322 -0
  181. package/dist/server/auth-marketing.d.ts +1 -0
  182. package/dist/server/auth-marketing.js +35 -6
  183. package/dist/server/auth.js +4 -17
  184. package/dist/server/builder-browser.d.ts +22 -0
  185. package/dist/server/builder-browser.js +77 -1
  186. package/dist/server/builder-oauth.d.ts +50 -0
  187. package/dist/server/builder-oauth.js +263 -0
  188. package/dist/server/core-routes-plugin.d.ts +11 -0
  189. package/dist/server/core-routes-plugin.js +291 -415
  190. package/dist/server/credential-provider.d.ts +1 -1
  191. package/dist/server/credential-provider.js +1 -1
  192. package/dist/server/csrf.js +2 -2
  193. package/dist/server/onboarding-html.js +52 -120
  194. package/dist/settings/store.d.ts +9 -0
  195. package/dist/settings/store.js +19 -0
  196. package/dist/templates/chat/netlify.toml +2 -0
  197. package/docs/content/deployment.mdx +2 -0
  198. package/docs/content/multi-app-workspace.mdx +1 -1
  199. package/package.json +2 -2
  200. package/src/templates/chat/netlify.toml +2 -0
@@ -0,0 +1,149 @@
1
+ import type { CodeLayerNode, CodeLayerTreeNode } from "@shared/code-layer";
2
+ import type { Dispatch, RefObject, SetStateAction } from "react";
3
+
4
+ import { prettyScreenName } from "@/lib/screen-names";
5
+ import {
6
+ bridgeSourceIdForCodeLayerNode,
7
+ elementInfoFromCodeLayerNode,
8
+ preferredCodeLayerSelector,
9
+ } from "@/pages/design-editor/code-layer-state";
10
+ import type {
11
+ PendingStructureVerificationStatus,
12
+ RuntimeLayerSnapshot,
13
+ } from "@/pages/design-editor/command-types";
14
+ import type { OverviewScreen } from "@/pages/design-editor/derive/overview-screens";
15
+ import { runtimeMultiplicityForElementProvenance } from "@/pages/design-editor/editor-helpers";
16
+ import type { ContentHistoryChange } from "@/pages/design-editor/history";
17
+ import { MAX_DESIGN_UNDO_STACK } from "@/pages/design-editor/history";
18
+ import type {
19
+ PendingLiveLayerStateEdit,
20
+ PendingLiveNonStyleEdit,
21
+ PendingLiveNonStyleUndoEntry,
22
+ PendingVisualStyleUndoEntry,
23
+ } from "@/pages/design-editor/pending-edits";
24
+ import {
25
+ mergePendingLiveNonStyleEdits,
26
+ pendingLiveLayerStateUndoRevertValue,
27
+ reactSourceAnchorForPendingEdit,
28
+ resolveOverviewScreenSourceType,
29
+ } from "@/pages/design-editor/pending-edits";
30
+ import type { DesignFile } from "@/pages/design-editor/types";
31
+
32
+ export interface RecordPendingLiveLayerStateEditArgs {
33
+ canEditDesign: boolean;
34
+ cancelPendingStructureVerification: (
35
+ nextStatus?: PendingStructureVerificationStatus,
36
+ ) => void;
37
+ clipboardPasteRedoStackRef: RefObject<ContentHistoryChange[]>;
38
+ codeLayerOwnerByNodeIdRef: RefObject<
39
+ Map<
40
+ string,
41
+ {
42
+ fileId: string;
43
+ node: CodeLayerNode;
44
+ tree: CodeLayerTreeNode[];
45
+ runtimeOnly: boolean;
46
+ }
47
+ >
48
+ >;
49
+ files: DesignFile[];
50
+ localhostConnectionRootPathByIdRef: RefObject<Map<string, string>>;
51
+ overviewScreens: OverviewScreen[];
52
+ pendingLiveNonStyleEditsRef: RefObject<PendingLiveNonStyleEdit[]>;
53
+ pendingLiveNonStyleRedoStackRef: RefObject<PendingLiveNonStyleUndoEntry[]>;
54
+ pendingLiveNonStyleUndoStackRef: RefObject<PendingLiveNonStyleUndoEntry[]>;
55
+ pendingVisualStyleRedoStackRef: RefObject<PendingVisualStyleUndoEntry[]>;
56
+ runtimeLayerSnapshotsById: Record<string, RuntimeLayerSnapshot>;
57
+ setPendingLiveNonStyleEdits: Dispatch<
58
+ SetStateAction<PendingLiveNonStyleEdit[]>
59
+ >;
60
+ }
61
+
62
+ export function runRecordPendingLiveLayerStateEdit(
63
+ {
64
+ canEditDesign,
65
+ cancelPendingStructureVerification,
66
+ clipboardPasteRedoStackRef,
67
+ codeLayerOwnerByNodeIdRef,
68
+ files,
69
+ localhostConnectionRootPathByIdRef,
70
+ overviewScreens,
71
+ pendingLiveNonStyleEditsRef,
72
+ pendingLiveNonStyleRedoStackRef,
73
+ pendingLiveNonStyleUndoStackRef,
74
+ pendingVisualStyleRedoStackRef,
75
+ runtimeLayerSnapshotsById,
76
+ setPendingLiveNonStyleEdits,
77
+ }: RecordPendingLiveLayerStateEditArgs,
78
+ layerId: string,
79
+ state: "hidden" | "locked",
80
+ enabled: boolean,
81
+ originalEnabled: boolean,
82
+ ) {
83
+ if (!canEditDesign) return false;
84
+ const owner = codeLayerOwnerByNodeIdRef.current.get(layerId);
85
+ if (!owner) return false;
86
+ const screen = overviewScreens.find(
87
+ (candidate) => candidate.id === owner.fileId,
88
+ );
89
+ if (resolveOverviewScreenSourceType(screen) !== "localhost") {
90
+ return false;
91
+ }
92
+ const info = elementInfoFromCodeLayerNode(owner.node);
93
+ const sourceId = bridgeSourceIdForCodeLayerNode(owner.node);
94
+ const selector = preferredCodeLayerSelector(owner.node);
95
+ const rootPath = screen?.connectionId
96
+ ? localhostConnectionRootPathByIdRef.current.get(screen.connectionId)
97
+ : undefined;
98
+ const fallbackName =
99
+ files.find((file) => file.id === owner.fileId)?.filename ?? owner.fileId;
100
+ const nextEdit: PendingLiveLayerStateEdit = {
101
+ kind: "layer-state",
102
+ screenId: owner.fileId,
103
+ filename: fallbackName,
104
+ screenName: prettyScreenName(fallbackName),
105
+ layerId,
106
+ selector,
107
+ sourceId,
108
+ sourceAnchor: reactSourceAnchorForPendingEdit({
109
+ info,
110
+ id: sourceId,
111
+ rootPath,
112
+ runtimeMultiplicity: runtimeMultiplicityForElementProvenance(
113
+ runtimeLayerSnapshotsById,
114
+ info,
115
+ ),
116
+ reason: `Pending live ${state} state for layer ${layerId} in screen ${owner.fileId}.`,
117
+ }),
118
+ tagName: info.tagName ?? null,
119
+ classes: info.classes ?? [],
120
+ state,
121
+ enabled,
122
+ originalEnabled,
123
+ updatedAt: Date.now(),
124
+ };
125
+ const revertEnabled = pendingLiveLayerStateUndoRevertValue(
126
+ pendingLiveNonStyleEditsRef.current,
127
+ nextEdit,
128
+ );
129
+ cancelPendingStructureVerification("conflict");
130
+ pendingLiveNonStyleRedoStackRef.current = [];
131
+ pendingVisualStyleRedoStackRef.current = [];
132
+ clipboardPasteRedoStackRef.current = [];
133
+ pendingLiveNonStyleUndoStackRef.current = [
134
+ ...pendingLiveNonStyleUndoStackRef.current.slice(
135
+ -(MAX_DESIGN_UNDO_STACK - 1),
136
+ ),
137
+ {
138
+ kind: "layer-state",
139
+ edit: nextEdit,
140
+ revertEnabled,
141
+ },
142
+ ];
143
+ const nextPending = mergePendingLiveNonStyleEdits(
144
+ pendingLiveNonStyleUndoStackRef.current.map((entry) => entry.edit),
145
+ );
146
+ pendingLiveNonStyleEditsRef.current = nextPending;
147
+ setPendingLiveNonStyleEdits(nextPending);
148
+ return true;
149
+ }
@@ -0,0 +1,200 @@
1
+ import type { Dispatch, RefObject, SetStateAction } from "react";
2
+
3
+ import type { ElementInfo } from "@/components/design/types";
4
+ import { prettyScreenName } from "@/lib/screen-names";
5
+ import type {
6
+ PendingStructureVerificationStatus,
7
+ RuntimeLayerSnapshot,
8
+ } from "@/pages/design-editor/command-types";
9
+ import type { OverviewScreen } from "@/pages/design-editor/derive/overview-screens";
10
+ import { runtimeMultiplicityForElementProvenance } from "@/pages/design-editor/editor-helpers";
11
+ import { MAX_DESIGN_UNDO_STACK } from "@/pages/design-editor/history";
12
+ import type {
13
+ PendingLiveNonStyleEdit,
14
+ PendingLiveNonStyleUndoEntry,
15
+ PendingLiveStructureEdit,
16
+ PendingLiveStructureUndoEntry,
17
+ PendingVisualStyleUndoEntry,
18
+ } from "@/pages/design-editor/pending-edits";
19
+ import {
20
+ mergePendingLiveNonStyleEdits,
21
+ pendingLiveStructureEditsMatch,
22
+ projectRelativeSourcePath,
23
+ reactSourceAnchorForPendingEdit,
24
+ } from "@/pages/design-editor/pending-edits";
25
+ import type { DesignFile } from "@/pages/design-editor/types";
26
+
27
+ export interface RecordPendingLiveStructureEditArgs {
28
+ canEditDesign: boolean;
29
+ cancelPendingStructureVerification: (
30
+ nextStatus?: PendingStructureVerificationStatus,
31
+ ) => void;
32
+ files: DesignFile[];
33
+ localhostConnectionRootPathByIdRef: RefObject<Map<string, string>>;
34
+ overviewScreens: OverviewScreen[];
35
+ pendingLiveNonStyleEditsRef: RefObject<PendingLiveNonStyleEdit[]>;
36
+ pendingLiveNonStyleRedoStackRef: RefObject<PendingLiveNonStyleUndoEntry[]>;
37
+ pendingLiveNonStyleUndoStackRef: RefObject<PendingLiveNonStyleUndoEntry[]>;
38
+ pendingStructureRedoReplayRef: RefObject<
39
+ PendingLiveStructureUndoEntry | undefined
40
+ >;
41
+ pendingStructureRedoReplayTimerRef: RefObject<number | undefined>;
42
+ pendingVisualStyleRedoStackRef: RefObject<PendingVisualStyleUndoEntry[]>;
43
+ runtimeLayerSnapshotsById: Record<string, RuntimeLayerSnapshot>;
44
+ setPendingLiveNonStyleEdits: Dispatch<
45
+ SetStateAction<PendingLiveNonStyleEdit[]>
46
+ >;
47
+ }
48
+
49
+ export function runRecordPendingLiveStructureEdit(
50
+ {
51
+ canEditDesign,
52
+ cancelPendingStructureVerification,
53
+ files,
54
+ localhostConnectionRootPathByIdRef,
55
+ overviewScreens,
56
+ pendingLiveNonStyleEditsRef,
57
+ pendingLiveNonStyleRedoStackRef,
58
+ pendingLiveNonStyleUndoStackRef,
59
+ pendingStructureRedoReplayRef,
60
+ pendingStructureRedoReplayTimerRef,
61
+ pendingVisualStyleRedoStackRef,
62
+ runtimeLayerSnapshotsById,
63
+ setPendingLiveNonStyleEdits,
64
+ }: RecordPendingLiveStructureEditArgs,
65
+ screenId: string,
66
+ selector: string,
67
+ anchorSelector: string,
68
+ placement: "before" | "after" | "inside",
69
+ elementInfo?: ElementInfo,
70
+ details?: {
71
+ sourceId?: string;
72
+ anchorSourceId?: string;
73
+ anchorElementInfo?: ElementInfo;
74
+ requestId?: string;
75
+ dropMode?: "flow-insert" | "absolute-container";
76
+ forceFlowPositionOverride?: boolean;
77
+ sourceRect?: { x: number; y: number; width: number; height: number };
78
+ anchorRect?: { x: number; y: number; width: number; height: number };
79
+ /** Markup this change introduced; the subject does not exist in the
80
+ * screen's source yet, so it must be added rather than relocated. */
81
+ insertedHtml?: string;
82
+ /** The inserted markup replaced this subject as one live gesture. */
83
+ replaced?: true;
84
+ replacementSelector?: string;
85
+ replacementSourceId?: string;
86
+ /** This change DELETED the subject; it has no anchor. */
87
+ removed?: true;
88
+ },
89
+ ) {
90
+ if (!canEditDesign) return;
91
+ cancelPendingStructureVerification("conflict");
92
+ const screen = files.find((file) => file.id === screenId);
93
+ const overviewScreen = overviewScreens.find(
94
+ (candidate) => candidate.id === screenId,
95
+ );
96
+ const connectionRootPath = overviewScreen?.connectionId
97
+ ? localhostConnectionRootPathByIdRef.current.get(
98
+ overviewScreen.connectionId,
99
+ )
100
+ : undefined;
101
+ const routeSourceFile = projectRelativeSourcePath({
102
+ sourceFile: overviewScreen?.sourceFile,
103
+ rootPath: connectionRootPath,
104
+ });
105
+ const fallbackName = screen?.filename ?? screenId;
106
+ const nextEdit: PendingLiveStructureEdit = {
107
+ kind: "structure",
108
+ screenId,
109
+ filename: fallbackName,
110
+ screenName: prettyScreenName(fallbackName),
111
+ selector,
112
+ sourceId: details?.sourceId ?? elementInfo?.sourceId ?? null,
113
+ sourceAnchor: reactSourceAnchorForPendingEdit({
114
+ info: elementInfo,
115
+ id: details?.sourceId ?? elementInfo?.sourceId,
116
+ rootPath: (() => {
117
+ const connectionId = overviewScreens.find(
118
+ (candidate) => candidate.id === screenId,
119
+ )?.connectionId;
120
+ return connectionId
121
+ ? localhostConnectionRootPathByIdRef.current.get(connectionId)
122
+ : undefined;
123
+ })(),
124
+ runtimeMultiplicity: runtimeMultiplicityForElementProvenance(
125
+ runtimeLayerSnapshotsById,
126
+ elementInfo,
127
+ ),
128
+ }),
129
+ anchorSelector,
130
+ anchorSourceId: details?.anchorSourceId ?? null,
131
+ anchorSourceAnchor: reactSourceAnchorForPendingEdit({
132
+ info: details?.anchorElementInfo,
133
+ id: details?.anchorSourceId,
134
+ rootPath: (() => {
135
+ const connectionId = overviewScreens.find(
136
+ (candidate) => candidate.id === screenId,
137
+ )?.connectionId;
138
+ return connectionId
139
+ ? localhostConnectionRootPathByIdRef.current.get(connectionId)
140
+ : undefined;
141
+ })(),
142
+ runtimeMultiplicity: runtimeMultiplicityForElementProvenance(
143
+ runtimeLayerSnapshotsById,
144
+ details?.anchorElementInfo,
145
+ ),
146
+ }),
147
+ placement,
148
+ ...(routeSourceFile ? { routeSourceFile } : {}),
149
+ dropMode: details?.dropMode,
150
+ forceFlowPositionOverride: details?.forceFlowPositionOverride,
151
+ sourceRect: details?.sourceRect,
152
+ anchorRect: details?.anchorRect,
153
+ insertedHtml: details?.insertedHtml,
154
+ ...(details?.replaced
155
+ ? {
156
+ replaced: true as const,
157
+ replacementSelector: details.replacementSelector,
158
+ replacementSourceId: details.replacementSourceId,
159
+ }
160
+ : {}),
161
+ ...(details?.removed ? { removed: true as const } : {}),
162
+ requestId: details?.requestId,
163
+ updatedAt: Date.now(),
164
+ };
165
+ const structureRedoReplay = pendingStructureRedoReplayRef.current;
166
+ const replaysUndoneStructure = Boolean(
167
+ structureRedoReplay &&
168
+ pendingLiveStructureEditsMatch(structureRedoReplay.edit, nextEdit),
169
+ );
170
+ if (replaysUndoneStructure && structureRedoReplay) {
171
+ pendingStructureRedoReplayRef.current = undefined;
172
+ if (pendingStructureRedoReplayTimerRef.current !== undefined) {
173
+ window.clearTimeout(pendingStructureRedoReplayTimerRef.current);
174
+ pendingStructureRedoReplayTimerRef.current = undefined;
175
+ }
176
+ const redoStack = pendingLiveNonStyleRedoStackRef.current;
177
+ if (redoStack[redoStack.length - 1] === structureRedoReplay) {
178
+ pendingLiveNonStyleRedoStackRef.current = redoStack.slice(0, -1);
179
+ }
180
+ } else {
181
+ pendingLiveNonStyleRedoStackRef.current = [];
182
+ pendingStructureRedoReplayRef.current = undefined;
183
+ if (pendingStructureRedoReplayTimerRef.current !== undefined) {
184
+ window.clearTimeout(pendingStructureRedoReplayTimerRef.current);
185
+ pendingStructureRedoReplayTimerRef.current = undefined;
186
+ }
187
+ pendingVisualStyleRedoStackRef.current = [];
188
+ }
189
+ pendingLiveNonStyleUndoStackRef.current = [
190
+ ...pendingLiveNonStyleUndoStackRef.current.slice(
191
+ -(MAX_DESIGN_UNDO_STACK - 1),
192
+ ),
193
+ { kind: "structure", edit: nextEdit },
194
+ ];
195
+ const nextPending = mergePendingLiveNonStyleEdits(
196
+ pendingLiveNonStyleUndoStackRef.current.map((entry) => entry.edit),
197
+ );
198
+ pendingLiveNonStyleEditsRef.current = nextPending;
199
+ setPendingLiveNonStyleEdits(nextPending);
200
+ }
@@ -0,0 +1,152 @@
1
+ import type { Dispatch, RefObject, SetStateAction } from "react";
2
+
3
+ import type { ElementInfo } from "@/components/design/types";
4
+ import { prettyScreenName } from "@/lib/screen-names";
5
+ import type {
6
+ PendingStructureVerificationStatus,
7
+ RuntimeLayerSnapshot,
8
+ } from "@/pages/design-editor/command-types";
9
+ import type { OverviewScreen } from "@/pages/design-editor/derive/overview-screens";
10
+ import { runtimeMultiplicityForElementProvenance } from "@/pages/design-editor/editor-helpers";
11
+ import { MAX_DESIGN_UNDO_STACK } from "@/pages/design-editor/history";
12
+ import type {
13
+ PendingLiveNonStyleEdit,
14
+ PendingLiveNonStyleUndoEntry,
15
+ PendingLiveStructureUndoEntry,
16
+ PendingLiveTextEdit,
17
+ PendingVisualStyleUndoEntry,
18
+ } from "@/pages/design-editor/pending-edits";
19
+ import {
20
+ mergePendingLiveNonStyleEdits,
21
+ pendingLiveTextUndoRevertValue,
22
+ reactSourceAnchorForPendingEdit,
23
+ } from "@/pages/design-editor/pending-edits";
24
+ import type { DesignFile } from "@/pages/design-editor/types";
25
+
26
+ export interface RecordPendingLiveTextEditArgs {
27
+ activeFile: DesignFile;
28
+ canEditDesign: boolean;
29
+ cancelPendingStructureVerification: (
30
+ nextStatus?: PendingStructureVerificationStatus,
31
+ ) => void;
32
+ files: DesignFile[];
33
+ localhostConnectionRootPathByIdRef: RefObject<Map<string, string>>;
34
+ overviewScreens: OverviewScreen[];
35
+ pendingLiveNonStyleEditsRef: RefObject<PendingLiveNonStyleEdit[]>;
36
+ pendingLiveNonStyleRedoStackRef: RefObject<PendingLiveNonStyleUndoEntry[]>;
37
+ pendingLiveNonStyleUndoStackRef: RefObject<PendingLiveNonStyleUndoEntry[]>;
38
+ pendingStructureRedoReplayRef: RefObject<
39
+ PendingLiveStructureUndoEntry | undefined
40
+ >;
41
+ pendingStructureRedoReplayTimerRef: RefObject<number | undefined>;
42
+ pendingVisualStyleRedoStackRef: RefObject<PendingVisualStyleUndoEntry[]>;
43
+ runtimeLayerSnapshotsById: Record<string, RuntimeLayerSnapshot>;
44
+ selectedElement: ElementInfo | null;
45
+ setPendingLiveNonStyleEdits: Dispatch<
46
+ SetStateAction<PendingLiveNonStyleEdit[]>
47
+ >;
48
+ }
49
+
50
+ export function runRecordPendingLiveTextEdit(
51
+ {
52
+ activeFile,
53
+ canEditDesign,
54
+ cancelPendingStructureVerification,
55
+ files,
56
+ localhostConnectionRootPathByIdRef,
57
+ overviewScreens,
58
+ pendingLiveNonStyleEditsRef,
59
+ pendingLiveNonStyleRedoStackRef,
60
+ pendingLiveNonStyleUndoStackRef,
61
+ pendingStructureRedoReplayRef,
62
+ pendingStructureRedoReplayTimerRef,
63
+ pendingVisualStyleRedoStackRef,
64
+ runtimeLayerSnapshotsById,
65
+ selectedElement,
66
+ setPendingLiveNonStyleEdits,
67
+ }: RecordPendingLiveTextEditArgs,
68
+ screenId: string,
69
+ selector: string,
70
+ value: string,
71
+ elementInfo?: ElementInfo,
72
+ details?: {
73
+ html?: string;
74
+ originalValue?: string;
75
+ originalHtml?: string;
76
+ },
77
+ ) {
78
+ if (!canEditDesign) return;
79
+ const screen = files.find((file) => file.id === screenId);
80
+ const fallbackName = screen?.filename ?? screenId;
81
+ const sourceId =
82
+ elementInfo?.sourceId ??
83
+ (screenId === activeFile?.id ? selectedElement?.sourceId : null);
84
+ cancelPendingStructureVerification("conflict");
85
+ pendingLiveNonStyleRedoStackRef.current = [];
86
+ pendingStructureRedoReplayRef.current = undefined;
87
+ if (pendingStructureRedoReplayTimerRef.current !== undefined) {
88
+ window.clearTimeout(pendingStructureRedoReplayTimerRef.current);
89
+ pendingStructureRedoReplayTimerRef.current = undefined;
90
+ }
91
+ pendingVisualStyleRedoStackRef.current = [];
92
+ const originalValue =
93
+ details?.originalValue ??
94
+ elementInfo?.textContent ??
95
+ (screenId === activeFile?.id ? selectedElement?.textContent : "") ??
96
+ "";
97
+ const originalHtml =
98
+ details?.originalHtml ??
99
+ elementInfo?.htmlContent ??
100
+ (screenId === activeFile?.id ? selectedElement?.htmlContent : undefined);
101
+ const nextEdit: PendingLiveTextEdit = {
102
+ kind: "text",
103
+ screenId,
104
+ filename: fallbackName,
105
+ screenName: prettyScreenName(fallbackName),
106
+ selector,
107
+ sourceId,
108
+ sourceAnchor: reactSourceAnchorForPendingEdit({
109
+ info: elementInfo,
110
+ id: sourceId ?? undefined,
111
+ rootPath: (() => {
112
+ const connectionId = overviewScreens.find(
113
+ (candidate) => candidate.id === screenId,
114
+ )?.connectionId;
115
+ return connectionId
116
+ ? localhostConnectionRootPathByIdRef.current.get(connectionId)
117
+ : undefined;
118
+ })(),
119
+ runtimeMultiplicity: runtimeMultiplicityForElementProvenance(
120
+ runtimeLayerSnapshotsById,
121
+ elementInfo,
122
+ ),
123
+ }),
124
+ tagName: elementInfo?.tagName ?? null,
125
+ classes: elementInfo?.classes ?? [],
126
+ value,
127
+ html: details?.html,
128
+ originalValue,
129
+ originalHtml,
130
+ updatedAt: Date.now(),
131
+ };
132
+ const revert = pendingLiveTextUndoRevertValue(
133
+ pendingLiveNonStyleEditsRef.current,
134
+ nextEdit,
135
+ );
136
+ pendingLiveNonStyleUndoStackRef.current = [
137
+ ...pendingLiveNonStyleUndoStackRef.current.slice(
138
+ -(MAX_DESIGN_UNDO_STACK - 1),
139
+ ),
140
+ {
141
+ kind: "text",
142
+ edit: nextEdit,
143
+ revertValue: revert.value,
144
+ revertHtml: revert.html,
145
+ },
146
+ ];
147
+ const nextPending = mergePendingLiveNonStyleEdits(
148
+ pendingLiveNonStyleUndoStackRef.current.map((entry) => entry.edit),
149
+ );
150
+ pendingLiveNonStyleEditsRef.current = nextPending;
151
+ setPendingLiveNonStyleEdits(nextPending);
152
+ }