@shopify/shop-minis-react 0.0.0-snapshot.20251216112959 → 0.0.0-snapshot.20251217193626
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_virtual/index4.js +2 -2
- package/dist/_virtual/index5.js +3 -2
- package/dist/_virtual/index5.js.map +1 -1
- package/dist/_virtual/index6.js +2 -3
- package/dist/_virtual/index6.js.map +1 -1
- package/dist/components/atoms/alert-dialog.js.map +1 -1
- package/dist/components/atoms/button.js.map +1 -1
- package/dist/components/atoms/icon-button.js.map +1 -1
- package/dist/components/atoms/image.js +65 -51
- package/dist/components/atoms/image.js.map +1 -1
- package/dist/components/atoms/list.js.map +1 -1
- package/dist/components/atoms/product-variant-price.js +1 -1
- package/dist/components/atoms/product-variant-price.js.map +1 -1
- package/dist/components/atoms/text-input.js.map +1 -1
- package/dist/components/atoms/touchable.js.map +1 -1
- package/dist/components/atoms/video-player.js +1 -1
- package/dist/components/atoms/video-player.js.map +1 -1
- package/dist/components/commerce/add-to-cart.js.map +1 -1
- package/dist/components/commerce/buy-now.js.map +1 -1
- package/dist/components/commerce/favorite-button.js +1 -4
- package/dist/components/commerce/favorite-button.js.map +1 -1
- package/dist/components/commerce/merchant-card.js.map +1 -1
- package/dist/components/commerce/product-card.js +1 -1
- package/dist/components/commerce/product-card.js.map +1 -1
- package/dist/components/commerce/product-link.js +1 -1
- package/dist/components/commerce/product-link.js.map +1 -1
- package/dist/components/commerce/quantity-selector.js.map +1 -1
- package/dist/components/content/image-content-wrapper.js.map +1 -1
- package/dist/components/navigation/minis-router.js.map +1 -1
- package/dist/components/navigation/transition-link.js.map +1 -1
- package/dist/components/ui/alert.js.map +1 -1
- package/dist/components/ui/badge.js.map +1 -1
- package/dist/components/ui/input.js.map +1 -1
- package/dist/hooks/storage/useImageUpload.js +32 -24
- package/dist/hooks/storage/useImageUpload.js.map +1 -1
- package/dist/index.js +92 -88
- package/dist/index.js.map +1 -1
- package/dist/mocks.js +70 -50
- package/dist/mocks.js.map +1 -1
- package/dist/shop-minis-react/node_modules/.pnpm/@videojs_xhr@2.7.0/node_modules/@videojs/xhr/lib/index.js +1 -1
- package/dist/shop-minis-react/node_modules/.pnpm/mpd-parser@1.3.1/node_modules/mpd-parser/dist/mpd-parser.es.js +1 -1
- package/dist/shop-minis-react/node_modules/.pnpm/querystringify@2.2.0/node_modules/querystringify/index.js +1 -1
- package/dist/utils/formatMoney.js.map +1 -0
- package/dist/utils/image.js +44 -24
- package/dist/utils/image.js.map +1 -1
- package/eslint/rules/validate-manifest.cjs +91 -41
- package/package.json +2 -2
- package/src/components/atoms/alert-dialog.tsx +3 -3
- package/src/components/atoms/button.tsx +22 -0
- package/src/components/atoms/icon-button.tsx +16 -8
- package/src/components/atoms/image.test.tsx +27 -13
- package/src/components/atoms/image.tsx +41 -8
- package/src/components/atoms/list.tsx +25 -2
- package/src/components/atoms/product-variant-price.test.tsx +1 -1
- package/src/components/atoms/product-variant-price.tsx +1 -1
- package/src/components/atoms/text-input.tsx +3 -1
- package/src/components/atoms/touchable.tsx +15 -4
- package/src/components/atoms/video-player.tsx +16 -6
- package/src/components/commerce/add-to-cart.tsx +7 -11
- package/src/components/commerce/buy-now.tsx +7 -10
- package/src/components/commerce/favorite-button.tsx +6 -5
- package/src/components/commerce/merchant-card.tsx +4 -0
- package/src/components/commerce/product-card.test.tsx +1 -1
- package/src/components/commerce/product-card.tsx +1 -1
- package/src/components/commerce/product-link.test.tsx +1 -1
- package/src/components/commerce/product-link.tsx +16 -1
- package/src/components/commerce/quantity-selector.tsx +6 -1
- package/src/components/content/image-content-wrapper.tsx +16 -1
- package/src/components/navigation/minis-router.tsx +2 -2
- package/src/components/navigation/transition-link.tsx +11 -1
- package/src/components/ui/alert.tsx +7 -0
- package/src/components/ui/badge.tsx +9 -0
- package/src/components/ui/input.tsx +15 -0
- package/src/hooks/storage/useImageUpload.ts +13 -0
- package/src/mocks.ts +48 -19
- package/src/utils/image.ts +38 -0
- package/src/utils/index.ts +1 -0
- package/dist/lib/formatMoney.js.map +0 -1
- /package/dist/{lib → utils}/formatMoney.js +0 -0
- /package/src/{lib → utils}/formatMoney.ts +0 -0
package/dist/_virtual/index4.js
CHANGED
package/dist/_virtual/index5.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index5.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index5.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
|
package/dist/_virtual/index6.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index6.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index6.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"alert-dialog.js","sources":["../../../src/components/atoms/alert-dialog.tsx"],"sourcesContent":["import {useState} from 'react'\n\nimport {\n AlertDialogTrigger,\n AlertDialogContent,\n AlertDialogHeader,\n AlertDialogTitle,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogCancel,\n AlertDialogAction,\n AlertDialog as AlertDialogPrimitive,\n} from '../ui/alert-dialog'\n\nexport interface AlertDialogAtomProps {\n /** The trigger element that opens the alert dialog */\n children: React.ReactNode\n /** The title text shown in the alert dialog header */\n title: string\n /** The description text shown in the alert dialog body */\n description: string\n /** The text shown in the cancel button */\n cancelButtonText
|
|
1
|
+
{"version":3,"file":"alert-dialog.js","sources":["../../../src/components/atoms/alert-dialog.tsx"],"sourcesContent":["import {useState} from 'react'\n\nimport {\n AlertDialogTrigger,\n AlertDialogContent,\n AlertDialogHeader,\n AlertDialogTitle,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogCancel,\n AlertDialogAction,\n AlertDialog as AlertDialogPrimitive,\n} from '../ui/alert-dialog'\n\nexport interface AlertDialogAtomProps {\n /** The trigger element that opens the alert dialog */\n children: React.ReactNode\n /** The title text shown in the alert dialog header */\n title: string\n /** The description text shown in the alert dialog body */\n description: string\n /** The text shown in the cancel button */\n cancelButtonText?: string\n /** The text shown in the confirmation button */\n confirmationButtonText?: string\n /** Whether the alert dialog is open */\n open?: boolean\n /** Callback fired when the alert dialog open state changes */\n onOpenChange: (open: boolean) => void\n /** Callback fired when the confirmation button is clicked */\n onConfirmationAction: () => void\n}\n\nexport const AlertDialogAtom = ({\n children,\n title,\n description,\n cancelButtonText,\n confirmationButtonText,\n open,\n onOpenChange,\n onConfirmationAction,\n}: AlertDialogAtomProps) => {\n const [isOpen, setIsOpen] = useState(open)\n\n return (\n <AlertDialogPrimitive\n open={isOpen}\n onOpenChange={open => {\n setIsOpen(open)\n onOpenChange(open)\n }}\n >\n <AlertDialogTrigger asChild>{children}</AlertDialogTrigger>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>{title}</AlertDialogTitle>\n <AlertDialogDescription>{description}</AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>{cancelButtonText}</AlertDialogCancel>\n <AlertDialogAction onClick={onConfirmationAction}>\n {confirmationButtonText}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialogPrimitive>\n )\n}\n"],"names":["AlertDialogAtom","children","title","description","cancelButtonText","confirmationButtonText","open","onOpenChange","onConfirmationAction","isOpen","setIsOpen","useState","jsxs","AlertDialogPrimitive","jsx","AlertDialogTrigger","AlertDialogContent","AlertDialogHeader","AlertDialogTitle","AlertDialogDescription","AlertDialogFooter","AlertDialogCancel","AlertDialogAction"],"mappings":";;;AAiCO,MAAMA,IAAkB,CAAC;AAAA,EAC9B,UAAAC;AAAA,EACA,OAAAC;AAAA,EACA,aAAAC;AAAA,EACA,kBAAAC;AAAA,EACA,wBAAAC;AAAA,EACA,MAAAC;AAAA,EACA,cAAAC;AAAA,EACA,sBAAAC;AACF,MAA4B;AAC1B,QAAM,CAACC,GAAQC,CAAS,IAAIC,EAASL,CAAI;AAGvC,SAAA,gBAAAM;AAAA,IAACC;AAAAA,IAAA;AAAA,MACC,MAAMJ;AAAA,MACN,cAAc,CAAAH,MAAQ;AACpB,QAAAI,EAAUJ,CAAI,GACdC,EAAaD,CAAI;AAAA,MACnB;AAAA,MAEA,UAAA;AAAA,QAAC,gBAAAQ,EAAAC,GAAA,EAAmB,SAAO,IAAE,UAAAd,EAAS,CAAA;AAAA,0BACrCe,GACC,EAAA,UAAA;AAAA,UAAA,gBAAAJ,EAACK,GACC,EAAA,UAAA;AAAA,YAAA,gBAAAH,EAACI,KAAkB,UAAMhB,EAAA,CAAA;AAAA,YACzB,gBAAAY,EAACK,KAAwB,UAAYhB,EAAA,CAAA;AAAA,UAAA,GACvC;AAAA,4BACCiB,GACC,EAAA,UAAA;AAAA,YAAA,gBAAAN,EAACO,KAAmB,UAAiBjB,EAAA,CAAA;AAAA,YACpC,gBAAAU,EAAAQ,GAAA,EAAkB,SAASd,GACzB,UACHH,EAAA,CAAA;AAAA,UAAA,EACF,CAAA;AAAA,QAAA,EACF,CAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EACF;AAEJ;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"button.js","sources":["../../../src/components/atoms/button.tsx"],"sourcesContent":["import React from 'react'\n\nimport {VariantProps} from 'class-variance-authority'\n\nimport {cn} from '../../lib/utils'\nimport {BaseButton, buttonVariants} from '../ui/button'\n\nimport {Touchable} from './touchable'\n\nexport function Button({\n className,\n variant,\n size,\n onClick,\n stopPropagation = false,\n ...props\n}: React.ComponentProps<'button'> &\n VariantProps<typeof buttonVariants> & {stopPropagation?: boolean}) {\n const handleClick = React.useCallback(\n (event: React.MouseEvent<any>) => {\n onClick?.(event)\n },\n [onClick]\n )\n\n const wrapperClassName = cn(\n variant === 'icon' ? 'flex w-auto' : 'flex w-full'\n )\n\n return (\n <Touchable\n onClick={handleClick}\n stopPropagation={stopPropagation}\n className={wrapperClassName}\n >\n <BaseButton\n className={cn(className, wrapperClassName)}\n variant={variant}\n size={size}\n {...props}\n />\n </Touchable>\n )\n}\n"],"names":["Button","className","variant","size","onClick","stopPropagation","props","handleClick","React","event","wrapperClassName","cn","jsx","Touchable","BaseButton"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"button.js","sources":["../../../src/components/atoms/button.tsx"],"sourcesContent":["import React from 'react'\n\nimport {VariantProps} from 'class-variance-authority'\n\nimport {cn} from '../../lib/utils'\nimport {BaseButton, buttonVariants} from '../ui/button'\n\nimport {Touchable} from './touchable'\n\nexport interface ButtonDocProps {\n /** Visual style variant */\n variant?:\n | 'default'\n | 'secondary'\n | 'destructive'\n | 'outline'\n | 'ghost'\n | 'link'\n | 'icon'\n /** Button size */\n size?: 'default' | 'sm' | 'lg' | 'icon'\n /** Click handler */\n onClick?: React.MouseEventHandler<HTMLButtonElement>\n /** Prevent click from bubbling to parent elements */\n stopPropagation?: boolean\n /** Whether the button is disabled */\n disabled?: boolean\n /** Button content */\n children?: React.ReactNode\n}\n\nexport function Button({\n className,\n variant,\n size,\n onClick,\n stopPropagation = false,\n ...props\n}: React.ComponentProps<'button'> &\n VariantProps<typeof buttonVariants> & {stopPropagation?: boolean}) {\n const handleClick = React.useCallback(\n (event: React.MouseEvent<any>) => {\n onClick?.(event)\n },\n [onClick]\n )\n\n const wrapperClassName = cn(\n variant === 'icon' ? 'flex w-auto' : 'flex w-full'\n )\n\n return (\n <Touchable\n onClick={handleClick}\n stopPropagation={stopPropagation}\n className={wrapperClassName}\n >\n <BaseButton\n className={cn(className, wrapperClassName)}\n variant={variant}\n size={size}\n {...props}\n />\n </Touchable>\n )\n}\n"],"names":["Button","className","variant","size","onClick","stopPropagation","props","handleClick","React","event","wrapperClassName","cn","jsx","Touchable","BaseButton"],"mappings":";;;;;AA+BO,SAASA,EAAO;AAAA,EACrB,WAAAC;AAAA,EACA,SAAAC;AAAA,EACA,MAAAC;AAAA,EACA,SAAAC;AAAA,EACA,iBAAAC,IAAkB;AAAA,EAClB,GAAGC;AACL,GACqE;AACnE,QAAMC,IAAcC,EAAM;AAAA,IACxB,CAACC,MAAiC;AAChC,MAAAL,IAAUK,CAAK;AAAA,IACjB;AAAA,IACA,CAACL,CAAO;AAAA,EACV,GAEMM,IAAmBC;AAAA,IACvBT,MAAY,SAAS,gBAAgB;AAAA,EACvC;AAGE,SAAA,gBAAAU;AAAA,IAACC;AAAA,IAAA;AAAA,MACC,SAASN;AAAA,MACT,iBAAAF;AAAA,MACA,WAAWK;AAAA,MAEX,UAAA,gBAAAE;AAAA,QAACE;AAAA,QAAA;AAAA,UACC,WAAWH,EAAGV,GAAWS,CAAgB;AAAA,UACzC,SAAAR;AAAA,UACA,MAAAC;AAAA,UACC,GAAGG;AAAA,QAAA;AAAA,MAAA;AAAA,IACN;AAAA,EACF;AAEJ;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"icon-button.js","sources":["../../../src/components/atoms/icon-button.tsx"],"sourcesContent":["import {LucideIcon} from 'lucide-react'\n\nimport {cn} from '../../lib/utils'\n\nimport {Button} from './button'\n\nexport
|
|
1
|
+
{"version":3,"file":"icon-button.js","sources":["../../../src/components/atoms/icon-button.tsx"],"sourcesContent":["import {LucideIcon} from 'lucide-react'\n\nimport {cn} from '../../lib/utils'\n\nimport {Button} from './button'\n\nexport interface IconButtonProps {\n /** Click handler */\n onClick?: () => void\n /** Whether the button is in a filled/active state */\n filled?: boolean\n /** Button size variant */\n size?: 'default' | 'sm' | 'lg'\n /** Lucide icon component to render */\n Icon: LucideIcon\n /** Custom CSS classes for the button container */\n buttonStyles?: string\n /** Custom CSS classes for the icon */\n iconStyles?: string\n}\n\nexport function IconButton({\n onClick,\n filled = false,\n size = 'default',\n Icon,\n buttonStyles,\n iconStyles,\n}: IconButtonProps) {\n const sizeMap = {\n sm: 'size-3',\n default: 'size-4',\n lg: 'size-6',\n }\n\n return (\n <Button\n onClick={onClick}\n variant=\"icon\"\n size={size}\n className={cn(buttonStyles)}\n stopPropagation\n >\n <Icon\n fill={filled ? 'currentColor' : 'none'}\n className={cn('text-primary-foreground', sizeMap[size], iconStyles)}\n />\n </Button>\n )\n}\n"],"names":["IconButton","onClick","filled","size","Icon","buttonStyles","iconStyles","sizeMap","jsx","Button","cn"],"mappings":";;;AAqBO,SAASA,EAAW;AAAA,EACzB,SAAAC;AAAA,EACA,QAAAC,IAAS;AAAA,EACT,MAAAC,IAAO;AAAA,EACP,MAAAC;AAAA,EACA,cAAAC;AAAA,EACA,YAAAC;AACF,GAAoB;AAClB,QAAMC,IAAU;AAAA,IACd,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,IAAI;AAAA,EACN;AAGE,SAAA,gBAAAC;AAAA,IAACC;AAAA,IAAA;AAAA,MACC,SAAAR;AAAA,MACA,SAAQ;AAAA,MACR,MAAAE;AAAA,MACA,WAAWO,EAAGL,CAAY;AAAA,MAC1B,iBAAe;AAAA,MAEf,UAAA,gBAAAG;AAAA,QAACJ;AAAA,QAAA;AAAA,UACC,MAAMF,IAAS,iBAAiB;AAAA,UAChC,WAAWQ,EAAG,2BAA2BH,EAAQJ,CAAI,GAAGG,CAAU;AAAA,QAAA;AAAA,MAAA;AAAA,IACpE;AAAA,EACF;AAEJ;"}
|
|
@@ -1,66 +1,80 @@
|
|
|
1
|
-
import { jsx as
|
|
2
|
-
import { memo as
|
|
3
|
-
import { cn as
|
|
4
|
-
import {
|
|
5
|
-
const
|
|
1
|
+
import { jsxs as y, jsx as m } from "react/jsx-runtime";
|
|
2
|
+
import { memo as I, useState as b, useEffect as f, useMemo as d, useCallback as N } from "react";
|
|
3
|
+
import { cn as r } from "../../lib/utils.js";
|
|
4
|
+
import { getThumbhashBlobURL as k, getResizedImageUrl as w } from "../../utils/image.js";
|
|
5
|
+
const C = I(function(h) {
|
|
6
6
|
const {
|
|
7
|
-
src:
|
|
8
|
-
file:
|
|
9
|
-
thumbhash:
|
|
10
|
-
onLoad:
|
|
11
|
-
className:
|
|
12
|
-
style:
|
|
13
|
-
aspectRatio:
|
|
14
|
-
objectFit:
|
|
15
|
-
...
|
|
16
|
-
} =
|
|
17
|
-
|
|
18
|
-
if (!
|
|
19
|
-
|
|
7
|
+
src: l,
|
|
8
|
+
file: s,
|
|
9
|
+
thumbhash: c,
|
|
10
|
+
onLoad: u,
|
|
11
|
+
className: L,
|
|
12
|
+
style: U,
|
|
13
|
+
aspectRatio: t = "auto",
|
|
14
|
+
objectFit: p = "contain",
|
|
15
|
+
...R
|
|
16
|
+
} = h, [i, g] = b(!1), [a, n] = b(null);
|
|
17
|
+
f(() => {
|
|
18
|
+
if (!s) {
|
|
19
|
+
n(null);
|
|
20
20
|
return;
|
|
21
21
|
}
|
|
22
|
-
const
|
|
23
|
-
return
|
|
24
|
-
URL.revokeObjectURL(
|
|
22
|
+
const o = URL.createObjectURL(s);
|
|
23
|
+
return n(o), () => {
|
|
24
|
+
URL.revokeObjectURL(o);
|
|
25
25
|
};
|
|
26
|
-
}, [
|
|
27
|
-
const
|
|
28
|
-
() =>
|
|
29
|
-
[s]
|
|
30
|
-
), R = y(
|
|
31
|
-
(e) => {
|
|
32
|
-
U(!0), c?.(e);
|
|
33
|
-
},
|
|
26
|
+
}, [s]);
|
|
27
|
+
const e = d(
|
|
28
|
+
() => k(c ?? void 0),
|
|
34
29
|
[c]
|
|
35
|
-
)
|
|
36
|
-
|
|
30
|
+
);
|
|
31
|
+
f(() => () => {
|
|
32
|
+
e && URL.revokeObjectURL(e);
|
|
33
|
+
}, [e]);
|
|
34
|
+
const j = N(
|
|
35
|
+
(o) => {
|
|
36
|
+
g(!0), u?.(o);
|
|
37
|
+
},
|
|
38
|
+
[u]
|
|
39
|
+
), v = d(() => a || w(l), [a, l]);
|
|
40
|
+
return /* @__PURE__ */ y(
|
|
37
41
|
"div",
|
|
38
42
|
{
|
|
39
|
-
className:
|
|
43
|
+
className: r("relative w-full", L),
|
|
40
44
|
style: {
|
|
41
|
-
...
|
|
42
|
-
...
|
|
43
|
-
backgroundImage: n ? `url(${n})` : void 0,
|
|
44
|
-
backgroundSize: "cover",
|
|
45
|
-
backgroundPosition: "center"
|
|
45
|
+
...U,
|
|
46
|
+
...t !== "auto" && { aspectRatio: t }
|
|
46
47
|
},
|
|
47
|
-
children:
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
48
|
+
children: [
|
|
49
|
+
e && !i && /* @__PURE__ */ m(
|
|
50
|
+
"img",
|
|
51
|
+
{
|
|
52
|
+
className: r(
|
|
53
|
+
t === "auto" ? "w-full h-auto" : "absolute inset-0 size-full",
|
|
54
|
+
"object-cover"
|
|
55
|
+
),
|
|
56
|
+
src: e,
|
|
57
|
+
"aria-hidden": "true"
|
|
58
|
+
}
|
|
59
|
+
),
|
|
60
|
+
/* @__PURE__ */ m(
|
|
61
|
+
"img",
|
|
62
|
+
{
|
|
63
|
+
className: r(
|
|
64
|
+
t === "auto" ? "opacity-0 w-full h-auto" : "absolute inset-0 opacity-0 size-full",
|
|
65
|
+
`object-${p}`,
|
|
66
|
+
i && "opacity-100"
|
|
67
|
+
),
|
|
68
|
+
src: v,
|
|
69
|
+
onLoad: j,
|
|
70
|
+
...R
|
|
71
|
+
}
|
|
72
|
+
)
|
|
73
|
+
]
|
|
60
74
|
}
|
|
61
75
|
);
|
|
62
76
|
});
|
|
63
77
|
export {
|
|
64
|
-
|
|
78
|
+
C as Image
|
|
65
79
|
};
|
|
66
80
|
//# sourceMappingURL=image.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image.js","sources":["../../../src/components/atoms/image.tsx"],"sourcesContent":["/* eslint-disable jsx-a11y/alt-text */\n/* eslint-disable jsx-a11y/no-noninteractive-element-interactions */\nimport {\n ImgHTMLAttributes,\n useCallback,\n useMemo,\n memo,\n useState,\n useEffect,\n} from 'react'\n\nimport {cn} from '../../lib/utils'\nimport {
|
|
1
|
+
{"version":3,"file":"image.js","sources":["../../../src/components/atoms/image.tsx"],"sourcesContent":["/* eslint-disable jsx-a11y/alt-text */\n/* eslint-disable jsx-a11y/no-noninteractive-element-interactions */\nimport {\n ImgHTMLAttributes,\n useCallback,\n useMemo,\n memo,\n useState,\n useEffect,\n} from 'react'\n\nimport {cn} from '../../lib/utils'\nimport {getThumbhashBlobURL, getResizedImageUrl} from '../../utils'\n\nexport interface ImageDocProps {\n /** Remote image URL */\n src?: string\n /** File object from useImagePicker (auto-manages blob URL lifecycle) */\n file?: File\n /** Thumbhash string for progressive loading placeholder */\n thumbhash?: string | null\n /** Aspect ratio (e.g., 16/9, \"4/3\", or \"auto\") */\n aspectRatio?: number | string\n /** How the image should fit within its container */\n objectFit?: 'cover' | 'contain' | 'fill' | 'scale-down' | 'none'\n /** Alt text for accessibility */\n alt?: string\n /** Callback when image finishes loading */\n onLoad?: () => void\n}\n\ntype ImageProps = ImgHTMLAttributes<HTMLImageElement> & {\n src?: string\n file?: File\n thumbhash?: string | null\n aspectRatio?: number | string\n objectFit?: 'cover' | 'contain' | 'fill' | 'scale-down' | 'none'\n}\n\nexport const Image = memo(function Image(props: ImageProps) {\n const {\n src,\n file,\n thumbhash,\n onLoad,\n className,\n style,\n aspectRatio = 'auto',\n objectFit = 'contain',\n ...restProps\n } = props\n\n const [isLoaded, setIsLoaded] = useState(false)\n const [blobUrl, setBlobUrl] = useState<string | null>(null)\n\n // Create and manage blob URL for File objects\n useEffect(() => {\n if (!file) {\n setBlobUrl(null)\n return\n }\n\n const url = URL.createObjectURL(file)\n setBlobUrl(url)\n\n // Cleanup on unmount or when file changes\n return () => {\n URL.revokeObjectURL(url)\n }\n }, [file])\n\n const thumbhashBlobUrl = useMemo(\n () => getThumbhashBlobURL(thumbhash ?? undefined),\n [thumbhash]\n )\n\n // Cleanup blob URL when it changes or component unmounts\n useEffect(() => {\n return () => {\n if (thumbhashBlobUrl) {\n URL.revokeObjectURL(thumbhashBlobUrl)\n }\n }\n }, [thumbhashBlobUrl])\n\n const handleLoad = useCallback(\n (event: React.SyntheticEvent<HTMLImageElement, Event>) => {\n setIsLoaded(true)\n onLoad?.(event)\n },\n [onLoad]\n )\n\n // Use blob URL if file is provided, otherwise use src\n const imageSrc = useMemo(() => {\n if (blobUrl) return blobUrl\n return getResizedImageUrl(src)\n }, [blobUrl, src])\n\n return (\n <div\n className={cn('relative w-full', className)}\n style={{\n ...style,\n ...(aspectRatio !== 'auto' && {aspectRatio}),\n }}\n >\n {thumbhashBlobUrl && !isLoaded && (\n <img\n className={cn(\n aspectRatio === 'auto'\n ? 'w-full h-auto'\n : 'absolute inset-0 size-full',\n 'object-cover'\n )}\n src={thumbhashBlobUrl}\n aria-hidden=\"true\"\n />\n )}\n <img\n className={cn(\n aspectRatio === 'auto'\n ? 'opacity-0 w-full h-auto'\n : 'absolute inset-0 opacity-0 size-full',\n `object-${objectFit}`,\n isLoaded && 'opacity-100'\n )}\n src={imageSrc}\n onLoad={handleLoad}\n {...restProps}\n />\n </div>\n )\n})\n"],"names":["Image","memo","props","src","file","thumbhash","onLoad","className","style","aspectRatio","objectFit","restProps","isLoaded","setIsLoaded","useState","blobUrl","setBlobUrl","useEffect","url","thumbhashBlobUrl","useMemo","getThumbhashBlobURL","handleLoad","useCallback","event","imageSrc","getResizedImageUrl","jsxs","cn","jsx"],"mappings":";;;;AAuCO,MAAMA,IAAQC,EAAK,SAAeC,GAAmB;AACpD,QAAA;AAAA,IACJ,KAAAC;AAAA,IACA,MAAAC;AAAA,IACA,WAAAC;AAAA,IACA,QAAAC;AAAA,IACA,WAAAC;AAAA,IACA,OAAAC;AAAA,IACA,aAAAC,IAAc;AAAA,IACd,WAAAC,IAAY;AAAA,IACZ,GAAGC;AAAA,EAAA,IACDT,GAEE,CAACU,GAAUC,CAAW,IAAIC,EAAS,EAAK,GACxC,CAACC,GAASC,CAAU,IAAIF,EAAwB,IAAI;AAG1D,EAAAG,EAAU,MAAM;AACd,QAAI,CAACb,GAAM;AACT,MAAAY,EAAW,IAAI;AACf;AAAA,IAAA;AAGI,UAAAE,IAAM,IAAI,gBAAgBd,CAAI;AACpC,WAAAY,EAAWE,CAAG,GAGP,MAAM;AACX,UAAI,gBAAgBA,CAAG;AAAA,IACzB;AAAA,EAAA,GACC,CAACd,CAAI,CAAC;AAET,QAAMe,IAAmBC;AAAA,IACvB,MAAMC,EAAoBhB,KAAa,MAAS;AAAA,IAChD,CAACA,CAAS;AAAA,EACZ;AAGA,EAAAY,EAAU,MACD,MAAM;AACX,IAAIE,KACF,IAAI,gBAAgBA,CAAgB;AAAA,EAExC,GACC,CAACA,CAAgB,CAAC;AAErB,QAAMG,IAAaC;AAAA,IACjB,CAACC,MAAyD;AACxD,MAAAX,EAAY,EAAI,GAChBP,IAASkB,CAAK;AAAA,IAChB;AAAA,IACA,CAAClB,CAAM;AAAA,EACT,GAGMmB,IAAWL,EAAQ,MACnBL,KACGW,EAAmBvB,CAAG,GAC5B,CAACY,GAASZ,CAAG,CAAC;AAGf,SAAA,gBAAAwB;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAWC,EAAG,mBAAmBrB,CAAS;AAAA,MAC1C,OAAO;AAAA,QACL,GAAGC;AAAA,QACH,GAAIC,MAAgB,UAAU,EAAC,aAAAA,EAAW;AAAA,MAC5C;AAAA,MAEC,UAAA;AAAA,QAAAU,KAAoB,CAACP,KACpB,gBAAAiB;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,WAAWD;AAAA,cACTnB,MAAgB,SACZ,kBACA;AAAA,cACJ;AAAA,YACF;AAAA,YACA,KAAKU;AAAA,YACL,eAAY;AAAA,UAAA;AAAA,QACd;AAAA,QAEF,gBAAAU;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,WAAWD;AAAA,cACTnB,MAAgB,SACZ,4BACA;AAAA,cACJ,UAAUC,CAAS;AAAA,cACnBE,KAAY;AAAA,YACd;AAAA,YACA,KAAKa;AAAA,YACL,QAAQH;AAAA,YACP,GAAGX;AAAA,UAAA;AAAA,QAAA;AAAA,MACN;AAAA,IAAA;AAAA,EACF;AAEJ,CAAC;"}
|
|
@@ -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\
|
|
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,6 +1,6 @@
|
|
|
1
1
|
import { jsx as n, jsxs as h, Fragment as d } from "react/jsx-runtime";
|
|
2
|
-
import { formatMoney as a } from "../../lib/formatMoney.js";
|
|
3
2
|
import { cn as i } from "../../lib/utils.js";
|
|
3
|
+
import { formatMoney as a } from "../../utils/formatMoney.js";
|
|
4
4
|
function N({
|
|
5
5
|
amount: r,
|
|
6
6
|
currencyCode: t,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"product-variant-price.js","sources":["../../../src/components/atoms/product-variant-price.tsx"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"product-variant-price.js","sources":["../../../src/components/atoms/product-variant-price.tsx"],"sourcesContent":["import {cn} from '../../lib/utils'\nimport {formatMoney} from '../../utils/formatMoney'\n\nexport interface ProductVariantPriceProps {\n amount: number | string\n currencyCode?: string\n compareAtPriceAmount?: number | string\n compareAtPriceCurrencyCode?: string\n currentPriceClassName?: string\n originalPriceClassName?: string\n className?: string\n}\n\nexport function ProductVariantPrice({\n amount,\n currencyCode,\n compareAtPriceAmount,\n compareAtPriceCurrencyCode,\n currentPriceClassName,\n originalPriceClassName,\n className,\n}: ProductVariantPriceProps) {\n if (!amount || !currencyCode) {\n return null\n }\n\n const hasDiscount = compareAtPriceAmount && compareAtPriceAmount !== amount\n\n const amountStr = String(amount)\n const compareAtPriceAmountStr = compareAtPriceAmount\n ? String(compareAtPriceAmount)\n : undefined\n\n return (\n <div className={cn('flex items-center gap-2', className)}>\n {hasDiscount ? (\n <>\n <span\n className={cn(\n 'text-sm font-semibold text-gray-900',\n currentPriceClassName\n )}\n >\n {formatMoney(amountStr, currencyCode)}\n </span>\n <span\n className={cn(\n 'text-sm text-gray-500 line-through',\n originalPriceClassName\n )}\n >\n {formatMoney(\n compareAtPriceAmountStr!,\n compareAtPriceCurrencyCode || currencyCode\n )}\n </span>\n </>\n ) : (\n <span\n className={cn(\n 'text-sm font-semibold text-gray-900',\n currentPriceClassName\n )}\n >\n {formatMoney(amountStr, currencyCode)}\n </span>\n )}\n </div>\n )\n}\n"],"names":["ProductVariantPrice","amount","currencyCode","compareAtPriceAmount","compareAtPriceCurrencyCode","currentPriceClassName","originalPriceClassName","className","hasDiscount","amountStr","compareAtPriceAmountStr","jsx","cn","jsxs","Fragment","formatMoney"],"mappings":";;;AAaO,SAASA,EAAoB;AAAA,EAClC,QAAAC;AAAA,EACA,cAAAC;AAAA,EACA,sBAAAC;AAAA,EACA,4BAAAC;AAAA,EACA,uBAAAC;AAAA,EACA,wBAAAC;AAAA,EACA,WAAAC;AACF,GAA6B;AACvB,MAAA,CAACN,KAAU,CAACC;AACP,WAAA;AAGH,QAAAM,IAAcL,KAAwBA,MAAyBF,GAE/DQ,IAAY,OAAOR,CAAM,GACzBS,IAA0BP,IAC5B,OAAOA,CAAoB,IAC3B;AAGF,SAAA,gBAAAQ,EAAC,SAAI,WAAWC,EAAG,2BAA2BL,CAAS,GACpD,cAEG,gBAAAM,EAAAC,GAAA,EAAA,UAAA;AAAA,IAAA,gBAAAH;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAWC;AAAA,UACT;AAAA,UACAP;AAAA,QACF;AAAA,QAEC,UAAAU,EAAYN,GAAWP,CAAY;AAAA,MAAA;AAAA,IACtC;AAAA,IACA,gBAAAS;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAWC;AAAA,UACT;AAAA,UACAN;AAAA,QACF;AAAA,QAEC,UAAAS;AAAA,UACCL;AAAA,UACAN,KAA8BF;AAAA,QAAA;AAAA,MAChC;AAAA,IAAA;AAAA,EACF,EAAA,CACF,IAEA,gBAAAS;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAWC;AAAA,QACT;AAAA,QACAP;AAAA,MACF;AAAA,MAEC,UAAAU,EAAYN,GAAWP,CAAY;AAAA,IAAA;AAAA,EAAA,GAG1C;AAEJ;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text-input.js","sources":["../../../src/components/atoms/text-input.tsx"],"sourcesContent":["import * as React from 'react'\n\nimport {useKeyboardAvoidingView} from '../../hooks'\nimport {Input} from '../ui/input'\n\nfunction TextInput({...props}:
|
|
1
|
+
{"version":3,"file":"text-input.js","sources":["../../../src/components/atoms/text-input.tsx"],"sourcesContent":["import * as React from 'react'\n\nimport {useKeyboardAvoidingView} from '../../hooks'\nimport {Input} from '../ui/input'\n\nexport type TextInputProps = React.ComponentProps<'input'>\n\nfunction TextInput({...props}: TextInputProps) {\n const inputRef = React.useRef<HTMLInputElement>(null)\n const {onBlur, onFocus} = useKeyboardAvoidingView()\n\n const _onFocus = React.useCallback(\n (event: React.FocusEvent<HTMLInputElement>) => {\n onFocus(inputRef)\n props.onFocus?.(event)\n },\n [props, onFocus, inputRef]\n )\n\n const _onBlur = React.useCallback(\n (event: React.FocusEvent<HTMLInputElement>) => {\n onBlur()\n props.onBlur?.(event)\n },\n [props, onBlur]\n )\n\n return (\n <Input innerRef={inputRef} onFocus={_onFocus} onBlur={_onBlur} {...props} />\n )\n}\n\nexport {TextInput}\n"],"names":["TextInput","props","inputRef","React","onBlur","onFocus","useKeyboardAvoidingView","_onFocus","event","_onBlur","jsx","Input"],"mappings":";;;;AAOA,SAASA,EAAU,EAAC,GAAGC,KAAwB;AACvC,QAAAC,IAAWC,EAAM,OAAyB,IAAI,GAC9C,EAAC,QAAAC,GAAQ,SAAAC,EAAO,IAAIC,EAAwB,GAE5CC,IAAWJ,EAAM;AAAA,IACrB,CAACK,MAA8C;AAC7C,MAAAH,EAAQH,CAAQ,GAChBD,EAAM,UAAUO,CAAK;AAAA,IACvB;AAAA,IACA,CAACP,GAAOI,GAASH,CAAQ;AAAA,EAC3B,GAEMO,IAAUN,EAAM;AAAA,IACpB,CAACK,MAA8C;AACtC,MAAAJ,EAAA,GACPH,EAAM,SAASO,CAAK;AAAA,IACtB;AAAA,IACA,CAACP,GAAOG,CAAM;AAAA,EAChB;AAGE,SAAA,gBAAAM,EAACC,KAAM,UAAUT,GAAU,SAASK,GAAU,QAAQE,GAAU,GAAGR,EAAO,CAAA;AAE9E;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"touchable.js","sources":["../../../src/components/atoms/touchable.tsx"],"sourcesContent":["import * as React from 'react'\n\nimport {motion, HTMLMotionProps, useAnimationControls} from 'motion/react'\n\nexport
|
|
1
|
+
{"version":3,"file":"touchable.js","sources":["../../../src/components/atoms/touchable.tsx"],"sourcesContent":["import * as React from 'react'\n\nimport {motion, HTMLMotionProps, useAnimationControls} from 'motion/react'\n\nexport interface TouchableDocProps {\n /** Click handler */\n onClick?: React.MouseEventHandler<HTMLDivElement>\n /** Prevent click event from bubbling to parent elements */\n stopPropagation?: boolean\n /** Content to render inside the touchable area */\n children?: React.ReactNode\n}\n\nexport interface TouchableProps extends HTMLMotionProps<'div'> {\n onClick?: React.MouseEventHandler<HTMLDivElement>\n stopPropagation?: boolean\n}\n\nexport const Touchable = ({\n children,\n onClick,\n stopPropagation = false,\n ...props\n}: TouchableProps) => {\n const ref = React.useRef<HTMLDivElement>(null)\n const controls = useAnimationControls()\n\n // Filter out props that shouldn't be passed to motion.div\n // Any other custom props that get added to the component interface should be filtered here\n const {ref: _, ...motionProps} = props\n\n const handleClick = React.useCallback(\n (event: React.MouseEvent<HTMLDivElement>) => {\n if (stopPropagation) event.stopPropagation()\n onClick?.(event)\n },\n [stopPropagation, onClick]\n )\n\n // Handle animations manually when stopPropagation is true to prevent parent from receiving event\n React.useEffect(() => {\n if (!stopPropagation || !ref.current) return\n\n const element = ref.current\n\n const handlePointerDown = (event: PointerEvent) => {\n event.stopImmediatePropagation()\n event.stopPropagation()\n\n // Animate to pressed state\n controls.start({\n opacity: 0.7,\n transition: {\n opacity: {type: 'tween', duration: 0.08, ease: 'linear'},\n },\n })\n }\n\n const handlePointerUp = (event: PointerEvent) => {\n event.stopImmediatePropagation()\n event.stopPropagation()\n\n // Animate back to normal state\n controls.start({\n opacity: 1,\n transition: {\n opacity: {type: 'tween', duration: 0.08, ease: 'linear'},\n },\n })\n }\n\n // Capture pointer event before Motion\n element.addEventListener('pointerdown', handlePointerDown, true)\n element.addEventListener('pointerup', handlePointerUp, true)\n\n return () => {\n element.removeEventListener('pointerdown', handlePointerDown, true)\n element.removeEventListener('pointerup', handlePointerUp, true)\n }\n }, [stopPropagation, controls])\n\n return (\n <motion.div\n ref={ref}\n data-touchable=\"true\"\n className=\"flex w-full\"\n animate={stopPropagation ? controls : undefined}\n whileTap={stopPropagation ? undefined : {opacity: 0.7}}\n transition={{\n opacity: {type: 'tween', duration: 0.08, ease: 'linear'},\n }}\n onClick={handleClick}\n style={{\n touchAction: stopPropagation ? 'manipulation' : undefined,\n }}\n {...motionProps}\n >\n {children}\n </motion.div>\n )\n}\n"],"names":["Touchable","children","onClick","stopPropagation","props","ref","React","controls","useAnimationControls","_","motionProps","handleClick","event","element","handlePointerDown","handlePointerUp","jsx","motion"],"mappings":";;;;AAkBO,MAAMA,IAAY,CAAC;AAAA,EACxB,UAAAC;AAAA,EACA,SAAAC;AAAA,EACA,iBAAAC,IAAkB;AAAA,EAClB,GAAGC;AACL,MAAsB;AACd,QAAAC,IAAMC,EAAM,OAAuB,IAAI,GACvCC,IAAWC,EAAqB,GAIhC,EAAC,KAAKC,GAAG,GAAGC,EAAe,IAAAN,GAE3BO,IAAcL,EAAM;AAAA,IACxB,CAACM,MAA4C;AACvC,MAAAT,OAAuB,gBAAgB,GAC3CD,IAAUU,CAAK;AAAA,IACjB;AAAA,IACA,CAACT,GAAiBD,CAAO;AAAA,EAC3B;AAGA,SAAAI,EAAM,UAAU,MAAM;AACpB,QAAI,CAACH,KAAmB,CAACE,EAAI,QAAS;AAEtC,UAAMQ,IAAUR,EAAI,SAEdS,IAAoB,CAACF,MAAwB;AACjD,MAAAA,EAAM,yBAAyB,GAC/BA,EAAM,gBAAgB,GAGtBL,EAAS,MAAM;AAAA,QACb,SAAS;AAAA,QACT,YAAY;AAAA,UACV,SAAS,EAAC,MAAM,SAAS,UAAU,MAAM,MAAM,SAAQ;AAAA,QAAA;AAAA,MACzD,CACD;AAAA,IACH,GAEMQ,IAAkB,CAACH,MAAwB;AAC/C,MAAAA,EAAM,yBAAyB,GAC/BA,EAAM,gBAAgB,GAGtBL,EAAS,MAAM;AAAA,QACb,SAAS;AAAA,QACT,YAAY;AAAA,UACV,SAAS,EAAC,MAAM,SAAS,UAAU,MAAM,MAAM,SAAQ;AAAA,QAAA;AAAA,MACzD,CACD;AAAA,IACH;AAGQ,WAAAM,EAAA,iBAAiB,eAAeC,GAAmB,EAAI,GACvDD,EAAA,iBAAiB,aAAaE,GAAiB,EAAI,GAEpD,MAAM;AACH,MAAAF,EAAA,oBAAoB,eAAeC,GAAmB,EAAI,GAC1DD,EAAA,oBAAoB,aAAaE,GAAiB,EAAI;AAAA,IAChE;AAAA,EAAA,GACC,CAACZ,GAAiBI,CAAQ,CAAC,GAG5B,gBAAAS;AAAA,IAACC,EAAO;AAAA,IAAP;AAAA,MACC,KAAAZ;AAAA,MACA,kBAAe;AAAA,MACf,WAAU;AAAA,MACV,SAASF,IAAkBI,IAAW;AAAA,MACtC,UAAUJ,IAAkB,SAAY,EAAC,SAAS,IAAG;AAAA,MACrD,YAAY;AAAA,QACV,SAAS,EAAC,MAAM,SAAS,UAAU,MAAM,MAAM,SAAQ;AAAA,MACzD;AAAA,MACA,SAASQ;AAAA,MACT,OAAO;AAAA,QACL,aAAaR,IAAkB,iBAAiB;AAAA,MAClD;AAAA,MACC,GAAGO;AAAA,MAEH,UAAAT;AAAA,IAAA;AAAA,EACH;AAEJ;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"video-player.js","sources":["../../../src/components/atoms/video-player.tsx"],"sourcesContent":["import {\n useRef,\n useEffect,\n useState,\n useCallback,\n forwardRef,\n useImperativeHandle,\n useMemo,\n} from 'react'\n\nimport videojs from 'video.js'\nimport Player from 'video.js/dist/types/player'\nimport 'video.js/dist/video-js.css'\n\nexport interface VideoPlayerRef {\n play: () => Promise<void>\n pause: () => void\n}\n\
|
|
1
|
+
{"version":3,"file":"video-player.js","sources":["../../../src/components/atoms/video-player.tsx"],"sourcesContent":["import {\n useRef,\n useEffect,\n useState,\n useCallback,\n forwardRef,\n useImperativeHandle,\n useMemo,\n} from 'react'\n\nimport videojs from 'video.js'\nimport Player from 'video.js/dist/types/player'\nimport 'video.js/dist/video-js.css'\n\nexport interface VideoPlayerRef {\n play: () => Promise<void>\n pause: () => void\n}\n\nexport interface VideoPlayerProps {\n /** The video source URL */\n src: string\n /** The format/MIME type of the video (default: 'video/mp4') */\n format?: string\n /** Whether the video should be muted */\n muted?: boolean\n /** URL for the poster image shown before playback */\n poster?: string\n /** Whether the video should autoplay */\n autoplay?: boolean\n /** Preload behavior: 'none', 'metadata', or 'auto' */\n preload?: 'none' | 'metadata' | 'auto'\n /** Whether the video should loop */\n loop?: boolean\n /** Video width in pixels */\n width?: number\n /** Video height in pixels */\n height?: number\n /** Custom play button component */\n playButtonComponent?: React.ReactNode\n /** Callback when video starts playing */\n onPlay?: () => void\n /** Callback when video is paused */\n onPause?: () => void\n /** Callback when video ends */\n onEnded?: () => void\n /** Callback when video player is ready */\n onReady?: () => void\n}\n\nexport const VideoPlayer: React.ForwardRefExoticComponent<\n VideoPlayerProps & React.RefAttributes<VideoPlayerRef>\n> = forwardRef<VideoPlayerRef, VideoPlayerProps>(\n (\n {\n src,\n format = 'video/mp4',\n poster,\n muted,\n autoplay,\n preload = 'auto',\n loop = false,\n width,\n height,\n playButtonComponent,\n onPlay,\n onPause,\n onEnded,\n onReady,\n },\n ref\n ) => {\n const videoContainerRef = useRef<HTMLDivElement>(null)\n const playerRef = useRef<Player | null>(null)\n\n const [isPlaying, setIsPlaying] = useState(false)\n\n // Expose imperative methods to parent components\n useImperativeHandle(\n ref,\n () => ({\n play: async () => {\n if (playerRef.current) {\n try {\n await playerRef.current.play()\n setIsPlaying(true)\n } catch (error) {\n console.error('Error playing video:', error)\n }\n }\n },\n pause: () => {\n if (playerRef.current) {\n playerRef.current.pause()\n setIsPlaying(false)\n }\n },\n }),\n []\n )\n\n const options = useMemo(\n () => ({\n controls: false,\n controlBar: {\n volumePanel: {\n inline: false,\n },\n },\n preload,\n loop,\n muted,\n // This makes sure that the video player does not take over the whole screen\n preferFullWindow: false,\n playsinline: true,\n poster,\n height,\n width,\n sources: [\n {\n src,\n type: format,\n },\n ],\n }),\n [muted, poster, height, width, src, format, preload, loop]\n )\n\n useEffect(() => {\n const player = playerRef.current\n\n return () => {\n if (player && !player.isDisposed()) {\n player.dispose()\n playerRef.current = null\n }\n }\n }, [playerRef])\n\n useEffect(() => {\n if (!playerRef.current) return\n\n const handlePlay = () => {\n onPlay?.()\n setIsPlaying(true)\n }\n const handlePause = () => {\n onPause?.()\n setIsPlaying(false)\n }\n const handleEnded = () => {\n onEnded?.()\n setIsPlaying(false)\n }\n\n playerRef.current.on('play', handlePlay)\n playerRef.current.on('pause', handlePause)\n playerRef.current.on('ended', handleEnded)\n\n return () => {\n if (playerRef.current) {\n playerRef.current.off('play', handlePlay)\n playerRef.current.off('pause', handlePause)\n playerRef.current.off('ended', handleEnded)\n }\n }\n }, [onEnded, onPause, onPlay])\n\n const togglePlayPause = useCallback(() => {\n if (isPlaying) {\n playerRef.current?.pause()\n setIsPlaying(false)\n } else {\n playerRef.current?.play()\n setIsPlaying(true)\n }\n }, [isPlaying])\n\n useEffect(() => {\n if (!playerRef.current) {\n const videoElement = document.createElement('video-js')\n\n // The Video.js player needs to be _inside_ the component element for React 18 Strict Mode.\n videoContainerRef.current?.appendChild(videoElement)\n\n playerRef.current = videojs(videoElement, options, () => {\n onReady && onReady()\n\n if (autoplay) {\n togglePlayPause()\n }\n })\n }\n }, [options, videoContainerRef, autoplay, onReady, togglePlayPause])\n\n // Update muted state when prop changes after initial render\n useEffect(() => {\n if (playerRef.current && !playerRef.current.isDisposed()) {\n playerRef.current.muted(muted ?? false)\n }\n }, [muted])\n\n const containerClassName = [\n width ? `w-${width}` : undefined,\n 'relative',\n ].join(' ')\n\n return (\n <div className=\"flex\">\n <div data-vjs-player className={containerClassName}>\n <div ref={videoContainerRef} />\n <div\n className=\"absolute top-0 left-0 w-full h-full flex items-center justify-center cursor-pointer\"\n onClick={togglePlayPause}\n aria-hidden\n >\n {isPlaying ? null : (playButtonComponent ?? <DefaultPlayIcon />)}\n </div>\n </div>\n </div>\n )\n }\n)\n\nconst DefaultPlayIcon = () => (\n <div className=\"absolute inset-0 flex items-center justify-center bg-black/20 cursor-pointer animate-in fade-in duration-200\">\n <svg\n viewBox=\"0 0 24 24\"\n className=\"w-10 h-10 text-white\"\n fill=\"currentColor\"\n >\n <path d=\"M8 5v14l11-7z\" />\n </svg>\n </div>\n)\n"],"names":["VideoPlayer","forwardRef","src","format","poster","muted","autoplay","preload","loop","width","height","playButtonComponent","onPlay","onPause","onEnded","onReady","ref","videoContainerRef","useRef","playerRef","isPlaying","setIsPlaying","useState","useImperativeHandle","error","options","useMemo","useEffect","player","handlePlay","handlePause","handleEnded","togglePlayPause","useCallback","videoElement","videojs","containerClassName","jsx","DefaultPlayIcon"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"add-to-cart.js","sources":["../../../src/components/commerce/add-to-cart.tsx"],"sourcesContent":["import * as React from 'react'\nimport {useState, useCallback} from 'react'\n\nimport {Product} from '@shopify/shop-minis-platform'\nimport {CheckIcon} from 'lucide-react'\nimport {motion, AnimatePresence} from 'motion/react'\n\nimport {useErrorToast, useShopNavigation} from '../../hooks'\nimport {useShopCartActions} from '../../internal/useShopCartActions'\nimport {cn} from '../../lib/utils'\nimport {Button} from '../atoms/button'\n\
|
|
1
|
+
{"version":3,"file":"add-to-cart.js","sources":["../../../src/components/commerce/add-to-cart.tsx"],"sourcesContent":["import * as React from 'react'\nimport {useState, useCallback} from 'react'\n\nimport {Product} from '@shopify/shop-minis-platform'\nimport {CheckIcon} from 'lucide-react'\nimport {motion, AnimatePresence} from 'motion/react'\n\nimport {useErrorToast, useShopNavigation} from '../../hooks'\nimport {useShopCartActions} from '../../internal/useShopCartActions'\nimport {cn} from '../../lib/utils'\nimport {Button} from '../atoms/button'\n\nexport interface AddToCartButtonProps {\n /** Whether the button is disabled */\n disabled?: boolean\n /** CSS class name */\n className?: string\n /** Button size variant */\n size?: 'default' | 'sm' | 'lg'\n /** The discount codes to apply to the cart */\n discountCodes?: string[]\n /** The GID of the product variant. E.g. `gid://shopify/ProductVariant/456` */\n productVariantId: string\n /** The product to add to the cart */\n product?: Product\n}\n\nexport function AddToCartButton({\n disabled = false,\n className,\n size = 'default',\n productVariantId,\n discountCodes,\n product,\n}: AddToCartButtonProps) {\n const {addToCart} = useShopCartActions()\n const {navigateToProduct} = useShopNavigation()\n const [isAdded, setIsAdded] = useState(false)\n const timeoutRef = React.useRef<number | undefined>(undefined)\n const {id, referral, variants} = product ?? {}\n\n const variantImageUrl = variants?.find(\n variant => variant.id === productVariantId\n )?.image?.url\n\n const {showErrorToast} = useErrorToast()\n\n const handleClick = useCallback(async () => {\n if (disabled) return\n\n if (id && referral) {\n navigateToProduct({\n productId: id,\n })\n\n return\n }\n\n if (isAdded) return\n\n try {\n if (id && productVariantId) {\n addToCart({\n productId: id,\n productVariantId,\n quantity: 1,\n discountCodes,\n variantImageUrl,\n })\n .then(() => {})\n .catch(() => {\n showErrorToast({message: 'Failed to add to cart'})\n })\n }\n\n // Show success state\n setIsAdded(true)\n\n // Clear any existing timeout\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current)\n }\n\n // Reset to initial state after delay\n timeoutRef.current = window.setTimeout(() => {\n setIsAdded(false)\n }, 2000)\n } catch (error) {\n // Handle error - reset to initial state\n setIsAdded(false)\n console.error('Failed to add to cart:', error)\n }\n }, [\n disabled,\n id,\n referral,\n isAdded,\n navigateToProduct,\n productVariantId,\n addToCart,\n discountCodes,\n variantImageUrl,\n showErrorToast,\n ])\n\n // Cleanup timeout on unmount\n React.useEffect(() => {\n return () => {\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current)\n }\n }\n }, [])\n\n const addToCartText = isAdded ? 'Added to cart' : 'Add to cart'\n const buttonText = referral ? 'View product' : addToCartText\n\n return (\n <Button\n onClick={handleClick}\n disabled={disabled}\n className={cn(\n 'relative overflow-hidden transition-all duration-300',\n className\n )}\n size={size}\n >\n <div className=\"relative flex items-center justify-center\">\n <AnimatePresence>\n {isAdded && (\n <motion.div\n initial={{scale: 0, rotate: -180}}\n animate={{scale: 1, rotate: 0}}\n exit={{scale: 0, rotate: 180}}\n transition={{\n duration: 0.4,\n ease: [0.175, 0.885, 0.32, 1.275], // bounce effect\n }}\n className=\"absolute left-2\"\n style={{x: -8}}\n >\n <CheckIcon className=\"size-4\" />\n </motion.div>\n )}\n </AnimatePresence>\n <span className={cn(isAdded && 'pl-5', 'transition-all duration-300')}>\n {buttonText}\n </span>\n </div>\n </Button>\n )\n}\n"],"names":["AddToCartButton","disabled","className","size","productVariantId","discountCodes","product","addToCart","useShopCartActions","navigateToProduct","useShopNavigation","isAdded","setIsAdded","useState","timeoutRef","React","id","referral","variants","variantImageUrl","variant","showErrorToast","useErrorToast","handleClick","useCallback","error","buttonText","jsx","Button","cn","jsxs","AnimatePresence","motion","CheckIcon"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"buy-now.js","sources":["../../../src/components/commerce/buy-now.tsx"],"sourcesContent":["import {useState, useCallback} from 'react'\n\nimport {Product} from '@shopify/shop-minis-platform'\nimport {motion, AnimatePresence} from 'motion/react'\n\nimport {useErrorToast, useShopNavigation} from '../../hooks'\nimport {useShopCartActions} from '../../internal/useShopCartActions'\nimport {cn} from '../../lib/utils'\nimport {Button} from '../atoms/button'\n\
|
|
1
|
+
{"version":3,"file":"buy-now.js","sources":["../../../src/components/commerce/buy-now.tsx"],"sourcesContent":["import {useState, useCallback} from 'react'\n\nimport {Product} from '@shopify/shop-minis-platform'\nimport {motion, AnimatePresence} from 'motion/react'\n\nimport {useErrorToast, useShopNavigation} from '../../hooks'\nimport {useShopCartActions} from '../../internal/useShopCartActions'\nimport {cn} from '../../lib/utils'\nimport {Button} from '../atoms/button'\n\nexport interface BuyNowButtonProps {\n /** Whether the button is disabled */\n disabled?: boolean\n /** CSS class name */\n className?: string\n /** Button size variant */\n size?: 'default' | 'sm' | 'lg'\n /** The discount code to apply to the purchase */\n discountCode?: string\n /** The GID of the product variant. E.g. `gid://shopify/ProductVariant/456` */\n productVariantId: string\n /** The product to buy now */\n product?: Product\n}\n\nexport function BuyNowButton({\n disabled = false,\n className,\n size = 'default',\n productVariantId,\n discountCode,\n product,\n}: BuyNowButtonProps) {\n const {buyProduct} = useShopCartActions()\n const {navigateToProduct} = useShopNavigation()\n const [isPurchasing, setIsPurchasing] = useState(false)\n const {id, referral} = product ?? {}\n\n const {showErrorToast} = useErrorToast()\n\n const handleClick = useCallback(async () => {\n if (disabled) return\n\n if (id && referral) {\n navigateToProduct({\n productId: id,\n })\n\n return\n }\n\n if (isPurchasing) return\n\n try {\n if (id && productVariantId) {\n setIsPurchasing(true)\n\n await buyProduct({\n productId: id,\n productVariantId,\n quantity: 1,\n discountCode,\n })\n\n setIsPurchasing(false)\n }\n } catch (error) {\n showErrorToast({message: 'Failed to complete purchase'})\n setIsPurchasing(false)\n }\n }, [\n disabled,\n id,\n referral,\n isPurchasing,\n navigateToProduct,\n productVariantId,\n buyProduct,\n discountCode,\n showErrorToast,\n ])\n\n return (\n <Button\n onClick={handleClick}\n disabled={disabled || isPurchasing}\n className={cn('relative overflow-hidden', className)}\n size={size}\n aria-live=\"polite\"\n aria-busy={isPurchasing}\n >\n <AnimatePresence mode=\"wait\">\n <motion.span\n key=\"text\"\n initial={{opacity: 0, y: 10}}\n animate={{opacity: 1, y: 0}}\n exit={{opacity: 0, y: -10}}\n transition={{duration: 0.2}}\n >\n {referral ? 'View product' : 'Buy now'}\n </motion.span>\n </AnimatePresence>\n </Button>\n )\n}\n"],"names":["BuyNowButton","disabled","className","size","productVariantId","discountCode","product","buyProduct","useShopCartActions","navigateToProduct","useShopNavigation","isPurchasing","setIsPurchasing","useState","id","referral","showErrorToast","useErrorToast","handleClick","useCallback","jsx","Button","cn","AnimatePresence","motion"],"mappings":";;;;;;;;;AAyBO,SAASA,EAAa;AAAA,EAC3B,UAAAC,IAAW;AAAA,EACX,WAAAC;AAAA,EACA,MAAAC,IAAO;AAAA,EACP,kBAAAC;AAAA,EACA,cAAAC;AAAA,EACA,SAAAC;AACF,GAAsB;AACd,QAAA,EAAC,YAAAC,EAAU,IAAIC,EAAmB,GAClC,EAAC,mBAAAC,EAAiB,IAAIC,EAAkB,GACxC,CAACC,GAAcC,CAAe,IAAIC,EAAS,EAAK,GAChD,EAAC,IAAAC,GAAI,UAAAC,EAAQ,IAAIT,KAAW,CAAC,GAE7B,EAAC,gBAAAU,EAAc,IAAIC,EAAc,GAEjCC,IAAcC,EAAY,YAAY;AAC1C,QAAI,CAAAlB,GAEJ;AAAA,UAAIa,KAAMC,GAAU;AACA,QAAAN,EAAA;AAAA,UAChB,WAAWK;AAAA,QAAA,CACZ;AAED;AAAA,MAAA;AAGF,UAAI,CAAAH;AAEA,YAAA;AACF,UAAIG,KAAMV,MACRQ,EAAgB,EAAI,GAEpB,MAAML,EAAW;AAAA,YACf,WAAWO;AAAA,YACX,kBAAAV;AAAA,YACA,UAAU;AAAA,YACV,cAAAC;AAAA,UAAA,CACD,GAEDO,EAAgB,EAAK;AAAA,gBAET;AACC,UAAAI,EAAA,EAAC,SAAS,+BAA8B,GACvDJ,EAAgB,EAAK;AAAA,QAAA;AAAA;AAAA,EACvB,GACC;AAAA,IACDX;AAAA,IACAa;AAAA,IACAC;AAAA,IACAJ;AAAA,IACAF;AAAA,IACAL;AAAA,IACAG;AAAA,IACAF;AAAA,IACAW;AAAA,EAAA,CACD;AAGC,SAAA,gBAAAI;AAAA,IAACC;AAAA,IAAA;AAAA,MACC,SAASH;AAAA,MACT,UAAUjB,KAAYU;AAAA,MACtB,WAAWW,EAAG,4BAA4BpB,CAAS;AAAA,MACnD,MAAAC;AAAA,MACA,aAAU;AAAA,MACV,aAAWQ;AAAA,MAEX,UAAA,gBAAAS,EAACG,GAAgB,EAAA,MAAK,QACpB,UAAA,gBAAAH;AAAA,QAACI,EAAO;AAAA,QAAP;AAAA,UAEC,SAAS,EAAC,SAAS,GAAG,GAAG,GAAE;AAAA,UAC3B,SAAS,EAAC,SAAS,GAAG,GAAG,EAAC;AAAA,UAC1B,MAAM,EAAC,SAAS,GAAG,GAAG,IAAG;AAAA,UACzB,YAAY,EAAC,UAAU,IAAG;AAAA,UAEzB,cAAW,iBAAiB;AAAA,QAAA;AAAA,QANzB;AAAA,MAAA,EAQR,CAAA;AAAA,IAAA;AAAA,EACF;AAEJ;"}
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { jsx as r } from "react/jsx-runtime";
|
|
2
2
|
import { IconButton as n } from "../atoms/icon-button.js";
|
|
3
3
|
import m from "../../shop-minis-react/node_modules/.pnpm/lucide-react@0.513.0_react@19.1.0/node_modules/lucide-react/dist/esm/icons/heart.js";
|
|
4
|
-
function e({
|
|
5
|
-
onClick: t,
|
|
6
|
-
filled: o = !1
|
|
7
|
-
}) {
|
|
4
|
+
function e({ onClick: t, filled: o = !1 }) {
|
|
8
5
|
return /* @__PURE__ */ r(
|
|
9
6
|
n,
|
|
10
7
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"favorite-button.js","sources":["../../../src/components/commerce/favorite-button.tsx"],"sourcesContent":["import {Heart} from 'lucide-react'\n\nimport {IconButton} from '../atoms/icon-button'\n\nexport
|
|
1
|
+
{"version":3,"file":"favorite-button.js","sources":["../../../src/components/commerce/favorite-button.tsx"],"sourcesContent":["import {Heart} from 'lucide-react'\n\nimport {IconButton} from '../atoms/icon-button'\n\nexport interface FavoriteButtonProps {\n /** Click handler for toggling favorite state */\n onClick?: () => void\n /** Whether the product is currently favorited */\n filled?: boolean\n}\n\nexport function FavoriteButton({onClick, filled = false}: FavoriteButtonProps) {\n return (\n <IconButton\n Icon={Heart}\n filled={filled}\n onClick={onClick}\n buttonStyles={\n filled ? 'bg-primary' : 'bg-button-overlay/30 backdrop-blur-sm'\n }\n />\n )\n}\n"],"names":["FavoriteButton","onClick","filled","jsx","IconButton","Heart"],"mappings":";;;AAWO,SAASA,EAAe,EAAC,SAAAC,GAAS,QAAAC,IAAS,MAA6B;AAE3E,SAAA,gBAAAC;AAAA,IAACC;AAAA,IAAA;AAAA,MACC,MAAMC;AAAA,MACN,QAAAH;AAAA,MACA,SAAAD;AAAA,MACA,cACEC,IAAS,eAAe;AAAA,IAAA;AAAA,EAE5B;AAEJ;"}
|