`<wa-tree>` のサイズをフォントサイズ連動に変更し、インデントガイドの位置ずれも修正
<wa-tree> コンポーネントの内部寸法がすべて font-size に連動するようになり、ツリー全体のサイズ変更が容易になりました。あわせて、インデントガイドの位置ずれも修正されています。
背景
#2147 で指摘されていたとおり、従来の <wa-tree> はフォントサイズが内部でハードコードされており、ツリー全体をリサイズすることが困難でした。ラベル・チェックボックス・展開ボタンなどの内部要素が固定の --wa-font-size-m トークンや絶対的なスペーストークンに依存していたため、外部から font-size を指定しても寸法が追従しませんでした。
また、インデントガイドを実装するために font-size: 0 トリックが使われており、これが問題の根本にもなっていました。このトリックを除去するにあたってインデントガイドの描画ロジック全体を見直した結果、ガイドが中央からずれていたバグも発見・修正されています。
技術的な変更
font-size: 0 トリックの廃止により、インデント量の算出ロジックが刷新されました。これが今回の変更の中核です。
tree.styles.ts — font-size: 0 の削除と --indent-size のデフォルト値変更
変更前は :host に font-size: 0 を設定し、EMの相対計算でルートのインデントをゼロにしていました。
変更前:
:host {
--indent-size: var(--wa-space-l);
display: block;
/*
* Tree item indentation uses the "em" unit to increment its width on each level,
* so setting the font size to zero here removes the indentation for all the nodes
* on the first level.
*/
font-size: 0;
}
変更後:
:host {
--indent-guide-offset: 0;
--indent-guide-style: solid;
--indent-guide-width: 0;
--indent-size: 2em;
display: block;
}
--indent-size のデフォルト値が var(--wa-space-l)(絶対値トークン)から 2em(相対値)に変わり、ツリー自体の font-size に連動するようになりました。
tree-item.ts — 深さをJavaScriptで計算してCSS変数に注入
font-size: 0 が使えなくなったため、各アイテムのインデント幅をDOMのネスト深さから計算し、プライベートなCSS変数 --indent としてホスト要素に直接設定する updateIndentation() メソッドが追加されました。
/** Counts the nesting depth and sets the private --indent property on the host for indentation. */
private updateIndentation() {
let depth = 0;
let node = this.parentElement;
while (node) {
if (WaTreeItem.isTreeItem(node)) {
depth++;
}
node = node.parentElement;
}
this.style.setProperty('--indent', `calc(${depth} * var(--indent-size, 2em))`);
}
このメソッドは connectedCallback から呼び出され、コンポーネントがDOMに接続された時点でインデントが確定します。深さは親要素を while ループで辿り、WaTreeItem のインスタンスをカウントすることで求めています。
tree-item.styles.ts — 固定値の相対値への置き換え
スタイル側でも固定値の参照が一掃されました。主な変更点は以下のとおりです:
-
.indentationの幅が1emからvar(--indent)に変更(JSで計算した深さを参照) -
.checkbox/.labelのfont-sizeがvar(--wa-font-size-m)からinheritに変更 -
.itemのborder-inline-startがsolid 3px transparentからsolid 0.1875em transparentに変更(EM単位化) - アイコンの
margin-inline-endがvar(--wa-space-xs)から0.5emに変更 -
.childrenのfont-size: calc(1em + var(--indent-size, ...))の行が削除(深さ計算をJSに移譲)
また、--indent はコンポーネントが制御するプライベート変数であることをコメントで明示するため、:host ブロックに --indent: 0px の初期値が追加されています。
設計判断
CSSによるEM相対計算からJavaScriptによる深さ計算への移行という方向性が選択されました。
旧実装は font-size: 0 を親要素に設定し、子要素のEM計算で自動的にインデントが積算される巧妙な手法でしたが、ツリー全体の font-size を外部から制御できないという制約がありました。新実装はDOMツリーを走査して深さを明示的に算出することで、この制約を取り除いています。副作用として、インデント計算が宣言的なCSSではなく命令的なJavaScriptに移ったため、動的なDOM操作後に updateIndentation() を呼ぶ責務がコンポーネント側に生まれています。
また、--indent-size のデフォルト値を 2em に固定したことで、font-size を変えるだけでツリー全体が比例してリサイズされます。カスタマイズの際も --indent-size を上書きすることで任意の幅を指定できるため、公開APIは変わっていません。
まとめ
font-size: 0 トリックを廃止し、インデント深さをJavaScriptで計算してCSS変数に注入する方式に切り替えることで、<wa-tree> はフォントサイズに完全に追従するコンポーネントになりました。内部の固定値をEM単位に統一したこの変更は、単なるバグ修正にとどまらず、コンポーネント設計における「CSSトリックの限界とJSによる補完」というトレードオフを示す好例です。