From dd22f2b7ee0c59a42a2e235c7c8d8ca16cac06c8 Mon Sep 17 00:00:00 2001 From: haksoo Date: Mon, 16 Dec 2024 16:49:01 +0900 Subject: [PATCH 1/4] =?UTF-8?q?=F0=9F=93=A6=20react-quill-new=20=ED=8C=A8?= =?UTF-8?q?=ED=82=A4=EC=A7=80=20=EC=84=A4=EC=B9=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 84 +++++++++++++++++++++++++++++++++++++++++++++-- package.json | 3 +- 2 files changed, 84 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 765a356..c55d131 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,8 @@ "next": "^15.1.0", "postcss-nesting": "^13.0.1", "react": "^19.0.0", - "react-dom": "^19.0.0" + "react-dom": "^19.0.0", + "react-quill-new": "^3.3.3" }, "devDependencies": { "@eslint/eslintrc": "^3.2.0", @@ -2897,6 +2898,12 @@ "node": ">=0.10.0" } }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "license": "MIT" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -2908,7 +2915,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", - "dev": true, "license": "Apache-2.0" }, "node_modules/fast-glob": { @@ -4091,6 +4097,30 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "license": "MIT" + }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", + "license": "MIT" + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", + "license": "MIT" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -4543,6 +4573,12 @@ "dev": true, "license": "BlueOak-1.0.0" }, + "node_modules/parchment": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/parchment/-/parchment-3.0.0.tgz", + "integrity": "sha512-HUrJFQ/StvgmXRcQ1ftY6VEZUq3jA2t9ncFN4F84J/vN0/FPpQF+8FKXb3l6fLces6q0uOHj6NJn+2xvZnxO6A==", + "license": "BSD-3-Clause" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -5047,6 +5083,35 @@ ], "license": "MIT" }, + "node_modules/quill": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/quill/-/quill-2.0.3.tgz", + "integrity": "sha512-xEYQBqfYx/sfb33VJiKnSJp8ehloavImQ2A6564GAbqG55PGw1dAWUn1MUbQB62t0azawUS2CZZhWCjO8gRvTw==", + "license": "BSD-3-Clause", + "dependencies": { + "eventemitter3": "^5.0.1", + "lodash-es": "^4.17.21", + "parchment": "^3.0.0", + "quill-delta": "^5.1.0" + }, + "engines": { + "npm": ">=8.2.3" + } + }, + "node_modules/quill-delta": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/quill-delta/-/quill-delta-5.1.0.tgz", + "integrity": "sha512-X74oCeRI4/p0ucjb5Ma8adTXd9Scumz367kkMK5V/IatcX6A0vlgLgKbzXWy5nZmCGeNJm2oQX0d2Eqj+ZIlCA==", + "license": "MIT", + "dependencies": { + "fast-diff": "^1.3.0", + "lodash.clonedeep": "^4.5.0", + "lodash.isequal": "^4.5.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, "node_modules/react": { "version": "19.0.0", "resolved": "https://registry.npmjs.org/react/-/react-19.0.0.tgz", @@ -5075,6 +5140,21 @@ "dev": true, "license": "MIT" }, + "node_modules/react-quill-new": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/react-quill-new/-/react-quill-new-3.3.3.tgz", + "integrity": "sha512-jxbm1QUJlkuGUpc9/GUgGw5USLHdp43H0M7AufqS3V+zRLng9uqLeVBGjXYqEbUKi8QVOM4SClSV3F7kVNj68w==", + "license": "MIT", + "dependencies": { + "lodash": "^4.17.21", + "quill": "~2.0.2" + }, + "peerDependencies": { + "quill-delta": "^5.1.0", + "react": "^16 || ^17 || ^18 || ^19", + "react-dom": "^16 || ^17 || ^18 || ^19" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", diff --git a/package.json b/package.json index 0019e92..b853582 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,8 @@ "next": "^15.1.0", "postcss-nesting": "^13.0.1", "react": "^19.0.0", - "react-dom": "^19.0.0" + "react-dom": "^19.0.0", + "react-quill-new": "^3.3.3" }, "devDependencies": { "@eslint/eslintrc": "^3.2.0", From d70fa96a33ce036dc58140766dbf517e9fffb12f Mon Sep 17 00:00:00 2001 From: haksoo Date: Mon, 16 Dec 2024 16:50:54 +0900 Subject: [PATCH 2/4] =?UTF-8?q?=E2=9C=A8=20TextEditor=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=20=EC=B6=94=EA=B0=80,=20editor=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/TextEditor.tsx | 50 +++++++++++++++++++++++++++++++++++++ pages/test/editor.tsx | 52 +++++++++++++++++++++++++++++++++++++++ styles/globals.css | 33 +++++++++++++++++++++++++ 3 files changed, 135 insertions(+) create mode 100644 components/TextEditor.tsx create mode 100644 pages/test/editor.tsx diff --git a/components/TextEditor.tsx b/components/TextEditor.tsx new file mode 100644 index 0000000..cff4d89 --- /dev/null +++ b/components/TextEditor.tsx @@ -0,0 +1,50 @@ +import dynamic from 'next/dynamic'; + +import 'react-quill-new/dist/quill.snow.css'; + +// ref: https://www.npmjs.com/package/react-quill-new +const QuillEditor = dynamic(() => import('react-quill-new'), { + ssr: false, + loading: () =>

편집기 불러오는 중...

, +}); + +interface Props { + value?: string; + onChange: (value: string) => void; +} + +/** + * 텍스트 에디터 컴포넌트 + * @param {object} props + * @param {string} props.value - 초기 값 + * @param {function} props.onChange - 값 변경시 콜백 함수 + * @returns {JSX.Element} + */ +export default function TextEditor({ value = '', onChange }: Props) { + const modules = { + toolbar: { + container: [ + [{ header: [1, 2, 3, false] }], + ['bold', 'italic', 'underline'], + [{ align: null }, { align: 'center' }, { align: 'right' }], + [{ list: 'ordered' }, { list: 'bullet' }], + ['blockquote', 'link', 'image'], + ], + }, + }; + + const handleChange = (value: string) => { + onChange(value); + }; + + return ( + + ); +} diff --git a/pages/test/editor.tsx b/pages/test/editor.tsx new file mode 100644 index 0000000..f89958c --- /dev/null +++ b/pages/test/editor.tsx @@ -0,0 +1,52 @@ +import { useState } from 'react'; + +import TextEditor from '@/components/TextEditor'; + +const cellStyle = 'px-4 py-2'; +const trStyle = 'border-b'; + +export default function Editor() { + const [value, setValue] = useState(''); + + const handleChange = (v: string) => { + console.log('value', v); + setValue(v); + }; + + return ( +
+ + + + + + + + + + + + + +
+ props + + example +
+
    +
  • value: string
  • +
  • onChange: (value: string) => void
  • +
+
+
+ +
+
+

+ 참고: 에디터의 크기는 에디터 부모의 100%가 적용되니 부모의 + 크기를 정의하시면 됩니다. +

+
+
+ ); +} diff --git a/styles/globals.css b/styles/globals.css index 5a6ef0a..b3d8f34 100644 --- a/styles/globals.css +++ b/styles/globals.css @@ -51,3 +51,36 @@ body { color: var(--gray-500); background: var(--background); } + +/* quill editor custom style */ +.quill-custom { + @apply grid h-full w-full; + grid-template-rows: 1fr max-content; + + .ql-editor { + @apply p-0; + } + .ql-editor.ql-blank::before { + @apply left-0 not-italic text-gray-400; + } + .ql-container { + @apply overflow-auto font-sans text-16; + } + .ql-container.ql-snow { + @apply border-0; + } + .ql-toolbar.ql-snow { + @apply order-last rounded-full border-gray-200 text-gray-400; + } + .ql-snow .ql-stroke { + stroke: var(--gray-400); + } + .ql-snow .ql-fill, + .ql-snow .ql-stroke.ql-fill { + fill: var(--gray-400); + } + .ql-snow .ql-picker.ql-header .ql-picker-label::before, + .ql-snow .ql-picker.ql-header .ql-picker-item::before { + color: var(--gray-400); + } +} From 7bd821f5ae77f352a814aab8d053390b41a6b727 Mon Sep 17 00:00:00 2001 From: haksoo Date: Mon, 16 Dec 2024 17:08:57 +0900 Subject: [PATCH 3/4] =?UTF-8?q?=F0=9F=94=A8=20=EC=97=90=EB=94=94=ED=84=B0?= =?UTF-8?q?=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=ED=8E=98=EC=9D=B4=EC=A7=80=20?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/test/editor.tsx | 2 +- styles/globals.css | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pages/test/editor.tsx b/pages/test/editor.tsx index f89958c..63064b8 100644 --- a/pages/test/editor.tsx +++ b/pages/test/editor.tsx @@ -9,7 +9,7 @@ export default function Editor() { const [value, setValue] = useState(''); const handleChange = (v: string) => { - console.log('value', v); + // console.log('value', v); setValue(v); }; diff --git a/styles/globals.css b/styles/globals.css index b3d8f34..647f854 100644 --- a/styles/globals.css +++ b/styles/globals.css @@ -64,7 +64,7 @@ body { @apply left-0 not-italic text-gray-400; } .ql-container { - @apply overflow-auto font-sans text-16; + @apply overflow-y-auto font-sans text-16; } .ql-container.ql-snow { @apply border-0; From 05fd75f52afbf5bed809cb6ecf3f2d84eb4bd28f Mon Sep 17 00:00:00 2001 From: haksoo Date: Mon, 16 Dec 2024 20:29:07 +0900 Subject: [PATCH 4/4] =?UTF-8?q?=F0=9F=90=9B=20=20jsDoc=20return=20?= =?UTF-8?q?=EB=B6=80=EB=B6=84=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/TextEditor.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/components/TextEditor.tsx b/components/TextEditor.tsx index cff4d89..d3e0be7 100644 --- a/components/TextEditor.tsx +++ b/components/TextEditor.tsx @@ -18,7 +18,6 @@ interface Props { * @param {object} props * @param {string} props.value - 초기 값 * @param {function} props.onChange - 값 변경시 콜백 함수 - * @returns {JSX.Element} */ export default function TextEditor({ value = '', onChange }: Props) { const modules = {