Skip to content

feat(toolify): 全ツールで結果 permalink を有効化 (7/223 → 223/223) - #5

Merged
appdevelopsk merged 1 commit into
mainfrom
audit/2026-09-07
Sep 9, 2026
Merged

feat(toolify): 全ツールで結果 permalink を有効化 (7/223 → 223/223)#5
appdevelopsk merged 1 commit into
mainfrom
audit/2026-09-07

Conversation

@appdevelopsk

Copy link
Copy Markdown
Owner

目的

日次監査 2026-09-09 の Toolify365「High/S Result share/permalink」への対応。
結果共有リンク (?s=) の対応を 7/223 本 → 全 223 本 に広げる。

なぜ DOM 総なめ方式か

既存の useShareableState(slug, value, restore) をツール側が手書きする契約で、
223 本中 7 本しか採用されていない。残り 216 本に個別の restore コールバックを
書くのは非現実的で、実装差異による取りこぼしも避けられない。

入力の実体はどれも DOM 上の input / select / textarea なので、既存の
ToolInteractionTracker と同じく バブリングを 1 箇所で拾う 方が網羅的。
ShareBar は既に ?s= を監視してボタンを出し分けているため無変更で追従する。

設計上の要点

  • 構造キー (${type}${同種内連番}) — 素の通し番号だと、mode で表示本数が
    変わるツール 35 本で復元先が 1 つずれ、別の欄に値が入る。
  • 2 パス復元 — select / radio / モードボタンを先に当て、requestAnimationFrame
    で現れた欄を埋める。1 パスだと「sss の共有リンクを right の初期表示に流し込む」ことになる。
  • ネイティブ setter — React 19 の制御コンポーネントは el.value 直接代入を
    無視する (value tracker が「変化なし」と判断し onChange が出ない)。
  • button 式モード — 選択中 (bg-brand-600) の index を b キーで保存し、
    復元時に click し直す。規約が当てはまらないツールでは b が空になり、
    従来通り入力値だけが復元される (壊れるのではなく共有範囲が狭まるだけ)。
  • history.replaceState を使うので「戻る」は壊れない。値は端末を離れず、
    URL に載るのはユーザーが自分で共有した時だけ。

自前実装の 7 本は MANUAL_SHARE_SLUGS で除外し ?s= の二重書き込みを防ぐ。
リストが腐らないよう、実際に useShareableState を import しているツールと
一致することをテストで固定した。

変更

site/src/lib/hooks/useAutoShareableState.ts
site/src/lib/tools/manual-share.ts
site/src/lib/tools/manual-share.test.ts
site/src/components/tools/ToolInteractionTracker.tsx (shareable prop)
site/src/components/tools/ToolFrame.tsx (除外リストを渡す)

検証

  • tsc --noEmit clean
  • vitest 26/26
  • CDP e2e 10/10 (button 式モードの b 往復を含む)
  • ランダム 30 本スイープ実質全通

スイープで残った不一致はいずれもハーネス側の欠陥で、hook の欠陥ではない:
ohm-law-calculator は V=I×R による再計算 (正常動作)、hcg-calculator
datetime-local に素の数値を書いていた、html-entity-encoderreadOnly
出力欄を読んでいた (後 2 者はハーネス修正後 PASS)。

なお NAS のワークツリーは remote より 6 コミット遅れていたため、本コミットは
現在の remote tip (0c48927) 上に載せ直してある。変更 2 ファイルの base は
remote と byte 一致を確認済みで、i18n 修正 48 ファイルとは競合しない。

https://claude.ai/code/session_015fXFezC8ABkuZga4497Jw2

?s= による結果共有はこれまで useShareableState を自前で呼ぶ 7 本だけの
対応だった。残り 216 本に個別の restore コールバックを書くのは現実的でなく、
実装差異による取りこぼしも避けられないため、DOM を総なめして直列化する
汎用フックを ToolInteractionTracker と同じ「バブリングを1箇所で拾う」方式で
追加する。ShareBar は既に ?s= を監視しているので無変更で追従する。

設計上の要点:
- 構造キー(type + 同種内連番)。素の通し番号だと mode で表示本数が変わる
  ツール 35 本で復元先が 1 つずれ、別の欄に値が入る。
- 2 パス復元。select/radio/モードボタンを先に当て、rAF で現れた欄を埋める。
- ネイティブ setter。React 19 の制御コンポーネントは el.value 直接代入を
  無視する(value tracker が「変化なし」と判断し onChange が出ない)。
- モード切替が button のツール向けに、選択中(bg-brand-600)の index を
  b キーで保存し復元時に click し直す。

自前実装の 7 本は MANUAL_SHARE_SLUGS で除外し、?s= の二重書き込みを防ぐ。
リストが腐らないよう、実際に useShareableState を import しているツールと
一致することをテストで固定する。

検証: typecheck clean / vitest 26/26 / CDP e2e 10/10 / ランダム 30 本スイープ。

Claude-Session: https://claude.ai/code/session_015fXFezC8ABkuZga4497Jw2
@appdevelopsk
appdevelopsk merged commit 407dc4f into main Sep 9, 2026
2 checks 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.

1 participant