@dloizides/ui-nav 1.12.0 → 1.13.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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/isRouteActive.ts","../src/styles.ts","../src/webStyle.ts","../src/NavExpandableItem.tsx","../src/textSlot.tsx","../src/Sidebar.tsx","../src/constants.ts","../src/FocusableTouchable.tsx","../src/Topbar.tsx","../src/NavBarLink.tsx","../src/NavOverflowMenu.tsx","../src/computeVisibleCount.ts","../src/useNavOverflow.ts","../src/useReducedMotion.ts","../src/NavBar.tsx","../src/Nav.tsx","../src/appShellContent.tsx","../src/MobileDrawer.tsx","../src/railMode.ts","../src/useContentMaxWidth.ts","../src/AppShell.tsx","../src/CollapsedRail.tsx","../src/NavShell.tsx","../src/PillNav.tsx","../src/DarkModeControl.tsx","../src/commandPaletteFilter.ts","../src/CommandPalette.tsx","../src/useCommandPaletteHotkey.ts","../src/roleNav.ts"],"names":["jsx","Text","React","useUi","jsxs","View","useState","TEXT_ON_PRIMARY","ariaCurrentProps","Pressable","useMemo","useCallback","useEffect","StyleSheet","MENU_GLYPH","styles","useWindowDimensions","ActivityIndicator","SCRIM_COLOR","useRef","ScrollView"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Active-route matcher shared by the sidebar entries. Ported verbatim from the\n * twin app sidebars: an item is active when the current pathname equals its\n * route or is nested under it (`/foo` matches `/foo` and `/foo/bar`, but `/`\n * only matches `/`).\n */\nexport function isRouteActive(pathname: string, route: string): boolean {\n if (route === '/') return pathname === '/';\n return pathname === route || pathname.startsWith(`${route}/`);\n}\n","/**\n * Layout styles for the nav shell — ported verbatim (dimensions unchanged) from\n * erevna-web / katalogos-web `theme/utils/layoutSidebar.ts` + `layoutTopbar.ts`,\n * so a migrated app's sidebar/topbar keep the exact same metrics. Colours are\n * NOT baked in here; they are applied at render time from the UiProvider theme.\n */\nimport { StyleSheet } from 'react-native';\n\nexport const ACTIVE_BORDER_RADIUS = 4;\n/** Width (px) of the active-leaf left accent bar (reserved on every leaf). */\nexport const ACTIVE_ACCENT_WIDTH = 3;\n\n/**\n * Horizontal gap (px) between adjacent inline items in the `NavBar` links row.\n * Single source of truth: it is both the row's `columnGap` AND the gap the\n * priority+ overflow fit ({@link computeVisibleCount}) reasons about, so the two\n * can never drift apart.\n */\nexport const NAV_LINK_GAP = 4;\n\nexport const navStyles = StyleSheet.create({\n // --- Sidebar ---\n sidebarContainer: {\n width: 220,\n paddingTop: 24,\n paddingHorizontal: 12,\n borderRightWidth: 1,\n height: '100%',\n },\n sidebarTitle: {\n fontWeight: '700',\n marginBottom: 12,\n },\n sidebarItem: {\n paddingVertical: 10,\n paddingHorizontal: 6,\n borderRadius: 4,\n },\n sidebarItemText: {\n fontSize: 16,\n },\n sidebarSpacer: {\n flex: 1,\n },\n\n // --- Topbar ---\n topbarContainer: {\n height: 64,\n paddingHorizontal: 12,\n borderBottomWidth: 1,\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: 'space-between',\n },\n topbarLeft: { flex: 1 },\n topbarRight: { flexDirection: 'row', alignItems: 'center' },\n topbarRowItem: { marginHorizontal: 8, alignItems: 'center' },\n topbarLabel: { fontSize: 14 },\n userBlock: { marginHorizontal: 12, alignItems: 'flex-end' },\n userName: { fontWeight: '600' },\n userEmail: { fontSize: 12 },\n accountBtn: { marginLeft: 8, paddingHorizontal: 10, paddingVertical: 6, borderRadius: 4 },\n accountText: { fontWeight: '600' },\n // --- Rich account-state header (Move 1c) ---\n accountTenant: { fontSize: 12 },\n planBadge: { marginTop: 2, paddingHorizontal: 8, paddingVertical: 2, borderRadius: 10, alignSelf: 'flex-end' },\n planBadgeText: { fontSize: 11, fontWeight: '700' },\n});\n\nexport const navBarStyles = StyleSheet.create({\n // --- Horizontal top NavBar ---\n container: {\n borderBottomWidth: 1,\n paddingHorizontal: 12,\n },\n inner: {\n minHeight: 56,\n flexDirection: 'row',\n alignItems: 'center',\n flexWrap: 'wrap',\n columnGap: 8,\n rowGap: 4,\n paddingVertical: 8,\n },\n // EXPANDED: the row must NOT wrap — otherwise flexbox drops the right slot onto a 2nd line the\n // moment brand+links+right overflow, instead of SHRINKING the (scrollable) links. `flex-shrink`\n // only distributes negative space on a `nowrap` line; with `wrap` it wraps first and never shrinks.\n // Collapsed keeps `wrap` so the stacked links/right (width:100%) can drop to their own lines.\n innerNoWrap: {\n flexWrap: 'nowrap',\n },\n brand: { marginRight: 16, flexShrink: 0 },\n toggle: {\n marginLeft: 'auto',\n paddingHorizontal: 10,\n paddingVertical: 6,\n borderRadius: 4,\n // a11y: keep the hamburger a comfortable ≥44×44 touch target.\n minWidth: 44,\n minHeight: 44,\n alignItems: 'center',\n justifyContent: 'center',\n },\n toggleGlyph: { fontSize: 20, fontWeight: '700' },\n // Expanded links live on ONE ROW that never wraps: it is a shrinkable/growable flex child that\n // fills the space between the pinned brand (left) and right slot, and CLIPS overflow. A measure\n // pass (priority+) then keeps only the leading items that fit inline and collapses the rest behind\n // the \"More ▾\" overflow trigger — so no item is ever cut off; the surplus moves into a dropdown.\n // `overflow:'hidden'` only masks the single unmeasured first frame before the fit resolves.\n linksRow: {\n flexGrow: 1,\n flexShrink: 1,\n minWidth: 0,\n flexDirection: 'row',\n alignItems: 'center',\n flexWrap: 'nowrap',\n columnGap: NAV_LINK_GAP,\n overflow: 'hidden',\n },\n // Each inline link + the overflow trigger sit in a natural-width cell that never shrinks, so their\n // measured widths are their true content widths (what the priority+ fit computation reasons about).\n linkCell: { flexShrink: 0 },\n overflowTrigger: { columnGap: 4 },\n overflowChevron: { fontSize: 12, fontWeight: '700' },\n // Collapsed (below breakpoint): links drop onto their own full-width line,\n // stacked vertically — mirrors the v1 `.gn-links` responsive behaviour.\n linksStacked: {\n width: '100%',\n flexBasis: '100%',\n flexDirection: 'column',\n alignItems: 'stretch',\n rowGap: 2,\n marginTop: 8,\n },\n link: {\n paddingVertical: 8,\n paddingHorizontal: 14,\n borderRadius: 8,\n flexDirection: 'row',\n alignItems: 'center',\n // a11y: comfortable ≥44 tall touch target (rounded-pill hover/active affordance).\n minHeight: 44,\n justifyContent: 'center',\n },\n linkStacked: { paddingVertical: 10 },\n linkIcon: { marginRight: 6 },\n linkText: { fontSize: 15, fontWeight: '600' },\n right: {\n marginLeft: 'auto',\n flexShrink: 0,\n flexDirection: 'row',\n alignItems: 'center',\n columnGap: 8,\n },\n rightStacked: {\n width: '100%',\n flexBasis: '100%',\n marginTop: 4,\n flexDirection: 'row',\n alignItems: 'center',\n columnGap: 8,\n },\n});\n\nexport const pillNavStyles = StyleSheet.create({\n // Cross-nav pill row (kefi coral dashboard switcher): fully-rounded pills, wraps.\n container: {\n flexDirection: 'row',\n flexWrap: 'wrap',\n alignItems: 'center',\n columnGap: 8,\n rowGap: 8,\n paddingVertical: 8,\n },\n pill: {\n paddingHorizontal: 16,\n paddingVertical: 8,\n borderRadius: 999,\n minHeight: 36,\n flexDirection: 'row',\n alignItems: 'center',\n columnGap: 6,\n justifyContent: 'center',\n },\n pillText: { fontSize: 14, fontWeight: '600' },\n});\n\nexport const darkModeStyles = StyleSheet.create({\n // Segmented Light / Dark / System control.\n segmentRow: {\n flexDirection: 'row',\n alignItems: 'center',\n borderWidth: 1,\n borderRadius: 8,\n overflow: 'hidden',\n alignSelf: 'flex-start',\n },\n segment: {\n paddingHorizontal: 12,\n paddingVertical: 8,\n minHeight: 36,\n flexDirection: 'row',\n alignItems: 'center',\n columnGap: 6,\n justifyContent: 'center',\n },\n segmentText: { fontSize: 13, fontWeight: '600' },\n // Cycle-button variant.\n cycle: {\n paddingHorizontal: 12,\n paddingVertical: 8,\n minHeight: 44,\n minWidth: 44,\n borderRadius: 8,\n flexDirection: 'row',\n alignItems: 'center',\n columnGap: 6,\n justifyContent: 'center',\n },\n cycleText: { fontSize: 13, fontWeight: '600' },\n});\n\nexport const collapsedRailStyles = StyleSheet.create({\n // Intermediate (tablet) icon-only rail: a narrow vertical strip of icon buttons.\n container: {\n width: 64,\n paddingTop: 16,\n paddingHorizontal: 8,\n borderRightWidth: 1,\n height: '100%',\n alignItems: 'center',\n },\n // Each item is a ≥44×44 centred touch target with a rounded active/hover pill.\n item: {\n width: 48,\n height: 48,\n marginVertical: 4,\n borderRadius: 8,\n alignItems: 'center',\n justifyContent: 'center',\n },\n // Glyph fallback (the label's first character) when an item has no renderIcon.\n glyph: { fontSize: 18, fontWeight: '700' },\n spacer: { flex: 1 },\n slot: { alignItems: 'center' },\n});\n\nexport const expandableStyles = StyleSheet.create({\n // Every leaf reserves the accent-bar gutter (a TRANSPARENT left border of the\n // same width the active item colours in) so activation never shifts the row.\n childItem: {\n borderRadius: 6,\n flexDirection: 'row',\n alignItems: 'center',\n paddingVertical: 9,\n borderLeftWidth: ACTIVE_ACCENT_WIDTH,\n borderLeftColor: 'transparent',\n },\n childItemText: { fontSize: 14 },\n childItemTextWithIcon: { fontSize: 14, marginLeft: 6 },\n chevron: { marginLeft: 'auto' },\n childrenContainer: { overflow: 'hidden', marginBottom: 4 },\n header: {\n borderRadius: 6,\n flexDirection: 'row',\n alignItems: 'center',\n paddingVertical: 8,\n },\n // Depth-0 module groups render as docs-style SECTION HEADERS: extra top rhythm\n // to separate one module from the next.\n sectionHeader: { marginTop: 12 },\n headerText: { fontSize: 15, fontWeight: '600', marginLeft: 6 },\n // The section-label look: small, uppercased, tracked, muted — the aml-screening\n // docs treatment (\"START HERE\" / \"REFERENCE\"), kept on an interactive toggle.\n sectionHeaderText: {\n fontSize: 12,\n fontWeight: '700',\n marginLeft: 6,\n textTransform: 'uppercase',\n letterSpacing: 0.8,\n },\n iconWrapper: { width: 20, alignItems: 'center' },\n});\n\n/** Base indent applied per nesting depth in the expandable item. */\nexport const BASE_INDENT = 12;\n/** Default icon size for nav item icons. */\nexport const NAV_ICON_SIZE = 14;\n/** Chevron icon size for expandable sections. */\nexport const CHEVRON_ICON_SIZE = 12;\n","/**\n * Web-only style helpers for the nav shell. React Native's `ViewStyle` has no\n * `outline*` or `transition*` keys, but react-native-web forwards them to the DOM,\n * so we build them as typed web-style objects and cast ONCE to `ViewStyle` (no\n * `any`). On native these CSS-only props are meaningless — every helper returns\n * `undefined` when `IS_WEB` is false, so nothing is applied off the web.\n */\nimport { Platform, type ViewStyle } from 'react-native';\n\n/** True only under react-native-web. Gates the CSS-only focus ring + hover transition. */\nexport const IS_WEB = Platform.OS === 'web';\n\n/** Keyboard focus-ring width (px). */\nconst FOCUS_RING_WIDTH = 2;\n/** Gap between the ring and the element edge (px) so the ring reads clearly. */\nconst FOCUS_RING_OFFSET = 2;\n/** Hover-pill colour/background cross-fade duration (ms). */\nconst HOVER_TRANSITION_MS = 150;\n\n/** DOM `outline-*` shape — not part of RN `ViewStyle`, but honoured by react-native-web. */\ninterface WebOutlineStyle {\n outlineWidth: number;\n outlineStyle: 'solid';\n outlineColor: string;\n outlineOffset: number;\n}\n\n/** DOM `transition-*` shape — not part of RN `ViewStyle`, but honoured by react-native-web. */\ninterface WebTransitionStyle {\n transitionProperty: string;\n transitionDuration: string;\n}\n\n/**\n * A visible keyboard-focus ring in the theme accent colour. Returns `undefined`\n * on native, and when the element is not focused, so nothing is applied. Never\n * removes the outline without a replacement — it ADDS a themed ring on focus.\n */\nexport function focusRingStyle(focused: boolean, ringColor: string): ViewStyle | undefined {\n if (!IS_WEB || !focused) return undefined;\n const ring: WebOutlineStyle = {\n outlineWidth: FOCUS_RING_WIDTH,\n outlineStyle: 'solid',\n outlineColor: ringColor,\n outlineOffset: FOCUS_RING_OFFSET,\n };\n return ring as unknown as ViewStyle;\n}\n\n/**\n * A cheap CSS cross-fade for the hover-pill colour/background. Disabled (`0ms`)\n * when the user prefers reduced motion, and omitted entirely on native. No JS\n * animation — the transition is pure CSS applied by react-native-web.\n */\nexport function hoverTransitionStyle(reducedMotion: boolean): ViewStyle | undefined {\n if (!IS_WEB) return undefined;\n const transition: WebTransitionStyle = {\n transitionProperty: 'color, background-color',\n transitionDuration: reducedMotion ? '0ms' : `${HOVER_TRANSITION_MS}ms`,\n };\n return transition as unknown as ViewStyle;\n}\n","/**\n * NavExpandableItem — a single sidebar entry that is either a leaf (navigates)\n * or an expandable section (toggles nested children). Ported from the twin\n * erevna/katalogos `Sidebar/NavExpandableItem`, made config-driven: labels are\n * pre-localized strings, icons are render slots, colours come from `useUi`.\n */\nimport React, { useCallback, useMemo, useState } from 'react';\n\nimport { Text, TouchableOpacity, View, type TouchableOpacityProps } from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\n\nimport {\n BASE_INDENT,\n CHEVRON_ICON_SIZE,\n NAV_ICON_SIZE,\n ACTIVE_BORDER_RADIUS,\n ACTIVE_ACCENT_WIDTH,\n expandableStyles as styles,\n} from './styles';\nimport { isRouteActive } from './isRouteActive';\nimport type { NavItem } from './types';\nimport { focusRingStyle } from './webStyle';\n\n/**\n * `aria-current=\"page\"` marks the active leaf for assistive tech. RN's prop types\n * omit `aria-current`; react-native-web forwards `aria-*` to the DOM — attach it\n * (no `any`) only when the leaf is active.\n */\nfunction ariaCurrentProps(isActive: boolean): TouchableOpacityProps & { 'aria-current'?: 'page' } {\n return isActive ? { 'aria-current': 'page' } : {};\n}\n\n/**\n * `aria-expanded` marks an expandable section header as a disclosure control for\n * assistive tech — and, just as importantly, is the DOM signal `MobileDrawer` uses\n * to tell a group TOGGLE apart from a navigating leaf (so expanding a group on\n * mobile no longer dismisses the drawer). RNW forwards `aria-*` props to the DOM\n * but does NOT synthesize `aria-expanded` from `accessibilityState.expanded` in\n * this version, so set it explicitly (same pattern as `aria-current` above).\n */\nfunction ariaExpandedProps(expanded: boolean): TouchableOpacityProps & { 'aria-expanded'?: boolean } {\n return { 'aria-expanded': expanded };\n}\n\n/**\n * True when the current route is inside this item — its own route is active, or\n * any descendant's is. Drives the initial expansion so a group that contains the\n * active route opens on mount and its active leaf is visible; a group with no\n * active descendant mounts collapsed (the prior behaviour). Recursive so it holds\n * at any nesting depth.\n */\nfunction hasActiveDescendant(item: NavItem, pathname: string): boolean {\n if (isRouteActive(pathname, item.route)) return true;\n return (item.children ?? []).some((child) => hasActiveDescendant(child, pathname));\n}\n\nexport interface NavExpandableItemProps {\n item: NavItem;\n pathname: string;\n onNavigate: (route: string) => void;\n /** a11y hint for a leaf item, given its label. */\n navigateHint: (label: string) => string;\n /** a11y hint shown when the section is collapsed (press expands). */\n expandHint: string;\n /** a11y hint shown when the section is expanded (press collapses). */\n collapseHint: string;\n /** Optional chevron icon renderer for expandable sections. */\n renderChevron?: (expanded: boolean, color: string, size: number) => React.ReactNode;\n depth?: number;\n}\n\nexport const NavExpandableItem = ({\n item,\n pathname,\n onNavigate,\n navigateHint,\n expandHint,\n collapseHint,\n renderChevron,\n depth = 0,\n}: NavExpandableItemProps): React.ReactElement => {\n const [expanded, setExpanded] = useState(() => hasActiveDescendant(item, pathname));\n const [focused, setFocused] = useState(false);\n const { theme } = useUi();\n const colors = theme.colors;\n const primaryColor = theme.palette.primary['500'];\n\n const toggle = useCallback(() => setExpanded((v) => !v), []);\n\n const indent = depth * BASE_INDENT;\n const hasChildren = Array.isArray(item.children) && item.children.length > 0;\n const isActive = isRouteActive(pathname, item.route);\n // A top-level expandable group is a docs-style section header (uppercase, muted);\n // nested groups keep the plain header look.\n const isSectionHeader = hasChildren && depth === 0;\n\n // Active leaf: the docs-style strong treatment — a coloured left accent bar\n // (over the transparent gutter every leaf reserves, so there is no layout\n // shift) plus a tinted surface. The bar colour is the theme primary, so each\n // portal's brand drives it.\n const activeItemStyle = useMemo(\n () => ({\n backgroundColor: colors.border,\n borderRadius: ACTIVE_BORDER_RADIUS,\n borderLeftWidth: ACTIVE_ACCENT_WIDTH,\n borderLeftColor: primaryColor,\n }),\n [colors.border, primaryColor],\n );\n const paddingStyle = useMemo(() => ({ paddingLeft: indent + BASE_INDENT }), [indent]);\n const headerPaddingStyle = useMemo(() => ({ paddingLeft: indent }), [indent]);\n\n if (!hasChildren)\n return (\n <TouchableOpacity\n accessibilityHint={navigateHint(item.label)}\n accessibilityLabel={item.label}\n accessibilityRole=\"button\"\n accessibilityState={{ selected: isActive }}\n style={[\n styles.childItem,\n paddingStyle,\n isActive ? activeItemStyle : undefined,\n focusRingStyle(focused, primaryColor),\n ]}\n testID={item.testID ?? item.key}\n onBlur={() => setFocused(false)}\n onFocus={() => setFocused(true)}\n onPress={() => onNavigate(item.route)}\n {...ariaCurrentProps(isActive)}\n >\n {typeof item.renderIcon === 'function' ? (\n <View style={styles.iconWrapper}>{item.renderIcon(colors.textSecondary, NAV_ICON_SIZE)}</View>\n ) : null}\n <Text\n style={[\n typeof item.renderIcon === 'function' ? styles.childItemTextWithIcon : styles.childItemText,\n { color: isActive ? primaryColor : colors.text },\n ]}\n >\n {item.label}\n </Text>\n </TouchableOpacity>\n );\n\n return (\n <View>\n <TouchableOpacity\n accessibilityHint={expanded ? collapseHint : expandHint}\n accessibilityLabel={item.label}\n accessibilityRole=\"button\"\n accessibilityState={{ expanded }}\n style={[\n styles.header,\n isSectionHeader ? styles.sectionHeader : undefined,\n headerPaddingStyle,\n focusRingStyle(focused, primaryColor),\n ]}\n testID={item.testID ?? item.key}\n onBlur={() => setFocused(false)}\n onFocus={() => setFocused(true)}\n onPress={toggle}\n {...ariaExpandedProps(expanded)}\n >\n {typeof item.renderIcon === 'function' ? (\n <View style={styles.iconWrapper}>\n {item.renderIcon(isSectionHeader ? colors.textSecondary : colors.text, NAV_ICON_SIZE)}\n </View>\n ) : null}\n <Text\n style={[\n isSectionHeader ? styles.sectionHeaderText : styles.headerText,\n { color: isSectionHeader ? colors.textSecondary : colors.text },\n ]}\n >\n {item.label}\n </Text>\n {typeof renderChevron === 'function' ? (\n <View style={styles.chevron}>{renderChevron(expanded, colors.textSecondary, CHEVRON_ICON_SIZE)}</View>\n ) : null}\n </TouchableOpacity>\n\n {expanded ? (\n <View style={styles.childrenContainer}>\n {item.children?.map((child) => (\n <NavExpandableItem\n key={child.key}\n collapseHint={collapseHint}\n depth={depth + 1}\n expandHint={expandHint}\n item={child}\n navigateHint={navigateHint}\n pathname={pathname}\n renderChevron={renderChevron}\n onNavigate={onNavigate}\n />\n ))}\n </View>\n ) : null}\n </View>\n );\n};\n\nexport default NavExpandableItem;\n","/**\n * `renderTextSlot` — the single guard for every caller-supplied `React.ReactNode`\n * slot in this kit (brand, right, left, header, footer, banner, notificationSlot…).\n *\n * Why this exists. React Native Web refuses to render a bare text node inside a\n * `<View>`: it logs `Unexpected text node: <s>. A text node cannot be a child of a\n * <View>.` through `console.error` on EVERY render. Slots are typed `React.ReactNode`,\n * which legitimately includes `string`, and callers do exactly that — Digital Kin's\n * shell passes `brand: FM('app.name')`, a plain localized string. Nothing in the type\n * system objects, so the defect only ever surfaces as console noise in the browser,\n * which is why it survived in all seven portals.\n *\n * Rather than push the `<Text>` wrapper onto every consuming app (seven chances to\n * forget, and the type would still permit the mistake), the kit absorbs it here: a\n * string or number slot is wrapped in `<Text>`, and an element slot is passed through\n * untouched so existing callers are byte-identical. `React.Children.map` is used so an\n * ARRAY slot (`['Digital', <Logo key=\"l\" />]`) has each string member wrapped\n * individually while keys are preserved.\n *\n * `style` lets the call site route the wrapper through the theme — an unwrapped\n * `<Text>` would otherwise default to black and ignore dark mode.\n */\nimport React from 'react';\n\nimport { Text, type TextStyle } from 'react-native';\n\n/** Is this node a bare text node that RN-web would refuse to render inside a `<View>`? */\nfunction isBareText(node: React.ReactNode): node is string | number {\n return typeof node === 'string' || typeof node === 'number';\n}\n\n/**\n * Wrap bare string / number members of `node` in `<Text>`; pass elements through as-is.\n * Returns `node` unchanged when it is `undefined` / `null` so callers can keep their\n * existing `!== undefined` guards.\n */\nexport function renderTextSlot(node: React.ReactNode, style?: TextStyle): React.ReactNode {\n if (node === undefined || node === null) return node;\n if (isBareText(node)) return <Text style={style}>{node}</Text>;\n return React.Children.map(node, (child) =>\n isBareText(child) ? <Text style={style}>{child}</Text> : child,\n );\n}\n","/**\r\n * Sidebar — the config-driven left navigation shell promoted from the\r\n * byte-identical erevna-web / katalogos-web `Sidebar`. It renders a caller\r\n * supplied `NavItem[]` (leaf + expandable), highlights the active route, and\r\n * exposes header/footer slots for app-specific chrome (title, dark-mode toggle,\r\n * logout, notification bell). Every colour is read from the UiProvider theme.\r\n */\r\nimport React from 'react';\r\n\r\nimport { Text, View, type ViewStyle } from 'react-native';\r\n\r\nimport { useUi } from '@dloizides/ui-feedback';\r\n\r\nimport { isRouteActive } from './isRouteActive';\r\nimport { NavExpandableItem } from './NavExpandableItem';\r\nimport { navStyles as styles } from './styles';\r\nimport type { NavItem } from './types';\r\nimport { renderTextSlot } from './textSlot';\r\n\r\nexport interface SidebarProps {\r\n /** Nav entries — already role-filtered / grouped by the app. */\r\n items: NavItem[];\r\n /** Current active route/path. */\r\n pathname: string;\r\n /** Navigation callback — receives a `NavItem.route`. */\r\n onNavigate: (route: string) => void;\r\n /** Localized menu title (heading). */\r\n title: string;\r\n /** Localized accessibility label for the navigation landmark. */\r\n regionLabel: string;\r\n /** a11y hint for a leaf item, given its label. Defaults to the label. */\r\n navigateHint?: (label: string) => string;\r\n /** a11y hint shown when an expandable section is collapsed. */\r\n expandHint?: string;\r\n /** a11y hint shown when an expandable section is expanded. */\r\n collapseHint?: string;\r\n /** Optional chevron renderer for expandable sections. */\r\n renderChevron?: (expanded: boolean, color: string, size: number) => React.ReactNode;\r\n /** Optional header slot rendered above the items (e.g. a Home shortcut). */\r\n header?: React.ReactNode;\r\n /** Optional footer slot rendered after a flex spacer (dark-mode toggle, logout). */\r\n footer?: React.ReactNode;\r\n /** Extra container style overrides. */\r\n containerStyle?: ViewStyle | ViewStyle[];\r\n}\r\n\r\nexport const Sidebar = ({\r\n items,\r\n pathname,\r\n onNavigate,\r\n title,\r\n regionLabel,\r\n navigateHint = (label) => label,\r\n expandHint = '',\r\n collapseHint = '',\r\n renderChevron,\r\n header,\r\n footer,\r\n containerStyle,\r\n}: SidebarProps): React.ReactElement => {\r\n const { theme } = useUi();\r\n const colors = theme.colors;\r\n\r\n return (\r\n <View\r\n accessibilityRole=\"none\"\r\n aria-label={regionLabel}\r\n role=\"navigation\"\r\n style={[\r\n styles.sidebarContainer,\r\n { backgroundColor: colors.surface, borderRightColor: colors.border },\r\n containerStyle,\r\n ]}\r\n >\r\n <Text accessibilityRole=\"header\" style={[styles.sidebarTitle, { color: colors.text }]}>\r\n {title}\r\n </Text>\r\n\r\n {renderTextSlot(header, { color: colors.text })}\r\n\r\n {items.map((item) => (\r\n <NavExpandableItem\r\n key={item.key}\r\n collapseHint={collapseHint}\r\n expandHint={expandHint}\r\n item={item}\r\n navigateHint={navigateHint}\r\n pathname={pathname}\r\n renderChevron={renderChevron}\r\n onNavigate={onNavigate}\r\n />\r\n ))}\r\n\r\n <View style={styles.sidebarSpacer} />\r\n\r\n {renderTextSlot(footer, { color: colors.text })}\r\n </View>\r\n );\r\n};\r\n\r\nexport { isRouteActive };\r\nexport default Sidebar;\r\n","/**\n * Default testIDs for `@dloizides/ui-nav`. Kept as a small central map (mirrors\n * `@dloizides/ui-layout`'s `LAYOUT_TEST_IDS`) so the app-agnostic chrome exposes\n * stable Playwright selectors. The existing Topbar logout/account buttons keep\n * their *caller-supplied* testIDs (via `TopbarAction.testID`) — these constants\n * only name the NEW account-state bits and the AppShell region suffixes.\n */\nexport const NAV_TEST_IDS = {\n /** displayName line in the rich account header (tappable when `onAccount` set). */\n accountName: 'topbar-account-name',\n /** muted tenant-name line under the displayName. */\n accountTenant: 'topbar-account-tenant',\n /** small plan badge (free / pro / enterprise). */\n accountPlan: 'topbar-account-plan',\n /** default testID for the rich header's upgrade action (overridable per-action). */\n accountUpgrade: 'topbar-account-upgrade',\n /** responsive hamburger toggle in the horizontal NavBar (shown below the breakpoint). */\n navBarToggle: 'navbar-toggle',\n /** links container in the horizontal NavBar. */\n navBarLinks: 'navbar-links',\n /** the \"More ▾\" priority+ overflow trigger in the horizontal NavBar (shown when items spill). */\n navBarOverflow: 'navbar-overflow',\n} as const;\n\n/** Suffixes appended to an `AppShell`'s required `testID` to name its regions. */\nexport const APP_SHELL_SUFFIX = {\n content: '-content',\n header: '-header',\n nav: '-nav',\n /** The persistent left rail of the back-office layout (only when `sidebar` is supplied). */\n sidebar: '-sidebar',\n /** The intermediate persistent COLLAPSED (icon-only) rail (3-tier layout, tablet band). */\n collapsedSidebar: '-collapsed-sidebar',\n /** Mobile hamburger that opens the nav drawer (back-office layout, below the breakpoint). */\n menuToggle: '-menu-toggle',\n /** The mobile nav drawer panel (holds the `sidebar` slot when opened on a narrow viewport). */\n drawer: '-drawer',\n /** The mobile nav drawer scrim (tap to close). */\n scrim: '-drawer-scrim',\n banner: '-banner',\n pending: '-pending',\n loading: '-loading',\n error: '-error',\n forbidden: '-forbidden',\n} as const;\n","/**\n * FocusableTouchable — a thin `Pressable` wrapper that adds a THEMED keyboard\n * focus ring (via `focusRingStyle`) to any tappable, while forwarding the usual\n * accessibility props. Used by `Topbar` (and available to any nav element that\n * needs a focus ring without its own hover logic). Native-safe: the ring is\n * web-only; on native the focus state simply never drives a visible outline.\n */\nimport React, { useState } from 'react';\n\nimport { Pressable, type StyleProp, type ViewStyle } from 'react-native';\n\nimport { focusRingStyle } from './webStyle';\n\nexport interface FocusableTouchableProps {\n /** Press handler. */\n onPress: () => void;\n /** Accessible name. */\n accessibilityLabel: string;\n /** Accessible hint. */\n accessibilityHint: string;\n /** ARIA role — button (default) or link. */\n accessibilityRole?: 'button' | 'link';\n /** Focus-ring colour (theme accent). */\n ringColor: string;\n /** Base style(s) applied under the focus ring. */\n style?: StyleProp<ViewStyle>;\n /** Optional testID. */\n testID?: string;\n children: React.ReactNode;\n}\n\nexport const FocusableTouchable = ({\n onPress,\n accessibilityLabel,\n accessibilityHint,\n accessibilityRole = 'button',\n ringColor,\n style,\n testID,\n children,\n}: FocusableTouchableProps): React.ReactElement => {\n const [focused, setFocused] = useState(false);\n return (\n <Pressable\n accessibilityHint={accessibilityHint}\n accessibilityLabel={accessibilityLabel}\n accessibilityRole={accessibilityRole}\n style={[style, focusRingStyle(focused, ringColor)]}\n testID={testID}\n onBlur={() => setFocused(false)}\n onFocus={() => setFocused(true)}\n onPress={onPress}\n >\n {children}\n </Pressable>\n );\n};\n\nexport default FocusableTouchable;\n","/**\r\n * Topbar — the config-driven top navigation bar promoted from the byte-identical\r\n * erevna-web / katalogos-web `Topbar`. Structured slots replace the app-specific\r\n * wiring: a `left` logo slot, an optional language toggle, a notification slot,\r\n * an optional user block, an optional account button, and a required logout\r\n * action. Every colour comes from the UiProvider theme.\r\n *\r\n * Move 1c enriches this WITHOUT breaking the promoted contract: `account` now\r\n * accepts EITHER the legacy `TopbarAction` (today's erevna/katalogos calls) OR a\r\n * richer `AccountState` (displayName + muted tenant line + plan badge + upgrade\r\n * action). The `logout` action stays required, so every existing call keeps\r\n * compiling and the logout button keeps its caller-supplied testID.\r\n */\r\nimport React from 'react';\r\n\r\nimport { Text, View, type ViewStyle } from 'react-native';\r\n\r\nimport { useUi, type UiTheme } from '@dloizides/ui-feedback';\r\n\r\nimport { NAV_TEST_IDS } from './constants';\r\nimport { FocusableTouchable } from './FocusableTouchable';\r\nimport { navStyles as styles } from './styles';\r\nimport { renderTextSlot } from './textSlot';\r\n\r\n/** Text color for elements on primary/coloured badge backgrounds. */\r\nconst TEXT_ON_PRIMARY = '#ffffff';\r\n\r\nexport interface TopbarAction {\r\n label: string;\r\n hint: string;\r\n onPress: () => void;\r\n testID?: string;\r\n}\r\n\r\nexport interface TopbarUser {\r\n name: string;\r\n email: string;\r\n}\r\n\r\n/** Plan tier shown as a small badge in the rich account header. */\r\nexport interface AccountPlan {\r\n label: string;\r\n tone?: 'free' | 'pro' | 'enterprise';\r\n}\r\n\r\n/**\r\n * Richer account model for the header (Move 1c). Supplied via `account` as an\r\n * alternative to the legacy `TopbarAction` — the Topbar renders the display name\r\n * (tappable when `onAccount` is set), a muted tenant line, a plan badge, and an\r\n * `upgrade` action beside logout. No FM/router/store — everything is a\r\n * pre-localized string or a callback.\r\n */\r\nexport interface AccountState {\r\n displayName: string;\r\n tenantName?: string;\r\n plan?: AccountPlan;\r\n onLogout: () => void;\r\n onAccount?: () => void;\r\n /**\r\n * a11y hint for the account-name button (what pressing it DOES).\r\n *\r\n * Without this the hint fell back to `displayName` — byte-identical to the\r\n * accessibility LABEL, so a screen reader announced the name twice and never\r\n * said where the button goes. The sibling `upgrade?: TopbarAction` on this very\r\n * interface has always carried a `hint`; this closes that inconsistency. The\r\n * `displayName` fallback is retained so existing callers are unaffected.\r\n */\r\n accountHint?: string;\r\n /** testID for the account-name button. Defaults to `NAV_TEST_IDS.accountName`. */\r\n accountTestID?: string;\r\n upgrade?: TopbarAction;\r\n}\r\n\r\n/** Type guard: distinguishes the rich `AccountState` from a legacy `TopbarAction`. */\r\nfunction isAccountState(account: TopbarAction | AccountState): account is AccountState {\r\n return 'displayName' in account;\r\n}\r\n\r\n/** Resolve a plan badge background from its tone, routed through the theme. */\r\nfunction planToneColor(theme: UiTheme, tone: AccountPlan['tone']): string {\r\n const palette = theme.palette;\r\n if (tone === 'pro') return palette.primary['500'];\r\n if (tone === 'enterprise') return palette.accent?.['500'] ?? palette.primary['500'];\r\n return theme.colors.textSecondary;\r\n}\r\n\r\nexport interface TopbarProps {\r\n /** Left slot — typically the tenant logo. */\r\n left?: React.ReactNode;\r\n /**\r\n * Optional language toggle. `testID` is optional but the repo standard wants\r\n * one — before 1.10.0 this inline type declared none, so a testID was\r\n * structurally unreachable for this button while every other Topbar action\r\n * (which use `TopbarAction`) accepted one.\r\n */\r\n language?: { label: string; hint: string; onPress: () => void; testID?: string };\r\n /** Optional notification slot (e.g. a notification bell). */\r\n notificationSlot?: React.ReactNode;\r\n /** Optional user identity block. */\r\n user?: TopbarUser;\r\n /**\r\n * Optional account slot. Legacy callers pass a `TopbarAction` (an account\r\n * button). Move-1c callers pass an `AccountState` for the richer header.\r\n */\r\n account?: TopbarAction | AccountState;\r\n /** Required logout action (drives the stable logout button testID). */\r\n logout: TopbarAction;\r\n /** Extra container style overrides. */\r\n containerStyle?: ViewStyle | ViewStyle[];\r\n}\r\n\r\nexport const Topbar = ({\r\n left,\r\n language,\r\n notificationSlot,\r\n user,\r\n account,\r\n logout,\r\n containerStyle,\r\n}: TopbarProps): React.ReactElement => {\r\n const { theme } = useUi();\r\n const colors = theme.colors;\r\n const primaryColor = theme.palette.primary['500'];\r\n\r\n const richAccount = account !== undefined && isAccountState(account) ? account : undefined;\r\n const legacyAccount = account !== undefined && !isAccountState(account) ? account : undefined;\r\n const upgrade = richAccount?.upgrade;\r\n\r\n return (\r\n <View\r\n style={[\r\n styles.topbarContainer,\r\n { borderBottomColor: colors.border, backgroundColor: colors.background },\r\n containerStyle,\r\n ]}\r\n >\r\n <View style={styles.topbarLeft}>{renderTextSlot(left, { color: colors.text })}</View>\r\n <View style={styles.topbarRight}>\r\n {language ? (\r\n <FocusableTouchable\r\n accessibilityHint={language.hint}\r\n accessibilityLabel={language.label}\r\n ringColor={primaryColor}\r\n style={styles.topbarRowItem}\r\n testID={language.testID}\r\n onPress={language.onPress}\r\n >\r\n <Text style={[styles.topbarLabel, { color: colors.text }]}>{language.label}</Text>\r\n </FocusableTouchable>\r\n ) : null}\r\n\r\n {renderTextSlot(notificationSlot, { color: colors.text })}\r\n\r\n {user ? (\r\n <View style={styles.userBlock}>\r\n <Text style={[styles.userName, { color: colors.text }]}>{user.name}</Text>\r\n <Text style={[styles.userEmail, { color: colors.textSecondary }]}>{user.email}</Text>\r\n </View>\r\n ) : null}\r\n\r\n {richAccount ? (\r\n <View style={styles.userBlock}>\r\n {richAccount.onAccount ? (\r\n <FocusableTouchable\r\n accessibilityHint={richAccount.accountHint ?? richAccount.displayName}\r\n accessibilityLabel={richAccount.displayName}\r\n ringColor={primaryColor}\r\n testID={richAccount.accountTestID ?? NAV_TEST_IDS.accountName}\r\n onPress={richAccount.onAccount}\r\n >\r\n <Text style={[styles.userName, { color: colors.text }]}>{richAccount.displayName}</Text>\r\n </FocusableTouchable>\r\n ) : (\r\n <Text style={[styles.userName, { color: colors.text }]} testID={NAV_TEST_IDS.accountName}>\r\n {richAccount.displayName}\r\n </Text>\r\n )}\r\n\r\n {richAccount.tenantName !== undefined ? (\r\n <Text\r\n style={[styles.accountTenant, { color: colors.textSecondary }]}\r\n testID={NAV_TEST_IDS.accountTenant}\r\n >\r\n {richAccount.tenantName}\r\n </Text>\r\n ) : null}\r\n\r\n {richAccount.plan ? (\r\n <View\r\n style={[styles.planBadge, { backgroundColor: planToneColor(theme, richAccount.plan.tone) }]}\r\n testID={NAV_TEST_IDS.accountPlan}\r\n >\r\n <Text style={[styles.planBadgeText, { color: TEXT_ON_PRIMARY }]}>{richAccount.plan.label}</Text>\r\n </View>\r\n ) : null}\r\n </View>\r\n ) : null}\r\n\r\n {legacyAccount ? (\r\n <FocusableTouchable\r\n accessibilityHint={legacyAccount.hint}\r\n accessibilityLabel={legacyAccount.label}\r\n ringColor={primaryColor}\r\n style={[styles.accountBtn, { backgroundColor: primaryColor }]}\r\n testID={legacyAccount.testID}\r\n onPress={legacyAccount.onPress}\r\n >\r\n <Text style={[styles.accountText, { color: TEXT_ON_PRIMARY }]}>{legacyAccount.label}</Text>\r\n </FocusableTouchable>\r\n ) : null}\r\n\r\n {upgrade ? (\r\n <FocusableTouchable\r\n accessibilityHint={upgrade.hint}\r\n accessibilityLabel={upgrade.label}\r\n ringColor={primaryColor}\r\n style={[styles.accountBtn, { backgroundColor: primaryColor }]}\r\n testID={upgrade.testID ?? NAV_TEST_IDS.accountUpgrade}\r\n onPress={upgrade.onPress}\r\n >\r\n <Text style={[styles.accountText, { color: TEXT_ON_PRIMARY }]}>{upgrade.label}</Text>\r\n </FocusableTouchable>\r\n ) : null}\r\n\r\n <FocusableTouchable\r\n accessibilityHint={logout.hint}\r\n accessibilityLabel={logout.label}\r\n ringColor={primaryColor}\r\n style={[styles.accountBtn, { backgroundColor: primaryColor }]}\r\n testID={logout.testID}\r\n onPress={richAccount ? richAccount.onLogout : logout.onPress}\r\n >\r\n <Text style={[styles.accountText, { color: TEXT_ON_PRIMARY }]}>{logout.label}</Text>\r\n </FocusableTouchable>\r\n </View>\r\n </View>\r\n );\r\n};\r\n\r\nexport default Topbar;\r\n","/**\n * NavBarLink — a SINGLE horizontal `NavBar` link, extracted so each link owns its\n * own hover/focus state (React hooks can't be per-item inside a map otherwise).\n *\n * It renders the v1 `.gn-links a` affordance, THEME-DRIVEN (no hard-coded colours\n * beyond white ink on the accent pill):\n * - rest → muted text (`colors.rest`), no background\n * - hover → text brightens to full contrast (`colors.hoverText`) + a subtle\n * rounded-pill background (`colors.hoverBg`, e.g. v1 `#16223a`)\n * - active → solid accent pill (`colors.activeBg`) with white ink + aria-current\n * - focus → a themed keyboard focus ring (`colors.ring`)\n * Hover/focus are WEB-only (react-native-web fires `onHoverIn/Out`); on native\n * those handlers never fire, so the link stays at its rest style.\n */\nimport React, { useState } from 'react';\n\nimport { Pressable, Text, View, type PressableProps, type ViewStyle } from 'react-native';\n\nimport { navBarStyles as styles } from './styles';\nimport { focusRingStyle, hoverTransitionStyle } from './webStyle';\nimport type { NavItem } from './types';\n\n/** Ink for a link sitting on the primary (active) pill — always full-contrast white. */\nconst TEXT_ON_PRIMARY = '#ffffff';\n\n/** Theme-resolved colours a link needs, computed once by `NavBar`. */\nexport interface NavBarLinkColors {\n /** Muted link text at rest. */\n rest: string;\n /** Brightened link text on hover. */\n hoverText: string;\n /** Subtle hover-pill background. */\n hoverBg: string;\n /** Active-pill background (accent). */\n activeBg: string;\n /** Focus-ring colour. */\n ring: string;\n}\n\nexport interface NavBarLinkProps {\n item: NavItem;\n isActive: boolean;\n collapsed: boolean;\n iconSize: number;\n reducedMotion: boolean;\n colors: NavBarLinkColors;\n navigateHint: (label: string) => string;\n onPress: (route: string) => void;\n}\n\n/**\n * `aria-current=\"page\"` marks the active link for assistive tech. RN's prop types\n * omit `aria-current`, but react-native-web forwards `aria-*` to the DOM — so we\n * attach it (no `any`) only when a link is active.\n */\nfunction ariaCurrentProps(isActive: boolean): PressableProps & { 'aria-current'?: 'page' } {\n return isActive ? { 'aria-current': 'page' } : {};\n}\n\nexport const NavBarLink = ({\n item,\n isActive,\n collapsed,\n iconSize,\n reducedMotion,\n colors,\n navigateHint,\n onPress,\n}: NavBarLinkProps): React.ReactElement => {\n const [hovered, setHovered] = useState(false);\n const [focused, setFocused] = useState(false);\n\n const isHovered = hovered && !isActive;\n const textColor = isActive ? TEXT_ON_PRIMARY : isHovered ? colors.hoverText : colors.rest;\n\n // Only the pill BACKGROUND changes per state — the ~8px rounding comes from the\n // base `styles.link` so the hover + active pills share the same rounded shape.\n const pillStyle: ViewStyle | undefined = isActive\n ? { backgroundColor: colors.activeBg }\n : isHovered\n ? { backgroundColor: colors.hoverBg }\n : undefined;\n\n return (\n <Pressable\n accessibilityHint={navigateHint(item.label)}\n accessibilityLabel={item.label}\n accessibilityRole=\"link\"\n accessibilityState={{ selected: isActive }}\n style={[\n styles.link,\n collapsed ? styles.linkStacked : undefined,\n pillStyle,\n hoverTransitionStyle(reducedMotion),\n focusRingStyle(focused, colors.ring),\n ]}\n testID={item.testID ?? item.key}\n onBlur={() => setFocused(false)}\n onFocus={() => setFocused(true)}\n onHoverIn={() => setHovered(true)}\n onHoverOut={() => setHovered(false)}\n onPress={() => onPress(item.route)}\n {...ariaCurrentProps(isActive)}\n >\n {typeof item.renderIcon === 'function' ? (\n <View style={styles.linkIcon}>{item.renderIcon(textColor, iconSize)}</View>\n ) : null}\n <Text style={[styles.linkText, { color: textColor }]}>{item.label}</Text>\n </Pressable>\n );\n};\n\nexport default NavBarLink;\n","/**\n * NavOverflowMenu — the \"More ▾\" trigger + dropdown that holds the `NavBar` items\n * which don't fit inline (the priority+ overflow set).\n *\n * It REUSES the shared `@dloizides/ui-layout` `ModalDropdown` — the exact component\n * every other menu in the app uses — so the overflow menu is portalled, keyboard\n * navigable, dismissed on outside-click / Escape, and opens on click, looking\n * identical to the rest of the app's menus. The overflow entries are the same\n * `NavItem`s (label + route + active state); selecting one navigates via the same\n * `onNavigate` the inline links use.\n *\n * The trigger is a rounded pill matching a `NavBarLink`: muted at rest, and — when\n * the ACTIVE route lives in the overflow set — it wears the accent pill so the\n * active item stays visibly reachable behind the \"…\". The dropdown marks that same\n * item selected (its `value` is the active overflow route). a11y: `ModalDropdown`\n * owns the trigger's `role=\"button\"` + `aria-expanded` + caller-supplied label/hint,\n * and gives the options keyboard navigation.\n *\n * Contract discipline (as the rest of `@dloizides/ui-nav`): no FM / router / icon\n * set / store; the label + hint are pre-localized strings from the caller and every\n * colour comes from the theme (via the `NavBarLinkColors` the `NavBar` computed).\n */\nimport React, { useMemo } from 'react';\n\nimport { Text, View } from 'react-native';\n\nimport { ModalDropdown, type DropdownVariant } from '@dloizides/ui-layout';\n\nimport { isRouteActive } from './isRouteActive';\nimport type { NavBarLinkColors } from './NavBarLink';\nimport { navBarStyles as styles } from './styles';\nimport type { NavItem } from './types';\n\n/** Ink for the trigger while it wears the active accent pill — full-contrast white. */\nconst TEXT_ON_PRIMARY = '#ffffff';\n/** No overflow item is active → a value that matches no option (nothing selected). */\nconst NO_ACTIVE_ROUTE = '';\n\nexport interface NavOverflowMenuProps {\n /** The items that spilled out of the inline row. */\n items: NavItem[];\n /** Current active route/path — decides the active-pill + selected option. */\n pathname: string;\n /** Navigation callback — receives the chosen item's `route`. */\n onNavigate: (route: string) => void;\n /** Theme-resolved link colours (same set the inline links use). */\n colors: NavBarLinkColors;\n /** Localized visible + accessible label for the trigger (e.g. \"More\"). */\n label: string;\n /** Localized accessibility hint for the trigger. */\n hint: string;\n /** testID for the trigger (options default to `` `${testID}-option-${route}` ``). */\n testID: string;\n /** Force a dropdown variant (default: responsive — inline menu on desktop). */\n variant?: DropdownVariant;\n}\n\nexport const NavOverflowMenu = ({\n items,\n pathname,\n onNavigate,\n colors,\n label,\n hint,\n testID,\n variant,\n}: NavOverflowMenuProps): React.ReactElement => {\n const options = useMemo(() => items.map((item) => ({ label: item.label, value: item.route })), [items]);\n const activeRoute = useMemo(\n () => items.find((item) => isRouteActive(pathname, item.route))?.route ?? NO_ACTIVE_ROUTE,\n [items, pathname],\n );\n const optionTestID = useMemo(() => {\n const byRoute = new Map(items.map((item) => [item.route, item.testID ?? item.key]));\n return (route: string): string => byRoute.get(route) ?? `${testID}-option-${route}`;\n }, [items, testID]);\n\n const hasActive = activeRoute !== NO_ACTIVE_ROUTE;\n const textColor = hasActive ? TEXT_ON_PRIMARY : colors.rest;\n const pillStyle = hasActive ? { backgroundColor: colors.activeBg } : undefined;\n\n return (\n <ModalDropdown<string>\n accessibilityHint={hint}\n accessibilityLabel={label}\n optionTestID={optionTestID}\n options={options}\n testID={testID}\n value={activeRoute}\n variant={variant}\n onChange={onNavigate}\n renderTrigger={({ isOpen }) => (\n <View style={[styles.link, styles.overflowTrigger, pillStyle]}>\n <Text style={[styles.linkText, { color: textColor }]}>{label}</Text>\n <Text style={[styles.overflowChevron, { color: textColor }]}>{isOpen ? '▴' : '▾'}</Text>\n </View>\n )}\n />\n );\n};\n\nexport default NavOverflowMenu;\n","/**\n * Priority+ (\"overflow menu\") fit computation for the horizontal `NavBar`.\n *\n * Pure + framework-free so it can be unit-tested directly: given the available\n * width of the inline links row, the measured natural width of each nav item, and\n * the width of the overflow (\"More ▾\") trigger, it returns how many of the LEADING\n * items fit inline on a single row. Any items beyond the returned count spill into\n * the overflow dropdown.\n *\n * Graceful degradation: it returns `itemWidths.length` (everything inline, no\n * overflow trigger) whenever measurements are not ready yet — `availableWidth <= 0`\n * or any item width `<= 0` — so a first paint before layout resolves (and jsdom /\n * SSR, where there is no layout) shows every item rather than flashing a truncated\n * row. It also returns the full count when every item already fits without a trigger.\n */\nexport interface OverflowMeasurements {\n /** Width available for the inline links row (the flex space between brand + right). */\n availableWidth: number;\n /** Natural pixel width of each nav item, in item order. */\n itemWidths: number[];\n /** Natural pixel width of the overflow (\"More\") trigger. */\n moreWidth: number;\n /** Horizontal gap (px) between adjacent inline items (the row's `columnGap`). */\n gap: number;\n}\n\nfunction sum(values: number[]): number {\n return values.reduce((acc, value) => acc + value, 0);\n}\n\nexport function computeVisibleCount({ availableWidth, itemWidths, moreWidth, gap }: OverflowMeasurements): number {\n const total = itemWidths.length;\n if (total === 0) return 0;\n\n // Unmeasured (pre-layout / SSR / jsdom) → show everything; never truncate before\n // the row has actually been measured, which would flash items in and back out.\n if (availableWidth <= 0 || itemWidths.some((width) => width <= 0)) return total;\n\n // Does the FULL row fit with no overflow trigger at all? Gaps sit BETWEEN items,\n // so `total` items carry `total - 1` gaps.\n const fullRowWidth = sum(itemWidths) + gap * (total - 1);\n if (fullRowWidth <= availableWidth) return total;\n\n // Overflow is needed: reserve room for the More trigger (plus the gap before it)\n // and greedily fit the leading items. `used` grows by each item plus the gap that\n // precedes it (every item after the first).\n const reservedForMore = moreWidth + gap;\n let used = 0;\n let count = 0;\n for (let index = 0; index < total; index += 1) {\n const width = itemWidths[index] ?? 0;\n const withGap = used + (count > 0 ? gap : 0) + width;\n if (withGap + reservedForMore > availableWidth) break;\n used = withGap;\n count += 1;\n }\n return count;\n}\n","/**\n * `useNavOverflow` — the measurement state behind the `NavBar` priority+ overflow.\n *\n * It owns the measured widths (available row width, each item's natural width, the\n * \"More\" trigger width) and derives, via the pure {@link computeVisibleCount}, how\n * many leading items fit inline. The actual measuring is done by the caller wiring\n * RN's `onLayout` (react-native-web backs it with a `ResizeObserver`, so it re-fires\n * on resize — no manual `window` access, SSR-safe) into the setters returned here.\n *\n * Widths are cached per item index: an item measured while inline keeps its width\n * after it spills into the overflow menu (its content width does not change), so a\n * resize narrower reuses the cached width and a resize wider brings it back inline\n * and re-measures (a no-op). When the item COUNT changes the buffer is reset to\n * unmeasured (0), so `computeVisibleCount` shows every item until the new row is\n * measured again.\n */\nimport { useCallback, useEffect, useMemo, useState } from 'react';\n\nimport { computeVisibleCount } from './computeVisibleCount';\n\nexport interface NavOverflowState {\n /** How many leading items to render inline; the rest go into the overflow menu. */\n visibleCount: number;\n /** Wire to the links row's `onLayout` (its resolved flex width = available space). */\n setAvailableWidth: (width: number) => void;\n /** Wire to item `index`'s `onLayout` to record its natural width. */\n setItemWidth: (index: number, width: number) => void;\n /** Wire to the overflow (\"More\") trigger's `onLayout`. */\n setMoreWidth: (width: number) => void;\n}\n\nfunction resizeWidthBuffer(previous: number[], count: number): number[] {\n const next = new Array<number>(count).fill(0);\n const shared = Math.min(previous.length, count);\n for (let index = 0; index < shared; index += 1) next[index] = previous[index] ?? 0;\n return next;\n}\n\nexport function useNavOverflow(itemCount: number, gap: number): NavOverflowState {\n const [availableWidth, setAvailableWidthState] = useState(0);\n const [moreWidth, setMoreWidthState] = useState(0);\n const [itemWidths, setItemWidths] = useState<number[]>(() => new Array<number>(itemCount).fill(0));\n\n // Item count changed (items added / removed) → reset to unmeasured so we show all\n // and re-measure, preserving any still-valid leading widths.\n useEffect(() => {\n setItemWidths((previous) => (previous.length === itemCount ? previous : resizeWidthBuffer(previous, itemCount)));\n }, [itemCount]);\n\n const setItemWidth = useCallback((index: number, width: number) => {\n setItemWidths((previous) => {\n if (index < 0 || index >= previous.length || previous[index] === width) return previous;\n const next = previous.slice();\n next[index] = width;\n return next;\n });\n }, []);\n\n const setAvailableWidth = useCallback(\n (width: number) => setAvailableWidthState((previous) => (previous === width ? previous : width)),\n [],\n );\n const setMoreWidth = useCallback(\n (width: number) => setMoreWidthState((previous) => (previous === width ? previous : width)),\n [],\n );\n\n const visibleCount = useMemo(\n () => computeVisibleCount({ availableWidth, itemWidths, moreWidth, gap }),\n [availableWidth, itemWidths, moreWidth, gap],\n );\n\n return { visibleCount, setAvailableWidth, setItemWidth, setMoreWidth };\n}\n","/**\n * `useReducedMotion` — `true` when the user has asked the OS/browser to minimise\n * motion (`prefers-reduced-motion: reduce`). It is a WEB-only signal read from\n * `window.matchMedia`; on native (no `matchMedia`) it is always `false`. The\n * `NavBar` uses it to drop the hover-pill CSS transition for motion-sensitive\n * users. Cheap: one media-query subscription, no JS animation.\n */\nimport { useEffect, useState } from 'react';\n\nconst REDUCED_MOTION_QUERY = '(prefers-reduced-motion: reduce)';\n\n/** The slice of `MediaQueryList` we rely on — kept minimal so native builds needn't provide it. */\ninterface MediaQueryListLike {\n matches: boolean;\n addEventListener?: (type: 'change', listener: () => void) => void;\n removeEventListener?: (type: 'change', listener: () => void) => void;\n}\n\n/** Resolve the reduced-motion media query on web; `undefined` where `matchMedia` is unavailable. */\nfunction getReducedMotionQuery(): MediaQueryListLike | undefined {\n if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return undefined;\n return window.matchMedia(REDUCED_MOTION_QUERY);\n}\n\nexport function useReducedMotion(): boolean {\n const [reduced, setReduced] = useState<boolean>(() => getReducedMotionQuery()?.matches ?? false);\n\n useEffect(() => {\n const mql = getReducedMotionQuery();\n if (mql === undefined || mql.addEventListener === undefined) return undefined;\n const onChange = (): void => setReduced(mql.matches);\n mql.addEventListener('change', onChange);\n return () => {\n mql.removeEventListener?.('change', onChange);\n };\n }, []);\n\n return reduced;\n}\n\nexport default useReducedMotion;\n","/**\r\n * NavBar — the config-driven HORIZONTAL top navigation bar. It is the top-bar\r\n * counterpart to `Sidebar`: it renders the SAME caller-supplied `NavItem[]`\r\n * (already role-filtered / localized by the app) as inline links across the top\r\n * instead of a left rail, with an optional brand slot on the left and a free-form\r\n * right slot (auth link / user / logout). Below a configurable breakpoint it\r\n * collapses the links behind a hamburger toggle — mirroring the v1 AML console's\r\n * responsive `.global-nav`.\r\n *\r\n * Look + feel: each link is a rounded-pill target with the v1 `.gn-links a`\r\n * affordance — muted at rest, brightening text + a subtle pill background on\r\n * HOVER, and a solid accent pill when ACTIVE. All colours are THEME-DRIVEN from\r\n * the `@dloizides/ui-feedback` UiProvider (rest=`textSecondary`, hover text=`text`,\r\n * hover bg=`surfaceElevated`, active=`palette.primary`, ring=`palette.primary`).\r\n * Hover/focus are web-only (react-native-web); native stays at the rest style.\r\n *\r\n * Overflow (\"…\" priority+ menu). Above the `collapseBelow` breakpoint the links sit\r\n * on ONE row; when they don't all fit, a measure pass ({@link useNavOverflow} +\r\n * {@link computeVisibleCount}) keeps the leading items that fit inline and collapses\r\n * the rest behind a \"More ▾\" trigger — the shared `ModalDropdown` (see\r\n * {@link NavOverflowMenu}) — so no item is ever cut off. BELOW `collapseBelow` the\r\n * whole set still collapses into the responsive hamburger drawer (all items stacked),\r\n * so the two mechanisms don't overlap: hamburger for true mobile, \"…\" for the\r\n * in-between desktop case where only SOME items spill.\r\n *\r\n * Contract discipline (same as the rest of `@dloizides/ui-nav`): NO FM, router,\r\n * icon set, or store imports. Labels are pre-localized strings, icons are render\r\n * slots, and every colour is read from the theme. This is purely additive —\r\n * `Sidebar`/`Topbar` are unchanged and the new overflow labels are optional.\r\n */\r\nimport React, { useCallback, useMemo, useState } from 'react';\r\n\r\nimport {\r\n Pressable,\r\n Text,\r\n useWindowDimensions,\r\n View,\r\n type LayoutChangeEvent,\r\n type PressableProps,\r\n type ViewStyle,\r\n} from 'react-native';\r\n\r\nimport { useUi, UiProvider, type UiTheme } from '@dloizides/ui-feedback';\r\n\r\nimport { NAV_TEST_IDS } from './constants';\r\nimport { isRouteActive } from './isRouteActive';\r\nimport { NavBarLink, type NavBarLinkColors } from './NavBarLink';\r\nimport { NavOverflowMenu } from './NavOverflowMenu';\r\nimport { navBarStyles as styles, NAV_ICON_SIZE, NAV_LINK_GAP } from './styles';\r\nimport type { NavItem } from './types';\r\nimport { useNavOverflow } from './useNavOverflow';\r\nimport { useReducedMotion } from './useReducedMotion';\r\nimport { focusRingStyle } from './webStyle';\r\nimport { renderTextSlot } from './textSlot';\r\n\r\n/** DOM id linking the toggle (`aria-controls`) to the collapsible links region. */\r\nconst LINKS_REGION_ID = 'navbar-links-region';\r\n/** Collapse to a hamburger at/under this viewport width (matches v1's 760px). */\r\nconst DEFAULT_COLLAPSE_BELOW = 760;\r\n/** Default hamburger glyph (☰) when no `renderMenuIcon` is supplied. */\r\nconst MENU_GLYPH = '☰';\r\n\r\nexport interface NavBarProps {\r\n /** Nav entries — already role-filtered / grouped by the app. */\r\n items: NavItem[];\r\n /** Current active route/path. */\r\n pathname: string;\r\n /** Navigation callback — receives a `NavItem.route`. */\r\n onNavigate: (route: string) => void;\r\n /** Localized accessibility label for the navigation landmark. */\r\n regionLabel: string;\r\n /** a11y hint for a link, given its label. Defaults to the label. */\r\n navigateHint?: (label: string) => string;\r\n /** Left slot — typically the brand / tenant logo. */\r\n brand?: React.ReactNode;\r\n /** Right slot — free-form (auth link, user block, logout). */\r\n right?: React.ReactNode;\r\n /** Localized accessibility label for the responsive menu toggle. */\r\n menuLabel?: string;\r\n /** Localized accessibility hint for the responsive menu toggle. */\r\n menuHint?: string;\r\n /** Optional custom glyph renderer for the toggle; defaults to ☰. */\r\n renderMenuIcon?: (color: string, open: boolean) => React.ReactNode;\r\n /** Collapse the links behind a hamburger below this viewport width (default 760). */\r\n collapseBelow?: number;\r\n /**\r\n * Localized visible + accessible label for the \"More ▾\" overflow trigger shown when\r\n * the inline links don't all fit on one row (priority+ menu). Defaults to `\"More\"`.\r\n */\r\n overflowLabel?: string;\r\n /** Localized accessibility hint for the overflow trigger. */\r\n overflowHint?: string;\r\n /** Extra container style overrides. */\r\n containerStyle?: ViewStyle | ViewStyle[];\r\n /**\r\n * Optional content-column cap (px). When set, the OUTER container — which carries\r\n * the background + bottom border (`barTheme`/theme surface + any `containerStyle`,\r\n * e.g. the AML radial-glow appbar) — stays FULL WIDTH (full-bleed), while the INNER\r\n * row (brand + links + right) is capped to this width and centred. Omit for the\r\n * default where the inner spans the full container. The priority+ overflow \"…\" fit\r\n * measures the (now capped) inner's rendered width via `onLayout`, so it keeps\r\n * working against the capped column, not the full-bleed container.\r\n */\r\n contentMaxWidth?: number;\r\n /**\r\n * Optional CHROME theme override — re-provisions the `@dloizides/ui-feedback`\r\n * theme for the bar ONLY, so the top bar can be dark while the page below keeps\r\n * the light workspace theme (the AML v1-console \"dark appbar over light content\"\r\n * pattern). The live `t` (+ `navigate`) from the surrounding provider are\r\n * re-passed, so nav labels keep localizing. Omit for a bar that shares the page\r\n * theme. Style-only: every colour still flows through the theme — no per-app fork.\r\n */\r\n barTheme?: UiTheme;\r\n}\r\n\r\n/**\r\n * `aria-controls` links the toggle to the collapsible links region. RN's prop\r\n * types omit `aria-controls`, but react-native-web forwards `aria-*` to the DOM —\r\n * so we attach it (no `any`).\r\n */\r\nfunction ariaControlsProps(id: string): PressableProps & { 'aria-controls'?: string } {\r\n return { 'aria-controls': id };\r\n}\r\n\r\nconst NavBarInner = ({\r\n items,\r\n pathname,\r\n onNavigate,\r\n regionLabel,\r\n navigateHint = (label) => label,\r\n brand,\r\n right,\r\n menuLabel = 'Menu',\r\n menuHint = '',\r\n renderMenuIcon,\r\n collapseBelow = DEFAULT_COLLAPSE_BELOW,\r\n overflowLabel = 'More',\r\n overflowHint = '',\r\n containerStyle,\r\n contentMaxWidth,\r\n}: Omit<NavBarProps, 'barTheme'>): React.ReactElement => {\r\n const { theme } = useUi();\r\n const colors = theme.colors;\r\n const primaryColor = theme.palette.primary['500'];\r\n const { width } = useWindowDimensions();\r\n const reducedMotion = useReducedMotion();\r\n const [open, setOpen] = useState(false);\r\n const [toggleFocused, setToggleFocused] = useState(false);\r\n const { visibleCount, setAvailableWidth, setItemWidth, setMoreWidth } = useNavOverflow(items.length, NAV_LINK_GAP);\r\n\r\n const collapsed = width < collapseBelow;\r\n const showLinks = !collapsed || open;\r\n\r\n // Content-column cap: keep the OUTER container full-bleed (its background + bottom\r\n // border span the viewport) and cap only the INNER row, centred. Omitted ⇒ null ⇒\r\n // the inner spans the full container (unchanged). The overflow \"…\" fit still measures\r\n // the inner's rendered width, so it reasons about the capped column, not the container.\r\n const innerCapStyle = useMemo<ViewStyle | null>(\r\n () => (contentMaxWidth === undefined ? null : { maxWidth: contentMaxWidth, width: '100%', alignSelf: 'center' }),\r\n [contentMaxWidth],\r\n );\r\n\r\n const toggleMenu = useCallback(() => setOpen((v) => !v), []);\r\n const handlePress = useCallback(\r\n (route: string) => {\r\n setOpen(false);\r\n onNavigate(route);\r\n },\r\n [onNavigate],\r\n );\r\n\r\n // Theme-driven link colours (v1 `.gn-links a`): muted → brightened-on-hover text,\r\n // a subtle raised pill on hover, the accent pill when active, accent focus ring.\r\n const linkColors = useMemo<NavBarLinkColors>(\r\n () => ({\r\n rest: colors.textSecondary,\r\n hoverText: colors.text,\r\n hoverBg: colors.surfaceElevated,\r\n activeBg: primaryColor,\r\n ring: primaryColor,\r\n }),\r\n [colors.textSecondary, colors.text, colors.surfaceElevated, primaryColor],\r\n );\r\n\r\n return (\r\n <View\r\n accessibilityRole=\"none\"\r\n aria-label={regionLabel}\r\n role=\"navigation\"\r\n style={[\r\n styles.container,\r\n { backgroundColor: colors.surface, borderBottomColor: colors.border },\r\n containerStyle,\r\n ]}\r\n >\r\n <View style={[styles.inner, collapsed ? null : styles.innerNoWrap, innerCapStyle]}>\r\n {brand !== undefined ? (\r\n <View style={styles.brand}>{renderTextSlot(brand, { color: colors.text })}</View>\r\n ) : null}\r\n\r\n {collapsed ? (\r\n <Pressable\r\n accessibilityHint={menuHint}\r\n accessibilityLabel={menuLabel}\r\n accessibilityRole=\"button\"\r\n accessibilityState={{ expanded: open }}\r\n aria-expanded={open}\r\n style={[styles.toggle, focusRingStyle(toggleFocused, primaryColor)]}\r\n testID={NAV_TEST_IDS.navBarToggle}\r\n onBlur={() => setToggleFocused(false)}\r\n onFocus={() => setToggleFocused(true)}\r\n onPress={toggleMenu}\r\n {...ariaControlsProps(LINKS_REGION_ID)}\r\n >\r\n {typeof renderMenuIcon === 'function' ? (\r\n renderMenuIcon(colors.text, open)\r\n ) : (\r\n <Text style={[styles.toggleGlyph, { color: colors.text }]}>{MENU_GLYPH}</Text>\r\n )}\r\n </Pressable>\r\n ) : null}\r\n\r\n {showLinks\r\n ? (() => {\r\n const renderLink = (item: NavItem): React.ReactElement => (\r\n <NavBarLink\r\n collapsed={collapsed}\r\n colors={linkColors}\r\n iconSize={NAV_ICON_SIZE}\r\n isActive={isRouteActive(pathname, item.route)}\r\n item={item}\r\n navigateHint={navigateHint}\r\n reducedMotion={reducedMotion}\r\n onPress={handlePress}\r\n />\r\n );\r\n // Collapsed (mobile): every item stacks vertically on its own full-width line — the\r\n // responsive hamburger drawer. No overflow menu here; the drawer already holds them all.\r\n if (collapsed) {\r\n return (\r\n <View nativeID={LINKS_REGION_ID} style={styles.linksStacked} testID={NAV_TEST_IDS.navBarLinks}>\r\n {items.map((item) => (\r\n <React.Fragment key={item.key}>{renderLink(item)}</React.Fragment>\r\n ))}\r\n </View>\r\n );\r\n }\r\n // Expanded (desktop): ONE non-wrapping row. A measure pass keeps the leading items\r\n // that fit inline and collapses the rest behind the \"More ▾\" overflow trigger. Each\r\n // inline cell reports its natural width via onLayout; the row reports the available\r\n // width. Until measured, every item shows (computeVisibleCount returns the full count).\r\n const visibleItems = items.slice(0, visibleCount);\r\n const overflowItems = items.slice(visibleCount);\r\n return (\r\n <View\r\n nativeID={LINKS_REGION_ID}\r\n style={styles.linksRow}\r\n testID={NAV_TEST_IDS.navBarLinks}\r\n onLayout={(event: LayoutChangeEvent) => setAvailableWidth(event.nativeEvent.layout.width)}\r\n >\r\n {visibleItems.map((item, index) => (\r\n <View\r\n key={item.key}\r\n style={styles.linkCell}\r\n onLayout={(event: LayoutChangeEvent) => setItemWidth(index, event.nativeEvent.layout.width)}\r\n >\r\n {renderLink(item)}\r\n </View>\r\n ))}\r\n {overflowItems.length > 0 ? (\r\n <View\r\n style={styles.linkCell}\r\n onLayout={(event: LayoutChangeEvent) => setMoreWidth(event.nativeEvent.layout.width)}\r\n >\r\n <NavOverflowMenu\r\n colors={linkColors}\r\n hint={overflowHint}\r\n items={overflowItems}\r\n label={overflowLabel}\r\n pathname={pathname}\r\n testID={NAV_TEST_IDS.navBarOverflow}\r\n onNavigate={handlePress}\r\n />\r\n </View>\r\n ) : null}\r\n </View>\r\n );\r\n })()\r\n : null}\r\n\r\n {showLinks && right !== undefined ? (\r\n <View style={collapsed ? styles.rightStacked : styles.right}>\r\n {renderTextSlot(right, { color: colors.text })}\r\n </View>\r\n ) : null}\r\n </View>\r\n </View>\r\n );\r\n};\r\n\r\n/**\r\n * `NavBar` — the horizontal top bar. When `barTheme` is supplied it re-provisions\r\n * the `@dloizides/ui-feedback` theme around the bar (dark bar over a light page),\r\n * re-passing the live `t` / `navigate` so labels keep localizing; otherwise it\r\n * renders directly against the surrounding theme (byte-identical to before).\r\n */\r\nexport const NavBar = ({ barTheme, ...props }: NavBarProps): React.ReactElement => {\r\n const { t, navigate } = useUi();\r\n if (barTheme === undefined) return <NavBarInner {...props} />;\r\n return (\r\n <UiProvider navigate={navigate} t={t} theme={barTheme}>\r\n <NavBarInner {...props} />\r\n </UiProvider>\r\n );\r\n};\r\n\r\nexport { isRouteActive };\r\nexport default NavBar;\r\n","/**\n * `Nav` — ONE component that renders EITHER the horizontal top bar (`NavBar`) or the\n * vertical rail (`Sidebar`) from the same `NavItem[]`, chosen by a single\n * `orientation` prop. It lets an app flip its navigation between a top bar and a side\n * menu without swapping components or re-plumbing props:\n *\n * <Nav orientation=\"horizontal\" items={items} pathname={p} onNavigate={go} .../> // NavBar\n * <Nav orientation=\"vertical\" items={items} pathname={p} onNavigate={go} .../> // Sidebar\n *\n * `orientation` defaults to `\"horizontal\"`. The remaining props are exactly the\n * delegate's props — a discriminated union — so TypeScript enforces the right prop\n * set per orientation (e.g. `title` is required only for the vertical/Sidebar side,\n * `collapseBelow` / `overflowLabel` only for the horizontal/NavBar side).\n *\n * `Nav` is purely additive: `NavBar` and `Sidebar` remain exported and unchanged, so\n * every existing consumer (erevna / katalogos / kefi / agora) is untouched. Vertical\n * navigation is the existing Sidebar — stacked links that scroll vertically, so it\n * needs no overflow menu; the priority+ \"…\" overflow is a horizontal-bar concern.\n */\nimport React from 'react';\n\nimport { NavBar, type NavBarProps } from './NavBar';\nimport { Sidebar, type SidebarProps } from './Sidebar';\n\n/** Which axis the navigation renders on. */\nexport type NavOrientation = 'horizontal' | 'vertical';\n\nexport type NavProps =\n | ({ orientation?: 'horizontal' } & NavBarProps)\n | ({ orientation: 'vertical' } & SidebarProps);\n\nexport const Nav = (props: NavProps): React.ReactElement => {\n // `orientation` is only the discriminant; the delegates (`Sidebar` / `NavBar`)\n // read their own known props and ignore the extra field, so the whole narrowed\n // props object can be spread straight through (a JSX spread is not excess-checked).\n if (props.orientation === 'vertical') {\n return <Sidebar {...props} />;\n }\n return <NavBar {...props} />;\n};\n\nexport default Nav;\n","/**\n * AppShell content-body helpers — the page-state cards (loading / error /\n * forbidden) and the precedence rule that picks what renders inside the content\n * column. Split out of `AppShell` so the shell file stays focused on layout /\n * responsive composition. Colours are routed through the `@dloizides/ui-feedback`\n * theme, same as the rest of `@dloizides/ui-nav`.\n */\nimport React from 'react';\n\nimport { ActivityIndicator, StyleSheet, Text, View } from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\n\nimport { APP_SHELL_SUFFIX } from './constants';\n\nconst CARD_PADDING = 20;\nconst CARD_BORDER_RADIUS = 12;\nconst CARD_BORDER_WIDTH = 1;\nconst CARD_TITLE_FONT_SIZE = 16;\nconst CARD_MESSAGE_FONT_SIZE = 14;\nconst CARD_TITLE_MARGIN_BOTTOM = 8;\n\nconst styles = StyleSheet.create({\n centerFill: { flex: 1, justifyContent: 'center', alignItems: 'center' },\n card: {\n padding: CARD_PADDING,\n borderRadius: CARD_BORDER_RADIUS,\n borderWidth: CARD_BORDER_WIDTH,\n },\n cardTitle: { fontSize: CARD_TITLE_FONT_SIZE, fontWeight: '700', marginBottom: CARD_TITLE_MARGIN_BOTTOM },\n cardMessage: { fontSize: CARD_MESSAGE_FONT_SIZE },\n});\n\n/** A titled message card (error / forbidden). Colours come from the theme. */\nexport interface ShellMessage {\n titleText: string;\n messageText: string;\n}\n\n/** Page-state model — a loading spinner card, or a titled error / forbidden card. */\nexport interface ShellState {\n loading?: boolean;\n error?: ShellMessage | null;\n forbidden?: ShellMessage | null;\n}\n\nfunction MessageCard({\n message,\n accentColor,\n testID,\n}: {\n message: ShellMessage;\n accentColor: string;\n testID: string;\n}): React.ReactElement {\n const { theme } = useUi();\n const colors = theme.colors;\n return (\n <View style={[styles.card, { backgroundColor: colors.surface, borderColor: accentColor }]} testID={testID}>\n <Text style={[styles.cardTitle, { color: accentColor }]}>{message.titleText}</Text>\n <Text style={[styles.cardMessage, { color: colors.textSecondary }]}>{message.messageText}</Text>\n </View>\n );\n}\n\n/** Pick what renders inside the content column, honouring state precedence. */\nexport function useContentBody(\n state: ShellState | undefined,\n children: React.ReactNode,\n testID: string,\n): React.ReactNode {\n const { theme } = useUi();\n const primary = theme.palette.primary['500'];\n const errorColor = theme.semantic.error['500'];\n\n if (state?.forbidden)\n return <MessageCard accentColor={errorColor} message={state.forbidden} testID={`${testID}${APP_SHELL_SUFFIX.forbidden}`} />;\n if (state?.error)\n return <MessageCard accentColor={errorColor} message={state.error} testID={`${testID}${APP_SHELL_SUFFIX.error}`} />;\n if (state?.loading === true)\n return (\n <View style={styles.centerFill} testID={`${testID}${APP_SHELL_SUFFIX.loading}`}>\n <ActivityIndicator color={primary} size=\"large\" />\n </View>\n );\n return children;\n}\n","/**\r\n * MobileDrawer — the below-the-breakpoint face of `AppShell`'s back-office\r\n * `sidebar` layout. On a narrow viewport (<768px) the persistent left rail would\r\n * starve the content column, so instead of the rail we render a hamburger toggle\r\n * (`MenuToggle`) in the header and slide the same `Sidebar` in as an overlay\r\n * drawer (a scrim + a left panel). The drawer closes on a scrim tap and on any\r\n * nav-item press inside the panel (web: a bubbled click on a `role=\"button\"` /\r\n * link element). Desktop is untouched — AppShell never mounts this above 768px.\r\n *\r\n * Contract discipline (same as the rest of `@dloizides/ui-nav`): NO FM / router /\r\n * store imports. Labels are pre-localized strings (English defaults, overridable\r\n * by the consumer via `AppShell`'s `mobileMenu` prop); every colour is read from\r\n * the `@dloizides/ui-feedback` UiProvider theme.\r\n */\r\nimport React, { useEffect, useRef } from 'react';\r\n\r\nimport { Pressable, StyleSheet, Text, View } from 'react-native';\r\n\r\nimport { useUi } from '@dloizides/ui-feedback';\r\n\r\nimport { FocusableTouchable } from './FocusableTouchable';\r\nimport { renderTextSlot } from './textSlot';\r\n\r\n/** Collapse the persistent rail into a drawer at/under this viewport width. */\r\nexport const MOBILE_BREAKPOINT = 768;\r\n\r\nconst SCRIM_COLOR = 'rgba(0, 0, 0, 0.5)';\r\nconst MENU_GLYPH = '☰';\r\nconst MENU_MIN_TARGET = 44;\r\nconst MENU_GLYPH_FONT_SIZE = 20;\r\nconst MENU_TOGGLE_PADDING = 12;\r\nconst DRAWER_Z_INDEX = 50;\r\n/**\r\n * Fixed width (px) of the sliding drawer panel. It must be > 0 and anchored so the\r\n * scrim can sit BESIDE it (see below): a panel with no width — the pre-1.10.2 bug —\r\n * establishes no hit area, and a full-bleed scrim then swallowed every nav tap.\r\n */\r\nconst DRAWER_WIDTH = 280;\r\n/**\r\n * The panel stacks ABOVE the scrim within the overlay. Equal zIndex (both 0, the\r\n * old geometry) left react-native-web to break the tie by DOM order — unreliable\r\n * for pointer capture, which is how the full-bleed scrim intercepted panel presses.\r\n */\r\nconst SCRIM_Z_INDEX = 1;\r\nconst PANEL_Z_INDEX = 2;\r\n/**\r\n * A nav element that, when clicked inside the open drawer, should close it.\r\n * react-native-web maps `accessibilityRole` -> the DOM `role`, so the Sidebar's\r\n * leaf `TouchableOpacity`s render as `role=\"button\"` and match here.\r\n */\r\nconst NAV_ACTIVATABLE_SELECTOR = 'a, [role=\"button\"], [role=\"link\"]';\r\n/**\r\n * An expandable GROUP HEADER is also a `role=\"button\"` (see `NavExpandableItem`),\r\n * but its press only TOGGLES the section — it does not navigate — so the drawer\r\n * must stay open. A toggle carries `aria-expanded` (from `accessibilityState.\r\n * expanded`); a navigating leaf never does. So we treat a click whose closest\r\n * activatable is (or is inside) an `aria-expanded` element as a toggle, not a\r\n * navigation, and leave the drawer open. Without this, tapping a group to expand\r\n * it dismissed the whole drawer (the 1.11.0 grouped-nav regression).\r\n */\r\nconst NAV_TOGGLE_SELECTOR = '[aria-expanded]';\r\n\r\n/** Pre-localized labels for the drawer's hamburger + scrim. */\r\nexport interface DrawerLabels {\r\n /** Accessible name of the hamburger that opens the drawer. */\r\n openLabel: string;\r\n /** Accessible hint of the hamburger that opens the drawer. */\r\n openHint: string;\r\n /** Accessible name of the scrim (tap to close). */\r\n closeLabel: string;\r\n /** Accessible hint of the scrim (tap to close). */\r\n closeHint: string;\r\n}\r\n\r\n/** English defaults — the consumer overrides these with localized strings. */\r\nexport const DEFAULT_DRAWER_LABELS: DrawerLabels = {\r\n openLabel: 'Menu',\r\n openHint: 'Open the navigation menu',\r\n closeLabel: 'Close menu',\r\n closeHint: 'Close the navigation menu',\r\n};\r\n\r\nconst styles = StyleSheet.create({\r\n overlay: { ...StyleSheet.absoluteFillObject, zIndex: DRAWER_Z_INDEX },\r\n // The scrim's tap-to-close hit area is anchored to the RIGHT of the panel\r\n // (`left: DRAWER_WIDTH`), so it NEVER overlaps the panel: nav-item taps always\r\n // reach the Sidebar's TouchableOpacity, while taps beside the drawer still close.\r\n scrim: {\r\n position: 'absolute',\r\n top: 0,\r\n bottom: 0,\r\n left: DRAWER_WIDTH,\r\n right: 0,\r\n backgroundColor: SCRIM_COLOR,\r\n zIndex: SCRIM_Z_INDEX,\r\n },\r\n // The panel gets an explicit width (a real drawer) AND a zIndex above the scrim,\r\n // so on react-native-web it — and the nav leaves inside it — sit above the scrim\r\n // and receive presses instead of the scrim swallowing them.\r\n panel: { position: 'absolute', top: 0, bottom: 0, left: 0, width: DRAWER_WIDTH, zIndex: PANEL_Z_INDEX },\r\n menuToggle: {\r\n minWidth: MENU_MIN_TARGET,\r\n minHeight: MENU_MIN_TARGET,\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n paddingHorizontal: MENU_TOGGLE_PADDING,\r\n },\r\n menuToggleGlyph: { fontSize: MENU_GLYPH_FONT_SIZE, fontWeight: '700' },\r\n});\r\n\r\nexport interface MenuToggleProps {\r\n label: string;\r\n hint: string;\r\n onOpen: () => void;\r\n testID: string;\r\n}\r\n\r\n/** The mobile hamburger button, rendered in the header region below the breakpoint. */\r\nexport const MenuToggle = ({ label, hint, onOpen, testID }: MenuToggleProps): React.ReactElement => {\r\n const { theme } = useUi();\r\n return (\r\n <FocusableTouchable\r\n accessibilityHint={hint}\r\n accessibilityLabel={label}\r\n ringColor={theme.palette.primary['500']}\r\n style={styles.menuToggle}\r\n testID={testID}\r\n onPress={onOpen}\r\n >\r\n <Text style={[styles.menuToggleGlyph, { color: theme.colors.text }]}>{MENU_GLYPH}</Text>\r\n </FocusableTouchable>\r\n );\r\n};\r\n\r\nexport interface MobileDrawerProps {\r\n /** The `Sidebar` slot to render inside the drawer panel. */\r\n sidebar: React.ReactNode;\r\n /** Pre-localized close (scrim) labels. */\r\n labels: DrawerLabels;\r\n /** Close the drawer. */\r\n onClose: () => void;\r\n /** testID for the drawer panel. */\r\n drawerTestID: string;\r\n /** testID for the scrim. */\r\n scrimTestID: string;\r\n}\r\n\r\n/** The open drawer overlay: a tap-to-close scrim + the sidebar panel. */\r\nexport const MobileDrawer = ({\r\n sidebar,\r\n labels,\r\n onClose,\r\n drawerTestID,\r\n scrimTestID,\r\n}: MobileDrawerProps): React.ReactElement => {\r\n const { theme } = useUi();\r\n const panelRef = useRef<View | null>(null);\r\n\r\n // Close on a nav-item press. The consumer wires the Sidebar's `onNavigate`\r\n // directly to the router, so we cannot intercept that callback; instead (on\r\n // web) we watch for a bubbled click on an activatable element inside the panel.\r\n useEffect(() => {\r\n const node = panelRef.current as unknown as HTMLElement | null;\r\n if (node === null || typeof node.addEventListener !== 'function') return undefined;\r\n const handleClick = (event: MouseEvent): void => {\r\n const target = event.target as HTMLElement | null;\r\n if (target === null) return;\r\n const activatable = target.closest(NAV_ACTIVATABLE_SELECTOR);\r\n // A group-header toggle is a `role=\"button\"` too — only a real navigation\r\n // (a leaf, never an `aria-expanded` toggle) should dismiss the drawer.\r\n const isToggle = activatable !== null && activatable.closest(NAV_TOGGLE_SELECTOR) !== null;\r\n if (activatable !== null && !isToggle) onClose();\r\n };\r\n node.addEventListener('click', handleClick);\r\n return () => node.removeEventListener('click', handleClick);\r\n }, [onClose]);\r\n\r\n return (\r\n <View style={styles.overlay}>\r\n <Pressable\r\n accessibilityHint={labels.closeHint}\r\n accessibilityLabel={labels.closeLabel}\r\n accessibilityRole=\"button\"\r\n style={styles.scrim}\r\n testID={scrimTestID}\r\n onPress={onClose}\r\n />\r\n <View\r\n ref={panelRef}\r\n aria-modal\r\n role=\"dialog\"\r\n style={[styles.panel, { backgroundColor: theme.colors.surface }]}\r\n testID={drawerTestID}\r\n >\r\n {renderTextSlot(sidebar, { color: theme.colors.text })}\r\n </View>\r\n </View>\r\n );\r\n};\r\n\r\nexport default MobileDrawer;\r\n","/**\n * Rail responsive mode — the pure (viewport → which rail face) rule behind\n * `AppShell`'s optional THREE-tier layout, split out so it is directly\n * unit-testable.\n *\n * Two-tier (default, back-compat): a persistent full rail at/above\n * {@link RAIL_FULL_BREAKPOINT}, an overlay drawer below it. This is what every\n * existing `AppShell` `sidebar` consumer already gets.\n *\n * Three-tier (opt-in — supply a `collapsedSidebar`): a persistent full rail on\n * desktop, an intermediate persistent COLLAPSED (icon-only) rail on tablet, and\n * the overlay drawer on a phone — the erevna / katalogos responsive scheme.\n */\n\n/** At/above this viewport width the persistent FULL rail shows (two-tier boundary). */\nexport const RAIL_FULL_BREAKPOINT = 768;\n/** Default upper bound of the collapsed-rail band (full rail at/above this). */\nexport const DEFAULT_COLLAPSED_RAIL_MAX = 1024;\n\n/** Which face the rail takes at a given viewport. */\nexport type RailMode = 'none' | 'full' | 'collapsed' | 'drawer';\n\n/**\n * Viewport band in which the intermediate COLLAPSED icon-rail shows: `[min, max)`.\n * At/above `max` the full rail shows; below `min` the overlay drawer shows.\n */\nexport interface CollapsedRailRange {\n min: number;\n max: number;\n}\n\nexport interface ResolveRailModeArgs {\n viewport: number;\n /** Whether a `sidebar` (full rail) node was supplied at all. */\n hasSidebar: boolean;\n /** Whether an intermediate `collapsedSidebar` node was supplied (enables 3-tier). */\n hasCollapsed: boolean;\n /** The collapsed-rail band; only consulted in 3-tier mode. */\n range: CollapsedRailRange;\n}\n\n/**\n * Resolve the rail mode. No sidebar ⇒ `'none'`. With a `collapsedSidebar`\n * (3-tier): full at/above `range.max`, collapsed in `[range.min, range.max)`,\n * drawer below `range.min`. Without one (2-tier, unchanged): full at/above\n * {@link RAIL_FULL_BREAKPOINT}, drawer below.\n */\nexport function resolveRailMode({ viewport, hasSidebar, hasCollapsed, range }: ResolveRailModeArgs): RailMode {\n if (!hasSidebar) return 'none';\n if (hasCollapsed) {\n if (viewport >= range.max) return 'full';\n if (viewport >= range.min) return 'collapsed';\n return 'drawer';\n }\n return viewport >= RAIL_FULL_BREAKPOINT ? 'full' : 'drawer';\n}\n","/**\n * Width-discipline helper for `AppShell` (Move 1c). Split out from the component\n * so the (viewport → max-width) rule is a small, directly unit-testable pure\n * function, with a thin hook wrapper that feeds it the live viewport width.\n */\nimport { useWindowDimensions } from 'react-native';\n\n/** Content-width policy: a capped column, optionally wider past a viewport breakpoint, or full-bleed. */\nexport type AppShellWidth =\n | { max: number; wideMax?: number; wideMinViewport?: number }\n | 'full';\n\n/**\n * Resolve the content column's max width for a given viewport. `'full'` passes\n * through (no cap); an object caps at `max`, widening to `wideMax` once the\n * viewport reaches `wideMinViewport`.\n */\nexport function resolveContentMaxWidth(width: AppShellWidth, viewport: number): number | 'full' {\n if (width === 'full') return 'full';\n const wideMinViewport = width.wideMinViewport ?? Number.POSITIVE_INFINITY;\n const isWide = viewport >= wideMinViewport;\n return isWide ? (width.wideMax ?? width.max) : width.max;\n}\n\n/** Hook wrapper: resolves the content max width against the live window width. */\nexport function useContentMaxWidth(width: AppShellWidth): number | 'full' {\n const { width: viewport } = useWindowDimensions();\n return resolveContentMaxWidth(width, viewport);\n}\n","/**\r\n * AppShell — the shared dashboard-chrome composition (Move 1c). It hosts, top to\r\n * bottom: an app-supplied header (full-bleed), an optional per-app nav region, an\r\n * optional banner, and a width-disciplined scrollable content column. It also\r\n * folds in the two things every product page re-implements: an auth gate\r\n * (pending spinner / redirect-when-unauthenticated) and page state cards\r\n * (loading / error / forbidden).\r\n *\r\n * A BACK-OFFICE variant is supported via the optional `sidebar` slot (added for\r\n * Agora's merchant admin): supply a `<Sidebar>` and the body below the header /\r\n * nav / banner becomes a ROW — a persistent left rail beside the scrolling\r\n * content column — instead of the default single vertical stack. Omit `sidebar`\r\n * and the render tree is byte-identical to before, so every existing consumer\r\n * (erevna / katalogos / kefi) is untouched.\r\n *\r\n * Contract discipline (same as the rest of `@dloizides/ui-nav`): NO FM, router,\r\n * or store imports. The app passes wired elements, pre-localized strings, and\r\n * callbacks; every colour is routed through the `@dloizides/ui-feedback` theme.\r\n */\r\nimport React, { useCallback, useEffect, useState } from 'react';\r\n\r\nimport {\r\n ActivityIndicator,\r\n ScrollView,\r\n StyleSheet,\r\n useWindowDimensions,\r\n View,\r\n type ViewStyle,\r\n} from 'react-native';\r\n\r\nimport { useUi } from '@dloizides/ui-feedback';\r\n\r\nimport { useContentBody, type ShellState } from './appShellContent';\r\nimport { APP_SHELL_SUFFIX } from './constants';\r\nimport {\r\n DEFAULT_DRAWER_LABELS,\r\n MenuToggle,\r\n MobileDrawer,\r\n type DrawerLabels,\r\n} from './MobileDrawer';\r\nimport {\r\n DEFAULT_COLLAPSED_RAIL_MAX,\r\n RAIL_FULL_BREAKPOINT,\r\n resolveRailMode,\r\n type CollapsedRailRange,\r\n} from './railMode';\r\nimport { useContentMaxWidth, type AppShellWidth } from './useContentMaxWidth';\r\nimport { renderTextSlot } from './textSlot';\r\n\r\nconst DEFAULT_CONTENT_PADDING = 24;\r\n\r\nconst styles = StyleSheet.create({\r\n root: { flex: 1 },\r\n centerFill: { flex: 1, justifyContent: 'center', alignItems: 'center' },\r\n scroll: { flex: 1 },\r\n scrollContent: { flexGrow: 1 },\r\n // Mobile back-office header: the hamburger sits inline before the header slot.\r\n headerRow: { flexDirection: 'row', alignItems: 'center' },\r\n headerFill: { flex: 1 },\r\n // Back-office layout: a persistent left rail beside the scrolling content column.\r\n bodyRow: { flex: 1, flexDirection: 'row' },\r\n columnFull: { flex: 1 },\r\n columnCapped: { flex: 1, width: '100%', alignSelf: 'center' },\r\n // Non-flex variant used to cap the nav strip's inner content to the content\r\n // column so the nav aligns with the page content instead of running full-bleed.\r\n chromeCapped: { width: '100%', alignSelf: 'center' },\r\n});\r\n\r\nexport type { ShellMessage } from './appShellContent';\r\n\r\nexport interface AppShellProps {\r\n /** App-supplied wired header (Topbar / AppHeader), rendered full-bleed. */\r\n header: React.ReactNode;\r\n /** Per-app nav region (kefi coral pills / erevna sidebar+drawer). */\r\n nav?: React.ReactNode;\r\n /**\r\n * Optional persistent LEFT RAIL (a `<Sidebar>`), for back-office surfaces. When\r\n * supplied, the region below header/nav/banner lays out as a row: the rail on the\r\n * left, the scrolling content column on the right. Omit for the default vertical\r\n * stack — the tree is then byte-identical to the pre-`sidebar` AppShell.\r\n *\r\n * Responsive: at/under ~768px the persistent rail is REPLACED by a hamburger (in\r\n * the header) that opens the same `sidebar` as an overlay drawer, so the content\r\n * takes the full width. Desktop (≥768px) is unchanged. No effect without `sidebar`.\r\n */\r\n sidebar?: React.ReactNode;\r\n /**\r\n * Optional intermediate COLLAPSED (icon-only) rail — opts the `sidebar` layout\r\n * into a THREE-tier responsive scheme (erevna / katalogos): the full `sidebar`\r\n * on desktop, this collapsed rail on a tablet-width band, and the overlay drawer\r\n * (hosting the full `sidebar`) on a phone. Omit it and the layout stays the\r\n * unchanged two-tier scheme (full rail ≥768px, drawer below). No effect without\r\n * `sidebar`. Exposed as `${testID}${APP_SHELL_SUFFIX.collapsedSidebar}`.\r\n */\r\n collapsedSidebar?: React.ReactNode;\r\n /**\r\n * The viewport band `[min, max)` in which `collapsedSidebar` shows: at/above\r\n * `max` the full rail shows, below `min` the drawer shows. Defaults to\r\n * `{ min: 768, max: 1024 }`. Only consulted when `collapsedSidebar` is supplied.\r\n */\r\n collapsedRailRange?: CollapsedRailRange;\r\n /**\r\n * Pre-localized labels for the mobile nav drawer (only used in the `sidebar`\r\n * layout, below the breakpoint): the hamburger's open label/hint and the scrim's\r\n * close label/hint. Optional — English defaults apply. NO i18n in this package.\r\n */\r\n mobileMenu?: Partial<DrawerLabels>;\r\n /** Banner slot (e.g. verification-pending). */\r\n banner?: React.ReactNode;\r\n /** Content-width policy. Defaults to full-bleed. */\r\n width?: AppShellWidth;\r\n /** Content padding inside the scroll column. Defaults to 24. */\r\n contentPadding?: number;\r\n /**\r\n * Whether the nav strip aligns with the width-capped content column\r\n * (`'content'`) or runs full-bleed (`'full'`, the default). Only has an effect\r\n * when `width` caps the content. The header always renders full-bleed.\r\n */\r\n chromeAlignment?: 'full' | 'content';\r\n /** Auth gate — spinner while pending, `onRedirect` when unauthenticated. */\r\n gate?: { pending: boolean; authenticated: boolean; onRedirect: () => void };\r\n /** Page state — loading spinner card, or a titled error / forbidden card. */\r\n state?: ShellState;\r\n /** Root testID; the content region is exposed as `${testID}-content`. */\r\n testID: string;\r\n children: React.ReactNode;\r\n}\r\n\r\nexport const AppShell = ({\r\n header,\r\n nav,\r\n sidebar,\r\n collapsedSidebar,\r\n collapsedRailRange,\r\n mobileMenu,\r\n banner,\r\n width = 'full',\r\n contentPadding = DEFAULT_CONTENT_PADDING,\r\n chromeAlignment = 'full',\r\n gate,\r\n state,\r\n testID,\r\n children,\r\n}: AppShellProps): React.ReactElement | null => {\r\n const { theme } = useUi();\r\n const primary = theme.palette.primary['500'];\r\n const maxWidth = useContentMaxWidth(width);\r\n const body = useContentBody(state, children, testID);\r\n\r\n // Back-office responsive behaviour: the rail takes one of three faces by\r\n // viewport — the persistent full rail, an optional intermediate collapsed\r\n // (icon-only) rail, or an overlay drawer. Without `collapsedSidebar` this stays\r\n // the unchanged two-tier scheme (full rail ≥768px, drawer below).\r\n const { width: viewportWidth } = useWindowDimensions();\r\n const railRange: CollapsedRailRange = collapsedRailRange ?? { min: RAIL_FULL_BREAKPOINT, max: DEFAULT_COLLAPSED_RAIL_MAX };\r\n const railMode = resolveRailMode({\r\n viewport: viewportWidth,\r\n hasSidebar: sidebar !== undefined,\r\n hasCollapsed: collapsedSidebar !== undefined,\r\n range: railRange,\r\n });\r\n const useDrawer = railMode === 'drawer';\r\n const [drawerOpen, setDrawerOpen] = useState(false);\r\n const openDrawer = useCallback(() => setDrawerOpen(true), []);\r\n const closeDrawer = useCallback(() => setDrawerOpen(false), []);\r\n useEffect(() => {\r\n if (!useDrawer && drawerOpen) setDrawerOpen(false);\r\n }, [useDrawer, drawerOpen]);\r\n const drawerLabels: DrawerLabels = { ...DEFAULT_DRAWER_LABELS, ...mobileMenu };\r\n\r\n const isUnauthenticated = gate !== undefined && !gate.pending && !gate.authenticated;\r\n useEffect(() => {\r\n if (isUnauthenticated && gate !== undefined) gate.onRedirect();\r\n }, [isUnauthenticated, gate]);\r\n\r\n if (gate?.pending === true)\r\n return (\r\n <View style={[styles.root, styles.centerFill, { backgroundColor: theme.colors.background }]} testID={`${testID}${APP_SHELL_SUFFIX.pending}`}>\r\n <ActivityIndicator color={primary} size=\"large\" />\r\n </View>\r\n );\r\n\r\n if (isUnauthenticated) return null;\r\n\r\n const columnStyle: ViewStyle | ViewStyle[] =\r\n maxWidth === 'full' ? styles.columnFull : [styles.columnCapped, { maxWidth }];\r\n\r\n // Align the nav strip's inner content with the capped content column when asked\r\n // (and only when the content is actually capped); otherwise it runs full-bleed.\r\n const navInnerStyle: ViewStyle | ViewStyle[] | undefined =\r\n chromeAlignment === 'content' && maxWidth !== 'full'\r\n ? [styles.chromeCapped, { maxWidth, paddingHorizontal: contentPadding }]\r\n : undefined;\r\n\r\n const scroller = (\r\n <ScrollView\r\n contentContainerStyle={[styles.scrollContent, { padding: contentPadding }]}\r\n style={styles.scroll}\r\n testID={`${testID}${APP_SHELL_SUFFIX.content}`}\r\n >\r\n <View style={columnStyle}>{body}</View>\r\n </ScrollView>\r\n );\r\n\r\n // Header region: below the breakpoint (with a sidebar) the hamburger sits inline\r\n // before the header slot; otherwise the header wrapper is unchanged.\r\n const headerRegion = useDrawer ? (\r\n <View style={styles.headerRow} testID={`${testID}${APP_SHELL_SUFFIX.header}`}>\r\n <MenuToggle\r\n hint={drawerLabels.openHint}\r\n label={drawerLabels.openLabel}\r\n testID={`${testID}${APP_SHELL_SUFFIX.menuToggle}`}\r\n onOpen={openDrawer}\r\n />\r\n <View style={styles.headerFill}>{renderTextSlot(header, { color: theme.colors.text })}</View>\r\n </View>\r\n ) : (\r\n <View testID={`${testID}${APP_SHELL_SUFFIX.header}`}>\r\n {renderTextSlot(header, { color: theme.colors.text })}\r\n </View>\r\n );\r\n\r\n // Body: the persistent rail (full or collapsed) sits beside the content in a\r\n // row; in drawer mode the content takes the full width and the rail moves into\r\n // the overlay drawer.\r\n const railRegion =\r\n railMode === 'full' ? (\r\n <View testID={`${testID}${APP_SHELL_SUFFIX.sidebar}`}>\r\n {renderTextSlot(sidebar, { color: theme.colors.text })}\r\n </View>\r\n ) : railMode === 'collapsed' ? (\r\n <View testID={`${testID}${APP_SHELL_SUFFIX.collapsedSidebar}`}>\r\n {renderTextSlot(collapsedSidebar, { color: theme.colors.text })}\r\n </View>\r\n ) : null;\r\n\r\n return (\r\n <View style={[styles.root, { backgroundColor: theme.colors.background }]} testID={testID}>\r\n {headerRegion}\r\n {nav !== undefined ? (\r\n <View testID={`${testID}${APP_SHELL_SUFFIX.nav}`}>\r\n {navInnerStyle !== undefined ? (\r\n <View style={navInnerStyle}>{renderTextSlot(nav, { color: theme.colors.text })}</View>\r\n ) : (\r\n renderTextSlot(nav, { color: theme.colors.text })\r\n )}\r\n </View>\r\n ) : null}\r\n {banner !== undefined ? (\r\n <View testID={`${testID}${APP_SHELL_SUFFIX.banner}`}>\r\n {renderTextSlot(banner, { color: theme.colors.text })}\r\n </View>\r\n ) : null}\r\n {railRegion !== null ? (\r\n <View style={styles.bodyRow}>\r\n {railRegion}\r\n {scroller}\r\n </View>\r\n ) : (\r\n scroller\r\n )}\r\n {useDrawer && drawerOpen ? (\r\n <MobileDrawer\r\n drawerTestID={`${testID}${APP_SHELL_SUFFIX.drawer}`}\r\n labels={drawerLabels}\r\n scrimTestID={`${testID}${APP_SHELL_SUFFIX.scrim}`}\r\n sidebar={sidebar}\r\n onClose={closeDrawer}\r\n />\r\n ) : null}\r\n </View>\r\n );\r\n};\r\n\r\nexport default AppShell;\r\n","/**\r\n * CollapsedRail — the icon-only vertical rail for the intermediate (tablet) tier\r\n * of `AppShell`'s three-tier responsive layout (the erevna / katalogos collapsed\r\n * rail). It renders the SAME caller-supplied `NavItem[]` as `Sidebar`, but as a\r\n * narrow strip of icon buttons: each item shows its `renderIcon` (or a first-letter\r\n * glyph fallback), labelled for assistive tech, with the active route highlighted.\r\n * Optional `header` / `footer` slots carry app chrome (a home shortcut, a\r\n * dark-mode toggle, logout) top and bottom.\r\n *\r\n * A collapsed rail cannot expand a section inline, so pressing ANY item — leaf or\r\n * parent — navigates to its `route`; an app that wants a parent to open the full\r\n * drawer instead can special-case that in its `onNavigate`.\r\n *\r\n * Contract discipline (same as the rest of `@dloizides/ui-nav`): NO FM, router,\r\n * icon-set, or store imports. Labels are pre-localized strings, icons are render\r\n * slots, and every colour is read from the `@dloizides/ui-feedback` theme.\r\n */\r\nimport React from 'react';\r\n\r\nimport { Text, View, type ViewStyle } from 'react-native';\r\n\r\nimport { useUi } from '@dloizides/ui-feedback';\r\n\r\nimport { FocusableTouchable } from './FocusableTouchable';\r\nimport { isRouteActive } from './isRouteActive';\r\nimport { collapsedRailStyles as styles } from './styles';\r\nimport type { NavItem } from './types';\r\nimport { renderTextSlot } from './textSlot';\r\n\r\n/** Icon size for a collapsed-rail item. */\r\nconst COLLAPSED_ICON_SIZE = 22;\r\n\r\nexport interface CollapsedRailProps {\r\n /** Nav entries — the same role-filtered `NavItem[]` the full `Sidebar` renders. */\r\n items: NavItem[];\r\n /** Current active route/path. */\r\n pathname: string;\r\n /** Navigation callback — receives a `NavItem.route`. */\r\n onNavigate: (route: string) => void;\r\n /** Localized accessibility label for the navigation landmark. */\r\n regionLabel: string;\r\n /** a11y hint for an item, given its label. Defaults to the label. */\r\n navigateHint?: (label: string) => string;\r\n /** Optional header slot rendered above the items (e.g. a home shortcut). */\r\n header?: React.ReactNode;\r\n /** Optional footer slot rendered after a flex spacer (dark-mode toggle, logout). */\r\n footer?: React.ReactNode;\r\n /** Extra container style overrides. */\r\n containerStyle?: ViewStyle | ViewStyle[];\r\n}\r\n\r\n/** First character of a label, uppercased — the icon fallback glyph. */\r\nfunction glyphFor(label: string): string {\r\n return label.trim().charAt(0).toUpperCase();\r\n}\r\n\r\nexport const CollapsedRail = ({\r\n items,\r\n pathname,\r\n onNavigate,\r\n regionLabel,\r\n navigateHint = (label) => label,\r\n header,\r\n footer,\r\n containerStyle,\r\n}: CollapsedRailProps): React.ReactElement => {\r\n const { theme } = useUi();\r\n const colors = theme.colors;\r\n const primaryColor = theme.palette.primary['500'];\r\n\r\n return (\r\n <View\r\n accessibilityRole=\"none\"\r\n aria-label={regionLabel}\r\n role=\"navigation\"\r\n style={[\r\n styles.container,\r\n { backgroundColor: colors.surface, borderRightColor: colors.border },\r\n containerStyle,\r\n ]}\r\n >\r\n {header !== undefined ? (\r\n <View style={styles.slot}>{renderTextSlot(header, { color: colors.text })}</View>\r\n ) : null}\r\n\r\n {items.map((item) => {\r\n const active = isRouteActive(pathname, item.route);\r\n const iconColor = active ? primaryColor : colors.textSecondary;\r\n return (\r\n <FocusableTouchable\r\n key={item.key}\r\n accessibilityHint={navigateHint(item.label)}\r\n accessibilityLabel={item.label}\r\n ringColor={primaryColor}\r\n style={[styles.item, active ? { backgroundColor: colors.border } : undefined]}\r\n testID={item.testID ?? item.key}\r\n onPress={() => onNavigate(item.route)}\r\n >\r\n {typeof item.renderIcon === 'function' ? (\r\n item.renderIcon(iconColor, COLLAPSED_ICON_SIZE)\r\n ) : (\r\n <Text style={[styles.glyph, { color: iconColor }]}>{glyphFor(item.label)}</Text>\r\n )}\r\n </FocusableTouchable>\r\n );\r\n })}\r\n\r\n <View style={styles.spacer} />\r\n\r\n {footer !== undefined ? (\r\n <View style={styles.slot}>{renderTextSlot(footer, { color: colors.text })}</View>\r\n ) : null}\r\n </View>\r\n );\r\n};\r\n\r\nexport default CollapsedRail;\r\n","/**\n * NavShell — the ONE first-class navigation shell that renders a **top bar**, a\n * **side rail**, or **BOTH together**, chosen by a single `layout` prop\n * (`'top' | 'side' | 'both'`). It is the shell-level answer to `Nav`'s\n * single-axis question: where `Nav` returns one element (a `NavBar` OR a\n * `Sidebar`), `NavShell` owns the whole page composition — it wires a top bar\n * into `AppShell`'s `header` slot and a side rail into `AppShell`'s `sidebar`\n * slot, and inherits every `AppShell` capability (auth gate, loading / error /\n * forbidden state cards, width discipline, banner, the responsive\n * hamburger + overlay drawer for the rail).\n *\n * layout=\"top\" → a horizontal top bar only (brand + links + overflow \"…\" + right).\n * layout=\"side\" → a header + a persistent left rail of sections (the erevna / katalogos shape).\n * layout=\"both\" → a top bar (brand / global links + overflow \"…\" / user) AND a side rail\n * (sections), together — the AML-console shape, now first-class.\n *\n * \"both\" is inherently a shell composition (a top region + a side region + a\n * content column), which a single-element `Nav` cannot own; `NavShell` is that\n * composition, so no app hand-wires `Topbar` + `Sidebar` + a `ScrollView` row\n * again. Customizability is STYLE-only: every colour flows through the\n * `@dloizides/ui-feedback` UiProvider theme, and brand / user / language /\n * notification / section content are render slots. Structure + behaviour are\n * shared.\n *\n * Contract discipline (same as the rest of `@dloizides/ui-nav`): NO FM, router,\n * icon-set, or store imports. Labels are pre-localized strings, icons are render\n * slots, and every colour is read from the theme.\n */\nimport React from 'react';\n\nimport type { ViewStyle } from 'react-native';\n\nimport type { UiTheme } from '@dloizides/ui-feedback';\n\nimport { AppShell, type AppShellProps } from './AppShell';\nimport { CollapsedRail } from './CollapsedRail';\nimport { NavBar } from './NavBar';\nimport type { CollapsedRailRange } from './railMode';\nimport { Sidebar } from './Sidebar';\nimport type { NavItem } from './types';\n\n/** Which regions the shell renders: a top bar, a side rail, or both together. */\nexport type NavShellLayout = 'top' | 'side' | 'both';\n\n/**\n * Config for the TOP bar (rendered as a `NavBar` in `AppShell`'s header slot).\n * Used when `layout` is `'top'` or `'both'`. Every field is optional except the\n * items — an empty `items` array renders a bar with just the brand + right slots\n * (a plain top bar with no nav links), which is the natural `'side'`-mode header.\n */\nexport interface NavShellTopBar {\n /** Top-bar nav entries (global links). Empty ⇒ brand + right only. */\n items: NavItem[];\n /** Left slot — typically the tenant brand / logo. */\n brand?: React.ReactNode;\n /** Right slot — free-form (language toggle, notification bell, user chip, logout). */\n right?: React.ReactNode;\n /** Collapse the links behind a hamburger below this viewport width (default 760). */\n collapseBelow?: number;\n /** Localized visible + accessible label for the \"More ▾\" overflow trigger (default \"More\"). */\n overflowLabel?: string;\n /** Localized accessibility hint for the overflow trigger. */\n overflowHint?: string;\n /** Localized accessibility label for the responsive menu toggle. */\n menuLabel?: string;\n /** Localized accessibility hint for the responsive menu toggle. */\n menuHint?: string;\n /** Optional custom glyph renderer for the responsive toggle; defaults to ☰. */\n renderMenuIcon?: (color: string, open: boolean) => React.ReactNode;\n /**\n * Extra container style overrides (e.g. an app-specific appbar background —\n * including a web `background`/`backgroundImage` gradient cast through\n * `ViewStyle`, the AML radial-glow appbar). Style-only.\n */\n containerStyle?: ViewStyle | ViewStyle[];\n /**\n * Optional content-column cap (px) for the top bar. When set, the bar's\n * background + bottom border (from `containerStyle` / `barTheme`) stay FULL WIDTH\n * (full-bleed) while the inner brand + links + right row is capped to this width\n * and centred — the AML v1-console appbar shape. Forwarded to `NavBar.contentMaxWidth`.\n */\n contentMaxWidth?: number;\n /**\n * Optional CHROME theme override for the top bar only (dark bar over a light\n * page). Forwarded to `NavBar.barTheme`. Style-only — see `NavBar`.\n */\n barTheme?: UiTheme;\n}\n\n/**\n * Config for the intermediate COLLAPSED (icon-only) rail — opts the side layout\n * into a THREE-tier responsive scheme (full rail → collapsed rail → drawer). When\n * present, NavShell builds a `<CollapsedRail>` and hands it to `AppShell` for the\n * tablet band; omit it and the layout stays two-tier.\n */\nexport interface NavShellCollapsedRail {\n /** Items for the icon rail. Defaults to the full rail's `items`. */\n items?: NavItem[];\n /** Optional header slot (e.g. a home shortcut). */\n header?: React.ReactNode;\n /** Optional footer slot (dark-mode toggle, logout). */\n footer?: React.ReactNode;\n /** The `[min, max)` viewport band for the collapsed rail (default `{ min: 768, max: 1024 }`). */\n range?: CollapsedRailRange;\n}\n\n/**\n * Config for the SIDE rail (rendered as a `Sidebar` in `AppShell`'s sidebar\n * slot). Used when `layout` is `'side'` or `'both'`.\n */\nexport interface NavShellSideRail {\n /** Side-rail nav entries (sections — leaf + expandable). */\n items: NavItem[];\n /** Localized menu title (heading). */\n title: string;\n /** Optional header slot rendered above the items (e.g. a Home shortcut). */\n header?: React.ReactNode;\n /** Optional footer slot rendered after a flex spacer (dark-mode toggle, logout). */\n footer?: React.ReactNode;\n /** a11y hint shown when an expandable section is collapsed. */\n expandHint?: string;\n /** a11y hint shown when an expandable section is expanded. */\n collapseHint?: string;\n /** Optional chevron renderer for expandable sections. */\n renderChevron?: (expanded: boolean, color: string, size: number) => React.ReactNode;\n /** Extra container style overrides. */\n containerStyle?: ViewStyle | ViewStyle[];\n /** Optional collapsed (icon-only) rail config → the intermediate tablet tier. */\n collapsed?: NavShellCollapsedRail;\n}\n\n/**\n * `AppShell` props NavShell forwards straight through. It composes the `header`\n * and `sidebar` (+ `collapsedSidebar`) regions itself, so those are handled here;\n * everything else — including the optional `nav` strip (e.g. a `PillNav`), the\n * auth gate, state cards, banner, and width policy — passes through untouched.\n */\ntype ForwardedShellProps = Omit<AppShellProps, 'header' | 'sidebar' | 'children'>;\n\nexport interface NavShellProps extends ForwardedShellProps {\n /** Which regions to render: a top bar, a side rail, or both. */\n layout: NavShellLayout;\n /** Current active route/path — drives active highlighting on both regions. */\n pathname: string;\n /** Navigation callback — receives a `NavItem.route`. */\n onNavigate: (route: string) => void;\n /** Localized accessibility label for the navigation landmark(s). */\n regionLabel: string;\n /** a11y hint for a nav item, given its label. Defaults to the label. */\n navigateHint?: (label: string) => string;\n /**\n * Top-bar config → a `NavBar` in the header slot. Required for `'top'` /\n * `'both'`; **ignored for `'side'`** — `layout` decides which regions exist, so\n * a `'side'` app that also wants a bar asks for `layout=\"both\"`. A `'side'` app\n * that wants its OWN header node uses the `header` escape hatch instead.\n */\n topBar?: NavShellTopBar;\n /**\n * Escape hatch: a ready-made header node (e.g. an app-composed `<Topbar>`).\n * When supplied it REPLACES the `topBar`-built `NavBar` — used by `'side'`\n * apps that want the structured `Topbar` (language / notification / user\n * slots) instead of a `NavBar` header.\n */\n header?: React.ReactNode;\n /**\n * Side-rail config → a `Sidebar` in the sidebar slot. Required for `'side'` /\n * `'both'`; ignored for `'top'`.\n */\n sideRail?: NavShellSideRail;\n children: React.ReactNode;\n}\n\n/**\n * Should the top bar render? Yes for `'top'`/`'both'`, or when an explicit\n * `header` NODE is supplied.\n *\n * `layout` is the AUTHORITY over which regions exist: a `topBar` **config** is\n * the content of the top region, never the decision to have one, so passing a\n * `topBar` with `layout=\"side\"` renders NO top bar (use `'both'` — that is what\n * a rail plus a bar means). Before 1.10.0 an extra `layout === 'side' && hasTopBar`\n * clause made `'side'` + a `topBar` render identically to `'both'`, so `layout`\n * stopped being observable.\n *\n * `hasHeader` is a DIFFERENT concern and is deliberately kept: `header` is the\n * documented escape hatch by which a `'side'` app supplies its own ready-made\n * header node (the structured `Topbar` with language / notification / user slots)\n * instead of a `NavBar`. It is an explicit \"render THIS node in the header slot\",\n * not a config whose mere presence is read as an orientation change — and four\n * portals (erevna, katalogos, zygos, agora) depend on it.\n */\nfunction wantsTopBar(layout: NavShellLayout, hasHeader: boolean): boolean {\n return layout === 'top' || layout === 'both' || hasHeader;\n}\n\n/** Should the side rail render? Yes for `'side'`/`'both'` (when a rail is configured). */\nfunction wantsSideRail(layout: NavShellLayout, hasSideRail: boolean): boolean {\n return (layout === 'side' || layout === 'both') && hasSideRail;\n}\n\nexport const NavShell = ({\n layout,\n pathname,\n onNavigate,\n regionLabel,\n navigateHint,\n topBar,\n header,\n sideRail,\n children,\n collapsedSidebar: collapsedSidebarProp,\n collapsedRailRange: collapsedRailRangeProp,\n ...shellProps\n}: NavShellProps): React.ReactElement | null => {\n const showTopBar = wantsTopBar(layout, header !== undefined);\n const showSideRail = wantsSideRail(layout, sideRail !== undefined);\n\n // Header region: an app-supplied node wins; otherwise build a NavBar from topBar.\n const headerNode: React.ReactNode =\n header !== undefined\n ? header\n : showTopBar && topBar !== undefined\n ? (\n <NavBar\n barTheme={topBar.barTheme}\n brand={topBar.brand}\n collapseBelow={topBar.collapseBelow}\n containerStyle={topBar.containerStyle}\n contentMaxWidth={topBar.contentMaxWidth}\n items={topBar.items}\n menuHint={topBar.menuHint}\n menuLabel={topBar.menuLabel}\n navigateHint={navigateHint}\n overflowHint={topBar.overflowHint}\n overflowLabel={topBar.overflowLabel}\n pathname={pathname}\n regionLabel={regionLabel}\n renderMenuIcon={topBar.renderMenuIcon}\n right={topBar.right}\n onNavigate={onNavigate}\n />\n )\n : null;\n\n // Side-rail region: a Sidebar built from sideRail config.\n const sidebarNode: React.ReactNode =\n showSideRail && sideRail !== undefined ? (\n <Sidebar\n collapseHint={sideRail.collapseHint}\n containerStyle={sideRail.containerStyle}\n expandHint={sideRail.expandHint}\n footer={sideRail.footer}\n header={sideRail.header}\n items={sideRail.items}\n navigateHint={navigateHint}\n pathname={pathname}\n regionLabel={regionLabel}\n renderChevron={sideRail.renderChevron}\n title={sideRail.title}\n onNavigate={onNavigate}\n />\n ) : undefined;\n\n // Collapsed (tablet) rail: build a CollapsedRail from `sideRail.collapsed`\n // config when present (config-driven, not hand-wired); otherwise fall back to a\n // raw `collapsedSidebar` node the caller may have passed straight through.\n const collapsedCfg = showSideRail ? sideRail?.collapsed : undefined;\n const collapsedNode: React.ReactNode =\n collapsedCfg !== undefined && sideRail !== undefined ? (\n <CollapsedRail\n footer={collapsedCfg.footer}\n header={collapsedCfg.header}\n items={collapsedCfg.items ?? sideRail.items}\n navigateHint={navigateHint}\n pathname={pathname}\n regionLabel={regionLabel}\n onNavigate={onNavigate}\n />\n ) : (\n collapsedSidebarProp\n );\n const collapsedRange = collapsedCfg?.range ?? collapsedRailRangeProp;\n\n return (\n <AppShell\n {...shellProps}\n collapsedRailRange={collapsedRange}\n collapsedSidebar={collapsedNode}\n header={headerNode}\n sidebar={sidebarNode}\n >\n {children}\n </AppShell>\n );\n};\n\nexport default NavShell;\n","/**\n * PillNav — a horizontal row of fully-rounded \"pills\", the cross-navigation\n * switcher promoted from kefi's coral dashboard nav. It renders the same\n * caller-supplied `NavItem[]` as the other nav components, as pills that wrap,\n * with the active route wearing the accent pill.\n *\n * It also folds in kefi's **visibility rule**: the whole nav hides (renders\n * `null`) unless there are at least `minItems` entries — a single destination is\n * not worth a switcher. Default `minItems` is 1 (always show when there is at\n * least one item); kefi passes `2`.\n *\n * \"Coral pills\" is STYLE, not structure: the accent colour is the theme\n * `palette.primary` (kefi's coral), the resting pill is `surfaceElevated`, and\n * `containerStyle` / theme tokens carry any per-app tweak — no layout fork.\n *\n * Contract discipline (same as the rest of `@dloizides/ui-nav`): NO FM, router,\n * icon-set, or store imports. Labels are pre-localized strings, icons are render\n * slots, and every colour is read from the `@dloizides/ui-feedback` theme.\n */\nimport React from 'react';\n\nimport { Text, View, type ViewStyle } from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\n\nimport { FocusableTouchable } from './FocusableTouchable';\nimport { isRouteActive } from './isRouteActive';\nimport { NAV_ICON_SIZE, pillNavStyles as styles } from './styles';\nimport type { NavItem } from './types';\n\n/** Ink for a pill sitting on the accent (active) background — full-contrast white. */\nconst TEXT_ON_PRIMARY = '#ffffff';\n/** Default minimum item count to show the switcher (kefi passes 2). */\nconst DEFAULT_MIN_ITEMS = 1;\n\nexport interface PillNavProps {\n /** Nav entries — the cross-navigation destinations. */\n items: NavItem[];\n /** Current active route/path. */\n pathname: string;\n /** Navigation callback — receives a `NavItem.route`. */\n onNavigate: (route: string) => void;\n /** Localized accessibility label for the navigation landmark. */\n regionLabel: string;\n /** a11y hint for a pill, given its label. Defaults to the label. */\n navigateHint?: (label: string) => string;\n /**\n * Hide the whole switcher unless there are at least this many items. Default 1\n * (show when non-empty); kefi passes 2 (a lone dashboard needs no switcher).\n */\n minItems?: number;\n /** Extra container style overrides. */\n containerStyle?: ViewStyle | ViewStyle[];\n}\n\nexport const PillNav = ({\n items,\n pathname,\n onNavigate,\n regionLabel,\n navigateHint = (label) => label,\n minItems = DEFAULT_MIN_ITEMS,\n containerStyle,\n}: PillNavProps): React.ReactElement | null => {\n const { theme } = useUi();\n const colors = theme.colors;\n const primaryColor = theme.palette.primary['500'];\n\n if (items.length < minItems) return null;\n\n return (\n <View\n accessibilityRole=\"none\"\n aria-label={regionLabel}\n role=\"navigation\"\n style={[styles.container, containerStyle]}\n >\n {items.map((item) => {\n const active = isRouteActive(pathname, item.route);\n const textColor = active ? TEXT_ON_PRIMARY : colors.textSecondary;\n const pillStyle: ViewStyle = active\n ? { backgroundColor: primaryColor }\n : { backgroundColor: colors.surfaceElevated };\n return (\n <FocusableTouchable\n key={item.key}\n accessibilityHint={navigateHint(item.label)}\n accessibilityLabel={item.label}\n accessibilityRole=\"link\"\n ringColor={primaryColor}\n style={[styles.pill, pillStyle]}\n testID={item.testID ?? item.key}\n onPress={() => onNavigate(item.route)}\n >\n {typeof item.renderIcon === 'function' ? item.renderIcon(textColor, NAV_ICON_SIZE) : null}\n <Text style={[styles.pillText, { color: textColor }]}>{item.label}</Text>\n </FocusableTouchable>\n );\n })}\n </View>\n );\n};\n\nexport default PillNav;\n","/**\n * DarkModeControl — the shared colour-scheme control promoted from erevna /\n * katalogos (their Light / Dark / System toggle + the icon-only \"cycle\" button).\n * It is a CONTROLLED component: the app owns the current `value` and applies the\n * chosen scheme; this component only renders the choices and reports changes.\n *\n * Two variants encode the two behaviours the apps shipped:\n * - `\"segmented\"` (default): a row of segments (Light / Dark / System), the\n * active one highlighted — the desktop control.\n * - `\"cycle\"`: a single icon+label button that advances to the NEXT option on\n * each press (wrapping) — the compact mobile control.\n *\n * The options are pre-localized (`label` + `hint`) and value-agnostic (a string),\n * so the app maps its own `DarkModePreference` enum to strings without this\n * package importing it. Every colour flows through the `@dloizides/ui-feedback`\n * theme; STYLE is the only per-app variation.\n */\nimport React, { useCallback } from 'react';\n\nimport { Text, View, type ViewStyle } from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\n\nimport { FocusableTouchable } from './FocusableTouchable';\nimport { darkModeStyles as styles } from './styles';\n\n/** Ink for the active (accent-filled) segment / cycle button. */\nconst TEXT_ON_PRIMARY = '#ffffff';\n/** Icon size for a dark-mode option. */\nconst DARK_MODE_ICON_SIZE = 16;\n\n/** Which control shape to render. */\nexport type DarkModeVariant = 'segmented' | 'cycle';\n\n/** One pre-localized colour-scheme choice (e.g. Light / Dark / System). */\nexport interface DarkModeOption {\n /** App-defined value (its own preference enum mapped to a string). */\n value: string;\n /** Localized visible + accessible label. */\n label: string;\n /** Localized accessibility hint. */\n hint: string;\n /** Optional leading icon. Receives the resolved colour + size. */\n renderIcon?: (color: string, size: number) => React.ReactNode;\n}\n\nexport interface DarkModeControlProps {\n /** Current selected value — must match one of `options[].value`. */\n value: string;\n /** The pre-localized choices (typically Light / Dark / System). */\n options: DarkModeOption[];\n /** Change callback — receives the newly-selected value. */\n onChange: (value: string) => void;\n /** Localized accessibility label for the control group. */\n regionLabel: string;\n /** Control shape — a segmented row (default) or a single cycling button. */\n variant?: DarkModeVariant;\n /** testID for the control; segments are `${testID}-${value}`. */\n testID?: string;\n /** Extra container style overrides. */\n containerStyle?: ViewStyle | ViewStyle[];\n}\n\nexport const DarkModeControl = ({\n value,\n options,\n onChange,\n regionLabel,\n variant = 'segmented',\n testID,\n containerStyle,\n}: DarkModeControlProps): React.ReactElement | null => {\n const { theme } = useUi();\n const colors = theme.colors;\n const primaryColor = theme.palette.primary['500'];\n\n const currentIndex = options.findIndex((option) => option.value === value);\n const current = currentIndex >= 0 ? options[currentIndex] : options[0];\n\n const advance = useCallback(() => {\n if (options.length === 0) return;\n const from = currentIndex >= 0 ? currentIndex : 0;\n const next = options[(from + 1) % options.length];\n if (next !== undefined) onChange(next.value);\n }, [options, currentIndex, onChange]);\n\n if (options.length === 0 || current === undefined) return null;\n\n if (variant === 'cycle') {\n const iconColor = colors.text;\n return (\n <View aria-label={regionLabel} style={containerStyle}>\n <FocusableTouchable\n accessibilityHint={current.hint}\n accessibilityLabel={current.label}\n ringColor={primaryColor}\n style={[styles.cycle, { backgroundColor: colors.surfaceElevated }]}\n testID={testID}\n onPress={advance}\n >\n {typeof current.renderIcon === 'function' ? current.renderIcon(iconColor, DARK_MODE_ICON_SIZE) : null}\n <Text style={[styles.cycleText, { color: colors.text }]}>{current.label}</Text>\n </FocusableTouchable>\n </View>\n );\n }\n\n return (\n <View\n aria-label={regionLabel}\n role=\"group\"\n style={[styles.segmentRow, { borderColor: colors.border }, containerStyle]}\n >\n {options.map((option) => {\n const active = option.value === value;\n const textColor = active ? TEXT_ON_PRIMARY : colors.textSecondary;\n return (\n <FocusableTouchable\n key={option.value}\n accessibilityHint={option.hint}\n accessibilityLabel={option.label}\n ringColor={primaryColor}\n style={[styles.segment, active ? { backgroundColor: primaryColor } : undefined]}\n testID={testID !== undefined ? `${testID}-${option.value}` : undefined}\n onPress={() => onChange(option.value)}\n >\n {typeof option.renderIcon === 'function' ? option.renderIcon(textColor, DARK_MODE_ICON_SIZE) : null}\n <Text style={[styles.segmentText, { color: textColor }]}>{option.label}</Text>\n </FocusableTouchable>\n );\n })}\n </View>\n );\n};\n\nexport default DarkModeControl;\n","/**\n * Pure matching logic for the {@link CommandPalette}. Kept framework-free so the\n * ranking/filtering is unit-testable without rendering: a command matches when\n * every whitespace-separated token of the query appears (case-insensitively) in\n * its haystack (label + hint + keywords). Requiring ALL tokens lets an operator\n * narrow with \"pay dash\" the way a fuzzy launcher would, without a fuzzy lib.\n */\nimport type React from 'react';\n\n/** One actionable destination/command shown in the palette. */\nexport interface CommandItem {\n /** Stable key + default testID. */\n key: string;\n /** Optional testID override (defaults to `key`). */\n testID?: string;\n /** Localized display label (what the operator reads). */\n label: string;\n /** Optional localized secondary line (e.g. the module it lives in). */\n hint?: string;\n /** Optional extra search terms not shown but matched (synonyms, route words). */\n keywords?: readonly string[];\n /** Invoked when the item is chosen (the consumer navigates / runs the action). */\n onSelect: () => void;\n /** Optional leading icon slot, same contract as `NavItem.renderIcon`. */\n renderIcon?: (color: string, size: number) => React.ReactNode;\n}\n\n/** The searchable text for one command, lower-cased once. */\nfunction haystack(item: CommandItem): string {\n return [item.label, item.hint ?? '', ...(item.keywords ?? [])].join(' ').toLowerCase();\n}\n\n/**\n * Filter `items` to those matching `query`. An empty/whitespace query returns\n * the list unchanged (the palette opens showing everything). Order is preserved\n * — the caller supplies items in a meaningful order (nav order).\n */\nexport function filterCommands(items: readonly CommandItem[], query: string): CommandItem[] {\n const tokens = query.trim().toLowerCase().split(/\\s+/).filter(Boolean);\n if (tokens.length === 0) return [...items];\n return items.filter((item) => {\n const hay = haystack(item);\n return tokens.every((token) => hay.includes(token));\n });\n}\n","/**\n * CommandPalette — the shared ⌘K launcher for `@dloizides/ui-nav`. An overlay\n * (scrim + centred panel) with a search input over a keyboard-navigable list of\n * {@link CommandItem}s — jump to any nav destination (or run any action) without\n * hunting the rail. Web-first (RN-web), but degrades safely: when `open` is\n * false it renders nothing.\n *\n * Package discipline (as the rest of ui-nav): NO FM / router / store / icon-set\n * imports. Labels are pre-localized strings; icons are render slots; every colour\n * comes from the `@dloizides/ui-feedback` UiProvider theme. The consumer owns the\n * `open` state (pair with {@link useCommandPaletteHotkey}) and each item's\n * `onSelect` (navigate / run) — the palette just closes after a choice.\n */\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport {\n Pressable,\n ScrollView,\n StyleSheet,\n Text,\n TextInput,\n View,\n type NativeSyntheticEvent,\n type TextInputKeyPressEventData,\n} from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\n\nimport { filterCommands, type CommandItem } from './commandPaletteFilter';\nimport { NAV_ICON_SIZE } from './styles';\n\nconst SCRIM_COLOR = 'rgba(0, 0, 0, 0.5)';\nconst OVERLAY_Z_INDEX = 60;\nconst PANEL_MAX_WIDTH = 560;\nconst PANEL_TOP_OFFSET = 88;\nconst LIST_MAX_HEIGHT = 360;\nconst KEY_DOWN = 'ArrowDown';\nconst KEY_UP = 'ArrowUp';\nconst KEY_ENTER = 'Enter';\nconst KEY_ESCAPE = 'Escape';\n\n/** Pre-localized labels for the palette chrome. */\nexport interface CommandPaletteLabels {\n /** Search input placeholder. */\n placeholder: string;\n /** Accessible name of the scrim (tap to close). */\n closeLabel: string;\n /** Accessible hint of the scrim (tap to close). */\n closeHint: string;\n /** Shown when the query matches nothing. */\n emptyText: string;\n /** Accessible label for the palette dialog landmark. */\n regionLabel: string;\n}\n\nexport interface CommandPaletteProps {\n /** Whether the palette overlay is shown. */\n open: boolean;\n /** The commands to search over, in a meaningful (nav) order. */\n items: readonly CommandItem[];\n /** Close the palette (scrim tap / Escape / after a selection). */\n onClose: () => void;\n /** Pre-localized chrome labels. */\n labels: CommandPaletteLabels;\n /** testID for the panel (defaults to `command-palette`). */\n testID?: string;\n}\n\nconst styles = StyleSheet.create({\n overlay: { ...StyleSheet.absoluteFillObject, zIndex: OVERLAY_Z_INDEX, alignItems: 'center' },\n scrim: { ...StyleSheet.absoluteFillObject, backgroundColor: SCRIM_COLOR },\n panel: {\n marginTop: PANEL_TOP_OFFSET,\n width: '92%',\n maxWidth: PANEL_MAX_WIDTH,\n borderRadius: 12,\n borderWidth: 1,\n overflow: 'hidden',\n },\n input: { fontSize: 16, paddingHorizontal: 16, paddingVertical: 14, borderBottomWidth: 1 },\n list: { maxHeight: LIST_MAX_HEIGHT },\n row: { flexDirection: 'row', alignItems: 'center', paddingHorizontal: 16, paddingVertical: 12, columnGap: 10 },\n rowText: { flex: 1 },\n rowLabel: { fontSize: 15, fontWeight: '600' },\n rowHint: { fontSize: 12, marginTop: 2 },\n empty: { paddingHorizontal: 16, paddingVertical: 20, fontSize: 14 },\n});\n\ninterface PaletteRowProps {\n item: CommandItem;\n selected: boolean;\n onChoose: (item: CommandItem) => void;\n}\n\n/** One result row — highlighted when it is the active (keyboard) selection. */\nconst PaletteRow = ({ item, selected, onChoose }: PaletteRowProps): React.ReactElement => {\n const { theme } = useUi();\n const colors = theme.colors;\n return (\n <Pressable\n accessibilityHint={item.hint}\n accessibilityLabel={item.label}\n accessibilityRole=\"button\"\n accessibilityState={{ selected }}\n style={[styles.row, selected ? { backgroundColor: colors.border } : undefined]}\n testID={item.testID ?? item.key}\n onPress={() => onChoose(item)}\n >\n {typeof item.renderIcon === 'function' ? item.renderIcon(colors.textSecondary, NAV_ICON_SIZE) : null}\n <View style={styles.rowText}>\n <Text style={[styles.rowLabel, { color: colors.text }]}>{item.label}</Text>\n {item.hint ? <Text style={[styles.rowHint, { color: colors.textSecondary }]}>{item.hint}</Text> : null}\n </View>\n </Pressable>\n );\n};\n\n/** The overlay palette. Renders null when closed. */\nexport const CommandPalette = ({ open, items, onClose, labels, testID }: CommandPaletteProps): React.ReactElement | null => {\n const { theme } = useUi();\n const colors = theme.colors;\n const [query, setQuery] = useState('');\n const [selected, setSelected] = useState(0);\n const inputRef = useRef<TextInput | null>(null);\n\n const results = useMemo(() => filterCommands(items, query), [items, query]);\n\n // Reset + focus each time the palette opens; clamp the selection as results shrink.\n useEffect(() => {\n if (!open) return;\n setQuery('');\n setSelected(0);\n inputRef.current?.focus();\n }, [open]);\n useEffect(() => {\n setSelected((prev) => Math.min(prev, Math.max(0, results.length - 1)));\n }, [results.length]);\n\n const choose = useCallback(\n (item: CommandItem) => {\n item.onSelect();\n onClose();\n },\n [onClose],\n );\n\n const onKeyPress = useCallback(\n (event: NativeSyntheticEvent<TextInputKeyPressEventData>) => {\n const key = event.nativeEvent.key;\n if (key === KEY_DOWN) setSelected((i) => Math.min(i + 1, results.length - 1));\n else if (key === KEY_UP) setSelected((i) => Math.max(i - 1, 0));\n else if (key === KEY_ESCAPE) onClose();\n else if (key === KEY_ENTER && results[selected]) choose(results[selected]);\n },\n [results, selected, choose, onClose],\n );\n\n if (!open) return null;\n\n return (\n <View style={styles.overlay}>\n <Pressable\n accessibilityHint={labels.closeHint}\n accessibilityLabel={labels.closeLabel}\n accessibilityRole=\"button\"\n style={styles.scrim}\n testID={`${testID ?? 'command-palette'}-scrim`}\n onPress={onClose}\n />\n <View\n aria-modal\n aria-label={labels.regionLabel}\n role=\"dialog\"\n style={[styles.panel, { backgroundColor: colors.surface, borderColor: colors.border }]}\n testID={testID ?? 'command-palette'}\n >\n <TextInput\n ref={inputRef}\n accessibilityLabel={labels.placeholder}\n placeholder={labels.placeholder}\n placeholderTextColor={colors.textSecondary}\n style={[styles.input, { color: colors.text, borderBottomColor: colors.border }]}\n testID={`${testID ?? 'command-palette'}-input`}\n value={query}\n onChangeText={setQuery}\n onKeyPress={onKeyPress}\n />\n {results.length === 0 ? (\n <Text style={[styles.empty, { color: colors.textSecondary }]}>{labels.emptyText}</Text>\n ) : (\n <ScrollView keyboardShouldPersistTaps=\"handled\" style={styles.list}>\n {results.map((item, index) => (\n <PaletteRow key={item.key} item={item} selected={index === selected} onChoose={choose} />\n ))}\n </ScrollView>\n )}\n </View>\n </View>\n );\n};\n\nexport default CommandPalette;\n","/**\n * Binds the ⌘K / Ctrl-K launcher shortcut for {@link CommandPalette}. Web-only\n * (guards `document`), so it is a no-op under native RN and in SSR/tests without\n * a DOM. `preventDefault` stops the browser's own Ctrl-K (address-bar search) so\n * the palette wins. The consumer owns the open state; this only requests opening.\n */\nimport { useEffect } from 'react';\n\n/** The launcher key (with ⌘ on macOS or Ctrl elsewhere). */\nconst LAUNCH_KEY = 'k';\n\n/**\n * Call `onOpen` when the operator presses ⌘K (macOS) or Ctrl-K (Windows/Linux),\n * anywhere in the document. `enabled=false` unbinds (e.g. when the shell has no\n * palette configured), so the shortcut never fires without a handler behind it.\n */\nexport function useCommandPaletteHotkey(onOpen: () => void, enabled = true): void {\n useEffect(() => {\n if (!enabled || typeof document === 'undefined') return undefined;\n const handler = (event: KeyboardEvent): void => {\n const isLauncher = event.key.toLowerCase() === LAUNCH_KEY && (event.metaKey || event.ctrlKey);\n if (!isLauncher) return;\n event.preventDefault();\n onOpen();\n };\n document.addEventListener('keydown', handler);\n return () => document.removeEventListener('keydown', handler);\n }, [onOpen, enabled]);\n}\n","/**\n * Role-gated nav helpers — build a `NavItem[]` from a user's roles, reusing the\n * existing `resolveAccessibleRoutes` from `@dloizides/auth-web` (the same helper\n * the multi-role dashboard nav uses) rather than reimplementing role filtering.\n *\n * The app supplies its ordered `RoleRouteTable` (role → route + optional\n * `labelKey`) and a `translate` fn (its `FM`); this returns the ordered set of\n * `NavItem`s the user's roles unlock — most privileged first, empty when none.\n */\nimport { resolveAccessibleRoutes } from '@dloizides/auth-web';\nimport type { RoleRoute, RoleRouteTable } from '@dloizides/auth-web';\n\nimport type { NavItem } from './types';\n\n/** The user shape `resolveAccessibleRoutes` accepts (derived — no extra dep). */\nexport type NavUser = Parameters<typeof resolveAccessibleRoutes>[0];\n\n/** Map already-resolved role routes to nav items, localizing each `labelKey`. */\nexport function roleRoutesToNavItems(\n routes: RoleRoute[],\n translate: (key: string) => string,\n): NavItem[] {\n return routes.map((entry) => ({\n key: entry.role,\n route: entry.route,\n label: entry.labelKey !== undefined ? translate(entry.labelKey) : entry.route,\n }));\n}\n\n/**\n * Resolve the nav items a user can reach, in table (priority) order. Wraps\n * `resolveAccessibleRoutes` so role gating lives in one place.\n */\nexport function accessibleNavItems(\n user: NavUser,\n table: RoleRouteTable,\n translate: (key: string) => string,\n): NavItem[] {\n return roleRoutesToNavItems(resolveAccessibleRoutes(user, table), translate);\n}\n"]}
1
+ {"version":3,"sources":["../src/isRouteActive.ts","../src/styles.ts","../src/webStyle.ts","../src/NavExpandableItem.tsx","../src/textSlot.tsx","../src/Sidebar.tsx","../src/constants.ts","../src/FocusableTouchable.tsx","../src/Topbar.tsx","../src/NavBarLink.tsx","../src/NavOverflowMenu.tsx","../src/computeVisibleCount.ts","../src/useNavOverflow.ts","../src/useReducedMotion.ts","../src/NavBar.tsx","../src/Nav.tsx","../src/appShellContent.tsx","../src/MobileDrawer.tsx","../src/railMode.ts","../src/useContentMaxWidth.ts","../src/AppShell.tsx","../src/CollapsedRail.tsx","../src/NavShell.tsx","../src/PillNav.tsx","../src/DarkModeControl.tsx","../src/commandPaletteFilter.ts","../src/CommandPalette.tsx","../src/CommandPaletteTrigger.tsx","../src/useCommandPaletteHotkey.ts","../src/roleNav.ts"],"names":["jsx","Text","React","useUi","jsxs","View","useState","TEXT_ON_PRIMARY","ariaCurrentProps","Pressable","useMemo","useCallback","useEffect","StyleSheet","MENU_GLYPH","styles","useWindowDimensions","ActivityIndicator","SCRIM_COLOR","useRef","ScrollView"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Active-route matcher shared by the sidebar entries. Ported verbatim from the\n * twin app sidebars: an item is active when the current pathname equals its\n * route or is nested under it (`/foo` matches `/foo` and `/foo/bar`, but `/`\n * only matches `/`).\n */\nexport function isRouteActive(pathname: string, route: string): boolean {\n if (route === '/') return pathname === '/';\n return pathname === route || pathname.startsWith(`${route}/`);\n}\n","/**\n * Layout styles for the nav shell — ported verbatim (dimensions unchanged) from\n * erevna-web / katalogos-web `theme/utils/layoutSidebar.ts` + `layoutTopbar.ts`,\n * so a migrated app's sidebar/topbar keep the exact same metrics. Colours are\n * NOT baked in here; they are applied at render time from the UiProvider theme.\n */\nimport { StyleSheet } from 'react-native';\n\nexport const ACTIVE_BORDER_RADIUS = 4;\n/** Width (px) of the active-leaf left accent bar (reserved on every leaf). */\nexport const ACTIVE_ACCENT_WIDTH = 3;\n\n/**\n * Horizontal gap (px) between adjacent inline items in the `NavBar` links row.\n * Single source of truth: it is both the row's `columnGap` AND the gap the\n * priority+ overflow fit ({@link computeVisibleCount}) reasons about, so the two\n * can never drift apart.\n */\nexport const NAV_LINK_GAP = 4;\n\nexport const navStyles = StyleSheet.create({\n // --- Sidebar ---\n sidebarContainer: {\n width: 220,\n paddingTop: 24,\n paddingHorizontal: 12,\n borderRightWidth: 1,\n height: '100%',\n },\n sidebarTitle: {\n fontWeight: '700',\n marginBottom: 12,\n },\n sidebarItem: {\n paddingVertical: 10,\n paddingHorizontal: 6,\n borderRadius: 4,\n },\n sidebarItemText: {\n fontSize: 16,\n },\n sidebarSpacer: {\n flex: 1,\n },\n\n // --- Topbar ---\n topbarContainer: {\n height: 64,\n paddingHorizontal: 12,\n borderBottomWidth: 1,\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: 'space-between',\n },\n topbarLeft: { flex: 1 },\n topbarRight: { flexDirection: 'row', alignItems: 'center' },\n topbarRowItem: { marginHorizontal: 8, alignItems: 'center' },\n topbarLabel: { fontSize: 14 },\n userBlock: { marginHorizontal: 12, alignItems: 'flex-end' },\n userName: { fontWeight: '600' },\n userEmail: { fontSize: 12 },\n accountBtn: { marginLeft: 8, paddingHorizontal: 10, paddingVertical: 6, borderRadius: 4 },\n accountText: { fontWeight: '600' },\n // --- Rich account-state header (Move 1c) ---\n accountTenant: { fontSize: 12 },\n planBadge: { marginTop: 2, paddingHorizontal: 8, paddingVertical: 2, borderRadius: 10, alignSelf: 'flex-end' },\n planBadgeText: { fontSize: 11, fontWeight: '700' },\n});\n\nexport const navBarStyles = StyleSheet.create({\n // --- Horizontal top NavBar ---\n container: {\n borderBottomWidth: 1,\n paddingHorizontal: 12,\n },\n inner: {\n minHeight: 56,\n flexDirection: 'row',\n alignItems: 'center',\n flexWrap: 'wrap',\n columnGap: 8,\n rowGap: 4,\n paddingVertical: 8,\n },\n // EXPANDED: the row must NOT wrap — otherwise flexbox drops the right slot onto a 2nd line the\n // moment brand+links+right overflow, instead of SHRINKING the (scrollable) links. `flex-shrink`\n // only distributes negative space on a `nowrap` line; with `wrap` it wraps first and never shrinks.\n // Collapsed keeps `wrap` so the stacked links/right (width:100%) can drop to their own lines.\n innerNoWrap: {\n flexWrap: 'nowrap',\n },\n brand: { marginRight: 16, flexShrink: 0 },\n toggle: {\n marginLeft: 'auto',\n paddingHorizontal: 10,\n paddingVertical: 6,\n borderRadius: 4,\n // a11y: keep the hamburger a comfortable ≥44×44 touch target.\n minWidth: 44,\n minHeight: 44,\n alignItems: 'center',\n justifyContent: 'center',\n },\n toggleGlyph: { fontSize: 20, fontWeight: '700' },\n // Expanded links live on ONE ROW that never wraps: it is a shrinkable/growable flex child that\n // fills the space between the pinned brand (left) and right slot, and CLIPS overflow. A measure\n // pass (priority+) then keeps only the leading items that fit inline and collapses the rest behind\n // the \"More ▾\" overflow trigger — so no item is ever cut off; the surplus moves into a dropdown.\n // `overflow:'hidden'` only masks the single unmeasured first frame before the fit resolves.\n linksRow: {\n flexGrow: 1,\n flexShrink: 1,\n minWidth: 0,\n flexDirection: 'row',\n alignItems: 'center',\n flexWrap: 'nowrap',\n columnGap: NAV_LINK_GAP,\n overflow: 'hidden',\n },\n // Each inline link + the overflow trigger sit in a natural-width cell that never shrinks, so their\n // measured widths are their true content widths (what the priority+ fit computation reasons about).\n linkCell: { flexShrink: 0 },\n overflowTrigger: { columnGap: 4 },\n overflowChevron: { fontSize: 12, fontWeight: '700' },\n // Collapsed (below breakpoint): links drop onto their own full-width line,\n // stacked vertically — mirrors the v1 `.gn-links` responsive behaviour.\n linksStacked: {\n width: '100%',\n flexBasis: '100%',\n flexDirection: 'column',\n alignItems: 'stretch',\n rowGap: 2,\n marginTop: 8,\n },\n link: {\n paddingVertical: 8,\n paddingHorizontal: 14,\n borderRadius: 8,\n flexDirection: 'row',\n alignItems: 'center',\n // a11y: comfortable ≥44 tall touch target (rounded-pill hover/active affordance).\n minHeight: 44,\n justifyContent: 'center',\n },\n linkStacked: { paddingVertical: 10 },\n linkIcon: { marginRight: 6 },\n linkText: { fontSize: 15, fontWeight: '600' },\n right: {\n marginLeft: 'auto',\n flexShrink: 0,\n flexDirection: 'row',\n alignItems: 'center',\n columnGap: 8,\n },\n rightStacked: {\n width: '100%',\n flexBasis: '100%',\n marginTop: 4,\n flexDirection: 'row',\n alignItems: 'center',\n columnGap: 8,\n },\n});\n\nexport const pillNavStyles = StyleSheet.create({\n // Cross-nav pill row (kefi coral dashboard switcher): fully-rounded pills, wraps.\n container: {\n flexDirection: 'row',\n flexWrap: 'wrap',\n alignItems: 'center',\n columnGap: 8,\n rowGap: 8,\n paddingVertical: 8,\n },\n pill: {\n paddingHorizontal: 16,\n paddingVertical: 8,\n borderRadius: 999,\n minHeight: 36,\n flexDirection: 'row',\n alignItems: 'center',\n columnGap: 6,\n justifyContent: 'center',\n },\n pillText: { fontSize: 14, fontWeight: '600' },\n});\n\nexport const darkModeStyles = StyleSheet.create({\n // Segmented Light / Dark / System control.\n segmentRow: {\n flexDirection: 'row',\n alignItems: 'center',\n borderWidth: 1,\n borderRadius: 8,\n overflow: 'hidden',\n alignSelf: 'flex-start',\n },\n segment: {\n paddingHorizontal: 12,\n paddingVertical: 8,\n minHeight: 36,\n flexDirection: 'row',\n alignItems: 'center',\n columnGap: 6,\n justifyContent: 'center',\n },\n segmentText: { fontSize: 13, fontWeight: '600' },\n // Cycle-button variant.\n cycle: {\n paddingHorizontal: 12,\n paddingVertical: 8,\n minHeight: 44,\n minWidth: 44,\n borderRadius: 8,\n flexDirection: 'row',\n alignItems: 'center',\n columnGap: 6,\n justifyContent: 'center',\n },\n cycleText: { fontSize: 13, fontWeight: '600' },\n});\n\nexport const collapsedRailStyles = StyleSheet.create({\n // Intermediate (tablet) icon-only rail: a narrow vertical strip of icon buttons.\n container: {\n width: 64,\n paddingTop: 16,\n paddingHorizontal: 8,\n borderRightWidth: 1,\n height: '100%',\n alignItems: 'center',\n },\n // Each item is a ≥44×44 centred touch target with a rounded active/hover pill.\n item: {\n width: 48,\n height: 48,\n marginVertical: 4,\n borderRadius: 8,\n alignItems: 'center',\n justifyContent: 'center',\n },\n // Glyph fallback (the label's first character) when an item has no renderIcon.\n glyph: { fontSize: 18, fontWeight: '700' },\n spacer: { flex: 1 },\n slot: { alignItems: 'center' },\n});\n\nexport const expandableStyles = StyleSheet.create({\n // Every leaf reserves the accent-bar gutter (a TRANSPARENT left border of the\n // same width the active item colours in) so activation never shifts the row.\n childItem: {\n borderRadius: 6,\n flexDirection: 'row',\n alignItems: 'center',\n paddingVertical: 9,\n borderLeftWidth: ACTIVE_ACCENT_WIDTH,\n borderLeftColor: 'transparent',\n },\n childItemText: { fontSize: 14 },\n childItemTextWithIcon: { fontSize: 14, marginLeft: 6 },\n chevron: { marginLeft: 'auto' },\n childrenContainer: { overflow: 'hidden', marginBottom: 4 },\n header: {\n borderRadius: 6,\n flexDirection: 'row',\n alignItems: 'center',\n paddingVertical: 8,\n },\n // Depth-0 module groups render as docs-style SECTION HEADERS: extra top rhythm\n // to separate one module from the next.\n sectionHeader: { marginTop: 12 },\n headerText: { fontSize: 15, fontWeight: '600', marginLeft: 6 },\n // The section-label look: small, uppercased, tracked, muted — the aml-screening\n // docs treatment (\"START HERE\" / \"REFERENCE\"), kept on an interactive toggle.\n sectionHeaderText: {\n fontSize: 12,\n fontWeight: '700',\n marginLeft: 6,\n textTransform: 'uppercase',\n letterSpacing: 0.8,\n },\n iconWrapper: { width: 20, alignItems: 'center' },\n});\n\n/** Base indent applied per nesting depth in the expandable item. */\nexport const BASE_INDENT = 12;\n/** Default icon size for nav item icons. */\nexport const NAV_ICON_SIZE = 14;\n/** Chevron icon size for expandable sections. */\nexport const CHEVRON_ICON_SIZE = 12;\n","/**\n * Web-only style helpers for the nav shell. React Native's `ViewStyle` has no\n * `outline*` or `transition*` keys, but react-native-web forwards them to the DOM,\n * so we build them as typed web-style objects and cast ONCE to `ViewStyle` (no\n * `any`). On native these CSS-only props are meaningless — every helper returns\n * `undefined` when `IS_WEB` is false, so nothing is applied off the web.\n */\nimport { Platform, type ViewStyle } from 'react-native';\n\n/** True only under react-native-web. Gates the CSS-only focus ring + hover transition. */\nexport const IS_WEB = Platform.OS === 'web';\n\n/** Keyboard focus-ring width (px). */\nconst FOCUS_RING_WIDTH = 2;\n/** Gap between the ring and the element edge (px) so the ring reads clearly. */\nconst FOCUS_RING_OFFSET = 2;\n/** Hover-pill colour/background cross-fade duration (ms). */\nconst HOVER_TRANSITION_MS = 150;\n\n/** DOM `outline-*` shape — not part of RN `ViewStyle`, but honoured by react-native-web. */\ninterface WebOutlineStyle {\n outlineWidth: number;\n outlineStyle: 'solid';\n outlineColor: string;\n outlineOffset: number;\n}\n\n/** DOM `transition-*` shape — not part of RN `ViewStyle`, but honoured by react-native-web. */\ninterface WebTransitionStyle {\n transitionProperty: string;\n transitionDuration: string;\n}\n\n/**\n * A visible keyboard-focus ring in the theme accent colour. Returns `undefined`\n * on native, and when the element is not focused, so nothing is applied. Never\n * removes the outline without a replacement — it ADDS a themed ring on focus.\n */\nexport function focusRingStyle(focused: boolean, ringColor: string): ViewStyle | undefined {\n if (!IS_WEB || !focused) return undefined;\n const ring: WebOutlineStyle = {\n outlineWidth: FOCUS_RING_WIDTH,\n outlineStyle: 'solid',\n outlineColor: ringColor,\n outlineOffset: FOCUS_RING_OFFSET,\n };\n return ring as unknown as ViewStyle;\n}\n\n/**\n * A cheap CSS cross-fade for the hover-pill colour/background. Disabled (`0ms`)\n * when the user prefers reduced motion, and omitted entirely on native. No JS\n * animation — the transition is pure CSS applied by react-native-web.\n */\nexport function hoverTransitionStyle(reducedMotion: boolean): ViewStyle | undefined {\n if (!IS_WEB) return undefined;\n const transition: WebTransitionStyle = {\n transitionProperty: 'color, background-color',\n transitionDuration: reducedMotion ? '0ms' : `${HOVER_TRANSITION_MS}ms`,\n };\n return transition as unknown as ViewStyle;\n}\n","/**\n * NavExpandableItem — a single sidebar entry that is either a leaf (navigates)\n * or an expandable section (toggles nested children). Ported from the twin\n * erevna/katalogos `Sidebar/NavExpandableItem`, made config-driven: labels are\n * pre-localized strings, icons are render slots, colours come from `useUi`.\n */\nimport React, { useCallback, useMemo, useState } from 'react';\n\nimport { Text, TouchableOpacity, View, type TouchableOpacityProps } from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\n\nimport {\n BASE_INDENT,\n CHEVRON_ICON_SIZE,\n NAV_ICON_SIZE,\n ACTIVE_BORDER_RADIUS,\n ACTIVE_ACCENT_WIDTH,\n expandableStyles as styles,\n} from './styles';\nimport { isRouteActive } from './isRouteActive';\nimport type { NavItem } from './types';\nimport { focusRingStyle } from './webStyle';\n\n/**\n * `aria-current=\"page\"` marks the active leaf for assistive tech. RN's prop types\n * omit `aria-current`; react-native-web forwards `aria-*` to the DOM — attach it\n * (no `any`) only when the leaf is active.\n */\nfunction ariaCurrentProps(isActive: boolean): TouchableOpacityProps & { 'aria-current'?: 'page' } {\n return isActive ? { 'aria-current': 'page' } : {};\n}\n\n/**\n * `aria-expanded` marks an expandable section header as a disclosure control for\n * assistive tech — and, just as importantly, is the DOM signal `MobileDrawer` uses\n * to tell a group TOGGLE apart from a navigating leaf (so expanding a group on\n * mobile no longer dismisses the drawer). RNW forwards `aria-*` props to the DOM\n * but does NOT synthesize `aria-expanded` from `accessibilityState.expanded` in\n * this version, so set it explicitly (same pattern as `aria-current` above).\n */\nfunction ariaExpandedProps(expanded: boolean): TouchableOpacityProps & { 'aria-expanded'?: boolean } {\n return { 'aria-expanded': expanded };\n}\n\n/**\n * True when the current route is inside this item — its own route is active, or\n * any descendant's is. Drives the initial expansion so a group that contains the\n * active route opens on mount and its active leaf is visible; a group with no\n * active descendant mounts collapsed (the prior behaviour). Recursive so it holds\n * at any nesting depth.\n */\nfunction hasActiveDescendant(item: NavItem, pathname: string): boolean {\n if (isRouteActive(pathname, item.route)) return true;\n return (item.children ?? []).some((child) => hasActiveDescendant(child, pathname));\n}\n\nexport interface NavExpandableItemProps {\n item: NavItem;\n pathname: string;\n onNavigate: (route: string) => void;\n /** a11y hint for a leaf item, given its label. */\n navigateHint: (label: string) => string;\n /** a11y hint shown when the section is collapsed (press expands). */\n expandHint: string;\n /** a11y hint shown when the section is expanded (press collapses). */\n collapseHint: string;\n /** Optional chevron icon renderer for expandable sections. */\n renderChevron?: (expanded: boolean, color: string, size: number) => React.ReactNode;\n depth?: number;\n}\n\nexport const NavExpandableItem = ({\n item,\n pathname,\n onNavigate,\n navigateHint,\n expandHint,\n collapseHint,\n renderChevron,\n depth = 0,\n}: NavExpandableItemProps): React.ReactElement => {\n const [expanded, setExpanded] = useState(() => hasActiveDescendant(item, pathname));\n const [focused, setFocused] = useState(false);\n const { theme } = useUi();\n const colors = theme.colors;\n const primaryColor = theme.palette.primary['500'];\n\n const toggle = useCallback(() => setExpanded((v) => !v), []);\n\n const indent = depth * BASE_INDENT;\n const hasChildren = Array.isArray(item.children) && item.children.length > 0;\n const isActive = isRouteActive(pathname, item.route);\n // A top-level expandable group is a docs-style section header (uppercase, muted);\n // nested groups keep the plain header look.\n const isSectionHeader = hasChildren && depth === 0;\n\n // Active leaf: the docs-style strong treatment — a coloured left accent bar\n // (over the transparent gutter every leaf reserves, so there is no layout\n // shift) plus a tinted surface. The bar colour is the theme primary, so each\n // portal's brand drives it.\n const activeItemStyle = useMemo(\n () => ({\n backgroundColor: colors.border,\n borderRadius: ACTIVE_BORDER_RADIUS,\n borderLeftWidth: ACTIVE_ACCENT_WIDTH,\n borderLeftColor: primaryColor,\n }),\n [colors.border, primaryColor],\n );\n const paddingStyle = useMemo(() => ({ paddingLeft: indent + BASE_INDENT }), [indent]);\n const headerPaddingStyle = useMemo(() => ({ paddingLeft: indent }), [indent]);\n\n if (!hasChildren)\n return (\n <TouchableOpacity\n accessibilityHint={navigateHint(item.label)}\n accessibilityLabel={item.label}\n accessibilityRole=\"button\"\n accessibilityState={{ selected: isActive }}\n style={[\n styles.childItem,\n paddingStyle,\n isActive ? activeItemStyle : undefined,\n focusRingStyle(focused, primaryColor),\n ]}\n testID={item.testID ?? item.key}\n onBlur={() => setFocused(false)}\n onFocus={() => setFocused(true)}\n onPress={() => onNavigate(item.route)}\n {...ariaCurrentProps(isActive)}\n >\n {typeof item.renderIcon === 'function' ? (\n <View style={styles.iconWrapper}>{item.renderIcon(colors.textSecondary, NAV_ICON_SIZE)}</View>\n ) : null}\n <Text\n style={[\n typeof item.renderIcon === 'function' ? styles.childItemTextWithIcon : styles.childItemText,\n { color: isActive ? primaryColor : colors.text },\n ]}\n >\n {item.label}\n </Text>\n </TouchableOpacity>\n );\n\n return (\n <View>\n <TouchableOpacity\n accessibilityHint={expanded ? collapseHint : expandHint}\n accessibilityLabel={item.label}\n accessibilityRole=\"button\"\n accessibilityState={{ expanded }}\n style={[\n styles.header,\n isSectionHeader ? styles.sectionHeader : undefined,\n headerPaddingStyle,\n focusRingStyle(focused, primaryColor),\n ]}\n testID={item.testID ?? item.key}\n onBlur={() => setFocused(false)}\n onFocus={() => setFocused(true)}\n onPress={toggle}\n {...ariaExpandedProps(expanded)}\n >\n {typeof item.renderIcon === 'function' ? (\n <View style={styles.iconWrapper}>\n {item.renderIcon(isSectionHeader ? colors.textSecondary : colors.text, NAV_ICON_SIZE)}\n </View>\n ) : null}\n <Text\n style={[\n isSectionHeader ? styles.sectionHeaderText : styles.headerText,\n { color: isSectionHeader ? colors.textSecondary : colors.text },\n ]}\n >\n {item.label}\n </Text>\n {typeof renderChevron === 'function' ? (\n <View style={styles.chevron}>{renderChevron(expanded, colors.textSecondary, CHEVRON_ICON_SIZE)}</View>\n ) : null}\n </TouchableOpacity>\n\n {expanded ? (\n <View style={styles.childrenContainer}>\n {item.children?.map((child) => (\n <NavExpandableItem\n key={child.key}\n collapseHint={collapseHint}\n depth={depth + 1}\n expandHint={expandHint}\n item={child}\n navigateHint={navigateHint}\n pathname={pathname}\n renderChevron={renderChevron}\n onNavigate={onNavigate}\n />\n ))}\n </View>\n ) : null}\n </View>\n );\n};\n\nexport default NavExpandableItem;\n","/**\n * `renderTextSlot` — the single guard for every caller-supplied `React.ReactNode`\n * slot in this kit (brand, right, left, header, footer, banner, notificationSlot…).\n *\n * Why this exists. React Native Web refuses to render a bare text node inside a\n * `<View>`: it logs `Unexpected text node: <s>. A text node cannot be a child of a\n * <View>.` through `console.error` on EVERY render. Slots are typed `React.ReactNode`,\n * which legitimately includes `string`, and callers do exactly that — Digital Kin's\n * shell passes `brand: FM('app.name')`, a plain localized string. Nothing in the type\n * system objects, so the defect only ever surfaces as console noise in the browser,\n * which is why it survived in all seven portals.\n *\n * Rather than push the `<Text>` wrapper onto every consuming app (seven chances to\n * forget, and the type would still permit the mistake), the kit absorbs it here: a\n * string or number slot is wrapped in `<Text>`, and an element slot is passed through\n * untouched so existing callers are byte-identical. `React.Children.map` is used so an\n * ARRAY slot (`['Digital', <Logo key=\"l\" />]`) has each string member wrapped\n * individually while keys are preserved.\n *\n * `style` lets the call site route the wrapper through the theme — an unwrapped\n * `<Text>` would otherwise default to black and ignore dark mode.\n */\nimport React from 'react';\n\nimport { Text, type TextStyle } from 'react-native';\n\n/** Is this node a bare text node that RN-web would refuse to render inside a `<View>`? */\nfunction isBareText(node: React.ReactNode): node is string | number {\n return typeof node === 'string' || typeof node === 'number';\n}\n\n/**\n * Wrap bare string / number members of `node` in `<Text>`; pass elements through as-is.\n * Returns `node` unchanged when it is `undefined` / `null` so callers can keep their\n * existing `!== undefined` guards.\n */\nexport function renderTextSlot(node: React.ReactNode, style?: TextStyle): React.ReactNode {\n if (node === undefined || node === null) return node;\n if (isBareText(node)) return <Text style={style}>{node}</Text>;\n return React.Children.map(node, (child) =>\n isBareText(child) ? <Text style={style}>{child}</Text> : child,\n );\n}\n","/**\r\n * Sidebar — the config-driven left navigation shell promoted from the\r\n * byte-identical erevna-web / katalogos-web `Sidebar`. It renders a caller\r\n * supplied `NavItem[]` (leaf + expandable), highlights the active route, and\r\n * exposes header/footer slots for app-specific chrome (title, dark-mode toggle,\r\n * logout, notification bell). Every colour is read from the UiProvider theme.\r\n */\r\nimport React from 'react';\r\n\r\nimport { Text, View, type ViewStyle } from 'react-native';\r\n\r\nimport { useUi } from '@dloizides/ui-feedback';\r\n\r\nimport { isRouteActive } from './isRouteActive';\r\nimport { NavExpandableItem } from './NavExpandableItem';\r\nimport { navStyles as styles } from './styles';\r\nimport type { NavItem } from './types';\r\nimport { renderTextSlot } from './textSlot';\r\n\r\nexport interface SidebarProps {\r\n /** Nav entries — already role-filtered / grouped by the app. */\r\n items: NavItem[];\r\n /** Current active route/path. */\r\n pathname: string;\r\n /** Navigation callback — receives a `NavItem.route`. */\r\n onNavigate: (route: string) => void;\r\n /** Localized menu title (heading). */\r\n title: string;\r\n /** Localized accessibility label for the navigation landmark. */\r\n regionLabel: string;\r\n /** a11y hint for a leaf item, given its label. Defaults to the label. */\r\n navigateHint?: (label: string) => string;\r\n /** a11y hint shown when an expandable section is collapsed. */\r\n expandHint?: string;\r\n /** a11y hint shown when an expandable section is expanded. */\r\n collapseHint?: string;\r\n /** Optional chevron renderer for expandable sections. */\r\n renderChevron?: (expanded: boolean, color: string, size: number) => React.ReactNode;\r\n /** Optional header slot rendered above the items (e.g. a Home shortcut). */\r\n header?: React.ReactNode;\r\n /** Optional footer slot rendered after a flex spacer (dark-mode toggle, logout). */\r\n footer?: React.ReactNode;\r\n /** Extra container style overrides. */\r\n containerStyle?: ViewStyle | ViewStyle[];\r\n}\r\n\r\nexport const Sidebar = ({\r\n items,\r\n pathname,\r\n onNavigate,\r\n title,\r\n regionLabel,\r\n navigateHint = (label) => label,\r\n expandHint = '',\r\n collapseHint = '',\r\n renderChevron,\r\n header,\r\n footer,\r\n containerStyle,\r\n}: SidebarProps): React.ReactElement => {\r\n const { theme } = useUi();\r\n const colors = theme.colors;\r\n\r\n return (\r\n <View\r\n accessibilityRole=\"none\"\r\n aria-label={regionLabel}\r\n role=\"navigation\"\r\n style={[\r\n styles.sidebarContainer,\r\n { backgroundColor: colors.surface, borderRightColor: colors.border },\r\n containerStyle,\r\n ]}\r\n >\r\n <Text accessibilityRole=\"header\" style={[styles.sidebarTitle, { color: colors.text }]}>\r\n {title}\r\n </Text>\r\n\r\n {renderTextSlot(header, { color: colors.text })}\r\n\r\n {items.map((item) => (\r\n <NavExpandableItem\r\n key={item.key}\r\n collapseHint={collapseHint}\r\n expandHint={expandHint}\r\n item={item}\r\n navigateHint={navigateHint}\r\n pathname={pathname}\r\n renderChevron={renderChevron}\r\n onNavigate={onNavigate}\r\n />\r\n ))}\r\n\r\n <View style={styles.sidebarSpacer} />\r\n\r\n {renderTextSlot(footer, { color: colors.text })}\r\n </View>\r\n );\r\n};\r\n\r\nexport { isRouteActive };\r\nexport default Sidebar;\r\n","/**\n * Default testIDs for `@dloizides/ui-nav`. Kept as a small central map (mirrors\n * `@dloizides/ui-layout`'s `LAYOUT_TEST_IDS`) so the app-agnostic chrome exposes\n * stable Playwright selectors. The existing Topbar logout/account buttons keep\n * their *caller-supplied* testIDs (via `TopbarAction.testID`) — these constants\n * only name the NEW account-state bits and the AppShell region suffixes.\n */\nexport const NAV_TEST_IDS = {\n /** displayName line in the rich account header (tappable when `onAccount` set). */\n accountName: 'topbar-account-name',\n /** muted tenant-name line under the displayName. */\n accountTenant: 'topbar-account-tenant',\n /** small plan badge (free / pro / enterprise). */\n accountPlan: 'topbar-account-plan',\n /** default testID for the rich header's upgrade action (overridable per-action). */\n accountUpgrade: 'topbar-account-upgrade',\n /** responsive hamburger toggle in the horizontal NavBar (shown below the breakpoint). */\n navBarToggle: 'navbar-toggle',\n /** links container in the horizontal NavBar. */\n navBarLinks: 'navbar-links',\n /** the \"More ▾\" priority+ overflow trigger in the horizontal NavBar (shown when items spill). */\n navBarOverflow: 'navbar-overflow',\n} as const;\n\n/** Suffixes appended to an `AppShell`'s required `testID` to name its regions. */\nexport const APP_SHELL_SUFFIX = {\n content: '-content',\n header: '-header',\n nav: '-nav',\n /** The persistent left rail of the back-office layout (only when `sidebar` is supplied). */\n sidebar: '-sidebar',\n /** The intermediate persistent COLLAPSED (icon-only) rail (3-tier layout, tablet band). */\n collapsedSidebar: '-collapsed-sidebar',\n /** Mobile hamburger that opens the nav drawer (back-office layout, below the breakpoint). */\n menuToggle: '-menu-toggle',\n /** The mobile nav drawer panel (holds the `sidebar` slot when opened on a narrow viewport). */\n drawer: '-drawer',\n /** The mobile nav drawer scrim (tap to close). */\n scrim: '-drawer-scrim',\n banner: '-banner',\n pending: '-pending',\n loading: '-loading',\n error: '-error',\n forbidden: '-forbidden',\n} as const;\n","/**\n * FocusableTouchable — a thin `Pressable` wrapper that adds a THEMED keyboard\n * focus ring (via `focusRingStyle`) to any tappable, while forwarding the usual\n * accessibility props. Used by `Topbar` (and available to any nav element that\n * needs a focus ring without its own hover logic). Native-safe: the ring is\n * web-only; on native the focus state simply never drives a visible outline.\n */\nimport React, { useState } from 'react';\n\nimport { Pressable, type StyleProp, type ViewStyle } from 'react-native';\n\nimport { focusRingStyle } from './webStyle';\n\nexport interface FocusableTouchableProps {\n /** Press handler. */\n onPress: () => void;\n /** Accessible name. */\n accessibilityLabel: string;\n /** Accessible hint. */\n accessibilityHint: string;\n /** ARIA role — button (default) or link. */\n accessibilityRole?: 'button' | 'link';\n /** Focus-ring colour (theme accent). */\n ringColor: string;\n /** Base style(s) applied under the focus ring. */\n style?: StyleProp<ViewStyle>;\n /** Optional testID. */\n testID?: string;\n children: React.ReactNode;\n}\n\nexport const FocusableTouchable = ({\n onPress,\n accessibilityLabel,\n accessibilityHint,\n accessibilityRole = 'button',\n ringColor,\n style,\n testID,\n children,\n}: FocusableTouchableProps): React.ReactElement => {\n const [focused, setFocused] = useState(false);\n return (\n <Pressable\n accessibilityHint={accessibilityHint}\n accessibilityLabel={accessibilityLabel}\n accessibilityRole={accessibilityRole}\n style={[style, focusRingStyle(focused, ringColor)]}\n testID={testID}\n onBlur={() => setFocused(false)}\n onFocus={() => setFocused(true)}\n onPress={onPress}\n >\n {children}\n </Pressable>\n );\n};\n\nexport default FocusableTouchable;\n","/**\r\n * Topbar — the config-driven top navigation bar promoted from the byte-identical\r\n * erevna-web / katalogos-web `Topbar`. Structured slots replace the app-specific\r\n * wiring: a `left` logo slot, an optional language toggle, a notification slot,\r\n * an optional user block, an optional account button, and a required logout\r\n * action. Every colour comes from the UiProvider theme.\r\n *\r\n * Move 1c enriches this WITHOUT breaking the promoted contract: `account` now\r\n * accepts EITHER the legacy `TopbarAction` (today's erevna/katalogos calls) OR a\r\n * richer `AccountState` (displayName + muted tenant line + plan badge + upgrade\r\n * action). The `logout` action stays required, so every existing call keeps\r\n * compiling and the logout button keeps its caller-supplied testID.\r\n */\r\nimport React from 'react';\r\n\r\nimport { Text, View, type ViewStyle } from 'react-native';\r\n\r\nimport { useUi, type UiTheme } from '@dloizides/ui-feedback';\r\n\r\nimport { NAV_TEST_IDS } from './constants';\r\nimport { FocusableTouchable } from './FocusableTouchable';\r\nimport { navStyles as styles } from './styles';\r\nimport { renderTextSlot } from './textSlot';\r\n\r\n/** Text color for elements on primary/coloured badge backgrounds. */\r\nconst TEXT_ON_PRIMARY = '#ffffff';\r\n\r\nexport interface TopbarAction {\r\n label: string;\r\n hint: string;\r\n onPress: () => void;\r\n testID?: string;\r\n}\r\n\r\nexport interface TopbarUser {\r\n name: string;\r\n email: string;\r\n}\r\n\r\n/** Plan tier shown as a small badge in the rich account header. */\r\nexport interface AccountPlan {\r\n label: string;\r\n tone?: 'free' | 'pro' | 'enterprise';\r\n}\r\n\r\n/**\r\n * Richer account model for the header (Move 1c). Supplied via `account` as an\r\n * alternative to the legacy `TopbarAction` — the Topbar renders the display name\r\n * (tappable when `onAccount` is set), a muted tenant line, a plan badge, and an\r\n * `upgrade` action beside logout. No FM/router/store — everything is a\r\n * pre-localized string or a callback.\r\n */\r\nexport interface AccountState {\r\n displayName: string;\r\n tenantName?: string;\r\n plan?: AccountPlan;\r\n onLogout: () => void;\r\n onAccount?: () => void;\r\n /**\r\n * a11y hint for the account-name button (what pressing it DOES).\r\n *\r\n * Without this the hint fell back to `displayName` — byte-identical to the\r\n * accessibility LABEL, so a screen reader announced the name twice and never\r\n * said where the button goes. The sibling `upgrade?: TopbarAction` on this very\r\n * interface has always carried a `hint`; this closes that inconsistency. The\r\n * `displayName` fallback is retained so existing callers are unaffected.\r\n */\r\n accountHint?: string;\r\n /** testID for the account-name button. Defaults to `NAV_TEST_IDS.accountName`. */\r\n accountTestID?: string;\r\n upgrade?: TopbarAction;\r\n}\r\n\r\n/** Type guard: distinguishes the rich `AccountState` from a legacy `TopbarAction`. */\r\nfunction isAccountState(account: TopbarAction | AccountState): account is AccountState {\r\n return 'displayName' in account;\r\n}\r\n\r\n/** Resolve a plan badge background from its tone, routed through the theme. */\r\nfunction planToneColor(theme: UiTheme, tone: AccountPlan['tone']): string {\r\n const palette = theme.palette;\r\n if (tone === 'pro') return palette.primary['500'];\r\n if (tone === 'enterprise') return palette.accent?.['500'] ?? palette.primary['500'];\r\n return theme.colors.textSecondary;\r\n}\r\n\r\nexport interface TopbarProps {\r\n /** Left slot — typically the tenant logo. */\r\n left?: React.ReactNode;\r\n /**\r\n * Optional language toggle. `testID` is optional but the repo standard wants\r\n * one — before 1.10.0 this inline type declared none, so a testID was\r\n * structurally unreachable for this button while every other Topbar action\r\n * (which use `TopbarAction`) accepted one.\r\n */\r\n language?: { label: string; hint: string; onPress: () => void; testID?: string };\r\n /** Optional notification slot (e.g. a notification bell). */\r\n notificationSlot?: React.ReactNode;\r\n /** Optional user identity block. */\r\n user?: TopbarUser;\r\n /**\r\n * Optional account slot. Legacy callers pass a `TopbarAction` (an account\r\n * button). Move-1c callers pass an `AccountState` for the richer header.\r\n */\r\n account?: TopbarAction | AccountState;\r\n /** Required logout action (drives the stable logout button testID). */\r\n logout: TopbarAction;\r\n /** Extra container style overrides. */\r\n containerStyle?: ViewStyle | ViewStyle[];\r\n}\r\n\r\nexport const Topbar = ({\r\n left,\r\n language,\r\n notificationSlot,\r\n user,\r\n account,\r\n logout,\r\n containerStyle,\r\n}: TopbarProps): React.ReactElement => {\r\n const { theme } = useUi();\r\n const colors = theme.colors;\r\n const primaryColor = theme.palette.primary['500'];\r\n\r\n const richAccount = account !== undefined && isAccountState(account) ? account : undefined;\r\n const legacyAccount = account !== undefined && !isAccountState(account) ? account : undefined;\r\n const upgrade = richAccount?.upgrade;\r\n\r\n return (\r\n <View\r\n style={[\r\n styles.topbarContainer,\r\n { borderBottomColor: colors.border, backgroundColor: colors.background },\r\n containerStyle,\r\n ]}\r\n >\r\n <View style={styles.topbarLeft}>{renderTextSlot(left, { color: colors.text })}</View>\r\n <View style={styles.topbarRight}>\r\n {language ? (\r\n <FocusableTouchable\r\n accessibilityHint={language.hint}\r\n accessibilityLabel={language.label}\r\n ringColor={primaryColor}\r\n style={styles.topbarRowItem}\r\n testID={language.testID}\r\n onPress={language.onPress}\r\n >\r\n <Text style={[styles.topbarLabel, { color: colors.text }]}>{language.label}</Text>\r\n </FocusableTouchable>\r\n ) : null}\r\n\r\n {renderTextSlot(notificationSlot, { color: colors.text })}\r\n\r\n {user ? (\r\n <View style={styles.userBlock}>\r\n <Text style={[styles.userName, { color: colors.text }]}>{user.name}</Text>\r\n <Text style={[styles.userEmail, { color: colors.textSecondary }]}>{user.email}</Text>\r\n </View>\r\n ) : null}\r\n\r\n {richAccount ? (\r\n <View style={styles.userBlock}>\r\n {richAccount.onAccount ? (\r\n <FocusableTouchable\r\n accessibilityHint={richAccount.accountHint ?? richAccount.displayName}\r\n accessibilityLabel={richAccount.displayName}\r\n ringColor={primaryColor}\r\n testID={richAccount.accountTestID ?? NAV_TEST_IDS.accountName}\r\n onPress={richAccount.onAccount}\r\n >\r\n <Text style={[styles.userName, { color: colors.text }]}>{richAccount.displayName}</Text>\r\n </FocusableTouchable>\r\n ) : (\r\n <Text style={[styles.userName, { color: colors.text }]} testID={NAV_TEST_IDS.accountName}>\r\n {richAccount.displayName}\r\n </Text>\r\n )}\r\n\r\n {richAccount.tenantName !== undefined ? (\r\n <Text\r\n style={[styles.accountTenant, { color: colors.textSecondary }]}\r\n testID={NAV_TEST_IDS.accountTenant}\r\n >\r\n {richAccount.tenantName}\r\n </Text>\r\n ) : null}\r\n\r\n {richAccount.plan ? (\r\n <View\r\n style={[styles.planBadge, { backgroundColor: planToneColor(theme, richAccount.plan.tone) }]}\r\n testID={NAV_TEST_IDS.accountPlan}\r\n >\r\n <Text style={[styles.planBadgeText, { color: TEXT_ON_PRIMARY }]}>{richAccount.plan.label}</Text>\r\n </View>\r\n ) : null}\r\n </View>\r\n ) : null}\r\n\r\n {legacyAccount ? (\r\n <FocusableTouchable\r\n accessibilityHint={legacyAccount.hint}\r\n accessibilityLabel={legacyAccount.label}\r\n ringColor={primaryColor}\r\n style={[styles.accountBtn, { backgroundColor: primaryColor }]}\r\n testID={legacyAccount.testID}\r\n onPress={legacyAccount.onPress}\r\n >\r\n <Text style={[styles.accountText, { color: TEXT_ON_PRIMARY }]}>{legacyAccount.label}</Text>\r\n </FocusableTouchable>\r\n ) : null}\r\n\r\n {upgrade ? (\r\n <FocusableTouchable\r\n accessibilityHint={upgrade.hint}\r\n accessibilityLabel={upgrade.label}\r\n ringColor={primaryColor}\r\n style={[styles.accountBtn, { backgroundColor: primaryColor }]}\r\n testID={upgrade.testID ?? NAV_TEST_IDS.accountUpgrade}\r\n onPress={upgrade.onPress}\r\n >\r\n <Text style={[styles.accountText, { color: TEXT_ON_PRIMARY }]}>{upgrade.label}</Text>\r\n </FocusableTouchable>\r\n ) : null}\r\n\r\n <FocusableTouchable\r\n accessibilityHint={logout.hint}\r\n accessibilityLabel={logout.label}\r\n ringColor={primaryColor}\r\n style={[styles.accountBtn, { backgroundColor: primaryColor }]}\r\n testID={logout.testID}\r\n onPress={richAccount ? richAccount.onLogout : logout.onPress}\r\n >\r\n <Text style={[styles.accountText, { color: TEXT_ON_PRIMARY }]}>{logout.label}</Text>\r\n </FocusableTouchable>\r\n </View>\r\n </View>\r\n );\r\n};\r\n\r\nexport default Topbar;\r\n","/**\n * NavBarLink — a SINGLE horizontal `NavBar` link, extracted so each link owns its\n * own hover/focus state (React hooks can't be per-item inside a map otherwise).\n *\n * It renders the v1 `.gn-links a` affordance, THEME-DRIVEN (no hard-coded colours\n * beyond white ink on the accent pill):\n * - rest → muted text (`colors.rest`), no background\n * - hover → text brightens to full contrast (`colors.hoverText`) + a subtle\n * rounded-pill background (`colors.hoverBg`, e.g. v1 `#16223a`)\n * - active → solid accent pill (`colors.activeBg`) with white ink + aria-current\n * - focus → a themed keyboard focus ring (`colors.ring`)\n * Hover/focus are WEB-only (react-native-web fires `onHoverIn/Out`); on native\n * those handlers never fire, so the link stays at its rest style.\n */\nimport React, { useState } from 'react';\n\nimport { Pressable, Text, View, type PressableProps, type ViewStyle } from 'react-native';\n\nimport { navBarStyles as styles } from './styles';\nimport { focusRingStyle, hoverTransitionStyle } from './webStyle';\nimport type { NavItem } from './types';\n\n/** Ink for a link sitting on the primary (active) pill — always full-contrast white. */\nconst TEXT_ON_PRIMARY = '#ffffff';\n\n/** Theme-resolved colours a link needs, computed once by `NavBar`. */\nexport interface NavBarLinkColors {\n /** Muted link text at rest. */\n rest: string;\n /** Brightened link text on hover. */\n hoverText: string;\n /** Subtle hover-pill background. */\n hoverBg: string;\n /** Active-pill background (accent). */\n activeBg: string;\n /** Focus-ring colour. */\n ring: string;\n}\n\nexport interface NavBarLinkProps {\n item: NavItem;\n isActive: boolean;\n collapsed: boolean;\n iconSize: number;\n reducedMotion: boolean;\n colors: NavBarLinkColors;\n navigateHint: (label: string) => string;\n onPress: (route: string) => void;\n}\n\n/**\n * `aria-current=\"page\"` marks the active link for assistive tech. RN's prop types\n * omit `aria-current`, but react-native-web forwards `aria-*` to the DOM — so we\n * attach it (no `any`) only when a link is active.\n */\nfunction ariaCurrentProps(isActive: boolean): PressableProps & { 'aria-current'?: 'page' } {\n return isActive ? { 'aria-current': 'page' } : {};\n}\n\nexport const NavBarLink = ({\n item,\n isActive,\n collapsed,\n iconSize,\n reducedMotion,\n colors,\n navigateHint,\n onPress,\n}: NavBarLinkProps): React.ReactElement => {\n const [hovered, setHovered] = useState(false);\n const [focused, setFocused] = useState(false);\n\n const isHovered = hovered && !isActive;\n const textColor = isActive ? TEXT_ON_PRIMARY : isHovered ? colors.hoverText : colors.rest;\n\n // Only the pill BACKGROUND changes per state — the ~8px rounding comes from the\n // base `styles.link` so the hover + active pills share the same rounded shape.\n const pillStyle: ViewStyle | undefined = isActive\n ? { backgroundColor: colors.activeBg }\n : isHovered\n ? { backgroundColor: colors.hoverBg }\n : undefined;\n\n return (\n <Pressable\n accessibilityHint={navigateHint(item.label)}\n accessibilityLabel={item.label}\n accessibilityRole=\"link\"\n accessibilityState={{ selected: isActive }}\n style={[\n styles.link,\n collapsed ? styles.linkStacked : undefined,\n pillStyle,\n hoverTransitionStyle(reducedMotion),\n focusRingStyle(focused, colors.ring),\n ]}\n testID={item.testID ?? item.key}\n onBlur={() => setFocused(false)}\n onFocus={() => setFocused(true)}\n onHoverIn={() => setHovered(true)}\n onHoverOut={() => setHovered(false)}\n onPress={() => onPress(item.route)}\n {...ariaCurrentProps(isActive)}\n >\n {typeof item.renderIcon === 'function' ? (\n <View style={styles.linkIcon}>{item.renderIcon(textColor, iconSize)}</View>\n ) : null}\n <Text style={[styles.linkText, { color: textColor }]}>{item.label}</Text>\n </Pressable>\n );\n};\n\nexport default NavBarLink;\n","/**\n * NavOverflowMenu — the \"More ▾\" trigger + dropdown that holds the `NavBar` items\n * which don't fit inline (the priority+ overflow set).\n *\n * It REUSES the shared `@dloizides/ui-layout` `ModalDropdown` — the exact component\n * every other menu in the app uses — so the overflow menu is portalled, keyboard\n * navigable, dismissed on outside-click / Escape, and opens on click, looking\n * identical to the rest of the app's menus. The overflow entries are the same\n * `NavItem`s (label + route + active state); selecting one navigates via the same\n * `onNavigate` the inline links use.\n *\n * The trigger is a rounded pill matching a `NavBarLink`: muted at rest, and — when\n * the ACTIVE route lives in the overflow set — it wears the accent pill so the\n * active item stays visibly reachable behind the \"…\". The dropdown marks that same\n * item selected (its `value` is the active overflow route). a11y: `ModalDropdown`\n * owns the trigger's `role=\"button\"` + `aria-expanded` + caller-supplied label/hint,\n * and gives the options keyboard navigation.\n *\n * Contract discipline (as the rest of `@dloizides/ui-nav`): no FM / router / icon\n * set / store; the label + hint are pre-localized strings from the caller and every\n * colour comes from the theme (via the `NavBarLinkColors` the `NavBar` computed).\n */\nimport React, { useMemo } from 'react';\n\nimport { Text, View } from 'react-native';\n\nimport { ModalDropdown, type DropdownVariant } from '@dloizides/ui-layout';\n\nimport { isRouteActive } from './isRouteActive';\nimport type { NavBarLinkColors } from './NavBarLink';\nimport { navBarStyles as styles } from './styles';\nimport type { NavItem } from './types';\n\n/** Ink for the trigger while it wears the active accent pill — full-contrast white. */\nconst TEXT_ON_PRIMARY = '#ffffff';\n/** No overflow item is active → a value that matches no option (nothing selected). */\nconst NO_ACTIVE_ROUTE = '';\n\nexport interface NavOverflowMenuProps {\n /** The items that spilled out of the inline row. */\n items: NavItem[];\n /** Current active route/path — decides the active-pill + selected option. */\n pathname: string;\n /** Navigation callback — receives the chosen item's `route`. */\n onNavigate: (route: string) => void;\n /** Theme-resolved link colours (same set the inline links use). */\n colors: NavBarLinkColors;\n /** Localized visible + accessible label for the trigger (e.g. \"More\"). */\n label: string;\n /** Localized accessibility hint for the trigger. */\n hint: string;\n /** testID for the trigger (options default to `` `${testID}-option-${route}` ``). */\n testID: string;\n /** Force a dropdown variant (default: responsive — inline menu on desktop). */\n variant?: DropdownVariant;\n}\n\nexport const NavOverflowMenu = ({\n items,\n pathname,\n onNavigate,\n colors,\n label,\n hint,\n testID,\n variant,\n}: NavOverflowMenuProps): React.ReactElement => {\n const options = useMemo(() => items.map((item) => ({ label: item.label, value: item.route })), [items]);\n const activeRoute = useMemo(\n () => items.find((item) => isRouteActive(pathname, item.route))?.route ?? NO_ACTIVE_ROUTE,\n [items, pathname],\n );\n const optionTestID = useMemo(() => {\n const byRoute = new Map(items.map((item) => [item.route, item.testID ?? item.key]));\n return (route: string): string => byRoute.get(route) ?? `${testID}-option-${route}`;\n }, [items, testID]);\n\n const hasActive = activeRoute !== NO_ACTIVE_ROUTE;\n const textColor = hasActive ? TEXT_ON_PRIMARY : colors.rest;\n const pillStyle = hasActive ? { backgroundColor: colors.activeBg } : undefined;\n\n return (\n <ModalDropdown<string>\n accessibilityHint={hint}\n accessibilityLabel={label}\n optionTestID={optionTestID}\n options={options}\n testID={testID}\n value={activeRoute}\n variant={variant}\n onChange={onNavigate}\n renderTrigger={({ isOpen }) => (\n <View style={[styles.link, styles.overflowTrigger, pillStyle]}>\n <Text style={[styles.linkText, { color: textColor }]}>{label}</Text>\n <Text style={[styles.overflowChevron, { color: textColor }]}>{isOpen ? '▴' : '▾'}</Text>\n </View>\n )}\n />\n );\n};\n\nexport default NavOverflowMenu;\n","/**\n * Priority+ (\"overflow menu\") fit computation for the horizontal `NavBar`.\n *\n * Pure + framework-free so it can be unit-tested directly: given the available\n * width of the inline links row, the measured natural width of each nav item, and\n * the width of the overflow (\"More ▾\") trigger, it returns how many of the LEADING\n * items fit inline on a single row. Any items beyond the returned count spill into\n * the overflow dropdown.\n *\n * Graceful degradation: it returns `itemWidths.length` (everything inline, no\n * overflow trigger) whenever measurements are not ready yet — `availableWidth <= 0`\n * or any item width `<= 0` — so a first paint before layout resolves (and jsdom /\n * SSR, where there is no layout) shows every item rather than flashing a truncated\n * row. It also returns the full count when every item already fits without a trigger.\n */\nexport interface OverflowMeasurements {\n /** Width available for the inline links row (the flex space between brand + right). */\n availableWidth: number;\n /** Natural pixel width of each nav item, in item order. */\n itemWidths: number[];\n /** Natural pixel width of the overflow (\"More\") trigger. */\n moreWidth: number;\n /** Horizontal gap (px) between adjacent inline items (the row's `columnGap`). */\n gap: number;\n}\n\nfunction sum(values: number[]): number {\n return values.reduce((acc, value) => acc + value, 0);\n}\n\nexport function computeVisibleCount({ availableWidth, itemWidths, moreWidth, gap }: OverflowMeasurements): number {\n const total = itemWidths.length;\n if (total === 0) return 0;\n\n // Unmeasured (pre-layout / SSR / jsdom) → show everything; never truncate before\n // the row has actually been measured, which would flash items in and back out.\n if (availableWidth <= 0 || itemWidths.some((width) => width <= 0)) return total;\n\n // Does the FULL row fit with no overflow trigger at all? Gaps sit BETWEEN items,\n // so `total` items carry `total - 1` gaps.\n const fullRowWidth = sum(itemWidths) + gap * (total - 1);\n if (fullRowWidth <= availableWidth) return total;\n\n // Overflow is needed: reserve room for the More trigger (plus the gap before it)\n // and greedily fit the leading items. `used` grows by each item plus the gap that\n // precedes it (every item after the first).\n const reservedForMore = moreWidth + gap;\n let used = 0;\n let count = 0;\n for (let index = 0; index < total; index += 1) {\n const width = itemWidths[index] ?? 0;\n const withGap = used + (count > 0 ? gap : 0) + width;\n if (withGap + reservedForMore > availableWidth) break;\n used = withGap;\n count += 1;\n }\n return count;\n}\n","/**\n * `useNavOverflow` — the measurement state behind the `NavBar` priority+ overflow.\n *\n * It owns the measured widths (available row width, each item's natural width, the\n * \"More\" trigger width) and derives, via the pure {@link computeVisibleCount}, how\n * many leading items fit inline. The actual measuring is done by the caller wiring\n * RN's `onLayout` (react-native-web backs it with a `ResizeObserver`, so it re-fires\n * on resize — no manual `window` access, SSR-safe) into the setters returned here.\n *\n * Widths are cached per item index: an item measured while inline keeps its width\n * after it spills into the overflow menu (its content width does not change), so a\n * resize narrower reuses the cached width and a resize wider brings it back inline\n * and re-measures (a no-op). When the item COUNT changes the buffer is reset to\n * unmeasured (0), so `computeVisibleCount` shows every item until the new row is\n * measured again.\n */\nimport { useCallback, useEffect, useMemo, useState } from 'react';\n\nimport { computeVisibleCount } from './computeVisibleCount';\n\nexport interface NavOverflowState {\n /** How many leading items to render inline; the rest go into the overflow menu. */\n visibleCount: number;\n /** Wire to the links row's `onLayout` (its resolved flex width = available space). */\n setAvailableWidth: (width: number) => void;\n /** Wire to item `index`'s `onLayout` to record its natural width. */\n setItemWidth: (index: number, width: number) => void;\n /** Wire to the overflow (\"More\") trigger's `onLayout`. */\n setMoreWidth: (width: number) => void;\n}\n\nfunction resizeWidthBuffer(previous: number[], count: number): number[] {\n const next = new Array<number>(count).fill(0);\n const shared = Math.min(previous.length, count);\n for (let index = 0; index < shared; index += 1) next[index] = previous[index] ?? 0;\n return next;\n}\n\nexport function useNavOverflow(itemCount: number, gap: number): NavOverflowState {\n const [availableWidth, setAvailableWidthState] = useState(0);\n const [moreWidth, setMoreWidthState] = useState(0);\n const [itemWidths, setItemWidths] = useState<number[]>(() => new Array<number>(itemCount).fill(0));\n\n // Item count changed (items added / removed) → reset to unmeasured so we show all\n // and re-measure, preserving any still-valid leading widths.\n useEffect(() => {\n setItemWidths((previous) => (previous.length === itemCount ? previous : resizeWidthBuffer(previous, itemCount)));\n }, [itemCount]);\n\n const setItemWidth = useCallback((index: number, width: number) => {\n setItemWidths((previous) => {\n if (index < 0 || index >= previous.length || previous[index] === width) return previous;\n const next = previous.slice();\n next[index] = width;\n return next;\n });\n }, []);\n\n const setAvailableWidth = useCallback(\n (width: number) => setAvailableWidthState((previous) => (previous === width ? previous : width)),\n [],\n );\n const setMoreWidth = useCallback(\n (width: number) => setMoreWidthState((previous) => (previous === width ? previous : width)),\n [],\n );\n\n const visibleCount = useMemo(\n () => computeVisibleCount({ availableWidth, itemWidths, moreWidth, gap }),\n [availableWidth, itemWidths, moreWidth, gap],\n );\n\n return { visibleCount, setAvailableWidth, setItemWidth, setMoreWidth };\n}\n","/**\n * `useReducedMotion` — `true` when the user has asked the OS/browser to minimise\n * motion (`prefers-reduced-motion: reduce`). It is a WEB-only signal read from\n * `window.matchMedia`; on native (no `matchMedia`) it is always `false`. The\n * `NavBar` uses it to drop the hover-pill CSS transition for motion-sensitive\n * users. Cheap: one media-query subscription, no JS animation.\n */\nimport { useEffect, useState } from 'react';\n\nconst REDUCED_MOTION_QUERY = '(prefers-reduced-motion: reduce)';\n\n/** The slice of `MediaQueryList` we rely on — kept minimal so native builds needn't provide it. */\ninterface MediaQueryListLike {\n matches: boolean;\n addEventListener?: (type: 'change', listener: () => void) => void;\n removeEventListener?: (type: 'change', listener: () => void) => void;\n}\n\n/** Resolve the reduced-motion media query on web; `undefined` where `matchMedia` is unavailable. */\nfunction getReducedMotionQuery(): MediaQueryListLike | undefined {\n if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return undefined;\n return window.matchMedia(REDUCED_MOTION_QUERY);\n}\n\nexport function useReducedMotion(): boolean {\n const [reduced, setReduced] = useState<boolean>(() => getReducedMotionQuery()?.matches ?? false);\n\n useEffect(() => {\n const mql = getReducedMotionQuery();\n if (mql === undefined || mql.addEventListener === undefined) return undefined;\n const onChange = (): void => setReduced(mql.matches);\n mql.addEventListener('change', onChange);\n return () => {\n mql.removeEventListener?.('change', onChange);\n };\n }, []);\n\n return reduced;\n}\n\nexport default useReducedMotion;\n","/**\r\n * NavBar — the config-driven HORIZONTAL top navigation bar. It is the top-bar\r\n * counterpart to `Sidebar`: it renders the SAME caller-supplied `NavItem[]`\r\n * (already role-filtered / localized by the app) as inline links across the top\r\n * instead of a left rail, with an optional brand slot on the left and a free-form\r\n * right slot (auth link / user / logout). Below a configurable breakpoint it\r\n * collapses the links behind a hamburger toggle — mirroring the v1 AML console's\r\n * responsive `.global-nav`.\r\n *\r\n * Look + feel: each link is a rounded-pill target with the v1 `.gn-links a`\r\n * affordance — muted at rest, brightening text + a subtle pill background on\r\n * HOVER, and a solid accent pill when ACTIVE. All colours are THEME-DRIVEN from\r\n * the `@dloizides/ui-feedback` UiProvider (rest=`textSecondary`, hover text=`text`,\r\n * hover bg=`surfaceElevated`, active=`palette.primary`, ring=`palette.primary`).\r\n * Hover/focus are web-only (react-native-web); native stays at the rest style.\r\n *\r\n * Overflow (\"…\" priority+ menu). Above the `collapseBelow` breakpoint the links sit\r\n * on ONE row; when they don't all fit, a measure pass ({@link useNavOverflow} +\r\n * {@link computeVisibleCount}) keeps the leading items that fit inline and collapses\r\n * the rest behind a \"More ▾\" trigger — the shared `ModalDropdown` (see\r\n * {@link NavOverflowMenu}) — so no item is ever cut off. BELOW `collapseBelow` the\r\n * whole set still collapses into the responsive hamburger drawer (all items stacked),\r\n * so the two mechanisms don't overlap: hamburger for true mobile, \"…\" for the\r\n * in-between desktop case where only SOME items spill.\r\n *\r\n * Contract discipline (same as the rest of `@dloizides/ui-nav`): NO FM, router,\r\n * icon set, or store imports. Labels are pre-localized strings, icons are render\r\n * slots, and every colour is read from the theme. This is purely additive —\r\n * `Sidebar`/`Topbar` are unchanged and the new overflow labels are optional.\r\n */\r\nimport React, { useCallback, useMemo, useState } from 'react';\r\n\r\nimport {\r\n Pressable,\r\n Text,\r\n useWindowDimensions,\r\n View,\r\n type LayoutChangeEvent,\r\n type PressableProps,\r\n type ViewStyle,\r\n} from 'react-native';\r\n\r\nimport { useUi, UiProvider, type UiTheme } from '@dloizides/ui-feedback';\r\n\r\nimport { NAV_TEST_IDS } from './constants';\r\nimport { isRouteActive } from './isRouteActive';\r\nimport { NavBarLink, type NavBarLinkColors } from './NavBarLink';\r\nimport { NavOverflowMenu } from './NavOverflowMenu';\r\nimport { navBarStyles as styles, NAV_ICON_SIZE, NAV_LINK_GAP } from './styles';\r\nimport type { NavItem } from './types';\r\nimport { useNavOverflow } from './useNavOverflow';\r\nimport { useReducedMotion } from './useReducedMotion';\r\nimport { focusRingStyle } from './webStyle';\r\nimport { renderTextSlot } from './textSlot';\r\n\r\n/** DOM id linking the toggle (`aria-controls`) to the collapsible links region. */\r\nconst LINKS_REGION_ID = 'navbar-links-region';\r\n/** Collapse to a hamburger at/under this viewport width (matches v1's 760px). */\r\nconst DEFAULT_COLLAPSE_BELOW = 760;\r\n/** Default hamburger glyph (☰) when no `renderMenuIcon` is supplied. */\r\nconst MENU_GLYPH = '☰';\r\n\r\nexport interface NavBarProps {\r\n /** Nav entries — already role-filtered / grouped by the app. */\r\n items: NavItem[];\r\n /** Current active route/path. */\r\n pathname: string;\r\n /** Navigation callback — receives a `NavItem.route`. */\r\n onNavigate: (route: string) => void;\r\n /** Localized accessibility label for the navigation landmark. */\r\n regionLabel: string;\r\n /** a11y hint for a link, given its label. Defaults to the label. */\r\n navigateHint?: (label: string) => string;\r\n /** Left slot — typically the brand / tenant logo. */\r\n brand?: React.ReactNode;\r\n /** Right slot — free-form (auth link, user block, logout). */\r\n right?: React.ReactNode;\r\n /** Localized accessibility label for the responsive menu toggle. */\r\n menuLabel?: string;\r\n /** Localized accessibility hint for the responsive menu toggle. */\r\n menuHint?: string;\r\n /** Optional custom glyph renderer for the toggle; defaults to ☰. */\r\n renderMenuIcon?: (color: string, open: boolean) => React.ReactNode;\r\n /** Collapse the links behind a hamburger below this viewport width (default 760). */\r\n collapseBelow?: number;\r\n /**\r\n * Localized visible + accessible label for the \"More ▾\" overflow trigger shown when\r\n * the inline links don't all fit on one row (priority+ menu). Defaults to `\"More\"`.\r\n */\r\n overflowLabel?: string;\r\n /** Localized accessibility hint for the overflow trigger. */\r\n overflowHint?: string;\r\n /** Extra container style overrides. */\r\n containerStyle?: ViewStyle | ViewStyle[];\r\n /**\r\n * Optional content-column cap (px). When set, the OUTER container — which carries\r\n * the background + bottom border (`barTheme`/theme surface + any `containerStyle`,\r\n * e.g. the AML radial-glow appbar) — stays FULL WIDTH (full-bleed), while the INNER\r\n * row (brand + links + right) is capped to this width and centred. Omit for the\r\n * default where the inner spans the full container. The priority+ overflow \"…\" fit\r\n * measures the (now capped) inner's rendered width via `onLayout`, so it keeps\r\n * working against the capped column, not the full-bleed container.\r\n */\r\n contentMaxWidth?: number;\r\n /**\r\n * Optional CHROME theme override — re-provisions the `@dloizides/ui-feedback`\r\n * theme for the bar ONLY, so the top bar can be dark while the page below keeps\r\n * the light workspace theme (the AML v1-console \"dark appbar over light content\"\r\n * pattern). The live `t` (+ `navigate`) from the surrounding provider are\r\n * re-passed, so nav labels keep localizing. Omit for a bar that shares the page\r\n * theme. Style-only: every colour still flows through the theme — no per-app fork.\r\n */\r\n barTheme?: UiTheme;\r\n}\r\n\r\n/**\r\n * `aria-controls` links the toggle to the collapsible links region. RN's prop\r\n * types omit `aria-controls`, but react-native-web forwards `aria-*` to the DOM —\r\n * so we attach it (no `any`).\r\n */\r\nfunction ariaControlsProps(id: string): PressableProps & { 'aria-controls'?: string } {\r\n return { 'aria-controls': id };\r\n}\r\n\r\nconst NavBarInner = ({\r\n items,\r\n pathname,\r\n onNavigate,\r\n regionLabel,\r\n navigateHint = (label) => label,\r\n brand,\r\n right,\r\n menuLabel = 'Menu',\r\n menuHint = '',\r\n renderMenuIcon,\r\n collapseBelow = DEFAULT_COLLAPSE_BELOW,\r\n overflowLabel = 'More',\r\n overflowHint = '',\r\n containerStyle,\r\n contentMaxWidth,\r\n}: Omit<NavBarProps, 'barTheme'>): React.ReactElement => {\r\n const { theme } = useUi();\r\n const colors = theme.colors;\r\n const primaryColor = theme.palette.primary['500'];\r\n const { width } = useWindowDimensions();\r\n const reducedMotion = useReducedMotion();\r\n const [open, setOpen] = useState(false);\r\n const [toggleFocused, setToggleFocused] = useState(false);\r\n const { visibleCount, setAvailableWidth, setItemWidth, setMoreWidth } = useNavOverflow(items.length, NAV_LINK_GAP);\r\n\r\n const collapsed = width < collapseBelow;\r\n const showLinks = !collapsed || open;\r\n\r\n // Content-column cap: keep the OUTER container full-bleed (its background + bottom\r\n // border span the viewport) and cap only the INNER row, centred. Omitted ⇒ null ⇒\r\n // the inner spans the full container (unchanged). The overflow \"…\" fit still measures\r\n // the inner's rendered width, so it reasons about the capped column, not the container.\r\n const innerCapStyle = useMemo<ViewStyle | null>(\r\n () => (contentMaxWidth === undefined ? null : { maxWidth: contentMaxWidth, width: '100%', alignSelf: 'center' }),\r\n [contentMaxWidth],\r\n );\r\n\r\n const toggleMenu = useCallback(() => setOpen((v) => !v), []);\r\n const handlePress = useCallback(\r\n (route: string) => {\r\n setOpen(false);\r\n onNavigate(route);\r\n },\r\n [onNavigate],\r\n );\r\n\r\n // Theme-driven link colours (v1 `.gn-links a`): muted → brightened-on-hover text,\r\n // a subtle raised pill on hover, the accent pill when active, accent focus ring.\r\n const linkColors = useMemo<NavBarLinkColors>(\r\n () => ({\r\n rest: colors.textSecondary,\r\n hoverText: colors.text,\r\n hoverBg: colors.surfaceElevated,\r\n activeBg: primaryColor,\r\n ring: primaryColor,\r\n }),\r\n [colors.textSecondary, colors.text, colors.surfaceElevated, primaryColor],\r\n );\r\n\r\n return (\r\n <View\r\n accessibilityRole=\"none\"\r\n aria-label={regionLabel}\r\n role=\"navigation\"\r\n style={[\r\n styles.container,\r\n { backgroundColor: colors.surface, borderBottomColor: colors.border },\r\n containerStyle,\r\n ]}\r\n >\r\n <View style={[styles.inner, collapsed ? null : styles.innerNoWrap, innerCapStyle]}>\r\n {brand !== undefined ? (\r\n <View style={styles.brand}>{renderTextSlot(brand, { color: colors.text })}</View>\r\n ) : null}\r\n\r\n {collapsed ? (\r\n <Pressable\r\n accessibilityHint={menuHint}\r\n accessibilityLabel={menuLabel}\r\n accessibilityRole=\"button\"\r\n accessibilityState={{ expanded: open }}\r\n aria-expanded={open}\r\n style={[styles.toggle, focusRingStyle(toggleFocused, primaryColor)]}\r\n testID={NAV_TEST_IDS.navBarToggle}\r\n onBlur={() => setToggleFocused(false)}\r\n onFocus={() => setToggleFocused(true)}\r\n onPress={toggleMenu}\r\n {...ariaControlsProps(LINKS_REGION_ID)}\r\n >\r\n {typeof renderMenuIcon === 'function' ? (\r\n renderMenuIcon(colors.text, open)\r\n ) : (\r\n <Text style={[styles.toggleGlyph, { color: colors.text }]}>{MENU_GLYPH}</Text>\r\n )}\r\n </Pressable>\r\n ) : null}\r\n\r\n {showLinks\r\n ? (() => {\r\n const renderLink = (item: NavItem): React.ReactElement => (\r\n <NavBarLink\r\n collapsed={collapsed}\r\n colors={linkColors}\r\n iconSize={NAV_ICON_SIZE}\r\n isActive={isRouteActive(pathname, item.route)}\r\n item={item}\r\n navigateHint={navigateHint}\r\n reducedMotion={reducedMotion}\r\n onPress={handlePress}\r\n />\r\n );\r\n // Collapsed (mobile): every item stacks vertically on its own full-width line — the\r\n // responsive hamburger drawer. No overflow menu here; the drawer already holds them all.\r\n if (collapsed) {\r\n return (\r\n <View nativeID={LINKS_REGION_ID} style={styles.linksStacked} testID={NAV_TEST_IDS.navBarLinks}>\r\n {items.map((item) => (\r\n <React.Fragment key={item.key}>{renderLink(item)}</React.Fragment>\r\n ))}\r\n </View>\r\n );\r\n }\r\n // Expanded (desktop): ONE non-wrapping row. A measure pass keeps the leading items\r\n // that fit inline and collapses the rest behind the \"More ▾\" overflow trigger. Each\r\n // inline cell reports its natural width via onLayout; the row reports the available\r\n // width. Until measured, every item shows (computeVisibleCount returns the full count).\r\n const visibleItems = items.slice(0, visibleCount);\r\n const overflowItems = items.slice(visibleCount);\r\n return (\r\n <View\r\n nativeID={LINKS_REGION_ID}\r\n style={styles.linksRow}\r\n testID={NAV_TEST_IDS.navBarLinks}\r\n onLayout={(event: LayoutChangeEvent) => setAvailableWidth(event.nativeEvent.layout.width)}\r\n >\r\n {visibleItems.map((item, index) => (\r\n <View\r\n key={item.key}\r\n style={styles.linkCell}\r\n onLayout={(event: LayoutChangeEvent) => setItemWidth(index, event.nativeEvent.layout.width)}\r\n >\r\n {renderLink(item)}\r\n </View>\r\n ))}\r\n {overflowItems.length > 0 ? (\r\n <View\r\n style={styles.linkCell}\r\n onLayout={(event: LayoutChangeEvent) => setMoreWidth(event.nativeEvent.layout.width)}\r\n >\r\n <NavOverflowMenu\r\n colors={linkColors}\r\n hint={overflowHint}\r\n items={overflowItems}\r\n label={overflowLabel}\r\n pathname={pathname}\r\n testID={NAV_TEST_IDS.navBarOverflow}\r\n onNavigate={handlePress}\r\n />\r\n </View>\r\n ) : null}\r\n </View>\r\n );\r\n })()\r\n : null}\r\n\r\n {showLinks && right !== undefined ? (\r\n <View style={collapsed ? styles.rightStacked : styles.right}>\r\n {renderTextSlot(right, { color: colors.text })}\r\n </View>\r\n ) : null}\r\n </View>\r\n </View>\r\n );\r\n};\r\n\r\n/**\r\n * `NavBar` — the horizontal top bar. When `barTheme` is supplied it re-provisions\r\n * the `@dloizides/ui-feedback` theme around the bar (dark bar over a light page),\r\n * re-passing the live `t` / `navigate` so labels keep localizing; otherwise it\r\n * renders directly against the surrounding theme (byte-identical to before).\r\n */\r\nexport const NavBar = ({ barTheme, ...props }: NavBarProps): React.ReactElement => {\r\n const { t, navigate } = useUi();\r\n if (barTheme === undefined) return <NavBarInner {...props} />;\r\n return (\r\n <UiProvider navigate={navigate} t={t} theme={barTheme}>\r\n <NavBarInner {...props} />\r\n </UiProvider>\r\n );\r\n};\r\n\r\nexport { isRouteActive };\r\nexport default NavBar;\r\n","/**\n * `Nav` — ONE component that renders EITHER the horizontal top bar (`NavBar`) or the\n * vertical rail (`Sidebar`) from the same `NavItem[]`, chosen by a single\n * `orientation` prop. It lets an app flip its navigation between a top bar and a side\n * menu without swapping components or re-plumbing props:\n *\n * <Nav orientation=\"horizontal\" items={items} pathname={p} onNavigate={go} .../> // NavBar\n * <Nav orientation=\"vertical\" items={items} pathname={p} onNavigate={go} .../> // Sidebar\n *\n * `orientation` defaults to `\"horizontal\"`. The remaining props are exactly the\n * delegate's props — a discriminated union — so TypeScript enforces the right prop\n * set per orientation (e.g. `title` is required only for the vertical/Sidebar side,\n * `collapseBelow` / `overflowLabel` only for the horizontal/NavBar side).\n *\n * `Nav` is purely additive: `NavBar` and `Sidebar` remain exported and unchanged, so\n * every existing consumer (erevna / katalogos / kefi / agora) is untouched. Vertical\n * navigation is the existing Sidebar — stacked links that scroll vertically, so it\n * needs no overflow menu; the priority+ \"…\" overflow is a horizontal-bar concern.\n */\nimport React from 'react';\n\nimport { NavBar, type NavBarProps } from './NavBar';\nimport { Sidebar, type SidebarProps } from './Sidebar';\n\n/** Which axis the navigation renders on. */\nexport type NavOrientation = 'horizontal' | 'vertical';\n\nexport type NavProps =\n | ({ orientation?: 'horizontal' } & NavBarProps)\n | ({ orientation: 'vertical' } & SidebarProps);\n\nexport const Nav = (props: NavProps): React.ReactElement => {\n // `orientation` is only the discriminant; the delegates (`Sidebar` / `NavBar`)\n // read their own known props and ignore the extra field, so the whole narrowed\n // props object can be spread straight through (a JSX spread is not excess-checked).\n if (props.orientation === 'vertical') {\n return <Sidebar {...props} />;\n }\n return <NavBar {...props} />;\n};\n\nexport default Nav;\n","/**\n * AppShell content-body helpers — the page-state cards (loading / error /\n * forbidden) and the precedence rule that picks what renders inside the content\n * column. Split out of `AppShell` so the shell file stays focused on layout /\n * responsive composition. Colours are routed through the `@dloizides/ui-feedback`\n * theme, same as the rest of `@dloizides/ui-nav`.\n */\nimport React from 'react';\n\nimport { ActivityIndicator, StyleSheet, Text, View } from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\n\nimport { APP_SHELL_SUFFIX } from './constants';\n\nconst CARD_PADDING = 20;\nconst CARD_BORDER_RADIUS = 12;\nconst CARD_BORDER_WIDTH = 1;\nconst CARD_TITLE_FONT_SIZE = 16;\nconst CARD_MESSAGE_FONT_SIZE = 14;\nconst CARD_TITLE_MARGIN_BOTTOM = 8;\n\nconst styles = StyleSheet.create({\n centerFill: { flex: 1, justifyContent: 'center', alignItems: 'center' },\n card: {\n padding: CARD_PADDING,\n borderRadius: CARD_BORDER_RADIUS,\n borderWidth: CARD_BORDER_WIDTH,\n },\n cardTitle: { fontSize: CARD_TITLE_FONT_SIZE, fontWeight: '700', marginBottom: CARD_TITLE_MARGIN_BOTTOM },\n cardMessage: { fontSize: CARD_MESSAGE_FONT_SIZE },\n});\n\n/** A titled message card (error / forbidden). Colours come from the theme. */\nexport interface ShellMessage {\n titleText: string;\n messageText: string;\n}\n\n/** Page-state model — a loading spinner card, or a titled error / forbidden card. */\nexport interface ShellState {\n loading?: boolean;\n error?: ShellMessage | null;\n forbidden?: ShellMessage | null;\n}\n\nfunction MessageCard({\n message,\n accentColor,\n testID,\n}: {\n message: ShellMessage;\n accentColor: string;\n testID: string;\n}): React.ReactElement {\n const { theme } = useUi();\n const colors = theme.colors;\n return (\n <View style={[styles.card, { backgroundColor: colors.surface, borderColor: accentColor }]} testID={testID}>\n <Text style={[styles.cardTitle, { color: accentColor }]}>{message.titleText}</Text>\n <Text style={[styles.cardMessage, { color: colors.textSecondary }]}>{message.messageText}</Text>\n </View>\n );\n}\n\n/** Pick what renders inside the content column, honouring state precedence. */\nexport function useContentBody(\n state: ShellState | undefined,\n children: React.ReactNode,\n testID: string,\n): React.ReactNode {\n const { theme } = useUi();\n const primary = theme.palette.primary['500'];\n const errorColor = theme.semantic.error['500'];\n\n if (state?.forbidden)\n return <MessageCard accentColor={errorColor} message={state.forbidden} testID={`${testID}${APP_SHELL_SUFFIX.forbidden}`} />;\n if (state?.error)\n return <MessageCard accentColor={errorColor} message={state.error} testID={`${testID}${APP_SHELL_SUFFIX.error}`} />;\n if (state?.loading === true)\n return (\n <View style={styles.centerFill} testID={`${testID}${APP_SHELL_SUFFIX.loading}`}>\n <ActivityIndicator color={primary} size=\"large\" />\n </View>\n );\n return children;\n}\n","/**\r\n * MobileDrawer — the below-the-breakpoint face of `AppShell`'s back-office\r\n * `sidebar` layout. On a narrow viewport (<768px) the persistent left rail would\r\n * starve the content column, so instead of the rail we render a hamburger toggle\r\n * (`MenuToggle`) in the header and slide the same `Sidebar` in as an overlay\r\n * drawer (a scrim + a left panel). The drawer closes on a scrim tap and on any\r\n * nav-item press inside the panel (web: a bubbled click on a `role=\"button\"` /\r\n * link element). Desktop is untouched — AppShell never mounts this above 768px.\r\n *\r\n * Contract discipline (same as the rest of `@dloizides/ui-nav`): NO FM / router /\r\n * store imports. Labels are pre-localized strings (English defaults, overridable\r\n * by the consumer via `AppShell`'s `mobileMenu` prop); every colour is read from\r\n * the `@dloizides/ui-feedback` UiProvider theme.\r\n */\r\nimport React, { useEffect, useRef } from 'react';\r\n\r\nimport { Pressable, StyleSheet, Text, View } from 'react-native';\r\n\r\nimport { useUi } from '@dloizides/ui-feedback';\r\n\r\nimport { FocusableTouchable } from './FocusableTouchable';\r\nimport { renderTextSlot } from './textSlot';\r\n\r\n/** Collapse the persistent rail into a drawer at/under this viewport width. */\r\nexport const MOBILE_BREAKPOINT = 768;\r\n\r\nconst SCRIM_COLOR = 'rgba(0, 0, 0, 0.5)';\r\nconst MENU_GLYPH = '☰';\r\nconst MENU_MIN_TARGET = 44;\r\nconst MENU_GLYPH_FONT_SIZE = 20;\r\nconst MENU_TOGGLE_PADDING = 12;\r\nconst DRAWER_Z_INDEX = 50;\r\n/**\r\n * Fixed width (px) of the sliding drawer panel. It must be > 0 and anchored so the\r\n * scrim can sit BESIDE it (see below): a panel with no width — the pre-1.10.2 bug —\r\n * establishes no hit area, and a full-bleed scrim then swallowed every nav tap.\r\n */\r\nconst DRAWER_WIDTH = 280;\r\n/**\r\n * The panel stacks ABOVE the scrim within the overlay. Equal zIndex (both 0, the\r\n * old geometry) left react-native-web to break the tie by DOM order — unreliable\r\n * for pointer capture, which is how the full-bleed scrim intercepted panel presses.\r\n */\r\nconst SCRIM_Z_INDEX = 1;\r\nconst PANEL_Z_INDEX = 2;\r\n/**\r\n * A nav element that, when clicked inside the open drawer, should close it.\r\n * react-native-web maps `accessibilityRole` -> the DOM `role`, so the Sidebar's\r\n * leaf `TouchableOpacity`s render as `role=\"button\"` and match here.\r\n */\r\nconst NAV_ACTIVATABLE_SELECTOR = 'a, [role=\"button\"], [role=\"link\"]';\r\n/**\r\n * An expandable GROUP HEADER is also a `role=\"button\"` (see `NavExpandableItem`),\r\n * but its press only TOGGLES the section — it does not navigate — so the drawer\r\n * must stay open. A toggle carries `aria-expanded` (from `accessibilityState.\r\n * expanded`); a navigating leaf never does. So we treat a click whose closest\r\n * activatable is (or is inside) an `aria-expanded` element as a toggle, not a\r\n * navigation, and leave the drawer open. Without this, tapping a group to expand\r\n * it dismissed the whole drawer (the 1.11.0 grouped-nav regression).\r\n */\r\nconst NAV_TOGGLE_SELECTOR = '[aria-expanded]';\r\n\r\n/**\r\n * Run `close` on the NEXT macrotask rather than synchronously. See the load-bearing\r\n * comment on the panel's click watcher: the drawer's close must not unmount the panel\r\n * until React has finished dispatching the tapped leaf's `onPress` (the navigation)\r\n * for the CURRENT click. `setTimeout(…, 0)` yields to the browser after this click's\r\n * full dispatch (native listeners → React's synthetic listeners) completes, so the\r\n * route has changed before the panel goes away. Falls back to a synchronous call where\r\n * `setTimeout` is unavailable (non-DOM host), which is harmless — the race is web-only.\r\n */\r\nfunction deferClose(close: () => void): void {\r\n if (typeof setTimeout === 'function') setTimeout(close, 0);\r\n else close();\r\n}\r\n\r\n/** Pre-localized labels for the drawer's hamburger + scrim. */\r\nexport interface DrawerLabels {\r\n /** Accessible name of the hamburger that opens the drawer. */\r\n openLabel: string;\r\n /** Accessible hint of the hamburger that opens the drawer. */\r\n openHint: string;\r\n /** Accessible name of the scrim (tap to close). */\r\n closeLabel: string;\r\n /** Accessible hint of the scrim (tap to close). */\r\n closeHint: string;\r\n}\r\n\r\n/** English defaults — the consumer overrides these with localized strings. */\r\nexport const DEFAULT_DRAWER_LABELS: DrawerLabels = {\r\n openLabel: 'Menu',\r\n openHint: 'Open the navigation menu',\r\n closeLabel: 'Close menu',\r\n closeHint: 'Close the navigation menu',\r\n};\r\n\r\nconst styles = StyleSheet.create({\r\n overlay: { ...StyleSheet.absoluteFillObject, zIndex: DRAWER_Z_INDEX },\r\n // The scrim's tap-to-close hit area is anchored to the RIGHT of the panel\r\n // (`left: DRAWER_WIDTH`), so it NEVER overlaps the panel: nav-item taps always\r\n // reach the Sidebar's TouchableOpacity, while taps beside the drawer still close.\r\n scrim: {\r\n position: 'absolute',\r\n top: 0,\r\n bottom: 0,\r\n left: DRAWER_WIDTH,\r\n right: 0,\r\n backgroundColor: SCRIM_COLOR,\r\n zIndex: SCRIM_Z_INDEX,\r\n },\r\n // The panel gets an explicit width (a real drawer) AND a zIndex above the scrim,\r\n // so on react-native-web it — and the nav leaves inside it — sit above the scrim\r\n // and receive presses instead of the scrim swallowing them.\r\n panel: { position: 'absolute', top: 0, bottom: 0, left: 0, width: DRAWER_WIDTH, zIndex: PANEL_Z_INDEX },\r\n menuToggle: {\r\n minWidth: MENU_MIN_TARGET,\r\n minHeight: MENU_MIN_TARGET,\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n paddingHorizontal: MENU_TOGGLE_PADDING,\r\n },\r\n menuToggleGlyph: { fontSize: MENU_GLYPH_FONT_SIZE, fontWeight: '700' },\r\n});\r\n\r\nexport interface MenuToggleProps {\r\n label: string;\r\n hint: string;\r\n onOpen: () => void;\r\n testID: string;\r\n}\r\n\r\n/** The mobile hamburger button, rendered in the header region below the breakpoint. */\r\nexport const MenuToggle = ({ label, hint, onOpen, testID }: MenuToggleProps): React.ReactElement => {\r\n const { theme } = useUi();\r\n return (\r\n <FocusableTouchable\r\n accessibilityHint={hint}\r\n accessibilityLabel={label}\r\n ringColor={theme.palette.primary['500']}\r\n style={styles.menuToggle}\r\n testID={testID}\r\n onPress={onOpen}\r\n >\r\n <Text style={[styles.menuToggleGlyph, { color: theme.colors.text }]}>{MENU_GLYPH}</Text>\r\n </FocusableTouchable>\r\n );\r\n};\r\n\r\nexport interface MobileDrawerProps {\r\n /** The `Sidebar` slot to render inside the drawer panel. */\r\n sidebar: React.ReactNode;\r\n /** Pre-localized close (scrim) labels. */\r\n labels: DrawerLabels;\r\n /** Close the drawer. */\r\n onClose: () => void;\r\n /** testID for the drawer panel. */\r\n drawerTestID: string;\r\n /** testID for the scrim. */\r\n scrimTestID: string;\r\n}\r\n\r\n/** The open drawer overlay: a tap-to-close scrim + the sidebar panel. */\r\nexport const MobileDrawer = ({\r\n sidebar,\r\n labels,\r\n onClose,\r\n drawerTestID,\r\n scrimTestID,\r\n}: MobileDrawerProps): React.ReactElement => {\r\n const { theme } = useUi();\r\n const panelRef = useRef<View | null>(null);\r\n\r\n // Close on a nav-item press. The consumer wires the Sidebar's `onNavigate`\r\n // directly to the router, so we cannot intercept that callback; instead (on\r\n // web) we watch for a bubbled click on an activatable element inside the panel.\r\n //\r\n // 🔴 THE CLOSE MUST BE DEFERRED, and the defer is load-bearing — removing it\r\n // reintroduces a real, ship-blocking bug (a leaf tap dismissed the drawer WITHOUT\r\n // navigating). Why: react-native-web's `PressResponder` fires a leaf's `onPress`\r\n // from its `onClick`, dispatched through REACT's synthetic event system — whose\r\n // root listener lives on the app-root container, an ANCESTOR of this panel. This\r\n // handler is a NATIVE `addEventListener('click')` on the panel, so it fires during\r\n // the real DOM bubble BEFORE the event ever reaches React's root. If we closed\r\n // synchronously here, `setDrawerOpen(false)` would unmount the panel — tearing the\r\n // leaf out of the tree — and React would then have no leaf to dispatch `onPress`\r\n // to: the drawer vanishes and navigation never runs. Deferring the close to a\r\n // macrotask lets React finish dispatching the leaf's `onPress` (the navigation)\r\n // during THIS click; the drawer then unmounts on the next tick, after the route\r\n // has already changed. (jsdom's `fireEvent.click` + an inert `jest.fn()` onClose\r\n // never unmounts, so a unit test alone cannot catch this — see the regression test\r\n // that renders a real unmounting onClose, and the live Playwright repro.)\r\n useEffect(() => {\r\n const node = panelRef.current as unknown as HTMLElement | null;\r\n if (node === null || typeof node.addEventListener !== 'function') return undefined;\r\n const handleClick = (event: MouseEvent): void => {\r\n const target = event.target as HTMLElement | null;\r\n if (target === null) return;\r\n const activatable = target.closest(NAV_ACTIVATABLE_SELECTOR);\r\n // A group-header toggle is a `role=\"button\"` too — only a real navigation\r\n // (a leaf, never an `aria-expanded` toggle) should dismiss the drawer.\r\n const isToggle = activatable !== null && activatable.closest(NAV_TOGGLE_SELECTOR) !== null;\r\n if (activatable !== null && !isToggle) deferClose(onClose);\r\n };\r\n node.addEventListener('click', handleClick);\r\n return () => node.removeEventListener('click', handleClick);\r\n }, [onClose]);\r\n\r\n return (\r\n <View style={styles.overlay}>\r\n <Pressable\r\n accessibilityHint={labels.closeHint}\r\n accessibilityLabel={labels.closeLabel}\r\n accessibilityRole=\"button\"\r\n style={styles.scrim}\r\n testID={scrimTestID}\r\n onPress={onClose}\r\n />\r\n <View\r\n ref={panelRef}\r\n aria-modal\r\n role=\"dialog\"\r\n style={[styles.panel, { backgroundColor: theme.colors.surface }]}\r\n testID={drawerTestID}\r\n >\r\n {renderTextSlot(sidebar, { color: theme.colors.text })}\r\n </View>\r\n </View>\r\n );\r\n};\r\n\r\nexport default MobileDrawer;\r\n","/**\n * Rail responsive mode — the pure (viewport → which rail face) rule behind\n * `AppShell`'s optional THREE-tier layout, split out so it is directly\n * unit-testable.\n *\n * Two-tier (default, back-compat): a persistent full rail at/above\n * {@link RAIL_FULL_BREAKPOINT}, an overlay drawer below it. This is what every\n * existing `AppShell` `sidebar` consumer already gets.\n *\n * Three-tier (opt-in — supply a `collapsedSidebar`): a persistent full rail on\n * desktop, an intermediate persistent COLLAPSED (icon-only) rail on tablet, and\n * the overlay drawer on a phone — the erevna / katalogos responsive scheme.\n */\n\n/** At/above this viewport width the persistent FULL rail shows (two-tier boundary). */\nexport const RAIL_FULL_BREAKPOINT = 768;\n/** Default upper bound of the collapsed-rail band (full rail at/above this). */\nexport const DEFAULT_COLLAPSED_RAIL_MAX = 1024;\n\n/** Which face the rail takes at a given viewport. */\nexport type RailMode = 'none' | 'full' | 'collapsed' | 'drawer';\n\n/**\n * Viewport band in which the intermediate COLLAPSED icon-rail shows: `[min, max)`.\n * At/above `max` the full rail shows; below `min` the overlay drawer shows.\n */\nexport interface CollapsedRailRange {\n min: number;\n max: number;\n}\n\nexport interface ResolveRailModeArgs {\n viewport: number;\n /** Whether a `sidebar` (full rail) node was supplied at all. */\n hasSidebar: boolean;\n /** Whether an intermediate `collapsedSidebar` node was supplied (enables 3-tier). */\n hasCollapsed: boolean;\n /** The collapsed-rail band; only consulted in 3-tier mode. */\n range: CollapsedRailRange;\n}\n\n/**\n * Resolve the rail mode. No sidebar ⇒ `'none'`. With a `collapsedSidebar`\n * (3-tier): full at/above `range.max`, collapsed in `[range.min, range.max)`,\n * drawer below `range.min`. Without one (2-tier, unchanged): full at/above\n * {@link RAIL_FULL_BREAKPOINT}, drawer below.\n */\nexport function resolveRailMode({ viewport, hasSidebar, hasCollapsed, range }: ResolveRailModeArgs): RailMode {\n if (!hasSidebar) return 'none';\n if (hasCollapsed) {\n if (viewport >= range.max) return 'full';\n if (viewport >= range.min) return 'collapsed';\n return 'drawer';\n }\n return viewport >= RAIL_FULL_BREAKPOINT ? 'full' : 'drawer';\n}\n","/**\n * Width-discipline helper for `AppShell` (Move 1c). Split out from the component\n * so the (viewport → max-width) rule is a small, directly unit-testable pure\n * function, with a thin hook wrapper that feeds it the live viewport width.\n */\nimport { useWindowDimensions } from 'react-native';\n\n/** Content-width policy: a capped column, optionally wider past a viewport breakpoint, or full-bleed. */\nexport type AppShellWidth =\n | { max: number; wideMax?: number; wideMinViewport?: number }\n | 'full';\n\n/**\n * Resolve the content column's max width for a given viewport. `'full'` passes\n * through (no cap); an object caps at `max`, widening to `wideMax` once the\n * viewport reaches `wideMinViewport`.\n */\nexport function resolveContentMaxWidth(width: AppShellWidth, viewport: number): number | 'full' {\n if (width === 'full') return 'full';\n const wideMinViewport = width.wideMinViewport ?? Number.POSITIVE_INFINITY;\n const isWide = viewport >= wideMinViewport;\n return isWide ? (width.wideMax ?? width.max) : width.max;\n}\n\n/** Hook wrapper: resolves the content max width against the live window width. */\nexport function useContentMaxWidth(width: AppShellWidth): number | 'full' {\n const { width: viewport } = useWindowDimensions();\n return resolveContentMaxWidth(width, viewport);\n}\n","/**\r\n * AppShell — the shared dashboard-chrome composition (Move 1c). It hosts, top to\r\n * bottom: an app-supplied header (full-bleed), an optional per-app nav region, an\r\n * optional banner, and a width-disciplined scrollable content column. It also\r\n * folds in the two things every product page re-implements: an auth gate\r\n * (pending spinner / redirect-when-unauthenticated) and page state cards\r\n * (loading / error / forbidden).\r\n *\r\n * A BACK-OFFICE variant is supported via the optional `sidebar` slot (added for\r\n * Agora's merchant admin): supply a `<Sidebar>` and the body below the header /\r\n * nav / banner becomes a ROW — a persistent left rail beside the scrolling\r\n * content column — instead of the default single vertical stack. Omit `sidebar`\r\n * and the render tree is byte-identical to before, so every existing consumer\r\n * (erevna / katalogos / kefi) is untouched.\r\n *\r\n * Contract discipline (same as the rest of `@dloizides/ui-nav`): NO FM, router,\r\n * or store imports. The app passes wired elements, pre-localized strings, and\r\n * callbacks; every colour is routed through the `@dloizides/ui-feedback` theme.\r\n */\r\nimport React, { useCallback, useEffect, useState } from 'react';\r\n\r\nimport {\r\n ActivityIndicator,\r\n ScrollView,\r\n StyleSheet,\r\n useWindowDimensions,\r\n View,\r\n type ViewStyle,\r\n} from 'react-native';\r\n\r\nimport { useUi } from '@dloizides/ui-feedback';\r\n\r\nimport { useContentBody, type ShellState } from './appShellContent';\r\nimport { APP_SHELL_SUFFIX } from './constants';\r\nimport {\r\n DEFAULT_DRAWER_LABELS,\r\n MenuToggle,\r\n MobileDrawer,\r\n type DrawerLabels,\r\n} from './MobileDrawer';\r\nimport {\r\n DEFAULT_COLLAPSED_RAIL_MAX,\r\n RAIL_FULL_BREAKPOINT,\r\n resolveRailMode,\r\n type CollapsedRailRange,\r\n} from './railMode';\r\nimport { useContentMaxWidth, type AppShellWidth } from './useContentMaxWidth';\r\nimport { renderTextSlot } from './textSlot';\r\n\r\nconst DEFAULT_CONTENT_PADDING = 24;\r\n\r\nconst styles = StyleSheet.create({\r\n root: { flex: 1 },\r\n centerFill: { flex: 1, justifyContent: 'center', alignItems: 'center' },\r\n scroll: { flex: 1 },\r\n scrollContent: { flexGrow: 1 },\r\n // Mobile back-office header: the hamburger sits inline before the header slot.\r\n headerRow: { flexDirection: 'row', alignItems: 'center' },\r\n headerFill: { flex: 1 },\r\n // Back-office layout: a persistent left rail beside the scrolling content column.\r\n bodyRow: { flex: 1, flexDirection: 'row' },\r\n columnFull: { flex: 1 },\r\n columnCapped: { flex: 1, width: '100%', alignSelf: 'center' },\r\n // Non-flex variant used to cap the nav strip's inner content to the content\r\n // column so the nav aligns with the page content instead of running full-bleed.\r\n chromeCapped: { width: '100%', alignSelf: 'center' },\r\n});\r\n\r\nexport type { ShellMessage } from './appShellContent';\r\n\r\nexport interface AppShellProps {\r\n /** App-supplied wired header (Topbar / AppHeader), rendered full-bleed. */\r\n header: React.ReactNode;\r\n /** Per-app nav region (kefi coral pills / erevna sidebar+drawer). */\r\n nav?: React.ReactNode;\r\n /**\r\n * Optional persistent LEFT RAIL (a `<Sidebar>`), for back-office surfaces. When\r\n * supplied, the region below header/nav/banner lays out as a row: the rail on the\r\n * left, the scrolling content column on the right. Omit for the default vertical\r\n * stack — the tree is then byte-identical to the pre-`sidebar` AppShell.\r\n *\r\n * Responsive: at/under ~768px the persistent rail is REPLACED by a hamburger (in\r\n * the header) that opens the same `sidebar` as an overlay drawer, so the content\r\n * takes the full width. Desktop (≥768px) is unchanged. No effect without `sidebar`.\r\n */\r\n sidebar?: React.ReactNode;\r\n /**\r\n * Optional intermediate COLLAPSED (icon-only) rail — opts the `sidebar` layout\r\n * into a THREE-tier responsive scheme (erevna / katalogos): the full `sidebar`\r\n * on desktop, this collapsed rail on a tablet-width band, and the overlay drawer\r\n * (hosting the full `sidebar`) on a phone. Omit it and the layout stays the\r\n * unchanged two-tier scheme (full rail ≥768px, drawer below). No effect without\r\n * `sidebar`. Exposed as `${testID}${APP_SHELL_SUFFIX.collapsedSidebar}`.\r\n */\r\n collapsedSidebar?: React.ReactNode;\r\n /**\r\n * The viewport band `[min, max)` in which `collapsedSidebar` shows: at/above\r\n * `max` the full rail shows, below `min` the drawer shows. Defaults to\r\n * `{ min: 768, max: 1024 }`. Only consulted when `collapsedSidebar` is supplied.\r\n */\r\n collapsedRailRange?: CollapsedRailRange;\r\n /**\r\n * Pre-localized labels for the mobile nav drawer (only used in the `sidebar`\r\n * layout, below the breakpoint): the hamburger's open label/hint and the scrim's\r\n * close label/hint. Optional — English defaults apply. NO i18n in this package.\r\n */\r\n mobileMenu?: Partial<DrawerLabels>;\r\n /** Banner slot (e.g. verification-pending). */\r\n banner?: React.ReactNode;\r\n /** Content-width policy. Defaults to full-bleed. */\r\n width?: AppShellWidth;\r\n /** Content padding inside the scroll column. Defaults to 24. */\r\n contentPadding?: number;\r\n /**\r\n * Whether the nav strip aligns with the width-capped content column\r\n * (`'content'`) or runs full-bleed (`'full'`, the default). Only has an effect\r\n * when `width` caps the content. The header always renders full-bleed.\r\n */\r\n chromeAlignment?: 'full' | 'content';\r\n /** Auth gate — spinner while pending, `onRedirect` when unauthenticated. */\r\n gate?: { pending: boolean; authenticated: boolean; onRedirect: () => void };\r\n /** Page state — loading spinner card, or a titled error / forbidden card. */\r\n state?: ShellState;\r\n /** Root testID; the content region is exposed as `${testID}-content`. */\r\n testID: string;\r\n children: React.ReactNode;\r\n}\r\n\r\nexport const AppShell = ({\r\n header,\r\n nav,\r\n sidebar,\r\n collapsedSidebar,\r\n collapsedRailRange,\r\n mobileMenu,\r\n banner,\r\n width = 'full',\r\n contentPadding = DEFAULT_CONTENT_PADDING,\r\n chromeAlignment = 'full',\r\n gate,\r\n state,\r\n testID,\r\n children,\r\n}: AppShellProps): React.ReactElement | null => {\r\n const { theme } = useUi();\r\n const primary = theme.palette.primary['500'];\r\n const maxWidth = useContentMaxWidth(width);\r\n const body = useContentBody(state, children, testID);\r\n\r\n // Back-office responsive behaviour: the rail takes one of three faces by\r\n // viewport — the persistent full rail, an optional intermediate collapsed\r\n // (icon-only) rail, or an overlay drawer. Without `collapsedSidebar` this stays\r\n // the unchanged two-tier scheme (full rail ≥768px, drawer below).\r\n const { width: viewportWidth } = useWindowDimensions();\r\n const railRange: CollapsedRailRange = collapsedRailRange ?? { min: RAIL_FULL_BREAKPOINT, max: DEFAULT_COLLAPSED_RAIL_MAX };\r\n const railMode = resolveRailMode({\r\n viewport: viewportWidth,\r\n hasSidebar: sidebar !== undefined,\r\n hasCollapsed: collapsedSidebar !== undefined,\r\n range: railRange,\r\n });\r\n const useDrawer = railMode === 'drawer';\r\n const [drawerOpen, setDrawerOpen] = useState(false);\r\n const openDrawer = useCallback(() => setDrawerOpen(true), []);\r\n const closeDrawer = useCallback(() => setDrawerOpen(false), []);\r\n useEffect(() => {\r\n if (!useDrawer && drawerOpen) setDrawerOpen(false);\r\n }, [useDrawer, drawerOpen]);\r\n const drawerLabels: DrawerLabels = { ...DEFAULT_DRAWER_LABELS, ...mobileMenu };\r\n\r\n const isUnauthenticated = gate !== undefined && !gate.pending && !gate.authenticated;\r\n useEffect(() => {\r\n if (isUnauthenticated && gate !== undefined) gate.onRedirect();\r\n }, [isUnauthenticated, gate]);\r\n\r\n if (gate?.pending === true)\r\n return (\r\n <View style={[styles.root, styles.centerFill, { backgroundColor: theme.colors.background }]} testID={`${testID}${APP_SHELL_SUFFIX.pending}`}>\r\n <ActivityIndicator color={primary} size=\"large\" />\r\n </View>\r\n );\r\n\r\n if (isUnauthenticated) return null;\r\n\r\n const columnStyle: ViewStyle | ViewStyle[] =\r\n maxWidth === 'full' ? styles.columnFull : [styles.columnCapped, { maxWidth }];\r\n\r\n // Align the nav strip's inner content with the capped content column when asked\r\n // (and only when the content is actually capped); otherwise it runs full-bleed.\r\n const navInnerStyle: ViewStyle | ViewStyle[] | undefined =\r\n chromeAlignment === 'content' && maxWidth !== 'full'\r\n ? [styles.chromeCapped, { maxWidth, paddingHorizontal: contentPadding }]\r\n : undefined;\r\n\r\n const scroller = (\r\n <ScrollView\r\n contentContainerStyle={[styles.scrollContent, { padding: contentPadding }]}\r\n style={styles.scroll}\r\n testID={`${testID}${APP_SHELL_SUFFIX.content}`}\r\n >\r\n <View style={columnStyle}>{body}</View>\r\n </ScrollView>\r\n );\r\n\r\n // Header region: below the breakpoint (with a sidebar) the hamburger sits inline\r\n // before the header slot; otherwise the header wrapper is unchanged.\r\n const headerRegion = useDrawer ? (\r\n <View style={styles.headerRow} testID={`${testID}${APP_SHELL_SUFFIX.header}`}>\r\n <MenuToggle\r\n hint={drawerLabels.openHint}\r\n label={drawerLabels.openLabel}\r\n testID={`${testID}${APP_SHELL_SUFFIX.menuToggle}`}\r\n onOpen={openDrawer}\r\n />\r\n <View style={styles.headerFill}>{renderTextSlot(header, { color: theme.colors.text })}</View>\r\n </View>\r\n ) : (\r\n <View testID={`${testID}${APP_SHELL_SUFFIX.header}`}>\r\n {renderTextSlot(header, { color: theme.colors.text })}\r\n </View>\r\n );\r\n\r\n // Body: the persistent rail (full or collapsed) sits beside the content in a\r\n // row; in drawer mode the content takes the full width and the rail moves into\r\n // the overlay drawer.\r\n const railRegion =\r\n railMode === 'full' ? (\r\n <View testID={`${testID}${APP_SHELL_SUFFIX.sidebar}`}>\r\n {renderTextSlot(sidebar, { color: theme.colors.text })}\r\n </View>\r\n ) : railMode === 'collapsed' ? (\r\n <View testID={`${testID}${APP_SHELL_SUFFIX.collapsedSidebar}`}>\r\n {renderTextSlot(collapsedSidebar, { color: theme.colors.text })}\r\n </View>\r\n ) : null;\r\n\r\n return (\r\n <View style={[styles.root, { backgroundColor: theme.colors.background }]} testID={testID}>\r\n {headerRegion}\r\n {nav !== undefined ? (\r\n <View testID={`${testID}${APP_SHELL_SUFFIX.nav}`}>\r\n {navInnerStyle !== undefined ? (\r\n <View style={navInnerStyle}>{renderTextSlot(nav, { color: theme.colors.text })}</View>\r\n ) : (\r\n renderTextSlot(nav, { color: theme.colors.text })\r\n )}\r\n </View>\r\n ) : null}\r\n {banner !== undefined ? (\r\n <View testID={`${testID}${APP_SHELL_SUFFIX.banner}`}>\r\n {renderTextSlot(banner, { color: theme.colors.text })}\r\n </View>\r\n ) : null}\r\n {railRegion !== null ? (\r\n <View style={styles.bodyRow}>\r\n {railRegion}\r\n {scroller}\r\n </View>\r\n ) : (\r\n scroller\r\n )}\r\n {useDrawer && drawerOpen ? (\r\n <MobileDrawer\r\n drawerTestID={`${testID}${APP_SHELL_SUFFIX.drawer}`}\r\n labels={drawerLabels}\r\n scrimTestID={`${testID}${APP_SHELL_SUFFIX.scrim}`}\r\n sidebar={sidebar}\r\n onClose={closeDrawer}\r\n />\r\n ) : null}\r\n </View>\r\n );\r\n};\r\n\r\nexport default AppShell;\r\n","/**\r\n * CollapsedRail — the icon-only vertical rail for the intermediate (tablet) tier\r\n * of `AppShell`'s three-tier responsive layout (the erevna / katalogos collapsed\r\n * rail). It renders the SAME caller-supplied `NavItem[]` as `Sidebar`, but as a\r\n * narrow strip of icon buttons: each item shows its `renderIcon` (or a first-letter\r\n * glyph fallback), labelled for assistive tech, with the active route highlighted.\r\n * Optional `header` / `footer` slots carry app chrome (a home shortcut, a\r\n * dark-mode toggle, logout) top and bottom.\r\n *\r\n * A collapsed rail cannot expand a section inline, so pressing ANY item — leaf or\r\n * parent — navigates to its `route`; an app that wants a parent to open the full\r\n * drawer instead can special-case that in its `onNavigate`.\r\n *\r\n * Contract discipline (same as the rest of `@dloizides/ui-nav`): NO FM, router,\r\n * icon-set, or store imports. Labels are pre-localized strings, icons are render\r\n * slots, and every colour is read from the `@dloizides/ui-feedback` theme.\r\n */\r\nimport React from 'react';\r\n\r\nimport { Text, View, type ViewStyle } from 'react-native';\r\n\r\nimport { useUi } from '@dloizides/ui-feedback';\r\n\r\nimport { FocusableTouchable } from './FocusableTouchable';\r\nimport { isRouteActive } from './isRouteActive';\r\nimport { collapsedRailStyles as styles } from './styles';\r\nimport type { NavItem } from './types';\r\nimport { renderTextSlot } from './textSlot';\r\n\r\n/** Icon size for a collapsed-rail item. */\r\nconst COLLAPSED_ICON_SIZE = 22;\r\n\r\nexport interface CollapsedRailProps {\r\n /** Nav entries — the same role-filtered `NavItem[]` the full `Sidebar` renders. */\r\n items: NavItem[];\r\n /** Current active route/path. */\r\n pathname: string;\r\n /** Navigation callback — receives a `NavItem.route`. */\r\n onNavigate: (route: string) => void;\r\n /** Localized accessibility label for the navigation landmark. */\r\n regionLabel: string;\r\n /** a11y hint for an item, given its label. Defaults to the label. */\r\n navigateHint?: (label: string) => string;\r\n /** Optional header slot rendered above the items (e.g. a home shortcut). */\r\n header?: React.ReactNode;\r\n /** Optional footer slot rendered after a flex spacer (dark-mode toggle, logout). */\r\n footer?: React.ReactNode;\r\n /** Extra container style overrides. */\r\n containerStyle?: ViewStyle | ViewStyle[];\r\n}\r\n\r\n/** First character of a label, uppercased — the icon fallback glyph. */\r\nfunction glyphFor(label: string): string {\r\n return label.trim().charAt(0).toUpperCase();\r\n}\r\n\r\nexport const CollapsedRail = ({\r\n items,\r\n pathname,\r\n onNavigate,\r\n regionLabel,\r\n navigateHint = (label) => label,\r\n header,\r\n footer,\r\n containerStyle,\r\n}: CollapsedRailProps): React.ReactElement => {\r\n const { theme } = useUi();\r\n const colors = theme.colors;\r\n const primaryColor = theme.palette.primary['500'];\r\n\r\n return (\r\n <View\r\n accessibilityRole=\"none\"\r\n aria-label={regionLabel}\r\n role=\"navigation\"\r\n style={[\r\n styles.container,\r\n { backgroundColor: colors.surface, borderRightColor: colors.border },\r\n containerStyle,\r\n ]}\r\n >\r\n {header !== undefined ? (\r\n <View style={styles.slot}>{renderTextSlot(header, { color: colors.text })}</View>\r\n ) : null}\r\n\r\n {items.map((item) => {\r\n const active = isRouteActive(pathname, item.route);\r\n const iconColor = active ? primaryColor : colors.textSecondary;\r\n return (\r\n <FocusableTouchable\r\n key={item.key}\r\n accessibilityHint={navigateHint(item.label)}\r\n accessibilityLabel={item.label}\r\n ringColor={primaryColor}\r\n style={[styles.item, active ? { backgroundColor: colors.border } : undefined]}\r\n testID={item.testID ?? item.key}\r\n onPress={() => onNavigate(item.route)}\r\n >\r\n {typeof item.renderIcon === 'function' ? (\r\n item.renderIcon(iconColor, COLLAPSED_ICON_SIZE)\r\n ) : (\r\n <Text style={[styles.glyph, { color: iconColor }]}>{glyphFor(item.label)}</Text>\r\n )}\r\n </FocusableTouchable>\r\n );\r\n })}\r\n\r\n <View style={styles.spacer} />\r\n\r\n {footer !== undefined ? (\r\n <View style={styles.slot}>{renderTextSlot(footer, { color: colors.text })}</View>\r\n ) : null}\r\n </View>\r\n );\r\n};\r\n\r\nexport default CollapsedRail;\r\n","/**\n * NavShell — the ONE first-class navigation shell that renders a **top bar**, a\n * **side rail**, or **BOTH together**, chosen by a single `layout` prop\n * (`'top' | 'side' | 'both'`). It is the shell-level answer to `Nav`'s\n * single-axis question: where `Nav` returns one element (a `NavBar` OR a\n * `Sidebar`), `NavShell` owns the whole page composition — it wires a top bar\n * into `AppShell`'s `header` slot and a side rail into `AppShell`'s `sidebar`\n * slot, and inherits every `AppShell` capability (auth gate, loading / error /\n * forbidden state cards, width discipline, banner, the responsive\n * hamburger + overlay drawer for the rail).\n *\n * layout=\"top\" → a horizontal top bar only (brand + links + overflow \"…\" + right).\n * layout=\"side\" → a header + a persistent left rail of sections (the erevna / katalogos shape).\n * layout=\"both\" → a top bar (brand / global links + overflow \"…\" / user) AND a side rail\n * (sections), together — the AML-console shape, now first-class.\n *\n * \"both\" is inherently a shell composition (a top region + a side region + a\n * content column), which a single-element `Nav` cannot own; `NavShell` is that\n * composition, so no app hand-wires `Topbar` + `Sidebar` + a `ScrollView` row\n * again. Customizability is STYLE-only: every colour flows through the\n * `@dloizides/ui-feedback` UiProvider theme, and brand / user / language /\n * notification / section content are render slots. Structure + behaviour are\n * shared.\n *\n * Contract discipline (same as the rest of `@dloizides/ui-nav`): NO FM, router,\n * icon-set, or store imports. Labels are pre-localized strings, icons are render\n * slots, and every colour is read from the theme.\n */\nimport React from 'react';\n\nimport type { ViewStyle } from 'react-native';\n\nimport type { UiTheme } from '@dloizides/ui-feedback';\n\nimport { AppShell, type AppShellProps } from './AppShell';\nimport { CollapsedRail } from './CollapsedRail';\nimport { NavBar } from './NavBar';\nimport type { CollapsedRailRange } from './railMode';\nimport { Sidebar } from './Sidebar';\nimport type { NavItem } from './types';\n\n/** Which regions the shell renders: a top bar, a side rail, or both together. */\nexport type NavShellLayout = 'top' | 'side' | 'both';\n\n/**\n * Config for the TOP bar (rendered as a `NavBar` in `AppShell`'s header slot).\n * Used when `layout` is `'top'` or `'both'`. Every field is optional except the\n * items — an empty `items` array renders a bar with just the brand + right slots\n * (a plain top bar with no nav links), which is the natural `'side'`-mode header.\n */\nexport interface NavShellTopBar {\n /** Top-bar nav entries (global links). Empty ⇒ brand + right only. */\n items: NavItem[];\n /** Left slot — typically the tenant brand / logo. */\n brand?: React.ReactNode;\n /** Right slot — free-form (language toggle, notification bell, user chip, logout). */\n right?: React.ReactNode;\n /** Collapse the links behind a hamburger below this viewport width (default 760). */\n collapseBelow?: number;\n /** Localized visible + accessible label for the \"More ▾\" overflow trigger (default \"More\"). */\n overflowLabel?: string;\n /** Localized accessibility hint for the overflow trigger. */\n overflowHint?: string;\n /** Localized accessibility label for the responsive menu toggle. */\n menuLabel?: string;\n /** Localized accessibility hint for the responsive menu toggle. */\n menuHint?: string;\n /** Optional custom glyph renderer for the responsive toggle; defaults to ☰. */\n renderMenuIcon?: (color: string, open: boolean) => React.ReactNode;\n /**\n * Extra container style overrides (e.g. an app-specific appbar background —\n * including a web `background`/`backgroundImage` gradient cast through\n * `ViewStyle`, the AML radial-glow appbar). Style-only.\n */\n containerStyle?: ViewStyle | ViewStyle[];\n /**\n * Optional content-column cap (px) for the top bar. When set, the bar's\n * background + bottom border (from `containerStyle` / `barTheme`) stay FULL WIDTH\n * (full-bleed) while the inner brand + links + right row is capped to this width\n * and centred — the AML v1-console appbar shape. Forwarded to `NavBar.contentMaxWidth`.\n */\n contentMaxWidth?: number;\n /**\n * Optional CHROME theme override for the top bar only (dark bar over a light\n * page). Forwarded to `NavBar.barTheme`. Style-only — see `NavBar`.\n */\n barTheme?: UiTheme;\n}\n\n/**\n * Config for the intermediate COLLAPSED (icon-only) rail — opts the side layout\n * into a THREE-tier responsive scheme (full rail → collapsed rail → drawer). When\n * present, NavShell builds a `<CollapsedRail>` and hands it to `AppShell` for the\n * tablet band; omit it and the layout stays two-tier.\n */\nexport interface NavShellCollapsedRail {\n /** Items for the icon rail. Defaults to the full rail's `items`. */\n items?: NavItem[];\n /** Optional header slot (e.g. a home shortcut). */\n header?: React.ReactNode;\n /** Optional footer slot (dark-mode toggle, logout). */\n footer?: React.ReactNode;\n /** The `[min, max)` viewport band for the collapsed rail (default `{ min: 768, max: 1024 }`). */\n range?: CollapsedRailRange;\n}\n\n/**\n * Config for the SIDE rail (rendered as a `Sidebar` in `AppShell`'s sidebar\n * slot). Used when `layout` is `'side'` or `'both'`.\n */\nexport interface NavShellSideRail {\n /** Side-rail nav entries (sections — leaf + expandable). */\n items: NavItem[];\n /** Localized menu title (heading). */\n title: string;\n /** Optional header slot rendered above the items (e.g. a Home shortcut). */\n header?: React.ReactNode;\n /** Optional footer slot rendered after a flex spacer (dark-mode toggle, logout). */\n footer?: React.ReactNode;\n /** a11y hint shown when an expandable section is collapsed. */\n expandHint?: string;\n /** a11y hint shown when an expandable section is expanded. */\n collapseHint?: string;\n /** Optional chevron renderer for expandable sections. */\n renderChevron?: (expanded: boolean, color: string, size: number) => React.ReactNode;\n /** Extra container style overrides. */\n containerStyle?: ViewStyle | ViewStyle[];\n /** Optional collapsed (icon-only) rail config → the intermediate tablet tier. */\n collapsed?: NavShellCollapsedRail;\n}\n\n/**\n * `AppShell` props NavShell forwards straight through. It composes the `header`\n * and `sidebar` (+ `collapsedSidebar`) regions itself, so those are handled here;\n * everything else — including the optional `nav` strip (e.g. a `PillNav`), the\n * auth gate, state cards, banner, and width policy — passes through untouched.\n */\ntype ForwardedShellProps = Omit<AppShellProps, 'header' | 'sidebar' | 'children'>;\n\nexport interface NavShellProps extends ForwardedShellProps {\n /** Which regions to render: a top bar, a side rail, or both. */\n layout: NavShellLayout;\n /** Current active route/path — drives active highlighting on both regions. */\n pathname: string;\n /** Navigation callback — receives a `NavItem.route`. */\n onNavigate: (route: string) => void;\n /** Localized accessibility label for the navigation landmark(s). */\n regionLabel: string;\n /** a11y hint for a nav item, given its label. Defaults to the label. */\n navigateHint?: (label: string) => string;\n /**\n * Top-bar config → a `NavBar` in the header slot. Required for `'top'` /\n * `'both'`; **ignored for `'side'`** — `layout` decides which regions exist, so\n * a `'side'` app that also wants a bar asks for `layout=\"both\"`. A `'side'` app\n * that wants its OWN header node uses the `header` escape hatch instead.\n */\n topBar?: NavShellTopBar;\n /**\n * Escape hatch: a ready-made header node (e.g. an app-composed `<Topbar>`).\n * When supplied it REPLACES the `topBar`-built `NavBar` — used by `'side'`\n * apps that want the structured `Topbar` (language / notification / user\n * slots) instead of a `NavBar` header.\n */\n header?: React.ReactNode;\n /**\n * Side-rail config → a `Sidebar` in the sidebar slot. Required for `'side'` /\n * `'both'`; ignored for `'top'`.\n */\n sideRail?: NavShellSideRail;\n children: React.ReactNode;\n}\n\n/**\n * Should the top bar render? Yes for `'top'`/`'both'`, or when an explicit\n * `header` NODE is supplied.\n *\n * `layout` is the AUTHORITY over which regions exist: a `topBar` **config** is\n * the content of the top region, never the decision to have one, so passing a\n * `topBar` with `layout=\"side\"` renders NO top bar (use `'both'` — that is what\n * a rail plus a bar means). Before 1.10.0 an extra `layout === 'side' && hasTopBar`\n * clause made `'side'` + a `topBar` render identically to `'both'`, so `layout`\n * stopped being observable.\n *\n * `hasHeader` is a DIFFERENT concern and is deliberately kept: `header` is the\n * documented escape hatch by which a `'side'` app supplies its own ready-made\n * header node (the structured `Topbar` with language / notification / user slots)\n * instead of a `NavBar`. It is an explicit \"render THIS node in the header slot\",\n * not a config whose mere presence is read as an orientation change — and four\n * portals (erevna, katalogos, zygos, agora) depend on it.\n */\nfunction wantsTopBar(layout: NavShellLayout, hasHeader: boolean): boolean {\n return layout === 'top' || layout === 'both' || hasHeader;\n}\n\n/** Should the side rail render? Yes for `'side'`/`'both'` (when a rail is configured). */\nfunction wantsSideRail(layout: NavShellLayout, hasSideRail: boolean): boolean {\n return (layout === 'side' || layout === 'both') && hasSideRail;\n}\n\nexport const NavShell = ({\n layout,\n pathname,\n onNavigate,\n regionLabel,\n navigateHint,\n topBar,\n header,\n sideRail,\n children,\n collapsedSidebar: collapsedSidebarProp,\n collapsedRailRange: collapsedRailRangeProp,\n ...shellProps\n}: NavShellProps): React.ReactElement | null => {\n const showTopBar = wantsTopBar(layout, header !== undefined);\n const showSideRail = wantsSideRail(layout, sideRail !== undefined);\n\n // Header region: an app-supplied node wins; otherwise build a NavBar from topBar.\n const headerNode: React.ReactNode =\n header !== undefined\n ? header\n : showTopBar && topBar !== undefined\n ? (\n <NavBar\n barTheme={topBar.barTheme}\n brand={topBar.brand}\n collapseBelow={topBar.collapseBelow}\n containerStyle={topBar.containerStyle}\n contentMaxWidth={topBar.contentMaxWidth}\n items={topBar.items}\n menuHint={topBar.menuHint}\n menuLabel={topBar.menuLabel}\n navigateHint={navigateHint}\n overflowHint={topBar.overflowHint}\n overflowLabel={topBar.overflowLabel}\n pathname={pathname}\n regionLabel={regionLabel}\n renderMenuIcon={topBar.renderMenuIcon}\n right={topBar.right}\n onNavigate={onNavigate}\n />\n )\n : null;\n\n // Side-rail region: a Sidebar built from sideRail config.\n const sidebarNode: React.ReactNode =\n showSideRail && sideRail !== undefined ? (\n <Sidebar\n collapseHint={sideRail.collapseHint}\n containerStyle={sideRail.containerStyle}\n expandHint={sideRail.expandHint}\n footer={sideRail.footer}\n header={sideRail.header}\n items={sideRail.items}\n navigateHint={navigateHint}\n pathname={pathname}\n regionLabel={regionLabel}\n renderChevron={sideRail.renderChevron}\n title={sideRail.title}\n onNavigate={onNavigate}\n />\n ) : undefined;\n\n // Collapsed (tablet) rail: build a CollapsedRail from `sideRail.collapsed`\n // config when present (config-driven, not hand-wired); otherwise fall back to a\n // raw `collapsedSidebar` node the caller may have passed straight through.\n const collapsedCfg = showSideRail ? sideRail?.collapsed : undefined;\n const collapsedNode: React.ReactNode =\n collapsedCfg !== undefined && sideRail !== undefined ? (\n <CollapsedRail\n footer={collapsedCfg.footer}\n header={collapsedCfg.header}\n items={collapsedCfg.items ?? sideRail.items}\n navigateHint={navigateHint}\n pathname={pathname}\n regionLabel={regionLabel}\n onNavigate={onNavigate}\n />\n ) : (\n collapsedSidebarProp\n );\n const collapsedRange = collapsedCfg?.range ?? collapsedRailRangeProp;\n\n return (\n <AppShell\n {...shellProps}\n collapsedRailRange={collapsedRange}\n collapsedSidebar={collapsedNode}\n header={headerNode}\n sidebar={sidebarNode}\n >\n {children}\n </AppShell>\n );\n};\n\nexport default NavShell;\n","/**\n * PillNav — a horizontal row of fully-rounded \"pills\", the cross-navigation\n * switcher promoted from kefi's coral dashboard nav. It renders the same\n * caller-supplied `NavItem[]` as the other nav components, as pills that wrap,\n * with the active route wearing the accent pill.\n *\n * It also folds in kefi's **visibility rule**: the whole nav hides (renders\n * `null`) unless there are at least `minItems` entries — a single destination is\n * not worth a switcher. Default `minItems` is 1 (always show when there is at\n * least one item); kefi passes `2`.\n *\n * \"Coral pills\" is STYLE, not structure: the accent colour is the theme\n * `palette.primary` (kefi's coral), the resting pill is `surfaceElevated`, and\n * `containerStyle` / theme tokens carry any per-app tweak — no layout fork.\n *\n * Contract discipline (same as the rest of `@dloizides/ui-nav`): NO FM, router,\n * icon-set, or store imports. Labels are pre-localized strings, icons are render\n * slots, and every colour is read from the `@dloizides/ui-feedback` theme.\n */\nimport React from 'react';\n\nimport { Text, View, type ViewStyle } from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\n\nimport { FocusableTouchable } from './FocusableTouchable';\nimport { isRouteActive } from './isRouteActive';\nimport { NAV_ICON_SIZE, pillNavStyles as styles } from './styles';\nimport type { NavItem } from './types';\n\n/** Ink for a pill sitting on the accent (active) background — full-contrast white. */\nconst TEXT_ON_PRIMARY = '#ffffff';\n/** Default minimum item count to show the switcher (kefi passes 2). */\nconst DEFAULT_MIN_ITEMS = 1;\n\nexport interface PillNavProps {\n /** Nav entries — the cross-navigation destinations. */\n items: NavItem[];\n /** Current active route/path. */\n pathname: string;\n /** Navigation callback — receives a `NavItem.route`. */\n onNavigate: (route: string) => void;\n /** Localized accessibility label for the navigation landmark. */\n regionLabel: string;\n /** a11y hint for a pill, given its label. Defaults to the label. */\n navigateHint?: (label: string) => string;\n /**\n * Hide the whole switcher unless there are at least this many items. Default 1\n * (show when non-empty); kefi passes 2 (a lone dashboard needs no switcher).\n */\n minItems?: number;\n /** Extra container style overrides. */\n containerStyle?: ViewStyle | ViewStyle[];\n}\n\nexport const PillNav = ({\n items,\n pathname,\n onNavigate,\n regionLabel,\n navigateHint = (label) => label,\n minItems = DEFAULT_MIN_ITEMS,\n containerStyle,\n}: PillNavProps): React.ReactElement | null => {\n const { theme } = useUi();\n const colors = theme.colors;\n const primaryColor = theme.palette.primary['500'];\n\n if (items.length < minItems) return null;\n\n return (\n <View\n accessibilityRole=\"none\"\n aria-label={regionLabel}\n role=\"navigation\"\n style={[styles.container, containerStyle]}\n >\n {items.map((item) => {\n const active = isRouteActive(pathname, item.route);\n const textColor = active ? TEXT_ON_PRIMARY : colors.textSecondary;\n const pillStyle: ViewStyle = active\n ? { backgroundColor: primaryColor }\n : { backgroundColor: colors.surfaceElevated };\n return (\n <FocusableTouchable\n key={item.key}\n accessibilityHint={navigateHint(item.label)}\n accessibilityLabel={item.label}\n accessibilityRole=\"link\"\n ringColor={primaryColor}\n style={[styles.pill, pillStyle]}\n testID={item.testID ?? item.key}\n onPress={() => onNavigate(item.route)}\n >\n {typeof item.renderIcon === 'function' ? item.renderIcon(textColor, NAV_ICON_SIZE) : null}\n <Text style={[styles.pillText, { color: textColor }]}>{item.label}</Text>\n </FocusableTouchable>\n );\n })}\n </View>\n );\n};\n\nexport default PillNav;\n","/**\n * DarkModeControl — the shared colour-scheme control promoted from erevna /\n * katalogos (their Light / Dark / System toggle + the icon-only \"cycle\" button).\n * It is a CONTROLLED component: the app owns the current `value` and applies the\n * chosen scheme; this component only renders the choices and reports changes.\n *\n * Two variants encode the two behaviours the apps shipped:\n * - `\"segmented\"` (default): a row of segments (Light / Dark / System), the\n * active one highlighted — the desktop control.\n * - `\"cycle\"`: a single icon+label button that advances to the NEXT option on\n * each press (wrapping) — the compact mobile control.\n *\n * The options are pre-localized (`label` + `hint`) and value-agnostic (a string),\n * so the app maps its own `DarkModePreference` enum to strings without this\n * package importing it. Every colour flows through the `@dloizides/ui-feedback`\n * theme; STYLE is the only per-app variation.\n */\nimport React, { useCallback } from 'react';\n\nimport { Text, View, type ViewStyle } from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\n\nimport { FocusableTouchable } from './FocusableTouchable';\nimport { darkModeStyles as styles } from './styles';\n\n/** Ink for the active (accent-filled) segment / cycle button. */\nconst TEXT_ON_PRIMARY = '#ffffff';\n/** Icon size for a dark-mode option. */\nconst DARK_MODE_ICON_SIZE = 16;\n\n/** Which control shape to render. */\nexport type DarkModeVariant = 'segmented' | 'cycle';\n\n/** One pre-localized colour-scheme choice (e.g. Light / Dark / System). */\nexport interface DarkModeOption {\n /** App-defined value (its own preference enum mapped to a string). */\n value: string;\n /** Localized visible + accessible label. */\n label: string;\n /** Localized accessibility hint. */\n hint: string;\n /** Optional leading icon. Receives the resolved colour + size. */\n renderIcon?: (color: string, size: number) => React.ReactNode;\n}\n\nexport interface DarkModeControlProps {\n /** Current selected value — must match one of `options[].value`. */\n value: string;\n /** The pre-localized choices (typically Light / Dark / System). */\n options: DarkModeOption[];\n /** Change callback — receives the newly-selected value. */\n onChange: (value: string) => void;\n /** Localized accessibility label for the control group. */\n regionLabel: string;\n /** Control shape — a segmented row (default) or a single cycling button. */\n variant?: DarkModeVariant;\n /** testID for the control; segments are `${testID}-${value}`. */\n testID?: string;\n /** Extra container style overrides. */\n containerStyle?: ViewStyle | ViewStyle[];\n}\n\nexport const DarkModeControl = ({\n value,\n options,\n onChange,\n regionLabel,\n variant = 'segmented',\n testID,\n containerStyle,\n}: DarkModeControlProps): React.ReactElement | null => {\n const { theme } = useUi();\n const colors = theme.colors;\n const primaryColor = theme.palette.primary['500'];\n\n const currentIndex = options.findIndex((option) => option.value === value);\n const current = currentIndex >= 0 ? options[currentIndex] : options[0];\n\n const advance = useCallback(() => {\n if (options.length === 0) return;\n const from = currentIndex >= 0 ? currentIndex : 0;\n const next = options[(from + 1) % options.length];\n if (next !== undefined) onChange(next.value);\n }, [options, currentIndex, onChange]);\n\n if (options.length === 0 || current === undefined) return null;\n\n if (variant === 'cycle') {\n const iconColor = colors.text;\n return (\n <View aria-label={regionLabel} style={containerStyle}>\n <FocusableTouchable\n accessibilityHint={current.hint}\n accessibilityLabel={current.label}\n ringColor={primaryColor}\n style={[styles.cycle, { backgroundColor: colors.surfaceElevated }]}\n testID={testID}\n onPress={advance}\n >\n {typeof current.renderIcon === 'function' ? current.renderIcon(iconColor, DARK_MODE_ICON_SIZE) : null}\n <Text style={[styles.cycleText, { color: colors.text }]}>{current.label}</Text>\n </FocusableTouchable>\n </View>\n );\n }\n\n return (\n <View\n aria-label={regionLabel}\n role=\"group\"\n style={[styles.segmentRow, { borderColor: colors.border }, containerStyle]}\n >\n {options.map((option) => {\n const active = option.value === value;\n const textColor = active ? TEXT_ON_PRIMARY : colors.textSecondary;\n return (\n <FocusableTouchable\n key={option.value}\n accessibilityHint={option.hint}\n accessibilityLabel={option.label}\n ringColor={primaryColor}\n style={[styles.segment, active ? { backgroundColor: primaryColor } : undefined]}\n testID={testID !== undefined ? `${testID}-${option.value}` : undefined}\n onPress={() => onChange(option.value)}\n >\n {typeof option.renderIcon === 'function' ? option.renderIcon(textColor, DARK_MODE_ICON_SIZE) : null}\n <Text style={[styles.segmentText, { color: textColor }]}>{option.label}</Text>\n </FocusableTouchable>\n );\n })}\n </View>\n );\n};\n\nexport default DarkModeControl;\n","/**\n * Pure matching logic for the {@link CommandPalette}. Kept framework-free so the\n * ranking/filtering is unit-testable without rendering: a command matches when\n * every whitespace-separated token of the query appears (case-insensitively) in\n * its haystack (label + hint + keywords). Requiring ALL tokens lets an operator\n * narrow with \"pay dash\" the way a fuzzy launcher would, without a fuzzy lib.\n */\nimport type React from 'react';\n\n/** One actionable destination/command shown in the palette. */\nexport interface CommandItem {\n /** Stable key + default testID. */\n key: string;\n /** Optional testID override (defaults to `key`). */\n testID?: string;\n /** Localized display label (what the operator reads). */\n label: string;\n /** Optional localized secondary line (e.g. the module it lives in). */\n hint?: string;\n /** Optional extra search terms not shown but matched (synonyms, route words). */\n keywords?: readonly string[];\n /** Invoked when the item is chosen (the consumer navigates / runs the action). */\n onSelect: () => void;\n /** Optional leading icon slot, same contract as `NavItem.renderIcon`. */\n renderIcon?: (color: string, size: number) => React.ReactNode;\n}\n\n/** The searchable text for one command, lower-cased once. */\nfunction haystack(item: CommandItem): string {\n return [item.label, item.hint ?? '', ...(item.keywords ?? [])].join(' ').toLowerCase();\n}\n\n/**\n * Filter `items` to those matching `query`. An empty/whitespace query returns\n * the list unchanged (the palette opens showing everything). Order is preserved\n * — the caller supplies items in a meaningful order (nav order).\n */\nexport function filterCommands(items: readonly CommandItem[], query: string): CommandItem[] {\n const tokens = query.trim().toLowerCase().split(/\\s+/).filter(Boolean);\n if (tokens.length === 0) return [...items];\n return items.filter((item) => {\n const hay = haystack(item);\n return tokens.every((token) => hay.includes(token));\n });\n}\n","/**\n * CommandPalette — the shared ⌘K launcher for `@dloizides/ui-nav`. An overlay\n * (scrim + centred panel) with a search input over a keyboard-navigable list of\n * {@link CommandItem}s — jump to any nav destination (or run any action) without\n * hunting the rail. Web-first (RN-web), but degrades safely: when `open` is\n * false it renders nothing.\n *\n * Package discipline (as the rest of ui-nav): NO FM / router / store / icon-set\n * imports. Labels are pre-localized strings; icons are render slots; every colour\n * comes from the `@dloizides/ui-feedback` UiProvider theme. The consumer owns the\n * `open` state (pair with {@link useCommandPaletteHotkey}) and each item's\n * `onSelect` (navigate / run) — the palette just closes after a choice.\n */\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport {\n Pressable,\n ScrollView,\n StyleSheet,\n Text,\n TextInput,\n View,\n type NativeSyntheticEvent,\n type TextInputKeyPressEventData,\n} from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\n\nimport { filterCommands, type CommandItem } from './commandPaletteFilter';\nimport { NAV_ICON_SIZE } from './styles';\n\nconst SCRIM_COLOR = 'rgba(0, 0, 0, 0.5)';\nconst OVERLAY_Z_INDEX = 60;\nconst PANEL_MAX_WIDTH = 560;\nconst PANEL_TOP_OFFSET = 88;\nconst LIST_MAX_HEIGHT = 360;\nconst KEY_DOWN = 'ArrowDown';\nconst KEY_UP = 'ArrowUp';\nconst KEY_ENTER = 'Enter';\nconst KEY_ESCAPE = 'Escape';\n\n/** Pre-localized labels for the palette chrome. */\nexport interface CommandPaletteLabels {\n /** Search input placeholder. */\n placeholder: string;\n /** Accessible name of the scrim (tap to close). */\n closeLabel: string;\n /** Accessible hint of the scrim (tap to close). */\n closeHint: string;\n /** Shown when the query matches nothing. */\n emptyText: string;\n /** Accessible label for the palette dialog landmark. */\n regionLabel: string;\n}\n\nexport interface CommandPaletteProps {\n /** Whether the palette overlay is shown. */\n open: boolean;\n /** The commands to search over, in a meaningful (nav) order. */\n items: readonly CommandItem[];\n /** Close the palette (scrim tap / Escape / after a selection). */\n onClose: () => void;\n /** Pre-localized chrome labels. */\n labels: CommandPaletteLabels;\n /** testID for the panel (defaults to `command-palette`). */\n testID?: string;\n}\n\nconst styles = StyleSheet.create({\n overlay: { ...StyleSheet.absoluteFillObject, zIndex: OVERLAY_Z_INDEX, alignItems: 'center' },\n scrim: { ...StyleSheet.absoluteFillObject, backgroundColor: SCRIM_COLOR },\n panel: {\n marginTop: PANEL_TOP_OFFSET,\n width: '92%',\n maxWidth: PANEL_MAX_WIDTH,\n borderRadius: 12,\n borderWidth: 1,\n overflow: 'hidden',\n },\n input: { fontSize: 16, paddingHorizontal: 16, paddingVertical: 14, borderBottomWidth: 1 },\n list: { maxHeight: LIST_MAX_HEIGHT },\n row: { flexDirection: 'row', alignItems: 'center', paddingHorizontal: 16, paddingVertical: 12, columnGap: 10 },\n rowText: { flex: 1 },\n rowLabel: { fontSize: 15, fontWeight: '600' },\n rowHint: { fontSize: 12, marginTop: 2 },\n empty: { paddingHorizontal: 16, paddingVertical: 20, fontSize: 14 },\n});\n\ninterface PaletteRowProps {\n item: CommandItem;\n selected: boolean;\n onChoose: (item: CommandItem) => void;\n}\n\n/** One result row — highlighted when it is the active (keyboard) selection. */\nconst PaletteRow = ({ item, selected, onChoose }: PaletteRowProps): React.ReactElement => {\n const { theme } = useUi();\n const colors = theme.colors;\n return (\n <Pressable\n accessibilityHint={item.hint}\n accessibilityLabel={item.label}\n accessibilityRole=\"button\"\n accessibilityState={{ selected }}\n style={[styles.row, selected ? { backgroundColor: colors.border } : undefined]}\n testID={item.testID ?? item.key}\n onPress={() => onChoose(item)}\n >\n {typeof item.renderIcon === 'function' ? item.renderIcon(colors.textSecondary, NAV_ICON_SIZE) : null}\n <View style={styles.rowText}>\n <Text style={[styles.rowLabel, { color: colors.text }]}>{item.label}</Text>\n {item.hint ? <Text style={[styles.rowHint, { color: colors.textSecondary }]}>{item.hint}</Text> : null}\n </View>\n </Pressable>\n );\n};\n\n/** The overlay palette. Renders null when closed. */\nexport const CommandPalette = ({ open, items, onClose, labels, testID }: CommandPaletteProps): React.ReactElement | null => {\n const { theme } = useUi();\n const colors = theme.colors;\n const [query, setQuery] = useState('');\n const [selected, setSelected] = useState(0);\n const inputRef = useRef<TextInput | null>(null);\n\n const results = useMemo(() => filterCommands(items, query), [items, query]);\n\n // Reset + focus each time the palette opens; clamp the selection as results shrink.\n useEffect(() => {\n if (!open) return;\n setQuery('');\n setSelected(0);\n inputRef.current?.focus();\n }, [open]);\n useEffect(() => {\n setSelected((prev) => Math.min(prev, Math.max(0, results.length - 1)));\n }, [results.length]);\n\n const choose = useCallback(\n (item: CommandItem) => {\n item.onSelect();\n onClose();\n },\n [onClose],\n );\n\n const onKeyPress = useCallback(\n (event: NativeSyntheticEvent<TextInputKeyPressEventData>) => {\n const key = event.nativeEvent.key;\n if (key === KEY_DOWN) setSelected((i) => Math.min(i + 1, results.length - 1));\n else if (key === KEY_UP) setSelected((i) => Math.max(i - 1, 0));\n else if (key === KEY_ESCAPE) onClose();\n else if (key === KEY_ENTER && results[selected]) choose(results[selected]);\n },\n [results, selected, choose, onClose],\n );\n\n if (!open) return null;\n\n return (\n <View style={styles.overlay}>\n <Pressable\n accessibilityHint={labels.closeHint}\n accessibilityLabel={labels.closeLabel}\n accessibilityRole=\"button\"\n style={styles.scrim}\n testID={`${testID ?? 'command-palette'}-scrim`}\n onPress={onClose}\n />\n <View\n aria-modal\n aria-label={labels.regionLabel}\n role=\"dialog\"\n style={[styles.panel, { backgroundColor: colors.surface, borderColor: colors.border }]}\n testID={testID ?? 'command-palette'}\n >\n <TextInput\n ref={inputRef}\n accessibilityLabel={labels.placeholder}\n placeholder={labels.placeholder}\n placeholderTextColor={colors.textSecondary}\n style={[styles.input, { color: colors.text, borderBottomColor: colors.border }]}\n testID={`${testID ?? 'command-palette'}-input`}\n value={query}\n onChangeText={setQuery}\n onKeyPress={onKeyPress}\n />\n {results.length === 0 ? (\n <Text style={[styles.empty, { color: colors.textSecondary }]}>{labels.emptyText}</Text>\n ) : (\n <ScrollView keyboardShouldPersistTaps=\"handled\" style={styles.list}>\n {results.map((item, index) => (\n <PaletteRow key={item.key} item={item} selected={index === selected} onChoose={choose} />\n ))}\n </ScrollView>\n )}\n </View>\n </View>\n );\n};\n\nexport default CommandPalette;\n","/**\n * CommandPaletteTrigger — the VISIBLE, discoverable affordance that opens the\n * {@link CommandPalette}. A ⌘K shortcut alone is invisible; a docs-style search\n * pill (muted placeholder on the left, a keyboard-shortcut badge on the right)\n * tells operators the palette exists and is one click away. Place it in a shell\n * header / sidebar; wire `onPress` to the same open handler as the ⌘K hotkey.\n *\n * Self-contained on purpose: the shared icon set has no magnifier, so this uses\n * text + a shortcut badge (the recognizable \"Search … ⌘K\" pattern) rather than a\n * render-slot icon — one less thing every consumer must supply. Colours come from\n * the `@dloizides/ui-feedback` UiProvider theme; the label/shortcut are\n * pre-localized strings (package discipline: no FM/router imports).\n */\nimport React from 'react';\n\nimport { Pressable, StyleSheet, Text, View } from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\n\nimport { focusRingStyle } from './webStyle';\n\nconst MIN_TARGET = 36;\n\nexport interface CommandPaletteTriggerProps {\n /** Placeholder-style label, e.g. \"Search\". */\n label: string;\n /** a11y hint describing what activating it does. */\n hint: string;\n /** The shortcut badge text, e.g. \"⌘K\" (already chosen per-platform by the caller). */\n shortcut: string;\n /** Open the palette (same handler as the ⌘K hotkey). */\n onPress: () => void;\n /** testID for the trigger. */\n testID: string;\n}\n\nconst styles = StyleSheet.create({\n trigger: {\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: 'space-between',\n columnGap: 8,\n paddingHorizontal: 12,\n minHeight: MIN_TARGET,\n borderWidth: 1,\n borderRadius: 8,\n },\n label: { fontSize: 14 },\n badge: { paddingHorizontal: 6, paddingVertical: 2, borderRadius: 4, borderWidth: 1 },\n badgeText: { fontSize: 11, fontWeight: '700' },\n});\n\n/** The visible \"Search … ⌘K\" pill that opens the command palette. */\nexport const CommandPaletteTrigger = ({\n label,\n hint,\n shortcut,\n onPress,\n testID,\n}: CommandPaletteTriggerProps): React.ReactElement => {\n const { theme } = useUi();\n const colors = theme.colors;\n const primary = theme.palette.primary['500'];\n const [focused, setFocused] = React.useState(false);\n return (\n <Pressable\n accessibilityHint={hint}\n accessibilityLabel={label}\n accessibilityRole=\"button\"\n style={[\n styles.trigger,\n { backgroundColor: colors.surface, borderColor: colors.border },\n focusRingStyle(focused, primary),\n ]}\n testID={testID}\n onBlur={() => setFocused(false)}\n onFocus={() => setFocused(true)}\n onPress={onPress}\n >\n <Text style={[styles.label, { color: colors.textSecondary }]}>{label}</Text>\n <View style={[styles.badge, { borderColor: colors.border }]}>\n <Text style={[styles.badgeText, { color: colors.textSecondary }]}>{shortcut}</Text>\n </View>\n </Pressable>\n );\n};\n\nexport default CommandPaletteTrigger;\n","/**\n * Binds the ⌘K / Ctrl-K launcher shortcut for {@link CommandPalette}. Web-only\n * (guards `document`), so it is a no-op under native RN and in SSR/tests without\n * a DOM. `preventDefault` stops the browser's own Ctrl-K (address-bar search) so\n * the palette wins. The consumer owns the open state; this only requests opening.\n */\nimport { useEffect } from 'react';\n\n/** The launcher key (with ⌘ on macOS or Ctrl elsewhere). */\nconst LAUNCH_KEY = 'k';\n\n/**\n * Call `onOpen` when the operator presses ⌘K (macOS) or Ctrl-K (Windows/Linux),\n * anywhere in the document. `enabled=false` unbinds (e.g. when the shell has no\n * palette configured), so the shortcut never fires without a handler behind it.\n */\nexport function useCommandPaletteHotkey(onOpen: () => void, enabled = true): void {\n useEffect(() => {\n if (!enabled || typeof document === 'undefined') return undefined;\n const handler = (event: KeyboardEvent): void => {\n const isLauncher = event.key.toLowerCase() === LAUNCH_KEY && (event.metaKey || event.ctrlKey);\n if (!isLauncher) return;\n event.preventDefault();\n onOpen();\n };\n document.addEventListener('keydown', handler);\n return () => document.removeEventListener('keydown', handler);\n }, [onOpen, enabled]);\n}\n","/**\n * Role-gated nav helpers — build a `NavItem[]` from a user's roles, reusing the\n * existing `resolveAccessibleRoutes` from `@dloizides/auth-web` (the same helper\n * the multi-role dashboard nav uses) rather than reimplementing role filtering.\n *\n * The app supplies its ordered `RoleRouteTable` (role → route + optional\n * `labelKey`) and a `translate` fn (its `FM`); this returns the ordered set of\n * `NavItem`s the user's roles unlock — most privileged first, empty when none.\n */\nimport { resolveAccessibleRoutes } from '@dloizides/auth-web';\nimport type { RoleRoute, RoleRouteTable } from '@dloizides/auth-web';\n\nimport type { NavItem } from './types';\n\n/** The user shape `resolveAccessibleRoutes` accepts (derived — no extra dep). */\nexport type NavUser = Parameters<typeof resolveAccessibleRoutes>[0];\n\n/** Map already-resolved role routes to nav items, localizing each `labelKey`. */\nexport function roleRoutesToNavItems(\n routes: RoleRoute[],\n translate: (key: string) => string,\n): NavItem[] {\n return routes.map((entry) => ({\n key: entry.role,\n route: entry.route,\n label: entry.labelKey !== undefined ? translate(entry.labelKey) : entry.route,\n }));\n}\n\n/**\n * Resolve the nav items a user can reach, in table (priority) order. Wraps\n * `resolveAccessibleRoutes` so role gating lives in one place.\n */\nexport function accessibleNavItems(\n user: NavUser,\n table: RoleRouteTable,\n translate: (key: string) => string,\n): NavItem[] {\n return roleRoutesToNavItems(resolveAccessibleRoutes(user, table), translate);\n}\n"]}