@pie-lib/editable-html 9.0.2 → 9.0.5
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.md +27 -0
- package/lib/editor.js +75 -27
- package/lib/editor.js.map +1 -1
- package/lib/index.js +3 -1
- package/lib/index.js.map +1 -1
- package/lib/plugins/image/alt-dialog.js +119 -0
- package/lib/plugins/image/alt-dialog.js.map +1 -0
- package/lib/plugins/image/component.js +3 -1
- package/lib/plugins/image/component.js.map +1 -1
- package/lib/plugins/image/image-toolbar.js +52 -4
- package/lib/plugins/image/image-toolbar.js.map +1 -1
- package/lib/plugins/image/index.js +11 -6
- package/lib/plugins/image/index.js.map +1 -1
- package/lib/plugins/respArea/index.js.map +1 -1
- package/lib/plugins/table/index.js.map +1 -1
- package/package.json +4 -3
- package/src/editor.jsx +38 -8
- package/src/index.jsx +2 -2
- package/src/plugins/image/alt-dialog.jsx +69 -0
- package/src/plugins/image/component.jsx +2 -0
- package/src/plugins/image/image-toolbar.jsx +44 -4
- package/src/plugins/image/index.jsx +12 -5
- package/src/plugins/respArea/index.jsx +0 -1
- package/src/plugins/table/index.jsx +3 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pie-lib/editable-html",
|
|
3
|
-
"version": "9.0.
|
|
3
|
+
"version": "9.0.5",
|
|
4
4
|
"description": "",
|
|
5
5
|
"license": "ISC",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"@material-ui/styles": "^3.0.0-alpha.10",
|
|
13
13
|
"@pie-lib/drag": "^1.1.52",
|
|
14
14
|
"@pie-lib/math-rendering": "^2.4.5",
|
|
15
|
-
"@pie-lib/math-toolbar": "^1.10.
|
|
15
|
+
"@pie-lib/math-toolbar": "^1.10.3",
|
|
16
16
|
"@pie-lib/render-ui": "^4.13.1",
|
|
17
17
|
"change-case": "^3.0.2",
|
|
18
18
|
"classnames": "^2.2.6",
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"slate-edit-list": "^0.11.3",
|
|
30
30
|
"slate-edit-table": "^0.17.0",
|
|
31
31
|
"slate-html-serializer": "^0.6.12",
|
|
32
|
+
"slate-plain-serializer": "^0.5.26",
|
|
32
33
|
"slate-prop-types": "^0.4.38",
|
|
33
34
|
"slate-react": "^0.14.3",
|
|
34
35
|
"slate-schema-violations": "^0.1.39",
|
|
@@ -46,6 +47,6 @@
|
|
|
46
47
|
"publishConfig": {
|
|
47
48
|
"access": "public"
|
|
48
49
|
},
|
|
49
|
-
"gitHead": "
|
|
50
|
+
"gitHead": "45e12d524142a6576c9ebb9292de01a34e88fc03",
|
|
50
51
|
"scripts": {}
|
|
51
52
|
}
|
package/src/editor.jsx
CHANGED
|
@@ -11,6 +11,8 @@ import debug from 'debug';
|
|
|
11
11
|
import { withStyles } from '@material-ui/core/styles';
|
|
12
12
|
import classNames from 'classnames';
|
|
13
13
|
import { color } from '@pie-lib/render-ui';
|
|
14
|
+
import Plain from 'slate-plain-serializer';
|
|
15
|
+
|
|
14
16
|
import { getBase64 } from './serialization';
|
|
15
17
|
|
|
16
18
|
export { ALL_PLUGINS, DEFAULT_PLUGINS, serialization };
|
|
@@ -31,7 +33,7 @@ const defaultResponseAreaProps = {
|
|
|
31
33
|
onHandleAreaChange: () => {}
|
|
32
34
|
};
|
|
33
35
|
|
|
34
|
-
const defaultLanguageCharactersProps = [
|
|
36
|
+
const defaultLanguageCharactersProps = [];
|
|
35
37
|
|
|
36
38
|
const createToolbarOpts = toolbarOpts => {
|
|
37
39
|
return {
|
|
@@ -100,7 +102,7 @@ export class Editor extends React.Component {
|
|
|
100
102
|
}),
|
|
101
103
|
className: PropTypes.string,
|
|
102
104
|
maxImageWidth: PropTypes.number,
|
|
103
|
-
maxImageHeight: PropTypes.number
|
|
105
|
+
maxImageHeight: PropTypes.number
|
|
104
106
|
};
|
|
105
107
|
|
|
106
108
|
static defaultProps = {
|
|
@@ -350,7 +352,7 @@ export class Editor extends React.Component {
|
|
|
350
352
|
log('[onBlur] node: ', node);
|
|
351
353
|
|
|
352
354
|
return new Promise(resolve => {
|
|
353
|
-
this.setState({ focusedNode: node }, this.handleBlur.bind(this, resolve));
|
|
355
|
+
this.setState({ focusedNode: !node ? null : node }, this.handleBlur.bind(this, resolve));
|
|
354
356
|
this.props.onBlur(event);
|
|
355
357
|
});
|
|
356
358
|
};
|
|
@@ -572,14 +574,21 @@ export class Editor extends React.Component {
|
|
|
572
574
|
};
|
|
573
575
|
|
|
574
576
|
onDropPaste = async (event, change, dropContext) => {
|
|
575
|
-
if (!this.props.imageSupport) {
|
|
576
|
-
return;
|
|
577
|
-
}
|
|
578
577
|
const editor = change.editor;
|
|
579
578
|
const transfer = getEventTransfer(event);
|
|
580
|
-
const file = transfer.files[0];
|
|
579
|
+
const file = transfer.files && transfer.files[0];
|
|
580
|
+
|
|
581
|
+
const type = transfer.type;
|
|
582
|
+
const fragment = transfer.fragment;
|
|
583
|
+
const text = transfer.text;
|
|
581
584
|
|
|
582
|
-
if (
|
|
585
|
+
if (
|
|
586
|
+
file &&
|
|
587
|
+
(file.type === 'image/jpeg' || file.type === 'image/jpg' || file.type === 'image/png')
|
|
588
|
+
) {
|
|
589
|
+
if (!this.props.imageSupport) {
|
|
590
|
+
return;
|
|
591
|
+
}
|
|
583
592
|
try {
|
|
584
593
|
log('[onDropPaste]');
|
|
585
594
|
const src = await getBase64(file);
|
|
@@ -606,6 +615,27 @@ export class Editor extends React.Component {
|
|
|
606
615
|
} catch (err) {
|
|
607
616
|
log('[onDropPaste] error: ', err);
|
|
608
617
|
}
|
|
618
|
+
} else if (type === 'fragment') {
|
|
619
|
+
change.insertFragment(fragment);
|
|
620
|
+
} else if (type === 'text' || type === 'html') {
|
|
621
|
+
if (!text) {
|
|
622
|
+
return;
|
|
623
|
+
}
|
|
624
|
+
const {
|
|
625
|
+
value: { document, selection, startBlock }
|
|
626
|
+
} = change;
|
|
627
|
+
|
|
628
|
+
if (startBlock.isVoid) {
|
|
629
|
+
return;
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
const defaultBlock = startBlock;
|
|
633
|
+
const defaultMarks = document.getInsertMarksAtRange(selection);
|
|
634
|
+
const frag = Plain.deserialize(text, {
|
|
635
|
+
defaultBlock,
|
|
636
|
+
defaultMarks
|
|
637
|
+
}).document;
|
|
638
|
+
change.insertFragment(frag);
|
|
609
639
|
}
|
|
610
640
|
};
|
|
611
641
|
|
package/src/index.jsx
CHANGED
|
@@ -95,9 +95,9 @@ export default class EditableHtml extends React.Component {
|
|
|
95
95
|
c.focus();
|
|
96
96
|
|
|
97
97
|
if (position === 'end' && lastText) {
|
|
98
|
-
c.moveFocusTo(lastText.key, lastText.text
|
|
98
|
+
c.moveFocusTo(lastText.key, lastText.text?.length).moveAnchorTo(
|
|
99
99
|
lastText.key,
|
|
100
|
-
lastText.text
|
|
100
|
+
lastText.text?.length
|
|
101
101
|
);
|
|
102
102
|
}
|
|
103
103
|
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import DialogContent from '@material-ui/core/DialogContent';
|
|
3
|
+
import ArrowBackIos from '@material-ui/icons/ArrowBackIos';
|
|
4
|
+
import TextField from '@material-ui/core/TextField';
|
|
5
|
+
import DialogActions from '@material-ui/core/DialogActions';
|
|
6
|
+
import Button from '@material-ui/core/Button';
|
|
7
|
+
import Dialog from '@material-ui/core/Dialog';
|
|
8
|
+
import PropTypes from "prop-types";
|
|
9
|
+
|
|
10
|
+
export class AltDialog extends React.Component {
|
|
11
|
+
static propTypes = {
|
|
12
|
+
onDone: PropTypes.func.isRequired,
|
|
13
|
+
alt: PropTypes.string
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
constructor(props) {
|
|
17
|
+
super(props);
|
|
18
|
+
|
|
19
|
+
const { alt } = props;
|
|
20
|
+
|
|
21
|
+
this.state = {
|
|
22
|
+
value: alt
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
closeDialog = () => {
|
|
27
|
+
const allDialogs = document.querySelectorAll('#text-dialog');
|
|
28
|
+
|
|
29
|
+
allDialogs.forEach(function(s) {
|
|
30
|
+
return s.remove();
|
|
31
|
+
});
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
onDone = () => {
|
|
35
|
+
const { onDone } = this.props;
|
|
36
|
+
const { value } = this.state;
|
|
37
|
+
|
|
38
|
+
onDone(value);
|
|
39
|
+
this.closeDialog();
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
render() {
|
|
43
|
+
const { value } = this.state;
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<Dialog open disablePortal onClose={this.closeDialog} id="text-dialog" hideBackdrop>
|
|
47
|
+
<DialogContent>
|
|
48
|
+
<div style={{ display: 'flex' }}>
|
|
49
|
+
<ArrowBackIos style={{ paddingTop: '6px' }} />
|
|
50
|
+
<TextField
|
|
51
|
+
multiline
|
|
52
|
+
placeholder={'Enter an Alt Text description of this image'}
|
|
53
|
+
helperText={
|
|
54
|
+
'Users with visual limitations rely on Alt Text, since screen readers cannot otherwise describe the contents of an image.'
|
|
55
|
+
}
|
|
56
|
+
value={value}
|
|
57
|
+
onChange={event => this.setState({ value: event.target.value })}
|
|
58
|
+
/>
|
|
59
|
+
</div>
|
|
60
|
+
</DialogContent>
|
|
61
|
+
<DialogActions>
|
|
62
|
+
<Button onClick={this.onDone}>Done</Button>
|
|
63
|
+
</DialogActions>
|
|
64
|
+
</Dialog>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export default AltDialog;
|
|
@@ -208,6 +208,7 @@ export class Component extends React.Component {
|
|
|
208
208
|
const deleteStatus = node.data.get('deleteStatus');
|
|
209
209
|
const alignment = node.data.get('alignment');
|
|
210
210
|
const percent = node.data.get('percent');
|
|
211
|
+
const alt = node.data.get('alt');
|
|
211
212
|
let margin;
|
|
212
213
|
let justifyContent;
|
|
213
214
|
|
|
@@ -261,6 +262,7 @@ export class Component extends React.Component {
|
|
|
261
262
|
src={src}
|
|
262
263
|
style={size}
|
|
263
264
|
onLoad={this.loadImage}
|
|
265
|
+
alt={alt}
|
|
264
266
|
/>
|
|
265
267
|
<div
|
|
266
268
|
ref={ref => {
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import PropTypes from 'prop-types';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import debug from 'debug';
|
|
4
|
+
import ReactDOM from 'react-dom';
|
|
4
5
|
import { withStyles } from '@material-ui/core/styles';
|
|
6
|
+
import classNames from 'classnames';
|
|
5
7
|
|
|
6
8
|
import { MarkButton } from '../toolbar/toolbar-buttons';
|
|
9
|
+
import AltDialog from './alt-dialog';
|
|
7
10
|
|
|
8
11
|
const log = debug('@pie-lib:editable-html:plugins:image:image-toolbar');
|
|
9
12
|
|
|
@@ -24,16 +27,36 @@ AlignmentButton.propTypes = {
|
|
|
24
27
|
export class ImageToolbar extends React.Component {
|
|
25
28
|
static propTypes = {
|
|
26
29
|
onChange: PropTypes.func.isRequired,
|
|
27
|
-
classes: PropTypes.object.isRequired
|
|
30
|
+
classes: PropTypes.object.isRequired,
|
|
31
|
+
alignment: PropTypes.string,
|
|
32
|
+
alt: PropTypes.string,
|
|
33
|
+
imageLoaded: PropTypes.bool
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
onAltTextDone = newAlt => {
|
|
37
|
+
log('[onAltTextDone]: alt:', newAlt);
|
|
38
|
+
|
|
39
|
+
this.props.onChange({ alt: newAlt });
|
|
28
40
|
};
|
|
29
41
|
|
|
30
42
|
onAlignmentClick = alignment => {
|
|
31
43
|
log('[onAlignmentClick]: alignment:', alignment);
|
|
32
|
-
this.props.onChange(alignment);
|
|
44
|
+
this.props.onChange({ alignment });
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
renderDialog = () => {
|
|
48
|
+
const { alt } = this.props;
|
|
49
|
+
const popoverEl = document.createElement('div');
|
|
50
|
+
|
|
51
|
+
const el = <AltDialog alt={alt} onDone={this.onAltTextDone} />;
|
|
52
|
+
|
|
53
|
+
ReactDOM.render(el, popoverEl);
|
|
54
|
+
|
|
55
|
+
document.body.appendChild(popoverEl);
|
|
33
56
|
};
|
|
34
57
|
|
|
35
58
|
render() {
|
|
36
|
-
const { classes, alignment } = this.props;
|
|
59
|
+
const { classes, alignment, imageLoaded } = this.props;
|
|
37
60
|
|
|
38
61
|
return (
|
|
39
62
|
<div className={classes.holder}>
|
|
@@ -52,6 +75,15 @@ export class ImageToolbar extends React.Component {
|
|
|
52
75
|
active={alignment === 'right'}
|
|
53
76
|
onClick={this.onAlignmentClick}
|
|
54
77
|
/>
|
|
78
|
+
<span
|
|
79
|
+
className={classNames({
|
|
80
|
+
[classes.disabled]: !imageLoaded,
|
|
81
|
+
[classes.altButton]: true
|
|
82
|
+
})}
|
|
83
|
+
onMouseDown={event => imageLoaded && this.renderDialog(event)}
|
|
84
|
+
>
|
|
85
|
+
Alt text
|
|
86
|
+
</span>
|
|
55
87
|
</div>
|
|
56
88
|
);
|
|
57
89
|
}
|
|
@@ -62,7 +94,15 @@ const styles = theme => ({
|
|
|
62
94
|
paddingLeft: theme.spacing.unit,
|
|
63
95
|
display: 'flex',
|
|
64
96
|
alignItems: 'center'
|
|
65
|
-
}
|
|
97
|
+
},
|
|
98
|
+
disabled: {
|
|
99
|
+
opacity: 0.5
|
|
100
|
+
},
|
|
101
|
+
altButton: {
|
|
102
|
+
borderLeft: '1px solid grey',
|
|
103
|
+
paddingLeft: 8,
|
|
104
|
+
marginLeft: 4,
|
|
105
|
+
},
|
|
66
106
|
});
|
|
67
107
|
|
|
68
108
|
export default withStyles(styles)(ImageToolbar);
|
|
@@ -30,17 +30,21 @@ export default function ImagePlugin(opts) {
|
|
|
30
30
|
supports: node => node.object === 'inline' && node.type === 'image',
|
|
31
31
|
customToolbar: (node, value, onToolbarDone) => {
|
|
32
32
|
const alignment = node.data.get('alignment');
|
|
33
|
-
const
|
|
33
|
+
const alt = node.data.get('alt');
|
|
34
|
+
const imageLoaded = node.data.get('loaded') !== false;
|
|
35
|
+
const onChange = newValues => {
|
|
34
36
|
const update = {
|
|
35
37
|
...node.data.toObject(),
|
|
36
|
-
|
|
38
|
+
...newValues
|
|
37
39
|
};
|
|
38
40
|
|
|
39
41
|
const change = value.change().setNodeByKey(node.key, { data: update });
|
|
40
42
|
onToolbarDone(change, false);
|
|
41
43
|
};
|
|
42
44
|
|
|
43
|
-
const Tb = () =>
|
|
45
|
+
const Tb = () => (
|
|
46
|
+
<ImageToolbar alt={alt} imageLoaded={imageLoaded} alignment={alignment || 'left'} onChange={onChange} />
|
|
47
|
+
);
|
|
44
48
|
return Tb;
|
|
45
49
|
},
|
|
46
50
|
showDone: true
|
|
@@ -150,7 +154,8 @@ export const serialization = {
|
|
|
150
154
|
height,
|
|
151
155
|
margin: el.style.margin,
|
|
152
156
|
justifyContent: el.style.justifyContent,
|
|
153
|
-
alignment: el.getAttribute('alignment')
|
|
157
|
+
alignment: el.getAttribute('alignment'),
|
|
158
|
+
alt: el.getAttribute('alt')
|
|
154
159
|
}
|
|
155
160
|
};
|
|
156
161
|
log('return object: ', out);
|
|
@@ -166,6 +171,7 @@ export const serialization = {
|
|
|
166
171
|
const alignment = data.get('alignment');
|
|
167
172
|
const margin = data.get('margin');
|
|
168
173
|
const justifyContent = data.get('margin');
|
|
174
|
+
const alt = data.get('alt');
|
|
169
175
|
const style = {};
|
|
170
176
|
if (width) {
|
|
171
177
|
style.width = `${width}px`;
|
|
@@ -203,7 +209,8 @@ export const serialization = {
|
|
|
203
209
|
const props = {
|
|
204
210
|
src,
|
|
205
211
|
style,
|
|
206
|
-
alignment
|
|
212
|
+
alignment,
|
|
213
|
+
alt
|
|
207
214
|
};
|
|
208
215
|
|
|
209
216
|
return <img {...props} />;
|
|
@@ -79,7 +79,9 @@ TableCell.propTypes = {
|
|
|
79
79
|
};
|
|
80
80
|
|
|
81
81
|
export const moveFocusToBeginningOfTable = change => {
|
|
82
|
-
const addedTable = change.value.document.findDescendant(
|
|
82
|
+
const addedTable = change.value.document.findDescendant(
|
|
83
|
+
d => !!d.data && !!d.data.get('newTable')
|
|
84
|
+
);
|
|
83
85
|
|
|
84
86
|
if (!addedTable) {
|
|
85
87
|
return;
|