react-native-auto-positioned-popup 1.0.12 → 1.0.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/lib/AutoPositionedPopup.d.ts.map +1 -1
- package/lib/AutoPositionedPopup.js +356 -153
- package/lib/AutoPositionedPopup.js.map +1 -1
- package/lib/AutoPositionedPopupProps.d.ts +6 -0
- package/lib/AutoPositionedPopupProps.d.ts.map +1 -1
- package/lib/KeyboardManager.d.ts.map +1 -1
- package/lib/KeyboardManager.js +60 -34
- package/lib/KeyboardManager.js.map +1 -1
- package/lib/RootViewContext.d.ts.map +1 -1
- package/lib/RootViewContext.js +21 -16
- package/lib/RootViewContext.js.map +1 -1
- package/package.json +1 -1
- package/src/AutoPositionedPopup.tsx +419 -238
- package/src/AutoPositionedPopupProps.ts +13 -7
- package/src/KeyboardManager.tsx +73 -49
- package/src/RootViewContext.tsx +31 -28
|
@@ -34,9 +34,7 @@ const ListItem = memo(({ updateState, item, index, selectedItem, }) => {
|
|
|
34
34
|
rootViewsRef.current = rootViews;
|
|
35
35
|
}, [rootViews]);
|
|
36
36
|
return useMemo(() => {
|
|
37
|
-
// console.log('AutoPositionedPopup.tsx ListItem
|
|
38
|
-
console.log('AutoPositionedPopup.tsx ListItem item=', item);
|
|
39
|
-
console.log('AutoPositionedPopup.tsx ListItem selectedItem=', selectedItem);
|
|
37
|
+
// console.log('AutoPositionedPopup.tsx ListItem=', {index, item, selectedItem});
|
|
40
38
|
const isSelected = item.id === (selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.id);
|
|
41
39
|
return (<TouchableOpacity key={item.id} style={[
|
|
42
40
|
styles.commonModalRow,
|
|
@@ -79,8 +77,8 @@ const AutoPositionedPopupList = memo(({ tag, updateState, fetchData, keyExtracto
|
|
|
79
77
|
};
|
|
80
78
|
}, []);
|
|
81
79
|
// useEffect(() => {
|
|
82
|
-
// //
|
|
83
|
-
// //
|
|
80
|
+
// // Listen to TextInput events, refresh list when received, not dependent on global searchQuery
|
|
81
|
+
// // Sync the latest searchQuery to list-specific ref for _fetchData to use
|
|
84
82
|
// ref_searchQuery.current = searchQuery;
|
|
85
83
|
// console.log('AutoPositionedPopupList useEffect searchQuery=', searchQuery);
|
|
86
84
|
// console.log('AutoPositionedPopupList useEffect state.localData=', state.localData);
|
|
@@ -109,10 +107,7 @@ const AutoPositionedPopupList = memo(({ tag, updateState, fetchData, keyExtracto
|
|
|
109
107
|
updateState(key, value);
|
|
110
108
|
};
|
|
111
109
|
const _fetchData = async ({ pageIndex, pageSize: currentPageSize, }) => {
|
|
112
|
-
console.log('AutoPositionedPopupList _fetchData
|
|
113
|
-
console.log('AutoPositionedPopupList _fetchData state.localData=', state.localData);
|
|
114
|
-
console.log('AutoPositionedPopupList _fetchData ref_searchQuery.current=', ref_searchQuery.current);
|
|
115
|
-
console.log('AutoPositionedPopupList _fetchData localSearch=', localSearch);
|
|
110
|
+
console.log('AutoPositionedPopupList _fetchData=', { pageIndex, pageSize: currentPageSize, 'state.localData': state.localData, 'ref_searchQuery.current': ref_searchQuery.current, localSearch });
|
|
116
111
|
if (localSearch && state.localData.length > 0) {
|
|
117
112
|
const result = state.localData.filter((item) => {
|
|
118
113
|
var _a;
|
|
@@ -183,7 +178,7 @@ const listLayout = {
|
|
|
183
178
|
// Main AutoPositionedPopup component
|
|
184
179
|
const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
|
|
185
180
|
console.log('AutoPositionedPopup props=', props);
|
|
186
|
-
const { tag, style, AutoPositionedPopupBtnStyle, placeholder = 'Please Select', onSubmitEditing, TextInputProps = {}, inputStyle, labelStyle, popUpViewStyle = { left: '5%', width: '90%' }, fetchData = async ({ pageIndex, pageSize, searchQuery, }) => {
|
|
181
|
+
const { tag, style, AutoPositionedPopupBtnStyle, placeholder = 'Please Select', onSubmitEditing, TextInputProps = { autoFocus: true }, inputStyle, labelStyle, popUpViewStyle = { left: '5%', width: '90%' }, fetchData = async ({ pageIndex, pageSize, searchQuery, }) => {
|
|
187
182
|
const res = {
|
|
188
183
|
items: [],
|
|
189
184
|
pageIndex,
|
|
@@ -219,6 +214,16 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
|
|
|
219
214
|
const keyboardVisibleRef = useRef(false);
|
|
220
215
|
const refAutoPositionedPopup = useRef(null);
|
|
221
216
|
const ref_searchQuery = useRef('');
|
|
217
|
+
// Add ref to track previous keyboard state to avoid false triggers during parent component re-renders
|
|
218
|
+
const prevIsKeyboardFullyShownRef = useRef(false);
|
|
219
|
+
const prevPropsRef = useRef({});
|
|
220
|
+
// Add ref to prevent onFocus/onBlur loop triggers during parent component re-renders
|
|
221
|
+
const lastFocusTimeRef = useRef(0);
|
|
222
|
+
const isFocusEventProcessingRef = useRef(false);
|
|
223
|
+
// Add ref to stabilize TextInput props reference
|
|
224
|
+
// Only update when deep comparison detects real changes to avoid TextInput recreation due to reference changes during parent component redraws
|
|
225
|
+
const stableInputStyleRef = useRef(inputStyle);
|
|
226
|
+
const stableTextInputPropsRef = useRef(TextInputProps);
|
|
222
227
|
// Simple keyboard status tracking (alternative to useKeyboardStatus hook)
|
|
223
228
|
// Legacy state for compatibility
|
|
224
229
|
const [isVisible, setIsVisible] = useState(false);
|
|
@@ -240,8 +245,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
|
|
|
240
245
|
useEffect(() => {
|
|
241
246
|
(async () => {
|
|
242
247
|
})();
|
|
243
|
-
console.log(`AutoPositionedPopup componentDidMount tag
|
|
244
|
-
console.log('AutoPositionedPopup componentDidMount CustomPopView=', CustomPopView);
|
|
248
|
+
console.log(`AutoPositionedPopup componentDidMount=`, { tag, CustomPopView });
|
|
245
249
|
//componentWillUnmount
|
|
246
250
|
return () => {
|
|
247
251
|
console.log(`AutoPositionedPopup componentWillUnmount tag=`, tag);
|
|
@@ -272,8 +276,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
|
|
|
272
276
|
}, [rootViews]);
|
|
273
277
|
useEffect(() => {
|
|
274
278
|
var _a, _b;
|
|
275
|
-
console.log('AutoPositionedPopup useEffect tag=', tag);
|
|
276
|
-
console.log('AutoPositionedPopup useEffect selectedItem=', selectedItem);
|
|
279
|
+
console.log('AutoPositionedPopup useEffect [selectedItem, state.selectedItem, tag]=', { tag, selectedItem, 'state.selectedItem': state.selectedItem });
|
|
277
280
|
console.log('AutoPositionedPopup useEffect state.selectedItem=', state.selectedItem);
|
|
278
281
|
if (((_a = state.selectedItem) === null || _a === void 0 ? void 0 : _a.id) !== (selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.id) || ((_b = state.selectedItem) === null || _b === void 0 ? void 0 : _b.title) !== (selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.title)) {
|
|
279
282
|
console.log('AutoPositionedPopup useEffect selectedItem!=state.selectedItem');
|
|
@@ -283,47 +286,123 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
|
|
|
283
286
|
}
|
|
284
287
|
}, [selectedItem, state.selectedItem, tag]);
|
|
285
288
|
useEffect(() => {
|
|
286
|
-
var _a, _b
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
console.log('AutoPositionedPopup useEffect
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
289
|
+
var _a, _b;
|
|
290
|
+
// Detect if keyboard state has actually changed to avoid false triggers during parent component re-renders
|
|
291
|
+
const keyboardStateChanged = prevIsKeyboardFullyShownRef.current !== isKeyboardFullyShown;
|
|
292
|
+
const propsChanged = prevPropsRef.current.CustomPopView !== CustomPopView ||
|
|
293
|
+
prevPropsRef.current.CustomPopViewStyle !== CustomPopViewStyle ||
|
|
294
|
+
prevPropsRef.current.TextInputProps !== TextInputProps;
|
|
295
|
+
console.log('AutoPositionedPopup useEffect [isKeyboardFullyShown,\n' +
|
|
296
|
+
' state.isFocus,\n' +
|
|
297
|
+
' useTextInput,\n' +
|
|
298
|
+
' CustomPopView,\n' +
|
|
299
|
+
' CustomPopViewStyle,\n' +
|
|
300
|
+
' forceRemoveAllRootViewOnItemSelected,\n' +
|
|
301
|
+
' tag, TextInputProps,\n' +
|
|
302
|
+
' state.selectedItem, showListEmptyComponent\n' +
|
|
303
|
+
' ]=', {
|
|
304
|
+
tag,
|
|
305
|
+
'state.isFocus': state.isFocus,
|
|
306
|
+
isKeyboardFullyShown,
|
|
307
|
+
'ref_isFocus.current': ref_isFocus.current,
|
|
308
|
+
'ref_isKeyboardFullyShown.current': ref_isKeyboardFullyShown.current,
|
|
309
|
+
useTextInput, TextInputProps,
|
|
310
|
+
'hasAddedRootView.current': hasAddedRootView.current,
|
|
311
|
+
'hasShownRootView.current': hasShownRootView.current,
|
|
312
|
+
'keyboardStateChanged': keyboardStateChanged,
|
|
313
|
+
'propsChanged': propsChanged
|
|
314
|
+
});
|
|
315
|
+
// Update ref to record current state
|
|
316
|
+
prevIsKeyboardFullyShownRef.current = isKeyboardFullyShown;
|
|
317
|
+
prevPropsRef.current = {
|
|
318
|
+
CustomPopView,
|
|
319
|
+
CustomPopViewStyle,
|
|
320
|
+
TextInputProps
|
|
321
|
+
};
|
|
322
|
+
// Only execute logic when keyboard state actually changes or user actively operates
|
|
323
|
+
if (!keyboardStateChanged && hasAddedRootView.current) {
|
|
324
|
+
console.log('AutoPositionedPopup: Skip execution - parent component re-rendered but keyboard state unchanged textInputRef.current=', textInputRef.current);
|
|
325
|
+
// if (!ref_isFocus.current) {
|
|
326
|
+
// textInputRef.current?.focus()
|
|
327
|
+
// }
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
296
330
|
if (useTextInput) {
|
|
297
331
|
if (isKeyboardFullyShown && hasAddedRootView.current && !hasShownRootView.current && state.isFocus) {
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
332
|
+
// CRITICAL FIX FOR KEYBOARD POSITION CALCULATION
|
|
333
|
+
// Problem: When keyboard appears, the page shifts up but measureInWindow executes too early
|
|
334
|
+
// Solution: Wait for keyboard animation (300ms) + use requestAnimationFrame for next render frame
|
|
335
|
+
//
|
|
336
|
+
// Timing breakdown:
|
|
337
|
+
// 1. Keyboard animation: ~250-300ms (iOS/Android)
|
|
338
|
+
// 2. Page shift animation: ~200-300ms (KeyboardAvoidingView)
|
|
339
|
+
// 3. Layout tree update: ~50-100ms (React Native)
|
|
340
|
+
// Total: ~500-700ms needed for stable layout
|
|
341
|
+
//
|
|
342
|
+
// Strategy: setTimeout(300ms) waits for most animations to complete,
|
|
343
|
+
// then requestAnimationFrame ensures measurement happens after next render frame
|
|
344
|
+
setTimeout(() => {
|
|
345
|
+
requestAnimationFrame(() => {
|
|
346
|
+
var _a;
|
|
347
|
+
(_a = refAutoPositionedPopup.current) === null || _a === void 0 ? void 0 : _a.measureInWindow((x, y, width, height) => {
|
|
348
|
+
var _a;
|
|
349
|
+
console.log('AutoPositionedPopup useTextInput measureInWindow (after 300ms + RAF, layout stable)=', { x, y, width, height });
|
|
350
|
+
// CRITICAL FIX: Coordinate system mismatch issue
|
|
351
|
+
// Problem: measureInWindow returns coordinates relative to window (fixed reference),
|
|
352
|
+
// but popup uses absolute positioning relative to App container (which shifts when keyboard appears)
|
|
353
|
+
//
|
|
354
|
+
// When keyboard appears:
|
|
355
|
+
// 1. measureInWindow returns y relative to window (e.g., y=400 after shifting)
|
|
356
|
+
// 2. But popup's absolute positioning is relative to App container
|
|
357
|
+
// 3. If App container shifted up by 200px, setting top=200 will display at window.y=0 (wrong!)
|
|
358
|
+
//
|
|
359
|
+
// Solution: Since popup is rendered at root level and uses absolute positioning,
|
|
360
|
+
// we should directly use measureInWindow's y value without additional calculations
|
|
361
|
+
// The popup container is at the same level as the page content
|
|
362
|
+
const screenHeight = Dimensions.get('window').height; // Use window height, not screen
|
|
363
|
+
console.log('AutoPositionedPopup useTextInput positioning data=', {
|
|
364
|
+
screenHeight,
|
|
365
|
+
componentY: y,
|
|
366
|
+
componentHeight: height,
|
|
367
|
+
listHeight: listLayout.height
|
|
368
|
+
});
|
|
369
|
+
// CORRECT POSITIONING LOGIC (as per user requirement):
|
|
370
|
+
// 1. ALWAYS try to show popup ABOVE the input field first
|
|
371
|
+
// 2. Only if that goes off the top of screen, show BELOW instead
|
|
372
|
+
// 3. Don't cover/overlap the input field
|
|
373
|
+
let popupY = y - listLayout.height; // Default: above input field
|
|
374
|
+
// Check if showing above would go off the top of screen
|
|
375
|
+
if (popupY < 0) {
|
|
376
|
+
console.log('AutoPositionedPopup with keyboard: would go off screen top, showing BELOW instead');
|
|
377
|
+
popupY = y + height; // Show below input field
|
|
378
|
+
// Also check if showing below would go off the bottom
|
|
379
|
+
const maxY = screenHeight - listLayout.height;
|
|
380
|
+
if (popupY > maxY) {
|
|
381
|
+
// If both positions are problematic, clamp to visible area
|
|
382
|
+
console.log('AutoPositionedPopup with keyboard: both positions problematic, clamping to visible area');
|
|
383
|
+
popupY = Math.min(Math.max(0, y - listLayout.height), maxY);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
else {
|
|
387
|
+
console.log('AutoPositionedPopup with keyboard: showing ABOVE input field (preferred position)');
|
|
388
|
+
}
|
|
389
|
+
ref_listPos.current = { x: x, y: popupY, width: width };
|
|
390
|
+
console.log('AutoPositionedPopup useTextInput final position=', ref_listPos.current);
|
|
391
|
+
setRootViewNativeStyle(tag, {
|
|
392
|
+
top: (_a = ref_listPos.current) === null || _a === void 0 ? void 0 : _a.y,
|
|
393
|
+
left: popUpViewStyle === null || popUpViewStyle === void 0 ? void 0 : popUpViewStyle.left,
|
|
394
|
+
width: popUpViewStyle === null || popUpViewStyle === void 0 ? void 0 : popUpViewStyle.width,
|
|
395
|
+
height: listLayout.height,
|
|
396
|
+
opacity: 1,
|
|
397
|
+
});
|
|
398
|
+
hasShownRootView.current = true;
|
|
399
|
+
});
|
|
321
400
|
});
|
|
322
|
-
|
|
323
|
-
});
|
|
401
|
+
}, 300); // 300ms is sufficient for keyboard animation, as proven by user testing (even 3000ms didn't fix wrong logic)
|
|
324
402
|
}
|
|
325
|
-
else if (!isKeyboardFullyShown && ref_isFocus.current) {
|
|
326
|
-
|
|
403
|
+
else if (!isKeyboardFullyShown && ref_isFocus.current && keyboardStateChanged) {
|
|
404
|
+
// Only execute close logic when keyboard state actually changes from true to false
|
|
405
|
+
console.log('AutoPositionedPopup isKeyboardFullyShown useEffect removeRootView (keyboard state changed)=', { tag, forceRemoveAllRootViewOnItemSelected, keyboardStateChanged });
|
|
327
406
|
removeRootView(tag, forceRemoveAllRootViewOnItemSelected);
|
|
328
407
|
setState((prevState) => {
|
|
329
408
|
return Object.assign(Object.assign({}, prevState), { isFocus: false });
|
|
@@ -335,11 +414,11 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
|
|
|
335
414
|
}
|
|
336
415
|
else {
|
|
337
416
|
if (state.isFocus) {
|
|
338
|
-
(
|
|
339
|
-
console.log('AutoPositionedPopup measureInWindow
|
|
417
|
+
(_a = refAutoPositionedPopup.current) === null || _a === void 0 ? void 0 : _a.measureInWindow((x, y, width, height) => {
|
|
418
|
+
console.log('AutoPositionedPopup !useTextInput measureInWindow=', { x, y, width, height });
|
|
340
419
|
// INTELLIGENT POSITION CALCULATION - MODIFIED VERSION WITH STATUS BAR SAFETY
|
|
341
420
|
const calculateOptimalPosition = (componentY, componentHeight, popupHeight) => {
|
|
342
|
-
console.log('🔥🔥🔥 NEW CALCULATE OPTIMAL POSITION FUNCTION EXECUTING 🔥🔥🔥');
|
|
421
|
+
console.log('AutoPositionedPopup 🔥🔥🔥 NEW CALCULATE OPTIMAL POSITION FUNCTION EXECUTING 🔥🔥🔥');
|
|
343
422
|
// Use window height (visible area) instead of screen height (includes status bar)
|
|
344
423
|
const windowHeight = Dimensions.get('window').height;
|
|
345
424
|
const visibleAreaCenter = windowHeight / 2;
|
|
@@ -356,7 +435,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
|
|
|
356
435
|
}
|
|
357
436
|
};
|
|
358
437
|
const statusBarHeight = getStatusBarHeight();
|
|
359
|
-
console.log('🔥 Cross-platform StatusBar height:', statusBarHeight, 'Platform:', Platform.OS);
|
|
438
|
+
console.log('AutoPositionedPopup 🔥 Cross-platform StatusBar height:', statusBarHeight, 'Platform:', Platform.OS);
|
|
360
439
|
// Calculate component center point as requested
|
|
361
440
|
const componentCenterY = componentY + componentHeight / 2;
|
|
362
441
|
console.log('AutoPositionedPopup positioning data:', {
|
|
@@ -404,7 +483,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
|
|
|
404
483
|
// Strong platform adjustment - much smaller for Android bottom components
|
|
405
484
|
const platformMultiplier = Platform.OS === 'ios' ? 1.0 : (isInBottomHalf ? 0.5 : 0.9);
|
|
406
485
|
const finalSpacing = Math.max(baseSpacing, relativeSpacing) * edgeProximityFactor * platformMultiplier;
|
|
407
|
-
console.log('🔥 Advanced spacing calculation:', {
|
|
486
|
+
console.log('AutoPositionedPopup 🔥 Advanced spacing calculation:', {
|
|
408
487
|
componentCenter,
|
|
409
488
|
screenCenter,
|
|
410
489
|
distanceFromCenter,
|
|
@@ -440,7 +519,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
|
|
|
440
519
|
// Component in bottom half + enough space above = FORCE ABOVE
|
|
441
520
|
showAbove = true;
|
|
442
521
|
finalY = componentY - popupHeight + componentHeight / 2;
|
|
443
|
-
console.log('🔥 AutoPositionedPopup: FORCE ABOVE - bottom half component with enough space, finalY=', finalY);
|
|
522
|
+
console.log('AutoPositionedPopup 🔥 AutoPositionedPopup: FORCE ABOVE - bottom half component with enough space, finalY=', finalY);
|
|
444
523
|
}
|
|
445
524
|
else if (!isInBottomHalf && spaceBelow >= popupHeight) {
|
|
446
525
|
// Component in top half + enough space below = show below
|
|
@@ -474,7 +553,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
|
|
|
474
553
|
}
|
|
475
554
|
}
|
|
476
555
|
// Enhanced boundary check with detailed logging
|
|
477
|
-
console.log('🔥 Pre-boundary check:', {
|
|
556
|
+
console.log('AutoPositionedPopup 🔥 Pre-boundary check:', {
|
|
478
557
|
originalFinalY: finalY,
|
|
479
558
|
showAbove,
|
|
480
559
|
statusBarHeight,
|
|
@@ -486,21 +565,21 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
|
|
|
486
565
|
if (showAbove && finalY < statusBarHeight) {
|
|
487
566
|
const oldFinalY = finalY;
|
|
488
567
|
finalY = statusBarHeight;
|
|
489
|
-
console.log('🔥 BOUNDARY
|
|
568
|
+
console.log('AutoPositionedPopup 🔥 BOUNDARY : Above display adjusted for status bar:', oldFinalY, '->', finalY);
|
|
490
569
|
}
|
|
491
570
|
if (!showAbove && finalY + popupHeight > windowHeight) {
|
|
492
571
|
const oldFinalY = finalY;
|
|
493
572
|
finalY = windowHeight - popupHeight;
|
|
494
|
-
console.log('🔥 BOUNDARY
|
|
573
|
+
console.log('AutoPositionedPopup 🔥 BOUNDARY : Below display adjusted to fit window:', oldFinalY, '->', finalY);
|
|
495
574
|
}
|
|
496
575
|
// CRITICAL CHECK: Detect if boundary check is changing display direction
|
|
497
576
|
if (showAbove && finalY + popupHeight > componentY) {
|
|
498
|
-
console.log('🚨 WARNING: Above positioning may overlap with component!');
|
|
577
|
+
console.log('AutoPositionedPopup 🚨 WARNING: Above positioning may overlap with component!');
|
|
499
578
|
}
|
|
500
579
|
if (!showAbove && finalY < componentY + componentHeight) {
|
|
501
|
-
console.log('🚨 WARNING: Below positioning may overlap with component!');
|
|
580
|
+
console.log('AutoPositionedPopup 🚨 WARNING: Below positioning may overlap with component!');
|
|
502
581
|
}
|
|
503
|
-
console.log('🔥 Post-boundary check final result:', {
|
|
582
|
+
console.log('AutoPositionedPopup 🔥 Post-boundary check final result:', {
|
|
504
583
|
finalY,
|
|
505
584
|
showAbove,
|
|
506
585
|
'popupTop': finalY,
|
|
@@ -514,17 +593,15 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
|
|
|
514
593
|
const actualPopupHeight = CustomPopView && CustomPopViewStyle && typeof CustomPopViewStyle.height === 'number'
|
|
515
594
|
? CustomPopViewStyle.height
|
|
516
595
|
: listLayout.height;
|
|
517
|
-
console.log('🔥 Using actualPopupHeight for calculation:', actualPopupHeight,
|
|
596
|
+
console.log('AutoPositionedPopup 🔥 Using actualPopupHeight for calculation:', { actualPopupHeight, CustomPopView: !!CustomPopView });
|
|
518
597
|
const positionResult = calculateOptimalPosition(y, height, actualPopupHeight);
|
|
519
598
|
console.log('AutoPositionedPopup FINAL position result:', positionResult);
|
|
520
599
|
ref_listPos.current = { x: x, y: positionResult.finalY, width: width };
|
|
521
|
-
console.log('AutoPositionedPopup ref_listPos.current=', ref_listPos.current);
|
|
600
|
+
console.log('AutoPositionedPopup !useTextInput ref_listPos.current=', ref_listPos.current);
|
|
522
601
|
if (CustomPopView && CustomPopViewStyle) {
|
|
523
|
-
console.log('AutoPositionedPopup CustomPopViewStyle=', CustomPopViewStyle);
|
|
524
602
|
// Position already calculated correctly above, no need to recalculate
|
|
525
603
|
const PopViewComponent = CustomPopView();
|
|
526
|
-
console.log('AutoPositionedPopup addRootView
|
|
527
|
-
console.log('AutoPositionedPopup addRootView state.selectedItem=', state.selectedItem);
|
|
604
|
+
console.log('AutoPositionedPopup !useTextInput addRootView=', { CustomPopViewStyle, PopViewComponent, 'state.selectedItem': state.selectedItem });
|
|
528
605
|
addRootView({
|
|
529
606
|
id: tag,
|
|
530
607
|
style: !centerDisplay
|
|
@@ -546,7 +623,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
|
|
|
546
623
|
});
|
|
547
624
|
}
|
|
548
625
|
else {
|
|
549
|
-
console.log('AutoPositionedPopup addRootView tag=', tag);
|
|
626
|
+
console.log('AutoPositionedPopup !useTextInput addRootView tag=', tag);
|
|
550
627
|
addRootView({
|
|
551
628
|
id: tag,
|
|
552
629
|
style: {
|
|
@@ -572,7 +649,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
|
|
|
572
649
|
}
|
|
573
650
|
}
|
|
574
651
|
if (isKeyboardFullyShown) {
|
|
575
|
-
ref_isFocus.current = (
|
|
652
|
+
ref_isFocus.current = (_b = state.isFocus) !== null && _b !== void 0 ? _b : false;
|
|
576
653
|
if (isKeyboardFullyShown !== keyboardVisibleRef.current) {
|
|
577
654
|
keyboardVisibleRef.current = isKeyboardFullyShown;
|
|
578
655
|
if (isKeyboardFullyShown && textInputRef.current) {
|
|
@@ -588,7 +665,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
|
|
|
588
665
|
CustomPopView,
|
|
589
666
|
CustomPopViewStyle,
|
|
590
667
|
forceRemoveAllRootViewOnItemSelected,
|
|
591
|
-
tag,
|
|
668
|
+
tag, TextInputProps,
|
|
592
669
|
state.selectedItem, showListEmptyComponent
|
|
593
670
|
]);
|
|
594
671
|
// Imperative handle for parent component access
|
|
@@ -601,7 +678,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
|
|
|
601
678
|
},
|
|
602
679
|
}), []);
|
|
603
680
|
const updateState = (key, value) => {
|
|
604
|
-
console.log('AutoPositionedPopup updateState
|
|
681
|
+
console.log('AutoPositionedPopup updateState=', { key, value });
|
|
605
682
|
setState((prevState) => (Object.assign(Object.assign({}, prevState), { [key]: value })));
|
|
606
683
|
if (key === 'selectedItem' && onItemSelected) {
|
|
607
684
|
onItemSelected(value);
|
|
@@ -616,6 +693,179 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
|
|
|
616
693
|
setSearchQuery('');
|
|
617
694
|
}
|
|
618
695
|
};
|
|
696
|
+
// Simple deep comparison function (for style objects only)
|
|
697
|
+
const shallowEqual = (obj1, obj2) => {
|
|
698
|
+
if (obj1 === obj2)
|
|
699
|
+
return true;
|
|
700
|
+
if (!obj1 || !obj2)
|
|
701
|
+
return false;
|
|
702
|
+
if (typeof obj1 !== 'object' || typeof obj2 !== 'object')
|
|
703
|
+
return false;
|
|
704
|
+
const keys1 = Object.keys(obj1);
|
|
705
|
+
const keys2 = Object.keys(obj2);
|
|
706
|
+
if (keys1.length !== keys2.length)
|
|
707
|
+
return false;
|
|
708
|
+
for (const key of keys1) {
|
|
709
|
+
if (obj1[key] !== obj2[key])
|
|
710
|
+
return false;
|
|
711
|
+
}
|
|
712
|
+
return true;
|
|
713
|
+
};
|
|
714
|
+
// Use useMemo to create stable props reference
|
|
715
|
+
// Only update when deep comparison detects real changes to avoid TextInput recreation due to reference changes during parent component redraws
|
|
716
|
+
const stableInputStyle = useMemo(() => {
|
|
717
|
+
if (!shallowEqual(stableInputStyleRef.current, inputStyle)) {
|
|
718
|
+
console.log(`AutoPositionedPopup inputStyle deep change detected, updating stable reference - tag: ${tag}`);
|
|
719
|
+
stableInputStyleRef.current = inputStyle;
|
|
720
|
+
}
|
|
721
|
+
return stableInputStyleRef.current;
|
|
722
|
+
}, [inputStyle, tag]);
|
|
723
|
+
const stableTextInputProps = useMemo(() => {
|
|
724
|
+
if (!shallowEqual(stableTextInputPropsRef.current, TextInputProps)) {
|
|
725
|
+
console.log(`AutoPositionedPopup TextInputProps deep change detected, updating stable reference - tag: ${tag}`);
|
|
726
|
+
stableTextInputPropsRef.current = TextInputProps;
|
|
727
|
+
}
|
|
728
|
+
return stableTextInputPropsRef.current;
|
|
729
|
+
}, [TextInputProps, tag]);
|
|
730
|
+
// Use useCallback to stabilize onFocus and onBlur callback references
|
|
731
|
+
// Prevent creating new callback functions during parent component redraws to avoid TextInput re-triggering focus
|
|
732
|
+
// Use ref to store latest state values to avoid adding frequently changing values to dependencies
|
|
733
|
+
const stateRef = useRef(state);
|
|
734
|
+
stateRef.current = state;
|
|
735
|
+
const handleTextInputFocus = useCallback(() => {
|
|
736
|
+
const currentTime = Date.now();
|
|
737
|
+
const timeSinceLastFocus = currentTime - lastFocusTimeRef.current;
|
|
738
|
+
console.log('AutoPositionedPopup onFocus=', {
|
|
739
|
+
tag,
|
|
740
|
+
'state.selectedItem': stateRef.current.selectedItem,
|
|
741
|
+
'hasTriggeredFocus.current=': hasTriggeredFocus.current,
|
|
742
|
+
'textInputRef.current=': textInputRef.current,
|
|
743
|
+
'ref_searchQuery.current=': ref_searchQuery.current,
|
|
744
|
+
'timeSinceLastFocus': timeSinceLastFocus,
|
|
745
|
+
'isKeyboardFullyShown': isKeyboardFullyShown,
|
|
746
|
+
'isFocusEventProcessing': isFocusEventProcessingRef.current
|
|
747
|
+
});
|
|
748
|
+
// Prevent rapid repeated triggers (repeated events within 300ms are ignored)
|
|
749
|
+
if (timeSinceLastFocus < 300) {
|
|
750
|
+
console.log('AutoPositionedPopup onFocus: Skip - event triggered too quickly (< 300ms)');
|
|
751
|
+
return;
|
|
752
|
+
}
|
|
753
|
+
// Skip if keyboard is already open and focus has been handled
|
|
754
|
+
if (isKeyboardFullyShown && hasTriggeredFocus.current) {
|
|
755
|
+
console.log('AutoPositionedPopup onFocus: Skip - keyboard already open and focus handled');
|
|
756
|
+
return;
|
|
757
|
+
}
|
|
758
|
+
// Prevent concurrent processing
|
|
759
|
+
if (isFocusEventProcessingRef.current) {
|
|
760
|
+
console.log('AutoPositionedPopup onFocus: Skip - processing another focus event');
|
|
761
|
+
return;
|
|
762
|
+
}
|
|
763
|
+
isFocusEventProcessingRef.current = true;
|
|
764
|
+
lastFocusTimeRef.current = currentTime;
|
|
765
|
+
if (!hasTriggeredFocus.current) {
|
|
766
|
+
hasTriggeredFocus.current = true;
|
|
767
|
+
ref_isFocus.current = true;
|
|
768
|
+
if (stateRef.current.selectedItem) {
|
|
769
|
+
ref_searchQuery.current = stateRef.current.selectedItem.title;
|
|
770
|
+
}
|
|
771
|
+
if (textInputRef.current && ref_searchQuery.current) {
|
|
772
|
+
textInputRef.current.setNativeProps({
|
|
773
|
+
text: ref_searchQuery.current,
|
|
774
|
+
});
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
// Delay resetting processing flag to avoid blocking subsequent legitimate focus events
|
|
778
|
+
setTimeout(() => {
|
|
779
|
+
isFocusEventProcessingRef.current = false;
|
|
780
|
+
}, 100);
|
|
781
|
+
}, [tag, isKeyboardFullyShown]); // Remove state.selectedItem, use stateRef instead
|
|
782
|
+
const handleTextInputBlur = useCallback(() => {
|
|
783
|
+
console.log('AutoPositionedPopup onBlur=', {
|
|
784
|
+
tag,
|
|
785
|
+
'textInputRef.current': textInputRef.current,
|
|
786
|
+
'isKeyboardFullyShown': isKeyboardFullyShown,
|
|
787
|
+
'hasTriggeredFocus.current': hasTriggeredFocus.current
|
|
788
|
+
});
|
|
789
|
+
// If keyboard is still open, this is a false trigger caused by parent component re-render, should not reset
|
|
790
|
+
if (isKeyboardFullyShown && hasTriggeredFocus.current) {
|
|
791
|
+
console.log('AutoPositionedPopup onBlur: Skip - keyboard still open, possibly caused by parent component re-render');
|
|
792
|
+
return;
|
|
793
|
+
}
|
|
794
|
+
// Only reset internal state, do not actively close keyboard
|
|
795
|
+
// Keyboard will close naturally when TextInput loses focus, no need to manually call Keyboard.dismiss()
|
|
796
|
+
hasTriggeredFocus.current = false;
|
|
797
|
+
hasAddedRootView.current = false;
|
|
798
|
+
hasShownRootView.current = false;
|
|
799
|
+
ref_isFocus.current = false;
|
|
800
|
+
setState((prevState) => {
|
|
801
|
+
return Object.assign(Object.assign({}, prevState), { isFocus: false });
|
|
802
|
+
});
|
|
803
|
+
removeRootView(tag, forceRemoveAllRootViewOnItemSelected);
|
|
804
|
+
setSearchQuery('');
|
|
805
|
+
if (textInputRef.current) {
|
|
806
|
+
textInputRef.current.setNativeProps({ text: '' });
|
|
807
|
+
ref_searchQuery.current = '';
|
|
808
|
+
// Remove textInputRef.current.blur() - avoid forcing blur causing keyboard to close
|
|
809
|
+
}
|
|
810
|
+
// Remove Keyboard.dismiss() - let keyboard close naturally to avoid triggering keyboardDidHide event
|
|
811
|
+
}, [tag, isKeyboardFullyShown, forceRemoveAllRootViewOnItemSelected]);
|
|
812
|
+
// Wrap TextInput independently in useMemo to recreate only when key props change
|
|
813
|
+
// This avoids repeated ref callback triggers due to other props changes during parent component redraws
|
|
814
|
+
const memoizedTextInput = useMemo(() => {
|
|
815
|
+
console.log(`AutoPositionedPopup useMemo creating TextInput - tag: ${tag}, isFocus: ${state.isFocus}`);
|
|
816
|
+
if (!useTextInput || !state.isFocus) {
|
|
817
|
+
return null;
|
|
818
|
+
}
|
|
819
|
+
return (<RNTextInput ref={(ref) => {
|
|
820
|
+
// Monitor TextInput mounting and unmounting
|
|
821
|
+
if (ref && !textInputRef.current) {
|
|
822
|
+
console.log(`AutoPositionedPopup TextInput created/mounted - tag: ${tag}, ref:`, ref);
|
|
823
|
+
}
|
|
824
|
+
else if (!ref && textInputRef.current) {
|
|
825
|
+
console.log(`AutoPositionedPopup TextInput unmounted - tag: ${tag}`);
|
|
826
|
+
}
|
|
827
|
+
else if (ref && textInputRef.current && ref !== textInputRef.current) {
|
|
828
|
+
console.log(`AutoPositionedPopup TextInput replaced - tag: ${tag}, oldRef:`, textInputRef.current, 'newRef:', ref);
|
|
829
|
+
}
|
|
830
|
+
textInputRef.current = ref;
|
|
831
|
+
}} key={`textinput-${tag}`} style={[
|
|
832
|
+
styles.inputStyle,
|
|
833
|
+
stableInputStyle,
|
|
834
|
+
]} textAlign={stableTextInputProps['textAlign'] || 'left'} multiline={stableTextInputProps['multiline'] || false} numberOfLines={stableTextInputProps['numberOfLines'] || 1} onChangeText={(searchQuery) => {
|
|
835
|
+
ref_searchQuery.current = searchQuery;
|
|
836
|
+
console.log('AutoPositionedPopup onChangeText rootViews=', rootViews);
|
|
837
|
+
if (!localSearch) {
|
|
838
|
+
if (debounceTimerRef.current) {
|
|
839
|
+
clearTimeout(debounceTimerRef.current);
|
|
840
|
+
}
|
|
841
|
+
debounceTimerRef.current = setTimeout(() => {
|
|
842
|
+
emitQueryChange(ref_searchQuery.current);
|
|
843
|
+
}, 500);
|
|
844
|
+
}
|
|
845
|
+
else {
|
|
846
|
+
emitQueryChange(ref_searchQuery.current);
|
|
847
|
+
}
|
|
848
|
+
}} placeholderTextColor={theme.colors.placeholderText} placeholder={placeholder} onKeyPress={(e) => {
|
|
849
|
+
if (e.nativeEvent.key === 'Enter') {
|
|
850
|
+
Keyboard.dismiss();
|
|
851
|
+
}
|
|
852
|
+
}} keyboardType={stableTextInputProps['keyboardType'] || 'default'} clearButtonMode="while-editing" returnKeyType={stableTextInputProps['returnKeyType'] || 'done'} maxLength={stableTextInputProps['maxLength'] || 100} accessibilityLabel="selectInput" accessible={true} autoFocus={stableTextInputProps['autoFocus'] || false} autoCorrect={false} underlineColorAndroid="transparent" editable={stableTextInputProps['editable'] || true} secureTextEntry={stableTextInputProps['secureTextEntry'] || false} defaultValue="" caretHidden={false} enablesReturnKeyAutomatically onFocus={handleTextInputFocus} onBlur={handleTextInputBlur} selectTextOnFocus={stableTextInputProps['selectTextOnFocus'] || false} onSubmitEditing={(e) => {
|
|
853
|
+
console.log('AutoPositionedPopup.tsx onSubmitEditing e.nativeEvent.text=', e.nativeEvent.text);
|
|
854
|
+
onSubmitEditing && onSubmitEditing(e);
|
|
855
|
+
}}/>);
|
|
856
|
+
}, [
|
|
857
|
+
tag, // tag 是稳定的
|
|
858
|
+
useTextInput, // useTextInput 是稳定的
|
|
859
|
+
state.isFocus, // isFocus 控制显示/隐藏
|
|
860
|
+
handleTextInputFocus, // useCallback wrapped, reference stable
|
|
861
|
+
handleTextInputBlur, // useCallback wrapped, reference stable
|
|
862
|
+
stableInputStyle, // Use stable inputStyle reference (after deep comparison)
|
|
863
|
+
stableTextInputProps, // Use stable TextInputProps reference (after deep comparison)
|
|
864
|
+
placeholder, // placeholder usually stable
|
|
865
|
+
onSubmitEditing, // onSubmitEditing usually stable
|
|
866
|
+
// No longer use original inputStyle and TextInputProps, use stable references instead
|
|
867
|
+
// Stable references only update when deep comparison detects actual content changes, avoiding frequent TextInput recreation during parent component redraws
|
|
868
|
+
]);
|
|
619
869
|
// Render the component following project implementation
|
|
620
870
|
return useMemo(() => {
|
|
621
871
|
var _a;
|
|
@@ -623,17 +873,20 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
|
|
|
623
873
|
return (<CustomRow>
|
|
624
874
|
<View style={[styles.contain, style]} ref={refAutoPositionedPopup}>
|
|
625
875
|
{!state.isFocus || !useTextInput ? (<TouchableOpacity style={[styles.AutoPositionedPopupBtn, AutoPositionedPopupBtnStyle]} disabled={AutoPositionedPopupBtnDisabled} onPress={() => {
|
|
626
|
-
console.log('AutoPositionedPopup onPress
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
876
|
+
console.log('AutoPositionedPopup onPress=', {
|
|
877
|
+
tag,
|
|
878
|
+
'state.isFocus': state.isFocus,
|
|
879
|
+
useTextInput,
|
|
880
|
+
'hasAddedRootView.current': hasAddedRootView.current,
|
|
881
|
+
'hasShownRootView.current': hasShownRootView.current,
|
|
882
|
+
'hasTriggeredFocus.current': hasTriggeredFocus.current,
|
|
883
|
+
'state.selectedItem': state.selectedItem
|
|
884
|
+
});
|
|
633
885
|
setState((prevState) => {
|
|
634
886
|
return Object.assign(Object.assign({}, prevState), { isFocus: true });
|
|
635
887
|
});
|
|
636
888
|
if (!hasAddedRootView.current && useTextInput) {
|
|
889
|
+
// TextInput version: hide first, show after keyboard is fully displayed
|
|
637
890
|
hasAddedRootView.current = true;
|
|
638
891
|
hasShownRootView.current = false;
|
|
639
892
|
addRootView({
|
|
@@ -649,6 +902,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
|
|
|
649
902
|
useModal: false,
|
|
650
903
|
});
|
|
651
904
|
}
|
|
905
|
+
console.log('AutoPositionedPopup onPress done');
|
|
652
906
|
}}>
|
|
653
907
|
{!btwChildren ? (<Text style={[
|
|
654
908
|
styles.searchQueryTxt,
|
|
@@ -657,87 +911,36 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
|
|
|
657
911
|
]} numberOfLines={1} ellipsizeMode={'tail'}>
|
|
658
912
|
{((_a = state.selectedItem) === null || _a === void 0 ? void 0 : _a.title) || placeholder}
|
|
659
913
|
</Text>) : (btwChildren())}
|
|
660
|
-
</TouchableOpacity>) : (
|
|
661
|
-
state.isFocus && (<RNTextInput ref={textInputRef} key="fixed-textinput-key" style={[
|
|
662
|
-
styles.inputStyle,
|
|
663
|
-
inputStyle,
|
|
664
|
-
]} textAlign={TextInputProps['textAlign'] || 'left'} multiline={TextInputProps['multiline'] || false} numberOfLines={TextInputProps['numberOfLines'] || 1} onChangeText={(searchQuery) => {
|
|
665
|
-
ref_searchQuery.current = searchQuery;
|
|
666
|
-
console.log('AutoPositionedPopup onChangeText rootViews=', rootViews);
|
|
667
|
-
if (!localSearch) {
|
|
668
|
-
if (debounceTimerRef.current) {
|
|
669
|
-
clearTimeout(debounceTimerRef.current);
|
|
670
|
-
}
|
|
671
|
-
debounceTimerRef.current = setTimeout(() => {
|
|
672
|
-
emitQueryChange(ref_searchQuery.current);
|
|
673
|
-
}, 500);
|
|
674
|
-
}
|
|
675
|
-
else {
|
|
676
|
-
emitQueryChange(ref_searchQuery.current);
|
|
677
|
-
}
|
|
678
|
-
}} placeholderTextColor={theme.colors.placeholderText} placeholder={placeholder} onKeyPress={(e) => {
|
|
679
|
-
if (e.nativeEvent.key === 'Enter') {
|
|
680
|
-
Keyboard.dismiss();
|
|
681
|
-
}
|
|
682
|
-
}} keyboardType={TextInputProps['keyboardType'] || 'default'} clearButtonMode="while-editing" returnKeyType={TextInputProps['returnKeyType'] || 'done'} maxLength={TextInputProps['maxLength'] || 100} accessibilityLabel="selectInput" accessible={true} autoFocus={TextInputProps['autoFocus'] || false} autoCorrect={false} underlineColorAndroid="transparent" editable={TextInputProps['editable'] || true} secureTextEntry={TextInputProps['secureTextEntry'] || false} defaultValue="" caretHidden={false} enablesReturnKeyAutomatically onFocus={() => {
|
|
683
|
-
console.log('AutoPositionedPopup onFocus tag=', tag, ' selectedItem=', state.selectedItem, ' hasTriggeredFocus.current=', hasTriggeredFocus.current, ' textInputRef.current=', textInputRef.current, ' ref_searchQuery.current=', ref_searchQuery.current);
|
|
684
|
-
if (!hasTriggeredFocus.current) {
|
|
685
|
-
hasTriggeredFocus.current = true;
|
|
686
|
-
ref_isFocus.current = true;
|
|
687
|
-
if (state.selectedItem) {
|
|
688
|
-
ref_searchQuery.current = state.selectedItem.title;
|
|
689
|
-
}
|
|
690
|
-
if (textInputRef.current && ref_searchQuery.current) {
|
|
691
|
-
textInputRef.current.setNativeProps({
|
|
692
|
-
text: ref_searchQuery.current,
|
|
693
|
-
});
|
|
694
|
-
}
|
|
695
|
-
}
|
|
696
|
-
}} onBlur={() => {
|
|
697
|
-
console.log('AutoPositionedPopup onBlur tag=', tag, 'textInputRef.current=', textInputRef.current);
|
|
698
|
-
hasTriggeredFocus.current = false;
|
|
699
|
-
hasAddedRootView.current = false; // 重置 RootView 狀態
|
|
700
|
-
hasShownRootView.current = false;
|
|
701
|
-
ref_isFocus.current = false;
|
|
702
|
-
setState((prevState) => {
|
|
703
|
-
return Object.assign(Object.assign({}, prevState), { isFocus: false });
|
|
704
|
-
});
|
|
705
|
-
removeRootView(tag, forceRemoveAllRootViewOnItemSelected);
|
|
706
|
-
setSearchQuery('');
|
|
707
|
-
if (textInputRef.current) {
|
|
708
|
-
textInputRef.current.setNativeProps({ text: '' });
|
|
709
|
-
ref_searchQuery.current = '';
|
|
710
|
-
textInputRef.current.blur();
|
|
711
|
-
}
|
|
712
|
-
Keyboard.dismiss();
|
|
713
|
-
}} selectTextOnFocus={TextInputProps['selectTextOnFocus'] || false} onSubmitEditing={(e) => {
|
|
714
|
-
console.log('AutoPositionedPopup.tsx onSubmitEditing e.nativeEvent.text=', e.nativeEvent.text);
|
|
715
|
-
onSubmitEditing && onSubmitEditing(e);
|
|
716
|
-
}}/>))}
|
|
914
|
+
</TouchableOpacity>) : (memoizedTextInput)}
|
|
717
915
|
</View>
|
|
718
916
|
</CustomRow>);
|
|
719
|
-
}, [
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
917
|
+
}, [
|
|
918
|
+
tag,
|
|
919
|
+
// ✅ CRITICAL FIX: Remove all props that may change frequently or are inline functions
|
|
920
|
+
// Changes to these props should not cause the entire component tree to recreate, especially TextInput
|
|
921
|
+
// fetchData, // ❌ Removed: inline function
|
|
922
|
+
// renderItem, // ❌ Removed: possibly inline function
|
|
923
|
+
// onItemSelected, // ❌ Removed: possibly inline function
|
|
924
|
+
// onSubmitEditing, // ❌ Removed: possibly inline function
|
|
724
925
|
localSearch,
|
|
725
|
-
placeholder,
|
|
726
|
-
textAlign,
|
|
926
|
+
// placeholder, // ❌ Removed: may change
|
|
927
|
+
// textAlign, // ❌ Removed: may change
|
|
727
928
|
pageSize,
|
|
728
929
|
selectedItem,
|
|
729
|
-
CustomRow,
|
|
930
|
+
// CustomRow, // ❌ Removed: inline function, new reference each time
|
|
730
931
|
useTextInput,
|
|
731
|
-
btwChildren,
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
CustomPopViewStyle,
|
|
932
|
+
// btwChildren, // ❌ Removed: inline function
|
|
933
|
+
// keyExtractor, // ❌ Removed: possibly inline function
|
|
934
|
+
// AutoPositionedPopupBtnStyle, // ❌ Removed: possibly inline object
|
|
935
|
+
// CustomPopView, // ❌ Removed: may change
|
|
936
|
+
// CustomPopViewStyle, // ❌ Removed: may change
|
|
737
937
|
forceRemoveAllRootViewOnItemSelected,
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
938
|
+
state.isFocus,
|
|
939
|
+
showListEmptyComponent,
|
|
940
|
+
emptyText,
|
|
941
|
+
// ✅ Removed most dependencies that may cause re-rendering, keeping only core dependencies that truly affect component structure
|
|
942
|
+
// This prevents TextInput recreation due to inline functions/objects during parent component redraws
|
|
943
|
+
]);
|
|
741
944
|
}));
|
|
742
945
|
export default AutoPositionedPopup;
|
|
743
946
|
//# sourceMappingURL=AutoPositionedPopup.js.map
|