@dloizides/ui-nav 1.26.1 → 1.27.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.mjs CHANGED
@@ -1,8 +1,8 @@
1
1
  import React, { useState, useCallback, useMemo, useEffect, useRef } from 'react';
2
- import { StyleSheet, Platform, Pressable, Text, View, TextInput, useWindowDimensions, ScrollView, ActivityIndicator } from 'react-native';
2
+ import { StyleSheet, Platform, Pressable, Text, View, TextInput, useWindowDimensions, ScrollView, ActivityIndicator, Animated } from 'react-native';
3
3
  import { useUi, UiProvider } from '@dloizides/ui-feedback';
4
4
  import { jsxs, jsx } from 'react/jsx-runtime';
5
- import { Collapse } from '@dloizides/ui-motion';
5
+ import { Collapse, motionDurations, motionEasings } from '@dloizides/ui-motion';
6
6
  import { LAYOUT_COLLAPSE_BREAKPOINT, ModalDropdown, DropdownVariant, SelectedMarker } from '@dloizides/ui-layout';
7
7
  import { Z_INDEX } from '@dloizides/design-tokens';
8
8
  import { resolveAccessibleRoutes } from '@dloizides/auth-web';
@@ -65,7 +65,7 @@ var navStyles = StyleSheet.create({
65
65
  justifyContent: "space-between"
66
66
  },
67
67
  topbarLeft: { flexGrow: 1, flexShrink: 0 },
68
- topbarCenter: { flexShrink: 1, minWidth: 0, flexDirection: "row", alignItems: "center", marginHorizontal: 8 },
68
+ topbarCenter: { flexShrink: 0, minWidth: 0, flexDirection: "row", alignItems: "center", marginHorizontal: 8 },
69
69
  topbarRight: { flexDirection: "row", alignItems: "center", flexShrink: 1, minWidth: 0 },
70
70
  topbarRowItem: {
71
71
  marginHorizontal: 8,
@@ -1051,10 +1051,88 @@ var Topbar = ({
1051
1051
  }
1052
1052
  );
1053
1053
  };
1054
+
1055
+ // src/NavHoverFeedback.ts
1056
+ var NavHoverFeedback = /* @__PURE__ */ ((NavHoverFeedback2) => {
1057
+ NavHoverFeedback2["Default"] = "default";
1058
+ NavHoverFeedback2["TintPill"] = "tint-pill";
1059
+ NavHoverFeedback2["Underline"] = "underline";
1060
+ NavHoverFeedback2["Lift"] = "lift";
1061
+ NavHoverFeedback2["SlidingHighlight"] = "sliding-highlight";
1062
+ return NavHoverFeedback2;
1063
+ })(NavHoverFeedback || {});
1064
+
1065
+ // src/feedback/navLinkFeedback.ts
1066
+ var DEFAULT_FADE_MS = 150;
1067
+ var PRESS_SCALE = 0.97;
1068
+ var PRESS_NUDGE_PX = 1;
1069
+ var LIFT_PX = -2;
1070
+ var PILL_KINDS = /* @__PURE__ */ new Set([
1071
+ "default" /* Default */,
1072
+ "tint-pill" /* TintPill */,
1073
+ "lift" /* Lift */
1074
+ ]);
1075
+ function pillBackground(kind, isHovered, active, colors) {
1076
+ if (!PILL_KINDS.has(kind)) return void 0;
1077
+ if (active) return colors.activeBg;
1078
+ return isHovered ? colors.hoverBg : void 0;
1079
+ }
1080
+ function linkTextColor(kind, isHovered, active, colors) {
1081
+ if (active) return PILL_KINDS.has(kind) ? colors.onPrimary : colors.activeBg;
1082
+ return isHovered ? colors.hoverText : colors.rest;
1083
+ }
1084
+ function pressTransform(kind, pressed, isHovered) {
1085
+ if (kind === "tint-pill" /* TintPill */) return pressed ? [{ scale: PRESS_SCALE }] : void 0;
1086
+ if (kind === "underline" /* Underline */) return pressed ? [{ translateY: PRESS_NUDGE_PX }] : void 0;
1087
+ if (kind !== "lift" /* Lift */) return void 0;
1088
+ if (pressed) return [{ translateY: 0 }];
1089
+ return isHovered ? [{ translateY: LIFT_PX }] : void 0;
1090
+ }
1091
+ function feedbackDuration(kind) {
1092
+ if (kind === "default" /* Default */) return DEFAULT_FADE_MS;
1093
+ return kind === "tint-pill" /* TintPill */ ? motionDurations.fast : motionDurations.base;
1094
+ }
1095
+ function resolveLinkFeedback(kind, state, colors, reducedMotion) {
1096
+ const isHovered = state.hovered && !state.active;
1097
+ const underlined = state.active || isHovered;
1098
+ return {
1099
+ background: pillBackground(kind, isHovered, state.active, colors),
1100
+ textColor: linkTextColor(kind, isHovered, state.active, colors),
1101
+ transform: reducedMotion ? void 0 : pressTransform(kind, state.pressed, isHovered),
1102
+ shadow: kind === "lift" /* Lift */ && isHovered,
1103
+ underline: kind === "underline" /* Underline */ ? { color: colors.activeBg, scale: underlined ? 1 : 0 } : null,
1104
+ durationMs: reducedMotion ? motionDurations.instant : feedbackDuration(kind)
1105
+ };
1106
+ }
1054
1107
  var TEXT_ON_PRIMARY2 = "#ffffff";
1055
1108
  function ariaCurrentProps2(isActive) {
1056
1109
  return isActive ? { "aria-current": "page" } : {};
1057
1110
  }
1111
+ var FEEDBACK_PROPERTIES = "color, background-color, transform, box-shadow";
1112
+ var UNDERLINE_INSET = 14;
1113
+ var UNDERLINE_HEIGHT = 2;
1114
+ var SHADOW_OPACITY = 0.18;
1115
+ var SHADOW_RADIUS = 6;
1116
+ var SHADOW_OFFSET = { width: 0, height: 2 };
1117
+ function feedbackStyle(kind, feedback, shadowColor, reducedMotion) {
1118
+ const background = feedback.background === void 0 ? {} : { backgroundColor: feedback.background };
1119
+ const shadow = feedback.shadow ? { shadowColor, shadowOpacity: SHADOW_OPACITY, shadowRadius: SHADOW_RADIUS, shadowOffset: SHADOW_OFFSET } : {};
1120
+ const transition = kind === "default" /* Default */ ? hoverTransitionStyle(reducedMotion) : webTransition(FEEDBACK_PROPERTIES, feedback.durationMs, reducedMotion);
1121
+ return [background, shadow, { transform: feedback.transform }, transition ?? {}];
1122
+ }
1123
+ function underlineStyle(feedback, reducedMotion) {
1124
+ if (feedback.underline === null) return null;
1125
+ const line = {
1126
+ position: "absolute",
1127
+ left: UNDERLINE_INSET,
1128
+ right: UNDERLINE_INSET,
1129
+ bottom: 0,
1130
+ height: UNDERLINE_HEIGHT,
1131
+ backgroundColor: feedback.underline.color,
1132
+ transform: [{ scaleX: feedback.underline.scale }]
1133
+ };
1134
+ return [line, webTransition("transform", feedback.durationMs, reducedMotion) ?? {}];
1135
+ }
1058
1136
  var NavBarLink = ({
1059
1137
  item,
1060
1138
  isActive,
@@ -1063,13 +1141,20 @@ var NavBarLink = ({
1063
1141
  reducedMotion,
1064
1142
  colors,
1065
1143
  navigateHint,
1066
- onPress
1144
+ onPress,
1145
+ hoverFeedback = "default" /* Default */,
1146
+ onHoverChange
1067
1147
  }) => {
1068
1148
  const [hovered, setHovered] = useState(false);
1069
1149
  const [focused, setFocused] = useState(false);
1070
- const isHovered = hovered && !isActive;
1071
- const textColor = isActive ? TEXT_ON_PRIMARY2 : isHovered ? colors.hoverText : colors.rest;
1072
- const pillStyle = isActive ? { backgroundColor: colors.activeBg } : isHovered ? { backgroundColor: colors.hoverBg } : void 0;
1150
+ const linkColors = { ...colors, onPrimary: TEXT_ON_PRIMARY2 };
1151
+ const resolve = (pressed) => resolveLinkFeedback(hoverFeedback, { hovered, pressed, active: isActive }, linkColors, reducedMotion);
1152
+ const textColor = resolve(false).textColor;
1153
+ const underline = underlineStyle(resolve(false), reducedMotion);
1154
+ const setHover = (next) => {
1155
+ setHovered(next);
1156
+ onHoverChange?.(item.key, next);
1157
+ };
1073
1158
  return /* @__PURE__ */ jsxs(
1074
1159
  Pressable,
1075
1160
  {
@@ -1077,27 +1162,61 @@ var NavBarLink = ({
1077
1162
  accessibilityLabel: item.label,
1078
1163
  accessibilityRole: "link",
1079
1164
  accessibilityState: { selected: isActive },
1080
- style: [
1165
+ style: ({ pressed }) => [
1081
1166
  navBarStyles.link,
1082
1167
  collapsed ? navBarStyles.linkStacked : void 0,
1083
- pillStyle,
1084
- hoverTransitionStyle(reducedMotion),
1168
+ ...feedbackStyle(hoverFeedback, resolve(pressed), colors.rest, reducedMotion),
1085
1169
  focusRingStyle(focused, colors.ring)
1086
1170
  ],
1087
1171
  testID: item.testID ?? item.key,
1088
1172
  onBlur: () => setFocused(false),
1089
1173
  onFocus: () => setFocused(true),
1090
- onHoverIn: () => setHovered(true),
1091
- onHoverOut: () => setHovered(false),
1174
+ onHoverIn: () => setHover(true),
1175
+ onHoverOut: () => setHover(false),
1092
1176
  onPress: () => onPress(item.route),
1093
1177
  ...ariaCurrentProps2(isActive),
1094
1178
  children: [
1095
1179
  typeof item.renderIcon === "function" ? /* @__PURE__ */ jsx(View, { style: navBarStyles.linkIcon, children: item.renderIcon(textColor, iconSize) }) : null,
1180
+ underline === null ? null : /* @__PURE__ */ jsx(View, { pointerEvents: "none", style: underline }),
1096
1181
  /* @__PURE__ */ jsx(Text, { style: [navBarStyles.linkText, { color: textColor }], children: item.label })
1097
1182
  ]
1098
1183
  }
1099
1184
  );
1100
1185
  };
1186
+ var HIGHLIGHT_RADIUS = 8;
1187
+ var SLIDE_PROPERTIES = "left, top, width, height";
1188
+ function slideHighlightRect(layouts, activeKey, hoveredKey) {
1189
+ const hoveredRect = hoveredKey === null ? void 0 : layouts[hoveredKey];
1190
+ const activeRect = activeKey === void 0 ? void 0 : layouts[activeKey];
1191
+ return hoveredRect ?? activeRect ?? null;
1192
+ }
1193
+ function useSlidingHighlight(enabled, activeKey, color, reducedMotion) {
1194
+ const [layouts, setLayouts] = useState({});
1195
+ const [hoveredKey, setHoveredKey] = useState(null);
1196
+ const measure = useCallback(
1197
+ (key, layout) => {
1198
+ if (enabled) setLayouts((prev) => ({ ...prev, [key]: layout }));
1199
+ },
1200
+ [enabled]
1201
+ );
1202
+ const hover = useCallback((key, hovered) => {
1203
+ setHoveredKey((prev) => hovered ? key : prev === key ? null : prev);
1204
+ }, []);
1205
+ const rect = enabled ? slideHighlightRect(layouts, activeKey, hoveredKey) : null;
1206
+ const style = rect === null ? null : [
1207
+ {
1208
+ position: "absolute",
1209
+ left: rect.x,
1210
+ top: rect.y,
1211
+ width: rect.width,
1212
+ height: rect.height,
1213
+ borderRadius: HIGHLIGHT_RADIUS,
1214
+ backgroundColor: color
1215
+ },
1216
+ webTransition(SLIDE_PROPERTIES, motionDurations.base, reducedMotion)
1217
+ ];
1218
+ return { style, measure, hover };
1219
+ }
1101
1220
  var TEXT_ON_PRIMARY3 = "#ffffff";
1102
1221
  var NO_ACTIVE_ROUTE = "";
1103
1222
  var OVERFLOW_MENU_MIN_WIDTH = 200;
@@ -1238,7 +1357,8 @@ var NavBarInner = ({
1238
1357
  overflowLabel = "More",
1239
1358
  overflowHint = "",
1240
1359
  containerStyle,
1241
- contentMaxWidth
1360
+ contentMaxWidth,
1361
+ hoverFeedback = "default" /* Default */
1242
1362
  }) => {
1243
1363
  const { theme } = useUi();
1244
1364
  const colors = theme.colors;
@@ -1272,6 +1392,12 @@ var NavBarInner = ({
1272
1392
  [onNavigate]
1273
1393
  );
1274
1394
  const activeRoute = resolveActiveRoute(items, pathname);
1395
+ const slide = useSlidingHighlight(
1396
+ hoverFeedback === "sliding-highlight" /* SlidingHighlight */,
1397
+ items.find((item) => item.route === activeRoute)?.key,
1398
+ colors.surfaceElevated,
1399
+ reducedMotion
1400
+ );
1275
1401
  const linkColors = useMemo(
1276
1402
  () => ({
1277
1403
  rest: colors.textSecondary,
@@ -1321,9 +1447,11 @@ var NavBarInner = ({
1321
1447
  colors: linkColors,
1322
1448
  iconSize: NAV_ICON_SIZE,
1323
1449
  isActive: item.route === activeRoute,
1450
+ hoverFeedback,
1324
1451
  item,
1325
1452
  navigateHint,
1326
1453
  reducedMotion,
1454
+ onHoverChange: slide.hover,
1327
1455
  onPress: handlePress
1328
1456
  }
1329
1457
  );
@@ -1349,11 +1477,15 @@ var NavBarInner = ({
1349
1477
  testID: NAV_TEST_IDS.navBarLinks,
1350
1478
  onLayout: (event) => setAvailableWidth(event.nativeEvent.layout.width),
1351
1479
  children: [
1480
+ slide.style === null ? null : /* @__PURE__ */ jsx(View, { pointerEvents: "none", style: slide.style }),
1352
1481
  visibleItems.map((item, index) => /* @__PURE__ */ jsx(
1353
1482
  View,
1354
1483
  {
1355
1484
  style: navBarStyles.linkCell,
1356
- onLayout: (event) => setItemWidth(index, event.nativeEvent.layout.width),
1485
+ onLayout: (event) => {
1486
+ setItemWidth(index, event.nativeEvent.layout.width);
1487
+ slide.measure(item.key, event.nativeEvent.layout);
1488
+ },
1357
1489
  children: renderLink(item)
1358
1490
  },
1359
1491
  item.key
@@ -2214,6 +2346,196 @@ function accessibleNavItems(user, table, translate) {
2214
2346
  return roleRoutesToNavItems(resolveAccessibleRoutes(user, table), translate);
2215
2347
  }
2216
2348
 
2217
- export { ACTIVE_BORDER_RADIUS, ACTIVE_TINT_OPACITY, APP_SHELL_SUFFIX, AppShell, BASE_INDENT, CHEVRON_ICON_SIZE, CollapsedRail, CommandPalette, CommandPaletteTrigger, DEFAULT_COLLAPSED_RAIL_MAX, DEFAULT_SEARCH_BREAKPOINT, DarkModeControl, HOVER_TINT_OPACITY, NAV_ICON_SIZE, NAV_LINK_GAP, NAV_ROW_RADIUS, NAV_TEST_IDS, Nav, NavBar, NavExpandableItem, NavOverflowMenu, NavShell, PillNav, PillNavVariant, RAIL_FULL_BREAKPOINT, Sidebar, SidebarChevron, SidebarSearch, Topbar, accessibleNavItems, collapsedRailStyles, darkModeStyles, expandableStyles, filterCommands, filterNavItems, isFilterActive, isRouteActive, navStyles, pillNavStyles, resolveActiveRoute, resolveContentMaxWidth, resolvePillMenuLabel, resolveRailMode, resolveSearchAffordance, roleRoutesToNavItems, searchTokens, useCommandPaletteHotkey, useContentMaxWidth };
2349
+ // src/TabFeedback.ts
2350
+ var TabFeedback = /* @__PURE__ */ ((TabFeedback2) => {
2351
+ TabFeedback2["Default"] = "default";
2352
+ TabFeedback2["IndicatorPill"] = "indicator-pill";
2353
+ TabFeedback2["DimSpring"] = "dim-spring";
2354
+ TabFeedback2["SlidingBar"] = "sliding-bar";
2355
+ TabFeedback2["IconLift"] = "icon-lift";
2356
+ return TabFeedback2;
2357
+ })(TabFeedback || {});
2358
+
2359
+ // src/feedback/tabPressFeedback.ts
2360
+ var FULL = 1;
2361
+ var PERCENT = 100;
2362
+ var PRESS_ICON_SCALE = 0.92;
2363
+ var DIM_OPACITY = 0.6;
2364
+ var ICON_LIFT_PX = -3;
2365
+ var SPRING_OVERSHOOT = 1.06;
2366
+ function tabIconTransform(kind, state) {
2367
+ if (kind === "indicator-pill" /* IndicatorPill */ && state.pressed) return [{ scale: PRESS_ICON_SCALE }];
2368
+ const lifted = state.active || state.pressed;
2369
+ return kind === "icon-lift" /* IconLift */ && lifted ? [{ translateY: ICON_LIFT_PX }] : void 0;
2370
+ }
2371
+ function tabDuration(kind) {
2372
+ if (kind === "default" /* Default */) return motionDurations.instant;
2373
+ const slow = kind === "dim-spring" /* DimSpring */ || kind === "sliding-bar" /* SlidingBar */;
2374
+ return slow ? motionDurations.slow : motionDurations.base;
2375
+ }
2376
+ function resolveTabFeedback(kind, state, reducedMotion) {
2377
+ const pillScale = state.active ? FULL : 0;
2378
+ return {
2379
+ opacity: kind === "dim-spring" /* DimSpring */ && state.pressed ? DIM_OPACITY : FULL,
2380
+ iconTransform: reducedMotion ? void 0 : tabIconTransform(kind, state),
2381
+ pillScale: kind === "indicator-pill" /* IndicatorPill */ ? pillScale : null,
2382
+ spring: kind === "dim-spring" /* DimSpring */ && !reducedMotion,
2383
+ durationMs: reducedMotion ? motionDurations.instant : tabDuration(kind)
2384
+ };
2385
+ }
2386
+ function slidingBarPosition(activeIndex, count) {
2387
+ if (activeIndex < 0 || count <= 0) return null;
2388
+ const share = PERCENT / count;
2389
+ return { left: `${activeIndex * share}%`, width: `${share}%` };
2390
+ }
2391
+ function springSteps() {
2392
+ return [
2393
+ { toValue: SPRING_OVERSHOOT, durationMs: motionDurations.fast },
2394
+ { toValue: FULL, durationMs: motionDurations.slow - motionDurations.fast }
2395
+ ];
2396
+ }
2397
+ function useSettleSpring(active, enabled) {
2398
+ const scale = useRef(new Animated.Value(FULL)).current;
2399
+ useEffect(() => {
2400
+ if (!enabled || !active) return void 0;
2401
+ const steps = springSteps().map(
2402
+ (step) => Animated.timing(scale, {
2403
+ toValue: step.toValue,
2404
+ duration: step.durationMs,
2405
+ easing: motionEasings.standard,
2406
+ useNativeDriver: false
2407
+ })
2408
+ );
2409
+ const animation = Animated.sequence(steps);
2410
+ animation.start();
2411
+ return () => animation.stop();
2412
+ }, [active, enabled, scale]);
2413
+ return scale;
2414
+ }
2415
+ var ICON_SIZE = 24;
2416
+ var PILL_WIDTH = 56;
2417
+ var PILL_HEIGHT = 32;
2418
+ var PILL_RADIUS = 16;
2419
+ var TAB_MIN_HEIGHT = 56;
2420
+ var LABEL_SIZE = 12;
2421
+ var LABEL_GAP = 2;
2422
+ var TAB_PADDING = 4;
2423
+ var styles7 = StyleSheet.create({
2424
+ tab: {
2425
+ flex: 1,
2426
+ minHeight: TAB_MIN_HEIGHT,
2427
+ alignItems: "center",
2428
+ justifyContent: "center",
2429
+ paddingVertical: TAB_PADDING,
2430
+ rowGap: LABEL_GAP
2431
+ },
2432
+ iconWrap: { width: PILL_WIDTH, height: PILL_HEIGHT, alignItems: "center", justifyContent: "center" },
2433
+ pill: { ...StyleSheet.absoluteFillObject, borderRadius: PILL_RADIUS },
2434
+ label: { fontSize: LABEL_SIZE, textAlign: "center" }
2435
+ });
2436
+ function ariaCurrentProps3(isActive) {
2437
+ return isActive ? { "aria-current": "page" } : {};
2438
+ }
2439
+ var BottomTab = ({
2440
+ item,
2441
+ isActive,
2442
+ kind,
2443
+ colors,
2444
+ reducedMotion,
2445
+ navigateHint,
2446
+ onPress
2447
+ }) => {
2448
+ const [pressed, setPressed] = useState(false);
2449
+ const feedback = resolveTabFeedback(kind, { active: isActive, pressed }, reducedMotion);
2450
+ const scale = useSettleSpring(isActive, feedback.spring);
2451
+ const color = isActive ? colors.active : colors.rest;
2452
+ const motion = webTransition("transform", feedback.durationMs, reducedMotion);
2453
+ return /* @__PURE__ */ jsxs(
2454
+ Pressable,
2455
+ {
2456
+ accessibilityHint: navigateHint(item.label),
2457
+ accessibilityLabel: item.label,
2458
+ accessibilityRole: "link",
2459
+ accessibilityState: { selected: isActive },
2460
+ style: [styles7.tab, { opacity: feedback.opacity }],
2461
+ testID: item.testID ?? item.key,
2462
+ onPress: () => onPress(item.route),
2463
+ onPressIn: () => setPressed(true),
2464
+ onPressOut: () => setPressed(false),
2465
+ ...ariaCurrentProps3(isActive),
2466
+ children: [
2467
+ /* @__PURE__ */ jsxs(Animated.View, { style: [styles7.iconWrap, { transform: [{ scale }] }], children: [
2468
+ feedback.pillScale === null ? null : /* @__PURE__ */ jsx(
2469
+ View,
2470
+ {
2471
+ pointerEvents: "none",
2472
+ style: [styles7.pill, { backgroundColor: colors.pill, transform: [{ scale: feedback.pillScale }] }, motion]
2473
+ }
2474
+ ),
2475
+ /* @__PURE__ */ jsx(View, { style: [{ transform: feedback.iconTransform }, motion], children: item.renderIcon?.(color, ICON_SIZE) })
2476
+ ] }),
2477
+ /* @__PURE__ */ jsx(Text, { style: [styles7.label, { color }], children: item.label })
2478
+ ]
2479
+ }
2480
+ );
2481
+ };
2482
+ var DEFAULT_TEST_ID = "bottom-tab-bar";
2483
+ var SLIDER_HEIGHT = 3;
2484
+ var styles8 = StyleSheet.create({
2485
+ bar: { flexDirection: "row", borderTopWidth: StyleSheet.hairlineWidth },
2486
+ slider: { position: "absolute", top: 0, height: SLIDER_HEIGHT }
2487
+ });
2488
+ var BottomTabBar = ({
2489
+ items,
2490
+ pathname,
2491
+ onNavigate,
2492
+ tabFeedback = "default" /* Default */,
2493
+ navigateHint = (label) => label,
2494
+ regionLabel = "",
2495
+ containerStyle,
2496
+ testID = DEFAULT_TEST_ID
2497
+ }) => {
2498
+ const { theme } = useUi();
2499
+ const reducedMotion = useReducedMotion();
2500
+ const primary = theme.palette.primary["500"];
2501
+ const activeRoute = resolveActiveRoute(items, pathname);
2502
+ const activeIndex = items.findIndex((item) => item.route === activeRoute);
2503
+ const bar = tabFeedback === "sliding-bar" /* SlidingBar */ ? slidingBarPosition(activeIndex, items.length) : null;
2504
+ const barMs = resolveTabFeedback(tabFeedback, { active: true, pressed: false }, reducedMotion).durationMs;
2505
+ const colors = { active: primary, rest: theme.colors.textSecondary, pill: theme.colors.surfaceElevated };
2506
+ return /* @__PURE__ */ jsxs(
2507
+ View,
2508
+ {
2509
+ "aria-label": regionLabel,
2510
+ role: "navigation",
2511
+ style: [styles8.bar, { backgroundColor: theme.colors.surface, borderTopColor: theme.colors.border }, containerStyle],
2512
+ testID,
2513
+ children: [
2514
+ bar === null ? null : /* @__PURE__ */ jsx(
2515
+ View,
2516
+ {
2517
+ pointerEvents: "none",
2518
+ style: [styles8.slider, { left: bar.left, width: bar.width, backgroundColor: primary }, webTransition("left", barMs, reducedMotion)]
2519
+ }
2520
+ ),
2521
+ items.map((item) => /* @__PURE__ */ jsx(
2522
+ BottomTab,
2523
+ {
2524
+ colors,
2525
+ isActive: item.route === activeRoute,
2526
+ item,
2527
+ kind: tabFeedback,
2528
+ navigateHint,
2529
+ reducedMotion,
2530
+ onPress: onNavigate
2531
+ },
2532
+ item.key
2533
+ ))
2534
+ ]
2535
+ }
2536
+ );
2537
+ };
2538
+
2539
+ export { ACTIVE_BORDER_RADIUS, ACTIVE_TINT_OPACITY, APP_SHELL_SUFFIX, AppShell, BASE_INDENT, BottomTabBar, CHEVRON_ICON_SIZE, CollapsedRail, CommandPalette, CommandPaletteTrigger, DEFAULT_COLLAPSED_RAIL_MAX, DEFAULT_SEARCH_BREAKPOINT, DarkModeControl, HOVER_TINT_OPACITY, NAV_ICON_SIZE, NAV_LINK_GAP, NAV_ROW_RADIUS, NAV_TEST_IDS, Nav, NavBar, NavExpandableItem, NavHoverFeedback, NavOverflowMenu, NavShell, PillNav, PillNavVariant, RAIL_FULL_BREAKPOINT, Sidebar, SidebarChevron, SidebarSearch, TabFeedback, Topbar, accessibleNavItems, collapsedRailStyles, darkModeStyles, expandableStyles, filterCommands, filterNavItems, isFilterActive, isRouteActive, navStyles, pillNavStyles, resolveActiveRoute, resolveContentMaxWidth, resolvePillMenuLabel, resolveRailMode, resolveSearchAffordance, roleRoutesToNavItems, searchTokens, useCommandPaletteHotkey, useContentMaxWidth };
2218
2540
  //# sourceMappingURL=index.mjs.map
2219
2541
  //# sourceMappingURL=index.mjs.map