@dynamic-labs/sdk-react-core 3.0.0-alpha.57 → 3.0.0-alpha.59

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/package.cjs +1 -1
  3. package/package.js +1 -1
  4. package/package.json +11 -12
  5. package/src/index.cjs +2 -1
  6. package/src/index.d.ts +1 -1
  7. package/src/index.js +1 -1
  8. package/src/lib/context/DynamicContext/DynamicContext.cjs +1 -3
  9. package/src/lib/context/DynamicContext/DynamicContext.js +1 -3
  10. package/src/lib/context/DynamicContext/hooks/useSelectedWalletConnector/useSelectedWalletConnector.d.ts +1 -1
  11. package/src/lib/context/DynamicContext/types/DynamicContextProps.d.ts +0 -1
  12. package/src/lib/context/DynamicContext/types/IDynamicContext.d.ts +0 -2
  13. package/src/lib/context/UserWalletsContext/UserWalletsContext.d.ts +1 -1
  14. package/src/lib/context/ViewContext/types/index.d.ts +1 -1
  15. package/src/lib/locale/en/translation.cjs +42 -0
  16. package/src/lib/locale/en/translation.d.ts +42 -0
  17. package/src/lib/locale/en/translation.js +42 -0
  18. package/src/lib/styles/index.shadow.cjs +1 -1
  19. package/src/lib/styles/index.shadow.js +1 -1
  20. package/src/lib/utils/hooks/useAuthLayoutChecks/useAuthLayoutChecks.cjs +1 -0
  21. package/src/lib/utils/hooks/useAuthLayoutChecks/useAuthLayoutChecks.js +1 -0
  22. package/src/lib/utils/hooks/useConnectedAccountWallet/useConnectedAccountWallet.d.ts +1 -1
  23. package/src/lib/utils/hooks/useEmbeddedWallet/useEmbeddedWallet.d.ts +2 -2
  24. package/src/lib/utils/hooks/useSyncOnboardingFlow/useSyncOnboardingFlow.cjs +1 -6
  25. package/src/lib/utils/hooks/useSyncOnboardingFlow/useSyncOnboardingFlow.js +1 -6
  26. package/src/lib/utils/hooks/useWalletItemActions/useWalletItemActions.cjs +5 -2
  27. package/src/lib/utils/hooks/useWalletItemActions/useWalletItemActions.js +5 -2
  28. package/src/lib/views/GlobalWalletInfoView/GlobalWalletInfoView.cjs +34 -0
  29. package/src/lib/views/GlobalWalletInfoView/GlobalWalletInfoView.d.ts +3 -0
  30. package/src/lib/views/GlobalWalletInfoView/GlobalWalletInfoView.js +29 -0
  31. package/src/lib/views/viewToComponentMap.cjs +2 -0
  32. package/src/lib/views/viewToComponentMap.d.ts +1 -0
  33. package/src/lib/views/viewToComponentMap.js +2 -0
  34. package/src/lib/widgets/DynamicWidget/views/GlobalWalletView/GlobalWalletTypes.d.ts +31 -0
  35. package/src/lib/widgets/DynamicWidget/views/GlobalWalletView/GlobalWalletView.cjs +84 -95
  36. package/src/lib/widgets/DynamicWidget/views/GlobalWalletView/GlobalWalletView.js +86 -97
  37. package/src/lib/widgets/DynamicWidget/views/GlobalWalletView/scanner/GlobalWalletScanner.cjs +54 -0
  38. package/src/lib/widgets/DynamicWidget/views/GlobalWalletView/scanner/GlobalWalletScanner.d.ts +7 -0
  39. package/src/lib/widgets/DynamicWidget/views/GlobalWalletView/scanner/GlobalWalletScanner.js +49 -0
@@ -1,8 +1,9 @@
1
1
  'use client'
2
2
  import { __awaiter } from '../../../../../../_virtual/_tslib.js';
3
- import { jsxs, jsx } from 'react/jsx-runtime';
4
- import { useState, useEffect } from 'react';
3
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
4
+ import { useState, useCallback, useEffect } from 'react';
5
5
  import { useTranslation } from 'react-i18next';
6
+ import { isMobile } from '@dynamic-labs/utils';
6
7
  import '@dynamic-labs/sdk-api-core';
7
8
  import '../../../../shared/logger.js';
8
9
  import '@dynamic-labs/iconic';
@@ -11,13 +12,13 @@ import { useViewContext } from '../../../../context/ViewContext/ViewContext.js';
11
12
  import { ReactComponent as SvgArrowLeft } from '../../../../shared/assets/arrow-left.js';
12
13
  import { ReactComponent as SvgCopy } from '../../../../shared/assets/copy.js';
13
14
  import { ReactComponent as SvgBlueWalletconnect } from '../../../../shared/assets/blue-walletconnect.js';
15
+ import { ReactComponent as SvgQuestionMark } from '../../../../shared/assets/question-mark.js';
14
16
  import '@dynamic-labs/wallet-book';
15
17
  import '../../../../utils/constants/colors.js';
16
18
  import '../../../../utils/constants/values.js';
17
19
  import '../../../../shared/utils/classes/storage/localStorage.js';
18
20
  import '../../../../shared/utils/classes/storage/sessionStorage.js';
19
21
  import '../../../../store/state/loadingAndLifecycle.js';
20
- import '@dynamic-labs/utils';
21
22
  import '../../../../shared/consts/index.js';
22
23
  import { IconButton } from '../../../../components/IconButton/IconButton.js';
23
24
  import { useWidgetContext } from '../../context/DynamicWidgetContext.js';
@@ -64,6 +65,7 @@ import '../../../../context/SocialRedirectContext/SocialRedirectContext.js';
64
65
  import '../../../../context/WalletGroupContext/WalletGroupContext.js';
65
66
  import '../../components/DynamicWidgetHeader/DynamicWidgetHeader.js';
66
67
  import 'react-focus-lock';
68
+ import { Divider } from '../../../../components/Divider/Divider.js';
67
69
  import '../../../../components/MenuList/Dropdown/Dropdown.js';
68
70
  import 'formik';
69
71
  import '../../../../store/state/sendBalances/sendBalances.js';
@@ -71,6 +73,7 @@ import '../../../../views/TransactionConfirmationView/helpers/transactionErrorMe
71
73
  import { Input } from '../../../../components/Input/Input.js';
72
74
  import '../../../../context/PasskeyContext/PasskeyContext.js';
73
75
  import '../ManagePasskeysWidgetView/PasskeyCard/PasskeyCard.js';
76
+ import { GlobalWalletScanner } from './scanner/GlobalWalletScanner.js';
74
77
  import '../../../../../polyfills.js';
75
78
  import '../../../../context/DynamicContext/DynamicContext.js';
76
79
  import '../../../../context/ErrorBoundary/ErrorBoundaryBase.js';
@@ -97,6 +100,7 @@ import '../../../../components/InlineWidget/InlineWidget.js';
97
100
  import 'qrcode';
98
101
 
99
102
  const GlobalWalletView = () => {
103
+ var _a;
100
104
  const { t } = useTranslation();
101
105
  const { setDynamicWidgetView, goToInitialDynamicWidgetView } = useWidgetContext();
102
106
  const { setView } = useViewContext();
@@ -104,47 +108,60 @@ const GlobalWalletView = () => {
104
108
  const { primaryWallet } = useDynamicContext();
105
109
  const [walletConnectUri, setWalletConnectUri] = useState('');
106
110
  const [bannerMessage, setBannerMessage] = useState(null);
107
- const [isHovered, setIsHovered] = useState(false);
108
- const [isFocused, setIsFocused] = useState(false);
109
- const { globalWallet } = primaryWallet === null || primaryWallet === void 0 ? void 0 : primaryWallet.connector;
111
+ const [isScanned, setIsScanned] = useState(false);
112
+ const { globalWallet } =
113
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
114
+ (_a = primaryWallet === null || primaryWallet === void 0 ? void 0 : primaryWallet.connector) !== null && _a !== void 0 ? _a : {};
110
115
  if (!globalWallet)
111
116
  throw new Error('Global Wallet not found');
112
- useEffect(() => {
113
- let timeoutId;
114
- if (bannerMessage) {
115
- timeoutId = setTimeout(() => {
116
- setBannerMessage(null);
117
- }, 3000);
118
- }
119
- return () => {
120
- if (timeoutId) {
121
- clearTimeout(timeoutId);
122
- }
123
- };
124
- }, [bannerMessage]);
125
- const onClickBack = () => {
126
- goToInitialDynamicWidgetView();
127
- };
128
- const onConnectClick = () => __awaiter(void 0, void 0, void 0, function* () {
117
+ const showBanner = useCallback((message, type) => {
118
+ setBannerMessage({ message, type });
119
+ const timeout = type === 'success' ? 2000 : 3000;
120
+ setTimeout(() => {
121
+ setBannerMessage(null);
122
+ if (type === 'success')
123
+ goToInitialDynamicWidgetView();
124
+ }, timeout);
125
+ }, [goToInitialDynamicWidgetView]);
126
+ const handlePairing = useCallback(() => __awaiter(void 0, void 0, void 0, function* () {
129
127
  if (!walletConnectUri.startsWith('wc:')) {
130
- setBannerMessage({
131
- message: t('global_wallet.banner.bad_input'),
132
- type: 'error',
133
- });
128
+ showBanner(t('global_wallet.banner.bad_input'), 'error');
134
129
  return;
135
130
  }
136
131
  try {
137
132
  yield globalWallet.pairWithWC(walletConnectUri);
138
- // wait 0.5 second to receive the pairing request event
139
133
  yield new Promise((resolve) => setTimeout(resolve, 500));
140
134
  const pendingPairing = globalWallet.getPendingPairing();
141
135
  if (!pendingPairing)
142
136
  throw new Error('No pending pairing');
143
- const { name, url, icons } = pendingPairing.params
144
- .proposer.metadata;
137
+ const { name, url, icons } = pendingPairing.params.proposer.metadata;
145
138
  setView('global-wallet-confirm', {
146
- onCancel: onCancelPairing,
147
- onConfirm: onConfirmPairing,
139
+ onCancel: () => {
140
+ setDynamicWidgetView('global-wallet');
141
+ setShowAuthFlow(false, {
142
+ ignoreIfIsEmbeddedWidget: false,
143
+ performMultiWalletChecks: false,
144
+ });
145
+ setWalletConnectUri('');
146
+ },
147
+ onConfirm: () => __awaiter(void 0, void 0, void 0, function* () {
148
+ try {
149
+ yield globalWallet.confirmPairing(true);
150
+ setDynamicWidgetView('global-wallet');
151
+ setShowAuthFlow(false, {
152
+ ignoreIfIsEmbeddedWidget: false,
153
+ performMultiWalletChecks: false,
154
+ });
155
+ showBanner(t('global_wallet.banner.success', {
156
+ name: name !== null && name !== void 0 ? name : t('global_wallet.the_dapp'),
157
+ }), 'success');
158
+ }
159
+ catch (error) {
160
+ showBanner(t('global_wallet.banner.warning', {
161
+ name: name !== null && name !== void 0 ? name : t('global_wallet.the_dapp'),
162
+ }), 'error');
163
+ }
164
+ }),
148
165
  pairingInfo: { icons, name, url },
149
166
  });
150
167
  setShowAuthFlow(true, {
@@ -153,78 +170,50 @@ const GlobalWalletView = () => {
153
170
  });
154
171
  }
155
172
  catch (error) {
156
- if (String(error).includes('expired')) {
157
- setBannerMessage({
158
- message: t('global_wallet.banner.expired', {
159
- name: 'this app',
160
- }),
161
- type: 'error',
162
- });
173
+ const errorMessage = String(error);
174
+ if (errorMessage.includes('expired')) {
175
+ showBanner(t('global_wallet.banner.expired'), 'error');
163
176
  }
164
- else if (String(error).includes('exists')) {
165
- setBannerMessage({
166
- message: t('global_wallet.banner.already_connected', {
167
- name: 'this app',
168
- }),
169
- type: 'success',
170
- });
177
+ else if (errorMessage.includes('exists')) {
178
+ showBanner(t('global_wallet.banner.already_connected', {
179
+ name: t('global_wallet.this_app'),
180
+ }), 'success');
171
181
  }
172
182
  else {
173
- setBannerMessage({
174
- message: t('global_wallet.banner.warning', { name: 'the app' }),
175
- type: 'error',
176
- });
183
+ showBanner(t('global_wallet.banner.warning', {
184
+ name: t('global_wallet.the_dapp'),
185
+ }), 'error');
177
186
  }
178
187
  }
179
- });
180
- const onConfirmPairing = () => __awaiter(void 0, void 0, void 0, function* () {
181
- var _a;
182
- const pendingConnection = (_a = globalWallet.getPendingPairing()) !== null && _a !== void 0 ? _a : {};
183
- const { name } = pendingConnection.params.proposer.metadata;
184
- try {
185
- yield globalWallet.confirmPairing(true);
186
- setDynamicWidgetView('global-wallet');
187
- setShowAuthFlow(false, {
188
- ignoreIfIsEmbeddedWidget: false,
189
- performMultiWalletChecks: false,
190
- });
191
- setBannerMessage({
192
- message: t('global_wallet.banner.success', {
193
- name: name !== null && name !== void 0 ? name : 'the dApp',
194
- }),
195
- type: 'success',
196
- });
197
- }
198
- catch (error) {
199
- setBannerMessage({
200
- message: t('global_wallet.banner.warning', {
201
- name: name !== null && name !== void 0 ? name : 'the dApp',
202
- }),
203
- type: 'error',
204
- });
188
+ }), // eslint-disable-next-line react-hooks/exhaustive-deps
189
+ [walletConnectUri]);
190
+ const handleScan = useCallback((result) => {
191
+ if (result) {
192
+ setIsScanned(true);
193
+ setWalletConnectUri(result);
205
194
  }
206
- });
207
- const onCancelPairing = () => __awaiter(void 0, void 0, void 0, function* () {
208
- setDynamicWidgetView('global-wallet');
209
- setShowAuthFlow(false, {
210
- ignoreIfIsEmbeddedWidget: false,
211
- performMultiWalletChecks: false,
212
- });
213
- });
214
- const handleSubmit = (e) => {
215
- e.preventDefault();
216
- onConnectClick();
217
- };
218
- const handleKeyDown = (e) => {
219
- if (e.key === 'Enter') {
220
- handleSubmit(e);
195
+ }, []);
196
+ useEffect(() => {
197
+ if (walletConnectUri.startsWith('wc:')) {
198
+ handlePairing();
221
199
  }
222
- };
223
- const InlineWalletConnectTypography = () => (jsx(Typography, { variant: 'body_small', weight: 'regular', color: 'secondary', children: jsxs("span", { className: 'inline-logo-text', children: ["3. Open WalletConnect ", jsx(SvgBlueWalletconnect, { className: 'inline-logo' }), ' ', "from the list"] }) }));
224
- const InlineCopyTextTypography = () => (jsx(Typography, { variant: 'body_small', weight: 'regular', color: 'secondary', children: jsxs("span", { className: 'inline-logo-text', children: ["4. Locate and click ", jsx(SvgCopy, { className: 'inline-logo' }), " to copy the URI code"] }) }));
225
- return (jsxs("div", { className: 'connect-dapps-view', children: [jsxs("div", { className: 'header', children: [jsx(IconButton, { type: 'button', onClick: onClickBack, "data-testid": 'back-button', children: jsx(SvgArrowLeft, {}) }), jsx(Typography, { variant: 'title', weight: 'medium', color: 'primary', as: 'h1', children: "Connect to apps" })] }), jsxs("div", { className: 'wallet-connect-card', children: [jsx("div", { className: 'input-group', children: jsx(Input, { id: 'walletconnect-uri', label: 'WalletConnect URI', placeholder: 'wc:...', value: walletConnectUri, onChange: (e) => setWalletConnectUri(e.target.value), variant: 'dense', onKeyDown: handleKeyDown, suffix:
226
- // eslint-disable-next-line react/jsx-wrap-multilines
227
- jsx("div", { className: 'input-suffix', onClick: handleSubmit, role: 'button', tabIndex: 0, onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), onFocus: () => setIsFocused(true), onBlur: () => setIsFocused(false), children: jsx(InlineSubmitButton, { disabled: false, highlighted: Boolean(walletConnectUri), isFocused: isFocused, isHovered: isHovered, emailSubmitButtonInsideInput: true }) }) }) }), bannerMessage && (jsx("div", { className: `banner ${bannerMessage.type}`, children: jsx(Typography, { variant: 'body_small', weight: 'regular', color: 'primary', children: bannerMessage.message }) }))] }), jsx("div", { className: 'info-card', children: jsxs("div", { className: 'wrapper', children: [jsx(Typography, { variant: 'body_small', weight: 'bold', color: 'primary', as: 'h2', children: t('global_wallet.help.title') }), jsx(Typography, { variant: 'body_small', weight: 'regular', color: 'secondary', children: t('global_wallet.help.step.1') }), jsx(Typography, { variant: 'body_small', weight: 'regular', color: 'secondary', children: t('global_wallet.help.step.2') }), jsx(InlineWalletConnectTypography, {}), jsx(InlineCopyTextTypography, {})] }) })] }));
200
+ }, [walletConnectUri, handlePairing]);
201
+ const renderHeader = () => (jsxs("div", { className: 'header', children: [jsx(IconButton, { type: 'button', onClick: goToInitialDynamicWidgetView, "data-testid": 'back-button', children: jsx(SvgArrowLeft, {}) }), jsx(Typography, { variant: 'title', weight: 'medium', color: 'primary', as: 'h1', copykey: 'global_wallet.connect_to_apps', children: t('global_wallet.connect_to_apps') }), isMobile() && (jsx(IconButton, { type: 'button', onClick: () => {
202
+ setView('global-wallet-info');
203
+ setShowAuthFlow(true, {
204
+ ignoreIfIsEmbeddedWidget: false,
205
+ performMultiWalletChecks: false,
206
+ });
207
+ }, "data-testid": 'info-button', children: jsx(SvgQuestionMark, {}) }))] }));
208
+ const renderScanner = () => isMobile() && (jsxs(Fragment, { children: [jsxs("div", { className: 'scanner-wrapper', children: [jsx(GlobalWalletScanner, { onScan: handleScan, jsQR: globalWallet.qrScanner }), jsxs("div", { className: 'scanner-overlay', children: [jsxs("div", { className: 'scanner-frame', children: [jsx("div", { className: 'corner top-left' }), jsx("div", { className: 'corner top-right' }), jsx("div", { className: 'corner bottom-left' }), jsx("div", { className: 'corner bottom-right' })] }), jsxs("div", { className: 'scanner-overlay-content', children: [jsx(SvgBlueWalletconnect, { className: 'scanner-icon' }), jsx(Typography, { variant: 'body_small', weight: 'regular', color: 'white', copykey: 'global_wallet.scan_qr_code', children: t('global_wallet.scan_qr_code') })] })] })] }), jsx(Divider, { text: t('global_wallet.or') })] }));
209
+ const renderInput = () => (jsxs("div", { className: 'wallet-connect-card', children: [jsx("div", { className: 'input-group', children: jsx(Input, { copykey: 'global_wallet.walletconnect_uri', id: 'walletconnect-uri', label: t('global_wallet.walletconnect_uri'), placeholder: 'wc:...', value: isScanned ? '' : walletConnectUri, onChange: (e) => {
210
+ setWalletConnectUri(e.target.value);
211
+ setIsScanned(false);
212
+ }, variant: 'dense', onKeyDown: (e) => e.key === 'Enter' && handlePairing(), suffix:
213
+ // eslint-disable-next-line react/jsx-wrap-multilines
214
+ jsx("div", { className: 'input-suffix', onClick: handlePairing, role: 'button', tabIndex: 0, children: jsx(InlineSubmitButton, { disabled: false, highlighted: Boolean(walletConnectUri) && !isScanned, isFocused: false, isHovered: false, emailSubmitButtonInsideInput: true }) }) }) }), bannerMessage && (jsx("div", { className: `banner ${bannerMessage.type}`, children: jsx(Typography, { variant: 'body_small', weight: 'regular', color: 'primary', children: bannerMessage.message }) }))] }));
215
+ const renderInfoCard = () => !isMobile() && (jsx("div", { className: 'info-card', children: jsxs("div", { className: 'wrapper', children: [jsx(Typography, { variant: 'body_small', weight: 'bold', color: 'primary', as: 'h2', children: t('global_wallet.help.title') }), jsx(Typography, { variant: 'body_small', weight: 'regular', color: 'secondary', children: t('global_wallet.help.step.1') }), jsx(Typography, { variant: 'body_small', weight: 'regular', color: 'secondary', children: t('global_wallet.help.step.2') }), jsx(Typography, { variant: 'body_small', weight: 'regular', color: 'secondary', children: jsxs("span", { className: 'inline-logo-text', children: ["3. Open WalletConnect", jsx(SvgBlueWalletconnect, { className: 'inline-logo' }), " from the list"] }) }), jsx(Typography, { variant: 'body_small', weight: 'regular', color: 'secondary', children: jsxs("span", { className: 'inline-logo-text', children: ["4. Locate and click ", jsx(SvgCopy, { className: 'inline-logo' }), " to copy the URI code"] }) })] }) }));
216
+ return (jsxs("div", { className: 'connect-dapps-view', children: [renderHeader(), renderScanner(), renderInput(), renderInfoCard()] }));
228
217
  };
229
218
 
230
219
  export { GlobalWalletView, GlobalWalletView as default };
@@ -0,0 +1,54 @@
1
+ 'use client'
2
+ 'use strict';
3
+
4
+ Object.defineProperty(exports, '__esModule', { value: true });
5
+
6
+ var jsxRuntime = require('react/jsx-runtime');
7
+ var React = require('react');
8
+
9
+ const GlobalWalletScanner = ({ onScan, jsQR, }) => {
10
+ const videoRef = React.useRef(null);
11
+ const canvasRef = React.useRef(null);
12
+ React.useEffect(() => {
13
+ const video = videoRef.current;
14
+ const canvas = canvasRef.current;
15
+ if (!video || !canvas)
16
+ return;
17
+ const ctx = canvas.getContext('2d');
18
+ if (!ctx)
19
+ return;
20
+ const constraints = {
21
+ video: { facingMode: 'environment' },
22
+ };
23
+ navigator.mediaDevices.getUserMedia(constraints).then((stream) => {
24
+ video.srcObject = stream;
25
+ video.setAttribute('playsinline', 'true'); // required to tell iOS safari we don't want fullscreen
26
+ video.play();
27
+ requestAnimationFrame(tick);
28
+ });
29
+ const tick = () => {
30
+ if (video.readyState === video.HAVE_ENOUGH_DATA) {
31
+ canvas.height = video.videoHeight;
32
+ canvas.width = video.videoWidth;
33
+ ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
34
+ const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
35
+ const code = jsQR(imageData.data, imageData.width, imageData.height, {
36
+ inversionAttempts: 'dontInvert',
37
+ });
38
+ if (code) {
39
+ onScan(code.data);
40
+ }
41
+ }
42
+ requestAnimationFrame(tick);
43
+ };
44
+ return () => {
45
+ const stream = video.srcObject;
46
+ const tracks = stream === null || stream === void 0 ? void 0 : stream.getTracks();
47
+ tracks === null || tracks === void 0 ? void 0 : tracks.forEach((track) => track.stop());
48
+ };
49
+ }, [onScan]);
50
+ return (jsxRuntime.jsx("div", { children: jsxRuntime.jsxs("div", { className: 'videoWrapper', children: [jsxRuntime.jsx("video", { ref: videoRef, className: 'qrVideo' }), jsxRuntime.jsx("canvas", { ref: canvasRef, style: { display: 'none' } })] }) }));
51
+ };
52
+
53
+ exports.GlobalWalletScanner = GlobalWalletScanner;
54
+ exports["default"] = GlobalWalletScanner;
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ interface GlobalWalletScannerProps {
3
+ jsQR: (data: Uint8ClampedArray, width: number, height: number, providedOptions?: any) => any;
4
+ onScan: (result: string) => void;
5
+ }
6
+ export declare const GlobalWalletScanner: React.FC<GlobalWalletScannerProps>;
7
+ export default GlobalWalletScanner;
@@ -0,0 +1,49 @@
1
+ 'use client'
2
+ import { jsx, jsxs } from 'react/jsx-runtime';
3
+ import { useRef, useEffect } from 'react';
4
+
5
+ const GlobalWalletScanner = ({ onScan, jsQR, }) => {
6
+ const videoRef = useRef(null);
7
+ const canvasRef = useRef(null);
8
+ useEffect(() => {
9
+ const video = videoRef.current;
10
+ const canvas = canvasRef.current;
11
+ if (!video || !canvas)
12
+ return;
13
+ const ctx = canvas.getContext('2d');
14
+ if (!ctx)
15
+ return;
16
+ const constraints = {
17
+ video: { facingMode: 'environment' },
18
+ };
19
+ navigator.mediaDevices.getUserMedia(constraints).then((stream) => {
20
+ video.srcObject = stream;
21
+ video.setAttribute('playsinline', 'true'); // required to tell iOS safari we don't want fullscreen
22
+ video.play();
23
+ requestAnimationFrame(tick);
24
+ });
25
+ const tick = () => {
26
+ if (video.readyState === video.HAVE_ENOUGH_DATA) {
27
+ canvas.height = video.videoHeight;
28
+ canvas.width = video.videoWidth;
29
+ ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
30
+ const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
31
+ const code = jsQR(imageData.data, imageData.width, imageData.height, {
32
+ inversionAttempts: 'dontInvert',
33
+ });
34
+ if (code) {
35
+ onScan(code.data);
36
+ }
37
+ }
38
+ requestAnimationFrame(tick);
39
+ };
40
+ return () => {
41
+ const stream = video.srcObject;
42
+ const tracks = stream === null || stream === void 0 ? void 0 : stream.getTracks();
43
+ tracks === null || tracks === void 0 ? void 0 : tracks.forEach((track) => track.stop());
44
+ };
45
+ }, [onScan]);
46
+ return (jsx("div", { children: jsxs("div", { className: 'videoWrapper', children: [jsx("video", { ref: videoRef, className: 'qrVideo' }), jsx("canvas", { ref: canvasRef, style: { display: 'none' } })] }) }));
47
+ };
48
+
49
+ export { GlobalWalletScanner, GlobalWalletScanner as default };