@selfcommunity/react-ui
Version:
React UI Components to integrate a Community created with SelfCommunity Platform.
148 lines (140 loc) • 6.46 kB
JavaScript
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
import { forwardRef, useCallback, useImperativeHandle, useMemo, useRef, useState } from 'react';
import { styled } from '@mui/material/styles';
import { FormattedMessage } from 'react-intl';
import { Box, Stack } from '@mui/material';
import classNames from 'classnames';
import { useThemeProps } from '@mui/system';
import nodes from './nodes';
import { LexicalComposer } from '@lexical/react/LexicalComposer';
import { ContentEditable } from '@lexical/react/LexicalContentEditable';
import ToolbarPlugin from './plugins/ToolbarPlugin';
import { PREFIX } from './constants';
import { HorizontalRulePlugin } from './plugins/HorizontalRulePlugin';
import { RichTextPlugin } from './plugins/LexicalRichTextPlugin';
import { LexicalErrorBoundary } from '@lexical/react/LexicalErrorBoundary';
import { AutoLinkPlugin, DefaultHtmlValuePlugin, EmojiPlugin, ImagePlugin, MentionsPlugin, OnChangePlugin } from './plugins';
import OnBlurPlugin from './plugins/OnBlurPlugin';
import OnFocusPlugin from './plugins/OnFocusPlugin';
import { LinkPlugin } from '@lexical/react/LexicalLinkPlugin';
import FloatingLinkPlugin from './plugins/FloatingLinkPlugin';
import ApiPlugin from './plugins/ApiPlugin';
import { HistoryPlugin } from '@lexical/react/LexicalHistoryPlugin';
import { ListPlugin } from '@lexical/react/LexicalListPlugin';
const classes = {
root: `${PREFIX}-root`,
focused: `${PREFIX}-focused`,
toolbar: `${PREFIX}-toolbar`,
content: `${PREFIX}-content`,
placeholder: `${PREFIX}-placeholder`,
actions: `${PREFIX}-actions`
};
const Root = styled(Box, {
name: PREFIX,
slot: 'Root',
overridesResolver: (props, styles) => {
return [styles.root, props.className.includes(classes.toolbar) && styles.toolbar];
}
})(({ theme }) => ({}));
const editorTheme = {
heading: {
h1: `${PREFIX}-h1`,
h2: `${PREFIX}-h2`,
h3: `${PREFIX}-h3`,
h4: `${PREFIX}-h4`,
h5: `${PREFIX}-h5`,
h6: `${PREFIX}-h6`
},
link: `${PREFIX}-link`,
list: {
listitem: `${PREFIX}-listItem`,
nested: {
listitem: `${PREFIX}-nestedListItem`
},
olDepth: [`${PREFIX}-ol1`, `${PREFIX}-ol2`, `${PREFIX}-ol3`, `${PREFIX}-ol4`, `${PREFIX}-ol5`],
ul: `${PREFIX}-ul`
},
ltr: `${PREFIX}-ltr`,
paragraph: `${PREFIX}-paragraph`,
image: `${PREFIX}-image`,
quote: `${PREFIX}-quote`,
rtl: `${PREFIX}-rtl`,
text: {
bold: `${PREFIX}-textBold`,
italic: `${PREFIX}-textItalic`,
strikethrough: `${PREFIX}-textStrikethrough`,
subscript: `${PREFIX}-textSubscript`,
superscript: `${PREFIX}-textSuperscript`,
underline: `${PREFIX}-textUnderline`,
underlineStrikethrough: `${PREFIX}-textUnderlineStrikethrough`
}
};
/**
* > API documentation for the Community-JS Editor component. Learn about the available props and the CSS API.
*
*
* This component renders a text editor.
* Take a look at our <strong>demo</strong> component [here](/docs/sdk/community-js/react-ui/Components/Editor)
#### Import
```jsx
import {Editor} from '@selfcommunity/react-ui';
```
#### Component Name
The name `SCEditor` can be used when providing style overrides in the theme.
#### CSS
|Rule Name|Global class|Description|
|---|---|---|
|root|.SCEditor-root|Styles applied to the root element.|
|toolbar|.SCEditor-toolbar|Styles applied to the toolbar element.|
|content|.SCEditor-content|Styles applied to the content element.|
|placeholder|.SCEditor-placeholder|Styles applied to the placeholder element.|
|actions|.SCEditor-actions|Styles applied to the actions section.|
* @param inProps
*/
const Editor = (inProps, ref) => {
// PROPS
const props = useThemeProps({
props: inProps,
name: PREFIX
});
const { id = 'editor', className = null, defaultValue = '', toolbar = false, uploadImage = false, editable = true, onChange = null, onFocus = null, onBlur = null } = props;
const apiRef = useRef();
// STATE
const [focused, setFocused] = useState(false);
// HANDLERS
const handleChange = (value) => {
onChange && onChange(value);
};
const handleError = (error, editor) => {
console.log(error);
};
const handleFocus = () => {
apiRef.current.focus();
};
const handleHasFocus = useCallback((event) => {
setFocused(true);
onFocus && onFocus(event);
}, [onFocus]);
const handleHasBlur = useCallback((event) => {
setFocused(false);
onBlur && onBlur(event);
}, [onBlur]);
// EXPOSED METHODS
useImperativeHandle(ref, () => ({
focus: () => {
apiRef.current.focus();
}
}));
// RENDER
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
const initialConfig = useMemo(() => ({
namespace: 'LexicalEditor',
editable: editable,
onError: handleError,
nodes: [...nodes],
theme: editorTheme
}), [editable]);
return (_jsx(Root, Object.assign({ id: id, className: classNames(classes.root, className, { [classes.toolbar]: toolbar, [classes.focused]: focused }) }, { children: _jsxs(LexicalComposer, Object.assign({ initialConfig: initialConfig }, { children: [toolbar ? (_jsxs(_Fragment, { children: [_jsx(ToolbarPlugin, { uploadImage: uploadImage }), _jsx(ListPlugin, {}), _jsx(HorizontalRulePlugin, {})] })) : (_jsxs(Stack, Object.assign({ className: classes.actions, direction: "row" }, { children: [uploadImage && _jsx(ImagePlugin, {}), _jsx(EmojiPlugin, {})] }))), _jsx(RichTextPlugin, { contentEditable: _jsx(ContentEditable, { className: classes.content }), placeholder: _jsx(Box, Object.assign({ className: classes.placeholder, onClick: handleFocus }, { children: _jsx(FormattedMessage, { id: "ui.editor.placeholder", defaultMessage: "ui.editor.placeholder" }) })), ErrorBoundary: LexicalErrorBoundary }), _jsx(DefaultHtmlValuePlugin, { defaultValue: defaultValue }), _jsx(HistoryPlugin, {}), _jsx(OnChangePlugin, { onChange: handleChange }), _jsx(OnBlurPlugin, { onBlur: handleHasBlur }), _jsx(OnFocusPlugin, { onFocus: handleHasFocus }), _jsx(AutoLinkPlugin, {}), _jsx(MentionsPlugin, {}), _jsx(LinkPlugin, {}), _jsx(FloatingLinkPlugin, {}), _jsx(ApiPlugin, { ref: apiRef })] })) })));
};
export default forwardRef(Editor);