Skip to content

クイックメモ: 本文を全消しした後もEnterで改行できるようにする - #12

Merged
MotimotiNotch merged 1 commit into
mainfrom
fix/issue-11-note-editor-recovery
Sep 12, 2026
Merged

MotimotiNotch merged 1 commit into
mainfrom
fix/issue-11-note-editor-recovery

Conversation

@MotimotiNotch

Copy link
Copy Markdown
Owner

Fixes #11

症状

メモ(クイックメモ/Chain Viewの詳細パネル/Noteページ)で、本文を全部消した直後に文字を打つとEnterを押しても改行できない。一度カーソルを外すと改行できるようになるが、消したはずの本文が丸ごと復活し、直前に打った文字は消える

原因

ts/web/notemd.tscreateLiveEditor。DOMを書くのは render() だけ、読み戻すのは syncActiveLineText() が見る1要素([data-line="${activeLine}"])だけで、input を購読していなかった。ブラウザ任せの編集のうち構造を変えるもの(全選択削除・複数行にまたがる削除・貼り付け・ドラッグ)を通ると、内部の lines が既に存在しないDOMを指したままになる。

全消しが最悪のケースで、Chromeは [data-line] のラッパごと削除する(2回目のBackspaceでcontainerが空になることを実機で確認)。次に打った文字はcontainer直下の裸のテキストノードになり、currentLineAndCol() がnullを返す。Enter分岐は e.preventDefault()先に呼んでから if (!pos) return; するため、既定の改行も自前の改行も走らず無言で何も起きない。blurで直るのは focusoutrender() がラッパを作り直すからで、描画元が古い lines なので本文が復活していた。

直し方

input を購読し、[data-line] の数が lines.length と合わない/activeLine の要素が消えているときだけ、現在のDOMから linesactiveLine・キャレットを組み直して描き直す。1行の中で打っているだけの通常入力では何もしないので、IMEやキャレットの挙動は従来のまま。変換で選択範囲を置き換えた場合は isComposing 中の input を素通りさせているので compositionend 側で拾う。Enter分岐の先頭にも同じ修復を入れ、preventDefault() 後の無言no-opを無くした。

復元時、無傷で残っている行は lines 側の生テキストを採る(表示文字列から逆算すると - [x] foofoo に、**a**a に潰れるため)。中身を削られた行は残っているクラスから記法の頭を組み直す(そのままだと箇条書きの が本文に混ざる)。中身が空になった行は空行として返す。

確認

  • typecheck clean / 104 tests green
  • Chromeの実機で、クイックメモ・Chain Viewの詳細パネル・Noteページの3箇所すべてで再現手順が通ることを確認
  • のっちの実機UXチェック済み

renderNoteMd を使うCollections/Loadoutsのメモ欄は表示専用で、この変更の影響を受けない。

🤖 Generated with Claude Code

https://claude.ai/code/session_01GK23a3A9J1eeGHFKaYgpga

ライブエディタはDOMをrender()でしか書かず、読み戻すのはsyncActiveLineTextが
見る1要素([data-line=activeLine])だけだったため、ブラウザ任せの編集のうち
構造を変えるもの(全選択削除・複数行にまたがる削除・貼り付け・ドラッグ)を
通ると内部のlinesが既に存在しないDOMを指したままになっていた。

全消しが最悪のケースで、Chromeは[data-line]のラッパごと削除する。次に打った
文字はcontainer直下の裸のテキストノードになり、currentLineAndCol()が祖先を
見つけられずnullを返す。Enter分岐はpreventDefault()を先に呼んでからreturnする
ので、既定の改行も自前の改行も走らず無言で何も起きなかった。blurで直るのは
focusoutのrender()がラッパを作り直すからで、同時に古いlinesから消したはずの
本文が復活していた。

inputを購読し、[data-line]の数がlinesと合わない/activeLineの要素が消えている
ときだけ、現在のDOMからlines・activeLine・キャレットを組み直して描き直す。
通常の1行内の入力では何もしないのでIMEやキャレットの挙動は従来のまま。変換で
選択範囲を置き換えた場合はisComposing中にinputを素通りさせているため、
compositionend側で拾う。Enter分岐の先頭にも同じ修復を入れ、preventDefault後の
無言no-opを無くした。

復元時、無傷で残っている行はlines側の生テキストを採る(表示文字列から逆算すると
"- [x] foo"が"foo"に、"**a**"が"a"に潰れるため)。中身を削られた行は残っている
クラスから記法の頭を組み直す(そのままだと箇条書きの"•"が本文に混ざる)。

Fixes #11

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GK23a3A9J1eeGHFKaYgpga
@MotimotiNotch
MotimotiNotch merged commit 192e14c into main Sep 12, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

クイックメモ: 本文を全消しした直後にEnterで改行できず、blurすると消した本文が復活する

1 participant