import type { Snippet } from 'svelte'; import type { HTMLAttributes } from 'svelte/elements'; import type { SidebarLayoutSlots, SidebarLayoutVariants } from './sidebar-layout.variants.js'; /** * Snippet payload for the `mobileHeader` slot. Receives an opener for the * sidebar overlay so the consumer can wire a hamburger button without * threading state through the layout. */ export interface MobileHeaderContext { /** Open the sidebar (mobile overlay or collapsible panel). */ openSidebar: () => void; /** Current open state of the sidebar. */ sidebarOpen: boolean; } /** * Slot keys for `slotClasses`. The tv-driven slots (`SidebarLayoutSlots`: * root | mobileHeader | main | inner) are the layout's own; the `sidebar*` * keys are forwarded to the embedded `` (mapped to its * `slotClasses.panel`/`backdrop`/`header`/`content`/`footer`). */ type SidebarLayoutSlot = SidebarLayoutSlots | 'sidebar' | 'sidebarBackdrop' | 'sidebarHeader' | 'sidebarContent' | 'sidebarFooter'; /** * @summary The app shell — sidebar, content, and the mobile header that opens it. * @description App-shell layout that wires a `` to a main content * region and an optional mobile header. Use this whenever you want a * permanent sidebar on desktop with a hamburger overlay on mobile — it * resolves the CSS-variable scoping so the main content offset works without * boilerplate. * * The component renders the sidebar internally; consumers configure it via * `sidebarHeader`, `sidebar`, and `sidebarFooter` snippets and bind `open` * for the mobile overlay (or for collapsible mode at all viewports). * * For non-shell sidebars (right-side detail panels, drawers inside a page), * keep using the `` primitive directly. * * @tag layout * @tag navigation * @related Sidebar * * @example Default app shell with mobile header * ```svelte * * * * {#snippet sidebarHeader()} * My App * {/snippet} * * {#snippet sidebar()} * * {/snippet} * * {#snippet mobileHeader({ openSidebar })} * * My App * {/snippet} * *

Page content

*
* ``` * * @example Collapsible — toggleable on all viewports * ```svelte * * {#snippet sidebarHeader()}App{/snippet} * {#snippet sidebar()}{/snippet} * * * * * ``` */ export interface SidebarLayoutProps extends Omit, 'children'> { /** * Sidebar visibility. In `responsive` mode this only affects the mobile * overlay. In `collapsible` mode it controls visibility at all viewports. * Supports `bind:open`. * @default false */ open?: boolean; /** * Sidebar mode. * - `responsive` (default): permanent on desktop (≥1024px), slide-in overlay on mobile. * - `collapsible`: toggleable at all viewports — width animation on desktop, overlay on mobile. * @default 'responsive' * @summary Whether the sidebar is permanent on desktop, or toggleable at every width. */ mode?: 'responsive' | 'collapsible'; /** Which edge the sidebar attaches to. @default 'left' */ side?: SidebarLayoutVariants['side']; /** * Sidebar panel width. Single source of truth — the layout exposes it as * `--sidebar-width` (constant) and `--sidebar-effective-width` (animates to * `0` when collapsed) on the layout root, so the main content offset stays * in sync automatically. * @default '16rem' * @summary How wide the sidebar panel is; the content offset follows it automatically. */ sidebarWidth?: string; /** Close the mobile sidebar overlay when pressing Escape. @default true */ closeOnEscape?: boolean; /** Close the mobile sidebar overlay when clicking the backdrop. @default true */ closeOnBackdropClick?: boolean; /** Maximum width of the centered content column. @default 'xl' */ contentMaxWidth?: SidebarLayoutVariants['contentMaxWidth']; /** Fires when the sidebar open state changes. */ onOpenChange?: (open: boolean) => void; /** Sidebar header (above the scrollable nav). */ sidebarHeader?: Snippet; /** Sidebar main content — typically a `