Bulk action bar
canonFloating pill at the bottom of a table or list once rows are selected: count, actions, ⋮ for the rest and × to clear; folds to one inline action on phones.
Beta 5 Oct 2026 (acrm !4743): one implementation everywhere (Lidé, Firmy, Segment, Pipeline table, Datamart, Komunikace). Phone (≤ 720 px) folding into ⋮, × always visible, page FAB hidden, Esc clears selection everywhere. Dev check 5 Oct 2026 at 390: Lidé '3 vybráno · Vytvořit obchod · ⋯ · ×', FAB hidden. Open: overflow trigger uses dots (⋯) — align with canon dots-vertical in the record-actions-menu wave. Canon after that wave. Owner approved 11 Oct 2026 (item 17 c, acrm !4961, prototype proto/bulkbar-mobile@d457d2c90): on the phone „Vybrat všech N" is the first item in ⋮ (divider, actions, divider, Koš last; gone when all selected); the bar hides under an open sheet or modal dialog at every width; one rule in bulk-bar.css. Dev check 11 Oct (Komunikace, 360/390 light/dark): × inside the bar (309 < 316 / 324 < 331), ⋮ order as approved, bar hidden under the sheet. ⋮ tap target 43×43 (as prototype). Dev check 19 Oct 2026 (Lidé, real data): 1440 light/dark bar '2 vybráno · Vytvořit obchod · Změnit vlastníka · Exportovat · Smazat', 390 dark '2 vybráno · Vytvořit obchod · ⋮ · ×' (⋮ = dots-vertical, menu Změnit vlastníka · Exportovat · Smazat), FAB hidden, brown 0. Blocker for canon: Esc does not clear the selection when focus is on a row checkbox (BulkActionBar Esc guard skips every input, incl. type=checkbox) — contradicts a11y.md; fix in acrm, then canon. Esc blocker fixed in acrm !5293 (19 Oct 2026): checkbox/radio no longer count as a typing field; re-checked on dev (Lidé 1440, focus on the row checkbox → Esc clears, bar unmounts). Canon 19 Oct 2026 (AD): stories Default · States · Composition, usage + a11y, dev check 1440/390 light/dark.
Used in 8 files · 4 areas · 8× — components/segment, pages/PipelinePage, pages/datamart, pages/komunikace
Default
export const Default = () => (
<Stack>
<Frame text="3 rows selected — Lidé: actions inline, × clears (Esc)">
<Bar count={3} inline={PEOPLE} />
</Frame>
</Stack>
);States
export const States = () => (
<Stack>
<Frame text="Page fully selected, filter has more → „Vybrat všech N“">
<Bar count={50} inline={PEOPLE} selectAll={160} />
</Frame>
<Frame text="Whole filter selected">
<Bar count={160} inline={PEOPLE} allMatching />
</Frame>
<Frame text="Action unavailable for this selection (disabled, hint in title)">
<Bar
count={3}
noun="členů · 0 nových"
inline={[{ key: 'take', label: 'Převzít vybrané (0)', icon: 'download', disabled: true }]}
/>
</Frame>
<Frame text="Less frequent actions in „⋮“ (Komunikace)">
<Bar
count={3}
noun="zprávy"
selectAll={50}
inline={[
{ key: 'done', label: 'Hotovo', icon: 'archive' },
{ key: 'snooze', label: 'Odložit', icon: 'clock' },
{ key: 'read', label: 'Přečteno', icon: 'mail-opened' },
{ key: 'delegate', label: 'Delegovat…', icon: 'user-share' },
]}
overflow={[
{ key: 'star', label: 'Hvězda', icon: 'star' },
{ key: 'trash', label: 'Koš', icon: 'trash', danger: true },
]}
/>
</Frame>
</Stack>
);Composition
export const Composition = () => (
<Stack>
<Frame
text="Phone 390 px — one inline action, the rest in „⋮“, × always visible"
width={390}
height={160}
>
<Bar count={3} inline={PEOPLE.slice(0, 1)} overflow={PEOPLE.slice(1)} />
</Frame>
<Frame
text="Phone 390 px — Komunikace keeps Delegovat… inline (primary); „Vybrat všech N“ moves to „⋮“ (it did not fit, × overflowed the edge)"
width={390}
height={160}
>
<Bar
phone
count={3}
noun="zprávy"
selectAll={50}
inline={[{ key: 'delegate', label: 'Delegovat…', icon: 'user-share' }]}
overflow={COMMS_MORE}
/>
</Frame>
<div style={{ display: 'grid', gap: 'var(--sp-2)' }}>
{/* Statická replika otevřeného „⋮" na telefonu (živé menu je v portálu / šuplíku). */}
<StaticPopover width={300}>
<MenuItems
onDone={() => {}}
items={[
{ key: 'select-all', icon: 'checks', label: 'Vybrat všech 50', onClick: () => {} },
{ key: 'sep-select-all', sep: true },
...COMMS_MORE.map((a) => ({
key: a.key,
icon: a.icon,
label: a.label,
danger: a.danger,
onClick: () => {},
})),
]}
/>
</StaticPopover>
<span style={{ color: 'var(--fg-muted)', font: 'var(--small)' }}>
Phone „⋮“ open — Vybrat všech N first · hairline · actions · hairline · Koš last; after „all
selected“ the item disappears. While this sheet or a confirm dialog is open the bar hides,
so it never covers their CTA.
</span>
</div>
<Frame text="Pipeline table — a single destructive action stays a quiet ghost; red only in confirm">
<Bar count={3} inline={[PEOPLE[3]!]} />
</Frame>
</Stack>
);