@pie-lib/editable-html 7.17.4-next.59 → 7.17.4-next.592

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 (99) hide show
  1. package/CHANGELOG.json +135 -0
  2. package/CHANGELOG.md +421 -0
  3. package/lib/editor.js +392 -172
  4. package/lib/editor.js.map +1 -1
  5. package/lib/index.js +66 -53
  6. package/lib/index.js.map +1 -1
  7. package/lib/parse-html.js.map +1 -1
  8. package/lib/plugins/characters/custom-popper.js +73 -0
  9. package/lib/plugins/characters/custom-popper.js.map +1 -0
  10. package/lib/plugins/characters/index.js +285 -0
  11. package/lib/plugins/characters/index.js.map +1 -0
  12. package/lib/plugins/characters/utils.js +381 -0
  13. package/lib/plugins/characters/utils.js.map +1 -0
  14. package/lib/plugins/image/alt-dialog.js +119 -0
  15. package/lib/plugins/image/alt-dialog.js.map +1 -0
  16. package/lib/plugins/image/component.js +253 -77
  17. package/lib/plugins/image/component.js.map +1 -1
  18. package/lib/plugins/image/image-toolbar.js +95 -61
  19. package/lib/plugins/image/image-toolbar.js.map +1 -1
  20. package/lib/plugins/image/index.js +62 -20
  21. package/lib/plugins/image/index.js.map +1 -1
  22. package/lib/plugins/image/insert-image-handler.js +9 -15
  23. package/lib/plugins/image/insert-image-handler.js.map +1 -1
  24. package/lib/plugins/index.js +20 -12
  25. package/lib/plugins/index.js.map +1 -1
  26. package/lib/plugins/list/index.js +82 -14
  27. package/lib/plugins/list/index.js.map +1 -1
  28. package/lib/plugins/math/index.js +50 -55
  29. package/lib/plugins/math/index.js.map +1 -1
  30. package/lib/plugins/media/index.js +71 -27
  31. package/lib/plugins/media/index.js.map +1 -1
  32. package/lib/plugins/media/media-dialog.js +248 -72
  33. package/lib/plugins/media/media-dialog.js.map +1 -1
  34. package/lib/plugins/media/media-toolbar.js +24 -30
  35. package/lib/plugins/media/media-toolbar.js.map +1 -1
  36. package/lib/plugins/media/media-wrapper.js +28 -35
  37. package/lib/plugins/media/media-wrapper.js.map +1 -1
  38. package/lib/plugins/respArea/drag-in-the-blank/choice.js +68 -46
  39. package/lib/plugins/respArea/drag-in-the-blank/choice.js.map +1 -1
  40. package/lib/plugins/respArea/drag-in-the-blank/index.js +12 -12
  41. package/lib/plugins/respArea/drag-in-the-blank/index.js.map +1 -1
  42. package/lib/plugins/respArea/explicit-constructed-response/index.js +10 -9
  43. package/lib/plugins/respArea/explicit-constructed-response/index.js.map +1 -1
  44. package/lib/plugins/respArea/icons/index.js +11 -11
  45. package/lib/plugins/respArea/icons/index.js.map +1 -1
  46. package/lib/plugins/respArea/index.js +58 -42
  47. package/lib/plugins/respArea/index.js.map +1 -1
  48. package/lib/plugins/respArea/inline-dropdown/index.js +8 -8
  49. package/lib/plugins/respArea/inline-dropdown/index.js.map +1 -1
  50. package/lib/plugins/respArea/utils.js +5 -5
  51. package/lib/plugins/respArea/utils.js.map +1 -1
  52. package/lib/plugins/table/icons/index.js +12 -12
  53. package/lib/plugins/table/icons/index.js.map +1 -1
  54. package/lib/plugins/table/index.js +83 -27
  55. package/lib/plugins/table/index.js.map +1 -1
  56. package/lib/plugins/table/table-toolbar.js +41 -50
  57. package/lib/plugins/table/table-toolbar.js.map +1 -1
  58. package/lib/plugins/toolbar/default-toolbar.js +19 -13
  59. package/lib/plugins/toolbar/default-toolbar.js.map +1 -1
  60. package/lib/plugins/toolbar/done-button.js +5 -5
  61. package/lib/plugins/toolbar/done-button.js.map +1 -1
  62. package/lib/plugins/toolbar/editor-and-toolbar.js +62 -45
  63. package/lib/plugins/toolbar/editor-and-toolbar.js.map +1 -1
  64. package/lib/plugins/toolbar/index.js +6 -5
  65. package/lib/plugins/toolbar/index.js.map +1 -1
  66. package/lib/plugins/toolbar/toolbar-buttons.js +49 -52
  67. package/lib/plugins/toolbar/toolbar-buttons.js.map +1 -1
  68. package/lib/plugins/toolbar/toolbar.js +64 -62
  69. package/lib/plugins/toolbar/toolbar.js.map +1 -1
  70. package/lib/plugins/utils.js +1 -1
  71. package/lib/plugins/utils.js.map +1 -1
  72. package/lib/serialization.js +32 -9
  73. package/lib/serialization.js.map +1 -1
  74. package/lib/theme.js.map +1 -1
  75. package/package.json +7 -6
  76. package/src/editor.jsx +226 -26
  77. package/src/index.jsx +22 -5
  78. package/src/plugins/characters/custom-popper.js +48 -0
  79. package/src/plugins/characters/index.jsx +268 -0
  80. package/src/plugins/characters/utils.js +447 -0
  81. package/src/plugins/image/alt-dialog.jsx +69 -0
  82. package/src/plugins/image/component.jsx +204 -21
  83. package/src/plugins/image/image-toolbar.jsx +68 -22
  84. package/src/plugins/image/index.jsx +47 -9
  85. package/src/plugins/index.jsx +4 -1
  86. package/src/plugins/list/index.jsx +67 -5
  87. package/src/plugins/math/index.jsx +31 -37
  88. package/src/plugins/media/index.jsx +49 -6
  89. package/src/plugins/media/media-dialog.js +261 -89
  90. package/src/plugins/respArea/drag-in-the-blank/choice.jsx +28 -1
  91. package/src/plugins/respArea/explicit-constructed-response/index.jsx +3 -3
  92. package/src/plugins/respArea/index.jsx +50 -31
  93. package/src/plugins/table/index.jsx +63 -14
  94. package/src/plugins/toolbar/default-toolbar.jsx +20 -2
  95. package/src/plugins/toolbar/editor-and-toolbar.jsx +50 -11
  96. package/src/plugins/toolbar/index.jsx +1 -0
  97. package/src/plugins/toolbar/toolbar-buttons.jsx +13 -2
  98. package/src/plugins/toolbar/toolbar.jsx +18 -3
  99. package/src/serialization.jsx +19 -3
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import EditTable from 'slate-edit-table';
3
- import { Block, Inline } from 'slate';
3
+ import { Block } from 'slate';
4
4
  import debug from 'debug';
5
5
  import GridOn from '@material-ui/icons/GridOn';
6
6
  import TableToolbar from './table-toolbar';
@@ -78,6 +78,22 @@ TableCell.propTypes = {
78
78
  children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]).isRequired
79
79
  };
80
80
 
81
+ export const moveFocusToBeginningOfTable = change => {
82
+ const addedTable = change.value.document.findDescendant(
83
+ d => !!d.data && !!d.data.get('newTable')
84
+ );
85
+
86
+ if (!addedTable) {
87
+ return;
88
+ }
89
+
90
+ change.collapseToStartOf(addedTable);
91
+
92
+ const update = addedTable.data.remove('newTable');
93
+
94
+ change.setNodeByKey(addedTable.key, { data: update });
95
+ };
96
+
81
97
  export default (opts, toolbarPlugins /* : {toolbar: {}}[] */) => {
82
98
  const core = EditTable({
83
99
  typeContent: 'div'
@@ -117,12 +133,32 @@ export default (opts, toolbarPlugins /* : {toolbar: {}}[] */) => {
117
133
  return ancestors.findLast(p => p.type === 'table');
118
134
  };
119
135
 
136
+ core.utils.createTableWithOptions = (row, columns, extra) => {
137
+ const createdTable = core.utils.createTable(row, columns);
138
+ const newTable = Block.create({
139
+ ...createdTable.toJSON(),
140
+ ...extra
141
+ });
142
+
143
+ return newTable;
144
+ };
145
+
120
146
  core.toolbar = {
121
147
  icon: <GridOn />,
122
148
  onClick: (value, onChange) => {
123
149
  log('insert table');
124
- const c = core.changes.insertTable(value.change(), 2, 2);
125
- onChange(c);
150
+ const change = value.change();
151
+ const newTable = core.utils.createTableWithOptions(2, 2, {
152
+ data: {
153
+ border: '1',
154
+ newTable: true
155
+ }
156
+ });
157
+
158
+ change.insertBlock(newTable);
159
+
160
+ moveFocusToBeginningOfTable(change);
161
+ onChange(change);
126
162
  },
127
163
  supports: (node, value) =>
128
164
  node && node.object === 'block' && core.utils.isSelectionInTable(value),
@@ -132,7 +168,7 @@ export default (opts, toolbarPlugins /* : {toolbar: {}}[] */) => {
132
168
  customToolbar: (node, value, onToolbarDone) => {
133
169
  log('[customToolbar] node.data: ', node.data);
134
170
 
135
- const tableBlock = core.utils.getTableBlock(value.document, node.key);
171
+ const tableBlock = core.utils.getTableBlock(value.document, node?.key);
136
172
  log('[customToolbar] tableBlock: ', tableBlock);
137
173
 
138
174
  const hasBorder = () =>
@@ -215,9 +251,16 @@ export default (opts, toolbarPlugins /* : {toolbar: {}}[] */) => {
215
251
  return;
216
252
  }
217
253
 
254
+ const tableAdded = node.findDescendant(d => d.data && d.data.get('newTable'));
255
+
256
+ if (!tableAdded) {
257
+ return;
258
+ }
259
+
260
+ const nodeToSearch = node.getParent(tableAdded.key) || node;
218
261
  let shouldAddTextAfterNode = false;
219
- const indexToNotHaveTableOn = node.nodes.size - 1;
220
- const indexOfLastTable = node.nodes.findLastIndex(d => d.type === 'table');
262
+ const indexToNotHaveTableOn = nodeToSearch.nodes.size - 1;
263
+ const indexOfLastTable = nodeToSearch.nodes.findLastIndex(d => d.type === 'table');
221
264
 
222
265
  // if the last table in the document is of type table, we need to do the change
223
266
  if (indexOfLastTable === indexToNotHaveTableOn) {
@@ -228,15 +271,13 @@ export default (opts, toolbarPlugins /* : {toolbar: {}}[] */) => {
228
271
  return;
229
272
  }
230
273
 
231
- const tableNode = node.nodes.get(indexOfLastTable);
232
-
233
274
  return change => {
234
275
  if (shouldAddTextAfterNode) {
235
- const tableJSON = tableNode.toJSON();
276
+ const tableJSON = tableAdded.toJSON();
236
277
 
237
278
  // we remove the table node because otherwise we can't add the empty block after it
238
279
  // we need a block that contains text in order to do it
239
- change.removeNodeByKey(tableNode.key);
280
+ change.removeNodeByKey(tableAdded.key);
240
281
 
241
282
  const newBlock = Block.create({
242
283
  object: 'block',
@@ -256,12 +297,20 @@ export default (opts, toolbarPlugins /* : {toolbar: {}}[] */) => {
256
297
  if (prevText) {
257
298
  // we move focus to the previous text
258
299
  change
259
- .moveFocusTo(prevText.key, prevText.text.length)
260
- .moveAnchorTo(prevText.key, prevText.text.length);
300
+ .moveFocusTo(prevText.key, prevText.text?.length)
301
+ .moveAnchorTo(prevText.key, prevText.text?.length);
261
302
  }
262
303
 
263
304
  // we insert the table block between the first block with text and the last block with text
264
- change.insertBlock(tableJSON);
305
+ change.insertBlock({
306
+ ...tableJSON,
307
+ data: {
308
+ ...tableJSON.data,
309
+ newTable: true
310
+ }
311
+ });
312
+
313
+ moveFocusToBeginningOfTable(change);
265
314
  });
266
315
  }
267
316
  };
@@ -282,7 +331,7 @@ export const parseStyleString = s => {
282
331
  return result;
283
332
  };
284
333
 
285
- export const reactAttributes = o => toStyleObject(o, { camelize: true });
334
+ export const reactAttributes = o => toStyleObject(o, { camelize: true, addUnits: false });
286
335
 
287
336
  const attributesToMap = el => (acc, attribute) => {
288
337
  const value = el.getAttribute(attribute);
@@ -14,26 +14,33 @@ const log = debug('@pie-lib:editable-html:plugins:toolbar');
14
14
  export const ToolbarButton = props => {
15
15
  const onToggle = () => {
16
16
  const c = props.onToggle(props.value.change(), props);
17
+
17
18
  props.onChange(c);
18
19
  };
19
20
 
20
21
  if (props.isMark) {
21
22
  const isActive = hasMark(props.value, props.type);
23
+
22
24
  log('[ToolbarButton] mark:isActive: ', isActive);
25
+
23
26
  return (
24
27
  <MarkButton active={isActive} label={props.type} onToggle={onToggle} mark={props.type}>
25
28
  {props.icon}
26
29
  </MarkButton>
27
30
  );
28
31
  } else {
32
+ const { disabled } = props;
29
33
  const isActive = props.isActive
30
34
  ? props.isActive(props.value, props.type)
31
35
  : hasBlock(props.value, props.type);
36
+
32
37
  log('[ToolbarButton] block:isActive: ', isActive);
38
+
33
39
  return (
34
40
  <Button
35
41
  active={isActive}
36
- onClick={() => props.onClick(props.value, props.onChange)}
42
+ disabled={disabled}
43
+ onClick={() => props.onClick(props.value, props.onChange, props.getFocusedValue)}
37
44
  extraStyles={props.buttonStyles}
38
45
  >
39
46
  {props.icon}
@@ -44,6 +51,7 @@ export const ToolbarButton = props => {
44
51
 
45
52
  const isActiveToolbarPlugin = props => plugin => {
46
53
  const isDisabled = (props[plugin.name] || {}).disabled;
54
+
47
55
  return plugin && plugin.toolbar && !isDisabled;
48
56
  };
49
57
 
@@ -52,6 +60,7 @@ export const DefaultToolbar = ({
52
60
  pluginProps,
53
61
  value,
54
62
  onChange,
63
+ getFocusedValue,
55
64
  onDone,
56
65
  classes,
57
66
  showDone,
@@ -63,7 +72,15 @@ export const DefaultToolbar = ({
63
72
  <div className={classes.defaultToolbar}>
64
73
  <div className={classes.buttonsContainer}>
65
74
  {filtered.map((p, index) => {
66
- return <ToolbarButton {...p} key={index} value={value} onChange={onChange} />;
75
+ return (
76
+ <ToolbarButton
77
+ {...p}
78
+ key={index}
79
+ value={value}
80
+ onChange={onChange}
81
+ getFocusedValue={getFocusedValue}
82
+ />
83
+ );
67
84
  })}
68
85
  </div>
69
86
  {showDone && !deletable && <DoneButton onClick={onDone} />}
@@ -77,6 +94,7 @@ DefaultToolbar.propTypes = {
77
94
  pluginProps: PropTypes.object,
78
95
  value: SlatePropTypes.value.isRequired,
79
96
  onChange: PropTypes.func.isRequired,
97
+ getFocusedValue: PropTypes.func.isRequired,
80
98
  onDone: PropTypes.func.isRequired,
81
99
  showDone: PropTypes.bool,
82
100
  addArea: PropTypes.bool,
@@ -17,18 +17,21 @@ export class EditorAndToolbar extends React.Component {
17
17
  value: SlatePropTypes.value.isRequired,
18
18
  plugins: PropTypes.array.isRequired,
19
19
  onChange: PropTypes.func.isRequired,
20
+ getFocusedValue: PropTypes.func.isRequired,
20
21
  onDone: PropTypes.func.isRequired,
21
22
  onDataChange: PropTypes.func,
22
23
  toolbarRef: PropTypes.func,
23
24
  focusedNode: SlatePropTypes.node,
24
25
  readOnly: PropTypes.bool,
26
+ disableScrollbar: PropTypes.bool,
25
27
  disableUnderline: PropTypes.bool,
26
28
  autoWidth: PropTypes.bool,
27
29
  classes: PropTypes.object.isRequired,
28
30
  pluginProps: PropTypes.object,
29
31
  toolbarOpts: PropTypes.shape({
30
32
  position: PropTypes.oneOf(['bottom', 'top']),
31
- alwaysVisible: PropTypes.bool
33
+ alwaysVisible: PropTypes.bool,
34
+ error: PropTypes.string
32
35
  })
33
36
  };
34
37
 
@@ -48,10 +51,12 @@ export class EditorAndToolbar extends React.Component {
48
51
  value,
49
52
  plugins,
50
53
  onChange,
54
+ getFocusedValue,
51
55
  onDone,
52
56
  focusedNode,
53
57
  autoWidth,
54
58
  readOnly,
59
+ disableScrollbar,
55
60
  disableUnderline,
56
61
  pluginProps,
57
62
  toolbarOpts,
@@ -60,12 +65,12 @@ export class EditorAndToolbar extends React.Component {
60
65
  } = this.props;
61
66
 
62
67
  const inFocus = value.isFocused || (focusedNode !== null && focusedNode !== undefined);
63
- const holderNames = classNames(
64
- classes.editorHolder,
65
- inFocus && classes.editorInFocus,
66
- readOnly && classes.readOnly,
67
- disableUnderline && classes.disabledUnderline
68
- );
68
+ const holderNames = classNames(classes.editorHolder, {
69
+ [classes.editorInFocus]: inFocus,
70
+ [classes.readOnly]: readOnly,
71
+ [classes.disabledUnderline]: disableUnderline,
72
+ [classes.disabledScrollbar]: disableScrollbar
73
+ });
69
74
  let clonedChildren = children;
70
75
 
71
76
  if (typeof children !== 'string') {
@@ -84,9 +89,26 @@ export class EditorAndToolbar extends React.Component {
84
89
  );
85
90
 
86
91
  return (
87
- <div className={classes.root}>
92
+ <div
93
+ className={classNames(
94
+ {
95
+ [classes.noBorder]: toolbarOpts && toolbarOpts.noBorder,
96
+ [classes.error]: toolbarOpts && toolbarOpts.error
97
+ },
98
+ classes.root
99
+ )}
100
+ >
88
101
  <div className={holderNames}>
89
- <div className={classes.children}>{clonedChildren}</div>
102
+ <div
103
+ className={classNames(
104
+ {
105
+ [classes.noPadding]: toolbarOpts && toolbarOpts.noBorder
106
+ },
107
+ classes.children
108
+ )}
109
+ >
110
+ {clonedChildren}
111
+ </div>
90
112
  </div>
91
113
  <Toolbar
92
114
  autoWidth={autoWidth}
@@ -95,6 +117,7 @@ export class EditorAndToolbar extends React.Component {
95
117
  value={value}
96
118
  isFocused={inFocus}
97
119
  onChange={onChange}
120
+ getFocusedValue={getFocusedValue}
98
121
  onDone={onDone}
99
122
  onDataChange={onDataChange}
100
123
  toolbarRef={toolbarRef}
@@ -117,7 +140,8 @@ const style = {
117
140
  wordBreak: 'break-word',
118
141
  overflow: 'visible',
119
142
  maxHeight: '500px',
120
- padding: '5px 0'
143
+ // needed in order to be able to put the focus before a void element when it is the first one in the editor
144
+ padding: '5px'
121
145
  }
122
146
  },
123
147
  children: {
@@ -175,7 +199,13 @@ const style = {
175
199
  display: 'none'
176
200
  }
177
201
  },
178
-
202
+ disabledScrollbar: {
203
+ '&::-webkit-scrollbar': {
204
+ display: 'none'
205
+ },
206
+ scrollbarWidth: 'none',
207
+ '-ms-overflow-style': 'none'
208
+ },
179
209
  readOnly: {
180
210
  '&::before': {
181
211
  background: 'transparent',
@@ -214,6 +244,15 @@ const style = {
214
244
  backgroundColor: primary
215
245
  }
216
246
  }
247
+ },
248
+ error: {
249
+ border: '2px solid red'
250
+ },
251
+ noBorder: {
252
+ border: 'none'
253
+ },
254
+ noPadding: {
255
+ padding: 0
217
256
  }
218
257
  };
219
258
 
@@ -13,6 +13,7 @@ export default function ToolbarPlugin(opts) {
13
13
  <EditorAndToolbar
14
14
  {...props}
15
15
  mainEditorRef={opts.mainEditorRef}
16
+ disableScrollbar={opts.disableScrollbar}
16
17
  disableUnderline={opts.disableUnderline}
17
18
  onDone={opts.onDone}
18
19
  />
@@ -15,6 +15,13 @@ const styles = () => ({
15
15
  },
16
16
  active: {
17
17
  color: 'black'
18
+ },
19
+ disabled: {
20
+ opacity: 0.7,
21
+ cursor: 'not-allowed',
22
+ '& :hover': {
23
+ color: 'grey'
24
+ }
18
25
  }
19
26
  });
20
27
 
@@ -26,6 +33,7 @@ export class RawButton extends React.Component {
26
33
  classes: PropTypes.object.isRequired,
27
34
  children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]).isRequired,
28
35
  active: PropTypes.bool,
36
+ disabled: PropTypes.bool,
29
37
  extraStyles: PropTypes.object
30
38
  };
31
39
 
@@ -41,8 +49,11 @@ export class RawButton extends React.Component {
41
49
  };
42
50
 
43
51
  render() {
44
- const { active, classes, children, extraStyles } = this.props;
45
- const names = classNames(classes.button, active && classes.active);
52
+ const { active, classes, children, disabled, extraStyles } = this.props;
53
+ const names = classNames(classes.button, {
54
+ [classes.active]: active,
55
+ [classes.disabled]: disabled
56
+ });
46
57
 
47
58
  return (
48
59
  <div style={extraStyles} className={names} onMouseDown={this.onClick}>
@@ -1,16 +1,19 @@
1
- import { DoneButton } from './done-button';
1
+ import React from 'react';
2
+ import { Change } from 'slate';
2
3
  import Delete from '@material-ui/icons/Delete';
3
4
  import IconButton from '@material-ui/core/IconButton';
4
5
  import PropTypes from 'prop-types';
5
- import React from 'react';
6
6
  import classNames from 'classnames';
7
7
  import debug from 'debug';
8
8
  import SlatePropTypes from 'slate-prop-types';
9
9
  import debounce from 'lodash/debounce';
10
10
 
11
+ import { DoneButton } from './done-button';
12
+
11
13
  import { findSingleNode, findParentNode } from '../utils';
12
14
  import { withStyles } from '@material-ui/core/styles';
13
15
  import DefaultToolbar from './default-toolbar';
16
+ import { removeDialogs as removeCharacterDialogs } from '../characters';
14
17
 
15
18
  const log = debug('@pie-lib:editable-html:plugins:toolbar');
16
19
 
@@ -48,12 +51,13 @@ export class Toolbar extends React.Component {
48
51
  isFocused: PropTypes.bool,
49
52
  autoWidth: PropTypes.bool,
50
53
  onChange: PropTypes.func.isRequired,
54
+ getFocusedValue: PropTypes.func.isRequired,
51
55
  pluginProps: PropTypes.object,
52
56
  toolbarOpts: PropTypes.shape({
53
57
  position: PropTypes.oneOf(['bottom', 'top']),
54
58
  alignment: PropTypes.oneOf(['left', 'right']),
55
59
  alwaysVisible: PropTypes.bool,
56
- ref: PropTypes.obj,
60
+ ref: PropTypes.func,
57
61
  showDone: PropTypes.bool
58
62
  }),
59
63
  onDataChange: PropTypes.func
@@ -66,6 +70,10 @@ export class Toolbar extends React.Component {
66
70
  };
67
71
  }
68
72
 
73
+ componentWillUnmount() {
74
+ removeCharacterDialogs();
75
+ }
76
+
69
77
  hasMark = type => {
70
78
  const { value } = this.props;
71
79
  return value.marks.some(mark => mark.type == type);
@@ -134,6 +142,7 @@ export class Toolbar extends React.Component {
134
142
  value,
135
143
  autoWidth,
136
144
  onChange,
145
+ getFocusedValue,
137
146
  isFocused,
138
147
  onDone,
139
148
  toolbarRef
@@ -167,6 +176,11 @@ export class Toolbar extends React.Component {
167
176
  log('[render] plugin: ', plugin);
168
177
 
169
178
  const handleDone = (change, done) => {
179
+ // use handler only if this is an actual Slate Change
180
+ if (!(change instanceof Change)) {
181
+ return;
182
+ }
183
+
170
184
  let handler = onDone;
171
185
 
172
186
  if (plugin && plugin.toolbar && plugin.toolbar.customToolbar) {
@@ -241,6 +255,7 @@ export class Toolbar extends React.Component {
241
255
  pluginProps={pluginProps}
242
256
  value={value}
243
257
  onChange={onChange}
258
+ getFocusedValue={getFocusedValue}
244
259
  showDone={defaultToolbarShowDone}
245
260
  onDone={handleDone}
246
261
  deletable={deletable}
@@ -58,7 +58,16 @@ export const parseStyleString = s => {
58
58
  return result;
59
59
  };
60
60
 
61
- export const reactAttributes = o => toStyleObject(o, { camelize: true });
61
+ export const getBase64 = file => {
62
+ return new Promise((resolve, reject) => {
63
+ const reader = new FileReader();
64
+ reader.readAsDataURL(file);
65
+ reader.onload = () => resolve(reader.result);
66
+ reader.onerror = error => reject(error);
67
+ });
68
+ };
69
+
70
+ export const reactAttributes = o => toStyleObject(o, { camelize: true, addUnits: false });
62
71
 
63
72
  const attributesToMap = el => (acc, attribute) => {
64
73
  const value = el.getAttribute(attribute);
@@ -340,7 +349,7 @@ serializer.deserialize = function deserialize(html) {
340
349
 
341
350
  let i;
342
351
 
343
- for (i = 0; i < 1000; i++) {
352
+ for (i = 0; i < 3000; i++) {
344
353
  json.schema.rules.push({
345
354
  match: { object: 'document' },
346
355
  nodes: [{ match: { object: 'block' } }]
@@ -356,7 +365,14 @@ serializer.deserialize = function deserialize(html) {
356
365
  return null;
357
366
  };
358
367
 
359
- export const htmlToValue = html => serializer.deserialize(html);
368
+ export const htmlToValue = html => {
369
+ try {
370
+ return serializer.deserialize(html);
371
+ } catch (e) {
372
+ console.log("Couldn't parse html: ", e);
373
+ return {};
374
+ }
375
+ };
360
376
 
361
377
  export const valueToHtml = value => serializer.serialize(value);
362
378