@dloizides/ui-nav 1.16.0 → 1.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +38 -0
- package/dist/index.d.mts +53 -4
- package/dist/index.d.ts +53 -4
- package/dist/index.js +237 -195
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +185 -143
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,18 +1,99 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var React = require('react');
|
|
4
4
|
var reactNative = require('react-native');
|
|
5
5
|
var uiFeedback = require('@dloizides/ui-feedback');
|
|
6
|
-
var uiMotion = require('@dloizides/ui-motion');
|
|
7
6
|
var jsxRuntime = require('react/jsx-runtime');
|
|
7
|
+
var uiMotion = require('@dloizides/ui-motion');
|
|
8
8
|
var uiLayout = require('@dloizides/ui-layout');
|
|
9
9
|
var authWeb = require('@dloizides/auth-web');
|
|
10
10
|
|
|
11
11
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
12
12
|
|
|
13
|
-
var
|
|
13
|
+
var React__default = /*#__PURE__*/_interopDefault(React);
|
|
14
14
|
|
|
15
15
|
// src/Sidebar.tsx
|
|
16
|
+
var IS_WEB = reactNative.Platform.OS === "web";
|
|
17
|
+
var FOCUS_RING_WIDTH = 2;
|
|
18
|
+
var FOCUS_RING_OFFSET = 2;
|
|
19
|
+
var HOVER_TRANSITION_MS = 150;
|
|
20
|
+
var TINT_TRANSITION_MS = 160;
|
|
21
|
+
function focusRingStyle(focused, ringColor) {
|
|
22
|
+
if (!IS_WEB || !focused) return void 0;
|
|
23
|
+
const ring = {
|
|
24
|
+
outlineWidth: FOCUS_RING_WIDTH,
|
|
25
|
+
outlineStyle: "solid",
|
|
26
|
+
outlineColor: ringColor,
|
|
27
|
+
outlineOffset: FOCUS_RING_OFFSET
|
|
28
|
+
};
|
|
29
|
+
return ring;
|
|
30
|
+
}
|
|
31
|
+
function webTransition(properties, durationMs, reducedMotion) {
|
|
32
|
+
if (!IS_WEB) return void 0;
|
|
33
|
+
const transition = {
|
|
34
|
+
transitionProperty: properties,
|
|
35
|
+
transitionDuration: reducedMotion ? "0ms" : `${durationMs}ms`
|
|
36
|
+
};
|
|
37
|
+
return transition;
|
|
38
|
+
}
|
|
39
|
+
function hoverTransitionStyle(reducedMotion) {
|
|
40
|
+
return webTransition("color, background-color", HOVER_TRANSITION_MS, reducedMotion);
|
|
41
|
+
}
|
|
42
|
+
function tintTransitionStyle(reducedMotion) {
|
|
43
|
+
return webTransition("opacity", TINT_TRANSITION_MS, reducedMotion);
|
|
44
|
+
}
|
|
45
|
+
function rotateTransitionStyle(reducedMotion) {
|
|
46
|
+
return webTransition("transform", TINT_TRANSITION_MS, reducedMotion);
|
|
47
|
+
}
|
|
48
|
+
var MIN_TARGET = 36;
|
|
49
|
+
var styles = reactNative.StyleSheet.create({
|
|
50
|
+
trigger: {
|
|
51
|
+
flexDirection: "row",
|
|
52
|
+
alignItems: "center",
|
|
53
|
+
justifyContent: "space-between",
|
|
54
|
+
columnGap: 8,
|
|
55
|
+
paddingHorizontal: 12,
|
|
56
|
+
minHeight: MIN_TARGET,
|
|
57
|
+
borderWidth: 1,
|
|
58
|
+
borderRadius: 8
|
|
59
|
+
},
|
|
60
|
+
label: { fontSize: 14 },
|
|
61
|
+
badge: { paddingHorizontal: 6, paddingVertical: 2, borderRadius: 4, borderWidth: 1 },
|
|
62
|
+
badgeText: { fontSize: 11, fontWeight: "700" }
|
|
63
|
+
});
|
|
64
|
+
var CommandPaletteTrigger = ({
|
|
65
|
+
label,
|
|
66
|
+
hint,
|
|
67
|
+
shortcut,
|
|
68
|
+
onPress,
|
|
69
|
+
testID
|
|
70
|
+
}) => {
|
|
71
|
+
const { theme } = uiFeedback.useUi();
|
|
72
|
+
const colors = theme.colors;
|
|
73
|
+
const primary = theme.palette.primary["500"];
|
|
74
|
+
const [focused, setFocused] = React__default.default.useState(false);
|
|
75
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
76
|
+
reactNative.Pressable,
|
|
77
|
+
{
|
|
78
|
+
accessibilityHint: hint,
|
|
79
|
+
accessibilityLabel: label,
|
|
80
|
+
accessibilityRole: "button",
|
|
81
|
+
style: [
|
|
82
|
+
styles.trigger,
|
|
83
|
+
{ backgroundColor: colors.surface, borderColor: colors.border },
|
|
84
|
+
focusRingStyle(focused, primary)
|
|
85
|
+
],
|
|
86
|
+
testID,
|
|
87
|
+
onBlur: () => setFocused(false),
|
|
88
|
+
onFocus: () => setFocused(true),
|
|
89
|
+
onPress,
|
|
90
|
+
children: [
|
|
91
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles.label, { color: colors.textSecondary }], children: label }),
|
|
92
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles.badge, { borderColor: colors.border }], children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles.badgeText, { color: colors.textSecondary }], children: shortcut }) })
|
|
93
|
+
]
|
|
94
|
+
}
|
|
95
|
+
);
|
|
96
|
+
};
|
|
16
97
|
|
|
17
98
|
// src/sidebarFilter.ts
|
|
18
99
|
function searchTokens(query) {
|
|
@@ -56,6 +137,10 @@ var ACTIVE_ACCENT_WIDTH = 3;
|
|
|
56
137
|
var NAV_ROW_RADIUS = 8;
|
|
57
138
|
var ACTIVE_TINT_OPACITY = 0.14;
|
|
58
139
|
var HOVER_TINT_OPACITY = 0.06;
|
|
140
|
+
function rowTintOpacity(isActive, hovered) {
|
|
141
|
+
if (isActive) return ACTIVE_TINT_OPACITY;
|
|
142
|
+
return hovered ? HOVER_TINT_OPACITY : 0;
|
|
143
|
+
}
|
|
59
144
|
var NAV_LINK_GAP = 4;
|
|
60
145
|
var navStyles = reactNative.StyleSheet.create({
|
|
61
146
|
// --- Sidebar ---
|
|
@@ -81,6 +166,12 @@ var navStyles = reactNative.StyleSheet.create({
|
|
|
81
166
|
sidebarSpacer: {
|
|
82
167
|
flex: 1
|
|
83
168
|
},
|
|
169
|
+
// Bottom rhythm under the ⌘K palette trigger (the narrow-viewport search
|
|
170
|
+
// affordance), matching the inline field's own `marginBottom` so swapping
|
|
171
|
+
// affordances by width keeps the same gap above the nav list.
|
|
172
|
+
sidebarTriggerSlot: {
|
|
173
|
+
marginBottom: 12
|
|
174
|
+
},
|
|
84
175
|
// Inline-search no-match text — sits where the nav list would, muted + padded.
|
|
85
176
|
sidebarEmpty: {
|
|
86
177
|
fontSize: 13,
|
|
@@ -343,46 +434,14 @@ var expandableStyles = reactNative.StyleSheet.create({
|
|
|
343
434
|
var BASE_INDENT = 12;
|
|
344
435
|
var NAV_ICON_SIZE = 14;
|
|
345
436
|
var CHEVRON_ICON_SIZE = 12;
|
|
346
|
-
var IS_WEB = reactNative.Platform.OS === "web";
|
|
347
|
-
var FOCUS_RING_WIDTH = 2;
|
|
348
|
-
var FOCUS_RING_OFFSET = 2;
|
|
349
|
-
var HOVER_TRANSITION_MS = 150;
|
|
350
|
-
var TINT_TRANSITION_MS = 160;
|
|
351
|
-
function focusRingStyle(focused, ringColor) {
|
|
352
|
-
if (!IS_WEB || !focused) return void 0;
|
|
353
|
-
const ring = {
|
|
354
|
-
outlineWidth: FOCUS_RING_WIDTH,
|
|
355
|
-
outlineStyle: "solid",
|
|
356
|
-
outlineColor: ringColor,
|
|
357
|
-
outlineOffset: FOCUS_RING_OFFSET
|
|
358
|
-
};
|
|
359
|
-
return ring;
|
|
360
|
-
}
|
|
361
|
-
function webTransition(properties, durationMs, reducedMotion) {
|
|
362
|
-
if (!IS_WEB) return void 0;
|
|
363
|
-
const transition = {
|
|
364
|
-
transitionProperty: properties,
|
|
365
|
-
transitionDuration: reducedMotion ? "0ms" : `${durationMs}ms`
|
|
366
|
-
};
|
|
367
|
-
return transition;
|
|
368
|
-
}
|
|
369
|
-
function hoverTransitionStyle(reducedMotion) {
|
|
370
|
-
return webTransition("color, background-color", HOVER_TRANSITION_MS, reducedMotion);
|
|
371
|
-
}
|
|
372
|
-
function tintTransitionStyle(reducedMotion) {
|
|
373
|
-
return webTransition("opacity", TINT_TRANSITION_MS, reducedMotion);
|
|
374
|
-
}
|
|
375
|
-
function rotateTransitionStyle(reducedMotion) {
|
|
376
|
-
return webTransition("transform", TINT_TRANSITION_MS, reducedMotion);
|
|
377
|
-
}
|
|
378
437
|
var REDUCED_MOTION_QUERY = "(prefers-reduced-motion: reduce)";
|
|
379
438
|
function getReducedMotionQuery() {
|
|
380
439
|
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return void 0;
|
|
381
440
|
return window.matchMedia(REDUCED_MOTION_QUERY);
|
|
382
441
|
}
|
|
383
442
|
function useReducedMotion() {
|
|
384
|
-
const [reduced, setReduced] =
|
|
385
|
-
|
|
443
|
+
const [reduced, setReduced] = React.useState(() => getReducedMotionQuery()?.matches ?? false);
|
|
444
|
+
React.useEffect(() => {
|
|
386
445
|
const mql = getReducedMotionQuery();
|
|
387
446
|
if (mql === void 0 || mql.addEventListener === void 0) return void 0;
|
|
388
447
|
const onChange = () => setReduced(mql.matches);
|
|
@@ -428,9 +487,19 @@ function hasActiveDescendant(item, pathname) {
|
|
|
428
487
|
if (isRouteActive(pathname, item.route)) return true;
|
|
429
488
|
return (item.children ?? []).some((child) => hasActiveDescendant(child, pathname));
|
|
430
489
|
}
|
|
431
|
-
function TintOverlay({
|
|
490
|
+
function TintOverlay({
|
|
491
|
+
opacity,
|
|
492
|
+
color,
|
|
493
|
+
testID
|
|
494
|
+
}) {
|
|
432
495
|
const reducedMotion = useReducedMotion();
|
|
433
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
496
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
497
|
+
reactNative.View,
|
|
498
|
+
{
|
|
499
|
+
style: [expandableStyles.tintOverlay, { backgroundColor: color, opacity }, tintTransitionStyle(reducedMotion)],
|
|
500
|
+
testID
|
|
501
|
+
}
|
|
502
|
+
);
|
|
434
503
|
}
|
|
435
504
|
var NavExpandableItem = ({
|
|
436
505
|
item,
|
|
@@ -442,30 +511,31 @@ var NavExpandableItem = ({
|
|
|
442
511
|
renderChevron,
|
|
443
512
|
depth = 0
|
|
444
513
|
}) => {
|
|
445
|
-
const [expanded, setExpanded] =
|
|
446
|
-
const [focused, setFocused] =
|
|
447
|
-
const [hovered, setHovered] =
|
|
514
|
+
const [expanded, setExpanded] = React.useState(() => hasActiveDescendant(item, pathname));
|
|
515
|
+
const [focused, setFocused] = React.useState(false);
|
|
516
|
+
const [hovered, setHovered] = React.useState(false);
|
|
448
517
|
const { theme } = uiFeedback.useUi();
|
|
449
518
|
const colors = theme.colors;
|
|
450
519
|
const primaryColor = theme.palette.primary["500"];
|
|
451
|
-
const toggle =
|
|
452
|
-
const onHoverIn =
|
|
453
|
-
const onHoverOut =
|
|
520
|
+
const toggle = React.useCallback(() => setExpanded((v) => !v), []);
|
|
521
|
+
const onHoverIn = React.useCallback(() => setHovered(true), []);
|
|
522
|
+
const onHoverOut = React.useCallback(() => setHovered(false), []);
|
|
454
523
|
const indent = depth * BASE_INDENT;
|
|
455
524
|
const hasChildren = Array.isArray(item.children) && item.children.length > 0;
|
|
456
525
|
const isActive = isRouteActive(pathname, item.route);
|
|
457
526
|
const isSectionHeader = hasChildren && depth === 0;
|
|
458
|
-
const activeAccentStyle =
|
|
527
|
+
const activeAccentStyle = React.useMemo(
|
|
459
528
|
() => ({ borderLeftWidth: ACTIVE_ACCENT_WIDTH, borderLeftColor: primaryColor }),
|
|
460
529
|
[primaryColor]
|
|
461
530
|
);
|
|
462
|
-
const paddingStyle =
|
|
463
|
-
const headerPaddingStyle =
|
|
464
|
-
const leafTintOpacity = isActive
|
|
465
|
-
const headerTintOpacity = hovered
|
|
531
|
+
const paddingStyle = React.useMemo(() => ({ paddingLeft: indent + BASE_INDENT }), [indent]);
|
|
532
|
+
const headerPaddingStyle = React.useMemo(() => ({ paddingLeft: indent }), [indent]);
|
|
533
|
+
const leafTintOpacity = rowTintOpacity(isActive, hovered);
|
|
534
|
+
const headerTintOpacity = rowTintOpacity(false, hovered);
|
|
535
|
+
const rowTestID = item.testID ?? item.key;
|
|
466
536
|
if (!hasChildren)
|
|
467
537
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
468
|
-
reactNative.
|
|
538
|
+
reactNative.Pressable,
|
|
469
539
|
{
|
|
470
540
|
accessibilityHint: navigateHint(item.label),
|
|
471
541
|
accessibilityLabel: item.label,
|
|
@@ -477,14 +547,14 @@ var NavExpandableItem = ({
|
|
|
477
547
|
isActive ? activeAccentStyle : void 0,
|
|
478
548
|
focusRingStyle(focused, primaryColor)
|
|
479
549
|
],
|
|
480
|
-
testID:
|
|
550
|
+
testID: rowTestID,
|
|
481
551
|
onBlur: () => setFocused(false),
|
|
482
552
|
onFocus: () => setFocused(true),
|
|
483
553
|
onPress: () => onNavigate(item.route),
|
|
484
554
|
...hoverHandlerProps(onHoverIn, onHoverOut),
|
|
485
555
|
...ariaCurrentProps(isActive),
|
|
486
556
|
children: [
|
|
487
|
-
/* @__PURE__ */ jsxRuntime.jsx(TintOverlay, { color: primaryColor, opacity: leafTintOpacity }),
|
|
557
|
+
/* @__PURE__ */ jsxRuntime.jsx(TintOverlay, { color: primaryColor, opacity: leafTintOpacity, testID: `${rowTestID}-tint` }),
|
|
488
558
|
typeof item.renderIcon === "function" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: expandableStyles.iconWrapper, children: item.renderIcon(colors.textSecondary, NAV_ICON_SIZE) }) : null,
|
|
489
559
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
490
560
|
reactNative.Text,
|
|
@@ -502,7 +572,7 @@ var NavExpandableItem = ({
|
|
|
502
572
|
const chevronColor = colors.textSecondary;
|
|
503
573
|
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { children: [
|
|
504
574
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
505
|
-
reactNative.
|
|
575
|
+
reactNative.Pressable,
|
|
506
576
|
{
|
|
507
577
|
accessibilityHint: expanded ? collapseHint : expandHint,
|
|
508
578
|
accessibilityLabel: item.label,
|
|
@@ -514,14 +584,14 @@ var NavExpandableItem = ({
|
|
|
514
584
|
headerPaddingStyle,
|
|
515
585
|
focusRingStyle(focused, primaryColor)
|
|
516
586
|
],
|
|
517
|
-
testID:
|
|
587
|
+
testID: rowTestID,
|
|
518
588
|
onBlur: () => setFocused(false),
|
|
519
589
|
onFocus: () => setFocused(true),
|
|
520
590
|
onPress: toggle,
|
|
521
591
|
...hoverHandlerProps(onHoverIn, onHoverOut),
|
|
522
592
|
...ariaExpandedProps(expanded),
|
|
523
593
|
children: [
|
|
524
|
-
/* @__PURE__ */ jsxRuntime.jsx(TintOverlay, { color: primaryColor, opacity: headerTintOpacity }),
|
|
594
|
+
/* @__PURE__ */ jsxRuntime.jsx(TintOverlay, { color: primaryColor, opacity: headerTintOpacity, testID: `${rowTestID}-tint` }),
|
|
525
595
|
typeof item.renderIcon === "function" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: expandableStyles.iconWrapper, children: item.renderIcon(isSectionHeader ? colors.textSecondary : colors.text, NAV_ICON_SIZE) }) : null,
|
|
526
596
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
527
597
|
reactNative.Text,
|
|
@@ -553,10 +623,16 @@ var NavExpandableItem = ({
|
|
|
553
623
|
)) }) })
|
|
554
624
|
] });
|
|
555
625
|
};
|
|
626
|
+
|
|
627
|
+
// src/searchAffordance.ts
|
|
628
|
+
var DEFAULT_SEARCH_BREAKPOINT = 768;
|
|
629
|
+
function resolveSearchAffordance(viewport, breakpoint = DEFAULT_SEARCH_BREAKPOINT) {
|
|
630
|
+
return viewport >= breakpoint ? "inline" : "palette";
|
|
631
|
+
}
|
|
556
632
|
var FIELD_MIN_HEIGHT = 38;
|
|
557
633
|
var CLEAR_GLYPH = "\u2715";
|
|
558
634
|
var CLEAR_MIN_TARGET = 28;
|
|
559
|
-
var
|
|
635
|
+
var styles2 = reactNative.StyleSheet.create({
|
|
560
636
|
wrap: {
|
|
561
637
|
flexDirection: "row",
|
|
562
638
|
alignItems: "center",
|
|
@@ -591,13 +667,13 @@ var SidebarSearch = ({
|
|
|
591
667
|
const { theme } = uiFeedback.useUi();
|
|
592
668
|
const colors = theme.colors;
|
|
593
669
|
const primary = theme.palette.primary["500"];
|
|
594
|
-
const [focused, setFocused] =
|
|
670
|
+
const [focused, setFocused] = React.useState(false);
|
|
595
671
|
const hasQuery = value.length > 0;
|
|
596
672
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
597
673
|
reactNative.View,
|
|
598
674
|
{
|
|
599
675
|
style: [
|
|
600
|
-
|
|
676
|
+
styles2.wrap,
|
|
601
677
|
{ backgroundColor: colors.surface, borderColor: focused ? primary : colors.border },
|
|
602
678
|
focusRingStyle(focused, primary)
|
|
603
679
|
],
|
|
@@ -609,7 +685,7 @@ var SidebarSearch = ({
|
|
|
609
685
|
accessibilityLabel: labels.placeholder,
|
|
610
686
|
placeholder: labels.placeholder,
|
|
611
687
|
placeholderTextColor: colors.textSecondary,
|
|
612
|
-
style: [
|
|
688
|
+
style: [styles2.input, { color: colors.text }],
|
|
613
689
|
testID,
|
|
614
690
|
value,
|
|
615
691
|
onBlur: () => setFocused(false),
|
|
@@ -623,10 +699,10 @@ var SidebarSearch = ({
|
|
|
623
699
|
accessibilityHint: labels.clearHint,
|
|
624
700
|
accessibilityLabel: labels.clearLabel,
|
|
625
701
|
accessibilityRole: "button",
|
|
626
|
-
style:
|
|
702
|
+
style: styles2.clear,
|
|
627
703
|
testID: `${testID}-clear`,
|
|
628
704
|
onPress: onClear,
|
|
629
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [
|
|
705
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles2.clearGlyph, { color: colors.textSecondary }], children: CLEAR_GLYPH })
|
|
630
706
|
}
|
|
631
707
|
) : null
|
|
632
708
|
]
|
|
@@ -639,11 +715,12 @@ function isBareText(node) {
|
|
|
639
715
|
function renderTextSlot(node, style) {
|
|
640
716
|
if (node === void 0 || node === null) return node;
|
|
641
717
|
if (isBareText(node)) return /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style, children: node });
|
|
642
|
-
return
|
|
718
|
+
return React__default.default.Children.map(
|
|
643
719
|
node,
|
|
644
720
|
(child) => isBareText(child) ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style, children: child }) : child
|
|
645
721
|
);
|
|
646
722
|
}
|
|
723
|
+
var DEFAULT_TRIGGER_TEST_ID = "sidebar-command-palette-trigger";
|
|
647
724
|
var Sidebar = ({
|
|
648
725
|
items,
|
|
649
726
|
pathname,
|
|
@@ -656,6 +733,7 @@ var Sidebar = ({
|
|
|
656
733
|
renderChevron,
|
|
657
734
|
enableInlineSearch = false,
|
|
658
735
|
search,
|
|
736
|
+
paletteTrigger,
|
|
659
737
|
searchQuery,
|
|
660
738
|
onSearchChange,
|
|
661
739
|
header,
|
|
@@ -664,20 +742,24 @@ var Sidebar = ({
|
|
|
664
742
|
}) => {
|
|
665
743
|
const { theme } = uiFeedback.useUi();
|
|
666
744
|
const colors = theme.colors;
|
|
667
|
-
const
|
|
745
|
+
const { width } = reactNative.useWindowDimensions();
|
|
746
|
+
const [internalQuery, setInternalQuery] = React.useState("");
|
|
668
747
|
const controlled = searchQuery !== void 0;
|
|
669
748
|
const query = controlled ? searchQuery : internalQuery;
|
|
670
|
-
const setQuery =
|
|
749
|
+
const setQuery = React.useCallback(
|
|
671
750
|
(next) => {
|
|
672
751
|
if (!controlled) setInternalQuery(next);
|
|
673
752
|
onSearchChange?.(next);
|
|
674
753
|
},
|
|
675
754
|
[controlled, onSearchChange]
|
|
676
755
|
);
|
|
677
|
-
const clearQuery =
|
|
678
|
-
const
|
|
679
|
-
const
|
|
680
|
-
const
|
|
756
|
+
const clearQuery = React.useCallback(() => setQuery(""), [setQuery]);
|
|
757
|
+
const affordance = resolveSearchAffordance(width);
|
|
758
|
+
const isInlineAffordance = affordance === "inline";
|
|
759
|
+
const showInlineSearch = enableInlineSearch && search !== void 0 && isInlineAffordance;
|
|
760
|
+
const showPaletteTrigger = paletteTrigger !== void 0 && !isInlineAffordance;
|
|
761
|
+
const visibleItems = showInlineSearch ? filterNavItems(items, query) : items;
|
|
762
|
+
const showEmpty = showInlineSearch && isFilterActive(query) && visibleItems.length === 0;
|
|
681
763
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
682
764
|
reactNative.View,
|
|
683
765
|
{
|
|
@@ -691,7 +773,7 @@ var Sidebar = ({
|
|
|
691
773
|
],
|
|
692
774
|
children: [
|
|
693
775
|
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { accessibilityRole: "header", style: [navStyles.sidebarTitle, { color: colors.text }], children: title }),
|
|
694
|
-
|
|
776
|
+
showInlineSearch && search !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
695
777
|
SidebarSearch,
|
|
696
778
|
{
|
|
697
779
|
labels: search,
|
|
@@ -701,6 +783,16 @@ var Sidebar = ({
|
|
|
701
783
|
onClear: clearQuery
|
|
702
784
|
}
|
|
703
785
|
) : null,
|
|
786
|
+
showPaletteTrigger && paletteTrigger !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: navStyles.sidebarTriggerSlot, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
787
|
+
CommandPaletteTrigger,
|
|
788
|
+
{
|
|
789
|
+
hint: paletteTrigger.hint,
|
|
790
|
+
label: paletteTrigger.label,
|
|
791
|
+
shortcut: paletteTrigger.shortcut,
|
|
792
|
+
testID: paletteTrigger.testID ?? DEFAULT_TRIGGER_TEST_ID,
|
|
793
|
+
onPress: paletteTrigger.onOpen
|
|
794
|
+
}
|
|
795
|
+
) }) : null,
|
|
704
796
|
renderTextSlot(header, { color: colors.text }),
|
|
705
797
|
showEmpty && search !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [navStyles.sidebarEmpty, { color: colors.textSecondary }], testID: "sidebar-search-empty", children: search.emptyText }) : visibleItems.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
706
798
|
NavExpandableItem,
|
|
@@ -722,12 +814,6 @@ var Sidebar = ({
|
|
|
722
814
|
);
|
|
723
815
|
};
|
|
724
816
|
|
|
725
|
-
// src/searchAffordance.ts
|
|
726
|
-
var DEFAULT_SEARCH_BREAKPOINT = 768;
|
|
727
|
-
function resolveSearchAffordance(viewport, breakpoint = DEFAULT_SEARCH_BREAKPOINT) {
|
|
728
|
-
return viewport >= breakpoint ? "inline" : "palette";
|
|
729
|
-
}
|
|
730
|
-
|
|
731
817
|
// src/constants.ts
|
|
732
818
|
var NAV_TEST_IDS = {
|
|
733
819
|
/** displayName line in the rich account header (tappable when `onAccount` set). */
|
|
@@ -775,7 +861,7 @@ var FocusableTouchable = ({
|
|
|
775
861
|
testID,
|
|
776
862
|
children
|
|
777
863
|
}) => {
|
|
778
|
-
const [focused, setFocused] =
|
|
864
|
+
const [focused, setFocused] = React.useState(false);
|
|
779
865
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
780
866
|
reactNative.Pressable,
|
|
781
867
|
{
|
|
@@ -928,8 +1014,8 @@ var NavBarLink = ({
|
|
|
928
1014
|
navigateHint,
|
|
929
1015
|
onPress
|
|
930
1016
|
}) => {
|
|
931
|
-
const [hovered, setHovered] =
|
|
932
|
-
const [focused, setFocused] =
|
|
1017
|
+
const [hovered, setHovered] = React.useState(false);
|
|
1018
|
+
const [focused, setFocused] = React.useState(false);
|
|
933
1019
|
const isHovered = hovered && !isActive;
|
|
934
1020
|
const textColor = isActive ? TEXT_ON_PRIMARY2 : isHovered ? colors.hoverText : colors.rest;
|
|
935
1021
|
const pillStyle = isActive ? { backgroundColor: colors.activeBg } : isHovered ? { backgroundColor: colors.hoverBg } : void 0;
|
|
@@ -973,12 +1059,12 @@ var NavOverflowMenu = ({
|
|
|
973
1059
|
testID,
|
|
974
1060
|
variant
|
|
975
1061
|
}) => {
|
|
976
|
-
const options =
|
|
977
|
-
const activeRoute =
|
|
1062
|
+
const options = React.useMemo(() => items.map((item) => ({ label: item.label, value: item.route })), [items]);
|
|
1063
|
+
const activeRoute = React.useMemo(
|
|
978
1064
|
() => items.find((item) => isRouteActive(pathname, item.route))?.route ?? NO_ACTIVE_ROUTE,
|
|
979
1065
|
[items, pathname]
|
|
980
1066
|
);
|
|
981
|
-
const optionTestID =
|
|
1067
|
+
const optionTestID = React.useMemo(() => {
|
|
982
1068
|
const byRoute = new Map(items.map((item) => [item.route, item.testID ?? item.key]));
|
|
983
1069
|
return (route) => byRoute.get(route) ?? `${testID}-option-${route}`;
|
|
984
1070
|
}, [items, testID]);
|
|
@@ -1035,13 +1121,13 @@ function resizeWidthBuffer(previous, count) {
|
|
|
1035
1121
|
return next;
|
|
1036
1122
|
}
|
|
1037
1123
|
function useNavOverflow(itemCount, gap) {
|
|
1038
|
-
const [availableWidth, setAvailableWidthState] =
|
|
1039
|
-
const [moreWidth, setMoreWidthState] =
|
|
1040
|
-
const [itemWidths, setItemWidths] =
|
|
1041
|
-
|
|
1124
|
+
const [availableWidth, setAvailableWidthState] = React.useState(0);
|
|
1125
|
+
const [moreWidth, setMoreWidthState] = React.useState(0);
|
|
1126
|
+
const [itemWidths, setItemWidths] = React.useState(() => new Array(itemCount).fill(0));
|
|
1127
|
+
React.useEffect(() => {
|
|
1042
1128
|
setItemWidths((previous) => previous.length === itemCount ? previous : resizeWidthBuffer(previous, itemCount));
|
|
1043
1129
|
}, [itemCount]);
|
|
1044
|
-
const setItemWidth =
|
|
1130
|
+
const setItemWidth = React.useCallback((index, width) => {
|
|
1045
1131
|
setItemWidths((previous) => {
|
|
1046
1132
|
if (index < 0 || index >= previous.length || previous[index] === width) return previous;
|
|
1047
1133
|
const next = previous.slice();
|
|
@@ -1049,15 +1135,15 @@ function useNavOverflow(itemCount, gap) {
|
|
|
1049
1135
|
return next;
|
|
1050
1136
|
});
|
|
1051
1137
|
}, []);
|
|
1052
|
-
const setAvailableWidth =
|
|
1138
|
+
const setAvailableWidth = React.useCallback(
|
|
1053
1139
|
(width) => setAvailableWidthState((previous) => previous === width ? previous : width),
|
|
1054
1140
|
[]
|
|
1055
1141
|
);
|
|
1056
|
-
const setMoreWidth =
|
|
1142
|
+
const setMoreWidth = React.useCallback(
|
|
1057
1143
|
(width) => setMoreWidthState((previous) => previous === width ? previous : width),
|
|
1058
1144
|
[]
|
|
1059
1145
|
);
|
|
1060
|
-
const visibleCount =
|
|
1146
|
+
const visibleCount = React.useMemo(
|
|
1061
1147
|
() => computeVisibleCount({ availableWidth, itemWidths, moreWidth, gap }),
|
|
1062
1148
|
[availableWidth, itemWidths, moreWidth, gap]
|
|
1063
1149
|
);
|
|
@@ -1091,24 +1177,24 @@ var NavBarInner = ({
|
|
|
1091
1177
|
const primaryColor = theme.palette.primary["500"];
|
|
1092
1178
|
const { width } = reactNative.useWindowDimensions();
|
|
1093
1179
|
const reducedMotion = useReducedMotion();
|
|
1094
|
-
const [open, setOpen] =
|
|
1095
|
-
const [toggleFocused, setToggleFocused] =
|
|
1180
|
+
const [open, setOpen] = React.useState(false);
|
|
1181
|
+
const [toggleFocused, setToggleFocused] = React.useState(false);
|
|
1096
1182
|
const { visibleCount, setAvailableWidth, setItemWidth, setMoreWidth } = useNavOverflow(items.length, NAV_LINK_GAP);
|
|
1097
1183
|
const collapsed = width < collapseBelow;
|
|
1098
1184
|
const showLinks = !collapsed || open;
|
|
1099
|
-
const innerCapStyle =
|
|
1185
|
+
const innerCapStyle = React.useMemo(
|
|
1100
1186
|
() => contentMaxWidth === void 0 ? null : { maxWidth: contentMaxWidth, width: "100%", alignSelf: "center" },
|
|
1101
1187
|
[contentMaxWidth]
|
|
1102
1188
|
);
|
|
1103
|
-
const toggleMenu =
|
|
1104
|
-
const handlePress =
|
|
1189
|
+
const toggleMenu = React.useCallback(() => setOpen((v) => !v), []);
|
|
1190
|
+
const handlePress = React.useCallback(
|
|
1105
1191
|
(route) => {
|
|
1106
1192
|
setOpen(false);
|
|
1107
1193
|
onNavigate(route);
|
|
1108
1194
|
},
|
|
1109
1195
|
[onNavigate]
|
|
1110
1196
|
);
|
|
1111
|
-
const linkColors =
|
|
1197
|
+
const linkColors = React.useMemo(
|
|
1112
1198
|
() => ({
|
|
1113
1199
|
rest: colors.textSecondary,
|
|
1114
1200
|
hoverText: colors.text,
|
|
@@ -1163,7 +1249,7 @@ var NavBarInner = ({
|
|
|
1163
1249
|
}
|
|
1164
1250
|
);
|
|
1165
1251
|
if (collapsed) {
|
|
1166
|
-
return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { nativeID: LINKS_REGION_ID, style: navBarStyles.linksStacked, testID: NAV_TEST_IDS.navBarLinks, children: items.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1252
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { nativeID: LINKS_REGION_ID, style: navBarStyles.linksStacked, testID: NAV_TEST_IDS.navBarLinks, children: items.map((item) => /* @__PURE__ */ jsxRuntime.jsx(React__default.default.Fragment, { children: renderLink(item) }, item.key)) });
|
|
1167
1253
|
}
|
|
1168
1254
|
const visibleItems = items.slice(0, visibleCount);
|
|
1169
1255
|
const overflowItems = items.slice(visibleCount);
|
|
@@ -1229,7 +1315,7 @@ var CARD_BORDER_WIDTH = 1;
|
|
|
1229
1315
|
var CARD_TITLE_FONT_SIZE = 16;
|
|
1230
1316
|
var CARD_MESSAGE_FONT_SIZE = 14;
|
|
1231
1317
|
var CARD_TITLE_MARGIN_BOTTOM = 8;
|
|
1232
|
-
var
|
|
1318
|
+
var styles3 = reactNative.StyleSheet.create({
|
|
1233
1319
|
centerFill: { flex: 1, justifyContent: "center", alignItems: "center" },
|
|
1234
1320
|
card: {
|
|
1235
1321
|
padding: CARD_PADDING,
|
|
@@ -1246,9 +1332,9 @@ function MessageCard({
|
|
|
1246
1332
|
}) {
|
|
1247
1333
|
const { theme } = uiFeedback.useUi();
|
|
1248
1334
|
const colors = theme.colors;
|
|
1249
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [
|
|
1250
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [
|
|
1251
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [
|
|
1335
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles3.card, { backgroundColor: colors.surface, borderColor: accentColor }], testID, children: [
|
|
1336
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles3.cardTitle, { color: accentColor }], children: message.titleText }),
|
|
1337
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles3.cardMessage, { color: colors.textSecondary }], children: message.messageText })
|
|
1252
1338
|
] });
|
|
1253
1339
|
}
|
|
1254
1340
|
function useContentBody(state, children, testID) {
|
|
@@ -1260,7 +1346,7 @@ function useContentBody(state, children, testID) {
|
|
|
1260
1346
|
if (state?.error)
|
|
1261
1347
|
return /* @__PURE__ */ jsxRuntime.jsx(MessageCard, { accentColor: errorColor, message: state.error, testID: `${testID}${APP_SHELL_SUFFIX.error}` });
|
|
1262
1348
|
if (state?.loading === true)
|
|
1263
|
-
return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style:
|
|
1349
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles3.centerFill, testID: `${testID}${APP_SHELL_SUFFIX.loading}`, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: primary, size: "large" }) });
|
|
1264
1350
|
return children;
|
|
1265
1351
|
}
|
|
1266
1352
|
var SCRIM_COLOR = "rgba(0, 0, 0, 0.5)";
|
|
@@ -1284,7 +1370,7 @@ var DEFAULT_DRAWER_LABELS = {
|
|
|
1284
1370
|
closeLabel: "Close menu",
|
|
1285
1371
|
closeHint: "Close the navigation menu"
|
|
1286
1372
|
};
|
|
1287
|
-
var
|
|
1373
|
+
var styles4 = reactNative.StyleSheet.create({
|
|
1288
1374
|
overlay: { ...reactNative.StyleSheet.absoluteFillObject, zIndex: DRAWER_Z_INDEX },
|
|
1289
1375
|
// The scrim's tap-to-close hit area is anchored to the RIGHT of the panel
|
|
1290
1376
|
// (`left: DRAWER_WIDTH`), so it NEVER overlaps the panel: nav-item taps always
|
|
@@ -1319,10 +1405,10 @@ var MenuToggle = ({ label, hint, onOpen, testID }) => {
|
|
|
1319
1405
|
accessibilityHint: hint,
|
|
1320
1406
|
accessibilityLabel: label,
|
|
1321
1407
|
ringColor: theme.palette.primary["500"],
|
|
1322
|
-
style:
|
|
1408
|
+
style: styles4.menuToggle,
|
|
1323
1409
|
testID,
|
|
1324
1410
|
onPress: onOpen,
|
|
1325
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [
|
|
1411
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles4.menuToggleGlyph, { color: theme.colors.text }], children: MENU_GLYPH2 })
|
|
1326
1412
|
}
|
|
1327
1413
|
);
|
|
1328
1414
|
};
|
|
@@ -1334,8 +1420,8 @@ var MobileDrawer = ({
|
|
|
1334
1420
|
scrimTestID
|
|
1335
1421
|
}) => {
|
|
1336
1422
|
const { theme } = uiFeedback.useUi();
|
|
1337
|
-
const panelRef =
|
|
1338
|
-
|
|
1423
|
+
const panelRef = React.useRef(null);
|
|
1424
|
+
React.useEffect(() => {
|
|
1339
1425
|
const node = panelRef.current;
|
|
1340
1426
|
if (node === null || typeof node.addEventListener !== "function") return void 0;
|
|
1341
1427
|
const handleClick = (event) => {
|
|
@@ -1348,14 +1434,14 @@ var MobileDrawer = ({
|
|
|
1348
1434
|
node.addEventListener("click", handleClick);
|
|
1349
1435
|
return () => node.removeEventListener("click", handleClick);
|
|
1350
1436
|
}, [onClose]);
|
|
1351
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
1437
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles4.overlay, children: [
|
|
1352
1438
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1353
1439
|
reactNative.Pressable,
|
|
1354
1440
|
{
|
|
1355
1441
|
accessibilityHint: labels.closeHint,
|
|
1356
1442
|
accessibilityLabel: labels.closeLabel,
|
|
1357
1443
|
accessibilityRole: "button",
|
|
1358
|
-
style:
|
|
1444
|
+
style: styles4.scrim,
|
|
1359
1445
|
testID: scrimTestID,
|
|
1360
1446
|
onPress: onClose
|
|
1361
1447
|
}
|
|
@@ -1366,7 +1452,7 @@ var MobileDrawer = ({
|
|
|
1366
1452
|
ref: panelRef,
|
|
1367
1453
|
"aria-modal": true,
|
|
1368
1454
|
role: "dialog",
|
|
1369
|
-
style: [
|
|
1455
|
+
style: [styles4.panel, { backgroundColor: theme.colors.surface }],
|
|
1370
1456
|
testID: drawerTestID,
|
|
1371
1457
|
children: renderTextSlot(sidebar, { color: theme.colors.text })
|
|
1372
1458
|
}
|
|
@@ -1397,7 +1483,7 @@ function useContentMaxWidth(width) {
|
|
|
1397
1483
|
return resolveContentMaxWidth(width, viewport);
|
|
1398
1484
|
}
|
|
1399
1485
|
var DEFAULT_CONTENT_PADDING = 24;
|
|
1400
|
-
var
|
|
1486
|
+
var styles5 = reactNative.StyleSheet.create({
|
|
1401
1487
|
root: { flex: 1 },
|
|
1402
1488
|
centerFill: { flex: 1, justifyContent: "center", alignItems: "center" },
|
|
1403
1489
|
scroll: { flex: 1 },
|
|
@@ -1442,32 +1528,32 @@ var AppShell = ({
|
|
|
1442
1528
|
range: railRange
|
|
1443
1529
|
});
|
|
1444
1530
|
const useDrawer = railMode === "drawer";
|
|
1445
|
-
const [drawerOpen, setDrawerOpen] =
|
|
1446
|
-
const openDrawer =
|
|
1447
|
-
const closeDrawer =
|
|
1448
|
-
|
|
1531
|
+
const [drawerOpen, setDrawerOpen] = React.useState(false);
|
|
1532
|
+
const openDrawer = React.useCallback(() => setDrawerOpen(true), []);
|
|
1533
|
+
const closeDrawer = React.useCallback(() => setDrawerOpen(false), []);
|
|
1534
|
+
React.useEffect(() => {
|
|
1449
1535
|
if (!useDrawer && drawerOpen) setDrawerOpen(false);
|
|
1450
1536
|
}, [useDrawer, drawerOpen]);
|
|
1451
1537
|
const drawerLabels = { ...DEFAULT_DRAWER_LABELS, ...mobileMenu };
|
|
1452
1538
|
const isUnauthenticated = gate !== void 0 && !gate.pending && !gate.authenticated;
|
|
1453
|
-
|
|
1539
|
+
React.useEffect(() => {
|
|
1454
1540
|
if (isUnauthenticated && gate !== void 0) gate.onRedirect();
|
|
1455
1541
|
}, [isUnauthenticated, gate]);
|
|
1456
1542
|
if (gate?.pending === true)
|
|
1457
|
-
return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [
|
|
1543
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles5.root, styles5.centerFill, { backgroundColor: theme.colors.background }], testID: `${testID}${APP_SHELL_SUFFIX.pending}`, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: primary, size: "large" }) });
|
|
1458
1544
|
if (isUnauthenticated) return null;
|
|
1459
|
-
const columnStyle = maxWidth === "full" ?
|
|
1460
|
-
const navInnerStyle = chromeAlignment === "content" && maxWidth !== "full" ? [
|
|
1545
|
+
const columnStyle = maxWidth === "full" ? styles5.columnFull : [styles5.columnCapped, { maxWidth }];
|
|
1546
|
+
const navInnerStyle = chromeAlignment === "content" && maxWidth !== "full" ? [styles5.chromeCapped, { maxWidth, paddingHorizontal: contentPadding }] : void 0;
|
|
1461
1547
|
const scroller = /* @__PURE__ */ jsxRuntime.jsx(
|
|
1462
1548
|
reactNative.ScrollView,
|
|
1463
1549
|
{
|
|
1464
|
-
contentContainerStyle: [
|
|
1465
|
-
style:
|
|
1550
|
+
contentContainerStyle: [styles5.scrollContent, { padding: contentPadding }],
|
|
1551
|
+
style: styles5.scroll,
|
|
1466
1552
|
testID: `${testID}${APP_SHELL_SUFFIX.content}`,
|
|
1467
1553
|
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: columnStyle, children: body })
|
|
1468
1554
|
}
|
|
1469
1555
|
);
|
|
1470
|
-
const headerRegion = useDrawer ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
1556
|
+
const headerRegion = useDrawer ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles5.headerRow, testID: `${testID}${APP_SHELL_SUFFIX.header}`, children: [
|
|
1471
1557
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1472
1558
|
MenuToggle,
|
|
1473
1559
|
{
|
|
@@ -1477,14 +1563,14 @@ var AppShell = ({
|
|
|
1477
1563
|
onOpen: openDrawer
|
|
1478
1564
|
}
|
|
1479
1565
|
),
|
|
1480
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style:
|
|
1566
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles5.headerFill, children: renderTextSlot(header, { color: theme.colors.text }) })
|
|
1481
1567
|
] }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { testID: `${testID}${APP_SHELL_SUFFIX.header}`, children: renderTextSlot(header, { color: theme.colors.text }) });
|
|
1482
1568
|
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;
|
|
1483
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [
|
|
1569
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles5.root, { backgroundColor: theme.colors.background }], testID, children: [
|
|
1484
1570
|
headerRegion,
|
|
1485
1571
|
nav !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { testID: `${testID}${APP_SHELL_SUFFIX.nav}`, children: navInnerStyle !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: navInnerStyle, children: renderTextSlot(nav, { color: theme.colors.text }) }) : renderTextSlot(nav, { color: theme.colors.text }) }) : null,
|
|
1486
1572
|
banner !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { testID: `${testID}${APP_SHELL_SUFFIX.banner}`, children: renderTextSlot(banner, { color: theme.colors.text }) }) : null,
|
|
1487
|
-
railRegion !== null ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
1573
|
+
railRegion !== null ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles5.bodyRow, children: [
|
|
1488
1574
|
railRegion,
|
|
1489
1575
|
scroller
|
|
1490
1576
|
] }) : scroller,
|
|
@@ -1601,16 +1687,21 @@ var NavShell = ({
|
|
|
1601
1687
|
{
|
|
1602
1688
|
collapseHint: sideRail.collapseHint,
|
|
1603
1689
|
containerStyle: sideRail.containerStyle,
|
|
1690
|
+
enableInlineSearch: sideRail.enableInlineSearch,
|
|
1604
1691
|
expandHint: sideRail.expandHint,
|
|
1605
1692
|
footer: sideRail.footer,
|
|
1606
1693
|
header: sideRail.header,
|
|
1607
1694
|
items: sideRail.items,
|
|
1608
1695
|
navigateHint,
|
|
1696
|
+
paletteTrigger: sideRail.paletteTrigger,
|
|
1609
1697
|
pathname,
|
|
1610
1698
|
regionLabel,
|
|
1611
1699
|
renderChevron: sideRail.renderChevron,
|
|
1700
|
+
search: sideRail.search,
|
|
1701
|
+
searchQuery: sideRail.searchQuery,
|
|
1612
1702
|
title: sideRail.title,
|
|
1613
|
-
onNavigate
|
|
1703
|
+
onNavigate,
|
|
1704
|
+
onSearchChange: sideRail.onSearchChange
|
|
1614
1705
|
}
|
|
1615
1706
|
) : void 0;
|
|
1616
1707
|
const collapsedCfg = showSideRail ? sideRail?.collapsed : void 0;
|
|
@@ -1702,7 +1793,7 @@ var DarkModeControl = ({
|
|
|
1702
1793
|
const primaryColor = theme.palette.primary["500"];
|
|
1703
1794
|
const currentIndex = options.findIndex((option) => option.value === value);
|
|
1704
1795
|
const current = currentIndex >= 0 ? options[currentIndex] : options[0];
|
|
1705
|
-
const advance =
|
|
1796
|
+
const advance = React.useCallback(() => {
|
|
1706
1797
|
if (options.length === 0) return;
|
|
1707
1798
|
const from = currentIndex >= 0 ? currentIndex : 0;
|
|
1708
1799
|
const next = options[(from + 1) % options.length];
|
|
@@ -1778,7 +1869,7 @@ var KEY_DOWN = "ArrowDown";
|
|
|
1778
1869
|
var KEY_UP = "ArrowUp";
|
|
1779
1870
|
var KEY_ENTER = "Enter";
|
|
1780
1871
|
var KEY_ESCAPE = "Escape";
|
|
1781
|
-
var
|
|
1872
|
+
var styles6 = reactNative.StyleSheet.create({
|
|
1782
1873
|
overlay: { ...reactNative.StyleSheet.absoluteFillObject, zIndex: OVERLAY_Z_INDEX, alignItems: "center" },
|
|
1783
1874
|
scrim: { ...reactNative.StyleSheet.absoluteFillObject, backgroundColor: SCRIM_COLOR2 },
|
|
1784
1875
|
panel: {
|
|
@@ -1807,14 +1898,14 @@ var PaletteRow = ({ item, selected, onChoose }) => {
|
|
|
1807
1898
|
accessibilityLabel: item.label,
|
|
1808
1899
|
accessibilityRole: "button",
|
|
1809
1900
|
accessibilityState: { selected },
|
|
1810
|
-
style: [
|
|
1901
|
+
style: [styles6.row, selected ? { backgroundColor: colors.border } : void 0],
|
|
1811
1902
|
testID: item.testID ?? item.key,
|
|
1812
1903
|
onPress: () => onChoose(item),
|
|
1813
1904
|
children: [
|
|
1814
1905
|
typeof item.renderIcon === "function" ? item.renderIcon(colors.textSecondary, NAV_ICON_SIZE) : null,
|
|
1815
|
-
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
1816
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [
|
|
1817
|
-
item.hint ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [
|
|
1906
|
+
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles6.rowText, children: [
|
|
1907
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles6.rowLabel, { color: colors.text }], children: item.label }),
|
|
1908
|
+
item.hint ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles6.rowHint, { color: colors.textSecondary }], children: item.hint }) : null
|
|
1818
1909
|
] })
|
|
1819
1910
|
]
|
|
1820
1911
|
}
|
|
@@ -1823,27 +1914,27 @@ var PaletteRow = ({ item, selected, onChoose }) => {
|
|
|
1823
1914
|
var CommandPalette = ({ open, items, onClose, labels, testID }) => {
|
|
1824
1915
|
const { theme } = uiFeedback.useUi();
|
|
1825
1916
|
const colors = theme.colors;
|
|
1826
|
-
const [query, setQuery] =
|
|
1827
|
-
const [selected, setSelected] =
|
|
1828
|
-
const inputRef =
|
|
1829
|
-
const results =
|
|
1830
|
-
|
|
1917
|
+
const [query, setQuery] = React.useState("");
|
|
1918
|
+
const [selected, setSelected] = React.useState(0);
|
|
1919
|
+
const inputRef = React.useRef(null);
|
|
1920
|
+
const results = React.useMemo(() => filterCommands(items, query), [items, query]);
|
|
1921
|
+
React.useEffect(() => {
|
|
1831
1922
|
if (!open) return;
|
|
1832
1923
|
setQuery("");
|
|
1833
1924
|
setSelected(0);
|
|
1834
1925
|
inputRef.current?.focus();
|
|
1835
1926
|
}, [open]);
|
|
1836
|
-
|
|
1927
|
+
React.useEffect(() => {
|
|
1837
1928
|
setSelected((prev) => Math.min(prev, Math.max(0, results.length - 1)));
|
|
1838
1929
|
}, [results.length]);
|
|
1839
|
-
const choose =
|
|
1930
|
+
const choose = React.useCallback(
|
|
1840
1931
|
(item) => {
|
|
1841
1932
|
item.onSelect();
|
|
1842
1933
|
onClose();
|
|
1843
1934
|
},
|
|
1844
1935
|
[onClose]
|
|
1845
1936
|
);
|
|
1846
|
-
const onKeyPress =
|
|
1937
|
+
const onKeyPress = React.useCallback(
|
|
1847
1938
|
(event) => {
|
|
1848
1939
|
const key = event.nativeEvent.key;
|
|
1849
1940
|
if (key === KEY_DOWN) setSelected((i) => Math.min(i + 1, results.length - 1));
|
|
@@ -1854,14 +1945,14 @@ var CommandPalette = ({ open, items, onClose, labels, testID }) => {
|
|
|
1854
1945
|
[results, selected, choose, onClose]
|
|
1855
1946
|
);
|
|
1856
1947
|
if (!open) return null;
|
|
1857
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
1948
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles6.overlay, children: [
|
|
1858
1949
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1859
1950
|
reactNative.Pressable,
|
|
1860
1951
|
{
|
|
1861
1952
|
accessibilityHint: labels.closeHint,
|
|
1862
1953
|
accessibilityLabel: labels.closeLabel,
|
|
1863
1954
|
accessibilityRole: "button",
|
|
1864
|
-
style:
|
|
1955
|
+
style: styles6.scrim,
|
|
1865
1956
|
testID: `${testID ?? "command-palette"}-scrim`,
|
|
1866
1957
|
onPress: onClose
|
|
1867
1958
|
}
|
|
@@ -1872,7 +1963,7 @@ var CommandPalette = ({ open, items, onClose, labels, testID }) => {
|
|
|
1872
1963
|
"aria-modal": true,
|
|
1873
1964
|
"aria-label": labels.regionLabel,
|
|
1874
1965
|
role: "dialog",
|
|
1875
|
-
style: [
|
|
1966
|
+
style: [styles6.panel, { backgroundColor: colors.surface, borderColor: colors.border }],
|
|
1876
1967
|
testID: testID ?? "command-palette",
|
|
1877
1968
|
children: [
|
|
1878
1969
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1882,71 +1973,22 @@ var CommandPalette = ({ open, items, onClose, labels, testID }) => {
|
|
|
1882
1973
|
accessibilityLabel: labels.placeholder,
|
|
1883
1974
|
placeholder: labels.placeholder,
|
|
1884
1975
|
placeholderTextColor: colors.textSecondary,
|
|
1885
|
-
style: [
|
|
1976
|
+
style: [styles6.input, { color: colors.text, borderBottomColor: colors.border }],
|
|
1886
1977
|
testID: `${testID ?? "command-palette"}-input`,
|
|
1887
1978
|
value: query,
|
|
1888
1979
|
onChangeText: setQuery,
|
|
1889
1980
|
onKeyPress
|
|
1890
1981
|
}
|
|
1891
1982
|
),
|
|
1892
|
-
results.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [
|
|
1983
|
+
results.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles6.empty, { color: colors.textSecondary }], children: labels.emptyText }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.ScrollView, { keyboardShouldPersistTaps: "handled", style: styles6.list, children: results.map((item, index) => /* @__PURE__ */ jsxRuntime.jsx(PaletteRow, { item, selected: index === selected, onChoose: choose }, item.key)) })
|
|
1893
1984
|
]
|
|
1894
1985
|
}
|
|
1895
1986
|
)
|
|
1896
1987
|
] });
|
|
1897
1988
|
};
|
|
1898
|
-
var MIN_TARGET = 36;
|
|
1899
|
-
var styles6 = reactNative.StyleSheet.create({
|
|
1900
|
-
trigger: {
|
|
1901
|
-
flexDirection: "row",
|
|
1902
|
-
alignItems: "center",
|
|
1903
|
-
justifyContent: "space-between",
|
|
1904
|
-
columnGap: 8,
|
|
1905
|
-
paddingHorizontal: 12,
|
|
1906
|
-
minHeight: MIN_TARGET,
|
|
1907
|
-
borderWidth: 1,
|
|
1908
|
-
borderRadius: 8
|
|
1909
|
-
},
|
|
1910
|
-
label: { fontSize: 14 },
|
|
1911
|
-
badge: { paddingHorizontal: 6, paddingVertical: 2, borderRadius: 4, borderWidth: 1 },
|
|
1912
|
-
badgeText: { fontSize: 11, fontWeight: "700" }
|
|
1913
|
-
});
|
|
1914
|
-
var CommandPaletteTrigger = ({
|
|
1915
|
-
label,
|
|
1916
|
-
hint,
|
|
1917
|
-
shortcut,
|
|
1918
|
-
onPress,
|
|
1919
|
-
testID
|
|
1920
|
-
}) => {
|
|
1921
|
-
const { theme } = uiFeedback.useUi();
|
|
1922
|
-
const colors = theme.colors;
|
|
1923
|
-
const primary = theme.palette.primary["500"];
|
|
1924
|
-
const [focused, setFocused] = React3__default.default.useState(false);
|
|
1925
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1926
|
-
reactNative.Pressable,
|
|
1927
|
-
{
|
|
1928
|
-
accessibilityHint: hint,
|
|
1929
|
-
accessibilityLabel: label,
|
|
1930
|
-
accessibilityRole: "button",
|
|
1931
|
-
style: [
|
|
1932
|
-
styles6.trigger,
|
|
1933
|
-
{ backgroundColor: colors.surface, borderColor: colors.border },
|
|
1934
|
-
focusRingStyle(focused, primary)
|
|
1935
|
-
],
|
|
1936
|
-
testID,
|
|
1937
|
-
onBlur: () => setFocused(false),
|
|
1938
|
-
onFocus: () => setFocused(true),
|
|
1939
|
-
onPress,
|
|
1940
|
-
children: [
|
|
1941
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles6.label, { color: colors.textSecondary }], children: label }),
|
|
1942
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles6.badge, { borderColor: colors.border }], children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles6.badgeText, { color: colors.textSecondary }], children: shortcut }) })
|
|
1943
|
-
]
|
|
1944
|
-
}
|
|
1945
|
-
);
|
|
1946
|
-
};
|
|
1947
1989
|
var LAUNCH_KEY = "k";
|
|
1948
1990
|
function useCommandPaletteHotkey(onOpen, enabled = true) {
|
|
1949
|
-
|
|
1991
|
+
React.useEffect(() => {
|
|
1950
1992
|
if (!enabled || typeof document === "undefined") return void 0;
|
|
1951
1993
|
const handler = (event) => {
|
|
1952
1994
|
const isLauncher = event.key.toLowerCase() === LAUNCH_KEY && (event.metaKey || event.ctrlKey);
|