コード例プレビューにカラー・方向トグルを追加

shoelace-style/webawesome

Webawesome のドキュメントでは、コード例プレビューをページ全体のテーマに依存させていたため、個別にライト/ダークや LTR/RTL を確認できないという課題がありました。今回の PR では、各コード例に専用のテーマ切替と文字方向切替ボタンを toolbar に組み込み、ページ全体を変更せずにプレビューだけを切り替えられるようにしました。これにより、開発者は実装中のコンポーネントを多様な環境で手軽にテストできるようになります。

背景

コード例のプレビューは従来、ドキュメント全体のカラースキームと文字方向に従属していました。ライトモードで表示された例はダークモードに切り替えると同時にページ全体が暗くなるため、個別のビジュアルチェックが難しかった点が利用者から指摘されていました。さらに、RTL 言語向けのレイアウト確認も、ページ全体を RTL にするしかなく、コード例だけを対象にしたテストが不可能でした。そこで、例ごとにトグルを提供し、ページ全体の状態に影響されないプレビュー機能を実装する方向で設計が進められました。

技術的な変更

code-examples.js のトランスフォーマで新しいクラス属性を検出し、フレーム内例を除外するロジックが追加されましたno-color-schemeno-dir のクラス判定、そして <iframe><wa-zoomable‑frame> が存在するかをチェックして、該当例ではトグルボタンを生成しないようにしています。

@@ -112,6 +112,8 @@ export function codeExamplesTransformer(options = {}) {
       const noEdit = code.classList.contains('no-edit');
+      const noColorScheme = code.classList.contains('no-color-scheme');
+      const noDir = code.classList.contains('no-dir');
@@ -133,6 +135,10 @@ export function codeExamplesTransformer(options = {}) {
       // A scoped color-scheme/direction toggle can't reach into a separate iframe document,
       // so suppress both toggles for framed examples.
-      const hasFrame = !!root.querySelector('wa-zoomable-frame, iframe');
+      const hasFrame = !!root.querySelector('wa-zoomable-frame, iframe');

toolbar の HTML 生成部にテーマと方向切替ボタンが組み込まれ、アイコンは新規 SVG アセットを参照するようになりましたhasPreview && !noColorScheme && !hasFrame の条件でテーマボタンを、hasPreview && !noDir && !hasFrame の条件で方向ボタンを出力し、ボタン内部は wa-icon コンポーネントでラベル付与された SVG を表示します。

@@ -176,15 +180,37 @@ export function codeExamplesTransformer(options = {}) {
                     <button class="code-example-theme" type="button">
-                        <wa-icon class="code-example-theme-light" src="/assets/images/sun-bright.svg" label="Show in dark mode"></wa-icon>
-                        <wa-icon class="code-example-theme-dark" src="/assets/images/moon-stars.svg" label="Show in light mode"></wa-icon>
+                        <wa-icon class="code-example-theme-light" src="/assets/images/sun-bright.svg" label="Show in dark mode"></wa-icon>
+                        <wa-icon class="code-example-theme-dark" src="/assets/images/moon-stars.svg" label="Show in light mode"></wa-icon>
                     </button>
+                  `
+                : ''
+              }
+              ${hasPreview && !noDir && !hasFrame ? `
+                <button class="code-example-dir" type="button">
+                  <wa-icon class="code-example-dir-ltr" src="/assets/images/align-left.svg" label="Show RTL"></wa-icon>
+                  <wa-icon class="code-example-dir-rtl" src="/assets/images/align-right.svg" label="Show LTR"></wa-icon>
+                </button>
+              ` : ''}

クライアントサイドのスクリプトに方向スタンプと MutationObserver が実装され、RTL 時は新しく追加されたノードへも dir="rtl" を自動付与しますsetPreviewDirection が呼び出されると既存のオブザーバーを破棄し、必要に応じて新規オブザーバーを作成して directionObservers に保持します。

+const directionObservers = new WeakMap();
+
+function stampDirection(content, dir) {
+  content.setAttribute('dir', dir);
+  content.querySelectorAll('*').forEach(el => el.setAttribute('dir', dir));
+}
+
+function setPreviewDirection(content, dir) {
+  directionObservers.get(content)?.disconnect();
+  directionObservers.delete(content);
+  stampDirection(content, dir);
+  if (dir === 'rtl') {
+    const observer = new MutationObserver(mutations => {
+      for (const mutation of mutations) {
+        mutation.addedNodes.forEach(node => {
+          if (node.nodeType === 1) stampDirection(node, 'rtl');
+        });
+      }
+    });
+    observer.observe(content, { childList: true, subtree: true });
+    directionObservers.set(content, observer);
+  }
+}

カラー切替は View Transition を利用してクロスフェードし、トランジション中はプレビューを凍結してスナップショットが正しい色で取得できるようにしましたfreezePreview がプレビュー要素に viewTransitionName.is-syncing-scheme クラスを付与し、CSS 側でトランジションプロパティを 0 にして即座に状態を固定します。

+function freezePreview(preview, name) {
+  preview.style.viewTransitionName = name;
+  preview.classList.add('is-syncing-scheme');
+}

CSS では新たにカラースキーム切替時に使用するカスタムプロパティと、凍結状態のスタイルが追加されました.code-example-preview.is-syncing-scheme とその子要素に対し transition: none !important を適用し、View Transition のスナップショットがインタラクティブ要素の遅延レイアウトを受けないようにしています。

+.code-example-preview.is-syncing-scheme {
+  --wa-transition-fast: 0s;
+  --wa-transition-normal: 0s;
+  --wa-transition-slow: 0s;
+}
+.code-example-preview.is-syncing-scheme,
+.code-example-preview.is-syncing-scheme * {
+  transition: none !important;
+}

新規 SVG アイコン(sun-bright.svg, moon-stars.svg, align-left.svg, align-right.svg など)が assets/images に追加され、wa-icon コンポーネントがそれらを参照します。これにより、テーマと方向ボタンが視覚的に統一されたデザインとなります。

既存のドキュメント例では .no-color-scheme.no-dir クラスでトグルを抑制でき、iframe を含む例は自動的に除外されます。たとえば、details コンポーネントの例に .no-dir を付与すると RTL トグルが表示されず、customizing の例に .no-color-scheme を付与するとテーマトグルが除外されます。

設計判断

既存の .code-example 裏地を拡張し、追加機能を最小限の差分で実装する方針が取られました。新規コンポーネントを作らずに toolbar にボタンを差し込むことで、既存のレイアウトやスタイルへの影響を抑えつつ、後方互換性を維持しています。no-color-schemeno-dir のオプトアウト機構は、特定例で不要なトグルを除外できる柔軟性を提供します。

トグルの状態は永続化せず、action‑label パターンでラベルを切り替える設計とすることで、アクセシビリティと UI のシンプルさを両立させましたaria-pressed を使わずラベルテキストを変えるだけなので、スクリーンリーダーでも現在の状態が明示されます。さらに、<canvas> で描画されたチャートは色変化を受けないことを明記し、期待される挙動をドキュメントで説明しています。

変更はドキュメントサイト全体に影響を与えず、コード例単位でのプレビュー切替を可能にした点が大きな価値です。開発者はページ全体のテーマや文字方向を変えることなく、個別コンポーネントの外観を確認でき、デザインレビューや多言語対応のテストが効率化されます。

記事メタデータ

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

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

品質レビュー結果

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

Review Criteria:

記事構成 ⚠ WARNING

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

リード文はあるが、最後に明確な『まとめ』セクションが欠けている。設計判断は結論に近い内容だが、総論→各論→結論の明示的な構成が不足している。

カスタムMarkdown構文 ✓ PASS

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

ファイル名付きシンタックスハイライトは正しい形式(```javascript:filepath など)で使用され、GitHubリンクも PR 番号のリンク記法が正しく適用されている。

対象読者への適合性 ✓ PASS

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

専門的なエンジニア向けの内容で、余計な初心者向け解説はなく適切なレベルで書かれている。

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

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

各セクションは総論パラグラフで要旨を示し、続く段落は単一トピックで構成されており、段落間は空行で区切られている。長すぎる段落は見受けられない。

Diff内容との照合 ✓ PASS

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

記事中のコードブロックは提供された Diff と一致しており、追加・変更箇所が正確に反映されている。抜粋形式でも内容は誤っていない。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

「color-scheme」「direction」「no-color-scheme」「no-dir」「View Transition」などの用語が正しく使用され、PR と Diff の記述と合致している。

説明の技術的正確性 ✓ PASS

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

トグル機能の目的、実装方法、オプトアウトクラス、ビュー・トランジションによるクロスフェードなどの説明が技術的に正確で、PR の記載と矛盾していない。

事実の突合 ✓ PASS

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

全ての主張は PR のタイトル・ディスクリプション、Diff のコードに裏付けられており、根拠のない推測はない。

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

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

PR 番号 #2554 など数値情報は正しく記載され、誤りは見当たらない。

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

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

記事タイトルは PR タイトルの内容を日本語で正確に要約しており、一致している。

外部知識の正確性 ✓ PASS

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

バージョンサポートや LTS 等の外部知識は記載されておらず、PR 情報のみで構成されている。

時間表現の正確性 ✓ PASS

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

時間表現のずれはなく、PR の記述と整合している。