Tips & Tricks

如何Build a Rich Text Editor:Claude Code 实战指南

学习如何build a rich text editor:Claude Code 实战. 包含实用代码示例和分步指导。

リッチテキストエディタの构建

リッチテキストエディタはCMS、メール创建、文档Editなど多くの应用で必要とされますが、一から构建するのは非常に很复杂。借助 Claude Code,Tiptapなどの库をベースに、用途に合ったエディタを快速自定义可以。

Tiptapベースのエディタ构建

> Tiptap使用...的リッチテキストエディタを作って。
> 太字、イタリック、列表、リンク、图片挿入に支持して。
import { useEditor, EditorContent } from '@tiptap/react';
import StarterKit from '@tiptap/starter-kit';
import Link from '@tiptap/extension-link';
import Image from '@tiptap/extension-image';

function RichTextEditor({ content, onChange }: { content: string; onChange: (html: string) => void }) {
  const editor = useEditor({
    extensions: [
      StarterKit,
      Link.configure({ openOnClick: false }),
      Image.configure({ inline: true }),
    ],
    content,
    onUpdate: ({ editor }) => {
      onChange(editor.getHTML());
    },
  });

  if (!editor) return null;

  return (
    <div className="border rounded-lg overflow-hidden">
      <Toolbar editor={editor} />
      <EditorContent editor={editor} className="prose max-w-none p-4 min-h-[200px]" />
    </div>
  );
}

ツールバーの实现

import { Editor } from '@tiptap/react';

function Toolbar({ editor }: { editor: Editor }) {
  const addLink = () => {
    const url = window.prompt('URLを入力');
    if (url) editor.chain().focus().setLink({ href: url }).run();
  };

  const addImage = () => {
    const url = window.prompt('画像URLを入力');
    if (url) editor.chain().focus().setImage({ src: url }).run();
  };

  return (
    <div className="flex gap-1 p-2 border-b bg-gray-50" role="toolbar" aria-label="書式設定">
      <ToolButton
        active={editor.isActive('bold')}
        onClick={() => editor.chain().focus().toggleBold().run()}
        label="太字"
      >B</ToolButton>
      <ToolButton
        active={editor.isActive('italic')}
        onClick={() => editor.chain().focus().toggleItalic().run()}
        label="斜体"
      >I</ToolButton>
      <ToolButton
        active={editor.isActive('bulletList')}
        onClick={() => editor.chain().focus().toggleBulletList().run()}
        label="箇条書き"
      >•</ToolButton>
      <ToolButton
        active={editor.isActive('orderedList')}
        onClick={() => editor.chain().focus().toggleOrderedList().run()}
        label="番号付きリスト"
      >1.</ToolButton>
      <ToolButton onClick={addLink} label="リンク追加" active={editor.isActive('link')}>🔗</ToolButton>
      <ToolButton onClick={addImage} label="画像追加">📷</ToolButton>
    </div>
  );
}

function ToolButton({ active, onClick, label, children }: {
  active?: boolean; onClick: () => void; label: string; children: React.ReactNode;
}) {
  return (
    <button
      type="button"
      onClick={onClick}
      aria-label={label}
      aria-pressed={active}
      className={`px-3 py-1 rounded text-sm font-medium ${
        active ? 'bg-blue-100 text-blue-700' : 'hover:bg-gray-200'
      }`}
    >{children}</button>
  );
}

カスタム扩展の创建

> メンション機能(@用户名)の扩展を作って。
import { Node, mergeAttributes } from '@tiptap/core';
import Suggestion from '@tiptap/suggestion';

const Mention = Node.create({
  name: 'mention',
  group: 'inline',
  inline: true,
  selectable: false,
  atom: true,

  addAttributes() {
    return {
      id: { default: null },
      label: { default: null },
    };
  },

  parseHTML() {
    return [{ tag: 'span[data-mention]' }];
  },

  renderHTML({ node, HTMLAttributes }) {
    return ['span', mergeAttributes(HTMLAttributes, {
      'data-mention': '',
      class: 'mention bg-blue-100 text-blue-700 rounded px-1',
    }), `@${node.attrs.label}`];
  },

  addProseMirrorPlugins() {
    return [
      Suggestion({
        editor: this.editor,
        char: '@',
        items: ({ query }) => fetchUsers(query),
        render: () => createSuggestionRenderer(),
      }),
    ];
  },
});

内容のサニタイズ

import DOMPurify from 'dompurify';

function sanitizeContent(html: string): string {
  return DOMPurify.sanitize(html, {
    ALLOWED_TAGS: ['p', 'br', 'strong', 'em', 'ul', 'ol', 'li', 'a', 'img', 'h1', 'h2', 'h3', 'blockquote', 'code', 'pre'],
    ALLOWED_ATTR: ['href', 'src', 'alt', 'class', 'target', 'rel'],
  });
}

总结

借助 Claude Code,Tiptapをベースとしたリッチテキストエディタの构建から、カスタム扩展开发、セキュアな内容管理まで高效地实现可以。表单设计相关内容请参阅表单验证を、Markdown処理はMarkdown処理の文章

Tiptap的详细信息请参阅Tiptap官方文档

#Claude Code #リッチテキストエディタ #React #Tiptap #コンテンツ管理