@dloizides/ui-nav 1.13.1 → 1.16.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,12 +1,45 @@
1
- import { StyleSheet, Platform, TouchableOpacity, View, Text, useWindowDimensions, ActivityIndicator, ScrollView, Pressable, TextInput } from 'react-native';
1
+ import React3, { useState, useCallback, useMemo, useEffect, useRef } from 'react';
2
+ import { StyleSheet, Platform, Text, TouchableOpacity, View, TextInput, Pressable, useWindowDimensions, ActivityIndicator, ScrollView } from 'react-native';
2
3
  import { useUi, UiProvider } from '@dloizides/ui-feedback';
3
- import React2, { useState, useCallback, useMemo, useEffect, useRef } from 'react';
4
- import { jsxs, jsx } from 'react/jsx-runtime';
4
+ import { Collapse } from '@dloizides/ui-motion';
5
+ import { jsx, jsxs } from 'react/jsx-runtime';
5
6
  import { ModalDropdown } from '@dloizides/ui-layout';
6
7
  import { resolveAccessibleRoutes } from '@dloizides/auth-web';
7
8
 
8
9
  // src/Sidebar.tsx
9
10
 
11
+ // src/sidebarFilter.ts
12
+ function searchTokens(query) {
13
+ return query.trim().toLowerCase().split(/\s+/).filter(Boolean);
14
+ }
15
+ function labelMatches(item, tokens) {
16
+ const label = item.label.toLowerCase();
17
+ return tokens.every((token) => label.includes(token));
18
+ }
19
+ function filterNavItems(items, query) {
20
+ const tokens = searchTokens(query);
21
+ if (tokens.length === 0) return [...items];
22
+ return filterByTokens(items, tokens);
23
+ }
24
+ function filterByTokens(items, tokens) {
25
+ const kept = [];
26
+ for (const item of items) {
27
+ const selfMatch = labelMatches(item, tokens);
28
+ const children = item.children ?? [];
29
+ if (selfMatch) {
30
+ kept.push(item);
31
+ continue;
32
+ }
33
+ if (children.length === 0) continue;
34
+ const prunedChildren = filterByTokens(children, tokens);
35
+ if (prunedChildren.length > 0) kept.push({ ...item, children: prunedChildren });
36
+ }
37
+ return kept;
38
+ }
39
+ function isFilterActive(query) {
40
+ return searchTokens(query).length > 0;
41
+ }
42
+
10
43
  // src/isRouteActive.ts
11
44
  function isRouteActive(pathname, route) {
12
45
  if (route === "/") return pathname === "/";
@@ -14,6 +47,9 @@ function isRouteActive(pathname, route) {
14
47
  }
15
48
  var ACTIVE_BORDER_RADIUS = 4;
16
49
  var ACTIVE_ACCENT_WIDTH = 3;
50
+ var NAV_ROW_RADIUS = 8;
51
+ var ACTIVE_TINT_OPACITY = 0.14;
52
+ var HOVER_TINT_OPACITY = 0.06;
17
53
  var NAV_LINK_GAP = 4;
18
54
  var navStyles = StyleSheet.create({
19
55
  // --- Sidebar ---
@@ -39,6 +75,12 @@ var navStyles = StyleSheet.create({
39
75
  sidebarSpacer: {
40
76
  flex: 1
41
77
  },
78
+ // Inline-search no-match text — sits where the nav list would, muted + padded.
79
+ sidebarEmpty: {
80
+ fontSize: 13,
81
+ paddingVertical: 10,
82
+ paddingHorizontal: 12
83
+ },
42
84
  // --- Topbar ---
43
85
  topbarContainer: {
44
86
  height: 64,
@@ -239,8 +281,12 @@ var collapsedRailStyles = StyleSheet.create({
239
281
  var expandableStyles = StyleSheet.create({
240
282
  // Every leaf reserves the accent-bar gutter (a TRANSPARENT left border of the
241
283
  // same width the active item colours in) so activation never shifts the row.
284
+ // `overflow: hidden` clips the rounded {@link tintOverlay} to the row's corners;
285
+ // `position: relative` anchors that absolutely-filled overlay to the row.
242
286
  childItem: {
243
- borderRadius: 6,
287
+ position: "relative",
288
+ overflow: "hidden",
289
+ borderRadius: NAV_ROW_RADIUS,
244
290
  flexDirection: "row",
245
291
  alignItems: "center",
246
292
  paddingVertical: 9,
@@ -251,8 +297,24 @@ var expandableStyles = StyleSheet.create({
251
297
  childItemTextWithIcon: { fontSize: 14, marginLeft: 6 },
252
298
  chevron: { marginLeft: "auto" },
253
299
  childrenContainer: { overflow: "hidden", marginBottom: 4 },
300
+ // The hover/active brand wash: a rounded fill behind the row's icon + label,
301
+ // its opacity eased between 0 / hover / active. Colour + opacity are applied at
302
+ // render time (theme primary); this only positions and rounds it.
303
+ tintOverlay: {
304
+ position: "absolute",
305
+ top: 0,
306
+ left: 0,
307
+ right: 0,
308
+ bottom: 0,
309
+ borderRadius: NAV_ROW_RADIUS,
310
+ // `style.pointerEvents` (not the deprecated prop) so the overlay never
311
+ // intercepts the row's press/hover — RNW forwards this style key to the DOM.
312
+ pointerEvents: "none"
313
+ },
254
314
  header: {
255
- borderRadius: 6,
315
+ position: "relative",
316
+ overflow: "hidden",
317
+ borderRadius: NAV_ROW_RADIUS,
256
318
  flexDirection: "row",
257
319
  alignItems: "center",
258
320
  paddingVertical: 8
@@ -279,6 +341,7 @@ var IS_WEB = Platform.OS === "web";
279
341
  var FOCUS_RING_WIDTH = 2;
280
342
  var FOCUS_RING_OFFSET = 2;
281
343
  var HOVER_TRANSITION_MS = 150;
344
+ var TINT_TRANSITION_MS = 160;
282
345
  function focusRingStyle(focused, ringColor) {
283
346
  if (!IS_WEB || !focused) return void 0;
284
347
  const ring = {
@@ -289,24 +352,80 @@ function focusRingStyle(focused, ringColor) {
289
352
  };
290
353
  return ring;
291
354
  }
292
- function hoverTransitionStyle(reducedMotion) {
355
+ function webTransition(properties, durationMs, reducedMotion) {
293
356
  if (!IS_WEB) return void 0;
294
357
  const transition = {
295
- transitionProperty: "color, background-color",
296
- transitionDuration: reducedMotion ? "0ms" : `${HOVER_TRANSITION_MS}ms`
358
+ transitionProperty: properties,
359
+ transitionDuration: reducedMotion ? "0ms" : `${durationMs}ms`
297
360
  };
298
361
  return transition;
299
362
  }
363
+ function hoverTransitionStyle(reducedMotion) {
364
+ return webTransition("color, background-color", HOVER_TRANSITION_MS, reducedMotion);
365
+ }
366
+ function tintTransitionStyle(reducedMotion) {
367
+ return webTransition("opacity", TINT_TRANSITION_MS, reducedMotion);
368
+ }
369
+ function rotateTransitionStyle(reducedMotion) {
370
+ return webTransition("transform", TINT_TRANSITION_MS, reducedMotion);
371
+ }
372
+ var REDUCED_MOTION_QUERY = "(prefers-reduced-motion: reduce)";
373
+ function getReducedMotionQuery() {
374
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") return void 0;
375
+ return window.matchMedia(REDUCED_MOTION_QUERY);
376
+ }
377
+ function useReducedMotion() {
378
+ const [reduced, setReduced] = useState(() => getReducedMotionQuery()?.matches ?? false);
379
+ useEffect(() => {
380
+ const mql = getReducedMotionQuery();
381
+ if (mql === void 0 || mql.addEventListener === void 0) return void 0;
382
+ const onChange = () => setReduced(mql.matches);
383
+ mql.addEventListener("change", onChange);
384
+ return () => {
385
+ mql.removeEventListener?.("change", onChange);
386
+ };
387
+ }, []);
388
+ return reduced;
389
+ }
390
+ var CHEVRON_GLYPH = "\u203A";
391
+ var EXPANDED_ROTATION = "90deg";
392
+ var COLLAPSED_ROTATION = "0deg";
393
+ var CHEVRON_FONT_WEIGHT = "700";
394
+ var SidebarChevron = ({ expanded, color, size }) => {
395
+ const reducedMotion = useReducedMotion();
396
+ const style = {
397
+ color,
398
+ fontSize: size,
399
+ fontWeight: CHEVRON_FONT_WEIGHT,
400
+ transform: [{ rotate: expanded ? EXPANDED_ROTATION : COLLAPSED_ROTATION }]
401
+ };
402
+ return /* @__PURE__ */ jsx(
403
+ Text,
404
+ {
405
+ accessibilityElementsHidden: true,
406
+ importantForAccessibility: "no",
407
+ style: [style, rotateTransitionStyle(reducedMotion)],
408
+ children: CHEVRON_GLYPH
409
+ }
410
+ );
411
+ };
300
412
  function ariaCurrentProps(isActive) {
301
413
  return isActive ? { "aria-current": "page" } : {};
302
414
  }
303
415
  function ariaExpandedProps(expanded) {
304
416
  return { "aria-expanded": expanded };
305
417
  }
418
+ function hoverHandlerProps(onIn, onOut) {
419
+ return IS_WEB ? { onHoverIn: onIn, onHoverOut: onOut } : {};
420
+ }
306
421
  function hasActiveDescendant(item, pathname) {
307
422
  if (isRouteActive(pathname, item.route)) return true;
308
423
  return (item.children ?? []).some((child) => hasActiveDescendant(child, pathname));
309
424
  }
425
+ function TintOverlay({ opacity, color }) {
426
+ const reducedMotion = useReducedMotion();
427
+ return /* @__PURE__ */ jsx(View, { style: [expandableStyles.tintOverlay, { backgroundColor: color, opacity }, tintTransitionStyle(reducedMotion)] });
428
+ }
310
429
  var NavExpandableItem = ({
311
430
  item,
312
431
  pathname,
@@ -319,25 +438,25 @@ var NavExpandableItem = ({
319
438
  }) => {
320
439
  const [expanded, setExpanded] = useState(() => hasActiveDescendant(item, pathname));
321
440
  const [focused, setFocused] = useState(false);
441
+ const [hovered, setHovered] = useState(false);
322
442
  const { theme } = useUi();
323
443
  const colors = theme.colors;
324
444
  const primaryColor = theme.palette.primary["500"];
325
445
  const toggle = useCallback(() => setExpanded((v) => !v), []);
446
+ const onHoverIn = useCallback(() => setHovered(true), []);
447
+ const onHoverOut = useCallback(() => setHovered(false), []);
326
448
  const indent = depth * BASE_INDENT;
327
449
  const hasChildren = Array.isArray(item.children) && item.children.length > 0;
328
450
  const isActive = isRouteActive(pathname, item.route);
329
451
  const isSectionHeader = hasChildren && depth === 0;
330
- const activeItemStyle = useMemo(
331
- () => ({
332
- backgroundColor: colors.border,
333
- borderRadius: ACTIVE_BORDER_RADIUS,
334
- borderLeftWidth: ACTIVE_ACCENT_WIDTH,
335
- borderLeftColor: primaryColor
336
- }),
337
- [colors.border, primaryColor]
452
+ const activeAccentStyle = useMemo(
453
+ () => ({ borderLeftWidth: ACTIVE_ACCENT_WIDTH, borderLeftColor: primaryColor }),
454
+ [primaryColor]
338
455
  );
339
456
  const paddingStyle = useMemo(() => ({ paddingLeft: indent + BASE_INDENT }), [indent]);
340
457
  const headerPaddingStyle = useMemo(() => ({ paddingLeft: indent }), [indent]);
458
+ const leafTintOpacity = isActive ? ACTIVE_TINT_OPACITY : hovered ? HOVER_TINT_OPACITY : 0;
459
+ const headerTintOpacity = hovered ? HOVER_TINT_OPACITY : 0;
341
460
  if (!hasChildren)
342
461
  return /* @__PURE__ */ jsxs(
343
462
  TouchableOpacity,
@@ -349,15 +468,17 @@ var NavExpandableItem = ({
349
468
  style: [
350
469
  expandableStyles.childItem,
351
470
  paddingStyle,
352
- isActive ? activeItemStyle : void 0,
471
+ isActive ? activeAccentStyle : void 0,
353
472
  focusRingStyle(focused, primaryColor)
354
473
  ],
355
474
  testID: item.testID ?? item.key,
356
475
  onBlur: () => setFocused(false),
357
476
  onFocus: () => setFocused(true),
358
477
  onPress: () => onNavigate(item.route),
478
+ ...hoverHandlerProps(onHoverIn, onHoverOut),
359
479
  ...ariaCurrentProps(isActive),
360
480
  children: [
481
+ /* @__PURE__ */ jsx(TintOverlay, { color: primaryColor, opacity: leafTintOpacity }),
361
482
  typeof item.renderIcon === "function" ? /* @__PURE__ */ jsx(View, { style: expandableStyles.iconWrapper, children: item.renderIcon(colors.textSecondary, NAV_ICON_SIZE) }) : null,
362
483
  /* @__PURE__ */ jsx(
363
484
  Text,
@@ -372,6 +493,7 @@ var NavExpandableItem = ({
372
493
  ]
373
494
  }
374
495
  );
496
+ const chevronColor = colors.textSecondary;
375
497
  return /* @__PURE__ */ jsxs(View, { children: [
376
498
  /* @__PURE__ */ jsxs(
377
499
  TouchableOpacity,
@@ -390,8 +512,10 @@ var NavExpandableItem = ({
390
512
  onBlur: () => setFocused(false),
391
513
  onFocus: () => setFocused(true),
392
514
  onPress: toggle,
515
+ ...hoverHandlerProps(onHoverIn, onHoverOut),
393
516
  ...ariaExpandedProps(expanded),
394
517
  children: [
518
+ /* @__PURE__ */ jsx(TintOverlay, { color: primaryColor, opacity: headerTintOpacity }),
395
519
  typeof item.renderIcon === "function" ? /* @__PURE__ */ jsx(View, { style: expandableStyles.iconWrapper, children: item.renderIcon(isSectionHeader ? colors.textSecondary : colors.text, NAV_ICON_SIZE) }) : null,
396
520
  /* @__PURE__ */ jsx(
397
521
  Text,
@@ -403,11 +527,11 @@ var NavExpandableItem = ({
403
527
  children: item.label
404
528
  }
405
529
  ),
406
- typeof renderChevron === "function" ? /* @__PURE__ */ jsx(View, { style: expandableStyles.chevron, children: renderChevron(expanded, colors.textSecondary, CHEVRON_ICON_SIZE) }) : null
530
+ /* @__PURE__ */ jsx(View, { style: expandableStyles.chevron, children: typeof renderChevron === "function" ? renderChevron(expanded, chevronColor, CHEVRON_ICON_SIZE) : /* @__PURE__ */ jsx(SidebarChevron, { color: chevronColor, expanded, size: CHEVRON_ICON_SIZE }) })
407
531
  ]
408
532
  }
409
533
  ),
410
- expanded ? /* @__PURE__ */ jsx(View, { style: expandableStyles.childrenContainer, children: item.children?.map((child) => /* @__PURE__ */ jsx(
534
+ /* @__PURE__ */ jsx(Collapse, { open: expanded, children: /* @__PURE__ */ jsx(View, { style: expandableStyles.childrenContainer, children: item.children?.map((child) => /* @__PURE__ */ jsx(
411
535
  NavExpandableItem,
412
536
  {
413
537
  collapseHint,
@@ -420,16 +544,96 @@ var NavExpandableItem = ({
420
544
  onNavigate
421
545
  },
422
546
  child.key
423
- )) }) : null
547
+ )) }) })
424
548
  ] });
425
549
  };
550
+ var FIELD_MIN_HEIGHT = 38;
551
+ var CLEAR_GLYPH = "\u2715";
552
+ var CLEAR_MIN_TARGET = 28;
553
+ var styles = StyleSheet.create({
554
+ wrap: {
555
+ flexDirection: "row",
556
+ alignItems: "center",
557
+ borderWidth: 1,
558
+ borderRadius: 8,
559
+ paddingLeft: 12,
560
+ paddingRight: 6,
561
+ marginBottom: 12
562
+ },
563
+ input: {
564
+ flex: 1,
565
+ fontSize: 14,
566
+ paddingVertical: 8,
567
+ minHeight: FIELD_MIN_HEIGHT
568
+ },
569
+ clear: {
570
+ minWidth: CLEAR_MIN_TARGET,
571
+ minHeight: CLEAR_MIN_TARGET,
572
+ alignItems: "center",
573
+ justifyContent: "center",
574
+ borderRadius: 6
575
+ },
576
+ clearGlyph: { fontSize: 13, fontWeight: "700" }
577
+ });
578
+ var SidebarSearch = ({
579
+ value,
580
+ onChangeText,
581
+ onClear,
582
+ labels,
583
+ testID
584
+ }) => {
585
+ const { theme } = useUi();
586
+ const colors = theme.colors;
587
+ const primary = theme.palette.primary["500"];
588
+ const [focused, setFocused] = useState(false);
589
+ const hasQuery = value.length > 0;
590
+ return /* @__PURE__ */ jsxs(
591
+ View,
592
+ {
593
+ style: [
594
+ styles.wrap,
595
+ { backgroundColor: colors.surface, borderColor: focused ? primary : colors.border },
596
+ focusRingStyle(focused, primary)
597
+ ],
598
+ children: [
599
+ /* @__PURE__ */ jsx(
600
+ TextInput,
601
+ {
602
+ accessibilityHint: labels.hint,
603
+ accessibilityLabel: labels.placeholder,
604
+ placeholder: labels.placeholder,
605
+ placeholderTextColor: colors.textSecondary,
606
+ style: [styles.input, { color: colors.text }],
607
+ testID,
608
+ value,
609
+ onBlur: () => setFocused(false),
610
+ onChangeText,
611
+ onFocus: () => setFocused(true)
612
+ }
613
+ ),
614
+ hasQuery ? /* @__PURE__ */ jsx(
615
+ Pressable,
616
+ {
617
+ accessibilityHint: labels.clearHint,
618
+ accessibilityLabel: labels.clearLabel,
619
+ accessibilityRole: "button",
620
+ style: styles.clear,
621
+ testID: `${testID}-clear`,
622
+ onPress: onClear,
623
+ children: /* @__PURE__ */ jsx(Text, { style: [styles.clearGlyph, { color: colors.textSecondary }], children: CLEAR_GLYPH })
624
+ }
625
+ ) : null
626
+ ]
627
+ }
628
+ );
629
+ };
426
630
  function isBareText(node) {
427
631
  return typeof node === "string" || typeof node === "number";
428
632
  }
429
633
  function renderTextSlot(node, style) {
430
634
  if (node === void 0 || node === null) return node;
431
635
  if (isBareText(node)) return /* @__PURE__ */ jsx(Text, { style, children: node });
432
- return React2.Children.map(
636
+ return React3.Children.map(
433
637
  node,
434
638
  (child) => isBareText(child) ? /* @__PURE__ */ jsx(Text, { style, children: child }) : child
435
639
  );
@@ -444,12 +648,30 @@ var Sidebar = ({
444
648
  expandHint = "",
445
649
  collapseHint = "",
446
650
  renderChevron,
651
+ enableInlineSearch = false,
652
+ search,
653
+ searchQuery,
654
+ onSearchChange,
447
655
  header,
448
656
  footer,
449
657
  containerStyle
450
658
  }) => {
451
659
  const { theme } = useUi();
452
660
  const colors = theme.colors;
661
+ const [internalQuery, setInternalQuery] = useState("");
662
+ const controlled = searchQuery !== void 0;
663
+ const query = controlled ? searchQuery : internalQuery;
664
+ const setQuery = useCallback(
665
+ (next) => {
666
+ if (!controlled) setInternalQuery(next);
667
+ onSearchChange?.(next);
668
+ },
669
+ [controlled, onSearchChange]
670
+ );
671
+ const clearQuery = useCallback(() => setQuery(""), [setQuery]);
672
+ const searchOn = enableInlineSearch && search !== void 0;
673
+ const visibleItems = searchOn ? filterNavItems(items, query) : items;
674
+ const showEmpty = searchOn && isFilterActive(query) && visibleItems.length === 0;
453
675
  return /* @__PURE__ */ jsxs(
454
676
  View,
455
677
  {
@@ -463,8 +685,18 @@ var Sidebar = ({
463
685
  ],
464
686
  children: [
465
687
  /* @__PURE__ */ jsx(Text, { accessibilityRole: "header", style: [navStyles.sidebarTitle, { color: colors.text }], children: title }),
688
+ searchOn && search !== void 0 ? /* @__PURE__ */ jsx(
689
+ SidebarSearch,
690
+ {
691
+ labels: search,
692
+ testID: "sidebar-search",
693
+ value: query,
694
+ onChangeText: setQuery,
695
+ onClear: clearQuery
696
+ }
697
+ ) : null,
466
698
  renderTextSlot(header, { color: colors.text }),
467
- items.map((item) => /* @__PURE__ */ jsx(
699
+ showEmpty && search !== void 0 ? /* @__PURE__ */ jsx(Text, { style: [navStyles.sidebarEmpty, { color: colors.textSecondary }], testID: "sidebar-search-empty", children: search.emptyText }) : visibleItems.map((item) => /* @__PURE__ */ jsx(
468
700
  NavExpandableItem,
469
701
  {
470
702
  collapseHint,
@@ -484,6 +716,12 @@ var Sidebar = ({
484
716
  );
485
717
  };
486
718
 
719
+ // src/searchAffordance.ts
720
+ var DEFAULT_SEARCH_BREAKPOINT = 768;
721
+ function resolveSearchAffordance(viewport, breakpoint = DEFAULT_SEARCH_BREAKPOINT) {
722
+ return viewport >= breakpoint ? "inline" : "palette";
723
+ }
724
+
487
725
  // src/constants.ts
488
726
  var NAV_TEST_IDS = {
489
727
  /** displayName line in the rich account header (tappable when `onAccount` set). */
@@ -819,24 +1057,6 @@ function useNavOverflow(itemCount, gap) {
819
1057
  );
820
1058
  return { visibleCount, setAvailableWidth, setItemWidth, setMoreWidth };
821
1059
  }
822
- var REDUCED_MOTION_QUERY = "(prefers-reduced-motion: reduce)";
823
- function getReducedMotionQuery() {
824
- if (typeof window === "undefined" || typeof window.matchMedia !== "function") return void 0;
825
- return window.matchMedia(REDUCED_MOTION_QUERY);
826
- }
827
- function useReducedMotion() {
828
- const [reduced, setReduced] = useState(() => getReducedMotionQuery()?.matches ?? false);
829
- useEffect(() => {
830
- const mql = getReducedMotionQuery();
831
- if (mql === void 0 || mql.addEventListener === void 0) return void 0;
832
- const onChange = () => setReduced(mql.matches);
833
- mql.addEventListener("change", onChange);
834
- return () => {
835
- mql.removeEventListener?.("change", onChange);
836
- };
837
- }, []);
838
- return reduced;
839
- }
840
1060
  var LINKS_REGION_ID = "navbar-links-region";
841
1061
  var DEFAULT_COLLAPSE_BELOW = 760;
842
1062
  var MENU_GLYPH = "\u2630";
@@ -937,7 +1157,7 @@ var NavBarInner = ({
937
1157
  }
938
1158
  );
939
1159
  if (collapsed) {
940
- return /* @__PURE__ */ jsx(View, { nativeID: LINKS_REGION_ID, style: navBarStyles.linksStacked, testID: NAV_TEST_IDS.navBarLinks, children: items.map((item) => /* @__PURE__ */ jsx(React2.Fragment, { children: renderLink(item) }, item.key)) });
1160
+ return /* @__PURE__ */ jsx(View, { nativeID: LINKS_REGION_ID, style: navBarStyles.linksStacked, testID: NAV_TEST_IDS.navBarLinks, children: items.map((item) => /* @__PURE__ */ jsx(React3.Fragment, { children: renderLink(item) }, item.key)) });
941
1161
  }
942
1162
  const visibleItems = items.slice(0, visibleCount);
943
1163
  const overflowItems = items.slice(visibleCount);
@@ -1003,7 +1223,7 @@ var CARD_BORDER_WIDTH = 1;
1003
1223
  var CARD_TITLE_FONT_SIZE = 16;
1004
1224
  var CARD_MESSAGE_FONT_SIZE = 14;
1005
1225
  var CARD_TITLE_MARGIN_BOTTOM = 8;
1006
- var styles = StyleSheet.create({
1226
+ var styles2 = StyleSheet.create({
1007
1227
  centerFill: { flex: 1, justifyContent: "center", alignItems: "center" },
1008
1228
  card: {
1009
1229
  padding: CARD_PADDING,
@@ -1020,9 +1240,9 @@ function MessageCard({
1020
1240
  }) {
1021
1241
  const { theme } = useUi();
1022
1242
  const colors = theme.colors;
1023
- return /* @__PURE__ */ jsxs(View, { style: [styles.card, { backgroundColor: colors.surface, borderColor: accentColor }], testID, children: [
1024
- /* @__PURE__ */ jsx(Text, { style: [styles.cardTitle, { color: accentColor }], children: message.titleText }),
1025
- /* @__PURE__ */ jsx(Text, { style: [styles.cardMessage, { color: colors.textSecondary }], children: message.messageText })
1243
+ return /* @__PURE__ */ jsxs(View, { style: [styles2.card, { backgroundColor: colors.surface, borderColor: accentColor }], testID, children: [
1244
+ /* @__PURE__ */ jsx(Text, { style: [styles2.cardTitle, { color: accentColor }], children: message.titleText }),
1245
+ /* @__PURE__ */ jsx(Text, { style: [styles2.cardMessage, { color: colors.textSecondary }], children: message.messageText })
1026
1246
  ] });
1027
1247
  }
1028
1248
  function useContentBody(state, children, testID) {
@@ -1034,7 +1254,7 @@ function useContentBody(state, children, testID) {
1034
1254
  if (state?.error)
1035
1255
  return /* @__PURE__ */ jsx(MessageCard, { accentColor: errorColor, message: state.error, testID: `${testID}${APP_SHELL_SUFFIX.error}` });
1036
1256
  if (state?.loading === true)
1037
- return /* @__PURE__ */ jsx(View, { style: styles.centerFill, testID: `${testID}${APP_SHELL_SUFFIX.loading}`, children: /* @__PURE__ */ jsx(ActivityIndicator, { color: primary, size: "large" }) });
1257
+ return /* @__PURE__ */ jsx(View, { style: styles2.centerFill, testID: `${testID}${APP_SHELL_SUFFIX.loading}`, children: /* @__PURE__ */ jsx(ActivityIndicator, { color: primary, size: "large" }) });
1038
1258
  return children;
1039
1259
  }
1040
1260
  var SCRIM_COLOR = "rgba(0, 0, 0, 0.5)";
@@ -1058,7 +1278,7 @@ var DEFAULT_DRAWER_LABELS = {
1058
1278
  closeLabel: "Close menu",
1059
1279
  closeHint: "Close the navigation menu"
1060
1280
  };
1061
- var styles2 = StyleSheet.create({
1281
+ var styles3 = StyleSheet.create({
1062
1282
  overlay: { ...StyleSheet.absoluteFillObject, zIndex: DRAWER_Z_INDEX },
1063
1283
  // The scrim's tap-to-close hit area is anchored to the RIGHT of the panel
1064
1284
  // (`left: DRAWER_WIDTH`), so it NEVER overlaps the panel: nav-item taps always
@@ -1093,10 +1313,10 @@ var MenuToggle = ({ label, hint, onOpen, testID }) => {
1093
1313
  accessibilityHint: hint,
1094
1314
  accessibilityLabel: label,
1095
1315
  ringColor: theme.palette.primary["500"],
1096
- style: styles2.menuToggle,
1316
+ style: styles3.menuToggle,
1097
1317
  testID,
1098
1318
  onPress: onOpen,
1099
- children: /* @__PURE__ */ jsx(Text, { style: [styles2.menuToggleGlyph, { color: theme.colors.text }], children: MENU_GLYPH2 })
1319
+ children: /* @__PURE__ */ jsx(Text, { style: [styles3.menuToggleGlyph, { color: theme.colors.text }], children: MENU_GLYPH2 })
1100
1320
  }
1101
1321
  );
1102
1322
  };
@@ -1122,14 +1342,14 @@ var MobileDrawer = ({
1122
1342
  node.addEventListener("click", handleClick);
1123
1343
  return () => node.removeEventListener("click", handleClick);
1124
1344
  }, [onClose]);
1125
- return /* @__PURE__ */ jsxs(View, { style: styles2.overlay, children: [
1345
+ return /* @__PURE__ */ jsxs(View, { style: styles3.overlay, children: [
1126
1346
  /* @__PURE__ */ jsx(
1127
1347
  Pressable,
1128
1348
  {
1129
1349
  accessibilityHint: labels.closeHint,
1130
1350
  accessibilityLabel: labels.closeLabel,
1131
1351
  accessibilityRole: "button",
1132
- style: styles2.scrim,
1352
+ style: styles3.scrim,
1133
1353
  testID: scrimTestID,
1134
1354
  onPress: onClose
1135
1355
  }
@@ -1140,7 +1360,7 @@ var MobileDrawer = ({
1140
1360
  ref: panelRef,
1141
1361
  "aria-modal": true,
1142
1362
  role: "dialog",
1143
- style: [styles2.panel, { backgroundColor: theme.colors.surface }],
1363
+ style: [styles3.panel, { backgroundColor: theme.colors.surface }],
1144
1364
  testID: drawerTestID,
1145
1365
  children: renderTextSlot(sidebar, { color: theme.colors.text })
1146
1366
  }
@@ -1171,7 +1391,7 @@ function useContentMaxWidth(width) {
1171
1391
  return resolveContentMaxWidth(width, viewport);
1172
1392
  }
1173
1393
  var DEFAULT_CONTENT_PADDING = 24;
1174
- var styles3 = StyleSheet.create({
1394
+ var styles4 = StyleSheet.create({
1175
1395
  root: { flex: 1 },
1176
1396
  centerFill: { flex: 1, justifyContent: "center", alignItems: "center" },
1177
1397
  scroll: { flex: 1 },
@@ -1228,20 +1448,20 @@ var AppShell = ({
1228
1448
  if (isUnauthenticated && gate !== void 0) gate.onRedirect();
1229
1449
  }, [isUnauthenticated, gate]);
1230
1450
  if (gate?.pending === true)
1231
- return /* @__PURE__ */ jsx(View, { style: [styles3.root, styles3.centerFill, { backgroundColor: theme.colors.background }], testID: `${testID}${APP_SHELL_SUFFIX.pending}`, children: /* @__PURE__ */ jsx(ActivityIndicator, { color: primary, size: "large" }) });
1451
+ return /* @__PURE__ */ jsx(View, { style: [styles4.root, styles4.centerFill, { backgroundColor: theme.colors.background }], testID: `${testID}${APP_SHELL_SUFFIX.pending}`, children: /* @__PURE__ */ jsx(ActivityIndicator, { color: primary, size: "large" }) });
1232
1452
  if (isUnauthenticated) return null;
1233
- const columnStyle = maxWidth === "full" ? styles3.columnFull : [styles3.columnCapped, { maxWidth }];
1234
- const navInnerStyle = chromeAlignment === "content" && maxWidth !== "full" ? [styles3.chromeCapped, { maxWidth, paddingHorizontal: contentPadding }] : void 0;
1453
+ const columnStyle = maxWidth === "full" ? styles4.columnFull : [styles4.columnCapped, { maxWidth }];
1454
+ const navInnerStyle = chromeAlignment === "content" && maxWidth !== "full" ? [styles4.chromeCapped, { maxWidth, paddingHorizontal: contentPadding }] : void 0;
1235
1455
  const scroller = /* @__PURE__ */ jsx(
1236
1456
  ScrollView,
1237
1457
  {
1238
- contentContainerStyle: [styles3.scrollContent, { padding: contentPadding }],
1239
- style: styles3.scroll,
1458
+ contentContainerStyle: [styles4.scrollContent, { padding: contentPadding }],
1459
+ style: styles4.scroll,
1240
1460
  testID: `${testID}${APP_SHELL_SUFFIX.content}`,
1241
1461
  children: /* @__PURE__ */ jsx(View, { style: columnStyle, children: body })
1242
1462
  }
1243
1463
  );
1244
- const headerRegion = useDrawer ? /* @__PURE__ */ jsxs(View, { style: styles3.headerRow, testID: `${testID}${APP_SHELL_SUFFIX.header}`, children: [
1464
+ const headerRegion = useDrawer ? /* @__PURE__ */ jsxs(View, { style: styles4.headerRow, testID: `${testID}${APP_SHELL_SUFFIX.header}`, children: [
1245
1465
  /* @__PURE__ */ jsx(
1246
1466
  MenuToggle,
1247
1467
  {
@@ -1251,14 +1471,14 @@ var AppShell = ({
1251
1471
  onOpen: openDrawer
1252
1472
  }
1253
1473
  ),
1254
- /* @__PURE__ */ jsx(View, { style: styles3.headerFill, children: renderTextSlot(header, { color: theme.colors.text }) })
1474
+ /* @__PURE__ */ jsx(View, { style: styles4.headerFill, children: renderTextSlot(header, { color: theme.colors.text }) })
1255
1475
  ] }) : /* @__PURE__ */ jsx(View, { testID: `${testID}${APP_SHELL_SUFFIX.header}`, children: renderTextSlot(header, { color: theme.colors.text }) });
1256
1476
  const railRegion = railMode === "full" ? /* @__PURE__ */ jsx(View, { testID: `${testID}${APP_SHELL_SUFFIX.sidebar}`, children: renderTextSlot(sidebar, { color: theme.colors.text }) }) : railMode === "collapsed" ? /* @__PURE__ */ jsx(View, { testID: `${testID}${APP_SHELL_SUFFIX.collapsedSidebar}`, children: renderTextSlot(collapsedSidebar, { color: theme.colors.text }) }) : null;
1257
- return /* @__PURE__ */ jsxs(View, { style: [styles3.root, { backgroundColor: theme.colors.background }], testID, children: [
1477
+ return /* @__PURE__ */ jsxs(View, { style: [styles4.root, { backgroundColor: theme.colors.background }], testID, children: [
1258
1478
  headerRegion,
1259
1479
  nav !== void 0 ? /* @__PURE__ */ jsx(View, { testID: `${testID}${APP_SHELL_SUFFIX.nav}`, children: navInnerStyle !== void 0 ? /* @__PURE__ */ jsx(View, { style: navInnerStyle, children: renderTextSlot(nav, { color: theme.colors.text }) }) : renderTextSlot(nav, { color: theme.colors.text }) }) : null,
1260
1480
  banner !== void 0 ? /* @__PURE__ */ jsx(View, { testID: `${testID}${APP_SHELL_SUFFIX.banner}`, children: renderTextSlot(banner, { color: theme.colors.text }) }) : null,
1261
- railRegion !== null ? /* @__PURE__ */ jsxs(View, { style: styles3.bodyRow, children: [
1481
+ railRegion !== null ? /* @__PURE__ */ jsxs(View, { style: styles4.bodyRow, children: [
1262
1482
  railRegion,
1263
1483
  scroller
1264
1484
  ] }) : scroller,
@@ -1552,7 +1772,7 @@ var KEY_DOWN = "ArrowDown";
1552
1772
  var KEY_UP = "ArrowUp";
1553
1773
  var KEY_ENTER = "Enter";
1554
1774
  var KEY_ESCAPE = "Escape";
1555
- var styles4 = StyleSheet.create({
1775
+ var styles5 = StyleSheet.create({
1556
1776
  overlay: { ...StyleSheet.absoluteFillObject, zIndex: OVERLAY_Z_INDEX, alignItems: "center" },
1557
1777
  scrim: { ...StyleSheet.absoluteFillObject, backgroundColor: SCRIM_COLOR2 },
1558
1778
  panel: {
@@ -1581,14 +1801,14 @@ var PaletteRow = ({ item, selected, onChoose }) => {
1581
1801
  accessibilityLabel: item.label,
1582
1802
  accessibilityRole: "button",
1583
1803
  accessibilityState: { selected },
1584
- style: [styles4.row, selected ? { backgroundColor: colors.border } : void 0],
1804
+ style: [styles5.row, selected ? { backgroundColor: colors.border } : void 0],
1585
1805
  testID: item.testID ?? item.key,
1586
1806
  onPress: () => onChoose(item),
1587
1807
  children: [
1588
1808
  typeof item.renderIcon === "function" ? item.renderIcon(colors.textSecondary, NAV_ICON_SIZE) : null,
1589
- /* @__PURE__ */ jsxs(View, { style: styles4.rowText, children: [
1590
- /* @__PURE__ */ jsx(Text, { style: [styles4.rowLabel, { color: colors.text }], children: item.label }),
1591
- item.hint ? /* @__PURE__ */ jsx(Text, { style: [styles4.rowHint, { color: colors.textSecondary }], children: item.hint }) : null
1809
+ /* @__PURE__ */ jsxs(View, { style: styles5.rowText, children: [
1810
+ /* @__PURE__ */ jsx(Text, { style: [styles5.rowLabel, { color: colors.text }], children: item.label }),
1811
+ item.hint ? /* @__PURE__ */ jsx(Text, { style: [styles5.rowHint, { color: colors.textSecondary }], children: item.hint }) : null
1592
1812
  ] })
1593
1813
  ]
1594
1814
  }
@@ -1628,14 +1848,14 @@ var CommandPalette = ({ open, items, onClose, labels, testID }) => {
1628
1848
  [results, selected, choose, onClose]
1629
1849
  );
1630
1850
  if (!open) return null;
1631
- return /* @__PURE__ */ jsxs(View, { style: styles4.overlay, children: [
1851
+ return /* @__PURE__ */ jsxs(View, { style: styles5.overlay, children: [
1632
1852
  /* @__PURE__ */ jsx(
1633
1853
  Pressable,
1634
1854
  {
1635
1855
  accessibilityHint: labels.closeHint,
1636
1856
  accessibilityLabel: labels.closeLabel,
1637
1857
  accessibilityRole: "button",
1638
- style: styles4.scrim,
1858
+ style: styles5.scrim,
1639
1859
  testID: `${testID ?? "command-palette"}-scrim`,
1640
1860
  onPress: onClose
1641
1861
  }
@@ -1646,7 +1866,7 @@ var CommandPalette = ({ open, items, onClose, labels, testID }) => {
1646
1866
  "aria-modal": true,
1647
1867
  "aria-label": labels.regionLabel,
1648
1868
  role: "dialog",
1649
- style: [styles4.panel, { backgroundColor: colors.surface, borderColor: colors.border }],
1869
+ style: [styles5.panel, { backgroundColor: colors.surface, borderColor: colors.border }],
1650
1870
  testID: testID ?? "command-palette",
1651
1871
  children: [
1652
1872
  /* @__PURE__ */ jsx(
@@ -1656,21 +1876,21 @@ var CommandPalette = ({ open, items, onClose, labels, testID }) => {
1656
1876
  accessibilityLabel: labels.placeholder,
1657
1877
  placeholder: labels.placeholder,
1658
1878
  placeholderTextColor: colors.textSecondary,
1659
- style: [styles4.input, { color: colors.text, borderBottomColor: colors.border }],
1879
+ style: [styles5.input, { color: colors.text, borderBottomColor: colors.border }],
1660
1880
  testID: `${testID ?? "command-palette"}-input`,
1661
1881
  value: query,
1662
1882
  onChangeText: setQuery,
1663
1883
  onKeyPress
1664
1884
  }
1665
1885
  ),
1666
- results.length === 0 ? /* @__PURE__ */ jsx(Text, { style: [styles4.empty, { color: colors.textSecondary }], children: labels.emptyText }) : /* @__PURE__ */ jsx(ScrollView, { keyboardShouldPersistTaps: "handled", style: styles4.list, children: results.map((item, index) => /* @__PURE__ */ jsx(PaletteRow, { item, selected: index === selected, onChoose: choose }, item.key)) })
1886
+ results.length === 0 ? /* @__PURE__ */ jsx(Text, { style: [styles5.empty, { color: colors.textSecondary }], children: labels.emptyText }) : /* @__PURE__ */ jsx(ScrollView, { keyboardShouldPersistTaps: "handled", style: styles5.list, children: results.map((item, index) => /* @__PURE__ */ jsx(PaletteRow, { item, selected: index === selected, onChoose: choose }, item.key)) })
1667
1887
  ]
1668
1888
  }
1669
1889
  )
1670
1890
  ] });
1671
1891
  };
1672
1892
  var MIN_TARGET = 36;
1673
- var styles5 = StyleSheet.create({
1893
+ var styles6 = StyleSheet.create({
1674
1894
  trigger: {
1675
1895
  flexDirection: "row",
1676
1896
  alignItems: "center",
@@ -1695,7 +1915,7 @@ var CommandPaletteTrigger = ({
1695
1915
  const { theme } = useUi();
1696
1916
  const colors = theme.colors;
1697
1917
  const primary = theme.palette.primary["500"];
1698
- const [focused, setFocused] = React2.useState(false);
1918
+ const [focused, setFocused] = React3.useState(false);
1699
1919
  return /* @__PURE__ */ jsxs(
1700
1920
  Pressable,
1701
1921
  {
@@ -1703,7 +1923,7 @@ var CommandPaletteTrigger = ({
1703
1923
  accessibilityLabel: label,
1704
1924
  accessibilityRole: "button",
1705
1925
  style: [
1706
- styles5.trigger,
1926
+ styles6.trigger,
1707
1927
  { backgroundColor: colors.surface, borderColor: colors.border },
1708
1928
  focusRingStyle(focused, primary)
1709
1929
  ],
@@ -1712,8 +1932,8 @@ var CommandPaletteTrigger = ({
1712
1932
  onFocus: () => setFocused(true),
1713
1933
  onPress,
1714
1934
  children: [
1715
- /* @__PURE__ */ jsx(Text, { style: [styles5.label, { color: colors.textSecondary }], children: label }),
1716
- /* @__PURE__ */ jsx(View, { style: [styles5.badge, { borderColor: colors.border }], children: /* @__PURE__ */ jsx(Text, { style: [styles5.badgeText, { color: colors.textSecondary }], children: shortcut }) })
1935
+ /* @__PURE__ */ jsx(Text, { style: [styles6.label, { color: colors.textSecondary }], children: label }),
1936
+ /* @__PURE__ */ jsx(View, { style: [styles6.badge, { borderColor: colors.border }], children: /* @__PURE__ */ jsx(Text, { style: [styles6.badgeText, { color: colors.textSecondary }], children: shortcut }) })
1717
1937
  ]
1718
1938
  }
1719
1939
  );
@@ -1743,6 +1963,6 @@ function accessibleNavItems(user, table, translate) {
1743
1963
  return roleRoutesToNavItems(resolveAccessibleRoutes(user, table), translate);
1744
1964
  }
1745
1965
 
1746
- export { ACTIVE_BORDER_RADIUS, APP_SHELL_SUFFIX, AppShell, BASE_INDENT, CHEVRON_ICON_SIZE, CollapsedRail, CommandPalette, CommandPaletteTrigger, DEFAULT_COLLAPSED_RAIL_MAX, DarkModeControl, NAV_ICON_SIZE, NAV_LINK_GAP, NAV_TEST_IDS, Nav, NavBar, NavExpandableItem, NavOverflowMenu, NavShell, PillNav, RAIL_FULL_BREAKPOINT, Sidebar, Topbar, accessibleNavItems, collapsedRailStyles, darkModeStyles, expandableStyles, filterCommands, isRouteActive, navStyles, pillNavStyles, resolveContentMaxWidth, resolveRailMode, roleRoutesToNavItems, useCommandPaletteHotkey, useContentMaxWidth };
1966
+ 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, RAIL_FULL_BREAKPOINT, Sidebar, SidebarChevron, SidebarSearch, Topbar, accessibleNavItems, collapsedRailStyles, darkModeStyles, expandableStyles, filterCommands, filterNavItems, isFilterActive, isRouteActive, navStyles, pillNavStyles, resolveContentMaxWidth, resolveRailMode, resolveSearchAffordance, roleRoutesToNavItems, searchTokens, useCommandPaletteHotkey, useContentMaxWidth };
1747
1967
  //# sourceMappingURL=index.mjs.map
1748
1968
  //# sourceMappingURL=index.mjs.map