@parhelia/core 0.1.12926 → 0.1.12928

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 (138) hide show
  1. package/dist/client-components/index.d.ts +1 -1
  2. package/dist/client-components/index.js +1 -1
  3. package/dist/client-components/index.js.map +1 -1
  4. package/dist/components/ui/close-icon.d.ts +6 -1
  5. package/dist/components/ui/close-icon.js +12 -7
  6. package/dist/components/ui/close-icon.js.map +1 -1
  7. package/dist/editor/FieldListField.js +8 -0
  8. package/dist/editor/FieldListField.js.map +1 -1
  9. package/dist/editor/MainLayout.js +2 -1
  10. package/dist/editor/MainLayout.js.map +1 -1
  11. package/dist/editor/PerfProfiler.d.ts +11 -0
  12. package/dist/editor/PerfProfiler.js +29 -0
  13. package/dist/editor/PerfProfiler.js.map +1 -0
  14. package/dist/editor/ai/GuidanceOverlay.js +4 -9
  15. package/dist/editor/ai/GuidanceOverlay.js.map +1 -1
  16. package/dist/editor/ai/InlineAiDialog.js +2 -2
  17. package/dist/editor/ai/InlineAiDialog.js.map +1 -1
  18. package/dist/editor/ai/dialogs/capturePageScreenshot.js +1 -1
  19. package/dist/editor/ai/dialogs/capturePageScreenshot.js.map +1 -1
  20. package/dist/editor/ai/terminal/components/AgentSettingsContent.d.ts +2 -1
  21. package/dist/editor/ai/terminal/components/AgentSettingsContent.js.map +1 -1
  22. package/dist/editor/ai/terminal/components/AgentSettingsSections.d.ts +2 -1
  23. package/dist/editor/ai/terminal/components/AgentSettingsSections.js +9 -2
  24. package/dist/editor/ai/terminal/components/AgentSettingsSections.js.map +1 -1
  25. package/dist/editor/ai/terminal/components/ContextInfoBar.js +4 -3
  26. package/dist/editor/ai/terminal/components/ContextInfoBar.js.map +1 -1
  27. package/dist/editor/ai/terminal/components/TodoListPanel.js +21 -48
  28. package/dist/editor/ai/terminal/components/TodoListPanel.js.map +1 -1
  29. package/dist/editor/ai/terminal/useAgentSettingsData.d.ts +8 -1
  30. package/dist/editor/ai/terminal/useAgentSettingsData.js +42 -3
  31. package/dist/editor/ai/terminal/useAgentSettingsData.js.map +1 -1
  32. package/dist/editor/ai/terminal/useAgentSettingsPanel.d.ts +1 -1
  33. package/dist/editor/bridge/BridgeClient.js +9 -1
  34. package/dist/editor/bridge/BridgeClient.js.map +1 -1
  35. package/dist/editor/bridge/protocol.d.ts +25 -0
  36. package/dist/editor/bridge/protocol.js +1 -1
  37. package/dist/editor/bridge/protocol.js.map +1 -1
  38. package/dist/editor/client/EditorShell.js +156 -20
  39. package/dist/editor/client/EditorShell.js.map +1 -1
  40. package/dist/editor/client/editContext.d.ts +32 -1
  41. package/dist/editor/client/editContext.js +8 -0
  42. package/dist/editor/client/editContext.js.map +1 -1
  43. package/dist/editor/client/errorToast.js +21 -5
  44. package/dist/editor/client/errorToast.js.map +1 -1
  45. package/dist/editor/client/fieldModificationStore.js +64 -0
  46. package/dist/editor/client/fieldModificationStore.js.map +1 -1
  47. package/dist/editor/client/itemsRepository.js +95 -3
  48. package/dist/editor/client/itemsRepository.js.map +1 -1
  49. package/dist/editor/client/operations.d.ts +1 -0
  50. package/dist/editor/client/operations.js +147 -13
  51. package/dist/editor/client/operations.js.map +1 -1
  52. package/dist/editor/client/ui/EditorChrome.js +6 -5
  53. package/dist/editor/client/ui/EditorChrome.js.map +1 -1
  54. package/dist/editor/commands/keyboardCommands.js +1 -1
  55. package/dist/editor/commands/keyboardCommands.js.map +1 -1
  56. package/dist/editor/componentTreeHelper.js +15 -5
  57. package/dist/editor/componentTreeHelper.js.map +1 -1
  58. package/dist/editor/field-types/SingleLineText.js +79 -9
  59. package/dist/editor/field-types/SingleLineText.js.map +1 -1
  60. package/dist/editor/fieldValueDiagnostics.d.ts +79 -0
  61. package/dist/editor/fieldValueDiagnostics.js +133 -0
  62. package/dist/editor/fieldValueDiagnostics.js.map +1 -0
  63. package/dist/editor/menubar/FavoritesControls.js +2 -2
  64. package/dist/editor/menubar/FavoritesControls.js.map +1 -1
  65. package/dist/editor/notifications/NotificationCenter.js +4 -3
  66. package/dist/editor/notifications/NotificationCenter.js.map +1 -1
  67. package/dist/editor/notifications/WatchButton.js +6 -31
  68. package/dist/editor/notifications/WatchButton.js.map +1 -1
  69. package/dist/editor/notifications/watchEventOptions.js +3 -3
  70. package/dist/editor/notifications/watchEventOptions.js.map +1 -1
  71. package/dist/editor/page-editor-chrome/DragInsertionOverlay.js +51 -19
  72. package/dist/editor/page-editor-chrome/DragInsertionOverlay.js.map +1 -1
  73. package/dist/editor/page-editor-chrome/FrameMenu.d.ts +2 -0
  74. package/dist/editor/page-editor-chrome/FrameMenu.js +8 -6
  75. package/dist/editor/page-editor-chrome/FrameMenu.js.map +1 -1
  76. package/dist/editor/page-editor-chrome/FrameMenus.d.ts +3 -1
  77. package/dist/editor/page-editor-chrome/FrameMenus.js +4 -4
  78. package/dist/editor/page-editor-chrome/FrameMenus.js.map +1 -1
  79. package/dist/editor/page-editor-chrome/PageEditorChrome.js +17 -4
  80. package/dist/editor/page-editor-chrome/PageEditorChrome.js.map +1 -1
  81. package/dist/editor/page-editor-chrome/PictureEditorOverlay.js +4 -7
  82. package/dist/editor/page-editor-chrome/PictureEditorOverlay.js.map +1 -1
  83. package/dist/editor/page-editor-chrome/PlaceholderDropZone.d.ts +8 -1
  84. package/dist/editor/page-editor-chrome/PlaceholderDropZone.js +14 -3
  85. package/dist/editor/page-editor-chrome/PlaceholderDropZone.js.map +1 -1
  86. package/dist/editor/page-editor-chrome/PlaceholderDropZones.d.ts +3 -1
  87. package/dist/editor/page-editor-chrome/PlaceholderDropZones.js +2 -2
  88. package/dist/editor/page-editor-chrome/PlaceholderDropZones.js.map +1 -1
  89. package/dist/editor/page-editor-chrome/overlay/placeholderZones.js +43 -1
  90. package/dist/editor/page-editor-chrome/overlay/placeholderZones.js.map +1 -1
  91. package/dist/editor/page-editor-chrome/useBridgeInlineEditing.js +121 -48
  92. package/dist/editor/page-editor-chrome/useBridgeInlineEditing.js.map +1 -1
  93. package/dist/editor/page-viewer/EditorForm.js +54 -5
  94. package/dist/editor/page-viewer/EditorForm.js.map +1 -1
  95. package/dist/editor/page-viewer/MiniMap.d.ts +12 -1
  96. package/dist/editor/page-viewer/MiniMap.js +65 -26
  97. package/dist/editor/page-viewer/MiniMap.js.map +1 -1
  98. package/dist/editor/page-viewer/PageViewer.js +9 -7
  99. package/dist/editor/page-viewer/PageViewer.js.map +1 -1
  100. package/dist/editor/page-viewer/PageViewerFrame.js +290 -37
  101. package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
  102. package/dist/editor/page-viewer/bridgeFieldPatch.js +49 -2
  103. package/dist/editor/page-viewer/bridgeFieldPatch.js.map +1 -1
  104. package/dist/editor/page-viewer/pageViewContext.d.ts +1 -0
  105. package/dist/editor/page-viewer/pageViewContext.js +7 -0
  106. package/dist/editor/page-viewer/pageViewContext.js.map +1 -1
  107. package/dist/editor/perfTrace.d.ts +46 -0
  108. package/dist/editor/perfTrace.js +213 -0
  109. package/dist/editor/perfTrace.js.map +1 -0
  110. package/dist/editor/reviews/CommentPopover.js +2 -3
  111. package/dist/editor/reviews/CommentPopover.js.map +1 -1
  112. package/dist/editor/reviews/Comments.js +12 -3
  113. package/dist/editor/reviews/Comments.js.map +1 -1
  114. package/dist/editor/reviews/commentAi.js +1 -1
  115. package/dist/editor/reviews/commentAi.js.map +1 -1
  116. package/dist/editor/services/agentService.d.ts +2 -0
  117. package/dist/editor/services/agentService.js.map +1 -1
  118. package/dist/editor/services/aiService.d.ts +1 -0
  119. package/dist/editor/services/aiService.js.map +1 -1
  120. package/dist/editor/settings/panels/CreateAgentProfileDialog.js +3 -2
  121. package/dist/editor/settings/panels/CreateAgentProfileDialog.js.map +1 -1
  122. package/dist/editor/sidebar/ComponentTree.js +10 -9
  123. package/dist/editor/sidebar/ComponentTree.js.map +1 -1
  124. package/dist/editor/sidebar/ContentTreePanel.d.ts +2 -2
  125. package/dist/editor/sidebar/ContentTreePanel.js +6 -2
  126. package/dist/editor/sidebar/ContentTreePanel.js.map +1 -1
  127. package/dist/editor/sidebar/MainContentTree.js +3 -2
  128. package/dist/editor/sidebar/MainContentTree.js.map +1 -1
  129. package/dist/editor/sidebar/SidebarPanel.js +1 -1
  130. package/dist/editor/sidebar/SidebarPanel.js.map +1 -1
  131. package/dist/editor/utils/keyboardNavigation.js +2 -2
  132. package/dist/editor/utils/keyboardNavigation.js.map +1 -1
  133. package/dist/index.d.ts +1 -1
  134. package/dist/index.js +1 -1
  135. package/dist/index.js.map +1 -1
  136. package/dist/revision.d.ts +2 -2
  137. package/dist/revision.js +2 -2
  138. package/package.json +1 -1
@@ -1,14 +1,14 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useCallback, useEffect, useRef, useState } from "react";
3
3
  import { BRIDGE_DOM_UPDATED_EVENT, MiniMap } from "./MiniMap";
4
- import { useEditContext, useEditContextRef, useFieldsEditContext, useFieldsEditContextRef, } from "../client/editContext";
4
+ import { useCanvasSelection, useEditContext, useEditContextRef, useFieldsEditContext, useFieldsEditContextRef, } from "../client/editContext";
5
5
  import { useSlotContext } from "../views/editorSlotContext";
6
6
  import { useDebouncedCallback, useThrottledCallback } from "use-debounce";
7
7
  import { PageEditorChrome } from "../page-editor-chrome/PageEditorChrome";
8
8
  import { useBridgeInlineEditing, } from "../page-editor-chrome/useBridgeInlineEditing";
9
9
  import { getInlineAiAnchorFromBridgeToolbar, getVisibleBridgeToolbarRect, waitForVisibleBridgeToolbarRect, } from "../page-editor-chrome/bridgeInlineFormatToolbarLayout";
10
10
  import { IFRAME_OVERLAY_BRIDGE_DRAG_GESTURE_EVENT, IFRAME_OVERLAY_BRIDGE_GEOMETRY_EVENT, IFRAME_OVERLAY_BRIDGE_SCROLL_EVENT, IframeOverlayProvider, } from "../page-editor-chrome/overlay/IframeOverlayProvider";
11
- import { DEVICE_CHANGE_EVENT, useViewportChangeSignal, } from "./pageViewContext";
11
+ import { CANVAS_REFRESH_COMPLETED_EVENT, DEVICE_CHANGE_EVENT, useViewportChangeSignal, } from "./pageViewContext";
12
12
  import uuid from "react-uuid";
13
13
  import { cn } from "../../lib/utils";
14
14
  import { normalizeMarkerId } from "../utils";
@@ -26,8 +26,10 @@ import { DeviceToolbar } from "./DeviceToolbar";
26
26
  import { FullscreenControls } from "../client/ui/FullscreenControls";
27
27
  import { toSitecoreDate } from "../utils/sitecoreDate";
28
28
  import { BridgeClient } from "../bridge/BridgeClient";
29
+ import { beginPerfTrace, isPerfTraceActive, isPerfTraceEnabled, perfTraceStep, } from "../perfTrace";
29
30
  import { getSuggestionDisplayValue } from "../reviews/suggestionDisplayValue";
30
31
  import { buildBridgeFieldPatchPayload, getBridgeFieldPatchValue, isBridgePatchableTextField, } from "./bridgeFieldPatch";
32
+ import { logFieldValueDiagnostic, summarizeField, summarizeFieldDescriptor, summarizeFieldValue, } from "../fieldValueDiagnostics";
31
33
  import { createKeyboardEventFromBridgeInteraction } from "./bridgeKeyboardShortcuts";
32
34
  import { formatParentBridgeInjectionDiagnostic, injectParheliaBridgeFromParent, } from "./parentBridgeInjection";
33
35
  import { getTextCompletion, normalizeTextCompletion, } from "../services/textCompletionService";
@@ -39,6 +41,9 @@ const BRIDGE_INLINE_EDIT_RELEASE_EVENT = "parhelia:bridge-inline-edit-release";
39
41
  const INLINE_AI_CLOSE_EVENT = "inline-ai-close";
40
42
  const BRIDGE_INLINE_LINK_OPEN_EVENT = "bridge-inline-link-open";
41
43
  const SCROLL_INTO_VIEW_BRIDGE_SOURCE = "scroll-into-view";
44
+ // How long a requested canvas refresh may suppress viewport reactions
45
+ // (selection auto-scroll, scrollIntoView) before it is presumed lost.
46
+ const CANVAS_REFRESH_IN_FLIGHT_MAX_MS = 15000;
42
47
  // Suggestions-mode cursor: a text I-beam (the click insertion point) badged with
43
48
  // the lucide PenLine icon from the "Suggestions mode" toolbar button. A white
44
49
  // halo keeps it visible on any page background; the hotspot is the I-beam centre.
@@ -602,6 +607,7 @@ export function PageViewerFrame(props) {
602
607
  function PageViewerFrameContent({ compareView, pageViewContext, editContext, className, slotCloseButton, }) {
603
608
  const fieldsContext = useFieldsEditContext();
604
609
  const slotContext = useSlotContext();
610
+ const canvasSelection = useCanvasSelection();
605
611
  const pathname = usePathname();
606
612
  const pageViewContextRef = useRef(undefined);
607
613
  useEffect(() => {
@@ -636,6 +642,27 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
636
642
  const directOverlayScrollSyncRef = useRef(false);
637
643
  const lastBridgeHoverInteractionRef = useRef(undefined);
638
644
  const pendingRefreshScrollRef = useRef(undefined);
645
+ // Set when a canvas refresh (bridge patch or full reload) has been requested
646
+ // and its result has not landed yet. While in flight, bridgeGeometry still
647
+ // describes the PRE-refresh DOM — a moved component is still measured at its
648
+ // old position — so viewport-affecting reactions (selection auto-scroll,
649
+ // scrollIntoView) must wait for the refreshed geometry instead of scrolling
650
+ // toward stale rects. Timestamped so a refresh that never completes cannot
651
+ // suppress scrolling forever.
652
+ const canvasRefreshInFlightSinceRef = useRef(null);
653
+ // Set when refreshCompleted arrived with applied:"host-app": the page's own
654
+ // app accepted the refresh but its re-render lands later as DOM mutations.
655
+ // The in-flight window then stays open until the next structureUpdated.
656
+ const awaitingHostAppRefreshRenderRef = useRef(false);
657
+ const isCanvasRefreshInFlight = useCallback(() => {
658
+ const since = canvasRefreshInFlightSinceRef.current;
659
+ return (since !== null && Date.now() - since < CANVAS_REFRESH_IN_FLIGHT_MAX_MS);
660
+ }, []);
661
+ const completeCanvasRefresh = useCallback(() => {
662
+ awaitingHostAppRefreshRenderRef.current = false;
663
+ canvasRefreshInFlightSinceRef.current = null;
664
+ window.dispatchEvent(new CustomEvent(CANVAS_REFRESH_COMPLETED_EVENT));
665
+ }, []);
639
666
  const restorePendingRefreshScroll = useCallback((iframe, targetScroll, observedScroll) => {
640
667
  if (!targetScroll)
641
668
  return;
@@ -644,6 +671,17 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
644
671
  pendingRefreshScrollRef.current = undefined;
645
672
  }
646
673
  };
674
+ const currentScroll = getIframeWindowScroll(iframe) ??
675
+ observedScroll ?? { x: 0, y: 0 };
676
+ const deltaX = targetScroll.x - currentScroll.x;
677
+ const deltaY = targetScroll.y - currentScroll.y;
678
+ // Already at the target: re-asserting the position would be a no-op
679
+ // except that scrollTo cancels any in-flight smooth scroll (e.g. a
680
+ // minimap navigation issued while the refresh was still running).
681
+ if (Math.abs(deltaX) <= 1 && Math.abs(deltaY) <= 1) {
682
+ clearPendingTarget();
683
+ return;
684
+ }
647
685
  const restoreStarted = restoreIframeWindowScroll(iframe, targetScroll, {
648
686
  maxAttempts: 150,
649
687
  onSettled: clearPendingTarget,
@@ -652,17 +690,11 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
652
690
  if (!restoreStarted) {
653
691
  clearPendingTarget();
654
692
  }
655
- const currentScroll = observedScroll ??
656
- getIframeWindowScroll(iframe) ?? { x: 0, y: 0 };
657
- const deltaX = targetScroll.x - currentScroll.x;
658
- const deltaY = targetScroll.y - currentScroll.y;
659
- if (Math.abs(deltaX) > 1 || Math.abs(deltaY) > 1) {
660
- bridgeClientRef.current?.sendCommand("scrollBy", {
661
- x: deltaX,
662
- y: deltaY,
663
- behavior: "instant",
664
- });
665
- }
693
+ bridgeClientRef.current?.sendCommand("scrollBy", {
694
+ x: deltaX,
695
+ y: deltaY,
696
+ behavior: "instant",
697
+ });
666
698
  }, []);
667
699
  const suppressNextSelectionScrollRef = useRef(false);
668
700
  // Timestamp (ms) until which selection auto-scroll is suppressed. Held open for
@@ -770,16 +802,34 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
770
802
  // Iframe blur is handled by the bridge inline-edit lifecycle now.
771
803
  }, []);
772
804
  const sendBeginInlineEdit = useCallback((payload) => {
773
- return (bridgeClientRef.current?.sendCommand("beginInlineEdit", payload) ??
774
- false);
805
+ const sent = bridgeClientRef.current?.sendCommand("beginInlineEdit", payload) ??
806
+ false;
807
+ logFieldValueDiagnostic("bridge-frame", "beginInlineEdit command", {
808
+ sent,
809
+ payload,
810
+ });
811
+ return sent;
775
812
  }, []);
776
813
  const sendCancelInlineEdit = useCallback((payload) => {
777
- return (bridgeClientRef.current?.sendCommand("cancelInlineEdit", payload) ??
778
- false);
814
+ const sent = bridgeClientRef.current?.sendCommand("cancelInlineEdit", payload) ??
815
+ false;
816
+ logFieldValueDiagnostic("bridge-frame", "cancelInlineEdit command", {
817
+ sent,
818
+ payload,
819
+ });
820
+ return sent;
779
821
  }, []);
780
822
  const sendApplyFieldPatchCommand = useCallback((payload) => {
781
- return (bridgeClientRef.current?.sendCommand("applyFieldPatch", payload) ??
782
- false);
823
+ const sent = bridgeClientRef.current?.sendCommand("applyFieldPatch", payload) ??
824
+ false;
825
+ logFieldValueDiagnostic("bridge-frame", "applyFieldPatch command", {
826
+ sent,
827
+ payload: {
828
+ ...payload,
829
+ value: summarizeFieldValue(payload.value),
830
+ },
831
+ });
832
+ return sent;
783
833
  }, []);
784
834
  const sendApplyRichTextCommand = useCallback((payload) => {
785
835
  return (bridgeClientRef.current?.sendCommand("applyRichTextCommand", payload) ??
@@ -828,6 +878,18 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
828
878
  sendApplyFieldPatch: sendApplyFieldPatchCommand,
829
879
  });
830
880
  const beginTrackedBridgeInlineEdit = useCallback(async (interaction) => {
881
+ logFieldValueDiagnostic("bridge-frame", "begin tracked inline edit", {
882
+ previousActiveInlineEdit: activeBridgeInlineEditRef.current,
883
+ interaction: {
884
+ kind: interaction.kind,
885
+ elementKey: interaction.elementKey,
886
+ fieldId: interaction.fieldId,
887
+ item: interaction.item,
888
+ selectedText: summarizeFieldValue(interaction.selectedText),
889
+ selectionStartOffset: interaction.selectionStartOffset,
890
+ selectionEndOffset: interaction.selectionEndOffset,
891
+ },
892
+ });
831
893
  clearActiveBridgeInlineEdit();
832
894
  const started = await beginBridgeInlineEdit(interaction);
833
895
  if (started && interaction.elementKey && interaction.fieldId) {
@@ -852,6 +914,10 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
852
914
  };
853
915
  setIsBridgeInlineEditing(true);
854
916
  }
917
+ logFieldValueDiagnostic("bridge-frame", "tracked inline edit result", {
918
+ started,
919
+ nextActiveInlineEdit: activeBridgeInlineEditRef.current,
920
+ });
855
921
  return started;
856
922
  }, [
857
923
  beginBridgeInlineEdit,
@@ -860,9 +926,17 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
860
926
  editContextRef,
861
927
  ]);
862
928
  const endTrackedBridgeFieldFocus = useCallback(() => {
929
+ logFieldValueDiagnostic("bridge-frame", "ending tracked field focus", {
930
+ activeInlineEdit: activeBridgeInlineEditRef.current,
931
+ });
863
932
  clearActiveBridgeInlineEdit();
864
933
  endBridgeFieldFocus();
865
934
  }, [clearActiveBridgeInlineEdit, endBridgeFieldFocus]);
935
+ const beginTrackedBridgeInlineEditAfterSelection = useCallback((interaction) => {
936
+ window.setTimeout(() => {
937
+ void beginTrackedBridgeInlineEdit(interaction);
938
+ }, 0);
939
+ }, [beginTrackedBridgeInlineEdit]);
866
940
  useEffect(() => {
867
941
  const handleBridgeInlineEditRelease = (event) => {
868
942
  const detail = event
@@ -876,6 +950,10 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
876
950
  if (activeEdit.item && !bridgeItemMatches(activeEdit.item, field.item)) {
877
951
  return;
878
952
  }
953
+ logFieldValueDiagnostic("bridge-frame", "inline edit released by form", {
954
+ activeInlineEdit: activeEdit,
955
+ field: summarizeFieldDescriptor(field),
956
+ });
879
957
  clearActiveBridgeInlineEdit();
880
958
  bridgePatchSignatureRef.current.delete(`${activeEdit.elementKey}:${activeEdit.fieldId}`);
881
959
  };
@@ -927,12 +1005,33 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
927
1005
  },
928
1006
  mode: showSuggestions ? "suggestions" : "baseline",
929
1007
  });
930
- return {
1008
+ const result = {
931
1009
  value: showSuggestions ? display.mergedValue : display.baselineValue,
932
1010
  source: showSuggestions && display.hasSuggestions
933
1011
  ? "suggestion-preview"
934
1012
  : "real",
935
1013
  };
1014
+ logFieldValueDiagnostic("bridge-patch", "display value resolved", {
1015
+ showSuggestions,
1016
+ preferRepositoryValue,
1017
+ field: summarizeField(field),
1018
+ structureField: {
1019
+ elementKey: structureField.elementKey,
1020
+ fieldId: structureField.fieldId,
1021
+ item: structureField.item,
1022
+ textContent: summarizeFieldValue(structureField.textContent),
1023
+ isRichText: structureField.isRichText,
1024
+ },
1025
+ itemDescriptor,
1026
+ repositoryValue: summarizeFieldValue(repositoryValue),
1027
+ result: {
1028
+ ...result,
1029
+ value: summarizeFieldValue(result.value),
1030
+ },
1031
+ modifiedFieldCount: fieldsContext?.modifiedFields?.length,
1032
+ suggestedEditCount: editContext.suggestedEdits?.length,
1033
+ });
1034
+ return result;
936
1035
  }, [
937
1036
  editContext.mode,
938
1037
  editContext.showSuggestedEdits,
@@ -967,10 +1066,28 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
967
1066
  source: patch.source ?? "",
968
1067
  observedTextContent: observedTextContent ?? "",
969
1068
  });
970
- if (bridgePatchSignatureRef.current.get(cacheKey) === signature) {
1069
+ const previousSignature = bridgePatchSignatureRef.current.get(cacheKey);
1070
+ if (previousSignature === signature) {
1071
+ logFieldValueDiagnostic("bridge-patch", "skipped duplicate send", {
1072
+ cacheKey,
1073
+ patch: {
1074
+ ...patch,
1075
+ value: summarizeFieldValue(patch.value),
1076
+ },
1077
+ observedTextContent: summarizeFieldValue(observedTextContent),
1078
+ });
971
1079
  return false;
972
1080
  }
973
1081
  bridgePatchSignatureRef.current.set(cacheKey, signature);
1082
+ logFieldValueDiagnostic("bridge-patch", "sending patch", {
1083
+ cacheKey,
1084
+ patch: {
1085
+ ...patch,
1086
+ value: summarizeFieldValue(patch.value),
1087
+ },
1088
+ observedTextContent: summarizeFieldValue(observedTextContent),
1089
+ previousSignature,
1090
+ });
974
1091
  bridge.sendCommand("applyFieldPatch", patch);
975
1092
  return true;
976
1093
  }, []);
@@ -1512,9 +1629,11 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
1512
1629
  if (!editor)
1513
1630
  return;
1514
1631
  const selectFromBridgeInteraction = (ids) => {
1515
- if (!bridgeComponentSelectionsMatch(editor.selection, ids)) {
1632
+ const unchanged = bridgeComponentSelectionsMatch(editor.getSelection(), ids);
1633
+ if (!unchanged) {
1516
1634
  suppressNextSelectionScrollRef.current = true;
1517
1635
  }
1636
+ perfTraceStep("frame:select-dispatched", { ids, unchanged });
1518
1637
  editor.select(ids);
1519
1638
  };
1520
1639
  let effectiveInteraction = interaction;
@@ -1576,7 +1695,7 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
1576
1695
  selectFromBridgeInteraction([]);
1577
1696
  if (isEditableFieldClick) {
1578
1697
  clearSelectedRangeForEditableClick();
1579
- await beginTrackedBridgeInlineEdit(effectiveInteraction);
1698
+ beginTrackedBridgeInlineEditAfterSelection(effectiveInteraction);
1580
1699
  }
1581
1700
  else if (interaction.kind === "click") {
1582
1701
  closeInlineAiIfOpen();
@@ -1584,7 +1703,7 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
1584
1703
  }
1585
1704
  return;
1586
1705
  }
1587
- const currentSelection = editor.selection || [];
1706
+ const currentSelection = editor.getSelection();
1588
1707
  if (interaction.kind === "contextMenu") {
1589
1708
  if (pageViewContextRef.current) {
1590
1709
  pageViewContextRef.current.bridgeInteraction = effectiveInteraction;
@@ -1714,7 +1833,7 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
1714
1833
  selectFromBridgeInteraction([componentId]);
1715
1834
  if (isEditableFieldClick) {
1716
1835
  clearSelectedRangeForEditableClick();
1717
- await beginTrackedBridgeInlineEdit(effectiveInteraction);
1836
+ beginTrackedBridgeInlineEditAfterSelection(effectiveInteraction);
1718
1837
  }
1719
1838
  else {
1720
1839
  closeInlineAiIfOpen();
@@ -1723,6 +1842,7 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
1723
1842
  }, [
1724
1843
  applyBridgeTextCompletion,
1725
1844
  beginTrackedBridgeInlineEdit,
1845
+ beginTrackedBridgeInlineEditAfterSelection,
1726
1846
  clearBridgeTextCompletion,
1727
1847
  endTrackedBridgeFieldFocus,
1728
1848
  requestBridgeTextCompletion,
@@ -1844,9 +1964,12 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
1844
1964
  suggestionsCursorActive: !activeBridgeInlineEditRef.current &&
1845
1965
  (editContextRef.current?.mode === "suggestions" ||
1846
1966
  !!editContextRef.current?.showSuggestedEdits),
1847
- selectedComponentIds: editContextRef.current?.selection ?? [],
1967
+ selectedComponentIds: editContextRef.current?.getSelection() ?? [],
1848
1968
  featureFlags: {
1849
1969
  crossOriginBridge: true,
1970
+ // Lets the host emit its own perf logs + interaction perf
1971
+ // timestamps without needing a flag in the iframe's origin.
1972
+ perfTrace: isPerfTraceEnabled(),
1850
1973
  },
1851
1974
  version: bridge.getDiagnostics().editorVersion,
1852
1975
  acknowledgedCapabilities: bridge.getAcknowledgedCapabilities(),
@@ -1859,12 +1982,31 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
1859
1982
  }
1860
1983
  break;
1861
1984
  case "structureUpdated":
1985
+ if (isPerfTraceActive()) {
1986
+ perfTraceStep("frame:structure-updated-received", {
1987
+ components: event.payload.structure.components.length,
1988
+ fields: event.payload.structure.fields.length,
1989
+ transportMs: Date.now() - event.timestamp,
1990
+ });
1991
+ }
1862
1992
  pageViewContext.setBridgeStructure(event.payload.structure);
1993
+ if (awaitingHostAppRefreshRenderRef.current) {
1994
+ // First structure change after a host-app refresh: the page's
1995
+ // own re-render has reached the DOM — the refresh is now truly
1996
+ // complete.
1997
+ completeCanvasRefresh();
1998
+ }
1863
1999
  break;
1864
2000
  case "pageSkeletonUpdated":
1865
2001
  pageViewContext.setPageSkeleton(event.payload.pageSkeleton);
1866
2002
  break;
1867
2003
  case "geometryUpdated": {
2004
+ if (isPerfTraceActive()) {
2005
+ perfTraceStep("frame:geometry-updated-received", {
2006
+ targets: event.payload.geometry.targets.length,
2007
+ transportMs: Date.now() - event.timestamp,
2008
+ });
2009
+ }
1868
2010
  latestBridgeScrollRef.current = event.payload.geometry.scroll;
1869
2011
  pageViewContext.bridgeGeometry = event.payload.geometry;
1870
2012
  pageViewContext.setBridgeGeometry(event.payload.geometry);
@@ -1888,11 +2030,22 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
1888
2030
  window.dispatchEvent(new CustomEvent(BRIDGE_DOM_UPDATED_EVENT));
1889
2031
  break;
1890
2032
  case "refreshStarted":
2033
+ logFieldValueDiagnostic("bridge-frame", "refresh started", {
2034
+ revision: event.payload.revision,
2035
+ activeInlineEdit: activeBridgeInlineEditRef.current,
2036
+ patchSignatureCount: bridgePatchSignatureRef.current.size,
2037
+ });
1891
2038
  clearBridgeTextCompletion();
1892
2039
  clearBridgePatchSignatures();
1893
2040
  clearActiveBridgeInlineEdit();
1894
2041
  break;
1895
2042
  case "refreshCompleted":
2043
+ logFieldValueDiagnostic("bridge-frame", "refresh completed", {
2044
+ activeInlineEdit: activeBridgeInlineEditRef.current,
2045
+ hasStructure: !!event.payload.structure,
2046
+ hasGeometry: !!event.payload.geometry,
2047
+ structureFieldCount: event.payload.structure?.fields.length,
2048
+ });
1896
2049
  // Runtime refresh replaces host DOM without a new bridge ready event.
1897
2050
  // Field patches sent during the refresh window may have been cached
1898
2051
  // against the previous DOM generation, so force the refreshed host to
@@ -1915,7 +2068,13 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
1915
2068
  scrollHandlerRef.current(event.payload.geometry.scroll.y);
1916
2069
  }
1917
2070
  }
1918
- if (pendingRefreshScrollRef.current) {
2071
+ if (event.payload.scrollIntentApplied) {
2072
+ // The host already replayed a scroll issued during the refresh
2073
+ // (e.g. a minimap navigation) — restoring the pre-refresh
2074
+ // position now would clobber that newer intent.
2075
+ pendingRefreshScrollRef.current = undefined;
2076
+ }
2077
+ else if (pendingRefreshScrollRef.current) {
1919
2078
  const targetScroll = pendingRefreshScrollRef.current;
1920
2079
  const observedScroll = event.payload.geometry?.scroll ?? {
1921
2080
  x: 0,
@@ -1923,6 +2082,18 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
1923
2082
  };
1924
2083
  restorePendingRefreshScroll(iframe, targetScroll, observedScroll);
1925
2084
  }
2085
+ if (event.payload.applied === "host-app") {
2086
+ // The page's own app (e.g. a Next.js rendering host) accepted
2087
+ // the refresh, but its re-render lands later as ordinary DOM
2088
+ // mutations. Completing now would reopen viewport reactions
2089
+ // (selection auto-scroll, scrollIntoView, the inserting
2090
+ // indicator) while geometry still describes the pre-edit DOM —
2091
+ // wait for the mutation-driven structureUpdated instead.
2092
+ awaitingHostAppRefreshRenderRef.current = true;
2093
+ }
2094
+ else {
2095
+ completeCanvasRefresh();
2096
+ }
1926
2097
  setShowSpinner(false);
1927
2098
  break;
1928
2099
  case "selectionChanged":
@@ -1933,11 +2104,32 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
1933
2104
  if (event.payload.elementKey && event.payload.fieldId) {
1934
2105
  setIsBridgeInlineEditing(true);
1935
2106
  }
2107
+ logFieldValueDiagnostic("bridge-frame", "fieldValueChanged event", {
2108
+ elementKey: event.payload.elementKey,
2109
+ fieldId: event.payload.fieldId,
2110
+ item: event.payload.item,
2111
+ isRichText: event.payload.isRichText,
2112
+ value: summarizeFieldValue(event.payload.value),
2113
+ activeInlineEdit: activeBridgeInlineEditRef.current,
2114
+ });
1936
2115
  handleBridgeFieldValueChanged(event.payload);
1937
2116
  break;
1938
2117
  case "inlineEditEnded":
2118
+ logFieldValueDiagnostic("bridge-frame", "inlineEditEnded event", {
2119
+ reason: event.payload.reason,
2120
+ elementKey: event.payload.elementKey,
2121
+ fieldId: event.payload.fieldId,
2122
+ item: event.payload.item,
2123
+ isRichText: event.payload.isRichText,
2124
+ value: summarizeFieldValue(event.payload.value),
2125
+ activeInlineEdit: activeBridgeInlineEditRef.current,
2126
+ });
1939
2127
  handleBridgeInlineEditEnded(event.payload);
1940
2128
  clearActiveBridgeInlineEdit();
2129
+ logFieldValueDiagnostic("bridge-frame", "active inline edit cleared after end", {
2130
+ fieldId: event.payload.fieldId,
2131
+ reason: event.payload.reason,
2132
+ });
1941
2133
  break;
1942
2134
  case "interaction":
1943
2135
  if (event.payload.kind === "hover") {
@@ -1949,6 +2141,24 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
1949
2141
  else {
1950
2142
  lastBridgeHoverInteractionRef.current = undefined;
1951
2143
  }
2144
+ if (isPerfTraceEnabled() &&
2145
+ (event.payload.kind === "click" ||
2146
+ event.payload.kind === "doubleClick" ||
2147
+ event.payload.kind === "contextMenu")) {
2148
+ // Backdate to the host's DOM-event timestamp when available so
2149
+ // host-side dispatch (hit-test + deferred-click debounce) is
2150
+ // part of the waterfall; the envelope timestamp is when the
2151
+ // host posted the message.
2152
+ const eventAt = event.payload.perf?.eventAt;
2153
+ beginPerfTrace(`select-${event.payload.kind}`, {
2154
+ componentId: event.payload.componentId,
2155
+ fieldId: event.payload.fieldId,
2156
+ hostDispatchMs: eventAt !== undefined
2157
+ ? event.timestamp - eventAt
2158
+ : "n/a (host without perf tracing)",
2159
+ transportMs: Date.now() - event.timestamp,
2160
+ }, eventAt ?? event.timestamp);
2161
+ }
1952
2162
  pageViewContext.setBridgeInteraction(event.payload);
1953
2163
  void handleBridgeInteraction(event.payload, iframe);
1954
2164
  break;
@@ -2021,6 +2231,7 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
2021
2231
  scheduleBridgeGeometryRevision,
2022
2232
  shouldTrackMinimapScroll,
2023
2233
  restorePendingRefreshScroll,
2234
+ completeCanvasRefresh,
2024
2235
  ]);
2025
2236
  useEffect(() => {
2026
2237
  const repository = editContext.itemsRepository;
@@ -2410,6 +2621,8 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
2410
2621
  pendingRefreshScrollRef.current ??=
2411
2622
  getIframeWindowScroll(iframeRef.current) ??
2412
2623
  latestBridgeScrollRef.current;
2624
+ canvasRefreshInFlightSinceRef.current = Date.now();
2625
+ awaitingHostAppRefreshRenderRef.current = false;
2413
2626
  setShowSpinner(true);
2414
2627
  console.log(initialLoad
2415
2628
  ? "Initial load - setting iframe src"
@@ -2432,6 +2645,8 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
2432
2645
  }
2433
2646
  console.log("Bridge - requesting iframe refresh");
2434
2647
  pageViewContext.setIframeSupportsRefresh(true);
2648
+ canvasRefreshInFlightSinceRef.current = Date.now();
2649
+ awaitingHostAppRefreshRenderRef.current = false;
2435
2650
  const accepted = bridge.sendCommand("refresh", {
2436
2651
  url: renderUrl.toString(),
2437
2652
  revision: editContext.revision,
@@ -2439,6 +2654,7 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
2439
2654
  });
2440
2655
  if (!accepted) {
2441
2656
  pendingRefreshScrollRef.current = undefined;
2657
+ canvasRefreshInFlightSinceRef.current = null;
2442
2658
  pageViewContext.setIframeSupportsRefresh(false);
2443
2659
  runFallbackRefresh();
2444
2660
  }
@@ -2475,8 +2691,18 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
2475
2691
  ]);
2476
2692
  useEffect(() => {
2477
2693
  if (fieldsContext?.focusedField) {
2478
- if (editContext.selection.length > 0 &&
2479
- fieldsContext.focusedField.item.id !== editContext.selection[0])
2694
+ // A refresh is being applied: the field's rect still describes the
2695
+ // pre-edit DOM (after a move, its old position — where the drag
2696
+ // started), so scrolling now would yank the canvas to a stale spot.
2697
+ // This fires on the post-operation auto-focus of the moved/added
2698
+ // component; a genuine user focus during a refresh loses one
2699
+ // auto-scroll, which is the lesser evil.
2700
+ if (isCanvasRefreshInFlight())
2701
+ return;
2702
+ // Event-time read: this effect is keyed on focusedField, not selection.
2703
+ const currentSelection = editContext.getSelection();
2704
+ if (currentSelection.length > 0 &&
2705
+ fieldsContext.focusedField.item.id !== currentSelection[0])
2480
2706
  return;
2481
2707
  const bounds = findBridgeFieldDocumentBounds(pageViewContextRef.current?.bridgeGeometry, fieldsContext.focusedField);
2482
2708
  const activePageViewContext = pageViewContextRef.current;
@@ -2484,7 +2710,7 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
2484
2710
  scrollBridgeBoundsIntoView(activePageViewContext, bounds, latestBridgeScrollRef.current);
2485
2711
  }
2486
2712
  }
2487
- }, [fieldsContext?.focusedField]);
2713
+ }, [fieldsContext?.focusedField, isCanvasRefreshInFlight]);
2488
2714
  // Drive the selection-scroll suppression window from the drag lifecycle.
2489
2715
  // Declared BEFORE the selection-scroll effect so it runs first in the same
2490
2716
  // commit (when a drop changes both dragObject and selection at once).
@@ -2501,7 +2727,7 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
2501
2727
  }
2502
2728
  }, [editContext.dragObject]);
2503
2729
  useEffect(() => {
2504
- const selectionKey = editContext.selection.join("|");
2730
+ const selectionKey = canvasSelection.join("|");
2505
2731
  const selectionChanged = selectionKey !== lastScrolledSelectionKeyRef.current;
2506
2732
  lastScrolledSelectionKeyRef.current = selectionKey;
2507
2733
  // The effect also re-runs when focusedField changes (e.g. a field blurs
@@ -2514,24 +2740,43 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
2514
2740
  suppressNextSelectionScrollRef.current = false;
2515
2741
  return;
2516
2742
  }
2743
+ // Programmatic selections (the drop target's parent, the post-operation
2744
+ // focus of a moved/added component) arm this suppression at their source:
2745
+ // their targets may still measure at pre-edit geometry, and unlike user
2746
+ // clicks they carry no intent to see the component. Deterministic — no
2747
+ // time window to lose against a slow operation or frozen host.
2748
+ if (editContext.consumeNextSelectionAutoScrollSuppression?.())
2749
+ return;
2517
2750
  // Suppressed during a drag and briefly after it ends. The drag owns
2518
2751
  // scrolling, and the drop's re-selection must not jump the page away from
2519
2752
  // where the user dropped (toward stale pre-move geometry).
2520
2753
  if (Date.now() < suppressSelectionScrollUntilRef.current)
2521
2754
  return;
2522
- if (!fieldsContext?.focusedField && editContext.selection.length > 0) {
2523
- const lastSelectedComponent = getComponentById(editContext.selection[editContext.selection.length - 1], pageViewContextRef.current.page);
2755
+ // Suppressed while a refresh is applying: geometry still measures the
2756
+ // pre-refresh DOM (a just-moved component still sits at its old rect), so
2757
+ // scrolling now would target a stale position. The refresh restore owns
2758
+ // the viewport until the refreshed geometry lands.
2759
+ if (isCanvasRefreshInFlight())
2760
+ return;
2761
+ if (!fieldsContext?.focusedField && canvasSelection.length > 0) {
2762
+ const lastSelectedComponent = getComponentById(canvasSelection[canvasSelection.length - 1], pageViewContextRef.current.page);
2524
2763
  if (lastSelectedComponent) {
2525
2764
  editContext.setScrollIntoView(lastSelectedComponent.id);
2526
2765
  }
2527
2766
  }
2528
- }, [editContext.selection, fieldsContext?.focusedField]);
2767
+ }, [canvasSelection, fieldsContext?.focusedField, isCanvasRefreshInFlight]);
2529
2768
  useEffect(() => {
2530
2769
  if (!editContext.scrollIntoView)
2531
2770
  return;
2532
2771
  const activePageViewContext = pageViewContextRef.current;
2533
2772
  if (!activePageViewContext)
2534
2773
  return;
2774
+ // Defer (without consuming the request) while a refresh is applying:
2775
+ // resolving now would measure the target against pre-refresh geometry and
2776
+ // scroll to a stale rect. The effect re-runs when the refreshed geometry
2777
+ // arrives (bridgeGeometry dependency) and resolves against fresh bounds.
2778
+ if (isCanvasRefreshInFlight())
2779
+ return;
2535
2780
  const scrollTarget = editContext.scrollIntoView;
2536
2781
  const requestState = scrollIntoViewRequestRef.current;
2537
2782
  const signature = getScrollIntoViewSignature(scrollTarget);
@@ -2566,6 +2811,7 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
2566
2811
  editContext.scrollIntoView,
2567
2812
  pageViewContext.page,
2568
2813
  pageViewContext.bridgeGeometry,
2814
+ isCanvasRefreshInFlight,
2569
2815
  ]);
2570
2816
  useEffect(() => {
2571
2817
  const handleMessage = (message) => {
@@ -2640,10 +2886,16 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
2640
2886
  };
2641
2887
  }, [iframeElement]);
2642
2888
  useEffect(() => {
2643
- bridgeClientRef.current?.sendCommand("setSelection", {
2644
- componentIds: editContext.selection,
2889
+ const sent = bridgeClientRef.current?.sendCommand("setSelection", {
2890
+ componentIds: canvasSelection,
2645
2891
  });
2646
- }, [editContext.selection]);
2892
+ if (isPerfTraceActive()) {
2893
+ perfTraceStep("frame:setSelection-command-sent", {
2894
+ ids: canvasSelection,
2895
+ sent: sent ?? false,
2896
+ });
2897
+ }
2898
+ }, [canvasSelection]);
2647
2899
  useEffect(() => {
2648
2900
  const bridge = bridgeClientRef.current;
2649
2901
  bridge?.sendCommand("setPreviewMode", {
@@ -2776,6 +3028,7 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
2776
3028
  if (pendingRefreshScrollRef.current) {
2777
3029
  restorePendingRefreshScroll(iframeRef.current, pendingRefreshScrollRef.current);
2778
3030
  }
3031
+ completeCanvasRefresh();
2779
3032
  }
2780
3033
  } }), iframeElement && (_jsx(IframeOverlayProvider, { iframe: iframeElement, mode: "scrolling", scrollScale: 1, visualScale: 1, invalidationKey: `${zoom}:${bridgeGeometryRevision}`, deferredInvalidationMs: ZOOM_TRANSITION_MS + 50, bleed: { top: 2, bottom: 2, left: 2 }, children: _jsx(PageEditorChrome, { iframe: iframeElement, compareView: compareView, pageViewContext: pageViewContext, onBridgeRichTextCommand: sendApplyRichTextCommand }) })), pageViewContext.deviceHeight && pageViewContext.device && (_jsx("div", { className: "bg-neutral-grey-5 relative z-40 h-full w-full" }))] }), shouldRenderMiniMap && (_jsx(MiniMap, { compareView: compareView, scroll: scroll, mainViewIframeRef: iframeRef, pageViewContext: pageViewContext })), showSpinner && (_jsxs(_Fragment, { children: [_jsx("div", { className: "bg-neutral-grey-5/50 absolute top-0 left-0 h-full w-full" }), _jsx("div", { className: "absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 transform", children: _jsx(Spinner, {}) })] }))] }), _jsx(FieldActionsOverlay, { ref: fieldActionsOverlay, generatorButtons: contextMenuFieldButtons, onActionClick: handleActionClick, onParameterizedActionExecute: handleParameterizedActionExecute, currentOverlay: editContext?.currentOverlay, fieldId: contextMenuField?.fieldId || "", setCurrentOverlay: editContext?.setCurrentOverlay || (() => { }), preSelectedAction: preSelectedAction })] }));
2781
3034
  }