@shopify/shop-minis-react 0.13.1 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/dist/_virtual/index2.js +4 -4
  2. package/dist/_virtual/index3.js +2 -5
  3. package/dist/_virtual/index3.js.map +1 -1
  4. package/dist/_virtual/index4.js +2 -2
  5. package/dist/_virtual/index5.js +3 -2
  6. package/dist/_virtual/index5.js.map +1 -1
  7. package/dist/_virtual/index6.js +2 -2
  8. package/dist/_virtual/index7.js +2 -3
  9. package/dist/_virtual/index7.js.map +1 -1
  10. package/dist/_virtual/index8.js +2 -2
  11. package/dist/components/atoms/list.js.map +1 -1
  12. package/dist/components/commerce/product-link.js.map +1 -1
  13. package/dist/components/commerce/search.js.map +1 -1
  14. package/dist/components/navigation/transition-link.js.map +1 -1
  15. package/dist/internal/components/product-review-stars.js.map +1 -1
  16. package/dist/shop-minis-react/node_modules/.pnpm/@radix-ui_react-use-is-hydrated@0.1.0_@types_react@19.1.6_react@19.1.0/node_modules/@radix-ui/react-use-is-hydrated/dist/index.js +1 -1
  17. package/dist/shop-minis-react/node_modules/.pnpm/@videojs_xhr@2.7.0/node_modules/@videojs/xhr/lib/index.js +1 -1
  18. package/dist/shop-minis-react/node_modules/.pnpm/@xmldom_xmldom@0.8.10/node_modules/@xmldom/xmldom/lib/index.js +1 -1
  19. package/dist/shop-minis-react/node_modules/.pnpm/color-convert@3.1.3/node_modules/color-convert/conversions.js +422 -0
  20. package/dist/shop-minis-react/node_modules/.pnpm/color-convert@3.1.3/node_modules/color-convert/conversions.js.map +1 -0
  21. package/dist/shop-minis-react/node_modules/.pnpm/color-convert@3.1.3/node_modules/color-convert/index.js +36 -0
  22. package/dist/shop-minis-react/node_modules/.pnpm/color-convert@3.1.3/node_modules/color-convert/index.js.map +1 -0
  23. package/dist/shop-minis-react/node_modules/.pnpm/color-convert@3.1.3/node_modules/color-convert/route.js +47 -0
  24. package/dist/shop-minis-react/node_modules/.pnpm/color-convert@3.1.3/node_modules/color-convert/route.js.map +1 -0
  25. package/dist/shop-minis-react/node_modules/.pnpm/color-name@2.1.0/node_modules/color-name/index.js +156 -0
  26. package/dist/shop-minis-react/node_modules/.pnpm/color-name@2.1.0/node_modules/color-name/index.js.map +1 -0
  27. package/dist/shop-minis-react/node_modules/.pnpm/color-string@2.1.4/node_modules/color-string/index.js +106 -0
  28. package/dist/shop-minis-react/node_modules/.pnpm/color-string@2.1.4/node_modules/color-string/index.js.map +1 -0
  29. package/dist/shop-minis-react/node_modules/.pnpm/color@5.0.3/node_modules/color/index.js +263 -0
  30. package/dist/shop-minis-react/node_modules/.pnpm/color@5.0.3/node_modules/color/index.js.map +1 -0
  31. package/dist/shop-minis-react/node_modules/.pnpm/mpd-parser@1.3.1/node_modules/mpd-parser/dist/mpd-parser.es.js +1 -1
  32. package/dist/shop-minis-react/node_modules/.pnpm/querystringify@2.2.0/node_modules/querystringify/index.js +1 -1
  33. package/dist/shop-minis-react/node_modules/.pnpm/use-sync-external-store@1.5.0_react@19.1.0/node_modules/use-sync-external-store/shim/index.js +1 -1
  34. package/dist/shop-minis-react/node_modules/.pnpm/video.js@8.23.3/node_modules/video.js/dist/video.es.js +1 -1
  35. package/dist/utils/colors.js +1 -1
  36. package/package.json +2 -3
  37. package/src/components/atoms/list.tsx +4 -5
  38. package/src/components/commerce/product-link.tsx +2 -1
  39. package/src/components/commerce/search.tsx +6 -3
  40. package/src/components/navigation/transition-link.tsx +1 -2
  41. package/src/internal/components/product-review-stars.tsx +1 -2
  42. package/dist/_virtual/index10.js +0 -5
  43. package/dist/_virtual/index10.js.map +0 -1
  44. package/dist/_virtual/index11.js +0 -5
  45. package/dist/_virtual/index11.js.map +0 -1
  46. package/dist/_virtual/index9.js +0 -5
  47. package/dist/_virtual/index9.js.map +0 -1
  48. package/dist/shop-minis-react/node_modules/.pnpm/color-convert@2.0.1/node_modules/color-convert/conversions.js +0 -308
  49. package/dist/shop-minis-react/node_modules/.pnpm/color-convert@2.0.1/node_modules/color-convert/conversions.js.map +0 -1
  50. package/dist/shop-minis-react/node_modules/.pnpm/color-convert@2.0.1/node_modules/color-convert/index.js +0 -41
  51. package/dist/shop-minis-react/node_modules/.pnpm/color-convert@2.0.1/node_modules/color-convert/index.js.map +0 -1
  52. package/dist/shop-minis-react/node_modules/.pnpm/color-convert@2.0.1/node_modules/color-convert/route.js +0 -53
  53. package/dist/shop-minis-react/node_modules/.pnpm/color-convert@2.0.1/node_modules/color-convert/route.js.map +0 -1
  54. package/dist/shop-minis-react/node_modules/.pnpm/color-name@1.1.4/node_modules/color-name/index.js +0 -157
  55. package/dist/shop-minis-react/node_modules/.pnpm/color-name@1.1.4/node_modules/color-name/index.js.map +0 -1
  56. package/dist/shop-minis-react/node_modules/.pnpm/color-string@1.9.1/node_modules/color-string/index.js +0 -103
  57. package/dist/shop-minis-react/node_modules/.pnpm/color-string@1.9.1/node_modules/color-string/index.js.map +0 -1
  58. package/dist/shop-minis-react/node_modules/.pnpm/color@4.2.3/node_modules/color/index.js +0 -269
  59. package/dist/shop-minis-react/node_modules/.pnpm/color@4.2.3/node_modules/color/index.js.map +0 -1
  60. package/dist/shop-minis-react/node_modules/.pnpm/is-arrayish@0.3.2/node_modules/is-arrayish/index.js +0 -10
  61. package/dist/shop-minis-react/node_modules/.pnpm/is-arrayish@0.3.2/node_modules/is-arrayish/index.js.map +0 -1
  62. package/dist/shop-minis-react/node_modules/.pnpm/simple-swizzle@0.2.2/node_modules/simple-swizzle/index.js +0 -23
  63. package/dist/shop-minis-react/node_modules/.pnpm/simple-swizzle@0.2.2/node_modules/simple-swizzle/index.js.map +0 -1
@@ -1,8 +1,8 @@
1
1
  import { getDefaultExportFromCjs as r } from "./_commonjsHelpers.js";
2
- import { __require as o } from "../shop-minis-react/node_modules/.pnpm/color@4.2.3/node_modules/color/index.js";
3
- var t = /* @__PURE__ */ o();
4
- const l = /* @__PURE__ */ r(t);
2
+ import { __require as o } from "../shop-minis-react/node_modules/.pnpm/@videojs_xhr@2.7.0/node_modules/@videojs/xhr/lib/index.js";
3
+ var t = o();
4
+ const a = /* @__PURE__ */ r(t);
5
5
  export {
6
- l as default
6
+ a as default
7
7
  };
8
8
  //# sourceMappingURL=index2.js.map
@@ -1,8 +1,5 @@
1
- import { getDefaultExportFromCjs as r } from "./_commonjsHelpers.js";
2
- import { __require as o } from "../shop-minis-react/node_modules/.pnpm/@videojs_xhr@2.7.0/node_modules/@videojs/xhr/lib/index.js";
3
- var t = o();
4
- const a = /* @__PURE__ */ r(t);
1
+ var r = {};
5
2
  export {
6
- a as default
3
+ r as __exports
7
4
  };
8
5
  //# sourceMappingURL=index3.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index3.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}
1
+ {"version":3,"file":"index3.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
@@ -1,5 +1,5 @@
1
- var r = {};
1
+ var e = { exports: {} };
2
2
  export {
3
- r as __exports
3
+ e as __module
4
4
  };
5
5
  //# sourceMappingURL=index4.js.map
@@ -1,5 +1,6 @@
1
- var e = { exports: {} };
1
+ import { __require as r } from "../shop-minis-react/node_modules/.pnpm/@xmldom_xmldom@0.8.10/node_modules/@xmldom/xmldom/lib/index.js";
2
+ var i = r();
2
3
  export {
3
- e as __module
4
+ i as l
4
5
  };
5
6
  //# sourceMappingURL=index5.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index5.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
1
+ {"version":3,"file":"index5.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
@@ -1,6 +1,6 @@
1
- import { __require as r } from "../shop-minis-react/node_modules/.pnpm/@xmldom_xmldom@0.8.10/node_modules/@xmldom/xmldom/lib/index.js";
1
+ import { __require as r } from "../shop-minis-react/node_modules/.pnpm/use-sync-external-store@1.5.0_react@19.1.0/node_modules/use-sync-external-store/shim/index.js";
2
2
  var i = r();
3
3
  export {
4
- i as l
4
+ i as s
5
5
  };
6
6
  //# sourceMappingURL=index6.js.map
@@ -1,6 +1,5 @@
1
- import { __require as r } from "../shop-minis-react/node_modules/.pnpm/use-sync-external-store@1.5.0_react@19.1.0/node_modules/use-sync-external-store/shim/index.js";
2
- var i = r();
1
+ var r = {};
3
2
  export {
4
- i as s
3
+ r as __exports
5
4
  };
6
5
  //# sourceMappingURL=index7.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index7.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
1
+ {"version":3,"file":"index7.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
@@ -1,5 +1,5 @@
1
- var o = { exports: {} };
1
+ var e = { exports: {} };
2
2
  export {
3
- o as __module
3
+ e as __module
4
4
  };
5
5
  //# sourceMappingURL=index8.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"list.js","sources":["../../../src/components/atoms/list.tsx"],"sourcesContent":["import {useCallback, useEffect, useRef} from 'react'\n\nimport {Virtuoso, VirtuosoProps} from 'react-virtuoso'\n\nimport {RefreshIndicator} from '../../internal/components/refresh-indicator'\nimport {usePullToRefresh} from '../../internal/usePullToRefresh'\nimport {findVirtuosoScrollableElement} from '../../internal/utils/virtuoso-dom'\nimport {cn} from '../../lib/utils'\nimport '../../styles/utilities.css'\nimport {Skeleton} from '../ui/skeleton'\n\nconst DEFAULT_REFRESH_PULL_THRESHOLD = 200\nconst ELEMENT_BIND_DELAY = 100\n\nexport interface ListDocProps<T = any> {\n /** Array of items to render */\n items: T[]\n /** Function to render each item */\n renderItem: (item: T, index: number) => React.ReactNode\n /** Height of the list container */\n height?: string | number\n /** Show scrollbar (default: false) */\n showScrollbar?: boolean\n /** Header element rendered at the top of the list */\n header?: React.ReactNode\n /** Callback to fetch more items when scrolled to bottom */\n fetchMore?: () => Promise<void>\n /** Custom loading component shown while fetching more */\n loadingComponent?: React.ReactNode\n /** Callback for pull-to-refresh */\n onRefresh?: () => Promise<void>\n /** Whether the list is currently refreshing */\n refreshing?: boolean\n /** Enable pull-to-refresh gesture (default: true) */\n enablePullToRefresh?: boolean\n}\n\nexport interface ListProps<T = any>\n extends Omit<\n VirtuosoProps<T, unknown>,\n 'data' | 'itemContent' | 'endReached'\n > {\n items: T[]\n renderItem: (item: T, index: number) => React.ReactNode\n showScrollbar?: boolean\n header?: React.ReactNode\n fetchMore?: () => Promise<void>\n loadingComponent?: React.ReactNode\n onRefresh?: () => Promise<void>\n refreshing?: boolean\n enablePullToRefresh?: boolean\n}\n\nexport function List<T = any>({\n items,\n height,\n renderItem,\n className,\n showScrollbar = false,\n header,\n fetchMore,\n loadingComponent,\n onRefresh,\n refreshing,\n enablePullToRefresh = true,\n ...virtuosoProps\n}: ListProps<T>) {\n const inFlightFetchMoreRef = useRef<Promise<void> | null>(null)\n const virtuosoRef = useRef<any>(null)\n const containerRef = useRef<HTMLDivElement>(null)\n\n const {state: pullToRefreshState, bindToElement} = usePullToRefresh({\n onRefresh,\n threshold: DEFAULT_REFRESH_PULL_THRESHOLD,\n enabled: enablePullToRefresh && Boolean(onRefresh),\n })\n\n const _fetchMore = useCallback(() => {\n // Dedupe concurrent calls by returning the same in-flight promise\n if (inFlightFetchMoreRef.current) return\n\n const current = Promise.resolve(fetchMore?.()).finally(() => {\n // Only clear if this is still the most recent promise\n if (inFlightFetchMoreRef.current === current) {\n inFlightFetchMoreRef.current = null\n }\n })\n\n inFlightFetchMoreRef.current = current\n }, [fetchMore])\n\n const itemContent = useCallback(\n (index: number, item: T) => <>{renderItem(item, index)}</>,\n [renderItem]\n )\n\n const Footer = useCallback(() => {\n if (!fetchMore) return null\n\n return loadingComponent ?? <Skeleton className=\"h-10 w-full p-8\" />\n }, [loadingComponent, fetchMore])\n\n const classNames = cn(showScrollbar ? undefined : 'no-scrollbars', className)\n\n useEffect(() => {\n if (containerRef.current && enablePullToRefresh && onRefresh) {\n let cleanup: (() => void) | undefined\n\n const findAndBind = () => {\n if (!containerRef.current) return\n\n const scrollableElement = findVirtuosoScrollableElement(\n containerRef.current\n )\n cleanup = bindToElement(scrollableElement)\n }\n\n const timeoutId = setTimeout(findAndBind, ELEMENT_BIND_DELAY)\n\n return () => {\n clearTimeout(timeoutId)\n if (cleanup) cleanup()\n }\n }\n return undefined\n }, [bindToElement, enablePullToRefresh, onRefresh])\n\n const EnhancedHeader = useCallback(() => {\n const effectivePullDistance = refreshing\n ? Math.max(pullToRefreshState.pullDistance, 140)\n : pullToRefreshState.pullDistance\n\n const refreshHeaderHeight = Math.min(\n Math.max(effectivePullDistance, 0),\n 140\n )\n\n return (\n <>\n {enablePullToRefresh && onRefresh && (\n <div\n className=\"flex items-center justify-center\"\n style={{\n height: refreshHeaderHeight,\n overflow: 'hidden',\n }}\n >\n <RefreshIndicator\n pullDistance={pullToRefreshState.pullDistance}\n threshold={DEFAULT_REFRESH_PULL_THRESHOLD}\n isRefreshing={refreshing ?? false}\n canRefresh={pullToRefreshState.canRefresh}\n className=\"relative top-0 inset-x-auto\"\n />\n </div>\n )}\n {header && <div>{header}</div>}\n </>\n )\n }, [header, enablePullToRefresh, onRefresh, pullToRefreshState, refreshing])\n\n return (\n <div\n ref={containerRef}\n className={cn('relative transition-all duration-200', classNames)}\n style={{\n height,\n }}\n >\n <Virtuoso\n ref={virtuosoRef}\n className=\"h-full w-full\"\n data={items}\n itemContent={itemContent}\n components={{\n Header: EnhancedHeader,\n Footer,\n }}\n endReached={fetchMore ? _fetchMore : undefined}\n {...virtuosoProps}\n />\n </div>\n )\n}\n"],"names":["DEFAULT_REFRESH_PULL_THRESHOLD","ELEMENT_BIND_DELAY","List","items","height","renderItem","className","showScrollbar","header","fetchMore","loadingComponent","onRefresh","refreshing","enablePullToRefresh","virtuosoProps","inFlightFetchMoreRef","useRef","virtuosoRef","containerRef","pullToRefreshState","bindToElement","usePullToRefresh","_fetchMore","useCallback","current","itemContent","index","item","Footer","jsx","Skeleton","classNames","cn","useEffect","cleanup","timeoutId","scrollableElement","findVirtuosoScrollableElement","EnhancedHeader","effectivePullDistance","refreshHeaderHeight","jsxs","Fragment","RefreshIndicator","Virtuoso"],"mappings":"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"}
1
+ {"version":3,"file":"list.js","sources":["../../../src/components/atoms/list.tsx"],"sourcesContent":["import {useCallback, useEffect, useRef} from 'react'\n\nimport {Virtuoso, VirtuosoProps} from 'react-virtuoso'\n\nimport {RefreshIndicator} from '../../internal/components/refresh-indicator'\nimport {usePullToRefresh} from '../../internal/usePullToRefresh'\nimport {findVirtuosoScrollableElement} from '../../internal/utils/virtuoso-dom'\nimport {cn} from '../../lib/utils'\nimport '../../styles/utilities.css'\nimport {Skeleton} from '../ui/skeleton'\n\nconst DEFAULT_REFRESH_PULL_THRESHOLD = 200\nconst ELEMENT_BIND_DELAY = 100\n\nexport interface ListDocProps<T = any> {\n /** Array of items to render */\n items: T[]\n /** Function to render each item */\n renderItem: (item: T, index: number) => React.ReactNode\n /** Height of the list container */\n height?: string | number\n /** Show scrollbar (default: false) */\n showScrollbar?: boolean\n /** Header element rendered at the top of the list */\n header?: React.ReactNode\n /** Callback to fetch more items when scrolled to bottom */\n fetchMore?: () => Promise<void>\n /** Custom loading component shown while fetching more */\n loadingComponent?: React.ReactNode\n /** Callback for pull-to-refresh */\n onRefresh?: () => Promise<void>\n /** Whether the list is currently refreshing */\n refreshing?: boolean\n /** Enable pull-to-refresh gesture (default: true) */\n enablePullToRefresh?: boolean\n}\n\nexport interface ListProps<T = any> extends Omit<\n VirtuosoProps<T, unknown>,\n 'data' | 'itemContent' | 'endReached'\n> {\n items: T[]\n renderItem: (item: T, index: number) => React.ReactNode\n showScrollbar?: boolean\n header?: React.ReactNode\n fetchMore?: () => Promise<void>\n loadingComponent?: React.ReactNode\n onRefresh?: () => Promise<void>\n refreshing?: boolean\n enablePullToRefresh?: boolean\n}\n\nexport function List<T = any>({\n items,\n height,\n renderItem,\n className,\n showScrollbar = false,\n header,\n fetchMore,\n loadingComponent,\n onRefresh,\n refreshing,\n enablePullToRefresh = true,\n ...virtuosoProps\n}: ListProps<T>) {\n const inFlightFetchMoreRef = useRef<Promise<void> | null>(null)\n const virtuosoRef = useRef<any>(null)\n const containerRef = useRef<HTMLDivElement>(null)\n\n const {state: pullToRefreshState, bindToElement} = usePullToRefresh({\n onRefresh,\n threshold: DEFAULT_REFRESH_PULL_THRESHOLD,\n enabled: enablePullToRefresh && Boolean(onRefresh),\n })\n\n const _fetchMore = useCallback(() => {\n // Dedupe concurrent calls by returning the same in-flight promise\n if (inFlightFetchMoreRef.current) return\n\n const current = Promise.resolve(fetchMore?.()).finally(() => {\n // Only clear if this is still the most recent promise\n if (inFlightFetchMoreRef.current === current) {\n inFlightFetchMoreRef.current = null\n }\n })\n\n inFlightFetchMoreRef.current = current\n }, [fetchMore])\n\n const itemContent = useCallback(\n (index: number, item: T) => <>{renderItem(item, index)}</>,\n [renderItem]\n )\n\n const Footer = useCallback(() => {\n if (!fetchMore) return null\n\n return loadingComponent ?? <Skeleton className=\"h-10 w-full p-8\" />\n }, [loadingComponent, fetchMore])\n\n const classNames = cn(showScrollbar ? undefined : 'no-scrollbars', className)\n\n useEffect(() => {\n if (containerRef.current && enablePullToRefresh && onRefresh) {\n let cleanup: (() => void) | undefined\n\n const findAndBind = () => {\n if (!containerRef.current) return\n\n const scrollableElement = findVirtuosoScrollableElement(\n containerRef.current\n )\n cleanup = bindToElement(scrollableElement)\n }\n\n const timeoutId = setTimeout(findAndBind, ELEMENT_BIND_DELAY)\n\n return () => {\n clearTimeout(timeoutId)\n if (cleanup) cleanup()\n }\n }\n return undefined\n }, [bindToElement, enablePullToRefresh, onRefresh])\n\n const EnhancedHeader = useCallback(() => {\n const effectivePullDistance = refreshing\n ? Math.max(pullToRefreshState.pullDistance, 140)\n : pullToRefreshState.pullDistance\n\n const refreshHeaderHeight = Math.min(\n Math.max(effectivePullDistance, 0),\n 140\n )\n\n return (\n <>\n {enablePullToRefresh && onRefresh && (\n <div\n className=\"flex items-center justify-center\"\n style={{\n height: refreshHeaderHeight,\n overflow: 'hidden',\n }}\n >\n <RefreshIndicator\n pullDistance={pullToRefreshState.pullDistance}\n threshold={DEFAULT_REFRESH_PULL_THRESHOLD}\n isRefreshing={refreshing ?? false}\n canRefresh={pullToRefreshState.canRefresh}\n className=\"relative top-0 inset-x-auto\"\n />\n </div>\n )}\n {header && <div>{header}</div>}\n </>\n )\n }, [header, enablePullToRefresh, onRefresh, pullToRefreshState, refreshing])\n\n return (\n <div\n ref={containerRef}\n className={cn('relative transition-all duration-200', classNames)}\n style={{\n height,\n }}\n >\n <Virtuoso\n ref={virtuosoRef}\n className=\"h-full w-full\"\n data={items}\n itemContent={itemContent}\n components={{\n Header: EnhancedHeader,\n Footer,\n }}\n endReached={fetchMore ? _fetchMore : undefined}\n {...virtuosoProps}\n />\n </div>\n )\n}\n"],"names":["DEFAULT_REFRESH_PULL_THRESHOLD","ELEMENT_BIND_DELAY","List","items","height","renderItem","className","showScrollbar","header","fetchMore","loadingComponent","onRefresh","refreshing","enablePullToRefresh","virtuosoProps","inFlightFetchMoreRef","useRef","virtuosoRef","containerRef","pullToRefreshState","bindToElement","usePullToRefresh","_fetchMore","useCallback","current","itemContent","index","item","Footer","jsx","Skeleton","classNames","cn","useEffect","cleanup","timeoutId","scrollableElement","findVirtuosoScrollableElement","EnhancedHeader","effectivePullDistance","refreshHeaderHeight","jsxs","Fragment","RefreshIndicator","Virtuoso"],"mappings":";;;;;;;;;AAWA,MAAMA,IAAiC,KACjCC,IAAqB;AAwCpB,SAASC,EAAc;AAAA,EAC5B,OAAAC;AAAA,EACA,QAAAC;AAAA,EACA,YAAAC;AAAA,EACA,WAAAC;AAAA,EACA,eAAAC,IAAgB;AAAA,EAChB,QAAAC;AAAA,EACA,WAAAC;AAAA,EACA,kBAAAC;AAAA,EACA,WAAAC;AAAA,EACA,YAAAC;AAAA,EACA,qBAAAC,IAAsB;AAAA,EACtB,GAAGC;AACL,GAAiB;AACT,QAAAC,IAAuBC,EAA6B,IAAI,GACxDC,IAAcD,EAAY,IAAI,GAC9BE,IAAeF,EAAuB,IAAI,GAE1C,EAAC,OAAOG,GAAoB,eAAAC,EAAA,IAAiBC,EAAiB;AAAA,IAClE,WAAAV;AAAA,IACA,WAAWX;AAAA,IACX,SAASa,KAAuB,EAAQF;AAAA,EAAS,CAClD,GAEKW,IAAaC,EAAY,MAAM;AAEnC,QAAIR,EAAqB,QAAS;AAElC,UAAMS,IAAU,QAAQ,QAAQf,IAAa,CAAA,EAAE,QAAQ,MAAM;AAEvD,MAAAM,EAAqB,YAAYS,MACnCT,EAAqB,UAAU;AAAA,IACjC,CACD;AAED,IAAAA,EAAqB,UAAUS;AAAA,EAAA,GAC9B,CAACf,CAAS,CAAC,GAERgB,IAAcF;AAAA,IAClB,CAACG,GAAeC,6BAAe,UAAWtB,EAAAsB,GAAMD,CAAK,GAAE;AAAA,IACvD,CAACrB,CAAU;AAAA,EACb,GAEMuB,IAASL,EAAY,MACpBd,IAEEC,KAAoB,gBAAAmB,EAACC,GAAS,EAAA,WAAU,kBAAkB,CAAA,IAF1C,MAGtB,CAACpB,GAAkBD,CAAS,CAAC,GAE1BsB,IAAaC,EAAGzB,IAAgB,SAAY,iBAAiBD,CAAS;AAE5E,EAAA2B,EAAU,MAAM;AACV,QAAAf,EAAa,WAAWL,KAAuBF,GAAW;AACxD,UAAAuB;AAWE,YAAAC,IAAY,WATE,MAAM;AACpB,YAAA,CAACjB,EAAa,QAAS;AAE3B,cAAMkB,IAAoBC;AAAA,UACxBnB,EAAa;AAAA,QACf;AACA,QAAAgB,IAAUd,EAAcgB,CAAiB;AAAA,MAC3C,GAE0CnC,CAAkB;AAE5D,aAAO,MAAM;AACX,qBAAakC,CAAS,GAClBD,KAAiBA,EAAA;AAAA,MACvB;AAAA,IAAA;AAAA,EAGD,GAAA,CAACd,GAAeP,GAAqBF,CAAS,CAAC;AAE5C,QAAA2B,IAAiBf,EAAY,MAAM;AACjC,UAAAgB,IAAwB3B,IAC1B,KAAK,IAAIO,EAAmB,cAAc,GAAG,IAC7CA,EAAmB,cAEjBqB,IAAsB,KAAK;AAAA,MAC/B,KAAK,IAAID,GAAuB,CAAC;AAAA,MACjC;AAAA,IACF;AAEA,WAEK,gBAAAE,EAAAC,GAAA,EAAA,UAAA;AAAA,MAAA7B,KAAuBF,KACtB,gBAAAkB;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,WAAU;AAAA,UACV,OAAO;AAAA,YACL,QAAQW;AAAA,YACR,UAAU;AAAA,UACZ;AAAA,UAEA,UAAA,gBAAAX;AAAA,YAACc;AAAA,YAAA;AAAA,cACC,cAAcxB,EAAmB;AAAA,cACjC,WAAWnB;AAAA,cACX,cAAcY,KAAc;AAAA,cAC5B,YAAYO,EAAmB;AAAA,cAC/B,WAAU;AAAA,YAAA;AAAA,UAAA;AAAA,QACZ;AAAA,MACF;AAAA,MAEDX,KAAW,gBAAAqB,EAAA,OAAA,EAAK,UAAOrB,EAAA,CAAA;AAAA,IAAA,GAC1B;AAAA,EAAA,GAED,CAACA,GAAQK,GAAqBF,GAAWQ,GAAoBP,CAAU,CAAC;AAGzE,SAAA,gBAAAiB;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,KAAKX;AAAA,MACL,WAAWc,EAAG,wCAAwCD,CAAU;AAAA,MAChE,OAAO;AAAA,QACL,QAAA3B;AAAA,MACF;AAAA,MAEA,UAAA,gBAAAyB;AAAA,QAACe;AAAAA,QAAA;AAAA,UACC,KAAK3B;AAAA,UACL,WAAU;AAAA,UACV,MAAMd;AAAA,UACN,aAAAsB;AAAA,UACA,YAAY;AAAA,YACV,QAAQa;AAAA,YACR,QAAAV;AAAA,UACF;AAAA,UACA,YAAYnB,IAAYa,IAAa;AAAA,UACpC,GAAGR;AAAA,QAAA;AAAA,MAAA;AAAA,IACN;AAAA,EACF;AAEJ;"}
@@ -1 +1 @@
1
- {"version":3,"file":"product-link.js","sources":["../../../src/components/commerce/product-link.tsx"],"sourcesContent":["import * as React from 'react'\n\nimport {type Product} from '@shopify/shop-minis-platform'\nimport {cva, type VariantProps} from 'class-variance-authority'\nimport {Slot as SlotPrimitive} from 'radix-ui'\n\nimport {useShopNavigation} from '../../hooks/navigation/useShopNavigation'\nimport {useSavedProductsActions} from '../../hooks/user/useSavedProductsActions'\nimport {ProductReviewStars} from '../../internal/components/product-review-stars'\nimport {useProductImpression} from '../../internal/useProductImpression'\nimport {cn} from '../../lib/utils'\nimport {formatMoney} from '../../utils/formatMoney'\nimport {Touchable} from '../atoms/touchable'\nimport {Card, CardContent, CardAction} from '../ui/card'\n\nimport {FavoriteButton} from './favorite-button'\n\nconst productLinkVariants = cva('', {\n variants: {\n layout: {\n horizontal: 'w-full !flex-row items-center gap-3 px-4 py-3',\n vertical: 'flex-col',\n },\n discount: {\n none: '',\n small: '',\n large: '',\n },\n },\n defaultVariants: {\n layout: 'horizontal',\n discount: 'none',\n },\n})\n\n// Primitive components (building blocks)\nexport interface ProductLinkRootProps\n extends React.ComponentProps<typeof Card>,\n VariantProps<typeof productLinkVariants> {\n layout?: 'horizontal' | 'vertical'\n asChild?: boolean\n onPress?: () => void\n}\n\nfunction ProductLinkRoot({\n className,\n layout,\n discount,\n asChild = false,\n onPress,\n ...props\n}: ProductLinkRootProps) {\n const Comp = asChild ? SlotPrimitive.Root : Card\n\n return (\n <Touchable\n onClick={onPress}\n whileTap={{opacity: 0.7}}\n transition={{\n opacity: {type: 'tween', duration: 0.08, ease: 'easeInOut'},\n }}\n >\n <Comp\n className={cn(\n productLinkVariants({layout, discount}),\n 'border-0 bg-white rounded-xl shadow-lg shadow-black/10',\n className\n )}\n {...props}\n />\n </Touchable>\n )\n}\n\nfunction ProductLinkImage({\n className,\n layout = 'horizontal',\n ...props\n}: React.ComponentProps<'div'> & {layout?: 'horizontal' | 'vertical'}) {\n return (\n <div\n data-slot=\"product-link-image\"\n className={cn(\n 'overflow-hidden rounded-md bg-muted',\n layout === 'horizontal'\n ? 'h-16 w-16 flex-shrink-0'\n : 'aspect-square w-full',\n className\n )}\n {...props}\n />\n )\n}\n\nfunction ProductLinkInfo({\n className,\n layout = 'horizontal',\n ...props\n}: React.ComponentProps<typeof CardContent> & {\n layout?: 'horizontal' | 'vertical'\n}) {\n return (\n <CardContent\n className={cn(\n layout === 'horizontal'\n ? 'flex-1 min-w-0 space-y-1 px-0 py-0'\n : 'space-y-2',\n className\n )}\n {...props}\n />\n )\n}\n\nfunction ProductLinkTitle({\n className,\n children,\n ...props\n}: React.ComponentProps<'h3'>) {\n return (\n <h3\n data-slot=\"product-link-title\"\n className={cn(\n 'text-sm font-medium leading-tight text-gray-900 truncate overflow-hidden whitespace-nowrap text-ellipsis',\n className\n )}\n {...props}\n >\n {children}\n </h3>\n )\n}\n\nfunction ProductLinkPrice({className, ...props}: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"product-link-price\"\n className={cn('flex items-center gap-2', className)}\n {...props}\n />\n )\n}\n\nfunction ProductLinkCurrentPrice({\n className,\n ...props\n}: React.ComponentProps<'span'>) {\n return (\n <span\n data-slot=\"product-link-current-price\"\n className={cn('text-sm font-semibold text-gray-900', className)}\n {...props}\n />\n )\n}\n\nfunction ProductLinkOriginalPrice({\n className,\n ...props\n}: React.ComponentProps<'span'>) {\n return (\n <span\n data-slot=\"product-link-original-price\"\n className={cn('text-sm text-gray-500 line-through', className)}\n {...props}\n />\n )\n}\n\nfunction ProductLinkDiscountPrice({\n className,\n ...props\n}: React.ComponentProps<'span'>) {\n return (\n <span\n data-slot=\"product-link-discount-price\"\n className={cn('text-sm font-semibold text-red-600', className)}\n {...props}\n />\n )\n}\n\nfunction ProductLinkRating({className, ...props}: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"product-link-rating\"\n className={cn('', className)}\n {...props}\n />\n )\n}\n\nfunction ProductLinkActions({\n className,\n hideFavoriteAction = false,\n onPress,\n filled = false,\n customAction,\n ...props\n}: React.ComponentProps<typeof CardAction> & {\n hideFavoriteAction?: boolean\n onPress?: () => void\n filled?: boolean\n customAction?: React.ReactNode\n}) {\n const favoriteAction = hideFavoriteAction ? null : (\n <FavoriteButton filled={filled} onClick={onPress} />\n )\n\n return (\n <CardAction\n className={cn('flex-shrink-0 self-center px-0 py-0', className)}\n {...props}\n >\n <Touchable\n stopPropagation\n onClick={onPress}\n whileTap={{opacity: 0.7, scale: 0.95}}\n transition={{\n opacity: {type: 'tween', duration: 0.08, ease: 'easeInOut'},\n scale: {type: 'tween', duration: 0.08, ease: 'easeInOut'},\n }}\n >\n {customAction ? <>{customAction}</> : favoriteAction}\n </Touchable>\n </CardAction>\n )\n}\n\nexport interface ProductLinkDocProps {\n /** The product to display */\n product: Product\n /** Hide the favorite/save button */\n hideFavoriteAction?: boolean\n /** Callback when the product link is clicked */\n onClick?: (product: Product) => void\n /** Hide the review stars */\n reviewsDisabled?: boolean\n /** Custom action element to replace the favorite button. Must be provided with `onCustomActionClick`. */\n customAction?: React.ReactNode\n /** Callback when the custom action is clicked. Must be provided with `customAction`. */\n onCustomActionClick?: () => void\n /** Whether to disable impression tracking */\n impressionTrackingDisabled?: boolean\n}\n\nexport type ProductLinkProps = {\n product: Product\n hideFavoriteAction?: boolean\n onClick?: (product: Product) => void\n reviewsDisabled?: boolean\n impressionTrackingDisabled?: boolean\n} & (\n | {\n customAction?: never\n onCustomActionClick?: never\n }\n | {\n customAction: React.ReactNode\n onCustomActionClick: () => void\n }\n)\n\n// Composed ProductLink component\nfunction ProductLink({\n product,\n hideFavoriteAction = false,\n onClick,\n customAction,\n onCustomActionClick,\n reviewsDisabled = false,\n impressionTrackingDisabled = false,\n}: ProductLinkProps) {\n const {navigateToProduct} = useShopNavigation()\n const {saveProduct, unsaveProduct} = useSavedProductsActions()\n const {ref: impressionRef} = useProductImpression({\n productId: product.id,\n skip: impressionTrackingDisabled,\n })\n\n const {\n id,\n title,\n featuredImage,\n reviewAnalytics,\n price,\n compareAtPrice,\n isFavorited,\n selectedVariant,\n defaultVariantId,\n shop,\n } = product\n\n // Local state for optimistic UI updates\n const [isFavoritedLocal, setIsFavoritedLocal] = React.useState(isFavorited)\n\n const averageRating = reviewAnalytics?.averageRating\n const reviewCount = reviewAnalytics?.reviewCount\n const amount = price?.amount\n ? formatMoney(price?.amount, price?.currencyCode)\n : undefined\n const imageUrl = featuredImage?.url\n const imageAltText = featuredImage?.altText || title\n const compareAtPriceAmount = compareAtPrice?.amount\n ? formatMoney(compareAtPrice?.amount, compareAtPrice?.currencyCode)\n : undefined\n const hasDiscount = compareAtPriceAmount && compareAtPriceAmount !== amount\n\n const handlePress = React.useCallback(() => {\n navigateToProduct({\n productId: id,\n })\n onClick?.(product)\n }, [navigateToProduct, id, onClick, product])\n\n const handleActionPress = React.useCallback(async () => {\n if (customAction || onCustomActionClick) {\n onCustomActionClick?.()\n return\n }\n\n const previousState = isFavoritedLocal\n\n // Optimistic update\n setIsFavoritedLocal(!previousState)\n\n try {\n if (previousState) {\n await unsaveProduct({\n productId: id,\n shopId: shop.id,\n productVariantId: selectedVariant?.id || defaultVariantId,\n })\n } else {\n await saveProduct({\n productId: id,\n shopId: shop.id,\n productVariantId: selectedVariant?.id || defaultVariantId,\n })\n }\n } catch (error) {\n // Revert optimistic update on error\n setIsFavoritedLocal(previousState)\n }\n }, [\n customAction,\n onCustomActionClick,\n isFavoritedLocal,\n unsaveProduct,\n id,\n shop.id,\n selectedVariant?.id,\n defaultVariantId,\n saveProduct,\n ])\n\n return (\n <div ref={impressionRef}>\n <ProductLinkRoot\n layout=\"horizontal\"\n discount={hasDiscount ? 'small' : 'none'}\n onPress={handlePress}\n >\n <ProductLinkImage layout=\"horizontal\">\n {imageUrl ? (\n <img\n src={imageUrl}\n alt={imageAltText}\n className=\"h-full w-full object-cover\"\n />\n ) : (\n <div className=\"h-full w-full bg-muted flex items-center justify-center text-muted-foreground text-xs\">\n No Image\n </div>\n )}\n </ProductLinkImage>\n\n <ProductLinkInfo layout=\"horizontal\">\n <ProductLinkTitle>{title}</ProductLinkTitle>\n\n {averageRating && !reviewsDisabled ? (\n <ProductLinkRating>\n <ProductReviewStars\n averageRating={averageRating}\n reviewCount={reviewCount}\n />\n </ProductLinkRating>\n ) : null}\n\n <ProductLinkPrice>\n {hasDiscount ? (\n <>\n <ProductLinkDiscountPrice>{amount}</ProductLinkDiscountPrice>\n <ProductLinkOriginalPrice>\n {compareAtPriceAmount}\n </ProductLinkOriginalPrice>\n </>\n ) : (\n <ProductLinkCurrentPrice>{amount}</ProductLinkCurrentPrice>\n )}\n </ProductLinkPrice>\n </ProductLinkInfo>\n\n <ProductLinkActions\n filled={isFavoritedLocal}\n onPress={handleActionPress}\n customAction={customAction}\n hideFavoriteAction={hideFavoriteAction}\n />\n </ProductLinkRoot>\n </div>\n )\n}\n\nexport {ProductLink}\n"],"names":["productLinkVariants","cva","ProductLinkRoot","className","layout","discount","asChild","onPress","props","jsx","Touchable","SlotPrimitive.Root","Card","cn","ProductLinkImage","ProductLinkInfo","CardContent","ProductLinkTitle","children","ProductLinkPrice","ProductLinkCurrentPrice","ProductLinkOriginalPrice","ProductLinkDiscountPrice","ProductLinkRating","ProductLinkActions","hideFavoriteAction","filled","customAction","favoriteAction","FavoriteButton","CardAction","Fragment","ProductLink","product","onClick","onCustomActionClick","reviewsDisabled","impressionTrackingDisabled","navigateToProduct","useShopNavigation","saveProduct","unsaveProduct","useSavedProductsActions","impressionRef","useProductImpression","id","title","featuredImage","reviewAnalytics","price","compareAtPrice","isFavorited","selectedVariant","defaultVariantId","shop","isFavoritedLocal","setIsFavoritedLocal","React","averageRating","reviewCount","amount","formatMoney","imageUrl","imageAltText","compareAtPriceAmount","hasDiscount","handlePress","handleActionPress","previousState","jsxs","ProductReviewStars"],"mappings":"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"}
1
+ {"version":3,"file":"product-link.js","sources":["../../../src/components/commerce/product-link.tsx"],"sourcesContent":["import * as React from 'react'\n\nimport {type Product} from '@shopify/shop-minis-platform'\nimport {cva, type VariantProps} from 'class-variance-authority'\nimport {Slot as SlotPrimitive} from 'radix-ui'\n\nimport {useShopNavigation} from '../../hooks/navigation/useShopNavigation'\nimport {useSavedProductsActions} from '../../hooks/user/useSavedProductsActions'\nimport {ProductReviewStars} from '../../internal/components/product-review-stars'\nimport {useProductImpression} from '../../internal/useProductImpression'\nimport {cn} from '../../lib/utils'\nimport {formatMoney} from '../../utils/formatMoney'\nimport {Touchable} from '../atoms/touchable'\nimport {Card, CardContent, CardAction} from '../ui/card'\n\nimport {FavoriteButton} from './favorite-button'\n\nconst productLinkVariants = cva('', {\n variants: {\n layout: {\n horizontal: 'w-full !flex-row items-center gap-3 px-4 py-3',\n vertical: 'flex-col',\n },\n discount: {\n none: '',\n small: '',\n large: '',\n },\n },\n defaultVariants: {\n layout: 'horizontal',\n discount: 'none',\n },\n})\n\n// Primitive components (building blocks)\nexport interface ProductLinkRootProps\n extends\n React.ComponentProps<typeof Card>,\n VariantProps<typeof productLinkVariants> {\n layout?: 'horizontal' | 'vertical'\n asChild?: boolean\n onPress?: () => void\n}\n\nfunction ProductLinkRoot({\n className,\n layout,\n discount,\n asChild = false,\n onPress,\n ...props\n}: ProductLinkRootProps) {\n const Comp = asChild ? SlotPrimitive.Root : Card\n\n return (\n <Touchable\n onClick={onPress}\n whileTap={{opacity: 0.7}}\n transition={{\n opacity: {type: 'tween', duration: 0.08, ease: 'easeInOut'},\n }}\n >\n <Comp\n className={cn(\n productLinkVariants({layout, discount}),\n 'border-0 bg-white rounded-xl shadow-lg shadow-black/10',\n className\n )}\n {...props}\n />\n </Touchable>\n )\n}\n\nfunction ProductLinkImage({\n className,\n layout = 'horizontal',\n ...props\n}: React.ComponentProps<'div'> & {layout?: 'horizontal' | 'vertical'}) {\n return (\n <div\n data-slot=\"product-link-image\"\n className={cn(\n 'overflow-hidden rounded-md bg-muted',\n layout === 'horizontal'\n ? 'h-16 w-16 flex-shrink-0'\n : 'aspect-square w-full',\n className\n )}\n {...props}\n />\n )\n}\n\nfunction ProductLinkInfo({\n className,\n layout = 'horizontal',\n ...props\n}: React.ComponentProps<typeof CardContent> & {\n layout?: 'horizontal' | 'vertical'\n}) {\n return (\n <CardContent\n className={cn(\n layout === 'horizontal'\n ? 'flex-1 min-w-0 space-y-1 px-0 py-0'\n : 'space-y-2',\n className\n )}\n {...props}\n />\n )\n}\n\nfunction ProductLinkTitle({\n className,\n children,\n ...props\n}: React.ComponentProps<'h3'>) {\n return (\n <h3\n data-slot=\"product-link-title\"\n className={cn(\n 'text-sm font-medium leading-tight text-gray-900 truncate overflow-hidden whitespace-nowrap text-ellipsis',\n className\n )}\n {...props}\n >\n {children}\n </h3>\n )\n}\n\nfunction ProductLinkPrice({className, ...props}: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"product-link-price\"\n className={cn('flex items-center gap-2', className)}\n {...props}\n />\n )\n}\n\nfunction ProductLinkCurrentPrice({\n className,\n ...props\n}: React.ComponentProps<'span'>) {\n return (\n <span\n data-slot=\"product-link-current-price\"\n className={cn('text-sm font-semibold text-gray-900', className)}\n {...props}\n />\n )\n}\n\nfunction ProductLinkOriginalPrice({\n className,\n ...props\n}: React.ComponentProps<'span'>) {\n return (\n <span\n data-slot=\"product-link-original-price\"\n className={cn('text-sm text-gray-500 line-through', className)}\n {...props}\n />\n )\n}\n\nfunction ProductLinkDiscountPrice({\n className,\n ...props\n}: React.ComponentProps<'span'>) {\n return (\n <span\n data-slot=\"product-link-discount-price\"\n className={cn('text-sm font-semibold text-red-600', className)}\n {...props}\n />\n )\n}\n\nfunction ProductLinkRating({className, ...props}: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"product-link-rating\"\n className={cn('', className)}\n {...props}\n />\n )\n}\n\nfunction ProductLinkActions({\n className,\n hideFavoriteAction = false,\n onPress,\n filled = false,\n customAction,\n ...props\n}: React.ComponentProps<typeof CardAction> & {\n hideFavoriteAction?: boolean\n onPress?: () => void\n filled?: boolean\n customAction?: React.ReactNode\n}) {\n const favoriteAction = hideFavoriteAction ? null : (\n <FavoriteButton filled={filled} onClick={onPress} />\n )\n\n return (\n <CardAction\n className={cn('flex-shrink-0 self-center px-0 py-0', className)}\n {...props}\n >\n <Touchable\n stopPropagation\n onClick={onPress}\n whileTap={{opacity: 0.7, scale: 0.95}}\n transition={{\n opacity: {type: 'tween', duration: 0.08, ease: 'easeInOut'},\n scale: {type: 'tween', duration: 0.08, ease: 'easeInOut'},\n }}\n >\n {customAction ? <>{customAction}</> : favoriteAction}\n </Touchable>\n </CardAction>\n )\n}\n\nexport interface ProductLinkDocProps {\n /** The product to display */\n product: Product\n /** Hide the favorite/save button */\n hideFavoriteAction?: boolean\n /** Callback when the product link is clicked */\n onClick?: (product: Product) => void\n /** Hide the review stars */\n reviewsDisabled?: boolean\n /** Custom action element to replace the favorite button. Must be provided with `onCustomActionClick`. */\n customAction?: React.ReactNode\n /** Callback when the custom action is clicked. Must be provided with `customAction`. */\n onCustomActionClick?: () => void\n /** Whether to disable impression tracking */\n impressionTrackingDisabled?: boolean\n}\n\nexport type ProductLinkProps = {\n product: Product\n hideFavoriteAction?: boolean\n onClick?: (product: Product) => void\n reviewsDisabled?: boolean\n impressionTrackingDisabled?: boolean\n} & (\n | {\n customAction?: never\n onCustomActionClick?: never\n }\n | {\n customAction: React.ReactNode\n onCustomActionClick: () => void\n }\n)\n\n// Composed ProductLink component\nfunction ProductLink({\n product,\n hideFavoriteAction = false,\n onClick,\n customAction,\n onCustomActionClick,\n reviewsDisabled = false,\n impressionTrackingDisabled = false,\n}: ProductLinkProps) {\n const {navigateToProduct} = useShopNavigation()\n const {saveProduct, unsaveProduct} = useSavedProductsActions()\n const {ref: impressionRef} = useProductImpression({\n productId: product.id,\n skip: impressionTrackingDisabled,\n })\n\n const {\n id,\n title,\n featuredImage,\n reviewAnalytics,\n price,\n compareAtPrice,\n isFavorited,\n selectedVariant,\n defaultVariantId,\n shop,\n } = product\n\n // Local state for optimistic UI updates\n const [isFavoritedLocal, setIsFavoritedLocal] = React.useState(isFavorited)\n\n const averageRating = reviewAnalytics?.averageRating\n const reviewCount = reviewAnalytics?.reviewCount\n const amount = price?.amount\n ? formatMoney(price?.amount, price?.currencyCode)\n : undefined\n const imageUrl = featuredImage?.url\n const imageAltText = featuredImage?.altText || title\n const compareAtPriceAmount = compareAtPrice?.amount\n ? formatMoney(compareAtPrice?.amount, compareAtPrice?.currencyCode)\n : undefined\n const hasDiscount = compareAtPriceAmount && compareAtPriceAmount !== amount\n\n const handlePress = React.useCallback(() => {\n navigateToProduct({\n productId: id,\n })\n onClick?.(product)\n }, [navigateToProduct, id, onClick, product])\n\n const handleActionPress = React.useCallback(async () => {\n if (customAction || onCustomActionClick) {\n onCustomActionClick?.()\n return\n }\n\n const previousState = isFavoritedLocal\n\n // Optimistic update\n setIsFavoritedLocal(!previousState)\n\n try {\n if (previousState) {\n await unsaveProduct({\n productId: id,\n shopId: shop.id,\n productVariantId: selectedVariant?.id || defaultVariantId,\n })\n } else {\n await saveProduct({\n productId: id,\n shopId: shop.id,\n productVariantId: selectedVariant?.id || defaultVariantId,\n })\n }\n } catch (error) {\n // Revert optimistic update on error\n setIsFavoritedLocal(previousState)\n }\n }, [\n customAction,\n onCustomActionClick,\n isFavoritedLocal,\n unsaveProduct,\n id,\n shop.id,\n selectedVariant?.id,\n defaultVariantId,\n saveProduct,\n ])\n\n return (\n <div ref={impressionRef}>\n <ProductLinkRoot\n layout=\"horizontal\"\n discount={hasDiscount ? 'small' : 'none'}\n onPress={handlePress}\n >\n <ProductLinkImage layout=\"horizontal\">\n {imageUrl ? (\n <img\n src={imageUrl}\n alt={imageAltText}\n className=\"h-full w-full object-cover\"\n />\n ) : (\n <div className=\"h-full w-full bg-muted flex items-center justify-center text-muted-foreground text-xs\">\n No Image\n </div>\n )}\n </ProductLinkImage>\n\n <ProductLinkInfo layout=\"horizontal\">\n <ProductLinkTitle>{title}</ProductLinkTitle>\n\n {averageRating && !reviewsDisabled ? (\n <ProductLinkRating>\n <ProductReviewStars\n averageRating={averageRating}\n reviewCount={reviewCount}\n />\n </ProductLinkRating>\n ) : null}\n\n <ProductLinkPrice>\n {hasDiscount ? (\n <>\n <ProductLinkDiscountPrice>{amount}</ProductLinkDiscountPrice>\n <ProductLinkOriginalPrice>\n {compareAtPriceAmount}\n </ProductLinkOriginalPrice>\n </>\n ) : (\n <ProductLinkCurrentPrice>{amount}</ProductLinkCurrentPrice>\n )}\n </ProductLinkPrice>\n </ProductLinkInfo>\n\n <ProductLinkActions\n filled={isFavoritedLocal}\n onPress={handleActionPress}\n customAction={customAction}\n hideFavoriteAction={hideFavoriteAction}\n />\n </ProductLinkRoot>\n </div>\n )\n}\n\nexport {ProductLink}\n"],"names":["productLinkVariants","cva","ProductLinkRoot","className","layout","discount","asChild","onPress","props","jsx","Touchable","SlotPrimitive.Root","Card","cn","ProductLinkImage","ProductLinkInfo","CardContent","ProductLinkTitle","children","ProductLinkPrice","ProductLinkCurrentPrice","ProductLinkOriginalPrice","ProductLinkDiscountPrice","ProductLinkRating","ProductLinkActions","hideFavoriteAction","filled","customAction","favoriteAction","FavoriteButton","CardAction","Fragment","ProductLink","product","onClick","onCustomActionClick","reviewsDisabled","impressionTrackingDisabled","navigateToProduct","useShopNavigation","saveProduct","unsaveProduct","useSavedProductsActions","impressionRef","useProductImpression","id","title","featuredImage","reviewAnalytics","price","compareAtPrice","isFavorited","selectedVariant","defaultVariantId","shop","isFavoritedLocal","setIsFavoritedLocal","React","averageRating","reviewCount","amount","formatMoney","imageUrl","imageAltText","compareAtPriceAmount","hasDiscount","handlePress","handleActionPress","previousState","jsxs","ProductReviewStars"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"search.js","sources":["../../../src/components/commerce/search.tsx"],"sourcesContent":["import * as React from 'react'\nimport {createContext, useContext, useState, useCallback} from 'react'\n\nimport {SearchIcon, X} from 'lucide-react'\n\nimport {useProductSearch} from '../../hooks/product/useProductSearch'\nimport {cn} from '../../lib/utils'\nimport {type Product} from '../../types'\nimport {IconButton} from '../atoms/icon-button'\nimport {List} from '../atoms/list'\nimport {Input} from '../ui/input'\n\nimport {ProductLink} from './product-link'\nimport {ProductLinkSkeleton} from './product-link-skeleton'\n\ninterface SearchContextValue {\n query: string\n setQuery: (query: string) => void\n products: Product[] | null\n loading: boolean\n error: Error | null\n fetchMore?: () => Promise<void>\n hasNextPage: boolean\n isTyping: boolean\n}\n\nconst SearchContext = createContext<SearchContextValue | null>(null)\n\nfunction useSearchContext() {\n const context = useContext(SearchContext)\n if (!context) {\n throw new Error('useSearchContext must be used within a SearchProvider')\n }\n return context\n}\n\nexport interface SearchProviderProps {\n initialQuery?: string\n children: React.ReactNode\n}\n\nfunction SearchProvider({initialQuery = '', children}: SearchProviderProps) {\n const [query, setQueryState] = useState(initialQuery)\n\n const {products, loading, error, fetchMore, hasNextPage, isTyping} =\n useProductSearch({\n query,\n fetchPolicy: 'network-only',\n })\n\n const setQuery = useCallback((newQuery: string) => {\n setQueryState(newQuery)\n }, [])\n\n const contextValue: SearchContextValue = {\n query,\n setQuery,\n products,\n loading,\n error,\n fetchMore,\n hasNextPage,\n isTyping,\n }\n\n return (\n <SearchContext.Provider value={contextValue}>\n {children}\n </SearchContext.Provider>\n )\n}\n\nexport interface SearchInputProps {\n placeholder?: string\n className?: string\n inputProps?: React.ComponentProps<'input'>\n}\n\nfunction SearchInput({\n placeholder = 'Search products...',\n className,\n inputProps,\n}: SearchInputProps) {\n const {query, setQuery} = useSearchContext()\n\n const handleQueryChange = useCallback(\n (event: React.ChangeEvent<HTMLInputElement>) => {\n setQuery(event.target.value)\n inputProps?.onChange?.(event)\n },\n [inputProps, setQuery]\n )\n\n return (\n <div className=\"relative flex flex-1 items-center rounded-full pl-4 pr-2 py-1 bg-gray-100\">\n <div className=\"relative flex items-center\">\n <SearchIcon\n size={18}\n className={cn('text-accent-foreground opacity-60')}\n />\n </div>\n <div className=\"relative flex-1 flex items-center mx-2\">\n <Input\n name=\"search\"\n onChange={handleQueryChange}\n placeholder={placeholder}\n type=\"search\"\n role=\"searchbox\"\n autoComplete=\"off\"\n value={query}\n data-testid=\"search-input\"\n {...inputProps}\n className={cn(\n `w-full flex overflow-hidden rounded-radius-28 border-none shadow-none py-4 px-0 text-text placeholder:text-text placeholder:opacity-60`,\n className\n )}\n />\n </div>\n <div className=\"relative flex items-center\">\n {query === '' ? null : (\n <IconButton\n Icon={X}\n size=\"sm\"\n filled={false}\n iconStyles=\"\"\n onClick={() => setQuery('')}\n buttonStyles=\"flex items-center rounded-radius-max bg-[var(--grayscale-l20)]\"\n />\n )}\n </div>\n </div>\n )\n}\n\nexport interface SearchResultsListProps {\n renderItem?: (product: Product, index: number) => React.ReactNode\n height?: number\n itemHeight?: number\n initialStateComponent?: React.JSX.Element\n showScrollbar?: boolean\n overscanCount?: number\n}\n\nfunction SearchResultsList({\n height = window.innerHeight,\n renderItem,\n initialStateComponent,\n showScrollbar,\n}: SearchResultsListProps) {\n const {query, products, loading, fetchMore, hasNextPage, isTyping} =\n useSearchContext()\n\n const _renderItem = (product: Product, index: number) => {\n if (renderItem) {\n return renderItem(product, index)\n }\n\n return (\n <div className=\"p-2\">\n <ProductLink key={product.id} product={product} hideFavoriteAction />\n </div>\n )\n }\n\n const shouldShowStartingState = query.trim().length === 0\n const shouldShowLoading =\n (!products || products.length === 0) && (loading || isTyping)\n const shouldShowEmptyState = (!products || products.length === 0) && !loading\n\n if (shouldShowStartingState) {\n return (\n initialStateComponent || (\n <div className=\"flex items-center justify-center h-32 text-gray-500\">\n Start typing to search for products\n </div>\n )\n )\n }\n\n if (shouldShowLoading) {\n return (\n <div className=\"flex flex-col px-4 py-4\">\n <ProductLinkSkeleton className=\"mb-4\" />\n <ProductLinkSkeleton className=\"mb-4\" />\n <ProductLinkSkeleton className=\"mb-4\" />\n <ProductLinkSkeleton className=\"mb-4\" />\n </div>\n )\n }\n\n if (shouldShowEmptyState) {\n return (\n <div className=\"flex items-center justify-center h-32 text-gray-500\">\n {`No products found for \"${query}\"`}\n </div>\n )\n }\n\n return (\n <List\n items={products || []}\n height={height}\n renderItem={_renderItem}\n fetchMore={hasNextPage ? fetchMore : undefined}\n showScrollbar={showScrollbar}\n />\n )\n}\n\ninterface SearchProviderPropsWithoutChildren\n extends Omit<SearchProviderProps, 'children'> {}\nexport interface SearchResultsProps\n extends SearchProviderPropsWithoutChildren,\n SearchInputProps,\n SearchResultsListProps {\n showSearchInput?: boolean\n onProductClick?: (product: Product) => void\n}\n\nfunction Search({\n initialQuery,\n placeholder,\n inputProps,\n height,\n className,\n renderItem,\n itemHeight,\n onProductClick,\n}: SearchResultsProps) {\n const _renderItem = (product: Product, index: number) => {\n if (renderItem) {\n return renderItem(product, index)\n }\n\n return (\n <div className=\"p-2\">\n <ProductLink\n key={product.id}\n product={product}\n hideFavoriteAction\n onClick={onProductClick}\n />\n </div>\n )\n }\n\n return (\n <SearchProvider initialQuery={initialQuery}>\n <div className={cn('flex flex-col relative', className)}>\n <div className=\"absolute top-0 left-0 right-0 p-4 w-full z-20 bg-background\">\n <SearchInput placeholder={placeholder} inputProps={inputProps} />\n </div>\n <div className=\"h-14\" />\n <SearchResultsList\n height={height}\n renderItem={_renderItem}\n itemHeight={itemHeight}\n showScrollbar\n />\n </div>\n </SearchProvider>\n )\n}\n\nexport {SearchProvider, SearchInput, SearchResultsList, Search}\n"],"names":["SearchContext","createContext","useSearchContext","context","useContext","SearchProvider","initialQuery","children","query","setQueryState","useState","products","loading","error","fetchMore","hasNextPage","isTyping","useProductSearch","setQuery","useCallback","newQuery","contextValue","SearchInput","placeholder","className","inputProps","handleQueryChange","event","jsxs","jsx","SearchIcon","cn","Input","IconButton","X","SearchResultsList","height","renderItem","initialStateComponent","showScrollbar","_renderItem","product","index","ProductLink","shouldShowStartingState","shouldShowLoading","shouldShowEmptyState","ProductLinkSkeleton","List","Search","itemHeight","onProductClick"],"mappings":"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"}
1
+ {"version":3,"file":"search.js","sources":["../../../src/components/commerce/search.tsx"],"sourcesContent":["import * as React from 'react'\nimport {createContext, useContext, useState, useCallback} from 'react'\n\nimport {SearchIcon, X} from 'lucide-react'\n\nimport {useProductSearch} from '../../hooks/product/useProductSearch'\nimport {cn} from '../../lib/utils'\nimport {type Product} from '../../types'\nimport {IconButton} from '../atoms/icon-button'\nimport {List} from '../atoms/list'\nimport {Input} from '../ui/input'\n\nimport {ProductLink} from './product-link'\nimport {ProductLinkSkeleton} from './product-link-skeleton'\n\ninterface SearchContextValue {\n query: string\n setQuery: (query: string) => void\n products: Product[] | null\n loading: boolean\n error: Error | null\n fetchMore?: () => Promise<void>\n hasNextPage: boolean\n isTyping: boolean\n}\n\nconst SearchContext = createContext<SearchContextValue | null>(null)\n\nfunction useSearchContext() {\n const context = useContext(SearchContext)\n if (!context) {\n throw new Error('useSearchContext must be used within a SearchProvider')\n }\n return context\n}\n\nexport interface SearchProviderProps {\n initialQuery?: string\n children: React.ReactNode\n}\n\nfunction SearchProvider({initialQuery = '', children}: SearchProviderProps) {\n const [query, setQueryState] = useState(initialQuery)\n\n const {products, loading, error, fetchMore, hasNextPage, isTyping} =\n useProductSearch({\n query,\n fetchPolicy: 'network-only',\n })\n\n const setQuery = useCallback((newQuery: string) => {\n setQueryState(newQuery)\n }, [])\n\n const contextValue: SearchContextValue = {\n query,\n setQuery,\n products,\n loading,\n error,\n fetchMore,\n hasNextPage,\n isTyping,\n }\n\n return (\n <SearchContext.Provider value={contextValue}>\n {children}\n </SearchContext.Provider>\n )\n}\n\nexport interface SearchInputProps {\n placeholder?: string\n className?: string\n inputProps?: React.ComponentProps<'input'>\n}\n\nfunction SearchInput({\n placeholder = 'Search products...',\n className,\n inputProps,\n}: SearchInputProps) {\n const {query, setQuery} = useSearchContext()\n\n const handleQueryChange = useCallback(\n (event: React.ChangeEvent<HTMLInputElement>) => {\n setQuery(event.target.value)\n inputProps?.onChange?.(event)\n },\n [inputProps, setQuery]\n )\n\n return (\n <div className=\"relative flex flex-1 items-center rounded-full pl-4 pr-2 py-1 bg-gray-100\">\n <div className=\"relative flex items-center\">\n <SearchIcon\n size={18}\n className={cn('text-accent-foreground opacity-60')}\n />\n </div>\n <div className=\"relative flex-1 flex items-center mx-2\">\n <Input\n name=\"search\"\n onChange={handleQueryChange}\n placeholder={placeholder}\n type=\"search\"\n role=\"searchbox\"\n autoComplete=\"off\"\n value={query}\n data-testid=\"search-input\"\n {...inputProps}\n className={cn(\n `w-full flex overflow-hidden rounded-radius-28 border-none shadow-none py-4 px-0 text-text placeholder:text-text placeholder:opacity-60`,\n className\n )}\n />\n </div>\n <div className=\"relative flex items-center\">\n {query === '' ? null : (\n <IconButton\n Icon={X}\n size=\"sm\"\n filled={false}\n iconStyles=\"\"\n onClick={() => setQuery('')}\n buttonStyles=\"flex items-center rounded-radius-max bg-[var(--grayscale-l20)]\"\n />\n )}\n </div>\n </div>\n )\n}\n\nexport interface SearchResultsListProps {\n renderItem?: (product: Product, index: number) => React.ReactNode\n height?: number\n itemHeight?: number\n initialStateComponent?: React.JSX.Element\n showScrollbar?: boolean\n overscanCount?: number\n}\n\nfunction SearchResultsList({\n height = window.innerHeight,\n renderItem,\n initialStateComponent,\n showScrollbar,\n}: SearchResultsListProps) {\n const {query, products, loading, fetchMore, hasNextPage, isTyping} =\n useSearchContext()\n\n const _renderItem = (product: Product, index: number) => {\n if (renderItem) {\n return renderItem(product, index)\n }\n\n return (\n <div className=\"p-2\">\n <ProductLink key={product.id} product={product} hideFavoriteAction />\n </div>\n )\n }\n\n const shouldShowStartingState = query.trim().length === 0\n const shouldShowLoading =\n (!products || products.length === 0) && (loading || isTyping)\n const shouldShowEmptyState = (!products || products.length === 0) && !loading\n\n if (shouldShowStartingState) {\n return (\n initialStateComponent || (\n <div className=\"flex items-center justify-center h-32 text-gray-500\">\n Start typing to search for products\n </div>\n )\n )\n }\n\n if (shouldShowLoading) {\n return (\n <div className=\"flex flex-col px-4 py-4\">\n <ProductLinkSkeleton className=\"mb-4\" />\n <ProductLinkSkeleton className=\"mb-4\" />\n <ProductLinkSkeleton className=\"mb-4\" />\n <ProductLinkSkeleton className=\"mb-4\" />\n </div>\n )\n }\n\n if (shouldShowEmptyState) {\n return (\n <div className=\"flex items-center justify-center h-32 text-gray-500\">\n {`No products found for \"${query}\"`}\n </div>\n )\n }\n\n return (\n <List\n items={products || []}\n height={height}\n renderItem={_renderItem}\n fetchMore={hasNextPage ? fetchMore : undefined}\n showScrollbar={showScrollbar}\n />\n )\n}\n\ninterface SearchProviderPropsWithoutChildren extends Omit<\n SearchProviderProps,\n 'children'\n> {}\nexport interface SearchResultsProps\n extends\n SearchProviderPropsWithoutChildren,\n SearchInputProps,\n SearchResultsListProps {\n showSearchInput?: boolean\n onProductClick?: (product: Product) => void\n}\n\nfunction Search({\n initialQuery,\n placeholder,\n inputProps,\n height,\n className,\n renderItem,\n itemHeight,\n onProductClick,\n}: SearchResultsProps) {\n const _renderItem = (product: Product, index: number) => {\n if (renderItem) {\n return renderItem(product, index)\n }\n\n return (\n <div className=\"p-2\">\n <ProductLink\n key={product.id}\n product={product}\n hideFavoriteAction\n onClick={onProductClick}\n />\n </div>\n )\n }\n\n return (\n <SearchProvider initialQuery={initialQuery}>\n <div className={cn('flex flex-col relative', className)}>\n <div className=\"absolute top-0 left-0 right-0 p-4 w-full z-20 bg-background\">\n <SearchInput placeholder={placeholder} inputProps={inputProps} />\n </div>\n <div className=\"h-14\" />\n <SearchResultsList\n height={height}\n renderItem={_renderItem}\n itemHeight={itemHeight}\n showScrollbar\n />\n </div>\n </SearchProvider>\n )\n}\n\nexport {SearchProvider, SearchInput, SearchResultsList, Search}\n"],"names":["SearchContext","createContext","useSearchContext","context","useContext","SearchProvider","initialQuery","children","query","setQueryState","useState","products","loading","error","fetchMore","hasNextPage","isTyping","useProductSearch","setQuery","useCallback","newQuery","contextValue","SearchInput","placeholder","className","inputProps","handleQueryChange","event","jsxs","jsx","SearchIcon","cn","Input","IconButton","X","SearchResultsList","height","renderItem","initialStateComponent","showScrollbar","_renderItem","product","index","ProductLink","shouldShowStartingState","shouldShowLoading","shouldShowEmptyState","ProductLinkSkeleton","List","Search","itemHeight","onProductClick"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"transition-link.js","sources":["../../../src/components/navigation/transition-link.tsx"],"sourcesContent":["import {forwardRef, AnchorHTMLAttributes} from 'react'\n\nimport {useHref} from 'react-router'\n\nimport {useNavigateWithTransition} from '../../hooks/navigation/useNavigateWithTransition'\n\nexport interface TransitionLinkDocProps {\n /** The target path to navigate to */\n to: string\n /** Click handler called before navigation */\n onClick?: React.MouseEventHandler<HTMLAnchorElement>\n /** Content to render inside the link */\n children?: React.ReactNode\n}\n\nexport interface TransitionLinkProps\n extends AnchorHTMLAttributes<HTMLAnchorElement> {\n to: string\n}\n\nconst ABSOLUTE_URL_REGEX = /^(?:[a-z][a-z0-9+.-]*:|\\/\\/)/i\n\nexport const TransitionLink = forwardRef<\n HTMLAnchorElement,\n TransitionLinkProps\n>(({onClick, to, children, ...props}, forwardedRef) => {\n const transitionNavigate = useNavigateWithTransition()\n\n const isAbsolute = typeof to === 'string' && ABSOLUTE_URL_REGEX.test(to)\n\n if (isAbsolute) {\n console.warn(\n `TransitionLink: absolute URLs are not supported. Please update to a valid relative path.`\n )\n }\n\n const href = useHref(to)\n\n const handleClick = (event: React.MouseEvent<HTMLAnchorElement>) => {\n if (onClick) onClick(event)\n\n if (!event.defaultPrevented) {\n event.preventDefault()\n transitionNavigate(to)\n }\n }\n\n return (\n <a\n {...props}\n onClick={handleClick}\n href={isAbsolute ? undefined : href}\n ref={forwardedRef}\n >\n {children}\n </a>\n )\n})\n"],"names":["ABSOLUTE_URL_REGEX","TransitionLink","forwardRef","onClick","to","children","props","forwardedRef","transitionNavigate","useNavigateWithTransition","isAbsolute","href","useHref","jsx","event"],"mappings":";;;;AAoBA,MAAMA,IAAqB,iCAEdC,IAAiBC,EAG5B,CAAC,EAAC,SAAAC,GAAS,IAAAC,GAAI,UAAAC,GAAU,GAAGC,EAAK,GAAGC,MAAiB;AACrD,QAAMC,IAAqBC,EAA0B,GAE/CC,IAAa,OAAON,KAAO,YAAYJ,EAAmB,KAAKI,CAAE;AAEvE,EAAIM,KACM,QAAA;AAAA,IACN;AAAA,EACF;AAGI,QAAAC,IAAOC,EAAQR,CAAE;AAYrB,SAAA,gBAAAS;AAAA,IAAC;AAAA,IAAA;AAAA,MACE,GAAGP;AAAA,MACJ,SAZgB,CAACQ,MAA+C;AAC9D,QAAAX,OAAiBW,CAAK,GAErBA,EAAM,qBACTA,EAAM,eAAe,GACrBN,EAAmBJ,CAAE;AAAA,MAEzB;AAAA,MAMI,MAAMM,IAAa,SAAYC;AAAA,MAC/B,KAAKJ;AAAA,MAEJ,UAAAF;AAAA,IAAA;AAAA,EACH;AAEJ,CAAC;"}
1
+ {"version":3,"file":"transition-link.js","sources":["../../../src/components/navigation/transition-link.tsx"],"sourcesContent":["import {forwardRef, AnchorHTMLAttributes} from 'react'\n\nimport {useHref} from 'react-router'\n\nimport {useNavigateWithTransition} from '../../hooks/navigation/useNavigateWithTransition'\n\nexport interface TransitionLinkDocProps {\n /** The target path to navigate to */\n to: string\n /** Click handler called before navigation */\n onClick?: React.MouseEventHandler<HTMLAnchorElement>\n /** Content to render inside the link */\n children?: React.ReactNode\n}\n\nexport interface TransitionLinkProps extends AnchorHTMLAttributes<HTMLAnchorElement> {\n to: string\n}\n\nconst ABSOLUTE_URL_REGEX = /^(?:[a-z][a-z0-9+.-]*:|\\/\\/)/i\n\nexport const TransitionLink = forwardRef<\n HTMLAnchorElement,\n TransitionLinkProps\n>(({onClick, to, children, ...props}, forwardedRef) => {\n const transitionNavigate = useNavigateWithTransition()\n\n const isAbsolute = typeof to === 'string' && ABSOLUTE_URL_REGEX.test(to)\n\n if (isAbsolute) {\n console.warn(\n `TransitionLink: absolute URLs are not supported. Please update to a valid relative path.`\n )\n }\n\n const href = useHref(to)\n\n const handleClick = (event: React.MouseEvent<HTMLAnchorElement>) => {\n if (onClick) onClick(event)\n\n if (!event.defaultPrevented) {\n event.preventDefault()\n transitionNavigate(to)\n }\n }\n\n return (\n <a\n {...props}\n onClick={handleClick}\n href={isAbsolute ? undefined : href}\n ref={forwardedRef}\n >\n {children}\n </a>\n )\n})\n"],"names":["ABSOLUTE_URL_REGEX","TransitionLink","forwardRef","onClick","to","children","props","forwardedRef","transitionNavigate","useNavigateWithTransition","isAbsolute","href","useHref","jsx","event"],"mappings":";;;;AAmBA,MAAMA,IAAqB,iCAEdC,IAAiBC,EAG5B,CAAC,EAAC,SAAAC,GAAS,IAAAC,GAAI,UAAAC,GAAU,GAAGC,EAAK,GAAGC,MAAiB;AACrD,QAAMC,IAAqBC,EAA0B,GAE/CC,IAAa,OAAON,KAAO,YAAYJ,EAAmB,KAAKI,CAAE;AAEvE,EAAIM,KACM,QAAA;AAAA,IACN;AAAA,EACF;AAGI,QAAAC,IAAOC,EAAQR,CAAE;AAYrB,SAAA,gBAAAS;AAAA,IAAC;AAAA,IAAA;AAAA,MACE,GAAGP;AAAA,MACJ,SAZgB,CAACQ,MAA+C;AAC9D,QAAAX,OAAiBW,CAAK,GAErBA,EAAM,qBACTA,EAAM,eAAe,GACrBN,EAAmBJ,CAAE;AAAA,MAEzB;AAAA,MAMI,MAAMM,IAAa,SAAYC;AAAA,MAC/B,KAAKJ;AAAA,MAEJ,UAAAF;AAAA,IAAA;AAAA,EACH;AAEJ,CAAC;"}
@@ -1 +1 @@
1
- {"version":3,"file":"product-review-stars.js","sources":["../../../src/internal/components/product-review-stars.tsx"],"sourcesContent":["import * as React from 'react'\n\nimport {Star, StarHalf} from 'lucide-react'\n\nimport {cn} from '../../lib/utils'\nimport {formatReviewCount, normalizeRating} from '../../utils/merchant-card'\n\nconst starSizeClasses = {\n sm: 'h-3 w-3',\n md: 'h-4 w-4',\n lg: 'h-5 w-5',\n} as const\n\nconst textSizeClasses = {\n sm: 'text-xs',\n md: 'text-sm',\n lg: 'text-base',\n} as const\n\nexport interface ProductReviewStarsProps\n extends React.HTMLAttributes<HTMLDivElement> {\n /**\n * Average rating value (0-5)\n */\n averageRating: number\n /**\n * Total number of reviews\n */\n reviewCount?: number | null\n /**\n * Custom color for filled star\n * @default 'var(--grayscale-d100)' (black)\n */\n filledStarColor?: string\n /**\n * Custom color for empty star\n * @default 'var(--grayscale-l20)' (light gray)\n */\n emptyStarColor?: string\n /**\n * Size of the stars\n * @default 'sm'\n */\n size?: 'sm' | 'md' | 'lg'\n}\n\nexport const ProductReviewStars = React.forwardRef<\n HTMLDivElement,\n ProductReviewStarsProps\n>(\n (\n {\n averageRating,\n reviewCount,\n size = 'sm',\n filledStarColor = 'var(--grayscale-d100)',\n emptyStarColor = 'var(--grayscale-l20)',\n className,\n ...props\n },\n ref\n ) => {\n const normalizedRating = Math.min(5, normalizeRating(averageRating))\n const filledStars = Math.floor(normalizedRating)\n const remainder = normalizedRating % 1\n\n return (\n <div\n ref={ref}\n className={cn('flex items-center', className)}\n data-slot=\"product-review-stars\"\n {...props}\n >\n <div className=\"relative\">\n <div className=\"flex\">\n {Array.from({length: 5}, (_, i) => (\n <Star\n key={i}\n className={cn(starSizeClasses[size])}\n style={{fill: emptyStarColor}}\n strokeWidth={0}\n />\n ))}\n </div>\n <div className=\"flex absolute top-0 left-0\">\n {Array.from({length: filledStars}, (_, i) => (\n <Star\n key={i}\n className={cn(starSizeClasses[size])}\n style={{fill: filledStarColor}}\n strokeWidth={0}\n />\n ))}\n {remainder >= 0.5 && (\n <StarHalf\n className={cn(starSizeClasses[size])}\n style={{fill: filledStarColor}}\n strokeWidth={0}\n />\n )}\n </div>\n </div>\n {reviewCount && (\n <span className={cn(textSizeClasses[size], 'ml-1')}>\n ({formatReviewCount(reviewCount)})\n </span>\n )}\n </div>\n )\n }\n)\n\nProductReviewStars.displayName = 'ProductReviewStars'\n"],"names":["starSizeClasses","textSizeClasses","ProductReviewStars","React","averageRating","reviewCount","size","filledStarColor","emptyStarColor","className","props","ref","normalizedRating","normalizeRating","filledStars","remainder","jsxs","cn","jsx","_","i","Star","StarHalf","formatReviewCount"],"mappings":";;;;;;AAOA,MAAMA,IAAkB;AAAA,EACtB,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN,GAEMC,IAAkB;AAAA,EACtB,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN,GA6BaC,IAAqBC,EAAM;AAAA,EAItC,CACE;AAAA,IACE,eAAAC;AAAA,IACA,aAAAC;AAAA,IACA,MAAAC,IAAO;AAAA,IACP,iBAAAC,IAAkB;AAAA,IAClB,gBAAAC,IAAiB;AAAA,IACjB,WAAAC;AAAA,IACA,GAAGC;AAAA,KAELC,MACG;AACH,UAAMC,IAAmB,KAAK,IAAI,GAAGC,EAAgBT,CAAa,CAAC,GAC7DU,IAAc,KAAK,MAAMF,CAAgB,GACzCG,IAAYH,IAAmB;AAGnC,WAAA,gBAAAI;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,KAAAL;AAAA,QACA,WAAWM,EAAG,qBAAqBR,CAAS;AAAA,QAC5C,aAAU;AAAA,QACT,GAAGC;AAAA,QAEJ,UAAA;AAAA,UAAC,gBAAAM,EAAA,OAAA,EAAI,WAAU,YACb,UAAA;AAAA,YAAC,gBAAAE,EAAA,OAAA,EAAI,WAAU,QACZ,UAAM,MAAA,KAAK,EAAC,QAAQ,EAAC,GAAG,CAACC,GAAGC,MAC3B,gBAAAF;AAAA,cAACG;AAAA,cAAA;AAAA,gBAEC,WAAWJ,EAAGjB,EAAgBM,CAAI,CAAC;AAAA,gBACnC,OAAO,EAAC,MAAME,EAAc;AAAA,gBAC5B,aAAa;AAAA,cAAA;AAAA,cAHRY;AAAA,YAKR,CAAA,GACH;AAAA,YACA,gBAAAJ,EAAC,OAAI,EAAA,WAAU,8BACZ,UAAA;AAAA,cAAA,MAAM,KAAK,EAAC,QAAQF,KAAc,CAACK,GAAGC,MACrC,gBAAAF;AAAA,gBAACG;AAAA,gBAAA;AAAA,kBAEC,WAAWJ,EAAGjB,EAAgBM,CAAI,CAAC;AAAA,kBACnC,OAAO,EAAC,MAAMC,EAAe;AAAA,kBAC7B,aAAa;AAAA,gBAAA;AAAA,gBAHRa;AAAA,cAAA,CAKR;AAAA,cACAL,KAAa,OACZ,gBAAAG;AAAA,gBAACI;AAAA,gBAAA;AAAA,kBACC,WAAWL,EAAGjB,EAAgBM,CAAI,CAAC;AAAA,kBACnC,OAAO,EAAC,MAAMC,EAAe;AAAA,kBAC7B,aAAa;AAAA,gBAAA;AAAA,cAAA;AAAA,YACf,EAEJ,CAAA;AAAA,UAAA,GACF;AAAA,UACCF,uBACE,QAAK,EAAA,WAAWY,EAAGhB,EAAgBK,CAAI,GAAG,MAAM,GAAG,UAAA;AAAA,YAAA;AAAA,YAChDiB,EAAkBlB,CAAW;AAAA,YAAE;AAAA,UAAA,EACnC,CAAA;AAAA,QAAA;AAAA,MAAA;AAAA,IAEJ;AAAA,EAAA;AAGN;AAEAH,EAAmB,cAAc;"}
1
+ {"version":3,"file":"product-review-stars.js","sources":["../../../src/internal/components/product-review-stars.tsx"],"sourcesContent":["import * as React from 'react'\n\nimport {Star, StarHalf} from 'lucide-react'\n\nimport {cn} from '../../lib/utils'\nimport {formatReviewCount, normalizeRating} from '../../utils/merchant-card'\n\nconst starSizeClasses = {\n sm: 'h-3 w-3',\n md: 'h-4 w-4',\n lg: 'h-5 w-5',\n} as const\n\nconst textSizeClasses = {\n sm: 'text-xs',\n md: 'text-sm',\n lg: 'text-base',\n} as const\n\nexport interface ProductReviewStarsProps extends React.HTMLAttributes<HTMLDivElement> {\n /**\n * Average rating value (0-5)\n */\n averageRating: number\n /**\n * Total number of reviews\n */\n reviewCount?: number | null\n /**\n * Custom color for filled star\n * @default 'var(--grayscale-d100)' (black)\n */\n filledStarColor?: string\n /**\n * Custom color for empty star\n * @default 'var(--grayscale-l20)' (light gray)\n */\n emptyStarColor?: string\n /**\n * Size of the stars\n * @default 'sm'\n */\n size?: 'sm' | 'md' | 'lg'\n}\n\nexport const ProductReviewStars = React.forwardRef<\n HTMLDivElement,\n ProductReviewStarsProps\n>(\n (\n {\n averageRating,\n reviewCount,\n size = 'sm',\n filledStarColor = 'var(--grayscale-d100)',\n emptyStarColor = 'var(--grayscale-l20)',\n className,\n ...props\n },\n ref\n ) => {\n const normalizedRating = Math.min(5, normalizeRating(averageRating))\n const filledStars = Math.floor(normalizedRating)\n const remainder = normalizedRating % 1\n\n return (\n <div\n ref={ref}\n className={cn('flex items-center', className)}\n data-slot=\"product-review-stars\"\n {...props}\n >\n <div className=\"relative\">\n <div className=\"flex\">\n {Array.from({length: 5}, (_, i) => (\n <Star\n key={i}\n className={cn(starSizeClasses[size])}\n style={{fill: emptyStarColor}}\n strokeWidth={0}\n />\n ))}\n </div>\n <div className=\"flex absolute top-0 left-0\">\n {Array.from({length: filledStars}, (_, i) => (\n <Star\n key={i}\n className={cn(starSizeClasses[size])}\n style={{fill: filledStarColor}}\n strokeWidth={0}\n />\n ))}\n {remainder >= 0.5 && (\n <StarHalf\n className={cn(starSizeClasses[size])}\n style={{fill: filledStarColor}}\n strokeWidth={0}\n />\n )}\n </div>\n </div>\n {reviewCount && (\n <span className={cn(textSizeClasses[size], 'ml-1')}>\n ({formatReviewCount(reviewCount)})\n </span>\n )}\n </div>\n )\n }\n)\n\nProductReviewStars.displayName = 'ProductReviewStars'\n"],"names":["starSizeClasses","textSizeClasses","ProductReviewStars","React","averageRating","reviewCount","size","filledStarColor","emptyStarColor","className","props","ref","normalizedRating","normalizeRating","filledStars","remainder","jsxs","cn","jsx","_","i","Star","StarHalf","formatReviewCount"],"mappings":";;;;;;AAOA,MAAMA,IAAkB;AAAA,EACtB,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN,GAEMC,IAAkB;AAAA,EACtB,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN,GA4BaC,IAAqBC,EAAM;AAAA,EAItC,CACE;AAAA,IACE,eAAAC;AAAA,IACA,aAAAC;AAAA,IACA,MAAAC,IAAO;AAAA,IACP,iBAAAC,IAAkB;AAAA,IAClB,gBAAAC,IAAiB;AAAA,IACjB,WAAAC;AAAA,IACA,GAAGC;AAAA,KAELC,MACG;AACH,UAAMC,IAAmB,KAAK,IAAI,GAAGC,EAAgBT,CAAa,CAAC,GAC7DU,IAAc,KAAK,MAAMF,CAAgB,GACzCG,IAAYH,IAAmB;AAGnC,WAAA,gBAAAI;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,KAAAL;AAAA,QACA,WAAWM,EAAG,qBAAqBR,CAAS;AAAA,QAC5C,aAAU;AAAA,QACT,GAAGC;AAAA,QAEJ,UAAA;AAAA,UAAC,gBAAAM,EAAA,OAAA,EAAI,WAAU,YACb,UAAA;AAAA,YAAC,gBAAAE,EAAA,OAAA,EAAI,WAAU,QACZ,UAAM,MAAA,KAAK,EAAC,QAAQ,EAAC,GAAG,CAACC,GAAGC,MAC3B,gBAAAF;AAAA,cAACG;AAAA,cAAA;AAAA,gBAEC,WAAWJ,EAAGjB,EAAgBM,CAAI,CAAC;AAAA,gBACnC,OAAO,EAAC,MAAME,EAAc;AAAA,gBAC5B,aAAa;AAAA,cAAA;AAAA,cAHRY;AAAA,YAKR,CAAA,GACH;AAAA,YACA,gBAAAJ,EAAC,OAAI,EAAA,WAAU,8BACZ,UAAA;AAAA,cAAA,MAAM,KAAK,EAAC,QAAQF,KAAc,CAACK,GAAGC,MACrC,gBAAAF;AAAA,gBAACG;AAAA,gBAAA;AAAA,kBAEC,WAAWJ,EAAGjB,EAAgBM,CAAI,CAAC;AAAA,kBACnC,OAAO,EAAC,MAAMC,EAAe;AAAA,kBAC7B,aAAa;AAAA,gBAAA;AAAA,gBAHRa;AAAA,cAAA,CAKR;AAAA,cACAL,KAAa,OACZ,gBAAAG;AAAA,gBAACI;AAAA,gBAAA;AAAA,kBACC,WAAWL,EAAGjB,EAAgBM,CAAI,CAAC;AAAA,kBACnC,OAAO,EAAC,MAAMC,EAAe;AAAA,kBAC7B,aAAa;AAAA,gBAAA;AAAA,cAAA;AAAA,YACf,EAEJ,CAAA;AAAA,UAAA,GACF;AAAA,UACCF,uBACE,QAAK,EAAA,WAAWY,EAAGhB,EAAgBK,CAAI,GAAG,MAAM,GAAG,UAAA;AAAA,YAAA;AAAA,YAChDiB,EAAkBlB,CAAW;AAAA,YAAE;AAAA,UAAA,EACnC,CAAA;AAAA,QAAA;AAAA,MAAA;AAAA,IAEJ;AAAA,EAAA;AAGN;AAEAH,EAAmB,cAAc;"}
@@ -1,4 +1,4 @@
1
- import { s as r } from "../../../../../../../../_virtual/index7.js";
1
+ import { s as r } from "../../../../../../../../_virtual/index6.js";
2
2
  function s() {
3
3
  return r.useSyncExternalStore(
4
4
  e,
@@ -1,4 +1,4 @@
1
- import { __module as q } from "../../../../../../../../_virtual/index5.js";
1
+ import { __module as q } from "../../../../../../../../_virtual/index4.js";
2
2
  import { __require as F } from "../../../../../global@4.4.0/node_modules/global/window.js";
3
3
  import { __require as N } from "../../../../../@babel_runtime@7.27.6/node_modules/@babel/runtime/helpers/extends.js";
4
4
  import { __require as J } from "../../../../../is-function@1.0.2/node_modules/is-function/index.js";
@@ -1,4 +1,4 @@
1
- import { __exports as r } from "../../../../../../../../_virtual/index9.js";
1
+ import { __exports as r } from "../../../../../../../../_virtual/index7.js";
2
2
  import { __require as a } from "./dom.js";
3
3
  import { __require as o } from "./dom-parser.js";
4
4
  var i;