jodit-pro 4.12.32 → 4.12.34

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 (333) hide show
  1. package/es2015/jodit.css +1 -1
  2. package/es2015/jodit.fat.min.css +1 -1
  3. package/es2015/jodit.fat.min.js +8 -8
  4. package/es2015/jodit.js +38 -2
  5. package/es2015/jodit.min.js +2 -2
  6. package/es2015/plugins/ai-assistant-pro/ai-assistant-pro.css +34 -1
  7. package/es2015/plugins/ai-assistant-pro/ai-assistant-pro.js +596 -44
  8. package/es2015/plugins/ai-assistant-pro/ai-assistant-pro.min.css +1 -1
  9. package/es2015/plugins/ai-assistant-pro/ai-assistant-pro.min.js +33 -33
  10. package/es2015/plugins/autocomplete/autocomplete.css +1 -1
  11. package/es2015/plugins/autocomplete/autocomplete.js +1 -1
  12. package/es2015/plugins/autocomplete/autocomplete.min.js +1 -1
  13. package/es2015/plugins/backup/backup.css +1 -1
  14. package/es2015/plugins/backup/backup.js +1 -1
  15. package/es2015/plugins/backup/backup.min.js +1 -1
  16. package/es2015/plugins/button-generator/button-generator.css +1 -1
  17. package/es2015/plugins/button-generator/button-generator.js +1 -1
  18. package/es2015/plugins/button-generator/button-generator.min.js +1 -1
  19. package/es2015/plugins/change-case/change-case.js +1 -1
  20. package/es2015/plugins/change-case/change-case.min.js +1 -1
  21. package/es2015/plugins/color-picker/color-picker.css +1 -1
  22. package/es2015/plugins/color-picker/color-picker.js +1 -1
  23. package/es2015/plugins/color-picker/color-picker.min.js +1 -1
  24. package/es2015/plugins/emoji/emoji.css +1 -1
  25. package/es2015/plugins/emoji/emoji.js +1 -1
  26. package/es2015/plugins/emoji/emoji.min.js +1 -1
  27. package/es2015/plugins/export-docs/export-docs.js +1 -1
  28. package/es2015/plugins/export-docs/export-docs.min.js +1 -1
  29. package/es2015/plugins/finder/finder.css +1 -1
  30. package/es2015/plugins/finder/finder.js +1 -1
  31. package/es2015/plugins/finder/finder.min.js +1 -1
  32. package/es2015/plugins/google-maps/google-maps.css +1 -1
  33. package/es2015/plugins/google-maps/google-maps.js +1 -1
  34. package/es2015/plugins/google-maps/google-maps.min.js +1 -1
  35. package/es2015/plugins/google-search/google-search.js +1 -1
  36. package/es2015/plugins/google-search/google-search.min.js +1 -1
  37. package/es2015/plugins/highlight-signature/highlight-signature.js +1 -1
  38. package/es2015/plugins/highlight-signature/highlight-signature.min.js +1 -1
  39. package/es2015/plugins/iframe-editor/iframe-editor.css +1 -1
  40. package/es2015/plugins/iframe-editor/iframe-editor.js +1 -1
  41. package/es2015/plugins/iframe-editor/iframe-editor.min.js +1 -1
  42. package/es2015/plugins/keyboard/keyboard.css +1 -1
  43. package/es2015/plugins/keyboard/keyboard.js +1 -1
  44. package/es2015/plugins/keyboard/keyboard.min.js +1 -1
  45. package/es2015/plugins/mobile-view/mobile-view.js +1 -1
  46. package/es2015/plugins/mobile-view/mobile-view.min.js +1 -1
  47. package/es2015/plugins/page-break/page-break.js +1 -1
  48. package/es2015/plugins/page-break/page-break.min.js +1 -1
  49. package/es2015/plugins/paste-code/paste-code.css +1 -1
  50. package/es2015/plugins/paste-code/paste-code.js +1 -1
  51. package/es2015/plugins/paste-code/paste-code.min.js +1 -1
  52. package/es2015/plugins/paste-from-word/paste-from-word.js +1 -1
  53. package/es2015/plugins/paste-from-word/paste-from-word.min.js +1 -1
  54. package/es2015/plugins/show-blocks/show-blocks.js +1 -1
  55. package/es2015/plugins/show-blocks/show-blocks.min.js +1 -1
  56. package/es2015/plugins/style/style.css +1 -1
  57. package/es2015/plugins/style/style.js +1 -1
  58. package/es2015/plugins/style/style.min.js +1 -1
  59. package/es2015/plugins/templates/templates.css +1 -1
  60. package/es2015/plugins/templates/templates.js +1 -1
  61. package/es2015/plugins/templates/templates.min.js +1 -1
  62. package/es2015/plugins/todo-list/todo-list.css +1 -1
  63. package/es2015/plugins/todo-list/todo-list.js +1 -1
  64. package/es2015/plugins/todo-list/todo-list.min.js +1 -1
  65. package/es2015/plugins/translate/translate.css +1 -1
  66. package/es2015/plugins/translate/translate.js +1 -1
  67. package/es2015/plugins/translate/translate.min.js +1 -1
  68. package/es2015/plugins/tune-block/tune-block.css +1 -1
  69. package/es2015/plugins/tune-block/tune-block.js +1 -1
  70. package/es2015/plugins/tune-block/tune-block.min.js +1 -1
  71. package/es2018/jodit.fat.min.css +1 -1
  72. package/es2018/jodit.fat.min.js +6 -6
  73. package/es2018/jodit.min.js +2 -2
  74. package/es2018/plugins/ai-assistant-pro/ai-assistant-pro.min.css +1 -1
  75. package/es2018/plugins/ai-assistant-pro/ai-assistant-pro.min.js +38 -38
  76. package/es2018/plugins/autocomplete/autocomplete.min.js +1 -1
  77. package/es2018/plugins/backup/backup.min.js +1 -1
  78. package/es2018/plugins/button-generator/button-generator.min.js +1 -1
  79. package/es2018/plugins/change-case/change-case.min.js +1 -1
  80. package/es2018/plugins/color-picker/color-picker.min.js +1 -1
  81. package/es2018/plugins/emoji/emoji.min.js +1 -1
  82. package/es2018/plugins/export-docs/export-docs.min.js +1 -1
  83. package/es2018/plugins/finder/finder.min.js +1 -1
  84. package/es2018/plugins/google-maps/google-maps.min.js +1 -1
  85. package/es2018/plugins/google-search/google-search.min.js +1 -1
  86. package/es2018/plugins/highlight-signature/highlight-signature.min.js +1 -1
  87. package/es2018/plugins/iframe-editor/iframe-editor.min.js +1 -1
  88. package/es2018/plugins/keyboard/keyboard.min.js +1 -1
  89. package/es2018/plugins/mobile-view/mobile-view.min.js +1 -1
  90. package/es2018/plugins/page-break/page-break.min.js +1 -1
  91. package/es2018/plugins/paste-code/paste-code.min.js +1 -1
  92. package/es2018/plugins/paste-from-word/paste-from-word.min.js +1 -1
  93. package/es2018/plugins/show-blocks/show-blocks.min.js +1 -1
  94. package/es2018/plugins/style/style.min.js +1 -1
  95. package/es2018/plugins/templates/templates.min.js +1 -1
  96. package/es2018/plugins/todo-list/todo-list.min.js +1 -1
  97. package/es2018/plugins/translate/translate.min.js +1 -1
  98. package/es2018/plugins/tune-block/tune-block.min.js +1 -1
  99. package/es2021/jodit.css +1 -1
  100. package/es2021/jodit.fat.min.css +1 -1
  101. package/es2021/jodit.fat.min.js +8 -8
  102. package/es2021/jodit.js +38 -2
  103. package/es2021/jodit.min.js +3 -3
  104. package/es2021/plugins/ai-assistant-pro/ai-assistant-pro.css +34 -1
  105. package/es2021/plugins/ai-assistant-pro/ai-assistant-pro.js +569 -42
  106. package/es2021/plugins/ai-assistant-pro/ai-assistant-pro.min.css +1 -1
  107. package/es2021/plugins/ai-assistant-pro/ai-assistant-pro.min.js +9 -9
  108. package/es2021/plugins/autocomplete/autocomplete.css +1 -1
  109. package/es2021/plugins/autocomplete/autocomplete.js +1 -1
  110. package/es2021/plugins/autocomplete/autocomplete.min.js +1 -1
  111. package/es2021/plugins/backup/backup.css +1 -1
  112. package/es2021/plugins/backup/backup.js +1 -1
  113. package/es2021/plugins/backup/backup.min.js +1 -1
  114. package/es2021/plugins/button-generator/button-generator.css +1 -1
  115. package/es2021/plugins/button-generator/button-generator.js +1 -1
  116. package/es2021/plugins/button-generator/button-generator.min.js +1 -1
  117. package/es2021/plugins/change-case/change-case.js +1 -1
  118. package/es2021/plugins/change-case/change-case.min.js +1 -1
  119. package/es2021/plugins/color-picker/color-picker.css +1 -1
  120. package/es2021/plugins/color-picker/color-picker.js +1 -1
  121. package/es2021/plugins/color-picker/color-picker.min.js +1 -1
  122. package/es2021/plugins/emoji/emoji.css +1 -1
  123. package/es2021/plugins/emoji/emoji.js +1 -1
  124. package/es2021/plugins/emoji/emoji.min.js +1 -1
  125. package/es2021/plugins/export-docs/export-docs.js +1 -1
  126. package/es2021/plugins/export-docs/export-docs.min.js +1 -1
  127. package/es2021/plugins/finder/finder.css +1 -1
  128. package/es2021/plugins/finder/finder.js +1 -1
  129. package/es2021/plugins/finder/finder.min.js +1 -1
  130. package/es2021/plugins/google-maps/google-maps.css +1 -1
  131. package/es2021/plugins/google-maps/google-maps.js +1 -1
  132. package/es2021/plugins/google-maps/google-maps.min.js +1 -1
  133. package/es2021/plugins/google-search/google-search.js +1 -1
  134. package/es2021/plugins/google-search/google-search.min.js +1 -1
  135. package/es2021/plugins/highlight-signature/highlight-signature.js +1 -1
  136. package/es2021/plugins/highlight-signature/highlight-signature.min.js +1 -1
  137. package/es2021/plugins/iframe-editor/iframe-editor.css +1 -1
  138. package/es2021/plugins/iframe-editor/iframe-editor.js +1 -1
  139. package/es2021/plugins/iframe-editor/iframe-editor.min.js +1 -1
  140. package/es2021/plugins/keyboard/keyboard.css +1 -1
  141. package/es2021/plugins/keyboard/keyboard.js +1 -1
  142. package/es2021/plugins/keyboard/keyboard.min.js +1 -1
  143. package/es2021/plugins/mobile-view/mobile-view.js +1 -1
  144. package/es2021/plugins/mobile-view/mobile-view.min.js +1 -1
  145. package/es2021/plugins/page-break/page-break.js +1 -1
  146. package/es2021/plugins/page-break/page-break.min.js +1 -1
  147. package/es2021/plugins/paste-code/paste-code.css +1 -1
  148. package/es2021/plugins/paste-code/paste-code.js +1 -1
  149. package/es2021/plugins/paste-code/paste-code.min.js +1 -1
  150. package/es2021/plugins/paste-from-word/paste-from-word.js +1 -1
  151. package/es2021/plugins/paste-from-word/paste-from-word.min.js +1 -1
  152. package/es2021/plugins/show-blocks/show-blocks.js +1 -1
  153. package/es2021/plugins/show-blocks/show-blocks.min.js +1 -1
  154. package/es2021/plugins/style/style.css +1 -1
  155. package/es2021/plugins/style/style.js +1 -1
  156. package/es2021/plugins/style/style.min.js +1 -1
  157. package/es2021/plugins/templates/templates.css +1 -1
  158. package/es2021/plugins/templates/templates.js +1 -1
  159. package/es2021/plugins/templates/templates.min.js +1 -1
  160. package/es2021/plugins/todo-list/todo-list.css +1 -1
  161. package/es2021/plugins/todo-list/todo-list.js +1 -1
  162. package/es2021/plugins/todo-list/todo-list.min.js +1 -1
  163. package/es2021/plugins/translate/translate.css +1 -1
  164. package/es2021/plugins/translate/translate.js +1 -1
  165. package/es2021/plugins/translate/translate.min.js +1 -1
  166. package/es2021/plugins/tune-block/tune-block.css +1 -1
  167. package/es2021/plugins/tune-block/tune-block.js +1 -1
  168. package/es2021/plugins/tune-block/tune-block.min.js +1 -1
  169. package/es2021.en/jodit.css +1 -1
  170. package/es2021.en/jodit.fat.min.css +1 -1
  171. package/es2021.en/jodit.fat.min.js +25 -25
  172. package/es2021.en/jodit.js +38 -2
  173. package/es2021.en/jodit.min.js +3 -3
  174. package/es2021.en/plugins/ai-assistant-pro/ai-assistant-pro.css +34 -1
  175. package/es2021.en/plugins/ai-assistant-pro/ai-assistant-pro.js +569 -42
  176. package/es2021.en/plugins/ai-assistant-pro/ai-assistant-pro.min.css +1 -1
  177. package/es2021.en/plugins/ai-assistant-pro/ai-assistant-pro.min.js +9 -9
  178. package/es2021.en/plugins/autocomplete/autocomplete.css +1 -1
  179. package/es2021.en/plugins/autocomplete/autocomplete.js +1 -1
  180. package/es2021.en/plugins/autocomplete/autocomplete.min.js +1 -1
  181. package/es2021.en/plugins/backup/backup.css +1 -1
  182. package/es2021.en/plugins/backup/backup.js +1 -1
  183. package/es2021.en/plugins/backup/backup.min.js +1 -1
  184. package/es2021.en/plugins/button-generator/button-generator.css +1 -1
  185. package/es2021.en/plugins/button-generator/button-generator.js +1 -1
  186. package/es2021.en/plugins/button-generator/button-generator.min.js +1 -1
  187. package/es2021.en/plugins/change-case/change-case.js +1 -1
  188. package/es2021.en/plugins/change-case/change-case.min.js +1 -1
  189. package/es2021.en/plugins/color-picker/color-picker.css +1 -1
  190. package/es2021.en/plugins/color-picker/color-picker.js +1 -1
  191. package/es2021.en/plugins/color-picker/color-picker.min.js +1 -1
  192. package/es2021.en/plugins/emoji/emoji.css +1 -1
  193. package/es2021.en/plugins/emoji/emoji.js +1 -1
  194. package/es2021.en/plugins/emoji/emoji.min.js +1 -1
  195. package/es2021.en/plugins/export-docs/export-docs.js +1 -1
  196. package/es2021.en/plugins/export-docs/export-docs.min.js +1 -1
  197. package/es2021.en/plugins/finder/finder.css +1 -1
  198. package/es2021.en/plugins/finder/finder.js +1 -1
  199. package/es2021.en/plugins/finder/finder.min.js +1 -1
  200. package/es2021.en/plugins/google-maps/google-maps.css +1 -1
  201. package/es2021.en/plugins/google-maps/google-maps.js +1 -1
  202. package/es2021.en/plugins/google-maps/google-maps.min.js +1 -1
  203. package/es2021.en/plugins/google-search/google-search.js +1 -1
  204. package/es2021.en/plugins/google-search/google-search.min.js +1 -1
  205. package/es2021.en/plugins/highlight-signature/highlight-signature.js +1 -1
  206. package/es2021.en/plugins/highlight-signature/highlight-signature.min.js +1 -1
  207. package/es2021.en/plugins/iframe-editor/iframe-editor.css +1 -1
  208. package/es2021.en/plugins/iframe-editor/iframe-editor.js +1 -1
  209. package/es2021.en/plugins/iframe-editor/iframe-editor.min.js +1 -1
  210. package/es2021.en/plugins/keyboard/keyboard.css +1 -1
  211. package/es2021.en/plugins/keyboard/keyboard.js +1 -1
  212. package/es2021.en/plugins/keyboard/keyboard.min.js +1 -1
  213. package/es2021.en/plugins/mobile-view/mobile-view.js +1 -1
  214. package/es2021.en/plugins/mobile-view/mobile-view.min.js +1 -1
  215. package/es2021.en/plugins/page-break/page-break.js +1 -1
  216. package/es2021.en/plugins/page-break/page-break.min.js +1 -1
  217. package/es2021.en/plugins/paste-code/paste-code.css +1 -1
  218. package/es2021.en/plugins/paste-code/paste-code.js +1 -1
  219. package/es2021.en/plugins/paste-code/paste-code.min.js +1 -1
  220. package/es2021.en/plugins/paste-from-word/paste-from-word.js +1 -1
  221. package/es2021.en/plugins/paste-from-word/paste-from-word.min.js +1 -1
  222. package/es2021.en/plugins/show-blocks/show-blocks.js +1 -1
  223. package/es2021.en/plugins/show-blocks/show-blocks.min.js +1 -1
  224. package/es2021.en/plugins/style/style.css +1 -1
  225. package/es2021.en/plugins/style/style.js +1 -1
  226. package/es2021.en/plugins/style/style.min.js +1 -1
  227. package/es2021.en/plugins/templates/templates.css +1 -1
  228. package/es2021.en/plugins/templates/templates.js +1 -1
  229. package/es2021.en/plugins/templates/templates.min.js +1 -1
  230. package/es2021.en/plugins/todo-list/todo-list.css +1 -1
  231. package/es2021.en/plugins/todo-list/todo-list.js +1 -1
  232. package/es2021.en/plugins/todo-list/todo-list.min.js +1 -1
  233. package/es2021.en/plugins/translate/translate.css +1 -1
  234. package/es2021.en/plugins/translate/translate.js +1 -1
  235. package/es2021.en/plugins/translate/translate.min.js +1 -1
  236. package/es2021.en/plugins/tune-block/tune-block.css +1 -1
  237. package/es2021.en/plugins/tune-block/tune-block.js +1 -1
  238. package/es2021.en/plugins/tune-block/tune-block.min.js +1 -1
  239. package/es5/jodit.css +2 -2
  240. package/es5/jodit.fat.min.css +1 -1
  241. package/es5/jodit.fat.min.js +2 -2
  242. package/es5/jodit.js +38 -2
  243. package/es5/jodit.min.css +2 -2
  244. package/es5/jodit.min.js +2 -2
  245. package/es5/plugins/ai-assistant-pro/ai-assistant-pro.css +34 -1
  246. package/es5/plugins/ai-assistant-pro/ai-assistant-pro.js +734 -44
  247. package/es5/plugins/ai-assistant-pro/ai-assistant-pro.min.css +1 -1
  248. package/es5/plugins/ai-assistant-pro/ai-assistant-pro.min.js +2 -2
  249. package/es5/plugins/autocomplete/autocomplete.css +1 -1
  250. package/es5/plugins/autocomplete/autocomplete.js +1 -1
  251. package/es5/plugins/autocomplete/autocomplete.min.js +1 -1
  252. package/es5/plugins/backup/backup.css +1 -1
  253. package/es5/plugins/backup/backup.js +1 -1
  254. package/es5/plugins/backup/backup.min.js +1 -1
  255. package/es5/plugins/button-generator/button-generator.css +1 -1
  256. package/es5/plugins/button-generator/button-generator.js +1 -1
  257. package/es5/plugins/button-generator/button-generator.min.js +1 -1
  258. package/es5/plugins/change-case/change-case.js +1 -1
  259. package/es5/plugins/change-case/change-case.min.js +1 -1
  260. package/es5/plugins/color-picker/color-picker.css +1 -1
  261. package/es5/plugins/color-picker/color-picker.js +1 -1
  262. package/es5/plugins/color-picker/color-picker.min.js +1 -1
  263. package/es5/plugins/emoji/emoji.css +1 -1
  264. package/es5/plugins/emoji/emoji.js +1 -1
  265. package/es5/plugins/emoji/emoji.min.js +1 -1
  266. package/es5/plugins/export-docs/export-docs.js +1 -1
  267. package/es5/plugins/export-docs/export-docs.min.js +1 -1
  268. package/es5/plugins/finder/finder.css +1 -1
  269. package/es5/plugins/finder/finder.js +1 -1
  270. package/es5/plugins/finder/finder.min.js +1 -1
  271. package/es5/plugins/google-maps/google-maps.css +1 -1
  272. package/es5/plugins/google-maps/google-maps.js +1 -1
  273. package/es5/plugins/google-maps/google-maps.min.js +1 -1
  274. package/es5/plugins/google-search/google-search.js +1 -1
  275. package/es5/plugins/google-search/google-search.min.js +1 -1
  276. package/es5/plugins/highlight-signature/highlight-signature.js +1 -1
  277. package/es5/plugins/highlight-signature/highlight-signature.min.js +1 -1
  278. package/es5/plugins/iframe-editor/iframe-editor.css +1 -1
  279. package/es5/plugins/iframe-editor/iframe-editor.js +1 -1
  280. package/es5/plugins/iframe-editor/iframe-editor.min.js +1 -1
  281. package/es5/plugins/keyboard/keyboard.css +1 -1
  282. package/es5/plugins/keyboard/keyboard.js +1 -1
  283. package/es5/plugins/keyboard/keyboard.min.js +1 -1
  284. package/es5/plugins/mobile-view/mobile-view.js +1 -1
  285. package/es5/plugins/mobile-view/mobile-view.min.js +1 -1
  286. package/es5/plugins/page-break/page-break.js +1 -1
  287. package/es5/plugins/page-break/page-break.min.js +1 -1
  288. package/es5/plugins/paste-code/paste-code.css +1 -1
  289. package/es5/plugins/paste-code/paste-code.js +1 -1
  290. package/es5/plugins/paste-code/paste-code.min.js +1 -1
  291. package/es5/plugins/paste-from-word/paste-from-word.js +1 -1
  292. package/es5/plugins/paste-from-word/paste-from-word.min.js +1 -1
  293. package/es5/plugins/show-blocks/show-blocks.js +1 -1
  294. package/es5/plugins/show-blocks/show-blocks.min.js +1 -1
  295. package/es5/plugins/style/style.css +1 -1
  296. package/es5/plugins/style/style.js +1 -1
  297. package/es5/plugins/style/style.min.js +1 -1
  298. package/es5/plugins/templates/templates.css +1 -1
  299. package/es5/plugins/templates/templates.js +1 -1
  300. package/es5/plugins/templates/templates.min.js +1 -1
  301. package/es5/plugins/todo-list/todo-list.css +1 -1
  302. package/es5/plugins/todo-list/todo-list.js +1 -1
  303. package/es5/plugins/todo-list/todo-list.min.js +1 -1
  304. package/es5/plugins/translate/translate.css +1 -1
  305. package/es5/plugins/translate/translate.js +1 -1
  306. package/es5/plugins/translate/translate.min.js +1 -1
  307. package/es5/plugins/tune-block/tune-block.css +1 -1
  308. package/es5/plugins/tune-block/tune-block.js +1 -1
  309. package/es5/plugins/tune-block/tune-block.min.js +1 -1
  310. package/es5/polyfills.fat.min.js +1 -1
  311. package/es5/polyfills.js +1 -1
  312. package/es5/polyfills.min.js +1 -1
  313. package/esm/plugins/ai-assistant-pro/config.js +1 -1
  314. package/esm/plugins/ai-assistant-pro/icons/microphone.svg.js +1 -0
  315. package/esm/plugins/ai-assistant-pro/interface/options.d.ts +35 -0
  316. package/esm/plugins/ai-assistant-pro/providers/jodit-ai-adapter.js +1 -1
  317. package/esm/plugins/ai-assistant-pro/ui/input-area/input-area.d.ts +20 -0
  318. package/esm/plugins/ai-assistant-pro/ui/input-area/input-area.js +2 -2
  319. package/esm/plugins/ai-assistant-pro/voice/microphone-streamer.d.ts +26 -0
  320. package/esm/plugins/ai-assistant-pro/voice/microphone-streamer.js +1 -0
  321. package/esm/plugins/ai-assistant-pro/voice/voice-engine.d.ts +36 -0
  322. package/esm/plugins/ai-assistant-pro/voice/voice-engine.js +0 -0
  323. package/esm/plugins/ai-assistant-pro/voice/voice-input-button.d.ts +85 -0
  324. package/esm/plugins/ai-assistant-pro/voice/voice-input-button.js +1 -0
  325. package/esm/plugins/ai-assistant-pro/voice/voice-transcriber.d.ts +55 -0
  326. package/esm/plugins/ai-assistant-pro/voice/voice-transcriber.js +1 -0
  327. package/package.json +1 -1
  328. package/types/plugins/ai-assistant-pro/interface/options.d.ts +35 -0
  329. package/types/plugins/ai-assistant-pro/ui/input-area/input-area.d.ts +20 -0
  330. package/types/plugins/ai-assistant-pro/voice/microphone-streamer.d.ts +26 -0
  331. package/types/plugins/ai-assistant-pro/voice/voice-engine.d.ts +36 -0
  332. package/types/plugins/ai-assistant-pro/voice/voice-input-button.d.ts +85 -0
  333. package/types/plugins/ai-assistant-pro/voice/voice-transcriber.d.ts +55 -0
@@ -1,7 +1,7 @@
1
1
  /*!
2
2
  * jodit-pro - PRO Version of Jodit Editor
3
3
  * Author: Chupurnov Valerii <chupurnov@gmail.com>
4
- * Version: v4.12.32
4
+ * Version: v4.12.34
5
5
  * Url: https://xdsoft.net/jodit/pro/
6
6
  * License(s): SEE LICENSE IN LICENSE.md
7
7
  */
@@ -1 +1 @@
1
- var d=Object.defineProperty;var r=(e,t)=>d(e,"name",{value:t,configurable:!0});var n;import{base64ToFile as p}from"../ai-assistant-pro/helpers/base64tofile.js";import m from"./icons/add-context.svg.js";import c from"./icons/ai-assistant.svg.js";import f from"./icons/ai-commands.svg.js";import g from"./icons/chevron-right.svg.js";import h from"./icons/send.svg.js";import A from"./icons/shield.svg.js";import x from"./icons/tool-bolt.svg.js";import{getAIProviderOptions as C,registerAIProvider as y}from"./providers/index.js";import{getToolNames as w}from"./tools/index.js";import{Config as s}from"jodit/esm/config.js";import{Icon as T}from"jodit/esm/core/ui/icon.js";import{aiAssitentCommands as I}from"jodit/esm/plugins/ai-assistant/config.js";import{marked as b}from"marked";T.set("ai-assistant-pro",c).set("ai-commands-pro",f).set("ai-add-context",m).set("send",h).set("tool-bolt",x).set("chevron-right",g).set("shield",A),s.prototype.aiAssistantPro={displayMode:"right",panelWidth:400,panelHeight:500,flightPanelHeight:250,dialogFullSize:!1,resizable:!0,apiMode:"incremental",apiRequest:null,maxRetries:3,requestTimeout:6e4*5,retryDelay:1e3,maxRecursionToolCallDepth:1e3,enabledTools:w(),customTools:[],toolPermissions:{},autoApproveTools:["readDocument","readBlocks","readSelection","insertHTML","addHTML"],alwaysDenyTools:[],defaultPermissionScope:"conversation",storage:"indexedDB",maxConversations:50,storageKey:"jodit-ai-assistant-pro",showConversationList:!0,enableMarkdown:!0,enableCodeHighlight:!0,maxMessageHeight:400,placeholderText:"Ask AI assistant...",sendShortcut:"Ctrl+Enter",showTimestamps:!0,formatTimestamp:r((e,t)=>{const o=new Date(e),i=new Date().getTime()-o.getTime();return i<6e4?t("Just now"):i<36e5?t("%dm ago",Math.floor(i/6e4)):i<864e5?t("%dh ago",Math.floor(i/36e5)):o.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})},"formatTimestamp"),formatMessageContent:r((e,t)=>b.parse(e,{breaks:!0,gfm:!0}),"formatMessageContent"),showAvatars:!0,showTypingIndicator:!0,includeSelectionByDefault:!0,maxContextRanges:5,showContextPreview:!0,sendOnEnter:!0,instructions:void 0,includeEditorMetadata:!1,autoOpen:!0,rememberLastConversation:!0,autoFocusInput:!0,closeAfterInsert:!1,enableSoundNotifications:!1,debug:!1,textAutocompleteEnabled:!1,textAutocompleteApiRequest:null,textAutocompleteMinQueryLength:3,textAutocompleteMaxSuggestions:3,textAutocompleteDebounceMs:500,textAutocompleteCacheTTL:3e4,textAutocompleteCacheMaxSize:50,quickCommandsSilentMode:!1,quickCommandsDisplayMode:"flight",showCopyMessageAction:!0,showRestartMessageAction:!0,showEditMessageAction:!0,showDeleteMessageAction:!0,dialogSettings:{},allowEditDialogSettings:!1,allowEditDisplayMode:!0,allowEditPanelWidth:!0,initiallyOpened:!1,allowClose:!0,persistOpenState:!0,theme:"parent",allowEditTheme:!0,async uploadBase64Artifact(e,t){if(e.type==="image"&&e.data&&e.data.kind==="base64")try{const o=p(e.data.base64,e.id,e.mimeType),a=await t.uploader.upload([o]);return{...e,data:{kind:"url",url:a.baseurl+a.files[0]},metadata:{...e.metadata,filename:a.files[0]}}}catch(o){t.e.fire("error",o)}return e},getAIProviderOptions(e,t){return C(e,t)},registerAIProvider(e,t){y(e,t)}},s.prototype.controls.aiAssistantPro={icon:"ai-assistant-pro",tooltip:"AI Assistant",hotkeys:["ctrl+shift+a","cmd+shift+a"],exec(e){e.e.fire("openAIAssistantPro.ai-assistant-pro")},isDisabled(e){return!e.o.aiAssistantPro.apiRequest},getLabel(e){return e.o.aiAssistantPro.apiRequest?"AI Assistant":"AI Assistant (not configured)"}},s.prototype.controls.aiAddContext={icon:"ai-add-context",tooltip:"Add to AI Context",exec(e){e.e.fire("addContextToAIAssistant")},isDisabled(e){return e.o.aiAssistantPro.apiRequest?e.s.isCollapsed():!0}},s.prototype.controls.aiCommandsPro={icon:"ai-commands-pro",tooltip:"AI Commands",isDisabled(e){return!e.o.aiAssistantPro.apiRequest},list:I,exec(e,t,{control:o}){e.e.fire("executeQuickCommand.ai-assistant-pro",o.name)}};const l=((n=s.prototype.tuneBlock)===null||n===void 0?void 0:n.popup)||{},u={},M=["p","h1","h2","h3","h4","h5","h6","div","section","article","pre","blockquote","ul","ol","li","table","tr","td","th","img","figure"];M.forEach(e=>{const t=l[e]||["tune.up","tune.remove","tune.down"];u[e]=[...t,"|","aiAddContext"]}),s.prototype.tuneBlock&&(s.prototype.tuneBlock.popup={...l,...u});
1
+ var d=Object.defineProperty;var r=(e,t)=>d(e,"name",{value:t,configurable:!0});var n;import{base64ToFile as p}from"../ai-assistant-pro/helpers/base64tofile.js";import m from"./icons/add-context.svg.js";import c from"./icons/ai-assistant.svg.js";import f from"./icons/ai-commands.svg.js";import h from"./icons/chevron-right.svg.js";import g from"./icons/microphone.svg.js";import A from"./icons/send.svg.js";import x from"./icons/shield.svg.js";import C from"./icons/tool-bolt.svg.js";import{getAIProviderOptions as y,registerAIProvider as I}from"./providers/index.js";import{getToolNames as w}from"./tools/index.js";import{Config as s}from"jodit/esm/config.js";import{Icon as T}from"jodit/esm/core/ui/icon.js";import{aiAssitentCommands as b}from"jodit/esm/plugins/ai-assistant/config.js";import{marked as M}from"marked";T.set("ai-assistant-pro",c).set("ai-commands-pro",f).set("ai-add-context",m).set("send",A).set("microphone",g).set("tool-bolt",C).set("chevron-right",h).set("shield",x),s.prototype.aiAssistantPro={displayMode:"right",panelWidth:400,panelHeight:500,flightPanelHeight:250,dialogFullSize:!1,resizable:!0,apiMode:"incremental",apiRequest:null,maxRetries:3,requestTimeout:6e4*5,retryDelay:1e3,maxRecursionToolCallDepth:1e3,enabledTools:w(),customTools:[],toolPermissions:{},autoApproveTools:["readDocument","readBlocks","readSelection","insertHTML","addHTML"],alwaysDenyTools:[],defaultPermissionScope:"conversation",storage:"indexedDB",maxConversations:50,storageKey:"jodit-ai-assistant-pro",showConversationList:!0,enableMarkdown:!0,enableCodeHighlight:!0,maxMessageHeight:400,placeholderText:"Ask AI assistant...",sendShortcut:"Ctrl+Enter",showTimestamps:!0,formatTimestamp:r((e,t)=>{const o=new Date(e),i=new Date().getTime()-o.getTime();return i<6e4?t("Just now"):i<36e5?t("%dm ago",Math.floor(i/6e4)):i<864e5?t("%dh ago",Math.floor(i/36e5)):o.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})},"formatTimestamp"),formatMessageContent:r((e,t)=>M.parse(e,{breaks:!0,gfm:!0}),"formatMessageContent"),showAvatars:!0,showTypingIndicator:!0,includeSelectionByDefault:!0,maxContextRanges:5,showContextPreview:!0,sendOnEnter:!0,instructions:void 0,includeEditorMetadata:!1,autoOpen:!0,rememberLastConversation:!0,autoFocusInput:!0,voiceInputEnabled:!1,closeAfterInsert:!1,enableSoundNotifications:!1,debug:!1,textAutocompleteEnabled:!1,textAutocompleteApiRequest:null,textAutocompleteMinQueryLength:3,textAutocompleteMaxSuggestions:3,textAutocompleteDebounceMs:500,textAutocompleteCacheTTL:3e4,textAutocompleteCacheMaxSize:50,quickCommandsSilentMode:!1,quickCommandsDisplayMode:"flight",showCopyMessageAction:!0,showRestartMessageAction:!0,showEditMessageAction:!0,showDeleteMessageAction:!0,dialogSettings:{},allowEditDialogSettings:!1,allowEditDisplayMode:!0,allowEditPanelWidth:!0,initiallyOpened:!1,allowClose:!0,persistOpenState:!0,theme:"parent",allowEditTheme:!0,async uploadBase64Artifact(e,t){if(e.type==="image"&&e.data&&e.data.kind==="base64")try{const o=p(e.data.base64,e.id,e.mimeType),a=await t.uploader.upload([o]);return{...e,data:{kind:"url",url:a.baseurl+a.files[0]},metadata:{...e.metadata,filename:a.files[0]}}}catch(o){t.e.fire("error",o)}return e},getAIProviderOptions(e,t){return y(e,t)},registerAIProvider(e,t){I(e,t)}},s.prototype.controls.aiAssistantPro={icon:"ai-assistant-pro",tooltip:"AI Assistant",hotkeys:["ctrl+shift+a","cmd+shift+a"],exec(e){e.e.fire("openAIAssistantPro.ai-assistant-pro")},isDisabled(e){return!e.o.aiAssistantPro.apiRequest},getLabel(e){return e.o.aiAssistantPro.apiRequest?"AI Assistant":"AI Assistant (not configured)"}},s.prototype.controls.aiAddContext={icon:"ai-add-context",tooltip:"Add to AI Context",exec(e){e.e.fire("addContextToAIAssistant")},isDisabled(e){return e.o.aiAssistantPro.apiRequest?e.s.isCollapsed():!0}},s.prototype.controls.aiCommandsPro={icon:"ai-commands-pro",tooltip:"AI Commands",isDisabled(e){return!e.o.aiAssistantPro.apiRequest},list:b,exec(e,t,{control:o}){e.e.fire("executeQuickCommand.ai-assistant-pro",o.name)}};const l=((n=s.prototype.tuneBlock)===null||n===void 0?void 0:n.popup)||{},u={},v=["p","h1","h2","h3","h4","h5","h6","div","section","article","pre","blockquote","ul","ol","li","table","tr","td","th","img","figure"];v.forEach(e=>{const t=l[e]||["tune.up","tune.remove","tune.down"];u[e]=[...t,"|","aiAddContext"]}),s.prototype.tuneBlock&&(s.prototype.tuneBlock.popup={...l,...u});
@@ -0,0 +1 @@
1
+ var e='<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <rect x="9" y="2" width="6" height="12" rx="3"></rect> <path d="M5 10v1a7 7 0 0 0 14 0v-1" fill="none"></path> <line x1="12" y1="18" x2="12" y2="22"></line> <line x1="8" y1="22" x2="16" y2="22"></line> </svg> ';export{e as default};
@@ -4,6 +4,7 @@
4
4
  * Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net/jodit/pro/
5
5
  */
6
6
  import type { IDictionary, IJodit, IViewBased } from "jodit/esm/types/index";
7
+ import type { VoiceEngineFactory } from "../voice/voice-engine";
7
8
  import type { IAIArtifact } from "./artifacts";
8
9
  import type { IAIAssistantrRequseter } from "./requests";
9
10
  import type { IAIAssistantStorage } from "./storage";
@@ -283,6 +284,40 @@ export interface IAIAssistantProOptions {
283
284
  * @default true
284
285
  */
285
286
  autoFocusInput: boolean;
287
+ /**
288
+ * Voice dictation into the prompt — show the microphone button.
289
+ * Speech is transcribed through the Jodit transcription proxy
290
+ * (`wss://…/v1/ai/transcribe`). The `jodit-ai-adapter` provider fills
291
+ * `voiceInputUrl`/`voiceInputApiKey` automatically.
292
+ * @default false
293
+ */
294
+ voiceInputEnabled: boolean;
295
+ /** Transcription proxy URL, e.g. `wss://cloud.xdsoft.net/v1/ai/transcribe`. */
296
+ voiceInputUrl?: string;
297
+ /** Cloud API key for voice transcription. */
298
+ voiceInputApiKey?: string;
299
+ /** Voice transcription model (mirrors `defaultModel`; server default if unset). */
300
+ voiceInputDefaultModel?: string;
301
+ /** Voice language hint, e.g. `en-US`. */
302
+ voiceInputLanguage?: string;
303
+ /**
304
+ * Silence (ms) before a spoken phrase is committed. Lower = more frequent
305
+ * interim/final transcripts on shorter pauses (server clamps to 100–2000ms).
306
+ */
307
+ voiceInputSilenceTimeoutMs?: number;
308
+ /**
309
+ * Hands-free auto-send: while the microphone is on, if no further speech
310
+ * arrives for this many ms after a phrase, the prompt is sent automatically.
311
+ * `null`/unset disables it.
312
+ */
313
+ voiceInputAutoSendSilenceMs?: number | null;
314
+ /**
315
+ * Custom voice recognition engine. When set it **replaces** the built-in
316
+ * transcription-proxy engine, so you can dictate against any backend — e.g.
317
+ * `createOpenAIRealtimeVoiceEngine(...)` to talk to OpenAI Realtime directly.
318
+ * With a custom engine `voiceInputUrl`/`voiceInputApiKey` are not used.
319
+ */
320
+ voiceInputApi?: VoiceEngineFactory;
286
321
  /**
287
322
  * Close panel after inserting generated content
288
323
  * @default false
@@ -1 +1 @@
1
- var y=Object.defineProperty;var d=(e,t)=>y(e,"name",{value:t,configurable:!0});import{registerAIProvider as v}from"./registry.js";import{Ajax as m}from"jodit/esm/core/request/ajax.js";v("jodit-ai-adapter",(e=>{var t;const p=e.url.replace(/\/+$/,""),u=(t=e.provider)!==null&&t!==void 0?t:"openai",c=e.stream!==!1;return{apiMode:"incremental",maxRetries:0,textAutocompleteEnabled:!0,textAutocompleteApiRequest:d(async(a,s,o)=>{var r;const n=new m({url:`${p}/ai/autocomplete?query=${encodeURIComponent(a)}&key=${encodeURIComponent(e.apiKey)}`,method:"POST",contentType:"application/json",data:{provider:u,context:{maxSuggestions:s}}});o.addEventListener("abort",()=>n.abort(),{once:!0});const i=await(await n.send()).json();return i.success&&(!((r=i.result)===null||r===void 0)&&r.suggestions)?i.result.suggestions:[]},"textAutocompleteApiRequest"),apiRequest:d(async(a,s)=>{const o=new m({url:`${p}/ai/request?key=${encodeURIComponent(e.apiKey)}`,method:"POST",contentType:"application/json",data:{provider:u,context:c?{...a,metadata:{...a.metadata,stream:!0}}:a}});if(s&&s.addEventListener("abort",()=>o.abort(),{once:!0}),!c)return{mode:"final",response:(await(await o.send()).json()).result};const r=o.stream();return{mode:"stream",stream:(async function*(){for await(const n of r)yield JSON.parse(n)})()}},"apiRequest")}}));
1
+ var v=Object.defineProperty;var c=(e,t)=>v(e,"name",{value:t,configurable:!0});import{registerAIProvider as y}from"./registry.js";import{Ajax as l}from"jodit/esm/core/request/ajax.js";y("jodit-ai-adapter",(e=>{var t;const i=e.url.replace(/\/+$/,""),d=(t=e.provider)!==null&&t!==void 0?t:"openai",u=e.stream!==!1;return{apiMode:"incremental",maxRetries:0,voiceInputEnabled:!0,voiceInputUrl:`${i.replace(/^http/,"ws")}/v1/ai/transcribe`,voiceInputApiKey:e.apiKey,textAutocompleteEnabled:!0,textAutocompleteApiRequest:c(async(a,s,r)=>{var n;const o=new l({url:`${i}/ai/autocomplete?query=${encodeURIComponent(a)}&key=${encodeURIComponent(e.apiKey)}`,method:"POST",contentType:"application/json",data:{provider:d,context:{maxSuggestions:s}}});r.addEventListener("abort",()=>o.abort(),{once:!0});const p=await(await o.send()).json();return p.success&&(!((n=p.result)===null||n===void 0)&&n.suggestions)?p.result.suggestions:[]},"textAutocompleteApiRequest"),apiRequest:c(async(a,s)=>{const r=new l({url:`${i}/ai/request?key=${encodeURIComponent(e.apiKey)}`,method:"POST",contentType:"application/json",data:{provider:d,context:u?{...a,metadata:{...a.metadata,stream:!0}}:a}});if(s&&s.addEventListener("abort",()=>r.abort(),{once:!0}),!u)return{mode:"final",response:(await(await r.send()).json()).result};const n=r.stream();return{mode:"stream",stream:(async function*(){for await(const o of n)yield JSON.parse(o)})()}},"apiRequest")}}));
@@ -5,16 +5,26 @@
5
5
  */
6
6
  import type { IViewBased } from "jodit/esm/types/index";
7
7
  import type { ISelectionContext } from "../../interface/index";
8
+ import type { VoiceEngineFactory } from "../../voice/voice-engine";
8
9
  import { UIElement } from "jodit/esm/core/ui/index";
9
10
  export declare class UIInputArea extends UIElement<IViewBased> {
10
11
  protected options: {
11
12
  placeholderText: string;
12
13
  sendShortcut: string;
13
14
  sendOnEnter: boolean;
15
+ voiceInputEnabled?: boolean;
16
+ voiceInputUrl?: string;
17
+ voiceInputApiKey?: string;
18
+ voiceInputDefaultModel?: string;
19
+ voiceInputLanguage?: string;
20
+ voiceInputSilenceTimeoutMs?: number;
21
+ voiceInputAutoSendSilenceMs?: number | null;
22
+ voiceInputApi?: VoiceEngineFactory;
14
23
  };
15
24
  private textarea;
16
25
  private sendButton;
17
26
  private stopButton;
27
+ private voiceButton;
18
28
  private contextBadges;
19
29
  private contexts;
20
30
  private isLoading;
@@ -23,11 +33,21 @@ export declare class UIInputArea extends UIElement<IViewBased> {
23
33
  placeholderText: string;
24
34
  sendShortcut: string;
25
35
  sendOnEnter: boolean;
36
+ voiceInputEnabled?: boolean;
37
+ voiceInputUrl?: string;
38
+ voiceInputApiKey?: string;
39
+ voiceInputDefaultModel?: string;
40
+ voiceInputLanguage?: string;
41
+ voiceInputSilenceTimeoutMs?: number;
42
+ voiceInputAutoSendSilenceMs?: number | null;
43
+ voiceInputApi?: VoiceEngineFactory;
26
44
  });
27
45
  setParentView(view: IViewBased): this;
28
46
  protected render(): string;
29
47
  protected onInputRowClick(): void;
30
48
  protected afterRender(): void;
49
+ /** Grow the textarea to fit its content up to a max height, then scroll. */
50
+ private autosize;
31
51
  private createControls;
32
52
  private attachHandlers;
33
53
  private onSend;
@@ -1,4 +1,4 @@
1
- var v=Object.defineProperty;var h=(d,t)=>v(d,"name",{value:t,configurable:!0});var r,l=function(d,t,e,s){var n=arguments.length,i=n<3?t:s===null?s=Object.getOwnPropertyDescriptor(t,e):s,a;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")i=Reflect.decorate(d,t,e,s);else for(var c=d.length-1;c>=0;c--)(a=d[c])&&(i=(n<3?a(i):n>3?a(t,e,i):a(t,e))||i);return n>3&&i&&Object.defineProperty(t,e,i),i};import{autobind as p,component as f,hook as x,watch as m}from"jodit/esm/core/decorators/index.js";import{assert as g}from"jodit/esm/core/helpers/utils/assert.js";import{UIElement as _}from"jodit/esm/core/ui/index.js";import{UIButton as u}from"jodit/esm/core/ui/button/index.js";import{UITextArea as B}from"jodit/esm/core/ui/form/inputs/area/area.js";let o=(r=class extends _{className(){return"UIInputArea"}constructor(t,e){super(t),this.options=e,this.textarea=null,this.sendButton=null,this.stopButton=null,this.contexts=[],this.isLoading=!1}setParentView(t){var e,s,n;return(e=this.textarea)===null||e===void 0||e.setParentView(t),(s=this.sendButton)===null||s===void 0||s.setParentView(t),(n=this.stopButton)===null||n===void 0||n.setParentView(t),super.setParentView(t)}render(){return`<div class="&__container">
1
+ var v=Object.defineProperty;var a=(u,t)=>v(u,"name",{value:t,configurable:!0});var d,h=function(u,t,e,i){var n=arguments.length,s=n<3?t:i===null?i=Object.getOwnPropertyDescriptor(t,e):i,o;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")s=Reflect.decorate(u,t,e,i);else for(var l=u.length-1;l>=0;l--)(o=u[l])&&(s=(n<3?o(s):n>3?o(t,e,s):o(t,e))||s);return n>3&&s&&Object.defineProperty(t,e,s),s};import{VoiceInputButton as f}from"../../voice/voice-input-button.js";import{autobind as c,component as x,hook as g,watch as m}from"jodit/esm/core/decorators/index.js";import{assert as _}from"jodit/esm/core/helpers/utils/assert.js";import{UIElement as B}from"jodit/esm/core/ui/index.js";import{UIButton as p}from"jodit/esm/core/ui/button/index.js";import{UITextArea as y}from"jodit/esm/core/ui/form/inputs/area/area.js";let r=(d=class extends B{className(){return"UIInputArea"}constructor(t,e){super(t),this.options=e,this.textarea=null,this.sendButton=null,this.stopButton=null,this.voiceButton=null,this.contexts=[],this.isLoading=!1}setParentView(t){var e,i,n,s;return(e=this.textarea)===null||e===void 0||e.setParentView(t),(i=this.sendButton)===null||i===void 0||i.setParentView(t),(n=this.stopButton)===null||n===void 0||n.setParentView(t),(s=this.voiceButton)===null||s===void 0||s.setParentView(t),super.setParentView(t)}render(){return`<div class="&__container">
2
2
  <div class="&__context-badges"></div>
3
3
  <div class="&__loading-indicator">
4
4
  <span class="&__loading-dot"></span>
@@ -9,4 +9,4 @@ var v=Object.defineProperty;var h=(d,t)=>v(d,"name",{value:t,configurable:!0});v
9
9
  <div class="&__textarea-wrapper"></div>
10
10
  <div class="&__buttons"></div>
11
11
  </div>
12
- </div>`}onInputRowClick(){var t;this.textarea!==this.j.od.activeElement&&((t=this.textarea)===null||t===void 0||t.focus())}afterRender(){this.contextBadges=this.getElm("context-badges"),this.createControls(),this.attachHandlers()}createControls(){const t=this.getElm("textarea-wrapper"),e=this.getElm("buttons");this.textarea=new B(this.j,{name:"message",placeholder:this.options.placeholderText,resizable:!1}),t.appendChild(this.textarea.container),this.sendButton=new u(this.j,{name:"send-message",icon:{name:"send"},variant:"initial",size:"middle"}),this.stopButton=new u(this.j,{name:"abort-message",icon:{name:"cancel"},variant:"default",size:"middle"}),this.stopButton.container.style.display="none",e.appendChild(this.sendButton.container),e.appendChild(this.stopButton.container)}attachHandlers(){this.j.e.on(this.sendButton,"click",this.onSend),this.j.e.on(this.stopButton,"click",this.onStop),this.j.e.on(this.textarea.nativeInput,"keydown",t=>{const{sendShortcut:e,sendOnEnter:s}=this.options;if(e==="Ctrl+Enter"&&t.ctrlKey&&t.key==="Enter"){t.preventDefault(),this.onSend();return}if(t.key==="Escape"){this.j.e.fire("cancelEditMessage.ai-assistant-pro");return}t.key==="Enter"&&(s?t.shiftKey||(t.preventDefault(),this.onSend()):t.shiftKey&&(t.preventDefault(),this.onSend()))})}onSend(){var t;const e=(t=this.textarea)===null||t===void 0?void 0:t.value.trim();!e||this.isLoading||(this.j.e.fire("sendMessage.ai-assistant-pro",e),this.textarea&&(this.textarea.value="",this.textarea.nativeInput.focus()))}onStop(){this.j.e.fire("abortRequest.ai-assistant-pro")}setContexts(t){this.contexts=t,this.updateContextBadges()}updateContextBadges(){if(this.contextBadges.innerHTML="",this.contexts.length===0){this.contextBadges.style.display="none";return}this.contextBadges.style.display="",this.contexts.forEach((t,e)=>{const s=this.createContextBadge(t,e);this.contextBadges.appendChild(s)})}createContextBadge(t,e){const s=this.j.c.div(this.getFullElName("context-badge")),n=this.j.c.span(),i=t.html.replace(/<[^>]*>/g,"").substring(0,20);n.textContent=t.blockIndex!==void 0?`Block ${t.blockIndex}: ${i}...`:`${i}...`;const a=this.j.c.span(this.getFullElName("context-remove"));return a.textContent="\xD7",a.setAttribute("data-index",String(e)),this.j.e.on(a,"click",()=>{this.j.e.fire("removeContext.ai-assistant-pro",e)}),s.appendChild(n),s.appendChild(a),s}setLoading(t){this.isLoading=t;const{sendButton:e,stopButton:s,textarea:n}=this;g(e&&s&&n,"Buttons must be initialized"),n.setMod("disabled",t),e.setMod("disabled",t),this.setMod("loading",t),t?(e.container.style.display="none",s.container.style.display=""):(e.container.style.display="",s.container.style.display="none")}focus(){var t;(t=this.textarea)===null||t===void 0||t.nativeInput.focus()}setValue(t){this.textarea&&(this.textarea.value=t)}getValue(){var t;return((t=this.textarea)===null||t===void 0?void 0:t.value.trim())||""}destruct(){var t,e,s;(t=this.textarea)===null||t===void 0||t.destruct(),(e=this.sendButton)===null||e===void 0||e.destruct(),(s=this.stopButton)===null||s===void 0||s.destruct(),super.destruct()}},h(r,"UIInputArea"),r);l([m("input-row:click")],o.prototype,"onInputRowClick",null),l([x("ready")],o.prototype,"afterRender",null),l([p],o.prototype,"onSend",null),l([p],o.prototype,"onStop",null),o=l([f],o);export{o as UIInputArea};
12
+ </div>`}onInputRowClick(){var t;this.textarea!==this.j.od.activeElement&&((t=this.textarea)===null||t===void 0||t.focus())}afterRender(){this.contextBadges=this.getElm("context-badges"),this.createControls(),this.attachHandlers(),this.autosize()}autosize(){var t;const e=(t=this.textarea)===null||t===void 0?void 0:t.nativeInput;if(!e)return;const i=160;e.style.height="auto",e.style.height=`${Math.min(e.scrollHeight,i)}px`,e.style.overflowY=e.scrollHeight>i?"auto":"hidden"}createControls(){const t=this.getElm("textarea-wrapper"),e=this.getElm("buttons");this.textarea=new y(this.j,{name:"message",placeholder:this.options.placeholderText,resizable:!1}),t.appendChild(this.textarea.container),this.sendButton=new p(this.j,{name:"send-message",icon:{name:"send"},variant:"initial",size:"middle"}),this.stopButton=new p(this.j,{name:"abort-message",icon:{name:"cancel"},variant:"default",size:"middle"}),this.stopButton.container.style.display="none",this.options.voiceInputEnabled&&(this.voiceButton=new f(this.j,{url:this.options.voiceInputUrl,apiKey:this.options.voiceInputApiKey,defaultModel:this.options.voiceInputDefaultModel,language:this.options.voiceInputLanguage,silenceTimeoutMs:this.options.voiceInputSilenceTimeoutMs,autoSendSilenceMs:this.options.voiceInputAutoSendSilenceMs,api:this.options.voiceInputApi},{getValue:a(()=>{var i,n;return(n=(i=this.textarea)===null||i===void 0?void 0:i.nativeInput.value)!==null&&n!==void 0?n:""},"getValue"),setValue:a((i,n)=>{if(this.textarea){if(this.textarea.value=i,n!==void 0){const s=this.textarea.nativeInput;s.selectionStart=n,s.selectionEnd=n}this.autosize()}},"setValue"),getSelection:a(()=>{var i,n,s;const o=(i=this.textarea)===null||i===void 0?void 0:i.nativeInput;if(!o)return{start:0,end:0};const l=o.value.length;return{start:(n=o.selectionStart)!==null&&n!==void 0?n:l,end:(s=o.selectionEnd)!==null&&s!==void 0?s:l}},"getSelection"),focus:a(()=>this.focus(),"focus"),send:a(()=>this.onSend(),"send")}),e.appendChild(this.voiceButton.container)),e.appendChild(this.sendButton.container),e.appendChild(this.stopButton.container)}attachHandlers(){this.j.e.on(this.sendButton,"click",this.onSend),this.j.e.on(this.stopButton,"click",this.onStop),this.j.e.on(this.textarea.nativeInput,"input",()=>this.autosize()),this.j.e.on(this.textarea.nativeInput,"keydown",t=>{const{sendShortcut:e,sendOnEnter:i}=this.options;if(e==="Ctrl+Enter"&&t.ctrlKey&&t.key==="Enter"){t.preventDefault(),this.onSend();return}if(t.key==="Escape"){this.j.e.fire("cancelEditMessage.ai-assistant-pro");return}t.key==="Enter"&&(i?t.shiftKey||(t.preventDefault(),this.onSend()):t.shiftKey&&(t.preventDefault(),this.onSend()))})}onSend(){var t;const e=(t=this.textarea)===null||t===void 0?void 0:t.value.trim();!e||this.isLoading||(this.j.e.fire("sendMessage.ai-assistant-pro",e),this.textarea&&(this.textarea.value="",this.autosize(),this.textarea.nativeInput.focus()))}onStop(){this.j.e.fire("abortRequest.ai-assistant-pro")}setContexts(t){this.contexts=t,this.updateContextBadges()}updateContextBadges(){if(this.contextBadges.innerHTML="",this.contexts.length===0){this.contextBadges.style.display="none";return}this.contextBadges.style.display="",this.contexts.forEach((t,e)=>{const i=this.createContextBadge(t,e);this.contextBadges.appendChild(i)})}createContextBadge(t,e){const i=this.j.c.div(this.getFullElName("context-badge")),n=this.j.c.span(),s=t.html.replace(/<[^>]*>/g,"").substring(0,20);n.textContent=t.blockIndex!==void 0?`Block ${t.blockIndex}: ${s}...`:`${s}...`;const o=this.j.c.span(this.getFullElName("context-remove"));return o.textContent="\xD7",o.setAttribute("data-index",String(e)),this.j.e.on(o,"click",()=>{this.j.e.fire("removeContext.ai-assistant-pro",e)}),i.appendChild(n),i.appendChild(o),i}setLoading(t){this.isLoading=t;const{sendButton:e,stopButton:i,textarea:n}=this;_(e&&i&&n,"Buttons must be initialized"),n.setMod("disabled",t),e.setMod("disabled",t),this.setMod("loading",t),t?(e.container.style.display="none",i.container.style.display=""):(e.container.style.display="",i.container.style.display="none")}focus(){var t;(t=this.textarea)===null||t===void 0||t.nativeInput.focus()}setValue(t){this.textarea&&(this.textarea.value=t,this.autosize())}getValue(){var t;return((t=this.textarea)===null||t===void 0?void 0:t.value.trim())||""}destruct(){var t,e,i,n;(t=this.textarea)===null||t===void 0||t.destruct(),(e=this.sendButton)===null||e===void 0||e.destruct(),(i=this.stopButton)===null||i===void 0||i.destruct(),(n=this.voiceButton)===null||n===void 0||n.destruct(),super.destruct()}},a(d,"UIInputArea"),d);h([m("input-row:click")],r.prototype,"onInputRowClick",null),h([g("ready")],r.prototype,"afterRender",null),h([c],r.prototype,"onSend",null),h([c],r.prototype,"onStop",null),r=h([x],r);export{r as UIInputArea};
@@ -0,0 +1,26 @@
1
+ /*!
2
+ * Jodit Editor PRO (https://xdsoft.net/jodit/)
3
+ * See LICENSE.md in the project root for license information.
4
+ * Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net/jodit/pro/
5
+ */
6
+ export declare class MicrophoneStreamer {
7
+ private readonly onFrame;
8
+ private stream;
9
+ private audioCtx;
10
+ private processor;
11
+ private source;
12
+ private zeroGain;
13
+ private running;
14
+ /**
15
+ * @param onFrame - receives each binary PCM16 audio frame to send upstream.
16
+ */
17
+ constructor(onFrame: (frame: ArrayBufferView<ArrayBuffer>) => void);
18
+ /**
19
+ * Request the microphone and start streaming audio frames. Rejects if access
20
+ * is denied or the audio graph cannot start.
21
+ */
22
+ start(): Promise<void>;
23
+ /** Stop streaming and release the microphone and audio graph. */
24
+ stop(): void;
25
+ private stopTracks;
26
+ }
@@ -0,0 +1 @@
1
+ var h=Object.defineProperty;var a=(o,t)=>h(o,"name",{value:t,configurable:!0});const g=24e3;function d(o){const t=new Int16Array(o.length);for(let s=0;s<o.length;s++){const n=Math.max(-1,Math.min(1,o[s]));t[s]=n<0?n*32768:n*32767}return t}a(d,"floatTo16BitPCM");function f(o,t,s){if(s>=t)return o;const n=t/s,i=Math.round(o.length/n),r=new Float32Array(i);for(let e=0;e<i;e++)r[e]=o[Math.min(Math.round(e*n),o.length-1)];return r}a(f,"downsample");const c=class c{constructor(t){this.onFrame=t,this.stream=null,this.audioCtx=null,this.processor=null,this.source=null,this.zeroGain=null,this.running=!1}async start(){if(this.running=!0,this.stream=await navigator.mediaDevices.getUserMedia({audio:{channelCount:1,echoCancellation:!0,noiseSuppression:!0}}),!this.running){this.stopTracks();return}const t=new AudioContext;if(t.state==="suspended"&&await t.resume(),!this.running){t.close();return}const s=t.createMediaStreamSource(this.stream),n=t.createScriptProcessor(4096,1,1),i=t.createGain();i.gain.value=0,n.onaudioprocess=r=>{if(!this.running)return;const e=r.inputBuffer.getChannelData(0),l=d(f(e,r.inputBuffer.sampleRate,24e3));this.onFrame(l)},s.connect(n),n.connect(i),i.connect(t.destination),this.audioCtx=t,this.source=s,this.processor=n,this.zeroGain=i}stop(){var t,s;this.running=!1,this.processor&&(this.processor.onaudioprocess=null,this.processor.disconnect(),this.processor=null),(t=this.zeroGain)===null||t===void 0||t.disconnect(),(s=this.source)===null||s===void 0||s.disconnect(),this.zeroGain=null,this.source=null,this.audioCtx&&(this.audioCtx.close(),this.audioCtx=null),this.stopTracks()}stopTracks(){var t;(t=this.stream)===null||t===void 0||t.getTracks().forEach(s=>s.stop()),this.stream=null}};a(c,"MicrophoneStreamer");let u=c;export{u as MicrophoneStreamer};
@@ -0,0 +1,36 @@
1
+ /*!
2
+ * Jodit Editor PRO (https://xdsoft.net/jodit/)
3
+ * See LICENSE.md in the project root for license information.
4
+ * Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net/jodit/pro/
5
+ */
6
+ /**
7
+ * Pluggable voice-recognition engine contract. The mic button drives an engine
8
+ * and reacts to its callbacks; this lets you point voice dictation at any
9
+ * backend — the built-in Jodit transcription proxy, OpenAI Realtime directly, or
10
+ * your own service — via the `voiceInputApi` option.
11
+ *
12
+ * @module plugins/ai-assistant-pro/voice
13
+ */
14
+ export interface IVoiceEngineCallbacks {
15
+ /** Recognition is live — audio is now streaming. */
16
+ onReady?(): void;
17
+ /** Interim (partial) transcript for the current phrase. */
18
+ onInterim?(text: string): void;
19
+ /** Committed transcript for a finished phrase. */
20
+ onFinal?(text: string): void;
21
+ /** A recoverable error (mic denied, connection/provider error). */
22
+ onError?(message: string): void;
23
+ /** The session ended. */
24
+ onEnd?(): void;
25
+ }
26
+ export interface IVoiceEngine {
27
+ /** Begin capturing and recognising speech. */
28
+ start(): void;
29
+ /** Stop and release resources. */
30
+ stop(): void;
31
+ }
32
+ /**
33
+ * Factory for a voice engine. Receives the mic button's callbacks and returns an
34
+ * engine bound to them. Assign to `voiceInputApi` to use a custom backend.
35
+ */
36
+ export type VoiceEngineFactory = (callbacks: IVoiceEngineCallbacks) => IVoiceEngine;
@@ -0,0 +1,85 @@
1
+ /*!
2
+ * Jodit Editor PRO (https://xdsoft.net/jodit/)
3
+ * See LICENSE.md in the project root for license information.
4
+ * Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net/jodit/pro/
5
+ */
6
+ import type { IViewBased } from "jodit/esm/types/index";
7
+ import type { VoiceEngineFactory } from "./voice-engine";
8
+ /**
9
+ * Resolved voice settings the mic button needs (built by the input area from the
10
+ * flat `voiceInput*` options).
11
+ *
12
+ * @module plugins/ai-assistant-pro/voice
13
+ */
14
+ export interface IVoiceInputConfig {
15
+ url?: string;
16
+ apiKey?: string;
17
+ defaultModel?: string;
18
+ language?: string;
19
+ silenceTimeoutMs?: number;
20
+ autoSendSilenceMs?: number | null;
21
+ /** Custom recognition engine; when set it replaces the built-in proxy engine. */
22
+ api?: VoiceEngineFactory;
23
+ }
24
+ /**
25
+ * Read/write access to the prompt the dictated text goes into.
26
+ */
27
+ export interface IVoiceInputIO {
28
+ /** Raw current value (not trimmed). */
29
+ getValue(): string;
30
+ /** Replace the value and optionally place the caret at `caret`. */
31
+ setValue(value: string, caret?: number): void;
32
+ /** Current selection range within the value. */
33
+ getSelection(): {
34
+ start: number;
35
+ end: number;
36
+ };
37
+ focus(): void;
38
+ /** Send the current prompt (no-op if empty or a request is in flight). */
39
+ send(): void;
40
+ }
41
+ /**
42
+ * The microphone button for the assistant input area. Toggles a
43
+ * `VoiceTranscriber` session and writes interim/final transcripts into the prompt
44
+ * (interim text is previewed; final phrases are appended).
45
+ */
46
+ export declare class VoiceInputButton {
47
+ private readonly jodit;
48
+ private readonly config;
49
+ private readonly io;
50
+ private readonly button;
51
+ private engine;
52
+ /** Whether a recognition session is active. */
53
+ private listening;
54
+ /** Whether a phrase is in progress (between its first interim and its final). */
55
+ private phraseActive;
56
+ /** Prompt text before the caret, captured at the start of the current phrase. */
57
+ private before;
58
+ /** Prompt text after the caret (or selection), captured at phrase start. */
59
+ private after;
60
+ /** Pending hands-free auto-send timer id (0 = none). */
61
+ private autoSendTimer;
62
+ constructor(jodit: IViewBased, config: IVoiceInputConfig, io: IVoiceInputIO);
63
+ private onPromptSent;
64
+ get container(): HTMLElement;
65
+ setParentView(view: IViewBased): void;
66
+ private toggle;
67
+ private start;
68
+ private reset;
69
+ /**
70
+ * Schedule a hands-free auto-send after `autoSendSilenceMs` of no new speech.
71
+ * No-op when the option is unset/null.
72
+ */
73
+ private scheduleAutoSend;
74
+ private clearAutoSend;
75
+ private setActive;
76
+ /**
77
+ * Insert the current phrase at the caret. The text around the caret (or
78
+ * selection) is captured once at the start of each phrase from the live input,
79
+ * so dictation lands where the cursor is, replaces any selection, and respects
80
+ * manual edits / sends between phrases. Subsequent interims of the same phrase
81
+ * replace its preview rather than accumulating.
82
+ */
83
+ private insertPhrase;
84
+ destruct(): void;
85
+ }
@@ -0,0 +1 @@
1
+ var u=Object.defineProperty;var n=(a,t)=>u(a,"name",{value:t,configurable:!0});import{VoiceTranscriber as d}from"./voice-transcriber.js";import{UIButton as f}from"jodit/esm/core/ui/button/index.js";const g="jodit-ai-voice-active",o=class o{constructor(t,s,e){this.jodit=t,this.config=s,this.io=e,this.engine=null,this.listening=!1,this.phraseActive=!1,this.before="",this.after="",this.autoSendTimer=0,this.onPromptSent=()=>{this.phraseActive=!1},this.toggle=()=>{var i;if(this.listening){(i=this.engine)===null||i===void 0||i.stop(),this.reset();return}this.start()},this.button=new f(t,{name:"voice-input",icon:{name:"microphone"},variant:"initial",size:"middle"}),this.button.container.setAttribute("title","Dictate"),this.button.container.setAttribute("data-ref","voiceInputButton"),this.jodit.e.on(this.button,"click",this.toggle),this.jodit.e.on("sendMessage.ai-assistant-pro",this.onPromptSent)}get container(){return this.button.container}setParentView(t){this.button.setParentView(t)}start(){const t={onInterim:n(e=>{this.clearAutoSend(),this.insertPhrase(e)},"onInterim"),onFinal:n(e=>{this.insertPhrase(e),this.phraseActive=!1,this.scheduleAutoSend()},"onFinal"),onError:n(()=>this.reset(),"onError"),onEnd:n(()=>this.reset(),"onEnd")};let s;if(this.config.api)s=this.config.api(t);else{const{url:e,apiKey:i}=this.config;if(!e||!i)return;s=new d({url:e,apiKey:i,model:this.config.defaultModel,language:this.config.language,silenceMs:this.config.silenceTimeoutMs,...t})}this.phraseActive=!1,this.engine=s,this.listening=!0,this.setActive(!0),s.start()}reset(){this.clearAutoSend(),this.setActive(!1),this.phraseActive=!1,this.listening=!1,this.engine=null,this.io.focus()}scheduleAutoSend(){this.clearAutoSend();const t=this.config.autoSendSilenceMs;t!=null&&(this.autoSendTimer=this.jodit.async.setTimeout(()=>{this.autoSendTimer=0,this.io.send()},t))}clearAutoSend(){this.autoSendTimer&&(this.jodit.async.clearTimeout(this.autoSendTimer),this.autoSendTimer=0)}setActive(t){this.button.container.classList.toggle(g,t)}insertPhrase(t){if(!this.phraseActive){this.phraseActive=!0;const{start:c,end:l}=this.io.getSelection(),h=this.io.getValue();this.before=h.slice(0,c),this.after=h.slice(l)}const e=(this.before.length>0&&!/\s$/.test(this.before)?" ":"")+t,i=this.before.length+e.length;this.io.setValue(this.before+e+this.after,i)}destruct(){var t;this.clearAutoSend(),this.jodit.e.off("sendMessage.ai-assistant-pro",this.onPromptSent),(t=this.engine)===null||t===void 0||t.stop(),this.engine=null,this.button.destruct()}};n(o,"VoiceInputButton");let r=o;export{r as VoiceInputButton};
@@ -0,0 +1,55 @@
1
+ /*!
2
+ * Jodit Editor PRO (https://xdsoft.net/jodit/)
3
+ * See LICENSE.md in the project root for license information.
4
+ * Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net/jodit/pro/
5
+ */
6
+ import type { IVoiceEngine } from "./voice-engine";
7
+ /**
8
+ * Streams microphone audio to the Jodit transcription proxy
9
+ * (`wss://…/v1/ai/transcribe`) and reports transcript events back. The cloud key
10
+ * stays on the server; the browser only opens an authenticated socket and sends
11
+ * binary PCM16 audio.
12
+ *
13
+ * The server speaks the JSON protocol `ready` / `delta` / `final` / `error`; this
14
+ * class translates it into callbacks the mic button consumes.
15
+ *
16
+ * @module plugins/ai-assistant-pro/voice
17
+ */
18
+ export interface IVoiceTranscriberOptions {
19
+ /** Proxy endpoint, e.g. `wss://cloud.xdsoft.net/v1/ai/transcribe`. */
20
+ url: string;
21
+ /** Cloud API key (sent as the `key` query param). */
22
+ apiKey: string;
23
+ /** Transcription model; defaults to the server's default. */
24
+ model?: string;
25
+ /** BCP-47 language hint, e.g. `en-US`. */
26
+ language?: string;
27
+ /** Silence (ms) before a phrase is committed; sent as the `silence` param. */
28
+ silenceMs?: number;
29
+ /** Upstream session is live — audio is now streaming. */
30
+ onReady?: () => void;
31
+ /** Interim (partial) transcript for the current phrase. */
32
+ onInterim?: (text: string) => void;
33
+ /** Committed transcript for a finished phrase. */
34
+ onFinal?: (text: string) => void;
35
+ /** A recoverable error (mic denied, connection/provider error). */
36
+ onError?: (message: string) => void;
37
+ /** The session ended (socket closed). */
38
+ onEnd?: () => void;
39
+ }
40
+ export declare class VoiceTranscriber implements IVoiceEngine {
41
+ private readonly options;
42
+ private ws;
43
+ private streamer;
44
+ private running;
45
+ constructor(options: IVoiceTranscriberOptions);
46
+ get isActive(): boolean;
47
+ /** Open the socket and begin a transcription session. */
48
+ start(): void;
49
+ /** Stop the session and release the microphone. */
50
+ stop(): void;
51
+ private onMessage;
52
+ private startAudio;
53
+ private fail;
54
+ private finish;
55
+ }
@@ -0,0 +1 @@
1
+ var p=Object.defineProperty;var d=(u,s)=>p(u,"name",{value:s,configurable:!0});import{MicrophoneStreamer as f}from"./microphone-streamer.js";const l=class l{constructor(s){this.options=s,this.ws=null,this.streamer=null,this.running=!1}get isActive(){return this.running}start(){if(this.running)return;this.running=!0;let s;try{const t=new URL(this.options.url);t.searchParams.set("key",this.options.apiKey),this.options.model&&t.searchParams.set("model",this.options.model),this.options.language&&t.searchParams.set("language",this.options.language),this.options.silenceMs!==void 0&&t.searchParams.set("silence",String(this.options.silenceMs)),s=t.toString()}catch{this.fail("Invalid transcription URL");return}const i=new WebSocket(s);i.binaryType="arraybuffer",this.ws=i,i.addEventListener("message",t=>this.onMessage(t)),i.addEventListener("error",()=>this.fail("Transcription connection error")),i.addEventListener("close",()=>this.finish())}stop(){var s;this.running&&(this.running=!1,(s=this.streamer)===null||s===void 0||s.stop(),this.streamer=null,this.ws&&(this.ws.readyState===WebSocket.OPEN||this.ws.readyState===WebSocket.CONNECTING)&&this.ws.close())}onMessage(s){var i,t,n,r,h,a,o;if(typeof s.data!="string")return;let e;try{e=JSON.parse(s.data)}catch{return}switch(e.type){case"ready":(t=(i=this.options).onReady)===null||t===void 0||t.call(i),this.startAudio();break;case"delta":e.text&&((r=(n=this.options).onInterim)===null||r===void 0||r.call(n,e.text));break;case"final":e.text&&((a=(h=this.options).onFinal)===null||a===void 0||a.call(h,e.text));break;case"error":this.fail((o=e.message)!==null&&o!==void 0?o:"Transcription error");break}}startAudio(){if(!this.running||this.streamer)return;const s=new f(i=>{var t;((t=this.ws)===null||t===void 0?void 0:t.readyState)===WebSocket.OPEN&&this.ws.send(i)});this.streamer=s,s.start().catch(()=>{this.fail("Microphone access denied")})}fail(s){var i,t;(t=(i=this.options).onError)===null||t===void 0||t.call(i,s),this.stop()}finish(){var s,i,t;const n=this.running;this.running=!1,(s=this.streamer)===null||s===void 0||s.stop(),this.streamer=null,n&&((t=(i=this.options).onEnd)===null||t===void 0||t.call(i))}};d(l,"VoiceTranscriber");let c=l;export{c as VoiceTranscriber};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jodit-pro",
3
- "version": "4.12.32",
3
+ "version": "4.12.34",
4
4
  "author": "Chupurnov Valerii <chupurnov@gmail.com>",
5
5
  "homepage": "https://xdsoft.net/jodit/pro/",
6
6
  "bugs": {
@@ -4,6 +4,7 @@
4
4
  * Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net/jodit/pro/
5
5
  */
6
6
  import type { IDictionary, IJodit, IViewBased } from "jodit/esm/types/index";
7
+ import type { VoiceEngineFactory } from "../voice/voice-engine";
7
8
  import type { IAIArtifact } from "./artifacts";
8
9
  import type { IAIAssistantrRequseter } from "./requests";
9
10
  import type { IAIAssistantStorage } from "./storage";
@@ -283,6 +284,40 @@ export interface IAIAssistantProOptions {
283
284
  * @default true
284
285
  */
285
286
  autoFocusInput: boolean;
287
+ /**
288
+ * Voice dictation into the prompt — show the microphone button.
289
+ * Speech is transcribed through the Jodit transcription proxy
290
+ * (`wss://…/v1/ai/transcribe`). The `jodit-ai-adapter` provider fills
291
+ * `voiceInputUrl`/`voiceInputApiKey` automatically.
292
+ * @default false
293
+ */
294
+ voiceInputEnabled: boolean;
295
+ /** Transcription proxy URL, e.g. `wss://cloud.xdsoft.net/v1/ai/transcribe`. */
296
+ voiceInputUrl?: string;
297
+ /** Cloud API key for voice transcription. */
298
+ voiceInputApiKey?: string;
299
+ /** Voice transcription model (mirrors `defaultModel`; server default if unset). */
300
+ voiceInputDefaultModel?: string;
301
+ /** Voice language hint, e.g. `en-US`. */
302
+ voiceInputLanguage?: string;
303
+ /**
304
+ * Silence (ms) before a spoken phrase is committed. Lower = more frequent
305
+ * interim/final transcripts on shorter pauses (server clamps to 100–2000ms).
306
+ */
307
+ voiceInputSilenceTimeoutMs?: number;
308
+ /**
309
+ * Hands-free auto-send: while the microphone is on, if no further speech
310
+ * arrives for this many ms after a phrase, the prompt is sent automatically.
311
+ * `null`/unset disables it.
312
+ */
313
+ voiceInputAutoSendSilenceMs?: number | null;
314
+ /**
315
+ * Custom voice recognition engine. When set it **replaces** the built-in
316
+ * transcription-proxy engine, so you can dictate against any backend — e.g.
317
+ * `createOpenAIRealtimeVoiceEngine(...)` to talk to OpenAI Realtime directly.
318
+ * With a custom engine `voiceInputUrl`/`voiceInputApiKey` are not used.
319
+ */
320
+ voiceInputApi?: VoiceEngineFactory;
286
321
  /**
287
322
  * Close panel after inserting generated content
288
323
  * @default false
@@ -5,16 +5,26 @@
5
5
  */
6
6
  import type { IViewBased } from "jodit/esm/types/index";
7
7
  import type { ISelectionContext } from "../../interface/index";
8
+ import type { VoiceEngineFactory } from "../../voice/voice-engine";
8
9
  import { UIElement } from "jodit/esm/core/ui/index";
9
10
  export declare class UIInputArea extends UIElement<IViewBased> {
10
11
  protected options: {
11
12
  placeholderText: string;
12
13
  sendShortcut: string;
13
14
  sendOnEnter: boolean;
15
+ voiceInputEnabled?: boolean;
16
+ voiceInputUrl?: string;
17
+ voiceInputApiKey?: string;
18
+ voiceInputDefaultModel?: string;
19
+ voiceInputLanguage?: string;
20
+ voiceInputSilenceTimeoutMs?: number;
21
+ voiceInputAutoSendSilenceMs?: number | null;
22
+ voiceInputApi?: VoiceEngineFactory;
14
23
  };
15
24
  private textarea;
16
25
  private sendButton;
17
26
  private stopButton;
27
+ private voiceButton;
18
28
  private contextBadges;
19
29
  private contexts;
20
30
  private isLoading;
@@ -23,11 +33,21 @@ export declare class UIInputArea extends UIElement<IViewBased> {
23
33
  placeholderText: string;
24
34
  sendShortcut: string;
25
35
  sendOnEnter: boolean;
36
+ voiceInputEnabled?: boolean;
37
+ voiceInputUrl?: string;
38
+ voiceInputApiKey?: string;
39
+ voiceInputDefaultModel?: string;
40
+ voiceInputLanguage?: string;
41
+ voiceInputSilenceTimeoutMs?: number;
42
+ voiceInputAutoSendSilenceMs?: number | null;
43
+ voiceInputApi?: VoiceEngineFactory;
26
44
  });
27
45
  setParentView(view: IViewBased): this;
28
46
  protected render(): string;
29
47
  protected onInputRowClick(): void;
30
48
  protected afterRender(): void;
49
+ /** Grow the textarea to fit its content up to a max height, then scroll. */
50
+ private autosize;
31
51
  private createControls;
32
52
  private attachHandlers;
33
53
  private onSend;
@@ -0,0 +1,26 @@
1
+ /*!
2
+ * Jodit Editor PRO (https://xdsoft.net/jodit/)
3
+ * See LICENSE.md in the project root for license information.
4
+ * Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net/jodit/pro/
5
+ */
6
+ export declare class MicrophoneStreamer {
7
+ private readonly onFrame;
8
+ private stream;
9
+ private audioCtx;
10
+ private processor;
11
+ private source;
12
+ private zeroGain;
13
+ private running;
14
+ /**
15
+ * @param onFrame - receives each binary PCM16 audio frame to send upstream.
16
+ */
17
+ constructor(onFrame: (frame: ArrayBufferView<ArrayBuffer>) => void);
18
+ /**
19
+ * Request the microphone and start streaming audio frames. Rejects if access
20
+ * is denied or the audio graph cannot start.
21
+ */
22
+ start(): Promise<void>;
23
+ /** Stop streaming and release the microphone and audio graph. */
24
+ stop(): void;
25
+ private stopTracks;
26
+ }
@@ -0,0 +1,36 @@
1
+ /*!
2
+ * Jodit Editor PRO (https://xdsoft.net/jodit/)
3
+ * See LICENSE.md in the project root for license information.
4
+ * Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net/jodit/pro/
5
+ */
6
+ /**
7
+ * Pluggable voice-recognition engine contract. The mic button drives an engine
8
+ * and reacts to its callbacks; this lets you point voice dictation at any
9
+ * backend — the built-in Jodit transcription proxy, OpenAI Realtime directly, or
10
+ * your own service — via the `voiceInputApi` option.
11
+ *
12
+ * @module plugins/ai-assistant-pro/voice
13
+ */
14
+ export interface IVoiceEngineCallbacks {
15
+ /** Recognition is live — audio is now streaming. */
16
+ onReady?(): void;
17
+ /** Interim (partial) transcript for the current phrase. */
18
+ onInterim?(text: string): void;
19
+ /** Committed transcript for a finished phrase. */
20
+ onFinal?(text: string): void;
21
+ /** A recoverable error (mic denied, connection/provider error). */
22
+ onError?(message: string): void;
23
+ /** The session ended. */
24
+ onEnd?(): void;
25
+ }
26
+ export interface IVoiceEngine {
27
+ /** Begin capturing and recognising speech. */
28
+ start(): void;
29
+ /** Stop and release resources. */
30
+ stop(): void;
31
+ }
32
+ /**
33
+ * Factory for a voice engine. Receives the mic button's callbacks and returns an
34
+ * engine bound to them. Assign to `voiceInputApi` to use a custom backend.
35
+ */
36
+ export type VoiceEngineFactory = (callbacks: IVoiceEngineCallbacks) => IVoiceEngine;