@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.
Files changed (33) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/package.cjs +1 -1
  3. package/package.js +1 -1
  4. package/package.json +12 -12
  5. package/src/lib/components/SendBalanceForm/SendBalanceForm.cjs +63 -3
  6. package/src/lib/components/SendBalanceForm/SendBalanceForm.js +63 -3
  7. package/src/lib/components/SendBalanceForm/TransactionModeSegmentedControl/TransactionModeSegmentedControl.cjs +40 -0
  8. package/src/lib/components/SendBalanceForm/TransactionModeSegmentedControl/TransactionModeSegmentedControl.d.ts +16 -0
  9. package/src/lib/components/SendBalanceForm/TransactionModeSegmentedControl/TransactionModeSegmentedControl.js +36 -0
  10. package/src/lib/components/SendBalanceForm/TransactionModeSegmentedControl/icons.cjs +17 -0
  11. package/src/lib/components/SendBalanceForm/TransactionModeSegmentedControl/icons.d.ts +8 -0
  12. package/src/lib/components/SendBalanceForm/TransactionModeSegmentedControl/icons.js +12 -0
  13. package/src/lib/components/SendBalanceForm/TransactionModeSegmentedControl/index.d.ts +1 -0
  14. package/src/lib/styles/index.shadow.cjs +1 -1
  15. package/src/lib/styles/index.shadow.js +1 -1
  16. package/src/lib/utils/hooks/useAleoShieldedBalances/index.d.ts +1 -0
  17. package/src/lib/utils/hooks/useAleoShieldedBalances/useAleoShieldedBalances.cjs +372 -0
  18. package/src/lib/utils/hooks/useAleoShieldedBalances/useAleoShieldedBalances.d.ts +24 -0
  19. package/src/lib/utils/hooks/useAleoShieldedBalances/useAleoShieldedBalances.js +368 -0
  20. package/src/lib/utils/hooks/useEmbeddedWallet/useEmbeddedWallet.cjs +1 -0
  21. package/src/lib/utils/hooks/useEmbeddedWallet/useEmbeddedWallet.d.ts +1 -0
  22. package/src/lib/utils/hooks/useEmbeddedWallet/useEmbeddedWallet.js +1 -0
  23. package/src/lib/views/SendBalanceView/SendBalanceView.cjs +53 -0
  24. package/src/lib/views/SendBalanceView/SendBalanceView.js +53 -0
  25. package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/ActiveWalletBalance.cjs +191 -11
  26. package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/ActiveWalletBalance.js +191 -11
  27. package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/TokenBalanceItem/TokenBalanceItem.cjs +5 -2
  28. package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/TokenBalanceItem/TokenBalanceItem.d.ts +10 -1
  29. package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/TokenBalanceItem/TokenBalanceItem.js +5 -2
  30. package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/TokenBalanceItem/index.d.ts +1 -0
  31. package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/TokenBalanceList/TokenBalanceList.cjs +2 -2
  32. package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/TokenBalanceList/TokenBalanceList.d.ts +3 -1
  33. 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
@@ -3,7 +3,7 @@
3
3
 
4
4
  Object.defineProperty(exports, '__esModule', { value: true });
5
5
 
6
- var version = "4.80.0";
6
+ var version = "4.81.0";
7
7
  var dependencies = {
8
8
  "@dynamic-labs/sdk-api-core": "0.0.964",
9
9
  "@dynamic-labs-sdk/client": "0.26.9",
package/package.js CHANGED
@@ -1,5 +1,5 @@
1
1
  'use client'
2
- var version = "4.80.0";
2
+ var version = "4.81.0";
3
3
  var dependencies = {
4
4
  "@dynamic-labs/sdk-api-core": "0.0.964",
5
5
  "@dynamic-labs-sdk/client": "0.26.9",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dynamic-labs/sdk-react-core",
3
- "version": "4.80.0",
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.80.0",
20
- "@dynamic-labs/iconic": "4.80.0",
21
- "@dynamic-labs/locale": "4.80.0",
22
- "@dynamic-labs/logger": "4.80.0",
23
- "@dynamic-labs/multi-wallet": "4.80.0",
24
- "@dynamic-labs/rpc-providers": "4.80.0",
25
- "@dynamic-labs/store": "4.80.0",
26
- "@dynamic-labs/types": "4.80.0",
27
- "@dynamic-labs/utils": "4.80.0",
28
- "@dynamic-labs/wallet-book": "4.80.0",
29
- "@dynamic-labs/wallet-connector-core": "4.80.0",
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') }), 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', children: t('dyn_send_transaction.preview_transaction') })] }));
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') }), jsx(TypographyButton, { dataTestId: 'sendBalanceFormSubmitButton', expanded: true, type: 'submit', buttonVariant: 'primary', buttonPadding: 'small', buttonClassName: 'send-balance-form__button', copykey: 'dyn_send_transaction.preview_transaction', children: t('dyn_send_transaction.preview_transaction') })] }));
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';