@legendapp/list 2.0.0-next.2 → 2.0.0-next.4
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/{dist/index.d.mts → index.d.mts} +28 -21
- package/{dist/index.d.ts → index.d.ts} +28 -21
- package/{dist/index.js → index.js} +808 -760
- package/{dist/index.mjs → index.mjs} +808 -760
- package/{dist → integrations}/animated.d.mts +2 -1
- package/{dist → integrations}/animated.d.ts +2 -1
- package/{dist → integrations}/animated.js +2 -2
- package/{dist → integrations}/animated.mjs +2 -2
- package/{dist → integrations}/keyboard-controller.d.mts +4 -0
- package/{dist → integrations}/keyboard-controller.d.ts +4 -0
- package/{dist → integrations}/keyboard-controller.js +4 -4
- package/{dist → integrations}/keyboard-controller.mjs +4 -4
- package/{dist → integrations}/reanimated.js +7 -7
- package/{dist → integrations}/reanimated.mjs +7 -7
- package/package.json +34 -88
- package/.claude/settings.local.json +0 -8
- package/.cursor/rules/changelog.mdc +0 -60
- package/.github/FUNDING.yml +0 -15
- package/.gitignore +0 -5
- package/.prettierrc.json +0 -5
- package/.vscode/settings.json +0 -14
- package/CLAUDE.md +0 -126
- package/biome.json +0 -46
- package/bun.lock +0 -1289
- package/bunfig.toml +0 -2
- package/dist/CHANGELOG.md +0 -119
- package/dist/LICENSE +0 -21
- package/dist/README.md +0 -139
- package/dist/package.json +0 -35
- package/example/README.md +0 -40
- package/example/api/data/genres.json +0 -23
- package/example/api/data/playlist/10402-10749.json +0 -1
- package/example/api/data/playlist/10402-10770.json +0 -1
- package/example/api/data/playlist/10402-37.json +0 -1
- package/example/api/data/playlist/10749-10752.json +0 -1
- package/example/api/data/playlist/10749-10770.json +0 -1
- package/example/api/data/playlist/10749-37.json +0 -1
- package/example/api/data/playlist/10749-878.json +0 -1
- package/example/api/data/playlist/10751-10402.json +0 -1
- package/example/api/data/playlist/10751-10752.json +0 -1
- package/example/api/data/playlist/10751-37.json +0 -1
- package/example/api/data/playlist/10751-53.json +0 -1
- package/example/api/data/playlist/10751-878.json +0 -1
- package/example/api/data/playlist/10751-9648.json +0 -1
- package/example/api/data/playlist/10752-37.json +0 -1
- package/example/api/data/playlist/12-10402.json +0 -1
- package/example/api/data/playlist/12-10749.json +0 -1
- package/example/api/data/playlist/12-18.json +0 -1
- package/example/api/data/playlist/12-27.json +0 -1
- package/example/api/data/playlist/12-35.json +0 -1
- package/example/api/data/playlist/14-36.json +0 -1
- package/example/api/data/playlist/14-878.json +0 -1
- package/example/api/data/playlist/16-10751.json +0 -1
- package/example/api/data/playlist/16-10770.json +0 -1
- package/example/api/data/playlist/16-35.json +0 -1
- package/example/api/data/playlist/16-36.json +0 -1
- package/example/api/data/playlist/16-53.json +0 -1
- package/example/api/data/playlist/18-10751.json +0 -1
- package/example/api/data/playlist/18-10752.json +0 -1
- package/example/api/data/playlist/18-37.json +0 -1
- package/example/api/data/playlist/18-53.json +0 -1
- package/example/api/data/playlist/18-878.json +0 -1
- package/example/api/data/playlist/27-10749.json +0 -1
- package/example/api/data/playlist/27-10770.json +0 -1
- package/example/api/data/playlist/28-10749.json +0 -1
- package/example/api/data/playlist/28-10751.json +0 -1
- package/example/api/data/playlist/28-10770.json +0 -1
- package/example/api/data/playlist/28-16.json +0 -1
- package/example/api/data/playlist/28-18.json +0 -1
- package/example/api/data/playlist/28-36.json +0 -1
- package/example/api/data/playlist/28-37.json +0 -1
- package/example/api/data/playlist/28-53.json +0 -1
- package/example/api/data/playlist/28-80.json +0 -1
- package/example/api/data/playlist/28-99.json +0 -1
- package/example/api/data/playlist/35-10749.json +0 -1
- package/example/api/data/playlist/35-10751.json +0 -1
- package/example/api/data/playlist/35-10752.json +0 -1
- package/example/api/data/playlist/35-27.json +0 -1
- package/example/api/data/playlist/35-36.json +0 -1
- package/example/api/data/playlist/35-53.json +0 -1
- package/example/api/data/playlist/35-80.json +0 -1
- package/example/api/data/playlist/36-37.json +0 -1
- package/example/api/data/playlist/36-878.json +0 -1
- package/example/api/data/playlist/36-9648.json +0 -1
- package/example/api/data/playlist/53-10752.json +0 -1
- package/example/api/data/playlist/80-10770.json +0 -1
- package/example/api/data/playlist/80-14.json +0 -1
- package/example/api/data/playlist/80-18.json +0 -1
- package/example/api/data/playlist/80-37.json +0 -1
- package/example/api/data/playlist/878-37.json +0 -1
- package/example/api/data/playlist/9648-10770.json +0 -1
- package/example/api/data/playlist/9648-37.json +0 -1
- package/example/api/data/playlist/9648-53.json +0 -1
- package/example/api/data/playlist/9648-878.json +0 -1
- package/example/api/data/playlist/99-10749.json +0 -1
- package/example/api/data/playlist/99-14.json +0 -1
- package/example/api/data/playlist/99-18.json +0 -1
- package/example/api/data/playlist/99-27.json +0 -1
- package/example/api/data/playlist/99-53.json +0 -1
- package/example/api/data/playlist/99-9648.json +0 -1
- package/example/api/data/playlist/index.ts +0 -73
- package/example/api/data/rows.json +0 -1
- package/example/api/index.ts +0 -36
- package/example/app/(tabs)/_layout.tsx +0 -60
- package/example/app/(tabs)/cards.tsx +0 -81
- package/example/app/(tabs)/index.tsx +0 -205
- package/example/app/(tabs)/moviesL.tsx +0 -7
- package/example/app/(tabs)/moviesLR.tsx +0 -7
- package/example/app/+not-found.tsx +0 -32
- package/example/app/_layout.tsx +0 -34
- package/example/app/accurate-scrollto/index.tsx +0 -125
- package/example/app/accurate-scrollto-2/index.tsx +0 -52
- package/example/app/accurate-scrollto-huge/index.tsx +0 -128
- package/example/app/add-to-end/index.tsx +0 -82
- package/example/app/ai-chat/index.tsx +0 -236
- package/example/app/bidirectional-infinite-list/index.tsx +0 -133
- package/example/app/cards-columns/index.tsx +0 -37
- package/example/app/cards-flashlist/index.tsx +0 -122
- package/example/app/cards-flatlist/index.tsx +0 -94
- package/example/app/cards-no-recycle/index.tsx +0 -110
- package/example/app/cards-renderItem.tsx +0 -354
- package/example/app/chat-example/index.tsx +0 -167
- package/example/app/chat-infinite/index.tsx +0 -239
- package/example/app/chat-keyboard/index.tsx +0 -248
- package/example/app/chat-resize-outer/index.tsx +0 -247
- package/example/app/columns/index.tsx +0 -78
- package/example/app/countries/index.tsx +0 -182
- package/example/app/countries-flashlist/index.tsx +0 -163
- package/example/app/countries-reorder/index.tsx +0 -187
- package/example/app/extra-data/index.tsx +0 -86
- package/example/app/filter-elements/filter-data-provider.tsx +0 -55
- package/example/app/filter-elements/index.tsx +0 -118
- package/example/app/initial-scroll-index/index.tsx +0 -106
- package/example/app/initial-scroll-index/renderFixedItem.tsx +0 -215
- package/example/app/initial-scroll-index-free-height/index.tsx +0 -70
- package/example/app/initial-scroll-index-keyed/index.tsx +0 -62
- package/example/app/lazy-list/index.tsx +0 -123
- package/example/app/movies-flashlist/index.tsx +0 -7
- package/example/app/mutable-cells/index.tsx +0 -104
- package/example/app/video-feed/index.tsx +0 -119
- package/example/app.config.js +0 -22
- package/example/app.json +0 -45
- package/example/assets/fonts/SpaceMono-Regular.ttf +0 -0
- package/example/assets/images/adaptive-icon.png +0 -0
- package/example/assets/images/favicon.png +0 -0
- package/example/assets/images/icon.png +0 -0
- package/example/assets/images/partial-react-logo.png +0 -0
- package/example/assets/images/react-logo.png +0 -0
- package/example/assets/images/react-logo@2x.png +0 -0
- package/example/assets/images/react-logo@3x.png +0 -0
- package/example/assets/images/splash-icon.png +0 -0
- package/example/autoscroll.sh +0 -101
- package/example/bun.lock +0 -2266
- package/example/bunfig.toml +0 -2
- package/example/components/Breathe.tsx +0 -54
- package/example/components/Circle.tsx +0 -69
- package/example/components/Collapsible.tsx +0 -44
- package/example/components/ExternalLink.tsx +0 -24
- package/example/components/HapticTab.tsx +0 -18
- package/example/components/HelloWave.tsx +0 -37
- package/example/components/Movies.tsx +0 -179
- package/example/components/ParallaxScrollView.tsx +0 -81
- package/example/components/ThemedText.tsx +0 -60
- package/example/components/ThemedView.tsx +0 -14
- package/example/components/__tests__/ThemedText-test.tsx +0 -10
- package/example/components/__tests__/__snapshots__/ThemedText-test.tsx.snap +0 -24
- package/example/components/ui/IconSymbol.ios.tsx +0 -32
- package/example/components/ui/IconSymbol.tsx +0 -43
- package/example/components/ui/TabBarBackground.ios.tsx +0 -22
- package/example/components/ui/TabBarBackground.tsx +0 -6
- package/example/constants/Colors.ts +0 -26
- package/example/constants/constants.ts +0 -5
- package/example/constants/useScrollTest.ts +0 -19
- package/example/hooks/useColorScheme.ts +0 -1
- package/example/hooks/useColorScheme.web.ts +0 -8
- package/example/hooks/useThemeColor.ts +0 -22
- package/example/ios/.xcode.env +0 -11
- package/example/ios/Podfile +0 -64
- package/example/ios/Podfile.lock +0 -2767
- package/example/ios/Podfile.properties.json +0 -5
- package/example/ios/listtest/AppDelegate.swift +0 -70
- package/example/ios/listtest/Images.xcassets/AppIcon.appiconset/App-Icon-1024x1024@1x.png +0 -0
- package/example/ios/listtest/Images.xcassets/AppIcon.appiconset/Contents.json +0 -14
- package/example/ios/listtest/Images.xcassets/Contents.json +0 -6
- package/example/ios/listtest/Images.xcassets/SplashScreenBackground.colorset/Contents.json +0 -20
- package/example/ios/listtest/Images.xcassets/SplashScreenLogo.imageset/Contents.json +0 -23
- package/example/ios/listtest/Images.xcassets/SplashScreenLogo.imageset/image.png +0 -0
- package/example/ios/listtest/Images.xcassets/SplashScreenLogo.imageset/image@2x.png +0 -0
- package/example/ios/listtest/Images.xcassets/SplashScreenLogo.imageset/image@3x.png +0 -0
- package/example/ios/listtest/Info.plist +0 -85
- package/example/ios/listtest/PrivacyInfo.xcprivacy +0 -48
- package/example/ios/listtest/SplashScreen.storyboard +0 -42
- package/example/ios/listtest/Supporting/Expo.plist +0 -12
- package/example/ios/listtest/listtest-Bridging-Header.h +0 -3
- package/example/ios/listtest/listtest.entitlements +0 -5
- package/example/ios/listtest.xcodeproj/project.pbxproj +0 -547
- package/example/ios/listtest.xcodeproj/xcshareddata/xcschemes/listtest.xcscheme +0 -88
- package/example/ios/listtest.xcworkspace/contents.xcworkspacedata +0 -10
- package/example/metro.config.js +0 -16
- package/example/package.json +0 -73
- package/example/scripts/reset-project.js +0 -84
- package/example/tsconfig.json +0 -26
- package/posttsup.ts +0 -24
- package/src/Container.tsx +0 -176
- package/src/Containers.tsx +0 -85
- package/src/ContextContainer.ts +0 -145
- package/src/DebugView.tsx +0 -83
- package/src/LazyLegendList.tsx +0 -41
- package/src/LeanView.tsx +0 -18
- package/src/LegendList.tsx +0 -558
- package/src/ListComponent.tsx +0 -191
- package/src/ScrollAdjust.tsx +0 -24
- package/src/ScrollAdjustHandler.ts +0 -26
- package/src/Separator.tsx +0 -14
- package/src/animated.tsx +0 -6
- package/src/calculateItemsInView.ts +0 -363
- package/src/calculateOffsetForIndex.ts +0 -23
- package/src/calculateOffsetWithOffsetPosition.ts +0 -26
- package/src/checkAllSizesKnown.ts +0 -17
- package/src/checkAtBottom.ts +0 -36
- package/src/checkAtTop.ts +0 -27
- package/src/checkThreshold.ts +0 -30
- package/src/constants.ts +0 -11
- package/src/createColumnWrapperStyle.ts +0 -16
- package/src/doInitialAllocateContainers.ts +0 -40
- package/src/doMaintainScrollAtEnd.ts +0 -34
- package/src/findAvailableContainers.ts +0 -98
- package/src/finishScrollTo.ts +0 -8
- package/src/getId.ts +0 -21
- package/src/getItemSize.ts +0 -52
- package/src/getRenderedItem.ts +0 -34
- package/src/getScrollVelocity.ts +0 -47
- package/src/handleLayout.ts +0 -70
- package/src/helpers.ts +0 -39
- package/src/index.ts +0 -11
- package/src/keyboard-controller.tsx +0 -63
- package/src/onScroll.ts +0 -66
- package/src/prepareMVCP.ts +0 -50
- package/src/reanimated.tsx +0 -63
- package/src/requestAdjust.ts +0 -41
- package/src/scrollTo.ts +0 -40
- package/src/scrollToIndex.ts +0 -34
- package/src/setDidLayout.ts +0 -25
- package/src/setPaddingTop.ts +0 -28
- package/src/state.tsx +0 -304
- package/src/types.ts +0 -610
- package/src/updateAlignItemsPaddingTop.ts +0 -18
- package/src/updateAllPositions.ts +0 -130
- package/src/updateItemSize.ts +0 -203
- package/src/updateTotalSize.ts +0 -44
- package/src/useAnimatedValue.ts +0 -6
- package/src/useCombinedRef.ts +0 -22
- package/src/useInit.ts +0 -17
- package/src/useSyncLayout.tsx +0 -68
- package/src/useValue$.ts +0 -53
- package/src/viewability.ts +0 -279
- package/tsconfig.json +0 -59
- package/tsup.config.ts +0 -21
- package/{dist → integrations}/reanimated.d.mts +1 -1
- package/{dist → integrations}/reanimated.d.ts +1 -1
package/src/onScroll.ts
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import type { NativeScrollEvent, NativeSyntheticEvent } from "react-native";
|
|
2
|
-
import { calculateItemsInView } from "./calculateItemsInView";
|
|
3
|
-
import { checkAtBottom } from "./checkAtBottom";
|
|
4
|
-
import { checkAtTop } from "./checkAtTop";
|
|
5
|
-
import type { StateContext } from "./state";
|
|
6
|
-
import type { InternalState } from "./types";
|
|
7
|
-
|
|
8
|
-
export function onScroll(
|
|
9
|
-
ctx: StateContext,
|
|
10
|
-
state: InternalState,
|
|
11
|
-
event: {
|
|
12
|
-
nativeEvent: NativeScrollEvent;
|
|
13
|
-
},
|
|
14
|
-
) {
|
|
15
|
-
if (event.nativeEvent?.contentSize?.height === 0 && event.nativeEvent.contentSize?.width === 0) {
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
|
|
20
|
-
|
|
21
|
-
// Ignore scroll events that are too close to the previous scroll position
|
|
22
|
-
// after adjusting for MVCP
|
|
23
|
-
const ignoreScrollFromMVCP = state.ignoreScrollFromMVCP;
|
|
24
|
-
if (ignoreScrollFromMVCP && !state.scrollingTo) {
|
|
25
|
-
const { lt, gt } = ignoreScrollFromMVCP;
|
|
26
|
-
if ((lt && newScroll < lt) || (gt && newScroll > gt)) {
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
state.scrollPending = newScroll;
|
|
32
|
-
|
|
33
|
-
updateScroll(ctx, state, newScroll);
|
|
34
|
-
|
|
35
|
-
state.props.onScroll?.(event as NativeSyntheticEvent<NativeScrollEvent>);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function updateScroll(ctx: StateContext, state: InternalState, newScroll: number) {
|
|
39
|
-
const scrollingTo = state.scrollingTo;
|
|
40
|
-
|
|
41
|
-
state.hasScrolled = true;
|
|
42
|
-
state.lastBatchingAction = Date.now();
|
|
43
|
-
const currentTime = performance.now();
|
|
44
|
-
|
|
45
|
-
// Don't add to the history if it's initial scroll event otherwise invalid velocity will be calculated
|
|
46
|
-
// Don't add to the history if we are scrolling to an offset
|
|
47
|
-
if (scrollingTo === undefined && !(state.scrollHistory.length === 0 && newScroll === state.scroll)) {
|
|
48
|
-
// Update scroll history
|
|
49
|
-
state.scrollHistory.push({ scroll: newScroll, time: currentTime });
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// Keep only last 5 entries
|
|
53
|
-
if (state.scrollHistory.length > 5) {
|
|
54
|
-
state.scrollHistory.shift();
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Update current scroll state
|
|
58
|
-
state.scrollPrev = state.scroll;
|
|
59
|
-
state.scrollPrevTime = state.scrollTime;
|
|
60
|
-
state.scroll = newScroll;
|
|
61
|
-
state.scrollTime = currentTime;
|
|
62
|
-
// Use velocity to predict scroll position
|
|
63
|
-
calculateItemsInView(ctx, state);
|
|
64
|
-
checkAtBottom(ctx, state);
|
|
65
|
-
checkAtTop(state);
|
|
66
|
-
}
|
package/src/prepareMVCP.ts
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { getId } from "./getId";
|
|
2
|
-
import { requestAdjust } from "./requestAdjust";
|
|
3
|
-
import { type StateContext, peek$ } from "./state";
|
|
4
|
-
import type { InternalState } from "./types";
|
|
5
|
-
|
|
6
|
-
export function prepareMVCP(ctx: StateContext, state: InternalState): () => void {
|
|
7
|
-
const {
|
|
8
|
-
positions,
|
|
9
|
-
scrollingTo,
|
|
10
|
-
props: { maintainVisibleContentPosition },
|
|
11
|
-
} = state;
|
|
12
|
-
|
|
13
|
-
let prevPosition: number;
|
|
14
|
-
let targetId: string | undefined;
|
|
15
|
-
let targetIndex: number | undefined;
|
|
16
|
-
const scrollTarget = scrollingTo?.index;
|
|
17
|
-
|
|
18
|
-
if (maintainVisibleContentPosition) {
|
|
19
|
-
const indexByKey = state.indexByKey;
|
|
20
|
-
|
|
21
|
-
if (scrollTarget !== undefined) {
|
|
22
|
-
// If we're currently scrolling to a target index, do MVCP for its position
|
|
23
|
-
targetId = getId(state, scrollTarget);
|
|
24
|
-
targetIndex = scrollTarget;
|
|
25
|
-
} else if (state.idsInView.length > 0 && peek$(ctx, "containersDidLayout")) {
|
|
26
|
-
// Do MVCP for the first item fully in view
|
|
27
|
-
targetId = state.idsInView.find((id) => indexByKey.get(id) !== undefined);
|
|
28
|
-
targetIndex = indexByKey.get(targetId!);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
if (targetId !== undefined && targetIndex !== undefined) {
|
|
32
|
-
prevPosition = positions.get(targetId)!;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// Return a function to do MVCP based on the prepared values
|
|
37
|
-
return () => {
|
|
38
|
-
if (targetId !== undefined && prevPosition !== undefined) {
|
|
39
|
-
const newPosition = positions.get(targetId);
|
|
40
|
-
|
|
41
|
-
if (newPosition !== undefined) {
|
|
42
|
-
const positionDiff = newPosition - prevPosition;
|
|
43
|
-
|
|
44
|
-
if (Math.abs(positionDiff) > 0.1) {
|
|
45
|
-
requestAdjust(ctx, state, positionDiff);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
}
|
package/src/reanimated.tsx
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { LegendList, type LegendListProps, type LegendListPropsBase, type LegendListRef } from "@legendapp/list";
|
|
2
|
-
import React, { type ComponentProps } from "react";
|
|
3
|
-
import Animated from "react-native-reanimated";
|
|
4
|
-
import { useCombinedRef } from "./useCombinedRef";
|
|
5
|
-
|
|
6
|
-
type KeysToOmit =
|
|
7
|
-
| "getEstimatedItemSize"
|
|
8
|
-
| "keyExtractor"
|
|
9
|
-
| "animatedProps"
|
|
10
|
-
| "renderItem"
|
|
11
|
-
| "onItemSizeChanged"
|
|
12
|
-
| "ItemSeparatorComponent";
|
|
13
|
-
|
|
14
|
-
type PropsBase<ItemT> = LegendListPropsBase<ItemT, ComponentProps<typeof Animated.ScrollView>>;
|
|
15
|
-
|
|
16
|
-
export interface AnimatedLegendListPropsBase<ItemT> extends Omit<PropsBase<ItemT>, KeysToOmit> {
|
|
17
|
-
refScrollView?: React.Ref<Animated.ScrollView>;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
type OtherAnimatedLegendListProps<ItemT> = Pick<PropsBase<ItemT>, KeysToOmit>;
|
|
21
|
-
|
|
22
|
-
// A component that receives a ref for the Animated.ScrollView and passes it to the LegendList
|
|
23
|
-
const LegendListForwardedRef = React.forwardRef(function LegendListForwardedRef<ItemT>(
|
|
24
|
-
props: LegendListProps<ItemT> & { refLegendList: (r: LegendListRef | null) => void },
|
|
25
|
-
ref: React.Ref<Animated.ScrollView>,
|
|
26
|
-
) {
|
|
27
|
-
const { refLegendList, ...rest } = props;
|
|
28
|
-
|
|
29
|
-
return (
|
|
30
|
-
<LegendList
|
|
31
|
-
refScrollView={ref}
|
|
32
|
-
ref={(r) => {
|
|
33
|
-
refLegendList(r);
|
|
34
|
-
}}
|
|
35
|
-
{...rest}
|
|
36
|
-
/>
|
|
37
|
-
);
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
const AnimatedLegendListComponent = Animated.createAnimatedComponent(LegendListForwardedRef);
|
|
41
|
-
|
|
42
|
-
type AnimatedLegendListProps<ItemT> = Omit<AnimatedLegendListPropsBase<ItemT>, "refLegendList" | "ref"> &
|
|
43
|
-
OtherAnimatedLegendListProps<ItemT>;
|
|
44
|
-
|
|
45
|
-
type AnimatedLegendListDefinition = <ItemT>(
|
|
46
|
-
props: AnimatedLegendListProps<ItemT> & { ref?: React.Ref<LegendListRef> },
|
|
47
|
-
) => React.ReactElement | null;
|
|
48
|
-
|
|
49
|
-
// A component that has the shape of LegendList which passes the ref down as refLegendList
|
|
50
|
-
const AnimatedLegendList = React.forwardRef(function AnimatedLegendList<ItemT>(
|
|
51
|
-
props: AnimatedLegendListProps<ItemT>,
|
|
52
|
-
ref: React.Ref<LegendListRef>,
|
|
53
|
-
) {
|
|
54
|
-
const { refScrollView, ...rest } = props as AnimatedLegendListPropsBase<ItemT>;
|
|
55
|
-
|
|
56
|
-
const refLegendList = React.useRef<LegendListRef | null>(null);
|
|
57
|
-
|
|
58
|
-
const combinedRef = useCombinedRef(refLegendList, ref);
|
|
59
|
-
|
|
60
|
-
return <AnimatedLegendListComponent refLegendList={combinedRef} ref={refScrollView} {...rest} />;
|
|
61
|
-
}) as AnimatedLegendListDefinition;
|
|
62
|
-
|
|
63
|
-
export { AnimatedLegendList, type AnimatedLegendListProps };
|
package/src/requestAdjust.ts
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { type StateContext, peek$ } from "./state";
|
|
2
|
-
import type { InternalState } from "./types";
|
|
3
|
-
|
|
4
|
-
export function requestAdjust(ctx: StateContext, state: InternalState, positionDiff: number) {
|
|
5
|
-
if (Math.abs(positionDiff) > 0.1) {
|
|
6
|
-
const doit = () => {
|
|
7
|
-
state.scrollAdjustHandler.requestAdjust(positionDiff);
|
|
8
|
-
};
|
|
9
|
-
state.scroll += positionDiff;
|
|
10
|
-
state.scrollForNextCalculateItemsInView = undefined;
|
|
11
|
-
|
|
12
|
-
const didLayout = peek$(ctx, "containersDidLayout");
|
|
13
|
-
|
|
14
|
-
if (didLayout) {
|
|
15
|
-
doit();
|
|
16
|
-
|
|
17
|
-
// Calculate a threshold to ignore scroll jumps for a short period of time
|
|
18
|
-
// This is to avoid the case where a scroll event comes in that was relevant from before
|
|
19
|
-
// the requestAdjust. So we ignore scroll events that are closer to the previous
|
|
20
|
-
// scroll position than the target position.
|
|
21
|
-
const threshold = state.scroll - positionDiff / 2;
|
|
22
|
-
if (!state.ignoreScrollFromMVCP) {
|
|
23
|
-
state.ignoreScrollFromMVCP = {};
|
|
24
|
-
}
|
|
25
|
-
if (positionDiff > 0) {
|
|
26
|
-
state.ignoreScrollFromMVCP.lt = threshold;
|
|
27
|
-
} else {
|
|
28
|
-
state.ignoreScrollFromMVCP.gt = threshold;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
if (state.ignoreScrollFromMVCPTimeout) {
|
|
32
|
-
clearTimeout(state.ignoreScrollFromMVCPTimeout);
|
|
33
|
-
}
|
|
34
|
-
state.ignoreScrollFromMVCPTimeout = setTimeout(() => {
|
|
35
|
-
state.ignoreScrollFromMVCP = undefined;
|
|
36
|
-
}, 100);
|
|
37
|
-
} else {
|
|
38
|
-
requestAnimationFrame(doit);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
package/src/scrollTo.ts
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { calculateOffsetWithOffsetPosition } from "./calculateOffsetWithOffsetPosition";
|
|
2
|
-
import { finishScrollTo } from "./finishScrollTo";
|
|
3
|
-
import type { InternalState } from "./types";
|
|
4
|
-
|
|
5
|
-
export function scrollTo(
|
|
6
|
-
state: InternalState,
|
|
7
|
-
params: {
|
|
8
|
-
animated?: boolean;
|
|
9
|
-
index?: number;
|
|
10
|
-
offset: number;
|
|
11
|
-
viewOffset?: number;
|
|
12
|
-
viewPosition?: number;
|
|
13
|
-
} = {} as any,
|
|
14
|
-
) {
|
|
15
|
-
const { animated } = params;
|
|
16
|
-
const {
|
|
17
|
-
refScroller,
|
|
18
|
-
props: { horizontal },
|
|
19
|
-
} = state;
|
|
20
|
-
|
|
21
|
-
const offset = calculateOffsetWithOffsetPosition(state, params.offset, params);
|
|
22
|
-
|
|
23
|
-
// Disable scroll adjust while scrolling so that it doesn't do extra work affecting the target offset
|
|
24
|
-
state.scrollHistory.length = 0;
|
|
25
|
-
state.scrollingTo = params;
|
|
26
|
-
state.scrollPending = offset;
|
|
27
|
-
// Do the scroll
|
|
28
|
-
refScroller.current?.scrollTo({
|
|
29
|
-
x: horizontal ? offset : 0,
|
|
30
|
-
y: horizontal ? 0 : offset,
|
|
31
|
-
animated: !!animated,
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
if (!animated) {
|
|
35
|
-
state.scroll = offset;
|
|
36
|
-
// TODO: Should this not be a timeout, and instead wait for all item layouts to settle?
|
|
37
|
-
// It's used for mvcp for when items change size above scroll.
|
|
38
|
-
setTimeout(() => finishScrollTo(state), 100);
|
|
39
|
-
}
|
|
40
|
-
}
|
package/src/scrollToIndex.ts
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { calculateOffsetForIndex } from "./calculateOffsetForIndex";
|
|
2
|
-
import { scrollTo } from "./scrollTo";
|
|
3
|
-
import type { StateContext } from "./state";
|
|
4
|
-
import type { InternalState, LegendListRef } from "./types";
|
|
5
|
-
|
|
6
|
-
export function scrollToIndex(
|
|
7
|
-
ctx: StateContext,
|
|
8
|
-
state: InternalState,
|
|
9
|
-
{ index, viewOffset = 0, animated = true, viewPosition }: Parameters<LegendListRef["scrollToIndex"]>[0],
|
|
10
|
-
) {
|
|
11
|
-
if (index >= state.props.data.length) {
|
|
12
|
-
index = state.props.data.length - 1;
|
|
13
|
-
} else if (index < 0) {
|
|
14
|
-
index = 0;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const firstIndexOffset = calculateOffsetForIndex(ctx, state, index);
|
|
18
|
-
|
|
19
|
-
const isLast = index === state.props.data.length - 1;
|
|
20
|
-
if (isLast && viewPosition === undefined) {
|
|
21
|
-
viewPosition = 1;
|
|
22
|
-
}
|
|
23
|
-
const firstIndexScrollPostion = firstIndexOffset - viewOffset;
|
|
24
|
-
|
|
25
|
-
state.scrollForNextCalculateItemsInView = undefined;
|
|
26
|
-
|
|
27
|
-
scrollTo(state, {
|
|
28
|
-
offset: firstIndexScrollPostion,
|
|
29
|
-
animated,
|
|
30
|
-
index,
|
|
31
|
-
viewPosition: viewPosition ?? 0,
|
|
32
|
-
viewOffset,
|
|
33
|
-
});
|
|
34
|
-
}
|
package/src/setDidLayout.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { checkAtBottom } from "./checkAtBottom";
|
|
2
|
-
import { IsNewArchitecture } from "./constants";
|
|
3
|
-
import { scrollToIndex } from "./scrollToIndex";
|
|
4
|
-
import { type StateContext, set$ } from "./state";
|
|
5
|
-
import type { InternalState } from "./types";
|
|
6
|
-
|
|
7
|
-
export function setDidLayout(ctx: StateContext, state: InternalState) {
|
|
8
|
-
const {
|
|
9
|
-
loadStartTime,
|
|
10
|
-
initialScroll,
|
|
11
|
-
props: { onLoad },
|
|
12
|
-
} = state;
|
|
13
|
-
state.queuedInitialLayout = true;
|
|
14
|
-
checkAtBottom(ctx, state);
|
|
15
|
-
|
|
16
|
-
if (!IsNewArchitecture && initialScroll) {
|
|
17
|
-
scrollToIndex(ctx, state, { ...initialScroll, animated: false });
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
set$(ctx, "containersDidLayout", true);
|
|
21
|
-
|
|
22
|
-
if (onLoad) {
|
|
23
|
-
onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
|
|
24
|
-
}
|
|
25
|
-
}
|
package/src/setPaddingTop.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { type StateContext, peek$, set$ } from "./state";
|
|
2
|
-
|
|
3
|
-
export function setPaddingTop(
|
|
4
|
-
ctx: StateContext,
|
|
5
|
-
{ stylePaddingTop, alignItemsPaddingTop }: { stylePaddingTop?: number; alignItemsPaddingTop?: number },
|
|
6
|
-
) {
|
|
7
|
-
if (stylePaddingTop !== undefined) {
|
|
8
|
-
const prevStylePaddingTop = peek$(ctx, "stylePaddingTop") || 0;
|
|
9
|
-
if (stylePaddingTop < prevStylePaddingTop) {
|
|
10
|
-
// If reducing top padding then we need to make sure the ScrollView doesn't
|
|
11
|
-
// scroll itself because the height reduced.
|
|
12
|
-
// First add the padding to the total size so that the total height in the ScrollView
|
|
13
|
-
// doesn't change
|
|
14
|
-
const prevTotalSize = peek$(ctx, "totalSize") || 0;
|
|
15
|
-
set$(ctx, "totalSize", prevTotalSize + prevStylePaddingTop);
|
|
16
|
-
setTimeout(() => {
|
|
17
|
-
// Then reset it back to how it was
|
|
18
|
-
set$(ctx, "totalSize", prevTotalSize);
|
|
19
|
-
}, 16);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// Now set the padding
|
|
23
|
-
set$(ctx, "stylePaddingTop", stylePaddingTop);
|
|
24
|
-
}
|
|
25
|
-
if (alignItemsPaddingTop !== undefined) {
|
|
26
|
-
set$(ctx, "alignItemsPaddingTop", alignItemsPaddingTop);
|
|
27
|
-
}
|
|
28
|
-
}
|
package/src/state.tsx
DELETED
|
@@ -1,304 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import type { View } from "react-native";
|
|
3
|
-
import { useSyncExternalStore } from "use-sync-external-store/shim";
|
|
4
|
-
import type {
|
|
5
|
-
ColumnWrapperStyle,
|
|
6
|
-
ViewAmountToken,
|
|
7
|
-
ViewToken,
|
|
8
|
-
ViewabilityAmountCallback,
|
|
9
|
-
ViewabilityCallback,
|
|
10
|
-
} from "./types";
|
|
11
|
-
|
|
12
|
-
// This is an implementation of a simple state management system, inspired by Legend State.
|
|
13
|
-
// It stores values and listeners in Maps, with peek$ and set$ functions to get and set values.
|
|
14
|
-
// The set$ function also triggers the listeners.
|
|
15
|
-
//
|
|
16
|
-
// This is definitely not general purpose and has one big optimization/caveat: use$ is only ever called
|
|
17
|
-
// once for each unique name. So we don't need to manage a Set of listeners or dispose them,
|
|
18
|
-
// which saves needing useEffect hooks or managing listeners in a Set.
|
|
19
|
-
|
|
20
|
-
export type ListenerType =
|
|
21
|
-
| "numContainers"
|
|
22
|
-
| "numContainersPooled"
|
|
23
|
-
| `containerItemKey${number}`
|
|
24
|
-
| `containerItemData${number}`
|
|
25
|
-
| `containerPosition${number}`
|
|
26
|
-
| `containerColumn${number}`
|
|
27
|
-
| "containersDidLayout"
|
|
28
|
-
| "extraData"
|
|
29
|
-
| "numColumns"
|
|
30
|
-
| "lastItemKeys"
|
|
31
|
-
| "totalSize"
|
|
32
|
-
| "alignItemsPaddingTop"
|
|
33
|
-
| "stylePaddingTop"
|
|
34
|
-
| "scrollAdjust"
|
|
35
|
-
| "scrollAdjustUserOffset"
|
|
36
|
-
| "headerSize"
|
|
37
|
-
| "footerSize"
|
|
38
|
-
| "maintainVisibleContentPosition"
|
|
39
|
-
| "debugRawScroll"
|
|
40
|
-
| "debugComputedScroll"
|
|
41
|
-
| "otherAxisSize"
|
|
42
|
-
| "scrollSize";
|
|
43
|
-
|
|
44
|
-
export type ListenerTypeValueMap = {
|
|
45
|
-
numContainers: number;
|
|
46
|
-
numContainersPooled: number;
|
|
47
|
-
containersDidLayout: boolean;
|
|
48
|
-
extraData: any;
|
|
49
|
-
numColumns: number;
|
|
50
|
-
lastItemKeys: string[];
|
|
51
|
-
totalSize: number;
|
|
52
|
-
alignItemsPaddingTop: number;
|
|
53
|
-
stylePaddingTop: number;
|
|
54
|
-
scrollAdjust: number;
|
|
55
|
-
scrollAdjustUserOffset: number;
|
|
56
|
-
headerSize: number;
|
|
57
|
-
footerSize: number;
|
|
58
|
-
maintainVisibleContentPosition: boolean;
|
|
59
|
-
debugRawScroll: number;
|
|
60
|
-
debugComputedScroll: number;
|
|
61
|
-
otherAxisSize: number;
|
|
62
|
-
scrollSize: { width: number; height: number };
|
|
63
|
-
} & {
|
|
64
|
-
[K in ListenerType as K extends `containerItemKey${number}` ? K : never]: string;
|
|
65
|
-
} & {
|
|
66
|
-
[K in ListenerType as K extends `containerItemData${number}` ? K : never]: any;
|
|
67
|
-
} & {
|
|
68
|
-
[K in ListenerType as K extends `containerPosition${number}` ? K : never]: number;
|
|
69
|
-
} & {
|
|
70
|
-
[K in ListenerType as K extends `containerColumn${number}` ? K : never]: number;
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
export interface StateContext {
|
|
74
|
-
listeners: Map<ListenerType, Set<(value: any) => void>>;
|
|
75
|
-
values: Map<ListenerType, any>;
|
|
76
|
-
mapViewabilityCallbacks: Map<string, ViewabilityCallback>;
|
|
77
|
-
mapViewabilityValues: Map<string, ViewToken>;
|
|
78
|
-
mapViewabilityAmountCallbacks: Map<number, ViewabilityAmountCallback>;
|
|
79
|
-
mapViewabilityAmountValues: Map<number, ViewAmountToken>;
|
|
80
|
-
columnWrapperStyle: ColumnWrapperStyle | undefined;
|
|
81
|
-
viewRefs: Map<number, React.RefObject<View>>;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const ContextState = React.createContext<StateContext | null>(null);
|
|
85
|
-
|
|
86
|
-
export function StateProvider({ children }: { children: React.ReactNode }) {
|
|
87
|
-
const [value] = React.useState<StateContext>(() => ({
|
|
88
|
-
listeners: new Map(),
|
|
89
|
-
values: new Map<ListenerType, any>([
|
|
90
|
-
["alignItemsPaddingTop", 0],
|
|
91
|
-
["stylePaddingTop", 0],
|
|
92
|
-
["headerSize", 0],
|
|
93
|
-
]),
|
|
94
|
-
mapViewabilityCallbacks: new Map<string, ViewabilityCallback>(),
|
|
95
|
-
mapViewabilityValues: new Map<string, ViewToken>(),
|
|
96
|
-
mapViewabilityAmountCallbacks: new Map<number, ViewabilityAmountCallback>(),
|
|
97
|
-
mapViewabilityAmountValues: new Map<number, ViewAmountToken>(),
|
|
98
|
-
columnWrapperStyle: undefined,
|
|
99
|
-
viewRefs: new Map<number, React.RefObject<View>>(),
|
|
100
|
-
}));
|
|
101
|
-
return <ContextState.Provider value={value}>{children}</ContextState.Provider>;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
export function useStateContext() {
|
|
105
|
-
return React.useContext(ContextState)!;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
function createSelectorFunctionsArr(ctx: StateContext, signalNames: ListenerType[]) {
|
|
109
|
-
let lastValues: any[] = [];
|
|
110
|
-
let lastSignalValues: any[] = [];
|
|
111
|
-
|
|
112
|
-
return {
|
|
113
|
-
subscribe: (cb: (value: any) => void) => {
|
|
114
|
-
const listeners: (() => void)[] = [];
|
|
115
|
-
for (const signalName of signalNames) {
|
|
116
|
-
listeners.push(listen$(ctx, signalName, cb));
|
|
117
|
-
}
|
|
118
|
-
return () => {
|
|
119
|
-
for (const listener of listeners) {
|
|
120
|
-
listener();
|
|
121
|
-
}
|
|
122
|
-
};
|
|
123
|
-
},
|
|
124
|
-
get: () => {
|
|
125
|
-
const currentValues: any[] = [];
|
|
126
|
-
let hasChanged = false;
|
|
127
|
-
|
|
128
|
-
for (let i = 0; i < signalNames.length; i++) {
|
|
129
|
-
const value = peek$(ctx, signalNames[i]);
|
|
130
|
-
currentValues.push(value);
|
|
131
|
-
|
|
132
|
-
// Check if this value has changed from last time
|
|
133
|
-
if (value !== lastSignalValues[i]) {
|
|
134
|
-
hasChanged = true;
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// Update our cached signal values regardless
|
|
139
|
-
lastSignalValues = currentValues;
|
|
140
|
-
|
|
141
|
-
// Only create a new array reference if something changed
|
|
142
|
-
if (hasChanged) {
|
|
143
|
-
lastValues = currentValues;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
return lastValues;
|
|
147
|
-
},
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
export function listen$<T extends ListenerType>(
|
|
152
|
-
ctx: StateContext,
|
|
153
|
-
signalName: T,
|
|
154
|
-
cb: (value: ListenerTypeValueMap[T]) => void,
|
|
155
|
-
): () => void {
|
|
156
|
-
const { listeners } = ctx;
|
|
157
|
-
let setListeners = listeners.get(signalName);
|
|
158
|
-
if (!setListeners) {
|
|
159
|
-
setListeners = new Set();
|
|
160
|
-
listeners.set(signalName, setListeners);
|
|
161
|
-
}
|
|
162
|
-
setListeners!.add(cb);
|
|
163
|
-
|
|
164
|
-
return () => setListeners!.delete(cb);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// Function to get value based on ListenerType without requiring generic type
|
|
168
|
-
export function peek$<T extends ListenerType>(ctx: StateContext, signalName: T): ListenerTypeValueMap[T] {
|
|
169
|
-
const { values } = ctx;
|
|
170
|
-
return values.get(signalName);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
export function set$<T extends ListenerType>(
|
|
174
|
-
ctx: StateContext,
|
|
175
|
-
signalName: T,
|
|
176
|
-
value: ListenerTypeValueMap[T] | undefined,
|
|
177
|
-
) {
|
|
178
|
-
const { listeners, values } = ctx;
|
|
179
|
-
if (values.get(signalName) !== value) {
|
|
180
|
-
values.set(signalName, value);
|
|
181
|
-
const setListeners = listeners.get(signalName);
|
|
182
|
-
if (setListeners) {
|
|
183
|
-
for (const listener of setListeners) {
|
|
184
|
-
listener(value);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
export function getContentSize(ctx: StateContext) {
|
|
191
|
-
const { values } = ctx;
|
|
192
|
-
const stylePaddingTop = values.get("stylePaddingTop") || 0;
|
|
193
|
-
const headerSize = values.get("headerSize") || 0;
|
|
194
|
-
const footerSize = values.get("footerSize") || 0;
|
|
195
|
-
const totalSize = values.get("totalSize") || 0;
|
|
196
|
-
return headerSize + footerSize + totalSize + stylePaddingTop;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
export function useArr$<T extends ListenerType>(signalNames: [T]): [ListenerTypeValueMap[T]];
|
|
200
|
-
export function useArr$<T1 extends ListenerType, T2 extends ListenerType>(
|
|
201
|
-
signalNames: [T1, T2],
|
|
202
|
-
): [ListenerTypeValueMap[T1], ListenerTypeValueMap[T2]];
|
|
203
|
-
export function useArr$<T1 extends ListenerType, T2 extends ListenerType, T3 extends ListenerType>(
|
|
204
|
-
signalNames: [T1, T2, T3],
|
|
205
|
-
): [ListenerTypeValueMap[T1], ListenerTypeValueMap[T2], ListenerTypeValueMap[T3]];
|
|
206
|
-
export function useArr$<
|
|
207
|
-
T1 extends ListenerType,
|
|
208
|
-
T2 extends ListenerType,
|
|
209
|
-
T3 extends ListenerType,
|
|
210
|
-
T4 extends ListenerType,
|
|
211
|
-
>(
|
|
212
|
-
signalNames: [T1, T2, T3, T4],
|
|
213
|
-
): [ListenerTypeValueMap[T1], ListenerTypeValueMap[T2], ListenerTypeValueMap[T3], ListenerTypeValueMap[T4]];
|
|
214
|
-
export function useArr$<
|
|
215
|
-
T1 extends ListenerType,
|
|
216
|
-
T2 extends ListenerType,
|
|
217
|
-
T3 extends ListenerType,
|
|
218
|
-
T4 extends ListenerType,
|
|
219
|
-
T5 extends ListenerType,
|
|
220
|
-
>(
|
|
221
|
-
signalNames: [T1, T2, T3, T4, T5],
|
|
222
|
-
): [
|
|
223
|
-
ListenerTypeValueMap[T1],
|
|
224
|
-
ListenerTypeValueMap[T2],
|
|
225
|
-
ListenerTypeValueMap[T3],
|
|
226
|
-
ListenerTypeValueMap[T4],
|
|
227
|
-
ListenerTypeValueMap[T5],
|
|
228
|
-
];
|
|
229
|
-
export function useArr$<
|
|
230
|
-
T1 extends ListenerType,
|
|
231
|
-
T2 extends ListenerType,
|
|
232
|
-
T3 extends ListenerType,
|
|
233
|
-
T4 extends ListenerType,
|
|
234
|
-
T5 extends ListenerType,
|
|
235
|
-
T6 extends ListenerType,
|
|
236
|
-
>(
|
|
237
|
-
signalNames: [T1, T2, T3, T4, T5, T6],
|
|
238
|
-
): [
|
|
239
|
-
ListenerTypeValueMap[T1],
|
|
240
|
-
ListenerTypeValueMap[T2],
|
|
241
|
-
ListenerTypeValueMap[T3],
|
|
242
|
-
ListenerTypeValueMap[T4],
|
|
243
|
-
ListenerTypeValueMap[T5],
|
|
244
|
-
ListenerTypeValueMap[T6],
|
|
245
|
-
];
|
|
246
|
-
export function useArr$<
|
|
247
|
-
T1 extends ListenerType,
|
|
248
|
-
T2 extends ListenerType,
|
|
249
|
-
T3 extends ListenerType,
|
|
250
|
-
T4 extends ListenerType,
|
|
251
|
-
T5 extends ListenerType,
|
|
252
|
-
T6 extends ListenerType,
|
|
253
|
-
T7 extends ListenerType,
|
|
254
|
-
>(
|
|
255
|
-
signalNames: [T1, T2, T3, T4, T5, T6, T7],
|
|
256
|
-
): [
|
|
257
|
-
ListenerTypeValueMap[T1],
|
|
258
|
-
ListenerTypeValueMap[T2],
|
|
259
|
-
ListenerTypeValueMap[T3],
|
|
260
|
-
ListenerTypeValueMap[T4],
|
|
261
|
-
ListenerTypeValueMap[T5],
|
|
262
|
-
ListenerTypeValueMap[T6],
|
|
263
|
-
ListenerTypeValueMap[T7],
|
|
264
|
-
];
|
|
265
|
-
export function useArr$<
|
|
266
|
-
T1 extends ListenerType,
|
|
267
|
-
T2 extends ListenerType,
|
|
268
|
-
T3 extends ListenerType,
|
|
269
|
-
T4 extends ListenerType,
|
|
270
|
-
T5 extends ListenerType,
|
|
271
|
-
T6 extends ListenerType,
|
|
272
|
-
T7 extends ListenerType,
|
|
273
|
-
T8 extends ListenerType,
|
|
274
|
-
>(
|
|
275
|
-
signalNames: [T1, T2, T3, T4, T5, T6, T7, T8],
|
|
276
|
-
): [
|
|
277
|
-
ListenerTypeValueMap[T1],
|
|
278
|
-
ListenerTypeValueMap[T2],
|
|
279
|
-
ListenerTypeValueMap[T3],
|
|
280
|
-
ListenerTypeValueMap[T4],
|
|
281
|
-
ListenerTypeValueMap[T5],
|
|
282
|
-
ListenerTypeValueMap[T6],
|
|
283
|
-
ListenerTypeValueMap[T7],
|
|
284
|
-
ListenerTypeValueMap[T8],
|
|
285
|
-
];
|
|
286
|
-
export function useArr$<T extends ListenerType>(signalNames: T[]): ListenerTypeValueMap[T][] {
|
|
287
|
-
const ctx = React.useContext(ContextState)!;
|
|
288
|
-
const { subscribe, get } = React.useMemo(() => createSelectorFunctionsArr(ctx, signalNames), [ctx, signalNames]);
|
|
289
|
-
const value = useSyncExternalStore(subscribe, get);
|
|
290
|
-
|
|
291
|
-
return value;
|
|
292
|
-
}
|
|
293
|
-
export function useSelector$<T extends ListenerType, T2>(
|
|
294
|
-
signalName: T,
|
|
295
|
-
selector: (value: ListenerTypeValueMap[T]) => T2,
|
|
296
|
-
): T2 {
|
|
297
|
-
const ctx = React.useContext(ContextState)!;
|
|
298
|
-
const { subscribe, get } = React.useMemo(() => createSelectorFunctionsArr(ctx, [signalName]), [ctx, signalName]);
|
|
299
|
-
|
|
300
|
-
// Return a selected value based on the signal name, so it only re-renders when the selected value changes
|
|
301
|
-
const value = useSyncExternalStore(subscribe, () => selector(get()[0]));
|
|
302
|
-
|
|
303
|
-
return value;
|
|
304
|
-
}
|