@dloizides/ui-nav 1.1.1 → 1.2.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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.2.0
4
+
5
+ Add `NavBar` — a config-driven **horizontal top navigation bar**, the top-bar
6
+ counterpart to `Sidebar`. It renders the same caller-supplied `NavItem[]` as inline
7
+ links across the top (brand left slot + inline links + free-form right slot), with
8
+ an active-link highlight (`aria-current="page"`) and a responsive collapse to a
9
+ hamburger toggle below a configurable breakpoint (`collapseBelow`, default `760`) —
10
+ mirroring the v1 AML console `.global-nav`. Theme-driven (UiProvider colours),
11
+ `role="navigation"` landmark, keyboard-operable links. Purely additive: `Sidebar`,
12
+ `Topbar`, `AppShell`, and the role-gating helpers are unchanged. New `NAV_TEST_IDS`
13
+ entries `navBarToggle` / `navBarLinks`.
14
+
3
15
  ## 1.0.0
4
16
 
5
17
  Initial release. `Sidebar` (leaf + expandable items, active-route highlight, header/footer
package/README.md CHANGED
@@ -46,6 +46,37 @@ const items: NavItem[] = buildItems(); // your role-filtered / grouped items
46
46
  />
47
47
  ```
48
48
 
49
+ ### Horizontal top bar (`NavBar`)
50
+
51
+ Prefer the nav links **on top** (a horizontal menu bar) instead of the left rail?
52
+ `NavBar` renders the SAME `NavItem[]` model horizontally — brand slot on the left,
53
+ inline links, a free-form right slot (auth / user / logout) — and collapses the
54
+ links behind a hamburger below a configurable breakpoint (default `760`, matching
55
+ the v1 AML console `.global-nav`). It is purely additive; `Sidebar` is unchanged.
56
+
57
+ ```tsx
58
+ import { NavBar, type NavItem } from '@dloizides/ui-nav';
59
+
60
+ <NavBar
61
+ items={items} // same role-filtered NavItem[] as Sidebar
62
+ pathname={usePathname()}
63
+ onNavigate={(route) => router.push(route)}
64
+ regionLabel={FM('accessibility.navigationRegion')}
65
+ navigateHint={(label) => FM('menu.navigateToHint', label)}
66
+ brand={<BrandLogo />} // left slot
67
+ right={<AuthLink />} // right slot (auth / user / logout)
68
+ menuLabel={FM('menu.toggle')} // a11y label for the hamburger
69
+ menuHint={FM('menu.toggleHint')}
70
+ collapseBelow={760} // hamburger under this viewport width
71
+ />
72
+ ```
73
+
74
+ An app that renders a `Sidebar` today switches to a top bar by swapping the
75
+ `Sidebar` element for `NavBar` (same `items` / `pathname` / `onNavigate`) — e.g.
76
+ the AML v2 app drops `NavBar` into the `AppShell` `header` (or `nav`) slot so its
77
+ links sit across the top like the rest of the console. Active links expose
78
+ `aria-current="page"`; the container is a `role="navigation"` landmark.
79
+
49
80
  ### Role gating
50
81
 
51
82
  `accessibleNavItems(user, roleRouteTable, translate)` builds the `NavItem[]` a user's roles
package/dist/index.d.mts CHANGED
@@ -145,6 +145,49 @@ interface TopbarProps {
145
145
  }
146
146
  declare const Topbar: ({ left, language, notificationSlot, user, account, logout, containerStyle, }: TopbarProps) => React.ReactElement;
147
147
 
148
+ /**
149
+ * NavBar — the config-driven HORIZONTAL top navigation bar. It is the top-bar
150
+ * counterpart to `Sidebar`: it renders the SAME caller-supplied `NavItem[]`
151
+ * (already role-filtered / localized by the app) as inline links across the top
152
+ * instead of a left rail, with an optional brand slot on the left and a free-form
153
+ * right slot (auth link / user / logout). Below a configurable breakpoint it
154
+ * collapses the links behind a hamburger toggle — mirroring the v1 AML console's
155
+ * responsive `.global-nav`.
156
+ *
157
+ * Contract discipline (same as the rest of `@dloizides/ui-nav`): NO FM, router,
158
+ * icon set, or store imports. Labels are pre-localized strings, icons are render
159
+ * slots, and every colour is read from the `@dloizides/ui-feedback` UiProvider
160
+ * theme. This is purely additive — `Sidebar`/`Topbar` are unchanged.
161
+ */
162
+
163
+ interface NavBarProps {
164
+ /** Nav entries — already role-filtered / grouped by the app. */
165
+ items: NavItem[];
166
+ /** Current active route/path. */
167
+ pathname: string;
168
+ /** Navigation callback — receives a `NavItem.route`. */
169
+ onNavigate: (route: string) => void;
170
+ /** Localized accessibility label for the navigation landmark. */
171
+ regionLabel: string;
172
+ /** a11y hint for a link, given its label. Defaults to the label. */
173
+ navigateHint?: (label: string) => string;
174
+ /** Left slot — typically the brand / tenant logo. */
175
+ brand?: React.ReactNode;
176
+ /** Right slot — free-form (auth link, user block, logout). */
177
+ right?: React.ReactNode;
178
+ /** Localized accessibility label for the responsive menu toggle. */
179
+ menuLabel?: string;
180
+ /** Localized accessibility hint for the responsive menu toggle. */
181
+ menuHint?: string;
182
+ /** Optional custom glyph renderer for the toggle; defaults to ☰. */
183
+ renderMenuIcon?: (color: string, open: boolean) => React.ReactNode;
184
+ /** Collapse the links behind a hamburger below this viewport width (default 760). */
185
+ collapseBelow?: number;
186
+ /** Extra container style overrides. */
187
+ containerStyle?: ViewStyle | ViewStyle[];
188
+ }
189
+ declare const NavBar: ({ items, pathname, onNavigate, regionLabel, navigateHint, brand, right, menuLabel, menuHint, renderMenuIcon, collapseBelow, containerStyle, }: NavBarProps) => React.ReactElement;
190
+
148
191
  /** Content-width policy: a capped column, optionally wider past a viewport breakpoint, or full-bleed. */
149
192
  type AppShellWidth = {
150
193
  max: number;
@@ -229,6 +272,10 @@ declare const NAV_TEST_IDS: {
229
272
  readonly accountPlan: "topbar-account-plan";
230
273
  /** default testID for the rich header's upgrade action (overridable per-action). */
231
274
  readonly accountUpgrade: "topbar-account-upgrade";
275
+ /** responsive hamburger toggle in the horizontal NavBar (shown below the breakpoint). */
276
+ readonly navBarToggle: "navbar-toggle";
277
+ /** links container in the horizontal NavBar. */
278
+ readonly navBarLinks: "navbar-links";
232
279
  };
233
280
  /** Suffixes appended to an `AppShell`'s required `testID` to name its regions. */
234
281
  declare const APP_SHELL_SUFFIX: {
@@ -408,4 +455,4 @@ declare const NAV_ICON_SIZE = 14;
408
455
  /** Chevron icon size for expandable sections. */
409
456
  declare const CHEVRON_ICON_SIZE = 12;
410
457
 
411
- export { ACTIVE_BORDER_RADIUS, APP_SHELL_SUFFIX, type AccountPlan, type AccountState, AppShell, type AppShellProps, type AppShellWidth, BASE_INDENT, CHEVRON_ICON_SIZE, NAV_ICON_SIZE, NAV_TEST_IDS, NavExpandableItem, type NavExpandableItemProps, type NavItem, type NavUser, type ShellMessage, Sidebar, type SidebarProps, Topbar, type TopbarAction, type TopbarProps, type TopbarUser, accessibleNavItems, expandableStyles, isRouteActive, navStyles, resolveContentMaxWidth, roleRoutesToNavItems, useContentMaxWidth };
458
+ export { ACTIVE_BORDER_RADIUS, APP_SHELL_SUFFIX, type AccountPlan, type AccountState, AppShell, type AppShellProps, type AppShellWidth, BASE_INDENT, CHEVRON_ICON_SIZE, NAV_ICON_SIZE, NAV_TEST_IDS, NavBar, type NavBarProps, NavExpandableItem, type NavExpandableItemProps, type NavItem, type NavUser, type ShellMessage, Sidebar, type SidebarProps, Topbar, type TopbarAction, type TopbarProps, type TopbarUser, accessibleNavItems, expandableStyles, isRouteActive, navStyles, resolveContentMaxWidth, roleRoutesToNavItems, useContentMaxWidth };
package/dist/index.d.ts CHANGED
@@ -145,6 +145,49 @@ interface TopbarProps {
145
145
  }
146
146
  declare const Topbar: ({ left, language, notificationSlot, user, account, logout, containerStyle, }: TopbarProps) => React.ReactElement;
147
147
 
148
+ /**
149
+ * NavBar — the config-driven HORIZONTAL top navigation bar. It is the top-bar
150
+ * counterpart to `Sidebar`: it renders the SAME caller-supplied `NavItem[]`
151
+ * (already role-filtered / localized by the app) as inline links across the top
152
+ * instead of a left rail, with an optional brand slot on the left and a free-form
153
+ * right slot (auth link / user / logout). Below a configurable breakpoint it
154
+ * collapses the links behind a hamburger toggle — mirroring the v1 AML console's
155
+ * responsive `.global-nav`.
156
+ *
157
+ * Contract discipline (same as the rest of `@dloizides/ui-nav`): NO FM, router,
158
+ * icon set, or store imports. Labels are pre-localized strings, icons are render
159
+ * slots, and every colour is read from the `@dloizides/ui-feedback` UiProvider
160
+ * theme. This is purely additive — `Sidebar`/`Topbar` are unchanged.
161
+ */
162
+
163
+ interface NavBarProps {
164
+ /** Nav entries — already role-filtered / grouped by the app. */
165
+ items: NavItem[];
166
+ /** Current active route/path. */
167
+ pathname: string;
168
+ /** Navigation callback — receives a `NavItem.route`. */
169
+ onNavigate: (route: string) => void;
170
+ /** Localized accessibility label for the navigation landmark. */
171
+ regionLabel: string;
172
+ /** a11y hint for a link, given its label. Defaults to the label. */
173
+ navigateHint?: (label: string) => string;
174
+ /** Left slot — typically the brand / tenant logo. */
175
+ brand?: React.ReactNode;
176
+ /** Right slot — free-form (auth link, user block, logout). */
177
+ right?: React.ReactNode;
178
+ /** Localized accessibility label for the responsive menu toggle. */
179
+ menuLabel?: string;
180
+ /** Localized accessibility hint for the responsive menu toggle. */
181
+ menuHint?: string;
182
+ /** Optional custom glyph renderer for the toggle; defaults to ☰. */
183
+ renderMenuIcon?: (color: string, open: boolean) => React.ReactNode;
184
+ /** Collapse the links behind a hamburger below this viewport width (default 760). */
185
+ collapseBelow?: number;
186
+ /** Extra container style overrides. */
187
+ containerStyle?: ViewStyle | ViewStyle[];
188
+ }
189
+ declare const NavBar: ({ items, pathname, onNavigate, regionLabel, navigateHint, brand, right, menuLabel, menuHint, renderMenuIcon, collapseBelow, containerStyle, }: NavBarProps) => React.ReactElement;
190
+
148
191
  /** Content-width policy: a capped column, optionally wider past a viewport breakpoint, or full-bleed. */
149
192
  type AppShellWidth = {
150
193
  max: number;
@@ -229,6 +272,10 @@ declare const NAV_TEST_IDS: {
229
272
  readonly accountPlan: "topbar-account-plan";
230
273
  /** default testID for the rich header's upgrade action (overridable per-action). */
231
274
  readonly accountUpgrade: "topbar-account-upgrade";
275
+ /** responsive hamburger toggle in the horizontal NavBar (shown below the breakpoint). */
276
+ readonly navBarToggle: "navbar-toggle";
277
+ /** links container in the horizontal NavBar. */
278
+ readonly navBarLinks: "navbar-links";
232
279
  };
233
280
  /** Suffixes appended to an `AppShell`'s required `testID` to name its regions. */
234
281
  declare const APP_SHELL_SUFFIX: {
@@ -408,4 +455,4 @@ declare const NAV_ICON_SIZE = 14;
408
455
  /** Chevron icon size for expandable sections. */
409
456
  declare const CHEVRON_ICON_SIZE = 12;
410
457
 
411
- export { ACTIVE_BORDER_RADIUS, APP_SHELL_SUFFIX, type AccountPlan, type AccountState, AppShell, type AppShellProps, type AppShellWidth, BASE_INDENT, CHEVRON_ICON_SIZE, NAV_ICON_SIZE, NAV_TEST_IDS, NavExpandableItem, type NavExpandableItemProps, type NavItem, type NavUser, type ShellMessage, Sidebar, type SidebarProps, Topbar, type TopbarAction, type TopbarProps, type TopbarUser, accessibleNavItems, expandableStyles, isRouteActive, navStyles, resolveContentMaxWidth, roleRoutesToNavItems, useContentMaxWidth };
458
+ export { ACTIVE_BORDER_RADIUS, APP_SHELL_SUFFIX, type AccountPlan, type AccountState, AppShell, type AppShellProps, type AppShellWidth, BASE_INDENT, CHEVRON_ICON_SIZE, NAV_ICON_SIZE, NAV_TEST_IDS, NavBar, type NavBarProps, NavExpandableItem, type NavExpandableItemProps, type NavItem, type NavUser, type ShellMessage, Sidebar, type SidebarProps, Topbar, type TopbarAction, type TopbarProps, type TopbarUser, accessibleNavItems, expandableStyles, isRouteActive, navStyles, resolveContentMaxWidth, roleRoutesToNavItems, useContentMaxWidth };
package/dist/index.js CHANGED
@@ -61,6 +61,71 @@ var navStyles = reactNative.StyleSheet.create({
61
61
  planBadge: { marginTop: 2, paddingHorizontal: 8, paddingVertical: 2, borderRadius: 10, alignSelf: "flex-end" },
62
62
  planBadgeText: { fontSize: 11, fontWeight: "700" }
63
63
  });
64
+ var navBarStyles = reactNative.StyleSheet.create({
65
+ // --- Horizontal top NavBar ---
66
+ container: {
67
+ borderBottomWidth: 1,
68
+ paddingHorizontal: 12
69
+ },
70
+ inner: {
71
+ minHeight: 56,
72
+ flexDirection: "row",
73
+ alignItems: "center",
74
+ flexWrap: "wrap",
75
+ columnGap: 8,
76
+ rowGap: 4,
77
+ paddingVertical: 8
78
+ },
79
+ brand: { marginRight: 16 },
80
+ toggle: {
81
+ marginLeft: "auto",
82
+ paddingHorizontal: 10,
83
+ paddingVertical: 6,
84
+ borderRadius: 4
85
+ },
86
+ toggleGlyph: { fontSize: 20, fontWeight: "700" },
87
+ links: {
88
+ flexDirection: "row",
89
+ alignItems: "center",
90
+ flexWrap: "wrap",
91
+ columnGap: 4,
92
+ rowGap: 4
93
+ },
94
+ // Collapsed (below breakpoint): links drop onto their own full-width line,
95
+ // stacked vertically — mirrors the v1 `.gn-links` responsive behaviour.
96
+ linksStacked: {
97
+ width: "100%",
98
+ flexBasis: "100%",
99
+ flexDirection: "column",
100
+ alignItems: "stretch",
101
+ rowGap: 2,
102
+ marginTop: 8
103
+ },
104
+ link: {
105
+ paddingVertical: 8,
106
+ paddingHorizontal: 14,
107
+ borderRadius: 8,
108
+ flexDirection: "row",
109
+ alignItems: "center"
110
+ },
111
+ linkStacked: { paddingVertical: 10 },
112
+ linkIcon: { marginRight: 6 },
113
+ linkText: { fontSize: 15, fontWeight: "600" },
114
+ right: {
115
+ marginLeft: "auto",
116
+ flexDirection: "row",
117
+ alignItems: "center",
118
+ columnGap: 8
119
+ },
120
+ rightStacked: {
121
+ width: "100%",
122
+ flexBasis: "100%",
123
+ marginTop: 4,
124
+ flexDirection: "row",
125
+ alignItems: "center",
126
+ columnGap: 8
127
+ }
128
+ });
64
129
  var expandableStyles = reactNative.StyleSheet.create({
65
130
  childItem: {
66
131
  borderRadius: 4,
@@ -226,7 +291,11 @@ var NAV_TEST_IDS = {
226
291
  /** small plan badge (free / pro / enterprise). */
227
292
  accountPlan: "topbar-account-plan",
228
293
  /** default testID for the rich header's upgrade action (overridable per-action). */
229
- accountUpgrade: "topbar-account-upgrade"
294
+ accountUpgrade: "topbar-account-upgrade",
295
+ /** responsive hamburger toggle in the horizontal NavBar (shown below the breakpoint). */
296
+ navBarToggle: "navbar-toggle",
297
+ /** links container in the horizontal NavBar. */
298
+ navBarLinks: "navbar-links"
230
299
  };
231
300
  var APP_SHELL_SUFFIX = {
232
301
  content: "-content",
@@ -361,6 +430,102 @@ var Topbar = ({
361
430
  }
362
431
  );
363
432
  };
433
+ var TEXT_ON_PRIMARY2 = "#ffffff";
434
+ var DEFAULT_COLLAPSE_BELOW = 760;
435
+ var MENU_GLYPH = "\u2630";
436
+ function activeAriaProps(isActive) {
437
+ return isActive ? { "aria-current": "page" } : {};
438
+ }
439
+ var NavBar = ({
440
+ items,
441
+ pathname,
442
+ onNavigate,
443
+ regionLabel,
444
+ navigateHint = (label) => label,
445
+ brand,
446
+ right,
447
+ menuLabel = "Menu",
448
+ menuHint = "",
449
+ renderMenuIcon,
450
+ collapseBelow = DEFAULT_COLLAPSE_BELOW,
451
+ containerStyle
452
+ }) => {
453
+ const { theme } = uiFeedback.useUi();
454
+ const colors = theme.colors;
455
+ const primaryColor = theme.palette.primary["500"];
456
+ const { width } = reactNative.useWindowDimensions();
457
+ const [open, setOpen] = react.useState(false);
458
+ const collapsed = width < collapseBelow;
459
+ const showLinks = !collapsed || open;
460
+ const toggleMenu = react.useCallback(() => setOpen((v) => !v), []);
461
+ const handlePress = react.useCallback(
462
+ (route) => {
463
+ setOpen(false);
464
+ onNavigate(route);
465
+ },
466
+ [onNavigate]
467
+ );
468
+ const activeLinkStyle = react.useMemo(
469
+ () => ({ backgroundColor: primaryColor, borderRadius: ACTIVE_BORDER_RADIUS }),
470
+ [primaryColor]
471
+ );
472
+ const renderLink = (item) => {
473
+ const isActive = isRouteActive(pathname, item.route);
474
+ const textColor = isActive ? TEXT_ON_PRIMARY2 : colors.textSecondary;
475
+ return /* @__PURE__ */ jsxRuntime.jsxs(
476
+ reactNative.TouchableOpacity,
477
+ {
478
+ accessible: true,
479
+ accessibilityHint: navigateHint(item.label),
480
+ accessibilityLabel: item.label,
481
+ accessibilityRole: "link",
482
+ accessibilityState: { selected: isActive },
483
+ style: [navBarStyles.link, collapsed ? navBarStyles.linkStacked : void 0, isActive ? activeLinkStyle : void 0],
484
+ testID: item.testID ?? item.key,
485
+ onPress: () => handlePress(item.route),
486
+ ...activeAriaProps(isActive),
487
+ children: [
488
+ typeof item.renderIcon === "function" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: navBarStyles.linkIcon, children: item.renderIcon(textColor, NAV_ICON_SIZE) }) : null,
489
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [navBarStyles.linkText, { color: textColor }], children: item.label })
490
+ ]
491
+ },
492
+ item.key
493
+ );
494
+ };
495
+ return /* @__PURE__ */ jsxRuntime.jsx(
496
+ reactNative.View,
497
+ {
498
+ accessibilityRole: "none",
499
+ "aria-label": regionLabel,
500
+ role: "navigation",
501
+ style: [
502
+ navBarStyles.container,
503
+ { backgroundColor: colors.surface, borderBottomColor: colors.border },
504
+ containerStyle
505
+ ],
506
+ children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: navBarStyles.inner, children: [
507
+ brand !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: navBarStyles.brand, children: brand }) : null,
508
+ collapsed ? /* @__PURE__ */ jsxRuntime.jsx(
509
+ reactNative.TouchableOpacity,
510
+ {
511
+ accessible: true,
512
+ accessibilityHint: menuHint,
513
+ accessibilityLabel: menuLabel,
514
+ accessibilityRole: "button",
515
+ accessibilityState: { expanded: open },
516
+ "aria-expanded": open,
517
+ style: navBarStyles.toggle,
518
+ testID: NAV_TEST_IDS.navBarToggle,
519
+ onPress: toggleMenu,
520
+ children: typeof renderMenuIcon === "function" ? renderMenuIcon(colors.text, open) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [navBarStyles.toggleGlyph, { color: colors.text }], children: MENU_GLYPH })
521
+ }
522
+ ) : null,
523
+ showLinks ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: collapsed ? navBarStyles.linksStacked : navBarStyles.links, testID: NAV_TEST_IDS.navBarLinks, children: items.map(renderLink) }) : null,
524
+ showLinks && right !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: collapsed ? navBarStyles.rightStacked : navBarStyles.right, children: right }) : null
525
+ ] })
526
+ }
527
+ );
528
+ };
364
529
  function resolveContentMaxWidth(width, viewport) {
365
530
  if (width === "full") return "full";
366
531
  const wideMinViewport = width.wideMinViewport ?? Number.POSITIVE_INFINITY;
@@ -485,6 +650,7 @@ exports.BASE_INDENT = BASE_INDENT;
485
650
  exports.CHEVRON_ICON_SIZE = CHEVRON_ICON_SIZE;
486
651
  exports.NAV_ICON_SIZE = NAV_ICON_SIZE;
487
652
  exports.NAV_TEST_IDS = NAV_TEST_IDS;
653
+ exports.NavBar = NavBar;
488
654
  exports.NavExpandableItem = NavExpandableItem;
489
655
  exports.Sidebar = Sidebar;
490
656
  exports.Topbar = Topbar;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/isRouteActive.ts","../src/styles.ts","../src/NavExpandableItem.tsx","../src/Sidebar.tsx","../src/constants.ts","../src/Topbar.tsx","../src/useContentMaxWidth.ts","../src/AppShell.tsx","../src/roleNav.ts"],"names":["StyleSheet","useState","useUi","useCallback","useMemo","jsxs","TouchableOpacity","jsx","View","Text","useWindowDimensions","ActivityIndicator","useEffect","ScrollView","resolveAccessibleRoutes"],"mappings":"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","file":"index.js","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 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 * 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 } 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';\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 { 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 style={[styles.childItem, paddingStyle, isActive ? activeItemStyle : undefined]}\n testID={item.testID ?? item.key}\n onPress={() => onNavigate(item.route)}\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]}\n testID={item.testID ?? item.key}\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} 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 banner: '-banner',\n pending: '-pending',\n loading: '-loading',\n error: '-error',\n forbidden: '-forbidden',\n} as const;\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, TouchableOpacity, View, type ViewStyle } from 'react-native';\n\nimport { useUi, type UiTheme } from '@dloizides/ui-feedback';\n\nimport { NAV_TEST_IDS } from './constants';\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 <TouchableOpacity\n accessibilityHint={language.hint}\n accessibilityLabel={language.label}\n accessibilityRole=\"button\"\n style={styles.topbarRowItem}\n onPress={language.onPress}\n >\n <Text style={[styles.topbarLabel, { color: colors.text }]}>{language.label}</Text>\n </TouchableOpacity>\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 <TouchableOpacity\n accessibilityHint={richAccount.displayName}\n accessibilityLabel={richAccount.displayName}\n accessibilityRole=\"button\"\n testID={NAV_TEST_IDS.accountName}\n onPress={richAccount.onAccount}\n >\n <Text style={[styles.userName, { color: colors.text }]}>{richAccount.displayName}</Text>\n </TouchableOpacity>\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 <TouchableOpacity\n accessibilityHint={legacyAccount.hint}\n accessibilityLabel={legacyAccount.label}\n accessibilityRole=\"button\"\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 </TouchableOpacity>\n ) : null}\n\n {upgrade ? (\n <TouchableOpacity\n accessibilityHint={upgrade.hint}\n accessibilityLabel={upgrade.label}\n accessibilityRole=\"button\"\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 </TouchableOpacity>\n ) : null}\n\n <TouchableOpacity\n accessible\n accessibilityHint={logout.hint}\n accessibilityLabel={logout.label}\n accessibilityRole=\"button\"\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 </TouchableOpacity>\n </View>\n </View>\n );\n};\n\nexport default Topbar;\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 * 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, { useEffect } from 'react';\n\nimport { ActivityIndicator, ScrollView, StyleSheet, Text, View, type ViewStyle } from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\n\nimport { APP_SHELL_SUFFIX } from './constants';\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 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 /** 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 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 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 return (\n <View style={[styles.root, { backgroundColor: theme.colors.background }]} testID={testID}>\n <View testID={`${testID}${APP_SHELL_SUFFIX.header}`}>{header}</View>\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 <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 </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/NavExpandableItem.tsx","../src/Sidebar.tsx","../src/constants.ts","../src/Topbar.tsx","../src/NavBar.tsx","../src/useContentMaxWidth.ts","../src/AppShell.tsx","../src/roleNav.ts"],"names":["StyleSheet","useState","useUi","useCallback","useMemo","jsxs","TouchableOpacity","jsx","View","Text","TEXT_ON_PRIMARY","useWindowDimensions","ActivityIndicator","useEffect","ScrollView","resolveAccessibleRoutes"],"mappings":"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","file":"index.js","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 brand: { marginRight: 16 },\n toggle: {\n marginLeft: 'auto',\n paddingHorizontal: 10,\n paddingVertical: 6,\n borderRadius: 4,\n },\n toggleGlyph: { fontSize: 20, fontWeight: '700' },\n links: {\n flexDirection: 'row',\n alignItems: 'center',\n flexWrap: 'wrap',\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 },\n linkStacked: { paddingVertical: 10 },\n linkIcon: { marginRight: 6 },\n linkText: { fontSize: 15, fontWeight: '600' },\n right: {\n marginLeft: 'auto',\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 * 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 } 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';\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 { 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 style={[styles.childItem, paddingStyle, isActive ? activeItemStyle : undefined]}\n testID={item.testID ?? item.key}\n onPress={() => onNavigate(item.route)}\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]}\n testID={item.testID ?? item.key}\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 banner: '-banner',\n pending: '-pending',\n loading: '-loading',\n error: '-error',\n forbidden: '-forbidden',\n} as const;\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, TouchableOpacity, View, type ViewStyle } from 'react-native';\n\nimport { useUi, type UiTheme } from '@dloizides/ui-feedback';\n\nimport { NAV_TEST_IDS } from './constants';\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 <TouchableOpacity\n accessibilityHint={language.hint}\n accessibilityLabel={language.label}\n accessibilityRole=\"button\"\n style={styles.topbarRowItem}\n onPress={language.onPress}\n >\n <Text style={[styles.topbarLabel, { color: colors.text }]}>{language.label}</Text>\n </TouchableOpacity>\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 <TouchableOpacity\n accessibilityHint={richAccount.displayName}\n accessibilityLabel={richAccount.displayName}\n accessibilityRole=\"button\"\n testID={NAV_TEST_IDS.accountName}\n onPress={richAccount.onAccount}\n >\n <Text style={[styles.userName, { color: colors.text }]}>{richAccount.displayName}</Text>\n </TouchableOpacity>\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 <TouchableOpacity\n accessibilityHint={legacyAccount.hint}\n accessibilityLabel={legacyAccount.label}\n accessibilityRole=\"button\"\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 </TouchableOpacity>\n ) : null}\n\n {upgrade ? (\n <TouchableOpacity\n accessibilityHint={upgrade.hint}\n accessibilityLabel={upgrade.label}\n accessibilityRole=\"button\"\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 </TouchableOpacity>\n ) : null}\n\n <TouchableOpacity\n accessible\n accessibilityHint={logout.hint}\n accessibilityLabel={logout.label}\n accessibilityRole=\"button\"\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 </TouchableOpacity>\n </View>\n </View>\n );\n};\n\nexport default Topbar;\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 * 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` UiProvider\n * theme. This is purely additive — `Sidebar`/`Topbar` are unchanged.\n */\nimport React, { useCallback, useMemo, useState } from 'react';\n\nimport {\n Text,\n TouchableOpacity,\n useWindowDimensions,\n View,\n type TouchableOpacityProps,\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 { ACTIVE_BORDER_RADIUS, navBarStyles as styles, NAV_ICON_SIZE } from './styles';\nimport type { NavItem } from './types';\n\n/** Text colour for a link sitting on the primary (active) background. */\nconst TEXT_ON_PRIMARY = '#ffffff';\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-current=\"page\"` marks the active link for assistive tech. react-native's\n * prop types omit `aria-current`, but react-native-web forwards `aria-*` to the\n * DOM — so we attach it (no `any`) only when a link is active.\n */\nfunction activeAriaProps(isActive: boolean): TouchableOpacityProps & { 'aria-current'?: 'page' } {\n return isActive ? { 'aria-current': 'page' } : {};\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 [open, setOpen] = 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 const activeLinkStyle = useMemo(\n () => ({ backgroundColor: primaryColor, borderRadius: ACTIVE_BORDER_RADIUS }),\n [primaryColor],\n );\n\n const renderLink = (item: NavItem): React.ReactElement => {\n const isActive = isRouteActive(pathname, item.route);\n const textColor = isActive ? TEXT_ON_PRIMARY : colors.textSecondary;\n return (\n <TouchableOpacity\n key={item.key}\n accessible\n accessibilityHint={navigateHint(item.label)}\n accessibilityLabel={item.label}\n accessibilityRole=\"link\"\n accessibilityState={{ selected: isActive }}\n style={[styles.link, collapsed ? styles.linkStacked : undefined, isActive ? activeLinkStyle : undefined]}\n testID={item.testID ?? item.key}\n onPress={() => handlePress(item.route)}\n {...activeAriaProps(isActive)}\n >\n {typeof item.renderIcon === 'function' ? (\n <View style={styles.linkIcon}>{item.renderIcon(textColor, NAV_ICON_SIZE)}</View>\n ) : null}\n <Text style={[styles.linkText, { color: textColor }]}>{item.label}</Text>\n </TouchableOpacity>\n );\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}>\n {brand !== undefined ? <View style={styles.brand}>{brand}</View> : null}\n\n {collapsed ? (\n <TouchableOpacity\n accessible\n accessibilityHint={menuHint}\n accessibilityLabel={menuLabel}\n accessibilityRole=\"button\"\n accessibilityState={{ expanded: open }}\n aria-expanded={open}\n style={styles.toggle}\n testID={NAV_TEST_IDS.navBarToggle}\n onPress={toggleMenu}\n >\n {typeof renderMenuIcon === 'function' ? (\n renderMenuIcon(colors.text, open)\n ) : (\n <Text style={[styles.toggleGlyph, { color: colors.text }]}>{MENU_GLYPH}</Text>\n )}\n </TouchableOpacity>\n ) : null}\n\n {showLinks ? (\n <View style={collapsed ? styles.linksStacked : styles.links} testID={NAV_TEST_IDS.navBarLinks}>\n {items.map(renderLink)}\n </View>\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 * 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 * 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, { useEffect } from 'react';\n\nimport { ActivityIndicator, ScrollView, StyleSheet, Text, View, type ViewStyle } from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\n\nimport { APP_SHELL_SUFFIX } from './constants';\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 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 /** 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 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 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 return (\n <View style={[styles.root, { backgroundColor: theme.colors.background }]} testID={testID}>\n <View testID={`${testID}${APP_SHELL_SUFFIX.header}`}>{header}</View>\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 <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 </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"]}
package/dist/index.mjs CHANGED
@@ -59,6 +59,71 @@ var navStyles = StyleSheet.create({
59
59
  planBadge: { marginTop: 2, paddingHorizontal: 8, paddingVertical: 2, borderRadius: 10, alignSelf: "flex-end" },
60
60
  planBadgeText: { fontSize: 11, fontWeight: "700" }
61
61
  });
62
+ var navBarStyles = StyleSheet.create({
63
+ // --- Horizontal top NavBar ---
64
+ container: {
65
+ borderBottomWidth: 1,
66
+ paddingHorizontal: 12
67
+ },
68
+ inner: {
69
+ minHeight: 56,
70
+ flexDirection: "row",
71
+ alignItems: "center",
72
+ flexWrap: "wrap",
73
+ columnGap: 8,
74
+ rowGap: 4,
75
+ paddingVertical: 8
76
+ },
77
+ brand: { marginRight: 16 },
78
+ toggle: {
79
+ marginLeft: "auto",
80
+ paddingHorizontal: 10,
81
+ paddingVertical: 6,
82
+ borderRadius: 4
83
+ },
84
+ toggleGlyph: { fontSize: 20, fontWeight: "700" },
85
+ links: {
86
+ flexDirection: "row",
87
+ alignItems: "center",
88
+ flexWrap: "wrap",
89
+ columnGap: 4,
90
+ rowGap: 4
91
+ },
92
+ // Collapsed (below breakpoint): links drop onto their own full-width line,
93
+ // stacked vertically — mirrors the v1 `.gn-links` responsive behaviour.
94
+ linksStacked: {
95
+ width: "100%",
96
+ flexBasis: "100%",
97
+ flexDirection: "column",
98
+ alignItems: "stretch",
99
+ rowGap: 2,
100
+ marginTop: 8
101
+ },
102
+ link: {
103
+ paddingVertical: 8,
104
+ paddingHorizontal: 14,
105
+ borderRadius: 8,
106
+ flexDirection: "row",
107
+ alignItems: "center"
108
+ },
109
+ linkStacked: { paddingVertical: 10 },
110
+ linkIcon: { marginRight: 6 },
111
+ linkText: { fontSize: 15, fontWeight: "600" },
112
+ right: {
113
+ marginLeft: "auto",
114
+ flexDirection: "row",
115
+ alignItems: "center",
116
+ columnGap: 8
117
+ },
118
+ rightStacked: {
119
+ width: "100%",
120
+ flexBasis: "100%",
121
+ marginTop: 4,
122
+ flexDirection: "row",
123
+ alignItems: "center",
124
+ columnGap: 8
125
+ }
126
+ });
62
127
  var expandableStyles = StyleSheet.create({
63
128
  childItem: {
64
129
  borderRadius: 4,
@@ -224,7 +289,11 @@ var NAV_TEST_IDS = {
224
289
  /** small plan badge (free / pro / enterprise). */
225
290
  accountPlan: "topbar-account-plan",
226
291
  /** default testID for the rich header's upgrade action (overridable per-action). */
227
- accountUpgrade: "topbar-account-upgrade"
292
+ accountUpgrade: "topbar-account-upgrade",
293
+ /** responsive hamburger toggle in the horizontal NavBar (shown below the breakpoint). */
294
+ navBarToggle: "navbar-toggle",
295
+ /** links container in the horizontal NavBar. */
296
+ navBarLinks: "navbar-links"
228
297
  };
229
298
  var APP_SHELL_SUFFIX = {
230
299
  content: "-content",
@@ -359,6 +428,102 @@ var Topbar = ({
359
428
  }
360
429
  );
361
430
  };
431
+ var TEXT_ON_PRIMARY2 = "#ffffff";
432
+ var DEFAULT_COLLAPSE_BELOW = 760;
433
+ var MENU_GLYPH = "\u2630";
434
+ function activeAriaProps(isActive) {
435
+ return isActive ? { "aria-current": "page" } : {};
436
+ }
437
+ var NavBar = ({
438
+ items,
439
+ pathname,
440
+ onNavigate,
441
+ regionLabel,
442
+ navigateHint = (label) => label,
443
+ brand,
444
+ right,
445
+ menuLabel = "Menu",
446
+ menuHint = "",
447
+ renderMenuIcon,
448
+ collapseBelow = DEFAULT_COLLAPSE_BELOW,
449
+ containerStyle
450
+ }) => {
451
+ const { theme } = useUi();
452
+ const colors = theme.colors;
453
+ const primaryColor = theme.palette.primary["500"];
454
+ const { width } = useWindowDimensions();
455
+ const [open, setOpen] = useState(false);
456
+ const collapsed = width < collapseBelow;
457
+ const showLinks = !collapsed || open;
458
+ const toggleMenu = useCallback(() => setOpen((v) => !v), []);
459
+ const handlePress = useCallback(
460
+ (route) => {
461
+ setOpen(false);
462
+ onNavigate(route);
463
+ },
464
+ [onNavigate]
465
+ );
466
+ const activeLinkStyle = useMemo(
467
+ () => ({ backgroundColor: primaryColor, borderRadius: ACTIVE_BORDER_RADIUS }),
468
+ [primaryColor]
469
+ );
470
+ const renderLink = (item) => {
471
+ const isActive = isRouteActive(pathname, item.route);
472
+ const textColor = isActive ? TEXT_ON_PRIMARY2 : colors.textSecondary;
473
+ return /* @__PURE__ */ jsxs(
474
+ TouchableOpacity,
475
+ {
476
+ accessible: true,
477
+ accessibilityHint: navigateHint(item.label),
478
+ accessibilityLabel: item.label,
479
+ accessibilityRole: "link",
480
+ accessibilityState: { selected: isActive },
481
+ style: [navBarStyles.link, collapsed ? navBarStyles.linkStacked : void 0, isActive ? activeLinkStyle : void 0],
482
+ testID: item.testID ?? item.key,
483
+ onPress: () => handlePress(item.route),
484
+ ...activeAriaProps(isActive),
485
+ children: [
486
+ typeof item.renderIcon === "function" ? /* @__PURE__ */ jsx(View, { style: navBarStyles.linkIcon, children: item.renderIcon(textColor, NAV_ICON_SIZE) }) : null,
487
+ /* @__PURE__ */ jsx(Text, { style: [navBarStyles.linkText, { color: textColor }], children: item.label })
488
+ ]
489
+ },
490
+ item.key
491
+ );
492
+ };
493
+ return /* @__PURE__ */ jsx(
494
+ View,
495
+ {
496
+ accessibilityRole: "none",
497
+ "aria-label": regionLabel,
498
+ role: "navigation",
499
+ style: [
500
+ navBarStyles.container,
501
+ { backgroundColor: colors.surface, borderBottomColor: colors.border },
502
+ containerStyle
503
+ ],
504
+ children: /* @__PURE__ */ jsxs(View, { style: navBarStyles.inner, children: [
505
+ brand !== void 0 ? /* @__PURE__ */ jsx(View, { style: navBarStyles.brand, children: brand }) : null,
506
+ collapsed ? /* @__PURE__ */ jsx(
507
+ TouchableOpacity,
508
+ {
509
+ accessible: true,
510
+ accessibilityHint: menuHint,
511
+ accessibilityLabel: menuLabel,
512
+ accessibilityRole: "button",
513
+ accessibilityState: { expanded: open },
514
+ "aria-expanded": open,
515
+ style: navBarStyles.toggle,
516
+ testID: NAV_TEST_IDS.navBarToggle,
517
+ onPress: toggleMenu,
518
+ children: typeof renderMenuIcon === "function" ? renderMenuIcon(colors.text, open) : /* @__PURE__ */ jsx(Text, { style: [navBarStyles.toggleGlyph, { color: colors.text }], children: MENU_GLYPH })
519
+ }
520
+ ) : null,
521
+ showLinks ? /* @__PURE__ */ jsx(View, { style: collapsed ? navBarStyles.linksStacked : navBarStyles.links, testID: NAV_TEST_IDS.navBarLinks, children: items.map(renderLink) }) : null,
522
+ showLinks && right !== void 0 ? /* @__PURE__ */ jsx(View, { style: collapsed ? navBarStyles.rightStacked : navBarStyles.right, children: right }) : null
523
+ ] })
524
+ }
525
+ );
526
+ };
362
527
  function resolveContentMaxWidth(width, viewport) {
363
528
  if (width === "full") return "full";
364
529
  const wideMinViewport = width.wideMinViewport ?? Number.POSITIVE_INFINITY;
@@ -476,6 +641,6 @@ function accessibleNavItems(user, table, translate) {
476
641
  return roleRoutesToNavItems(resolveAccessibleRoutes(user, table), translate);
477
642
  }
478
643
 
479
- export { ACTIVE_BORDER_RADIUS, APP_SHELL_SUFFIX, AppShell, BASE_INDENT, CHEVRON_ICON_SIZE, NAV_ICON_SIZE, NAV_TEST_IDS, NavExpandableItem, Sidebar, Topbar, accessibleNavItems, expandableStyles, isRouteActive, navStyles, resolveContentMaxWidth, roleRoutesToNavItems, useContentMaxWidth };
644
+ export { ACTIVE_BORDER_RADIUS, APP_SHELL_SUFFIX, AppShell, BASE_INDENT, CHEVRON_ICON_SIZE, NAV_ICON_SIZE, NAV_TEST_IDS, NavBar, NavExpandableItem, Sidebar, Topbar, accessibleNavItems, expandableStyles, isRouteActive, navStyles, resolveContentMaxWidth, roleRoutesToNavItems, useContentMaxWidth };
480
645
  //# sourceMappingURL=index.mjs.map
481
646
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/isRouteActive.ts","../src/styles.ts","../src/NavExpandableItem.tsx","../src/Sidebar.tsx","../src/constants.ts","../src/Topbar.tsx","../src/useContentMaxWidth.ts","../src/AppShell.tsx","../src/roleNav.ts"],"names":["useUi","jsxs","View","jsx","Text","TouchableOpacity","StyleSheet"],"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 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 * 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 } 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';\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 { 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 style={[styles.childItem, paddingStyle, isActive ? activeItemStyle : undefined]}\n testID={item.testID ?? item.key}\n onPress={() => onNavigate(item.route)}\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]}\n testID={item.testID ?? item.key}\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} 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 banner: '-banner',\n pending: '-pending',\n loading: '-loading',\n error: '-error',\n forbidden: '-forbidden',\n} as const;\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, TouchableOpacity, View, type ViewStyle } from 'react-native';\n\nimport { useUi, type UiTheme } from '@dloizides/ui-feedback';\n\nimport { NAV_TEST_IDS } from './constants';\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 <TouchableOpacity\n accessibilityHint={language.hint}\n accessibilityLabel={language.label}\n accessibilityRole=\"button\"\n style={styles.topbarRowItem}\n onPress={language.onPress}\n >\n <Text style={[styles.topbarLabel, { color: colors.text }]}>{language.label}</Text>\n </TouchableOpacity>\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 <TouchableOpacity\n accessibilityHint={richAccount.displayName}\n accessibilityLabel={richAccount.displayName}\n accessibilityRole=\"button\"\n testID={NAV_TEST_IDS.accountName}\n onPress={richAccount.onAccount}\n >\n <Text style={[styles.userName, { color: colors.text }]}>{richAccount.displayName}</Text>\n </TouchableOpacity>\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 <TouchableOpacity\n accessibilityHint={legacyAccount.hint}\n accessibilityLabel={legacyAccount.label}\n accessibilityRole=\"button\"\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 </TouchableOpacity>\n ) : null}\n\n {upgrade ? (\n <TouchableOpacity\n accessibilityHint={upgrade.hint}\n accessibilityLabel={upgrade.label}\n accessibilityRole=\"button\"\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 </TouchableOpacity>\n ) : null}\n\n <TouchableOpacity\n accessible\n accessibilityHint={logout.hint}\n accessibilityLabel={logout.label}\n accessibilityRole=\"button\"\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 </TouchableOpacity>\n </View>\n </View>\n );\n};\n\nexport default Topbar;\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 * 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, { useEffect } from 'react';\n\nimport { ActivityIndicator, ScrollView, StyleSheet, Text, View, type ViewStyle } from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\n\nimport { APP_SHELL_SUFFIX } from './constants';\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 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 /** 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 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 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 return (\n <View style={[styles.root, { backgroundColor: theme.colors.background }]} testID={testID}>\n <View testID={`${testID}${APP_SHELL_SUFFIX.header}`}>{header}</View>\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 <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 </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/NavExpandableItem.tsx","../src/Sidebar.tsx","../src/constants.ts","../src/Topbar.tsx","../src/NavBar.tsx","../src/useContentMaxWidth.ts","../src/AppShell.tsx","../src/roleNav.ts"],"names":["useUi","jsxs","View","jsx","Text","TouchableOpacity","TEXT_ON_PRIMARY","useState","useCallback","useMemo","useWindowDimensions","StyleSheet"],"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 brand: { marginRight: 16 },\n toggle: {\n marginLeft: 'auto',\n paddingHorizontal: 10,\n paddingVertical: 6,\n borderRadius: 4,\n },\n toggleGlyph: { fontSize: 20, fontWeight: '700' },\n links: {\n flexDirection: 'row',\n alignItems: 'center',\n flexWrap: 'wrap',\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 },\n linkStacked: { paddingVertical: 10 },\n linkIcon: { marginRight: 6 },\n linkText: { fontSize: 15, fontWeight: '600' },\n right: {\n marginLeft: 'auto',\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 * 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 } 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';\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 { 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 style={[styles.childItem, paddingStyle, isActive ? activeItemStyle : undefined]}\n testID={item.testID ?? item.key}\n onPress={() => onNavigate(item.route)}\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]}\n testID={item.testID ?? item.key}\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 banner: '-banner',\n pending: '-pending',\n loading: '-loading',\n error: '-error',\n forbidden: '-forbidden',\n} as const;\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, TouchableOpacity, View, type ViewStyle } from 'react-native';\n\nimport { useUi, type UiTheme } from '@dloizides/ui-feedback';\n\nimport { NAV_TEST_IDS } from './constants';\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 <TouchableOpacity\n accessibilityHint={language.hint}\n accessibilityLabel={language.label}\n accessibilityRole=\"button\"\n style={styles.topbarRowItem}\n onPress={language.onPress}\n >\n <Text style={[styles.topbarLabel, { color: colors.text }]}>{language.label}</Text>\n </TouchableOpacity>\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 <TouchableOpacity\n accessibilityHint={richAccount.displayName}\n accessibilityLabel={richAccount.displayName}\n accessibilityRole=\"button\"\n testID={NAV_TEST_IDS.accountName}\n onPress={richAccount.onAccount}\n >\n <Text style={[styles.userName, { color: colors.text }]}>{richAccount.displayName}</Text>\n </TouchableOpacity>\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 <TouchableOpacity\n accessibilityHint={legacyAccount.hint}\n accessibilityLabel={legacyAccount.label}\n accessibilityRole=\"button\"\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 </TouchableOpacity>\n ) : null}\n\n {upgrade ? (\n <TouchableOpacity\n accessibilityHint={upgrade.hint}\n accessibilityLabel={upgrade.label}\n accessibilityRole=\"button\"\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 </TouchableOpacity>\n ) : null}\n\n <TouchableOpacity\n accessible\n accessibilityHint={logout.hint}\n accessibilityLabel={logout.label}\n accessibilityRole=\"button\"\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 </TouchableOpacity>\n </View>\n </View>\n );\n};\n\nexport default Topbar;\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 * 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` UiProvider\n * theme. This is purely additive — `Sidebar`/`Topbar` are unchanged.\n */\nimport React, { useCallback, useMemo, useState } from 'react';\n\nimport {\n Text,\n TouchableOpacity,\n useWindowDimensions,\n View,\n type TouchableOpacityProps,\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 { ACTIVE_BORDER_RADIUS, navBarStyles as styles, NAV_ICON_SIZE } from './styles';\nimport type { NavItem } from './types';\n\n/** Text colour for a link sitting on the primary (active) background. */\nconst TEXT_ON_PRIMARY = '#ffffff';\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-current=\"page\"` marks the active link for assistive tech. react-native's\n * prop types omit `aria-current`, but react-native-web forwards `aria-*` to the\n * DOM — so we attach it (no `any`) only when a link is active.\n */\nfunction activeAriaProps(isActive: boolean): TouchableOpacityProps & { 'aria-current'?: 'page' } {\n return isActive ? { 'aria-current': 'page' } : {};\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 [open, setOpen] = 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 const activeLinkStyle = useMemo(\n () => ({ backgroundColor: primaryColor, borderRadius: ACTIVE_BORDER_RADIUS }),\n [primaryColor],\n );\n\n const renderLink = (item: NavItem): React.ReactElement => {\n const isActive = isRouteActive(pathname, item.route);\n const textColor = isActive ? TEXT_ON_PRIMARY : colors.textSecondary;\n return (\n <TouchableOpacity\n key={item.key}\n accessible\n accessibilityHint={navigateHint(item.label)}\n accessibilityLabel={item.label}\n accessibilityRole=\"link\"\n accessibilityState={{ selected: isActive }}\n style={[styles.link, collapsed ? styles.linkStacked : undefined, isActive ? activeLinkStyle : undefined]}\n testID={item.testID ?? item.key}\n onPress={() => handlePress(item.route)}\n {...activeAriaProps(isActive)}\n >\n {typeof item.renderIcon === 'function' ? (\n <View style={styles.linkIcon}>{item.renderIcon(textColor, NAV_ICON_SIZE)}</View>\n ) : null}\n <Text style={[styles.linkText, { color: textColor }]}>{item.label}</Text>\n </TouchableOpacity>\n );\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}>\n {brand !== undefined ? <View style={styles.brand}>{brand}</View> : null}\n\n {collapsed ? (\n <TouchableOpacity\n accessible\n accessibilityHint={menuHint}\n accessibilityLabel={menuLabel}\n accessibilityRole=\"button\"\n accessibilityState={{ expanded: open }}\n aria-expanded={open}\n style={styles.toggle}\n testID={NAV_TEST_IDS.navBarToggle}\n onPress={toggleMenu}\n >\n {typeof renderMenuIcon === 'function' ? (\n renderMenuIcon(colors.text, open)\n ) : (\n <Text style={[styles.toggleGlyph, { color: colors.text }]}>{MENU_GLYPH}</Text>\n )}\n </TouchableOpacity>\n ) : null}\n\n {showLinks ? (\n <View style={collapsed ? styles.linksStacked : styles.links} testID={NAV_TEST_IDS.navBarLinks}>\n {items.map(renderLink)}\n </View>\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 * 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 * 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, { useEffect } from 'react';\n\nimport { ActivityIndicator, ScrollView, StyleSheet, Text, View, type ViewStyle } from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\n\nimport { APP_SHELL_SUFFIX } from './constants';\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 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 /** 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 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 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 return (\n <View style={[styles.root, { backgroundColor: theme.colors.background }]} testID={testID}>\n <View testID={`${testID}${APP_SHELL_SUFFIX.header}`}>{header}</View>\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 <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 </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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dloizides/ui-nav",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "Config-driven, brand-agnostic React Native (RN-web) navigation shell — Sidebar + Topbar promoted from the byte-identical erevna-web/katalogos-web nav twins. Renders a caller-supplied NavItem[] (pre-localized labels, icon render slots), routes colours through the @dloizides/ui-feedback UiProvider, and gates items by role via resolveAccessibleRoutes from @dloizides/auth-web. Part of the dloizides.com shared UI kit.",
5
5
  "keywords": [
6
6
  "react",