@dynamic-labs/sdk-react-core 4.80.0 → 4.81.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/package.cjs +1 -1
- package/package.js +1 -1
- package/package.json +12 -12
- package/src/lib/components/SendBalanceForm/SendBalanceForm.cjs +63 -3
- package/src/lib/components/SendBalanceForm/SendBalanceForm.js +63 -3
- package/src/lib/components/SendBalanceForm/TransactionModeSegmentedControl/TransactionModeSegmentedControl.cjs +40 -0
- package/src/lib/components/SendBalanceForm/TransactionModeSegmentedControl/TransactionModeSegmentedControl.d.ts +16 -0
- package/src/lib/components/SendBalanceForm/TransactionModeSegmentedControl/TransactionModeSegmentedControl.js +36 -0
- package/src/lib/components/SendBalanceForm/TransactionModeSegmentedControl/icons.cjs +17 -0
- package/src/lib/components/SendBalanceForm/TransactionModeSegmentedControl/icons.d.ts +8 -0
- package/src/lib/components/SendBalanceForm/TransactionModeSegmentedControl/icons.js +12 -0
- package/src/lib/components/SendBalanceForm/TransactionModeSegmentedControl/index.d.ts +1 -0
- package/src/lib/styles/index.shadow.cjs +1 -1
- package/src/lib/styles/index.shadow.js +1 -1
- package/src/lib/utils/hooks/useAleoShieldedBalances/index.d.ts +1 -0
- package/src/lib/utils/hooks/useAleoShieldedBalances/useAleoShieldedBalances.cjs +372 -0
- package/src/lib/utils/hooks/useAleoShieldedBalances/useAleoShieldedBalances.d.ts +24 -0
- package/src/lib/utils/hooks/useAleoShieldedBalances/useAleoShieldedBalances.js +368 -0
- package/src/lib/utils/hooks/useEmbeddedWallet/useEmbeddedWallet.cjs +1 -0
- package/src/lib/utils/hooks/useEmbeddedWallet/useEmbeddedWallet.d.ts +1 -0
- package/src/lib/utils/hooks/useEmbeddedWallet/useEmbeddedWallet.js +1 -0
- package/src/lib/views/SendBalanceView/SendBalanceView.cjs +53 -0
- package/src/lib/views/SendBalanceView/SendBalanceView.js +53 -0
- package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/ActiveWalletBalance.cjs +191 -11
- package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/ActiveWalletBalance.js +191 -11
- package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/TokenBalanceItem/TokenBalanceItem.cjs +5 -2
- package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/TokenBalanceItem/TokenBalanceItem.d.ts +10 -1
- package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/TokenBalanceItem/TokenBalanceItem.js +5 -2
- package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/TokenBalanceItem/index.d.ts +1 -0
- package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/TokenBalanceList/TokenBalanceList.cjs +2 -2
- package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/TokenBalanceList/TokenBalanceList.d.ts +3 -1
- package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/TokenBalanceList/TokenBalanceList.js +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,20 @@
|
|
|
1
1
|
|
|
2
|
+
## [4.81.0](https://github.com/dynamic-labs/dynamic-auth/compare/v4.80.0...v4.81.0) (2026-05-07)
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
* **react-native:** add waitForAuthSuccess() to auth module ([#11137](https://github.com/dynamic-labs/dynamic-auth/issues/11137)) ([089a566](https://github.com/dynamic-labs/dynamic-auth/commit/089a5663283639e7e425eead291b135010c8b398))
|
|
8
|
+
* **waas:** hook Aleo into DynamicWaasMixin ([#11102](https://github.com/dynamic-labs/dynamic-auth/issues/11102)) ([ff42df9](https://github.com/dynamic-labs/dynamic-auth/commit/ff42df99d8993e22894caee3c0570cd9c332a3d1))
|
|
9
|
+
* **widget:** shielded/unshielded tabs + Shield Manually CTA on ActiveWalletBalance for Aleo ([#11103](https://github.com/dynamic-labs/dynamic-auth/issues/11103)) ([e278836](https://github.com/dynamic-labs/dynamic-auth/commit/e278836bfcb19c13828c10483ebb87d165f5d00d))
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
### Bug Fixes
|
|
13
|
+
|
|
14
|
+
* **ethereum-aa:** return hex chain ids from EIP-5792 getCapabilities ([#11146](https://github.com/dynamic-labs/dynamic-auth/issues/11146)) ([b32dc8f](https://github.com/dynamic-labs/dynamic-auth/commit/b32dc8f6fdee3722073921787c4f77908ab4f740))
|
|
15
|
+
* remediate high-severity dependency vulnerabilities ([#11151](https://github.com/dynamic-labs/dynamic-auth/issues/11151)) ([1d84ef1](https://github.com/dynamic-labs/dynamic-auth/commit/1d84ef12e10544be0b2a80dbbbd63f615b03adc3))
|
|
16
|
+
* **wagmi-connector:** emit change unconditionally on MM accountsChanged DYNT-549 ([#11131](https://github.com/dynamic-labs/dynamic-auth/issues/11131)) ([348ee6f](https://github.com/dynamic-labs/dynamic-auth/commit/348ee6ff9a22cb55ef0cb84c4b8f8d2e843bd10e)), closes [#11043](https://github.com/dynamic-labs/dynamic-auth/issues/11043)
|
|
17
|
+
|
|
2
18
|
## [4.80.0](https://github.com/dynamic-labs/dynamic-auth/compare/v4.79.2...v4.80.0) (2026-05-05)
|
|
3
19
|
|
|
4
20
|
|
package/package.cjs
CHANGED
package/package.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dynamic-labs/sdk-react-core",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.81.0",
|
|
4
4
|
"dependencies": {
|
|
5
5
|
"@dynamic-labs/sdk-api-core": "0.0.964",
|
|
6
6
|
"@dynamic-labs-sdk/client": "0.26.9",
|
|
@@ -16,17 +16,17 @@
|
|
|
16
16
|
"yup": "0.32.11",
|
|
17
17
|
"react-international-phone": "4.5.0",
|
|
18
18
|
"bs58": "5.0.0",
|
|
19
|
-
"@dynamic-labs/assert-package-version": "4.
|
|
20
|
-
"@dynamic-labs/iconic": "4.
|
|
21
|
-
"@dynamic-labs/locale": "4.
|
|
22
|
-
"@dynamic-labs/logger": "4.
|
|
23
|
-
"@dynamic-labs/multi-wallet": "4.
|
|
24
|
-
"@dynamic-labs/rpc-providers": "4.
|
|
25
|
-
"@dynamic-labs/store": "4.
|
|
26
|
-
"@dynamic-labs/types": "4.
|
|
27
|
-
"@dynamic-labs/utils": "4.
|
|
28
|
-
"@dynamic-labs/wallet-book": "4.
|
|
29
|
-
"@dynamic-labs/wallet-connector-core": "4.
|
|
19
|
+
"@dynamic-labs/assert-package-version": "4.81.0",
|
|
20
|
+
"@dynamic-labs/iconic": "4.81.0",
|
|
21
|
+
"@dynamic-labs/locale": "4.81.0",
|
|
22
|
+
"@dynamic-labs/logger": "4.81.0",
|
|
23
|
+
"@dynamic-labs/multi-wallet": "4.81.0",
|
|
24
|
+
"@dynamic-labs/rpc-providers": "4.81.0",
|
|
25
|
+
"@dynamic-labs/store": "4.81.0",
|
|
26
|
+
"@dynamic-labs/types": "4.81.0",
|
|
27
|
+
"@dynamic-labs/utils": "4.81.0",
|
|
28
|
+
"@dynamic-labs/wallet-book": "4.81.0",
|
|
29
|
+
"@dynamic-labs/wallet-connector-core": "4.81.0",
|
|
30
30
|
"eventemitter3": "5.0.1"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
5
5
|
|
|
6
|
+
var _tslib = require('../../../../_virtual/_tslib.cjs');
|
|
6
7
|
var jsxRuntime = require('react/jsx-runtime');
|
|
7
8
|
var React = require('react');
|
|
8
9
|
var formik = require('formik');
|
|
@@ -21,7 +22,6 @@ require('../../utils/constants/values.cjs');
|
|
|
21
22
|
require('@dynamic-labs/sdk-api-core');
|
|
22
23
|
require('../../shared/consts/index.cjs');
|
|
23
24
|
require('../../events/dynamicEvents.cjs');
|
|
24
|
-
require('../../../../_virtual/_tslib.cjs');
|
|
25
25
|
require('../../context/CaptchaContext/CaptchaContext.cjs');
|
|
26
26
|
require('../../context/ErrorContext/ErrorContext.cjs');
|
|
27
27
|
require('@dynamic-labs/multi-wallet');
|
|
@@ -60,7 +60,7 @@ require('../../context/UserFieldEditorContext/UserFieldEditorContext.cjs');
|
|
|
60
60
|
require('@dynamic-labs/rpc-providers');
|
|
61
61
|
require('../../store/state/walletOptions/walletOptions.cjs');
|
|
62
62
|
require('../Accordion/components/AccordionItem/AccordionItem.cjs');
|
|
63
|
-
require('../Alert/Alert.cjs');
|
|
63
|
+
var Alert = require('../Alert/Alert.cjs');
|
|
64
64
|
var Typography = require('../Typography/Typography.cjs');
|
|
65
65
|
require('../ShadowDOM/ShadowDOM.cjs');
|
|
66
66
|
var TypographyButton = require('../TypographyButton/TypographyButton.cjs');
|
|
@@ -101,6 +101,7 @@ var sendBalances = require('../../store/state/sendBalances.cjs');
|
|
|
101
101
|
var TokensBalanceDropdown = require('../SendBalancePageLayout/components/TokensBalanceDropdown/TokensBalanceDropdown.cjs');
|
|
102
102
|
var utils = require('../TransactionConfirmationPageLayout/utils.cjs');
|
|
103
103
|
var FeeTokenSelector = require('./FeeTokenSelector/FeeTokenSelector.cjs');
|
|
104
|
+
var TransactionModeSegmentedControl = require('./TransactionModeSegmentedControl/TransactionModeSegmentedControl.cjs');
|
|
104
105
|
require('../../store/state/connectorsInitializing/connectorsInitializing.cjs');
|
|
105
106
|
require('../OverlayCardBase/OverlayCardTarget/OverlayCardTarget.cjs');
|
|
106
107
|
require('../../widgets/DynamicWidget/components/DynamicWidgetHeader/DynamicWidgetHeader.cjs');
|
|
@@ -142,11 +143,55 @@ const getDisplayErrorMessage = (errors, t, field, decimals) => {
|
|
|
142
143
|
return '';
|
|
143
144
|
};
|
|
144
145
|
const SendBalanceForm = ({ initialValues, onSubmit, decimals = 18, validateAddress = () => true, validateAmount = () => true, currentToken, transaction, tokenBalances, setCurrentToken, isLoading, supportsFeeTokenSelection = false, feeTokenOptions, currentFeeToken, setCurrentFeeToken, }) => {
|
|
146
|
+
var _a;
|
|
145
147
|
const { t } = reactI18next.useTranslation();
|
|
146
148
|
const { showFiat } = useInternalDynamicContext.useInternalDynamicContext();
|
|
147
149
|
const floatingValueRef = React.useRef(null);
|
|
148
150
|
const [leftSymbolPadding, setLeftSymbolPadding] = React.useState(0);
|
|
149
151
|
const { amount } = sendBalances.useSendBalanceState();
|
|
152
|
+
// Aleo (and any future chain that opts in) populates `transactionModes`
|
|
153
|
+
// on its IUITransaction. We render a segmented control between the
|
|
154
|
+
// recipient field and the submit button. The chain may leave
|
|
155
|
+
// `selectedTransactionMode` undefined to force the user to explicitly
|
|
156
|
+
// pick — in that case we keep the form interactive (token list,
|
|
157
|
+
// amount, recipient all stay editable since they don't depend on the
|
|
158
|
+
// mode), and only the submit button is gated until a selection lands.
|
|
159
|
+
// `transaction` is supplied by Send-launching call sites (widget) but
|
|
160
|
+
// legacy / unit-test consumers may render the form without one. Guard
|
|
161
|
+
// every property access so the form still renders for those cases —
|
|
162
|
+
// the segmented-mode UI just stays hidden when transaction is absent.
|
|
163
|
+
const transactionModes = (_a = transaction === null || transaction === void 0 ? void 0 : transaction.transactionModes) !== null && _a !== void 0 ? _a : [];
|
|
164
|
+
const hasModes = transactionModes.length > 1;
|
|
165
|
+
const [selectedModeId, setSelectedModeId] = React.useState(transaction === null || transaction === void 0 ? void 0 : transaction.selectedTransactionMode);
|
|
166
|
+
const modeReady = !hasModes || Boolean(selectedModeId);
|
|
167
|
+
// The merge CTA is re-derived after each form change / mode change so
|
|
168
|
+
// the banner can appear, disappear, or change copy without a manual
|
|
169
|
+
// refresh. We snapshot it in state so the banner survives re-renders
|
|
170
|
+
// while the user clicks the action and the underlying merge runs.
|
|
171
|
+
const [mergeAction, setMergeAction] = React.useState(() => { var _a; return (_a = transaction === null || transaction === void 0 ? void 0 : transaction.getRecordMergeAction) === null || _a === void 0 ? void 0 : _a.call(transaction); });
|
|
172
|
+
const [isMerging, setIsMerging] = React.useState(false);
|
|
173
|
+
const refreshMergeAction = () => {
|
|
174
|
+
var _a;
|
|
175
|
+
setMergeAction((_a = transaction === null || transaction === void 0 ? void 0 : transaction.getRecordMergeAction) === null || _a === void 0 ? void 0 : _a.call(transaction));
|
|
176
|
+
};
|
|
177
|
+
const handleModeChange = (modeId) => {
|
|
178
|
+
var _a;
|
|
179
|
+
setSelectedModeId(modeId);
|
|
180
|
+
(_a = transaction === null || transaction === void 0 ? void 0 : transaction.setTransactionMode) === null || _a === void 0 ? void 0 : _a.call(transaction, modeId);
|
|
181
|
+
refreshMergeAction();
|
|
182
|
+
};
|
|
183
|
+
const handleMergeAction = () => _tslib.__awaiter(void 0, void 0, void 0, function* () {
|
|
184
|
+
if (!mergeAction || isMerging)
|
|
185
|
+
return;
|
|
186
|
+
setIsMerging(true);
|
|
187
|
+
try {
|
|
188
|
+
yield mergeAction.onAction();
|
|
189
|
+
}
|
|
190
|
+
finally {
|
|
191
|
+
setIsMerging(false);
|
|
192
|
+
refreshMergeAction();
|
|
193
|
+
}
|
|
194
|
+
});
|
|
150
195
|
React.useEffect(() => {
|
|
151
196
|
if (floatingValueRef.current) {
|
|
152
197
|
const floatingDivWidth = floatingValueRef.current.offsetWidth;
|
|
@@ -188,9 +233,16 @@ const SendBalanceForm = ({ initialValues, onSubmit, decimals = 18, validateAddre
|
|
|
188
233
|
}
|
|
189
234
|
sendBalances.setSendBalanceVariable('amount', (currentToken === null || currentToken === void 0 ? void 0 : currentToken.price) ? Number(newValue) : undefined);
|
|
190
235
|
}, onBlur: (e) => {
|
|
236
|
+
var _a, _b;
|
|
191
237
|
handleBlur(e);
|
|
192
238
|
setFieldTouched('amount', true);
|
|
193
239
|
validateField('amount');
|
|
240
|
+
// Push the latest amount string to the transaction so any
|
|
241
|
+
// chain-specific derived state (e.g. Aleo's merge CTA) can
|
|
242
|
+
// reflect what the user has entered without waiting for
|
|
243
|
+
// the submit step that would otherwise set transaction.value.
|
|
244
|
+
(_a = transaction === null || transaction === void 0 ? void 0 : transaction.setPendingAmount) === null || _a === void 0 ? void 0 : _a.call(transaction, (_b = e.target.value) !== null && _b !== void 0 ? _b : '');
|
|
245
|
+
refreshMergeAction();
|
|
194
246
|
}, placeholder: t('dyn_send_transaction.data.amount.placeholder'), as: Input.Input, error: errors['amount'], copykey: 'dyn_send_transaction.data.amount.label', message: touched['amount'] &&
|
|
195
247
|
getDisplayErrorMessage(errors, t, 'amount', decimals), style: {
|
|
196
248
|
paddingLeft: `${leftSymbolPadding}px`,
|
|
@@ -201,7 +253,15 @@ const SendBalanceForm = ({ initialValues, onSubmit, decimals = 18, validateAddre
|
|
|
201
253
|
feeTokenOptions.length > 0 &&
|
|
202
254
|
setCurrentFeeToken &&
|
|
203
255
|
currentFeeToken && (jsxRuntime.jsx(FeeTokenSelector.FeeTokenSelector, { feeTokenOptions: feeTokenOptions, currentFeeToken: currentFeeToken, setCurrentFeeToken: setCurrentFeeToken, label: t('dyn_send_transaction.data.fee_token_label') })), jsxRuntime.jsx(Typography.Typography, { variant: 'body_small', weight: 'regular', color: 'secondary', copykey: 'dyn_send_transaction.data.recipient.label', children: "Recipient Address" }), jsxRuntime.jsx(formik.Field, { className: 'send-balance-form__field', placeholder: t('dyn_send_transaction.data.recipient.placeholder'), label: t('dyn_send_transaction.data.recipient.label'), id: 'recipient', name: 'recipient', as: Input.Input, error: errors['recipient'], copykey: 'dyn_send_transaction.data.recipient.label', message: touched['recipient'] &&
|
|
204
|
-
getDisplayErrorMessage(errors, t, 'recipient')
|
|
256
|
+
getDisplayErrorMessage(errors, t, 'recipient'), onBlur: (e) => {
|
|
257
|
+
handleBlur(e);
|
|
258
|
+
setFieldTouched('recipient', true);
|
|
259
|
+
// Re-evaluate the merge CTA once the recipient lands; some
|
|
260
|
+
// chains' merge logic may key off both amount and address.
|
|
261
|
+
refreshMergeAction();
|
|
262
|
+
} }), hasModes && (jsxRuntime.jsx(TransactionModeSegmentedControl.TransactionModeSegmentedControl, { options: transactionModes, selectedId: selectedModeId, onChange: handleModeChange, disabled: isMerging })), mergeAction && (jsxRuntime.jsx("div", { className: 'send-balance-form__inline-action', children: jsxRuntime.jsx(Alert.Alert, { icon: 'error', variant: 'warning', children: jsxRuntime.jsxs("div", { className: 'send-balance-form__inline-action-content', children: [jsxRuntime.jsx(Typography.Typography, { variant: 'body_small', weight: 'regular', children: mergeAction.message }), jsxRuntime.jsx(TypographyButton.TypographyButton, { dataTestId: 'sendBalanceFormMergeRecordsButton', type: 'button', buttonVariant: 'secondary', buttonPadding: 'small', onClick: handleMergeAction, disabled: isMerging, children: isMerging
|
|
263
|
+
? t('dyn_send_transaction.merging', 'Merging…')
|
|
264
|
+
: mergeAction.actionLabel })] }) }) })), jsxRuntime.jsx(TypographyButton.TypographyButton, { dataTestId: 'sendBalanceFormSubmitButton', expanded: true, type: 'submit', buttonVariant: 'primary', buttonPadding: 'small', buttonClassName: 'send-balance-form__button', copykey: 'dyn_send_transaction.preview_transaction', disabled: !modeReady || isMerging || Boolean(mergeAction), children: t('dyn_send_transaction.preview_transaction') })] }));
|
|
205
265
|
} }));
|
|
206
266
|
};
|
|
207
267
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
'use client'
|
|
2
|
+
import { __awaiter } from '../../../../_virtual/_tslib.js';
|
|
2
3
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
3
4
|
import { useRef, useState, useEffect, useMemo } from 'react';
|
|
4
5
|
import { Formik, Form, Field } from 'formik';
|
|
@@ -17,7 +18,6 @@ import '../../utils/constants/values.js';
|
|
|
17
18
|
import '@dynamic-labs/sdk-api-core';
|
|
18
19
|
import '../../shared/consts/index.js';
|
|
19
20
|
import '../../events/dynamicEvents.js';
|
|
20
|
-
import '../../../../_virtual/_tslib.js';
|
|
21
21
|
import '../../context/CaptchaContext/CaptchaContext.js';
|
|
22
22
|
import '../../context/ErrorContext/ErrorContext.js';
|
|
23
23
|
import '@dynamic-labs/multi-wallet';
|
|
@@ -56,7 +56,7 @@ import '../../context/UserFieldEditorContext/UserFieldEditorContext.js';
|
|
|
56
56
|
import '@dynamic-labs/rpc-providers';
|
|
57
57
|
import '../../store/state/walletOptions/walletOptions.js';
|
|
58
58
|
import '../Accordion/components/AccordionItem/AccordionItem.js';
|
|
59
|
-
import '../Alert/Alert.js';
|
|
59
|
+
import { Alert } from '../Alert/Alert.js';
|
|
60
60
|
import { Typography } from '../Typography/Typography.js';
|
|
61
61
|
import '../ShadowDOM/ShadowDOM.js';
|
|
62
62
|
import { TypographyButton } from '../TypographyButton/TypographyButton.js';
|
|
@@ -97,6 +97,7 @@ import { useSendBalanceState, setSendBalanceVariable } from '../../store/state/s
|
|
|
97
97
|
import { TokensBalanceDropdown } from '../SendBalancePageLayout/components/TokensBalanceDropdown/TokensBalanceDropdown.js';
|
|
98
98
|
import { getDisplayFiatPrice } from '../TransactionConfirmationPageLayout/utils.js';
|
|
99
99
|
import { FeeTokenSelector } from './FeeTokenSelector/FeeTokenSelector.js';
|
|
100
|
+
import { TransactionModeSegmentedControl } from './TransactionModeSegmentedControl/TransactionModeSegmentedControl.js';
|
|
100
101
|
import '../../store/state/connectorsInitializing/connectorsInitializing.js';
|
|
101
102
|
import '../OverlayCardBase/OverlayCardTarget/OverlayCardTarget.js';
|
|
102
103
|
import '../../widgets/DynamicWidget/components/DynamicWidgetHeader/DynamicWidgetHeader.js';
|
|
@@ -138,11 +139,55 @@ const getDisplayErrorMessage = (errors, t, field, decimals) => {
|
|
|
138
139
|
return '';
|
|
139
140
|
};
|
|
140
141
|
const SendBalanceForm = ({ initialValues, onSubmit, decimals = 18, validateAddress = () => true, validateAmount = () => true, currentToken, transaction, tokenBalances, setCurrentToken, isLoading, supportsFeeTokenSelection = false, feeTokenOptions, currentFeeToken, setCurrentFeeToken, }) => {
|
|
142
|
+
var _a;
|
|
141
143
|
const { t } = useTranslation();
|
|
142
144
|
const { showFiat } = useInternalDynamicContext();
|
|
143
145
|
const floatingValueRef = useRef(null);
|
|
144
146
|
const [leftSymbolPadding, setLeftSymbolPadding] = useState(0);
|
|
145
147
|
const { amount } = useSendBalanceState();
|
|
148
|
+
// Aleo (and any future chain that opts in) populates `transactionModes`
|
|
149
|
+
// on its IUITransaction. We render a segmented control between the
|
|
150
|
+
// recipient field and the submit button. The chain may leave
|
|
151
|
+
// `selectedTransactionMode` undefined to force the user to explicitly
|
|
152
|
+
// pick — in that case we keep the form interactive (token list,
|
|
153
|
+
// amount, recipient all stay editable since they don't depend on the
|
|
154
|
+
// mode), and only the submit button is gated until a selection lands.
|
|
155
|
+
// `transaction` is supplied by Send-launching call sites (widget) but
|
|
156
|
+
// legacy / unit-test consumers may render the form without one. Guard
|
|
157
|
+
// every property access so the form still renders for those cases —
|
|
158
|
+
// the segmented-mode UI just stays hidden when transaction is absent.
|
|
159
|
+
const transactionModes = (_a = transaction === null || transaction === void 0 ? void 0 : transaction.transactionModes) !== null && _a !== void 0 ? _a : [];
|
|
160
|
+
const hasModes = transactionModes.length > 1;
|
|
161
|
+
const [selectedModeId, setSelectedModeId] = useState(transaction === null || transaction === void 0 ? void 0 : transaction.selectedTransactionMode);
|
|
162
|
+
const modeReady = !hasModes || Boolean(selectedModeId);
|
|
163
|
+
// The merge CTA is re-derived after each form change / mode change so
|
|
164
|
+
// the banner can appear, disappear, or change copy without a manual
|
|
165
|
+
// refresh. We snapshot it in state so the banner survives re-renders
|
|
166
|
+
// while the user clicks the action and the underlying merge runs.
|
|
167
|
+
const [mergeAction, setMergeAction] = useState(() => { var _a; return (_a = transaction === null || transaction === void 0 ? void 0 : transaction.getRecordMergeAction) === null || _a === void 0 ? void 0 : _a.call(transaction); });
|
|
168
|
+
const [isMerging, setIsMerging] = useState(false);
|
|
169
|
+
const refreshMergeAction = () => {
|
|
170
|
+
var _a;
|
|
171
|
+
setMergeAction((_a = transaction === null || transaction === void 0 ? void 0 : transaction.getRecordMergeAction) === null || _a === void 0 ? void 0 : _a.call(transaction));
|
|
172
|
+
};
|
|
173
|
+
const handleModeChange = (modeId) => {
|
|
174
|
+
var _a;
|
|
175
|
+
setSelectedModeId(modeId);
|
|
176
|
+
(_a = transaction === null || transaction === void 0 ? void 0 : transaction.setTransactionMode) === null || _a === void 0 ? void 0 : _a.call(transaction, modeId);
|
|
177
|
+
refreshMergeAction();
|
|
178
|
+
};
|
|
179
|
+
const handleMergeAction = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
180
|
+
if (!mergeAction || isMerging)
|
|
181
|
+
return;
|
|
182
|
+
setIsMerging(true);
|
|
183
|
+
try {
|
|
184
|
+
yield mergeAction.onAction();
|
|
185
|
+
}
|
|
186
|
+
finally {
|
|
187
|
+
setIsMerging(false);
|
|
188
|
+
refreshMergeAction();
|
|
189
|
+
}
|
|
190
|
+
});
|
|
146
191
|
useEffect(() => {
|
|
147
192
|
if (floatingValueRef.current) {
|
|
148
193
|
const floatingDivWidth = floatingValueRef.current.offsetWidth;
|
|
@@ -184,9 +229,16 @@ const SendBalanceForm = ({ initialValues, onSubmit, decimals = 18, validateAddre
|
|
|
184
229
|
}
|
|
185
230
|
setSendBalanceVariable('amount', (currentToken === null || currentToken === void 0 ? void 0 : currentToken.price) ? Number(newValue) : undefined);
|
|
186
231
|
}, onBlur: (e) => {
|
|
232
|
+
var _a, _b;
|
|
187
233
|
handleBlur(e);
|
|
188
234
|
setFieldTouched('amount', true);
|
|
189
235
|
validateField('amount');
|
|
236
|
+
// Push the latest amount string to the transaction so any
|
|
237
|
+
// chain-specific derived state (e.g. Aleo's merge CTA) can
|
|
238
|
+
// reflect what the user has entered without waiting for
|
|
239
|
+
// the submit step that would otherwise set transaction.value.
|
|
240
|
+
(_a = transaction === null || transaction === void 0 ? void 0 : transaction.setPendingAmount) === null || _a === void 0 ? void 0 : _a.call(transaction, (_b = e.target.value) !== null && _b !== void 0 ? _b : '');
|
|
241
|
+
refreshMergeAction();
|
|
190
242
|
}, placeholder: t('dyn_send_transaction.data.amount.placeholder'), as: Input, error: errors['amount'], copykey: 'dyn_send_transaction.data.amount.label', message: touched['amount'] &&
|
|
191
243
|
getDisplayErrorMessage(errors, t, 'amount', decimals), style: {
|
|
192
244
|
paddingLeft: `${leftSymbolPadding}px`,
|
|
@@ -197,7 +249,15 @@ const SendBalanceForm = ({ initialValues, onSubmit, decimals = 18, validateAddre
|
|
|
197
249
|
feeTokenOptions.length > 0 &&
|
|
198
250
|
setCurrentFeeToken &&
|
|
199
251
|
currentFeeToken && (jsx(FeeTokenSelector, { feeTokenOptions: feeTokenOptions, currentFeeToken: currentFeeToken, setCurrentFeeToken: setCurrentFeeToken, label: t('dyn_send_transaction.data.fee_token_label') })), jsx(Typography, { variant: 'body_small', weight: 'regular', color: 'secondary', copykey: 'dyn_send_transaction.data.recipient.label', children: "Recipient Address" }), jsx(Field, { className: 'send-balance-form__field', placeholder: t('dyn_send_transaction.data.recipient.placeholder'), label: t('dyn_send_transaction.data.recipient.label'), id: 'recipient', name: 'recipient', as: Input, error: errors['recipient'], copykey: 'dyn_send_transaction.data.recipient.label', message: touched['recipient'] &&
|
|
200
|
-
getDisplayErrorMessage(errors, t, 'recipient')
|
|
252
|
+
getDisplayErrorMessage(errors, t, 'recipient'), onBlur: (e) => {
|
|
253
|
+
handleBlur(e);
|
|
254
|
+
setFieldTouched('recipient', true);
|
|
255
|
+
// Re-evaluate the merge CTA once the recipient lands; some
|
|
256
|
+
// chains' merge logic may key off both amount and address.
|
|
257
|
+
refreshMergeAction();
|
|
258
|
+
} }), hasModes && (jsx(TransactionModeSegmentedControl, { options: transactionModes, selectedId: selectedModeId, onChange: handleModeChange, disabled: isMerging })), mergeAction && (jsx("div", { className: 'send-balance-form__inline-action', children: jsx(Alert, { icon: 'error', variant: 'warning', children: jsxs("div", { className: 'send-balance-form__inline-action-content', children: [jsx(Typography, { variant: 'body_small', weight: 'regular', children: mergeAction.message }), jsx(TypographyButton, { dataTestId: 'sendBalanceFormMergeRecordsButton', type: 'button', buttonVariant: 'secondary', buttonPadding: 'small', onClick: handleMergeAction, disabled: isMerging, children: isMerging
|
|
259
|
+
? t('dyn_send_transaction.merging', 'Merging…')
|
|
260
|
+
: mergeAction.actionLabel })] }) }) })), jsx(TypographyButton, { dataTestId: 'sendBalanceFormSubmitButton', expanded: true, type: 'submit', buttonVariant: 'primary', buttonPadding: 'small', buttonClassName: 'send-balance-form__button', copykey: 'dyn_send_transaction.preview_transaction', disabled: !modeReady || isMerging || Boolean(mergeAction), children: t('dyn_send_transaction.preview_transaction') })] }));
|
|
201
261
|
} }));
|
|
202
262
|
};
|
|
203
263
|
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
5
|
+
|
|
6
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
7
|
+
var classNames = require('../../../utils/functions/classNames/classNames.cjs');
|
|
8
|
+
var Typography = require('../../Typography/Typography.cjs');
|
|
9
|
+
var icons = require('./icons.cjs');
|
|
10
|
+
|
|
11
|
+
const renderIcon = (icon) => {
|
|
12
|
+
if (icon === 'individual')
|
|
13
|
+
return jsxRuntime.jsx(icons.IndividualIcon, {});
|
|
14
|
+
if (icon === 'exchange')
|
|
15
|
+
return jsxRuntime.jsx(icons.ExchangeIcon, {});
|
|
16
|
+
return null;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Generic 2+ option segmented control rendered inside the SDK's send form
|
|
20
|
+
* when an `IUITransaction` exposes `transactionModes`. Aleo is the first
|
|
21
|
+
* caller (Individual / Exchange = private vs. public transfer); the
|
|
22
|
+
* component is intentionally chain-agnostic so any future chain can opt
|
|
23
|
+
* in by populating the same field on its UI transaction.
|
|
24
|
+
*/
|
|
25
|
+
const TransactionModeSegmentedControl = ({ options, selectedId, onChange, disabled = false }) => (jsxRuntime.jsx("div", { className: 'transaction-mode-segmented-control', role: 'radiogroup', "aria-label": 'Transaction mode', children: options.map((option) => {
|
|
26
|
+
const active = option.id === selectedId;
|
|
27
|
+
const isDisabled = disabled || option.disabled === true;
|
|
28
|
+
return (jsxRuntime.jsxs("button", { type: 'button', role: 'radio', "aria-checked": active, "aria-label": option.label, "aria-disabled": isDisabled, title: option.disabled && option.disabledReason
|
|
29
|
+
? option.disabledReason
|
|
30
|
+
: undefined, disabled: isDisabled, className: classNames.classNames('transaction-mode-segmented-control__option', {
|
|
31
|
+
'transaction-mode-segmented-control__option--active': active,
|
|
32
|
+
'transaction-mode-segmented-control__option--disabled': isDisabled,
|
|
33
|
+
}), onClick: () => {
|
|
34
|
+
if (!isDisabled && !active) {
|
|
35
|
+
onChange(option.id);
|
|
36
|
+
}
|
|
37
|
+
}, children: [option.icon && (jsxRuntime.jsx("span", { className: 'transaction-mode-segmented-control__option-icon', children: renderIcon(option.icon) })), jsxRuntime.jsx(Typography.Typography, { variant: 'body_small', weight: active ? 'bold' : 'regular', color: active ? 'primary' : 'secondary', children: option.label })] }, option.id));
|
|
38
|
+
}) }));
|
|
39
|
+
|
|
40
|
+
exports.TransactionModeSegmentedControl = TransactionModeSegmentedControl;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { FC } from 'react';
|
|
2
|
+
import { TransactionModeOption } from '@dynamic-labs/types';
|
|
3
|
+
export type TransactionModeSegmentedControlProps = {
|
|
4
|
+
options: TransactionModeOption[];
|
|
5
|
+
selectedId: string | undefined;
|
|
6
|
+
onChange: (modeId: string) => void;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Generic 2+ option segmented control rendered inside the SDK's send form
|
|
11
|
+
* when an `IUITransaction` exposes `transactionModes`. Aleo is the first
|
|
12
|
+
* caller (Individual / Exchange = private vs. public transfer); the
|
|
13
|
+
* component is intentionally chain-agnostic so any future chain can opt
|
|
14
|
+
* in by populating the same field on its UI transaction.
|
|
15
|
+
*/
|
|
16
|
+
export declare const TransactionModeSegmentedControl: FC<TransactionModeSegmentedControlProps>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
3
|
+
import { classNames } from '../../../utils/functions/classNames/classNames.js';
|
|
4
|
+
import { Typography } from '../../Typography/Typography.js';
|
|
5
|
+
import { IndividualIcon, ExchangeIcon } from './icons.js';
|
|
6
|
+
|
|
7
|
+
const renderIcon = (icon) => {
|
|
8
|
+
if (icon === 'individual')
|
|
9
|
+
return jsx(IndividualIcon, {});
|
|
10
|
+
if (icon === 'exchange')
|
|
11
|
+
return jsx(ExchangeIcon, {});
|
|
12
|
+
return null;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Generic 2+ option segmented control rendered inside the SDK's send form
|
|
16
|
+
* when an `IUITransaction` exposes `transactionModes`. Aleo is the first
|
|
17
|
+
* caller (Individual / Exchange = private vs. public transfer); the
|
|
18
|
+
* component is intentionally chain-agnostic so any future chain can opt
|
|
19
|
+
* in by populating the same field on its UI transaction.
|
|
20
|
+
*/
|
|
21
|
+
const TransactionModeSegmentedControl = ({ options, selectedId, onChange, disabled = false }) => (jsx("div", { className: 'transaction-mode-segmented-control', role: 'radiogroup', "aria-label": 'Transaction mode', children: options.map((option) => {
|
|
22
|
+
const active = option.id === selectedId;
|
|
23
|
+
const isDisabled = disabled || option.disabled === true;
|
|
24
|
+
return (jsxs("button", { type: 'button', role: 'radio', "aria-checked": active, "aria-label": option.label, "aria-disabled": isDisabled, title: option.disabled && option.disabledReason
|
|
25
|
+
? option.disabledReason
|
|
26
|
+
: undefined, disabled: isDisabled, className: classNames('transaction-mode-segmented-control__option', {
|
|
27
|
+
'transaction-mode-segmented-control__option--active': active,
|
|
28
|
+
'transaction-mode-segmented-control__option--disabled': isDisabled,
|
|
29
|
+
}), onClick: () => {
|
|
30
|
+
if (!isDisabled && !active) {
|
|
31
|
+
onChange(option.id);
|
|
32
|
+
}
|
|
33
|
+
}, children: [option.icon && (jsx("span", { className: 'transaction-mode-segmented-control__option-icon', children: renderIcon(option.icon) })), jsx(Typography, { variant: 'body_small', weight: active ? 'bold' : 'regular', color: active ? 'primary' : 'secondary', children: option.label })] }, option.id));
|
|
34
|
+
}) }));
|
|
35
|
+
|
|
36
|
+
export { TransactionModeSegmentedControl };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
5
|
+
|
|
6
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Inline SVG icons for the TransactionModeSegmentedControl. We deliberately
|
|
10
|
+
* inline these rather than depending on an icon set so the segmented
|
|
11
|
+
* control is self-contained and easy to drop into other widgets.
|
|
12
|
+
*/
|
|
13
|
+
const IndividualIcon = () => (jsxRuntime.jsxs("svg", { width: '16', height: '16', viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg', "aria-hidden": 'true', children: [jsxRuntime.jsx("circle", { cx: '8', cy: '5.5', r: '2.5', stroke: 'currentColor', strokeWidth: '1.25' }), jsxRuntime.jsx("path", { d: 'M3 13.5c.5-2.4 2.6-4 5-4s4.5 1.6 5 4', stroke: 'currentColor', strokeWidth: '1.25', strokeLinecap: 'round' })] }));
|
|
14
|
+
const ExchangeIcon = () => (jsxRuntime.jsxs("svg", { width: '16', height: '16', viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg', "aria-hidden": 'true', children: [jsxRuntime.jsx("path", { d: 'M2 6.5h12M3.5 6.5V13M12.5 6.5V13M2 13h12', stroke: 'currentColor', strokeWidth: '1.25', strokeLinecap: 'round' }), jsxRuntime.jsx("path", { d: 'M8 2L13 6.5H3L8 2Z', stroke: 'currentColor', strokeWidth: '1.25', strokeLinejoin: 'round' })] }));
|
|
15
|
+
|
|
16
|
+
exports.ExchangeIcon = ExchangeIcon;
|
|
17
|
+
exports.IndividualIcon = IndividualIcon;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
/**
|
|
3
|
+
* Inline SVG icons for the TransactionModeSegmentedControl. We deliberately
|
|
4
|
+
* inline these rather than depending on an icon set so the segmented
|
|
5
|
+
* control is self-contained and easy to drop into other widgets.
|
|
6
|
+
*/
|
|
7
|
+
export declare const IndividualIcon: () => JSX.Element;
|
|
8
|
+
export declare const ExchangeIcon: () => JSX.Element;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Inline SVG icons for the TransactionModeSegmentedControl. We deliberately
|
|
6
|
+
* inline these rather than depending on an icon set so the segmented
|
|
7
|
+
* control is self-contained and easy to drop into other widgets.
|
|
8
|
+
*/
|
|
9
|
+
const IndividualIcon = () => (jsxs("svg", { width: '16', height: '16', viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg', "aria-hidden": 'true', children: [jsx("circle", { cx: '8', cy: '5.5', r: '2.5', stroke: 'currentColor', strokeWidth: '1.25' }), jsx("path", { d: 'M3 13.5c.5-2.4 2.6-4 5-4s4.5 1.6 5 4', stroke: 'currentColor', strokeWidth: '1.25', strokeLinecap: 'round' })] }));
|
|
10
|
+
const ExchangeIcon = () => (jsxs("svg", { width: '16', height: '16', viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg', "aria-hidden": 'true', children: [jsx("path", { d: 'M2 6.5h12M3.5 6.5V13M12.5 6.5V13M2 13h12', stroke: 'currentColor', strokeWidth: '1.25', strokeLinecap: 'round' }), jsx("path", { d: 'M8 2L13 6.5H3L8 2Z', stroke: 'currentColor', strokeWidth: '1.25', strokeLinejoin: 'round' })] }));
|
|
11
|
+
|
|
12
|
+
export { ExchangeIcon, IndividualIcon };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { TransactionModeSegmentedControl, type TransactionModeSegmentedControlProps, } from './TransactionModeSegmentedControl';
|