Я нашел этот черновик js с примером Formik на Codesandbox , и я пытаюсь реализовать его в своем проекте Next JS.
Я не понимаю, в чем здесь проблема.
Это мой код:
Артикул. js
import { useState, useEffect } from 'react';
import { addArticle } from '../../store/actions/articleActions';
import { useDispatch, useSelector } from 'react-redux'
import * as Yup from 'yup'
import { Formik } from 'formik'
import dynamic from 'next/dynamic'
import {Editor, EditorState, convertToRaw, convertFromRaw } from 'draft-js';
import {stateToHTML} from 'draft-js-export-html';
import ArticleForm from './ArticleForm'
// reactstrap components
import {
Card,
CardBody,
Container,
Row,
Col
} from "reactstrap";
const Article = () => {
const initialArticle = {
title: '',
slug: '',
content: EditorState.createEmpty()
}
const validationSchema = Yup.object({
title: Yup.string()
.min(3, "Password must be more than 3 charachters!")
.max(20, "Password cant have more than 20 charachters"),
content: Yup.string()
.min(3, "Password must be more than 3 charachters!")
.max(20, "Password cant have more than 20 charachters")
})
const dispatch = useDispatch()
const handleSubmit = async (values) => {
const html = stateToHTML(values.content.getCurrentContent());
console.log("HTMLL", html)
const saveArticle = {
title: values.title,
slug: values.slug,
content: html
}
console.log("articleee", saveArticle)
dispatch(addArticle(saveArticle))
console.log("articleee", saveArticle)
}
return (
<main>
<section className="">
<Container className="pt-lg-md">
<Row className="justify-content-center">
<Col lg="12">
<Card className="bg-secondary shadow border-0">
<CardBody className="px-lg-5 py-lg-5">
<Formik
enableReinitialize={true}
component={ArticleForm}
initialValues={initialArticle}
validationSchema={validationSchema}
validateOnChange={false}
validateOnBlur={true}
onSubmit={(values) => {
handleSubmit(values)
}}
/>
</CardBody>
</Card>
</Col>
</Row>
</Container>
</section>
</main>
);
};
export default Article;
ArticleForm. js
import { Form } from 'formik'
import dynamic from 'next/dynamic'
import {Editor} from 'draft-js';
import { RichEditorExample } from '../../helpers/RichEditor';
// reactstrap components
import {
Button,
FormGroup,
Input,
InputGroupAddon,
InputGroupText,
InputGroup,
} from "reactstrap";
const ArticleForm = props => {
const {
values: {
title,
slug,
content
},
handleChange,
handleSubmit,
setFieldValue,
handleBlur
} = props
// Custom overrides for "code" style.
return (
<React.Fragment>
<Form onSubmit={(e) => {
e.preventDefault()
console.log('submitted')
handleSubmit()
}}
>
<FormGroup>
<InputGroup className="input-group-alternative mb-3">
<InputGroupAddon addonType="prepend">
<InputGroupText>
<i className="ni ni-lock-circle-open" />
</InputGroupText>
</InputGroupAddon>
<Input
placeholder="Title"
type='text'
name='title'
value={title}
onBlur={handleBlur}
onChange={handleChange}
/>
</InputGroup>
</FormGroup>
<FormGroup>
<InputGroup className="input-group-alternative mb-3">
<InputGroupAddon addonType="prepend">
<InputGroupText>
<i className="ni ni-lock-circle-open" />
</InputGroupText>
</InputGroupAddon>
<Input
placeholder="Slug"
type='text'
name='slug'
value={slug}
onBlur={handleBlur}
onChange={handleChange}
/>
</InputGroup>
</FormGroup>
<FormGroup>
<RichEditorExample
editorState={content}
onChange={value => setFieldValue("content", value)}
/>
</FormGroup>
<div className="text-center">
<Button
className="mt-4"
color="primary"
type="submit"
>
Create
</Button>
</div>
</Form>
</React.Fragment>
);
}
export default ArticleForm;
RichEditorExample. js
import React from "react";
import {
Editor,
EditorState,
RichUtils,
convertToRaw,
convertFromRaw
} from "draft-js";
export class RichEditorExample extends React.Component {
onChange = editorState => {
const raw = convertToRaw(editorState.getCurrentContent());
const inputValue = convertFromRaw(raw);
console.log("@@raw", { raw, inputValue });
this.props.onChange("editorState", editorState);
};
focus = () => this.refs.editor.focus();
handleKeyCommand = command => {
const { editorState } = this.props;
const newState = RichUtils.handleKeyCommand(editorState, command);
if (newState) {
this.onChange(newState);
return true;
}
return false;
};
onTab = e => {
const maxDepth = 4;
this.onChange(RichUtils.onTab(e, this.props.editorState, maxDepth));
};
toggleBlockType = blockType => {
this.onChange(RichUtils.toggleBlockType(this.props.editorState, blockType));
};
toggleInlineStyle = inlineStyle => {
this.onChange(
RichUtils.toggleInlineStyle(this.props.editorState, inlineStyle)
);
};
render() {
const { editorState } = this.props;
// If the user changes block type before entering any text, we can
// either style the placeholder or hide it. Let's just hide it now.
let className = "RichEditor-editor";
var contentState = editorState.getCurrentContent() ;
console.log("contentState", contentState)
if (!contentState.hasText()) {
if (
contentState
.getBlockMap()
.first()
.getType() !== "unstyled"
) {
className += " RichEditor-hidePlaceholder";
}
}
return (
<div className="RichEditor-root">
<BlockStyleControls
editorState={editorState}
onToggle={this.toggleBlockType}
/>
<InlineStyleControls
editorState={editorState}
onToggle={this.toggleInlineStyle}
/>
<div className={className} onClick={this.focus}>
<Editor
blockStyleFn={getBlockStyle}
customStyleMap={styleMap}
editorState={editorState}
handleKeyCommand={this.handleKeyCommand}
onChange={this.onChange}
onTab={this.onTab}
placeholder=""
ref="editor"
spellCheck={true}
/>
</div>
</div>
);
}
}
// Custom overrides for "code" style.
const styleMap = {
CODE: {
backgroundColor: "rgba(0, 0, 0, 0.05)",
fontFamily: '"Inconsolata", "Menlo", "Consolas", monospace',
fontSize: 16,
padding: 2
}
};
function getBlockStyle(block) {
switch (block.getType()) {
case "blockquote":
return "RichEditor-blockquote";
default:
return null;
}
}
class StyleButton extends React.Component {
constructor() {
super();
this.onToggle = e => {
e.preventDefault();
this.props.onToggle(this.props.style);
};
}
render() {
let className = "RichEditor-styleButton";
if (this.props.active) {
className += " RichEditor-activeButton";
}
return (
<span className={className} onMouseDown={this.onToggle}>
{this.props.label}
</span>
);
}
}
const BLOCK_TYPES = [
{ label: "H1", style: "header-one" },
{ label: "H2", style: "header-two" },
{ label: "H3", style: "header-three" },
{ label: "H4", style: "header-four" },
{ label: "H5", style: "header-five" },
{ label: "H6", style: "header-six" },
{ label: "Blockquote", style: "blockquote" },
{ label: "UL", style: "unordered-list-item" },
{ label: "OL", style: "ordered-list-item" },
{ label: "Code Block", style: "code-block" }
];
const BlockStyleControls = props => {
const { editorState } = props;
const selection = editorState.getSelection();
const blockType = editorState
.getCurrentContent()
.getBlockForKey(selection.getStartKey())
.getType();
return (
<div className="RichEditor-controls">
{BLOCK_TYPES.map(type => (
<StyleButton
key={type.label}
active={type.style === blockType}
label={type.label}
onToggle={props.onToggle}
style={type.style}
/>
))}
</div>
);
};
var INLINE_STYLES = [
{ label: "Bold", style: "BOLD" },
{ label: "Italic", style: "ITALIC" },
{ label: "Underline", style: "UNDERLINE" },
{ label: "Monospace", style: "CODE" }
];
const InlineStyleControls = props => {
var currentStyle = props.editorState.getCurrentInlineStyle();
return (
<div className="RichEditor-controls">
{INLINE_STYLES.map(type => (
<StyleButton
key={type.label}
active={currentStyle.has(type.style)}
label={type.label}
onToggle={props.onToggle}
style={type.style}
/>
))}
</div>
);
};
Ранее я пытался реализовать редактор реакции-перо аналогичным образом, но есть проблема, которую я могу ' t жирный текст, и я не могу сохранить в базе данных более 2 слов. Поэтому я решил попробовать с Draft JS.
Если вы можете мне помочь, я буду очень благодарен!