コード例プレビューにカラー・方向トグルを追加
Webawesome のドキュメントでは、コード例プレビューをページ全体のテーマに依存させていたため、個別にライト/ダークや LTR/RTL を確認できないという課題がありました。今回の PR では、各コード例に専用のテーマ切替と文字方向切替ボタンを toolbar に組み込み、ページ全体を変更せずにプレビューだけを切り替えられるようにしました。これにより、開発者は実装中のコンポーネントを多様な環境で手軽にテストできるようになります。
背景
コード例のプレビューは従来、ドキュメント全体のカラースキームと文字方向に従属していました。ライトモードで表示された例はダークモードに切り替えると同時にページ全体が暗くなるため、個別のビジュアルチェックが難しかった点が利用者から指摘されていました。さらに、RTL 言語向けのレイアウト確認も、ページ全体を RTL にするしかなく、コード例だけを対象にしたテストが不可能でした。そこで、例ごとにトグルを提供し、ページ全体の状態に影響されないプレビュー機能を実装する方向で設計が進められました。
技術的な変更
code-examples.js のトランスフォーマで新しいクラス属性を検出し、フレーム内例を除外するロジックが追加されました。no-color-scheme と no-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-scheme と no-dir のオプトアウト機構は、特定例で不要なトグルを除外できる柔軟性を提供します。
トグルの状態は永続化せず、action‑label パターンでラベルを切り替える設計とすることで、アクセシビリティと UI のシンプルさを両立させました。aria-pressed を使わずラベルテキストを変えるだけなので、スクリーンリーダーでも現在の状態が明示されます。さらに、<canvas> で描画されたチャートは色変化を受けないことを明記し、期待される挙動をドキュメントで説明しています。
変更はドキュメントサイト全体に影響を与えず、コード例単位でのプレビュー切替を可能にした点が大きな価値です。開発者はページ全体のテーマや文字方向を変えることなく、個別コンポーネントの外観を確認でき、デザインレビューや多言語対応のテストが効率化されます。