@pie-lib/editable-html 10.0.0-beta.7 → 10.0.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 (118) hide show
  1. package/CHANGELOG.json +1 -1
  2. package/CHANGELOG.md +81 -0
  3. package/LICENSE.md +5 -0
  4. package/lib/editor.js +410 -543
  5. package/lib/editor.js.map +1 -1
  6. package/lib/index.js +200 -101
  7. package/lib/index.js.map +1 -1
  8. package/lib/parse-html.js +5 -6
  9. package/lib/parse-html.js.map +1 -1
  10. package/lib/plugins/characters/custom-popper.js +12 -2
  11. package/lib/plugins/characters/custom-popper.js.map +1 -1
  12. package/lib/plugins/characters/index.js +71 -19
  13. package/lib/plugins/characters/index.js.map +1 -1
  14. package/lib/plugins/characters/utils.js.map +1 -1
  15. package/lib/plugins/html/icons/index.js +38 -0
  16. package/lib/plugins/html/icons/index.js.map +1 -0
  17. package/lib/plugins/html/index.js +75 -0
  18. package/lib/plugins/html/index.js.map +1 -0
  19. package/lib/plugins/image/alt-dialog.js +26 -0
  20. package/lib/plugins/image/alt-dialog.js.map +1 -1
  21. package/lib/plugins/image/component.js +124 -90
  22. package/lib/plugins/image/component.js.map +1 -1
  23. package/lib/plugins/image/image-toolbar.js +45 -7
  24. package/lib/plugins/image/image-toolbar.js.map +1 -1
  25. package/lib/plugins/image/index.js +91 -113
  26. package/lib/plugins/image/index.js.map +1 -1
  27. package/lib/plugins/image/insert-image-handler.js +54 -72
  28. package/lib/plugins/image/insert-image-handler.js.map +1 -1
  29. package/lib/plugins/index.js +71 -31
  30. package/lib/plugins/index.js.map +1 -1
  31. package/lib/plugins/list/index.js +129 -58
  32. package/lib/plugins/list/index.js.map +1 -1
  33. package/lib/plugins/math/index.js +152 -118
  34. package/lib/plugins/math/index.js.map +1 -1
  35. package/lib/plugins/media/index.js +185 -168
  36. package/lib/plugins/media/index.js.map +1 -1
  37. package/lib/plugins/media/media-dialog.js +197 -110
  38. package/lib/plugins/media/media-dialog.js.map +1 -1
  39. package/lib/plugins/media/media-toolbar.js +24 -4
  40. package/lib/plugins/media/media-toolbar.js.map +1 -1
  41. package/lib/plugins/media/media-wrapper.js +65 -23
  42. package/lib/plugins/media/media-wrapper.js.map +1 -1
  43. package/lib/plugins/respArea/drag-in-the-blank/choice.js +50 -10
  44. package/lib/plugins/respArea/drag-in-the-blank/choice.js.map +1 -1
  45. package/lib/plugins/respArea/drag-in-the-blank/index.js +22 -9
  46. package/lib/plugins/respArea/drag-in-the-blank/index.js.map +1 -1
  47. package/lib/plugins/respArea/explicit-constructed-response/index.js +9 -4
  48. package/lib/plugins/respArea/explicit-constructed-response/index.js.map +1 -1
  49. package/lib/plugins/respArea/icons/index.js +18 -1
  50. package/lib/plugins/respArea/icons/index.js.map +1 -1
  51. package/lib/plugins/respArea/index.js +133 -122
  52. package/lib/plugins/respArea/index.js.map +1 -1
  53. package/lib/plugins/respArea/inline-dropdown/index.js +10 -4
  54. package/lib/plugins/respArea/inline-dropdown/index.js.map +1 -1
  55. package/lib/plugins/respArea/utils.js +33 -15
  56. package/lib/plugins/respArea/utils.js.map +1 -1
  57. package/lib/plugins/table/icons/index.js +7 -0
  58. package/lib/plugins/table/icons/index.js.map +1 -1
  59. package/lib/plugins/table/index.js +279 -390
  60. package/lib/plugins/table/index.js.map +1 -1
  61. package/lib/plugins/table/table-toolbar.js +47 -14
  62. package/lib/plugins/table/table-toolbar.js.map +1 -1
  63. package/lib/plugins/toolbar/default-toolbar.js +63 -51
  64. package/lib/plugins/toolbar/default-toolbar.js.map +1 -1
  65. package/lib/plugins/toolbar/done-button.js +9 -1
  66. package/lib/plugins/toolbar/done-button.js.map +1 -1
  67. package/lib/plugins/toolbar/editor-and-toolbar.js +140 -83
  68. package/lib/plugins/toolbar/editor-and-toolbar.js.map +1 -1
  69. package/lib/plugins/toolbar/index.js +5 -0
  70. package/lib/plugins/toolbar/index.js.map +1 -1
  71. package/lib/plugins/toolbar/toolbar-buttons.js +39 -8
  72. package/lib/plugins/toolbar/toolbar-buttons.js.map +1 -1
  73. package/lib/plugins/toolbar/toolbar.js +261 -225
  74. package/lib/plugins/toolbar/toolbar.js.map +1 -1
  75. package/lib/plugins/utils.js +16 -19
  76. package/lib/plugins/utils.js.map +1 -1
  77. package/lib/serialization.js +70 -11
  78. package/lib/serialization.js.map +1 -1
  79. package/lib/theme.js.map +1 -1
  80. package/package.json +18 -17
  81. package/src/editor.jsx +139 -434
  82. package/src/index.jsx +96 -62
  83. package/src/plugins/characters/index.jsx +17 -12
  84. package/src/plugins/html/icons/index.jsx +19 -0
  85. package/src/plugins/html/index.jsx +68 -0
  86. package/src/plugins/image/component.jsx +38 -60
  87. package/src/plugins/image/index.jsx +42 -95
  88. package/src/plugins/image/insert-image-handler.js +27 -62
  89. package/src/plugins/index.jsx +39 -21
  90. package/src/plugins/list/index.jsx +90 -62
  91. package/src/plugins/math/index.jsx +70 -93
  92. package/src/plugins/media/index.jsx +117 -146
  93. package/src/plugins/media/media-dialog.js +9 -10
  94. package/src/plugins/media/media-wrapper.jsx +27 -29
  95. package/src/plugins/respArea/drag-in-the-blank/index.jsx +4 -5
  96. package/src/plugins/respArea/explicit-constructed-response/index.jsx +1 -2
  97. package/src/plugins/respArea/index.jsx +84 -114
  98. package/src/plugins/respArea/inline-dropdown/index.jsx +2 -3
  99. package/src/plugins/respArea/utils.jsx +28 -23
  100. package/src/plugins/table/index.jsx +214 -334
  101. package/src/plugins/table/table-toolbar.jsx +4 -3
  102. package/src/plugins/toolbar/default-toolbar.jsx +30 -48
  103. package/src/plugins/toolbar/editor-and-toolbar.jsx +114 -114
  104. package/src/plugins/toolbar/toolbar.jsx +224 -254
  105. package/src/plugins/utils.js +0 -16
  106. package/src/serialization.jsx +1 -1
  107. package/lib/components.js +0 -92
  108. package/lib/components.js.map +0 -1
  109. package/lib/new-serialization.js +0 -280
  110. package/lib/new-serialization.js.map +0 -1
  111. package/lib/plugins/hotKeys/index.js +0 -60
  112. package/lib/plugins/hotKeys/index.js.map +0 -1
  113. package/lib/test-serializer.js +0 -138
  114. package/lib/test-serializer.js.map +0 -1
  115. package/src/components.js +0 -135
  116. package/src/new-serialization.jsx +0 -310
  117. package/src/plugins/hotKeys/index.js +0 -54
  118. package/src/test-serializer.js +0 -132
@@ -14,7 +14,7 @@ const log = debug('@pie-lib:editable-html:plugins:table-toolbar');
14
14
  export class TableToolbar extends React.Component {
15
15
  static propTypes = {
16
16
  plugins: PropTypes.array.isRequired,
17
- editor: PropTypes.object.isRequired,
17
+ value: PropTypes.object.isRequired,
18
18
  onChange: PropTypes.func.isRequired,
19
19
  onAddRow: PropTypes.func.isRequired,
20
20
  onRemoveRow: PropTypes.func.isRequired,
@@ -29,6 +29,7 @@ export class TableToolbar extends React.Component {
29
29
 
30
30
  static defaultProps = {
31
31
  plugins: [],
32
+ value: {},
32
33
  onChange: () => {},
33
34
  };
34
35
 
@@ -41,7 +42,7 @@ export class TableToolbar extends React.Component {
41
42
  render() {
42
43
  const {
43
44
  plugins,
44
- editor,
45
+ value,
45
46
  onChange,
46
47
  onAddRow,
47
48
  onRemoveRow,
@@ -73,7 +74,7 @@ export class TableToolbar extends React.Component {
73
74
  <RemoveTable />
74
75
  </Button>
75
76
  {plugins.map((p, index) => (
76
- <ToolbarButton key={`plugin-${index}`} editor={editor} {...p.toolbar} onChange={onChange} />
77
+ <ToolbarButton key={`plugin-${index}`} {...p.toolbar} value={value} onChange={onChange} />
77
78
  ))}
78
79
  <Button onClick={onToggleBorder} active={hasBorder}>
79
80
  <BorderAll />
@@ -1,43 +1,26 @@
1
1
  import { DoneButton } from './done-button';
2
2
  import PropTypes from 'prop-types';
3
3
  import React from 'react';
4
+ import SlatePropTypes from 'slate-prop-types';
4
5
 
5
6
  import { hasBlock, hasMark } from '../utils';
6
7
  import { withStyles } from '@material-ui/core/styles';
7
8
 
8
9
  import { Button, MarkButton } from './toolbar-buttons';
9
10
  import debug from 'debug';
10
- import { Editor, Element as SlateElement } from 'slate';
11
+ import { is } from 'immutable';
11
12
 
12
13
  const log = debug('@pie-lib:editable-html:plugins:toolbar');
13
14
 
14
- const isMarkActive = (editor, format) => {
15
- const marks = Editor.marks(editor);
16
- return marks ? marks[format] === true : false;
17
- };
18
-
19
- const isBlockActive = (editor, format) => {
20
- const { selection } = editor;
21
- if (!selection) return false;
22
-
23
- const [match] = Array.from(
24
- Editor.nodes(editor, {
25
- at: Editor.unhangRange(editor, selection),
26
- match: (n) => !Editor.isEditor(n) && SlateElement.isElement(n) && n.type === format,
27
- }),
28
- );
29
-
30
- return !!match;
31
- };
32
-
33
15
  export const ToolbarButton = (props) => {
34
- const { editor } = props;
35
16
  const onToggle = () => {
36
- props.onToggle(editor, props);
17
+ const c = props.onToggle(props.value.change(), props);
18
+
19
+ props.onChange(c);
37
20
  };
38
21
 
39
22
  if (props.isMark) {
40
- const isActive = isMarkActive(editor, props.type);
23
+ const isActive = hasMark(props.value, props.type);
41
24
 
42
25
  log('[ToolbarButton] mark:isActive: ', isActive);
43
26
 
@@ -48,7 +31,7 @@ export const ToolbarButton = (props) => {
48
31
  );
49
32
  } else {
50
33
  const { disabled } = props;
51
- const isActive = props.isActive ? props.isActive(editor, props.type) : isBlockActive(editor, props.type);
34
+ const isActive = props.isActive ? props.isActive(props.value, props.type) : hasBlock(props.value, props.type);
52
35
 
53
36
  log('[ToolbarButton] block:isActive: ', isActive);
54
37
 
@@ -56,7 +39,7 @@ export const ToolbarButton = (props) => {
56
39
  <Button
57
40
  active={isActive}
58
41
  disabled={disabled}
59
- onClick={() => props.onClick(editor)}
42
+ onClick={() => props.onClick(props.value, props.onChange, props.getFocusedValue)}
60
43
  extraStyles={props.buttonStyles}
61
44
  >
62
45
  {props.icon}
@@ -66,15 +49,17 @@ export const ToolbarButton = (props) => {
66
49
  };
67
50
 
68
51
  ToolbarButton.propTypes = {
52
+ buttonStyles: PropTypes.object,
69
53
  disabled: PropTypes.bool,
70
- icon: PropTypes.object,
71
- editor: PropTypes.object,
72
- isActive: PropTypes.func,
54
+ icon: PropTypes.any,
55
+ isActive: PropTypes.bool,
73
56
  isMark: PropTypes.bool,
74
- onClick: PropTypes.func,
57
+ getFocusedValue: PropTypes.func,
75
58
  onToggle: PropTypes.func,
59
+ onChange: PropTypes.func,
60
+ onClick: PropTypes.func,
76
61
  type: PropTypes.string,
77
- buttonStyles: PropTypes.object,
62
+ value: PropTypes.object,
78
63
  };
79
64
 
80
65
  const isActiveToolbarPlugin = (props) => (plugin) => {
@@ -84,7 +69,6 @@ const isActiveToolbarPlugin = (props) => (plugin) => {
84
69
  };
85
70
 
86
71
  export const DefaultToolbar = ({
87
- editor,
88
72
  plugins,
89
73
  pluginProps,
90
74
  value,
@@ -94,26 +78,30 @@ export const DefaultToolbar = ({
94
78
  classes,
95
79
  showDone,
96
80
  deletable,
81
+ isHtmlMode,
97
82
  }) => {
98
- const filtered = plugins.filter(isActiveToolbarPlugin(pluginProps)).map((p) => p.toolbar);
83
+ let filtered;
84
+
85
+ if (isHtmlMode) {
86
+ filtered = plugins
87
+ .filter((plugin) => {
88
+ return isActiveToolbarPlugin(pluginProps)(plugin) && (plugin.name === 'characters' || plugin.name === 'html');
89
+ })
90
+ .map((p) => p.toolbar);
91
+ } else {
92
+ filtered = plugins.filter(isActiveToolbarPlugin(pluginProps)).map((p) => p.toolbar);
93
+ }
99
94
 
100
95
  return (
101
96
  <div className={classes.defaultToolbar}>
102
97
  <div className={classes.buttonsContainer}>
103
98
  {filtered.map((p, index) => {
104
99
  return (
105
- <ToolbarButton
106
- {...p}
107
- editor={editor}
108
- key={index}
109
- value={value}
110
- onChange={onChange}
111
- getFocusedValue={getFocusedValue}
112
- />
100
+ <ToolbarButton {...p} key={index} value={value} onChange={onChange} getFocusedValue={getFocusedValue} />
113
101
  );
114
102
  })}
115
103
  </div>
116
- {showDone && !deletable && <DoneButton onClick={() => onDone(editor)} />}
104
+ {showDone && !deletable && <DoneButton onClick={onDone} />}
117
105
  </div>
118
106
  );
119
107
  };
@@ -122,13 +110,7 @@ DefaultToolbar.propTypes = {
122
110
  classes: PropTypes.object.isRequired,
123
111
  plugins: PropTypes.array.isRequired,
124
112
  pluginProps: PropTypes.object,
125
- value: PropTypes.arrayOf(
126
- PropTypes.shape({
127
- type: PropTypes.string,
128
- children: PropTypes.array,
129
- data: PropTypes.object,
130
- }),
131
- ),
113
+ value: SlatePropTypes.value.isRequired,
132
114
  onChange: PropTypes.func.isRequired,
133
115
  getFocusedValue: PropTypes.func.isRequired,
134
116
  onDone: PropTypes.func.isRequired,
@@ -1,15 +1,128 @@
1
1
  import React from 'react';
2
-
3
2
  import Toolbar from './toolbar';
4
3
  import classNames from 'classnames';
5
4
  import debug from 'debug';
6
5
  import { primary } from '../../theme';
7
6
  import { withStyles } from '@material-ui/core/styles';
8
7
  import PropTypes from 'prop-types';
8
+ import SlatePropTypes from 'slate-prop-types';
9
+ import { IS_FIREFOX } from 'slate-dev-environment';
9
10
  import { color } from '@pie-lib/render-ui';
10
11
 
11
12
  const log = debug('@pie-lib:editable-html:plugins:toolbar:editor-and-toolbar');
12
13
 
14
+ export class EditorAndToolbar extends React.Component {
15
+ static propTypes = {
16
+ children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]).isRequired,
17
+ value: SlatePropTypes.value.isRequired,
18
+ plugins: PropTypes.array.isRequired,
19
+ onChange: PropTypes.func.isRequired,
20
+ getFocusedValue: PropTypes.func.isRequired,
21
+ onDone: PropTypes.func.isRequired,
22
+ onDataChange: PropTypes.func,
23
+ toolbarRef: PropTypes.func,
24
+ focusedNode: SlatePropTypes.node,
25
+ readOnly: PropTypes.bool,
26
+ disableScrollbar: PropTypes.bool,
27
+ disableUnderline: PropTypes.bool,
28
+ autoWidth: PropTypes.bool,
29
+ classes: PropTypes.object.isRequired,
30
+ pluginProps: PropTypes.object,
31
+ toolbarOpts: PropTypes.shape({
32
+ position: PropTypes.oneOf(['bottom', 'top']),
33
+ alwaysVisible: PropTypes.bool,
34
+ error: PropTypes.string,
35
+ noBorder: PropTypes.any,
36
+ }),
37
+ };
38
+
39
+ /** This is an interim fix until this PR is merged in slate:
40
+ * https://github.com/ianstormtaylor/slate/pull/2236
41
+ */
42
+ componentDidMount() {
43
+ if (IS_FIREFOX) {
44
+ this.editorRef.tmp.isUpdatingSelection = true;
45
+ }
46
+ }
47
+
48
+ render() {
49
+ const {
50
+ classes,
51
+ children,
52
+ value,
53
+ plugins,
54
+ onChange,
55
+ getFocusedValue,
56
+ onDone,
57
+ focusedNode,
58
+ autoWidth,
59
+ readOnly,
60
+ disableScrollbar,
61
+ disableUnderline,
62
+ pluginProps,
63
+ toolbarOpts,
64
+ onDataChange,
65
+ toolbarRef,
66
+ } = this.props;
67
+
68
+ const inFocus = value.isFocused || (focusedNode !== null && focusedNode !== undefined);
69
+ const holderNames = classNames(classes.editorHolder, {
70
+ [classes.editorInFocus]: inFocus,
71
+ [classes.readOnly]: readOnly,
72
+ [classes.disabledUnderline]: disableUnderline,
73
+ [classes.disabledScrollbar]: disableScrollbar,
74
+ });
75
+ let clonedChildren = children;
76
+
77
+ if (typeof children !== 'string') {
78
+ clonedChildren = React.cloneElement(children, {
79
+ ref: (el) => (this.editorRef = el),
80
+ });
81
+ }
82
+
83
+ log('[render] inFocus: ', inFocus, 'value.isFocused:', value.isFocused, 'focused node: ', focusedNode);
84
+
85
+ return (
86
+ <div
87
+ className={classNames(
88
+ {
89
+ [classes.noBorder]: toolbarOpts && toolbarOpts.noBorder,
90
+ [classes.error]: toolbarOpts && toolbarOpts.error,
91
+ },
92
+ classes.root,
93
+ )}
94
+ >
95
+ <div className={holderNames}>
96
+ <div
97
+ className={classNames(
98
+ {
99
+ [classes.noPadding]: toolbarOpts && toolbarOpts.noBorder,
100
+ },
101
+ classes.children,
102
+ )}
103
+ >
104
+ {clonedChildren}
105
+ </div>
106
+ </div>
107
+ <Toolbar
108
+ autoWidth={autoWidth}
109
+ plugins={plugins}
110
+ focusedNode={focusedNode}
111
+ value={value}
112
+ isFocused={inFocus}
113
+ onChange={onChange}
114
+ getFocusedValue={getFocusedValue}
115
+ onDone={onDone}
116
+ onDataChange={onDataChange}
117
+ toolbarRef={toolbarRef}
118
+ pluginProps={pluginProps}
119
+ toolbarOpts={toolbarOpts}
120
+ />
121
+ </div>
122
+ );
123
+ }
124
+ }
125
+
13
126
  const style = (theme) => ({
14
127
  root: {
15
128
  position: 'relative',
@@ -24,10 +137,6 @@ const style = (theme) => ({
24
137
  // needed in order to be able to put the focus before a void element when it is the first one in the editor
25
138
  padding: '5px',
26
139
  },
27
- '& [data-slate-void="true"]': {
28
- // needed in order to be able to put the focus before a void element when it is the first one in the editor
29
- padding: '1px',
30
- },
31
140
  },
32
141
  children: {
33
142
  padding: '10px 16px',
@@ -74,9 +183,6 @@ const style = (theme) => ({
74
183
  height: '2px',
75
184
  },
76
185
  },
77
- '& :focus-visible': {
78
- outline: 'none !important',
79
- },
80
186
  },
81
187
  disabledUnderline: {
82
188
  '&::before': {
@@ -143,110 +249,4 @@ const style = (theme) => ({
143
249
  },
144
250
  });
145
251
 
146
- export const EditorAndToolbar = (props) => {
147
- const {
148
- editor,
149
- classes,
150
- children,
151
- value,
152
- plugins,
153
- onChange,
154
- getFocusedValue,
155
- onDone,
156
- focusedNode,
157
- autoWidth,
158
- readOnly,
159
- disableScrollbar,
160
- disableUnderline,
161
- pluginProps,
162
- toolbarOpts,
163
- toolbarRef,
164
- isFocused,
165
- } = props;
166
-
167
- const holderNames = classNames(classes.editorHolder, {
168
- [classes.editorInFocus]: isFocused,
169
- [classes.readOnly]: readOnly,
170
- [classes.disabledUnderline]: disableUnderline,
171
- [classes.disabledScrollbar]: disableScrollbar,
172
- });
173
- let clonedChildren = children;
174
-
175
- log('[render] inFocus: ', isFocused, 'value.isFocused:', value.isFocused, 'focused node: ', focusedNode);
176
-
177
- return (
178
- <div
179
- className={classNames(
180
- {
181
- [classes.noBorder]: toolbarOpts && toolbarOpts.noBorder,
182
- [classes.error]: toolbarOpts && toolbarOpts.error,
183
- },
184
- classes.root,
185
- )}
186
- >
187
- <div className={holderNames}>
188
- <div
189
- className={classNames(
190
- {
191
- [classes.noPadding]: toolbarOpts && toolbarOpts.noBorder,
192
- },
193
- classes.children,
194
- )}
195
- >
196
- {clonedChildren}
197
- </div>
198
- </div>
199
- <Toolbar
200
- editor={editor}
201
- autoWidth={autoWidth}
202
- plugins={plugins}
203
- focusedNode={focusedNode}
204
- value={value}
205
- isFocused={isFocused}
206
- onChange={onChange}
207
- getFocusedValue={getFocusedValue}
208
- onDone={onDone}
209
- toolbarRef={toolbarRef}
210
- pluginProps={pluginProps}
211
- toolbarOpts={toolbarOpts}
212
- />
213
- </div>
214
- );
215
- };
216
-
217
- EditorAndToolbar.propTypes = {
218
- children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]).isRequired,
219
- value: PropTypes.arrayOf(
220
- PropTypes.shape({
221
- type: PropTypes.string,
222
- children: PropTypes.array,
223
- data: PropTypes.object,
224
- }),
225
- ),
226
- editor: PropTypes.object.isRequired,
227
- isFocused: PropTypes.bool,
228
- plugins: PropTypes.array.isRequired,
229
- onChange: PropTypes.func.isRequired,
230
- getFocusedValue: PropTypes.func.isRequired,
231
- onDone: PropTypes.func.isRequired,
232
- toolbarRef: PropTypes.func,
233
- focusedNode: PropTypes.shape({
234
- type: PropTypes.string,
235
- children: PropTypes.array,
236
- data: PropTypes.object,
237
- }),
238
- readOnly: PropTypes.bool,
239
- disableScrollbar: PropTypes.bool,
240
- disableUnderline: PropTypes.bool,
241
- autoWidth: PropTypes.bool,
242
- classes: PropTypes.object.isRequired,
243
- pluginProps: PropTypes.object,
244
- toolbarOpts: PropTypes.shape({
245
- alwaysVisible: PropTypes.bool,
246
- error: PropTypes.string,
247
- noBorder: PropTypes.bool,
248
- position: PropTypes.oneOf(['bottom', 'top']),
249
- }),
250
- };
251
-
252
252
  export default withStyles(style)(EditorAndToolbar);