diff --git a/.eslintrc.js b/.eslintrc.js
index 0b931dfd2ed..30248d7375c 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -30,6 +30,7 @@ module.exports = {
// methods, such as implicit use of signed transactions
'deprecation/deprecation': 'warn',
'no-console': ['error'],
+ 'no-duplicate-imports': ['error'],
'prefer-const': [
'error',
{
diff --git a/package.json b/package.json
index 742d2d76b83..8dea4cf12e7 100644
--- a/package.json
+++ b/package.json
@@ -251,14 +251,14 @@
"@sentry/webpack-plugin": "2.10.2",
"@stacks/connect-react": "22.2.0",
"@stacks/stacks-blockchain-api-types": "6.3.4",
- "@storybook/addon-essentials": "7.6.7",
- "@storybook/addon-interactions": "7.6.7",
- "@storybook/addon-links": "7.6.7",
+ "@storybook/addon-essentials": "7.6.10",
+ "@storybook/addon-interactions": "7.6.10",
+ "@storybook/addon-links": "7.6.10",
"@storybook/addon-onboarding": "1.0.10",
- "@storybook/blocks": "7.6.7",
- "@storybook/react": "7.6.7",
- "@storybook/react-webpack5": "7.6.7",
- "@storybook/test": "7.6.7",
+ "@storybook/blocks": "7.6.10",
+ "@storybook/react": "7.6.10",
+ "@storybook/react-webpack5": "7.6.10",
+ "@storybook/test": "7.6.10",
"@types/argon2-browser": "1.18.2",
"@types/chroma-js": "2.4.1",
"@types/chrome": "0.0.246",
@@ -319,7 +319,7 @@
"react-refresh": "0.14.0",
"schema-inspector": "2.0.2",
"speed-measure-webpack-plugin": "1.5.0",
- "storybook": "7.6.7",
+ "storybook": "7.6.10",
"stream-browserify": "3.0.0",
"svg-url-loader": "8.0.0",
"ts-node": "10.9.2",
diff --git a/src/app/common/account-restoration/legacy-gaia-config-lookup.ts b/src/app/common/account-restoration/legacy-gaia-config-lookup.ts
index 0736769f574..cd905ce1730 100644
--- a/src/app/common/account-restoration/legacy-gaia-config-lookup.ts
+++ b/src/app/common/account-restoration/legacy-gaia-config-lookup.ts
@@ -1,5 +1,9 @@
-import { fetchWalletConfig, generateWallet } from '@stacks/wallet-sdk';
-import { connectToGaiaHubWithConfig, getHubInfo } from '@stacks/wallet-sdk';
+import {
+ connectToGaiaHubWithConfig,
+ fetchWalletConfig,
+ generateWallet,
+ getHubInfo,
+} from '@stacks/wallet-sdk';
import { gaiaUrl as gaiaHubUrl } from '@shared/constants';
diff --git a/src/app/common/hooks/use-bitcoin-contracts.ts b/src/app/common/hooks/use-bitcoin-contracts.ts
index 88355b05eb5..8bec3e13ca6 100644
--- a/src/app/common/hooks/use-bitcoin-contracts.ts
+++ b/src/app/common/hooks/use-bitcoin-contracts.ts
@@ -11,8 +11,7 @@ import {
import { Money, createMoneyFromDecimal } from '@shared/models/money.model';
import { RouteUrls } from '@shared/route-urls';
import { BitcoinContractResponseStatus } from '@shared/rpc/methods/accept-bitcoin-contract';
-import { makeRpcSuccessResponse } from '@shared/rpc/rpc-methods';
-import { makeRpcErrorResponse } from '@shared/rpc/rpc-methods';
+import { makeRpcErrorResponse, makeRpcSuccessResponse } from '@shared/rpc/rpc-methods';
import { sendAcceptedBitcoinContractOfferToProtocolWallet } from '@app/query/bitcoin/contract/send-accepted-bitcoin-contract-offer';
import {
diff --git a/src/app/common/hooks/use-brc20-tokens.ts b/src/app/common/hooks/use-brc20-tokens.ts
new file mode 100644
index 00000000000..9e638d67e31
--- /dev/null
+++ b/src/app/common/hooks/use-brc20-tokens.ts
@@ -0,0 +1,11 @@
+import { useGetBrc20TokensQuery } from '@app/query/bitcoin/ordinals/brc20/brc20-tokens.query';
+
+export function useBrc20Tokens() {
+ const { data: allBrc20TokensResponse } = useGetBrc20TokensQuery();
+ const brc20Tokens = allBrc20TokensResponse?.pages
+ .flatMap(page => page.brc20Tokens)
+ .filter(token => token.length > 0)
+ .flatMap(token => token);
+
+ return brc20Tokens;
+}
diff --git a/src/app/common/hooks/use-event-listener.ts b/src/app/common/hooks/use-event-listener.ts
index d7a1c1bd48d..b50275a17c4 100644
--- a/src/app/common/hooks/use-event-listener.ts
+++ b/src/app/common/hooks/use-event-listener.ts
@@ -43,32 +43,32 @@ const isBrowser = checkIsBrowser();
*
* @param event the event name
* @param handler the event handler function to execute
- * @param doc the dom environment to execute against (defaults to `document`)
+ * @param element the dom environment to execute against (defaults to `document`)
* @param options the event listener options
*/
export function useEventListener(
event: keyof WindowEventMap,
handler: (event: any) => void,
- doc: Document | null = isBrowser ? document : null,
+ element: Document | null = isBrowser ? document : null,
options?: AddEventListener[2]
) {
const savedHandler = useLatestRef(handler);
useEffect(() => {
- if (!doc) return;
+ if (!element) return;
const listener = (event: any) => {
savedHandler.current(event);
};
- doc.addEventListener(event, listener, options);
+ element.addEventListener(event, listener, options);
return () => {
- doc.removeEventListener(event, listener, options);
+ element.removeEventListener(event, listener, options);
};
- }, [event, doc, options, savedHandler]);
+ }, [event, element, options, savedHandler]);
return () => {
- doc?.removeEventListener(event, savedHandler.current, options);
+ element?.removeEventListener(event, savedHandler.current, options);
};
}
diff --git a/src/app/common/theme-provider.tsx b/src/app/common/theme-provider.tsx
index fc4bb066f18..4a493699aa5 100644
--- a/src/app/common/theme-provider.tsx
+++ b/src/app/common/theme-provider.tsx
@@ -82,7 +82,7 @@ export function ThemeSwitcherProvider({ children }: ThemeSwitcherProviderProps)
return (
- {children}
+ {children}
);
diff --git a/src/app/common/transactions/bitcoin/coinselect/local-coin-selection.spec.ts b/src/app/common/transactions/bitcoin/coinselect/local-coin-selection.spec.ts
index e35f615f865..efe3f638dcb 100644
--- a/src/app/common/transactions/bitcoin/coinselect/local-coin-selection.spec.ts
+++ b/src/app/common/transactions/bitcoin/coinselect/local-coin-selection.spec.ts
@@ -34,7 +34,7 @@ describe(determineUtxosForSpend.name, () => {
describe('sorting algorithm (biggest first and no dust)', () => {
test('that it filters out dust utxos', () => {
const result = generate10kSpendWithTestData('tb1qt28eagxcl9gvhq2rpj5slg7dwgxae2dn2hk93m');
- const hasDust = result.orderedUtxos.some(utxo => utxo.value <= BTC_P2WPKH_DUST_AMOUNT);
+ const hasDust = result.filteredUtxos.some(utxo => utxo.value <= BTC_P2WPKH_DUST_AMOUNT);
expect(hasDust).toBeFalsy();
});
diff --git a/src/app/common/transactions/bitcoin/coinselect/local-coin-selection.ts b/src/app/common/transactions/bitcoin/coinselect/local-coin-selection.ts
index cdbe309d93f..ade9b348719 100644
--- a/src/app/common/transactions/bitcoin/coinselect/local-coin-selection.ts
+++ b/src/app/common/transactions/bitcoin/coinselect/local-coin-selection.ts
@@ -1,10 +1,8 @@
-import { getAddressInfo, validate } from 'bitcoin-address-validation';
-
-import { BTC_P2WPKH_DUST_AMOUNT } from '@shared/constants';
+import { validate } from 'bitcoin-address-validation';
import { UtxoResponseItem } from '@app/query/bitcoin/bitcoin-client';
-import { BtcSizeFeeEstimator } from '../fees/btc-size-fee-estimator';
+import { filterUneconomicalUtxos, getSizeInfo } from '../utils';
export interface DetermineUtxosForSpendArgs {
amount: number;
@@ -20,17 +18,12 @@ export function determineUtxosForSpendAll({
utxos,
}: DetermineUtxosForSpendArgs) {
if (!validate(recipient)) throw new Error('Cannot calculate spend of invalid address type');
+ const filteredUtxos = filterUneconomicalUtxos({ utxos, feeRate, address: recipient });
- const addressInfo = getAddressInfo(recipient);
-
- const txSizer = new BtcSizeFeeEstimator();
-
- const filteredUtxos = utxos.filter(utxo => utxo.value >= BTC_P2WPKH_DUST_AMOUNT);
-
- const sizeInfo = txSizer.calcTxSize({
- input_script: 'p2wpkh',
- input_count: filteredUtxos.length,
- [addressInfo.type + '_output_count']: 1,
+ const sizeInfo = getSizeInfo({
+ inputLength: filteredUtxos.length,
+ outputLength: 1,
+ recipient,
});
// Fee has already been deducted from the amount with send all
@@ -54,25 +47,23 @@ export function determineUtxosForSpend({
}: DetermineUtxosForSpendArgs) {
if (!validate(recipient)) throw new Error('Cannot calculate spend of invalid address type');
- const addressInfo = getAddressInfo(recipient);
-
- const orderedUtxos = utxos
- .filter(utxo => utxo.value >= BTC_P2WPKH_DUST_AMOUNT)
- .sort((a, b) => b.value - a.value);
+ const orderedUtxos = utxos.sort((a, b) => b.value - a.value);
- const txSizer = new BtcSizeFeeEstimator();
+ const filteredUtxos = filterUneconomicalUtxos({
+ utxos: orderedUtxos,
+ feeRate,
+ address: recipient,
+ });
const neededUtxos = [];
let sum = 0n;
let sizeInfo = null;
- for (const utxo of orderedUtxos) {
- sizeInfo = txSizer.calcTxSize({
- // Only p2wpkh is supported by the wallet
- input_script: 'p2wpkh',
- input_count: neededUtxos.length,
- // From the address of the recipient, we infer the output type
- [addressInfo.type + '_output_count']: 2,
+ for (const utxo of filteredUtxos) {
+ sizeInfo = getSizeInfo({
+ inputLength: neededUtxos.length,
+ outputLength: 2,
+ recipient,
});
if (sum >= BigInt(amount) + BigInt(Math.ceil(sizeInfo.txVBytes * feeRate))) break;
@@ -92,7 +83,7 @@ export function determineUtxosForSpend({
];
return {
- orderedUtxos,
+ filteredUtxos,
inputs: neededUtxos,
outputs,
size: sizeInfo.txVBytes,
diff --git a/src/app/common/transactions/bitcoin/fees/bitcoin-fees.spec.ts b/src/app/common/transactions/bitcoin/fees/bitcoin-fees.spec.ts
new file mode 100644
index 00000000000..4e28ccdbde9
--- /dev/null
+++ b/src/app/common/transactions/bitcoin/fees/bitcoin-fees.spec.ts
@@ -0,0 +1,143 @@
+import BigNumber from 'bignumber.js';
+import { sha256 } from 'bitcoinjs-lib/src/crypto';
+
+import { UtxoResponseItem } from '@app/query/bitcoin/bitcoin-client';
+
+import { filterUneconomicalUtxos } from '../utils';
+import { calculateMaxBitcoinSpend } from './calculate-max-bitcoin-spend';
+
+function generateTxId(value: number): UtxoResponseItem {
+ const buffer = Buffer.from(Math.random().toString());
+ return {
+ txid: sha256(sha256(buffer)).toString(),
+ vout: 0,
+ status: {
+ confirmed: true,
+ block_height: 2568495,
+ block_hash: '000000000000008622fafce4a5388861b252d534f819d0f7cb5d4f2c5f9c1638',
+ block_time: 1703787327,
+ },
+ value,
+ };
+}
+
+function generateTransactions(values: number[]) {
+ return values.map(val => generateTxId(val));
+}
+
+function generateAverageFee(value: number) {
+ return {
+ hourFee: BigNumber(value / 2),
+ halfHourFee: BigNumber(value),
+ fastestFee: BigNumber(value * 2),
+ };
+}
+
+describe(calculateMaxBitcoinSpend.name, () => {
+ const utxos = generateTransactions([600, 600, 1200, 1200, 10000, 10000, 25000, 40000, 50000000]);
+
+ test('with 1 sat/vb fee', () => {
+ const fee = 1;
+ const maxBitcoinSpend = calculateMaxBitcoinSpend({
+ address: '',
+ utxos,
+ fetchedFeeRates: generateAverageFee(fee),
+ });
+ expect(maxBitcoinSpend.amount.amount.toNumber()).toEqual(50087948);
+ });
+
+ test('with 5 sat/vb fee', () => {
+ const fee = 5;
+ const maxBitcoinSpend = calculateMaxBitcoinSpend({
+ address: '',
+ utxos,
+ fetchedFeeRates: generateAverageFee(fee),
+ });
+ expect(maxBitcoinSpend.amount.amount.toNumber()).toEqual(50085342);
+ });
+
+ test('with 30 sat/vb fee', () => {
+ const fee = 30;
+ const maxBitcoinSpend = calculateMaxBitcoinSpend({
+ address: '',
+ utxos,
+ fetchedFeeRates: generateAverageFee(fee),
+ });
+ expect(maxBitcoinSpend.amount.amount.toNumber()).toEqual(50073585);
+ });
+
+ test('with 100 sat/vb fee', () => {
+ const fee = 100;
+ const maxBitcoinSpend = calculateMaxBitcoinSpend({
+ address: '',
+ utxos,
+ fetchedFeeRates: generateAverageFee(fee),
+ });
+ expect(maxBitcoinSpend.amount.amount.toNumber()).toEqual(50046950);
+ });
+
+ test('with 400 sat/vb fee', () => {
+ const fee = 400;
+ const maxBitcoinSpend = calculateMaxBitcoinSpend({
+ address: '',
+ utxos,
+ fetchedFeeRates: generateAverageFee(fee),
+ });
+ expect(maxBitcoinSpend.amount.amount.toNumber()).toEqual(49969100);
+ });
+});
+
+describe(filterUneconomicalUtxos.name, () => {
+ const utxos = generateTransactions([600, 600, 1200, 1200, 10000, 10000, 25000, 40000, 50000000]);
+
+ test('with 1 sat/vb fee', () => {
+ const fee = 1;
+ const filteredUtxos = filterUneconomicalUtxos({
+ address: '',
+ utxos,
+ feeRate: fee,
+ });
+
+ expect(filteredUtxos.length).toEqual(9);
+ });
+
+ test('with 10 sat/vb fee', () => {
+ const fee = 10;
+ const filteredUtxos = filterUneconomicalUtxos({
+ address: '',
+ utxos,
+ feeRate: fee,
+ });
+ expect(filteredUtxos.length).toEqual(7);
+ });
+
+ test('with 30 sat/vb fee', () => {
+ const fee = 30;
+ const filteredUtxos = filterUneconomicalUtxos({
+ address: '',
+ utxos,
+ feeRate: fee,
+ });
+ expect(filteredUtxos.length).toEqual(5);
+ });
+
+ test('with 200 sat/vb fee', () => {
+ const fee = 200;
+ const filteredUtxos = filterUneconomicalUtxos({
+ address: '',
+ utxos,
+ feeRate: fee,
+ });
+ expect(filteredUtxos.length).toEqual(3);
+ });
+
+ test('with 400 sat/vb fee', () => {
+ const fee = 400;
+ const filteredUtxos = filterUneconomicalUtxos({
+ address: '',
+ utxos,
+ feeRate: fee,
+ });
+ expect(filteredUtxos.length).toEqual(2);
+ });
+});
diff --git a/src/app/common/transactions/bitcoin/fees/btc-size-fee-estimator.ts b/src/app/common/transactions/bitcoin/fees/btc-size-fee-estimator.ts
index 2b4d4cf06fc..ecbe796f1d3 100644
--- a/src/app/common/transactions/bitcoin/fees/btc-size-fee-estimator.ts
+++ b/src/app/common/transactions/bitcoin/fees/btc-size-fee-estimator.ts
@@ -10,7 +10,7 @@ type InputScriptTypes =
| 'p2wsh'
| 'p2tr';
-interface Params {
+interface TxSizerParams {
input_count: number;
input_script: InputScriptTypes;
input_m: number;
@@ -48,7 +48,7 @@ export class BtcSizeFeeEstimator {
'p2tr',
];
- defaultParams: Params = {
+ defaultParams: TxSizerParams = {
input_count: 0,
input_script: 'p2wpkh',
input_m: 0,
@@ -62,7 +62,7 @@ export class BtcSizeFeeEstimator {
p2tr_output_count: 0,
};
- params: Params = { ...this.defaultParams };
+ params: TxSizerParams = { ...this.defaultParams };
getSizeOfScriptLengthElement(length: number) {
if (length < 75) {
@@ -128,7 +128,7 @@ export class BtcSizeFeeEstimator {
return witness_vbytes * 3;
}
- prepareParams(opts: Partial) {
+ prepareParams(opts: Partial) {
// Verify opts and set them to this.params
opts = opts || Object.assign(this.defaultParams);
@@ -279,7 +279,7 @@ export class BtcSizeFeeEstimator {
};
}
- calcTxSize(opts: Partial) {
+ calcTxSize(opts: Partial) {
this.prepareParams(opts);
const output_count = this.getOutputCount();
const { inputSize, inputWitnessSize } = this.getSizeBasedOnInputType();
diff --git a/src/app/common/transactions/bitcoin/fees/calculate-max-bitcoin-spend.ts b/src/app/common/transactions/bitcoin/fees/calculate-max-bitcoin-spend.ts
new file mode 100644
index 00000000000..c5e38813c09
--- /dev/null
+++ b/src/app/common/transactions/bitcoin/fees/calculate-max-bitcoin-spend.ts
@@ -0,0 +1,50 @@
+import BigNumber from 'bignumber.js';
+
+import { AverageBitcoinFeeRates } from '@shared/models/fees/bitcoin-fees.model';
+import { createMoney } from '@shared/models/money.model';
+
+import { satToBtc } from '@app/common/money/unit-conversion';
+import { UtxoResponseItem } from '@app/query/bitcoin/bitcoin-client';
+
+import { filterUneconomicalUtxos, getSpendableAmount } from '../utils';
+
+interface CalculateMaxBitcoinSpend {
+ address: string;
+ utxos: UtxoResponseItem[];
+ fetchedFeeRates?: AverageBitcoinFeeRates;
+ feeRate?: number;
+}
+
+export function calculateMaxBitcoinSpend({
+ address,
+ utxos,
+ feeRate,
+ fetchedFeeRates,
+}: CalculateMaxBitcoinSpend) {
+ if (!utxos.length || !fetchedFeeRates)
+ return {
+ spendAllFee: 0,
+ amount: createMoney(0, 'BTC'),
+ spendableBitcoin: new BigNumber(0),
+ };
+
+ const currentFeeRate = feeRate ?? fetchedFeeRates.halfHourFee.toNumber();
+
+ const filteredUtxos = filterUneconomicalUtxos({
+ utxos,
+ feeRate: currentFeeRate,
+ address,
+ });
+
+ const { spendableAmount, fee } = getSpendableAmount({
+ utxos: filteredUtxos,
+ feeRate: currentFeeRate,
+ address,
+ });
+
+ return {
+ spendAllFee: fee,
+ amount: createMoney(spendableAmount, 'BTC'),
+ spendableBitcoin: satToBtc(spendableAmount),
+ };
+}
diff --git a/src/app/common/transactions/bitcoin/utils.ts b/src/app/common/transactions/bitcoin/utils.ts
index 6730c435990..b4df0aab8f2 100644
--- a/src/app/common/transactions/bitcoin/utils.ts
+++ b/src/app/common/transactions/bitcoin/utils.ts
@@ -1,10 +1,15 @@
-import { getAddressInfo } from 'bitcoin-address-validation';
+import BigNumber from 'bignumber.js';
+import { getAddressInfo, validate } from 'bitcoin-address-validation';
-import { BitcoinTransactionVectorOutput } from '@shared/models/transactions/bitcoin-transaction.model';
-import { BitcoinTx } from '@shared/models/transactions/bitcoin-transaction.model';
+import { BTC_P2WPKH_DUST_AMOUNT } from '@shared/constants';
+import {
+ BitcoinTransactionVectorOutput,
+ BitcoinTx,
+} from '@shared/models/transactions/bitcoin-transaction.model';
import { sumNumbers } from '@app/common/math/helpers';
import { satToBtc } from '@app/common/money/unit-conversion';
+import { UtxoResponseItem } from '@app/query/bitcoin/bitcoin-client';
import { truncateMiddle } from '@app/ui/utils/truncate-middle';
import { BtcSizeFeeEstimator } from './fees/btc-size-fee-estimator';
@@ -12,14 +17,71 @@ import { BtcSizeFeeEstimator } from './fees/btc-size-fee-estimator';
export function containsTaprootInput(tx: BitcoinTx) {
return tx.vin.some(input => input.prevout.scriptpubkey_type === 'v1_p2tr');
}
+export function getSpendableAmount({
+ utxos,
+ feeRate,
+ address,
+}: {
+ utxos: UtxoResponseItem[];
+ feeRate: number;
+ address: string;
+}) {
+ const balance = utxos.map(utxo => utxo.value).reduce((prevVal, curVal) => prevVal + curVal, 0);
+
+ const size = getSizeInfo({
+ inputLength: utxos.length,
+ outputLength: 1,
+ recipient: address,
+ });
+ const fee = Math.ceil(size.txVBytes * feeRate);
+ const bigNumberBalance = BigNumber(balance);
+ return {
+ spendableAmount: BigNumber.max(0, bigNumberBalance.minus(fee)),
+ fee,
+ };
+}
+
+// Check if the spendable amount drops when adding a utxo. If it drops, don't use that utxo.
+// Method might be not particularly efficient as it would
+// go through the utxo array multiple times, but it's reliable.
+export function filterUneconomicalUtxos({
+ utxos,
+ feeRate,
+ address,
+}: {
+ utxos: UtxoResponseItem[];
+ feeRate: number;
+ address: string;
+}) {
+ const { spendableAmount: fullSpendableAmount } = getSpendableAmount({
+ utxos,
+ feeRate,
+ address,
+ });
+
+ const filteredUtxos = utxos
+ .filter(utxo => utxo.value >= BTC_P2WPKH_DUST_AMOUNT)
+ .filter(utxo => {
+ // calculate spendableAmount without that utxo.
+ const { spendableAmount } = getSpendableAmount({
+ utxos: utxos.filter(u => u.txid !== utxo.txid),
+ feeRate,
+ address,
+ });
+ // if spendable amount becomes bigger, do not use that utxo
+ return spendableAmount.toNumber() < fullSpendableAmount.toNumber();
+ });
+ return filteredUtxos;
+}
export function getSizeInfo(payload: {
inputLength: number;
- recipient: string;
outputLength: number;
+ recipient: string;
}) {
const { inputLength, recipient, outputLength } = payload;
- const addressInfo = getAddressInfo(recipient);
+ const addressInfo = validate(recipient) ? getAddressInfo(recipient) : null;
+ const outputAddressTypeWithFallback = addressInfo ? addressInfo.type : 'p2wpkh';
const txSizer = new BtcSizeFeeEstimator();
const sizeInfo = txSizer.calcTxSize({
@@ -27,7 +89,7 @@ export function getSizeInfo(payload: {
input_script: 'p2wpkh',
input_count: inputLength,
// From the address of the recipient, we infer the output type
- [addressInfo.type + '_output_count']: outputLength,
+ [outputAddressTypeWithFallback + '_output_count']: outputLength,
});
return sizeInfo;
diff --git a/src/app/common/utils.spec.ts b/src/app/common/utils.spec.ts
index 95c25e720f8..91c033e7105 100644
--- a/src/app/common/utils.spec.ts
+++ b/src/app/common/utils.spec.ts
@@ -1,5 +1,4 @@
-import { getTicker } from '@app/common/utils';
-import { extractPhraseFromString } from '@app/common/utils';
+import { extractPhraseFromString, getTicker } from '@app/common/utils';
import { countDecimals } from './math/helpers';
diff --git a/src/app/common/utils.ts b/src/app/common/utils.ts
index 51ff3d352e1..8f7e1235e56 100644
--- a/src/app/common/utils.ts
+++ b/src/app/common/utils.ts
@@ -8,6 +8,7 @@ import {
import { toUnicode } from 'punycode';
import { BitcoinChainConfig, BitcoinNetworkModes, KEBAB_REGEX } from '@shared/constants';
+import { isBoolean } from '@shared/utils';
export function createNullArrayOfLength(length: number) {
return new Array(length).fill(null);
@@ -314,3 +315,7 @@ export function removeTrailingNullCharacters(s: string) {
export function removeMinusSign(value: string) {
return value.replace('-', '');
}
+
+export function propIfDefined(prop: string, value: any) {
+ return isBoolean(value) ? { [prop]: value } : {};
+}
diff --git a/src/app/components/account/account-list-item-layout.tsx b/src/app/components/account/account-list-item-layout.tsx
index 91aae1cba45..5fde1bb6215 100644
--- a/src/app/components/account/account-list-item-layout.tsx
+++ b/src/app/components/account/account-list-item-layout.tsx
@@ -2,11 +2,11 @@ import { SettingsSelectors } from '@tests/selectors/settings.selectors';
import { Flex, HStack, Stack, StackProps, styled } from 'leather-styles/jsx';
import { useViewportMinWidth } from '@app/common/hooks/use-media-query';
+import { BulletSeparator } from '@app/ui/components/bullet-separator/bullet-separator';
import { CheckmarkIcon } from '@app/ui/components/icons/checkmark-icon';
import { Spinner } from '@app/ui/components/spinner';
import { truncateMiddle } from '@app/ui/utils/truncate-middle';
-import { CaptionDotSeparator } from '../caption-dot-separator';
import { Flag } from '../layout/flag';
import { StacksAccountLoader } from '../loaders/stacks-account-loader';
import { BitcoinNativeSegwitAccountLoader } from './bitcoin-account-loader';
@@ -65,7 +65,7 @@ export function AccountListItemLayout(props: AccountListItemLayoutProps) {
)}
-
+
{account => (
@@ -81,7 +81,7 @@ export function AccountListItemLayout(props: AccountListItemLayoutProps) {
)}
-
+
diff --git a/src/app/components/app-version.tsx b/src/app/components/app-version.tsx
index 442e4b24a35..c67990f8ffe 100644
--- a/src/app/components/app-version.tsx
+++ b/src/app/components/app-version.tsx
@@ -1,5 +1,4 @@
-import { useMemo } from 'react';
-import { forwardRef } from 'react';
+import { forwardRef, useMemo } from 'react';
import { HTMLStyledProps, styled } from 'leather-styles/jsx';
diff --git a/src/app/components/bitcoin-transaction-item/bitcoin-transaction-item.tsx b/src/app/components/bitcoin-transaction-item/bitcoin-transaction-item.tsx
index 432bdc35320..227990cc93f 100644
--- a/src/app/components/bitcoin-transaction-item/bitcoin-transaction-item.tsx
+++ b/src/app/components/bitcoin-transaction-item/bitcoin-transaction-item.tsx
@@ -24,9 +24,9 @@ import {
} from '@app/query/bitcoin/ordinals/inscription.hooks';
import { useGetInscriptionsByOutputQuery } from '@app/query/bitcoin/ordinals/inscriptions-by-param.query';
import { useCurrentAccountNativeSegwitAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
+import { BulletSeparator } from '@app/ui/components/bullet-separator/bullet-separator';
import { BtcIcon } from '@app/ui/components/icons/btc-icon';
-import { CaptionDotSeparator } from '../caption-dot-separator';
import { TransactionItemLayout } from '../transaction-item/transaction-item.layout';
import { BitcoinTransactionCaption } from './bitcoin-transaction-caption';
import { BitcoinTransactionIcon } from './bitcoin-transaction-icon';
@@ -79,12 +79,12 @@ export function BitcoinTransactionItem({ transaction, ...rest }: BitcoinTransact
isOriginator && !transaction.status.confirmed && !containsTaprootInput(transaction);
const txCaption = (
-
+
{caption}
{inscriptionData ? (
{inscriptionData.mime_type}
) : null}
-
+
);
const txValue = {value};
diff --git a/src/app/components/brc20-tokens-loader.tsx b/src/app/components/brc20-tokens-loader.tsx
index 042559d4670..373467bcaa6 100644
--- a/src/app/components/brc20-tokens-loader.tsx
+++ b/src/app/components/brc20-tokens-loader.tsx
@@ -1,17 +1,12 @@
-import {
- Brc20Token,
- useGetBrc20TokensQuery,
-} from '@app/query/bitcoin/ordinals/brc20/brc20-tokens.query';
+import { useBrc20Tokens } from '@app/common/hooks/use-brc20-tokens';
+import { Brc20Token } from '@app/query/bitcoin/ordinals/brc20/brc20-tokens.query';
interface Brc20TokensLoaderProps {
children(brc20Tokens: Brc20Token[]): React.JSX.Element;
}
+
export function Brc20TokensLoader({ children }: Brc20TokensLoaderProps) {
- const { data: allBrc20TokensResponse } = useGetBrc20TokensQuery();
- const brc20Tokens = allBrc20TokensResponse?.pages
- .flatMap(page => page.brc20Tokens)
- .filter(token => token.length > 0)
- .flatMap(token => token);
+ const brc20Tokens = useBrc20Tokens();
if (!brc20Tokens) return null;
return children(brc20Tokens);
diff --git a/src/app/components/caption-dot-separator.tsx b/src/app/components/caption-dot-separator.tsx
deleted file mode 100644
index f7a27864bdc..00000000000
--- a/src/app/components/caption-dot-separator.tsx
+++ /dev/null
@@ -1,26 +0,0 @@
-import { cloneElement, isValidElement } from 'react';
-
-import { BoxProps, styled } from 'leather-styles/jsx';
-
-function CaptionSeparatorDot(props: BoxProps) {
- return (
-
- •
-
- );
-}
-
-interface CaptionDotSeparatorProps {
- children: React.ReactNode;
-}
-export function CaptionDotSeparator({ children }: CaptionDotSeparatorProps) {
- const parsedChildren = Array.isArray(children) ? children : [children];
- const content = parsedChildren
- .flatMap((child, index) => {
- if (!isValidElement(child)) return null;
- return [cloneElement(child, { key: index }), ];
- })
- .filter(val => val !== null)
- .slice(0, -1);
- return <>{content}>;
-}
diff --git a/src/app/components/crypto-assets/bitcoin/brc20-token-asset-list/brc20-token-asset-list.tsx b/src/app/components/crypto-assets/bitcoin/brc20-token-asset-list/brc20-token-asset-list.tsx
index 7667d5b29aa..5bd77800863 100644
--- a/src/app/components/crypto-assets/bitcoin/brc20-token-asset-list/brc20-token-asset-list.tsx
+++ b/src/app/components/crypto-assets/bitcoin/brc20-token-asset-list/brc20-token-asset-list.tsx
@@ -7,9 +7,6 @@ import { Brc20TokenAssetItem } from '@app/components/crypto-assets/bitcoin/brc20
import { useNativeSegwitBalance } from '@app/query/bitcoin/balance/btc-native-segwit-balance.hooks';
import { Brc20Token } from '@app/query/bitcoin/ordinals/brc20/brc20-tokens.query';
import { useCurrentAccountNativeSegwitAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
-import { BasicTooltip } from '@app/ui/components/tooltip/basic-tooltip';
-
-import { Brc20AssetListLayout } from './components/brc20-token-asset-list.layout';
export function Brc20TokenAssetList(props: { brc20Tokens?: Brc20Token[] }) {
const navigate = useNavigate();
@@ -27,23 +24,13 @@ export function Brc20TokenAssetList(props: { brc20Tokens?: Brc20Token[] }) {
}
if (!props.brc20Tokens?.length) return null;
-
- return (
-
- {props.brc20Tokens?.map(token => (
-
- navigateToBrc20SendForm(token) : noop}
- />
-
- ))}
-
- );
+ return props.brc20Tokens.map(token => (
+ navigateToBrc20SendForm(token) : noop}
+ displayNotEnoughBalance={!hasPositiveBtcBalanceForFees}
+ key={token.tick}
+ />
+ ));
}
diff --git a/src/app/components/crypto-assets/bitcoin/brc20-token-asset-list/components/brc20-token-asset-item.layout.tsx b/src/app/components/crypto-assets/bitcoin/brc20-token-asset-list/components/brc20-token-asset-item.layout.tsx
index 2b9946fb0dd..0e9223ec493 100644
--- a/src/app/components/crypto-assets/bitcoin/brc20-token-asset-list/components/brc20-token-asset-item.layout.tsx
+++ b/src/app/components/crypto-assets/bitcoin/brc20-token-asset-list/components/brc20-token-asset-item.layout.tsx
@@ -15,6 +15,7 @@ interface Brc20TokenAssetItemLayoutProps extends BoxProps {
isPressable?: boolean;
onClick?(): void;
title: string;
+ displayNotEnoughBalance?: boolean;
}
export function Brc20TokenAssetItemLayout({
balance,
@@ -22,39 +23,47 @@ export function Brc20TokenAssetItemLayout({
isPressable,
onClick,
title,
+ displayNotEnoughBalance,
}: Brc20TokenAssetItemLayoutProps) {
const [component, bind] = usePressable(isPressable);
const formattedBalance = formatBalance(balance.amount.toString());
return (
-
- } spacing="space.04" width="100%">
-
-
- {title}
-
-
-
- {formattedBalance.value}
+
+
+ } spacing="space.04" width="100%">
+
+
+ {title}
-
-
-
-
-
- {component}
-
-
+
+
+ {formattedBalance.value}
+
+
+
+
+
+
+ {component}
+
+
+
);
}
diff --git a/src/app/components/crypto-assets/bitcoin/brc20-token-asset-list/components/brc20-token-asset-item.tsx b/src/app/components/crypto-assets/bitcoin/brc20-token-asset-list/components/brc20-token-asset-item.tsx
index 131566227ba..29820b11099 100644
--- a/src/app/components/crypto-assets/bitcoin/brc20-token-asset-list/components/brc20-token-asset-item.tsx
+++ b/src/app/components/crypto-assets/bitcoin/brc20-token-asset-list/components/brc20-token-asset-item.tsx
@@ -8,8 +8,14 @@ interface Brc20TokenAssetItemProps {
token: Brc20Token;
isPressable?: boolean;
onClick?(): void;
+ displayNotEnoughBalance?: boolean;
}
-export function Brc20TokenAssetItem({ token, isPressable, onClick }: Brc20TokenAssetItemProps) {
+export function Brc20TokenAssetItem({
+ token,
+ isPressable,
+ onClick,
+ displayNotEnoughBalance,
+}: Brc20TokenAssetItemProps) {
return (
);
}
diff --git a/src/app/components/crypto-assets/bitcoin/brc20-token-asset-list/components/brc20-token-asset-list.layout.tsx b/src/app/components/crypto-assets/bitcoin/brc20-token-asset-list/components/brc20-token-asset-list.layout.tsx
deleted file mode 100644
index bf306441449..00000000000
--- a/src/app/components/crypto-assets/bitcoin/brc20-token-asset-list/components/brc20-token-asset-list.layout.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import { CryptoAssetSelectors } from '@tests/selectors/crypto-asset.selectors';
-import { Stack, StackProps } from 'leather-styles/jsx';
-
-export function Brc20AssetListLayout({ children }: StackProps) {
- return (
-
- {children}
-
- );
-}
diff --git a/src/app/components/crypto-assets/choose-crypto-asset/crypto-asset-list.tsx b/src/app/components/crypto-assets/choose-crypto-asset/crypto-asset-list.tsx
index a3d019aaf6e..48dbaac5e9d 100644
--- a/src/app/components/crypto-assets/choose-crypto-asset/crypto-asset-list.tsx
+++ b/src/app/components/crypto-assets/choose-crypto-asset/crypto-asset-list.tsx
@@ -1,14 +1,25 @@
import type { AllTransferableCryptoAssetBalances } from '@shared/models/crypto-asset-balance.model';
import { StacksFungibleTokenAsset } from '@shared/models/crypto-asset.model';
+import { useWalletType } from '@app/common/use-wallet-type';
+import { Brc20TokenAssetList } from '@app/components/crypto-assets/bitcoin/brc20-token-asset-list/brc20-token-asset-list';
+import { Brc20Token } from '@app/query/bitcoin/ordinals/brc20/brc20-tokens.query';
+
import { CryptoAssetListItem } from './crypto-asset-list-item';
import { CryptoAssetListLayout } from './crypto-asset-list.layout';
interface CryptoAssetListProps {
cryptoAssetBalances: AllTransferableCryptoAssetBalances[];
onItemClick(cryptoAssetBalance: AllTransferableCryptoAssetBalances): void;
+ brc20Tokens?: Brc20Token[];
}
-export function CryptoAssetList({ cryptoAssetBalances, onItemClick }: CryptoAssetListProps) {
+export function CryptoAssetList({
+ cryptoAssetBalances,
+ onItemClick,
+ brc20Tokens,
+}: CryptoAssetListProps) {
+ const { whenWallet } = useWalletType();
+
return (
{cryptoAssetBalances.map(cryptoAssetBalance => (
@@ -21,6 +32,12 @@ export function CryptoAssetList({ cryptoAssetBalances, onItemClick }: CryptoAsse
}
/>
))}
+ {brc20Tokens
+ ? whenWallet({
+ software: ,
+ ledger: null,
+ })
+ : null}
);
}
diff --git a/src/app/components/crypto-assets/components/asset-caption.tsx b/src/app/components/crypto-assets/components/asset-caption.tsx
index d0ff9b5caa0..25116dfecf0 100644
--- a/src/app/components/crypto-assets/components/asset-caption.tsx
+++ b/src/app/components/crypto-assets/components/asset-caption.tsx
@@ -1,5 +1,6 @@
import { Flex, HStack, styled } from 'leather-styles/jsx';
+import { BulletOperator } from '@app/ui/components/bullet-separator/bullet-separator';
import { InfoIcon } from '@app/ui/components/icons/info-icon';
import { BasicTooltip } from '@app/ui/components/tooltip/basic-tooltip';
@@ -14,7 +15,7 @@ export function AssetCaption({ caption, isUnanchored }: AssetCaptionProps) {
{isUnanchored ? (
<>
- • Microblock
+ Microblock
diff --git a/src/app/components/crypto-assets/components/asset-row-grid.tsx b/src/app/components/crypto-assets/components/asset-row-grid.tsx
index 50abc1384ac..3508934ab32 100644
--- a/src/app/components/crypto-assets/components/asset-row-grid.tsx
+++ b/src/app/components/crypto-assets/components/asset-row-grid.tsx
@@ -22,7 +22,13 @@ export function AssetRowGrid({
{balance}
);
return (
-
+
{title}
diff --git a/src/app/components/crypto-assets/crypto-currency-asset/crypto-currency-asset-item.layout.tsx b/src/app/components/crypto-assets/crypto-currency-asset/crypto-currency-asset-item.layout.tsx
index ff8086c2ff0..bf4a65215d5 100644
--- a/src/app/components/crypto-assets/crypto-currency-asset/crypto-currency-asset-item.layout.tsx
+++ b/src/app/components/crypto-assets/crypto-currency-asset/crypto-currency-asset-item.layout.tsx
@@ -1,6 +1,5 @@
import { CryptoAssetSelectors } from '@tests/selectors/crypto-asset.selectors';
-import { Flex } from 'leather-styles/jsx';
-import { styled } from 'leather-styles/jsx';
+import { Flex, styled } from 'leather-styles/jsx';
import { CryptoCurrencies } from '@shared/models/currencies.model';
import { Money } from '@shared/models/money.model';
@@ -80,11 +79,17 @@ export function CryptoCurrencyAssetItemLayout({
}
- caption={{caption}}
+ caption={
+
+ {caption}
+
+ }
usdBalance={
{balance.amount.toNumber() > 0 && address ? (
- {usdBalance}
+
+ {usdBalance}
+
) : null}
{additionalUsdBalanceInfo}
diff --git a/src/app/components/fees-row/components/fees-row.layout.tsx b/src/app/components/fees-row/components/fees-row.layout.tsx
index 9c60f48c63a..0a63fb8ccf5 100644
--- a/src/app/components/fees-row/components/fees-row.layout.tsx
+++ b/src/app/components/fees-row/components/fees-row.layout.tsx
@@ -1,6 +1,5 @@
import { useField } from 'formik';
-import { HstackProps, styled } from 'leather-styles/jsx';
-import { HStack } from 'leather-styles/jsx';
+import { HStack, HstackProps, styled } from 'leather-styles/jsx';
import { openInNewTab } from '@app/common/utils/open-in-new-tab';
import { SponsoredLabel } from '@app/components/sponsored-label';
diff --git a/src/app/components/secret-key/mnemonic-key/mnemonic-input-field.tsx b/src/app/components/secret-key/mnemonic-key/mnemonic-input-field.tsx
deleted file mode 100644
index b1cf126aa3d..00000000000
--- a/src/app/components/secret-key/mnemonic-key/mnemonic-input-field.tsx
+++ /dev/null
@@ -1,104 +0,0 @@
-import { useState } from 'react';
-
-import { TextField } from '@radix-ui/themes';
-import { useField } from 'formik';
-import { css } from 'leather-styles/css';
-import { FlexProps, styled } from 'leather-styles/jsx';
-
-import { useIsFieldDirty } from '@app/common/form-utils';
-
-interface InputFieldProps extends FlexProps {
- dataTestId?: string;
- name: string;
- value: string;
- onPaste(e: React.ClipboardEvent): void;
- onUpdateWord(word: string): void;
- hasError?: boolean;
- wordlist: string[];
-}
-
-const psuedoBorderStyles = {
- content: '""',
- zIndex: 1,
- top: 0,
- right: 0,
- bottom: 0,
- left: 0,
- background: 'transparent',
- position: 'absolute',
- border: '1px solid',
- borderRadius: 'sm',
-};
-
-export function InputField({ dataTestId, name, onPaste, onChange, value }: InputFieldProps) {
- const [field, meta] = useField(name);
- const [isFocused, setIsFocused] = useState(false);
- const isDirty = useIsFieldDirty(name);
- return (
-
-
- {`${name}.`}
-
- setIsFocused(!isFocused)}
- {...field}
- value={value || field.value || ''}
- // using onChangeCapture + onBlurCapture to keep Formik validation
- onChangeCapture={onChange}
- onBlurCapture={() => setIsFocused(!isFocused)}
- onPaste={onPaste}
- />
-
- );
-}
diff --git a/src/app/components/secret-key/mnemonic-key/mnemonic-word-input.tsx b/src/app/components/secret-key/mnemonic-key/mnemonic-word-input.tsx
index f06ec9fa1d5..257d8a38bc4 100644
--- a/src/app/components/secret-key/mnemonic-key/mnemonic-word-input.tsx
+++ b/src/app/components/secret-key/mnemonic-key/mnemonic-word-input.tsx
@@ -1,8 +1,10 @@
-import { wordlist } from '@scure/bip39/wordlists/english';
+import { useState } from 'react';
-import { extractPhraseFromString } from '@app/common/utils';
+import { useField } from 'formik';
-import { InputField } from './mnemonic-input-field';
+import { useIsFieldDirty } from '@app/common/form-utils';
+import { extractPhraseFromString } from '@app/common/utils';
+import { Input } from '@app/ui/components/input/input';
interface MnemonicWordInputProps {
fieldNumber: number;
@@ -16,28 +18,41 @@ export function MnemonicWordInput({
onUpdateWord,
onPasteEntireKey,
}: MnemonicWordInputProps) {
+ const name = `${fieldNumber}`;
+ const [field, meta] = useField(name);
+ const [isFocused, setIsFocused] = useState(false);
+ const isDirty = useIsFieldDirty(name);
return (
- {
- const pasteValue = extractPhraseFromString(e.clipboardData.getData('text'));
- if (pasteValue.includes(' ')) {
+
+ setIsFocused(!isFocused)}
+ {...field}
+ value={value || field.value || ''}
+ // using onChangeCapture + onBlurCapture to keep Formik validation
+ onChangeCapture={(e: any) => {
e.preventDefault();
- //assume its a full key
- onPasteEntireKey(pasteValue);
- }
- }}
- onChange={(e: any) => {
- e.preventDefault();
- onUpdateWord(e.target.value);
- }}
- wordlist={wordlist}
- value={value}
- height="3rem"
- />
+ onUpdateWord(e.target.value);
+ }}
+ onBlurCapture={() => setIsFocused(!isFocused)}
+ onPaste={e => {
+ const pasteValue = extractPhraseFromString(e.clipboardData.getData('text'));
+ if (pasteValue.includes(' ')) {
+ e.preventDefault();
+ //assume its a full key
+ onPasteEntireKey(pasteValue);
+ }
+ }}
+ />
+ Word {fieldNumber}
+
);
}
diff --git a/src/app/features/add-network/add-network.tsx b/src/app/features/add-network/add-network.tsx
index 06fbb497d29..339faa38c97 100644
--- a/src/app/features/add-network/add-network.tsx
+++ b/src/app/features/add-network/add-network.tsx
@@ -22,7 +22,7 @@ import {
useNetworksActions,
} from '@app/store/networks/networks.hooks';
import { Button } from '@app/ui/components/button/button';
-import { Input } from '@app/ui/components/input';
+import { Input } from '@app/ui/components/input/input';
import { Title } from '@app/ui/components/typography/title';
/**
@@ -70,14 +70,14 @@ export function AddNetwork() {
const setStacksUrl = useCallback(
(value: string) => {
- setFieldValue('stacksUrl', value);
+ void setFieldValue('stacksUrl', value);
},
[setFieldValue]
);
const setBitcoinUrl = useCallback(
(value: string) => {
- setFieldValue('bitcoinUrl', value);
+ void setFieldValue('bitcoinUrl', value);
},
[setFieldValue]
);
@@ -224,17 +224,17 @@ export function AddNetwork() {
. Make sure you review and trust the host before you add it.
-
+
+ Name
+
+
Bitcoin API
{/* TODO: Replace with new Select */}
@@ -269,37 +269,38 @@ export function AddNetwork() {
Stacks API URL
-
+
+ Name
+
+
Bitcoin API URL
-
-
+
+ Bitcoin API URL
+
+
+
+ Network key
+
+
{error ? (
{error}
) : null}
diff --git a/src/app/features/asset-list/components/stacks-asset-list.tsx b/src/app/features/asset-list/components/stacks-asset-list.tsx
index 0c8d0e6308e..40207ba6177 100644
--- a/src/app/features/asset-list/components/stacks-asset-list.tsx
+++ b/src/app/features/asset-list/components/stacks-asset-list.tsx
@@ -1,9 +1,12 @@
+import { styled } from 'leather-styles/jsx';
+
import { useStxBalance } from '@app/common/hooks/balance/stx/use-stx-balance';
import { ftDecimals } from '@app/common/stacks-utils';
import { CryptoCurrencyAssetItem } from '@app/components/crypto-assets/crypto-currency-asset/crypto-currency-asset-item';
import { StxAvatar } from '@app/components/crypto-assets/stacks/components/stx-avatar';
import { useStacksFungibleTokenAssetBalancesAnchoredWithMetadata } from '@app/query/stacks/balance/stacks-ft-balances.hooks';
import { StacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.models';
+import { BulletOperator } from '@app/ui/components/bullet-separator/bullet-separator';
import { Caption } from '@app/ui/components/typography/caption';
import { StacksFungibleTokenAssetList } from './stacks-fungible-token-asset-list';
@@ -20,11 +23,17 @@ export function StacksAssetList({ account }: StacksAssetListProps) {
useStxBalance();
const stxAdditionalBalanceInfo = stxLockedBalance?.amount.isGreaterThan(0) ? (
- <>({ftDecimals(stxLockedBalance.amount, stxLockedBalance.decimals || 0)} locked)>
+
+
+ {ftDecimals(stxLockedBalance.amount, stxLockedBalance.decimals || 0)} locked
+
) : undefined;
const stxAdditionalUsdBalanceInfo = stxLockedBalance?.amount.isGreaterThan(0) ? (
- ({stxUsdLockedBalance} locked)
+
+
+ {stxUsdLockedBalance} locked
+
) : undefined;
return (
diff --git a/src/app/features/bitcoin-choose-fee/bitcoin-choose-fee.tsx b/src/app/features/bitcoin-choose-fee/bitcoin-choose-fee.tsx
index 99e3f3472bc..bfdc9ebb901 100644
--- a/src/app/features/bitcoin-choose-fee/bitcoin-choose-fee.tsx
+++ b/src/app/features/bitcoin-choose-fee/bitcoin-choose-fee.tsx
@@ -1,7 +1,6 @@
import { useState } from 'react';
-import { Box, FlexProps, Stack } from 'leather-styles/jsx';
-import { styled } from 'leather-styles/jsx';
+import { Box, FlexProps, Stack, styled } from 'leather-styles/jsx';
import { BtcFeeType } from '@shared/models/fees/bitcoin-fees.model';
import { Money } from '@shared/models/money.model';
diff --git a/src/app/features/collectibles/components/taproot-balance-displayer.tsx b/src/app/features/collectibles/components/taproot-balance-displayer.tsx
index b5440a6cadd..e82e23a3986 100644
--- a/src/app/features/collectibles/components/taproot-balance-displayer.tsx
+++ b/src/app/features/collectibles/components/taproot-balance-displayer.tsx
@@ -18,7 +18,7 @@ export function TaprootBalanceDisplayer({ onSelectRetrieveBalance }: TaprootBala
if (!isRecoverFeatureEnabled) return null;
if (balance.amount.isLessThanOrEqualTo(0)) return null;
return (
-
+
onSelectRetrieveBalance()} textStyle="caption.02" variant="text">
{formatMoney(balance)}
diff --git a/src/app/features/container/container.tsx b/src/app/features/container/container.tsx
index 76d8367fcaf..55d4ea9e5c8 100644
--- a/src/app/features/container/container.tsx
+++ b/src/app/features/container/container.tsx
@@ -4,8 +4,7 @@ import { Outlet, useLocation } from 'react-router-dom';
import { closeWindow } from '@shared/utils';
-import { useInitalizeAnalytics } from '@app/common/hooks/analytics/use-analytics';
-import { useAnalytics } from '@app/common/hooks/analytics/use-analytics';
+import { useAnalytics, useInitalizeAnalytics } from '@app/common/hooks/analytics/use-analytics';
import { LoadingSpinner } from '@app/components/loading-spinner';
import { useOnSignOut } from '@app/routes/hooks/use-on-sign-out';
import { useOnWalletLock } from '@app/routes/hooks/use-on-wallet-lock';
diff --git a/src/app/features/edit-nonce-drawer/components/edit-nonce-field.tsx b/src/app/features/edit-nonce-drawer/components/edit-nonce-field.tsx
index ee8825535f0..de37a000648 100644
--- a/src/app/features/edit-nonce-drawer/components/edit-nonce-field.tsx
+++ b/src/app/features/edit-nonce-drawer/components/edit-nonce-field.tsx
@@ -4,7 +4,7 @@ import { useField } from 'formik';
import { Stack, StackProps } from 'leather-styles/jsx';
import { ErrorLabel } from '@app/components/error-label';
-import { Input } from '@app/ui/components/input';
+import { Input } from '@app/ui/components/input/input';
interface EditNonceFieldProps extends StackProps {
onBlur(): void;
@@ -15,14 +15,16 @@ export const EditNonceField = memo((props: EditNonceFieldProps) => {
return (
- ) => {
- await helpers.setValue(evt.currentTarget.value);
- }}
- placeholder="Enter a custom nonce"
- value={field.value}
- />
+
+ Custom nonce
+ ) => {
+ await helpers.setValue(evt.currentTarget.value);
+ }}
+ />
+
{meta.error && {meta.error}}
);
diff --git a/src/app/features/leather-intro-dialog/leather-intro-steps.tsx b/src/app/features/leather-intro-dialog/leather-intro-steps.tsx
index 766d3b8c5bd..29b62738bfc 100644
--- a/src/app/features/leather-intro-dialog/leather-intro-steps.tsx
+++ b/src/app/features/leather-intro-dialog/leather-intro-steps.tsx
@@ -1,8 +1,7 @@
import { useLayoutEffect, useRef, useState } from 'react';
import Confetti from 'react-dom-confetti';
-import { Dialog } from '@radix-ui/themes';
-import { Inset } from '@radix-ui/themes';
+import { Dialog, Inset } from '@radix-ui/themes';
import { css } from 'leather-styles/css';
import { Box, Flex, Stack, styled } from 'leather-styles/jsx';
diff --git a/src/app/features/ledger/utils/stacks-ledger-utils.ts b/src/app/features/ledger/utils/stacks-ledger-utils.ts
index 71edcb5a606..63899a1895f 100644
--- a/src/app/features/ledger/utils/stacks-ledger-utils.ts
+++ b/src/app/features/ledger/utils/stacks-ledger-utils.ts
@@ -19,8 +19,8 @@ import {
SemVerObject,
prepareLedgerDeviceForAppFn,
promptOpenAppOnDevice,
+ versionObjectToVersionString,
} from './generic-ledger-utils';
-import { versionObjectToVersionString } from './generic-ledger-utils';
export function requestPublicKeyForStxAccount(app: StacksApp) {
return async (index: number) =>
diff --git a/src/app/features/message-signer/message-preview-box.tsx b/src/app/features/message-signer/message-preview-box.tsx
index 6eb65039d44..ba45782363c 100644
--- a/src/app/features/message-signer/message-preview-box.tsx
+++ b/src/app/features/message-signer/message-preview-box.tsx
@@ -1,5 +1,4 @@
-import { Stack } from 'leather-styles/jsx';
-import { styled } from 'leather-styles/jsx';
+import { Stack, styled } from 'leather-styles/jsx';
import { HashDrawer } from './hash-drawer';
diff --git a/src/app/features/pending-brc-20-transfers/pending-brc-20-transfers.tsx b/src/app/features/pending-brc-20-transfers/pending-brc-20-transfers.tsx
index 8c06beec5d9..9a99ec21b4e 100644
--- a/src/app/features/pending-brc-20-transfers/pending-brc-20-transfers.tsx
+++ b/src/app/features/pending-brc-20-transfers/pending-brc-20-transfers.tsx
@@ -5,7 +5,6 @@ import { Box, Flex, HStack, Stack } from 'leather-styles/jsx';
import { RouteUrls } from '@shared/route-urls';
import { noop } from '@shared/utils';
-import { CaptionDotSeparator } from '@app/components/caption-dot-separator';
import { usePressable } from '@app/components/item-hover';
import { Flag } from '@app/components/layout/flag';
import { StatusPending } from '@app/components/status-pending';
@@ -21,6 +20,7 @@ import {
PendingBrc20Transfer,
usePendingBrc20Transfers,
} from '@app/store/ordinals/ordinals.slice';
+import { BulletSeparator } from '@app/ui/components/bullet-separator/bullet-separator';
import { BasicTooltip } from '@app/ui/components/tooltip/basic-tooltip';
import { Caption } from '@app/ui/components/typography/caption';
@@ -128,7 +128,7 @@ function PendingBrcTransfer({ order }: PendingBrcTransferProps) {
{order.amount} {order.tick}
>
-
+
-
+
{component}
diff --git a/src/app/features/psbt-signer/components/psbt-request-sighash-warning-label.tsx b/src/app/features/psbt-signer/components/psbt-request-sighash-warning-label.tsx
index b69c18efd57..9eb16180a6a 100644
--- a/src/app/features/psbt-signer/components/psbt-request-sighash-warning-label.tsx
+++ b/src/app/features/psbt-signer/components/psbt-request-sighash-warning-label.tsx
@@ -1,11 +1,13 @@
import { WarningLabel } from '@app/components/warning-label';
-export function PsbtRequestSighashWarningLabel() {
+interface PsbtRequestSighashWarningLabelProps {
+ origin: string;
+}
+export function PsbtRequestSighashWarningLabel({ origin }: PsbtRequestSighashWarningLabelProps) {
return (
- The details you see here are not guaranteed. Be sure to fully trust your counterparty, who can
- later modify this transaction to send or receive other assets from your account, and possibly
- even drain it.
+ The details of this transaction are not guaranteed and could be modified later. Continue only
+ if you trust {origin}
);
}
diff --git a/src/app/features/psbt-signer/psbt-signer.tsx b/src/app/features/psbt-signer/psbt-signer.tsx
index d1d53249425..0b59788e404 100644
--- a/src/app/features/psbt-signer/psbt-signer.tsx
+++ b/src/app/features/psbt-signer/psbt-signer.tsx
@@ -98,7 +98,7 @@ export function PsbtSigner(props: PsbtSignerProps) {
- {isPsbtMutable ? : null}
+ {isPsbtMutable ? : null}
diff --git a/src/app/features/stacks-transaction-request/post-conditions/no-post-conditions.tsx b/src/app/features/stacks-transaction-request/post-conditions/no-post-conditions.tsx
index 6b680558c91..6023981e5de 100644
--- a/src/app/features/stacks-transaction-request/post-conditions/no-post-conditions.tsx
+++ b/src/app/features/stacks-transaction-request/post-conditions/no-post-conditions.tsx
@@ -1,5 +1,4 @@
-import { Box, Circle, HStack } from 'leather-styles/jsx';
-import { styled } from 'leather-styles/jsx';
+import { Box, Circle, HStack, styled } from 'leather-styles/jsx';
import { LockIcon } from '@app/ui/components/icons/lock-icon';
diff --git a/src/app/pages/bitcoin-contract-list/bitcoin-contract-list.tsx b/src/app/pages/bitcoin-contract-list/bitcoin-contract-list.tsx
index 5f8766e5a95..ba8eb71cd97 100644
--- a/src/app/pages/bitcoin-contract-list/bitcoin-contract-list.tsx
+++ b/src/app/pages/bitcoin-contract-list/bitcoin-contract-list.tsx
@@ -2,8 +2,10 @@ import { useState } from 'react';
import { Flex, styled } from 'leather-styles/jsx';
-import { useBitcoinContracts } from '@app/common/hooks/use-bitcoin-contracts';
-import { BitcoinContractListItem } from '@app/common/hooks/use-bitcoin-contracts';
+import {
+ BitcoinContractListItem,
+ useBitcoinContracts,
+} from '@app/common/hooks/use-bitcoin-contracts';
import { useOnMount } from '@app/common/hooks/use-on-mount';
import { FullPageLoadingSpinner } from '@app/components/loading-spinner';
import { truncateMiddle } from '@app/ui/utils/truncate-middle';
diff --git a/src/app/pages/bitcoin-contract-request/bitcoin-contract-request.tsx b/src/app/pages/bitcoin-contract-request/bitcoin-contract-request.tsx
index cbed6c93363..46150148e84 100644
--- a/src/app/pages/bitcoin-contract-request/bitcoin-contract-request.tsx
+++ b/src/app/pages/bitcoin-contract-request/bitcoin-contract-request.tsx
@@ -6,8 +6,10 @@ import { Stack } from 'leather-styles/jsx';
import { RouteUrls } from '@shared/route-urls';
import { BitcoinContractResponseStatus } from '@shared/rpc/methods/accept-bitcoin-contract';
-import { useBitcoinContracts } from '@app/common/hooks/use-bitcoin-contracts';
-import { BitcoinContractOfferDetails } from '@app/common/hooks/use-bitcoin-contracts';
+import {
+ BitcoinContractOfferDetails,
+ useBitcoinContracts,
+} from '@app/common/hooks/use-bitcoin-contracts';
import { useOnMount } from '@app/common/hooks/use-on-mount';
import { initialSearchParams } from '@app/common/initial-search-params';
import { useCurrentAccountNativeSegwitSigner } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
diff --git a/src/app/pages/bitcoin-contract-request/components/bitcoin-contract-offer/bitcoin-contract-emergency-refund-time.tsx b/src/app/pages/bitcoin-contract-request/components/bitcoin-contract-offer/bitcoin-contract-emergency-refund-time.tsx
index 2e71ab32ec4..9c92c47ff8b 100644
--- a/src/app/pages/bitcoin-contract-request/components/bitcoin-contract-offer/bitcoin-contract-emergency-refund-time.tsx
+++ b/src/app/pages/bitcoin-contract-request/components/bitcoin-contract-offer/bitcoin-contract-emergency-refund-time.tsx
@@ -1,6 +1,5 @@
import { BitcoinContractRequestSelectors } from '@tests/selectors/bitcoin-contract-request.selectors';
-import { Flex } from 'leather-styles/jsx';
-import { styled } from 'leather-styles/jsx';
+import { Flex, styled } from 'leather-styles/jsx';
interface BitcoinContractEmergencyRefundTimeProps {
emergencyRefundTime: string;
diff --git a/src/app/pages/bitcoin-contract-request/components/bitcoin-contract-offer/bitcoin-contract-lock-amount.tsx b/src/app/pages/bitcoin-contract-request/components/bitcoin-contract-offer/bitcoin-contract-lock-amount.tsx
index e8ce61bfba3..cc1cd5c6bcc 100644
--- a/src/app/pages/bitcoin-contract-request/components/bitcoin-contract-offer/bitcoin-contract-lock-amount.tsx
+++ b/src/app/pages/bitcoin-contract-request/components/bitcoin-contract-offer/bitcoin-contract-lock-amount.tsx
@@ -44,11 +44,14 @@ export function BitcoinContractLockAmount({
+ {/** TODO: We need to persist the tooltip after it is clicked.
+ Current implementation of radix-ui tooltip doesn't allow that, ref: https://github.com/radix-ui/primitives/issues/2029 */}
{subtitle ? (
}>
{homePageModalRoutes}
-
{homePageModalRoutes}
diff --git a/src/app/pages/onboarding/set-password/components/password-field.tsx b/src/app/pages/onboarding/set-password/components/password-field.tsx
index ffdb59c97fb..bd7e0cef06c 100644
--- a/src/app/pages/onboarding/set-password/components/password-field.tsx
+++ b/src/app/pages/onboarding/set-password/components/password-field.tsx
@@ -7,6 +7,7 @@ import { Box, Flex, styled } from 'leather-styles/jsx';
import { ValidatedPassword } from '@app/common/validation/validate-password';
import { EyeIcon } from '@app/ui/components/icons/eye-icon';
import { EyeSlashIcon } from '@app/ui/components/icons/eye-slash-icon';
+import { Input } from '@app/ui/components/input/input';
import { Caption } from '@app/ui/components/typography/caption';
import { getIndicatorsOfPasswordStrength } from './password-field.utils';
@@ -28,38 +29,33 @@ export function PasswordField({ strengthResult, isDisabled }: PasswordFieldProps
return (
<>
-
+
+ Password
+
+
setShowPassword(!showPassword)}
position="absolute"
right="space.04"
- top="20px"
- transform="matrix(-1, 0, 0, 1, 0, 0)"
+ top="22px"
type="button"
width="20px"
+ zIndex={10}
>
{showPassword ? : }
diff --git a/src/app/pages/onboarding/welcome/welcome.layout.tsx b/src/app/pages/onboarding/welcome/welcome.layout.tsx
index de153ec3e8c..d57bf278a8c 100644
--- a/src/app/pages/onboarding/welcome/welcome.layout.tsx
+++ b/src/app/pages/onboarding/welcome/welcome.layout.tsx
@@ -100,6 +100,7 @@ export function WelcomeLayout({
invert={isAtleastBreakpointMd}
flex={1}
mt={[0, 0, 'space.05']}
+ onClick={onSelectConnectLedger}
>
Use Ledger
diff --git a/src/app/pages/onboarding/welcome/welcome.tsx b/src/app/pages/onboarding/welcome/welcome.tsx
index fae11bd2dc8..b513e63bcaf 100644
--- a/src/app/pages/onboarding/welcome/welcome.tsx
+++ b/src/app/pages/onboarding/welcome/welcome.tsx
@@ -67,15 +67,22 @@ export function WelcomePage() {
const restoreWallet = pageModeRoutingAction(RouteUrls.SignIn);
+ const onSelectConnectLedger = useCallback(async () => {
+ await keyActions.signOut();
+ if (doesBrowserSupportWebUsbApi()) {
+ supportsWebUsbAction();
+ } else {
+ doesNotSupportWebUsbAction();
+ }
+ }, [doesNotSupportWebUsbAction, keyActions, supportsWebUsbAction]);
+
return (
<>
- doesBrowserSupportWebUsbApi() ? supportsWebUsbAction() : doesNotSupportWebUsbAction()
- }
+ onSelectConnectLedger={onSelectConnectLedger}
onStartOnboarding={() => startOnboarding()}
onRestoreWallet={() => restoreWallet()}
/>
diff --git a/src/app/pages/select-network/components/network-list-item.layout.tsx b/src/app/pages/select-network/components/network-list-item.layout.tsx
index d6d6ba0ee8e..8e2de838d7c 100644
--- a/src/app/pages/select-network/components/network-list-item.layout.tsx
+++ b/src/app/pages/select-network/components/network-list-item.layout.tsx
@@ -1,6 +1,5 @@
import { SettingsSelectors } from '@tests/selectors/settings.selectors';
-import { Box, Flex, Stack } from 'leather-styles/jsx';
-import { styled } from 'leather-styles/jsx';
+import { Box, Flex, Stack, styled } from 'leather-styles/jsx';
import { NetworkConfiguration } from '@shared/constants';
diff --git a/src/app/pages/send/choose-crypto-asset/choose-crypto-asset.tsx b/src/app/pages/send/choose-crypto-asset/choose-crypto-asset.tsx
index 7167b26ea96..14bf7580719 100644
--- a/src/app/pages/send/choose-crypto-asset/choose-crypto-asset.tsx
+++ b/src/app/pages/send/choose-crypto-asset/choose-crypto-asset.tsx
@@ -4,11 +4,10 @@ import { useNavigate } from 'react-router-dom';
import { AllTransferableCryptoAssetBalances } from '@shared/models/crypto-asset-balance.model';
import { RouteUrls } from '@shared/route-urls';
+import { useBrc20Tokens } from '@app/common/hooks/use-brc20-tokens';
import { useRouteHeader } from '@app/common/hooks/use-route-header';
import { useAllTransferableCryptoAssetBalances } from '@app/common/hooks/use-transferable-asset-balances.hooks';
import { useWalletType } from '@app/common/use-wallet-type';
-import { Brc20TokensLoader } from '@app/components/brc20-tokens-loader';
-import { Brc20TokenAssetList } from '@app/components/crypto-assets/bitcoin/brc20-token-asset-list/brc20-token-asset-list';
import { ChooseCryptoAssetLayout } from '@app/components/crypto-assets/choose-crypto-asset/choose-crypto-asset.layout';
import { CryptoAssetList } from '@app/components/crypto-assets/choose-crypto-asset/crypto-asset-list';
import { ModalHeader } from '@app/components/modal-header';
@@ -17,6 +16,7 @@ import { useCheckLedgerBlockchainAvailable } from '@app/store/accounts/blockchai
export function ChooseCryptoAsset() {
const allTransferableCryptoAssetBalances = useAllTransferableCryptoAssetBalances();
+ const brc20Tokens = useBrc20Tokens();
const { whenWallet } = useWalletType();
const navigate = useNavigate();
@@ -49,6 +49,7 @@ export function ChooseCryptoAsset() {
navigateToSendForm(cryptoAssetBalance)}
+ brc20Tokens={brc20Tokens}
cryptoAssetBalances={allTransferableCryptoAssetBalances.filter(asset =>
whenWallet({
ledger: checkBlockchainAvailable(asset.blockchain),
@@ -56,14 +57,6 @@ export function ChooseCryptoAsset() {
})
)}
/>
- {whenWallet({
- software: (
-
- {brc20Tokens => }
-
- ),
- ledger: null,
- })}
);
}
diff --git a/src/app/pages/send/ordinal-inscription/components/collectible-asset.tsx b/src/app/pages/send/ordinal-inscription/components/collectible-asset.tsx
index e769cdfd4f5..adf6c33f02f 100644
--- a/src/app/pages/send/ordinal-inscription/components/collectible-asset.tsx
+++ b/src/app/pages/send/ordinal-inscription/components/collectible-asset.tsx
@@ -1,5 +1,4 @@
-import { Flex } from 'leather-styles/jsx';
-import { HStack, styled } from 'leather-styles/jsx';
+import { Flex, HStack, styled } from 'leather-styles/jsx';
interface CollectibleAssetProps {
icon: React.JSX.Element;
diff --git a/src/app/pages/send/send-crypto-asset-form/components/amount-field.tsx b/src/app/pages/send/send-crypto-asset-form/components/amount-field.tsx
index 2225aa24356..03d182f6c19 100644
--- a/src/app/pages/send/send-crypto-asset-form/components/amount-field.tsx
+++ b/src/app/pages/send/send-crypto-asset-form/components/amount-field.tsx
@@ -1,5 +1,4 @@
-import type { ChangeEvent } from 'react';
-import { useCallback, useEffect, useRef, useState } from 'react';
+import { type ChangeEvent, useCallback, useEffect, useRef, useState } from 'react';
import { SendCryptoAssetSelectors } from '@tests/selectors/send.selectors';
import { useField } from 'formik';
diff --git a/src/app/pages/send/send-crypto-asset-form/components/form-footer.tsx b/src/app/pages/send/send-crypto-asset-form/components/form-footer.tsx
index 2993596e33b..9a5157f55e9 100644
--- a/src/app/pages/send/send-crypto-asset-form/components/form-footer.tsx
+++ b/src/app/pages/send/send-crypto-asset-form/components/form-footer.tsx
@@ -1,5 +1,4 @@
-import { Box } from 'leather-styles/jsx';
-import { Flex } from 'leather-styles/jsx';
+import { Box, Flex } from 'leather-styles/jsx';
import { Money } from '@shared/models/money.model';
diff --git a/src/app/pages/send/send-crypto-asset-form/components/recipient-fields/components/recipient-address-displayer.tsx b/src/app/pages/send/send-crypto-asset-form/components/recipient-fields/components/recipient-address-displayer.tsx
index 48c9b81c792..5241f2915fc 100644
--- a/src/app/pages/send/send-crypto-asset-form/components/recipient-fields/components/recipient-address-displayer.tsx
+++ b/src/app/pages/send/send-crypto-asset-form/components/recipient-fields/components/recipient-address-displayer.tsx
@@ -28,7 +28,9 @@ export function RecipientAddressDisplayer({ address }: RecipientAddressDisplayer
>
{address}
-
+ {/** TODO: We need to persist the tooltip after it is clicked.
+ Current implementation of radix-ui tooltip doesn't allow that, ref: https://github.com/radix-ui/primitives/issues/2029 */}
+
;
return (
-
-
- onSendMax()}
- {...props}
- >
- {isSendingMax ? 'Sending max' : 'Send max'}
-
-
+
+ onSendMax()}
+ {...props}
+ >
+ {isSendingMax ? 'Sending max' : 'Send max'}
+
);
}
diff --git a/src/app/pages/send/send-crypto-asset-form/family/bitcoin/hooks/use-calculate-max-spend.ts b/src/app/pages/send/send-crypto-asset-form/family/bitcoin/hooks/use-calculate-max-spend.ts
index c63aecbe149..d83eef530f7 100644
--- a/src/app/pages/send/send-crypto-asset-form/family/bitcoin/hooks/use-calculate-max-spend.ts
+++ b/src/app/pages/send/send-crypto-asset-form/family/bitcoin/hooks/use-calculate-max-spend.ts
@@ -1,47 +1,20 @@
import { useCallback } from 'react';
-import BigNumber from 'bignumber.js';
-import { getAddressInfo, validate } from 'bitcoin-address-validation';
-
-import { createMoney } from '@shared/models/money.model';
-
-import { satToBtc } from '@app/common/money/unit-conversion';
-import { BtcSizeFeeEstimator } from '@app/common/transactions/bitcoin/fees/btc-size-fee-estimator';
-import { useCurrentNativeSegwitAddressBalance } from '@app/query/bitcoin/balance/btc-native-segwit-balance.hooks';
+import { calculateMaxBitcoinSpend } from '@app/common/transactions/bitcoin/fees/calculate-max-bitcoin-spend';
import { UtxoResponseItem } from '@app/query/bitcoin/bitcoin-client';
import { useAverageBitcoinFeeRates } from '@app/query/bitcoin/fees/fee-estimates.hooks';
export function useCalculateMaxBitcoinSpend() {
- const balance = useCurrentNativeSegwitAddressBalance();
const { data: feeRates } = useAverageBitcoinFeeRates();
return useCallback(
- (address = '', utxos: UtxoResponseItem[], feeRate?: number) => {
- if (!utxos.length || !feeRates)
- return {
- spendAllFee: 0,
- amount: createMoney(0, 'BTC'),
- spendableBitcoin: new BigNumber(0),
- };
-
- const txSizer = new BtcSizeFeeEstimator();
- const addressInfo = validate(address) ? getAddressInfo(address) : null;
- const addressTypeWithFallback = addressInfo ? addressInfo.type : 'p2wpkh';
- const size = txSizer.calcTxSize({
- input_script: 'p2wpkh',
- input_count: utxos.length,
- [`${addressTypeWithFallback}_output_count`]: 1,
- });
- const fee = Math.ceil(size.txVBytes * (feeRate ?? feeRates.halfHourFee.toNumber()));
-
- const spendableAmount = BigNumber.max(0, balance.amount.minus(fee));
-
- return {
- spendAllFee: fee,
- amount: createMoney(spendableAmount, 'BTC'),
- spendableBitcoin: satToBtc(spendableAmount),
- };
- },
- [balance.amount, feeRates]
+ (address = '', utxos: UtxoResponseItem[], feeRate?: number) =>
+ calculateMaxBitcoinSpend({
+ address,
+ utxos,
+ feeRate,
+ fetchedFeeRates: feeRates,
+ }),
+ [feeRates]
);
}
diff --git a/src/app/pages/send/send-crypto-asset-form/form/brc-20/brc-20-choose-fee.tsx b/src/app/pages/send/send-crypto-asset-form/form/brc-20/brc-20-choose-fee.tsx
index 763821f9d6e..22eb0020c78 100644
--- a/src/app/pages/send/send-crypto-asset-form/form/brc-20/brc-20-choose-fee.tsx
+++ b/src/app/pages/send/send-crypto-asset-form/form/brc-20/brc-20-choose-fee.tsx
@@ -1,7 +1,6 @@
import { useState } from 'react';
import { toast } from 'react-hot-toast';
-import { Outlet } from 'react-router-dom';
-import { useLocation, useNavigate } from 'react-router-dom';
+import { Outlet, useLocation, useNavigate } from 'react-router-dom';
import { Stack } from 'leather-styles/jsx';
import get from 'lodash.get';
diff --git a/src/app/query/common/market-data/market-data.hooks.ts b/src/app/query/common/market-data/market-data.hooks.ts
index 506bc916320..499fd612837 100644
--- a/src/app/query/common/market-data/market-data.hooks.ts
+++ b/src/app/query/common/market-data/market-data.hooks.ts
@@ -1,5 +1,4 @@
-import { useMemo } from 'react';
-import { useCallback } from 'react';
+import { useCallback, useMemo } from 'react';
import BigNumber from 'bignumber.js';
@@ -8,8 +7,10 @@ import { MarketData, createMarketData, createMarketPair } from '@shared/models/m
import { Money, createMoney, currencyDecimalsMap } from '@shared/models/money.model';
import { calculateMeanAverage } from '@app/common/math/calculate-averages';
-import { convertAmountToFractionalUnit } from '@app/common/money/calculate-money';
-import { baseCurrencyAmountInQuote } from '@app/common/money/calculate-money';
+import {
+ baseCurrencyAmountInQuote,
+ convertAmountToFractionalUnit,
+} from '@app/common/money/calculate-money';
import {
selectBinanceUsdPrice,
diff --git a/src/app/routes/onboarding-gate.tsx b/src/app/routes/onboarding-gate.tsx
index 619022a117b..9ba0efb67ea 100644
--- a/src/app/routes/onboarding-gate.tsx
+++ b/src/app/routes/onboarding-gate.tsx
@@ -4,6 +4,7 @@ import { Navigate } from 'react-router-dom';
import { RouteUrls } from '@shared/route-urls';
import { useDefaultWalletSecretKey } from '@app/store/in-memory-key/in-memory-key.selectors';
+import { useHasLedgerKeys } from '@app/store/ledger/ledger.selectors';
import { useCurrentKeyDetails } from '@app/store/software-keys/software-key.selectors';
function hasAlreadyMadeWalletAndPlaintextKeyInMemory(encryptedKey?: string, inMemoryKey?: string) {
@@ -20,10 +21,15 @@ interface OnboardingGateProps {
export function OnboardingGate({ children }: OnboardingGateProps) {
const keyDetails = useCurrentKeyDetails();
const currentInMemoryKey = useDefaultWalletSecretKey();
+ const isLedger = useHasLedgerKeys();
if (
- keyDetails?.type === 'software' &&
- hasAlreadyMadeWalletAndPlaintextKeyInMemory(keyDetails.encryptedSecretKey, currentInMemoryKey)
+ (keyDetails?.type === 'software' &&
+ hasAlreadyMadeWalletAndPlaintextKeyInMemory(
+ keyDetails.encryptedSecretKey,
+ currentInMemoryKey
+ )) ||
+ isLedger
) {
return ;
}
diff --git a/src/app/store/accounts/blockchain/bitcoin/bitcoin.hooks.ts b/src/app/store/accounts/blockchain/bitcoin/bitcoin.hooks.ts
index 1076321a929..9d6b056de0c 100644
--- a/src/app/store/accounts/blockchain/bitcoin/bitcoin.hooks.ts
+++ b/src/app/store/accounts/blockchain/bitcoin/bitcoin.hooks.ts
@@ -7,9 +7,9 @@ import AppClient from 'ledger-bitcoin';
import { getBitcoinJsLibNetworkConfigByMode } from '@shared/crypto/bitcoin/bitcoin.network';
import {
extractAddressIndexFromPath,
+ getInputPaymentType,
getTaprootAddress,
} from '@shared/crypto/bitcoin/bitcoin.utils';
-import { getInputPaymentType } from '@shared/crypto/bitcoin/bitcoin.utils';
import { getTaprootAccountDerivationPath } from '@shared/crypto/bitcoin/p2tr-address-gen';
import { getNativeSegwitAccountDerivationPath } from '@shared/crypto/bitcoin/p2wpkh-address-gen';
import {
@@ -40,10 +40,12 @@ import {
useCurrentAccountNativeSegwitSigner,
useCurrentNativeSegwitAccount,
useUpdateLedgerSpecificNativeSegwitBip32DerivationForAdddressIndexZero,
+ useUpdateLedgerSpecificNativeSegwitUtxoHexForAdddressIndexZero,
} from './native-segwit-account.hooks';
-import { useUpdateLedgerSpecificNativeSegwitUtxoHexForAdddressIndexZero } from './native-segwit-account.hooks';
-import { useCurrentTaprootAccount } from './taproot-account.hooks';
-import { useUpdateLedgerSpecificTaprootInputPropsForAdddressIndexZero } from './taproot-account.hooks';
+import {
+ useCurrentTaprootAccount,
+ useUpdateLedgerSpecificTaprootInputPropsForAdddressIndexZero,
+} from './taproot-account.hooks';
// Checks for both TR and NativeSegwit hooks
export function useHasCurrentBitcoinAccount() {
diff --git a/src/app/ui/components/bullet-separator/bullet-separator.stories.tsx b/src/app/ui/components/bullet-separator/bullet-separator.stories.tsx
new file mode 100644
index 00000000000..cbe12f78380
--- /dev/null
+++ b/src/app/ui/components/bullet-separator/bullet-separator.stories.tsx
@@ -0,0 +1,52 @@
+import { Meta, StoryObj } from '@storybook/react';
+
+import { Caption } from '../typography/caption';
+import { Title } from '../typography/title';
+import { BulletSeparator as Component } from './bullet-separator';
+
+/**
+ * Note that the BulletSeparator component doesn't bring it's own margins, these
+ * should be appiled separately
+ */
+const meta: Meta = {
+ component: Component,
+ tags: ['autodocs'],
+ title: 'BulletSeparator',
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const BulletSeparator: Story = {
+ render: () => (
+
+ Item 1
+ Item 2
+ Item 3
+
+ ),
+};
+
+export const WithCaption: Story = {
+ render: () => (
+
+
+ Item 1
+ Item 2
+ Item 3
+
+
+ ),
+};
+
+export const WithTitle: Story = {
+ render: () => (
+
+
+ Item 1
+ Item 2
+ Item 3
+
+
+ ),
+};
diff --git a/src/app/ui/components/bullet-separator/bullet-separator.tsx b/src/app/ui/components/bullet-separator/bullet-separator.tsx
new file mode 100644
index 00000000000..9d6c7f1213e
--- /dev/null
+++ b/src/app/ui/components/bullet-separator/bullet-separator.tsx
@@ -0,0 +1,32 @@
+import { cloneElement, isValidElement } from 'react';
+
+import { Circle, CircleProps } from 'leather-styles/jsx';
+
+export function BulletOperator(props: CircleProps) {
+ return (
+
+ );
+}
+
+interface BulletSeparatorSeparatorProps {
+ children: React.ReactNode;
+}
+export function BulletSeparator({ children }: BulletSeparatorSeparatorProps) {
+ const parsedChildren = Array.isArray(children) ? children : [children];
+ const content = parsedChildren
+ .flatMap((child, index) => {
+ if (!isValidElement(child)) return null;
+ return [cloneElement(child, { key: index }), ];
+ })
+ .filter(val => val !== null)
+ .slice(0, -1);
+ return <>{content}>;
+}
diff --git a/src/app/ui/components/input.tsx b/src/app/ui/components/input.tsx
deleted file mode 100644
index 09ec6190015..00000000000
--- a/src/app/ui/components/input.tsx
+++ /dev/null
@@ -1,19 +0,0 @@
-import { HTMLStyledProps, styled } from 'leather-styles/jsx';
-
-type InputProps = HTMLStyledProps<'input'>;
-
-export function Input(props: InputProps) {
- return (
-
- );
-}
diff --git a/src/app/ui/components/input/input.stories.tsx b/src/app/ui/components/input/input.stories.tsx
new file mode 100644
index 00000000000..199aef5db32
--- /dev/null
+++ b/src/app/ui/components/input/input.stories.tsx
@@ -0,0 +1,72 @@
+import type { Meta, StoryObj } from '@storybook/react';
+
+import { Input } from './input';
+
+const meta: Meta = {
+ component: Input.Root,
+ tags: ['autodocs'],
+ title: 'Input',
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const Default: Story = {
+ render: () => (
+
+ Label
+
+
+ ),
+};
+
+export const Error: Story = {
+ render: () => (
+
+ Error field
+
+
+ ),
+};
+
+export const Disabled: Story = {
+ render: () => (
+
+ Field is disabled
+
+
+ ),
+};
+
+export const DefaultValue: Story = {
+ render: () => (
+
+ Description
+
+
+ ),
+};
+
+/**
+ * Layout needs to be adjusted in case where there's no label provided
+ * An example of this is our Secret Key input form
+ */
+export const InputNoLabel: Story = {
+ render: () => (
+
+
+
+ ),
+};
+
+/**
+ * When using a placeholder, the label *must* come after the `Input.Field`.
+ */
+export const WithPlaceholder: Story = {
+ render: () => (
+
+
+ Error field
+
+ ),
+};
diff --git a/src/app/ui/components/input/input.tsx b/src/app/ui/components/input/input.tsx
new file mode 100644
index 00000000000..90afff1870a
--- /dev/null
+++ b/src/app/ui/components/input/input.tsx
@@ -0,0 +1,215 @@
+import {
+ type ComponentProps,
+ LegacyRef,
+ createContext,
+ forwardRef,
+ useContext,
+ useImperativeHandle,
+ useRef,
+ useState,
+} from 'react';
+
+import { sva } from 'leather-styles/css';
+import { SystemStyleObject } from 'leather-styles/types';
+
+import { useOnMount } from '@app/common/hooks/use-on-mount';
+import { propIfDefined } from '@app/common/utils';
+import { createStyleContext } from '@app/ui/utils/style-context';
+
+const hackyDelayOneMs = 1;
+
+const transformedLabelStyles: SystemStyleObject = {
+ textStyle: 'label.03',
+ transform: 'translateY(-12px)',
+ fontWeight: 500,
+};
+
+const input = sva({
+ slots: ['root', 'label', 'input'],
+ base: {
+ root: {
+ display: 'block',
+ pos: 'relative',
+ minHeight: '64px',
+ p: 'space.04',
+ ring: 'none',
+ textStyle: 'body.02',
+ zIndex: 4,
+ color: 'accent.text-subdued',
+ _before: {
+ content: '""',
+ rounded: 'xs',
+ pos: 'absolute',
+ top: '-1px',
+ left: '-1px',
+ right: '-1px',
+ bottom: '-1px',
+ border: '3px solid transparent',
+ zIndex: 9,
+ pointerEvents: 'none',
+ },
+ _focusWithin: {
+ '& label': { color: 'accent.text-primary', ...transformedLabelStyles },
+ _before: {
+ border: 'action',
+ borderWidth: '2px',
+ },
+ },
+ '&[data-has-error="true"]': {
+ color: 'error.label',
+ _before: {
+ borderColor: 'error.label',
+ borderWidth: '2px',
+ },
+ },
+ },
+ input: {
+ background: 'transparent',
+ appearance: 'none',
+ rounded: 'xs',
+ pos: 'absolute',
+ px: 'space.04',
+ top: 0,
+ left: 0,
+ right: 0,
+ bottom: 0,
+ zIndex: 5,
+ textStyle: 'body.01',
+ color: 'accent.text-primary',
+ border: '1px solid',
+ borderColor: 'accent.border-hover',
+ _disabled: {
+ bg: 'accent.component-background-default',
+ borderColor: 'accent.non-interactive',
+ cursor: 'not-allowed',
+ },
+ _focus: { ring: 'none' },
+ _placeholder: { color: 'accent.text-subdued' },
+ '&:placeholder-shown + label': transformedLabelStyles,
+ '[data-has-label="true"] &': {
+ pt: '22px',
+ pb: '4px',
+ },
+ },
+ label: {
+ pointerEvents: 'none',
+ pos: 'absolute',
+ top: '36%',
+ left: 'space.04',
+ zIndex: 9,
+ color: 'inherit',
+ textStyle: 'body.02',
+ transition: 'font-size 100ms ease-in-out, transform 100ms ease-in-out',
+ // Move the input's label to the top when the input has a value
+ '[data-has-value="true"] &': transformedLabelStyles,
+ '[data-shrink="true"] &': transformedLabelStyles,
+ },
+ },
+});
+
+type InputChldren = 'root' | 'label' | 'input';
+
+const { withProvider, withContext } = createStyleContext(input);
+
+interface InputContextProps {
+ hasValue: boolean;
+ setHasValue(hasValue: boolean): void;
+ registerChild(child: string): void;
+ children: InputChldren[];
+}
+
+const InputContext = createContext(null);
+
+function useInputContext() {
+ const context = useContext(InputContext);
+ if (!context) throw new Error('useInputContext must be used within an Input.Root');
+ return context;
+}
+
+const RootBase = withProvider('div', 'root');
+
+interface RootProps extends ComponentProps<'div'> {
+ hasError?: boolean;
+ /**
+ * Display the label in a top fixed position. Often necessary when
+ * programmatically updating inputs, similar to issues described here
+ * https://mui.com/material-ui/react-text-field/#limitations
+ */
+ shrink?: boolean;
+}
+function Root({ hasError, shrink, ...props }: RootProps) {
+ const [hasValue, setHasValue] = useState(false);
+ const [children, setChildren] = useState(['root']);
+
+ function registerChild(child: InputChldren) {
+ setChildren(children => [...children, child]);
+ }
+
+ const dataAttrs = {
+ ...propIfDefined('data-has-error', hasError),
+ ...propIfDefined('data-shrink', shrink),
+ 'data-has-label': children.includes('label'),
+ };
+
+ return (
+
+
+
+ );
+}
+
+const FieldBase = withContext('input', 'input');
+
+const Field = forwardRef(({ type, ...props }: ComponentProps<'input'>, ref) => {
+ const { setHasValue } = useInputContext();
+ const innerRef = useRef(null);
+
+ useImperativeHandle(ref, () => innerRef.current);
+
+ // We need to determine whether the input has a value on it's initial
+ // render. In many places we use Formik to apply default form values.
+ // Formik sets these values after the initial render, so we need to wait
+ // before doing this check to see if there's a value.
+ useOnMount(
+ () =>
+ void setTimeout(() => {
+ if (innerRef.current?.value !== '') setHasValue(true);
+ }, hackyDelayOneMs)
+ );
+
+ // `type=number` is bad UX, instead we follow guidance here
+ // https://mui.com/material-ui/react-text-field/#type-quot-number-quot
+ // https://technology.blog.gov.uk/2020/02/24/why-the-gov-uk-design-system-team-changed-the-input-type-for-numbers/
+ const inputTypeProps =
+ type === 'number'
+ ? ({ type: 'text', inputMode: 'numeric', pattern: '[0-9]*' } as const)
+ : { type };
+
+ return (
+ {
+ // Note: this logic to determine if the field is empty may have to be
+ // made dynamic to `input=type`, and potentially made configurable with
+ // a callback passed to `Input.Root` e.g.
+ // ```
+ // typeof value === 'number' && value <= 0} />
+ // ```
+ if (e.target instanceof HTMLInputElement) setHasValue(e.target.value !== '');
+ props.onInput?.(e);
+ }}
+ />
+ );
+});
+
+const LabelBase = withContext('label', 'label');
+
+const Label = forwardRef((props: ComponentProps<'label'>, ref: LegacyRef) => {
+ const { registerChild } = useInputContext();
+ useOnMount(() => registerChild('label'));
+ return ;
+});
+
+export const Input = { Root, Field, Label };
diff --git a/src/app/ui/components/link/link.tsx b/src/app/ui/components/link/link.tsx
index 97e359844b5..ff714540708 100644
--- a/src/app/ui/components/link/link.tsx
+++ b/src/app/ui/components/link/link.tsx
@@ -1,3 +1,5 @@
+import { ForwardedRef, forwardRef } from 'react';
+
import { styled } from 'leather-styles/jsx';
import { type LinkVariantProps, link as linkRecipe } from 'leather-styles/recipes/link';
@@ -6,11 +8,12 @@ const StyledLink = styled('a');
type LinkProps = Omit, keyof LinkVariantProps> &
LinkVariantProps;
-export function Link(props: LinkProps) {
+export const Link = forwardRef((props: LinkProps, ref: ForwardedRef) => {
const { children, fullWidth, invert, size, variant, ...rest } = props;
return (
);
-}
+});
diff --git a/src/app/ui/components/tabs/tabs.stories.tsx b/src/app/ui/components/tabs/tabs.stories.tsx
index f2127fcc98e..c98cee10e08 100644
--- a/src/app/ui/components/tabs/tabs.stories.tsx
+++ b/src/app/ui/components/tabs/tabs.stories.tsx
@@ -9,6 +9,7 @@ const meta: Meta = {
};
export default meta;
+
type Story = StoryObj;
export const Tabs: Story = {
diff --git a/src/app/ui/components/tooltip/basic-tooltip.tsx b/src/app/ui/components/tooltip/basic-tooltip.tsx
index 79928e829a7..e10e2d61616 100644
--- a/src/app/ui/components/tooltip/basic-tooltip.tsx
+++ b/src/app/ui/components/tooltip/basic-tooltip.tsx
@@ -9,13 +9,14 @@ interface BasicTooltipProps {
label?: string;
disabled?: boolean;
side?: RadixTooltip.TooltipContentProps['side'];
+ asChild?: boolean;
}
-export function BasicTooltip({ children, label, disabled, side }: BasicTooltipProps) {
+export function BasicTooltip({ children, label, disabled, side, asChild }: BasicTooltipProps) {
const isDisabled = !label || disabled;
return (
- {children}
+ {children}
{label}
diff --git a/src/app/ui/components/tooltip/tooltip.stories.tsx b/src/app/ui/components/tooltip/tooltip.stories.tsx
index b71080778fb..1c03757f053 100644
--- a/src/app/ui/components/tooltip/tooltip.stories.tsx
+++ b/src/app/ui/components/tooltip/tooltip.stories.tsx
@@ -21,7 +21,7 @@ export const Tooltip: Story = {
disabled: false,
},
render: args => (
-
+
diff --git a/src/app/ui/components/typography/caption.tsx b/src/app/ui/components/typography/caption.tsx
index a9f2a9c33cf..96eb6c55b1b 100644
--- a/src/app/ui/components/typography/caption.tsx
+++ b/src/app/ui/components/typography/caption.tsx
@@ -3,13 +3,7 @@ import { forwardRef } from 'react';
import { BoxProps, styled } from 'leather-styles/jsx';
export const Caption = forwardRef(({ children, ...props }, ref) => (
-
+
{children}
));
diff --git a/src/app/ui/utils/style-context.tsx b/src/app/ui/utils/style-context.tsx
new file mode 100644
index 00000000000..8cba84f2665
--- /dev/null
+++ b/src/app/ui/utils/style-context.tsx
@@ -0,0 +1,70 @@
+import {
+ ComponentProps,
+ ElementType,
+ JSX,
+ createContext,
+ createElement,
+ forwardRef,
+ useContext,
+} from 'react';
+
+// Copied from Panda docs. This logic is needed when composing together sva
+// components, so they can share style state between slots.
+// https://panda-css.com/docs/concepts/slot-recipes#styling-jsx-compound-components
+type GenericProps = Record;
+interface StyleRecipe {
+ (props?: GenericProps): Record;
+ splitVariantProps(props: GenericProps): any;
+}
+type StyleSlot = keyof ReturnType;
+type StyleSlotRecipe = Record, string>;
+type StyleVariantProps = Parameters[0];
+type CombineProps = Omit & U;
+
+const cx = (...args: (string | undefined)[]) => args.filter(Boolean).join(' ');
+
+interface ComponentVariants {
+ (props: CombineProps, StyleVariantProps>): JSX.Element;
+}
+
+export const createStyleContext = (recipe: R) => {
+ const StyleContext = createContext | null>(null);
+
+ const withProvider = (
+ Component: T,
+ slot?: StyleSlot
+ ): ComponentVariants => {
+ const StyledComponent = forwardRef((props: ComponentProps, ref) => {
+ const [variantProps, otherProps] = recipe.splitVariantProps(props);
+ const slotStyles = recipe(variantProps) as StyleSlotRecipe;
+ return (
+
+
+
+ );
+ });
+ return StyledComponent as unknown as ComponentVariants;
+ };
+
+ const withContext = (Component: T, slot?: StyleSlot): T => {
+ if (!slot) return Component;
+ const StyledComponent = forwardRef((props: ComponentProps, ref) => {
+ const slotStyles = useContext(StyleContext);
+ return createElement(Component, {
+ ...props,
+ className: cx(slotStyles?.[slot ?? ''], props.className),
+ ref,
+ });
+ });
+ return StyledComponent as unknown as T;
+ };
+
+ return {
+ withProvider,
+ withContext,
+ };
+};
diff --git a/src/background/background.ts b/src/background/background.ts
index 52a7be9dd0f..d2a78af40bd 100755
--- a/src/background/background.ts
+++ b/src/background/background.ts
@@ -2,8 +2,7 @@
// This file is the entrypoint to the extension's background script
// https://developer.chrome.com/docs/extensions/mv3/architecture-overview/#background_script
import { logger } from '@shared/logger';
-import { CONTENT_SCRIPT_PORT } from '@shared/message-types';
-import type { LegacyMessageFromContentScript } from '@shared/message-types';
+import { CONTENT_SCRIPT_PORT, type LegacyMessageFromContentScript } from '@shared/message-types';
import { RouteUrls } from '@shared/route-urls';
import { WalletRequests } from '@shared/rpc/rpc-methods';
import { warnUsersAboutDevToolsDangers } from '@shared/utils/dev-tools-warning-log';
diff --git a/src/background/messaging/rpc-methods/accept-bitcoin-contract.ts b/src/background/messaging/rpc-methods/accept-bitcoin-contract.ts
index ecbdee03111..bafaf0d2d3f 100644
--- a/src/background/messaging/rpc-methods/accept-bitcoin-contract.ts
+++ b/src/background/messaging/rpc-methods/accept-bitcoin-contract.ts
@@ -1,8 +1,10 @@
import { RpcErrorCode } from '@btckit/types';
import { RouteUrls } from '@shared/route-urls';
-import { BitcoinContractRequest } from '@shared/rpc/methods/accept-bitcoin-contract';
-import { BitcoinContractResponseStatus } from '@shared/rpc/methods/accept-bitcoin-contract';
+import {
+ BitcoinContractRequest,
+ BitcoinContractResponseStatus,
+} from '@shared/rpc/methods/accept-bitcoin-contract';
import { makeRpcErrorResponse } from '@shared/rpc/rpc-methods';
import {
diff --git a/src/shared/crypto/bitcoin/bitcoin.utils.ts b/src/shared/crypto/bitcoin/bitcoin.utils.ts
index 0197364e3cd..9160b3a94e4 100644
--- a/src/shared/crypto/bitcoin/bitcoin.utils.ts
+++ b/src/shared/crypto/bitcoin/bitcoin.utils.ts
@@ -5,8 +5,7 @@ import * as btc from '@scure/btc-signer';
import { BitcoinNetworkModes, NetworkModes } from '@shared/constants';
import { logger } from '@shared/logger';
-import { defaultWalletKeyId } from '@shared/utils';
-import { isDefined, whenNetwork } from '@shared/utils';
+import { defaultWalletKeyId, isDefined, whenNetwork } from '@shared/utils';
import { DerivationPathDepth } from '../derivation-path.utils';
import { BtcSignerNetwork, getBtcSignerLibNetworkConfigByMode } from './bitcoin.network';
diff --git a/src/shared/utils.ts b/src/shared/utils.ts
index 125843d74df..34e35814db7 100644
--- a/src/shared/utils.ts
+++ b/src/shared/utils.ts
@@ -21,6 +21,10 @@ export function isFunction(value: unknown): value is () => void {
return typeof value === 'function';
}
+export function isBoolean(value: unknown): value is boolean {
+ return typeof value === 'boolean';
+}
+
export function isObject(value: unknown): value is object {
return typeof value === 'object';
}
diff --git a/yarn.lock b/yarn.lock
index f80eb53952f..73ab754db58 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5468,112 +5468,112 @@
resolved "https://registry.yarnpkg.com/@stitches/react/-/react-1.2.8.tgz#954f8008be8d9c65c4e58efa0937f32388ce3a38"
integrity sha512-9g9dWI4gsSVe8bNLlb+lMkBYsnIKCZTmvqvDG+Avnn69XfmHZKiaMrx7cgTaddq7aTPPmXiTsbFcUy0xgI4+wA==
-"@storybook/addon-actions@7.6.7":
- version "7.6.7"
- resolved "https://registry.yarnpkg.com/@storybook/addon-actions/-/addon-actions-7.6.7.tgz#2985d5417c65a9a0bce75a487b09bf1d1140b943"
- integrity sha512-+6EZvhIeKEqG/RNsU3R5DxOrd60BL5GEvmzE2w60s2eKaNNxtyilDjiO1g4z2s2zDNyr7JL/Ft03pJ0Jgo0lew==
+"@storybook/addon-actions@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/addon-actions/-/addon-actions-7.6.10.tgz#5b43534e158797114db032f4ad8505a81809ed00"
+ integrity sha512-pcKmf0H/caGzKDy8cz1adNSjv+KOBWLJ11RzGExrWm+Ad5ACifwlsQPykJ3TQ/21sTd9IXVrE9uuq4LldEnPbg==
dependencies:
- "@storybook/core-events" "7.6.7"
+ "@storybook/core-events" "7.6.10"
"@storybook/global" "^5.0.0"
"@types/uuid" "^9.0.1"
dequal "^2.0.2"
polished "^4.2.2"
uuid "^9.0.0"
-"@storybook/addon-backgrounds@7.6.7":
- version "7.6.7"
- resolved "https://registry.yarnpkg.com/@storybook/addon-backgrounds/-/addon-backgrounds-7.6.7.tgz#1795abcb45def9ac05fec1d293bf69061201315a"
- integrity sha512-55sBy1YUqponAVe+qL16qtWxdf63vHEnIoqFyHEwGpk7K9IhFA1BmdSpFr5VnWEwXeJXKj30db78frh2LUdk3Q==
+"@storybook/addon-backgrounds@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/addon-backgrounds/-/addon-backgrounds-7.6.10.tgz#4ecfc017befd400e5eabad347ab1819c2ea67a8c"
+ integrity sha512-kGzsN1QkfyI8Cz7TErEx9OCB3PMzpCFGLd/iy7FreXwbMbeAQ3/9fYgKUsNOYgOhuTz7S09koZUWjS/WJuZGFA==
dependencies:
"@storybook/global" "^5.0.0"
memoizerific "^1.11.3"
ts-dedent "^2.0.0"
-"@storybook/addon-controls@7.6.7":
- version "7.6.7"
- resolved "https://registry.yarnpkg.com/@storybook/addon-controls/-/addon-controls-7.6.7.tgz#b9ba4ab78efecf01fde2eecb18ec26e2a2412f6a"
- integrity sha512-DJ3gfvcdCgqi7AQxu83vx0AEUKiuJrNcSATfWV3Jqi8dH6fYO2yqpemHEeWOEy+DAHxIOaqLKwb1QjIBj+vSRQ==
+"@storybook/addon-controls@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/addon-controls/-/addon-controls-7.6.10.tgz#6cd309440bf2b86c21f11a8b5f20bc1340d6c045"
+ integrity sha512-LjwCQRMWq1apLtFwDi6U8MI6ITUr+KhxJucZ60tfc58RgB2v8ayozyDAonFEONsx9YSR1dNIJ2Z/e2rWTBJeYA==
dependencies:
- "@storybook/blocks" "7.6.7"
+ "@storybook/blocks" "7.6.10"
lodash "^4.17.21"
ts-dedent "^2.0.0"
-"@storybook/addon-docs@7.6.7":
- version "7.6.7"
- resolved "https://registry.yarnpkg.com/@storybook/addon-docs/-/addon-docs-7.6.7.tgz#47f111c4bcf0ea8f238d70219b2c65562f6810ee"
- integrity sha512-2dfajNhweofJ3LxjGO83UE5sBMvKtJB0Agj7q8mMtK/9PUCUcbvsFSyZnO/s6X1zAjSn5ZrirbSoTXU4IqxwSA==
+"@storybook/addon-docs@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/addon-docs/-/addon-docs-7.6.10.tgz#aab69f253a9cfbb57fd84062f00fac08f9c796cd"
+ integrity sha512-GtyQ9bMx1AOOtl6ZS9vwK104HFRK+tqzxddRRxhXkpyeKu3olm9aMgXp35atE/3fJSqyyDm2vFtxxH8mzBA20A==
dependencies:
"@jest/transform" "^29.3.1"
"@mdx-js/react" "^2.1.5"
- "@storybook/blocks" "7.6.7"
- "@storybook/client-logger" "7.6.7"
- "@storybook/components" "7.6.7"
- "@storybook/csf-plugin" "7.6.7"
- "@storybook/csf-tools" "7.6.7"
+ "@storybook/blocks" "7.6.10"
+ "@storybook/client-logger" "7.6.10"
+ "@storybook/components" "7.6.10"
+ "@storybook/csf-plugin" "7.6.10"
+ "@storybook/csf-tools" "7.6.10"
"@storybook/global" "^5.0.0"
"@storybook/mdx2-csf" "^1.0.0"
- "@storybook/node-logger" "7.6.7"
- "@storybook/postinstall" "7.6.7"
- "@storybook/preview-api" "7.6.7"
- "@storybook/react-dom-shim" "7.6.7"
- "@storybook/theming" "7.6.7"
- "@storybook/types" "7.6.7"
+ "@storybook/node-logger" "7.6.10"
+ "@storybook/postinstall" "7.6.10"
+ "@storybook/preview-api" "7.6.10"
+ "@storybook/react-dom-shim" "7.6.10"
+ "@storybook/theming" "7.6.10"
+ "@storybook/types" "7.6.10"
fs-extra "^11.1.0"
remark-external-links "^8.0.0"
remark-slug "^6.0.0"
ts-dedent "^2.0.0"
-"@storybook/addon-essentials@7.6.7":
- version "7.6.7"
- resolved "https://registry.yarnpkg.com/@storybook/addon-essentials/-/addon-essentials-7.6.7.tgz#6de31f175b0771739ec56dcf445dee0535f1847c"
- integrity sha512-nNLMrpIvc04z4XCA+kval/44eKAFJlUJeeL2pxwP7F/PSzjWe5BXv1bQHOiw8inRO5II0PzqwWnVCI9jsj7K5A==
- dependencies:
- "@storybook/addon-actions" "7.6.7"
- "@storybook/addon-backgrounds" "7.6.7"
- "@storybook/addon-controls" "7.6.7"
- "@storybook/addon-docs" "7.6.7"
- "@storybook/addon-highlight" "7.6.7"
- "@storybook/addon-measure" "7.6.7"
- "@storybook/addon-outline" "7.6.7"
- "@storybook/addon-toolbars" "7.6.7"
- "@storybook/addon-viewport" "7.6.7"
- "@storybook/core-common" "7.6.7"
- "@storybook/manager-api" "7.6.7"
- "@storybook/node-logger" "7.6.7"
- "@storybook/preview-api" "7.6.7"
+"@storybook/addon-essentials@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/addon-essentials/-/addon-essentials-7.6.10.tgz#9078abe56b15d976e3d4c15247c748b2e8e53c30"
+ integrity sha512-cjbuCCK/3dtUity0Uqi5LwbkgfxqCCE5x5mXZIk9lTMeDz5vB9q6M5nzncVDy8F8przF3NbDLLgxKlt8wjiICg==
+ dependencies:
+ "@storybook/addon-actions" "7.6.10"
+ "@storybook/addon-backgrounds" "7.6.10"
+ "@storybook/addon-controls" "7.6.10"
+ "@storybook/addon-docs" "7.6.10"
+ "@storybook/addon-highlight" "7.6.10"
+ "@storybook/addon-measure" "7.6.10"
+ "@storybook/addon-outline" "7.6.10"
+ "@storybook/addon-toolbars" "7.6.10"
+ "@storybook/addon-viewport" "7.6.10"
+ "@storybook/core-common" "7.6.10"
+ "@storybook/manager-api" "7.6.10"
+ "@storybook/node-logger" "7.6.10"
+ "@storybook/preview-api" "7.6.10"
ts-dedent "^2.0.0"
-"@storybook/addon-highlight@7.6.7":
- version "7.6.7"
- resolved "https://registry.yarnpkg.com/@storybook/addon-highlight/-/addon-highlight-7.6.7.tgz#53fb3ba648fcbcfafa2162299fa240b492631d0b"
- integrity sha512-2F/tJdn45d4zrvf/cmE1vsczl99wK8+I+kkj0G7jLsrJR0w1zTgbgjy6T9j86HBTBvWcnysNFNIRWPAOh5Wdbw==
+"@storybook/addon-highlight@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/addon-highlight/-/addon-highlight-7.6.10.tgz#19cad3d67655e9b9eef3d2f6760789fc29ba0790"
+ integrity sha512-dIuS5QmoT1R+gFOcf6CoBa6D9UR5/wHCfPqPRH8dNNcCLtIGSHWQ4v964mS5OCq1Huj7CghmR15lOUk7SaYwUA==
dependencies:
"@storybook/global" "^5.0.0"
-"@storybook/addon-interactions@7.6.7":
- version "7.6.7"
- resolved "https://registry.yarnpkg.com/@storybook/addon-interactions/-/addon-interactions-7.6.7.tgz#742ea9816bb6eb41abd5f22d6ebac81dc997b7ee"
- integrity sha512-iXE2m9i/1D2baYkRgoYe9zwcAjtBOxBfW4o2AS0pzBNPN7elpP9C6mIa0ScpSltawBfIjfe6iQRXAMXOsIIh3Q==
+"@storybook/addon-interactions@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/addon-interactions/-/addon-interactions-7.6.10.tgz#e1522ed169021f808401dfc46271b8c896abd258"
+ integrity sha512-lEsAdP/PrOZK/KmRbZ/fU4RjEqDP+e/PBlVVVJT2QvHniWK/xxkjCD0axsHU/XuaeQRFhmg0/KR342PC/cIf9A==
dependencies:
"@storybook/global" "^5.0.0"
- "@storybook/types" "7.6.7"
+ "@storybook/types" "7.6.10"
jest-mock "^27.0.6"
polished "^4.2.2"
ts-dedent "^2.2.0"
-"@storybook/addon-links@7.6.7":
- version "7.6.7"
- resolved "https://registry.yarnpkg.com/@storybook/addon-links/-/addon-links-7.6.7.tgz#9f9c9a259bcb383d6d139c49472a9cd932a157ff"
- integrity sha512-O5LekPslkAIDtXC/TCIyg/3c0htBxDYwb/s+NrZUPTNWJsngxvTAwp6aIk6aVSeSCFUMWvBFcVsuV3hv+ndK6w==
+"@storybook/addon-links@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/addon-links/-/addon-links-7.6.10.tgz#e437d35b360ac9a33ee6078d901417a73f916629"
+ integrity sha512-s/WkSYHpr2pb9p57j6u/xDBg3TKJhBq55YMl0GB5gXgkRPIeuGbPhGJhm2yTGVFLvXgr/aHHnOxb/R/W8PiRhA==
dependencies:
"@storybook/csf" "^0.1.2"
"@storybook/global" "^5.0.0"
ts-dedent "^2.0.0"
-"@storybook/addon-measure@7.6.7":
- version "7.6.7"
- resolved "https://registry.yarnpkg.com/@storybook/addon-measure/-/addon-measure-7.6.7.tgz#32f8c53a0cead48040017493d2d8e088038fc65d"
- integrity sha512-t1RnnNO4Xzgnsxu63FlZwsCTF0+9jKxr44NiJAUOxW9ppbCvs/JfSDOOvcDRtPWyjgnyzexNUUctMfxvLrU01A==
+"@storybook/addon-measure@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/addon-measure/-/addon-measure-7.6.10.tgz#5e41d64aa6e02b9c6df1696d918058979598250e"
+ integrity sha512-OVfTI56+kc4hLWfZ/YPV3WKj/aA9e4iKXYxZyPdhfX4Z8TgZdD1wv9Z6e8DKS0H5kuybYrHKHaID5ki6t7qz3w==
dependencies:
"@storybook/global" "^5.0.0"
tiny-invariant "^1.3.1"
@@ -5586,10 +5586,10 @@
"@storybook/telemetry" "^7.1.0"
react-confetti "^6.1.0"
-"@storybook/addon-outline@7.6.7":
- version "7.6.7"
- resolved "https://registry.yarnpkg.com/@storybook/addon-outline/-/addon-outline-7.6.7.tgz#5f33444af0c07482ee75a381742fef002fb0b52e"
- integrity sha512-gu2y46ijjMkXlxy1f8Cctgjw5b5y8vSIqNAYlrs5/Qy+hJAWyU6lj2PFGOCCUG4L+F45fAjwWAin6qz43+WnRQ==
+"@storybook/addon-outline@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/addon-outline/-/addon-outline-7.6.10.tgz#02b51084cc1d555c270995cebfe512924df0ce7e"
+ integrity sha512-RVJrEoPArhI6zAIMNl1Gz0zrj84BTfEWYYz0yDWOTVgvN411ugsoIk1hw0671MOneXJ2RcQ9MFIeV/v6AVDQYg==
dependencies:
"@storybook/global" "^5.0.0"
ts-dedent "^2.0.0"
@@ -5601,34 +5601,34 @@
dependencies:
"@storybook/node-logger" "^7.0.12"
-"@storybook/addon-toolbars@7.6.7":
- version "7.6.7"
- resolved "https://registry.yarnpkg.com/@storybook/addon-toolbars/-/addon-toolbars-7.6.7.tgz#666641dd01f5e0291b857c19c738dceac279f2da"
- integrity sha512-vT+YMzw8yVwndhJglI0XtELfXWq1M0HEy5ST3XPzbjmsJ54LgTf1b29UMkh0E/05qBQNFCcbT9B/tLxqWezxlg==
+"@storybook/addon-toolbars@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/addon-toolbars/-/addon-toolbars-7.6.10.tgz#4d841e87acca5455a8339a29c1062612ccb07df6"
+ integrity sha512-PaXY/oj9yxF7/H0CNdQKcioincyCkfeHpISZriZbZqhyqsjn3vca7RFEmsB88Q+ou6rMeqyA9st+6e2cx/Ct6A==
-"@storybook/addon-viewport@7.6.7":
- version "7.6.7"
- resolved "https://registry.yarnpkg.com/@storybook/addon-viewport/-/addon-viewport-7.6.7.tgz#ea1cdb71abf2ed3be6e6b89d78ea1f5cd506723c"
- integrity sha512-Q/BKjJaKzl4RWxH45K2iIXwkicj4ReVAUIpIyd7dPBb/Bx+hEDYZxR5dDg82AMkZdA71x5ttMnuDSuVpmWAE6g==
+"@storybook/addon-viewport@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/addon-viewport/-/addon-viewport-7.6.10.tgz#834bad76a56e4117ffb2dc935d349dca3b49bcc3"
+ integrity sha512-+bA6juC/lH4vEhk+w0rXakaG8JgLG4MOYrIudk5vJKQaC6X58LIM9N4kzIS2KSExRhkExXBPrWsnMfCo7uxmKg==
dependencies:
memoizerific "^1.11.3"
-"@storybook/blocks@7.6.7":
- version "7.6.7"
- resolved "https://registry.yarnpkg.com/@storybook/blocks/-/blocks-7.6.7.tgz#7fad3d24d9d66ddd04483156b720adcdf9d41812"
- integrity sha512-+QEvGQ0he/YvFS3lsZORJWxhQIyqcCDWsxbJxJiByePd+Z4my3q8xwtPhHW0TKRL0xUgNE/GnTfMMqJfevTuSw==
+"@storybook/blocks@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/blocks/-/blocks-7.6.10.tgz#353a5efa6a922a9a3766254f9f24cc2adad34f83"
+ integrity sha512-oSIukGC3yuF8pojABC/HLu5tv2axZvf60TaUs8eDg7+NiiKhzYSPoMQxs5uMrKngl+EJDB92ESgWT9vvsfvIPg==
dependencies:
- "@storybook/channels" "7.6.7"
- "@storybook/client-logger" "7.6.7"
- "@storybook/components" "7.6.7"
- "@storybook/core-events" "7.6.7"
+ "@storybook/channels" "7.6.10"
+ "@storybook/client-logger" "7.6.10"
+ "@storybook/components" "7.6.10"
+ "@storybook/core-events" "7.6.10"
"@storybook/csf" "^0.1.2"
- "@storybook/docs-tools" "7.6.7"
+ "@storybook/docs-tools" "7.6.10"
"@storybook/global" "^5.0.0"
- "@storybook/manager-api" "7.6.7"
- "@storybook/preview-api" "7.6.7"
- "@storybook/theming" "7.6.7"
- "@storybook/types" "7.6.7"
+ "@storybook/manager-api" "7.6.10"
+ "@storybook/preview-api" "7.6.10"
+ "@storybook/theming" "7.6.10"
+ "@storybook/types" "7.6.10"
"@types/lodash" "^4.14.167"
color-convert "^2.0.1"
dequal "^2.0.2"
@@ -5642,15 +5642,15 @@
ts-dedent "^2.0.0"
util-deprecate "^1.0.2"
-"@storybook/builder-manager@7.6.7":
- version "7.6.7"
- resolved "https://registry.yarnpkg.com/@storybook/builder-manager/-/builder-manager-7.6.7.tgz#03ac44dfd4127d147d69af495c1e9aba2d9eda9c"
- integrity sha512-6HYpj6+g/qbDMvImVz/G/aANbkhppyBa1ozfHxLK7tRD79YvozCWmj2Z9umRekPv9VIeMxnI5EEzJXOsoMX5DQ==
+"@storybook/builder-manager@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/builder-manager/-/builder-manager-7.6.10.tgz#fc30b19dd74e6f6ae896d8f4045552c3206c25f9"
+ integrity sha512-f+YrjZwohGzvfDtH8BHzqM3xW0p4vjjg9u7uzRorqUiNIAAKHpfNrZ/WvwPlPYmrpAHt4xX/nXRJae4rFSygPw==
dependencies:
"@fal-works/esbuild-plugin-global-externals" "^2.1.2"
- "@storybook/core-common" "7.6.7"
- "@storybook/manager" "7.6.7"
- "@storybook/node-logger" "7.6.7"
+ "@storybook/core-common" "7.6.10"
+ "@storybook/manager" "7.6.10"
+ "@storybook/node-logger" "7.6.10"
"@types/ejs" "^3.1.1"
"@types/find-cache-dir" "^3.2.1"
"@yarnpkg/esbuild-plugin-pnp" "^3.0.0-rc.10"
@@ -5664,26 +5664,27 @@
process "^0.11.10"
util "^0.12.4"
-"@storybook/builder-webpack5@7.6.7":
- version "7.6.7"
- resolved "https://registry.yarnpkg.com/@storybook/builder-webpack5/-/builder-webpack5-7.6.7.tgz#65c830e1bf24879ddddf5ff4163278d9fa842b28"
- integrity sha512-b5AaWXOHwIXl5Q1iRRl6eRhljId0Zsg0ANawDoubK1y1jsBoQtWal7c4TQPMeLAd2G30fc3sW5zCdb9rCo2Vrg==
+"@storybook/builder-webpack5@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/builder-webpack5/-/builder-webpack5-7.6.10.tgz#9cd8ae541e836c089e17e5f8d527b9cad6d4d99f"
+ integrity sha512-ja47rdy75tAs37T+JLSqgUGJiba+74zM/8IpEZAzgJmGxLetnHuCWEDskZWh3NXemxYS2uCvsg5rNc+dL9z4RA==
dependencies:
"@babel/core" "^7.23.2"
- "@storybook/channels" "7.6.7"
- "@storybook/client-logger" "7.6.7"
- "@storybook/core-common" "7.6.7"
- "@storybook/core-events" "7.6.7"
- "@storybook/core-webpack" "7.6.7"
- "@storybook/node-logger" "7.6.7"
- "@storybook/preview" "7.6.7"
- "@storybook/preview-api" "7.6.7"
+ "@storybook/channels" "7.6.10"
+ "@storybook/client-logger" "7.6.10"
+ "@storybook/core-common" "7.6.10"
+ "@storybook/core-events" "7.6.10"
+ "@storybook/core-webpack" "7.6.10"
+ "@storybook/node-logger" "7.6.10"
+ "@storybook/preview" "7.6.10"
+ "@storybook/preview-api" "7.6.10"
"@swc/core" "^1.3.82"
"@types/node" "^18.0.0"
"@types/semver" "^7.3.4"
babel-loader "^9.0.0"
browser-assert "^1.2.1"
case-sensitive-paths-webpack-plugin "^2.4.0"
+ cjs-module-lexer "^1.2.3"
constants-browserify "^1.0.0"
css-loader "^6.7.1"
es-module-lexer "^1.4.1"
@@ -5707,6 +5708,18 @@
webpack-hot-middleware "^2.25.1"
webpack-virtual-modules "^0.5.0"
+"@storybook/channels@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/channels/-/channels-7.6.10.tgz#04fd2c2f0b530bb8d236f5763e8df8cb5fa7c921"
+ integrity sha512-ITCLhFuDBKgxetuKnWwYqMUWlU7zsfH3gEKZltTb+9/2OAWR7ez0iqU7H6bXP1ridm0DCKkt2UMWj2mmr9iQqg==
+ dependencies:
+ "@storybook/client-logger" "7.6.10"
+ "@storybook/core-events" "7.6.10"
+ "@storybook/global" "^5.0.0"
+ qs "^6.10.0"
+ telejson "^7.2.0"
+ tiny-invariant "^1.3.1"
+
"@storybook/channels@7.6.7":
version "7.6.7"
resolved "https://registry.yarnpkg.com/@storybook/channels/-/channels-7.6.7.tgz#23a0c59ebfdfbb83e4a49d8d3fafdd25a9a67140"
@@ -5719,23 +5732,23 @@
telejson "^7.2.0"
tiny-invariant "^1.3.1"
-"@storybook/cli@7.6.7":
- version "7.6.7"
- resolved "https://registry.yarnpkg.com/@storybook/cli/-/cli-7.6.7.tgz#51f12a6cb2cdd10b78f255caca61ef12ffccebc6"
- integrity sha512-DwDWzkifBH17ry+n+d+u52Sv69dZQ+04ETJdDDzghcyAcKnFzrRNukj4tJ21cm+ZAU/r0fKR9d4Qpbogca9fAg==
+"@storybook/cli@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/cli/-/cli-7.6.10.tgz#2436276c5404b166a9f795fef44bbd75826d9bfe"
+ integrity sha512-pK1MEseMm73OMO2OVoSz79QWX8ymxgIGM8IeZTCo9gImiVRChMNDFYcv8yPWkjuyesY8c15CoO48aR7pdA1OjQ==
dependencies:
"@babel/core" "^7.23.2"
"@babel/preset-env" "^7.23.2"
"@babel/types" "^7.23.0"
"@ndelangen/get-tarball" "^3.0.7"
- "@storybook/codemod" "7.6.7"
- "@storybook/core-common" "7.6.7"
- "@storybook/core-events" "7.6.7"
- "@storybook/core-server" "7.6.7"
- "@storybook/csf-tools" "7.6.7"
- "@storybook/node-logger" "7.6.7"
- "@storybook/telemetry" "7.6.7"
- "@storybook/types" "7.6.7"
+ "@storybook/codemod" "7.6.10"
+ "@storybook/core-common" "7.6.10"
+ "@storybook/core-events" "7.6.10"
+ "@storybook/core-server" "7.6.10"
+ "@storybook/csf-tools" "7.6.10"
+ "@storybook/node-logger" "7.6.10"
+ "@storybook/telemetry" "7.6.10"
+ "@storybook/types" "7.6.10"
"@types/semver" "^7.3.4"
"@yarnpkg/fslib" "2.10.3"
"@yarnpkg/libzip" "2.3.0"
@@ -5760,12 +5773,18 @@
puppeteer-core "^2.1.1"
read-pkg-up "^7.0.1"
semver "^7.3.7"
- simple-update-notifier "^2.0.0"
strip-json-comments "^3.0.1"
tempy "^1.0.1"
ts-dedent "^2.0.0"
util-deprecate "^1.0.2"
+"@storybook/client-logger@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/client-logger/-/client-logger-7.6.10.tgz#5d66feb18a21836f84b63f71cf5b3a85d669f049"
+ integrity sha512-U7bbpu21ntgePMz/mKM18qvCSWCUGCUlYru8mgVlXLCKqFqfTeP887+CsPEQf29aoE3cLgDrxqbRJ1wxX9kL9A==
+ dependencies:
+ "@storybook/global" "^5.0.0"
+
"@storybook/client-logger@7.6.7":
version "7.6.7"
resolved "https://registry.yarnpkg.com/@storybook/client-logger/-/client-logger-7.6.7.tgz#a2cb75a668c09bf091c1925c3403e3f2f8b1e4e1"
@@ -5773,18 +5792,18 @@
dependencies:
"@storybook/global" "^5.0.0"
-"@storybook/codemod@7.6.7":
- version "7.6.7"
- resolved "https://registry.yarnpkg.com/@storybook/codemod/-/codemod-7.6.7.tgz#49ee0e824dcb0ae8f1d887266e82ee694d149b6f"
- integrity sha512-an2pD5OHqO7CE8Wb7JxjrDnpQgeoxB22MyOs8PPJ9Rvclhpjg+Ku9RogoObYm//zR4g406l7Ec8mTltUkVCEOA==
+"@storybook/codemod@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/codemod/-/codemod-7.6.10.tgz#21cc0e69df6f57d567fc27264310f820662d62fa"
+ integrity sha512-pzFR0nocBb94vN9QCJLC3C3dP734ZigqyPmd0ZCDj9Xce2ytfHK3v1lKB6TZWzKAZT8zztauECYxrbo4LVuagw==
dependencies:
"@babel/core" "^7.23.2"
"@babel/preset-env" "^7.23.2"
"@babel/types" "^7.23.0"
"@storybook/csf" "^0.1.2"
- "@storybook/csf-tools" "7.6.7"
- "@storybook/node-logger" "7.6.7"
- "@storybook/types" "7.6.7"
+ "@storybook/csf-tools" "7.6.10"
+ "@storybook/node-logger" "7.6.10"
+ "@storybook/types" "7.6.10"
"@types/cross-spawn" "^6.0.2"
cross-spawn "^7.0.3"
globby "^11.0.2"
@@ -5793,29 +5812,58 @@
prettier "^2.8.0"
recast "^0.23.1"
-"@storybook/components@7.6.7":
- version "7.6.7"
- resolved "https://registry.yarnpkg.com/@storybook/components/-/components-7.6.7.tgz#a9d58745b7a11cd7fcb154cfebdbd22b9d210c4e"
- integrity sha512-1HN4p+MCI4Tx9VGZayZyqbW7SB7mXQLnS5fUbTE1gXaMYHpzFvcrRNROeV1LZPClJX6qx1jgE5ngZojhxGuxMA==
+"@storybook/components@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/components/-/components-7.6.10.tgz#2d1b8c66c374327663b91f65db3b1be5749a1a6b"
+ integrity sha512-H5hF8pxwtbt0LxV24KMMsPlbYG9Oiui3ObvAQkvGu6q62EYxRPeNSrq3GBI5XEbI33OJY9bT24cVaZx18dXqwQ==
dependencies:
"@radix-ui/react-select" "^1.2.2"
"@radix-ui/react-toolbar" "^1.0.4"
- "@storybook/client-logger" "7.6.7"
+ "@storybook/client-logger" "7.6.10"
"@storybook/csf" "^0.1.2"
"@storybook/global" "^5.0.0"
- "@storybook/theming" "7.6.7"
- "@storybook/types" "7.6.7"
+ "@storybook/theming" "7.6.10"
+ "@storybook/types" "7.6.10"
memoizerific "^1.11.3"
use-resize-observer "^9.1.0"
util-deprecate "^1.0.2"
-"@storybook/core-client@7.6.7":
- version "7.6.7"
- resolved "https://registry.yarnpkg.com/@storybook/core-client/-/core-client-7.6.7.tgz#5dfd61519101ead2056a2f2b6ef3f265b257899a"
- integrity sha512-ZQivyEzYsZok8vRj5Qan7LbiMUnO89rueWzTnZs4IS6JIaQtjoPI1rGVq+h6qOCM6tki478hic8FS+zwGQ6q+w==
+"@storybook/core-client@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/core-client/-/core-client-7.6.10.tgz#cd427d7017c1f32b2e956b4eb8ea89f3424b60c9"
+ integrity sha512-DjnzSzSNDmZyxyg6TxugzWQwOsW+n/iWVv6sHNEvEd5STr0mjuJjIEELmv58LIr5Lsre5+LEddqHsyuLyt8ubg==
dependencies:
- "@storybook/client-logger" "7.6.7"
- "@storybook/preview-api" "7.6.7"
+ "@storybook/client-logger" "7.6.10"
+ "@storybook/preview-api" "7.6.10"
+
+"@storybook/core-common@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/core-common/-/core-common-7.6.10.tgz#00b73761eb3c4452105a7d79b5179237a6f01b32"
+ integrity sha512-K3YWqjCKMnpvYsWNjOciwTH6zWbuuZzmOiipziZaVJ+sB1XYmH52Y3WGEm07TZI8AYK9DRgwA13dR/7W0nw72Q==
+ dependencies:
+ "@storybook/core-events" "7.6.10"
+ "@storybook/node-logger" "7.6.10"
+ "@storybook/types" "7.6.10"
+ "@types/find-cache-dir" "^3.2.1"
+ "@types/node" "^18.0.0"
+ "@types/node-fetch" "^2.6.4"
+ "@types/pretty-hrtime" "^1.0.0"
+ chalk "^4.1.0"
+ esbuild "^0.18.0"
+ esbuild-register "^3.5.0"
+ file-system-cache "2.3.0"
+ find-cache-dir "^3.0.0"
+ find-up "^5.0.0"
+ fs-extra "^11.1.0"
+ glob "^10.0.0"
+ handlebars "^4.7.7"
+ lazy-universal-dotenv "^4.0.0"
+ node-fetch "^2.0.0"
+ picomatch "^2.3.0"
+ pkg-dir "^5.0.0"
+ pretty-hrtime "^1.0.3"
+ resolve-from "^5.0.0"
+ ts-dedent "^2.0.0"
"@storybook/core-common@7.6.7":
version "7.6.7"
@@ -5846,6 +5894,13 @@
resolve-from "^5.0.0"
ts-dedent "^2.0.0"
+"@storybook/core-events@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/core-events/-/core-events-7.6.10.tgz#d521cbdadebfa56caaa8815a1e132694a20f05e9"
+ integrity sha512-yccDH67KoROrdZbRKwxgTswFMAco5nlCyxszCDASCLygGSV2Q2e+YuywrhchQl3U6joiWi3Ps1qWu56NeNafag==
+ dependencies:
+ ts-dedent "^2.0.0"
+
"@storybook/core-events@7.6.7":
version "7.6.7"
resolved "https://registry.yarnpkg.com/@storybook/core-events/-/core-events-7.6.7.tgz#ee8823090cc4e30fddebe72be29738e4b2e66b11"
@@ -5853,26 +5908,26 @@
dependencies:
ts-dedent "^2.0.0"
-"@storybook/core-server@7.6.7":
- version "7.6.7"
- resolved "https://registry.yarnpkg.com/@storybook/core-server/-/core-server-7.6.7.tgz#6d1c3b0d71296bf00438ba5112156f96fc78b2cb"
- integrity sha512-elKRv/DNahNNkGcQY/FdOBrLPmZF0T0fwmAmbc4qqeAisjl+to9TO77zdo2ieaEHKyRwE3B3dOB4EXomdF4N/g==
+"@storybook/core-server@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/core-server/-/core-server-7.6.10.tgz#53bf43b8b3c999c87196774a0b92e2e10a434e4c"
+ integrity sha512-2icnqJkn3vwq0eJPP0rNaHd7IOvxYf5q4lSVl2AWTxo/Ae19KhokI6j/2vvS2XQJMGQszwshlIwrZUNsj5p0yw==
dependencies:
"@aw-web-design/x-default-browser" "1.4.126"
"@discoveryjs/json-ext" "^0.5.3"
- "@storybook/builder-manager" "7.6.7"
- "@storybook/channels" "7.6.7"
- "@storybook/core-common" "7.6.7"
- "@storybook/core-events" "7.6.7"
+ "@storybook/builder-manager" "7.6.10"
+ "@storybook/channels" "7.6.10"
+ "@storybook/core-common" "7.6.10"
+ "@storybook/core-events" "7.6.10"
"@storybook/csf" "^0.1.2"
- "@storybook/csf-tools" "7.6.7"
+ "@storybook/csf-tools" "7.6.10"
"@storybook/docs-mdx" "^0.1.0"
"@storybook/global" "^5.0.0"
- "@storybook/manager" "7.6.7"
- "@storybook/node-logger" "7.6.7"
- "@storybook/preview-api" "7.6.7"
- "@storybook/telemetry" "7.6.7"
- "@storybook/types" "7.6.7"
+ "@storybook/manager" "7.6.10"
+ "@storybook/node-logger" "7.6.10"
+ "@storybook/preview-api" "7.6.10"
+ "@storybook/telemetry" "7.6.10"
+ "@storybook/types" "7.6.10"
"@types/detect-port" "^1.3.0"
"@types/node" "^18.0.0"
"@types/pretty-hrtime" "^1.0.0"
@@ -5900,25 +5955,40 @@
watchpack "^2.2.0"
ws "^8.2.3"
-"@storybook/core-webpack@7.6.7":
- version "7.6.7"
- resolved "https://registry.yarnpkg.com/@storybook/core-webpack/-/core-webpack-7.6.7.tgz#ca7d70171e104403709d83d8ad8a4027cee5b5c1"
- integrity sha512-+UpjJc1fXs9KPIRbTzsBVDgsGQb+VlU3Z7w7XJM1M6ERQrvNAX3oj0iLdDK/AO1ks1qTg+meLFnVwpgKxcTTqg==
+"@storybook/core-webpack@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/core-webpack/-/core-webpack-7.6.10.tgz#e4ca086973d4d10f08b5bed789f1398eb983d8b1"
+ integrity sha512-+GiCRp+2Hw0NO3NYRKamG/U5SyOQ8tOfRUxuAqWI7nduXwB3WWdjji3/ofjqOm/ryKesuQFtfhozaczvBJBvng==
dependencies:
- "@storybook/core-common" "7.6.7"
- "@storybook/node-logger" "7.6.7"
- "@storybook/types" "7.6.7"
+ "@storybook/core-common" "7.6.10"
+ "@storybook/node-logger" "7.6.10"
+ "@storybook/types" "7.6.10"
"@types/node" "^18.0.0"
ts-dedent "^2.0.0"
-"@storybook/csf-plugin@7.6.7":
- version "7.6.7"
- resolved "https://registry.yarnpkg.com/@storybook/csf-plugin/-/csf-plugin-7.6.7.tgz#c4eb87aab082febd8d13dd6c20a01bb2f2bc19af"
- integrity sha512-YL7e6H4iVcsDI0UpgpdQX2IiGDrlbgaQMHQgDLWXmZyKxBcy0ONROAX5zoT1ml44EHkL60TMaG4f7SinviJCog==
+"@storybook/csf-plugin@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/csf-plugin/-/csf-plugin-7.6.10.tgz#479cffe04c68a87f60589a6891a306805c758437"
+ integrity sha512-Sc+zZg/BnPH2X28tthNaQBnDiFfO0QmfjVoOx0fGYM9SvY3P5ehzWwp5hMRBim6a/twOTzePADtqYL+t6GMqqg==
dependencies:
- "@storybook/csf-tools" "7.6.7"
+ "@storybook/csf-tools" "7.6.10"
unplugin "^1.3.1"
+"@storybook/csf-tools@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/csf-tools/-/csf-tools-7.6.10.tgz#320638f64e2e14cf539dd55188f676fd82789be5"
+ integrity sha512-TnDNAwIALcN6SA4l00Cb67G02XMOrYU38bIpFJk5VMDX2dvgPjUtJNBuLmEbybGcOt7nPyyFIHzKcY5FCVGoWA==
+ dependencies:
+ "@babel/generator" "^7.23.0"
+ "@babel/parser" "^7.23.0"
+ "@babel/traverse" "^7.23.2"
+ "@babel/types" "^7.23.0"
+ "@storybook/csf" "^0.1.2"
+ "@storybook/types" "7.6.10"
+ fs-extra "^11.1.0"
+ recast "^0.23.1"
+ ts-dedent "^2.0.0"
+
"@storybook/csf-tools@7.6.7":
version "7.6.7"
resolved "https://registry.yarnpkg.com/@storybook/csf-tools/-/csf-tools-7.6.7.tgz#1707bc5d6289ec79aeab472877aadda76def5015"
@@ -5953,14 +6023,14 @@
resolved "https://registry.yarnpkg.com/@storybook/docs-mdx/-/docs-mdx-0.1.0.tgz#33ba0e39d1461caf048b57db354b2cc410705316"
integrity sha512-JDaBR9lwVY4eSH5W8EGHrhODjygPd6QImRbwjAuJNEnY0Vw4ie3bPkeGfnacB3OBW6u/agqPv2aRlR46JcAQLg==
-"@storybook/docs-tools@7.6.7":
- version "7.6.7"
- resolved "https://registry.yarnpkg.com/@storybook/docs-tools/-/docs-tools-7.6.7.tgz#dc496827c50e9ae30dffd0f42076dd085b9b2cd3"
- integrity sha512-enTO/xVjBqwUraGCYTwdyjMvug3OSAM7TPPUEJ3KPieJNwAzcYkww/qNDMIAR4S39zPMrkAmtS3STvVadlJz7g==
+"@storybook/docs-tools@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/docs-tools/-/docs-tools-7.6.10.tgz#90ce6bcf468b8d0a479fb75e9a6ff87f482095dc"
+ integrity sha512-UgbikducoXzqQHf2TozO0f2rshaeBNnShVbL5Ai4oW7pDymBmrfzdjGbF/milO7yxNKcoIByeoNmu384eBamgQ==
dependencies:
- "@storybook/core-common" "7.6.7"
- "@storybook/preview-api" "7.6.7"
- "@storybook/types" "7.6.7"
+ "@storybook/core-common" "7.6.10"
+ "@storybook/preview-api" "7.6.10"
+ "@storybook/types" "7.6.10"
"@types/doctrine" "^0.0.3"
assert "^2.1.0"
doctrine "^3.0.0"
@@ -5971,32 +6041,32 @@
resolved "https://registry.yarnpkg.com/@storybook/global/-/global-5.0.0.tgz#b793d34b94f572c1d7d9e0f44fac4e0dbc9572ed"
integrity sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==
-"@storybook/instrumenter@7.6.7":
- version "7.6.7"
- resolved "https://registry.yarnpkg.com/@storybook/instrumenter/-/instrumenter-7.6.7.tgz#ee2900821da3c10e38e56805362573c459e34a9a"
- integrity sha512-Q4NstXZKCk62MkP7jgpg5CRFmhszg9QdoN8CwffuUGtjQRADhmeRHgP4usB87Sg6Tq9MLSopAEqUZxlKKYeeag==
+"@storybook/instrumenter@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/instrumenter/-/instrumenter-7.6.10.tgz#e5ba21e9574263b2ef3d225eac4e0f3d0bc3edee"
+ integrity sha512-9FYXW1CKXnZ7yYmy2A6U0seqJMe1F7g55J28Vslk3ZLoGATFJ2BR0eoQS+cgfBly6djehjaVeuV3IcUYGnQ/6Q==
dependencies:
- "@storybook/channels" "7.6.7"
- "@storybook/client-logger" "7.6.7"
- "@storybook/core-events" "7.6.7"
+ "@storybook/channels" "7.6.10"
+ "@storybook/client-logger" "7.6.10"
+ "@storybook/core-events" "7.6.10"
"@storybook/global" "^5.0.0"
- "@storybook/preview-api" "7.6.7"
+ "@storybook/preview-api" "7.6.10"
"@vitest/utils" "^0.34.6"
util "^0.12.4"
-"@storybook/manager-api@7.6.7":
- version "7.6.7"
- resolved "https://registry.yarnpkg.com/@storybook/manager-api/-/manager-api-7.6.7.tgz#6e7816df4e789aca73456a383d8da8fc984b7815"
- integrity sha512-3Wk/BvuGUlw/X05s57zZO7gJbzfUeE9Xe+CSIvuH7RY5jx9PYnNwqNlTXPXhJ5LPvwMthae7WJVn3SuBpbptoQ==
+"@storybook/manager-api@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/manager-api/-/manager-api-7.6.10.tgz#0c2932f42bb97de8fb25240844fcf64474fc8905"
+ integrity sha512-8eGVpRlpunuFScDtc7nxpPJf/4kJBAAZlNdlhmX09j8M3voX6GpcxabBamSEX5pXZqhwxQCshD4IbqBmjvadlw==
dependencies:
- "@storybook/channels" "7.6.7"
- "@storybook/client-logger" "7.6.7"
- "@storybook/core-events" "7.6.7"
+ "@storybook/channels" "7.6.10"
+ "@storybook/client-logger" "7.6.10"
+ "@storybook/core-events" "7.6.10"
"@storybook/csf" "^0.1.2"
"@storybook/global" "^5.0.0"
- "@storybook/router" "7.6.7"
- "@storybook/theming" "7.6.7"
- "@storybook/types" "7.6.7"
+ "@storybook/router" "7.6.10"
+ "@storybook/theming" "7.6.10"
+ "@storybook/types" "7.6.10"
dequal "^2.0.2"
lodash "^4.17.21"
memoizerific "^1.11.3"
@@ -6004,38 +6074,43 @@
telejson "^7.2.0"
ts-dedent "^2.0.0"
-"@storybook/manager@7.6.7":
- version "7.6.7"
- resolved "https://registry.yarnpkg.com/@storybook/manager/-/manager-7.6.7.tgz#993b4dd4800496ee4161c29e853efe7ee2c1a67f"
- integrity sha512-ZCrkB2zEXogzdOcVzD242ZVm4tlHqrayotnI6iOn9uiun0Pgny0m2d7s9Zge6K2dTOO1vZiOHuA/Mr6nnIDjsA==
+"@storybook/manager@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/manager/-/manager-7.6.10.tgz#eb1b71c802fbf04353f3bf017dfb102eb0db217e"
+ integrity sha512-Co3sLCbNYY6O4iH2ggmRDLCPWLj03JE5s/DOG8OVoXc6vBwTc/Qgiyrsxxp6BHQnPpM0mxL6aKAxE3UjsW/Nog==
"@storybook/mdx2-csf@^1.0.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@storybook/mdx2-csf/-/mdx2-csf-1.1.0.tgz#97f6df04d0bf616991cc1005a073ac004a7281e5"
integrity sha512-TXJJd5RAKakWx4BtpwvSNdgTDkKM6RkXU8GK34S/LhidQ5Pjz3wcnqb0TxEkfhK/ztbP8nKHqXFwLfa2CYkvQw==
+"@storybook/node-logger@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/node-logger/-/node-logger-7.6.10.tgz#d4c52d04384d2728d6610fb0afff6eb1feb50fd4"
+ integrity sha512-ZBuqrv4bjJzKXyfRGFkVIi+z6ekn6rOPoQao4KmsfLNQAUUsEdR8Baw/zMnnU417zw5dSEaZdpuwx75SCQAeOA==
+
"@storybook/node-logger@7.6.7", "@storybook/node-logger@^7.0.12":
version "7.6.7"
resolved "https://registry.yarnpkg.com/@storybook/node-logger/-/node-logger-7.6.7.tgz#35cee2b3e4d234b0b0735715d8856dc141d4a9b0"
integrity sha512-XLih8MxylkpZG9+8tgp8sPGc2tldlWF+DpuAkUv6J3Mc81mPyc3cQKQWZ7Hb+m1LpRGqKV4wyOQj1rC+leVMoQ==
-"@storybook/postinstall@7.6.7":
- version "7.6.7"
- resolved "https://registry.yarnpkg.com/@storybook/postinstall/-/postinstall-7.6.7.tgz#edb389a2b2d5c85cdf5dfdcc3f19971437e24e89"
- integrity sha512-mrpRmcwFd9FcvtHPXA9x6vOrHLVCKScZX/Xx2QPWgAvB3W6uzP8G+8QNb1u834iToxrWeuszUMB9UXZK4Qj5yg==
+"@storybook/postinstall@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/postinstall/-/postinstall-7.6.10.tgz#9e81c54b1f23f71a59a6db7ee8a4d5ac40852d17"
+ integrity sha512-SMdXtednPCy3+SRJ7oN1OPN1oVFhj3ih+ChOEX8/kZ5J3nfmV3wLPtsZvFGUCf0KWQEP1xL+1Urv48mzMKcV/w==
-"@storybook/preset-react-webpack@7.6.7":
- version "7.6.7"
- resolved "https://registry.yarnpkg.com/@storybook/preset-react-webpack/-/preset-react-webpack-7.6.7.tgz#e5eb2a516a7590b46d146c9a3b9caca333327324"
- integrity sha512-olKTivJmbyuiPIa99/4Gx3zxbBplyXgbNso9ZAXHnSf7rBD0irV5oRqk+gFlEFJDHkK9vnpWMenly7vzX8QCXQ==
+"@storybook/preset-react-webpack@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/preset-react-webpack/-/preset-react-webpack-7.6.10.tgz#86b34f7156258ddf6481bffd6c638e5382d01054"
+ integrity sha512-fUcr4dmXJdPIQdjkhA4bE8QF8Pavr4BSLxovtTRupbWxtRjZxJrH5hf+0HZycq1cp9umO/11Lsmw9Nx5Xg3Eww==
dependencies:
"@babel/preset-flow" "^7.22.15"
"@babel/preset-react" "^7.22.15"
"@pmmmwh/react-refresh-webpack-plugin" "^0.5.11"
- "@storybook/core-webpack" "7.6.7"
- "@storybook/docs-tools" "7.6.7"
- "@storybook/node-logger" "7.6.7"
- "@storybook/react" "7.6.7"
+ "@storybook/core-webpack" "7.6.10"
+ "@storybook/docs-tools" "7.6.10"
+ "@storybook/node-logger" "7.6.10"
+ "@storybook/react" "7.6.10"
"@storybook/react-docgen-typescript-plugin" "1.0.6--canary.9.0c3f3b7.0"
"@types/node" "^18.0.0"
"@types/semver" "^7.3.4"
@@ -6047,17 +6122,17 @@
semver "^7.3.7"
webpack "5"
-"@storybook/preview-api@7.6.7":
- version "7.6.7"
- resolved "https://registry.yarnpkg.com/@storybook/preview-api/-/preview-api-7.6.7.tgz#4f963c95749157f0f9db7fc92c431214057f90e8"
- integrity sha512-ja85ItrT6q2TeBQ6n0CNoRi1R6L8yF2kkis9hVeTQHpwLdZyHUTRqqR5WmhtLqqQXcofyasBPOeJV06wuOhgRQ==
+"@storybook/preview-api@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/preview-api/-/preview-api-7.6.10.tgz#b8d5a4f897745fc28f0ae75f7e0e9278b0e4a50a"
+ integrity sha512-5A3etoIwZCx05yuv3KSTv1wynN4SR4rrzaIs/CTBp3BC4q1RBL+Or/tClk0IJPXQMlx/4Y134GtNIBbkiDofpw==
dependencies:
- "@storybook/channels" "7.6.7"
- "@storybook/client-logger" "7.6.7"
- "@storybook/core-events" "7.6.7"
+ "@storybook/channels" "7.6.10"
+ "@storybook/client-logger" "7.6.10"
+ "@storybook/core-events" "7.6.10"
"@storybook/csf" "^0.1.2"
"@storybook/global" "^5.0.0"
- "@storybook/types" "7.6.7"
+ "@storybook/types" "7.6.10"
"@types/qs" "^6.9.5"
dequal "^2.0.2"
lodash "^4.17.21"
@@ -6067,10 +6142,10 @@
ts-dedent "^2.0.0"
util-deprecate "^1.0.2"
-"@storybook/preview@7.6.7":
- version "7.6.7"
- resolved "https://registry.yarnpkg.com/@storybook/preview/-/preview-7.6.7.tgz#50b70a58f9a8f95273e1fd963bbe358935b04dde"
- integrity sha512-/ddKIyT+6b8CKGJAma1wood4nwCAoi/E1olCqgpCmviMeUtAiMzgK0xzPwvq5Mxkz/cPeXVi8CQgaQZCa4yvNA==
+"@storybook/preview@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/preview/-/preview-7.6.10.tgz#895053c97f7e09141c6321fa42390fa8af377bef"
+ integrity sha512-F07BzVXTD3byq+KTWtvsw3pUu3fQbyiBNLFr2CnfU4XSdLKja5lDt8VqDQq70TayVQOf5qfUTzRd4M6pQkjw1w==
"@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0":
version "1.0.6--canary.9.0c3f3b7.0"
@@ -6085,33 +6160,33 @@
react-docgen-typescript "^2.2.2"
tslib "^2.0.0"
-"@storybook/react-dom-shim@7.6.7":
- version "7.6.7"
- resolved "https://registry.yarnpkg.com/@storybook/react-dom-shim/-/react-dom-shim-7.6.7.tgz#73db51e895998e91984de751814b22cf7cdfb426"
- integrity sha512-b/rmy/YzVrwP+ifyZG4yXVIdeFVdTbmziodHUlbrWiUNsqtTZZur9kqkKRUH/7ofji9MFe81nd0MRlcTNFomqg==
+"@storybook/react-dom-shim@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/react-dom-shim/-/react-dom-shim-7.6.10.tgz#d16df5d65a51ed66df92430d8f51d50bd177f2c2"
+ integrity sha512-M+N/h6ximacaFdIDjMN2waNoWwApeVYTpFeoDppiFTvdBTXChyIuiPgYX9QSg7gDz92OaA52myGOot4wGvXVzg==
-"@storybook/react-webpack5@7.6.7":
- version "7.6.7"
- resolved "https://registry.yarnpkg.com/@storybook/react-webpack5/-/react-webpack5-7.6.7.tgz#a31658bc9d8129bf359dc2d73a566f381093de67"
- integrity sha512-/HK+v8vmeApN4WI5RyaDdhPhjFuEQfMQmvZLl+ewpamhJNMRr4nvrdvxOSfBw46zFubKgieuxEcW+VxHwvZ1og==
+"@storybook/react-webpack5@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/react-webpack5/-/react-webpack5-7.6.10.tgz#f9d3cb4abc4177d43cefcc62d497b2cbee2b5181"
+ integrity sha512-LWwasiSLEg4wqsMjoRHcOn6BXv2ZyZfTfQV7gCvaX732xf0teblh+/GltAz8x+BtFXruXWmZ8bJ5cd9U4I6hUg==
dependencies:
- "@storybook/builder-webpack5" "7.6.7"
- "@storybook/preset-react-webpack" "7.6.7"
- "@storybook/react" "7.6.7"
+ "@storybook/builder-webpack5" "7.6.10"
+ "@storybook/preset-react-webpack" "7.6.10"
+ "@storybook/react" "7.6.10"
"@types/node" "^18.0.0"
-"@storybook/react@7.6.7":
- version "7.6.7"
- resolved "https://registry.yarnpkg.com/@storybook/react/-/react-7.6.7.tgz#53af9e97c1c3d0a59601637f655cefb93a426505"
- integrity sha512-uT9IBPDM1SQg6FglWqb7IemOJ1Z8kYB5rehIDEDToi0u5INihSY8rHd003TxG4Wx4REp6J+rfbDJO2aVui/gxA==
+"@storybook/react@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/react/-/react-7.6.10.tgz#aca5c446f43de75981f19d112a8a04d7abd0a03d"
+ integrity sha512-wwBn1cg2uZWW4peqqBjjU7XGmFq8HdkVUtWwh6dpfgmlY1Aopi+vPgZt7pY9KkWcTOq5+DerMdSfwxukpc3ajQ==
dependencies:
- "@storybook/client-logger" "7.6.7"
- "@storybook/core-client" "7.6.7"
- "@storybook/docs-tools" "7.6.7"
+ "@storybook/client-logger" "7.6.10"
+ "@storybook/core-client" "7.6.10"
+ "@storybook/docs-tools" "7.6.10"
"@storybook/global" "^5.0.0"
- "@storybook/preview-api" "7.6.7"
- "@storybook/react-dom-shim" "7.6.7"
- "@storybook/types" "7.6.7"
+ "@storybook/preview-api" "7.6.10"
+ "@storybook/react-dom-shim" "7.6.10"
+ "@storybook/types" "7.6.10"
"@types/escodegen" "^0.0.6"
"@types/estree" "^0.0.51"
"@types/node" "^18.0.0"
@@ -6127,16 +6202,30 @@
type-fest "~2.19"
util-deprecate "^1.0.2"
-"@storybook/router@7.6.7":
- version "7.6.7"
- resolved "https://registry.yarnpkg.com/@storybook/router/-/router-7.6.7.tgz#790eed44a20496376c6e6fad2dc79c18bb79d28e"
- integrity sha512-kkhNSdC3fXaQxILg8a26RKk4/ZbF/AUVrepUEyO8lwvbJ6LItTyWSE/4I9Ih4qV2Mjx33ncc8vLqM9p8r5qnMA==
+"@storybook/router@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/router/-/router-7.6.10.tgz#b1f2c550eeb9f7146eefa33c5460e4149a62d721"
+ integrity sha512-G/H4Jn2+y8PDe8Zbq4DVxF/TPn0/goSItdILts39JENucHiuGBCjKjSWGBe1rkwKi1tUbB3yhxJVrLagxFEPpQ==
dependencies:
- "@storybook/client-logger" "7.6.7"
+ "@storybook/client-logger" "7.6.10"
memoizerific "^1.11.3"
qs "^6.10.0"
-"@storybook/telemetry@7.6.7", "@storybook/telemetry@^7.1.0":
+"@storybook/telemetry@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/telemetry/-/telemetry-7.6.10.tgz#31c0edfb9c7005cf9b5922e51ca896218e3d81ea"
+ integrity sha512-p3mOSUtIyy2tF1z6pQXxNh1JzYFcAm97nUgkwLzF07GfEdVAPM+ftRSLFbD93zVvLEkmLTlsTiiKaDvOY/lQWg==
+ dependencies:
+ "@storybook/client-logger" "7.6.10"
+ "@storybook/core-common" "7.6.10"
+ "@storybook/csf-tools" "7.6.10"
+ chalk "^4.1.0"
+ detect-package-manager "^2.0.1"
+ fetch-retry "^5.0.2"
+ fs-extra "^11.1.0"
+ read-pkg-up "^7.0.1"
+
+"@storybook/telemetry@^7.1.0":
version "7.6.7"
resolved "https://registry.yarnpkg.com/@storybook/telemetry/-/telemetry-7.6.7.tgz#46aed41588fca4f081a9127c473cde1ae8b954e0"
integrity sha512-NHGzC/LGLXpK4AFbVj8ln5ab86ZiiNFvORQMn3+LNGwUt3ZdsHBzExN+WPZdw7OPtfk4ubUY89FXH2GedhTALw==
@@ -6150,15 +6239,15 @@
fs-extra "^11.1.0"
read-pkg-up "^7.0.1"
-"@storybook/test@7.6.7":
- version "7.6.7"
- resolved "https://registry.yarnpkg.com/@storybook/test/-/test-7.6.7.tgz#875e9f181847ba9a8477fe0e503a916ff5c054c4"
- integrity sha512-6gyRIvtOSq/ODYjpUO8LgY1YlWoYINhhKtLKwZasbp8hQ0zkd2vRSWlVCwzsw28cZXo2UL92UNSgEVD1sf73Qg==
+"@storybook/test@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/test/-/test-7.6.10.tgz#d27e626b1124918a1a0eddb7bfa2079952bf31d8"
+ integrity sha512-dn/T+HcWOBlVh3c74BHurp++BaqBoQgNbSIaXlYDpJoZ+DzNIoEQVsWFYm5gCbtKK27iFd4n52RiQI3f6Vblqw==
dependencies:
- "@storybook/client-logger" "7.6.7"
- "@storybook/core-events" "7.6.7"
- "@storybook/instrumenter" "7.6.7"
- "@storybook/preview-api" "7.6.7"
+ "@storybook/client-logger" "7.6.10"
+ "@storybook/core-events" "7.6.10"
+ "@storybook/instrumenter" "7.6.10"
+ "@storybook/preview-api" "7.6.10"
"@testing-library/dom" "^9.3.1"
"@testing-library/jest-dom" "^6.1.3"
"@testing-library/user-event" "14.3.0"
@@ -6168,16 +6257,26 @@
chai "^4.3.7"
util "^0.12.4"
-"@storybook/theming@7.6.7":
- version "7.6.7"
- resolved "https://registry.yarnpkg.com/@storybook/theming/-/theming-7.6.7.tgz#82450f9c8f59c266e2fa22a1d893fb14bb690d37"
- integrity sha512-+42rfC4rZtWVAXJ7JBUQKnQ6vWBXJVHZ9HtNUWzQLPR9sJSMmHnnSMV6y5tizGgZqmBnAIkuoYk+Tt6NfwUmSA==
+"@storybook/theming@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/theming/-/theming-7.6.10.tgz#c09d66d19f5756964cc89b1f94051545fc4aaea7"
+ integrity sha512-f5tuy7yV3TOP3fIboSqpgLHy0wKayAw/M8HxX0jVET4Z4fWlFK0BiHJabQ+XEdAfQM97XhPFHB2IPbwsqhCEcQ==
dependencies:
"@emotion/use-insertion-effect-with-fallbacks" "^1.0.0"
- "@storybook/client-logger" "7.6.7"
+ "@storybook/client-logger" "7.6.10"
"@storybook/global" "^5.0.0"
memoizerific "^1.11.3"
+"@storybook/types@7.6.10":
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/@storybook/types/-/types-7.6.10.tgz#20cfb2dfeba2ecf54721de131276041d073fe42e"
+ integrity sha512-hcS2HloJblaMpCAj2axgGV+53kgSRYPT0a1PG1IHsZaYQILfHSMmBqM8XzXXYTsgf9250kz3dqFX1l0n3EqMlQ==
+ dependencies:
+ "@storybook/channels" "7.6.10"
+ "@types/babel__core" "^7.0.0"
+ "@types/express" "^4.7.0"
+ file-system-cache "2.3.0"
+
"@storybook/types@7.6.7":
version "7.6.7"
resolved "https://registry.yarnpkg.com/@storybook/types/-/types-7.6.7.tgz#f3935fbd3ba7f958e18106fd1626452a8961ef8c"
@@ -9673,6 +9772,11 @@ citty@^0.1.5:
dependencies:
consola "^3.2.3"
+cjs-module-lexer@^1.2.3:
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz#6c370ab19f8a3394e318fe682686ec0ac684d107"
+ integrity sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==
+
clarity-codegen@^0.2.6:
version "0.2.6"
resolved "https://registry.yarnpkg.com/clarity-codegen/-/clarity-codegen-0.2.6.tgz#897bfdc0374279c3a6dceebbe83bb6b553d6184b"
@@ -18487,13 +18591,6 @@ simple-swizzle@^0.2.2:
dependencies:
is-arrayish "^0.3.1"
-simple-update-notifier@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz#d70b92bdab7d6d90dfd73931195a30b6e3d7cebb"
- integrity sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==
- dependencies:
- semver "^7.5.3"
-
sirv@^2.0.3:
version "2.0.4"
resolved "https://registry.yarnpkg.com/sirv/-/sirv-2.0.4.tgz#5dd9a725c578e34e449f332703eb2a74e46a29b0"
@@ -18827,12 +18924,12 @@ store2@^2.14.2:
resolved "https://registry.yarnpkg.com/store2/-/store2-2.14.2.tgz#56138d200f9fe5f582ad63bc2704dbc0e4a45068"
integrity sha512-siT1RiqlfQnGqgT/YzXVUNsom9S0H1OX+dpdGN1xkyYATo4I6sep5NmsRD/40s3IIOvlCq6akxkqG82urIZW1w==
-storybook@7.6.7:
- version "7.6.7"
- resolved "https://registry.yarnpkg.com/storybook/-/storybook-7.6.7.tgz#90865997e806cbce278481fce1bb5be1984964fc"
- integrity sha512-1Cd895dqYIT5MOUOCDlD73OTWoJubLq/sWC7AMzkMrLu76yD4Cu6f+wv1HDrRAheRaCaeT3yhYEhsMB6qHIcaA==
+storybook@7.6.10:
+ version "7.6.10"
+ resolved "https://registry.yarnpkg.com/storybook/-/storybook-7.6.10.tgz#2185d26cd7b43390e3e2c7581586e2f60cdbd9bd"
+ integrity sha512-ypFeGhQTUBBfqSUVZYh7wS5ghn3O2wILCiQc4459SeUpvUn+skcqw/TlrwGSoF5EWjDA7gtRrWDxO3mnlPt5Cw==
dependencies:
- "@storybook/cli" "7.6.7"
+ "@storybook/cli" "7.6.10"
stream-browserify@3.0.0:
version "3.0.0"
@@ -20109,9 +20206,9 @@ vite-node@1.1.3:
vite "^5.0.0"
vite@^5.0.0:
- version "5.0.11"
- resolved "https://registry.yarnpkg.com/vite/-/vite-5.0.11.tgz#31562e41e004cb68e1d51f5d2c641ab313b289e4"
- integrity sha512-XBMnDjZcNAw/G1gEiskiM1v6yzM4GE5aMGvhWTlHAYYhxb7S3/V1s3m2LDHa8Vh6yIWYYB0iJwsEaS523c4oYA==
+ version "5.0.12"
+ resolved "https://registry.yarnpkg.com/vite/-/vite-5.0.12.tgz#8a2ffd4da36c132aec4adafe05d7adde38333c47"
+ integrity sha512-4hsnEkG3q0N4Tzf1+t6NdN9dg/L3BM+q8SWgbSPnJvrgH2kgdyzfVJwbR1ic69/4uMJJ/3dqDZZE5/WwqW8U1w==
dependencies:
esbuild "^0.19.3"
postcss "^8.4.32"