@parhelia/core 0.1.12868 → 0.1.12875

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 (290) hide show
  1. package/dist/components/ui/card.d.ts +3 -1
  2. package/dist/components/ui/card.js +2 -2
  3. package/dist/components/ui/card.js.map +1 -1
  4. package/dist/components/ui/context-menu.js +2 -2
  5. package/dist/config/config.js +22 -2
  6. package/dist/config/config.js.map +1 -1
  7. package/dist/config/types.d.ts +0 -1
  8. package/dist/config/types.js.map +1 -1
  9. package/dist/editor/FieldActionsOverlay.d.ts +0 -1
  10. package/dist/editor/FieldActionsOverlay.js +1 -45
  11. package/dist/editor/FieldActionsOverlay.js.map +1 -1
  12. package/dist/editor/FieldListField.d.ts +1 -1
  13. package/dist/editor/FieldListField.js +20 -18
  14. package/dist/editor/FieldListField.js.map +1 -1
  15. package/dist/editor/ImageEditor.d.ts +6 -1
  16. package/dist/editor/ImageEditor.js +19 -3
  17. package/dist/editor/ImageEditor.js.map +1 -1
  18. package/dist/editor/PictureEditor.d.ts +2 -1
  19. package/dist/editor/PictureEditor.js +5 -14
  20. package/dist/editor/PictureEditor.js.map +1 -1
  21. package/dist/editor/ai/Agents.js +2 -2
  22. package/dist/editor/ai/Agents.js.map +1 -1
  23. package/dist/editor/ai/GuidanceOverlay.js +1 -11
  24. package/dist/editor/ai/GuidanceOverlay.js.map +1 -1
  25. package/dist/editor/ai/InlineAiDialog.js +22 -11
  26. package/dist/editor/ai/InlineAiDialog.js.map +1 -1
  27. package/dist/editor/ai/InlineAiTrigger.js +15 -15
  28. package/dist/editor/ai/InlineAiTrigger.js.map +1 -1
  29. package/dist/editor/ai/dialogs/capturePageDom.js +66 -36
  30. package/dist/editor/ai/dialogs/capturePageDom.js.map +1 -1
  31. package/dist/editor/ai/dialogs/capturePageScreenshot.js +281 -162
  32. package/dist/editor/ai/dialogs/capturePageScreenshot.js.map +1 -1
  33. package/dist/editor/ai/terminal/agentSessionState.d.ts +3 -0
  34. package/dist/editor/ai/terminal/agentSessionState.js +3 -1
  35. package/dist/editor/ai/terminal/agentSessionState.js.map +1 -1
  36. package/dist/editor/ai/terminal/agentStartRequest.d.ts +2 -1
  37. package/dist/editor/ai/terminal/agentStartRequest.js +2 -1
  38. package/dist/editor/ai/terminal/agentStartRequest.js.map +1 -1
  39. package/dist/editor/ai/terminal/components/AgentCostDisplay.js +1 -1
  40. package/dist/editor/ai/terminal/components/AgentCostDisplay.js.map +1 -1
  41. package/dist/editor/ai/terminal/components/AgentDocumentList.d.ts +7 -0
  42. package/dist/editor/ai/terminal/components/AgentDocumentList.js +55 -13
  43. package/dist/editor/ai/terminal/components/AgentDocumentList.js.map +1 -1
  44. package/dist/editor/ai/terminal/components/AgentEditHistoryButton.d.ts +5 -0
  45. package/dist/editor/ai/terminal/components/AgentEditHistoryButton.js +12 -0
  46. package/dist/editor/ai/terminal/components/AgentEditHistoryButton.js.map +1 -0
  47. package/dist/editor/ai/terminal/components/AgentFullPromptControls.d.ts +3 -1
  48. package/dist/editor/ai/terminal/components/AgentFullPromptControls.js +22 -14
  49. package/dist/editor/ai/terminal/components/AgentFullPromptControls.js.map +1 -1
  50. package/dist/editor/ai/terminal/components/AgentModeSelector.js +4 -4
  51. package/dist/editor/ai/terminal/components/AgentModeSelector.js.map +1 -1
  52. package/dist/editor/ai/terminal/components/AgentPromptActionButtons.js +4 -4
  53. package/dist/editor/ai/terminal/components/AgentPromptActionButtons.js.map +1 -1
  54. package/dist/editor/ai/terminal/components/AgentPromptComposer.js +1 -1
  55. package/dist/editor/ai/terminal/components/AgentPromptComposer.js.map +1 -1
  56. package/dist/editor/ai/terminal/components/AgentPromptInputArea.d.ts +2 -1
  57. package/dist/editor/ai/terminal/components/AgentPromptInputArea.js +8 -11
  58. package/dist/editor/ai/terminal/components/AgentPromptInputArea.js.map +1 -1
  59. package/dist/editor/ai/terminal/components/AgentPromptTrayPopovers.d.ts +1 -4
  60. package/dist/editor/ai/terminal/components/AgentPromptTrayPopovers.js +29 -13
  61. package/dist/editor/ai/terminal/components/AgentPromptTrayPopovers.js.map +1 -1
  62. package/dist/editor/ai/terminal/components/AgentSettingsPopover.js +1 -1
  63. package/dist/editor/ai/terminal/components/AgentSettingsPopover.js.map +1 -1
  64. package/dist/editor/ai/terminal/components/AgentTerminalFullLayout.d.ts +2 -1
  65. package/dist/editor/ai/terminal/components/AgentTerminalFullLayout.js +2 -4
  66. package/dist/editor/ai/terminal/components/AgentTerminalFullLayout.js.map +1 -1
  67. package/dist/editor/ai/terminal/components/AgentTerminalMessageGroups.js +1 -1
  68. package/dist/editor/ai/terminal/components/AgentTerminalMessageGroups.js.map +1 -1
  69. package/dist/editor/ai/terminal/components/AgentTerminalView.js +13 -2
  70. package/dist/editor/ai/terminal/components/AgentTerminalView.js.map +1 -1
  71. package/dist/editor/ai/terminal/components/AiResponseMessage.js +16 -14
  72. package/dist/editor/ai/terminal/components/AiResponseMessage.js.map +1 -1
  73. package/dist/editor/ai/terminal/components/QueuedPromptsPanel.js +37 -26
  74. package/dist/editor/ai/terminal/components/QueuedPromptsPanel.js.map +1 -1
  75. package/dist/editor/ai/terminal/components/UserMessage.d.ts +2 -1
  76. package/dist/editor/ai/terminal/components/UserMessage.js +130 -8
  77. package/dist/editor/ai/terminal/components/UserMessage.js.map +1 -1
  78. package/dist/editor/ai/terminal/useAgentPromptComposerHandlers.js +1 -1
  79. package/dist/editor/ai/terminal/useAgentPromptComposerHandlers.js.map +1 -1
  80. package/dist/editor/ai/terminal/useAgentSessionSync.d.ts +1 -0
  81. package/dist/editor/ai/terminal/useAgentSubmitHandlers.d.ts +3 -1
  82. package/dist/editor/ai/terminal/useAgentSubmitHandlers.js +9 -3
  83. package/dist/editor/ai/terminal/useAgentSubmitHandlers.js.map +1 -1
  84. package/dist/editor/ai/terminal/useAgentTerminalController.js +7 -0
  85. package/dist/editor/ai/terminal/useAgentTerminalController.js.map +1 -1
  86. package/dist/editor/ai/terminal/useAgentTerminalUiState.js +1 -1
  87. package/dist/editor/ai/terminal/useAgentTerminalUiState.js.map +1 -1
  88. package/dist/editor/ai/terminal/useAgentUserMessageSocketHandler.js +3 -1
  89. package/dist/editor/ai/terminal/useAgentUserMessageSocketHandler.js.map +1 -1
  90. package/dist/editor/ai/useInlineAiPosition.d.ts +1 -1
  91. package/dist/editor/ai/useInlineAiPosition.js +22 -52
  92. package/dist/editor/ai/useInlineAiPosition.js.map +1 -1
  93. package/dist/editor/ai-image-editor/AiImageResultOverlay.js +30 -62
  94. package/dist/editor/ai-image-editor/AiImageResultOverlay.js.map +1 -1
  95. package/dist/editor/bridge/BridgeClient.d.ts +80 -0
  96. package/dist/editor/bridge/BridgeClient.js +416 -0
  97. package/dist/editor/bridge/BridgeClient.js.map +1 -0
  98. package/dist/editor/client/EditorShell.d.ts +5 -1
  99. package/dist/editor/client/EditorShell.js +286 -126
  100. package/dist/editor/client/EditorShell.js.map +1 -1
  101. package/dist/editor/client/editContext.d.ts +37 -5
  102. package/dist/editor/client/editContext.js.map +1 -1
  103. package/dist/editor/client/hooks/useSocketMessageHandler.js +14 -17
  104. package/dist/editor/client/hooks/useSocketMessageHandler.js.map +1 -1
  105. package/dist/editor/client/itemsRepository.d.ts +2 -0
  106. package/dist/editor/client/itemsRepository.js +15 -8
  107. package/dist/editor/client/itemsRepository.js.map +1 -1
  108. package/dist/editor/client/operations.d.ts +1 -1
  109. package/dist/editor/client/operations.js +41 -17
  110. package/dist/editor/client/operations.js.map +1 -1
  111. package/dist/editor/client/pageModelBuilder.js +24 -7
  112. package/dist/editor/client/pageModelBuilder.js.map +1 -1
  113. package/dist/editor/field-types/MultiLineText.js +10 -3
  114. package/dist/editor/field-types/MultiLineText.js.map +1 -1
  115. package/dist/editor/field-types/RawEditor.js +8 -1
  116. package/dist/editor/field-types/RawEditor.js.map +1 -1
  117. package/dist/editor/field-types/RichTextEditorComponent.js +156 -45
  118. package/dist/editor/field-types/RichTextEditorComponent.js.map +1 -1
  119. package/dist/editor/field-types/SingleLineText.js +10 -3
  120. package/dist/editor/field-types/SingleLineText.js.map +1 -1
  121. package/dist/editor/field-types/richtext/components/ReactSlate.js +8 -2
  122. package/dist/editor/field-types/richtext/components/ReactSlate.js.map +1 -1
  123. package/dist/editor/field-types/richtext/contextMenuFactory.d.ts +1 -2
  124. package/dist/editor/field-types/richtext/contextMenuFactory.js +100 -303
  125. package/dist/editor/field-types/richtext/contextMenuFactory.js.map +1 -1
  126. package/dist/editor/field-types/richtext/types.d.ts +2 -0
  127. package/dist/editor/field-types/richtext/types.js.map +1 -1
  128. package/dist/editor/field-types/useFormFieldCaretPresence.d.ts +13 -0
  129. package/dist/editor/field-types/useFormFieldCaretPresence.js +92 -0
  130. package/dist/editor/field-types/useFormFieldCaretPresence.js.map +1 -0
  131. package/dist/editor/media-selector/TreeSelector.js +15 -15
  132. package/dist/editor/media-selector/TreeSelector.js.map +1 -1
  133. package/dist/editor/menubar/PageSelector.js +8 -2
  134. package/dist/editor/menubar/PageSelector.js.map +1 -1
  135. package/dist/editor/menubar/VersionPreviewCard.js +4 -249
  136. package/dist/editor/menubar/VersionPreviewCard.js.map +1 -1
  137. package/dist/editor/menubar/toolbar-sections/EditControls.js +2 -2
  138. package/dist/editor/menubar/toolbar-sections/EditControls.js.map +1 -1
  139. package/dist/editor/menubar/toolbar-sections/ManualBrowser.d.ts +0 -7
  140. package/dist/editor/menubar/toolbar-sections/ManualBrowser.js +23 -198
  141. package/dist/editor/menubar/toolbar-sections/ManualBrowser.js.map +1 -1
  142. package/dist/editor/menubar/toolbar-sections/ViewportControls.js +1 -1
  143. package/dist/editor/page-editor-chrome/BridgeInlineFormatOverlay.d.ts +6 -0
  144. package/dist/editor/page-editor-chrome/BridgeInlineFormatOverlay.js +123 -0
  145. package/dist/editor/page-editor-chrome/BridgeInlineFormatOverlay.js.map +1 -0
  146. package/dist/editor/page-editor-chrome/CommentHighlightings.d.ts +5 -2
  147. package/dist/editor/page-editor-chrome/CommentHighlightings.js +340 -215
  148. package/dist/editor/page-editor-chrome/CommentHighlightings.js.map +1 -1
  149. package/dist/editor/page-editor-chrome/FeedbackHighlightBadge.d.ts +5 -1
  150. package/dist/editor/page-editor-chrome/FeedbackHighlightBadge.js +11 -4
  151. package/dist/editor/page-editor-chrome/FeedbackHighlightBadge.js.map +1 -1
  152. package/dist/editor/page-editor-chrome/FieldActionIndicator.js +21 -13
  153. package/dist/editor/page-editor-chrome/FieldActionIndicator.js.map +1 -1
  154. package/dist/editor/page-editor-chrome/FieldEditedIndicator.js +23 -29
  155. package/dist/editor/page-editor-chrome/FieldEditedIndicator.js.map +1 -1
  156. package/dist/editor/page-editor-chrome/FrameMenu.js +110 -19
  157. package/dist/editor/page-editor-chrome/FrameMenu.js.map +1 -1
  158. package/dist/editor/page-editor-chrome/LockedFieldIndicator.d.ts +3 -2
  159. package/dist/editor/page-editor-chrome/LockedFieldIndicator.js +148 -45
  160. package/dist/editor/page-editor-chrome/LockedFieldIndicator.js.map +1 -1
  161. package/dist/editor/page-editor-chrome/PageEditorChrome.d.ts +2 -0
  162. package/dist/editor/page-editor-chrome/PageEditorChrome.js +25 -21
  163. package/dist/editor/page-editor-chrome/PageEditorChrome.js.map +1 -1
  164. package/dist/editor/page-editor-chrome/PictureEditorOverlay.js +163 -128
  165. package/dist/editor/page-editor-chrome/PictureEditorOverlay.js.map +1 -1
  166. package/dist/editor/page-editor-chrome/PlaceholderDropZone.d.ts +1 -1
  167. package/dist/editor/page-editor-chrome/PlaceholderDropZone.js +6 -3
  168. package/dist/editor/page-editor-chrome/PlaceholderDropZone.js.map +1 -1
  169. package/dist/editor/page-editor-chrome/PlaceholderDropZones.d.ts +1 -2
  170. package/dist/editor/page-editor-chrome/PlaceholderDropZones.js +83 -146
  171. package/dist/editor/page-editor-chrome/PlaceholderDropZones.js.map +1 -1
  172. package/dist/editor/page-editor-chrome/SuggestionHighlightings.d.ts +5 -2
  173. package/dist/editor/page-editor-chrome/SuggestionHighlightings.js +144 -63
  174. package/dist/editor/page-editor-chrome/SuggestionHighlightings.js.map +1 -1
  175. package/dist/editor/page-editor-chrome/VersionDiffHighlightings.d.ts +1 -2
  176. package/dist/editor/page-editor-chrome/VersionDiffHighlightings.js +101 -30
  177. package/dist/editor/page-editor-chrome/VersionDiffHighlightings.js.map +1 -1
  178. package/dist/editor/page-editor-chrome/overlay/IframeOverlayProvider.d.ts +10 -1
  179. package/dist/editor/page-editor-chrome/overlay/IframeOverlayProvider.js +105 -122
  180. package/dist/editor/page-editor-chrome/overlay/IframeOverlayProvider.js.map +1 -1
  181. package/dist/editor/page-editor-chrome/overlay/geometry.d.ts +11 -4
  182. package/dist/editor/page-editor-chrome/overlay/geometry.js +139 -36
  183. package/dist/editor/page-editor-chrome/overlay/geometry.js.map +1 -1
  184. package/dist/editor/page-editor-chrome/useBridgeInlineEditing.d.ts +26 -0
  185. package/dist/editor/page-editor-chrome/useBridgeInlineEditing.js +222 -0
  186. package/dist/editor/page-editor-chrome/useBridgeInlineEditing.js.map +1 -0
  187. package/dist/editor/page-viewer/EditorForm.js +17 -1
  188. package/dist/editor/page-viewer/EditorForm.js.map +1 -1
  189. package/dist/editor/page-viewer/MiniMap.d.ts +2 -2
  190. package/dist/editor/page-viewer/MiniMap.js +176 -364
  191. package/dist/editor/page-viewer/MiniMap.js.map +1 -1
  192. package/dist/editor/page-viewer/PageViewer.js +40 -13
  193. package/dist/editor/page-viewer/PageViewer.js.map +1 -1
  194. package/dist/editor/page-viewer/PageViewerFrame.d.ts +0 -5
  195. package/dist/editor/page-viewer/PageViewerFrame.js +1525 -1507
  196. package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
  197. package/dist/editor/page-viewer/bridgeFieldPatch.d.ts +20 -0
  198. package/dist/editor/page-viewer/bridgeFieldPatch.js +33 -0
  199. package/dist/editor/page-viewer/bridgeFieldPatch.js.map +1 -0
  200. package/dist/editor/page-viewer/pageViewContext.d.ts +32 -0
  201. package/dist/editor/page-viewer/pageViewContext.js +37 -6
  202. package/dist/editor/page-viewer/pageViewContext.js.map +1 -1
  203. package/dist/editor/reviews/Comment.d.ts +2 -1
  204. package/dist/editor/reviews/Comment.js +9 -4
  205. package/dist/editor/reviews/Comment.js.map +1 -1
  206. package/dist/editor/reviews/CommentEditor.js +1 -1
  207. package/dist/editor/reviews/CommentEditor.js.map +1 -1
  208. package/dist/editor/reviews/CommentPopover.js +68 -9
  209. package/dist/editor/reviews/CommentPopover.js.map +1 -1
  210. package/dist/editor/reviews/CommentView.js +24 -4
  211. package/dist/editor/reviews/CommentView.js.map +1 -1
  212. package/dist/editor/reviews/Comments.d.ts +0 -2
  213. package/dist/editor/reviews/Comments.js +29 -30
  214. package/dist/editor/reviews/Comments.js.map +1 -1
  215. package/dist/editor/reviews/FeedbackCard.d.ts +4 -2
  216. package/dist/editor/reviews/FeedbackCard.js +5 -5
  217. package/dist/editor/reviews/FeedbackCard.js.map +1 -1
  218. package/dist/editor/reviews/SuggestedEdit.js +4 -6
  219. package/dist/editor/reviews/SuggestedEdit.js.map +1 -1
  220. package/dist/editor/reviews/SuggestionDisplayPopover.js +3 -2
  221. package/dist/editor/reviews/SuggestionDisplayPopover.js.map +1 -1
  222. package/dist/editor/reviews/commentTransientSelection.d.ts +23 -0
  223. package/dist/editor/reviews/commentTransientSelection.js +7 -0
  224. package/dist/editor/reviews/commentTransientSelection.js.map +1 -0
  225. package/dist/editor/reviews/feedbackOrdering.d.ts +5 -0
  226. package/dist/editor/reviews/feedbackOrdering.js +27 -0
  227. package/dist/editor/reviews/feedbackOrdering.js.map +1 -0
  228. package/dist/editor/reviews/feedbackSelection.js +32 -4
  229. package/dist/editor/reviews/feedbackSelection.js.map +1 -1
  230. package/dist/editor/reviews/suggestedEditState.d.ts +12 -0
  231. package/dist/editor/reviews/suggestedEditState.js +90 -0
  232. package/dist/editor/reviews/suggestedEditState.js.map +1 -0
  233. package/dist/editor/reviews/suggestionDisplayValue.d.ts +43 -0
  234. package/dist/editor/reviews/suggestionDisplayValue.js +93 -0
  235. package/dist/editor/reviews/suggestionDisplayValue.js.map +1 -0
  236. package/dist/editor/services/agentService.d.ts +14 -0
  237. package/dist/editor/services/agentService.js +11 -1
  238. package/dist/editor/services/agentService.js.map +1 -1
  239. package/dist/editor/services/reviewsService.d.ts +2 -2
  240. package/dist/editor/services/reviewsService.js.map +1 -1
  241. package/dist/editor/settings/SettingsView.js +2 -2
  242. package/dist/editor/settings/SettingsView.js.map +1 -1
  243. package/dist/editor/settings/panels/ProjectTemplatesPanel.js +1 -1
  244. package/dist/editor/settings/panels/ProjectTemplatesPanel.js.map +1 -1
  245. package/dist/editor/settings/panels/ProvidersPanel.js +2 -3
  246. package/dist/editor/settings/panels/ProvidersPanel.js.map +1 -1
  247. package/dist/editor/sidebar/BridgeDiagnostics.d.ts +1 -0
  248. package/dist/editor/sidebar/BridgeDiagnostics.js +41 -0
  249. package/dist/editor/sidebar/BridgeDiagnostics.js.map +1 -0
  250. package/dist/editor/sidebar/MorePanelsButton.js +1 -1
  251. package/dist/editor/sidebar/MorePanelsButton.js.map +1 -1
  252. package/dist/editor/sidebar/Workbox.js +1 -1
  253. package/dist/editor/sidebar/Workbox.js.map +1 -1
  254. package/dist/editor/ui/IconSelectorDialog.js +1 -1
  255. package/dist/editor/ui/IconSelectorDialog.js.map +1 -1
  256. package/dist/editor/ui/SimpleIconButton.d.ts +2 -2
  257. package/dist/editor/ui/SimpleIconButton.js +1 -1
  258. package/dist/editor/ui/SimpleIconButton.js.map +1 -1
  259. package/dist/editor/utils.d.ts +1 -17
  260. package/dist/editor/utils.js +0 -143
  261. package/dist/editor/utils.js.map +1 -1
  262. package/dist/editor/version-diff/versionDiffTargets.d.ts +3 -8
  263. package/dist/editor/version-diff/versionDiffTargets.js +37 -94
  264. package/dist/editor/version-diff/versionDiffTargets.js.map +1 -1
  265. package/dist/revision.d.ts +2 -2
  266. package/dist/revision.js +2 -2
  267. package/dist/splash-screen/DialogWrappers.js +2 -2
  268. package/dist/splash-screen/DialogWrappers.js.map +1 -1
  269. package/dist/splash-screen/ModernSplashScreen.js +11 -3
  270. package/dist/splash-screen/ModernSplashScreen.js.map +1 -1
  271. package/dist/splash-screen/NewPage.js +7 -5
  272. package/dist/splash-screen/NewPage.js.map +1 -1
  273. package/dist/splash-screen/OpenPage.js +5 -3
  274. package/dist/splash-screen/OpenPage.js.map +1 -1
  275. package/dist/splash-screen/RecentPages.js +3 -3
  276. package/dist/splash-screen/RecentPages.js.map +1 -1
  277. package/package.json +2 -1
  278. package/styles.css +49 -0
  279. package/dist/editor/page-editor-chrome/InlineEditor.d.ts +0 -7
  280. package/dist/editor/page-editor-chrome/InlineEditor.js +0 -1719
  281. package/dist/editor/page-editor-chrome/InlineEditor.js.map +0 -1
  282. package/dist/editor/page-editor-chrome/overlay/iframeAccess.d.ts +0 -2
  283. package/dist/editor/page-editor-chrome/overlay/iframeAccess.js +0 -21
  284. package/dist/editor/page-editor-chrome/overlay/iframeAccess.js.map +0 -1
  285. package/dist/editor/page-editor-chrome/useInlineAICompletion.d.ts +0 -7
  286. package/dist/editor/page-editor-chrome/useInlineAICompletion.js +0 -758
  287. package/dist/editor/page-editor-chrome/useInlineAICompletion.js.map +0 -1
  288. package/dist/editor/page-viewer/pageModelSkeletonBuilder.d.ts +0 -3
  289. package/dist/editor/page-viewer/pageModelSkeletonBuilder.js +0 -796
  290. package/dist/editor/page-viewer/pageModelSkeletonBuilder.js.map +0 -1
@@ -46,6 +46,7 @@ import { QuickItemSwitcher } from "../QuickItemSwitcher";
46
46
  import { useEditorSlotContext, } from "../views/editorSlotContext";
47
47
  import { getComments, getAvailableCommentTags, } from "../services/reviewsService";
48
48
  import { useReviews } from "../reviews/useReviews";
49
+ import { COMMENT_TRANSIENT_ELEMENT_KEY, COMMENT_TRANSIENT_SELECTION_RECT, } from "../reviews/commentTransientSelection";
49
50
  import uuid from "react-uuid";
50
51
  import { flushSync } from "react-dom";
51
52
  import { getSuggestedEdits } from "../services/suggestedEditsService";
@@ -67,6 +68,24 @@ import { FeatureGate, LicenseFeatures, LicenseProvider, LicenseOverlay, } from "
67
68
  // nothing open" (param present with this value) so reload can honor the user's intent.
68
69
  const SIDEBAR_NONE_SENTINEL = "none";
69
70
  const sidebarUrlValue = (ids) => ids.length ? ids.join(",") : SIDEBAR_NONE_SENTINEL;
71
+ // moved to hooks/useQuota
72
+ function isUsableTextSelectionRange(range) {
73
+ return !!(range &&
74
+ range.text?.trim() &&
75
+ typeof range.startOffset === "number" &&
76
+ typeof range.endOffset === "number" &&
77
+ range.startOffset !== range.endOffset &&
78
+ range.fieldId &&
79
+ range.itemId);
80
+ }
81
+ function selectionRangeMatchesField(range, field) {
82
+ if (!range || !field)
83
+ return false;
84
+ return (cleanId(range.fieldId) === cleanId(field.fieldId) &&
85
+ cleanId(range.itemId) === cleanId(field.item.id) &&
86
+ (!range.language || range.language === field.item.language) &&
87
+ (typeof range.version !== "number" || range.version === field.item.version));
88
+ }
70
89
  function reconcileSlotSettingsState(previous, slots, defaults) {
71
90
  const next = {};
72
91
  let changed = false;
@@ -134,8 +153,10 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
134
153
  const [focusedField, setFocusedField] = useState();
135
154
  const focusedFieldRef = useRef(undefined);
136
155
  const [selectedRange, setSelectedRange] = useState();
156
+ const lastTextSelectionRangeRef = useRef(undefined);
137
157
  const [validating, setValidating] = useState(false);
138
158
  const [inserting, setInserting] = useState();
159
+ const insertingSequenceRef = useRef(0);
139
160
  const [showFullscreenHint, setShowFullscreenHint] = useState(false);
140
161
  // Fullscreen is a shell-level UI mode. Keep it in EditorShell state so the shell can rerender
141
162
  // immediately when toggled, while still syncing the active slot's PageViewContext.fullscreen.
@@ -153,6 +174,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
153
174
  const [activeFieldActions, setActiveFieldActions] = useState([]);
154
175
  const fieldEditorPopupRef = React.useRef(null);
155
176
  const [validationResult, setValidationResult] = useState();
177
+ const [bridgeDiagnostics, setBridgeDiagnostics] = useState(undefined);
156
178
  const [editHistory, setEditHistory] = useState([]);
157
179
  const [historyMode, setHistoryMode] = useState("global");
158
180
  const [showOnlyMyChanges, setShowOnlyMyChanges] = useState(true);
@@ -465,7 +487,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
465
487
  // The very first URL sync after initial load should replaceState (not pushState)
466
488
  // so the initial bare URL isn't left as a dead-end history entry.
467
489
  const isFirstUrlSyncRef = useRef(true);
468
- const [inlineEditingFieldElement, setInlineEditingFieldElement] = useState();
469
490
  const [lockedField, setLockedField] = useState();
470
491
  const [itemLanguages, setItemLanguages] = useState([]);
471
492
  const [itemVersions, setItemVersions] = useState([]);
@@ -555,9 +576,67 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
555
576
  const [isTourActive, setIsTourActive] = useState(tourRestoredFromUrl);
556
577
  // Track if tour was restored from URL to skip prepareAction on initial render
557
578
  const tourRestoredRef = useRef(tourRestoredFromUrl);
558
- const [mode, setMode] = useState("edit");
579
+ const [mode, setModeState] = useState("edit");
580
+ const modeRef = useRef("edit");
581
+ modeRef.current = mode;
582
+ const modeChangeParticipantsRef = useRef(new Set());
583
+ const loadSuggestedEditsRef = useRef(async () => { });
584
+ const [modeTransitionRevision, setModeTransitionRevision] = useState(0);
559
585
  const [previewDate, setPreviewDate] = useState();
560
586
  const [layoutMode, setLayoutMode] = useState("final");
587
+ const registerModeChangeParticipant = useCallback((participant) => {
588
+ modeChangeParticipantsRef.current.add(participant);
589
+ return () => {
590
+ modeChangeParticipantsRef.current.delete(participant);
591
+ };
592
+ }, []);
593
+ const changeMode = useCallback(async (nextMode, options) => {
594
+ const previousMode = modeRef.current;
595
+ if (nextMode === previousMode)
596
+ return;
597
+ const participants = Array.from(modeChangeParticipantsRef.current);
598
+ for (const participant of participants) {
599
+ await participant.beforeModeChange?.(nextMode, previousMode, options);
600
+ }
601
+ for (const participant of participants) {
602
+ participant.clearInlineDedupe?.(nextMode, previousMode, options);
603
+ }
604
+ flushSync(() => {
605
+ modeRef.current = nextMode;
606
+ setModeState(nextMode);
607
+ setModeTransitionRevision((revision) => revision + 1);
608
+ if (nextMode !== "preview") {
609
+ setPreviewDate(undefined);
610
+ }
611
+ if (nextMode === "suggestions") {
612
+ setShowSuggestedEdits(true);
613
+ setWorkspaceId("editor");
614
+ setOpenSidebars((prev) => {
615
+ if (prev.includes("feedback"))
616
+ return prev;
617
+ const next = [...prev, "feedback"];
618
+ openSidebarsRef.current = next;
619
+ return next;
620
+ });
621
+ }
622
+ else {
623
+ setShowSuggestedEdits(false);
624
+ }
625
+ });
626
+ if (nextMode === "suggestions") {
627
+ void loadSuggestedEditsRef.current();
628
+ }
629
+ }, []);
630
+ const setMode = useCallback((nextMode) => {
631
+ const resolvedMode = typeof nextMode === "function" ? nextMode(modeRef.current) : nextMode;
632
+ void changeMode(resolvedMode);
633
+ }, [changeMode]);
634
+ const workspaceShowsModeControls = !!configuration.editor.workspaces?.find((workspace) => workspace.id === workspaceId)?.toolbarFactory;
635
+ useEffect(() => {
636
+ if (workspaceShowsModeControls || mode !== "suggestions")
637
+ return;
638
+ void changeMode("edit", { reason: "mode-controls-hidden" });
639
+ }, [changeMode, mode, workspaceId, workspaceShowsModeControls]);
561
640
  useEffect(() => {
562
641
  if (mode !== "preview") {
563
642
  setPreviewDate(undefined);
@@ -663,19 +742,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
663
742
  setSelectedHelpSectionId(helpParam === "contents" || helpParam === "true" ? null : helpParam);
664
743
  }
665
744
  }, [searchParams, isInitialLoad]);
666
- useEffect(() => {
667
- if (mode === "suggestions") {
668
- // Ensure we're in the editor workspace and open the feedback sidebar
669
- setWorkspaceId("editor");
670
- // Open the feedback sidebar if not already open
671
- setOpenSidebars((prev) => {
672
- if (!prev.includes("comments")) {
673
- return [...prev, "comments"];
674
- }
675
- return prev;
676
- });
677
- }
678
- }, [mode]);
679
745
  useEffect(() => {
680
746
  if (focusedField &&
681
747
  selection.length > 0 &&
@@ -685,7 +751,19 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
685
751
  }, [selection]);
686
752
  useEffect(() => {
687
753
  focusedFieldRef.current = focusedField;
754
+ const lastTextSelection = lastTextSelectionRangeRef.current;
755
+ if (focusedField &&
756
+ lastTextSelection &&
757
+ (focusedField.fieldId !== lastTextSelection.fieldId ||
758
+ focusedField.item.id !== lastTextSelection.itemId)) {
759
+ lastTextSelectionRangeRef.current = undefined;
760
+ }
688
761
  }, [focusedField]);
762
+ useEffect(() => {
763
+ if (isUsableTextSelectionRange(selectedRange)) {
764
+ lastTextSelectionRangeRef.current = selectedRange;
765
+ }
766
+ }, [selectedRange]);
689
767
  // Track the current page item descriptor for itemsRepository
690
768
  const [currentPageItem, setCurrentPageItem] = useState();
691
769
  // Create itemsRepository with current page item (will be updated when page loads)
@@ -1216,7 +1294,8 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
1216
1294
  const toggleHelpTerminal = useCallback((options) => {
1217
1295
  const isCurrentlyOpen = showHelpTerminal;
1218
1296
  const requestedTab = options?.activeTab;
1219
- if (isCurrentlyOpen && (!requestedTab || requestedTab === helpTerminalActiveTab)) {
1297
+ if (isCurrentlyOpen &&
1298
+ (!requestedTab || requestedTab === helpTerminalActiveTab)) {
1220
1299
  // Close when toggling the currently active help view.
1221
1300
  handleSetShowHelpTerminal(false);
1222
1301
  }
@@ -1419,9 +1498,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
1419
1498
  }
1420
1499
  // Handle mode changes — always set to avoid stale-closure mismatch
1421
1500
  const urlMode = urlParams.get("mode");
1422
- if (urlMode) {
1423
- setMode(urlMode);
1424
- }
1501
+ setMode(urlMode ?? "edit");
1425
1502
  // Handle fullscreen changes (shell-level state)
1426
1503
  const isFullscreen = urlParams.get("fullscreen") === "true";
1427
1504
  if (configuration.forceFullscreen) {
@@ -1698,6 +1775,9 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
1698
1775
  const edits = result.data || [];
1699
1776
  setSuggestedEdits(edits);
1700
1777
  }, [item, searchParams]);
1778
+ useEffect(() => {
1779
+ loadSuggestedEditsRef.current = loadSuggestedEdits;
1780
+ }, [loadSuggestedEdits]);
1701
1781
  const loadFavorites = useCallback(async () => {
1702
1782
  try {
1703
1783
  const result = await getAllFavorites();
@@ -1710,6 +1790,9 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
1710
1790
  setFavorites([]);
1711
1791
  }
1712
1792
  }, []);
1793
+ const refreshFavorites = useCallback(async (opts) => {
1794
+ await loadFavorites();
1795
+ }, [loadFavorites]);
1713
1796
  const page = activePageViewContext.page;
1714
1797
  const currentHistoryScope = useMemo(() => {
1715
1798
  const currentItem = item?.descriptor;
@@ -2106,6 +2189,9 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
2106
2189
  globalThis.editorRefreshTimer = undefined;
2107
2190
  };
2108
2191
  if (mode === "immediate") {
2192
+ if (refreshTimer) {
2193
+ clearTimeout(refreshTimer);
2194
+ }
2109
2195
  doRefresh();
2110
2196
  return;
2111
2197
  }
@@ -2299,7 +2385,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
2299
2385
  else {
2300
2386
  current.set("compare", "true");
2301
2387
  }
2302
- current.set("mode", mode);
2388
+ current.set("mode", workspaceShowsModeControls ? mode : "edit");
2303
2389
  // Handle fullscreen parameter
2304
2390
  if (fullscreen) {
2305
2391
  current.set("fullscreen", "true");
@@ -3004,9 +3090,35 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
3004
3090
  };
3005
3091
  }, [promptSessionReconnect]);
3006
3092
  const sendSocketMessage = useCallback((message) => {
3093
+ if (message.type === "caret-position" &&
3094
+ message.payload?.source === "form-field") {
3095
+ const payload = message.payload;
3096
+ setRemoteCarets((current) => {
3097
+ if (payload.offset == null) {
3098
+ if (!current[sessionId])
3099
+ return current;
3100
+ const next = { ...current };
3101
+ delete next[sessionId];
3102
+ return next;
3103
+ }
3104
+ if (!payload.fieldId || !payload.item) {
3105
+ return current;
3106
+ }
3107
+ return {
3108
+ ...current,
3109
+ [sessionId]: {
3110
+ sessionId,
3111
+ fieldId: payload.fieldId,
3112
+ item: payload.item,
3113
+ offset: payload.offset,
3114
+ value: payload.value,
3115
+ },
3116
+ };
3117
+ });
3118
+ }
3007
3119
  // Routes over whichever transport is active (WebSocket preferred, SSE fallback).
3008
3120
  getEditorRealtime().send(message);
3009
- }, []);
3121
+ }, [sessionId]);
3010
3122
  // URL update helper - defined early so it can be used by workspace/sidebar functions
3011
3123
  const updateUrl = useCallback((params) => {
3012
3124
  // Use the actual browser pathname (including any basePath like /parhelia)
@@ -3484,34 +3596,51 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
3484
3596
  operationsContext.context.markOperationComplete;
3485
3597
  }, [operationsContext.context.markOperationComplete]);
3486
3598
  // Replace selected text with new content (for inline AI editing)
3487
- const replaceSelectedText = useCallback(async (newText) => {
3488
- if (!focusedField)
3489
- return;
3599
+ const replaceSelectedText = useCallback(async (newText, selectionOverride) => {
3600
+ const rangeToReplace = selectionOverride ?? selectedRange ?? lastTextSelectionRangeRef.current;
3490
3601
  try {
3491
3602
  // If we have selected text and a replaceText callback, use it
3492
- if (selectedRange?.text && selectedRange.replaceText) {
3493
- selectedRange.replaceText(newText);
3603
+ if (rangeToReplace?.text && rangeToReplace.replaceText) {
3604
+ rangeToReplace.replaceText(newText);
3494
3605
  setSelectedRange(undefined);
3606
+ lastTextSelectionRangeRef.current = undefined;
3495
3607
  return;
3496
3608
  }
3497
3609
  // If no selection but we have a replaceText callback, try to use it for insertion
3498
3610
  // (some editors might support insertion via the same callback)
3499
- if (!selectedRange?.text && selectedRange?.replaceText) {
3500
- selectedRange.replaceText(newText);
3611
+ if (!rangeToReplace?.text && rangeToReplace?.replaceText) {
3612
+ rangeToReplace.replaceText(newText);
3501
3613
  setSelectedRange(undefined);
3614
+ lastTextSelectionRangeRef.current = undefined;
3502
3615
  return;
3503
3616
  }
3617
+ const fieldToReplace = focusedField ??
3618
+ (rangeToReplace?.fieldId &&
3619
+ rangeToReplace.itemId &&
3620
+ rangeToReplace.language &&
3621
+ typeof rangeToReplace.version === "number"
3622
+ ? {
3623
+ fieldId: rangeToReplace.fieldId,
3624
+ item: {
3625
+ id: rangeToReplace.itemId,
3626
+ language: rangeToReplace.language,
3627
+ version: rangeToReplace.version,
3628
+ },
3629
+ }
3630
+ : undefined);
3631
+ if (!fieldToReplace)
3632
+ return;
3504
3633
  // Fallback: indexOf-based replacement/insertion for plain text fields
3505
- const { fieldId, item } = focusedField;
3634
+ const { fieldId, item } = fieldToReplace;
3506
3635
  const modifiedField = getActiveSlotContext()?.fieldModificationStore.getField(fieldId, item.id, item.language, item.version);
3507
3636
  const currentValue = modifiedField
3508
3637
  ? modifiedField.value || ""
3509
- : (await itemsRepository.getField(focusedField))?.value ||
3510
- "";
3638
+ : (await itemsRepository.getField(fieldToReplace))
3639
+ ?.value || "";
3511
3640
  let newValue;
3512
- if (selectedRange?.text) {
3641
+ if (rangeToReplace?.text) {
3513
3642
  // Replace selected text
3514
- const { text: originalSelectedText } = selectedRange;
3643
+ const { text: originalSelectedText } = rangeToReplace;
3515
3644
  const actualPosition = currentValue.indexOf(originalSelectedText);
3516
3645
  if (actualPosition === -1) {
3517
3646
  console.error("Failed to find selected text in field value");
@@ -3524,7 +3653,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
3524
3653
  }
3525
3654
  else {
3526
3655
  // Insert at cursor position (use startOffset if available, otherwise append)
3527
- const insertPosition = selectedRange?.startOffset ?? currentValue.length;
3656
+ const insertPosition = rangeToReplace?.startOffset ?? currentValue.length;
3528
3657
  newValue =
3529
3658
  currentValue.slice(0, insertPosition) +
3530
3659
  newText +
@@ -3532,12 +3661,13 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
3532
3661
  }
3533
3662
  // Update the field
3534
3663
  await operations.editField({
3535
- field: focusedField,
3664
+ field: fieldToReplace,
3536
3665
  value: newValue,
3537
3666
  refresh: "immediate",
3538
3667
  });
3539
3668
  // Clear the selection after replacement/insertion
3540
3669
  setSelectedRange(undefined);
3670
+ lastTextSelectionRangeRef.current = undefined;
3541
3671
  }
3542
3672
  catch (error) {
3543
3673
  console.error("Failed to replace/insert text:", error);
@@ -4014,18 +4144,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
4014
4144
  };
4015
4145
  }
4016
4146
  }, [operations.onFieldBlur]);
4017
- useEffect(() => {
4018
- if (mode === "suggestions") {
4019
- setShowSuggestedEdits(true);
4020
- // Refresh from the server to recover from any missed
4021
- // `suggested-edit-updated` WebSocket events (e.g. created by an
4022
- // agent tool while another tab was focused).
4023
- loadSuggestedEdits();
4024
- }
4025
- else {
4026
- setShowSuggestedEdits(false);
4027
- }
4028
- }, [mode, loadSuggestedEdits]);
4029
4147
  const isReadOnly = !item ||
4030
4148
  !item.canWriteItem ||
4031
4149
  !item.canWriteLanguage ||
@@ -4044,15 +4162,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
4044
4162
  // Otherwise, only show workspaces that are in the settings
4045
4163
  return workspaceIdsFromSettings.includes(w.id) && !w.visible;
4046
4164
  });
4047
- // Handle initial mode setup from URL (only on initial load)
4048
- useEffect(() => {
4049
- if (!isInitialLoad)
4050
- return;
4051
- const queryMode = searchParams.get("mode");
4052
- if (queryMode) {
4053
- setMode(queryMode);
4054
- }
4055
- }, [searchParams, isInitialLoad]);
4056
4165
  // Add this new effect for initial fullscreen setup
4057
4166
  useEffect(() => {
4058
4167
  if (!isInitialLoad)
@@ -4180,16 +4289,11 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
4180
4289
  dragEnd: () => {
4181
4290
  setDragObject(undefined);
4182
4291
  },
4183
- droppedInPlaceholder: async (placeholderKey, index, spotPositionElement, spotPositionAnchor, insertOption) => {
4184
- if ((!dragObject && !insertOption) || !page)
4292
+ droppedInPlaceholder: async (placeholderKey, index, spotPositionElement, spotPositionAnchor, insertOption, spotPosition) => {
4293
+ const droppedDragObject = dragObject;
4294
+ if ((!droppedDragObject && !insertOption) || !page)
4185
4295
  return;
4186
4296
  setDragObject(undefined);
4187
- if (spotPositionElement && spotPositionAnchor) {
4188
- setInserting({
4189
- positionElement: spotPositionElement,
4190
- positionAnchor: spotPositionAnchor,
4191
- });
4192
- }
4193
4297
  const placeholderKeyComponents = placeholderKey.split("_");
4194
4298
  const parentId = placeholderKeyComponents.length === 1
4195
4299
  ? undefined
@@ -4199,39 +4303,31 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
4199
4303
  let op;
4200
4304
  if (!currentItemDescriptorRef.current)
4201
4305
  return;
4306
+ let insertionSequence;
4307
+ if ((spotPosition || spotPositionElement) && spotPositionAnchor) {
4308
+ insertionSequence = ++insertingSequenceRef.current;
4309
+ setInserting({
4310
+ position: spotPosition,
4311
+ positionElement: spotPositionElement,
4312
+ positionAnchor: spotPositionAnchor,
4313
+ });
4314
+ }
4315
+ let operationPromise;
4202
4316
  if (insertOption) {
4203
4317
  // Clear any selected component type for insertion once the component
4204
4318
  // has been dropped into a placeholder. This ensures that insert mode
4205
4319
  // can exit cleanly and the editor header updates from "Add Component"
4206
4320
  // to the actual component name after the operation completes.
4207
4321
  setSelectedForInsertion("");
4208
- operations
4209
- .addComponent(insertOption.typeId, placeholderKey, index, currentItemDescriptorRef.current)
4210
- .then((result) => {
4211
- setInserting(undefined);
4212
- })
4213
- .catch((err) => {
4214
- setInserting(undefined);
4215
- });
4216
- return;
4322
+ operationPromise = operations.addComponent(insertOption.typeId, placeholderKey, index, currentItemDescriptorRef.current);
4217
4323
  }
4218
- if (!dragObject)
4219
- return;
4220
- if (dragObject && dragObject.type == "template") {
4221
- operations
4222
- .addComponent(dragObject.typeId, placeholderKey, index, currentItemDescriptorRef.current)
4223
- .then((result) => {
4224
- setInserting(undefined);
4225
- })
4226
- .catch((err) => {
4227
- setInserting(undefined);
4228
- });
4229
- return;
4324
+ else if (droppedDragObject?.type == "template") {
4325
+ operationPromise = operations.addComponent(droppedDragObject.typeId, placeholderKey, index, currentItemDescriptorRef.current);
4230
4326
  }
4231
- if (dragObject.type == "component" ||
4232
- (dragObject.type == "items" && dragObject.items)) {
4327
+ else if (droppedDragObject?.type == "component" ||
4328
+ (droppedDragObject?.type == "items" && droppedDragObject.items)) {
4233
4329
  const parentComponent = parentId && page ? getComponentById(parentId, page) : null;
4234
- if (dragObject.type == "items" && dragObject.items) {
4330
+ if (droppedDragObject.type == "items" && droppedDragObject.items) {
4235
4331
  op = {
4236
4332
  type: "link-component",
4237
4333
  mainItem: page.item.descriptor,
@@ -4245,33 +4341,52 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
4245
4341
  placeholderIndex: index,
4246
4342
  date: new Date().toISOString(),
4247
4343
  id: uuid(),
4248
- linkedComponentItem: dragObject.items[0],
4344
+ linkedComponentItem: droppedDragObject.items[0],
4249
4345
  title: "Link component",
4250
4346
  };
4251
4347
  }
4252
4348
  else {
4253
- const componentIds = dragObject.components?.map((c) => c.id) ?? [];
4254
- if (componentIds.length === 0)
4255
- return;
4256
- op = {
4257
- type: "move-component",
4258
- mainItem: page.item.descriptor,
4259
- parent: parentId && {
4260
- id: parentId,
4261
- language: page.item.descriptor.language,
4262
- version: page.item.descriptor.version,
4263
- },
4264
- placeholderKey,
4265
- placeholderIndex: index,
4266
- componentIds,
4267
- date: new Date().toISOString(),
4268
- id: uuid(),
4269
- title: "Move component",
4270
- };
4349
+ const componentIds = droppedDragObject.components?.map((c) => c.id) ?? [];
4350
+ if (componentIds.length > 0) {
4351
+ op = {
4352
+ type: "move-component",
4353
+ mainItem: page.item.descriptor,
4354
+ parent: parentId && {
4355
+ id: parentId,
4356
+ language: page.item.descriptor.language,
4357
+ version: page.item.descriptor.version,
4358
+ },
4359
+ placeholderKey,
4360
+ placeholderIndex: index,
4361
+ componentIds,
4362
+ date: new Date().toISOString(),
4363
+ id: uuid(),
4364
+ title: "Move component",
4365
+ };
4366
+ }
4271
4367
  }
4272
4368
  }
4273
4369
  if (op)
4274
- operations.executeEditOperation(op);
4370
+ operationPromise = operations.executeEditOperation(op);
4371
+ if (!operationPromise) {
4372
+ if (insertionSequence !== undefined &&
4373
+ insertingSequenceRef.current === insertionSequence) {
4374
+ setInserting(undefined);
4375
+ }
4376
+ return;
4377
+ }
4378
+ try {
4379
+ await operationPromise;
4380
+ }
4381
+ catch (err) {
4382
+ console.error("Failed to drop component in placeholder", err);
4383
+ }
4384
+ finally {
4385
+ if (insertionSequence !== undefined &&
4386
+ insertingSequenceRef.current === insertionSequence) {
4387
+ setInserting(undefined);
4388
+ }
4389
+ }
4275
4390
  },
4276
4391
  page,
4277
4392
  triggerFieldAction: async (fieldDescriptor, actionButton, parameters, event) => {
@@ -4421,6 +4536,8 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
4421
4536
  inserting,
4422
4537
  validating,
4423
4538
  validationResult,
4539
+ bridgeDiagnostics,
4540
+ setBridgeDiagnostics,
4424
4541
  loadItem,
4425
4542
  editHistory: editHistory,
4426
4543
  historyMode,
@@ -4550,27 +4667,50 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
4550
4667
  setShowComments,
4551
4668
  showResolvedComments,
4552
4669
  setShowResolvedComments,
4553
- addComment: async () => {
4670
+ addComment: async (options) => {
4554
4671
  const descriptor = item?.descriptor;
4555
4672
  if (!descriptor)
4556
4673
  return;
4557
4674
  // Snapshot selection context up-front so switching views doesn't change what we comment on.
4675
+ const hintedFieldSnapshot = options?.field;
4558
4676
  const focusedFieldSnapshot = focusedFieldRef.current;
4559
- const selectionSnapshot = [...selection];
4560
- const selectedRangeSnapshot = selectedRange;
4561
- const itemId = focusedFieldSnapshot?.item.id ||
4562
- (selectionSnapshot.length > 0 ? selectionSnapshot[0] : undefined) ||
4677
+ const selectedRangeCandidate = isUsableTextSelectionRange(selectedRange)
4678
+ ? selectedRange
4679
+ : lastTextSelectionRangeRef.current;
4680
+ const selectedRangeSnapshot = !hintedFieldSnapshot ||
4681
+ selectionRangeMatchesField(selectedRangeCandidate, hintedFieldSnapshot)
4682
+ ? selectedRangeCandidate
4683
+ : undefined;
4684
+ const selectedRangeFieldSnapshot = isUsableTextSelectionRange(selectedRangeSnapshot)
4685
+ ? {
4686
+ fieldId: selectedRangeSnapshot.fieldId,
4687
+ item: {
4688
+ id: selectedRangeSnapshot.itemId,
4689
+ language: selectedRangeSnapshot.language || descriptor.language,
4690
+ version: typeof selectedRangeSnapshot.version === "number"
4691
+ ? selectedRangeSnapshot.version
4692
+ : descriptor.version,
4693
+ },
4694
+ }
4695
+ : undefined;
4696
+ const commentFieldSnapshot = selectedRangeFieldSnapshot ??
4697
+ hintedFieldSnapshot ??
4698
+ focusedFieldSnapshot;
4699
+ const itemId = commentFieldSnapshot?.item.id ||
4700
+ (selection.length > 0 ? selection[0] : undefined) ||
4563
4701
  descriptor.id;
4564
4702
  if (!itemId)
4565
4703
  return;
4566
4704
  // Ensure the feedback sidebar is open when adding a comment (e.g. command palette / toolbar button).
4567
4705
  openSidebar("feedback");
4568
- const language = descriptor.language;
4569
- const version = descriptor.version;
4706
+ const language = commentFieldSnapshot?.item.language || descriptor.language;
4707
+ const version = typeof commentFieldSnapshot?.item.version === "number"
4708
+ ? commentFieldSnapshot.item.version
4709
+ : descriptor.version;
4570
4710
  const getFieldName = async () => {
4571
- if (!focusedFieldSnapshot)
4711
+ if (!commentFieldSnapshot)
4572
4712
  return "";
4573
- const field = await itemsRepository.getField(focusedFieldSnapshot);
4713
+ const field = await itemsRepository.getField(commentFieldSnapshot);
4574
4714
  return field?.name;
4575
4715
  };
4576
4716
  const getItemName = async () => {
@@ -4586,24 +4726,40 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
4586
4726
  isNew: true,
4587
4727
  itemId,
4588
4728
  itemName: await getItemName(),
4589
- fieldId: focusedFieldSnapshot?.fieldId,
4729
+ fieldId: commentFieldSnapshot?.fieldId,
4590
4730
  fieldName: await getFieldName(),
4591
4731
  mainItemId: descriptor.id,
4592
4732
  language,
4593
4733
  version,
4594
4734
  position: 0,
4595
- rangeStart: selectedRangeSnapshot?.startOffset || 0,
4596
- rangeEnd: selectedRangeSnapshot?.endOffset || 0,
4735
+ rangeStart: isUsableTextSelectionRange(selectedRangeSnapshot)
4736
+ ? selectedRangeSnapshot.startOffset
4737
+ : 0,
4738
+ rangeEnd: isUsableTextSelectionRange(selectedRangeSnapshot)
4739
+ ? selectedRangeSnapshot.endOffset
4740
+ : 0,
4597
4741
  author: user?.name,
4598
4742
  authorDisplayName: user?.fullName,
4599
- date: new Date().toISOString(),
4743
+ created: new Date().toISOString(),
4600
4744
  };
4745
+ if (selectedRangeSnapshot?.clientRect) {
4746
+ newComment[COMMENT_TRANSIENT_SELECTION_RECT] =
4747
+ selectedRangeSnapshot.clientRect;
4748
+ }
4749
+ if (selectedRangeSnapshot?.elementKey) {
4750
+ newComment[COMMENT_TRANSIENT_ELEMENT_KEY] =
4751
+ selectedRangeSnapshot.elementKey;
4752
+ }
4601
4753
  setComments([newComment, ...comments]);
4602
4754
  setSelectedComment(newComment);
4603
4755
  setShowComments(true);
4756
+ lastTextSelectionRangeRef.current = undefined;
4604
4757
  },
4605
4758
  mode,
4759
+ changeMode,
4606
4760
  setMode,
4761
+ registerModeChangeParticipant,
4762
+ modeTransitionRevision,
4607
4763
  previewDate,
4608
4764
  setPreviewDate,
4609
4765
  layoutMode,
@@ -4671,6 +4827,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
4671
4827
  setCurrentWizardId,
4672
4828
  favorites,
4673
4829
  loadFavorites,
4830
+ refreshFavorites,
4674
4831
  isQuickSwitcherVisible: quickSwitcherVisible,
4675
4832
  // Context factory registry methods
4676
4833
  registerContextFactory: (name, factory) => {
@@ -4779,6 +4936,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
4779
4936
  isRefreshing,
4780
4937
  favorites,
4781
4938
  loadFavorites,
4939
+ refreshFavorites,
4782
4940
  currentWizardId,
4783
4941
  quickSwitcherVisible,
4784
4942
  quickSwitcherSelectedIndex,
@@ -4789,6 +4947,10 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
4789
4947
  factoriesRef,
4790
4948
  user,
4791
4949
  statusMessage,
4950
+ changeMode,
4951
+ setMode,
4952
+ registerModeChangeParticipant,
4953
+ modeTransitionRevision,
4792
4954
  previewDate,
4793
4955
  layoutMode,
4794
4956
  enableCompletions,
@@ -4832,6 +4994,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
4832
4994
  openDialog,
4833
4995
  validating,
4834
4996
  validationResult,
4997
+ bridgeDiagnostics,
4835
4998
  isRefreshing,
4836
4999
  executeCommand,
4837
5000
  showInfoToast,
@@ -4854,8 +5017,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
4854
5017
  setLockedField(undefined); // Clear client-side lock state
4855
5018
  await releaseFieldLocks(sessionId);
4856
5019
  },
4857
- inlineEditingFieldElement,
4858
- setInlineEditingFieldElement,
4859
5020
  };
4860
5021
  // Debug: Track editContext changes
4861
5022
  // const prevDependencies = useRef<any[]>([]);
@@ -4894,7 +5055,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
4894
5055
  // componentDesignerRendering,
4895
5056
  // insertMode,
4896
5057
  // currentOverlay,
4897
- // inlineEditingFieldElement,
4898
5058
  // lockedField,
4899
5059
  // selectedRange,
4900
5060
  // pageViewContext,
@@ -4982,7 +5142,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
4982
5142
  // 'componentDesignerRendering',
4983
5143
  // 'insertMode',
4984
5144
  // 'currentOverlay',
4985
- // 'inlineEditingFieldElement',
4986
5145
  // 'lockedField',
4987
5146
  // 'selectedRange',
4988
5147
  // 'pageViewContext',
@@ -5110,7 +5269,8 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
5110
5269
  : window.location.pathname;
5111
5270
  window.history.replaceState(getCurrentHistoryState(), "", newUrl);
5112
5271
  }, configuration: configuration, restoredFromUrl: tourRestoredRef.current })), _jsx(FeatureGate, { feature: LicenseFeatures.AI, children: _jsx(GuidanceOverlay, {}) }), _jsx(FeatureGate, { feature: LicenseFeatures.AI, children: _jsx(AgentDialogHandler, {}) })] }));
5113
- return (_jsx(LicenseProvider, { initialLicenseStatus: initialLicenseStatus, initialStatusLoaded: initialLicenseStatusLoaded, children: _jsx("div", { className: `editor h-full w-full`, children: _jsx(OperationsContextProvider, { value: operationsContext.context, children: _jsx(FieldsEditContextProvider, { value: fieldsEditContext, children: _jsx(EditContextProvider, { value: editContext, children: _jsxs(SplashScreenAgentProvider, { children: [_jsx(DevModeIndicator, {}), startupChecks.state === "loading" && _jsx(EditorLoadingOverlay, {}), editContext.isRefreshing && (_jsx("div", { className: "text-neutral-grey-50 pointer-events-none fixed right-0 bottom-0 flex h-24 w-24 items-center justify-center opacity-50 select-none", children: _jsx(Spinner, {}) })), (currentWorkspace.id === "agents" ||
5272
+ const showRefreshSpinner = editContext.isRefreshing && !activePageViewContext.iframeSupportsRefresh;
5273
+ return (_jsx(LicenseProvider, { initialLicenseStatus: initialLicenseStatus, initialStatusLoaded: initialLicenseStatusLoaded, children: _jsx("div", { className: `editor h-full w-full`, children: _jsx(OperationsContextProvider, { value: operationsContext.context, children: _jsx(FieldsEditContextProvider, { value: fieldsEditContext, children: _jsx(EditContextProvider, { value: editContext, children: _jsxs(SplashScreenAgentProvider, { children: [_jsx(DevModeIndicator, {}), startupChecks.state === "loading" && _jsx(EditorLoadingOverlay, {}), showRefreshSpinner && (_jsx("div", { className: "text-neutral-grey-50 pointer-events-none fixed right-0 bottom-0 flex h-24 w-24 items-center justify-center opacity-50 select-none", children: _jsx(Spinner, {}) })), (currentWorkspace.id === "agents" ||
5114
5274
  currentWorkspace.id === "taskboard" ||
5115
5275
  currentWorkspace.id === "translation-management") &&
5116
5276
  showAgentsWorkspaceEditor && (_jsx(AgentsSlotContextBridgeHost, { slots: editorSlots })), startupChecks.state !== "loading" && (children || editorUi), startupChecks.state !== "loading" && dialog, _jsx(Toaster, { position: "top-center" }), " ", _jsx(ConfirmationDialog, { ref: confirmationDialogRef }), _jsx(ConcurrentUserLimitDialog, { open: concurrentUserLimitError !== null, onOpenChange: (open) => {