From 5dd1e110b1b1088cd02789a5c56c49cc5c3c6949 Mon Sep 17 00:00:00 2001 From: daishi Date: Sat, 16 May 2020 12:29:01 +0900 Subject: [PATCH] use CKEditor in MomentaryChat --- web/package.json | 12 +++++++++ web/src/components/MomentaryChat.css | 9 ++----- web/src/components/MomentaryChat.tsx | 39 +++++++++++++++++----------- web/src/components/WysiwygEditor.tsx | 25 ++++++++++++++++++ yarn.lock | 31 +++++++++++++++++++++- 5 files changed, 93 insertions(+), 23 deletions(-) create mode 100644 web/src/components/WysiwygEditor.tsx diff --git a/web/package.json b/web/package.json index 10f13959..c9b611f3 100644 --- a/web/package.json +++ b/web/package.json @@ -15,6 +15,9 @@ }, "homepage": "./", "dependencies": { + "@ckeditor/ckeditor5-build-inline": "^19.0.0", + "@ckeditor/ckeditor5-react": "^2.1.0", + "dompurify": "^2.0.11", "emoji-mart": "^3.0.0", "peerjs": "^1.2.0", "react": "^16.13.1", @@ -24,6 +27,7 @@ "@testing-library/jest-dom": "^4.2.4", "@testing-library/react": "^9.3.2", "@testing-library/user-event": "^7.1.2", + "@types/dompurify": "^2.0.2", "@types/emoji-mart": "^2.11.3", "@types/jest": "^25.2.1", "@types/node": "^12.0.0", @@ -106,6 +110,14 @@ "no-use-before-define": "off" } }, + { + "files": [ + "src/components/MomentaryChat.tsx" + ], + "rules": { + "eslint react/no-danger": "off" + } + }, { "files": [ "src/react-app-env.d.ts", diff --git a/web/src/components/MomentaryChat.css b/web/src/components/MomentaryChat.css index b9f84438..70885f18 100644 --- a/web/src/components/MomentaryChat.css +++ b/web/src/components/MomentaryChat.css @@ -7,13 +7,8 @@ grid-template-rows: 1fr 50px; } -.MomentaryChat-message-input-area { - display: flex; -} - -.MomentaryChat-message-input-area input { - flex-grow: 1; - height: 24px; +.MomentaryChat-editor { + border: 1px solid lightgray; } .MomentaryChat-list { diff --git a/web/src/components/MomentaryChat.tsx b/web/src/components/MomentaryChat.tsx index 01ec0e5b..4bc27b05 100644 --- a/web/src/components/MomentaryChat.tsx +++ b/web/src/components/MomentaryChat.tsx @@ -1,12 +1,18 @@ import React, { useState, useRef, useLayoutEffect } from "react"; +import DOMPurify from "dompurify"; import "./MomentaryChat.css"; import { useMomentaryChat, ChatItem } from "../hooks/useMomentaryChat"; import { EmojiPicker } from "../utils/emoji"; +import { WysiwygEditor } from "./WysiwygEditor"; type ChatList = ReturnType["chatList"]; type ReplyChat = ReturnType["replyChat"]; +const sanitize = (text: string) => ({ + __html: DOMPurify.sanitize(text), +}); + const MomentaryChatContentPart = React.memo<{ item: ChatItem; replyChat: ReplyChat; @@ -41,7 +47,7 @@ const MomentaryChatContentPart = React.memo<{ {item.time} -
{item.text}
+
{item.replies.map(([text, count]) => ( -
- +
+ +
+
+ +
); }); diff --git a/web/src/components/WysiwygEditor.tsx b/web/src/components/WysiwygEditor.tsx new file mode 100644 index 00000000..0a789ce7 --- /dev/null +++ b/web/src/components/WysiwygEditor.tsx @@ -0,0 +1,25 @@ +// @ts-nocheck XXX ckeditor5 doesn't come with types + +import React from "react"; +import CKEditor from "@ckeditor/ckeditor5-react"; +import CustomEditor from "@ckeditor/ckeditor5-build-inline"; + +export const WysiwygEditor = React.memo<{ + registerClear: (clear: () => void) => void; + onChange: (data: string) => void; +}>(({ registerClear, onChange }) => { + return ( + { + registerClear(() => { + editor.setData(""); + }); + }} + onChange={(_event, editor) => { + const data = editor.getData(); + onChange(data); + }} + /> + ); +}); diff --git a/yarn.lock b/yarn.lock index 619cf555..9780dea5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -944,6 +944,18 @@ lodash "^4.17.13" to-fast-properties "^2.0.0" +"@ckeditor/ckeditor5-build-inline@^19.0.0": + version "19.0.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-build-inline/-/ckeditor5-build-inline-19.0.0.tgz#419e0c8dc83f0812083f6f7b2ea30a58f5e71388" + integrity sha512-5T2HnomjaguegbetjKguYZZ603HU8uZLIi0DgL+eh02m2NDaYoomGj8SOjvTLihTr380njCaNUulgopEkil32Q== + +"@ckeditor/ckeditor5-react@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-react/-/ckeditor5-react-2.1.0.tgz#f612546a5a328899a436d71b72ffd632600049e8" + integrity sha512-rlHjRKhwP9tNK0Yj2UJShL14mRfxLPgJ+Pv6zTv/Mvmd4wrwGnJf+5ybOAGK92S02hP1cXH+9km+PRO1b4V+ng== + dependencies: + prop-types "^15.6.1" + "@cnakazawa/watch@^1.0.3": version "1.0.4" resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a" @@ -1404,6 +1416,13 @@ resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.5.tgz#b14efa8852b7768d898906613c23f688713e02cd" integrity sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ== +"@types/dompurify@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@types/dompurify/-/dompurify-2.0.2.tgz#94b5c05dc9b8a682a0abb4a8d6f0b82df61baeac" + integrity sha512-WHoQQTziRHm5/Fw/KsUKyh2V+wd3k2QUpJyjUXo8K7d9kMJ5i5wQnGDkO4URkwulhY2HuM/gbX25nSooi6+wUA== + dependencies: + "@types/trusted-types" "*" + "@types/emoji-mart@^2.11.3": version "2.11.3" resolved "https://registry.yarnpkg.com/@types/emoji-mart/-/emoji-mart-2.11.3.tgz#9949f6a8a231aea47aac1b2d4212597b41140b07" @@ -1555,6 +1574,11 @@ "@types/testing-library__dom" "*" pretty-format "^25.1.0" +"@types/trusted-types@*": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-1.0.4.tgz#922d092c84a776a59acb0bd6785fd82b59b9bad5" + integrity sha512-6jtHrHpmiXOXoJ31Cg9R+iEVwuEKPf0XHwFUI93eEPXx492/J2JHyafkleKE2EYzZprayk9FSjTyK1GDqcwDng== + "@types/w3c-image-capture@^1.0.2": version "1.0.2" resolved "https://registry.yarnpkg.com/@types/w3c-image-capture/-/w3c-image-capture-1.0.2.tgz#d80c3db69eacce7de0a7f580d9c7fbed0aabdffa" @@ -4026,6 +4050,11 @@ domhandler@^2.3.0: dependencies: domelementtype "1" +dompurify@^2.0.11: + version "2.0.11" + resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.0.11.tgz#cd47935774230c5e478b183a572e726300b3891d" + integrity sha512-qVoGPjIW9IqxRij7klDQQ2j6nSe4UNWANBhZNLnsS7ScTtLb+3YdxkRY8brNTpkUiTtcXsCJO+jS0UCDfenLuA== + domutils@1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf" @@ -9343,7 +9372,7 @@ prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.4" -prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2: +prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2: version "15.7.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==