@tapcart/mobile-components 0.13.1 → 0.14.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.
- package/dist/components/hooks/__tests__/use-infinite-scroll-params.test.d.ts +2 -0
- package/dist/components/hooks/__tests__/use-infinite-scroll-params.test.d.ts.map +1 -0
- package/dist/components/hooks/__tests__/use-infinite-scroll-params.test.js +35 -0
- package/dist/components/hooks/use-infinite-scroll.d.ts +2 -0
- package/dist/components/hooks/use-infinite-scroll.d.ts.map +1 -1
- package/dist/components/hooks/use-infinite-scroll.js +61 -21
- package/dist/components/hooks/use-infinite-scroll.test.d.ts +2 -0
- package/dist/components/hooks/use-infinite-scroll.test.d.ts.map +1 -0
- package/dist/components/hooks/use-infinite-scroll.test.js +212 -0
- package/dist/components/ui/animate-container.d.ts.map +1 -1
- package/dist/components/ui/chip.d.ts.map +1 -1
- package/dist/components/ui/quantity-picker.d.ts.map +1 -1
- package/dist/components/ui/quantity-picker.js +1 -1
- package/dist/components/ui/quantity-pickerNEW.d.ts +0 -1
- package/dist/components/ui/quantity-pickerNEW.d.ts.map +1 -1
- package/dist/components/ui/quantity-pickerNEW.js +1 -1
- package/dist/components/ui/use-toast.d.ts.map +1 -1
- package/dist/components/ui/wishlist-select.d.ts.map +1 -1
- package/dist/lib/cart.util.d.ts.map +1 -1
- package/dist/lib/variablesCart.util.d.ts.map +1 -1
- package/dist/styles.css +13 -6
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-infinite-scroll-params.test.d.ts","sourceRoot":"","sources":["../../../../components/hooks/__tests__/use-infinite-scroll-params.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { formatSearchParamsAsNextQueryVariables, stripLayoutOnlyParams, LAYOUT_ONLY_QUERY_PARAMS, } from "../use-infinite-scroll";
|
|
2
|
+
// In API mode the formatted searchParams object is what forks the product cache
|
|
3
|
+
// key: it's hashed into the server Redis key (the by-page route does
|
|
4
|
+
// md5(JSON.stringify(body))) and serialized into the client IDB key. The
|
|
5
|
+
// layout-only `column` param must not survive into that object, or column=2 and
|
|
6
|
+
// column=3 read independent, independently-aged snapshots of the same
|
|
7
|
+
// collection (the Diamond Art Club bug).
|
|
8
|
+
const format = (qs) => stripLayoutOnlyParams(formatSearchParamsAsNextQueryVariables(new URLSearchParams(qs)));
|
|
9
|
+
describe("layout-only param stripping (column cache-key fork fix)", () => {
|
|
10
|
+
it("strips `column` but keeps the data-affecting params", () => {
|
|
11
|
+
const formatted = format("country=US&lang=EN&collectionId=463133769921&collectionHandle=diamond-painting-restocks&column=3");
|
|
12
|
+
expect(formatted).not.toHaveProperty("column");
|
|
13
|
+
expect(formatted).toEqual({
|
|
14
|
+
country: "US",
|
|
15
|
+
lang: "EN",
|
|
16
|
+
collectionId: "463133769921",
|
|
17
|
+
collectionHandle: "diamond-painting-restocks",
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
it("yields IDENTICAL cache-key input for column=2 vs column=3", () => {
|
|
21
|
+
const base = "country=US&lang=EN&collectionId=463133769921&collectionHandle=diamond-painting-restocks";
|
|
22
|
+
const col2 = format(`${base}&column=2`);
|
|
23
|
+
const col3 = format(`${base}&column=3`);
|
|
24
|
+
// Same serialization => one shared Redis + IDB entry across layout variants.
|
|
25
|
+
expect(JSON.stringify(col2)).toEqual(JSON.stringify(col3));
|
|
26
|
+
});
|
|
27
|
+
it("never strips real filter/sort params", () => {
|
|
28
|
+
const formatted = format("column=3&sort_by=best-selling&filter.p.tag=in-stock");
|
|
29
|
+
expect(formatted).toEqual({
|
|
30
|
+
sort_by: "best-selling",
|
|
31
|
+
"filter.p.tag": "in-stock",
|
|
32
|
+
});
|
|
33
|
+
expect(LAYOUT_ONLY_QUERY_PARAMS).toContain("column");
|
|
34
|
+
});
|
|
35
|
+
});
|
|
@@ -35,6 +35,8 @@ interface UseInfiniteScrollReturn {
|
|
|
35
35
|
isValidating: boolean;
|
|
36
36
|
}
|
|
37
37
|
export declare const formatSearchParamsAsNextQueryVariables: (searchParams: ReadonlyURLSearchParams) => {};
|
|
38
|
+
export declare const LAYOUT_ONLY_QUERY_PARAMS: string[];
|
|
39
|
+
export declare const stripLayoutOnlyParams: (params: Record<string, unknown>) => Record<string, unknown>;
|
|
38
40
|
declare const constructURL: (apiURL: string) => string;
|
|
39
41
|
declare const useInfiniteScroll: ({ searchClient, initialData, queryVariables: queryVariableProps, direction, productLimit, threshold, interval, customFetcher, customGetKey, shouldSkipFetch: shouldSkipFetchProp, }: UseInfiniteScrollProps) => UseInfiniteScrollReturn;
|
|
40
42
|
export { useInfiniteScroll, constructURL };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-infinite-scroll.d.ts","sourceRoot":"","sources":["../../../components/hooks/use-infinite-scroll.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,uBAAuB,EAAmB,MAAM,iBAAiB,CAAA;AAE1E,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAG5D,UAAU,QAAQ;IAChB,QAAQ,EAAE,OAAO,EAAE,CAAA;IACnB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,GAAG,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,cAAc,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,CAAA;CACxC;AAED,UAAU,sBAAsB;IAE9B,YAAY,CAAC,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAA;IAGxC,WAAW,CAAC,EAAE,QAAQ,CAAA;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAGpC,SAAS,CAAC,EAAE,UAAU,GAAG,YAAY,CAAA;IACrC,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,aAAa,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,GAAG,CAAC,CAAA;IAChD,YAAY,CAAC,EAAE,CACb,SAAS,EAAE,MAAM,EACjB,gBAAgB,EAAE,GAAG,GAAG,IAAI,EAC5B,GAAG,IAAI,EAAE,GAAG,EAAE,KACX,GAAG,CAAA;IACR,eAAe,CAAC,EAAE,OAAO,CAAA;CAC1B;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;IACnB,oBAAoB,EAAE,GAAG,EAAE,CAAA;IAC3B,SAAS,EAAE,OAAO,CAAA;IAClB,YAAY,EAAE,OAAO,CAAA;CACtB;AAED,eAAO,MAAM,sCAAsC,iBACnC,uBAAuB,OAsBtC,CAAA;AAED,QAAA,MAAM,YAAY,WAAY,MAAM,WAGnC,CAAA;AAED,QAAA,MAAM,iBAAiB,wLAgBpB,sBAAsB,KAAG,
|
|
1
|
+
{"version":3,"file":"use-infinite-scroll.d.ts","sourceRoot":"","sources":["../../../components/hooks/use-infinite-scroll.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,uBAAuB,EAAmB,MAAM,iBAAiB,CAAA;AAE1E,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAG5D,UAAU,QAAQ;IAChB,QAAQ,EAAE,OAAO,EAAE,CAAA;IACnB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,GAAG,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,cAAc,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,CAAA;CACxC;AAED,UAAU,sBAAsB;IAE9B,YAAY,CAAC,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAA;IAGxC,WAAW,CAAC,EAAE,QAAQ,CAAA;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAGpC,SAAS,CAAC,EAAE,UAAU,GAAG,YAAY,CAAA;IACrC,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,aAAa,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,GAAG,CAAC,CAAA;IAChD,YAAY,CAAC,EAAE,CACb,SAAS,EAAE,MAAM,EACjB,gBAAgB,EAAE,GAAG,GAAG,IAAI,EAC5B,GAAG,IAAI,EAAE,GAAG,EAAE,KACX,GAAG,CAAA;IACR,eAAe,CAAC,EAAE,OAAO,CAAA;CAC1B;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;IACnB,oBAAoB,EAAE,GAAG,EAAE,CAAA;IAC3B,SAAS,EAAE,OAAO,CAAA;IAClB,YAAY,EAAE,OAAO,CAAA;CACtB;AAED,eAAO,MAAM,sCAAsC,iBACnC,uBAAuB,OAsBtC,CAAA;AAWD,eAAO,MAAM,wBAAwB,UAAa,CAAA;AAIlD,eAAO,MAAM,qBAAqB,WACxB,OAAO,MAAM,EAAE,OAAO,CAAC,KAC9B,OAAO,MAAM,EAAE,OAAO,CAMxB,CAAA;AAED,QAAA,MAAM,YAAY,WAAY,MAAM,WAGnC,CAAA;AAED,QAAA,MAAM,iBAAiB,wLAgBpB,sBAAsB,KAAG,uBA8V3B,CAAA;AAED,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,CAAA"}
|
|
@@ -38,6 +38,25 @@ export const formatSearchParamsAsNextQueryVariables = (searchParams) => {
|
|
|
38
38
|
});
|
|
39
39
|
return formattedParams;
|
|
40
40
|
};
|
|
41
|
+
// URL params that only affect how the grid is laid out, never which products a
|
|
42
|
+
// collection/search returns. They MUST NOT enter the product cache key: in API
|
|
43
|
+
// mode this `searchParams` object is hashed into the server Redis key (the
|
|
44
|
+
// by-page route does `md5(JSON.stringify(body))`) and serialized into the
|
|
45
|
+
// client IDB cache key. Leaving `column` in meant column=2 and column=3 forked
|
|
46
|
+
// into two independent cache entries, each holding a snapshot of the same
|
|
47
|
+
// collection taken at a different time — so switching the column view could
|
|
48
|
+
// surface different (and independently-aged) products. Stripping them collapses
|
|
49
|
+
// every layout variant onto one shared cache entry.
|
|
50
|
+
export const LAYOUT_ONLY_QUERY_PARAMS = ["column"];
|
|
51
|
+
// Returns a copy of `params` with the layout-only keys removed (never mutates
|
|
52
|
+
// the input).
|
|
53
|
+
export const stripLayoutOnlyParams = (params) => {
|
|
54
|
+
const result = Object.assign({}, params);
|
|
55
|
+
for (const param of LAYOUT_ONLY_QUERY_PARAMS) {
|
|
56
|
+
delete result[param];
|
|
57
|
+
}
|
|
58
|
+
return result;
|
|
59
|
+
};
|
|
41
60
|
const constructURL = (apiURL) => {
|
|
42
61
|
const url = new URL(apiURL);
|
|
43
62
|
return url.toString();
|
|
@@ -52,7 +71,6 @@ direction = "vertical", productLimit = Infinity, threshold = 0.01, interval = 33
|
|
|
52
71
|
customFetcher, customGetKey, shouldSkipFetch: shouldSkipFetchProp, }) => {
|
|
53
72
|
var _a, _b, _c, _d, _e, _f;
|
|
54
73
|
const searchParams = useSearchParams();
|
|
55
|
-
const productCount = useRef(0);
|
|
56
74
|
const isFirstRender = useRef(true);
|
|
57
75
|
const prevParamsRef = useRef({
|
|
58
76
|
collectionId: null,
|
|
@@ -90,7 +108,7 @@ customFetcher, customGetKey, shouldSkipFetch: shouldSkipFetchProp, }) => {
|
|
|
90
108
|
const queryVariables = useMemo(() => {
|
|
91
109
|
if (usingSearchClient)
|
|
92
110
|
return null;
|
|
93
|
-
const formattedParams = formatSearchParamsAsNextQueryVariables(searchParams);
|
|
111
|
+
const formattedParams = stripLayoutOnlyParams(formatSearchParamsAsNextQueryVariables(searchParams));
|
|
94
112
|
return Object.assign(Object.assign({}, queryVariableProps), { searchParams: formattedParams });
|
|
95
113
|
}, [queryVariableProps, searchParams, usingSearchClient]);
|
|
96
114
|
const apiGetKey = (pageIndex, previousPageData, queryVariables) => {
|
|
@@ -103,7 +121,6 @@ customFetcher, customGetKey, shouldSkipFetch: shouldSkipFetchProp, }) => {
|
|
|
103
121
|
return Object.assign(Object.assign({}, queryVariables), { cursorBlob: previousPageData.pageData.cursorBlob });
|
|
104
122
|
};
|
|
105
123
|
const apiFetcher = (body) => __awaiter(void 0, void 0, void 0, function* () {
|
|
106
|
-
var _g, _h;
|
|
107
124
|
if (!(initialData === null || initialData === void 0 ? void 0 : initialData.apiURL)) {
|
|
108
125
|
throw new Error("initialData.apiURL is required for API mode");
|
|
109
126
|
}
|
|
@@ -112,7 +129,6 @@ customFetcher, customGetKey, shouldSkipFetch: shouldSkipFetchProp, }) => {
|
|
|
112
129
|
body: JSON.stringify(body),
|
|
113
130
|
});
|
|
114
131
|
const data = yield res.json();
|
|
115
|
-
productCount.current += (_h = (_g = data === null || data === void 0 ? void 0 : data.products) === null || _g === void 0 ? void 0 : _g.length) !== null && _h !== void 0 ? _h : 0;
|
|
116
132
|
return data;
|
|
117
133
|
});
|
|
118
134
|
// Return null from getKey to conditionally skip fetching
|
|
@@ -135,18 +151,14 @@ customFetcher, customGetKey, shouldSkipFetch: shouldSkipFetchProp, }) => {
|
|
|
135
151
|
};
|
|
136
152
|
const fetcher = usingSearchClient
|
|
137
153
|
? (...args) => __awaiter(void 0, void 0, void 0, function* () {
|
|
138
|
-
var _j, _k;
|
|
139
154
|
if (!searchClientFetcher)
|
|
140
155
|
return null;
|
|
141
156
|
const result = yield searchClientFetcher(...args);
|
|
142
|
-
productCount.current += (_k = (_j = result === null || result === void 0 ? void 0 : result.products) === null || _j === void 0 ? void 0 : _j.length) !== null && _k !== void 0 ? _k : 0;
|
|
143
157
|
return result;
|
|
144
158
|
})
|
|
145
159
|
: (...args) => __awaiter(void 0, void 0, void 0, function* () {
|
|
146
|
-
var _l, _m;
|
|
147
160
|
if (customFetcher) {
|
|
148
161
|
const result = yield customFetcher(...args);
|
|
149
|
-
productCount.current += (_m = (_l = result === null || result === void 0 ? void 0 : result.products) === null || _l === void 0 ? void 0 : _l.length) !== null && _m !== void 0 ? _m : 0;
|
|
150
162
|
return result;
|
|
151
163
|
}
|
|
152
164
|
return apiFetcher(args[0]);
|
|
@@ -184,7 +196,6 @@ customFetcher, customGetKey, shouldSkipFetch: shouldSkipFetchProp, }) => {
|
|
|
184
196
|
};
|
|
185
197
|
// Skip reset on first render, but force it for any subsequent transitions to valid params
|
|
186
198
|
if (!isFirstRender.current && hasValidCurrentParams) {
|
|
187
|
-
productCount.current = 0;
|
|
188
199
|
mutate();
|
|
189
200
|
}
|
|
190
201
|
}
|
|
@@ -222,10 +233,49 @@ customFetcher, customGetKey, shouldSkipFetch: shouldSkipFetchProp, }) => {
|
|
|
222
233
|
}
|
|
223
234
|
const isReachingEnd = isEmpty || isEndPointer;
|
|
224
235
|
const isRefreshing = isValidating && data && data.length === size;
|
|
236
|
+
// Flatten the SWR Infinite pages into the rendered list, deduped by product id
|
|
237
|
+
// (handle fallback). Cursor/page pagination over a volatile, mutable-sort
|
|
238
|
+
// result set — Shopify relevance/best-selling search, reorderable collections —
|
|
239
|
+
// re-serves boundary products on the following page, so consecutive pages
|
|
240
|
+
// overlap; without this dedupe the same product renders twice (seen on Edikted
|
|
241
|
+
// search). Keep the FIRST occurrence so the original ranked position wins, and
|
|
242
|
+
// dedupe BEFORE the productLimit slice so a finite limit (carousels) yields N
|
|
243
|
+
// UNIQUE products. Two rows sharing a product id always resolve to the same
|
|
244
|
+
// product-level card (the search-client pipeline resolves every row via
|
|
245
|
+
// getProduct(id|handle) and discards per-hit variant context), so this can
|
|
246
|
+
// never collapse a legitimately-distinct variant card.
|
|
247
|
+
const products = useMemo(() => {
|
|
248
|
+
var _a;
|
|
249
|
+
const flat = data
|
|
250
|
+
? data.flatMap((page) => { var _a; return (_a = page === null || page === void 0 ? void 0 : page.products) !== null && _a !== void 0 ? _a : []; })
|
|
251
|
+
: hasInitialProducts
|
|
252
|
+
? initialData.products
|
|
253
|
+
: [];
|
|
254
|
+
const seen = new Set();
|
|
255
|
+
const deduped = [];
|
|
256
|
+
for (const product of flat) {
|
|
257
|
+
if (!product)
|
|
258
|
+
continue;
|
|
259
|
+
const key = (_a = product.id) !== null && _a !== void 0 ? _a : product.handle;
|
|
260
|
+
if (key == null) {
|
|
261
|
+
deduped.push(product);
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
if (seen.has(key))
|
|
265
|
+
continue;
|
|
266
|
+
seen.add(key);
|
|
267
|
+
deduped.push(product);
|
|
268
|
+
}
|
|
269
|
+
return deduped.slice(0, productLimit);
|
|
270
|
+
}, [data, productLimit, hasInitialProducts, initialData === null || initialData === void 0 ? void 0 : initialData.products]);
|
|
225
271
|
const loadMore = useCallback(() => {
|
|
226
272
|
if (isLoading || isLoadingMore || isReachingEnd || isRefreshing)
|
|
227
273
|
return;
|
|
228
|
-
|
|
274
|
+
// Gate on the deduped, limit-sliced `products` count. Counting raw fetched
|
|
275
|
+
// products would include the page-seam duplicates the memo above removes, so
|
|
276
|
+
// a finite productLimit could look "reached" while fewer than productLimit
|
|
277
|
+
// unique products have actually loaded — under-filling the carousel.
|
|
278
|
+
if (products.length >= productLimit)
|
|
229
279
|
return;
|
|
230
280
|
setSize(size + 1);
|
|
231
281
|
}, [
|
|
@@ -233,6 +283,7 @@ customFetcher, customGetKey, shouldSkipFetch: shouldSkipFetchProp, }) => {
|
|
|
233
283
|
isLoadingMore,
|
|
234
284
|
isReachingEnd,
|
|
235
285
|
isRefreshing,
|
|
286
|
+
products.length,
|
|
236
287
|
productLimit,
|
|
237
288
|
setSize,
|
|
238
289
|
size,
|
|
@@ -248,21 +299,10 @@ customFetcher, customGetKey, shouldSkipFetch: shouldSkipFetchProp, }) => {
|
|
|
248
299
|
if (!usingSearchClient || !searchClient)
|
|
249
300
|
return;
|
|
250
301
|
const unsubscribeAllChanges = searchClient.onSearchStateChange(() => {
|
|
251
|
-
productCount.current = 0;
|
|
252
302
|
mutate();
|
|
253
303
|
});
|
|
254
304
|
return unsubscribeAllChanges;
|
|
255
305
|
}, [searchClient, mutate, usingSearchClient]);
|
|
256
|
-
const products = useMemo(() => {
|
|
257
|
-
if (data) {
|
|
258
|
-
return data.flatMap((page) => page === null || page === void 0 ? void 0 : page.products).slice(0, productLimit);
|
|
259
|
-
}
|
|
260
|
-
// Use pre-fetched products while SWR fetches the real paginated data
|
|
261
|
-
if (hasInitialProducts) {
|
|
262
|
-
return initialData.products;
|
|
263
|
-
}
|
|
264
|
-
return [];
|
|
265
|
-
}, [data, productLimit, hasInitialProducts, initialData === null || initialData === void 0 ? void 0 : initialData.products]);
|
|
266
306
|
// Collect all integration responses per page when using search client
|
|
267
307
|
const integrationResponses = useMemo(() => {
|
|
268
308
|
if (!usingSearchClient)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-infinite-scroll.test.d.ts","sourceRoot":"","sources":["../../../components/hooks/use-infinite-scroll.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { renderHook } from "@testing-library/react";
|
|
2
|
+
// ─── Module mocks ────────────────────────────────────────────────────────────
|
|
3
|
+
// useSWRInfinite is the source of `data` (the array of fetched pages). We mock
|
|
4
|
+
// it so each test can hand the hook an exact set of (possibly overlapping)
|
|
5
|
+
// pages and assert how they are flattened/deduped into `products`.
|
|
6
|
+
jest.mock("swr/infinite", () => ({
|
|
7
|
+
__esModule: true,
|
|
8
|
+
default: jest.fn(),
|
|
9
|
+
}));
|
|
10
|
+
jest.mock("react-intersection-observer", () => ({
|
|
11
|
+
useInView: jest.fn(() => ({ ref: jest.fn(), inView: false })),
|
|
12
|
+
}));
|
|
13
|
+
jest.mock("next/navigation", () => ({
|
|
14
|
+
useSearchParams: () => new URLSearchParams(),
|
|
15
|
+
}));
|
|
16
|
+
jest.mock("./swr-retry", () => ({
|
|
17
|
+
useSwrRetryConfig: () => ({
|
|
18
|
+
errorRetryCount: 0,
|
|
19
|
+
shouldRetryOnError: false,
|
|
20
|
+
onErrorRetry: jest.fn(),
|
|
21
|
+
onSuccess: jest.fn(),
|
|
22
|
+
isRetrying: false,
|
|
23
|
+
}),
|
|
24
|
+
}));
|
|
25
|
+
// ─── Imports after mocks ─────────────────────────────────────────────────────
|
|
26
|
+
import useSWRInfinite from "swr/infinite";
|
|
27
|
+
import { useInView } from "react-intersection-observer";
|
|
28
|
+
import { useInfiniteScroll } from "./use-infinite-scroll";
|
|
29
|
+
const mockUseSWRInfinite = useSWRInfinite;
|
|
30
|
+
const mockUseInView = useInView;
|
|
31
|
+
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
32
|
+
const setPages = (pages) => {
|
|
33
|
+
var _a;
|
|
34
|
+
mockUseSWRInfinite.mockReturnValue({
|
|
35
|
+
data: pages,
|
|
36
|
+
error: undefined,
|
|
37
|
+
size: (_a = pages === null || pages === void 0 ? void 0 : pages.length) !== null && _a !== void 0 ? _a : 0,
|
|
38
|
+
setSize: jest.fn(),
|
|
39
|
+
isLoading: false,
|
|
40
|
+
isValidating: false,
|
|
41
|
+
mutate: jest.fn(),
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
const page = (products, hasMore = true) => ({
|
|
45
|
+
products,
|
|
46
|
+
hasMore,
|
|
47
|
+
filtersData: null,
|
|
48
|
+
apiURL: "https://example.com/api",
|
|
49
|
+
});
|
|
50
|
+
const renderProducts = (props = {}) => renderHook(() => useInfiniteScroll(Object.assign({
|
|
51
|
+
// Force fetching on so `products` is returned (not the skip-override).
|
|
52
|
+
shouldSkipFetch: false, initialData: {
|
|
53
|
+
apiURL: "https://example.com/api",
|
|
54
|
+
products: [],
|
|
55
|
+
filtersData: null,
|
|
56
|
+
}, queryVariables: { collectionId: "c1" } }, props))).result.current.products;
|
|
57
|
+
// ─── Tests ───────────────────────────────────────────────────────────────────
|
|
58
|
+
describe("useInfiniteScroll – page flatten & dedupe", () => {
|
|
59
|
+
beforeEach(() => {
|
|
60
|
+
mockUseSWRInfinite.mockReset();
|
|
61
|
+
});
|
|
62
|
+
it("removes products re-served at page seams, keeping first occurrence", () => {
|
|
63
|
+
// page 1 ends with id 3; page 2 re-serves 3 at its head (the cursor race);
|
|
64
|
+
// page 3 re-serves 5. Expected: 1..6 once each, in first-seen order.
|
|
65
|
+
setPages([
|
|
66
|
+
page([{ id: "1" }, { id: "2" }, { id: "3" }]),
|
|
67
|
+
page([{ id: "3" }, { id: "4" }, { id: "5" }]),
|
|
68
|
+
page([{ id: "5" }, { id: "6" }], false),
|
|
69
|
+
]);
|
|
70
|
+
expect(renderProducts().map((p) => p.id)).toEqual([
|
|
71
|
+
"1",
|
|
72
|
+
"2",
|
|
73
|
+
"3",
|
|
74
|
+
"4",
|
|
75
|
+
"5",
|
|
76
|
+
"6",
|
|
77
|
+
]);
|
|
78
|
+
});
|
|
79
|
+
it("dedupes BEFORE applying productLimit (limit counts unique products)", () => {
|
|
80
|
+
setPages([
|
|
81
|
+
page([{ id: "1" }, { id: "2" }, { id: "3" }]),
|
|
82
|
+
page([{ id: "3" }, { id: "4" }, { id: "5" }]),
|
|
83
|
+
]);
|
|
84
|
+
// If the slice ran before dedupe we'd get ["1","2","3","3"]; dedupe-first
|
|
85
|
+
// yields four UNIQUE products.
|
|
86
|
+
expect(renderProducts({ productLimit: 4 }).map((p) => p.id)).toEqual([
|
|
87
|
+
"1",
|
|
88
|
+
"2",
|
|
89
|
+
"3",
|
|
90
|
+
"4",
|
|
91
|
+
]);
|
|
92
|
+
});
|
|
93
|
+
it("dedupes and slices the initialData fallback before SWR data resolves", () => {
|
|
94
|
+
// Before the first fetch resolves, `data` is undefined and `products` falls
|
|
95
|
+
// back to `initialData.products` (the warm-IDB seed from
|
|
96
|
+
// useInfiniteScrollCached, which is NOT pre-bounded to productLimit). That
|
|
97
|
+
// fallback now runs through the same dedupe + productLimit slice as fetched
|
|
98
|
+
// pages, so a seed with duplicates and more entries than the limit is capped
|
|
99
|
+
// to N unique products on first paint instead of rendering the raw seed.
|
|
100
|
+
setPages(undefined);
|
|
101
|
+
const products = renderProducts({
|
|
102
|
+
initialData: {
|
|
103
|
+
apiURL: "https://example.com/api",
|
|
104
|
+
products: [{ id: "1" }, { id: "1" }, { id: "2" }, { id: "3" }],
|
|
105
|
+
filtersData: null,
|
|
106
|
+
},
|
|
107
|
+
productLimit: 2,
|
|
108
|
+
});
|
|
109
|
+
expect(products.map((p) => p.id)).toEqual(["1", "2"]);
|
|
110
|
+
});
|
|
111
|
+
it("falls back to handle when id is absent", () => {
|
|
112
|
+
setPages([
|
|
113
|
+
page([{ handle: "a" }, { handle: "b" }]),
|
|
114
|
+
page([{ handle: "b" }, { handle: "c" }], false),
|
|
115
|
+
]);
|
|
116
|
+
expect(renderProducts().map((p) => p.handle)).toEqual(["a", "b", "c"]);
|
|
117
|
+
});
|
|
118
|
+
it("does not collapse same-name colorways that are distinct product ids", () => {
|
|
119
|
+
// The Edikted "Holly Glitter" case: same title, different ids → all kept.
|
|
120
|
+
setPages([
|
|
121
|
+
page([
|
|
122
|
+
{ id: "gid://shopify/Product/1", handle: "holly_silver" },
|
|
123
|
+
{ id: "gid://shopify/Product/2", handle: "holly_gold" },
|
|
124
|
+
]),
|
|
125
|
+
page([
|
|
126
|
+
{ id: "gid://shopify/Product/2", handle: "holly_gold" },
|
|
127
|
+
{ id: "gid://shopify/Product/3", handle: "holly_black" },
|
|
128
|
+
], false),
|
|
129
|
+
]);
|
|
130
|
+
expect(renderProducts().map((p) => p.handle)).toEqual([
|
|
131
|
+
"holly_silver",
|
|
132
|
+
"holly_gold",
|
|
133
|
+
"holly_black",
|
|
134
|
+
]);
|
|
135
|
+
});
|
|
136
|
+
it("keeps unkeyable items (no id and no handle) rather than dropping them", () => {
|
|
137
|
+
setPages([page([{ title: "x" }, { title: "y" }], false)]);
|
|
138
|
+
expect(renderProducts()).toHaveLength(2);
|
|
139
|
+
});
|
|
140
|
+
it("skips nullish page payloads while still in flight", () => {
|
|
141
|
+
setPages([page([{ id: "1" }, { id: "2" }]), undefined]);
|
|
142
|
+
expect(renderProducts().map((p) => p.id)).toEqual(["1", "2"]);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
// ─── loadMore gate: deduped count, not raw fetch count ──────────────────────
|
|
146
|
+
//
|
|
147
|
+
// `loadMore` must gate on the deduped, limit-sliced `products` count, not the
|
|
148
|
+
// raw `productCount` ref (which counts every fetched product including
|
|
149
|
+
// page-seam duplicates the `products` memo removes). These tests drive the
|
|
150
|
+
// `inView` intersection-observer effect (the real trigger path for `loadMore`)
|
|
151
|
+
// against pages whose provider size is smaller than `productLimit`, with
|
|
152
|
+
// boundary duplicates between pages. `pageData.cursorBlob` is set on every
|
|
153
|
+
// page (non-search-client / API mode) so `isReachingEnd` stays false and only
|
|
154
|
+
// the productLimit gate can be responsible for stopping pagination.
|
|
155
|
+
describe("useInfiniteScroll – loadMore gate uses deduped count, not raw fetch count", () => {
|
|
156
|
+
const apiPage = (products, cursorBlob = "cursor") => ({
|
|
157
|
+
products,
|
|
158
|
+
pageData: { cursorBlob },
|
|
159
|
+
filtersData: null,
|
|
160
|
+
apiURL: "https://example.com/api",
|
|
161
|
+
});
|
|
162
|
+
const renderWithPages = (pages, setSizeSpy, productLimit) => {
|
|
163
|
+
mockUseSWRInfinite.mockReturnValue({
|
|
164
|
+
data: pages,
|
|
165
|
+
error: undefined,
|
|
166
|
+
size: pages.length,
|
|
167
|
+
setSize: setSizeSpy,
|
|
168
|
+
isLoading: false,
|
|
169
|
+
isValidating: false,
|
|
170
|
+
mutate: jest.fn(),
|
|
171
|
+
});
|
|
172
|
+
return renderHook(() => useInfiniteScroll({
|
|
173
|
+
shouldSkipFetch: false,
|
|
174
|
+
initialData: {
|
|
175
|
+
apiURL: "https://example.com/api",
|
|
176
|
+
products: [],
|
|
177
|
+
filtersData: null,
|
|
178
|
+
},
|
|
179
|
+
queryVariables: { collectionId: "c1" },
|
|
180
|
+
// interval: 0 makes the lodash throttle wrapping loadMore invoke
|
|
181
|
+
// synchronously on the leading edge, so the inView effect's call is
|
|
182
|
+
// observable immediately after render.
|
|
183
|
+
interval: 0,
|
|
184
|
+
productLimit,
|
|
185
|
+
}));
|
|
186
|
+
};
|
|
187
|
+
beforeEach(() => {
|
|
188
|
+
mockUseSWRInfinite.mockReset();
|
|
189
|
+
mockUseInView.mockReturnValue({ ref: jest.fn(), inView: true });
|
|
190
|
+
});
|
|
191
|
+
it("keeps paginating while deduped products are still below a finite limit", () => {
|
|
192
|
+
const setSizeSpy = jest.fn();
|
|
193
|
+
// Provider page size (2) is well below productLimit (6); only 2 unique
|
|
194
|
+
// products so far — loadMore must advance setSize rather than gate off.
|
|
195
|
+
renderWithPages([apiPage([{ id: "1" }, { id: "2" }])], setSizeSpy, 6);
|
|
196
|
+
expect(setSizeSpy).toHaveBeenCalled();
|
|
197
|
+
});
|
|
198
|
+
it("stops paginating once deduped products reach the limit, even though raw fetched count differs due to seam duplicates", () => {
|
|
199
|
+
const setSizeSpy = jest.fn();
|
|
200
|
+
// 3 pages x 2 raw products = 6 raw fetched entries, but seam duplicates
|
|
201
|
+
// ("2" and "3") collapse them to 4 UNIQUE products — exactly productLimit.
|
|
202
|
+
// The last page still has a cursorBlob (more pages are technically
|
|
203
|
+
// available), so only the deduped-count gate — not isReachingEnd — can be
|
|
204
|
+
// responsible for stopping pagination here.
|
|
205
|
+
renderWithPages([
|
|
206
|
+
apiPage([{ id: "1" }, { id: "2" }]),
|
|
207
|
+
apiPage([{ id: "2" }, { id: "3" }]),
|
|
208
|
+
apiPage([{ id: "3" }, { id: "4" }]),
|
|
209
|
+
], setSizeSpy, 4);
|
|
210
|
+
expect(setSizeSpy).not.toHaveBeenCalled();
|
|
211
|
+
});
|
|
212
|
+
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"animate-container.d.ts","sourceRoot":"","sources":["../../../components/ui/animate-container.tsx"],"names":[],"mappings":"AAEA,OAAO,
|
|
1
|
+
{"version":3,"file":"animate-container.d.ts","sourceRoot":"","sources":["../../../components/ui/animate-container.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA4B,MAAM,OAAO,CAAA;AAGhD,KAAK,aAAa,GAAG,OAAO,GAAG,MAAM,CAAA;AAErC,UAAU,eAAe;IACvB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,OAAO,CAAA;CAClB;AAED,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,aAAa,EAAE,eAAe,CAW7D,CAAA;AAED,UAAU,qBAAqB;IAC7B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,UAAU,EAAE,eAAe,EAAE,CAAA;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,QAAQ,EACR,UAAU,EACV,QAAc,EACd,SAAS,EACT,SAAS,EACT,OAAO,GACR,EAAE,qBAAqB,2CAmCvB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chip.d.ts","sourceRoot":"","sources":["../../../components/ui/chip.tsx"],"names":[],"mappings":"AACA,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAEjE,OAAO,
|
|
1
|
+
{"version":3,"file":"chip.d.ts","sourceRoot":"","sources":["../../../components/ui/chip.tsx"],"names":[],"mappings":"AACA,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAEjE,OAAO,KAA8B,MAAM,OAAO,CAAA;AAIlD,QAAA,MAAM,YAAY;;;;mFAwBjB,CAAA;AAED,KAAK,SAAS,GAAG,KAAK,CAAC,wBAAwB,CAAC,KAAK,CAAC,GACpD,YAAY,CAAC,OAAO,YAAY,CAAC,GAAG;IAClC,IAAI,CAAC,EAAE,KAAK,CAAC,WAAW,CAAA;IACxB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAA;IACxB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAA;IACxB,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB,CAAA;AAEH,QAAA,MAAM,IAAI;;;;;;;;;;yBALc,IAAI;yBACJ,IAAI;;wCAgF3B,CAAA;AAGD,KAAK,kBAAkB,GAAG;IACxB,QAAQ,EAAE,KAAK,CAAC,YAAY,CAAC,SAAS,CAAC,EAAE,CAAA;IACzC,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAA;IAC3B,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,CAAC,CAAA;CAC9C,CAAA;AAED,QAAA,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAqD/C,CAAA;AAED,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,SAAS,EAAE,KAAK,kBAAkB,EAAE,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quantity-picker.d.ts","sourceRoot":"","sources":["../../../components/ui/quantity-picker.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"quantity-picker.d.ts","sourceRoot":"","sources":["../../../components/ui/quantity-picker.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B,MAAM,WAAW,mBACf,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IAC5C,eAAe,EAAE,MAAM,CAAA;IACvB,eAAe,EAAE,MAAM,CAAA;IACvB,aAAa,EAAE,MAAM,CAAA;IACrB,YAAY,EAAE,OAAO,CAAA;IACrB,SAAS,EAAE,MAAM,CAAA;IACjB,eAAe,EAAE,KAAK,CAAC,iBAAiB,CAAA;IACxC,eAAe,EAAE,KAAK,CAAC,iBAAiB,CAAA;IACxC,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE,KAAK,CAAC,aAAa,CAAA;IAChC,WAAW,CAAC,EAAE,KAAK,CAAC,aAAa,CAAA;IACjC,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAmCD,QAAA,MAAM,cAAc,4FA2GnB,CAAA;AAID,OAAO,EAAE,cAAc,EAAE,CAAA"}
|
|
@@ -12,7 +12,7 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
12
12
|
};
|
|
13
13
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
14
14
|
import * as React from "react";
|
|
15
|
-
import { cn
|
|
15
|
+
import { cn } from "../../lib/utils";
|
|
16
16
|
import { Icon } from "./icon";
|
|
17
17
|
const IconButton = ({ iconUrl, iconColor, handler, className, style, disabled }) => {
|
|
18
18
|
const visualButtonStyle = Object.assign({}, style);
|
|
@@ -17,7 +17,6 @@ export interface QuantityPickerNEWProps extends React.HTMLAttributes<HTMLDivElem
|
|
|
17
17
|
inputStyle?: React.CSSProperties;
|
|
18
18
|
buttonStyle?: React.CSSProperties;
|
|
19
19
|
buttonCornerRadius?: number;
|
|
20
|
-
debounceTime?: number;
|
|
21
20
|
max?: number;
|
|
22
21
|
parentRef?: React.RefObject<HTMLDivElement>;
|
|
23
22
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quantity-pickerNEW.d.ts","sourceRoot":"","sources":["../../../components/ui/quantity-pickerNEW.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"quantity-pickerNEW.d.ts","sourceRoot":"","sources":["../../../components/ui/quantity-pickerNEW.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAK9B,MAAM,WAAW,sBACf,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IAC5C,eAAe,EAAE,MAAM,CAAA;IACvB,eAAe,EAAE,MAAM,CAAA;IACvB,aAAa,EAAE,MAAM,CAAA;IACrB,YAAY,EAAE,OAAO,CAAA;IACrB,SAAS,EAAE,MAAM,CAAA;IACjB,eAAe,EAAE,KAAK,CAAC,iBAAiB,CAAA;IACxC,eAAe,EAAE,KAAK,CAAC,iBAAiB,CAAA;IACxC,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/B,gBAAgB,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;IACrC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE,KAAK,CAAC,aAAa,CAAA;IAChC,WAAW,CAAC,EAAE,KAAK,CAAC,aAAa,CAAA;IACjC,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,CAAC,CAAA;CAC5C;AAgED,QAAA,MAAM,iBAAiB,+FA2KtB,CAAA;AAID,OAAO,EAAE,iBAAiB,EAAE,CAAA"}
|
|
@@ -37,7 +37,7 @@ const IconButton = ({ iconUrl, iconColor, handler, className, style, disabled })
|
|
|
37
37
|
}, disabled: disabled, "aria-label": "Quantity button" })] })));
|
|
38
38
|
};
|
|
39
39
|
const QuantityPickerNEW = React.forwardRef((_a, ref) => {
|
|
40
|
-
var { className, decreaseIconUrl, increaseIconUrl, deleteIconUrl, isDeleteOnly = false, iconColor, onDecreaseClick, onIncreaseClick, isDecreaseDisabled, isIncreaseDisabled, value, onValueSet, onAdjustQuantity, inputStyle, buttonStyle, buttonCornerRadius = 4, max = 99, loading = false,
|
|
40
|
+
var { className, decreaseIconUrl, increaseIconUrl, deleteIconUrl, isDeleteOnly = false, iconColor, onDecreaseClick, onIncreaseClick, isDecreaseDisabled, isIncreaseDisabled, value, onValueSet, onAdjustQuantity, inputStyle, buttonStyle, buttonCornerRadius = 4, max = 99, loading = false, parentRef } = _a, props = __rest(_a, ["className", "decreaseIconUrl", "increaseIconUrl", "deleteIconUrl", "isDeleteOnly", "iconColor", "onDecreaseClick", "onIncreaseClick", "isDecreaseDisabled", "isIncreaseDisabled", "value", "onValueSet", "onAdjustQuantity", "inputStyle", "buttonStyle", "buttonCornerRadius", "max", "loading", "parentRef"]);
|
|
41
41
|
const safeValue = typeof value === "number" && Number.isFinite(value) ? value : 1;
|
|
42
42
|
const inputRef = React.useRef(null);
|
|
43
43
|
const [isFocused, setIsFocused] = React.useState(false);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-toast.d.ts","sourceRoot":"","sources":["../../../components/ui/use-toast.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"use-toast.d.ts","sourceRoot":"","sources":["../../../components/ui/use-toast.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAKzC,KAAK,YAAY,GAAG,UAAU,GAAG;IAC/B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACvB,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC7B,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,IAAI,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,CAAA;CACnD,CAAA;AAED,QAAA,MAAM,WAAW;;;;;CAKP,CAAA;AASV,KAAK,UAAU,GAAG,OAAO,WAAW,CAAA;AAEpC,KAAK,MAAM,GACP;IACE,IAAI,EAAE,UAAU,CAAC,WAAW,CAAC,CAAA;IAC7B,KAAK,EAAE,YAAY,CAAA;CACpB,GACD;IACE,IAAI,EAAE,UAAU,CAAC,cAAc,CAAC,CAAA;IAChC,KAAK,EAAE,OAAO,CAAC,YAAY,CAAC,CAAA;CAC7B,GACD;IACE,IAAI,EAAE,UAAU,CAAC,eAAe,CAAC,CAAA;IACjC,OAAO,CAAC,EAAE,YAAY,CAAC,IAAI,CAAC,CAAA;CAC7B,GACD;IACE,IAAI,EAAE,UAAU,CAAC,cAAc,CAAC,CAAA;IAChC,OAAO,CAAC,EAAE,YAAY,CAAC,IAAI,CAAC,CAAA;CAC7B,CAAA;AAEL,UAAU,KAAK;IACb,MAAM,EAAE,YAAY,EAAE,CAAA;CACvB;AAoBD,eAAO,MAAM,OAAO,UAAW,KAAK,UAAU,MAAM,KAAG,KAqDtD,CAAA;AAaD,KAAK,KAAK,GAAG,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,CAAA;AAErC,iBAAS,KAAK,CAAC,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK;;;oBAGT,YAAY;EAwBpC;AAED,iBAAS,QAAQ;;wBAgBO,MAAM;;EAE7B;AAED,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wishlist-select.d.ts","sourceRoot":"","sources":["../../../components/ui/wishlist-select.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,EAAgB,KAAK,
|
|
1
|
+
{"version":3,"file":"wishlist-select.d.ts","sourceRoot":"","sources":["../../../components/ui/wishlist-select.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,EAAgB,KAAK,EAAE,MAAM,iBAAiB,CAAA;AAGrD,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAE/C,UAAU,yBAAyB;IACjC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,UAAU,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IAC/C,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,WAAW,CAAC,EAAE,KAAK,CAAA;IACnB,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,sBAAsB,CAAC,EAAE,KAAK,CAAA;IAC9B,kBAAkB,CAAC,EAAE,KAAK,CAAA;IAC1B,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,cAAc,CAAC,EAAE;QACf,GAAG,EAAE,MAAM,CAAA;QACX,MAAM,EAAE,MAAM,CAAA;QACd,IAAI,EAAE,MAAM,CAAA;QACZ,KAAK,EAAE,MAAM,CAAA;KACd,CAAA;IACD,YAAY,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAA;IACvD,iBAAiB,CAAC,EAAE,KAAK,CAAA;IACzB,gBAAgB,CAAC,EAAE,KAAK,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,SAAS,CAAA;IACvE,sBAAsB,CAAC,EAAE,KAAK,CAAA;IAC9B,kBAAkB,CAAC,EAAE,KAAK,CAAA;IAC1B,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,gBAAgB,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAA;IAC3D,sBAAsB,CAAC,EAAE,KAAK,CAAA;IAC9B,qBAAqB,CAAC,EAAE,KAAK,CAAA;IAC7B,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,sBAAsB,CAAC,EAAE,MAAM,CAAA;IAC/B,cAAc,CAAC,EAAE,KAAK,CAAA;IACtB,iBAAiB,CAAC,EAAE,KAAK,CAAA;IACzB,gBAAgB,CAAC,EAAE,KAAK,CAAA;IACxB,aAAa,CAAC,EAAE,KAAK,CAAA;IACrB,QAAQ,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IAC7C,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,cAAc,CAAC,EAAE,KAAK,CAAA;IACtB,SAAS,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,kBAAkB,CAAC,EAAE,KAAK,CAAA;IAC1B,wBAAwB,CAAC,EAAE,KAAK,CAAA;IAChC,oBAAoB,CAAC,EAAE,KAAK,CAAA;CAC7B;AAED,UAAU,WAAW,CAAC,CAAC;IACrB,QAAQ,EAAE,KAAK,CAAC,YAAY,CAAC;QAC3B,KAAK,EAAE,CAAC,CAAA;QACR,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;QACrB,SAAS,CAAC,EAAE,OAAO,CAAA;QACnB,UAAU,CAAC,EAAE,OAAO,CAAA;QACpB,YAAY,EAAE,YAAY,CAAA;QAC1B,WAAW,CAAC,EAAE,yBAAyB,CAAA;QACvC,QAAQ,EAAE,CAAC,EACT,SAAS,EACT,YAAY,GACb,EAAE;YACD,SAAS,EAAE,OAAO,CAAA;YAClB,YAAY,EAAE,YAAY,CAAA;SAC3B,KAAK,KAAK,CAAC,SAAS,CAAA;KACtB,CAAC,EAAE,CAAA;IACJ,YAAY,CAAC,EAAE,CAAC,CAAA;IAChB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAA;IAC7B,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAA;IACxC,WAAW,CAAC,EAAE,MAAM,IAAI,CAAA;IACxB,YAAY,EAAE,YAAY,CAAA;IAC1B,WAAW,CAAC,EAAE,yBAAyB,CAAA;CACxC;AAED,QAAA,MAAM,cAAc,6FAoNnB,CAAA;AAID,UAAU,kBACR,SAAQ,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC;IACrD,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,WAAW,CAAC,EAAE,yBAAyB,CAAA;CACxC;AAED,QAAA,MAAM,qBAAqB,8FAwCzB,CAAA;AAGF,UAAU,kBAAkB;IAC1B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,MAAM,EAAE,OAAO,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,yBAAyB,CAAA;CACxC;AAED,QAAA,MAAM,qBAAqB,2FAgCzB,CAAA;AAGF,UAAU,eACR,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC;IAC9D,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,WAAW,CAAC,EAAE,yBAAyB,CAAA;IACvC,QAAQ,EACJ,KAAK,CAAC,SAAS,GACf,CAAC,CAAC,EAAE,SAAS,EAAE,EAAE;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,KAAK,KAAK,CAAC,SAAS,CAAC,CAAA;CACjE;AAED,QAAA,MAAM,kBAAkB,wFA8CvB,CAAA;AAGD,OAAO,EACL,cAAc,EACd,qBAAqB,EACrB,qBAAqB,EACrB,kBAAkB,GACnB,CAAA;AAED,YAAY,EAAE,yBAAyB,EAAE,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cart.util.d.ts","sourceRoot":"","sources":["../../lib/cart.util.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,sBAAsB,EACtB,6BAA6B,
|
|
1
|
+
{"version":3,"file":"cart.util.d.ts","sourceRoot":"","sources":["../../lib/cart.util.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,sBAAsB,EACtB,6BAA6B,EAC7B,cAAc,EACf,MAAM,kBAAkB,CAAA;AAGzB,eAAO,MAAM,eAAe;cAKhB,MAAM;aACP,cAAc;;0BAEH;YAChB,gBAAgB,CAAC,EAAE;gBACjB,MAAM,EAAE,MAAM,CAAA;gBACd,YAAY,EAAE,MAAM,CAAA;aACrB,CAAA;YACD,KAAK,EAAE;gBACL,MAAM,EAAE,MAAM,CAAA;gBACd,YAAY,EAAE,MAAM,CAAA;aACrB,CAAA;YACD,cAAc,CAAC,EAAE;gBACf,MAAM,EAAE,MAAM,CAAA;gBACd,YAAY,EAAE,MAAM,CAAA;aACrB,CAAA;SACF,EAAE;;;;;;;CAgCN,CAAA;AAuCD,eAAO,MAAM,oBAAoB,SAAU,MAAM,QAAQ,YAAY,YAMpE,CAAA;AAED,eAAO,MAAM,kBAAkB,SAAU,MAAM,QAAQ,YAAY,YAMlE,CAAA;AAoHD,MAAM,MAAM,cAAc,GAAG;IAC3B,yBAAyB,EAAE,sBAAsB,EAAE,CAAA;IACnD,gBAAgB,EAAE,6BAA6B,EAAE,CAAA;IACjD,cAAc,EAAE,OAAO,CAAA;IACvB,oBAAoB,EAAE,MAAM,CAAA;IAC5B,oBAAoB,EAAE,MAAM,CAAA;IAC5B,WAAW,EAAE,MAAM,CAAA;IACnB,mBAAmB,EAAE,MAAM,CAAA;IAC3B,oBAAoB,EAAE,MAAM,CAAA;IAC5B,gBAAgB,EAAE,MAAM,CAAA;CACzB,CAAA;AAED,eAAO,MAAM,uBAAuB,EAAE,cAUrC,CAAA;AAED,eAAO,MAAM,qBAAqB,SAAU,YAAY,KAAG,cA8B1D,CAAA;AAGD,eAAO,MAAM,mBAAmB;eACnB,MAAM;;;;;aAEG,MAAM;eAAS,MAAM;;;;oBAIN,MAAM;0BAAgB,MAAM;;;eAElD,MAAM;;;;;gBAML,MAAM;cACR,MAAM;;cAEN,MAAM;;;0BAIM;YAAE,MAAM,EAAE,MAAM,CAAC;YAAC,YAAY,EAAE,MAAM,CAAA;SAAE;oBAC9C,MAAM;;;;YAsCzB,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"variablesCart.util.d.ts","sourceRoot":"","sources":["../../lib/variablesCart.util.ts"],"names":[],"mappings":"AACA,OAAO,EACL,SAAS,EACT,sBAAsB,EACtB,6BAA6B,
|
|
1
|
+
{"version":3,"file":"variablesCart.util.d.ts","sourceRoot":"","sources":["../../lib/variablesCart.util.ts"],"names":[],"mappings":"AACA,OAAO,EACL,SAAS,EACT,sBAAsB,EACtB,6BAA6B,EAG9B,MAAM,kBAAkB,CAAA;AAEzB,eAAO,MAAM,2BAA2B;;cAM5B,MAAM;;0BAEI;YAChB,gBAAgB,CAAC,EAAE,MAAM,CAAA;YACzB,KAAK,EAAE,MAAM,CAAA;YACb,cAAc,CAAC,EAAE,MAAM,CAAA;SACxB,EAAE;;;;;;CAyBN,CAAA;AA8FD,eAAO,MAAM,6BAA6B,SAClC,MAAM,QACN,SAAS,GAAG,IAAI,YAUvB,CAAA;AAED,eAAO,MAAM,2BAA2B,SAChC,MAAM,QACN,SAAS,GAAG,IAAI,YAUvB,CAAA;AAoMD,MAAM,MAAM,uBAAuB,GAAG;IACpC,yBAAyB,EAAE,sBAAsB,EAAE,CAAA;IACnD,gBAAgB,EAAE,6BAA6B,EAAE,CAAA;IACjD,cAAc,EAAE,OAAO,CAAA;IACvB,oBAAoB,EAAE,MAAM,CAAA;IAC5B,oBAAoB,EAAE,MAAM,CAAA;IAC5B,WAAW,EAAE,MAAM,CAAA;IACnB,mBAAmB,EAAE,MAAM,CAAA;IAC3B,oBAAoB,EAAE,MAAM,CAAA;IAC5B,gBAAgB,EAAE,MAAM,CAAA;CACzB,CAAA;AAED,eAAO,MAAM,iCAAiC,EAAE,uBAU/C,CAAA;AAED,eAAO,MAAM,8BAA8B,SACnC,SAAS,GAAG,IAAI,KACrB,uBAmCF,CAAA"}
|
package/dist/styles.css
CHANGED
|
@@ -695,6 +695,9 @@ video {
|
|
|
695
695
|
.invisible {
|
|
696
696
|
visibility: hidden;
|
|
697
697
|
}
|
|
698
|
+
.collapse {
|
|
699
|
+
visibility: collapse;
|
|
700
|
+
}
|
|
698
701
|
.static {
|
|
699
702
|
position: static;
|
|
700
703
|
}
|
|
@@ -1496,9 +1499,6 @@ video {
|
|
|
1496
1499
|
.max-w-\[480px\] {
|
|
1497
1500
|
max-width: 480px;
|
|
1498
1501
|
}
|
|
1499
|
-
.max-w-\[50\%\] {
|
|
1500
|
-
max-width: 50%;
|
|
1501
|
-
}
|
|
1502
1502
|
.max-w-\[5rem\] {
|
|
1503
1503
|
max-width: 5rem;
|
|
1504
1504
|
}
|
|
@@ -1520,6 +1520,9 @@ video {
|
|
|
1520
1520
|
.flex-1 {
|
|
1521
1521
|
flex: 1 1 0%;
|
|
1522
1522
|
}
|
|
1523
|
+
.flex-\[0_0_138px\] {
|
|
1524
|
+
flex: 0 0 138px;
|
|
1525
|
+
}
|
|
1523
1526
|
.flex-\[0_0_226px\] {
|
|
1524
1527
|
flex: 0 0 226px;
|
|
1525
1528
|
}
|
|
@@ -1550,9 +1553,6 @@ video {
|
|
|
1550
1553
|
.basis-\[300px\] {
|
|
1551
1554
|
flex-basis: 300px;
|
|
1552
1555
|
}
|
|
1553
|
-
.basis-\[88\%\] {
|
|
1554
|
-
flex-basis: 88%;
|
|
1555
|
-
}
|
|
1556
1556
|
.basis-full {
|
|
1557
1557
|
flex-basis: 100%;
|
|
1558
1558
|
}
|
|
@@ -1860,6 +1860,10 @@ video {
|
|
|
1860
1860
|
-moz-column-gap: 0.5rem;
|
|
1861
1861
|
column-gap: 0.5rem;
|
|
1862
1862
|
}
|
|
1863
|
+
.gap-x-3 {
|
|
1864
|
+
-moz-column-gap: 0.75rem;
|
|
1865
|
+
column-gap: 0.75rem;
|
|
1866
|
+
}
|
|
1863
1867
|
.gap-x-\[7px\] {
|
|
1864
1868
|
-moz-column-gap: 7px;
|
|
1865
1869
|
column-gap: 7px;
|
|
@@ -1867,6 +1871,9 @@ video {
|
|
|
1867
1871
|
.gap-y-0 {
|
|
1868
1872
|
row-gap: 0px;
|
|
1869
1873
|
}
|
|
1874
|
+
.gap-y-1 {
|
|
1875
|
+
row-gap: 0.25rem;
|
|
1876
|
+
}
|
|
1870
1877
|
.gap-y-2 {
|
|
1871
1878
|
row-gap: 0.5rem;
|
|
1872
1879
|
}
|