@pie-lib/editable-html-tip-tap 1.0.1 → 1.0.3

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 (129) hide show
  1. package/lib/components/CharacterPicker.js +221 -0
  2. package/lib/components/EditableHtml.js +323 -0
  3. package/lib/components/MenuBar.js +693 -0
  4. package/lib/components/TiptapContainer.js +90 -0
  5. package/lib/components/buttons/done-button.js +53 -0
  6. package/lib/components/characters/characterUtils.js +112 -0
  7. package/lib/components/characters/custom-popper.js +73 -0
  8. package/lib/components/common/done-button.js +53 -0
  9. package/lib/components/icons/CssIcon.js +37 -0
  10. package/lib/components/icons/RespArea.js +95 -0
  11. package/lib/components/icons/TableIcons.js +69 -0
  12. package/lib/components/icons/TextAlign.js +194 -0
  13. package/lib/components/icons/index.js +194 -0
  14. package/lib/components/image/ImageToolbar.js +16 -0
  15. package/lib/components/image/InsertImageHandler.js +16 -0
  16. package/lib/components/media/MediaDialog.js +16 -0
  17. package/lib/components/media/MediaToolbar.js +16 -0
  18. package/lib/components/respArea/DragInTheBlank/DragInTheBlank.js +94 -0
  19. package/lib/components/respArea/DragInTheBlank/choice.js +289 -0
  20. package/lib/components/respArea/DragInTheBlank.js +94 -0
  21. package/lib/components/respArea/ExplicitConstructedResponse.js +120 -0
  22. package/lib/components/respArea/InlineDropdown.js +126 -0
  23. package/lib/components/respArea/ToolbarIcon.js +105 -0
  24. package/lib/components/respArea/choice.js +2 -0
  25. package/lib/extensions/component.js +5 -5
  26. package/lib/extensions/custom-toolbar-wrapper.js +2 -4
  27. package/lib/extensions/extended-table.js +30 -0
  28. package/lib/extensions/index.js +52 -0
  29. package/lib/extensions/media.js +5 -5
  30. package/lib/extensions/responseArea.js +7 -7
  31. package/lib/index.js +16 -1454
  32. package/lib/plugins/index.js +10 -82
  33. package/lib/styles/editorContainerStyles.js +200 -0
  34. package/lib/utils/size.js +34 -0
  35. package/package.json +1 -1
  36. package/src/components/CharacterPicker.jsx +185 -0
  37. package/src/components/EditableHtml.jsx +306 -0
  38. package/src/components/MenuBar.jsx +630 -0
  39. package/src/components/TiptapContainer.jsx +96 -0
  40. package/src/components/characters/characterUtils.js +127 -0
  41. package/src/components/image/ImageToolbar.jsx +1 -0
  42. package/src/components/image/InsertImageHandler.js +1 -0
  43. package/src/components/media/MediaDialog.js +1 -0
  44. package/src/components/media/MediaToolbar.jsx +1 -0
  45. package/src/{plugins/respArea/drag-in-the-blank → components/respArea/DragInTheBlank}/choice.jsx +1 -1
  46. package/src/{plugins/respArea/inline-dropdown/index.jsx → components/respArea/InlineDropdown.jsx} +1 -1
  47. package/src/components/respArea/ToolbarIcon.jsx +68 -0
  48. package/src/extensions/component.jsx +2 -2
  49. package/src/extensions/custom-toolbar-wrapper.jsx +6 -7
  50. package/src/extensions/extended-table.js +27 -0
  51. package/src/extensions/index.js +76 -0
  52. package/src/extensions/media.js +10 -4
  53. package/src/extensions/responseArea.js +7 -7
  54. package/src/index.jsx +3 -1409
  55. package/src/styles/editorContainerStyles.js +203 -0
  56. package/src/utils/size.js +32 -0
  57. package/src/__tests__/editor.test.jsx +0 -363
  58. package/src/__tests__/serialization.test.js +0 -291
  59. package/src/block-tags.js +0 -17
  60. package/src/editor.jsx +0 -1197
  61. package/src/extensions/characters.js +0 -46
  62. package/src/old-index.jsx +0 -162
  63. package/src/parse-html.js +0 -8
  64. package/src/plugins/README.md +0 -27
  65. package/src/plugins/characters/index.jsx +0 -284
  66. package/src/plugins/characters/utils.js +0 -447
  67. package/src/plugins/css/index.jsx +0 -340
  68. package/src/plugins/customPlugin/index.jsx +0 -85
  69. package/src/plugins/html/icons/index.jsx +0 -19
  70. package/src/plugins/html/index.jsx +0 -72
  71. package/src/plugins/image/__tests__/__snapshots__/component.test.jsx.snap +0 -51
  72. package/src/plugins/image/__tests__/__snapshots__/image-toolbar-logic.test.jsx.snap +0 -27
  73. package/src/plugins/image/__tests__/__snapshots__/image-toolbar.test.jsx.snap +0 -44
  74. package/src/plugins/image/__tests__/component.test.jsx +0 -41
  75. package/src/plugins/image/__tests__/image-toolbar-logic.test.jsx +0 -42
  76. package/src/plugins/image/__tests__/image-toolbar.test.jsx +0 -11
  77. package/src/plugins/image/__tests__/index.test.js +0 -95
  78. package/src/plugins/image/__tests__/insert-image-handler.test.js +0 -113
  79. package/src/plugins/image/__tests__/mock-change.js +0 -15
  80. package/src/plugins/image/alt-dialog.jsx +0 -82
  81. package/src/plugins/image/component.jsx +0 -343
  82. package/src/plugins/image/image-toolbar.jsx +0 -100
  83. package/src/plugins/image/index.jsx +0 -227
  84. package/src/plugins/image/insert-image-handler.js +0 -79
  85. package/src/plugins/index.jsx +0 -377
  86. package/src/plugins/list/__tests__/index.test.js +0 -54
  87. package/src/plugins/list/index.jsx +0 -305
  88. package/src/plugins/math/__tests__/__snapshots__/index.test.jsx.snap +0 -48
  89. package/src/plugins/math/__tests__/index.test.jsx +0 -245
  90. package/src/plugins/math/index.jsx +0 -379
  91. package/src/plugins/media/__tests__/index.test.js +0 -75
  92. package/src/plugins/media/index.jsx +0 -325
  93. package/src/plugins/media/media-dialog.js +0 -624
  94. package/src/plugins/media/media-toolbar.jsx +0 -56
  95. package/src/plugins/media/media-wrapper.jsx +0 -43
  96. package/src/plugins/rendering/index.js +0 -31
  97. package/src/plugins/respArea/index.jsx +0 -299
  98. package/src/plugins/respArea/math-templated/index.jsx +0 -104
  99. package/src/plugins/respArea/utils.jsx +0 -90
  100. package/src/plugins/table/CustomTablePlugin.js +0 -113
  101. package/src/plugins/table/__tests__/__snapshots__/table-toolbar.test.jsx.snap +0 -44
  102. package/src/plugins/table/__tests__/index.test.jsx +0 -401
  103. package/src/plugins/table/__tests__/table-toolbar.test.jsx +0 -42
  104. package/src/plugins/table/index.jsx +0 -427
  105. package/src/plugins/table/table-toolbar.jsx +0 -136
  106. package/src/plugins/textAlign/index.jsx +0 -23
  107. package/src/plugins/toolbar/__tests__/__snapshots__/default-toolbar.test.jsx.snap +0 -923
  108. package/src/plugins/toolbar/__tests__/__snapshots__/editor-and-toolbar.test.jsx.snap +0 -20
  109. package/src/plugins/toolbar/__tests__/__snapshots__/toolbar-buttons.test.jsx.snap +0 -36
  110. package/src/plugins/toolbar/__tests__/__snapshots__/toolbar.test.jsx.snap +0 -46
  111. package/src/plugins/toolbar/__tests__/default-toolbar.test.jsx +0 -94
  112. package/src/plugins/toolbar/__tests__/editor-and-toolbar.test.jsx +0 -37
  113. package/src/plugins/toolbar/__tests__/toolbar-buttons.test.jsx +0 -51
  114. package/src/plugins/toolbar/__tests__/toolbar.test.jsx +0 -106
  115. package/src/plugins/toolbar/default-toolbar.jsx +0 -206
  116. package/src/plugins/toolbar/editor-and-toolbar.jsx +0 -257
  117. package/src/plugins/toolbar/index.jsx +0 -23
  118. package/src/plugins/toolbar/toolbar-buttons.jsx +0 -138
  119. package/src/plugins/toolbar/toolbar.jsx +0 -338
  120. package/src/plugins/utils.js +0 -31
  121. package/src/serialization.jsx +0 -621
  122. /package/src/{plugins → components}/characters/custom-popper.js +0 -0
  123. /package/src/{plugins/toolbar → components/common}/done-button.jsx +0 -0
  124. /package/src/{plugins/css/icons/index.jsx → components/icons/CssIcon.jsx} +0 -0
  125. /package/src/{plugins/respArea/icons/index.jsx → components/icons/RespArea.jsx} +0 -0
  126. /package/src/{plugins/table/icons/index.jsx → components/icons/TableIcons.jsx} +0 -0
  127. /package/src/{plugins/textAlign/icons/index.jsx → components/icons/TextAlign.jsx} +0 -0
  128. /package/src/{plugins/respArea/drag-in-the-blank/index.jsx → components/respArea/DragInTheBlank/DragInTheBlank.jsx} +0 -0
  129. /package/src/{plugins/respArea/explicit-constructed-response/index.jsx → components/respArea/ExplicitConstructedResponse.jsx} +0 -0
@@ -1,305 +0,0 @@
1
- import React from 'react';
2
- import { Data } from 'slate';
3
- import Immutable from 'immutable';
4
- import PropTypes from 'prop-types';
5
- import EditList from 'slate-edit-list';
6
- import ListOptions from 'slate-edit-list/dist/options';
7
- import debug from 'debug';
8
-
9
- const log = debug('@pie-lib:editable-html:plugins:list');
10
-
11
- const b = (type, next, childNodes) => ({
12
- object: 'block',
13
- type,
14
- nodes: next(childNodes),
15
- });
16
-
17
- export const serialization = {
18
- deserialize(el, next) {
19
- const name = el.tagName.toLowerCase();
20
-
21
- if (name === 'li') {
22
- return b('list_item', next, el.childNodes);
23
- }
24
-
25
- if (name === 'ul') {
26
- return b('ul_list', next, el.children.length ? Array.from(el.children) : el.childNodes);
27
- }
28
-
29
- if (name === 'ol') {
30
- return b('ol_list', next, el.children.length ? Array.from(el.children) : el.childNodes);
31
- }
32
- },
33
- serialize(object, children) {
34
- if (object.object !== 'block') return;
35
-
36
- if (object.type === 'list_item') {
37
- return <li>{children}</li>;
38
- }
39
-
40
- if (object.type === 'ul_list') {
41
- return <ul>{children}</ul>;
42
- }
43
-
44
- if (object.type === 'ol_list') {
45
- return <ol>{children}</ol>;
46
- }
47
- },
48
- };
49
-
50
- const createEditList = () => {
51
- const core = EditList({
52
- typeDefault: 'span',
53
- });
54
-
55
- const listOptions = new ListOptions({
56
- typeDefault: 'span',
57
- });
58
-
59
- // fix outdated schema
60
- if (core.schema && core.schema.blocks) {
61
- Object.keys(core.schema.blocks).forEach((key) => {
62
- const block = core.schema.blocks[key];
63
-
64
- if (block.parent) {
65
- return;
66
- }
67
-
68
- block.nodes[0] = { type: block.nodes[0].types[0] };
69
- });
70
- }
71
-
72
- /**
73
- * This override of the core.changes.wrapInList is needed because the version
74
- * of immutable that we have does not support getting the element at a specific
75
- * index with a square bracket (list[0]). We have to use the list.get function instead
76
- */
77
-
78
- /**
79
- * Returns the highest list of blocks that cover the current selection
80
- */
81
- const getHighestSelectedBlocks = (value) => {
82
- const range = value.selection;
83
- const document = value.document;
84
-
85
- const startBlock = document.getClosestBlock(range.startKey);
86
- const endBlock = document.getClosestBlock(range.endKey);
87
-
88
- if (startBlock === endBlock) {
89
- return Immutable.List([startBlock]);
90
- }
91
-
92
- const ancestor = document.getCommonAncestor(startBlock.key, endBlock.key);
93
- const startPath = ancestor.getPath(startBlock.key);
94
- const endPath = ancestor.getPath(endBlock.key);
95
-
96
- return ancestor.nodes.slice(startPath.get(0), endPath.get(0) + 1);
97
- };
98
-
99
- /**
100
- * Wrap the blocks in the current selection in a new list. Selected
101
- * lists are merged together.
102
- */
103
- core.changes.wrapInList = function(change, type, data) {
104
- const selectedBlocks = getHighestSelectedBlocks(change.value);
105
-
106
- // Wrap in container
107
- change.wrapBlock({ type: type, data: Data.create(data) }, { normalize: false });
108
-
109
- // Wrap in list items
110
- selectedBlocks.forEach(function(node) {
111
- if (core.utils.isList(node)) {
112
- // Merge its items with the created list
113
- node.nodes.forEach(function(_ref) {
114
- const key = _ref.key;
115
- return change.unwrapNodeByKey(key, { normalize: false });
116
- });
117
- } else if (node.type !== 'list_item') {
118
- change.wrapBlockByKey(node.key, 'list_item', {
119
- normalize: false,
120
- });
121
- }
122
- });
123
-
124
- return change.normalize();
125
- };
126
-
127
- core.changes.unwrapList = function unwrapList(opts, change) {
128
- const items = core.utils.getItemsAtRange(change.value);
129
-
130
- if (items.isEmpty()) {
131
- return change;
132
- }
133
-
134
- // Unwrap the items from their list
135
- items.forEach((item) => change.unwrapNodeByKey(item.key, { normalize: false }));
136
-
137
- // Parent of the list of the items
138
- const firstItem = items.first();
139
- const parent = change.value.document.getParent(firstItem.key);
140
-
141
- let index = parent.nodes.findIndex((node) => node.key === firstItem.key);
142
-
143
- // Unwrap the items' children
144
- items.forEach((item) => {
145
- item.nodes.forEach((node) => {
146
- change.moveNodeByKey(node.key, parent.key, index, {
147
- normalize: false,
148
- });
149
- index += 1;
150
- });
151
- });
152
-
153
- // Finally, remove the now empty items
154
- items.forEach((item) => change.removeNodeByKey(item.key, { normalize: false }));
155
-
156
- return change;
157
- }.bind(this, listOptions);
158
-
159
- core.utils.getItemsAtRange = function(opts, value, range) {
160
- range = range || value.selection;
161
-
162
- if (!range.startKey) {
163
- return Immutable.List();
164
- }
165
-
166
- const { document } = value;
167
-
168
- const startBlock = document.getClosestBlock(range.startKey);
169
- const endBlock = document.getClosestBlock(range.endKey);
170
-
171
- if (startBlock === endBlock) {
172
- const item = core.utils.getCurrentItem(value, startBlock);
173
- return item ? Immutable.List([item]) : Immutable.List();
174
- }
175
-
176
- const ancestor = document.getCommonAncestor(startBlock.key, endBlock.key);
177
-
178
- if (core.utils.isList(ancestor)) {
179
- const startPath = ancestor.getPath(startBlock.key);
180
- const endPath = ancestor.getPath(endBlock.key);
181
-
182
- return ancestor.nodes.slice(startPath.get(0), endPath.get(0) + 1);
183
- } else if (ancestor.type === opts.typeItem) {
184
- // The ancestor is the highest list item that covers the range
185
- return Immutable.List([ancestor]);
186
- }
187
- // No list of items can cover the range
188
- return Immutable.List();
189
- }.bind(this, listOptions);
190
-
191
- core.utils.getListForItem = function(opts, value, item) {
192
- const { document } = value;
193
- const parent = document.getParent(item.key);
194
- return parent && core.utils.isList(parent) ? parent : null;
195
- }.bind(this, listOptions);
196
-
197
- core.utils.isSelectionInList = function(opts, value, type) {
198
- const items = core.utils.getItemsAtRange(value);
199
- return (
200
- !items.isEmpty() &&
201
- // Check the type of the list if needed
202
- (!type || core.utils.getListForItem(value, items.first()).get('type') === type)
203
- );
204
- }.bind(this, listOptions);
205
-
206
- return core;
207
- };
208
-
209
- export default (options) => {
210
- const { type, icon } = options;
211
-
212
- const core = createEditList();
213
-
214
- // eslint-disable-next-line react/display-name
215
- core.renderNode = (props) => {
216
- const { node, attributes, children } = props;
217
-
218
- switch (node.type) {
219
- case 'ul_list':
220
- return <ul {...attributes}>{children}</ul>;
221
- case 'ol_list':
222
- return <ol {...attributes}>{children}</ol>;
223
- case 'list_item':
224
- return <li {...attributes}>{children}</li>;
225
- }
226
- };
227
-
228
- core.toolbar = {
229
- isMark: false,
230
- ariaLabel: type == 'ul_list' ? 'bulleted list' : 'numbered-list',
231
- type,
232
- icon,
233
- isActive: (value, type) => {
234
- if (!core.utils.isSelectionInList(value)) {
235
- return false;
236
- }
237
- const current = core.utils.getCurrentList(value);
238
- return current ? current.type === type : false;
239
- },
240
- onClick: (value, onChange) => {
241
- log('[onClick]', value);
242
- const inList = core.utils.isSelectionInList(value);
243
- if (inList) {
244
- const change = value.change().call(core.changes.unwrapList);
245
- onChange(change);
246
- } else {
247
- const change = value.change().call(core.changes.wrapInList, type);
248
- onChange(change);
249
- }
250
- },
251
- };
252
-
253
- core.normalizeNode = (node) => {
254
- if (node.object !== 'document' && node.object !== 'block') {
255
- return undefined;
256
- }
257
-
258
- const response = core.validateNode(node);
259
-
260
- const invalidListItems = [];
261
-
262
- node.forEachDescendant((d) => {
263
- if (d.type === 'list_item' && d.nodes.size === 1 && d.nodes.first().object === 'text') {
264
- // if we have a list_item that has only a text inside, we need to add a block in it
265
- invalidListItems.push(d);
266
- }
267
- });
268
-
269
- if (!invalidListItems.length && !response) {
270
- return undefined;
271
- }
272
-
273
- return (change) => {
274
- if (response) {
275
- response(change);
276
- }
277
-
278
- if (invalidListItems.length) {
279
- change.withoutNormalization(() => {
280
- invalidListItems.forEach((node) => {
281
- const textNode = node.nodes.first();
282
- const wrappedBlock = {
283
- object: 'block',
284
- type: 'div',
285
- nodes: [textNode.toJSON()],
286
- };
287
-
288
- change.removeNodeByKey(textNode.key);
289
-
290
- change.insertNodeByKey(node.key, 0, wrappedBlock);
291
- });
292
- });
293
- }
294
- };
295
- };
296
-
297
- core.renderNode.propTypes = {
298
- node: PropTypes.object,
299
- attributes: PropTypes.object,
300
- children: PropTypes.func,
301
- };
302
- core.name = type;
303
-
304
- return core;
305
- };
@@ -1,48 +0,0 @@
1
- // Jest Snapshot v1, https://goo.gl/fbAQLP
2
-
3
- exports[`CustomToolbarComp render renders with default keypadMode 1`] = `
4
- <MathToolbar
5
- additionalKeys={Array []}
6
- autoFocus={true}
7
- controlledKeypadMode={true}
8
- keypadMode="geometry"
9
- latex="foo"
10
- onChange={[Function]}
11
- onDone={[Function]}
12
- />
13
- `;
14
-
15
- exports[`CustomToolbarComp render renders with default keypadMode 2`] = `
16
- <MathToolbar
17
- additionalKeys={Array []}
18
- autoFocus={true}
19
- controlledKeypadMode={true}
20
- keypadMode={3}
21
- latex="foo"
22
- onChange={[Function]}
23
- onDone={[Function]}
24
- />
25
- `;
26
-
27
- exports[`CustomToolbarComp render renders without default keypadMode 1`] = `
28
- <MathToolbar
29
- additionalKeys={Array []}
30
- autoFocus={true}
31
- controlledKeypadMode={true}
32
- latex="foo"
33
- onChange={[Function]}
34
- onDone={[Function]}
35
- />
36
- `;
37
-
38
- exports[`CustomToolbarComp render renders without default keypadMode 2`] = `
39
- <MathToolbar
40
- additionalKeys={Array []}
41
- autoFocus={true}
42
- controlledKeypadMode={true}
43
- keypadMode={3}
44
- latex="foo"
45
- onChange={[Function]}
46
- onDone={[Function]}
47
- />
48
- `;
@@ -1,245 +0,0 @@
1
- import React from 'react';
2
- import debug from 'debug';
3
- import MockChange from '../../image/__tests__/mock-change';
4
- import { Data } from 'slate';
5
- import MathPlugin, { serialization, inlineMath, CustomToolbarComp } from '../index';
6
- import { shallow } from 'enzyme';
7
- import { MathToolbar } from '@pie-lib/math-toolbar';
8
- jest.mock('@pie-framework/mathquill', () => ({
9
- StaticMath: jest.fn(),
10
- getInterface: jest.fn().mockReturnThis(),
11
- registerEmbed: jest.fn(),
12
- }));
13
-
14
- jest.mock('@pie-lib/math-toolbar', () => ({
15
- MathPreview: () => <div />,
16
- MathToolbar: () => <div />,
17
- }));
18
-
19
- jest.mock('@pie-lib/math-rendering', () => ({
20
- ...jest.requireActual('@pie-lib/math-rendering'),
21
- mmlToLatex: jest.fn(() => {
22
- return '/foobar/latex';
23
- }),
24
- }));
25
- const log = debug('@pie-lib:editable-html:test:math');
26
-
27
- // I believe @andrei is moving this stuff out.
28
- describe('MathPlugin', () => {
29
- describe('toolbar', () => {
30
- describe('onClick', () => {
31
- let plugin, mockChange, value, onChange;
32
- beforeEach(() => {
33
- plugin = MathPlugin({});
34
- mockChange = new MockChange();
35
- value = {
36
- change: jest.fn(() => mockChange),
37
- };
38
- onChange = jest.fn();
39
- plugin.toolbar.onClick(value, onChange);
40
- });
41
-
42
- test('calls insertInline', () => {
43
- expect(mockChange.insertInline).toBeCalledWith(expect.objectContaining({ data: inlineMath().data }));
44
- });
45
-
46
- test('it calls onChange', () => {
47
- expect(onChange).toHaveBeenCalledWith(mockChange);
48
- });
49
- });
50
- });
51
-
52
- describe('renderNode', () => {
53
- test('the component has props', () => {
54
- const plugin = MathPlugin({});
55
- const { props } = plugin.renderNode({ node: { type: 'math' } });
56
- expect(props.node).toEqual({ type: 'math' });
57
- });
58
- });
59
-
60
- describe('serialization', () => {
61
- describe('deserialize', () => {
62
- const assertDeserialize = (html, expected, wrapType) => {
63
- it(`innerHTML: ${html} is deserialized to: ${expected} with wrapType: ${wrapType}`, () => {
64
- const el = {
65
- tagName: 'span',
66
- childNodes: [],
67
- getAttribute: jest.fn(() => ''),
68
- hasAttribute: jest.fn(() => true),
69
- innerHTML: html,
70
- };
71
- const next = jest.fn();
72
-
73
- const out = serialization.deserialize(el, next);
74
- expect(out).toEqual({
75
- object: 'inline',
76
- type: 'math',
77
- isVoid: true,
78
- nodes: [],
79
- data: {
80
- latex: expected,
81
- wrapper: wrapType,
82
- },
83
- });
84
- });
85
- };
86
-
87
- assertDeserialize('$$&lt;$$', '<', MathPlugin.DOLLAR);
88
- assertDeserialize('$&lt;$', '<', MathPlugin.DOLLAR);
89
- assertDeserialize('\\(&lt;\\)', '<', MathPlugin.ROUND_BRACKETS);
90
- assertDeserialize('\\[&lt;\\]', '<', MathPlugin.ROUND_BRACKETS);
91
- assertDeserialize('latex', 'latex', MathPlugin.ROUND_BRACKETS);
92
- assertDeserialize('\\displaystyle foo', 'foo', MathPlugin.ROUND_BRACKETS);
93
-
94
- it('should make mathml editable if MathPlugin.mathMlOptions.mmlEditing is true', () => {
95
- MathPlugin.mathMlOptions.mmlEditing = true;
96
- const el = {
97
- tagName: 'math',
98
- outerHTML:
99
- '<math xmlns="http://www.w3.org/1998/Math/MathML"> <mn>2</mn> <mi>x</mi> <mtext>&#xA0;</mtext> <mo>&#x2264;</mo> <mn>4</mn> <mi>y</mi> <mtext>&#xA0;</mtext> <mo>+</mo> <mtext>&#xA0;</mtext> <mn>8</mn> <msqrt> <mi>h</mi> </msqrt></math>',
100
- };
101
- const next = jest.fn();
102
-
103
- const out = serialization.deserialize(el, next);
104
-
105
- expect(out).toEqual({
106
- object: 'inline',
107
- type: 'math',
108
- isVoid: true,
109
- nodes: [],
110
- data: {
111
- latex: '/foobar/latex',
112
- wrapper: 'round_brackets',
113
- },
114
- });
115
- });
116
-
117
- it('should make mathml readOnly if MathPlugin.mathMlOptions.mmlEditing is false', () => {
118
- MathPlugin.mathMlOptions.mmlEditing = false;
119
- const el = {
120
- tagName: 'math',
121
- outerHTML:
122
- '<math xmlns="http://www.w3.org/1998/Math/MathML"> <mn>2</mn> <mi>x</mi> <mtext>&#xA0;</mtext> <mo>&#x2264;</mo> <mn>4</mn> <mi>y</mi> <mtext>&#xA0;</mtext> <mo>+</mo> <mtext>&#xA0;</mtext> <mn>8</mn> <msqrt> <mi>h</mi> </msqrt></math>',
123
- };
124
- const next = jest.fn();
125
-
126
- const out = serialization.deserialize(el, next);
127
-
128
- expect(out).toEqual({
129
- object: 'inline',
130
- isVoid: true,
131
- type: 'mathml',
132
- data: {
133
- html: el.outerHTML,
134
- },
135
- });
136
- });
137
- });
138
-
139
- describe('serialize', () => {
140
- const assertSerialize = (latex, expectedHtml, wrapper) => {
141
- wrapper = wrapper || MathPlugin.ROUND_BRACKETS;
142
- it(`${latex} is serialized to: ${expectedHtml}`, () => {
143
- const object = {
144
- kind: 'inline',
145
- type: 'math',
146
- isVoid: true,
147
- nodes: [],
148
- data: Data.create({ latex, wrapper }),
149
- };
150
- const children = [];
151
-
152
- const out = serialization.serialize(object, children);
153
- log('out: ', out);
154
- expect(out).toEqual(
155
- <span data-latex="" data-raw={latex}>
156
- {expectedHtml}
157
- </span>,
158
- );
159
- });
160
- };
161
-
162
- assertSerialize('latex', '\\(latex\\)', MathPlugin.ROUND_BRACKETS);
163
- assertSerialize('latex', '\\(latex\\)', MathPlugin.SQUARE_BRACKETS);
164
- assertSerialize('latex', '$latex$', MathPlugin.DOLLAR);
165
- assertSerialize('latex', '$latex$', MathPlugin.DOUBLE_DOLLAR);
166
-
167
- /**
168
- * Note that when this is converted to html it get's escaped - but that's an issue with the slate html-serializer.
169
- */
170
- assertSerialize('<', '\\(<\\)');
171
- assertSerialize('x<y', '\\(x<y\\)');
172
- });
173
- });
174
- });
175
-
176
- describe('CustomToolbarComp', () => {
177
- let onDataChange;
178
- let onToolbarDone;
179
-
180
- const wrapper = (extras) => {
181
- let mockChange = new MockChange();
182
- const defaults = {
183
- node: {
184
- key: '1',
185
- data: Data.create({ latex: 'foo' }),
186
- equals: () => true,
187
- },
188
- value: {
189
- document: {
190
- getNextText: jest.fn().mockReturnValue({ key: 'nt' }),
191
- },
192
- change: jest.fn().mockReturnValue(mockChange),
193
- },
194
- onDataChange,
195
- onToolbarDone,
196
- };
197
-
198
- const props = {
199
- ...defaults,
200
- ...extras,
201
- };
202
-
203
- return shallow(<CustomToolbarComp {...props} />);
204
- };
205
-
206
- describe('render', () => {
207
- it('renders without default keypadMode', () => {
208
- const w = wrapper();
209
-
210
- expect(w).toMatchSnapshot();
211
-
212
- w.setProps({ pluginProps: { math: { keypadMode: 3 } } });
213
-
214
- expect(w).toMatchSnapshot();
215
- });
216
-
217
- it('renders with default keypadMode', () => {
218
- const w = wrapper({ pluginProps: { math: { keypadMode: 'geometry' } } });
219
-
220
- expect(w).toMatchSnapshot();
221
-
222
- w.setProps({ pluginProps: { math: { keypadMode: 3 } } });
223
-
224
- expect(w).toMatchSnapshot();
225
- });
226
- });
227
-
228
- describe('onDone', () => {
229
- it('calls onToolbarDone', () => {
230
- onToolbarDone = jest.fn();
231
- const w = wrapper();
232
- w.find(MathToolbar).prop('onDone')('oo');
233
- expect(onToolbarDone).toHaveBeenCalledWith(expect.anything(), false);
234
- });
235
- });
236
-
237
- describe('onChange', () => {
238
- it('calls onDataChange', () => {
239
- onDataChange = jest.fn();
240
- const w = wrapper();
241
- w.find(MathToolbar).prop('onChange')('oo');
242
- expect(onDataChange).toHaveBeenCalledWith('1', { latex: 'oo' });
243
- });
244
- });
245
- });