@shopify/shop-minis-react 0.4.0 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/atoms/list.js +57 -65
- package/dist/components/atoms/list.js.map +1 -1
- package/dist/hooks/util/useImagePicker.js +13 -6
- package/dist/hooks/util/useImagePicker.js.map +1 -1
- package/dist/internal/utils/resizeImage.js +61 -0
- package/dist/internal/utils/resizeImage.js.map +1 -0
- package/dist/providers/ImagePickerProvider.js +123 -102
- package/dist/providers/ImagePickerProvider.js.map +1 -1
- package/package.json +1 -1
- package/src/components/atoms/list.tsx +3 -12
- package/src/hooks/util/useImagePicker.test.tsx +193 -0
- package/src/hooks/util/useImagePicker.ts +24 -5
- package/src/internal/utils/resizeImage.test.ts +314 -0
- package/src/internal/utils/resizeImage.ts +108 -0
- package/src/providers/ImagePickerProvider.test.tsx +32 -1
- package/src/providers/ImagePickerProvider.tsx +108 -65
- package/dist/components/atoms/pagination.js +0 -10
- package/dist/components/atoms/pagination.js.map +0 -1
- package/dist/components/atoms/tracking-pixel.js +0 -32
- package/dist/components/atoms/tracking-pixel.js.map +0 -1
- package/dist/shop-minis-react/node_modules/.pnpm/react-intersection-observer@9.13.1_react-dom@19.1.0_react@19.1.0__react@19.1.0/node_modules/react-intersection-observer/dist/index.js +0 -135
- package/dist/shop-minis-react/node_modules/.pnpm/react-intersection-observer@9.13.1_react-dom@19.1.0_react@19.1.0__react@19.1.0/node_modules/react-intersection-observer/dist/index.js.map +0 -1
- package/src/components/atoms/pagination.tsx +0 -19
- package/src/components/atoms/tracking-pixel.tsx +0 -40
|
@@ -1,70 +1,62 @@
|
|
|
1
|
-
import { jsx as e, Fragment as
|
|
2
|
-
import { useRef as
|
|
3
|
-
import { Virtuoso as
|
|
4
|
-
import { RefreshIndicator as
|
|
5
|
-
import { usePullToRefresh as
|
|
6
|
-
import { findVirtuosoScrollableElement as
|
|
7
|
-
import { cn as
|
|
1
|
+
import { jsx as e, Fragment as E, jsxs as w } from "react/jsx-runtime";
|
|
2
|
+
import { useRef as d, useCallback as a, useEffect as b } from "react";
|
|
3
|
+
import { Virtuoso as g } from "../../shop-minis-react/node_modules/.pnpm/react-virtuoso@4.14.0_react-dom@19.1.0_react@19.1.0__react@19.1.0/node_modules/react-virtuoso/dist/index.js";
|
|
4
|
+
import { RefreshIndicator as k } from "../../internal/components/refresh-indicator.js";
|
|
5
|
+
import { usePullToRefresh as I } from "../../internal/usePullToRefresh.js";
|
|
6
|
+
import { findVirtuosoScrollableElement as M } from "../../internal/utils/virtuoso-dom.js";
|
|
7
|
+
import { cn as v } from "../../lib/utils.js";
|
|
8
8
|
/* empty css */
|
|
9
|
-
import {
|
|
10
|
-
const
|
|
11
|
-
function
|
|
12
|
-
items:
|
|
13
|
-
height:
|
|
14
|
-
renderItem:
|
|
15
|
-
className:
|
|
16
|
-
showScrollbar:
|
|
9
|
+
import { Skeleton as U } from "../ui/skeleton.js";
|
|
10
|
+
const D = 200, V = 100;
|
|
11
|
+
function Q({
|
|
12
|
+
items: N,
|
|
13
|
+
height: x,
|
|
14
|
+
renderItem: f,
|
|
15
|
+
className: H,
|
|
16
|
+
showScrollbar: L = !1,
|
|
17
17
|
header: u,
|
|
18
18
|
fetchMore: r,
|
|
19
|
-
loadingComponent:
|
|
20
|
-
isFetchingMore: h,
|
|
19
|
+
loadingComponent: p,
|
|
21
20
|
onRefresh: n,
|
|
22
21
|
refreshing: m,
|
|
23
22
|
enablePullToRefresh: i = !0,
|
|
24
|
-
...
|
|
23
|
+
...F
|
|
25
24
|
}) {
|
|
26
|
-
const
|
|
25
|
+
const s = d(null), _ = d(null), o = d(null), { state: l, bindToElement: h } = I({
|
|
27
26
|
onRefresh: n,
|
|
28
|
-
threshold:
|
|
27
|
+
threshold: D,
|
|
29
28
|
enabled: i && !!n
|
|
30
|
-
}),
|
|
31
|
-
if (
|
|
29
|
+
}), R = a(() => {
|
|
30
|
+
if (s.current) return;
|
|
32
31
|
const t = Promise.resolve(r?.()).finally(() => {
|
|
33
|
-
|
|
32
|
+
s.current === t && (s.current = null);
|
|
34
33
|
});
|
|
35
|
-
|
|
36
|
-
}, [r]),
|
|
37
|
-
(t, c) => /* @__PURE__ */ e(
|
|
38
|
-
[
|
|
39
|
-
),
|
|
40
|
-
|
|
41
|
-
{
|
|
42
|
-
fetchMore: d,
|
|
43
|
-
loadingComponent: E,
|
|
44
|
-
isFetchingMore: h
|
|
45
|
-
}
|
|
46
|
-
) : null, [d, r, E, h]), S = x(F ? void 0 : "no-scrollbars", _);
|
|
47
|
-
w(() => {
|
|
48
|
-
if (s.current && i && n) {
|
|
34
|
+
s.current = t;
|
|
35
|
+
}, [r]), S = a(
|
|
36
|
+
(t, c) => /* @__PURE__ */ e(E, { children: f(c, t) }),
|
|
37
|
+
[f]
|
|
38
|
+
), y = a(() => r ? p ?? /* @__PURE__ */ e(U, { className: "h-10 w-full p-8" }) : null, [p, r]), A = v(L ? void 0 : "no-scrollbars", H);
|
|
39
|
+
b(() => {
|
|
40
|
+
if (o.current && i && n) {
|
|
49
41
|
let t;
|
|
50
|
-
const
|
|
51
|
-
if (!
|
|
52
|
-
const
|
|
53
|
-
|
|
42
|
+
const T = setTimeout(() => {
|
|
43
|
+
if (!o.current) return;
|
|
44
|
+
const j = M(
|
|
45
|
+
o.current
|
|
54
46
|
);
|
|
55
|
-
t =
|
|
56
|
-
},
|
|
47
|
+
t = h(j);
|
|
48
|
+
}, V);
|
|
57
49
|
return () => {
|
|
58
|
-
clearTimeout(
|
|
50
|
+
clearTimeout(T), t && t();
|
|
59
51
|
};
|
|
60
52
|
}
|
|
61
|
-
}, [
|
|
62
|
-
const
|
|
63
|
-
const t = m ? Math.max(
|
|
53
|
+
}, [h, i, n]);
|
|
54
|
+
const B = a(() => {
|
|
55
|
+
const t = m ? Math.max(l.pullDistance, 140) : l.pullDistance, c = Math.min(
|
|
64
56
|
Math.max(t, 0),
|
|
65
57
|
140
|
|
66
58
|
);
|
|
67
|
-
return /* @__PURE__ */
|
|
59
|
+
return /* @__PURE__ */ w(E, { children: [
|
|
68
60
|
i && n && /* @__PURE__ */ e(
|
|
69
61
|
"div",
|
|
70
62
|
{
|
|
@@ -74,12 +66,12 @@ function W({
|
|
|
74
66
|
overflow: "hidden"
|
|
75
67
|
},
|
|
76
68
|
children: /* @__PURE__ */ e(
|
|
77
|
-
|
|
69
|
+
k,
|
|
78
70
|
{
|
|
79
|
-
pullDistance:
|
|
80
|
-
threshold:
|
|
71
|
+
pullDistance: l.pullDistance,
|
|
72
|
+
threshold: D,
|
|
81
73
|
isRefreshing: m ?? !1,
|
|
82
|
-
canRefresh:
|
|
74
|
+
canRefresh: l.canRefresh,
|
|
83
75
|
className: "relative top-0 inset-x-auto"
|
|
84
76
|
}
|
|
85
77
|
)
|
|
@@ -87,34 +79,34 @@ function W({
|
|
|
87
79
|
),
|
|
88
80
|
u && /* @__PURE__ */ e("div", { children: u })
|
|
89
81
|
] });
|
|
90
|
-
}, [u, i, n,
|
|
82
|
+
}, [u, i, n, l, m]);
|
|
91
83
|
return /* @__PURE__ */ e(
|
|
92
84
|
"div",
|
|
93
85
|
{
|
|
94
|
-
ref:
|
|
95
|
-
className:
|
|
86
|
+
ref: o,
|
|
87
|
+
className: v("relative transition-all duration-200", A),
|
|
96
88
|
style: {
|
|
97
|
-
height:
|
|
89
|
+
height: x
|
|
98
90
|
},
|
|
99
91
|
children: /* @__PURE__ */ e(
|
|
100
|
-
|
|
92
|
+
g,
|
|
101
93
|
{
|
|
102
|
-
ref:
|
|
94
|
+
ref: _,
|
|
103
95
|
className: "h-full w-full",
|
|
104
|
-
data:
|
|
105
|
-
itemContent:
|
|
96
|
+
data: N,
|
|
97
|
+
itemContent: S,
|
|
106
98
|
components: {
|
|
107
|
-
Header:
|
|
108
|
-
Footer:
|
|
99
|
+
Header: B,
|
|
100
|
+
Footer: y
|
|
109
101
|
},
|
|
110
|
-
endReached: r ?
|
|
111
|
-
...
|
|
102
|
+
endReached: r ? R : void 0,
|
|
103
|
+
...F
|
|
112
104
|
}
|
|
113
105
|
)
|
|
114
106
|
}
|
|
115
107
|
);
|
|
116
108
|
}
|
|
117
109
|
export {
|
|
118
|
-
|
|
110
|
+
Q as List
|
|
119
111
|
};
|
|
120
112
|
//# sourceMappingURL=list.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'\
|
|
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\ninterface Props<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}: Props<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,12 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { useCallback as o } from "react";
|
|
2
|
+
import { useImagePickerContext as c } from "../../providers/ImagePickerProvider.js";
|
|
3
|
+
function u() {
|
|
4
|
+
const { openCamera: t, openGallery: n } = c(), i = o(
|
|
5
|
+
async ({ cameraFacing: e, quality: a, customQuality: r } = {}) => await t({ cameraFacing: e, quality: a, customQuality: r }),
|
|
6
|
+
[t]
|
|
7
|
+
), l = o(
|
|
8
|
+
async ({ quality: e, customQuality: a } = {}) => await n({ quality: e, customQuality: a }),
|
|
9
|
+
[n]
|
|
10
|
+
);
|
|
4
11
|
return {
|
|
5
|
-
openCamera:
|
|
6
|
-
openGallery:
|
|
12
|
+
openCamera: i,
|
|
13
|
+
openGallery: l
|
|
7
14
|
};
|
|
8
15
|
}
|
|
9
16
|
export {
|
|
10
|
-
|
|
17
|
+
u as useImagePicker
|
|
11
18
|
};
|
|
12
19
|
//# sourceMappingURL=useImagePicker.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useImagePicker.js","sources":["../../../src/hooks/util/useImagePicker.ts"],"sourcesContent":["import {\n
|
|
1
|
+
{"version":3,"file":"useImagePicker.js","sources":["../../../src/hooks/util/useImagePicker.ts"],"sourcesContent":["import {useCallback} from 'react'\n\nimport {\n useImagePickerContext,\n OpenCameraParams,\n OpenGalleryParams,\n} from '../../providers/ImagePickerProvider'\n\ninterface UseImagePickerReturns {\n /**\n * Opens the camera to take a photo.\n */\n openCamera: (params?: OpenCameraParams) => Promise<File>\n /**\n * Opens the gallery to select an image.\n */\n openGallery: (params?: OpenGalleryParams) => Promise<File>\n}\n\nexport function useImagePicker(): UseImagePickerReturns {\n const {openCamera, openGallery} = useImagePickerContext()\n\n const openCameraWithQuality = useCallback(\n async ({cameraFacing, quality, customQuality}: OpenCameraParams = {}) => {\n const file = await openCamera({cameraFacing, quality, customQuality})\n return file\n },\n [openCamera]\n )\n\n const openGalleryWithQuality = useCallback(\n async ({quality, customQuality}: OpenGalleryParams = {}) => {\n const file = await openGallery({quality, customQuality})\n return file\n },\n [openGallery]\n )\n\n return {\n openCamera: openCameraWithQuality,\n openGallery: openGalleryWithQuality,\n }\n}\n"],"names":["useImagePicker","openCamera","openGallery","useImagePickerContext","openCameraWithQuality","useCallback","cameraFacing","quality","customQuality","openGalleryWithQuality"],"mappings":";;AAmBO,SAASA,IAAwC;AACtD,QAAM,EAAC,YAAAC,GAAY,aAAAC,EAAW,IAAIC,EAAsB,GAElDC,IAAwBC;AAAA,IAC5B,OAAO,EAAC,cAAAC,GAAc,SAAAC,GAAS,eAAAC,EAAa,IAAsB,CAAA,MACnD,MAAMP,EAAW,EAAC,cAAAK,GAAc,SAAAC,GAAS,eAAAC,GAAc;AAAA,IAGtE,CAACP,CAAU;AAAA,EACb,GAEMQ,IAAyBJ;AAAA,IAC7B,OAAO,EAAC,SAAAE,GAAS,eAAAC,EAAa,IAAuB,OACtC,MAAMN,EAAY,EAAC,SAAAK,GAAS,eAAAC,GAAc;AAAA,IAGzD,CAACN,CAAW;AAAA,EACd;AAEO,SAAA;AAAA,IACL,YAAYE;AAAA,IACZ,aAAaK;AAAA,EACf;AACF;"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
const z = {
|
|
2
|
+
low: {
|
|
3
|
+
size: 1080,
|
|
4
|
+
compression: 0.7
|
|
5
|
+
},
|
|
6
|
+
medium: {
|
|
7
|
+
size: 1600,
|
|
8
|
+
compression: 0.85
|
|
9
|
+
},
|
|
10
|
+
high: {
|
|
11
|
+
size: 2048,
|
|
12
|
+
compression: 0.92
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
function f({
|
|
16
|
+
file: s,
|
|
17
|
+
quality: g,
|
|
18
|
+
customQuality: r
|
|
19
|
+
}) {
|
|
20
|
+
if (g === "original")
|
|
21
|
+
return Promise.resolve(s);
|
|
22
|
+
const c = z[g], d = r ? {
|
|
23
|
+
size: r.size ?? c.size,
|
|
24
|
+
compression: r.compression ?? c.compression
|
|
25
|
+
} : c, i = d.size;
|
|
26
|
+
return new Promise((h, a) => {
|
|
27
|
+
const t = new Image(), m = URL.createObjectURL(s);
|
|
28
|
+
t.onerror = () => {
|
|
29
|
+
URL.revokeObjectURL(m), a(new Error("Failed to load image"));
|
|
30
|
+
}, t.onload = () => {
|
|
31
|
+
URL.revokeObjectURL(m);
|
|
32
|
+
const n = document.createElement("canvas");
|
|
33
|
+
let e = t.width, o = t.height;
|
|
34
|
+
e > o ? e > i && (o *= i / e, e = i) : o > i && (e *= i / o, o = i), n.width = e, n.height = o;
|
|
35
|
+
const l = n.getContext("2d");
|
|
36
|
+
if (!l) {
|
|
37
|
+
a(new Error("Failed to get canvas context"));
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
l.drawImage(t, 0, 0, e, o), n.toBlob(
|
|
41
|
+
(w) => {
|
|
42
|
+
if (!w) {
|
|
43
|
+
a(new Error("Failed to create blob"));
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const p = new File([w], s.name, {
|
|
47
|
+
type: "image/jpeg",
|
|
48
|
+
lastModified: Date.now()
|
|
49
|
+
});
|
|
50
|
+
h(p);
|
|
51
|
+
},
|
|
52
|
+
"image/jpeg",
|
|
53
|
+
d.compression
|
|
54
|
+
);
|
|
55
|
+
}, t.src = m;
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
export {
|
|
59
|
+
f as resizeImage
|
|
60
|
+
};
|
|
61
|
+
//# sourceMappingURL=resizeImage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resizeImage.js","sources":["../../../src/internal/utils/resizeImage.ts"],"sourcesContent":["import type {\n ImageQuality,\n CustomImageQuality,\n} from '../../providers/ImagePickerProvider'\n\ninterface ResizeSettings {\n size: number\n compression: number\n}\n\nexport interface ResizeImageParams {\n file: File\n quality: ImageQuality\n customQuality?: CustomImageQuality\n}\n\nconst QUALITY_SETTINGS: {\n [key in Exclude<ImageQuality, 'original'>]: ResizeSettings\n} = {\n low: {\n size: 1080,\n compression: 0.7,\n },\n medium: {\n size: 1600,\n compression: 0.85,\n },\n high: {\n size: 2048,\n compression: 0.92,\n },\n} as const\n\nexport function resizeImage({\n file,\n quality,\n customQuality,\n}: ResizeImageParams): Promise<File> {\n if (quality === 'original') {\n return Promise.resolve(file)\n }\n\n const defaultSettings = QUALITY_SETTINGS[quality]\n const settings: ResizeSettings = customQuality\n ? {\n size: customQuality.size ?? defaultSettings.size,\n compression: customQuality.compression ?? defaultSettings.compression,\n }\n : defaultSettings\n const maxSize = settings.size\n\n return new Promise((resolve, reject) => {\n const img = new Image()\n const url = URL.createObjectURL(file)\n\n img.onerror = () => {\n URL.revokeObjectURL(url)\n reject(new Error('Failed to load image'))\n }\n\n img.onload = () => {\n URL.revokeObjectURL(url)\n\n const canvas = document.createElement('canvas')\n let width = img.width\n let height = img.height\n\n // Resize image dimensions maintaining aspect ratio\n if (width > height) {\n if (width > maxSize) {\n height *= maxSize / width\n width = maxSize\n }\n } else if (height > maxSize) {\n width *= maxSize / height\n height = maxSize\n }\n\n canvas.width = width\n canvas.height = height\n\n const ctx = canvas.getContext('2d')\n if (!ctx) {\n reject(new Error('Failed to get canvas context'))\n return\n }\n ctx.drawImage(img, 0, 0, width, height)\n\n canvas.toBlob(\n blob => {\n if (!blob) {\n reject(new Error('Failed to create blob'))\n return\n }\n const resizedFile = new File([blob], file.name, {\n type: 'image/jpeg',\n lastModified: Date.now(),\n })\n resolve(resizedFile)\n },\n 'image/jpeg',\n settings.compression\n )\n }\n\n img.src = url\n })\n}\n"],"names":["QUALITY_SETTINGS","resizeImage","file","quality","customQuality","defaultSettings","settings","maxSize","resolve","reject","img","url","canvas","width","height","ctx","blob","resizedFile"],"mappings":"AAgBA,MAAMA,IAEF;AAAA,EACF,KAAK;AAAA,IACH,MAAM;AAAA,IACN,aAAa;AAAA,EACf;AAAA,EACA,QAAQ;AAAA,IACN,MAAM;AAAA,IACN,aAAa;AAAA,EACf;AAAA,EACA,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,EAAA;AAEjB;AAEO,SAASC,EAAY;AAAA,EAC1B,MAAAC;AAAA,EACA,SAAAC;AAAA,EACA,eAAAC;AACF,GAAqC;AACnC,MAAID,MAAY;AACP,WAAA,QAAQ,QAAQD,CAAI;AAGvB,QAAAG,IAAkBL,EAAiBG,CAAO,GAC1CG,IAA2BF,IAC7B;AAAA,IACE,MAAMA,EAAc,QAAQC,EAAgB;AAAA,IAC5C,aAAaD,EAAc,eAAeC,EAAgB;AAAA,EAAA,IAE5DA,GACEE,IAAUD,EAAS;AAEzB,SAAO,IAAI,QAAQ,CAACE,GAASC,MAAW;AAChC,UAAAC,IAAM,IAAI,MAAM,GAChBC,IAAM,IAAI,gBAAgBT,CAAI;AAEpC,IAAAQ,EAAI,UAAU,MAAM;AAClB,UAAI,gBAAgBC,CAAG,GAChBF,EAAA,IAAI,MAAM,sBAAsB,CAAC;AAAA,IAC1C,GAEAC,EAAI,SAAS,MAAM;AACjB,UAAI,gBAAgBC,CAAG;AAEjB,YAAAC,IAAS,SAAS,cAAc,QAAQ;AAC9C,UAAIC,IAAQH,EAAI,OACZI,IAASJ,EAAI;AAGjB,MAAIG,IAAQC,IACND,IAAQN,MACVO,KAAUP,IAAUM,GACZA,IAAAN,KAEDO,IAASP,MAClBM,KAASN,IAAUO,GACVA,IAAAP,IAGXK,EAAO,QAAQC,GACfD,EAAO,SAASE;AAEV,YAAAC,IAAMH,EAAO,WAAW,IAAI;AAClC,UAAI,CAACG,GAAK;AACD,QAAAN,EAAA,IAAI,MAAM,8BAA8B,CAAC;AAChD;AAAA,MAAA;AAEF,MAAAM,EAAI,UAAUL,GAAK,GAAG,GAAGG,GAAOC,CAAM,GAE/BF,EAAA;AAAA,QACL,CAAQI,MAAA;AACN,cAAI,CAACA,GAAM;AACF,YAAAP,EAAA,IAAI,MAAM,uBAAuB,CAAC;AACzC;AAAA,UAAA;AAEF,gBAAMQ,IAAc,IAAI,KAAK,CAACD,CAAI,GAAGd,EAAK,MAAM;AAAA,YAC9C,MAAM;AAAA,YACN,cAAc,KAAK,IAAI;AAAA,UAAA,CACxB;AACD,UAAAM,EAAQS,CAAW;AAAA,QACrB;AAAA,QACA;AAAA,QACAX,EAAS;AAAA,MACX;AAAA,IACF,GAEAI,EAAI,MAAMC;AAAA,EAAA,CACX;AACH;"}
|
|
@@ -1,167 +1,188 @@
|
|
|
1
|
-
import { jsxs as
|
|
2
|
-
import { useRef as
|
|
3
|
-
import { useRequestPermissions as
|
|
4
|
-
import { useReportInteraction as
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
import { jsxs as q, jsx as w } from "react/jsx-runtime";
|
|
2
|
+
import { useRef as o, useCallback as y, useEffect as A, useMemo as z, createContext as L, useContext as M } from "react";
|
|
3
|
+
import { useRequestPermissions as F } from "../hooks/util/useRequestPermissions.js";
|
|
4
|
+
import { useReportInteraction as G } from "../internal/useReportInteraction.js";
|
|
5
|
+
import { resizeImage as H } from "../internal/utils/resizeImage.js";
|
|
6
|
+
const V = L(null);
|
|
7
|
+
function B() {
|
|
8
|
+
const C = M(V);
|
|
9
|
+
if (!C)
|
|
9
10
|
throw new Error(
|
|
10
11
|
"useImagePickerContext must be used within an ImagePickerProvider"
|
|
11
12
|
);
|
|
12
|
-
return
|
|
13
|
+
return C;
|
|
13
14
|
}
|
|
14
|
-
function
|
|
15
|
-
const
|
|
16
|
-
if (
|
|
17
|
-
const { input: c, handler:
|
|
18
|
-
c.removeEventListener("cancel",
|
|
15
|
+
function D({ children: C }) {
|
|
16
|
+
const E = o(null), P = o(null), R = o(null), n = o(null), e = o(null), g = o(null), t = o(null), h = o("medium"), k = o(void 0), { requestPermission: v } = F(), { reportInteraction: r } = G(), u = y(() => {
|
|
17
|
+
if (g.current) {
|
|
18
|
+
const { input: c, handler: l } = g.current;
|
|
19
|
+
c.removeEventListener("cancel", l), g.current = null;
|
|
19
20
|
}
|
|
20
|
-
}, []),
|
|
21
|
+
}, []), d = y(() => {
|
|
21
22
|
if (e.current) {
|
|
22
23
|
const c = new Error(
|
|
23
24
|
"New file picker opened before previous completed"
|
|
24
25
|
);
|
|
25
|
-
|
|
26
|
+
t.current === "gallery" ? r({
|
|
26
27
|
interactionType: "image_picker_error",
|
|
27
28
|
interactionValue: c.message
|
|
28
|
-
}) :
|
|
29
|
+
}) : t.current === "camera" && r({
|
|
29
30
|
interactionType: "camera_error",
|
|
30
31
|
interactionValue: c.message
|
|
31
|
-
}), e.current(c),
|
|
32
|
+
}), e.current(c), n.current = null, e.current = null, t.current = null, h.current = "medium", k.current = void 0;
|
|
32
33
|
}
|
|
33
|
-
}, [r]),
|
|
34
|
-
(c) => {
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
34
|
+
}, [r]), _ = y(
|
|
35
|
+
async (c) => {
|
|
36
|
+
const { target: l } = c, p = l.files?.[0];
|
|
37
|
+
if (p && n.current) {
|
|
38
|
+
try {
|
|
39
|
+
const s = await H({
|
|
40
|
+
file: p,
|
|
41
|
+
quality: h.current,
|
|
42
|
+
customQuality: k.current
|
|
43
|
+
});
|
|
44
|
+
t.current === "gallery" ? r({
|
|
45
|
+
interactionType: "image_picker_success"
|
|
46
|
+
}) : t.current === "camera" && r({
|
|
47
|
+
interactionType: "camera_success"
|
|
48
|
+
}), n.current(s);
|
|
49
|
+
} catch (s) {
|
|
50
|
+
console.warn("Image resize failed, using original:", s), n.current && n.current(p);
|
|
51
|
+
}
|
|
52
|
+
n.current = null, e.current = null, t.current = null, u();
|
|
53
|
+
}
|
|
54
|
+
l.value = "";
|
|
41
55
|
},
|
|
42
|
-
[
|
|
43
|
-
),
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
interactionType: "image_picker_error",
|
|
50
|
-
interactionValue: o.message
|
|
51
|
-
}), i(o), t.current = null, e.current = null, n.current = null;
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
const s = () => {
|
|
55
|
-
if (e.current) {
|
|
56
|
-
const o = new Error("User cancelled file selection");
|
|
56
|
+
[u, r]
|
|
57
|
+
), I = y(
|
|
58
|
+
({ quality: c = "medium", customQuality: l } = {}) => new Promise((p, s) => {
|
|
59
|
+
d(), u(), h.current = c, k.current = l, n.current = p, e.current = s, t.current = "gallery";
|
|
60
|
+
const i = E.current;
|
|
61
|
+
if (!i) {
|
|
62
|
+
const m = new Error("Gallery input not found");
|
|
57
63
|
r({
|
|
58
64
|
interactionType: "image_picker_error",
|
|
59
|
-
interactionValue:
|
|
60
|
-
}),
|
|
65
|
+
interactionValue: m.message
|
|
66
|
+
}), s(m), n.current = null, e.current = null, t.current = null;
|
|
67
|
+
return;
|
|
61
68
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
69
|
+
const f = () => {
|
|
70
|
+
if (e.current) {
|
|
71
|
+
const m = new Error("User cancelled file selection");
|
|
72
|
+
r({
|
|
73
|
+
interactionType: "image_picker_error",
|
|
74
|
+
interactionValue: m.message
|
|
75
|
+
}), e.current(m), n.current = null, e.current = null, t.current = null;
|
|
76
|
+
}
|
|
77
|
+
u();
|
|
78
|
+
};
|
|
79
|
+
i.addEventListener("cancel", f), g.current = { input: i, handler: f }, r({
|
|
80
|
+
interactionType: "image_picker_open"
|
|
81
|
+
}), v({ permission: "CAMERA" }).then(() => {
|
|
82
|
+
i.click();
|
|
83
|
+
}).catch(() => {
|
|
84
|
+
i.click();
|
|
85
|
+
});
|
|
86
|
+
}),
|
|
87
|
+
[
|
|
88
|
+
d,
|
|
89
|
+
u,
|
|
90
|
+
v,
|
|
91
|
+
r
|
|
92
|
+
]
|
|
93
|
+
), T = y(
|
|
94
|
+
({
|
|
95
|
+
cameraFacing: c = "back",
|
|
96
|
+
quality: l = "medium",
|
|
97
|
+
customQuality: p
|
|
98
|
+
} = {}) => new Promise((s, i) => {
|
|
99
|
+
d(), u(), h.current = l, k.current = p, n.current = s, e.current = i, t.current = "camera";
|
|
100
|
+
const f = c === "front" ? P.current : R.current;
|
|
101
|
+
if (!f) {
|
|
102
|
+
const a = new Error("Camera input not found");
|
|
82
103
|
r({
|
|
83
104
|
interactionType: "camera_error",
|
|
84
|
-
interactionValue:
|
|
85
|
-
}),
|
|
105
|
+
interactionValue: a.message
|
|
106
|
+
}), i(a), n.current = null, e.current = null, t.current = null;
|
|
86
107
|
return;
|
|
87
108
|
}
|
|
88
|
-
const
|
|
109
|
+
const m = () => {
|
|
89
110
|
if (e.current) {
|
|
90
|
-
const
|
|
111
|
+
const a = new Error("User cancelled camera");
|
|
91
112
|
r({
|
|
92
113
|
interactionType: "camera_error",
|
|
93
|
-
interactionValue:
|
|
94
|
-
}), e.current(
|
|
114
|
+
interactionValue: a.message
|
|
115
|
+
}), e.current(a), n.current = null, e.current = null, t.current = null;
|
|
95
116
|
}
|
|
96
|
-
|
|
117
|
+
u();
|
|
97
118
|
};
|
|
98
|
-
|
|
119
|
+
f.addEventListener("cancel", m), g.current = { input: f, handler: m }, r({
|
|
99
120
|
interactionType: "camera_open"
|
|
100
|
-
}),
|
|
101
|
-
if (
|
|
102
|
-
|
|
121
|
+
}), v({ permission: "CAMERA" }).then(({ granted: a }) => {
|
|
122
|
+
if (a)
|
|
123
|
+
f.click();
|
|
103
124
|
else {
|
|
104
|
-
const
|
|
125
|
+
const x = new Error("Camera permission not granted");
|
|
105
126
|
r({
|
|
106
127
|
interactionType: "camera_error",
|
|
107
|
-
interactionValue:
|
|
108
|
-
}),
|
|
128
|
+
interactionValue: x.message
|
|
129
|
+
}), i(x), n.current = null, e.current = null, t.current = null;
|
|
109
130
|
}
|
|
110
131
|
}).catch(() => {
|
|
111
|
-
const
|
|
112
|
-
|
|
132
|
+
const a = new Error("Camera permission not granted");
|
|
133
|
+
i(a), n.current = null, e.current = null, t.current = null;
|
|
113
134
|
});
|
|
114
135
|
}),
|
|
115
136
|
[
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
137
|
+
d,
|
|
138
|
+
u,
|
|
139
|
+
v,
|
|
119
140
|
r
|
|
120
141
|
]
|
|
121
142
|
);
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
}, [
|
|
125
|
-
const
|
|
143
|
+
A(() => () => {
|
|
144
|
+
d(), u();
|
|
145
|
+
}, [d, u]);
|
|
146
|
+
const b = z(
|
|
126
147
|
() => ({
|
|
127
|
-
openCamera:
|
|
128
|
-
openGallery:
|
|
148
|
+
openCamera: T,
|
|
149
|
+
openGallery: I
|
|
129
150
|
}),
|
|
130
|
-
[
|
|
151
|
+
[T, I]
|
|
131
152
|
);
|
|
132
|
-
return /* @__PURE__ */
|
|
133
|
-
|
|
134
|
-
/* @__PURE__ */
|
|
153
|
+
return /* @__PURE__ */ q(V.Provider, { value: b, children: [
|
|
154
|
+
C,
|
|
155
|
+
/* @__PURE__ */ w(
|
|
135
156
|
"input",
|
|
136
157
|
{
|
|
137
|
-
ref:
|
|
158
|
+
ref: E,
|
|
138
159
|
type: "file",
|
|
139
160
|
accept: "image/*",
|
|
140
|
-
onChange:
|
|
161
|
+
onChange: _,
|
|
141
162
|
style: { display: "none" },
|
|
142
163
|
"aria-hidden": "true"
|
|
143
164
|
}
|
|
144
165
|
),
|
|
145
|
-
/* @__PURE__ */
|
|
166
|
+
/* @__PURE__ */ w(
|
|
146
167
|
"input",
|
|
147
168
|
{
|
|
148
|
-
ref:
|
|
169
|
+
ref: P,
|
|
149
170
|
type: "file",
|
|
150
171
|
accept: "image/*",
|
|
151
172
|
capture: "user",
|
|
152
|
-
onChange:
|
|
173
|
+
onChange: _,
|
|
153
174
|
style: { display: "none" },
|
|
154
175
|
"aria-hidden": "true"
|
|
155
176
|
}
|
|
156
177
|
),
|
|
157
|
-
/* @__PURE__ */
|
|
178
|
+
/* @__PURE__ */ w(
|
|
158
179
|
"input",
|
|
159
180
|
{
|
|
160
|
-
ref:
|
|
181
|
+
ref: R,
|
|
161
182
|
type: "file",
|
|
162
183
|
accept: "image/*",
|
|
163
184
|
capture: "environment",
|
|
164
|
-
onChange:
|
|
185
|
+
onChange: _,
|
|
165
186
|
style: { display: "none" },
|
|
166
187
|
"aria-hidden": "true"
|
|
167
188
|
}
|
|
@@ -169,7 +190,7 @@ function N({ children: g }) {
|
|
|
169
190
|
] });
|
|
170
191
|
}
|
|
171
192
|
export {
|
|
172
|
-
|
|
173
|
-
|
|
193
|
+
D as ImagePickerProvider,
|
|
194
|
+
B as useImagePickerContext
|
|
174
195
|
};
|
|
175
196
|
//# sourceMappingURL=ImagePickerProvider.js.map
|