@swan-io/lake 8.4.6 → 8.5.0
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/package.json +1 -1
- package/src/components/FilterChooser.js +2 -1
- package/src/components/Filters.js +2 -1
- package/src/components/FlatList.d.ts +31 -0
- package/src/components/FlatList.js +34 -0
- package/src/components/LakeCombobox.js +6 -9
- package/src/components/LakeSelect.js +2 -1
- package/src/components/MultiSelect.js +5 -4
- package/src/components/SectionList.d.ts +33 -0
- package/src/components/SectionList.js +35 -0
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useRef } from "react";
|
|
3
|
-
import {
|
|
3
|
+
import { Pressable, StyleSheet, View } from "react-native";
|
|
4
4
|
import { colors } from "../constants/design";
|
|
5
5
|
import { useDisclosure } from "../hooks/useDisclosure";
|
|
6
6
|
import { isNotNullishOrEmpty } from "../utils/nullish";
|
|
7
7
|
import { Box } from "./Box";
|
|
8
|
+
import { FlatList } from "./FlatList";
|
|
8
9
|
import { Icon } from "./Icon";
|
|
9
10
|
import { LakeButton } from "./LakeButton";
|
|
10
11
|
import { LakeText } from "./LakeText";
|
|
@@ -3,7 +3,7 @@ import { DatePickerModal, } from "@swan-io/shared-business/src/components/DatePi
|
|
|
3
3
|
import { useForm } from "@swan-io/use-form";
|
|
4
4
|
import dayjs from "dayjs";
|
|
5
5
|
import { forwardRef, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
6
|
-
import {
|
|
6
|
+
import { Pressable, StyleSheet, Text, View } from "react-native";
|
|
7
7
|
import { P, match } from "ts-pattern";
|
|
8
8
|
import { colors, shadows, spacings } from "../constants/design";
|
|
9
9
|
import { useDisclosure } from "../hooks/useDisclosure";
|
|
@@ -11,6 +11,7 @@ import { useMergeRefs } from "../hooks/useMergeRefs";
|
|
|
11
11
|
import { usePreviousValue } from "../hooks/usePreviousValue";
|
|
12
12
|
import { isNotNullish } from "../utils/nullish";
|
|
13
13
|
import { Box } from "./Box";
|
|
14
|
+
import { FlatList } from "./FlatList";
|
|
14
15
|
import { Icon } from "./Icon";
|
|
15
16
|
import { LakeButton } from "./LakeButton";
|
|
16
17
|
import { LakeCheckbox } from "./LakeCheckbox";
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { ForwardedRef, ReactNode } from "react";
|
|
2
|
+
import { ScrollView, ScrollViewProps, StyleProp, ViewStyle, WebRole } from "react-native";
|
|
3
|
+
export type FlatListRef = ScrollView;
|
|
4
|
+
export type ListRenderItemInfo<T> = {
|
|
5
|
+
item: T;
|
|
6
|
+
index: number;
|
|
7
|
+
};
|
|
8
|
+
type Props<T> = {
|
|
9
|
+
ItemSeparatorComponent?: ReactNode;
|
|
10
|
+
ListEmptyComponent?: ReactNode;
|
|
11
|
+
ListFooterComponent?: ReactNode;
|
|
12
|
+
ListHeaderComponent?: ReactNode;
|
|
13
|
+
contentContainerStyle?: StyleProp<ViewStyle>;
|
|
14
|
+
data: T[];
|
|
15
|
+
horizontal?: boolean;
|
|
16
|
+
keyExtractor: (item: T, index: number) => string;
|
|
17
|
+
onEndReached?: () => void;
|
|
18
|
+
onEndReachedThresholdPx?: number;
|
|
19
|
+
onKeyDown?: ScrollViewProps["onKeyDown"];
|
|
20
|
+
onScroll?: ScrollViewProps["onScroll"];
|
|
21
|
+
renderItem: (info: ListRenderItemInfo<T>) => ReactNode;
|
|
22
|
+
role?: WebRole;
|
|
23
|
+
scrollEventThrottle?: number;
|
|
24
|
+
showsScrollIndicators?: boolean;
|
|
25
|
+
style?: StyleProp<ViewStyle>;
|
|
26
|
+
};
|
|
27
|
+
declare const FlatListWithRef: <T>({ ItemSeparatorComponent, ListEmptyComponent, ListFooterComponent, ListHeaderComponent, contentContainerStyle, data, horizontal, keyExtractor, onEndReached, onEndReachedThresholdPx, onKeyDown, onScroll, renderItem, role, scrollEventThrottle, showsScrollIndicators, style, }: Props<T>, forwardedRef: ForwardedRef<FlatListRef>) => import("react/jsx-runtime").JSX.Element;
|
|
28
|
+
export declare const FlatList: <T>(props: Props<T> & {
|
|
29
|
+
ref?: ForwardedRef<FlatListRef>;
|
|
30
|
+
}) => ReturnType<typeof FlatListWithRef>;
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Fragment, forwardRef, useEffect, useRef } from "react";
|
|
3
|
+
import { ScrollView, StyleSheet, View, } from "react-native";
|
|
4
|
+
const styles = StyleSheet.create({
|
|
5
|
+
scrollTracker: {
|
|
6
|
+
position: "absolute",
|
|
7
|
+
pointerEvents: "none",
|
|
8
|
+
left: 0,
|
|
9
|
+
bottom: 0,
|
|
10
|
+
right: 0,
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
const FlatListWithRef = ({ ItemSeparatorComponent, ListEmptyComponent, ListFooterComponent, ListHeaderComponent, contentContainerStyle, data, horizontal = false, keyExtractor, onEndReached, onEndReachedThresholdPx = 200, onKeyDown, onScroll, renderItem, role, scrollEventThrottle = 0, showsScrollIndicators = true, style, }, forwardedRef) => {
|
|
14
|
+
const scrollTrackerRef = useRef(null);
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
const element = scrollTrackerRef.current;
|
|
17
|
+
if (element != null) {
|
|
18
|
+
const observer = new IntersectionObserver(entries => {
|
|
19
|
+
entries.forEach(entry => {
|
|
20
|
+
if (entry.isIntersecting) {
|
|
21
|
+
onEndReached === null || onEndReached === void 0 ? void 0 : onEndReached();
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
observer.observe(element);
|
|
26
|
+
return () => {
|
|
27
|
+
observer.unobserve(element);
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
// re-create an observer only on list length change
|
|
31
|
+
}, [data.length]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
32
|
+
return (_jsxs(ScrollView, { contentContainerStyle: contentContainerStyle, horizontal: horizontal, onKeyDown: onKeyDown, onScroll: onScroll, ref: forwardedRef, role: role, scrollEventThrottle: scrollEventThrottle, showsHorizontalScrollIndicator: showsScrollIndicators, showsVerticalScrollIndicator: showsScrollIndicators, style: style, children: [ListHeaderComponent, data.length > 0 ? (_jsxs(View, { children: [data.map((item, index) => (_jsxs(Fragment, { children: [index !== 0 && ItemSeparatorComponent, renderItem({ item, index })] }, keyExtractor(item, index)))), _jsx(View, { ref: scrollTrackerRef, style: [styles.scrollTracker, { height: onEndReachedThresholdPx }] })] })) : (ListEmptyComponent), ListFooterComponent] }));
|
|
33
|
+
};
|
|
34
|
+
export const FlatList = forwardRef(FlatListWithRef);
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { forwardRef, useCallback, useId, useImperativeHandle, useRef, useState, } from "react";
|
|
3
|
-
import {
|
|
3
|
+
import { Pressable, StyleSheet, Text, View, } from "react-native";
|
|
4
4
|
import { backgroundColor, colors, spacings } from "../constants/design";
|
|
5
5
|
import { useMergeRefs } from "../hooks/useMergeRefs";
|
|
6
6
|
import { getFocusableElements } from "../utils/a11y";
|
|
7
7
|
import { isNotEmpty } from "../utils/nullish";
|
|
8
8
|
import { Box } from "./Box";
|
|
9
|
+
import { FlatList } from "./FlatList";
|
|
9
10
|
import { Icon } from "./Icon";
|
|
10
11
|
import { LakeText } from "./LakeText";
|
|
11
12
|
import { LakeTextInput } from "./LakeTextInput";
|
|
@@ -19,7 +20,9 @@ const styles = StyleSheet.create({
|
|
|
19
20
|
list: {
|
|
20
21
|
marginVertical: spacings[8],
|
|
21
22
|
},
|
|
22
|
-
flatList: {
|
|
23
|
+
flatList: {
|
|
24
|
+
scrollBehavior: "smooth",
|
|
25
|
+
},
|
|
23
26
|
item: {
|
|
24
27
|
flexShrink: 1,
|
|
25
28
|
flexGrow: 1,
|
|
@@ -71,15 +74,9 @@ const styles = StyleSheet.create({
|
|
|
71
74
|
flexGrow: 1,
|
|
72
75
|
},
|
|
73
76
|
});
|
|
74
|
-
const getItemLayout = (_data, index) => ({
|
|
75
|
-
length: DEFAULT_ELEMENT_HEIGHT,
|
|
76
|
-
offset: DEFAULT_ELEMENT_HEIGHT * index,
|
|
77
|
-
index,
|
|
78
|
-
});
|
|
79
77
|
const LakeComboboxWithRef = ({ inputRef, value, items, itemHeight = DEFAULT_ELEMENT_HEIGHT, nbItemsDisplayed = DEFAULT_NB_SUGGESTION_DISPLAYED, ListFooterComponent, onChange, onValueChange, onSelectItem, renderItem, keyExtractor, icon, placeholder, disabled = false, emptyResultText, readOnly, id, error, hideErrors, }, forwardedRef) => {
|
|
80
78
|
const ref = useRef(null);
|
|
81
79
|
const inputTextRef = useMergeRefs(ref, inputRef);
|
|
82
|
-
const listRef = useRef(null);
|
|
83
80
|
const listContainerRef = useRef(null);
|
|
84
81
|
const blurTimeoutId = useRef(undefined);
|
|
85
82
|
const [isFetchingAdditionalInfo, setIsFetchingAdditionalInfo] = useState(false);
|
|
@@ -156,7 +153,7 @@ const LakeComboboxWithRef = ({ inputRef, value, items, itemHeight = DEFAULT_ELEM
|
|
|
156
153
|
Loading: () => _jsx(LoadingView, { style: styles.loader }),
|
|
157
154
|
Done: items => items.match({
|
|
158
155
|
Error: _ => (_jsx(Icon, { name: "error-circle-regular", size: 22, color: colors.negative[500] })),
|
|
159
|
-
Ok: items => (_jsxs(View, { ref: listContainerRef, style: styles.listContainer, children: [items.length === 0 ? (_jsxs(Box, { justifyContent: "center", alignItems: "center", style: styles.emptyList, children: [_jsx(Icon, { name: "clipboard-search-regular", size: 24, color: colors.gray.primary }), _jsx(Space, { height: 8 }), _jsx(Text, { style: styles.emptyListText, children: emptyResultText })] })) : (_jsx(FlatList, {
|
|
156
|
+
Ok: items => (_jsxs(View, { ref: listContainerRef, style: styles.listContainer, children: [items.length === 0 ? (_jsxs(Box, { justifyContent: "center", alignItems: "center", style: styles.emptyList, children: [_jsx(Icon, { name: "clipboard-search-regular", size: 24, color: colors.gray.primary }), _jsx(Space, { height: 8 }), _jsx(Text, { style: styles.emptyListText, children: emptyResultText })] })) : (_jsx(FlatList, { keyExtractor: keyExtractor, role: "list", data: items, style: styles.flatList, ItemSeparatorComponent: _jsx(Separator, {}), renderItem: ({ item }) => {
|
|
160
157
|
const rendered = renderItem(item);
|
|
161
158
|
return (_jsx(Pressable, { onFocus: handleFocus, onBlur: handleBlur, role: "listitem", onKeyDown: handleListItemKeyPress, style: ({ hovered, pressed, focused }) => [
|
|
162
159
|
styles.item,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { forwardRef, useCallback, useRef, } from "react";
|
|
3
|
-
import {
|
|
3
|
+
import { StyleSheet, View, } from "react-native";
|
|
4
4
|
import { commonStyles } from "../constants/commonStyles";
|
|
5
5
|
import { colors, invariantColors, radii, shadows, spacings, texts, } from "../constants/design";
|
|
6
6
|
import { useDisclosure } from "../hooks/useDisclosure";
|
|
@@ -9,6 +9,7 @@ import { getFocusableElements } from "../utils/a11y";
|
|
|
9
9
|
import { isNotNullish, isNullishOrEmpty } from "../utils/nullish";
|
|
10
10
|
import { Box } from "./Box";
|
|
11
11
|
import { Fill } from "./Fill";
|
|
12
|
+
import { FlatList } from "./FlatList";
|
|
12
13
|
import { Icon } from "./Icon";
|
|
13
14
|
import { LakeText } from "./LakeText";
|
|
14
15
|
import { LakeTooltip } from "./LakeTooltip";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { Array, Dict, Option } from "@swan-io/boxed";
|
|
3
3
|
import { memo, useEffect, useMemo, useRef, useState } from "react";
|
|
4
|
-
import {
|
|
4
|
+
import { Pressable, StyleSheet, Text, TextInput, View, } from "react-native";
|
|
5
5
|
import { backgroundColor, colors, radii, shadows, texts } from "../constants/design";
|
|
6
6
|
import { useBoolean } from "../hooks/useBoolean";
|
|
7
7
|
import { useDisclosure } from "../hooks/useDisclosure";
|
|
@@ -9,10 +9,12 @@ import { groupBy } from "../utils/array";
|
|
|
9
9
|
import { isNotNullish, isNotNullishOrEmpty } from "../utils/nullish";
|
|
10
10
|
import { safeSplitAround } from "../utils/string";
|
|
11
11
|
import { Box } from "./Box";
|
|
12
|
+
import { FlatList } from "./FlatList";
|
|
12
13
|
import { Icon } from "./Icon";
|
|
13
14
|
import { InputError } from "./InputError";
|
|
14
15
|
import { Popover } from "./Popover";
|
|
15
16
|
import { PressableText } from "./Pressable";
|
|
17
|
+
import { SectionList } from "./SectionList";
|
|
16
18
|
import { Space } from "./Space";
|
|
17
19
|
import { Tag } from "./Tag";
|
|
18
20
|
const MAX_INPUT_HEIGHT = 120;
|
|
@@ -141,7 +143,6 @@ export const MultiSelect = memo(({ color = "gray", disabled = false, emptyResult
|
|
|
141
143
|
const shouldScrollToBottomRef = useRef(false);
|
|
142
144
|
const selectedTagListRef = useRef(null);
|
|
143
145
|
const inputRef = useRef(null);
|
|
144
|
-
const listRef = useRef(null);
|
|
145
146
|
const [visible, { open, close }] = useDisclosure(false);
|
|
146
147
|
const tint50 = colors[color][50];
|
|
147
148
|
const tint100 = colors[color][100];
|
|
@@ -198,11 +199,11 @@ export const MultiSelect = memo(({ color = "gray", disabled = false, emptyResult
|
|
|
198
199
|
(focused || visible) && styles.focused,
|
|
199
200
|
disabled && styles.disabled,
|
|
200
201
|
isNotNullish(error) && styles.errored,
|
|
201
|
-
], children: [_jsx(Box, { ref: selectedTagListRef, alignItems: "center", direction: "row", style: styles.tagsList, children: selectedTags.length > 0 ? (selectedTags.map(item => (_jsx(Tag, { color: color, onPressRemove: disabled ? undefined : () => handleRemoveItem(item), style: styles.tag, children: item.label }, item.value)))) : placeholder !== "" ? (_jsx(Text, { role: "label", numberOfLines: 1, style: styles.placeholder, children: placeholder })) : null }), _jsxs(Box, { direction: "row", alignItems: "center", style: styles.actions, children: [selectedTags.length >= 1 && !disabled && (_jsxs(_Fragment, { children: [_jsx(Pressable, { role: "button", onPress: handleClearAll, children: _jsx(Icon, { name: "dismiss-filled", color: colors.gray.primary, size: 15 }) }), _jsx(Space, { width: 8 })] })), _jsx(Icon, { color: colors.gray.primary, name: visible ? "chevron-up-filled" : "chevron-down-filled", size: 20 })] })] }), _jsx(Popover, { role: "listbox", matchReferenceWidth: true, onDismiss: close, referenceRef: inputRef, returnFocus: true, visible: visible, children: _jsx(View, { style: styles.list, children: enableGroups ? (_jsx(SectionList, { role: "listbox", "aria-multiselectable": true, keyExtractor: (item, index) => `group-field-${item.value}-${index}`,
|
|
202
|
+
], children: [_jsx(Box, { ref: selectedTagListRef, alignItems: "center", direction: "row", style: styles.tagsList, children: selectedTags.length > 0 ? (selectedTags.map(item => (_jsx(Tag, { color: color, onPressRemove: disabled ? undefined : () => handleRemoveItem(item), style: styles.tag, children: item.label }, item.value)))) : placeholder !== "" ? (_jsx(Text, { role: "label", numberOfLines: 1, style: styles.placeholder, children: placeholder })) : null }), _jsxs(Box, { direction: "row", alignItems: "center", style: styles.actions, children: [selectedTags.length >= 1 && !disabled && (_jsxs(_Fragment, { children: [_jsx(Pressable, { role: "button", onPress: handleClearAll, children: _jsx(Icon, { name: "dismiss-filled", color: colors.gray.primary, size: 15 }) }), _jsx(Space, { width: 8 })] })), _jsx(Icon, { color: colors.gray.primary, name: visible ? "chevron-up-filled" : "chevron-down-filled", size: 20 })] })] }), _jsx(Popover, { role: "listbox", matchReferenceWidth: true, onDismiss: close, referenceRef: inputRef, returnFocus: true, visible: visible, children: _jsx(View, { style: styles.list, children: enableGroups ? (_jsx(SectionList, { role: "listbox", "aria-multiselectable": true, keyExtractor: (item, index) => `group-field-${item.value}-${index}`, ListHeaderComponent: ListHeaderComponent, ListEmptyComponent: ListEmptyComponent, ListFooterComponent: _jsx(Space, { height: 16 }), sections: sections, renderSectionHeader: ({ title, data }) => (_jsxs(Pressable, { role: "listitem", onPress: () => handleSelectGroup(data), style: ({ hovered, pressed, focused }) => [
|
|
202
203
|
styles.groupTitleBase,
|
|
203
204
|
(hovered || focused) && { backgroundColor: tint50 },
|
|
204
205
|
pressed && { backgroundColor: tint100 },
|
|
205
|
-
], children: [_jsx(Text, { numberOfLines: 1, style: styles.groupTitle, children: title }), isNotNullish(renderTagGroup) && (_jsx(Tag, { color: color, children: renderTagGroup(data) }))] })), renderItem: ({ item }) => (_jsx(LineItem, { color: color, filter: filter, item: item, handleSelectItem: handleSelectItem, style: styles.lineInGroup })) })) : (_jsx(FlatList, {
|
|
206
|
+
], children: [_jsx(Text, { numberOfLines: 1, style: styles.groupTitle, children: title }), isNotNullish(renderTagGroup) && (_jsx(Tag, { color: color, children: renderTagGroup(data) }))] })), renderItem: ({ item }) => (_jsx(LineItem, { color: color, filter: filter, item: item, handleSelectItem: handleSelectItem, style: styles.lineInGroup })) })) : (_jsx(FlatList, { role: "list", data: filteredItems, keyExtractor: item => `field-${item.value}`, ListHeaderComponent: ListHeaderComponent, ListEmptyComponent: ListEmptyComponent, ListFooterComponent: _jsx(Space, { height: 8 }), renderItem: ({ item }) => (_jsx(LineItem, { color: color, filter: filter, item: item, handleSelectItem: handleSelectItem })) })) }) }), _jsx(InputError, { message: error })] }));
|
|
206
207
|
});
|
|
207
208
|
const LineItem = ({ item, color, filter, handleSelectItem, style }) => {
|
|
208
209
|
const { label, disabled = false } = item;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { ForwardedRef, ReactNode } from "react";
|
|
2
|
+
import { ScrollView, ScrollViewProps, StyleProp, ViewStyle, WebRole } from "react-native";
|
|
3
|
+
import { ListRenderItemInfo } from "./FlatList";
|
|
4
|
+
export type SectionListRef = ScrollView;
|
|
5
|
+
type Section<T> = {
|
|
6
|
+
title: string;
|
|
7
|
+
data: T[];
|
|
8
|
+
};
|
|
9
|
+
type Props<T> = {
|
|
10
|
+
ItemSeparatorComponent?: ReactNode;
|
|
11
|
+
ListEmptyComponent?: ReactNode;
|
|
12
|
+
ListFooterComponent?: ReactNode;
|
|
13
|
+
ListHeaderComponent?: ReactNode;
|
|
14
|
+
contentContainerStyle?: StyleProp<ViewStyle>;
|
|
15
|
+
horizontal?: boolean;
|
|
16
|
+
keyExtractor: (item: T, index: number) => string;
|
|
17
|
+
onEndReached?: () => void;
|
|
18
|
+
onEndReachedThresholdPx?: number;
|
|
19
|
+
onKeyDown?: ScrollViewProps["onKeyDown"];
|
|
20
|
+
onScroll?: ScrollViewProps["onScroll"];
|
|
21
|
+
renderItem: (info: ListRenderItemInfo<T>) => ReactNode;
|
|
22
|
+
renderSectionHeader?: (section: Section<T>) => ReactNode;
|
|
23
|
+
role?: WebRole;
|
|
24
|
+
scrollEventThrottle?: number;
|
|
25
|
+
sections: Section<T>[];
|
|
26
|
+
showsScrollIndicators?: boolean;
|
|
27
|
+
style?: StyleProp<ViewStyle>;
|
|
28
|
+
};
|
|
29
|
+
declare const SectionListWithRef: <T>({ ItemSeparatorComponent, ListEmptyComponent, ListFooterComponent, ListHeaderComponent, contentContainerStyle, horizontal, keyExtractor, onEndReached, onEndReachedThresholdPx, onKeyDown, onScroll, renderItem, renderSectionHeader, role, scrollEventThrottle, sections, showsScrollIndicators, style, }: Props<T>, forwardedRef: ForwardedRef<SectionListRef>) => import("react/jsx-runtime").JSX.Element;
|
|
30
|
+
export declare const SectionList: <T>(props: Props<T> & {
|
|
31
|
+
ref?: ForwardedRef<SectionListRef>;
|
|
32
|
+
}) => ReturnType<typeof SectionListWithRef>;
|
|
33
|
+
export {};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Fragment, forwardRef, useEffect, useId, useRef } from "react";
|
|
3
|
+
import { ScrollView, StyleSheet, View, } from "react-native";
|
|
4
|
+
const styles = StyleSheet.create({
|
|
5
|
+
scrollTracker: {
|
|
6
|
+
position: "absolute",
|
|
7
|
+
pointerEvents: "none",
|
|
8
|
+
bottom: 0,
|
|
9
|
+
left: 0,
|
|
10
|
+
right: 0,
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
const SectionListWithRef = ({ ItemSeparatorComponent, ListEmptyComponent, ListFooterComponent, ListHeaderComponent, contentContainerStyle, horizontal = false, keyExtractor, onEndReached, onEndReachedThresholdPx = 200, onKeyDown, onScroll, renderItem, renderSectionHeader, role, scrollEventThrottle = 0, sections, showsScrollIndicators = true, style, }, forwardedRef) => {
|
|
14
|
+
const groupId = useId();
|
|
15
|
+
const scrollTrackerRef = useRef(null);
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
const element = scrollTrackerRef.current;
|
|
18
|
+
if (element != null) {
|
|
19
|
+
const observer = new IntersectionObserver(entries => {
|
|
20
|
+
entries.forEach(entry => {
|
|
21
|
+
if (entry.isIntersecting) {
|
|
22
|
+
onEndReached === null || onEndReached === void 0 ? void 0 : onEndReached();
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
observer.observe(element);
|
|
27
|
+
return () => {
|
|
28
|
+
observer.unobserve(element);
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
// re-create an observer only on list length change
|
|
32
|
+
}, [sections.length]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
33
|
+
return (_jsxs(ScrollView, { contentContainerStyle: contentContainerStyle, horizontal: horizontal, onKeyDown: onKeyDown, onScroll: onScroll, ref: forwardedRef, role: role, scrollEventThrottle: scrollEventThrottle, showsHorizontalScrollIndicator: showsScrollIndicators, showsVerticalScrollIndicator: showsScrollIndicators, style: style, children: [ListHeaderComponent, sections.length > 0 ? (_jsxs(View, { children: [sections.map(section => (_jsxs(Fragment, { children: [renderSectionHeader === null || renderSectionHeader === void 0 ? void 0 : renderSectionHeader(section), section.data.map((item, index) => (_jsxs(Fragment, { children: [index !== 0 && ItemSeparatorComponent, renderItem({ item, index })] }, keyExtractor(item, index))))] }, `group-${groupId}-${section.title}`))), _jsx(View, { ref: scrollTrackerRef, style: [styles.scrollTracker, { height: onEndReachedThresholdPx }] })] })) : (ListEmptyComponent), ListFooterComponent] }));
|
|
34
|
+
};
|
|
35
|
+
export const SectionList = forwardRef(SectionListWithRef);
|