@dloizides/ui-nav 1.23.1 → 1.24.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,14 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.24.0
4
+
5
+ - `Topbar` gets an optional `center` slot between `left` and the actions (testID `topbar-center`); callers that do not pass it render as before (KEFI-EDITOR-HEADER-1 "Compact the landing editor header").
6
+ - `PillNav` gets `variant={PillNavVariant.Menu}`: one compact "Current ▾" trigger (44px pill) opening a menu of the same items through the shared `ModalDropdown` (role menu, arrow keys / Home / End / Enter / Escape, highlight starts on the current item). New optional props `menuHint`, `menuTestID`, `dropdownVariant`; new exports `PillNavVariant`, `resolvePillMenuLabel`. Default stays `Pills`.
7
+
8
+ ## 1.23.2
9
+
10
+ - Topbar account-name button and language toggle get a 44x44 minimum hit box (KEFI-HEADER-HITBOX-1 "kefi-web header account control reaches 44x44").
11
+
3
12
  ## 1.23.1
4
13
 
5
14
  **Overlay z-indexes come from the shared `@dloizides/design-tokens` `Z_INDEX` scale (UI-ZINDEX-SCALE-1 "Shared overlay z-index scale").**
package/dist/index.d.mts CHANGED
@@ -333,6 +333,8 @@ interface AccountState {
333
333
  interface TopbarProps {
334
334
  /** Left slot — typically the tenant logo. */
335
335
  left?: React.ReactNode;
336
+ /** Optional middle slot between `left` and the actions (e.g. a compact dashboard switch). */
337
+ center?: React.ReactNode;
336
338
  /**
337
339
  * Optional language toggle. `testID` is optional but the repo standard wants
338
340
  * one — before 1.10.0 this inline type declared none, so a testID was
@@ -359,7 +361,7 @@ interface TopbarProps {
359
361
  /** Extra container style overrides. */
360
362
  containerStyle?: ViewStyle | ViewStyle[];
361
363
  }
362
- declare const Topbar: ({ left, language, notificationSlot, user, account, logout, containerStyle, }: TopbarProps) => React.ReactElement;
364
+ declare const Topbar: ({ left, center, language, notificationSlot, user, account, logout, containerStyle, }: TopbarProps) => React.ReactElement;
363
365
 
364
366
  /**
365
367
  * NavBar — the config-driven HORIZONTAL top navigation bar. It is the top-bar
@@ -893,6 +895,12 @@ interface CollapsedRailProps {
893
895
  }
894
896
  declare const CollapsedRail: ({ items, pathname, onNavigate, regionLabel, navigateHint, header, footer, containerStyle, }: CollapsedRailProps) => React.ReactElement;
895
897
 
898
+ /** How `PillNav` lays out its items: a wrapping pill row, or one compact "Current ▾" menu button. */
899
+ declare enum PillNavVariant {
900
+ Pills = "pills",
901
+ Menu = "menu"
902
+ }
903
+
896
904
  /**
897
905
  * PillNav — a horizontal row of fully-rounded "pills", the cross-navigation
898
906
  * switcher promoted from kefi's coral dashboard nav. It renders the same
@@ -929,10 +937,21 @@ interface PillNavProps {
929
937
  * (show when non-empty); kefi passes 2 (a lone dashboard needs no switcher).
930
938
  */
931
939
  minItems?: number;
940
+ /** `Pills` (default) renders the wrapping row; `Menu` renders one compact "Current ▾" menu button. */
941
+ variant?: PillNavVariant;
942
+ /** a11y hint for the `Menu` trigger. Defaults to `regionLabel`. */
943
+ menuHint?: string;
944
+ /** testID for the `Menu` trigger. Defaults to `NAV_TEST_IDS.pillNavMenu`. */
945
+ menuTestID?: string;
946
+ /** Forces the `Menu` dropdown variant (default: responsive). */
947
+ dropdownVariant?: DropdownVariant;
932
948
  /** Extra container style overrides. */
933
949
  containerStyle?: ViewStyle | ViewStyle[];
934
950
  }
935
- declare const PillNav: ({ items, pathname, onNavigate, regionLabel, navigateHint, minItems, containerStyle, }: PillNavProps) => React.ReactElement | null;
951
+ declare const PillNav: ({ items, pathname, onNavigate, regionLabel, navigateHint, minItems, variant, menuHint, menuTestID, dropdownVariant, containerStyle, }: PillNavProps) => React.ReactElement | null;
952
+
953
+ /** The label the compact menu trigger shows: the active item's label, else `fallback`. */
954
+ declare function resolvePillMenuLabel(items: NavItem[], pathname: string, fallback: string): string;
936
955
 
937
956
  /**
938
957
  * DarkModeControl — the shared colour-scheme control promoted from erevna /
@@ -1077,6 +1096,10 @@ declare const NAV_TEST_IDS: {
1077
1096
  readonly navBarLinks: "navbar-links";
1078
1097
  /** the "More ▾" priority+ overflow trigger in the horizontal NavBar (shown when items spill). */
1079
1098
  readonly navBarOverflow: "navbar-overflow";
1099
+ /** the compact "Current ▾" trigger of `PillNav` with `variant={PillNavVariant.Menu}`. */
1100
+ readonly pillNavMenu: "pill-nav-menu";
1101
+ /** the optional middle slot of `Topbar` (rendered only when `center` is passed). */
1102
+ readonly topbarCenter: "topbar-center";
1080
1103
  };
1081
1104
  /** Suffixes appended to an `AppShell`'s required `testID` to name its regions. */
1082
1105
  declare const APP_SHELL_SUFFIX: {
@@ -1333,6 +1356,13 @@ declare const navStyles: {
1333
1356
  topbarLeft: {
1334
1357
  flex: number;
1335
1358
  };
1359
+ topbarCenter: {
1360
+ flexShrink: number;
1361
+ minWidth: number;
1362
+ flexDirection: "row";
1363
+ alignItems: "center";
1364
+ marginHorizontal: number;
1365
+ };
1336
1366
  topbarRight: {
1337
1367
  flexDirection: "row";
1338
1368
  alignItems: "center";
@@ -1340,6 +1370,9 @@ declare const navStyles: {
1340
1370
  topbarRowItem: {
1341
1371
  marginHorizontal: number;
1342
1372
  alignItems: "center";
1373
+ justifyContent: "center";
1374
+ minHeight: number;
1375
+ minWidth: number;
1343
1376
  };
1344
1377
  topbarLabel: {
1345
1378
  fontSize: number;
@@ -1351,6 +1384,12 @@ declare const navStyles: {
1351
1384
  userName: {
1352
1385
  fontWeight: "600";
1353
1386
  };
1387
+ accountNameBtn: {
1388
+ minHeight: number;
1389
+ minWidth: number;
1390
+ justifyContent: "center";
1391
+ alignItems: "flex-end";
1392
+ };
1354
1393
  userEmail: {
1355
1394
  fontSize: number;
1356
1395
  };
@@ -1404,6 +1443,9 @@ declare const pillNavStyles: {
1404
1443
  fontSize: number;
1405
1444
  fontWeight: "600";
1406
1445
  };
1446
+ menuTriggerText: {
1447
+ flexShrink: number;
1448
+ };
1407
1449
  };
1408
1450
  declare const darkModeStyles: {
1409
1451
  segmentRow: {
@@ -1543,4 +1585,4 @@ declare const NAV_ICON_SIZE = 14;
1543
1585
  /** Chevron icon size for expandable sections. */
1544
1586
  declare const CHEVRON_ICON_SIZE = 12;
1545
1587
 
1546
- export { ACTIVE_BORDER_RADIUS, ACTIVE_TINT_OPACITY, APP_SHELL_SUFFIX, type AccountPlan, type AccountState, AppShell, type AppShellProps, type AppShellWidth, BASE_INDENT, CHEVRON_ICON_SIZE, CollapsedRail, type CollapsedRailProps, type CollapsedRailRange, type CommandItem, CommandPalette, type CommandPaletteLabels, type CommandPaletteProps, CommandPaletteTrigger, type CommandPaletteTriggerProps, DEFAULT_COLLAPSED_RAIL_MAX, DEFAULT_SEARCH_BREAKPOINT, DarkModeControl, type DarkModeControlProps, type DarkModeOption, type DarkModeVariant, HOVER_TINT_OPACITY, NAV_ICON_SIZE, NAV_LINK_GAP, NAV_ROW_RADIUS, NAV_TEST_IDS, Nav, NavBar, type NavBarProps, NavExpandableItem, type NavExpandableItemProps, type NavItem, type NavOrientation, NavOverflowMenu, type NavOverflowMenuProps, type NavProps, NavShell, type NavShellCollapsedRail, type NavShellLayout, type NavShellProps, type NavShellSideRail, type NavShellTopBar, type NavUser, PillNav, type PillNavProps, RAIL_FULL_BREAKPOINT, type RailMode, type ResolveRailModeArgs, type SearchAffordance, type ShellMessage, Sidebar, SidebarChevron, type SidebarChevronProps, type SidebarPaletteTriggerConfig, type SidebarProps, SidebarSearch, type SidebarSearchConfig, type SidebarSearchLabels, type SidebarSearchProps, Topbar, type TopbarAction, type TopbarProps, type TopbarUser, accessibleNavItems, collapsedRailStyles, darkModeStyles, expandableStyles, filterCommands, filterNavItems, isFilterActive, isRouteActive, navStyles, pillNavStyles, resolveActiveRoute, resolveContentMaxWidth, resolveRailMode, resolveSearchAffordance, roleRoutesToNavItems, searchTokens, useCommandPaletteHotkey, useContentMaxWidth };
1588
+ export { ACTIVE_BORDER_RADIUS, ACTIVE_TINT_OPACITY, APP_SHELL_SUFFIX, type AccountPlan, type AccountState, AppShell, type AppShellProps, type AppShellWidth, BASE_INDENT, CHEVRON_ICON_SIZE, CollapsedRail, type CollapsedRailProps, type CollapsedRailRange, type CommandItem, CommandPalette, type CommandPaletteLabels, type CommandPaletteProps, CommandPaletteTrigger, type CommandPaletteTriggerProps, DEFAULT_COLLAPSED_RAIL_MAX, DEFAULT_SEARCH_BREAKPOINT, DarkModeControl, type DarkModeControlProps, type DarkModeOption, type DarkModeVariant, HOVER_TINT_OPACITY, NAV_ICON_SIZE, NAV_LINK_GAP, NAV_ROW_RADIUS, NAV_TEST_IDS, Nav, NavBar, type NavBarProps, NavExpandableItem, type NavExpandableItemProps, type NavItem, type NavOrientation, NavOverflowMenu, type NavOverflowMenuProps, type NavProps, NavShell, type NavShellCollapsedRail, type NavShellLayout, type NavShellProps, type NavShellSideRail, type NavShellTopBar, type NavUser, PillNav, type PillNavProps, PillNavVariant, RAIL_FULL_BREAKPOINT, type RailMode, type ResolveRailModeArgs, type SearchAffordance, type ShellMessage, Sidebar, SidebarChevron, type SidebarChevronProps, type SidebarPaletteTriggerConfig, type SidebarProps, SidebarSearch, type SidebarSearchConfig, type SidebarSearchLabels, type SidebarSearchProps, Topbar, type TopbarAction, type TopbarProps, type TopbarUser, accessibleNavItems, collapsedRailStyles, darkModeStyles, expandableStyles, filterCommands, filterNavItems, isFilterActive, isRouteActive, navStyles, pillNavStyles, resolveActiveRoute, resolveContentMaxWidth, resolvePillMenuLabel, resolveRailMode, resolveSearchAffordance, roleRoutesToNavItems, searchTokens, useCommandPaletteHotkey, useContentMaxWidth };
package/dist/index.d.ts CHANGED
@@ -333,6 +333,8 @@ interface AccountState {
333
333
  interface TopbarProps {
334
334
  /** Left slot — typically the tenant logo. */
335
335
  left?: React.ReactNode;
336
+ /** Optional middle slot between `left` and the actions (e.g. a compact dashboard switch). */
337
+ center?: React.ReactNode;
336
338
  /**
337
339
  * Optional language toggle. `testID` is optional but the repo standard wants
338
340
  * one — before 1.10.0 this inline type declared none, so a testID was
@@ -359,7 +361,7 @@ interface TopbarProps {
359
361
  /** Extra container style overrides. */
360
362
  containerStyle?: ViewStyle | ViewStyle[];
361
363
  }
362
- declare const Topbar: ({ left, language, notificationSlot, user, account, logout, containerStyle, }: TopbarProps) => React.ReactElement;
364
+ declare const Topbar: ({ left, center, language, notificationSlot, user, account, logout, containerStyle, }: TopbarProps) => React.ReactElement;
363
365
 
364
366
  /**
365
367
  * NavBar — the config-driven HORIZONTAL top navigation bar. It is the top-bar
@@ -893,6 +895,12 @@ interface CollapsedRailProps {
893
895
  }
894
896
  declare const CollapsedRail: ({ items, pathname, onNavigate, regionLabel, navigateHint, header, footer, containerStyle, }: CollapsedRailProps) => React.ReactElement;
895
897
 
898
+ /** How `PillNav` lays out its items: a wrapping pill row, or one compact "Current ▾" menu button. */
899
+ declare enum PillNavVariant {
900
+ Pills = "pills",
901
+ Menu = "menu"
902
+ }
903
+
896
904
  /**
897
905
  * PillNav — a horizontal row of fully-rounded "pills", the cross-navigation
898
906
  * switcher promoted from kefi's coral dashboard nav. It renders the same
@@ -929,10 +937,21 @@ interface PillNavProps {
929
937
  * (show when non-empty); kefi passes 2 (a lone dashboard needs no switcher).
930
938
  */
931
939
  minItems?: number;
940
+ /** `Pills` (default) renders the wrapping row; `Menu` renders one compact "Current ▾" menu button. */
941
+ variant?: PillNavVariant;
942
+ /** a11y hint for the `Menu` trigger. Defaults to `regionLabel`. */
943
+ menuHint?: string;
944
+ /** testID for the `Menu` trigger. Defaults to `NAV_TEST_IDS.pillNavMenu`. */
945
+ menuTestID?: string;
946
+ /** Forces the `Menu` dropdown variant (default: responsive). */
947
+ dropdownVariant?: DropdownVariant;
932
948
  /** Extra container style overrides. */
933
949
  containerStyle?: ViewStyle | ViewStyle[];
934
950
  }
935
- declare const PillNav: ({ items, pathname, onNavigate, regionLabel, navigateHint, minItems, containerStyle, }: PillNavProps) => React.ReactElement | null;
951
+ declare const PillNav: ({ items, pathname, onNavigate, regionLabel, navigateHint, minItems, variant, menuHint, menuTestID, dropdownVariant, containerStyle, }: PillNavProps) => React.ReactElement | null;
952
+
953
+ /** The label the compact menu trigger shows: the active item's label, else `fallback`. */
954
+ declare function resolvePillMenuLabel(items: NavItem[], pathname: string, fallback: string): string;
936
955
 
937
956
  /**
938
957
  * DarkModeControl — the shared colour-scheme control promoted from erevna /
@@ -1077,6 +1096,10 @@ declare const NAV_TEST_IDS: {
1077
1096
  readonly navBarLinks: "navbar-links";
1078
1097
  /** the "More ▾" priority+ overflow trigger in the horizontal NavBar (shown when items spill). */
1079
1098
  readonly navBarOverflow: "navbar-overflow";
1099
+ /** the compact "Current ▾" trigger of `PillNav` with `variant={PillNavVariant.Menu}`. */
1100
+ readonly pillNavMenu: "pill-nav-menu";
1101
+ /** the optional middle slot of `Topbar` (rendered only when `center` is passed). */
1102
+ readonly topbarCenter: "topbar-center";
1080
1103
  };
1081
1104
  /** Suffixes appended to an `AppShell`'s required `testID` to name its regions. */
1082
1105
  declare const APP_SHELL_SUFFIX: {
@@ -1333,6 +1356,13 @@ declare const navStyles: {
1333
1356
  topbarLeft: {
1334
1357
  flex: number;
1335
1358
  };
1359
+ topbarCenter: {
1360
+ flexShrink: number;
1361
+ minWidth: number;
1362
+ flexDirection: "row";
1363
+ alignItems: "center";
1364
+ marginHorizontal: number;
1365
+ };
1336
1366
  topbarRight: {
1337
1367
  flexDirection: "row";
1338
1368
  alignItems: "center";
@@ -1340,6 +1370,9 @@ declare const navStyles: {
1340
1370
  topbarRowItem: {
1341
1371
  marginHorizontal: number;
1342
1372
  alignItems: "center";
1373
+ justifyContent: "center";
1374
+ minHeight: number;
1375
+ minWidth: number;
1343
1376
  };
1344
1377
  topbarLabel: {
1345
1378
  fontSize: number;
@@ -1351,6 +1384,12 @@ declare const navStyles: {
1351
1384
  userName: {
1352
1385
  fontWeight: "600";
1353
1386
  };
1387
+ accountNameBtn: {
1388
+ minHeight: number;
1389
+ minWidth: number;
1390
+ justifyContent: "center";
1391
+ alignItems: "flex-end";
1392
+ };
1354
1393
  userEmail: {
1355
1394
  fontSize: number;
1356
1395
  };
@@ -1404,6 +1443,9 @@ declare const pillNavStyles: {
1404
1443
  fontSize: number;
1405
1444
  fontWeight: "600";
1406
1445
  };
1446
+ menuTriggerText: {
1447
+ flexShrink: number;
1448
+ };
1407
1449
  };
1408
1450
  declare const darkModeStyles: {
1409
1451
  segmentRow: {
@@ -1543,4 +1585,4 @@ declare const NAV_ICON_SIZE = 14;
1543
1585
  /** Chevron icon size for expandable sections. */
1544
1586
  declare const CHEVRON_ICON_SIZE = 12;
1545
1587
 
1546
- export { ACTIVE_BORDER_RADIUS, ACTIVE_TINT_OPACITY, APP_SHELL_SUFFIX, type AccountPlan, type AccountState, AppShell, type AppShellProps, type AppShellWidth, BASE_INDENT, CHEVRON_ICON_SIZE, CollapsedRail, type CollapsedRailProps, type CollapsedRailRange, type CommandItem, CommandPalette, type CommandPaletteLabels, type CommandPaletteProps, CommandPaletteTrigger, type CommandPaletteTriggerProps, DEFAULT_COLLAPSED_RAIL_MAX, DEFAULT_SEARCH_BREAKPOINT, DarkModeControl, type DarkModeControlProps, type DarkModeOption, type DarkModeVariant, HOVER_TINT_OPACITY, NAV_ICON_SIZE, NAV_LINK_GAP, NAV_ROW_RADIUS, NAV_TEST_IDS, Nav, NavBar, type NavBarProps, NavExpandableItem, type NavExpandableItemProps, type NavItem, type NavOrientation, NavOverflowMenu, type NavOverflowMenuProps, type NavProps, NavShell, type NavShellCollapsedRail, type NavShellLayout, type NavShellProps, type NavShellSideRail, type NavShellTopBar, type NavUser, PillNav, type PillNavProps, RAIL_FULL_BREAKPOINT, type RailMode, type ResolveRailModeArgs, type SearchAffordance, type ShellMessage, Sidebar, SidebarChevron, type SidebarChevronProps, type SidebarPaletteTriggerConfig, type SidebarProps, SidebarSearch, type SidebarSearchConfig, type SidebarSearchLabels, type SidebarSearchProps, Topbar, type TopbarAction, type TopbarProps, type TopbarUser, accessibleNavItems, collapsedRailStyles, darkModeStyles, expandableStyles, filterCommands, filterNavItems, isFilterActive, isRouteActive, navStyles, pillNavStyles, resolveActiveRoute, resolveContentMaxWidth, resolveRailMode, resolveSearchAffordance, roleRoutesToNavItems, searchTokens, useCommandPaletteHotkey, useContentMaxWidth };
1588
+ export { ACTIVE_BORDER_RADIUS, ACTIVE_TINT_OPACITY, APP_SHELL_SUFFIX, type AccountPlan, type AccountState, AppShell, type AppShellProps, type AppShellWidth, BASE_INDENT, CHEVRON_ICON_SIZE, CollapsedRail, type CollapsedRailProps, type CollapsedRailRange, type CommandItem, CommandPalette, type CommandPaletteLabels, type CommandPaletteProps, CommandPaletteTrigger, type CommandPaletteTriggerProps, DEFAULT_COLLAPSED_RAIL_MAX, DEFAULT_SEARCH_BREAKPOINT, DarkModeControl, type DarkModeControlProps, type DarkModeOption, type DarkModeVariant, HOVER_TINT_OPACITY, NAV_ICON_SIZE, NAV_LINK_GAP, NAV_ROW_RADIUS, NAV_TEST_IDS, Nav, NavBar, type NavBarProps, NavExpandableItem, type NavExpandableItemProps, type NavItem, type NavOrientation, NavOverflowMenu, type NavOverflowMenuProps, type NavProps, NavShell, type NavShellCollapsedRail, type NavShellLayout, type NavShellProps, type NavShellSideRail, type NavShellTopBar, type NavUser, PillNav, type PillNavProps, PillNavVariant, RAIL_FULL_BREAKPOINT, type RailMode, type ResolveRailModeArgs, type SearchAffordance, type ShellMessage, Sidebar, SidebarChevron, type SidebarChevronProps, type SidebarPaletteTriggerConfig, type SidebarProps, SidebarSearch, type SidebarSearchConfig, type SidebarSearchLabels, type SidebarSearchProps, Topbar, type TopbarAction, type TopbarProps, type TopbarUser, accessibleNavItems, collapsedRailStyles, darkModeStyles, expandableStyles, filterCommands, filterNavItems, isFilterActive, isRouteActive, navStyles, pillNavStyles, resolveActiveRoute, resolveContentMaxWidth, resolvePillMenuLabel, resolveRailMode, resolveSearchAffordance, roleRoutesToNavItems, searchTokens, useCommandPaletteHotkey, useContentMaxWidth };
package/dist/index.js CHANGED
@@ -71,11 +71,24 @@ var navStyles = reactNative.StyleSheet.create({
71
71
  justifyContent: "space-between"
72
72
  },
73
73
  topbarLeft: { flex: 1 },
74
+ topbarCenter: { flexShrink: 1, minWidth: 0, flexDirection: "row", alignItems: "center", marginHorizontal: 8 },
74
75
  topbarRight: { flexDirection: "row", alignItems: "center" },
75
- topbarRowItem: { marginHorizontal: 8, alignItems: "center" },
76
+ topbarRowItem: {
77
+ marginHorizontal: 8,
78
+ alignItems: "center",
79
+ justifyContent: "center",
80
+ minHeight: MIN_TOUCH_TARGET,
81
+ minWidth: MIN_TOUCH_TARGET
82
+ },
76
83
  topbarLabel: { fontSize: 14 },
77
84
  userBlock: { marginHorizontal: 12, alignItems: "flex-end" },
78
85
  userName: { fontWeight: "600" },
86
+ accountNameBtn: {
87
+ minHeight: MIN_TOUCH_TARGET,
88
+ minWidth: MIN_TOUCH_TARGET,
89
+ justifyContent: "center",
90
+ alignItems: "flex-end"
91
+ },
79
92
  userEmail: { fontSize: 12 },
80
93
  accountBtn: {
81
94
  marginLeft: 8,
@@ -212,7 +225,8 @@ var pillNavStyles = reactNative.StyleSheet.create({
212
225
  columnGap: 6,
213
226
  justifyContent: "center"
214
227
  },
215
- pillText: { fontSize: 14, fontWeight: "600" }
228
+ pillText: { fontSize: 14, fontWeight: "600" },
229
+ menuTriggerText: { flexShrink: 1 }
216
230
  });
217
231
  var darkModeStyles = reactNative.StyleSheet.create({
218
232
  // Segmented Light / Dark / System control.
@@ -869,7 +883,11 @@ var NAV_TEST_IDS = {
869
883
  /** links container in the horizontal NavBar. */
870
884
  navBarLinks: "navbar-links",
871
885
  /** the "More ▾" priority+ overflow trigger in the horizontal NavBar (shown when items spill). */
872
- navBarOverflow: "navbar-overflow"
886
+ navBarOverflow: "navbar-overflow",
887
+ /** the compact "Current ▾" trigger of `PillNav` with `variant={PillNavVariant.Menu}`. */
888
+ pillNavMenu: "pill-nav-menu",
889
+ /** the optional middle slot of `Topbar` (rendered only when `center` is passed). */
890
+ topbarCenter: "topbar-center"
873
891
  };
874
892
  var APP_SHELL_SUFFIX = {
875
893
  content: "-content",
@@ -929,6 +947,7 @@ function planToneColor(theme, tone) {
929
947
  }
930
948
  var Topbar = ({
931
949
  left,
950
+ center,
932
951
  language,
933
952
  notificationSlot,
934
953
  user,
@@ -952,6 +971,7 @@ var Topbar = ({
952
971
  ],
953
972
  children: [
954
973
  /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: navStyles.topbarLeft, children: renderTextSlot(left, { color: colors.text }) }),
974
+ center !== void 0 && center !== null ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: navStyles.topbarCenter, testID: NAV_TEST_IDS.topbarCenter, children: renderTextSlot(center, { color: colors.text }) }) : null,
955
975
  /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: navStyles.topbarRight, children: [
956
976
  language ? /* @__PURE__ */ jsxRuntime.jsx(
957
977
  FocusableTouchable,
@@ -977,6 +997,7 @@ var Topbar = ({
977
997
  accessibilityHint: richAccount.accountHint ?? richAccount.displayName,
978
998
  accessibilityLabel: richAccount.displayName,
979
999
  ringColor: primaryColor,
1000
+ style: navStyles.accountNameBtn,
980
1001
  testID: richAccount.accountTestID ?? NAV_TEST_IDS.accountName,
981
1002
  onPress: richAccount.onAccount,
982
1003
  children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [navStyles.userName, { color: colors.text }], children: richAccount.displayName })
@@ -1846,7 +1867,61 @@ var NavShell = ({
1846
1867
  }
1847
1868
  );
1848
1869
  };
1870
+
1871
+ // src/pillMenuLabel.ts
1872
+ function resolvePillMenuLabel(items, pathname, fallback) {
1873
+ const activeRoute = resolveActiveRoute(items, pathname);
1874
+ const active = items.find((item) => item.route === activeRoute);
1875
+ return active?.label ?? fallback;
1876
+ }
1849
1877
  var TEXT_ON_PRIMARY4 = "#ffffff";
1878
+ var NO_ACTIVE_ROUTE2 = "";
1879
+ var PILL_MENU_MIN_WIDTH = 200;
1880
+ var PillNavMenu = ({
1881
+ items,
1882
+ pathname,
1883
+ onNavigate,
1884
+ regionLabel,
1885
+ hint,
1886
+ testID = NAV_TEST_IDS.pillNavMenu,
1887
+ dropdownVariant
1888
+ }) => {
1889
+ const { theme } = uiFeedback.useUi();
1890
+ const primaryColor = theme.palette.primary["500"];
1891
+ const options = React.useMemo(() => items.map((item) => ({ label: item.label, value: item.route })), [items]);
1892
+ const activeRoute = resolveActiveRoute(items, pathname) ?? NO_ACTIVE_ROUTE2;
1893
+ const label = resolvePillMenuLabel(items, pathname, regionLabel);
1894
+ const optionTestID = React.useMemo(() => {
1895
+ const byRoute = new Map(items.map((item) => [item.route, item.testID ?? item.key]));
1896
+ return (route) => byRoute.get(route) ?? `${testID}-option-${route}`;
1897
+ }, [items, testID]);
1898
+ return /* @__PURE__ */ jsxRuntime.jsx(
1899
+ uiLayout.ModalDropdown,
1900
+ {
1901
+ accessibilityHint: hint,
1902
+ accessibilityLabel: label,
1903
+ menuMinWidth: PILL_MENU_MIN_WIDTH,
1904
+ optionTestID,
1905
+ options,
1906
+ testID,
1907
+ value: activeRoute,
1908
+ variant: dropdownVariant,
1909
+ onChange: onNavigate,
1910
+ renderTrigger: ({ isOpen }) => /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [pillNavStyles.pill, { backgroundColor: primaryColor }], children: [
1911
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { numberOfLines: 1, style: [pillNavStyles.pillText, pillNavStyles.menuTriggerText, { color: TEXT_ON_PRIMARY4 }], children: label }),
1912
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [pillNavStyles.pillText, { color: TEXT_ON_PRIMARY4 }], children: isOpen ? "\u25B4" : "\u25BE" })
1913
+ ] })
1914
+ }
1915
+ );
1916
+ };
1917
+
1918
+ // src/PillNavVariant.ts
1919
+ var PillNavVariant = /* @__PURE__ */ ((PillNavVariant2) => {
1920
+ PillNavVariant2["Pills"] = "pills";
1921
+ PillNavVariant2["Menu"] = "menu";
1922
+ return PillNavVariant2;
1923
+ })(PillNavVariant || {});
1924
+ var TEXT_ON_PRIMARY5 = "#ffffff";
1850
1925
  var DEFAULT_MIN_ITEMS = 1;
1851
1926
  var PillNav = ({
1852
1927
  items,
@@ -1855,12 +1930,29 @@ var PillNav = ({
1855
1930
  regionLabel,
1856
1931
  navigateHint = (label) => label,
1857
1932
  minItems = DEFAULT_MIN_ITEMS,
1933
+ variant = "pills" /* Pills */,
1934
+ menuHint,
1935
+ menuTestID,
1936
+ dropdownVariant,
1858
1937
  containerStyle
1859
1938
  }) => {
1860
1939
  const { theme } = uiFeedback.useUi();
1861
1940
  const colors = theme.colors;
1862
1941
  const primaryColor = theme.palette.primary["500"];
1863
1942
  if (items.length < minItems) return null;
1943
+ if (variant === "menu" /* Menu */)
1944
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { accessibilityRole: "none", "aria-label": regionLabel, role: "navigation", style: containerStyle, children: /* @__PURE__ */ jsxRuntime.jsx(
1945
+ PillNavMenu,
1946
+ {
1947
+ dropdownVariant,
1948
+ hint: menuHint ?? regionLabel,
1949
+ items,
1950
+ pathname,
1951
+ regionLabel,
1952
+ testID: menuTestID,
1953
+ onNavigate
1954
+ }
1955
+ ) });
1864
1956
  const activeRoute = resolveActiveRoute(items, pathname);
1865
1957
  return /* @__PURE__ */ jsxRuntime.jsx(
1866
1958
  reactNative.View,
@@ -1871,7 +1963,7 @@ var PillNav = ({
1871
1963
  style: [pillNavStyles.container, containerStyle],
1872
1964
  children: items.map((item) => {
1873
1965
  const active = item.route === activeRoute;
1874
- const textColor = active ? TEXT_ON_PRIMARY4 : colors.textSecondary;
1966
+ const textColor = active ? TEXT_ON_PRIMARY5 : colors.textSecondary;
1875
1967
  const pillStyle = active ? { backgroundColor: primaryColor } : { backgroundColor: colors.surfaceElevated };
1876
1968
  return /* @__PURE__ */ jsxRuntime.jsxs(
1877
1969
  FocusableTouchable,
@@ -1894,7 +1986,7 @@ var PillNav = ({
1894
1986
  }
1895
1987
  );
1896
1988
  };
1897
- var TEXT_ON_PRIMARY5 = "#ffffff";
1989
+ var TEXT_ON_PRIMARY6 = "#ffffff";
1898
1990
  var DARK_MODE_ICON_SIZE = 16;
1899
1991
  var DarkModeControl = ({
1900
1992
  value,
@@ -1943,7 +2035,7 @@ var DarkModeControl = ({
1943
2035
  style: [darkModeStyles.segmentRow, { borderColor: colors.border }, containerStyle],
1944
2036
  children: options.map((option) => {
1945
2037
  const active = option.value === value;
1946
- const textColor = active ? TEXT_ON_PRIMARY5 : colors.textSecondary;
2038
+ const textColor = active ? TEXT_ON_PRIMARY6 : colors.textSecondary;
1947
2039
  return /* @__PURE__ */ jsxRuntime.jsxs(
1948
2040
  FocusableTouchable,
1949
2041
  {
@@ -2151,6 +2243,7 @@ exports.NavExpandableItem = NavExpandableItem;
2151
2243
  exports.NavOverflowMenu = NavOverflowMenu;
2152
2244
  exports.NavShell = NavShell;
2153
2245
  exports.PillNav = PillNav;
2246
+ exports.PillNavVariant = PillNavVariant;
2154
2247
  exports.RAIL_FULL_BREAKPOINT = RAIL_FULL_BREAKPOINT;
2155
2248
  exports.Sidebar = Sidebar;
2156
2249
  exports.SidebarChevron = SidebarChevron;
@@ -2168,6 +2261,7 @@ exports.navStyles = navStyles;
2168
2261
  exports.pillNavStyles = pillNavStyles;
2169
2262
  exports.resolveActiveRoute = resolveActiveRoute;
2170
2263
  exports.resolveContentMaxWidth = resolveContentMaxWidth;
2264
+ exports.resolvePillMenuLabel = resolvePillMenuLabel;
2171
2265
  exports.resolveRailMode = resolveRailMode;
2172
2266
  exports.resolveSearchAffordance = resolveSearchAffordance;
2173
2267
  exports.roleRoutesToNavItems = roleRoutesToNavItems;