ドキュメントにフルページパターンを表示するための基盤整備
WebAwesomeのドキュメントシステムに、フルページパターンを適切に提示するための複数の改善が加えられました。コード例のトランスフォーマー拡張、CSSのロジカルプロパティ化、コンテナクエリへの移行、そしてファイルエクスプローラーUIスタイルの追加が主な変更点です。
背景
これまでのドキュメントシステムは、フルページパターン(アプリ・ブログ・ECサイトなどの実際の画面を模したレイアウト)を効果的に提示する手段が不足していました。<wa-zoomable-frame> を使ったコード例の表示機能はあったものの、<wa-include> のトップレベルでの直接利用や、プレビューなしのコード表示、ネストした <wa-include> の展開制御といった機能が欠けていました。
サイドバーのナビゲーション構造も見直され、Layouts エントリが一覧の下部から上部へ移動し、App・Blog・Ecommerce のアンカーリンクを持つ構成に再編されています。これに伴い、/docs/patterns/layouts/ecommerce/ や /docs/patterns/layouts/blog/ といった個別パスは廃止されました。
技術的な変更
code-examples.js の拡張
コード例処理の中核となる関数が getFrameSource から getElementSource へリファクタリングされ、<wa-zoomable-frame> だけでなく <wa-include> のトップレベル要素も同様に処理できるようになりました。
変更前:
const getFrameSource = frame => {
const selectSrc = frame?.hasAttribute('data-select-src');
if (!selectSrc) return;
let src = frame.getAttribute('src');
let source = frame.getAttribute('srcdoc');
if (!source && src) {
src += src.match(/\.html/) ? '' : `${src.endsWith('/') ? '' : '/'}index.html`;
src = src.split('?')[0].split('#')[0];
source = readFileSync(path.join(baseDir, src), 'utf8');
}
const selectors = frame?.getAttribute('data-select-src');
if (selectors) {
const sourceNode = parse(source, { comment: true, voidTag: { closingSlash: true } });
sourceNode.querySelectorAll('wa-include').forEach(e => replaceIncludeWithSource(e));
// ...
}
};
変更後:
const getElementSource = element => {
const selectSrc = element?.hasAttribute('data-select-src');
const expandIncludes = element?.hasAttribute('data-expand-includes');
if (!selectSrc) return;
let src = element.getAttribute('src');
let source = element.getAttribute('srcdoc');
const isInclude = element.tagName?.toLowerCase() === 'wa-include';
if (!source && src) {
// For wa-include, read the source file directly
// For frames, normalize src for file path resolution
if (!isInclude) {
src += src.match(/\.html/) ? '' : `${src.endsWith('/') ? '' : '/'}index.html`;
src = src.split('?')[0].split('#')[0];
}
source = readFileSync(path.join(baseDir, src), 'utf8');
}
const selectors = element?.getAttribute('data-select-src');
if (selectors) {
const sourceNode = parse(source, { comment: true, voidTag: { closingSlash: true } });
if (expandIncludes) {
sourceNode.querySelectorAll('wa-include').forEach(e => replaceIncludeWithSource(e));
}
// ...
}
};
主な変更点は3つです。まず、isInclude フラグによる要素種別の判定で、<wa-include> の場合はパスの正規化(index.html 付与やクエリ文字列除去)をスキップし、ファイルを直接読み込みます。次に、data-expand-includes 属性によるネスト展開の明示的な制御で、以前は <wa-zoomable-frame> で非boolean値の data-select-src を指定した場合に自動的に展開されていた動作が、オプトイン方式に変更されました。さらに、no-preview クラスの追加により、<wa-zoomable-frame> や <wa-include> のパース結果を描画せずコードのみを表示できるようになりました。
code-examples.css のロジカルプロパティ化
code-examples.css では、物理プロパティからロジカルプロパティへの移行が行われました。具体的には、border-top-left-radius / border-top-right-radius が border-start-start-radius / border-start-end-radius に、top / left / right / bottom が inset-block-start / inset-inline-start 等に置き換えられています。また、境界線のスタイリング値が CSS カスタムプロパティ(--code-example-border-color、--code-example-border-radius、--code-example-border-width)にまとめられ、一元管理されるようになっています。
margin-block-end の付与条件も変わっています。従来は .code-example に常に適用されていた下マージンが、:has(+ *) セレクタを使って後続要素が存在する場合のみ適用されるよう改善されました。これにより、コードブロックが最後の要素である場合の余分な余白がなくなります。
docs.css のコンテナクエリへの移行
docs.css の検索インデックス(.search-list)において、メディアクエリがコンテナクエリに置き換えられました。
変更前:
@media screen and (max-width: 1470px) {
grid-template-columns: repeat(3, 1fr);
}
@media screen and (max-width: 960px) {
grid-template-columns: repeat(2, 1fr);
}
@media screen and (max-width: 500px) {
grid-template-columns: repeat(1, 1fr);
}
変更後:
.search-list {
container-type: inline-size;
}
@container (width < 768px) {
grid-template-columns: repeat(3, 1fr);
}
@container (width < 576px) {
grid-template-columns: repeat(2, 1fr);
}
@container (width < 384px) {
grid-template-columns: repeat(1, 1fr);
}
あわせて、2カラムレイアウトを基準とした .large グリッドバリアントが追加されています。これはフルページパターンのサムネイルギャラリーなど、より大きなカードを表示したい場面での使用を想定しています。また、ヘッダースタイルの適用対象が &::part(header) から &[with-header]::part(header) に絞り込まれ、with-header 属性を持つ要素のみにヘッダースタイルが適用されるようになっています。
utils.css へのファイルエクスプローラーUIの追加
utils.css に .file-explorer コンポーネントのスタイルが追加されました。これはフルページパターンの説明ページで、パターンを構成する複数のファイルをツリー形式で表示し、選択したファイルのコードをパネルに表示するUIを実現します。
レイアウトは grid-template-columns: 30ch 1fr の2カラムグリッドで、左ペインに <wa-tree> によるファイルツリー、右ペインにコードキャンバスを配置します。ファイルツリーは position: sticky と overflow-y: auto で独立スクロール可能にされており、高さは block-size: 60vh に固定されています。選択中のアイテムは &:state(selected)::part(item) でスタイリングされており、Web Componentsの CSS Part と Custom State に対応した実装です。また、wa-zoomable-frame:has(+ .file-explorer) セレクタにより、ファイルエクスプローラーの直前に置かれた <wa-zoomable-frame> には自動的に枠線とmin-heightが適用されます。
設計判断
data-expand-includes による明示的なオプトインという設計が採用された点が注目されます。以前は <wa-zoomable-frame> で非boolean値の data-select-src を指定すると <wa-include> が自動展開されていましたが、この動作が暗黙的すぎるとして、属性による明示的な制御に変更されています。自動展開が常に望ましいわけではなく(<wa-include> の参照を展開せずそのままコードとして示したい場合など)、利用側が展開の有無を選択できる柔軟性が確保されています。
コンテナクエリへの移行も重要な設計判断です。メディアクエリはビューポート幅に依存するため、サイドバーの開閉状態などコンテナの実際の幅が変化する文脈では正確に機能しません。container-type: inline-size を .search-list 自身に持たせることで、コンポーネントが埋め込まれる場所の幅に応じたレスポンシブ対応が可能になっています。
まとめ
本PRは、フルページパターンのドキュメント化という具体的なユースケースに対応するため、コード例処理の汎化(フレームからインクルードへの対応拡大)、CSSのモダン化(ロジカルプロパティ・コンテナクエリ)、そしてファイルエクスプローラーUIの追加という複数の変更を一体的に実施しています。各変更は独立した改善でありながら、フルページパターンの提示という共通目的のもとに整合しており、ドキュメントの表現力を大幅に高める基盤となっています。