@dloizides/ui-nav 1.6.1 → 1.8.0
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.
- package/ADOPTION.md +83 -0
- package/CHANGELOG.md +100 -0
- package/README.md +113 -0
- package/dist/index.d.mts +595 -14
- package/dist/index.d.ts +595 -14
- package/dist/index.js +640 -115
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +603 -95
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -2
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/isRouteActive.ts","../src/styles.ts","../src/webStyle.ts","../src/NavExpandableItem.tsx","../src/Sidebar.tsx","../src/constants.ts","../src/FocusableTouchable.tsx","../src/Topbar.tsx","../src/NavBarLink.tsx","../src/useReducedMotion.ts","../src/NavBar.tsx","../src/MobileDrawer.tsx","../src/useContentMaxWidth.ts","../src/AppShell.tsx","../src/roleNav.ts"],"names":["useUi","jsxs","View","jsx","Text","useState","TEXT_ON_PRIMARY","ariaCurrentProps","Pressable","useCallback","useMemo","MENU_GLYPH","StyleSheet","useEffect","useWindowDimensions","styles","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\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 inside a horizontal ScrollView so the bar stays ONE ROW no matter how many\n // items an app passes: they never wrap onto a second line — any overflow scrolls instead, with the\n // brand (left) and right slot pinned. `linksScroll` is the ScrollView's own box (a shrinkable,\n // growable flex child that may collapse to 0 and scroll); `links` is its non-wrapping content row.\n linksScroll: {\n flexGrow: 1,\n flexShrink: 1,\n minWidth: 0,\n },\n links: {\n flexDirection: 'row',\n alignItems: 'center',\n flexWrap: 'nowrap',\n columnGap: 4,\n rowGap: 4,\n },\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 expandableStyles = StyleSheet.create({\n childItem: {\n borderRadius: 4,\n flexDirection: 'row',\n alignItems: 'center',\n paddingVertical: 6,\n },\n childItemText: { fontSize: 14 },\n childItemTextWithIcon: { fontSize: 14, marginLeft: 6 },\n chevron: { marginLeft: 'auto' },\n childrenContainer: { overflow: 'hidden' },\n header: {\n borderRadius: 4,\n flexDirection: 'row',\n alignItems: 'center',\n paddingVertical: 8,\n },\n headerText: { fontSize: 15, fontWeight: '600', marginLeft: 6 },\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 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\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(false);\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\n const activeItemStyle = useMemo(\n () => ({ backgroundColor: colors.border, borderRadius: ACTIVE_BORDER_RADIUS }),\n [colors.border],\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={[styles.header, headerPaddingStyle, focusRingStyle(focused, primaryColor)]}\n testID={item.testID ?? item.key}\n onBlur={() => setFocused(false)}\n onFocus={() => setFocused(true)}\n onPress={toggle}\n >\n {typeof item.renderIcon === 'function' ? (\n <View style={styles.iconWrapper}>{item.renderIcon(colors.text, NAV_ICON_SIZE)}</View>\n ) : null}\n <Text style={[styles.headerText, { color: colors.text }]}>{item.label}</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 * Sidebar — the config-driven left navigation shell promoted from the\n * byte-identical erevna-web / katalogos-web `Sidebar`. It renders a caller\n * supplied `NavItem[]` (leaf + expandable), highlights the active route, and\n * exposes header/footer slots for app-specific chrome (title, dark-mode toggle,\n * logout, notification bell). Every colour is read from the UiProvider theme.\n */\nimport React from 'react';\n\nimport { Text, View, type ViewStyle } from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\n\nimport { isRouteActive } from './isRouteActive';\nimport { NavExpandableItem } from './NavExpandableItem';\nimport { navStyles as styles } from './styles';\nimport type { NavItem } from './types';\n\nexport interface SidebarProps {\n /** Nav entries — already role-filtered / grouped by the app. */\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 menu title (heading). */\n title: string;\n /** Localized accessibility label for the navigation landmark. */\n regionLabel: string;\n /** a11y hint for a leaf item, given its label. Defaults to the label. */\n navigateHint?: (label: string) => string;\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 /** 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 /** Extra container style overrides. */\n containerStyle?: ViewStyle | ViewStyle[];\n}\n\nexport const Sidebar = ({\n items,\n pathname,\n onNavigate,\n title,\n regionLabel,\n navigateHint = (label) => label,\n expandHint = '',\n collapseHint = '',\n renderChevron,\n header,\n footer,\n containerStyle,\n}: SidebarProps): React.ReactElement => {\n const { theme } = useUi();\n const colors = theme.colors;\n\n return (\n <View\n accessibilityRole=\"none\"\n aria-label={regionLabel}\n role=\"navigation\"\n style={[\n styles.sidebarContainer,\n { backgroundColor: colors.surface, borderRightColor: colors.border },\n containerStyle,\n ]}\n >\n <Text accessibilityRole=\"header\" style={[styles.sidebarTitle, { color: colors.text }]}>\n {title}\n </Text>\n\n {header}\n\n {items.map((item) => (\n <NavExpandableItem\n key={item.key}\n collapseHint={collapseHint}\n expandHint={expandHint}\n item={item}\n navigateHint={navigateHint}\n pathname={pathname}\n renderChevron={renderChevron}\n onNavigate={onNavigate}\n />\n ))}\n\n <View style={styles.sidebarSpacer} />\n\n {footer}\n </View>\n );\n};\n\nexport { isRouteActive };\nexport default Sidebar;\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} 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 /** 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","/**\n * Topbar — the config-driven top navigation bar promoted from the byte-identical\n * erevna-web / katalogos-web `Topbar`. Structured slots replace the app-specific\n * wiring: a `left` logo slot, an optional language toggle, a notification slot,\n * an optional user block, an optional account button, and a required logout\n * action. Every colour comes from the UiProvider theme.\n *\n * Move 1c enriches this WITHOUT breaking the promoted contract: `account` now\n * accepts EITHER the legacy `TopbarAction` (today's erevna/katalogos calls) OR a\n * richer `AccountState` (displayName + muted tenant line + plan badge + upgrade\n * action). The `logout` action stays required, so every existing call keeps\n * compiling and the logout button keeps its caller-supplied testID.\n */\nimport React from 'react';\n\nimport { Text, View, type ViewStyle } from 'react-native';\n\nimport { useUi, type UiTheme } from '@dloizides/ui-feedback';\n\nimport { NAV_TEST_IDS } from './constants';\nimport { FocusableTouchable } from './FocusableTouchable';\nimport { navStyles as styles } from './styles';\n\n/** Text color for elements on primary/coloured badge backgrounds. */\nconst TEXT_ON_PRIMARY = '#ffffff';\n\nexport interface TopbarAction {\n label: string;\n hint: string;\n onPress: () => void;\n testID?: string;\n}\n\nexport interface TopbarUser {\n name: string;\n email: string;\n}\n\n/** Plan tier shown as a small badge in the rich account header. */\nexport interface AccountPlan {\n label: string;\n tone?: 'free' | 'pro' | 'enterprise';\n}\n\n/**\n * Richer account model for the header (Move 1c). Supplied via `account` as an\n * alternative to the legacy `TopbarAction` — the Topbar renders the display name\n * (tappable when `onAccount` is set), a muted tenant line, a plan badge, and an\n * `upgrade` action beside logout. No FM/router/store — everything is a\n * pre-localized string or a callback.\n */\nexport interface AccountState {\n displayName: string;\n tenantName?: string;\n plan?: AccountPlan;\n onLogout: () => void;\n onAccount?: () => void;\n upgrade?: TopbarAction;\n}\n\n/** Type guard: distinguishes the rich `AccountState` from a legacy `TopbarAction`. */\nfunction isAccountState(account: TopbarAction | AccountState): account is AccountState {\n return 'displayName' in account;\n}\n\n/** Resolve a plan badge background from its tone, routed through the theme. */\nfunction planToneColor(theme: UiTheme, tone: AccountPlan['tone']): string {\n const palette = theme.palette;\n if (tone === 'pro') return palette.primary['500'];\n if (tone === 'enterprise') return palette.accent?.['500'] ?? palette.primary['500'];\n return theme.colors.textSecondary;\n}\n\nexport interface TopbarProps {\n /** Left slot — typically the tenant logo. */\n left?: React.ReactNode;\n /** Optional language toggle. */\n language?: { label: string; hint: string; onPress: () => void };\n /** Optional notification slot (e.g. a notification bell). */\n notificationSlot?: React.ReactNode;\n /** Optional user identity block. */\n user?: TopbarUser;\n /**\n * Optional account slot. Legacy callers pass a `TopbarAction` (an account\n * button). Move-1c callers pass an `AccountState` for the richer header.\n */\n account?: TopbarAction | AccountState;\n /** Required logout action (drives the stable logout button testID). */\n logout: TopbarAction;\n /** Extra container style overrides. */\n containerStyle?: ViewStyle | ViewStyle[];\n}\n\nexport const Topbar = ({\n left,\n language,\n notificationSlot,\n user,\n account,\n logout,\n containerStyle,\n}: TopbarProps): React.ReactElement => {\n const { theme } = useUi();\n const colors = theme.colors;\n const primaryColor = theme.palette.primary['500'];\n\n const richAccount = account !== undefined && isAccountState(account) ? account : undefined;\n const legacyAccount = account !== undefined && !isAccountState(account) ? account : undefined;\n const upgrade = richAccount?.upgrade;\n\n return (\n <View\n style={[\n styles.topbarContainer,\n { borderBottomColor: colors.border, backgroundColor: colors.background },\n containerStyle,\n ]}\n >\n <View style={styles.topbarLeft}>{left}</View>\n <View style={styles.topbarRight}>\n {language ? (\n <FocusableTouchable\n accessibilityHint={language.hint}\n accessibilityLabel={language.label}\n ringColor={primaryColor}\n style={styles.topbarRowItem}\n onPress={language.onPress}\n >\n <Text style={[styles.topbarLabel, { color: colors.text }]}>{language.label}</Text>\n </FocusableTouchable>\n ) : null}\n\n {notificationSlot}\n\n {user ? (\n <View style={styles.userBlock}>\n <Text style={[styles.userName, { color: colors.text }]}>{user.name}</Text>\n <Text style={[styles.userEmail, { color: colors.textSecondary }]}>{user.email}</Text>\n </View>\n ) : null}\n\n {richAccount ? (\n <View style={styles.userBlock}>\n {richAccount.onAccount ? (\n <FocusableTouchable\n accessibilityHint={richAccount.displayName}\n accessibilityLabel={richAccount.displayName}\n ringColor={primaryColor}\n testID={NAV_TEST_IDS.accountName}\n onPress={richAccount.onAccount}\n >\n <Text style={[styles.userName, { color: colors.text }]}>{richAccount.displayName}</Text>\n </FocusableTouchable>\n ) : (\n <Text style={[styles.userName, { color: colors.text }]} testID={NAV_TEST_IDS.accountName}>\n {richAccount.displayName}\n </Text>\n )}\n\n {richAccount.tenantName !== undefined ? (\n <Text\n style={[styles.accountTenant, { color: colors.textSecondary }]}\n testID={NAV_TEST_IDS.accountTenant}\n >\n {richAccount.tenantName}\n </Text>\n ) : null}\n\n {richAccount.plan ? (\n <View\n style={[styles.planBadge, { backgroundColor: planToneColor(theme, richAccount.plan.tone) }]}\n testID={NAV_TEST_IDS.accountPlan}\n >\n <Text style={[styles.planBadgeText, { color: TEXT_ON_PRIMARY }]}>{richAccount.plan.label}</Text>\n </View>\n ) : null}\n </View>\n ) : null}\n\n {legacyAccount ? (\n <FocusableTouchable\n accessibilityHint={legacyAccount.hint}\n accessibilityLabel={legacyAccount.label}\n ringColor={primaryColor}\n style={[styles.accountBtn, { backgroundColor: primaryColor }]}\n testID={legacyAccount.testID}\n onPress={legacyAccount.onPress}\n >\n <Text style={[styles.accountText, { color: TEXT_ON_PRIMARY }]}>{legacyAccount.label}</Text>\n </FocusableTouchable>\n ) : null}\n\n {upgrade ? (\n <FocusableTouchable\n accessibilityHint={upgrade.hint}\n accessibilityLabel={upgrade.label}\n ringColor={primaryColor}\n style={[styles.accountBtn, { backgroundColor: primaryColor }]}\n testID={upgrade.testID ?? NAV_TEST_IDS.accountUpgrade}\n onPress={upgrade.onPress}\n >\n <Text style={[styles.accountText, { color: TEXT_ON_PRIMARY }]}>{upgrade.label}</Text>\n </FocusableTouchable>\n ) : null}\n\n <FocusableTouchable\n accessibilityHint={logout.hint}\n accessibilityLabel={logout.label}\n ringColor={primaryColor}\n style={[styles.accountBtn, { backgroundColor: primaryColor }]}\n testID={logout.testID}\n onPress={richAccount ? richAccount.onLogout : logout.onPress}\n >\n <Text style={[styles.accountText, { color: TEXT_ON_PRIMARY }]}>{logout.label}</Text>\n </FocusableTouchable>\n </View>\n </View>\n );\n};\n\nexport default Topbar;\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 * `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","/**\n * NavBar — the config-driven HORIZONTAL top navigation bar. It is the top-bar\n * counterpart to `Sidebar`: it renders the SAME caller-supplied `NavItem[]`\n * (already role-filtered / localized by the app) as inline links across the top\n * instead of a left rail, with an optional brand slot on the left and a free-form\n * right slot (auth link / user / logout). Below a configurable breakpoint it\n * collapses the links behind a hamburger toggle — mirroring the v1 AML console's\n * responsive `.global-nav`.\n *\n * Look + feel: each link is a rounded-pill target with the v1 `.gn-links a`\n * affordance — muted at rest, brightening text + a subtle pill background on\n * HOVER, and a solid accent pill when ACTIVE. All colours are THEME-DRIVEN from\n * the `@dloizides/ui-feedback` UiProvider (rest=`textSecondary`, hover text=`text`,\n * hover bg=`surfaceElevated`, active=`palette.primary`, ring=`palette.primary`).\n * Hover/focus are web-only (react-native-web); native stays at the rest style.\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. This is purely additive —\n * `Sidebar`/`Topbar` are unchanged.\n */\nimport React, { useCallback, useMemo, useState } from 'react';\n\nimport {\n Pressable,\n ScrollView,\n Text,\n useWindowDimensions,\n View,\n type PressableProps,\n type ViewStyle,\n} from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\n\nimport { NAV_TEST_IDS } from './constants';\nimport { isRouteActive } from './isRouteActive';\nimport { NavBarLink, type NavBarLinkColors } from './NavBarLink';\nimport { navBarStyles as styles, NAV_ICON_SIZE } from './styles';\nimport type { NavItem } from './types';\nimport { useReducedMotion } from './useReducedMotion';\nimport { focusRingStyle } from './webStyle';\n\n/** DOM id linking the toggle (`aria-controls`) to the collapsible links region. */\nconst LINKS_REGION_ID = 'navbar-links-region';\n/** Collapse to a hamburger at/under this viewport width (matches v1's 760px). */\nconst DEFAULT_COLLAPSE_BELOW = 760;\n/** Default hamburger glyph (☰) when no `renderMenuIcon` is supplied. */\nconst MENU_GLYPH = '☰';\n\nexport interface NavBarProps {\n /** Nav entries — already role-filtered / grouped by the app. */\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 link, given its label. Defaults to the label. */\n navigateHint?: (label: string) => string;\n /** Left slot — typically the brand / tenant logo. */\n brand?: React.ReactNode;\n /** Right slot — free-form (auth link, user block, logout). */\n right?: React.ReactNode;\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 toggle; defaults to ☰. */\n renderMenuIcon?: (color: string, open: boolean) => React.ReactNode;\n /** Collapse the links behind a hamburger below this viewport width (default 760). */\n collapseBelow?: number;\n /** Extra container style overrides. */\n containerStyle?: ViewStyle | ViewStyle[];\n}\n\n/**\n * `aria-controls` links the toggle to the collapsible links region. RN's prop\n * types omit `aria-controls`, but react-native-web forwards `aria-*` to the DOM —\n * so we attach it (no `any`).\n */\nfunction ariaControlsProps(id: string): PressableProps & { 'aria-controls'?: string } {\n return { 'aria-controls': id };\n}\n\nexport const NavBar = ({\n items,\n pathname,\n onNavigate,\n regionLabel,\n navigateHint = (label) => label,\n brand,\n right,\n menuLabel = 'Menu',\n menuHint = '',\n renderMenuIcon,\n collapseBelow = DEFAULT_COLLAPSE_BELOW,\n containerStyle,\n}: NavBarProps): React.ReactElement => {\n const { theme } = useUi();\n const colors = theme.colors;\n const primaryColor = theme.palette.primary['500'];\n const { width } = useWindowDimensions();\n const reducedMotion = useReducedMotion();\n const [open, setOpen] = useState(false);\n const [toggleFocused, setToggleFocused] = useState(false);\n\n const collapsed = width < collapseBelow;\n const showLinks = !collapsed || open;\n\n const toggleMenu = useCallback(() => setOpen((v) => !v), []);\n const handlePress = useCallback(\n (route: string) => {\n setOpen(false);\n onNavigate(route);\n },\n [onNavigate],\n );\n\n // Theme-driven link colours (v1 `.gn-links a`): muted → brightened-on-hover text,\n // a subtle raised pill on hover, the accent pill when active, accent focus ring.\n const linkColors = useMemo<NavBarLinkColors>(\n () => ({\n rest: colors.textSecondary,\n hoverText: colors.text,\n hoverBg: colors.surfaceElevated,\n activeBg: primaryColor,\n ring: primaryColor,\n }),\n [colors.textSecondary, colors.text, colors.surfaceElevated, primaryColor],\n );\n\n return (\n <View\n accessibilityRole=\"none\"\n aria-label={regionLabel}\n role=\"navigation\"\n style={[\n styles.container,\n { backgroundColor: colors.surface, borderBottomColor: colors.border },\n containerStyle,\n ]}\n >\n <View style={[styles.inner, collapsed ? null : styles.innerNoWrap]}>\n {brand !== undefined ? <View style={styles.brand}>{brand}</View> : null}\n\n {collapsed ? (\n <Pressable\n accessibilityHint={menuHint}\n accessibilityLabel={menuLabel}\n accessibilityRole=\"button\"\n accessibilityState={{ expanded: open }}\n aria-expanded={open}\n style={[styles.toggle, focusRingStyle(toggleFocused, primaryColor)]}\n testID={NAV_TEST_IDS.navBarToggle}\n onBlur={() => setToggleFocused(false)}\n onFocus={() => setToggleFocused(true)}\n onPress={toggleMenu}\n {...ariaControlsProps(LINKS_REGION_ID)}\n >\n {typeof renderMenuIcon === 'function' ? (\n renderMenuIcon(colors.text, open)\n ) : (\n <Text style={[styles.toggleGlyph, { color: colors.text }]}>{MENU_GLYPH}</Text>\n )}\n </Pressable>\n ) : null}\n\n {showLinks\n ? (() => {\n const links = items.map((item) => (\n <NavBarLink\n key={item.key}\n collapsed={collapsed}\n colors={linkColors}\n iconSize={NAV_ICON_SIZE}\n isActive={isRouteActive(pathname, item.route)}\n item={item}\n navigateHint={navigateHint}\n reducedMotion={reducedMotion}\n onPress={handlePress}\n />\n ));\n // Collapsed (mobile): links stack vertically on their own full-width line.\n // Expanded (desktop): links live in a horizontal ScrollView so the bar stays ONE row —\n // any overflow scrolls instead of wrapping onto a second line, with brand + right pinned.\n return collapsed ? (\n <View nativeID={LINKS_REGION_ID} style={styles.linksStacked} testID={NAV_TEST_IDS.navBarLinks}>\n {links}\n </View>\n ) : (\n <ScrollView\n horizontal\n showsHorizontalScrollIndicator={false}\n nativeID={LINKS_REGION_ID}\n style={styles.linksScroll}\n contentContainerStyle={styles.links}\n testID={NAV_TEST_IDS.navBarLinks}\n >\n {links}\n </ScrollView>\n );\n })()\n : null}\n\n {showLinks && right !== undefined ? (\n <View style={collapsed ? styles.rightStacked : styles.right}>{right}</View>\n ) : null}\n </View>\n </View>\n );\n};\n\nexport { isRouteActive };\nexport default NavBar;\n","/**\n * MobileDrawer — the below-the-breakpoint face of `AppShell`'s back-office\n * `sidebar` layout. On a narrow viewport (<768px) the persistent left rail would\n * starve the content column, so instead of the rail we render a hamburger toggle\n * (`MenuToggle`) in the header and slide the same `Sidebar` in as an overlay\n * drawer (a scrim + a left panel). The drawer closes on a scrim tap and on any\n * nav-item press inside the panel (web: a bubbled click on a `role=\"button\"` /\n * link element). Desktop is untouched — AppShell never mounts this above 768px.\n *\n * Contract discipline (same as the rest of `@dloizides/ui-nav`): NO FM / router /\n * store imports. Labels are pre-localized strings (English defaults, overridable\n * by the consumer via `AppShell`'s `mobileMenu` prop); every colour is read from\n * the `@dloizides/ui-feedback` UiProvider theme.\n */\nimport React, { useEffect, useRef } from 'react';\n\nimport { Pressable, StyleSheet, Text, View } from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\n\nimport { FocusableTouchable } from './FocusableTouchable';\n\n/** Collapse the persistent rail into a drawer at/under this viewport width. */\nexport const MOBILE_BREAKPOINT = 768;\n\nconst SCRIM_COLOR = 'rgba(0, 0, 0, 0.5)';\nconst MENU_GLYPH = '☰';\nconst MENU_MIN_TARGET = 44;\nconst MENU_GLYPH_FONT_SIZE = 20;\nconst MENU_TOGGLE_PADDING = 12;\nconst DRAWER_Z_INDEX = 50;\n/**\n * A nav element that, when clicked inside the open drawer, should close it.\n * react-native-web maps `accessibilityRole` -> the DOM `role`, so the Sidebar's\n * leaf `TouchableOpacity`s render as `role=\"button\"` and match here.\n */\nconst NAV_ACTIVATABLE_SELECTOR = 'a, [role=\"button\"], [role=\"link\"]';\n\n/** Pre-localized labels for the drawer's hamburger + scrim. */\nexport interface DrawerLabels {\n /** Accessible name of the hamburger that opens the drawer. */\n openLabel: string;\n /** Accessible hint of the hamburger that opens the drawer. */\n openHint: 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}\n\n/** English defaults — the consumer overrides these with localized strings. */\nexport const DEFAULT_DRAWER_LABELS: DrawerLabels = {\n openLabel: 'Menu',\n openHint: 'Open the navigation menu',\n closeLabel: 'Close menu',\n closeHint: 'Close the navigation menu',\n};\n\nconst styles = StyleSheet.create({\n overlay: { ...StyleSheet.absoluteFillObject, zIndex: DRAWER_Z_INDEX },\n scrim: { ...StyleSheet.absoluteFillObject, backgroundColor: SCRIM_COLOR },\n panel: { position: 'absolute', top: 0, bottom: 0, left: 0 },\n menuToggle: {\n minWidth: MENU_MIN_TARGET,\n minHeight: MENU_MIN_TARGET,\n alignItems: 'center',\n justifyContent: 'center',\n paddingHorizontal: MENU_TOGGLE_PADDING,\n },\n menuToggleGlyph: { fontSize: MENU_GLYPH_FONT_SIZE, fontWeight: '700' },\n});\n\nexport interface MenuToggleProps {\n label: string;\n hint: string;\n onOpen: () => void;\n testID: string;\n}\n\n/** The mobile hamburger button, rendered in the header region below the breakpoint. */\nexport const MenuToggle = ({ label, hint, onOpen, testID }: MenuToggleProps): React.ReactElement => {\n const { theme } = useUi();\n return (\n <FocusableTouchable\n accessibilityHint={hint}\n accessibilityLabel={label}\n ringColor={theme.palette.primary['500']}\n style={styles.menuToggle}\n testID={testID}\n onPress={onOpen}\n >\n <Text style={[styles.menuToggleGlyph, { color: theme.colors.text }]}>{MENU_GLYPH}</Text>\n </FocusableTouchable>\n );\n};\n\nexport interface MobileDrawerProps {\n /** The `Sidebar` slot to render inside the drawer panel. */\n sidebar: React.ReactNode;\n /** Pre-localized close (scrim) labels. */\n labels: DrawerLabels;\n /** Close the drawer. */\n onClose: () => void;\n /** testID for the drawer panel. */\n drawerTestID: string;\n /** testID for the scrim. */\n scrimTestID: string;\n}\n\n/** The open drawer overlay: a tap-to-close scrim + the sidebar panel. */\nexport const MobileDrawer = ({\n sidebar,\n labels,\n onClose,\n drawerTestID,\n scrimTestID,\n}: MobileDrawerProps): React.ReactElement => {\n const panelRef = useRef<View | null>(null);\n\n // Close on a nav-item press. The consumer wires the Sidebar's `onNavigate`\n // directly to the router, so we cannot intercept that callback; instead (on\n // web) we watch for a bubbled click on an activatable element inside the panel.\n useEffect(() => {\n const node = panelRef.current as unknown as HTMLElement | null;\n if (node === null || typeof node.addEventListener !== 'function') return undefined;\n const handleClick = (event: MouseEvent): void => {\n const target = event.target as HTMLElement | null;\n const onNavItem = target !== null && target.closest(NAV_ACTIVATABLE_SELECTOR) !== null;\n if (onNavItem) onClose();\n };\n node.addEventListener('click', handleClick);\n return () => node.removeEventListener('click', handleClick);\n }, [onClose]);\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={scrimTestID}\n onPress={onClose}\n />\n <View ref={panelRef} aria-modal role=\"dialog\" style={styles.panel} testID={drawerTestID}>\n {sidebar}\n </View>\n </View>\n );\n};\n\nexport default MobileDrawer;\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","/**\n * AppShell — the shared dashboard-chrome composition (Move 1c). It hosts, top to\n * bottom: an app-supplied header (full-bleed), an optional per-app nav region, an\n * optional banner, and a width-disciplined scrollable content column. It also\n * folds in the two things every product page re-implements: an auth gate\n * (pending spinner / redirect-when-unauthenticated) and page state cards\n * (loading / error / forbidden).\n *\n * A BACK-OFFICE variant is supported via the optional `sidebar` slot (added for\n * Agora's merchant admin): supply a `<Sidebar>` and the body below the header /\n * nav / banner becomes a ROW — a persistent left rail beside the scrolling\n * content column — instead of the default single vertical stack. Omit `sidebar`\n * and the render tree is byte-identical to before, so every existing consumer\n * (erevna / katalogos / kefi) is untouched.\n *\n * Contract discipline (same as the rest of `@dloizides/ui-nav`): NO FM, router,\n * or store imports. The app passes wired elements, pre-localized strings, and\n * callbacks; every colour is routed through the `@dloizides/ui-feedback` theme.\n */\nimport React, { useCallback, useEffect, useState } from 'react';\n\nimport {\n ActivityIndicator,\n ScrollView,\n StyleSheet,\n Text,\n useWindowDimensions,\n View,\n type ViewStyle,\n} from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\n\nimport { APP_SHELL_SUFFIX } from './constants';\nimport {\n DEFAULT_DRAWER_LABELS,\n MenuToggle,\n MobileDrawer,\n MOBILE_BREAKPOINT,\n type DrawerLabels,\n} from './MobileDrawer';\nimport { useContentMaxWidth, type AppShellWidth } from './useContentMaxWidth';\n\nconst DEFAULT_CONTENT_PADDING = 24;\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 root: { flex: 1 },\n centerFill: { flex: 1, justifyContent: 'center', alignItems: 'center' },\n scroll: { flex: 1 },\n scrollContent: { flexGrow: 1 },\n // Mobile back-office header: the hamburger sits inline before the header slot.\n headerRow: { flexDirection: 'row', alignItems: 'center' },\n headerFill: { flex: 1 },\n // Back-office layout: a persistent left rail beside the scrolling content column.\n bodyRow: { flex: 1, flexDirection: 'row' },\n columnFull: { flex: 1 },\n columnCapped: { flex: 1, width: '100%', alignSelf: 'center' },\n // Non-flex variant used to cap the nav strip's inner content to the content\n // column so the nav aligns with the page content instead of running full-bleed.\n chromeCapped: { width: '100%', alignSelf: '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\nexport interface AppShellProps {\n /** App-supplied wired header (Topbar / AppHeader), rendered full-bleed. */\n header: React.ReactNode;\n /** Per-app nav region (kefi coral pills / erevna sidebar+drawer). */\n nav?: React.ReactNode;\n /**\n * Optional persistent LEFT RAIL (a `<Sidebar>`), for back-office surfaces. When\n * supplied, the region below header/nav/banner lays out as a row: the rail on the\n * left, the scrolling content column on the right. Omit for the default vertical\n * stack — the tree is then byte-identical to the pre-`sidebar` AppShell.\n *\n * Responsive: at/under ~768px the persistent rail is REPLACED by a hamburger (in\n * the header) that opens the same `sidebar` as an overlay drawer, so the content\n * takes the full width. Desktop (≥768px) is unchanged. No effect without `sidebar`.\n */\n sidebar?: React.ReactNode;\n /**\n * Pre-localized labels for the mobile nav drawer (only used in the `sidebar`\n * layout, below the breakpoint): the hamburger's open label/hint and the scrim's\n * close label/hint. Optional — English defaults apply. NO i18n in this package.\n */\n mobileMenu?: Partial<DrawerLabels>;\n /** Banner slot (e.g. verification-pending). */\n banner?: React.ReactNode;\n /** Content-width policy. Defaults to full-bleed. */\n width?: AppShellWidth;\n /** Content padding inside the scroll column. Defaults to 24. */\n contentPadding?: number;\n /**\n * Whether the nav strip aligns with the width-capped content column\n * (`'content'`) or runs full-bleed (`'full'`, the default). Only has an effect\n * when `width` caps the content. The header always renders full-bleed.\n */\n chromeAlignment?: 'full' | 'content';\n /** Auth gate — spinner while pending, `onRedirect` when unauthenticated. */\n gate?: { pending: boolean; authenticated: boolean; onRedirect: () => void };\n /** Page state — loading spinner card, or a titled error / forbidden card. */\n state?: {\n loading?: boolean;\n error?: ShellMessage | null;\n forbidden?: ShellMessage | null;\n };\n /** Root testID; the content region is exposed as `${testID}-content`. */\n testID: string;\n children: React.ReactNode;\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\n style={[styles.card, { backgroundColor: colors.surface, borderColor: accentColor }]}\n testID={testID}\n >\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. */\nfunction useContentBody(\n state: AppShellProps['state'],\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\nexport const AppShell = ({\n header,\n nav,\n sidebar,\n mobileMenu,\n banner,\n width = 'full',\n contentPadding = DEFAULT_CONTENT_PADDING,\n chromeAlignment = 'full',\n gate,\n state,\n testID,\n children,\n}: AppShellProps): React.ReactElement | null => {\n const { theme } = useUi();\n const primary = theme.palette.primary['500'];\n const maxWidth = useContentMaxWidth(width);\n const body = useContentBody(state, children, testID);\n\n // Back-office responsive behaviour: below the breakpoint the persistent rail\n // collapses behind a hamburger + overlay drawer (only when a `sidebar` is set).\n const { width: viewportWidth } = useWindowDimensions();\n const isNarrow = viewportWidth < MOBILE_BREAKPOINT;\n const useDrawer = sidebar !== undefined && isNarrow;\n const [drawerOpen, setDrawerOpen] = useState(false);\n const openDrawer = useCallback(() => setDrawerOpen(true), []);\n const closeDrawer = useCallback(() => setDrawerOpen(false), []);\n useEffect(() => {\n if (!isNarrow && drawerOpen) setDrawerOpen(false);\n }, [isNarrow, drawerOpen]);\n const drawerLabels: DrawerLabels = { ...DEFAULT_DRAWER_LABELS, ...mobileMenu };\n\n const isUnauthenticated = gate !== undefined && !gate.pending && !gate.authenticated;\n useEffect(() => {\n if (isUnauthenticated && gate !== undefined) gate.onRedirect();\n }, [isUnauthenticated, gate]);\n\n if (gate?.pending === true)\n return (\n <View style={[styles.root, styles.centerFill, { backgroundColor: theme.colors.background }]} testID={`${testID}${APP_SHELL_SUFFIX.pending}`}>\n <ActivityIndicator color={primary} size=\"large\" />\n </View>\n );\n\n if (isUnauthenticated) return null;\n\n const columnStyle: ViewStyle | ViewStyle[] =\n maxWidth === 'full' ? styles.columnFull : [styles.columnCapped, { maxWidth }];\n\n // Align the nav strip's inner content with the capped content column when asked\n // (and only when the content is actually capped); otherwise it runs full-bleed.\n const navInnerStyle: ViewStyle | ViewStyle[] | undefined =\n chromeAlignment === 'content' && maxWidth !== 'full'\n ? [styles.chromeCapped, { maxWidth, paddingHorizontal: contentPadding }]\n : undefined;\n\n const scroller = (\n <ScrollView\n contentContainerStyle={[styles.scrollContent, { padding: contentPadding }]}\n style={styles.scroll}\n testID={`${testID}${APP_SHELL_SUFFIX.content}`}\n >\n <View style={columnStyle}>{body}</View>\n </ScrollView>\n );\n\n // Header region: below the breakpoint (with a sidebar) the hamburger sits inline\n // before the header slot; otherwise the header wrapper is unchanged.\n const headerRegion = useDrawer ? (\n <View style={styles.headerRow} testID={`${testID}${APP_SHELL_SUFFIX.header}`}>\n <MenuToggle\n hint={drawerLabels.openHint}\n label={drawerLabels.openLabel}\n testID={`${testID}${APP_SHELL_SUFFIX.menuToggle}`}\n onOpen={openDrawer}\n />\n <View style={styles.headerFill}>{header}</View>\n </View>\n ) : (\n <View testID={`${testID}${APP_SHELL_SUFFIX.header}`}>{header}</View>\n );\n\n // Body: the persistent left rail is desktop-only. Below the breakpoint the\n // content takes the full width and the rail moves into the overlay drawer.\n const showRail = sidebar !== undefined && !isNarrow;\n\n return (\n <View style={[styles.root, { backgroundColor: theme.colors.background }]} testID={testID}>\n {headerRegion}\n {nav !== undefined ? (\n <View testID={`${testID}${APP_SHELL_SUFFIX.nav}`}>\n {navInnerStyle !== undefined ? <View style={navInnerStyle}>{nav}</View> : nav}\n </View>\n ) : null}\n {banner !== undefined ? <View testID={`${testID}${APP_SHELL_SUFFIX.banner}`}>{banner}</View> : null}\n {showRail ? (\n <View style={styles.bodyRow}>\n <View testID={`${testID}${APP_SHELL_SUFFIX.sidebar}`}>{sidebar}</View>\n {scroller}\n </View>\n ) : (\n scroller\n )}\n {useDrawer && drawerOpen ? (\n <MobileDrawer\n drawerTestID={`${testID}${APP_SHELL_SUFFIX.drawer}`}\n labels={drawerLabels}\n scrimTestID={`${testID}${APP_SHELL_SUFFIX.scrim}`}\n sidebar={sidebar}\n onClose={closeDrawer}\n />\n ) : null}\n </View>\n );\n};\n\nexport default AppShell;\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/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/roleNav.ts"],"names":["useUi","jsxs","View","jsx","Text","useState","TEXT_ON_PRIMARY","ariaCurrentProps","Pressable","useMemo","useCallback","useEffect","React","StyleSheet","MENU_GLYPH","styles","useWindowDimensions","ActivityIndicator"],"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\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 childItem: {\n borderRadius: 4,\n flexDirection: 'row',\n alignItems: 'center',\n paddingVertical: 6,\n },\n childItemText: { fontSize: 14 },\n childItemTextWithIcon: { fontSize: 14, marginLeft: 6 },\n chevron: { marginLeft: 'auto' },\n childrenContainer: { overflow: 'hidden' },\n header: {\n borderRadius: 4,\n flexDirection: 'row',\n alignItems: 'center',\n paddingVertical: 8,\n },\n headerText: { fontSize: 15, fontWeight: '600', marginLeft: 6 },\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 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\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(false);\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\n const activeItemStyle = useMemo(\n () => ({ backgroundColor: colors.border, borderRadius: ACTIVE_BORDER_RADIUS }),\n [colors.border],\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={[styles.header, headerPaddingStyle, focusRingStyle(focused, primaryColor)]}\n testID={item.testID ?? item.key}\n onBlur={() => setFocused(false)}\n onFocus={() => setFocused(true)}\n onPress={toggle}\n >\n {typeof item.renderIcon === 'function' ? (\n <View style={styles.iconWrapper}>{item.renderIcon(colors.text, NAV_ICON_SIZE)}</View>\n ) : null}\n <Text style={[styles.headerText, { color: colors.text }]}>{item.label}</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 * Sidebar — the config-driven left navigation shell promoted from the\n * byte-identical erevna-web / katalogos-web `Sidebar`. It renders a caller\n * supplied `NavItem[]` (leaf + expandable), highlights the active route, and\n * exposes header/footer slots for app-specific chrome (title, dark-mode toggle,\n * logout, notification bell). Every colour is read from the UiProvider theme.\n */\nimport React from 'react';\n\nimport { Text, View, type ViewStyle } from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\n\nimport { isRouteActive } from './isRouteActive';\nimport { NavExpandableItem } from './NavExpandableItem';\nimport { navStyles as styles } from './styles';\nimport type { NavItem } from './types';\n\nexport interface SidebarProps {\n /** Nav entries — already role-filtered / grouped by the app. */\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 menu title (heading). */\n title: string;\n /** Localized accessibility label for the navigation landmark. */\n regionLabel: string;\n /** a11y hint for a leaf item, given its label. Defaults to the label. */\n navigateHint?: (label: string) => string;\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 /** 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 /** Extra container style overrides. */\n containerStyle?: ViewStyle | ViewStyle[];\n}\n\nexport const Sidebar = ({\n items,\n pathname,\n onNavigate,\n title,\n regionLabel,\n navigateHint = (label) => label,\n expandHint = '',\n collapseHint = '',\n renderChevron,\n header,\n footer,\n containerStyle,\n}: SidebarProps): React.ReactElement => {\n const { theme } = useUi();\n const colors = theme.colors;\n\n return (\n <View\n accessibilityRole=\"none\"\n aria-label={regionLabel}\n role=\"navigation\"\n style={[\n styles.sidebarContainer,\n { backgroundColor: colors.surface, borderRightColor: colors.border },\n containerStyle,\n ]}\n >\n <Text accessibilityRole=\"header\" style={[styles.sidebarTitle, { color: colors.text }]}>\n {title}\n </Text>\n\n {header}\n\n {items.map((item) => (\n <NavExpandableItem\n key={item.key}\n collapseHint={collapseHint}\n expandHint={expandHint}\n item={item}\n navigateHint={navigateHint}\n pathname={pathname}\n renderChevron={renderChevron}\n onNavigate={onNavigate}\n />\n ))}\n\n <View style={styles.sidebarSpacer} />\n\n {footer}\n </View>\n );\n};\n\nexport { isRouteActive };\nexport default Sidebar;\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","/**\n * Topbar — the config-driven top navigation bar promoted from the byte-identical\n * erevna-web / katalogos-web `Topbar`. Structured slots replace the app-specific\n * wiring: a `left` logo slot, an optional language toggle, a notification slot,\n * an optional user block, an optional account button, and a required logout\n * action. Every colour comes from the UiProvider theme.\n *\n * Move 1c enriches this WITHOUT breaking the promoted contract: `account` now\n * accepts EITHER the legacy `TopbarAction` (today's erevna/katalogos calls) OR a\n * richer `AccountState` (displayName + muted tenant line + plan badge + upgrade\n * action). The `logout` action stays required, so every existing call keeps\n * compiling and the logout button keeps its caller-supplied testID.\n */\nimport React from 'react';\n\nimport { Text, View, type ViewStyle } from 'react-native';\n\nimport { useUi, type UiTheme } from '@dloizides/ui-feedback';\n\nimport { NAV_TEST_IDS } from './constants';\nimport { FocusableTouchable } from './FocusableTouchable';\nimport { navStyles as styles } from './styles';\n\n/** Text color for elements on primary/coloured badge backgrounds. */\nconst TEXT_ON_PRIMARY = '#ffffff';\n\nexport interface TopbarAction {\n label: string;\n hint: string;\n onPress: () => void;\n testID?: string;\n}\n\nexport interface TopbarUser {\n name: string;\n email: string;\n}\n\n/** Plan tier shown as a small badge in the rich account header. */\nexport interface AccountPlan {\n label: string;\n tone?: 'free' | 'pro' | 'enterprise';\n}\n\n/**\n * Richer account model for the header (Move 1c). Supplied via `account` as an\n * alternative to the legacy `TopbarAction` — the Topbar renders the display name\n * (tappable when `onAccount` is set), a muted tenant line, a plan badge, and an\n * `upgrade` action beside logout. No FM/router/store — everything is a\n * pre-localized string or a callback.\n */\nexport interface AccountState {\n displayName: string;\n tenantName?: string;\n plan?: AccountPlan;\n onLogout: () => void;\n onAccount?: () => void;\n upgrade?: TopbarAction;\n}\n\n/** Type guard: distinguishes the rich `AccountState` from a legacy `TopbarAction`. */\nfunction isAccountState(account: TopbarAction | AccountState): account is AccountState {\n return 'displayName' in account;\n}\n\n/** Resolve a plan badge background from its tone, routed through the theme. */\nfunction planToneColor(theme: UiTheme, tone: AccountPlan['tone']): string {\n const palette = theme.palette;\n if (tone === 'pro') return palette.primary['500'];\n if (tone === 'enterprise') return palette.accent?.['500'] ?? palette.primary['500'];\n return theme.colors.textSecondary;\n}\n\nexport interface TopbarProps {\n /** Left slot — typically the tenant logo. */\n left?: React.ReactNode;\n /** Optional language toggle. */\n language?: { label: string; hint: string; onPress: () => void };\n /** Optional notification slot (e.g. a notification bell). */\n notificationSlot?: React.ReactNode;\n /** Optional user identity block. */\n user?: TopbarUser;\n /**\n * Optional account slot. Legacy callers pass a `TopbarAction` (an account\n * button). Move-1c callers pass an `AccountState` for the richer header.\n */\n account?: TopbarAction | AccountState;\n /** Required logout action (drives the stable logout button testID). */\n logout: TopbarAction;\n /** Extra container style overrides. */\n containerStyle?: ViewStyle | ViewStyle[];\n}\n\nexport const Topbar = ({\n left,\n language,\n notificationSlot,\n user,\n account,\n logout,\n containerStyle,\n}: TopbarProps): React.ReactElement => {\n const { theme } = useUi();\n const colors = theme.colors;\n const primaryColor = theme.palette.primary['500'];\n\n const richAccount = account !== undefined && isAccountState(account) ? account : undefined;\n const legacyAccount = account !== undefined && !isAccountState(account) ? account : undefined;\n const upgrade = richAccount?.upgrade;\n\n return (\n <View\n style={[\n styles.topbarContainer,\n { borderBottomColor: colors.border, backgroundColor: colors.background },\n containerStyle,\n ]}\n >\n <View style={styles.topbarLeft}>{left}</View>\n <View style={styles.topbarRight}>\n {language ? (\n <FocusableTouchable\n accessibilityHint={language.hint}\n accessibilityLabel={language.label}\n ringColor={primaryColor}\n style={styles.topbarRowItem}\n onPress={language.onPress}\n >\n <Text style={[styles.topbarLabel, { color: colors.text }]}>{language.label}</Text>\n </FocusableTouchable>\n ) : null}\n\n {notificationSlot}\n\n {user ? (\n <View style={styles.userBlock}>\n <Text style={[styles.userName, { color: colors.text }]}>{user.name}</Text>\n <Text style={[styles.userEmail, { color: colors.textSecondary }]}>{user.email}</Text>\n </View>\n ) : null}\n\n {richAccount ? (\n <View style={styles.userBlock}>\n {richAccount.onAccount ? (\n <FocusableTouchable\n accessibilityHint={richAccount.displayName}\n accessibilityLabel={richAccount.displayName}\n ringColor={primaryColor}\n testID={NAV_TEST_IDS.accountName}\n onPress={richAccount.onAccount}\n >\n <Text style={[styles.userName, { color: colors.text }]}>{richAccount.displayName}</Text>\n </FocusableTouchable>\n ) : (\n <Text style={[styles.userName, { color: colors.text }]} testID={NAV_TEST_IDS.accountName}>\n {richAccount.displayName}\n </Text>\n )}\n\n {richAccount.tenantName !== undefined ? (\n <Text\n style={[styles.accountTenant, { color: colors.textSecondary }]}\n testID={NAV_TEST_IDS.accountTenant}\n >\n {richAccount.tenantName}\n </Text>\n ) : null}\n\n {richAccount.plan ? (\n <View\n style={[styles.planBadge, { backgroundColor: planToneColor(theme, richAccount.plan.tone) }]}\n testID={NAV_TEST_IDS.accountPlan}\n >\n <Text style={[styles.planBadgeText, { color: TEXT_ON_PRIMARY }]}>{richAccount.plan.label}</Text>\n </View>\n ) : null}\n </View>\n ) : null}\n\n {legacyAccount ? (\n <FocusableTouchable\n accessibilityHint={legacyAccount.hint}\n accessibilityLabel={legacyAccount.label}\n ringColor={primaryColor}\n style={[styles.accountBtn, { backgroundColor: primaryColor }]}\n testID={legacyAccount.testID}\n onPress={legacyAccount.onPress}\n >\n <Text style={[styles.accountText, { color: TEXT_ON_PRIMARY }]}>{legacyAccount.label}</Text>\n </FocusableTouchable>\n ) : null}\n\n {upgrade ? (\n <FocusableTouchable\n accessibilityHint={upgrade.hint}\n accessibilityLabel={upgrade.label}\n ringColor={primaryColor}\n style={[styles.accountBtn, { backgroundColor: primaryColor }]}\n testID={upgrade.testID ?? NAV_TEST_IDS.accountUpgrade}\n onPress={upgrade.onPress}\n >\n <Text style={[styles.accountText, { color: TEXT_ON_PRIMARY }]}>{upgrade.label}</Text>\n </FocusableTouchable>\n ) : null}\n\n <FocusableTouchable\n accessibilityHint={logout.hint}\n accessibilityLabel={logout.label}\n ringColor={primaryColor}\n style={[styles.accountBtn, { backgroundColor: primaryColor }]}\n testID={logout.testID}\n onPress={richAccount ? richAccount.onLogout : logout.onPress}\n >\n <Text style={[styles.accountText, { color: TEXT_ON_PRIMARY }]}>{logout.label}</Text>\n </FocusableTouchable>\n </View>\n </View>\n );\n};\n\nexport default Topbar;\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","/**\n * NavBar — the config-driven HORIZONTAL top navigation bar. It is the top-bar\n * counterpart to `Sidebar`: it renders the SAME caller-supplied `NavItem[]`\n * (already role-filtered / localized by the app) as inline links across the top\n * instead of a left rail, with an optional brand slot on the left and a free-form\n * right slot (auth link / user / logout). Below a configurable breakpoint it\n * collapses the links behind a hamburger toggle — mirroring the v1 AML console's\n * responsive `.global-nav`.\n *\n * Look + feel: each link is a rounded-pill target with the v1 `.gn-links a`\n * affordance — muted at rest, brightening text + a subtle pill background on\n * HOVER, and a solid accent pill when ACTIVE. All colours are THEME-DRIVEN from\n * the `@dloizides/ui-feedback` UiProvider (rest=`textSecondary`, hover text=`text`,\n * hover bg=`surfaceElevated`, active=`palette.primary`, ring=`palette.primary`).\n * Hover/focus are web-only (react-native-web); native stays at the rest style.\n *\n * Overflow (\"…\" priority+ menu). Above the `collapseBelow` breakpoint the links sit\n * on ONE row; when they don't all fit, a measure pass ({@link useNavOverflow} +\n * {@link computeVisibleCount}) keeps the leading items that fit inline and collapses\n * the rest behind a \"More ▾\" trigger — the shared `ModalDropdown` (see\n * {@link NavOverflowMenu}) — so no item is ever cut off. BELOW `collapseBelow` the\n * whole set still collapses into the responsive hamburger drawer (all items stacked),\n * so the two mechanisms don't overlap: hamburger for true mobile, \"…\" for the\n * in-between desktop case where only SOME items spill.\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. This is purely additive —\n * `Sidebar`/`Topbar` are unchanged and the new overflow labels are optional.\n */\nimport React, { useCallback, useMemo, useState } from 'react';\n\nimport {\n Pressable,\n Text,\n useWindowDimensions,\n View,\n type LayoutChangeEvent,\n type PressableProps,\n type ViewStyle,\n} from 'react-native';\n\nimport { useUi, UiProvider, type UiTheme } from '@dloizides/ui-feedback';\n\nimport { NAV_TEST_IDS } from './constants';\nimport { isRouteActive } from './isRouteActive';\nimport { NavBarLink, type NavBarLinkColors } from './NavBarLink';\nimport { NavOverflowMenu } from './NavOverflowMenu';\nimport { navBarStyles as styles, NAV_ICON_SIZE, NAV_LINK_GAP } from './styles';\nimport type { NavItem } from './types';\nimport { useNavOverflow } from './useNavOverflow';\nimport { useReducedMotion } from './useReducedMotion';\nimport { focusRingStyle } from './webStyle';\n\n/** DOM id linking the toggle (`aria-controls`) to the collapsible links region. */\nconst LINKS_REGION_ID = 'navbar-links-region';\n/** Collapse to a hamburger at/under this viewport width (matches v1's 760px). */\nconst DEFAULT_COLLAPSE_BELOW = 760;\n/** Default hamburger glyph (☰) when no `renderMenuIcon` is supplied. */\nconst MENU_GLYPH = '☰';\n\nexport interface NavBarProps {\n /** Nav entries — already role-filtered / grouped by the app. */\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 link, given its label. Defaults to the label. */\n navigateHint?: (label: string) => string;\n /** Left slot — typically the brand / tenant logo. */\n brand?: React.ReactNode;\n /** Right slot — free-form (auth link, user block, logout). */\n right?: React.ReactNode;\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 toggle; defaults to ☰. */\n renderMenuIcon?: (color: string, open: boolean) => React.ReactNode;\n /** Collapse the links behind a hamburger below this viewport width (default 760). */\n collapseBelow?: number;\n /**\n * Localized visible + accessible label for the \"More ▾\" overflow trigger shown when\n * the inline links don't all fit on one row (priority+ menu). Defaults to `\"More\"`.\n */\n overflowLabel?: string;\n /** Localized accessibility hint for the overflow trigger. */\n overflowHint?: string;\n /** Extra container style overrides. */\n containerStyle?: ViewStyle | ViewStyle[];\n /**\n * Optional CHROME theme override — re-provisions the `@dloizides/ui-feedback`\n * theme for the bar ONLY, so the top bar can be dark while the page below keeps\n * the light workspace theme (the AML v1-console \"dark appbar over light content\"\n * pattern). The live `t` (+ `navigate`) from the surrounding provider are\n * re-passed, so nav labels keep localizing. Omit for a bar that shares the page\n * theme. Style-only: every colour still flows through the theme — no per-app fork.\n */\n barTheme?: UiTheme;\n}\n\n/**\n * `aria-controls` links the toggle to the collapsible links region. RN's prop\n * types omit `aria-controls`, but react-native-web forwards `aria-*` to the DOM —\n * so we attach it (no `any`).\n */\nfunction ariaControlsProps(id: string): PressableProps & { 'aria-controls'?: string } {\n return { 'aria-controls': id };\n}\n\nconst NavBarInner = ({\n items,\n pathname,\n onNavigate,\n regionLabel,\n navigateHint = (label) => label,\n brand,\n right,\n menuLabel = 'Menu',\n menuHint = '',\n renderMenuIcon,\n collapseBelow = DEFAULT_COLLAPSE_BELOW,\n overflowLabel = 'More',\n overflowHint = '',\n containerStyle,\n}: Omit<NavBarProps, 'barTheme'>): React.ReactElement => {\n const { theme } = useUi();\n const colors = theme.colors;\n const primaryColor = theme.palette.primary['500'];\n const { width } = useWindowDimensions();\n const reducedMotion = useReducedMotion();\n const [open, setOpen] = useState(false);\n const [toggleFocused, setToggleFocused] = useState(false);\n const { visibleCount, setAvailableWidth, setItemWidth, setMoreWidth } = useNavOverflow(items.length, NAV_LINK_GAP);\n\n const collapsed = width < collapseBelow;\n const showLinks = !collapsed || open;\n\n const toggleMenu = useCallback(() => setOpen((v) => !v), []);\n const handlePress = useCallback(\n (route: string) => {\n setOpen(false);\n onNavigate(route);\n },\n [onNavigate],\n );\n\n // Theme-driven link colours (v1 `.gn-links a`): muted → brightened-on-hover text,\n // a subtle raised pill on hover, the accent pill when active, accent focus ring.\n const linkColors = useMemo<NavBarLinkColors>(\n () => ({\n rest: colors.textSecondary,\n hoverText: colors.text,\n hoverBg: colors.surfaceElevated,\n activeBg: primaryColor,\n ring: primaryColor,\n }),\n [colors.textSecondary, colors.text, colors.surfaceElevated, primaryColor],\n );\n\n return (\n <View\n accessibilityRole=\"none\"\n aria-label={regionLabel}\n role=\"navigation\"\n style={[\n styles.container,\n { backgroundColor: colors.surface, borderBottomColor: colors.border },\n containerStyle,\n ]}\n >\n <View style={[styles.inner, collapsed ? null : styles.innerNoWrap]}>\n {brand !== undefined ? <View style={styles.brand}>{brand}</View> : null}\n\n {collapsed ? (\n <Pressable\n accessibilityHint={menuHint}\n accessibilityLabel={menuLabel}\n accessibilityRole=\"button\"\n accessibilityState={{ expanded: open }}\n aria-expanded={open}\n style={[styles.toggle, focusRingStyle(toggleFocused, primaryColor)]}\n testID={NAV_TEST_IDS.navBarToggle}\n onBlur={() => setToggleFocused(false)}\n onFocus={() => setToggleFocused(true)}\n onPress={toggleMenu}\n {...ariaControlsProps(LINKS_REGION_ID)}\n >\n {typeof renderMenuIcon === 'function' ? (\n renderMenuIcon(colors.text, open)\n ) : (\n <Text style={[styles.toggleGlyph, { color: colors.text }]}>{MENU_GLYPH}</Text>\n )}\n </Pressable>\n ) : null}\n\n {showLinks\n ? (() => {\n const renderLink = (item: NavItem): React.ReactElement => (\n <NavBarLink\n collapsed={collapsed}\n colors={linkColors}\n iconSize={NAV_ICON_SIZE}\n isActive={isRouteActive(pathname, item.route)}\n item={item}\n navigateHint={navigateHint}\n reducedMotion={reducedMotion}\n onPress={handlePress}\n />\n );\n // Collapsed (mobile): every item stacks vertically on its own full-width line — the\n // responsive hamburger drawer. No overflow menu here; the drawer already holds them all.\n if (collapsed) {\n return (\n <View nativeID={LINKS_REGION_ID} style={styles.linksStacked} testID={NAV_TEST_IDS.navBarLinks}>\n {items.map((item) => (\n <React.Fragment key={item.key}>{renderLink(item)}</React.Fragment>\n ))}\n </View>\n );\n }\n // Expanded (desktop): ONE non-wrapping row. A measure pass keeps the leading items\n // that fit inline and collapses the rest behind the \"More ▾\" overflow trigger. Each\n // inline cell reports its natural width via onLayout; the row reports the available\n // width. Until measured, every item shows (computeVisibleCount returns the full count).\n const visibleItems = items.slice(0, visibleCount);\n const overflowItems = items.slice(visibleCount);\n return (\n <View\n nativeID={LINKS_REGION_ID}\n style={styles.linksRow}\n testID={NAV_TEST_IDS.navBarLinks}\n onLayout={(event: LayoutChangeEvent) => setAvailableWidth(event.nativeEvent.layout.width)}\n >\n {visibleItems.map((item, index) => (\n <View\n key={item.key}\n style={styles.linkCell}\n onLayout={(event: LayoutChangeEvent) => setItemWidth(index, event.nativeEvent.layout.width)}\n >\n {renderLink(item)}\n </View>\n ))}\n {overflowItems.length > 0 ? (\n <View\n style={styles.linkCell}\n onLayout={(event: LayoutChangeEvent) => setMoreWidth(event.nativeEvent.layout.width)}\n >\n <NavOverflowMenu\n colors={linkColors}\n hint={overflowHint}\n items={overflowItems}\n label={overflowLabel}\n pathname={pathname}\n testID={NAV_TEST_IDS.navBarOverflow}\n onNavigate={handlePress}\n />\n </View>\n ) : null}\n </View>\n );\n })()\n : null}\n\n {showLinks && right !== undefined ? (\n <View style={collapsed ? styles.rightStacked : styles.right}>{right}</View>\n ) : null}\n </View>\n </View>\n );\n};\n\n/**\n * `NavBar` — the horizontal top bar. When `barTheme` is supplied it re-provisions\n * the `@dloizides/ui-feedback` theme around the bar (dark bar over a light page),\n * re-passing the live `t` / `navigate` so labels keep localizing; otherwise it\n * renders directly against the surrounding theme (byte-identical to before).\n */\nexport const NavBar = ({ barTheme, ...props }: NavBarProps): React.ReactElement => {\n const { t, navigate } = useUi();\n if (barTheme === undefined) return <NavBarInner {...props} />;\n return (\n <UiProvider navigate={navigate} t={t} theme={barTheme}>\n <NavBarInner {...props} />\n </UiProvider>\n );\n};\n\nexport { isRouteActive };\nexport default NavBar;\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","/**\n * MobileDrawer — the below-the-breakpoint face of `AppShell`'s back-office\n * `sidebar` layout. On a narrow viewport (<768px) the persistent left rail would\n * starve the content column, so instead of the rail we render a hamburger toggle\n * (`MenuToggle`) in the header and slide the same `Sidebar` in as an overlay\n * drawer (a scrim + a left panel). The drawer closes on a scrim tap and on any\n * nav-item press inside the panel (web: a bubbled click on a `role=\"button\"` /\n * link element). Desktop is untouched — AppShell never mounts this above 768px.\n *\n * Contract discipline (same as the rest of `@dloizides/ui-nav`): NO FM / router /\n * store imports. Labels are pre-localized strings (English defaults, overridable\n * by the consumer via `AppShell`'s `mobileMenu` prop); every colour is read from\n * the `@dloizides/ui-feedback` UiProvider theme.\n */\nimport React, { useEffect, useRef } from 'react';\n\nimport { Pressable, StyleSheet, Text, View } from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\n\nimport { FocusableTouchable } from './FocusableTouchable';\n\n/** Collapse the persistent rail into a drawer at/under this viewport width. */\nexport const MOBILE_BREAKPOINT = 768;\n\nconst SCRIM_COLOR = 'rgba(0, 0, 0, 0.5)';\nconst MENU_GLYPH = '☰';\nconst MENU_MIN_TARGET = 44;\nconst MENU_GLYPH_FONT_SIZE = 20;\nconst MENU_TOGGLE_PADDING = 12;\nconst DRAWER_Z_INDEX = 50;\n/**\n * A nav element that, when clicked inside the open drawer, should close it.\n * react-native-web maps `accessibilityRole` -> the DOM `role`, so the Sidebar's\n * leaf `TouchableOpacity`s render as `role=\"button\"` and match here.\n */\nconst NAV_ACTIVATABLE_SELECTOR = 'a, [role=\"button\"], [role=\"link\"]';\n\n/** Pre-localized labels for the drawer's hamburger + scrim. */\nexport interface DrawerLabels {\n /** Accessible name of the hamburger that opens the drawer. */\n openLabel: string;\n /** Accessible hint of the hamburger that opens the drawer. */\n openHint: 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}\n\n/** English defaults — the consumer overrides these with localized strings. */\nexport const DEFAULT_DRAWER_LABELS: DrawerLabels = {\n openLabel: 'Menu',\n openHint: 'Open the navigation menu',\n closeLabel: 'Close menu',\n closeHint: 'Close the navigation menu',\n};\n\nconst styles = StyleSheet.create({\n overlay: { ...StyleSheet.absoluteFillObject, zIndex: DRAWER_Z_INDEX },\n scrim: { ...StyleSheet.absoluteFillObject, backgroundColor: SCRIM_COLOR },\n panel: { position: 'absolute', top: 0, bottom: 0, left: 0 },\n menuToggle: {\n minWidth: MENU_MIN_TARGET,\n minHeight: MENU_MIN_TARGET,\n alignItems: 'center',\n justifyContent: 'center',\n paddingHorizontal: MENU_TOGGLE_PADDING,\n },\n menuToggleGlyph: { fontSize: MENU_GLYPH_FONT_SIZE, fontWeight: '700' },\n});\n\nexport interface MenuToggleProps {\n label: string;\n hint: string;\n onOpen: () => void;\n testID: string;\n}\n\n/** The mobile hamburger button, rendered in the header region below the breakpoint. */\nexport const MenuToggle = ({ label, hint, onOpen, testID }: MenuToggleProps): React.ReactElement => {\n const { theme } = useUi();\n return (\n <FocusableTouchable\n accessibilityHint={hint}\n accessibilityLabel={label}\n ringColor={theme.palette.primary['500']}\n style={styles.menuToggle}\n testID={testID}\n onPress={onOpen}\n >\n <Text style={[styles.menuToggleGlyph, { color: theme.colors.text }]}>{MENU_GLYPH}</Text>\n </FocusableTouchable>\n );\n};\n\nexport interface MobileDrawerProps {\n /** The `Sidebar` slot to render inside the drawer panel. */\n sidebar: React.ReactNode;\n /** Pre-localized close (scrim) labels. */\n labels: DrawerLabels;\n /** Close the drawer. */\n onClose: () => void;\n /** testID for the drawer panel. */\n drawerTestID: string;\n /** testID for the scrim. */\n scrimTestID: string;\n}\n\n/** The open drawer overlay: a tap-to-close scrim + the sidebar panel. */\nexport const MobileDrawer = ({\n sidebar,\n labels,\n onClose,\n drawerTestID,\n scrimTestID,\n}: MobileDrawerProps): React.ReactElement => {\n const panelRef = useRef<View | null>(null);\n\n // Close on a nav-item press. The consumer wires the Sidebar's `onNavigate`\n // directly to the router, so we cannot intercept that callback; instead (on\n // web) we watch for a bubbled click on an activatable element inside the panel.\n useEffect(() => {\n const node = panelRef.current as unknown as HTMLElement | null;\n if (node === null || typeof node.addEventListener !== 'function') return undefined;\n const handleClick = (event: MouseEvent): void => {\n const target = event.target as HTMLElement | null;\n const onNavItem = target !== null && target.closest(NAV_ACTIVATABLE_SELECTOR) !== null;\n if (onNavItem) onClose();\n };\n node.addEventListener('click', handleClick);\n return () => node.removeEventListener('click', handleClick);\n }, [onClose]);\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={scrimTestID}\n onPress={onClose}\n />\n <View ref={panelRef} aria-modal role=\"dialog\" style={styles.panel} testID={drawerTestID}>\n {sidebar}\n </View>\n </View>\n );\n};\n\nexport default MobileDrawer;\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","/**\n * AppShell — the shared dashboard-chrome composition (Move 1c). It hosts, top to\n * bottom: an app-supplied header (full-bleed), an optional per-app nav region, an\n * optional banner, and a width-disciplined scrollable content column. It also\n * folds in the two things every product page re-implements: an auth gate\n * (pending spinner / redirect-when-unauthenticated) and page state cards\n * (loading / error / forbidden).\n *\n * A BACK-OFFICE variant is supported via the optional `sidebar` slot (added for\n * Agora's merchant admin): supply a `<Sidebar>` and the body below the header /\n * nav / banner becomes a ROW — a persistent left rail beside the scrolling\n * content column — instead of the default single vertical stack. Omit `sidebar`\n * and the render tree is byte-identical to before, so every existing consumer\n * (erevna / katalogos / kefi) is untouched.\n *\n * Contract discipline (same as the rest of `@dloizides/ui-nav`): NO FM, router,\n * or store imports. The app passes wired elements, pre-localized strings, and\n * callbacks; every colour is routed through the `@dloizides/ui-feedback` theme.\n */\nimport React, { useCallback, useEffect, useState } from 'react';\n\nimport {\n ActivityIndicator,\n ScrollView,\n StyleSheet,\n useWindowDimensions,\n View,\n type ViewStyle,\n} from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\n\nimport { useContentBody, type ShellState } from './appShellContent';\nimport { APP_SHELL_SUFFIX } from './constants';\nimport {\n DEFAULT_DRAWER_LABELS,\n MenuToggle,\n MobileDrawer,\n type DrawerLabels,\n} from './MobileDrawer';\nimport {\n DEFAULT_COLLAPSED_RAIL_MAX,\n RAIL_FULL_BREAKPOINT,\n resolveRailMode,\n type CollapsedRailRange,\n} from './railMode';\nimport { useContentMaxWidth, type AppShellWidth } from './useContentMaxWidth';\n\nconst DEFAULT_CONTENT_PADDING = 24;\n\nconst styles = StyleSheet.create({\n root: { flex: 1 },\n centerFill: { flex: 1, justifyContent: 'center', alignItems: 'center' },\n scroll: { flex: 1 },\n scrollContent: { flexGrow: 1 },\n // Mobile back-office header: the hamburger sits inline before the header slot.\n headerRow: { flexDirection: 'row', alignItems: 'center' },\n headerFill: { flex: 1 },\n // Back-office layout: a persistent left rail beside the scrolling content column.\n bodyRow: { flex: 1, flexDirection: 'row' },\n columnFull: { flex: 1 },\n columnCapped: { flex: 1, width: '100%', alignSelf: 'center' },\n // Non-flex variant used to cap the nav strip's inner content to the content\n // column so the nav aligns with the page content instead of running full-bleed.\n chromeCapped: { width: '100%', alignSelf: 'center' },\n});\n\nexport type { ShellMessage } from './appShellContent';\n\nexport interface AppShellProps {\n /** App-supplied wired header (Topbar / AppHeader), rendered full-bleed. */\n header: React.ReactNode;\n /** Per-app nav region (kefi coral pills / erevna sidebar+drawer). */\n nav?: React.ReactNode;\n /**\n * Optional persistent LEFT RAIL (a `<Sidebar>`), for back-office surfaces. When\n * supplied, the region below header/nav/banner lays out as a row: the rail on the\n * left, the scrolling content column on the right. Omit for the default vertical\n * stack — the tree is then byte-identical to the pre-`sidebar` AppShell.\n *\n * Responsive: at/under ~768px the persistent rail is REPLACED by a hamburger (in\n * the header) that opens the same `sidebar` as an overlay drawer, so the content\n * takes the full width. Desktop (≥768px) is unchanged. No effect without `sidebar`.\n */\n sidebar?: React.ReactNode;\n /**\n * Optional intermediate COLLAPSED (icon-only) rail — opts the `sidebar` layout\n * into a THREE-tier responsive scheme (erevna / katalogos): the full `sidebar`\n * on desktop, this collapsed rail on a tablet-width band, and the overlay drawer\n * (hosting the full `sidebar`) on a phone. Omit it and the layout stays the\n * unchanged two-tier scheme (full rail ≥768px, drawer below). No effect without\n * `sidebar`. Exposed as `${testID}${APP_SHELL_SUFFIX.collapsedSidebar}`.\n */\n collapsedSidebar?: React.ReactNode;\n /**\n * The viewport band `[min, max)` in which `collapsedSidebar` shows: at/above\n * `max` the full rail shows, below `min` the drawer shows. Defaults to\n * `{ min: 768, max: 1024 }`. Only consulted when `collapsedSidebar` is supplied.\n */\n collapsedRailRange?: CollapsedRailRange;\n /**\n * Pre-localized labels for the mobile nav drawer (only used in the `sidebar`\n * layout, below the breakpoint): the hamburger's open label/hint and the scrim's\n * close label/hint. Optional — English defaults apply. NO i18n in this package.\n */\n mobileMenu?: Partial<DrawerLabels>;\n /** Banner slot (e.g. verification-pending). */\n banner?: React.ReactNode;\n /** Content-width policy. Defaults to full-bleed. */\n width?: AppShellWidth;\n /** Content padding inside the scroll column. Defaults to 24. */\n contentPadding?: number;\n /**\n * Whether the nav strip aligns with the width-capped content column\n * (`'content'`) or runs full-bleed (`'full'`, the default). Only has an effect\n * when `width` caps the content. The header always renders full-bleed.\n */\n chromeAlignment?: 'full' | 'content';\n /** Auth gate — spinner while pending, `onRedirect` when unauthenticated. */\n gate?: { pending: boolean; authenticated: boolean; onRedirect: () => void };\n /** Page state — loading spinner card, or a titled error / forbidden card. */\n state?: ShellState;\n /** Root testID; the content region is exposed as `${testID}-content`. */\n testID: string;\n children: React.ReactNode;\n}\n\nexport const AppShell = ({\n header,\n nav,\n sidebar,\n collapsedSidebar,\n collapsedRailRange,\n mobileMenu,\n banner,\n width = 'full',\n contentPadding = DEFAULT_CONTENT_PADDING,\n chromeAlignment = 'full',\n gate,\n state,\n testID,\n children,\n}: AppShellProps): React.ReactElement | null => {\n const { theme } = useUi();\n const primary = theme.palette.primary['500'];\n const maxWidth = useContentMaxWidth(width);\n const body = useContentBody(state, children, testID);\n\n // Back-office responsive behaviour: the rail takes one of three faces by\n // viewport — the persistent full rail, an optional intermediate collapsed\n // (icon-only) rail, or an overlay drawer. Without `collapsedSidebar` this stays\n // the unchanged two-tier scheme (full rail ≥768px, drawer below).\n const { width: viewportWidth } = useWindowDimensions();\n const railRange: CollapsedRailRange = collapsedRailRange ?? { min: RAIL_FULL_BREAKPOINT, max: DEFAULT_COLLAPSED_RAIL_MAX };\n const railMode = resolveRailMode({\n viewport: viewportWidth,\n hasSidebar: sidebar !== undefined,\n hasCollapsed: collapsedSidebar !== undefined,\n range: railRange,\n });\n const useDrawer = railMode === 'drawer';\n const [drawerOpen, setDrawerOpen] = useState(false);\n const openDrawer = useCallback(() => setDrawerOpen(true), []);\n const closeDrawer = useCallback(() => setDrawerOpen(false), []);\n useEffect(() => {\n if (!useDrawer && drawerOpen) setDrawerOpen(false);\n }, [useDrawer, drawerOpen]);\n const drawerLabels: DrawerLabels = { ...DEFAULT_DRAWER_LABELS, ...mobileMenu };\n\n const isUnauthenticated = gate !== undefined && !gate.pending && !gate.authenticated;\n useEffect(() => {\n if (isUnauthenticated && gate !== undefined) gate.onRedirect();\n }, [isUnauthenticated, gate]);\n\n if (gate?.pending === true)\n return (\n <View style={[styles.root, styles.centerFill, { backgroundColor: theme.colors.background }]} testID={`${testID}${APP_SHELL_SUFFIX.pending}`}>\n <ActivityIndicator color={primary} size=\"large\" />\n </View>\n );\n\n if (isUnauthenticated) return null;\n\n const columnStyle: ViewStyle | ViewStyle[] =\n maxWidth === 'full' ? styles.columnFull : [styles.columnCapped, { maxWidth }];\n\n // Align the nav strip's inner content with the capped content column when asked\n // (and only when the content is actually capped); otherwise it runs full-bleed.\n const navInnerStyle: ViewStyle | ViewStyle[] | undefined =\n chromeAlignment === 'content' && maxWidth !== 'full'\n ? [styles.chromeCapped, { maxWidth, paddingHorizontal: contentPadding }]\n : undefined;\n\n const scroller = (\n <ScrollView\n contentContainerStyle={[styles.scrollContent, { padding: contentPadding }]}\n style={styles.scroll}\n testID={`${testID}${APP_SHELL_SUFFIX.content}`}\n >\n <View style={columnStyle}>{body}</View>\n </ScrollView>\n );\n\n // Header region: below the breakpoint (with a sidebar) the hamburger sits inline\n // before the header slot; otherwise the header wrapper is unchanged.\n const headerRegion = useDrawer ? (\n <View style={styles.headerRow} testID={`${testID}${APP_SHELL_SUFFIX.header}`}>\n <MenuToggle\n hint={drawerLabels.openHint}\n label={drawerLabels.openLabel}\n testID={`${testID}${APP_SHELL_SUFFIX.menuToggle}`}\n onOpen={openDrawer}\n />\n <View style={styles.headerFill}>{header}</View>\n </View>\n ) : (\n <View testID={`${testID}${APP_SHELL_SUFFIX.header}`}>{header}</View>\n );\n\n // Body: the persistent rail (full or collapsed) sits beside the content in a\n // row; in drawer mode the content takes the full width and the rail moves into\n // the overlay drawer.\n const railRegion =\n railMode === 'full' ? (\n <View testID={`${testID}${APP_SHELL_SUFFIX.sidebar}`}>{sidebar}</View>\n ) : railMode === 'collapsed' ? (\n <View testID={`${testID}${APP_SHELL_SUFFIX.collapsedSidebar}`}>{collapsedSidebar}</View>\n ) : null;\n\n return (\n <View style={[styles.root, { backgroundColor: theme.colors.background }]} testID={testID}>\n {headerRegion}\n {nav !== undefined ? (\n <View testID={`${testID}${APP_SHELL_SUFFIX.nav}`}>\n {navInnerStyle !== undefined ? <View style={navInnerStyle}>{nav}</View> : nav}\n </View>\n ) : null}\n {banner !== undefined ? <View testID={`${testID}${APP_SHELL_SUFFIX.banner}`}>{banner}</View> : null}\n {railRegion !== null ? (\n <View style={styles.bodyRow}>\n {railRegion}\n {scroller}\n </View>\n ) : (\n scroller\n )}\n {useDrawer && drawerOpen ? (\n <MobileDrawer\n drawerTestID={`${testID}${APP_SHELL_SUFFIX.drawer}`}\n labels={drawerLabels}\n scrimTestID={`${testID}${APP_SHELL_SUFFIX.scrim}`}\n sidebar={sidebar}\n onClose={closeDrawer}\n />\n ) : null}\n </View>\n );\n};\n\nexport default AppShell;\n","/**\n * CollapsedRail — the icon-only vertical rail for the intermediate (tablet) tier\n * of `AppShell`'s three-tier responsive layout (the erevna / katalogos collapsed\n * rail). It renders the SAME caller-supplied `NavItem[]` as `Sidebar`, but as a\n * narrow strip of icon buttons: each item shows its `renderIcon` (or a first-letter\n * glyph fallback), labelled for assistive tech, with the active route highlighted.\n * Optional `header` / `footer` slots carry app chrome (a home shortcut, a\n * dark-mode toggle, logout) top and bottom.\n *\n * A collapsed rail cannot expand a section inline, so pressing ANY item — leaf or\n * parent — navigates to its `route`; an app that wants a parent to open the full\n * drawer instead can special-case that in its `onNavigate`.\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 { collapsedRailStyles as styles } from './styles';\nimport type { NavItem } from './types';\n\n/** Icon size for a collapsed-rail item. */\nconst COLLAPSED_ICON_SIZE = 22;\n\nexport interface CollapsedRailProps {\n /** Nav entries — the same role-filtered `NavItem[]` the full `Sidebar` renders. */\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 an item, given its label. Defaults to the label. */\n navigateHint?: (label: string) => 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 /** Extra container style overrides. */\n containerStyle?: ViewStyle | ViewStyle[];\n}\n\n/** First character of a label, uppercased — the icon fallback glyph. */\nfunction glyphFor(label: string): string {\n return label.trim().charAt(0).toUpperCase();\n}\n\nexport const CollapsedRail = ({\n items,\n pathname,\n onNavigate,\n regionLabel,\n navigateHint = (label) => label,\n header,\n footer,\n containerStyle,\n}: CollapsedRailProps): React.ReactElement => {\n const { theme } = useUi();\n const colors = theme.colors;\n const primaryColor = theme.palette.primary['500'];\n\n return (\n <View\n accessibilityRole=\"none\"\n aria-label={regionLabel}\n role=\"navigation\"\n style={[\n styles.container,\n { backgroundColor: colors.surface, borderRightColor: colors.border },\n containerStyle,\n ]}\n >\n {header !== undefined ? <View style={styles.slot}>{header}</View> : null}\n\n {items.map((item) => {\n const active = isRouteActive(pathname, item.route);\n const iconColor = active ? primaryColor : colors.textSecondary;\n return (\n <FocusableTouchable\n key={item.key}\n accessibilityHint={navigateHint(item.label)}\n accessibilityLabel={item.label}\n ringColor={primaryColor}\n style={[styles.item, active ? { backgroundColor: colors.border } : undefined]}\n testID={item.testID ?? item.key}\n onPress={() => onNavigate(item.route)}\n >\n {typeof item.renderIcon === 'function' ? (\n item.renderIcon(iconColor, COLLAPSED_ICON_SIZE)\n ) : (\n <Text style={[styles.glyph, { color: iconColor }]}>{glyphFor(item.label)}</Text>\n )}\n </FocusableTouchable>\n );\n })}\n\n <View style={styles.spacer} />\n\n {footer !== undefined ? <View style={styles.slot}>{footer}</View> : null}\n </View>\n );\n};\n\nexport default CollapsedRail;\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 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'` unless supplied (a `'side'` app may still pass\n * a `topBar` with empty `items` for its brand + user header).\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/** Should the top bar render? Yes for `'top'`/`'both'`, or when a header/topBar is supplied. */\nfunction wantsTopBar(layout: NavShellLayout, hasHeader: boolean, hasTopBar: boolean): boolean {\n return layout === 'top' || layout === 'both' || hasHeader || (layout === 'side' && hasTopBar);\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, topBar !== 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 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 * 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"]}
|