@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.
- package/CHANGELOG.json +1 -1
- package/CHANGELOG.md +81 -0
- package/LICENSE.md +5 -0
- package/lib/editor.js +410 -543
- package/lib/editor.js.map +1 -1
- package/lib/index.js +200 -101
- package/lib/index.js.map +1 -1
- package/lib/parse-html.js +5 -6
- package/lib/parse-html.js.map +1 -1
- package/lib/plugins/characters/custom-popper.js +12 -2
- package/lib/plugins/characters/custom-popper.js.map +1 -1
- package/lib/plugins/characters/index.js +71 -19
- package/lib/plugins/characters/index.js.map +1 -1
- package/lib/plugins/characters/utils.js.map +1 -1
- package/lib/plugins/html/icons/index.js +38 -0
- package/lib/plugins/html/icons/index.js.map +1 -0
- package/lib/plugins/html/index.js +75 -0
- package/lib/plugins/html/index.js.map +1 -0
- package/lib/plugins/image/alt-dialog.js +26 -0
- package/lib/plugins/image/alt-dialog.js.map +1 -1
- package/lib/plugins/image/component.js +124 -90
- package/lib/plugins/image/component.js.map +1 -1
- package/lib/plugins/image/image-toolbar.js +45 -7
- package/lib/plugins/image/image-toolbar.js.map +1 -1
- package/lib/plugins/image/index.js +91 -113
- package/lib/plugins/image/index.js.map +1 -1
- package/lib/plugins/image/insert-image-handler.js +54 -72
- package/lib/plugins/image/insert-image-handler.js.map +1 -1
- package/lib/plugins/index.js +71 -31
- package/lib/plugins/index.js.map +1 -1
- package/lib/plugins/list/index.js +129 -58
- package/lib/plugins/list/index.js.map +1 -1
- package/lib/plugins/math/index.js +152 -118
- package/lib/plugins/math/index.js.map +1 -1
- package/lib/plugins/media/index.js +185 -168
- package/lib/plugins/media/index.js.map +1 -1
- package/lib/plugins/media/media-dialog.js +197 -110
- package/lib/plugins/media/media-dialog.js.map +1 -1
- package/lib/plugins/media/media-toolbar.js +24 -4
- package/lib/plugins/media/media-toolbar.js.map +1 -1
- package/lib/plugins/media/media-wrapper.js +65 -23
- package/lib/plugins/media/media-wrapper.js.map +1 -1
- package/lib/plugins/respArea/drag-in-the-blank/choice.js +50 -10
- package/lib/plugins/respArea/drag-in-the-blank/choice.js.map +1 -1
- package/lib/plugins/respArea/drag-in-the-blank/index.js +22 -9
- package/lib/plugins/respArea/drag-in-the-blank/index.js.map +1 -1
- package/lib/plugins/respArea/explicit-constructed-response/index.js +9 -4
- package/lib/plugins/respArea/explicit-constructed-response/index.js.map +1 -1
- package/lib/plugins/respArea/icons/index.js +18 -1
- package/lib/plugins/respArea/icons/index.js.map +1 -1
- package/lib/plugins/respArea/index.js +133 -122
- package/lib/plugins/respArea/index.js.map +1 -1
- package/lib/plugins/respArea/inline-dropdown/index.js +10 -4
- package/lib/plugins/respArea/inline-dropdown/index.js.map +1 -1
- package/lib/plugins/respArea/utils.js +33 -15
- package/lib/plugins/respArea/utils.js.map +1 -1
- package/lib/plugins/table/icons/index.js +7 -0
- package/lib/plugins/table/icons/index.js.map +1 -1
- package/lib/plugins/table/index.js +279 -390
- package/lib/plugins/table/index.js.map +1 -1
- package/lib/plugins/table/table-toolbar.js +47 -14
- package/lib/plugins/table/table-toolbar.js.map +1 -1
- package/lib/plugins/toolbar/default-toolbar.js +63 -51
- package/lib/plugins/toolbar/default-toolbar.js.map +1 -1
- package/lib/plugins/toolbar/done-button.js +9 -1
- package/lib/plugins/toolbar/done-button.js.map +1 -1
- package/lib/plugins/toolbar/editor-and-toolbar.js +140 -83
- package/lib/plugins/toolbar/editor-and-toolbar.js.map +1 -1
- package/lib/plugins/toolbar/index.js +5 -0
- package/lib/plugins/toolbar/index.js.map +1 -1
- package/lib/plugins/toolbar/toolbar-buttons.js +39 -8
- package/lib/plugins/toolbar/toolbar-buttons.js.map +1 -1
- package/lib/plugins/toolbar/toolbar.js +261 -225
- package/lib/plugins/toolbar/toolbar.js.map +1 -1
- package/lib/plugins/utils.js +16 -19
- package/lib/plugins/utils.js.map +1 -1
- package/lib/serialization.js +70 -11
- package/lib/serialization.js.map +1 -1
- package/lib/theme.js.map +1 -1
- package/package.json +18 -17
- package/src/editor.jsx +139 -434
- package/src/index.jsx +96 -62
- package/src/plugins/characters/index.jsx +17 -12
- package/src/plugins/html/icons/index.jsx +19 -0
- package/src/plugins/html/index.jsx +68 -0
- package/src/plugins/image/component.jsx +38 -60
- package/src/plugins/image/index.jsx +42 -95
- package/src/plugins/image/insert-image-handler.js +27 -62
- package/src/plugins/index.jsx +39 -21
- package/src/plugins/list/index.jsx +90 -62
- package/src/plugins/math/index.jsx +70 -93
- package/src/plugins/media/index.jsx +117 -146
- package/src/plugins/media/media-dialog.js +9 -10
- package/src/plugins/media/media-wrapper.jsx +27 -29
- package/src/plugins/respArea/drag-in-the-blank/index.jsx +4 -5
- package/src/plugins/respArea/explicit-constructed-response/index.jsx +1 -2
- package/src/plugins/respArea/index.jsx +84 -114
- package/src/plugins/respArea/inline-dropdown/index.jsx +2 -3
- package/src/plugins/respArea/utils.jsx +28 -23
- package/src/plugins/table/index.jsx +214 -334
- package/src/plugins/table/table-toolbar.jsx +4 -3
- package/src/plugins/toolbar/default-toolbar.jsx +30 -48
- package/src/plugins/toolbar/editor-and-toolbar.jsx +114 -114
- package/src/plugins/toolbar/toolbar.jsx +224 -254
- package/src/plugins/utils.js +0 -16
- package/src/serialization.jsx +1 -1
- package/lib/components.js +0 -92
- package/lib/components.js.map +0 -1
- package/lib/new-serialization.js +0 -280
- package/lib/new-serialization.js.map +0 -1
- package/lib/plugins/hotKeys/index.js +0 -60
- package/lib/plugins/hotKeys/index.js.map +0 -1
- package/lib/test-serializer.js +0 -138
- package/lib/test-serializer.js.map +0 -1
- package/src/components.js +0 -135
- package/src/new-serialization.jsx +0 -310
- package/src/plugins/hotKeys/index.js +0 -54
- package/src/test-serializer.js +0 -132
package/src/index.jsx
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import React
|
|
2
|
-
import { useSlate } from 'slate-react';
|
|
1
|
+
import React from 'react';
|
|
3
2
|
import PropTypes from 'prop-types';
|
|
4
3
|
import Editor, { DEFAULT_PLUGINS, ALL_PLUGINS } from './editor';
|
|
5
|
-
import { htmlToValue, valueToHtml } from './
|
|
4
|
+
import { htmlToValue, valueToHtml } from './serialization';
|
|
6
5
|
import { parseDegrees } from './parse-html';
|
|
7
6
|
import debug from 'debug';
|
|
8
7
|
import { Range } from 'slate';
|
|
@@ -13,43 +12,87 @@ const log = debug('@pie-lib:editable-html');
|
|
|
13
12
|
*/
|
|
14
13
|
export { htmlToValue, valueToHtml, Editor, DEFAULT_PLUGINS, ALL_PLUGINS };
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
/**
|
|
16
|
+
* Wrapper around the editor that exposes a `markup` and `onChange(markup:string)` api.
|
|
17
|
+
* Because of the mismatch between the markup and the `Value` we need to convert the incoming markup to a value and
|
|
18
|
+
* compare it. TODO: This is an interim fix, we'll need to strip back `Editor` and look how best to maintain the
|
|
19
|
+
* `markup` api whilst avoiding the serialization mismatch. We should be making better use of schemas w/ normalize.
|
|
20
|
+
*/
|
|
18
21
|
|
|
19
|
-
|
|
20
|
-
|
|
22
|
+
const reduceMultipleBrs = (markup) => {
|
|
23
|
+
try {
|
|
24
|
+
return markup.replace(/(<br\s*\/?>){3,}/gi, '<br>');
|
|
25
|
+
} catch (e) {
|
|
26
|
+
// eslint-disable-next-line no-console
|
|
27
|
+
console.log("Couldn't remove <br/> tags: ", e);
|
|
21
28
|
}
|
|
22
29
|
|
|
23
|
-
|
|
24
|
-
setHasBeenCalled(true);
|
|
30
|
+
return markup;
|
|
25
31
|
};
|
|
26
32
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
33
|
+
export default class EditableHtml extends React.Component {
|
|
34
|
+
static propTypes = {
|
|
35
|
+
error: PropTypes.any,
|
|
36
|
+
onChange: PropTypes.func.isRequired,
|
|
37
|
+
onDone: PropTypes.func,
|
|
38
|
+
markup: PropTypes.string.isRequired,
|
|
39
|
+
allowValidation: PropTypes.bool,
|
|
40
|
+
toolbarOpts: PropTypes.object,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
static defaultProps = {
|
|
44
|
+
onDone: () => {},
|
|
45
|
+
allowValidation: false,
|
|
46
|
+
};
|
|
31
47
|
|
|
32
|
-
|
|
48
|
+
constructor(props) {
|
|
49
|
+
super(props);
|
|
33
50
|
const v = htmlToValue(props.markup);
|
|
34
|
-
|
|
35
|
-
|
|
51
|
+
this.state = {
|
|
52
|
+
value: v,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// eslint-disable-next-line react/no-deprecated
|
|
57
|
+
componentWillReceiveProps(props) {
|
|
58
|
+
if (!props.allowValidation && props.markup === this.props.markup) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const v = htmlToValue(reduceMultipleBrs(props.markup));
|
|
63
|
+
const current = htmlToValue(reduceMultipleBrs(this.props.markup));
|
|
64
|
+
|
|
65
|
+
if (v.equals && !v.equals(current)) {
|
|
66
|
+
this.setState({ value: v });
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
runSerializationOnMarkup = () => {
|
|
71
|
+
if (!this.props.markup) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const v = htmlToValue(reduceMultipleBrs(this.props.markup));
|
|
36
76
|
|
|
37
|
-
|
|
77
|
+
this.setState({ value: v });
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
onChange = (value, done) => {
|
|
38
81
|
const html = valueToHtml(value);
|
|
39
82
|
const htmlParsed = parseDegrees(html);
|
|
40
83
|
|
|
41
84
|
log('value as html: ', html);
|
|
42
85
|
|
|
43
|
-
if (html !== props.markup) {
|
|
44
|
-
props.onChange(htmlParsed);
|
|
86
|
+
if (html !== this.props.markup) {
|
|
87
|
+
this.props.onChange(htmlParsed);
|
|
45
88
|
}
|
|
46
89
|
|
|
47
90
|
if (done) {
|
|
48
|
-
props.onDone(htmlParsed);
|
|
91
|
+
this.props.onDone(htmlParsed);
|
|
49
92
|
}
|
|
50
93
|
};
|
|
51
94
|
|
|
52
|
-
|
|
95
|
+
focus = (position, node, select = false) => {
|
|
53
96
|
if (this.editorRef) {
|
|
54
97
|
this.editorRef.change((c) => {
|
|
55
98
|
const lastText = node ? c.value.document.getNextText(node.key) : c.value.document.getLastText();
|
|
@@ -84,48 +127,39 @@ const EditableHtml = React.forwardRef((props, forwardedRef) => {
|
|
|
84
127
|
}
|
|
85
128
|
};
|
|
86
129
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const newProps = {
|
|
94
|
-
...props,
|
|
95
|
-
markup: null,
|
|
96
|
-
value,
|
|
97
|
-
onChange,
|
|
98
|
-
focus,
|
|
130
|
+
finishEditing = () => {
|
|
131
|
+
if (this.editorRef) {
|
|
132
|
+
this.editorRef.props.onEditingDone();
|
|
133
|
+
}
|
|
99
134
|
};
|
|
100
135
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
onRef={(ref) => {
|
|
105
|
-
if (ref) {
|
|
106
|
-
rootRef.current = ref;
|
|
136
|
+
render() {
|
|
137
|
+
const { value } = this.state;
|
|
138
|
+
const { toolbarOpts, error } = this.props;
|
|
107
139
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
112
|
-
}}
|
|
113
|
-
editorRef={(ref) => ref && (editorRef.current = ref)}
|
|
114
|
-
/>
|
|
115
|
-
);
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
EditableHtml.propTypes = {
|
|
119
|
-
onChange: PropTypes.func.isRequired,
|
|
120
|
-
onDone: PropTypes.func,
|
|
121
|
-
onEditor: PropTypes.func,
|
|
122
|
-
markup: PropTypes.string.isRequired,
|
|
123
|
-
allowValidation: PropTypes.bool,
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
EditableHtml.defaultProps = {
|
|
127
|
-
onDone: () => {},
|
|
128
|
-
allowValidation: false,
|
|
129
|
-
};
|
|
140
|
+
if (toolbarOpts) {
|
|
141
|
+
toolbarOpts.error = error;
|
|
142
|
+
}
|
|
130
143
|
|
|
131
|
-
|
|
144
|
+
const props = {
|
|
145
|
+
...this.props,
|
|
146
|
+
markup: null,
|
|
147
|
+
value,
|
|
148
|
+
onChange: this.onChange,
|
|
149
|
+
focus: this.focus,
|
|
150
|
+
runSerializationOnMarkup: this.runSerializationOnMarkup,
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
return (
|
|
154
|
+
<Editor
|
|
155
|
+
onRef={(ref) => {
|
|
156
|
+
if (ref) {
|
|
157
|
+
this.rootRef = ref;
|
|
158
|
+
}
|
|
159
|
+
}}
|
|
160
|
+
editorRef={(ref) => ref && (this.editorRef = ref)}
|
|
161
|
+
{...props}
|
|
162
|
+
/>
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { ReactEditor } from 'slate-react';
|
|
3
|
-
import { Editor } from 'slate';
|
|
4
2
|
import ReactDOM from 'react-dom';
|
|
5
|
-
import PropTypes from 'prop-types';
|
|
6
3
|
import debug from 'debug';
|
|
7
4
|
import get from 'lodash/get';
|
|
8
5
|
|
|
@@ -11,6 +8,7 @@ import { PureToolbar } from '@pie-lib/math-toolbar';
|
|
|
11
8
|
import CustomPopper from './custom-popper';
|
|
12
9
|
import { insertSnackBar } from '../respArea/utils';
|
|
13
10
|
import { characterIcons, spanishConfig, specialConfig } from './utils';
|
|
11
|
+
import PropTypes from 'prop-types';
|
|
14
12
|
const log = debug('@pie-lib:editable-html:plugins:characters');
|
|
15
13
|
|
|
16
14
|
const removePopOvers = () => {
|
|
@@ -28,7 +26,7 @@ export const removeDialogs = () => {
|
|
|
28
26
|
removePopOvers();
|
|
29
27
|
};
|
|
30
28
|
|
|
31
|
-
const insertDialog = ({
|
|
29
|
+
const insertDialog = ({ editorDOM, value, callback, opts }) => {
|
|
32
30
|
const newEl = document.createElement('div');
|
|
33
31
|
|
|
34
32
|
log('[characters:insertDialog]');
|
|
@@ -108,7 +106,6 @@ const insertDialog = ({ editor, callback, opts }) => {
|
|
|
108
106
|
// so right after mouseup, the click will be triggered
|
|
109
107
|
if (firstCallMade) {
|
|
110
108
|
const focusIsInModals = newEl.contains(e.target) || (popoverEl && popoverEl.contains(e.target));
|
|
111
|
-
const editorDOM = ReactEditor.toDOMNode(editor, editor);
|
|
112
109
|
const focusIsInEditor = editorDOM.contains(e.target);
|
|
113
110
|
|
|
114
111
|
if (!(focusIsInModals || focusIsInEditor)) {
|
|
@@ -173,8 +170,7 @@ const insertDialog = ({ editor, callback, opts }) => {
|
|
|
173
170
|
);
|
|
174
171
|
|
|
175
172
|
ReactDOM.render(el, newEl, () => {
|
|
176
|
-
const
|
|
177
|
-
const cursorItem = ReactEditor.toDOMNode(editor, nodeAtSelection);
|
|
173
|
+
const cursorItem = document.querySelector(`[data-key="${value.anchorKey}"]`);
|
|
178
174
|
|
|
179
175
|
if (cursorItem) {
|
|
180
176
|
const bodyRect = document.body.getBoundingClientRect();
|
|
@@ -241,21 +237,30 @@ export default function CharactersPlugin(opts) {
|
|
|
241
237
|
name: 'characters',
|
|
242
238
|
toolbar: {
|
|
243
239
|
icon: <CharacterIcon letter={opts.characterIcon || characterIcons[opts.language] || 'ñ'} />,
|
|
244
|
-
onClick: (
|
|
240
|
+
onClick: (value, onChange, getFocusedValue) => {
|
|
241
|
+
const editorDOM = document.querySelector(`[data-key="${value.document.key}"]`);
|
|
242
|
+
let valueToUse = value;
|
|
245
243
|
const callback = (char, focus) => {
|
|
244
|
+
valueToUse = getFocusedValue();
|
|
245
|
+
|
|
246
246
|
if (char) {
|
|
247
|
-
|
|
248
|
-
|
|
247
|
+
const change = valueToUse.change().insertTextByKey(valueToUse.anchorKey, valueToUse.anchorOffset, char);
|
|
248
|
+
|
|
249
|
+
valueToUse = change.value;
|
|
250
|
+
log('[characters:insert]: ', value);
|
|
251
|
+
onChange(change);
|
|
249
252
|
}
|
|
250
253
|
|
|
251
254
|
log('[characters:click]');
|
|
252
255
|
|
|
253
256
|
if (focus) {
|
|
254
|
-
|
|
257
|
+
if (editorDOM) {
|
|
258
|
+
editorDOM.focus();
|
|
259
|
+
}
|
|
255
260
|
}
|
|
256
261
|
};
|
|
257
262
|
|
|
258
|
-
insertDialog({
|
|
263
|
+
insertDialog({ editorDOM, value: valueToUse, callback, opts });
|
|
259
264
|
},
|
|
260
265
|
},
|
|
261
266
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { withStyles } from '@material-ui/core/styles';
|
|
3
|
+
|
|
4
|
+
const styles = (theme) => ({
|
|
5
|
+
icon: {
|
|
6
|
+
fontFamily: 'Cerebri Sans, Arial, sans-serif',
|
|
7
|
+
fontSize: theme.typography.fontSize,
|
|
8
|
+
fontWeight: 'bold',
|
|
9
|
+
lineHeight: '14px',
|
|
10
|
+
position: 'relative',
|
|
11
|
+
whiteSpace: 'nowrap',
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
const HtmlModeIcon = ({ classes, isHtmlMode }) => (
|
|
16
|
+
<div className={classes.icon}>{isHtmlMode ? 'Exit <HTML> mode' : '<HTML>'}</div>
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
export default withStyles(styles)(HtmlModeIcon);
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import HtmlModeIcon from './icons';
|
|
3
|
+
import { htmlToValue, valueToHtml } from './../../serialization';
|
|
4
|
+
|
|
5
|
+
const toggleToRichText = (value, onChange) => {
|
|
6
|
+
const plainText = value.document.text;
|
|
7
|
+
const slateValue = htmlToValue(plainText);
|
|
8
|
+
|
|
9
|
+
const change = value
|
|
10
|
+
.change()
|
|
11
|
+
.selectAll()
|
|
12
|
+
.delete()
|
|
13
|
+
.insertFragment(slateValue.document);
|
|
14
|
+
onChange(change);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export default function HtmlPlugin(opts) {
|
|
18
|
+
const { isHtmlMode, isEdited, toggleHtmlMode, handleAlertDialog } = opts;
|
|
19
|
+
|
|
20
|
+
const handleHtmlModeOn = (value, onChange) => {
|
|
21
|
+
const dialogProps = {
|
|
22
|
+
title: 'Warning',
|
|
23
|
+
text: 'Returning to rich text mode may cause edits to be lost.',
|
|
24
|
+
onConfirm: () => {
|
|
25
|
+
toggleToRichText(value, onChange);
|
|
26
|
+
handleAlertDialog(false);
|
|
27
|
+
},
|
|
28
|
+
onClose: () => {
|
|
29
|
+
handleAlertDialog(false);
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
handleAlertDialog(true, dialogProps);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const handleHtmlModeOff = (value, onChange) => {
|
|
37
|
+
const change = value
|
|
38
|
+
.change()
|
|
39
|
+
.selectAll()
|
|
40
|
+
.delete()
|
|
41
|
+
.insertText(valueToHtml(value));
|
|
42
|
+
onChange(change);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
name: 'html',
|
|
47
|
+
toolbar: {
|
|
48
|
+
icon: <HtmlModeIcon isHtmlMode={isHtmlMode} />,
|
|
49
|
+
buttonStyles: {
|
|
50
|
+
margin: '0 20px 0 auto',
|
|
51
|
+
},
|
|
52
|
+
type: 'html',
|
|
53
|
+
onClick: (value, onChange) => {
|
|
54
|
+
if (isHtmlMode) {
|
|
55
|
+
if (isEdited) {
|
|
56
|
+
handleHtmlModeOn(value, onChange);
|
|
57
|
+
} else {
|
|
58
|
+
toggleToRichText(value, onChange);
|
|
59
|
+
}
|
|
60
|
+
} else {
|
|
61
|
+
handleHtmlModeOff(value, onChange);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
toggleHtmlMode();
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
}
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
import
|
|
1
|
+
import LinearProgress from '@material-ui/core/LinearProgress';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
|
+
import React from 'react';
|
|
3
4
|
import classNames from 'classnames';
|
|
4
5
|
import debug from 'debug';
|
|
5
|
-
import isEqual from 'lodash/isEqual';
|
|
6
|
-
import cloneDeep from 'lodash/cloneDeep';
|
|
7
|
-
import LinearProgress from '@material-ui/core/LinearProgress';
|
|
8
6
|
import { withStyles } from '@material-ui/core/styles';
|
|
9
|
-
import
|
|
7
|
+
import SlatePropTypes from 'slate-prop-types';
|
|
10
8
|
|
|
11
9
|
const log = debug('@pie-lib:editable-html:plugins:image:component');
|
|
12
10
|
|
|
@@ -14,12 +12,7 @@ const size = (s) => (s ? `${s}px` : 'auto');
|
|
|
14
12
|
|
|
15
13
|
export class Component extends React.Component {
|
|
16
14
|
static propTypes = {
|
|
17
|
-
node:
|
|
18
|
-
type: PropTypes.string,
|
|
19
|
-
children: PropTypes.array,
|
|
20
|
-
data: PropTypes.object,
|
|
21
|
-
}).isRequired,
|
|
22
|
-
focused: PropTypes.bool,
|
|
15
|
+
node: SlatePropTypes.node.isRequired,
|
|
23
16
|
editor: PropTypes.shape({
|
|
24
17
|
change: PropTypes.func.isRequired,
|
|
25
18
|
value: PropTypes.object,
|
|
@@ -50,27 +43,17 @@ export class Component extends React.Component {
|
|
|
50
43
|
applySizeData = () => {
|
|
51
44
|
const { node, editor } = this.props;
|
|
52
45
|
|
|
53
|
-
let update =
|
|
54
|
-
|
|
55
|
-
const w = update.width;
|
|
46
|
+
let update = node.data;
|
|
56
47
|
|
|
48
|
+
const w = update.get('width');
|
|
57
49
|
if (w) {
|
|
58
|
-
update = update.resizePercent
|
|
50
|
+
update = update.set('resizePercent', this.getPercentFromWidth(w));
|
|
59
51
|
}
|
|
60
52
|
|
|
61
53
|
log('[applySizeData] update: ', update);
|
|
62
54
|
|
|
63
|
-
if (
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
editor.apply({
|
|
67
|
-
type: 'set_node',
|
|
68
|
-
path: nodePath,
|
|
69
|
-
properties: {
|
|
70
|
-
data: node.data,
|
|
71
|
-
},
|
|
72
|
-
newProperties: { data: update },
|
|
73
|
-
});
|
|
55
|
+
if (!update.equals(node.data)) {
|
|
56
|
+
editor.change((c) => c.setNodeByKey(node.key, { data: update }));
|
|
74
57
|
}
|
|
75
58
|
};
|
|
76
59
|
|
|
@@ -95,8 +78,8 @@ export class Component extends React.Component {
|
|
|
95
78
|
|
|
96
79
|
getSize(data) {
|
|
97
80
|
return {
|
|
98
|
-
width: size(data.width),
|
|
99
|
-
height: size(data.height),
|
|
81
|
+
width: size(data.get('width')),
|
|
82
|
+
height: size(data.get('height')),
|
|
100
83
|
objectFit: 'contain',
|
|
101
84
|
};
|
|
102
85
|
}
|
|
@@ -133,22 +116,13 @@ export class Component extends React.Component {
|
|
|
133
116
|
|
|
134
117
|
const { node, editor } = this.props;
|
|
135
118
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
update.width = width;
|
|
139
|
-
update.height = height;
|
|
119
|
+
let update = node.data;
|
|
140
120
|
|
|
141
|
-
|
|
142
|
-
|
|
121
|
+
update = update.set('width', width);
|
|
122
|
+
update = update.set('height', height);
|
|
143
123
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
path: nodePath,
|
|
147
|
-
properties: {
|
|
148
|
-
data: node.data,
|
|
149
|
-
},
|
|
150
|
-
newProperties: { data: update },
|
|
151
|
-
});
|
|
124
|
+
if (!update.equals(node.data)) {
|
|
125
|
+
editor.change((c) => c.setNodeByKey(node.key, { data: update }));
|
|
152
126
|
}
|
|
153
127
|
}
|
|
154
128
|
};
|
|
@@ -227,10 +201,14 @@ export class Component extends React.Component {
|
|
|
227
201
|
};
|
|
228
202
|
|
|
229
203
|
render() {
|
|
230
|
-
const { node,
|
|
231
|
-
const active =
|
|
232
|
-
const
|
|
233
|
-
const
|
|
204
|
+
const { node, editor, classes, attributes, onFocus } = this.props;
|
|
205
|
+
const active = editor.value.isFocused && editor.value.selection.hasEdgeIn(node);
|
|
206
|
+
const src = node.data.get('src');
|
|
207
|
+
const loaded = node.data.get('loaded') !== false;
|
|
208
|
+
const deleteStatus = node.data.get('deleteStatus');
|
|
209
|
+
const alignment = node.data.get('alignment');
|
|
210
|
+
const percent = node.data.get('percent');
|
|
211
|
+
const alt = node.data.get('alt');
|
|
234
212
|
let justifyContent;
|
|
235
213
|
|
|
236
214
|
switch (alignment) {
|
|
@@ -256,22 +234,22 @@ export class Component extends React.Component {
|
|
|
256
234
|
|
|
257
235
|
log('[render] style:', size);
|
|
258
236
|
|
|
259
|
-
const className = classNames(
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
237
|
+
const className = classNames(
|
|
238
|
+
classes.root,
|
|
239
|
+
!loaded && classes.loading,
|
|
240
|
+
deleteStatus === 'pending' && classes.pendingDelete,
|
|
241
|
+
);
|
|
263
242
|
|
|
264
|
-
const progressClasses = classNames(classes.progress,
|
|
265
|
-
[classes.hideProgress]: isLoaded,
|
|
266
|
-
});
|
|
243
|
+
const progressClasses = classNames(classes.progress, loaded && classes.hideProgress);
|
|
267
244
|
|
|
268
|
-
return
|
|
269
|
-
<
|
|
270
|
-
|
|
245
|
+
return [
|
|
246
|
+
<span key={'sp1'}> </span>,
|
|
247
|
+
<div key={'comp'} onFocus={onFocus} className={className} style={{ justifyContent }}>
|
|
271
248
|
<LinearProgress mode="determinate" value={percent > 0 ? percent : 0} className={progressClasses} />
|
|
272
249
|
<div className={classes.imageContainer}>
|
|
273
250
|
<img
|
|
274
|
-
|
|
251
|
+
{...attributes}
|
|
252
|
+
className={classNames(classes.image, active && classes.active)}
|
|
275
253
|
ref={(ref) => {
|
|
276
254
|
this.img = ref;
|
|
277
255
|
}}
|
|
@@ -287,8 +265,9 @@ export class Component extends React.Component {
|
|
|
287
265
|
className={classNames(classes.resize, 'resize')}
|
|
288
266
|
/>
|
|
289
267
|
</div>
|
|
290
|
-
</div
|
|
291
|
-
|
|
268
|
+
</div>,
|
|
269
|
+
<span key={'sp2'}> </span>,
|
|
270
|
+
];
|
|
292
271
|
}
|
|
293
272
|
}
|
|
294
273
|
|
|
@@ -328,7 +307,6 @@ const styles = (theme) => ({
|
|
|
328
307
|
border: `solid 1px ${theme.palette.common.white}`,
|
|
329
308
|
display: 'flex',
|
|
330
309
|
transition: 'opacity 200ms linear',
|
|
331
|
-
width: '100%',
|
|
332
310
|
},
|
|
333
311
|
delete: {
|
|
334
312
|
position: 'absolute',
|