@dloizides/ui-nav 1.13.1 → 1.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +59 -0
- package/README.md +31 -0
- package/dist/index.d.mts +182 -3
- package/dist/index.d.ts +182 -3
- package/dist/index.js +348 -118
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +298 -78
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -1
package/dist/index.js
CHANGED
|
@@ -1,18 +1,51 @@
|
|
|
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
|
|
6
|
+
var uiMotion = require('@dloizides/ui-motion');
|
|
6
7
|
var jsxRuntime = require('react/jsx-runtime');
|
|
7
8
|
var uiLayout = require('@dloizides/ui-layout');
|
|
8
9
|
var authWeb = require('@dloizides/auth-web');
|
|
9
10
|
|
|
10
11
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
12
|
|
|
12
|
-
var
|
|
13
|
+
var React3__default = /*#__PURE__*/_interopDefault(React3);
|
|
13
14
|
|
|
14
15
|
// src/Sidebar.tsx
|
|
15
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
|
+
|
|
16
49
|
// src/isRouteActive.ts
|
|
17
50
|
function isRouteActive(pathname, route) {
|
|
18
51
|
if (route === "/") return pathname === "/";
|
|
@@ -20,6 +53,9 @@ function isRouteActive(pathname, route) {
|
|
|
20
53
|
}
|
|
21
54
|
var ACTIVE_BORDER_RADIUS = 4;
|
|
22
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;
|
|
23
59
|
var NAV_LINK_GAP = 4;
|
|
24
60
|
var navStyles = reactNative.StyleSheet.create({
|
|
25
61
|
// --- Sidebar ---
|
|
@@ -45,6 +81,12 @@ var navStyles = reactNative.StyleSheet.create({
|
|
|
45
81
|
sidebarSpacer: {
|
|
46
82
|
flex: 1
|
|
47
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
|
+
},
|
|
48
90
|
// --- Topbar ---
|
|
49
91
|
topbarContainer: {
|
|
50
92
|
height: 64,
|
|
@@ -245,8 +287,12 @@ var collapsedRailStyles = reactNative.StyleSheet.create({
|
|
|
245
287
|
var expandableStyles = reactNative.StyleSheet.create({
|
|
246
288
|
// Every leaf reserves the accent-bar gutter (a TRANSPARENT left border of the
|
|
247
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.
|
|
248
292
|
childItem: {
|
|
249
|
-
|
|
293
|
+
position: "relative",
|
|
294
|
+
overflow: "hidden",
|
|
295
|
+
borderRadius: NAV_ROW_RADIUS,
|
|
250
296
|
flexDirection: "row",
|
|
251
297
|
alignItems: "center",
|
|
252
298
|
paddingVertical: 9,
|
|
@@ -257,8 +303,24 @@ var expandableStyles = reactNative.StyleSheet.create({
|
|
|
257
303
|
childItemTextWithIcon: { fontSize: 14, marginLeft: 6 },
|
|
258
304
|
chevron: { marginLeft: "auto" },
|
|
259
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
|
+
},
|
|
260
320
|
header: {
|
|
261
|
-
|
|
321
|
+
position: "relative",
|
|
322
|
+
overflow: "hidden",
|
|
323
|
+
borderRadius: NAV_ROW_RADIUS,
|
|
262
324
|
flexDirection: "row",
|
|
263
325
|
alignItems: "center",
|
|
264
326
|
paddingVertical: 8
|
|
@@ -285,6 +347,7 @@ var IS_WEB = reactNative.Platform.OS === "web";
|
|
|
285
347
|
var FOCUS_RING_WIDTH = 2;
|
|
286
348
|
var FOCUS_RING_OFFSET = 2;
|
|
287
349
|
var HOVER_TRANSITION_MS = 150;
|
|
350
|
+
var TINT_TRANSITION_MS = 160;
|
|
288
351
|
function focusRingStyle(focused, ringColor) {
|
|
289
352
|
if (!IS_WEB || !focused) return void 0;
|
|
290
353
|
const ring = {
|
|
@@ -295,24 +358,80 @@ function focusRingStyle(focused, ringColor) {
|
|
|
295
358
|
};
|
|
296
359
|
return ring;
|
|
297
360
|
}
|
|
298
|
-
function
|
|
361
|
+
function webTransition(properties, durationMs, reducedMotion) {
|
|
299
362
|
if (!IS_WEB) return void 0;
|
|
300
363
|
const transition = {
|
|
301
|
-
transitionProperty:
|
|
302
|
-
transitionDuration: reducedMotion ? "0ms" : `${
|
|
364
|
+
transitionProperty: properties,
|
|
365
|
+
transitionDuration: reducedMotion ? "0ms" : `${durationMs}ms`
|
|
303
366
|
};
|
|
304
367
|
return transition;
|
|
305
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
|
+
};
|
|
306
418
|
function ariaCurrentProps(isActive) {
|
|
307
419
|
return isActive ? { "aria-current": "page" } : {};
|
|
308
420
|
}
|
|
309
421
|
function ariaExpandedProps(expanded) {
|
|
310
422
|
return { "aria-expanded": expanded };
|
|
311
423
|
}
|
|
424
|
+
function hoverHandlerProps(onIn, onOut) {
|
|
425
|
+
return IS_WEB ? { onHoverIn: onIn, onHoverOut: onOut } : {};
|
|
426
|
+
}
|
|
312
427
|
function hasActiveDescendant(item, pathname) {
|
|
313
428
|
if (isRouteActive(pathname, item.route)) return true;
|
|
314
429
|
return (item.children ?? []).some((child) => hasActiveDescendant(child, pathname));
|
|
315
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
|
+
}
|
|
316
435
|
var NavExpandableItem = ({
|
|
317
436
|
item,
|
|
318
437
|
pathname,
|
|
@@ -323,27 +442,27 @@ var NavExpandableItem = ({
|
|
|
323
442
|
renderChevron,
|
|
324
443
|
depth = 0
|
|
325
444
|
}) => {
|
|
326
|
-
const [expanded, setExpanded] =
|
|
327
|
-
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);
|
|
328
448
|
const { theme } = uiFeedback.useUi();
|
|
329
449
|
const colors = theme.colors;
|
|
330
450
|
const primaryColor = theme.palette.primary["500"];
|
|
331
|
-
const toggle =
|
|
451
|
+
const toggle = React3.useCallback(() => setExpanded((v) => !v), []);
|
|
452
|
+
const onHoverIn = React3.useCallback(() => setHovered(true), []);
|
|
453
|
+
const onHoverOut = React3.useCallback(() => setHovered(false), []);
|
|
332
454
|
const indent = depth * BASE_INDENT;
|
|
333
455
|
const hasChildren = Array.isArray(item.children) && item.children.length > 0;
|
|
334
456
|
const isActive = isRouteActive(pathname, item.route);
|
|
335
457
|
const isSectionHeader = hasChildren && depth === 0;
|
|
336
|
-
const
|
|
337
|
-
() => ({
|
|
338
|
-
|
|
339
|
-
borderRadius: ACTIVE_BORDER_RADIUS,
|
|
340
|
-
borderLeftWidth: ACTIVE_ACCENT_WIDTH,
|
|
341
|
-
borderLeftColor: primaryColor
|
|
342
|
-
}),
|
|
343
|
-
[colors.border, primaryColor]
|
|
458
|
+
const activeAccentStyle = React3.useMemo(
|
|
459
|
+
() => ({ borderLeftWidth: ACTIVE_ACCENT_WIDTH, borderLeftColor: primaryColor }),
|
|
460
|
+
[primaryColor]
|
|
344
461
|
);
|
|
345
|
-
const paddingStyle =
|
|
346
|
-
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;
|
|
347
466
|
if (!hasChildren)
|
|
348
467
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
349
468
|
reactNative.TouchableOpacity,
|
|
@@ -355,15 +474,17 @@ var NavExpandableItem = ({
|
|
|
355
474
|
style: [
|
|
356
475
|
expandableStyles.childItem,
|
|
357
476
|
paddingStyle,
|
|
358
|
-
isActive ?
|
|
477
|
+
isActive ? activeAccentStyle : void 0,
|
|
359
478
|
focusRingStyle(focused, primaryColor)
|
|
360
479
|
],
|
|
361
480
|
testID: item.testID ?? item.key,
|
|
362
481
|
onBlur: () => setFocused(false),
|
|
363
482
|
onFocus: () => setFocused(true),
|
|
364
483
|
onPress: () => onNavigate(item.route),
|
|
484
|
+
...hoverHandlerProps(onHoverIn, onHoverOut),
|
|
365
485
|
...ariaCurrentProps(isActive),
|
|
366
486
|
children: [
|
|
487
|
+
/* @__PURE__ */ jsxRuntime.jsx(TintOverlay, { color: primaryColor, opacity: leafTintOpacity }),
|
|
367
488
|
typeof item.renderIcon === "function" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: expandableStyles.iconWrapper, children: item.renderIcon(colors.textSecondary, NAV_ICON_SIZE) }) : null,
|
|
368
489
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
369
490
|
reactNative.Text,
|
|
@@ -378,6 +499,7 @@ var NavExpandableItem = ({
|
|
|
378
499
|
]
|
|
379
500
|
}
|
|
380
501
|
);
|
|
502
|
+
const chevronColor = colors.textSecondary;
|
|
381
503
|
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { children: [
|
|
382
504
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
383
505
|
reactNative.TouchableOpacity,
|
|
@@ -396,8 +518,10 @@ var NavExpandableItem = ({
|
|
|
396
518
|
onBlur: () => setFocused(false),
|
|
397
519
|
onFocus: () => setFocused(true),
|
|
398
520
|
onPress: toggle,
|
|
521
|
+
...hoverHandlerProps(onHoverIn, onHoverOut),
|
|
399
522
|
...ariaExpandedProps(expanded),
|
|
400
523
|
children: [
|
|
524
|
+
/* @__PURE__ */ jsxRuntime.jsx(TintOverlay, { color: primaryColor, opacity: headerTintOpacity }),
|
|
401
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,
|
|
402
526
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
403
527
|
reactNative.Text,
|
|
@@ -409,11 +533,11 @@ var NavExpandableItem = ({
|
|
|
409
533
|
children: item.label
|
|
410
534
|
}
|
|
411
535
|
),
|
|
412
|
-
|
|
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 }) })
|
|
413
537
|
]
|
|
414
538
|
}
|
|
415
539
|
),
|
|
416
|
-
expanded
|
|
540
|
+
/* @__PURE__ */ jsxRuntime.jsx(uiMotion.Collapse, { open: expanded, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: expandableStyles.childrenContainer, children: item.children?.map((child) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
417
541
|
NavExpandableItem,
|
|
418
542
|
{
|
|
419
543
|
collapseHint,
|
|
@@ -426,16 +550,96 @@ var NavExpandableItem = ({
|
|
|
426
550
|
onNavigate
|
|
427
551
|
},
|
|
428
552
|
child.key
|
|
429
|
-
)) })
|
|
553
|
+
)) }) })
|
|
430
554
|
] });
|
|
431
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
|
+
};
|
|
432
636
|
function isBareText(node) {
|
|
433
637
|
return typeof node === "string" || typeof node === "number";
|
|
434
638
|
}
|
|
435
639
|
function renderTextSlot(node, style) {
|
|
436
640
|
if (node === void 0 || node === null) return node;
|
|
437
641
|
if (isBareText(node)) return /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style, children: node });
|
|
438
|
-
return
|
|
642
|
+
return React3__default.default.Children.map(
|
|
439
643
|
node,
|
|
440
644
|
(child) => isBareText(child) ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style, children: child }) : child
|
|
441
645
|
);
|
|
@@ -450,12 +654,30 @@ var Sidebar = ({
|
|
|
450
654
|
expandHint = "",
|
|
451
655
|
collapseHint = "",
|
|
452
656
|
renderChevron,
|
|
657
|
+
enableInlineSearch = false,
|
|
658
|
+
search,
|
|
659
|
+
searchQuery,
|
|
660
|
+
onSearchChange,
|
|
453
661
|
header,
|
|
454
662
|
footer,
|
|
455
663
|
containerStyle
|
|
456
664
|
}) => {
|
|
457
665
|
const { theme } = uiFeedback.useUi();
|
|
458
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;
|
|
459
681
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
460
682
|
reactNative.View,
|
|
461
683
|
{
|
|
@@ -469,8 +691,18 @@ var Sidebar = ({
|
|
|
469
691
|
],
|
|
470
692
|
children: [
|
|
471
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,
|
|
472
704
|
renderTextSlot(header, { color: colors.text }),
|
|
473
|
-
|
|
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(
|
|
474
706
|
NavExpandableItem,
|
|
475
707
|
{
|
|
476
708
|
collapseHint,
|
|
@@ -490,6 +722,12 @@ var Sidebar = ({
|
|
|
490
722
|
);
|
|
491
723
|
};
|
|
492
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
|
+
|
|
493
731
|
// src/constants.ts
|
|
494
732
|
var NAV_TEST_IDS = {
|
|
495
733
|
/** displayName line in the rich account header (tappable when `onAccount` set). */
|
|
@@ -537,7 +775,7 @@ var FocusableTouchable = ({
|
|
|
537
775
|
testID,
|
|
538
776
|
children
|
|
539
777
|
}) => {
|
|
540
|
-
const [focused, setFocused] =
|
|
778
|
+
const [focused, setFocused] = React3.useState(false);
|
|
541
779
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
542
780
|
reactNative.Pressable,
|
|
543
781
|
{
|
|
@@ -690,8 +928,8 @@ var NavBarLink = ({
|
|
|
690
928
|
navigateHint,
|
|
691
929
|
onPress
|
|
692
930
|
}) => {
|
|
693
|
-
const [hovered, setHovered] =
|
|
694
|
-
const [focused, setFocused] =
|
|
931
|
+
const [hovered, setHovered] = React3.useState(false);
|
|
932
|
+
const [focused, setFocused] = React3.useState(false);
|
|
695
933
|
const isHovered = hovered && !isActive;
|
|
696
934
|
const textColor = isActive ? TEXT_ON_PRIMARY2 : isHovered ? colors.hoverText : colors.rest;
|
|
697
935
|
const pillStyle = isActive ? { backgroundColor: colors.activeBg } : isHovered ? { backgroundColor: colors.hoverBg } : void 0;
|
|
@@ -735,12 +973,12 @@ var NavOverflowMenu = ({
|
|
|
735
973
|
testID,
|
|
736
974
|
variant
|
|
737
975
|
}) => {
|
|
738
|
-
const options =
|
|
739
|
-
const activeRoute =
|
|
976
|
+
const options = React3.useMemo(() => items.map((item) => ({ label: item.label, value: item.route })), [items]);
|
|
977
|
+
const activeRoute = React3.useMemo(
|
|
740
978
|
() => items.find((item) => isRouteActive(pathname, item.route))?.route ?? NO_ACTIVE_ROUTE,
|
|
741
979
|
[items, pathname]
|
|
742
980
|
);
|
|
743
|
-
const optionTestID =
|
|
981
|
+
const optionTestID = React3.useMemo(() => {
|
|
744
982
|
const byRoute = new Map(items.map((item) => [item.route, item.testID ?? item.key]));
|
|
745
983
|
return (route) => byRoute.get(route) ?? `${testID}-option-${route}`;
|
|
746
984
|
}, [items, testID]);
|
|
@@ -797,13 +1035,13 @@ function resizeWidthBuffer(previous, count) {
|
|
|
797
1035
|
return next;
|
|
798
1036
|
}
|
|
799
1037
|
function useNavOverflow(itemCount, gap) {
|
|
800
|
-
const [availableWidth, setAvailableWidthState] =
|
|
801
|
-
const [moreWidth, setMoreWidthState] =
|
|
802
|
-
const [itemWidths, setItemWidths] =
|
|
803
|
-
|
|
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(() => {
|
|
804
1042
|
setItemWidths((previous) => previous.length === itemCount ? previous : resizeWidthBuffer(previous, itemCount));
|
|
805
1043
|
}, [itemCount]);
|
|
806
|
-
const setItemWidth =
|
|
1044
|
+
const setItemWidth = React3.useCallback((index, width) => {
|
|
807
1045
|
setItemWidths((previous) => {
|
|
808
1046
|
if (index < 0 || index >= previous.length || previous[index] === width) return previous;
|
|
809
1047
|
const next = previous.slice();
|
|
@@ -811,38 +1049,20 @@ function useNavOverflow(itemCount, gap) {
|
|
|
811
1049
|
return next;
|
|
812
1050
|
});
|
|
813
1051
|
}, []);
|
|
814
|
-
const setAvailableWidth =
|
|
1052
|
+
const setAvailableWidth = React3.useCallback(
|
|
815
1053
|
(width) => setAvailableWidthState((previous) => previous === width ? previous : width),
|
|
816
1054
|
[]
|
|
817
1055
|
);
|
|
818
|
-
const setMoreWidth =
|
|
1056
|
+
const setMoreWidth = React3.useCallback(
|
|
819
1057
|
(width) => setMoreWidthState((previous) => previous === width ? previous : width),
|
|
820
1058
|
[]
|
|
821
1059
|
);
|
|
822
|
-
const visibleCount =
|
|
1060
|
+
const visibleCount = React3.useMemo(
|
|
823
1061
|
() => computeVisibleCount({ availableWidth, itemWidths, moreWidth, gap }),
|
|
824
1062
|
[availableWidth, itemWidths, moreWidth, gap]
|
|
825
1063
|
);
|
|
826
1064
|
return { visibleCount, setAvailableWidth, setItemWidth, setMoreWidth };
|
|
827
1065
|
}
|
|
828
|
-
var REDUCED_MOTION_QUERY = "(prefers-reduced-motion: reduce)";
|
|
829
|
-
function getReducedMotionQuery() {
|
|
830
|
-
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return void 0;
|
|
831
|
-
return window.matchMedia(REDUCED_MOTION_QUERY);
|
|
832
|
-
}
|
|
833
|
-
function useReducedMotion() {
|
|
834
|
-
const [reduced, setReduced] = React2.useState(() => getReducedMotionQuery()?.matches ?? false);
|
|
835
|
-
React2.useEffect(() => {
|
|
836
|
-
const mql = getReducedMotionQuery();
|
|
837
|
-
if (mql === void 0 || mql.addEventListener === void 0) return void 0;
|
|
838
|
-
const onChange = () => setReduced(mql.matches);
|
|
839
|
-
mql.addEventListener("change", onChange);
|
|
840
|
-
return () => {
|
|
841
|
-
mql.removeEventListener?.("change", onChange);
|
|
842
|
-
};
|
|
843
|
-
}, []);
|
|
844
|
-
return reduced;
|
|
845
|
-
}
|
|
846
1066
|
var LINKS_REGION_ID = "navbar-links-region";
|
|
847
1067
|
var DEFAULT_COLLAPSE_BELOW = 760;
|
|
848
1068
|
var MENU_GLYPH = "\u2630";
|
|
@@ -871,24 +1091,24 @@ var NavBarInner = ({
|
|
|
871
1091
|
const primaryColor = theme.palette.primary["500"];
|
|
872
1092
|
const { width } = reactNative.useWindowDimensions();
|
|
873
1093
|
const reducedMotion = useReducedMotion();
|
|
874
|
-
const [open, setOpen] =
|
|
875
|
-
const [toggleFocused, setToggleFocused] =
|
|
1094
|
+
const [open, setOpen] = React3.useState(false);
|
|
1095
|
+
const [toggleFocused, setToggleFocused] = React3.useState(false);
|
|
876
1096
|
const { visibleCount, setAvailableWidth, setItemWidth, setMoreWidth } = useNavOverflow(items.length, NAV_LINK_GAP);
|
|
877
1097
|
const collapsed = width < collapseBelow;
|
|
878
1098
|
const showLinks = !collapsed || open;
|
|
879
|
-
const innerCapStyle =
|
|
1099
|
+
const innerCapStyle = React3.useMemo(
|
|
880
1100
|
() => contentMaxWidth === void 0 ? null : { maxWidth: contentMaxWidth, width: "100%", alignSelf: "center" },
|
|
881
1101
|
[contentMaxWidth]
|
|
882
1102
|
);
|
|
883
|
-
const toggleMenu =
|
|
884
|
-
const handlePress =
|
|
1103
|
+
const toggleMenu = React3.useCallback(() => setOpen((v) => !v), []);
|
|
1104
|
+
const handlePress = React3.useCallback(
|
|
885
1105
|
(route) => {
|
|
886
1106
|
setOpen(false);
|
|
887
1107
|
onNavigate(route);
|
|
888
1108
|
},
|
|
889
1109
|
[onNavigate]
|
|
890
1110
|
);
|
|
891
|
-
const linkColors =
|
|
1111
|
+
const linkColors = React3.useMemo(
|
|
892
1112
|
() => ({
|
|
893
1113
|
rest: colors.textSecondary,
|
|
894
1114
|
hoverText: colors.text,
|
|
@@ -943,7 +1163,7 @@ var NavBarInner = ({
|
|
|
943
1163
|
}
|
|
944
1164
|
);
|
|
945
1165
|
if (collapsed) {
|
|
946
|
-
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)) });
|
|
947
1167
|
}
|
|
948
1168
|
const visibleItems = items.slice(0, visibleCount);
|
|
949
1169
|
const overflowItems = items.slice(visibleCount);
|
|
@@ -1009,7 +1229,7 @@ var CARD_BORDER_WIDTH = 1;
|
|
|
1009
1229
|
var CARD_TITLE_FONT_SIZE = 16;
|
|
1010
1230
|
var CARD_MESSAGE_FONT_SIZE = 14;
|
|
1011
1231
|
var CARD_TITLE_MARGIN_BOTTOM = 8;
|
|
1012
|
-
var
|
|
1232
|
+
var styles2 = reactNative.StyleSheet.create({
|
|
1013
1233
|
centerFill: { flex: 1, justifyContent: "center", alignItems: "center" },
|
|
1014
1234
|
card: {
|
|
1015
1235
|
padding: CARD_PADDING,
|
|
@@ -1026,9 +1246,9 @@ function MessageCard({
|
|
|
1026
1246
|
}) {
|
|
1027
1247
|
const { theme } = uiFeedback.useUi();
|
|
1028
1248
|
const colors = theme.colors;
|
|
1029
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [
|
|
1030
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [
|
|
1031
|
-
/* @__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 })
|
|
1032
1252
|
] });
|
|
1033
1253
|
}
|
|
1034
1254
|
function useContentBody(state, children, testID) {
|
|
@@ -1040,7 +1260,7 @@ function useContentBody(state, children, testID) {
|
|
|
1040
1260
|
if (state?.error)
|
|
1041
1261
|
return /* @__PURE__ */ jsxRuntime.jsx(MessageCard, { accentColor: errorColor, message: state.error, testID: `${testID}${APP_SHELL_SUFFIX.error}` });
|
|
1042
1262
|
if (state?.loading === true)
|
|
1043
|
-
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" }) });
|
|
1044
1264
|
return children;
|
|
1045
1265
|
}
|
|
1046
1266
|
var SCRIM_COLOR = "rgba(0, 0, 0, 0.5)";
|
|
@@ -1064,7 +1284,7 @@ var DEFAULT_DRAWER_LABELS = {
|
|
|
1064
1284
|
closeLabel: "Close menu",
|
|
1065
1285
|
closeHint: "Close the navigation menu"
|
|
1066
1286
|
};
|
|
1067
|
-
var
|
|
1287
|
+
var styles3 = reactNative.StyleSheet.create({
|
|
1068
1288
|
overlay: { ...reactNative.StyleSheet.absoluteFillObject, zIndex: DRAWER_Z_INDEX },
|
|
1069
1289
|
// The scrim's tap-to-close hit area is anchored to the RIGHT of the panel
|
|
1070
1290
|
// (`left: DRAWER_WIDTH`), so it NEVER overlaps the panel: nav-item taps always
|
|
@@ -1099,10 +1319,10 @@ var MenuToggle = ({ label, hint, onOpen, testID }) => {
|
|
|
1099
1319
|
accessibilityHint: hint,
|
|
1100
1320
|
accessibilityLabel: label,
|
|
1101
1321
|
ringColor: theme.palette.primary["500"],
|
|
1102
|
-
style:
|
|
1322
|
+
style: styles3.menuToggle,
|
|
1103
1323
|
testID,
|
|
1104
1324
|
onPress: onOpen,
|
|
1105
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [
|
|
1325
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles3.menuToggleGlyph, { color: theme.colors.text }], children: MENU_GLYPH2 })
|
|
1106
1326
|
}
|
|
1107
1327
|
);
|
|
1108
1328
|
};
|
|
@@ -1114,8 +1334,8 @@ var MobileDrawer = ({
|
|
|
1114
1334
|
scrimTestID
|
|
1115
1335
|
}) => {
|
|
1116
1336
|
const { theme } = uiFeedback.useUi();
|
|
1117
|
-
const panelRef =
|
|
1118
|
-
|
|
1337
|
+
const panelRef = React3.useRef(null);
|
|
1338
|
+
React3.useEffect(() => {
|
|
1119
1339
|
const node = panelRef.current;
|
|
1120
1340
|
if (node === null || typeof node.addEventListener !== "function") return void 0;
|
|
1121
1341
|
const handleClick = (event) => {
|
|
@@ -1128,14 +1348,14 @@ var MobileDrawer = ({
|
|
|
1128
1348
|
node.addEventListener("click", handleClick);
|
|
1129
1349
|
return () => node.removeEventListener("click", handleClick);
|
|
1130
1350
|
}, [onClose]);
|
|
1131
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
1351
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.overlay, children: [
|
|
1132
1352
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1133
1353
|
reactNative.Pressable,
|
|
1134
1354
|
{
|
|
1135
1355
|
accessibilityHint: labels.closeHint,
|
|
1136
1356
|
accessibilityLabel: labels.closeLabel,
|
|
1137
1357
|
accessibilityRole: "button",
|
|
1138
|
-
style:
|
|
1358
|
+
style: styles3.scrim,
|
|
1139
1359
|
testID: scrimTestID,
|
|
1140
1360
|
onPress: onClose
|
|
1141
1361
|
}
|
|
@@ -1146,7 +1366,7 @@ var MobileDrawer = ({
|
|
|
1146
1366
|
ref: panelRef,
|
|
1147
1367
|
"aria-modal": true,
|
|
1148
1368
|
role: "dialog",
|
|
1149
|
-
style: [
|
|
1369
|
+
style: [styles3.panel, { backgroundColor: theme.colors.surface }],
|
|
1150
1370
|
testID: drawerTestID,
|
|
1151
1371
|
children: renderTextSlot(sidebar, { color: theme.colors.text })
|
|
1152
1372
|
}
|
|
@@ -1177,7 +1397,7 @@ function useContentMaxWidth(width) {
|
|
|
1177
1397
|
return resolveContentMaxWidth(width, viewport);
|
|
1178
1398
|
}
|
|
1179
1399
|
var DEFAULT_CONTENT_PADDING = 24;
|
|
1180
|
-
var
|
|
1400
|
+
var styles4 = reactNative.StyleSheet.create({
|
|
1181
1401
|
root: { flex: 1 },
|
|
1182
1402
|
centerFill: { flex: 1, justifyContent: "center", alignItems: "center" },
|
|
1183
1403
|
scroll: { flex: 1 },
|
|
@@ -1222,32 +1442,32 @@ var AppShell = ({
|
|
|
1222
1442
|
range: railRange
|
|
1223
1443
|
});
|
|
1224
1444
|
const useDrawer = railMode === "drawer";
|
|
1225
|
-
const [drawerOpen, setDrawerOpen] =
|
|
1226
|
-
const openDrawer =
|
|
1227
|
-
const closeDrawer =
|
|
1228
|
-
|
|
1445
|
+
const [drawerOpen, setDrawerOpen] = React3.useState(false);
|
|
1446
|
+
const openDrawer = React3.useCallback(() => setDrawerOpen(true), []);
|
|
1447
|
+
const closeDrawer = React3.useCallback(() => setDrawerOpen(false), []);
|
|
1448
|
+
React3.useEffect(() => {
|
|
1229
1449
|
if (!useDrawer && drawerOpen) setDrawerOpen(false);
|
|
1230
1450
|
}, [useDrawer, drawerOpen]);
|
|
1231
1451
|
const drawerLabels = { ...DEFAULT_DRAWER_LABELS, ...mobileMenu };
|
|
1232
1452
|
const isUnauthenticated = gate !== void 0 && !gate.pending && !gate.authenticated;
|
|
1233
|
-
|
|
1453
|
+
React3.useEffect(() => {
|
|
1234
1454
|
if (isUnauthenticated && gate !== void 0) gate.onRedirect();
|
|
1235
1455
|
}, [isUnauthenticated, gate]);
|
|
1236
1456
|
if (gate?.pending === true)
|
|
1237
|
-
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" }) });
|
|
1238
1458
|
if (isUnauthenticated) return null;
|
|
1239
|
-
const columnStyle = maxWidth === "full" ?
|
|
1240
|
-
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;
|
|
1241
1461
|
const scroller = /* @__PURE__ */ jsxRuntime.jsx(
|
|
1242
1462
|
reactNative.ScrollView,
|
|
1243
1463
|
{
|
|
1244
|
-
contentContainerStyle: [
|
|
1245
|
-
style:
|
|
1464
|
+
contentContainerStyle: [styles4.scrollContent, { padding: contentPadding }],
|
|
1465
|
+
style: styles4.scroll,
|
|
1246
1466
|
testID: `${testID}${APP_SHELL_SUFFIX.content}`,
|
|
1247
1467
|
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: columnStyle, children: body })
|
|
1248
1468
|
}
|
|
1249
1469
|
);
|
|
1250
|
-
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: [
|
|
1251
1471
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1252
1472
|
MenuToggle,
|
|
1253
1473
|
{
|
|
@@ -1257,14 +1477,14 @@ var AppShell = ({
|
|
|
1257
1477
|
onOpen: openDrawer
|
|
1258
1478
|
}
|
|
1259
1479
|
),
|
|
1260
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style:
|
|
1480
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles4.headerFill, children: renderTextSlot(header, { color: theme.colors.text }) })
|
|
1261
1481
|
] }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { testID: `${testID}${APP_SHELL_SUFFIX.header}`, children: renderTextSlot(header, { color: theme.colors.text }) });
|
|
1262
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;
|
|
1263
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [
|
|
1483
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles4.root, { backgroundColor: theme.colors.background }], testID, children: [
|
|
1264
1484
|
headerRegion,
|
|
1265
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,
|
|
1266
1486
|
banner !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { testID: `${testID}${APP_SHELL_SUFFIX.banner}`, children: renderTextSlot(banner, { color: theme.colors.text }) }) : null,
|
|
1267
|
-
railRegion !== null ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
1487
|
+
railRegion !== null ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles4.bodyRow, children: [
|
|
1268
1488
|
railRegion,
|
|
1269
1489
|
scroller
|
|
1270
1490
|
] }) : scroller,
|
|
@@ -1482,7 +1702,7 @@ var DarkModeControl = ({
|
|
|
1482
1702
|
const primaryColor = theme.palette.primary["500"];
|
|
1483
1703
|
const currentIndex = options.findIndex((option) => option.value === value);
|
|
1484
1704
|
const current = currentIndex >= 0 ? options[currentIndex] : options[0];
|
|
1485
|
-
const advance =
|
|
1705
|
+
const advance = React3.useCallback(() => {
|
|
1486
1706
|
if (options.length === 0) return;
|
|
1487
1707
|
const from = currentIndex >= 0 ? currentIndex : 0;
|
|
1488
1708
|
const next = options[(from + 1) % options.length];
|
|
@@ -1558,7 +1778,7 @@ var KEY_DOWN = "ArrowDown";
|
|
|
1558
1778
|
var KEY_UP = "ArrowUp";
|
|
1559
1779
|
var KEY_ENTER = "Enter";
|
|
1560
1780
|
var KEY_ESCAPE = "Escape";
|
|
1561
|
-
var
|
|
1781
|
+
var styles5 = reactNative.StyleSheet.create({
|
|
1562
1782
|
overlay: { ...reactNative.StyleSheet.absoluteFillObject, zIndex: OVERLAY_Z_INDEX, alignItems: "center" },
|
|
1563
1783
|
scrim: { ...reactNative.StyleSheet.absoluteFillObject, backgroundColor: SCRIM_COLOR2 },
|
|
1564
1784
|
panel: {
|
|
@@ -1587,14 +1807,14 @@ var PaletteRow = ({ item, selected, onChoose }) => {
|
|
|
1587
1807
|
accessibilityLabel: item.label,
|
|
1588
1808
|
accessibilityRole: "button",
|
|
1589
1809
|
accessibilityState: { selected },
|
|
1590
|
-
style: [
|
|
1810
|
+
style: [styles5.row, selected ? { backgroundColor: colors.border } : void 0],
|
|
1591
1811
|
testID: item.testID ?? item.key,
|
|
1592
1812
|
onPress: () => onChoose(item),
|
|
1593
1813
|
children: [
|
|
1594
1814
|
typeof item.renderIcon === "function" ? item.renderIcon(colors.textSecondary, NAV_ICON_SIZE) : null,
|
|
1595
|
-
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
1596
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [
|
|
1597
|
-
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
|
|
1598
1818
|
] })
|
|
1599
1819
|
]
|
|
1600
1820
|
}
|
|
@@ -1603,27 +1823,27 @@ var PaletteRow = ({ item, selected, onChoose }) => {
|
|
|
1603
1823
|
var CommandPalette = ({ open, items, onClose, labels, testID }) => {
|
|
1604
1824
|
const { theme } = uiFeedback.useUi();
|
|
1605
1825
|
const colors = theme.colors;
|
|
1606
|
-
const [query, setQuery] =
|
|
1607
|
-
const [selected, setSelected] =
|
|
1608
|
-
const inputRef =
|
|
1609
|
-
const results =
|
|
1610
|
-
|
|
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(() => {
|
|
1611
1831
|
if (!open) return;
|
|
1612
1832
|
setQuery("");
|
|
1613
1833
|
setSelected(0);
|
|
1614
1834
|
inputRef.current?.focus();
|
|
1615
1835
|
}, [open]);
|
|
1616
|
-
|
|
1836
|
+
React3.useEffect(() => {
|
|
1617
1837
|
setSelected((prev) => Math.min(prev, Math.max(0, results.length - 1)));
|
|
1618
1838
|
}, [results.length]);
|
|
1619
|
-
const choose =
|
|
1839
|
+
const choose = React3.useCallback(
|
|
1620
1840
|
(item) => {
|
|
1621
1841
|
item.onSelect();
|
|
1622
1842
|
onClose();
|
|
1623
1843
|
},
|
|
1624
1844
|
[onClose]
|
|
1625
1845
|
);
|
|
1626
|
-
const onKeyPress =
|
|
1846
|
+
const onKeyPress = React3.useCallback(
|
|
1627
1847
|
(event) => {
|
|
1628
1848
|
const key = event.nativeEvent.key;
|
|
1629
1849
|
if (key === KEY_DOWN) setSelected((i) => Math.min(i + 1, results.length - 1));
|
|
@@ -1634,14 +1854,14 @@ var CommandPalette = ({ open, items, onClose, labels, testID }) => {
|
|
|
1634
1854
|
[results, selected, choose, onClose]
|
|
1635
1855
|
);
|
|
1636
1856
|
if (!open) return null;
|
|
1637
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
1857
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles5.overlay, children: [
|
|
1638
1858
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1639
1859
|
reactNative.Pressable,
|
|
1640
1860
|
{
|
|
1641
1861
|
accessibilityHint: labels.closeHint,
|
|
1642
1862
|
accessibilityLabel: labels.closeLabel,
|
|
1643
1863
|
accessibilityRole: "button",
|
|
1644
|
-
style:
|
|
1864
|
+
style: styles5.scrim,
|
|
1645
1865
|
testID: `${testID ?? "command-palette"}-scrim`,
|
|
1646
1866
|
onPress: onClose
|
|
1647
1867
|
}
|
|
@@ -1652,7 +1872,7 @@ var CommandPalette = ({ open, items, onClose, labels, testID }) => {
|
|
|
1652
1872
|
"aria-modal": true,
|
|
1653
1873
|
"aria-label": labels.regionLabel,
|
|
1654
1874
|
role: "dialog",
|
|
1655
|
-
style: [
|
|
1875
|
+
style: [styles5.panel, { backgroundColor: colors.surface, borderColor: colors.border }],
|
|
1656
1876
|
testID: testID ?? "command-palette",
|
|
1657
1877
|
children: [
|
|
1658
1878
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1662,21 +1882,21 @@ var CommandPalette = ({ open, items, onClose, labels, testID }) => {
|
|
|
1662
1882
|
accessibilityLabel: labels.placeholder,
|
|
1663
1883
|
placeholder: labels.placeholder,
|
|
1664
1884
|
placeholderTextColor: colors.textSecondary,
|
|
1665
|
-
style: [
|
|
1885
|
+
style: [styles5.input, { color: colors.text, borderBottomColor: colors.border }],
|
|
1666
1886
|
testID: `${testID ?? "command-palette"}-input`,
|
|
1667
1887
|
value: query,
|
|
1668
1888
|
onChangeText: setQuery,
|
|
1669
1889
|
onKeyPress
|
|
1670
1890
|
}
|
|
1671
1891
|
),
|
|
1672
|
-
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)) })
|
|
1673
1893
|
]
|
|
1674
1894
|
}
|
|
1675
1895
|
)
|
|
1676
1896
|
] });
|
|
1677
1897
|
};
|
|
1678
1898
|
var MIN_TARGET = 36;
|
|
1679
|
-
var
|
|
1899
|
+
var styles6 = reactNative.StyleSheet.create({
|
|
1680
1900
|
trigger: {
|
|
1681
1901
|
flexDirection: "row",
|
|
1682
1902
|
alignItems: "center",
|
|
@@ -1701,7 +1921,7 @@ var CommandPaletteTrigger = ({
|
|
|
1701
1921
|
const { theme } = uiFeedback.useUi();
|
|
1702
1922
|
const colors = theme.colors;
|
|
1703
1923
|
const primary = theme.palette.primary["500"];
|
|
1704
|
-
const [focused, setFocused] =
|
|
1924
|
+
const [focused, setFocused] = React3__default.default.useState(false);
|
|
1705
1925
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1706
1926
|
reactNative.Pressable,
|
|
1707
1927
|
{
|
|
@@ -1709,7 +1929,7 @@ var CommandPaletteTrigger = ({
|
|
|
1709
1929
|
accessibilityLabel: label,
|
|
1710
1930
|
accessibilityRole: "button",
|
|
1711
1931
|
style: [
|
|
1712
|
-
|
|
1932
|
+
styles6.trigger,
|
|
1713
1933
|
{ backgroundColor: colors.surface, borderColor: colors.border },
|
|
1714
1934
|
focusRingStyle(focused, primary)
|
|
1715
1935
|
],
|
|
@@ -1718,15 +1938,15 @@ var CommandPaletteTrigger = ({
|
|
|
1718
1938
|
onFocus: () => setFocused(true),
|
|
1719
1939
|
onPress,
|
|
1720
1940
|
children: [
|
|
1721
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [
|
|
1722
|
-
/* @__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 }) })
|
|
1723
1943
|
]
|
|
1724
1944
|
}
|
|
1725
1945
|
);
|
|
1726
1946
|
};
|
|
1727
1947
|
var LAUNCH_KEY = "k";
|
|
1728
1948
|
function useCommandPaletteHotkey(onOpen, enabled = true) {
|
|
1729
|
-
|
|
1949
|
+
React3.useEffect(() => {
|
|
1730
1950
|
if (!enabled || typeof document === "undefined") return void 0;
|
|
1731
1951
|
const handler = (event) => {
|
|
1732
1952
|
const isLauncher = event.key.toLowerCase() === LAUNCH_KEY && (event.metaKey || event.ctrlKey);
|
|
@@ -1750,6 +1970,7 @@ function accessibleNavItems(user, table, translate) {
|
|
|
1750
1970
|
}
|
|
1751
1971
|
|
|
1752
1972
|
exports.ACTIVE_BORDER_RADIUS = ACTIVE_BORDER_RADIUS;
|
|
1973
|
+
exports.ACTIVE_TINT_OPACITY = ACTIVE_TINT_OPACITY;
|
|
1753
1974
|
exports.APP_SHELL_SUFFIX = APP_SHELL_SUFFIX;
|
|
1754
1975
|
exports.AppShell = AppShell;
|
|
1755
1976
|
exports.BASE_INDENT = BASE_INDENT;
|
|
@@ -1758,9 +1979,12 @@ exports.CollapsedRail = CollapsedRail;
|
|
|
1758
1979
|
exports.CommandPalette = CommandPalette;
|
|
1759
1980
|
exports.CommandPaletteTrigger = CommandPaletteTrigger;
|
|
1760
1981
|
exports.DEFAULT_COLLAPSED_RAIL_MAX = DEFAULT_COLLAPSED_RAIL_MAX;
|
|
1982
|
+
exports.DEFAULT_SEARCH_BREAKPOINT = DEFAULT_SEARCH_BREAKPOINT;
|
|
1761
1983
|
exports.DarkModeControl = DarkModeControl;
|
|
1984
|
+
exports.HOVER_TINT_OPACITY = HOVER_TINT_OPACITY;
|
|
1762
1985
|
exports.NAV_ICON_SIZE = NAV_ICON_SIZE;
|
|
1763
1986
|
exports.NAV_LINK_GAP = NAV_LINK_GAP;
|
|
1987
|
+
exports.NAV_ROW_RADIUS = NAV_ROW_RADIUS;
|
|
1764
1988
|
exports.NAV_TEST_IDS = NAV_TEST_IDS;
|
|
1765
1989
|
exports.Nav = Nav;
|
|
1766
1990
|
exports.NavBar = NavBar;
|
|
@@ -1770,18 +1994,24 @@ exports.NavShell = NavShell;
|
|
|
1770
1994
|
exports.PillNav = PillNav;
|
|
1771
1995
|
exports.RAIL_FULL_BREAKPOINT = RAIL_FULL_BREAKPOINT;
|
|
1772
1996
|
exports.Sidebar = Sidebar;
|
|
1997
|
+
exports.SidebarChevron = SidebarChevron;
|
|
1998
|
+
exports.SidebarSearch = SidebarSearch;
|
|
1773
1999
|
exports.Topbar = Topbar;
|
|
1774
2000
|
exports.accessibleNavItems = accessibleNavItems;
|
|
1775
2001
|
exports.collapsedRailStyles = collapsedRailStyles;
|
|
1776
2002
|
exports.darkModeStyles = darkModeStyles;
|
|
1777
2003
|
exports.expandableStyles = expandableStyles;
|
|
1778
2004
|
exports.filterCommands = filterCommands;
|
|
2005
|
+
exports.filterNavItems = filterNavItems;
|
|
2006
|
+
exports.isFilterActive = isFilterActive;
|
|
1779
2007
|
exports.isRouteActive = isRouteActive;
|
|
1780
2008
|
exports.navStyles = navStyles;
|
|
1781
2009
|
exports.pillNavStyles = pillNavStyles;
|
|
1782
2010
|
exports.resolveContentMaxWidth = resolveContentMaxWidth;
|
|
1783
2011
|
exports.resolveRailMode = resolveRailMode;
|
|
2012
|
+
exports.resolveSearchAffordance = resolveSearchAffordance;
|
|
1784
2013
|
exports.roleRoutesToNavItems = roleRoutesToNavItems;
|
|
2014
|
+
exports.searchTokens = searchTokens;
|
|
1785
2015
|
exports.useCommandPaletteHotkey = useCommandPaletteHotkey;
|
|
1786
2016
|
exports.useContentMaxWidth = useContentMaxWidth;
|
|
1787
2017
|
//# sourceMappingURL=index.js.map
|