@selfcommunity/react-ui 0.7.0-alpha.314 → 0.7.0-alpha.316
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/lib/cjs/components/Editor/Editor.js +0 -2
- package/lib/cjs/components/Editor/nodes/ImageNode.d.ts +8 -11
- package/lib/cjs/components/Editor/nodes/ImageNode.js +47 -313
- package/lib/cjs/components/Editor/plugins/ImagePlugin.js +1 -1
- package/lib/cjs/components/Feed/Feed.js +3 -2
- package/lib/esm/components/Editor/Editor.js +0 -2
- package/lib/esm/components/Editor/nodes/ImageNode.d.ts +8 -11
- package/lib/esm/components/Editor/nodes/ImageNode.js +49 -315
- package/lib/esm/components/Editor/plugins/ImagePlugin.js +1 -1
- package/lib/esm/components/Feed/Feed.js +4 -3
- package/lib/umd/react-ui.js +1 -1
- package/package.json +2 -2
|
@@ -1,250 +1,20 @@
|
|
|
1
|
-
import React, { Suspense, useCallback, useEffect, useRef
|
|
2
|
-
import { $getNodeByKey, $getSelection, $isNodeSelection, $setSelection, CLICK_COMMAND, COMMAND_PRIORITY_LOW, DecoratorNode,
|
|
1
|
+
import React, { Suspense, useCallback, useEffect, useRef } from 'react';
|
|
2
|
+
import { $getNodeByKey, $getSelection, $isNodeSelection, $setSelection, CLICK_COMMAND, COMMAND_PRIORITY_LOW, DecoratorNode, KEY_BACKSPACE_COMMAND, KEY_DELETE_COMMAND, KEY_ENTER_COMMAND, KEY_ESCAPE_COMMAND, SELECTION_CHANGE_COMMAND, TextNode } from 'lexical';
|
|
3
3
|
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
|
4
4
|
import { useLexicalNodeSelection } from '@lexical/react/useLexicalNodeSelection';
|
|
5
5
|
import { mergeRegister } from '@lexical/utils';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
position: 'absolute',
|
|
19
|
-
top: 0,
|
|
20
|
-
left: 0,
|
|
21
|
-
zIndex: 2000,
|
|
22
|
-
outline: `2px solid ${theme.palette.primary.main}`,
|
|
23
|
-
userSelect: 'none',
|
|
24
|
-
display: 'flex',
|
|
25
|
-
justifyContent: 'center',
|
|
26
|
-
alignItems: 'center',
|
|
27
|
-
'& .MuiPaper-root': {
|
|
28
|
-
padding: theme.spacing(1),
|
|
29
|
-
display: 'flex',
|
|
30
|
-
flexDirection: 'column',
|
|
31
|
-
justifyContent: 'center',
|
|
32
|
-
alignItems: 'center',
|
|
33
|
-
width: '50%',
|
|
34
|
-
backgroundColor: theme.palette.background.paper,
|
|
35
|
-
'& > *': {
|
|
36
|
-
margin: theme.spacing(1)
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}));
|
|
40
|
-
const ImageEdit = ({ onResize, onDelete, imageRef }) => {
|
|
41
|
-
// STATE
|
|
42
|
-
const [width, setWidth] = useState(imageRef.current.width);
|
|
43
|
-
const [height, setHeight] = useState(imageRef.current.height);
|
|
44
|
-
const [openResizePanel, setOpenResizePanel] = useState(false);
|
|
45
|
-
// HANDLERS
|
|
46
|
-
const handleStopPropagation = (event) => {
|
|
47
|
-
event.preventDefault();
|
|
48
|
-
event.stopPropagation();
|
|
49
|
-
return false;
|
|
50
|
-
};
|
|
51
|
-
const handleOpenResizePanel = (event) => {
|
|
52
|
-
event.preventDefault();
|
|
53
|
-
event.stopPropagation();
|
|
54
|
-
setOpenResizePanel(true);
|
|
55
|
-
return false;
|
|
56
|
-
};
|
|
57
|
-
const handleChangeWidth = (event) => {
|
|
58
|
-
setWidth(event.target.value);
|
|
59
|
-
};
|
|
60
|
-
const handleChangeHeight = (event) => {
|
|
61
|
-
setHeight(event.target.value);
|
|
62
|
-
};
|
|
63
|
-
const handleResize = (event) => {
|
|
64
|
-
onResize(width, height);
|
|
65
|
-
setOpenResizePanel(false);
|
|
66
|
-
};
|
|
67
|
-
// RENDER
|
|
68
|
-
return (React.createElement(Root, { className: classes.root, style: { width: imageRef.current.width, height: imageRef.current.height }, contentEditable: false, onClick: handleStopPropagation },
|
|
69
|
-
React.createElement(Paper, null, openResizePanel ? (React.createElement(React.Fragment, null,
|
|
70
|
-
React.createElement(TextField, { value: width, type: "number", onChange: handleChangeWidth, label: React.createElement(FormattedMessage, { id: "ui.editor.imagePluginEdit.width", defaultMessage: "ui.editor.imagePluginEdit.width" }), InputProps: {
|
|
71
|
-
endAdornment: React.createElement(InputAdornment, { position: "start" }, "px")
|
|
72
|
-
} }),
|
|
73
|
-
React.createElement(TextField, { value: height, type: "number", onChange: handleChangeHeight, label: React.createElement(FormattedMessage, { id: "ui.editor.imagePluginEdit.height", defaultMessage: "ui.editor.imagePluginEdit.height" }), InputProps: {
|
|
74
|
-
endAdornment: React.createElement(InputAdornment, { position: "start" }, "px")
|
|
75
|
-
} }),
|
|
76
|
-
React.createElement(Button, { variant: "contained", color: "primary", disabled: width === imageRef.current.width && height === imageRef.current.height, onClick: handleResize },
|
|
77
|
-
React.createElement(FormattedMessage, { id: "ui.editor.imagePluginEdit.resize", defaultMessage: "ui.editor.imagePluginEdit.resize" })))) : (React.createElement(React.Fragment, null,
|
|
78
|
-
React.createElement(Button, { variant: "contained", color: "primary", onClick: handleOpenResizePanel },
|
|
79
|
-
React.createElement(FormattedMessage, { id: "ui.editor.imagePluginEdit.resize", defaultMessage: "ui.editor.imagePluginEdit.resize" })),
|
|
80
|
-
React.createElement(Button, { variant: "contained", color: "secondary", onClick: onDelete },
|
|
81
|
-
React.createElement(FormattedMessage, { id: "ui.editor.imagePluginEdit.delete", defaultMessage: "ui.editor.imagePluginEdit.delete" })))))));
|
|
82
|
-
};
|
|
83
|
-
function clamp(value, min, max) {
|
|
84
|
-
return Math.min(Math.max(value, min), Number(max));
|
|
85
|
-
}
|
|
86
|
-
const Direction = {
|
|
87
|
-
east: 1 << 0,
|
|
88
|
-
north: 1 << 3,
|
|
89
|
-
south: 1 << 1,
|
|
90
|
-
west: 1 << 2
|
|
91
|
-
};
|
|
92
|
-
function ImageResizer({ onResizeStart, onResizeEnd, imageRef, maxWidth, editor }) {
|
|
93
|
-
const controlWrapperRef = useRef(null);
|
|
94
|
-
const userSelect = useRef({
|
|
95
|
-
priority: '',
|
|
96
|
-
value: 'default'
|
|
97
|
-
});
|
|
98
|
-
const positioningRef = useRef({
|
|
99
|
-
currentHeight: 0,
|
|
100
|
-
currentWidth: 0,
|
|
101
|
-
direction: 0,
|
|
102
|
-
isResizing: false,
|
|
103
|
-
ratio: 0,
|
|
104
|
-
startHeight: 0,
|
|
105
|
-
startWidth: 0,
|
|
106
|
-
startX: 0,
|
|
107
|
-
startY: 0
|
|
108
|
-
});
|
|
109
|
-
const editorRootElement = editor.getRootElement();
|
|
110
|
-
// Find max width, accounting for editor padding.
|
|
111
|
-
const maxWidthContainer = maxWidth ? maxWidth : editorRootElement !== null ? editorRootElement.getBoundingClientRect().width - 20 : 100;
|
|
112
|
-
const maxHeightContainer = editorRootElement !== null ? editorRootElement.getBoundingClientRect().height - 20 : 100;
|
|
113
|
-
const minWidth = 100;
|
|
114
|
-
const minHeight = 100;
|
|
115
|
-
const setStartCursor = (direction) => {
|
|
116
|
-
const ew = direction === Direction.east || direction === Direction.west;
|
|
117
|
-
const ns = direction === Direction.north || direction === Direction.south;
|
|
118
|
-
const nwse = (direction & Direction.north && direction & Direction.west) || (direction & Direction.south && direction & Direction.east);
|
|
119
|
-
const cursorDir = ew ? 'ew' : ns ? 'ns' : nwse ? 'nwse' : 'nesw';
|
|
120
|
-
if (editorRootElement !== null) {
|
|
121
|
-
editorRootElement.style.setProperty('cursor', `${cursorDir}-resize`, 'important');
|
|
122
|
-
}
|
|
123
|
-
if (document.body !== null) {
|
|
124
|
-
document.body.style.setProperty('cursor', `${cursorDir}-resize`, 'important');
|
|
125
|
-
userSelect.current.value = document.body.style.getPropertyValue('-webkit-user-select');
|
|
126
|
-
userSelect.current.priority = document.body.style.getPropertyPriority('-webkit-user-select');
|
|
127
|
-
document.body.style.setProperty('-webkit-user-select', `none`, 'important');
|
|
128
|
-
}
|
|
129
|
-
};
|
|
130
|
-
const setEndCursor = () => {
|
|
131
|
-
if (editorRootElement !== null) {
|
|
132
|
-
editorRootElement.style.setProperty('cursor', 'text');
|
|
133
|
-
}
|
|
134
|
-
if (document.body !== null) {
|
|
135
|
-
document.body.style.setProperty('cursor', 'default');
|
|
136
|
-
document.body.style.setProperty('-webkit-user-select', userSelect.current.value, userSelect.current.priority);
|
|
137
|
-
}
|
|
138
|
-
};
|
|
139
|
-
const handlePointerDown = (event, direction) => {
|
|
140
|
-
if (!editor.isEditable()) {
|
|
141
|
-
return;
|
|
142
|
-
}
|
|
143
|
-
const image = imageRef.current;
|
|
144
|
-
const controlWrapper = controlWrapperRef.current;
|
|
145
|
-
if (image !== null && controlWrapper !== null) {
|
|
146
|
-
const { width, height } = image.getBoundingClientRect();
|
|
147
|
-
const positioning = positioningRef.current;
|
|
148
|
-
positioning.startWidth = width;
|
|
149
|
-
positioning.startHeight = height;
|
|
150
|
-
positioning.ratio = width / height;
|
|
151
|
-
positioning.currentWidth = width;
|
|
152
|
-
positioning.currentHeight = height;
|
|
153
|
-
positioning.startX = event.clientX;
|
|
154
|
-
positioning.startY = event.clientY;
|
|
155
|
-
positioning.isResizing = true;
|
|
156
|
-
positioning.direction = direction;
|
|
157
|
-
setStartCursor(direction);
|
|
158
|
-
onResizeStart();
|
|
159
|
-
controlWrapper.classList.add('image-control-wrapper--resizing');
|
|
160
|
-
image.style.height = `${height}px`;
|
|
161
|
-
image.style.width = `${width}px`;
|
|
162
|
-
document.addEventListener('pointermove', handlePointerMove);
|
|
163
|
-
document.addEventListener('pointerup', handlePointerUp);
|
|
164
|
-
}
|
|
165
|
-
};
|
|
166
|
-
const handlePointerMove = (event) => {
|
|
167
|
-
const image = imageRef.current;
|
|
168
|
-
const positioning = positioningRef.current;
|
|
169
|
-
const isHorizontal = positioning.direction & (Direction.east | Direction.west);
|
|
170
|
-
const isVertical = positioning.direction & (Direction.south | Direction.north);
|
|
171
|
-
if (image !== null && positioning.isResizing) {
|
|
172
|
-
// Corner cursor
|
|
173
|
-
if (isHorizontal && isVertical) {
|
|
174
|
-
let diff = Math.floor(positioning.startX - event.clientX);
|
|
175
|
-
diff = positioning.direction & Direction.east ? -diff : diff;
|
|
176
|
-
const width = clamp(positioning.startWidth + diff, minWidth, maxWidthContainer);
|
|
177
|
-
const height = width / positioning.ratio;
|
|
178
|
-
image.style.width = `${width}px`;
|
|
179
|
-
image.style.height = `${height}px`;
|
|
180
|
-
positioning.currentHeight = height;
|
|
181
|
-
positioning.currentWidth = width;
|
|
182
|
-
}
|
|
183
|
-
else if (isVertical) {
|
|
184
|
-
let diff = Math.floor(positioning.startY - event.clientY);
|
|
185
|
-
diff = positioning.direction & Direction.south ? -diff : diff;
|
|
186
|
-
const height = clamp(positioning.startHeight + diff, minHeight, maxHeightContainer);
|
|
187
|
-
image.style.height = `${height}px`;
|
|
188
|
-
positioning.currentHeight = height;
|
|
189
|
-
}
|
|
190
|
-
else {
|
|
191
|
-
let diff = Math.floor(positioning.startX - event.clientX);
|
|
192
|
-
diff = positioning.direction & Direction.east ? -diff : diff;
|
|
193
|
-
const width = clamp(positioning.startWidth + diff, minWidth, maxWidthContainer);
|
|
194
|
-
image.style.width = `${width}px`;
|
|
195
|
-
positioning.currentWidth = width;
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
};
|
|
199
|
-
const handlePointerUp = () => {
|
|
200
|
-
const image = imageRef.current;
|
|
201
|
-
const positioning = positioningRef.current;
|
|
202
|
-
const controlWrapper = controlWrapperRef.current;
|
|
203
|
-
if (image !== null && controlWrapper !== null && positioning.isResizing) {
|
|
204
|
-
const width = positioning.currentWidth;
|
|
205
|
-
const height = positioning.currentHeight;
|
|
206
|
-
positioning.startWidth = 0;
|
|
207
|
-
positioning.startHeight = 0;
|
|
208
|
-
positioning.ratio = 0;
|
|
209
|
-
positioning.startX = 0;
|
|
210
|
-
positioning.startY = 0;
|
|
211
|
-
positioning.currentWidth = 0;
|
|
212
|
-
positioning.currentHeight = 0;
|
|
213
|
-
positioning.isResizing = false;
|
|
214
|
-
controlWrapper.classList.remove('image-control-wrapper--resizing');
|
|
215
|
-
setEndCursor();
|
|
216
|
-
console.log(width);
|
|
217
|
-
console.log(height);
|
|
218
|
-
onResizeEnd(width, height);
|
|
219
|
-
document.removeEventListener('pointermove', handlePointerMove);
|
|
220
|
-
document.removeEventListener('pointerup', handlePointerUp);
|
|
221
|
-
}
|
|
222
|
-
};
|
|
223
|
-
return (React.createElement("div", { ref: controlWrapperRef },
|
|
224
|
-
React.createElement("div", { className: "image-resizer image-resizer-n", onPointerDown: (event) => {
|
|
225
|
-
handlePointerDown(event, Direction.north);
|
|
226
|
-
} }),
|
|
227
|
-
React.createElement("div", { className: "image-resizer image-resizer-ne", onPointerDown: (event) => {
|
|
228
|
-
handlePointerDown(event, Direction.north | Direction.east);
|
|
229
|
-
} }),
|
|
230
|
-
React.createElement("div", { className: "image-resizer image-resizer-e", onPointerDown: (event) => {
|
|
231
|
-
handlePointerDown(event, Direction.east);
|
|
232
|
-
} }),
|
|
233
|
-
React.createElement("div", { className: "image-resizer image-resizer-se", onPointerDown: (event) => {
|
|
234
|
-
handlePointerDown(event, Direction.south | Direction.east);
|
|
235
|
-
} }),
|
|
236
|
-
React.createElement("div", { className: "image-resizer image-resizer-s", onPointerDown: (event) => {
|
|
237
|
-
handlePointerDown(event, Direction.south);
|
|
238
|
-
} }),
|
|
239
|
-
React.createElement("div", { className: "image-resizer image-resizer-sw", onPointerDown: (event) => {
|
|
240
|
-
handlePointerDown(event, Direction.south | Direction.west);
|
|
241
|
-
} }),
|
|
242
|
-
React.createElement("div", { className: "image-resizer image-resizer-w", onPointerDown: (event) => {
|
|
243
|
-
handlePointerDown(event, Direction.west);
|
|
244
|
-
} }),
|
|
245
|
-
React.createElement("div", { className: "image-resizer image-resizer-nw", onPointerDown: (event) => {
|
|
246
|
-
handlePointerDown(event, Direction.north | Direction.west);
|
|
247
|
-
} })));
|
|
6
|
+
/**
|
|
7
|
+
* Limit the width of an image
|
|
8
|
+
* Used to compute the padding-bottom of the div that wrap the img
|
|
9
|
+
*/
|
|
10
|
+
const IMAGE_WIDTH_THRESHOLD = 500;
|
|
11
|
+
/**
|
|
12
|
+
* Calc aspect-ratio of image
|
|
13
|
+
* @param width
|
|
14
|
+
* @param height
|
|
15
|
+
*/
|
|
16
|
+
function getAspectRatio(width, height) {
|
|
17
|
+
return width / height;
|
|
248
18
|
}
|
|
249
19
|
const imageCache = new Set();
|
|
250
20
|
function useSuspenseImage(src) {
|
|
@@ -259,21 +29,21 @@ function useSuspenseImage(src) {
|
|
|
259
29
|
});
|
|
260
30
|
}
|
|
261
31
|
}
|
|
262
|
-
function LazyImage({ altText, className, imageRef, src, width, height
|
|
32
|
+
function LazyImage({ altText, className, imageRef, src, width, height }) {
|
|
263
33
|
useSuspenseImage(src);
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
34
|
+
const aspectRatio = getAspectRatio(IMAGE_WIDTH_THRESHOLD, height);
|
|
35
|
+
return (React.createElement("div", { draggable: false, className: className, style: { position: 'relative', paddingBottom: `${100 / aspectRatio}%` } },
|
|
36
|
+
React.createElement("img", { src: src, alt: altText, ref: imageRef, style: {
|
|
37
|
+
position: 'absolute',
|
|
38
|
+
height: `100%`,
|
|
39
|
+
width: `100%`
|
|
40
|
+
} })));
|
|
269
41
|
}
|
|
270
|
-
function ImageComponent({ src, altText, nodeKey, width, height
|
|
42
|
+
function ImageComponent({ src, altText, nodeKey, width, height }) {
|
|
271
43
|
const imageRef = useRef(null);
|
|
272
44
|
const buttonRef = useRef(null);
|
|
273
45
|
const [isSelected, setSelected, clearSelection] = useLexicalNodeSelection(nodeKey);
|
|
274
|
-
const [isResizing, setIsResizing] = useState(false);
|
|
275
46
|
const [editor] = useLexicalComposerContext();
|
|
276
|
-
const [selection, setSelection] = useState(null);
|
|
277
47
|
const activeEditorRef = useRef(null);
|
|
278
48
|
const onDelete = useCallback((payload) => {
|
|
279
49
|
if (isSelected && $isNodeSelection($getSelection())) {
|
|
@@ -314,19 +84,11 @@ function ImageComponent({ src, altText, nodeKey, width, height, maxWidth, resiza
|
|
|
314
84
|
return false;
|
|
315
85
|
}, [editor, setSelected]);
|
|
316
86
|
useEffect(() => {
|
|
317
|
-
|
|
318
|
-
const unregister = mergeRegister(editor.registerUpdateListener(({ editorState }) => {
|
|
319
|
-
if (isMounted) {
|
|
320
|
-
setSelection(editorState.read(() => $getSelection()));
|
|
321
|
-
}
|
|
322
|
-
}), editor.registerCommand(SELECTION_CHANGE_COMMAND, (_, activeEditor) => {
|
|
87
|
+
const unregister = mergeRegister(editor.registerCommand(SELECTION_CHANGE_COMMAND, (_, activeEditor) => {
|
|
323
88
|
activeEditorRef.current = activeEditor;
|
|
324
89
|
return false;
|
|
325
90
|
}, COMMAND_PRIORITY_LOW), editor.registerCommand(CLICK_COMMAND, (payload) => {
|
|
326
91
|
const event = payload;
|
|
327
|
-
if (isResizing) {
|
|
328
|
-
return true;
|
|
329
|
-
}
|
|
330
92
|
if (event.target === imageRef.current) {
|
|
331
93
|
if (event.shiftKey) {
|
|
332
94
|
setSelected(!isSelected);
|
|
@@ -338,65 +100,36 @@ function ImageComponent({ src, altText, nodeKey, width, height, maxWidth, resiza
|
|
|
338
100
|
return true;
|
|
339
101
|
}
|
|
340
102
|
return false;
|
|
341
|
-
}, COMMAND_PRIORITY_LOW), editor.registerCommand(DRAGSTART_COMMAND, (event) => {
|
|
342
|
-
if (event.target === imageRef.current) {
|
|
343
|
-
// TODO This is just a temporary workaround for FF to behave like other browsers.
|
|
344
|
-
// Ideally, this handles drag & drop too (and all browsers).
|
|
345
|
-
event.preventDefault();
|
|
346
|
-
return true;
|
|
347
|
-
}
|
|
348
|
-
return false;
|
|
349
103
|
}, COMMAND_PRIORITY_LOW), editor.registerCommand(KEY_DELETE_COMMAND, onDelete, COMMAND_PRIORITY_LOW), editor.registerCommand(KEY_BACKSPACE_COMMAND, onDelete, COMMAND_PRIORITY_LOW), editor.registerCommand(KEY_ENTER_COMMAND, onEnter, COMMAND_PRIORITY_LOW), editor.registerCommand(KEY_ESCAPE_COMMAND, onEscape, COMMAND_PRIORITY_LOW));
|
|
350
104
|
return () => {
|
|
351
|
-
isMounted = false;
|
|
352
105
|
unregister();
|
|
353
106
|
};
|
|
354
|
-
}, [clearSelection, editor,
|
|
355
|
-
const
|
|
356
|
-
// Delay hiding the resize bars for click case
|
|
357
|
-
setTimeout(() => {
|
|
358
|
-
setIsResizing(false);
|
|
359
|
-
}, 200);
|
|
360
|
-
editor.update(() => {
|
|
361
|
-
const node = $getNodeByKey(nodeKey);
|
|
362
|
-
if ($isImageNode(node)) {
|
|
363
|
-
node.setWidthAndHeight(nextWidth, nextHeight);
|
|
364
|
-
}
|
|
365
|
-
});
|
|
366
|
-
};
|
|
367
|
-
const onResizeStart = () => {
|
|
368
|
-
setIsResizing(true);
|
|
369
|
-
};
|
|
370
|
-
const draggable = isSelected && $isNodeSelection(selection) && !isResizing;
|
|
371
|
-
const isFocused = isSelected || isResizing;
|
|
107
|
+
}, [clearSelection, editor, isSelected, nodeKey, onDelete, onEnter, onEscape, setSelected]);
|
|
108
|
+
const isFocused = isSelected;
|
|
372
109
|
return (React.createElement(Suspense, { fallback: null },
|
|
373
|
-
React.createElement(
|
|
374
|
-
React.createElement("div", { draggable: draggable },
|
|
375
|
-
React.createElement(LazyImage, { className: isFocused ? `focused ${$isNodeSelection(selection) ? 'draggable' : ''}` : null, src: src, altText: altText, imageRef: imageRef, width: width, height: height, maxWidth: maxWidth })),
|
|
376
|
-
resizable && $isNodeSelection(selection) && isFocused && (React.createElement(ImageResizer, { editor: editor, imageRef: imageRef, maxWidth: typeof maxWidth === 'number' ? maxWidth : null, onResizeStart: onResizeStart, onResizeEnd: onResizeEnd })))));
|
|
110
|
+
React.createElement(LazyImage, { className: isFocused ? `focused` : null, src: src, altText: altText, imageRef: imageRef, width: width, height: height })));
|
|
377
111
|
}
|
|
378
112
|
function convertImageElement(domNode) {
|
|
379
113
|
if (domNode instanceof HTMLImageElement) {
|
|
380
|
-
const { alt: altText, src, width, height } = domNode;
|
|
381
|
-
const node = $createImageNode({ altText, height, src, width
|
|
114
|
+
const { alt: altText, src, dataset: { width, height } } = domNode;
|
|
115
|
+
const node = $createImageNode({ altText, height: Number(height), src, width: Number(width) });
|
|
382
116
|
return { node };
|
|
383
117
|
}
|
|
384
118
|
return null;
|
|
385
119
|
}
|
|
386
120
|
export class ImageNode extends DecoratorNode {
|
|
387
|
-
constructor(src, altText,
|
|
121
|
+
constructor(src, altText, width, height, key) {
|
|
388
122
|
super(key);
|
|
389
123
|
this.__src = src;
|
|
390
124
|
this.__altText = altText;
|
|
391
|
-
this.
|
|
392
|
-
this.
|
|
393
|
-
this.__height = height || 'inherit';
|
|
125
|
+
this.__width = width;
|
|
126
|
+
this.__height = height;
|
|
394
127
|
}
|
|
395
128
|
static getType() {
|
|
396
129
|
return 'image';
|
|
397
130
|
}
|
|
398
131
|
static clone(node) {
|
|
399
|
-
return new ImageNode(node.__src, node.__altText, node.
|
|
132
|
+
return new ImageNode(node.__src, node.__altText, node.__width, node.__height, node.__key);
|
|
400
133
|
}
|
|
401
134
|
setWidthAndHeight(width, height) {
|
|
402
135
|
const writable = this.getWritable();
|
|
@@ -430,24 +163,26 @@ export class ImageNode extends DecoratorNode {
|
|
|
430
163
|
}) }, dom);
|
|
431
164
|
}
|
|
432
165
|
exportDOM() {
|
|
433
|
-
const
|
|
434
|
-
element.
|
|
435
|
-
element.setAttribute('
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
166
|
+
const aspectRatio = getAspectRatio(this.__width, this.__height);
|
|
167
|
+
const element = document.createElement('div');
|
|
168
|
+
element.setAttribute('style', `position: relative;padding-bottom:${100 / aspectRatio}%`);
|
|
169
|
+
const image = document.createElement('img');
|
|
170
|
+
image.setAttribute('src', this.__src);
|
|
171
|
+
image.setAttribute('alt', this.__altText);
|
|
172
|
+
image.setAttribute('style', `position: absolute;width:100%;height:100%;`);
|
|
173
|
+
image.setAttribute('data-width', `${this.__width}`);
|
|
174
|
+
image.setAttribute('data-height', `${this.__height}`);
|
|
175
|
+
element.appendChild(image);
|
|
439
176
|
return { element };
|
|
440
177
|
}
|
|
441
178
|
decorate() {
|
|
442
|
-
|
|
443
|
-
return (React.createElement(ImageComponent, { src: this.__src, altText: this.__altText, width: this.__width, height: this.__height, maxWidth: this.__maxWidth, nodeKey: this.getKey(), resizable: true }));
|
|
179
|
+
return React.createElement(ImageComponent, { src: this.__src, altText: this.__altText, width: this.__width, height: this.__height, nodeKey: this.getKey() });
|
|
444
180
|
}
|
|
445
181
|
static importJSON(serializedNode) {
|
|
446
|
-
const { altText, height, width,
|
|
182
|
+
const { altText, height, width, src } = serializedNode;
|
|
447
183
|
const node = $createImageNode({
|
|
448
184
|
altText,
|
|
449
185
|
height,
|
|
450
|
-
maxWidth,
|
|
451
186
|
src,
|
|
452
187
|
width
|
|
453
188
|
});
|
|
@@ -456,17 +191,16 @@ export class ImageNode extends DecoratorNode {
|
|
|
456
191
|
exportJSON() {
|
|
457
192
|
return {
|
|
458
193
|
altText: this.getAltText(),
|
|
459
|
-
height: this.__height
|
|
460
|
-
maxWidth: this.__maxWidth,
|
|
194
|
+
height: this.__height,
|
|
461
195
|
src: this.getSrc(),
|
|
462
196
|
type: 'image',
|
|
463
197
|
version: 1,
|
|
464
|
-
width: this.__width
|
|
198
|
+
width: this.__width
|
|
465
199
|
};
|
|
466
200
|
}
|
|
467
201
|
}
|
|
468
|
-
export function $createImageNode({ src, altText,
|
|
469
|
-
return new ImageNode(src, altText,
|
|
202
|
+
export function $createImageNode({ src, altText, width, height }) {
|
|
203
|
+
return new ImageNode(src, altText, width, height);
|
|
470
204
|
}
|
|
471
205
|
export function $isImageNode(node) {
|
|
472
206
|
return node.getType() === 'image';
|
|
@@ -91,7 +91,7 @@ export default function ImagePlugin() {
|
|
|
91
91
|
if ($isRootNode(selection.anchor.getNode())) {
|
|
92
92
|
selection.insertParagraph();
|
|
93
93
|
}
|
|
94
|
-
const imageNode = $createImageNode({ src: payload.src, altText: payload.altText,
|
|
94
|
+
const imageNode = $createImageNode({ src: payload.src, altText: payload.altText, width: payload.width, height: payload.height });
|
|
95
95
|
selection.insertNodes([imageNode]);
|
|
96
96
|
}
|
|
97
97
|
return true;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import React, { forwardRef, useContext, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
|
|
3
3
|
import { Link, SCCache, SCPreferences, SCPreferencesContext, SCUserContext, useSCFetchFeed, usePreviousValue, useIsComponentMountedRef } from '@selfcommunity/react-core';
|
|
4
4
|
import { styled, useTheme } from '@mui/material/styles';
|
|
5
|
-
import { Box, CardContent, Grid, Hidden, useMediaQuery } from
|
|
5
|
+
import { Box, CardContent, Grid, Hidden, useMediaQuery } from '@mui/material';
|
|
6
6
|
import { FormattedMessage } from 'react-intl';
|
|
7
7
|
import { GenericSkeleton } from '../Skeleton';
|
|
8
8
|
import CustomAdv from '../CustomAdv';
|
|
@@ -25,6 +25,7 @@ const PREFIX = 'SCFeed';
|
|
|
25
25
|
const classes = {
|
|
26
26
|
root: `${PREFIX}-root`,
|
|
27
27
|
left: `${PREFIX}-left`,
|
|
28
|
+
leftItems: `${PREFIX}-left-items`,
|
|
28
29
|
start: `${PREFIX}-start`,
|
|
29
30
|
end: `${PREFIX}-end`,
|
|
30
31
|
endMessage: `${PREFIX}-end-message`,
|
|
@@ -411,14 +412,14 @@ const Feed = (inProps, ref) => {
|
|
|
411
412
|
React.createElement(CustomAdv, Object.assign({ position: SCCustomAdvPosition.POSITION_BELOW_TOPBAR }, CustomAdvProps)))) : null,
|
|
412
413
|
React.createElement(Grid, { item: true, xs: 12, md: 7 },
|
|
413
414
|
React.createElement("div", { style: { overflow: 'visible' } },
|
|
414
|
-
React.createElement(InfiniteScroll, { className: classes.left, dataLength: feedDataLeft.length, next: getNextPage, previous: getPreviousPage, hasMoreNext: Boolean(feedDataObject.next), hasMorePrevious: Boolean(feedDataObject.previous), header: PreviousPageLink, footer: NextPageLink, loaderNext: React.createElement(ItemSkeleton, Object.assign({}, ItemSkeletonProps)), loaderPrevious: React.createElement(ItemSkeleton, Object.assign({}, ItemSkeletonProps)), scrollThreshold:
|
|
415
|
+
React.createElement(InfiniteScroll, { className: classes.left, dataLength: feedDataLeft.length, next: getNextPage, previous: getPreviousPage, hasMoreNext: Boolean(feedDataObject.next), hasMorePrevious: Boolean(feedDataObject.previous), header: PreviousPageLink, footer: NextPageLink, loaderNext: React.createElement(ItemSkeleton, Object.assign({}, ItemSkeletonProps)), loaderPrevious: React.createElement(ItemSkeleton, Object.assign({}, ItemSkeletonProps)), scrollThreshold: '80%', endMessage: React.createElement(Box, { className: classes.end },
|
|
415
416
|
React.createElement(Widget, { className: classes.endMessage },
|
|
416
417
|
React.createElement(CardContent, null, endMessage)),
|
|
417
418
|
advEnabled && !hideAdvs && enabledCustomAdvPositions.includes(SCCustomAdvPosition.POSITION_ABOVE_FOOTER_BAR) ? (React.createElement(CustomAdv, Object.assign({ position: SCCustomAdvPosition.POSITION_ABOVE_FOOTER_BAR }, CustomAdvProps))) : null,
|
|
418
419
|
FooterComponent ? React.createElement(FooterComponent, Object.assign({}, FooterComponentProps)) : null), refreshFunction: refresh, pullDownToRefresh: true, pullDownToRefreshThreshold: 1000, pullDownToRefreshContent: null, releaseToRefreshContent: React.createElement(Widget, { variant: "outlined", className: classes.refresh },
|
|
419
420
|
React.createElement(CardContent, null, refreshMessage)), style: { overflow: 'visible' } },
|
|
420
421
|
renderHeaderComponent(),
|
|
421
|
-
React.createElement(VirtualizedScroller, Object.assign({ items: feedDataLeft, itemComponent: InnerItem, onMount: onScrollerMount, onScrollerStateChange: onScrollerStateChange, getItemId: getScrollItemId, preserveScrollPosition: true, preserveScrollPositionOnPrependItems: true, cacheScrollStateKey: SCCache.getVirtualizedScrollStateCacheKey(id), cacheScrollerPositionKey: SCCache.getFeedSPCacheKey(id), cacheStrategy: cacheStrategy }, VirtualizedScrollerProps))))),
|
|
422
|
+
React.createElement(VirtualizedScroller, Object.assign({ className: classes.leftItems, items: feedDataLeft, itemComponent: InnerItem, onMount: onScrollerMount, onScrollerStateChange: onScrollerStateChange, getItemId: getScrollItemId, preserveScrollPosition: true, preserveScrollPositionOnPrependItems: true, cacheScrollStateKey: SCCache.getVirtualizedScrollStateCacheKey(id), cacheScrollerPositionKey: SCCache.getFeedSPCacheKey(id), cacheStrategy: cacheStrategy }, VirtualizedScrollerProps))))),
|
|
422
423
|
feedDataRight.length > 0 && !hideAdvs && (React.createElement(Hidden, { smDown: true },
|
|
423
424
|
React.createElement(Grid, { item: true, xs: 12, md: 5 },
|
|
424
425
|
React.createElement(StickyBoxComp, Object.assign({ className: classes.right }, FeedSidebarProps),
|