@dloizides/ui-nav 1.29.0 → 1.30.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/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { ViewStyle, StyleProp } from 'react-native';
2
+ import { ViewStyle, ImageSourcePropType, StyleProp } from 'react-native';
3
3
  import { UiTheme } from '@dloizides/ui-feedback';
4
4
  import { DropdownVariant } from '@dloizides/ui-layout';
5
5
  import { resolveAccessibleRoutes, RoleRouteTable, RoleRoute } from '@dloizides/auth-web';
@@ -471,6 +471,18 @@ interface BrandHomeLinkProps {
471
471
  /** The app logo as a link to the app's home route, for `NavBar` and apps with their own header. */
472
472
  declare const BrandHomeLink: ({ route, label, onNavigate, children }: BrandHomeLinkProps) => React.ReactElement;
473
473
 
474
+ interface BrandMarkProps {
475
+ source: ImageSourcePropType;
476
+ name: string;
477
+ route: string;
478
+ label: string;
479
+ onNavigate: (route: string) => void;
480
+ size?: number;
481
+ iconOnly?: boolean;
482
+ }
483
+ /** The app icon with its name, as a link to the app's home route. */
484
+ declare const BrandMark: ({ source, name, route, label, onNavigate, size, iconOnly, }: BrandMarkProps) => React.ReactElement;
485
+
474
486
  /**
475
487
  * `Nav` — ONE component that renders EITHER the horizontal top bar (`NavBar`) or the
476
488
  * vertical rail (`Sidebar`) from the same `NavItem[]`, chosen by a single
@@ -1135,6 +1147,8 @@ declare const NAV_TEST_IDS: {
1135
1147
  /** the optional middle slot of `Topbar` (rendered only when `center` is passed). */
1136
1148
  readonly topbarCenter: "topbar-center";
1137
1149
  readonly brandHome: "nav-brand-home";
1150
+ readonly brandMarkIcon: "nav-brand-mark-icon";
1151
+ readonly brandMarkName: "nav-brand-mark-name";
1138
1152
  };
1139
1153
  /** Suffixes appended to an `AppShell`'s required `testID` to name its regions. */
1140
1154
  declare const APP_SHELL_SUFFIX: {
@@ -1653,4 +1667,4 @@ interface BottomTabBarProps {
1653
1667
  /** Phone tab bar; `tabFeedback` picks the press feedback, `Default` adds no motion. */
1654
1668
  declare const BottomTabBar: ({ items, pathname, onNavigate, tabFeedback, navigateHint, regionLabel, containerStyle, testID, }: BottomTabBarProps) => React.ReactElement;
1655
1669
 
1656
- export { ACTIVE_BORDER_RADIUS, ACTIVE_TINT_OPACITY, APP_SHELL_SUFFIX, type AccountPlan, type AccountState, AppShell, type AppShellBackdrop, type AppShellBackdropBand, type AppShellProps, type AppShellWidth, BASE_INDENT, BottomTabBar, type BottomTabBarProps, BrandHomeLink, type BrandHomeLinkProps, 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, NavHoverFeedback, 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, TabFeedback, 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 };
1670
+ export { ACTIVE_BORDER_RADIUS, ACTIVE_TINT_OPACITY, APP_SHELL_SUFFIX, type AccountPlan, type AccountState, AppShell, type AppShellBackdrop, type AppShellBackdropBand, type AppShellProps, type AppShellWidth, BASE_INDENT, BottomTabBar, type BottomTabBarProps, BrandHomeLink, type BrandHomeLinkProps, BrandMark, type BrandMarkProps, 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, NavHoverFeedback, 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, TabFeedback, 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
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { ViewStyle, StyleProp } from 'react-native';
2
+ import { ViewStyle, ImageSourcePropType, StyleProp } from 'react-native';
3
3
  import { UiTheme } from '@dloizides/ui-feedback';
4
4
  import { DropdownVariant } from '@dloizides/ui-layout';
5
5
  import { resolveAccessibleRoutes, RoleRouteTable, RoleRoute } from '@dloizides/auth-web';
@@ -471,6 +471,18 @@ interface BrandHomeLinkProps {
471
471
  /** The app logo as a link to the app's home route, for `NavBar` and apps with their own header. */
472
472
  declare const BrandHomeLink: ({ route, label, onNavigate, children }: BrandHomeLinkProps) => React.ReactElement;
473
473
 
474
+ interface BrandMarkProps {
475
+ source: ImageSourcePropType;
476
+ name: string;
477
+ route: string;
478
+ label: string;
479
+ onNavigate: (route: string) => void;
480
+ size?: number;
481
+ iconOnly?: boolean;
482
+ }
483
+ /** The app icon with its name, as a link to the app's home route. */
484
+ declare const BrandMark: ({ source, name, route, label, onNavigate, size, iconOnly, }: BrandMarkProps) => React.ReactElement;
485
+
474
486
  /**
475
487
  * `Nav` — ONE component that renders EITHER the horizontal top bar (`NavBar`) or the
476
488
  * vertical rail (`Sidebar`) from the same `NavItem[]`, chosen by a single
@@ -1135,6 +1147,8 @@ declare const NAV_TEST_IDS: {
1135
1147
  /** the optional middle slot of `Topbar` (rendered only when `center` is passed). */
1136
1148
  readonly topbarCenter: "topbar-center";
1137
1149
  readonly brandHome: "nav-brand-home";
1150
+ readonly brandMarkIcon: "nav-brand-mark-icon";
1151
+ readonly brandMarkName: "nav-brand-mark-name";
1138
1152
  };
1139
1153
  /** Suffixes appended to an `AppShell`'s required `testID` to name its regions. */
1140
1154
  declare const APP_SHELL_SUFFIX: {
@@ -1653,4 +1667,4 @@ interface BottomTabBarProps {
1653
1667
  /** Phone tab bar; `tabFeedback` picks the press feedback, `Default` adds no motion. */
1654
1668
  declare const BottomTabBar: ({ items, pathname, onNavigate, tabFeedback, navigateHint, regionLabel, containerStyle, testID, }: BottomTabBarProps) => React.ReactElement;
1655
1669
 
1656
- export { ACTIVE_BORDER_RADIUS, ACTIVE_TINT_OPACITY, APP_SHELL_SUFFIX, type AccountPlan, type AccountState, AppShell, type AppShellBackdrop, type AppShellBackdropBand, type AppShellProps, type AppShellWidth, BASE_INDENT, BottomTabBar, type BottomTabBarProps, BrandHomeLink, type BrandHomeLinkProps, 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, NavHoverFeedback, 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, TabFeedback, 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 };
1670
+ export { ACTIVE_BORDER_RADIUS, ACTIVE_TINT_OPACITY, APP_SHELL_SUFFIX, type AccountPlan, type AccountState, AppShell, type AppShellBackdrop, type AppShellBackdropBand, type AppShellProps, type AppShellWidth, BASE_INDENT, BottomTabBar, type BottomTabBarProps, BrandHomeLink, type BrandHomeLinkProps, BrandMark, type BrandMarkProps, 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, NavHoverFeedback, 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, TabFeedback, 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
@@ -884,7 +884,9 @@ var NAV_TEST_IDS = {
884
884
  pillNavMenu: "pill-nav-menu",
885
885
  /** the optional middle slot of `Topbar` (rendered only when `center` is passed). */
886
886
  topbarCenter: "topbar-center",
887
- brandHome: "nav-brand-home"
887
+ brandHome: "nav-brand-home",
888
+ brandMarkIcon: "nav-brand-mark-icon",
889
+ brandMarkName: "nav-brand-mark-name"
888
890
  };
889
891
  var APP_SHELL_SUFFIX = {
890
892
  content: "-content",
@@ -1572,6 +1574,44 @@ var BrandHomeLink = ({ route, label, onNavigate, children }) => {
1572
1574
  }
1573
1575
  );
1574
1576
  };
1577
+ var DEFAULT_ICON_SIZE = 32;
1578
+ var NAME_FONT_SIZE = 16;
1579
+ var NAME_GAP = 8;
1580
+ var styles4 = reactNative.StyleSheet.create({
1581
+ name: { flexShrink: 1, fontSize: NAME_FONT_SIZE, fontWeight: "700" },
1582
+ row: { alignItems: "center", flexDirection: "row", gap: NAME_GAP }
1583
+ });
1584
+ var BrandMark = ({
1585
+ source,
1586
+ name,
1587
+ route,
1588
+ label,
1589
+ onNavigate,
1590
+ size = DEFAULT_ICON_SIZE,
1591
+ iconOnly = false
1592
+ }) => {
1593
+ const { theme } = uiFeedback.useUi();
1594
+ return /* @__PURE__ */ jsxRuntime.jsx(BrandHomeLink, { label, route, onNavigate, children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles4.row, children: [
1595
+ /* @__PURE__ */ jsxRuntime.jsx(
1596
+ reactNative.Image,
1597
+ {
1598
+ accessibilityElementsHidden: true,
1599
+ source,
1600
+ style: { height: size, width: size },
1601
+ testID: NAV_TEST_IDS.brandMarkIcon
1602
+ }
1603
+ ),
1604
+ iconOnly ? null : /* @__PURE__ */ jsxRuntime.jsx(
1605
+ reactNative.Text,
1606
+ {
1607
+ numberOfLines: 1,
1608
+ style: [styles4.name, { color: theme.colors.text }],
1609
+ testID: NAV_TEST_IDS.brandMarkName,
1610
+ children: name
1611
+ }
1612
+ )
1613
+ ] }) });
1614
+ };
1575
1615
  var Nav = (props) => {
1576
1616
  if (props.orientation === "vertical") {
1577
1617
  return /* @__PURE__ */ jsxRuntime.jsx(Sidebar, { ...props });
@@ -1589,7 +1629,7 @@ function resolveRailMode({ viewport, hasSidebar, hasCollapsed, range }) {
1589
1629
  }
1590
1630
  return viewport >= RAIL_FULL_BREAKPOINT ? "full" : "drawer";
1591
1631
  }
1592
- var styles4 = reactNative.StyleSheet.create({
1632
+ var styles5 = reactNative.StyleSheet.create({
1593
1633
  band: { left: 0, position: "absolute", right: 0, top: 0 }
1594
1634
  });
1595
1635
  function readBackdrop(theme) {
@@ -1612,7 +1652,7 @@ function resolveShellBackdrop(theme, viewport, contentPadding, testID) {
1612
1652
  reactNative.View,
1613
1653
  {
1614
1654
  pointerEvents: "none",
1615
- style: [styles4.band, { backgroundColor: band.color, height: contentPadding + overlap }],
1655
+ style: [styles5.band, { backgroundColor: band.color, height: contentPadding + overlap }],
1616
1656
  testID: `${testID}${APP_SHELL_SUFFIX.band}`
1617
1657
  }
1618
1658
  );
@@ -1624,7 +1664,7 @@ var CARD_BORDER_WIDTH = 1;
1624
1664
  var CARD_TITLE_FONT_SIZE = 16;
1625
1665
  var CARD_MESSAGE_FONT_SIZE = 14;
1626
1666
  var CARD_TITLE_MARGIN_BOTTOM = 8;
1627
- var styles5 = reactNative.StyleSheet.create({
1667
+ var styles6 = reactNative.StyleSheet.create({
1628
1668
  // Loading is a TRANSITIONAL state: the spinner is an absolute overlay ON TOP of
1629
1669
  // stably-mounted children, never a replacement for them. Replacing children here
1630
1670
  // would unmount whatever they host (e.g. a navigator), and on remount React
@@ -1656,9 +1696,9 @@ function MessageCard({
1656
1696
  }) {
1657
1697
  const { theme } = uiFeedback.useUi();
1658
1698
  const colors = theme.colors;
1659
- return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles5.card, { backgroundColor: colors.surface, borderColor: accentColor }], testID, children: [
1660
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles5.cardTitle, { color: accentColor }], children: message.titleText }),
1661
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles5.cardMessage, { color: colors.textSecondary }], children: message.messageText })
1699
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles6.card, { backgroundColor: colors.surface, borderColor: accentColor }], testID, children: [
1700
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles6.cardTitle, { color: accentColor }], children: message.titleText }),
1701
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles6.cardMessage, { color: colors.textSecondary }], children: message.messageText })
1662
1702
  ] });
1663
1703
  }
1664
1704
  function useContentBody(state, children, testID) {
@@ -1670,12 +1710,12 @@ function useContentBody(state, children, testID) {
1670
1710
  return /* @__PURE__ */ jsxRuntime.jsx(MessageCard, { accentColor: errorColor, message: state.forbidden, testID: `${testID}${APP_SHELL_SUFFIX.forbidden}` });
1671
1711
  if (state.error)
1672
1712
  return /* @__PURE__ */ jsxRuntime.jsx(MessageCard, { accentColor: errorColor, message: state.error, testID: `${testID}${APP_SHELL_SUFFIX.error}` });
1673
- return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles5.loadingHost, children: [
1713
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles6.loadingHost, children: [
1674
1714
  children,
1675
1715
  state.loading === true ? /* @__PURE__ */ jsxRuntime.jsx(
1676
1716
  reactNative.View,
1677
1717
  {
1678
- style: [styles5.loadingOverlay, { backgroundColor: theme.colors.background }],
1718
+ style: [styles6.loadingOverlay, { backgroundColor: theme.colors.background }],
1679
1719
  testID: `${testID}${APP_SHELL_SUFFIX.loading}`,
1680
1720
  children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: primary, size: "large" })
1681
1721
  }
@@ -1702,7 +1742,7 @@ var DEFAULT_DRAWER_LABELS = {
1702
1742
  closeLabel: "Close menu",
1703
1743
  closeHint: "Close the navigation menu"
1704
1744
  };
1705
- var styles6 = reactNative.StyleSheet.create({
1745
+ var styles7 = reactNative.StyleSheet.create({
1706
1746
  overlay: { ...reactNative.StyleSheet.absoluteFillObject, zIndex: DRAWER_Z_INDEX },
1707
1747
  // The scrim's tap-to-close hit area is anchored to the RIGHT of the panel
1708
1748
  // (`left: DRAWER_WIDTH`), so it NEVER overlaps the panel: nav-item taps always
@@ -1737,10 +1777,10 @@ var MenuToggle = ({ label, hint, onOpen, testID }) => {
1737
1777
  accessibilityHint: hint,
1738
1778
  accessibilityLabel: label,
1739
1779
  ringColor: theme.palette.primary["500"],
1740
- style: styles6.menuToggle,
1780
+ style: styles7.menuToggle,
1741
1781
  testID,
1742
1782
  onPress: onOpen,
1743
- children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles6.menuToggleGlyph, { color: theme.colors.text }], children: MENU_GLYPH2 })
1783
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles7.menuToggleGlyph, { color: theme.colors.text }], children: MENU_GLYPH2 })
1744
1784
  }
1745
1785
  );
1746
1786
  };
@@ -1766,14 +1806,14 @@ var MobileDrawer = ({
1766
1806
  node.addEventListener("click", handleClick);
1767
1807
  return () => node.removeEventListener("click", handleClick);
1768
1808
  }, [onClose]);
1769
- return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles6.overlay, children: [
1809
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles7.overlay, children: [
1770
1810
  /* @__PURE__ */ jsxRuntime.jsx(
1771
1811
  reactNative.Pressable,
1772
1812
  {
1773
1813
  accessibilityHint: labels.closeHint,
1774
1814
  accessibilityLabel: labels.closeLabel,
1775
1815
  accessibilityRole: "button",
1776
- style: styles6.scrim,
1816
+ style: styles7.scrim,
1777
1817
  testID: scrimTestID,
1778
1818
  onPress: onClose
1779
1819
  }
@@ -1784,7 +1824,7 @@ var MobileDrawer = ({
1784
1824
  ref: panelRef,
1785
1825
  "aria-modal": true,
1786
1826
  role: "dialog",
1787
- style: [styles6.panel, { backgroundColor: theme.colors.surface }],
1827
+ style: [styles7.panel, { backgroundColor: theme.colors.surface }],
1788
1828
  testID: drawerTestID,
1789
1829
  children: renderTextSlot(sidebar, { color: theme.colors.text })
1790
1830
  }
@@ -1802,7 +1842,7 @@ function useContentMaxWidth(width) {
1802
1842
  return resolveContentMaxWidth(width, viewport);
1803
1843
  }
1804
1844
  var DEFAULT_CONTENT_PADDING = 24;
1805
- var styles7 = reactNative.StyleSheet.create({
1845
+ var styles8 = reactNative.StyleSheet.create({
1806
1846
  root: { flex: 1 },
1807
1847
  // Auth-pending spinner: an opaque absolute overlay over the mounted shell, so
1808
1848
  // `children` (and any navigator they host) are never unmounted while the gate
@@ -1864,13 +1904,13 @@ var AppShell = ({
1864
1904
  }, [isUnauthenticated, gate]);
1865
1905
  const gatePending = gate?.pending === true;
1866
1906
  if (isUnauthenticated) return null;
1867
- const columnStyle = maxWidth === "full" ? styles7.columnFull : [styles7.columnCapped, { maxWidth }];
1868
- const navInnerStyle = chromeAlignment === "content" && maxWidth !== "full" ? [styles7.chromeCapped, { maxWidth, paddingHorizontal: contentPadding }] : void 0;
1907
+ const columnStyle = maxWidth === "full" ? styles8.columnFull : [styles8.columnCapped, { maxWidth }];
1908
+ const navInnerStyle = chromeAlignment === "content" && maxWidth !== "full" ? [styles8.chromeCapped, { maxWidth, paddingHorizontal: contentPadding }] : void 0;
1869
1909
  const scroller = /* @__PURE__ */ jsxRuntime.jsxs(
1870
1910
  reactNative.ScrollView,
1871
1911
  {
1872
- contentContainerStyle: [styles7.scrollContent, { padding: contentPadding }],
1873
- style: styles7.scroll,
1912
+ contentContainerStyle: [styles8.scrollContent, { padding: contentPadding }],
1913
+ style: styles8.scroll,
1874
1914
  testID: `${testID}${APP_SHELL_SUFFIX.content}`,
1875
1915
  children: [
1876
1916
  look.band,
@@ -1878,7 +1918,7 @@ var AppShell = ({
1878
1918
  ]
1879
1919
  }
1880
1920
  );
1881
- const headerRegion = useDrawer ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles7.headerRow, look.chrome], testID: `${testID}${APP_SHELL_SUFFIX.header}`, children: [
1921
+ const headerRegion = useDrawer ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles8.headerRow, look.chrome], testID: `${testID}${APP_SHELL_SUFFIX.header}`, children: [
1882
1922
  /* @__PURE__ */ jsxRuntime.jsx(
1883
1923
  MenuToggle,
1884
1924
  {
@@ -1888,14 +1928,14 @@ var AppShell = ({
1888
1928
  onOpen: openDrawer
1889
1929
  }
1890
1930
  ),
1891
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles7.headerFill, children: renderTextSlot(header, { color: look.chromeText }) })
1931
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles8.headerFill, children: renderTextSlot(header, { color: look.chromeText }) })
1892
1932
  ] }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: look.chrome, testID: `${testID}${APP_SHELL_SUFFIX.header}`, children: renderTextSlot(header, { color: look.chromeText }) });
1893
1933
  const railRegion = railMode === "full" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { testID: `${testID}${APP_SHELL_SUFFIX.sidebar}`, children: renderTextSlot(sidebar, { color: theme.colors.text }) }) : railMode === "collapsed" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { testID: `${testID}${APP_SHELL_SUFFIX.collapsedSidebar}`, children: renderTextSlot(collapsedSidebar, { color: theme.colors.text }) }) : null;
1894
- return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles7.root, look.root], testID, children: [
1934
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles8.root, look.root], testID, children: [
1895
1935
  headerRegion,
1896
1936
  nav !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: look.chrome, testID: `${testID}${APP_SHELL_SUFFIX.nav}`, children: navInnerStyle !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: navInnerStyle, children: renderTextSlot(nav, { color: look.chromeText }) }) : renderTextSlot(nav, { color: look.chromeText }) }) : null,
1897
1937
  banner !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { testID: `${testID}${APP_SHELL_SUFFIX.banner}`, children: renderTextSlot(banner, { color: theme.colors.text }) }) : null,
1898
- railRegion !== null ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles7.bodyRow, children: [
1938
+ railRegion !== null ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles8.bodyRow, children: [
1899
1939
  railRegion,
1900
1940
  scroller
1901
1941
  ] }) : scroller,
@@ -1912,7 +1952,7 @@ var AppShell = ({
1912
1952
  gatePending ? /* @__PURE__ */ jsxRuntime.jsx(
1913
1953
  reactNative.View,
1914
1954
  {
1915
- style: [styles7.pendingOverlay, { backgroundColor: theme.colors.background }],
1955
+ style: [styles8.pendingOverlay, { backgroundColor: theme.colors.background }],
1916
1956
  testID: `${testID}${APP_SHELL_SUFFIX.pending}`,
1917
1957
  children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: primary, size: "large" })
1918
1958
  }
@@ -2279,7 +2319,7 @@ var KEY_DOWN = "ArrowDown";
2279
2319
  var KEY_UP = "ArrowUp";
2280
2320
  var KEY_ENTER = "Enter";
2281
2321
  var KEY_ESCAPE = "Escape";
2282
- var styles8 = reactNative.StyleSheet.create({
2322
+ var styles9 = reactNative.StyleSheet.create({
2283
2323
  overlay: { ...reactNative.StyleSheet.absoluteFillObject, zIndex: OVERLAY_Z_INDEX, alignItems: "center" },
2284
2324
  scrim: { ...reactNative.StyleSheet.absoluteFillObject, backgroundColor: SCRIM_COLOR2 },
2285
2325
  panel: {
@@ -2308,14 +2348,14 @@ var PaletteRow = ({ item, selected, onChoose }) => {
2308
2348
  accessibilityLabel: item.label,
2309
2349
  accessibilityRole: "button",
2310
2350
  accessibilityState: { selected },
2311
- style: [styles8.row, selected ? { backgroundColor: colors.border } : void 0],
2351
+ style: [styles9.row, selected ? { backgroundColor: colors.border } : void 0],
2312
2352
  testID: item.testID ?? item.key,
2313
2353
  onPress: () => onChoose(item),
2314
2354
  children: [
2315
2355
  typeof item.renderIcon === "function" ? item.renderIcon(colors.textSecondary, NAV_ICON_SIZE) : null,
2316
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles8.rowText, children: [
2317
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles8.rowLabel, { color: colors.text }], children: item.label }),
2318
- item.hint ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles8.rowHint, { color: colors.textSecondary }], children: item.hint }) : null
2356
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles9.rowText, children: [
2357
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles9.rowLabel, { color: colors.text }], children: item.label }),
2358
+ item.hint ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles9.rowHint, { color: colors.textSecondary }], children: item.hint }) : null
2319
2359
  ] })
2320
2360
  ]
2321
2361
  }
@@ -2355,14 +2395,14 @@ var CommandPalette = ({ open, items, onClose, labels, testID }) => {
2355
2395
  [results, selected, choose, onClose]
2356
2396
  );
2357
2397
  if (!open) return null;
2358
- return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles8.overlay, children: [
2398
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles9.overlay, children: [
2359
2399
  /* @__PURE__ */ jsxRuntime.jsx(
2360
2400
  reactNative.Pressable,
2361
2401
  {
2362
2402
  accessibilityHint: labels.closeHint,
2363
2403
  accessibilityLabel: labels.closeLabel,
2364
2404
  accessibilityRole: "button",
2365
- style: styles8.scrim,
2405
+ style: styles9.scrim,
2366
2406
  testID: `${testID ?? "command-palette"}-scrim`,
2367
2407
  onPress: onClose
2368
2408
  }
@@ -2373,7 +2413,7 @@ var CommandPalette = ({ open, items, onClose, labels, testID }) => {
2373
2413
  "aria-modal": true,
2374
2414
  "aria-label": labels.regionLabel,
2375
2415
  role: "dialog",
2376
- style: [styles8.panel, { backgroundColor: colors.surface, borderColor: colors.border }],
2416
+ style: [styles9.panel, { backgroundColor: colors.surface, borderColor: colors.border }],
2377
2417
  testID: testID ?? "command-palette",
2378
2418
  children: [
2379
2419
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -2383,14 +2423,14 @@ var CommandPalette = ({ open, items, onClose, labels, testID }) => {
2383
2423
  accessibilityLabel: labels.placeholder,
2384
2424
  placeholder: labels.placeholder,
2385
2425
  placeholderTextColor: colors.textSecondary,
2386
- style: [styles8.input, { color: colors.text, borderBottomColor: colors.border }],
2426
+ style: [styles9.input, { color: colors.text, borderBottomColor: colors.border }],
2387
2427
  testID: `${testID ?? "command-palette"}-input`,
2388
2428
  value: query,
2389
2429
  onChangeText: setQuery,
2390
2430
  onKeyPress
2391
2431
  }
2392
2432
  ),
2393
- results.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles8.empty, { color: colors.textSecondary }], children: labels.emptyText }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.ScrollView, { keyboardShouldPersistTaps: "handled", style: styles8.list, children: results.map((item, index) => /* @__PURE__ */ jsxRuntime.jsx(PaletteRow, { item, selected: index === selected, onChoose: choose }, item.key)) })
2433
+ results.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles9.empty, { color: colors.textSecondary }], children: labels.emptyText }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.ScrollView, { keyboardShouldPersistTaps: "handled", style: styles9.list, children: results.map((item, index) => /* @__PURE__ */ jsxRuntime.jsx(PaletteRow, { item, selected: index === selected, onChoose: choose }, item.key)) })
2394
2434
  ]
2395
2435
  }
2396
2436
  )
@@ -2495,7 +2535,7 @@ var TAB_MIN_HEIGHT = 56;
2495
2535
  var LABEL_SIZE = 12;
2496
2536
  var LABEL_GAP = 2;
2497
2537
  var TAB_PADDING = 4;
2498
- var styles9 = reactNative.StyleSheet.create({
2538
+ var styles10 = reactNative.StyleSheet.create({
2499
2539
  tab: {
2500
2540
  flex: 1,
2501
2541
  minHeight: TAB_MIN_HEIGHT,
@@ -2532,31 +2572,31 @@ var BottomTab = ({
2532
2572
  accessibilityLabel: item.label,
2533
2573
  accessibilityRole: "link",
2534
2574
  accessibilityState: { selected: isActive },
2535
- style: [styles9.tab, { opacity: feedback.opacity }],
2575
+ style: [styles10.tab, { opacity: feedback.opacity }],
2536
2576
  testID: item.testID ?? item.key,
2537
2577
  onPress: () => onPress(item.route),
2538
2578
  onPressIn: () => setPressed(true),
2539
2579
  onPressOut: () => setPressed(false),
2540
2580
  ...ariaCurrentProps3(isActive),
2541
2581
  children: [
2542
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Animated.View, { style: [styles9.iconWrap, { transform: [{ scale }] }], children: [
2582
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Animated.View, { style: [styles10.iconWrap, { transform: [{ scale }] }], children: [
2543
2583
  feedback.pillScale === null ? null : /* @__PURE__ */ jsxRuntime.jsx(
2544
2584
  reactNative.View,
2545
2585
  {
2546
2586
  pointerEvents: "none",
2547
- style: [styles9.pill, { backgroundColor: colors.pill, transform: [{ scale: feedback.pillScale }] }, motion]
2587
+ style: [styles10.pill, { backgroundColor: colors.pill, transform: [{ scale: feedback.pillScale }] }, motion]
2548
2588
  }
2549
2589
  ),
2550
2590
  /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [{ transform: feedback.iconTransform }, motion], children: item.renderIcon?.(color, ICON_SIZE) })
2551
2591
  ] }),
2552
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles9.label, { color }], children: item.label })
2592
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles10.label, { color }], children: item.label })
2553
2593
  ]
2554
2594
  }
2555
2595
  );
2556
2596
  };
2557
2597
  var DEFAULT_TEST_ID = "bottom-tab-bar";
2558
2598
  var SLIDER_HEIGHT = 3;
2559
- var styles10 = reactNative.StyleSheet.create({
2599
+ var styles11 = reactNative.StyleSheet.create({
2560
2600
  bar: { flexDirection: "row", borderTopWidth: reactNative.StyleSheet.hairlineWidth },
2561
2601
  slider: { position: "absolute", top: 0, height: SLIDER_HEIGHT }
2562
2602
  });
@@ -2583,14 +2623,14 @@ var BottomTabBar = ({
2583
2623
  {
2584
2624
  "aria-label": regionLabel,
2585
2625
  role: "navigation",
2586
- style: [styles10.bar, { backgroundColor: theme.colors.surface, borderTopColor: theme.colors.border }, containerStyle],
2626
+ style: [styles11.bar, { backgroundColor: theme.colors.surface, borderTopColor: theme.colors.border }, containerStyle],
2587
2627
  testID,
2588
2628
  children: [
2589
2629
  bar === null ? null : /* @__PURE__ */ jsxRuntime.jsx(
2590
2630
  reactNative.View,
2591
2631
  {
2592
2632
  pointerEvents: "none",
2593
- style: [styles10.slider, { left: bar.left, width: bar.width, backgroundColor: primary }, webTransition("left", barMs, reducedMotion)]
2633
+ style: [styles11.slider, { left: bar.left, width: bar.width, backgroundColor: primary }, webTransition("left", barMs, reducedMotion)]
2594
2634
  }
2595
2635
  ),
2596
2636
  items.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
@@ -2618,6 +2658,7 @@ exports.AppShell = AppShell;
2618
2658
  exports.BASE_INDENT = BASE_INDENT;
2619
2659
  exports.BottomTabBar = BottomTabBar;
2620
2660
  exports.BrandHomeLink = BrandHomeLink;
2661
+ exports.BrandMark = BrandMark;
2621
2662
  exports.CHEVRON_ICON_SIZE = CHEVRON_ICON_SIZE;
2622
2663
  exports.CollapsedRail = CollapsedRail;
2623
2664
  exports.CommandPalette = CommandPalette;