@dloizides/ui-nav 1.7.0 → 1.8.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 +58 -0
- package/README.md +83 -0
- package/dist/index.d.mts +533 -79
- package/dist/index.d.ts +533 -79
- package/dist/index.js +437 -69
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +430 -72
- 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,
|
|
@@ -848,13 +930,57 @@ var NavBar = ({
|
|
|
848
930
|
}
|
|
849
931
|
);
|
|
850
932
|
};
|
|
933
|
+
var NavBar = ({ barTheme, ...props }) => {
|
|
934
|
+
const { t, navigate } = uiFeedback.useUi();
|
|
935
|
+
if (barTheme === void 0) return /* @__PURE__ */ jsxRuntime.jsx(NavBarInner, { ...props });
|
|
936
|
+
return /* @__PURE__ */ jsxRuntime.jsx(uiFeedback.UiProvider, { navigate, t, theme: barTheme, children: /* @__PURE__ */ jsxRuntime.jsx(NavBarInner, { ...props }) });
|
|
937
|
+
};
|
|
851
938
|
var Nav = (props) => {
|
|
852
939
|
if (props.orientation === "vertical") {
|
|
853
940
|
return /* @__PURE__ */ jsxRuntime.jsx(Sidebar, { ...props });
|
|
854
941
|
}
|
|
855
942
|
return /* @__PURE__ */ jsxRuntime.jsx(NavBar, { ...props });
|
|
856
943
|
};
|
|
857
|
-
var
|
|
944
|
+
var CARD_PADDING = 20;
|
|
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 styles = reactNative.StyleSheet.create({
|
|
951
|
+
centerFill: { flex: 1, justifyContent: "center", alignItems: "center" },
|
|
952
|
+
card: {
|
|
953
|
+
padding: CARD_PADDING,
|
|
954
|
+
borderRadius: CARD_BORDER_RADIUS,
|
|
955
|
+
borderWidth: CARD_BORDER_WIDTH
|
|
956
|
+
},
|
|
957
|
+
cardTitle: { fontSize: CARD_TITLE_FONT_SIZE, fontWeight: "700", marginBottom: CARD_TITLE_MARGIN_BOTTOM },
|
|
958
|
+
cardMessage: { fontSize: CARD_MESSAGE_FONT_SIZE }
|
|
959
|
+
});
|
|
960
|
+
function MessageCard({
|
|
961
|
+
message,
|
|
962
|
+
accentColor,
|
|
963
|
+
testID
|
|
964
|
+
}) {
|
|
965
|
+
const { theme } = uiFeedback.useUi();
|
|
966
|
+
const colors = theme.colors;
|
|
967
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles.card, { backgroundColor: colors.surface, borderColor: accentColor }], testID, children: [
|
|
968
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles.cardTitle, { color: accentColor }], children: message.titleText }),
|
|
969
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles.cardMessage, { color: colors.textSecondary }], children: message.messageText })
|
|
970
|
+
] });
|
|
971
|
+
}
|
|
972
|
+
function useContentBody(state, children, testID) {
|
|
973
|
+
const { theme } = uiFeedback.useUi();
|
|
974
|
+
const primary = theme.palette.primary["500"];
|
|
975
|
+
const errorColor = theme.semantic.error["500"];
|
|
976
|
+
if (state?.forbidden)
|
|
977
|
+
return /* @__PURE__ */ jsxRuntime.jsx(MessageCard, { accentColor: errorColor, message: state.forbidden, testID: `${testID}${APP_SHELL_SUFFIX.forbidden}` });
|
|
978
|
+
if (state?.error)
|
|
979
|
+
return /* @__PURE__ */ jsxRuntime.jsx(MessageCard, { accentColor: errorColor, message: state.error, testID: `${testID}${APP_SHELL_SUFFIX.error}` });
|
|
980
|
+
if (state?.loading === true)
|
|
981
|
+
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" }) });
|
|
982
|
+
return children;
|
|
983
|
+
}
|
|
858
984
|
var SCRIM_COLOR = "rgba(0, 0, 0, 0.5)";
|
|
859
985
|
var MENU_GLYPH2 = "\u2630";
|
|
860
986
|
var MENU_MIN_TARGET = 44;
|
|
@@ -868,7 +994,7 @@ var DEFAULT_DRAWER_LABELS = {
|
|
|
868
994
|
closeLabel: "Close menu",
|
|
869
995
|
closeHint: "Close the navigation menu"
|
|
870
996
|
};
|
|
871
|
-
var
|
|
997
|
+
var styles2 = reactNative.StyleSheet.create({
|
|
872
998
|
overlay: { ...reactNative.StyleSheet.absoluteFillObject, zIndex: DRAWER_Z_INDEX },
|
|
873
999
|
scrim: { ...reactNative.StyleSheet.absoluteFillObject, backgroundColor: SCRIM_COLOR },
|
|
874
1000
|
panel: { position: "absolute", top: 0, bottom: 0, left: 0 },
|
|
@@ -889,10 +1015,10 @@ var MenuToggle = ({ label, hint, onOpen, testID }) => {
|
|
|
889
1015
|
accessibilityHint: hint,
|
|
890
1016
|
accessibilityLabel: label,
|
|
891
1017
|
ringColor: theme.palette.primary["500"],
|
|
892
|
-
style:
|
|
1018
|
+
style: styles2.menuToggle,
|
|
893
1019
|
testID,
|
|
894
1020
|
onPress: onOpen,
|
|
895
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [
|
|
1021
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles2.menuToggleGlyph, { color: theme.colors.text }], children: MENU_GLYPH2 })
|
|
896
1022
|
}
|
|
897
1023
|
);
|
|
898
1024
|
};
|
|
@@ -915,21 +1041,34 @@ var MobileDrawer = ({
|
|
|
915
1041
|
node.addEventListener("click", handleClick);
|
|
916
1042
|
return () => node.removeEventListener("click", handleClick);
|
|
917
1043
|
}, [onClose]);
|
|
918
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
1044
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles2.overlay, children: [
|
|
919
1045
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
920
1046
|
reactNative.Pressable,
|
|
921
1047
|
{
|
|
922
1048
|
accessibilityHint: labels.closeHint,
|
|
923
1049
|
accessibilityLabel: labels.closeLabel,
|
|
924
1050
|
accessibilityRole: "button",
|
|
925
|
-
style:
|
|
1051
|
+
style: styles2.scrim,
|
|
926
1052
|
testID: scrimTestID,
|
|
927
1053
|
onPress: onClose
|
|
928
1054
|
}
|
|
929
1055
|
),
|
|
930
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { ref: panelRef, "aria-modal": true, role: "dialog", style:
|
|
1056
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { ref: panelRef, "aria-modal": true, role: "dialog", style: styles2.panel, testID: drawerTestID, children: sidebar })
|
|
931
1057
|
] });
|
|
932
1058
|
};
|
|
1059
|
+
|
|
1060
|
+
// src/railMode.ts
|
|
1061
|
+
var RAIL_FULL_BREAKPOINT = 768;
|
|
1062
|
+
var DEFAULT_COLLAPSED_RAIL_MAX = 1024;
|
|
1063
|
+
function resolveRailMode({ viewport, hasSidebar, hasCollapsed, range }) {
|
|
1064
|
+
if (!hasSidebar) return "none";
|
|
1065
|
+
if (hasCollapsed) {
|
|
1066
|
+
if (viewport >= range.max) return "full";
|
|
1067
|
+
if (viewport >= range.min) return "collapsed";
|
|
1068
|
+
return "drawer";
|
|
1069
|
+
}
|
|
1070
|
+
return viewport >= RAIL_FULL_BREAKPOINT ? "full" : "drawer";
|
|
1071
|
+
}
|
|
933
1072
|
function resolveContentMaxWidth(width, viewport) {
|
|
934
1073
|
if (width === "full") return "full";
|
|
935
1074
|
const wideMinViewport = width.wideMinViewport ?? Number.POSITIVE_INFINITY;
|
|
@@ -941,13 +1080,7 @@ function useContentMaxWidth(width) {
|
|
|
941
1080
|
return resolveContentMaxWidth(width, viewport);
|
|
942
1081
|
}
|
|
943
1082
|
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({
|
|
1083
|
+
var styles3 = reactNative.StyleSheet.create({
|
|
951
1084
|
root: { flex: 1 },
|
|
952
1085
|
centerFill: { flex: 1, justifyContent: "center", alignItems: "center" },
|
|
953
1086
|
scroll: { flex: 1 },
|
|
@@ -961,50 +1094,14 @@ var styles2 = reactNative.StyleSheet.create({
|
|
|
961
1094
|
columnCapped: { flex: 1, width: "100%", alignSelf: "center" },
|
|
962
1095
|
// Non-flex variant used to cap the nav strip's inner content to the content
|
|
963
1096
|
// 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 }
|
|
1097
|
+
chromeCapped: { width: "100%", alignSelf: "center" }
|
|
972
1098
|
});
|
|
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
1099
|
var AppShell = ({
|
|
1005
1100
|
header,
|
|
1006
1101
|
nav,
|
|
1007
1102
|
sidebar,
|
|
1103
|
+
collapsedSidebar,
|
|
1104
|
+
collapsedRailRange,
|
|
1008
1105
|
mobileMenu,
|
|
1009
1106
|
banner,
|
|
1010
1107
|
width = "full",
|
|
@@ -1020,34 +1117,40 @@ var AppShell = ({
|
|
|
1020
1117
|
const maxWidth = useContentMaxWidth(width);
|
|
1021
1118
|
const body = useContentBody(state, children, testID);
|
|
1022
1119
|
const { width: viewportWidth } = reactNative.useWindowDimensions();
|
|
1023
|
-
const
|
|
1024
|
-
const
|
|
1120
|
+
const railRange = collapsedRailRange ?? { min: RAIL_FULL_BREAKPOINT, max: DEFAULT_COLLAPSED_RAIL_MAX };
|
|
1121
|
+
const railMode = resolveRailMode({
|
|
1122
|
+
viewport: viewportWidth,
|
|
1123
|
+
hasSidebar: sidebar !== void 0,
|
|
1124
|
+
hasCollapsed: collapsedSidebar !== void 0,
|
|
1125
|
+
range: railRange
|
|
1126
|
+
});
|
|
1127
|
+
const useDrawer = railMode === "drawer";
|
|
1025
1128
|
const [drawerOpen, setDrawerOpen] = React5.useState(false);
|
|
1026
1129
|
const openDrawer = React5.useCallback(() => setDrawerOpen(true), []);
|
|
1027
1130
|
const closeDrawer = React5.useCallback(() => setDrawerOpen(false), []);
|
|
1028
1131
|
React5.useEffect(() => {
|
|
1029
|
-
if (!
|
|
1030
|
-
}, [
|
|
1132
|
+
if (!useDrawer && drawerOpen) setDrawerOpen(false);
|
|
1133
|
+
}, [useDrawer, drawerOpen]);
|
|
1031
1134
|
const drawerLabels = { ...DEFAULT_DRAWER_LABELS, ...mobileMenu };
|
|
1032
1135
|
const isUnauthenticated = gate !== void 0 && !gate.pending && !gate.authenticated;
|
|
1033
1136
|
React5.useEffect(() => {
|
|
1034
1137
|
if (isUnauthenticated && gate !== void 0) gate.onRedirect();
|
|
1035
1138
|
}, [isUnauthenticated, gate]);
|
|
1036
1139
|
if (gate?.pending === true)
|
|
1037
|
-
return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [
|
|
1140
|
+
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
1141
|
if (isUnauthenticated) return null;
|
|
1039
|
-
const columnStyle = maxWidth === "full" ?
|
|
1040
|
-
const navInnerStyle = chromeAlignment === "content" && maxWidth !== "full" ? [
|
|
1142
|
+
const columnStyle = maxWidth === "full" ? styles3.columnFull : [styles3.columnCapped, { maxWidth }];
|
|
1143
|
+
const navInnerStyle = chromeAlignment === "content" && maxWidth !== "full" ? [styles3.chromeCapped, { maxWidth, paddingHorizontal: contentPadding }] : void 0;
|
|
1041
1144
|
const scroller = /* @__PURE__ */ jsxRuntime.jsx(
|
|
1042
1145
|
reactNative.ScrollView,
|
|
1043
1146
|
{
|
|
1044
|
-
contentContainerStyle: [
|
|
1045
|
-
style:
|
|
1147
|
+
contentContainerStyle: [styles3.scrollContent, { padding: contentPadding }],
|
|
1148
|
+
style: styles3.scroll,
|
|
1046
1149
|
testID: `${testID}${APP_SHELL_SUFFIX.content}`,
|
|
1047
1150
|
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: columnStyle, children: body })
|
|
1048
1151
|
}
|
|
1049
1152
|
);
|
|
1050
|
-
const headerRegion = useDrawer ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
1153
|
+
const headerRegion = useDrawer ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.headerRow, testID: `${testID}${APP_SHELL_SUFFIX.header}`, children: [
|
|
1051
1154
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1052
1155
|
MenuToggle,
|
|
1053
1156
|
{
|
|
@@ -1057,15 +1160,15 @@ var AppShell = ({
|
|
|
1057
1160
|
onOpen: openDrawer
|
|
1058
1161
|
}
|
|
1059
1162
|
),
|
|
1060
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style:
|
|
1163
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles3.headerFill, children: header })
|
|
1061
1164
|
] }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { testID: `${testID}${APP_SHELL_SUFFIX.header}`, children: header });
|
|
1062
|
-
const
|
|
1063
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [
|
|
1165
|
+
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;
|
|
1166
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles3.root, { backgroundColor: theme.colors.background }], testID, children: [
|
|
1064
1167
|
headerRegion,
|
|
1065
1168
|
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
1169
|
banner !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { testID: `${testID}${APP_SHELL_SUFFIX.banner}`, children: banner }) : null,
|
|
1067
|
-
|
|
1068
|
-
|
|
1170
|
+
railRegion !== null ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.bodyRow, children: [
|
|
1171
|
+
railRegion,
|
|
1069
1172
|
scroller
|
|
1070
1173
|
] }) : scroller,
|
|
1071
1174
|
useDrawer && drawerOpen ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1080,6 +1183,261 @@ var AppShell = ({
|
|
|
1080
1183
|
) : null
|
|
1081
1184
|
] });
|
|
1082
1185
|
};
|
|
1186
|
+
var COLLAPSED_ICON_SIZE = 22;
|
|
1187
|
+
function glyphFor(label) {
|
|
1188
|
+
return label.trim().charAt(0).toUpperCase();
|
|
1189
|
+
}
|
|
1190
|
+
var CollapsedRail = ({
|
|
1191
|
+
items,
|
|
1192
|
+
pathname,
|
|
1193
|
+
onNavigate,
|
|
1194
|
+
regionLabel,
|
|
1195
|
+
navigateHint = (label) => label,
|
|
1196
|
+
header,
|
|
1197
|
+
footer,
|
|
1198
|
+
containerStyle
|
|
1199
|
+
}) => {
|
|
1200
|
+
const { theme } = uiFeedback.useUi();
|
|
1201
|
+
const colors = theme.colors;
|
|
1202
|
+
const primaryColor = theme.palette.primary["500"];
|
|
1203
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1204
|
+
reactNative.View,
|
|
1205
|
+
{
|
|
1206
|
+
accessibilityRole: "none",
|
|
1207
|
+
"aria-label": regionLabel,
|
|
1208
|
+
role: "navigation",
|
|
1209
|
+
style: [
|
|
1210
|
+
collapsedRailStyles.container,
|
|
1211
|
+
{ backgroundColor: colors.surface, borderRightColor: colors.border },
|
|
1212
|
+
containerStyle
|
|
1213
|
+
],
|
|
1214
|
+
children: [
|
|
1215
|
+
header !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: collapsedRailStyles.slot, children: header }) : null,
|
|
1216
|
+
items.map((item) => {
|
|
1217
|
+
const active = isRouteActive(pathname, item.route);
|
|
1218
|
+
const iconColor = active ? primaryColor : colors.textSecondary;
|
|
1219
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1220
|
+
FocusableTouchable,
|
|
1221
|
+
{
|
|
1222
|
+
accessibilityHint: navigateHint(item.label),
|
|
1223
|
+
accessibilityLabel: item.label,
|
|
1224
|
+
ringColor: primaryColor,
|
|
1225
|
+
style: [collapsedRailStyles.item, active ? { backgroundColor: colors.border } : void 0],
|
|
1226
|
+
testID: item.testID ?? item.key,
|
|
1227
|
+
onPress: () => onNavigate(item.route),
|
|
1228
|
+
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) })
|
|
1229
|
+
},
|
|
1230
|
+
item.key
|
|
1231
|
+
);
|
|
1232
|
+
}),
|
|
1233
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: collapsedRailStyles.spacer }),
|
|
1234
|
+
footer !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: collapsedRailStyles.slot, children: footer }) : null
|
|
1235
|
+
]
|
|
1236
|
+
}
|
|
1237
|
+
);
|
|
1238
|
+
};
|
|
1239
|
+
function wantsTopBar(layout, hasHeader, hasTopBar) {
|
|
1240
|
+
return layout === "top" || layout === "both" || hasHeader || layout === "side" && hasTopBar;
|
|
1241
|
+
}
|
|
1242
|
+
function wantsSideRail(layout, hasSideRail) {
|
|
1243
|
+
return (layout === "side" || layout === "both") && hasSideRail;
|
|
1244
|
+
}
|
|
1245
|
+
var NavShell = ({
|
|
1246
|
+
layout,
|
|
1247
|
+
pathname,
|
|
1248
|
+
onNavigate,
|
|
1249
|
+
regionLabel,
|
|
1250
|
+
navigateHint,
|
|
1251
|
+
topBar,
|
|
1252
|
+
header,
|
|
1253
|
+
sideRail,
|
|
1254
|
+
children,
|
|
1255
|
+
collapsedSidebar: collapsedSidebarProp,
|
|
1256
|
+
collapsedRailRange: collapsedRailRangeProp,
|
|
1257
|
+
...shellProps
|
|
1258
|
+
}) => {
|
|
1259
|
+
const showTopBar = wantsTopBar(layout, header !== void 0, topBar !== void 0);
|
|
1260
|
+
const showSideRail = wantsSideRail(layout, sideRail !== void 0);
|
|
1261
|
+
const headerNode = header !== void 0 ? header : showTopBar && topBar !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1262
|
+
NavBar,
|
|
1263
|
+
{
|
|
1264
|
+
barTheme: topBar.barTheme,
|
|
1265
|
+
brand: topBar.brand,
|
|
1266
|
+
collapseBelow: topBar.collapseBelow,
|
|
1267
|
+
containerStyle: topBar.containerStyle,
|
|
1268
|
+
items: topBar.items,
|
|
1269
|
+
menuHint: topBar.menuHint,
|
|
1270
|
+
menuLabel: topBar.menuLabel,
|
|
1271
|
+
navigateHint,
|
|
1272
|
+
overflowHint: topBar.overflowHint,
|
|
1273
|
+
overflowLabel: topBar.overflowLabel,
|
|
1274
|
+
pathname,
|
|
1275
|
+
regionLabel,
|
|
1276
|
+
renderMenuIcon: topBar.renderMenuIcon,
|
|
1277
|
+
right: topBar.right,
|
|
1278
|
+
onNavigate
|
|
1279
|
+
}
|
|
1280
|
+
) : null;
|
|
1281
|
+
const sidebarNode = showSideRail && sideRail !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1282
|
+
Sidebar,
|
|
1283
|
+
{
|
|
1284
|
+
collapseHint: sideRail.collapseHint,
|
|
1285
|
+
containerStyle: sideRail.containerStyle,
|
|
1286
|
+
expandHint: sideRail.expandHint,
|
|
1287
|
+
footer: sideRail.footer,
|
|
1288
|
+
header: sideRail.header,
|
|
1289
|
+
items: sideRail.items,
|
|
1290
|
+
navigateHint,
|
|
1291
|
+
pathname,
|
|
1292
|
+
regionLabel,
|
|
1293
|
+
renderChevron: sideRail.renderChevron,
|
|
1294
|
+
title: sideRail.title,
|
|
1295
|
+
onNavigate
|
|
1296
|
+
}
|
|
1297
|
+
) : void 0;
|
|
1298
|
+
const collapsedCfg = showSideRail ? sideRail?.collapsed : void 0;
|
|
1299
|
+
const collapsedNode = collapsedCfg !== void 0 && sideRail !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1300
|
+
CollapsedRail,
|
|
1301
|
+
{
|
|
1302
|
+
footer: collapsedCfg.footer,
|
|
1303
|
+
header: collapsedCfg.header,
|
|
1304
|
+
items: collapsedCfg.items ?? sideRail.items,
|
|
1305
|
+
navigateHint,
|
|
1306
|
+
pathname,
|
|
1307
|
+
regionLabel,
|
|
1308
|
+
onNavigate
|
|
1309
|
+
}
|
|
1310
|
+
) : collapsedSidebarProp;
|
|
1311
|
+
const collapsedRange = collapsedCfg?.range ?? collapsedRailRangeProp;
|
|
1312
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1313
|
+
AppShell,
|
|
1314
|
+
{
|
|
1315
|
+
...shellProps,
|
|
1316
|
+
collapsedRailRange: collapsedRange,
|
|
1317
|
+
collapsedSidebar: collapsedNode,
|
|
1318
|
+
header: headerNode,
|
|
1319
|
+
sidebar: sidebarNode,
|
|
1320
|
+
children
|
|
1321
|
+
}
|
|
1322
|
+
);
|
|
1323
|
+
};
|
|
1324
|
+
var TEXT_ON_PRIMARY4 = "#ffffff";
|
|
1325
|
+
var DEFAULT_MIN_ITEMS = 1;
|
|
1326
|
+
var PillNav = ({
|
|
1327
|
+
items,
|
|
1328
|
+
pathname,
|
|
1329
|
+
onNavigate,
|
|
1330
|
+
regionLabel,
|
|
1331
|
+
navigateHint = (label) => label,
|
|
1332
|
+
minItems = DEFAULT_MIN_ITEMS,
|
|
1333
|
+
containerStyle
|
|
1334
|
+
}) => {
|
|
1335
|
+
const { theme } = uiFeedback.useUi();
|
|
1336
|
+
const colors = theme.colors;
|
|
1337
|
+
const primaryColor = theme.palette.primary["500"];
|
|
1338
|
+
if (items.length < minItems) return null;
|
|
1339
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1340
|
+
reactNative.View,
|
|
1341
|
+
{
|
|
1342
|
+
accessibilityRole: "none",
|
|
1343
|
+
"aria-label": regionLabel,
|
|
1344
|
+
role: "navigation",
|
|
1345
|
+
style: [pillNavStyles.container, containerStyle],
|
|
1346
|
+
children: items.map((item) => {
|
|
1347
|
+
const active = isRouteActive(pathname, item.route);
|
|
1348
|
+
const textColor = active ? TEXT_ON_PRIMARY4 : colors.textSecondary;
|
|
1349
|
+
const pillStyle = active ? { backgroundColor: primaryColor } : { backgroundColor: colors.surfaceElevated };
|
|
1350
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1351
|
+
FocusableTouchable,
|
|
1352
|
+
{
|
|
1353
|
+
accessibilityHint: navigateHint(item.label),
|
|
1354
|
+
accessibilityLabel: item.label,
|
|
1355
|
+
accessibilityRole: "link",
|
|
1356
|
+
ringColor: primaryColor,
|
|
1357
|
+
style: [pillNavStyles.pill, pillStyle],
|
|
1358
|
+
testID: item.testID ?? item.key,
|
|
1359
|
+
onPress: () => onNavigate(item.route),
|
|
1360
|
+
children: [
|
|
1361
|
+
typeof item.renderIcon === "function" ? item.renderIcon(textColor, NAV_ICON_SIZE) : null,
|
|
1362
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [pillNavStyles.pillText, { color: textColor }], children: item.label })
|
|
1363
|
+
]
|
|
1364
|
+
},
|
|
1365
|
+
item.key
|
|
1366
|
+
);
|
|
1367
|
+
})
|
|
1368
|
+
}
|
|
1369
|
+
);
|
|
1370
|
+
};
|
|
1371
|
+
var TEXT_ON_PRIMARY5 = "#ffffff";
|
|
1372
|
+
var DARK_MODE_ICON_SIZE = 16;
|
|
1373
|
+
var DarkModeControl = ({
|
|
1374
|
+
value,
|
|
1375
|
+
options,
|
|
1376
|
+
onChange,
|
|
1377
|
+
regionLabel,
|
|
1378
|
+
variant = "segmented",
|
|
1379
|
+
testID,
|
|
1380
|
+
containerStyle
|
|
1381
|
+
}) => {
|
|
1382
|
+
const { theme } = uiFeedback.useUi();
|
|
1383
|
+
const colors = theme.colors;
|
|
1384
|
+
const primaryColor = theme.palette.primary["500"];
|
|
1385
|
+
const currentIndex = options.findIndex((option) => option.value === value);
|
|
1386
|
+
const current = currentIndex >= 0 ? options[currentIndex] : options[0];
|
|
1387
|
+
const advance = React5.useCallback(() => {
|
|
1388
|
+
if (options.length === 0) return;
|
|
1389
|
+
const from = currentIndex >= 0 ? currentIndex : 0;
|
|
1390
|
+
const next = options[(from + 1) % options.length];
|
|
1391
|
+
if (next !== void 0) onChange(next.value);
|
|
1392
|
+
}, [options, currentIndex, onChange]);
|
|
1393
|
+
if (options.length === 0 || current === void 0) return null;
|
|
1394
|
+
if (variant === "cycle") {
|
|
1395
|
+
const iconColor = colors.text;
|
|
1396
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { "aria-label": regionLabel, style: containerStyle, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1397
|
+
FocusableTouchable,
|
|
1398
|
+
{
|
|
1399
|
+
accessibilityHint: current.hint,
|
|
1400
|
+
accessibilityLabel: current.label,
|
|
1401
|
+
ringColor: primaryColor,
|
|
1402
|
+
style: [darkModeStyles.cycle, { backgroundColor: colors.surfaceElevated }],
|
|
1403
|
+
testID,
|
|
1404
|
+
onPress: advance,
|
|
1405
|
+
children: [
|
|
1406
|
+
typeof current.renderIcon === "function" ? current.renderIcon(iconColor, DARK_MODE_ICON_SIZE) : null,
|
|
1407
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [darkModeStyles.cycleText, { color: colors.text }], children: current.label })
|
|
1408
|
+
]
|
|
1409
|
+
}
|
|
1410
|
+
) });
|
|
1411
|
+
}
|
|
1412
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1413
|
+
reactNative.View,
|
|
1414
|
+
{
|
|
1415
|
+
"aria-label": regionLabel,
|
|
1416
|
+
role: "group",
|
|
1417
|
+
style: [darkModeStyles.segmentRow, { borderColor: colors.border }, containerStyle],
|
|
1418
|
+
children: options.map((option) => {
|
|
1419
|
+
const active = option.value === value;
|
|
1420
|
+
const textColor = active ? TEXT_ON_PRIMARY5 : colors.textSecondary;
|
|
1421
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1422
|
+
FocusableTouchable,
|
|
1423
|
+
{
|
|
1424
|
+
accessibilityHint: option.hint,
|
|
1425
|
+
accessibilityLabel: option.label,
|
|
1426
|
+
ringColor: primaryColor,
|
|
1427
|
+
style: [darkModeStyles.segment, active ? { backgroundColor: primaryColor } : void 0],
|
|
1428
|
+
testID: testID !== void 0 ? `${testID}-${option.value}` : void 0,
|
|
1429
|
+
onPress: () => onChange(option.value),
|
|
1430
|
+
children: [
|
|
1431
|
+
typeof option.renderIcon === "function" ? option.renderIcon(textColor, DARK_MODE_ICON_SIZE) : null,
|
|
1432
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [darkModeStyles.segmentText, { color: textColor }], children: option.label })
|
|
1433
|
+
]
|
|
1434
|
+
},
|
|
1435
|
+
option.value
|
|
1436
|
+
);
|
|
1437
|
+
})
|
|
1438
|
+
}
|
|
1439
|
+
);
|
|
1440
|
+
};
|
|
1083
1441
|
function roleRoutesToNavItems(routes, translate) {
|
|
1084
1442
|
return routes.map((entry) => ({
|
|
1085
1443
|
key: entry.role,
|
|
@@ -1096,6 +1454,9 @@ exports.APP_SHELL_SUFFIX = APP_SHELL_SUFFIX;
|
|
|
1096
1454
|
exports.AppShell = AppShell;
|
|
1097
1455
|
exports.BASE_INDENT = BASE_INDENT;
|
|
1098
1456
|
exports.CHEVRON_ICON_SIZE = CHEVRON_ICON_SIZE;
|
|
1457
|
+
exports.CollapsedRail = CollapsedRail;
|
|
1458
|
+
exports.DEFAULT_COLLAPSED_RAIL_MAX = DEFAULT_COLLAPSED_RAIL_MAX;
|
|
1459
|
+
exports.DarkModeControl = DarkModeControl;
|
|
1099
1460
|
exports.NAV_ICON_SIZE = NAV_ICON_SIZE;
|
|
1100
1461
|
exports.NAV_LINK_GAP = NAV_LINK_GAP;
|
|
1101
1462
|
exports.NAV_TEST_IDS = NAV_TEST_IDS;
|
|
@@ -1103,13 +1464,20 @@ exports.Nav = Nav;
|
|
|
1103
1464
|
exports.NavBar = NavBar;
|
|
1104
1465
|
exports.NavExpandableItem = NavExpandableItem;
|
|
1105
1466
|
exports.NavOverflowMenu = NavOverflowMenu;
|
|
1467
|
+
exports.NavShell = NavShell;
|
|
1468
|
+
exports.PillNav = PillNav;
|
|
1469
|
+
exports.RAIL_FULL_BREAKPOINT = RAIL_FULL_BREAKPOINT;
|
|
1106
1470
|
exports.Sidebar = Sidebar;
|
|
1107
1471
|
exports.Topbar = Topbar;
|
|
1108
1472
|
exports.accessibleNavItems = accessibleNavItems;
|
|
1473
|
+
exports.collapsedRailStyles = collapsedRailStyles;
|
|
1474
|
+
exports.darkModeStyles = darkModeStyles;
|
|
1109
1475
|
exports.expandableStyles = expandableStyles;
|
|
1110
1476
|
exports.isRouteActive = isRouteActive;
|
|
1111
1477
|
exports.navStyles = navStyles;
|
|
1478
|
+
exports.pillNavStyles = pillNavStyles;
|
|
1112
1479
|
exports.resolveContentMaxWidth = resolveContentMaxWidth;
|
|
1480
|
+
exports.resolveRailMode = resolveRailMode;
|
|
1113
1481
|
exports.roleRoutesToNavItems = roleRoutesToNavItems;
|
|
1114
1482
|
exports.useContentMaxWidth = useContentMaxWidth;
|
|
1115
1483
|
//# sourceMappingURL=index.js.map
|