react-native-auto-positioned-popup 1.0.4 → 1.0.6

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.
@@ -3,7 +3,7 @@ import React, {
3
3
  forwardRef,
4
4
  ForwardRefExoticComponent,
5
5
  memo,
6
- MemoExoticComponent,
6
+ MemoExoticComponent, MutableRefObject,
7
7
  useCallback,
8
8
  useEffect,
9
9
  useImperativeHandle,
@@ -18,14 +18,18 @@ import {
18
18
  TextInput as RNTextInput,
19
19
  TouchableOpacity,
20
20
  View,
21
- ViewStyle,
22
21
  } from 'react-native';
23
- import {AdvancedFlatList} from 'react-native-advanced-flatlist';
22
+ // @ts-ignore - Skip type checking for third-party library with type issues
23
+ import {AdvancedFlatList as AdvancedFlatListLib} from 'react-native-advanced-flatlist';
24
+ // @ts-ignore - Direct import from source when using fake data
25
+ import AdvancedFlatListSource from 'react-native-advanced-flatlist/src/AdvancedFlatList.tsx';
24
26
  import {TextInputSubmitEditingEventData} from 'react-native/Libraries/Components/TextInput/TextInput';
25
27
  import {LayoutRectangle, NativeSyntheticEvent} from 'react-native/Libraries/Types/CoreEventTypes';
26
28
  import {AutoPositionedPopupProps, Data, SelectedItem} from './AutoPositionedPopupProps';
27
29
  import styles from './AutoPositionedPopup.style';
28
30
  import {useRootView} from './RootViewContext';
31
+ import {useKeyboardStatus} from './KeyboardManager';
32
+ import {useSafeAreaInsets} from "react-native-safe-area-context";
29
33
 
30
34
  // Lightweight emitter to decouple TextInput and list without re-rendering context
31
35
  type QueryListener = (query: string) => void;
@@ -64,144 +68,238 @@ const defaultTheme: Theme = {
64
68
 
65
69
  // List item component for rendering individual items
66
70
  const ListItem: React.FC<{
71
+ updateState: (key: string, value: SelectedItem) => void;
67
72
  item: SelectedItem;
68
73
  index: number;
69
74
  selectedItem?: SelectedItem;
70
- onItemPress: (item: SelectedItem) => void;
71
- theme: Theme;
72
- rootViewsRef?: React.MutableRefObject<any[]>;
73
- selectedItemBackgroundColor?: string;
74
- }> = memo(({item, index, selectedItem, onItemPress, theme, rootViewsRef, selectedItemBackgroundColor = 'rgba(116, 116, 128, 0.08)'}) => {
75
- const isSelected = item.id === selectedItem?.id;
76
-
77
- return useMemo(() => (
78
- <TouchableOpacity
79
- key={item.id}
80
- style={[
81
- styles.commonModalRow,
82
- {
83
- backgroundColor: isSelected ? selectedItemBackgroundColor : 'transparent',
84
- borderColor: theme.colors.border,
85
- },
86
- ]}
87
- onPress={() => {
88
- console.log('AutoPositionedPopup.tsx ListItem onPress item=', item);
89
- if (rootViewsRef) {
90
- console.log('AutoPositionedPopup.tsx ListItem onPress rootViews=', rootViewsRef.current);
91
- }
92
- onItemPress(item);
93
- }}
94
- >
95
- <Text
96
- style={[styles.ListItemCode, {color: theme.colors.text}]}
97
- numberOfLines={1}
98
- ellipsizeMode="tail"
99
- >
100
- {item.title}
101
- </Text>
102
- </TouchableOpacity>
103
- ), [item, index, selectedItem, onItemPress, theme, rootViewsRef, isSelected, selectedItemBackgroundColor]);
104
- });
75
+ }> = memo(
76
+ ({
77
+ updateState,
78
+ item,
79
+ index,
80
+ selectedItem,
81
+ }: {
82
+ updateState: (key: string, value: SelectedItem) => void;
83
+ item: SelectedItem;
84
+ index: number;
85
+ selectedItem?: SelectedItem;
86
+ }): React.JSX.Element => {
87
+ const {addRootView, setRootViewNativeStyle, removeRootView, rootViews} = useRootView();
88
+ const rootViewsRef = useRef(rootViews);
89
+ useEffect(() => {
90
+ rootViewsRef.current = rootViews;
91
+ }, [rootViews]);
92
+ return useMemo(() => {
93
+ // console.log('AutoPositionedPopup.tsx ListItem index=', index);
94
+ // console.log('AutoPositionedPopup.tsx ListItem item=', item);
95
+ const isSelected = item.id === selectedItem?.id;
96
+ return (
97
+ <TouchableOpacity
98
+ key={item.id}
99
+ style={[
100
+ styles.commonModalRow,
101
+ {backgroundColor: isSelected ? 'rgba(116, 116, 128, 0.08)' : 'transparent'},
102
+ ]}
103
+ onPress={() => {
104
+ // console.log('AutoPositionedPopup.tsx ListItem onPress item=', item); // Commented to prevent spam
105
+ // console.log('AutoPositionedPopup.tsx ListItem onPress rootViews=', rootViewsRef.current); // Commented to prevent spam
106
+ updateState('selectedItem', item);
107
+ }}
108
+ >
109
+ <Text style={styles.ListItemCode} numberOfLines={1} ellipsizeMode="tail">
110
+ {item.title}
111
+ </Text>
112
+ </TouchableOpacity>
113
+ );
114
+ }, [updateState, item, index, selectedItem, rootViewsRef]);
115
+ }
116
+ );
105
117
 
106
118
  // Popup list component with AdvancedFlatList
107
- interface PopupListProps {
108
- data: SelectedItem[];
109
- selectedItem?: SelectedItem;
110
- onItemPress: (item: SelectedItem) => void;
119
+ interface AutoPositionedPopupListProps {
120
+ tag: string;
121
+ updateState: (key: string, value: any) => void;
122
+ fetchData: ({
123
+ pageIndex,
124
+ pageSize,
125
+ searchQuery,
126
+ }: {
127
+ pageIndex: number;
128
+ pageSize: number;
129
+ searchQuery?: string;
130
+ }) => Promise<Data | null>;
131
+ keyExtractor?: (item: SelectedItem) => string; //keyExtractor={item => item?.id}
111
132
  renderItem?: ({item, index}: { item: SelectedItem; index: number }) => React.ReactElement;
112
- keyExtractor?: (item: SelectedItem) => string;
113
- theme: Theme;
114
- rootViewsRef?: React.MutableRefObject<any[]>;
115
- fetchData?: (params: { pageIndex: number; pageSize: number; searchQuery?: string }) => Promise<Data | null>;
133
+ selectedItem?: SelectedItem;
116
134
  localSearch?: boolean;
117
135
  pageSize?: number;
118
- onDataUpdate?: (newData: SelectedItem[]) => void;
119
- selectedItemBackgroundColor?: string;
120
136
  }
121
137
 
122
- const PopupList: React.FC<PopupListProps> = memo(({
123
- data,
124
- selectedItem,
125
- onItemPress,
126
- renderItem,
127
- keyExtractor = (item: SelectedItem) => String(item.id),
128
- theme,
129
- rootViewsRef,
130
- fetchData,
131
- localSearch = false,
132
- pageSize = 20,
133
- onDataUpdate,
134
- selectedItemBackgroundColor,
135
- }) => {
136
- const [internalData, setInternalData] = useState<SelectedItem[]>(data);
137
- const searchQueryRef = useRef<string>('');
138
-
139
- // Sync external data changes
140
- useEffect(() => {
141
- setInternalData(data);
142
- }, [data]);
143
-
144
- // Listen to search query changes
145
- useEffect(() => {
146
- const unsubscribe = subscribeQueryChange(async (newQuery: string) => {
147
- console.log('PopupList subscribeQueryChange newQuery=', newQuery);
148
- searchQueryRef.current = newQuery;
149
-
150
- if (fetchData) {
151
- try {
152
- const result = await fetchData({
153
- pageIndex: 0,
154
- pageSize,
155
- searchQuery: newQuery,
138
+ const AutoPositionedPopupList: React.FC<AutoPositionedPopupListProps> = memo(
139
+ ({
140
+ tag,
141
+ updateState,
142
+ fetchData,
143
+ keyExtractor = (item) => String(item.id),
144
+ renderItem,
145
+ selectedItem,
146
+ localSearch,
147
+ pageSize,
148
+ }: AutoPositionedPopupListProps): React.JSX.Element => {
149
+ const [state, setState] = useState<{
150
+ selectedItem?: SelectedItem;
151
+ localData: SelectedItem[];
152
+ }>({
153
+ selectedItem: selectedItem,
154
+ localData: [],
155
+ });
156
+ // Define an interface that matches the methods we need from CsxFlatList
157
+ const ref_list = useRef<{ scrollToTop: () => void; refresh: () => void } | null>(null);
158
+ const ref_searchQuery = useRef<string>('');
159
+ const {searchQuery, setSearchQuery, rootViews} = useRootView();
160
+ const rootViewsRef = useRef(rootViews);
161
+ useEffect(() => {
162
+ rootViewsRef.current = rootViews;
163
+ }, [rootViews]);
164
+ /**
165
+ * componentDidMount && componentWillUnmount
166
+ */
167
+ useEffect(() => {
168
+ (async () => {
169
+ })();
170
+ console.log(`AutoPositionedPopupList componentDidMount`);
171
+ //componentWillUnmount
172
+ return () => {
173
+ console.log(`AutoPositionedPopupList componentWillUnmount`);
174
+ setSearchQuery('');
175
+ };
176
+ }, []);
177
+ // useEffect(() => {
178
+ // // 監聽 TextInput 事件,收到就刷新列表,不依賴 global searchQuery
179
+ // // 將最新的 searchQuery 同步到 list 專用的 ref,供 _fetchData 使用
180
+ // ref_searchQuery.current = searchQuery;
181
+ // console.log('AutoPositionedPopupList useEffect searchQuery=', searchQuery);
182
+ // console.log('AutoPositionedPopupList useEffect state.localData=', state.localData);
183
+ // console.log('AutoPositionedPopupList useEffect ref_list.current=', ref_list.current);
184
+ // console.log('AutoPositionedPopupList useEffect localSearch=', localSearch);
185
+ // if (ref_list.current && (localSearch && state.localData.length > 0 || !localSearch)) {
186
+ // ref_list.current.scrollToTop();
187
+ // ref_list.current.refresh();
188
+ // }
189
+ // }, [searchQuery, state.localData, localSearch]);
190
+ useEffect(() => {
191
+ const unsubscribe = subscribeQueryChange((newQuery: string) => {
192
+ console.log('AutoPositionedPopupList useEffect subscribeQueryChange newQuery=', newQuery);
193
+ ref_searchQuery.current = newQuery;
194
+ if (ref_list.current) {
195
+ ref_list.current.scrollToTop();
196
+ ref_list.current.refresh();
197
+ }
198
+ });
199
+ return unsubscribe;
200
+ }, []);
201
+ const _updateState = (key: string, value: SelectedItem) => {
202
+ console.log('AutoPositionedPopupList _updateState key=', key, ' value=', value);
203
+ setState((prevState) => ({
204
+ ...prevState,
205
+ [key]: value,
206
+ }));
207
+ console.log('AutoPositionedPopupList _updateState rootViews=', rootViewsRef.current);
208
+ updateState(key, value);
209
+ };
210
+ const _fetchData = async ({
211
+ pageIndex,
212
+ pageSize: currentPageSize,
213
+ }: {
214
+ pageIndex: number;
215
+ pageSize: number;
216
+ }): Promise<Data | null> => {
217
+ console.log('AutoPositionedPopupList _fetchData pageIndex=', pageIndex, ' pageSize=', currentPageSize);
218
+ console.log('AutoPositionedPopupList _fetchData state.localData=', state.localData);
219
+ console.log('AutoPositionedPopupList _fetchData ref_searchQuery.current=', ref_searchQuery.current);
220
+ console.log('AutoPositionedPopupList _fetchData localSearch=', localSearch);
221
+ if (localSearch && state.localData.length > 0) {
222
+ const result: SelectedItem[] = state.localData.filter((item: SelectedItem) => {
223
+ return item.title?.toLowerCase().includes(ref_searchQuery.current.toLowerCase());
224
+ });
225
+ console.log('AutoPositionedPopupList _fetchData localSearch result=', result);
226
+ return Promise.resolve({
227
+ items: result,
228
+ pageIndex: 0,
229
+ needLoadMore: false,
230
+ });
231
+ }
232
+ try {
233
+ const res: Data | null = await fetchData({
234
+ pageIndex,
235
+ pageSize: pageSize || 10,
236
+ searchQuery: ref_searchQuery.current,
237
+ });
238
+ console.log('AutoPositionedPopupList _fetchData res=', res);
239
+ if (res?.items && localSearch) {
240
+ setState((prevState) => {
241
+ return {
242
+ ...prevState,
243
+ localData: res.items,
244
+ };
156
245
  });
157
-
158
- if (result?.items) {
159
- setInternalData(result.items);
160
- onDataUpdate?.(result.items);
161
- }
162
- } catch (error) {
163
- console.error('PopupList fetchData error:', error);
164
246
  }
165
- } else if (localSearch) {
166
- // Local filtering
167
- const filtered = data.filter(item =>
168
- item.title.toLowerCase().includes(newQuery.toLowerCase())
169
- );
170
- setInternalData(filtered);
171
- onDataUpdate?.(filtered);
247
+ return Promise.resolve(res);
248
+ } catch (e) {
249
+ console.warn('Error in fetchData:', e);
172
250
  }
173
- });
251
+ console.log('AutoPositionedPopupList _fetchData res=', null);
252
+ return null;
253
+ };
254
+ const _renderItem = useCallback(
255
+ ({item, index}: { item: SelectedItem; index: number }) => {
256
+ return <ListItem item={item} index={index} updateState={_updateState} selectedItem={state.selectedItem} />;
257
+ },
258
+ [state.selectedItem]
259
+ );
260
+ return useMemo(() => {
261
+ console.log('AutoPositionedPopupList (global as any)?.$fake=', (global as any)?.$fake);
262
+ // Choose AdvancedFlatList version based on global.$fake
263
+ const AdvancedFlatListComponent = (global as any)?.$fake ? AdvancedFlatListSource : AdvancedFlatListLib;
174
264
 
175
- return unsubscribe;
176
- }, [fetchData, localSearch, pageSize, data, onDataUpdate]);
177
- const defaultRenderItem = useCallback(
178
- ({item, index}: { item: SelectedItem; index: number }) => (
179
- <ListItem
180
- item={item}
181
- index={index}
182
- selectedItem={selectedItem}
183
- onItemPress={onItemPress}
184
- theme={theme}
185
- rootViewsRef={rootViewsRef}
186
- selectedItemBackgroundColor={selectedItemBackgroundColor}
187
- />
188
- ),
189
- [selectedItem, onItemPress, theme, rootViewsRef, selectedItemBackgroundColor]
190
- );
265
+ return (
266
+ <View style={[styles.baseModalView, styles.autoPositionedPopupList]}>
267
+ {/* @ts-ignore - Type assertion to bypass third-party library type issues */}
268
+ <AdvancedFlatListComponent
269
+ style={[{borderRadius: 0}]}
270
+ {...(ref_list && { ref: ref_list })}
271
+ keyExtractor={keyExtractor}
272
+ keyboardShouldPersistTaps={'always'}
273
+ {...({ fetchData: _fetchData })}
274
+ renderItem={renderItem || _renderItem}
275
+ />
276
+ </View>
277
+ );
278
+ }, [tag,
279
+ updateState,
280
+ fetchData,
281
+ keyExtractor,
282
+ renderItem,
283
+ state.selectedItem,
284
+ state.localData,
285
+ searchQuery,
286
+ localSearch,
287
+ pageSize,
288
+ rootViewsRef,
289
+ ]);
290
+ }
291
+ );
292
+
293
+ // State interface for AutoPositionedPopup
294
+ interface StateProps {
295
+ isFocus?: boolean;
296
+ selectedItem?: SelectedItem | any;
297
+ }
191
298
 
192
- return (
193
- <View style={[styles.autoPositionedPopupList, {backgroundColor: theme.colors.background}]}>
194
- <AdvancedFlatList
195
- data={internalData}
196
- keyExtractor={keyExtractor}
197
- renderItem={renderItem || defaultRenderItem}
198
- keyboardShouldPersistTaps="always"
199
- showsVerticalScrollIndicator={true}
200
- nestedScrollEnabled={true}
201
- />
202
- </View>
203
- );
204
- });
299
+ // List layout constants
300
+ const listLayout = {
301
+ height: 200,
302
+ };
205
303
 
206
304
  // Main AutoPositionedPopup component
207
305
  const AutoPositionedPopup: MemoExoticComponent<
@@ -209,18 +307,41 @@ const AutoPositionedPopup: MemoExoticComponent<
209
307
  > = memo(
210
308
  forwardRef<unknown, AutoPositionedPopupProps>(
211
309
  (props: AutoPositionedPopupProps, parentRef: ForwardedRef<unknown>): React.JSX.Element => {
310
+ console.log('AutoPositionedPopup props=', props);
212
311
  const {
213
312
  tag,
214
313
  style,
215
314
  AutoPositionedPopupBtnStyle,
216
315
  placeholder = 'Please Select',
217
- textAlign = 'right',
218
316
  onSubmitEditing,
219
317
  TextInputProps = {},
220
318
  inputStyle,
221
319
  labelStyle,
222
320
  popUpViewStyle = {left: '5%', width: '90%'},
223
- fetchData,
321
+ fetchData = async ({
322
+ pageIndex,
323
+ pageSize,
324
+ searchQuery,
325
+ }: {
326
+ pageIndex: number;
327
+ pageSize: number;
328
+ searchQuery?: string;
329
+ }): Promise<Data | null> => {
330
+ const res = {
331
+ items: [] as any[],
332
+ pageIndex,
333
+ needLoadMore: false,
334
+ };
335
+ try {
336
+ // const res1: any[] = await $api.xxx(pageSize)
337
+ // console.log('${NAME} xxx res=', res)
338
+ // res.items = res1
339
+ // res.needLoadMore = res1.length === pageSize
340
+ } catch (e) {
341
+ console.warn('Error in fetch operation:', e);
342
+ }
343
+ return res;
344
+ },
224
345
  renderItem,
225
346
  onItemSelected,
226
347
  localSearch = false,
@@ -229,22 +350,36 @@ const AutoPositionedPopup: MemoExoticComponent<
229
350
  useTextInput = false,
230
351
  btwChildren,
231
352
  CustomRow = ({children}) => <View>{children}</View>,
232
- keyExtractor = (item: any) => item?.id,
353
+ keyExtractor = (item: any) => String(item?.id || ''),
233
354
  AutoPositionedPopupBtnDisabled = false,
234
355
  forceRemoveAllRootViewOnItemSelected = false,
235
356
  centerDisplay = false,
236
357
  selectedItemBackgroundColor = 'rgba(116, 116, 128, 0.08)',
358
+ textAlign = 'right',
359
+ CustomPopView = undefined, CustomPopViewStyle
237
360
  } = props;
238
-
361
+ // State management similar to project implementation
362
+ const [state, setState] = useState<StateProps>({
363
+ isFocus: false,
364
+ selectedItem: selectedItem,
365
+ });
239
366
  // Use RootView context
240
- const {addRootView, removeRootView, rootViews, searchQuery: contextSearchQuery, setSearchQuery: setContextSearchQuery} = useRootView();
367
+ const {addRootView, setRootViewNativeStyle, removeRootView, rootViews, setSearchQuery} = useRootView();
368
+ const insets = useSafeAreaInsets();
241
369
  const rootViewsRef = useRef(rootViews);
242
-
243
- useEffect(() => {
244
- rootViewsRef.current = rootViews;
245
- }, [rootViews]);
246
-
247
- // State management
370
+ // Track TextInput focus and RootView states like project implementation
371
+ const hasTriggeredFocus = useRef(false);
372
+ const hasAddedRootView = useRef(false);
373
+ const hasShownRootView = useRef(false);
374
+ // Additional refs for keyboard and position tracking
375
+ const ref_isFocus = useRef<boolean>();
376
+ const ref_isKeyboardFullyShown = useRef<boolean>();
377
+ const ref_listPos: MutableRefObject<any> = useRef<LayoutRectangle>()
378
+ const keyboardVisibleRef = useRef(false);
379
+ const refAutoPositionedPopup = useRef<View>(null);
380
+ const ref_searchQuery = useRef<string>('');
381
+ // Simple keyboard status tracking (alternative to useKeyboardStatus hook)
382
+ // Legacy state for compatibility
248
383
  const [isVisible, setIsVisible] = useState(false);
249
384
  const [data, setData] = useState<SelectedItem[]>([]);
250
385
  const [loading, setLoading] = useState(false);
@@ -253,275 +388,504 @@ const AutoPositionedPopup: MemoExoticComponent<
253
388
  left: number;
254
389
  width: number;
255
390
  }>({top: 0, left: 0, width: 0});
256
- const popupId = useRef(`popup-${tag}-${Date.now()}`);
257
-
258
391
  // Refs for performance optimization
259
392
  const containerRef = useRef<View>(null);
260
393
  const textInputRef = useRef<RNTextInput>(null);
261
394
  const debounceTimerRef = useRef<NodeJS.Timeout | null>(null);
262
395
  const searchQueryRef = useRef<string>(''); // Use ref instead of state to avoid re-renders
263
-
264
- // Constants
265
- const LIST_HEIGHT = 200;
396
+ // Refs to store latest values for useEffect without adding to dependency array
397
+ const dataRef = useRef<SelectedItem[]>(data);
398
+ const isKeyboardFullyShown = useKeyboardStatus();
266
399
  const theme = defaultTheme;
267
-
268
- // Fetch data function
269
- const loadData = useCallback(async (query: string = '') => {
270
- if (!fetchData) return;
271
-
272
- setLoading(true);
273
- try {
274
- const result = await fetchData({
275
- pageIndex: 0,
276
- pageSize,
277
- searchQuery: query,
278
- });
279
-
280
- if (result?.items) {
281
- setData(result.items);
400
+ /**
401
+ * componentDidMount && componentWillUnmount
402
+ */
403
+ useEffect(() => {
404
+ (async () => {
405
+ })();
406
+ console.log(`AutoPositionedPopup componentDidMount tag=`, tag);
407
+ console.log('AutoPositionedPopup componentDidMount CustomPopView=', CustomPopView);
408
+ //componentWillUnmount
409
+ return () => {
410
+ console.log(`AutoPositionedPopup componentWillUnmount tag=`, tag);
411
+ removeRootView(tag, forceRemoveAllRootViewOnItemSelected, rootViewsRef.current);
412
+ setSearchQuery('');
413
+ if (textInputRef.current) {
414
+ textInputRef.current.blur();
415
+ hasTriggeredFocus.current = false;
416
+ hasAddedRootView.current = false;
417
+ hasShownRootView.current = false;
418
+ ref_isFocus.current = false;
282
419
  }
283
- } catch (error) {
284
- console.error('Error loading data:', error);
285
- } finally {
286
- setLoading(false);
287
- }
288
- }, [fetchData, pageSize]);
289
-
290
- // Handle search query change with debounce and event emission
291
- const handleSearchChange = useCallback((query: string) => {
292
- // Store in ref to avoid re-renders
293
- searchQueryRef.current = query;
294
-
295
- // Update TextInput value directly if needed
296
- if (textInputRef.current) {
297
- // The TextInput's value will be controlled by its own state
298
- }
299
-
300
- // Clear previous debounce timer
301
- if (debounceTimerRef.current) {
302
- clearTimeout(debounceTimerRef.current);
303
- }
304
-
305
- // Use debounce for performance optimization
306
- debounceTimerRef.current = setTimeout(() => {
307
- // Emit query change event to decouple components and avoid context re-rendering
308
- emitQueryChange(searchQueryRef.current);
309
- }, 300); // Use 300ms debounce like the original
420
+ };
310
421
  }, []);
311
-
312
- // Calculate popup position
313
- const calculatePosition = useCallback(() => {
314
- if (!containerRef.current) return;
315
-
316
- containerRef.current.measureInWindow((x, y, width, height) => {
317
- const screenHeight = Dimensions.get('screen').height;
318
- const screenWidth = Dimensions.get('screen').width;
319
-
320
- let top = y + height;
321
- let left = x;
322
- let popupWidth = width;
323
-
324
- // Check if popup should appear above the input
325
- if (y + height + LIST_HEIGHT > screenHeight) {
326
- top = y - LIST_HEIGHT;
327
- }
328
-
329
- // Adjust horizontal position if needed
330
- if (popUpViewStyle?.left && popUpViewStyle?.width) {
331
- const leftPercent = parseFloat(String(popUpViewStyle.left).replace('%', '')) / 100;
332
- const widthPercent = parseFloat(String(popUpViewStyle.width).replace('%', '')) / 100;
333
- left = screenWidth * leftPercent;
334
- popupWidth = screenWidth * widthPercent;
335
- }
336
-
337
- setPopupPosition({top, left, width: popupWidth});
338
- });
339
- }, [popUpViewStyle]);
340
-
341
- // Hide popup using RootView
342
- const hidePopup = useCallback(() => {
343
- setIsVisible(false);
344
- // Reset search query
345
- searchQueryRef.current = '';
346
- if (textInputRef.current) {
347
- textInputRef.current.blur();
348
- textInputRef.current.clear?.(); // Clear the TextInput
422
+ useEffect(() => {
423
+ console.log('AutoPositionedPopup rootViews=', rootViews);
424
+ rootViewsRef.current = rootViews;
425
+ if (rootViews.length === 0) {
426
+ hasAddedRootView.current = false;
427
+ hasShownRootView.current = false;
428
+ ref_isFocus.current = false;
429
+ ref_isKeyboardFullyShown.current = false;
430
+ hasTriggeredFocus.current = false;
431
+ setState((prevState) => {
432
+ return {
433
+ ...prevState,
434
+ isFocus: false,
435
+ };
436
+ });
349
437
  }
350
- removeRootView(popupId.current, forceRemoveAllRootViewOnItemSelected, rootViewsRef.current);
351
- }, [removeRootView, forceRemoveAllRootViewOnItemSelected]);
352
-
353
- // Handle data updates from PopupList
354
- const handleDataUpdate = useCallback((newData: SelectedItem[]) => {
355
- setData(newData);
356
- }, []);
357
-
358
- // Handle item selection
359
- const handleItemPress = useCallback((item: SelectedItem) => {
360
- onItemSelected?.(item);
361
- hidePopup();
362
- }, [onItemSelected, hidePopup]);
363
-
364
- // Show popup using RootView
365
- const showPopup = useCallback(() => {
366
- calculatePosition();
367
- setIsVisible(true);
368
- loadData(searchQueryRef.current);
369
-
370
- // Wait for position to be calculated
371
- setTimeout(() => {
372
- const popupComponent = (
373
- <TouchableOpacity
374
- style={{
375
- flex: 1,
376
- backgroundColor: 'rgba(0, 0, 0, 0.3)',
377
- }}
378
- activeOpacity={1}
379
- onPress={hidePopup}
380
- >
381
- <View
382
- style={{
383
- position: 'absolute',
384
- top: popupPosition.top,
385
- left: popupPosition.left,
386
- width: popupPosition.width,
387
- height: LIST_HEIGHT,
388
- backgroundColor: theme.colors.background,
389
- borderRadius: 8,
390
- shadowColor: '#000',
391
- shadowOffset: {width: 0, height: 2},
392
- shadowOpacity: 0.25,
393
- shadowRadius: 3.84,
394
- elevation: 5,
395
- }}
396
- >
397
- {useTextInput && (
398
- <RNTextInput
399
- ref={textInputRef}
400
- style={[
401
- styles.inputStyle,
402
- {
403
- height: 40,
404
- borderBottomWidth: 1,
405
- borderBottomColor: theme.colors.border,
406
- paddingHorizontal: 12,
407
- color: theme.colors.text,
408
- },
409
- inputStyle,
410
- ]}
411
- placeholder={placeholder}
412
- placeholderTextColor={theme.colors.placeholderText}
413
- defaultValue={searchQueryRef.current}
414
- onChangeText={handleSearchChange}
415
- onSubmitEditing={(e: NativeSyntheticEvent<TextInputSubmitEditingEventData>) => {
416
- onSubmitEditing?.(e);
417
- Keyboard.dismiss();
418
- }}
419
- returnKeyType="done"
420
- {...TextInputProps}
421
- />
422
- )}
423
-
424
- <PopupList
425
- data={data}
426
- selectedItem={selectedItem}
427
- onItemPress={handleItemPress}
428
- renderItem={renderItem}
429
- keyExtractor={keyExtractor}
430
- theme={theme}
431
- rootViewsRef={rootViewsRef}
432
- fetchData={fetchData}
433
- localSearch={localSearch}
434
- pageSize={pageSize}
435
- onDataUpdate={handleDataUpdate}
436
- selectedItemBackgroundColor={selectedItemBackgroundColor}
437
- />
438
- </View>
439
- </TouchableOpacity>
440
- );
441
-
442
- addRootView({
443
- id: popupId.current,
444
- style: {
445
- position: 'absolute',
446
- top: 0,
447
- left: 0,
448
- right: 0,
449
- bottom: 0,
450
- },
451
- component: popupComponent,
452
- useModal: true,
453
- onModalClose: hidePopup,
454
- centerDisplay: centerDisplay,
438
+ }, [rootViews]);
439
+ useEffect(() => {
440
+ console.log('AutoPositionedPopup useEffect tag=', tag);
441
+ console.log('AutoPositionedPopup useEffect selectedItem=', selectedItem);
442
+ console.log('AutoPositionedPopup useEffect state.selectedItem=', state.selectedItem);
443
+ if (state.selectedItem?.id !== selectedItem?.id || state.selectedItem?.title !== selectedItem?.title) {
444
+ console.log('AutoPositionedPopup useEffect selectedItem!=state.selectedItem');
445
+ setState((prevState) => {
446
+ return {
447
+ ...prevState,
448
+ selectedItem: selectedItem,
449
+ };
455
450
  });
456
- }, 100);
457
- }, [calculatePosition, loadData, popupPosition, useTextInput, placeholder, theme, inputStyle, TextInputProps, data, selectedItem, renderItem, keyExtractor, centerDisplay, addRootView, hidePopup, handleSearchChange, handleItemPress, LIST_HEIGHT, selectedItemBackgroundColor]);
458
-
459
- // Handle button press
460
- const handleButtonPress = useCallback(() => {
461
- if (AutoPositionedPopupBtnDisabled) return;
462
-
451
+ }
452
+ }, [selectedItem, state.selectedItem, tag]);
453
+ useEffect(() => {
454
+ console.log('AutoPositionedPopup useEffect tag=', tag);
455
+ console.log('AutoPositionedPopup useEffect state.isFocus=', state.isFocus);
456
+ console.log('AutoPositionedPopup useEffect isKeyboardFullyShown=', isKeyboardFullyShown);
457
+ console.log('AutoPositionedPopup useEffect ref_isFocus.current=', ref_isFocus.current);
458
+ console.log(
459
+ 'AutoPositionedPopup useEffect ref_isKeyboardFullyShown.current=',
460
+ ref_isKeyboardFullyShown.current
461
+ );
462
+ console.log('AutoPositionedPopup useEffect useTextInput=', useTextInput);
463
+ console.log('AutoPositionedPopup useEffect TextInputProps=', TextInputProps);
464
+ console.log('AutoPositionedPopup useEffect hasAddedRootView.current=', hasAddedRootView.current);
465
+ console.log('AutoPositionedPopup useEffect hasShownRootView.current=', hasShownRootView.current);
463
466
  if (useTextInput) {
464
- showPopup();
465
- // Focus text input after a short delay
466
- setTimeout(() => {
467
- textInputRef.current?.focus();
468
- }, 100);
467
+ if (isKeyboardFullyShown && hasAddedRootView.current && !hasShownRootView.current && state.isFocus) {
468
+ refAutoPositionedPopup.current?.measureInWindow((x: number, y: number, width: number, height: number) => {
469
+ console.log('AutoPositionedPopup measureInWindow x=', x, ' y=', y, ' width=', width, ' height=', height);
470
+ // SIMPLE CENTER-BASED POSITIONING STRATEGY
471
+ const screenHeight = Dimensions.get('screen').height;
472
+ const screenCenter = screenHeight / 2;
473
+ console.log('AutoPositionedPopup screenHeight=', screenHeight, ' screenCenter=', screenCenter, ' componentY=', y);
474
+
475
+ // Simple rule: if component Y > screen center, show popup above; otherwise show below
476
+ if (y > screenCenter) {
477
+ console.log('AutoPositionedPopup with keyboard: showing above (Y > center)');
478
+ ref_listPos.current = {x: x, y: y - listLayout.height, width: width};
479
+ } else {
480
+ console.log('AutoPositionedPopup with keyboard: showing below (Y <= center)');
481
+ ref_listPos.current = {x: x, y: y + height, width: width};
482
+ }
483
+ console.log('AutoPositionedPopup ref_listPos.current=', ref_listPos.current);
484
+ setRootViewNativeStyle(tag, {
485
+ top: ref_listPos.current?.y,
486
+ left: popUpViewStyle?.left,
487
+ width: popUpViewStyle?.width,
488
+ height: listLayout.height,
489
+ opacity: 1,
490
+ });
491
+ hasShownRootView.current = true;
492
+ });
493
+ } else if (!isKeyboardFullyShown && ref_isFocus.current) {
494
+ console.log(
495
+ 'AutoPositionedPopup isKeyboardFullyShown useEffect removeRootView tag=',
496
+ tag,
497
+ ' forceRemoveAllRootViewOnItemSelected=',
498
+ forceRemoveAllRootViewOnItemSelected
499
+ );
500
+ removeRootView(tag, forceRemoveAllRootViewOnItemSelected);
501
+ setState((prevState) => {
502
+ return {
503
+ ...prevState,
504
+ isFocus: false,
505
+ };
506
+ });
507
+ setSearchQuery('');
508
+ hasAddedRootView.current = false;
509
+ hasShownRootView.current = false;
510
+ }
469
511
  } else {
470
- showPopup();
512
+ if (state.isFocus) {
513
+ refAutoPositionedPopup.current?.measureInWindow((x: number, y: number, width: number, height: number) => {
514
+ console.log('AutoPositionedPopup measureInWindow x=', x, ' y=', y, ' width=', width, ' height=', height);
515
+ // SIMPLE CENTER-BASED POSITIONING STRATEGY
516
+ const screenHeight = Dimensions.get('screen').height;
517
+ const screenCenter = screenHeight / 2;
518
+ console.log('AutoPositionedPopup screenHeight=', screenHeight, ' screenCenter=', screenCenter, ' componentY=', y);
519
+
520
+ // Simple rule: if component Y > screen center, show popup above; otherwise show below
521
+ if (y+insets. top > screenCenter) {
522
+ console.log('AutoPositionedPopup: showing above (Y > center)');
523
+ ref_listPos.current = {x: x, y: y - listLayout.height, width: width};
524
+ } else {
525
+ console.log('AutoPositionedPopup: showing below (Y <= center)');
526
+ ref_listPos.current = {x: x, y: y + height+insets.top, width: width};
527
+ }
528
+ console.log('AutoPositionedPopup ref_listPos.current=', ref_listPos.current);
529
+ if (CustomPopView && CustomPopViewStyle) {
530
+ console.log('AutoPositionedPopup CustomPopViewStyle=', CustomPopViewStyle);
531
+ // Ensure CustomPopViewStyle.height is a number before using it in calculations
532
+ const customHeight =
533
+ typeof CustomPopViewStyle.height === 'number' ? CustomPopViewStyle.height : listLayout.height;
534
+
535
+ // Apply same simple center-based strategy for CustomPopView
536
+ console.log('AutoPositionedPopup CustomPopView using center-based positioning, customHeight=', customHeight);
537
+
538
+ // Simple rule: if component Y > screen center, show popup above; otherwise show below
539
+ if (y > screenCenter) {
540
+ console.log('AutoPositionedPopup CustomPopView: showing above (Y > center), tag=', tag);
541
+ ref_listPos.current = {x: x, y: y - customHeight, width: width};
542
+ } else {
543
+ console.log('AutoPositionedPopup CustomPopView: showing below (Y <= center), tag=', tag);
544
+ ref_listPos.current = {x: x, y: y + height, width: width};
545
+ }
546
+ const PopViewComponent = CustomPopView();
547
+ console.log('AutoPositionedPopup addRootView PopViewComponent=', PopViewComponent);
548
+ console.log('AutoPositionedPopup addRootView state.selectedItem=', state.selectedItem);
549
+ addRootView({
550
+ id: tag,
551
+ style: !centerDisplay
552
+ ? {
553
+ top: ref_listPos.current.y,
554
+ left: popUpViewStyle?.left,
555
+ width: popUpViewStyle?.width,
556
+ height: listLayout.height,
557
+ opacity: 1,
558
+ ...CustomPopViewStyle,
559
+ }
560
+ : {width: popUpViewStyle?.width, height: listLayout.height, ...CustomPopViewStyle},
561
+ component: <PopViewComponent selectedItem={state.selectedItem}></PopViewComponent>,
562
+ useModal: true,
563
+ onModalClose: () => {
564
+ console.log('AutoPositionedPopup onModalClose');
565
+ removeRootView(tag, forceRemoveAllRootViewOnItemSelected, rootViewsRef.current);
566
+ setState((prevState) => {
567
+ return {
568
+ ...prevState,
569
+ isFocus: false,
570
+ };
571
+ });
572
+ hasAddedRootView.current = false;
573
+ hasShownRootView.current = false;
574
+ hasTriggeredFocus.current = false;
575
+ setSearchQuery('');
576
+ },
577
+ centerDisplay,
578
+ });
579
+ } else {
580
+ console.log('AutoPositionedPopup addRootView tag=', tag);
581
+ addRootView({
582
+ id: tag,
583
+ style: {
584
+ top: ref_listPos.current.y,
585
+ left: popUpViewStyle?.left,
586
+ width: popUpViewStyle?.width,
587
+ height: listLayout.height,
588
+ opacity: 1,
589
+ },
590
+ component: (
591
+ <AutoPositionedPopupList
592
+ tag={tag}
593
+ updateState={updateState}
594
+ fetchData={fetchData}
595
+ pageSize={pageSize}
596
+ renderItem={renderItem}
597
+ selectedItem={state.selectedItem}
598
+ localSearch={localSearch}
599
+ />
600
+ ),
601
+ useModal: true,
602
+ onModalClose: () => {
603
+ console.log('AutoPositionedPopup onModalClose tag=', tag);
604
+ removeRootView(tag, forceRemoveAllRootViewOnItemSelected, rootViewsRef.current);
605
+ setState((prevState) => {
606
+ return {
607
+ ...prevState,
608
+ };
609
+ });
610
+ setSearchQuery('');
611
+ },
612
+ });
613
+ }
614
+ });
615
+ }
471
616
  }
472
- }, [AutoPositionedPopupBtnDisabled, useTextInput, showPopup]);
473
-
617
+ if (isKeyboardFullyShown) {
618
+ ref_isFocus.current = state.isFocus;
619
+ if (isKeyboardFullyShown !== keyboardVisibleRef.current) {
620
+ keyboardVisibleRef.current = isKeyboardFullyShown;
621
+ if (isKeyboardFullyShown && textInputRef.current) {
622
+ if (ref_searchQuery.current) {
623
+ textInputRef.current.setNativeProps({text: ref_searchQuery.current});
624
+ }
625
+ }
626
+ }
627
+ }
628
+ }, [insets,
629
+ isKeyboardFullyShown,
630
+ state.isFocus,
631
+ useTextInput,
632
+ CustomPopView,
633
+ CustomPopViewStyle,
634
+ forceRemoveAllRootViewOnItemSelected,
635
+ tag,
636
+ state.selectedItem,
637
+ ]);
474
638
  // Imperative handle for parent component access
475
639
  useImperativeHandle(
476
640
  parentRef,
477
641
  () => ({
478
642
  clearSelectedItem: () => {
479
- // Clear selection logic can be implemented here
480
- console.log('Clearing selected item for:', tag);
643
+ console.log('AutoPositionedPopup clearSelectedItem tag=', tag);
644
+ setState((prevState) => {
645
+ return {
646
+ ...prevState,
647
+ selectedItem: undefined,
648
+ };
649
+ });
481
650
  },
482
- showPopup,
483
- hidePopup,
484
651
  }),
485
- [tag, showPopup, hidePopup]
652
+ []
486
653
  );
487
-
488
- // Cleanup
489
- useEffect(() => {
490
- return () => {
491
- if (debounceTimerRef.current) {
492
- clearTimeout(debounceTimerRef.current);
493
- }
494
- };
495
- }, []);
496
-
497
- // Render the component
498
- return (
499
- <CustomRow>
500
- <View style={[styles.contain, style]} ref={containerRef}>
501
- <TouchableOpacity
502
- style={[styles.AutoPositionedPopupBtn, AutoPositionedPopupBtnStyle]}
503
- disabled={AutoPositionedPopupBtnDisabled}
504
- onPress={handleButtonPress}
505
- >
506
- {btwChildren ? (
507
- btwChildren()
508
- ) : (
509
- <Text
510
- style={[
511
- styles.searchQueryTxt,
512
- selectedItem && {color: theme.colors.text},
513
- labelStyle,
514
- ]}
515
- numberOfLines={1}
516
- ellipsizeMode="tail"
654
+ const updateState = (key: string, value: SelectedItem) => {
655
+ console.log('AutoPositionedPopup updateState key=', key, ' value=', value);
656
+ setState((prevState) => ({
657
+ ...prevState,
658
+ [key]: value,
659
+ }));
660
+ if (key === 'selectedItem' && onItemSelected) {
661
+ onItemSelected(value);
662
+ console.log('AutoPositionedPopup updateState onItemSelected rootViewsRef.current=', rootViewsRef.current);
663
+ removeRootView(tag, forceRemoveAllRootViewOnItemSelected, rootViewsRef.current);
664
+ hasAddedRootView.current = false;
665
+ hasShownRootView.current = false;
666
+ hasTriggeredFocus.current = false;
667
+ setState((prevState) => {
668
+ return {
669
+ ...prevState,
670
+ isFocus: false,
671
+ };
672
+ });
673
+ setSearchQuery('');
674
+ }
675
+ };
676
+ // Render the component following project implementation
677
+ return useMemo(() => {
678
+ console.log('AutoPositionedPopup render tag=', tag); // Now safe - circular dependency fixed
679
+ return (
680
+ <CustomRow>
681
+ <View style={[styles.contain, style]} ref={refAutoPositionedPopup}>
682
+ {!state.isFocus || !useTextInput ? (
683
+ <TouchableOpacity
684
+ style={[styles.AutoPositionedPopupBtn, AutoPositionedPopupBtnStyle]}
685
+ disabled={AutoPositionedPopupBtnDisabled}
686
+ onPress={() => {
687
+ console.log('AutoPositionedPopup onPress tag=', tag);
688
+ console.log('AutoPositionedPopup onPress state.isFocus=', state.isFocus);
689
+ console.log('AutoPositionedPopup onPress useTextInput=', useTextInput);
690
+ console.log(
691
+ 'AutoPositionedPopup onPress hasAddedRootView.current=',
692
+ hasAddedRootView.current
693
+ );
694
+ console.log(
695
+ 'AutoPositionedPopup onPress hasShownRootView.current=',
696
+ hasShownRootView.current
697
+ );
698
+ console.log(
699
+ 'AutoPositionedPopup onPress hasTriggeredFocus.current=',
700
+ hasTriggeredFocus.current
701
+ );
702
+ console.log('AutoPositionedPopup onPress state.selectedItem=', state.selectedItem);
703
+ setState((prevState) => {
704
+ return {
705
+ ...prevState,
706
+ isFocus: true,
707
+ };
708
+ });
709
+ if (!hasAddedRootView.current && useTextInput) {
710
+ hasAddedRootView.current = true;
711
+ hasShownRootView.current = false;
712
+ addRootView({
713
+ id: tag,
714
+ style: {
715
+ top: 0,
716
+ left: 0,
717
+ width: popUpViewStyle?.width,
718
+ height: listLayout.height,
719
+ opacity: 0,
720
+ },
721
+ component: (
722
+ <AutoPositionedPopupList
723
+ tag={tag}
724
+ updateState={updateState}
725
+ fetchData={fetchData}
726
+ pageSize={pageSize}
727
+ renderItem={renderItem}
728
+ selectedItem={state.selectedItem}
729
+ localSearch={localSearch}
730
+ />
731
+ ),
732
+ useModal: false,
733
+ });
734
+ }
735
+ }}
517
736
  >
518
- {selectedItem?.title || placeholder}
519
- </Text>
737
+ {!btwChildren ? (
738
+ <Text
739
+ style={[
740
+ styles.searchQueryTxt,
741
+ state.selectedItem && {color: theme.colors.text},
742
+ labelStyle,
743
+ ]}
744
+ numberOfLines={1}
745
+ ellipsizeMode={'tail'}
746
+ >
747
+ {state.selectedItem?.title || placeholder}
748
+ </Text>
749
+ ) : (
750
+ btwChildren()
751
+ )}
752
+ </TouchableOpacity>
753
+ ) : (
754
+ useTextInput &&
755
+ state.isFocus && (
756
+ <RNTextInput
757
+ ref={textInputRef}
758
+ key="fixed-textinput-key"
759
+ style={[
760
+ styles.inputStyle,
761
+ inputStyle,
762
+ ]}
763
+ textAlign={TextInputProps['textAlign'] || 'left'}
764
+ multiline={TextInputProps['multiline'] || false}
765
+ numberOfLines={TextInputProps['numberOfLines'] || 1}
766
+ onChangeText={(searchQuery) => {
767
+ ref_searchQuery.current = searchQuery;
768
+ console.log('AutoPositionedPopup onChangeText rootViews=', rootViews);
769
+ if (!localSearch) {
770
+ if (debounceTimerRef.current) {
771
+ clearTimeout(debounceTimerRef.current);
772
+ }
773
+ debounceTimerRef.current = setTimeout(() => {
774
+ emitQueryChange(ref_searchQuery.current);
775
+ }, 500);
776
+ } else {
777
+ emitQueryChange(ref_searchQuery.current);
778
+ }
779
+ }}
780
+ placeholderTextColor={theme.colors.placeholderText}
781
+ placeholder={placeholder}
782
+ onKeyPress={(e) => {
783
+ if (e.nativeEvent.key === 'Enter') {
784
+ Keyboard.dismiss();
785
+ }
786
+ }}
787
+ keyboardType={TextInputProps['keyboardType'] || 'default'}
788
+ clearButtonMode="while-editing"
789
+ returnKeyType={TextInputProps['returnKeyType'] || 'done'}
790
+ maxLength={TextInputProps['maxLength'] || 100}
791
+ accessibilityLabel="selectInput"
792
+ accessible={true}
793
+ autoFocus={TextInputProps['autoFocus'] || false}
794
+ autoCorrect={false}
795
+ underlineColorAndroid="transparent"
796
+ editable={TextInputProps['editable'] || true}
797
+ secureTextEntry={TextInputProps['secureTextEntry'] || false}
798
+ defaultValue=""
799
+ caretHidden={false}
800
+ enablesReturnKeyAutomatically
801
+ onFocus={() => {
802
+ console.log(
803
+ 'AutoPositionedPopup onFocus tag=',
804
+ tag,
805
+ ' selectedItem=',
806
+ state.selectedItem,
807
+ ' hasTriggeredFocus.current=',
808
+ hasTriggeredFocus.current,
809
+ ' textInputRef.current=',
810
+ textInputRef.current,
811
+ ' ref_searchQuery.current=',
812
+ ref_searchQuery.current
813
+ );
814
+ if (!hasTriggeredFocus.current) {
815
+ hasTriggeredFocus.current = true;
816
+ ref_isFocus.current = true;
817
+ if (state.selectedItem) {
818
+ ref_searchQuery.current = state.selectedItem.title;
819
+ }
820
+ if (textInputRef.current && ref_searchQuery.current) {
821
+ textInputRef.current.setNativeProps({
822
+ text: ref_searchQuery.current,
823
+ });
824
+ }
825
+ }
826
+ }}
827
+ onBlur={() => {
828
+ console.log(
829
+ 'AutoPositionedPopup onBlur tag=',
830
+ tag,
831
+ 'textInputRef.current=',
832
+ textInputRef.current
833
+ );
834
+ hasTriggeredFocus.current = false;
835
+ hasAddedRootView.current = false; // 重置 RootView 狀態
836
+ hasShownRootView.current = false;
837
+ ref_isFocus.current = false;
838
+ setState((prevState) => {
839
+ return {
840
+ ...prevState,
841
+ isFocus: false,
842
+ };
843
+ });
844
+ removeRootView(tag, forceRemoveAllRootViewOnItemSelected);
845
+ setSearchQuery('');
846
+ if (textInputRef.current) {
847
+ textInputRef.current.setNativeProps({text: ''});
848
+ ref_searchQuery.current = '';
849
+ textInputRef.current.blur();
850
+ }
851
+ Keyboard.dismiss();
852
+ }}
853
+ selectTextOnFocus={TextInputProps['selectTextOnFocus'] || false}
854
+ onSubmitEditing={(e: NativeSyntheticEvent<TextInputSubmitEditingEventData>) => {
855
+ console.log(
856
+ 'AutoPositionedPopup.tsx onSubmitEditing e.nativeEvent.text=',
857
+ e.nativeEvent.text
858
+ );
859
+ onSubmitEditing && onSubmitEditing(e);
860
+ }}
861
+ />
862
+ )
520
863
  )}
521
- </TouchableOpacity>
522
- </View>
523
- </CustomRow>
524
- );
864
+ </View>
865
+ </CustomRow>
866
+ );
867
+ }, [tag,
868
+ fetchData,
869
+ renderItem,
870
+ onItemSelected,
871
+ onSubmitEditing,
872
+ localSearch,
873
+ placeholder,
874
+ textAlign,
875
+ pageSize,
876
+ selectedItem,
877
+ CustomRow,
878
+ useTextInput,
879
+ btwChildren,
880
+ selectedItem,
881
+ keyExtractor,
882
+ AutoPositionedPopupBtnStyle,
883
+ CustomPopView,
884
+ CustomPopViewStyle,
885
+ forceRemoveAllRootViewOnItemSelected,
886
+ inputStyle,
887
+ TextInputProps,
888
+ state.isFocus,]);
525
889
  }
526
890
  )
527
891
  );