@pie-lib/editable-html-tip-tap 2.1.2-next.31 → 2.1.2-next.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 (276) hide show
  1. package/CHANGELOG.json +32 -0
  2. package/CHANGELOG.md +2532 -0
  3. package/LICENSE.md +5 -0
  4. package/lib/components/CharacterPicker.js +201 -0
  5. package/lib/components/CharacterPicker.js.map +1 -0
  6. package/lib/components/EditableHtml.js +376 -0
  7. package/lib/components/EditableHtml.js.map +1 -0
  8. package/lib/components/MenuBar.js +696 -0
  9. package/lib/components/MenuBar.js.map +1 -0
  10. package/lib/components/TiptapContainer.js +234 -0
  11. package/lib/components/TiptapContainer.js.map +1 -0
  12. package/lib/components/characters/characterUtils.js +378 -0
  13. package/lib/components/characters/characterUtils.js.map +1 -0
  14. package/lib/components/characters/custom-popper.js +44 -0
  15. package/lib/components/characters/custom-popper.js.map +1 -0
  16. package/lib/components/common/done-button.js +34 -0
  17. package/lib/components/common/done-button.js.map +1 -0
  18. package/lib/components/common/toolbar-buttons.js +144 -0
  19. package/lib/components/common/toolbar-buttons.js.map +1 -0
  20. package/lib/components/icons/CssIcon.js +25 -0
  21. package/lib/components/icons/CssIcon.js.map +1 -0
  22. package/lib/components/icons/RespArea.js +72 -0
  23. package/lib/components/icons/RespArea.js.map +1 -0
  24. package/lib/components/icons/TableIcons.js +53 -0
  25. package/lib/components/icons/TableIcons.js.map +1 -0
  26. package/lib/components/icons/TextAlign.js +157 -0
  27. package/lib/components/icons/TextAlign.js.map +1 -0
  28. package/lib/components/image/AltDialog.js +98 -0
  29. package/lib/components/image/AltDialog.js.map +1 -0
  30. package/lib/components/image/ImageToolbar.js +137 -0
  31. package/lib/components/image/ImageToolbar.js.map +1 -0
  32. package/lib/components/image/InsertImageHandler.js +135 -0
  33. package/lib/components/image/InsertImageHandler.js.map +1 -0
  34. package/lib/components/media/MediaDialog.js +594 -0
  35. package/lib/components/media/MediaDialog.js.map +1 -0
  36. package/lib/components/media/MediaToolbar.js +74 -0
  37. package/lib/components/media/MediaToolbar.js.map +1 -0
  38. package/lib/components/media/MediaWrapper.js +67 -0
  39. package/lib/components/media/MediaWrapper.js.map +1 -0
  40. package/lib/components/respArea/DragInTheBlank/DragInTheBlank.js +84 -0
  41. package/lib/components/respArea/DragInTheBlank/DragInTheBlank.js.map +1 -0
  42. package/lib/components/respArea/DragInTheBlank/choice.js +250 -0
  43. package/lib/components/respArea/DragInTheBlank/choice.js.map +1 -0
  44. package/lib/components/respArea/ExplicitConstructedResponse.js +136 -0
  45. package/lib/components/respArea/ExplicitConstructedResponse.js.map +1 -0
  46. package/lib/components/respArea/InlineDropdown.js +209 -0
  47. package/lib/components/respArea/InlineDropdown.js.map +1 -0
  48. package/lib/components/respArea/MathTemplated.js +130 -0
  49. package/lib/components/respArea/MathTemplated.js.map +1 -0
  50. package/lib/components/respArea/ToolbarIcon.js +81 -0
  51. package/lib/components/respArea/ToolbarIcon.js.map +1 -0
  52. package/lib/components/respArea/inlineDropdownUtils.js +67 -0
  53. package/lib/components/respArea/inlineDropdownUtils.js.map +1 -0
  54. package/lib/constants.js +11 -0
  55. package/lib/constants.js.map +1 -0
  56. package/lib/extensions/css.js +217 -0
  57. package/lib/extensions/css.js.map +1 -0
  58. package/lib/extensions/custom-toolbar-wrapper.js +92 -0
  59. package/lib/extensions/custom-toolbar-wrapper.js.map +1 -0
  60. package/lib/extensions/div-node.js +83 -0
  61. package/lib/extensions/div-node.js.map +1 -0
  62. package/lib/extensions/ensure-empty-root-div.js +48 -0
  63. package/lib/extensions/ensure-empty-root-div.js.map +1 -0
  64. package/lib/extensions/ensure-list-item-content-is-div.js +64 -0
  65. package/lib/extensions/ensure-list-item-content-is-div.js.map +1 -0
  66. package/lib/extensions/extended-list-item.js +15 -0
  67. package/lib/extensions/extended-list-item.js.map +1 -0
  68. package/lib/extensions/extended-table-cell.js +22 -0
  69. package/lib/extensions/extended-table-cell.js.map +1 -0
  70. package/lib/extensions/extended-table.js +75 -0
  71. package/lib/extensions/extended-table.js.map +1 -0
  72. package/lib/extensions/heading-paragraph.js +61 -0
  73. package/lib/extensions/heading-paragraph.js.map +1 -0
  74. package/lib/extensions/image-component.js +348 -0
  75. package/lib/extensions/image-component.js.map +1 -0
  76. package/lib/extensions/image.js +134 -0
  77. package/lib/extensions/image.js.map +1 -0
  78. package/lib/extensions/index.js +46 -0
  79. package/lib/extensions/index.js.map +1 -0
  80. package/lib/extensions/math.js +342 -0
  81. package/lib/extensions/math.js.map +1 -0
  82. package/lib/extensions/media.js +243 -0
  83. package/lib/extensions/media.js.map +1 -0
  84. package/lib/extensions/responseArea.js +446 -0
  85. package/lib/extensions/responseArea.js.map +1 -0
  86. package/lib/index.js +37 -0
  87. package/lib/index.js.map +1 -0
  88. package/lib/styles/editorContainerStyles.js +137 -0
  89. package/lib/styles/editorContainerStyles.js.map +1 -0
  90. package/lib/theme.js +8 -0
  91. package/lib/theme.js.map +1 -0
  92. package/lib/utils/helper.js +73 -0
  93. package/lib/utils/helper.js.map +1 -0
  94. package/lib/utils/size.js +26 -0
  95. package/lib/utils/size.js.map +1 -0
  96. package/package.json +24 -40
  97. package/src/__tests__/EditableHtml.test.jsx +554 -0
  98. package/src/__tests__/constants.test.js +19 -0
  99. package/src/__tests__/div-to-paragraph-conversion.test.jsx +125 -0
  100. package/src/__tests__/extensions.test.js +208 -0
  101. package/src/__tests__/index.test.jsx +154 -0
  102. package/src/__tests__/size-utils.test.js +64 -0
  103. package/src/__tests__/theme.test.js +17 -0
  104. package/src/components/CharacterPicker.jsx +207 -0
  105. package/src/components/EditableHtml.jsx +440 -0
  106. package/src/components/MenuBar.jsx +554 -0
  107. package/src/components/TiptapContainer.jsx +219 -0
  108. package/src/components/__tests__/AltDialog.test.jsx +147 -0
  109. package/src/components/__tests__/CharacterPicker.test.jsx +261 -0
  110. package/src/components/__tests__/CssIcon.test.jsx +46 -0
  111. package/src/components/__tests__/DragInTheBlank.test.jsx +255 -0
  112. package/src/components/__tests__/ExplicitConstructedResponse.test.jsx +204 -0
  113. package/src/components/__tests__/ImageToolbar.test.jsx +128 -0
  114. package/src/components/__tests__/InlineDropdown.test.jsx +388 -0
  115. package/src/components/__tests__/InsertImageHandler.test.js +161 -0
  116. package/src/components/__tests__/MediaDialog.test.jsx +293 -0
  117. package/src/components/__tests__/MediaToolbar.test.jsx +74 -0
  118. package/src/components/__tests__/MediaWrapper.test.jsx +81 -0
  119. package/src/components/__tests__/MenuBar.test.jsx +250 -0
  120. package/src/components/__tests__/RespArea.test.jsx +122 -0
  121. package/src/components/__tests__/TableIcons.test.jsx +149 -0
  122. package/src/components/__tests__/TextAlign.test.jsx +167 -0
  123. package/src/components/__tests__/TiptapContainer.test.jsx +138 -0
  124. package/src/components/__tests__/characterUtils.test.js +166 -0
  125. package/src/components/__tests__/choice.test.jsx +171 -0
  126. package/src/components/__tests__/custom-popper.test.jsx +82 -0
  127. package/src/components/__tests__/done-button.test.jsx +54 -0
  128. package/src/components/__tests__/toolbar-buttons.test.jsx +234 -0
  129. package/src/components/characters/characterUtils.js +447 -0
  130. package/src/components/characters/custom-popper.js +38 -0
  131. package/src/components/common/done-button.jsx +27 -0
  132. package/src/components/common/toolbar-buttons.jsx +122 -0
  133. package/src/components/icons/CssIcon.jsx +15 -0
  134. package/src/components/icons/RespArea.jsx +71 -0
  135. package/src/components/icons/TableIcons.jsx +52 -0
  136. package/src/components/icons/TextAlign.jsx +114 -0
  137. package/src/components/image/AltDialog.jsx +82 -0
  138. package/src/components/image/ImageToolbar.jsx +99 -0
  139. package/src/components/image/InsertImageHandler.js +107 -0
  140. package/src/components/media/MediaDialog.jsx +596 -0
  141. package/src/components/media/MediaToolbar.jsx +49 -0
  142. package/src/components/media/MediaWrapper.jsx +39 -0
  143. package/src/components/respArea/DragInTheBlank/DragInTheBlank.jsx +76 -0
  144. package/src/components/respArea/DragInTheBlank/choice.jsx +256 -0
  145. package/src/components/respArea/ExplicitConstructedResponse.jsx +135 -0
  146. package/src/components/respArea/InlineDropdown.jsx +220 -0
  147. package/src/components/respArea/MathTemplated.jsx +124 -0
  148. package/src/components/respArea/ToolbarIcon.jsx +66 -0
  149. package/src/components/respArea/__tests__/MathTemplated.test.jsx +210 -0
  150. package/src/components/respArea/inlineDropdownUtils.js +79 -0
  151. package/src/constants.js +5 -0
  152. package/src/extensions/__tests__/css.test.js +196 -0
  153. package/src/extensions/__tests__/custom-toolbar-wrapper.test.jsx +180 -0
  154. package/src/extensions/__tests__/divNode.test.js +87 -0
  155. package/src/extensions/__tests__/ensure-empty-root-div.test.js +57 -0
  156. package/src/extensions/__tests__/ensure-list-item-content-is-div.test.js +44 -0
  157. package/src/extensions/__tests__/extended-list-item.test.js +13 -0
  158. package/src/extensions/__tests__/extended-table-cell.test.js +22 -0
  159. package/src/extensions/__tests__/extended-table.test.js +183 -0
  160. package/src/extensions/__tests__/image-component.test.jsx +345 -0
  161. package/src/extensions/__tests__/image.test.js +237 -0
  162. package/src/extensions/__tests__/math.test.js +603 -0
  163. package/src/extensions/__tests__/media-node-view.test.jsx +298 -0
  164. package/src/extensions/__tests__/media.test.js +271 -0
  165. package/src/extensions/__tests__/responseArea.test.js +601 -0
  166. package/src/extensions/css.js +220 -0
  167. package/src/extensions/custom-toolbar-wrapper.jsx +78 -0
  168. package/src/extensions/div-node.js +86 -0
  169. package/src/extensions/ensure-empty-root-div.js +47 -0
  170. package/src/extensions/ensure-list-item-content-is-div.js +62 -0
  171. package/src/extensions/extended-list-item.js +10 -0
  172. package/src/extensions/extended-table-cell.js +19 -0
  173. package/src/extensions/extended-table.js +60 -0
  174. package/src/extensions/heading-paragraph.js +53 -0
  175. package/src/extensions/image-component.jsx +338 -0
  176. package/src/extensions/image.js +109 -0
  177. package/src/extensions/index.js +81 -0
  178. package/src/extensions/math.js +326 -0
  179. package/src/extensions/media.js +188 -0
  180. package/src/extensions/responseArea.js +401 -0
  181. package/src/index.jsx +5 -0
  182. package/src/styles/editorContainerStyles.js +145 -0
  183. package/src/theme.js +1 -0
  184. package/src/utils/__tests__/helper.test.js +126 -0
  185. package/src/utils/helper.js +69 -0
  186. package/src/utils/size.js +32 -0
  187. package/dist/components/CharacterPicker.d.ts +0 -31
  188. package/dist/components/CharacterPicker.js +0 -131
  189. package/dist/components/EditableHtml.d.ts +0 -11
  190. package/dist/components/EditableHtml.js +0 -291
  191. package/dist/components/MenuBar.d.ts +0 -11
  192. package/dist/components/MenuBar.js +0 -462
  193. package/dist/components/TiptapContainer.d.ts +0 -11
  194. package/dist/components/TiptapContainer.js +0 -154
  195. package/dist/components/characters/characterUtils.d.ts +0 -35
  196. package/dist/components/characters/characterUtils.js +0 -465
  197. package/dist/components/characters/custom-popper.d.ts +0 -14
  198. package/dist/components/characters/custom-popper.js +0 -32
  199. package/dist/components/common/done-button.d.ts +0 -30
  200. package/dist/components/common/done-button.js +0 -26
  201. package/dist/components/common/toolbar-buttons.d.ts +0 -38
  202. package/dist/components/common/toolbar-buttons.js +0 -91
  203. package/dist/components/icons/CssIcon.d.ts +0 -11
  204. package/dist/components/icons/CssIcon.js +0 -14
  205. package/dist/components/icons/RespArea.d.ts +0 -26
  206. package/dist/components/icons/RespArea.js +0 -42
  207. package/dist/components/icons/TableIcons.d.ts +0 -14
  208. package/dist/components/icons/TableIcons.js +0 -32
  209. package/dist/components/icons/TextAlign.d.ts +0 -18
  210. package/dist/components/icons/TextAlign.js +0 -134
  211. package/dist/components/image/AltDialog.d.ts +0 -22
  212. package/dist/components/image/AltDialog.js +0 -61
  213. package/dist/components/image/ImageToolbar.d.ts +0 -24
  214. package/dist/components/image/ImageToolbar.js +0 -80
  215. package/dist/components/image/InsertImageHandler.d.ts +0 -32
  216. package/dist/components/image/InsertImageHandler.js +0 -53
  217. package/dist/components/media/MediaDialog.d.ts +0 -43
  218. package/dist/components/media/MediaDialog.js +0 -389
  219. package/dist/components/media/MediaToolbar.d.ts +0 -19
  220. package/dist/components/media/MediaToolbar.js +0 -41
  221. package/dist/components/media/MediaWrapper.d.ts +0 -19
  222. package/dist/components/respArea/DragInTheBlank/DragInTheBlank.d.ts +0 -23
  223. package/dist/components/respArea/DragInTheBlank/DragInTheBlank.js +0 -58
  224. package/dist/components/respArea/DragInTheBlank/choice.d.ts +0 -56
  225. package/dist/components/respArea/DragInTheBlank/choice.js +0 -156
  226. package/dist/components/respArea/ExplicitConstructedResponse.d.ts +0 -20
  227. package/dist/components/respArea/ExplicitConstructedResponse.js +0 -83
  228. package/dist/components/respArea/InlineDropdown.d.ts +0 -18
  229. package/dist/components/respArea/InlineDropdown.js +0 -119
  230. package/dist/components/respArea/MathTemplated.d.ts +0 -19
  231. package/dist/components/respArea/MathTemplated.js +0 -97
  232. package/dist/components/respArea/ToolbarIcon.d.ts +0 -14
  233. package/dist/components/respArea/ToolbarIcon.js +0 -17
  234. package/dist/components/respArea/inlineDropdownUtils.d.ts +0 -15
  235. package/dist/components/respArea/inlineDropdownUtils.js +0 -15
  236. package/dist/constants.d.ts +0 -13
  237. package/dist/constants.js +0 -4
  238. package/dist/extensions/css.d.ts +0 -11
  239. package/dist/extensions/css.js +0 -115
  240. package/dist/extensions/custom-toolbar-wrapper.d.ts +0 -11
  241. package/dist/extensions/custom-toolbar-wrapper.js +0 -61
  242. package/dist/extensions/div-node.d.ts +0 -10
  243. package/dist/extensions/div-node.js +0 -42
  244. package/dist/extensions/ensure-empty-root-div.d.ts +0 -14
  245. package/dist/extensions/ensure-empty-root-div.js +0 -24
  246. package/dist/extensions/ensure-list-item-content-is-div.d.ts +0 -15
  247. package/dist/extensions/ensure-list-item-content-is-div.js +0 -31
  248. package/dist/extensions/extended-list-item.d.ts +0 -13
  249. package/dist/extensions/extended-list-item.js +0 -5
  250. package/dist/extensions/extended-table-cell.d.ts +0 -10
  251. package/dist/extensions/extended-table-cell.js +0 -6
  252. package/dist/extensions/extended-table.d.ts +0 -17
  253. package/dist/extensions/extended-table.js +0 -34
  254. package/dist/extensions/heading-paragraph.d.ts +0 -17
  255. package/dist/extensions/heading-paragraph.js +0 -30
  256. package/dist/extensions/image-component.d.ts +0 -22
  257. package/dist/extensions/image-component.js +0 -220
  258. package/dist/extensions/image.d.ts +0 -10
  259. package/dist/extensions/image.js +0 -68
  260. package/dist/extensions/index.d.ts +0 -16
  261. package/dist/extensions/index.js +0 -64
  262. package/dist/extensions/math.d.ts +0 -15
  263. package/dist/extensions/math.js +0 -158
  264. package/dist/extensions/media.d.ts +0 -19
  265. package/dist/extensions/media.js +0 -149
  266. package/dist/extensions/responseArea.d.ts +0 -27
  267. package/dist/extensions/responseArea.js +0 -259
  268. package/dist/index.d.ts +0 -13
  269. package/dist/index.js +0 -7
  270. package/dist/node_modules/.bun/clsx@2.1.1/node_modules/clsx/dist/clsx.js +0 -16
  271. package/dist/styles/editorContainerStyles.d.ts +0 -134
  272. package/dist/theme.d.ts +0 -9
  273. package/dist/utils/helper.d.ts +0 -9
  274. package/dist/utils/helper.js +0 -27
  275. package/dist/utils/size.d.ts +0 -9
  276. package/dist/utils/size.js +0 -14
@@ -0,0 +1,440 @@
1
+ import React, { useCallback, useEffect, useMemo, useState } from 'react';
2
+ import debounce from 'lodash-es/debounce';
3
+ import { EditorContent, useEditor, useEditorState } from '@tiptap/react';
4
+ import { styled } from '@mui/material/styles';
5
+ import StarterKit from '@tiptap/starter-kit';
6
+ import { TextStyleKit } from '@tiptap/extension-text-style';
7
+ import { CharacterCount } from '@tiptap/extension-character-count';
8
+ import SuperScript from '@tiptap/extension-superscript';
9
+ import SubScript from '@tiptap/extension-subscript';
10
+ import TextAlign from '@tiptap/extension-text-align';
11
+ import Image from '@tiptap/extension-image';
12
+ import Placeholder from '@tiptap/extension-placeholder';
13
+ import { normalizeInitialMarkup } from '../utils/helper';
14
+
15
+ import ExtendedTable from '../extensions/extended-table';
16
+ import { ExtendedTableCell, ExtendedTableHeader } from '../extensions/extended-table-cell';
17
+ import { DivNode } from '../extensions/div-node';
18
+ import { EnsureEmptyRootIsDiv } from '../extensions/ensure-empty-root-div';
19
+ import { EnsureListItemContentIsDiv } from '../extensions/ensure-list-item-content-is-div';
20
+ import { TableRow } from '@tiptap/extension-table-row';
21
+ import {
22
+ DragInTheBlankNode,
23
+ ExplicitConstructedResponseNode,
24
+ InlineDropdownNode,
25
+ MathTemplatedNode,
26
+ ResponseAreaExtension,
27
+ } from '../extensions/responseArea';
28
+ import { MathNode } from '../extensions/math';
29
+ import { ImageUploadNode } from '../extensions/image';
30
+ import { Media } from '../extensions/media';
31
+ import { CSSMark } from '../extensions/css';
32
+ import { ExtendedListItem } from '../extensions/extended-list-item';
33
+ import { HeadingParagraph } from '../extensions/heading-paragraph';
34
+
35
+ import EditorContainer from './TiptapContainer';
36
+ import { valueToSize } from '../utils/size';
37
+ import { buildExtensions, PLUGINS_MAP } from '../extensions';
38
+
39
+ const defaultToolbarOpts = {
40
+ position: 'bottom',
41
+ alignment: 'left',
42
+ alwaysVisible: false,
43
+ showDone: true,
44
+ doneOn: 'blur',
45
+ };
46
+
47
+ const defaultResponseAreaProps = {
48
+ options: {},
49
+ respAreaToolbar: () => {},
50
+ onHandleAreaChange: () => {},
51
+ };
52
+
53
+ const DEFAULT_ACTIVE_PLUGINS = [
54
+ 'bold',
55
+ 'italic',
56
+ 'underline',
57
+ 'strikethrough',
58
+ 'code',
59
+ 'bulleted-list',
60
+ 'numbered-list',
61
+ 'image',
62
+ 'math',
63
+ 'languageCharacters',
64
+ 'text-align',
65
+ 'table',
66
+ 'video',
67
+ 'audio',
68
+ 'responseArea',
69
+ 'superscript',
70
+ 'subscript',
71
+ 'css',
72
+ 'h3',
73
+ 'undo',
74
+ 'redo',
75
+ ];
76
+
77
+ const cssVariables = {
78
+ '--white': '#fff',
79
+ '--black': '#2e2b29',
80
+ '--black-contrast': '#110f0e',
81
+ '--gray-1': 'rgba(61, 37, 20, .05)',
82
+ '--gray-2': 'rgba(61, 37, 20, .08)',
83
+ '--gray-3': 'rgba(61, 37, 20, .12)',
84
+ '--gray-4': 'rgba(53, 38, 28, .3)',
85
+ '--gray-5': 'rgba(28, 25, 23, .6)',
86
+ '--green': '#22c55e',
87
+ '--purple': '#6a00f5',
88
+ '--purple-contrast': '#5800cc',
89
+ '--purple-light': 'rgba(88, 5, 255, .05)',
90
+ '--yellow-contrast': '#facc15',
91
+ '--yellow': 'rgba(250, 204, 21, .4)',
92
+ '--yellow-light': '#fffae5',
93
+ '--red': '#ff5c33',
94
+ '--red-light': '#ffebe5',
95
+ '--shadow': `0px 12px 33px 0px rgba(0, 0, 0, .06),
96
+ 0px 3.618px 9.949px 0px rgba(0, 0, 0, .04)`,
97
+ };
98
+
99
+ export const EditableHtml = (props) => {
100
+ const { showParagraphs, separateParagraphs } = props.pluginProps || {};
101
+ const [pendingImages, setPendingImages] = useState([]);
102
+ const [scheduled, setScheduled] = useState(false);
103
+ const { toolbarOpts } = props;
104
+
105
+ const removePendingImage = useCallback(
106
+ (imagePos) => {
107
+ setPendingImages((prev) => {
108
+ const next = prev.filter((img) => img.pos !== imagePos);
109
+ if (next.length === 0) {
110
+ setScheduled(false);
111
+ }
112
+ return next;
113
+ });
114
+ },
115
+ [setPendingImages],
116
+ );
117
+
118
+ const toolbarOptsToUse = {
119
+ ...defaultToolbarOpts,
120
+ ...toolbarOpts,
121
+ };
122
+
123
+ const activePluginsToUse = useMemo(() => {
124
+ let { customPlugins, ...otherPluginProps } = props.pluginProps || {};
125
+
126
+ customPlugins = customPlugins || [];
127
+
128
+ const filteredActivePlugins = (props.activePlugins || DEFAULT_ACTIVE_PLUGINS)?.filter((pluginName) => {
129
+ const nameToUse = PLUGINS_MAP[pluginName] || pluginName;
130
+ const pluginInfo = otherPluginProps[nameToUse] || {};
131
+
132
+ return !pluginInfo || !pluginInfo.disabled;
133
+ });
134
+
135
+ return buildExtensions(filteredActivePlugins, customPlugins, {
136
+ math: {},
137
+ textAlign: props.textAlign,
138
+ html: {},
139
+ extraCSSRules: props.extraCSSRules || {},
140
+ image: {
141
+ ...props.imageSupport,
142
+ },
143
+ toolbar: {},
144
+ table: {},
145
+ responseArea: {
146
+ type: props.responseAreaProps?.type,
147
+ },
148
+ languageCharacters: props.languageCharactersProps,
149
+ keyPadCharacterRef: {},
150
+ setKeypadInteraction: {},
151
+ media: {},
152
+ });
153
+ }, [props]);
154
+
155
+ const extensions = [
156
+ TextAlign.configure({
157
+ types: ['heading', 'paragraph', 'div', 'headingParagraph', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'td', 'th'],
158
+ alignments: ['left', 'right', 'center', 'justify'],
159
+ }),
160
+ TextStyleKit,
161
+ CharacterCount.configure({
162
+ limit: props.charactersLimit || 1000000,
163
+ }),
164
+ StarterKit.configure({
165
+ trailingNode: {
166
+ node: 'paragraph',
167
+ notAfter: ['paragraph', 'div'],
168
+ },
169
+ }),
170
+ ExtendedListItem,
171
+ DivNode,
172
+ HeadingParagraph,
173
+ EnsureEmptyRootIsDiv,
174
+ EnsureListItemContentIsDiv,
175
+ Placeholder.configure({
176
+ placeholder: props.placeholder,
177
+ // show placeholder even when editor is focused
178
+ showOnlyWhenEditable: true,
179
+ showOnlyCurrent: false, // show on all empty nodes, not only the current one
180
+ includeChildren: true,
181
+ }),
182
+ ExtendedTable,
183
+ TableRow,
184
+ ExtendedTableHeader,
185
+ ExtendedTableCell,
186
+ ResponseAreaExtension.configure(props.responseAreaProps),
187
+ ExplicitConstructedResponseNode.configure(props.responseAreaProps),
188
+ DragInTheBlankNode.configure(props.responseAreaProps),
189
+ InlineDropdownNode.configure(props.responseAreaProps),
190
+ MathTemplatedNode.configure(props.responseAreaProps),
191
+ MathNode.configure({
192
+ toolbarOpts: toolbarOptsToUse,
193
+ math: props.pluginProps?.math || {},
194
+ }),
195
+ SubScript,
196
+ SuperScript,
197
+ Image,
198
+ ImageUploadNode.configure({
199
+ toolbarOpts: toolbarOptsToUse,
200
+ imageHandling: {
201
+ disableImageAlignmentButtons: props.disableImageAlignmentButtons,
202
+ onDone: (editor) => props.onDone?.(editor.getHTML()),
203
+ onDelete:
204
+ props.imageSupport &&
205
+ props.imageSupport.delete &&
206
+ ((node) => {
207
+ const { src } = node.attrs;
208
+
209
+ props.imageSupport.delete(src, (e) => {
210
+ removePendingImage(node.pos);
211
+ });
212
+ }),
213
+ insertImageRequested:
214
+ props.imageSupport &&
215
+ ((editor, imageInfo, getHandler) => {
216
+ const [addedImage, pos] = imageInfo;
217
+
218
+ const onFinish = (result) => {
219
+ let cb;
220
+
221
+ if (scheduled && result) {
222
+ // finish editing only on success
223
+ cb = props.onChange;
224
+ }
225
+
226
+ removePendingImage(pos);
227
+ cb?.(editor.getHTML());
228
+ };
229
+
230
+ const callback = () => {
231
+ /**
232
+ * The handler is the object through which the outer context
233
+ * communicates file upload events like: fileChosen, cancel, progress
234
+ */
235
+ const handler = getHandler(onFinish);
236
+
237
+ // If the user closes the file picker without choosing a file, the window regains
238
+ // focus while _insertingImage is still true — drop the stale pending entry.
239
+ const focusHandler = debounce(() => {
240
+ const detach = () => window.removeEventListener('focus', focusHandler);
241
+
242
+ if (!editor._insertingImage) {
243
+ detach();
244
+ return;
245
+ }
246
+
247
+ removePendingImage(pos);
248
+ editor._insertingImage = false;
249
+ detach();
250
+ }, 500);
251
+
252
+ window.addEventListener('focus', focusHandler);
253
+
254
+ props.imageSupport.add(handler);
255
+ };
256
+
257
+ editor._insertingImage = true;
258
+ setPendingImages((prev) => [...prev, addedImage]);
259
+ callback();
260
+ }),
261
+ maxImageWidth: props.maxImageWidth,
262
+ maxImageHeight: props.maxImageHeight,
263
+ },
264
+ limit: 3,
265
+ }),
266
+ Media.configure({
267
+ uploadSoundSupport: props.uploadSoundSupport,
268
+ }),
269
+ CSSMark.configure({
270
+ extraCSSRules: props.extraCSSRules,
271
+ }),
272
+ ];
273
+
274
+ const editor = useEditor(
275
+ {
276
+ extensions,
277
+ immediatelyRender: false,
278
+ editorProps: {
279
+ handleKeyDown(view, event) {
280
+ if (props.onKeyDown) {
281
+ return props.onKeyDown(event);
282
+ }
283
+
284
+ // Return false to let default behavior continue
285
+ return false;
286
+ },
287
+ },
288
+ editable: !props.disabled,
289
+ content: normalizeInitialMarkup(props.markup),
290
+ onUpdate: ({ editor, transaction }) => {
291
+ if (transaction.isDone) {
292
+ props.onChange?.(editor.getHTML());
293
+ }
294
+ },
295
+ onBlur: ({ editor }) => {
296
+ const otherToolbarOpened =
297
+ editor._insertingImage ||
298
+ editor._toolbarOpened ||
299
+ editor.isActive('inline_dropdown') ||
300
+ editor.isActive('explicit_constructed_response');
301
+
302
+ if (otherToolbarOpened || !editor.schema) {
303
+ return;
304
+ }
305
+
306
+ const html = editor.getHTML();
307
+
308
+ if (props.markup !== html) {
309
+ props.onChange?.(html);
310
+ }
311
+
312
+ if (toolbarOptsToUse.doneOn === 'blur') {
313
+ props.onDone?.(html);
314
+ }
315
+ },
316
+ },
317
+ [props.charactersLimit],
318
+ );
319
+
320
+ useEffect(() => {
321
+ if (props.editorRef) {
322
+ props.editorRef(editor);
323
+ }
324
+ }, [props.editorRef, editor]);
325
+
326
+ useEffect(() => {
327
+ editor?.setEditable(!props.disabled);
328
+ }, [props.disabled, editor]);
329
+
330
+ useEffect(() => {
331
+ if (!editor) {
332
+ return;
333
+ }
334
+ const nextMarkup = normalizeInitialMarkup(props.markup);
335
+
336
+ if (nextMarkup !== editor.getHTML()) {
337
+ editor.commands.setContent(nextMarkup, false);
338
+ }
339
+ }, [props.markup, editor]);
340
+
341
+ useEffect(() => {
342
+ Object.entries(cssVariables).forEach(([key, value]) => {
343
+ document.documentElement.style.setProperty(key, value);
344
+ });
345
+ }, []);
346
+
347
+ const editorState = useEditorState({
348
+ editor,
349
+ selector: (ctx) => ({
350
+ isFocused: ctx.editor?.isFocused,
351
+ }),
352
+ });
353
+
354
+ const sizeStyle = useMemo(() => {
355
+ const { minWidth, width, maxWidth, minHeight, height, maxHeight } = props;
356
+
357
+ return {
358
+ width: valueToSize(width),
359
+ minWidth: valueToSize(minWidth),
360
+ maxWidth: valueToSize(maxWidth),
361
+ height: valueToSize(height),
362
+ minHeight: valueToSize(minHeight),
363
+ maxHeight: valueToSize(maxHeight),
364
+ };
365
+ }, [props]);
366
+
367
+ return (
368
+ <EditorContainer
369
+ {...{
370
+ ...props,
371
+ activePlugins: activePluginsToUse,
372
+ toolbarOpts: toolbarOptsToUse,
373
+ }}
374
+ editorState={editorState}
375
+ editor={editor}
376
+ >
377
+ {editor && (
378
+ <StyledEditorContent
379
+ style={{
380
+ minHeight: sizeStyle.minHeight,
381
+ height: sizeStyle.height,
382
+ maxHeight: sizeStyle.maxHeight,
383
+ }}
384
+ showParagraph={showParagraphs && !showParagraphs.disabled}
385
+ separateParagraph={separateParagraphs && !separateParagraphs.disabled}
386
+ editor={editor}
387
+ />
388
+ )}
389
+ </EditorContainer>
390
+ );
391
+ };
392
+
393
+ const StyledEditorContent = styled(EditorContent, {
394
+ shouldForwardProp: (prop) => !['showParagraph', 'separateParagraph'].includes(prop),
395
+ })(({ showParagraph, separateParagraph }) => ({
396
+ display: 'flex',
397
+ outline: 'none !important',
398
+ '& .ProseMirror': {
399
+ flex: 1,
400
+ padding: '5px',
401
+ maxHeight: '500px',
402
+ outline: 'none !important',
403
+ position: 'initial',
404
+
405
+ // reset default margins for all block paragraphs/divs in the editor
406
+ '& > p, & > div': {
407
+ margin: '0',
408
+ },
409
+
410
+ // Out of flow so the caret stays at the start of the block; in-flow ::before pushes the caret after the hint text.
411
+ '& p.is-editor-empty, & div.is-editor-empty': {
412
+ position: 'relative',
413
+ },
414
+ '& p.is-editor-empty::before, & div.is-editor-empty::before': {
415
+ content: 'attr(data-placeholder)',
416
+ position: 'absolute',
417
+ left: 0,
418
+ top: 0,
419
+ color: '#9CA3AF',
420
+ pointerEvents: 'none',
421
+ whiteSpace: 'pre-wrap',
422
+ },
423
+
424
+ ...(showParagraph && {
425
+ '& > p:has(+ p)::after, & > div:has(+ div)::after': {
426
+ display: 'block',
427
+ content: '"¶"',
428
+ fontSize: '1em',
429
+ color: '#146EB3',
430
+ },
431
+ }),
432
+ ...(separateParagraph && {
433
+ '& > p:has(+ p)': {
434
+ marginBottom: '1em',
435
+ },
436
+ }),
437
+ },
438
+ }));
439
+
440
+ export default EditableHtml;