Skip to content
fandhe-frontendcore v0.4.3
GitHub

Timer

カウントダウン/カウントアップを表示する unstyled 部品です。時計 API を一切使わず、時間の前進は tick(デルタミリ秒)の明示的な注入のみで進む決定的な状態機械です。

Themes 版(fandhe-frontend-pre-styled-ui)はこの構造へ既定 CSS を追加するだけの薄いラッパーであり、CSS は持ちません。スタイル済みの表示例は Timer を参照してください。

実際の計時駆動(setInterval 相当)はクライアントランタイム側の責務であり、本部品は経過値の表示 anatomy と現在フェーズの表示状態のみを提供します。

キーボード操作

キー対象効果
TabActionTriggerネイティブ <button type="button"> へのフォーカス移動です。hidden な ActionTrigger(下記「参考サイトとの差分」参照)はフォーカス対象から外れます。
Enter / SpaceActionTriggerネイティブ <button> の起動です。参考サイト(ark-ui / Zag.js)に専用の Keyboard Interactions 表はなく、本実装もブラウザ標準動作に委ねます。

参考サイトとの差分

一次ソース(zag.js packages/machines/timer/src/timer.connect.ts。chakra-ui v3 / Radix Primitives / Radix Themes に Timer は存在しない)と突合し、以下を是正しました。

  • area の ARIA: role="timer" と aria-atomic="true" を無条件付与するよう是正しました(旧版は付与していませんでした)。aria-label(既定書式 "{days} days {hh}:{mm}:{ss}")は Timer::area 利便メソッド経由で注入されます(area 自由関数自体は aria-label を持ちません)。
  • separator の ARIA: aria-hidden="true" を無条件付与するよう是正しました(装飾用の区切り文字を支援技術に読み上げさせないため)。
  • action_trigger の hidden 導出: 第 2 引数に現在の TimerPhase を受け取り、zag.js と同じ真偽式(running/paused の 2 述語)で hidden 属性の要否を導出するよう破壊的変更しました。
  • TimerControl::Restart(5 値目): zag.js(validActions 集合・restart: () => false)は start/pause/resume/reset/restart の 5 値を持ちますが、是正前の本実装は restart を欠いていました。zag.js に合わせて追加し、常に可視(hidden を持たない)としました。

一方、以下は意図的に参考サイトへ合わせていません。

  • Completed 状態: zag.js は完了到達時に idle へ戻りますが、本実装は data-state="completed" で完了を表現し続ける拡張を維持します。可視性は running/paused のいずれでもないため idle と同じです(Start/Restart のみ表示)。
  • Start の任意フェーズ受理: zag.js の START は idle 限定ですが、本実装は任意フェーズから running へ遷移できます。hidden により running/paused では UI 上到達不能なため実害はありません。
  • item の style="--value: N": zag.js は CSS カウンタ用の style 属性を付与しますが、装飾・レイアウト計測の関心を headless 層へ持ち込まない方針(docs/policy/intentional-non-adoption.md §3.25)により非採用です。必要な場合は呼び出し側 CSS か Themes 層で対応してください。
  • root の data-*: data-state/data-countdown/data-start-ms/data-target-ms/data-interval/data-elapsed は zag.js の root プロパティ(id のみ)に対する本実装の superset です。クライアント配線層(wasm-full)と Themes 側 CSS がこれらへ依存します。
  • id / dir / translations / asChild: 非対応です(translations.areaLabel 相当の差し替えは呼び出し側 attrs の aria-label で代替できます)。

関連 API: fandhe-frontend-headless-ui API

自前 CSS の最小例

Themes 版を使わず本部品を直接使う場合、action-trigger に [hidden] { display: none; } を必ず併記してください(display を宣言する規則が先に一致すると、ブラウザ既定の [hidden] { display: none } を上書きしてしまいます)。

CSS
[data-scope="timer"][data-part="area"] {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

[data-scope="timer"][data-part="item-value"] {
  font-variant-numeric: tabular-nums;
  font-size: 1.5rem;
}

[data-scope="timer"][data-part="root"][data-state="completed"] [data-part="item-value"] {
  color: #2563eb;
}

[data-scope="timer"][data-part="action-trigger"] {
  display: inline-flex;
  padding: 0.5rem 0.875rem;
  border: 1px solid #888;
  border-radius: 6px;
}

/* [hidden] を上書きしないよう、display 宣言を持つ規則には必ず併記する。 */
[data-scope="timer"][data-part="action-trigger"][hidden] {
  display: none;
}

Demo

枠線・余白は docs サイト側のデモ枠であり、fandhe-frontend-headless-ui 自体はスタイルを持ちません。

00min
45sec

Features

  • Root/Area/Item/ItemValue/ItemLabel/Separator/Control/ActionTrigger の 8 anatomy パーツと、idle/running/paused/completed の 4 値状態機械 Timer を提供する。
  • 時計 API(std::time・Instant・js_sys::Date)を一切使用しない。時間の前進は TimerAction::Tick(デルタミリ秒)の明示的注入のみで行われ、同一 tick 列を dispatch すれば常に同一の状態列に到達する決定的設計。
  • countdown/start_ms/target_ms/interval_ms/elapsed_ms を data-* としてそのまま出力し、クライアント配線層がこれらを読み取って tick 駆動・完了判定の表示反映を行う契約。
  • 実 tick 駆動(setInterval 相当)・ロケール依存の表示形式は本コンポーネントの責務外であり、ミリ秒の加算とゼロ埋め 2 桁整形のみを提供する(docs/policy/intentional-non-adoption.md §3.25)。

Anatomy

root
  area
    item
      item-value
      item-label
    separator
  control
    action-trigger

API Reference

Arguments

NameTypeDefaultDescription
countdownbool(必須)カウントダウン(true)かカウントアップ(false)か。
start_ms / target_msu64(必須)カウントダウンの開始値・カウントアップの目標値(target_ms = 0 は無期限)。
interval_msu641000tick の間隔(表示上のヒント。実 tick 駆動はクライアント配線層の責務)。
elapsed_msu640経過ミリ秒。data-elapsed へ反映される。
phaseTimerPhase(必須)data-state へ反映する現在フェーズ(idle/running/paused/completed)。

Data Attributes

PartAttributeObserved Values
action-triggerdata-actionpause, reset
itemdata-typeminutes, seconds
item-labeldata-typeminutes, seconds
item-valuedata-typeminutes, seconds
rootdata-countdown(値なし)
rootdata-elapsed15000
rootdata-interval1000
rootdata-start-ms0
rootdata-staterunning
rootdata-target-ms60000

Examples

完了状態(Completed)

TimerPhase::Completed を渡すと data-state="completed" となります。action_trigger の可視性は TimerControl::is_hidden_in が zag.js と同じ真偽式で導出し、Completed は running/paused のいずれでもないため Idle と同じ可視性(Start/Restart のみ表示、Pause/Resume/Reset は hidden)になります。

00sec

Accessibility

Keyboard Interactions

KeyDescription
Tab / Space / Enteraction_trigger はネイティブ <button type="button"> であり、フォーカス・押下操作はブラウザ既定動作で成立する。