react-native-dodge-keyboard 1.0.1 → 1.0.3
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/TODO +1 -0
- package/index.d.ts +10 -1
- package/index.js +285 -192
- package/package.json +1 -1
package/TODO
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
keyboard not dodging in state changes
|
package/index.d.ts
CHANGED
|
@@ -102,6 +102,15 @@ interface ReactHijackerProps {
|
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
export function ReactHijacker(props: ReactHijackerProps): React.ReactElement | null;
|
|
105
|
+
export function __HijackNode(props: { children: () => React.ReactElement | null }): React.ReactElement | null;
|
|
106
|
+
|
|
107
|
+
export function createHijackedElement(element?: React.ReactElement | null): { __element: React.ReactElement | null };
|
|
105
108
|
|
|
106
109
|
export function isDodgeScrollable(element: React.ReactNode, disableTagCheck?: boolean): boolean;
|
|
107
|
-
export function isDodgeInput(element: React.ReactNode, disableTagCheck?: boolean): boolean;
|
|
110
|
+
export function isDodgeInput(element: React.ReactNode, disableTagCheck?: boolean): boolean;
|
|
111
|
+
|
|
112
|
+
interface KeyboardPlaceholderProps {
|
|
113
|
+
doHeight: (keyboardheight: number) => number;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function KeyboardPlaceholderView(props: KeyboardPlaceholderProps): React.ReactElement | null;
|
package/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Children, cloneElement, createElement, forwardRef, isValidElement, memo, useEffect, useMemo, useRef, useState } from "react";
|
|
2
|
-
import { Dimensions, findNodeHandle, Keyboard, StyleSheet, UIManager } from "react-native";
|
|
2
|
+
import { Animated, Dimensions, findNodeHandle, Keyboard, Platform, StyleSheet, UIManager, useAnimatedValue } from "react-native";
|
|
3
3
|
|
|
4
4
|
export default function ({ children, offset = 10, disabled, onHandleDodging, disableTagCheck, checkIfElementIsFocused }) {
|
|
5
5
|
if (checkIfElementIsFocused !== undefined) {
|
|
@@ -24,9 +24,9 @@ export default function ({ children, offset = 10, disabled, onHandleDodging, dis
|
|
|
24
24
|
* @type {import("react").RefObject<{[key: string]: { __is_standalone: boolean, _standalone_props: { dodge_keyboard_offset?: number, dodge_keyboard_lift?: boolean }, scrollRef: import("react-native").ScrollView, inputRef: {[key: string]: { ref: import("react-native").TextInput, props: { dodge_keyboard_offset?: number, dodge_keyboard_lift?: boolean } }} }}>}
|
|
25
25
|
*/
|
|
26
26
|
const viewRefsMap = useRef({});
|
|
27
|
-
const isKeyboardVisible = useRef();
|
|
28
27
|
const doDodgeKeyboard = useRef();
|
|
29
28
|
const previousLift = useRef();
|
|
29
|
+
const wasVisible = useRef();
|
|
30
30
|
|
|
31
31
|
const clearPreviousDodge = (scrollId) => {
|
|
32
32
|
if (previousLift.current && previousLift.current !== scrollId) {
|
|
@@ -36,14 +36,26 @@ export default function ({ children, offset = 10, disabled, onHandleDodging, dis
|
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
/**
|
|
40
|
+
* @param {import('react-native').KeyboardEvent | undefined} event
|
|
41
|
+
* @param {boolean} visible
|
|
42
|
+
*/
|
|
43
|
+
doDodgeKeyboard.current = (event, visible) => {
|
|
44
|
+
if (typeof visible !== 'boolean') {
|
|
45
|
+
if (typeof wasVisible.current === 'boolean') {
|
|
46
|
+
visible = wasVisible.current;
|
|
47
|
+
} else return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
wasVisible.current = visible;
|
|
51
|
+
|
|
40
52
|
try {
|
|
41
|
-
const keyboardInfo = Keyboard.metrics();
|
|
53
|
+
const keyboardInfo = event?.endCoordinates || Keyboard.metrics();
|
|
42
54
|
const { width: windowWidth, height: windowHeight } = Dimensions.get('window');
|
|
43
55
|
|
|
44
|
-
console.log('doDodgeKeyboard');
|
|
56
|
+
// console.log('doDodgeKeyboard');
|
|
45
57
|
if (
|
|
46
|
-
|
|
58
|
+
visible &&
|
|
47
59
|
keyboardInfo &&
|
|
48
60
|
!disabled &&
|
|
49
61
|
(keyboardInfo.width === windowWidth ||
|
|
@@ -97,11 +109,11 @@ export default function ({ children, offset = 10, disabled, onHandleDodging, dis
|
|
|
97
109
|
const scrollLift = Math.max(0, (sy + sh + (thisOffset >= 0 ? thisOffset : 0)) - keyboardInfo.screenY);
|
|
98
110
|
const newScrollY = Math.min(requiredScrollY, t);
|
|
99
111
|
|
|
100
|
-
console.log('scrolling-to:', requiredScrollY, ' scrollLift:', scrollLift);
|
|
112
|
+
// console.log('scrolling-to:', requiredScrollY, ' scrollLift:', scrollLift);
|
|
101
113
|
if (scrollLift) {
|
|
102
114
|
setCurrentPaddedScroller([scrollId, scrollLift, newScrollY]);
|
|
103
115
|
} else {
|
|
104
|
-
scrollRef
|
|
116
|
+
tryPerformScroll(scrollRef, newScrollY, true);
|
|
105
117
|
setCurrentPaddedScroller();
|
|
106
118
|
}
|
|
107
119
|
}
|
|
@@ -124,20 +136,24 @@ export default function ({ children, offset = 10, disabled, onHandleDodging, dis
|
|
|
124
136
|
}
|
|
125
137
|
}
|
|
126
138
|
|
|
139
|
+
const tryPerformScroll = (ref, y, animated = true) => {
|
|
140
|
+
if (!ref) return;
|
|
141
|
+
|
|
142
|
+
if (ref.scrollTo) {
|
|
143
|
+
ref.scrollTo?.({ y, animated });
|
|
144
|
+
} else if (ref.scrollToOffset) {
|
|
145
|
+
ref.scrollToOffset?.({ offset: y, animated });
|
|
146
|
+
} else {
|
|
147
|
+
ref.getScrollResponder?.()?.scrollTo?.({ y, animated });
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
127
151
|
const [paddedId, paddedSize, paddedScroll] = currentPaddedScroller || [];
|
|
128
152
|
|
|
129
153
|
useEffect(() => {
|
|
130
154
|
if (currentPaddedScroller) {
|
|
131
155
|
const ref = viewRefsMap.current[paddedId]?.scrollRef;
|
|
132
|
-
|
|
133
|
-
if (ref.scrollTo) {
|
|
134
|
-
ref.scrollTo?.({ y: paddedScroll, animated: true });
|
|
135
|
-
} else if (ref.scrollToOffset) {
|
|
136
|
-
ref.scrollToOffset?.({ offset: paddedScroll, animated: true });
|
|
137
|
-
} else {
|
|
138
|
-
ref.getScrollResponder?.()?.scrollTo?.({ y: paddedScroll, animated: true });
|
|
139
|
-
}
|
|
140
|
-
}
|
|
156
|
+
tryPerformScroll(ref, paddedScroll, false);
|
|
141
157
|
}
|
|
142
158
|
}, [currentPaddedScroller]);
|
|
143
159
|
|
|
@@ -147,19 +163,15 @@ export default function ({ children, offset = 10, disabled, onHandleDodging, dis
|
|
|
147
163
|
|
|
148
164
|
useEffect(() => {
|
|
149
165
|
if (disabled) return;
|
|
150
|
-
const frameListener = Keyboard.addListener('keyboardDidChangeFrame', e =>
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
const hiddenListener = Keyboard.addListener('keyboardDidHide', e => {
|
|
160
|
-
isKeyboardVisible.current = false;
|
|
161
|
-
doDodgeKeyboard.current();
|
|
162
|
-
});
|
|
166
|
+
const frameListener = Keyboard.addListener('keyboardDidChangeFrame', e => doDodgeKeyboard.current(e));
|
|
167
|
+
const showListener = Keyboard.addListener(
|
|
168
|
+
Platform.OS === 'android' ? 'keyboardDidShow' : 'keyboardWillShow',
|
|
169
|
+
e => doDodgeKeyboard.current(e, true)
|
|
170
|
+
);
|
|
171
|
+
const hiddenListener = Keyboard.addListener(
|
|
172
|
+
Platform.OS === 'android' ? 'keyboardDidHide' : 'keyboardWillHide',
|
|
173
|
+
e => doDodgeKeyboard.current(e, false)
|
|
174
|
+
);
|
|
163
175
|
|
|
164
176
|
return () => {
|
|
165
177
|
frameListener.remove();
|
|
@@ -168,135 +180,158 @@ export default function ({ children, offset = 10, disabled, onHandleDodging, dis
|
|
|
168
180
|
}
|
|
169
181
|
}, [!disabled]);
|
|
170
182
|
|
|
171
|
-
|
|
172
|
-
<ReactHijacker
|
|
173
|
-
doHijack={(node, path) => {
|
|
174
|
-
if (node?.props?.['dodge_keyboard_scan_off']) return { element: node };
|
|
175
|
-
|
|
176
|
-
const isStandalone = isDodgeInput(node);
|
|
177
|
-
|
|
178
|
-
if (isStandalone || isDodgeScrollable(node, disableTagCheck)) {
|
|
179
|
-
const scrollId = path.join('=>');
|
|
180
|
-
const initNode = () => {
|
|
181
|
-
if (!viewRefsMap.current[scrollId])
|
|
182
|
-
viewRefsMap.current[scrollId] = { inputRef: {} };
|
|
183
|
-
|
|
184
|
-
if (isStandalone) {
|
|
185
|
-
viewRefsMap.current[scrollId].__is_standalone = true;
|
|
186
|
-
viewRefsMap.current[scrollId]._standalone_props = {
|
|
187
|
-
dodge_keyboard_offset: node.props?.dodge_keyboard_offset,
|
|
188
|
-
dodge_keyboard_lift: node.props?.dodge_keyboard_lift
|
|
189
|
-
};
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
const shouldPad = scrollId === paddedId;
|
|
193
|
-
const contentStyle = shouldPad && StyleSheet.flatten(node.props?.contentContainerStyle);
|
|
194
|
-
const rootRenderItem = node.prop?.renderItem;
|
|
195
|
-
const rootKeyExtractor = node.prop?.keyExtractor;
|
|
196
|
-
const hasInternalList = !isStandalone && (typeof rootRenderItem === 'function' && !node.props?.children);
|
|
197
|
-
|
|
198
|
-
const injectChild = (children, childPath) =>
|
|
199
|
-
ReactHijacker({
|
|
200
|
-
children,
|
|
201
|
-
path: childPath,
|
|
202
|
-
doHijack: (inputNode, path) => {
|
|
203
|
-
if (isDodgeInput(inputNode, disableTagCheck)) {
|
|
204
|
-
const inputId = path.join('=>');
|
|
205
|
-
const initInputNode = () => {
|
|
206
|
-
initNode();
|
|
207
|
-
if (!viewRefsMap.current[scrollId].inputRef[inputId])
|
|
208
|
-
viewRefsMap.current[scrollId].inputRef[inputId] = {};
|
|
209
|
-
viewRefsMap.current[scrollId].inputRef[inputId].props = {
|
|
210
|
-
dodge_keyboard_offset: inputNode.props?.dodge_keyboard_offset,
|
|
211
|
-
dodge_keyboard_lift: inputNode.props?.dodge_keyboard_lift
|
|
212
|
-
};
|
|
213
|
-
}
|
|
183
|
+
const nodeIdIte = useRef(0);
|
|
214
184
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
return {
|
|
218
|
-
props: {
|
|
219
|
-
...inputNode.props,
|
|
220
|
-
onFocus: (...args) => {
|
|
221
|
-
doDodgeKeyboard.current();
|
|
222
|
-
return inputNode.props?.onFocus?.(...args);
|
|
223
|
-
},
|
|
224
|
-
onLayout: (...args) => {
|
|
225
|
-
doDodgeKeyboard.current();
|
|
226
|
-
return inputNode.props?.onLayout?.(...args);
|
|
227
|
-
},
|
|
228
|
-
ref: r => {
|
|
229
|
-
if (r) {
|
|
230
|
-
initInputNode();
|
|
231
|
-
|
|
232
|
-
viewRefsMap.current[scrollId].inputRef[inputId].ref = r;
|
|
233
|
-
} else if (viewRefsMap.current[scrollId]?.inputRef?.[inputId]) {
|
|
234
|
-
delete viewRefsMap.current[scrollId].inputRef[inputId];
|
|
235
|
-
}
|
|
185
|
+
const onHijackNode = node => {
|
|
186
|
+
if (node?.props?.dodge_keyboard_scan_off || node?.props?.__dodging_keyboard) return;
|
|
236
187
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
188
|
+
const isStandalone = isDodgeInput(node);
|
|
189
|
+
if (!isStandalone && !isDodgeScrollable(node, disableTagCheck)) return;
|
|
190
|
+
|
|
191
|
+
const renderer = () => {
|
|
192
|
+
const scrollId = useMemo(() => `${++nodeIdIte.current}`, []);
|
|
193
|
+
|
|
194
|
+
const initNode = () => {
|
|
195
|
+
if (!viewRefsMap.current[scrollId])
|
|
196
|
+
viewRefsMap.current[scrollId] = { inputRef: {} };
|
|
197
|
+
|
|
198
|
+
if (isStandalone) {
|
|
199
|
+
viewRefsMap.current[scrollId].__is_standalone = true;
|
|
200
|
+
viewRefsMap.current[scrollId]._standalone_props = {
|
|
201
|
+
dodge_keyboard_offset: node.props?.dodge_keyboard_offset,
|
|
202
|
+
dodge_keyboard_lift: node.props?.dodge_keyboard_lift
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
const shouldPad = !isStandalone && scrollId === paddedId;
|
|
207
|
+
const contentStyle = shouldPad && StyleSheet.flatten(node.props?.contentContainerStyle);
|
|
208
|
+
const rootRenderItem = node.props?.renderItem;
|
|
209
|
+
const hasInternalList = !isStandalone && (typeof rootRenderItem === 'function' && !node.props?.children);
|
|
210
|
+
|
|
211
|
+
const doRefCleanup = () => {
|
|
212
|
+
if (
|
|
213
|
+
viewRefsMap.current[scrollId]?.scrollRef ||
|
|
214
|
+
Object.keys(viewRefsMap.current[scrollId]?.inputRef || {}).length
|
|
215
|
+
) return;
|
|
216
|
+
delete viewRefsMap.current[scrollId];
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const injectChild = (children, childPath) =>
|
|
220
|
+
ReactHijacker({
|
|
221
|
+
children,
|
|
222
|
+
path: childPath,
|
|
223
|
+
doHijack: inputNode => {
|
|
224
|
+
if (node?.props?.__dodging_keyboard) return;
|
|
225
|
+
|
|
226
|
+
if (!isDodgeInput(inputNode, disableTagCheck)) return;
|
|
227
|
+
|
|
228
|
+
const inputRenderer = () => {
|
|
229
|
+
const inputId = useMemo(() => `${++nodeIdIte.current}`, []);
|
|
230
|
+
const initInputNode = () => {
|
|
231
|
+
initNode();
|
|
232
|
+
if (!viewRefsMap.current[scrollId].inputRef[inputId])
|
|
233
|
+
viewRefsMap.current[scrollId].inputRef[inputId] = {};
|
|
234
|
+
viewRefsMap.current[scrollId].inputRef[inputId].props = {
|
|
235
|
+
dodge_keyboard_offset: inputNode.props?.dodge_keyboard_offset,
|
|
236
|
+
dodge_keyboard_lift: inputNode.props?.dodge_keyboard_lift
|
|
237
|
+
};
|
|
245
238
|
}
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
return {
|
|
249
|
-
props: {
|
|
250
|
-
...node.props,
|
|
251
|
-
...shouldPad ? {
|
|
252
|
-
contentContainerStyle: {
|
|
253
|
-
...contentStyle,
|
|
254
|
-
paddingBottom: paddedSize + (isNumber(contentStyle?.paddingBottom) ? contentStyle.paddingBottom : 0)
|
|
255
|
-
}
|
|
256
|
-
} : {},
|
|
257
|
-
ref: r => {
|
|
258
|
-
if (r) {
|
|
259
|
-
initNode();
|
|
260
|
-
viewRefsMap.current[scrollId].scrollRef = r;
|
|
261
|
-
} else if (viewRefsMap.current[scrollId]) {
|
|
262
|
-
delete viewRefsMap.current[scrollId];
|
|
263
|
-
}
|
|
264
239
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
...isStandalone ? {
|
|
240
|
+
initInputNode();
|
|
241
|
+
|
|
242
|
+
const newProps = {
|
|
243
|
+
...inputNode.props,
|
|
244
|
+
__dodging_keyboard: true,
|
|
271
245
|
onFocus: (...args) => {
|
|
272
246
|
doDodgeKeyboard.current();
|
|
273
|
-
return
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
[
|
|
288
|
-
...path,
|
|
289
|
-
index,
|
|
290
|
-
...typeof rootKeyExtractor === 'function' ?
|
|
291
|
-
[rootKeyExtractor?.(item, index)] : []
|
|
292
|
-
]
|
|
293
|
-
);
|
|
247
|
+
return inputNode.props?.onFocus?.(...args);
|
|
248
|
+
},
|
|
249
|
+
onLayout: (...args) => {
|
|
250
|
+
doDodgeKeyboard.current();
|
|
251
|
+
return inputNode.props?.onLayout?.(...args);
|
|
252
|
+
},
|
|
253
|
+
ref: r => {
|
|
254
|
+
if (r) {
|
|
255
|
+
initInputNode();
|
|
256
|
+
|
|
257
|
+
viewRefsMap.current[scrollId].inputRef[inputId].ref = r;
|
|
258
|
+
} else if (viewRefsMap.current[scrollId]?.inputRef?.[inputId]) {
|
|
259
|
+
delete viewRefsMap.current[scrollId].inputRef[inputId];
|
|
260
|
+
doRefCleanup();
|
|
294
261
|
}
|
|
295
|
-
|
|
262
|
+
|
|
263
|
+
const thatRef = inputNode.props?.ref;
|
|
264
|
+
if (typeof thatRef === 'function') {
|
|
265
|
+
thatRef(r);
|
|
266
|
+
} else if (thatRef) thatRef.current = r;
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
return cloneElement(inputNode, newProps);
|
|
296
271
|
}
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
272
|
+
|
|
273
|
+
return createHijackedElement(
|
|
274
|
+
<__HijackNode>
|
|
275
|
+
{inputRenderer}
|
|
276
|
+
</__HijackNode>
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
const newProps = {
|
|
282
|
+
...node.props,
|
|
283
|
+
__dodging_keyboard: true,
|
|
284
|
+
...shouldPad ? {
|
|
285
|
+
contentContainerStyle: {
|
|
286
|
+
...contentStyle,
|
|
287
|
+
paddingBottom: paddedSize + (isNumber(contentStyle?.paddingBottom) ? contentStyle.paddingBottom : 0)
|
|
288
|
+
}
|
|
289
|
+
} : {},
|
|
290
|
+
ref: r => {
|
|
291
|
+
if (r) {
|
|
292
|
+
initNode();
|
|
293
|
+
viewRefsMap.current[scrollId].scrollRef = r;
|
|
294
|
+
} else if (viewRefsMap.current[scrollId]) {
|
|
295
|
+
viewRefsMap.current[scrollId].scrollRef = undefined;
|
|
296
|
+
doRefCleanup();
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const thatRef = node.props?.ref;
|
|
300
|
+
if (typeof thatRef === 'function') {
|
|
301
|
+
thatRef(r);
|
|
302
|
+
} else if (thatRef) thatRef.current = r;
|
|
303
|
+
},
|
|
304
|
+
...isStandalone ? {
|
|
305
|
+
onFocus: (...args) => {
|
|
306
|
+
doDodgeKeyboard.current();
|
|
307
|
+
return node.props?.onFocus?.(...args);
|
|
308
|
+
}
|
|
309
|
+
} : {},
|
|
310
|
+
onLayout: (...args) => {
|
|
311
|
+
doDodgeKeyboard.current();
|
|
312
|
+
return node.props?.onLayout?.(...args);
|
|
313
|
+
},
|
|
314
|
+
...isStandalone ? {} :
|
|
315
|
+
hasInternalList ? {
|
|
316
|
+
renderItem: (...args) => {
|
|
317
|
+
return injectChild(rootRenderItem(...args));
|
|
318
|
+
}
|
|
319
|
+
} : { children: injectChild(node.props?.children) }
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
return cloneElement(node, newProps);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
return createHijackedElement(
|
|
326
|
+
<__HijackNode>
|
|
327
|
+
{renderer}
|
|
328
|
+
</__HijackNode>
|
|
329
|
+
);
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
return (
|
|
333
|
+
<ReactHijacker
|
|
334
|
+
doHijack={onHijackNode}>
|
|
300
335
|
{children}
|
|
301
336
|
</ReactHijacker>
|
|
302
337
|
);
|
|
@@ -319,61 +354,43 @@ const REACT_SYMBOLS = {
|
|
|
319
354
|
memo: Symbol.for('react.memo')
|
|
320
355
|
};
|
|
321
356
|
|
|
322
|
-
export function ReactHijacker({ children, doHijack,
|
|
323
|
-
const renderRefs = useMemo(() => new Map(), []);
|
|
324
|
-
|
|
357
|
+
export function ReactHijacker({ children, doHijack, enableLocator }) {
|
|
325
358
|
const instantDoHijack = useRef();
|
|
326
359
|
instantDoHijack.current = doHijack;
|
|
327
360
|
|
|
328
|
-
const injectIntoTree = (node, path
|
|
361
|
+
const injectIntoTree = (node, path) => {
|
|
329
362
|
if (!node) return node;
|
|
330
363
|
if (Array.isArray(node)) {
|
|
331
|
-
return Children.map(node, (v, i) => injectIntoTree(v, [...path, i]
|
|
364
|
+
return Children.map(node, (v, i) => injectIntoTree(v, path && [...path, i]));
|
|
332
365
|
}
|
|
333
366
|
if (!isValidElement(node)) return node;
|
|
334
367
|
|
|
335
|
-
path = [...path,
|
|
368
|
+
if (path) path = [...path, getNodeId(node)];
|
|
336
369
|
|
|
337
370
|
let thisObj;
|
|
338
|
-
if (thisObj = instantDoHijack.current?.(node, path)) {
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
if (Object.hasOwn(thisObj, 'element')) return element;
|
|
342
|
-
if (props) return cloneElement(node, props);
|
|
343
|
-
return node;
|
|
371
|
+
if (Object.hasOwn((thisObj = instantDoHijack.current?.(node, path)) || {}, '__element')) {
|
|
372
|
+
return thisObj.__element;
|
|
344
373
|
}
|
|
345
374
|
|
|
346
375
|
if (!isHostElement(node)) {
|
|
347
376
|
const wrapNodeType = (nodeType, pathway, pathKey) => {
|
|
348
|
-
pathway = [...pathway, getNodeId(undefined, nodeType, pathKey)];
|
|
349
|
-
const path_id = pathway.join(',');
|
|
350
|
-
let renderRefStore = renderRefs.get(nodeType);
|
|
351
|
-
|
|
352
|
-
if (renderRefStore?.[path_id]) return renderRefStore[path_id];
|
|
377
|
+
if (pathway) pathway = [...pathway, getNodeId(undefined, nodeType, pathKey)];
|
|
353
378
|
|
|
354
379
|
// if (doLogging) console.log('wrapNodeType path:', pathway, ' node:', nodeType);
|
|
355
380
|
const render = (renderedNode) => {
|
|
356
381
|
// if (doLogging) console.log('deep path:', pathway, ' node:', renderedNode);
|
|
357
|
-
return injectIntoTree(renderedNode, pathway);
|
|
382
|
+
return injectIntoTree(renderedNode, pathway && [...pathway, 0]);
|
|
358
383
|
}
|
|
359
384
|
|
|
360
|
-
let newType;
|
|
361
|
-
|
|
362
385
|
if (typeof nodeType === 'function') { // check self closed tag
|
|
363
|
-
|
|
386
|
+
return hijackRender(nodeType, render);
|
|
364
387
|
} else if (nodeType?.$$typeof === REACT_SYMBOLS.forwardRef) {
|
|
365
|
-
|
|
388
|
+
return forwardRef(hijackRender(nodeType.render, render));
|
|
366
389
|
} else if (nodeType?.$$typeof === REACT_SYMBOLS.memo) {
|
|
367
|
-
newType = memo(wrapNodeType(nodeType.type, pathway), nodeType.compare);
|
|
390
|
+
const newType = memo(wrapNodeType(nodeType.type, pathway), nodeType.compare);
|
|
368
391
|
newType.displayName = nodeType.displayName || nodeType.name;
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
if (newType) {
|
|
372
|
-
if (!renderRefStore) renderRefs.set(nodeType, renderRefStore = {});
|
|
373
|
-
renderRefStore[path_id] = newType;
|
|
374
392
|
return newType;
|
|
375
393
|
}
|
|
376
|
-
|
|
377
394
|
return nodeType;
|
|
378
395
|
}
|
|
379
396
|
|
|
@@ -383,15 +400,24 @@ export function ReactHijacker({ children, doHijack, path }) {
|
|
|
383
400
|
node.type?.$$typeof === REACT_SYMBOLS.memo // check memo
|
|
384
401
|
) {
|
|
385
402
|
// if (doLogging) console.log('doLog path:', path, ' node:', node);
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
403
|
+
return (
|
|
404
|
+
<__HijackNodePath>
|
|
405
|
+
{() => {
|
|
406
|
+
const hijackType = useMemo(() =>
|
|
407
|
+
wrapNodeType(node.type, path && path.slice(0, -1), node.key),
|
|
408
|
+
[node.type]
|
|
409
|
+
);
|
|
410
|
+
|
|
411
|
+
return createElement(
|
|
412
|
+
hijackType,
|
|
413
|
+
{
|
|
414
|
+
...node.props,
|
|
415
|
+
key: node.key
|
|
416
|
+
},
|
|
417
|
+
node.props?.children
|
|
418
|
+
);
|
|
419
|
+
}}
|
|
420
|
+
</__HijackNodePath>
|
|
395
421
|
);
|
|
396
422
|
}
|
|
397
423
|
}
|
|
@@ -399,15 +425,24 @@ export function ReactHijacker({ children, doHijack, path }) {
|
|
|
399
425
|
const children = node.props?.children;
|
|
400
426
|
if (children)
|
|
401
427
|
return cloneElement(node, {
|
|
402
|
-
children: injectIntoTree(children, path)
|
|
428
|
+
children: injectIntoTree(children, path && [...path, 0])
|
|
403
429
|
});
|
|
404
430
|
|
|
405
431
|
return node;
|
|
406
432
|
};
|
|
407
433
|
|
|
408
|
-
return injectIntoTree(children,
|
|
434
|
+
return injectIntoTree(children, enableLocator ? [] : undefined);
|
|
409
435
|
};
|
|
410
436
|
|
|
437
|
+
export const createHijackedElement = (element) => ({ __element: element });
|
|
438
|
+
export function __HijackNode({ children }) {
|
|
439
|
+
return children?.();
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
function __HijackNodePath({ children }) {
|
|
443
|
+
return children?.();
|
|
444
|
+
}
|
|
445
|
+
|
|
411
446
|
const hijackRender = (type, doHijack) =>
|
|
412
447
|
new Proxy(type, {
|
|
413
448
|
apply(target, thisArg, args) {
|
|
@@ -481,4 +516,62 @@ export const isDodgeInput = (element, disableTagCheck) => {
|
|
|
481
516
|
|
|
482
517
|
return inputTypes.includes(element.type?.displayName)
|
|
483
518
|
|| inputTypes.includes(element.type?.name);
|
|
484
|
-
};
|
|
519
|
+
};
|
|
520
|
+
|
|
521
|
+
export const KeyboardPlaceholderView = ({ doHeight }) => {
|
|
522
|
+
const height = useAnimatedValue(0);
|
|
523
|
+
|
|
524
|
+
const instantDoHeight = useRef();
|
|
525
|
+
instantDoHeight.current = doHeight;
|
|
526
|
+
|
|
527
|
+
useEffect(() => {
|
|
528
|
+
let wasVisible;
|
|
529
|
+
/**
|
|
530
|
+
* @param {import('react-native').KeyboardEvent} event
|
|
531
|
+
* @param {boolean} visible
|
|
532
|
+
*/
|
|
533
|
+
const updateKeyboardHeight = (event, visible) => {
|
|
534
|
+
if (typeof visible !== 'boolean') {
|
|
535
|
+
if (typeof wasVisible === 'boolean') {
|
|
536
|
+
visible = wasVisible;
|
|
537
|
+
} else return;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
wasVisible = visible;
|
|
541
|
+
|
|
542
|
+
const { endCoordinates, isEventFromThisApp, duration } = event;
|
|
543
|
+
if (Platform.OS === 'ios' && !isEventFromThisApp) return;
|
|
544
|
+
|
|
545
|
+
const kh = visible ? endCoordinates.height : 0;
|
|
546
|
+
const newHeight = Math.max(0, instantDoHeight.current ? instantDoHeight.current(kh) : kh);
|
|
547
|
+
const newDuration = (Math.abs(height._value - newHeight) * duration) / endCoordinates.height;
|
|
548
|
+
|
|
549
|
+
Animated.timing(height, {
|
|
550
|
+
duration: newDuration,
|
|
551
|
+
toValue: newHeight,
|
|
552
|
+
useNativeDriver: false
|
|
553
|
+
}).start();
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
const initialMetric = Keyboard.metrics();
|
|
557
|
+
if (initialMetric) updateKeyboardHeight(initialMetric, true);
|
|
558
|
+
|
|
559
|
+
const frameListener = Keyboard.addListener('keyboardDidChangeFrame', e => updateKeyboardHeight(e));
|
|
560
|
+
const showListener = Keyboard.addListener(
|
|
561
|
+
Platform.OS === 'android' ? 'keyboardDidShow' : 'keyboardWillShow',
|
|
562
|
+
e => updateKeyboardHeight(e, true)
|
|
563
|
+
);
|
|
564
|
+
const hiddenListener = Keyboard.addListener(
|
|
565
|
+
Platform.OS === 'android' ? 'keyboardDidHide' : 'keyboardWillHide',
|
|
566
|
+
e => updateKeyboardHeight(e, false)
|
|
567
|
+
);
|
|
568
|
+
|
|
569
|
+
return () => {
|
|
570
|
+
frameListener.remove();
|
|
571
|
+
showListener.remove();
|
|
572
|
+
hiddenListener.remove();
|
|
573
|
+
}
|
|
574
|
+
}, []);
|
|
575
|
+
|
|
576
|
+
return <Animated.View style={{ height }} />;
|
|
577
|
+
}
|
package/package.json
CHANGED