@shopify/shop-minis-react 0.2.1 → 0.2.3
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/index10.js +2 -2
- package/dist/_virtual/index4.js +3 -2
- package/dist/_virtual/index4.js.map +1 -1
- package/dist/_virtual/index7.js +2 -3
- package/dist/_virtual/index7.js.map +1 -1
- package/dist/_virtual/index9.js +2 -2
- package/dist/internal/useReportInteraction.js +21 -0
- package/dist/internal/useReportInteraction.js.map +1 -0
- package/dist/providers/ImagePickerProvider.js +122 -63
- package/dist/providers/ImagePickerProvider.js.map +1 -1
- 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
- package/dist/shop-minis-react/node_modules/.pnpm/@xmldom_xmldom@0.8.10/node_modules/@xmldom/xmldom/lib/index.js +1 -1
- package/dist/shop-minis-react/node_modules/.pnpm/querystringify@2.2.0/node_modules/querystringify/index.js +1 -1
- 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
- package/dist/utils/getWindowLocationPathname.js +7 -0
- package/dist/utils/getWindowLocationPathname.js.map +1 -0
- package/eslint/rules/prefer-sdk-components.cjs +0 -79
- package/eslint/rules/validate-manifest.cjs +86 -2
- package/generated-hook-maps/component-scopes-map.json +18 -0
- package/package.json +1 -2
- package/src/providers/ImagePickerProvider.test.tsx +391 -0
- package/src/providers/ImagePickerProvider.tsx +93 -12
|
@@ -8,6 +8,7 @@ import React, {
|
|
|
8
8
|
} from 'react'
|
|
9
9
|
|
|
10
10
|
import {useRequestPermissions} from '../hooks/util/useRequestPermissions'
|
|
11
|
+
import {useReportInteraction} from '../internal/useReportInteraction'
|
|
11
12
|
|
|
12
13
|
export type CameraFacing = 'front' | 'back'
|
|
13
14
|
|
|
@@ -42,8 +43,10 @@ export function ImagePickerProvider({children}: ImagePickerProviderProps) {
|
|
|
42
43
|
input: HTMLInputElement
|
|
43
44
|
handler: () => void
|
|
44
45
|
} | null>(null)
|
|
46
|
+
const activeOperationRef = useRef<'gallery' | 'camera' | null>(null)
|
|
45
47
|
|
|
46
48
|
const {requestPermission} = useRequestPermissions()
|
|
49
|
+
const {reportInteraction} = useReportInteraction()
|
|
47
50
|
|
|
48
51
|
const cleanupCancelHandler = useCallback(() => {
|
|
49
52
|
if (activeCancelHandlerRef.current) {
|
|
@@ -55,30 +58,56 @@ export function ImagePickerProvider({children}: ImagePickerProviderProps) {
|
|
|
55
58
|
|
|
56
59
|
const rejectPendingPromise = useCallback(() => {
|
|
57
60
|
if (rejectRef.current) {
|
|
58
|
-
|
|
59
|
-
|
|
61
|
+
const error = new Error(
|
|
62
|
+
'New file picker opened before previous completed'
|
|
60
63
|
)
|
|
64
|
+
if (activeOperationRef.current === 'gallery') {
|
|
65
|
+
reportInteraction({
|
|
66
|
+
interactionType: 'image_picker_error',
|
|
67
|
+
interactionValue: error.message,
|
|
68
|
+
})
|
|
69
|
+
} else if (activeOperationRef.current === 'camera') {
|
|
70
|
+
reportInteraction({
|
|
71
|
+
interactionType: 'camera_error',
|
|
72
|
+
interactionValue: error.message,
|
|
73
|
+
})
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
rejectRef.current(error)
|
|
61
77
|
resolveRef.current = null
|
|
62
78
|
rejectRef.current = null
|
|
79
|
+
activeOperationRef.current = null
|
|
63
80
|
}
|
|
64
|
-
}, [])
|
|
81
|
+
}, [reportInteraction])
|
|
65
82
|
|
|
66
83
|
const handleFileChange = useCallback(
|
|
67
84
|
(event: React.ChangeEvent<HTMLInputElement>) => {
|
|
68
85
|
const file = event.target.files?.[0]
|
|
69
86
|
|
|
70
87
|
if (file && resolveRef.current) {
|
|
88
|
+
// Report success based on the active operation
|
|
89
|
+
if (activeOperationRef.current === 'gallery') {
|
|
90
|
+
reportInteraction({
|
|
91
|
+
interactionType: 'image_picker_success',
|
|
92
|
+
})
|
|
93
|
+
} else if (activeOperationRef.current === 'camera') {
|
|
94
|
+
reportInteraction({
|
|
95
|
+
interactionType: 'camera_success',
|
|
96
|
+
})
|
|
97
|
+
}
|
|
98
|
+
|
|
71
99
|
resolveRef.current(file)
|
|
72
100
|
|
|
73
101
|
resolveRef.current = null
|
|
74
102
|
rejectRef.current = null
|
|
103
|
+
activeOperationRef.current = null
|
|
75
104
|
|
|
76
105
|
cleanupCancelHandler()
|
|
77
106
|
}
|
|
78
107
|
|
|
79
108
|
event.target.value = ''
|
|
80
109
|
},
|
|
81
|
-
[cleanupCancelHandler]
|
|
110
|
+
[cleanupCancelHandler, reportInteraction]
|
|
82
111
|
)
|
|
83
112
|
|
|
84
113
|
const openGallery = useCallback(() => {
|
|
@@ -88,21 +117,34 @@ export function ImagePickerProvider({children}: ImagePickerProviderProps) {
|
|
|
88
117
|
|
|
89
118
|
resolveRef.current = resolve
|
|
90
119
|
rejectRef.current = reject
|
|
120
|
+
activeOperationRef.current = 'gallery'
|
|
91
121
|
|
|
92
122
|
const input = galleryInputRef.current
|
|
93
123
|
|
|
94
124
|
if (!input) {
|
|
95
|
-
|
|
125
|
+
const error = new Error('Gallery input not found')
|
|
126
|
+
reportInteraction({
|
|
127
|
+
interactionType: 'image_picker_error',
|
|
128
|
+
interactionValue: error.message,
|
|
129
|
+
})
|
|
130
|
+
reject(error)
|
|
96
131
|
resolveRef.current = null
|
|
97
132
|
rejectRef.current = null
|
|
133
|
+
activeOperationRef.current = null
|
|
98
134
|
return
|
|
99
135
|
}
|
|
100
136
|
|
|
101
137
|
const handleCancel = () => {
|
|
102
138
|
if (rejectRef.current) {
|
|
103
|
-
|
|
139
|
+
const error = new Error('User cancelled file selection')
|
|
140
|
+
reportInteraction({
|
|
141
|
+
interactionType: 'image_picker_error',
|
|
142
|
+
interactionValue: error.message,
|
|
143
|
+
})
|
|
144
|
+
rejectRef.current(error)
|
|
104
145
|
resolveRef.current = null
|
|
105
146
|
rejectRef.current = null
|
|
147
|
+
activeOperationRef.current = null
|
|
106
148
|
}
|
|
107
149
|
cleanupCancelHandler()
|
|
108
150
|
}
|
|
@@ -110,6 +152,10 @@ export function ImagePickerProvider({children}: ImagePickerProviderProps) {
|
|
|
110
152
|
input.addEventListener('cancel', handleCancel)
|
|
111
153
|
activeCancelHandlerRef.current = {input, handler: handleCancel}
|
|
112
154
|
|
|
155
|
+
reportInteraction({
|
|
156
|
+
interactionType: 'image_picker_open',
|
|
157
|
+
})
|
|
158
|
+
|
|
113
159
|
requestPermission({permission: 'CAMERA'})
|
|
114
160
|
.then(() => {
|
|
115
161
|
// This will show both Camera and Gallery
|
|
@@ -120,7 +166,12 @@ export function ImagePickerProvider({children}: ImagePickerProviderProps) {
|
|
|
120
166
|
input.click()
|
|
121
167
|
})
|
|
122
168
|
})
|
|
123
|
-
}, [
|
|
169
|
+
}, [
|
|
170
|
+
rejectPendingPromise,
|
|
171
|
+
cleanupCancelHandler,
|
|
172
|
+
requestPermission,
|
|
173
|
+
reportInteraction,
|
|
174
|
+
])
|
|
124
175
|
|
|
125
176
|
const openCamera = useCallback(
|
|
126
177
|
(cameraFacing: CameraFacing = 'back') => {
|
|
@@ -130,6 +181,7 @@ export function ImagePickerProvider({children}: ImagePickerProviderProps) {
|
|
|
130
181
|
|
|
131
182
|
resolveRef.current = resolve
|
|
132
183
|
rejectRef.current = reject
|
|
184
|
+
activeOperationRef.current = 'camera'
|
|
133
185
|
|
|
134
186
|
const input =
|
|
135
187
|
cameraFacing === 'front'
|
|
@@ -137,17 +189,29 @@ export function ImagePickerProvider({children}: ImagePickerProviderProps) {
|
|
|
137
189
|
: backCameraInputRef.current
|
|
138
190
|
|
|
139
191
|
if (!input) {
|
|
140
|
-
|
|
192
|
+
const error = new Error('Camera input not found')
|
|
193
|
+
reportInteraction({
|
|
194
|
+
interactionType: 'camera_error',
|
|
195
|
+
interactionValue: error.message,
|
|
196
|
+
})
|
|
197
|
+
reject(error)
|
|
141
198
|
resolveRef.current = null
|
|
142
199
|
rejectRef.current = null
|
|
200
|
+
activeOperationRef.current = null
|
|
143
201
|
return
|
|
144
202
|
}
|
|
145
203
|
|
|
146
204
|
const handleCancel = () => {
|
|
147
205
|
if (rejectRef.current) {
|
|
148
|
-
|
|
206
|
+
const error = new Error('User cancelled camera')
|
|
207
|
+
reportInteraction({
|
|
208
|
+
interactionType: 'camera_error',
|
|
209
|
+
interactionValue: error.message,
|
|
210
|
+
})
|
|
211
|
+
rejectRef.current(error)
|
|
149
212
|
resolveRef.current = null
|
|
150
213
|
rejectRef.current = null
|
|
214
|
+
activeOperationRef.current = null
|
|
151
215
|
}
|
|
152
216
|
cleanupCancelHandler()
|
|
153
217
|
}
|
|
@@ -155,24 +219,41 @@ export function ImagePickerProvider({children}: ImagePickerProviderProps) {
|
|
|
155
219
|
input.addEventListener('cancel', handleCancel)
|
|
156
220
|
activeCancelHandlerRef.current = {input, handler: handleCancel}
|
|
157
221
|
|
|
222
|
+
reportInteraction({
|
|
223
|
+
interactionType: 'camera_open',
|
|
224
|
+
})
|
|
225
|
+
|
|
158
226
|
requestPermission({permission: 'CAMERA'})
|
|
159
227
|
.then(({granted}) => {
|
|
160
228
|
if (granted) {
|
|
161
229
|
input.click()
|
|
162
230
|
} else {
|
|
163
|
-
|
|
231
|
+
const error = new Error('Camera permission not granted')
|
|
232
|
+
reportInteraction({
|
|
233
|
+
interactionType: 'camera_error',
|
|
234
|
+
interactionValue: error.message,
|
|
235
|
+
})
|
|
236
|
+
reject(error)
|
|
164
237
|
resolveRef.current = null
|
|
165
238
|
rejectRef.current = null
|
|
239
|
+
activeOperationRef.current = null
|
|
166
240
|
}
|
|
167
241
|
})
|
|
168
242
|
.catch(() => {
|
|
169
|
-
|
|
243
|
+
const error = new Error('Camera permission not granted')
|
|
244
|
+
reject(error)
|
|
170
245
|
resolveRef.current = null
|
|
171
246
|
rejectRef.current = null
|
|
247
|
+
activeOperationRef.current = null
|
|
172
248
|
})
|
|
173
249
|
})
|
|
174
250
|
},
|
|
175
|
-
[
|
|
251
|
+
[
|
|
252
|
+
rejectPendingPromise,
|
|
253
|
+
cleanupCancelHandler,
|
|
254
|
+
requestPermission,
|
|
255
|
+
reportInteraction,
|
|
256
|
+
]
|
|
176
257
|
)
|
|
177
258
|
|
|
178
259
|
useEffect(() => {
|