@dloizides/ui-nav 1.7.0 → 1.9.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/ADOPTION.md +83 -0
- package/CHANGELOG.md +73 -0
- package/README.md +97 -0
- package/dist/index.d.mts +550 -79
- package/dist/index.d.ts +550 -79
- package/dist/index.js +445 -71
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +438 -74
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -161,6 +161,86 @@ var navBarStyles = reactNative.StyleSheet.create({
|
|
|
161
161
|
columnGap: 8
|
|
162
162
|
}
|
|
163
163
|
});
|
|
164
|
+
var pillNavStyles = reactNative.StyleSheet.create({
|
|
165
|
+
// Cross-nav pill row (kefi coral dashboard switcher): fully-rounded pills, wraps.
|
|
166
|
+
container: {
|
|
167
|
+
flexDirection: "row",
|
|
168
|
+
flexWrap: "wrap",
|
|
169
|
+
alignItems: "center",
|
|
170
|
+
columnGap: 8,
|
|
171
|
+
rowGap: 8,
|
|
172
|
+
paddingVertical: 8
|
|
173
|
+
},
|
|
174
|
+
pill: {
|
|
175
|
+
paddingHorizontal: 16,
|
|
176
|
+
paddingVertical: 8,
|
|
177
|
+
borderRadius: 999,
|
|
178
|
+
minHeight: 36,
|
|
179
|
+
flexDirection: "row",
|
|
180
|
+
alignItems: "center",
|
|
181
|
+
columnGap: 6,
|
|
182
|
+
justifyContent: "center"
|
|
183
|
+
},
|
|
184
|
+
pillText: { fontSize: 14, fontWeight: "600" }
|
|
185
|
+
});
|
|
186
|
+
var darkModeStyles = reactNative.StyleSheet.create({
|
|
187
|
+
// Segmented Light / Dark / System control.
|
|
188
|
+
segmentRow: {
|
|
189
|
+
flexDirection: "row",
|
|
190
|
+
alignItems: "center",
|
|
191
|
+
borderWidth: 1,
|
|
192
|
+
borderRadius: 8,
|
|
193
|
+
overflow: "hidden",
|
|
194
|
+
alignSelf: "flex-start"
|
|
195
|
+
},
|
|
196
|
+
segment: {
|
|
197
|
+
paddingHorizontal: 12,
|
|
198
|
+
paddingVertical: 8,
|
|
199
|
+
minHeight: 36,
|
|
200
|
+
flexDirection: "row",
|
|
201
|
+
alignItems: "center",
|
|
202
|
+
columnGap: 6,
|
|
203
|
+
justifyContent: "center"
|
|
204
|
+
},
|
|
205
|
+
segmentText: { fontSize: 13, fontWeight: "600" },
|
|
206
|
+
// Cycle-button variant.
|
|
207
|
+
cycle: {
|
|
208
|
+
paddingHorizontal: 12,
|
|
209
|
+
paddingVertical: 8,
|
|
210
|
+
minHeight: 44,
|
|
211
|
+
minWidth: 44,
|
|
212
|
+
borderRadius: 8,
|
|
213
|
+
flexDirection: "row",
|
|
214
|
+
alignItems: "center",
|
|
215
|
+
columnGap: 6,
|
|
216
|
+
justifyContent: "center"
|
|
217
|
+
},
|
|
218
|
+
cycleText: { fontSize: 13, fontWeight: "600" }
|
|
219
|
+
});
|
|
220
|
+
var collapsedRailStyles = reactNative.StyleSheet.create({
|
|
221
|
+
// Intermediate (tablet) icon-only rail: a narrow vertical strip of icon buttons.
|
|
222
|
+
container: {
|
|
223
|
+
width: 64,
|
|
224
|
+
paddingTop: 16,
|
|
225
|
+
paddingHorizontal: 8,
|
|
226
|
+
borderRightWidth: 1,
|
|
227
|
+
height: "100%",
|
|
228
|
+
alignItems: "center"
|
|
229
|
+
},
|
|
230
|
+
// Each item is a ≥44×44 centred touch target with a rounded active/hover pill.
|
|
231
|
+
item: {
|
|
232
|
+
width: 48,
|
|
233
|
+
height: 48,
|
|
234
|
+
marginVertical: 4,
|
|
235
|
+
borderRadius: 8,
|
|
236
|
+
alignItems: "center",
|
|
237
|
+
justifyContent: "center"
|
|
238
|
+
},
|
|
239
|
+
// Glyph fallback (the label's first character) when an item has no renderIcon.
|
|
240
|
+
glyph: { fontSize: 18, fontWeight: "700" },
|
|
241
|
+
spacer: { flex: 1 },
|
|
242
|
+
slot: { alignItems: "center" }
|
|
243
|
+
});
|
|
164
244
|
var expandableStyles = reactNative.StyleSheet.create({
|
|
165
245
|
childItem: {
|
|
166
246
|
borderRadius: 4,
|
|
@@ -377,6 +457,8 @@ var APP_SHELL_SUFFIX = {
|
|
|
377
457
|
nav: "-nav",
|
|
378
458
|
/** The persistent left rail of the back-office layout (only when `sidebar` is supplied). */
|
|
379
459
|
sidebar: "-sidebar",
|
|
460
|
+
/** The intermediate persistent COLLAPSED (icon-only) rail (3-tier layout, tablet band). */
|
|
461
|
+
collapsedSidebar: "-collapsed-sidebar",
|
|
380
462
|
/** Mobile hamburger that opens the nav drawer (back-office layout, below the breakpoint). */
|
|
381
463
|
menuToggle: "-menu-toggle",
|
|
382
464
|
/** The mobile nav drawer panel (holds the `sidebar` slot when opened on a narrow viewport). */
|
|
@@ -710,7 +792,7 @@ var MENU_GLYPH = "\u2630";
|
|
|
710
792
|
function ariaControlsProps(id) {
|
|
711
793
|
return { "aria-controls": id };
|
|
712
794
|
}
|
|
713
|
-
var
|
|
795
|
+
var NavBarInner = ({
|
|
714
796
|
items,
|
|
715
797
|
pathname,
|
|
716
798
|
onNavigate,
|
|
@@ -724,7 +806,8 @@ var NavBar = ({
|
|
|
724
806
|
collapseBelow = DEFAULT_COLLAPSE_BELOW,
|
|
725
807
|
overflowLabel = "More",
|
|
726
808
|
overflowHint = "",
|
|
727
|
-
containerStyle
|
|
809
|
+
containerStyle,
|
|
810
|
+
contentMaxWidth
|
|
728
811
|
}) => {
|
|
729
812
|
const { theme } = uiFeedback.useUi();
|
|
730
813
|
const colors = theme.colors;
|
|
@@ -736,6 +819,10 @@ var NavBar = ({
|
|
|
736
819
|
const { visibleCount, setAvailableWidth, setItemWidth, setMoreWidth } = useNavOverflow(items.length, NAV_LINK_GAP);
|
|
737
820
|
const collapsed = width < collapseBelow;
|
|
738
821
|
const showLinks = !collapsed || open;
|
|
822
|
+
const innerCapStyle = React5.useMemo(
|
|
823
|
+
() => contentMaxWidth === void 0 ? null : { maxWidth: contentMaxWidth, width: "100%", alignSelf: "center" },
|
|
824
|
+
[contentMaxWidth]
|
|
825
|
+
);
|
|
739
826
|
const toggleMenu = React5.useCallback(() => setOpen((v) => !v), []);
|
|
740
827
|
const handlePress = React5.useCallback(
|
|
741
828
|
(route) => {
|
|
@@ -765,7 +852,7 @@ var NavBar = ({
|
|
|
765
852
|
{ backgroundColor: colors.surface, borderBottomColor: colors.border },
|
|
766
853
|
containerStyle
|
|
767
854
|
],
|
|
768
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [navBarStyles.inner, collapsed ? null : navBarStyles.innerNoWrap], children: [
|
|
855
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [navBarStyles.inner, collapsed ? null : navBarStyles.innerNoWrap, innerCapStyle], children: [
|
|
769
856
|
brand !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: navBarStyles.brand, children: brand }) : null,
|
|
770
857
|
collapsed ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
771
858
|
reactNative.Pressable,
|
|
@@ -848,13 +935,57 @@ var NavBar = ({
|
|
|
848
935
|
}
|
|
849
936
|
);
|
|
850
937
|
};
|
|
938
|
+
var NavBar = ({ barTheme, ...props }) => {
|
|
939
|
+
const { t, navigate } = uiFeedback.useUi();
|
|
940
|
+
if (barTheme === void 0) return /* @__PURE__ */ jsxRuntime.jsx(NavBarInner, { ...props });
|
|
941
|
+
return /* @__PURE__ */ jsxRuntime.jsx(uiFeedback.UiProvider, { navigate, t, theme: barTheme, children: /* @__PURE__ */ jsxRuntime.jsx(NavBarInner, { ...props }) });
|
|
942
|
+
};
|
|
851
943
|
var Nav = (props) => {
|
|
852
944
|
if (props.orientation === "vertical") {
|
|
853
945
|
return /* @__PURE__ */ jsxRuntime.jsx(Sidebar, { ...props });
|
|
854
946
|
}
|
|
855
947
|
return /* @__PURE__ */ jsxRuntime.jsx(NavBar, { ...props });
|
|
856
948
|
};
|
|
857
|
-
var
|
|
949
|
+
var CARD_PADDING = 20;
|
|
950
|
+
var CARD_BORDER_RADIUS = 12;
|
|
951
|
+
var CARD_BORDER_WIDTH = 1;
|
|
952
|
+
var CARD_TITLE_FONT_SIZE = 16;
|
|
953
|
+
var CARD_MESSAGE_FONT_SIZE = 14;
|
|
954
|
+
var CARD_TITLE_MARGIN_BOTTOM = 8;
|
|
955
|
+
var styles = reactNative.StyleSheet.create({
|
|
956
|
+
centerFill: { flex: 1, justifyContent: "center", alignItems: "center" },
|
|
957
|
+
card: {
|
|
958
|
+
padding: CARD_PADDING,
|
|
959
|
+
borderRadius: CARD_BORDER_RADIUS,
|
|
960
|
+
borderWidth: CARD_BORDER_WIDTH
|
|
961
|
+
},
|
|
962
|
+
cardTitle: { fontSize: CARD_TITLE_FONT_SIZE, fontWeight: "700", marginBottom: CARD_TITLE_MARGIN_BOTTOM },
|
|
963
|
+
cardMessage: { fontSize: CARD_MESSAGE_FONT_SIZE }
|
|
964
|
+
});
|
|
965
|
+
function MessageCard({
|
|
966
|
+
message,
|
|
967
|
+
accentColor,
|
|
968
|
+
testID
|
|
969
|
+
}) {
|
|
970
|
+
const { theme } = uiFeedback.useUi();
|
|
971
|
+
const colors = theme.colors;
|
|
972
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles.card, { backgroundColor: colors.surface, borderColor: accentColor }], testID, children: [
|
|
973
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles.cardTitle, { color: accentColor }], children: message.titleText }),
|
|
974
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles.cardMessage, { color: colors.textSecondary }], children: message.messageText })
|
|
975
|
+
] });
|
|
976
|
+
}
|
|
977
|
+
function useContentBody(state, children, testID) {
|
|
978
|
+
const { theme } = uiFeedback.useUi();
|
|
979
|
+
const primary = theme.palette.primary["500"];
|
|
980
|
+
const errorColor = theme.semantic.error["500"];
|
|
981
|
+
if (state?.forbidden)
|
|
982
|
+
return /* @__PURE__ */ jsxRuntime.jsx(MessageCard, { accentColor: errorColor, message: state.forbidden, testID: `${testID}${APP_SHELL_SUFFIX.forbidden}` });
|
|
983
|
+
if (state?.error)
|
|
984
|
+
return /* @__PURE__ */ jsxRuntime.jsx(MessageCard, { accentColor: errorColor, message: state.error, testID: `${testID}${APP_SHELL_SUFFIX.error}` });
|
|
985
|
+
if (state?.loading === true)
|
|
986
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles.centerFill, testID: `${testID}${APP_SHELL_SUFFIX.loading}`, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: primary, size: "large" }) });
|
|
987
|
+
return children;
|
|
988
|
+
}
|
|
858
989
|
var SCRIM_COLOR = "rgba(0, 0, 0, 0.5)";
|
|
859
990
|
var MENU_GLYPH2 = "\u2630";
|
|
860
991
|
var MENU_MIN_TARGET = 44;
|
|
@@ -868,7 +999,7 @@ var DEFAULT_DRAWER_LABELS = {
|
|
|
868
999
|
closeLabel: "Close menu",
|
|
869
1000
|
closeHint: "Close the navigation menu"
|
|
870
1001
|
};
|
|
871
|
-
var
|
|
1002
|
+
var styles2 = reactNative.StyleSheet.create({
|
|
872
1003
|
overlay: { ...reactNative.StyleSheet.absoluteFillObject, zIndex: DRAWER_Z_INDEX },
|
|
873
1004
|
scrim: { ...reactNative.StyleSheet.absoluteFillObject, backgroundColor: SCRIM_COLOR },
|
|
874
1005
|
panel: { position: "absolute", top: 0, bottom: 0, left: 0 },
|
|
@@ -889,10 +1020,10 @@ var MenuToggle = ({ label, hint, onOpen, testID }) => {
|
|
|
889
1020
|
accessibilityHint: hint,
|
|
890
1021
|
accessibilityLabel: label,
|
|
891
1022
|
ringColor: theme.palette.primary["500"],
|
|
892
|
-
style:
|
|
1023
|
+
style: styles2.menuToggle,
|
|
893
1024
|
testID,
|
|
894
1025
|
onPress: onOpen,
|
|
895
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [
|
|
1026
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles2.menuToggleGlyph, { color: theme.colors.text }], children: MENU_GLYPH2 })
|
|
896
1027
|
}
|
|
897
1028
|
);
|
|
898
1029
|
};
|
|
@@ -915,21 +1046,34 @@ var MobileDrawer = ({
|
|
|
915
1046
|
node.addEventListener("click", handleClick);
|
|
916
1047
|
return () => node.removeEventListener("click", handleClick);
|
|
917
1048
|
}, [onClose]);
|
|
918
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
1049
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles2.overlay, children: [
|
|
919
1050
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
920
1051
|
reactNative.Pressable,
|
|
921
1052
|
{
|
|
922
1053
|
accessibilityHint: labels.closeHint,
|
|
923
1054
|
accessibilityLabel: labels.closeLabel,
|
|
924
1055
|
accessibilityRole: "button",
|
|
925
|
-
style:
|
|
1056
|
+
style: styles2.scrim,
|
|
926
1057
|
testID: scrimTestID,
|
|
927
1058
|
onPress: onClose
|
|
928
1059
|
}
|
|
929
1060
|
),
|
|
930
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { ref: panelRef, "aria-modal": true, role: "dialog", style:
|
|
1061
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { ref: panelRef, "aria-modal": true, role: "dialog", style: styles2.panel, testID: drawerTestID, children: sidebar })
|
|
931
1062
|
] });
|
|
932
1063
|
};
|
|
1064
|
+
|
|
1065
|
+
// src/railMode.ts
|
|
1066
|
+
var RAIL_FULL_BREAKPOINT = 768;
|
|
1067
|
+
var DEFAULT_COLLAPSED_RAIL_MAX = 1024;
|
|
1068
|
+
function resolveRailMode({ viewport, hasSidebar, hasCollapsed, range }) {
|
|
1069
|
+
if (!hasSidebar) return "none";
|
|
1070
|
+
if (hasCollapsed) {
|
|
1071
|
+
if (viewport >= range.max) return "full";
|
|
1072
|
+
if (viewport >= range.min) return "collapsed";
|
|
1073
|
+
return "drawer";
|
|
1074
|
+
}
|
|
1075
|
+
return viewport >= RAIL_FULL_BREAKPOINT ? "full" : "drawer";
|
|
1076
|
+
}
|
|
933
1077
|
function resolveContentMaxWidth(width, viewport) {
|
|
934
1078
|
if (width === "full") return "full";
|
|
935
1079
|
const wideMinViewport = width.wideMinViewport ?? Number.POSITIVE_INFINITY;
|
|
@@ -941,13 +1085,7 @@ function useContentMaxWidth(width) {
|
|
|
941
1085
|
return resolveContentMaxWidth(width, viewport);
|
|
942
1086
|
}
|
|
943
1087
|
var DEFAULT_CONTENT_PADDING = 24;
|
|
944
|
-
var
|
|
945
|
-
var CARD_BORDER_RADIUS = 12;
|
|
946
|
-
var CARD_BORDER_WIDTH = 1;
|
|
947
|
-
var CARD_TITLE_FONT_SIZE = 16;
|
|
948
|
-
var CARD_MESSAGE_FONT_SIZE = 14;
|
|
949
|
-
var CARD_TITLE_MARGIN_BOTTOM = 8;
|
|
950
|
-
var styles2 = reactNative.StyleSheet.create({
|
|
1088
|
+
var styles3 = reactNative.StyleSheet.create({
|
|
951
1089
|
root: { flex: 1 },
|
|
952
1090
|
centerFill: { flex: 1, justifyContent: "center", alignItems: "center" },
|
|
953
1091
|
scroll: { flex: 1 },
|
|
@@ -961,50 +1099,14 @@ var styles2 = reactNative.StyleSheet.create({
|
|
|
961
1099
|
columnCapped: { flex: 1, width: "100%", alignSelf: "center" },
|
|
962
1100
|
// Non-flex variant used to cap the nav strip's inner content to the content
|
|
963
1101
|
// column so the nav aligns with the page content instead of running full-bleed.
|
|
964
|
-
chromeCapped: { width: "100%", alignSelf: "center" }
|
|
965
|
-
card: {
|
|
966
|
-
padding: CARD_PADDING,
|
|
967
|
-
borderRadius: CARD_BORDER_RADIUS,
|
|
968
|
-
borderWidth: CARD_BORDER_WIDTH
|
|
969
|
-
},
|
|
970
|
-
cardTitle: { fontSize: CARD_TITLE_FONT_SIZE, fontWeight: "700", marginBottom: CARD_TITLE_MARGIN_BOTTOM },
|
|
971
|
-
cardMessage: { fontSize: CARD_MESSAGE_FONT_SIZE }
|
|
1102
|
+
chromeCapped: { width: "100%", alignSelf: "center" }
|
|
972
1103
|
});
|
|
973
|
-
function MessageCard({
|
|
974
|
-
message,
|
|
975
|
-
accentColor,
|
|
976
|
-
testID
|
|
977
|
-
}) {
|
|
978
|
-
const { theme } = uiFeedback.useUi();
|
|
979
|
-
const colors = theme.colors;
|
|
980
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
981
|
-
reactNative.View,
|
|
982
|
-
{
|
|
983
|
-
style: [styles2.card, { backgroundColor: colors.surface, borderColor: accentColor }],
|
|
984
|
-
testID,
|
|
985
|
-
children: [
|
|
986
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles2.cardTitle, { color: accentColor }], children: message.titleText }),
|
|
987
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles2.cardMessage, { color: colors.textSecondary }], children: message.messageText })
|
|
988
|
-
]
|
|
989
|
-
}
|
|
990
|
-
);
|
|
991
|
-
}
|
|
992
|
-
function useContentBody(state, children, testID) {
|
|
993
|
-
const { theme } = uiFeedback.useUi();
|
|
994
|
-
const primary = theme.palette.primary["500"];
|
|
995
|
-
const errorColor = theme.semantic.error["500"];
|
|
996
|
-
if (state?.forbidden)
|
|
997
|
-
return /* @__PURE__ */ jsxRuntime.jsx(MessageCard, { accentColor: errorColor, message: state.forbidden, testID: `${testID}${APP_SHELL_SUFFIX.forbidden}` });
|
|
998
|
-
if (state?.error)
|
|
999
|
-
return /* @__PURE__ */ jsxRuntime.jsx(MessageCard, { accentColor: errorColor, message: state.error, testID: `${testID}${APP_SHELL_SUFFIX.error}` });
|
|
1000
|
-
if (state?.loading === true)
|
|
1001
|
-
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" }) });
|
|
1002
|
-
return children;
|
|
1003
|
-
}
|
|
1004
1104
|
var AppShell = ({
|
|
1005
1105
|
header,
|
|
1006
1106
|
nav,
|
|
1007
1107
|
sidebar,
|
|
1108
|
+
collapsedSidebar,
|
|
1109
|
+
collapsedRailRange,
|
|
1008
1110
|
mobileMenu,
|
|
1009
1111
|
banner,
|
|
1010
1112
|
width = "full",
|
|
@@ -1020,34 +1122,40 @@ var AppShell = ({
|
|
|
1020
1122
|
const maxWidth = useContentMaxWidth(width);
|
|
1021
1123
|
const body = useContentBody(state, children, testID);
|
|
1022
1124
|
const { width: viewportWidth } = reactNative.useWindowDimensions();
|
|
1023
|
-
const
|
|
1024
|
-
const
|
|
1125
|
+
const railRange = collapsedRailRange ?? { min: RAIL_FULL_BREAKPOINT, max: DEFAULT_COLLAPSED_RAIL_MAX };
|
|
1126
|
+
const railMode = resolveRailMode({
|
|
1127
|
+
viewport: viewportWidth,
|
|
1128
|
+
hasSidebar: sidebar !== void 0,
|
|
1129
|
+
hasCollapsed: collapsedSidebar !== void 0,
|
|
1130
|
+
range: railRange
|
|
1131
|
+
});
|
|
1132
|
+
const useDrawer = railMode === "drawer";
|
|
1025
1133
|
const [drawerOpen, setDrawerOpen] = React5.useState(false);
|
|
1026
1134
|
const openDrawer = React5.useCallback(() => setDrawerOpen(true), []);
|
|
1027
1135
|
const closeDrawer = React5.useCallback(() => setDrawerOpen(false), []);
|
|
1028
1136
|
React5.useEffect(() => {
|
|
1029
|
-
if (!
|
|
1030
|
-
}, [
|
|
1137
|
+
if (!useDrawer && drawerOpen) setDrawerOpen(false);
|
|
1138
|
+
}, [useDrawer, drawerOpen]);
|
|
1031
1139
|
const drawerLabels = { ...DEFAULT_DRAWER_LABELS, ...mobileMenu };
|
|
1032
1140
|
const isUnauthenticated = gate !== void 0 && !gate.pending && !gate.authenticated;
|
|
1033
1141
|
React5.useEffect(() => {
|
|
1034
1142
|
if (isUnauthenticated && gate !== void 0) gate.onRedirect();
|
|
1035
1143
|
}, [isUnauthenticated, gate]);
|
|
1036
1144
|
if (gate?.pending === true)
|
|
1037
|
-
return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [
|
|
1145
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles3.root, styles3.centerFill, { backgroundColor: theme.colors.background }], testID: `${testID}${APP_SHELL_SUFFIX.pending}`, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: primary, size: "large" }) });
|
|
1038
1146
|
if (isUnauthenticated) return null;
|
|
1039
|
-
const columnStyle = maxWidth === "full" ?
|
|
1040
|
-
const navInnerStyle = chromeAlignment === "content" && maxWidth !== "full" ? [
|
|
1147
|
+
const columnStyle = maxWidth === "full" ? styles3.columnFull : [styles3.columnCapped, { maxWidth }];
|
|
1148
|
+
const navInnerStyle = chromeAlignment === "content" && maxWidth !== "full" ? [styles3.chromeCapped, { maxWidth, paddingHorizontal: contentPadding }] : void 0;
|
|
1041
1149
|
const scroller = /* @__PURE__ */ jsxRuntime.jsx(
|
|
1042
1150
|
reactNative.ScrollView,
|
|
1043
1151
|
{
|
|
1044
|
-
contentContainerStyle: [
|
|
1045
|
-
style:
|
|
1152
|
+
contentContainerStyle: [styles3.scrollContent, { padding: contentPadding }],
|
|
1153
|
+
style: styles3.scroll,
|
|
1046
1154
|
testID: `${testID}${APP_SHELL_SUFFIX.content}`,
|
|
1047
1155
|
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: columnStyle, children: body })
|
|
1048
1156
|
}
|
|
1049
1157
|
);
|
|
1050
|
-
const headerRegion = useDrawer ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
1158
|
+
const headerRegion = useDrawer ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.headerRow, testID: `${testID}${APP_SHELL_SUFFIX.header}`, children: [
|
|
1051
1159
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1052
1160
|
MenuToggle,
|
|
1053
1161
|
{
|
|
@@ -1057,15 +1165,15 @@ var AppShell = ({
|
|
|
1057
1165
|
onOpen: openDrawer
|
|
1058
1166
|
}
|
|
1059
1167
|
),
|
|
1060
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style:
|
|
1168
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles3.headerFill, children: header })
|
|
1061
1169
|
] }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { testID: `${testID}${APP_SHELL_SUFFIX.header}`, children: header });
|
|
1062
|
-
const
|
|
1063
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [
|
|
1170
|
+
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;
|
|
1171
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles3.root, { backgroundColor: theme.colors.background }], testID, children: [
|
|
1064
1172
|
headerRegion,
|
|
1065
1173
|
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,
|
|
1066
1174
|
banner !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { testID: `${testID}${APP_SHELL_SUFFIX.banner}`, children: banner }) : null,
|
|
1067
|
-
|
|
1068
|
-
|
|
1175
|
+
railRegion !== null ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.bodyRow, children: [
|
|
1176
|
+
railRegion,
|
|
1069
1177
|
scroller
|
|
1070
1178
|
] }) : scroller,
|
|
1071
1179
|
useDrawer && drawerOpen ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1080,6 +1188,262 @@ var AppShell = ({
|
|
|
1080
1188
|
) : null
|
|
1081
1189
|
] });
|
|
1082
1190
|
};
|
|
1191
|
+
var COLLAPSED_ICON_SIZE = 22;
|
|
1192
|
+
function glyphFor(label) {
|
|
1193
|
+
return label.trim().charAt(0).toUpperCase();
|
|
1194
|
+
}
|
|
1195
|
+
var CollapsedRail = ({
|
|
1196
|
+
items,
|
|
1197
|
+
pathname,
|
|
1198
|
+
onNavigate,
|
|
1199
|
+
regionLabel,
|
|
1200
|
+
navigateHint = (label) => label,
|
|
1201
|
+
header,
|
|
1202
|
+
footer,
|
|
1203
|
+
containerStyle
|
|
1204
|
+
}) => {
|
|
1205
|
+
const { theme } = uiFeedback.useUi();
|
|
1206
|
+
const colors = theme.colors;
|
|
1207
|
+
const primaryColor = theme.palette.primary["500"];
|
|
1208
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1209
|
+
reactNative.View,
|
|
1210
|
+
{
|
|
1211
|
+
accessibilityRole: "none",
|
|
1212
|
+
"aria-label": regionLabel,
|
|
1213
|
+
role: "navigation",
|
|
1214
|
+
style: [
|
|
1215
|
+
collapsedRailStyles.container,
|
|
1216
|
+
{ backgroundColor: colors.surface, borderRightColor: colors.border },
|
|
1217
|
+
containerStyle
|
|
1218
|
+
],
|
|
1219
|
+
children: [
|
|
1220
|
+
header !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: collapsedRailStyles.slot, children: header }) : null,
|
|
1221
|
+
items.map((item) => {
|
|
1222
|
+
const active = isRouteActive(pathname, item.route);
|
|
1223
|
+
const iconColor = active ? primaryColor : colors.textSecondary;
|
|
1224
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1225
|
+
FocusableTouchable,
|
|
1226
|
+
{
|
|
1227
|
+
accessibilityHint: navigateHint(item.label),
|
|
1228
|
+
accessibilityLabel: item.label,
|
|
1229
|
+
ringColor: primaryColor,
|
|
1230
|
+
style: [collapsedRailStyles.item, active ? { backgroundColor: colors.border } : void 0],
|
|
1231
|
+
testID: item.testID ?? item.key,
|
|
1232
|
+
onPress: () => onNavigate(item.route),
|
|
1233
|
+
children: typeof item.renderIcon === "function" ? item.renderIcon(iconColor, COLLAPSED_ICON_SIZE) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [collapsedRailStyles.glyph, { color: iconColor }], children: glyphFor(item.label) })
|
|
1234
|
+
},
|
|
1235
|
+
item.key
|
|
1236
|
+
);
|
|
1237
|
+
}),
|
|
1238
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: collapsedRailStyles.spacer }),
|
|
1239
|
+
footer !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: collapsedRailStyles.slot, children: footer }) : null
|
|
1240
|
+
]
|
|
1241
|
+
}
|
|
1242
|
+
);
|
|
1243
|
+
};
|
|
1244
|
+
function wantsTopBar(layout, hasHeader, hasTopBar) {
|
|
1245
|
+
return layout === "top" || layout === "both" || hasHeader || layout === "side" && hasTopBar;
|
|
1246
|
+
}
|
|
1247
|
+
function wantsSideRail(layout, hasSideRail) {
|
|
1248
|
+
return (layout === "side" || layout === "both") && hasSideRail;
|
|
1249
|
+
}
|
|
1250
|
+
var NavShell = ({
|
|
1251
|
+
layout,
|
|
1252
|
+
pathname,
|
|
1253
|
+
onNavigate,
|
|
1254
|
+
regionLabel,
|
|
1255
|
+
navigateHint,
|
|
1256
|
+
topBar,
|
|
1257
|
+
header,
|
|
1258
|
+
sideRail,
|
|
1259
|
+
children,
|
|
1260
|
+
collapsedSidebar: collapsedSidebarProp,
|
|
1261
|
+
collapsedRailRange: collapsedRailRangeProp,
|
|
1262
|
+
...shellProps
|
|
1263
|
+
}) => {
|
|
1264
|
+
const showTopBar = wantsTopBar(layout, header !== void 0, topBar !== void 0);
|
|
1265
|
+
const showSideRail = wantsSideRail(layout, sideRail !== void 0);
|
|
1266
|
+
const headerNode = header !== void 0 ? header : showTopBar && topBar !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1267
|
+
NavBar,
|
|
1268
|
+
{
|
|
1269
|
+
barTheme: topBar.barTheme,
|
|
1270
|
+
brand: topBar.brand,
|
|
1271
|
+
collapseBelow: topBar.collapseBelow,
|
|
1272
|
+
containerStyle: topBar.containerStyle,
|
|
1273
|
+
contentMaxWidth: topBar.contentMaxWidth,
|
|
1274
|
+
items: topBar.items,
|
|
1275
|
+
menuHint: topBar.menuHint,
|
|
1276
|
+
menuLabel: topBar.menuLabel,
|
|
1277
|
+
navigateHint,
|
|
1278
|
+
overflowHint: topBar.overflowHint,
|
|
1279
|
+
overflowLabel: topBar.overflowLabel,
|
|
1280
|
+
pathname,
|
|
1281
|
+
regionLabel,
|
|
1282
|
+
renderMenuIcon: topBar.renderMenuIcon,
|
|
1283
|
+
right: topBar.right,
|
|
1284
|
+
onNavigate
|
|
1285
|
+
}
|
|
1286
|
+
) : null;
|
|
1287
|
+
const sidebarNode = showSideRail && sideRail !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1288
|
+
Sidebar,
|
|
1289
|
+
{
|
|
1290
|
+
collapseHint: sideRail.collapseHint,
|
|
1291
|
+
containerStyle: sideRail.containerStyle,
|
|
1292
|
+
expandHint: sideRail.expandHint,
|
|
1293
|
+
footer: sideRail.footer,
|
|
1294
|
+
header: sideRail.header,
|
|
1295
|
+
items: sideRail.items,
|
|
1296
|
+
navigateHint,
|
|
1297
|
+
pathname,
|
|
1298
|
+
regionLabel,
|
|
1299
|
+
renderChevron: sideRail.renderChevron,
|
|
1300
|
+
title: sideRail.title,
|
|
1301
|
+
onNavigate
|
|
1302
|
+
}
|
|
1303
|
+
) : void 0;
|
|
1304
|
+
const collapsedCfg = showSideRail ? sideRail?.collapsed : void 0;
|
|
1305
|
+
const collapsedNode = collapsedCfg !== void 0 && sideRail !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1306
|
+
CollapsedRail,
|
|
1307
|
+
{
|
|
1308
|
+
footer: collapsedCfg.footer,
|
|
1309
|
+
header: collapsedCfg.header,
|
|
1310
|
+
items: collapsedCfg.items ?? sideRail.items,
|
|
1311
|
+
navigateHint,
|
|
1312
|
+
pathname,
|
|
1313
|
+
regionLabel,
|
|
1314
|
+
onNavigate
|
|
1315
|
+
}
|
|
1316
|
+
) : collapsedSidebarProp;
|
|
1317
|
+
const collapsedRange = collapsedCfg?.range ?? collapsedRailRangeProp;
|
|
1318
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1319
|
+
AppShell,
|
|
1320
|
+
{
|
|
1321
|
+
...shellProps,
|
|
1322
|
+
collapsedRailRange: collapsedRange,
|
|
1323
|
+
collapsedSidebar: collapsedNode,
|
|
1324
|
+
header: headerNode,
|
|
1325
|
+
sidebar: sidebarNode,
|
|
1326
|
+
children
|
|
1327
|
+
}
|
|
1328
|
+
);
|
|
1329
|
+
};
|
|
1330
|
+
var TEXT_ON_PRIMARY4 = "#ffffff";
|
|
1331
|
+
var DEFAULT_MIN_ITEMS = 1;
|
|
1332
|
+
var PillNav = ({
|
|
1333
|
+
items,
|
|
1334
|
+
pathname,
|
|
1335
|
+
onNavigate,
|
|
1336
|
+
regionLabel,
|
|
1337
|
+
navigateHint = (label) => label,
|
|
1338
|
+
minItems = DEFAULT_MIN_ITEMS,
|
|
1339
|
+
containerStyle
|
|
1340
|
+
}) => {
|
|
1341
|
+
const { theme } = uiFeedback.useUi();
|
|
1342
|
+
const colors = theme.colors;
|
|
1343
|
+
const primaryColor = theme.palette.primary["500"];
|
|
1344
|
+
if (items.length < minItems) return null;
|
|
1345
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1346
|
+
reactNative.View,
|
|
1347
|
+
{
|
|
1348
|
+
accessibilityRole: "none",
|
|
1349
|
+
"aria-label": regionLabel,
|
|
1350
|
+
role: "navigation",
|
|
1351
|
+
style: [pillNavStyles.container, containerStyle],
|
|
1352
|
+
children: items.map((item) => {
|
|
1353
|
+
const active = isRouteActive(pathname, item.route);
|
|
1354
|
+
const textColor = active ? TEXT_ON_PRIMARY4 : colors.textSecondary;
|
|
1355
|
+
const pillStyle = active ? { backgroundColor: primaryColor } : { backgroundColor: colors.surfaceElevated };
|
|
1356
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1357
|
+
FocusableTouchable,
|
|
1358
|
+
{
|
|
1359
|
+
accessibilityHint: navigateHint(item.label),
|
|
1360
|
+
accessibilityLabel: item.label,
|
|
1361
|
+
accessibilityRole: "link",
|
|
1362
|
+
ringColor: primaryColor,
|
|
1363
|
+
style: [pillNavStyles.pill, pillStyle],
|
|
1364
|
+
testID: item.testID ?? item.key,
|
|
1365
|
+
onPress: () => onNavigate(item.route),
|
|
1366
|
+
children: [
|
|
1367
|
+
typeof item.renderIcon === "function" ? item.renderIcon(textColor, NAV_ICON_SIZE) : null,
|
|
1368
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [pillNavStyles.pillText, { color: textColor }], children: item.label })
|
|
1369
|
+
]
|
|
1370
|
+
},
|
|
1371
|
+
item.key
|
|
1372
|
+
);
|
|
1373
|
+
})
|
|
1374
|
+
}
|
|
1375
|
+
);
|
|
1376
|
+
};
|
|
1377
|
+
var TEXT_ON_PRIMARY5 = "#ffffff";
|
|
1378
|
+
var DARK_MODE_ICON_SIZE = 16;
|
|
1379
|
+
var DarkModeControl = ({
|
|
1380
|
+
value,
|
|
1381
|
+
options,
|
|
1382
|
+
onChange,
|
|
1383
|
+
regionLabel,
|
|
1384
|
+
variant = "segmented",
|
|
1385
|
+
testID,
|
|
1386
|
+
containerStyle
|
|
1387
|
+
}) => {
|
|
1388
|
+
const { theme } = uiFeedback.useUi();
|
|
1389
|
+
const colors = theme.colors;
|
|
1390
|
+
const primaryColor = theme.palette.primary["500"];
|
|
1391
|
+
const currentIndex = options.findIndex((option) => option.value === value);
|
|
1392
|
+
const current = currentIndex >= 0 ? options[currentIndex] : options[0];
|
|
1393
|
+
const advance = React5.useCallback(() => {
|
|
1394
|
+
if (options.length === 0) return;
|
|
1395
|
+
const from = currentIndex >= 0 ? currentIndex : 0;
|
|
1396
|
+
const next = options[(from + 1) % options.length];
|
|
1397
|
+
if (next !== void 0) onChange(next.value);
|
|
1398
|
+
}, [options, currentIndex, onChange]);
|
|
1399
|
+
if (options.length === 0 || current === void 0) return null;
|
|
1400
|
+
if (variant === "cycle") {
|
|
1401
|
+
const iconColor = colors.text;
|
|
1402
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { "aria-label": regionLabel, style: containerStyle, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1403
|
+
FocusableTouchable,
|
|
1404
|
+
{
|
|
1405
|
+
accessibilityHint: current.hint,
|
|
1406
|
+
accessibilityLabel: current.label,
|
|
1407
|
+
ringColor: primaryColor,
|
|
1408
|
+
style: [darkModeStyles.cycle, { backgroundColor: colors.surfaceElevated }],
|
|
1409
|
+
testID,
|
|
1410
|
+
onPress: advance,
|
|
1411
|
+
children: [
|
|
1412
|
+
typeof current.renderIcon === "function" ? current.renderIcon(iconColor, DARK_MODE_ICON_SIZE) : null,
|
|
1413
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [darkModeStyles.cycleText, { color: colors.text }], children: current.label })
|
|
1414
|
+
]
|
|
1415
|
+
}
|
|
1416
|
+
) });
|
|
1417
|
+
}
|
|
1418
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1419
|
+
reactNative.View,
|
|
1420
|
+
{
|
|
1421
|
+
"aria-label": regionLabel,
|
|
1422
|
+
role: "group",
|
|
1423
|
+
style: [darkModeStyles.segmentRow, { borderColor: colors.border }, containerStyle],
|
|
1424
|
+
children: options.map((option) => {
|
|
1425
|
+
const active = option.value === value;
|
|
1426
|
+
const textColor = active ? TEXT_ON_PRIMARY5 : colors.textSecondary;
|
|
1427
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1428
|
+
FocusableTouchable,
|
|
1429
|
+
{
|
|
1430
|
+
accessibilityHint: option.hint,
|
|
1431
|
+
accessibilityLabel: option.label,
|
|
1432
|
+
ringColor: primaryColor,
|
|
1433
|
+
style: [darkModeStyles.segment, active ? { backgroundColor: primaryColor } : void 0],
|
|
1434
|
+
testID: testID !== void 0 ? `${testID}-${option.value}` : void 0,
|
|
1435
|
+
onPress: () => onChange(option.value),
|
|
1436
|
+
children: [
|
|
1437
|
+
typeof option.renderIcon === "function" ? option.renderIcon(textColor, DARK_MODE_ICON_SIZE) : null,
|
|
1438
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [darkModeStyles.segmentText, { color: textColor }], children: option.label })
|
|
1439
|
+
]
|
|
1440
|
+
},
|
|
1441
|
+
option.value
|
|
1442
|
+
);
|
|
1443
|
+
})
|
|
1444
|
+
}
|
|
1445
|
+
);
|
|
1446
|
+
};
|
|
1083
1447
|
function roleRoutesToNavItems(routes, translate) {
|
|
1084
1448
|
return routes.map((entry) => ({
|
|
1085
1449
|
key: entry.role,
|
|
@@ -1096,6 +1460,9 @@ exports.APP_SHELL_SUFFIX = APP_SHELL_SUFFIX;
|
|
|
1096
1460
|
exports.AppShell = AppShell;
|
|
1097
1461
|
exports.BASE_INDENT = BASE_INDENT;
|
|
1098
1462
|
exports.CHEVRON_ICON_SIZE = CHEVRON_ICON_SIZE;
|
|
1463
|
+
exports.CollapsedRail = CollapsedRail;
|
|
1464
|
+
exports.DEFAULT_COLLAPSED_RAIL_MAX = DEFAULT_COLLAPSED_RAIL_MAX;
|
|
1465
|
+
exports.DarkModeControl = DarkModeControl;
|
|
1099
1466
|
exports.NAV_ICON_SIZE = NAV_ICON_SIZE;
|
|
1100
1467
|
exports.NAV_LINK_GAP = NAV_LINK_GAP;
|
|
1101
1468
|
exports.NAV_TEST_IDS = NAV_TEST_IDS;
|
|
@@ -1103,13 +1470,20 @@ exports.Nav = Nav;
|
|
|
1103
1470
|
exports.NavBar = NavBar;
|
|
1104
1471
|
exports.NavExpandableItem = NavExpandableItem;
|
|
1105
1472
|
exports.NavOverflowMenu = NavOverflowMenu;
|
|
1473
|
+
exports.NavShell = NavShell;
|
|
1474
|
+
exports.PillNav = PillNav;
|
|
1475
|
+
exports.RAIL_FULL_BREAKPOINT = RAIL_FULL_BREAKPOINT;
|
|
1106
1476
|
exports.Sidebar = Sidebar;
|
|
1107
1477
|
exports.Topbar = Topbar;
|
|
1108
1478
|
exports.accessibleNavItems = accessibleNavItems;
|
|
1479
|
+
exports.collapsedRailStyles = collapsedRailStyles;
|
|
1480
|
+
exports.darkModeStyles = darkModeStyles;
|
|
1109
1481
|
exports.expandableStyles = expandableStyles;
|
|
1110
1482
|
exports.isRouteActive = isRouteActive;
|
|
1111
1483
|
exports.navStyles = navStyles;
|
|
1484
|
+
exports.pillNavStyles = pillNavStyles;
|
|
1112
1485
|
exports.resolveContentMaxWidth = resolveContentMaxWidth;
|
|
1486
|
+
exports.resolveRailMode = resolveRailMode;
|
|
1113
1487
|
exports.roleRoutesToNavItems = roleRoutesToNavItems;
|
|
1114
1488
|
exports.useContentMaxWidth = useContentMaxWidth;
|
|
1115
1489
|
//# sourceMappingURL=index.js.map
|