@pie-lib/editable-html 11.1.1 → 11.3.0-beta.0

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 (194) hide show
  1. package/CHANGELOG.md +8 -4
  2. package/NEXT.CHANGELOG.json +1 -0
  3. package/lib/__tests__/editor.test.js +470 -0
  4. package/lib/__tests__/serialization.test.js +246 -0
  5. package/lib/__tests__/utils.js +106 -0
  6. package/lib/block-tags.js +25 -0
  7. package/lib/constants.js +16 -0
  8. package/lib/editor.js +349 -88
  9. package/lib/index.js +26 -10
  10. package/lib/parse-html.js +1 -1
  11. package/lib/plugins/characters/custom-popper.js +1 -1
  12. package/lib/plugins/characters/index.js +9 -4
  13. package/lib/plugins/characters/utils.js +13 -13
  14. package/lib/plugins/css/icons/index.js +37 -0
  15. package/lib/plugins/css/index.js +397 -0
  16. package/lib/plugins/customPlugin/index.js +114 -0
  17. package/lib/plugins/html/icons/index.js +1 -1
  18. package/lib/plugins/html/index.js +12 -8
  19. package/lib/plugins/image/__tests__/component.test.js +51 -0
  20. package/lib/plugins/image/__tests__/image-toolbar-logic.test.js +56 -0
  21. package/lib/plugins/image/__tests__/image-toolbar.test.js +26 -0
  22. package/lib/plugins/image/__tests__/index.test.js +98 -0
  23. package/lib/plugins/image/__tests__/insert-image-handler.test.js +125 -0
  24. package/lib/plugins/image/__tests__/mock-change.js +25 -0
  25. package/lib/plugins/image/alt-dialog.js +1 -1
  26. package/lib/plugins/image/component.js +1 -1
  27. package/lib/plugins/image/image-toolbar.js +1 -1
  28. package/lib/plugins/image/index.js +3 -2
  29. package/lib/plugins/image/insert-image-handler.js +14 -5
  30. package/lib/plugins/index.js +271 -12
  31. package/lib/plugins/list/__tests__/index.test.js +79 -0
  32. package/lib/plugins/list/index.js +131 -1
  33. package/lib/plugins/math/__tests__/index.test.js +300 -0
  34. package/lib/plugins/math/index.js +92 -57
  35. package/lib/plugins/media/__tests__/index.test.js +71 -0
  36. package/lib/plugins/media/index.js +6 -3
  37. package/lib/plugins/media/media-dialog.js +99 -58
  38. package/lib/plugins/media/media-toolbar.js +1 -1
  39. package/lib/plugins/media/media-wrapper.js +1 -1
  40. package/lib/plugins/rendering/index.js +46 -0
  41. package/lib/plugins/respArea/drag-in-the-blank/choice.js +6 -3
  42. package/lib/plugins/respArea/drag-in-the-blank/index.js +1 -1
  43. package/lib/plugins/respArea/explicit-constructed-response/index.js +12 -10
  44. package/lib/plugins/respArea/icons/index.js +1 -1
  45. package/lib/plugins/respArea/index.js +70 -22
  46. package/lib/plugins/respArea/inline-dropdown/index.js +11 -6
  47. package/lib/plugins/respArea/math-templated/index.js +130 -0
  48. package/lib/plugins/respArea/utils.js +17 -2
  49. package/lib/plugins/table/CustomTablePlugin.js +133 -0
  50. package/lib/plugins/table/__tests__/index.test.js +442 -0
  51. package/lib/plugins/table/__tests__/table-toolbar.test.js +54 -0
  52. package/lib/plugins/table/icons/index.js +1 -1
  53. package/lib/plugins/table/index.js +44 -60
  54. package/lib/plugins/table/table-toolbar.js +34 -5
  55. package/lib/plugins/textAlign/icons/index.js +226 -0
  56. package/lib/plugins/textAlign/index.js +34 -0
  57. package/lib/plugins/toolbar/__tests__/default-toolbar.test.js +128 -0
  58. package/lib/plugins/toolbar/__tests__/editor-and-toolbar.test.js +51 -0
  59. package/lib/plugins/toolbar/__tests__/toolbar-buttons.test.js +54 -0
  60. package/lib/plugins/toolbar/__tests__/toolbar.test.js +120 -0
  61. package/lib/plugins/toolbar/default-toolbar.js +83 -28
  62. package/lib/plugins/toolbar/done-button.js +6 -3
  63. package/lib/plugins/toolbar/editor-and-toolbar.js +19 -20
  64. package/lib/plugins/toolbar/index.js +1 -1
  65. package/lib/plugins/toolbar/toolbar-buttons.js +45 -12
  66. package/lib/plugins/toolbar/toolbar.js +36 -12
  67. package/lib/plugins/utils.js +1 -1
  68. package/lib/serialization.js +234 -45
  69. package/lib/theme.js +1 -1
  70. package/package.json +6 -6
  71. package/src/__tests__/editor.test.jsx +363 -0
  72. package/src/__tests__/serialization.test.js +291 -0
  73. package/src/__tests__/utils.js +36 -0
  74. package/src/block-tags.js +17 -0
  75. package/src/constants.js +7 -0
  76. package/src/editor.jsx +303 -49
  77. package/src/index.jsx +19 -10
  78. package/src/plugins/characters/index.jsx +11 -3
  79. package/src/plugins/characters/utils.js +12 -12
  80. package/src/plugins/css/icons/index.jsx +17 -0
  81. package/src/plugins/css/index.jsx +346 -0
  82. package/src/plugins/customPlugin/index.jsx +85 -0
  83. package/src/plugins/html/index.jsx +9 -6
  84. package/src/plugins/image/__tests__/__snapshots__/component.test.jsx.snap +51 -0
  85. package/src/plugins/image/__tests__/__snapshots__/image-toolbar-logic.test.jsx.snap +27 -0
  86. package/src/plugins/image/__tests__/__snapshots__/image-toolbar.test.jsx.snap +44 -0
  87. package/src/plugins/image/__tests__/component.test.jsx +41 -0
  88. package/src/plugins/image/__tests__/image-toolbar-logic.test.jsx +42 -0
  89. package/src/plugins/image/__tests__/image-toolbar.test.jsx +11 -0
  90. package/src/plugins/image/__tests__/index.test.js +95 -0
  91. package/src/plugins/image/__tests__/insert-image-handler.test.js +113 -0
  92. package/src/plugins/image/__tests__/mock-change.js +15 -0
  93. package/src/plugins/image/index.jsx +2 -1
  94. package/src/plugins/image/insert-image-handler.js +13 -6
  95. package/src/plugins/index.jsx +248 -5
  96. package/src/plugins/list/__tests__/index.test.js +54 -0
  97. package/src/plugins/list/index.jsx +130 -0
  98. package/src/plugins/math/__tests__/__snapshots__/index.test.jsx.snap +48 -0
  99. package/src/plugins/math/__tests__/index.test.jsx +245 -0
  100. package/src/plugins/math/index.jsx +87 -56
  101. package/src/plugins/media/__tests__/index.test.js +75 -0
  102. package/src/plugins/media/index.jsx +3 -2
  103. package/src/plugins/media/media-dialog.js +106 -57
  104. package/src/plugins/rendering/index.js +31 -0
  105. package/src/plugins/respArea/drag-in-the-blank/choice.jsx +4 -1
  106. package/src/plugins/respArea/explicit-constructed-response/index.jsx +10 -8
  107. package/src/plugins/respArea/index.jsx +53 -7
  108. package/src/plugins/respArea/inline-dropdown/index.jsx +13 -6
  109. package/src/plugins/respArea/math-templated/index.jsx +104 -0
  110. package/src/plugins/respArea/utils.jsx +11 -0
  111. package/src/plugins/table/CustomTablePlugin.js +113 -0
  112. package/src/plugins/table/__tests__/__snapshots__/table-toolbar.test.jsx.snap +44 -0
  113. package/src/plugins/table/__tests__/index.test.jsx +401 -0
  114. package/src/plugins/table/__tests__/table-toolbar.test.jsx +42 -0
  115. package/src/plugins/table/index.jsx +46 -59
  116. package/src/plugins/table/table-toolbar.jsx +39 -2
  117. package/src/plugins/textAlign/icons/index.jsx +139 -0
  118. package/src/plugins/textAlign/index.jsx +23 -0
  119. package/src/plugins/toolbar/__tests__/__snapshots__/default-toolbar.test.jsx.snap +923 -0
  120. package/src/plugins/toolbar/__tests__/__snapshots__/editor-and-toolbar.test.jsx.snap +20 -0
  121. package/src/plugins/toolbar/__tests__/__snapshots__/toolbar-buttons.test.jsx.snap +36 -0
  122. package/src/plugins/toolbar/__tests__/__snapshots__/toolbar.test.jsx.snap +46 -0
  123. package/src/plugins/toolbar/__tests__/default-toolbar.test.jsx +94 -0
  124. package/src/plugins/toolbar/__tests__/editor-and-toolbar.test.jsx +37 -0
  125. package/src/plugins/toolbar/__tests__/toolbar-buttons.test.jsx +51 -0
  126. package/src/plugins/toolbar/__tests__/toolbar.test.jsx +106 -0
  127. package/src/plugins/toolbar/default-toolbar.jsx +80 -20
  128. package/src/plugins/toolbar/done-button.jsx +3 -1
  129. package/src/plugins/toolbar/editor-and-toolbar.jsx +18 -13
  130. package/src/plugins/toolbar/toolbar-buttons.jsx +52 -11
  131. package/src/plugins/toolbar/toolbar.jsx +31 -8
  132. package/src/serialization.jsx +213 -38
  133. package/README.md +0 -45
  134. package/deploy.sh +0 -16
  135. package/lib/editor.js.map +0 -1
  136. package/lib/index.js.map +0 -1
  137. package/lib/parse-html.js.map +0 -1
  138. package/lib/plugins/characters/custom-popper.js.map +0 -1
  139. package/lib/plugins/characters/index.js.map +0 -1
  140. package/lib/plugins/characters/utils.js.map +0 -1
  141. package/lib/plugins/html/icons/index.js.map +0 -1
  142. package/lib/plugins/html/index.js.map +0 -1
  143. package/lib/plugins/image/alt-dialog.js.map +0 -1
  144. package/lib/plugins/image/component.js.map +0 -1
  145. package/lib/plugins/image/image-toolbar.js.map +0 -1
  146. package/lib/plugins/image/index.js.map +0 -1
  147. package/lib/plugins/image/insert-image-handler.js.map +0 -1
  148. package/lib/plugins/index.js.map +0 -1
  149. package/lib/plugins/list/index.js.map +0 -1
  150. package/lib/plugins/math/index.js.map +0 -1
  151. package/lib/plugins/media/index.js.map +0 -1
  152. package/lib/plugins/media/media-dialog.js.map +0 -1
  153. package/lib/plugins/media/media-toolbar.js.map +0 -1
  154. package/lib/plugins/media/media-wrapper.js.map +0 -1
  155. package/lib/plugins/respArea/drag-in-the-blank/choice.js.map +0 -1
  156. package/lib/plugins/respArea/drag-in-the-blank/index.js.map +0 -1
  157. package/lib/plugins/respArea/explicit-constructed-response/index.js.map +0 -1
  158. package/lib/plugins/respArea/icons/index.js.map +0 -1
  159. package/lib/plugins/respArea/index.js.map +0 -1
  160. package/lib/plugins/respArea/inline-dropdown/index.js.map +0 -1
  161. package/lib/plugins/respArea/utils.js.map +0 -1
  162. package/lib/plugins/table/icons/index.js.map +0 -1
  163. package/lib/plugins/table/index.js.map +0 -1
  164. package/lib/plugins/table/table-toolbar.js.map +0 -1
  165. package/lib/plugins/toolbar/default-toolbar.js.map +0 -1
  166. package/lib/plugins/toolbar/done-button.js.map +0 -1
  167. package/lib/plugins/toolbar/editor-and-toolbar.js.map +0 -1
  168. package/lib/plugins/toolbar/index.js.map +0 -1
  169. package/lib/plugins/toolbar/toolbar-buttons.js.map +0 -1
  170. package/lib/plugins/toolbar/toolbar.js.map +0 -1
  171. package/lib/plugins/utils.js.map +0 -1
  172. package/lib/serialization.js.map +0 -1
  173. package/lib/theme.js.map +0 -1
  174. package/playground/image/data.js +0 -59
  175. package/playground/image/index.html +0 -22
  176. package/playground/image/index.jsx +0 -81
  177. package/playground/index.html +0 -25
  178. package/playground/mathquill/index.html +0 -22
  179. package/playground/mathquill/index.jsx +0 -155
  180. package/playground/package.json +0 -15
  181. package/playground/prod-test/index.html +0 -22
  182. package/playground/prod-test/index.jsx +0 -28
  183. package/playground/schema-override/data.js +0 -29
  184. package/playground/schema-override/image-plugin.jsx +0 -41
  185. package/playground/schema-override/index.html +0 -21
  186. package/playground/schema-override/index.jsx +0 -97
  187. package/playground/serialization/data.js +0 -29
  188. package/playground/serialization/image-plugin.jsx +0 -41
  189. package/playground/serialization/index.html +0 -22
  190. package/playground/serialization/index.jsx +0 -12
  191. package/playground/static.json +0 -3
  192. package/playground/table-examples.html +0 -70
  193. package/playground/webpack.config.js +0 -42
  194. package/static.json +0 -1
@@ -0,0 +1,363 @@
1
+ import React from 'react';
2
+ import { htmlToValue, valueToHtml } from '../index';
3
+ import { Editor } from '../editor';
4
+ import { shallow, configure } from 'enzyme';
5
+ import debug from 'debug';
6
+
7
+ import { mockComponents } from './utils';
8
+
9
+ const log = debug('@pie-lib:editable-html:test');
10
+
11
+ const value = htmlToValue('hi');
12
+
13
+ const resizeWindow = (width, height) => {
14
+ window.innerWidth = width;
15
+ window.innerHeight = height;
16
+ window.dispatchEvent(new Event('resize'));
17
+ };
18
+ jest.mock('@pie-lib/math-toolbar', () => ({}));
19
+ jest.mock('@pie-lib/math-input', () => {
20
+ HorizontalKeypad: () => <div>HorizontalKeypad</div>;
21
+ });
22
+
23
+ expect.extend({
24
+ toEqualHtml(value, html) {
25
+ const v = valueToHtml(value);
26
+ const pass = v === html;
27
+
28
+ return {
29
+ pass,
30
+ message: () => `expected ${html} to match ${v}`,
31
+ };
32
+ },
33
+ });
34
+
35
+ describe('logic', () => {
36
+ test('onFocus/onBlur saves the value', async () => {
37
+ const wrapper = shallow(
38
+ <Editor editorRef={jest.fn()} value={value} classes={{}} onChange={jest.fn()} onRef={jest.fn()} />,
39
+ );
40
+
41
+ await wrapper.instance().onFocus();
42
+
43
+ const v = htmlToValue('hi');
44
+
45
+ expect(wrapper.state('stashedValue')).toEqualHtml('<div>hi</div>');
46
+
47
+ wrapper.instance().onChange({ value: htmlToValue('new value') });
48
+
49
+ expect(wrapper.state('value')).toEqualHtml('<div>new value</div>');
50
+
51
+ return wrapper
52
+ .instance()
53
+ .onBlur({})
54
+ .then(() => {
55
+ expect(wrapper.state('value')).toEqualHtml('<div>new value</div>');
56
+ });
57
+ });
58
+ });
59
+
60
+ test('onFocus does not change focus if related target is a button from language keypad', async () => {
61
+ const wrapper = shallow(
62
+ <Editor editorRef={jest.fn()} value={value} classes={{}} onChange={jest.fn()} onRef={jest.fn()} />,
63
+ );
64
+
65
+ const event = {
66
+ relatedTarget: {
67
+ tagName: 'button',
68
+ },
69
+ };
70
+
71
+ const change = {
72
+ focus: jest.fn(),
73
+ };
74
+
75
+ wrapper.instance().keypadInteractionDetected = true;
76
+
77
+ await wrapper.instance().onFocus(event, change);
78
+
79
+ expect(change.focus).not.toHaveBeenCalled();
80
+ });
81
+
82
+ test('onFocus changes focus if related target is not a button from language keypad', async () => {
83
+ const wrapper = shallow(
84
+ <Editor editorRef={jest.fn()} value={value} classes={{}} onChange={jest.fn()} onRef={jest.fn()} />,
85
+ );
86
+
87
+ const event = {
88
+ relatedTarget: {
89
+ tagName: 'div',
90
+ },
91
+ };
92
+
93
+ const change = {
94
+ focus: jest.fn(),
95
+ };
96
+
97
+ await wrapper.instance().onFocus(event, change);
98
+
99
+ expect(change.focus).toHaveBeenCalled();
100
+ });
101
+
102
+ test('onFocus stashes the value', async () => {
103
+ const wrapper = shallow(
104
+ <Editor editorRef={jest.fn()} value={value} classes={{}} onChange={jest.fn()} onRef={jest.fn()} />,
105
+ );
106
+
107
+ await wrapper.instance().onFocus();
108
+
109
+ expect(wrapper.state('stashedValue')).toEqualHtml('<div>hi</div>');
110
+ });
111
+
112
+ test('onBlur does not set focusToolbar if related target is RawDoneButton', async () => {
113
+ const wrapper = shallow(
114
+ <Editor editorRef={jest.fn()} value={value} classes={{}} onChange={jest.fn()} onRef={jest.fn()} />,
115
+ );
116
+
117
+ const toolbarElement = document.createElement('div');
118
+ const relatedTarget = document.createElement('button');
119
+ relatedTarget.className = 'RawDoneButton';
120
+ toolbarElement.className = 'toolbar';
121
+ toolbarElement.appendChild(relatedTarget);
122
+
123
+ wrapper.instance().toolbarRef = toolbarElement;
124
+ wrapper.instance().doneButtonRef.current = relatedTarget;
125
+
126
+ const event = { relatedTarget };
127
+
128
+ await wrapper.instance().onBlur(event);
129
+
130
+ expect(wrapper.state('focusToolbar')).toBe(false);
131
+ });
132
+
133
+ test('handleToolbarFocus sets focusToolbar to true', () => {
134
+ const wrapper = shallow(
135
+ <Editor editorRef={jest.fn()} value={value} classes={{}} onChange={jest.fn()} onRef={jest.fn()} />,
136
+ );
137
+
138
+ wrapper.instance().handleToolbarFocus();
139
+ expect(wrapper.state('focusToolbar')).toBe(true);
140
+ });
141
+
142
+ test('handleToolbarBlur sets focusToolbar to false if toolbar does not contain focus', (done) => {
143
+ const wrapper = shallow(
144
+ <Editor editorRef={jest.fn()} value={value} classes={{}} onChange={jest.fn()} onRef={jest.fn()} />,
145
+ );
146
+
147
+ wrapper.instance().toolbarContainsFocus = jest.fn().mockReturnValue(false);
148
+
149
+ wrapper.instance().handleToolbarBlur();
150
+
151
+ setTimeout(() => {
152
+ expect(wrapper.state('focusToolbar')).toBe(false);
153
+ done();
154
+ }, 20);
155
+ });
156
+
157
+ test('handleToolbarBlur does not set focusToolbar to false if toolbar contains focus', (done) => {
158
+ const wrapper = shallow(
159
+ <Editor editorRef={jest.fn()} value={value} classes={{}} onChange={jest.fn()} onRef={jest.fn()} />,
160
+ );
161
+
162
+ wrapper.instance().toolbarContainsFocus = jest.fn().mockReturnValue(true);
163
+
164
+ wrapper.setState({ focusToolbar: true });
165
+
166
+ wrapper.instance().handleToolbarBlur();
167
+
168
+ setTimeout(() => {
169
+ expect(wrapper.state('focusToolbar')).toBe(true);
170
+ done();
171
+ }, 20);
172
+ });
173
+
174
+ test('toolbarContainsFocus correctly detects focus within toolbar', () => {
175
+ const wrapper = shallow(
176
+ <Editor editorRef={jest.fn()} value={value} classes={{}} onChange={jest.fn()} onRef={jest.fn()} />,
177
+ );
178
+
179
+ const toolbarElement = document.createElement('div');
180
+ const activeElement = document.createElement('button');
181
+ toolbarElement.appendChild(activeElement);
182
+
183
+ Object.defineProperty(document, 'activeElement', {
184
+ value: activeElement,
185
+ configurable: true,
186
+ });
187
+
188
+ wrapper.instance().toolbarRef = toolbarElement;
189
+
190
+ expect(wrapper.instance().toolbarContainsFocus()).toBe(true);
191
+
192
+ Object.defineProperty(document, 'activeElement', {
193
+ value: document.createElement('div'),
194
+ configurable: true,
195
+ });
196
+
197
+ expect(wrapper.instance().toolbarContainsFocus()).toBe(false);
198
+ });
199
+
200
+ test('onBlur sets focusToolbar to true if related target is within toolbar', async () => {
201
+ const wrapper = shallow(
202
+ <Editor editorRef={jest.fn()} value={value} classes={{}} onChange={jest.fn()} onRef={jest.fn()} />,
203
+ );
204
+
205
+ const toolbarElement = document.createElement('div');
206
+ const relatedTarget = document.createElement('button');
207
+ toolbarElement.className = 'toolbar';
208
+ toolbarElement.appendChild(relatedTarget);
209
+
210
+ wrapper.instance().toolbarRef = toolbarElement;
211
+
212
+ const event = { relatedTarget };
213
+
214
+ await wrapper.instance().onBlur(event);
215
+
216
+ expect(wrapper.state('focusToolbar')).toBe(true);
217
+ });
218
+
219
+ describe('buildSizeStyle', () => {
220
+ const wrapper = (extras) => {
221
+ const props = Object.assign({}, extras);
222
+ return shallow(
223
+ <Editor editorRef={jest.fn()} value={value} classes={{}} onChange={jest.fn()} onRef={jest.fn()} {...props} />,
224
+ );
225
+ };
226
+
227
+ it('builds width with px', () => {
228
+ const w = wrapper({ width: 100 });
229
+ expect(w.instance().buildSizeStyle()).toEqual({
230
+ width: '100px',
231
+ height: undefined,
232
+ minHeight: undefined,
233
+ maxHeight: undefined,
234
+ });
235
+ });
236
+
237
+ it('returns undefined for % ', () => {
238
+ const w = wrapper({ height: '100%', width: '100%' });
239
+ expect(w.instance().buildSizeStyle()).toEqual({
240
+ width: undefined,
241
+ height: undefined,
242
+ minHeight: undefined,
243
+ maxHeight: undefined,
244
+ });
245
+ });
246
+
247
+ it('builds height', () => {
248
+ const w = wrapper({ height: 100 });
249
+ expect(w.instance().buildSizeStyle()).toEqual({
250
+ width: undefined,
251
+ height: '100px',
252
+ minHeight: undefined,
253
+ maxHeight: undefined,
254
+ });
255
+ });
256
+
257
+ it('builds minHeight', () => {
258
+ const w = wrapper({ minHeight: 100 });
259
+ expect(w.instance().buildSizeStyle()).toEqual({
260
+ width: undefined,
261
+ height: undefined,
262
+ minHeight: '100px',
263
+ maxHeight: undefined,
264
+ });
265
+ });
266
+
267
+ it('builds maxHeight', () => {
268
+ const w = wrapper({ maxHeight: 100 });
269
+ expect(w.instance().buildSizeStyle()).toEqual({
270
+ width: undefined,
271
+ height: undefined,
272
+ minHeight: undefined,
273
+ maxHeight: '100px',
274
+ });
275
+ });
276
+
277
+ it('builds width with calc()', () => {
278
+ const w = wrapper({ width: 'calc(10em + 42px)' });
279
+ expect(w.instance().buildSizeStyle()).toEqual({
280
+ width: 'calc(10em + 42px)',
281
+ height: undefined,
282
+ minHeight: undefined,
283
+ maxHeight: undefined,
284
+ });
285
+ });
286
+
287
+ it('builds width with ch', () => {
288
+ const w = wrapper({ width: '9ch' });
289
+ expect(w.instance().buildSizeStyle()).toEqual({
290
+ width: '9ch',
291
+ height: undefined,
292
+ minHeight: undefined,
293
+ maxHeight: undefined,
294
+ });
295
+ });
296
+
297
+ it('builds', () => {
298
+ const w = wrapper({});
299
+ expect(w.instance().buildSizeStyle()).toEqual({
300
+ width: undefined,
301
+ height: undefined,
302
+ minHeight: undefined,
303
+ maxHeight: undefined,
304
+ });
305
+ });
306
+ });
307
+
308
+ describe('onResize', () => {
309
+ it('should display html of current state on Resize', () => {
310
+ const wrapper = shallow(
311
+ <Editor editorRef={jest.fn()} value={value} classes={{}} onChange={jest.fn()} onRef={jest.fn()} />,
312
+ );
313
+
314
+ resizeWindow(500, 300);
315
+ expect(wrapper.state('value')).toEqualHtml('<div>hi</div>');
316
+
317
+ wrapper.instance().onChange({ value: htmlToValue('new value') });
318
+ resizeWindow(1024, 768);
319
+ expect(wrapper.state('value')).toEqualHtml('<div>new value</div>');
320
+
321
+ resizeWindow(500, 300);
322
+ expect(wrapper.state('value')).toEqualHtml('<div>new value</div>');
323
+ });
324
+ });
325
+
326
+ describe('MathMl', () => {
327
+ beforeEach(() => {});
328
+
329
+ it('should not call runSerializationOnMarkup if mathMl props are not there', () => {
330
+ const runSerializationOnMarkup = jest.fn();
331
+
332
+ const wrapper = shallow(
333
+ <Editor
334
+ editorRef={jest.fn()}
335
+ value={value}
336
+ classes={{}}
337
+ onChange={jest.fn()}
338
+ onRef={jest.fn()}
339
+ runSerializationOnMarkup={runSerializationOnMarkup}
340
+ />,
341
+ );
342
+
343
+ expect(runSerializationOnMarkup).not.toHaveBeenCalled();
344
+ });
345
+
346
+ it('should call runSerializationOnMarkup if mmlEditing or mmlOutput are true', () => {
347
+ const runSerializationOnMarkup = jest.fn();
348
+
349
+ const wrapper = shallow(
350
+ <Editor
351
+ editorRef={jest.fn()}
352
+ value={value}
353
+ classes={{}}
354
+ onChange={jest.fn()}
355
+ onRef={jest.fn()}
356
+ runSerializationOnMarkup={runSerializationOnMarkup}
357
+ mathMlOptions={{ mmlOutput: true }}
358
+ />,
359
+ );
360
+
361
+ expect(runSerializationOnMarkup).toHaveBeenCalled();
362
+ });
363
+ });
@@ -0,0 +1,291 @@
1
+ import { htmlToValue, TEXT_RULE } from '../serialization';
2
+
3
+ jest.mock('../plugins/math', () => ({
4
+ serialization: {
5
+ serialize: jest.fn((o, c) => {
6
+ return undefined;
7
+ }),
8
+ deserialize: jest.fn((el, next) => {
9
+ return undefined;
10
+ }),
11
+ },
12
+ }));
13
+
14
+ describe('TEXT_RULE', () => {
15
+ const mkBr = (previousSibling) => {
16
+ return {
17
+ remove: jest.fn(),
18
+ previousSibling,
19
+ replaceWith: (foo) => {
20
+ previousSibling.textContent = previousSibling.textContent.replace(/(<br>)|(<\/br>)/g, foo);
21
+ },
22
+ normalize: jest.fn().mockReturnThis(),
23
+ tagName: 'br',
24
+ };
25
+ };
26
+
27
+ const mkTextNode = (textContent = '') => ({
28
+ nodeName: '#text',
29
+ textContent,
30
+ normalize: jest.fn().mockReturnThis(),
31
+ });
32
+
33
+ const mkEl = (querySelectorAllResult) => ({
34
+ querySelectorAll: jest.fn().mockReturnValue(querySelectorAllResult),
35
+ normalize: jest.fn().mockReturnThis(),
36
+ });
37
+
38
+ describe('deserialize', () => {
39
+ it('if no previous text node, no error is thrown', () => {
40
+ const br = mkBr();
41
+ const el = mkEl([br]);
42
+ expect(() => TEXT_RULE.deserialize(el)).not.toThrow();
43
+ });
44
+ });
45
+ });
46
+
47
+ describe('htmlToValue', () => {
48
+ it('converts', () => {
49
+ const expected = {
50
+ object: 'value',
51
+ document: {
52
+ object: 'document',
53
+ data: {},
54
+ nodes: [
55
+ {
56
+ object: 'block',
57
+ type: 'div',
58
+ isVoid: false,
59
+ data: {
60
+ attributes: {},
61
+ },
62
+ nodes: [
63
+ {
64
+ object: 'block',
65
+ type: 'paragraph',
66
+ isVoid: false,
67
+ data: {
68
+ attributes: {},
69
+ },
70
+ nodes: [
71
+ {
72
+ object: 'text',
73
+ leaves: [
74
+ {
75
+ object: 'leaf',
76
+ text: 'foo',
77
+ marks: [],
78
+ },
79
+ ],
80
+ },
81
+ {
82
+ object: 'inline',
83
+ type: 'image',
84
+ isVoid: true,
85
+ data: {
86
+ src: 'blah.jpg',
87
+ width: null,
88
+ height: null,
89
+ margin: '',
90
+ justifyContent: '',
91
+ alignment: null,
92
+ alt: null,
93
+ },
94
+ nodes: [
95
+ {
96
+ object: 'text',
97
+ leaves: [
98
+ {
99
+ object: 'leaf',
100
+ text: '',
101
+ marks: [],
102
+ },
103
+ ],
104
+ },
105
+ ],
106
+ },
107
+ {
108
+ object: 'text',
109
+ leaves: [
110
+ {
111
+ object: 'leaf',
112
+ text: 'bar',
113
+ marks: [],
114
+ },
115
+ ],
116
+ },
117
+ ],
118
+ },
119
+ ],
120
+ },
121
+ ],
122
+ },
123
+ };
124
+ const html = `<div><p>foo<img src="blah.jpg"/>bar</p></div>`;
125
+ const v = htmlToValue(html);
126
+
127
+ console.log(JSON.stringify(v.toJSON()));
128
+ expect(v.toJSON()).toEqual(expected);
129
+ });
130
+
131
+ it('does not break', () => {
132
+ /*
133
+ More than 12 iterations of the same kind would previously break the input. Here we have 16 text nodes, and now it works.
134
+ */
135
+ const expected = {
136
+ object: 'value',
137
+ document: {
138
+ object: 'document',
139
+ data: {},
140
+ nodes: [
141
+ {
142
+ object: 'block',
143
+ type: 'div',
144
+ isVoid: false,
145
+ data: { attributes: {} },
146
+ nodes: [
147
+ {
148
+ object: 'text',
149
+ leaves: [
150
+ {
151
+ object: 'leaf',
152
+ text: 'Foo ',
153
+ marks: [],
154
+ },
155
+ {
156
+ object: 'leaf',
157
+ text: 'x',
158
+ marks: [
159
+ {
160
+ object: 'mark',
161
+ type: 'italic',
162
+ data: {},
163
+ },
164
+ ],
165
+ },
166
+ {
167
+ object: 'leaf',
168
+ text: ' bar ',
169
+ marks: [],
170
+ },
171
+ {
172
+ object: 'leaf',
173
+ text: 'x',
174
+ marks: [
175
+ {
176
+ object: 'mark',
177
+ type: 'italic',
178
+ data: {},
179
+ },
180
+ ],
181
+ },
182
+ {
183
+ object: 'leaf',
184
+ text: ' Foo ',
185
+ marks: [],
186
+ },
187
+ {
188
+ object: 'leaf',
189
+ text: 'x',
190
+ marks: [
191
+ {
192
+ object: 'mark',
193
+ type: 'italic',
194
+ data: {},
195
+ },
196
+ ],
197
+ },
198
+ {
199
+ object: 'leaf',
200
+ text: ' bar ',
201
+ marks: [],
202
+ },
203
+ {
204
+ object: 'leaf',
205
+ text: 'x',
206
+ marks: [
207
+ {
208
+ object: 'mark',
209
+ type: 'italic',
210
+ data: {},
211
+ },
212
+ ],
213
+ },
214
+ {
215
+ object: 'leaf',
216
+ text: ' Foo ',
217
+ marks: [],
218
+ },
219
+ {
220
+ object: 'leaf',
221
+ text: 'x',
222
+ marks: [
223
+ {
224
+ object: 'mark',
225
+ type: 'italic',
226
+ data: {},
227
+ },
228
+ ],
229
+ },
230
+ {
231
+ object: 'leaf',
232
+ text: ' bar ',
233
+ marks: [],
234
+ },
235
+ {
236
+ object: 'leaf',
237
+ text: 'x',
238
+ marks: [
239
+ {
240
+ object: 'mark',
241
+ type: 'italic',
242
+ data: {},
243
+ },
244
+ ],
245
+ },
246
+ {
247
+ object: 'leaf',
248
+ text: ' Foo ',
249
+ marks: [],
250
+ },
251
+ {
252
+ object: 'leaf',
253
+ text: 'x',
254
+ marks: [
255
+ {
256
+ object: 'mark',
257
+ type: 'italic',
258
+ data: {},
259
+ },
260
+ ],
261
+ },
262
+ {
263
+ object: 'leaf',
264
+ text: ' bar ',
265
+ marks: [],
266
+ },
267
+ {
268
+ object: 'leaf',
269
+ text: 'x',
270
+ marks: [
271
+ {
272
+ object: 'mark',
273
+ type: 'italic',
274
+ data: {},
275
+ },
276
+ ],
277
+ },
278
+ ],
279
+ },
280
+ ],
281
+ },
282
+ ],
283
+ },
284
+ };
285
+ const html =
286
+ '<div>Foo <em>x</em> bar <em>x</em> Foo <em>x</em> bar <em>x</em> Foo <em>x</em> bar <em>x</em> Foo <em>x</em> bar <em>x</em></div>';
287
+ const v = htmlToValue(html);
288
+
289
+ expect(v.toJSON()).toEqual(expected);
290
+ });
291
+ });
@@ -0,0 +1,36 @@
1
+ import React from 'react';
2
+
3
+ export function classObject() {
4
+ const out = {};
5
+ for (var a in arguments) {
6
+ const value = arguments[a];
7
+ out[value] = value;
8
+ }
9
+ return out;
10
+ }
11
+
12
+ export function mockComponents() {
13
+ const out = {};
14
+ for (var a in arguments) {
15
+ const value = arguments[a];
16
+ out[value] = class extends React.Component {
17
+ render() {
18
+ return <div data-mock-component="true">{value}</div>;
19
+ }
20
+ };
21
+ }
22
+ return out;
23
+ }
24
+
25
+ export function mockIconButton() {
26
+ jest.mock('@material-ui/core/IconButton', () => {
27
+ return (props) => <div className={props.className} style={props.style} ariaLabel={props['aria-label']} />;
28
+ });
29
+ }
30
+ export function mockMathInput() {
31
+ jest.mock('@pie-lib/math-input', () => ({
32
+ addBrackets: jest.fn((s) => s),
33
+ removeBrackets: jest.fn((s) => s),
34
+ ...mockComponents('Keypad', 'MathQuillInput', 'EditableMathInput', 'HorizontalKeypad'),
35
+ }));
36
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Tags to blocks.
3
+ *
4
+ * @type {Object}
5
+ */
6
+
7
+ export const BLOCK_TAGS = {
8
+ div: 'div',
9
+ // span: 'span',
10
+ p: 'paragraph',
11
+ pre: 'code',
12
+ h1: 'heading-one',
13
+ h2: 'heading-two',
14
+ h4: 'heading-four',
15
+ h5: 'heading-five',
16
+ h6: 'heading-six',
17
+ };
@@ -0,0 +1,7 @@
1
+ export const MAIN_CONTAINER_CLASS = 'main-container';
2
+ export const PIE_TOOLBAR__CLASS = 'pie-toolbar';
3
+
4
+ export default {
5
+ MAIN_CONTAINER_CLASS,
6
+ PIE_TOOLBAR__CLASS,
7
+ };