ランダムコンテンツコンポーネントの追加

shoelace-style/webawesome

Web Awesome に新たに wa-random-content コンポーネントが実装され、スロットされた子要素をランダムに表示し、残りを自動で非表示にできるようになりました。これにより、テストimonial のローテーションや「今日の一言」など、静的ページに変化をもたらすユーティリティが標準化されます。

背景

Stretch goal #1076 で掲げられた 14 方向の新コンポーネントのうち、ランダムコンテンツは「ページに刺激を与える」役割を担うことが期待されていました。既存のコンポーネント群は明示的なレイアウトやインタラクションに特化していたため、同一ページ内で表示内容を周期的に変える手段が不足していました。この PR は、そのギャップを埋めるために作成されました。

技術的な変更

実装概要wa-random-contentWebAwesomeElement を継承した Lit カスタムエレメントとして実装され、属性 items, mode, animation を公開します。また、手動トリガー用メソッド randomize() と、表示が変わるたびに発火するカスタムイベント wa-content-change を提供します。

import { html, type PropertyValues } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';
import { WaContentChangeEvent } from '../../events/random-content-change.js';
import { prefersReducedMotion } from '../../internal/animate.js';
import { watch } from '../../internal/watch.js';
import WebAwesomeElement from '../../internal/webawesome-element.js';
import visuallyHidden from '../../styles/component/visually-hidden.styles.js';
import { AutoplayController } from '../carousel/autoplay-controller.js';
import styles from './random-content.styles.js';

/**
 * @summary Selects one or more child elements at random and displays them, hiding the rest.
 * @status experimental
 * @since 3.9
 */
@customElement('wa-random-content')
export default class WaRandomContent extends WebAwesomeElement {
  @property({ type: Number }) items = 1;
  @property({ type: String }) mode: 'random' | 'unique' | 'sequence' = 'random';
  @property({ type: String }) animation = 'none';
  @state() private _shown: Element[] = [];

  /** Imperatively trigger a new selection using the current mode. */
  randomize() {
    this._choose();
  }

  // ...内部ロジックは省略
}

スタイルと非表示ロジック::slotted([hidden]) で選択されなかった子要素を display:none !important にし、スロットされたコンテンツが意図通り隠れるようにしています。さらに、アニメーション用の @keyframes をドキュメントスコープとシャドウルート双方に注入し、Chromium と WebKit の挙動差を吸収しています。

:host { display: contents; }

::slotted([hidden]) { display: none !important; }

@keyframes wa-rc-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes wa-rc-fade-up { from { opacity: 0; transform: translateY(var(--animation-translate, 0.5em)); } to { opacity: 1; transform: translateY(0); } }
/* その他方向の keyframes も同様 */

カスタムイベント:表示が変わるたびに WaContentChangeEvent が生成され、detail.items に現在表示中の要素配列を格納します。イベントはバブルし、コンポジションツリー全体で購読可能です。

export class WaContentChangeEvent extends Event {
  readonly detail: { items: Element[] };
  constructor(detail: { items: Element[] }) {
    super('wa-content-change', { bubbles: true, cancelable: false, composed: true });
    this.detail = detail;
  }
}

SSR エクスポートpackages/webawesome/src/ssr/all.tsWaRandomContent が追加され、サーバーサイドレンダリングでも利用できるよう統合されています。

export { default as WaRandomContent } from '../components/random-content/random-content.js';

テスト網羅random-content.test.ts ではアクセシビリティ、初期表示、属性変化、各モードの振る舞い、randomize() の即時効果、wa-content-change の発火、そして prefers-reduced-motion に対する配慮まで 500 行近くにわたって検証しています。

設計判断

属性設計itemsmodeanimation を単一コンポーネントに集約することで、既存の属性パターンと一貫性を保ちつつ、拡張性を確保しています。items は 1 以上子要素数以下にクランプし、mode は列挙型で明示的に管理することで不正入力を防止しています。

モード実装random がシンプルな乱択、unique が直前の選択を除外、sequence が順次巡回という形で、利用シーンに応じたアルゴリズムを提供しています。これらは内部で同一ロジックを状態管理 (_shown とインデックス) に集約し、重複ロジックを排除しています。

アニメーション戦略:アニメーション名を CSS カスタムプロパティで切り替える設計にし、animation 属性に none|fade|fade-up|... を指定するだけでエントランス効果を変更可能にしています。さらに、prefers-reduced-motion が有効な環境ではアニメーションを自動的に無効化し、アクセシビリティ要件に合致させています。

再利用性と SSR:コンポーネントは WebAwesomeElementAutoplayController を組み合わせ、他のカルーセル系コンポーネントと同様の自動再生ロジックを共有しています。SSR エクスポートへの追加は、ビルド時のツリーシェイクに影響しないようシンプルな再エクスポートで実装されています。

まとめ

wa-random-content はランダム表示という汎用ユーティリティを公式コンポーネントとして提供し、属性ベースの設定・手動トリガー・イベント通知という標準的なインターフェースを備えました。スタイルとアニメーションのクロスブラウザ対応、アクセシビリティ考慮、SSR への統合といった設計判断により、既存の Web Awesome エコシステムにシームレスに組み込める形で実装されています。

記事メタデータ

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

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

品質レビュー結果

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

Review Criteria:

記事構成 ✓ PASS

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

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

カスタムMarkdown構文 ⚠ WARNING

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

コードブロックは `言語:ファイルパス` 形式で正しく記述されています。PRリンクは `[PR #2513](URL)` とテキストに「PR」が付加されていますが、ガイドラインの `[#123](URL)` と完全に一致していないため警告としました。

対象読者への適合性 ✓ PASS

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

対象は Web Awesome の開発者向けで、専門用語が中心。初心者向けの過剰な解説はありません。

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

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

各セクションが総論・各論・結論の段落構成になっており、トピックセンテンスで始まる段落がほとんどです。段落は適切な長さで空行で区切られています。

Diff内容との照合 ✓ PASS

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

記事中のコードブロックはすべて提供された Diff に含まれるファイル・内容と一致しています。抜粋で示されている点も情報を欠落させていません。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

属性名 `items`、`mode`、`animation`、メソッド `randomize`、イベント `wa-content-change` など、PR や Diff と同一の用語が使用されています。

説明の技術的正確性 ✓ PASS

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

コンポーネントが「子要素をランダムに表示し、残りを非表示にする」ことや、SSR へのエクスポート、アニメーション制御などの説明は Diff と PR の記述と一致しています。

事実の突合 ✓ PASS

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

記事中のすべての主張は PR タイトル・説明・Diff で裏付け可能です。外部情報や根拠のない数値・予測は含まれていません。

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

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

PR 番号 #2513、属性デフォルト値 1 など、数値・固有名詞は正確です。

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

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

記事タイトルは PR の内容「Wa‑random‑content Component」を日本語で要約しており、意味的に一致しています。

外部知識の正確性 ✓ PASS

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

バージョンサポートやリリーススケジュールなど PR に記載されていない外部知識は一切含まれていません。

時間表現の正確性 ✓ PASS

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

時間表現はなく、PR の記述と食い違う表現もありません。