@jobber/components-native 0.95.3 → 0.95.4-improve-co-ca924fd.14
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 +3 -5
- package/dist/src/ContentOverlay/ContentOverlay.js +128 -107
- package/dist/src/ContentOverlay/ContentOverlay.style.js +8 -12
- package/dist/src/ContentOverlay/ContentOverlayProvider.js +5 -0
- package/dist/src/ContentOverlay/computeContentOverlayBehavior.js +76 -0
- package/dist/src/ContentOverlay/hooks/useBottomSheetModalBackHandler.js +25 -0
- package/dist/src/ContentOverlay/index.js +1 -0
- package/dist/src/InputText/InputText.js +35 -1
- package/dist/src/utils/meta/meta.json +1 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/types/src/ContentOverlay/ContentOverlay.d.ts +1 -5
- package/dist/types/src/ContentOverlay/ContentOverlay.style.d.ts +11 -10
- package/dist/types/src/ContentOverlay/ContentOverlayProvider.d.ts +6 -0
- package/dist/types/src/ContentOverlay/computeContentOverlayBehavior.d.ts +32 -0
- package/dist/types/src/ContentOverlay/hooks/useBottomSheetModalBackHandler.d.ts +7 -0
- package/dist/types/src/ContentOverlay/index.d.ts +1 -0
- package/dist/types/src/ContentOverlay/types.d.ts +5 -12
- package/jestSetup.js +2 -0
- package/package.json +3 -5
- package/src/ContentOverlay/ContentOverlay.stories.tsx +59 -0
- package/src/ContentOverlay/ContentOverlay.style.ts +12 -12
- package/src/ContentOverlay/ContentOverlay.test.tsx +157 -79
- package/src/ContentOverlay/ContentOverlay.tsx +223 -210
- package/src/ContentOverlay/ContentOverlayProvider.tsx +12 -0
- package/src/ContentOverlay/computeContentOverlayBehavior.test.ts +276 -0
- package/src/ContentOverlay/computeContentOverlayBehavior.ts +119 -0
- package/src/ContentOverlay/hooks/useBottomSheetModalBackHandler.test.ts +81 -0
- package/src/ContentOverlay/hooks/useBottomSheetModalBackHandler.ts +36 -0
- package/src/ContentOverlay/index.ts +1 -0
- package/src/ContentOverlay/types.ts +5 -13
- package/src/InputText/InputText.test.tsx +122 -0
- package/src/InputText/InputText.tsx +52 -2
- package/src/ThumbnailList/__snapshots__/ThumbnailList.test.tsx.snap +0 -20
- package/src/utils/meta/meta.json +1 -0
- package/dist/src/ContentOverlay/UNSAFE_WrappedModalize.js +0 -23
- package/dist/types/src/ContentOverlay/UNSAFE_WrappedModalize.d.ts +0 -3
- package/src/ContentOverlay/UNSAFE_WrappedModalize.tsx +0 -41
|
@@ -14,7 +14,8 @@ import type {
|
|
|
14
14
|
TextInputProps,
|
|
15
15
|
TextStyle,
|
|
16
16
|
} from "react-native";
|
|
17
|
-
import { Platform, TextInput } from "react-native";
|
|
17
|
+
import { Platform, TextInput, findNodeHandle } from "react-native";
|
|
18
|
+
import { useBottomSheetInternal } from "@gorhom/bottom-sheet";
|
|
18
19
|
import type { RegisterOptions } from "react-hook-form";
|
|
19
20
|
import type { IconNames } from "@jobber/design";
|
|
20
21
|
import identity from "lodash/identity";
|
|
@@ -315,6 +316,11 @@ function InputTextInternal(
|
|
|
315
316
|
disabled,
|
|
316
317
|
});
|
|
317
318
|
|
|
319
|
+
// Bottom sheet keyboard handling - detect if we're inside a ContentOverlay
|
|
320
|
+
const bottomSheetContext = useBottomSheetInternal(true);
|
|
321
|
+
const animatedKeyboardState = bottomSheetContext?.animatedKeyboardState;
|
|
322
|
+
const textInputNodesRef = bottomSheetContext?.textInputNodesRef;
|
|
323
|
+
|
|
318
324
|
// Android doesn't have an accessibility label like iOS does. By adding
|
|
319
325
|
// it as a placeholder it readds it like a label. However we don't want to
|
|
320
326
|
// add a placeholder on iOS.
|
|
@@ -438,11 +444,13 @@ function InputTextInternal(
|
|
|
438
444
|
secureTextEntry={secureTextEntry}
|
|
439
445
|
{...androidA11yProps}
|
|
440
446
|
onFocus={event => {
|
|
447
|
+
handleBottomSheetFocus(event);
|
|
441
448
|
_name && setFocusedInput(_name);
|
|
442
449
|
setFocused(true);
|
|
443
450
|
onFocus?.(event);
|
|
444
451
|
}}
|
|
445
452
|
onBlur={event => {
|
|
453
|
+
handleBottomSheetBlur(event);
|
|
446
454
|
_name && setFocusedInput("");
|
|
447
455
|
setFocused(false);
|
|
448
456
|
onBlur?.(event);
|
|
@@ -469,6 +477,48 @@ function InputTextInternal(
|
|
|
469
477
|
updateFormAndState(removedIOSCharValue);
|
|
470
478
|
}
|
|
471
479
|
|
|
480
|
+
function handleBottomSheetFocus(event?: FocusEvent) {
|
|
481
|
+
if (!animatedKeyboardState || !textInputNodesRef || !event?.nativeEvent) {
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
animatedKeyboardState.set(state => ({
|
|
486
|
+
...state,
|
|
487
|
+
target: event.nativeEvent.target,
|
|
488
|
+
}));
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
function handleBottomSheetBlur(event?: FocusEvent) {
|
|
492
|
+
if (!animatedKeyboardState || !textInputNodesRef || !event?.nativeEvent) {
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
const keyboardState = animatedKeyboardState.get();
|
|
496
|
+
const currentlyFocusedInput = TextInput.State.currentlyFocusedInput();
|
|
497
|
+
const currentFocusedInput =
|
|
498
|
+
currentlyFocusedInput !== null
|
|
499
|
+
? findNodeHandle(
|
|
500
|
+
// @ts-expect-error - TextInput.State.currentlyFocusedInput() returns NativeMethods
|
|
501
|
+
// which is not directly assignable to findNodeHandle's expected type,
|
|
502
|
+
// but it works at runtime. This is a known type limitation in React Native.
|
|
503
|
+
currentlyFocusedInput,
|
|
504
|
+
)
|
|
505
|
+
: null;
|
|
506
|
+
|
|
507
|
+
// Only remove the target if it belongs to the current component
|
|
508
|
+
// and if the currently focused input is not in the targets set
|
|
509
|
+
const shouldRemoveCurrentTarget =
|
|
510
|
+
keyboardState.target === event.nativeEvent.target;
|
|
511
|
+
const shouldIgnoreBlurEvent =
|
|
512
|
+
currentFocusedInput && textInputNodesRef.current.has(currentFocusedInput);
|
|
513
|
+
|
|
514
|
+
if (shouldRemoveCurrentTarget && !shouldIgnoreBlurEvent) {
|
|
515
|
+
animatedKeyboardState.set(state => ({
|
|
516
|
+
...state,
|
|
517
|
+
target: undefined,
|
|
518
|
+
}));
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
472
522
|
function handleClear() {
|
|
473
523
|
handleChangeText("");
|
|
474
524
|
}
|
|
@@ -515,7 +565,7 @@ interface UseTextInputRefProps {
|
|
|
515
565
|
}
|
|
516
566
|
|
|
517
567
|
function useTextInputRef({ ref, onClear }: UseTextInputRefProps) {
|
|
518
|
-
const textInputRef = useRef<
|
|
568
|
+
const textInputRef = useRef<TextInput | null>(null);
|
|
519
569
|
|
|
520
570
|
useImperativeHandle(
|
|
521
571
|
ref,
|
|
@@ -152,20 +152,6 @@ exports[`renders a thumbnail component with attachments 1`] = `
|
|
|
152
152
|
}
|
|
153
153
|
>
|
|
154
154
|
<View
|
|
155
|
-
backdropComponent={[Function]}
|
|
156
|
-
backgroundStyle={
|
|
157
|
-
{
|
|
158
|
-
"borderTopLeftRadius": 24,
|
|
159
|
-
"borderTopRightRadius": 24,
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
enablePanDownToClose={true}
|
|
163
|
-
handleStyle={
|
|
164
|
-
{
|
|
165
|
-
"display": "none",
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
keyboardBlurBehavior="restore"
|
|
169
155
|
style={
|
|
170
156
|
{
|
|
171
157
|
"display": "none",
|
|
@@ -174,12 +160,6 @@ exports[`renders a thumbnail component with attachments 1`] = `
|
|
|
174
160
|
testID="bottom-sheet-mock"
|
|
175
161
|
>
|
|
176
162
|
<View
|
|
177
|
-
style={
|
|
178
|
-
{
|
|
179
|
-
"paddingBottom": 8,
|
|
180
|
-
"paddingTop": 8,
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
163
|
testID="bottom-sheet-view"
|
|
184
164
|
>
|
|
185
165
|
<View
|
package/src/utils/meta/meta.json
CHANGED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import React, { forwardRef, useImperativeHandle, useRef, useState, } from "react";
|
|
2
|
-
import { Modalize } from "react-native-modalize";
|
|
3
|
-
export const UNSAFE_WrappedModalize = forwardRef((props, ref) => {
|
|
4
|
-
const innerRef = useRef(null);
|
|
5
|
-
const [openRenderId, setOpenRenderId] = useState(0);
|
|
6
|
-
useImperativeHandle(ref, () => ({
|
|
7
|
-
open(dest) {
|
|
8
|
-
setOpenRenderId(id => id + 1);
|
|
9
|
-
// Open on a fresh tick for additional safety
|
|
10
|
-
requestAnimationFrame(() => {
|
|
11
|
-
var _a;
|
|
12
|
-
(_a = innerRef.current) === null || _a === void 0 ? void 0 : _a.open(dest);
|
|
13
|
-
});
|
|
14
|
-
},
|
|
15
|
-
close(dest) {
|
|
16
|
-
var _a;
|
|
17
|
-
(_a = innerRef.current) === null || _a === void 0 ? void 0 : _a.close(dest);
|
|
18
|
-
},
|
|
19
|
-
}), []);
|
|
20
|
-
// Use a unique key to force a remount, ensuring we get fresh gesture handler nodes within modalize
|
|
21
|
-
return (React.createElement(Modalize, Object.assign({ key: `modalize-${openRenderId}`, ref: innerRef }, props)));
|
|
22
|
-
});
|
|
23
|
-
UNSAFE_WrappedModalize.displayName = "UNSAFE_WrappedModalize";
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import type { IHandles } from "react-native-modalize/lib/options";
|
|
3
|
-
export declare const UNSAFE_WrappedModalize: React.ForwardRefExoticComponent<Omit<import("react-native-modalize/lib/options").IProps<any> & React.RefAttributes<any>, "ref"> & React.RefAttributes<IHandles | undefined>>;
|
|
@@ -1,41 +0,0 @@
|
|
|
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";
|