react-native-auto-positioned-popup 1.2.13 → 1.2.16

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.
@@ -1,12 +1,13 @@
1
+ import { debugLog } from './constants';
1
2
  import React, { forwardRef, memo, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState, } from 'react';
2
- import { Dimensions, Keyboard, Platform, StatusBar, Text, TextInput as RNTextInput, TouchableOpacity, View, } from 'react-native';
3
+ import { Dimensions, findNodeHandle, Keyboard, Platform, StatusBar, Text, TextInput as RNTextInput, TouchableOpacity, View, } from 'react-native';
3
4
  import { AdvancedFlatList } from 'react-native-advanced-flatlist';
4
5
  import styles from './AutoPositionedPopup.style';
5
6
  import { useRootView } from './RootViewContext';
6
7
  import { useKeyboardStatus } from './KeyboardManager';
7
8
  const queryChangeListeners = [];
8
9
  const emitQueryChange = (query) => {
9
- console.log('AutoPositionedPopup.tsx emitQueryChange query=', query, ' listeners=', queryChangeListeners.length);
10
+ debugLog('AutoPositionedPopup.tsx emitQueryChange query=', query, ' listeners=', queryChangeListeners.length);
10
11
  queryChangeListeners.forEach((l) => l(query));
11
12
  };
12
13
  const subscribeQueryChange = (listener) => {
@@ -34,14 +35,14 @@ const ListItem = memo(({ updateState, item, index, selectedItem, themeMode }) =>
34
35
  rootViewsRef.current = rootViews;
35
36
  }, [rootViews]);
36
37
  return useMemo(() => {
37
- // console.log('AutoPositionedPopup.tsx ListItem=', {index, item, selectedItem});
38
+ // debugLog('AutoPositionedPopup.tsx ListItem=', {index, item, selectedItem});
38
39
  const isSelected = item.id === (selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.id) || item.title == (selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.title);
39
40
  return (<TouchableOpacity key={item.id} style={[
40
41
  styles.commonModalRow,
41
42
  { backgroundColor: isSelected ? (themeMode === 'light' ? 'rgba(116, 116, 128, 0.08)' : 'rgba(120, 120, 128, 0.36)') : 'transparent' },
42
43
  ]} onPress={() => {
43
- // console.log('AutoPositionedPopup.tsx ListItem onPress item=', item); // Commented to prevent spam
44
- // console.log('AutoPositionedPopup.tsx ListItem onPress rootViews=', rootViewsRef.current); // Commented to prevent spam
44
+ // debugLog('AutoPositionedPopup.tsx ListItem onPress item=', item); // Commented to prevent spam
45
+ // debugLog('AutoPositionedPopup.tsx ListItem onPress rootViews=', rootViewsRef.current); // Commented to prevent spam
45
46
  updateState('selectedItem', item);
46
47
  }}>
47
48
  <Text style={(themeMode === 'light' ? styles.ListItemCode : Object.assign(Object.assign({}, styles.ListItemCode), { color: '#fff' }))} numberOfLines={1} ellipsizeMode="tail">
@@ -69,16 +70,16 @@ const AutoPositionedPopupList = memo(({ tag, updateState, fetchData, keyExtracto
69
70
  useEffect(() => {
70
71
  (async () => {
71
72
  })();
72
- console.log(`AutoPositionedPopupList componentDidMount`);
73
+ debugLog(`AutoPositionedPopupList componentDidMount`);
73
74
  //componentWillUnmount
74
75
  return () => {
75
- console.log(`AutoPositionedPopupList componentWillUnmount`);
76
+ debugLog(`AutoPositionedPopupList componentWillUnmount`);
76
77
  setSearchQuery('');
77
78
  };
78
79
  }, []);
79
80
  useEffect(() => {
80
81
  const unsubscribe = subscribeQueryChange((newQuery) => {
81
- console.log('AutoPositionedPopupList useEffect subscribeQueryChange newQuery=', newQuery);
82
+ debugLog('AutoPositionedPopupList useEffect subscribeQueryChange newQuery=', newQuery);
82
83
  ref_searchQuery.current = newQuery;
83
84
  if (ref_list.current) {
84
85
  ref_list.current.scrollToTop();
@@ -88,19 +89,19 @@ const AutoPositionedPopupList = memo(({ tag, updateState, fetchData, keyExtracto
88
89
  return unsubscribe;
89
90
  }, []);
90
91
  const _updateState = (key, value) => {
91
- console.log('AutoPositionedPopupList _updateState key=', key, ' value=', value);
92
+ debugLog('AutoPositionedPopupList _updateState key=', key, ' value=', value);
92
93
  setState((prevState) => (Object.assign(Object.assign({}, prevState), { [key]: value })));
93
- console.log('AutoPositionedPopupList _updateState rootViews=', rootViewsRef.current);
94
+ debugLog('AutoPositionedPopupList _updateState rootViews=', rootViewsRef.current);
94
95
  updateState(key, value);
95
96
  };
96
97
  const _fetchData = async ({ pageIndex, pageSize: currentPageSize, }) => {
97
- console.log('AutoPositionedPopupList _fetchData=', { pageIndex, pageSize: currentPageSize, 'state.localData': state.localData, 'ref_searchQuery.current': ref_searchQuery.current, localSearch });
98
+ debugLog('AutoPositionedPopupList _fetchData=', { pageIndex, pageSize: currentPageSize, 'state.localData': state.localData, 'ref_searchQuery.current': ref_searchQuery.current, localSearch });
98
99
  if (localSearch && state.localData.length > 0) {
99
100
  const result = state.localData.filter((item) => {
100
101
  var _a;
101
102
  return (_a = `${item.title}`) === null || _a === void 0 ? void 0 : _a.toLowerCase().includes(ref_searchQuery.current.toLowerCase());
102
103
  });
103
- console.log('AutoPositionedPopupList _fetchData localSearch result=', result);
104
+ debugLog('AutoPositionedPopupList _fetchData localSearch result=', result);
104
105
  return Promise.resolve({
105
106
  items: result,
106
107
  pageIndex: 0,
@@ -113,7 +114,7 @@ const AutoPositionedPopupList = memo(({ tag, updateState, fetchData, keyExtracto
113
114
  pageSize: pageSize || 10,
114
115
  searchQuery: ref_searchQuery.current,
115
116
  });
116
- console.log('AutoPositionedPopupList _fetchData res=', res);
117
+ debugLog('AutoPositionedPopupList _fetchData res=', res);
117
118
  if ((res === null || res === void 0 ? void 0 : res.items) && localSearch) {
118
119
  setState((prevState) => {
119
120
  return Object.assign(Object.assign({}, prevState), { localData: res.items });
@@ -132,14 +133,14 @@ const AutoPositionedPopupList = memo(({ tag, updateState, fetchData, keyExtracto
132
133
  catch (e) {
133
134
  console.warn('Error in fetchData:', e);
134
135
  }
135
- console.log('AutoPositionedPopupList _fetchData res=', null);
136
+ debugLog('AutoPositionedPopupList _fetchData res=', null);
136
137
  return null;
137
138
  };
138
139
  const _renderItem = useCallback(({ item, index }) => {
139
140
  return <ListItem item={item} index={index} updateState={_updateState} selectedItem={state.selectedItem} themeMode={themeMode}/>;
140
141
  }, [state.selectedItem, themeMode]);
141
142
  return useMemo(() => {
142
- console.log('AutoPositionedPopupList (global as any)?.$fake=', global === null || global === void 0 ? void 0 : global.$fake);
143
+ debugLog('AutoPositionedPopupList (global as any)?.$fake=', global === null || global === void 0 ? void 0 : global.$fake);
143
144
  // Babel configuration handles the path redirection based on global.$fake
144
145
  // No need for conditional import here
145
146
  return (<View style={[styles.baseModalView, styles.autoPositionedPopupList, { backgroundColor: themeMode === 'light' ? '#fff' : 'rgba(44, 44, 46, 1)', }]}>
@@ -164,7 +165,7 @@ const listLayout = {
164
165
  };
165
166
  // Main AutoPositionedPopup component
166
167
  const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
167
- console.log('AutoPositionedPopup props=', props);
168
+ debugLog('AutoPositionedPopup props=', props);
168
169
  const { tag, style, AutoPositionedPopupBtnStyle, placeholder = 'Please Select', onSubmitEditing, TextInputProps, //= {autoFocus: true},
169
170
  inputStyle, labelStyle, popUpViewStyle = { left: '5%', width: '90%' }, fetchData = async ({ pageIndex, pageSize, searchQuery, }) => {
170
171
  const res = {
@@ -174,7 +175,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
174
175
  };
175
176
  try {
176
177
  // const res1: any[] = await $api.xxx(pageSize)
177
- // console.log('${NAME} xxx res=', res)
178
+ // debugLog('${NAME} xxx res=', res)
178
179
  // res.items = res1
179
180
  // res.needLoadMore = res1.length === pageSize
180
181
  }
@@ -184,7 +185,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
184
185
  return res;
185
186
  }, renderItem, onItemSelected, localSearch = false, pageSize = 20, selectedItem, useTextInput = false, btwChildren, CustomRow = ({ children }) => <View>{children}</View>, keyExtractor = (item) => String((item === null || item === void 0 ? void 0 : item.id) || ''), AutoPositionedPopupBtnDisabled = false, forceRemoveAllRootViewOnItemSelected = false, centerDisplay = false, selectedItemBackgroundColor = 'rgba(116, 116, 128, 0.08)',
186
187
  // textAlign = 'right',
187
- CustomPopView = undefined, CustomPopViewStyle, showListEmptyComponent = true, emptyText = '', onChangeText, themeMode = 'light', } = props;
188
+ CustomPopView = undefined, CustomPopViewStyle, showListEmptyComponent = true, emptyText = '', onChangeText, themeMode = 'light', parentScrollViewRef, scrollExtraHeight = 100, } = props;
188
189
  // State management similar to project implementation
189
190
  const [state, setState] = useState({
190
191
  isFocus: false,
@@ -203,6 +204,8 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
203
204
  const keyboardVisibleRef = useRef(false);
204
205
  const refAutoPositionedPopup = useRef(null);
205
206
  const ref_searchQuery = useRef('');
207
+ // Store trigger button position when clicked (before it's replaced by TextInput)
208
+ const triggerPositionRef = useRef(null);
206
209
  // Add ref to track previous keyboard state to avoid false triggers during parent component re-renders
207
210
  const prevIsKeyboardFullyShownRef = useRef(false);
208
211
  const prevPropsRef = useRef({});
@@ -235,16 +238,136 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
235
238
  ref_isKeyboardFullyShown.current = isKeyboardFullyShown;
236
239
  }, [isKeyboardFullyShown]);
237
240
  const theme = defaultTheme;
241
+ /**
242
+ * Scrolls the parent KeyboardAwareScrollView to make the trigger button visible
243
+ * when keyboard appears and may cover the trigger.
244
+ * Uses the triggerBtnRef to measure position and scrolls parent accordingly.
245
+ */
246
+ const scrollParentToTrigger = useCallback(() => {
247
+ if (!(parentScrollViewRef === null || parentScrollViewRef === void 0 ? void 0 : parentScrollViewRef.current) || !triggerBtnRef.current) {
248
+ debugLog('AutoPositionedPopup scrollParentToTrigger: No parentScrollViewRef or triggerBtnRef available');
249
+ return;
250
+ }
251
+ // Use scrollToFocusedInput method from KeyboardAwareScrollView
252
+ // This method scrolls the ScrollView to make the specified node visible
253
+ const scrollView = parentScrollViewRef.current;
254
+ const nodeHandle = findNodeHandle(triggerBtnRef.current);
255
+ if (nodeHandle && scrollView) {
256
+ debugLog('AutoPositionedPopup scrollParentToTrigger: Scrolling to trigger button with extraHeight=', scrollExtraHeight);
257
+ // KeyboardAwareScrollView has a scrollToFocusedInput method that handles this
258
+ // However, it requires a ReactNode. We'll use scrollToPosition as an alternative.
259
+ // First, measure the trigger button position relative to the ScrollView
260
+ triggerBtnRef.current.measureInWindow((x, y, width, height) => {
261
+ if (y === undefined || height === undefined) {
262
+ debugLog('AutoPositionedPopup scrollParentToTrigger: measureInWindow returned undefined');
263
+ return;
264
+ }
265
+ debugLog('AutoPositionedPopup scrollParentToTrigger: trigger position=', { x, y, width, height });
266
+ // Get keyboard height from Keyboard API
267
+ // On keyboard show, scroll to position that keeps trigger above keyboard
268
+ Keyboard.addListener('keyboardDidShow', (event) => {
269
+ const keyboardHeight = event.endCoordinates.height;
270
+ const screenHeight = Dimensions.get('window').height;
271
+ // Calculate if trigger is below keyboard
272
+ const triggerBottom = y + height;
273
+ const visibleAreaBottom = screenHeight - keyboardHeight;
274
+ debugLog('AutoPositionedPopup scrollParentToTrigger: keyboard data=', {
275
+ keyboardHeight,
276
+ screenHeight,
277
+ triggerBottom,
278
+ visibleAreaBottom,
279
+ needsScroll: triggerBottom > visibleAreaBottom
280
+ });
281
+ if (triggerBottom > visibleAreaBottom) {
282
+ // Calculate how much to scroll
283
+ const scrollAmount = triggerBottom - visibleAreaBottom + scrollExtraHeight;
284
+ debugLog('AutoPositionedPopup scrollParentToTrigger: scrolling by', scrollAmount);
285
+ // Use scrollForExtraHeightOnAndroid or scrollToPosition
286
+ if (typeof scrollView.scrollToPosition === 'function') {
287
+ // scrollToPosition(x, y, animated)
288
+ scrollView.scrollToPosition(0, scrollAmount, true);
289
+ }
290
+ else if (typeof scrollView.scrollToEnd === 'function') {
291
+ // Fallback: scroll to end might help in some cases
292
+ debugLog('AutoPositionedPopup scrollParentToTrigger: using scrollToEnd fallback');
293
+ }
294
+ }
295
+ });
296
+ });
297
+ }
298
+ }, [parentScrollViewRef, scrollExtraHeight]);
299
+ /**
300
+ * Scroll parent KeyboardAwareScrollView to keep trigger visible above keyboard
301
+ * Uses stored trigger position (captured before TextInput replaces the trigger button)
302
+ */
303
+ const scrollToTriggerWithMeasure = useCallback(() => {
304
+ debugLog('AutoPositionedPopup scrollToTriggerWithMeasure called, tag=', tag, {
305
+ hasParentScrollViewRef: !!(parentScrollViewRef === null || parentScrollViewRef === void 0 ? void 0 : parentScrollViewRef.current),
306
+ hasTriggerPosition: !!triggerPositionRef.current,
307
+ triggerPosition: triggerPositionRef.current
308
+ });
309
+ if (!(parentScrollViewRef === null || parentScrollViewRef === void 0 ? void 0 : parentScrollViewRef.current)) {
310
+ debugLog('AutoPositionedPopup scrollToTriggerWithMeasure: parentScrollViewRef not available, tag=', tag);
311
+ return;
312
+ }
313
+ // Use stored trigger position (captured when trigger was clicked)
314
+ const storedPosition = triggerPositionRef.current;
315
+ if (!storedPosition) {
316
+ debugLog('AutoPositionedPopup scrollToTriggerWithMeasure: no stored trigger position, tag=', tag);
317
+ return;
318
+ }
319
+ const scrollView = parentScrollViewRef.current;
320
+ const { y: triggerY, height: triggerHeight } = storedPosition;
321
+ // Get keyboard height and screen dimensions
322
+ const screenHeight = Dimensions.get('window').height;
323
+ // Calculate keyboard height (approximate - keyboard typically takes 40-50% of screen on Android)
324
+ // We'll use the trigger position to determine if scrolling is needed
325
+ const keyboardApproxHeight = screenHeight * 0.4; // Conservative estimate
326
+ const visibleAreaBottom = screenHeight - keyboardApproxHeight;
327
+ const triggerBottom = triggerY + triggerHeight;
328
+ debugLog('AutoPositionedPopup scrollToTriggerWithMeasure: calculations=', {
329
+ tag,
330
+ triggerY,
331
+ triggerHeight,
332
+ triggerBottom,
333
+ screenHeight,
334
+ visibleAreaBottom,
335
+ needsScroll: triggerBottom > visibleAreaBottom
336
+ });
337
+ // Check if trigger is below the visible area (covered by keyboard)
338
+ if (triggerBottom > visibleAreaBottom) {
339
+ // Calculate scroll amount to bring trigger above keyboard
340
+ const scrollAmount = triggerBottom - visibleAreaBottom + scrollExtraHeight;
341
+ debugLog('AutoPositionedPopup scrollToTriggerWithMeasure: scrolling, amount=', scrollAmount, 'tag=', tag);
342
+ // Use scrollForExtraHeightOnAndroid for KeyboardAwareScrollView
343
+ if (typeof scrollView.scrollForExtraHeightOnAndroid === 'function') {
344
+ scrollView.scrollForExtraHeightOnAndroid(scrollAmount);
345
+ }
346
+ else if (typeof scrollView.scrollToPosition === 'function') {
347
+ scrollView.scrollToPosition(0, scrollAmount, true);
348
+ }
349
+ else if ('scrollTo' in scrollView && typeof scrollView.scrollTo === 'function') {
350
+ // Fallback to standard ScrollView method
351
+ scrollView.scrollTo({ y: scrollAmount, animated: true });
352
+ }
353
+ else {
354
+ debugLog('AutoPositionedPopup scrollToTriggerWithMeasure: no scroll method available on scrollView');
355
+ }
356
+ }
357
+ else {
358
+ debugLog('AutoPositionedPopup scrollToTriggerWithMeasure: trigger already visible, no scroll needed, tag=', tag);
359
+ }
360
+ }, [parentScrollViewRef, scrollExtraHeight, tag]);
238
361
  /**
239
362
  * componentDidMount && componentWillUnmount
240
363
  */
241
364
  useEffect(() => {
242
365
  (async () => {
243
366
  })();
244
- console.log(`AutoPositionedPopup componentDidMount=`, { tag, CustomPopView });
367
+ debugLog(`AutoPositionedPopup componentDidMount=`, { tag, CustomPopView });
245
368
  //componentWillUnmount
246
369
  return () => {
247
- console.log(`AutoPositionedPopup componentWillUnmount tag=`, tag);
370
+ debugLog(`AutoPositionedPopup componentWillUnmount tag=`, tag);
248
371
  removeRootView(tag, forceRemoveAllRootViewOnItemSelected, rootViewsRef.current);
249
372
  setSearchQuery('');
250
373
  if (textInputRef.current) {
@@ -257,7 +380,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
257
380
  };
258
381
  }, []);
259
382
  useEffect(() => {
260
- console.log('AutoPositionedPopup rootViews=', { tag, rootViews });
383
+ debugLog('AutoPositionedPopup rootViews=', { tag, rootViews });
261
384
  rootViewsRef.current = rootViews;
262
385
  if (rootViews.length === 0) {
263
386
  hasAddedRootView.current = false;
@@ -272,10 +395,10 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
272
395
  }, [rootViews]);
273
396
  useEffect(() => {
274
397
  var _a, _b;
275
- console.log('AutoPositionedPopup useEffect [selectedItem, state.selectedItem, tag]=', { tag, selectedItem, 'state.selectedItem': state.selectedItem });
276
- console.log('AutoPositionedPopup useEffect state.selectedItem=', state.selectedItem);
398
+ debugLog('AutoPositionedPopup useEffect [selectedItem, state.selectedItem, tag]=', { tag, selectedItem, 'state.selectedItem': state.selectedItem });
399
+ debugLog('AutoPositionedPopup useEffect state.selectedItem=', state.selectedItem);
277
400
  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)) {
278
- console.log('AutoPositionedPopup useEffect selectedItem!=state.selectedItem');
401
+ debugLog('AutoPositionedPopup useEffect selectedItem!=state.selectedItem');
279
402
  setState((prevState) => {
280
403
  return Object.assign(Object.assign({}, prevState), { selectedItem: selectedItem });
281
404
  });
@@ -288,7 +411,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
288
411
  const propsChanged = prevPropsRef.current.CustomPopView !== CustomPopView ||
289
412
  prevPropsRef.current.CustomPopViewStyle !== CustomPopViewStyle ||
290
413
  (prevPropsRef.current.TextInputProps !== TextInputProps && useTextInput);
291
- console.log('AutoPositionedPopup useEffect [isKeyboardFullyShown,\n' +
414
+ debugLog('AutoPositionedPopup useEffect [isKeyboardFullyShown,\n' +
292
415
  ' state.isFocus,\n' +
293
416
  ' useTextInput,\n' +
294
417
  ' CustomPopView,\n' +
@@ -320,7 +443,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
320
443
  };
321
444
  // Only execute logic when keyboard state actually changes or user actively operates
322
445
  if (!keyboardStateChanged && hasAddedRootView.current) {
323
- console.log('AutoPositionedPopup: Skip execution - parent component re-rendered but keyboard state unchanged textInputRef.current=', textInputRef.current);
446
+ debugLog('AutoPositionedPopup: Skip execution - parent component re-rendered but keyboard state unchanged textInputRef.current=', textInputRef.current);
324
447
  // if (!ref_isFocus.current) {
325
448
  // textInputRef.current?.focus()
326
449
  // }
@@ -342,6 +465,16 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
342
465
  const statusBarHeight = getStatusBarHeight();
343
466
  if (useTextInput) {
344
467
  if (isKeyboardFullyShown && hasAddedRootView.current && !hasShownRootView.current && state.isFocus) {
468
+ // KEYBOARD AVOIDANCE FIX: Scroll parent ScrollView to keep trigger visible
469
+ // When keyboard appears, the trigger button may be covered. If parentScrollViewRef
470
+ // is provided, scroll the parent to keep the trigger visible above the keyboard.
471
+ if (parentScrollViewRef === null || parentScrollViewRef === void 0 ? void 0 : parentScrollViewRef.current) {
472
+ debugLog('AutoPositionedPopup: Keyboard appeared, scrolling parent to keep trigger visible');
473
+ // Use a slight delay to ensure keyboard animation has started
474
+ setTimeout(() => {
475
+ scrollToTriggerWithMeasure();
476
+ }, 100);
477
+ }
345
478
  // CRITICAL FIX FOR KEYBOARD POSITION CALCULATION
346
479
  // Problem: When keyboard appears, the page shifts up but measureInWindow executes too early
347
480
  // Solution: Wait for keyboard animation (300ms) + use requestAnimationFrame for next render frame
@@ -361,7 +494,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
361
494
  const measureTarget = triggerBtnRef.current || refAutoPositionedPopup.current;
362
495
  measureTarget === null || measureTarget === void 0 ? void 0 : measureTarget.measureInWindow((x, y, width, height) => {
363
496
  var _a;
364
- console.log('AutoPositionedPopup useTextInput measureInWindow (after 300ms + RAF, layout stable)=', { x, y, width, height, usingTriggerRef: !!triggerBtnRef.current });
497
+ debugLog('AutoPositionedPopup useTextInput measureInWindow (after 300ms + RAF, layout stable)=', { x, y, width, height, usingTriggerRef: !!triggerBtnRef.current });
365
498
  // CRITICAL FIX: Handle undefined values from measureInWindow
366
499
  // This can happen during navigation transitions or when view is not yet mounted
367
500
  if (x === undefined || y === undefined || width === undefined || height === undefined) {
@@ -389,7 +522,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
389
522
  // we should directly use measureInWindow's y value without additional calculations
390
523
  // The popup container is at the same level as the page content
391
524
  const screenHeight = Dimensions.get('window').height; // Use window height, not screen
392
- console.log('AutoPositionedPopup useTextInput positioning data=', {
525
+ debugLog('AutoPositionedPopup useTextInput positioning data=', {
393
526
  screenHeight,
394
527
  componentY: y,
395
528
  componentHeight: height,
@@ -401,26 +534,27 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
401
534
  // So we should NOT add statusBarHeight to the position calculation
402
535
  //
403
536
  // 1. Default: show popup ABOVE the input field
404
- // FIX: Use (y + height) as the trigger's bottom edge reference point
405
- // This compensates for measurement inaccuracies when trigger is inside complex layouts
406
- // Formula: popup_top = trigger_bottom - componentHeight - popupHeight
407
- let popupY = y + height - listLayout.height;
408
- console.log('AutoPositionedPopup with keyboard: initial calculation for ABOVE position:', {
537
+ // Position popup so that the trigger remains VISIBLE below the popup
538
+ // Use (y + height * 0.7) as reference to compensate for measurement offset
539
+ // while still leaving trigger visible (30% of trigger height exposed)
540
+ let popupY = y + (height * 0.7) - listLayout.height;
541
+ debugLog('AutoPositionedPopup with keyboard: initial calculation for ABOVE position:', {
409
542
  componentY: y,
410
543
  componentHeight: height,
411
544
  popupHeight: listLayout.height,
412
545
  popupY,
413
- triggerBottom: y + height,
546
+ popupBottom: popupY + listLayout.height,
547
+ triggerTop: y,
414
548
  statusBarHeight
415
549
  });
416
550
  // 2. Check if showing above would go behind status bar
417
551
  if (popupY < statusBarHeight) {
418
- console.log('AutoPositionedPopup with keyboard: would go behind status bar, showing BELOW instead');
552
+ debugLog('AutoPositionedPopup with keyboard: would go behind status bar, showing BELOW instead');
419
553
  // Show BELOW the input field
420
554
  // Since y + height represents the trigger's "reference bottom" (accounting for measurement offset),
421
555
  // we need to add another height to position popup BELOW the actual trigger
422
556
  popupY = y + height + height;
423
- console.log('AutoPositionedPopup with keyboard: BELOW position calculated:', {
557
+ debugLog('AutoPositionedPopup with keyboard: BELOW position calculated:', {
424
558
  formula: 'y + 2*height',
425
559
  y,
426
560
  height,
@@ -430,15 +564,15 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
430
564
  const maxY = screenHeight - listLayout.height;
431
565
  if (popupY > maxY) {
432
566
  // If both positions are problematic, clamp to visible area
433
- console.log('AutoPositionedPopup with keyboard: both positions problematic, clamping to visible area');
567
+ debugLog('AutoPositionedPopup with keyboard: both positions problematic, clamping to visible area');
434
568
  popupY = Math.min(Math.max(statusBarHeight, y - listLayout.height), maxY);
435
569
  }
436
570
  }
437
571
  else {
438
- console.log('AutoPositionedPopup with keyboard: showing ABOVE input field (preferred position)');
572
+ debugLog('AutoPositionedPopup with keyboard: showing ABOVE input field (preferred position)');
439
573
  }
440
574
  ref_listPos.current = { x: x, y: popupY, width: width };
441
- console.log('AutoPositionedPopup useTextInput final position=', ref_listPos.current);
575
+ debugLog('AutoPositionedPopup useTextInput final position=', ref_listPos.current);
442
576
  setRootViewNativeStyle(tag, {
443
577
  top: (_a = ref_listPos.current) === null || _a === void 0 ? void 0 : _a.y,
444
578
  left: popUpViewStyle === null || popUpViewStyle === void 0 ? void 0 : popUpViewStyle.left,
@@ -453,7 +587,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
453
587
  }
454
588
  else if (!isKeyboardFullyShown && ref_isFocus.current && keyboardStateChanged) {
455
589
  // Only execute close logic when keyboard state actually changes from true to false
456
- console.log('AutoPositionedPopup isKeyboardFullyShown useEffect removeRootView (keyboard state changed)=', { tag, forceRemoveAllRootViewOnItemSelected, keyboardStateChanged });
590
+ debugLog('AutoPositionedPopup isKeyboardFullyShown useEffect removeRootView (keyboard state changed)=', { tag, forceRemoveAllRootViewOnItemSelected, keyboardStateChanged });
457
591
  removeRootView(tag, forceRemoveAllRootViewOnItemSelected);
458
592
  setState((prevState) => {
459
593
  return Object.assign(Object.assign({}, prevState), { isFocus: false });
@@ -474,7 +608,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
474
608
  // This ensures accurate position when component is inside complex layouts like KeyboardAwareScrollView
475
609
  const measureTarget = triggerBtnRef.current || refAutoPositionedPopup.current;
476
610
  measureTarget === null || measureTarget === void 0 ? void 0 : measureTarget.measureInWindow((x, y, width, height) => {
477
- console.log('AutoPositionedPopup !useTextInput measureInWindow=', { x, y, width, height, usingTriggerRef: !!triggerBtnRef.current });
611
+ debugLog('AutoPositionedPopup !useTextInput measureInWindow=', { x, y, width, height, usingTriggerRef: !!triggerBtnRef.current });
478
612
  // CRITICAL FIX: Handle undefined values from measureInWindow
479
613
  // This can happen during navigation transitions or when view is not yet mounted
480
614
  if (x === undefined || y === undefined || width === undefined || height === undefined) {
@@ -486,7 +620,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
486
620
  const fallbackX = screenWidth * 0.05; // 5% from left
487
621
  const fallbackWidth = screenWidth * 0.9; // 90% width
488
622
  ref_listPos.current = { x: fallbackX, y: fallbackY, width: fallbackWidth };
489
- console.log('AutoPositionedPopup !useTextInput using fallback position=', ref_listPos.current);
623
+ debugLog('AutoPositionedPopup !useTextInput using fallback position=', ref_listPos.current);
490
624
  // Proceed with fallback values
491
625
  x = fallbackX;
492
626
  y = fallbackY;
@@ -497,10 +631,10 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
497
631
  // Default: show popup ABOVE the input field
498
632
  // Only if that goes off the top of screen (considering status bar), show BELOW instead
499
633
  const calculateOptimalPosition = (componentY, componentHeight, popupHeight) => {
500
- console.log('AutoPositionedPopup calculateOptimalPosition executing');
634
+ debugLog('AutoPositionedPopup calculateOptimalPosition executing');
501
635
  // Use window height (visible area) instead of screen height
502
636
  const screenHeight = Dimensions.get('window').height;
503
- console.log('AutoPositionedPopup positioning data:', {
637
+ debugLog('AutoPositionedPopup positioning data:', {
504
638
  screenHeight,
505
639
  componentY,
506
640
  componentHeight,
@@ -520,7 +654,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
520
654
  // Formula: popup_top = trigger_bottom - componentHeight - popupHeight
521
655
  // popup_bottom = trigger_bottom - componentHeight = trigger_top
522
656
  let popupY = componentY + componentHeight - popupHeight;
523
- console.log('AutoPositionedPopup: initial calculation for ABOVE position:', {
657
+ debugLog('AutoPositionedPopup: initial calculation for ABOVE position:', {
524
658
  componentY,
525
659
  componentHeight,
526
660
  popupHeight,
@@ -530,7 +664,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
530
664
  });
531
665
  // 2. Check if showing above would go off the top of screen (behind status bar)
532
666
  if (popupY < statusBarHeight) {
533
- console.log('AutoPositionedPopup: would go behind status bar, showing BELOW instead');
667
+ debugLog('AutoPositionedPopup: would go behind status bar, showing BELOW instead');
534
668
  // Show BELOW the trigger element
535
669
  // Since componentY + componentHeight represents the trigger's "reference bottom" (accounting for measurement offset),
536
670
  // we need to add another componentHeight to position popup BELOW the actual trigger
@@ -538,7 +672,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
538
672
  // - (componentY + componentHeight) = trigger's actual top (compensated)
539
673
  // - + componentHeight = skip past trigger height to get to trigger's actual bottom
540
674
  popupY = componentY + componentHeight + componentHeight;
541
- console.log('AutoPositionedPopup: BELOW position calculated:', {
675
+ debugLog('AutoPositionedPopup: BELOW position calculated:', {
542
676
  formula: 'componentY + 2*componentHeight',
543
677
  componentY,
544
678
  componentHeight,
@@ -549,14 +683,14 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
549
683
  if (popupY > maxY) {
550
684
  // If both positions are problematic, clamp to visible area
551
685
  // Prioritize showing as close to trigger as possible
552
- console.log('AutoPositionedPopup: both positions problematic, clamping to visible area');
686
+ debugLog('AutoPositionedPopup: both positions problematic, clamping to visible area');
553
687
  popupY = Math.min(Math.max(statusBarHeight, componentY - popupHeight), maxY);
554
688
  }
555
689
  }
556
690
  else {
557
- console.log('AutoPositionedPopup: showing ABOVE input field (preferred position)');
691
+ debugLog('AutoPositionedPopup: showing ABOVE input field (preferred position)');
558
692
  }
559
- console.log('AutoPositionedPopup final position:', {
693
+ debugLog('AutoPositionedPopup final position:', {
560
694
  popupY,
561
695
  'showing above': popupY < componentY,
562
696
  'below status bar': popupY >= statusBarHeight
@@ -567,15 +701,15 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
567
701
  const actualPopupHeight = CustomPopView && CustomPopViewStyle && typeof CustomPopViewStyle.height === 'number'
568
702
  ? CustomPopViewStyle.height
569
703
  : listLayout.height;
570
- console.log('AutoPositionedPopup 🔥 Using actualPopupHeight for calculation:', { actualPopupHeight, CustomPopView: !!CustomPopView });
704
+ debugLog('AutoPositionedPopup 🔥 Using actualPopupHeight for calculation:', { actualPopupHeight, CustomPopView: !!CustomPopView });
571
705
  const positionResult = calculateOptimalPosition(y, height, actualPopupHeight);
572
- console.log('AutoPositionedPopup FINAL position result:', positionResult);
706
+ debugLog('AutoPositionedPopup FINAL position result:', positionResult);
573
707
  ref_listPos.current = { x: x, y: positionResult.finalY, width: width };
574
- console.log('AutoPositionedPopup !useTextInput ref_listPos.current=', ref_listPos.current);
708
+ debugLog('AutoPositionedPopup !useTextInput ref_listPos.current=', ref_listPos.current);
575
709
  if (CustomPopView && CustomPopViewStyle) {
576
710
  // Position already calculated correctly above, no need to recalculate
577
711
  const PopViewComponent = CustomPopView();
578
- console.log('AutoPositionedPopup !useTextInput addRootView=', { CustomPopViewStyle, PopViewComponent, 'state.selectedItem': state.selectedItem });
712
+ debugLog('AutoPositionedPopup !useTextInput addRootView=', { CustomPopViewStyle, PopViewComponent, 'state.selectedItem': state.selectedItem });
579
713
  addRootView({
580
714
  id: tag,
581
715
  style: !centerDisplay
@@ -583,7 +717,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
583
717
  component: <PopViewComponent selectedItem={state.selectedItem}></PopViewComponent>,
584
718
  useModal: true,
585
719
  onModalClose: () => {
586
- console.log('AutoPositionedPopup onModalClose');
720
+ debugLog('AutoPositionedPopup onModalClose');
587
721
  removeRootView(tag, forceRemoveAllRootViewOnItemSelected, rootViewsRef.current);
588
722
  setState((prevState) => {
589
723
  return Object.assign(Object.assign({}, prevState), { isFocus: false });
@@ -597,7 +731,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
597
731
  });
598
732
  }
599
733
  else {
600
- console.log('AutoPositionedPopup !useTextInput addRootView tag=', tag);
734
+ debugLog('AutoPositionedPopup !useTextInput addRootView tag=', tag);
601
735
  addRootView({
602
736
  id: tag,
603
737
  style: {
@@ -610,7 +744,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
610
744
  component: (<AutoPositionedPopupList tag={tag} updateState={updateState} fetchData={fetchData} pageSize={pageSize} renderItem={renderItem} selectedItem={state.selectedItem} localSearch={localSearch} showListEmptyComponent={showListEmptyComponent} emptyText={emptyText} themeMode={themeMode}/>),
611
745
  useModal: true,
612
746
  onModalClose: () => {
613
- console.log('AutoPositionedPopup onModalClose tag=', tag);
747
+ debugLog('AutoPositionedPopup onModalClose tag=', tag);
614
748
  removeRootView(tag, forceRemoveAllRootViewOnItemSelected, rootViewsRef.current);
615
749
  setState((prevState) => {
616
750
  return Object.assign({}, prevState);
@@ -645,7 +779,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
645
779
  // Imperative handle for parent component access
646
780
  useImperativeHandle(parentRef, () => ({
647
781
  clearSelectedItem: () => {
648
- console.log('AutoPositionedPopup clearSelectedItem tag=', tag);
782
+ debugLog('AutoPositionedPopup clearSelectedItem tag=', tag);
649
783
  setState((prevState) => {
650
784
  return Object.assign(Object.assign({}, prevState), { selectedItem: undefined, isFocus: false });
651
785
  });
@@ -662,11 +796,11 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
662
796
  },
663
797
  }), []);
664
798
  const updateState = (key, value) => {
665
- console.log('AutoPositionedPopup updateState=', { key, value });
799
+ debugLog('AutoPositionedPopup updateState=', { key, value });
666
800
  setState((prevState) => (Object.assign(Object.assign({}, prevState), { [key]: value })));
667
801
  if (key === 'selectedItem' && onItemSelected) {
668
802
  onItemSelected(value);
669
- console.log('AutoPositionedPopup updateState onItemSelected rootViewsRef.current=', rootViewsRef.current);
803
+ debugLog('AutoPositionedPopup updateState onItemSelected rootViewsRef.current=', rootViewsRef.current);
670
804
  removeRootView(tag, forceRemoveAllRootViewOnItemSelected, rootViewsRef.current);
671
805
  hasAddedRootView.current = false;
672
806
  hasShownRootView.current = false;
@@ -699,17 +833,17 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
699
833
  // Only update when deep comparison detects real changes to avoid TextInput recreation due to reference changes during parent component redraws
700
834
  const stableInputStyle = useMemo(() => {
701
835
  if (!shallowEqual(stableInputStyleRef.current, inputStyle)) {
702
- console.log(`AutoPositionedPopup stableInputStyle: `, { tag, inputStyle, themeMode });
836
+ debugLog(`AutoPositionedPopup stableInputStyle: `, { tag, inputStyle, themeMode });
703
837
  stableInputStyleRef.current = inputStyle;
704
838
  }
705
839
  return stableInputStyleRef.current;
706
840
  }, [inputStyle, tag, themeMode]);
707
841
  const stableTextInputProps = useMemo(() => {
708
842
  if (!shallowEqual(stableTextInputPropsRef.current, TextInputProps)) {
709
- console.log(`AutoPositionedPopup TextInputProps deep change detected, updating stable reference - tag: ${tag}`);
843
+ debugLog(`AutoPositionedPopup TextInputProps deep change detected, updating stable reference - tag: ${tag}`);
710
844
  stableTextInputPropsRef.current = TextInputProps;
711
845
  }
712
- console.log('AutoPositionedPopup stableTextInputProps=', { tag, TextInputProps, 'stableTextInputPropsRef.current': stableTextInputPropsRef.current });
846
+ debugLog('AutoPositionedPopup stableTextInputProps=', { tag, TextInputProps, 'stableTextInputPropsRef.current': stableTextInputPropsRef.current });
713
847
  return stableTextInputPropsRef.current;
714
848
  }, [TextInputProps, tag]);
715
849
  // Use useCallback to stabilize onFocus and onBlur callback references
@@ -720,7 +854,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
720
854
  const handleTextInputFocus = useCallback(() => {
721
855
  const currentTime = Date.now();
722
856
  const timeSinceLastFocus = currentTime - lastFocusTimeRef.current;
723
- console.log('AutoPositionedPopup onFocus=', {
857
+ debugLog('AutoPositionedPopup onFocus=', {
724
858
  tag,
725
859
  'state.selectedItem': stateRef.current.selectedItem,
726
860
  'hasTriggeredFocus.current=': hasTriggeredFocus.current,
@@ -732,17 +866,17 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
732
866
  });
733
867
  // Prevent rapid repeated triggers (repeated events within 300ms are ignored)
734
868
  if (timeSinceLastFocus < 300) {
735
- console.log('AutoPositionedPopup onFocus: Skip - event triggered too quickly (< 300ms)');
869
+ debugLog('AutoPositionedPopup onFocus: Skip - event triggered too quickly (< 300ms)');
736
870
  return;
737
871
  }
738
872
  // Skip if keyboard is already open and focus has been handled
739
873
  if (isKeyboardFullyShown && hasTriggeredFocus.current) {
740
- console.log('AutoPositionedPopup onFocus: Skip - keyboard already open and focus handled');
874
+ debugLog('AutoPositionedPopup onFocus: Skip - keyboard already open and focus handled');
741
875
  return;
742
876
  }
743
877
  // Prevent concurrent processing
744
878
  if (isFocusEventProcessingRef.current) {
745
- console.log('AutoPositionedPopup onFocus: Skip - processing another focus event');
879
+ debugLog('AutoPositionedPopup onFocus: Skip - processing another focus event');
746
880
  return;
747
881
  }
748
882
  isFocusEventProcessingRef.current = true;
@@ -765,7 +899,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
765
899
  }, 100);
766
900
  }, [tag, isKeyboardFullyShown]); // Remove state.selectedItem, use stateRef instead
767
901
  const handleTextInputBlur = useCallback(() => {
768
- console.log('AutoPositionedPopup onBlur=', {
902
+ debugLog('AutoPositionedPopup onBlur=', {
769
903
  tag,
770
904
  'textInputRef.current': textInputRef.current,
771
905
  'isKeyboardFullyShown': isKeyboardFullyShown,
@@ -773,7 +907,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
773
907
  });
774
908
  // If keyboard is still open, this is a false trigger caused by parent component re-render, should not reset
775
909
  if (isKeyboardFullyShown && hasTriggeredFocus.current) {
776
- console.log('AutoPositionedPopup onBlur: Skip - keyboard still open, possibly caused by parent component re-render');
910
+ debugLog('AutoPositionedPopup onBlur: Skip - keyboard still open, possibly caused by parent component re-render');
777
911
  return;
778
912
  }
779
913
  // Only reset internal state, do not actively close keyboard
@@ -797,20 +931,20 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
797
931
  // Wrap TextInput independently in useMemo to recreate only when key props change
798
932
  // This avoids repeated ref callback triggers due to other props changes during parent component redraws
799
933
  const memoizedTextInput = useMemo(() => {
800
- console.log('AutoPositionedPopup memoizedTextInput=', { tag, useTextInput, 'state.isFocus': state.isFocus, stableTextInputProps });
934
+ debugLog('AutoPositionedPopup memoizedTextInput=', { tag, useTextInput, 'state.isFocus': state.isFocus, stableTextInputProps });
801
935
  if (!useTextInput || !state.isFocus) {
802
936
  return null;
803
937
  }
804
938
  return (<RNTextInput ref={(ref) => {
805
939
  // Monitor TextInput mounting and unmounting
806
940
  if (ref && !textInputRef.current) {
807
- console.log(`AutoPositionedPopup TextInput created/mounted - tag: ${tag}, ref:`, ref);
941
+ debugLog(`AutoPositionedPopup TextInput created/mounted - tag: ${tag}, ref:`, ref);
808
942
  }
809
943
  else if (!ref && textInputRef.current) {
810
- console.log(`AutoPositionedPopup TextInput unmounted - tag: ${tag}`);
944
+ debugLog(`AutoPositionedPopup TextInput unmounted - tag: ${tag}`);
811
945
  }
812
946
  else if (ref && textInputRef.current && ref !== textInputRef.current) {
813
- console.log(`AutoPositionedPopup TextInput replaced - tag: ${tag}, oldRef:`, textInputRef.current, 'newRef:', ref);
947
+ debugLog(`AutoPositionedPopup TextInput replaced - tag: ${tag}, oldRef:`, textInputRef.current, 'newRef:', ref);
814
948
  }
815
949
  textInputRef.current = ref;
816
950
  }} key={`textinput-${tag}`} style={[
@@ -819,7 +953,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
819
953
  (themeMode === 'dark' && { color: '#fff' })
820
954
  ]} textAlign={stableTextInputProps && stableTextInputProps['textAlign'] || 'left'} multiline={stableTextInputProps && stableTextInputProps['multiline'] || false} numberOfLines={stableTextInputProps && stableTextInputProps['numberOfLines'] || 1} onChangeText={(searchQuery) => {
821
955
  ref_searchQuery.current = searchQuery;
822
- console.log('AutoPositionedPopup onChangeText rootViews=', rootViews);
956
+ debugLog('AutoPositionedPopup onChangeText rootViews=', rootViews);
823
957
  if (!localSearch) {
824
958
  if (debounceTimerRef.current) {
825
959
  clearTimeout(debounceTimerRef.current);
@@ -838,7 +972,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
838
972
  Keyboard.dismiss();
839
973
  }
840
974
  }} keyboardType={stableTextInputProps && stableTextInputProps['keyboardType'] || 'default'} clearButtonMode="while-editing" returnKeyType={stableTextInputProps && stableTextInputProps['returnKeyType'] || 'done'} maxLength={stableTextInputProps && stableTextInputProps['maxLength'] || 100} accessibilityLabel="selectInput" accessible={true} autoFocus={stableTextInputProps && stableTextInputProps['autoFocus'] || true} autoCorrect={false} underlineColorAndroid="transparent" editable={stableTextInputProps && stableTextInputProps['editable'] || true} secureTextEntry={stableTextInputProps && stableTextInputProps['secureTextEntry'] || false} defaultValue="" caretHidden={false} enablesReturnKeyAutomatically onFocus={handleTextInputFocus} onBlur={handleTextInputBlur} selectTextOnFocus={stableTextInputProps && stableTextInputProps['selectTextOnFocus'] || false} onSubmitEditing={(e) => {
841
- console.log('AutoPositionedPopup.tsx onSubmitEditing e.nativeEvent.text=', e.nativeEvent.text);
975
+ debugLog('AutoPositionedPopup.tsx onSubmitEditing e.nativeEvent.text=', e.nativeEvent.text);
842
976
  onSubmitEditing && onSubmitEditing(e);
843
977
  }}/>);
844
978
  }, [
@@ -857,11 +991,11 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
857
991
  // Render the component following project implementation
858
992
  return useMemo(() => {
859
993
  var _a;
860
- console.log('AutoPositionedPopup render tag=', tag); // Now safe - circular dependency fixed
994
+ debugLog('AutoPositionedPopup render tag=', tag); // Now safe - circular dependency fixed
861
995
  return (<CustomRow>
862
996
  <View style={[styles.contain, style]} ref={refAutoPositionedPopup}>
863
997
  {!state.isFocus || !useTextInput ? (<TouchableOpacity ref={triggerBtnRef} style={[styles.AutoPositionedPopupBtn, AutoPositionedPopupBtnStyle]} disabled={AutoPositionedPopupBtnDisabled} onPress={() => {
864
- console.log('AutoPositionedPopup onPress=', {
998
+ debugLog('AutoPositionedPopup onPress=', {
865
999
  tag,
866
1000
  'state.isFocus': state.isFocus,
867
1001
  useTextInput,
@@ -871,6 +1005,14 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
871
1005
  'selectedItem': selectedItem,
872
1006
  'ref_isKeyboardFullyShown.current': ref_isKeyboardFullyShown.current
873
1007
  });
1008
+ // Capture trigger button position BEFORE switching to TextInput
1009
+ // This is critical because triggerBtnRef will become null after isFocus=true
1010
+ if (triggerBtnRef.current && (parentScrollViewRef === null || parentScrollViewRef === void 0 ? void 0 : parentScrollViewRef.current)) {
1011
+ triggerBtnRef.current.measureInWindow((x, y, width, height) => {
1012
+ debugLog('AutoPositionedPopup onPress: captured trigger position=', { tag, x, y, width, height });
1013
+ triggerPositionRef.current = { x, y, width, height };
1014
+ });
1015
+ }
874
1016
  if (useTextInput) {
875
1017
  const _addRootView = () => {
876
1018
  if (!hasAddedRootView.current) {
@@ -912,7 +1054,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
912
1054
  return Object.assign(Object.assign({}, prevState), { isFocus: true });
913
1055
  });
914
1056
  }
915
- console.log('AutoPositionedPopup onPress done');
1057
+ debugLog('AutoPositionedPopup onPress done');
916
1058
  }}>
917
1059
  {!btwChildren ? (<Text style={[
918
1060
  styles.searchQueryTxt,