@momo-kits/carousel 0.165.2-beta.2 → 0.167.1-beta.1

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.
Files changed (40) hide show
  1. package/animation.ts +62 -0
  2. package/index.tsx +455 -390
  3. package/package.json +5 -6
  4. package/types.ts +48 -123
  5. package/core/LICENSE +0 -21
  6. package/core/README.md +0 -16
  7. package/core/components/Carousel.tsx +0 -28
  8. package/core/components/CarouselLayout.tsx +0 -231
  9. package/core/components/ItemLayout.tsx +0 -215
  10. package/core/components/ItemRenderer.tsx +0 -126
  11. package/core/components/LazyView.tsx +0 -14
  12. package/core/components/ScrollViewGesture.tsx +0 -443
  13. package/core/constants/index.ts +0 -11
  14. package/core/hooks/useAutoPlay.ts +0 -63
  15. package/core/hooks/useCarouselController.tsx +0 -295
  16. package/core/hooks/useCheckMounted.ts +0 -14
  17. package/core/hooks/useCommonVariables.ts +0 -261
  18. package/core/hooks/useInitProps.ts +0 -177
  19. package/core/hooks/useLayoutConfig.ts +0 -35
  20. package/core/hooks/useOffsetX.ts +0 -81
  21. package/core/hooks/useOnProgressChange.ts +0 -33
  22. package/core/hooks/usePanGestureProxy.ts +0 -144
  23. package/core/hooks/usePropsErrorBoundary.ts +0 -41
  24. package/core/hooks/useUpdateGestureConfig.ts +0 -17
  25. package/core/hooks/useVisibleRanges.tsx +0 -141
  26. package/core/layouts/index.tsx +0 -10
  27. package/core/layouts/normal.ts +0 -32
  28. package/core/layouts/parallax.ts +0 -50
  29. package/core/layouts/stack.ts +0 -266
  30. package/core/public-types.ts +0 -209
  31. package/core/store/index.tsx +0 -63
  32. package/core/types.ts +0 -32
  33. package/core/utils/carousel-direction.ts +0 -39
  34. package/core/utils/carousel-math.ts +0 -156
  35. package/core/utils/compute-gesture-translation.ts +0 -29
  36. package/core/utils/compute-offset-if-size-changed.ts +0 -14
  37. package/core/utils/computed-with-auto-fill-data.ts +0 -92
  38. package/core/utils/deal-with-animation.ts +0 -19
  39. package/core/utils/log.ts +0 -12
  40. package/core/utils/sanitize-animation-style.ts +0 -20
package/package.json CHANGED
@@ -1,19 +1,18 @@
1
1
  {
2
2
  "name": "@momo-kits/carousel",
3
- "version": "0.165.2-beta.2",
3
+ "version": "0.167.1-beta.1",
4
4
  "private": false,
5
5
  "main": "index.tsx",
6
6
  "peerDependencies": {
7
7
  "@momo-kits/foundation": "latest",
8
8
  "react": "*",
9
- "react-native": "*",
10
- "react-native-gesture-handler": "2.30.0",
11
- "react-native-reanimated": "4.1.3",
12
- "react-native-worklets": "0.6.1"
9
+ "react-native": "*"
13
10
  },
14
11
  "license": "MoMo",
15
12
  "publishConfig": {
16
13
  "registry": "https://registry.npmjs.org/"
17
14
  },
18
- "dependencies": {}
15
+ "dependencies": {
16
+ "moment": "^2.24.0"
17
+ }
19
18
  }
package/types.ts CHANGED
@@ -1,146 +1,71 @@
1
- import type { ReactNode } from 'react';
2
- import type {
1
+ import {
2
+ Animated,
3
3
  NativeScrollEvent,
4
4
  NativeSyntheticEvent,
5
5
  StyleProp,
6
6
  ViewStyle,
7
7
  } from 'react-native';
8
- import type { SharedValue } from 'react-native-reanimated';
9
8
 
10
- import type {
11
- CarouselItemAnimation,
12
- CarouselLayout,
13
- CarouselProps as CoreCarouselProps,
14
- CarouselRef as CoreCarouselRef,
15
- } from './core/public-types';
16
-
17
- export type {
18
- CarouselAnimation,
19
- CarouselItemAnimation,
20
- CarouselLayout,
21
- CarouselPanGesture,
22
- CarouselProgressChangeHandler,
23
- CarouselRenderItem,
24
- CarouselRenderItemInfo,
25
- CarouselScrollToOptions,
26
- CarouselStepOptions,
27
- } from './core/public-types';
28
-
29
- /**
30
- * Engine props minus the three the compatibility layer widens: `renderItem`
31
- * accepts a `ReactNode`, and `layout`/`itemAnimation` lose their compile-time
32
- * exclusivity (the engine still throws at runtime when both are passed).
33
- */
34
- type EngineProps<Item> = Omit<
35
- CoreCarouselProps<Item>,
36
- 'renderItem' | 'layout' | 'itemAnimation'
37
- >;
38
-
39
- /**
40
- * Props from the FlatList-based carousel. They keep working so call sites can
41
- * upgrade by bumping the version alone, but new code should prefer the engine
42
- * props they map onto.
43
- */
44
- type LegacyProps = {
45
- /** @deprecated Use `defaultIndex`. */
46
- firstItem?: number;
47
- /** @deprecated Use `itemSize`. */
48
- itemWidth?: number;
49
- /** @deprecated Use `itemSize` — this divides the container by `visibleItem`. */
50
- visibleItem?: number;
51
- /** @deprecated Item fills the container, which is the default. */
52
- full?: boolean;
53
- /**
54
- * @deprecated Use `snapMode` — `false` maps to `"none"`. Free scrolling
55
- * decelerates on the gesture handler's curve rather than the platform's.
56
- */
57
- enableSnap?: boolean;
58
- /** @deprecated Delay before autoplay starts. No engine equivalent. */
9
+ export type CarouselProps = {
10
+ activeSlideOffset?: number;
11
+ apparitionDelay?: number;
12
+ autoplay?: boolean;
59
13
  autoplayDelay?: number;
60
- /** @deprecated Use `layout` or `itemAnimation`. */
14
+ autoplayInterval?: number;
15
+ enableSnap?: boolean;
16
+ firstItem?: number;
61
17
  inactiveSlideOpacity?: number;
62
- /** @deprecated Use `layout` or `itemAnimation`. */
63
18
  inactiveSlideScale?: number;
64
- /** @deprecated Delay before the carousel becomes visible. */
65
- apparitionDelay?: number;
66
- /**
67
- * @deprecated Ignored — it was already unused by the FlatList implementation.
68
- * Set a gesture threshold with `onConfigurePanGesture` + `activeOffsetX`.
69
- */
70
- activeSlideOffset?: number;
71
- /** @deprecated Style each item inside `renderItem` instead. */
72
- slideStyle?: StyleProp<ViewStyle>;
73
- /** @deprecated Use `onProgressChange` or `progress`. */
74
- onScrollIndexChanged?: (index: number) => void;
75
- /**
76
- * @deprecated Use `onProgressChange`.
77
- *
78
- * Only `nativeEvent.contentOffset.x` is filled in, as it was by the FlatList
79
- * implementation. With `loop` the origin differs: the offset is now relative
80
- * to the first item and may go negative, where it used to count from the
81
- * leading clones.
82
- */
83
- onScroll?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
84
- /**
85
- * @deprecated Ignored. It used to carry a real momentum event from the
86
- * underlying ScrollView; there is no ScrollView and no momentum phase left to
87
- * report. Use `onSnapToItem` for the settled index.
88
- */
89
- onMomentumScrollEnd?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
90
- /**
91
- * @deprecated Use `onConfigurePanGesture` with `onBegin`.
92
- *
93
- * Called with no argument — the pan gesture has no `GestureResponderEvent`.
94
- */
95
- onTouchStart?: (event?: any) => void;
96
- /**
97
- * @deprecated Use `onConfigurePanGesture` with `onFinalize`.
98
- *
99
- * Called with no argument — the pan gesture has no `GestureResponderEvent`.
100
- */
101
- onTouchEnd?: (event?: any) => void;
102
-
103
- /** @deprecated Ignored. The engine loops by offset instead of cloning data. */
19
+ loop?: boolean;
104
20
  loopClonesPerSide?: number;
105
- /** @deprecated Ignored. Snapping is per item — use `snapMode`. */
106
- snapToInterval?: number;
107
- /** @deprecated Ignored. The engine does not use a native ScrollView. */
21
+ scrollEnabled?: boolean;
22
+ slideStyle?: StyleProp<ViewStyle>;
108
23
  disableIntervalMomentum?: boolean;
109
- /** @deprecated Ignored. The engine does not use a FlatList. */
24
+ itemWidth?: number;
25
+ data: any[];
26
+ renderItem: (info: { item: any; index: number }) => React.ReactNode;
27
+ onScroll?: any;
28
+ onScrollIndexChanged?: (index: number) => void;
29
+ onSnapToItem?: (index: number) => void;
30
+ onTouchStart?: (event: any) => void;
31
+ onTouchEnd?: (event: any) => void;
32
+ onMomentumScrollEnd?: (
33
+ event: NativeSyntheticEvent<NativeScrollEvent>
34
+ ) => void;
35
+ onLayout?: (event: any) => void;
36
+ keyExtractor?: (item: any, index: number) => string;
110
37
  getItemLayout?: (
111
38
  data: any,
112
39
  index: number
113
40
  ) => { length: number; offset: number; index: number };
41
+ style?: ViewStyle;
42
+ visibleItem?: number;
43
+ contentContainerStyle?: StyleProp<ViewStyle>;
44
+ full?: boolean;
45
+ snapToInterval?: number | Animated.Value | Animated.AnimatedInterpolation<number | string> | undefined
114
46
  };
115
47
 
116
- export type CarouselRenderItemInfoCompat<Item> = {
117
- item: Item;
118
- index: number;
119
- relativeProgress: SharedValue<number>;
120
- };
121
-
122
- /**
123
- * `Item` defaults to `any` so `CarouselProps` stays usable without a type
124
- * argument, the way the FlatList-based props type was.
125
- */
126
- export type CarouselProps<Item = any> = EngineProps<Item> &
127
- LegacyProps & {
128
- renderItem: (info: CarouselRenderItemInfoCompat<Item>) => ReactNode;
129
- layout?: CarouselLayout;
130
- itemAnimation?: CarouselItemAnimation;
131
- };
132
-
133
- export type CarouselRef = CoreCarouselRef & {
134
- /** @deprecated Use `scrollTo({ index, animated })`. */
135
- snapToItem: (index: number, animated?: boolean, fireCallback?: boolean) => void;
136
- /** @deprecated Use `next({ animated })`. */
48
+ export type CarouselRef = {
49
+ snapToItem: (
50
+ index: number,
51
+ animated?: boolean,
52
+ fireCallback?: boolean
53
+ ) => void;
137
54
  snapToNext: (animated?: boolean, fireCallback?: boolean) => void;
138
- /** @deprecated Use `prev({ animated })`. */
139
55
  snapToPrev: (animated?: boolean, fireCallback?: boolean) => void;
140
- /** @deprecated Toggle the `autoplay` prop instead. */
141
56
  startAutoplay: () => void;
142
- /** @deprecated Toggle the `autoplay` prop instead. */
143
57
  pauseAutoplay: () => void;
144
- /** @deprecated Toggle the `autoplay` prop instead. */
145
58
  stopAutoplay: () => void;
146
59
  };
60
+
61
+ export type CarouselState = {
62
+ hideCarousel: boolean;
63
+ interpolators: any;
64
+ containerWidth: number;
65
+ itemWidth: number;
66
+ };
67
+
68
+ export type Position = {
69
+ start: any;
70
+ end: any;
71
+ };
package/core/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2020 Doho
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
package/core/README.md DELETED
@@ -1,16 +0,0 @@
1
- # Vendored carousel engine
2
-
3
- Source: [react-native-reanimated-carousel](https://github.com/dohooo/react-native-reanimated-carousel) v5.1.1, MIT (see `LICENSE`).
4
-
5
- Copied from the upstream `src/` directory, minus two things we do not ship:
6
-
7
- - `index.tsx` — the package root is `../index.tsx` instead.
8
- - `components/Pagination/` — MoMo screens use `Pagination` from
9
- `@momo-kits/foundation`.
10
-
11
- Do not edit these files for MoMo-specific behaviour. `../index.tsx` decides what
12
- the package exposes.
13
-
14
- To update: re-copy upstream `src/` over `core/`, drop the two paths above again,
15
- keep `LICENSE` and this file, then re-check `../index.tsx` and `../types.ts`
16
- against the upstream public types.
@@ -1,28 +0,0 @@
1
- import React from "react";
2
- import { useCommonVariables } from "../hooks/useCommonVariables";
3
- import { useInitProps } from "../hooks/useInitProps";
4
- import { usePropsErrorBoundary } from "../hooks/usePropsErrorBoundary";
5
- import { GlobalStateProvider } from "../store";
6
- import type { CarouselProps, CarouselRef } from "../types";
7
- import { CarouselLayout } from "./CarouselLayout";
8
-
9
- const CarouselImpl = React.forwardRef<CarouselRef, CarouselProps<unknown>>((_props, ref) => {
10
- const props = useInitProps(_props);
11
- const { dataLength } = props;
12
- const commonVariables = useCommonVariables(props);
13
- usePropsErrorBoundary({ ...props, dataLength });
14
-
15
- return (
16
- <GlobalStateProvider value={{ props, common: commonVariables }}>
17
- <CarouselLayout ref={ref} />
18
- </GlobalStateProvider>
19
- );
20
- });
21
-
22
- type CarouselComponent = <T>(
23
- props: CarouselProps<T> & {
24
- ref?: React.Ref<CarouselRef>;
25
- }
26
- ) => React.ReactElement;
27
-
28
- export const Carousel = CarouselImpl as CarouselComponent;
@@ -1,231 +0,0 @@
1
- import React from "react";
2
- import { type StyleProp, StyleSheet, View, type ViewStyle } from "react-native";
3
- import { useAnimatedReaction, useAnimatedStyle, useDerivedValue } from "react-native-reanimated";
4
- import { scheduleOnRN } from "react-native-worklets";
5
- import { useAutoPlay } from "../hooks/useAutoPlay";
6
- import { useCarouselController } from "../hooks/useCarouselController";
7
- import { useLayoutConfig } from "../hooks/useLayoutConfig";
8
- import { useOnProgressChange } from "../hooks/useOnProgressChange";
9
- import { useGlobalState } from "../store";
10
- import type { CarouselRef } from "../types";
11
- import { ItemRenderer } from "./ItemRenderer";
12
- import { ScrollViewGesture } from "./ScrollViewGesture";
13
-
14
- export function resolveCarouselLayoutStyle(params: {
15
- flattenedStyle: Partial<ViewStyle>;
16
- isVertical: boolean;
17
- measuredSize: number;
18
- sizeExplicit: boolean;
19
- }) {
20
- "worklet";
21
-
22
- const { flattenedStyle, isVertical, measuredSize, sizeExplicit } = params;
23
- const { width, height } = flattenedStyle;
24
- const resolvedMainAxisSize = measuredSize || "100%";
25
-
26
- return {
27
- width: width ?? (isVertical ? "100%" : sizeExplicit ? resolvedMainAxisSize : "100%"),
28
- height: height ?? (isVertical ? (sizeExplicit ? resolvedMainAxisSize : "100%") : "100%"),
29
- };
30
- }
31
-
32
- export const CarouselLayout = React.forwardRef<CarouselRef>((_props, ref) => {
33
- const { props, common } = useGlobalState();
34
-
35
- const {
36
- testID,
37
- loop,
38
- autoFillData,
39
- // Fill data with autoFillData
40
- data,
41
- rawData,
42
- // Length of fill data
43
- dataLength,
44
- // Length of raw data
45
- rawDataLength,
46
- layout,
47
- style,
48
- contentContainerStyle,
49
- orientation,
50
- autoplay,
51
- renderWindowSize,
52
- autoplayDirection,
53
- autoplayInterval,
54
- animation,
55
- renderItem,
56
- onSnapToItem,
57
- onScrollStart,
58
- onProgressChange,
59
- progress,
60
- itemAnimation,
61
- defaultIndex,
62
- keyExtractor,
63
- } = props;
64
- const isVertical = orientation === "vertical";
65
-
66
- const { size, handlerOffset, resolvedSize, sizePhase, sizeExplicit } = common;
67
- const layoutConfig = useLayoutConfig({ ...props, size });
68
-
69
- const isSizeReady = useDerivedValue(() => {
70
- const currentSize = resolvedSize.value ?? 0;
71
- return sizePhase.value === "ready" && currentSize > 0;
72
- }, [resolvedSize, sizePhase]);
73
-
74
- const offsetX = useDerivedValue(() => {
75
- const currentSize = resolvedSize.value ?? 0;
76
- if (currentSize <= 0) return 0;
77
-
78
- const totalSize = currentSize * dataLength;
79
- const value = handlerOffset.value;
80
- if (!loop || totalSize === 0) {
81
- return value;
82
- }
83
-
84
- const x = value % totalSize;
85
- return Number.isNaN(x) ? 0 : x;
86
- }, [loop, dataLength, handlerOffset, resolvedSize]);
87
-
88
- useOnProgressChange({
89
- loop,
90
- offset: handlerOffset,
91
- progress,
92
- size,
93
- sizeReady: isSizeReady,
94
- rawDataLength,
95
- onProgressChange,
96
- });
97
-
98
- const _onScrollEnd = React.useCallback(
99
- (realIndex: number) => {
100
- if (onSnapToItem) onSnapToItem(realIndex);
101
- },
102
- [onSnapToItem]
103
- );
104
-
105
- const carouselController = useCarouselController({
106
- ref,
107
- loop,
108
- size,
109
- dataLength,
110
- rawDataLength,
111
- handlerOffset,
112
- animation,
113
- defaultIndex,
114
- onMovementEnd: _onScrollEnd,
115
- onScrollStart,
116
- });
117
-
118
- const {
119
- start: startAutoPlay,
120
- pause: pauseAutoPlay,
121
- trigger: triggerAutoPlay,
122
- } = useAutoPlay({
123
- autoplay,
124
- autoplayDirection,
125
- autoplayInterval,
126
- carouselController,
127
- });
128
-
129
- useAnimatedReaction(
130
- () => ({ ready: isSizeReady.value }),
131
- (state, previous) => {
132
- if (!autoplay) return;
133
- if (state.ready === previous?.ready) return;
134
-
135
- if (state.ready) scheduleOnRN(triggerAutoPlay);
136
- else scheduleOnRN(pauseAutoPlay);
137
- },
138
- [autoplay]
139
- );
140
-
141
- const scrollViewGestureOnScrollStart = React.useCallback(() => {
142
- carouselController.startMovement();
143
- pauseAutoPlay();
144
- onScrollStart?.();
145
- }, [carouselController, onScrollStart, pauseAutoPlay]);
146
-
147
- const scrollViewGestureOnScrollEnd = React.useCallback(() => {
148
- const settledIndex = carouselController.settle();
149
- startAutoPlay();
150
- _onScrollEnd(settledIndex);
151
- }, [_onScrollEnd, carouselController, startAutoPlay]);
152
-
153
- const scrollViewGestureOnTouchBegin = React.useCallback(pauseAutoPlay, [pauseAutoPlay]);
154
-
155
- const scrollViewGestureOnTouchEnd = React.useCallback(startAutoPlay, [startAutoPlay]);
156
-
157
- const { opacity, transform, ...restContentContainerStyle } =
158
- StyleSheet.flatten(contentContainerStyle as StyleProp<ViewStyle>) || {};
159
- const flattenedStyle = StyleSheet.flatten(style) || {};
160
-
161
- const layoutStyle = useAnimatedStyle(() => {
162
- const measuredSize = resolvedSize.value ?? 0;
163
- const { width, height } = resolveCarouselLayoutStyle({
164
- flattenedStyle,
165
- isVertical,
166
- measuredSize,
167
- sizeExplicit,
168
- });
169
-
170
- return {
171
- width,
172
- height,
173
- opacity: isSizeReady.value ? 1 : 0,
174
- };
175
- }, [flattenedStyle, isSizeReady, isVertical, resolvedSize, sizePhase, sizeExplicit]);
176
-
177
- return (
178
- <View testID={testID} style={[styles.layoutContainer, style]} onLayout={props.onLayout}>
179
- <ScrollViewGesture
180
- size={size}
181
- key={layout?.type}
182
- translation={handlerOffset}
183
- style={[
184
- styles.contentContainer,
185
- layoutStyle,
186
- restContentContainerStyle,
187
- isVertical ? styles.itemsVertical : styles.itemsHorizontal,
188
- ]}
189
- testID="carousel-content-container"
190
- onScrollStart={scrollViewGestureOnScrollStart}
191
- onScrollEnd={scrollViewGestureOnScrollEnd}
192
- onTouchBegin={scrollViewGestureOnTouchBegin}
193
- onTouchEnd={scrollViewGestureOnTouchEnd}
194
- >
195
- <ItemRenderer
196
- data={data}
197
- rawData={rawData}
198
- dataLength={dataLength}
199
- rawDataLength={rawDataLength}
200
- loop={loop}
201
- size={size}
202
- renderWindowSize={renderWindowSize}
203
- defaultIndex={defaultIndex}
204
- autoFillData={autoFillData}
205
- offsetX={offsetX}
206
- handlerOffset={handlerOffset}
207
- layoutConfig={layoutConfig}
208
- renderItem={renderItem}
209
- itemAnimation={itemAnimation}
210
- keyExtractor={keyExtractor}
211
- />
212
- </ScrollViewGesture>
213
- </View>
214
- );
215
- });
216
-
217
- const styles = StyleSheet.create({
218
- layoutContainer: {
219
- display: "flex",
220
- overflow: "hidden",
221
- },
222
- contentContainer: {
223
- overflow: "hidden",
224
- },
225
- itemsHorizontal: {
226
- flexDirection: "row",
227
- },
228
- itemsVertical: {
229
- flexDirection: "column",
230
- },
231
- });