@tapcart/mobile-components 0.2.7 → 0.2.9

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.
@@ -0,0 +1,25 @@
1
+ interface Product {
2
+ handle: string;
3
+ }
4
+ interface PageData {
5
+ products: Product[];
6
+ cursorBlob?: string;
7
+ }
8
+ interface UseInfiniteScrollProps {
9
+ initialData: PageData[];
10
+ loadMoreProducts: (params: any) => Promise<PageData>;
11
+ queryVariables: Record<string, any>;
12
+ }
13
+ interface UseInfiniteScrollReturn {
14
+ data: PageData[] | undefined;
15
+ error: any;
16
+ isLoadingInitialData: boolean;
17
+ isLoadingMore: boolean | undefined;
18
+ isEmpty: boolean;
19
+ isReachingEnd: boolean;
20
+ ref: (node?: Element | null | undefined) => void;
21
+ products: Product[];
22
+ }
23
+ declare const useInfiniteScroll: ({ initialData, loadMoreProducts, queryVariables, }: UseInfiniteScrollProps) => UseInfiniteScrollReturn;
24
+ export { useInfiniteScroll };
25
+ //# sourceMappingURL=use-infinite-scroll.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-infinite-scroll.d.ts","sourceRoot":"","sources":["../../../components/hooks/use-infinite-scroll.ts"],"names":[],"mappings":"AAOA,UAAU,OAAO;IACf,MAAM,EAAE,MAAM,CAAA;CAEf;AAED,UAAU,QAAQ;IAChB,QAAQ,EAAE,OAAO,EAAE,CAAA;IACnB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,UAAU,sBAAsB;IAC9B,WAAW,EAAE,QAAQ,EAAE,CAAA;IACvB,gBAAgB,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAA;IACpD,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;CACpC;AAED,UAAU,uBAAuB;IAC/B,IAAI,EAAE,QAAQ,EAAE,GAAG,SAAS,CAAA;IAC5B,KAAK,EAAE,GAAG,CAAA;IACV,oBAAoB,EAAE,OAAO,CAAA;IAC7B,aAAa,EAAE,OAAO,GAAG,SAAS,CAAA;IAClC,OAAO,EAAE,OAAO,CAAA;IAChB,aAAa,EAAE,OAAO,CAAA;IACtB,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,GAAG,SAAS,KAAK,IAAI,CAAA;IAChD,QAAQ,EAAE,OAAO,EAAE,CAAA;CACpB;AAED,QAAA,MAAM,iBAAiB,uDAIpB,sBAAsB,KAAG,uBAkD3B,CAAA;AAED,OAAO,EAAE,iBAAiB,EAAE,CAAA"}
@@ -0,0 +1,49 @@
1
+ "use client";
2
+ import { useCallback, useEffect } from "react";
3
+ import useSWRInfinite from "swr/infinite";
4
+ import { useInView } from "react-intersection-observer";
5
+ const PAGE_SIZE = 8;
6
+ const useInfiniteScroll = ({ initialData, loadMoreProducts, queryVariables, }) => {
7
+ var _a, _b, _c, _d;
8
+ const { ref, inView } = useInView();
9
+ const getKey = (pageIndex, previousPageData) => {
10
+ if (pageIndex === 0)
11
+ return queryVariables;
12
+ if (!previousPageData || !previousPageData.cursorBlob)
13
+ return null;
14
+ return Object.assign(Object.assign({}, queryVariables), { cursorBlob: previousPageData.cursorBlob });
15
+ };
16
+ const { data, error, size, setSize } = useSWRInfinite(getKey, loadMoreProducts, {
17
+ // @ts-ignore
18
+ fallbackData: [initialData],
19
+ revalidateFirstPage: false,
20
+ initialSize: 1,
21
+ });
22
+ const isLoadingInitialData = !data && !error;
23
+ const isLoadingMore = isLoadingInitialData ||
24
+ (size > 0 && data && typeof data[size - 1] === "undefined");
25
+ const isEmpty = ((_b = (_a = data === null || data === void 0 ? void 0 : data[0]) === null || _a === void 0 ? void 0 : _a.products) === null || _b === void 0 ? void 0 : _b.length) === 0;
26
+ const isReachingEnd = isEmpty ||
27
+ ((data && ((_d = (_c = data[data.length - 1]) === null || _c === void 0 ? void 0 : _c.products) === null || _d === void 0 ? void 0 : _d.length)) || 0) < PAGE_SIZE;
28
+ const loadMore = useCallback(() => {
29
+ if (!isLoadingMore && !isReachingEnd) {
30
+ setSize(size + 1);
31
+ }
32
+ }, [isLoadingMore, isReachingEnd, size, setSize]);
33
+ useEffect(() => {
34
+ if (inView) {
35
+ loadMore();
36
+ }
37
+ }, [inView, loadMore]);
38
+ return {
39
+ data,
40
+ error,
41
+ isLoadingInitialData,
42
+ isLoadingMore,
43
+ isEmpty,
44
+ isReachingEnd,
45
+ ref,
46
+ products: data ? data.flatMap((page) => page === null || page === void 0 ? void 0 : page.products) : [],
47
+ };
48
+ };
49
+ export { useInfiniteScroll };
@@ -1,32 +1,67 @@
1
1
  import * as React from "react";
2
+ export declare type Config = {
3
+ gridLayout?: string;
4
+ productImage?: {
5
+ enabled: boolean;
6
+ cornerRadius: number;
7
+ aspectRatio: "1:1" | "2:3" | "4:5";
8
+ scaling: "fill" | "fit";
9
+ };
10
+ price?: {
11
+ enabled: boolean;
12
+ fontSize: number;
13
+ textAlignment: string;
14
+ currency: string;
15
+ locale: string;
16
+ };
17
+ productTitle?: {
18
+ enabled: boolean;
19
+ fontSize: number;
20
+ uppercase: boolean;
21
+ textAlignment: string;
22
+ wrapText: boolean;
23
+ };
24
+ quickAdd?: {
25
+ enabled: boolean;
26
+ fontSize: number;
27
+ uppercase: boolean;
28
+ textAlignment: string;
29
+ cornerRadius: number;
30
+ quickAdd: (event: React.MouseEvent<HTMLButtonElement>, product: ProductCardProps["product"]) => void;
31
+ };
32
+ badge?: {
33
+ text: string;
34
+ verticalPosition: "top" | "bottom" | "below";
35
+ horizontalPosition: "left" | "right" | "full-width";
36
+ icon: string;
37
+ };
38
+ favoritesIcon?: {
39
+ enabled: boolean;
40
+ layoutType: "topLeft" | "topRight" | "bottomLeft" | "bottomRight" | "default";
41
+ showBackground: boolean;
42
+ cornerRadius: number;
43
+ icon: string;
44
+ size: "small" | "large" | null | undefined;
45
+ };
46
+ };
2
47
  declare type ProductCardProps = {
48
+ config: Config;
3
49
  product: {
4
50
  variants: {
5
51
  compare_at_price: number | undefined;
6
52
  price: number;
7
53
  }[];
8
54
  images: {
9
- src: string;
55
+ url: string;
10
56
  }[];
11
57
  title: string;
12
58
  tags: string[];
59
+ availableForSale: boolean;
60
+ openProduct: (event: React.MouseEvent<HTMLDivElement>, product: ProductCardProps["product"]) => void;
13
61
  };
14
- className: string;
15
- scaling: "fit" | "fill";
16
- isQuickAddProductEnabled: boolean;
17
62
  isLoading: boolean;
18
- badge?: {
19
- text: string;
20
- variant: "secondary" | "default" | "destructive" | "outline" | null | undefined;
21
- className?: string;
22
- position: "topLeft" | "topRight" | "bottomLeft" | "bottomRight";
23
- };
24
- icon?: {
25
- name: string;
26
- position: "topLeft" | "topRight" | "bottomLeft" | "bottomRight";
27
- };
28
- quickAdd: (event: React.MouseEvent<HTMLButtonElement>, product: ProductCardProps["product"]) => void;
29
- openProduct: (event: React.MouseEvent<HTMLDivElement>, product: ProductCardProps["product"]) => void;
63
+ favorited?: boolean;
64
+ onFavoriteClick?: () => void;
30
65
  };
31
66
  declare const ProductCard: React.FC<ProductCardProps>;
32
67
  export { ProductCard };
@@ -1 +1 @@
1
- {"version":3,"file":"product-card.d.ts","sourceRoot":"","sources":["../../../components/ui/product-card.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAK9B,aAAK,gBAAgB,GAAG;IACtB,OAAO,EAAE;QACP,QAAQ,EAAE;YAAE,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,EAAE,CAAC;QACpE,MAAM,EAAE;YAAE,GAAG,EAAE,MAAM,CAAA;SAAE,EAAE,CAAC;QAC1B,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,EAAE,CAAC;KAChB,CAAC;IACF,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,KAAK,GAAG,MAAM,CAAC;IACxB,wBAAwB,EAAE,OAAO,CAAC;IAClC,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,WAAW,GAAG,SAAS,GAAG,aAAa,GAAG,SAAS,GAAG,IAAI,GAAG,SAAS,CAAC;QAChF,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,QAAQ,EAAE,SAAS,GAAG,UAAU,GAAG,YAAY,GAAG,aAAa,CAAC;KACjE,CAAC;IACF,IAAI,CAAC,EAAE;QACL,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,SAAS,GAAG,UAAU,GAAG,YAAY,GAAG,aAAa,CAAC;KACjE,CAAA;IACD,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,iBAAiB,CAAC,EAAE,OAAO,EAAE,gBAAgB,CAAC,SAAS,CAAC,KAAK,IAAI,CAAC;IACrG,WAAW,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,OAAO,EAAE,gBAAgB,CAAC,SAAS,CAAC,KAAK,IAAI,CAAC;CACtG,CAAC;AAuBF,QAAA,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAkE3C,CAAA;AAED,OAAO,EAAE,WAAW,EAAE,CAAA"}
1
+ {"version":3,"file":"product-card.d.ts","sourceRoot":"","sources":["../../../components/ui/product-card.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAO9B,oBAAY,MAAM,GAAG;IACnB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,YAAY,CAAC,EAAE;QACb,OAAO,EAAE,OAAO,CAAA;QAChB,YAAY,EAAE,MAAM,CAAA;QACpB,WAAW,EAAE,KAAK,GAAG,KAAK,GAAG,KAAK,CAAA;QAClC,OAAO,EAAE,MAAM,GAAG,KAAK,CAAA;KACxB,CAAA;IACD,KAAK,CAAC,EAAE;QACN,OAAO,EAAE,OAAO,CAAA;QAChB,QAAQ,EAAE,MAAM,CAAA;QAChB,aAAa,EAAE,MAAM,CAAA;QACrB,QAAQ,EAAE,MAAM,CAAA;QAChB,MAAM,EAAE,MAAM,CAAA;KACf,CAAA;IACD,YAAY,CAAC,EAAE;QACb,OAAO,EAAE,OAAO,CAAA;QAChB,QAAQ,EAAE,MAAM,CAAA;QAChB,SAAS,EAAE,OAAO,CAAA;QAClB,aAAa,EAAE,MAAM,CAAA;QACrB,QAAQ,EAAE,OAAO,CAAA;KAClB,CAAA;IACD,QAAQ,CAAC,EAAE;QACT,OAAO,EAAE,OAAO,CAAA;QAChB,QAAQ,EAAE,MAAM,CAAA;QAChB,SAAS,EAAE,OAAO,CAAA;QAClB,aAAa,EAAE,MAAM,CAAA;QACrB,YAAY,EAAE,MAAM,CAAA;QACpB,QAAQ,EAAE,CACR,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,iBAAiB,CAAC,EAC1C,OAAO,EAAE,gBAAgB,CAAC,SAAS,CAAC,KACjC,IAAI,CAAA;KACV,CAAA;IACD,KAAK,CAAC,EAAE;QACN,IAAI,EAAE,MAAM,CAAA;QACZ,gBAAgB,EAAE,KAAK,GAAG,QAAQ,GAAG,OAAO,CAAA;QAC5C,kBAAkB,EAAE,MAAM,GAAG,OAAO,GAAG,YAAY,CAAA;QACnD,IAAI,EAAE,MAAM,CAAA;KACb,CAAA;IACD,aAAa,CAAC,EAAE;QACd,OAAO,EAAE,OAAO,CAAA;QAChB,UAAU,EACN,SAAS,GACT,UAAU,GACV,YAAY,GACZ,aAAa,GACb,SAAS,CAAA;QACb,cAAc,EAAE,OAAO,CAAA;QACvB,YAAY,EAAE,MAAM,CAAA;QACpB,IAAI,EAAE,MAAM,CAAA;QACZ,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAA;KAC3C,CAAA;CACF,CAAA;AAED,aAAK,gBAAgB,GAAG;IACtB,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE;QACP,QAAQ,EAAE;YAAE,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,EAAE,CAAA;QACnE,MAAM,EAAE;YAAE,GAAG,EAAE,MAAM,CAAA;SAAE,EAAE,CAAA;QACzB,KAAK,EAAE,MAAM,CAAA;QACb,IAAI,EAAE,MAAM,EAAE,CAAA;QACd,gBAAgB,EAAE,OAAO,CAAA;QACzB,WAAW,EAAE,CACX,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,cAAc,CAAC,EACvC,OAAO,EAAE,gBAAgB,CAAC,SAAS,CAAC,KACjC,IAAI,CAAA;KACV,CAAA;IACD,SAAS,EAAE,OAAO,CAAA;IAClB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,eAAe,CAAC,EAAE,MAAM,IAAI,CAAA;CAC7B,CAAA;AAqFD,QAAA,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CA2J3C,CAAA;AAED,OAAO,EAAE,WAAW,EAAE,CAAA"}
@@ -3,38 +3,130 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { Badge } from "../../components/ui/badge";
4
4
  import { Button } from "../../components/ui/button";
5
5
  import { Text } from "../../components/ui/text";
6
+ import * as React from "react";
6
7
  import { Price } from "../../components/ui/price";
7
- import { Icon } from "../../components/ui/icon";
8
8
  import { Skeleton } from "../../components/ui/skeleton";
9
- const positionClasses = {
10
- topLeft: "absolute top-0 left-0 mt-2",
11
- topRight: "absolute top-0 right-0 mt-2",
12
- bottomLeft: "absolute bottom-0 left-0 mb-2",
13
- bottomRight: "absolute bottom-0 right-0 mb-2",
14
- };
15
- var BadgeAlignment;
16
- (function (BadgeAlignment) {
17
- BadgeAlignment["Left"] = "left";
18
- BadgeAlignment["Right"] = "right";
19
- BadgeAlignment["FullWidth"] = "full-width";
20
- })(BadgeAlignment || (BadgeAlignment = {}));
21
- const badgeAlignmentClasses = {
22
- topLeft: BadgeAlignment.Left,
23
- topRight: BadgeAlignment.Right,
24
- bottomLeft: BadgeAlignment.Left,
25
- bottomRight: BadgeAlignment.Right,
26
- };
27
- const ProductCard = ({ product, scaling, className, badge, icon, quickAdd, openProduct, isQuickAddProductEnabled, isLoading, }) => {
28
- const { variants: [variant], images: [{ src }], title } = product;
29
- const badgePosition = (badge === null || badge === void 0 ? void 0 : badge.position) || "topRight";
30
- const iconPosition = (icon === null || icon === void 0 ? void 0 : icon.position) || "bottomRight";
31
- const scalingClass = scaling === "fit" ? "object-contain" : "object-cover";
9
+ import { Favorite } from "../../components/ui/favorite";
10
+ import { cn } from "../../lib/utils";
11
+ import { cva } from "class-variance-authority";
12
+ const aspectScalingVariants = cva("w-full", {
13
+ variants: {
14
+ aspectRatio: {
15
+ "1:1": "aspect-square",
16
+ "2:3": "aspect-[2/3]",
17
+ "4:5": "aspect-[4/5]",
18
+ },
19
+ scaling: {
20
+ fill: "object-cover",
21
+ fit: "object-contain",
22
+ },
23
+ },
24
+ defaultVariants: {
25
+ aspectRatio: "2:3",
26
+ scaling: "fill",
27
+ },
28
+ });
29
+ const badgeVariants = cva("absolute", {
30
+ variants: {
31
+ horizontalPosition: {
32
+ left: "left-0",
33
+ right: "right-0",
34
+ "full-width": "",
35
+ },
36
+ verticalPosition: {
37
+ top: "top-0 mt-2",
38
+ bottom: "bottom-0 mb-2",
39
+ },
40
+ },
41
+ });
42
+ const favoriteVariants = cva("absolute ", {
43
+ variants: {
44
+ iconPosition: {
45
+ topLeft: "top-0 left-2 mt-2",
46
+ topRight: "top-0 right-2 mt-2",
47
+ bottomLeft: "bottom-0 left-2 mb-2",
48
+ bottomRight: "bottom-0 right-2 mb-2",
49
+ default: "",
50
+ },
51
+ badgeHorizontalPosition: {
52
+ left: "",
53
+ right: "",
54
+ "full-width": "",
55
+ },
56
+ badgeVerticalPosition: {
57
+ top: "",
58
+ bottom: "",
59
+ below: "",
60
+ },
61
+ },
62
+ compoundVariants: [
63
+ {
64
+ iconPosition: "topLeft",
65
+ badgeHorizontalPosition: ["left", "full-width"],
66
+ badgeVerticalPosition: "top",
67
+ class: "top-10",
68
+ },
69
+ {
70
+ iconPosition: "topRight",
71
+ badgeHorizontalPosition: ["right", "full-width"],
72
+ badgeVerticalPosition: "top",
73
+ class: "top-10",
74
+ },
75
+ {
76
+ iconPosition: "bottomLeft",
77
+ badgeHorizontalPosition: ["left", "full-width"],
78
+ badgeVerticalPosition: "bottom",
79
+ class: "bottom-10",
80
+ },
81
+ {
82
+ iconPosition: "bottomRight",
83
+ badgeHorizontalPosition: ["right", "full-width"],
84
+ badgeVerticalPosition: "bottom",
85
+ class: "bottom-10",
86
+ },
87
+ ],
88
+ defaultVariants: {
89
+ iconPosition: "default",
90
+ },
91
+ });
92
+ const ProductCard = ({ config, product, isLoading, favorited, onFavoriteClick, }) => {
93
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
94
+ const { variants: [variant], images: [{ url }], title, tags, } = product;
95
+ const [isSelected, setIsSelected] = React.useState(false);
96
+ const handleFavoriteClick = () => {
97
+ setIsSelected((prevState) => !prevState);
98
+ };
99
+ const iconPosition = ((_a = config.favoritesIcon) === null || _a === void 0 ? void 0 : _a.layoutType) || "default";
32
100
  if (isLoading) {
33
- return (_jsxs("div", Object.assign({ className: "w-1/2" }, { children: [_jsx(Skeleton, { className: "w-full h-64" }, void 0), _jsx(Skeleton, { className: "h-6 w-1/2 mt-2" }, void 0), _jsx(Skeleton, { className: "h-6 w-3/4 mt-2" }, void 0)] }), void 0));
101
+ return (_jsxs("div", Object.assign({ className: "w-1/2 rounded" }, { children: [_jsx(Skeleton, { className: "w-full h-64 rounded" }, void 0), _jsx(Skeleton, { className: "h-6 w-1/2 mt-2 rounded" }, void 0), _jsx(Skeleton, { className: "h-4 w-full mt-2 rounded" }, void 0)] }), void 0));
34
102
  }
35
- return (_jsxs("div", Object.assign({ className: "w-1/2" }, { children: [_jsxs("div", Object.assign({ className: "relative" }, { children: [_jsx("img", { className: `w-full h-full ${scalingClass} ${isQuickAddProductEnabled ? "rounded-t-lg rounded-b-none" : "rounded-lg"}`, src: src }, void 0), badge && (_jsx(Badge, Object.assign({ size: "plp-layout", icon: "currency-dollar", className: positionClasses[badgePosition], alignment: badgeAlignmentClasses[badgePosition] }, { children: badge.text }), void 0)), icon && (_jsx(Icon, { name: "HeartFilled", className: positionClasses[iconPosition], color: "stateColors-favorites" }, void 0))] }), void 0), isQuickAddProductEnabled && (_jsx(Button, Object.assign({ variant: "quickadd", size: "sm", onClick: (e) => {
36
- e.stopPropagation();
37
- quickAdd(e, product);
38
- } }, { children: "+ Quick add" }), void 0)), _jsx(Price, { price: variant.price, isSale: !!variant.compare_at_price, compareAtPrice: variant.compare_at_price, currency: "USD", locale: "en-US" }, void 0), _jsx(Text, Object.assign({ className: "text-textColors-productTitle" }, { children: title }), void 0)] }), void 0));
103
+ return (_jsx("div", { children: _jsxs("div", { children: [((_b = config.productImage) === null || _b === void 0 ? void 0 : _b.enabled) && (_jsxs("div", Object.assign({ className: "relative w-full overflow-hidden", style: {
104
+ borderTopLeftRadius: `${config.productImage.cornerRadius}px`,
105
+ borderTopRightRadius: `${config.productImage.cornerRadius}px`,
106
+ } }, { children: [_jsx("img", { className: cn(aspectScalingVariants({
107
+ aspectRatio: (_c = config.productImage) === null || _c === void 0 ? void 0 : _c.aspectRatio,
108
+ scaling: config.productImage.scaling,
109
+ })), src: url, onClick: (e) => product.openProduct(e, product) }, void 0), config.badge &&
110
+ tags.includes(config.badge.text) &&
111
+ config.badge.verticalPosition !== "below" && (_jsx(Badge, Object.assign({ size: "plp-layout", className: cn(badgeVariants({
112
+ verticalPosition: config.badge.verticalPosition,
113
+ horizontalPosition: config.badge.horizontalPosition,
114
+ })), alignment: config.badge.horizontalPosition, icon: config.badge.icon }, { children: config.badge.text }), void 0)), ((_d = config.favoritesIcon) === null || _d === void 0 ? void 0 : _d.enabled) && iconPosition !== "default" && (_jsx(Favorite, { className: cn(favoriteVariants({
115
+ iconPosition,
116
+ badgeHorizontalPosition: (_e = config === null || config === void 0 ? void 0 : config.badge) === null || _e === void 0 ? void 0 : _e.horizontalPosition,
117
+ badgeVerticalPosition: (_f = config === null || config === void 0 ? void 0 : config.badge) === null || _f === void 0 ? void 0 : _f.verticalPosition,
118
+ })), selected: favorited, onClick: onFavoriteClick || handleFavoriteClick }, void 0))] }), void 0)), ((_g = config.quickAdd) === null || _g === void 0 ? void 0 : _g.enabled) && (_jsx(Button, Object.assign({ className: "outline-0", style: {
119
+ borderBottomLeftRadius: `${config.quickAdd.cornerRadius}px`,
120
+ borderBottomRightRadius: `${config.quickAdd.cornerRadius}px`,
121
+ }, variant: "quickadd", size: "default", onClick: (e) => {
122
+ var _a;
123
+ e.stopPropagation();
124
+ (_a = config.quickAdd) === null || _a === void 0 ? void 0 : _a.quickAdd(e, product);
125
+ } }, { children: "+ Quick add" }), void 0)), _jsxs("div", Object.assign({ className: "mt-2 w-full flex-col justify-start items-start gap-1 inline-flex" }, { children: [config.badge &&
126
+ tags.includes(config.badge.text) &&
127
+ config.badge.verticalPosition === "below" && (_jsx("div", Object.assign({ className: `w-full flex ${config.badge.horizontalPosition === "right"
128
+ ? "justify-end"
129
+ : "justify-start"}` }, { children: _jsx(Badge, Object.assign({ size: "plp-layout", alignment: config.badge.horizontalPosition, icon: config.badge.icon, className: "rounded" }, { children: config.badge.text }), void 0) }), void 0)), _jsxs("div", Object.assign({ className: "flex w-full justify-between items-center gap-2" }, { children: [((_h = config.price) === null || _h === void 0 ? void 0 : _h.enabled) && (_jsx(Price, { price: variant.price, isSale: !!variant.compare_at_price, compareAtPrice: variant.compare_at_price, currency: config.price.currency, locale: config.price.locale }, void 0)), _jsx("div", Object.assign({ className: "w-8 h-8 flex items-center justify-center" }, { children: ((_j = config.favoritesIcon) === null || _j === void 0 ? void 0 : _j.enabled) &&
130
+ config.favoritesIcon.layoutType === "default" && (_jsx(Favorite, { selected: isSelected, onClick: handleFavoriteClick, size: "small" }, void 0)) }), void 0)] }), void 0), ((_k = config.productTitle) === null || _k === void 0 ? void 0 : _k.enabled) && (_jsx("div", { children: _jsx(Text, Object.assign({ type: "body-secondary", className: "text-textColors-productTitle" }, { children: title }), void 0) }, void 0))] }), void 0)] }, void 0) }, void 0));
39
131
  };
40
132
  export { ProductCard };
@@ -0,0 +1,14 @@
1
+ declare type Product = any;
2
+ interface PageData {
3
+ products: Product[];
4
+ cursorBlob?: string;
5
+ }
6
+ interface ProductGridItemsProps {
7
+ initialData: PageData[];
8
+ loadMoreProducts: (params: any) => Promise<PageData>;
9
+ queryVariables: Record<string, any>;
10
+ config: Record<string, any>;
11
+ }
12
+ declare function ProductGrid({ loadMoreProducts, initialData, queryVariables, config, }: ProductGridItemsProps): import("react/jsx-runtime").JSX.Element;
13
+ export { ProductGrid };
14
+ //# sourceMappingURL=product-grid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"product-grid.d.ts","sourceRoot":"","sources":["../../../components/ui/product-grid.tsx"],"names":[],"mappings":"AAkBA,aAAK,OAAO,GAAG,GAAG,CAAA;AAClB,UAAU,QAAQ;IAChB,QAAQ,EAAE,OAAO,EAAE,CAAA;IACnB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,UAAU,qBAAqB;IAC7B,WAAW,EAAE,QAAQ,EAAE,CAAA;IACvB,gBAAgB,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAA;IACpD,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACnC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;CAC5B;AAED,iBAAS,WAAW,CAAC,EACnB,gBAAgB,EAChB,WAAW,EACX,cAAc,EACd,MAAM,GACP,EAAE,qBAAqB,2CAmCvB;AAED,OAAO,EAAE,WAAW,EAAE,CAAA"}
@@ -0,0 +1,22 @@
1
+ "use client";
2
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useInfiniteScroll } from "../../components/hooks/use-infinite-scroll";
4
+ import { ProductCard } from "./product-card";
5
+ const Loader = () => (_jsx("div", Object.assign({ className: "grid-cols-2 lg:grid-cols-3" }, { children: Array(4)
6
+ .fill(0)
7
+ .map((_, index) => (_jsx("div", { className: "aspect-[2/3] animate-pulse bg-neutral-100 dark:bg-neutral-900" }, index))) }), void 0));
8
+ function ProductGrid({ loadMoreProducts, initialData, queryVariables, config, }) {
9
+ const { data, error, isLoadingInitialData, isLoadingMore, isEmpty, isReachingEnd, ref, products, } = useInfiniteScroll({
10
+ initialData,
11
+ loadMoreProducts,
12
+ queryVariables,
13
+ });
14
+ if (error)
15
+ return _jsx("div", { children: "Failed to load data" }, void 0);
16
+ if (isLoadingInitialData)
17
+ return _jsx(Loader, {}, void 0);
18
+ return (_jsxs(_Fragment, { children: [_jsx("div", Object.assign({ className: "grid-cols-2 lg:grid-cols-3" }, { children: products.map((product, i) => (_jsx(ProductCard, {
19
+ // @ts-ignore
20
+ product: product, config: config, isLoading: false }, product.handle))) }), void 0), isLoadingMore ? _jsx(Loader, {}, void 0) : _jsx("div", { ref: ref }, void 0)] }, void 0));
21
+ }
22
+ export { ProductGrid };
package/dist/index.d.ts CHANGED
@@ -30,5 +30,7 @@ export * from "./components/ui/price";
30
30
  export * from "./components/ui/favorite";
31
31
  export * from "./components/ui/wishlist";
32
32
  export * from "./components/ui/product-card";
33
+ export * from "./components/ui/product-grid";
34
+ export * from "./components/hooks/use-infinite-scroll";
33
35
  export { cn, cva } from "./lib/utils";
34
36
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AACA,cAAc,wBAAwB,CAAA;AACtC,cAAc,uBAAuB,CAAA;AACrC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,2BAA2B,CAAA;AACzC,cAAc,sBAAsB,CAAA;AACpC,cAAc,0BAA0B,CAAA;AACxC,cAAc,0BAA0B,CAAA;AACxC,cAAc,2BAA2B,CAAA;AACzC,cAAc,sBAAsB,CAAA;AACpC,cAAc,uBAAuB,CAAA;AACrC,cAAc,2BAA2B,CAAA;AACzC,cAAc,uBAAuB,CAAA;AACrC,cAAc,uBAAuB,CAAA;AACrC,cAAc,uBAAuB,CAAA;AACrC,cAAc,0BAA0B,CAAA;AACxC,cAAc,sBAAsB,CAAA;AACpC,cAAc,wBAAwB,CAAA;AACtC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,wBAAwB,CAAA;AACtC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,2BAA2B,CAAA;AACzC,cAAc,uBAAuB,CAAA;AACrC,cAAc,yBAAyB,CAAA;AACvC,cAAc,sBAAsB,CAAA;AACpC,cAAc,2BAA2B,CAAA;AACzC,cAAc,wBAAwB,CAAA;AACtC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,sBAAsB,CAAA;AACpC,cAAc,uBAAuB,CAAA;AACrC,cAAc,0BAA0B,CAAA;AACxC,cAAc,0BAA0B,CAAA;AACxC,cAAc,8BAA8B,CAAA;AAC5C,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,aAAa,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AACA,cAAc,wBAAwB,CAAA;AACtC,cAAc,uBAAuB,CAAA;AACrC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,2BAA2B,CAAA;AACzC,cAAc,sBAAsB,CAAA;AACpC,cAAc,0BAA0B,CAAA;AACxC,cAAc,0BAA0B,CAAA;AACxC,cAAc,2BAA2B,CAAA;AACzC,cAAc,sBAAsB,CAAA;AACpC,cAAc,uBAAuB,CAAA;AACrC,cAAc,2BAA2B,CAAA;AACzC,cAAc,uBAAuB,CAAA;AACrC,cAAc,uBAAuB,CAAA;AACrC,cAAc,uBAAuB,CAAA;AACrC,cAAc,0BAA0B,CAAA;AACxC,cAAc,sBAAsB,CAAA;AACpC,cAAc,wBAAwB,CAAA;AACtC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,wBAAwB,CAAA;AACtC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,2BAA2B,CAAA;AACzC,cAAc,uBAAuB,CAAA;AACrC,cAAc,yBAAyB,CAAA;AACvC,cAAc,sBAAsB,CAAA;AACpC,cAAc,2BAA2B,CAAA;AACzC,cAAc,wBAAwB,CAAA;AACtC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,sBAAsB,CAAA;AACpC,cAAc,uBAAuB,CAAA;AACrC,cAAc,0BAA0B,CAAA;AACxC,cAAc,0BAA0B,CAAA;AACxC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,8BAA8B,CAAA;AAC5C,cAAc,wCAAwC,CAAA;AACtD,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,aAAa,CAAA"}
package/dist/index.js CHANGED
@@ -31,4 +31,6 @@ export * from "./components/ui/price";
31
31
  export * from "./components/ui/favorite";
32
32
  export * from "./components/ui/wishlist";
33
33
  export * from "./components/ui/product-card";
34
+ export * from "./components/ui/product-grid";
35
+ export * from "./components/hooks/use-infinite-scroll";
34
36
  export { cn, cva } from "./lib/utils";
package/dist/styles.css CHANGED
@@ -667,6 +667,9 @@ video {
667
667
  .bottom-0 {
668
668
  bottom: 0px;
669
669
  }
670
+ .bottom-10 {
671
+ bottom: 2.5rem;
672
+ }
670
673
  .end-4 {
671
674
  inset-inline-end: 1rem;
672
675
  }
@@ -676,6 +679,9 @@ video {
676
679
  .left-1\/2 {
677
680
  left: 50%;
678
681
  }
682
+ .left-2 {
683
+ left: 0.5rem;
684
+ }
679
685
  .left-\[50\%\] {
680
686
  left: 50%;
681
687
  }
@@ -694,6 +700,9 @@ video {
694
700
  .top-1\/2 {
695
701
  top: 50%;
696
702
  }
703
+ .top-10 {
704
+ top: 2.5rem;
705
+ }
697
706
  .top-2 {
698
707
  top: 0.5rem;
699
708
  }
@@ -779,6 +788,12 @@ video {
779
788
  .grid {
780
789
  display: grid;
781
790
  }
791
+ .aspect-\[2\/3\] {
792
+ aspect-ratio: 2/3;
793
+ }
794
+ .aspect-\[4\/5\] {
795
+ aspect-ratio: 4/5;
796
+ }
782
797
  .aspect-square {
783
798
  aspect-ratio: 1 / 1;
784
799
  }
@@ -857,9 +872,6 @@ video {
857
872
  .w-2\.5 {
858
873
  width: 0.625rem;
859
874
  }
860
- .w-3\/4 {
861
- width: 75%;
862
- }
863
875
  .w-4 {
864
876
  width: 1rem;
865
877
  }
@@ -997,6 +1009,12 @@ video {
997
1009
  .items-center {
998
1010
  align-items: center;
999
1011
  }
1012
+ .justify-start {
1013
+ justify-content: flex-start;
1014
+ }
1015
+ .justify-end {
1016
+ justify-content: flex-end;
1017
+ }
1000
1018
  .justify-center {
1001
1019
  justify-content: center;
1002
1020
  }
@@ -1067,9 +1085,6 @@ video {
1067
1085
  .rounded-full {
1068
1086
  border-radius: 9999px;
1069
1087
  }
1070
- .rounded-lg {
1071
- border-radius: var(--radius);
1072
- }
1073
1088
  .rounded-md {
1074
1089
  border-radius: calc(var(--radius) - 2px);
1075
1090
  }
@@ -1083,18 +1098,10 @@ video {
1083
1098
  border-bottom-right-radius: var(--radius);
1084
1099
  border-bottom-left-radius: var(--radius);
1085
1100
  }
1086
- .rounded-b-none {
1087
- border-bottom-right-radius: 0px;
1088
- border-bottom-left-radius: 0px;
1089
- }
1090
1101
  .rounded-t-2xl {
1091
1102
  border-top-left-radius: 1rem;
1092
1103
  border-top-right-radius: 1rem;
1093
1104
  }
1094
- .rounded-t-lg {
1095
- border-top-left-radius: var(--radius);
1096
- border-top-right-radius: var(--radius);
1097
- }
1098
1105
  .rounded-bl {
1099
1106
  border-bottom-left-radius: 0.25rem;
1100
1107
  }
@@ -1178,6 +1185,10 @@ video {
1178
1185
  .bg-coreColors-pageColor {
1179
1186
  background-color: var(--coreColors-pageColor);
1180
1187
  }
1188
+ .bg-neutral-100 {
1189
+ --tw-bg-opacity: 1;
1190
+ background-color: rgb(245 245 245 / var(--tw-bg-opacity));
1191
+ }
1181
1192
  .bg-productBadging-fill {
1182
1193
  background-color: var(--productBadging-fill);
1183
1194
  }
@@ -1361,6 +1372,9 @@ video {
1361
1372
  .font-semibold {
1362
1373
  font-weight: 600;
1363
1374
  }
1375
+ .uppercase {
1376
+ text-transform: uppercase;
1377
+ }
1364
1378
  .leading-\[130\%\] {
1365
1379
  line-height: 130%;
1366
1380
  }
@@ -1550,6 +1564,9 @@ video {
1550
1564
  .outline {
1551
1565
  outline-style: solid;
1552
1566
  }
1567
+ .outline-0 {
1568
+ outline-width: 0px;
1569
+ }
1553
1570
  .outline-1 {
1554
1571
  outline-width: 1px;
1555
1572
  }
@@ -1948,6 +1965,10 @@ video {
1948
1965
  .data-\[state\=open\]\:duration-500[data-state=open] {
1949
1966
  animation-duration: 500ms;
1950
1967
  }
1968
+ :is(.dark .dark\:bg-neutral-900) {
1969
+ --tw-bg-opacity: 1;
1970
+ background-color: rgb(23 23 23 / var(--tw-bg-opacity));
1971
+ }
1951
1972
  @media (min-width: 640px) {
1952
1973
 
1953
1974
  .sm\:mt-0 {
@@ -1976,6 +1997,12 @@ video {
1976
1997
  text-align: left;
1977
1998
  }
1978
1999
  }
2000
+ @media (min-width: 1024px) {
2001
+
2002
+ .lg\:grid-cols-3 {
2003
+ grid-template-columns: repeat(3, minmax(0, 1fr));
2004
+ }
2005
+ }
1979
2006
  .\[\&\+label\]\:text-stateColors-error+label {
1980
2007
  color: var(--stateColors-error);
1981
2008
  }
package/package.json CHANGED
@@ -1,8 +1,7 @@
1
1
  {
2
2
  "name": "@tapcart/mobile-components",
3
- "version": "0.2.7",
3
+ "version": "0.2.9",
4
4
  "main": "dist/index.js",
5
- "module": "dist/index.esm.js",
6
5
  "types": "dist/index.d.ts",
7
6
  "style": "dist/styles.css",
8
7
  "sourceMap": true,
@@ -17,13 +16,15 @@
17
16
  "ui:add": "pnpm dlx shadcn-ui@latest add",
18
17
  "build:styles": "postcss styles/globals.css -o dist/styles.css",
19
18
  "build:ts": "tsc -p tsconfig.json && tsc-alias",
20
- "build": "pnpm run build:ts && pnpm run build:styles"
19
+ "build": "pnpm run build:ts && pnpm run build:styles",
20
+ "dev": "tsc -w -p tsconfig.json"
21
21
  },
22
22
  "peerDependencies": {
23
23
  "react": "^17.0.2 || ^18.0.0",
24
24
  "react-dom": "^17.0.2 || ^18.0.0"
25
25
  },
26
26
  "devDependencies": {
27
+ "@types/lodash": "4.17.5",
27
28
  "@types/react": "^18.2.0",
28
29
  "@types/react-dom": "^18.2.0",
29
30
  "autoprefixer": "^10.4.14",
@@ -57,6 +58,8 @@
57
58
  "lucide-react": "^0.248.0",
58
59
  "next-themes": "^0.2.1",
59
60
  "postcss-cli": "^11.0.0",
61
+ "react-intersection-observer": "^9.10.2",
62
+ "swr": "^2.2.5",
60
63
  "tailwind-merge": "^1.13.2",
61
64
  "tailwindcss-animate": "^1.0.6",
62
65
  "vaul": "^0.9.1"