@jobber/components-native 0.95.4-improve-co-ca924fd.14 → 0.95.4
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/package.json +5 -3
- package/dist/src/ContentOverlay/ContentOverlay.js +107 -128
- package/dist/src/ContentOverlay/ContentOverlay.style.js +12 -8
- package/dist/src/ContentOverlay/UNSAFE_WrappedModalize.js +23 -0
- package/dist/src/ContentOverlay/index.js +0 -1
- package/dist/src/InputFieldWrapper/InputFieldWrapper.js +12 -2
- package/dist/src/InputText/InputText.js +2 -36
- package/dist/src/utils/meta/meta.json +0 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/types/src/ContentOverlay/ContentOverlay.d.ts +5 -1
- package/dist/types/src/ContentOverlay/ContentOverlay.style.d.ts +10 -11
- package/dist/types/src/ContentOverlay/UNSAFE_WrappedModalize.d.ts +3 -0
- package/dist/types/src/ContentOverlay/index.d.ts +0 -1
- package/dist/types/src/ContentOverlay/types.d.ts +12 -5
- package/dist/types/src/InputFieldWrapper/InputFieldWrapper.d.ts +5 -1
- package/jestSetup.js +0 -2
- package/package.json +5 -3
- package/src/ContentOverlay/ContentOverlay.style.ts +12 -12
- package/src/ContentOverlay/ContentOverlay.test.tsx +79 -157
- package/src/ContentOverlay/ContentOverlay.tsx +210 -223
- package/src/ContentOverlay/UNSAFE_WrappedModalize.tsx +41 -0
- package/src/ContentOverlay/index.ts +0 -1
- package/src/ContentOverlay/types.ts +13 -5
- package/src/InputFieldWrapper/InputFieldWrapper.test.tsx +47 -0
- package/src/InputFieldWrapper/InputFieldWrapper.tsx +19 -1
- package/src/InputText/InputText.test.tsx +0 -122
- package/src/InputText/InputText.tsx +3 -52
- package/src/ThumbnailList/__snapshots__/ThumbnailList.test.tsx.snap +20 -0
- package/src/utils/meta/meta.json +0 -1
- package/dist/src/ContentOverlay/ContentOverlayProvider.js +0 -5
- package/dist/src/ContentOverlay/computeContentOverlayBehavior.js +0 -76
- package/dist/src/ContentOverlay/hooks/useBottomSheetModalBackHandler.js +0 -25
- package/dist/types/src/ContentOverlay/ContentOverlayProvider.d.ts +0 -6
- package/dist/types/src/ContentOverlay/computeContentOverlayBehavior.d.ts +0 -32
- package/dist/types/src/ContentOverlay/hooks/useBottomSheetModalBackHandler.d.ts +0 -7
- package/src/ContentOverlay/ContentOverlay.stories.tsx +0 -59
- package/src/ContentOverlay/ContentOverlayProvider.tsx +0 -12
- package/src/ContentOverlay/computeContentOverlayBehavior.test.ts +0 -276
- package/src/ContentOverlay/computeContentOverlayBehavior.ts +0 -119
- package/src/ContentOverlay/hooks/useBottomSheetModalBackHandler.test.ts +0 -81
- package/src/ContentOverlay/hooks/useBottomSheetModalBackHandler.ts +0 -36
|
@@ -1,204 +1,228 @@
|
|
|
1
|
-
import
|
|
1
|
+
import type { Ref } from "react";
|
|
2
|
+
import React, {
|
|
3
|
+
forwardRef,
|
|
4
|
+
useCallback,
|
|
5
|
+
useImperativeHandle,
|
|
6
|
+
useMemo,
|
|
7
|
+
useRef,
|
|
8
|
+
useState,
|
|
9
|
+
} from "react";
|
|
10
|
+
import type { Modalize } from "react-native-modalize";
|
|
11
|
+
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
12
|
+
import type { NativeScrollEvent, NativeSyntheticEvent } from "react-native";
|
|
2
13
|
import {
|
|
3
14
|
AccessibilityInfo,
|
|
15
|
+
Platform,
|
|
4
16
|
View,
|
|
5
17
|
findNodeHandle,
|
|
6
18
|
useWindowDimensions,
|
|
7
19
|
} from "react-native";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
BottomSheetBackdrop,
|
|
11
|
-
BottomSheetModal,
|
|
12
|
-
BottomSheetScrollView,
|
|
13
|
-
BottomSheetView,
|
|
14
|
-
} from "@gorhom/bottom-sheet";
|
|
15
|
-
import type {
|
|
16
|
-
BottomSheetBackdropProps,
|
|
17
|
-
BottomSheetModal as BottomSheetModalType,
|
|
18
|
-
BottomSheetScrollViewMethods,
|
|
19
|
-
} from "@gorhom/bottom-sheet";
|
|
20
|
-
import type { ContentOverlayProps, ModalBackgroundColor } from "./types";
|
|
20
|
+
import { Portal } from "react-native-portalize";
|
|
21
|
+
import { useKeyboardVisibility } from "./hooks/useKeyboardVisibility";
|
|
21
22
|
import { useStyles } from "./ContentOverlay.style";
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
23
|
+
import { useViewLayoutHeight } from "./hooks/useViewLayoutHeight";
|
|
24
|
+
import type {
|
|
25
|
+
ContentOverlayProps,
|
|
26
|
+
ContentOverlayRef,
|
|
27
|
+
ModalBackgroundColor,
|
|
28
|
+
} from "./types";
|
|
29
|
+
import { UNSAFE_WrappedModalize } from "./UNSAFE_WrappedModalize";
|
|
24
30
|
import { useIsScreenReaderEnabled } from "../hooks";
|
|
25
31
|
import { IconButton } from "../IconButton";
|
|
26
32
|
import { Heading } from "../Heading";
|
|
27
33
|
import { useAtlantisI18n } from "../hooks/useAtlantisI18n";
|
|
28
34
|
import { useAtlantisTheme } from "../AtlantisThemeContext";
|
|
29
35
|
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
function getModalBackgroundColor(
|
|
33
|
-
variation: ModalBackgroundColor,
|
|
34
|
-
tokens: ReturnType<typeof useAtlantisTheme>["tokens"],
|
|
35
|
-
) {
|
|
36
|
-
switch (variation) {
|
|
37
|
-
case "surface":
|
|
38
|
-
return tokens["color-surface"];
|
|
39
|
-
case "background":
|
|
40
|
-
return tokens["color-surface--background"];
|
|
41
|
-
}
|
|
42
|
-
}
|
|
36
|
+
export const ContentOverlay = forwardRef(ContentOverlayPortal);
|
|
37
|
+
const ContentOverlayModal = forwardRef(ContentOverlayInternal);
|
|
43
38
|
|
|
44
39
|
// eslint-disable-next-line max-statements
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const styles = useStyles();
|
|
40
|
+
function ContentOverlayInternal(
|
|
41
|
+
{
|
|
42
|
+
children,
|
|
43
|
+
title,
|
|
44
|
+
accessibilityLabel,
|
|
45
|
+
fullScreen = false,
|
|
46
|
+
showDismiss = false,
|
|
47
|
+
isDraggable = true,
|
|
48
|
+
adjustToContentHeight = false,
|
|
49
|
+
keyboardShouldPersistTaps = false,
|
|
50
|
+
keyboardAvoidingBehavior,
|
|
51
|
+
scrollEnabled = false,
|
|
52
|
+
modalBackgroundColor = "surface",
|
|
53
|
+
onClose,
|
|
54
|
+
onOpen,
|
|
55
|
+
onBeforeExit,
|
|
56
|
+
loading = false,
|
|
57
|
+
avoidKeyboardLikeIOS,
|
|
58
|
+
}: ContentOverlayProps,
|
|
59
|
+
ref: Ref<ContentOverlayRef>,
|
|
60
|
+
) {
|
|
61
|
+
isDraggable = onBeforeExit ? false : isDraggable;
|
|
62
|
+
const isCloseableOnOverlayTap = onBeforeExit ? false : true;
|
|
69
63
|
const { t } = useAtlantisI18n();
|
|
70
64
|
const { tokens } = useAtlantisTheme();
|
|
65
|
+
const { width: windowWidth, height: windowHeight } = useWindowDimensions();
|
|
66
|
+
const insets = useSafeAreaInsets();
|
|
67
|
+
const [position, setPosition] = useState<"top" | "initial">("initial");
|
|
71
68
|
const isScreenReaderEnabled = useIsScreenReaderEnabled();
|
|
69
|
+
const isFullScreenOrTopPosition =
|
|
70
|
+
fullScreen || (!adjustToContentHeight && position === "top");
|
|
71
|
+
const shouldShowDismiss =
|
|
72
|
+
showDismiss || isScreenReaderEnabled || isFullScreenOrTopPosition;
|
|
73
|
+
const [showHeaderShadow, setShowHeaderShadow] = useState<boolean>(false);
|
|
74
|
+
const overlayHeader = useRef<View>(null);
|
|
72
75
|
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
{
|
|
82
|
-
isScreenReaderEnabled,
|
|
83
|
-
position: currentPosition,
|
|
84
|
-
},
|
|
85
|
-
);
|
|
76
|
+
const internalRef = useRef<Modalize>(null);
|
|
77
|
+
const [modalizeMethods, setModalizeMethods] = useState<ContentOverlayRef>();
|
|
78
|
+
const callbackInternalRef = useCallback((instance: Modalize) => {
|
|
79
|
+
if (instance && !internalRef.current) {
|
|
80
|
+
internalRef.current = instance;
|
|
81
|
+
setModalizeMethods(instance);
|
|
82
|
+
}
|
|
83
|
+
}, []);
|
|
86
84
|
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
85
|
+
const refMethods = useMemo(() => {
|
|
86
|
+
if (!modalizeMethods?.open || !modalizeMethods?.close) {
|
|
87
|
+
return {};
|
|
88
|
+
}
|
|
90
89
|
|
|
91
|
-
|
|
92
|
-
|
|
90
|
+
return {
|
|
91
|
+
open: modalizeMethods?.open,
|
|
92
|
+
close: modalizeMethods?.close,
|
|
93
|
+
};
|
|
94
|
+
}, [modalizeMethods]);
|
|
93
95
|
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
const scrollViewRef = useRef<
|
|
97
|
-
BottomSheetScrollViewMethods & { scrollTop?: number }
|
|
98
|
-
>(null);
|
|
96
|
+
const { keyboardHeight } = useKeyboardVisibility();
|
|
97
|
+
useImperativeHandle(ref, () => refMethods, [refMethods]);
|
|
99
98
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
99
|
+
const {
|
|
100
|
+
handleLayout: handleChildrenLayout,
|
|
101
|
+
height: childrenHeight,
|
|
102
|
+
heightKnown: childrenHeightKnown,
|
|
103
|
+
} = useViewLayoutHeight();
|
|
104
|
+
const {
|
|
105
|
+
handleLayout: handleHeaderLayout,
|
|
106
|
+
height: headerHeight,
|
|
107
|
+
heightKnown: headerHeightKnown,
|
|
108
|
+
} = useViewLayoutHeight();
|
|
108
109
|
|
|
109
|
-
const
|
|
110
|
-
if (!
|
|
111
|
-
|
|
112
|
-
} else {
|
|
113
|
-
onBeforeExit();
|
|
110
|
+
const snapPoint = useMemo(() => {
|
|
111
|
+
if (fullScreen || !isDraggable || adjustToContentHeight) {
|
|
112
|
+
return undefined;
|
|
114
113
|
}
|
|
115
|
-
|
|
114
|
+
const overlayHeight = headerHeight + childrenHeight;
|
|
116
115
|
|
|
117
|
-
|
|
118
|
-
|
|
116
|
+
if (overlayHeight >= windowHeight) {
|
|
117
|
+
return undefined;
|
|
118
|
+
}
|
|
119
119
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
120
|
+
return overlayHeight;
|
|
121
|
+
}, [
|
|
122
|
+
fullScreen,
|
|
123
|
+
isDraggable,
|
|
124
|
+
adjustToContentHeight,
|
|
125
|
+
headerHeight,
|
|
126
|
+
childrenHeight,
|
|
127
|
+
windowHeight,
|
|
128
|
+
]);
|
|
128
129
|
|
|
129
|
-
const
|
|
130
|
-
const previousIndex = previousIndexRef.current;
|
|
130
|
+
const styles = useStyles();
|
|
131
131
|
|
|
132
|
-
|
|
133
|
-
|
|
132
|
+
const modalStyle = [
|
|
133
|
+
styles.modal,
|
|
134
|
+
windowWidth > 640 ? styles.modalForLargeScreens : undefined,
|
|
135
|
+
{ backgroundColor: getModalBackgroundColor(modalBackgroundColor) },
|
|
136
|
+
keyboardHeight > 0 && { marginBottom: 0 },
|
|
137
|
+
];
|
|
134
138
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
onOpen?.();
|
|
139
|
+
const renderedChildren = renderChildren();
|
|
140
|
+
const renderedHeader = renderHeader();
|
|
138
141
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
+
const onCloseController = () => {
|
|
143
|
+
if (!onBeforeExit) {
|
|
144
|
+
internalRef.current?.close();
|
|
142
145
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}
|
|
147
|
-
}
|
|
146
|
+
return true;
|
|
147
|
+
} else {
|
|
148
|
+
onBeforeExit();
|
|
148
149
|
|
|
149
|
-
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
150
152
|
};
|
|
151
153
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
154
|
+
return (
|
|
155
|
+
<>
|
|
156
|
+
{headerHeightKnown && childrenHeightKnown && (
|
|
157
|
+
<UNSAFE_WrappedModalize
|
|
158
|
+
ref={callbackInternalRef}
|
|
159
|
+
overlayStyle={styles.overlay}
|
|
160
|
+
handleStyle={styles.handle}
|
|
161
|
+
handlePosition="inside"
|
|
162
|
+
modalStyle={modalStyle}
|
|
163
|
+
modalTopOffset={tokens["space-larger"]}
|
|
164
|
+
snapPoint={snapPoint}
|
|
165
|
+
closeSnapPointStraightEnabled={false}
|
|
166
|
+
withHandle={isDraggable}
|
|
167
|
+
panGestureEnabled={isDraggable}
|
|
168
|
+
adjustToContentHeight={adjustToContentHeight}
|
|
169
|
+
disableScrollIfPossible={!adjustToContentHeight} // workaround for scroll not working on Android when content fills the screen with adjustToContentHeight
|
|
170
|
+
onClose={onClose}
|
|
171
|
+
onOpen={onOpen}
|
|
172
|
+
keyboardAvoidingBehavior={keyboardAvoidingBehavior}
|
|
173
|
+
avoidKeyboardLikeIOS={avoidKeyboardLikeIOS}
|
|
174
|
+
childrenStyle={styles.childrenStyle}
|
|
175
|
+
onBackButtonPress={onCloseController}
|
|
176
|
+
closeOnOverlayTap={isCloseableOnOverlayTap}
|
|
177
|
+
onOpened={() => {
|
|
178
|
+
if (overlayHeader.current) {
|
|
179
|
+
const reactTag = findNodeHandle(overlayHeader.current);
|
|
156
180
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
181
|
+
if (reactTag) {
|
|
182
|
+
AccessibilityInfo.setAccessibilityFocus(reactTag);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}}
|
|
186
|
+
scrollViewProps={{
|
|
187
|
+
scrollEnabled,
|
|
188
|
+
showsVerticalScrollIndicator: false,
|
|
189
|
+
stickyHeaderIndices: Platform.OS === "android" ? [0] : undefined,
|
|
190
|
+
onScroll: handleOnScroll,
|
|
191
|
+
keyboardShouldPersistTaps: keyboardShouldPersistTaps
|
|
192
|
+
? "handled"
|
|
193
|
+
: "never",
|
|
194
|
+
}}
|
|
195
|
+
HeaderComponent={Platform.OS === "ios" ? renderedHeader : undefined}
|
|
196
|
+
onPositionChange={setPosition}
|
|
197
|
+
>
|
|
198
|
+
{Platform.OS === "android" ? renderedHeader : undefined}
|
|
199
|
+
{renderedChildren}
|
|
200
|
+
</UNSAFE_WrappedModalize>
|
|
201
|
+
)}
|
|
202
|
+
{!childrenHeightKnown && (
|
|
203
|
+
<View style={[styles.hiddenContent, modalStyle]}>
|
|
204
|
+
{renderedChildren}
|
|
205
|
+
</View>
|
|
206
|
+
)}
|
|
207
|
+
{!headerHeightKnown && (
|
|
208
|
+
<View style={[styles.hiddenContent, modalStyle]}>{renderedHeader}</View>
|
|
209
|
+
)}
|
|
210
|
+
</>
|
|
166
211
|
);
|
|
167
212
|
|
|
168
|
-
|
|
169
|
-
styles.background,
|
|
170
|
-
{ backgroundColor: getModalBackgroundColor(modalBackgroundColor, tokens) },
|
|
171
|
-
];
|
|
172
|
-
|
|
173
|
-
const handleIndicatorStyles = [
|
|
174
|
-
styles.handle,
|
|
175
|
-
!effectiveIsDraggable && {
|
|
176
|
-
opacity: 0,
|
|
177
|
-
},
|
|
178
|
-
];
|
|
179
|
-
|
|
180
|
-
const renderHeader = () => {
|
|
213
|
+
function renderHeader() {
|
|
181
214
|
const closeOverlayA11YLabel = t("ContentOverlay.close", {
|
|
182
215
|
title: title,
|
|
183
216
|
});
|
|
184
217
|
|
|
185
218
|
const headerStyles = [
|
|
186
219
|
styles.header,
|
|
187
|
-
{
|
|
188
|
-
// Background color is necessary for scrollable modals as the content flows behind the header.
|
|
189
|
-
backgroundColor: getModalBackgroundColor(modalBackgroundColor, tokens),
|
|
190
|
-
},
|
|
191
|
-
];
|
|
192
|
-
|
|
193
|
-
const headerShadowStyles = [
|
|
194
220
|
showHeaderShadow && styles.headerShadow,
|
|
195
|
-
{
|
|
196
|
-
backgroundColor: getModalBackgroundColor(modalBackgroundColor, tokens),
|
|
197
|
-
},
|
|
221
|
+
{ backgroundColor: getModalBackgroundColor(modalBackgroundColor) },
|
|
198
222
|
];
|
|
199
223
|
|
|
200
224
|
return (
|
|
201
|
-
<View testID="ATL-Overlay-Header">
|
|
225
|
+
<View onLayout={handleHeaderLayout} testID="ATL-Overlay-Header">
|
|
202
226
|
<View style={headerStyles}>
|
|
203
227
|
<View
|
|
204
228
|
style={[
|
|
@@ -236,82 +260,45 @@ export function ContentOverlay({
|
|
|
236
260
|
</View>
|
|
237
261
|
)}
|
|
238
262
|
</View>
|
|
239
|
-
<View>
|
|
240
|
-
<View style={headerShadowStyles} />
|
|
241
|
-
</View>
|
|
242
263
|
</View>
|
|
243
264
|
);
|
|
244
|
-
}
|
|
265
|
+
}
|
|
245
266
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
ref={scrollViewRef}
|
|
273
|
-
contentContainerStyle={{ paddingBottom: insets.bottom }}
|
|
274
|
-
keyboardShouldPersistTaps={
|
|
275
|
-
keyboardShouldPersistTaps ? "handled" : "never"
|
|
276
|
-
}
|
|
277
|
-
showsVerticalScrollIndicator={false}
|
|
278
|
-
onScroll={handleOnScroll}
|
|
279
|
-
stickyHeaderIndices={[0]}
|
|
280
|
-
>
|
|
281
|
-
{renderHeader()}
|
|
282
|
-
<View testID="ATL-Overlay-Children">{children}</View>
|
|
283
|
-
</BottomSheetScrollView>
|
|
284
|
-
) : (
|
|
285
|
-
<BottomSheetView>
|
|
286
|
-
{renderHeader()}
|
|
287
|
-
<View
|
|
288
|
-
style={{ paddingBottom: insets.bottom }}
|
|
289
|
-
testID="ATL-Overlay-Children"
|
|
290
|
-
>
|
|
291
|
-
{children}
|
|
292
|
-
</View>
|
|
293
|
-
</BottomSheetView>
|
|
294
|
-
)}
|
|
295
|
-
</BottomSheetModal>
|
|
296
|
-
);
|
|
267
|
+
function renderChildren() {
|
|
268
|
+
return (
|
|
269
|
+
<View
|
|
270
|
+
style={{ paddingBottom: insets.bottom }}
|
|
271
|
+
onLayout={handleChildrenLayout}
|
|
272
|
+
testID="ATL-Overlay-Children"
|
|
273
|
+
>
|
|
274
|
+
{children}
|
|
275
|
+
</View>
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function handleOnScroll({
|
|
280
|
+
nativeEvent,
|
|
281
|
+
}: NativeSyntheticEvent<NativeScrollEvent>) {
|
|
282
|
+
setShowHeaderShadow(nativeEvent.contentOffset.y > 0);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function getModalBackgroundColor(variation: ModalBackgroundColor) {
|
|
286
|
+
switch (variation) {
|
|
287
|
+
case "surface":
|
|
288
|
+
return tokens["color-surface"];
|
|
289
|
+
case "background":
|
|
290
|
+
return tokens["color-surface--background"];
|
|
291
|
+
}
|
|
292
|
+
}
|
|
297
293
|
}
|
|
298
294
|
|
|
299
|
-
function
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
},
|
|
295
|
+
function ContentOverlayPortal(
|
|
296
|
+
modalProps: ContentOverlayProps,
|
|
297
|
+
ref: Ref<ContentOverlayRef>,
|
|
303
298
|
) {
|
|
304
|
-
const styles = useStyles();
|
|
305
|
-
const { pressBehavior, ...props } = bottomSheetBackdropProps;
|
|
306
|
-
|
|
307
299
|
return (
|
|
308
|
-
<
|
|
309
|
-
{...
|
|
310
|
-
|
|
311
|
-
disappearsOnIndex={-1}
|
|
312
|
-
style={styles.backdrop}
|
|
313
|
-
opacity={1}
|
|
314
|
-
pressBehavior={pressBehavior}
|
|
315
|
-
/>
|
|
300
|
+
<Portal>
|
|
301
|
+
<ContentOverlayModal ref={ref} {...modalProps} />
|
|
302
|
+
</Portal>
|
|
316
303
|
);
|
|
317
304
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import React, {
|
|
2
|
+
forwardRef,
|
|
3
|
+
useImperativeHandle,
|
|
4
|
+
useRef,
|
|
5
|
+
useState,
|
|
6
|
+
} from "react";
|
|
7
|
+
import { Modalize } from "react-native-modalize";
|
|
8
|
+
import type { IHandles } from "react-native-modalize/lib/options";
|
|
9
|
+
|
|
10
|
+
type Props = React.ComponentProps<typeof Modalize>;
|
|
11
|
+
|
|
12
|
+
export const UNSAFE_WrappedModalize = forwardRef<IHandles | undefined, Props>(
|
|
13
|
+
(props, ref) => {
|
|
14
|
+
const innerRef = useRef<IHandles | null>(null);
|
|
15
|
+
const [openRenderId, setOpenRenderId] = useState(0);
|
|
16
|
+
|
|
17
|
+
useImperativeHandle(
|
|
18
|
+
ref,
|
|
19
|
+
() => ({
|
|
20
|
+
open(dest) {
|
|
21
|
+
setOpenRenderId(id => id + 1);
|
|
22
|
+
// Open on a fresh tick for additional safety
|
|
23
|
+
requestAnimationFrame(() => {
|
|
24
|
+
innerRef.current?.open(dest);
|
|
25
|
+
});
|
|
26
|
+
},
|
|
27
|
+
close(dest) {
|
|
28
|
+
innerRef.current?.close(dest);
|
|
29
|
+
},
|
|
30
|
+
}),
|
|
31
|
+
[],
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
// Use a unique key to force a remount, ensuring we get fresh gesture handler nodes within modalize
|
|
35
|
+
return (
|
|
36
|
+
<Modalize key={`modalize-${openRenderId}`} ref={innerRef} {...props} />
|
|
37
|
+
);
|
|
38
|
+
},
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
UNSAFE_WrappedModalize.displayName = "UNSAFE_WrappedModalize";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { ReactNode
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import type { Modalize } from "react-native-modalize";
|
|
2
3
|
|
|
3
4
|
export interface ContentOverlayProps {
|
|
4
5
|
/**
|
|
@@ -66,6 +67,12 @@ export interface ContentOverlayProps {
|
|
|
66
67
|
*/
|
|
67
68
|
readonly onBeforeExit?: () => void;
|
|
68
69
|
|
|
70
|
+
/**
|
|
71
|
+
* Define the behavior of the keyboard when having inputs inside the modal.
|
|
72
|
+
* @default padding
|
|
73
|
+
*/
|
|
74
|
+
readonly keyboardAvoidingBehavior?: "height" | "padding" | "position";
|
|
75
|
+
|
|
69
76
|
/**
|
|
70
77
|
* Boolean to show a disabled state
|
|
71
78
|
* @default false
|
|
@@ -73,16 +80,17 @@ export interface ContentOverlayProps {
|
|
|
73
80
|
readonly loading?: boolean;
|
|
74
81
|
|
|
75
82
|
/**
|
|
76
|
-
*
|
|
83
|
+
* Define keyboard's Android behavior like iOS's one.
|
|
84
|
+
* @default Platform.select({ ios: true, android: false })
|
|
77
85
|
*/
|
|
78
|
-
readonly
|
|
86
|
+
readonly avoidKeyboardLikeIOS?: boolean;
|
|
79
87
|
}
|
|
80
88
|
|
|
81
89
|
export type ModalBackgroundColor = "surface" | "background";
|
|
82
90
|
|
|
83
91
|
export type ContentOverlayRef =
|
|
84
92
|
| {
|
|
85
|
-
open?:
|
|
86
|
-
close?:
|
|
93
|
+
open?: Modalize["open"];
|
|
94
|
+
close?: Modalize["close"];
|
|
87
95
|
}
|
|
88
96
|
| undefined;
|
|
@@ -358,4 +358,51 @@ describe("InputFieldWrapper", () => {
|
|
|
358
358
|
).toBeNull();
|
|
359
359
|
});
|
|
360
360
|
});
|
|
361
|
+
|
|
362
|
+
describe("multiline", () => {
|
|
363
|
+
it("applies maxWidth of 90% when multiline is true", () => {
|
|
364
|
+
const { getByTestId } = renderInputFieldWrapper({ multiline: true });
|
|
365
|
+
const container = getByTestId("ATL-InputFieldWrapper");
|
|
366
|
+
|
|
367
|
+
const flattenedStyle = container.props.style.reduce(
|
|
368
|
+
(style: ViewStyle, additionalStyles: ViewStyle) => ({
|
|
369
|
+
...style,
|
|
370
|
+
...additionalStyles,
|
|
371
|
+
}),
|
|
372
|
+
{},
|
|
373
|
+
);
|
|
374
|
+
|
|
375
|
+
expect(flattenedStyle.maxWidth).toEqual("90%");
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
it("does not apply maxWidth when multiline is false", () => {
|
|
379
|
+
const { getByTestId } = renderInputFieldWrapper({ multiline: false });
|
|
380
|
+
const container = getByTestId("ATL-InputFieldWrapper");
|
|
381
|
+
|
|
382
|
+
const flattenedStyle = container.props.style.reduce(
|
|
383
|
+
(style: ViewStyle, additionalStyles: ViewStyle) => ({
|
|
384
|
+
...style,
|
|
385
|
+
...additionalStyles,
|
|
386
|
+
}),
|
|
387
|
+
{},
|
|
388
|
+
);
|
|
389
|
+
|
|
390
|
+
expect(flattenedStyle.maxWidth).toBeUndefined();
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
it("does not apply maxWidth when multiline is not provided", () => {
|
|
394
|
+
const { getByTestId } = renderInputFieldWrapper({});
|
|
395
|
+
const container = getByTestId("ATL-InputFieldWrapper");
|
|
396
|
+
|
|
397
|
+
const flattenedStyle = container.props.style.reduce(
|
|
398
|
+
(style: ViewStyle, additionalStyles: ViewStyle) => ({
|
|
399
|
+
...style,
|
|
400
|
+
...additionalStyles,
|
|
401
|
+
}),
|
|
402
|
+
{},
|
|
403
|
+
);
|
|
404
|
+
|
|
405
|
+
expect(flattenedStyle.maxWidth).toBeUndefined();
|
|
406
|
+
});
|
|
407
|
+
});
|
|
361
408
|
});
|