This commit is contained in:
2025-08-25 20:24:23 +08:00
parent 30106e0129
commit 0ae8d7a709
1044 changed files with 321581 additions and 0 deletions

View File

@@ -0,0 +1,134 @@
import React from 'react';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { List, Map } from 'immutable';
import RawEditor from './RawEditor';
import VisualEditor from './VisualEditor';
const MODE_STORAGE_KEY = 'cms.md-mode';
// TODO: passing the editorControl and components like this is horrible, should
// be handled through Redux and a separate registry store for instances
let editorControl;
// eslint-disable-next-line func-style
let _getEditorComponents = () => Map();
export function getEditorControl() {
return editorControl;
}
export function getEditorComponents() {
return _getEditorComponents();
}
export default class MarkdownControl extends React.Component {
static propTypes = {
onChange: PropTypes.func.isRequired,
onAddAsset: PropTypes.func.isRequired,
getAsset: PropTypes.func.isRequired,
classNameWrapper: PropTypes.string.isRequired,
editorControl: PropTypes.elementType.isRequired,
value: PropTypes.string,
field: ImmutablePropTypes.map.isRequired,
getEditorComponents: PropTypes.func,
t: PropTypes.func.isRequired,
};
static defaultProps = {
value: '',
};
constructor(props) {
super(props);
editorControl = props.editorControl;
const preferredMode = localStorage.getItem(MODE_STORAGE_KEY) ?? 'rich_text';
_getEditorComponents = props.getEditorComponents;
this.state = {
mode:
this.getAllowedModes().indexOf(preferredMode) !== -1
? preferredMode
: this.getAllowedModes()[0],
pendingFocus: false,
};
}
componentDidMount() {
// Manually validate PropTypes - React 19 breaking change
PropTypes.checkPropTypes(MarkdownControl.propTypes, this.props, 'prop', 'MarkdownControl');
}
handleMode = mode => {
this.setState({ mode, pendingFocus: true });
localStorage.setItem(MODE_STORAGE_KEY, mode);
};
processRef = ref => (this.ref = ref);
setFocusReceived = () => {
this.setState({ pendingFocus: false });
};
getAllowedModes = () => this.props.field.get('modes', List(['rich_text', 'raw'])).toArray();
focus() {
this.setState({ pendingFocus: true });
}
render() {
const {
onChange,
onAddAsset,
getAsset,
value,
classNameWrapper,
field,
getEditorComponents,
getRemarkPlugins,
resolveWidget,
t,
isDisabled,
} = this.props;
const { mode, pendingFocus } = this.state;
const isShowModeToggle = this.getAllowedModes().length > 1;
const visualEditor = (
<div className="cms-editor-visual" ref={this.processRef}>
<VisualEditor
onChange={onChange}
onAddAsset={onAddAsset}
isShowModeToggle={isShowModeToggle}
onMode={this.handleMode}
getAsset={getAsset}
className={classNameWrapper}
value={value}
field={field}
getEditorComponents={getEditorComponents}
getRemarkPlugins={getRemarkPlugins}
resolveWidget={resolveWidget}
pendingFocus={pendingFocus && this.setFocusReceived}
t={t}
isDisabled={isDisabled}
/>
</div>
);
const rawEditor = (
<div className="cms-editor-raw" ref={this.processRef}>
<RawEditor
onChange={onChange}
onAddAsset={onAddAsset}
isShowModeToggle={isShowModeToggle}
onMode={this.handleMode}
getAsset={getAsset}
className={classNameWrapper}
value={value}
field={field}
pendingFocus={pendingFocus && this.setFocusReceived}
t={t}
/>
</div>
);
return mode === 'rich_text' ? visualEditor : rawEditor;
}
}