annyoung

react ckeditor5 build with craco without eject 본문

프로그래밍

react ckeditor5 build with craco without eject

nopsled 2021. 12. 30. 11:15

베이스 참고: https://velog.io/@kyungjune/react-ckeditor5-%EA%B8%B0%EC%96%B5%ED%95%98%EA%B8%B0#4-2-craco-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0

 

react ckeditor5 기억하기

ckeditor5의 초기설정을 기억하기위한 글이다.ckeditor5에는 커스텀 가능한 기본제공 builds가 있다.(Classic, Balloon, Balloon Block, Inline, Document, Pagination)이중 하나를 선택해서 ckeditor5-r

velog.io

 

나는 여기서 조금 수정해서 사용했다.

import React from "react";
import {createGlobalStyle} from 'styled-components';
import { CKEditor } from "@ckeditor/ckeditor5-react";
import ClassicEditor from "@ckeditor/ckeditor5-editor-classic/src/classiceditor";
import Bold from "@ckeditor/ckeditor5-basic-styles/src/bold.js";
import Essentials from "@ckeditor/ckeditor5-essentials/src/essentials.js";
import Heading from "@ckeditor/ckeditor5-heading/src/heading.js";
import Paragraph from "@ckeditor/ckeditor5-paragraph/src/paragraph.js";
import Italic from "@ckeditor/ckeditor5-basic-styles/src/italic.js";
import Alignment from "@ckeditor/ckeditor5-alignment/src/alignment.js";
import BlockQuote from "@ckeditor/ckeditor5-block-quote/src/blockquote.js";
import Autoformat from "@ckeditor/ckeditor5-autoformat/src/autoformat.js";
import Autosave from "@ckeditor/ckeditor5-autosave/src/autosave.js";
import CKFinder from "@ckeditor/ckeditor5-ckfinder/src/ckfinder.js";
import CKFinderUploadAdapter from "@ckeditor/ckeditor5-adapter-ckfinder/src/uploadadapter.js";
import FontColor from "@ckeditor/ckeditor5-font/src/fontcolor.js";
import FontFamily from "@ckeditor/ckeditor5-font/src/fontfamily.js";
import FontSize from "@ckeditor/ckeditor5-font/src/fontsize.js";
import HorizontalLine from "@ckeditor/ckeditor5-horizontal-line/src/horizontalline.js";
import Image from "@ckeditor/ckeditor5-image/src/image.js";
import ImageCaption from "@ckeditor/ckeditor5-image/src/imagecaption.js";
import ImageResize from "@ckeditor/ckeditor5-image/src/imageresize.js";
import ImageStyle from "@ckeditor/ckeditor5-image/src/imagestyle.js";
import ImageToolbar from "@ckeditor/ckeditor5-image/src/imagetoolbar.js";
import ImageUpload from "@ckeditor/ckeditor5-image/src/imageupload.js";
import Indent from "@ckeditor/ckeditor5-indent/src/indent.js";
import IndentBlock from "@ckeditor/ckeditor5-indent/src/indentblock.js";
import Link from "@ckeditor/ckeditor5-link/src/link.js";
import List from "@ckeditor/ckeditor5-list/src/list.js";
import MediaEmbed from "@ckeditor/ckeditor5-media-embed/src/mediaembed.js";
import PasteFromOffice from "@ckeditor/ckeditor5-paste-from-office/src/pastefromoffice";
import SpecialCharacters from "@ckeditor/ckeditor5-special-characters/src/specialcharacters.js";
import SpecialCharactersEssentials from "@ckeditor/ckeditor5-special-characters/src/specialcharactersessentials.js";
import Strikethrough from "@ckeditor/ckeditor5-basic-styles/src/strikethrough.js";
import Table from "@ckeditor/ckeditor5-table/src/table.js";
import TableToolbar from "@ckeditor/ckeditor5-table/src/tabletoolbar.js";
import TextTransformation from "@ckeditor/ckeditor5-typing/src/texttransformation.js";
import Underline from "@ckeditor/ckeditor5-basic-styles/src/underline.js";
import '@ckeditor/ckeditor5-build-classic/build/translations/ko';
// import Base64UploadAdapter from "@ckeditor/ckeditor5-upload/src/adapters/base64uploadadapter";


const OverrideEditorStyle = createGlobalStyle`
    .ck-editor__editable {
        min-height: ${({height}) => height}px;
    }
`;

class Editor extends React.Component {
    constructor(props) {
        super(props);
        this.state = {

        };
    };

    editorConfiguration = {
        language: 'ko',
        plugins: [
            Alignment,
            Autoformat,
            Autosave,
            BlockQuote,
            Bold,
            CKFinder,
            CKFinderUploadAdapter,
            Essentials,
            FontColor,
            FontFamily,
            FontSize,
            Heading,
            HorizontalLine,
            Image,
            ImageCaption,
            ImageResize,
            ImageStyle,
            // ImageToolbar,
            ImageUpload,
            Indent,
            IndentBlock,
            Italic,
            Link,
            List,
            MediaEmbed,
            Paragraph,
            PasteFromOffice,
            SpecialCharacters,
            SpecialCharactersEssentials,
            Strikethrough,
            Table,
            TableToolbar,
            TextTransformation,
            Underline,
        ],
        toolbar: [
            "heading",
            "|",
            "fontFamily",
            "fontSize",
            "fontColor",
            "alignment",
            "|",
            "bold",
            "italic",
            "strikethrough",
            "underline",
            "specialCharacters",
            "horizontalLine",
            "|",
            "bulletedList",
            "numberedList",
            "|",
            "indent",
            "outdent",
            "|",
            "link",
            "blockQuote",
            // "CKFinder",
            "imageUpload",
            "insertTable",
            "mediaEmbed",
            "|",
            "undo",
            "redo",
        ],
        heading: {
            options: [
                {
                    model: "paragraph",
                    view: "p",
                    title: "본문",
                    class: "ck-heading_paragraph",
                },
                {
                    model: "heading1",
                    view: "h1",
                    title: "헤더1",
                    class: "ck-heading_heading1",
                },
                {
                    model: "heading2",
                    view: "h2",
                    title: "헤더2",
                    class: "ck-heading_heading2",
                },
                {
                    model: "heading3",
                    view: "h3",
                    title: "헤더3",
                    class: "ck-heading_heading3",
                },
            ],
        },
        fontSize: {
            options: [
                10,
                11,
                12,
                13,
                14,
                15,
                16,
                17,
                18,
                19,
                20,
            ],
        },
        alignment: {
            options: ["justify", "left", "center", "right"],
        },
        table: {
            contentToolbar: ["tableColumn", "tableRow", "mergeTableCells"],
        },
        image: {
            resizeUnit: "px",
            toolbar: [
                "imageStyle:alignLeft",
                "imageStyle:full",
                "imageStyle:alignRight",
                "|",
                "imageTextAlternative",
            ],
            styles: ["full", "alignLeft", "alignRight"],
        },
        typing: {
            transformations: {
                remove: [
                    "enDash",
                    "emDash",
                    "oneHalf",
                    "oneThird",
                    "twoThirds",
                    "oneForth",
                    "threeQuarters",
                ],
            },
        },
        placeholder: this.props.placeholder || "입력",
    };

    render() {
        return (
            <>
                <OverrideEditorStyle height={this.props.height}/>
                <CKEditor
                    editor={ ClassicEditor }
                    config={this.editorConfiguration}
                    data={this.props.value || ''}
                    onChange={ ( event, editor ) => {
                        const data = editor.getData();
                        this.props.onChange(event, editor, data);
                    } }
                />
            </>
        );
    }
}

export default Editor;

 

function component로 구성하면 react-query에서 초기값이 초기화 되어 버리는 버그..?가 있다. 그래서 Editor는 React.Component로 사용했다.

 

const initNotificationState = {
    content: '',
}

const Something = () => {
	// states
	const [notificationState, setNotificationState] = useState(initNotificationState);
    
    // apis
    const queryClient = useQueryClient();
    const {isLoading: isLoadingGet, isSuccess: isGetSuccess, data: getData} = useGetSomeHook();
    const {isLoading: isLoadingCreate, isSuccess: isCreateSuccess, data: createData} = useCreateSomeHook();
    
    // effectors
    useEffect(() => {
    	// get data from server and set the state
    	if (isGetSuccess) {
			setNotificationState({
				...getData.data.message,
			});
		}
	}, [isGetSuccess]);
    
    useEffect(() => {
    	// refetch the query when create something
    	if(isCreateSuccess) {
			queryClient.invalidateQueries("someHookKey");
		}
	}, [isCreateSuccess]);
    
    useEffect(() => {
    	// componentWillUnmount
		return () => {
			setNotificationState(initNotificationState);
		}
	}, []);

	// functions
	const handleChange = (name, value) => {
		setNotificationState({
			...notificationState,
			[name]: value,
		});
	}
    
    return (
        <Editor
            height={200}
            onChange={(evt, editor, data) => handleChange("content", data)}
        />
    )
}

export default Something;

Editor 컴포넌트를 사용할땐 저런식으로 사용하고 있다.

 

적용 화면

위 코드 적용해서 사용하면 위처럼 보여진다.

Comments