autocapitalize属性をcontenteditableへ転送しAndroidテキスト置換を回避

basecamp/lexxy

Lexxyエディタでハードコードされていた autocapitalize="none" を除去し、lexxy-editor[autocapitalize] の値を contenteditable 要素へ転送するようにしました。この変更により Android のテキスト置換バグを回避しつつ、属性の動的変更も正しく反映されます。

背景

従来、src/elements/editor.js はエディタ内部の contenteditable 要素に autocapitalize="none" を固定で付与していました。この固定値が Android のテキスト置換機構と衝突し、入力補正が期待通りに動作しないという報告がありました。さらに、開発者が <lexxy-editor autocapitalize="characters"> のように属性を設定しても、内部要素へ反映されないため属性の可視性が失われていました。これらの問題を解決するため、属性の転送と同期ロジックを導入する必要が生じました。

技術的な変更

observedAttributes 配列に "autocapitalize" が追加され、エレメントが属性変更を監視できるようになりました。

-  static observedAttributes = [ "connected", "required" ]
+  static observedAttributes = [ "autocapitalize", "connected", "required" ]

attributeChangedCallback は、属性名に対応する *ChangedCallback メソッドが存在すれば呼び出す汎用ロジックへ置き換えられました。これにより connectedrequired だけでなく、将来的な属性追加にも同一パターンで対応できます。

-    if (name === "connected") this.connectedChangedCallback(oldValue, newValue)
-    if (name === "required") this.requiredChangedCallback(oldValue, newValue)
+    if (typeof this[`${name}ChangedCallback`] === "function") {
+      this[`${name}ChangedCallback`](oldValue, newValue)
+    }

新たに autocapitalizeChangedCallback が実装され、editorContentElement が存在すれば #transferAttributeToContentEditable を呼び出して属性を転送します。

autocapitalizeChangedCallback() {
  if (this.editorContentElement) {
    this.#transferAttributeToContentEditable(this.editorContentElement, "autocapitalize")
  }
}

#createEditorContentElement からはハードコードされた autocapitalize="none" が削除され、代わりに属性転送ロジックが組み込まれました。tabindex についてもデフォルト 0 を設定しつつ、属性を同様に転送します。

-      contenteditable: true,
-      autocapitalize: "none",
+      contenteditable: true,
@@
-    editorContentElement.id = `${this.id}-content`
+    this.#transferAttributeToContentEditable(editorContentElement, "autocapitalize")
+    this.#transferAttributeToContentEditable(editorContentElement, "tabindex", { defaultValue: 0, removeSource: true })

テスト用 fixture attribute-transfer.html と新規テスト attribute_transfer.test.js が追加され、属性の転送・同期・削除が期待通りに動作することを自動検証します。テストは Playwright を用いてエディタと内部コンテンツ要素の属性状態を確認し、動的な setAttribute / removeAttribute もカバーします。

設計判断

属性変更時の処理を 汎用コールバックディスパッチ に統一したことにより、個別の if 分岐を排除しコードの拡張性が向上しました。新しい属性を追加する際は observedAttributes に列挙し、*ChangedCallback を実装すれば自動的に呼び出されます。

autocapitalizetabindex の転送は、#transferAttributeToContentEditable という単一メソッドに集約されました。これにより属性の同期ロジックが集中管理され、将来的な変更が局所的に抑えられます。また、tabindex のデフォルトを 0 に設定しつつ元属性を削除するオプションを提供することで、フォーカス制御の一貫性を保ちました。

この設計は既存の API(autocapitalize を明示的に設定しなくても動作する)を壊さず、Android のバグ回避という実装上の目的を達成すると同時に、属性拡張のためのスケーラブルな枠組みを提供しています。

まとめ

autocapitalize をハードコードから解放し、属性転送と同期を実装したことで Android 環境でのテキスト置換問題が解消されました。汎用的な属性コールバックと転送ロジックにより、今後の属性追加も最小変更で対応可能となり、エディタの拡張性が向上しています。

記事メタデータ

Generated by:
gpt-oss-120b for DiffDaily
LLM Trace:
28d52808

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
gpt-oss-120b for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

リード文→背景→技術的な変更→設計判断(任意)→まとめの流れが明確で、各要素が揃っています。

カスタムMarkdown構文 ✓ PASS

シンタックスハイライト・GitHubリンク記法の正確性

コードブロックは正しいdiff・javascriptシンタックスで記載され、GitHubリンクも正しくマークダウン化されています。ファイル名付きハイライトは使用していませんが必須ではありません。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

専門的なJavaScript/Webコンポーネントの知識を前提としており、初心者向けの過剰な説明はありません。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクションは総論→各論→結論の構成で、段落はトピックセンテンスで始まり、1段落1トピック、文数も適切です。

Diff内容との照合 ✓ PASS

コードブロックとDiff内容の一致

記事中のdiffブロックは提供されたDiffと一致しており、コードの追加・削除・変更箇所が正確に反映されています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

observedAttributes、attributeChangedCallback、autocapitalizeChangedCallback など、PRで使われている用語を正しく使用しています。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

技術的な説明はPRの記述と合致し、根拠が明示されています。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

全ての主張はPR情報(タイトル・説明・Diff)で裏付けられており、推測や捏造はありません。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

PR番号 #1116 が正しく記載されており、他の数値や固有名詞の誤りはありません。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

記事タイトルはPRの目的(autocapitalize の転送)を的確に表現しています。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

記事内にPRに無関係な外部知識(LTS、リリース日程等)は含まれていません。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

時間表現の歪曲はなく、PRの記述と一致しています。