@selfcommunity/react-ui 0.7.5-alpha.2 → 0.7.5-alpha.4
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/Composer/Composer.js +34 -4
- package/lib/cjs/components/Editor/Editor.js +1 -1
- package/lib/cjs/components/Editor/plugins/LexicalRichTextPlugin.d.ts +6 -0
- package/lib/cjs/components/Editor/plugins/LexicalRichTextPlugin.js +43 -0
- package/lib/cjs/components/Editor/shared/useCanShowPlaceholder.d.ts +9 -0
- package/lib/cjs/components/Editor/shared/useCanShowPlaceholder.js +27 -0
- package/lib/cjs/components/Editor/shared/useDecorators.d.ts +16 -0
- package/lib/cjs/components/Editor/shared/useDecorators.js +41 -0
- package/lib/cjs/components/Editor/shared/useEditorFocus.d.ts +2 -0
- package/lib/cjs/components/Editor/shared/useEditorFocus.js +20 -0
- package/lib/cjs/components/Editor/shared/useRichTextSetup.d.ts +9 -0
- package/lib/cjs/components/Editor/shared/useRichTextSetup.js +13 -0
- package/lib/cjs/components/UserProfileHeader/UserProfileHeader.js +5 -1
- package/lib/esm/components/Composer/Composer.js +34 -4
- package/lib/esm/components/Editor/Editor.js +1 -1
- package/lib/esm/components/Editor/plugins/LexicalRichTextPlugin.d.ts +6 -0
- package/lib/esm/components/Editor/plugins/LexicalRichTextPlugin.js +38 -0
- package/lib/esm/components/Editor/shared/useCanShowPlaceholder.d.ts +9 -0
- package/lib/esm/components/Editor/shared/useCanShowPlaceholder.js +23 -0
- package/lib/esm/components/Editor/shared/useDecorators.d.ts +16 -0
- package/lib/esm/components/Editor/shared/useDecorators.js +36 -0
- package/lib/esm/components/Editor/shared/useEditorFocus.d.ts +2 -0
- package/lib/esm/components/Editor/shared/useEditorFocus.js +17 -0
- package/lib/esm/components/Editor/shared/useRichTextSetup.d.ts +9 -0
- package/lib/esm/components/Editor/shared/useRichTextSetup.js +9 -0
- package/lib/esm/components/UserProfileHeader/UserProfileHeader.js +5 -1
- package/lib/umd/871.js +2 -0
- package/lib/umd/react-ui.js +1 -1
- package/package.json +2 -2
- package/lib/umd/92.js +0 -2
- /package/lib/umd/{92.js.LICENSE.txt → 871.js.LICENSE.txt} +0 -0
|
@@ -172,6 +172,7 @@ function Composer(inProps) {
|
|
|
172
172
|
// REFS
|
|
173
173
|
const dialogRef = (0, react_1.useRef)();
|
|
174
174
|
const unloadRef = (0, react_1.useRef)(false);
|
|
175
|
+
const pointerStartY = (0, react_1.useRef)(null);
|
|
175
176
|
// Create a ref for medias because of state update error on chunk upload
|
|
176
177
|
const mediasRef = (0, react_1.useRef)({ medias });
|
|
177
178
|
mediasRef.current = { medias };
|
|
@@ -224,15 +225,44 @@ function Composer(inProps) {
|
|
|
224
225
|
window.onbeforeunload = null;
|
|
225
226
|
}
|
|
226
227
|
}, [state, canSubmit]);
|
|
228
|
+
/**
|
|
229
|
+
* On iOS, since it is not possible to anchor meadiaObject actions
|
|
230
|
+
* to the bottom of the viewport, detect 'pan' gesture to close the
|
|
231
|
+
* soft keyboard on device and show actions
|
|
232
|
+
*/
|
|
227
233
|
(0, react_1.useEffect)(() => {
|
|
228
234
|
if (!dialogRef.current || !isIOS) {
|
|
229
235
|
return;
|
|
230
236
|
}
|
|
231
|
-
|
|
232
|
-
|
|
237
|
+
/**
|
|
238
|
+
* On touchStart event save the initial Y
|
|
239
|
+
* @param event
|
|
240
|
+
*/
|
|
241
|
+
const handleTouchStart = (event) => {
|
|
242
|
+
pointerStartY.current = event.touches[0].clientY;
|
|
243
|
+
};
|
|
244
|
+
/**
|
|
245
|
+
* Perform blur only if gesture is a pan (bottom direction)
|
|
246
|
+
* @param event
|
|
247
|
+
*/
|
|
248
|
+
const handleTouchmove = (event) => {
|
|
249
|
+
const currentY = event.touches[0].clientY;
|
|
250
|
+
const deltaY = currentY - pointerStartY.current;
|
|
251
|
+
pointerStartY.current = currentY;
|
|
252
|
+
if (deltaY > 0) {
|
|
253
|
+
dialogRef.current.focus();
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
/**
|
|
257
|
+
* Attach touchstart, touchmove necessary to detect the pan gesture
|
|
258
|
+
*/
|
|
259
|
+
dialogRef.current.addEventListener('touchstart', handleTouchStart);
|
|
260
|
+
dialogRef.current.addEventListener('touchmove', handleTouchmove);
|
|
261
|
+
return () => {
|
|
262
|
+
var _a, _b;
|
|
263
|
+
(_a = dialogRef.current) === null || _a === void 0 ? void 0 : _a.removeEventListener('touchstart', handleTouchStart);
|
|
264
|
+
(_b = dialogRef.current) === null || _b === void 0 ? void 0 : _b.removeEventListener('touchmove', handleTouchmove);
|
|
233
265
|
};
|
|
234
|
-
dialogRef.current.addEventListener('touchstart', handleBlur);
|
|
235
|
-
return () => { var _a; return (_a = dialogRef.current) === null || _a === void 0 ? void 0 : _a.removeEventListener('touchstart', handleBlur); };
|
|
236
266
|
}, [dialogRef.current, isIOS]);
|
|
237
267
|
/* Handlers */
|
|
238
268
|
const handleAddLayer = (0, react_1.useCallback)((layer) => setLayer(layer), []);
|
|
@@ -11,7 +11,7 @@ const nodes_1 = tslib_1.__importDefault(require("./nodes"));
|
|
|
11
11
|
const LexicalComposer_1 = require("@lexical/react/LexicalComposer");
|
|
12
12
|
const LexicalContentEditable_1 = require("@lexical/react/LexicalContentEditable");
|
|
13
13
|
const LexicalHistoryPlugin_1 = require("@lexical/react/LexicalHistoryPlugin");
|
|
14
|
-
const LexicalRichTextPlugin_1 = require("
|
|
14
|
+
const LexicalRichTextPlugin_1 = require("./plugins/LexicalRichTextPlugin");
|
|
15
15
|
const LexicalErrorBoundary_1 = tslib_1.__importDefault(require("@lexical/react/LexicalErrorBoundary"));
|
|
16
16
|
const LexicalHorizontalRulePlugin_1 = require("@lexical/react/LexicalHorizontalRulePlugin");
|
|
17
17
|
const plugins_1 = require("./plugins");
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ErrorBoundaryType } from '../shared/useDecorators';
|
|
2
|
+
export declare function RichTextPlugin({ contentEditable, placeholder, ErrorBoundary }: {
|
|
3
|
+
contentEditable: JSX.Element;
|
|
4
|
+
placeholder: ((isEditable: boolean) => null | JSX.Element) | null | JSX.Element;
|
|
5
|
+
ErrorBoundary: ErrorBoundaryType;
|
|
6
|
+
}): JSX.Element;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RichTextPlugin = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
/**
|
|
6
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
7
|
+
*
|
|
8
|
+
* This source code is licensed under the MIT license found in the
|
|
9
|
+
* LICENSE file in the root directory of this source tree.
|
|
10
|
+
*
|
|
11
|
+
*/
|
|
12
|
+
const React = tslib_1.__importStar(require("react"));
|
|
13
|
+
const LexicalComposerContext_1 = require("@lexical/react/LexicalComposerContext");
|
|
14
|
+
const useLexicalEditable_1 = tslib_1.__importDefault(require("@lexical/react/useLexicalEditable"));
|
|
15
|
+
const useDecorators_1 = require("../shared/useDecorators");
|
|
16
|
+
const useEditorFocus_1 = require("../shared/useEditorFocus");
|
|
17
|
+
const useCanShowPlaceholder_1 = require("../shared/useCanShowPlaceholder");
|
|
18
|
+
const useRichTextSetup_1 = require("../shared/useRichTextSetup");
|
|
19
|
+
function RichTextPlugin({ contentEditable, placeholder, ErrorBoundary }) {
|
|
20
|
+
const [editor] = (0, LexicalComposerContext_1.useLexicalComposerContext)();
|
|
21
|
+
const decorators = (0, useDecorators_1.useDecorators)(editor, ErrorBoundary);
|
|
22
|
+
(0, useRichTextSetup_1.useRichTextSetup)(editor);
|
|
23
|
+
return (React.createElement(React.Fragment, null,
|
|
24
|
+
contentEditable,
|
|
25
|
+
React.createElement(Placeholder, { content: placeholder }),
|
|
26
|
+
decorators));
|
|
27
|
+
}
|
|
28
|
+
exports.RichTextPlugin = RichTextPlugin;
|
|
29
|
+
function Placeholder({ content }) {
|
|
30
|
+
const [editor] = (0, LexicalComposerContext_1.useLexicalComposerContext)();
|
|
31
|
+
const showPlaceholder = (0, useCanShowPlaceholder_1.useCanShowPlaceholder)(editor);
|
|
32
|
+
const editable = (0, useLexicalEditable_1.default)();
|
|
33
|
+
const hasFocus = (0, useEditorFocus_1.useEditorFocus)();
|
|
34
|
+
if (!showPlaceholder || hasFocus) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
if (typeof content === 'function') {
|
|
38
|
+
return content(editable);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
return content;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
import type { LexicalEditor } from 'lexical';
|
|
9
|
+
export declare function useCanShowPlaceholder(editor: LexicalEditor): boolean;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useCanShowPlaceholder = void 0;
|
|
4
|
+
const text_1 = require("@lexical/text");
|
|
5
|
+
const utils_1 = require("@lexical/utils");
|
|
6
|
+
const react_1 = require("react");
|
|
7
|
+
const react_core_1 = require("@selfcommunity/react-core");
|
|
8
|
+
function canShowPlaceholderFromCurrentEditorState(editor) {
|
|
9
|
+
return editor.getEditorState().read((0, text_1.$canShowPlaceholderCurry)(editor.isComposing()));
|
|
10
|
+
}
|
|
11
|
+
function useCanShowPlaceholder(editor) {
|
|
12
|
+
const [canShowPlaceholder, setCanShowPlaceholder] = (0, react_1.useState)(() => canShowPlaceholderFromCurrentEditorState(editor));
|
|
13
|
+
(0, react_core_1.useIsomorphicLayoutEffect)(() => {
|
|
14
|
+
function resetCanShowPlaceholder() {
|
|
15
|
+
const currentCanShowPlaceholder = canShowPlaceholderFromCurrentEditorState(editor);
|
|
16
|
+
setCanShowPlaceholder(currentCanShowPlaceholder);
|
|
17
|
+
}
|
|
18
|
+
resetCanShowPlaceholder();
|
|
19
|
+
return (0, utils_1.mergeRegister)(editor.registerUpdateListener(() => {
|
|
20
|
+
resetCanShowPlaceholder();
|
|
21
|
+
}), editor.registerEditableListener(() => {
|
|
22
|
+
resetCanShowPlaceholder();
|
|
23
|
+
}));
|
|
24
|
+
}, [editor]);
|
|
25
|
+
return canShowPlaceholder;
|
|
26
|
+
}
|
|
27
|
+
exports.useCanShowPlaceholder = useCanShowPlaceholder;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
import type { LexicalEditor } from 'lexical';
|
|
9
|
+
import * as React from 'react';
|
|
10
|
+
declare type ErrorBoundaryProps = {
|
|
11
|
+
children: JSX.Element;
|
|
12
|
+
onError: (error: Error) => void;
|
|
13
|
+
};
|
|
14
|
+
export declare type ErrorBoundaryType = React.ComponentClass<ErrorBoundaryProps> | React.FC<ErrorBoundaryProps>;
|
|
15
|
+
export declare function useDecorators(editor: LexicalEditor, ErrorBoundary: ErrorBoundaryType): Array<JSX.Element>;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useDecorators = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const React = tslib_1.__importStar(require("react"));
|
|
7
|
+
const react_dom_1 = require("react-dom");
|
|
8
|
+
const react_core_1 = require("@selfcommunity/react-core");
|
|
9
|
+
function useDecorators(editor, ErrorBoundary) {
|
|
10
|
+
const [decorators, setDecorators] = (0, react_1.useState)(() => editor.getDecorators());
|
|
11
|
+
// Subscribe to changes
|
|
12
|
+
(0, react_core_1.useIsomorphicLayoutEffect)(() => {
|
|
13
|
+
return editor.registerDecoratorListener((nextDecorators) => {
|
|
14
|
+
(0, react_dom_1.flushSync)(() => {
|
|
15
|
+
setDecorators(nextDecorators);
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
}, [editor]);
|
|
19
|
+
(0, react_1.useEffect)(() => {
|
|
20
|
+
// If the content editable mounts before the subscription is added, then
|
|
21
|
+
// nothing will be rendered on initial pass. We can get around that by
|
|
22
|
+
// ensuring that we set the value.
|
|
23
|
+
setDecorators(editor.getDecorators());
|
|
24
|
+
}, [editor]);
|
|
25
|
+
// Return decorators defined as React Portals
|
|
26
|
+
return (0, react_1.useMemo)(() => {
|
|
27
|
+
const decoratedPortals = [];
|
|
28
|
+
const decoratorKeys = Object.keys(decorators);
|
|
29
|
+
for (let i = 0; i < decoratorKeys.length; i++) {
|
|
30
|
+
const nodeKey = decoratorKeys[i];
|
|
31
|
+
const reactDecorator = (React.createElement(ErrorBoundary, { onError: (e) => editor._onError(e) },
|
|
32
|
+
React.createElement(react_1.Suspense, { fallback: null }, decorators[nodeKey])));
|
|
33
|
+
const element = editor.getElementByKey(nodeKey);
|
|
34
|
+
if (element !== null) {
|
|
35
|
+
decoratedPortals.push((0, react_dom_1.createPortal)(reactDecorator, element, nodeKey));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return decoratedPortals;
|
|
39
|
+
}, [ErrorBoundary, decorators, editor]);
|
|
40
|
+
}
|
|
41
|
+
exports.useDecorators = useDecorators;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useEditorFocus = void 0;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
const LexicalComposerContext_1 = require("@lexical/react/LexicalComposerContext");
|
|
6
|
+
const lexical_1 = require("lexical");
|
|
7
|
+
const useEditorFocus = () => {
|
|
8
|
+
const [editor] = (0, LexicalComposerContext_1.useLexicalComposerContext)();
|
|
9
|
+
const [hasFocus, setFocus] = (0, react_1.useState)(false);
|
|
10
|
+
(0, react_1.useEffect)(() => editor.registerCommand(lexical_1.BLUR_COMMAND, () => {
|
|
11
|
+
setFocus(false);
|
|
12
|
+
return false;
|
|
13
|
+
}, lexical_1.COMMAND_PRIORITY_LOW), []);
|
|
14
|
+
(0, react_1.useEffect)(() => editor.registerCommand(lexical_1.FOCUS_COMMAND, () => {
|
|
15
|
+
setFocus(true);
|
|
16
|
+
return false;
|
|
17
|
+
}, lexical_1.COMMAND_PRIORITY_LOW), []);
|
|
18
|
+
return hasFocus;
|
|
19
|
+
};
|
|
20
|
+
exports.useEditorFocus = useEditorFocus;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
import type { LexicalEditor } from 'lexical';
|
|
9
|
+
export declare function useRichTextSetup(editor: LexicalEditor): void;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useRichTextSetup = void 0;
|
|
4
|
+
const dragon_1 = require("@lexical/dragon");
|
|
5
|
+
const rich_text_1 = require("@lexical/rich-text");
|
|
6
|
+
const utils_1 = require("@lexical/utils");
|
|
7
|
+
const react_core_1 = require("@selfcommunity/react-core");
|
|
8
|
+
function useRichTextSetup(editor) {
|
|
9
|
+
(0, react_core_1.useIsomorphicLayoutEffect)(() => {
|
|
10
|
+
return (0, utils_1.mergeRegister)((0, rich_text_1.registerRichText)(editor), (0, dragon_1.registerDragonSupport)(editor));
|
|
11
|
+
}, [editor]);
|
|
12
|
+
}
|
|
13
|
+
exports.useRichTextSetup = useRichTextSetup;
|
|
@@ -11,6 +11,7 @@ const Skeleton_1 = tslib_1.__importDefault(require("./Skeleton"));
|
|
|
11
11
|
const classnames_1 = tslib_1.__importDefault(require("classnames"));
|
|
12
12
|
const system_1 = require("@mui/system");
|
|
13
13
|
const constants_1 = require("./constants");
|
|
14
|
+
const UserAvatar_1 = tslib_1.__importDefault(require("../../shared/UserAvatar"));
|
|
14
15
|
const classes = {
|
|
15
16
|
root: `${constants_1.PREFIX}-root`,
|
|
16
17
|
cover: `${constants_1.PREFIX}-cover`,
|
|
@@ -108,9 +109,12 @@ function UserProfileHeader(inProps) {
|
|
|
108
109
|
? { background: `url('${scUser.cover}') center / cover` }
|
|
109
110
|
: { background: `url('${scPreferences.preferences[react_core_1.SCPreferences.IMAGES_USER_DEFAULT_COVER].value}') center / cover` }));
|
|
110
111
|
const realName = (isMe && scUserContext.user.real_name) || scUser.real_name;
|
|
112
|
+
const hasBadge = scUser && scUser.community_badge;
|
|
111
113
|
return (react_1.default.createElement(Root, Object.assign({ id: id, className: (0, classnames_1.default)(classes.root, className) }, rest),
|
|
112
114
|
react_1.default.createElement(material_1.Paper, { style: _backgroundCover, classes: { root: classes.cover } },
|
|
113
|
-
react_1.default.createElement(
|
|
115
|
+
react_1.default.createElement(material_1.Box, { className: classes.avatar },
|
|
116
|
+
react_1.default.createElement(UserAvatar_1.default, { hide: !hasBadge },
|
|
117
|
+
react_1.default.createElement("img", { src: scUser.avatar ? scUser.avatar : '' }))),
|
|
114
118
|
isMe && (react_1.default.createElement(react_1.default.Fragment, null,
|
|
115
119
|
react_1.default.createElement(ChangePicture_1.default, Object.assign({ iconButton: true, onChange: handleChangeAvatar, className: classes.changePicture }, ChangePictureProps)),
|
|
116
120
|
react_1.default.createElement("div", { className: classes.changeCover },
|
|
@@ -170,6 +170,7 @@ export default function Composer(inProps) {
|
|
|
170
170
|
// REFS
|
|
171
171
|
const dialogRef = useRef();
|
|
172
172
|
const unloadRef = useRef(false);
|
|
173
|
+
const pointerStartY = useRef(null);
|
|
173
174
|
// Create a ref for medias because of state update error on chunk upload
|
|
174
175
|
const mediasRef = useRef({ medias });
|
|
175
176
|
mediasRef.current = { medias };
|
|
@@ -222,15 +223,44 @@ export default function Composer(inProps) {
|
|
|
222
223
|
window.onbeforeunload = null;
|
|
223
224
|
}
|
|
224
225
|
}, [state, canSubmit]);
|
|
226
|
+
/**
|
|
227
|
+
* On iOS, since it is not possible to anchor meadiaObject actions
|
|
228
|
+
* to the bottom of the viewport, detect 'pan' gesture to close the
|
|
229
|
+
* soft keyboard on device and show actions
|
|
230
|
+
*/
|
|
225
231
|
useEffect(() => {
|
|
226
232
|
if (!dialogRef.current || !isIOS) {
|
|
227
233
|
return;
|
|
228
234
|
}
|
|
229
|
-
|
|
230
|
-
|
|
235
|
+
/**
|
|
236
|
+
* On touchStart event save the initial Y
|
|
237
|
+
* @param event
|
|
238
|
+
*/
|
|
239
|
+
const handleTouchStart = (event) => {
|
|
240
|
+
pointerStartY.current = event.touches[0].clientY;
|
|
241
|
+
};
|
|
242
|
+
/**
|
|
243
|
+
* Perform blur only if gesture is a pan (bottom direction)
|
|
244
|
+
* @param event
|
|
245
|
+
*/
|
|
246
|
+
const handleTouchmove = (event) => {
|
|
247
|
+
const currentY = event.touches[0].clientY;
|
|
248
|
+
const deltaY = currentY - pointerStartY.current;
|
|
249
|
+
pointerStartY.current = currentY;
|
|
250
|
+
if (deltaY > 0) {
|
|
251
|
+
dialogRef.current.focus();
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
/**
|
|
255
|
+
* Attach touchstart, touchmove necessary to detect the pan gesture
|
|
256
|
+
*/
|
|
257
|
+
dialogRef.current.addEventListener('touchstart', handleTouchStart);
|
|
258
|
+
dialogRef.current.addEventListener('touchmove', handleTouchmove);
|
|
259
|
+
return () => {
|
|
260
|
+
var _a, _b;
|
|
261
|
+
(_a = dialogRef.current) === null || _a === void 0 ? void 0 : _a.removeEventListener('touchstart', handleTouchStart);
|
|
262
|
+
(_b = dialogRef.current) === null || _b === void 0 ? void 0 : _b.removeEventListener('touchmove', handleTouchmove);
|
|
231
263
|
};
|
|
232
|
-
dialogRef.current.addEventListener('touchstart', handleBlur);
|
|
233
|
-
return () => { var _a; return (_a = dialogRef.current) === null || _a === void 0 ? void 0 : _a.removeEventListener('touchstart', handleBlur); };
|
|
234
264
|
}, [dialogRef.current, isIOS]);
|
|
235
265
|
/* Handlers */
|
|
236
266
|
const handleAddLayer = useCallback((layer) => setLayer(layer), []);
|
|
@@ -8,7 +8,7 @@ import nodes from './nodes';
|
|
|
8
8
|
import { LexicalComposer } from '@lexical/react/LexicalComposer';
|
|
9
9
|
import { ContentEditable } from '@lexical/react/LexicalContentEditable';
|
|
10
10
|
import { HistoryPlugin } from '@lexical/react/LexicalHistoryPlugin';
|
|
11
|
-
import { RichTextPlugin } from '
|
|
11
|
+
import { RichTextPlugin } from './plugins/LexicalRichTextPlugin';
|
|
12
12
|
import LexicalErrorBoundary from '@lexical/react/LexicalErrorBoundary';
|
|
13
13
|
import { HorizontalRulePlugin } from '@lexical/react/LexicalHorizontalRulePlugin';
|
|
14
14
|
import { AutoLinkPlugin, DefaultHtmlValuePlugin, EmojiPlugin, ImagePlugin, MentionsPlugin, OnChangePlugin } from './plugins';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ErrorBoundaryType } from '../shared/useDecorators';
|
|
2
|
+
export declare function RichTextPlugin({ contentEditable, placeholder, ErrorBoundary }: {
|
|
3
|
+
contentEditable: JSX.Element;
|
|
4
|
+
placeholder: ((isEditable: boolean) => null | JSX.Element) | null | JSX.Element;
|
|
5
|
+
ErrorBoundary: ErrorBoundaryType;
|
|
6
|
+
}): JSX.Element;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
import * as React from 'react';
|
|
9
|
+
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
|
10
|
+
import useLexicalEditable from '@lexical/react/useLexicalEditable';
|
|
11
|
+
import { useDecorators } from '../shared/useDecorators';
|
|
12
|
+
import { useEditorFocus } from '../shared/useEditorFocus';
|
|
13
|
+
import { useCanShowPlaceholder } from '../shared/useCanShowPlaceholder';
|
|
14
|
+
import { useRichTextSetup } from '../shared/useRichTextSetup';
|
|
15
|
+
export function RichTextPlugin({ contentEditable, placeholder, ErrorBoundary }) {
|
|
16
|
+
const [editor] = useLexicalComposerContext();
|
|
17
|
+
const decorators = useDecorators(editor, ErrorBoundary);
|
|
18
|
+
useRichTextSetup(editor);
|
|
19
|
+
return (React.createElement(React.Fragment, null,
|
|
20
|
+
contentEditable,
|
|
21
|
+
React.createElement(Placeholder, { content: placeholder }),
|
|
22
|
+
decorators));
|
|
23
|
+
}
|
|
24
|
+
function Placeholder({ content }) {
|
|
25
|
+
const [editor] = useLexicalComposerContext();
|
|
26
|
+
const showPlaceholder = useCanShowPlaceholder(editor);
|
|
27
|
+
const editable = useLexicalEditable();
|
|
28
|
+
const hasFocus = useEditorFocus();
|
|
29
|
+
if (!showPlaceholder || hasFocus) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
if (typeof content === 'function') {
|
|
33
|
+
return content(editable);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
return content;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
import type { LexicalEditor } from 'lexical';
|
|
9
|
+
export declare function useCanShowPlaceholder(editor: LexicalEditor): boolean;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { $canShowPlaceholderCurry } from '@lexical/text';
|
|
2
|
+
import { mergeRegister } from '@lexical/utils';
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { useIsomorphicLayoutEffect } from '@selfcommunity/react-core';
|
|
5
|
+
function canShowPlaceholderFromCurrentEditorState(editor) {
|
|
6
|
+
return editor.getEditorState().read($canShowPlaceholderCurry(editor.isComposing()));
|
|
7
|
+
}
|
|
8
|
+
export function useCanShowPlaceholder(editor) {
|
|
9
|
+
const [canShowPlaceholder, setCanShowPlaceholder] = useState(() => canShowPlaceholderFromCurrentEditorState(editor));
|
|
10
|
+
useIsomorphicLayoutEffect(() => {
|
|
11
|
+
function resetCanShowPlaceholder() {
|
|
12
|
+
const currentCanShowPlaceholder = canShowPlaceholderFromCurrentEditorState(editor);
|
|
13
|
+
setCanShowPlaceholder(currentCanShowPlaceholder);
|
|
14
|
+
}
|
|
15
|
+
resetCanShowPlaceholder();
|
|
16
|
+
return mergeRegister(editor.registerUpdateListener(() => {
|
|
17
|
+
resetCanShowPlaceholder();
|
|
18
|
+
}), editor.registerEditableListener(() => {
|
|
19
|
+
resetCanShowPlaceholder();
|
|
20
|
+
}));
|
|
21
|
+
}, [editor]);
|
|
22
|
+
return canShowPlaceholder;
|
|
23
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
import type { LexicalEditor } from 'lexical';
|
|
9
|
+
import * as React from 'react';
|
|
10
|
+
declare type ErrorBoundaryProps = {
|
|
11
|
+
children: JSX.Element;
|
|
12
|
+
onError: (error: Error) => void;
|
|
13
|
+
};
|
|
14
|
+
export declare type ErrorBoundaryType = React.ComponentClass<ErrorBoundaryProps> | React.FC<ErrorBoundaryProps>;
|
|
15
|
+
export declare function useDecorators(editor: LexicalEditor, ErrorBoundary: ErrorBoundaryType): Array<JSX.Element>;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Suspense, useEffect, useMemo, useState } from 'react';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { createPortal, flushSync } from 'react-dom';
|
|
4
|
+
import { useIsomorphicLayoutEffect } from '@selfcommunity/react-core';
|
|
5
|
+
export function useDecorators(editor, ErrorBoundary) {
|
|
6
|
+
const [decorators, setDecorators] = useState(() => editor.getDecorators());
|
|
7
|
+
// Subscribe to changes
|
|
8
|
+
useIsomorphicLayoutEffect(() => {
|
|
9
|
+
return editor.registerDecoratorListener((nextDecorators) => {
|
|
10
|
+
flushSync(() => {
|
|
11
|
+
setDecorators(nextDecorators);
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
}, [editor]);
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
// If the content editable mounts before the subscription is added, then
|
|
17
|
+
// nothing will be rendered on initial pass. We can get around that by
|
|
18
|
+
// ensuring that we set the value.
|
|
19
|
+
setDecorators(editor.getDecorators());
|
|
20
|
+
}, [editor]);
|
|
21
|
+
// Return decorators defined as React Portals
|
|
22
|
+
return useMemo(() => {
|
|
23
|
+
const decoratedPortals = [];
|
|
24
|
+
const decoratorKeys = Object.keys(decorators);
|
|
25
|
+
for (let i = 0; i < decoratorKeys.length; i++) {
|
|
26
|
+
const nodeKey = decoratorKeys[i];
|
|
27
|
+
const reactDecorator = (React.createElement(ErrorBoundary, { onError: (e) => editor._onError(e) },
|
|
28
|
+
React.createElement(Suspense, { fallback: null }, decorators[nodeKey])));
|
|
29
|
+
const element = editor.getElementByKey(nodeKey);
|
|
30
|
+
if (element !== null) {
|
|
31
|
+
decoratedPortals.push(createPortal(reactDecorator, element, nodeKey));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return decoratedPortals;
|
|
35
|
+
}, [ErrorBoundary, decorators, editor]);
|
|
36
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
|
3
|
+
import { BLUR_COMMAND, COMMAND_PRIORITY_LOW, FOCUS_COMMAND } from 'lexical';
|
|
4
|
+
const useEditorFocus = () => {
|
|
5
|
+
const [editor] = useLexicalComposerContext();
|
|
6
|
+
const [hasFocus, setFocus] = useState(false);
|
|
7
|
+
useEffect(() => editor.registerCommand(BLUR_COMMAND, () => {
|
|
8
|
+
setFocus(false);
|
|
9
|
+
return false;
|
|
10
|
+
}, COMMAND_PRIORITY_LOW), []);
|
|
11
|
+
useEffect(() => editor.registerCommand(FOCUS_COMMAND, () => {
|
|
12
|
+
setFocus(true);
|
|
13
|
+
return false;
|
|
14
|
+
}, COMMAND_PRIORITY_LOW), []);
|
|
15
|
+
return hasFocus;
|
|
16
|
+
};
|
|
17
|
+
export { useEditorFocus };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
import type { LexicalEditor } from 'lexical';
|
|
9
|
+
export declare function useRichTextSetup(editor: LexicalEditor): void;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { registerDragonSupport } from '@lexical/dragon';
|
|
2
|
+
import { registerRichText } from '@lexical/rich-text';
|
|
3
|
+
import { mergeRegister } from '@lexical/utils';
|
|
4
|
+
import { useIsomorphicLayoutEffect } from '@selfcommunity/react-core';
|
|
5
|
+
export function useRichTextSetup(editor) {
|
|
6
|
+
useIsomorphicLayoutEffect(() => {
|
|
7
|
+
return mergeRegister(registerRichText(editor), registerDragonSupport(editor));
|
|
8
|
+
}, [editor]);
|
|
9
|
+
}
|
|
@@ -9,6 +9,7 @@ import UserProfileHeaderSkeleton from './Skeleton';
|
|
|
9
9
|
import classNames from 'classnames';
|
|
10
10
|
import { useThemeProps } from '@mui/system';
|
|
11
11
|
import { PREFIX } from './constants';
|
|
12
|
+
import UserAvatar from '../../shared/UserAvatar';
|
|
12
13
|
const classes = {
|
|
13
14
|
root: `${PREFIX}-root`,
|
|
14
15
|
cover: `${PREFIX}-cover`,
|
|
@@ -106,9 +107,12 @@ export default function UserProfileHeader(inProps) {
|
|
|
106
107
|
? { background: `url('${scUser.cover}') center / cover` }
|
|
107
108
|
: { background: `url('${scPreferences.preferences[SCPreferences.IMAGES_USER_DEFAULT_COVER].value}') center / cover` }));
|
|
108
109
|
const realName = (isMe && scUserContext.user.real_name) || scUser.real_name;
|
|
110
|
+
const hasBadge = scUser && scUser.community_badge;
|
|
109
111
|
return (React.createElement(Root, Object.assign({ id: id, className: classNames(classes.root, className) }, rest),
|
|
110
112
|
React.createElement(Paper, { style: _backgroundCover, classes: { root: classes.cover } },
|
|
111
|
-
React.createElement(
|
|
113
|
+
React.createElement(Box, { className: classes.avatar },
|
|
114
|
+
React.createElement(UserAvatar, { hide: !hasBadge },
|
|
115
|
+
React.createElement("img", { src: scUser.avatar ? scUser.avatar : '' }))),
|
|
112
116
|
isMe && (React.createElement(React.Fragment, null,
|
|
113
117
|
React.createElement(ChangePicture, Object.assign({ iconButton: true, onChange: handleChangeAvatar, className: classes.changePicture }, ChangePictureProps)),
|
|
114
118
|
React.createElement("div", { className: classes.changeCover },
|