@dloizides/ui-nav 1.10.0 → 1.10.2
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 +45 -0
- package/dist/index.js +94 -55
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +57 -18
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,50 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.10.2
|
|
4
|
+
|
|
5
|
+
- **Fix (the mobile nav DRAWER was not clickable — a tap on a nav item did not navigate, it
|
|
6
|
+
just closed the drawer / did nothing, in all seven portals below 768px).**
|
|
7
|
+
`MobileDrawer` rendered a full-bleed scrim `Pressable` (`StyleSheet.absoluteFillObject`) and a
|
|
8
|
+
panel `View` with `{ position: 'absolute', top: 0, bottom: 0, left: 0 }` — **no width and no
|
|
9
|
+
zIndex**. Reproduced structurally: the panel's computed `width` was empty and its `zIndex` was
|
|
10
|
+
`0`; the scrim's computed `left`/`right` were both `0px` at `zIndex` `0`. So the scrim FULLY
|
|
11
|
+
overlapped the panel at the SAME stacking level, and on react-native-web the equal-zIndex scrim
|
|
12
|
+
won the pointer (the estate's known "RN-web Pressable swallows a sibling/child press" trap):
|
|
13
|
+
the tap closed the drawer and the nav-item's `TouchableOpacity` `onPress` (→ the app's router)
|
|
14
|
+
never fired.
|
|
15
|
+
- Fixed once, in the kit: the panel now has an explicit drawer **width** (`280px`), a solid
|
|
16
|
+
surface background, and a `zIndex` **above** the scrim; the scrim is anchored BESIDE the panel
|
|
17
|
+
(`left: DRAWER_WIDTH`) so its tap-to-close hit area never overlaps the panel. Nav-item taps
|
|
18
|
+
reach the `Sidebar` leaves; taps beside the drawer still close it.
|
|
19
|
+
- Guarded by `src/mobileDrawer.test.tsx` (RED-first): three structural assertions read the
|
|
20
|
+
resolved geometry via `getComputedStyle` and FAIL against the pre-fix panel/scrim (no width,
|
|
21
|
+
equal zIndex, overlapping scrim); two behavioural assertions lock the contract (nav-item tap
|
|
22
|
+
navigates + closes; scrim tap only closes).
|
|
23
|
+
- **No API change.** Consumers need no edit — bump the dependency and the drawer works.
|
|
24
|
+
|
|
25
|
+
## 1.10.1
|
|
26
|
+
|
|
27
|
+
- **Fix (a plain-string slot logged `console.error` on EVERY render, in all seven portals).**
|
|
28
|
+
Every caller-supplied slot in the kit is typed `React.ReactNode`, which legitimately includes
|
|
29
|
+
`string` — and callers pass exactly that (`brand: FM('app.name')`, a plain localized string).
|
|
30
|
+
The slot was dropped straight into a `<View>`, and react-native-web refuses to render a bare
|
|
31
|
+
text node there: `Unexpected text node: <s>. A text node cannot be a child of a <View>.`
|
|
32
|
+
Nothing in the type system objected, so the defect only ever surfaced as browser console
|
|
33
|
+
noise — which is why it survived to 1.10.0 across the whole fleet.
|
|
34
|
+
- Fixed once, in the kit, via the new internal `renderTextSlot` helper: a `string`/`number`
|
|
35
|
+
slot is wrapped in `<Text>` (routed through the theme's `colors.text`, so it honours dark
|
|
36
|
+
mode rather than defaulting to black); an element slot passes through **untouched**, so
|
|
37
|
+
every existing caller renders byte-identically. Array slots have each string member wrapped
|
|
38
|
+
individually, keys preserved.
|
|
39
|
+
- Applied to **all 12 slot render sites**, not just the reported one — `NavBar` (`brand`,
|
|
40
|
+
`right`), `Topbar` (`left`, `notificationSlot`), `Sidebar` (`header`, `footer`),
|
|
41
|
+
`CollapsedRail` (`header`, `footer`), `AppShell` (`header`, `nav`, `sidebar`,
|
|
42
|
+
`collapsedSidebar`, `banner`) and `MobileDrawer` (`sidebar`).
|
|
43
|
+
- Guarded by `src/rawTextSlots.test.tsx`, which spies on `console.error` and asserts silence.
|
|
44
|
+
Unit tests that only assert "the slot rendered" pass against the bug; this one does not.
|
|
45
|
+
- **No API change.** Consumers need no edit — the `<Text>` wrapper they were expected to
|
|
46
|
+
remember is now the kit's job.
|
|
47
|
+
|
|
3
48
|
## 1.10.0
|
|
4
49
|
|
|
5
50
|
- **Fix (`layout` was not authoritative — `layout="side"` rendered a top bar anyway).**
|
package/dist/index.js
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
var reactNative = require('react-native');
|
|
4
4
|
var uiFeedback = require('@dloizides/ui-feedback');
|
|
5
|
-
var
|
|
5
|
+
var React2 = require('react');
|
|
6
6
|
var jsxRuntime = require('react/jsx-runtime');
|
|
7
7
|
var uiLayout = require('@dloizides/ui-layout');
|
|
8
8
|
var authWeb = require('@dloizides/auth-web');
|
|
9
9
|
|
|
10
10
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
11
|
|
|
12
|
-
var
|
|
12
|
+
var React2__default = /*#__PURE__*/_interopDefault(React2);
|
|
13
13
|
|
|
14
14
|
// src/Sidebar.tsx
|
|
15
15
|
|
|
@@ -299,21 +299,21 @@ var NavExpandableItem = ({
|
|
|
299
299
|
renderChevron,
|
|
300
300
|
depth = 0
|
|
301
301
|
}) => {
|
|
302
|
-
const [expanded, setExpanded] =
|
|
303
|
-
const [focused, setFocused] =
|
|
302
|
+
const [expanded, setExpanded] = React2.useState(false);
|
|
303
|
+
const [focused, setFocused] = React2.useState(false);
|
|
304
304
|
const { theme } = uiFeedback.useUi();
|
|
305
305
|
const colors = theme.colors;
|
|
306
306
|
const primaryColor = theme.palette.primary["500"];
|
|
307
|
-
const toggle =
|
|
307
|
+
const toggle = React2.useCallback(() => setExpanded((v) => !v), []);
|
|
308
308
|
const indent = depth * BASE_INDENT;
|
|
309
309
|
const hasChildren = Array.isArray(item.children) && item.children.length > 0;
|
|
310
310
|
const isActive = isRouteActive(pathname, item.route);
|
|
311
|
-
const activeItemStyle =
|
|
311
|
+
const activeItemStyle = React2.useMemo(
|
|
312
312
|
() => ({ backgroundColor: colors.border, borderRadius: ACTIVE_BORDER_RADIUS }),
|
|
313
313
|
[colors.border]
|
|
314
314
|
);
|
|
315
|
-
const paddingStyle =
|
|
316
|
-
const headerPaddingStyle =
|
|
315
|
+
const paddingStyle = React2.useMemo(() => ({ paddingLeft: indent + BASE_INDENT }), [indent]);
|
|
316
|
+
const headerPaddingStyle = React2.useMemo(() => ({ paddingLeft: indent }), [indent]);
|
|
317
317
|
if (!hasChildren)
|
|
318
318
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
319
319
|
reactNative.TouchableOpacity,
|
|
@@ -384,6 +384,17 @@ var NavExpandableItem = ({
|
|
|
384
384
|
)) }) : null
|
|
385
385
|
] });
|
|
386
386
|
};
|
|
387
|
+
function isBareText(node) {
|
|
388
|
+
return typeof node === "string" || typeof node === "number";
|
|
389
|
+
}
|
|
390
|
+
function renderTextSlot(node, style) {
|
|
391
|
+
if (node === void 0 || node === null) return node;
|
|
392
|
+
if (isBareText(node)) return /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style, children: node });
|
|
393
|
+
return React2__default.default.Children.map(
|
|
394
|
+
node,
|
|
395
|
+
(child) => isBareText(child) ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style, children: child }) : child
|
|
396
|
+
);
|
|
397
|
+
}
|
|
387
398
|
var Sidebar = ({
|
|
388
399
|
items,
|
|
389
400
|
pathname,
|
|
@@ -413,7 +424,7 @@ var Sidebar = ({
|
|
|
413
424
|
],
|
|
414
425
|
children: [
|
|
415
426
|
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { accessibilityRole: "header", style: [navStyles.sidebarTitle, { color: colors.text }], children: title }),
|
|
416
|
-
header,
|
|
427
|
+
renderTextSlot(header, { color: colors.text }),
|
|
417
428
|
items.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
418
429
|
NavExpandableItem,
|
|
419
430
|
{
|
|
@@ -428,7 +439,7 @@ var Sidebar = ({
|
|
|
428
439
|
item.key
|
|
429
440
|
)),
|
|
430
441
|
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: navStyles.sidebarSpacer }),
|
|
431
|
-
footer
|
|
442
|
+
renderTextSlot(footer, { color: colors.text })
|
|
432
443
|
]
|
|
433
444
|
}
|
|
434
445
|
);
|
|
@@ -481,7 +492,7 @@ var FocusableTouchable = ({
|
|
|
481
492
|
testID,
|
|
482
493
|
children
|
|
483
494
|
}) => {
|
|
484
|
-
const [focused, setFocused] =
|
|
495
|
+
const [focused, setFocused] = React2.useState(false);
|
|
485
496
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
486
497
|
reactNative.Pressable,
|
|
487
498
|
{
|
|
@@ -531,7 +542,7 @@ var Topbar = ({
|
|
|
531
542
|
containerStyle
|
|
532
543
|
],
|
|
533
544
|
children: [
|
|
534
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: navStyles.topbarLeft, children: left }),
|
|
545
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: navStyles.topbarLeft, children: renderTextSlot(left, { color: colors.text }) }),
|
|
535
546
|
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: navStyles.topbarRight, children: [
|
|
536
547
|
language ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
537
548
|
FocusableTouchable,
|
|
@@ -545,7 +556,7 @@ var Topbar = ({
|
|
|
545
556
|
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [navStyles.topbarLabel, { color: colors.text }], children: language.label })
|
|
546
557
|
}
|
|
547
558
|
) : null,
|
|
548
|
-
notificationSlot,
|
|
559
|
+
renderTextSlot(notificationSlot, { color: colors.text }),
|
|
549
560
|
user ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: navStyles.userBlock, children: [
|
|
550
561
|
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [navStyles.userName, { color: colors.text }], children: user.name }),
|
|
551
562
|
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [navStyles.userEmail, { color: colors.textSecondary }], children: user.email })
|
|
@@ -634,8 +645,8 @@ var NavBarLink = ({
|
|
|
634
645
|
navigateHint,
|
|
635
646
|
onPress
|
|
636
647
|
}) => {
|
|
637
|
-
const [hovered, setHovered] =
|
|
638
|
-
const [focused, setFocused] =
|
|
648
|
+
const [hovered, setHovered] = React2.useState(false);
|
|
649
|
+
const [focused, setFocused] = React2.useState(false);
|
|
639
650
|
const isHovered = hovered && !isActive;
|
|
640
651
|
const textColor = isActive ? TEXT_ON_PRIMARY2 : isHovered ? colors.hoverText : colors.rest;
|
|
641
652
|
const pillStyle = isActive ? { backgroundColor: colors.activeBg } : isHovered ? { backgroundColor: colors.hoverBg } : void 0;
|
|
@@ -679,12 +690,12 @@ var NavOverflowMenu = ({
|
|
|
679
690
|
testID,
|
|
680
691
|
variant
|
|
681
692
|
}) => {
|
|
682
|
-
const options =
|
|
683
|
-
const activeRoute =
|
|
693
|
+
const options = React2.useMemo(() => items.map((item) => ({ label: item.label, value: item.route })), [items]);
|
|
694
|
+
const activeRoute = React2.useMemo(
|
|
684
695
|
() => items.find((item) => isRouteActive(pathname, item.route))?.route ?? NO_ACTIVE_ROUTE,
|
|
685
696
|
[items, pathname]
|
|
686
697
|
);
|
|
687
|
-
const optionTestID =
|
|
698
|
+
const optionTestID = React2.useMemo(() => {
|
|
688
699
|
const byRoute = new Map(items.map((item) => [item.route, item.testID ?? item.key]));
|
|
689
700
|
return (route) => byRoute.get(route) ?? `${testID}-option-${route}`;
|
|
690
701
|
}, [items, testID]);
|
|
@@ -741,13 +752,13 @@ function resizeWidthBuffer(previous, count) {
|
|
|
741
752
|
return next;
|
|
742
753
|
}
|
|
743
754
|
function useNavOverflow(itemCount, gap) {
|
|
744
|
-
const [availableWidth, setAvailableWidthState] =
|
|
745
|
-
const [moreWidth, setMoreWidthState] =
|
|
746
|
-
const [itemWidths, setItemWidths] =
|
|
747
|
-
|
|
755
|
+
const [availableWidth, setAvailableWidthState] = React2.useState(0);
|
|
756
|
+
const [moreWidth, setMoreWidthState] = React2.useState(0);
|
|
757
|
+
const [itemWidths, setItemWidths] = React2.useState(() => new Array(itemCount).fill(0));
|
|
758
|
+
React2.useEffect(() => {
|
|
748
759
|
setItemWidths((previous) => previous.length === itemCount ? previous : resizeWidthBuffer(previous, itemCount));
|
|
749
760
|
}, [itemCount]);
|
|
750
|
-
const setItemWidth =
|
|
761
|
+
const setItemWidth = React2.useCallback((index, width) => {
|
|
751
762
|
setItemWidths((previous) => {
|
|
752
763
|
if (index < 0 || index >= previous.length || previous[index] === width) return previous;
|
|
753
764
|
const next = previous.slice();
|
|
@@ -755,15 +766,15 @@ function useNavOverflow(itemCount, gap) {
|
|
|
755
766
|
return next;
|
|
756
767
|
});
|
|
757
768
|
}, []);
|
|
758
|
-
const setAvailableWidth =
|
|
769
|
+
const setAvailableWidth = React2.useCallback(
|
|
759
770
|
(width) => setAvailableWidthState((previous) => previous === width ? previous : width),
|
|
760
771
|
[]
|
|
761
772
|
);
|
|
762
|
-
const setMoreWidth =
|
|
773
|
+
const setMoreWidth = React2.useCallback(
|
|
763
774
|
(width) => setMoreWidthState((previous) => previous === width ? previous : width),
|
|
764
775
|
[]
|
|
765
776
|
);
|
|
766
|
-
const visibleCount =
|
|
777
|
+
const visibleCount = React2.useMemo(
|
|
767
778
|
() => computeVisibleCount({ availableWidth, itemWidths, moreWidth, gap }),
|
|
768
779
|
[availableWidth, itemWidths, moreWidth, gap]
|
|
769
780
|
);
|
|
@@ -775,8 +786,8 @@ function getReducedMotionQuery() {
|
|
|
775
786
|
return window.matchMedia(REDUCED_MOTION_QUERY);
|
|
776
787
|
}
|
|
777
788
|
function useReducedMotion() {
|
|
778
|
-
const [reduced, setReduced] =
|
|
779
|
-
|
|
789
|
+
const [reduced, setReduced] = React2.useState(() => getReducedMotionQuery()?.matches ?? false);
|
|
790
|
+
React2.useEffect(() => {
|
|
780
791
|
const mql = getReducedMotionQuery();
|
|
781
792
|
if (mql === void 0 || mql.addEventListener === void 0) return void 0;
|
|
782
793
|
const onChange = () => setReduced(mql.matches);
|
|
@@ -815,24 +826,24 @@ var NavBarInner = ({
|
|
|
815
826
|
const primaryColor = theme.palette.primary["500"];
|
|
816
827
|
const { width } = reactNative.useWindowDimensions();
|
|
817
828
|
const reducedMotion = useReducedMotion();
|
|
818
|
-
const [open, setOpen] =
|
|
819
|
-
const [toggleFocused, setToggleFocused] =
|
|
829
|
+
const [open, setOpen] = React2.useState(false);
|
|
830
|
+
const [toggleFocused, setToggleFocused] = React2.useState(false);
|
|
820
831
|
const { visibleCount, setAvailableWidth, setItemWidth, setMoreWidth } = useNavOverflow(items.length, NAV_LINK_GAP);
|
|
821
832
|
const collapsed = width < collapseBelow;
|
|
822
833
|
const showLinks = !collapsed || open;
|
|
823
|
-
const innerCapStyle =
|
|
834
|
+
const innerCapStyle = React2.useMemo(
|
|
824
835
|
() => contentMaxWidth === void 0 ? null : { maxWidth: contentMaxWidth, width: "100%", alignSelf: "center" },
|
|
825
836
|
[contentMaxWidth]
|
|
826
837
|
);
|
|
827
|
-
const toggleMenu =
|
|
828
|
-
const handlePress =
|
|
838
|
+
const toggleMenu = React2.useCallback(() => setOpen((v) => !v), []);
|
|
839
|
+
const handlePress = React2.useCallback(
|
|
829
840
|
(route) => {
|
|
830
841
|
setOpen(false);
|
|
831
842
|
onNavigate(route);
|
|
832
843
|
},
|
|
833
844
|
[onNavigate]
|
|
834
845
|
);
|
|
835
|
-
const linkColors =
|
|
846
|
+
const linkColors = React2.useMemo(
|
|
836
847
|
() => ({
|
|
837
848
|
rest: colors.textSecondary,
|
|
838
849
|
hoverText: colors.text,
|
|
@@ -854,7 +865,7 @@ var NavBarInner = ({
|
|
|
854
865
|
containerStyle
|
|
855
866
|
],
|
|
856
867
|
children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [navBarStyles.inner, collapsed ? null : navBarStyles.innerNoWrap, innerCapStyle], children: [
|
|
857
|
-
brand !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: navBarStyles.brand, children: brand }) : null,
|
|
868
|
+
brand !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: navBarStyles.brand, children: renderTextSlot(brand, { color: colors.text }) }) : null,
|
|
858
869
|
collapsed ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
859
870
|
reactNative.Pressable,
|
|
860
871
|
{
|
|
@@ -887,7 +898,7 @@ var NavBarInner = ({
|
|
|
887
898
|
}
|
|
888
899
|
);
|
|
889
900
|
if (collapsed) {
|
|
890
|
-
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(
|
|
901
|
+
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(React2__default.default.Fragment, { children: renderLink(item) }, item.key)) });
|
|
891
902
|
}
|
|
892
903
|
const visibleItems = items.slice(0, visibleCount);
|
|
893
904
|
const overflowItems = items.slice(visibleCount);
|
|
@@ -931,7 +942,7 @@ var NavBarInner = ({
|
|
|
931
942
|
}
|
|
932
943
|
);
|
|
933
944
|
})() : null,
|
|
934
|
-
showLinks && right !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: collapsed ? navBarStyles.rightStacked : navBarStyles.right, children: right }) : null
|
|
945
|
+
showLinks && right !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: collapsed ? navBarStyles.rightStacked : navBarStyles.right, children: renderTextSlot(right, { color: colors.text }) }) : null
|
|
935
946
|
] })
|
|
936
947
|
}
|
|
937
948
|
);
|
|
@@ -993,6 +1004,9 @@ var MENU_MIN_TARGET = 44;
|
|
|
993
1004
|
var MENU_GLYPH_FONT_SIZE = 20;
|
|
994
1005
|
var MENU_TOGGLE_PADDING = 12;
|
|
995
1006
|
var DRAWER_Z_INDEX = 50;
|
|
1007
|
+
var DRAWER_WIDTH = 280;
|
|
1008
|
+
var SCRIM_Z_INDEX = 1;
|
|
1009
|
+
var PANEL_Z_INDEX = 2;
|
|
996
1010
|
var NAV_ACTIVATABLE_SELECTOR = 'a, [role="button"], [role="link"]';
|
|
997
1011
|
var DEFAULT_DRAWER_LABELS = {
|
|
998
1012
|
openLabel: "Menu",
|
|
@@ -1002,8 +1016,22 @@ var DEFAULT_DRAWER_LABELS = {
|
|
|
1002
1016
|
};
|
|
1003
1017
|
var styles2 = reactNative.StyleSheet.create({
|
|
1004
1018
|
overlay: { ...reactNative.StyleSheet.absoluteFillObject, zIndex: DRAWER_Z_INDEX },
|
|
1005
|
-
scrim
|
|
1006
|
-
|
|
1019
|
+
// The scrim's tap-to-close hit area is anchored to the RIGHT of the panel
|
|
1020
|
+
// (`left: DRAWER_WIDTH`), so it NEVER overlaps the panel: nav-item taps always
|
|
1021
|
+
// reach the Sidebar's TouchableOpacity, while taps beside the drawer still close.
|
|
1022
|
+
scrim: {
|
|
1023
|
+
position: "absolute",
|
|
1024
|
+
top: 0,
|
|
1025
|
+
bottom: 0,
|
|
1026
|
+
left: DRAWER_WIDTH,
|
|
1027
|
+
right: 0,
|
|
1028
|
+
backgroundColor: SCRIM_COLOR,
|
|
1029
|
+
zIndex: SCRIM_Z_INDEX
|
|
1030
|
+
},
|
|
1031
|
+
// The panel gets an explicit width (a real drawer) AND a zIndex above the scrim,
|
|
1032
|
+
// so on react-native-web it — and the nav leaves inside it — sit above the scrim
|
|
1033
|
+
// and receive presses instead of the scrim swallowing them.
|
|
1034
|
+
panel: { position: "absolute", top: 0, bottom: 0, left: 0, width: DRAWER_WIDTH, zIndex: PANEL_Z_INDEX },
|
|
1007
1035
|
menuToggle: {
|
|
1008
1036
|
minWidth: MENU_MIN_TARGET,
|
|
1009
1037
|
minHeight: MENU_MIN_TARGET,
|
|
@@ -1035,8 +1063,9 @@ var MobileDrawer = ({
|
|
|
1035
1063
|
drawerTestID,
|
|
1036
1064
|
scrimTestID
|
|
1037
1065
|
}) => {
|
|
1038
|
-
const
|
|
1039
|
-
|
|
1066
|
+
const { theme } = uiFeedback.useUi();
|
|
1067
|
+
const panelRef = React2.useRef(null);
|
|
1068
|
+
React2.useEffect(() => {
|
|
1040
1069
|
const node = panelRef.current;
|
|
1041
1070
|
if (node === null || typeof node.addEventListener !== "function") return void 0;
|
|
1042
1071
|
const handleClick = (event) => {
|
|
@@ -1059,7 +1088,17 @@ var MobileDrawer = ({
|
|
|
1059
1088
|
onPress: onClose
|
|
1060
1089
|
}
|
|
1061
1090
|
),
|
|
1062
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1091
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1092
|
+
reactNative.View,
|
|
1093
|
+
{
|
|
1094
|
+
ref: panelRef,
|
|
1095
|
+
"aria-modal": true,
|
|
1096
|
+
role: "dialog",
|
|
1097
|
+
style: [styles2.panel, { backgroundColor: theme.colors.surface }],
|
|
1098
|
+
testID: drawerTestID,
|
|
1099
|
+
children: renderTextSlot(sidebar, { color: theme.colors.text })
|
|
1100
|
+
}
|
|
1101
|
+
)
|
|
1063
1102
|
] });
|
|
1064
1103
|
};
|
|
1065
1104
|
|
|
@@ -1131,15 +1170,15 @@ var AppShell = ({
|
|
|
1131
1170
|
range: railRange
|
|
1132
1171
|
});
|
|
1133
1172
|
const useDrawer = railMode === "drawer";
|
|
1134
|
-
const [drawerOpen, setDrawerOpen] =
|
|
1135
|
-
const openDrawer =
|
|
1136
|
-
const closeDrawer =
|
|
1137
|
-
|
|
1173
|
+
const [drawerOpen, setDrawerOpen] = React2.useState(false);
|
|
1174
|
+
const openDrawer = React2.useCallback(() => setDrawerOpen(true), []);
|
|
1175
|
+
const closeDrawer = React2.useCallback(() => setDrawerOpen(false), []);
|
|
1176
|
+
React2.useEffect(() => {
|
|
1138
1177
|
if (!useDrawer && drawerOpen) setDrawerOpen(false);
|
|
1139
1178
|
}, [useDrawer, drawerOpen]);
|
|
1140
1179
|
const drawerLabels = { ...DEFAULT_DRAWER_LABELS, ...mobileMenu };
|
|
1141
1180
|
const isUnauthenticated = gate !== void 0 && !gate.pending && !gate.authenticated;
|
|
1142
|
-
|
|
1181
|
+
React2.useEffect(() => {
|
|
1143
1182
|
if (isUnauthenticated && gate !== void 0) gate.onRedirect();
|
|
1144
1183
|
}, [isUnauthenticated, gate]);
|
|
1145
1184
|
if (gate?.pending === true)
|
|
@@ -1166,13 +1205,13 @@ var AppShell = ({
|
|
|
1166
1205
|
onOpen: openDrawer
|
|
1167
1206
|
}
|
|
1168
1207
|
),
|
|
1169
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles3.headerFill, children: header })
|
|
1170
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { testID: `${testID}${APP_SHELL_SUFFIX.header}`, children: header });
|
|
1171
|
-
const railRegion = railMode === "full" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { testID: `${testID}${APP_SHELL_SUFFIX.sidebar}`, children: sidebar }) : railMode === "collapsed" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { testID: `${testID}${APP_SHELL_SUFFIX.collapsedSidebar}`, children: collapsedSidebar }) : null;
|
|
1208
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles3.headerFill, children: renderTextSlot(header, { color: theme.colors.text }) })
|
|
1209
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { testID: `${testID}${APP_SHELL_SUFFIX.header}`, children: renderTextSlot(header, { color: theme.colors.text }) });
|
|
1210
|
+
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;
|
|
1172
1211
|
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles3.root, { backgroundColor: theme.colors.background }], testID, children: [
|
|
1173
1212
|
headerRegion,
|
|
1174
|
-
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: nav }) : nav }) : null,
|
|
1175
|
-
banner !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { testID: `${testID}${APP_SHELL_SUFFIX.banner}`, children: banner }) : null,
|
|
1213
|
+
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,
|
|
1214
|
+
banner !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { testID: `${testID}${APP_SHELL_SUFFIX.banner}`, children: renderTextSlot(banner, { color: theme.colors.text }) }) : null,
|
|
1176
1215
|
railRegion !== null ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.bodyRow, children: [
|
|
1177
1216
|
railRegion,
|
|
1178
1217
|
scroller
|
|
@@ -1218,7 +1257,7 @@ var CollapsedRail = ({
|
|
|
1218
1257
|
containerStyle
|
|
1219
1258
|
],
|
|
1220
1259
|
children: [
|
|
1221
|
-
header !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: collapsedRailStyles.slot, children: header }) : null,
|
|
1260
|
+
header !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: collapsedRailStyles.slot, children: renderTextSlot(header, { color: colors.text }) }) : null,
|
|
1222
1261
|
items.map((item) => {
|
|
1223
1262
|
const active = isRouteActive(pathname, item.route);
|
|
1224
1263
|
const iconColor = active ? primaryColor : colors.textSecondary;
|
|
@@ -1237,7 +1276,7 @@ var CollapsedRail = ({
|
|
|
1237
1276
|
);
|
|
1238
1277
|
}),
|
|
1239
1278
|
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: collapsedRailStyles.spacer }),
|
|
1240
|
-
footer !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: collapsedRailStyles.slot, children: footer }) : null
|
|
1279
|
+
footer !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: collapsedRailStyles.slot, children: renderTextSlot(footer, { color: colors.text }) }) : null
|
|
1241
1280
|
]
|
|
1242
1281
|
}
|
|
1243
1282
|
);
|
|
@@ -1391,7 +1430,7 @@ var DarkModeControl = ({
|
|
|
1391
1430
|
const primaryColor = theme.palette.primary["500"];
|
|
1392
1431
|
const currentIndex = options.findIndex((option) => option.value === value);
|
|
1393
1432
|
const current = currentIndex >= 0 ? options[currentIndex] : options[0];
|
|
1394
|
-
const advance =
|
|
1433
|
+
const advance = React2.useCallback(() => {
|
|
1395
1434
|
if (options.length === 0) return;
|
|
1396
1435
|
const from = currentIndex >= 0 ? currentIndex : 0;
|
|
1397
1436
|
const next = options[(from + 1) % options.length];
|