rich-react-component 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,65 @@
1
+ import { SidebarPresentation, SidebarTone, ThemeMode } from './Appearance';
2
+ import { ColorScheme } from './appearanceSchemes';
3
+ /**
4
+ * Every visible string is supplied by the caller — this component ships no
5
+ * built-in copy in any language, so it can be dropped into an application that
6
+ * owns its own localization.
7
+ */
8
+ export interface AppearanceMenuLabels {
9
+ presentation: {
10
+ title: string;
11
+ compact: string;
12
+ grouped: string;
13
+ };
14
+ mode: {
15
+ title: string;
16
+ light: string;
17
+ dark: string;
18
+ system: string;
19
+ };
20
+ tone: {
21
+ title: string;
22
+ light: string;
23
+ dark: string;
24
+ auto: string;
25
+ };
26
+ /** `options` maps a registered scheme id to its display name. */
27
+ colorScheme: {
28
+ title: string;
29
+ options: Record<string, string>;
30
+ };
31
+ }
32
+ /** Each section is hideable on its own. Omitted entries default to visible. */
33
+ export interface AppearanceMenuSections {
34
+ presentation?: boolean;
35
+ mode?: boolean;
36
+ tone?: boolean;
37
+ colorScheme?: boolean;
38
+ }
39
+ export interface AppearanceMenuProps {
40
+ labels: AppearanceMenuLabels;
41
+ sections?: AppearanceMenuSections;
42
+ className?: string;
43
+ /** Controlled values. When given, the provider is not written to for that setting. */
44
+ mode?: ThemeMode;
45
+ onModeChange?: (mode: ThemeMode) => void;
46
+ sidebarPresentation?: SidebarPresentation;
47
+ onSidebarPresentationChange?: (presentation: SidebarPresentation) => void;
48
+ sidebarTone?: SidebarTone;
49
+ onSidebarToneChange?: (tone: SidebarTone) => void;
50
+ colorSchemeId?: string;
51
+ onColorSchemeIdChange?: (id: string) => void;
52
+ /** Restrict/order the offered schemes. Defaults to every registered scheme. */
53
+ colorSchemes?: ColorScheme[];
54
+ }
55
+ /**
56
+ * Composable appearance selector. Drop it into a `Navbar` slot, a `Popover`,
57
+ * a `Menu` trigger's content, a settings drawer, or any application-owned
58
+ * container.
59
+ *
60
+ * Deliberately NOT a Metronic Layout Builder: it exposes exactly four
61
+ * independent settings and nothing else. It forces no persistence, mutates no
62
+ * global DOM, and makes no decision about who is allowed to change branding —
63
+ * those belong to the application.
64
+ */
65
+ export declare function AppearanceMenu({ labels, sections, className, mode, onModeChange, sidebarPresentation, onSidebarPresentationChange, sidebarTone, onSidebarToneChange, colorSchemeId, onColorSchemeIdChange, colorSchemes, }: AppearanceMenuProps): import("react").JSX.Element;
@@ -1,9 +1,16 @@
1
1
  import { ReactNode } from 'react';
2
2
  export type BadgeVariant = "primary" | "secondary" | "success" | "danger" | "warning" | "info" | "light" | "dark";
3
+ /**
4
+ * How the variant colour is applied. Additive: `solid` is the existing
5
+ * behaviour and stays the default, so no current rendering changes.
6
+ */
7
+ export type BadgeAppearance = "solid" | "light" | "outline";
3
8
  export interface BadgeProps {
4
9
  variant?: BadgeVariant;
10
+ /** `light` and `outline` are the restrained forms for ordinary metadata. */
11
+ appearance?: BadgeAppearance;
5
12
  pill?: boolean;
6
13
  className?: string;
7
14
  children: ReactNode;
8
15
  }
9
- export declare function Badge({ variant, pill, className, children }: BadgeProps): import("react").JSX.Element;
16
+ export declare function Badge({ variant, appearance, pill, className, children }: BadgeProps): import("react").JSX.Element;
@@ -1,5 +1,13 @@
1
1
  import { ButtonHTMLAttributes, ReactNode } from 'react';
2
- export type ButtonVariant = "primary" | "secondary" | "success" | "danger" | "warning" | "info" | "light" | "dark" | "link" | "outline-primary" | "outline-secondary";
2
+ export type ButtonVariant = "primary" | "secondary" | "success" | "danger" | "warning" | "info" | "light" | "dark" | "link" | "outline-primary" | "outline-secondary"
3
+ /**
4
+ * Contextual light variants — a soft tinted surface with the contextual
5
+ * foreground, the Metronic Bootstrap signature for a secondary action.
6
+ * Added additively; Bootstrap has no `btn-light-*` rule of its own, so these
7
+ * render as a plain button until `rich-react-component/style.css` is
8
+ * imported, and no existing variant changed.
9
+ */
10
+ | "light-primary" | "light-secondary" | "light-success" | "light-danger" | "light-warning" | "light-info";
3
11
  export interface ButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, "className" | "type" | "disabled"> {
4
12
  variant?: ButtonVariant;
5
13
  size?: "sm" | "lg";
@@ -1,31 +1,121 @@
1
- import { ReactNode } from 'react';
2
- export interface SidebarLeafItem {
3
- key: string;
4
- label: ReactNode;
5
- icon?: ReactNode;
6
- href?: string;
7
- onClick?: () => void;
8
- active?: boolean;
9
- disabled?: boolean;
1
+ import { CSSProperties, MouseEvent, ReactNode } from 'react';
2
+ import { SidebarPresentation, SidebarTone } from './Appearance';
3
+ import { SidebarExpandMode, SidebarItem, SidebarLinkItem, SidebarSection, SidebarSelectHandler } from './sidebarModel';
4
+ export type { SidebarActionItem, SidebarCollapsibleItem, SidebarDividerItem, SidebarExpandMode, SidebarGroup, SidebarGroupItem, SidebarItem, SidebarLeafItem, SidebarLinkItem, SidebarParentItem, SidebarSection, SidebarSelectHandler, } from './sidebarModel';
5
+ export { isSidebarExpandable, isSidebarParent, legacyActiveKey, legacyDefaultExpandedKeys, toSidebarItems } from './sidebarModel';
6
+ /**
7
+ * How the current route may change which branches are open.
8
+ *
9
+ * - `never` — the active route never touches expansion.
10
+ * - `on-active-change` — the active branch opens on mount and again whenever
11
+ * `activeKey` changes, and the user may close it afterwards. This is what
12
+ * `expandActivePath` means.
13
+ * - `always` — active ancestors are forced open on every render, so the active
14
+ * branch cannot be closed. Kept because it was the behaviour `expandActivePath`
15
+ * used to have; it is not the default and not recommended.
16
+ */
17
+ export type SidebarActivePathExpansion = "never" | "on-active-change" | "always";
18
+ /**
19
+ * `grouped` is the presentation this component has always rendered and stays
20
+ * the default. Alias of the appearance layer's `SidebarPresentation` so the
21
+ * two can never drift apart.
22
+ */
23
+ export type SidebarVariant = SidebarPresentation;
24
+ export interface SidebarLinkRenderProps {
25
+ item: SidebarLinkItem;
26
+ href: string;
27
+ className: string;
28
+ style: CSSProperties;
29
+ children: ReactNode;
30
+ onClick: (event: MouseEvent<HTMLAnchorElement>) => void;
31
+ "aria-current": "page" | undefined;
32
+ "aria-disabled": true | undefined;
33
+ "aria-label": string | undefined;
34
+ "data-active-ancestor": "true" | undefined;
35
+ target: string | undefined;
36
+ rel: string | undefined;
10
37
  }
11
- export interface SidebarGroup {
12
- key: string;
38
+ /**
39
+ * Lets the application swap the anchor for its own router link. Base stays
40
+ * routing-agnostic: no router package is imported and no route matching
41
+ * happens here (doc section 22).
42
+ */
43
+ export type SidebarLinkRenderer = (props: SidebarLinkRenderProps) => ReactNode;
44
+ export interface SidebarCollapseControlProps {
45
+ collapsed: boolean;
46
+ toggle: () => void;
13
47
  label: string;
14
- items: SidebarLeafItem[];
15
- defaultOpen?: boolean;
16
48
  }
17
- export type SidebarSection = SidebarLeafItem | SidebarGroup;
18
49
  export interface SidebarProps {
19
- sections: SidebarSection[];
50
+ /** Recursive navigation model. Takes precedence over `sections` when both are given. */
51
+ items?: SidebarItem[];
52
+ /** @deprecated Legacy flat/one-level model. Still fully supported; normalized onto `items`. */
53
+ sections?: SidebarSection[];
54
+ /** `grouped` (default, the historical presentation) or the compact Metronic-style aside. */
55
+ variant?: SidebarVariant;
56
+ /** Surface tone. `auto` inherits the page theme; `light`/`dark` scope Bootstrap 5.3's own `data-bs-theme`. */
57
+ tone?: SidebarTone;
58
+ /** The one authoritative active identity. Ancestors are derived, not passed in. */
59
+ activeKey?: string;
60
+ /**
61
+ * Open the branch leading to `activeKey`. Off by default, so legacy rendering
62
+ * is unchanged. Shorthand for `activePathExpansion="on-active-change"`: the
63
+ * path opens on mount and whenever `activeKey` changes, and stays closable by
64
+ * hand in between.
65
+ */
66
+ expandActivePath?: boolean;
67
+ /** Explicit strategy. Wins over `expandActivePath` when both are given. */
68
+ activePathExpansion?: SidebarActivePathExpansion;
69
+ expandedKeys?: string[];
70
+ defaultExpandedKeys?: string[];
71
+ onExpandedKeysChange?: (keys: string[]) => void;
72
+ /** `multiple` (default) reproduces the legacy independent-groups behavior. */
73
+ expandMode?: SidebarExpandMode;
74
+ collapsed?: boolean;
75
+ defaultCollapsed?: boolean;
76
+ onCollapsedChange?: (collapsed: boolean) => void;
77
+ /** Render the collapse/expand control. */
78
+ collapsible?: boolean;
79
+ renderCollapseControl?: (props: SidebarCollapseControlProps) => ReactNode;
80
+ /** Accessible name of the control while expanded (i.e. the action it performs). */
81
+ collapseLabel?: string;
82
+ /** Accessible name of the control while collapsed. */
83
+ expandLabel?: string;
84
+ mobileOpen?: boolean;
85
+ defaultMobileOpen?: boolean;
86
+ onMobileOpenChange?: (open: boolean) => void;
87
+ /** Accessible name for the mobile drawer dialog. Falls back to `navLabel`. */
88
+ mobileLabel?: string;
89
+ /** Close the mobile drawer when a link or action is selected. */
90
+ closeMobileOnSelect?: boolean;
20
91
  header?: ReactNode;
21
92
  footer?: ReactNode;
93
+ /**
94
+ * Footer presentation while collapsed. A footer sized for the expanded aside
95
+ * cannot survive a ~58px rail — a select or an input would simply be clipped —
96
+ * and CSS alone cannot turn one control into another. Supply a compact
97
+ * icon-sized control here. Additive: when it is omitted the footer region is
98
+ * not rendered while collapsed, so nothing is clipped and no focusable
99
+ * control is left in a region the user cannot read.
100
+ */
101
+ collapsedFooter?: ReactNode;
22
102
  className?: string;
103
+ /** Accessible name of the navigation landmark. */
104
+ navLabel?: string;
105
+ onSelect?: SidebarSelectHandler;
106
+ renderLink?: SidebarLinkRenderer;
23
107
  }
24
108
  /**
25
- * Persistent vertical navigation. Leaf entries render as plain nav links;
26
- * grouped/collapsible sections reuse Accordion (doc section 20 — no second
27
- * independent collapse implementation) instead of reimplementing open/close
28
- * state. Active-state comes from the `active` flag the caller passes in —
29
- * routing/URL matching is the consuming app's job (doc section 22).
109
+ * Persistent vertical navigation.
110
+ *
111
+ * One recursive tree, one authoritative expansion state and one authoritative
112
+ * `activeKey` — no per-group Accordion instance and no per-item `active`
113
+ * boolean to keep in sync. The legacy `sections` shape is normalized onto the
114
+ * same model (`toSidebarItems`) so there is a single rendering path
115
+ * (doc section 20).
116
+ *
117
+ * Routing stays out of Base: real destinations render as anchors (or the
118
+ * consumer's `renderLink`), commands render as buttons, and URL matching
119
+ * remains the application's job (doc section 22).
30
120
  */
31
- export declare function Sidebar({ sections, header, footer, className }: SidebarProps): import("react").JSX.Element;
121
+ export declare function Sidebar({ items, sections, variant, tone, activeKey, expandActivePath, activePathExpansion, expandedKeys, defaultExpandedKeys, onExpandedKeysChange, expandMode, collapsed, defaultCollapsed, onCollapsedChange, collapsible, renderCollapseControl, collapseLabel, expandLabel, mobileOpen, defaultMobileOpen, onMobileOpenChange, mobileLabel, closeMobileOnSelect, header, footer, collapsedFooter, className, navLabel, onSelect, renderLink, }: SidebarProps): import("react").JSX.Element;
@@ -1,7 +1,9 @@
1
1
  import { ReactNode } from 'react';
2
- import { BadgeVariant } from './Badge';
2
+ import { BadgeAppearance, BadgeVariant } from './Badge';
3
3
  export interface TagProps {
4
4
  variant?: BadgeVariant;
5
+ /** Same additive contract as Badge; `solid` stays the default. */
6
+ appearance?: BadgeAppearance;
5
7
  onRemove?: () => void;
6
8
  className?: string;
7
9
  children: ReactNode;
@@ -11,4 +13,4 @@ export interface TagProps {
11
13
  * from Badge is purely behavioral: Tag is removable/interactive, Badge is
12
14
  * static.
13
15
  */
14
- export declare function Tag({ variant, onRemove, className, children }: TagProps): import("react").JSX.Element;
16
+ export declare function Tag({ variant, appearance, onRemove, className, children }: TagProps): import("react").JSX.Element;
@@ -4,6 +4,13 @@ export interface TooltipProps {
4
4
  children: ReactNode;
5
5
  placement?: "top" | "bottom";
6
6
  className?: string;
7
+ /**
8
+ * Class for the trigger wrapper. The wrapper is inline-block by default,
9
+ * which is right for an inline trigger but wrong for a full-width row (e.g.
10
+ * a collapsed Sidebar item), so callers can override the display here
11
+ * instead of reimplementing a second tooltip.
12
+ */
13
+ wrapperClassName?: string;
7
14
  }
8
15
  /**
9
16
  * Reuses the existing Popup primitive (open/close, escape-to-close, outside
@@ -18,4 +25,4 @@ export interface TooltipProps {
18
25
  * conservative choice here, not less (doc section 18: "do NOT introduce
19
26
  * another positioning library unless actually necessary").
20
27
  */
21
- export declare function Tooltip({ content, children, placement, className }: TooltipProps): import("react").JSX.Element;
28
+ export declare function Tooltip({ content, children, placement, className, wrapperClassName }: TooltipProps): import("react").JSX.Element;
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Semantic color schemes.
3
+ *
4
+ * A scheme is deliberately NOT a single raw color. Changing only the primary
5
+ * hue leaves buttons, active components and menu states inconsistent, so a
6
+ * scheme is a complete coordinated token family that is validated before it
7
+ * can be registered or applied.
8
+ *
9
+ * Variable mapping (verified against the repository's real styling stack —
10
+ * `bootstrap@5.3.8`, which is this package's peer dependency):
11
+ *
12
+ * - `--bs-primary` and `--bs-primary-rgb` genuinely exist in Bootstrap 5.3 and
13
+ * are written directly, so Bootstrap's own components follow the scheme.
14
+ * - `--bs-primary-active`, `--bs-primary-light`, `--bs-primary-inverse`,
15
+ * `--bs-component-*` and `--bs-menu-link-color-*` do NOT exist in Bootstrap.
16
+ * They are Metronic's names. They are emitted anyway so that an application
17
+ * that really does ship Metronic gets a coordinated result instead of a
18
+ * half-recolored theme.
19
+ * - `--rrc-*` are this repository's own tokens, which are what this library's
20
+ * stylesheet actually consumes. Each one falls back to the Bootstrap or
21
+ * Metronic variable when present, so the mapping works with Metronic, with
22
+ * plain Bootstrap, and with neither.
23
+ */
24
+ /** The full token family a scheme must define. */
25
+ export interface ColorSchemeTokens {
26
+ primary: string;
27
+ primaryActive: string;
28
+ primaryLight: string;
29
+ /** Foreground placed on top of `primary` — the scheme's contrast value. */
30
+ primaryInverse: string;
31
+ /** Comma-separated channels of `primary`, e.g. "13, 110, 253". */
32
+ primaryRgb: string;
33
+ componentActiveColor: string;
34
+ componentActiveBg: string;
35
+ componentHoverColor: string;
36
+ componentHoverBg: string;
37
+ componentCheckedColor: string;
38
+ componentCheckedBg: string;
39
+ menuLinkColorHover: string;
40
+ menuLinkColorShow: string;
41
+ menuLinkColorHere: string;
42
+ menuLinkColorActive: string;
43
+ }
44
+ export interface ColorScheme {
45
+ id: string;
46
+ tokens: ColorSchemeTokens;
47
+ /**
48
+ * Optional swatch color for a selector UI. Defaults to `tokens.primary`.
49
+ * Never the scheme's identity — selection must be indicated by more than
50
+ * color alone, so the selector also renders a real label and a checked state.
51
+ */
52
+ swatch?: string;
53
+ }
54
+ export declare const COLOR_SCHEME_TOKEN_KEYS: readonly (keyof ColorSchemeTokens)[];
55
+ /** True only when every required token is present and non-empty. */
56
+ export declare function isValidColorScheme(value: unknown): value is ColorScheme;
57
+ export interface ColorSchemeSeed {
58
+ id: string;
59
+ primary: string;
60
+ primaryActive: string;
61
+ primaryLight: string;
62
+ primaryInverse: string;
63
+ primaryRgb: string;
64
+ swatch?: string;
65
+ }
66
+ /**
67
+ * Derives the coordinated component/menu tokens from the four primary shades,
68
+ * so a scheme author cannot accidentally register a half-defined family.
69
+ * Callers that need full control can build a `ColorScheme` literal instead.
70
+ */
71
+ export declare function createColorScheme(seed: ColorSchemeSeed): ColorScheme;
72
+ /** The scheme applied when nothing else is selected — Bootstrap's own primary. */
73
+ export declare const DEFAULT_COLOR_SCHEME_ID = "blue";
74
+ /**
75
+ * Registers an application-owned scheme. Rejects an incomplete family rather
76
+ * than applying a partially recolored theme.
77
+ */
78
+ export declare function registerColorScheme(scheme: ColorScheme): void;
79
+ export declare function getColorScheme(id: string): ColorScheme | undefined;
80
+ /** Registered schemes in registration order — built-ins first. */
81
+ export declare function listColorSchemes(): ColorScheme[];
82
+ /**
83
+ * Resolves an identifier to a scheme, falling back to the default rather than
84
+ * throwing, so an unknown persisted value degrades safely.
85
+ */
86
+ export declare function resolveColorScheme(id: string | undefined): ColorScheme;
87
+ /**
88
+ * The scheme as CSS custom properties, ready to spread into a `style` object
89
+ * or write onto a DOM node. Emits the real Bootstrap variables, the
90
+ * Metronic-compatible names, and this repository's own `--rrc-*` tokens.
91
+ */
92
+ export declare function colorSchemeCssVariables(scheme: ColorScheme): Record<string, string>;
@@ -53,6 +53,10 @@ export * from './IconButton';
53
53
  export * from './ListItem';
54
54
  export * from './Sparkline';
55
55
  export * from './Statistic';
56
+ export { AppearanceProvider, useAppearance, createAppearanceInitScript, THEME_MODES, SIDEBAR_PRESENTATIONS, SIDEBAR_TONES } from './Appearance';
57
+ export type { AppearanceContextValue, AppearanceInitScriptOptions, AppearanceProviderProps, AppearanceSettings, AppearanceStorage, ResolvedTheme, SidebarPresentation, SidebarTone, ThemeMode, } from './Appearance';
58
+ export * from './appearanceSchemes';
59
+ export * from './AppearanceMenu';
56
60
  export { Popup } from './shared/Popup';
57
61
  export type { PopupProps } from './shared/Popup';
58
62
  export { Label } from './shared/Label';
@@ -0,0 +1,171 @@
1
+ import { MouseEvent, ReactNode } from 'react';
2
+ /**
3
+ * @deprecated Use the recursive `SidebarItem` model (`SidebarLinkItem` /
4
+ * `SidebarActionItem`) via `Sidebar.items`. Still accepted by
5
+ * `Sidebar.sections` and normalized internally — see `toSidebarItems`.
6
+ */
7
+ export interface SidebarLeafItem {
8
+ key: string;
9
+ label: ReactNode;
10
+ icon?: ReactNode;
11
+ href?: string;
12
+ onClick?: () => void;
13
+ active?: boolean;
14
+ disabled?: boolean;
15
+ }
16
+ /**
17
+ * @deprecated Use `SidebarGroupItem` (`type: "group"`, `collapsible: true`)
18
+ * via `Sidebar.items`. Still accepted by `Sidebar.sections`.
19
+ */
20
+ export interface SidebarGroup {
21
+ key: string;
22
+ label: string;
23
+ items: SidebarLeafItem[];
24
+ defaultOpen?: boolean;
25
+ }
26
+ /** @deprecated Use `SidebarItem`. */
27
+ export type SidebarSection = SidebarLeafItem | SidebarGroup;
28
+ /**
29
+ * Fired for the two item kinds that represent a destination or a command.
30
+ * The original React event is passed through so the consuming app can decide
31
+ * for itself whether to take over navigation (`event.preventDefault()` plus a
32
+ * router push). The Base layer never calls `preventDefault()` for an enabled
33
+ * real link, so modified clicks (ctrl/cmd/middle-click, "open in new tab")
34
+ * keep working (doc section 22: Base must not know routing).
35
+ */
36
+ export type SidebarSelectHandler = (item: SidebarLinkItem | SidebarActionItem, event: MouseEvent<HTMLAnchorElement | HTMLButtonElement>) => void;
37
+ interface SidebarItemBase {
38
+ /** Stable identity. Never derived from an array index; must be unique in the tree. */
39
+ key: string;
40
+ label: ReactNode;
41
+ /** Any React node — an `<Icon />`, an `<img>`, an emoji. Icon-set agnostic (doc section 15). */
42
+ icon?: ReactNode;
43
+ badge?: ReactNode;
44
+ disabled?: boolean;
45
+ className?: string;
46
+ /**
47
+ * Accessible name, required whenever `label` is not plain readable text.
48
+ * Also used as the accessible name and the tooltip text while the Sidebar
49
+ * is collapsed to icons only.
50
+ */
51
+ ariaLabel?: string;
52
+ }
53
+ /** A real destination. Renders an anchor, or the consumer's `renderLink`. */
54
+ export interface SidebarLinkItem extends SidebarItemBase {
55
+ type: "link";
56
+ /** Required — an item without a destination is an `action`, not a `link`. */
57
+ href: string;
58
+ target?: string;
59
+ rel?: string;
60
+ onSelect?: SidebarSelectHandler;
61
+ }
62
+ /** A command with no destination. Renders a native button, never an empty-fragment anchor. */
63
+ export interface SidebarActionItem extends SidebarItemBase {
64
+ type: "action";
65
+ onSelect?: SidebarSelectHandler;
66
+ }
67
+ /** A parent whose children open and close. Renders an explicit toggle button. */
68
+ export interface SidebarCollapsibleItem extends SidebarItemBase {
69
+ type: "collapsible";
70
+ children: SidebarItem[];
71
+ }
72
+ /**
73
+ * A visual section. Presentation only: never navigable, and only participates
74
+ * in expansion when `collapsible` is explicitly set — which is what the legacy
75
+ * `SidebarGroup` normalizes to.
76
+ */
77
+ export interface SidebarGroupItem extends SidebarItemBase {
78
+ type: "group";
79
+ children: SidebarItem[];
80
+ collapsible?: boolean;
81
+ }
82
+ export interface SidebarDividerItem {
83
+ type: "divider";
84
+ key: string;
85
+ className?: string;
86
+ }
87
+ export type SidebarItem = SidebarLinkItem | SidebarActionItem | SidebarCollapsibleItem | SidebarGroupItem | SidebarDividerItem;
88
+ /** Items that own a `children` array and therefore can contain a branch. */
89
+ export type SidebarParentItem = SidebarCollapsibleItem | SidebarGroupItem;
90
+ export declare function isSidebarParent(item: SidebarItem): item is SidebarParentItem;
91
+ /**
92
+ * A `group` is expandable only when the consumer asked for it; a `collapsible`
93
+ * always is. Deliberately a plain boolean and not a type predicate: this is a
94
+ * runtime capability question, not a narrowing one — a non-expandable group is
95
+ * still a `SidebarParentItem`.
96
+ */
97
+ export declare function isSidebarExpandable(item: SidebarItem): boolean;
98
+ /**
99
+ * Additive adapter: turns the legacy `sections` shape into the recursive
100
+ * model so there is exactly one rendering path (doc section 20 — the Sidebar
101
+ * must not grow a second independent implementation for legacy input).
102
+ *
103
+ * A legacy leaf carrying a real `href` becomes a `link`; one without a
104
+ * destination becomes an `action` and renders as a button rather than the
105
+ * previous placeholder anchor (defect 8 — see the README migration notes).
106
+ */
107
+ export declare function toSidebarItems(sections: readonly SidebarSection[]): SidebarItem[];
108
+ /** Legacy `defaultOpen` groups, in declaration order, as Sidebar-level expanded keys. */
109
+ export declare function legacyDefaultExpandedKeys(sections: readonly SidebarSection[]): string[];
110
+ /**
111
+ * Legacy per-item `active` flags collapse into the single authoritative
112
+ * `activeKey`. Deliberately deterministic: the first flagged item in
113
+ * declaration order wins, so inconsistent caller-supplied flags degrade
114
+ * predictably instead of producing two simultaneously "active" rows.
115
+ */
116
+ export declare function legacyActiveKey(sections: readonly SidebarSection[]): string | undefined;
117
+ export interface SidebarNode {
118
+ item: SidebarItem;
119
+ key: string;
120
+ depth: number;
121
+ /** Ancestor keys, outermost first. */
122
+ ancestors: string[];
123
+ children: SidebarNode[];
124
+ }
125
+ export interface SidebarTree {
126
+ roots: SidebarNode[];
127
+ byKey: Map<string, SidebarNode>;
128
+ /** Every key in pre-order — the single source of deterministic key ordering. */
129
+ order: string[];
130
+ duplicateKeys: string[];
131
+ }
132
+ export declare function buildSidebarTree(items: readonly SidebarItem[]): SidebarTree;
133
+ /** Orders arbitrary keys by their position in the tree, so callbacks are reproducible. */
134
+ export declare function sortKeysByTreeOrder(order: readonly string[], keys: Iterable<string>): string[];
135
+ export type SidebarExpandMode = "single" | "multiple";
136
+ /**
137
+ * Authoritative expansion transition for the whole tree.
138
+ *
139
+ * - `multiple`: independent branches, which is exactly what the legacy
140
+ * one-Accordion-per-group layout produced, so it stays the default.
141
+ * - `single`: opening a branch keeps only that branch's own ancestor chain,
142
+ * closing every competing sibling at every level.
143
+ *
144
+ * Collapsing a branch also drops its descendants, so `expandedKeys` never
145
+ * reports a branch as open while that branch is not visible.
146
+ */
147
+ export declare function toggleExpandedKey(tree: SidebarTree, current: readonly string[], key: string, mode: SidebarExpandMode): string[];
148
+ /**
149
+ * Opens an ancestor chain without toggling anything.
150
+ *
151
+ * Used for route-driven expansion, which is a one-way "make this visible"
152
+ * request rather than a user toggle: it must never close the branch it was
153
+ * asked to open. `single` keeps only the requested chain, matching what
154
+ * `toggleExpandedKey` does when a branch is opened by hand, so a route change
155
+ * and a click leave the tree in the same shape.
156
+ */
157
+ export declare function expandPath(tree: SidebarTree, current: readonly string[], path: readonly string[], mode: SidebarExpandMode): string[];
158
+ /** True when two key lists describe the same expansion, order included. */
159
+ export declare function sameExpandedKeys(a: readonly string[], b: readonly string[]): boolean;
160
+ /** Ancestor keys of the active item — the "active branch" the UI highlights. */
161
+ export declare function activeAncestorKeys(tree: SidebarTree, activeKey: string | undefined): string[];
162
+ /**
163
+ * The subset of the active branch that can actually be opened.
164
+ *
165
+ * A non-interactive visual group is a caption, not a level of expansion: it has
166
+ * no toggle, no `aria-expanded` and no place in `expandedKeys`. Route-driven
167
+ * expansion therefore asks for this list, while highlighting still uses the
168
+ * full ancestor list above.
169
+ */
170
+ export declare function activeExpandablePath(tree: SidebarTree, activeKey: string | undefined): string[];
171
+ export {};