popconfirm —— 確認バルーン
削除、送信、公開——こうした「やったら元に戻しにくい」操作にはユーザーの再確認が 1 度必要です。dialog は重すぎ(モーダル、フォーカスを奪う、マスク)で、popconfirm はその場で小さなバルーンを出します:一文 + 2 つのボタンで、確認したら即座に消えます。インタラクションの重さがちょうど tooltip と dialog の間に位置するコンポーネントです。
- 各端末で
<LhPopconfirm>を実装:行の削除、操作の取り消し、データのクリア、注文の送信。 - 軽量、その場、取り消しの余地が小さい二次確認。
- 使うべきでないケース:ユーザーが全神経を集中する必要があるほど重大な結果(
dialogを使う——モーダルマスクが強制的にフォーカス);単なる情報提示(tooltip/messageを使う);理由の記入やチェック項目を伴う確認(フォーム付きのdialogを使う)。
インポート方法
Section titled “インポート方法”import { LH_POPCONFIRM_TYPE_DEFAULT, LH_POPCONFIRM_PLACEMENT_DEFAULT, getPopconfirmIconName, getPopconfirmClass, getPopconfirmTriggerAria, getPopconfirmPopperAria, getDefaultDelay, canCloseOnEscape,} from '@lh-ui/share/core/popconfirm'import type { LhPopconfirmType, LhPopconfirmTrigger, LhPopconfirmState } from '@lh-ui/share/core/popconfirm'デフォルトのトーンは info ではなく warning:LH_POPCONFIRM_TYPE_DEFAULT = 'warning'——確認ボックスが現れるということは基本的に「リスクがある」を意味し、デフォルトは警告トーンであるべきです。info は純粋な通知的な確認(「既読にマークしますか?」)に、danger は不可逆な操作(「削除すると元に戻せません」)に残します。
3 つのトーン、3 つのアイコン:info → info、warning → warning、danger → error(アイコン名は danger ではなく error——アイコンライブラリの命名が error であるため、これがクロス命名のマッピングです)。未知の type は warning にフォールバックします。
popover の "dialog" ではなく role="alertdialog":alertdialog は ARIA における「ユーザーの即時の応答を必要とするダイアログ」です——スクリーンリーダーは優先的に読み上げ(alert の割り込み性に似ているが、ユーザーに選択を求める)。これが「お前の決定待ち」のセマンティクスに、dialog よりも丁度合致します。
確認/キャンセルのイベント契約は UI 層にある:core はクラス名、アイコン、aria、遅延だけを出力します;onConfirm / onCancel イベント、ボタンの文案、loading 状態はすべて UI 層にあります——それらはコンポーネントツリー間の通信(emit)に関わり、core はフレームワーク API に触れないためです。
遅延は popover に従う:getDefaultDelay のデフォルトは 200/100 で、popover と同じです——確認バルーンも同様に hover トリガーを許可し、ポインタが中に入れるようにします。
| 関数 | シグネチャ | 戻り値 | 役割 |
|---|---|---|---|
getPopconfirmIconName |
(type: LhPopconfirmType) => string |
アイコン名 | 未知の type は warning にフォールバック |
getPopconfirmClass |
(state: { type, placement, popperClass? }) => string[] |
クラス名 | トーン + 方位 |
getPopconfirmTriggerAria |
(visible, popperId?) => LhAriaAttrs |
aria バッグ | expanded/controls/haspopup |
getPopconfirmPopperAria |
(id?) => LhAriaAttrs |
aria バッグ | role=alertdialog |
getDefaultDelay |
(showAfter?, hideAfter?) => { show, hide } |
遅延 | デフォルト 200 / 100 |
canCloseOnEscape |
(state: { disabled }) => boolean |
許可するか | disabled 時にインターセプト |
定数:LH_POPCONFIRM_TYPE_DEFAULT = 'warning'、LH_POPCONFIRM_PLACEMENT_DEFAULT = 'top'。
export type LhPopconfirmType = 'info' | 'warning' | 'danger'export type LhPopconfirmTrigger = 'click' | 'hover' | 'focus' | 'manual'
export interface LhPopconfirmState { type?: LhPopconfirmType trigger?: LhPopconfirmTrigger placement?: LhPlacement visible?: boolean disabled?: boolean showIcon?: boolean // デフォルト true}アクセシビリティ
Section titled “アクセシビリティ”getPopconfirmPopperAria('pc-1')// { role: 'alertdialog', id: 'pc-1' }getPopconfirmTriggerAria(true, 'pc-1')// { 'aria-expanded': true, 'aria-controls': 'pc-1', 'aria-haspopup': 'true' }- alertdialog の読み上げ:スクリーンリーダーは alertdialog に遭遇するとその内容(aria-labelledby または内部テキスト)を即座に読み上げます。ユーザーが自発的に読みに行く必要はありません——これが dialog よりも強制力が強い点で、「確認待ち」の意図に合致します。
- ボタンには明確な文案を:「OK / NO」やアイコンボタンよりも「確定 / キャンセル」が優れます。
dangerトーンでは確認ボタンの文案に結果を明記することを推奨します(「確定」ではなく「削除」)。 - キャンセルが安全な方向:Enter はデフォルトで確認とキャンセルのどちらをトリガーするべきか? 一般的な做法は初期フォーカスをキャンセルボタンに置くことです(Tab + Enter で安全に脱出できる)——破壊的操作ではフォーカスを確認ボタンに置かないでください。これは UI 層の决定で、core は関与しません。
- Esc = キャンセル:
canCloseOnEscapeが許可する場合、Esc は単に閉じるのではなく onCancel をトリガーするべきです——セマンティクス上「確認ボックスを閉じる」は「確認しない」だからです。 - アイコンの aria-hidden:セマンティックアイコン(warning/error)は文案で伝達済みで、アイコン自体は装飾化し、スクリーンリーダーが「警告」と二重に読み上げるのを避けます。
import { getPopconfirmIconName, getPopconfirmClass, LH_POPCONFIRM_TYPE_DEFAULT } from '@lh-ui/share/core/popconfirm'
getPopconfirmIconName('info') // 'info'getPopconfirmIconName('warning') // 'warning'getPopconfirmIconName('danger') // 'error'getPopconfirmIconName('other' as never) // 'warning'(フォールバック)
getPopconfirmClass({ type: 'danger', placement: 'top' })// ['lh-popconfirm__popper', 'lh-popconfirm__popper--danger', 'lh-popconfirm__popper--top']
LH_POPCONFIRM_TYPE_DEFAULT // 'warning'<!-- Vue3 --><template> <LhPopconfirm title="削除すると元に戻せません。この行を削除しますか?" type="danger" confirm-text="削除" cancel-text="キャンセル" @confirm="remove(row)" > <template #reference> <LhButton type="danger" size="small">削除</LhButton> </template> </LhPopconfirm></template>
<script setup>async function remove(row) { // onConfirm がトリガー;コンポーネント内部は confirmLoading をサポート可能:非同期完了後にバルーンを閉じる await api.delete(row.id) LhMessage.success('削除しました')}</script>// 非同期確認:confirm 中はボタンを無効化 + loading を表示、失敗時はバルーンを開いたままにする// これは UI 層のロジック:core は非同期状態を保持しない// React:onConfirm/onCancel は props として渡す;非同期確認には visible の制御を併用// uniapp:<view> のバルーン;ボタンのタッチ状態は hover-class;イベント契約は同モデルスタイルとトークン
Section titled “スタイルとトークン”| クラス名 | 意味 |
|---|---|
.lh-popconfirm__popper |
バルーンコンテナ |
.lh-popconfirm__popper--{info|warning|danger} |
トーン(アイコン色 + 確認ボタン色) |
.lh-popconfirm__popper--{top|bottom|…} |
方位 |
.lh-popconfirm__icon |
トーンアイコン |
.lh-popconfirm__title |
タイトル文案 |
.lh-popconfirm__actions |
ボタン領域(右揃え) |
確認ボタンの色はトーンに従う:danger は --lh-danger-color、warning は --lh-warning-color、info は --lh-primary-color。
- タイトルには結果を明記する:「削除しますか?」は悪い文案(結果を言っていない);「削除すると元に戻せません。この行を削除しますか?」は良い文案です。これが popconfirm の体験の核心です。
- ネストしない:popconfirm の中にさらに popconfirm を入れると、ユーザーは今どの階層を確認しているのか困惑します。多段階の確認には dialog を使ってください。
- トリガーが無効化されたボタンの場合:
disabledのボタンはイベントをトリガーせず(ブラウザの制限)、popconfirm が開けません——業務層で自行処理してください(無効化されていない要素で包むか、無効化時にレンダリングしない)。 - 非同期確認のクローズタイミング:confirm の処理中は 2 つのボタンを無効化 + マスクで重複クリックを防止し、失敗時はバルーンを開いたままにしてエラーを提示し、成功したら閉じます。onConfirm の中で同期的にバルーンを閉じるのはよくあるバグです。
- message との連携:確認完了後に
messageで成功フィードバック(「削除しました」)を与える——两者は「確認 → 実行 → フィードバック」の標準的な流れです。 - モバイルでの hover トリガー:popover と同様、タッチスクリーンに hover はありません。クロス端末ではデフォルトで click トリガーを使ってください。
role="alertdialog"はボタンの暗黙のセマンティクスを含まない:ボタン領域は本物の<button>としてレンダリングしなければ(div + onclick ではなく)、キーボードのユーザーが操作できません。
@lh-ui/share/core/popconfirm → getPopconfirmIconName( )(填好参数后点运行)Copyright © 2024-2026 FengMo WenXue