`<wa-copy-button>`にカスタムトリガーのスロット対応を追加

shoelace-style/webawesome

<wa-copy-button>のデフォルトスロットに任意のボタン要素を差し込めるようになりました。これにより、アイコンボタン固定だった制約を破り、<wa-button><button>など任意のインタラクティブ要素をコピー操作のトリガーとして使えます。

背景

従来の<wa-copy-button>はアイコンのみのボタンを内部に持つ固定UIで、サイズや見た目を他のボタンと統一する手段がありませんでした。#1327では「<wa-copy-button>を他の<wa-button>と並べると縦位置やサイズが合わない」というフィードバックが報告され、その解決策として2つのアプローチが検討されました。

1つ目はsizeappearanceなどのボタン属性を<wa-copy-button>自身に追加して機能を増やし続ける方法です。2つ目はデフォルトスロットを用意してユーザーが任意のボタンを差し込める構造に変える方法です。実装コストと柔軟性のトレードオフを考慮した結果、後者が採用されました。スロット方式であれば<wa-button>のすべての属性を再実装することなく、既存の<wa-button>の機能がそのまま使えます。

技術的な変更

copy-button.tsHasSlotControllerが導入され、デフォルトスロットに要素が挿入されているかどうかを検知できるようになりました。これにより、スロットが空のときは従来のアイコンボタンを、スロットに要素があるときはそちらをトリガーとして扱う分岐が実現しています。

具体的には以下のインポートとコントローラーの追加が行われました。

import { HasSlotController } from '../../internal/slot.js';
import { watch } from '../../internal/watch.js';
import hostStyles from '../../styles/component/host.styles.js';

// クラス内
private readonly hasSlotController = new HasSlotController(this, '[default]');

さらに、@watch('status')デコレータを使ったハンドラーが追加され、コピー操作の結果をCSSカスタムステート:state(success) / :state(error))として反映するようになりました。

@watch('status')
handleStatusChange() {
  this.customStates.set('success', this.status === 'success');
  this.customStates.set('error', this.status === 'error');
}

スタイル面では、copy-button.styles.ts.copy-button__triggerクラスが追加されています。display: inline-flexを指定することで、スロットされた要素のインラインレイアウトが適切に機能します。また、static csshostStylesが追加され、ホスト要素のスタイル基盤が整備されました。

カスタムトリガーを使う場合の記述例は以下の通りです。

<wa-copy-button value="You can copy anything with a custom trigger!">
  <wa-button appearance="filled">Copy to Clipboard</wa-button>
</wa-copy-button>
<wa-copy-button value="Native buttons work too!">
  <button type="button" class="wa-filled">Copy to Clipboard</button>
</wa-copy-button>

設計判断

後方互換性の維持を最優先にした設計が選ばれています。デフォルトスロットが空の場合は従来のアイコンボタン動作をそのまま維持し、既存の<wa-copy-button>ユーザーへの影響はありません。PR本文にも「existing copy buttons will continue to work just fine」と明記されています。

カスタムトリガーを使う場合はデフォルトのツールチップとアイコンフィードバックが表示されなくなりますが、代わりにwa-copywa-errorイベントやCSSカスタムステートでフィードバックを実装できます。また、copy-iconsuccess-iconerror-iconの既存スロットを維持するためにHasSlotControllerを導入したことがPR本文で明示されており、単純なフォールバックスロットではなくコントローラーを使った設計になった理由がここにあります。

まとめ

この変更は、<wa-copy-button>のUI固定という制約をデフォルトスロットの追加だけで解消したもので、既存APIへの変更を最小限に抑えながら柔軟性を大きく向上させています。CSSカスタムステートの採用により、カスタムトリガー使用時のフィードバック実装もWeb標準の手法で対応できるようになりました。

記事メタデータ

Generated by:
Claude Sonnet 4.6 for DiffDaily
LLM Trace:
c44aef0f

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

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
Gemini 2.5 Pro for DiffDaily

Review Criteria:

記事構成 ✓ PASS

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

「総論→各論→結論」の構成が明確です。リード文で要旨を、背景で経緯を、技術詳細でコード変更を、設計判断でトレードオフを、まとめで意義を述べるという理想的な構成になっています。

カスタムMarkdown構文 ✓ PASS

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

ファイル名付きコードブロックやGitHubへのリンク記法(PR/Issue番号)がガイドラインに沿って正しく使用されています。

対象読者への適合性 ✓ PASS

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

専門用語を適切に用い、コンポーネント開発者という対象読者に合わせた技術レベルで記述されています。初心者向けの冗長な説明もありません。

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

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

各セクションが「総論→各論」で構成され、各パラグラフはトピックセンテンスで始まるなど、パラグラフ・ライティングの原則が守られており、非常に読みやすいです。

Diff内容との照合 ✓ PASS

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

記事で引用されているすべてのコードブロックは、提供されたDiffの内容と完全に一致しており、ファイル名も正確です。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

`HasSlotController`やCSSカスタムステートなど、PRや関連技術で用いられる用語が正確かつ適切に使用されています。

説明の技術的正確性 ✓ PASS

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

コード変更がもたらす機能的な変化やその仕組みについての説明は、技術的に正確で論理的です。

事実の突合 ✓ PASS

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

記事内の主張はすべてPRのDescriptionやDiffの内容に基づいており、根拠のない憶測や創作(ハルシネーション)は見られません。

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

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

PR番号(#2218)やIssue番号(#1327)などの数値・固有名詞はすべて正確に記載されています。

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

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

記事のタイトルはPRの主題「`<wa-copy-button>`へのカスタムボタン対応」を的確に表現しています。

外部知識の正確性 ✓ PASS

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

PR情報に含まれないバージョン情報やリリース予定などの外部知識の追加はなく、事実に基づいた記述に徹しています。

時間表現の正確性 ✓ PASS

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

PRの時間軸を歪めるような不正確な時間表現はなく、事実関係が正確に記述されています。