Drawer slot
canonNon-modal panel slot beside the page; the side is chosen away from the click and the content survives closing.
Slot rendered by AppShell; screens fill it through <ShellDrawer>. .as-drawer.full was removed on 11 September 2026 (NAV-1, acrm !3403) — it had had no consumer since P276.
Used in 11 files · 11 areas · 11× — pages/AiZamestnanciPage, pages/DochazkaPage, pages/FirmyPage, pages/LidePage, pages/MajetekPage, pages/PipelinePage …
Default
export const Default = () => {
const [side, setSide] = useState<'left' | 'right' | null>('right');
return (
<Main>
<Rows onOpen={setSide} />
{side ? (
<div className={'as-drawer as-drawer-' + side}>
<Panel onClose={() => setSide(null)} />
</div>
) : null}
</Main>
);
};Variants
docked right — the default side
docked left — chosen when the user clicked on the right half, so the panel never covers the row that opened it
export const Variants = () => (
<div style={{ display: 'grid', gap: 'var(--sp-5)' }}>
<Labeled text="docked right — the default side">
<Main h={280}>
<Rows />
<div className="as-drawer as-drawer-right">
<Panel />
</div>
</Main>
</Labeled>
<Labeled text="docked left — chosen when the user clicked on the right half, so the panel never covers the row that opened it">
<Main h={280}>
<Rows />
<div className="as-drawer as-drawer-left">
<Panel name="Eva Dvořáková" />
</div>
</Main>
</Labeled>
</div>
);States
empty — the slot is rendered but holds nothing, and it lets clicks through to the page under it (pointer-events on the slot are off, on its children back on)
occupied — the panel floats over the page; there is no scrim, so the list next to it stays live and clickable
export const States = () => {
const [open, setOpen] = useState(false);
return (
<div style={{ display: 'grid', gap: 'var(--sp-5)' }}>
<Labeled text="empty — the slot is rendered but holds nothing, and it lets clicks through to the page under it (pointer-events on the slot are off, on its children back on)">
<Main h={220}>
<Rows onOpen={() => setOpen(true)} />
{open ? (
<div className="as-drawer as-drawer-right">
<Panel onClose={() => setOpen(false)} />
</div>
) : null}
</Main>
</Labeled>
<Labeled text="occupied — the panel floats over the page; there is no scrim, so the list next to it stays live and clickable">
<Main h={280}>
<Rows />
<div className="as-drawer as-drawer-right">
<Panel />
</div>
</Main>
</Labeled>
</div>
);
};Composition
export const Composition = () => {
const [side, setSide] = useState<'left' | 'right' | null>(null);
return (
<div
style={{
border: '1px solid var(--border)',
borderRadius: 'var(--radius-md)',
overflow: 'hidden',
}}
>
<header className="as-top">
<div className="as-brandzone">
<div className="as-mode">
<button className="as-modebtn">
<span className="tile crm">
<Icon name="target" />
</span>
<span className="ml" style={{ fontWeight: 600 }}>
CRM
</span>
</button>
</div>
</div>
<button type="button" className="as-search" aria-label="Hledat">
<Icon name="search" />
<span className="ph">Hledat…</span>
<kbd className="acrm-kbd">⌘K</kbd>
</button>
<div className="as-util" />
</header>
<div style={{ display: 'flex', height: 320 }}>
<aside className="as-side" style={{ minHeight: 0 }}>
<nav className="as-nav">
<button type="button" className="as-row active" aria-current="page">
<Icon name="users" />
<span className="lbl">Lidé</span>
</button>
<button type="button" className="as-row">
<Icon name="building" />
<span className="lbl">Firmy</span>
</button>
</nav>
</aside>
<Main h={320}>
<Rows onOpen={setSide} />
{side ? (
<div className={'as-drawer as-drawer-' + side}>
<Panel onClose={() => setSide(null)} />
</div>
) : null}
</Main>
</div>
</div>
);
};