@alpaca-editor/core 1.0.4112 → 1.0.4118

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 (289) hide show
  1. package/dist/components/FilterInput.js +3 -7
  2. package/dist/components/FilterInput.js.map +1 -1
  3. package/dist/components/ui/context-menu.js +3 -0
  4. package/dist/components/ui/context-menu.js.map +1 -1
  5. package/dist/components/ui/input.js +1 -1
  6. package/dist/components/ui/input.js.map +1 -1
  7. package/dist/config/config.js +3 -3
  8. package/dist/config/config.js.map +1 -1
  9. package/dist/editor/AspectRatioSelector.js +3 -3
  10. package/dist/editor/AspectRatioSelector.js.map +1 -1
  11. package/dist/editor/EditorWarning.js +2 -2
  12. package/dist/editor/EditorWarning.js.map +1 -1
  13. package/dist/editor/FieldEditorPopup.js +7 -6
  14. package/dist/editor/FieldEditorPopup.js.map +1 -1
  15. package/dist/editor/FieldHistory.js +2 -1
  16. package/dist/editor/FieldHistory.js.map +1 -1
  17. package/dist/editor/LinkEditorDialog.d.ts +3 -1
  18. package/dist/editor/LinkEditorDialog.js +7 -3
  19. package/dist/editor/LinkEditorDialog.js.map +1 -1
  20. package/dist/editor/MainLayout.js +3 -3
  21. package/dist/editor/MainLayout.js.map +1 -1
  22. package/dist/editor/PictureCropper.js +3 -3
  23. package/dist/editor/PictureCropper.js.map +1 -1
  24. package/dist/editor/PictureEditorDialog.js +55 -50
  25. package/dist/editor/PictureEditorDialog.js.map +1 -1
  26. package/dist/editor/Terminal.js +4 -4
  27. package/dist/editor/Terminal.js.map +1 -1
  28. package/dist/editor/ai/AgentTerminal.js +137 -6
  29. package/dist/editor/ai/AgentTerminal.js.map +1 -1
  30. package/dist/editor/ai/Agents.js +2 -2
  31. package/dist/editor/ai/Agents.js.map +1 -1
  32. package/dist/editor/ai/ContextInfoBar.js +1 -1
  33. package/dist/editor/ai/ContextInfoBar.js.map +1 -1
  34. package/dist/editor/client/EditorShell.js +2 -0
  35. package/dist/editor/client/EditorShell.js.map +1 -1
  36. package/dist/editor/client/GenericDialog.js +3 -3
  37. package/dist/editor/client/GenericDialog.js.map +1 -1
  38. package/dist/editor/client/hooks/useGlobalEditorKeyDown.d.ts +1 -0
  39. package/dist/editor/client/hooks/useGlobalEditorKeyDown.js +12 -0
  40. package/dist/editor/client/hooks/useGlobalEditorKeyDown.js.map +1 -0
  41. package/dist/editor/client/ui/EditorChrome.js +8 -2
  42. package/dist/editor/client/ui/EditorChrome.js.map +1 -1
  43. package/dist/editor/commands/localizeItem/LocalizeItemDialog.js +9 -7
  44. package/dist/editor/commands/localizeItem/LocalizeItemDialog.js.map +1 -1
  45. package/dist/editor/context-menu/CopyMoveMenu.js +3 -3
  46. package/dist/editor/context-menu/CopyMoveMenu.js.map +1 -1
  47. package/dist/editor/control-center/IndexOverview.js +39 -17
  48. package/dist/editor/control-center/IndexOverview.js.map +1 -1
  49. package/dist/editor/field-types/CheckboxEditor.js +2 -2
  50. package/dist/editor/field-types/CheckboxEditor.js.map +1 -1
  51. package/dist/editor/field-types/DateFieldEditor.js +2 -2
  52. package/dist/editor/field-types/DateFieldEditor.js.map +1 -1
  53. package/dist/editor/field-types/DateTimeFieldEditor.js.map +1 -1
  54. package/dist/editor/field-types/ImageFieldEditor.js +2 -2
  55. package/dist/editor/field-types/ImageFieldEditor.js.map +1 -1
  56. package/dist/editor/field-types/InternalLinkFieldEditor.js +2 -2
  57. package/dist/editor/field-types/InternalLinkFieldEditor.js.map +1 -1
  58. package/dist/editor/field-types/LinkFieldEditor.js +8 -3
  59. package/dist/editor/field-types/LinkFieldEditor.js.map +1 -1
  60. package/dist/editor/field-types/MultiLineText.js +2 -2
  61. package/dist/editor/field-types/MultiLineText.js.map +1 -1
  62. package/dist/editor/field-types/PictureFieldEditor.js +3 -2
  63. package/dist/editor/field-types/PictureFieldEditor.js.map +1 -1
  64. package/dist/editor/field-types/RawEditor.js +2 -2
  65. package/dist/editor/field-types/RawEditor.js.map +1 -1
  66. package/dist/editor/field-types/SingleLineText.js +2 -2
  67. package/dist/editor/field-types/SingleLineText.js.map +1 -1
  68. package/dist/editor/field-types/richtext/components/ReactSlate.js +2 -2
  69. package/dist/editor/field-types/richtext/components/ReactSlate.js.map +1 -1
  70. package/dist/editor/field-types/richtext/components/SimpleRichTextEditor.js +2 -2
  71. package/dist/editor/field-types/richtext/components/SimpleRichTextEditor.js.map +1 -1
  72. package/dist/editor/fieldTypes.d.ts +1 -0
  73. package/dist/editor/media-selector/AiImageSearch.js +5 -4
  74. package/dist/editor/media-selector/AiImageSearch.js.map +1 -1
  75. package/dist/editor/media-selector/MediaFolderBrowser.js +8 -8
  76. package/dist/editor/media-selector/MediaFolderBrowser.js.map +1 -1
  77. package/dist/editor/media-selector/Thumbnails.js +2 -2
  78. package/dist/editor/media-selector/Thumbnails.js.map +1 -1
  79. package/dist/editor/media-selector/TreeSelector.js +2 -2
  80. package/dist/editor/media-selector/TreeSelector.js.map +1 -1
  81. package/dist/editor/media-selector/UploadZone.js +2 -2
  82. package/dist/editor/media-selector/UploadZone.js.map +1 -1
  83. package/dist/editor/menubar/NavButtons.js +3 -5
  84. package/dist/editor/menubar/NavButtons.js.map +1 -1
  85. package/dist/editor/menubar/Separator.js +2 -2
  86. package/dist/editor/menubar/Separator.js.map +1 -1
  87. package/dist/editor/menubar/SiteInfo.js +9 -9
  88. package/dist/editor/menubar/SiteInfo.js.map +1 -1
  89. package/dist/editor/page-editor-chrome/CommentHighlighting.js +2 -2
  90. package/dist/editor/page-editor-chrome/CommentHighlighting.js.map +1 -1
  91. package/dist/editor/page-editor-chrome/FieldActionIndicator.js +2 -2
  92. package/dist/editor/page-editor-chrome/FieldActionIndicator.js.map +1 -1
  93. package/dist/editor/page-editor-chrome/PlaceholderDropZone.js +6 -1
  94. package/dist/editor/page-editor-chrome/PlaceholderDropZone.js.map +1 -1
  95. package/dist/editor/page-editor-chrome/SuggestionHighlighting.js +2 -2
  96. package/dist/editor/page-editor-chrome/SuggestionHighlighting.js.map +1 -1
  97. package/dist/editor/page-viewer/DeviceToolbar.js +3 -3
  98. package/dist/editor/page-viewer/DeviceToolbar.js.map +1 -1
  99. package/dist/editor/reviews/CommentView.js +5 -3
  100. package/dist/editor/reviews/CommentView.js.map +1 -1
  101. package/dist/editor/reviews/Reviews.js +55 -54
  102. package/dist/editor/reviews/Reviews.js.map +1 -1
  103. package/dist/editor/services/agentService.d.ts +3 -3
  104. package/dist/editor/services/agentService.js.map +1 -1
  105. package/dist/editor/services/aiService.js +5 -5
  106. package/dist/editor/services/aiService.js.map +1 -1
  107. package/dist/editor/sidebar/ComponentPalette.js +3 -3
  108. package/dist/editor/sidebar/ComponentPalette.js.map +1 -1
  109. package/dist/editor/sidebar/ComponentTree.js +6 -1
  110. package/dist/editor/sidebar/ComponentTree.js.map +1 -1
  111. package/dist/editor/sidebar/DictionaryEditor.js +9 -9
  112. package/dist/editor/sidebar/DictionaryEditor.js.map +1 -1
  113. package/dist/editor/sidebar/EditHistory.js +4 -3
  114. package/dist/editor/sidebar/EditHistory.js.map +1 -1
  115. package/dist/editor/sidebar/SEOInfo.js +3 -2
  116. package/dist/editor/sidebar/SEOInfo.js.map +1 -1
  117. package/dist/editor/sidebar/SidebarView.js +13 -8
  118. package/dist/editor/sidebar/SidebarView.js.map +1 -1
  119. package/dist/editor/sidebar/Translations.js +5 -2
  120. package/dist/editor/sidebar/Translations.js.map +1 -1
  121. package/dist/editor/sidebar/Validation.js +2 -2
  122. package/dist/editor/sidebar/Validation.js.map +1 -1
  123. package/dist/editor/sidebar/ViewSelector.js +22 -5
  124. package/dist/editor/sidebar/ViewSelector.js.map +1 -1
  125. package/dist/editor/sidebar/Workbox.js +14 -13
  126. package/dist/editor/sidebar/Workbox.js.map +1 -1
  127. package/dist/editor/ui/ItemNameDialogNew.js +2 -2
  128. package/dist/editor/ui/ItemNameDialogNew.js.map +1 -1
  129. package/dist/editor/ui/PerfectTree.js +2 -2
  130. package/dist/editor/ui/PerfectTree.js.map +1 -1
  131. package/dist/editor/ui/Section.js +3 -3
  132. package/dist/editor/ui/Section.js.map +1 -1
  133. package/dist/editor/ui/SimpleTable.js +3 -3
  134. package/dist/editor/ui/SimpleTable.js.map +1 -1
  135. package/dist/editor/utils/keyboardNavigation.js +1 -0
  136. package/dist/editor/utils/keyboardNavigation.js.map +1 -1
  137. package/dist/editor/views/ItemEditor.js +1 -1
  138. package/dist/editor/views/ItemEditor.js.map +1 -1
  139. package/dist/index.d.ts +1 -0
  140. package/dist/index.js +1 -0
  141. package/dist/index.js.map +1 -1
  142. package/dist/page-wizard/WizardSteps.js +2 -3
  143. package/dist/page-wizard/WizardSteps.js.map +1 -1
  144. package/dist/page-wizard/steps/CollectStep.js +2 -2
  145. package/dist/page-wizard/steps/CollectStep.js.map +1 -1
  146. package/dist/page-wizard/steps/ContentStep.js +3 -4
  147. package/dist/page-wizard/steps/ContentStep.js.map +1 -1
  148. package/dist/page-wizard/steps/Generate.js +2 -2
  149. package/dist/page-wizard/steps/Generate.js.map +1 -1
  150. package/dist/page-wizard/steps/ImagesStep.js +17 -15
  151. package/dist/page-wizard/steps/ImagesStep.js.map +1 -1
  152. package/dist/page-wizard/steps/MetaDataStep.js +2 -2
  153. package/dist/page-wizard/steps/MetaDataStep.js.map +1 -1
  154. package/dist/page-wizard/steps/SelectStep.js +5 -5
  155. package/dist/page-wizard/steps/SelectStep.js.map +1 -1
  156. package/dist/page-wizard/steps/StructureStep.js +3 -3
  157. package/dist/page-wizard/steps/StructureStep.js.map +1 -1
  158. package/dist/page-wizard/steps/TranslateStep.js +2 -2
  159. package/dist/page-wizard/steps/TranslateStep.js.map +1 -1
  160. package/dist/revision.d.ts +2 -2
  161. package/dist/revision.js +2 -2
  162. package/dist/splash-screen/NewPage.js +2 -2
  163. package/dist/splash-screen/NewPage.js.map +1 -1
  164. package/dist/splash-screen/SectionHeadline.js +2 -2
  165. package/dist/splash-screen/SectionHeadline.js.map +1 -1
  166. package/dist/styles.css +9 -26
  167. package/package.json +1 -1
  168. package/src/components/FilterInput.tsx +13 -16
  169. package/src/components/ui/context-menu.tsx +3 -0
  170. package/src/components/ui/input.tsx +1 -1
  171. package/src/config/config.tsx +3 -3
  172. package/src/editor/AspectRatioSelector.tsx +3 -3
  173. package/src/editor/EditorWarning.tsx +6 -6
  174. package/src/editor/FieldEditorPopup.tsx +36 -26
  175. package/src/editor/FieldHistory.tsx +2 -1
  176. package/src/editor/LinkEditorDialog.tsx +20 -0
  177. package/src/editor/MainLayout.tsx +3 -3
  178. package/src/editor/PictureCropper.tsx +3 -3
  179. package/src/editor/PictureEditorDialog.tsx +167 -145
  180. package/src/editor/Terminal.tsx +5 -6
  181. package/src/editor/ai/AgentTerminal.tsx +187 -23
  182. package/src/editor/ai/Agents.tsx +2 -2
  183. package/src/editor/ai/ContextInfoBar.tsx +8 -6
  184. package/src/editor/client/EditorShell.tsx +3 -0
  185. package/src/editor/client/GenericDialog.tsx +13 -9
  186. package/src/editor/client/hooks/useGlobalEditorKeyDown.ts +11 -0
  187. package/src/editor/client/ui/EditorChrome.tsx +8 -4
  188. package/src/editor/commands/localizeItem/LocalizeItemDialog.tsx +30 -11
  189. package/src/editor/context-menu/CopyMoveMenu.tsx +5 -3
  190. package/src/editor/control-center/IndexOverview.tsx +63 -34
  191. package/src/editor/field-types/CheckboxEditor.tsx +2 -2
  192. package/src/editor/field-types/DateFieldEditor.tsx +2 -2
  193. package/src/editor/field-types/DateTimeFieldEditor.tsx +0 -1
  194. package/src/editor/field-types/ImageFieldEditor.tsx +3 -4
  195. package/src/editor/field-types/InternalLinkFieldEditor.tsx +2 -2
  196. package/src/editor/field-types/LinkFieldEditor.tsx +8 -2
  197. package/src/editor/field-types/MultiLineText.tsx +4 -5
  198. package/src/editor/field-types/PictureFieldEditor.tsx +5 -5
  199. package/src/editor/field-types/RawEditor.tsx +4 -5
  200. package/src/editor/field-types/SingleLineText.tsx +4 -6
  201. package/src/editor/field-types/richtext/components/ReactSlate.tsx +2 -2
  202. package/src/editor/field-types/richtext/components/SimpleRichTextEditor.tsx +2 -2
  203. package/src/editor/fieldTypes.ts +1 -0
  204. package/src/editor/media-selector/AiImageSearch.tsx +11 -14
  205. package/src/editor/media-selector/MediaFolderBrowser.tsx +42 -35
  206. package/src/editor/media-selector/Thumbnails.tsx +3 -3
  207. package/src/editor/media-selector/TreeSelector.tsx +2 -2
  208. package/src/editor/media-selector/UploadZone.tsx +2 -2
  209. package/src/editor/menubar/NavButtons.tsx +12 -14
  210. package/src/editor/menubar/Separator.tsx +2 -2
  211. package/src/editor/menubar/SiteInfo.tsx +29 -23
  212. package/src/editor/page-editor-chrome/CommentHighlighting.tsx +2 -2
  213. package/src/editor/page-editor-chrome/FieldActionIndicator.tsx +2 -2
  214. package/src/editor/page-editor-chrome/PlaceholderDropZone.tsx +6 -1
  215. package/src/editor/page-editor-chrome/SuggestionHighlighting.tsx +2 -2
  216. package/src/editor/page-viewer/DeviceToolbar.tsx +4 -3
  217. package/src/editor/reviews/CommentView.tsx +34 -10
  218. package/src/editor/reviews/Reviews.tsx +116 -106
  219. package/src/editor/services/agentService.ts +3 -3
  220. package/src/editor/services/aiService.ts +5 -5
  221. package/src/editor/sidebar/ComponentPalette.tsx +3 -3
  222. package/src/editor/sidebar/ComponentTree.tsx +10 -1
  223. package/src/editor/sidebar/DictionaryEditor.tsx +12 -13
  224. package/src/editor/sidebar/EditHistory.tsx +4 -3
  225. package/src/editor/sidebar/SEOInfo.tsx +9 -7
  226. package/src/editor/sidebar/SidebarView.tsx +16 -9
  227. package/src/editor/sidebar/Translations.tsx +9 -5
  228. package/src/editor/sidebar/Validation.tsx +2 -2
  229. package/src/editor/sidebar/ViewSelector.tsx +32 -6
  230. package/src/editor/sidebar/Workbox.tsx +81 -63
  231. package/src/editor/ui/ItemNameDialogNew.tsx +2 -2
  232. package/src/editor/ui/PerfectTree.tsx +2 -5
  233. package/src/editor/ui/Section.tsx +4 -4
  234. package/src/editor/ui/SimpleTable.tsx +3 -3
  235. package/src/editor/utils/keyboardNavigation.ts +1 -0
  236. package/src/editor/views/ItemEditor.tsx +1 -1
  237. package/src/index.ts +6 -0
  238. package/src/page-wizard/WizardSteps.tsx +2 -3
  239. package/src/page-wizard/steps/CollectStep.tsx +3 -3
  240. package/src/page-wizard/steps/ContentStep.tsx +4 -5
  241. package/src/page-wizard/steps/Generate.tsx +2 -2
  242. package/src/page-wizard/steps/ImagesStep.tsx +43 -24
  243. package/src/page-wizard/steps/MetaDataStep.tsx +5 -5
  244. package/src/page-wizard/steps/SelectStep.tsx +8 -6
  245. package/src/page-wizard/steps/StructureStep.tsx +9 -8
  246. package/src/page-wizard/steps/TranslateStep.tsx +5 -3
  247. package/src/revision.ts +2 -2
  248. package/src/splash-screen/NewPage.tsx +2 -2
  249. package/src/splash-screen/SectionHeadline.tsx +4 -4
  250. package/dist/editor/component-designer/ComponentDesigner.d.ts +0 -1
  251. package/dist/editor/component-designer/ComponentDesigner.js +0 -51
  252. package/dist/editor/component-designer/ComponentDesigner.js.map +0 -1
  253. package/dist/editor/component-designer/ComponentDesignerMenu.d.ts +0 -1
  254. package/dist/editor/component-designer/ComponentDesignerMenu.js +0 -65
  255. package/dist/editor/component-designer/ComponentDesignerMenu.js.map +0 -1
  256. package/dist/editor/component-designer/ComponentEditor.d.ts +0 -4
  257. package/dist/editor/component-designer/ComponentEditor.js +0 -55
  258. package/dist/editor/component-designer/ComponentEditor.js.map +0 -1
  259. package/dist/editor/component-designer/ComponentRenderingCodeEditor.d.ts +0 -5
  260. package/dist/editor/component-designer/ComponentRenderingCodeEditor.js +0 -11
  261. package/dist/editor/component-designer/ComponentRenderingCodeEditor.js.map +0 -1
  262. package/dist/editor/component-designer/ComponentRenderingEditor.d.ts +0 -1
  263. package/dist/editor/component-designer/ComponentRenderingEditor.js +0 -69
  264. package/dist/editor/component-designer/ComponentRenderingEditor.js.map +0 -1
  265. package/dist/editor/component-designer/ComponentsDropdown.d.ts +0 -4
  266. package/dist/editor/component-designer/ComponentsDropdown.js +0 -20
  267. package/dist/editor/component-designer/ComponentsDropdown.js.map +0 -1
  268. package/dist/editor/component-designer/PlaceholdersEditor.d.ts +0 -4
  269. package/dist/editor/component-designer/PlaceholdersEditor.js +0 -63
  270. package/dist/editor/component-designer/PlaceholdersEditor.js.map +0 -1
  271. package/dist/editor/component-designer/RenderingsDropdown.d.ts +0 -1
  272. package/dist/editor/component-designer/RenderingsDropdown.js +0 -23
  273. package/dist/editor/component-designer/RenderingsDropdown.js.map +0 -1
  274. package/dist/editor/component-designer/TemplateEditor.d.ts +0 -1
  275. package/dist/editor/component-designer/TemplateEditor.js +0 -142
  276. package/dist/editor/component-designer/TemplateEditor.js.map +0 -1
  277. package/dist/editor/component-designer/aiContext.d.ts +0 -5
  278. package/dist/editor/component-designer/aiContext.js +0 -14
  279. package/dist/editor/component-designer/aiContext.js.map +0 -1
  280. package/src/editor/component-designer/ComponentDesigner.tsx +0 -66
  281. package/src/editor/component-designer/ComponentDesignerMenu.tsx +0 -91
  282. package/src/editor/component-designer/ComponentEditor.tsx +0 -95
  283. package/src/editor/component-designer/ComponentRenderingCodeEditor.tsx +0 -31
  284. package/src/editor/component-designer/ComponentRenderingEditor.tsx +0 -104
  285. package/src/editor/component-designer/ComponentsDropdown.tsx +0 -39
  286. package/src/editor/component-designer/PlaceholdersEditor.tsx +0 -179
  287. package/src/editor/component-designer/RenderingsDropdown.tsx +0 -36
  288. package/src/editor/component-designer/TemplateEditor.tsx +0 -236
  289. package/src/editor/component-designer/aiContext.ts +0 -21
@@ -5,7 +5,16 @@ import React, {
5
5
  useCallback,
6
6
  useLayoutEffect,
7
7
  } from "react";
8
- import { Send, AlertCircle, Loader2, User, Wand2, Square } from "lucide-react";
8
+ import {
9
+ Send,
10
+ AlertCircle,
11
+ Loader2,
12
+ User,
13
+ Wand2,
14
+ Square,
15
+ Mic,
16
+ MicOff,
17
+ } from "lucide-react";
9
18
  import { DancingDots } from "./DancingDots";
10
19
  import {
11
20
  AgentChatMessage,
@@ -197,6 +206,12 @@ export function AgentTerminal({
197
206
  const [agentMetadata, setAgentMetadata] = useState<AgentMetadata | null>(
198
207
  null,
199
208
  );
209
+ // Voice input state
210
+ const [isVoiceSupported, setIsVoiceSupported] = useState(false);
211
+ const [isListening, setIsListening] = useState(false);
212
+ const recognitionRef = useRef<any>(null);
213
+ const prevPlaceholderRef = useRef<string | null>(null);
214
+ const [voiceError, setVoiceError] = useState<string | null>(null);
200
215
  const [isWaitingForResponse, setIsWaitingForResponse] = useState(false);
201
216
  const isWaitingRef = useRef<boolean>(false);
202
217
  useEffect(() => {
@@ -256,7 +271,8 @@ export function AgentTerminal({
256
271
  const [selectedModelId, setSelectedModelId] = useState<string | undefined>(
257
272
  undefined,
258
273
  );
259
- const [mode, setMode] = useState<"agent" | "ask">("agent");
274
+ type AgentMode = "agent" | "ask" | "restricted";
275
+ const [mode, setMode] = useState<AgentMode>("restricted");
260
276
 
261
277
  // Read deterministic flags from query string once
262
278
  const deterministicFlags = React.useMemo(() => {
@@ -337,6 +353,120 @@ export function AgentTerminal({
337
353
  container.scrollTop = container.scrollHeight;
338
354
  }, []);
339
355
 
356
+ // Detect speech recognition support (client-only)
357
+ useEffect(() => {
358
+ try {
359
+ if (typeof window === "undefined") return;
360
+ const SR =
361
+ (window as any).SpeechRecognition ||
362
+ (window as any).webkitSpeechRecognition;
363
+ setIsVoiceSupported(!!SR);
364
+ } catch {
365
+ setIsVoiceSupported(false);
366
+ }
367
+ }, []);
368
+
369
+ // Start voice recognition
370
+ const startVoice = useCallback(() => {
371
+ try {
372
+ if (isListening) return;
373
+ if (typeof window === "undefined") return;
374
+ const SR: any =
375
+ (window as any).SpeechRecognition ||
376
+ (window as any).webkitSpeechRecognition;
377
+ if (!SR) {
378
+ setVoiceError("Voice input is not supported in this browser");
379
+ return;
380
+ }
381
+ const r = new SR();
382
+ r.lang = (editContext?.currentItemDescriptor?.language as any) || "en-US";
383
+ r.continuous = true;
384
+ r.interimResults = true;
385
+ r.onstart = () => {
386
+ setIsListening(true);
387
+ prevPlaceholderRef.current = inputPlaceholder;
388
+ setVoiceError(null);
389
+ setInputPlaceholder("Listening...");
390
+ };
391
+ r.onresult = (event: any) => {
392
+ let finalText = "";
393
+ let interimText = "";
394
+ for (let i = event.resultIndex; i < event.results.length; i++) {
395
+ const res = event.results[i];
396
+ if (res.isFinal) finalText += res[0]?.transcript || "";
397
+ else interimText += res[0]?.transcript || "";
398
+ }
399
+ if (interimText) {
400
+ setInputPlaceholder(`Listening... ${interimText.trim()}`);
401
+ } else {
402
+ setInputPlaceholder("Listening...");
403
+ }
404
+ if (finalText && finalText.trim()) {
405
+ setPrompt((prev) => {
406
+ const prefix = prev && !prev.endsWith(" ") ? prev + " " : prev;
407
+ return (prefix || "") + finalText.trim() + " ";
408
+ });
409
+ if (textareaRef.current) {
410
+ try {
411
+ const v = textareaRef.current.value || "";
412
+ textareaRef.current.selectionStart = v.length;
413
+ textareaRef.current.selectionEnd = v.length;
414
+ } catch {}
415
+ }
416
+ }
417
+ };
418
+ r.onerror = (e: any) => {
419
+ console.warn("Speech recognition error", e);
420
+ setVoiceError(e?.error || "Voice input error");
421
+ };
422
+ r.onend = () => {
423
+ setIsListening(false);
424
+ if (prevPlaceholderRef.current !== null) {
425
+ setInputPlaceholder(prevPlaceholderRef.current);
426
+ prevPlaceholderRef.current = null;
427
+ }
428
+ recognitionRef.current = null;
429
+ };
430
+ recognitionRef.current = r;
431
+ r.start();
432
+ } catch (e) {
433
+ console.error("Failed to start voice input", e);
434
+ setVoiceError("Failed to start voice input");
435
+ }
436
+ }, [
437
+ editContext?.currentItemDescriptor?.language,
438
+ inputPlaceholder,
439
+ isListening,
440
+ ]);
441
+
442
+ const stopVoice = useCallback(() => {
443
+ try {
444
+ const r = recognitionRef.current;
445
+ if (r) r.stop();
446
+ } catch {}
447
+ }, []);
448
+
449
+ const toggleVoice = useCallback(() => {
450
+ if (isListening) stopVoice();
451
+ else startVoice();
452
+ }, [isListening, startVoice, stopVoice]);
453
+
454
+ // Cleanup any active recognition on unmount
455
+ useEffect(() => {
456
+ return () => {
457
+ try {
458
+ const r = recognitionRef.current;
459
+ if (r) {
460
+ r.onresult = null;
461
+ r.onerror = null;
462
+ r.onend = null;
463
+ r.stop();
464
+ }
465
+ } catch {}
466
+ recognitionRef.current = null;
467
+ };
468
+ }, []);
469
+
340
470
  // Check if user is at the bottom of the scroll container
341
471
  const isAtBottom = useCallback(() => {
342
472
  const container = messagesContainerRef.current;
@@ -1240,22 +1370,31 @@ export function AgentTerminal({
1240
1370
  const metaMode = (agentMetadata as any)?.mode as
1241
1371
  | "agent"
1242
1372
  | "ask"
1373
+ | "restricted"
1243
1374
  | undefined;
1244
- if (metaMode === "agent" || metaMode === "ask") {
1375
+ if (
1376
+ metaMode === "agent" ||
1377
+ metaMode === "ask" ||
1378
+ metaMode === "restricted"
1379
+ ) {
1245
1380
  setMode(metaMode);
1246
1381
  return;
1247
1382
  }
1248
1383
  } catch {}
1249
1384
  try {
1250
1385
  const serverMode = (agent as any)?.mode as string | undefined;
1251
- if (serverMode === "agent" || serverMode === "ask") {
1386
+ if (
1387
+ serverMode === "agent" ||
1388
+ serverMode === "ask" ||
1389
+ serverMode === "restricted"
1390
+ ) {
1252
1391
  setMode(serverMode);
1253
1392
  }
1254
1393
  } catch {}
1255
1394
  }, [agentMetadata, (agent as any)?.mode]);
1256
1395
 
1257
1396
  const updateMode = useCallback(
1258
- async (nextMode: "agent" | "ask") => {
1397
+ async (nextMode: AgentMode) => {
1259
1398
  setMode(nextMode);
1260
1399
  const current = agentMetadata || ({} as AgentMetadata);
1261
1400
  const nextMeta: AgentMetadata = {
@@ -1305,7 +1444,7 @@ export function AgentTerminal({
1305
1444
  if (!pending) return;
1306
1445
  const payload: {
1307
1446
  model?: string | null;
1308
- mode?: "agent" | "ask" | string | null;
1447
+ mode?: AgentMode | string | null;
1309
1448
  } = {};
1310
1449
  if (pending.modelName) payload.model = pending.modelName;
1311
1450
  if (pending.mode) payload.mode = pending.mode;
@@ -1393,7 +1532,7 @@ export function AgentTerminal({
1393
1532
  version: editContext.currentItemDescriptor?.version || 1,
1394
1533
  selection: effectiveSelection,
1395
1534
  selectedText: selectedTextFromCtx,
1396
- mode: mode,
1535
+ mode: mode as any,
1397
1536
  allowedFunctions:
1398
1537
  mode === "ask"
1399
1538
  ? activeProfile?.askModeTools &&
@@ -1572,7 +1711,7 @@ export function AgentTerminal({
1572
1711
  version: editContext.currentItemDescriptor?.version || 1,
1573
1712
  selection: effectiveSelection,
1574
1713
  selectedText: selectedTextFromCtx,
1575
- mode: mode,
1714
+ mode: mode as any,
1576
1715
  allowedFunctions:
1577
1716
  mode === "ask"
1578
1717
  ? activeProfile?.askModeTools &&
@@ -2369,6 +2508,7 @@ export function AgentTerminal({
2369
2508
  aria-label="Mode"
2370
2509
  data-testid="agent-mode-select"
2371
2510
  >
2511
+ <option value="restricted">Restricted</option>
2372
2512
  <option value="agent">Agent</option>
2373
2513
  <option value="ask">Ask</option>
2374
2514
  </select>
@@ -2461,22 +2601,46 @@ export function AgentTerminal({
2461
2601
  </PopoverContent>
2462
2602
  </Popover>
2463
2603
  ) : null}
2464
- <AgentCostDisplay totalTokens={totalTokens} />
2465
2604
  </div>
2466
- <Button
2467
- onClick={isExecuting ? handleStop : handleSubmit}
2468
- disabled={!isExecuting && !prompt.trim()}
2469
- size="sm"
2470
- className="h-5.5 w-5.5 cursor-pointer self-end rounded-full"
2471
- title={isExecuting ? "Stop" : "Send"}
2472
- aria-label={isExecuting ? "Stop" : "Send"}
2473
- >
2474
- {isExecuting ? (
2475
- <Square className="size-3" strokeWidth={1} />
2476
- ) : (
2477
- <Send className="size-3" strokeWidth={1} />
2478
- )}
2479
- </Button>
2605
+ <div className="flex items-center gap-1 self-end">
2606
+ {isVoiceSupported ? (
2607
+ <Button
2608
+ onClick={toggleVoice}
2609
+ size="sm"
2610
+ className="h-5.5 w-5.5 cursor-pointer rounded-full"
2611
+ title={isListening ? "Stop voice input" : "Start voice input"}
2612
+ aria-label={
2613
+ isListening ? "Stop voice input" : "Start voice input"
2614
+ }
2615
+ aria-pressed={isListening}
2616
+ >
2617
+ {isListening ? (
2618
+ <MicOff className="size-3" strokeWidth={1} />
2619
+ ) : (
2620
+ <Mic className="size-3" strokeWidth={1} />
2621
+ )}
2622
+ </Button>
2623
+ ) : null}
2624
+ <Button
2625
+ onClick={isExecuting ? handleStop : handleSubmit}
2626
+ disabled={!isExecuting && !prompt.trim()}
2627
+ size="sm"
2628
+ className="h-5.5 w-5.5 cursor-pointer rounded-full"
2629
+ title={isExecuting ? "Stop" : "Send"}
2630
+ aria-label={isExecuting ? "Stop" : "Send"}
2631
+ data-testid="agent-send-stop-button"
2632
+ data-executing={isExecuting ? "true" : "false"}
2633
+ >
2634
+ {isExecuting ? (
2635
+ <Square className="size-3" strokeWidth={1} />
2636
+ ) : (
2637
+ <Send className="size-3" strokeWidth={1} />
2638
+ )}
2639
+ </Button>
2640
+ </div>
2641
+ </div>
2642
+ <div className="mt-1 flex justify-start">
2643
+ <AgentCostDisplay totalTokens={totalTokens} />
2480
2644
  </div>
2481
2645
  </div>
2482
2646
  </div>
@@ -545,7 +545,7 @@ export function Agents({ closeButton }: { closeButton?: React.ReactNode }) {
545
545
  <div
546
546
  key={agent.id}
547
547
  className={cn(
548
- "flex min-w-0 cursor-pointer items-center gap-1 border-r border-gray-200 px-3 py-2 text-xs",
548
+ "flex min-w-0 cursor-pointer items-center gap-1 border-r border-gray-200 px-2 py-2 pr-1.5 text-xs",
549
549
  activeAgentId === agent.id
550
550
  ? "border-b-white bg-white"
551
551
  : "hover:bg-gray-100",
@@ -594,7 +594,7 @@ export function Agents({ closeButton }: { closeButton?: React.ReactNode }) {
594
594
  e.stopPropagation();
595
595
  closeAgent(agent.id);
596
596
  }}
597
- icon={<X className="size-2" strokeWidth={1} />}
597
+ icon={<X className="size-3" strokeWidth={1} />}
598
598
  label="Close"
599
599
  className="ml-1 opacity-60 hover:opacity-100"
600
600
  />
@@ -537,9 +537,11 @@ export function ContextInfoBar({
537
537
  />
538
538
  </div>
539
539
  {!isCollapsed && (
540
- <div className="flex items-center justify-between text-xs text-gray-600">
541
- <div className="flex flex-wrap items-center gap-2">{chips}</div>
542
- <div className="ml-2 flex flex-col items-end gap-1">
540
+ <div className="flex flex-col gap-2">
541
+ <div className="flex items-center justify-between text-xs text-gray-600">
542
+ <div className="flex flex-wrap items-center gap-2">{chips}</div>
543
+ </div>
544
+ <div className="flex flex-col items-start gap-1">
543
545
  {canAddPage && (
544
546
  <Button size="xs" variant="outline" onClick={addPagesToContext}>
545
547
  <Plus className="mr-1 h-3 w-3" strokeWidth={1} /> Add current
@@ -556,9 +558,9 @@ export function ContextInfoBar({
556
558
  components
557
559
  </Button>
558
560
  )}
559
- <div className="text-2xs text-gray-400">
560
- Tip: Drag items or components here to add them
561
- </div>
561
+ </div>
562
+ <div className="text-2xs text-gray-400">
563
+ Tip: Drag items or components here to add them
562
564
  </div>
563
565
  </div>
564
566
  )}
@@ -142,6 +142,7 @@ import { FullscreenControls } from "./ui/FullscreenControls";
142
142
  import { EditorChrome } from "./ui/EditorChrome";
143
143
  import { useWorkbox } from "./hooks/useWorkbox";
144
144
  import { useMediaSelector } from "./hooks/useMediaSelector";
145
+ import { useGlobalEditorKeyDown } from "./hooks/useGlobalEditorKeyDown";
145
146
 
146
147
  export type FieldAction = {
147
148
  field: FieldDescriptor;
@@ -1525,6 +1526,8 @@ export function EditorShell({
1525
1526
  executeCommand,
1526
1527
  });
1527
1528
 
1529
+ useGlobalEditorKeyDown(handleKeyDown);
1530
+
1528
1531
  useEffect(() => {
1529
1532
  const handleGlobalBlur = () => {
1530
1533
  operations.onFieldBlur?.();
@@ -1,5 +1,9 @@
1
- import { Dialog } from "primereact/dialog";
2
-
1
+ import {
2
+ Dialog,
3
+ DialogContent,
4
+ DialogHeader,
5
+ DialogTitle,
6
+ } from "../../components/ui/dialog";
3
7
  import { forwardRef, useImperativeHandle, useState } from "react";
4
8
 
5
9
  export interface GenericDialogHandle {
@@ -38,13 +42,13 @@ export const GenericDialog = forwardRef<GenericDialogHandle>((_, ref) => {
38
42
  }));
39
43
 
40
44
  return (
41
- <Dialog
42
- onHide={() => setVisible(false)}
43
- visible={visible}
44
- header={title}
45
- style={{ width, height }}
46
- >
47
- {content}
45
+ <Dialog open={visible} onOpenChange={(open) => !open && setVisible(false)}>
46
+ <DialogContent className="max-w-none" style={{ width, height }}>
47
+ <DialogHeader>
48
+ <DialogTitle>{title}</DialogTitle>
49
+ </DialogHeader>
50
+ <div className="flex-1 overflow-auto p-6">{content}</div>
51
+ </DialogContent>
48
52
  </Dialog>
49
53
  );
50
54
  });
@@ -0,0 +1,11 @@
1
+ import { useEffect } from "react";
2
+
3
+ export function useGlobalEditorKeyDown(onKeyDown: (ev: KeyboardEvent) => void) {
4
+ useEffect(() => {
5
+ if (typeof window === "undefined") return;
6
+ window.addEventListener("keydown", onKeyDown, true);
7
+ return () => {
8
+ window.removeEventListener("keydown", onKeyDown, true);
9
+ };
10
+ }, [onKeyDown]);
11
+ }
@@ -34,7 +34,7 @@ export function EditorChrome(props: {
34
34
  centerPanelView={centerPanelView}
35
35
  rightSidebar={
36
36
  currentView.rightSidebar &&
37
- editContext.page &&
37
+ (editContext.page || editContext.contentEditorItem?.hasLayout) &&
38
38
  showComponentNavigator && (
39
39
  <SidebarView
40
40
  sidebar={currentView.rightSidebar}
@@ -49,9 +49,13 @@ export function EditorChrome(props: {
49
49
  farRightSidebar={
50
50
  showAgentsPanel &&
51
51
  !editContext.currentWizardId &&
52
- !["splash-screen", "open-page", "new-page", "page-wizard", "control-center"].includes(
53
- viewName,
54
- ) && (
52
+ ![
53
+ "splash-screen",
54
+ "open-page",
55
+ "new-page",
56
+ "page-wizard",
57
+ "control-center",
58
+ ].includes(viewName) && (
55
59
  <SidebarView
56
60
  sidebar={{
57
61
  title: "Agents",
@@ -1,5 +1,10 @@
1
- import { Button } from "primereact/button";
2
- import { Dialog } from "primereact/dialog";
1
+ import { Button } from "../../../components/ui/button";
2
+ import {
3
+ Dialog,
4
+ DialogContent,
5
+ DialogHeader,
6
+ DialogTitle,
7
+ } from "../../../components/ui/dialog";
3
8
  import { useEffect, useState } from "react";
4
9
  import DialogButtons from "../../ui/DialogButtons";
5
10
  import { DialogProps } from "../../client/editContext";
@@ -119,7 +124,9 @@ export function LocalizeItemDialog(
119
124
  </div>
120
125
  )}
121
126
  <DialogButtons>
122
- <Button onClick={() => props.onClose?.(null)} label="Close" />
127
+ <Button onClick={() => props.onClose?.(null)} size="sm">
128
+ Close
129
+ </Button>
123
130
  </DialogButtons>
124
131
  </div>
125
132
  );
@@ -179,8 +186,12 @@ export function LocalizeItemDialog(
179
186
  </div>
180
187
  </div>
181
188
  <DialogButtons>
182
- <Button onClick={startLocalization} label="Start" />
183
- <Button onClick={() => props.onClose?.(null)} label="Cancel" />
189
+ <Button onClick={startLocalization} size="sm">
190
+ Start
191
+ </Button>
192
+ <Button onClick={() => props.onClose?.(null)} size="sm">
193
+ Cancel
194
+ </Button>
184
195
  </DialogButtons>
185
196
  </div>
186
197
  );
@@ -188,14 +199,22 @@ export function LocalizeItemDialog(
188
199
 
189
200
  return (
190
201
  <Dialog
191
- visible={true}
192
- onHide={() => {
193
- props.onClose?.(null);
202
+ open={true}
203
+ onOpenChange={(open) => {
204
+ if (!open) {
205
+ props.onClose?.(null);
206
+ }
194
207
  }}
195
- style={{ width: "75vw", height: "75vh" }}
196
- header="Localize"
197
208
  >
198
- {dialogContent}
209
+ <DialogContent
210
+ className="max-w-none"
211
+ style={{ width: "75vw", height: "75vh" }}
212
+ >
213
+ <DialogHeader>
214
+ <DialogTitle>Localize</DialogTitle>
215
+ </DialogHeader>
216
+ <div className="flex-1 overflow-auto">{dialogContent}</div>
217
+ </DialogContent>
199
218
  </Dialog>
200
219
  );
201
220
  }
@@ -3,7 +3,7 @@ import { useEditContext } from "../client/editContext";
3
3
  import { MoveCopyItemsCommand } from "../commands/itemCommands";
4
4
  import { FullItem, ItemDescriptor } from "../pageModel";
5
5
  import { ScrollingContentTree } from "../ScrollingContentTree";
6
- import { Button } from "primereact/button";
6
+ import { Button } from "../../components/ui/button";
7
7
 
8
8
  export const CopyMoveMenuTemplate = ({
9
9
  items,
@@ -85,7 +85,7 @@ export const CopyMoveMenuTemplate = ({
85
85
  </div>
86
86
  <div className="flex justify-end">
87
87
  <Button
88
- label={mode === "copy" ? "Copy" : "Move"}
88
+ size="sm"
89
89
  onClick={() => {
90
90
  if (!selectedItem) return;
91
91
  const result = editContext?.executeCommand({
@@ -94,7 +94,9 @@ export const CopyMoveMenuTemplate = ({
94
94
  });
95
95
  commandCallback?.(command, result);
96
96
  }}
97
- />
97
+ >
98
+ {mode === "copy" ? "Copy" : "Move"}
99
+ </Button>
98
100
  </div>
99
101
  </div>
100
102
  </div>