From c9cf31851e05ebd7c31ca9b18146f51963e9a63a Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Mon, 3 Feb 2020 12:16:07 +0100 Subject: [PATCH 1/6] Display error message if invalid content is passed --- .../RichTextEditor/RichTextEditor.tsx | 406 +++++++++--------- .../stories/components/RichTextEditor.tsx | 16 + 2 files changed, 230 insertions(+), 192 deletions(-) diff --git a/src/components/RichTextEditor/RichTextEditor.tsx b/src/components/RichTextEditor/RichTextEditor.tsx index 8afa638c1..da092af23 100644 --- a/src/components/RichTextEditor/RichTextEditor.tsx +++ b/src/components/RichTextEditor/RichTextEditor.tsx @@ -1,6 +1,7 @@ import { makeStyles } from "@material-ui/core/styles"; import { fade } from "@material-ui/core/styles/colorManipulator"; import Typography from "@material-ui/core/Typography"; +import { FormattedMessage } from "react-intl"; import classNames from "classnames"; import { RawDraftContentState } from "draft-js"; import { @@ -13,6 +14,7 @@ import isEqual from "lodash-es/isEqual"; import React from "react"; import { ChangeEvent } from "@saleor/hooks/useForm"; +import ErrorBoundary from "react-error-boundary"; import BoldIcon from "../../icons/BoldIcon"; import HeaderTwo from "../../icons/HeaderTwo"; import HeaderThree from "../../icons/HeaderThree"; @@ -38,158 +40,165 @@ export interface RichTextEditorProps { } 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 - } + theme => { + const editorContainer: React.CSSProperties = { + border: `1px ${theme.palette.divider} solid`, + borderRadius: 4, + padding: "27px 12px 10px", + position: "relative", + transition: theme.transitions.duration.shortest + "ms" + }; + + return { + editorContainer, + error: { + color: theme.palette.error.main }, - "& .Draftail": { - "&-Editor": { - "&--focus": { - boxShadow: `inset 0px 0px 0px 2px ${theme.palette.primary.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" }, - "&: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" - }, - "&-Toolbar": { - "&Button": { - "& svg": { - padding: 2 - }, - "&--active": { - "&:hover": { - background: theme.palette.primary.main - }, - "&:not(:hover)": { - borderRightColor: theme.palette.primary.main - }, - background: theme.palette.primary.main - }, - "&:focus": { - "&:active": { - "&:after": { - background: fade(theme.palette.primary.main, 0.3), - borderRadius: "100%", - content: "''", - display: "block", - height: "100%", - width: "100%" - } - } - }, - "&: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", - display: "inline-flex", - height: 36, - justifyContent: "center", - padding: theme.spacing(1) + 2, - transition: theme.transitions.duration.short + "ms", - width: 36 - }, - "&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" + "&-root": { + ...theme.typography.body1 } }, - "&-block": { - "&--blockquote": { - borderLeft: `2px solid ${theme.palette.divider}`, - margin: 0, - padding: theme.spacing(1, 2) - } - } - }, - "&$error": { "& .Draftail": { "&-Editor": { - borderColor: theme.palette.error.main + "&--focus": { + boxShadow: `inset 0px 0px 0px 2px ${theme.palette.primary.main}` + }, + "&:hover": { + borderColor: theme.palette.primary.main + }, + ...editorContainer + }, + "&-Toolbar": { + "&Button": { + "& svg": { + padding: 2 + }, + "&--active": { + "&:hover": { + background: theme.palette.primary.main + }, + "&:not(:hover)": { + borderRightColor: theme.palette.primary.main + }, + background: theme.palette.primary.main + }, + "&:focus": { + "&:active": { + "&:after": { + background: fade(theme.palette.primary.main, 0.3), + borderRadius: "100%", + content: "''", + display: "block", + height: "100%", + width: "100%" + } + } + }, + "&: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", + display: "inline-flex", + height: 36, + justifyContent: "center", + padding: theme.spacing(1) + 2, + transition: theme.transitions.duration.short + "ms", + width: 36 + }, + "&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" + } + }, + "&-block": { + "&--blockquote": { + borderLeft: `2px solid ${theme.palette.divider}`, + margin: 0, + padding: theme.spacing(1, 2) + } + } + }, + "&$error": { + "& .Draftail": { + "&-Editor": { + borderColor: theme.palette.error.main + } } } - } - }, - scroll: { - "& .DraftEditor": { - "&-editorContainer": { - "& .public-DraftEditor-content": { - lineHeight: 1.62 + }, + scroll: { + "& .DraftEditor": { + "&-editorContainer": { + "& .public-DraftEditor-content": { + lineHeight: 1.62 + } } } + }, + smallIcon: { + marginLeft: 10 } - }, - smallIcon: { - marginLeft: 10 - } - }), + }; + }, { name: "RichTextEditor" } ); @@ -226,58 +235,71 @@ const RichTextEditor: React.FC = props => { {label} - 0 ? initial : null - } - onSave={value => handleSave(value, initial, name, onChange)} - blockTypes={[ - { - icon: , - type: BLOCK_TYPE.HEADER_ONE - }, - { icon: , type: BLOCK_TYPE.HEADER_TWO }, - { icon: , type: BLOCK_TYPE.HEADER_THREE }, - { icon: , type: BLOCK_TYPE.BLOCKQUOTE }, - { - icon: , - type: BLOCK_TYPE.UNORDERED_LIST_ITEM - }, - { icon: , type: BLOCK_TYPE.ORDERED_LIST_ITEM } - ]} - inlineStyles={[ - { - icon: , - type: INLINE_STYLE.BOLD - }, - { - icon: , - type: INLINE_STYLE.ITALIC - }, - { - icon: , - type: INLINE_STYLE.STRIKETHROUGH + ( +
+ + + +
+ )} + > + 0 ? initial : null } - ]} - enableLineBreak - entityTypes={[ - { - attributes: ["url"], - decorator: LinkEntity, - icon: , - source: LinkSource, - type: ENTITY_TYPE.LINK - } - // { - // attributes: ["href"], - // decorator: ImageEntity, - // icon: , - // source: ImageSource, - // type: ENTITY_TYPE.IMAGE - // } - ]} - /> + onSave={value => handleSave(value, initial, name, onChange)} + blockTypes={[ + { + icon: , + type: BLOCK_TYPE.HEADER_ONE + }, + { icon: , type: BLOCK_TYPE.HEADER_TWO }, + { icon: , type: BLOCK_TYPE.HEADER_THREE }, + { icon: , type: BLOCK_TYPE.BLOCKQUOTE }, + { + icon: , + type: BLOCK_TYPE.UNORDERED_LIST_ITEM + }, + { icon: , type: BLOCK_TYPE.ORDERED_LIST_ITEM } + ]} + inlineStyles={[ + { + icon: , + type: INLINE_STYLE.BOLD + }, + { + icon: , + type: INLINE_STYLE.ITALIC + }, + { + icon: , + type: INLINE_STYLE.STRIKETHROUGH + } + ]} + enableLineBreak + entityTypes={[ + { + attributes: ["url"], + decorator: LinkEntity, + icon: , + source: LinkSource, + type: ENTITY_TYPE.LINK + } + // { + // attributes: ["href"], + // decorator: ImageEntity, + // icon: , + // source: ImageSource, + // type: ENTITY_TYPE.IMAGE + // } + ]} + /> +
{helperText && ( undefined} /> + )) + .add("invalid content", () => ( + undefined} + /> )); From 1a843e59bddb79bb99ae286c40992387d1fe5de2 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Mon, 3 Feb 2020 12:20:01 +0100 Subject: [PATCH 2/6] Fix types --- src/components/RichTextEditor/RichTextEditor.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/RichTextEditor/RichTextEditor.tsx b/src/components/RichTextEditor/RichTextEditor.tsx index da092af23..1c6675ba5 100644 --- a/src/components/RichTextEditor/RichTextEditor.tsx +++ b/src/components/RichTextEditor/RichTextEditor.tsx @@ -15,6 +15,7 @@ import React from "react"; import { ChangeEvent } from "@saleor/hooks/useForm"; import ErrorBoundary from "react-error-boundary"; +import { CreateCSSProperties } from "@material-ui/styles/withStyles"; import BoldIcon from "../../icons/BoldIcon"; import HeaderTwo from "../../icons/HeaderTwo"; import HeaderThree from "../../icons/HeaderThree"; @@ -41,7 +42,7 @@ export interface RichTextEditorProps { const useStyles = makeStyles( theme => { - const editorContainer: React.CSSProperties = { + const editorContainer: CreateCSSProperties = { border: `1px ${theme.palette.divider} solid`, borderRadius: 4, padding: "27px 12px 10px", From 914368bfeba0bb23daf8bd60b55ba48f495e2217 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Mon, 3 Feb 2020 12:21:45 +0100 Subject: [PATCH 3/6] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ff0b4714a..c9880230b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,7 @@ All notable, unreleased changes to this project will be documented in this file. - Remove PO files from repo and update translations #409 by @dominik-zeglen - Add optional chaining and explicitely return "Not found" page - #408 by @dominik-zeglen - Do not store errors in form component - #410 by @dominik-zeglen +- Handle rich text editor content error - #395 by @dominik-zeglen ## 2.0.0 From a1353d20b3198ccb2ed7858876d9cc7b987fa67a Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Mon, 3 Feb 2020 12:27:29 +0100 Subject: [PATCH 4/6] Remove story --- .../stories/components/RichTextEditor.tsx | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/storybook/stories/components/RichTextEditor.tsx b/src/storybook/stories/components/RichTextEditor.tsx index 341ba95b8..375129efe 100644 --- a/src/storybook/stories/components/RichTextEditor.tsx +++ b/src/storybook/stories/components/RichTextEditor.tsx @@ -116,20 +116,4 @@ storiesOf("Generics / Rich text editor", module) name="content" onChange={() => undefined} /> - )) - .add("invalid content", () => ( - undefined} - /> )); From 8b0bf50ed481ba2e521507167dd6cc2dbfe7db90 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Wed, 19 Feb 2020 14:54:09 +0100 Subject: [PATCH 5/6] Remove unused code --- src/components/RichTextEditor/RichTextEditor.tsx | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/components/RichTextEditor/RichTextEditor.tsx b/src/components/RichTextEditor/RichTextEditor.tsx index 1c6675ba5..463a9ad40 100644 --- a/src/components/RichTextEditor/RichTextEditor.tsx +++ b/src/components/RichTextEditor/RichTextEditor.tsx @@ -291,13 +291,6 @@ const RichTextEditor: React.FC = props => { source: LinkSource, type: ENTITY_TYPE.LINK } - // { - // attributes: ["href"], - // decorator: ImageEntity, - // icon: , - // source: ImageSource, - // type: ENTITY_TYPE.IMAGE - // } ]} /> From 291dad742aeb6f99e44831012e47b5cda740e905 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Wed, 19 Feb 2020 14:57:37 +0100 Subject: [PATCH 6/6] Update messages --- locale/defaultMessages.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/locale/defaultMessages.json b/locale/defaultMessages.json index 682e22697..d0315fb20 100644 --- a/locale/defaultMessages.json +++ b/locale/defaultMessages.json @@ -1267,6 +1267,10 @@ "context": "button", "string": "Add or Edit Link" }, + "src_dot_components_dot_RichTextEditor_dot_286109898": { + "context": "rich text error", + "string": "Invalid content" + }, "src_dot_components_dot_RichTextEditor_dot_2925475978": { "string": "URL Linked" },