Picker panel
canonAnchored floating container that hosts the calendar or time list.
Used in 8 files · 7 areas · 8× — components/callwrapup, components/color, components/projects, components/segment, components/tasks, components/timeline …
Default
červenec 2026
export const Default = () => {
const ref = useRef<HTMLDivElement>(null);
const [open, setOpen] = useState(true);
const [value, setValue] = useState<string | null>('2026-07-26');
return (
<div>
<Anchor text="26. 7." open={open} onToggle={() => setOpen((v) => !v)} anchorRef={ref} />
<PickerPanel
open={open}
anchorRef={ref}
onClose={() => setOpen(false)}
ariaLabel="Vybrat datum"
>
<Calendar
mode="single"
value={value}
today={TODAY}
presets={singleDatePresets(TODAY)}
onChange={(v) => {
setValue(v);
setOpen(false);
}}
/>
<div className="dp-foot">
<div className="dp-rule" />
<button
type="button"
className="dp-clear"
onClick={() => {
setValue(null);
setOpen(false);
}}
>
<Icon name="x" />
Vymazat
</button>
</div>
</PickerPanel>
<Room h={400} />
</div>
);
};Variants
calendar body (.dp-pop)
time list body (.dp-timelist)
červenec 2026
export const Variants = () => {
const calRef = useRef<HTMLDivElement>(null);
const timeRef = useRef<HTMLDivElement>(null);
const [calOpen, setCalOpen] = useState(true);
const [timeOpen, setTimeOpen] = useState(true);
const [date, setDate] = useState<string | null>('2026-07-26');
const [time, setTime] = useState(9 * 60 + 30);
const times = Array.from({ length: 8 }, (_, i) => 8 * 60 + i * 15);
const hm = (m: number) => `${Math.floor(m / 60)}:${String(m % 60).padStart(2, '0')}`;
return (
<div style={{ display: 'grid', gridTemplateColumns: '320px 240px', gap: 'var(--sp-6)' }}>
<Labeled label="calendar body (.dp-pop)">
<Anchor
text="26. 7."
open={calOpen}
onToggle={() => setCalOpen((v) => !v)}
anchorRef={calRef}
/>
<PickerPanel
open={calOpen}
anchorRef={calRef}
onClose={() => setCalOpen(false)}
ariaLabel="Vybrat datum"
>
<Calendar
mode="single"
value={date}
today={TODAY}
onChange={(v) => {
setDate(v);
setCalOpen(false);
}}
/>
</PickerPanel>
</Labeled>
<Labeled label="time list body (.dp-timelist)">
<div className="dp-field time" ref={timeRef}>
<input
className="dp-input"
value={hm(time)}
aria-label="Čas"
readOnly
onClick={() => setTimeOpen((v) => !v)}
/>
</div>
<PickerPanel
open={timeOpen}
anchorRef={timeRef}
onClose={() => setTimeOpen(false)}
ariaLabel="Čas"
>
<div className="dp-timelist" role="listbox" aria-label="Čas">
{times.map((t) => (
<button
type="button"
key={t}
className={'dp-topt' + (t === time ? ' on' : '')}
role="option"
aria-selected={t === time}
onClick={() => {
setTime(t);
setTimeOpen(false);
}}
>
<span>{hm(t)}</span>
</button>
))}
</div>
</PickerPanel>
</Labeled>
<Room h={340} />
</div>
);
};Composition
range picker — anchor .dp-field.wide, body .dp-pop.range
–8 dní
červenec 2026srpen 2026
export const Composition = () => {
const ref = useRef<HTMLDivElement>(null);
const [open, setOpen] = useState(true);
const [range, setRange] = useState<CalendarRange>({ from: '2026-07-14', to: '2026-07-21' });
return (
<div>
<Labeled label="range picker — anchor .dp-field.wide, body .dp-pop.range">
<Anchor
text="14. 7. – 21. 7."
open={open}
onToggle={() => setOpen((v) => !v)}
anchorRef={ref}
wide
/>
</Labeled>
<PickerPanel
open={open}
anchorRef={ref}
onClose={() => setOpen(false)}
ariaLabel="Vybrat rozsah"
dep={range.from + '|' + range.to}
>
<Calendar
mode="range"
months={2}
value={range}
today={TODAY}
presets={pastRangePresets(TODAY)}
head={
<div className="dp-entry pair">
<Icon name="calendar" />
<input aria-label="Od" placeholder="od" readOnly value="14. 7." />
<span className="dash">–</span>
<input aria-label="Do" placeholder="do" readOnly value="21. 7." />
<span className="count">8 dní</span>
</div>
}
onChange={(v, done) => {
setRange(v);
if (done && v.from && v.to) setOpen(false);
}}
/>
<div className="dp-foot">
<div className="dp-rule" />
<button
type="button"
className="dp-clear"
onClick={() => {
setRange({ from: null, to: null });
setOpen(false);
}}
>
<Icon name="x" />
Vymazat
</button>
</div>
</PickerPanel>
<Room h={460} />
</div>
);
};