react-native-auto-positioned-popup 1.0.9 → 1.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +111 -8
- package/README_zh.md +112 -9
- package/lib/AutoPositionedPopup.d.ts +2 -2
- package/lib/AutoPositionedPopup.d.ts.map +1 -1
- package/lib/AutoPositionedPopup.js +175 -68
- package/lib/AutoPositionedPopup.js.map +1 -1
- package/package.json +8 -8
- package/src/AutoPositionedPopup.tsx +212 -89
- package/src/types/react-native-advanced-flatlist.d.ts +65 -12
|
@@ -14,15 +14,14 @@ import React, {
|
|
|
14
14
|
import {
|
|
15
15
|
Dimensions,
|
|
16
16
|
Keyboard,
|
|
17
|
+
Platform,
|
|
18
|
+
StatusBar,
|
|
17
19
|
Text,
|
|
18
20
|
TextInput as RNTextInput,
|
|
19
21
|
TouchableOpacity,
|
|
20
22
|
View,
|
|
21
23
|
} from 'react-native';
|
|
22
|
-
|
|
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';
|
|
24
|
+
import {AdvancedFlatList, ListData, FetchDataParams} from 'react-native-advanced-flatlist';
|
|
26
25
|
import {TextInputSubmitEditingEventData} from 'react-native/Libraries/Components/TextInput/TextInput';
|
|
27
26
|
import {LayoutRectangle, NativeSyntheticEvent} from 'react-native/Libraries/Types/CoreEventTypes';
|
|
28
27
|
import {AutoPositionedPopupProps, Data, SelectedItem} from './AutoPositionedPopupProps';
|
|
@@ -209,10 +208,7 @@ const AutoPositionedPopupList: React.FC<AutoPositionedPopupListProps> = memo(
|
|
|
209
208
|
const _fetchData = async ({
|
|
210
209
|
pageIndex,
|
|
211
210
|
pageSize: currentPageSize,
|
|
212
|
-
}: {
|
|
213
|
-
pageIndex: number;
|
|
214
|
-
pageSize: number;
|
|
215
|
-
}): Promise<Data | null> => {
|
|
211
|
+
}: FetchDataParams): Promise<ListData | null> => {
|
|
216
212
|
console.log('AutoPositionedPopupList _fetchData pageIndex=', pageIndex, ' pageSize=', currentPageSize);
|
|
217
213
|
console.log('AutoPositionedPopupList _fetchData state.localData=', state.localData);
|
|
218
214
|
console.log('AutoPositionedPopupList _fetchData ref_searchQuery.current=', ref_searchQuery.current);
|
|
@@ -243,7 +239,15 @@ const AutoPositionedPopupList: React.FC<AutoPositionedPopupListProps> = memo(
|
|
|
243
239
|
};
|
|
244
240
|
});
|
|
245
241
|
}
|
|
246
|
-
|
|
242
|
+
// Convert Data to ListData if needed
|
|
243
|
+
if (res) {
|
|
244
|
+
return Promise.resolve({
|
|
245
|
+
items: res.items as any[], // Convert to ListItem array
|
|
246
|
+
pageIndex: res.pageIndex,
|
|
247
|
+
needLoadMore: res.needLoadMore,
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
return null;
|
|
247
251
|
} catch (e) {
|
|
248
252
|
console.warn('Error in fetchData:', e);
|
|
249
253
|
}
|
|
@@ -258,19 +262,18 @@ const AutoPositionedPopupList: React.FC<AutoPositionedPopupListProps> = memo(
|
|
|
258
262
|
);
|
|
259
263
|
return useMemo(() => {
|
|
260
264
|
console.log('AutoPositionedPopupList (global as any)?.$fake=', (global as any)?.$fake);
|
|
261
|
-
//
|
|
262
|
-
|
|
263
|
-
|
|
265
|
+
// Babel configuration handles the path redirection based on global.$fake
|
|
266
|
+
// No need for conditional import here
|
|
264
267
|
return (
|
|
265
268
|
<View style={[styles.baseModalView, styles.autoPositionedPopupList]}>
|
|
266
|
-
|
|
267
|
-
<AdvancedFlatListComponent
|
|
269
|
+
<AdvancedFlatList
|
|
268
270
|
style={[{borderRadius: 0}]}
|
|
269
|
-
{...(ref_list && {
|
|
270
|
-
keyExtractor={keyExtractor}
|
|
271
|
+
{...(ref_list && {ref: ref_list})}
|
|
272
|
+
keyExtractor={(item, index) => keyExtractor ? keyExtractor(item as SelectedItem) : (item as SelectedItem).id}
|
|
271
273
|
keyboardShouldPersistTaps={'always'}
|
|
272
|
-
{
|
|
273
|
-
renderItem={renderItem
|
|
274
|
+
fetchData={_fetchData}
|
|
275
|
+
renderItem={renderItem ? ({item, index}) => renderItem({item: item as SelectedItem, index}) : ({item, index}) => _renderItem({item: item as SelectedItem, index})}
|
|
276
|
+
showListEmptyComponent={false}
|
|
274
277
|
/>
|
|
275
278
|
</View>
|
|
276
279
|
);
|
|
@@ -301,9 +304,7 @@ const listLayout = {
|
|
|
301
304
|
};
|
|
302
305
|
|
|
303
306
|
// Main AutoPositionedPopup component
|
|
304
|
-
const AutoPositionedPopup
|
|
305
|
-
ForwardRefExoticComponent<AutoPositionedPopupProps>
|
|
306
|
-
> = memo(
|
|
307
|
+
const AutoPositionedPopup = memo(
|
|
307
308
|
forwardRef<unknown, AutoPositionedPopupProps>(
|
|
308
309
|
(props: AutoPositionedPopupProps, parentRef: ForwardedRef<unknown>): React.JSX.Element => {
|
|
309
310
|
console.log('AutoPositionedPopup props=', props);
|
|
@@ -370,9 +371,9 @@ const AutoPositionedPopup: MemoExoticComponent<
|
|
|
370
371
|
const hasAddedRootView = useRef(false);
|
|
371
372
|
const hasShownRootView = useRef(false);
|
|
372
373
|
// Additional refs for keyboard and position tracking
|
|
373
|
-
const ref_isFocus = useRef<boolean>();
|
|
374
|
-
const ref_isKeyboardFullyShown = useRef<boolean>();
|
|
375
|
-
const ref_listPos: MutableRefObject<any> = useRef<LayoutRectangle>()
|
|
374
|
+
const ref_isFocus = useRef<boolean>(false);
|
|
375
|
+
const ref_isKeyboardFullyShown = useRef<boolean>(false);
|
|
376
|
+
const ref_listPos: MutableRefObject<any> = useRef<LayoutRectangle | undefined>(undefined)
|
|
376
377
|
const keyboardVisibleRef = useRef(false);
|
|
377
378
|
const refAutoPositionedPopup = useRef<View>(null);
|
|
378
379
|
const ref_searchQuery = useRef<string>('');
|
|
@@ -510,96 +511,218 @@ const AutoPositionedPopup: MemoExoticComponent<
|
|
|
510
511
|
if (state.isFocus) {
|
|
511
512
|
refAutoPositionedPopup.current?.measureInWindow((x: number, y: number, width: number, height: number) => {
|
|
512
513
|
console.log('AutoPositionedPopup measureInWindow x=', x, ' y=', y, ' width=', width, ' height=', height);
|
|
513
|
-
|
|
514
|
-
// INTELLIGENT POSITION CALCULATION
|
|
514
|
+
|
|
515
|
+
// INTELLIGENT POSITION CALCULATION - MODIFIED VERSION WITH STATUS BAR SAFETY
|
|
515
516
|
const calculateOptimalPosition = (componentY: number, componentHeight: number, popupHeight: number) => {
|
|
517
|
+
console.log('🔥🔥🔥 NEW CALCULATE OPTIMAL POSITION FUNCTION EXECUTING 🔥🔥🔥');
|
|
518
|
+
|
|
516
519
|
// Use window height (visible area) instead of screen height (includes status bar)
|
|
517
520
|
const windowHeight = Dimensions.get('window').height;
|
|
518
521
|
const visibleAreaCenter = windowHeight / 2;
|
|
519
|
-
|
|
522
|
+
|
|
523
|
+
// Cross-platform status bar height handling
|
|
524
|
+
const getStatusBarHeight = () => {
|
|
525
|
+
if (Platform.OS === 'android') {
|
|
526
|
+
return StatusBar.currentHeight || 24; // Android default
|
|
527
|
+
} else {
|
|
528
|
+
// iOS status bar heights vary by device
|
|
529
|
+
const {height: screenHeight} = Dimensions.get('screen');
|
|
530
|
+
const {height: windowHeightLocal} = Dimensions.get('window');
|
|
531
|
+
return screenHeight - windowHeightLocal; // Safe area top
|
|
532
|
+
}
|
|
533
|
+
};
|
|
534
|
+
const statusBarHeight = getStatusBarHeight();
|
|
535
|
+
console.log('🔥 Cross-platform StatusBar height:', statusBarHeight, 'Platform:', Platform.OS);
|
|
536
|
+
|
|
520
537
|
// Calculate component center point as requested
|
|
521
538
|
const componentCenterY = componentY + componentHeight / 2;
|
|
522
|
-
|
|
539
|
+
|
|
523
540
|
console.log('AutoPositionedPopup positioning data:', {
|
|
524
541
|
windowHeight,
|
|
525
542
|
visibleAreaCenter,
|
|
526
543
|
componentCenterY,
|
|
527
544
|
componentY,
|
|
528
545
|
componentHeight,
|
|
529
|
-
popupHeight
|
|
546
|
+
popupHeight,
|
|
547
|
+
statusBarHeight
|
|
530
548
|
});
|
|
531
|
-
|
|
549
|
+
|
|
532
550
|
let showAbove = false;
|
|
533
|
-
let finalY = componentY + componentHeight; // Default: show below
|
|
534
|
-
|
|
535
|
-
//
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
551
|
+
let finalY = componentY + componentHeight; // Default fallback: show below
|
|
552
|
+
|
|
553
|
+
// CORRECTED LOGIC: Calculate actual usable space considering status bar
|
|
554
|
+
const rawSpaceAbove = componentY;
|
|
555
|
+
const spaceBelow = windowHeight - (componentY + componentHeight);
|
|
556
|
+
// Actual usable space above must account for status bar
|
|
557
|
+
const usableSpaceAbove = componentY - statusBarHeight;
|
|
558
|
+
|
|
559
|
+
console.log('🔥 AutoPositionedPopup CORRECTED SPACE CALCULATION (pre-spacing):', {
|
|
560
|
+
rawSpaceAbove,
|
|
561
|
+
usableSpaceAbove,
|
|
562
|
+
spaceBelow,
|
|
563
|
+
popupHeight,
|
|
564
|
+
componentY,
|
|
565
|
+
componentHeight,
|
|
566
|
+
windowHeight,
|
|
567
|
+
statusBarHeight
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
// ULTRA-TIGHT SPACING: Minimal spacing for tight visual connection
|
|
571
|
+
const getOptimalSpacing = (compY: number, compHeight: number, winHeight: number) => {
|
|
572
|
+
const componentCenter = compY + compHeight / 2;
|
|
573
|
+
const screenCenter = winHeight / 2;
|
|
574
|
+
const distanceFromCenter = Math.abs(componentCenter - screenCenter) / screenCenter;
|
|
575
|
+
|
|
576
|
+
// Check if component is in bottom half for ultra-tight spacing
|
|
577
|
+
const isInBottomHalf = componentCenter > screenCenter;
|
|
578
|
+
|
|
579
|
+
// Base spacing: extremely small for bottom components
|
|
580
|
+
const baseSpacing = isInBottomHalf ? 0.5 : 3;
|
|
581
|
+
|
|
582
|
+
// Aggressive spacing reduction for edge positions - ultra tight for bottom half
|
|
583
|
+
const edgeProximityFactor = isInBottomHalf ?
|
|
584
|
+
Math.max(0.15, 1 - distanceFromCenter * 1.2) :
|
|
585
|
+
Math.max(0.4, 1 - distanceFromCenter * 0.7);
|
|
586
|
+
|
|
587
|
+
// Minimal component-relative spacing for bottom components
|
|
588
|
+
const relativeSpacingPercent = isInBottomHalf ? 0.02 : 0.12;
|
|
589
|
+
const relativeSpacing = Math.min(compHeight * relativeSpacingPercent, isInBottomHalf ? 3 : 10);
|
|
590
|
+
|
|
591
|
+
// Strong platform adjustment - much smaller for Android bottom components
|
|
592
|
+
const platformMultiplier = Platform.OS === 'ios' ? 1.0 : (isInBottomHalf ? 0.5 : 0.9);
|
|
593
|
+
|
|
594
|
+
const finalSpacing = Math.max(baseSpacing, relativeSpacing) * edgeProximityFactor * platformMultiplier;
|
|
595
|
+
|
|
596
|
+
console.log('🔥 Advanced spacing calculation:', {
|
|
597
|
+
componentCenter,
|
|
598
|
+
screenCenter,
|
|
599
|
+
distanceFromCenter,
|
|
600
|
+
isInBottomHalf,
|
|
601
|
+
edgeProximityFactor,
|
|
602
|
+
baseSpacing,
|
|
603
|
+
relativeSpacing,
|
|
604
|
+
relativeSpacingPercent,
|
|
605
|
+
platformMultiplier,
|
|
606
|
+
finalSpacing
|
|
607
|
+
});
|
|
608
|
+
|
|
609
|
+
return finalSpacing;
|
|
610
|
+
};
|
|
611
|
+
// const POPUP_SPACING = getOptimalSpacing(componentY, componentHeight, windowHeight);
|
|
612
|
+
// console.log('🔥 Optimal popup spacing calculated:', POPUP_SPACING, 'for componentHeight:', componentHeight, 'at Y:', componentY);
|
|
613
|
+
|
|
614
|
+
// console.log('🔥 AutoPositionedPopup FINAL SPACE CHECK WITH SPACING:', {
|
|
615
|
+
// POPUP_SPACING,
|
|
616
|
+
// 'usableSpaceAbove >= popupHeight + POPUP_SPACING': usableSpaceAbove >= popupHeight + POPUP_SPACING,
|
|
617
|
+
// 'spaceBelow >= popupHeight + POPUP_SPACING': spaceBelow >= popupHeight + POPUP_SPACING,
|
|
618
|
+
// 'usableSpaceAbove needed': popupHeight + POPUP_SPACING,
|
|
619
|
+
// 'spaceBelow needed': popupHeight + POPUP_SPACING
|
|
620
|
+
// });
|
|
621
|
+
|
|
622
|
+
// FORCE ABOVE PRIORITY: If component is in bottom half, always try above first
|
|
623
|
+
const isInBottomHalf = componentCenterY > visibleAreaCenter;
|
|
624
|
+
|
|
625
|
+
// console.log('🔥 Position decision factors:', {
|
|
626
|
+
// isInBottomHalf,
|
|
627
|
+
// componentCenterY,
|
|
628
|
+
// visibleAreaCenter,
|
|
629
|
+
// 'spaceBelow >= needed': spaceBelow >= popupHeight + POPUP_SPACING,
|
|
630
|
+
// 'usableSpaceAbove >= needed': usableSpaceAbove >= popupHeight + POPUP_SPACING
|
|
631
|
+
// });
|
|
632
|
+
|
|
633
|
+
if (isInBottomHalf && usableSpaceAbove >= popupHeight ) {
|
|
634
|
+
// Component in bottom half + enough space above = FORCE ABOVE
|
|
635
|
+
showAbove = true;
|
|
636
|
+
finalY = componentY - popupHeight +componentHeight/2;
|
|
637
|
+
console.log('🔥 AutoPositionedPopup: FORCE ABOVE - bottom half component with enough space, finalY=', finalY);
|
|
638
|
+
} else if (!isInBottomHalf && spaceBelow >= popupHeight ) {
|
|
639
|
+
// Component in top half + enough space below = show below
|
|
640
|
+
showAbove = false;
|
|
641
|
+
finalY = componentY + componentHeight*2;
|
|
642
|
+
console.log('🔥 AutoPositionedPopup: Showing below - top half component with enough space, finalY=', finalY);
|
|
643
|
+
} else if (usableSpaceAbove >= popupHeight ) {
|
|
644
|
+
// Fallback: enough space above
|
|
645
|
+
showAbove = true;
|
|
646
|
+
finalY = componentY - popupHeight ;
|
|
647
|
+
console.log('🔥 AutoPositionedPopup: Showing above - enough space available (fallback), finalY=', finalY);
|
|
648
|
+
} else if (spaceBelow >= popupHeight ) {
|
|
649
|
+
// Fallback: enough space below
|
|
650
|
+
showAbove = false;
|
|
651
|
+
finalY = componentY + componentHeight ;
|
|
652
|
+
console.log('🔥 AutoPositionedPopup: Showing below - enough space available (fallback), finalY=', finalY);
|
|
554
653
|
} else {
|
|
555
|
-
//
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
654
|
+
// Emergency fallback: choose larger space
|
|
655
|
+
if (usableSpaceAbove >= spaceBelow) {
|
|
656
|
+
showAbove = true;
|
|
657
|
+
finalY = Math.max(statusBarHeight, componentY - popupHeight );
|
|
658
|
+
console.log('🔥 AutoPositionedPopup: Emergency above - larger space, finalY=', finalY);
|
|
560
659
|
} else {
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
showAbove = true;
|
|
565
|
-
finalY = componentY - popupHeight;
|
|
566
|
-
} else {
|
|
567
|
-
// Force below with clipping
|
|
568
|
-
finalY = Math.min(windowHeight - popupHeight, componentY + componentHeight);
|
|
569
|
-
}
|
|
660
|
+
showAbove = false;
|
|
661
|
+
finalY = componentY + componentHeight ;
|
|
662
|
+
console.log('🔥 AutoPositionedPopup: Emergency below - larger space, finalY=', finalY);
|
|
570
663
|
}
|
|
571
664
|
}
|
|
572
|
-
|
|
573
|
-
//
|
|
574
|
-
|
|
575
|
-
finalY
|
|
665
|
+
|
|
666
|
+
// Enhanced boundary check with detailed logging
|
|
667
|
+
console.log('🔥 Pre-boundary check:', {
|
|
668
|
+
originalFinalY: finalY,
|
|
669
|
+
showAbove,
|
|
670
|
+
statusBarHeight,
|
|
671
|
+
windowHeight,
|
|
672
|
+
popupHeight,
|
|
673
|
+
'finalY < statusBarHeight': finalY < statusBarHeight,
|
|
674
|
+
'finalY + popupHeight > windowHeight': finalY + popupHeight > windowHeight
|
|
675
|
+
});
|
|
676
|
+
|
|
677
|
+
if (showAbove && finalY < statusBarHeight) {
|
|
678
|
+
const oldFinalY = finalY;
|
|
679
|
+
finalY = statusBarHeight;
|
|
680
|
+
console.log('🔥 BOUNDARY FIX: Above display adjusted for status bar:', oldFinalY, '->', finalY);
|
|
576
681
|
}
|
|
577
|
-
|
|
682
|
+
|
|
683
|
+
if (!showAbove && finalY + popupHeight > windowHeight) {
|
|
684
|
+
const oldFinalY = finalY;
|
|
578
685
|
finalY = windowHeight - popupHeight;
|
|
686
|
+
console.log('🔥 BOUNDARY FIX: Below display adjusted to fit window:', oldFinalY, '->', finalY);
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
// CRITICAL CHECK: Detect if boundary check is changing display direction
|
|
690
|
+
if (showAbove && finalY + popupHeight > componentY ) {
|
|
691
|
+
console.log('🚨 WARNING: Above positioning may overlap with component!');
|
|
579
692
|
}
|
|
580
|
-
|
|
581
|
-
|
|
693
|
+
|
|
694
|
+
if (!showAbove && finalY < componentY + componentHeight ) {
|
|
695
|
+
console.log('🚨 WARNING: Below positioning may overlap with component!');
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
console.log('🔥 Post-boundary check final result:', {
|
|
699
|
+
finalY,
|
|
700
|
+
showAbove,
|
|
701
|
+
'popupTop': finalY,
|
|
702
|
+
'popupBottom': finalY + popupHeight,
|
|
703
|
+
'componentTop': componentY,
|
|
704
|
+
'componentBottom': componentY + componentHeight
|
|
705
|
+
});
|
|
706
|
+
|
|
707
|
+
return {finalY, showAbove};
|
|
582
708
|
};
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
709
|
+
|
|
710
|
+
// Calculate position ONCE based on actual popup height
|
|
711
|
+
const actualPopupHeight = CustomPopView && CustomPopViewStyle && typeof CustomPopViewStyle.height === 'number'
|
|
712
|
+
? CustomPopViewStyle.height
|
|
713
|
+
: listLayout.height;
|
|
714
|
+
|
|
715
|
+
console.log('🔥 Using actualPopupHeight for calculation:', actualPopupHeight, 'CustomPopView:', !!CustomPopView);
|
|
716
|
+
|
|
717
|
+
const positionResult = calculateOptimalPosition(y, height, actualPopupHeight);
|
|
718
|
+
console.log('AutoPositionedPopup FINAL position result:', positionResult);
|
|
719
|
+
|
|
587
720
|
ref_listPos.current = {x: x, y: positionResult.finalY, width: width};
|
|
588
721
|
console.log('AutoPositionedPopup ref_listPos.current=', ref_listPos.current);
|
|
722
|
+
|
|
589
723
|
if (CustomPopView && CustomPopViewStyle) {
|
|
590
724
|
console.log('AutoPositionedPopup CustomPopViewStyle=', CustomPopViewStyle);
|
|
591
|
-
//
|
|
592
|
-
const customHeight =
|
|
593
|
-
typeof CustomPopViewStyle.height === 'number' ? CustomPopViewStyle.height : listLayout.height;
|
|
594
|
-
|
|
595
|
-
// Apply same intelligent positioning strategy for CustomPopView
|
|
596
|
-
console.log('AutoPositionedPopup CustomPopView using intelligent positioning, customHeight=', customHeight);
|
|
597
|
-
|
|
598
|
-
// Use the same intelligent positioning function for CustomPopView
|
|
599
|
-
const customPositionResult = calculateOptimalPosition(y, height, customHeight);
|
|
600
|
-
console.log('AutoPositionedPopup CustomPopView position result:', customPositionResult, 'tag=', tag);
|
|
601
|
-
|
|
602
|
-
ref_listPos.current = {x: x, y: customPositionResult.finalY, width: width};
|
|
725
|
+
// Position already calculated correctly above, no need to recalculate
|
|
603
726
|
const PopViewComponent = CustomPopView();
|
|
604
727
|
console.log('AutoPositionedPopup addRootView PopViewComponent=', PopViewComponent);
|
|
605
728
|
console.log('AutoPositionedPopup addRootView state.selectedItem=', state.selectedItem);
|
|
@@ -672,7 +795,7 @@ const AutoPositionedPopup: MemoExoticComponent<
|
|
|
672
795
|
}
|
|
673
796
|
}
|
|
674
797
|
if (isKeyboardFullyShown) {
|
|
675
|
-
ref_isFocus.current = state.isFocus;
|
|
798
|
+
ref_isFocus.current = state.isFocus ?? false;
|
|
676
799
|
if (isKeyboardFullyShown !== keyboardVisibleRef.current) {
|
|
677
800
|
keyboardVisibleRef.current = isKeyboardFullyShown;
|
|
678
801
|
if (isKeyboardFullyShown && textInputRef.current) {
|
|
@@ -1,19 +1,72 @@
|
|
|
1
1
|
declare module 'react-native-advanced-flatlist' {
|
|
2
|
-
import { ComponentType } from 'react';
|
|
3
|
-
import {
|
|
2
|
+
import React, { ComponentType, ReactNode } from 'react';
|
|
3
|
+
import { StyleProp, ViewStyle } from 'react-native';
|
|
4
4
|
|
|
5
|
-
export interface
|
|
6
|
-
|
|
5
|
+
export interface ListItem {
|
|
6
|
+
id: string | number;
|
|
7
|
+
selected?: boolean;
|
|
8
|
+
[key: string]: any;
|
|
7
9
|
}
|
|
8
10
|
|
|
9
|
-
export
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
export interface ListData {
|
|
12
|
+
items: ListItem[];
|
|
13
|
+
pageIndex?: number;
|
|
14
|
+
needLoadMore?: boolean;
|
|
15
|
+
}
|
|
12
16
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
17
|
+
export interface FetchDataParams {
|
|
18
|
+
pageIndex: number;
|
|
19
|
+
pageSize: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface RenderItemParams {
|
|
23
|
+
item: ListItem;
|
|
24
|
+
index: number;
|
|
25
|
+
selected?: boolean;
|
|
26
|
+
onItemPress?: (item: ListItem, index: number) => void;
|
|
27
|
+
}
|
|
16
28
|
|
|
17
|
-
|
|
18
|
-
|
|
29
|
+
export interface AdvancedFlatListProps {
|
|
30
|
+
tag?: string;
|
|
31
|
+
initialData?: Partial<ListData>;
|
|
32
|
+
initPageIndex?: number;
|
|
33
|
+
pageSize?: number;
|
|
34
|
+
fetchData: (params: FetchDataParams) => Promise<ListData | null>;
|
|
35
|
+
renderItem?: (params: RenderItemParams) => React.ReactNode;
|
|
36
|
+
keyExtractor?: (item: ListItem, index: number) => string;
|
|
37
|
+
style?: StyleProp<ViewStyle>;
|
|
38
|
+
ListHeaderComponent?: ReactNode;
|
|
39
|
+
ListEmptyComponent?: React.ComponentType<any> | React.ReactElement<unknown> | null | undefined;
|
|
40
|
+
autoRefresh?: boolean;
|
|
41
|
+
disabledRefresh?: boolean;
|
|
42
|
+
keyboardShouldPersistTaps?: 'always' | 'never' | 'handled' | undefined;
|
|
43
|
+
emptyText?: string;
|
|
44
|
+
showListEmptyComponent?: boolean;
|
|
45
|
+
onScrollBeginDrag?: (event: any) => void;
|
|
46
|
+
onScrollEndDrag?: (event: any) => void;
|
|
47
|
+
singleSelect?: boolean;
|
|
48
|
+
onSingleSelectChange?: (selectedItem: ListItem | null) => void;
|
|
49
|
+
onItemPress?: (item: ListItem, index: number) => void;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface AdvancedFlatListRef {
|
|
53
|
+
scrollToTop: () => void;
|
|
54
|
+
refresh: () => void;
|
|
55
|
+
stopRefresh: () => void;
|
|
56
|
+
getItems: () => ListItem[];
|
|
57
|
+
changeItemSelect: (index: number) => void;
|
|
58
|
+
clearSelection: () => void;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface InternalState {
|
|
62
|
+
items: ListItem[];
|
|
63
|
+
pageIndex: number;
|
|
64
|
+
loading: boolean;
|
|
65
|
+
refreshing: boolean;
|
|
66
|
+
needLoadMore: boolean;
|
|
67
|
+
selectedId: string | number | null;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export const AdvancedFlatList: ComponentType<AdvancedFlatListProps>;
|
|
71
|
+
export default AdvancedFlatList;
|
|
19
72
|
}
|