@parhelia/core 0.3.12788 → 0.3.12798
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/ui/LanguageSelector.js +4 -1
- package/dist/components/ui/LanguageSelector.js.map +1 -1
- package/dist/components/ui/PlaceholderInput.js +16 -2
- package/dist/components/ui/PlaceholderInput.js.map +1 -1
- package/dist/components/ui/select.js +12 -1
- package/dist/components/ui/select.js.map +1 -1
- package/dist/editor/FieldHistory.js +14 -4
- package/dist/editor/FieldHistory.js.map +1 -1
- package/dist/editor/ai/InlineAiDialog.js +35 -8
- package/dist/editor/ai/InlineAiDialog.js.map +1 -1
- package/dist/editor/ai/agentTodoExtraction.d.ts +1 -0
- package/dist/editor/ai/agentTodoExtraction.js +3 -0
- package/dist/editor/ai/agentTodoExtraction.js.map +1 -1
- package/dist/editor/ai/terminal/agentSessionState.js +26 -4
- package/dist/editor/ai/terminal/agentSessionState.js.map +1 -1
- package/dist/editor/ai/terminal/components/AgentProjectProgress.d.ts +4 -3
- package/dist/editor/ai/terminal/components/AgentProjectProgress.js +34 -50
- package/dist/editor/ai/terminal/components/AgentProjectProgress.js.map +1 -1
- package/dist/editor/ai/terminal/components/AgentTerminalView.d.ts +2 -1
- package/dist/editor/ai/terminal/components/AgentTerminalView.js +2 -2
- package/dist/editor/ai/terminal/components/AgentTerminalView.js.map +1 -1
- package/dist/editor/ai/terminal/components/AgentThinkingIndicator.js +2 -1
- package/dist/editor/ai/terminal/components/AgentThinkingIndicator.js.map +1 -1
- package/dist/editor/ai/terminal/components/AiResponseMessage.js +55 -41
- package/dist/editor/ai/terminal/components/AiResponseMessage.js.map +1 -1
- package/dist/editor/ai/terminal/components/ApprovalCard.d.ts +1 -0
- package/dist/editor/ai/terminal/components/ApprovalCard.js +15 -1
- package/dist/editor/ai/terminal/components/ApprovalCard.js.map +1 -1
- package/dist/editor/ai/terminal/components/EditFieldToolCallContent.d.ts +24 -0
- package/dist/editor/ai/terminal/components/EditFieldToolCallContent.js +97 -0
- package/dist/editor/ai/terminal/components/EditFieldToolCallContent.js.map +1 -0
- package/dist/editor/ai/terminal/components/InitialThinkingSplash.js +2 -1
- package/dist/editor/ai/terminal/components/InitialThinkingSplash.js.map +1 -1
- package/dist/editor/ai/terminal/components/TodoListPanel.js +5 -3
- package/dist/editor/ai/terminal/components/TodoListPanel.js.map +1 -1
- package/dist/editor/ai/terminal/components/ToolCallDisplay.d.ts +4 -1
- package/dist/editor/ai/terminal/components/ToolCallDisplay.js +33 -5
- package/dist/editor/ai/terminal/components/ToolCallDisplay.js.map +1 -1
- package/dist/editor/ai/terminal/components/ValueDiff.d.ts +15 -0
- package/dist/editor/ai/terminal/components/ValueDiff.js +21 -0
- package/dist/editor/ai/terminal/components/ValueDiff.js.map +1 -0
- package/dist/editor/ai/terminal/components/agentThinkingStyles.d.ts +1 -0
- package/dist/editor/ai/terminal/components/agentThinkingStyles.js +2 -0
- package/dist/editor/ai/terminal/components/agentThinkingStyles.js.map +1 -0
- package/dist/editor/ai/terminal/components/toolCallContentRenderers.d.ts +15 -0
- package/dist/editor/ai/terminal/components/toolCallContentRenderers.js +12 -0
- package/dist/editor/ai/terminal/components/toolCallContentRenderers.js.map +1 -0
- package/dist/editor/ai/terminal/useAgentRunResyncSocketHandler.d.ts +1 -0
- package/dist/editor/ai/terminal/useAgentRunResyncSocketHandler.js +6 -1
- package/dist/editor/ai/terminal/useAgentRunResyncSocketHandler.js.map +1 -1
- package/dist/editor/ai/terminal/useAgentStreamPipeline.js +1 -0
- package/dist/editor/ai/terminal/useAgentStreamPipeline.js.map +1 -1
- package/dist/editor/ai/terminal/useAgentTerminalController.js +1 -0
- package/dist/editor/ai/terminal/useAgentTerminalController.js.map +1 -1
- package/dist/editor/ai/terminal/useAgentTerminalViewProps.d.ts +1 -0
- package/dist/editor/ai/terminal/useAgentTerminalViewProps.js +2 -1
- package/dist/editor/ai/terminal/useAgentTerminalViewProps.js.map +1 -1
- package/dist/editor/ai/types.d.ts +1 -0
- package/dist/editor/bridge/protocol.d.ts +11 -0
- package/dist/editor/bridge/protocol.js +1 -0
- package/dist/editor/bridge/protocol.js.map +1 -1
- package/dist/editor/client/EditorShell.js +184 -68
- package/dist/editor/client/EditorShell.js.map +1 -1
- package/dist/editor/client/editContext.d.ts +13 -3
- package/dist/editor/client/editContext.js.map +1 -1
- package/dist/editor/client/hooks/activeSessionSnapshots.d.ts +2 -0
- package/dist/editor/client/hooks/activeSessionSnapshots.js +43 -0
- package/dist/editor/client/hooks/activeSessionSnapshots.js.map +1 -0
- package/dist/editor/client/hooks/feedbackSocketState.js +3 -0
- package/dist/editor/client/hooks/feedbackSocketState.js.map +1 -1
- package/dist/editor/client/hooks/operationRefreshDeduplication.d.ts +22 -0
- package/dist/editor/client/hooks/operationRefreshDeduplication.js +45 -0
- package/dist/editor/client/hooks/operationRefreshDeduplication.js.map +1 -0
- package/dist/editor/client/hooks/socketMessageRetention.d.ts +7 -0
- package/dist/editor/client/hooks/socketMessageRetention.js +11 -0
- package/dist/editor/client/hooks/socketMessageRetention.js.map +1 -0
- package/dist/editor/client/hooks/useSocketMessageHandler.js +53 -19
- package/dist/editor/client/hooks/useSocketMessageHandler.js.map +1 -1
- package/dist/editor/client/hooks/useWorkbox.d.ts +4 -0
- package/dist/editor/client/hooks/useWorkbox.js +132 -2
- package/dist/editor/client/hooks/useWorkbox.js.map +1 -1
- package/dist/editor/client/itemsRepository.d.ts +7 -1
- package/dist/editor/client/itemsRepository.js +55 -19
- package/dist/editor/client/itemsRepository.js.map +1 -1
- package/dist/editor/client/operations.d.ts +7 -3
- package/dist/editor/client/operations.js +216 -150
- package/dist/editor/client/operations.js.map +1 -1
- package/dist/editor/client/pageModelBuilder.js +21 -4
- package/dist/editor/client/pageModelBuilder.js.map +1 -1
- package/dist/editor/client/sidebarAvailability.d.ts +4 -0
- package/dist/editor/client/sidebarAvailability.js +15 -0
- package/dist/editor/client/sidebarAvailability.js.map +1 -1
- package/dist/editor/client/waitForEditOperationTerminal.js +1 -1
- package/dist/editor/client/waitForEditOperationTerminal.js.map +1 -1
- package/dist/editor/commands/itemCommands.js +1 -1
- package/dist/editor/commands/itemCommands.js.map +1 -1
- package/dist/editor/content-tree/TreeSettingsMenu.js +1 -1
- package/dist/editor/content-tree/TreeSettingsMenu.js.map +1 -1
- package/dist/editor/field-types/RichTextEditorComponent.js +6 -1
- package/dist/editor/field-types/RichTextEditorComponent.js.map +1 -1
- package/dist/editor/field-types/SingleLineText.js +2 -3
- package/dist/editor/field-types/SingleLineText.js.map +1 -1
- package/dist/editor/field-types/richtext/components/ReactSlate.d.ts +6 -1
- package/dist/editor/field-types/richtext/components/ReactSlate.js +91 -5
- package/dist/editor/field-types/richtext/components/ReactSlate.js.map +1 -1
- package/dist/editor/field-types/singleLineTextValue.d.ts +3 -0
- package/dist/editor/field-types/singleLineTextValue.js +9 -0
- package/dist/editor/field-types/singleLineTextValue.js.map +1 -0
- package/dist/editor/menubar/ItemLanguageVersion.js +1 -1
- package/dist/editor/menubar/ItemLanguageVersion.js.map +1 -1
- package/dist/editor/menubar/VersionSelector.js +18 -6
- package/dist/editor/menubar/VersionSelector.js.map +1 -1
- package/dist/editor/menubar/WorkflowButton.js +8 -3
- package/dist/editor/menubar/WorkflowButton.js.map +1 -1
- package/dist/editor/menubar/toolbar-sections/EditControls.js +1 -1
- package/dist/editor/menubar/toolbar-sections/EditControls.js.map +1 -1
- package/dist/editor/notifications/NotificationCenter.js +26 -7
- package/dist/editor/notifications/NotificationCenter.js.map +1 -1
- package/dist/editor/notifications/useNotifications.d.ts +3 -1
- package/dist/editor/notifications/useNotifications.js +27 -9
- package/dist/editor/notifications/useNotifications.js.map +1 -1
- package/dist/editor/page-editor-chrome/BridgeInlineFormatOverlay.js +18 -0
- package/dist/editor/page-editor-chrome/BridgeInlineFormatOverlay.js.map +1 -1
- package/dist/editor/page-editor-chrome/DragInsertionOverlay.js +54 -19
- package/dist/editor/page-editor-chrome/DragInsertionOverlay.js.map +1 -1
- package/dist/editor/page-editor-chrome/InlineFieldHistoryButton.js +30 -8
- package/dist/editor/page-editor-chrome/InlineFieldHistoryButton.js.map +1 -1
- package/dist/editor/page-editor-chrome/VersionDiffHighlightings.js +30 -8
- package/dist/editor/page-editor-chrome/VersionDiffHighlightings.js.map +1 -1
- package/dist/editor/page-editor-chrome/overlay/IframeOverlayProvider.d.ts +4 -0
- package/dist/editor/page-editor-chrome/overlay/IframeOverlayProvider.js.map +1 -1
- package/dist/editor/page-editor-chrome/overlay/placeholderZones.js +23 -1
- package/dist/editor/page-editor-chrome/overlay/placeholderZones.js.map +1 -1
- package/dist/editor/page-editor-chrome/useBridgeInlineEditing.d.ts +5 -3
- package/dist/editor/page-editor-chrome/useBridgeInlineEditing.js +111 -19
- package/dist/editor/page-editor-chrome/useBridgeInlineEditing.js.map +1 -1
- package/dist/editor/page-viewer/EditorForm.d.ts +2 -1
- package/dist/editor/page-viewer/EditorForm.js +41 -12
- package/dist/editor/page-viewer/EditorForm.js.map +1 -1
- package/dist/editor/page-viewer/PageViewer.d.ts +2 -0
- package/dist/editor/page-viewer/PageViewer.js +11 -2
- package/dist/editor/page-viewer/PageViewer.js.map +1 -1
- package/dist/editor/page-viewer/PageViewerFrame.js +266 -44
- package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
- package/dist/editor/page-viewer/bridgeFieldPatch.js +1 -0
- package/dist/editor/page-viewer/bridgeFieldPatch.js.map +1 -1
- package/dist/editor/page-viewer/bridgeInlineAiSelection.d.ts +17 -0
- package/dist/editor/page-viewer/bridgeInlineAiSelection.js +80 -0
- package/dist/editor/page-viewer/bridgeInlineAiSelection.js.map +1 -0
- package/dist/editor/page-viewer/bridgeInlineEditCommit.d.ts +18 -0
- package/dist/editor/page-viewer/bridgeInlineEditCommit.js +24 -0
- package/dist/editor/page-viewer/bridgeInlineEditCommit.js.map +1 -0
- package/dist/editor/page-viewer/bridgeInlineEditSession.d.ts +3 -0
- package/dist/editor/page-viewer/bridgeInlineEditSession.js +30 -0
- package/dist/editor/page-viewer/bridgeInlineEditSession.js.map +1 -1
- package/dist/editor/page-viewer/bridgeItemChangeTarget.d.ts +9 -0
- package/dist/editor/page-viewer/bridgeItemChangeTarget.js +38 -0
- package/dist/editor/page-viewer/bridgeItemChangeTarget.js.map +1 -0
- package/dist/editor/page-viewer/bridgePointerDragRelease.d.ts +31 -0
- package/dist/editor/page-viewer/bridgePointerDragRelease.js +32 -0
- package/dist/editor/page-viewer/bridgePointerDragRelease.js.map +1 -0
- package/dist/editor/page-viewer/renderUrl.d.ts +8 -0
- package/dist/editor/page-viewer/renderUrl.js +10 -0
- package/dist/editor/page-viewer/renderUrl.js.map +1 -1
- package/dist/editor/personalization/PersonalizationPanel.js +52 -25
- package/dist/editor/personalization/PersonalizationPanel.js.map +1 -1
- package/dist/editor/reviews/Comment.js +3 -1
- package/dist/editor/reviews/Comment.js.map +1 -1
- package/dist/editor/reviews/CommentDisplayPopover.js +2 -0
- package/dist/editor/reviews/CommentDisplayPopover.js.map +1 -1
- package/dist/editor/reviews/Comments.js +16 -3
- package/dist/editor/reviews/Comments.js.map +1 -1
- package/dist/editor/reviews/SuggestedEdit.js +25 -2
- package/dist/editor/reviews/SuggestedEdit.js.map +1 -1
- package/dist/editor/reviews/SuggestionCommentThread.js +2 -0
- package/dist/editor/reviews/SuggestionCommentThread.js.map +1 -1
- package/dist/editor/reviews/applySuggestedEditActions.js +105 -25
- package/dist/editor/reviews/applySuggestedEditActions.js.map +1 -1
- package/dist/editor/reviews/commentState.d.ts +4 -0
- package/dist/editor/reviews/commentState.js +15 -0
- package/dist/editor/reviews/commentState.js.map +1 -0
- package/dist/editor/reviews/feedbackOrdering.d.ts +1 -0
- package/dist/editor/reviews/feedbackOrdering.js +6 -0
- package/dist/editor/reviews/feedbackOrdering.js.map +1 -1
- package/dist/editor/reviews/suggestionContentChange.d.ts +7 -0
- package/dist/editor/reviews/suggestionContentChange.js +10 -0
- package/dist/editor/reviews/suggestionContentChange.js.map +1 -1
- package/dist/editor/reviews/suggestionPatch.js +6 -0
- package/dist/editor/reviews/suggestionPatch.js.map +1 -1
- package/dist/editor/services/agentService.d.ts +6 -0
- package/dist/editor/services/agentService.js.map +1 -1
- package/dist/editor/services/personalizationService.js +30 -6
- package/dist/editor/services/personalizationService.js.map +1 -1
- package/dist/editor/services/suggestedEditsService.d.ts +1 -0
- package/dist/editor/services/suggestedEditsService.js +3 -0
- package/dist/editor/services/suggestedEditsService.js.map +1 -1
- package/dist/editor/settings/SettingsView.js +15 -7
- package/dist/editor/settings/SettingsView.js.map +1 -1
- package/dist/editor/settings/panels/MemoriesPanel.js +3 -2
- package/dist/editor/settings/panels/MemoriesPanel.js.map +1 -1
- package/dist/editor/settings/panels/ProjectTemplatesPanel.d.ts +7 -0
- package/dist/editor/settings/panels/ProjectTemplatesPanel.js +232 -21
- package/dist/editor/settings/panels/ProjectTemplatesPanel.js.map +1 -1
- package/dist/editor/settings/panels/projectTemplateDuplication.d.ts +5 -0
- package/dist/editor/settings/panels/projectTemplateDuplication.js +57 -0
- package/dist/editor/settings/panels/projectTemplateDuplication.js.map +1 -0
- package/dist/editor/setup-wizard/steps/CreateSettingsStep.js +9 -4
- package/dist/editor/setup-wizard/steps/CreateSettingsStep.js.map +1 -1
- package/dist/editor/sidebar/MainContentTree.js +1 -1
- package/dist/editor/sidebar/MainContentTree.js.map +1 -1
- package/dist/editor/ui/PerfectTree.js +2 -2
- package/dist/editor/ui/PerfectTree.js.map +1 -1
- package/dist/editor/ui/PublishRestrictionsDialog.js +9 -1
- package/dist/editor/ui/PublishRestrictionsDialog.js.map +1 -1
- package/dist/editor/utils.js +5 -2
- package/dist/editor/utils.js.map +1 -1
- package/dist/editor/views/EditorSlot.js +5 -1
- package/dist/editor/views/EditorSlot.js.map +1 -1
- package/dist/editor/views/SingleEditView.d.ts +4 -1
- package/dist/editor/views/SingleEditView.js +2 -2
- package/dist/editor/views/SingleEditView.js.map +1 -1
- package/dist/licensing/LicenseContext.js +7 -0
- package/dist/licensing/LicenseContext.js.map +1 -1
- package/dist/revision.d.ts +2 -2
- package/dist/revision.js +2 -2
- package/dist/task-board/TaskBoardWorkspace.js +10 -10
- package/dist/task-board/TaskBoardWorkspace.js.map +1 -1
- package/dist/task-board/taskExecutionRecords.d.ts +1 -0
- package/dist/task-board/taskExecutionRecords.js +29 -0
- package/dist/task-board/taskExecutionRecords.js.map +1 -1
- package/dist/task-board/types.d.ts +9 -0
- package/dist/task-board/views/DependencyGraphView.d.ts +1 -0
- package/dist/task-board/views/DependencyGraphView.js +15 -12
- package/dist/task-board/views/DependencyGraphView.js.map +1 -1
- package/package.json +1 -1
|
@@ -22,7 +22,7 @@ import { loadFieldButtons } from "../services/editService";
|
|
|
22
22
|
import { usePathname } from "../client/navigation";
|
|
23
23
|
import { EditorWarnings } from "../EditorWarnings";
|
|
24
24
|
import { FieldActionsOverlay, } from "../FieldActionsOverlay";
|
|
25
|
-
import { alignLoopbackHostToEditor, alignXmCloudManagedEditingHostToEditor, applyParheliaRenderContext, getEditorQueryParam, } from "./renderUrl";
|
|
25
|
+
import { alignLoopbackHostToEditor, alignXmCloudManagedEditingHostToEditor, applyParheliaRenderContext, crossesPreviewRenderBoundary, getEditorQueryParam, } from "./renderUrl";
|
|
26
26
|
import { NoLayout } from "../page-editor-chrome/NoLayout";
|
|
27
27
|
import { Spinner } from "../ui/Spinner";
|
|
28
28
|
import { DeviceToolbar } from "./DeviceToolbar";
|
|
@@ -33,11 +33,15 @@ import { pickVersionAtDate } from "../utils/versionAtDate";
|
|
|
33
33
|
import { BridgeClient } from "../bridge/BridgeClient";
|
|
34
34
|
import { beginPerfTrace, isPerfTraceActive, isPerfTraceEnabled, perfTraceStep, } from "../perfTrace";
|
|
35
35
|
import { getPendingFieldSuggestions, getSuggestionSelectionKey, getSuggestionDisplayValue, } from "../reviews/suggestionDisplayValue";
|
|
36
|
+
import { bridgeItemDescriptorMatchesItem, bridgeStructureTargetsChangedItem, } from "./bridgeItemChangeTarget";
|
|
36
37
|
import { buildBridgeFieldPatchPayload, buildBridgeFieldPatchSignature, buildRemoteCaretFieldPatches, getBridgeFieldPatchValue, hasRemoteCaretDraftForField, isBridgePatchableTextField, isSuggestionPreviewPatchSignature, } from "./bridgeFieldPatch";
|
|
37
38
|
import { bridgeSelectionMatchesInteraction, resolveBridgeTextCompletionInput, } from "./bridgeTextCompletion";
|
|
39
|
+
import { resolveBridgeInlineAiSelectionRange } from "./bridgeInlineAiSelection";
|
|
40
|
+
import { BRIDGE_AUTHORITATIVE_REFRESH_EVENT, BRIDGE_INLINE_EDIT_COMMIT_EVENT, } from "./bridgeInlineEditCommit";
|
|
38
41
|
import { logFieldValueDiagnostic, summarizeFieldDescriptor, summarizeFieldValue, } from "../fieldValueDiagnostics";
|
|
39
42
|
import { createKeyboardEventFromBridgeInteraction, getBridgeFieldHistoryStepDirection, INLINE_FIELD_HISTORY_STEP_EVENT, } from "./bridgeKeyboardShortcuts";
|
|
40
43
|
import { formatParentBridgeInjectionDiagnostic, injectParheliaBridgeFromParent, } from "./parentBridgeInjection";
|
|
44
|
+
import { projectParentPointerToHost, resolveParentBridgePointerRelease, } from "./bridgePointerDragRelease";
|
|
41
45
|
import { getTextCompletion, normalizeTextCompletion, } from "../services/textCompletionService";
|
|
42
46
|
import { resolvePageAndSiteByPath } from "../services/contentService";
|
|
43
47
|
import { extractInternalLinkPath, extractInternalLinkTargetItemId, shouldOpenInternalLinkInNewSlot, } from "./internalLinkNavigation";
|
|
@@ -482,25 +486,6 @@ function bridgeComponentSelectionsMatch(left, right) {
|
|
|
482
486
|
return false;
|
|
483
487
|
return (left ?? []).every((leftId, index) => bridgeIdsMatch(leftId, right?.[index]));
|
|
484
488
|
}
|
|
485
|
-
function bridgeDescriptorMatchesItem(bridgeItem, item) {
|
|
486
|
-
if (!bridgeItem?.id)
|
|
487
|
-
return true;
|
|
488
|
-
if (!bridgeIdsMatch(bridgeItem.id, item.id))
|
|
489
|
-
return false;
|
|
490
|
-
if (bridgeItem.language &&
|
|
491
|
-
item.language &&
|
|
492
|
-
bridgeItem.language.toLowerCase() !== item.language.toLowerCase()) {
|
|
493
|
-
return false;
|
|
494
|
-
}
|
|
495
|
-
if (typeof bridgeItem.version === "number" &&
|
|
496
|
-
Number.isFinite(bridgeItem.version) &&
|
|
497
|
-
typeof item.version === "number" &&
|
|
498
|
-
Number.isFinite(item.version) &&
|
|
499
|
-
bridgeItem.version !== item.version) {
|
|
500
|
-
return false;
|
|
501
|
-
}
|
|
502
|
-
return true;
|
|
503
|
-
}
|
|
504
489
|
function fieldIdentifierMatches(field, fieldId) {
|
|
505
490
|
return (bridgeIdsMatch(field.id, fieldId) ||
|
|
506
491
|
bridgeIdsMatch(field.name, fieldId) ||
|
|
@@ -516,7 +501,7 @@ function findModifiedBridgeField({ modifiedFields, structureField, field, itemDe
|
|
|
516
501
|
return modifiedFields?.find((candidate) => {
|
|
517
502
|
if (dirtyOnly && !candidate.isDirty)
|
|
518
503
|
return false;
|
|
519
|
-
if (!
|
|
504
|
+
if (!bridgeItemDescriptorMatchesItem(candidate.item, itemDescriptor)) {
|
|
520
505
|
return false;
|
|
521
506
|
}
|
|
522
507
|
return (bridgeIdsMatch(candidate.fieldId, structureField.fieldId) ||
|
|
@@ -619,6 +604,7 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
|
|
|
619
604
|
const iframeRef = useRef(null);
|
|
620
605
|
const [iframeElement, setIframeElement] = useState(null);
|
|
621
606
|
const bridgeClientRef = useRef(null);
|
|
607
|
+
const activeBridgePointerDragRef = useRef(null);
|
|
622
608
|
const parentBridgeInjectionRef = useRef(null);
|
|
623
609
|
const latestParentBridgeInjectionRef = useRef(null);
|
|
624
610
|
useEffect(() => {
|
|
@@ -631,6 +617,15 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
|
|
|
631
617
|
const bridgeTextRangeSourcesRef = useRef(new Map());
|
|
632
618
|
const activeBridgeInlineEditRef = useRef(null);
|
|
633
619
|
const discardActiveFieldDraftOnNextRefreshRef = useRef(false);
|
|
620
|
+
useEffect(() => {
|
|
621
|
+
const markAuthoritativeRefresh = () => {
|
|
622
|
+
discardActiveFieldDraftOnNextRefreshRef.current = true;
|
|
623
|
+
};
|
|
624
|
+
window.addEventListener(BRIDGE_AUTHORITATIVE_REFRESH_EVENT, markAuthoritativeRefresh);
|
|
625
|
+
return () => {
|
|
626
|
+
window.removeEventListener(BRIDGE_AUTHORITATIVE_REFRESH_EVENT, markAuthoritativeRefresh);
|
|
627
|
+
};
|
|
628
|
+
}, []);
|
|
634
629
|
const [isBridgeInlineEditing, setIsBridgeInlineEditing] = useState(false);
|
|
635
630
|
const bridgeInlineEditSessionRef = useRef(null);
|
|
636
631
|
if (!bridgeInlineEditSessionRef.current) {
|
|
@@ -641,6 +636,7 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
|
|
|
641
636
|
});
|
|
642
637
|
}
|
|
643
638
|
const bridgeInlineEditSession = bridgeInlineEditSessionRef.current;
|
|
639
|
+
const bridgeInlineEditCommitRef = useRef(null);
|
|
644
640
|
const clearActiveBridgeInlineEdit = useCallback(() => {
|
|
645
641
|
bridgeInlineEditSession.clear();
|
|
646
642
|
}, [bridgeInlineEditSession]);
|
|
@@ -934,7 +930,7 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
|
|
|
934
930
|
bridgeTextCompletionAbortRef.current?.abort();
|
|
935
931
|
};
|
|
936
932
|
}, []);
|
|
937
|
-
const { beginInlineEdit: beginBridgeInlineEdit, clearInlineDedupe: clearBridgeInlineDedupe, endFieldFocus: endBridgeFieldFocus, handleFieldValueChanged: handleBridgeFieldValueChanged, handleInlineEditEnded: handleBridgeInlineEditEnded, } = useBridgeInlineEditing({
|
|
933
|
+
const { beginInlineEdit: beginBridgeInlineEdit, clearInlineDedupe: clearBridgeInlineDedupe, endFieldFocus: endBridgeFieldFocus, flushPendingFieldValueChanges: flushPendingBridgeFieldValueChanges, handleFieldValueChanged: handleBridgeFieldValueChanged, handleInlineEditEnded: handleBridgeInlineEditEnded, supersedeInlineEdit: supersedeBridgeInlineEdit, } = useBridgeInlineEditing({
|
|
938
934
|
pageViewContextRef,
|
|
939
935
|
inlineEditSession: bridgeInlineEditSession,
|
|
940
936
|
blockIframeBlurUntil,
|
|
@@ -958,7 +954,11 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
|
|
|
958
954
|
database: interaction.item.database,
|
|
959
955
|
}
|
|
960
956
|
: undefined;
|
|
961
|
-
|
|
957
|
+
// A repeated click on an already-active host field must still revalidate
|
|
958
|
+
// the server lock. The inline editor can remain mounted after another UI
|
|
959
|
+
// transition released that lock, so UI-session identity alone is not proof
|
|
960
|
+
// of ownership. Pending begins remain deduplicated by the coordinator.
|
|
961
|
+
const started = await bridgeInlineEditSession.revalidateSession({
|
|
962
962
|
elementKey: interaction.elementKey,
|
|
963
963
|
fieldId: interaction.fieldId,
|
|
964
964
|
item: interactionItem,
|
|
@@ -975,6 +975,50 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
|
|
|
975
975
|
clearActiveBridgeInlineEdit();
|
|
976
976
|
endBridgeFieldFocus();
|
|
977
977
|
}, [clearActiveBridgeInlineEdit, endBridgeFieldFocus]);
|
|
978
|
+
const commitActiveBridgeInlineEdit = useCallback(() => {
|
|
979
|
+
if (bridgeInlineEditCommitRef.current) {
|
|
980
|
+
return bridgeInlineEditCommitRef.current;
|
|
981
|
+
}
|
|
982
|
+
const activeEdit = activeBridgeInlineEditRef.current;
|
|
983
|
+
if (!activeEdit) {
|
|
984
|
+
return flushPendingBridgeFieldValueChanges().then(() => undefined);
|
|
985
|
+
}
|
|
986
|
+
const bridge = bridgeClientRef.current;
|
|
987
|
+
if (!bridge) {
|
|
988
|
+
return Promise.reject(new Error("Cannot commit the inline edit because the bridge is unavailable."));
|
|
989
|
+
}
|
|
990
|
+
const commit = bridge
|
|
991
|
+
.requestCommand("commitInlineEdit", {
|
|
992
|
+
elementKey: activeEdit.elementKey,
|
|
993
|
+
fieldId: activeEdit.fieldId,
|
|
994
|
+
}, "inlineEditEnded")
|
|
995
|
+
.then(async () => {
|
|
996
|
+
// The correlated acknowledgement is dispatched after fieldValueChanged.
|
|
997
|
+
// Drain its repository update, then flush the debounced backend save.
|
|
998
|
+
await flushPendingBridgeFieldValueChanges();
|
|
999
|
+
await editContextRef.current?.operations.onFieldBlur?.();
|
|
1000
|
+
})
|
|
1001
|
+
.finally(() => {
|
|
1002
|
+
if (bridgeInlineEditCommitRef.current === commit) {
|
|
1003
|
+
bridgeInlineEditCommitRef.current = null;
|
|
1004
|
+
}
|
|
1005
|
+
});
|
|
1006
|
+
bridgeInlineEditCommitRef.current = commit;
|
|
1007
|
+
return commit;
|
|
1008
|
+
}, [editContextRef, flushPendingBridgeFieldValueChanges]);
|
|
1009
|
+
useEffect(() => {
|
|
1010
|
+
const handleCommitRequest = (event) => {
|
|
1011
|
+
const detail = event
|
|
1012
|
+
.detail;
|
|
1013
|
+
if (!detail)
|
|
1014
|
+
return;
|
|
1015
|
+
detail.barriers.push(commitActiveBridgeInlineEdit());
|
|
1016
|
+
};
|
|
1017
|
+
window.addEventListener(BRIDGE_INLINE_EDIT_COMMIT_EVENT, handleCommitRequest);
|
|
1018
|
+
return () => {
|
|
1019
|
+
window.removeEventListener(BRIDGE_INLINE_EDIT_COMMIT_EVENT, handleCommitRequest);
|
|
1020
|
+
};
|
|
1021
|
+
}, [commitActiveBridgeInlineEdit]);
|
|
978
1022
|
const beginTrackedBridgeInlineEditAfterSelection = useCallback((interaction) => {
|
|
979
1023
|
window.setTimeout(() => {
|
|
980
1024
|
void beginTrackedBridgeInlineEdit(interaction);
|
|
@@ -997,22 +1041,36 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
|
|
|
997
1041
|
activeInlineEdit: activeEdit,
|
|
998
1042
|
field: summarizeFieldDescriptor(field),
|
|
999
1043
|
});
|
|
1000
|
-
|
|
1044
|
+
// The form is now authoritative for this field. Superseding closes the
|
|
1045
|
+
// host-side contenteditable session and tombstones any already-posted
|
|
1046
|
+
// draft events, so the form patch is neither rejected by the host nor
|
|
1047
|
+
// raced back to the previous canvas value.
|
|
1048
|
+
supersedeBridgeInlineEdit(activeEdit);
|
|
1001
1049
|
bridgePatchSignatureRef.current.delete(`${activeEdit.elementKey}:${activeEdit.fieldId}`);
|
|
1002
1050
|
};
|
|
1003
1051
|
window.addEventListener(BRIDGE_INLINE_EDIT_RELEASE_EVENT, handleBridgeInlineEditRelease);
|
|
1004
1052
|
return () => {
|
|
1005
1053
|
window.removeEventListener(BRIDGE_INLINE_EDIT_RELEASE_EVENT, handleBridgeInlineEditRelease);
|
|
1006
1054
|
};
|
|
1007
|
-
}, [
|
|
1055
|
+
}, [supersedeBridgeInlineEdit]);
|
|
1008
1056
|
useEffect(() => {
|
|
1009
1057
|
return editContext.registerModeChangeParticipant({
|
|
1010
|
-
|
|
1058
|
+
captureBeforeModeChange: () => commitActiveBridgeInlineEdit(),
|
|
1059
|
+
beforeModeChange: async (nextMode) => {
|
|
1011
1060
|
if (nextMode === "suggestions" &&
|
|
1012
1061
|
getSelectedRangeInlineEditInteraction(editContextRef.current?.selectedRange)) {
|
|
1062
|
+
// Keep the live selection/focus so it can seed the suggestion edit,
|
|
1063
|
+
// but still cross the persistence boundary for text typed in edit
|
|
1064
|
+
// mode. Skipping this flush could make suggestions use an older
|
|
1065
|
+
// repository value as their baseline.
|
|
1066
|
+
await flushPendingBridgeFieldValueChanges();
|
|
1067
|
+
await editContext.operations.onFieldBlur?.();
|
|
1068
|
+
await editContext.operations.prepareForModeChange?.();
|
|
1013
1069
|
return;
|
|
1014
1070
|
}
|
|
1015
|
-
|
|
1071
|
+
await flushPendingBridgeFieldValueChanges();
|
|
1072
|
+
await editContext.operations.onFieldBlur?.();
|
|
1073
|
+
await editContext.operations.prepareForModeChange?.();
|
|
1016
1074
|
void fieldsContextRef.current?.setFocusedField(undefined, false);
|
|
1017
1075
|
clearActiveBridgeInlineEdit();
|
|
1018
1076
|
endBridgeFieldFocus();
|
|
@@ -1024,10 +1082,12 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
|
|
|
1024
1082
|
}, [
|
|
1025
1083
|
clearBridgeInlineDedupe,
|
|
1026
1084
|
clearActiveBridgeInlineEdit,
|
|
1085
|
+
commitActiveBridgeInlineEdit,
|
|
1027
1086
|
editContext,
|
|
1028
1087
|
editContextRef,
|
|
1029
1088
|
endBridgeFieldFocus,
|
|
1030
1089
|
fieldsContextRef,
|
|
1090
|
+
flushPendingBridgeFieldValueChanges,
|
|
1031
1091
|
]);
|
|
1032
1092
|
const getBridgePatchDisplayValue = useCallback(({ field, structureField, itemDescriptor, preferRepositoryValue, }) => {
|
|
1033
1093
|
const showSuggestions = editContext.mode === "suggestions";
|
|
@@ -1069,19 +1129,23 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
|
|
|
1069
1129
|
fieldsContext?.modifiedFields,
|
|
1070
1130
|
pageViewContext.pageItemDescriptor,
|
|
1071
1131
|
]);
|
|
1072
|
-
const buildBridgeFieldPatch = useCallback(({ field, structureField, itemDescriptor, preferRepositoryValue, }) => {
|
|
1132
|
+
const buildBridgeFieldPatch = useCallback(({ field, structureField, itemDescriptor, preferRepositoryValue, replaceActiveInlineEdit, }) => {
|
|
1073
1133
|
const display = getBridgePatchDisplayValue({
|
|
1074
1134
|
field,
|
|
1075
1135
|
structureField,
|
|
1076
1136
|
itemDescriptor,
|
|
1077
1137
|
preferRepositoryValue,
|
|
1078
1138
|
});
|
|
1079
|
-
const
|
|
1139
|
+
const effectiveDisplay = replaceActiveInlineEdit
|
|
1140
|
+
? { ...display, source: "reset" }
|
|
1141
|
+
: display;
|
|
1080
1142
|
const patch = buildBridgeFieldPatchPayload({
|
|
1081
1143
|
field,
|
|
1082
1144
|
structureField,
|
|
1083
|
-
display,
|
|
1084
|
-
activeInlineEdit
|
|
1145
|
+
display: effectiveDisplay,
|
|
1146
|
+
activeInlineEdit: replaceActiveInlineEdit
|
|
1147
|
+
? undefined
|
|
1148
|
+
: activeBridgeInlineEditRef.current,
|
|
1085
1149
|
});
|
|
1086
1150
|
return patch;
|
|
1087
1151
|
}, [getBridgePatchDisplayValue]);
|
|
@@ -1165,6 +1229,11 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
|
|
|
1165
1229
|
structureFields,
|
|
1166
1230
|
activeInlineEdit: activeBridgeInlineEditRef.current,
|
|
1167
1231
|
});
|
|
1232
|
+
// Keep the host informed about the complete live-draft set. Unlike an
|
|
1233
|
+
// ordinary field patch, this state survives host-app/React renders: the
|
|
1234
|
+
// bridge reapplies these values in its mutation observer before other
|
|
1235
|
+
// observers can see stale server markup.
|
|
1236
|
+
bridge.sendCommand("syncRemoteFieldDrafts", { drafts: patches });
|
|
1168
1237
|
for (const patch of patches) {
|
|
1169
1238
|
const structureField = structureFields.find((field) => field.elementKey === patch.elementKey);
|
|
1170
1239
|
sendBridgeFieldPatch(bridge, patch, structureField?.textContent);
|
|
@@ -1643,6 +1712,13 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
|
|
|
1643
1712
|
}
|
|
1644
1713
|
const iframeRect = iframe.getBoundingClientRect();
|
|
1645
1714
|
const bridgeSelection = latestBridgeSelectionRef.current;
|
|
1715
|
+
const commandRange = resolveBridgeInlineAiSelectionRange({
|
|
1716
|
+
interaction,
|
|
1717
|
+
bridgeSelection,
|
|
1718
|
+
iframeRect,
|
|
1719
|
+
fallbackItem: pageViewContextRef.current?.page?.item ??
|
|
1720
|
+
pageViewContextRef.current?.pageItemDescriptor,
|
|
1721
|
+
});
|
|
1646
1722
|
const fallbackCaretRect = !interaction.selectionRect &&
|
|
1647
1723
|
!interaction.caretRect &&
|
|
1648
1724
|
bridgeSelection?.collapsed &&
|
|
@@ -1655,7 +1731,9 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
|
|
|
1655
1731
|
interaction.caretRect ??
|
|
1656
1732
|
fallbackCaretRect;
|
|
1657
1733
|
const toolbarRect = await waitForVisibleBridgeToolbarRect();
|
|
1658
|
-
const selectedRange =
|
|
1734
|
+
const selectedRange = commandRange ??
|
|
1735
|
+
editContextRef.current?.selectedRange ??
|
|
1736
|
+
editor?.selectedRange;
|
|
1659
1737
|
const toolbarAnchor = getInlineAiAnchorFromBridgeToolbar(selectedRange, toolbarRect ?? getVisibleBridgeToolbarRect());
|
|
1660
1738
|
const caretAnchor = toolbarAnchor
|
|
1661
1739
|
? toolbarAnchor
|
|
@@ -1678,7 +1756,9 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
|
|
|
1678
1756
|
document.dispatchEvent(new CustomEvent("inline-ai-open", {
|
|
1679
1757
|
bubbles: true,
|
|
1680
1758
|
cancelable: true,
|
|
1681
|
-
detail: caretAnchor
|
|
1759
|
+
detail: caretAnchor || commandRange
|
|
1760
|
+
? { anchor: caretAnchor, selectionRange: commandRange }
|
|
1761
|
+
: undefined,
|
|
1682
1762
|
}));
|
|
1683
1763
|
return;
|
|
1684
1764
|
}
|
|
@@ -2045,6 +2125,62 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
|
|
|
2045
2125
|
useEffect(() => {
|
|
2046
2126
|
pageViewContext.setEditorIframe(iframeElement);
|
|
2047
2127
|
}, [iframeElement, pageViewContext.setEditorIframe]);
|
|
2128
|
+
// A host drag normally ends inside the iframe and is forwarded by the
|
|
2129
|
+
// bridge. If Chromium loses pointer capture while the pointer crosses into
|
|
2130
|
+
// parent-rendered editor chrome, however, the release belongs to this
|
|
2131
|
+
// document and the iframe never receives pointerup. Finish that same drag
|
|
2132
|
+
// here so it cannot leave the editor stuck in insertion mode.
|
|
2133
|
+
useEffect(() => {
|
|
2134
|
+
const iframe = iframeElement;
|
|
2135
|
+
if (!iframe)
|
|
2136
|
+
return;
|
|
2137
|
+
const forwardParentPointerMove = (event) => {
|
|
2138
|
+
const active = activeBridgePointerDragRef.current;
|
|
2139
|
+
if (!active || event.pointerId !== active.pointerId)
|
|
2140
|
+
return;
|
|
2141
|
+
const projected = projectParentPointerToHost(event.clientX, event.clientY, iframe.getBoundingClientRect(), pageViewContextRef.current?.bridgeGeometry?.viewport);
|
|
2142
|
+
if (!projected.inside)
|
|
2143
|
+
return;
|
|
2144
|
+
active.clientX = projected.clientX;
|
|
2145
|
+
active.clientY = projected.clientY;
|
|
2146
|
+
iframe.dispatchEvent(new CustomEvent(IFRAME_OVERLAY_BRIDGE_DRAG_GESTURE_EVENT, {
|
|
2147
|
+
detail: {
|
|
2148
|
+
phase: "move",
|
|
2149
|
+
pointerId: active.pointerId,
|
|
2150
|
+
clientX: projected.clientX,
|
|
2151
|
+
clientY: projected.clientY,
|
|
2152
|
+
},
|
|
2153
|
+
}));
|
|
2154
|
+
};
|
|
2155
|
+
const finishBridgePointerDrag = (event) => {
|
|
2156
|
+
const active = activeBridgePointerDragRef.current;
|
|
2157
|
+
if (!active)
|
|
2158
|
+
return;
|
|
2159
|
+
const rect = iframe.getBoundingClientRect();
|
|
2160
|
+
const payload = resolveParentBridgePointerRelease(active, event, rect, pageViewContextRef.current?.bridgeGeometry?.viewport);
|
|
2161
|
+
if (!payload)
|
|
2162
|
+
return;
|
|
2163
|
+
// Clear before dispatching and before asking the host to clean up. Any
|
|
2164
|
+
// delayed move/end messages from the bridge then become harmless echoes.
|
|
2165
|
+
activeBridgePointerDragRef.current = null;
|
|
2166
|
+
iframe.dispatchEvent(new CustomEvent(IFRAME_OVERLAY_BRIDGE_DRAG_GESTURE_EVENT, {
|
|
2167
|
+
detail: {
|
|
2168
|
+
phase: "end",
|
|
2169
|
+
...payload,
|
|
2170
|
+
},
|
|
2171
|
+
}));
|
|
2172
|
+
bridgeClientRef.current?.sendCommand("cancelPointerDrag", {});
|
|
2173
|
+
};
|
|
2174
|
+
window.addEventListener("pointermove", forwardParentPointerMove, true);
|
|
2175
|
+
window.addEventListener("pointerup", finishBridgePointerDrag, true);
|
|
2176
|
+
window.addEventListener("mouseup", finishBridgePointerDrag, true);
|
|
2177
|
+
return () => {
|
|
2178
|
+
window.removeEventListener("pointermove", forwardParentPointerMove, true);
|
|
2179
|
+
window.removeEventListener("pointerup", finishBridgePointerDrag, true);
|
|
2180
|
+
window.removeEventListener("mouseup", finishBridgePointerDrag, true);
|
|
2181
|
+
activeBridgePointerDragRef.current = null;
|
|
2182
|
+
};
|
|
2183
|
+
}, [iframeElement]);
|
|
2048
2184
|
// Same-origin fast path for overlay scroll tracking. The bridge's
|
|
2049
2185
|
// scrollChanged postMessage is delivered as a task after the host's
|
|
2050
2186
|
// rendering update, so overlays driven by it paint at least one frame
|
|
@@ -2173,8 +2309,15 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
|
|
|
2173
2309
|
// Ready confirms the bridge transport, not that its initial
|
|
2174
2310
|
// mutation-driven geometry snapshot reached the editor. Query the
|
|
2175
2311
|
// current DOM explicitly so editing chrome never depends on that
|
|
2176
|
-
// first unsolicited event surviving startup contention.
|
|
2177
|
-
|
|
2312
|
+
// first unsolicited event surviving startup contention. A newly
|
|
2313
|
+
// connected iframe has no memory of the text-range union registered
|
|
2314
|
+
// by comments, suggestions, locks, and version diffs, so replay it
|
|
2315
|
+
// here. Sending a bare query can otherwise clear those ranges while
|
|
2316
|
+
// the contributing overlay still has the same request signature and
|
|
2317
|
+
// therefore has no reason to emit it again.
|
|
2318
|
+
bridge.sendCommand("queryGeometry", {
|
|
2319
|
+
textRanges: Array.from(bridgeTextRangeSourcesRef.current.values()).flat(),
|
|
2320
|
+
});
|
|
2178
2321
|
if (pendingRefreshScrollRef.current) {
|
|
2179
2322
|
restorePendingRefreshScroll(iframe, pendingRefreshScrollRef.current);
|
|
2180
2323
|
}
|
|
@@ -2205,6 +2348,29 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
|
|
|
2205
2348
|
case "pageSkeletonUpdated":
|
|
2206
2349
|
pageViewContext.setPageSkeleton(event.payload.pageSkeleton);
|
|
2207
2350
|
break;
|
|
2351
|
+
case "resizeChanged": {
|
|
2352
|
+
const currentGeometry = pageViewContext.bridgeGeometry;
|
|
2353
|
+
const viewportChanged = !currentGeometry ||
|
|
2354
|
+
currentGeometry.viewport.width !== event.payload.viewport.width ||
|
|
2355
|
+
currentGeometry.viewport.height !== event.payload.viewport.height ||
|
|
2356
|
+
currentGeometry.devicePixelRatio !==
|
|
2357
|
+
event.payload.devicePixelRatio;
|
|
2358
|
+
if (!viewportChanged)
|
|
2359
|
+
break;
|
|
2360
|
+
// Target rects are viewport-relative. Once the host reports a new
|
|
2361
|
+
// viewport, retaining the previous snapshot can visibly displace
|
|
2362
|
+
// chrome until the host's debounced geometry update arrives (for
|
|
2363
|
+
// example, when the minimap narrows the canvas). Remove that stale
|
|
2364
|
+
// snapshot immediately and request its replacement now, preserving
|
|
2365
|
+
// every overlay's registered text-range query.
|
|
2366
|
+
pageViewContext.bridgeGeometry = undefined;
|
|
2367
|
+
pageViewContext.setBridgeGeometry(undefined);
|
|
2368
|
+
scheduleBridgeGeometryRevision();
|
|
2369
|
+
bridge.sendCommand("queryGeometry", {
|
|
2370
|
+
textRanges: Array.from(bridgeTextRangeSourcesRef.current.values()).flat(),
|
|
2371
|
+
});
|
|
2372
|
+
break;
|
|
2373
|
+
}
|
|
2208
2374
|
case "geometryUpdated": {
|
|
2209
2375
|
if (isPerfTraceActive()) {
|
|
2210
2376
|
perfTraceStep("frame:geometry-updated-received", {
|
|
@@ -2373,21 +2539,39 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
|
|
|
2373
2539
|
void handleBridgeInteraction(event.payload, iframe);
|
|
2374
2540
|
break;
|
|
2375
2541
|
case "dragGestureStarted":
|
|
2542
|
+
activeBridgePointerDragRef.current = {
|
|
2543
|
+
pointerId: event.payload.pointerId,
|
|
2544
|
+
clientX: event.payload.clientX,
|
|
2545
|
+
clientY: event.payload.clientY,
|
|
2546
|
+
};
|
|
2376
2547
|
iframe?.dispatchEvent(new CustomEvent(IFRAME_OVERLAY_BRIDGE_DRAG_GESTURE_EVENT, {
|
|
2377
2548
|
detail: { phase: "start", ...event.payload },
|
|
2378
2549
|
}));
|
|
2379
2550
|
break;
|
|
2380
|
-
case "dragGestureMoved":
|
|
2551
|
+
case "dragGestureMoved": {
|
|
2552
|
+
const active = activeBridgePointerDragRef.current;
|
|
2553
|
+
if (!active || active.pointerId !== event.payload.pointerId)
|
|
2554
|
+
break;
|
|
2555
|
+
active.clientX = event.payload.clientX;
|
|
2556
|
+
active.clientY = event.payload.clientY;
|
|
2381
2557
|
iframe?.dispatchEvent(new CustomEvent(IFRAME_OVERLAY_BRIDGE_DRAG_GESTURE_EVENT, {
|
|
2382
2558
|
detail: { phase: "move", ...event.payload },
|
|
2383
2559
|
}));
|
|
2384
2560
|
break;
|
|
2385
|
-
|
|
2561
|
+
}
|
|
2562
|
+
case "dragGestureEnded": {
|
|
2563
|
+
const active = activeBridgePointerDragRef.current;
|
|
2564
|
+
if (!active || active.pointerId !== event.payload.pointerId)
|
|
2565
|
+
break;
|
|
2566
|
+
activeBridgePointerDragRef.current = null;
|
|
2386
2567
|
iframe?.dispatchEvent(new CustomEvent(IFRAME_OVERLAY_BRIDGE_DRAG_GESTURE_EVENT, {
|
|
2387
2568
|
detail: { phase: "end", ...event.payload },
|
|
2388
2569
|
}));
|
|
2389
2570
|
break;
|
|
2571
|
+
}
|
|
2390
2572
|
case "dragSnapshot":
|
|
2573
|
+
if (!activeBridgePointerDragRef.current)
|
|
2574
|
+
break;
|
|
2391
2575
|
iframe?.dispatchEvent(new CustomEvent(IFRAME_OVERLAY_BRIDGE_DRAG_GESTURE_EVENT, {
|
|
2392
2576
|
detail: { phase: "snapshot", ...event.payload },
|
|
2393
2577
|
}));
|
|
@@ -2463,17 +2647,41 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
|
|
|
2463
2647
|
return;
|
|
2464
2648
|
const patchedElementKeys = new Set();
|
|
2465
2649
|
const patches = [];
|
|
2650
|
+
const pageItemDescriptor = pageViewContextRef.current?.pageItemDescriptor ??
|
|
2651
|
+
pageViewContextRef.current?.page?.item?.descriptor;
|
|
2466
2652
|
for (const structureField of structure.fields) {
|
|
2467
2653
|
if (!structureField.elementKey)
|
|
2468
2654
|
continue;
|
|
2469
2655
|
if (patchedElementKeys.has(structureField.elementKey))
|
|
2470
2656
|
continue;
|
|
2471
|
-
|
|
2657
|
+
const targetItem = structureField.item?.id
|
|
2658
|
+
? structureField.item
|
|
2659
|
+
: pageItemDescriptor;
|
|
2660
|
+
if (!targetItem ||
|
|
2661
|
+
!bridgeItemDescriptorMatchesItem(targetItem, change.item)) {
|
|
2472
2662
|
continue;
|
|
2473
2663
|
}
|
|
2474
2664
|
if (!bridgeFieldMatchesChangedField(structureField.fieldId, changedFieldId, field)) {
|
|
2475
2665
|
continue;
|
|
2476
2666
|
}
|
|
2667
|
+
if (change.replaceActiveInlineEdit) {
|
|
2668
|
+
const identity = {
|
|
2669
|
+
elementKey: structureField.elementKey,
|
|
2670
|
+
fieldId: structureField.fieldId,
|
|
2671
|
+
item: structureField.item,
|
|
2672
|
+
};
|
|
2673
|
+
const inlineEdit = bridgeInlineEditSession.matches(identity)
|
|
2674
|
+
? bridgeInlineEditSession.getState()
|
|
2675
|
+
: bridgeInlineEditSession.getRecentlyClearedState(identity);
|
|
2676
|
+
if (inlineEdit) {
|
|
2677
|
+
// End the canvas session before sending the reset patch. This
|
|
2678
|
+
// prevents a later host refresh from preserving the superseded
|
|
2679
|
+
// draft, and tombstones already-captured events from that
|
|
2680
|
+
// session so they cannot race the external edit back to Sitecore.
|
|
2681
|
+
supersedeBridgeInlineEdit(inlineEdit);
|
|
2682
|
+
bridgePatchSignatureRef.current.delete(`${structureField.elementKey}:${structureField.fieldId}`);
|
|
2683
|
+
}
|
|
2684
|
+
}
|
|
2477
2685
|
// A remote session is live-syncing this field: its draft is
|
|
2478
2686
|
// authoritative, and the saved-value echo behind this change is
|
|
2479
2687
|
// stale mid-typing — applying it would roll the canvas text back
|
|
@@ -2490,6 +2698,7 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
|
|
|
2490
2698
|
structureField,
|
|
2491
2699
|
itemDescriptor: change.item,
|
|
2492
2700
|
preferRepositoryValue: change.source === "local-field-update",
|
|
2701
|
+
replaceActiveInlineEdit: change.replaceActiveInlineEdit,
|
|
2493
2702
|
});
|
|
2494
2703
|
if (!patch)
|
|
2495
2704
|
continue;
|
|
@@ -2506,6 +2715,11 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
|
|
|
2506
2715
|
};
|
|
2507
2716
|
const asyncFieldChanges = [];
|
|
2508
2717
|
for (const change of fieldChanges) {
|
|
2718
|
+
const pageItemDescriptor = pageViewContextRef.current?.pageItemDescriptor ??
|
|
2719
|
+
pageViewContextRef.current?.page?.item?.descriptor;
|
|
2720
|
+
if (!bridgeStructureTargetsChangedItem(structure.fields, change.item, pageItemDescriptor)) {
|
|
2721
|
+
continue;
|
|
2722
|
+
}
|
|
2509
2723
|
const localFieldsById = new Map((change.changes.fieldValues ?? []).map((field) => [
|
|
2510
2724
|
field.id.toLowerCase(),
|
|
2511
2725
|
field,
|
|
@@ -2558,8 +2772,10 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
|
|
|
2558
2772
|
};
|
|
2559
2773
|
}, [
|
|
2560
2774
|
buildBridgeFieldPatch,
|
|
2775
|
+
bridgeInlineEditSession,
|
|
2561
2776
|
editContext.itemsRepository,
|
|
2562
2777
|
sendBridgeFieldPatch,
|
|
2778
|
+
supersedeBridgeInlineEdit,
|
|
2563
2779
|
]);
|
|
2564
2780
|
useEffect(() => {
|
|
2565
2781
|
const bridge = bridgeClientRef.current;
|
|
@@ -2896,15 +3112,17 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
|
|
|
2896
3112
|
const fullReloadRequested = lastFullReloadTokenRef.current !== undefined &&
|
|
2897
3113
|
lastFullReloadTokenRef.current !== editContext.fullReloadToken;
|
|
2898
3114
|
lastFullReloadTokenRef.current = editContext.fullReloadToken;
|
|
2899
|
-
const shouldUseIframeSrcReload = initialLoad ||
|
|
2900
|
-
pageViewContext.fullscreen ||
|
|
2901
|
-
iframeOriginChanged ||
|
|
2902
|
-
fullReloadRequested;
|
|
2903
3115
|
const signatureUrl = new URL(renderUrl.toString());
|
|
2904
3116
|
signatureUrl.searchParams.delete("edit_rev");
|
|
2905
3117
|
const renderSignature = `${signatureUrl.toString()}|rev:${editContext.revision}`;
|
|
2906
|
-
const
|
|
3118
|
+
const previousRenderMode = lastRenderModeRef.current;
|
|
3119
|
+
const modeChanged = previousRenderMode !== editContext.mode;
|
|
3120
|
+
const previewRenderBoundaryChanged = crossesPreviewRenderBoundary(previousRenderMode, editContext.mode);
|
|
2907
3121
|
lastRenderModeRef.current = editContext.mode;
|
|
3122
|
+
const shouldUseIframeSrcReload = initialLoad ||
|
|
3123
|
+
iframeOriginChanged ||
|
|
3124
|
+
fullReloadRequested ||
|
|
3125
|
+
previewRenderBoundaryChanged;
|
|
2908
3126
|
// Only skip when a live bridge confirms the last refresh actually reached
|
|
2909
3127
|
// the host, or when the only meaningful trigger is an edit/suggestions
|
|
2910
3128
|
// mode change. Mode is delivered by setEditorMode and cannot change the
|
|
@@ -3358,6 +3576,10 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
|
|
|
3358
3576
|
}
|
|
3359
3577
|
}, children: [_jsx("iframe", { ref: bindIframeRef, className: "page-iframe h-full w-full bg-white transition-[height] duration-300 ease-in-out motion-reduce:transition-none", style: {
|
|
3360
3578
|
height: deviceHeight,
|
|
3579
|
+
// The iframe element exists before its document has loaded. Keep
|
|
3580
|
+
// that blank document out of both the UI and accessibility tree;
|
|
3581
|
+
// consumers can treat a visible canvas as a rendered canvas.
|
|
3582
|
+
visibility: loadedIframeSrc ? "visible" : "hidden",
|
|
3361
3583
|
cursor: showSuggestionsCursor
|
|
3362
3584
|
? SUGGESTIONS_CURSOR_VALUE
|
|
3363
3585
|
: undefined,
|
|
@@ -3375,7 +3597,7 @@ function PageViewerFrameContent({ compareView, pageViewContext, editContext, cla
|
|
|
3375
3597
|
parentBridgeInjectionRef.current.attempt;
|
|
3376
3598
|
}
|
|
3377
3599
|
const loadedSrc = iframe?.src;
|
|
3378
|
-
if (loadedSrc) {
|
|
3600
|
+
if (iframeSrc && loadedSrc) {
|
|
3379
3601
|
setLoadedIframeSrc(loadedSrc);
|
|
3380
3602
|
}
|
|
3381
3603
|
const sendZoomToBridge = () => {
|