@dloizides/ui-nav 1.30.0 → 1.32.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/dist/index.d.mts +15 -18
- package/dist/index.d.ts +15 -18
- package/dist/index.js +41 -23
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +41 -23
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -155,7 +155,7 @@ interface SidebarProps {
|
|
|
155
155
|
/** Navigation callback — receives a `NavItem.route`. */
|
|
156
156
|
onNavigate: (route: string) => void;
|
|
157
157
|
/** Localized menu title (heading). */
|
|
158
|
-
title:
|
|
158
|
+
title: React.ReactNode;
|
|
159
159
|
/** Localized accessibility label for the navigation landmark. */
|
|
160
160
|
regionLabel: string;
|
|
161
161
|
/** a11y hint for a leaf item, given its label. Defaults to the label. */
|
|
@@ -711,6 +711,13 @@ interface AppShellProps {
|
|
|
711
711
|
}
|
|
712
712
|
declare const AppShell: ({ header, nav, sidebar, collapsedSidebar, collapsedRailRange, mobileMenu, banner, width, contentPadding, chromeAlignment, gate, state, testID, children, }: AppShellProps) => React.ReactElement | null;
|
|
713
713
|
|
|
714
|
+
interface NavShellCollapsedRail {
|
|
715
|
+
items?: NavItem[];
|
|
716
|
+
header?: React.ReactNode;
|
|
717
|
+
footer?: React.ReactNode;
|
|
718
|
+
range?: CollapsedRailRange;
|
|
719
|
+
}
|
|
720
|
+
|
|
714
721
|
/**
|
|
715
722
|
* NavShell — the ONE first-class navigation shell that renders a **top bar**, a
|
|
716
723
|
* **side rail**, or **BOTH together**, chosen by a single `layout` prop
|
|
@@ -786,22 +793,7 @@ interface NavShellTopBar {
|
|
|
786
793
|
*/
|
|
787
794
|
barTheme?: UiTheme;
|
|
788
795
|
}
|
|
789
|
-
|
|
790
|
-
* Config for the intermediate COLLAPSED (icon-only) rail — opts the side layout
|
|
791
|
-
* into a THREE-tier responsive scheme (full rail → collapsed rail → drawer). When
|
|
792
|
-
* present, NavShell builds a `<CollapsedRail>` and hands it to `AppShell` for the
|
|
793
|
-
* tablet band; omit it and the layout stays two-tier.
|
|
794
|
-
*/
|
|
795
|
-
interface NavShellCollapsedRail {
|
|
796
|
-
/** Items for the icon rail. Defaults to the full rail's `items`. */
|
|
797
|
-
items?: NavItem[];
|
|
798
|
-
/** Optional header slot (e.g. a home shortcut). */
|
|
799
|
-
header?: React.ReactNode;
|
|
800
|
-
/** Optional footer slot (dark-mode toggle, logout). */
|
|
801
|
-
footer?: React.ReactNode;
|
|
802
|
-
/** The `[min, max)` viewport band for the collapsed rail (default `{ min: 768, max: 1024 }`). */
|
|
803
|
-
range?: CollapsedRailRange;
|
|
804
|
-
}
|
|
796
|
+
|
|
805
797
|
/**
|
|
806
798
|
* Config for the SIDE rail (rendered as a `Sidebar` in `AppShell`'s sidebar
|
|
807
799
|
* slot). Used when `layout` is `'side'` or `'both'`.
|
|
@@ -809,6 +801,7 @@ interface NavShellCollapsedRail {
|
|
|
809
801
|
interface NavShellSideRail {
|
|
810
802
|
/** Side-rail nav entries (sections — leaf + expandable). */
|
|
811
803
|
items: NavItem[];
|
|
804
|
+
brand?: React.ReactNode;
|
|
812
805
|
/** Localized menu title (heading). */
|
|
813
806
|
title: string;
|
|
814
807
|
/** Optional header slot rendered above the items (e.g. a Home shortcut). */
|
|
@@ -1372,6 +1365,9 @@ declare const navStyles: {
|
|
|
1372
1365
|
borderRightWidth: number;
|
|
1373
1366
|
height: "100%";
|
|
1374
1367
|
};
|
|
1368
|
+
sidebarBrand: {
|
|
1369
|
+
marginBottom: number;
|
|
1370
|
+
};
|
|
1375
1371
|
sidebarTitle: {
|
|
1376
1372
|
fontWeight: "700";
|
|
1377
1373
|
marginBottom: number;
|
|
@@ -1396,7 +1392,7 @@ declare const navStyles: {
|
|
|
1396
1392
|
paddingHorizontal: number;
|
|
1397
1393
|
};
|
|
1398
1394
|
topbarContainer: {
|
|
1399
|
-
|
|
1395
|
+
minHeight: number;
|
|
1400
1396
|
paddingHorizontal: number;
|
|
1401
1397
|
borderBottomWidth: number;
|
|
1402
1398
|
flexDirection: "row";
|
|
@@ -1450,6 +1446,7 @@ declare const navStyles: {
|
|
|
1450
1446
|
};
|
|
1451
1447
|
userEmail: {
|
|
1452
1448
|
fontSize: number;
|
|
1449
|
+
maxWidth: "100%";
|
|
1453
1450
|
};
|
|
1454
1451
|
accountBtn: {
|
|
1455
1452
|
marginLeft: number;
|
package/dist/index.d.ts
CHANGED
|
@@ -155,7 +155,7 @@ interface SidebarProps {
|
|
|
155
155
|
/** Navigation callback — receives a `NavItem.route`. */
|
|
156
156
|
onNavigate: (route: string) => void;
|
|
157
157
|
/** Localized menu title (heading). */
|
|
158
|
-
title:
|
|
158
|
+
title: React.ReactNode;
|
|
159
159
|
/** Localized accessibility label for the navigation landmark. */
|
|
160
160
|
regionLabel: string;
|
|
161
161
|
/** a11y hint for a leaf item, given its label. Defaults to the label. */
|
|
@@ -711,6 +711,13 @@ interface AppShellProps {
|
|
|
711
711
|
}
|
|
712
712
|
declare const AppShell: ({ header, nav, sidebar, collapsedSidebar, collapsedRailRange, mobileMenu, banner, width, contentPadding, chromeAlignment, gate, state, testID, children, }: AppShellProps) => React.ReactElement | null;
|
|
713
713
|
|
|
714
|
+
interface NavShellCollapsedRail {
|
|
715
|
+
items?: NavItem[];
|
|
716
|
+
header?: React.ReactNode;
|
|
717
|
+
footer?: React.ReactNode;
|
|
718
|
+
range?: CollapsedRailRange;
|
|
719
|
+
}
|
|
720
|
+
|
|
714
721
|
/**
|
|
715
722
|
* NavShell — the ONE first-class navigation shell that renders a **top bar**, a
|
|
716
723
|
* **side rail**, or **BOTH together**, chosen by a single `layout` prop
|
|
@@ -786,22 +793,7 @@ interface NavShellTopBar {
|
|
|
786
793
|
*/
|
|
787
794
|
barTheme?: UiTheme;
|
|
788
795
|
}
|
|
789
|
-
|
|
790
|
-
* Config for the intermediate COLLAPSED (icon-only) rail — opts the side layout
|
|
791
|
-
* into a THREE-tier responsive scheme (full rail → collapsed rail → drawer). When
|
|
792
|
-
* present, NavShell builds a `<CollapsedRail>` and hands it to `AppShell` for the
|
|
793
|
-
* tablet band; omit it and the layout stays two-tier.
|
|
794
|
-
*/
|
|
795
|
-
interface NavShellCollapsedRail {
|
|
796
|
-
/** Items for the icon rail. Defaults to the full rail's `items`. */
|
|
797
|
-
items?: NavItem[];
|
|
798
|
-
/** Optional header slot (e.g. a home shortcut). */
|
|
799
|
-
header?: React.ReactNode;
|
|
800
|
-
/** Optional footer slot (dark-mode toggle, logout). */
|
|
801
|
-
footer?: React.ReactNode;
|
|
802
|
-
/** The `[min, max)` viewport band for the collapsed rail (default `{ min: 768, max: 1024 }`). */
|
|
803
|
-
range?: CollapsedRailRange;
|
|
804
|
-
}
|
|
796
|
+
|
|
805
797
|
/**
|
|
806
798
|
* Config for the SIDE rail (rendered as a `Sidebar` in `AppShell`'s sidebar
|
|
807
799
|
* slot). Used when `layout` is `'side'` or `'both'`.
|
|
@@ -809,6 +801,7 @@ interface NavShellCollapsedRail {
|
|
|
809
801
|
interface NavShellSideRail {
|
|
810
802
|
/** Side-rail nav entries (sections — leaf + expandable). */
|
|
811
803
|
items: NavItem[];
|
|
804
|
+
brand?: React.ReactNode;
|
|
812
805
|
/** Localized menu title (heading). */
|
|
813
806
|
title: string;
|
|
814
807
|
/** Optional header slot rendered above the items (e.g. a Home shortcut). */
|
|
@@ -1372,6 +1365,9 @@ declare const navStyles: {
|
|
|
1372
1365
|
borderRightWidth: number;
|
|
1373
1366
|
height: "100%";
|
|
1374
1367
|
};
|
|
1368
|
+
sidebarBrand: {
|
|
1369
|
+
marginBottom: number;
|
|
1370
|
+
};
|
|
1375
1371
|
sidebarTitle: {
|
|
1376
1372
|
fontWeight: "700";
|
|
1377
1373
|
marginBottom: number;
|
|
@@ -1396,7 +1392,7 @@ declare const navStyles: {
|
|
|
1396
1392
|
paddingHorizontal: number;
|
|
1397
1393
|
};
|
|
1398
1394
|
topbarContainer: {
|
|
1399
|
-
|
|
1395
|
+
minHeight: number;
|
|
1400
1396
|
paddingHorizontal: number;
|
|
1401
1397
|
borderBottomWidth: number;
|
|
1402
1398
|
flexDirection: "row";
|
|
@@ -1450,6 +1446,7 @@ declare const navStyles: {
|
|
|
1450
1446
|
};
|
|
1451
1447
|
userEmail: {
|
|
1452
1448
|
fontSize: number;
|
|
1449
|
+
maxWidth: "100%";
|
|
1453
1450
|
};
|
|
1454
1451
|
accountBtn: {
|
|
1455
1452
|
marginLeft: number;
|
package/dist/index.js
CHANGED
|
@@ -34,6 +34,9 @@ var navStyles = reactNative.StyleSheet.create({
|
|
|
34
34
|
borderRightWidth: 1,
|
|
35
35
|
height: "100%"
|
|
36
36
|
},
|
|
37
|
+
sidebarBrand: {
|
|
38
|
+
marginBottom: 12
|
|
39
|
+
},
|
|
37
40
|
sidebarTitle: {
|
|
38
41
|
fontWeight: "700",
|
|
39
42
|
marginBottom: 12
|
|
@@ -63,7 +66,7 @@ var navStyles = reactNative.StyleSheet.create({
|
|
|
63
66
|
},
|
|
64
67
|
// --- Topbar ---
|
|
65
68
|
topbarContainer: {
|
|
66
|
-
|
|
69
|
+
minHeight: 64,
|
|
67
70
|
paddingHorizontal: 12,
|
|
68
71
|
borderBottomWidth: 1,
|
|
69
72
|
flexDirection: "row",
|
|
@@ -84,7 +87,7 @@ var navStyles = reactNative.StyleSheet.create({
|
|
|
84
87
|
userBlock: { marginHorizontal: 12, alignItems: "flex-end", flexShrink: 1, minWidth: 0 },
|
|
85
88
|
userName: { fontWeight: "600", maxWidth: "100%" },
|
|
86
89
|
accountNameBtn: { flexShrink: 1, maxWidth: "100%", minHeight: MIN_TOUCH_TARGET, minWidth: MIN_TOUCH_TARGET, justifyContent: "center", alignItems: "flex-end" },
|
|
87
|
-
userEmail: { fontSize: 12 },
|
|
90
|
+
userEmail: { fontSize: 12, maxWidth: "100%" },
|
|
88
91
|
accountBtn: {
|
|
89
92
|
marginLeft: 8,
|
|
90
93
|
paddingHorizontal: 10,
|
|
@@ -821,7 +824,7 @@ var Sidebar = ({
|
|
|
821
824
|
containerStyle
|
|
822
825
|
],
|
|
823
826
|
children: [
|
|
824
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { accessibilityRole: "header", style: [navStyles.sidebarTitle, { color: colors.text }], children: title }),
|
|
827
|
+
typeof title === "string" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { accessibilityRole: "header", style: [navStyles.sidebarTitle, { color: colors.text }], children: title }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: navStyles.sidebarBrand, children: title }),
|
|
825
828
|
showInlineSearch && search !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
826
829
|
SidebarSearch,
|
|
827
830
|
{
|
|
@@ -935,7 +938,22 @@ var FocusableTouchable = ({
|
|
|
935
938
|
}
|
|
936
939
|
);
|
|
937
940
|
};
|
|
941
|
+
var RAIL_FULL_BREAKPOINT = uiLayout.LAYOUT_COLLAPSE_BREAKPOINT;
|
|
942
|
+
var DEFAULT_COLLAPSED_RAIL_MAX = 1024;
|
|
943
|
+
function resolveRailMode({ viewport, hasSidebar, hasCollapsed, range }) {
|
|
944
|
+
if (!hasSidebar) return "none";
|
|
945
|
+
if (hasCollapsed) {
|
|
946
|
+
if (viewport >= range.max) return "full";
|
|
947
|
+
if (viewport >= range.min) return "collapsed";
|
|
948
|
+
return "drawer";
|
|
949
|
+
}
|
|
950
|
+
return viewport >= RAIL_FULL_BREAKPOINT ? "full" : "drawer";
|
|
951
|
+
}
|
|
938
952
|
var TEXT_ON_PRIMARY = "#ffffff";
|
|
953
|
+
var ON_BRAND_SCALE = "onBrand";
|
|
954
|
+
var USER_BLOCK_COMPACT = { marginHorizontal: 4 };
|
|
955
|
+
var MAIN_STEP = "500";
|
|
956
|
+
var WRAP_ANYWHERE = reactNative.Platform.OS === "web" ? { overflowWrap: "anywhere" } : null;
|
|
939
957
|
function isAccountState(account) {
|
|
940
958
|
return "displayName" in account;
|
|
941
959
|
}
|
|
@@ -945,6 +963,14 @@ function planToneColor(theme, tone) {
|
|
|
945
963
|
if (tone === "enterprise") return palette.accent?.["500"] ?? palette.primary["500"];
|
|
946
964
|
return theme.colors.textSecondary;
|
|
947
965
|
}
|
|
966
|
+
function onBrandInk(palette) {
|
|
967
|
+
const scales = palette;
|
|
968
|
+
return scales[ON_BRAND_SCALE]?.[MAIN_STEP] ?? TEXT_ON_PRIMARY;
|
|
969
|
+
}
|
|
970
|
+
function planBadgeInk(theme, tone) {
|
|
971
|
+
const fillIsPrimary = planToneColor(theme, tone) === theme.palette.primary["500"];
|
|
972
|
+
return fillIsPrimary ? onBrandInk(theme.palette) : TEXT_ON_PRIMARY;
|
|
973
|
+
}
|
|
948
974
|
var Topbar = ({
|
|
949
975
|
left,
|
|
950
976
|
center,
|
|
@@ -958,6 +984,9 @@ var Topbar = ({
|
|
|
958
984
|
const { theme } = uiFeedback.useUi();
|
|
959
985
|
const colors = theme.colors;
|
|
960
986
|
const primaryColor = theme.palette.primary["500"];
|
|
987
|
+
const onPrimaryInk = onBrandInk(theme.palette);
|
|
988
|
+
const { width: viewportWidth } = reactNative.useWindowDimensions();
|
|
989
|
+
const userBlockStyle = [navStyles.userBlock, viewportWidth < RAIL_FULL_BREAKPOINT ? USER_BLOCK_COMPACT : null];
|
|
961
990
|
const richAccount = account !== void 0 && isAccountState(account) ? account : void 0;
|
|
962
991
|
const legacyAccount = account !== void 0 && !isAccountState(account) ? account : void 0;
|
|
963
992
|
const upgrade = richAccount?.upgrade;
|
|
@@ -986,11 +1015,11 @@ var Topbar = ({
|
|
|
986
1015
|
}
|
|
987
1016
|
) : null,
|
|
988
1017
|
renderTextSlot(notificationSlot, { color: colors.text }),
|
|
989
|
-
user ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, {
|
|
990
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [navStyles.userName, { color: colors.text }], children: user.name }),
|
|
991
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [navStyles.userEmail, { color: colors.textSecondary }], children: user.email })
|
|
1018
|
+
user ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { accessible: true, accessibilityLabel: `${user.name}, ${user.email}`, style: userBlockStyle, children: [
|
|
1019
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [navStyles.userName, WRAP_ANYWHERE, { color: colors.text }], children: user.name }),
|
|
1020
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [navStyles.userEmail, WRAP_ANYWHERE, { color: colors.textSecondary }], children: user.email })
|
|
992
1021
|
] }) : null,
|
|
993
|
-
richAccount ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
1022
|
+
richAccount ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: userBlockStyle, children: [
|
|
994
1023
|
richAccount.onAccount ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
995
1024
|
FocusableTouchable,
|
|
996
1025
|
{
|
|
@@ -1016,7 +1045,7 @@ var Topbar = ({
|
|
|
1016
1045
|
{
|
|
1017
1046
|
style: [navStyles.planBadge, { backgroundColor: planToneColor(theme, richAccount.plan.tone) }],
|
|
1018
1047
|
testID: NAV_TEST_IDS.accountPlan,
|
|
1019
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [navStyles.planBadgeText, { color:
|
|
1048
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [navStyles.planBadgeText, { color: planBadgeInk(theme, richAccount.plan.tone) }], children: richAccount.plan.label })
|
|
1020
1049
|
}
|
|
1021
1050
|
) : null
|
|
1022
1051
|
] }) : null,
|
|
@@ -1029,7 +1058,7 @@ var Topbar = ({
|
|
|
1029
1058
|
style: [navStyles.accountBtn, { backgroundColor: primaryColor }],
|
|
1030
1059
|
testID: legacyAccount.testID,
|
|
1031
1060
|
onPress: legacyAccount.onPress,
|
|
1032
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [navStyles.accountText, { color:
|
|
1061
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [navStyles.accountText, { color: onPrimaryInk }], children: legacyAccount.label })
|
|
1033
1062
|
}
|
|
1034
1063
|
) : null,
|
|
1035
1064
|
upgrade ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1041,7 +1070,7 @@ var Topbar = ({
|
|
|
1041
1070
|
style: [navStyles.accountBtn, { backgroundColor: primaryColor }],
|
|
1042
1071
|
testID: upgrade.testID ?? NAV_TEST_IDS.accountUpgrade,
|
|
1043
1072
|
onPress: upgrade.onPress,
|
|
1044
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [navStyles.accountText, { color:
|
|
1073
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [navStyles.accountText, { color: onPrimaryInk }], children: upgrade.label })
|
|
1045
1074
|
}
|
|
1046
1075
|
) : null,
|
|
1047
1076
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1053,7 +1082,7 @@ var Topbar = ({
|
|
|
1053
1082
|
style: [navStyles.accountBtn, { backgroundColor: primaryColor }],
|
|
1054
1083
|
testID: logout.testID,
|
|
1055
1084
|
onPress: richAccount ? richAccount.onLogout : logout.onPress,
|
|
1056
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [navStyles.accountText, { color:
|
|
1085
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [navStyles.accountText, { color: onPrimaryInk }], children: logout.label })
|
|
1057
1086
|
}
|
|
1058
1087
|
)
|
|
1059
1088
|
] })
|
|
@@ -1618,17 +1647,6 @@ var Nav = (props) => {
|
|
|
1618
1647
|
}
|
|
1619
1648
|
return /* @__PURE__ */ jsxRuntime.jsx(NavBar, { ...props });
|
|
1620
1649
|
};
|
|
1621
|
-
var RAIL_FULL_BREAKPOINT = uiLayout.LAYOUT_COLLAPSE_BREAKPOINT;
|
|
1622
|
-
var DEFAULT_COLLAPSED_RAIL_MAX = 1024;
|
|
1623
|
-
function resolveRailMode({ viewport, hasSidebar, hasCollapsed, range }) {
|
|
1624
|
-
if (!hasSidebar) return "none";
|
|
1625
|
-
if (hasCollapsed) {
|
|
1626
|
-
if (viewport >= range.max) return "full";
|
|
1627
|
-
if (viewport >= range.min) return "collapsed";
|
|
1628
|
-
return "drawer";
|
|
1629
|
-
}
|
|
1630
|
-
return viewport >= RAIL_FULL_BREAKPOINT ? "full" : "drawer";
|
|
1631
|
-
}
|
|
1632
1650
|
var styles5 = reactNative.StyleSheet.create({
|
|
1633
1651
|
band: { left: 0, position: "absolute", right: 0, top: 0 }
|
|
1634
1652
|
});
|
|
@@ -2073,7 +2091,7 @@ var NavShell = ({
|
|
|
2073
2091
|
renderChevron: sideRail.renderChevron,
|
|
2074
2092
|
search: sideRail.search,
|
|
2075
2093
|
searchQuery: sideRail.searchQuery,
|
|
2076
|
-
title: sideRail.title,
|
|
2094
|
+
title: sideRail.brand ?? sideRail.title,
|
|
2077
2095
|
onNavigate,
|
|
2078
2096
|
onSearchChange: sideRail.onSearchChange
|
|
2079
2097
|
}
|