react-native-auto-positioned-popup 1.2.14 → 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,3 +1,4 @@
1
+ import { debugLog } from './constants';
1
2
  import React, { forwardRef, memo, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState, } from 'react';
2
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';
@@ -6,7 +7,7 @@ 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
  }
@@ -244,7 +245,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
244
245
  */
245
246
  const scrollParentToTrigger = useCallback(() => {
246
247
  if (!(parentScrollViewRef === null || parentScrollViewRef === void 0 ? void 0 : parentScrollViewRef.current) || !triggerBtnRef.current) {
247
- console.log('AutoPositionedPopup scrollParentToTrigger: No parentScrollViewRef or triggerBtnRef available');
248
+ debugLog('AutoPositionedPopup scrollParentToTrigger: No parentScrollViewRef or triggerBtnRef available');
248
249
  return;
249
250
  }
250
251
  // Use scrollToFocusedInput method from KeyboardAwareScrollView
@@ -252,16 +253,16 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
252
253
  const scrollView = parentScrollViewRef.current;
253
254
  const nodeHandle = findNodeHandle(triggerBtnRef.current);
254
255
  if (nodeHandle && scrollView) {
255
- console.log('AutoPositionedPopup scrollParentToTrigger: Scrolling to trigger button with extraHeight=', scrollExtraHeight);
256
+ debugLog('AutoPositionedPopup scrollParentToTrigger: Scrolling to trigger button with extraHeight=', scrollExtraHeight);
256
257
  // KeyboardAwareScrollView has a scrollToFocusedInput method that handles this
257
258
  // However, it requires a ReactNode. We'll use scrollToPosition as an alternative.
258
259
  // First, measure the trigger button position relative to the ScrollView
259
260
  triggerBtnRef.current.measureInWindow((x, y, width, height) => {
260
261
  if (y === undefined || height === undefined) {
261
- console.log('AutoPositionedPopup scrollParentToTrigger: measureInWindow returned undefined');
262
+ debugLog('AutoPositionedPopup scrollParentToTrigger: measureInWindow returned undefined');
262
263
  return;
263
264
  }
264
- console.log('AutoPositionedPopup scrollParentToTrigger: trigger position=', { x, y, width, height });
265
+ debugLog('AutoPositionedPopup scrollParentToTrigger: trigger position=', { x, y, width, height });
265
266
  // Get keyboard height from Keyboard API
266
267
  // On keyboard show, scroll to position that keeps trigger above keyboard
267
268
  Keyboard.addListener('keyboardDidShow', (event) => {
@@ -270,7 +271,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
270
271
  // Calculate if trigger is below keyboard
271
272
  const triggerBottom = y + height;
272
273
  const visibleAreaBottom = screenHeight - keyboardHeight;
273
- console.log('AutoPositionedPopup scrollParentToTrigger: keyboard data=', {
274
+ debugLog('AutoPositionedPopup scrollParentToTrigger: keyboard data=', {
274
275
  keyboardHeight,
275
276
  screenHeight,
276
277
  triggerBottom,
@@ -280,7 +281,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
280
281
  if (triggerBottom > visibleAreaBottom) {
281
282
  // Calculate how much to scroll
282
283
  const scrollAmount = triggerBottom - visibleAreaBottom + scrollExtraHeight;
283
- console.log('AutoPositionedPopup scrollParentToTrigger: scrolling by', scrollAmount);
284
+ debugLog('AutoPositionedPopup scrollParentToTrigger: scrolling by', scrollAmount);
284
285
  // Use scrollForExtraHeightOnAndroid or scrollToPosition
285
286
  if (typeof scrollView.scrollToPosition === 'function') {
286
287
  // scrollToPosition(x, y, animated)
@@ -288,7 +289,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
288
289
  }
289
290
  else if (typeof scrollView.scrollToEnd === 'function') {
290
291
  // Fallback: scroll to end might help in some cases
291
- console.log('AutoPositionedPopup scrollParentToTrigger: using scrollToEnd fallback');
292
+ debugLog('AutoPositionedPopup scrollParentToTrigger: using scrollToEnd fallback');
292
293
  }
293
294
  }
294
295
  });
@@ -300,19 +301,19 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
300
301
  * Uses stored trigger position (captured before TextInput replaces the trigger button)
301
302
  */
302
303
  const scrollToTriggerWithMeasure = useCallback(() => {
303
- console.log('AutoPositionedPopup scrollToTriggerWithMeasure called, tag=', tag, {
304
+ debugLog('AutoPositionedPopup scrollToTriggerWithMeasure called, tag=', tag, {
304
305
  hasParentScrollViewRef: !!(parentScrollViewRef === null || parentScrollViewRef === void 0 ? void 0 : parentScrollViewRef.current),
305
306
  hasTriggerPosition: !!triggerPositionRef.current,
306
307
  triggerPosition: triggerPositionRef.current
307
308
  });
308
309
  if (!(parentScrollViewRef === null || parentScrollViewRef === void 0 ? void 0 : parentScrollViewRef.current)) {
309
- console.log('AutoPositionedPopup scrollToTriggerWithMeasure: parentScrollViewRef not available, tag=', tag);
310
+ debugLog('AutoPositionedPopup scrollToTriggerWithMeasure: parentScrollViewRef not available, tag=', tag);
310
311
  return;
311
312
  }
312
313
  // Use stored trigger position (captured when trigger was clicked)
313
314
  const storedPosition = triggerPositionRef.current;
314
315
  if (!storedPosition) {
315
- console.log('AutoPositionedPopup scrollToTriggerWithMeasure: no stored trigger position, tag=', tag);
316
+ debugLog('AutoPositionedPopup scrollToTriggerWithMeasure: no stored trigger position, tag=', tag);
316
317
  return;
317
318
  }
318
319
  const scrollView = parentScrollViewRef.current;
@@ -324,7 +325,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
324
325
  const keyboardApproxHeight = screenHeight * 0.4; // Conservative estimate
325
326
  const visibleAreaBottom = screenHeight - keyboardApproxHeight;
326
327
  const triggerBottom = triggerY + triggerHeight;
327
- console.log('AutoPositionedPopup scrollToTriggerWithMeasure: calculations=', {
328
+ debugLog('AutoPositionedPopup scrollToTriggerWithMeasure: calculations=', {
328
329
  tag,
329
330
  triggerY,
330
331
  triggerHeight,
@@ -337,7 +338,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
337
338
  if (triggerBottom > visibleAreaBottom) {
338
339
  // Calculate scroll amount to bring trigger above keyboard
339
340
  const scrollAmount = triggerBottom - visibleAreaBottom + scrollExtraHeight;
340
- console.log('AutoPositionedPopup scrollToTriggerWithMeasure: scrolling, amount=', scrollAmount, 'tag=', tag);
341
+ debugLog('AutoPositionedPopup scrollToTriggerWithMeasure: scrolling, amount=', scrollAmount, 'tag=', tag);
341
342
  // Use scrollForExtraHeightOnAndroid for KeyboardAwareScrollView
342
343
  if (typeof scrollView.scrollForExtraHeightOnAndroid === 'function') {
343
344
  scrollView.scrollForExtraHeightOnAndroid(scrollAmount);
@@ -350,11 +351,11 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
350
351
  scrollView.scrollTo({ y: scrollAmount, animated: true });
351
352
  }
352
353
  else {
353
- console.log('AutoPositionedPopup scrollToTriggerWithMeasure: no scroll method available on scrollView');
354
+ debugLog('AutoPositionedPopup scrollToTriggerWithMeasure: no scroll method available on scrollView');
354
355
  }
355
356
  }
356
357
  else {
357
- console.log('AutoPositionedPopup scrollToTriggerWithMeasure: trigger already visible, no scroll needed, tag=', tag);
358
+ debugLog('AutoPositionedPopup scrollToTriggerWithMeasure: trigger already visible, no scroll needed, tag=', tag);
358
359
  }
359
360
  }, [parentScrollViewRef, scrollExtraHeight, tag]);
360
361
  /**
@@ -363,10 +364,10 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
363
364
  useEffect(() => {
364
365
  (async () => {
365
366
  })();
366
- console.log(`AutoPositionedPopup componentDidMount=`, { tag, CustomPopView });
367
+ debugLog(`AutoPositionedPopup componentDidMount=`, { tag, CustomPopView });
367
368
  //componentWillUnmount
368
369
  return () => {
369
- console.log(`AutoPositionedPopup componentWillUnmount tag=`, tag);
370
+ debugLog(`AutoPositionedPopup componentWillUnmount tag=`, tag);
370
371
  removeRootView(tag, forceRemoveAllRootViewOnItemSelected, rootViewsRef.current);
371
372
  setSearchQuery('');
372
373
  if (textInputRef.current) {
@@ -379,7 +380,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
379
380
  };
380
381
  }, []);
381
382
  useEffect(() => {
382
- console.log('AutoPositionedPopup rootViews=', { tag, rootViews });
383
+ debugLog('AutoPositionedPopup rootViews=', { tag, rootViews });
383
384
  rootViewsRef.current = rootViews;
384
385
  if (rootViews.length === 0) {
385
386
  hasAddedRootView.current = false;
@@ -394,10 +395,10 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
394
395
  }, [rootViews]);
395
396
  useEffect(() => {
396
397
  var _a, _b;
397
- console.log('AutoPositionedPopup useEffect [selectedItem, state.selectedItem, tag]=', { tag, selectedItem, 'state.selectedItem': state.selectedItem });
398
- 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);
399
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)) {
400
- console.log('AutoPositionedPopup useEffect selectedItem!=state.selectedItem');
401
+ debugLog('AutoPositionedPopup useEffect selectedItem!=state.selectedItem');
401
402
  setState((prevState) => {
402
403
  return Object.assign(Object.assign({}, prevState), { selectedItem: selectedItem });
403
404
  });
@@ -410,7 +411,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
410
411
  const propsChanged = prevPropsRef.current.CustomPopView !== CustomPopView ||
411
412
  prevPropsRef.current.CustomPopViewStyle !== CustomPopViewStyle ||
412
413
  (prevPropsRef.current.TextInputProps !== TextInputProps && useTextInput);
413
- console.log('AutoPositionedPopup useEffect [isKeyboardFullyShown,\n' +
414
+ debugLog('AutoPositionedPopup useEffect [isKeyboardFullyShown,\n' +
414
415
  ' state.isFocus,\n' +
415
416
  ' useTextInput,\n' +
416
417
  ' CustomPopView,\n' +
@@ -442,7 +443,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
442
443
  };
443
444
  // Only execute logic when keyboard state actually changes or user actively operates
444
445
  if (!keyboardStateChanged && hasAddedRootView.current) {
445
- 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);
446
447
  // if (!ref_isFocus.current) {
447
448
  // textInputRef.current?.focus()
448
449
  // }
@@ -468,7 +469,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
468
469
  // When keyboard appears, the trigger button may be covered. If parentScrollViewRef
469
470
  // is provided, scroll the parent to keep the trigger visible above the keyboard.
470
471
  if (parentScrollViewRef === null || parentScrollViewRef === void 0 ? void 0 : parentScrollViewRef.current) {
471
- console.log('AutoPositionedPopup: Keyboard appeared, scrolling parent to keep trigger visible');
472
+ debugLog('AutoPositionedPopup: Keyboard appeared, scrolling parent to keep trigger visible');
472
473
  // Use a slight delay to ensure keyboard animation has started
473
474
  setTimeout(() => {
474
475
  scrollToTriggerWithMeasure();
@@ -493,7 +494,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
493
494
  const measureTarget = triggerBtnRef.current || refAutoPositionedPopup.current;
494
495
  measureTarget === null || measureTarget === void 0 ? void 0 : measureTarget.measureInWindow((x, y, width, height) => {
495
496
  var _a;
496
- 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 });
497
498
  // CRITICAL FIX: Handle undefined values from measureInWindow
498
499
  // This can happen during navigation transitions or when view is not yet mounted
499
500
  if (x === undefined || y === undefined || width === undefined || height === undefined) {
@@ -521,7 +522,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
521
522
  // we should directly use measureInWindow's y value without additional calculations
522
523
  // The popup container is at the same level as the page content
523
524
  const screenHeight = Dimensions.get('window').height; // Use window height, not screen
524
- console.log('AutoPositionedPopup useTextInput positioning data=', {
525
+ debugLog('AutoPositionedPopup useTextInput positioning data=', {
525
526
  screenHeight,
526
527
  componentY: y,
527
528
  componentHeight: height,
@@ -537,7 +538,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
537
538
  // Use (y + height * 0.7) as reference to compensate for measurement offset
538
539
  // while still leaving trigger visible (30% of trigger height exposed)
539
540
  let popupY = y + (height * 0.7) - listLayout.height;
540
- console.log('AutoPositionedPopup with keyboard: initial calculation for ABOVE position:', {
541
+ debugLog('AutoPositionedPopup with keyboard: initial calculation for ABOVE position:', {
541
542
  componentY: y,
542
543
  componentHeight: height,
543
544
  popupHeight: listLayout.height,
@@ -548,12 +549,12 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
548
549
  });
549
550
  // 2. Check if showing above would go behind status bar
550
551
  if (popupY < statusBarHeight) {
551
- 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');
552
553
  // Show BELOW the input field
553
554
  // Since y + height represents the trigger's "reference bottom" (accounting for measurement offset),
554
555
  // we need to add another height to position popup BELOW the actual trigger
555
556
  popupY = y + height + height;
556
- console.log('AutoPositionedPopup with keyboard: BELOW position calculated:', {
557
+ debugLog('AutoPositionedPopup with keyboard: BELOW position calculated:', {
557
558
  formula: 'y + 2*height',
558
559
  y,
559
560
  height,
@@ -563,15 +564,15 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
563
564
  const maxY = screenHeight - listLayout.height;
564
565
  if (popupY > maxY) {
565
566
  // If both positions are problematic, clamp to visible area
566
- console.log('AutoPositionedPopup with keyboard: both positions problematic, clamping to visible area');
567
+ debugLog('AutoPositionedPopup with keyboard: both positions problematic, clamping to visible area');
567
568
  popupY = Math.min(Math.max(statusBarHeight, y - listLayout.height), maxY);
568
569
  }
569
570
  }
570
571
  else {
571
- console.log('AutoPositionedPopup with keyboard: showing ABOVE input field (preferred position)');
572
+ debugLog('AutoPositionedPopup with keyboard: showing ABOVE input field (preferred position)');
572
573
  }
573
574
  ref_listPos.current = { x: x, y: popupY, width: width };
574
- console.log('AutoPositionedPopup useTextInput final position=', ref_listPos.current);
575
+ debugLog('AutoPositionedPopup useTextInput final position=', ref_listPos.current);
575
576
  setRootViewNativeStyle(tag, {
576
577
  top: (_a = ref_listPos.current) === null || _a === void 0 ? void 0 : _a.y,
577
578
  left: popUpViewStyle === null || popUpViewStyle === void 0 ? void 0 : popUpViewStyle.left,
@@ -586,7 +587,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
586
587
  }
587
588
  else if (!isKeyboardFullyShown && ref_isFocus.current && keyboardStateChanged) {
588
589
  // Only execute close logic when keyboard state actually changes from true to false
589
- console.log('AutoPositionedPopup isKeyboardFullyShown useEffect removeRootView (keyboard state changed)=', { tag, forceRemoveAllRootViewOnItemSelected, keyboardStateChanged });
590
+ debugLog('AutoPositionedPopup isKeyboardFullyShown useEffect removeRootView (keyboard state changed)=', { tag, forceRemoveAllRootViewOnItemSelected, keyboardStateChanged });
590
591
  removeRootView(tag, forceRemoveAllRootViewOnItemSelected);
591
592
  setState((prevState) => {
592
593
  return Object.assign(Object.assign({}, prevState), { isFocus: false });
@@ -607,7 +608,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
607
608
  // This ensures accurate position when component is inside complex layouts like KeyboardAwareScrollView
608
609
  const measureTarget = triggerBtnRef.current || refAutoPositionedPopup.current;
609
610
  measureTarget === null || measureTarget === void 0 ? void 0 : measureTarget.measureInWindow((x, y, width, height) => {
610
- console.log('AutoPositionedPopup !useTextInput measureInWindow=', { x, y, width, height, usingTriggerRef: !!triggerBtnRef.current });
611
+ debugLog('AutoPositionedPopup !useTextInput measureInWindow=', { x, y, width, height, usingTriggerRef: !!triggerBtnRef.current });
611
612
  // CRITICAL FIX: Handle undefined values from measureInWindow
612
613
  // This can happen during navigation transitions or when view is not yet mounted
613
614
  if (x === undefined || y === undefined || width === undefined || height === undefined) {
@@ -619,7 +620,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
619
620
  const fallbackX = screenWidth * 0.05; // 5% from left
620
621
  const fallbackWidth = screenWidth * 0.9; // 90% width
621
622
  ref_listPos.current = { x: fallbackX, y: fallbackY, width: fallbackWidth };
622
- console.log('AutoPositionedPopup !useTextInput using fallback position=', ref_listPos.current);
623
+ debugLog('AutoPositionedPopup !useTextInput using fallback position=', ref_listPos.current);
623
624
  // Proceed with fallback values
624
625
  x = fallbackX;
625
626
  y = fallbackY;
@@ -630,10 +631,10 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
630
631
  // Default: show popup ABOVE the input field
631
632
  // Only if that goes off the top of screen (considering status bar), show BELOW instead
632
633
  const calculateOptimalPosition = (componentY, componentHeight, popupHeight) => {
633
- console.log('AutoPositionedPopup calculateOptimalPosition executing');
634
+ debugLog('AutoPositionedPopup calculateOptimalPosition executing');
634
635
  // Use window height (visible area) instead of screen height
635
636
  const screenHeight = Dimensions.get('window').height;
636
- console.log('AutoPositionedPopup positioning data:', {
637
+ debugLog('AutoPositionedPopup positioning data:', {
637
638
  screenHeight,
638
639
  componentY,
639
640
  componentHeight,
@@ -653,7 +654,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
653
654
  // Formula: popup_top = trigger_bottom - componentHeight - popupHeight
654
655
  // popup_bottom = trigger_bottom - componentHeight = trigger_top
655
656
  let popupY = componentY + componentHeight - popupHeight;
656
- console.log('AutoPositionedPopup: initial calculation for ABOVE position:', {
657
+ debugLog('AutoPositionedPopup: initial calculation for ABOVE position:', {
657
658
  componentY,
658
659
  componentHeight,
659
660
  popupHeight,
@@ -663,7 +664,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
663
664
  });
664
665
  // 2. Check if showing above would go off the top of screen (behind status bar)
665
666
  if (popupY < statusBarHeight) {
666
- console.log('AutoPositionedPopup: would go behind status bar, showing BELOW instead');
667
+ debugLog('AutoPositionedPopup: would go behind status bar, showing BELOW instead');
667
668
  // Show BELOW the trigger element
668
669
  // Since componentY + componentHeight represents the trigger's "reference bottom" (accounting for measurement offset),
669
670
  // we need to add another componentHeight to position popup BELOW the actual trigger
@@ -671,7 +672,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
671
672
  // - (componentY + componentHeight) = trigger's actual top (compensated)
672
673
  // - + componentHeight = skip past trigger height to get to trigger's actual bottom
673
674
  popupY = componentY + componentHeight + componentHeight;
674
- console.log('AutoPositionedPopup: BELOW position calculated:', {
675
+ debugLog('AutoPositionedPopup: BELOW position calculated:', {
675
676
  formula: 'componentY + 2*componentHeight',
676
677
  componentY,
677
678
  componentHeight,
@@ -682,14 +683,14 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
682
683
  if (popupY > maxY) {
683
684
  // If both positions are problematic, clamp to visible area
684
685
  // Prioritize showing as close to trigger as possible
685
- console.log('AutoPositionedPopup: both positions problematic, clamping to visible area');
686
+ debugLog('AutoPositionedPopup: both positions problematic, clamping to visible area');
686
687
  popupY = Math.min(Math.max(statusBarHeight, componentY - popupHeight), maxY);
687
688
  }
688
689
  }
689
690
  else {
690
- console.log('AutoPositionedPopup: showing ABOVE input field (preferred position)');
691
+ debugLog('AutoPositionedPopup: showing ABOVE input field (preferred position)');
691
692
  }
692
- console.log('AutoPositionedPopup final position:', {
693
+ debugLog('AutoPositionedPopup final position:', {
693
694
  popupY,
694
695
  'showing above': popupY < componentY,
695
696
  'below status bar': popupY >= statusBarHeight
@@ -700,15 +701,15 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
700
701
  const actualPopupHeight = CustomPopView && CustomPopViewStyle && typeof CustomPopViewStyle.height === 'number'
701
702
  ? CustomPopViewStyle.height
702
703
  : listLayout.height;
703
- console.log('AutoPositionedPopup 🔥 Using actualPopupHeight for calculation:', { actualPopupHeight, CustomPopView: !!CustomPopView });
704
+ debugLog('AutoPositionedPopup 🔥 Using actualPopupHeight for calculation:', { actualPopupHeight, CustomPopView: !!CustomPopView });
704
705
  const positionResult = calculateOptimalPosition(y, height, actualPopupHeight);
705
- console.log('AutoPositionedPopup FINAL position result:', positionResult);
706
+ debugLog('AutoPositionedPopup FINAL position result:', positionResult);
706
707
  ref_listPos.current = { x: x, y: positionResult.finalY, width: width };
707
- console.log('AutoPositionedPopup !useTextInput ref_listPos.current=', ref_listPos.current);
708
+ debugLog('AutoPositionedPopup !useTextInput ref_listPos.current=', ref_listPos.current);
708
709
  if (CustomPopView && CustomPopViewStyle) {
709
710
  // Position already calculated correctly above, no need to recalculate
710
711
  const PopViewComponent = CustomPopView();
711
- console.log('AutoPositionedPopup !useTextInput addRootView=', { CustomPopViewStyle, PopViewComponent, 'state.selectedItem': state.selectedItem });
712
+ debugLog('AutoPositionedPopup !useTextInput addRootView=', { CustomPopViewStyle, PopViewComponent, 'state.selectedItem': state.selectedItem });
712
713
  addRootView({
713
714
  id: tag,
714
715
  style: !centerDisplay
@@ -716,7 +717,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
716
717
  component: <PopViewComponent selectedItem={state.selectedItem}></PopViewComponent>,
717
718
  useModal: true,
718
719
  onModalClose: () => {
719
- console.log('AutoPositionedPopup onModalClose');
720
+ debugLog('AutoPositionedPopup onModalClose');
720
721
  removeRootView(tag, forceRemoveAllRootViewOnItemSelected, rootViewsRef.current);
721
722
  setState((prevState) => {
722
723
  return Object.assign(Object.assign({}, prevState), { isFocus: false });
@@ -730,7 +731,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
730
731
  });
731
732
  }
732
733
  else {
733
- console.log('AutoPositionedPopup !useTextInput addRootView tag=', tag);
734
+ debugLog('AutoPositionedPopup !useTextInput addRootView tag=', tag);
734
735
  addRootView({
735
736
  id: tag,
736
737
  style: {
@@ -743,7 +744,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
743
744
  component: (<AutoPositionedPopupList tag={tag} updateState={updateState} fetchData={fetchData} pageSize={pageSize} renderItem={renderItem} selectedItem={state.selectedItem} localSearch={localSearch} showListEmptyComponent={showListEmptyComponent} emptyText={emptyText} themeMode={themeMode}/>),
744
745
  useModal: true,
745
746
  onModalClose: () => {
746
- console.log('AutoPositionedPopup onModalClose tag=', tag);
747
+ debugLog('AutoPositionedPopup onModalClose tag=', tag);
747
748
  removeRootView(tag, forceRemoveAllRootViewOnItemSelected, rootViewsRef.current);
748
749
  setState((prevState) => {
749
750
  return Object.assign({}, prevState);
@@ -778,7 +779,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
778
779
  // Imperative handle for parent component access
779
780
  useImperativeHandle(parentRef, () => ({
780
781
  clearSelectedItem: () => {
781
- console.log('AutoPositionedPopup clearSelectedItem tag=', tag);
782
+ debugLog('AutoPositionedPopup clearSelectedItem tag=', tag);
782
783
  setState((prevState) => {
783
784
  return Object.assign(Object.assign({}, prevState), { selectedItem: undefined, isFocus: false });
784
785
  });
@@ -795,11 +796,11 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
795
796
  },
796
797
  }), []);
797
798
  const updateState = (key, value) => {
798
- console.log('AutoPositionedPopup updateState=', { key, value });
799
+ debugLog('AutoPositionedPopup updateState=', { key, value });
799
800
  setState((prevState) => (Object.assign(Object.assign({}, prevState), { [key]: value })));
800
801
  if (key === 'selectedItem' && onItemSelected) {
801
802
  onItemSelected(value);
802
- console.log('AutoPositionedPopup updateState onItemSelected rootViewsRef.current=', rootViewsRef.current);
803
+ debugLog('AutoPositionedPopup updateState onItemSelected rootViewsRef.current=', rootViewsRef.current);
803
804
  removeRootView(tag, forceRemoveAllRootViewOnItemSelected, rootViewsRef.current);
804
805
  hasAddedRootView.current = false;
805
806
  hasShownRootView.current = false;
@@ -832,17 +833,17 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
832
833
  // Only update when deep comparison detects real changes to avoid TextInput recreation due to reference changes during parent component redraws
833
834
  const stableInputStyle = useMemo(() => {
834
835
  if (!shallowEqual(stableInputStyleRef.current, inputStyle)) {
835
- console.log(`AutoPositionedPopup stableInputStyle: `, { tag, inputStyle, themeMode });
836
+ debugLog(`AutoPositionedPopup stableInputStyle: `, { tag, inputStyle, themeMode });
836
837
  stableInputStyleRef.current = inputStyle;
837
838
  }
838
839
  return stableInputStyleRef.current;
839
840
  }, [inputStyle, tag, themeMode]);
840
841
  const stableTextInputProps = useMemo(() => {
841
842
  if (!shallowEqual(stableTextInputPropsRef.current, TextInputProps)) {
842
- console.log(`AutoPositionedPopup TextInputProps deep change detected, updating stable reference - tag: ${tag}`);
843
+ debugLog(`AutoPositionedPopup TextInputProps deep change detected, updating stable reference - tag: ${tag}`);
843
844
  stableTextInputPropsRef.current = TextInputProps;
844
845
  }
845
- console.log('AutoPositionedPopup stableTextInputProps=', { tag, TextInputProps, 'stableTextInputPropsRef.current': stableTextInputPropsRef.current });
846
+ debugLog('AutoPositionedPopup stableTextInputProps=', { tag, TextInputProps, 'stableTextInputPropsRef.current': stableTextInputPropsRef.current });
846
847
  return stableTextInputPropsRef.current;
847
848
  }, [TextInputProps, tag]);
848
849
  // Use useCallback to stabilize onFocus and onBlur callback references
@@ -853,7 +854,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
853
854
  const handleTextInputFocus = useCallback(() => {
854
855
  const currentTime = Date.now();
855
856
  const timeSinceLastFocus = currentTime - lastFocusTimeRef.current;
856
- console.log('AutoPositionedPopup onFocus=', {
857
+ debugLog('AutoPositionedPopup onFocus=', {
857
858
  tag,
858
859
  'state.selectedItem': stateRef.current.selectedItem,
859
860
  'hasTriggeredFocus.current=': hasTriggeredFocus.current,
@@ -865,17 +866,17 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
865
866
  });
866
867
  // Prevent rapid repeated triggers (repeated events within 300ms are ignored)
867
868
  if (timeSinceLastFocus < 300) {
868
- console.log('AutoPositionedPopup onFocus: Skip - event triggered too quickly (< 300ms)');
869
+ debugLog('AutoPositionedPopup onFocus: Skip - event triggered too quickly (< 300ms)');
869
870
  return;
870
871
  }
871
872
  // Skip if keyboard is already open and focus has been handled
872
873
  if (isKeyboardFullyShown && hasTriggeredFocus.current) {
873
- console.log('AutoPositionedPopup onFocus: Skip - keyboard already open and focus handled');
874
+ debugLog('AutoPositionedPopup onFocus: Skip - keyboard already open and focus handled');
874
875
  return;
875
876
  }
876
877
  // Prevent concurrent processing
877
878
  if (isFocusEventProcessingRef.current) {
878
- console.log('AutoPositionedPopup onFocus: Skip - processing another focus event');
879
+ debugLog('AutoPositionedPopup onFocus: Skip - processing another focus event');
879
880
  return;
880
881
  }
881
882
  isFocusEventProcessingRef.current = true;
@@ -898,7 +899,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
898
899
  }, 100);
899
900
  }, [tag, isKeyboardFullyShown]); // Remove state.selectedItem, use stateRef instead
900
901
  const handleTextInputBlur = useCallback(() => {
901
- console.log('AutoPositionedPopup onBlur=', {
902
+ debugLog('AutoPositionedPopup onBlur=', {
902
903
  tag,
903
904
  'textInputRef.current': textInputRef.current,
904
905
  'isKeyboardFullyShown': isKeyboardFullyShown,
@@ -906,7 +907,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
906
907
  });
907
908
  // If keyboard is still open, this is a false trigger caused by parent component re-render, should not reset
908
909
  if (isKeyboardFullyShown && hasTriggeredFocus.current) {
909
- 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');
910
911
  return;
911
912
  }
912
913
  // Only reset internal state, do not actively close keyboard
@@ -930,20 +931,20 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
930
931
  // Wrap TextInput independently in useMemo to recreate only when key props change
931
932
  // This avoids repeated ref callback triggers due to other props changes during parent component redraws
932
933
  const memoizedTextInput = useMemo(() => {
933
- console.log('AutoPositionedPopup memoizedTextInput=', { tag, useTextInput, 'state.isFocus': state.isFocus, stableTextInputProps });
934
+ debugLog('AutoPositionedPopup memoizedTextInput=', { tag, useTextInput, 'state.isFocus': state.isFocus, stableTextInputProps });
934
935
  if (!useTextInput || !state.isFocus) {
935
936
  return null;
936
937
  }
937
938
  return (<RNTextInput ref={(ref) => {
938
939
  // Monitor TextInput mounting and unmounting
939
940
  if (ref && !textInputRef.current) {
940
- console.log(`AutoPositionedPopup TextInput created/mounted - tag: ${tag}, ref:`, ref);
941
+ debugLog(`AutoPositionedPopup TextInput created/mounted - tag: ${tag}, ref:`, ref);
941
942
  }
942
943
  else if (!ref && textInputRef.current) {
943
- console.log(`AutoPositionedPopup TextInput unmounted - tag: ${tag}`);
944
+ debugLog(`AutoPositionedPopup TextInput unmounted - tag: ${tag}`);
944
945
  }
945
946
  else if (ref && textInputRef.current && ref !== textInputRef.current) {
946
- console.log(`AutoPositionedPopup TextInput replaced - tag: ${tag}, oldRef:`, textInputRef.current, 'newRef:', ref);
947
+ debugLog(`AutoPositionedPopup TextInput replaced - tag: ${tag}, oldRef:`, textInputRef.current, 'newRef:', ref);
947
948
  }
948
949
  textInputRef.current = ref;
949
950
  }} key={`textinput-${tag}`} style={[
@@ -952,7 +953,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
952
953
  (themeMode === 'dark' && { color: '#fff' })
953
954
  ]} textAlign={stableTextInputProps && stableTextInputProps['textAlign'] || 'left'} multiline={stableTextInputProps && stableTextInputProps['multiline'] || false} numberOfLines={stableTextInputProps && stableTextInputProps['numberOfLines'] || 1} onChangeText={(searchQuery) => {
954
955
  ref_searchQuery.current = searchQuery;
955
- console.log('AutoPositionedPopup onChangeText rootViews=', rootViews);
956
+ debugLog('AutoPositionedPopup onChangeText rootViews=', rootViews);
956
957
  if (!localSearch) {
957
958
  if (debounceTimerRef.current) {
958
959
  clearTimeout(debounceTimerRef.current);
@@ -971,7 +972,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
971
972
  Keyboard.dismiss();
972
973
  }
973
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) => {
974
- console.log('AutoPositionedPopup.tsx onSubmitEditing e.nativeEvent.text=', e.nativeEvent.text);
975
+ debugLog('AutoPositionedPopup.tsx onSubmitEditing e.nativeEvent.text=', e.nativeEvent.text);
975
976
  onSubmitEditing && onSubmitEditing(e);
976
977
  }}/>);
977
978
  }, [
@@ -990,11 +991,11 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
990
991
  // Render the component following project implementation
991
992
  return useMemo(() => {
992
993
  var _a;
993
- console.log('AutoPositionedPopup render tag=', tag); // Now safe - circular dependency fixed
994
+ debugLog('AutoPositionedPopup render tag=', tag); // Now safe - circular dependency fixed
994
995
  return (<CustomRow>
995
996
  <View style={[styles.contain, style]} ref={refAutoPositionedPopup}>
996
997
  {!state.isFocus || !useTextInput ? (<TouchableOpacity ref={triggerBtnRef} style={[styles.AutoPositionedPopupBtn, AutoPositionedPopupBtnStyle]} disabled={AutoPositionedPopupBtnDisabled} onPress={() => {
997
- console.log('AutoPositionedPopup onPress=', {
998
+ debugLog('AutoPositionedPopup onPress=', {
998
999
  tag,
999
1000
  'state.isFocus': state.isFocus,
1000
1001
  useTextInput,
@@ -1008,7 +1009,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
1008
1009
  // This is critical because triggerBtnRef will become null after isFocus=true
1009
1010
  if (triggerBtnRef.current && (parentScrollViewRef === null || parentScrollViewRef === void 0 ? void 0 : parentScrollViewRef.current)) {
1010
1011
  triggerBtnRef.current.measureInWindow((x, y, width, height) => {
1011
- console.log('AutoPositionedPopup onPress: captured trigger position=', { tag, x, y, width, height });
1012
+ debugLog('AutoPositionedPopup onPress: captured trigger position=', { tag, x, y, width, height });
1012
1013
  triggerPositionRef.current = { x, y, width, height };
1013
1014
  });
1014
1015
  }
@@ -1053,7 +1054,7 @@ const AutoPositionedPopup = memo(forwardRef((props, parentRef) => {
1053
1054
  return Object.assign(Object.assign({}, prevState), { isFocus: true });
1054
1055
  });
1055
1056
  }
1056
- console.log('AutoPositionedPopup onPress done');
1057
+ debugLog('AutoPositionedPopup onPress done');
1057
1058
  }}>
1058
1059
  {!btwChildren ? (<Text style={[
1059
1060
  styles.searchQueryTxt,
@@ -1,3 +1,4 @@
1
+ import { debugLog } from './constants';
1
2
  import { useEffect, useState, useRef } from 'react';
2
3
  import { Keyboard } from 'react-native';
3
4
  // Debounce function
@@ -20,12 +21,12 @@ export const useKeyboardStatus = () => {
20
21
  const timeSinceLastUpdate = currentTime - lastUpdateTimeRef.current;
21
22
  // ✅ FIX: Check state before debounce
22
23
  if (currentKeyboardStatusRef.current === value) {
23
- console.log('KeyboardManager: Skip - Keyboard state unchanged (before debounce)', { value, timeSinceLastUpdate });
24
+ debugLog('KeyboardManager: Skip - Keyboard state unchanged (before debounce)', { value, timeSinceLastUpdate });
24
25
  return;
25
26
  }
26
27
  // ✅ FIX: Skip if the same value is already pending
27
28
  if (pendingValueRef.current === value) {
28
- console.log('KeyboardManager: Skip - Same value already in processing queue', { value });
29
+ debugLog('KeyboardManager: Skip - Same value already in processing queue', { value });
29
30
  return;
30
31
  }
31
32
  // ✅ FIX: Mark the value being processed
@@ -37,11 +38,11 @@ export const useKeyboardStatus = () => {
37
38
  const debouncedSetKeyboardShownInternal = useRef(debounce((value, currentTime, timeSinceLastUpdate) => {
38
39
  // ✅ FIX: Check state again (in case state was updated during debounce)
39
40
  if (currentKeyboardStatusRef.current === value) {
40
- console.log('KeyboardManager: Skip - Keyboard state unchanged (after debounce)', { value, timeSinceLastUpdate });
41
+ debugLog('KeyboardManager: Skip - Keyboard state unchanged (after debounce)', { value, timeSinceLastUpdate });
41
42
  pendingValueRef.current = null;
42
43
  return;
43
44
  }
44
- console.log('KeyboardManager: Setting keyboard status to', value, {
45
+ debugLog('KeyboardManager: Setting keyboard status to', value, {
45
46
  previousValue: currentKeyboardStatusRef.current,
46
47
  timeSinceLastUpdate
47
48
  });
@@ -60,7 +61,7 @@ export const useKeyboardStatus = () => {
60
61
  keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', () => {
61
62
  // ✅ FIX: Add protection at event listener level - skip if keyboard is already open
62
63
  if (currentKeyboardStatusRef.current === true) {
63
- console.log('KeyboardManager: Skip keyboardDidShow event - Keyboard is already open');
64
+ debugLog('KeyboardManager: Skip keyboardDidShow event - Keyboard is already open');
64
65
  return;
65
66
  }
66
67
  debouncedSetKeyboardShown(true);
@@ -68,7 +69,7 @@ export const useKeyboardStatus = () => {
68
69
  keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', () => {
69
70
  // ✅ FIX: Add protection at event listener level - skip if keyboard is already closed
70
71
  if (currentKeyboardStatusRef.current === false) {
71
- console.log('KeyboardManager: Skip keyboardDidHide event - Keyboard is already closed');
72
+ debugLog('KeyboardManager: Skip keyboardDidHide event - Keyboard is already closed');
72
73
  return;
73
74
  }
74
75
  debouncedSetKeyboardShown(false);
@@ -1,3 +1,4 @@
1
+ import { debugLog } from './constants';
1
2
  import React, { createContext, useContext, useEffect, useMemo, useRef, useState } from 'react';
2
3
  import { Pressable, View, Keyboard } from 'react-native';
3
4
  const RootViewContext = createContext(undefined);
@@ -11,13 +12,13 @@ export const RootViewProvider = ({ children }) => {
11
12
  const [searchQuery, setSearchQuery] = useState('');
12
13
  const viewRefs = useRef({});
13
14
  useEffect(() => {
14
- console.log('react-native-auto-positioned-popup RootViewProvider rootViews changed:', rootViews);
15
+ debugLog('react-native-auto-positioned-popup RootViewProvider rootViews changed:', rootViews);
15
16
  }, [rootViews]);
16
17
  const addRootView = (view) => {
17
18
  // const id = `dynamic-view-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
18
19
  const newView = Object.assign({}, view);
19
- console.log('react-native-auto-positioned-popup RootViewProvider addRootView rootViews=', rootViews);
20
- console.log('react-native-auto-positioned-popup RootViewProvider addRootView newView=', newView);
20
+ debugLog('react-native-auto-positioned-popup RootViewProvider addRootView rootViews=', rootViews);
21
+ debugLog('react-native-auto-positioned-popup RootViewProvider addRootView newView=', newView);
21
22
  setRootViews((prev) => [...prev, newView]);
22
23
  };
23
24
  const updateRootView = (id, update) => {
@@ -34,7 +35,7 @@ export const RootViewProvider = ({ children }) => {
34
35
  * @param _rootViews
35
36
  */
36
37
  const removeRootView = (id, force, _rootViews) => {
37
- console.log('react-native-auto-positioned-popup RootViewProvider removeRootView=', { id, force, rootViews, _rootViews });
38
+ debugLog('react-native-auto-positioned-popup RootViewProvider removeRootView=', { id, force, rootViews, _rootViews });
38
39
  // Ensure keyboard is dismissed when force removing all root views
39
40
  if (force) {
40
41
  // Dismiss keyboard first
@@ -44,14 +45,14 @@ export const RootViewProvider = ({ children }) => {
44
45
  // 100ms gives touch event system enough time to process pending events before views are removed
45
46
  setTimeout(() => {
46
47
  setRootViews((prev) => []);
47
- console.log('react-native-auto-positioned-popup RootViewProvider removeRootView setRootViews(prev => []) force=true');
48
+ debugLog('react-native-auto-positioned-popup RootViewProvider removeRootView setRootViews(prev => []) force=true');
48
49
  }, 100);
49
50
  return;
50
51
  }
51
52
  if (rootViews.length > 0 && id) {
52
53
  setRootViews((prev) => prev.filter((view) => view.id !== id));
53
54
  // else {
54
- // console.log('RootViewProvider removeRootView setRootViews(prev => [])')
55
+ // debugLog('RootViewProvider removeRootView setRootViews(prev => [])')
55
56
  // setRootViews(prev => [])
56
57
  // }
57
58
  }
@@ -79,7 +80,7 @@ export const RootViewProvider = ({ children }) => {
79
80
  <>
80
81
  {children}
81
82
  {rootViews.map(({ id, style, component, useModal, onModalClose, centerDisplay }) => {
82
- console.log('react-native-auto-positioned-popup RootViewProvider rootViews.map=', { id, style, component, useModal, centerDisplay });
83
+ debugLog('react-native-auto-positioned-popup RootViewProvider rootViews.map=', { id, style, component, useModal, centerDisplay });
83
84
  return !useModal ? (<View key={id} ref={(r) => {
84
85
  if (r)
85
86
  viewRefs.current[id] = r;
@@ -99,7 +100,7 @@ export const RootViewProvider = ({ children }) => {
99
100
  },
100
101
  centerDisplay && { justifyContent: 'center', alignItems: 'center' },
101
102
  ]} onPress={() => {
102
- console.log('react-native-auto-positioned-popup RootViewProvider Pressable onPress rootViews=', rootViews);
103
+ debugLog('react-native-auto-positioned-popup RootViewProvider Pressable onPress rootViews=', rootViews);
103
104
  removeRootView(id, true);
104
105
  onModalClose && onModalClose();
105
106
  }}>
package/lib/constants.js CHANGED
@@ -3,6 +3,19 @@
3
3
  * These constants can be used with global event emitters to coordinate
4
4
  * search query changes across different components
5
5
  */
6
+
7
+ /**
8
+ * Debug logging control flag - set to false to disable all console.log for performance
9
+ * In React Native debug mode, excessive console.log causes severe performance degradation
10
+ * due to JS Bridge serialization overhead
11
+ */
12
+ export const DEBUG_LOG = false;
13
+ export const debugLog = (...args) => {
14
+ if (DEBUG_LOG) {
15
+ console.log(...args);
16
+ }
17
+ };
18
+
6
19
  export const AutoPositionedPopupEventNames = {
7
20
  /**
8
21
  * Event fired when the search query in AutoPositionedPopup changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-auto-positioned-popup",
3
- "version": "1.2.14",
3
+ "version": "1.2.16",
4
4
  "description": "A highly customizable React Native auto-positioned popup component with search functionality and flexible styling options",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -12,7 +12,7 @@
12
12
  "LICENSE"
13
13
  ],
14
14
  "scripts": {
15
- "build": "npm run clean && tsc -p tsconfig.build.json",
15
+ "build": "npm run clean && tsc -p tsconfig.build.json && node scripts/strip-console-logs.js",
16
16
  "watch": "tsc --watch",
17
17
  "clean": "rimraf lib",
18
18
  "prepare": "npm run build",
@@ -63,8 +63,8 @@
63
63
  "@types/node": "^25.0.3",
64
64
  "@types/react": "^19.2.7",
65
65
  "@types/react-native": "^0.73.0",
66
- "@typescript-eslint/eslint-plugin": "^8.50.1",
67
- "@typescript-eslint/parser": "^8.50.1",
66
+ "@typescript-eslint/eslint-plugin": "^8.51.0",
67
+ "@typescript-eslint/parser": "^8.51.0",
68
68
  "eslint": "^9.39.2",
69
69
  "eslint-plugin-react": "^7.37.5",
70
70
  "eslint-plugin-react-hooks": "^7.0.1",