@tapcart/mobile-components 0.14.0 → 0.14.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/dist/components/hooks/use-infinite-scroll.d.ts.map +1 -1
  2. package/dist/components/hooks/use-infinite-scroll.js +41 -20
  3. package/dist/components/hooks/use-infinite-scroll.test.d.ts +2 -0
  4. package/dist/components/hooks/use-infinite-scroll.test.d.ts.map +1 -0
  5. package/dist/components/hooks/use-infinite-scroll.test.js +212 -0
  6. package/dist/components/ui/animate-container.d.ts.map +1 -1
  7. package/dist/components/ui/chip.d.ts.map +1 -1
  8. package/dist/components/ui/quantity-picker.d.ts.map +1 -1
  9. package/dist/components/ui/quantity-picker.js +1 -1
  10. package/dist/components/ui/quantity-pickerNEW.d.ts +0 -1
  11. package/dist/components/ui/quantity-pickerNEW.d.ts.map +1 -1
  12. package/dist/components/ui/quantity-pickerNEW.js +1 -1
  13. package/dist/components/ui/use-toast.d.ts.map +1 -1
  14. package/dist/components/ui/wishlist-select.d.ts.map +1 -1
  15. package/dist/index.d.ts +1 -0
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +1 -0
  18. package/dist/lib/cart.util.d.ts.map +1 -1
  19. package/dist/lib/cart.util.js +3 -2
  20. package/dist/lib/cart.util.test.js +89 -0
  21. package/dist/lib/discountAllocation.util.d.ts +24 -0
  22. package/dist/lib/discountAllocation.util.d.ts.map +1 -0
  23. package/dist/lib/discountAllocation.util.js +150 -0
  24. package/dist/lib/discountAllocation.util.test.d.ts +2 -0
  25. package/dist/lib/discountAllocation.util.test.d.ts.map +1 -0
  26. package/dist/lib/discountAllocation.util.test.js +200 -0
  27. package/dist/lib/variablesCart.util.d.ts.map +1 -1
  28. package/dist/lib/variablesCart.util.js +3 -4
  29. package/dist/lib/variablesCart.util.test.js +85 -0
  30. package/dist/styles.css +3 -0
  31. package/package.json +1 -1
@@ -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;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,uBAuU3B,CAAA;AAED,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,CAAA"}
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"}
@@ -71,7 +71,6 @@ direction = "vertical", productLimit = Infinity, threshold = 0.01, interval = 33
71
71
  customFetcher, customGetKey, shouldSkipFetch: shouldSkipFetchProp, }) => {
72
72
  var _a, _b, _c, _d, _e, _f;
73
73
  const searchParams = useSearchParams();
74
- const productCount = useRef(0);
75
74
  const isFirstRender = useRef(true);
76
75
  const prevParamsRef = useRef({
77
76
  collectionId: null,
@@ -122,7 +121,6 @@ customFetcher, customGetKey, shouldSkipFetch: shouldSkipFetchProp, }) => {
122
121
  return Object.assign(Object.assign({}, queryVariables), { cursorBlob: previousPageData.pageData.cursorBlob });
123
122
  };
124
123
  const apiFetcher = (body) => __awaiter(void 0, void 0, void 0, function* () {
125
- var _g, _h;
126
124
  if (!(initialData === null || initialData === void 0 ? void 0 : initialData.apiURL)) {
127
125
  throw new Error("initialData.apiURL is required for API mode");
128
126
  }
@@ -131,7 +129,6 @@ customFetcher, customGetKey, shouldSkipFetch: shouldSkipFetchProp, }) => {
131
129
  body: JSON.stringify(body),
132
130
  });
133
131
  const data = yield res.json();
134
- 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;
135
132
  return data;
136
133
  });
137
134
  // Return null from getKey to conditionally skip fetching
@@ -154,18 +151,14 @@ customFetcher, customGetKey, shouldSkipFetch: shouldSkipFetchProp, }) => {
154
151
  };
155
152
  const fetcher = usingSearchClient
156
153
  ? (...args) => __awaiter(void 0, void 0, void 0, function* () {
157
- var _j, _k;
158
154
  if (!searchClientFetcher)
159
155
  return null;
160
156
  const result = yield searchClientFetcher(...args);
161
- 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;
162
157
  return result;
163
158
  })
164
159
  : (...args) => __awaiter(void 0, void 0, void 0, function* () {
165
- var _l, _m;
166
160
  if (customFetcher) {
167
161
  const result = yield customFetcher(...args);
168
- 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;
169
162
  return result;
170
163
  }
171
164
  return apiFetcher(args[0]);
@@ -203,7 +196,6 @@ customFetcher, customGetKey, shouldSkipFetch: shouldSkipFetchProp, }) => {
203
196
  };
204
197
  // Skip reset on first render, but force it for any subsequent transitions to valid params
205
198
  if (!isFirstRender.current && hasValidCurrentParams) {
206
- productCount.current = 0;
207
199
  mutate();
208
200
  }
209
201
  }
@@ -241,10 +233,49 @@ customFetcher, customGetKey, shouldSkipFetch: shouldSkipFetchProp, }) => {
241
233
  }
242
234
  const isReachingEnd = isEmpty || isEndPointer;
243
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]);
244
271
  const loadMore = useCallback(() => {
245
272
  if (isLoading || isLoadingMore || isReachingEnd || isRefreshing)
246
273
  return;
247
- if (productCount.current >= productLimit)
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)
248
279
  return;
249
280
  setSize(size + 1);
250
281
  }, [
@@ -252,6 +283,7 @@ customFetcher, customGetKey, shouldSkipFetch: shouldSkipFetchProp, }) => {
252
283
  isLoadingMore,
253
284
  isReachingEnd,
254
285
  isRefreshing,
286
+ products.length,
255
287
  productLimit,
256
288
  setSize,
257
289
  size,
@@ -267,21 +299,10 @@ customFetcher, customGetKey, shouldSkipFetch: shouldSkipFetchProp, }) => {
267
299
  if (!usingSearchClient || !searchClient)
268
300
  return;
269
301
  const unsubscribeAllChanges = searchClient.onSearchStateChange(() => {
270
- productCount.current = 0;
271
302
  mutate();
272
303
  });
273
304
  return unsubscribeAllChanges;
274
305
  }, [searchClient, mutate, usingSearchClient]);
275
- const products = useMemo(() => {
276
- if (data) {
277
- return data.flatMap((page) => page === null || page === void 0 ? void 0 : page.products).slice(0, productLimit);
278
- }
279
- // Use pre-fetched products while SWR fetches the real paginated data
280
- if (hasInitialProducts) {
281
- return initialData.products;
282
- }
283
- return [];
284
- }, [data, productLimit, hasInitialProducts, initialData === null || initialData === void 0 ? void 0 : initialData.products]);
285
306
  // Collect all integration responses per page when using search client
286
307
  const integrationResponses = useMemo(() => {
287
308
  if (!usingSearchClient)
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=use-infinite-scroll.test.d.ts.map
@@ -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,KAAsC,MAAM,OAAO,CAAA;AAG1D,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
+ {"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,KAAsC,MAAM,OAAO,CAAA;AAI1D,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
+ {"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;AAS9B,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"}
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, } from "../../lib/utils";
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;AAM9B,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,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,CAAC,CAAA;CAC5C;AAgED,QAAA,MAAM,iBAAiB,+FA4KtB,CAAA;AAID,OAAO,EAAE,iBAAiB,EAAE,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, debounceTime = 300, parentRef } = _a, props = __rest(_a, ["className", "decreaseIconUrl", "increaseIconUrl", "deleteIconUrl", "isDeleteOnly", "iconColor", "onDecreaseClick", "onIncreaseClick", "isDecreaseDisabled", "isIncreaseDisabled", "value", "onValueSet", "onAdjustQuantity", "inputStyle", "buttonStyle", "buttonCornerRadius", "max", "loading", "debounceTime", "parentRef"]);
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,EAAsB,UAAU,EAAE,MAAM,SAAS,CAAA;AAK7D,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
+ {"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":"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"}
1
+ {"version":3,"file":"wishlist-select.d.ts","sourceRoot":"","sources":["../../../components/ui/wishlist-select.tsx"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export { addItemToWishlist, cn, createCollectionImageMap, cva, formatRelativeTime, getBackgroundAndPaddingStyle, getBackgroundAndSpacingStyle, getBadgesForProductFn, getBorderSidesStyle, getBorderStyle, getColor, getDestinationHandler, getEnabledWishlistIntegration, getGridSpacing, getIdFromGid, getInputPlaceholderTextProps, getLoyaltyButtonProps, getMarginStyle, getOverlayStyle, getPaddingStyle, getProductGidsFromIds, getSpaceBetween, getTextStyle, getVariantGidsFromIds, getVerticalAlignment, getVerticalAlignmentStyle, getWishlistAddItemNavigation, isFavoriteIntegrationEnabled, isVideo, mapFlexToAlignment, parsePhoneNumber, pluralize, productGidFromId, removeItemFromWishlists, stringRatioToInt, supportedVideoExtensions, supportsMultipleWishlists, throttleFunction, variantGidFromId, formatFrequency, formatPrice, shareContent, } from "./lib/utils";
2
2
  export type { WishlistEntryMatch } from "./lib/utils";
3
3
  export * from "./lib/cart.util";
4
+ export * from "./lib/discountAllocation.util";
4
5
  export * from "./lib/variablesCart.util";
5
6
  export * from "./lib/isTapcartVersion20.util";
6
7
  export * from "./components/contexts/translation-context";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  // component exports
2
2
  export { addItemToWishlist, cn, createCollectionImageMap, cva, formatRelativeTime, getBackgroundAndPaddingStyle, getBackgroundAndSpacingStyle, getBadgesForProductFn, getBorderSidesStyle, getBorderStyle, getColor, getDestinationHandler, getEnabledWishlistIntegration, getGridSpacing, getIdFromGid, getInputPlaceholderTextProps, getLoyaltyButtonProps, getMarginStyle, getOverlayStyle, getPaddingStyle, getProductGidsFromIds, getSpaceBetween, getTextStyle, getVariantGidsFromIds, getVerticalAlignment, getVerticalAlignmentStyle, getWishlistAddItemNavigation, isFavoriteIntegrationEnabled, isVideo, mapFlexToAlignment, parsePhoneNumber, pluralize, productGidFromId, removeItemFromWishlists, stringRatioToInt, supportedVideoExtensions, supportsMultipleWishlists, throttleFunction, variantGidFromId, formatFrequency, formatPrice, shareContent, } from "./lib/utils";
3
3
  export * from "./lib/cart.util";
4
+ export * from "./lib/discountAllocation.util";
4
5
  export * from "./lib/variablesCart.util";
5
6
  export * from "./lib/isTapcartVersion20.util";
6
7
  export * from "./components/contexts/translation-context";
@@ -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,EAE7B,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
+ {"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;AAOzB,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,3 +1,4 @@
1
+ import { isMerchandiseDiscountAllocation, isShippingDiscountAllocation, } from "./discountAllocation.util";
1
2
  import { getIdFromGid } from "./utils";
2
3
  export const getVariantPrice = ({ quantity, variant, sellingPlanAllocation = { priceAdjustments: [] }, }) => {
3
4
  var _a, _b, _c, _d;
@@ -27,7 +28,7 @@ export const getVariantPrice = ({ quantity, variant, sellingPlanAllocation = { p
27
28
  };
28
29
  const getOrderLevelDiscounts = (cart) => {
29
30
  var _a;
30
- const discountMap = (_a = cart.discountAllocations) === null || _a === void 0 ? void 0 : _a.filter((discount) => discount.targetType !== "SHIPPING_LINE").reduce((acc, discount) => {
31
+ const discountMap = (_a = cart.discountAllocations) === null || _a === void 0 ? void 0 : _a.filter((discount) => isMerchandiseDiscountAllocation(discount, cart)).reduce((acc, discount) => {
31
32
  var _a, _b;
32
33
  const code = ((_a = discount.code) !== null && _a !== void 0 ? _a : "unknown").toUpperCase();
33
34
  if (!acc[code]) {
@@ -51,7 +52,7 @@ const getShippingDiscounts = (cart) => {
51
52
  var _a;
52
53
  if (!(cart === null || cart === void 0 ? void 0 : cart.discountAllocations))
53
54
  return [];
54
- return (_a = cart.discountAllocations) === null || _a === void 0 ? void 0 : _a.filter((discount) => discount.targetType === "SHIPPING_LINE").map((discount) => {
55
+ return (_a = cart.discountAllocations) === null || _a === void 0 ? void 0 : _a.filter((discount) => isShippingDiscountAllocation(discount, cart)).map((discount) => {
55
56
  var _a;
56
57
  return ({
57
58
  amount: (_a = discount === null || discount === void 0 ? void 0 : discount.discountedAmount) === null || _a === void 0 ? void 0 : _a.amount,
@@ -88,6 +88,95 @@ describe("cart-provider.util", () => {
88
88
  const result = getCalculatedCartData(mockCart);
89
89
  expect(result.isFreeShipping).toBe(true);
90
90
  });
91
+ it("should exclude shipping discount without targetType from merchandise totals (TICKET-4028)", () => {
92
+ const mockCart = Object.assign(Object.assign({}, baseCartData), { discounts: ["CEXFS9P882N"], cost: {
93
+ subtotalAmount: { amount: "14.00", currencyCode: "USD" },
94
+ totalAmount: { amount: "14.00", currencyCode: "USD" },
95
+ totalTaxAmount: { amount: "0.00", currencyCode: "USD" },
96
+ }, items: [
97
+ {
98
+ id: "line1",
99
+ quantity: 1,
100
+ productId: "prod1",
101
+ variantId: "var1",
102
+ productDetails: {},
103
+ variantDetails: {
104
+ compareAtPrice: { amount: "14.00", currencyCode: "USD" },
105
+ price: { amount: "14.00", currencyCode: "USD" },
106
+ },
107
+ discounts: [],
108
+ cost: { totalAmount: { amount: "14.00", currencyCode: "USD" } },
109
+ },
110
+ ], discountAllocations: [
111
+ {
112
+ discountedAmount: { amount: "7.95", currencyCode: "USD" },
113
+ code: "CEXFS9P882N",
114
+ },
115
+ ], appliedGiftCards: [], deliveryGroups: [
116
+ {
117
+ deliveryOptions: [
118
+ {
119
+ title: "Ground Shipping",
120
+ estimatedCost: { amount: "7.95", currencyCode: "USD" },
121
+ },
122
+ {
123
+ title: "Express Shipping",
124
+ estimatedCost: { amount: "18.95", currencyCode: "USD" },
125
+ },
126
+ ],
127
+ },
128
+ ] });
129
+ const result = getCalculatedCartData(mockCart);
130
+ expect(result.orderAndLineItemDiscounts).toHaveLength(0);
131
+ expect(result.discountsTotalAmount).toBe(0);
132
+ expect(result.isFreeShipping).toBe(true);
133
+ expect(result.totalDiscountedPrice).toBe(14);
134
+ });
135
+ it("should exclude shipping from merchandise totals when merch + free ship stack (TICKET-4028)", () => {
136
+ const mockCart = Object.assign(Object.assign({}, baseCartData), { discounts: ["SAVE10", "FREESHIP"], cost: {
137
+ subtotalAmount: { amount: "100.00", currencyCode: "USD" },
138
+ totalAmount: { amount: "90.00", currencyCode: "USD" },
139
+ totalTaxAmount: { amount: "0.00", currencyCode: "USD" },
140
+ }, items: [
141
+ {
142
+ id: "line1",
143
+ quantity: 1,
144
+ productId: "prod1",
145
+ variantId: "var1",
146
+ productDetails: {},
147
+ variantDetails: {
148
+ compareAtPrice: { amount: "100.00", currencyCode: "USD" },
149
+ price: { amount: "100.00", currencyCode: "USD" },
150
+ },
151
+ discounts: [],
152
+ cost: { totalAmount: { amount: "100.00", currencyCode: "USD" } },
153
+ },
154
+ ], discountAllocations: [
155
+ {
156
+ discountedAmount: { amount: "10.00", currencyCode: "USD" },
157
+ code: "SAVE10",
158
+ },
159
+ {
160
+ discountedAmount: { amount: "10.00", currencyCode: "USD" },
161
+ code: "FREESHIP",
162
+ },
163
+ ], deliveryGroups: [
164
+ {
165
+ deliveryOptions: [
166
+ {
167
+ title: "Standard",
168
+ estimatedCost: { amount: "10.00", currencyCode: "USD" },
169
+ },
170
+ ],
171
+ },
172
+ ] });
173
+ const result = getCalculatedCartData(mockCart);
174
+ expect(result.orderAndLineItemDiscounts).toHaveLength(1);
175
+ expect(result.orderAndLineItemDiscounts[0].amount).toBe(10);
176
+ expect(result.discountsTotalAmount).toBe(10);
177
+ expect(result.isFreeShipping).toBe(true);
178
+ expect(result.totalDiscountedPrice).toBe(90);
179
+ });
91
180
  it("should calculate total discounted price correctly", () => {
92
181
  const mockCart = Object.assign(Object.assign({}, baseCartData), { discounts: ["Discount10"], items: [
93
182
  {
@@ -0,0 +1,24 @@
1
+ import { CartDiscountAllocation } from "app-studio-types";
2
+ type DeliveryOptionCost = {
3
+ estimatedCost?: {
4
+ amount?: string | number | null;
5
+ };
6
+ };
7
+ type CartWithDeliveryGroups = {
8
+ discountAllocations?: CartDiscountAllocation[];
9
+ deliveryGroups?: Array<{
10
+ deliveryOptions?: DeliveryOptionCost[];
11
+ }>;
12
+ cost?: {
13
+ subtotalAmount?: {
14
+ amount?: string | number | null;
15
+ };
16
+ totalAmount?: {
17
+ amount?: string | number | null;
18
+ };
19
+ };
20
+ };
21
+ export declare const isShippingDiscountAllocation: (allocation: CartDiscountAllocation, cart?: CartWithDeliveryGroups | null) => boolean;
22
+ export declare const isMerchandiseDiscountAllocation: (allocation: CartDiscountAllocation, cart?: CartWithDeliveryGroups | null) => boolean;
23
+ export {};
24
+ //# sourceMappingURL=discountAllocation.util.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discountAllocation.util.d.ts","sourceRoot":"","sources":["../../lib/discountAllocation.util.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EAEvB,MAAM,kBAAkB,CAAA;AAEzB,KAAK,kBAAkB,GAAG;IACxB,aAAa,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;KAAE,CAAA;CACpD,CAAA;AAED,KAAK,sBAAsB,GAAG;IAC5B,mBAAmB,CAAC,EAAE,sBAAsB,EAAE,CAAA;IAC9C,cAAc,CAAC,EAAE,KAAK,CAAC;QACrB,eAAe,CAAC,EAAE,kBAAkB,EAAE,CAAA;KACvC,CAAC,CAAA;IACF,IAAI,CAAC,EAAE;QACL,cAAc,CAAC,EAAE;YAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;SAAE,CAAA;QACpD,WAAW,CAAC,EAAE;YAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;SAAE,CAAA;KAClD,CAAA;CACF,CAAA;AAkMD,eAAO,MAAM,4BAA4B,eAC3B,sBAAsB,SAC3B,sBAAsB,GAAG,IAAI,KACnC,OAAiE,CAAA;AAEpE,eAAO,MAAM,+BAA+B,eAC9B,sBAAsB,SAC3B,sBAAsB,GAAG,IAAI,KACnC,OAAoE,CAAA"}
@@ -0,0 +1,150 @@
1
+ import { DiscountApplicationTargetType, } from "app-studio-types";
2
+ const MONEY_EPSILON = 0.01;
3
+ const parseAmount = (amount) => {
4
+ if (amount === undefined || amount === null || amount === "")
5
+ return 0;
6
+ const parsed = parseFloat(String(amount));
7
+ return Number.isFinite(parsed) ? parsed : 0;
8
+ };
9
+ const approxEqual = (a, b, epsilon = MONEY_EPSILON) => Math.abs(a - b) <= epsilon;
10
+ const getDeliveryOptionAmounts = (cart) => {
11
+ var _a;
12
+ if (!((_a = cart === null || cart === void 0 ? void 0 : cart.deliveryGroups) === null || _a === void 0 ? void 0 : _a.length))
13
+ return [];
14
+ return cart.deliveryGroups.flatMap((group) => {
15
+ var _a;
16
+ return ((_a = group.deliveryOptions) !== null && _a !== void 0 ? _a : []).map((option) => { var _a; return parseAmount((_a = option.estimatedCost) === null || _a === void 0 ? void 0 : _a.amount); });
17
+ });
18
+ };
19
+ const allocationMatchesDeliveryOptionCost = (allocation, cart) => {
20
+ var _a;
21
+ const allocationAmount = parseAmount((_a = allocation === null || allocation === void 0 ? void 0 : allocation.discountedAmount) === null || _a === void 0 ? void 0 : _a.amount);
22
+ if (!allocationAmount)
23
+ return false;
24
+ return getDeliveryOptionAmounts(cart).some((deliveryCost) => approxEqual(deliveryCost, allocationAmount));
25
+ };
26
+ const inferShippingWhenTargetTypeMissing = (allocation, cart) => {
27
+ var _a, _b, _c, _d, _e, _f;
28
+ if (!((_a = cart === null || cart === void 0 ? void 0 : cart.deliveryGroups) === null || _a === void 0 ? void 0 : _a.length))
29
+ return false;
30
+ const allocationAmount = parseAmount((_b = allocation === null || allocation === void 0 ? void 0 : allocation.discountedAmount) === null || _b === void 0 ? void 0 : _b.amount);
31
+ if (!allocationAmount)
32
+ return false;
33
+ const deliveryAmounts = getDeliveryOptionAmounts(cart);
34
+ if (!deliveryAmounts.length)
35
+ return false;
36
+ const subtotal = parseAmount((_d = (_c = cart === null || cart === void 0 ? void 0 : cart.cost) === null || _c === void 0 ? void 0 : _c.subtotalAmount) === null || _d === void 0 ? void 0 : _d.amount);
37
+ const total = parseAmount((_f = (_e = cart === null || cart === void 0 ? void 0 : cart.cost) === null || _e === void 0 ? void 0 : _e.totalAmount) === null || _f === void 0 ? void 0 : _f.amount);
38
+ if (subtotal > 0 && total > 0) {
39
+ if (approxEqual(total, subtotal - allocationAmount))
40
+ return false;
41
+ if (approxEqual(total, subtotal) &&
42
+ deliveryAmounts.some((cost) => approxEqual(cost, allocationAmount))) {
43
+ return true;
44
+ }
45
+ if (total > subtotal + MONEY_EPSILON &&
46
+ deliveryAmounts.some((cost) => approxEqual(cost, allocationAmount))) {
47
+ return true;
48
+ }
49
+ // Merchandise discounts reduce total below subtotal; unchanged total implies
50
+ // shipping-side allocation (e.g. FREESHIPPING with zeroed delivery rates).
51
+ if (approxEqual(total, subtotal) && allocationAmount > 0) {
52
+ return true;
53
+ }
54
+ return false;
55
+ }
56
+ return allocationMatchesDeliveryOptionCost(allocation, cart);
57
+ };
58
+ /**
59
+ * When multiple allocations omit targetType (stacked merch + free ship), per-allocation
60
+ * inference misclassifies shipping as merchandise. Partition using merchBudget =
61
+ * subtotal − total (Shopify subtotalAmount is merchandise-only).
62
+ */
63
+ const partitionAmbiguousAllocations = (ambiguous, cart) => {
64
+ var _a, _b, _c, _d;
65
+ const result = new Map();
66
+ const subtotal = parseAmount((_b = (_a = cart === null || cart === void 0 ? void 0 : cart.cost) === null || _a === void 0 ? void 0 : _a.subtotalAmount) === null || _b === void 0 ? void 0 : _b.amount);
67
+ const total = parseAmount((_d = (_c = cart === null || cart === void 0 ? void 0 : cart.cost) === null || _c === void 0 ? void 0 : _c.totalAmount) === null || _d === void 0 ? void 0 : _d.amount);
68
+ const merchBudget = subtotal > 0 && total > 0 ? Math.max(0, subtotal - total) : 0;
69
+ const items = ambiguous.map((allocation) => {
70
+ var _a;
71
+ return ({
72
+ allocation,
73
+ amount: parseAmount((_a = allocation === null || allocation === void 0 ? void 0 : allocation.discountedAmount) === null || _a === void 0 ? void 0 : _a.amount),
74
+ matchesDelivery: allocationMatchesDeliveryOptionCost(allocation, cart),
75
+ });
76
+ });
77
+ let assignedMerch = 0;
78
+ for (const item of items) {
79
+ if (!item.matchesDelivery) {
80
+ result.set(item.allocation, "merchandise");
81
+ assignedMerch += item.amount;
82
+ }
83
+ }
84
+ for (const item of items.filter((i) => i.matchesDelivery)) {
85
+ if (assignedMerch + item.amount <= merchBudget + MONEY_EPSILON) {
86
+ result.set(item.allocation, "merchandise");
87
+ assignedMerch += item.amount;
88
+ }
89
+ else if (assignedMerch >= merchBudget - MONEY_EPSILON ||
90
+ assignedMerch + item.amount > merchBudget + MONEY_EPSILON) {
91
+ result.set(item.allocation, "shipping");
92
+ }
93
+ else {
94
+ result.set(item.allocation, "merchandise");
95
+ assignedMerch += item.amount;
96
+ }
97
+ }
98
+ return result;
99
+ };
100
+ const kindMapCache = new WeakMap();
101
+ const buildAllocationKindMap = (cart) => {
102
+ const allocations = cart === null || cart === void 0 ? void 0 : cart.discountAllocations;
103
+ if (!Array.isArray(allocations) || !allocations.length)
104
+ return null;
105
+ const cached = kindMapCache.get(cart);
106
+ if (cached)
107
+ return cached;
108
+ const map = new Map();
109
+ const ambiguous = [];
110
+ for (const allocation of allocations) {
111
+ if ((allocation === null || allocation === void 0 ? void 0 : allocation.targetType) === DiscountApplicationTargetType.ShippingLine) {
112
+ map.set(allocation, "shipping");
113
+ continue;
114
+ }
115
+ if ((allocation === null || allocation === void 0 ? void 0 : allocation.targetType) != null) {
116
+ map.set(allocation, "merchandise");
117
+ continue;
118
+ }
119
+ ambiguous.push(allocation);
120
+ }
121
+ if (ambiguous.length === 1) {
122
+ const allocation = ambiguous[0];
123
+ map.set(allocation, inferShippingWhenTargetTypeMissing(allocation, cart)
124
+ ? "shipping"
125
+ : "merchandise");
126
+ }
127
+ else if (ambiguous.length > 1) {
128
+ const partitioned = partitionAmbiguousAllocations(ambiguous, cart);
129
+ partitioned.forEach((kind, allocation) => map.set(allocation, kind));
130
+ }
131
+ kindMapCache.set(cart, map);
132
+ return map;
133
+ };
134
+ const resolveAllocationKind = (allocation, cart) => {
135
+ if ((allocation === null || allocation === void 0 ? void 0 : allocation.targetType) === DiscountApplicationTargetType.ShippingLine) {
136
+ return "shipping";
137
+ }
138
+ if ((allocation === null || allocation === void 0 ? void 0 : allocation.targetType) != null) {
139
+ return "merchandise";
140
+ }
141
+ const kindMap = buildAllocationKindMap(cart);
142
+ const kind = kindMap === null || kindMap === void 0 ? void 0 : kindMap.get(allocation);
143
+ if (kind)
144
+ return kind;
145
+ return inferShippingWhenTargetTypeMissing(allocation, cart)
146
+ ? "shipping"
147
+ : "merchandise";
148
+ };
149
+ export const isShippingDiscountAllocation = (allocation, cart) => resolveAllocationKind(allocation, cart) === "shipping";
150
+ export const isMerchandiseDiscountAllocation = (allocation, cart) => resolveAllocationKind(allocation, cart) === "merchandise";
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=discountAllocation.util.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discountAllocation.util.test.d.ts","sourceRoot":"","sources":["../../lib/discountAllocation.util.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,200 @@
1
+ import { DiscountApplicationTargetType, } from "app-studio-types";
2
+ import { isMerchandiseDiscountAllocation, isShippingDiscountAllocation, } from "./discountAllocation.util";
3
+ const naturalLifeDeliveryGroups = [
4
+ {
5
+ deliveryOptions: [
6
+ {
7
+ title: "Ground Shipping",
8
+ estimatedCost: { amount: "7.95", currencyCode: "USD" },
9
+ },
10
+ {
11
+ title: "Express Shipping",
12
+ estimatedCost: { amount: "18.95", currencyCode: "USD" },
13
+ },
14
+ ],
15
+ },
16
+ ];
17
+ const naturalLifeFreeShippingCost = {
18
+ subtotalAmount: { amount: "14.00", currencyCode: "USD" },
19
+ totalAmount: { amount: "14.00", currencyCode: "USD" },
20
+ };
21
+ describe("discountAllocation.util", () => {
22
+ describe("isShippingDiscountAllocation", () => {
23
+ it("returns true when targetType is SHIPPING_LINE", () => {
24
+ const allocation = {
25
+ targetType: DiscountApplicationTargetType.ShippingLine,
26
+ discountedAmount: { amount: "5.00", currencyCode: "USD" },
27
+ };
28
+ expect(isShippingDiscountAllocation(allocation)).toBe(true);
29
+ expect(isMerchandiseDiscountAllocation(allocation)).toBe(false);
30
+ });
31
+ it("returns false when targetType is LINE_ITEM", () => {
32
+ const allocation = {
33
+ targetType: DiscountApplicationTargetType.LineItem,
34
+ discountedAmount: { amount: "10.00", currencyCode: "USD" },
35
+ };
36
+ expect(isShippingDiscountAllocation(allocation)).toBe(false);
37
+ expect(isMerchandiseDiscountAllocation(allocation)).toBe(true);
38
+ });
39
+ it("infers shipping when targetType is missing and amount matches a delivery option (TICKET-4028)", () => {
40
+ const allocation = {
41
+ discountedAmount: { amount: "7.95", currencyCode: "USD" },
42
+ code: "CEXFS9P882N",
43
+ };
44
+ const cart = {
45
+ deliveryGroups: naturalLifeDeliveryGroups,
46
+ cost: naturalLifeFreeShippingCost,
47
+ };
48
+ expect(isShippingDiscountAllocation(allocation, cart)).toBe(true);
49
+ expect(isMerchandiseDiscountAllocation(allocation, cart)).toBe(false);
50
+ });
51
+ it("infers shipping without cart.cost when amount matches delivery (legacy fallback)", () => {
52
+ const allocation = {
53
+ discountedAmount: { amount: "7.95", currencyCode: "USD" },
54
+ code: "CEXFS9P882N",
55
+ };
56
+ const cart = { deliveryGroups: naturalLifeDeliveryGroups };
57
+ expect(isShippingDiscountAllocation(allocation, cart)).toBe(true);
58
+ expect(isMerchandiseDiscountAllocation(allocation, cart)).toBe(false);
59
+ });
60
+ it("treats missing targetType as merchandise when amount equals shipping but total dropped vs subtotal", () => {
61
+ const allocation = {
62
+ discountedAmount: { amount: "7.95", currencyCode: "USD" },
63
+ code: "SAVE795",
64
+ };
65
+ const cart = {
66
+ deliveryGroups: naturalLifeDeliveryGroups,
67
+ cost: {
68
+ subtotalAmount: { amount: "14.00", currencyCode: "USD" },
69
+ totalAmount: { amount: "6.05", currencyCode: "USD" },
70
+ },
71
+ };
72
+ expect(isShippingDiscountAllocation(allocation, cart)).toBe(false);
73
+ expect(isMerchandiseDiscountAllocation(allocation, cart)).toBe(true);
74
+ });
75
+ it("treats missing targetType as merchandise when amount is less than shipping and total exceeds subtotal", () => {
76
+ const allocation = {
77
+ discountedAmount: { amount: "5.00", currencyCode: "USD" },
78
+ code: "SAVE5",
79
+ };
80
+ const cart = {
81
+ deliveryGroups: naturalLifeDeliveryGroups,
82
+ cost: {
83
+ subtotalAmount: { amount: "50.00", currencyCode: "USD" },
84
+ totalAmount: { amount: "52.95", currencyCode: "USD" },
85
+ },
86
+ };
87
+ expect(isShippingDiscountAllocation(allocation, cart)).toBe(false);
88
+ expect(isMerchandiseDiscountAllocation(allocation, cart)).toBe(true);
89
+ });
90
+ it("infers shipping when total exceeds subtotal and amount exactly matches delivery cost", () => {
91
+ const allocation = {
92
+ discountedAmount: { amount: "7.95", currencyCode: "USD" },
93
+ code: "FREESHIP",
94
+ };
95
+ const cart = {
96
+ deliveryGroups: naturalLifeDeliveryGroups,
97
+ cost: {
98
+ subtotalAmount: { amount: "50.00", currencyCode: "USD" },
99
+ totalAmount: { amount: "57.95", currencyCode: "USD" },
100
+ },
101
+ };
102
+ expect(isShippingDiscountAllocation(allocation, cart)).toBe(true);
103
+ expect(isMerchandiseDiscountAllocation(allocation, cart)).toBe(false);
104
+ });
105
+ it("infers shipping when total equals subtotal despite delivery cost mismatch (FREESHIPPING zeroed rates)", () => {
106
+ const allocation = {
107
+ discountedAmount: { amount: "10.00", currencyCode: "USD" },
108
+ code: "FREESHIPPING",
109
+ };
110
+ const cart = {
111
+ deliveryGroups: [
112
+ {
113
+ deliveryOptions: [
114
+ {
115
+ title: "Standard",
116
+ estimatedCost: { amount: "0.0", currencyCode: "USD" },
117
+ },
118
+ {
119
+ title: "Express Shipping",
120
+ estimatedCost: { amount: "0.0", currencyCode: "USD" },
121
+ },
122
+ ],
123
+ },
124
+ ],
125
+ cost: {
126
+ subtotalAmount: { amount: "50.0", currencyCode: "USD" },
127
+ totalAmount: { amount: "50.0", currencyCode: "USD" },
128
+ },
129
+ };
130
+ expect(isShippingDiscountAllocation(allocation, cart)).toBe(true);
131
+ expect(isMerchandiseDiscountAllocation(allocation, cart)).toBe(false);
132
+ });
133
+ it("infers shipping for single allocation when total equals subtotal (unchanged merchandise total)", () => {
134
+ const allocation = {
135
+ discountedAmount: { amount: "10.00", currencyCode: "USD" },
136
+ code: "SAVE10",
137
+ };
138
+ const cart = {
139
+ deliveryGroups: naturalLifeDeliveryGroups,
140
+ cost: naturalLifeFreeShippingCost,
141
+ };
142
+ expect(isShippingDiscountAllocation(allocation, cart)).toBe(true);
143
+ expect(isMerchandiseDiscountAllocation(allocation, cart)).toBe(false);
144
+ });
145
+ it("treats missing targetType as merchandise when cart has no deliveryGroups", () => {
146
+ const allocation = {
147
+ discountedAmount: { amount: "7.95", currencyCode: "USD" },
148
+ code: "CEXFS9P882N",
149
+ };
150
+ expect(isShippingDiscountAllocation(allocation, {})).toBe(false);
151
+ expect(isMerchandiseDiscountAllocation(allocation, {})).toBe(true);
152
+ });
153
+ it("treats missing targetType as merchandise when deliveryGroups is empty (pre-checkout)", () => {
154
+ const allocation = {
155
+ discountedAmount: { amount: "7.95", currencyCode: "GBP" },
156
+ code: "PROMO",
157
+ };
158
+ const cart = {
159
+ deliveryGroups: [],
160
+ cost: {
161
+ subtotalAmount: { amount: "5.7", currencyCode: "GBP" },
162
+ totalAmount: { amount: "5.7", currencyCode: "GBP" },
163
+ },
164
+ };
165
+ expect(isShippingDiscountAllocation(allocation, cart)).toBe(false);
166
+ expect(isMerchandiseDiscountAllocation(allocation, cart)).toBe(true);
167
+ });
168
+ it("partitions stacked $10 off + $10 free ship when targetType is missing (TICKET-4028)", () => {
169
+ const merchAllocation = {
170
+ discountedAmount: { amount: "10.00", currencyCode: "USD" },
171
+ code: "SAVE10",
172
+ };
173
+ const shipAllocation = {
174
+ discountedAmount: { amount: "10.00", currencyCode: "USD" },
175
+ code: "FREESHIP",
176
+ };
177
+ const cart = {
178
+ discountAllocations: [merchAllocation, shipAllocation],
179
+ deliveryGroups: [
180
+ {
181
+ deliveryOptions: [
182
+ {
183
+ title: "Standard",
184
+ estimatedCost: { amount: "10.00", currencyCode: "USD" },
185
+ },
186
+ ],
187
+ },
188
+ ],
189
+ cost: {
190
+ subtotalAmount: { amount: "100.00", currencyCode: "USD" },
191
+ totalAmount: { amount: "90.00", currencyCode: "USD" },
192
+ },
193
+ };
194
+ expect(isMerchandiseDiscountAllocation(merchAllocation, cart)).toBe(true);
195
+ expect(isShippingDiscountAllocation(merchAllocation, cart)).toBe(false);
196
+ expect(isShippingDiscountAllocation(shipAllocation, cart)).toBe(true);
197
+ expect(isMerchandiseDiscountAllocation(shipAllocation, cart)).toBe(false);
198
+ });
199
+ });
200
+ });
@@ -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,EAO9B,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"}
1
+ {"version":3,"file":"variablesCart.util.d.ts","sourceRoot":"","sources":["../../lib/variablesCart.util.ts"],"names":[],"mappings":"AACA,OAAO,EACL,SAAS,EACT,sBAAsB,EACtB,6BAA6B,EAE9B,MAAM,kBAAkB,CAAA;AAMzB,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;AA4FD,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"}
@@ -1,5 +1,4 @@
1
- // @ts-nocheck
2
- import { DiscountApplicationTargetType, } from "app-studio-types";
1
+ import { isMerchandiseDiscountAllocation, isShippingDiscountAllocation, } from "./discountAllocation.util";
3
2
  export const getSubscriptionPriceDetails = ({ totalAmount, quantity, sellingPlanAllocation = { priceAdjustments: [] }, }) => {
4
3
  var _a;
5
4
  const isSubscription = ((_a = sellingPlanAllocation === null || sellingPlanAllocation === void 0 ? void 0 : sellingPlanAllocation.priceAdjustments) === null || _a === void 0 ? void 0 : _a.length) > 0;
@@ -34,7 +33,7 @@ const getOrderLevelDiscounts = (cart) => {
34
33
  return [];
35
34
  // We'll build a map of code -> { amount, isAutomatic }
36
35
  const discountMap = discountAllocations
37
- .filter((discount) => discount.targetType !== DiscountApplicationTargetType.ShippingLine)
36
+ .filter((discount) => isMerchandiseDiscountAllocation(discount, cart))
38
37
  .reduce((acc, discount) => {
39
38
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
40
39
  // Figure out the code for this discount
@@ -87,7 +86,7 @@ const getShippingDiscounts = (cart) => {
87
86
  if (!discountAllocations)
88
87
  return [];
89
88
  return discountAllocations
90
- .filter((discount) => discount.targetType === DiscountApplicationTargetType.ShippingLine)
89
+ .filter((discount) => isShippingDiscountAllocation(discount, cart))
91
90
  .map((discount) => {
92
91
  var _a;
93
92
  return ({
@@ -103,6 +103,91 @@ describe("cart-provider.util", () => {
103
103
  const result = getVariablesCalculatedCartData(mockCart);
104
104
  expect(result.isFreeShipping).toBe(true);
105
105
  });
106
+ it("should exclude shipping discount without targetType from merchandise totals (TICKET-4028)", () => {
107
+ const mockCart = Object.assign(Object.assign({}, baseCartData), { discounts: ["CEXFS9P882N"], cost: {
108
+ subtotalAmount: { amount: "14.00", currencyCode: "USD" },
109
+ totalAmount: { amount: "14.00", currencyCode: "USD" },
110
+ totalTaxAmount: { amount: "0.00", currencyCode: "USD" },
111
+ }, items: [
112
+ {
113
+ id: "line1",
114
+ quantity: 1,
115
+ productId: "prod1",
116
+ variantId: "var1",
117
+ price: 14.0,
118
+ compareAtPrice: 14.0,
119
+ currencyCode: "USD",
120
+ discounts: [],
121
+ cost: { totalAmount: { amount: "14.00", currencyCode: "USD" } },
122
+ },
123
+ ], discountAllocations: [
124
+ {
125
+ discountedAmount: { amount: "7.95", currencyCode: "USD" },
126
+ code: "CEXFS9P882N",
127
+ },
128
+ ], deliveryGroups: [
129
+ {
130
+ deliveryOptions: [
131
+ {
132
+ title: "Ground Shipping",
133
+ estimatedCost: { amount: "7.95", currencyCode: "USD" },
134
+ },
135
+ {
136
+ title: "Express Shipping",
137
+ estimatedCost: { amount: "18.95", currencyCode: "USD" },
138
+ },
139
+ ],
140
+ },
141
+ ] });
142
+ const result = getVariablesCalculatedCartData(mockCart);
143
+ expect(result.orderAndLineItemDiscounts).toHaveLength(0);
144
+ expect(result.discountsTotalAmount).toBe(0);
145
+ expect(result.isFreeShipping).toBe(true);
146
+ expect(result.totalDiscountedPrice).toBe(14);
147
+ });
148
+ it("should exclude shipping from merchandise totals when merch + free ship stack (TICKET-4028)", () => {
149
+ const mockCart = Object.assign(Object.assign({}, baseCartData), { discounts: ["SAVE10", "FREESHIP"], cost: {
150
+ subtotalAmount: { amount: "100.00", currencyCode: "USD" },
151
+ totalAmount: { amount: "90.00", currencyCode: "USD" },
152
+ totalTaxAmount: { amount: "0.00", currencyCode: "USD" },
153
+ }, items: [
154
+ {
155
+ id: "line1",
156
+ quantity: 1,
157
+ productId: "prod1",
158
+ variantId: "var1",
159
+ price: 100.0,
160
+ compareAtPrice: 100.0,
161
+ currencyCode: "USD",
162
+ discounts: [],
163
+ cost: { totalAmount: { amount: "100.00", currencyCode: "USD" } },
164
+ },
165
+ ], discountAllocations: [
166
+ {
167
+ discountedAmount: { amount: "10.00", currencyCode: "USD" },
168
+ code: "SAVE10",
169
+ },
170
+ {
171
+ discountedAmount: { amount: "10.00", currencyCode: "USD" },
172
+ code: "FREESHIP",
173
+ },
174
+ ], deliveryGroups: [
175
+ {
176
+ deliveryOptions: [
177
+ {
178
+ title: "Standard",
179
+ estimatedCost: { amount: "10.00", currencyCode: "USD" },
180
+ },
181
+ ],
182
+ },
183
+ ] });
184
+ const result = getVariablesCalculatedCartData(mockCart);
185
+ expect(result.orderAndLineItemDiscounts).toHaveLength(1);
186
+ expect(result.orderAndLineItemDiscounts[0].amount).toBe(10);
187
+ expect(result.discountsTotalAmount).toBe(10);
188
+ expect(result.isFreeShipping).toBe(true);
189
+ expect(result.totalDiscountedPrice).toBe(90);
190
+ });
106
191
  it("should calculate total discounted price correctly", () => {
107
192
  const mockCart = Object.assign(Object.assign({}, baseCartData), { discounts: ["Discount10"], items: [
108
193
  {
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tapcart/mobile-components",
3
- "version": "0.14.0",
3
+ "version": "0.14.5",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "style": "dist/styles.css",