@dloizides/ui-nav 1.15.0 → 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/CHANGELOG.md +35 -1
- package/README.md +31 -0
- package/dist/index.d.mts +182 -3
- package/dist/index.d.ts +182 -3
- package/dist/index.js +345 -116
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +295 -76
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var React3 = require('react');
|
|
3
4
|
var reactNative = require('react-native');
|
|
4
5
|
var uiFeedback = require('@dloizides/ui-feedback');
|
|
5
|
-
var React2 = require('react');
|
|
6
6
|
var uiMotion = require('@dloizides/ui-motion');
|
|
7
7
|
var jsxRuntime = require('react/jsx-runtime');
|
|
8
8
|
var uiLayout = require('@dloizides/ui-layout');
|
|
@@ -10,10 +10,42 @@ 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 React3__default = /*#__PURE__*/_interopDefault(React3);
|
|
14
14
|
|
|
15
15
|
// src/Sidebar.tsx
|
|
16
16
|
|
|
17
|
+
// src/sidebarFilter.ts
|
|
18
|
+
function searchTokens(query) {
|
|
19
|
+
return query.trim().toLowerCase().split(/\s+/).filter(Boolean);
|
|
20
|
+
}
|
|
21
|
+
function labelMatches(item, tokens) {
|
|
22
|
+
const label = item.label.toLowerCase();
|
|
23
|
+
return tokens.every((token) => label.includes(token));
|
|
24
|
+
}
|
|
25
|
+
function filterNavItems(items, query) {
|
|
26
|
+
const tokens = searchTokens(query);
|
|
27
|
+
if (tokens.length === 0) return [...items];
|
|
28
|
+
return filterByTokens(items, tokens);
|
|
29
|
+
}
|
|
30
|
+
function filterByTokens(items, tokens) {
|
|
31
|
+
const kept = [];
|
|
32
|
+
for (const item of items) {
|
|
33
|
+
const selfMatch = labelMatches(item, tokens);
|
|
34
|
+
const children = item.children ?? [];
|
|
35
|
+
if (selfMatch) {
|
|
36
|
+
kept.push(item);
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
if (children.length === 0) continue;
|
|
40
|
+
const prunedChildren = filterByTokens(children, tokens);
|
|
41
|
+
if (prunedChildren.length > 0) kept.push({ ...item, children: prunedChildren });
|
|
42
|
+
}
|
|
43
|
+
return kept;
|
|
44
|
+
}
|
|
45
|
+
function isFilterActive(query) {
|
|
46
|
+
return searchTokens(query).length > 0;
|
|
47
|
+
}
|
|
48
|
+
|
|
17
49
|
// src/isRouteActive.ts
|
|
18
50
|
function isRouteActive(pathname, route) {
|
|
19
51
|
if (route === "/") return pathname === "/";
|
|
@@ -21,6 +53,9 @@ function isRouteActive(pathname, route) {
|
|
|
21
53
|
}
|
|
22
54
|
var ACTIVE_BORDER_RADIUS = 4;
|
|
23
55
|
var ACTIVE_ACCENT_WIDTH = 3;
|
|
56
|
+
var NAV_ROW_RADIUS = 8;
|
|
57
|
+
var ACTIVE_TINT_OPACITY = 0.14;
|
|
58
|
+
var HOVER_TINT_OPACITY = 0.06;
|
|
24
59
|
var NAV_LINK_GAP = 4;
|
|
25
60
|
var navStyles = reactNative.StyleSheet.create({
|
|
26
61
|
// --- Sidebar ---
|
|
@@ -46,6 +81,12 @@ var navStyles = reactNative.StyleSheet.create({
|
|
|
46
81
|
sidebarSpacer: {
|
|
47
82
|
flex: 1
|
|
48
83
|
},
|
|
84
|
+
// Inline-search no-match text — sits where the nav list would, muted + padded.
|
|
85
|
+
sidebarEmpty: {
|
|
86
|
+
fontSize: 13,
|
|
87
|
+
paddingVertical: 10,
|
|
88
|
+
paddingHorizontal: 12
|
|
89
|
+
},
|
|
49
90
|
// --- Topbar ---
|
|
50
91
|
topbarContainer: {
|
|
51
92
|
height: 64,
|
|
@@ -246,8 +287,12 @@ var collapsedRailStyles = reactNative.StyleSheet.create({
|
|
|
246
287
|
var expandableStyles = reactNative.StyleSheet.create({
|
|
247
288
|
// Every leaf reserves the accent-bar gutter (a TRANSPARENT left border of the
|
|
248
289
|
// same width the active item colours in) so activation never shifts the row.
|
|
290
|
+
// `overflow: hidden` clips the rounded {@link tintOverlay} to the row's corners;
|
|
291
|
+
// `position: relative` anchors that absolutely-filled overlay to the row.
|
|
249
292
|
childItem: {
|
|
250
|
-
|
|
293
|
+
position: "relative",
|
|
294
|
+
overflow: "hidden",
|
|
295
|
+
borderRadius: NAV_ROW_RADIUS,
|
|
251
296
|
flexDirection: "row",
|
|
252
297
|
alignItems: "center",
|
|
253
298
|
paddingVertical: 9,
|
|
@@ -258,8 +303,24 @@ var expandableStyles = reactNative.StyleSheet.create({
|
|
|
258
303
|
childItemTextWithIcon: { fontSize: 14, marginLeft: 6 },
|
|
259
304
|
chevron: { marginLeft: "auto" },
|
|
260
305
|
childrenContainer: { overflow: "hidden", marginBottom: 4 },
|
|
306
|
+
// The hover/active brand wash: a rounded fill behind the row's icon + label,
|
|
307
|
+
// its opacity eased between 0 / hover / active. Colour + opacity are applied at
|
|
308
|
+
// render time (theme primary); this only positions and rounds it.
|
|
309
|
+
tintOverlay: {
|
|
310
|
+
position: "absolute",
|
|
311
|
+
top: 0,
|
|
312
|
+
left: 0,
|
|
313
|
+
right: 0,
|
|
314
|
+
bottom: 0,
|
|
315
|
+
borderRadius: NAV_ROW_RADIUS,
|
|
316
|
+
// `style.pointerEvents` (not the deprecated prop) so the overlay never
|
|
317
|
+
// intercepts the row's press/hover — RNW forwards this style key to the DOM.
|
|
318
|
+
pointerEvents: "none"
|
|
319
|
+
},
|
|
261
320
|
header: {
|
|
262
|
-
|
|
321
|
+
position: "relative",
|
|
322
|
+
overflow: "hidden",
|
|
323
|
+
borderRadius: NAV_ROW_RADIUS,
|
|
263
324
|
flexDirection: "row",
|
|
264
325
|
alignItems: "center",
|
|
265
326
|
paddingVertical: 8
|
|
@@ -286,6 +347,7 @@ var IS_WEB = reactNative.Platform.OS === "web";
|
|
|
286
347
|
var FOCUS_RING_WIDTH = 2;
|
|
287
348
|
var FOCUS_RING_OFFSET = 2;
|
|
288
349
|
var HOVER_TRANSITION_MS = 150;
|
|
350
|
+
var TINT_TRANSITION_MS = 160;
|
|
289
351
|
function focusRingStyle(focused, ringColor) {
|
|
290
352
|
if (!IS_WEB || !focused) return void 0;
|
|
291
353
|
const ring = {
|
|
@@ -296,24 +358,80 @@ function focusRingStyle(focused, ringColor) {
|
|
|
296
358
|
};
|
|
297
359
|
return ring;
|
|
298
360
|
}
|
|
299
|
-
function
|
|
361
|
+
function webTransition(properties, durationMs, reducedMotion) {
|
|
300
362
|
if (!IS_WEB) return void 0;
|
|
301
363
|
const transition = {
|
|
302
|
-
transitionProperty:
|
|
303
|
-
transitionDuration: reducedMotion ? "0ms" : `${
|
|
364
|
+
transitionProperty: properties,
|
|
365
|
+
transitionDuration: reducedMotion ? "0ms" : `${durationMs}ms`
|
|
304
366
|
};
|
|
305
367
|
return transition;
|
|
306
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
|
+
var REDUCED_MOTION_QUERY = "(prefers-reduced-motion: reduce)";
|
|
379
|
+
function getReducedMotionQuery() {
|
|
380
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return void 0;
|
|
381
|
+
return window.matchMedia(REDUCED_MOTION_QUERY);
|
|
382
|
+
}
|
|
383
|
+
function useReducedMotion() {
|
|
384
|
+
const [reduced, setReduced] = React3.useState(() => getReducedMotionQuery()?.matches ?? false);
|
|
385
|
+
React3.useEffect(() => {
|
|
386
|
+
const mql = getReducedMotionQuery();
|
|
387
|
+
if (mql === void 0 || mql.addEventListener === void 0) return void 0;
|
|
388
|
+
const onChange = () => setReduced(mql.matches);
|
|
389
|
+
mql.addEventListener("change", onChange);
|
|
390
|
+
return () => {
|
|
391
|
+
mql.removeEventListener?.("change", onChange);
|
|
392
|
+
};
|
|
393
|
+
}, []);
|
|
394
|
+
return reduced;
|
|
395
|
+
}
|
|
396
|
+
var CHEVRON_GLYPH = "\u203A";
|
|
397
|
+
var EXPANDED_ROTATION = "90deg";
|
|
398
|
+
var COLLAPSED_ROTATION = "0deg";
|
|
399
|
+
var CHEVRON_FONT_WEIGHT = "700";
|
|
400
|
+
var SidebarChevron = ({ expanded, color, size }) => {
|
|
401
|
+
const reducedMotion = useReducedMotion();
|
|
402
|
+
const style = {
|
|
403
|
+
color,
|
|
404
|
+
fontSize: size,
|
|
405
|
+
fontWeight: CHEVRON_FONT_WEIGHT,
|
|
406
|
+
transform: [{ rotate: expanded ? EXPANDED_ROTATION : COLLAPSED_ROTATION }]
|
|
407
|
+
};
|
|
408
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
409
|
+
reactNative.Text,
|
|
410
|
+
{
|
|
411
|
+
accessibilityElementsHidden: true,
|
|
412
|
+
importantForAccessibility: "no",
|
|
413
|
+
style: [style, rotateTransitionStyle(reducedMotion)],
|
|
414
|
+
children: CHEVRON_GLYPH
|
|
415
|
+
}
|
|
416
|
+
);
|
|
417
|
+
};
|
|
307
418
|
function ariaCurrentProps(isActive) {
|
|
308
419
|
return isActive ? { "aria-current": "page" } : {};
|
|
309
420
|
}
|
|
310
421
|
function ariaExpandedProps(expanded) {
|
|
311
422
|
return { "aria-expanded": expanded };
|
|
312
423
|
}
|
|
424
|
+
function hoverHandlerProps(onIn, onOut) {
|
|
425
|
+
return IS_WEB ? { onHoverIn: onIn, onHoverOut: onOut } : {};
|
|
426
|
+
}
|
|
313
427
|
function hasActiveDescendant(item, pathname) {
|
|
314
428
|
if (isRouteActive(pathname, item.route)) return true;
|
|
315
429
|
return (item.children ?? []).some((child) => hasActiveDescendant(child, pathname));
|
|
316
430
|
}
|
|
431
|
+
function TintOverlay({ opacity, color }) {
|
|
432
|
+
const reducedMotion = useReducedMotion();
|
|
433
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [expandableStyles.tintOverlay, { backgroundColor: color, opacity }, tintTransitionStyle(reducedMotion)] });
|
|
434
|
+
}
|
|
317
435
|
var NavExpandableItem = ({
|
|
318
436
|
item,
|
|
319
437
|
pathname,
|
|
@@ -324,27 +442,27 @@ var NavExpandableItem = ({
|
|
|
324
442
|
renderChevron,
|
|
325
443
|
depth = 0
|
|
326
444
|
}) => {
|
|
327
|
-
const [expanded, setExpanded] =
|
|
328
|
-
const [focused, setFocused] =
|
|
445
|
+
const [expanded, setExpanded] = React3.useState(() => hasActiveDescendant(item, pathname));
|
|
446
|
+
const [focused, setFocused] = React3.useState(false);
|
|
447
|
+
const [hovered, setHovered] = React3.useState(false);
|
|
329
448
|
const { theme } = uiFeedback.useUi();
|
|
330
449
|
const colors = theme.colors;
|
|
331
450
|
const primaryColor = theme.palette.primary["500"];
|
|
332
|
-
const toggle =
|
|
451
|
+
const toggle = React3.useCallback(() => setExpanded((v) => !v), []);
|
|
452
|
+
const onHoverIn = React3.useCallback(() => setHovered(true), []);
|
|
453
|
+
const onHoverOut = React3.useCallback(() => setHovered(false), []);
|
|
333
454
|
const indent = depth * BASE_INDENT;
|
|
334
455
|
const hasChildren = Array.isArray(item.children) && item.children.length > 0;
|
|
335
456
|
const isActive = isRouteActive(pathname, item.route);
|
|
336
457
|
const isSectionHeader = hasChildren && depth === 0;
|
|
337
|
-
const
|
|
338
|
-
() => ({
|
|
339
|
-
|
|
340
|
-
borderRadius: ACTIVE_BORDER_RADIUS,
|
|
341
|
-
borderLeftWidth: ACTIVE_ACCENT_WIDTH,
|
|
342
|
-
borderLeftColor: primaryColor
|
|
343
|
-
}),
|
|
344
|
-
[colors.border, primaryColor]
|
|
458
|
+
const activeAccentStyle = React3.useMemo(
|
|
459
|
+
() => ({ borderLeftWidth: ACTIVE_ACCENT_WIDTH, borderLeftColor: primaryColor }),
|
|
460
|
+
[primaryColor]
|
|
345
461
|
);
|
|
346
|
-
const paddingStyle =
|
|
347
|
-
const headerPaddingStyle =
|
|
462
|
+
const paddingStyle = React3.useMemo(() => ({ paddingLeft: indent + BASE_INDENT }), [indent]);
|
|
463
|
+
const headerPaddingStyle = React3.useMemo(() => ({ paddingLeft: indent }), [indent]);
|
|
464
|
+
const leafTintOpacity = isActive ? ACTIVE_TINT_OPACITY : hovered ? HOVER_TINT_OPACITY : 0;
|
|
465
|
+
const headerTintOpacity = hovered ? HOVER_TINT_OPACITY : 0;
|
|
348
466
|
if (!hasChildren)
|
|
349
467
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
350
468
|
reactNative.TouchableOpacity,
|
|
@@ -356,15 +474,17 @@ var NavExpandableItem = ({
|
|
|
356
474
|
style: [
|
|
357
475
|
expandableStyles.childItem,
|
|
358
476
|
paddingStyle,
|
|
359
|
-
isActive ?
|
|
477
|
+
isActive ? activeAccentStyle : void 0,
|
|
360
478
|
focusRingStyle(focused, primaryColor)
|
|
361
479
|
],
|
|
362
480
|
testID: item.testID ?? item.key,
|
|
363
481
|
onBlur: () => setFocused(false),
|
|
364
482
|
onFocus: () => setFocused(true),
|
|
365
483
|
onPress: () => onNavigate(item.route),
|
|
484
|
+
...hoverHandlerProps(onHoverIn, onHoverOut),
|
|
366
485
|
...ariaCurrentProps(isActive),
|
|
367
486
|
children: [
|
|
487
|
+
/* @__PURE__ */ jsxRuntime.jsx(TintOverlay, { color: primaryColor, opacity: leafTintOpacity }),
|
|
368
488
|
typeof item.renderIcon === "function" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: expandableStyles.iconWrapper, children: item.renderIcon(colors.textSecondary, NAV_ICON_SIZE) }) : null,
|
|
369
489
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
370
490
|
reactNative.Text,
|
|
@@ -379,6 +499,7 @@ var NavExpandableItem = ({
|
|
|
379
499
|
]
|
|
380
500
|
}
|
|
381
501
|
);
|
|
502
|
+
const chevronColor = colors.textSecondary;
|
|
382
503
|
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { children: [
|
|
383
504
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
384
505
|
reactNative.TouchableOpacity,
|
|
@@ -397,8 +518,10 @@ var NavExpandableItem = ({
|
|
|
397
518
|
onBlur: () => setFocused(false),
|
|
398
519
|
onFocus: () => setFocused(true),
|
|
399
520
|
onPress: toggle,
|
|
521
|
+
...hoverHandlerProps(onHoverIn, onHoverOut),
|
|
400
522
|
...ariaExpandedProps(expanded),
|
|
401
523
|
children: [
|
|
524
|
+
/* @__PURE__ */ jsxRuntime.jsx(TintOverlay, { color: primaryColor, opacity: headerTintOpacity }),
|
|
402
525
|
typeof item.renderIcon === "function" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: expandableStyles.iconWrapper, children: item.renderIcon(isSectionHeader ? colors.textSecondary : colors.text, NAV_ICON_SIZE) }) : null,
|
|
403
526
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
404
527
|
reactNative.Text,
|
|
@@ -410,7 +533,7 @@ var NavExpandableItem = ({
|
|
|
410
533
|
children: item.label
|
|
411
534
|
}
|
|
412
535
|
),
|
|
413
|
-
|
|
536
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: expandableStyles.chevron, children: typeof renderChevron === "function" ? renderChevron(expanded, chevronColor, CHEVRON_ICON_SIZE) : /* @__PURE__ */ jsxRuntime.jsx(SidebarChevron, { color: chevronColor, expanded, size: CHEVRON_ICON_SIZE }) })
|
|
414
537
|
]
|
|
415
538
|
}
|
|
416
539
|
),
|
|
@@ -430,13 +553,93 @@ var NavExpandableItem = ({
|
|
|
430
553
|
)) }) })
|
|
431
554
|
] });
|
|
432
555
|
};
|
|
556
|
+
var FIELD_MIN_HEIGHT = 38;
|
|
557
|
+
var CLEAR_GLYPH = "\u2715";
|
|
558
|
+
var CLEAR_MIN_TARGET = 28;
|
|
559
|
+
var styles = reactNative.StyleSheet.create({
|
|
560
|
+
wrap: {
|
|
561
|
+
flexDirection: "row",
|
|
562
|
+
alignItems: "center",
|
|
563
|
+
borderWidth: 1,
|
|
564
|
+
borderRadius: 8,
|
|
565
|
+
paddingLeft: 12,
|
|
566
|
+
paddingRight: 6,
|
|
567
|
+
marginBottom: 12
|
|
568
|
+
},
|
|
569
|
+
input: {
|
|
570
|
+
flex: 1,
|
|
571
|
+
fontSize: 14,
|
|
572
|
+
paddingVertical: 8,
|
|
573
|
+
minHeight: FIELD_MIN_HEIGHT
|
|
574
|
+
},
|
|
575
|
+
clear: {
|
|
576
|
+
minWidth: CLEAR_MIN_TARGET,
|
|
577
|
+
minHeight: CLEAR_MIN_TARGET,
|
|
578
|
+
alignItems: "center",
|
|
579
|
+
justifyContent: "center",
|
|
580
|
+
borderRadius: 6
|
|
581
|
+
},
|
|
582
|
+
clearGlyph: { fontSize: 13, fontWeight: "700" }
|
|
583
|
+
});
|
|
584
|
+
var SidebarSearch = ({
|
|
585
|
+
value,
|
|
586
|
+
onChangeText,
|
|
587
|
+
onClear,
|
|
588
|
+
labels,
|
|
589
|
+
testID
|
|
590
|
+
}) => {
|
|
591
|
+
const { theme } = uiFeedback.useUi();
|
|
592
|
+
const colors = theme.colors;
|
|
593
|
+
const primary = theme.palette.primary["500"];
|
|
594
|
+
const [focused, setFocused] = React3.useState(false);
|
|
595
|
+
const hasQuery = value.length > 0;
|
|
596
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
597
|
+
reactNative.View,
|
|
598
|
+
{
|
|
599
|
+
style: [
|
|
600
|
+
styles.wrap,
|
|
601
|
+
{ backgroundColor: colors.surface, borderColor: focused ? primary : colors.border },
|
|
602
|
+
focusRingStyle(focused, primary)
|
|
603
|
+
],
|
|
604
|
+
children: [
|
|
605
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
606
|
+
reactNative.TextInput,
|
|
607
|
+
{
|
|
608
|
+
accessibilityHint: labels.hint,
|
|
609
|
+
accessibilityLabel: labels.placeholder,
|
|
610
|
+
placeholder: labels.placeholder,
|
|
611
|
+
placeholderTextColor: colors.textSecondary,
|
|
612
|
+
style: [styles.input, { color: colors.text }],
|
|
613
|
+
testID,
|
|
614
|
+
value,
|
|
615
|
+
onBlur: () => setFocused(false),
|
|
616
|
+
onChangeText,
|
|
617
|
+
onFocus: () => setFocused(true)
|
|
618
|
+
}
|
|
619
|
+
),
|
|
620
|
+
hasQuery ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
621
|
+
reactNative.Pressable,
|
|
622
|
+
{
|
|
623
|
+
accessibilityHint: labels.clearHint,
|
|
624
|
+
accessibilityLabel: labels.clearLabel,
|
|
625
|
+
accessibilityRole: "button",
|
|
626
|
+
style: styles.clear,
|
|
627
|
+
testID: `${testID}-clear`,
|
|
628
|
+
onPress: onClear,
|
|
629
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles.clearGlyph, { color: colors.textSecondary }], children: CLEAR_GLYPH })
|
|
630
|
+
}
|
|
631
|
+
) : null
|
|
632
|
+
]
|
|
633
|
+
}
|
|
634
|
+
);
|
|
635
|
+
};
|
|
433
636
|
function isBareText(node) {
|
|
434
637
|
return typeof node === "string" || typeof node === "number";
|
|
435
638
|
}
|
|
436
639
|
function renderTextSlot(node, style) {
|
|
437
640
|
if (node === void 0 || node === null) return node;
|
|
438
641
|
if (isBareText(node)) return /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style, children: node });
|
|
439
|
-
return
|
|
642
|
+
return React3__default.default.Children.map(
|
|
440
643
|
node,
|
|
441
644
|
(child) => isBareText(child) ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style, children: child }) : child
|
|
442
645
|
);
|
|
@@ -451,12 +654,30 @@ var Sidebar = ({
|
|
|
451
654
|
expandHint = "",
|
|
452
655
|
collapseHint = "",
|
|
453
656
|
renderChevron,
|
|
657
|
+
enableInlineSearch = false,
|
|
658
|
+
search,
|
|
659
|
+
searchQuery,
|
|
660
|
+
onSearchChange,
|
|
454
661
|
header,
|
|
455
662
|
footer,
|
|
456
663
|
containerStyle
|
|
457
664
|
}) => {
|
|
458
665
|
const { theme } = uiFeedback.useUi();
|
|
459
666
|
const colors = theme.colors;
|
|
667
|
+
const [internalQuery, setInternalQuery] = React3.useState("");
|
|
668
|
+
const controlled = searchQuery !== void 0;
|
|
669
|
+
const query = controlled ? searchQuery : internalQuery;
|
|
670
|
+
const setQuery = React3.useCallback(
|
|
671
|
+
(next) => {
|
|
672
|
+
if (!controlled) setInternalQuery(next);
|
|
673
|
+
onSearchChange?.(next);
|
|
674
|
+
},
|
|
675
|
+
[controlled, onSearchChange]
|
|
676
|
+
);
|
|
677
|
+
const clearQuery = React3.useCallback(() => setQuery(""), [setQuery]);
|
|
678
|
+
const searchOn = enableInlineSearch && search !== void 0;
|
|
679
|
+
const visibleItems = searchOn ? filterNavItems(items, query) : items;
|
|
680
|
+
const showEmpty = searchOn && isFilterActive(query) && visibleItems.length === 0;
|
|
460
681
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
461
682
|
reactNative.View,
|
|
462
683
|
{
|
|
@@ -470,8 +691,18 @@ var Sidebar = ({
|
|
|
470
691
|
],
|
|
471
692
|
children: [
|
|
472
693
|
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { accessibilityRole: "header", style: [navStyles.sidebarTitle, { color: colors.text }], children: title }),
|
|
694
|
+
searchOn && search !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
695
|
+
SidebarSearch,
|
|
696
|
+
{
|
|
697
|
+
labels: search,
|
|
698
|
+
testID: "sidebar-search",
|
|
699
|
+
value: query,
|
|
700
|
+
onChangeText: setQuery,
|
|
701
|
+
onClear: clearQuery
|
|
702
|
+
}
|
|
703
|
+
) : null,
|
|
473
704
|
renderTextSlot(header, { color: colors.text }),
|
|
474
|
-
|
|
705
|
+
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(
|
|
475
706
|
NavExpandableItem,
|
|
476
707
|
{
|
|
477
708
|
collapseHint,
|
|
@@ -491,6 +722,12 @@ var Sidebar = ({
|
|
|
491
722
|
);
|
|
492
723
|
};
|
|
493
724
|
|
|
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
|
+
|
|
494
731
|
// src/constants.ts
|
|
495
732
|
var NAV_TEST_IDS = {
|
|
496
733
|
/** displayName line in the rich account header (tappable when `onAccount` set). */
|
|
@@ -538,7 +775,7 @@ var FocusableTouchable = ({
|
|
|
538
775
|
testID,
|
|
539
776
|
children
|
|
540
777
|
}) => {
|
|
541
|
-
const [focused, setFocused] =
|
|
778
|
+
const [focused, setFocused] = React3.useState(false);
|
|
542
779
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
543
780
|
reactNative.Pressable,
|
|
544
781
|
{
|
|
@@ -691,8 +928,8 @@ var NavBarLink = ({
|
|
|
691
928
|
navigateHint,
|
|
692
929
|
onPress
|
|
693
930
|
}) => {
|
|
694
|
-
const [hovered, setHovered] =
|
|
695
|
-
const [focused, setFocused] =
|
|
931
|
+
const [hovered, setHovered] = React3.useState(false);
|
|
932
|
+
const [focused, setFocused] = React3.useState(false);
|
|
696
933
|
const isHovered = hovered && !isActive;
|
|
697
934
|
const textColor = isActive ? TEXT_ON_PRIMARY2 : isHovered ? colors.hoverText : colors.rest;
|
|
698
935
|
const pillStyle = isActive ? { backgroundColor: colors.activeBg } : isHovered ? { backgroundColor: colors.hoverBg } : void 0;
|
|
@@ -736,12 +973,12 @@ var NavOverflowMenu = ({
|
|
|
736
973
|
testID,
|
|
737
974
|
variant
|
|
738
975
|
}) => {
|
|
739
|
-
const options =
|
|
740
|
-
const activeRoute =
|
|
976
|
+
const options = React3.useMemo(() => items.map((item) => ({ label: item.label, value: item.route })), [items]);
|
|
977
|
+
const activeRoute = React3.useMemo(
|
|
741
978
|
() => items.find((item) => isRouteActive(pathname, item.route))?.route ?? NO_ACTIVE_ROUTE,
|
|
742
979
|
[items, pathname]
|
|
743
980
|
);
|
|
744
|
-
const optionTestID =
|
|
981
|
+
const optionTestID = React3.useMemo(() => {
|
|
745
982
|
const byRoute = new Map(items.map((item) => [item.route, item.testID ?? item.key]));
|
|
746
983
|
return (route) => byRoute.get(route) ?? `${testID}-option-${route}`;
|
|
747
984
|
}, [items, testID]);
|
|
@@ -798,13 +1035,13 @@ function resizeWidthBuffer(previous, count) {
|
|
|
798
1035
|
return next;
|
|
799
1036
|
}
|
|
800
1037
|
function useNavOverflow(itemCount, gap) {
|
|
801
|
-
const [availableWidth, setAvailableWidthState] =
|
|
802
|
-
const [moreWidth, setMoreWidthState] =
|
|
803
|
-
const [itemWidths, setItemWidths] =
|
|
804
|
-
|
|
1038
|
+
const [availableWidth, setAvailableWidthState] = React3.useState(0);
|
|
1039
|
+
const [moreWidth, setMoreWidthState] = React3.useState(0);
|
|
1040
|
+
const [itemWidths, setItemWidths] = React3.useState(() => new Array(itemCount).fill(0));
|
|
1041
|
+
React3.useEffect(() => {
|
|
805
1042
|
setItemWidths((previous) => previous.length === itemCount ? previous : resizeWidthBuffer(previous, itemCount));
|
|
806
1043
|
}, [itemCount]);
|
|
807
|
-
const setItemWidth =
|
|
1044
|
+
const setItemWidth = React3.useCallback((index, width) => {
|
|
808
1045
|
setItemWidths((previous) => {
|
|
809
1046
|
if (index < 0 || index >= previous.length || previous[index] === width) return previous;
|
|
810
1047
|
const next = previous.slice();
|
|
@@ -812,38 +1049,20 @@ function useNavOverflow(itemCount, gap) {
|
|
|
812
1049
|
return next;
|
|
813
1050
|
});
|
|
814
1051
|
}, []);
|
|
815
|
-
const setAvailableWidth =
|
|
1052
|
+
const setAvailableWidth = React3.useCallback(
|
|
816
1053
|
(width) => setAvailableWidthState((previous) => previous === width ? previous : width),
|
|
817
1054
|
[]
|
|
818
1055
|
);
|
|
819
|
-
const setMoreWidth =
|
|
1056
|
+
const setMoreWidth = React3.useCallback(
|
|
820
1057
|
(width) => setMoreWidthState((previous) => previous === width ? previous : width),
|
|
821
1058
|
[]
|
|
822
1059
|
);
|
|
823
|
-
const visibleCount =
|
|
1060
|
+
const visibleCount = React3.useMemo(
|
|
824
1061
|
() => computeVisibleCount({ availableWidth, itemWidths, moreWidth, gap }),
|
|
825
1062
|
[availableWidth, itemWidths, moreWidth, gap]
|
|
826
1063
|
);
|
|
827
1064
|
return { visibleCount, setAvailableWidth, setItemWidth, setMoreWidth };
|
|
828
1065
|
}
|
|
829
|
-
var REDUCED_MOTION_QUERY = "(prefers-reduced-motion: reduce)";
|
|
830
|
-
function getReducedMotionQuery() {
|
|
831
|
-
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return void 0;
|
|
832
|
-
return window.matchMedia(REDUCED_MOTION_QUERY);
|
|
833
|
-
}
|
|
834
|
-
function useReducedMotion() {
|
|
835
|
-
const [reduced, setReduced] = React2.useState(() => getReducedMotionQuery()?.matches ?? false);
|
|
836
|
-
React2.useEffect(() => {
|
|
837
|
-
const mql = getReducedMotionQuery();
|
|
838
|
-
if (mql === void 0 || mql.addEventListener === void 0) return void 0;
|
|
839
|
-
const onChange = () => setReduced(mql.matches);
|
|
840
|
-
mql.addEventListener("change", onChange);
|
|
841
|
-
return () => {
|
|
842
|
-
mql.removeEventListener?.("change", onChange);
|
|
843
|
-
};
|
|
844
|
-
}, []);
|
|
845
|
-
return reduced;
|
|
846
|
-
}
|
|
847
1066
|
var LINKS_REGION_ID = "navbar-links-region";
|
|
848
1067
|
var DEFAULT_COLLAPSE_BELOW = 760;
|
|
849
1068
|
var MENU_GLYPH = "\u2630";
|
|
@@ -872,24 +1091,24 @@ var NavBarInner = ({
|
|
|
872
1091
|
const primaryColor = theme.palette.primary["500"];
|
|
873
1092
|
const { width } = reactNative.useWindowDimensions();
|
|
874
1093
|
const reducedMotion = useReducedMotion();
|
|
875
|
-
const [open, setOpen] =
|
|
876
|
-
const [toggleFocused, setToggleFocused] =
|
|
1094
|
+
const [open, setOpen] = React3.useState(false);
|
|
1095
|
+
const [toggleFocused, setToggleFocused] = React3.useState(false);
|
|
877
1096
|
const { visibleCount, setAvailableWidth, setItemWidth, setMoreWidth } = useNavOverflow(items.length, NAV_LINK_GAP);
|
|
878
1097
|
const collapsed = width < collapseBelow;
|
|
879
1098
|
const showLinks = !collapsed || open;
|
|
880
|
-
const innerCapStyle =
|
|
1099
|
+
const innerCapStyle = React3.useMemo(
|
|
881
1100
|
() => contentMaxWidth === void 0 ? null : { maxWidth: contentMaxWidth, width: "100%", alignSelf: "center" },
|
|
882
1101
|
[contentMaxWidth]
|
|
883
1102
|
);
|
|
884
|
-
const toggleMenu =
|
|
885
|
-
const handlePress =
|
|
1103
|
+
const toggleMenu = React3.useCallback(() => setOpen((v) => !v), []);
|
|
1104
|
+
const handlePress = React3.useCallback(
|
|
886
1105
|
(route) => {
|
|
887
1106
|
setOpen(false);
|
|
888
1107
|
onNavigate(route);
|
|
889
1108
|
},
|
|
890
1109
|
[onNavigate]
|
|
891
1110
|
);
|
|
892
|
-
const linkColors =
|
|
1111
|
+
const linkColors = React3.useMemo(
|
|
893
1112
|
() => ({
|
|
894
1113
|
rest: colors.textSecondary,
|
|
895
1114
|
hoverText: colors.text,
|
|
@@ -944,7 +1163,7 @@ var NavBarInner = ({
|
|
|
944
1163
|
}
|
|
945
1164
|
);
|
|
946
1165
|
if (collapsed) {
|
|
947
|
-
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(
|
|
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(React3__default.default.Fragment, { children: renderLink(item) }, item.key)) });
|
|
948
1167
|
}
|
|
949
1168
|
const visibleItems = items.slice(0, visibleCount);
|
|
950
1169
|
const overflowItems = items.slice(visibleCount);
|
|
@@ -1010,7 +1229,7 @@ var CARD_BORDER_WIDTH = 1;
|
|
|
1010
1229
|
var CARD_TITLE_FONT_SIZE = 16;
|
|
1011
1230
|
var CARD_MESSAGE_FONT_SIZE = 14;
|
|
1012
1231
|
var CARD_TITLE_MARGIN_BOTTOM = 8;
|
|
1013
|
-
var
|
|
1232
|
+
var styles2 = reactNative.StyleSheet.create({
|
|
1014
1233
|
centerFill: { flex: 1, justifyContent: "center", alignItems: "center" },
|
|
1015
1234
|
card: {
|
|
1016
1235
|
padding: CARD_PADDING,
|
|
@@ -1027,9 +1246,9 @@ function MessageCard({
|
|
|
1027
1246
|
}) {
|
|
1028
1247
|
const { theme } = uiFeedback.useUi();
|
|
1029
1248
|
const colors = theme.colors;
|
|
1030
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [
|
|
1031
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [
|
|
1032
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [
|
|
1249
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles2.card, { backgroundColor: colors.surface, borderColor: accentColor }], testID, children: [
|
|
1250
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles2.cardTitle, { color: accentColor }], children: message.titleText }),
|
|
1251
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles2.cardMessage, { color: colors.textSecondary }], children: message.messageText })
|
|
1033
1252
|
] });
|
|
1034
1253
|
}
|
|
1035
1254
|
function useContentBody(state, children, testID) {
|
|
@@ -1041,7 +1260,7 @@ function useContentBody(state, children, testID) {
|
|
|
1041
1260
|
if (state?.error)
|
|
1042
1261
|
return /* @__PURE__ */ jsxRuntime.jsx(MessageCard, { accentColor: errorColor, message: state.error, testID: `${testID}${APP_SHELL_SUFFIX.error}` });
|
|
1043
1262
|
if (state?.loading === true)
|
|
1044
|
-
return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style:
|
|
1263
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles2.centerFill, testID: `${testID}${APP_SHELL_SUFFIX.loading}`, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: primary, size: "large" }) });
|
|
1045
1264
|
return children;
|
|
1046
1265
|
}
|
|
1047
1266
|
var SCRIM_COLOR = "rgba(0, 0, 0, 0.5)";
|
|
@@ -1065,7 +1284,7 @@ var DEFAULT_DRAWER_LABELS = {
|
|
|
1065
1284
|
closeLabel: "Close menu",
|
|
1066
1285
|
closeHint: "Close the navigation menu"
|
|
1067
1286
|
};
|
|
1068
|
-
var
|
|
1287
|
+
var styles3 = reactNative.StyleSheet.create({
|
|
1069
1288
|
overlay: { ...reactNative.StyleSheet.absoluteFillObject, zIndex: DRAWER_Z_INDEX },
|
|
1070
1289
|
// The scrim's tap-to-close hit area is anchored to the RIGHT of the panel
|
|
1071
1290
|
// (`left: DRAWER_WIDTH`), so it NEVER overlaps the panel: nav-item taps always
|
|
@@ -1100,10 +1319,10 @@ var MenuToggle = ({ label, hint, onOpen, testID }) => {
|
|
|
1100
1319
|
accessibilityHint: hint,
|
|
1101
1320
|
accessibilityLabel: label,
|
|
1102
1321
|
ringColor: theme.palette.primary["500"],
|
|
1103
|
-
style:
|
|
1322
|
+
style: styles3.menuToggle,
|
|
1104
1323
|
testID,
|
|
1105
1324
|
onPress: onOpen,
|
|
1106
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [
|
|
1325
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles3.menuToggleGlyph, { color: theme.colors.text }], children: MENU_GLYPH2 })
|
|
1107
1326
|
}
|
|
1108
1327
|
);
|
|
1109
1328
|
};
|
|
@@ -1115,8 +1334,8 @@ var MobileDrawer = ({
|
|
|
1115
1334
|
scrimTestID
|
|
1116
1335
|
}) => {
|
|
1117
1336
|
const { theme } = uiFeedback.useUi();
|
|
1118
|
-
const panelRef =
|
|
1119
|
-
|
|
1337
|
+
const panelRef = React3.useRef(null);
|
|
1338
|
+
React3.useEffect(() => {
|
|
1120
1339
|
const node = panelRef.current;
|
|
1121
1340
|
if (node === null || typeof node.addEventListener !== "function") return void 0;
|
|
1122
1341
|
const handleClick = (event) => {
|
|
@@ -1129,14 +1348,14 @@ var MobileDrawer = ({
|
|
|
1129
1348
|
node.addEventListener("click", handleClick);
|
|
1130
1349
|
return () => node.removeEventListener("click", handleClick);
|
|
1131
1350
|
}, [onClose]);
|
|
1132
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
1351
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.overlay, children: [
|
|
1133
1352
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1134
1353
|
reactNative.Pressable,
|
|
1135
1354
|
{
|
|
1136
1355
|
accessibilityHint: labels.closeHint,
|
|
1137
1356
|
accessibilityLabel: labels.closeLabel,
|
|
1138
1357
|
accessibilityRole: "button",
|
|
1139
|
-
style:
|
|
1358
|
+
style: styles3.scrim,
|
|
1140
1359
|
testID: scrimTestID,
|
|
1141
1360
|
onPress: onClose
|
|
1142
1361
|
}
|
|
@@ -1147,7 +1366,7 @@ var MobileDrawer = ({
|
|
|
1147
1366
|
ref: panelRef,
|
|
1148
1367
|
"aria-modal": true,
|
|
1149
1368
|
role: "dialog",
|
|
1150
|
-
style: [
|
|
1369
|
+
style: [styles3.panel, { backgroundColor: theme.colors.surface }],
|
|
1151
1370
|
testID: drawerTestID,
|
|
1152
1371
|
children: renderTextSlot(sidebar, { color: theme.colors.text })
|
|
1153
1372
|
}
|
|
@@ -1178,7 +1397,7 @@ function useContentMaxWidth(width) {
|
|
|
1178
1397
|
return resolveContentMaxWidth(width, viewport);
|
|
1179
1398
|
}
|
|
1180
1399
|
var DEFAULT_CONTENT_PADDING = 24;
|
|
1181
|
-
var
|
|
1400
|
+
var styles4 = reactNative.StyleSheet.create({
|
|
1182
1401
|
root: { flex: 1 },
|
|
1183
1402
|
centerFill: { flex: 1, justifyContent: "center", alignItems: "center" },
|
|
1184
1403
|
scroll: { flex: 1 },
|
|
@@ -1223,32 +1442,32 @@ var AppShell = ({
|
|
|
1223
1442
|
range: railRange
|
|
1224
1443
|
});
|
|
1225
1444
|
const useDrawer = railMode === "drawer";
|
|
1226
|
-
const [drawerOpen, setDrawerOpen] =
|
|
1227
|
-
const openDrawer =
|
|
1228
|
-
const closeDrawer =
|
|
1229
|
-
|
|
1445
|
+
const [drawerOpen, setDrawerOpen] = React3.useState(false);
|
|
1446
|
+
const openDrawer = React3.useCallback(() => setDrawerOpen(true), []);
|
|
1447
|
+
const closeDrawer = React3.useCallback(() => setDrawerOpen(false), []);
|
|
1448
|
+
React3.useEffect(() => {
|
|
1230
1449
|
if (!useDrawer && drawerOpen) setDrawerOpen(false);
|
|
1231
1450
|
}, [useDrawer, drawerOpen]);
|
|
1232
1451
|
const drawerLabels = { ...DEFAULT_DRAWER_LABELS, ...mobileMenu };
|
|
1233
1452
|
const isUnauthenticated = gate !== void 0 && !gate.pending && !gate.authenticated;
|
|
1234
|
-
|
|
1453
|
+
React3.useEffect(() => {
|
|
1235
1454
|
if (isUnauthenticated && gate !== void 0) gate.onRedirect();
|
|
1236
1455
|
}, [isUnauthenticated, gate]);
|
|
1237
1456
|
if (gate?.pending === true)
|
|
1238
|
-
return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [
|
|
1457
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles4.root, styles4.centerFill, { backgroundColor: theme.colors.background }], testID: `${testID}${APP_SHELL_SUFFIX.pending}`, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: primary, size: "large" }) });
|
|
1239
1458
|
if (isUnauthenticated) return null;
|
|
1240
|
-
const columnStyle = maxWidth === "full" ?
|
|
1241
|
-
const navInnerStyle = chromeAlignment === "content" && maxWidth !== "full" ? [
|
|
1459
|
+
const columnStyle = maxWidth === "full" ? styles4.columnFull : [styles4.columnCapped, { maxWidth }];
|
|
1460
|
+
const navInnerStyle = chromeAlignment === "content" && maxWidth !== "full" ? [styles4.chromeCapped, { maxWidth, paddingHorizontal: contentPadding }] : void 0;
|
|
1242
1461
|
const scroller = /* @__PURE__ */ jsxRuntime.jsx(
|
|
1243
1462
|
reactNative.ScrollView,
|
|
1244
1463
|
{
|
|
1245
|
-
contentContainerStyle: [
|
|
1246
|
-
style:
|
|
1464
|
+
contentContainerStyle: [styles4.scrollContent, { padding: contentPadding }],
|
|
1465
|
+
style: styles4.scroll,
|
|
1247
1466
|
testID: `${testID}${APP_SHELL_SUFFIX.content}`,
|
|
1248
1467
|
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: columnStyle, children: body })
|
|
1249
1468
|
}
|
|
1250
1469
|
);
|
|
1251
|
-
const headerRegion = useDrawer ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
1470
|
+
const headerRegion = useDrawer ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles4.headerRow, testID: `${testID}${APP_SHELL_SUFFIX.header}`, children: [
|
|
1252
1471
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1253
1472
|
MenuToggle,
|
|
1254
1473
|
{
|
|
@@ -1258,14 +1477,14 @@ var AppShell = ({
|
|
|
1258
1477
|
onOpen: openDrawer
|
|
1259
1478
|
}
|
|
1260
1479
|
),
|
|
1261
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style:
|
|
1480
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles4.headerFill, children: renderTextSlot(header, { color: theme.colors.text }) })
|
|
1262
1481
|
] }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { testID: `${testID}${APP_SHELL_SUFFIX.header}`, children: renderTextSlot(header, { color: theme.colors.text }) });
|
|
1263
1482
|
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;
|
|
1264
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [
|
|
1483
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles4.root, { backgroundColor: theme.colors.background }], testID, children: [
|
|
1265
1484
|
headerRegion,
|
|
1266
1485
|
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,
|
|
1267
1486
|
banner !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { testID: `${testID}${APP_SHELL_SUFFIX.banner}`, children: renderTextSlot(banner, { color: theme.colors.text }) }) : null,
|
|
1268
|
-
railRegion !== null ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
1487
|
+
railRegion !== null ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles4.bodyRow, children: [
|
|
1269
1488
|
railRegion,
|
|
1270
1489
|
scroller
|
|
1271
1490
|
] }) : scroller,
|
|
@@ -1483,7 +1702,7 @@ var DarkModeControl = ({
|
|
|
1483
1702
|
const primaryColor = theme.palette.primary["500"];
|
|
1484
1703
|
const currentIndex = options.findIndex((option) => option.value === value);
|
|
1485
1704
|
const current = currentIndex >= 0 ? options[currentIndex] : options[0];
|
|
1486
|
-
const advance =
|
|
1705
|
+
const advance = React3.useCallback(() => {
|
|
1487
1706
|
if (options.length === 0) return;
|
|
1488
1707
|
const from = currentIndex >= 0 ? currentIndex : 0;
|
|
1489
1708
|
const next = options[(from + 1) % options.length];
|
|
@@ -1559,7 +1778,7 @@ var KEY_DOWN = "ArrowDown";
|
|
|
1559
1778
|
var KEY_UP = "ArrowUp";
|
|
1560
1779
|
var KEY_ENTER = "Enter";
|
|
1561
1780
|
var KEY_ESCAPE = "Escape";
|
|
1562
|
-
var
|
|
1781
|
+
var styles5 = reactNative.StyleSheet.create({
|
|
1563
1782
|
overlay: { ...reactNative.StyleSheet.absoluteFillObject, zIndex: OVERLAY_Z_INDEX, alignItems: "center" },
|
|
1564
1783
|
scrim: { ...reactNative.StyleSheet.absoluteFillObject, backgroundColor: SCRIM_COLOR2 },
|
|
1565
1784
|
panel: {
|
|
@@ -1588,14 +1807,14 @@ var PaletteRow = ({ item, selected, onChoose }) => {
|
|
|
1588
1807
|
accessibilityLabel: item.label,
|
|
1589
1808
|
accessibilityRole: "button",
|
|
1590
1809
|
accessibilityState: { selected },
|
|
1591
|
-
style: [
|
|
1810
|
+
style: [styles5.row, selected ? { backgroundColor: colors.border } : void 0],
|
|
1592
1811
|
testID: item.testID ?? item.key,
|
|
1593
1812
|
onPress: () => onChoose(item),
|
|
1594
1813
|
children: [
|
|
1595
1814
|
typeof item.renderIcon === "function" ? item.renderIcon(colors.textSecondary, NAV_ICON_SIZE) : null,
|
|
1596
|
-
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
1597
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [
|
|
1598
|
-
item.hint ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [
|
|
1815
|
+
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles5.rowText, children: [
|
|
1816
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles5.rowLabel, { color: colors.text }], children: item.label }),
|
|
1817
|
+
item.hint ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles5.rowHint, { color: colors.textSecondary }], children: item.hint }) : null
|
|
1599
1818
|
] })
|
|
1600
1819
|
]
|
|
1601
1820
|
}
|
|
@@ -1604,27 +1823,27 @@ var PaletteRow = ({ item, selected, onChoose }) => {
|
|
|
1604
1823
|
var CommandPalette = ({ open, items, onClose, labels, testID }) => {
|
|
1605
1824
|
const { theme } = uiFeedback.useUi();
|
|
1606
1825
|
const colors = theme.colors;
|
|
1607
|
-
const [query, setQuery] =
|
|
1608
|
-
const [selected, setSelected] =
|
|
1609
|
-
const inputRef =
|
|
1610
|
-
const results =
|
|
1611
|
-
|
|
1826
|
+
const [query, setQuery] = React3.useState("");
|
|
1827
|
+
const [selected, setSelected] = React3.useState(0);
|
|
1828
|
+
const inputRef = React3.useRef(null);
|
|
1829
|
+
const results = React3.useMemo(() => filterCommands(items, query), [items, query]);
|
|
1830
|
+
React3.useEffect(() => {
|
|
1612
1831
|
if (!open) return;
|
|
1613
1832
|
setQuery("");
|
|
1614
1833
|
setSelected(0);
|
|
1615
1834
|
inputRef.current?.focus();
|
|
1616
1835
|
}, [open]);
|
|
1617
|
-
|
|
1836
|
+
React3.useEffect(() => {
|
|
1618
1837
|
setSelected((prev) => Math.min(prev, Math.max(0, results.length - 1)));
|
|
1619
1838
|
}, [results.length]);
|
|
1620
|
-
const choose =
|
|
1839
|
+
const choose = React3.useCallback(
|
|
1621
1840
|
(item) => {
|
|
1622
1841
|
item.onSelect();
|
|
1623
1842
|
onClose();
|
|
1624
1843
|
},
|
|
1625
1844
|
[onClose]
|
|
1626
1845
|
);
|
|
1627
|
-
const onKeyPress =
|
|
1846
|
+
const onKeyPress = React3.useCallback(
|
|
1628
1847
|
(event) => {
|
|
1629
1848
|
const key = event.nativeEvent.key;
|
|
1630
1849
|
if (key === KEY_DOWN) setSelected((i) => Math.min(i + 1, results.length - 1));
|
|
@@ -1635,14 +1854,14 @@ var CommandPalette = ({ open, items, onClose, labels, testID }) => {
|
|
|
1635
1854
|
[results, selected, choose, onClose]
|
|
1636
1855
|
);
|
|
1637
1856
|
if (!open) return null;
|
|
1638
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
1857
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles5.overlay, children: [
|
|
1639
1858
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1640
1859
|
reactNative.Pressable,
|
|
1641
1860
|
{
|
|
1642
1861
|
accessibilityHint: labels.closeHint,
|
|
1643
1862
|
accessibilityLabel: labels.closeLabel,
|
|
1644
1863
|
accessibilityRole: "button",
|
|
1645
|
-
style:
|
|
1864
|
+
style: styles5.scrim,
|
|
1646
1865
|
testID: `${testID ?? "command-palette"}-scrim`,
|
|
1647
1866
|
onPress: onClose
|
|
1648
1867
|
}
|
|
@@ -1653,7 +1872,7 @@ var CommandPalette = ({ open, items, onClose, labels, testID }) => {
|
|
|
1653
1872
|
"aria-modal": true,
|
|
1654
1873
|
"aria-label": labels.regionLabel,
|
|
1655
1874
|
role: "dialog",
|
|
1656
|
-
style: [
|
|
1875
|
+
style: [styles5.panel, { backgroundColor: colors.surface, borderColor: colors.border }],
|
|
1657
1876
|
testID: testID ?? "command-palette",
|
|
1658
1877
|
children: [
|
|
1659
1878
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1663,21 +1882,21 @@ var CommandPalette = ({ open, items, onClose, labels, testID }) => {
|
|
|
1663
1882
|
accessibilityLabel: labels.placeholder,
|
|
1664
1883
|
placeholder: labels.placeholder,
|
|
1665
1884
|
placeholderTextColor: colors.textSecondary,
|
|
1666
|
-
style: [
|
|
1885
|
+
style: [styles5.input, { color: colors.text, borderBottomColor: colors.border }],
|
|
1667
1886
|
testID: `${testID ?? "command-palette"}-input`,
|
|
1668
1887
|
value: query,
|
|
1669
1888
|
onChangeText: setQuery,
|
|
1670
1889
|
onKeyPress
|
|
1671
1890
|
}
|
|
1672
1891
|
),
|
|
1673
|
-
results.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [
|
|
1892
|
+
results.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles5.empty, { color: colors.textSecondary }], children: labels.emptyText }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.ScrollView, { keyboardShouldPersistTaps: "handled", style: styles5.list, children: results.map((item, index) => /* @__PURE__ */ jsxRuntime.jsx(PaletteRow, { item, selected: index === selected, onChoose: choose }, item.key)) })
|
|
1674
1893
|
]
|
|
1675
1894
|
}
|
|
1676
1895
|
)
|
|
1677
1896
|
] });
|
|
1678
1897
|
};
|
|
1679
1898
|
var MIN_TARGET = 36;
|
|
1680
|
-
var
|
|
1899
|
+
var styles6 = reactNative.StyleSheet.create({
|
|
1681
1900
|
trigger: {
|
|
1682
1901
|
flexDirection: "row",
|
|
1683
1902
|
alignItems: "center",
|
|
@@ -1702,7 +1921,7 @@ var CommandPaletteTrigger = ({
|
|
|
1702
1921
|
const { theme } = uiFeedback.useUi();
|
|
1703
1922
|
const colors = theme.colors;
|
|
1704
1923
|
const primary = theme.palette.primary["500"];
|
|
1705
|
-
const [focused, setFocused] =
|
|
1924
|
+
const [focused, setFocused] = React3__default.default.useState(false);
|
|
1706
1925
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1707
1926
|
reactNative.Pressable,
|
|
1708
1927
|
{
|
|
@@ -1710,7 +1929,7 @@ var CommandPaletteTrigger = ({
|
|
|
1710
1929
|
accessibilityLabel: label,
|
|
1711
1930
|
accessibilityRole: "button",
|
|
1712
1931
|
style: [
|
|
1713
|
-
|
|
1932
|
+
styles6.trigger,
|
|
1714
1933
|
{ backgroundColor: colors.surface, borderColor: colors.border },
|
|
1715
1934
|
focusRingStyle(focused, primary)
|
|
1716
1935
|
],
|
|
@@ -1719,15 +1938,15 @@ var CommandPaletteTrigger = ({
|
|
|
1719
1938
|
onFocus: () => setFocused(true),
|
|
1720
1939
|
onPress,
|
|
1721
1940
|
children: [
|
|
1722
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [
|
|
1723
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [
|
|
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 }) })
|
|
1724
1943
|
]
|
|
1725
1944
|
}
|
|
1726
1945
|
);
|
|
1727
1946
|
};
|
|
1728
1947
|
var LAUNCH_KEY = "k";
|
|
1729
1948
|
function useCommandPaletteHotkey(onOpen, enabled = true) {
|
|
1730
|
-
|
|
1949
|
+
React3.useEffect(() => {
|
|
1731
1950
|
if (!enabled || typeof document === "undefined") return void 0;
|
|
1732
1951
|
const handler = (event) => {
|
|
1733
1952
|
const isLauncher = event.key.toLowerCase() === LAUNCH_KEY && (event.metaKey || event.ctrlKey);
|
|
@@ -1751,6 +1970,7 @@ function accessibleNavItems(user, table, translate) {
|
|
|
1751
1970
|
}
|
|
1752
1971
|
|
|
1753
1972
|
exports.ACTIVE_BORDER_RADIUS = ACTIVE_BORDER_RADIUS;
|
|
1973
|
+
exports.ACTIVE_TINT_OPACITY = ACTIVE_TINT_OPACITY;
|
|
1754
1974
|
exports.APP_SHELL_SUFFIX = APP_SHELL_SUFFIX;
|
|
1755
1975
|
exports.AppShell = AppShell;
|
|
1756
1976
|
exports.BASE_INDENT = BASE_INDENT;
|
|
@@ -1759,9 +1979,12 @@ exports.CollapsedRail = CollapsedRail;
|
|
|
1759
1979
|
exports.CommandPalette = CommandPalette;
|
|
1760
1980
|
exports.CommandPaletteTrigger = CommandPaletteTrigger;
|
|
1761
1981
|
exports.DEFAULT_COLLAPSED_RAIL_MAX = DEFAULT_COLLAPSED_RAIL_MAX;
|
|
1982
|
+
exports.DEFAULT_SEARCH_BREAKPOINT = DEFAULT_SEARCH_BREAKPOINT;
|
|
1762
1983
|
exports.DarkModeControl = DarkModeControl;
|
|
1984
|
+
exports.HOVER_TINT_OPACITY = HOVER_TINT_OPACITY;
|
|
1763
1985
|
exports.NAV_ICON_SIZE = NAV_ICON_SIZE;
|
|
1764
1986
|
exports.NAV_LINK_GAP = NAV_LINK_GAP;
|
|
1987
|
+
exports.NAV_ROW_RADIUS = NAV_ROW_RADIUS;
|
|
1765
1988
|
exports.NAV_TEST_IDS = NAV_TEST_IDS;
|
|
1766
1989
|
exports.Nav = Nav;
|
|
1767
1990
|
exports.NavBar = NavBar;
|
|
@@ -1771,18 +1994,24 @@ exports.NavShell = NavShell;
|
|
|
1771
1994
|
exports.PillNav = PillNav;
|
|
1772
1995
|
exports.RAIL_FULL_BREAKPOINT = RAIL_FULL_BREAKPOINT;
|
|
1773
1996
|
exports.Sidebar = Sidebar;
|
|
1997
|
+
exports.SidebarChevron = SidebarChevron;
|
|
1998
|
+
exports.SidebarSearch = SidebarSearch;
|
|
1774
1999
|
exports.Topbar = Topbar;
|
|
1775
2000
|
exports.accessibleNavItems = accessibleNavItems;
|
|
1776
2001
|
exports.collapsedRailStyles = collapsedRailStyles;
|
|
1777
2002
|
exports.darkModeStyles = darkModeStyles;
|
|
1778
2003
|
exports.expandableStyles = expandableStyles;
|
|
1779
2004
|
exports.filterCommands = filterCommands;
|
|
2005
|
+
exports.filterNavItems = filterNavItems;
|
|
2006
|
+
exports.isFilterActive = isFilterActive;
|
|
1780
2007
|
exports.isRouteActive = isRouteActive;
|
|
1781
2008
|
exports.navStyles = navStyles;
|
|
1782
2009
|
exports.pillNavStyles = pillNavStyles;
|
|
1783
2010
|
exports.resolveContentMaxWidth = resolveContentMaxWidth;
|
|
1784
2011
|
exports.resolveRailMode = resolveRailMode;
|
|
2012
|
+
exports.resolveSearchAffordance = resolveSearchAffordance;
|
|
1785
2013
|
exports.roleRoutesToNavItems = roleRoutesToNavItems;
|
|
2014
|
+
exports.searchTokens = searchTokens;
|
|
1786
2015
|
exports.useCommandPaletteHotkey = useCommandPaletteHotkey;
|
|
1787
2016
|
exports.useContentMaxWidth = useContentMaxWidth;
|
|
1788
2017
|
//# sourceMappingURL=index.js.map
|