@alpaca-editor/core 1.0.4027 → 1.0.4030

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 (220) hide show
  1. package/dist/components/ActionButton.js +2 -2
  2. package/dist/components/ActionButton.js.map +1 -1
  3. package/dist/components/SimpleLanguageSelector.js +3 -1
  4. package/dist/components/SimpleLanguageSelector.js.map +1 -1
  5. package/dist/components/ui/button.d.ts +1 -1
  6. package/dist/config/config.js +1 -1
  7. package/dist/config/config.js.map +1 -1
  8. package/dist/config/types.d.ts +1 -1
  9. package/dist/editor/ContextMenu.js +0 -1
  10. package/dist/editor/ContextMenu.js.map +1 -1
  11. package/dist/editor/Editor.js +9 -3
  12. package/dist/editor/Editor.js.map +1 -1
  13. package/dist/editor/FieldListField.js +16 -24
  14. package/dist/editor/FieldListField.js.map +1 -1
  15. package/dist/editor/ImageEditButton.js +1 -1
  16. package/dist/editor/ImageEditButton.js.map +1 -1
  17. package/dist/editor/ImageEditor.js +1 -1
  18. package/dist/editor/ImageEditor.js.map +1 -1
  19. package/dist/editor/MainLayout.js +2 -2
  20. package/dist/editor/MainLayout.js.map +1 -1
  21. package/dist/editor/Terminal.js +1 -1
  22. package/dist/editor/Terminal.js.map +1 -1
  23. package/dist/editor/Titlebar.js +0 -1
  24. package/dist/editor/Titlebar.js.map +1 -1
  25. package/dist/editor/ai/AgentCostDisplay.d.ts +26 -0
  26. package/dist/editor/ai/AgentCostDisplay.js +65 -0
  27. package/dist/editor/ai/AgentCostDisplay.js.map +1 -0
  28. package/dist/editor/ai/Agents.js +59 -15
  29. package/dist/editor/ai/Agents.js.map +1 -1
  30. package/dist/editor/ai/AiPromptPopover.d.ts +7 -0
  31. package/dist/editor/ai/AiPromptPopover.js +111 -0
  32. package/dist/editor/ai/AiPromptPopover.js.map +1 -0
  33. package/dist/editor/ai/AiResponseMessage.d.ts +1 -0
  34. package/dist/editor/ai/AiResponseMessage.js +101 -23
  35. package/dist/editor/ai/AiResponseMessage.js.map +1 -1
  36. package/dist/editor/ai/AiTerminal.d.ts +15 -1
  37. package/dist/editor/ai/AiTerminal.js +379 -48
  38. package/dist/editor/ai/AiTerminal.js.map +1 -1
  39. package/dist/editor/ai/editorAiContext.d.ts +0 -1
  40. package/dist/editor/ai/editorAiContext.js +0 -2
  41. package/dist/editor/ai/editorAiContext.js.map +1 -1
  42. package/dist/editor/client/EditorClient.d.ts +3 -2
  43. package/dist/editor/client/EditorClient.js +326 -68
  44. package/dist/editor/client/EditorClient.js.map +1 -1
  45. package/dist/editor/client/editContext.d.ts +6 -4
  46. package/dist/editor/client/editContext.js.map +1 -1
  47. package/dist/editor/client/fieldModificationStore.d.ts +19 -0
  48. package/dist/editor/client/fieldModificationStore.js +125 -0
  49. package/dist/editor/client/fieldModificationStore.js.map +1 -0
  50. package/dist/editor/client/itemsRepository.d.ts +1 -1
  51. package/dist/editor/client/itemsRepository.js +38 -28
  52. package/dist/editor/client/itemsRepository.js.map +1 -1
  53. package/dist/editor/client/operations.d.ts +1 -0
  54. package/dist/editor/client/operations.js +39 -31
  55. package/dist/editor/client/operations.js.map +1 -1
  56. package/dist/editor/commands/componentCommands.js +5 -3
  57. package/dist/editor/commands/componentCommands.js.map +1 -1
  58. package/dist/editor/commands/itemCommands.js.map +1 -1
  59. package/dist/editor/component-designer/aiContext.js +0 -2
  60. package/dist/editor/component-designer/aiContext.js.map +1 -1
  61. package/dist/editor/field-types/DropLinkEditor.js +1 -1
  62. package/dist/editor/field-types/DropLinkEditor.js.map +1 -1
  63. package/dist/editor/field-types/MultiLineText.js +5 -7
  64. package/dist/editor/field-types/MultiLineText.js.map +1 -1
  65. package/dist/editor/field-types/RichTextEditorComponent.js +5 -7
  66. package/dist/editor/field-types/RichTextEditorComponent.js.map +1 -1
  67. package/dist/editor/field-types/SingleLineText.js +5 -7
  68. package/dist/editor/field-types/SingleLineText.js.map +1 -1
  69. package/dist/editor/hooks/useEditorSettings.d.ts +17 -0
  70. package/dist/editor/hooks/useEditorSettings.js +61 -0
  71. package/dist/editor/hooks/useEditorSettings.js.map +1 -0
  72. package/dist/editor/menubar/ItemActionsMenu.js +2 -2
  73. package/dist/editor/menubar/ItemActionsMenu.js.map +1 -1
  74. package/dist/editor/menubar/PageSelector.js +1 -1
  75. package/dist/editor/menubar/PageSelector.js.map +1 -1
  76. package/dist/editor/menubar/toolbar-sections/EditControls.js +1 -1
  77. package/dist/editor/menubar/toolbar-sections/EditControls.js.map +1 -1
  78. package/dist/editor/menubar/toolbar-sections/InsertControls.js +1 -1
  79. package/dist/editor/menubar/toolbar-sections/InsertControls.js.map +1 -1
  80. package/dist/editor/menubar/toolbar-sections/UtilityControls.js +1 -1
  81. package/dist/editor/menubar/toolbar-sections/UtilityControls.js.map +1 -1
  82. package/dist/editor/menubar/toolbar-sections/ViewportControls.js +1 -1
  83. package/dist/editor/menubar/toolbar-sections/ViewportControls.js.map +1 -1
  84. package/dist/editor/page-editor-chrome/FieldEditedIndicators.js +4 -3
  85. package/dist/editor/page-editor-chrome/FieldEditedIndicators.js.map +1 -1
  86. package/dist/editor/page-editor-chrome/FrameMenu.js +9 -1
  87. package/dist/editor/page-editor-chrome/FrameMenu.js.map +1 -1
  88. package/dist/editor/page-editor-chrome/useInlineAICompletion.js +0 -1
  89. package/dist/editor/page-editor-chrome/useInlineAICompletion.js.map +1 -1
  90. package/dist/editor/page-viewer/EditorForm.js +1 -1
  91. package/dist/editor/page-viewer/EditorForm.js.map +1 -1
  92. package/dist/editor/page-viewer/PageViewer.js +9 -8
  93. package/dist/editor/page-viewer/PageViewer.js.map +1 -1
  94. package/dist/editor/page-viewer/PageViewerFrame.js +7 -1
  95. package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
  96. package/dist/editor/page-viewer/pageViewContext.js +40 -6
  97. package/dist/editor/page-viewer/pageViewContext.js.map +1 -1
  98. package/dist/editor/reviews/Comment.js +7 -6
  99. package/dist/editor/reviews/Comment.js.map +1 -1
  100. package/dist/editor/services/agentService.d.ts +84 -12
  101. package/dist/editor/services/agentService.js +256 -15
  102. package/dist/editor/services/agentService.js.map +1 -1
  103. package/dist/editor/services/aiService.d.ts +17 -3
  104. package/dist/editor/services/aiService.js +5 -3
  105. package/dist/editor/services/aiService.js.map +1 -1
  106. package/dist/editor/services/contextService.js +0 -1
  107. package/dist/editor/services/contextService.js.map +1 -1
  108. package/dist/editor/services/systemService.d.ts +2 -1
  109. package/dist/editor/services/systemService.js +3 -0
  110. package/dist/editor/services/systemService.js.map +1 -1
  111. package/dist/editor/sidebar/ComponentPalette.js +1 -1
  112. package/dist/editor/sidebar/ComponentPalette.js.map +1 -1
  113. package/dist/editor/sidebar/EditHistory.js +2 -2
  114. package/dist/editor/sidebar/EditHistory.js.map +1 -1
  115. package/dist/editor/sidebar/GraphQL.d.ts +1 -0
  116. package/dist/editor/sidebar/GraphQL.js +8 -2
  117. package/dist/editor/sidebar/GraphQL.js.map +1 -1
  118. package/dist/editor/sidebar/MainContentTree.js +1 -1
  119. package/dist/editor/sidebar/MainContentTree.js.map +1 -1
  120. package/dist/editor/sidebar/SEOInfo.js +1 -1
  121. package/dist/editor/sidebar/SEOInfo.js.map +1 -1
  122. package/dist/editor/sidebar/ViewSelector.d.ts +4 -1
  123. package/dist/editor/sidebar/ViewSelector.js +64 -48
  124. package/dist/editor/sidebar/ViewSelector.js.map +1 -1
  125. package/dist/editor/ui/PerfectTree.js +2 -11
  126. package/dist/editor/ui/PerfectTree.js.map +1 -1
  127. package/dist/editor/ui/SimpleIconButton.d.ts +2 -0
  128. package/dist/editor/ui/SimpleIconButton.js +8 -4
  129. package/dist/editor/ui/SimpleIconButton.js.map +1 -1
  130. package/dist/index.d.ts +2 -0
  131. package/dist/index.js +2 -0
  132. package/dist/index.js.map +1 -1
  133. package/dist/page-wizard/steps/CollectStep.js +1 -1
  134. package/dist/page-wizard/steps/CollectStep.js.map +1 -1
  135. package/dist/page-wizard/steps/StructureStep.js +1 -1
  136. package/dist/page-wizard/steps/StructureStep.js.map +1 -1
  137. package/dist/page-wizard/steps/TranslateStep.js +233 -18
  138. package/dist/page-wizard/steps/TranslateStep.js.map +1 -1
  139. package/dist/revision.d.ts +2 -2
  140. package/dist/revision.js +2 -2
  141. package/dist/splash-screen/RecentPages.js +1 -13
  142. package/dist/splash-screen/RecentPages.js.map +1 -1
  143. package/dist/splash-screen/SplashScreen.js +1 -1
  144. package/dist/splash-screen/SplashScreen.js.map +1 -1
  145. package/dist/styles.css +88 -3
  146. package/dist/types.d.ts +6 -0
  147. package/package.json +2 -2
  148. package/src/components/ActionButton.tsx +3 -2
  149. package/src/components/SimpleLanguageSelector.tsx +6 -1
  150. package/src/config/config.tsx +1 -1
  151. package/src/config/types.ts +1 -1
  152. package/src/editor/ContextMenu.tsx +0 -3
  153. package/src/editor/Editor.tsx +11 -3
  154. package/src/editor/FieldListField.tsx +22 -31
  155. package/src/editor/ImageEditButton.tsx +1 -0
  156. package/src/editor/ImageEditor.tsx +1 -0
  157. package/src/editor/MainLayout.tsx +2 -2
  158. package/src/editor/Terminal.tsx +1 -1
  159. package/src/editor/Titlebar.tsx +0 -2
  160. package/src/editor/ai/AgentCostDisplay.tsx +237 -0
  161. package/src/editor/ai/Agents.tsx +69 -20
  162. package/src/editor/ai/AiPromptPopover.tsx +209 -0
  163. package/src/editor/ai/AiResponseMessage.tsx +201 -60
  164. package/src/editor/ai/AiTerminal.tsx +502 -71
  165. package/src/editor/ai/editorAiContext.ts +0 -3
  166. package/src/editor/client/EditorClient.tsx +409 -117
  167. package/src/editor/client/editContext.ts +7 -5
  168. package/src/editor/client/fieldModificationStore.ts +196 -0
  169. package/src/editor/client/itemsRepository.ts +41 -31
  170. package/src/editor/client/operations.ts +95 -76
  171. package/src/editor/commands/componentCommands.tsx +9 -3
  172. package/src/editor/commands/itemCommands.tsx +0 -1
  173. package/src/editor/component-designer/aiContext.ts +0 -2
  174. package/src/editor/field-types/DropLinkEditor.tsx +1 -1
  175. package/src/editor/field-types/MultiLineText.tsx +9 -9
  176. package/src/editor/field-types/RichTextEditorComponent.tsx +8 -8
  177. package/src/editor/field-types/SingleLineText.tsx +9 -9
  178. package/src/editor/hooks/useEditorSettings.ts +68 -0
  179. package/src/editor/menubar/ItemActionsMenu.tsx +3 -2
  180. package/src/editor/menubar/PageSelector.tsx +1 -1
  181. package/src/editor/menubar/toolbar-sections/EditControls.tsx +1 -0
  182. package/src/editor/menubar/toolbar-sections/InsertControls.tsx +1 -0
  183. package/src/editor/menubar/toolbar-sections/UtilityControls.tsx +2 -0
  184. package/src/editor/menubar/toolbar-sections/ViewportControls.tsx +2 -0
  185. package/src/editor/page-editor-chrome/FieldEditedIndicators.tsx +4 -3
  186. package/src/editor/page-editor-chrome/FrameMenu.tsx +10 -1
  187. package/src/editor/page-editor-chrome/useInlineAICompletion.tsx +0 -1
  188. package/src/editor/page-viewer/EditorForm.tsx +1 -0
  189. package/src/editor/page-viewer/PageViewer.tsx +9 -8
  190. package/src/editor/page-viewer/PageViewerFrame.tsx +7 -1
  191. package/src/editor/page-viewer/pageViewContext.ts +40 -5
  192. package/src/editor/reviews/Comment.tsx +7 -7
  193. package/src/editor/services/agentService.ts +405 -31
  194. package/src/editor/services/aiService.ts +22 -5
  195. package/src/editor/services/contextService.ts +0 -1
  196. package/src/editor/services/systemService.ts +7 -1
  197. package/src/editor/sidebar/ComponentPalette.tsx +4 -1
  198. package/src/editor/sidebar/EditHistory.tsx +2 -0
  199. package/src/editor/sidebar/GraphQL.tsx +19 -7
  200. package/src/editor/sidebar/MainContentTree.tsx +1 -1
  201. package/src/editor/sidebar/SEOInfo.tsx +1 -1
  202. package/src/editor/sidebar/ViewSelector.tsx +80 -64
  203. package/src/editor/ui/PerfectTree.tsx +2 -18
  204. package/src/editor/ui/SimpleIconButton.tsx +56 -38
  205. package/src/index.ts +2 -0
  206. package/src/page-wizard/steps/CollectStep.tsx +0 -2
  207. package/src/page-wizard/steps/StructureStep.tsx +3 -0
  208. package/src/page-wizard/steps/TranslateStep.tsx +473 -62
  209. package/src/revision.ts +2 -2
  210. package/src/splash-screen/RecentPages.tsx +0 -14
  211. package/src/splash-screen/SplashScreen.tsx +3 -2
  212. package/src/types.ts +7 -0
  213. package/dist/editor/ai/AiPopup.d.ts +0 -10
  214. package/dist/editor/ai/AiPopup.js +0 -23
  215. package/dist/editor/ai/AiPopup.js.map +0 -1
  216. package/dist/editor/ai/AiToolCall.d.ts +0 -5
  217. package/dist/editor/ai/AiToolCall.js +0 -28
  218. package/dist/editor/ai/AiToolCall.js.map +0 -1
  219. package/src/editor/ai/AiPopup.tsx +0 -59
  220. package/src/editor/ai/AiToolCall.tsx +0 -71
@@ -23,8 +23,10 @@ import {
23
23
  SelectionRange,
24
24
  EditorMode,
25
25
  } from "./editContext";
26
+ import { fieldModificationStore } from "./fieldModificationStore";
26
27
 
27
28
  import type { OpenDialog } from "./editContext";
29
+ import type { AiTerminalOptions } from "../ai/AiTerminal";
28
30
 
29
31
  import { EditorConfiguration, MenuItem } from "../../config/types";
30
32
  import { useRouter, useSearchParams, usePathname } from "next/navigation";
@@ -67,7 +69,7 @@ import { EditContextMenu, EditContextMenuRef } from "../ContextMenu";
67
69
  import { FieldEditorPopup, FieldEditorPopupRef } from "../FieldEditorPopup";
68
70
 
69
71
  import { Command, CommandData } from "../commands/commands";
70
- import { AiPopup, AiPopupRef } from "../ai/AiPopup";
72
+
71
73
  import {
72
74
  EditorFormPopup,
73
75
  EditorFormPopupRef,
@@ -90,6 +92,7 @@ import {
90
92
  SuggestedEdit,
91
93
  UserInfo,
92
94
  UserPreferences,
95
+ EditorSettings,
93
96
  } from "../../types";
94
97
 
95
98
  import { post } from "../services/serviceHelper";
@@ -120,7 +123,6 @@ import { Tour } from "../../tour/Tour";
120
123
  import { usePageViewContext } from "../page-viewer/pageViewContext";
121
124
 
122
125
  import { getComments } from "../services/reviewsService";
123
- import { AiTerminalOptions } from "../ai/AiTerminal";
124
126
  import { useReviews } from "../reviews/useReviews";
125
127
  import uuid from "react-uuid";
126
128
  import { flushSync } from "react-dom";
@@ -173,6 +175,7 @@ export function EditorClient({
173
175
  sessionId,
174
176
  userInfo,
175
177
  userPreferences,
178
+ editorSettings,
176
179
  setUserPreferences,
177
180
  children,
178
181
  }: {
@@ -182,6 +185,7 @@ export function EditorClient({
182
185
  sessionId: string;
183
186
  userInfo: UserInfo;
184
187
  userPreferences: UserPreferences;
188
+ editorSettings?: EditorSettings;
185
189
  setUserPreferences: (preferences: Partial<UserPreferences>) => void;
186
190
  children?: React.ReactNode;
187
191
  }) {
@@ -225,7 +229,6 @@ export function EditorClient({
225
229
  );
226
230
  const [renderedFields, setRenderedFields] = useState<FieldDescriptor[]>([]);
227
231
 
228
- const aiPopupRef = React.useRef<AiPopupRef>(null);
229
232
  const fieldEditorPopupRef = React.useRef<FieldEditorPopupRef>(null);
230
233
  const editorFormPopupRef = React.useRef<EditorFormPopupRef>(null);
231
234
 
@@ -235,7 +238,23 @@ export function EditorClient({
235
238
 
236
239
  const [editHistory, setEditHistory] = useState<EditOperation[]>([]);
237
240
 
238
- const [lastEditedFields, setLastEditedFields] = useState<EditedField[]>([]);
241
+ const [recentEdits, setRecentEdits] = useState<EditedField[]>([]);
242
+
243
+ const addRecentEdit = useCallback((edit: EditedField) => {
244
+ setRecentEdits((prevEditedFields) => {
245
+ return [
246
+ ...prevEditedFields.filter(
247
+ (x) =>
248
+ x.timestamp > Date.now() - 30000 &&
249
+ (x.fieldId !== edit.fieldId ||
250
+ x.item.id !== edit.item.id ||
251
+ x.item.language !== edit.item.language ||
252
+ x.item.version !== edit.item.version),
253
+ ),
254
+ edit,
255
+ ];
256
+ });
257
+ }, []);
239
258
 
240
259
  const [activeSessions, setActiveSessions] = useState<EditSession[]>([]);
241
260
 
@@ -385,10 +404,7 @@ export function EditorClient({
385
404
  }
386
405
  }, [selection]);
387
406
 
388
- const itemsRepository = useItemsRepository(
389
- setModifiedFields,
390
- setLastEditedFields,
391
- );
407
+ const itemsRepository = useItemsRepository(setModifiedFields, addRecentEdit);
392
408
 
393
409
  const pageViewContext = usePageViewContext({
394
410
  pageItemDescriptor: currentItemDescriptor,
@@ -398,12 +414,13 @@ export function EditorClient({
398
414
 
399
415
  const socketMessageListeners = useRef<Set<(data: any) => void>>(new Set());
400
416
 
401
- const addSocketMessageListener = (
402
- callback: (message: { type: string; payload: any }) => void,
403
- ) => {
404
- socketMessageListeners.current.add(callback);
405
- return () => socketMessageListeners.current.delete(callback);
406
- };
417
+ const addSocketMessageListener = useCallback(
418
+ (callback: (message: { type: string; payload: any }) => void) => {
419
+ socketMessageListeners.current.add(callback);
420
+ return () => socketMessageListeners.current.delete(callback);
421
+ },
422
+ [], // No dependencies - only uses ref
423
+ );
407
424
 
408
425
  const reviews = useReviews({
409
426
  currentItemDescriptor: contentEditorItem?.descriptor,
@@ -461,27 +478,33 @@ export function EditorClient({
461
478
  //}
462
479
  };
463
480
 
464
- const startTour = () => {
481
+ const startTour = useCallback(() => {
465
482
  setIsTourActive(true);
466
- };
467
-
468
- const handleSetShowRightSidebar = (
469
- value: boolean | ((prev: boolean) => boolean),
470
- ) => {
471
- const newValue =
472
- typeof value === "function" ? value(showRightSidebar) : value;
473
- setShowRightSidebar(newValue);
474
- setUserPreferences({ showRightSidebar: newValue });
475
- };
483
+ }, [setIsTourActive]);
484
+
485
+ const handleSetShowRightSidebar = useCallback(
486
+ (value: boolean | ((prev: boolean) => boolean)) => {
487
+ const newValue =
488
+ typeof value === "function" ? value(showRightSidebar) : value;
489
+ setShowRightSidebar(newValue);
490
+ setUserPreferences({ showRightSidebar: newValue });
491
+ },
492
+ [showRightSidebar, setShowRightSidebar, setUserPreferences],
493
+ );
476
494
 
477
- const handleSetHideNonEditableComponents = (
478
- value: boolean | ((prev: boolean) => boolean),
479
- ) => {
480
- const newValue =
481
- typeof value === "function" ? value(hideNonEditableComponents) : value;
482
- setHideNonEditableComponents(newValue);
483
- setUserPreferences({ hideNonEditableComponents: newValue });
484
- };
495
+ const handleSetHideNonEditableComponents = useCallback(
496
+ (value: boolean | ((prev: boolean) => boolean)) => {
497
+ const newValue =
498
+ typeof value === "function" ? value(hideNonEditableComponents) : value;
499
+ setHideNonEditableComponents(newValue);
500
+ setUserPreferences({ hideNonEditableComponents: newValue });
501
+ },
502
+ [
503
+ hideNonEditableComponents,
504
+ setHideNonEditableComponents,
505
+ setUserPreferences,
506
+ ],
507
+ );
485
508
 
486
509
  const messageHandler = useCallback(
487
510
  async (event: any) => {
@@ -565,7 +588,6 @@ export function EditorClient({
565
588
  if (currentItemDescriptorRef.current) {
566
589
  if (currentItemDescriptorRef.current.id === message.payload.item.id)
567
590
  await loadItemVersions();
568
- setCurrentItemDescriptor({ ...currentItemDescriptorRef.current });
569
591
  }
570
592
  }
571
593
 
@@ -735,10 +757,13 @@ export function EditorClient({
735
757
 
736
758
  socketMessageListeners.current.forEach((listener) => listener(message));
737
759
  },
738
- [currentItemDescriptorRef, setLastEditedFields],
760
+ [currentItemDescriptorRef, addRecentEdit],
739
761
  );
740
762
 
741
- const user = activeSessions.find((x) => x.sessionId === sessionId)?.user;
763
+ const user = useMemo(
764
+ () => activeSessions.find((x) => x.sessionId === sessionId)?.user,
765
+ [activeSessions, sessionId],
766
+ );
742
767
 
743
768
  useEffect(() => {
744
769
  if (typeof window === "undefined") return;
@@ -883,7 +908,7 @@ export function EditorClient({
883
908
  tour === "default" ? "editor.tourShown" : "editor.tourShown." + tour;
884
909
  const tourShown = localStorage.getItem(key);
885
910
 
886
- if (user?.isLimitedPreviewUser && !tourShown) {
911
+ if (!tourShown) {
887
912
  startTour();
888
913
  localStorage.setItem(key, "true");
889
914
  }
@@ -1023,7 +1048,7 @@ export function EditorClient({
1023
1048
  // Set a small timeout to ensure all initial state setting effects have run
1024
1049
  const timer = setTimeout(() => {
1025
1050
  setIsInitialLoad(false);
1026
- console.log("🔗 INITIAL LOAD COMPLETE - State now drives URL updates");
1051
+ //console.log("🔗 INITIAL LOAD COMPLETE - State now drives URL updates");
1027
1052
  }, 100);
1028
1053
  return () => clearTimeout(timer);
1029
1054
  }
@@ -1073,7 +1098,7 @@ export function EditorClient({
1073
1098
  useEffect(() => {
1074
1099
  setRefreshCompletedFlag(!refreshCompletedFlag);
1075
1100
  setInserting(undefined);
1076
- }, [currentItemDescriptor, pageViewContext.page]);
1101
+ }, [currentItemDescriptor, pageViewContext.page?.item.id]);
1077
1102
 
1078
1103
  useEffect(() => {
1079
1104
  sendClientInfo();
@@ -1198,7 +1223,7 @@ export function EditorClient({
1198
1223
  );
1199
1224
  }
1200
1225
  },
1201
- [contentEditorItem, router],
1226
+ [],
1202
1227
  );
1203
1228
 
1204
1229
  useEffect(() => {
@@ -1257,12 +1282,6 @@ export function EditorClient({
1257
1282
  current.set("version", currentItemDescriptor.version.toString());
1258
1283
  }
1259
1284
  if (current.get("view") !== viewName) {
1260
- console.log(
1261
- "EditorClient: Updating view from",
1262
- current.get("view"),
1263
- "to",
1264
- viewName,
1265
- );
1266
1285
  current.set("view", viewName);
1267
1286
  }
1268
1287
  if (!compareMode) {
@@ -1425,33 +1444,6 @@ export function EditorClient({
1425
1444
  setShowFullscreenHint(true);
1426
1445
  }, [pageViewContext.fullscreen]);
1427
1446
 
1428
- const executeCommand = useCallback(
1429
- async <T extends CommandData>({
1430
- command,
1431
- event,
1432
- data,
1433
- }: {
1434
- command: Command<T>;
1435
- data?: any;
1436
- event?: React.SyntheticEvent;
1437
- }): Promise<any> => {
1438
- if (!editContextRef.current) return;
1439
- const context = {
1440
- editContext: editContextRef.current,
1441
- pathname,
1442
- router,
1443
- searchParams,
1444
- openDialog: openDialog,
1445
- event,
1446
- data,
1447
- };
1448
- const result = await command.execute(context);
1449
-
1450
- return result;
1451
- },
1452
- [editContextRef, pathname, router, searchParams],
1453
- );
1454
-
1455
1447
  const state = useMemo(
1456
1448
  () => ({
1457
1449
  page,
@@ -1473,6 +1465,7 @@ export function EditorClient({
1473
1465
  setSuggestedEdits,
1474
1466
  mode,
1475
1467
  setFocusFieldComponentId,
1468
+ setInsertMode,
1476
1469
  }),
1477
1470
  [
1478
1471
  page,
@@ -1494,11 +1487,11 @@ export function EditorClient({
1494
1487
  setSuggestedEdits,
1495
1488
  mode,
1496
1489
  setFocusFieldComponentId,
1490
+ setInsertMode,
1497
1491
  ],
1498
1492
  );
1499
1493
 
1500
1494
  useEffect(() => {
1501
- if (currentOverlay !== "ai") aiPopupRef.current?.close();
1502
1495
  if (currentOverlay !== "fields") fieldEditorPopupRef.current?.close();
1503
1496
  if (currentOverlay !== "context-menu") contextMenuRef.current?.close({});
1504
1497
  }, [currentOverlay]);
@@ -1546,31 +1539,36 @@ export function EditorClient({
1546
1539
  [],
1547
1540
  );
1548
1541
 
1542
+ const onOperationExecuted = useCallback(
1543
+ (op: EditOperation) => {
1544
+ // Replace the operation in edit history with the executed operation
1545
+
1546
+ setEditHistory((prev) => {
1547
+ const existingOpIndex = prev.findIndex((x) => x.id === op.id);
1548
+ if (existingOpIndex >= 0) {
1549
+ prev[existingOpIndex] = op;
1550
+ }
1551
+ return prev;
1552
+ });
1553
+
1554
+ if (
1555
+ contentEditorItem?.id === op.mainItem?.id &&
1556
+ contentEditorItem?.language === op.mainItem?.language &&
1557
+ contentEditorItem?.version === op.mainItem?.version
1558
+ ) {
1559
+ setInsertMode(false);
1560
+ }
1561
+ },
1562
+ [contentEditorItem, setEditHistory, setInsertMode],
1563
+ );
1564
+
1549
1565
  const ui = useMemo(
1550
1566
  () => ({
1551
1567
  showErrorToast,
1552
1568
  confirmationDialogRef,
1553
- onOperationExecuted: (op: EditOperation) => {
1554
- // Replace the operation in edit history with the executed operation
1555
-
1556
- setEditHistory((prev) => {
1557
- const existingOpIndex = prev.findIndex((x) => x.id === op.id);
1558
- if (existingOpIndex >= 0) {
1559
- prev[existingOpIndex] = op;
1560
- }
1561
- return prev;
1562
- });
1563
-
1564
- if (
1565
- contentEditorItem?.id === op.mainItem?.id &&
1566
- contentEditorItem?.language === op.mainItem?.language &&
1567
- contentEditorItem?.version === op.mainItem?.version
1568
- ) {
1569
- setInsertMode(false);
1570
- }
1571
- },
1569
+ onOperationExecuted,
1572
1570
  }),
1573
- [showErrorToast, confirmationDialogRef, currentItemDescriptor],
1571
+ [showErrorToast, confirmationDialogRef, onOperationExecuted],
1574
1572
  );
1575
1573
 
1576
1574
  const selectMedia = useCallback(
@@ -1703,16 +1701,48 @@ export function EditorClient({
1703
1701
 
1704
1702
  const [dialog, setDialog] = useState<ReactNode>(null);
1705
1703
 
1706
- const openDialog: OpenDialog = (Component, props) => {
1707
- return new Promise((resolve) => {
1708
- const handleClose = (result: any) => {
1709
- setDialog(null);
1710
- resolve(result);
1704
+ const openDialog: OpenDialog = useCallback(
1705
+ (Component, props) => {
1706
+ return new Promise((resolve) => {
1707
+ const handleClose = (result: any) => {
1708
+ setDialog(null);
1709
+ resolve(result);
1710
+ };
1711
+
1712
+ setDialog(<Component {...(props as any)} onClose={handleClose} />);
1713
+ });
1714
+ },
1715
+ [setDialog],
1716
+ );
1717
+
1718
+ const executeCommand = useCallback(
1719
+ async <T extends CommandData>({
1720
+ command,
1721
+ event,
1722
+ data,
1723
+ }: {
1724
+ command: Command<T>;
1725
+ data?: any;
1726
+ event?: React.SyntheticEvent;
1727
+ }): Promise<any> => {
1728
+ if (!editContextRef.current) return;
1729
+
1730
+ const context = {
1731
+ editContext: editContextRef.current,
1732
+ pathname,
1733
+ router,
1734
+ searchParams,
1735
+ openDialog: openDialog,
1736
+ event,
1737
+ data,
1711
1738
  };
1712
1739
 
1713
- setDialog(<Component {...(props as any)} onClose={handleClose} />);
1714
- });
1715
- };
1740
+ const result = await command.execute(context);
1741
+
1742
+ return result;
1743
+ },
1744
+ [editContextRef, pathname, router, searchParams, openDialog],
1745
+ );
1716
1746
 
1717
1747
  const operationsContext = getOperationsContext(state, ui);
1718
1748
 
@@ -1839,8 +1869,44 @@ export function EditorClient({
1839
1869
  }
1840
1870
  }, [quotaInfo, getQuotaWarningMessage, isQuotaExceeded, showErrorToast]);
1841
1871
 
1872
+ // Calculate visible views separately to avoid circular dependency
1873
+ const visibleViews = useMemo(() => {
1874
+ const allViews =
1875
+ configuration.editor.views
1876
+ ?.filter((x) => {
1877
+ // For this calculation, we'll pass null for editContext since we're building it
1878
+ // The visibility check will be recalculated after editContext is available
1879
+ return !x.visible && !x.hidden;
1880
+ })
1881
+ .filter(
1882
+ (x) =>
1883
+ !userInfo.views ||
1884
+ userInfo.views.map((view) => view.name).includes(x.name),
1885
+ ) ?? [];
1886
+
1887
+ const pinnedViews =
1888
+ userInfo.preferences?.pinnedViews ||
1889
+ configuration.editor.defaultPinnedViews ||
1890
+ [];
1891
+
1892
+ return allViews.filter(
1893
+ (view) =>
1894
+ // Always show selected view
1895
+ view.name === viewName ||
1896
+ // Show pinned views
1897
+ pinnedViews.includes(view.name),
1898
+ );
1899
+ }, [
1900
+ configuration.editor.views,
1901
+ userInfo.views,
1902
+ userInfo.preferences?.pinnedViews,
1903
+ configuration.editor.defaultPinnedViews,
1904
+ viewName,
1905
+ ]);
1906
+
1842
1907
  const editContext = useMemo(() => {
1843
- return {
1908
+ // console.log('🔄 EditContext useMemo is being recalculated');
1909
+ const context = {
1844
1910
  operations: operationsContext.ops,
1845
1911
  itemsRepository,
1846
1912
  configuration,
@@ -2081,13 +2147,7 @@ export function EditorClient({
2081
2147
  contextMenuRef.current?.show(event, items);
2082
2148
  setCurrentOverlay("context-menu");
2083
2149
  },
2084
- showAiPopup: (
2085
- event: MouseEvent<HTMLElement>,
2086
- aiTerminalOptions?: AiTerminalOptions,
2087
- ) => {
2088
- setCurrentOverlay("ai");
2089
- aiPopupRef.current?.show(event, aiTerminalOptions);
2090
- },
2150
+
2091
2151
  showFieldEditorPopup: (fields: Field[], sections: string[], ev: any) => {
2092
2152
  setCurrentOverlay("fields");
2093
2153
  fieldEditorPopupRef.current?.show(fields, sections, ev);
@@ -2099,6 +2159,7 @@ export function EditorClient({
2099
2159
  setCurrentOverlay("editor-form");
2100
2160
  editorFormPopupRef.current?.show(event, activeTab);
2101
2161
  },
2162
+
2102
2163
  inserting,
2103
2164
  validating,
2104
2165
  validationResult,
@@ -2135,6 +2196,7 @@ export function EditorClient({
2135
2196
  compareMode,
2136
2197
  setCompareMode,
2137
2198
  view: currentView,
2199
+ visibleViews,
2138
2200
  pageView: pageViewContext,
2139
2201
  componentDesignerComponent,
2140
2202
  setComponentDesignerComponent,
@@ -2171,7 +2233,6 @@ export function EditorClient({
2171
2233
  currentItemDescriptor,
2172
2234
  compareTo,
2173
2235
  setCompareTo,
2174
- lastEditedFields,
2175
2236
  revision,
2176
2237
  selectedComment,
2177
2238
  setSelectedComment,
@@ -2260,6 +2321,7 @@ export function EditorClient({
2260
2321
  webSocketMessages,
2261
2322
  clearWebSocketMessages: () => setWebSocketMessages([]),
2262
2323
  userInfo: userInfo,
2324
+ editorSettings,
2263
2325
  userPreferences,
2264
2326
  setUserPreferences,
2265
2327
  currentWizardId,
@@ -2267,6 +2329,8 @@ export function EditorClient({
2267
2329
  favorites,
2268
2330
  loadFavorites,
2269
2331
  };
2332
+
2333
+ return context;
2270
2334
  }, [
2271
2335
  operations,
2272
2336
  itemsRepository,
@@ -2319,7 +2383,6 @@ export function EditorClient({
2319
2383
  currentItemDescriptor,
2320
2384
  compareTo,
2321
2385
  setCompareTo,
2322
- lastEditedFields,
2323
2386
  revision,
2324
2387
  comments,
2325
2388
  setComments,
@@ -2355,20 +2418,250 @@ export function EditorClient({
2355
2418
  setCurrentWizardId,
2356
2419
  favorites,
2357
2420
  loadFavorites,
2421
+ userInfo,
2422
+ editorSettings,
2423
+ visibleViews,
2358
2424
  ]);
2359
2425
 
2426
+ // CRITICAL: Assign editContext to ref so keyboard handlers can access it
2427
+ useEffect(() => {
2428
+ editContextRef.current = editContext;
2429
+ }, [editContext]);
2430
+
2360
2431
  const modifiedFieldsContext = useMemo(() => {
2361
2432
  return {
2362
2433
  modifiedFields,
2434
+ recentEdits,
2363
2435
  clear: () => {
2364
2436
  setModifiedFields([]);
2437
+ fieldModificationStore.clear();
2438
+ },
2439
+ clearRecentEdits: () => {
2440
+ setRecentEdits([]);
2365
2441
  },
2442
+ addRecentEdit,
2366
2443
  };
2367
- }, [modifiedFields, setModifiedFields]);
2444
+ }, [modifiedFields, recentEdits, addRecentEdit]);
2368
2445
 
2369
- useEffect(() => {
2370
- editContextRef.current = editContext;
2371
- }, [editContext]);
2446
+ // Debug: Track editContext changes
2447
+ const prevDependencies = useRef<any[]>([]);
2448
+
2449
+ // useEffect(() => {
2450
+ // // Create current dependencies array to match the useMemo dependency array
2451
+ // const currentDependencies = [
2452
+ // operations,
2453
+ // itemsRepository,
2454
+ // configuration,
2455
+ // contentEditorItem,
2456
+ // page?.item,
2457
+ // itemLanguages,
2458
+ // itemVersions,
2459
+ // sessionId,
2460
+ // isReadOnly,
2461
+ // selection,
2462
+ // selectedForInsertion,
2463
+ // dragObject,
2464
+ // requestRefresh,
2465
+ // refreshCompletedFlag,
2466
+ // searchParams,
2467
+ // pathname,
2468
+ // router,
2469
+ // selectMedia,
2470
+ // scrollIntoView,
2471
+ // focusedField,
2472
+ // renderedFields,
2473
+ // inserting,
2474
+ // page,
2475
+ // activeFieldActions,
2476
+ // editHistory,
2477
+ // isRefreshing,
2478
+ // activeSessions,
2479
+ // currentView,
2480
+ // componentDesignerComponent,
2481
+ // componentDesignerRendering,
2482
+ // insertMode,
2483
+ // currentOverlay,
2484
+ // inlineEditingFieldElement,
2485
+ // lockedField,
2486
+ // selectedRange,
2487
+ // pageViewContext,
2488
+ // browseHistory,
2489
+ // workboxItems,
2490
+ // validating,
2491
+ // setCenterPanelView,
2492
+ // handleKeyDown,
2493
+ // setTimings,
2494
+ // timings,
2495
+ // startTour,
2496
+ // viewName,
2497
+ // compareMode,
2498
+ // setCompareMode,
2499
+ // addSocketMessageListener,
2500
+ // currentItemDescriptor,
2501
+ // compareTo,
2502
+ // setCompareTo,
2503
+ // revision,
2504
+ // comments,
2505
+ // setComments,
2506
+ // selectedComment,
2507
+ // setSelectedComment,
2508
+ // loadComments,
2509
+ // mode,
2510
+ // setMode,
2511
+ // user,
2512
+ // reviews,
2513
+ // statusMessage,
2514
+ // setStatusMessage,
2515
+ // suggestedEdits,
2516
+ // setSuggestedEdits,
2517
+ // showSuggestedEdits,
2518
+ // setShowSuggestedEdits,
2519
+ // showSuggestedEditsDiff,
2520
+ // setShowSuggestedEditsDiff,
2521
+ // showRightSidebar,
2522
+ // handleSetShowRightSidebar,
2523
+ // activeEditorTab,
2524
+ // setActiveEditorTab,
2525
+ // hideNonEditableComponents,
2526
+ // handleSetHideNonEditableComponents,
2527
+ // quotaInfo,
2528
+ // isQuotaExceeded,
2529
+ // getQuotaWarningMessage,
2530
+ // isMobile,
2531
+ // openDialog,
2532
+ // pageWizard,
2533
+ // webSocketMessages,
2534
+ // currentWizardId,
2535
+ // setCurrentWizardId,
2536
+ // favorites,
2537
+ // loadFavorites,
2538
+ // ];
2539
+
2540
+ // const dependencyNames = [
2541
+ // 'operations',
2542
+ // 'itemsRepository',
2543
+ // 'configuration',
2544
+ // 'contentEditorItem',
2545
+ // 'page?.item',
2546
+ // 'itemLanguages',
2547
+ // 'itemVersions',
2548
+ // 'sessionId',
2549
+ // 'isReadOnly',
2550
+ // 'selection',
2551
+ // 'selectedForInsertion',
2552
+ // 'dragObject',
2553
+ // 'requestRefresh',
2554
+ // 'refreshCompletedFlag',
2555
+ // 'searchParams',
2556
+ // 'pathname',
2557
+ // 'router',
2558
+ // 'selectMedia',
2559
+ // 'scrollIntoView',
2560
+ // 'focusedField',
2561
+ // 'renderedFields',
2562
+ // 'inserting',
2563
+ // 'page',
2564
+ // 'activeFieldActions',
2565
+ // 'editHistory',
2566
+ // 'isRefreshing',
2567
+ // 'activeSessions',
2568
+ // 'currentView',
2569
+ // 'componentDesignerComponent',
2570
+ // 'componentDesignerRendering',
2571
+ // 'insertMode',
2572
+ // 'currentOverlay',
2573
+ // 'inlineEditingFieldElement',
2574
+ // 'lockedField',
2575
+ // 'selectedRange',
2576
+ // 'pageViewContext',
2577
+ // 'browseHistory',
2578
+ // 'workboxItems',
2579
+ // 'validating',
2580
+ // 'setCenterPanelView',
2581
+ // 'handleKeyDown',
2582
+ // 'setTimings',
2583
+ // 'timings',
2584
+ // 'startTour',
2585
+ // 'viewName',
2586
+ // 'compareMode',
2587
+ // 'setCompareMode',
2588
+ // 'addSocketMessageListener',
2589
+ // 'currentItemDescriptor',
2590
+ // 'compareTo',
2591
+ // 'setCompareTo',
2592
+ // 'revision',
2593
+ // 'comments',
2594
+ // 'setComments',
2595
+ // 'selectedComment',
2596
+ // 'setSelectedComment',
2597
+ // 'loadComments',
2598
+ // 'mode',
2599
+ // 'setMode',
2600
+ // 'user',
2601
+ // 'reviews',
2602
+ // 'statusMessage',
2603
+ // 'setStatusMessage',
2604
+ // 'suggestedEdits',
2605
+ // 'setSuggestedEdits',
2606
+ // 'showSuggestedEdits',
2607
+ // 'setShowSuggestedEdits',
2608
+ // 'showSuggestedEditsDiff',
2609
+ // 'setShowSuggestedEditsDiff',
2610
+ // 'showRightSidebar',
2611
+ // 'handleSetShowRightSidebar',
2612
+ // 'activeEditorTab',
2613
+ // 'setActiveEditorTab',
2614
+ // 'hideNonEditableComponents',
2615
+ // 'handleSetHideNonEditableComponents',
2616
+ // 'quotaInfo',
2617
+ // 'isQuotaExceeded',
2618
+ // 'getQuotaWarningMessage',
2619
+ // 'isMobile',
2620
+ // 'openDialog',
2621
+ // 'pageWizard',
2622
+ // 'webSocketMessages',
2623
+ // 'currentWizardId',
2624
+ // 'setCurrentWizardId',
2625
+ // 'favorites',
2626
+ // 'loadFavorites',
2627
+ // ];
2628
+
2629
+ // // Check which dependencies have changed
2630
+ // const changedDependencies: string[] = [];
2631
+ // currentDependencies.forEach((dep, index) => {
2632
+ // if (prevDependencies.current[index] !== dep) {
2633
+ // const depName = dependencyNames[index];
2634
+ // if (depName) {
2635
+ // changedDependencies.push(depName);
2636
+ // }
2637
+ // }
2638
+ // });
2639
+
2640
+ // if (changedDependencies.length > 0) {
2641
+ // console.group('🔍 EditContext Changed');
2642
+ // console.log('Changed dependencies:', changedDependencies);
2643
+ // console.log('Total dependencies tracked:', currentDependencies.length);
2644
+
2645
+ // // Log details about the changed dependencies
2646
+ // changedDependencies.forEach(depName => {
2647
+ // const index = dependencyNames.indexOf(depName);
2648
+ // const oldValue = prevDependencies.current[index];
2649
+ // const newValue = currentDependencies[index];
2650
+
2651
+ // console.log(`📝 ${depName}:`, {
2652
+ // from: oldValue,
2653
+ // to: newValue,
2654
+ // changed: oldValue !== newValue
2655
+ // });
2656
+ // });
2657
+
2658
+ // console.groupEnd();
2659
+ // }
2660
+
2661
+ // // Store current dependencies for next comparison
2662
+ // prevDependencies.current = currentDependencies;
2663
+ // editContextRef.current = editContext;
2664
+ // }, [editContext]);
2372
2665
 
2373
2666
  useEffect(() => {
2374
2667
  modifiedFieldsContext.clear();
@@ -2462,7 +2755,6 @@ export function EditorClient({
2462
2755
  mode={mediaSelectorMode}
2463
2756
  />
2464
2757
  )}
2465
- <AiPopup ref={aiPopupRef} />
2466
2758
  <FieldEditorPopup ref={fieldEditorPopupRef} />
2467
2759
  <EditorFormPopup
2468
2760
  ref={editorFormPopupRef}