Darginec05 / Yoopta-Editor

Build Notion-like, Craft-like, Coda-like, Medium-like editors with Yoopta
https://yoopta.dev/
MIT License
1.43k stars 111 forks source link

[BUG] Attempted import error: 'deserializeHTML' is not exported from '@yoopta/editor' #397

Open nugmubs opened 20 hours ago

nugmubs commented 20 hours ago

Has this bug been raised before?

Description

An unusual error has occurred. I cannot determine the cause. I cannot find any related errors.

Import trace for requested module:
./node_modules/@yoopta/exports/dist/index.js
./src/components/PostEditor.tsx
./src/app/write/page.tsx
 ⨯ ./node_modules/@yoopta/exports/dist/index.js
Attempted import error: 'deserializeHTML' is not exported from '@yoopta/editor' (imported as 'e').

Import trace for requested module:
./node_modules/@yoopta/exports/dist/index.js
./src/components/PostEditor.tsx
./src/app/write/page.tsx

This is my source code.

// 'use client';
import { useEffect, useMemo, useRef, useCallback } from 'react';
import YooptaEditor, { createYooptaEditor, YooEditor } from "@yoopta/editor";
import { markdown as markdownParser } from '@yoopta/exports';
import Paragraph from "@yoopta/paragraph";
import Blockquote from '@yoopta/blockquote';
import LinkTool, { DefaultLinkToolRender } from '@yoopta/link-tool';
import ActionMenuList, { DefaultActionMenuRender } from '@yoopta/action-menu-list';
import Toolbar, { DefaultToolbarRender } from '@yoopta/toolbar';
import { Bold, Italic, CodeMark, Underline, Strike, Highlight } from '@yoopta/marks';
import { HeadingOne, HeadingThree, HeadingTwo } from '@yoopta/headings';
import Embed from '@yoopta/embed';
import Image from '@yoopta/image';
import Link from '@yoopta/link';
import Callout from '@yoopta/callout';
import Video from '@yoopta/video';
import File from '@yoopta/file';
import Code from '@yoopta/code';
import Table from '@yoopta/table';
import Divider from '@yoopta/divider';
import { NumberedList, BulletedList, TodoList } from '@yoopta/lists';
import { INITIAL_VALUE } from './initValue2';
import { uploadToCloudinary } from '@/lib/cloudinary';

const MARKS = [Bold, Italic, CodeMark, Underline, Strike, Highlight];

const TOOLS = {
  ActionMenu: {
    render: DefaultActionMenuRender,
    tool: ActionMenuList,
  },
  Toolbar: {
    render: DefaultToolbarRender,
    tool: Toolbar,
  },
  LinkTool: {
    render: DefaultLinkToolRender,
    tool: LinkTool,
  },
};

const plugins = [
    Paragraph, 
    Blockquote, 
    HeadingOne, 
    HeadingTwo, 
    HeadingThree,
    Callout,
    NumberedList,
    BulletedList,
    TodoList,
    Code,
    Link,
    Embed,
    Table,
    Divider,
    Image.extend({
      options: {
        async onUpload(file) {
          const data = await uploadToCloudinary(file, 'image');

          return {
            src: data.secure_url,
            alt: 'cloudinary',
            sizes: {
              width: data.width,
              height: data.height,
            },
          };
        },
      },
    }),
    Video.extend({
      options: {
        onUpload: async (file) => {
          const data = await uploadToCloudinary(file, 'video');
          return {
            src: data.secure_url,
            alt: 'cloudinary',
            sizes: {
              width: data.width,
              height: data.height,
            },
          };
        },
        onUploadPoster: async (file) => {
          const image = await uploadToCloudinary(file, 'image');
          return image.secure_url;
        },
      },
    }),
    File.extend({
      options: {
        onUpload: async (file) => {
          const response = await uploadToCloudinary(file, 'auto');
          return { src: response.secure_url, format: response.format, name: response.name, size: response.bytes };
        },
      },
    }),
];

interface PostEditorProps {
  onChange: (value: string) => void;
  initialContent?: Record<string, unknown>;  // JSON 객체 타입으로 변경
}

const PostEditor = ({ onChange, initialContent }: PostEditorProps) => {
  const editor: YooEditor = useMemo(() => createYooptaEditor(), []);
  const selectionRef = useRef(null);

  // 에디터 내용 저장 함수
  const saveContent = useCallback(() => {
    const markdownContent = markdownParser.serialize(editor, editor.getEditorValue());
    onChange(markdownContent);
  }, [editor, onChange]);

  // 자동 저장 설정
  useEffect(() => {
    const intervalId = setInterval(saveContent, 5000);
    return () => clearInterval(intervalId);
  }, [saveContent]);

  // 단축키 저장 설정
  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      if ((e.ctrlKey || e.metaKey) && e.key === 's') {
        e.preventDefault();
        saveContent();
      }
    };

    document.addEventListener('keydown', handleKeyDown);
    return () => document.removeEventListener('keydown', handleKeyDown);
  }, [saveContent]);

  return (
    <div 
    id="editor"
    className="md:py-[100px] md:pl-[200px] md:pr-[80px] px-[20px] pt-[80px] pb-[40px] flex justify-center flex-col items-center"
    ref={selectionRef}
    >
    <YooptaEditor
      editor={editor}
      plugins={plugins}
      placeholder="명령을 실행하려면 '/' 를 입력하세요."
      selectionBoxRoot={selectionRef}
      tools={TOOLS}
      marks={MARKS}
      autoFocus
      value={INITIAL_VALUE}
      style={{ width: '100%', height: '100%' }}
    />
    </div>
  );
};

export default PostEditor;

Screenshots

image

image

Do you want to work on this issue?

Yes

nugmubs commented 20 hours ago

The very interesting point is that the error does not occur when not using the markdown from @editor/exports.

I have commented it out as shown in the image below.

image