Tips & Tricks

Cara Build a Rich Text Editor dengan Claude Code

Pelajari cara build a rich text editor menggunakan Claude Code. Dilengkapi contoh kode praktis dan panduan langkah demi langkah.

pembangunan リッチテキストeditor

リッチテキストeditor CMS、メールpembuatan、dokumenEdit dll.多く aplikasi diperlukan dan されます 、一 dari pembangunan 非常 kompleks.Claude Code 使えば、Tiptap dll. library ベース 、用途 合ったeditor 素早くカスタマイズ bisa dilakukan.

editorpembangunan Tiptapベース

> Tiptap 使ったリッチテキストeditor buatkan.
> 太字、イタリック、リスト、リンク、gambar挿入 support.
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>
  );
}

implementasi toolsバー

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

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

  const addImage = () => {
    const url = window.prompt('gambarURL input');
    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="書式pengaturan">
      <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="リンクpenambahan" active={editor.isActive('link')}>🔗</ToolButton>
      <ToolButton onClick={addImage} label="gambarpenambahan">📷</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>
  );
}

pembuatan カスタムエクステンション

> メンション機能(@pengguna名) エクステンション buatkan.
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(),
      }),
    ];
  },
});

サニタイズ konten

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'],
  });
}

Summary

Untuk Claude Codeを使えば、Tiptapをベースとしたリッチテキストeditorのpembangunanから、カスタムエクステンションpengembangan、セキュアなkontenmanajemenまでefisienにimplementasiできます。form設計についてはformvalidasiを、マークダウンpemrosesan, lihat Markdown処理の記事.

Tiptap 詳細 Tiptap公式dokumen silakan lihat.

#Claude Code #リッチテキストeditor #React #Tiptap #kontenmanajemen