@dloizides/ui-nav 1.34.0 → 1.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/dist/index.d.mts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +159 -76
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +160 -77
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.35.0
|
|
4
|
+
|
|
5
|
+
- NAV-SCROLL-1 "Opening sidebar groups never hides the items below" (AC-UI-1, AC-UI-2): `Sidebar` items (header slot + list) scroll in a `ScrollView` between the pinned title/search and the pinned footer, with a `theme.colors.surface` fade on each edge that hides items. Inside `MobileDrawer` opening a top-level group closes the other (through `NavAccordionContext`, which `MobileDrawer` provides; no new `Sidebar` prop). `NavExpandableItem` takes optional controlled `expanded` + `onToggle`. No prop changes for existing consumers.
|
|
6
|
+
|
|
3
7
|
## 1.28.0
|
|
4
8
|
|
|
5
9
|
- INVOICE-5 "Edit invoices before sending, shared background and menu hover" (AC-UI-3, AC-UI-6): `AppShell` draws `theme.backdrop` (the `@dloizides/theme-web` 1.5.0 `resolveBackdrop` shape, typed here as `AppShellBackdrop`): its colour and web image on the root, and for `horizon` a brand band behind header and nav that the content overlaps by `overlap.compact` (< 768 px) or `overlap.wide`. No `theme.backdrop` keeps today's flat background.
|
package/dist/index.d.mts
CHANGED
|
@@ -1209,8 +1209,10 @@ interface NavExpandableItemProps {
|
|
|
1209
1209
|
*/
|
|
1210
1210
|
renderChevron?: (expanded: boolean, color: string, size: number) => React.ReactNode;
|
|
1211
1211
|
depth?: number;
|
|
1212
|
+
expanded?: boolean;
|
|
1213
|
+
onToggle?: (key: string) => void;
|
|
1212
1214
|
}
|
|
1213
|
-
declare const NavExpandableItem: ({ item, pathname, onNavigate, navigateHint, expandHint, collapseHint, renderChevron, activeRoute, depth, }: NavExpandableItemProps) => React.ReactElement;
|
|
1215
|
+
declare const NavExpandableItem: ({ item, pathname, onNavigate, navigateHint, expandHint, collapseHint, renderChevron, activeRoute, depth, expanded: expandedProp, onToggle, }: NavExpandableItemProps) => React.ReactElement;
|
|
1214
1216
|
|
|
1215
1217
|
/**
|
|
1216
1218
|
* Pure matching logic for the {@link CommandPalette}. Kept framework-free so the
|
package/dist/index.d.ts
CHANGED
|
@@ -1209,8 +1209,10 @@ interface NavExpandableItemProps {
|
|
|
1209
1209
|
*/
|
|
1210
1210
|
renderChevron?: (expanded: boolean, color: string, size: number) => React.ReactNode;
|
|
1211
1211
|
depth?: number;
|
|
1212
|
+
expanded?: boolean;
|
|
1213
|
+
onToggle?: (key: string) => void;
|
|
1212
1214
|
}
|
|
1213
|
-
declare const NavExpandableItem: ({ item, pathname, onNavigate, navigateHint, expandHint, collapseHint, renderChevron, activeRoute, depth, }: NavExpandableItemProps) => React.ReactElement;
|
|
1215
|
+
declare const NavExpandableItem: ({ item, pathname, onNavigate, navigateHint, expandHint, collapseHint, renderChevron, activeRoute, depth, expanded: expandedProp, onToggle, }: NavExpandableItemProps) => React.ReactElement;
|
|
1214
1216
|
|
|
1215
1217
|
/**
|
|
1216
1218
|
* Pure matching logic for the {@link CommandPalette}. Kept framework-free so the
|
package/dist/index.js
CHANGED
|
@@ -486,6 +486,18 @@ function resolveActiveRoute(items, pathname) {
|
|
|
486
486
|
}
|
|
487
487
|
return winner;
|
|
488
488
|
}
|
|
489
|
+
var NavAccordionContext = React.createContext(false);
|
|
490
|
+
function hasActiveDescendant(item, pathname) {
|
|
491
|
+
if (isRouteActive(pathname, item.route)) return true;
|
|
492
|
+
return (item.children ?? []).some((child) => hasActiveDescendant(child, pathname));
|
|
493
|
+
}
|
|
494
|
+
function initialOpenGroup(items, pathname) {
|
|
495
|
+
const hasChildren = (item) => (item.children ?? []).length > 0;
|
|
496
|
+
return items.find((item) => hasChildren(item) && hasActiveDescendant(item, pathname))?.key;
|
|
497
|
+
}
|
|
498
|
+
function nextOpenGroup(current, pressed) {
|
|
499
|
+
return current === pressed ? void 0 : pressed;
|
|
500
|
+
}
|
|
489
501
|
var REDUCED_MOTION_QUERY = "(prefers-reduced-motion: reduce)";
|
|
490
502
|
function getReducedMotionQuery() {
|
|
491
503
|
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return void 0;
|
|
@@ -535,10 +547,6 @@ function ariaExpandedProps(expanded) {
|
|
|
535
547
|
function hoverHandlerProps(onIn, onOut) {
|
|
536
548
|
return IS_WEB ? { onHoverIn: onIn, onHoverOut: onOut } : {};
|
|
537
549
|
}
|
|
538
|
-
function hasActiveDescendant(item, pathname) {
|
|
539
|
-
if (isRouteActive(pathname, item.route)) return true;
|
|
540
|
-
return (item.children ?? []).some((child) => hasActiveDescendant(child, pathname));
|
|
541
|
-
}
|
|
542
550
|
function TintOverlay({
|
|
543
551
|
opacity,
|
|
544
552
|
color,
|
|
@@ -562,15 +570,21 @@ var NavExpandableItem = ({
|
|
|
562
570
|
collapseHint,
|
|
563
571
|
renderChevron,
|
|
564
572
|
activeRoute,
|
|
565
|
-
depth = 0
|
|
573
|
+
depth = 0,
|
|
574
|
+
expanded: expandedProp,
|
|
575
|
+
onToggle
|
|
566
576
|
}) => {
|
|
567
|
-
const [
|
|
577
|
+
const [internalExpanded, setExpanded] = React.useState(() => hasActiveDescendant(item, pathname));
|
|
578
|
+
const expanded = expandedProp ?? internalExpanded;
|
|
568
579
|
const [focused, setFocused] = React.useState(false);
|
|
569
580
|
const [hovered, setHovered] = React.useState(false);
|
|
570
581
|
const { theme } = uiFeedback.useUi();
|
|
571
582
|
const colors = theme.colors;
|
|
572
583
|
const primaryColor = theme.palette.primary["500"];
|
|
573
|
-
const toggle = React.useCallback(() =>
|
|
584
|
+
const toggle = React.useCallback(() => {
|
|
585
|
+
if (onToggle !== void 0) onToggle(item.key);
|
|
586
|
+
else setExpanded((v) => !v);
|
|
587
|
+
}, [onToggle, item.key]);
|
|
574
588
|
const onHoverIn = React.useCallback(() => setHovered(true), []);
|
|
575
589
|
const onHoverOut = React.useCallback(() => setHovered(false), []);
|
|
576
590
|
const indent = depth * BASE_INDENT;
|
|
@@ -681,9 +695,72 @@ var DEFAULT_SEARCH_BREAKPOINT = uiLayout.LAYOUT_COLLAPSE_BREAKPOINT;
|
|
|
681
695
|
function resolveSearchAffordance(viewport, breakpoint = DEFAULT_SEARCH_BREAKPOINT) {
|
|
682
696
|
return viewport >= breakpoint ? "inline" : "palette";
|
|
683
697
|
}
|
|
698
|
+
|
|
699
|
+
// src/sidebarEdgeFade.ts
|
|
700
|
+
var EDGE_TOLERANCE = 1;
|
|
701
|
+
function resolveEdgeFades({ offsetY, viewportHeight, contentHeight }) {
|
|
702
|
+
const hiddenBelow = contentHeight - (offsetY + viewportHeight);
|
|
703
|
+
return { top: offsetY > EDGE_TOLERANCE, bottom: hiddenBelow > EDGE_TOLERANCE };
|
|
704
|
+
}
|
|
705
|
+
var FADE_BAND_HEIGHT = 6;
|
|
706
|
+
var FADE_BAND_OPACITIES = [0.9, 0.65, 0.4, 0.15];
|
|
707
|
+
var SCROLL_EVENT_THROTTLE_MS = 16;
|
|
708
|
+
var styles2 = reactNative.StyleSheet.create({
|
|
709
|
+
area: { flex: 1, minHeight: 0 },
|
|
710
|
+
fade: { position: "absolute", left: 0, right: 0 },
|
|
711
|
+
fadeTop: { top: 0 },
|
|
712
|
+
fadeBottom: { bottom: 0, flexDirection: "column-reverse" },
|
|
713
|
+
band: { height: FADE_BAND_HEIGHT }
|
|
714
|
+
});
|
|
715
|
+
function EdgeFade({ edge, color }) {
|
|
716
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
717
|
+
reactNative.View,
|
|
718
|
+
{
|
|
719
|
+
pointerEvents: "none",
|
|
720
|
+
style: [styles2.fade, edge === "top" ? styles2.fadeTop : styles2.fadeBottom],
|
|
721
|
+
testID: `sidebar-fade-${edge}`,
|
|
722
|
+
children: FADE_BAND_OPACITIES.map((opacity) => /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles2.band, { backgroundColor: color, opacity }] }, opacity))
|
|
723
|
+
}
|
|
724
|
+
);
|
|
725
|
+
}
|
|
726
|
+
var SidebarScrollArea = ({ children }) => {
|
|
727
|
+
const { theme } = uiFeedback.useUi();
|
|
728
|
+
const metrics = React.useRef({ offsetY: 0, viewportHeight: 0, contentHeight: 0 });
|
|
729
|
+
const [fades, setFades] = React.useState({ top: false, bottom: false });
|
|
730
|
+
const update = React.useCallback((next) => {
|
|
731
|
+
metrics.current = { ...metrics.current, ...next };
|
|
732
|
+
const resolved = resolveEdgeFades(metrics.current);
|
|
733
|
+
setFades((prev) => prev.top === resolved.top && prev.bottom === resolved.bottom ? prev : resolved);
|
|
734
|
+
}, []);
|
|
735
|
+
const onLayout = React.useCallback(
|
|
736
|
+
(e) => update({ viewportHeight: e.nativeEvent.layout.height }),
|
|
737
|
+
[update]
|
|
738
|
+
);
|
|
739
|
+
const onContentSizeChange = React.useCallback((_w, h) => update({ contentHeight: h }), [update]);
|
|
740
|
+
const onScroll = React.useCallback(
|
|
741
|
+
(e) => update({ offsetY: e.nativeEvent.contentOffset.y }),
|
|
742
|
+
[update]
|
|
743
|
+
);
|
|
744
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles2.area, children: [
|
|
745
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
746
|
+
reactNative.ScrollView,
|
|
747
|
+
{
|
|
748
|
+
scrollEventThrottle: SCROLL_EVENT_THROTTLE_MS,
|
|
749
|
+
style: styles2.area,
|
|
750
|
+
testID: "sidebar-scroll",
|
|
751
|
+
onContentSizeChange,
|
|
752
|
+
onLayout,
|
|
753
|
+
onScroll,
|
|
754
|
+
children
|
|
755
|
+
}
|
|
756
|
+
),
|
|
757
|
+
fades.top ? /* @__PURE__ */ jsxRuntime.jsx(EdgeFade, { color: theme.colors.surface, edge: "top" }) : null,
|
|
758
|
+
fades.bottom ? /* @__PURE__ */ jsxRuntime.jsx(EdgeFade, { color: theme.colors.surface, edge: "bottom" }) : null
|
|
759
|
+
] });
|
|
760
|
+
};
|
|
684
761
|
var FIELD_MIN_HEIGHT = 38;
|
|
685
762
|
var CLEAR_GLYPH = "\u2715";
|
|
686
|
-
var
|
|
763
|
+
var styles3 = reactNative.StyleSheet.create({
|
|
687
764
|
wrap: {
|
|
688
765
|
flexDirection: "row",
|
|
689
766
|
alignItems: "center",
|
|
@@ -724,7 +801,7 @@ var SidebarSearch = ({
|
|
|
724
801
|
reactNative.View,
|
|
725
802
|
{
|
|
726
803
|
style: [
|
|
727
|
-
|
|
804
|
+
styles3.wrap,
|
|
728
805
|
{ backgroundColor: colors.surface, borderColor: focused ? primary : colors.border },
|
|
729
806
|
focusRingStyle(focused, primary)
|
|
730
807
|
],
|
|
@@ -736,7 +813,7 @@ var SidebarSearch = ({
|
|
|
736
813
|
accessibilityLabel: labels.placeholder,
|
|
737
814
|
placeholder: labels.placeholder,
|
|
738
815
|
placeholderTextColor: colors.textSecondary,
|
|
739
|
-
style: [
|
|
816
|
+
style: [styles3.input, { color: colors.text }],
|
|
740
817
|
testID,
|
|
741
818
|
value,
|
|
742
819
|
onBlur: () => setFocused(false),
|
|
@@ -750,10 +827,10 @@ var SidebarSearch = ({
|
|
|
750
827
|
accessibilityHint: labels.clearHint,
|
|
751
828
|
accessibilityLabel: labels.clearLabel,
|
|
752
829
|
accessibilityRole: "button",
|
|
753
|
-
style:
|
|
830
|
+
style: styles3.clear,
|
|
754
831
|
testID: `${testID}-clear`,
|
|
755
832
|
onPress: onClear,
|
|
756
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [
|
|
833
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles3.clearGlyph, { color: colors.textSecondary }], children: CLEAR_GLYPH })
|
|
757
834
|
}
|
|
758
835
|
) : null
|
|
759
836
|
]
|
|
@@ -812,6 +889,10 @@ var Sidebar = ({
|
|
|
812
889
|
const visibleItems = showInlineSearch ? filterNavItems(items, query) : items;
|
|
813
890
|
const showEmpty = showInlineSearch && isFilterActive(query) && visibleItems.length === 0;
|
|
814
891
|
const activeRoute = resolveActiveRoute(items, pathname);
|
|
892
|
+
const accordion = React.useContext(NavAccordionContext);
|
|
893
|
+
const [openGroup, setOpenGroup] = React.useState(() => initialOpenGroup(items, pathname));
|
|
894
|
+
const toggleGroup = React.useCallback((key) => setOpenGroup((current) => nextOpenGroup(current, key)), []);
|
|
895
|
+
const accordionProps = (item) => accordion && (item.children ?? []).length > 0 ? { expanded: openGroup === item.key, onToggle: toggleGroup } : {};
|
|
815
896
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
816
897
|
reactNative.View,
|
|
817
898
|
{
|
|
@@ -845,22 +926,24 @@ var Sidebar = ({
|
|
|
845
926
|
onPress: paletteTrigger.onOpen
|
|
846
927
|
}
|
|
847
928
|
) }) : null,
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
929
|
+
/* @__PURE__ */ jsxRuntime.jsxs(SidebarScrollArea, { children: [
|
|
930
|
+
renderTextSlot(header, { color: colors.text }),
|
|
931
|
+
showEmpty && search !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [navStyles.sidebarEmpty, { color: colors.textSecondary }], testID: "sidebar-search-empty", children: search.emptyText }) : visibleItems.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
932
|
+
NavExpandableItem,
|
|
933
|
+
{
|
|
934
|
+
activeRoute,
|
|
935
|
+
collapseHint,
|
|
936
|
+
expandHint,
|
|
937
|
+
item,
|
|
938
|
+
navigateHint,
|
|
939
|
+
pathname,
|
|
940
|
+
renderChevron,
|
|
941
|
+
onNavigate,
|
|
942
|
+
...accordionProps(item)
|
|
943
|
+
},
|
|
944
|
+
item.key
|
|
945
|
+
))
|
|
946
|
+
] }),
|
|
864
947
|
renderTextSlot(footer, { color: colors.text })
|
|
865
948
|
]
|
|
866
949
|
}
|
|
@@ -1582,7 +1665,7 @@ var NavBar = ({ barTheme, ...props }) => {
|
|
|
1582
1665
|
if (barTheme === void 0) return /* @__PURE__ */ jsxRuntime.jsx(NavBarInner, { ...props });
|
|
1583
1666
|
return /* @__PURE__ */ jsxRuntime.jsx(uiFeedback.UiProvider, { navigate, t, theme: barTheme, children: /* @__PURE__ */ jsxRuntime.jsx(NavBarInner, { ...props }) });
|
|
1584
1667
|
};
|
|
1585
|
-
var
|
|
1668
|
+
var styles4 = reactNative.StyleSheet.create({
|
|
1586
1669
|
hitBox: { minHeight: MIN_TOUCH_TARGET, minWidth: MIN_TOUCH_TARGET, justifyContent: "center" }
|
|
1587
1670
|
});
|
|
1588
1671
|
function anchorProps(route) {
|
|
@@ -1605,7 +1688,7 @@ var BrandHomeLink = ({ route, label, onNavigate, children }) => {
|
|
|
1605
1688
|
{
|
|
1606
1689
|
accessibilityLabel: label,
|
|
1607
1690
|
accessibilityRole: "link",
|
|
1608
|
-
style: [
|
|
1691
|
+
style: [styles4.hitBox, focusRingStyle(focused, theme.palette.primary["500"])],
|
|
1609
1692
|
testID: NAV_TEST_IDS.brandHome,
|
|
1610
1693
|
onBlur: () => setFocused(false),
|
|
1611
1694
|
onFocus: () => setFocused(true),
|
|
@@ -1618,7 +1701,7 @@ var BrandHomeLink = ({ route, label, onNavigate, children }) => {
|
|
|
1618
1701
|
var DEFAULT_ICON_SIZE = 32;
|
|
1619
1702
|
var NAME_FONT_SIZE = 16;
|
|
1620
1703
|
var NAME_GAP = 8;
|
|
1621
|
-
var
|
|
1704
|
+
var styles5 = reactNative.StyleSheet.create({
|
|
1622
1705
|
name: { flexShrink: 1, fontSize: NAME_FONT_SIZE, fontWeight: "700" },
|
|
1623
1706
|
row: { alignItems: "center", flexDirection: "row", gap: NAME_GAP }
|
|
1624
1707
|
});
|
|
@@ -1632,7 +1715,7 @@ var BrandMark = ({
|
|
|
1632
1715
|
iconOnly = false
|
|
1633
1716
|
}) => {
|
|
1634
1717
|
const { theme } = uiFeedback.useUi();
|
|
1635
|
-
return /* @__PURE__ */ jsxRuntime.jsx(BrandHomeLink, { label, route, onNavigate, children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
1718
|
+
return /* @__PURE__ */ jsxRuntime.jsx(BrandHomeLink, { label, route, onNavigate, children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles5.row, children: [
|
|
1636
1719
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1637
1720
|
reactNative.Image,
|
|
1638
1721
|
{
|
|
@@ -1646,7 +1729,7 @@ var BrandMark = ({
|
|
|
1646
1729
|
reactNative.Text,
|
|
1647
1730
|
{
|
|
1648
1731
|
numberOfLines: 1,
|
|
1649
|
-
style: [
|
|
1732
|
+
style: [styles5.name, { color: theme.colors.text }],
|
|
1650
1733
|
testID: NAV_TEST_IDS.brandMarkName,
|
|
1651
1734
|
children: name
|
|
1652
1735
|
}
|
|
@@ -1659,7 +1742,7 @@ var Nav = (props) => {
|
|
|
1659
1742
|
}
|
|
1660
1743
|
return /* @__PURE__ */ jsxRuntime.jsx(NavBar, { ...props });
|
|
1661
1744
|
};
|
|
1662
|
-
var
|
|
1745
|
+
var styles6 = reactNative.StyleSheet.create({
|
|
1663
1746
|
band: { left: 0, position: "absolute", right: 0, top: 0 }
|
|
1664
1747
|
});
|
|
1665
1748
|
function readBackdrop(theme) {
|
|
@@ -1682,7 +1765,7 @@ function resolveShellBackdrop(theme, viewport, contentPadding, testID) {
|
|
|
1682
1765
|
reactNative.View,
|
|
1683
1766
|
{
|
|
1684
1767
|
pointerEvents: "none",
|
|
1685
|
-
style: [
|
|
1768
|
+
style: [styles6.band, { backgroundColor: band.color, height: contentPadding + overlap }],
|
|
1686
1769
|
testID: `${testID}${APP_SHELL_SUFFIX.band}`
|
|
1687
1770
|
}
|
|
1688
1771
|
);
|
|
@@ -1694,7 +1777,7 @@ var CARD_BORDER_WIDTH = 1;
|
|
|
1694
1777
|
var CARD_TITLE_FONT_SIZE = 16;
|
|
1695
1778
|
var CARD_MESSAGE_FONT_SIZE = 14;
|
|
1696
1779
|
var CARD_TITLE_MARGIN_BOTTOM = 8;
|
|
1697
|
-
var
|
|
1780
|
+
var styles7 = reactNative.StyleSheet.create({
|
|
1698
1781
|
// Loading is a TRANSITIONAL state: the spinner is an absolute overlay ON TOP of
|
|
1699
1782
|
// stably-mounted children, never a replacement for them. Replacing children here
|
|
1700
1783
|
// would unmount whatever they host (e.g. a navigator), and on remount React
|
|
@@ -1726,9 +1809,9 @@ function MessageCard({
|
|
|
1726
1809
|
}) {
|
|
1727
1810
|
const { theme } = uiFeedback.useUi();
|
|
1728
1811
|
const colors = theme.colors;
|
|
1729
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [
|
|
1730
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [
|
|
1731
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [
|
|
1812
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles7.card, { backgroundColor: colors.surface, borderColor: accentColor }], testID, children: [
|
|
1813
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles7.cardTitle, { color: accentColor }], children: message.titleText }),
|
|
1814
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles7.cardMessage, { color: colors.textSecondary }], children: message.messageText })
|
|
1732
1815
|
] });
|
|
1733
1816
|
}
|
|
1734
1817
|
function useContentBody(state, children, testID) {
|
|
@@ -1740,12 +1823,12 @@ function useContentBody(state, children, testID) {
|
|
|
1740
1823
|
return /* @__PURE__ */ jsxRuntime.jsx(MessageCard, { accentColor: errorColor, message: state.forbidden, testID: `${testID}${APP_SHELL_SUFFIX.forbidden}` });
|
|
1741
1824
|
if (state.error)
|
|
1742
1825
|
return /* @__PURE__ */ jsxRuntime.jsx(MessageCard, { accentColor: errorColor, message: state.error, testID: `${testID}${APP_SHELL_SUFFIX.error}` });
|
|
1743
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
1826
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles7.loadingHost, children: [
|
|
1744
1827
|
children,
|
|
1745
1828
|
state.loading === true ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1746
1829
|
reactNative.View,
|
|
1747
1830
|
{
|
|
1748
|
-
style: [
|
|
1831
|
+
style: [styles7.loadingOverlay, { backgroundColor: theme.colors.background }],
|
|
1749
1832
|
testID: `${testID}${APP_SHELL_SUFFIX.loading}`,
|
|
1750
1833
|
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: primary, size: "large" })
|
|
1751
1834
|
}
|
|
@@ -1772,7 +1855,7 @@ var DEFAULT_DRAWER_LABELS = {
|
|
|
1772
1855
|
closeLabel: "Close menu",
|
|
1773
1856
|
closeHint: "Close the navigation menu"
|
|
1774
1857
|
};
|
|
1775
|
-
var
|
|
1858
|
+
var styles8 = reactNative.StyleSheet.create({
|
|
1776
1859
|
overlay: { ...reactNative.StyleSheet.absoluteFillObject, zIndex: DRAWER_Z_INDEX },
|
|
1777
1860
|
// The scrim's tap-to-close hit area is anchored to the RIGHT of the panel
|
|
1778
1861
|
// (`left: DRAWER_WIDTH`), so it NEVER overlaps the panel: nav-item taps always
|
|
@@ -1807,10 +1890,10 @@ var MenuToggle = ({ label, hint, onOpen, testID }) => {
|
|
|
1807
1890
|
accessibilityHint: hint,
|
|
1808
1891
|
accessibilityLabel: label,
|
|
1809
1892
|
ringColor: theme.palette.primary["500"],
|
|
1810
|
-
style:
|
|
1893
|
+
style: styles8.menuToggle,
|
|
1811
1894
|
testID,
|
|
1812
1895
|
onPress: onOpen,
|
|
1813
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [
|
|
1896
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles8.menuToggleGlyph, { color: theme.colors.text }], children: MENU_GLYPH2 })
|
|
1814
1897
|
}
|
|
1815
1898
|
);
|
|
1816
1899
|
};
|
|
@@ -1836,14 +1919,14 @@ var MobileDrawer = ({
|
|
|
1836
1919
|
node.addEventListener("click", handleClick);
|
|
1837
1920
|
return () => node.removeEventListener("click", handleClick);
|
|
1838
1921
|
}, [onClose]);
|
|
1839
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
1922
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles8.overlay, children: [
|
|
1840
1923
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1841
1924
|
reactNative.Pressable,
|
|
1842
1925
|
{
|
|
1843
1926
|
accessibilityHint: labels.closeHint,
|
|
1844
1927
|
accessibilityLabel: labels.closeLabel,
|
|
1845
1928
|
accessibilityRole: "button",
|
|
1846
|
-
style:
|
|
1929
|
+
style: styles8.scrim,
|
|
1847
1930
|
testID: scrimTestID,
|
|
1848
1931
|
onPress: onClose
|
|
1849
1932
|
}
|
|
@@ -1854,9 +1937,9 @@ var MobileDrawer = ({
|
|
|
1854
1937
|
ref: panelRef,
|
|
1855
1938
|
"aria-modal": true,
|
|
1856
1939
|
role: "dialog",
|
|
1857
|
-
style: [
|
|
1940
|
+
style: [styles8.panel, { backgroundColor: theme.colors.surface }],
|
|
1858
1941
|
testID: drawerTestID,
|
|
1859
|
-
children: renderTextSlot(sidebar, { color: theme.colors.text })
|
|
1942
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(NavAccordionContext.Provider, { value: true, children: renderTextSlot(sidebar, { color: theme.colors.text }) })
|
|
1860
1943
|
}
|
|
1861
1944
|
)
|
|
1862
1945
|
] });
|
|
@@ -1872,7 +1955,7 @@ function useContentMaxWidth(width) {
|
|
|
1872
1955
|
return resolveContentMaxWidth(width, viewport);
|
|
1873
1956
|
}
|
|
1874
1957
|
var DEFAULT_CONTENT_PADDING = 24;
|
|
1875
|
-
var
|
|
1958
|
+
var styles9 = reactNative.StyleSheet.create({
|
|
1876
1959
|
root: { flex: 1 },
|
|
1877
1960
|
// Auth-pending spinner: an opaque absolute overlay over the mounted shell, so
|
|
1878
1961
|
// `children` (and any navigator they host) are never unmounted while the gate
|
|
@@ -1934,13 +2017,13 @@ var AppShell = ({
|
|
|
1934
2017
|
}, [isUnauthenticated, gate]);
|
|
1935
2018
|
const gatePending = gate?.pending === true;
|
|
1936
2019
|
if (isUnauthenticated) return null;
|
|
1937
|
-
const columnStyle = maxWidth === "full" ?
|
|
1938
|
-
const navInnerStyle = chromeAlignment === "content" && maxWidth !== "full" ? [
|
|
2020
|
+
const columnStyle = maxWidth === "full" ? styles9.columnFull : [styles9.columnCapped, { maxWidth }];
|
|
2021
|
+
const navInnerStyle = chromeAlignment === "content" && maxWidth !== "full" ? [styles9.chromeCapped, { maxWidth, paddingHorizontal: contentPadding }] : void 0;
|
|
1939
2022
|
const scroller = /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1940
2023
|
reactNative.ScrollView,
|
|
1941
2024
|
{
|
|
1942
|
-
contentContainerStyle: [
|
|
1943
|
-
style:
|
|
2025
|
+
contentContainerStyle: [styles9.scrollContent, { padding: contentPadding }],
|
|
2026
|
+
style: styles9.scroll,
|
|
1944
2027
|
testID: `${testID}${APP_SHELL_SUFFIX.content}`,
|
|
1945
2028
|
children: [
|
|
1946
2029
|
look.band,
|
|
@@ -1948,7 +2031,7 @@ var AppShell = ({
|
|
|
1948
2031
|
]
|
|
1949
2032
|
}
|
|
1950
2033
|
);
|
|
1951
|
-
const headerRegion = useDrawer ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [
|
|
2034
|
+
const headerRegion = useDrawer ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles9.headerRow, look.chrome], testID: `${testID}${APP_SHELL_SUFFIX.header}`, children: [
|
|
1952
2035
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1953
2036
|
MenuToggle,
|
|
1954
2037
|
{
|
|
@@ -1958,14 +2041,14 @@ var AppShell = ({
|
|
|
1958
2041
|
onOpen: openDrawer
|
|
1959
2042
|
}
|
|
1960
2043
|
),
|
|
1961
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style:
|
|
2044
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles9.headerFill, children: renderTextSlot(header, { color: look.chromeText }) })
|
|
1962
2045
|
] }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: look.chrome, testID: `${testID}${APP_SHELL_SUFFIX.header}`, children: renderTextSlot(header, { color: look.chromeText }) });
|
|
1963
2046
|
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;
|
|
1964
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [
|
|
2047
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles9.root, look.root], testID, children: [
|
|
1965
2048
|
headerRegion,
|
|
1966
2049
|
nav !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: look.chrome, testID: `${testID}${APP_SHELL_SUFFIX.nav}`, children: navInnerStyle !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: navInnerStyle, children: renderTextSlot(nav, { color: look.chromeText }) }) : renderTextSlot(nav, { color: look.chromeText }) }) : null,
|
|
1967
2050
|
banner !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { testID: `${testID}${APP_SHELL_SUFFIX.banner}`, children: renderTextSlot(banner, { color: theme.colors.text }) }) : null,
|
|
1968
|
-
railRegion !== null ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
2051
|
+
railRegion !== null ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles9.bodyRow, children: [
|
|
1969
2052
|
railRegion,
|
|
1970
2053
|
scroller
|
|
1971
2054
|
] }) : scroller,
|
|
@@ -1982,7 +2065,7 @@ var AppShell = ({
|
|
|
1982
2065
|
gatePending ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1983
2066
|
reactNative.View,
|
|
1984
2067
|
{
|
|
1985
|
-
style: [
|
|
2068
|
+
style: [styles9.pendingOverlay, { backgroundColor: theme.colors.background }],
|
|
1986
2069
|
testID: `${testID}${APP_SHELL_SUFFIX.pending}`,
|
|
1987
2070
|
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: primary, size: "large" })
|
|
1988
2071
|
}
|
|
@@ -2351,7 +2434,7 @@ var KEY_DOWN = "ArrowDown";
|
|
|
2351
2434
|
var KEY_UP = "ArrowUp";
|
|
2352
2435
|
var KEY_ENTER = "Enter";
|
|
2353
2436
|
var KEY_ESCAPE = "Escape";
|
|
2354
|
-
var
|
|
2437
|
+
var styles10 = reactNative.StyleSheet.create({
|
|
2355
2438
|
overlay: { ...reactNative.StyleSheet.absoluteFillObject, zIndex: OVERLAY_Z_INDEX, alignItems: "center" },
|
|
2356
2439
|
scrim: { ...reactNative.StyleSheet.absoluteFillObject, backgroundColor: SCRIM_COLOR2 },
|
|
2357
2440
|
panel: {
|
|
@@ -2380,14 +2463,14 @@ var PaletteRow = ({ item, selected, onChoose }) => {
|
|
|
2380
2463
|
accessibilityLabel: item.label,
|
|
2381
2464
|
accessibilityRole: "button",
|
|
2382
2465
|
accessibilityState: { selected },
|
|
2383
|
-
style: [
|
|
2466
|
+
style: [styles10.row, selected ? { backgroundColor: colors.border } : void 0],
|
|
2384
2467
|
testID: item.testID ?? item.key,
|
|
2385
2468
|
onPress: () => onChoose(item),
|
|
2386
2469
|
children: [
|
|
2387
2470
|
typeof item.renderIcon === "function" ? item.renderIcon(colors.textSecondary, NAV_ICON_SIZE) : null,
|
|
2388
|
-
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
2389
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [
|
|
2390
|
-
item.hint ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [
|
|
2471
|
+
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles10.rowText, children: [
|
|
2472
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles10.rowLabel, { color: colors.text }], children: item.label }),
|
|
2473
|
+
item.hint ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles10.rowHint, { color: colors.textSecondary }], children: item.hint }) : null
|
|
2391
2474
|
] })
|
|
2392
2475
|
]
|
|
2393
2476
|
}
|
|
@@ -2427,14 +2510,14 @@ var CommandPalette = ({ open, items, onClose, labels, testID }) => {
|
|
|
2427
2510
|
[results, selected, choose, onClose]
|
|
2428
2511
|
);
|
|
2429
2512
|
if (!open) return null;
|
|
2430
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
2513
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles10.overlay, children: [
|
|
2431
2514
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2432
2515
|
reactNative.Pressable,
|
|
2433
2516
|
{
|
|
2434
2517
|
accessibilityHint: labels.closeHint,
|
|
2435
2518
|
accessibilityLabel: labels.closeLabel,
|
|
2436
2519
|
accessibilityRole: "button",
|
|
2437
|
-
style:
|
|
2520
|
+
style: styles10.scrim,
|
|
2438
2521
|
testID: `${testID ?? "command-palette"}-scrim`,
|
|
2439
2522
|
onPress: onClose
|
|
2440
2523
|
}
|
|
@@ -2445,7 +2528,7 @@ var CommandPalette = ({ open, items, onClose, labels, testID }) => {
|
|
|
2445
2528
|
"aria-modal": true,
|
|
2446
2529
|
"aria-label": labels.regionLabel,
|
|
2447
2530
|
role: "dialog",
|
|
2448
|
-
style: [
|
|
2531
|
+
style: [styles10.panel, { backgroundColor: colors.surface, borderColor: colors.border }],
|
|
2449
2532
|
testID: testID ?? "command-palette",
|
|
2450
2533
|
children: [
|
|
2451
2534
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -2455,14 +2538,14 @@ var CommandPalette = ({ open, items, onClose, labels, testID }) => {
|
|
|
2455
2538
|
accessibilityLabel: labels.placeholder,
|
|
2456
2539
|
placeholder: labels.placeholder,
|
|
2457
2540
|
placeholderTextColor: colors.textSecondary,
|
|
2458
|
-
style: [
|
|
2541
|
+
style: [styles10.input, { color: colors.text, borderBottomColor: colors.border }],
|
|
2459
2542
|
testID: `${testID ?? "command-palette"}-input`,
|
|
2460
2543
|
value: query,
|
|
2461
2544
|
onChangeText: setQuery,
|
|
2462
2545
|
onKeyPress
|
|
2463
2546
|
}
|
|
2464
2547
|
),
|
|
2465
|
-
results.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [
|
|
2548
|
+
results.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles10.empty, { color: colors.textSecondary }], children: labels.emptyText }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.ScrollView, { keyboardShouldPersistTaps: "handled", style: styles10.list, children: results.map((item, index) => /* @__PURE__ */ jsxRuntime.jsx(PaletteRow, { item, selected: index === selected, onChoose: choose }, item.key)) })
|
|
2466
2549
|
]
|
|
2467
2550
|
}
|
|
2468
2551
|
)
|
|
@@ -2567,7 +2650,7 @@ var TAB_MIN_HEIGHT = 56;
|
|
|
2567
2650
|
var LABEL_SIZE = 12;
|
|
2568
2651
|
var LABEL_GAP = 2;
|
|
2569
2652
|
var TAB_PADDING = 4;
|
|
2570
|
-
var
|
|
2653
|
+
var styles11 = reactNative.StyleSheet.create({
|
|
2571
2654
|
tab: {
|
|
2572
2655
|
flex: 1,
|
|
2573
2656
|
minHeight: TAB_MIN_HEIGHT,
|
|
@@ -2604,31 +2687,31 @@ var BottomTab = ({
|
|
|
2604
2687
|
accessibilityLabel: item.label,
|
|
2605
2688
|
accessibilityRole: "link",
|
|
2606
2689
|
accessibilityState: { selected: isActive },
|
|
2607
|
-
style: [
|
|
2690
|
+
style: [styles11.tab, { opacity: feedback.opacity }],
|
|
2608
2691
|
testID: item.testID ?? item.key,
|
|
2609
2692
|
onPress: () => onPress(item.route),
|
|
2610
2693
|
onPressIn: () => setPressed(true),
|
|
2611
2694
|
onPressOut: () => setPressed(false),
|
|
2612
2695
|
...ariaCurrentProps3(isActive),
|
|
2613
2696
|
children: [
|
|
2614
|
-
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.Animated.View, { style: [
|
|
2697
|
+
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.Animated.View, { style: [styles11.iconWrap, { transform: [{ scale }] }], children: [
|
|
2615
2698
|
feedback.pillScale === null ? null : /* @__PURE__ */ jsxRuntime.jsx(
|
|
2616
2699
|
reactNative.View,
|
|
2617
2700
|
{
|
|
2618
2701
|
pointerEvents: "none",
|
|
2619
|
-
style: [
|
|
2702
|
+
style: [styles11.pill, { backgroundColor: colors.pill, transform: [{ scale: feedback.pillScale }] }, motion]
|
|
2620
2703
|
}
|
|
2621
2704
|
),
|
|
2622
2705
|
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [{ transform: feedback.iconTransform }, motion], children: item.renderIcon?.(color, ICON_SIZE) })
|
|
2623
2706
|
] }),
|
|
2624
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [
|
|
2707
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles11.label, { color }], children: item.label })
|
|
2625
2708
|
]
|
|
2626
2709
|
}
|
|
2627
2710
|
);
|
|
2628
2711
|
};
|
|
2629
2712
|
var DEFAULT_TEST_ID = "bottom-tab-bar";
|
|
2630
2713
|
var SLIDER_HEIGHT = 3;
|
|
2631
|
-
var
|
|
2714
|
+
var styles12 = reactNative.StyleSheet.create({
|
|
2632
2715
|
bar: { flexDirection: "row", borderTopWidth: reactNative.StyleSheet.hairlineWidth },
|
|
2633
2716
|
slider: { position: "absolute", top: 0, height: SLIDER_HEIGHT }
|
|
2634
2717
|
});
|
|
@@ -2655,14 +2738,14 @@ var BottomTabBar = ({
|
|
|
2655
2738
|
{
|
|
2656
2739
|
"aria-label": regionLabel,
|
|
2657
2740
|
role: "navigation",
|
|
2658
|
-
style: [
|
|
2741
|
+
style: [styles12.bar, { backgroundColor: theme.colors.surface, borderTopColor: theme.colors.border }, containerStyle],
|
|
2659
2742
|
testID,
|
|
2660
2743
|
children: [
|
|
2661
2744
|
bar === null ? null : /* @__PURE__ */ jsxRuntime.jsx(
|
|
2662
2745
|
reactNative.View,
|
|
2663
2746
|
{
|
|
2664
2747
|
pointerEvents: "none",
|
|
2665
|
-
style: [
|
|
2748
|
+
style: [styles12.slider, { left: bar.left, width: bar.width, backgroundColor: primary }, webTransition("left", barMs, reducedMotion)]
|
|
2666
2749
|
}
|
|
2667
2750
|
),
|
|
2668
2751
|
items.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
|