SegmentBar
A whole split into parts, each as wide as its share, so a person compares them at a glance: the sections of a song, the steps of a job, what fills a budget.
import { SegmentBar } from '@adecore/ui';import { useState } from 'react';
import { SegmentBar } from '@adecore/ui';
const SECTIONS = [
{ value: 12, label: 'Intro' },
{ value: 36, label: 'Verse' },
{ value: 28, label: 'Chorus' },
{ value: 4, label: 'Break' },
{ value: 30, label: 'Outro' }
];
const SCENES = [
{ start: 8, value: 30, label: 'Interview' },
{ start: 46, value: 22, label: 'B-roll' },
{ start: 80, value: 24, label: 'Credits' }
];
const BEATS = [
...Array.from({ length: 5 }, () => ({ value: 1, color: 'var(--positive)' })),
{ value: 1, current: true },
...Array.from({ length: 4 }, () => ({ value: 1 }))
];
const CONTEXT = [
{ value: 18, label: 'System', color: 'var(--text-faint)' },
{ value: 34, label: 'Files read', color: 'var(--status-running)' },
{ value: 21, label: 'Conversation', color: 'var(--positive)' }
];
export default function SegmentBarDemo() {
const [picked, setPicked] = useState(1);
return (
<div className="flex w-full max-w-xl flex-col gap-6">
<SegmentBar label="Sections" parts={SECTIONS.map((part, i) => ({ ...part, current: i === picked }))} onSelect={setPicked} />
<SegmentBar label="Sections" parts={SECTIONS.slice(0, 3)} range={[0, 110]} />
<SegmentBar label="Scenes" parts={SCENES} range={[0, 110]} />
<SegmentBar label="Beats" parts={BEATS} size="sm" />
<SegmentBar label="Context" parts={CONTEXT} range={[0, 128]} size="sm" />
</div>
);
}The parts follow each other from 0, each as long as its value. Their bounds line up with anything drawn over the same stretch, such as the marks of a Waveform. A very narrow part may not show.
A part with its own start begins there, and the stretch before it stays empty. The parts still go in order.
range sets the stretch the bar shows, by default 0 to the end of the last part. A longer range leaves the rest empty, so bars side by side compare by eye. A shorter one shows the visible part of a zoomable timeline.
<SegmentBar label="Sections" parts={[{ value: 12, label: 'Intro' }, { value: 36, label: 'Verse', current: true }]} range={[0, 110]} />
<SegmentBar label="Scenes" parts={[{ start: 8, value: 30, label: 'Interview' }, { start: 46, value: 22, label: 'B-roll' }]} range={[0, 110]} />The default size draws each label in its part, cut short where it does not fit, with a Tooltip for the whole label. size="sm" is a thin bar that shows labels only as a tooltip.
A part takes the theme's color, or any CSS color in color, such as var(--positive). current draws a part in the accent; color wins over it.
With onSelect every part is a button that passes its index in parts. Give every part a label then, as the button's name.
A screen reader hears the parts as a list, by label, with the current one marked. A bar without labels and onSelect is hidden from it, so name the whole on the element around it.
Props
| Prop | Type | Default | |
|---|---|---|---|
parts | readonly SegmentBarPart[] | Required. | |
range | readonly [from: number, to: number] | 0 up to the end of the last part | The stretch it shows, in the unit of the parts. |
size | 'sm' | 'md' | 'md' | sm is thin without visible labels. |
onSelect | (index: number) => void | Makes every part a button. | |
label | string | The name of the whole. | |
className | string | ||
ref | Ref<HTMLOListElement> |
A SegmentBarPart has these fields:
| Field | Type | |
|---|---|---|
value | number | Required. Its length, in the unit of range. |
start | number | Where it starts, in the unit of range. Defaults to the end of the part before, or 0. |
label | string | Drawn where there is room, and always read by a screen reader. |
color | string | Any CSS color in place of the theme's. |
current | boolean | The part a person is at. |
SegmentBarProps and SegmentBarPart are exported types.