How to add Tweet HTML Block to react-quilljs - javascript

I'm using 'react-quilljs' package, and I want to add Tweet HTML Block to the toolbar, I couldn't find any tutorial how to in their webpage
The Code I'm Using:
import { useQuill } from 'react-quilljs';
import 'quill/dist/quill.snow.css';
export default function NewPost() {
const [content, setContent] = useState("");
//Quill Editor Toolbar
const modules = {
toolbar:{
container: [
[{'header': '1'}, {'header':'2'}, {'font':'[]'}],
[{size:[]}],
['bold', 'italic', 'underline', 'strike', 'blockquote'],
[{'list': 'ordered'}, {'list': 'bullet'}, {'indent':'-1'}, {'indent':'+1'}],
['link', 'image', imageHandler],
['clean'], ['code-block']
],
},
clipboard: {
matchVisual: false,
},
};
const { quill, quillRef } = useQuill();
useEffect(() => {
if (quill){
quill.on('text-change', () => {
console.log(quillRef.current.firstChild.innerHTML);
setContent(quillRef.current.firstChild.innerHTML)
});
}
}, [quill]);
console.log(content, "this is quill editor")
return (
<div className="newPostContentContainer">
<label className="newPostFormLabel">Post Content:</label
<div className="newPostContentTextareaContainer">
<div dir="auto" style={{ height: '300px', width: '100%', boxSizing: 'border-box'}}>
<div ref={quillRef} />
</div>
</div>
</div>
)
}
the problem is that the toolbar I have right now don't have the tweet HTML block or code sample, I have to add them by myself, which I failed to know how, any help would be appreciated.

Related

React CKEditor5 Form submit not getting the data?

I am using CKeditor in react. On Form submit, why entered data is not coming.
Form submit, CKeditor data is still showing empty
How to get the CKEditor data both in text as well as HTML format.
Please find my code:
import React from "react";
import { CKEditor } from '#ckeditor/ckeditor5-react';
import ClassicEditor from '#ckeditor/ckeditor5-build-classic';
export class UseEditor extends React.Component {
constructor(props)
super(props);
this.state = {
DescriptionTextPlain: "",
DescriptionTextHTML: "",
loading: true,
};
this.handleSubmit = this.handleSubmit.bind(this);
}
handleEditorChange(event, editor) {
console.log({ event, editor });
}
handleSubmit(event) {
const DescriptionTextPlain = this.state.DescriptionTextPlain;
const DescriptionTextHTML = this.state.DescriptionTextHTML;
const data = {
DescriptionTextPlain, DescriptionTextHTML
}
fetch(REQUEST_URL, {
method: 'POST'
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<div>
<CKEditor name="DescriptionTextPlain" editor={ClassicEditor}
config={{
toolbar: [
'|', 'bold', 'italic', 'link', 'bulletedList', 'numberedList', '|',
'outdent', 'indent', '|', 'insertTable', 'undo', 'redo', 'style',
'strikethrough', 'subscript', 'superscript'
] }}
data={this.state.DescriptionTextPlain || ''}
onReady={editor => { this.editor = editor;}}
onChange={this.handleEditorChange}
Width="100%" Height="125px"
value={this.state.DescriptionTextPlain} />
</div> <input type="submit" name="submit" value="Submit" />
</form>
</div>
);
}
}
export default UseEditor;

Proper way to use react-quil to store images embedded in text

I am using react-quill 1.3.3. I also allow for the addition of images into the posts. The way that quill works right now, is that it just converts the image to a string and sends it all as text. The problem is that this seems to take a lot of extra memory (data). For instance, I am getting 413 errors, "413 (Payload Too Large)", for images that are only 20K, etc. The real way to do this is to convert your images into links and save the images to a cloud service. I already have the cloud service working for saving avatar images, so that can just be copied. The problem is, how do we get react-quill to do this? Quill seems like a one stop shop that just converts your images to text, so we are going to have to do some special coding and I have no idea how to do that.
Here is the quill component:
import React from 'react'
export default class PostEditor extends React.Component {
constructor(props) {
super(props)
this.state = { editorHtml: '', theme: 'snow' }
this.handleChange = this.handleChange.bind(this)
if (typeof window !== 'undefined') {
this.ReactQuill = require('react-quill');
require('katex');
require('react-quill/dist/quill.snow.css');
}
}
handleChange (value) {
this.props.onChange(value);
}
render() {
const ReactQuill = this.ReactQuill
const { value } = this.props;
if (typeof window !== 'undefined' && ReactQuill) {
return (
<ReactQuill
onChange={this.handleChange}
theme="snow"
value={value}
modules={PostEditor.modules}
/>
)
} else {
return <textarea />;
}
}
}
PostEditor.modules = {
toolbar: [
[{ 'header': '1'}, {'header': '2'}, { 'font': [] }],
[{size: []}],
['bold', 'italic', 'underline', 'strike', 'blockquote'],
[{'list': 'ordered'}, {'list': 'bullet'},
{'indent': '-1'}, {'indent': '+1'}],
['link', 'image', 'video','formula'],
['clean']
],
clipboard: {
// toggle to add extra line breaks when pasting HTML:
matchVisual: false,
}
}
PostEditor.formats = [
'header', 'font', 'size',
'bold', 'italic', 'underline', 'strike', 'blockquote',
'list', 'bullet', 'indent',
'link', 'image', 'video', 'formula'
]
// PostEditor.propTypes = {
// placeholder: PropTypes.string,
// }
Here is some work done to do something similar, but I have no idea how to add this code to my app.
What I am expecting is that we should be able to use the "add image" button on the quill toolbar and the wysiwyg works fine and the image is taken from the user's hard drive and placed in the text properly formated. The difference is that when you save, the image is sent to your cloud storage and a link is pasted into the saved html. When you view the post, that link is expanded into an image again.
If anyone knows why the images are being converted into such large sizes (more than 20MB) please let me know because I might also just accept that as a solution.
Here is the code for the part of the component that contains the quill:
{this.isActiveField('postText') && (
<Fieldset className="mt2">
<PostEditor
id="postText"
onChange={this.onChange}
value={postText}
/>
<Snackbar
anchorOrigin={{
vertical: 'bottom',
horizontal: 'left',
}}
open={!!ErrorHandling.getFieldErrors(errors, 'postText')}
autoHideDuration={4000}
onClose={this.handleClose}
ContentProps={{
'aria-describedby': 'message-id',
}}
message={<span id="message-id">{ErrorHandling.getFieldErrors(errors, 'postText')}</span>}
action={[
<IconButton
key="close"
aria-label="Close"
color="inherit"
className={classes.close}
onClick={this.handleClose}
>
<CloseIcon />
</IconButton>,
]}
/>
</Fieldset>
)}
Edit:
I worked out the second solution. In my Apollo server code I added the bodyParser as recommended here. It seems to work fine now.

ReactQuill (rich text) - Error: React.Children.only expected to receive a single React element child - React

I have a form and I replaced the textarea with ReactQuill based on this tutorial (https://www.youtube.com/watch?v=DjEANvaZFv0&feature=youtu.be) to get Rich Text. However once I did it, I got an error saying 'Error: React.Children.only expected to receive a single React element child' (see screenshot below).
This only came up after I replaced the textarea with ReactQuill but on the error page it shows me the code in the App.js where I've implemented google authentication with firebase and I'm not sure how the two are connected. How do I fix this?
Here's my AddArticle.js where the form is:
import React, { Component } from "react";
import firebase from "../Firebase";
import ReactQuill from "react-quill";
import "react-quill/dist/quill.snow.css";
import renderHTML from 'react-render-html';
class AddArticle extends Component {
constructor() {
super();
this.ref = firebase.firestore().collection("articles");
this.state = {
title: "",
content: "",
};
}
onChange = (e) => {
const state = this.state;
state[e.target.name] = e.target.value;
this.setState(state);
};
onBodyChange(e) {
this.setState({ content: e });
}
onSubmit = (e) => {
e.preventDefault();
const { title, content } = this.state;
this.ref
.add({
title,
content,
})
.then((docRef) => {
this.setState({
title: "",
content: "",
});
this.props.history.push("/");
})
.catch((error) => {
console.error("Error adding document: ", error);
});
};
render() {
const { title, content } = this.state;
return (
<div className="container">
<br></br>
<br></br>
<br></br>
<div className="panel panel-default">
<div className="panel-heading">
<h3 className="panel-title text-center">Create a new article</h3>
</div>
<br></br>
<br></br>
<div className="panel-body">
<form onSubmit={this.onSubmit}>
<div className="form-group input-group-lg">
<label for="title">Title:</label>
<input
type="text"
className="form-control"
name="title"
value={title}
onChange={this.onChange}
placeholder="Title"
/>
</div>
<div className="form-group">
<label for="content">Content:</label>
<ReactQuill
modules={AddArticle.modules}
formats={AddArticle.formats}
name="content"
onChange={this.onBodyChange}
placeholder="Content"
cols="80"
rows="20"
>
{content}
</ReactQuill>
</div>
<button type="submit" className="btn btn-success">
Submit
</button>
</form>
</div>
</div>
</div>
);
}
}
// Quill Config
AddArticle.modules = {
toolbar: [
[{ header: [1, 2, 3, 4, 5, 6, false] }],
[{ size: [] }],
["bold", "italic", "underline", "strike", "blockquote"],
[
{ list: "ordered" },
{ list: "bullet" },
{ indent: "-1" },
{ indent: "+1" },
],
["link", "image", "video"],
["clean"],
["code-block"],
],
clipboard: {
// toggle to add extra line breaks when pasting HTML:
matchVisual: false,
},
};
AddArticle.formats = [
"header",
"font",
"size",
"bold",
"italic",
"underline",
"strike",
"blockquote",
"list",
"bullet",
"indent",
"link",
"image",
"video",
"code-block",
];
export default AddArticle;
And here is my App.js in case it's relevant:
import React, { Component } from "react";
import "./App.css";
import Navbar from "./components/Navbar";
import Main from "./Main";
import firebase from "firebase";
import StyledFirebaseAuth from "react-firebaseui/StyledFirebaseAuth";
class App extends Component {
state={isSignedIn:false}
uiConfig = {
signInFlow: "popup",
signInOptions: [
firebase.auth.GoogleAuthProvider.PROVIDER_ID
],
callbacks: {
signInSuccess: () => false
}
}
componentDidMount = () => {
firebase.auth().onAuthStateChanged(user => {
this.setState({isSignedIn:!!user})
})
}
render() {
return (
<div>
{this.state.isSignedIn ? (
<span>
<Navbar />
<Main />
</span>
) :
(
<StyledFirebaseAuth
uiConfig={this.uiConfig}
firebaseAuth={firebase.auth()}
/>
)}
</div>
);
}
}
export default App;
As described here, I suggest passing content as ReactQuill's value instead of making it a child:
<ReactQuill
value={this.state.content}
// ... other props are OK
/> // Close the tag: no children

Why won't my <InnerBlocks.Content /> save?

I am building this custom wrapper block in Gutenberg (Based on create-guten-block).
It works fine on its own, but wont save the Innerblocks! So when I add a new block in the editor, it shows up fine, but when I save and refresh, the innerblock is gone! (the wrapper is still there with the saved attributes).
Can anyone of you clever people tell me why?
MY SECTION BLOCK (Wrapper):
import './style.scss';
import './editor.scss';
const {__} = wp.i18n; // Import __() from wp.i18n
const {registerBlockType} = wp.blocks; // Import registerBlockType() from wp.blocks
const { ColorPalette, InnerBlocks, MediaUpload, InspectorControls } = wp.editor;
const {Button, RangeControl, PanelBody, PanelRow, RadioControl } = wp.components; // used in Inspector controls
registerBlockType('my-blocks/my-section', {
title: __('my Section'), // Block title.
icon: 'welcome-add-page',
category: 'common',
keywords: [
__('my Section'),
__('my Block'),
],
attributes: {
overlayOpacity: {
type: 'number',
default: 40
},
sectionBackgroundImage: {
type: 'string',
default: null
},
sectionBgColor: {
type: 'string',
default: '#e2e2e2',
},
sectionLineColor: {
type: 'string',
default: 'gray', //rgba(194,194,194,0.8)
}
},
edit: props => {
const {
setAttributes,
attributes,
className
} = props;
const {overlayOpacity, sectionBackgroundImage, sectionBgColor, sectionLineColor} = props.attributes;
return ([
<InspectorControls>
/*This code is edited out to save space*/
</InspectorControls>,
<section className={[className + ' page-section-top page-section-bottom ' + sectionLineColor]}
style={{
backgroundColor: sectionBgColor,
backgroundImage: `url(${sectionBackgroundImage})`,
backgroundSize: 'cover',
backgroundPosition: 'center'
}}
>
<div className="page-section-image-dimmer"
style={{opacity: overlayOpacity / 100}}
/>
<InnerBlocks />
</section>
]);
},
save: props => {
const {
className
} = props;
const {overlayOpacity, sectionBackgroundImage, sectionBgColor, sectionLineColor} = props.attributes;
return ([
<section className={[className + ' page-section-top page-section-bottom ' + sectionLineColor]}
style={{
backgroundColor: sectionBgColor,
backgroundImage: `url(${sectionBackgroundImage})`,
backgroundSize: 'cover',
backgroundPosition: 'center'
}}
>
<div className="page-section-image-dimmer"
style={{opacity: overlayOpacity / 100}}
/>
<InnerBlocks.Content />
</section>
]);
}
});
Actually... It seems my code is correct. Somehow it was the create-guten-block setup that was buggy. I did a fresh install and copied the above code in to a new custom block, and now it works :)

react-quill missing style after adding custom toolbar button

I need to add a custom toolbar button inside the react quill HTML editor.
I have followed the tutorial https://github.com/zenoamaro/react-quill#custom-toolbar but was not able to get this to work. The code is as follows.
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import ReactQuill from 'react-quill'; // ES6
import './style.scss';
class DocumentForm extends Component {
constructor(props) {
super(props);
this.state = {
file: null,
documentDetails: {},
text: ''
};
this.handleEditorChange = this.handleEditorChange.bind(this);
this.modules = {
toolbar: [
[{ 'header': [1, 2, false] }],
['bold', 'italic', 'underline','strike', 'blockquote'],
[{'list': 'ordered'}, {'list': 'bullet'}, {'indent': '-1'}, {'indent': '+1'}],
['link', 'image'],
['clean']
],
}
this.formats = [
'header',
'bold', 'italic', 'underline', 'strike', 'blockquote',
'list', 'bullet', 'indent',
'link', 'image'
]
}
handleEditorChange(value) {
this.setDocumentDetails('html_content', value)
}
render() {
let selectedDocument = this.state.documentDetails;
return (
<div>
<div>
<div className="form-group">
<label>File Content</label>
<Editor placeholder={'Write something or insert a star ★'}/>,
</div>
</div>
</div>
);
}
}
export default DocumentForm
/*
* Custom "star" icon for the toolbar using an Octicon
* https://octicons.github.io
*/
const CustomButton = () => <span className="octicon octicon-star" />
/*
* Event handler to be attached using Quill toolbar module
* http://quilljs.com/docs/modules/toolbar/
*/
function insertStar () {
const cursorPosition = this.quill.getSelection().index
this.quill.insertText(cursorPosition, "★")
this.quill.setSelection(cursorPosition + 1)
}
/*
* Custom toolbar component including insertStar button and dropdowns
*/
const CustomToolbar = () => (
<div id="toolbar">
<select className="ql-header" defaultValue={""} onChange={e => e.persist()}>
<option value="1"></option>
<option value="2"></option>
<option selected></option>
</select>
<button className="ql-bold"></button>
<button className="ql-italic"></button>
<select className="ql-color">
<option value="red"></option>
<option value="green"></option>
<option value="blue"></option>
<option value="orange"></option>
<option value="violet"></option>
<option value="#d0d1d2"></option>
<option selected></option>
</select>
<button className="ql-insertStar">
<CustomButton />
</button>
</div>
)
/*
* Editor component with custom toolbar and content containers
*/
class Editor extends React.Component {
constructor (props) {
super(props)
this.state = { editorHtml: '' }
this.handleChange = this.handleChange.bind(this)
}
handleChange (html) {
this.setState({ editorHtml: html });
}
render() {
return (
<div className="text-editor">
<CustomToolbar />
<ReactQuill
onChange={this.handleChange}
placeholder={this.props.placeholder}
modules={Editor.modules}
/>
</div>
)
}
}
/*
* Quill modules to attach to editor
* See http://quilljs.com/docs/modules/ for complete options
*/
Editor.modules = {
toolbar: {
container: "#toolbar",
handlers: {
"insertStar": insertStar,
}
}
}
/*
* Quill editor formats
* See http://quilljs.com/docs/formats/
*/
Editor.formats = [
'header', 'font', 'size',
'bold', 'italic', 'underline', 'strike', 'blockquote',
'list', 'bullet', 'indent',
'link', 'image', 'color',
]
Unlike the tutorial there were 2 toolbars
The custom toolbar was displayed but the buttons were not having styles.
Also the button handler(insertStar) is not working.
A screenshot of the page is as follows.
Any idea on how to fix this
In Reactquill documentation https://www.npmjs.com/package/react-quill#import-the-stylesheet the stylesheet must be imported as:
require('react-quill/dist/quill.snow.css'); // CommonJS
import 'react-quill/dist/quill.snow.css'; // ES6
According to the quill.js guide, you need to import the CSS like following
#import "~quill/dist/quill.core.css"
Try importing, the stylesheet like:
import "react-quill/dist/quill.snow.css"

Categories