メインコンテンツまでスキップ

ConnectionIndicator コンポーネント

接続状態をリアルタイムで表示するコンポーネント。


概要

目的: ユーザーに現在の接続状態を一目で伝える

使用場面:

  • メイン画面のヘッダー
  • セッション中の常時表示エリア
  • ミキサーの各参加者チャンネル

Props / API

interface ConnectionIndicatorProps {
/** 接続状態 */
status: ConnectionStatus;

/** RTT(往復遅延)をミリ秒で表示 */
latencyMs?: number;

/** 遅延値を表示するか */
showLatency?: boolean;

/** サイズ */
size?: 'sm' | 'md' | 'lg';

/** クリック時のハンドラ(詳細表示へ遷移など) */
onClick?: () => void;
}

type ConnectionStatus =
| 'disconnected'
| 'connecting'
| 'connected'
| 'unstable'
| 'error';

Props 詳細

Prop必須デフォルト説明
statusConnectionStatus-現在の接続状態
latencyMsnumber-undefinedRTT値(ms)
showLatencyboolean-true遅延値を表示するか
size'sm' | 'md' | 'lg'-'md'コンポーネントサイズ
onClickfunction-undefinedクリックハンドラ

状態とバリアント

接続状態

Statusアイコンテキスト(JA)テキスト(EN)
disconnected--color-status-disconnected○ (空)未接続Disconnected
connecting--color-status-connecting↻ (回転)接続中...Connecting...
connected--color-status-connected● (塗り)接続中Connected
unstable--color-status-unstable不安定Unstable
error--color-status-error切断されましたDisconnected

サイズ

Sizeアイコンサイズフォントサイズ用途
sm12px--font-size-captionミキサーチャンネル
md16px--font-size-bodyメイン画面ヘッダー
lg20px--font-size-h3フルスクリーン表示

ビジュアル仕様

レイアウト

┌─────────────────────────────┐
│ [●] 接続中(15ms) │
└─────────────────────────────┘
↑ ↑ ↑
│ │ └─ 遅延値(latencyMsが設定時)
│ └─ ステータステキスト
└─ ステータスアイコン

各状態の表示例

未接続 (disconnected)

○ 未接続

接続中 (connecting)

↻ 接続中...   ← アイコンが回転アニメーション

接続済み (connected)

● 接続中(15ms)   ← 遅延値は表示設定による

不安定 (unstable)

⚠ 不安定(45ms)   ← 黄色で警告

エラー (error)

✕ 切断されました   ← 赤色

色の適用

.connection-indicator {
display: inline-flex;
align-items: center;
gap: var(--space-xs);
}

.connection-indicator__icon {
width: 16px; /* size=md の場合 */
height: 16px;
}

.connection-indicator--disconnected .connection-indicator__icon {
color: var(--color-status-disconnected);
}

.connection-indicator--connecting .connection-indicator__icon {
color: var(--color-status-connecting);
animation: spin 1s linear infinite;
}

.connection-indicator--connected .connection-indicator__icon {
color: var(--color-status-connected);
}

.connection-indicator--unstable .connection-indicator__icon {
color: var(--color-status-unstable);
}

.connection-indicator--error .connection-indicator__icon {
color: var(--color-status-error);
}

@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}

アニメーション

接続中 (connecting)

.connection-indicator--connecting .connection-indicator__icon {
animation: spin 1s linear infinite;
}

/* 演奏中は回転を停止(CPU負荷軽減) */
.session-active .connection-indicator--connecting .connection-indicator__icon {
animation: none;
}

@media (prefers-reduced-motion: reduce) {
.connection-indicator--connecting .connection-indicator__icon {
animation: none;
}
}

状態変更時

.connection-indicator__icon {
transition: color var(--transition-normal);
}

.connection-indicator__text {
transition: color var(--transition-normal);
}

アクセシビリティ

ARIA 属性

<div
role="status"
aria-live="polite"
aria-label={getAriaLabel(status, latencyMs)}
className={`connection-indicator connection-indicator--${status}`}
>
<span className="connection-indicator__icon" aria-hidden="true">
{getIcon(status)}
</span>
<span className="connection-indicator__text">
{getText(status, latencyMs)}
</span>
</div>

aria-label の構築

function getAriaLabel(status: ConnectionStatus, latencyMs?: number): string {
const statusLabels = {
disconnected: '接続状態: 未接続',
connecting: '接続状態: 接続中',
connected: latencyMs
? `接続状態: 接続中、遅延${latencyMs}ミリ秒`
: '接続状態: 接続中',
unstable: latencyMs
? `接続状態: 不安定、遅延${latencyMs}ミリ秒`
: '接続状態: 不安定',
error: '接続状態: 切断されました',
};
return statusLabels[status];
}

スクリーンリーダー

  • role="status" で状態変更を通知
  • aria-live="polite" で他の読み上げを邪魔しない
  • 状態変更時にスクリーンリーダーが自動的に読み上げる

キーボード操作

  • onClick が設定されている場合、tabindex="0" を追加
  • Enter/Space でクリックイベント発火

i18n キー

{
"status": {
"disconnected": "未接続",
"connecting": "接続中...",
"connected": "接続中",
"unstable": "不安定",
"error": "切断されました",
"latency": "{{ms}}ms"
}
}

使用例

import { useTranslation } from 'react-i18next';

function ConnectionIndicator({ status, latencyMs }: Props) {
const { t } = useTranslation();

const text = t(`status.${status}`);
const latency = latencyMs ? t('status.latency', { ms: latencyMs }) : '';

return (
<div className={`connection-indicator connection-indicator--${status}`}>
{/* ... */}
</div>
);
}

使用例

基本使用

<ConnectionIndicator status="connected" latencyMs={15} />

遅延非表示

<ConnectionIndicator status="connected" showLatency={false} />

ミキサーチャンネル(小サイズ)

<ConnectionIndicator status="connected" latencyMs={15} size="sm" />

クリック可能(詳細表示へ遷移)

<ConnectionIndicator
status="connected"
latencyMs={15}
onClick={() => navigate('/connection-info')}
/>

状態に応じた条件分岐

function SessionHeader({ connectionStatus, latencyMs }: Props) {
return (
<header className="session-header">
<ConnectionIndicator
status={connectionStatus}
latencyMs={connectionStatus === 'connected' ? latencyMs : undefined}
/>
{/* ... */}
</header>
);
}

テスト観点

ユニットテスト

  • 各 status で正しいアイコンと色が表示される
  • latencyMs が設定されると遅延値が表示される
  • showLatency=false で遅延値が非表示になる
  • size に応じてサイズが変わる
  • onClick が設定されるとクリック可能になる

アクセシビリティテスト

  • status 変更時に aria-label が更新される
  • スクリーンリーダーで状態が読み上げられる
  • キーボードでフォーカス・クリックできる

ビジュアルリグレッションテスト

  • 各 status のスナップショット
  • 各 size のスナップショット
  • ダーク/ライトテーマでの表示

実装ファイル構成

ui/src/components/ConnectionIndicator/
├── ConnectionIndicator.tsx # コンポーネント本体
├── ConnectionIndicator.css # スタイル
├── ConnectionIndicator.test.tsx # テスト
├── icons.tsx # 各状態のアイコン
└── index.ts # エクスポート