いちにちの帯DayBandExperimental

1日を1本の帯にして、時間帯を面で、節目を印で、いまの時刻とつまみの位置を重ねて見せます。日の出も「いま」も呼び出し側が渡す数で、部品は1日について何も計算しません。

プレビュー

東京 9月12日14:30
日の出 05:22日の入 17:56いま
06121824

状態とバリエーション

TimeTransport の中に入れる

操作盤の scrubber スロットへ差し込んだ形。帯を掴めば時刻が動き、「いまへ戻る」で戻ります。この組み合わせのために作られた部品です。⚠️ ここでの単位は「分」なので、TimeTransport の liveTolerance も分で渡しています(既定の 1000 はエポックミリ秒の1秒ぶんです)。

14:30
2026-09-12 JST
いまではない
日の出 05:22日の入 17:56いま
06121824

当番表

同じ形で当番表になります。時間帯にトーン名を渡すと、面のトークン(--*-subtle)へ解決します。節目の印は交代の時刻です。

3階病棟 9月12日14:30
交代 08:00交代 18:00
06121824

見せるだけ(sm)

onValueChange を渡さなければ操作を受け取らず、焦点も持ちません。value も外せば、つまみのない営業時間の帯になります。size="sm" は 24px です。

営業時間11:00 – 22:00
ラストオーダー 21:00
06121824

掴んで流す(relative)

触っただけでは動かず、掴んだ距離ぶんだけ動きます。細い帯で指が現在位置を隠さず、誤って触っても時刻が飛びません。0時をまたぐと帯の外の値も返るので、呼び出し側が日を入れ替えます。

14:30
日の出 05:22日の入 17:56いま
06121824

いちばん小さい形

時間帯だけ。印も時刻の数字も目盛りも外せます(marks を渡さず、hourLabels={[]}、tickEvery={0})。表の行の中など、狭いところに置くときの形です。

操作できない

帯全体が無効。読み取り専用の盤や、まだ日が決まっていないときに使います。

14:30
日の出 05:22日の入 17:56
06121824

プロパティ

表は横にスクロールできます
プロパティ初期値説明
min / maxnumber / number-1日の始まりと終わり。単位は呼び出し側のもので、既定は午前0時からの分です。実日付ならその日の0時のエポックミリ秒と +86400000 を渡します。phases・marks・value・now はすべてこの単位です。
valuenumber-つまみが指す位置。渡さなければつまみは出ません(見せるだけの帯になります)。
onValueChange(next: number) => void-掴んで動かしたときの次の位置。渡さなければ帯は操作を受け取らず、スライダーの役割も焦点も持ちません。
phasesDayBandPhase[]-1日の中の時間帯。{ start, end, label?, color? } で、面として敷かれます。color はトーン名(success など)か任意の CSS 色。トーンは面のトークン(--*-subtle)へ解決します。⚠️ 0時をまたぐ時間帯は2つに分けてください(22:00–24:00 と 00:00–06:00)。
marksDayBandMark[]-節目の印。{ at, label?, color? }。ラベルは帯の上の行に出ます(下の行は時刻の数字なので、ぶつかりません)。色がつくのは線だけで、文字は着色しません。
nownumber-「いま」の位置。印として描かれるので、動かしたあとも戻り先が見えます。⚠️ 時刻は effect の中で読んでください(部品は時計を持ちません)。
scrub"absolute" | "relative"-absolute は触った位置がそのまま時刻(ひと触りでどの時刻へも行けます)。relative は掴んだ距離ぶんだけ動く(指が現在位置を隠さず、触っただけでは動きません)。relative は0時をまたいで帯の外の値も返すので、呼び出し側が日を入れ替えます。
step / coarseStepnumber / number-矢印キーの刻みと、Shift+矢印・PageUp / PageDown の刻み。既定は15分と1時間ぶんです。Home / End は帯の両端へ飛びます。
tickEverynumber-帯の中に立てる目盛りの間隔(時間)。0 で消えます。
hourLabels / formatHournumber[] / (hour: number) => ReactNode-帯の下に出す時刻の数字と、その書式。既定は単位なしの数字なので、そのまま多言語に出せます。[] で行ごと消えます。
formatValue(value: number) => string-読み上げ(aria-valuetext)の書式。既定は1日の中の位置から出した HH:MM で、時間帯の名前が「10:40 · 昼」のように続きます。
size"sm" | "default"-帯の高さ。default は触れる 44px、sm は 24px で、見せるだけの帯に使います。
label / hintReactNode / ReactNode-帯の上の行。左が label(地点・日付・担当)、右が hint(いまの時刻・注記・合計)。現在時刻を出したいときは hint に渡します。
labelsDayBandLabels-組み込みの文字列の差し替え(band=帯の読み上げ名/now=「いま」の印の名前)。既定は英語です。
disabledboolean-帯を無効にし、タブ移動からも外します。

使い方

import { DayBand } from "@gunjo/ui";

// 既定の単位は「午前0時からの分」(min 0 / max 1440)。
// 実日付で使うなら min にその日の0時のエポックミリ秒、max に +86400000 を渡します。
export function SunBand() {
  const [value, setValue] = React.useState(640);

  return (
    <DayBand
      value={value}
      onValueChange={setValue}
      // ⚠️ 日の出・日の入は呼び出し側が渡します。部品は天文計算を持ちません。
      phases={[
        { start: 0, end: 260, label: "夜", color: "hsl(var(--gunjo-deepest))" },
        { start: 260, end: 322, label: "薄明", color: "hsl(var(--gunjo-deep))" },
        { start: 322, end: 1076, label: "昼", color: "hsl(var(--gunjo-bright))" },
        { start: 1076, end: 1138, label: "薄明", color: "hsl(var(--gunjo-deep))" },
        { start: 1138, end: 1440, label: "夜", color: "hsl(var(--gunjo-deepest))" },
      ]}
      marks={[
        { at: 322, label: "日の出 05:22", color: "warning" },
        { at: 1076, label: "日の入 17:56", color: "info" },
      ]}
      // ⚠️ いまの時刻は描画中ではなく effect の中で読んでください。
      now={nowMinutes}
      label="東京 9月12日"
      hint={formatClock(value)}
      labels={{ band: "いちにちの中の時刻", now: "いま" }}
    />
  );
}

// TimeTransport の掴んで動かす面として差し込む場合
<TimeTransport value={value} now={now} onValueChange={setValue}
  scrubber={<DayBand value={value} now={now} onValueChange={setValue} phases={PHASES} />} />

設計の判断

  • 時間帯の色は「面のトークン」へ解決します。success のようなトーン名は、強い色ではなく --success-subtle の側へ 落とします。時間帯は下地で、その上に印とつまみが乗るからです。空のような絵としての色が要るときは、任意の CSS 色をそのまま渡せます。
  • つまみは2色で描いています。下地の時間帯は明色でも暗色でもありうるので、背景色の線に前景色の縁を重ねています。 片方の色に賭けると、夜の帯か昼の帯のどちらかで必ず消えます。
  • 印のラベルは帯の上、時刻の数字は帯の下。出どころの実装は1つの行に詰めていたため、印から48px以内の時刻の数字を消して衝突を避けていました。 行を分ければ、消す必要がありません。
  • 指で触ったときは、押した瞬間には動きません。押した指がそのまま縦スクロールに変わることがあるためで、動かしたときか、指を離したとき (=はっきりした「触った」)に確定します。マウスとペンは押した瞬間です。 帯の上から始めた縦スクロールも止めません(touch-action: pan-y)。
  • 色だけに意味を載せません。読み上げには「10:40 · 昼」のように時間帯の名前が乗り、節目は文字のラベルを 持ち、時間帯にはポインタで読める名前がつきます。矢印・Shift+矢印・PageUp / PageDown・ Home / End で、触らずに1日を歩けます。
  • 0時をまたぐ時間帯は2つに分けます。1本の帯は1日です。startend 以上の時間帯は描かず、開発時に 警告を出します(黙って反対側を塗るより、言うほうが正しいためです)。