@lookiero/checkout 3.9.0 → 3.10.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/dist/infrastructure/ui/components/layouts/layout/dummyLayout/DummyLayout.js +7 -5
- package/dist/infrastructure/ui/components/layouts/tabs/Tabs.d.ts +6 -4
- package/dist/infrastructure/ui/components/layouts/tabs/Tabs.js +9 -11
- package/dist/infrastructure/ui/components/layouts/tabs/Tabs.style.d.ts +1 -0
- package/dist/infrastructure/ui/components/layouts/tabs/Tabs.style.js +1 -0
- package/dist/infrastructure/ui/components/templates/header/Header.style.d.ts +1 -0
- package/dist/infrastructure/ui/components/templates/header/Header.style.js +3 -1
- package/dist/infrastructure/ui/hooks/useSubmitCheckout.d.ts +1 -1
- package/dist/infrastructure/ui/views/item/components/itemActions/ItemActions.style.js +3 -3
- package/dist/infrastructure/ui/views/item/components/productVariantDescription/ProductVariantDescription.style.d.ts +2 -1
- package/dist/infrastructure/ui/views/item/components/productVariantDescription/ProductVariantDescription.style.js +4 -3
- package/dist/infrastructure/ui/views/item/components/productVariantSlider/ProductVariantSlider.js +16 -15
- package/dist/infrastructure/ui/views/item/components/productVariantSlider/ProductVariantSlider.style.d.ts +3 -0
- package/dist/infrastructure/ui/views/item/components/productVariantSlider/ProductVariantSlider.style.js +4 -1
- package/dist/infrastructure/ui/views/item/views/productVariant/ProductVariant.js +5 -5
- package/dist/infrastructure/ui/views/item/views/productVariant/ProductVariant.style.d.ts +0 -4
- package/dist/infrastructure/ui/views/item/views/productVariant/ProductVariant.style.js +0 -4
- package/dist/infrastructure/ui/views/summaryTabs/components/checkoutItemsTabs/CheckoutItemsTabs.js +6 -6
- package/dist/shared/ui/components/layouts/carousel/Bullets.d.ts +10 -0
- package/dist/shared/ui/components/layouts/carousel/Bullets.js +28 -0
- package/dist/shared/ui/components/layouts/carousel/Bullets.style.d.ts +12 -0
- package/dist/shared/ui/components/layouts/carousel/Bullets.style.js +15 -0
- package/dist/shared/ui/components/layouts/carousel/Carousel.d.ts +32 -0
- package/dist/shared/ui/components/layouts/carousel/Carousel.js +87 -0
- package/dist/shared/ui/components/layouts/carousel/Carousel.style.d.ts +24 -0
- package/dist/shared/ui/components/layouts/carousel/Carousel.style.js +25 -0
- package/dist/shared/ui/components/layouts/sticky/Sticky.js +1 -3
- package/dist/shared/ui/components/layouts/sticky/Sticky.style.d.ts +3 -0
- package/dist/shared/ui/components/layouts/sticky/Sticky.style.js +3 -2
- package/package.json +6 -2
- package/dist/shared/ui/components/layouts/slider/Pagination.d.ts +0 -14
- package/dist/shared/ui/components/layouts/slider/Pagination.js +0 -11
- package/dist/shared/ui/components/layouts/slider/Pagination.style.d.ts +0 -23
- package/dist/shared/ui/components/layouts/slider/Pagination.style.js +0 -27
- package/dist/shared/ui/components/layouts/slider/Slider.d.ts +0 -20
- package/dist/shared/ui/components/layouts/slider/Slider.js +0 -132
- package/dist/shared/ui/components/layouts/slider/Slider.style.d.ts +0 -11
- package/dist/shared/ui/components/layouts/slider/Slider.style.js +0 -12
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/* eslint-disable react/prop-types */
|
|
2
2
|
import React from "react";
|
|
3
|
-
import {
|
|
3
|
+
import { View } from "react-native";
|
|
4
|
+
import { GestureHandlerRootView, ScrollView as RNGHScrollView } from "react-native-gesture-handler";
|
|
4
5
|
import { SafeAreaView } from "react-native-safe-area-context";
|
|
5
6
|
import { Footer as DefaultFooter } from "../../../templates/footer/Footer";
|
|
6
7
|
import { DefaultHeader } from "../../../templates/header/defaultHeader/DefaultHeader";
|
|
@@ -8,9 +9,10 @@ import { Footer } from "../components/footer/Footer";
|
|
|
8
9
|
import { Header } from "../components/header/Header";
|
|
9
10
|
import { style } from "./DummyLayout.style";
|
|
10
11
|
const DummyLayout = ({ children, header = React.createElement(DefaultHeader, null), footer = React.createElement(DefaultFooter, null), panel, style: customStyle, scrollEnabled, onLayout, }) => (React.createElement(SafeAreaView, { style: [style.safeAreaView, customStyle?.safeAreaView] },
|
|
11
|
-
React.createElement(
|
|
12
|
-
React.createElement(
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
React.createElement(GestureHandlerRootView, { style: { flex: 1 } },
|
|
13
|
+
React.createElement(RNGHScrollView, { contentContainerStyle: [style.scrollView, customStyle?.scrollView], scrollEnabled: scrollEnabled, scrollEventThrottle: 16, showsVerticalScrollIndicator: false, stickyHeaderIndices: [0] },
|
|
14
|
+
React.createElement(Header, null, header),
|
|
15
|
+
panel,
|
|
16
|
+
React.createElement(View, { style: style.children, onLayout: onLayout }, children))),
|
|
15
17
|
React.createElement(Footer, null, footer)));
|
|
16
18
|
export { DummyLayout };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
2
|
import { StyleProp, TextStyle, ViewStyle } from "react-native";
|
|
3
|
+
import { RenderItemFunction } from "../../../../../shared/ui/components/layouts/carousel/Carousel";
|
|
3
4
|
interface TabStyle {
|
|
4
5
|
readonly tab: StyleProp<ViewStyle>;
|
|
5
6
|
readonly tabText: StyleProp<TextStyle>;
|
|
@@ -14,13 +15,14 @@ interface TabsStyle {
|
|
|
14
15
|
readonly sliderContainer: StyleProp<ViewStyle>;
|
|
15
16
|
readonly tabList: Partial<TabListStyle>;
|
|
16
17
|
}
|
|
17
|
-
interface TabsProps {
|
|
18
|
-
readonly
|
|
18
|
+
interface TabsProps<T> {
|
|
19
|
+
readonly data: T[];
|
|
20
|
+
readonly children: RenderItemFunction<T>;
|
|
19
21
|
readonly defaultIndex?: number;
|
|
20
22
|
readonly tabLabels: string[];
|
|
21
23
|
readonly style?: Partial<TabsStyle>;
|
|
22
24
|
readonly onChanged?: (index: number) => void;
|
|
23
25
|
readonly tabLabelsWrapper?: (children: ReactNode) => ReactNode;
|
|
24
26
|
}
|
|
25
|
-
declare const Tabs:
|
|
27
|
+
declare const Tabs: <T>({ data, children, defaultIndex, tabLabels, style: customStyle, onChanged, tabLabelsWrapper, }: TabsProps<T>) => JSX.Element;
|
|
26
28
|
export { Tabs };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { COLOR, Text } from "@lookiero/aurora";
|
|
2
2
|
import { animated, useSpring } from "@react-spring/native";
|
|
3
|
-
import React, {
|
|
3
|
+
import React, { useCallback, useEffect, useState } from "react";
|
|
4
4
|
import { Pressable, View } from "react-native";
|
|
5
5
|
import invariant from "tiny-invariant";
|
|
6
|
-
import {
|
|
6
|
+
import { Carousel } from "../../../../../shared/ui/components/layouts/carousel/Carousel";
|
|
7
7
|
import { style } from "./Tabs.style";
|
|
8
8
|
const Tab = ({ children, active, disabled = false, style: customStyle, onPress, onLayout }) => (React.createElement(Pressable, { disabled: disabled, style: [style.tab, customStyle?.tab], testID: "tab", onLayout: onLayout, onPress: onPress },
|
|
9
9
|
React.createElement(Text, { color: active ? COLOR.CONTENT : COLOR.GRAYSCALE_L, level: 2, style: customStyle?.tabText, detail: true }, children)));
|
|
@@ -18,8 +18,8 @@ const TabList = ({ labels = [], tabIndex = 0, style: customStyle, onSelect }) =>
|
|
|
18
18
|
...prevState.slice(index),
|
|
19
19
|
]), []);
|
|
20
20
|
const springs = useSpring({
|
|
21
|
-
width: tabItemPositions[tabIndex]?.width,
|
|
22
|
-
left: tabItemPositions[tabIndex]?.position,
|
|
21
|
+
width: tabItemPositions[tabIndex]?.width || 0,
|
|
22
|
+
left: tabItemPositions[tabIndex]?.position || 0,
|
|
23
23
|
});
|
|
24
24
|
return (React.createElement(View, { style: [style.tabs, customStyle?.tabList], testID: "tab-list" },
|
|
25
25
|
labels.map((item, index) => (React.createElement(Tab, { key: index, active: tabIndex === index, style: customStyle?.tab, onLayout: (event) => handleOnLayout(event, index), onPress: () => onSelect?.(index) }, item))),
|
|
@@ -27,21 +27,19 @@ const TabList = ({ labels = [], tabIndex = 0, style: customStyle, onSelect }) =>
|
|
|
27
27
|
style.indicator,
|
|
28
28
|
{
|
|
29
29
|
width: springs.width,
|
|
30
|
-
|
|
30
|
+
transform: [{ translateX: springs.left }],
|
|
31
31
|
},
|
|
32
32
|
customStyle?.indicator,
|
|
33
33
|
] })));
|
|
34
34
|
};
|
|
35
|
-
const Tabs = ({ children, defaultIndex = 0, tabLabels, style: customStyle, onChanged, tabLabelsWrapper = (children) => children, }) => {
|
|
36
|
-
invariant(
|
|
35
|
+
const Tabs = ({ data, children, defaultIndex = 0, tabLabels, style: customStyle, onChanged, tabLabelsWrapper = (children) => children, }) => {
|
|
36
|
+
invariant(data.length === tabLabels.length, "data and tab labels must be the same length");
|
|
37
37
|
const [active, setActive] = useState(defaultIndex);
|
|
38
38
|
const handleOnActiveChanged = useCallback((activeIndex) => setActive(activeIndex), []);
|
|
39
|
-
useEffect(() =>
|
|
40
|
-
onChanged?.(active);
|
|
41
|
-
}, [active, onChanged]);
|
|
39
|
+
useEffect(() => onChanged?.(active), [active, onChanged]);
|
|
42
40
|
return (React.createElement(View, { style: [style.container, customStyle?.tabContainer], testID: "tabs" },
|
|
43
41
|
tabLabelsWrapper(React.createElement(TabList, { labels: tabLabels, style: customStyle?.tabList, tabIndex: active, onSelect: handleOnActiveChanged })),
|
|
44
42
|
React.createElement(View, { style: customStyle?.sliderContainer },
|
|
45
|
-
React.createElement(
|
|
43
|
+
React.createElement(Carousel, { activeIndex: active, data: data, enabled: false, onActiveIndexChanged: handleOnActiveChanged }, children))));
|
|
46
44
|
};
|
|
47
45
|
export { Tabs };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { StyleSheet } from "react-native";
|
|
2
2
|
import { theme } from "../../../theme/theme";
|
|
3
|
-
const { colorBase, spaceS } = theme();
|
|
3
|
+
const { colorBase, spaceS, spaceXXXL } = theme();
|
|
4
|
+
const HEADER_HEIGHT = spaceXXXL;
|
|
4
5
|
const style = StyleSheet.create({
|
|
5
6
|
header: {
|
|
6
7
|
alignItems: "center",
|
|
@@ -8,6 +9,7 @@ const style = StyleSheet.create({
|
|
|
8
9
|
flexDirection: "row",
|
|
9
10
|
flexGrow: 0,
|
|
10
11
|
flexWrap: "nowrap",
|
|
12
|
+
height: HEADER_HEIGHT,
|
|
11
13
|
justifyContent: "space-between",
|
|
12
14
|
overflow: "visible",
|
|
13
15
|
paddingHorizontal: spaceS,
|
|
@@ -23,5 +23,5 @@ interface UseSubmitCheckoutFunction {
|
|
|
23
23
|
(args: UseSubmitCheckoutFunctionArgs): UseSubmitCheckoutResult;
|
|
24
24
|
}
|
|
25
25
|
declare const useSubmitCheckout: UseSubmitCheckoutFunction;
|
|
26
|
-
export type { Status };
|
|
26
|
+
export type { Status, SubmitCheckoutFunction };
|
|
27
27
|
export { useSubmitCheckout };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { StyleSheet } from "react-native";
|
|
2
2
|
import { theme } from "../../../../theme/theme";
|
|
3
|
-
const { colorGrayscaleL,
|
|
3
|
+
const { colorGrayscaleL, spaceM, spaceXL } = theme();
|
|
4
4
|
const style = StyleSheet.create({
|
|
5
5
|
buttonText: {
|
|
6
6
|
width: "100%",
|
|
@@ -17,11 +17,11 @@ const style = StyleSheet.create({
|
|
|
17
17
|
row: {
|
|
18
18
|
alignItems: "center",
|
|
19
19
|
flexDirection: "row",
|
|
20
|
-
marginTop:
|
|
20
|
+
marginTop: spaceM,
|
|
21
21
|
},
|
|
22
22
|
sizeSelector: {
|
|
23
23
|
flex: 1,
|
|
24
|
-
marginRight:
|
|
24
|
+
marginRight: spaceM,
|
|
25
25
|
},
|
|
26
26
|
});
|
|
27
27
|
export { style };
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { StyleSheet } from "react-native";
|
|
2
2
|
import { theme } from "../../../../theme/theme";
|
|
3
|
-
const {
|
|
3
|
+
const { spaceXS, spaceL } = theme();
|
|
4
4
|
const style = StyleSheet.create({
|
|
5
5
|
container: {
|
|
6
6
|
width: "100%",
|
|
7
7
|
},
|
|
8
8
|
name: {
|
|
9
|
-
marginVertical:
|
|
9
|
+
marginVertical: spaceXS,
|
|
10
10
|
},
|
|
11
11
|
size: {
|
|
12
|
-
|
|
12
|
+
marginBottom: spaceXS,
|
|
13
|
+
marginTop: spaceL,
|
|
13
14
|
},
|
|
14
15
|
});
|
|
15
16
|
export { style };
|
package/dist/infrastructure/ui/views/item/components/productVariantSlider/ProductVariantSlider.js
CHANGED
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
import React, { useCallback, useState } from "react";
|
|
2
|
-
import { Image } from "react-native";
|
|
3
|
-
import {
|
|
2
|
+
import { Image, View } from "react-native";
|
|
3
|
+
import { AspectRatioView } from "../../../../../../shared/ui/components/atoms/aspectRatioView/AspectRatioView";
|
|
4
|
+
import { Bullets } from "../../../../../../shared/ui/components/layouts/carousel/Bullets";
|
|
5
|
+
import { Carousel, } from "../../../../../../shared/ui/components/layouts/carousel/Carousel";
|
|
4
6
|
import { useMediaImage } from "../../../../hooks/useMediaImage";
|
|
5
7
|
import { style } from "./ProductVariantSlider.style";
|
|
6
8
|
const ProductVariantSlider = ({ producVariantMedia, onChanged }) => {
|
|
7
9
|
const cdnImageUrl = useMediaImage();
|
|
8
|
-
const [
|
|
10
|
+
const [activeIndex, setActiveIndex] = useState(0);
|
|
9
11
|
const handleOnActiveChanged = useCallback((activeIndex) => {
|
|
10
|
-
|
|
12
|
+
setActiveIndex(activeIndex);
|
|
11
13
|
onChanged?.(activeIndex);
|
|
12
14
|
}, [onChanged]);
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
} })))));
|
|
15
|
+
const renderItem = useCallback(({ item }) => (React.createElement(View, { style: style.slide },
|
|
16
|
+
React.createElement(AspectRatioView, { aspectRatio: 4 / 3 },
|
|
17
|
+
React.createElement(Image, { resizeMode: "contain", style: style.image, testID: "product-variant-image", source: {
|
|
18
|
+
uri: cdnImageUrl({
|
|
19
|
+
url: item.url,
|
|
20
|
+
width: 600,
|
|
21
|
+
}),
|
|
22
|
+
} })))), [cdnImageUrl]);
|
|
23
|
+
const renderBullets = useCallback(({ activeIndex, count, onChange }) => React.createElement(Bullets, { activeIndex: activeIndex, count: count, onChange: onChange }), []);
|
|
24
|
+
return (React.createElement(Carousel, { activeIndex: activeIndex, bullets: renderBullets, data: producVariantMedia, onActiveIndexChanged: handleOnActiveChanged }, renderItem));
|
|
24
25
|
};
|
|
25
26
|
export { ProductVariantSlider };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { StyleSheet } from "react-native";
|
|
2
2
|
import { theme } from "../../../../theme/theme";
|
|
3
|
-
const { colorBase, colorGrayscaleL, colorContent, spaceM } = theme();
|
|
3
|
+
const { colorBase, colorGrayscaleL, colorContent, spaceM, spaceXL } = theme();
|
|
4
4
|
const PAGINATION_SIZE = 37;
|
|
5
5
|
const style = StyleSheet.create({
|
|
6
6
|
image: {
|
|
@@ -25,5 +25,8 @@ const style = StyleSheet.create({
|
|
|
25
25
|
marginTop: spaceM,
|
|
26
26
|
position: "relative",
|
|
27
27
|
},
|
|
28
|
+
slide: {
|
|
29
|
+
paddingHorizontal: spaceXL,
|
|
30
|
+
},
|
|
28
31
|
});
|
|
29
32
|
export { style };
|
|
@@ -19,10 +19,10 @@ const ProductVariant = ({ country, checkoutId, checkoutItem, currentProductVaria
|
|
|
19
19
|
const handleOnChangedProductVariantSlider = useCallback((active) => trackImageView({ perspective: checkoutItem.productVariant.media[active]?.perspective }), [checkoutItem.productVariant.media, trackImageView]);
|
|
20
20
|
const { price } = checkoutItem;
|
|
21
21
|
const { media, brand, name, color } = checkoutItem.productVariant;
|
|
22
|
-
return (React.createElement(View, {
|
|
23
|
-
React.createElement(
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
return (React.createElement(View, { testID: "product-variant" },
|
|
23
|
+
React.createElement(ProductVariantSlider, { producVariantMedia: media, onChanged: handleOnChangedProductVariantSlider }),
|
|
24
|
+
React.createElement(View, { style: [style.content, customStyle?.content] },
|
|
25
|
+
React.createElement(ProductVariantDescription, { brand: brand, color: color, country: country, name: name, price: price, size: currentProductVariant.size }),
|
|
26
|
+
children)));
|
|
27
27
|
};
|
|
28
28
|
export { ProductVariant };
|
package/dist/infrastructure/ui/views/summaryTabs/components/checkoutItemsTabs/CheckoutItemsTabs.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Text } from "@lookiero/aurora";
|
|
2
2
|
import { useI18nMessage } from "@lookiero/i18n-react";
|
|
3
|
-
import React, { useCallback } from "react";
|
|
3
|
+
import React, { useCallback, useMemo } from "react";
|
|
4
4
|
import { View } from "react-native";
|
|
5
5
|
import { CheckoutItemStatus } from "../../../../../../domain/checkoutItem/model/checkoutItem";
|
|
6
6
|
import { Tabs } from "../../../../components/layouts/tabs/Tabs";
|
|
@@ -15,10 +15,10 @@ const CheckoutItemsTabs = ({ tabIndex, checkoutItemsKept, checkoutItemsReturned,
|
|
|
15
15
|
const keepEmptyText = useI18nMessage({ id: I18nMessages.SUMMARY_KEEP_EMPTY });
|
|
16
16
|
const returnEmptyText = useI18nMessage({ id: I18nMessages.SUMMARY_RETURN_EMPTY });
|
|
17
17
|
const handleOnPressItem = useCallback((checkoutItemId) => onPressItem(checkoutItemId), [onPressItem]);
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
const data = useMemo(() => [0, 0], []);
|
|
19
|
+
const renderItem = useCallback(({ index }) => index === 0 ? (checkoutItemsKept.length === 0 ? (React.createElement(Text, { style: style.emptyText }, keepEmptyText)) : (React.createElement(React.Fragment, null, checkoutItemsKept.map((checkoutItem) => (React.createElement(CheckoutItem, { key: checkoutItem.id, checkoutItemPrice: checkoutItem.price, checkoutItemStatus: checkoutItem.status, country: country, testID: "keep-checkout-item", checkoutItemProductVariant: checkoutItem.status === CheckoutItemStatus.REPLACED && checkoutItem.replacedFor
|
|
20
|
+
? checkoutItem.replacedFor
|
|
21
|
+
: checkoutItem.productVariant, onPress: () => handleOnPressItem(checkoutItem.id) })))))) : checkoutItemsReturned.length === 0 ? (React.createElement(Text, { style: style.emptyText }, returnEmptyText)) : (React.createElement(React.Fragment, null, checkoutItemsReturned.map((checkoutItem) => (React.createElement(CheckoutItem, { key: checkoutItem.id, checkoutItemPrice: checkoutItem.price, checkoutItemProductVariant: checkoutItem.productVariant, checkoutItemStatus: checkoutItem.status, country: country, style: { image: style.returnCheckoutItem }, testID: "return-checkout-item", discarded: true, onPress: () => handleOnPressItem(checkoutItem.id) }))))), [checkoutItemsKept, checkoutItemsReturned, country, handleOnPressItem, keepEmptyText, returnEmptyText]);
|
|
22
|
+
return (React.createElement(Tabs, { data: data, defaultIndex: tabIndex, style: { sliderContainer: style.sliderContainer }, tabLabels: [`${keepTabText} (${checkoutItemsKept.length})`, `${returnTabText} (${checkoutItemsReturned.length})`], onChanged: onChanged }, renderItem));
|
|
23
23
|
};
|
|
24
24
|
export { CheckoutItemsTabs };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { FC } from "react";
|
|
2
|
+
interface BulletsProps {
|
|
3
|
+
readonly activeIndex: number;
|
|
4
|
+
readonly onChange: (index: number) => void;
|
|
5
|
+
readonly count: number;
|
|
6
|
+
readonly maxBullets?: number;
|
|
7
|
+
readonly testID?: string;
|
|
8
|
+
}
|
|
9
|
+
declare const Bullets: FC<BulletsProps>;
|
|
10
|
+
export { Bullets };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { animated, useSpring } from "@react-spring/native";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { View, Pressable } from "react-native";
|
|
4
|
+
import { theme } from "../../../../../infrastructure/ui/theme/theme";
|
|
5
|
+
import { style } from "./Bullets.style";
|
|
6
|
+
const { colorContent, colorGrayscaleM } = theme();
|
|
7
|
+
const MAX = 5;
|
|
8
|
+
const DIAMETER_MAX = 8;
|
|
9
|
+
const DIAMETER_MIN = 2;
|
|
10
|
+
const Bullet = ({ index, activeIndex, maxBullets, onChange }) => {
|
|
11
|
+
const pivot = Math.floor(maxBullets / 2) + 1;
|
|
12
|
+
const delta = Math.abs(index - activeIndex);
|
|
13
|
+
const diameter = delta > 1 ? DIAMETER_MAX - delta * DIAMETER_MIN : DIAMETER_MAX;
|
|
14
|
+
const color = delta === 0 ? colorContent : colorGrayscaleM;
|
|
15
|
+
const springs = useSpring({ diameter, color });
|
|
16
|
+
return delta >= pivot ? null : (React.createElement(Pressable, { onPress: () => onChange(index) },
|
|
17
|
+
React.createElement(animated.View, { accessibilityState: { selected: delta === 0 }, testID: "bullet", style: [
|
|
18
|
+
style.bullet,
|
|
19
|
+
{
|
|
20
|
+
width: springs.diameter,
|
|
21
|
+
height: springs.diameter,
|
|
22
|
+
backgroundColor: springs.color,
|
|
23
|
+
borderRadius: springs.diameter,
|
|
24
|
+
},
|
|
25
|
+
] })));
|
|
26
|
+
};
|
|
27
|
+
const Bullets = ({ activeIndex, count, maxBullets = MAX, onChange, testID = "bullets" }) => (React.createElement(View, { style: style.bullets, testID: testID }, [...Array(count).keys()].map((index) => (React.createElement(Bullet, { key: index, activeIndex: activeIndex, index: index, maxBullets: maxBullets, onChange: onChange })))));
|
|
28
|
+
export { Bullets };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { StyleSheet } from "react-native";
|
|
2
|
+
import { theme } from "../../../../../infrastructure/ui/theme/theme";
|
|
3
|
+
const { spaceM } = theme();
|
|
4
|
+
const style = StyleSheet.create({
|
|
5
|
+
bullet: {
|
|
6
|
+
marginHorizontal: 3,
|
|
7
|
+
},
|
|
8
|
+
bullets: {
|
|
9
|
+
alignItems: "center",
|
|
10
|
+
flexDirection: "row",
|
|
11
|
+
justifyContent: "center",
|
|
12
|
+
paddingVertical: spaceM,
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
export { style };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import { StyleProp, ViewStyle } from "react-native";
|
|
3
|
+
interface RenderItemFunctionArgs<T> {
|
|
4
|
+
readonly item: T;
|
|
5
|
+
readonly index: number;
|
|
6
|
+
}
|
|
7
|
+
interface RenderItemFunction<T> {
|
|
8
|
+
(args: RenderItemFunctionArgs<T>): JSX.Element;
|
|
9
|
+
}
|
|
10
|
+
interface RenderBulletsFunctionArgs {
|
|
11
|
+
readonly activeIndex: number;
|
|
12
|
+
readonly count: number;
|
|
13
|
+
readonly onChange: (index: number) => void;
|
|
14
|
+
}
|
|
15
|
+
interface RenderBulletsFunction {
|
|
16
|
+
(args: RenderBulletsFunctionArgs): JSX.Element;
|
|
17
|
+
}
|
|
18
|
+
interface CarouselStyle {
|
|
19
|
+
readonly container?: StyleProp<ViewStyle>;
|
|
20
|
+
}
|
|
21
|
+
interface CarouselProps<T> {
|
|
22
|
+
readonly activeIndex?: number;
|
|
23
|
+
readonly data: T[];
|
|
24
|
+
readonly enabled?: boolean;
|
|
25
|
+
readonly children: RenderItemFunction<T>;
|
|
26
|
+
readonly bullets?: RenderBulletsFunction;
|
|
27
|
+
readonly onActiveIndexChanged?: (index: number) => void;
|
|
28
|
+
readonly style?: CarouselStyle;
|
|
29
|
+
}
|
|
30
|
+
declare const Carousel: <T>({ activeIndex, data, enabled, children, bullets, onActiveIndexChanged, style: customStyle, }: CarouselProps<T>) => JSX.Element;
|
|
31
|
+
export type { RenderItemFunction, RenderBulletsFunction };
|
|
32
|
+
export { Carousel };
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
2
|
+
import { View } from "react-native";
|
|
3
|
+
import { Gesture, GestureDetector, GestureHandlerRootView } from "react-native-gesture-handler";
|
|
4
|
+
import Animated, { useSharedValue, withSpring, useAnimatedStyle, runOnJS } from "react-native-reanimated";
|
|
5
|
+
import { style } from "./Carousel.style";
|
|
6
|
+
const SPRING_CONFIG = {
|
|
7
|
+
damping: 25,
|
|
8
|
+
mass: 1,
|
|
9
|
+
stiffness: 300,
|
|
10
|
+
};
|
|
11
|
+
const clamp = (min, max, value) => {
|
|
12
|
+
"worklet";
|
|
13
|
+
return Math.min(max, Math.max(min, value));
|
|
14
|
+
};
|
|
15
|
+
const Carousel = ({ activeIndex = 0, data, enabled = true, children, bullets, onActiveIndexChanged, style: customStyle, }) => {
|
|
16
|
+
const [carouselDimensions, setCarouselDimensions] = useState();
|
|
17
|
+
const handleOnLayout = useCallback(({ nativeEvent: { layout } }) => setCarouselDimensions({ width: layout.width, height: layout.height }), []);
|
|
18
|
+
const carouselWidth = carouselDimensions?.width;
|
|
19
|
+
const panTranslationX = useSharedValue(0);
|
|
20
|
+
const panInitialTranslationX = useSharedValue(undefined);
|
|
21
|
+
const [panActive, setPanActive] = useState(false);
|
|
22
|
+
const activeIndexRef = useRef(activeIndex);
|
|
23
|
+
activeIndexRef.current = activeIndex;
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
if (panActive || !carouselWidth) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
panTranslationX.value = -activeIndex * carouselWidth;
|
|
29
|
+
}, [activeIndex, carouselWidth, panActive, panTranslationX]);
|
|
30
|
+
const updateActiveIndex = useCallback((index) => {
|
|
31
|
+
if (activeIndexRef.current === index) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
onActiveIndexChanged?.(index);
|
|
35
|
+
}, [onActiveIndexChanged]);
|
|
36
|
+
const handleOnActiveIndexChanged = useCallback((index) => {
|
|
37
|
+
if (!carouselWidth) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
updateActiveIndex(index);
|
|
41
|
+
panTranslationX.value = withSpring(-index * carouselWidth, SPRING_CONFIG);
|
|
42
|
+
}, [carouselWidth, panTranslationX, updateActiveIndex]);
|
|
43
|
+
const panGesture = useMemo(() => Gesture.Pan()
|
|
44
|
+
.withTestId("carousel-pan-gesture")
|
|
45
|
+
.enabled(enabled)
|
|
46
|
+
.maxPointers(1)
|
|
47
|
+
.activeOffsetX([-20, 20])
|
|
48
|
+
// This method does not work if legacy implementation is enabled
|
|
49
|
+
// Expo.tsx => enableLegacyWebImplementation(true)
|
|
50
|
+
// .onStart(() => {
|
|
51
|
+
// panInitialTranslationX.value = panTranslationX.value;
|
|
52
|
+
// })
|
|
53
|
+
// This method is defined as legacy implementation is enabled
|
|
54
|
+
.onBegin(() => {
|
|
55
|
+
runOnJS(setPanActive)(true);
|
|
56
|
+
panInitialTranslationX.value = panTranslationX.value;
|
|
57
|
+
})
|
|
58
|
+
.onUpdate(({ translationX }) => {
|
|
59
|
+
if (panInitialTranslationX.value === undefined || !carouselWidth) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const tX = panInitialTranslationX.value + translationX;
|
|
63
|
+
const index = clamp(0, data.length - 1, Math.round(-tX / carouselWidth));
|
|
64
|
+
panTranslationX.value = tX;
|
|
65
|
+
runOnJS(updateActiveIndex)(index);
|
|
66
|
+
})
|
|
67
|
+
.onEnd(({ translationX, velocityX }) => {
|
|
68
|
+
if (panInitialTranslationX.value === undefined || !carouselWidth) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const tX = panInitialTranslationX.value + translationX;
|
|
72
|
+
const indexDelta = Math.round(translationX / carouselWidth);
|
|
73
|
+
const velocityIndex = Math.abs(indexDelta) > 0 ? 0 : clamp(-1, 1, Math.abs(velocityX) > 2 ? -velocityX : 0);
|
|
74
|
+
const index = clamp(0, data.length - 1, Math.round(-tX / carouselWidth) + velocityIndex);
|
|
75
|
+
panTranslationX.value = withSpring(-index * carouselWidth, SPRING_CONFIG);
|
|
76
|
+
panInitialTranslationX.value = undefined;
|
|
77
|
+
runOnJS(updateActiveIndex)(index);
|
|
78
|
+
runOnJS(setPanActive)(true);
|
|
79
|
+
}), [carouselWidth, data.length, enabled, panInitialTranslationX, panTranslationX, updateActiveIndex]);
|
|
80
|
+
const animatedStyle = useAnimatedStyle(() => ({ transform: [{ translateX: panTranslationX.value }] }), [panTranslationX]);
|
|
81
|
+
return (React.createElement(View, { style: [style.container, customStyle?.container], testID: "carousel" },
|
|
82
|
+
React.createElement(View, { style: style.carousel, testID: "carousel-layout", onLayout: handleOnLayout }, carouselWidth && (React.createElement(GestureHandlerRootView, { style: { flex: 1 } },
|
|
83
|
+
React.createElement(GestureDetector, { gesture: panGesture },
|
|
84
|
+
React.createElement(Animated.View, { style: [style.carouselTrack, { width: carouselWidth * data.length }, animatedStyle], testID: "carousel-track" }, data.map((item, index) => (React.createElement(View, { key: index, style: [style.carouselItem, { width: carouselWidth }], testID: "carousel-item" }, children({ index, item }))))))))),
|
|
85
|
+
bullets && (React.createElement(View, { style: style.bullets, testID: "carousel-bullets" }, bullets({ activeIndex, count: data.length, onChange: handleOnActiveIndexChanged })))));
|
|
86
|
+
};
|
|
87
|
+
export { Carousel };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
declare const style: {
|
|
2
|
+
bullets: {
|
|
3
|
+
bottom: number;
|
|
4
|
+
justifyContent: "center";
|
|
5
|
+
position: "absolute";
|
|
6
|
+
width: string;
|
|
7
|
+
};
|
|
8
|
+
carousel: {
|
|
9
|
+
flex: number;
|
|
10
|
+
};
|
|
11
|
+
carouselItem: {
|
|
12
|
+
flex: number;
|
|
13
|
+
};
|
|
14
|
+
carouselTrack: {
|
|
15
|
+
flex: number;
|
|
16
|
+
flexDirection: "row";
|
|
17
|
+
height: string;
|
|
18
|
+
};
|
|
19
|
+
container: {
|
|
20
|
+
flex: number;
|
|
21
|
+
overflow: "hidden";
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
export { style };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { StyleSheet } from "react-native";
|
|
2
|
+
const style = StyleSheet.create({
|
|
3
|
+
bullets: {
|
|
4
|
+
bottom: 0,
|
|
5
|
+
justifyContent: "center",
|
|
6
|
+
position: "absolute",
|
|
7
|
+
width: "100%",
|
|
8
|
+
},
|
|
9
|
+
carousel: {
|
|
10
|
+
flex: 1,
|
|
11
|
+
},
|
|
12
|
+
carouselItem: {
|
|
13
|
+
flex: 1,
|
|
14
|
+
},
|
|
15
|
+
carouselTrack: {
|
|
16
|
+
flex: 1,
|
|
17
|
+
flexDirection: "row",
|
|
18
|
+
height: "100%",
|
|
19
|
+
},
|
|
20
|
+
container: {
|
|
21
|
+
flex: 1,
|
|
22
|
+
overflow: "hidden",
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
export { style };
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import React, { useCallback } from "react";
|
|
2
2
|
import { View } from "react-native";
|
|
3
|
-
import { theme } from "../../../../../infrastructure/ui/theme/theme";
|
|
4
3
|
import { style } from "./Sticky.style";
|
|
5
|
-
const { spaceXL } = theme();
|
|
6
4
|
const Sticky = ({ children, style: customStyle, onLayout }) => {
|
|
7
5
|
const handleOnLayout = useCallback(({ nativeEvent: { layout: { width, height }, }, }) => onLayout?.({ width, height }), [onLayout]);
|
|
8
|
-
return (React.createElement(View, { style: [style.sticky,
|
|
6
|
+
return (React.createElement(View, { style: [style.sticky, customStyle], onLayout: handleOnLayout }, children));
|
|
9
7
|
};
|
|
10
8
|
export { Sticky };
|
|
@@ -5,6 +5,7 @@ declare const style: StyleSheet.NamedStyles<any> | StyleSheet.NamedStyles<{
|
|
|
5
5
|
backgroundColor: string;
|
|
6
6
|
bottom: number;
|
|
7
7
|
elevation: number;
|
|
8
|
+
paddingBottom: number;
|
|
8
9
|
paddingTop: number;
|
|
9
10
|
shadowColor: string;
|
|
10
11
|
shadowOffset: {
|
|
@@ -20,6 +21,7 @@ declare const style: StyleSheet.NamedStyles<any> | StyleSheet.NamedStyles<{
|
|
|
20
21
|
backgroundColor: string;
|
|
21
22
|
bottom: number;
|
|
22
23
|
elevation: number;
|
|
24
|
+
paddingBottom: number;
|
|
23
25
|
paddingTop: number;
|
|
24
26
|
shadowColor: string;
|
|
25
27
|
shadowOffset: {
|
|
@@ -35,6 +37,7 @@ declare const style: StyleSheet.NamedStyles<any> | StyleSheet.NamedStyles<{
|
|
|
35
37
|
backgroundColor: string;
|
|
36
38
|
bottom: number;
|
|
37
39
|
elevation: number;
|
|
40
|
+
paddingBottom: number;
|
|
38
41
|
paddingTop: number;
|
|
39
42
|
shadowColor: string;
|
|
40
43
|
shadowOffset: {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Platform, StyleSheet } from "react-native";
|
|
2
2
|
import { theme } from "../../../../../infrastructure/ui/theme/theme";
|
|
3
|
-
const { colorBase, elevationColor, elevationLayerL, elevationOffset, elevationOpacityM, elevationRadius,
|
|
3
|
+
const { colorBase, elevationColor, elevationLayerL, elevationOffset, elevationOpacityM, elevationRadius, spaceM, spaceL, } = theme();
|
|
4
4
|
const style = StyleSheet.create({
|
|
5
5
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
6
6
|
// @ts-ignore
|
|
@@ -8,7 +8,8 @@ const style = StyleSheet.create({
|
|
|
8
8
|
backgroundColor: colorBase,
|
|
9
9
|
bottom: 0,
|
|
10
10
|
elevation: elevationLayerL,
|
|
11
|
-
|
|
11
|
+
paddingBottom: spaceL,
|
|
12
|
+
paddingTop: spaceM,
|
|
12
13
|
shadowColor: elevationColor,
|
|
13
14
|
shadowOffset: elevationOffset,
|
|
14
15
|
shadowOpacity: elevationOpacityM,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lookiero/checkout",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.10.0",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"files": [
|
|
@@ -57,8 +57,10 @@
|
|
|
57
57
|
"react": "^18.2.0",
|
|
58
58
|
"react-dom": "^18.2.0",
|
|
59
59
|
"react-native": "^0.71.4",
|
|
60
|
+
"react-native-gesture-handler": "^2.12.0",
|
|
60
61
|
"react-native-get-random-values": "^1.8.0",
|
|
61
62
|
"react-native-web": "^0.18.11",
|
|
63
|
+
"react-native-reanimated": "^3.3.0",
|
|
62
64
|
"react-router-dom": "^6.8.1",
|
|
63
65
|
"react-router-native": "^6.8.1"
|
|
64
66
|
},
|
|
@@ -77,8 +79,8 @@
|
|
|
77
79
|
"@pact-foundation/pact-node": "^10.17.6",
|
|
78
80
|
"@react-native-firebase/analytics": "10.5.1",
|
|
79
81
|
"@react-native-firebase/app": "10.5.0",
|
|
80
|
-
"@testing-library/react-native": "^11.5.0",
|
|
81
82
|
"@testing-library/jest-native": "^5.4.2",
|
|
83
|
+
"@testing-library/react-native": "^11.5.0",
|
|
82
84
|
"@trivago/prettier-plugin-sort-imports": "^3.3.0",
|
|
83
85
|
"@types/jest": "^29.2.4",
|
|
84
86
|
"@types/pino-pretty": "^5.0.0",
|
|
@@ -116,8 +118,10 @@
|
|
|
116
118
|
"react-error-overlay": "^6.0.9",
|
|
117
119
|
"react-native": "^0.71.3",
|
|
118
120
|
"react-native-adjust": "^4.33.0",
|
|
121
|
+
"react-native-gesture-handler": "^2.12.0",
|
|
119
122
|
"react-native-get-random-values": "^1.8.0",
|
|
120
123
|
"react-native-web": "^0.18.11",
|
|
124
|
+
"react-native-reanimated": "^3.3.0",
|
|
121
125
|
"react-router-dom": "^6.8.1",
|
|
122
126
|
"react-router-native": "^6.8.1",
|
|
123
127
|
"react-test-renderer": "^18.0.0",
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { FC, ReactNode } from "react";
|
|
2
|
-
import { StyleProp, ViewStyle } from "react-native";
|
|
3
|
-
interface PaginationProps {
|
|
4
|
-
readonly touchable?: boolean;
|
|
5
|
-
readonly paginationStyle?: StyleProp<ViewStyle>;
|
|
6
|
-
readonly paginationItemStyle?: StyleProp<ViewStyle>;
|
|
7
|
-
readonly paginationActiveItemStyle?: StyleProp<ViewStyle>;
|
|
8
|
-
readonly count?: number;
|
|
9
|
-
readonly activeIndex?: number;
|
|
10
|
-
readonly onChange: (index: number) => void;
|
|
11
|
-
readonly renderItem?: (index: number) => ReactNode;
|
|
12
|
-
}
|
|
13
|
-
declare const Pagination: FC<PaginationProps>;
|
|
14
|
-
export { Pagination };
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { Pressable, View } from "react-native";
|
|
3
|
-
import { style } from "./Pagination.style";
|
|
4
|
-
const Pagination = ({ touchable = true, paginationStyle, paginationItemStyle, paginationActiveItemStyle, count = 0, activeIndex = 0, renderItem, onChange, }) => (React.createElement(View, { style: [style.paginationWrapper, paginationStyle], testID: "slider-pagination" }, Array.from(Array(count).keys()).map((index) => (React.createElement(View, { key: index, style: style.paginationContainer },
|
|
5
|
-
React.createElement(Pressable, { testID: "slider-pagination-item", style: [
|
|
6
|
-
style.paginationItem,
|
|
7
|
-
activeIndex === index && style.active,
|
|
8
|
-
paginationItemStyle,
|
|
9
|
-
activeIndex === index && paginationActiveItemStyle,
|
|
10
|
-
], onPress: !touchable ? undefined : () => onChange(index) }, renderItem?.(index)))))));
|
|
11
|
-
export { Pagination };
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
declare const style: {
|
|
2
|
-
active: {
|
|
3
|
-
backgroundColor: string;
|
|
4
|
-
};
|
|
5
|
-
paginationContainer: {
|
|
6
|
-
margin: number;
|
|
7
|
-
};
|
|
8
|
-
paginationItem: {
|
|
9
|
-
backgroundColor: string;
|
|
10
|
-
borderRadius: number;
|
|
11
|
-
height: number;
|
|
12
|
-
width: number;
|
|
13
|
-
};
|
|
14
|
-
paginationWrapper: {
|
|
15
|
-
alignItems: "center";
|
|
16
|
-
bottom: number;
|
|
17
|
-
flexDirection: "row";
|
|
18
|
-
justifyContent: "center";
|
|
19
|
-
position: "absolute";
|
|
20
|
-
width: string;
|
|
21
|
-
};
|
|
22
|
-
};
|
|
23
|
-
export { style };
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { StyleSheet } from "react-native";
|
|
2
|
-
import { theme } from "../../../../../infrastructure/ui/theme/theme";
|
|
3
|
-
const { colorGrayscaleS, colorGrayscaleXL } = theme();
|
|
4
|
-
const DOT_SIZE = 8;
|
|
5
|
-
const style = StyleSheet.create({
|
|
6
|
-
active: {
|
|
7
|
-
backgroundColor: colorGrayscaleXL,
|
|
8
|
-
},
|
|
9
|
-
paginationContainer: {
|
|
10
|
-
margin: 3,
|
|
11
|
-
},
|
|
12
|
-
paginationItem: {
|
|
13
|
-
backgroundColor: colorGrayscaleS,
|
|
14
|
-
borderRadius: DOT_SIZE / 2,
|
|
15
|
-
height: DOT_SIZE,
|
|
16
|
-
width: DOT_SIZE,
|
|
17
|
-
},
|
|
18
|
-
paginationWrapper: {
|
|
19
|
-
alignItems: "center",
|
|
20
|
-
bottom: 10,
|
|
21
|
-
flexDirection: "row",
|
|
22
|
-
justifyContent: "center",
|
|
23
|
-
position: "absolute",
|
|
24
|
-
width: "100%",
|
|
25
|
-
},
|
|
26
|
-
});
|
|
27
|
-
export { style };
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { FC, ReactNode } from "react";
|
|
2
|
-
import { StyleProp, ViewStyle } from "react-native";
|
|
3
|
-
interface SliderProps {
|
|
4
|
-
readonly children: ReactNode[];
|
|
5
|
-
readonly active?: number;
|
|
6
|
-
readonly loop?: boolean;
|
|
7
|
-
readonly minDistanceToCapture?: number;
|
|
8
|
-
readonly minDistanceForAction?: number;
|
|
9
|
-
readonly gesturesEnabled?: boolean;
|
|
10
|
-
readonly paginationEnabled?: boolean;
|
|
11
|
-
readonly paginationStyle?: StyleProp<ViewStyle>;
|
|
12
|
-
readonly paginationItemStyle?: StyleProp<ViewStyle>;
|
|
13
|
-
readonly paginationActiveItemStyle?: StyleProp<ViewStyle>;
|
|
14
|
-
readonly onSliderStart?: () => void;
|
|
15
|
-
readonly onSliderEnd?: () => void;
|
|
16
|
-
readonly onChanged?: (index: number) => void;
|
|
17
|
-
readonly paginationRenderItem?: (index: number) => ReactNode;
|
|
18
|
-
}
|
|
19
|
-
declare const Slider: FC<SliderProps>;
|
|
20
|
-
export { Slider };
|
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
import React, { useCallback, useEffect, useRef, useState } from "react";
|
|
2
|
-
import { Animated, I18nManager, PanResponder, StyleSheet, View, } from "react-native";
|
|
3
|
-
import { Pagination } from "./Pagination";
|
|
4
|
-
import { style } from "./Slider.style";
|
|
5
|
-
const DEFAULT_WIDTH = 200;
|
|
6
|
-
const Slider = ({ children, active = 0, loop = false, minDistanceToCapture = 5, minDistanceForAction = 0.2, gesturesEnabled = true, paginationEnabled = true, paginationStyle, paginationItemStyle, paginationActiveItemStyle, onSliderStart, onSliderEnd, onChanged, paginationRenderItem, }) => {
|
|
7
|
-
const flatennedChildren = children.flat();
|
|
8
|
-
const count = flatennedChildren.length;
|
|
9
|
-
const [width, setWidth] = useState(0);
|
|
10
|
-
const widthRef = useRef(width);
|
|
11
|
-
const activeIndex = useRef(active);
|
|
12
|
-
const animatedValueX = useRef(0);
|
|
13
|
-
const animatedValueY = useRef(0);
|
|
14
|
-
const pan = useRef(new Animated.ValueXY()).current;
|
|
15
|
-
const started = useRef(false);
|
|
16
|
-
const panResponder = useRef(PanResponder.create({
|
|
17
|
-
onPanResponderTerminationRequest: () => false,
|
|
18
|
-
onMoveShouldSetPanResponder: () => gesturesEnabled,
|
|
19
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
20
|
-
onMoveShouldSetPanResponderCapture: (_e, gestureState) => {
|
|
21
|
-
if (!gesturesEnabled) {
|
|
22
|
-
return false;
|
|
23
|
-
}
|
|
24
|
-
startAnimation();
|
|
25
|
-
const allow = Math.abs(gestureState.dx) > minDistanceToCapture;
|
|
26
|
-
return allow;
|
|
27
|
-
},
|
|
28
|
-
onPanResponderGrant: () => fixState(),
|
|
29
|
-
onPanResponderMove: Animated.event([null, { dx: pan.x }], {
|
|
30
|
-
useNativeDriver: false,
|
|
31
|
-
}),
|
|
32
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
33
|
-
onPanResponderRelease: (_e, gesture) => {
|
|
34
|
-
const correction = gesture.moveX - gesture.x0;
|
|
35
|
-
if (Math.abs(correction) < widthRef.current * minDistanceForAction) {
|
|
36
|
-
spring({ x: 0, y: 0 });
|
|
37
|
-
}
|
|
38
|
-
else {
|
|
39
|
-
changeIndex(correction > 0 ? (I18nManager.isRTL ? 1 : -1) : I18nManager.isRTL ? -1 : 1);
|
|
40
|
-
}
|
|
41
|
-
},
|
|
42
|
-
onPanResponderEnd: () => endAnimation(),
|
|
43
|
-
})).current;
|
|
44
|
-
const startAnimation = useCallback(() => {
|
|
45
|
-
if (!started.current) {
|
|
46
|
-
onSliderStart?.();
|
|
47
|
-
started.current = true;
|
|
48
|
-
}
|
|
49
|
-
}, [onSliderStart]);
|
|
50
|
-
const endAnimation = useCallback(() => {
|
|
51
|
-
if (started.current) {
|
|
52
|
-
onSliderEnd?.();
|
|
53
|
-
started.current = false;
|
|
54
|
-
}
|
|
55
|
-
}, [onSliderEnd]);
|
|
56
|
-
const fixState = useCallback(() => {
|
|
57
|
-
animatedValueX.current = widthRef.current * activeIndex.current * (I18nManager.isRTL ? 1 : -1);
|
|
58
|
-
animatedValueY.current = 0;
|
|
59
|
-
pan.setOffset({
|
|
60
|
-
x: animatedValueX.current,
|
|
61
|
-
y: animatedValueY.current,
|
|
62
|
-
});
|
|
63
|
-
pan.setValue({ x: 0, y: 0 });
|
|
64
|
-
}, [pan]);
|
|
65
|
-
const spring = useCallback((toValue) => {
|
|
66
|
-
Animated.spring(pan, {
|
|
67
|
-
toValue,
|
|
68
|
-
useNativeDriver: false,
|
|
69
|
-
}).start();
|
|
70
|
-
}, [pan]);
|
|
71
|
-
const changeIndex = useCallback((delta = 1) => {
|
|
72
|
-
const toValue = { x: 0, y: 0 };
|
|
73
|
-
let skipChanges = !delta;
|
|
74
|
-
let calcDelta = delta;
|
|
75
|
-
if (activeIndex.current <= 0 && delta < 0) {
|
|
76
|
-
skipChanges = !loop;
|
|
77
|
-
calcDelta = count + delta;
|
|
78
|
-
}
|
|
79
|
-
else if (activeIndex.current + 1 >= count && delta > 0) {
|
|
80
|
-
skipChanges = !loop;
|
|
81
|
-
calcDelta = -1 * activeIndex.current + delta - 1;
|
|
82
|
-
}
|
|
83
|
-
if (skipChanges) {
|
|
84
|
-
return spring(toValue);
|
|
85
|
-
}
|
|
86
|
-
const index = activeIndex.current + calcDelta;
|
|
87
|
-
activeIndex.current = index;
|
|
88
|
-
toValue.x = widthRef.current * (I18nManager.isRTL ? 1 : -1) * calcDelta;
|
|
89
|
-
spring(toValue);
|
|
90
|
-
onChanged?.(index);
|
|
91
|
-
}, [count, loop, onChanged, spring]);
|
|
92
|
-
const fixAndGo = useCallback((delta) => {
|
|
93
|
-
fixState();
|
|
94
|
-
startAnimation();
|
|
95
|
-
changeIndex(delta);
|
|
96
|
-
}, [changeIndex, fixState, startAnimation]);
|
|
97
|
-
const goTo = useCallback((index = 0) => {
|
|
98
|
-
const delta = index - activeIndex.current;
|
|
99
|
-
if (delta) {
|
|
100
|
-
fixAndGo(delta);
|
|
101
|
-
}
|
|
102
|
-
}, [fixAndGo]);
|
|
103
|
-
const getActiveIndex = useCallback(() => activeIndex.current, []);
|
|
104
|
-
useEffect(() => {
|
|
105
|
-
pan.x.addListener(({ value }) => (animatedValueX.current = value));
|
|
106
|
-
pan.y.addListener(({ value }) => (animatedValueY.current = value));
|
|
107
|
-
return () => {
|
|
108
|
-
pan.x.removeAllListeners();
|
|
109
|
-
pan.y.removeAllListeners();
|
|
110
|
-
};
|
|
111
|
-
}, [pan.x, pan.y]);
|
|
112
|
-
useEffect(() => {
|
|
113
|
-
if (activeIndex.current !== active) {
|
|
114
|
-
goTo(active);
|
|
115
|
-
}
|
|
116
|
-
}, [active, goTo]);
|
|
117
|
-
const onLayoutWrapper = useCallback(({ nativeEvent: { layout: { width: wrapperWidth }, }, }) => {
|
|
118
|
-
const width = wrapperWidth || DEFAULT_WIDTH;
|
|
119
|
-
setWidth(width);
|
|
120
|
-
widthRef.current = width;
|
|
121
|
-
fixState();
|
|
122
|
-
}, [fixState]);
|
|
123
|
-
return (React.createElement(View, { style: style.container, testID: "slider", onLayout: onLayoutWrapper },
|
|
124
|
-
React.createElement(Animated.View, { style: StyleSheet.flatten([
|
|
125
|
-
{
|
|
126
|
-
left: pan.x,
|
|
127
|
-
},
|
|
128
|
-
style.sliderAreaStyle,
|
|
129
|
-
]), ...panResponder.panHandlers }, flatennedChildren.map((child, index) => (React.createElement(View, { key: index, style: { width }, testID: "slider-child" }, child)))),
|
|
130
|
-
paginationEnabled && (React.createElement(Pagination, { activeIndex: getActiveIndex(), count: count, paginationActiveItemStyle: paginationActiveItemStyle, paginationItemStyle: paginationItemStyle, paginationStyle: paginationStyle, renderItem: paginationRenderItem, onChange: (index) => goTo(index) }))));
|
|
131
|
-
};
|
|
132
|
-
export { Slider };
|