2019-10-30 14:34:24 +00:00
|
|
|
import { makeStyles } from "@material-ui/core/styles";
|
2019-06-19 14:40:52 +00:00
|
|
|
import { fade } from "@material-ui/core/styles/colorManipulator";
|
|
|
|
import Typography from "@material-ui/core/Typography";
|
2019-08-09 11:14:35 +00:00
|
|
|
import classNames from "classnames";
|
2019-06-19 14:40:52 +00:00
|
|
|
import { RawDraftContentState } from "draft-js";
|
|
|
|
import {
|
|
|
|
BLOCK_TYPE,
|
|
|
|
DraftailEditor,
|
|
|
|
ENTITY_TYPE,
|
|
|
|
INLINE_STYLE
|
|
|
|
} from "draftail";
|
2019-08-09 11:14:35 +00:00
|
|
|
import isEqual from "lodash-es/isEqual";
|
2019-08-09 10:26:22 +00:00
|
|
|
import React from "react";
|
2019-06-19 14:40:52 +00:00
|
|
|
|
2019-12-02 10:49:14 +00:00
|
|
|
import { ChangeEvent } from "@saleor/hooks/useForm";
|
2019-06-19 14:40:52 +00:00
|
|
|
import BoldIcon from "../../icons/BoldIcon";
|
|
|
|
import HeaderTwo from "../../icons/HeaderTwo";
|
2019-12-02 10:49:14 +00:00
|
|
|
import HeaderThree from "../../icons/HeaderThree";
|
2019-06-19 14:40:52 +00:00
|
|
|
import ItalicIcon from "../../icons/ItalicIcon";
|
|
|
|
import LinkIcon from "../../icons/LinkIcon";
|
|
|
|
import OrderedListIcon from "../../icons/OrderedListIcon";
|
2019-12-02 10:49:14 +00:00
|
|
|
import HeaderOne from "../../icons/HeaderOne";
|
2019-06-19 14:40:52 +00:00
|
|
|
import QuotationIcon from "../../icons/QuotationIcon";
|
|
|
|
import StrikethroughIcon from "../../icons/StrikethroughIcon";
|
|
|
|
import UnorderedListIcon from "../../icons/UnorderedListIcon";
|
|
|
|
import LinkEntity from "./LinkEntity";
|
|
|
|
import LinkSource from "./LinkSource";
|
|
|
|
|
|
|
|
export interface RichTextEditorProps {
|
|
|
|
disabled: boolean;
|
|
|
|
error: boolean;
|
|
|
|
helperText: string;
|
2019-12-02 10:49:14 +00:00
|
|
|
initial?: RawDraftContentState;
|
2019-06-19 14:40:52 +00:00
|
|
|
label: string;
|
|
|
|
name: string;
|
|
|
|
scroll?: boolean;
|
|
|
|
onChange: (event: React.ChangeEvent<any>) => void;
|
|
|
|
}
|
|
|
|
|
2019-10-30 14:34:24 +00:00
|
|
|
const useStyles = makeStyles(theme => ({
|
|
|
|
error: {
|
|
|
|
color: theme.palette.error.main
|
|
|
|
},
|
|
|
|
helperText: {
|
|
|
|
marginTop: theme.spacing(0.75)
|
|
|
|
},
|
|
|
|
input: {
|
|
|
|
position: "relative"
|
|
|
|
},
|
|
|
|
label: {
|
|
|
|
fontSize: theme.typography.caption.fontSize,
|
|
|
|
left: 12,
|
|
|
|
position: "absolute",
|
|
|
|
top: 9
|
|
|
|
},
|
|
|
|
linkIcon: {
|
|
|
|
marginTop: 2
|
|
|
|
},
|
|
|
|
root: {
|
|
|
|
"& .DraftEditor": {
|
|
|
|
"&-editorContainer": {
|
|
|
|
"& .public-DraftEditor-content": {
|
|
|
|
lineHeight: 1.62
|
|
|
|
},
|
|
|
|
"& a": {
|
|
|
|
color: theme.palette.primary.light
|
|
|
|
},
|
|
|
|
"&:after": {
|
|
|
|
background: theme.palette.getContrastText(
|
|
|
|
theme.palette.background.default
|
|
|
|
),
|
|
|
|
bottom: -11,
|
|
|
|
content: "''",
|
|
|
|
display: "block",
|
|
|
|
height: 2,
|
|
|
|
left: -12,
|
|
|
|
position: "absolute",
|
|
|
|
transform: "scaleX(0) scaleY(0)",
|
|
|
|
width: "calc(100% + 24px)"
|
|
|
|
},
|
|
|
|
position: "relative"
|
|
|
|
},
|
|
|
|
"&-root": {
|
|
|
|
...theme.typography.body1
|
|
|
|
}
|
2019-06-19 14:40:52 +00:00
|
|
|
},
|
2019-10-30 14:34:24 +00:00
|
|
|
"& .Draftail": {
|
|
|
|
"&-Editor": {
|
|
|
|
"&--focus": {
|
|
|
|
boxShadow: `inset 0px 0px 0px 2px ${theme.palette.primary.main}`
|
2019-06-19 14:40:52 +00:00
|
|
|
},
|
2019-10-30 14:34:24 +00:00
|
|
|
"&:hover": {
|
|
|
|
borderColor: theme.palette.primary.main
|
|
|
|
},
|
|
|
|
border: `1px ${theme.palette.divider} solid`,
|
|
|
|
borderRadius: 4,
|
|
|
|
padding: "27px 12px 10px",
|
|
|
|
position: "relative",
|
|
|
|
transition: theme.transitions.duration.shortest + "ms"
|
2019-06-19 14:40:52 +00:00
|
|
|
},
|
2019-10-30 14:34:24 +00:00
|
|
|
"&-Toolbar": {
|
|
|
|
"&Button": {
|
|
|
|
"& svg": {
|
|
|
|
padding: 2
|
2019-08-09 11:14:35 +00:00
|
|
|
},
|
2019-10-30 14:34:24 +00:00
|
|
|
"&--active": {
|
|
|
|
"&:hover": {
|
2019-06-19 14:40:52 +00:00
|
|
|
background: theme.palette.primary.main
|
|
|
|
},
|
2019-10-30 14:34:24 +00:00
|
|
|
"&:not(:hover)": {
|
|
|
|
borderRightColor: theme.palette.primary.main
|
2019-06-19 14:40:52 +00:00
|
|
|
},
|
2019-10-30 14:34:24 +00:00
|
|
|
background: theme.palette.primary.main
|
2019-06-19 14:40:52 +00:00
|
|
|
},
|
2019-10-30 14:34:24 +00:00
|
|
|
"&:focus": {
|
|
|
|
"&:active": {
|
|
|
|
"&:after": {
|
|
|
|
background: fade(theme.palette.primary.main, 0.3),
|
|
|
|
borderRadius: "100%",
|
|
|
|
content: "''",
|
|
|
|
display: "block",
|
|
|
|
height: "100%",
|
|
|
|
width: "100%"
|
2019-06-19 14:40:52 +00:00
|
|
|
}
|
2019-10-30 14:34:24 +00:00
|
|
|
}
|
2019-06-19 14:40:52 +00:00
|
|
|
},
|
2019-10-30 14:34:24 +00:00
|
|
|
"&:hover": {
|
|
|
|
background: fade(theme.palette.primary.main, 0.3)
|
|
|
|
},
|
|
|
|
alignItems: "center",
|
|
|
|
background: "none",
|
|
|
|
border: "none",
|
|
|
|
borderRight: `1px ${theme.palette.divider} solid`,
|
|
|
|
color: theme.typography.body1.color,
|
|
|
|
cursor: "pointer",
|
2019-06-19 14:40:52 +00:00
|
|
|
display: "inline-flex",
|
2019-10-30 14:34:24 +00:00
|
|
|
height: 36,
|
|
|
|
justifyContent: "center",
|
|
|
|
padding: theme.spacing(1) + 2,
|
|
|
|
transition: theme.transitions.duration.short + "ms",
|
|
|
|
width: 36
|
2019-06-19 14:40:52 +00:00
|
|
|
},
|
2019-10-30 14:34:24 +00:00
|
|
|
"&Group": {
|
|
|
|
"&:last-of-type": {
|
|
|
|
"& .Draftail-ToolbarButton": {
|
|
|
|
"&:last-of-type": {
|
|
|
|
border: "none"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
display: "flex"
|
|
|
|
},
|
|
|
|
background: theme.palette.background.default,
|
|
|
|
border: `1px ${theme.palette.divider} solid`,
|
|
|
|
display: "inline-flex",
|
|
|
|
flexWrap: "wrap",
|
|
|
|
marginBottom: theme.spacing(),
|
|
|
|
marginTop: 10,
|
|
|
|
[theme.breakpoints.down(460)]: {
|
|
|
|
width: "min-content"
|
2019-06-19 14:40:52 +00:00
|
|
|
}
|
|
|
|
},
|
2019-10-30 14:34:24 +00:00
|
|
|
"&-block": {
|
|
|
|
"&--blockquote": {
|
|
|
|
borderLeft: `2px solid ${theme.palette.divider}`,
|
|
|
|
margin: 0,
|
|
|
|
padding: theme.spacing(1, 2)
|
2019-06-19 14:40:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2019-10-30 14:34:24 +00:00
|
|
|
"&$error": {
|
|
|
|
"& .Draftail": {
|
|
|
|
"&-Editor": {
|
|
|
|
borderColor: theme.palette.error.main
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
scroll: {
|
|
|
|
"& .DraftEditor": {
|
|
|
|
"&-editorContainer": {
|
|
|
|
"& .public-DraftEditor-content": {
|
|
|
|
lineHeight: 1.62
|
2019-06-19 14:40:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-10-30 14:34:24 +00:00
|
|
|
},
|
|
|
|
smallIcon: {
|
|
|
|
marginLeft: 10
|
|
|
|
}
|
|
|
|
}));
|
2019-08-09 11:14:35 +00:00
|
|
|
|
|
|
|
function handleSave(
|
|
|
|
value: any,
|
|
|
|
initial: any,
|
|
|
|
name: string,
|
|
|
|
onChange: (event: ChangeEvent) => void
|
|
|
|
) {
|
|
|
|
if (value && !isEqual(value, initial)) {
|
|
|
|
onChange({
|
|
|
|
target: {
|
|
|
|
name,
|
|
|
|
value
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-30 14:34:24 +00:00
|
|
|
const RichTextEditor: React.FC<RichTextEditorProps> = props => {
|
|
|
|
const { error, helperText, initial, label, name, scroll, onChange } = props;
|
|
|
|
|
|
|
|
const classes = useStyles(props);
|
|
|
|
|
|
|
|
return (
|
2019-06-19 14:40:52 +00:00
|
|
|
<div
|
|
|
|
className={classNames({
|
|
|
|
[classes.error]: error,
|
|
|
|
[classes.root]: true,
|
|
|
|
[classes.scroll]: scroll
|
|
|
|
})}
|
|
|
|
>
|
|
|
|
<div className={classes.input}>
|
|
|
|
<Typography className={classes.label} variant="caption" color="primary">
|
|
|
|
{label}
|
|
|
|
</Typography>
|
|
|
|
<DraftailEditor
|
|
|
|
key={JSON.stringify(initial)}
|
|
|
|
rawContentState={
|
|
|
|
initial && Object.keys(initial).length > 0 ? initial : null
|
|
|
|
}
|
2019-08-09 11:14:35 +00:00
|
|
|
onSave={value => handleSave(value, initial, name, onChange)}
|
2019-06-19 14:40:52 +00:00
|
|
|
blockTypes={[
|
|
|
|
{
|
|
|
|
icon: <HeaderOne />,
|
|
|
|
type: BLOCK_TYPE.HEADER_ONE
|
|
|
|
},
|
|
|
|
{ icon: <HeaderTwo />, type: BLOCK_TYPE.HEADER_TWO },
|
|
|
|
{ icon: <HeaderThree />, type: BLOCK_TYPE.HEADER_THREE },
|
|
|
|
{ icon: <QuotationIcon />, type: BLOCK_TYPE.BLOCKQUOTE },
|
|
|
|
{
|
|
|
|
icon: <UnorderedListIcon />,
|
|
|
|
type: BLOCK_TYPE.UNORDERED_LIST_ITEM
|
|
|
|
},
|
|
|
|
{ icon: <OrderedListIcon />, type: BLOCK_TYPE.ORDERED_LIST_ITEM }
|
|
|
|
]}
|
|
|
|
inlineStyles={[
|
|
|
|
{
|
|
|
|
icon: <BoldIcon className={classes.smallIcon} />,
|
|
|
|
type: INLINE_STYLE.BOLD
|
|
|
|
},
|
|
|
|
{
|
|
|
|
icon: <ItalicIcon className={classes.smallIcon} />,
|
|
|
|
type: INLINE_STYLE.ITALIC
|
|
|
|
},
|
|
|
|
{
|
|
|
|
icon: <StrikethroughIcon />,
|
|
|
|
type: INLINE_STYLE.STRIKETHROUGH
|
|
|
|
}
|
|
|
|
]}
|
|
|
|
enableLineBreak
|
|
|
|
entityTypes={[
|
|
|
|
{
|
|
|
|
attributes: ["url"],
|
|
|
|
decorator: LinkEntity,
|
|
|
|
icon: <LinkIcon className={classes.linkIcon} />,
|
|
|
|
source: LinkSource,
|
|
|
|
type: ENTITY_TYPE.LINK
|
|
|
|
}
|
|
|
|
// {
|
|
|
|
// attributes: ["href"],
|
|
|
|
// decorator: ImageEntity,
|
|
|
|
// icon: <ImageIcon />,
|
|
|
|
// source: ImageSource,
|
|
|
|
// type: ENTITY_TYPE.IMAGE
|
|
|
|
// }
|
|
|
|
]}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
{helperText && (
|
|
|
|
<Typography
|
|
|
|
className={classNames({
|
|
|
|
[classes.error]: error,
|
|
|
|
[classes.helperText]: true
|
|
|
|
})}
|
|
|
|
variant="caption"
|
|
|
|
>
|
|
|
|
{helperText}
|
|
|
|
</Typography>
|
|
|
|
)}
|
|
|
|
</div>
|
2019-10-30 14:34:24 +00:00
|
|
|
);
|
|
|
|
};
|
|
|
|
|
2019-06-19 14:40:52 +00:00
|
|
|
RichTextEditor.displayName = "RichTextEditor";
|
|
|
|
RichTextEditor.defaultProps = {
|
|
|
|
scroll: true
|
|
|
|
};
|
|
|
|
export default RichTextEditor;
|