@terreno/ui 0.8.3 → 0.9.1
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/Common.d.ts +106 -0
- package/dist/Common.js +10 -0
- package/dist/Common.js.map +1 -1
- package/dist/ConsentFormScreen.d.ts +1 -0
- package/dist/ConsentFormScreen.js +5 -2
- package/dist/ConsentFormScreen.js.map +1 -1
- package/dist/ConsentNavigator.d.ts +2 -0
- package/dist/ConsentNavigator.js +15 -3
- package/dist/ConsentNavigator.js.map +1 -1
- package/dist/DateTimeField.js +2 -2
- package/dist/DateTimeField.js.map +1 -1
- package/dist/SidebarNavigation.d.ts +15 -0
- package/dist/SidebarNavigation.js +143 -0
- package/dist/SidebarNavigation.js.map +1 -0
- package/dist/SidebarNavigation.native.d.ts +22 -0
- package/dist/SidebarNavigation.native.js +171 -0
- package/dist/SidebarNavigation.native.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
- package/src/Common.ts +111 -0
- package/src/ConsentFormScreen.tsx +6 -1
- package/src/ConsentNavigator.test.tsx +56 -0
- package/src/ConsentNavigator.tsx +19 -0
- package/src/DateTimeField.tsx +2 -2
- package/src/SidebarNavigation.native.tsx +331 -0
- package/src/SidebarNavigation.tsx +291 -0
- package/src/__snapshots__/Field.test.tsx.snap +13 -13
- package/src/index.tsx +1 -0
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { TabRouter } from "@react-navigation/native";
|
|
3
|
+
import { Navigator, Slot } from "expo-router";
|
|
4
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
5
|
+
import { Animated, Dimensions, Pressable, View } from "react-native";
|
|
6
|
+
import { Badge } from "./Badge";
|
|
7
|
+
import { SIDEBAR_BADGE_STATUS_MAP } from "./Common";
|
|
8
|
+
import { Icon } from "./Icon";
|
|
9
|
+
import { Text } from "./Text";
|
|
10
|
+
import { useTheme } from "./Theme";
|
|
11
|
+
const DRAWER_WIDTH = 280;
|
|
12
|
+
const ITEM_HEIGHT = 48;
|
|
13
|
+
const ICON_SIZE = 20;
|
|
14
|
+
const BACKDROP_OPACITY = 0.5;
|
|
15
|
+
const ANIMATION_DURATION = 250;
|
|
16
|
+
const SidebarItem = ({ item, isActive, onPress, itemStyle }) => {
|
|
17
|
+
var _a;
|
|
18
|
+
const { theme } = useTheme();
|
|
19
|
+
const handlePress = useCallback(() => {
|
|
20
|
+
onPress(item.route);
|
|
21
|
+
}, [onPress, item.route]);
|
|
22
|
+
return (_jsxs(Pressable, { accessibilityLabel: item.label, accessibilityRole: "button", onPress: handlePress, style: [
|
|
23
|
+
{
|
|
24
|
+
alignItems: "center",
|
|
25
|
+
backgroundColor: isActive ? theme.surface.secondaryLight : "transparent",
|
|
26
|
+
borderRadius: theme.radius.default,
|
|
27
|
+
flexDirection: "row",
|
|
28
|
+
gap: 14,
|
|
29
|
+
height: ITEM_HEIGHT,
|
|
30
|
+
marginHorizontal: 12,
|
|
31
|
+
paddingHorizontal: 14,
|
|
32
|
+
},
|
|
33
|
+
itemStyle,
|
|
34
|
+
], children: [_jsxs(View, { style: { alignItems: "center", justifyContent: "center", width: ICON_SIZE }, children: [_jsx(Icon, { color: isActive ? "primary" : "secondaryDark", iconName: item.iconName, size: "md" }), Boolean(item.badge) && (_jsx(View, { style: {
|
|
35
|
+
bottom: item.badge === true ? -4 : undefined,
|
|
36
|
+
position: "absolute",
|
|
37
|
+
right: -6,
|
|
38
|
+
top: item.badge === true ? undefined : -4,
|
|
39
|
+
}, children: _jsx(Badge, { maxValue: 99, status: SIDEBAR_BADGE_STATUS_MAP[(_a = item.badgeStatus) !== null && _a !== void 0 ? _a : "error"], value: item.badge === true ? undefined : String(item.badge), variant: item.badge === true ? "iconOnly" : "numberOnly" }) }))] }), _jsx(Text, { bold: isActive, color: isActive ? "primary" : "secondaryDark", size: "md", children: item.label })] }));
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Renders the hamburger button, drawer overlay, and children. Works without expo-router Navigator context.
|
|
43
|
+
*/
|
|
44
|
+
export const SidebarNavigationPanel = ({ topItems, bottomItems, activeRoute, onNavigate, children, panelStyle, itemStyle, }) => {
|
|
45
|
+
const { theme } = useTheme();
|
|
46
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
47
|
+
const slideAnim = useRef(new Animated.Value(-DRAWER_WIDTH)).current;
|
|
48
|
+
const backdropAnim = useRef(new Animated.Value(0)).current;
|
|
49
|
+
// Animate drawer open/close
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
if (isOpen) {
|
|
52
|
+
Animated.parallel([
|
|
53
|
+
Animated.timing(slideAnim, {
|
|
54
|
+
duration: ANIMATION_DURATION,
|
|
55
|
+
toValue: 0,
|
|
56
|
+
useNativeDriver: true,
|
|
57
|
+
}),
|
|
58
|
+
Animated.timing(backdropAnim, {
|
|
59
|
+
duration: ANIMATION_DURATION,
|
|
60
|
+
toValue: BACKDROP_OPACITY,
|
|
61
|
+
useNativeDriver: true,
|
|
62
|
+
}),
|
|
63
|
+
]).start();
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
Animated.parallel([
|
|
67
|
+
Animated.timing(slideAnim, {
|
|
68
|
+
duration: ANIMATION_DURATION,
|
|
69
|
+
toValue: -DRAWER_WIDTH,
|
|
70
|
+
useNativeDriver: true,
|
|
71
|
+
}),
|
|
72
|
+
Animated.timing(backdropAnim, {
|
|
73
|
+
duration: ANIMATION_DURATION,
|
|
74
|
+
toValue: 0,
|
|
75
|
+
useNativeDriver: true,
|
|
76
|
+
}),
|
|
77
|
+
]).start();
|
|
78
|
+
}
|
|
79
|
+
}, [isOpen, slideAnim, backdropAnim]);
|
|
80
|
+
const handleOpen = useCallback(() => setIsOpen(true), []);
|
|
81
|
+
const handleClose = useCallback(() => setIsOpen(false), []);
|
|
82
|
+
const handleNavigate = useCallback((route) => {
|
|
83
|
+
setIsOpen(false);
|
|
84
|
+
onNavigate(route);
|
|
85
|
+
}, [onNavigate]);
|
|
86
|
+
const screenHeight = Dimensions.get("window").height;
|
|
87
|
+
return (_jsxs(View, { style: { flex: 1 }, children: [children, _jsx(Pressable, { accessibilityLabel: "Open navigation menu", accessibilityRole: "button", onPress: handleOpen, style: {
|
|
88
|
+
alignItems: "center",
|
|
89
|
+
backgroundColor: theme.surface.primary,
|
|
90
|
+
borderRadius: theme.radius.full,
|
|
91
|
+
elevation: 4,
|
|
92
|
+
height: 44,
|
|
93
|
+
justifyContent: "center",
|
|
94
|
+
left: 16,
|
|
95
|
+
position: "absolute",
|
|
96
|
+
shadowColor: "#000",
|
|
97
|
+
shadowOffset: { height: 2, width: 0 },
|
|
98
|
+
shadowOpacity: 0.25,
|
|
99
|
+
shadowRadius: 4,
|
|
100
|
+
top: 16,
|
|
101
|
+
width: 44,
|
|
102
|
+
zIndex: 10,
|
|
103
|
+
}, children: _jsx(Icon, { color: "inverted", iconName: "bars", size: "md" }) }), isOpen && (_jsx(Pressable, { onPress: handleClose, style: {
|
|
104
|
+
bottom: 0,
|
|
105
|
+
left: 0,
|
|
106
|
+
position: "absolute",
|
|
107
|
+
right: 0,
|
|
108
|
+
top: 0,
|
|
109
|
+
zIndex: 100,
|
|
110
|
+
}, children: _jsx(Animated.View, { style: {
|
|
111
|
+
backgroundColor: "#000",
|
|
112
|
+
flex: 1,
|
|
113
|
+
opacity: backdropAnim,
|
|
114
|
+
} }) })), _jsxs(Animated.View, { style: [
|
|
115
|
+
{
|
|
116
|
+
backgroundColor: theme.surface.base,
|
|
117
|
+
borderColor: theme.border.default,
|
|
118
|
+
borderRightWidth: 1,
|
|
119
|
+
height: screenHeight,
|
|
120
|
+
justifyContent: "space-between",
|
|
121
|
+
left: 0,
|
|
122
|
+
paddingBottom: 32,
|
|
123
|
+
paddingTop: 20,
|
|
124
|
+
position: "absolute",
|
|
125
|
+
top: 0,
|
|
126
|
+
transform: [{ translateX: slideAnim }],
|
|
127
|
+
width: DRAWER_WIDTH,
|
|
128
|
+
zIndex: 200,
|
|
129
|
+
},
|
|
130
|
+
panelStyle,
|
|
131
|
+
], children: [_jsxs(View, { children: [_jsx(Pressable, { accessibilityLabel: "Close navigation menu", accessibilityRole: "button", onPress: handleClose, style: {
|
|
132
|
+
alignItems: "center",
|
|
133
|
+
alignSelf: "flex-end",
|
|
134
|
+
height: 40,
|
|
135
|
+
justifyContent: "center",
|
|
136
|
+
marginRight: 12,
|
|
137
|
+
width: 40,
|
|
138
|
+
}, children: _jsx(Icon, { color: "secondaryDark", iconName: "xmark", size: "md" }) }), _jsx(View, { style: { gap: 4, marginTop: 8 }, children: topItems.map((item) => (_jsx(SidebarItem, { isActive: activeRoute === item.route, item: item, itemStyle: itemStyle, onPress: handleNavigate }, item.route))) })] }), _jsx(View, { style: { gap: 4 }, children: bottomItems.map((item) => (_jsx(SidebarItem, { isActive: activeRoute === item.route, item: item, onPress: handleNavigate }, item.route))) })] })] }));
|
|
139
|
+
};
|
|
140
|
+
/**
|
|
141
|
+
* Reads active route from Navigator context and renders the drawer + Slot.
|
|
142
|
+
*/
|
|
143
|
+
const SidebarNavigatorContent = ({ topItems, bottomItems, onNavigate, panelStyle, itemStyle }) => {
|
|
144
|
+
var _a;
|
|
145
|
+
const { state, navigation } = Navigator.useContext();
|
|
146
|
+
const activeRoute = (_a = state.routes[state.index]) === null || _a === void 0 ? void 0 : _a.name;
|
|
147
|
+
const handleNavigate = useCallback((route) => {
|
|
148
|
+
navigation.navigate(route);
|
|
149
|
+
onNavigate === null || onNavigate === void 0 ? void 0 : onNavigate(route);
|
|
150
|
+
}, [navigation, onNavigate]);
|
|
151
|
+
return (_jsx(SidebarNavigationPanel, { activeRoute: activeRoute, bottomItems: bottomItems, itemStyle: itemStyle, onNavigate: handleNavigate, panelStyle: panelStyle, topItems: topItems, children: _jsx(Slot, {}) }));
|
|
152
|
+
};
|
|
153
|
+
/**
|
|
154
|
+
* Custom expo-router navigator with a hamburger-triggered slide-in drawer.
|
|
155
|
+
* Use in _layout.tsx files:
|
|
156
|
+
*
|
|
157
|
+
* ```tsx
|
|
158
|
+
* export default function SidebarLayout() {
|
|
159
|
+
* return (
|
|
160
|
+
* <SidebarNavigation
|
|
161
|
+
* topItems={[{label: "Home", route: "index", iconName: "house"}]}
|
|
162
|
+
* bottomItems={[{label: "Settings", route: "settings", iconName: "gear"}]}
|
|
163
|
+
* />
|
|
164
|
+
* );
|
|
165
|
+
* }
|
|
166
|
+
* ```
|
|
167
|
+
*/
|
|
168
|
+
export const SidebarNavigation = ({ topItems, bottomItems, onNavigate, initialRouteName, screenOptions, panelStyle, itemStyle, }) => {
|
|
169
|
+
return (_jsx(Navigator, { initialRouteName: initialRouteName, router: TabRouter, screenOptions: screenOptions, children: _jsx(SidebarNavigatorContent, { bottomItems: bottomItems, itemStyle: itemStyle, onNavigate: onNavigate, panelStyle: panelStyle, topItems: topItems }) }));
|
|
170
|
+
};
|
|
171
|
+
//# sourceMappingURL=SidebarNavigation.native.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SidebarNavigation.native.js","sourceRoot":"","sources":["../src/SidebarNavigation.native.tsx"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -69,6 +69,7 @@ export * from "./SectionDivider";
|
|
|
69
69
|
export * from "./SegmentedControl";
|
|
70
70
|
export * from "./SelectBadge";
|
|
71
71
|
export * from "./SelectField";
|
|
72
|
+
export * from "./SidebarNavigation";
|
|
72
73
|
export * from "./SideDrawer";
|
|
73
74
|
export * from "./Signature";
|
|
74
75
|
export * from "./SignatureField";
|
package/dist/index.js
CHANGED
|
@@ -68,6 +68,7 @@ export * from "./SectionDivider";
|
|
|
68
68
|
export * from "./SegmentedControl";
|
|
69
69
|
export * from "./SelectBadge";
|
|
70
70
|
export * from "./SelectField";
|
|
71
|
+
export * from "./SidebarNavigation";
|
|
71
72
|
export * from "./SideDrawer";
|
|
72
73
|
export * from "./Signature";
|
|
73
74
|
export * from "./SignatureField";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"@react-native-community/datetimepicker": "8.6.0",
|
|
26
26
|
"@react-native-community/slider": "5.0.1",
|
|
27
27
|
"@react-native-picker/picker": "2.11.4",
|
|
28
|
+
"@react-navigation/native": "^7.1.8",
|
|
28
29
|
"emoji-datasource": "^16.0.0",
|
|
29
30
|
"expo-clipboard": "~8.0.8",
|
|
30
31
|
"expo-document-picker": "~14.0.8",
|
|
@@ -132,5 +133,5 @@
|
|
|
132
133
|
"test:ci": "TZ=America/New_York bun test",
|
|
133
134
|
"types": "bun typedoc"
|
|
134
135
|
},
|
|
135
|
-
"version": "0.
|
|
136
|
+
"version": "0.9.1"
|
|
136
137
|
}
|
package/src/Common.ts
CHANGED
|
@@ -2909,3 +2909,114 @@ export interface UserInactivityProps {
|
|
|
2909
2909
|
*/
|
|
2910
2910
|
timeForInactivity?: number;
|
|
2911
2911
|
}
|
|
2912
|
+
|
|
2913
|
+
/**
|
|
2914
|
+
* Maps badge status keys to their semantic meaning for sidebar navigation items.
|
|
2915
|
+
*/
|
|
2916
|
+
export const SIDEBAR_BADGE_STATUS_MAP = {
|
|
2917
|
+
error: "error",
|
|
2918
|
+
info: "info",
|
|
2919
|
+
neutral: "neutral",
|
|
2920
|
+
success: "success",
|
|
2921
|
+
warning: "warning",
|
|
2922
|
+
} as const;
|
|
2923
|
+
|
|
2924
|
+
export type SidebarBadgeStatus = keyof typeof SIDEBAR_BADGE_STATUS_MAP;
|
|
2925
|
+
|
|
2926
|
+
export interface SidebarNavigationItem {
|
|
2927
|
+
/**
|
|
2928
|
+
* Display text for the navigation item.
|
|
2929
|
+
*/
|
|
2930
|
+
label: string;
|
|
2931
|
+
/**
|
|
2932
|
+
* Route name matching the expo-router file-based route (e.g. "index", "dashboard").
|
|
2933
|
+
*/
|
|
2934
|
+
route: string;
|
|
2935
|
+
/**
|
|
2936
|
+
* FontAwesome 6 icon name rendered alongside the label.
|
|
2937
|
+
*/
|
|
2938
|
+
iconName: IconName;
|
|
2939
|
+
/**
|
|
2940
|
+
* Badge displayed on the icon. A number shows a count (capped at 99+); true shows a dot indicator.
|
|
2941
|
+
*/
|
|
2942
|
+
badge?: number | boolean;
|
|
2943
|
+
/**
|
|
2944
|
+
* Color status of the badge. Defaults to "error".
|
|
2945
|
+
*/
|
|
2946
|
+
badgeStatus?: SidebarBadgeStatus;
|
|
2947
|
+
}
|
|
2948
|
+
|
|
2949
|
+
/**
|
|
2950
|
+
* Props for the SidebarNavigation custom expo-router navigator.
|
|
2951
|
+
* Used in _layout.tsx files to provide sidebar navigation.
|
|
2952
|
+
*/
|
|
2953
|
+
export interface SidebarNavigationProps {
|
|
2954
|
+
/**
|
|
2955
|
+
* Navigation items displayed at the top of the sidebar.
|
|
2956
|
+
*/
|
|
2957
|
+
topItems: SidebarNavigationItem[];
|
|
2958
|
+
/**
|
|
2959
|
+
* Navigation items displayed at the bottom of the sidebar.
|
|
2960
|
+
*/
|
|
2961
|
+
bottomItems: SidebarNavigationItem[];
|
|
2962
|
+
/**
|
|
2963
|
+
* Optional callback fired after a navigation item is pressed.
|
|
2964
|
+
*/
|
|
2965
|
+
onNavigate?: (route: string) => void;
|
|
2966
|
+
/**
|
|
2967
|
+
* The route to show when the navigator first renders.
|
|
2968
|
+
*/
|
|
2969
|
+
initialRouteName?: string;
|
|
2970
|
+
/**
|
|
2971
|
+
* Screen options passed through to the underlying Navigator.
|
|
2972
|
+
*/
|
|
2973
|
+
screenOptions?: Record<string, unknown>;
|
|
2974
|
+
/**
|
|
2975
|
+
* Additional styles applied to the sidebar panel container.
|
|
2976
|
+
*/
|
|
2977
|
+
panelStyle?: StyleProp<ViewStyle>;
|
|
2978
|
+
/**
|
|
2979
|
+
* Additional styles applied to each navigation item.
|
|
2980
|
+
*/
|
|
2981
|
+
itemStyle?: StyleProp<ViewStyle>;
|
|
2982
|
+
/**
|
|
2983
|
+
* Optional Screen definitions passed to the underlying Navigator,
|
|
2984
|
+
* e.g. <Screen name="index" options={{title: "Home"}} />.
|
|
2985
|
+
*/
|
|
2986
|
+
children?: React.ReactNode;
|
|
2987
|
+
}
|
|
2988
|
+
|
|
2989
|
+
/**
|
|
2990
|
+
* Props for the standalone SidebarNavigationPanel (no expo-router dependency).
|
|
2991
|
+
* Useful for demos, testing, or non-expo-router apps.
|
|
2992
|
+
*/
|
|
2993
|
+
export interface SidebarNavigationPanelProps {
|
|
2994
|
+
/**
|
|
2995
|
+
* Navigation items displayed at the top of the sidebar.
|
|
2996
|
+
*/
|
|
2997
|
+
topItems: SidebarNavigationItem[];
|
|
2998
|
+
/**
|
|
2999
|
+
* Navigation items displayed at the bottom of the sidebar.
|
|
3000
|
+
*/
|
|
3001
|
+
bottomItems: SidebarNavigationItem[];
|
|
3002
|
+
/**
|
|
3003
|
+
* The currently active route, used to highlight the matching item.
|
|
3004
|
+
*/
|
|
3005
|
+
activeRoute?: string;
|
|
3006
|
+
/**
|
|
3007
|
+
* Called when a navigation item is pressed.
|
|
3008
|
+
*/
|
|
3009
|
+
onNavigate: (route: string) => void;
|
|
3010
|
+
/**
|
|
3011
|
+
* Main content rendered beside (web) or behind (mobile) the sidebar.
|
|
3012
|
+
*/
|
|
3013
|
+
children: React.ReactNode;
|
|
3014
|
+
/**
|
|
3015
|
+
* Additional styles applied to the sidebar panel container.
|
|
3016
|
+
*/
|
|
3017
|
+
panelStyle?: StyleProp<ViewStyle>;
|
|
3018
|
+
/**
|
|
3019
|
+
* Additional styles applied to each navigation item.
|
|
3020
|
+
*/
|
|
3021
|
+
itemStyle?: StyleProp<ViewStyle>;
|
|
3022
|
+
}
|
|
@@ -17,6 +17,7 @@ interface ConsentFormScreenProps {
|
|
|
17
17
|
locale: string;
|
|
18
18
|
onAgree: (data: {checkboxValues: Record<string, boolean>; signature?: string}) => void;
|
|
19
19
|
onDecline?: () => void;
|
|
20
|
+
variables?: Record<string, string>;
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
export const ConsentFormScreen: React.FC<ConsentFormScreenProps> = ({
|
|
@@ -25,6 +26,7 @@ export const ConsentFormScreen: React.FC<ConsentFormScreenProps> = ({
|
|
|
25
26
|
locale,
|
|
26
27
|
onAgree,
|
|
27
28
|
onDecline,
|
|
29
|
+
variables,
|
|
28
30
|
}) => {
|
|
29
31
|
const [checkboxValues, setCheckboxValues] = useState<Record<string, boolean>>({});
|
|
30
32
|
const [hasScrolledToBottom, setHasScrolledToBottom] = useState(!form.requireScrollToBottom);
|
|
@@ -35,7 +37,10 @@ export const ConsentFormScreen: React.FC<ConsentFormScreenProps> = ({
|
|
|
35
37
|
const [contentHeight, setContentHeight] = useState(0);
|
|
36
38
|
const [layoutHeight, setLayoutHeight] = useState(0);
|
|
37
39
|
|
|
38
|
-
const
|
|
40
|
+
const rawContent = form.content[locale] ?? form.content[form.defaultLocale] ?? "";
|
|
41
|
+
const content = variables
|
|
42
|
+
? rawContent.replace(/\{\{(\w+)\}\}/g, (match, key) => variables[key] ?? match)
|
|
43
|
+
: rawContent;
|
|
39
44
|
|
|
40
45
|
const allRequiredCheckboxesChecked = form.checkboxes.every((checkbox, index) => {
|
|
41
46
|
if (!checkbox.required) {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import {describe, expect, it, mock} from "bun:test";
|
|
2
2
|
import React from "react";
|
|
3
|
+
import {Pressable} from "react-native";
|
|
4
|
+
import {Box} from "./Box";
|
|
3
5
|
import {ConsentNavigator} from "./ConsentNavigator";
|
|
4
6
|
import {Text} from "./Text";
|
|
5
7
|
import {renderWithTheme} from "./test-utils";
|
|
@@ -71,6 +73,15 @@ const createLoadingMockApi = () => {
|
|
|
71
73
|
};
|
|
72
74
|
};
|
|
73
75
|
|
|
76
|
+
const ExtraScreen: React.FC<{onNext?: () => void}> = ({onNext}) => (
|
|
77
|
+
<Box testID="extra-screen">
|
|
78
|
+
<Text>Extra Screen Content</Text>
|
|
79
|
+
<Pressable onPress={onNext} testID="extra-screen-next">
|
|
80
|
+
<Text>Next</Text>
|
|
81
|
+
</Pressable>
|
|
82
|
+
</Box>
|
|
83
|
+
);
|
|
84
|
+
|
|
74
85
|
describe("ConsentNavigator", () => {
|
|
75
86
|
it("renders children when there are no pending consent forms", async () => {
|
|
76
87
|
const api = createMockApi([]);
|
|
@@ -108,4 +119,49 @@ describe("ConsentNavigator", () => {
|
|
|
108
119
|
|
|
109
120
|
expect(getByTestId("consent-navigator-loading")).toBeTruthy();
|
|
110
121
|
});
|
|
122
|
+
|
|
123
|
+
it("shows extra screens after consent forms are completed", async () => {
|
|
124
|
+
const api = createMockApi([]);
|
|
125
|
+
|
|
126
|
+
const {getByTestId, queryByText} = renderWithTheme(
|
|
127
|
+
<ConsentNavigator api={api} extraScreens={[<ExtraScreen key="extra" />]}>
|
|
128
|
+
<Text>App Content</Text>
|
|
129
|
+
</ConsentNavigator>
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
expect(getByTestId("extra-screen")).toBeTruthy();
|
|
133
|
+
expect(queryByText("App Content")).toBeNull();
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it("shows children after all extra screens are dismissed", async () => {
|
|
137
|
+
const api = createMockApi([]);
|
|
138
|
+
const {act, fireEvent, waitFor} = await import("@testing-library/react-native");
|
|
139
|
+
|
|
140
|
+
const {getByTestId, getByText} = renderWithTheme(
|
|
141
|
+
<ConsentNavigator api={api} extraScreens={[<ExtraScreen key="extra" />]}>
|
|
142
|
+
<Text>App Content</Text>
|
|
143
|
+
</ConsentNavigator>
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
expect(getByTestId("extra-screen")).toBeTruthy();
|
|
147
|
+
await act(async () => {
|
|
148
|
+
fireEvent.press(getByTestId("extra-screen-next"));
|
|
149
|
+
});
|
|
150
|
+
await waitFor(() => {
|
|
151
|
+
expect(getByText("App Content")).toBeTruthy();
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it("injects onNext prop into extra screen elements", async () => {
|
|
156
|
+
const api = createMockApi([]);
|
|
157
|
+
|
|
158
|
+
const {getByTestId} = renderWithTheme(
|
|
159
|
+
<ConsentNavigator api={api} extraScreens={[<ExtraScreen key="extra" />]}>
|
|
160
|
+
<Text>App Content</Text>
|
|
161
|
+
</ConsentNavigator>
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
// The extra screen should have a working next button (onNext was injected)
|
|
165
|
+
expect(getByTestId("extra-screen-next")).toBeTruthy();
|
|
166
|
+
});
|
|
111
167
|
});
|
package/src/ConsentNavigator.tsx
CHANGED
|
@@ -13,19 +13,25 @@ interface ConsentNavigatorProps {
|
|
|
13
13
|
api: any;
|
|
14
14
|
baseUrl?: string;
|
|
15
15
|
children: React.ReactNode;
|
|
16
|
+
extraScreens?: React.ReactNode[];
|
|
16
17
|
onError?: (error: any) => void;
|
|
18
|
+
variables?: Record<string, string>;
|
|
17
19
|
}
|
|
18
20
|
|
|
19
21
|
export const ConsentNavigator: React.FC<ConsentNavigatorProps> = ({
|
|
20
22
|
api,
|
|
21
23
|
baseUrl,
|
|
22
24
|
children,
|
|
25
|
+
extraScreens,
|
|
23
26
|
onError,
|
|
27
|
+
variables,
|
|
24
28
|
}) => {
|
|
25
29
|
const [currentIndex, setCurrentIndex] = useState(0);
|
|
30
|
+
const [extraScreenIndex, setExtraScreenIndex] = useState(0);
|
|
26
31
|
const {forms, isLoading, error, refetch} = useConsentForms(api, baseUrl);
|
|
27
32
|
const {submit, isSubmitting} = useSubmitConsent(api, baseUrl);
|
|
28
33
|
const locale = detectLocale();
|
|
34
|
+
const validExtraScreens = extraScreens ?? [];
|
|
29
35
|
|
|
30
36
|
if (isLoading) {
|
|
31
37
|
console.debug("[ConsentNavigator] Loading pending consents...");
|
|
@@ -68,6 +74,18 @@ export const ConsentNavigator: React.FC<ConsentNavigatorProps> = ({
|
|
|
68
74
|
}
|
|
69
75
|
|
|
70
76
|
if (forms.length === 0 || currentIndex >= forms.length) {
|
|
77
|
+
if (extraScreenIndex < validExtraScreens.length) {
|
|
78
|
+
const currentScreen = validExtraScreens[extraScreenIndex];
|
|
79
|
+
console.debug(
|
|
80
|
+
`[ConsentNavigator] Showing extra screen ${extraScreenIndex + 1}/${validExtraScreens.length}`
|
|
81
|
+
);
|
|
82
|
+
if (React.isValidElement(currentScreen)) {
|
|
83
|
+
return React.cloneElement(currentScreen as React.ReactElement<any>, {
|
|
84
|
+
onNext: () => setExtraScreenIndex((i) => i + 1),
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
return <>{currentScreen}</>;
|
|
88
|
+
}
|
|
71
89
|
console.debug("[ConsentNavigator] No pending consents, showing app");
|
|
72
90
|
return <>{children}</>;
|
|
73
91
|
}
|
|
@@ -123,6 +141,7 @@ export const ConsentNavigator: React.FC<ConsentNavigatorProps> = ({
|
|
|
123
141
|
locale={locale}
|
|
124
142
|
onAgree={handleAgree}
|
|
125
143
|
onDecline={currentForm.required ? undefined : handleDecline}
|
|
144
|
+
variables={variables}
|
|
126
145
|
/>
|
|
127
146
|
);
|
|
128
147
|
};
|
package/src/DateTimeField.tsx
CHANGED
|
@@ -66,7 +66,7 @@ const DateTimeSegment: FC<DateTimeSegmentProps> = ({
|
|
|
66
66
|
borderColor: error ? theme.border.error : "transparent",
|
|
67
67
|
flexDirection: "row",
|
|
68
68
|
flexShrink: 1,
|
|
69
|
-
height:
|
|
69
|
+
height: 40,
|
|
70
70
|
overflow: "hidden",
|
|
71
71
|
padding: 0,
|
|
72
72
|
width: config.width,
|
|
@@ -999,9 +999,9 @@ export const DateTimeField: FC<DateTimeFieldProps> = ({
|
|
|
999
999
|
borderWidth: 1,
|
|
1000
1000
|
flexDirection: parentIsLessThanBreakpointOrIsMobile ? "column" : "row",
|
|
1001
1001
|
maxWidth: isMobileDatetime ? 250 : maximumWidth,
|
|
1002
|
+
minHeight: 40,
|
|
1002
1003
|
minWidth: isMobileDatetime ? 200 : minimumWidth,
|
|
1003
1004
|
paddingHorizontal: 6,
|
|
1004
|
-
paddingVertical: 2,
|
|
1005
1005
|
}}
|
|
1006
1006
|
>
|
|
1007
1007
|
{showDateSection && (
|