@selfcommunity/react-ui 0.7.0-alpha.313 → 0.7.0-alpha.315

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.
@@ -1,251 +1,10 @@
1
- import React, { Suspense, useCallback, useEffect, useRef, useState } from 'react';
2
- import { $getNodeByKey, $getSelection, $isNodeSelection, $setSelection, CLICK_COMMAND, COMMAND_PRIORITY_LOW, DecoratorNode, DRAGSTART_COMMAND, KEY_BACKSPACE_COMMAND, KEY_DELETE_COMMAND, KEY_ENTER_COMMAND, KEY_ESCAPE_COMMAND, SELECTION_CHANGE_COMMAND, TextNode } from 'lexical';
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
- import { styled } from '@mui/material/styles';
7
- import { FormattedMessage } from 'react-intl';
8
- import { Box, Button, InputAdornment, Paper, TextField } from '@mui/material';
9
- const PREFIX = 'SCEditorImagePluginImageEdit';
10
- const classes = {
11
- root: `${PREFIX}-root`
12
- };
13
- const Root = styled(Box, {
14
- name: PREFIX,
15
- slot: 'Root',
16
- overridesResolver: (props, styles) => styles.root
17
- })(({ theme }) => ({
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
- console.log(width);
69
- return (React.createElement(Root, { className: classes.root, style: { width: imageRef.current.width, height: imageRef.current.height }, contentEditable: false, onClick: handleStopPropagation },
70
- React.createElement(Paper, null, openResizePanel ? (React.createElement(React.Fragment, null,
71
- React.createElement(TextField, { value: width, type: "number", onChange: handleChangeWidth, label: React.createElement(FormattedMessage, { id: "ui.editor.imagePluginEdit.width", defaultMessage: "ui.editor.imagePluginEdit.width" }), InputProps: {
72
- endAdornment: React.createElement(InputAdornment, { position: "start" }, "px")
73
- } }),
74
- React.createElement(TextField, { value: height, type: "number", onChange: handleChangeHeight, label: React.createElement(FormattedMessage, { id: "ui.editor.imagePluginEdit.height", defaultMessage: "ui.editor.imagePluginEdit.height" }), InputProps: {
75
- endAdornment: React.createElement(InputAdornment, { position: "start" }, "px")
76
- } }),
77
- React.createElement(Button, { variant: "contained", color: "primary", disabled: width === imageRef.current.width && height === imageRef.current.height, onClick: handleResize },
78
- React.createElement(FormattedMessage, { id: "ui.editor.imagePluginEdit.resize", defaultMessage: "ui.editor.imagePluginEdit.resize" })))) : (React.createElement(React.Fragment, null,
79
- React.createElement(Button, { variant: "contained", color: "primary", onClick: handleOpenResizePanel },
80
- React.createElement(FormattedMessage, { id: "ui.editor.imagePluginEdit.resize", defaultMessage: "ui.editor.imagePluginEdit.resize" })),
81
- React.createElement(Button, { variant: "contained", color: "secondary", onClick: onDelete },
82
- React.createElement(FormattedMessage, { id: "ui.editor.imagePluginEdit.delete", defaultMessage: "ui.editor.imagePluginEdit.delete" })))))));
83
- };
84
- function clamp(value, min, max) {
85
- return Math.min(Math.max(value, min), Number(max));
86
- }
87
- const Direction = {
88
- east: 1 << 0,
89
- north: 1 << 3,
90
- south: 1 << 1,
91
- west: 1 << 2
92
- };
93
- function ImageResizer({ onResizeStart, onResizeEnd, imageRef, maxWidth, editor }) {
94
- const controlWrapperRef = useRef(null);
95
- const userSelect = useRef({
96
- priority: '',
97
- value: 'default'
98
- });
99
- const positioningRef = useRef({
100
- currentHeight: 0,
101
- currentWidth: 0,
102
- direction: 0,
103
- isResizing: false,
104
- ratio: 0,
105
- startHeight: 0,
106
- startWidth: 0,
107
- startX: 0,
108
- startY: 0
109
- });
110
- const editorRootElement = editor.getRootElement();
111
- // Find max width, accounting for editor padding.
112
- const maxWidthContainer = maxWidth ? maxWidth : editorRootElement !== null ? editorRootElement.getBoundingClientRect().width - 20 : 100;
113
- const maxHeightContainer = editorRootElement !== null ? editorRootElement.getBoundingClientRect().height - 20 : 100;
114
- const minWidth = 100;
115
- const minHeight = 100;
116
- const setStartCursor = (direction) => {
117
- const ew = direction === Direction.east || direction === Direction.west;
118
- const ns = direction === Direction.north || direction === Direction.south;
119
- const nwse = (direction & Direction.north && direction & Direction.west) || (direction & Direction.south && direction & Direction.east);
120
- const cursorDir = ew ? 'ew' : ns ? 'ns' : nwse ? 'nwse' : 'nesw';
121
- if (editorRootElement !== null) {
122
- editorRootElement.style.setProperty('cursor', `${cursorDir}-resize`, 'important');
123
- }
124
- if (document.body !== null) {
125
- document.body.style.setProperty('cursor', `${cursorDir}-resize`, 'important');
126
- userSelect.current.value = document.body.style.getPropertyValue('-webkit-user-select');
127
- userSelect.current.priority = document.body.style.getPropertyPriority('-webkit-user-select');
128
- document.body.style.setProperty('-webkit-user-select', `none`, 'important');
129
- }
130
- };
131
- const setEndCursor = () => {
132
- if (editorRootElement !== null) {
133
- editorRootElement.style.setProperty('cursor', 'text');
134
- }
135
- if (document.body !== null) {
136
- document.body.style.setProperty('cursor', 'default');
137
- document.body.style.setProperty('-webkit-user-select', userSelect.current.value, userSelect.current.priority);
138
- }
139
- };
140
- const handlePointerDown = (event, direction) => {
141
- if (!editor.isEditable()) {
142
- return;
143
- }
144
- const image = imageRef.current;
145
- const controlWrapper = controlWrapperRef.current;
146
- if (image !== null && controlWrapper !== null) {
147
- const { width, height } = image.getBoundingClientRect();
148
- const positioning = positioningRef.current;
149
- positioning.startWidth = width;
150
- positioning.startHeight = height;
151
- positioning.ratio = width / height;
152
- positioning.currentWidth = width;
153
- positioning.currentHeight = height;
154
- positioning.startX = event.clientX;
155
- positioning.startY = event.clientY;
156
- positioning.isResizing = true;
157
- positioning.direction = direction;
158
- setStartCursor(direction);
159
- onResizeStart();
160
- controlWrapper.classList.add('image-control-wrapper--resizing');
161
- image.style.height = `${height}px`;
162
- image.style.width = `${width}px`;
163
- document.addEventListener('pointermove', handlePointerMove);
164
- document.addEventListener('pointerup', handlePointerUp);
165
- }
166
- };
167
- const handlePointerMove = (event) => {
168
- const image = imageRef.current;
169
- const positioning = positioningRef.current;
170
- const isHorizontal = positioning.direction & (Direction.east | Direction.west);
171
- const isVertical = positioning.direction & (Direction.south | Direction.north);
172
- if (image !== null && positioning.isResizing) {
173
- // Corner cursor
174
- if (isHorizontal && isVertical) {
175
- let diff = Math.floor(positioning.startX - event.clientX);
176
- diff = positioning.direction & Direction.east ? -diff : diff;
177
- const width = clamp(positioning.startWidth + diff, minWidth, maxWidthContainer);
178
- const height = width / positioning.ratio;
179
- image.style.width = `${width}px`;
180
- image.style.height = `${height}px`;
181
- positioning.currentHeight = height;
182
- positioning.currentWidth = width;
183
- }
184
- else if (isVertical) {
185
- let diff = Math.floor(positioning.startY - event.clientY);
186
- diff = positioning.direction & Direction.south ? -diff : diff;
187
- const height = clamp(positioning.startHeight + diff, minHeight, maxHeightContainer);
188
- image.style.height = `${height}px`;
189
- positioning.currentHeight = height;
190
- }
191
- else {
192
- let diff = Math.floor(positioning.startX - event.clientX);
193
- diff = positioning.direction & Direction.east ? -diff : diff;
194
- const width = clamp(positioning.startWidth + diff, minWidth, maxWidthContainer);
195
- image.style.width = `${width}px`;
196
- positioning.currentWidth = width;
197
- }
198
- }
199
- };
200
- const handlePointerUp = () => {
201
- const image = imageRef.current;
202
- const positioning = positioningRef.current;
203
- const controlWrapper = controlWrapperRef.current;
204
- if (image !== null && controlWrapper !== null && positioning.isResizing) {
205
- const width = positioning.currentWidth;
206
- const height = positioning.currentHeight;
207
- positioning.startWidth = 0;
208
- positioning.startHeight = 0;
209
- positioning.ratio = 0;
210
- positioning.startX = 0;
211
- positioning.startY = 0;
212
- positioning.currentWidth = 0;
213
- positioning.currentHeight = 0;
214
- positioning.isResizing = false;
215
- controlWrapper.classList.remove('image-control-wrapper--resizing');
216
- setEndCursor();
217
- console.log(width);
218
- console.log(height);
219
- onResizeEnd(width, height);
220
- document.removeEventListener('pointermove', handlePointerMove);
221
- document.removeEventListener('pointerup', handlePointerUp);
222
- }
223
- };
224
- return (React.createElement("div", { ref: controlWrapperRef },
225
- React.createElement("div", { className: "image-resizer image-resizer-n", onPointerDown: (event) => {
226
- handlePointerDown(event, Direction.north);
227
- } }),
228
- React.createElement("div", { className: "image-resizer image-resizer-ne", onPointerDown: (event) => {
229
- handlePointerDown(event, Direction.north | Direction.east);
230
- } }),
231
- React.createElement("div", { className: "image-resizer image-resizer-e", onPointerDown: (event) => {
232
- handlePointerDown(event, Direction.east);
233
- } }),
234
- React.createElement("div", { className: "image-resizer image-resizer-se", onPointerDown: (event) => {
235
- handlePointerDown(event, Direction.south | Direction.east);
236
- } }),
237
- React.createElement("div", { className: "image-resizer image-resizer-s", onPointerDown: (event) => {
238
- handlePointerDown(event, Direction.south);
239
- } }),
240
- React.createElement("div", { className: "image-resizer image-resizer-sw", onPointerDown: (event) => {
241
- handlePointerDown(event, Direction.south | Direction.west);
242
- } }),
243
- React.createElement("div", { className: "image-resizer image-resizer-w", onPointerDown: (event) => {
244
- handlePointerDown(event, Direction.west);
245
- } }),
246
- React.createElement("div", { className: "image-resizer image-resizer-nw", onPointerDown: (event) => {
247
- handlePointerDown(event, Direction.north | Direction.west);
248
- } })));
6
+ function getAspectRatio(width, height) {
7
+ return width / height;
249
8
  }
250
9
  const imageCache = new Set();
251
10
  function useSuspenseImage(src) {
@@ -260,21 +19,21 @@ function useSuspenseImage(src) {
260
19
  });
261
20
  }
262
21
  }
263
- function LazyImage({ altText, className, imageRef, src, width, height, maxWidth }) {
22
+ function LazyImage({ altText, className, imageRef, src, width, height }) {
264
23
  useSuspenseImage(src);
265
- return (React.createElement("img", { className: className, src: src, alt: altText, ref: imageRef, style: {
266
- height: `${height}${height === 'inherit' ? '' : 'px'}`,
267
- maxWidth,
268
- width: `${width}${width === 'inherit' ? '' : 'px'}`
269
- } }));
24
+ const aspectRatio = getAspectRatio(width, height);
25
+ return (React.createElement("div", { draggable: false, className: className, style: { position: 'relative', paddingBottom: `${100 / aspectRatio}%` } },
26
+ React.createElement("img", { src: src, alt: altText, ref: imageRef, style: {
27
+ position: 'absolute',
28
+ height: `100%`,
29
+ width: `100%`
30
+ } })));
270
31
  }
271
- function ImageComponent({ src, altText, nodeKey, width, height, maxWidth, resizable }) {
32
+ function ImageComponent({ src, altText, nodeKey, width, height }) {
272
33
  const imageRef = useRef(null);
273
34
  const buttonRef = useRef(null);
274
35
  const [isSelected, setSelected, clearSelection] = useLexicalNodeSelection(nodeKey);
275
- const [isResizing, setIsResizing] = useState(false);
276
36
  const [editor] = useLexicalComposerContext();
277
- const [selection, setSelection] = useState(null);
278
37
  const activeEditorRef = useRef(null);
279
38
  const onDelete = useCallback((payload) => {
280
39
  if (isSelected && $isNodeSelection($getSelection())) {
@@ -315,19 +74,11 @@ function ImageComponent({ src, altText, nodeKey, width, height, maxWidth, resiza
315
74
  return false;
316
75
  }, [editor, setSelected]);
317
76
  useEffect(() => {
318
- let isMounted = true;
319
- const unregister = mergeRegister(editor.registerUpdateListener(({ editorState }) => {
320
- if (isMounted) {
321
- setSelection(editorState.read(() => $getSelection()));
322
- }
323
- }), editor.registerCommand(SELECTION_CHANGE_COMMAND, (_, activeEditor) => {
77
+ const unregister = mergeRegister(editor.registerCommand(SELECTION_CHANGE_COMMAND, (_, activeEditor) => {
324
78
  activeEditorRef.current = activeEditor;
325
79
  return false;
326
80
  }, COMMAND_PRIORITY_LOW), editor.registerCommand(CLICK_COMMAND, (payload) => {
327
81
  const event = payload;
328
- if (isResizing) {
329
- return true;
330
- }
331
82
  if (event.target === imageRef.current) {
332
83
  if (event.shiftKey) {
333
84
  setSelected(!isSelected);
@@ -339,63 +90,36 @@ function ImageComponent({ src, altText, nodeKey, width, height, maxWidth, resiza
339
90
  return true;
340
91
  }
341
92
  return false;
342
- }, COMMAND_PRIORITY_LOW), editor.registerCommand(DRAGSTART_COMMAND, (event) => {
343
- if (event.target === imageRef.current) {
344
- // TODO This is just a temporary workaround for FF to behave like other browsers.
345
- // Ideally, this handles drag & drop too (and all browsers).
346
- event.preventDefault();
347
- return true;
348
- }
349
- return false;
350
93
  }, 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));
351
94
  return () => {
352
- isMounted = false;
353
95
  unregister();
354
96
  };
355
- }, [clearSelection, editor, isResizing, isSelected, nodeKey, onDelete, onEnter, onEscape, setSelected]);
356
- const onResizeEnd = (nextWidth, nextHeight) => {
357
- // Delay hiding the resize bars for click case
358
- setTimeout(() => {
359
- setIsResizing(false);
360
- }, 200);
361
- editor.update(() => {
362
- const node = $getNodeByKey(nodeKey);
363
- if ($isImageNode(node)) {
364
- node.setWidthAndHeight(nextWidth, nextHeight);
365
- }
366
- });
367
- };
368
- const onResizeStart = () => {
369
- setIsResizing(true);
370
- };
371
- const draggable = isSelected && $isNodeSelection(selection) && !isResizing;
372
- const isFocused = isSelected || isResizing;
97
+ }, [clearSelection, editor, isSelected, nodeKey, onDelete, onEnter, onEscape, setSelected]);
98
+ const isFocused = isSelected;
373
99
  return (React.createElement(Suspense, { fallback: null },
374
- React.createElement(React.Fragment, null,
375
- React.createElement("div", { draggable: draggable },
376
- React.createElement(LazyImage, { className: isFocused ? `focused ${$isNodeSelection(selection) ? 'draggable' : ''}` : null, src: src, altText: altText, imageRef: imageRef, width: width, height: height, maxWidth: maxWidth })),
377
- resizable && $isNodeSelection(selection) && isFocused && (React.createElement(ImageResizer, { editor: editor, imageRef: imageRef, maxWidth: typeof maxWidth === 'number' ? maxWidth : null, onResizeStart: onResizeStart, onResizeEnd: onResizeEnd })))));
100
+ React.createElement(LazyImage, { className: isFocused ? `focused` : null, src: src, altText: altText, imageRef: imageRef, width: width, height: height })));
378
101
  }
379
102
  function convertImageElement(domNode) {
380
- const image = domNode;
381
- return {
382
- node: $createImageNode({ src: image.getAttribute('src'), altText: image.getAttribute('alt'), maxWidth: '100%' })
383
- };
103
+ if (domNode instanceof HTMLImageElement) {
104
+ const { alt: altText, src, dataset: { width, height } } = domNode;
105
+ const node = $createImageNode({ altText, height: Number(height), src, width: Number(width) });
106
+ return { node };
107
+ }
108
+ return null;
384
109
  }
385
110
  export class ImageNode extends DecoratorNode {
386
- constructor(src, altText, maxWidth, width, height, key) {
111
+ constructor(src, altText, width, height, key) {
387
112
  super(key);
388
113
  this.__src = src;
389
114
  this.__altText = altText;
390
- this.__maxWidth = maxWidth;
391
- this.__width = width || 'inherit';
392
- this.__height = height || 'inherit';
115
+ this.__width = width;
116
+ this.__height = height;
393
117
  }
394
118
  static getType() {
395
119
  return 'image';
396
120
  }
397
121
  static clone(node) {
398
- return new ImageNode(node.__src, node.__altText, node.__maxWidth, node.__width, node.__height, node.__key);
122
+ return new ImageNode(node.__src, node.__altText, node.__width, node.__height, node.__key);
399
123
  }
400
124
  setWidthAndHeight(width, height) {
401
125
  const writable = this.getWritable();
@@ -429,24 +153,26 @@ export class ImageNode extends DecoratorNode {
429
153
  }) }, dom);
430
154
  }
431
155
  exportDOM() {
432
- const element = document.createElement('img');
433
- element.setAttribute('src', this.__src);
434
- element.setAttribute('alt', this.__altText);
435
- element.setAttribute('width', `${this.__width}`);
436
- element.setAttribute('height', `${this.__height}`);
437
- element.setAttribute('style', `max-width: ${this.__maxWidth}px;`);
156
+ const aspectRatio = getAspectRatio(this.__width, this.__height);
157
+ const element = document.createElement('div');
158
+ element.setAttribute('style', `position: relative;padding-bottom:${100 / aspectRatio}%`);
159
+ const image = document.createElement('img');
160
+ image.setAttribute('src', this.__src);
161
+ image.setAttribute('alt', this.__altText);
162
+ image.setAttribute('style', `position: absolute;width:100%;height:100%;`);
163
+ image.setAttribute('data-width', `${this.__width}`);
164
+ image.setAttribute('data-height', `${this.__height}`);
165
+ element.appendChild(image);
438
166
  return { element };
439
167
  }
440
168
  decorate() {
441
- console.log(this.__maxWidth);
442
- return (React.createElement(ImageComponent, { src: this.__src, altText: this.__altText, width: this.__width, height: this.__height, maxWidth: this.__maxWidth, nodeKey: this.getKey(), resizable: true }));
169
+ return (React.createElement(ImageComponent, { src: this.__src, altText: this.__altText, width: this.__width, height: this.__height, nodeKey: this.getKey() }));
443
170
  }
444
171
  static importJSON(serializedNode) {
445
- const { altText, height, width, maxWidth, src } = serializedNode;
172
+ const { altText, height, width, src } = serializedNode;
446
173
  const node = $createImageNode({
447
174
  altText,
448
175
  height,
449
- maxWidth,
450
176
  src,
451
177
  width
452
178
  });
@@ -455,17 +181,16 @@ export class ImageNode extends DecoratorNode {
455
181
  exportJSON() {
456
182
  return {
457
183
  altText: this.getAltText(),
458
- height: this.__height === 'inherit' ? 0 : this.__height,
459
- maxWidth: this.__maxWidth,
184
+ height: this.__height,
460
185
  src: this.getSrc(),
461
186
  type: 'image',
462
187
  version: 1,
463
- width: this.__width === 'inherit' ? 0 : this.__width
188
+ width: this.__width
464
189
  };
465
190
  }
466
191
  }
467
- export function $createImageNode({ src, altText, maxWidth, width = null, height = null }) {
468
- return new ImageNode(src, altText, maxWidth, width, height);
192
+ export function $createImageNode({ src, altText, width, height }) {
193
+ return new ImageNode(src, altText, width, height);
469
194
  }
470
195
  export function $isImageNode(node) {
471
196
  return node.getType() === 'image';
@@ -29,12 +29,17 @@ function Image({ editor, className = '' }) {
29
29
  return file.type.startsWith('image/');
30
30
  };
31
31
  const handleUploadSuccess = (media) => {
32
- const data = {
33
- altText: media.title,
34
- src: media.image,
32
+ const image = media.image_thumbnail ? media.image_thumbnail : {
33
+ url: media.image,
35
34
  width: media.image_width,
36
35
  height: media.image_height
37
36
  };
37
+ const data = {
38
+ altText: media.title,
39
+ src: image.url,
40
+ width: image.width,
41
+ height: image.height
42
+ };
38
43
  editor.focus();
39
44
  editor.dispatchCommand(INSERT_IMAGE_COMMAND, data);
40
45
  editor.dispatchCommand(INSERT_PARAGRAPH_COMMAND, undefined);
@@ -86,7 +91,7 @@ export default function ImagePlugin() {
86
91
  if ($isRootNode(selection.anchor.getNode())) {
87
92
  selection.insertParagraph();
88
93
  }
89
- const imageNode = $createImageNode({ src: payload.src, altText: payload.altText, maxWidth: '100%' });
94
+ const imageNode = $createImageNode({ src: payload.src, altText: payload.altText, width: payload.width, height: payload.height });
90
95
  selection.insertNodes([imageNode]);
91
96
  }
92
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 "@mui/material";
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: 1, endMessage: React.createElement(Box, { className: classes.end },
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),