import { type ReactNode } from "react"; import { type GestureResponderEvent } from "react-native"; import { type BreakpointKey, type ColorTokens, type StyleProp, type ViewStyle, type TextStyle } from "../../style/index.js"; import { type HoverMotion } from "../../style/hover.js"; import { Drawer as WebDrawer } from "../drawer/drawer.js"; import { Badge as WebBadge } from "../../atoms/badge/badge.js"; import { Avatar as WebAvatar } from "../../atoms/avatar/avatar.js"; import { type Density, type Frame } from "./sidebar.styles.js"; import { type SidebarItem, type SidebarSection } from "./sidebar.item.js"; /** The Icon color booleans a nav row's glyph can carry, per active state (the * skin picks foreground (default), `muted`, or brand `primary`). */ export type SidebarIconTint = { primary?: boolean; muted?: boolean; }; export interface SidebarSkin { /** Web paints the accent fill on a pressed (non-active) row; iOS/Android don't. */ pressedFill: boolean; /** iOS dims the row on press; web/Android don't (null). */ pressedOpacity: number | null; /** Android ripple over a pressed row; null on iOS/web. */ ripple: ((t: ColorTokens) => { color: string; borderless: boolean; }) | null; /** * Where the keyboard focus ring sits on the row Pressables: INSET_FOCUS_RING draws it * just inside the full-width row, which the column's scroll clip would otherwise cut. * The ring itself is the kit Pressable's (the palette's `ring`). No-op natively. */ focusRing?: ViewStyle; /** * The hover wash on a nav row: its timing and its colour. Painted beneath the row by its * frame (`SidebarRowFrame`), so the row's pressed and active fills still switch at once; * a translucent colour reads over the rail's surface and over glass alike. Omitted by * the iOS and Android skins, which keep their platform rows (and whose platforms deliver * no pointer hover by default). */ wash?: { motion: HoverMotion; color: (t: ColorTokens) => string; }; /** The outer navigation column, per frame. `collapsed` swaps to the rail width; * `shell` (a header/footer is present) drops the inner padding/gap onto the * scroll body and fills the parent height. */ column: (t: ColorTokens, frame: Frame, collapsed: boolean, shell: boolean) => ViewStyle; /** A titled group of nav rows (the row spacing), per density. */ group: (density: Density) => ViewStyle; /** The heading line above a pinned group (its inset; the title and count sit at either end). */ sectionHeading: (t: ColorTokens, density: Density) => ViewStyle; /** The heading's title type; `current` marks the reader's current place. */ sectionTitle: (t: ColorTokens, density: Density, current: boolean) => TextStyle; /** The section heading's trailing count (`SidebarSection.count`). */ sectionCount: (t: ColorTokens, current: boolean) => TextStyle; /** The nav-row container (shape + density padding); `collapsed` centers the icon. */ row: (t: ColorTokens, density: Density, collapsed: boolean) => ViewStyle; /** The selected-row highlight fill (null when not active). */ rowFill: (t: ColorTokens, active: boolean) => ViewStyle | null; /** The row label (flex, type, color), per active state + density; `lifted` is a * resting row of the current place, which may take a stronger ink. */ label: (t: ColorTokens, active: boolean, density: Density, lifted?: boolean) => TextStyle; /** The leading Canvas icon's color booleans, per active state. */ iconTint: (active: boolean) => SidebarIconTint; /** The leading Canvas icon size (px), per platform. */ iconSize: number; /** A row's count is the small quiet pill (the hand-off rail's) rather than the default one. */ smallCount?: boolean; /** The trailing marker dot `markers` draws: the active row's, or a marked row's. */ marker: (t: ColorTokens, kind: "active" | "marked") => ViewStyle; /** The panel width when collapsed. */ collapsedWidth: number; /** The header collapse/expand toggle button hit area. */ collapseToggle: (t: ColorTokens) => ViewStyle; /** The collapse toggle glyph size (glyph is `chevronLeft`, muted). */ collapseIconSize: number; /** The pinned header block (holds the brand slot + collapse toggle) + its divider. */ header: (t: ColorTokens, collapsed: boolean) => ViewStyle; /** The pinned footer block + its divider. */ footer: (t: ColorTokens, collapsed: boolean) => ViewStyle; /** The `account` card at the column's foot (pushed there by its own auto top margin); * `collapsed` keeps only the avatar, centred. */ account: (t: ColorTokens, collapsed: boolean) => ViewStyle; /** The account card's name line. */ accountName: (t: ColorTokens) => TextStyle; /** The account card's detail line under the name. */ accountDetail: (t: ColorTokens) => TextStyle; /** The scrolling body wrapper ({ flex: 1 }). */ scroll: ViewStyle; /** The scroll body contentContainer inset + inter-section gap. */ scrollContent: (t: ColorTokens, collapsed: boolean) => ViewStyle; /** The collapsible-section header row layout. */ sectionHeaderRow: (t: ColorTokens, density: Density) => ViewStyle; /** The collapsible-section header title type (flex, no standalone padding). */ sectionHeaderTitle: (t: ColorTokens, current: boolean) => TextStyle; /** The disclosure chevron glyph at rest (chevronRight iOS/web; chevronDown M3). */ sectionChevronGlyph: "chevronRight" | "chevronDown"; /** Degrees the chevron rotates to when open (90 iOS/web; 180 M3). */ sectionChevronSpinTo: number; /** The disclosure chevron glyph size. */ sectionChevronSize: number; /** The brand dot marking a section that holds the active row. */ activeDot: (t: ColorTokens) => ViewStyle; /** The back-row layout for a drilled-in level of the responsive drawer. */ drillBackRow: (t: ColorTokens) => ViewStyle; /** The back-row title type (the parent section's name). */ drillBackTitle: (t: ColorTokens) => TextStyle; } export type { SidebarItem, SidebarSection } from "./sidebar.item.js"; /** The signed-in account the `account` card names at the foot of the column. */ export interface SidebarAccount { /** The account or workspace name (e.g. "Northwind"). */ name: string; /** A short line under the name (e.g. "24 members"). */ detail?: string; /** The avatar photo (a URL or a bundled image); the name's initials without one. */ src?: string | number; } export interface SidebarProps { /** Titled sections of nav rows. Use this or the flat `items` array. */ sections?: SidebarSection[]; /** Flat list of nav rows, wrapped into a single untitled section. */ items?: SidebarItem[]; /** The active row (CONTROLLED), by id, by label, or by flat index across all rows. Omit for uncontrolled use. */ active?: string | number; /** Initial active row for uncontrolled use (a bare sidebar moves the highlight on press). */ defaultActive?: string | number; /** Fired with the selected row and its flat index across all sections. */ onSelect?: (item: SidebarItem, index: number, event: GestureResponderEvent) => void; compact?: boolean; /** A rounded card inside the field hairline. */ bordered?: boolean; /** A rounded card lifted on the medium shadow (the bordered card natively). */ floating?: boolean; /** Navigation groups embedded in an app-owned rail: no frame, fill or width of its * own and no scroll body (the host rail scrolls); the `header` and `footer` slots * stack above and below the groups as plain blocks. */ embedded?: boolean; /** Trailing marker dots: the accent on the active row, the field hairline on a row of * the current place (an item's `marked`, or every row of a `current` section). */ markers?: boolean; /** Collapsed to the mini icon-rail (CONTROLLED). Omit for uncontrolled use. */ collapsed?: boolean; /** Initial collapsed state for uncontrolled use (default expanded). */ defaultCollapsed?: boolean; /** Show the collapse/expand toggle in the header slot. */ collapsible?: boolean; /** Fired when the user taps the collapse/expand toggle. */ onToggleCollapse?: () => void; /** Open collapsible sections (CONTROLLED), by section id/title. A single key by * default, an array when `independentSections`. Pair with `onOpenSectionsChange`. */ openSections?: string | string[]; /** Initial open sections for uncontrolled use. */ defaultOpenSections?: string | string[]; /** Fired with the next open sections whenever a section header toggles. */ onOpenSectionsChange?: (value: string | string[]) => void; /** Allow more than one collapsible section open at once (default: one-open-at-a-time). */ independentSections?: boolean; /** Opt in to the responsive rail->drawer behavior. Off by default: a bare sidebar is the * inline rail at every width, byte-identical to before. */ responsive?: boolean; /** * Always the drill-down drawer, at every width, never the inline rail: for an app shell * whose only entry to the site tree is its own hamburger (a top app bar). Takes * the same `open` / `onOpenChange` wiring as `responsive`, and wins over it. */ drawer?: boolean; /** The narrow drawer's open state (CONTROLLED). The consumer wires its hamburger to this. */ open?: boolean; /** Initial open state for the uncontrolled narrow drawer (default closed). */ defaultOpen?: boolean; /** Fired when the narrow drawer opens or closes (scrim tap, back, or a leaf selection). */ onOpenChange?: (open: boolean) => void; /** The width at and below which `responsive` switches to the drawer (default `lg` = 1024). */ drawerBreakpoint?: BreakpointKey; /** The narrow drawer panel width in px (default 288). */ drawerWidth?: number; /** * Extra bottom padding for the drawer's scrolling content, so its last rows clear persistent * chrome painting over the drawer * * (e.g. a native bottom tab bar on Android). * * * (e.g. a native bottom tab bar). * */ drawerContentInsetBottom?: number; /** Slide the drawer in from the end (right) edge instead of the start (left). */ drawerRight?: boolean; /** Drop the drawer down from the top edge (a top sheet). */ drawerTop?: boolean; /** Raise the drawer up from the bottom edge (a bottom sheet). */ drawerBottom?: boolean; /** Optional top slot (a brand lockup / logo). A render function receives the * collapsed state so it can show a compact mark in the rail. When `header` or * `footer` is set, the panel becomes a pinned header + scrolling body (+ footer). */ header?: ReactNode | ((collapsed: boolean) => ReactNode); /** Optional bottom slot (pinned below the scrolling sections). A render function * receives the collapsed state so it can show a compact (icon-only) footer in the rail. */ footer?: ReactNode | ((collapsed: boolean) => ReactNode); /** * The signed-in account, drawn as a filled card pinned to the foot of the column: a * small avatar beside the name and a detail line in the third ink. The collapsed rail * keeps the avatar alone. It sits under the groups (above a `footer` slot), and in the * drawer under the drill-down. */ account?: SidebarAccount; /** * The name of the sidebar's navigation landmark, a short statement of what it navigates * ("Workspace", "Controls components"). A sidebar is a navigation landmark on every * platform, and a page holding two navigation landmarks needs a distinct name on each, so * a landmark list can tell them apart. In the narrow `responsive` drawer it names the * drawer. Omit it and the landmark stays unnamed, as before. */ accessibilityLabel?: string; /** E2E hook forwarded to the root element. */ testID?: string; /** Outer layout composition only (width/flex within a parent), never a restyle hook. */ style?: StyleProp; } export declare function densityOf(p: SidebarProps): Density; export declare function frameOf(p: SidebarProps): Frame; export declare function drawerEdgeOf(p: Pick): "left" | "right" | "top" | "bottom"; /** Build a Sidebar component from a platform skin. */ /** * The components a Sidebar draws with that look different per platform. The web * builds are the defaults; the iOS and Android entries pass their own, so the docs' * platform columns render them truthfully (a device resolves them by platform either way). */ export interface SidebarParts { Drawer?: typeof WebDrawer; /** A row's trailing count. */ Badge?: typeof WebBadge; /** The `account` card's avatar. */ Avatar?: typeof WebAvatar; } export declare function createSidebar(skin: SidebarSkin, parts?: SidebarParts): (props: SidebarProps) => import("react").JSX.Element; //# sourceMappingURL=sidebar.shared.d.ts.map