Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Tiptapで校正機能を作った時に考えたこと
Search
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
kirik
May 26, 2026
Technology
30
0
Share
Tiptapで校正機能を作った時に考えたこと
https://web-study.connpass.com/event/391357/
kirik
May 26, 2026
More Decks by kirik
See All by kirik
Recoil脱却の現状と挑戦
kirik
2
840
Tiptapで実現する堅牢で柔軟なエディター開発
kirik
1
440
Recoilを剥がしている話
kirik
5
12k
Other Decks in Technology
See All in Technology
Orchestration Development Workshopを半期実施して
lycorptech_jp
PRO
0
130
ソフトウェアサプライチェーン攻撃対策として今からサクッとできること
flatt_security
2
110
【2026年版】プロジェクトマネジメント実践論|現役エンジニアが語る!~チームでモノづくりをする時のコツとは?~
mixi_engineers
PRO
1
120
AWS運用におけるAI Agent活用術 / JAWS-UG 神戸 #11 LT大会
genda
1
330
最新技術を"今は選ばない"という技術選定
leveragestech
PRO
0
360
ワールドカフェ再び、そしてゴール・ルール・ロール・ツール / World Café Revisited, and the Goals-Rules-Roles-Tools
ks91
PRO
0
190
Pythonでベイズモデリング
soogie
0
170
GitHub Copilot CLI で考える複数エージェント設計
tomokusaba
0
150
情シスがMCP環境導入時に打ちのめされる認可の崖
oidfj
0
120
Claude Code x Accounting
kawaguti
PRO
0
240
基礎から解説!Icebergで紐解くSnowflake×Databricks連携の現在地
cm_yasuhara
0
110
【新卒研修】ライブデモ + compose.yaml読解_講義資料
dip_tech
PRO
0
130
Featured
See All Featured
The Illustrated Guide to Node.js - THAT Conference 2024
reverentgeek
1
350
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
55
3.3k
Lightning Talk: Beautiful Slides for Beginners
inesmontani
PRO
1
550
How People are Using Generative and Agentic AI to Supercharge Their Products, Projects, Services and Value Streams Today
helenjbeal
1
180
Lightning talk: Run Django tests with GitHub Actions
sabderemane
0
180
A Guide to Academic Writing Using Generative AI - A Workshop
ks91
PRO
1
300
Ethics towards AI in product and experience design
skipperchong
2
280
コードの90%をAIが書く世界で何が待っているのか / What awaits us in a world where 90% of the code is written by AI
rkaga
61
44k
Scaling GitHub
holman
464
140k
Why Our Code Smells
bkeepers
PRO
340
58k
Statistics for Hackers
jakevdp
799
230k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
55k
Transcript
Tiptap で校正機能を作った時に 考えたこと Rich Text Editor Study 2026/5/19 (火) 株式会社PR
TIMES @kiririLee
• 校正機能について • Tiptap について ◦ Tiptap が持つドキュメント構造 • API
レスポンスをHTMLにマッピングする • 校正箇所が重なった場合を表現する • ProseMirror Plugin で細かい挙動を制御する • まとめ
校正機能について
• 2024年9月12日にリリースされた 機能 • プレスリリース入稿時のエディター上 で文章を校正し、誤りを修正できる 機能 • 一般的に校正対象となるようなルー ルとプレスリリースに特化したルー
ルが組まれている https://prtimes.jp/main/html/rd/p/000001456.000000112.html
デモ動画 https://youtu.be/n0jryll2o1o
Tiptap について
• Tiptap は ProseMirror のラッパーであり、内部的には ProseMirror が 独自のツリーを管理している • ProseMirror
は HTML を直接操作するのではなく、独自のドキュメント構 造に落とし込み、エディタ上の状態と合わせて扱う。
Node と Mark このスライドでは ProseMirror が持つドキュメント構造全体を 「ProseMirror Document Model」 と呼ぶようにします。
API レスポンスを HTML にマッピングする
• 文章の校正処理はAPIに投げている。校正結果は JSON であるため、校正箇所を 示す要素を HTML にマッピングする • 校正箇所を示す要素は proofreading
要素を使用している ◦ ブラウザ標準で proofreading 要素はなく、当社で拡張している要素 ※ マッピング処理は Tiptap が関係しない
• parseHTML (と renderHTML) が HTML 構造を ProseMirror の Mark
に変換するための橋渡し になっているメソッド • HTMLドキュメント上の proofreading 要素を Proofreading Mark として紐づけ、その他のプ ロパティやメソッドなどで 振る舞いを実装 proofreading 要素に対してエディターの振る舞いを付与
• Tiptap から提供される Mark.create で特定の HTML 要素を指定して、 ProseMirror Document Model
の一部として読み込む(パースする) • Mark.create の戻り値は Tiptap では Extension という概念で管理される • 校正機能はコードベース上で proofreading 要素をパースして、振る舞いを付与し た Extension を ProofreadingExtension と呼んでいる proofreading 要素に対してエディターの振る舞いを付与
• 最大のポイントは excludes オプションの 設定 • この後のスライドで登場す る要件を実装するのに必 要不可欠
校正箇所が重なった場合を表現する
校正の指摘箇所が重なる場合のデモ https://youtu.be/MMX-cjl8Jxk
校正箇所は重なる場合がある • 指摘箇所がドキュメント上で重なる。これを視覚的にユーザーにフィードバック したい
• proofreading 要素をネストし、CSS で透明度 20% を重ねる
この時の同一要素のネストが excludes で設定出来る • デフォルトの設定だとできない • この設定を見つけるのにかなり時 間がかかった
設定しないとパース時にフラットにノーマライズされる パースされる前 パースされた後
同一要素をネストする設定方法がすぐに分からなかった • 最初は Tiptap のドキュメント を参照したが、空文字の指定で同一要素のネス トができることは書かれていなかった • 実装した当時(2024年6月ごろ)は、ChatGPT に聞いても教えてくれず、
inline 化した Node で実装する方法しか提案されなかった • Tiptap の作者が同一要素のネストを inline化した Node で実装することを 提案していた • PromseMirror のドキュメントには書かれていたが inline化した Node に よる実装に着手してから気がつく
inline node での実装提案 https://github.com/ueberdosis/tiptap/ discussions/2270
開発当初は inline node で実装していた • 開発当初は、Tiptap 作者が同一要素のネスト実装として inline node を提案し
ていたため、それを採用して開発を進めていた • しかし、改行ができないなどテキスト編集機能に制約が多く、不足を補うための複 雑な実装が増加 • その結果、システムテストで多数の不具合が発生し、inline node ベースの実装 には限界があると判断 • 最終的には、excludes: '' を設定した Mark で再実装 「Mark + excludes: ''」 で実装するというのは、 校正機能開発において最も時間を要した設計判断
None
この節のまとめ
ProseMirror Plugin で 細かい挙動を制御する
実装が必要だった要件 • 校正箇所で Backspace キーが押下された場合、該当する校正箇所を 削除する • 校正の指摘が重複している位置で Backspace キーが押下された場
合、重複しているすべての校正箇所を削除する
Mark のデフォルト挙動デモ https://youtu.be/5Ud2BzmHy3M
PM Plugin 実装後の挙動デモ https://youtu.be/ikJTJ5xaMFs
要件に合わせてMark のデフォルト挙動を変える実装をする
実装の概要 • handleKeyDown で Backspace を検知 • ProseMirror のメソッドである tr.removeMark で
Node に付与 されている Proofreading Mark を削除する • 校正の指摘が重複した場合は、親の Proofreading Mark も削除する
handleKeyDown で Backspace を拾う • Proofreading Extension に addProseMirrorPlugins を持たせ、その中で
ProseMirror の Plugin を返 す • Plugin の実装は完全に ProseMirror の世界 • Tiptap 越しではなく、 ProseMirror の API を直接 扱う
ProseMirror 3つの基本概念
Proofreading Mark を外す処理 • Backspace が押されたタイ ミングで、カーソル位置を取 得 • カーソル位置にある
Node を取得 • Node に付与されている Proofreading Mark を外 す
Proofreading Mark を外す処理 • カーソル位置から直接Mark を消すのではなく、 TextNode に付与されてい る Mark
を消す • 取得した TextNode には太 文字や下線など校正以外の別 Mark も同時に付与されてい る可能性があるため、校正の Mark のみ消す
基本的には Proofreading Mark を外す処理はこれでOK。 校正の指摘が重複した場合、 親の Proofreading Mark も 外す必要がある
HTML から見て親の Proofreading Mark も消す必要がある 子の Proofreading Mark は消せた
校正の指摘が重複したことを判定する • 校正の指摘が重複した、という判 定が必要 • この判定は、TextNode に付与 されている Proofreading Mark
が複数あるかどうかで判 定している
校正の指摘が重複したことを判定する https://youtu.be/jhiXM1EpVwY
コンソールに表示される TextNode HTML構造 • 「食べれ」の TextNode に親の id も付与されて いる
• この id を元に親の Mark を消す
校正の指摘が重複した時、 親の Proofreading Mark も外す HTML構造 ProseMirror Document Model
校正の指摘が重複した時、 親の Proofreading Mark も外す • Mark は TextNode に付与
される • ドキュメント上にある「子で取 得した id」 を持つ Mark が 付与されている TextNode をドキュメント上の Node を 走査して全て探す • 探し出した TextNode から Proofreading Mark を外 す
• 隣接する TextNode を取得するメソッドはあるが、2つ以上重複した場合 (可能性は非常に低い) を考えると横方向に全ての Proofreading Mark を辿るのが野暮ったい(コードから何をしているかが分かりにくい) •
ProseMirror Document Model の Mark はフラットな構造であるた め、ネストや親と子というような関係はない • Mark がフラットであるため、ドキュメント上の Node を全て走査する実装 は結構やる事が多い印象 • (他に良い方法があるかも? unsetMark メソッドで対応できないケースを 紹介したいけどまた今度) 校正の指摘が重複した時、 親の Proofreading Mark も外す
まとめ
• 校正箇所に対してエディター上ではテキスト操作がメインにな るため Mark を使う • 同一要素をネストして扱いたい場合には excludes オプ ションに空文字を指定する
• ProseMirror Plugin を使うと Mark のデフォルト挙動 を柔軟に変えられる