Editor.tsx 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. 'use client';
  2. /**
  3. * @author: Kim Jino
  4. * @since: 2025.03.31
  5. * @description: CKEditor component for Next.js using Script component for loading CKEditor script
  6. */
  7. import '@/styles/editor.scss';
  8. import Script from 'next/script';
  9. import React, { useRef, useState, useEffect, useCallback, useMemo } from 'react';
  10. import { CKEditor } from '@ckeditor/ckeditor5-react';
  11. import type { Editor as CKEditorInstance } from 'ckeditor5';
  12. import Loading from '@/app/component/Loading';
  13. interface EditorProps {
  14. data?: string;
  15. onChange?: (data: string) => void;
  16. }
  17. export default function Editor({ data = '', onChange }: EditorProps)
  18. {
  19. const editorRef = useRef<typeof window.Editor|null>(null);
  20. const [ready, setReady] = useState(false);
  21. useEffect(() => {
  22. if (typeof window !== 'undefined' && window.Editor) {
  23. editorRef.current = window.Editor;
  24. setReady(true);
  25. }
  26. }, []);
  27. const handleScriptLoad = () => {
  28. if (typeof window !== 'undefined' && window.Editor) {
  29. editorRef.current = window.Editor;
  30. setReady(true);
  31. } else {
  32. console.error('CKEditor script not loaded properly.');
  33. }
  34. };
  35. const editorConfig = useMemo(() => ({
  36. placeholder: '내용을 입력하세요.',
  37. maxWordCount: 3000,
  38. // 이미지 설정
  39. allowImage: true,
  40. imageUploadLimit: 1,
  41. imageUploadMaxSize: 5120,
  42. // 미디어어 설정
  43. allowMedia: true,
  44. mediaUploadLimit: 1
  45. }), []);
  46. const handleReady = useCallback((editor: CKEditorInstance) => {
  47. console.log('Editor was initialized');
  48. // 최소 높이 설정
  49. editor.editing.view.change(writer => {
  50. const root = editor.editing.view.document.getRoot();
  51. if (root) {
  52. writer.setStyle('min-height', '300px', root);
  53. }
  54. });
  55. }, []);
  56. const handleChange = useCallback((_: unknown, editor: CKEditorInstance) => {
  57. onChange?.(editor.getData());
  58. }, [onChange]);
  59. return (
  60. <>
  61. <Script src="/editor/editor.min.js" strategy="afterInteractive" onLoad={handleScriptLoad}/>
  62. {ready && editorRef.current ? (
  63. <CKEditor
  64. editor={editorRef.current}
  65. data={data}
  66. config={editorConfig}
  67. onReady={handleReady}
  68. onChange={handleChange}
  69. />
  70. ) : (
  71. <Loading/>
  72. )}
  73. </>
  74. );
  75. }