@parhelia/core 0.1.12556 → 0.1.12565

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 (587) hide show
  1. package/dist/agents-view/AgentCard.d.ts +6 -4
  2. package/dist/agents-view/AgentCard.js +143 -24
  3. package/dist/agents-view/AgentCard.js.map +1 -1
  4. package/dist/agents-view/AgentsInbox.d.ts +1 -1
  5. package/dist/agents-view/AgentsInbox.js +7 -92
  6. package/dist/agents-view/AgentsInbox.js.map +1 -1
  7. package/dist/agents-view/AgentsTitlebar.js +3 -2
  8. package/dist/agents-view/AgentsTitlebar.js.map +1 -1
  9. package/dist/agents-view/AgentsView.d.ts +6 -7
  10. package/dist/agents-view/AgentsView.js +191 -99
  11. package/dist/agents-view/AgentsView.js.map +1 -1
  12. package/dist/agents-view/AgentsWorkspaceView.d.ts +2 -6
  13. package/dist/agents-view/AgentsWorkspaceView.js +266 -113
  14. package/dist/agents-view/AgentsWorkspaceView.js.map +1 -1
  15. package/dist/agents-view/ProfileAgentsGroup.d.ts +2 -1
  16. package/dist/agents-view/ProfileAgentsGroup.js +4 -3
  17. package/dist/agents-view/ProfileAgentsGroup.js.map +1 -1
  18. package/dist/components/ActionButton.d.ts +1 -1
  19. package/dist/components/ActionButton.js.map +1 -1
  20. package/dist/components/FilterInput.d.ts +1 -1
  21. package/dist/components/FilterInput.js +1 -1
  22. package/dist/components/FilterInput.js.map +1 -1
  23. package/dist/components/ui/LanguageSelector.js +2 -4
  24. package/dist/components/ui/LanguageSelector.js.map +1 -1
  25. package/dist/components/ui/PlaceholderInput.js +3 -3
  26. package/dist/components/ui/PlaceholderInput.js.map +1 -1
  27. package/dist/components/ui/PlaceholderInputTypes.js +1 -1
  28. package/dist/components/ui/PlaceholderInputTypes.js.map +1 -1
  29. package/dist/components/ui/alert-dialog.d.ts +1 -1
  30. package/dist/components/ui/alert-dialog.js +6 -10
  31. package/dist/components/ui/alert-dialog.js.map +1 -1
  32. package/dist/components/ui/button.d.ts +4 -4
  33. package/dist/components/ui/button.js +4 -1
  34. package/dist/components/ui/button.js.map +1 -1
  35. package/dist/components/ui/context-menu.d.ts +1 -1
  36. package/dist/components/ui/context-menu.js +12 -4
  37. package/dist/components/ui/context-menu.js.map +1 -1
  38. package/dist/components/ui/copy-button.d.ts +2 -1
  39. package/dist/components/ui/copy-button.js +2 -2
  40. package/dist/components/ui/copy-button.js.map +1 -1
  41. package/dist/components/ui/dialog.d.ts +1 -1
  42. package/dist/components/ui/dialog.js +21 -126
  43. package/dist/components/ui/dialog.js.map +1 -1
  44. package/dist/components/ui/input.d.ts +1 -1
  45. package/dist/components/ui/input.js +5 -3
  46. package/dist/components/ui/input.js.map +1 -1
  47. package/dist/components/ui/paste-button.d.ts +2 -1
  48. package/dist/components/ui/paste-button.js +2 -2
  49. package/dist/components/ui/paste-button.js.map +1 -1
  50. package/dist/components/ui/popover.js +1 -9
  51. package/dist/components/ui/popover.js.map +1 -1
  52. package/dist/components/ui/select.js +1 -1
  53. package/dist/components/ui/select.js.map +1 -1
  54. package/dist/components/ui/styled-dialog-title.js +1 -1
  55. package/dist/components/ui/styled-dialog-title.js.map +1 -1
  56. package/dist/components/ui/tabs.d.ts +1 -1
  57. package/dist/components/ui/tabs.js +4 -11
  58. package/dist/components/ui/tabs.js.map +1 -1
  59. package/dist/config/config.d.ts +4 -2
  60. package/dist/config/config.js +250 -70
  61. package/dist/config/config.js.map +1 -1
  62. package/dist/config/notificationRoutes.js +14 -0
  63. package/dist/config/notificationRoutes.js.map +1 -1
  64. package/dist/config/types/workspace.d.ts +6 -0
  65. package/dist/config/types.d.ts +63 -12
  66. package/dist/config/types.js.map +1 -1
  67. package/dist/editor/ConfirmationDialog.js +20 -4
  68. package/dist/editor/ConfirmationDialog.js.map +1 -1
  69. package/dist/editor/ContentTree.d.ts +2 -1
  70. package/dist/editor/ContentTree.js +93 -32
  71. package/dist/editor/ContentTree.js.map +1 -1
  72. package/dist/editor/Editor.js +87 -22
  73. package/dist/editor/Editor.js.map +1 -1
  74. package/dist/editor/FieldHistory.js +84 -36
  75. package/dist/editor/FieldHistory.js.map +1 -1
  76. package/dist/editor/FieldListField.js +21 -9
  77. package/dist/editor/FieldListField.js.map +1 -1
  78. package/dist/editor/FieldListFieldWithFallbacks.js +23 -2
  79. package/dist/editor/FieldListFieldWithFallbacks.js.map +1 -1
  80. package/dist/editor/GlobalMenuBar.js +29 -2
  81. package/dist/editor/GlobalMenuBar.js.map +1 -1
  82. package/dist/editor/ImageEditor.js +5 -2
  83. package/dist/editor/ImageEditor.js.map +1 -1
  84. package/dist/editor/ItemInfo.js +36 -1
  85. package/dist/editor/ItemInfo.js.map +1 -1
  86. package/dist/editor/LinkEditorDialog.js +3 -0
  87. package/dist/editor/LinkEditorDialog.js.map +1 -1
  88. package/dist/editor/MainLayout.d.ts +0 -2
  89. package/dist/editor/MainLayout.js +65 -8
  90. package/dist/editor/MainLayout.js.map +1 -1
  91. package/dist/editor/MigrationsView.js +29 -5
  92. package/dist/editor/MigrationsView.js.map +1 -1
  93. package/dist/editor/MobileLayout.js +37 -12
  94. package/dist/editor/MobileLayout.js.map +1 -1
  95. package/dist/editor/PictureCropper.js +54 -45
  96. package/dist/editor/PictureCropper.js.map +1 -1
  97. package/dist/editor/PictureEditor.js +17 -15
  98. package/dist/editor/PictureEditor.js.map +1 -1
  99. package/dist/editor/QuickItemSwitcher.js +21 -21
  100. package/dist/editor/QuickItemSwitcher.js.map +1 -1
  101. package/dist/editor/SetupWizard.js +52 -12
  102. package/dist/editor/SetupWizard.js.map +1 -1
  103. package/dist/editor/Titlebar.js +7 -2
  104. package/dist/editor/Titlebar.js.map +1 -1
  105. package/dist/editor/ai/AgentCostDisplay.d.ts +1 -0
  106. package/dist/editor/ai/AgentCostDisplay.js +1 -1
  107. package/dist/editor/ai/AgentCostDisplay.js.map +1 -1
  108. package/dist/editor/ai/AgentDocumentList.js +32 -14
  109. package/dist/editor/ai/AgentDocumentList.js.map +1 -1
  110. package/dist/editor/ai/AgentGreeting.js +3 -2
  111. package/dist/editor/ai/AgentGreeting.js.map +1 -1
  112. package/dist/editor/ai/AgentProfileSelector.js +2 -1
  113. package/dist/editor/ai/AgentProfileSelector.js.map +1 -1
  114. package/dist/editor/ai/AgentStatusBadge.d.ts +0 -5
  115. package/dist/editor/ai/AgentStatusBadge.js +67 -65
  116. package/dist/editor/ai/AgentStatusBadge.js.map +1 -1
  117. package/dist/editor/ai/AgentTerminal.d.ts +14 -2
  118. package/dist/editor/ai/AgentTerminal.js +2406 -496
  119. package/dist/editor/ai/AgentTerminal.js.map +1 -1
  120. package/dist/editor/ai/AgentTerminalStatusBar.d.ts +8 -3
  121. package/dist/editor/ai/AgentTerminalStatusBar.js +481 -56
  122. package/dist/editor/ai/AgentTerminalStatusBar.js.map +1 -1
  123. package/dist/editor/ai/Agents.js +161 -113
  124. package/dist/editor/ai/Agents.js.map +1 -1
  125. package/dist/editor/ai/AiResponseMessage.d.ts +10 -1
  126. package/dist/editor/ai/AiResponseMessage.js +267 -26
  127. package/dist/editor/ai/AiResponseMessage.js.map +1 -1
  128. package/dist/editor/ai/ContextInfoBar.d.ts +2 -3
  129. package/dist/editor/ai/ContextInfoBar.js +64 -7
  130. package/dist/editor/ai/ContextInfoBar.js.map +1 -1
  131. package/dist/editor/ai/GuidanceOverlay.js +17 -11
  132. package/dist/editor/ai/GuidanceOverlay.js.map +1 -1
  133. package/dist/editor/ai/InlineAiDialog.d.ts +1 -1
  134. package/dist/editor/ai/InlineAiDialog.js +514 -192
  135. package/dist/editor/ai/InlineAiDialog.js.map +1 -1
  136. package/dist/editor/ai/InlineAiTrigger.js +115 -12
  137. package/dist/editor/ai/InlineAiTrigger.js.map +1 -1
  138. package/dist/editor/ai/MediaImage.js +40 -8
  139. package/dist/editor/ai/MediaImage.js.map +1 -1
  140. package/dist/editor/ai/SpawnedAgentsPanel.js +10 -12
  141. package/dist/editor/ai/SpawnedAgentsPanel.js.map +1 -1
  142. package/dist/editor/ai/ToolCallDisplay.d.ts +22 -2
  143. package/dist/editor/ai/ToolCallDisplay.js +542 -150
  144. package/dist/editor/ai/ToolCallDisplay.js.map +1 -1
  145. package/dist/editor/ai/agentDiagnostics.d.ts +7 -0
  146. package/dist/editor/ai/agentDiagnostics.js.map +1 -1
  147. package/dist/editor/ai/dialogs/AgentDialogHandler.d.ts +1 -8
  148. package/dist/editor/ai/dialogs/AgentDialogHandler.js +379 -42
  149. package/dist/editor/ai/dialogs/AgentDialogHandler.js.map +1 -1
  150. package/dist/editor/ai/dialogs/QuestionnaireInline.d.ts +5 -1
  151. package/dist/editor/ai/dialogs/QuestionnaireInline.js +628 -60
  152. package/dist/editor/ai/dialogs/QuestionnaireInline.js.map +1 -1
  153. package/dist/editor/ai/dialogs/agentDialogTypes.d.ts +115 -0
  154. package/dist/editor/ai/dialogs/agentDialogTypes.js +2 -0
  155. package/dist/editor/ai/dialogs/agentDialogTypes.js.map +1 -1
  156. package/dist/editor/ai/types.d.ts +3 -1
  157. package/dist/editor/ai/useAgentStatus.d.ts +2 -1
  158. package/dist/editor/ai/useAgentStatus.js +90 -100
  159. package/dist/editor/ai/useAgentStatus.js.map +1 -1
  160. package/dist/editor/ai/useInlineAiPosition.js +45 -5
  161. package/dist/editor/ai/useInlineAiPosition.js.map +1 -1
  162. package/dist/editor/client/AboutDialog.js +4 -2
  163. package/dist/editor/client/AboutDialog.js.map +1 -1
  164. package/dist/editor/client/EditorShell.d.ts +4 -1
  165. package/dist/editor/client/EditorShell.js +770 -237
  166. package/dist/editor/client/EditorShell.js.map +1 -1
  167. package/dist/editor/client/editContext.d.ts +33 -19
  168. package/dist/editor/client/editContext.js.map +1 -1
  169. package/dist/editor/client/helpers.js +6 -0
  170. package/dist/editor/client/helpers.js.map +1 -1
  171. package/dist/editor/client/hooks/useEditorUrlSync.js +1 -2
  172. package/dist/editor/client/hooks/useEditorUrlSync.js.map +1 -1
  173. package/dist/editor/client/hooks/useEditorWebSocket.d.ts +10 -0
  174. package/dist/editor/client/hooks/useEditorWebSocket.js +209 -14
  175. package/dist/editor/client/hooks/useEditorWebSocket.js.map +1 -1
  176. package/dist/editor/client/hooks/useQuota.d.ts +8 -0
  177. package/dist/editor/client/hooks/useQuota.js.map +1 -1
  178. package/dist/editor/client/hooks/useSocketMessageHandler.js +73 -15
  179. package/dist/editor/client/hooks/useSocketMessageHandler.js.map +1 -1
  180. package/dist/editor/client/itemsRepository.js +10 -6
  181. package/dist/editor/client/itemsRepository.js.map +1 -1
  182. package/dist/editor/client/navigation.js +35 -3
  183. package/dist/editor/client/navigation.js.map +1 -1
  184. package/dist/editor/client/operations.d.ts +6 -3
  185. package/dist/editor/client/operations.js +208 -30
  186. package/dist/editor/client/operations.js.map +1 -1
  187. package/dist/editor/client/pageModelBuilder.js +4 -31
  188. package/dist/editor/client/pageModelBuilder.js.map +1 -1
  189. package/dist/editor/client/ui/DevModeIndicator.js +2 -2
  190. package/dist/editor/client/ui/DevModeIndicator.js.map +1 -1
  191. package/dist/editor/client/ui/EditorChrome.d.ts +0 -6
  192. package/dist/editor/client/ui/EditorChrome.js +55 -72
  193. package/dist/editor/client/ui/EditorChrome.js.map +1 -1
  194. package/dist/editor/client/ui/FullscreenControls.js +5 -3
  195. package/dist/editor/client/ui/FullscreenControls.js.map +1 -1
  196. package/dist/editor/commands/commands.d.ts +11 -1
  197. package/dist/editor/commands/commands.js +12 -1
  198. package/dist/editor/commands/commands.js.map +1 -1
  199. package/dist/editor/commands/componentCommands.js +109 -55
  200. package/dist/editor/commands/componentCommands.js.map +1 -1
  201. package/dist/editor/commands/customCommandConverter.d.ts +8 -1
  202. package/dist/editor/commands/customCommandConverter.js +35 -5
  203. package/dist/editor/commands/customCommandConverter.js.map +1 -1
  204. package/dist/editor/commands/handlers/agentHandler.js +2 -1
  205. package/dist/editor/commands/handlers/agentHandler.js.map +1 -1
  206. package/dist/editor/commands/itemCommands.d.ts +3 -0
  207. package/dist/editor/commands/itemCommands.js +93 -10
  208. package/dist/editor/commands/itemCommands.js.map +1 -1
  209. package/dist/editor/commands/undo.d.ts +9 -15
  210. package/dist/editor/commands/undo.js +24 -0
  211. package/dist/editor/commands/undo.js.map +1 -1
  212. package/dist/editor/context-menu/InsertMenu.js +83 -39
  213. package/dist/editor/context-menu/InsertMenu.js.map +1 -1
  214. package/dist/editor/field-types/MultiLineText.js +1 -1
  215. package/dist/editor/field-types/MultiLineText.js.map +1 -1
  216. package/dist/editor/field-types/RawEditor.js +1 -1
  217. package/dist/editor/field-types/RichTextEditor.js +13 -5
  218. package/dist/editor/field-types/RichTextEditor.js.map +1 -1
  219. package/dist/editor/field-types/RichTextEditorComponent.js +37 -3
  220. package/dist/editor/field-types/RichTextEditorComponent.js.map +1 -1
  221. package/dist/editor/field-types/SingleLineText.js +1 -1
  222. package/dist/editor/field-types/TreeListEditor.js +3 -2
  223. package/dist/editor/field-types/TreeListEditor.js.map +1 -1
  224. package/dist/editor/field-types/richtext/components/ReactSlate.css +23 -5
  225. package/dist/editor/field-types/richtext/components/ReactSlate.d.ts +2 -0
  226. package/dist/editor/field-types/richtext/components/ReactSlate.js +28 -4
  227. package/dist/editor/field-types/richtext/components/ReactSlate.js.map +1 -1
  228. package/dist/editor/field-types/richtext/components/ToolbarButton.js +4 -2
  229. package/dist/editor/field-types/richtext/components/ToolbarButton.js.map +1 -1
  230. package/dist/editor/field-types/richtext/contextMenuFactory.d.ts +13 -0
  231. package/dist/editor/field-types/richtext/contextMenuFactory.js +181 -24
  232. package/dist/editor/field-types/richtext/contextMenuFactory.js.map +1 -1
  233. package/dist/editor/field-types/richtext/types.d.ts +2 -0
  234. package/dist/editor/field-types/richtext/types.js.map +1 -1
  235. package/dist/editor/field-types/richtext/utils/plugins.js +4 -0
  236. package/dist/editor/field-types/richtext/utils/plugins.js.map +1 -1
  237. package/dist/editor/field-types/textContextMenuFactory.js +3 -2
  238. package/dist/editor/field-types/textContextMenuFactory.js.map +1 -1
  239. package/dist/editor/media-selector/AiImageSearchPrompt.js +4 -2
  240. package/dist/editor/media-selector/AiImageSearchPrompt.js.map +1 -1
  241. package/dist/editor/media-selector/MediaFolderBrowser.js +1 -1
  242. package/dist/editor/media-selector/MediaFolderBrowser.js.map +1 -1
  243. package/dist/editor/media-selector/MediaSelector.js +7 -1
  244. package/dist/editor/media-selector/MediaSelector.js.map +1 -1
  245. package/dist/editor/media-selector/TreeSelector.js +40 -35
  246. package/dist/editor/media-selector/TreeSelector.js.map +1 -1
  247. package/dist/editor/menubar/ActiveUsers.js +1 -1
  248. package/dist/editor/menubar/ActiveUsers.js.map +1 -1
  249. package/dist/editor/menubar/GenericToolbar.js +4 -2
  250. package/dist/editor/menubar/GenericToolbar.js.map +1 -1
  251. package/dist/editor/menubar/ItemLanguageVersion.js +2 -2
  252. package/dist/editor/menubar/ItemLanguageVersion.js.map +1 -1
  253. package/dist/editor/menubar/PageSelector.js +26 -147
  254. package/dist/editor/menubar/PageSelector.js.map +1 -1
  255. package/dist/editor/menubar/Separator.js +1 -1
  256. package/dist/editor/menubar/VersionSelector.js +2 -4
  257. package/dist/editor/menubar/VersionSelector.js.map +1 -1
  258. package/dist/editor/menubar/WorkflowButton.js +39 -12
  259. package/dist/editor/menubar/WorkflowButton.js.map +1 -1
  260. package/dist/editor/menubar/toolbar-sections/CustomCommandsToolbar.js +16 -38
  261. package/dist/editor/menubar/toolbar-sections/CustomCommandsToolbar.js.map +1 -1
  262. package/dist/editor/menubar/toolbar-sections/EditControls.js +3 -3
  263. package/dist/editor/menubar/toolbar-sections/EditControls.js.map +1 -1
  264. package/dist/editor/menubar/toolbar-sections/HelpButton.js +1 -0
  265. package/dist/editor/menubar/toolbar-sections/HelpButton.js.map +1 -1
  266. package/dist/editor/menubar/toolbar-sections/ManualBrowser.d.ts +6 -10
  267. package/dist/editor/menubar/toolbar-sections/ManualBrowser.js +597 -220
  268. package/dist/editor/menubar/toolbar-sections/ManualBrowser.js.map +1 -1
  269. package/dist/editor/menubar/toolbar-sections/UtilityControls.js +13 -2
  270. package/dist/editor/menubar/toolbar-sections/UtilityControls.js.map +1 -1
  271. package/dist/editor/page-editor-chrome/CommentHighlighting.js +42 -1
  272. package/dist/editor/page-editor-chrome/CommentHighlighting.js.map +1 -1
  273. package/dist/editor/page-editor-chrome/FrameMenu.js +1 -1
  274. package/dist/editor/page-editor-chrome/FrameMenu.js.map +1 -1
  275. package/dist/editor/page-editor-chrome/InlineEditor.js +97 -48
  276. package/dist/editor/page-editor-chrome/InlineEditor.js.map +1 -1
  277. package/dist/editor/page-editor-chrome/PlaceholderDropZone.js +38 -17
  278. package/dist/editor/page-editor-chrome/PlaceholderDropZone.js.map +1 -1
  279. package/dist/editor/page-editor-chrome/PlaceholderDropZones.js +17 -11
  280. package/dist/editor/page-editor-chrome/PlaceholderDropZones.js.map +1 -1
  281. package/dist/editor/page-editor-chrome/useInlineAICompletion.js +301 -301
  282. package/dist/editor/page-editor-chrome/useInlineAICompletion.js.map +1 -1
  283. package/dist/editor/page-viewer/DeviceToolbar.js +1 -1
  284. package/dist/editor/page-viewer/DeviceToolbar.js.map +1 -1
  285. package/dist/editor/page-viewer/EditorForm.js +69 -11
  286. package/dist/editor/page-viewer/EditorForm.js.map +1 -1
  287. package/dist/editor/page-viewer/MiniMap.d.ts +2 -4
  288. package/dist/editor/page-viewer/MiniMap.js +91 -28
  289. package/dist/editor/page-viewer/MiniMap.js.map +1 -1
  290. package/dist/editor/page-viewer/PageViewer.d.ts +3 -1
  291. package/dist/editor/page-viewer/PageViewer.js +92 -19
  292. package/dist/editor/page-viewer/PageViewer.js.map +1 -1
  293. package/dist/editor/page-viewer/PageViewerFrame.d.ts +2 -1
  294. package/dist/editor/page-viewer/PageViewerFrame.js +348 -115
  295. package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
  296. package/dist/editor/page-viewer/pageModelSkeletonBuilder.js +114 -49
  297. package/dist/editor/page-viewer/pageModelSkeletonBuilder.js.map +1 -1
  298. package/dist/editor/page-viewer/pageViewContext.d.ts +1 -0
  299. package/dist/editor/page-viewer/pageViewContext.js +51 -14
  300. package/dist/editor/page-viewer/pageViewContext.js.map +1 -1
  301. package/dist/editor/pageModel.d.ts +14 -1
  302. package/dist/editor/reviews/Comment.js +26 -12
  303. package/dist/editor/reviews/Comment.js.map +1 -1
  304. package/dist/editor/reviews/CommentDisplayPopover.js +7 -5
  305. package/dist/editor/reviews/CommentDisplayPopover.js.map +1 -1
  306. package/dist/editor/reviews/CommentView.js +19 -4
  307. package/dist/editor/reviews/CommentView.js.map +1 -1
  308. package/dist/editor/reviews/Comments.js +89 -72
  309. package/dist/editor/reviews/Comments.js.map +1 -1
  310. package/dist/editor/reviews/CreateReviewDialog.js +281 -177
  311. package/dist/editor/reviews/CreateReviewDialog.js.map +1 -1
  312. package/dist/editor/reviews/DecisionsMatrix.js +96 -25
  313. package/dist/editor/reviews/DecisionsMatrix.js.map +1 -1
  314. package/dist/editor/reviews/DiffView.js +7 -14
  315. package/dist/editor/reviews/DiffView.js.map +1 -1
  316. package/dist/editor/reviews/EditReviewSettingsDialog.js +6 -4
  317. package/dist/editor/reviews/EditReviewSettingsDialog.js.map +1 -1
  318. package/dist/editor/reviews/MultiReviewManager.js +25 -3
  319. package/dist/editor/reviews/MultiReviewManager.js.map +1 -1
  320. package/dist/editor/reviews/PagesPanel.js +31 -15
  321. package/dist/editor/reviews/PagesPanel.js.map +1 -1
  322. package/dist/editor/reviews/PreviewInfo.js +1 -4
  323. package/dist/editor/reviews/PreviewInfo.js.map +1 -1
  324. package/dist/editor/reviews/ReviewCard.js +13 -7
  325. package/dist/editor/reviews/ReviewCard.js.map +1 -1
  326. package/dist/editor/reviews/ReviewDetail.js +3 -2
  327. package/dist/editor/reviews/ReviewDetail.js.map +1 -1
  328. package/dist/editor/reviews/ReviewsList.js +7 -3
  329. package/dist/editor/reviews/ReviewsList.js.map +1 -1
  330. package/dist/editor/reviews/SuggestedEdit.js +34 -3
  331. package/dist/editor/reviews/SuggestedEdit.js.map +1 -1
  332. package/dist/editor/reviews/SuggestionDisplayPopover.js +31 -5
  333. package/dist/editor/reviews/SuggestionDisplayPopover.js.map +1 -1
  334. package/dist/editor/reviews/commentAi.js +25 -6
  335. package/dist/editor/reviews/commentAi.js.map +1 -1
  336. package/dist/editor/reviews/reviewCommands.js +4 -1
  337. package/dist/editor/reviews/reviewCommands.js.map +1 -1
  338. package/dist/editor/reviews/useMultiReview.js +2 -2
  339. package/dist/editor/reviews/useMultiReview.js.map +1 -1
  340. package/dist/editor/reviews/useReviews.d.ts +2 -2
  341. package/dist/editor/reviews/useReviews.js +12 -30
  342. package/dist/editor/reviews/useReviews.js.map +1 -1
  343. package/dist/editor/services/agentErrorMessage.d.ts +1 -0
  344. package/dist/editor/services/agentErrorMessage.js +91 -0
  345. package/dist/editor/services/agentErrorMessage.js.map +1 -0
  346. package/dist/editor/services/agentService.d.ts +229 -5
  347. package/dist/editor/services/agentService.js +292 -39
  348. package/dist/editor/services/agentService.js.map +1 -1
  349. package/dist/editor/services/agentStatus.d.ts +1 -0
  350. package/dist/editor/services/agentStatus.js +19 -0
  351. package/dist/editor/services/agentStatus.js.map +1 -1
  352. package/dist/editor/services/aiService.d.ts +57 -1
  353. package/dist/editor/services/aiService.js +79 -6
  354. package/dist/editor/services/aiService.js.map +1 -1
  355. package/dist/editor/services/contentService.d.ts +6 -3
  356. package/dist/editor/services/contentService.js +13 -12
  357. package/dist/editor/services/contentService.js.map +1 -1
  358. package/dist/editor/services/editService.d.ts +52 -1
  359. package/dist/editor/services/editService.js +94 -2
  360. package/dist/editor/services/editService.js.map +1 -1
  361. package/dist/editor/services/indexService.js +1 -1
  362. package/dist/editor/services/indexService.js.map +1 -1
  363. package/dist/editor/services/reviewsService.d.ts +3 -6
  364. package/dist/editor/services/reviewsService.js +2 -11
  365. package/dist/editor/services/reviewsService.js.map +1 -1
  366. package/dist/editor/services/serviceHelper.d.ts +2 -1
  367. package/dist/editor/services/serviceHelper.js +112 -20
  368. package/dist/editor/services/serviceHelper.js.map +1 -1
  369. package/dist/editor/services/systemService.d.ts +2 -1
  370. package/dist/editor/services/systemService.js +3 -0
  371. package/dist/editor/services/systemService.js.map +1 -1
  372. package/dist/editor/services-server/api.d.ts +1 -2
  373. package/dist/editor/services-server/api.js +11 -6
  374. package/dist/editor/services-server/api.js.map +1 -1
  375. package/dist/editor/settings/About.js +317 -3
  376. package/dist/editor/settings/About.js.map +1 -1
  377. package/dist/editor/settings/QuotaInfo.js +210 -4
  378. package/dist/editor/settings/QuotaInfo.js.map +1 -1
  379. package/dist/editor/settings/SettingsView.js +25 -23
  380. package/dist/editor/settings/SettingsView.js.map +1 -1
  381. package/dist/editor/settings/Status.js +7 -6
  382. package/dist/editor/settings/Status.js.map +1 -1
  383. package/dist/editor/settings/index/useIndexStatus.js +20 -22
  384. package/dist/editor/settings/index/useIndexStatus.js.map +1 -1
  385. package/dist/editor/settings/panels/AgentsPanel.d.ts +0 -4
  386. package/dist/editor/settings/panels/AgentsPanel.js +95 -121
  387. package/dist/editor/settings/panels/AgentsPanel.js.map +1 -1
  388. package/dist/editor/settings/panels/ModelsPanel.js +329 -108
  389. package/dist/editor/settings/panels/ModelsPanel.js.map +1 -1
  390. package/dist/editor/settings/panels/ProvidersPanel.d.ts +1 -1
  391. package/dist/editor/settings/panels/ProvidersPanel.js +86 -59
  392. package/dist/editor/settings/panels/ProvidersPanel.js.map +1 -1
  393. package/dist/editor/settings/panels/SearchConfigPanel.js +4 -4
  394. package/dist/editor/settings/panels/SearchConfigPanel.js.map +1 -1
  395. package/dist/editor/settings/panels/index.d.ts +3 -2
  396. package/dist/editor/settings/panels/index.js +3 -2
  397. package/dist/editor/settings/panels/index.js.map +1 -1
  398. package/dist/editor/settings/status/coreStatusChecks.js +124 -19
  399. package/dist/editor/settings/status/coreStatusChecks.js.map +1 -1
  400. package/dist/editor/settings/status/useStartupChecks.d.ts +3 -1
  401. package/dist/editor/settings/status/useStartupChecks.js +9 -5
  402. package/dist/editor/settings/status/useStartupChecks.js.map +1 -1
  403. package/dist/editor/setup-wizard/steps/CompleteStep.d.ts +2 -1
  404. package/dist/editor/setup-wizard/steps/CompleteStep.js +2 -1
  405. package/dist/editor/setup-wizard/steps/CompleteStep.js.map +1 -1
  406. package/dist/editor/sidebar/ComponentPalette.js +2 -1
  407. package/dist/editor/sidebar/ComponentPalette.js.map +1 -1
  408. package/dist/editor/sidebar/ComponentTree.d.ts +8 -1
  409. package/dist/editor/sidebar/ComponentTree.js +216 -69
  410. package/dist/editor/sidebar/ComponentTree.js.map +1 -1
  411. package/dist/editor/sidebar/EditHistory.js +22 -46
  412. package/dist/editor/sidebar/EditHistory.js.map +1 -1
  413. package/dist/editor/sidebar/Favorites.js +4 -8
  414. package/dist/editor/sidebar/Favorites.js.map +1 -1
  415. package/dist/editor/sidebar/MainContentTree.js +4 -3
  416. package/dist/editor/sidebar/MainContentTree.js.map +1 -1
  417. package/dist/editor/sidebar/OperationItem.js +21 -7
  418. package/dist/editor/sidebar/OperationItem.js.map +1 -1
  419. package/dist/editor/sidebar/SidebarPanel.d.ts +3 -1
  420. package/dist/editor/sidebar/SidebarPanel.js +44 -12
  421. package/dist/editor/sidebar/SidebarPanel.js.map +1 -1
  422. package/dist/editor/sidebar/SidebarStack.d.ts +2 -1
  423. package/dist/editor/sidebar/SidebarStack.js +4 -3
  424. package/dist/editor/sidebar/SidebarStack.js.map +1 -1
  425. package/dist/editor/sidebar/Validation.js +24 -12
  426. package/dist/editor/sidebar/Validation.js.map +1 -1
  427. package/dist/editor/sidebar/Workbox.js +53 -3
  428. package/dist/editor/sidebar/Workbox.js.map +1 -1
  429. package/dist/editor/sidebar/WorkspaceRail.d.ts +0 -1
  430. package/dist/editor/sidebar/WorkspaceRail.js +56 -167
  431. package/dist/editor/sidebar/WorkspaceRail.js.map +1 -1
  432. package/dist/editor/tree-indicators/GutterColumns.d.ts +3 -1
  433. package/dist/editor/tree-indicators/GutterColumns.js +26 -5
  434. package/dist/editor/tree-indicators/GutterColumns.js.map +1 -1
  435. package/dist/editor/tree-indicators/GutterContext.d.ts +4 -0
  436. package/dist/editor/tree-indicators/GutterContext.js +23 -0
  437. package/dist/editor/tree-indicators/GutterContext.js.map +1 -1
  438. package/dist/editor/tree-indicators/index.d.ts +0 -1
  439. package/dist/editor/tree-indicators/index.js +0 -1
  440. package/dist/editor/tree-indicators/index.js.map +1 -1
  441. package/dist/editor/tree-indicators/types.d.ts +12 -1
  442. package/dist/editor/ui/CopyMoveTargetSelectorDialog.js +1 -1
  443. package/dist/editor/ui/CopyMoveTargetSelectorDialog.js.map +1 -1
  444. package/dist/editor/ui/Icons.js +1 -1
  445. package/dist/editor/ui/Icons.js.map +1 -1
  446. package/dist/editor/ui/ItemNameDialogNew.d.ts +2 -0
  447. package/dist/editor/ui/ItemNameDialogNew.js +33 -17
  448. package/dist/editor/ui/ItemNameDialogNew.js.map +1 -1
  449. package/dist/editor/ui/ItemSearch.js +7 -11
  450. package/dist/editor/ui/ItemSearch.js.map +1 -1
  451. package/dist/editor/ui/SimpleIconButton.js +1 -1
  452. package/dist/editor/ui/SimpleIconButton.js.map +1 -1
  453. package/dist/editor/ui/SimpleTabs.d.ts +1 -0
  454. package/dist/editor/ui/SimpleTabs.js +45 -25
  455. package/dist/editor/ui/SimpleTabs.js.map +1 -1
  456. package/dist/editor/ui/Splitter.d.ts +1 -0
  457. package/dist/editor/ui/Splitter.js +102 -86
  458. package/dist/editor/ui/Splitter.js.map +1 -1
  459. package/dist/editor/ui/TemplateSelectorDialog.js +4 -4
  460. package/dist/editor/ui/TemplateSelectorDialog.js.map +1 -1
  461. package/dist/editor/ui/TreeListSelector.d.ts +6 -1
  462. package/dist/editor/ui/TreeListSelector.js +2 -2
  463. package/dist/editor/ui/TreeListSelector.js.map +1 -1
  464. package/dist/editor/utils/keyboardNavigation.d.ts +6 -20
  465. package/dist/editor/utils/keyboardNavigation.js +48 -140
  466. package/dist/editor/utils/keyboardNavigation.js.map +1 -1
  467. package/dist/editor/utils.js +19 -9
  468. package/dist/editor/utils.js.map +1 -1
  469. package/dist/editor/views/CompareView.d.ts +3 -1
  470. package/dist/editor/views/CompareView.js +7 -5
  471. package/dist/editor/views/CompareView.js.map +1 -1
  472. package/dist/editor/views/EditView.js +1 -1
  473. package/dist/editor/views/EditView.js.map +1 -1
  474. package/dist/editor/views/EditorSlot.js +27 -34
  475. package/dist/editor/views/EditorSlot.js.map +1 -1
  476. package/dist/editor/views/ItemEditor.js +7 -3
  477. package/dist/editor/views/ItemEditor.js.map +1 -1
  478. package/dist/editor/views/MediaFolderEditView.js +1 -1
  479. package/dist/editor/views/MediaFolderEditView.js.map +1 -1
  480. package/dist/editor/views/ParheliaView.js +5 -6
  481. package/dist/editor/views/ParheliaView.js.map +1 -1
  482. package/dist/editor/views/SingleEditView.d.ts +2 -1
  483. package/dist/editor/views/SingleEditView.js +10 -8
  484. package/dist/editor/views/SingleEditView.js.map +1 -1
  485. package/dist/editor/views/editorSlotContext.js +35 -6
  486. package/dist/editor/views/editorSlotContext.js.map +1 -1
  487. package/dist/index.d.ts +16 -2
  488. package/dist/index.js +11 -0
  489. package/dist/index.js.map +1 -1
  490. package/dist/revision.d.ts +2 -2
  491. package/dist/revision.js +2 -2
  492. package/dist/setup/services/setupWizardService.d.ts +40 -13
  493. package/dist/setup/services/setupWizardService.js +32 -17
  494. package/dist/setup/services/setupWizardService.js.map +1 -1
  495. package/dist/setup/wizard/steps/AddModelDialog.js +12 -3
  496. package/dist/setup/wizard/steps/AddModelDialog.js.map +1 -1
  497. package/dist/setup/wizard/steps/ImportModelDialog.js +39 -22
  498. package/dist/setup/wizard/steps/ImportModelDialog.js.map +1 -1
  499. package/dist/splash-screen/ModernSplashScreen.js +112 -32
  500. package/dist/splash-screen/ModernSplashScreen.js.map +1 -1
  501. package/dist/splash-screen/NewPage.js +33 -50
  502. package/dist/splash-screen/NewPage.js.map +1 -1
  503. package/dist/splash-screen/OpenPage.js +2 -6
  504. package/dist/splash-screen/OpenPage.js.map +1 -1
  505. package/dist/splash-screen/ParheliaAssistantChat.js +12 -29
  506. package/dist/splash-screen/ParheliaAssistantChat.js.map +1 -1
  507. package/dist/splash-screen/ParheliaLogo.js +87 -37
  508. package/dist/splash-screen/ParheliaLogo.js.map +1 -1
  509. package/dist/splash-screen/RecentPages.js +3 -3
  510. package/dist/splash-screen/RecentPages.js.map +1 -1
  511. package/dist/tour/Tour.d.ts +2 -1
  512. package/dist/tour/Tour.js +256 -75
  513. package/dist/tour/Tour.js.map +1 -1
  514. package/dist/tour/default-tour.js +222 -96
  515. package/dist/tour/default-tour.js.map +1 -1
  516. package/dist/types.d.ts +63 -29
  517. package/package.json +19 -15
  518. package/styles.css +39 -10
  519. package/dist/editor/ComponentInfo.d.ts +0 -4
  520. package/dist/editor/ComponentInfo.js +0 -41
  521. package/dist/editor/ComponentInfo.js.map +0 -1
  522. package/dist/editor/ai/HelpTerminal.d.ts +0 -5
  523. package/dist/editor/ai/HelpTerminal.js +0 -166
  524. package/dist/editor/ai/HelpTerminal.js.map +0 -1
  525. package/dist/editor/field-types/ReactQuill.d.ts +0 -125
  526. package/dist/editor/field-types/ReactQuill.js +0 -385
  527. package/dist/editor/field-types/ReactQuill.js.map +0 -1
  528. package/dist/editor/services-server/graphQL.d.ts +0 -29
  529. package/dist/editor/services-server/graphQL.js +0 -53
  530. package/dist/editor/services-server/graphQL.js.map +0 -1
  531. package/dist/editor/settings/AllAgentsPanel.d.ts +0 -5
  532. package/dist/editor/settings/AllAgentsPanel.js +0 -139
  533. package/dist/editor/settings/AllAgentsPanel.js.map +0 -1
  534. package/dist/editor/settings/LatestFeedback.d.ts +0 -1
  535. package/dist/editor/settings/LatestFeedback.js +0 -136
  536. package/dist/editor/settings/LatestFeedback.js.map +0 -1
  537. package/dist/editor/settings/Setup.d.ts +0 -1
  538. package/dist/editor/settings/Setup.js +0 -211
  539. package/dist/editor/settings/Setup.js.map +0 -1
  540. package/dist/editor/settings/panels/DatabasePanel.d.ts +0 -6
  541. package/dist/editor/settings/panels/DatabasePanel.js +0 -50
  542. package/dist/editor/settings/panels/DatabasePanel.js.map +0 -1
  543. package/dist/editor/settings/setup-steps/AiSetupStep/EmbeddingsModelSection.d.ts +0 -2
  544. package/dist/editor/settings/setup-steps/AiSetupStep/EmbeddingsModelSection.js +0 -195
  545. package/dist/editor/settings/setup-steps/AiSetupStep/EmbeddingsModelSection.js.map +0 -1
  546. package/dist/editor/settings/setup-steps/AiSetupStep/index.d.ts +0 -2
  547. package/dist/editor/settings/setup-steps/AiSetupStep/index.js +0 -21
  548. package/dist/editor/settings/setup-steps/AiSetupStep/index.js.map +0 -1
  549. package/dist/editor/settings/setup-steps/AiSetupStep/provider/ProviderSection.d.ts +0 -1
  550. package/dist/editor/settings/setup-steps/AiSetupStep/provider/ProviderSection.js +0 -233
  551. package/dist/editor/settings/setup-steps/AiSetupStep/provider/ProviderSection.js.map +0 -1
  552. package/dist/editor/settings/setup-steps/AiSetupStep/required-containers/RequiredContainersList.d.ts +0 -15
  553. package/dist/editor/settings/setup-steps/AiSetupStep/required-containers/RequiredContainersList.js +0 -14
  554. package/dist/editor/settings/setup-steps/AiSetupStep/required-containers/RequiredContainersList.js.map +0 -1
  555. package/dist/editor/settings/setup-steps/AiSetupStep/required-containers/RequiredContainersSection.d.ts +0 -1
  556. package/dist/editor/settings/setup-steps/AiSetupStep/required-containers/RequiredContainersSection.js +0 -94
  557. package/dist/editor/settings/setup-steps/AiSetupStep/required-containers/RequiredContainersSection.js.map +0 -1
  558. package/dist/editor/settings/setup-steps/AiSetupStep/types.d.ts +0 -1
  559. package/dist/editor/settings/setup-steps/AiSetupStep/types.js +0 -2
  560. package/dist/editor/settings/setup-steps/AiSetupStep/types.js.map +0 -1
  561. package/dist/editor/settings/setup-steps/AiSetupStep/utils.d.ts +0 -5
  562. package/dist/editor/settings/setup-steps/AiSetupStep/utils.js +0 -44
  563. package/dist/editor/settings/setup-steps/AiSetupStep/utils.js.map +0 -1
  564. package/dist/editor/settings/setup-steps/IndexSetupStep.d.ts +0 -2
  565. package/dist/editor/settings/setup-steps/IndexSetupStep.js +0 -36
  566. package/dist/editor/settings/setup-steps/IndexSetupStep.js.map +0 -1
  567. package/dist/editor/settings/setup-steps/SettingsSetupStep.d.ts +0 -2
  568. package/dist/editor/settings/setup-steps/SettingsSetupStep.js +0 -111
  569. package/dist/editor/settings/setup-steps/SettingsSetupStep.js.map +0 -1
  570. package/dist/editor/settings/setup-steps/SetupOverview.d.ts +0 -14
  571. package/dist/editor/settings/setup-steps/SetupOverview.js +0 -38
  572. package/dist/editor/settings/setup-steps/SetupOverview.js.map +0 -1
  573. package/dist/editor/sidebar/Debug.d.ts +0 -1
  574. package/dist/editor/sidebar/Debug.js +0 -70
  575. package/dist/editor/sidebar/Debug.js.map +0 -1
  576. package/dist/editor/sidebar/GraphQL.d.ts +0 -2
  577. package/dist/editor/sidebar/GraphQL.js +0 -234
  578. package/dist/editor/sidebar/GraphQL.js.map +0 -1
  579. package/dist/editor/sidebar/LeftToolbar.d.ts +0 -1
  580. package/dist/editor/sidebar/LeftToolbar.js +0 -12
  581. package/dist/editor/sidebar/LeftToolbar.js.map +0 -1
  582. package/dist/editor/sidebar/NavigationSidebar.d.ts +0 -4
  583. package/dist/editor/sidebar/NavigationSidebar.js +0 -254
  584. package/dist/editor/sidebar/NavigationSidebar.js.map +0 -1
  585. package/dist/editor/tree-indicators/GutterSelector.d.ts +0 -5
  586. package/dist/editor/tree-indicators/GutterSelector.js +0 -91
  587. package/dist/editor/tree-indicators/GutterSelector.js.map +0 -1
@@ -1,11 +1,27 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useState, useEffect, useCallback, useMemo, useRef, } from "react";
3
- import { Book, Loader2, Edit, ArrowLeft } from "lucide-react";
2
+ import React, { useState, useEffect, useCallback, useMemo, useRef, } from "react";
3
+ import { Book, BookOpen, Loader2, Edit, ArrowLeft, ArrowRight, ChevronDown, ChevronRight, LocateFixed, Rocket, FileEdit, X, } from "lucide-react";
4
4
  import { loadManualToc, loadManualSection, invalidateManualSectionCache, } from "../../services/aiService";
5
- import { Select } from "../../../components/ui/select";
5
+ import { executeSearch } from "../../services/searchService";
6
+ import { FilterInput } from "../../../components/FilterInput";
7
+ import { MarkdownDisplay, } from "../../../components/MarkdownDisplay";
6
8
  import { Tooltip, TooltipTrigger, TooltipContent, } from "../../../components/ui/tooltip";
7
9
  import { useEditContext } from "../../client/editContext";
8
10
  import { cn } from "../../../lib/utils";
11
+ import { sanitizeSvg } from "../../../lib/sanitize";
12
+ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from "../../../components/ui/dropdown-menu";
13
+ /** Render a sanitized SVG string at a specific pixel size. */
14
+ function SvgIcon({ svg, size, className, }) {
15
+ const sanitizedSvg = sanitizeSvg(svg).trim();
16
+ return (_jsx("span", { className: cn("inline-flex items-center justify-center [&>svg]:block [&>svg]:h-full [&>svg]:w-full", className), style: { width: size, height: size }, dangerouslySetInnerHTML: { __html: sanitizedSvg } }));
17
+ }
18
+ const HIGHLIGHT_DURATION_MS = 2000;
19
+ const manualMarkdownComponents = {
20
+ h1: ({ children }) => (_jsx("h1", { className: "mt-4 mb-0 text-xl font-bold text-gray-900", children: children })),
21
+ h2: ({ children }) => (_jsx("h2", { className: "mt-3 mb-0 text-lg font-semibold text-gray-800", children: children })),
22
+ h3: ({ children }) => (_jsx("h3", { className: "mt-2 mb-0 text-base font-semibold text-gray-700", children: children })),
23
+ h4: ({ children }) => (_jsx("h4", { className: "mt-2 mb-0 text-sm font-semibold text-gray-700", children: children })),
24
+ };
9
25
  // Parse the uiSelectors field
10
26
  // Formats:
11
27
  // - @selector-name: Description | Not found message
@@ -14,7 +30,10 @@ export function parseUiSelectors(uiSelectors) {
14
30
  const map = new Map();
15
31
  if (!uiSelectors)
16
32
  return map;
17
- const lines = uiSelectors.split("\n").filter((line) => line.trim());
33
+ const lines = uiSelectors
34
+ .split(/\r?\n/)
35
+ .map((line) => line.trim())
36
+ .filter(Boolean);
18
37
  for (const line of lines) {
19
38
  // Format: @selector-name: ...
20
39
  const match = line.match(/^@([\w\-]+):\s*(.+)$/);
@@ -23,10 +42,34 @@ export function parseUiSelectors(uiSelectors) {
23
42
  const rest = match[2];
24
43
  if (!name || !rest)
25
44
  continue;
26
- // Split by | for optional not-found message
27
- const pipeIndex = rest.indexOf("|");
28
- const description = pipeIndex >= 0 ? rest.substring(0, pipeIndex).trim() : rest.trim();
29
- const notFoundMessage = pipeIndex >= 0 ? rest.substring(pipeIndex + 1).trim() : undefined;
45
+ const segments = rest
46
+ .split("|")
47
+ .map((segment) => segment.trim())
48
+ .filter(Boolean);
49
+ const description = segments.shift() ?? "";
50
+ let notFoundMessage;
51
+ let beforeAction;
52
+ let afterAction;
53
+ let availabilitySelector;
54
+ for (const segment of segments) {
55
+ if (segment.startsWith("beforeAction=")) {
56
+ beforeAction = segment.substring("beforeAction=".length).trim();
57
+ continue;
58
+ }
59
+ if (segment.startsWith("afterAction=")) {
60
+ afterAction = segment.substring("afterAction=".length).trim();
61
+ continue;
62
+ }
63
+ if (segment.startsWith("availabilitySelector=")) {
64
+ availabilitySelector = segment
65
+ .substring("availabilitySelector=".length)
66
+ .trim();
67
+ continue;
68
+ }
69
+ if (!notFoundMessage) {
70
+ notFoundMessage = segment;
71
+ }
72
+ }
30
73
  // Check if this is a sidebar-only selector (e.g., @reviews-sidebar)
31
74
  // These end with -sidebar
32
75
  const isSidebarOnly = name.endsWith("-sidebar");
@@ -37,10 +80,13 @@ export function parseUiSelectors(uiSelectors) {
37
80
  const parsed = {
38
81
  name,
39
82
  selector: isSidebarOnly ? "" : `@${name}`, // Empty selector for sidebar-only
83
+ availabilitySelector,
40
84
  description,
41
85
  notFoundMessage: notFoundMessage || undefined,
42
86
  location: isSidebarOnly ? sidebarId : undefined, // Use actual sidebar ID (without -sidebar suffix) for sidebar-only
43
87
  isSidebarOnly,
88
+ beforeAction,
89
+ afterAction,
44
90
  };
45
91
  // Primary key remains the selector name
46
92
  map.set(name, parsed);
@@ -94,59 +140,122 @@ export function expandSelector(selectorShorthand) {
94
140
  // Default: data-testid selector: @name → [data-testid="name"]
95
141
  return `[data-testid="${selector}"]`;
96
142
  }
97
- // Highlight an element temporarily
98
- export function highlightElement(selector, duration = 2000) {
143
+ function getElementsForSelector(selector) {
99
144
  const cssSelector = expandSelector(selector);
100
- // Handle iframe selectors
101
145
  if (cssSelector.startsWith("iframe:")) {
102
146
  const iframeSelector = cssSelector.substring(7);
103
147
  const iframe = document.querySelector("iframe.page-iframe");
104
- if (iframe?.contentDocument) {
105
- const elements = iframe.contentDocument.querySelectorAll(iframeSelector);
106
- if (elements.length > 0) {
107
- const iframeRect = iframe.getBoundingClientRect();
108
- elements.forEach((element) => {
109
- const elementRect = element.getBoundingClientRect();
110
- showHighlightOverlay(elementRect.left + iframeRect.left, elementRect.top + iframeRect.top, elementRect.width, elementRect.height, duration);
111
- });
112
- // Scroll the first element into view
113
- elements[0]?.scrollIntoView({ behavior: "smooth", block: "center" });
148
+ if (!iframe?.contentDocument) {
149
+ return [];
150
+ }
151
+ return Array.from(iframe.contentDocument.querySelectorAll(iframeSelector));
152
+ }
153
+ return Array.from(document.querySelectorAll(cssSelector));
154
+ }
155
+ function shouldSkipHighlightScroll(element) {
156
+ const rect = element.getBoundingClientRect();
157
+ const computedStyle = window.getComputedStyle(element);
158
+ const viewportPadding = 24;
159
+ const isFixedLike = computedStyle.position === "fixed" || computedStyle.position === "sticky";
160
+ const isFullyVisible = rect.top >= viewportPadding &&
161
+ rect.bottom <= window.innerHeight - viewportPadding &&
162
+ rect.left >= 0 &&
163
+ rect.right <= window.innerWidth;
164
+ const isLargeTarget = rect.height >= window.innerHeight * 0.6;
165
+ return isFixedLike || isFullyVisible || isLargeTarget;
166
+ }
167
+ function waitForNextFrame() {
168
+ return new Promise((resolve) => {
169
+ window.requestAnimationFrame(() => resolve());
170
+ });
171
+ }
172
+ async function waitForScrollToFinish(element) {
173
+ let stableFrames = 0;
174
+ let previousRect = element.getBoundingClientRect();
175
+ for (let frame = 0; frame < 30; frame++) {
176
+ await waitForNextFrame();
177
+ const currentRect = element.getBoundingClientRect();
178
+ const moved = Math.abs(currentRect.top - previousRect.top) > 0.5 ||
179
+ Math.abs(currentRect.left - previousRect.left) > 0.5;
180
+ if (moved) {
181
+ stableFrames = 0;
182
+ }
183
+ else {
184
+ stableFrames += 1;
185
+ if (stableFrames >= 2) {
186
+ return;
114
187
  }
115
188
  }
189
+ previousRect = currentRect;
190
+ }
191
+ }
192
+ async function scrollElementForHighlight(element) {
193
+ if (shouldSkipHighlightScroll(element)) {
116
194
  return;
117
195
  }
118
- // Regular selectors - highlight all matching elements
119
- const elements = document.querySelectorAll(cssSelector);
120
- if (elements.length > 0) {
196
+ element.scrollIntoView({
197
+ behavior: "smooth",
198
+ block: "nearest",
199
+ inline: "nearest",
200
+ });
201
+ await waitForScrollToFinish(element);
202
+ }
203
+ // Highlight an element temporarily
204
+ export async function highlightElement(selector, duration = HIGHLIGHT_DURATION_MS) {
205
+ const cssSelector = expandSelector(selector);
206
+ const elements = getElementsForSelector(selector);
207
+ if (elements.length === 0)
208
+ return;
209
+ if (cssSelector.startsWith("iframe:")) {
210
+ const iframe = document.querySelector("iframe.page-iframe");
211
+ const iframeRect = iframe?.getBoundingClientRect();
212
+ if (elements[0]) {
213
+ await scrollElementForHighlight(elements[0]);
214
+ }
121
215
  elements.forEach((element) => {
122
- const rect = element.getBoundingClientRect();
123
- showHighlightOverlay(rect.left, rect.top, rect.width, rect.height, duration);
216
+ const elementRect = element.getBoundingClientRect();
217
+ showHighlightOverlay(elementRect.left + (iframeRect?.left ?? 0), elementRect.top + (iframeRect?.top ?? 0), elementRect.width, elementRect.height, duration);
124
218
  });
125
- // Scroll the first element into view
126
- elements[0]?.scrollIntoView({ behavior: "smooth", block: "center" });
219
+ return;
127
220
  }
221
+ if (elements[0]) {
222
+ await scrollElementForHighlight(elements[0]);
223
+ }
224
+ elements.forEach((element) => {
225
+ const rect = element.getBoundingClientRect();
226
+ showHighlightOverlay(rect.left, rect.top, rect.width, rect.height, duration);
227
+ });
128
228
  }
129
229
  // Check if an element is currently available in the DOM
130
230
  function isElementAvailable(selector) {
131
- const cssSelector = expandSelector(selector);
132
- if (cssSelector.startsWith("iframe:")) {
133
- const iframeSelector = cssSelector.substring(7);
134
- const iframe = document.querySelector("iframe.page-iframe");
135
- return !!iframe?.contentDocument?.querySelector(iframeSelector);
136
- }
137
- return !!document.querySelector(cssSelector);
231
+ return getElementsForSelector(selector).length > 0;
138
232
  }
139
233
  // Create a temporary highlight overlay
140
234
  function showHighlightOverlay(x, y, width, height, duration) {
141
235
  const padding = 4;
236
+ const viewportWidth = window.innerWidth;
237
+ const viewportHeight = window.innerHeight;
238
+ const rawLeft = x - padding;
239
+ const rawTop = y - padding;
240
+ const rawRight = x + width + padding;
241
+ const rawBottom = y + height + padding;
242
+ const left = Math.max(0, Math.min(rawLeft, viewportWidth));
243
+ const top = Math.max(0, Math.min(rawTop, viewportHeight));
244
+ const right = Math.max(0, Math.min(rawRight, viewportWidth));
245
+ const bottom = Math.max(0, Math.min(rawBottom, viewportHeight));
246
+ const clampedWidth = right - left;
247
+ const clampedHeight = bottom - top;
248
+ // Skip if target is fully outside the viewport after clamping.
249
+ if (clampedWidth <= 0 || clampedHeight <= 0)
250
+ return;
142
251
  const overlay = document.createElement("div");
143
252
  overlay.className = "selector-highlight-overlay";
144
253
  overlay.style.cssText = `
145
254
  position: fixed;
146
- left: ${x - padding}px;
147
- top: ${y - padding}px;
148
- width: ${width + padding * 2}px;
149
- height: ${height + padding * 2}px;
255
+ left: ${left}px;
256
+ top: ${top}px;
257
+ width: ${clampedWidth}px;
258
+ height: ${clampedHeight}px;
150
259
  border: 2px solid #3b82f6;
151
260
  border-radius: 4px;
152
261
  background: rgba(59, 130, 246, 0.1);
@@ -175,6 +284,8 @@ function showHighlightOverlay(x, y, width, height, duration) {
175
284
  // Button component for "Show me" functionality with availability detection
176
285
  function SelectorButton({ selectorDef, keyProp, }) {
177
286
  const editContext = useEditContext();
287
+ const manualActions = editContext?.configuration.editor.manualActions;
288
+ const availabilitySelector = selectorDef.availabilitySelector || selectorDef.selector;
178
289
  // For sidebar-only selectors, we don't need to check for an element
179
290
  const isSidebarOnly = selectorDef.isSidebarOnly;
180
291
  // Initialize to true for sidebar-only, false otherwise to avoid hydration mismatch
@@ -182,9 +293,12 @@ function SelectorButton({ selectorDef, keyProp, }) {
182
293
  const [isAvailable, setIsAvailable] = useState(isSidebarOnly ? true : false);
183
294
  // Can open sidebar if: sidebar-only selector
184
295
  const canAutoOpenSidebar = Boolean(isSidebarOnly && editContext?.openSidebar && selectorDef.location);
296
+ const hasBeforeAction = Boolean(selectorDef.beforeAction &&
297
+ manualActions?.[selectorDef.beforeAction] &&
298
+ editContext);
185
299
  const isActionable = isSidebarOnly
186
- ? canAutoOpenSidebar
187
- : isAvailable || canAutoOpenSidebar;
300
+ ? canAutoOpenSidebar || hasBeforeAction
301
+ : isAvailable || canAutoOpenSidebar || hasBeforeAction;
188
302
  // Monitor for element availability changes (skip for sidebar-only selectors)
189
303
  useEffect(() => {
190
304
  // Sidebar-only selectors are always "available" if openSidebar exists
@@ -193,10 +307,11 @@ function SelectorButton({ selectorDef, keyProp, }) {
193
307
  return;
194
308
  }
195
309
  // Initial check
196
- setIsAvailable(isElementAvailable(selectorDef.selector));
310
+ const initialAvailable = isElementAvailable(availabilitySelector);
311
+ setIsAvailable(initialAvailable);
197
312
  // Set up MutationObserver to watch for DOM changes
198
313
  const checkAvailability = () => {
199
- const available = isElementAvailable(selectorDef.selector);
314
+ const available = isElementAvailable(availabilitySelector);
200
315
  setIsAvailable(available);
201
316
  };
202
317
  // Watch the main document for changes
@@ -226,13 +341,31 @@ function SelectorButton({ selectorDef, keyProp, }) {
226
341
  iframeObserver?.disconnect();
227
342
  clearInterval(intervalId);
228
343
  };
229
- }, [selectorDef.selector, isSidebarOnly]);
230
- const tooltipText = isAvailable
344
+ }, [availabilitySelector, isSidebarOnly]);
345
+ const tooltipText = isActionable
231
346
  ? selectorDef.description
232
347
  : selectorDef.notFoundMessage || selectorDef.description;
233
- return (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { onClick: async () => {
348
+ return (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("button", { "aria-label": "Show me", onClick: async () => {
234
349
  if (!isActionable)
235
350
  return;
351
+ const runId = globalThis.crypto?.randomUUID?.() ??
352
+ `manual-${Date.now()}-${Math.random().toString(36).slice(2)}`;
353
+ const resolveElements = (selector = selectorDef.selector) => selector ? getElementsForSelector(selector) : [];
354
+ const runManualAction = async (actionName, elements) => {
355
+ if (!actionName || !editContext || !manualActions?.[actionName]) {
356
+ return;
357
+ }
358
+ const action = manualActions[actionName];
359
+ const actionProps = {
360
+ editContext,
361
+ selectorDef,
362
+ duration: HIGHLIGHT_DURATION_MS,
363
+ runId,
364
+ elements,
365
+ resolveElements,
366
+ };
367
+ await action(actionProps);
368
+ };
236
369
  // If this selector is sidebar-only, open the sidebar before highlighting.
237
370
  // For sidebar-only selectors, location is the sidebar ID (without -sidebar suffix)
238
371
  if (selectorDef.isSidebarOnly &&
@@ -246,164 +379,68 @@ function SelectorButton({ selectorDef, keyProp, }) {
246
379
  await new Promise((resolve) => setTimeout(resolve, 150));
247
380
  }
248
381
  }
382
+ const resolvedElements = !isSidebarOnly ? resolveElements() : [];
383
+ await runManualAction(selectorDef.beforeAction, resolvedElements);
249
384
  // For sidebar-only selectors, we just open the sidebar (done above)
250
385
  // For regular selectors, also highlight the element
251
386
  if (!isSidebarOnly && selectorDef.selector) {
252
- highlightElement(selectorDef.selector);
387
+ await highlightElement(selectorDef.selector, HIGHLIGHT_DURATION_MS);
388
+ }
389
+ if (selectorDef.afterAction) {
390
+ window.setTimeout(() => {
391
+ void runManualAction(selectorDef.afterAction, !isSidebarOnly ? resolveElements() : []);
392
+ }, HIGHLIGHT_DURATION_MS);
253
393
  }
254
- }, disabled: !isActionable, className: cn("inline-flex items-center rounded border px-1.5 py-0.5 text-xs font-medium transition-colors", isActionable
394
+ }, disabled: !isActionable, className: cn("inline-flex h-5 w-5 items-center justify-center rounded border transition-colors", isActionable
255
395
  ? "cursor-pointer border-blue-200 bg-blue-50 text-blue-700 hover:bg-blue-100"
256
- : "cursor-not-allowed border-gray-200 bg-gray-100 text-gray-400"), children: "Show me" }, keyProp) }), _jsx(TooltipContent, { children: tooltipText })] }));
257
- }
258
- // Check if a line is a markdown table row (starts and ends with |)
259
- function isTableRow(line) {
260
- const trimmed = line.trim();
261
- return trimmed.startsWith("|") && trimmed.endsWith("|");
262
- }
263
- // Check if a line is a table separator row (contains only |, -, :, and spaces)
264
- function isTableSeparator(line) {
265
- const trimmed = line.trim();
266
- return isTableRow(line) && /^\|[\s\-:|]+\|$/.test(trimmed);
267
- }
268
- // Parse table cells from a row, handling the | delimiters
269
- function parseTableCells(line) {
270
- const trimmed = line.trim();
271
- // Remove leading and trailing |, then split by |
272
- const inner = trimmed.slice(1, -1);
273
- return inner.split("|").map((cell) => cell.trim());
274
- }
275
- // Parse column alignments from separator row
276
- function parseTableAlignments(separatorLine) {
277
- const cells = parseTableCells(separatorLine);
278
- return cells.map((cell) => {
279
- const trimmed = cell.trim();
280
- const startsWithColon = trimmed.startsWith(":");
281
- const endsWithColon = trimmed.endsWith(":");
282
- if (startsWithColon && endsWithColon)
283
- return "center";
284
- if (endsWithColon)
285
- return "right";
286
- return "left";
287
- });
288
- }
289
- // Render a markdown table
290
- function renderTable(headerCells, alignments, bodyRows, uiSelectors, keyPrefix) {
291
- const alignClasses = {
292
- left: "text-left",
293
- center: "text-center",
294
- right: "text-right",
295
- };
296
- return (_jsx("div", { className: "my-3 overflow-x-auto", children: _jsxs("table", { className: "min-w-full border-collapse rounded-md border border-gray-200 text-sm", children: [_jsx("thead", { className: "bg-gray-50", children: _jsx("tr", { children: headerCells.map((cell, cellIndex) => (_jsx("th", { className: cn("border border-gray-200 px-3 py-2 font-semibold text-gray-700", alignClasses[alignments[cellIndex] || "left"]), children: renderLineWithSelectors(cell, uiSelectors) }, cellIndex))) }) }), _jsx("tbody", { children: bodyRows.map((row, rowIndex) => (_jsx("tr", { className: rowIndex % 2 === 0 ? "bg-white" : "bg-gray-50", children: row.map((cell, cellIndex) => (_jsx("td", { className: cn("border border-gray-200 px-3 py-2 text-gray-600", alignClasses[alignments[cellIndex] || "left"]), children: renderLineWithSelectors(cell, uiSelectors) }, cellIndex))) }, rowIndex))) })] }) }, keyPrefix));
396
+ : "cursor-not-allowed border-gray-200 bg-gray-100 text-gray-400"), children: [_jsx(LocateFixed, { className: "h-3.5 w-3.5", strokeWidth: 1.5 }), _jsx("span", { className: "sr-only", children: "Show me" })] }, keyProp) }), _jsx(TooltipContent, { children: tooltipText })] }));
297
397
  }
298
398
  // Render markdown content with clickable selectors
299
399
  // Supports both {{selectorName}} syntax (looks up in uiSelectors) and legacy @selector syntax
300
- function renderMarkdownWithSelectors(content, uiSelectors) {
301
- // Simple markdown rendering with selector support
302
- // Normalize line endings (handle \r\n and \r)
303
- const normalizedContent = content.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
304
- const lines = normalizedContent.split("\n");
305
- const elements = [];
306
- let lineIndex = 0;
307
- while (lineIndex < lines.length) {
308
- const line = lines[lineIndex] || "";
309
- // Check if this is the start of a table
310
- if (isTableRow(line) && !isTableSeparator(line)) {
311
- // Look ahead for separator row to confirm this is a table
312
- const nextLine = lines[lineIndex + 1];
313
- if (nextLine && isTableSeparator(nextLine)) {
314
- // This is a table! Parse it
315
- const headerCells = parseTableCells(line);
316
- const alignments = parseTableAlignments(nextLine);
317
- const bodyRows = [];
318
- // Skip header and separator
319
- let tableLineIndex = lineIndex + 2;
320
- // Collect body rows
321
- while (tableLineIndex < lines.length &&
322
- isTableRow(lines[tableLineIndex] || "") &&
323
- !isTableSeparator(lines[tableLineIndex] || "")) {
324
- bodyRows.push(parseTableCells(lines[tableLineIndex] || ""));
325
- tableLineIndex++;
326
- }
327
- elements.push(renderTable(headerCells, alignments, bodyRows, uiSelectors, lineIndex));
328
- lineIndex = tableLineIndex;
329
- continue;
330
- }
331
- }
332
- // Handle headings
333
- if (line.startsWith("# ")) {
334
- elements.push(_jsx("h1", { className: "mt-4 mb-2 text-xl font-bold text-gray-900", children: renderLineWithSelectors(line.substring(2), uiSelectors) }, lineIndex));
335
- lineIndex++;
336
- continue;
337
- }
338
- if (line.startsWith("## ")) {
339
- elements.push(_jsx("h2", { className: "mt-3 mb-2 text-lg font-semibold text-gray-800", children: renderLineWithSelectors(line.substring(3), uiSelectors) }, lineIndex));
340
- lineIndex++;
341
- continue;
342
- }
343
- if (line.startsWith("### ")) {
344
- elements.push(_jsx("h3", { className: "mt-2 mb-1 text-base font-semibold text-gray-700", children: renderLineWithSelectors(line.substring(4), uiSelectors) }, lineIndex));
345
- lineIndex++;
346
- continue;
347
- }
348
- // Handle unordered list items - collect consecutive items and wrap in <ul>
349
- if (line.match(/^[-*] /)) {
350
- const listItems = [];
351
- const startIndex = lineIndex;
352
- while (lineIndex < lines.length &&
353
- (lines[lineIndex] || "").match(/^[-*] /)) {
354
- const itemLine = lines[lineIndex] || "";
355
- listItems.push(_jsx("li", { className: "text-sm text-gray-600", children: renderLineWithSelectors(itemLine.substring(2), uiSelectors) }, lineIndex));
356
- lineIndex++;
357
- }
358
- elements.push(_jsx("ul", { className: "my-2 ml-6 space-y-1", style: { listStyleType: "disc", paddingLeft: "1rem" }, children: listItems }, `ul-${startIndex}`));
359
- continue;
360
- }
361
- // Handle ordered list items - collect consecutive items and wrap in <ol>
362
- if (line.match(/^\d+\.\s/)) {
363
- const listItems = [];
364
- const startIndex = lineIndex;
365
- while (lineIndex < lines.length &&
366
- (lines[lineIndex] || "").match(/^\d+\.\s/)) {
367
- const itemLine = lines[lineIndex] || "";
368
- // Extract content after "N. " - use substring to get everything after the number and dot
369
- const dotIndex = itemLine.indexOf(".");
370
- const itemContent = dotIndex >= 0
371
- ? itemLine.substring(dotIndex + 1).trimStart()
372
- : itemLine;
373
- listItems.push(_jsx("li", { className: "text-sm text-gray-600", children: renderLineWithSelectors(itemContent, uiSelectors) }, lineIndex));
374
- lineIndex++;
375
- }
376
- elements.push(_jsx("ol", { className: "my-2 ml-6 space-y-1", style: { listStyleType: "decimal", paddingLeft: "1rem" }, children: listItems }, `ol-${startIndex}`));
377
- continue;
378
- }
379
- // Handle horizontal rules (---, ***, ___)
380
- if (line.match(/^[-*_]{3,}\s*$/)) {
381
- elements.push(_jsx("hr", { className: "my-4 border-t border-gray-200" }, lineIndex));
382
- lineIndex++;
383
- continue;
400
+ function renderMarkdownWithSelectors(content, uiSelectors, manualLinkTargets, onManualLinkClick) {
401
+ return (_jsx(MarkdownDisplay, { source: content, className: "space-y-0", components: manualMarkdownComponents, renderInline: (line) => renderLineWithSelectors(line, uiSelectors, manualLinkTargets, onManualLinkClick) }));
402
+ }
403
+ // Render a line with clickable selectors and basic formatting
404
+ // Supports: {{selectorName}} for named selectors, @selector for legacy direct selectors, **bold** text
405
+ // Parentheses around selectors (e.g., ({{name}})) are automatically hidden
406
+ function renderLineWithSelectors(text, uiSelectors, manualLinkTargets, onManualLinkClick) {
407
+ if (!manualLinkTargets || !onManualLinkClick) {
408
+ return renderInlineSelectorsAndFormatting(text, uiSelectors);
409
+ }
410
+ const parts = [];
411
+ const linkRegex = /\[\[([^\]]+)\]\]/g;
412
+ let lastIndex = 0;
413
+ let match;
414
+ while ((match = linkRegex.exec(text)) !== null) {
415
+ const fullMatch = match[0] || "";
416
+ const linkTitle = (match[1] || "").trim();
417
+ if (match.index > lastIndex) {
418
+ const prefix = text.substring(lastIndex, match.index);
419
+ parts.push(_jsx(React.Fragment, { children: renderInlineSelectorsAndFormatting(prefix, uiSelectors) }, `text-${match.index}`));
384
420
  }
385
- // Regular paragraph
386
- if (line.trim()) {
387
- elements.push(_jsx("p", { className: "my-1 text-sm text-gray-600", children: renderLineWithSelectors(line, uiSelectors) }, lineIndex));
421
+ const targetId = manualLinkTargets.get(linkTitle.toLowerCase());
422
+ if (targetId) {
423
+ parts.push(_jsx("button", { type: "button", onClick: () => onManualLinkClick(targetId), className: "cursor-pointer text-blue-600 underline decoration-blue-300 underline-offset-2 hover:text-blue-700", title: `Open "${linkTitle}"`, children: linkTitle }, `manual-link-${match.index}`));
388
424
  }
389
425
  else {
390
- elements.push(_jsx("div", { className: "h-2" }, lineIndex));
426
+ parts.push(_jsx("span", { className: "text-orange-600", title: `Manual section not found: ${linkTitle}`, children: fullMatch }, `manual-link-missing-${match.index}`));
391
427
  }
392
- lineIndex++;
428
+ lastIndex = match.index + fullMatch.length;
429
+ }
430
+ if (lastIndex < text.length) {
431
+ const suffix = text.substring(lastIndex);
432
+ parts.push(_jsx(React.Fragment, { children: renderInlineSelectorsAndFormatting(suffix, uiSelectors) }, `suffix-${lastIndex}`));
393
433
  }
394
- return _jsx("div", { className: "space-y-1", children: elements });
434
+ return _jsx(_Fragment, { children: parts });
395
435
  }
396
- // Render a line with clickable selectors and basic formatting
397
- // Supports: {{selectorName}} for named selectors, @selector for legacy direct selectors, **bold** text
398
- // Parentheses around selectors (e.g., ({{name}})) are automatically hidden
399
- function renderLineWithSelectors(text, uiSelectors) {
436
+ function renderInlineSelectorsAndFormatting(text, uiSelectors) {
400
437
  const parts = [];
401
438
  let lastIndex = 0;
402
439
  // Combined regex for {{namedSelector}}, @selector, and **bold**
403
440
  // Note: @selector can include -sidebar suffix for sidebar-only selectors
404
441
  // Also supports @iframe:selector syntax (iframe: is special and allowed)
405
442
  // Now also matches optional parentheses around selectors: ({{name}}) or (@selector)
406
- const regex = /(\()?(\{\{([\w\-]+)\}\})|(\()?(@(?:iframe:[\w\-\.#\[\]=]+|[\w\-\.#\[\]=]+))|(\*\*(.+?)\*\*)/g;
443
+ const regex = /(\()?(\{\{([\w\-]+)\}\})|(\()?(@(?:iframe:[\w\-\.#\[\]=]*[\w\-#\[\]=]|[\w\-\.#\[\]=]*[\w\-#\[\]=]))|(\*\*(.+?)\*\*)/g;
407
444
  let match;
408
445
  while ((match = regex.exec(text)) !== null) {
409
446
  // Check if there's an opening parenthesis before the selector
@@ -440,7 +477,9 @@ function renderLineWithSelectors(text, uiSelectors) {
440
477
  // @selector match (legacy direct selector syntax) - create ad-hoc selector def
441
478
  const selectorToken = match[5];
442
479
  const parsed = parseSelectorToken(selectorToken);
443
- const adHocSelectorDef = {
480
+ const selectorName = selectorToken.replace(/^@/, "");
481
+ const registeredSelectorDef = uiSelectors.get(selectorName);
482
+ const effectiveSelectorDef = registeredSelectorDef ?? {
444
483
  name: selectorToken,
445
484
  selector: parsed.selector,
446
485
  description: parsed.isSidebarOnly
@@ -452,7 +491,7 @@ function renderLineWithSelectors(text, uiSelectors) {
452
491
  // Check if there's a closing paren after this selector
453
492
  const afterMatch = match.index + match[0].length;
454
493
  const hasCloseParen = text[afterMatch] === ")";
455
- parts.push(_jsx(SelectorButton, { selectorDef: adHocSelectorDef, keyProp: match.index }, match.index));
494
+ parts.push(_jsx(SelectorButton, { selectorDef: effectiveSelectorDef, keyProp: match.index }, match.index));
456
495
  // Skip the closing paren if present
457
496
  if (hasCloseParen && hasOpenParen) {
458
497
  lastIndex = afterMatch + 1;
@@ -472,21 +511,6 @@ function renderLineWithSelectors(text, uiSelectors) {
472
511
  }
473
512
  return _jsx(_Fragment, { children: parts });
474
513
  }
475
- // Flatten TOC tree into options with indentation for hierarchy
476
- function flattenTocToOptions(sections, depth = 0) {
477
- const options = [];
478
- for (const section of sections) {
479
- const indent = "\u00A0\u00A0".repeat(depth); // Non-breaking spaces for indentation
480
- options.push({
481
- value: section.id,
482
- label: `${indent}${section.title || "Untitled"}`,
483
- });
484
- if (section.children && section.children.length > 0) {
485
- options.push(...flattenTocToOptions(section.children, depth + 1));
486
- }
487
- }
488
- return options;
489
- }
490
514
  function findTocPath(sections, targetId, ancestors = []) {
491
515
  for (const section of sections) {
492
516
  const nextAncestors = [...ancestors, section];
@@ -500,36 +524,278 @@ function findTocPath(sections, targetId, ancestors = []) {
500
524
  }
501
525
  return null;
502
526
  }
503
- export function ManualBrowser() {
527
+ function isDirectlyNavigableSection(section) {
528
+ return !!section.hasContent || section.children.length === 0;
529
+ }
530
+ function resolveFirstNavigableSection(section) {
531
+ if (isDirectlyNavigableSection(section) || section.children.length === 0) {
532
+ return section;
533
+ }
534
+ return resolveFirstNavigableSection(section.children[0]);
535
+ }
536
+ function resolveSelectedSectionId(sections, targetId) {
537
+ const path = findTocPath(sections, targetId);
538
+ const targetSection = path?.[path.length - 1];
539
+ if (!targetSection)
540
+ return targetId;
541
+ return resolveFirstNavigableSection(targetSection).id;
542
+ }
543
+ function findNearestNavigableAncestor(path) {
544
+ if (!path || path.length < 2)
545
+ return null;
546
+ for (let i = path.length - 2; i >= 0; i -= 1) {
547
+ const section = path[i];
548
+ if (section && isDirectlyNavigableSection(section)) {
549
+ return section;
550
+ }
551
+ }
552
+ return null;
553
+ }
554
+ const SECTION_THEMES = {
555
+ "getting started": {
556
+ icon: Rocket,
557
+ color: "text-emerald-600",
558
+ bg: "bg-emerald-50",
559
+ border: "border-emerald-100",
560
+ accent: "bg-emerald-500",
561
+ },
562
+ "page editing": {
563
+ icon: FileEdit,
564
+ color: "text-blue-600",
565
+ bg: "bg-blue-50",
566
+ border: "border-blue-100",
567
+ accent: "bg-blue-500",
568
+ },
569
+ "managing content": {
570
+ icon: BookOpen,
571
+ color: "text-amber-600",
572
+ bg: "bg-amber-50",
573
+ border: "border-amber-100",
574
+ accent: "bg-amber-500",
575
+ },
576
+ "ai assistant": {
577
+ icon: BookOpen,
578
+ color: "text-violet-600",
579
+ bg: "bg-violet-50",
580
+ border: "border-violet-100",
581
+ accent: "bg-violet-500",
582
+ },
583
+ };
584
+ const DEFAULT_THEME = {
585
+ icon: BookOpen,
586
+ color: "text-violet-600",
587
+ bg: "bg-violet-50",
588
+ border: "border-violet-100",
589
+ accent: "bg-violet-500",
590
+ };
591
+ function getSectionTheme(title) {
592
+ if (!title)
593
+ return DEFAULT_THEME;
594
+ return SECTION_THEMES[title.toLowerCase()] ?? DEFAULT_THEME;
595
+ }
596
+ function TocSectionCard({ section, onSelect, onToggleCollapse, isCollapsed, }) {
597
+ const theme = getSectionTheme(section.title);
598
+ const Icon = theme.icon;
599
+ const hasChildren = !!(section.children && section.children.length > 0);
600
+ return (_jsxs("div", { className: "group", children: [_jsx("button", { type: "button", onClick: () => onSelect(section.id), className: cn("w-full rounded-lg p-3 text-left transition-all", "bg-white hover:bg-gray-50/50"), children: _jsxs("div", { className: "flex items-start gap-3", children: [_jsx("div", { className: cn("flex h-9 w-9 shrink-0 items-center justify-center rounded-lg", theme.bg), children: section.svgIcon ? (_jsx(SvgIcon, { svg: section.svgIcon, size: 24, className: theme.color })) : (_jsx(Icon, { className: cn("h-[18px] w-[18px]", theme.color), strokeWidth: 1.75 })) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "flex items-center gap-2", children: _jsx("span", { className: "text-sm font-semibold text-gray-900", children: section.title || "Untitled" }) }), section.summary && (_jsx("p", { className: "mt-0.5 line-clamp-2 text-xs leading-relaxed text-gray-500", children: section.summary }))] })] }) }), hasChildren && (_jsxs("div", { className: "mt-1", children: [_jsxs("button", { type: "button", onClick: () => onToggleCollapse(section.id), className: "ml-[60px] flex w-fit items-center gap-1.5 rounded-md py-1 text-xs text-gray-400 transition-colors hover:text-gray-600", children: [_jsx(ChevronRight, { className: cn("h-3 w-3 shrink-0 transition-transform", !isCollapsed && "rotate-90") }), _jsx("span", { children: isCollapsed ? "Show articles" : "Hide articles" })] }), !isCollapsed && (_jsx("div", { className: "mt-0.5 ml-[60px] space-y-px border-l-2 border-gray-100 pl-3", children: section.children.map((child) => (_jsxs("button", { type: "button", onClick: () => onSelect(child.id), className: "flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-left text-sm text-gray-600 transition-colors hover:bg-gray-50 hover:text-gray-900", children: [_jsx("span", { className: cn("h-1.5 w-1.5 shrink-0 rounded-full", theme.accent, "opacity-40 transition-opacity group-hover:opacity-70") }), _jsx("span", { className: "truncate", children: child.title || "Untitled" })] }, child.id))) }))] }))] }));
601
+ }
602
+ function renderTocTree(sections, onSelect, onToggleCollapse, collapsedSectionIds, depth = 0) {
603
+ if (depth === 0) {
604
+ return (_jsx("div", { className: "space-y-3", children: sections.map((section) => {
605
+ const isCollapsed = collapsedSectionIds.has(section.id);
606
+ return (_jsx(TocSectionCard, { section: section, onSelect: onSelect, onToggleCollapse: onToggleCollapse, isCollapsed: isCollapsed }, section.id));
607
+ }) }));
608
+ }
609
+ return (_jsx("div", { className: cn(depth > 0 && "ml-3 border-l border-gray-100 pl-2"), children: sections.map((section) => {
610
+ const hasChildren = !!(section.children && section.children.length > 0);
611
+ const isCollapsed = hasChildren && collapsedSectionIds.has(section.id);
612
+ return (_jsxs("div", { className: "my-0.5", children: [_jsxs("div", { className: cn("group flex w-full items-center gap-1.5 rounded-md px-2 py-1.5 transition-colors hover:bg-gray-50", "text-sm text-gray-500 hover:text-gray-700"), children: [hasChildren ? (_jsx("button", { type: "button", onClick: () => onToggleCollapse(section.id), className: "rounded p-0.5 text-gray-300 transition-colors hover:bg-gray-100 hover:text-gray-500", "aria-label": isCollapsed
613
+ ? `Expand ${section.title || "section"}`
614
+ : `Collapse ${section.title || "section"}`, title: isCollapsed ? "Expand section" : "Collapse section", children: _jsx(ChevronRight, { className: cn("h-3.5 w-3.5 shrink-0 transition-transform", !isCollapsed && "rotate-90") }) })) : (_jsx("span", { className: "h-3.5 w-3.5 shrink-0" })), _jsx("button", { type: "button", onClick: () => onSelect(section.id), className: "flex-1 text-left", children: section.title || "Untitled" })] }), hasChildren &&
615
+ !isCollapsed &&
616
+ renderTocTree(section.children, onSelect, onToggleCollapse, collapsedSectionIds, depth + 1)] }, section.id));
617
+ }) }));
618
+ }
619
+ function buildChapterOptions(chapter) {
620
+ const result = [];
621
+ const walk = (sections, depth) => {
622
+ for (const section of sections) {
623
+ result.push({ section, depth });
624
+ if (section.children.length > 0) {
625
+ walk(section.children, depth + 1);
626
+ }
627
+ }
628
+ };
629
+ // Include the chapter itself if it has content, then its children
630
+ if (isDirectlyNavigableSection(chapter)) {
631
+ result.push({ section: chapter, depth: 0 });
632
+ }
633
+ walk(chapter.children, isDirectlyNavigableSection(chapter) ? 1 : 0);
634
+ return result;
635
+ }
636
+ function InChapterDropdown({ toc, currentTocPath, selectedSectionId, onSelect, }) {
637
+ const chapter = currentTocPath?.[0] ?? null;
638
+ const chapterOptions = useMemo(() => (chapter ? buildChapterOptions(chapter) : []), [chapter]);
639
+ const allChapters = useMemo(() => toc, [toc]);
640
+ // Don't render if there's no chapter or only one page in it
641
+ if (!chapter || chapterOptions.length <= 1)
642
+ return null;
643
+ const selectedTitle = chapterOptions.find((o) => o.section.id === selectedSectionId)?.section.title;
644
+ return (_jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs("button", { type: "button", className: "inline-flex w-full items-center justify-between gap-2 rounded-md border border-gray-200 bg-white px-2.5 py-1.5 text-xs transition-colors hover:bg-gray-50", children: [_jsxs("span", { className: "truncate text-gray-500", children: [_jsx("span", { className: "font-medium text-gray-700", children: selectedTitle ?? chapter.title }), " ", _jsxs("span", { className: "text-gray-400", children: ["\u2014 in ", chapter.title] })] }), _jsx(ChevronDown, { className: "h-3.5 w-3.5 shrink-0 text-gray-400" })] }) }), _jsxs(DropdownMenuContent, { align: "start", className: "max-h-80 w-[--radix-dropdown-menu-trigger-width] overflow-y-auto", children: [allChapters.length > 0 && (_jsxs(_Fragment, { children: [_jsx(DropdownMenuLabel, { className: "text-[11px] font-semibold tracking-wide text-gray-400 uppercase", children: "Chapters" }), allChapters.map((c) => {
645
+ const isCurrent = c.id === chapter?.id;
646
+ const theme = getSectionTheme(c.title);
647
+ const Icon = theme.icon;
648
+ return (_jsxs(DropdownMenuItem, { onClick: () => !isCurrent && onSelect(c.id), className: cn(isCurrent && "bg-blue-50 font-medium"), children: [c.svgIcon ? (_jsx(SvgIcon, { svg: c.svgIcon, size: 14, className: cn("mr-1.5 shrink-0", theme.color) })) : (_jsx(Icon, { className: cn("mr-1.5 h-3.5 w-3.5 shrink-0", theme.color), strokeWidth: 1.75 })), _jsx("span", { className: "truncate", children: c.title })] }, c.id));
649
+ }), _jsx(DropdownMenuSeparator, {}), _jsxs(DropdownMenuLabel, { className: "text-[11px] font-semibold tracking-wide text-gray-400 uppercase", children: ["In ", chapter.title] })] })), chapterOptions.map(({ section, depth }) => {
650
+ const isActive = section.id === selectedSectionId;
651
+ const navigable = isDirectlyNavigableSection(section);
652
+ return (_jsx(DropdownMenuItem, { disabled: !navigable, onClick: () => navigable && onSelect(section.id), className: cn(isActive && "bg-blue-50 font-medium", !navigable && "pointer-events-none opacity-60"), style: { paddingLeft: `${8 + depth * 16}px` }, children: _jsx("span", { className: "truncate", children: section.title || "Untitled" }) }, section.id));
653
+ })] })] }));
654
+ }
655
+ function flattenSections(sections) {
656
+ const flattened = [];
657
+ for (const section of sections) {
658
+ flattened.push(section);
659
+ if (section.children && section.children.length > 0) {
660
+ flattened.push(...flattenSections(section.children));
661
+ }
662
+ }
663
+ return flattened;
664
+ }
665
+ function flattenNavigableSections(sections) {
666
+ const flattened = [];
667
+ for (const section of sections) {
668
+ if (isDirectlyNavigableSection(section)) {
669
+ flattened.push(section);
670
+ }
671
+ if (section.children.length > 0) {
672
+ flattened.push(...flattenNavigableSections(section.children));
673
+ }
674
+ }
675
+ return flattened;
676
+ }
677
+ const MANUAL_SECTION_TEMPLATE_ID = "c5f1e8a2-9b50-4fe2-9b6d-3db00c3b3b8a";
678
+ export function ManualBrowser({ onClose }) {
504
679
  const editContext = useEditContext();
505
680
  const [toc, setToc] = useState([]);
506
- const [selectedSectionId, setSelectedSectionId] = useState(null);
681
+ const selectedSectionId = editContext?.selectedHelpSectionId ?? null;
507
682
  const [currentSection, setCurrentSection] = useState(null);
683
+ const currentSectionRef = useRef(null);
508
684
  const [loadingToc, setLoadingToc] = useState(false);
509
685
  const [loadingSection, setLoadingSection] = useState(false);
510
686
  const [error, setError] = useState(null);
687
+ const [searchQuery, setSearchQuery] = useState("");
688
+ const [searchResults, setSearchResults] = useState([]);
689
+ const [searching, setSearching] = useState(false);
690
+ const [collapsedTocSectionIds, setCollapsedTocSectionIds] = useState(() => new Set());
691
+ const [manualBackHistory, setManualBackHistory] = useState([]);
511
692
  // Track revision to force re-fetch (incremented when websocket notifies of changes)
512
693
  const [sectionRevision, setSectionRevision] = useState(0);
513
694
  // Keep a ref to all TOC item IDs for checking if changed item is in the manual
514
695
  const tocItemIdsRef = useRef(new Set());
696
+ const manualBackHistoryRef = useRef([]);
697
+ const historyNavigationModeRef = useRef(null);
698
+ const lastObservedSelectedSectionIdRef = useRef(undefined);
515
699
  // Keep a ref to selectedSectionId to avoid stale closures in websocket callback
516
700
  const selectedSectionIdRef = useRef(null);
517
- // Flatten TOC into select options
518
- const sectionOptions = useMemo(() => flattenTocToOptions(toc), [toc]);
519
701
  const currentTocPath = useMemo(() => {
520
702
  if (!selectedSectionId)
521
703
  return null;
522
704
  return findTocPath(toc, selectedSectionId);
523
705
  }, [toc, selectedSectionId]);
524
706
  const parentTocSection = useMemo(() => {
525
- if (!currentTocPath || currentTocPath.length < 2)
526
- return null;
527
- return currentTocPath[currentTocPath.length - 2] || null;
707
+ return findNearestNavigableAncestor(currentTocPath);
528
708
  }, [currentTocPath]);
709
+ const chapterNavigation = useMemo(() => {
710
+ if (!selectedSectionId)
711
+ return { previous: null, next: null };
712
+ const flatSections = flattenNavigableSections(toc);
713
+ const currentIndex = flatSections.findIndex((section) => section.id === selectedSectionId);
714
+ if (currentIndex < 0)
715
+ return { previous: null, next: null };
716
+ return {
717
+ previous: currentIndex > 0 ? flatSections[currentIndex - 1] : null,
718
+ next: currentIndex < flatSections.length - 1
719
+ ? flatSections[currentIndex + 1]
720
+ : null,
721
+ };
722
+ }, [toc, selectedSectionId]);
723
+ const manualLinkTargets = useMemo(() => {
724
+ const lookup = new Map();
725
+ const sections = flattenSections(toc);
726
+ for (const section of sections) {
727
+ const key = section.title?.trim().toLowerCase();
728
+ if (key && !lookup.has(key)) {
729
+ lookup.set(key, resolveFirstNavigableSection(section).id);
730
+ }
731
+ }
732
+ return lookup;
733
+ }, [toc]);
734
+ const manualSectionsById = useMemo(() => {
735
+ const map = new Map();
736
+ const sections = flattenSections(toc);
737
+ for (const section of sections) {
738
+ map.set(section.id.toLowerCase(), section);
739
+ }
740
+ return map;
741
+ }, [toc]);
742
+ const backTargetSectionId = manualBackHistory.length > 0
743
+ ? manualBackHistory[manualBackHistory.length - 1]
744
+ : null;
745
+ const backTargetSection = useMemo(() => {
746
+ if (!backTargetSectionId)
747
+ return null;
748
+ return manualSectionsById.get(backTargetSectionId.toLowerCase()) ?? null;
749
+ }, [backTargetSectionId, manualSectionsById]);
750
+ const backButtonLabel = backTargetSection?.title
751
+ ? `Back to ${backTargetSection.title}`
752
+ : "Back to contents";
753
+ const backButtonText = backTargetSectionId === null ? "Contents" : "Back";
529
754
  // Keep selectedSectionId ref in sync
530
755
  useEffect(() => {
531
756
  selectedSectionIdRef.current = selectedSectionId;
532
757
  }, [selectedSectionId]);
758
+ useEffect(() => {
759
+ currentSectionRef.current = currentSection;
760
+ }, [currentSection]);
761
+ useEffect(() => {
762
+ manualBackHistoryRef.current = manualBackHistory;
763
+ }, [manualBackHistory]);
764
+ useEffect(() => {
765
+ const previousSelectedSectionId = lastObservedSelectedSectionIdRef.current;
766
+ if (previousSelectedSectionId === undefined) {
767
+ lastObservedSelectedSectionIdRef.current = selectedSectionId;
768
+ return;
769
+ }
770
+ const normalizedPreviousSelectedSectionId = previousSelectedSectionId && toc.length > 0
771
+ ? resolveSelectedSectionId(toc, previousSelectedSectionId)
772
+ : previousSelectedSectionId;
773
+ const normalizedSelectedSectionId = selectedSectionId && toc.length > 0
774
+ ? resolveSelectedSectionId(toc, selectedSectionId)
775
+ : selectedSectionId;
776
+ if (normalizedPreviousSelectedSectionId === normalizedSelectedSectionId) {
777
+ lastObservedSelectedSectionIdRef.current = selectedSectionId;
778
+ return;
779
+ }
780
+ if (historyNavigationModeRef.current === "back") {
781
+ historyNavigationModeRef.current = null;
782
+ }
783
+ else {
784
+ setManualBackHistory((prev) => [
785
+ ...prev,
786
+ normalizedPreviousSelectedSectionId,
787
+ ]);
788
+ }
789
+ lastObservedSelectedSectionIdRef.current = selectedSectionId;
790
+ }, [selectedSectionId, toc]);
791
+ useEffect(() => {
792
+ if (!selectedSectionId || !editContext || toc.length === 0)
793
+ return;
794
+ const resolvedSectionId = resolveSelectedSectionId(toc, selectedSectionId);
795
+ if (resolvedSectionId !== selectedSectionId) {
796
+ editContext.setSelectedHelpSectionId(resolvedSectionId);
797
+ }
798
+ }, [editContext, selectedSectionId, toc]);
533
799
  // Build set of all TOC item IDs (for websocket matching)
534
800
  useEffect(() => {
535
801
  const collectIds = (sections) => {
@@ -551,10 +817,6 @@ export function ManualBrowser() {
551
817
  loadManualToc()
552
818
  .then((data) => {
553
819
  setToc(data);
554
- // Auto-select first section if available
555
- if (data.length > 0 && data[0]) {
556
- setSelectedSectionId(data[0].id);
557
- }
558
820
  })
559
821
  .catch((err) => {
560
822
  console.error("Failed to load manual TOC:", err);
@@ -566,28 +828,96 @@ export function ManualBrowser() {
566
828
  }, []);
567
829
  // Load section content when selection changes or revision changes
568
830
  useEffect(() => {
831
+ let cancelled = false;
569
832
  if (!selectedSectionId) {
570
833
  setCurrentSection(null);
571
834
  setLoadingSection(false);
572
835
  return;
573
836
  }
837
+ const resolvedSectionId = toc.length > 0
838
+ ? resolveSelectedSectionId(toc, selectedSectionId)
839
+ : selectedSectionId;
840
+ if (resolvedSectionId !== selectedSectionId) {
841
+ return () => {
842
+ cancelled = true;
843
+ };
844
+ }
574
845
  // Only show loading spinner if we don't have current section (initial load)
575
846
  // For refreshes, keep showing the old content to avoid flicker
576
- const isInitialLoad = !currentSection || currentSection.id !== selectedSectionId;
847
+ const isInitialLoad = !currentSectionRef.current ||
848
+ currentSectionRef.current.id !== selectedSectionId;
577
849
  if (isInitialLoad) {
578
850
  setLoadingSection(true);
579
851
  }
580
- loadManualSection(selectedSectionId)
852
+ loadManualSection(resolvedSectionId)
581
853
  .then((data) => {
854
+ if (cancelled)
855
+ return;
582
856
  setCurrentSection(data);
583
857
  setLoadingSection(false);
584
858
  })
585
859
  .catch((err) => {
860
+ if (cancelled)
861
+ return;
586
862
  console.error("Failed to load section:", err);
587
863
  setCurrentSection(null);
588
864
  setLoadingSection(false);
589
865
  });
590
- }, [selectedSectionId, sectionRevision]);
866
+ return () => {
867
+ cancelled = true;
868
+ };
869
+ }, [sectionRevision, selectedSectionId, toc]);
870
+ // Search manual sections using internal search (SQL + AI providers).
871
+ useEffect(() => {
872
+ let cancelled = false;
873
+ const trimmedQuery = searchQuery.trim();
874
+ if (!trimmedQuery || !editContext) {
875
+ setSearching(false);
876
+ setSearchResults([]);
877
+ return;
878
+ }
879
+ const timeoutId = window.setTimeout(async () => {
880
+ setSearching(true);
881
+ try {
882
+ const result = await executeSearch({
883
+ query: `${trimmedQuery}|template:${MANUAL_SECTION_TEMPLATE_ID}`,
884
+ editContext,
885
+ maxResults: 20,
886
+ index: "master",
887
+ skipValidation: true,
888
+ });
889
+ if (cancelled)
890
+ return;
891
+ if (result.type === "success") {
892
+ const items = result.data || [];
893
+ const mapped = items
894
+ .map((item) => manualSectionsById.get(String(item.id || "").toLowerCase()))
895
+ .filter((section) => !!section);
896
+ const unique = Array.from(new Map(mapped.map((section) => [section.id, section])).values());
897
+ setSearchResults(unique);
898
+ }
899
+ else {
900
+ console.error("Failed to search manual", result.response.statusText);
901
+ setSearchResults([]);
902
+ }
903
+ }
904
+ catch (err) {
905
+ if (!cancelled) {
906
+ console.error("Manual search failed", err);
907
+ setSearchResults([]);
908
+ }
909
+ }
910
+ finally {
911
+ if (!cancelled) {
912
+ setSearching(false);
913
+ }
914
+ }
915
+ }, 300);
916
+ return () => {
917
+ cancelled = true;
918
+ window.clearTimeout(timeoutId);
919
+ };
920
+ }, [searchQuery, editContext, manualSectionsById]);
591
921
  // Listen for websocket messages to auto-refresh when manual items change
592
922
  // Use ref for selectedSectionId to avoid stale closures and only re-register when selection actually changes
593
923
  useEffect(() => {
@@ -621,8 +951,43 @@ export function ManualBrowser() {
621
951
  return removeListener;
622
952
  }, [selectedSectionId]); // Only re-register when selectedSectionId changes, not when editContext object changes
623
953
  const handleSelectSection = useCallback((id) => {
624
- setSelectedSectionId(id);
954
+ if (!editContext)
955
+ return;
956
+ editContext.setSelectedHelpSectionId(resolveSelectedSectionId(toc, id));
957
+ }, [editContext, toc]);
958
+ const handleSelectSearchResult = useCallback((id) => {
959
+ if (!editContext)
960
+ return;
961
+ editContext.setSelectedHelpSectionId(resolveSelectedSectionId(toc, id));
962
+ setSearchQuery("");
963
+ setSearchResults([]);
964
+ }, [editContext, toc]);
965
+ const handleToggleTocSection = useCallback((id) => {
966
+ setCollapsedTocSectionIds((prev) => {
967
+ const next = new Set(prev);
968
+ if (next.has(id)) {
969
+ next.delete(id);
970
+ }
971
+ else {
972
+ next.add(id);
973
+ }
974
+ return next;
975
+ });
625
976
  }, []);
977
+ const normalizeHistorySectionId = useCallback((id) => {
978
+ if (!id || toc.length === 0)
979
+ return id;
980
+ return resolveSelectedSectionId(toc, id);
981
+ }, [toc]);
982
+ const handleGoBack = useCallback(() => {
983
+ if (!editContext || !selectedSectionId)
984
+ return;
985
+ const history = manualBackHistoryRef.current;
986
+ const previousSectionId = history.length > 0 ? history[history.length - 1] : null;
987
+ historyNavigationModeRef.current = "back";
988
+ setManualBackHistory((prev) => prev.length > 0 ? prev.slice(0, -1) : prev);
989
+ editContext.setSelectedHelpSectionId(normalizeHistorySectionId(previousSectionId));
990
+ }, [editContext, normalizeHistorySectionId, selectedSectionId]);
626
991
  if (loadingToc) {
627
992
  return (_jsx("div", { className: "flex items-center justify-center py-8", children: _jsx(Loader2, { className: "h-5 w-5 animate-spin text-gray-400" }) }));
628
993
  }
@@ -632,7 +997,7 @@ export function ManualBrowser() {
632
997
  if (toc.length === 0) {
633
998
  return (_jsxs("div", { className: "px-4 py-8 text-center text-sm text-gray-500", children: [_jsx(Book, { className: "mx-auto mb-2 h-8 w-8 text-gray-300" }), _jsx("p", { children: "No manual content available yet." })] }));
634
999
  }
635
- return (_jsxs("div", { className: "flex h-full flex-col", children: [_jsx("div", { className: "shrink-0 border-b border-gray-100 px-3 py-2", children: _jsx(Select, { value: selectedSectionId || undefined, onValueChange: handleSelectSection, options: sectionOptions, placeholder: "Select a section...", size: "sm", className: "w-full rounded-md", searchable: sectionOptions.length > 10, searchPlaceholder: "Search sections..." }) }), _jsx("div", { className: "flex-1 overflow-y-auto p-4 select-text", children: loadingSection ? (_jsx("div", { className: "flex items-center justify-center py-8", children: _jsx(Loader2, { className: "h-5 w-5 animate-spin text-gray-400" }) })) : currentSection ? (_jsxs("div", { children: [_jsxs("div", { className: "mb-1 flex items-start justify-between gap-2", children: [_jsxs("div", { className: "flex min-w-0 flex-1 items-start gap-2", children: [parentTocSection && (_jsxs("button", { type: "button", onClick: () => handleSelectSection(parentTocSection.id), className: "inline-flex shrink-0 items-center gap-1 rounded px-2 py-1 text-sm text-gray-600 transition-colors hover:bg-gray-100 hover:text-gray-900", "aria-label": `Back to ${parentTocSection.title}`, title: `Back to ${parentTocSection.title}`, children: [_jsx(ArrowLeft, { className: "h-4 w-4" }), _jsx("span", { className: "hidden sm:inline", children: "Back" })] })), _jsx("h2", { className: "min-w-0 flex-1 text-xl font-bold text-gray-900", children: currentSection.title })] }), editContext?.user?.isAdministrator && editContext?.loadItem && (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", onClick: async (e) => {
1000
+ return (_jsxs("div", { className: "flex h-full flex-col", children: [_jsxs("div", { className: "shrink-0 border-b border-gray-200/60 bg-linear-to-b from-gray-50 to-white px-4 py-3", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "flex h-7 w-7 items-center justify-center rounded-lg bg-blue-50", children: _jsx(Book, { className: "h-4 w-4 text-blue-600", strokeWidth: 1.75 }) }), _jsx("h2", { className: "text-base font-semibold text-gray-900", children: "User Manual" })] }), onClose && (_jsx("button", { onClick: onClose, className: "shrink-0 rounded p-1 text-gray-400 transition-colors hover:bg-gray-200 hover:text-gray-600", "aria-label": "Close", children: _jsx(X, { size: 16, strokeWidth: 1.5 }) }))] }), _jsx("div", { className: "mt-2", children: _jsx(FilterInput, { value: searchQuery, onChange: setSearchQuery, placeholder: "Search manual pages...", size: "xs", loading: searching }) }), selectedSectionId && (_jsx("div", { className: "mt-2", children: _jsx(InChapterDropdown, { toc: toc, currentTocPath: currentTocPath, selectedSectionId: selectedSectionId, onSelect: handleSelectSection }) })), searchQuery.trim().length > 0 && (_jsx("div", { className: "mt-2 max-h-52 overflow-y-auto rounded-lg border border-gray-200 bg-white shadow-sm", children: searching ? (_jsxs("div", { className: "flex items-center gap-2 px-3 py-3 text-xs text-gray-500", children: [_jsx(Loader2, { className: "h-3 w-3 animate-spin" }), "Searching manual..."] })) : searchResults.length > 0 ? (searchResults.map((section) => (_jsxs("button", { type: "button", onClick: () => handleSelectSearchResult(section.id), className: "group block w-full border-b border-gray-50 px-3 py-2.5 text-left transition-colors last:border-b-0 hover:bg-blue-50/50", children: [_jsx("span", { className: "block text-sm font-medium text-gray-900 transition-colors group-hover:text-blue-700", children: section.title || "Untitled" }), section.summary && (_jsx("span", { className: "mt-0.5 line-clamp-2 block text-xs leading-relaxed text-gray-500", children: section.summary }))] }, section.id)))) : (_jsx("div", { className: "px-3 py-3 text-center text-xs text-gray-500", children: "No manual pages matched your search." })) }))] }), _jsx("div", { className: "flex-1 overflow-y-auto p-4 select-text", children: loadingSection ? (_jsx("div", { className: "flex items-center justify-center py-8", children: _jsx(Loader2, { className: "h-5 w-5 animate-spin text-gray-400" }) })) : !selectedSectionId ? (_jsx("div", { children: renderTocTree(toc, handleSelectSection, handleToggleTocSection, collapsedTocSectionIds) })) : currentSection ? (_jsxs("div", { children: [_jsxs("div", { className: "mb-1 flex items-center justify-between", children: [_jsxs("button", { type: "button", onClick: handleGoBack, className: "inline-flex shrink-0 items-center gap-1 rounded px-2 py-1 text-sm text-gray-600 transition-colors hover:bg-gray-100 hover:text-gray-900", "aria-label": backButtonLabel, title: backButtonLabel, children: [_jsx(ArrowLeft, { className: "h-4 w-4" }), _jsx("span", { className: "hidden sm:inline", children: backButtonText })] }), editContext?.user?.isAdministrator && editContext?.loadItem && (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", onClick: async (e) => {
636
1001
  e.preventDefault();
637
1002
  e.stopPropagation();
638
1003
  if (!editContext?.loadItem) {
@@ -640,7 +1005,6 @@ export function ManualBrowser() {
640
1005
  return;
641
1006
  }
642
1007
  try {
643
- // Load the manual section item in the editor
644
1008
  const language = editContext?.currentItemDescriptor?.language ||
645
1009
  editContext?.item?.language ||
646
1010
  "en";
@@ -655,7 +1019,20 @@ export function ManualBrowser() {
655
1019
  catch (error) {
656
1020
  console.error("Failed to load manual section:", error);
657
1021
  }
658
- }, className: "shrink-0 rounded p-1.5 text-gray-500 transition-colors hover:bg-gray-100 hover:text-gray-700", "aria-label": "Edit item", title: "Edit item", children: _jsx(Edit, { className: "h-4 w-4" }) }) }), _jsx(TooltipContent, { children: "Edit item" })] }))] }), currentSection.summary && (_jsx("p", { className: "mb-3 text-sm text-gray-500", children: currentSection.summary })), _jsx("div", { className: "prose prose-sm max-w-none select-text", children: renderMarkdownWithSelectors(currentSection.content || "", parseUiSelectors(currentSection.uiSelectors)) }), currentSection.subsections &&
659
- currentSection.subsections.length > 0 && (_jsxs("div", { className: "mt-6 border-t border-gray-200 pt-4", children: [_jsx("h3", { className: "mb-3 text-sm font-semibold text-gray-700", children: "Subsections" }), _jsx("ul", { className: "space-y-2", children: currentSection.subsections.map((subsection) => (_jsx("li", { children: _jsx("button", { onClick: () => handleSelectSection(subsection.id), className: "text-left text-sm text-blue-600 hover:text-blue-800 hover:underline", children: subsection.title }) }, subsection.id))) })] }))] })) : (_jsx("div", { className: "py-8 text-center text-sm text-gray-500", children: "Select a section to view its content" })) })] }));
1022
+ }, className: "shrink-0 rounded p-1.5 text-gray-500 transition-colors hover:bg-gray-100 hover:text-gray-700", "aria-label": "Edit item", title: "Edit item", children: _jsx(Edit, { className: "h-4 w-4" }) }) }), _jsx(TooltipContent, { children: "Edit item" })] }))] }), _jsxs("h2", { className: "my-2 flex items-center gap-2 text-xl font-bold text-gray-900", children: [currentSection.svgIcon && (_jsx(SvgIcon, { svg: currentSection.svgIcon, size: 24, className: "shrink-0 text-gray-500" })), currentSection.title] }), currentSection.summary &&
1023
+ (() => {
1024
+ const theme = parentTocSection
1025
+ ? getSectionTheme(parentTocSection.title)
1026
+ : getSectionTheme(currentSection.title);
1027
+ return (_jsx("p", { className: cn("my-4 mb-8 border-l-2 pl-3 text-sm text-gray-500 italic", theme.border), children: currentSection.summary }));
1028
+ })(), _jsx("div", { className: "prose prose-sm max-w-none select-text", children: renderMarkdownWithSelectors(currentSection.content || "", parseUiSelectors(currentSection.uiSelectors), manualLinkTargets, handleSelectSection) }), currentSection.subsections &&
1029
+ currentSection.subsections.length > 0 && (_jsxs("div", { className: "mt-8 border-t border-gray-100 pt-4", children: [_jsx("h3", { className: "mb-3 text-[11px] font-bold tracking-widest text-gray-400 uppercase", children: "In this section" }), _jsx("div", { className: "space-y-0.5", children: currentSection.subsections.map((subsection) => {
1030
+ const theme = getSectionTheme(currentSection.title);
1031
+ return (_jsxs("button", { onClick: () => handleSelectSection(subsection.id), className: "group flex w-full items-center gap-2.5 rounded-lg px-3 py-2 text-left text-sm text-gray-600 transition-all hover:bg-gray-50 hover:text-gray-900", children: [_jsx("span", { className: cn("h-1.5 w-1.5 shrink-0 rounded-full transition-transform group-hover:scale-125", theme.accent, "opacity-50 group-hover:opacity-80") }), _jsx("span", { className: "flex-1 truncate font-medium", children: subsection.title }), _jsx(ChevronRight, { className: "h-3.5 w-3.5 shrink-0 text-gray-300 transition-colors group-hover:text-gray-500" })] }, subsection.id));
1032
+ }) })] }))] })) : (_jsx("div", { className: "py-8 text-center text-sm text-gray-500", children: "Select a section to view its content" })) }), selectedSectionId &&
1033
+ currentSection &&
1034
+ (chapterNavigation.previous || chapterNavigation.next) && (_jsx("div", { className: "shrink-0 border-t border-gray-200/60 bg-white px-4 py-3", children: _jsxs("div", { className: "grid grid-cols-2 gap-2", children: [chapterNavigation.previous ? (_jsxs("button", { type: "button", onClick: () => chapterNavigation.previous &&
1035
+ handleSelectSection(chapterNavigation.previous.id), className: "group rounded-lg border border-gray-200 px-3 py-2 text-left transition-all hover:border-blue-200 hover:bg-blue-50/30", children: [_jsxs("span", { className: "mb-0.5 inline-flex items-center gap-1 text-xs font-medium text-gray-400 transition-colors group-hover:text-blue-500", children: [_jsx(ArrowLeft, { className: "h-3 w-3" }), "Previous"] }), _jsx("span", { className: "block truncate text-sm font-medium text-gray-700 transition-colors group-hover:text-gray-900", children: chapterNavigation.previous.title })] })) : (_jsx("div", {})), chapterNavigation.next ? (_jsxs("button", { type: "button", onClick: () => chapterNavigation.next &&
1036
+ handleSelectSection(chapterNavigation.next.id), className: "group rounded-lg border border-gray-200 px-3 py-2 text-right transition-all hover:border-blue-200 hover:bg-blue-50/30", children: [_jsxs("span", { className: "mb-0.5 inline-flex items-center justify-end gap-1 text-xs font-medium text-gray-400 transition-colors group-hover:text-blue-500", children: ["Next", _jsx(ArrowRight, { className: "h-3 w-3" })] }), _jsx("span", { className: "block truncate text-sm font-medium text-gray-700 transition-colors group-hover:text-gray-900", children: chapterNavigation.next.title })] })) : (_jsx("div", {}))] }) }))] }));
660
1037
  }
661
1038
  //# sourceMappingURL=ManualBrowser.js.map