I'm using my react typescript project for Ant design,
this is my conflict, I wanna click on the tag and its display to Sun editor content area so when I click the tag display the text area but it I cant to add on the sun editor any solution for this? Thanks
code here
import React from 'react';
import ReactDOM from 'react-dom';
import 'antd/dist/antd.css';
import './index.css';
import { Comment, Avatar, Form, Button, List, Input,Tag } from 'antd';
import moment from 'moment';
import 'suneditor/dist/css/suneditor.min.css';
import SunEditor from "suneditor-react";
const { TextArea } = Input;
const CommentList = ({ comments }) => (
<List
dataSource={comments}
header={`${comments.length} ${comments.length > 1 ? 'replies' : 'reply'}`}
itemLayout="horizontal"
renderItem={props => <Comment {...props} />}
/>
);
const Editor = ({ onChange, onSubmit, submitting, value }) => (
<>
<Form.Item>
<TextArea rows={4} onChange={onChange} value={value} />
</Form.Item>
<Form.Item>
<Button htmlType="submit" loading={submitting} onClick={onSubmit} type="primary">
Add Comment
</Button>
</Form.Item>
</>
);
class App extends React.Component {
state = {
comments: [],
submitting: false,
value: '',
};
handleSubmit = () => {
if (!this.state.value) {
return;
}
this.setState({
submitting: true,
});
setTimeout(() => {
this.setState({
submitting: false,
value: '',
comments: [
...this.state.comments,
{
author: 'Han Solo',
avatar: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png',
content: <p>{this.state.value}</p>,
datetime: moment().fromNow(),
},
],
});
}, 1000);
};
handleChange = e => {
this.setState({
value: e.target.value,
});
};
addTag = e => {
const txt = e.target.innerHTML;
this.setState(prevState => ({
...prevState,
value: `${prevState.value} <${txt}> `,
}));
}
render() {
const { comments, submitting, value } = this.state;
return (
<>
<div>
<Tag onClick={this.addTag} color="magenta">First Name</Tag>
<Tag onClick={this.addTag} color="red">Last Name</Tag>
<Tag onClick={this.addTag} color="volcano">NIC</Tag>
<Tag onClick={this.addTag} color="orange">FAX</Tag>
</div>
{comments.length > 0 && <CommentList comments={comments} />}
<Comment
avatar={
<Avatar
src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png"
alt="Han Solo"
/>
}
content={
<Editor
onChange={this.handleChange}
onSubmit={this.handleSubmit}
submitting={submitting}
value={value}
/>
}
/>
<SunEditor
autoFocus={true}
width="100%"
height="150px"
onChange={this.handleChange}
onClick={this.onSubmit}
/* defaultValue={value}*/
setOptions={{
buttonList: [
// default
['undo', 'redo'],
['bold', 'underline', 'italic', 'list'],
['table', 'link', 'image'],
['fullScreen'],
['codeView']
]
}}
setContents={value}
/>
</>
);
}
}
ReactDOM.render(<App />, document.getElementById('container'));
[1]: https://www.npmjs.com/package/suneditor-react
[2]: https://stackblitz.com/edit/react-pqp2iu-ynivmu?file=index.js
UPDATE 13-MAY-2021
using state in sun editor will trigger race problem between handleChange()
and addTag()
, there is a chance the state will be replaced by old state.
To get rid of it, use the sun editor reference to manipulate the content.
For adding new text and place it horizontally instead of vertically, they have a insertHTML()
function which will respect the html content without adding new <p>
in the first place.
Updated Code: https://stackblitz.com/edit/react-pqp2iu-axacak?file=index.js
constructor() {
super();
this.editorRef = React.createRef();
}
<SunEditor ref={this.editorRef} ... />
handleChange()
, leave it to sun editor to handle it by itselfinsertHTML()
addTag = e => {
const txt = e.target.innerHTML;
this.editorRef.current.editor.insertHTML(`{${txt}}`);
};
OLD content
<
and >
have special meaning in sun text editor which is representing html tags like <p>
<a>
etc and it will be hidden from the editor.
Therefore, when you apply <Firtname>
to the editor, it will disappear. To be able to display it, I suggest you to use mustache syntax {}
which is used by SendGrid, Twilio template as well.
Other than that, handleChange
in sun text editor will return you the content directly so there is no need to get it from event target.
Here is the forked version of yours with mustache template
https://stackblitz.com/edit/react-pqp2iu-axacak?file=index.js
handleChange = content => {
console.log(content);
this.setState({
value: content
});
};
addTag = e => {
const txt = e.target.innerHTML;
console.log(txt);
this.setState(prevState => ({
...prevState,
value: prevState.value.replace(/<\/p>$/, '') + `{${txt}}</p>` // remove the last </p>, append the new content, add back the </p> to avoid new line
}));
};