Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Tiptapで校正機能を作った時に考えたこと
Search
kirik
May 26, 2026
Technology
99
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Tiptapで校正機能を作った時に考えたこと
https://web-study.connpass.com/event/391357/
kirik
May 26, 2026
More Decks by kirik
See All by kirik
Recoil脱却の現状と挑戦
kirik
2
930
Tiptapで実現する堅牢で柔軟なエディター開発
kirik
1
500
Recoilを剥がしている話
kirik
5
12k
Other Decks in Technology
See All in Technology
株式会社シーエーシー エンジニア向け会社紹介資料
cac
0
57k
おい、エージェントを使って終わらせろ
nwiizo
1
610
安心して変更できるWebフロントエンドの作り方
pirosikick
5
2.7k
HHKBエバンジェリストになる方法
941
0
110
Azure Serverless 2026:Production-ready な AI エージェント基盤 / Azure Serverless 2026: Production-Ready AI Agent Platform
miyake
2
160
品質と信頼性を地続きにする
grimoh
0
640
Minecraft JavaのMODをSwiftで作る
1mash0
0
170
[2026-09-11]SREは誰のもの?運用エンジニアが始める 「SRE領域への越境」とチームの進化の軌跡 〜Road to NEXT CRE
tosite
0
290
Slack上でインフラをトラブルシュートする! Agentic Platform Engineeringの第一歩
teru0x1
5
1.8k
越境するなら専門用語を使うな高校校歌 / If you wanna cross border, you shouldn't use jargon
vtryo
0
140
アクセスキーこわい やめかたと漏らさない工夫
sassssan68
1
350
OpenTelemetryのメトリクスをCloudWatchに送ってPromQLで見てみた
ota1022
0
150
Featured
See All Featured
How to Think Like a Performance Engineer
csswizardry
28
2.8k
Fireside Chat
paigeccino
43
4k
Effective software design: The role of men in debugging patriarchy in IT @ Voxxed Days AMS
baasie
1
530
The Curious Case for Waylosing
cassininazir
1
510
The Mindset for Success: Future Career Progression
greggifford
PRO
0
500
Future Trends and Review - Lecture 12 - Web Technologies (1019888BNR)
signer
PRO
0
3.7k
Imperfection Machines: The Place of Print at Facebook
scottboms
270
14k
Navigating Team Friction
lara
192
16k
Automating Front-end Workflow
addyosmani
1369
210k
Side Projects
sachag
456
43k
Building Applications with DynamoDB
mza
96
7.2k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
32
4.8k
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 のデフォルト挙動 を柔軟に変えられる