react-native-auto-positioned-popup 1.2.17 → 1.2.19

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,6 +1,6 @@
1
1
  import { debugLog } from './constants';
2
2
  import React, { createContext, useContext, useEffect, useMemo, useRef, useState } from 'react';
3
- import { Pressable, View, Keyboard } from 'react-native';
3
+ import { Pressable, View, Keyboard, StyleSheet } from 'react-native';
4
4
  // DEBUG FLAG: Set to false to disable all console logs for better performance
5
5
  const ROOTVIEW_DEBUG = false;
6
6
  const debugLog = (...args) => {
@@ -87,56 +87,78 @@ export const RootViewProvider = ({ children }) => {
87
87
  setSearchQuery,
88
88
  }), [addRootView, setRootViewNativeStyle, updateRootView, removeRootView, rootViews, searchQuery, setSearchQuery]);
89
89
  return (<RootViewContext.Provider value={contextValue}>
90
- <>
90
+ {/* CRITICAL FIX: Use View with flex:1 instead of Fragment */}
91
+ {/* Fragment doesn't create actual View, causing absolute positioning to use wrong ancestor */}
92
+ {/* View with flex:1 ensures popup container positions relative to this full-screen View */}
93
+ <View style={rootViewStyles.container}>
91
94
  {children}
92
- {rootViews.map(({ id, style, component, useModal, onModalClose, centerDisplay }) => {
93
- debugLog('react-native-auto-positioned-popup RootViewProvider rootViews.map=', { id, style, component, useModal, centerDisplay });
94
- return !useModal ? (<View key={id} ref={(r) => {
95
- if (r)
96
- viewRefs.current[id] = r;
97
- }} style={[style, { position: 'absolute' }]}>
98
- {component}
99
- </View>) : (<Pressable key={id} style={[
100
- {
101
- flex: 1,
102
- position: 'absolute',
103
- width: '100%',
104
- left: 0,
105
- right: 0,
106
- top: 0,
107
- bottom: 0,
108
- zIndex: 99999999999,
109
- backgroundColor: 'rgba(0,0,0,0.5)',
110
- },
111
- centerDisplay && { justifyContent: 'center', alignItems: 'center' },
112
- ]} onPress={() => {
113
- debugLog('react-native-auto-positioned-popup RootViewProvider Pressable onPress rootViews=', rootViews);
114
- removeRootView(id, true);
115
- onModalClose && onModalClose();
116
- }}>
95
+ {/* CRITICAL: Full-screen container ensures absolute positioning is relative to screen */}
96
+ {/* Without this, popup position may be offset by parent containers */}
97
+ {rootViews.length > 0 && (<View pointerEvents="box-none" style={rootViewStyles.popupContainer}>
98
+ {rootViews.map(({ id, style, component, useModal, onModalClose, centerDisplay }) => {
99
+ // POSITION DEBUG: Log the actual top value being applied (simple format for cleaner logs)
100
+ debugLog(`📍 RENDER_STYLE id=${id} top=${style === null || style === void 0 ? void 0 : style.top} left=${style === null || style === void 0 ? void 0 : style.left} w=${style === null || style === void 0 ? void 0 : style.width} h=${style === null || style === void 0 ? void 0 : style.height} op=${style === null || style === void 0 ? void 0 : style.opacity}`);
101
+ return !useModal ? (<View key={id} ref={(r) => {
102
+ if (r)
103
+ viewRefs.current[id] = r;
104
+ }} style={[style, { position: 'absolute' }]}>
105
+ {component}
106
+ </View>) : (<Pressable key={id} style={[
107
+ {
108
+ flex: 1,
109
+ position: 'absolute',
110
+ width: '100%',
111
+ left: 0,
112
+ right: 0,
113
+ top: 0,
114
+ bottom: 0,
115
+ zIndex: 99999999999,
116
+ backgroundColor: 'rgba(0,0,0,0.5)',
117
+ },
118
+ centerDisplay && { justifyContent: 'center', alignItems: 'center' },
119
+ ]} onPress={() => {
120
+ debugLog('react-native-auto-positioned-popup RootViewProvider Pressable onPress rootViews=', rootViews);
121
+ removeRootView(id, true);
122
+ onModalClose && onModalClose();
123
+ }}>
117
124
  <View ref={(r) => {
118
- if (r)
119
- viewRefs.current[id] = r;
120
- }} style={[{ position: 'absolute' }, style]}>
125
+ if (r)
126
+ viewRefs.current[id] = r;
127
+ }} style={[{ position: 'absolute' }, style]}>
121
128
  {component}
122
129
  </View>
123
130
  </Pressable>);
124
- // (<Modal
125
- // animationType="none"
126
- // transparent={false}
127
- // visible={true}
128
- // presentationStyle="overFullScreen" // iOS特定属性
129
- // onRequestClose={() => {
130
- // // Android 返回鍵按下時的回調
131
- // onModalClose && onModalClose()
132
- // }}
133
- // key={id}
134
- // >
135
- // </Modal>)
136
- })}
137
- </>
131
+ // (<Modal
132
+ // animationType="none"
133
+ // transparent={false}
134
+ // visible={true}
135
+ // presentationStyle="overFullScreen" // iOS特定属性
136
+ // onRequestClose={() => {
137
+ // // Android 返回鍵按下時的回調
138
+ // onModalClose && onModalClose()
139
+ // }}
140
+ // key={id}
141
+ // >
142
+ // </Modal>)
143
+ })}
144
+ </View>)}
145
+ </View>
138
146
  </RootViewContext.Provider>);
139
147
  };
148
+ // Styles for RootView container - extracted for better performance
149
+ const rootViewStyles = StyleSheet.create({
150
+ container: {
151
+ flex: 1,
152
+ },
153
+ popupContainer: {
154
+ position: 'absolute',
155
+ top: 0,
156
+ left: 0,
157
+ right: 0,
158
+ bottom: 0,
159
+ zIndex: 99999,
160
+ },
161
+ });
140
162
  /*
141
163
  const { addRootView, updateRootView, removeRootView ,searchQuery } = useRootView();
142
164
  */
@@ -1 +1 @@
1
- {"version":3,"file":"RootViewContext.js","sourceRoot":"","sources":["../src/RootViewContext.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"RootViewContext.js","sourceRoot":"","sources":["../src/RootViewContext.tsx"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-auto-positioned-popup",
3
- "version": "1.2.17",
3
+ "version": "1.2.19",
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",
@@ -1,14 +1,24 @@
1
1
  // Module load marker - unique ID for tracking code version
2
+ // V19f (2025-01-04): CORRECT direction for coordinate adjustment - ADD statusBarHeight to move popup DOWN
3
+ // Wait 1 second for KeyboardAwareScrollView to stabilize, then use measureInWindow to get trigger's FINAL position
4
+ // NOTE: Parent component (KeyboardAwareScrollView) is responsible for scrolling trigger into view
2
5
  // DEBUG FLAG: Set to false to disable all console logs for better performance
3
- const POPUP_DEBUG = false;
6
+ const POPUP_DEBUG = false; // DISABLED: Too many logs cause app freeze
7
+ const POPUP_POSITION_DEBUG = true; // Only log positioning calculations
4
8
  const debugLog = (...args: any[]) => {
5
9
  if (POPUP_DEBUG) {
6
10
  console.log(...args);
7
11
  }
8
12
  };
13
+ // Separate logging function for position-related logs only
14
+ const positionDebugLog = (...args: any[]) => {
15
+ if (POPUP_POSITION_DEBUG) {
16
+ console.log(...args);
17
+ }
18
+ };
9
19
 
10
20
  // Only log module load in debug mode
11
- debugLog('POPUP_MODULE_V17_LOADED at ' + new Date().toISOString());
21
+ positionDebugLog('POPUP_MODULE_V19f_LOADED at ' + new Date().toISOString() + ' (Parent handles scroll)');
12
22
 
13
23
  import React, {
14
24
  ForwardedRef,
@@ -382,6 +392,8 @@ const AutoPositionedPopup = memo(
382
392
  const ref_searchQuery = useRef<string>('');
383
393
  // Store trigger button position when clicked (before it's replaced by TextInput)
384
394
  const triggerPositionRef = useRef<{x: number; y: number; width: number; height: number} | null>(null);
395
+ // V19: Track keyboard height for accurate popup positioning
396
+ const keyboardHeightRef = useRef<number>(0);
385
397
  // Add ref to track previous keyboard state to avoid false triggers during parent component re-renders
386
398
  const prevIsKeyboardFullyShownRef = useRef<boolean>(false);
387
399
  const prevPropsRef = useRef<{
@@ -416,11 +428,16 @@ const AutoPositionedPopup = memo(
416
428
  const searchQueryRef = useRef<string>(''); // Use ref instead of state to avoid re-renders
417
429
  // Refs to store latest values for useEffect without adding to dependency array
418
430
  const dataRef = useRef<SelectedItem[]>(data);
419
- const isKeyboardFullyShown = useKeyboardStatus();
431
+ // V19: useKeyboardStatus now returns { isShown, height } for accurate positioning
432
+ const keyboardStatus = useKeyboardStatus();
433
+ const isKeyboardFullyShown = keyboardStatus.isShown;
420
434
  const ref_isKeyboardFullyShown = useRef<boolean>(isKeyboardFullyShown);
421
435
  useEffect(() => {
422
436
  ref_isKeyboardFullyShown.current = isKeyboardFullyShown;
423
- }, [isKeyboardFullyShown])
437
+ // V19: Store keyboard height for popup positioning calculations
438
+ keyboardHeightRef.current = keyboardStatus.height;
439
+ positionDebugLog(`KEYBOARD_HEIGHT_UPDATE: height=${keyboardStatus.height} isShown=${isKeyboardFullyShown}`);
440
+ }, [keyboardStatus.isShown, keyboardStatus.height])
424
441
  const theme = defaultTheme;
425
442
 
426
443
  /**
@@ -674,30 +691,46 @@ const AutoPositionedPopup = memo(
674
691
  const statusBarHeight = getStatusBarHeight();
675
692
  if (useTextInput) {
676
693
  if (isKeyboardFullyShown && hasAddedRootView.current && !hasShownRootView.current && state.isFocus) {
677
- // KEYBOARD AVOIDANCE FIX: Scroll parent ScrollView to keep trigger visible
678
- // When keyboard appears, the trigger button may be covered. If parentScrollViewRef
679
- // is provided, scroll the parent to keep the trigger visible above the keyboard.
680
- if (parentScrollViewRef?.current) {
681
- debugLog('AutoPositionedPopup: Keyboard appeared, scrolling parent to keep trigger visible');
682
- // Use a slight delay to ensure keyboard animation has started
683
- setTimeout(() => {
684
- scrollToTriggerWithMeasure();
685
- }, 100);
694
+ // KEYBOARD AVOIDANCE FIX: Use KeyboardAwareScrollView's native scrollToFocusedInput method
695
+ // This properly scrolls to the dynamically created TextInput without causing double scrolling.
696
+ // The previous custom scrollToTriggerWithMeasure() caused over-scrolling issues.
697
+ if (parentScrollViewRef?.current && textInputRef.current) {
698
+ debugLog('AutoPositionedPopup: Keyboard appeared, using scrollToFocusedInput to scroll parent');
699
+ // Use KeyboardAwareScrollView's native method to scroll to the focused TextInput
700
+ // This is more reliable than custom scroll calculations
701
+ const scrollView = parentScrollViewRef.current;
702
+ if (typeof scrollView.scrollToFocusedInput === 'function') {
703
+ // findNodeHandle is needed to get the native node reference
704
+ const nodeHandle = findNodeHandle(textInputRef.current);
705
+ if (nodeHandle) {
706
+ // scrollToFocusedInput expects a ReactNode, use the TextInput ref
707
+ scrollView.scrollToFocusedInput(textInputRef.current, scrollExtraHeight);
708
+ debugLog('AutoPositionedPopup: Called scrollToFocusedInput with extraHeight=', scrollExtraHeight);
709
+ }
710
+ } else {
711
+ debugLog('AutoPositionedPopup: scrollToFocusedInput not available, skipping scroll');
712
+ }
686
713
  }
687
714
 
688
715
  // CRITICAL FIX FOR KEYBOARD POSITION CALCULATION
689
716
  // Problem: When keyboard appears, the page shifts up but measureInWindow executes too early
690
- // Solution: Wait for keyboard animation (300ms) + use requestAnimationFrame for next render frame
717
+ // Solution: Wait for keyboard animation + page scroll to complete before measuring
691
718
  //
692
719
  // Timing breakdown:
693
720
  // 1. Keyboard animation: ~250-300ms (iOS/Android)
694
- // 2. Page shift animation: ~200-300ms (KeyboardAvoidingView)
695
- // 3. Layout tree update: ~50-100ms (React Native)
696
- // Total: ~500-700ms needed for stable layout
721
+ // 2. Page shift animation: ~300-500ms (KeyboardAwareScrollView)
722
+ // 3. Layout tree update: ~100-200ms (React Native)
723
+ // Total: ~700-1000ms needed for stable layout
697
724
  //
698
- // Strategy: setTimeout(300ms) waits for most animations to complete,
725
+ // USER REQUEST (2025-01-04): Wait 1 second (1000ms) after keyboard appears
726
+ // to ensure trigger component position has fully stabilized after scroll
727
+ //
728
+ // Strategy: setTimeout(1000ms) waits for all animations to complete,
699
729
  // then requestAnimationFrame ensures measurement happens after next render frame
730
+ const KEYBOARD_STABILIZATION_DELAY = 500; // 500ms as requested by user
731
+ positionDebugLog(`POPUP_WAIT: Waiting ${KEYBOARD_STABILIZATION_DELAY}ms for keyboard/scroll stabilization, tag=${tag}`);
700
732
  setTimeout(() => {
733
+ positionDebugLog(`POPUP_MEASURE_START: ${KEYBOARD_STABILIZATION_DELAY}ms elapsed, now measuring position for tag=${tag}`);
701
734
  requestAnimationFrame(() => {
702
735
  // CRITICAL FIX: Measure CURRENT position AFTER keyboard animation completes
703
736
  // DO NOT use stored triggerPositionRef because keyboard may have shifted the view up
@@ -705,10 +738,7 @@ const AutoPositionedPopup = memo(
705
738
  // which reflects the ACTUAL current position after keyboard shift
706
739
 
707
740
  // DEBUG: Log both refs to compare their positions
708
- debugLog('AutoPositionedPopup DEBUG: refs status=', {
709
- hasTextInputRef: !!textInputRef.current,
710
- hasRefAutoPositionedPopup: !!refAutoPositionedPopup.current,
711
- });
741
+ positionDebugLog(`POPUP_REFS: textInputRef=${!!textInputRef.current} refAutoPositionedPopup=${!!refAutoPositionedPopup.current}`);
712
742
 
713
743
  // Measure BOTH refs for comparison
714
744
  if (textInputRef.current && refAutoPositionedPopup.current) {
@@ -749,111 +779,72 @@ const AutoPositionedPopup = memo(
749
779
  const usingTextInputRef = measureTarget === textInputRef.current;
750
780
  debugLog('AutoPositionedPopup useTextInput: using measureTarget=', usingTextInputRef ? 'textInputRef' : 'refAutoPositionedPopup');
751
781
 
752
- // Measure CURRENT position (after keyboard shifted the view)
782
+ // V19f: Position popup above trigger
783
+ // Parent KeyboardAwareScrollView is responsible for scrolling trigger into view
784
+ // This component only handles popup positioning relative to trigger's FINAL position
785
+ const screenHeight = Dimensions.get('window').height;
786
+ const screenWidth = Dimensions.get('window').width;
787
+ const currentKeyboardHeight = keyboardHeightRef.current;
788
+ const popupHeight = listLayout.height; // 200px
789
+
790
+ positionDebugLog(`V19f_SCREEN: height=${screenHeight} width=${screenWidth} keyboardH=${currentKeyboardHeight} statusBarH=${statusBarHeight}`);
791
+
753
792
  measureTarget.measureInWindow((x: number | undefined, y: number | undefined, width: number | undefined, height: number | undefined) => {
754
- debugLog('AutoPositionedPopup useTextInput: measured position for positioning=', {
755
- x, y, width, height,
756
- measureTarget: usingTextInputRef ? 'textInputRef' : 'refAutoPositionedPopup'
757
- });
793
+ positionDebugLog(`V19f_MEASURE: triggerX=${x} triggerY=${y} triggerW=${width} triggerH=${height}`);
758
794
 
759
- // Handle undefined values (can happen during navigation transitions)
795
+ // Handle undefined values
760
796
  if (x === undefined || y === undefined || width === undefined || height === undefined) {
761
- debugLog('AutoPositionedPopup useTextInput: measureInWindow returned undefined, using fallback');
762
- const screenHeightFallback = Dimensions.get('window').height;
763
- const screenWidthFallback = Dimensions.get('window').width;
764
- const fallbackY = (screenHeightFallback - listLayout.height) / 2;
765
- x = screenWidthFallback * 0.05;
766
- y = fallbackY;
767
- width = screenWidthFallback * 0.9;
768
- height = 50;
797
+ positionDebugLog('V19f: undefined values, using center fallback');
798
+ const fallbackY = (screenHeight - currentKeyboardHeight - popupHeight) / 2;
799
+ updateRootView(tag, {
800
+ style: { top: fallbackY, left: popUpViewStyle?.left, width: popUpViewStyle?.width, height: popupHeight, opacity: 1 }
801
+ });
802
+ hasShownRootView.current = true;
803
+ return;
769
804
  }
770
805
 
771
- // Calculate screen height and popup position
772
- const screenHeight = Dimensions.get('window').height;
773
- debugLog('AutoPositionedPopup useTextInput positioning data=', {
774
- screenHeight,
775
- componentY: y,
776
- componentHeight: height,
777
- listHeight: listLayout.height
778
- });
806
+ const triggerTop = y;
807
+ const triggerHeight = height;
808
+ const triggerBottom = y + height;
809
+ const keyboardTop = screenHeight - currentKeyboardHeight;
779
810
 
780
- // POSITIONING LOGIC (with keyboard):
781
- // Simple rule: popup must TOUCH the trigger with NO GAP
782
- // 1. Default: show ABOVE trigger (popup bottom touches trigger top)
783
- // 2. If ABOVE would overlap status bar: show BELOW (popup top touches trigger bottom)
784
-
785
- debugLog('AutoPositionedPopup POSITIONING:', {
786
- triggerY: y,
787
- triggerHeight: height,
788
- triggerBottom: y + height,
789
- popupHeight: listLayout.height,
790
- screenHeight,
791
- statusBarHeight
792
- });
811
+ positionDebugLog(`V19f_ANALYSIS: triggerTop=${triggerTop} triggerBottom=${triggerBottom} keyboardTop=${keyboardTop}`);
793
812
 
794
- // 1. Default: show popup ABOVE the trigger
795
- // Popup has internal padding (12px from autoPositionedPopupList style)
796
- // To make popup CONTENT touch trigger (not container), add padding offset
797
- // Container bottom at y + POPUP_PADDING, content bottom at y (no gap)
798
- const POPUP_PADDING = 12;
799
- let popupY = y - listLayout.height + POPUP_PADDING;
813
+ // V19f: Position popup DIRECTLY above trigger
814
+ // ADD statusBarHeight to close the gap (coordinates adjustment)
815
+ let popupY = triggerTop - popupHeight + statusBarHeight;
800
816
  let position = 'ABOVE';
801
817
 
802
- debugLog('AutoPositionedPopup: trying ABOVE position:', {
803
- popupY,
804
- popupBottom: popupY + listLayout.height,
805
- contentBottom: popupY + listLayout.height - POPUP_PADDING,
806
- triggerTop: y,
807
- paddingOffset: POPUP_PADDING,
808
- wouldOverlapStatusBar: popupY < statusBarHeight
809
- });
818
+ positionDebugLog(`V19f_CALC: base=${triggerTop - popupHeight} + statusBarH=${statusBarHeight} = popupY=${popupY}`);
810
819
 
811
- // 2. If showing ABOVE would go behind status bar, show BELOW instead
812
- if (popupY < statusBarHeight) {
813
- // Show BELOW: popup top at trigger bottom
814
- // Use trigger's measured height as buffer to account for row padding
815
- // The TextInput is only part of the trigger row - row height scales with trigger height
816
- const BELOW_BUFFER = height;
817
- popupY = y + height + BELOW_BUFFER;
820
+ // Safety check: ensure popup doesn't go above screen top
821
+ if (popupY < 0) {
822
+ // If popup would go off screen top, position it BELOW trigger instead
823
+ popupY = triggerBottom + statusBarHeight;
818
824
  position = 'BELOW';
819
-
820
- debugLog('AutoPositionedPopup: using BELOW position (ABOVE overlaps status bar):', {
821
- popupY,
822
- triggerBottom: y + height,
823
- buffer: BELOW_BUFFER,
824
- actualGap: BELOW_BUFFER
825
- });
826
-
827
- // 3. Safety check: if BELOW would go off screen bottom, clamp it
828
- const maxY = screenHeight - listLayout.height;
825
+ // Clamp to stay above keyboard
826
+ const maxY = keyboardTop - popupHeight;
829
827
  if (popupY > maxY) {
830
828
  popupY = maxY;
831
- debugLog('AutoPositionedPopup: clamped to screen bottom:', { popupY, maxY });
832
829
  }
833
- } else {
834
- debugLog('AutoPositionedPopup: using ABOVE position (preferred)');
830
+ positionDebugLog(`V19f_BELOW: popupY=${popupY} (clamped to stay above keyboard)`);
835
831
  }
836
832
 
837
- debugLog('AutoPositionedPopup FINAL POSITION:', { position, popupY, touchesTrigger: true });
838
-
839
- ref_listPos.current = {x: x, y: popupY, width: width};
840
- debugLog('AutoPositionedPopup useTextInput final position=', ref_listPos.current);
841
-
842
- // Use updateRootView instead of setRootViewNativeStyle for more reliable style updates
843
- // setNativeProps may not work correctly when initial style is in an array
844
- const newStyle = {
845
- top: ref_listPos.current?.y,
846
- left: popUpViewStyle?.left,
847
- width: popUpViewStyle?.width,
848
- height: listLayout.height,
849
- opacity: 1,
850
- };
851
- debugLog('AutoPositionedPopup useTextInput: applying new style via updateRootView=', newStyle);
852
- updateRootView(tag, {style: newStyle});
833
+ // V19f: Verification
834
+ const popupBottom = popupY + popupHeight;
835
+ const gapPixels = triggerTop - popupBottom;
836
+
837
+ positionDebugLog(`V19f_RESULT: position=${position} popupY=${popupY} popupBottom=${popupBottom}`);
838
+ positionDebugLog(`V19f_GAP: trigger_top=${triggerTop} - popup_bottom=${popupBottom} = gap=${gapPixels}px`);
839
+
840
+ ref_listPos.current = {x, y: popupY, width};
841
+ updateRootView(tag, {
842
+ style: { top: popupY, left: popUpViewStyle?.left, width: popUpViewStyle?.width, height: listLayout.height, opacity: 1 }
843
+ });
853
844
  hasShownRootView.current = true;
854
845
  });
855
846
  });
856
- }, 300) // 300ms is sufficient for keyboard animation, as proven by user testing (even 3000ms didn't fix wrong logic)
847
+ }, KEYBOARD_STABILIZATION_DELAY) // 1000ms to wait for keyboard + scroll stabilization (user request 2025-01-04)
857
848
  } else if (!isKeyboardFullyShown && ref_isFocus.current && keyboardStateChanged) {
858
849
  // Only execute close logic when keyboard state actually changes from true to false
859
850
  debugLog(
@@ -938,11 +929,10 @@ const AutoPositionedPopup = memo(
938
929
  state.selectedItem, showListEmptyComponent, themeMode
939
930
  ]);
940
931
 
941
- // V16: All positioning logic is now in the useEffect above (calculateOptimalPosition + processPosition)
942
- // V16 FIX: Capture position in onPress callback BEFORE setState is called
943
- // This ensures triggerPositionRef.current is set when useEffect runs
932
+ // V18: All positioning logic is now in the useEffect above
933
+ // V18 FIX (2025-01-04): Wait 1000ms after keyboard appears before measuring position
934
+ // This ensures trigger position is stable after KeyboardAwareScrollView scrolls
944
935
  // Formula: top = componentY - popupHeight (popup bottom touches trigger top exactly)
945
- debugLog('🟢 POPUP_MODULE_V16_LOADED - capturing position in onPress callback before setState');
946
936
 
947
937
  // Imperative handle for parent component access
948
938
  useImperativeHandle(
@@ -1341,29 +1331,29 @@ const AutoPositionedPopup = memo(
1341
1331
  );
1342
1332
  }, [
1343
1333
  tag,
1344
- // �?CRITICAL FIX: Remove all props that may change frequently or are inline functions
1334
+ // CRITICAL FIX: Remove all props that may change frequently or are inline functions
1345
1335
  // Changes to these props should not cause the entire component tree to recreate, especially TextInput
1346
- // fetchData, // �?Removed: inline function
1347
- // renderItem, // �?Removed: possibly inline function
1348
- // onItemSelected, // �?Removed: possibly inline function
1349
- // onSubmitEditing, // �?Removed: possibly inline function
1336
+ // fetchData, // Removed: inline function
1337
+ // renderItem, // Removed: possibly inline function
1338
+ // onItemSelected, // Removed: possibly inline function
1339
+ // onSubmitEditing, // Removed: possibly inline function
1350
1340
  localSearch,
1351
- // placeholder, // �?Removed: may change
1352
- // textAlign, // �?Removed: may change
1341
+ // placeholder, // Removed: may change
1342
+ // textAlign, // Removed: may change
1353
1343
  pageSize,
1354
1344
  selectedItem,
1355
- // CustomRow, // �?Removed: inline function, new reference each time
1345
+ // CustomRow, // Removed: inline function, new reference each time
1356
1346
  useTextInput,
1357
- // btwChildren, // �?Removed: inline function
1358
- // keyExtractor, // �?Removed: possibly inline function
1359
- // AutoPositionedPopupBtnStyle, // �?Removed: possibly inline object
1360
- // CustomPopView, // �?Removed: may change
1361
- // CustomPopViewStyle, // �?Removed: may change
1347
+ // btwChildren, // Removed: inline function
1348
+ // keyExtractor, // Removed: possibly inline function
1349
+ // AutoPositionedPopupBtnStyle, // Removed: possibly inline object
1350
+ // CustomPopView, // Removed: may change
1351
+ // CustomPopViewStyle, // Removed: may change
1362
1352
  forceRemoveAllRootViewOnItemSelected,
1363
1353
  state.isFocus,
1364
1354
  showListEmptyComponent,
1365
1355
  emptyText,
1366
- // �?Removed most dependencies that may cause re-rendering, keeping only core dependencies that truly affect component structure
1356
+ // Removed most dependencies that may cause re-rendering, keeping only core dependencies that truly affect component structure
1367
1357
  // This prevents TextInput recreation due to inline functions/objects during parent component redraws
1368
1358
  ]);
1369
1359
  }
@@ -1,5 +1,5 @@
1
1
  import React, { useEffect, useState, useRef } from 'react';
2
- import { Keyboard, EmitterSubscription, Platform } from 'react-native';
2
+ import { Keyboard, EmitterSubscription, Platform, KeyboardEvent } from 'react-native';
3
3
 
4
4
  // DEBUG FLAG: Set to false to disable all console logs for better performance
5
5
  const KEYBOARD_DEBUG = false;
@@ -18,8 +18,16 @@ const debounce = (func: Function, delay: number) => {
18
18
  };
19
19
  };
20
20
 
21
- export const useKeyboardStatus = () => {
21
+ // V19: Return type for keyboard status hook - includes height for accurate positioning
22
+ interface KeyboardStatus {
23
+ isShown: boolean;
24
+ height: number;
25
+ }
26
+
27
+ export const useKeyboardStatus = (): KeyboardStatus => {
22
28
  const [isKeyboardFullyShown, setIsKeyboardFullyShown] = useState(false);
29
+ // V19: Track keyboard height for popup positioning
30
+ const [keyboardHeight, setKeyboardHeight] = useState(0);
23
31
 
24
32
  // Add state cache to avoid repeatedly setting the same state
25
33
  const currentKeyboardStatusRef = useRef<boolean>(false);
@@ -83,7 +91,12 @@ export const useKeyboardStatus = () => {
83
91
  // Remove Will event listeners to avoid duplicate triggers and state race conditions
84
92
  keyboardDidShowListener = Keyboard.addListener(
85
93
  'keyboardDidShow',
86
- () => {
94
+ (e: KeyboardEvent) => {
95
+ // V19: Capture keyboard height from event for accurate popup positioning
96
+ const height = e.endCoordinates?.height || 0;
97
+ debugLog('KeyboardManager: keyboardDidShow event', { height });
98
+ setKeyboardHeight(height);
99
+
87
100
  // ✅ FIX: Add protection at event listener level - skip if keyboard is already open
88
101
  if (currentKeyboardStatusRef.current === true) {
89
102
  debugLog('KeyboardManager: Skip keyboardDidShow event - Keyboard is already open');
@@ -95,6 +108,9 @@ export const useKeyboardStatus = () => {
95
108
  keyboardDidHideListener = Keyboard.addListener(
96
109
  'keyboardDidHide',
97
110
  () => {
111
+ // V19: Reset keyboard height when keyboard hides
112
+ setKeyboardHeight(0);
113
+
98
114
  // ✅ FIX: Add protection at event listener level - skip if keyboard is already closed
99
115
  if (currentKeyboardStatusRef.current === false) {
100
116
  debugLog('KeyboardManager: Skip keyboardDidHide event - Keyboard is already closed');
@@ -110,5 +126,6 @@ export const useKeyboardStatus = () => {
110
126
  };
111
127
  }, []);
112
128
 
113
- return isKeyboardFullyShown;
129
+ // V19: Return both keyboard visibility status and height
130
+ return { isShown: isKeyboardFullyShown, height: keyboardHeight };
114
131
  };