diff --git a/eslint.config.mjs b/eslint.config.mjs
index 23651fb5b8..c5c6cacca7 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -30,14 +30,9 @@ const RESTRICTED_MODULES = {
importNames: [ 'Popover', 'Menu', 'PinInput', 'useToast', 'Skeleton' ],
message: 'Please use corresponding component or hook from ui/shared/chakra component instead',
},
- {
- name: 'lodash',
- message: 'Please use `import [package] from \'lodash/[package]\'` instead.',
- },
],
patterns: [
'icons/*',
- '!lodash/*',
],
};
diff --git a/icons/clock-light.svg b/icons/clock-light.svg
index 9b18072460..110cd4b797 100644
--- a/icons/clock-light.svg
+++ b/icons/clock-light.svg
@@ -1,3 +1,3 @@
diff --git a/lib/api/useApiFetch.tsx b/lib/api/useApiFetch.tsx
index cda519c1c1..a0658417d9 100644
--- a/lib/api/useApiFetch.tsx
+++ b/lib/api/useApiFetch.tsx
@@ -1,6 +1,5 @@
import { useQueryClient } from '@tanstack/react-query';
-import _omit from 'lodash/omit';
-import _pickBy from 'lodash/pickBy';
+import { omit, pickBy } from 'es-toolkit';
import React from 'react';
import type { CsrfData } from 'types/client/account';
@@ -38,7 +37,7 @@ export default function useApiFetch() {
const resource: ApiResource = RESOURCES[resourceName];
const url = buildUrl(resourceName, pathParams, queryParams);
const withBody = isBodyAllowed(fetchParams?.method);
- const headers = _pickBy({
+ const headers = pickBy({
'x-endpoint': resource.endpoint && isNeedProxy() ? resource.endpoint : undefined,
Authorization: resource.endpoint && resource.needAuth ? apiToken : undefined,
'x-csrf-token': withBody && csrfToken ? csrfToken : undefined,
@@ -55,7 +54,7 @@ export default function useApiFetch() {
// change condition here if something is changed
credentials: config.features.account.isEnabled ? 'include' : 'same-origin',
headers,
- ..._omit(fetchParams, 'headers'),
+ ...(fetchParams ? omit(fetchParams, [ 'headers' ]) : {}),
},
{
resource: resource.path,
diff --git a/lib/contexts/scrollDirection.tsx b/lib/contexts/scrollDirection.tsx
index 154b5438b4..1c4f5503bd 100644
--- a/lib/contexts/scrollDirection.tsx
+++ b/lib/contexts/scrollDirection.tsx
@@ -1,5 +1,4 @@
-import clamp from 'lodash/clamp';
-import throttle from 'lodash/throttle';
+import { throttle, clamp } from 'es-toolkit';
import React from 'react';
const ScrollDirectionContext = React.createContext<'up' | 'down' | null>(null);
diff --git a/lib/hooks/useClientRect.tsx b/lib/hooks/useClientRect.tsx
index 05aa278f5b..44033e30cc 100644
--- a/lib/hooks/useClientRect.tsx
+++ b/lib/hooks/useClientRect.tsx
@@ -1,4 +1,4 @@
-import _debounce from 'lodash/debounce';
+import { debounce } from 'es-toolkit';
import type { LegacyRef } from 'react';
import React from 'react';
@@ -19,7 +19,7 @@ export default function useClientRect(): [ DOMRect | null, Le
return;
}
- const resizeHandler = _debounce(() => {
+ const resizeHandler = debounce(() => {
setRect(nodeRef.current?.getBoundingClientRect() ?? null);
}, 100);
diff --git a/lib/hooks/useIsSticky.tsx b/lib/hooks/useIsSticky.tsx
index cc9c5c4b6d..2dfa3ff574 100644
--- a/lib/hooks/useIsSticky.tsx
+++ b/lib/hooks/useIsSticky.tsx
@@ -1,4 +1,4 @@
-import throttle from 'lodash/throttle';
+import { throttle } from 'es-toolkit';
import React from 'react';
export default function useIsSticky(ref: React.RefObject, offset = 0, isEnabled = true) {
diff --git a/lib/hooks/useLazyRenderedList.tsx b/lib/hooks/useLazyRenderedList.tsx
index 3f2d828fe0..4ebd630b18 100644
--- a/lib/hooks/useLazyRenderedList.tsx
+++ b/lib/hooks/useLazyRenderedList.tsx
@@ -1,4 +1,4 @@
-import _clamp from 'lodash/clamp';
+import { clamp } from 'es-toolkit';
import React from 'react';
import { useInView } from 'react-intersection-observer';
@@ -15,7 +15,7 @@ export default function useLazyRenderedList(list: Array, isEnabled: boo
React.useEffect(() => {
if (inView) {
- setRenderedItemsNum((prev) => _clamp(prev + STEP, 0, list.length));
+ setRenderedItemsNum((prev) => clamp(prev + STEP, 0, list.length));
}
}, [ inView, list.length ]);
diff --git a/lib/mixpanel/getTabName.ts b/lib/mixpanel/getTabName.ts
index 3ca3b8cae8..99f742a887 100644
--- a/lib/mixpanel/getTabName.ts
+++ b/lib/mixpanel/getTabName.ts
@@ -1,5 +1,5 @@
-import _capitalize from 'lodash/capitalize';
+import { capitalize } from 'es-toolkit';
export default function getTabName(tab: string) {
- return tab !== '' ? _capitalize(tab.replaceAll('_', ' ')) : 'Default';
+ return tab !== '' ? capitalize(tab.replaceAll('_', ' ')) : 'Default';
}
diff --git a/lib/mixpanel/useInit.tsx b/lib/mixpanel/useInit.tsx
index 23f02332f8..9e67acc858 100644
--- a/lib/mixpanel/useInit.tsx
+++ b/lib/mixpanel/useInit.tsx
@@ -1,4 +1,4 @@
-import _capitalize from 'lodash/capitalize';
+import { capitalize } from 'es-toolkit';
import type { Config } from 'mixpanel-browser';
import mixpanel from 'mixpanel-browser';
import { useRouter } from 'next/router';
@@ -40,12 +40,12 @@ export default function useMixpanelInit() {
'Viewport width': window.innerWidth,
'Viewport height': window.innerHeight,
Language: window.navigator.language,
- 'Device type': _capitalize(deviceType),
+ 'Device type': capitalize(deviceType),
'User id': userId,
});
mixpanel.identify(userId);
userProfile.set({
- 'Device Type': _capitalize(deviceType),
+ 'Device Type': capitalize(deviceType),
...(isAuth ? { 'With Account': true } : {}),
});
userProfile.setOnce({
diff --git a/lib/networks/networkExplorers.ts b/lib/networks/networkExplorers.ts
index cfcc828115..b5a4648d41 100644
--- a/lib/networks/networkExplorers.ts
+++ b/lib/networks/networkExplorers.ts
@@ -1,5 +1,4 @@
-import _compose from 'lodash/fp/compose';
-import _mapValues from 'lodash/mapValues';
+import { mapValues } from 'es-toolkit';
import type { NetworkExplorer } from 'types/networks';
@@ -32,7 +31,7 @@ const networkExplorers: Array = (() => {
return config.UI.explorers.items.map((explorer) => ({
...explorer,
baseUrl: stripTrailingSlash(explorer.baseUrl),
- paths: _mapValues(explorer.paths, _compose(stripTrailingSlash, addLeadingSlash)),
+ paths: mapValues(explorer.paths, (value) => value ? stripTrailingSlash(addLeadingSlash(value)) : value),
}));
})();
diff --git a/lib/recentSearchKeywords.ts b/lib/recentSearchKeywords.ts
index 5fe5a6bd71..3c0b31d6fe 100644
--- a/lib/recentSearchKeywords.ts
+++ b/lib/recentSearchKeywords.ts
@@ -1,4 +1,4 @@
-import _uniq from 'lodash/uniq';
+import { uniq } from 'es-toolkit';
import isBrowser from './isBrowser';
@@ -27,7 +27,7 @@ export function saveToRecentKeywords(value: string) {
}
const keywordsArr = getRecentSearchKeywords();
- const result = _uniq([ value, ...keywordsArr ]).slice(0, MAX_KEYWORDS_NUMBER - 1);
+ const result = uniq([ value, ...keywordsArr ]).slice(0, MAX_KEYWORDS_NUMBER - 1);
window.localStorage.setItem(RECENT_KEYWORDS_LS_KEY, JSON.stringify(result));
}
diff --git a/lib/token/metadata/attributesParser.ts b/lib/token/metadata/attributesParser.ts
index 63e572fe72..2167464d96 100644
--- a/lib/token/metadata/attributesParser.ts
+++ b/lib/token/metadata/attributesParser.ts
@@ -1,4 +1,4 @@
-import _upperFirst from 'lodash/upperFirst';
+import { upperFirst } from 'es-toolkit';
import type { Metadata, MetadataAttributes } from 'types/client/token';
@@ -72,7 +72,7 @@ export default function attributesParser(attributes: Array): Metadata['
return {
...formatValue(value, display, trait),
- trait_type: _upperFirst(trait || 'property'),
+ trait_type: upperFirst(trait || 'property'),
};
})
.filter((item) => item?.value)
diff --git a/lib/web3/useAddOrSwitchChain.tsx b/lib/web3/useAddOrSwitchChain.tsx
index adba7a6d4e..b4e533571b 100644
--- a/lib/web3/useAddOrSwitchChain.tsx
+++ b/lib/web3/useAddOrSwitchChain.tsx
@@ -1,4 +1,4 @@
-import _get from 'lodash/get';
+import { get } from 'es-toolkit/compat';
import React from 'react';
import config from 'configs/app';
@@ -25,7 +25,7 @@ export default function useAddOrSwitchChain() {
const errorObj = getErrorObj(error);
const code = errorObj && 'code' in errorObj ? errorObj.code : undefined;
- const originalErrorCode = _get(errorObj, 'data.originalError.code');
+ const originalErrorCode = get(errorObj, 'data.originalError.code');
// This error code indicates that the chain has not been added to Wallet.
if (code === 4902 || originalErrorCode === 4902) {
diff --git a/mocks/blocks/epoch.ts b/mocks/blocks/epoch.ts
index 58f614fbe6..165660c7c1 100644
--- a/mocks/blocks/epoch.ts
+++ b/mocks/blocks/epoch.ts
@@ -1,4 +1,4 @@
-import _padStart from 'lodash/padStart';
+import { padStart } from 'es-toolkit/compat';
import type { BlockEpoch, BlockEpochElectionRewardDetails, BlockEpochElectionRewardDetailsResponse } from 'types/api/block';
@@ -42,11 +42,11 @@ function getRewardDetailsItem(index: number): BlockEpochElectionRewardDetails {
amount: `${ 100 - index }210001063118670575`,
account: {
...addressMock.withoutName,
- hash: `0x30D060F129817c4DE5fBc1366d53e19f43c8c6${ _padStart(String(index), 2, '0') }`,
+ hash: `0x30D060F129817c4DE5fBc1366d53e19f43c8c6${ padStart(String(index), 2, '0') }`,
},
associated_account: {
...addressMock.withoutName,
- hash: `0x456f41406B32c45D59E539e4BBA3D7898c3584${ _padStart(String(index), 2, '0') }`,
+ hash: `0x456f41406B32c45D59E539e4BBA3D7898c3584${ padStart(String(index), 2, '0') }`,
},
};
}
diff --git a/mocks/stats/index.ts b/mocks/stats/index.ts
index f4bc3f53e3..725831d2d3 100644
--- a/mocks/stats/index.ts
+++ b/mocks/stats/index.ts
@@ -1,4 +1,4 @@
-import _mapValues from 'lodash/mapValues';
+import { mapValues } from 'es-toolkit';
import type { HomeStats } from 'types/api/stats';
@@ -51,17 +51,17 @@ export const withBtcLocked: HomeStats = {
export const withoutFiatPrices: HomeStats = {
...base,
- gas_prices: _mapValues(base.gas_prices, (price) => price ? ({ ...price, fiat_price: null }) : null),
+ gas_prices: base.gas_prices ? mapValues(base.gas_prices, (price) => price ? ({ ...price, fiat_price: null }) : null) : null,
};
export const withoutGweiPrices: HomeStats = {
...base,
- gas_prices: _mapValues(base.gas_prices, (price) => price ? ({ ...price, price: null }) : null),
+ gas_prices: base.gas_prices ? mapValues(base.gas_prices, (price) => price ? ({ ...price, price: null }) : null) : null,
};
export const withoutBothPrices: HomeStats = {
...base,
- gas_prices: _mapValues(base.gas_prices, (price) => price ? ({ ...price, price: null, fiat_price: null }) : null),
+ gas_prices: base.gas_prices ? mapValues(base.gas_prices, (price) => price ? ({ ...price, price: null, fiat_price: null }) : null) : null,
};
export const withoutGasInfo: HomeStats = {
diff --git a/nextjs/csp/utils.ts b/nextjs/csp/utils.ts
index cdc9a0fdd7..6c5dc55797 100644
--- a/nextjs/csp/utils.ts
+++ b/nextjs/csp/utils.ts
@@ -1,4 +1,5 @@
import type CspDev from 'csp-dev';
+import { uniq } from 'es-toolkit';
export const KEY_WORDS = {
BLOB: 'blob:',
@@ -11,17 +12,6 @@ export const KEY_WORDS = {
UNSAFE_EVAL: '\'unsafe-eval\'',
};
-// we cannot use lodash/uniq and lodash/mergeWith in middleware code since it calls new Set() and it'is causing an error in Next.js
-// "Dynamic Code Evaluation (e. g. 'eval', 'new Function', 'WebAssembly.compile') not allowed in Edge Runtime"
-export function unique(array: Array) {
- const set: Record = {};
- for (const item of array) {
- item && (set[item] = true);
- }
-
- return Object.keys(set);
-}
-
export function mergeDescriptors(...descriptors: Array) {
return descriptors.reduce((result, item) => {
for (const _key in item) {
@@ -50,7 +40,7 @@ export function makePolicyString(policyDescriptor: CspDev.DirectiveDescriptor) {
return;
}
- const uniqueValues = unique(value);
+ const uniqueValues = uniq(value);
return [ key, uniqueValues.join(' ') ].join(' ');
})
.filter(Boolean)
diff --git a/nextjs/utils/fetchProxy.ts b/nextjs/utils/fetchProxy.ts
index a8f0c032f2..0fd5b19b57 100644
--- a/nextjs/utils/fetchProxy.ts
+++ b/nextjs/utils/fetchProxy.ts
@@ -1,5 +1,5 @@
+import { pick } from 'es-toolkit';
import type { IncomingMessage } from 'http';
-import _pick from 'lodash/pick';
import type { NextApiRequest } from 'next';
import type { NextApiRequestCookies } from 'next/dist/server/api-utils';
import type { RequestInit, Response } from 'node-fetch';
@@ -21,7 +21,7 @@ export default function fetchFactory(
accept: _req.headers['accept'] || 'application/json',
'content-type': _req.headers['content-type'] || 'application/json',
cookie: apiToken ? `${ cookies.NAMES.API_TOKEN }=${ apiToken }` : '',
- ..._pick(_req.headers, [
+ ...pick(_req.headers, [
'x-csrf-token',
'Authorization', // the old value, just in case
'authorization', // Node.js automatically lowercases headers
diff --git a/package.json b/package.json
index 43de857133..d9212fb6ed 100644
--- a/package.json
+++ b/package.json
@@ -80,6 +80,7 @@
"dappscout-iframe": "0.2.5",
"dayjs": "^1.11.5",
"dom-to-image": "^2.6.0",
+ "es-toolkit": "1.31.0",
"focus-visible": "^5.2.0",
"framer-motion": "^6.5.1",
"getit-sdk": "^1.0.4",
@@ -88,7 +89,6 @@
"graphql": "^16.8.1",
"graphql-ws": "^5.11.3",
"js-cookie": "^3.0.1",
- "lodash": "^4.0.0",
"magic-bytes.js": "1.8.0",
"mixpanel-browser": "^2.47.0",
"monaco-editor": "^0.34.1",
diff --git a/pages/api/proxy.ts b/pages/api/proxy.ts
index 78d8e152ba..ebb653f73b 100644
--- a/pages/api/proxy.ts
+++ b/pages/api/proxy.ts
@@ -1,5 +1,4 @@
-import _pick from 'lodash/pick';
-import _pickBy from 'lodash/pickBy';
+import { pick, pickBy } from 'es-toolkit';
import type { NextApiRequest, NextApiResponse } from 'next';
import fetchFactory from 'nextjs/utils/fetchProxy';
@@ -18,7 +17,7 @@ const handler = async(nextReq: NextApiRequest, nextRes: NextApiResponse) => {
);
const apiRes = await fetchFactory(nextReq)(
url.toString(),
- _pickBy(_pick(nextReq, [ 'body', 'method' ]), Boolean),
+ pickBy(pick(nextReq, [ 'body', 'method' ]), Boolean),
);
// proxy some headers from API
diff --git a/playwright/fixtures/mockContractReadResponse.ts b/playwright/fixtures/mockContractReadResponse.ts
index 1245724c69..9a9325d960 100644
--- a/playwright/fixtures/mockContractReadResponse.ts
+++ b/playwright/fixtures/mockContractReadResponse.ts
@@ -1,5 +1,5 @@
import type { TestFixture, Page } from '@playwright/test';
-import _isEqual from 'lodash/isEqual';
+import { isEqual } from 'es-toolkit';
import { encodeFunctionData, encodeFunctionResult, type AbiFunction } from 'viem';
import { getEnvValue } from 'configs/app/utils';
@@ -43,7 +43,7 @@ const fixture: TestFixture = as
value: params?.value,
};
- if (_isEqual(params, callParams) && id) {
+ if (isEqual(params, callParams) && id) {
return route.fulfill({
status: 200,
json: {
diff --git a/playwright/fixtures/mockRpcResponse.ts b/playwright/fixtures/mockRpcResponse.ts
index b257599fe3..ceacf111b8 100644
--- a/playwright/fixtures/mockRpcResponse.ts
+++ b/playwright/fixtures/mockRpcResponse.ts
@@ -1,5 +1,5 @@
import type { TestFixture, Page } from '@playwright/test';
-import _isEqual from 'lodash/isEqual';
+import { isEqual } from 'es-toolkit';
import type { PublicRpcSchema } from 'viem';
import { getEnvValue } from 'configs/app/utils';
@@ -34,7 +34,7 @@ const fixture: TestFixture = async({ pag
...(rpcMock.Parameters ? { params: rpcMock.Parameters } : {}),
};
- if (_isEqual(json, payload) && id !== undefined) {
+ if (isEqual(json, payload) && id !== undefined) {
return route.fulfill({
status: 200,
json: {
diff --git a/playwright/index.ts b/playwright/index.ts
index 96c506e9fc..31ab5f53de 100644
--- a/playwright/index.ts
+++ b/playwright/index.ts
@@ -1,7 +1,6 @@
import './fonts.css';
import './index.css';
import { beforeMount } from '@playwright/experimental-ct-react/hooks';
-import _defaultsDeep from 'lodash/defaultsDeep';
import MockDate from 'mockdate';
import * as router from 'next/router';
@@ -12,12 +11,15 @@ const NEXT_ROUTER_MOCK = {
replace: () => Promise.resolve(),
};
-beforeMount(async({ hooksConfig }) => {
+beforeMount(async({ hooksConfig }: { hooksConfig?: { router: typeof router } }) => {
// Before mount, redefine useRouter to return mock value from test.
// @ts-ignore: I really want to redefine this property :)
// eslint-disable-next-line no-import-assign
- router.useRouter = () => _defaultsDeep(hooksConfig?.router, NEXT_ROUTER_MOCK);
+ router.useRouter = () => ({
+ ...NEXT_ROUTER_MOCK,
+ ...hooksConfig?.router,
+ });
// set current date
MockDate.set('2022-11-11T12:00:00Z');
diff --git a/public/static/badges.svg b/public/static/badges.svg
index 741e81b6e5..a1f43d51c2 100644
--- a/public/static/badges.svg
+++ b/public/static/badges.svg
@@ -17,15 +17,14 @@
-
+
-
+
-
-
-
+
+
@@ -36,18 +35,18 @@
-
-
-
+
+
+
-
+
-
+
-
+
@@ -81,7 +80,7 @@
-
+
@@ -96,15 +95,15 @@
-
-
+
+
-
+
-
+
@@ -113,22 +112,22 @@
-
+
-
-
+
+
-
+
-
+
-
+
@@ -144,10 +143,10 @@
-
-
-
-
+
+
+
+
@@ -160,7 +159,7 @@
-
+
@@ -171,13 +170,12 @@
-
-
+
+
-
-
-
-
+
+
+
@@ -192,27 +190,27 @@
-
+
-
-
-
+
+
+
-
+
-
-
+
+
-
+
@@ -221,7 +219,7 @@
-
+
@@ -231,16 +229,16 @@
-
+
-
-
+
+
-
+
@@ -277,27 +275,27 @@
-
+
-
+
-
+
-
+
-
+
-
+
diff --git a/ui/address/contract/audits/ContractSubmitAuditForm.pw.tsx b/ui/address/contract/audits/ContractSubmitAuditForm.pw.tsx
index a9053cad83..b95829f290 100644
--- a/ui/address/contract/audits/ContractSubmitAuditForm.pw.tsx
+++ b/ui/address/contract/audits/ContractSubmitAuditForm.pw.tsx
@@ -1,4 +1,4 @@
-import noop from 'lodash/noop';
+import { noop } from 'es-toolkit';
import React from 'react';
import { test, expect } from 'playwright/lib';
diff --git a/ui/address/contract/methods/ContractAbi.tsx b/ui/address/contract/methods/ContractAbi.tsx
index 72f7fe6295..660cc99eff 100644
--- a/ui/address/contract/methods/ContractAbi.tsx
+++ b/ui/address/contract/methods/ContractAbi.tsx
@@ -1,5 +1,5 @@
import { Accordion, Box, Flex, Link } from '@chakra-ui/react';
-import _range from 'lodash/range';
+import { range } from 'es-toolkit';
import React from 'react';
import type { SmartContractMethod } from './types';
@@ -39,7 +39,7 @@ const ContractAbi = ({ abi, addressHash, sourceAddress, tab, visibleItems }: Pro
}
if (expandedSections.length < abi.length) {
- setExpandedSections(_range(0, abi.length));
+ setExpandedSections(range(0, abi.length));
} else {
setExpandedSections([]);
}
diff --git a/ui/address/contract/methods/form/utils.ts b/ui/address/contract/methods/form/utils.ts
index e067f0f74f..1c1c197cbc 100644
--- a/ui/address/contract/methods/form/utils.ts
+++ b/ui/address/contract/methods/form/utils.ts
@@ -1,4 +1,4 @@
-import _set from 'lodash/set';
+import { set } from 'es-toolkit/compat';
import type { ContractAbiItemInput } from '../types';
@@ -78,7 +78,7 @@ export function transformFormDataToMethodArgs(formData: ContractMethodFormFields
for (const field in formData) {
const value = formData[field];
- _set(result, field.replaceAll(':', '.'), value);
+ set(result, field.replaceAll(':', '.'), value);
}
const filteredResult = filterOutEmptyItems(result);
diff --git a/ui/address/contract/methods/useMethodsFilters.ts b/ui/address/contract/methods/useMethodsFilters.ts
index 5cda37075f..78e5709713 100644
--- a/ui/address/contract/methods/useMethodsFilters.ts
+++ b/ui/address/contract/methods/useMethodsFilters.ts
@@ -1,4 +1,4 @@
-import _pickBy from 'lodash/pickBy';
+import { pickBy } from 'es-toolkit';
import { useRouter } from 'next/router';
import React from 'react';
@@ -63,7 +63,7 @@ export default function useMethodsFilters({ abi }: Params) {
return;
}
- const queryForPathname = _pickBy(router.query, (value, key) => router.pathname.includes(`[${ key }]`));
+ const queryForPathname = pickBy(router.query, (value, key) => router.pathname.includes(`[${ key }]`));
router.push(
{ pathname: router.pathname, query: { ...queryForPathname, tab: nextTab } },
undefined,
diff --git a/ui/address/details/AddressMultichainButton.tsx b/ui/address/details/AddressMultichainButton.tsx
index eee6e63c92..a8dc73382a 100644
--- a/ui/address/details/AddressMultichainButton.tsx
+++ b/ui/address/details/AddressMultichainButton.tsx
@@ -1,5 +1,5 @@
import { Image, Tooltip } from '@chakra-ui/react';
-import _capitalize from 'lodash/capitalize';
+import { capitalize } from 'es-toolkit';
import React from 'react';
import type { MultichainProviderConfigParsed } from 'types/client/multichainProviderConfig';
@@ -25,10 +25,10 @@ const AddressMultichainButton = ({ item, addressHash, onClick, hasSingleProvider
const buttonContent = hasSingleProvider ? (
<>
{ buttonIcon }
- { _capitalize(item.name) }
+ { capitalize(item.name) }
>
) : (
- { buttonIcon }
+ { buttonIcon }
);
const linkProps = {
diff --git a/ui/address/ensDomains/AddressEnsDomains.tsx b/ui/address/ensDomains/AddressEnsDomains.tsx
index 6349d3d431..0f488cfa84 100644
--- a/ui/address/ensDomains/AddressEnsDomains.tsx
+++ b/ui/address/ensDomains/AddressEnsDomains.tsx
@@ -12,7 +12,7 @@ import {
chakra,
} from '@chakra-ui/react';
import type { UseQueryResult } from '@tanstack/react-query';
-import _clamp from 'lodash/clamp';
+import { clamp } from 'es-toolkit';
import React from 'react';
import type * as bens from '@blockscout/bens-types';
@@ -37,7 +37,7 @@ interface Props {
const DomainsGrid = ({ data }: { data: Array }) => {
return (
{
);
}
- const hasTokens = _sumBy(Object.values(data), ({ items }) => items.length) > 0;
+ const hasTokens = sumBy(Object.values(data), ({ items }) => items.length) > 0;
if (isError || !hasTokens) {
return 0;
}
diff --git a/ui/address/tokenSelect/TokenSelectMenu.tsx b/ui/address/tokenSelect/TokenSelectMenu.tsx
index 41c8129d11..bb25a39f76 100644
--- a/ui/address/tokenSelect/TokenSelectMenu.tsx
+++ b/ui/address/tokenSelect/TokenSelectMenu.tsx
@@ -1,5 +1,5 @@
import { Text, Box, Input, InputGroup, InputLeftElement, useColorModeValue, Flex, Link } from '@chakra-ui/react';
-import _sumBy from 'lodash/sumBy';
+import { sumBy } from 'es-toolkit';
import type { ChangeEvent } from 'react';
import React from 'react';
@@ -26,7 +26,7 @@ interface Props {
const TokenSelectMenu = ({ erc20sort, erc1155sort, erc404sort, filteredData, onInputChange, onSortClick, searchTerm }: Props) => {
const searchIconColor = useColorModeValue('blackAlpha.600', 'whiteAlpha.600');
- const hasFilteredResult = _sumBy(Object.values(filteredData), ({ items }) => items.length) > 0;
+ const hasFilteredResult = sumBy(Object.values(filteredData), ({ items }) => items.length) > 0;
return (
<>
diff --git a/ui/address/tokenSelect/useTokenSelect.ts b/ui/address/tokenSelect/useTokenSelect.ts
index 95346e25c3..35ecc004d1 100644
--- a/ui/address/tokenSelect/useTokenSelect.ts
+++ b/ui/address/tokenSelect/useTokenSelect.ts
@@ -1,4 +1,4 @@
-import _mapValues from 'lodash/mapValues';
+import { mapValues } from 'es-toolkit';
import type { ChangeEvent } from 'react';
import React from 'react';
@@ -31,7 +31,7 @@ export default function useTokenSelect(data: FormattedData) {
}, []);
const filteredData = React.useMemo(() => {
- return _mapValues(data, ({ items, isOverflow }) => ({
+ return mapValues(data, ({ items, isOverflow }) => ({
isOverflow,
items: items.filter(filterTokens(searchTerm.toLowerCase())),
}));
diff --git a/ui/address/utils/tokenUtils.ts b/ui/address/utils/tokenUtils.ts
index a4aaa37364..293f245ed0 100644
--- a/ui/address/utils/tokenUtils.ts
+++ b/ui/address/utils/tokenUtils.ts
@@ -1,5 +1,4 @@
import BigNumber from 'bignumber.js';
-import fpAdd from 'lodash/fp/add';
import type { AddressTokenBalance } from 'types/api/address';
import type { TokenType } from 'types/api/token';
@@ -100,7 +99,7 @@ export const getTokensTotalInfo = (data: TokenSelectData) => {
const num = Object.values(data)
.map(({ items }) => items.length)
- .reduce(fpAdd, 0);
+ .reduce((result, item) => result + item, 0);
const isOverflow = Object.values(data).some(({ isOverflow }) => isOverflow);
diff --git a/ui/advancedFilter/filters/AddressFilter.tsx b/ui/advancedFilter/filters/AddressFilter.tsx
index 9bb197a099..7620c5bcb9 100644
--- a/ui/advancedFilter/filters/AddressFilter.tsx
+++ b/ui/advancedFilter/filters/AddressFilter.tsx
@@ -1,5 +1,5 @@
import { Flex, Select, Input, InputGroup, InputRightElement, VStack, IconButton } from '@chakra-ui/react';
-import isEqual from 'lodash/isEqual';
+import { isEqual } from 'es-toolkit';
import type { ChangeEvent } from 'react';
import React from 'react';
diff --git a/ui/advancedFilter/filters/AgeFilter.tsx b/ui/advancedFilter/filters/AgeFilter.tsx
index 370407e518..d9cb00be1c 100644
--- a/ui/advancedFilter/filters/AgeFilter.tsx
+++ b/ui/advancedFilter/filters/AgeFilter.tsx
@@ -1,5 +1,5 @@
import { Flex, Input, Text } from '@chakra-ui/react';
-import isEqual from 'lodash/isEqual';
+import { isEqual } from 'es-toolkit';
import type { ChangeEvent } from 'react';
import React from 'react';
diff --git a/ui/advancedFilter/filters/AmountFilter.tsx b/ui/advancedFilter/filters/AmountFilter.tsx
index df64eb08e6..68abad8a2a 100644
--- a/ui/advancedFilter/filters/AmountFilter.tsx
+++ b/ui/advancedFilter/filters/AmountFilter.tsx
@@ -1,5 +1,5 @@
import { Flex, Input, Tag, Text } from '@chakra-ui/react';
-import isEqual from 'lodash/isEqual';
+import { isEqual } from 'es-toolkit';
import type { ChangeEvent } from 'react';
import React from 'react';
diff --git a/ui/advancedFilter/filters/AssetFilter.tsx b/ui/advancedFilter/filters/AssetFilter.tsx
index 048e8aeddb..619fe7bcff 100644
--- a/ui/advancedFilter/filters/AssetFilter.tsx
+++ b/ui/advancedFilter/filters/AssetFilter.tsx
@@ -1,5 +1,5 @@
import { Flex, Checkbox, CheckboxGroup, Text, Spinner, Select } from '@chakra-ui/react';
-import isEqual from 'lodash/isEqual';
+import { isEqual } from 'es-toolkit';
import React from 'react';
import type { AdvancedFilterParams } from 'types/api/advancedFilter';
diff --git a/ui/advancedFilter/filters/MethodFilter.tsx b/ui/advancedFilter/filters/MethodFilter.tsx
index 93bc65e45d..d61622ae92 100644
--- a/ui/advancedFilter/filters/MethodFilter.tsx
+++ b/ui/advancedFilter/filters/MethodFilter.tsx
@@ -1,6 +1,5 @@
import { Flex, Checkbox, CheckboxGroup, Spinner, chakra } from '@chakra-ui/react';
-import differenceBy from 'lodash/differenceBy';
-import isEqual from 'lodash/isEqual';
+import { isEqual, differenceBy } from 'es-toolkit';
import type { ChangeEvent } from 'react';
import React from 'react';
diff --git a/ui/advancedFilter/filters/TypeFilter.tsx b/ui/advancedFilter/filters/TypeFilter.tsx
index f3a61c2562..c6cd46f8be 100644
--- a/ui/advancedFilter/filters/TypeFilter.tsx
+++ b/ui/advancedFilter/filters/TypeFilter.tsx
@@ -1,6 +1,5 @@
import { Flex, Checkbox, CheckboxGroup } from '@chakra-ui/react';
-import isEqual from 'lodash/isEqual';
-import without from 'lodash/without';
+import { isEqual, without } from 'es-toolkit';
import type { ChangeEvent } from 'react';
import React from 'react';
diff --git a/ui/advancedFilter/lib.ts b/ui/advancedFilter/lib.ts
index 3b8380fde2..b65cc08f01 100644
--- a/ui/advancedFilter/lib.ts
+++ b/ui/advancedFilter/lib.ts
@@ -1,4 +1,4 @@
-import castArray from 'lodash/castArray';
+import { castArray } from 'es-toolkit/compat';
import type { AdvancedFilterAge, AdvancedFilterParams } from 'types/api/advancedFilter';
diff --git a/ui/block/BlockDetails.tsx b/ui/block/BlockDetails.tsx
index 5e8d95bb13..f97d84d250 100644
--- a/ui/block/BlockDetails.tsx
+++ b/ui/block/BlockDetails.tsx
@@ -1,6 +1,6 @@
import { Grid, GridItem, Text, Link, Box, Tooltip } from '@chakra-ui/react';
import BigNumber from 'bignumber.js';
-import capitalize from 'lodash/capitalize';
+import { capitalize } from 'es-toolkit';
import { useRouter } from 'next/router';
import React from 'react';
import { scroller, Element } from 'react-scroll';
diff --git a/ui/blockCountdown/splitSecondsInPeriods.ts b/ui/blockCountdown/splitSecondsInPeriods.ts
index b187ba5e0e..9c915a82d6 100644
--- a/ui/blockCountdown/splitSecondsInPeriods.ts
+++ b/ui/blockCountdown/splitSecondsInPeriods.ts
@@ -1,4 +1,4 @@
-import _padStart from 'lodash/padStart';
+import { padStart } from 'es-toolkit/compat';
export default function splitSecondsInPeriods(value: number) {
const seconds = value % 60;
@@ -7,9 +7,9 @@ export default function splitSecondsInPeriods(value: number) {
const days = (value - seconds - minutes * 60 - hours * 60 * 60) / (60 * 60 * 24);
return {
- seconds: _padStart(String(seconds), 2, '0'),
- minutes: _padStart(String(minutes), 2, '0'),
- hours: _padStart(String(hours), 2, '0'),
- days: _padStart(String(days), 2, '0'),
+ seconds: padStart(String(seconds), 2, '0'),
+ minutes: padStart(String(minutes), 2, '0'),
+ hours: padStart(String(hours), 2, '0'),
+ days: padStart(String(days), 2, '0'),
};
}
diff --git a/ui/blocks/BlocksListItem.tsx b/ui/blocks/BlocksListItem.tsx
index 8c33ef8afc..be78336f86 100644
--- a/ui/blocks/BlocksListItem.tsx
+++ b/ui/blocks/BlocksListItem.tsx
@@ -1,6 +1,6 @@
import { Flex, Text, Box, Tooltip } from '@chakra-ui/react';
import BigNumber from 'bignumber.js';
-import capitalize from 'lodash/capitalize';
+import { capitalize } from 'es-toolkit';
import React from 'react';
import type { Block } from 'types/api/block';
diff --git a/ui/blocks/BlocksTable.tsx b/ui/blocks/BlocksTable.tsx
index 45a1fd0cbd..e563da20ea 100644
--- a/ui/blocks/BlocksTable.tsx
+++ b/ui/blocks/BlocksTable.tsx
@@ -1,6 +1,6 @@
import { Table, Tbody, Tr, Th } from '@chakra-ui/react';
+import { capitalize } from 'es-toolkit';
import { AnimatePresence } from 'framer-motion';
-import capitalize from 'lodash/capitalize';
import React from 'react';
import type { Block } from 'types/api/block';
diff --git a/ui/contractVerification/fields/ContractVerificationFieldGitHubRepo.tsx b/ui/contractVerification/fields/ContractVerificationFieldGitHubRepo.tsx
index 68e378b868..f05750fbff 100644
--- a/ui/contractVerification/fields/ContractVerificationFieldGitHubRepo.tsx
+++ b/ui/contractVerification/fields/ContractVerificationFieldGitHubRepo.tsx
@@ -1,4 +1,4 @@
-import _get from 'lodash/get';
+import { get } from 'es-toolkit/compat';
import React from 'react';
import { useFormContext } from 'react-hook-form';
@@ -43,7 +43,7 @@ const ContractVerificationFieldGitHubRepo = ({ onCommitHashChange }: Props) => {
const response = await fetch(`https://api.github.com/repos/${ gitHubData.owner }/${ gitHubData.repo }/commits?per_page=1`);
repoErrorRef.current = undefined;
trigger('repository_url');
- onCommitHashChange(_get(response, '[0].sha'));
+ onCommitHashChange(get(response, '[0].sha'));
return;
} catch (error) {
repoErrorRef.current = 'GitHub repository not found';
diff --git a/ui/csvExport/CsvExportFormField.tsx b/ui/csvExport/CsvExportFormField.tsx
index 9c556e2a1e..c64eef9b38 100644
--- a/ui/csvExport/CsvExportFormField.tsx
+++ b/ui/csvExport/CsvExportFormField.tsx
@@ -1,4 +1,4 @@
-import _capitalize from 'lodash/capitalize';
+import { capitalize } from 'es-toolkit';
import React from 'react';
import type { UseFormReturn } from 'react-hook-form';
@@ -40,7 +40,7 @@ const CsvExportFormField = ({ formApi, name }: Props) => {
name={ name }
type="date"
max={ dayjs().format('YYYY-MM-DD') }
- placeholder={ _capitalize(name) }
+ placeholder={ capitalize(name) }
isRequired
rules={{ validate }}
size={{ base: 'md', lg: 'lg' }}
diff --git a/ui/pages/AdvancedFilter.tsx b/ui/pages/AdvancedFilter.tsx
index 9fc6a5a9f1..e37733babf 100644
--- a/ui/pages/AdvancedFilter.tsx
+++ b/ui/pages/AdvancedFilter.tsx
@@ -15,7 +15,7 @@ import {
HStack,
Link,
} from '@chakra-ui/react';
-import omit from 'lodash/omit';
+import { omit } from 'es-toolkit';
import { useRouter } from 'next/router';
import React from 'react';
diff --git a/ui/pages/Block.tsx b/ui/pages/Block.tsx
index 9bea7844d9..5a45762d54 100644
--- a/ui/pages/Block.tsx
+++ b/ui/pages/Block.tsx
@@ -1,5 +1,5 @@
import { chakra } from '@chakra-ui/react';
-import capitalize from 'lodash/capitalize';
+import { capitalize } from 'es-toolkit';
import { useRouter } from 'next/router';
import React from 'react';
diff --git a/ui/pages/Transactions.tsx b/ui/pages/Transactions.tsx
index c3b5146b38..fbf07a8846 100644
--- a/ui/pages/Transactions.tsx
+++ b/ui/pages/Transactions.tsx
@@ -1,5 +1,5 @@
import { Flex } from '@chakra-ui/react';
-import capitalize from 'lodash/capitalize';
+import { capitalize } from 'es-toolkit';
import { useRouter } from 'next/router';
import React from 'react';
diff --git a/ui/pages/UserOp.tsx b/ui/pages/UserOp.tsx
index 92eebad927..18bfcb1f46 100644
--- a/ui/pages/UserOp.tsx
+++ b/ui/pages/UserOp.tsx
@@ -1,4 +1,4 @@
-import _inRange from 'lodash/inRange';
+import { inRange } from 'es-toolkit';
import { useRouter } from 'next/router';
import React from 'react';
@@ -43,7 +43,7 @@ const UserOp = () => {
if (!userOpQuery.data) {
return true;
} else {
- if (_inRange(
+ if (inRange(
Number(tt.log_index),
userOpQuery.data?.user_logs_start_index,
userOpQuery.data?.user_logs_start_index + userOpQuery.data?.user_logs_count,
@@ -58,7 +58,7 @@ const UserOp = () => {
if (!userOpQuery.data) {
return true;
} else {
- if (_inRange(log.index, userOpQuery.data?.user_logs_start_index, userOpQuery.data?.user_logs_start_index + userOpQuery.data?.user_logs_count)) {
+ if (inRange(log.index, userOpQuery.data?.user_logs_start_index, userOpQuery.data?.user_logs_start_index + userOpQuery.data?.user_logs_count)) {
return true;
}
return false;
diff --git a/ui/publicTags/submit/PublicTagsSubmitResult.tsx b/ui/publicTags/submit/PublicTagsSubmitResult.tsx
index f1fd62eb74..1ce36ad7e7 100644
--- a/ui/publicTags/submit/PublicTagsSubmitResult.tsx
+++ b/ui/publicTags/submit/PublicTagsSubmitResult.tsx
@@ -1,5 +1,5 @@
import { Alert, Box, Button, Flex, Grid, GridItem } from '@chakra-ui/react';
-import _pickBy from 'lodash/pickBy';
+import { pickBy } from 'es-toolkit';
import React from 'react';
import type { FormSubmitResult } from './types';
@@ -26,7 +26,7 @@ const PublicTagsSubmitResult = ({ data }: Props) => {
const hasErrors = groupedData.items.some((item) => item.error !== null);
const companyWebsite = makePrettyLink(groupedData.companyWebsite);
- const startOverButtonQuery = hasErrors ? _pickBy({
+ const startOverButtonQuery = hasErrors ? pickBy({
requesterName: groupedData.requesterName,
requesterEmail: groupedData.requesterEmail,
companyName: groupedData.companyName,
diff --git a/ui/publicTags/submit/fields/PublicTagsSubmitFieldTagType.tsx b/ui/publicTags/submit/fields/PublicTagsSubmitFieldTagType.tsx
index 23d0c2ec68..df5c3782a0 100644
--- a/ui/publicTags/submit/fields/PublicTagsSubmitFieldTagType.tsx
+++ b/ui/publicTags/submit/fields/PublicTagsSubmitFieldTagType.tsx
@@ -1,7 +1,7 @@
import { chakra, Flex } from '@chakra-ui/react';
import type { GroupBase, SelectComponentsConfig, SingleValueProps } from 'chakra-react-select';
import { chakraComponents } from 'chakra-react-select';
-import _capitalize from 'lodash/capitalize';
+import { capitalize } from 'es-toolkit';
import React from 'react';
import { useFormContext } from 'react-hook-form';
@@ -22,7 +22,7 @@ const PublicTagsSubmitFieldTagType = ({ index, tagTypes }: Props) => {
const typeOptions = React.useMemo(() => tagTypes?.map((type) => ({
value: type.type,
- label: _capitalize(type.type),
+ label: capitalize(type.type),
})) ?? [], [ tagTypes ]);
const fieldValue = watch(`tags.${ index }.type`).value;
diff --git a/ui/publicTags/submit/result/PublicTagsSubmitResultWithErrors.tsx b/ui/publicTags/submit/result/PublicTagsSubmitResultWithErrors.tsx
index e38492462f..92df2f1e6c 100644
--- a/ui/publicTags/submit/result/PublicTagsSubmitResultWithErrors.tsx
+++ b/ui/publicTags/submit/result/PublicTagsSubmitResultWithErrors.tsx
@@ -1,5 +1,5 @@
import { Box, Button, Flex, Grid, GridItem, useColorModeValue } from '@chakra-ui/react';
-import _pickBy from 'lodash/pickBy';
+import { pickBy } from 'es-toolkit';
import React from 'react';
import type { FormSubmitResultGrouped } from '../types';
@@ -23,7 +23,7 @@ const PublicTagsSubmitResultWithErrors = ({ data }: Props) => {
{ data.items.map((item, index) => {
- const startOverButtonQuery = _pickBy({
+ const startOverButtonQuery = pickBy({
addresses: item.addresses,
requesterName: data.requesterName,
requesterEmail: data.requesterEmail,
diff --git a/ui/publicTags/submit/utils.ts b/ui/publicTags/submit/utils.ts
index 6ee6df8c8a..1e45d41d3a 100644
--- a/ui/publicTags/submit/utils.ts
+++ b/ui/publicTags/submit/utils.ts
@@ -1,5 +1,4 @@
-import _isEqual from 'lodash/isEqual';
-import _pickBy from 'lodash/pickBy';
+import { pickBy, isEqual } from 'es-toolkit';
import type { FormFieldTag, FormFields, FormSubmitResult, FormSubmitResultGrouped, FormSubmitResultItemGrouped, SubmitRequestBody } from './types';
import type { UserInfo } from 'types/api/account';
@@ -22,7 +21,7 @@ export function convertFormDataToRequestsBody(data: FormFields): Array error === item.error && _isEqual(tags, item.tags));
+ const existingItem = items.find(({ error, tags }) => error === item.error && isEqual(tags, item.tags));
if (existingItem) {
existingItem.addresses.push(...item.addresses);
continue;
diff --git a/ui/searchResults/SearchResultsInput.tsx b/ui/searchResults/SearchResultsInput.tsx
index 10cc920adb..925ca952a8 100644
--- a/ui/searchResults/SearchResultsInput.tsx
+++ b/ui/searchResults/SearchResultsInput.tsx
@@ -1,5 +1,5 @@
import { PopoverTrigger, PopoverContent, PopoverBody, useDisclosure } from '@chakra-ui/react';
-import _debounce from 'lodash/debounce';
+import { debounce } from 'es-toolkit';
import type { FormEvent, FocusEvent } from 'react';
import React from 'react';
@@ -59,7 +59,7 @@ const SearchResultsInput = ({ searchTerm, handleSubmit, handleSearchTermChange }
}
calculateMenuWidth();
- const resizeHandler = _debounce(calculateMenuWidth, 200);
+ const resizeHandler = debounce(calculateMenuWidth, 200);
const resizeObserver = new ResizeObserver(resizeHandler);
resizeObserver.observe(inputRef.current);
diff --git a/ui/shared/AccountPageDescription.tsx b/ui/shared/AccountPageDescription.tsx
index dc19772a87..3364c34cfc 100644
--- a/ui/shared/AccountPageDescription.tsx
+++ b/ui/shared/AccountPageDescription.tsx
@@ -1,5 +1,5 @@
import { Box, useColorModeValue } from '@chakra-ui/react';
-import _debounce from 'lodash/debounce';
+import { debounce } from 'es-toolkit';
import React, { useRef, useEffect, useState, useCallback } from 'react';
const CUT_HEIGHT = 144;
@@ -25,7 +25,7 @@ const AccountPageDescription = ({ children, allowCut = true }: { children: React
}
calculateCut();
- const resizeHandler = _debounce(calculateCut, 300);
+ const resizeHandler = debounce(calculateCut, 300);
window.addEventListener('resize', resizeHandler);
return function cleanup() {
window.removeEventListener('resize', resizeHandler);
diff --git a/ui/shared/HashStringShortenDynamic.tsx b/ui/shared/HashStringShortenDynamic.tsx
index cb1130662d..343df0f6ab 100644
--- a/ui/shared/HashStringShortenDynamic.tsx
+++ b/ui/shared/HashStringShortenDynamic.tsx
@@ -10,7 +10,7 @@
import type { As } from '@chakra-ui/react';
import { Tooltip, chakra } from '@chakra-ui/react';
-import _debounce from 'lodash/debounce';
+import { debounce } from 'es-toolkit';
import React, { useCallback, useEffect, useRef } from 'react';
import type { FontFace } from 'use-font-face-observer';
import useFontFaceObserver from 'use-font-face-observer';
@@ -81,7 +81,7 @@ const HashStringShortenDynamic = ({ hash, fontWeight = '400', isTooltipDisabled,
}, [ calculateString, isFontFaceLoaded ]);
useEffect(() => {
- const resizeHandler = _debounce(calculateString, 100);
+ const resizeHandler = debounce(calculateString, 100);
const resizeObserver = new ResizeObserver(resizeHandler);
resizeObserver.observe(document.body);
diff --git a/ui/shared/Page/PageTitle.tsx b/ui/shared/Page/PageTitle.tsx
index 9e199f5136..95b3e838f3 100644
--- a/ui/shared/Page/PageTitle.tsx
+++ b/ui/shared/Page/PageTitle.tsx
@@ -1,5 +1,5 @@
import { Heading, Flex, Tooltip, Link, chakra, useDisclosure } from '@chakra-ui/react';
-import _debounce from 'lodash/debounce';
+import { debounce } from 'es-toolkit';
import React from 'react';
import useIsMobile from 'lib/hooks/useIsMobile';
@@ -94,7 +94,7 @@ const PageTitle = ({ title, contentAfter, withTextAd, backLink, className, isLoa
}, [ isLoading, updatedTruncateState ]);
React.useEffect(() => {
- const handleResize = _debounce(updatedTruncateState, 1000);
+ const handleResize = debounce(updatedTruncateState, 1000);
window.addEventListener('resize', handleResize);
return function cleanup() {
diff --git a/ui/shared/Tabs/RoutedTabs.tsx b/ui/shared/Tabs/RoutedTabs.tsx
index 227dc81108..950a45a323 100644
--- a/ui/shared/Tabs/RoutedTabs.tsx
+++ b/ui/shared/Tabs/RoutedTabs.tsx
@@ -1,6 +1,6 @@
import type { ChakraProps, ThemingProps } from '@chakra-ui/react';
import { chakra } from '@chakra-ui/react';
-import _pickBy from 'lodash/pickBy';
+import { pickBy } from 'es-toolkit';
import { useRouter } from 'next/router';
import React, { useEffect, useRef } from 'react';
@@ -42,7 +42,7 @@ const RoutedTabs = ({
const handleTabChange = React.useCallback((index: number) => {
const nextTab = tabs[index];
- const queryForPathname = _pickBy(router.query, (value, key) => router.pathname.includes(`[${ key }]`));
+ const queryForPathname = pickBy(router.query, (value, key) => router.pathname.includes(`[${ key }]`));
const tabId = Array.isArray(nextTab.id) ? nextTab.id[0] : nextTab.id;
router.push(
{ pathname: router.pathname, query: { ...queryForPathname, tab: tabId } },
diff --git a/ui/shared/Tabs/TabsWithScroll.tsx b/ui/shared/Tabs/TabsWithScroll.tsx
index 3b4503e0bb..97dfc6a1f0 100644
--- a/ui/shared/Tabs/TabsWithScroll.tsx
+++ b/ui/shared/Tabs/TabsWithScroll.tsx
@@ -6,7 +6,7 @@ import {
TabPanels,
chakra,
} from '@chakra-ui/react';
-import _debounce from 'lodash/debounce';
+import { debounce } from 'es-toolkit';
import React, { useEffect, useRef, useState } from 'react';
import type { TabItem } from './types';
@@ -69,7 +69,7 @@ const TabsWithScroll = ({
}, [ defaultTabIndex ]);
React.useEffect(() => {
- const resizeHandler = _debounce(() => {
+ const resizeHandler = debounce(() => {
setScreenWidth(window.innerWidth);
}, 100);
const resizeObserver = new ResizeObserver(resizeHandler);
diff --git a/ui/shared/TheadSticky.tsx b/ui/shared/TheadSticky.tsx
index 966e870681..e25af0fbe7 100644
--- a/ui/shared/TheadSticky.tsx
+++ b/ui/shared/TheadSticky.tsx
@@ -1,6 +1,6 @@
import { Thead, useColorModeValue } from '@chakra-ui/react';
import type { TableHeadProps, PositionProps } from '@chakra-ui/react';
-import throttle from 'lodash/throttle';
+import { throttle } from 'es-toolkit';
import React from 'react';
interface Props extends TableHeadProps {
diff --git a/ui/shared/TruncatedTextTooltip.tsx b/ui/shared/TruncatedTextTooltip.tsx
index eaf7dfdd66..454e37e01c 100644
--- a/ui/shared/TruncatedTextTooltip.tsx
+++ b/ui/shared/TruncatedTextTooltip.tsx
@@ -1,6 +1,6 @@
import type { PlacementWithLogical } from '@chakra-ui/react';
import { Tooltip, useDisclosure } from '@chakra-ui/react';
-import debounce from 'lodash/debounce';
+import { debounce } from 'es-toolkit';
import React from 'react';
import useFontFaceObserver from 'use-font-face-observer';
diff --git a/ui/shared/Utilization/Utilization.tsx b/ui/shared/Utilization/Utilization.tsx
index bcd0d9f3f3..82353b1f3e 100644
--- a/ui/shared/Utilization/Utilization.tsx
+++ b/ui/shared/Utilization/Utilization.tsx
@@ -1,5 +1,5 @@
import { Box, Flex, chakra, useColorModeValue } from '@chakra-ui/react';
-import clamp from 'lodash/clamp';
+import { clamp } from 'es-toolkit';
import React from 'react';
import Skeleton from 'ui/shared/chakra/Skeleton';
diff --git a/ui/shared/chart/tooltip/ChartTooltipContent.tsx b/ui/shared/chart/tooltip/ChartTooltipContent.tsx
index da1a62a5d6..a5d325838c 100644
--- a/ui/shared/chart/tooltip/ChartTooltipContent.tsx
+++ b/ui/shared/chart/tooltip/ChartTooltipContent.tsx
@@ -1,5 +1,5 @@
import * as d3 from 'd3';
-import _clamp from 'lodash/clamp';
+import { clamp } from 'es-toolkit';
import React from 'react';
import { POINT_SIZE } from './utils';
@@ -69,33 +69,33 @@ function calculatePosition({ pointX, pointY, canvasWidth, canvasHeight, nodeWidt
// right
if (pointX + offset + nodeWidth <= canvasWidth) {
const x = pointX + offset;
- const y = _clamp(pointY - nodeHeight / 2, 0, canvasHeight - nodeHeight);
+ const y = clamp(pointY - nodeHeight / 2, 0, canvasHeight - nodeHeight);
return [ x, y ];
}
// left
if (nodeWidth + offset <= pointX) {
const x = pointX - offset - nodeWidth;
- const y = _clamp(pointY - nodeHeight / 2, 0, canvasHeight - nodeHeight);
+ const y = clamp(pointY - nodeHeight / 2, 0, canvasHeight - nodeHeight);
return [ x, y ];
}
// top
if (nodeHeight + offset <= pointY) {
- const x = _clamp(pointX - nodeWidth / 2, 0, canvasWidth - nodeWidth);
+ const x = clamp(pointX - nodeWidth / 2, 0, canvasWidth - nodeWidth);
const y = pointY - offset - nodeHeight;
return [ x, y ];
}
// bottom
if (pointY + offset + nodeHeight <= canvasHeight) {
- const x = _clamp(pointX - nodeWidth / 2, 0, canvasWidth - nodeWidth);
+ const x = clamp(pointX - nodeWidth / 2, 0, canvasWidth - nodeWidth);
const y = pointY + offset;
return [ x, y ];
}
- const x = _clamp(pointX / 2, 0, canvasWidth - nodeWidth);
- const y = _clamp(pointY / 2, 0, canvasHeight - nodeHeight);
+ const x = clamp(pointX / 2, 0, canvasWidth - nodeWidth);
+ const y = clamp(pointY / 2, 0, canvasHeight - nodeHeight);
return [ x, y ];
}
diff --git a/ui/shared/chart/useChartLegend.tsx b/ui/shared/chart/useChartLegend.tsx
index 2a0987f8a0..56beded875 100644
--- a/ui/shared/chart/useChartLegend.tsx
+++ b/ui/shared/chart/useChartLegend.tsx
@@ -1,8 +1,8 @@
-import _range from 'lodash/range';
+import { range } from 'es-toolkit';
import React from 'react';
export default function useChartLegend(dataLength: number) {
- const [ selectedLines, setSelectedLines ] = React.useState>(_range(dataLength));
+ const [ selectedLines, setSelectedLines ] = React.useState>(range(dataLength));
const handleLegendItemClick = React.useCallback((index: number) => {
const nextSelectedLines = selectedLines.includes(index) ? selectedLines.filter((item) => item !== index) : [ ...selectedLines, index ];
diff --git a/ui/shared/chart/utils/timeChartAxis.ts b/ui/shared/chart/utils/timeChartAxis.ts
index b57253fe39..95ab77fab1 100644
--- a/ui/shared/chart/utils/timeChartAxis.ts
+++ b/ui/shared/chart/utils/timeChartAxis.ts
@@ -1,6 +1,5 @@
import * as d3 from 'd3';
-import _maxBy from 'lodash/maxBy';
-import _unique from 'lodash/uniq';
+import { maxBy, uniq } from 'es-toolkit';
import type { AxesConfig, AxisConfig, TimeChartData } from '../types';
@@ -88,8 +87,8 @@ function getYLabelFormatParams(ticks: Array, maximumSignificantDigits =
notation: 'compact' as const,
};
- const uniqTicksStr = _unique(ticks.map((tick) => tick.toLocaleString(undefined, params)));
- const maxLabelLength = _maxBy(uniqTicksStr, (items) => items.length)?.length ?? DEFAULT_LABEL_LENGTH;
+ const uniqTicksStr = uniq(ticks.map((tick) => tick.toLocaleString(undefined, params)));
+ const maxLabelLength = maxBy(uniqTicksStr, (items) => items.length)?.length ?? DEFAULT_LABEL_LENGTH;
if (uniqTicksStr.length === ticks.length || maximumSignificantDigits === MAXIMUM_SIGNIFICANT_DIGITS_LIMIT) {
return { ...params, maxLabelLength };
diff --git a/ui/shared/forms/inputs/select/FancySelect.pw.tsx b/ui/shared/forms/inputs/select/FancySelect.pw.tsx
index 1c6ebcfcbd..de15975b29 100644
--- a/ui/shared/forms/inputs/select/FancySelect.pw.tsx
+++ b/ui/shared/forms/inputs/select/FancySelect.pw.tsx
@@ -1,4 +1,4 @@
-import _noop from 'lodash/noop';
+import { noop } from 'es-toolkit';
import React from 'react';
import { test, expect } from 'playwright/lib';
@@ -18,7 +18,7 @@ const defaultProps = {
isRequired: true,
placeholder: 'Compiler',
name: 'compiler',
- onChange: _noop,
+ onChange: noop,
};
[ 'md' as const, 'lg' as const ].forEach((size) => {
diff --git a/ui/shared/monaco/CodeEditorSideBar.tsx b/ui/shared/monaco/CodeEditorSideBar.tsx
index eccf855d42..c7e9af280d 100644
--- a/ui/shared/monaco/CodeEditorSideBar.tsx
+++ b/ui/shared/monaco/CodeEditorSideBar.tsx
@@ -1,6 +1,6 @@
import type { HTMLChakraProps } from '@chakra-ui/react';
import { Box, Tab, TabList, TabPanel, TabPanels, Tabs, useBoolean } from '@chakra-ui/react';
-import _throttle from 'lodash/throttle';
+import { throttle } from 'es-toolkit';
import type * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
import React from 'react';
@@ -47,7 +47,7 @@ const CodeEditorSideBar = ({ onFileSelect, data, monaco, editor, selectedFile, m
letterSpacing: 0.3,
};
- const handleScrollThrottled = React.useRef(_throttle((event: React.SyntheticEvent) => {
+ const handleScrollThrottled = React.useRef(throttle((event: React.SyntheticEvent) => {
setIsStuck((event.target as HTMLDivElement).scrollTop > 0);
}, 100));
diff --git a/ui/shared/pagination/useQueryWithPages.ts b/ui/shared/pagination/useQueryWithPages.ts
index df554bb91b..d6e80c3084 100644
--- a/ui/shared/pagination/useQueryWithPages.ts
+++ b/ui/shared/pagination/useQueryWithPages.ts
@@ -1,6 +1,6 @@
import type { UseQueryResult } from '@tanstack/react-query';
import { useQueryClient } from '@tanstack/react-query';
-import omit from 'lodash/omit';
+import { omit } from 'es-toolkit';
import { useRouter } from 'next/router';
import React, { useCallback } from 'react';
import { animateScroll } from 'react-scroll';
@@ -154,7 +154,14 @@ export default function useQueryWithPages({
}, [ queryClient, resourceName, router, scrollToTop ]);
const onFilterChange = useCallback((newFilters: PaginationFilters | undefined) => {
- const newQuery = omit(router.query, 'next_page_params', 'page', 'filterFields' in resource ? resource.filterFields : []);
+ const newQuery: typeof router.query = omit(
+ router.query,
+ [
+ 'next_page_params',
+ 'page',
+ ...('filterFields' in resource ? resource.filterFields : []),
+ ],
+ );
if (newFilters) {
Object.entries(newFilters).forEach(([ key, value ]) => {
const isValidValue = typeof value === 'boolean' || (value && value.length);
@@ -179,8 +186,8 @@ export default function useQueryWithPages({
}, [ router, resource, scrollToTop ]);
const onSortingChange = useCallback((newSorting: PaginationSorting | undefined) => {
- const newQuery = {
- ...omit(router.query, 'next_page_params', 'page', SORTING_FIELDS),
+ const newQuery: typeof router.query = {
+ ...omit(router.query, [ 'next_page_params', 'page', ...SORTING_FIELDS ]),
...newSorting,
};
scrollToTop();
diff --git a/ui/shared/tagGroupSelect/TagGroupSelect.pw.tsx b/ui/shared/tagGroupSelect/TagGroupSelect.pw.tsx
index 4ccc12110c..82b8426912 100644
--- a/ui/shared/tagGroupSelect/TagGroupSelect.pw.tsx
+++ b/ui/shared/tagGroupSelect/TagGroupSelect.pw.tsx
@@ -1,4 +1,4 @@
-import _noop from 'lodash/noop';
+import { noop } from 'es-toolkit';
import React from 'react';
import { test, expect } from 'playwright/lib';
@@ -12,7 +12,7 @@ test('base view +@dark-mode', async({ render }) => {
,
);
diff --git a/ui/snippets/networkMenu/NetworkMenuContentMobile.tsx b/ui/snippets/networkMenu/NetworkMenuContentMobile.tsx
index 4b48882365..98f1f2b142 100644
--- a/ui/snippets/networkMenu/NetworkMenuContentMobile.tsx
+++ b/ui/snippets/networkMenu/NetworkMenuContentMobile.tsx
@@ -1,5 +1,5 @@
import { Box, Select, VStack, Flex } from '@chakra-ui/react';
-import capitalize from 'lodash/capitalize';
+import { capitalize } from 'es-toolkit';
import React from 'react';
import type { NetworkGroup, FeaturedNetwork } from 'types/networks';
diff --git a/ui/snippets/searchBar/SearchBar.tsx b/ui/snippets/searchBar/SearchBar.tsx
index 07de33d020..806e63c627 100644
--- a/ui/snippets/searchBar/SearchBar.tsx
+++ b/ui/snippets/searchBar/SearchBar.tsx
@@ -8,7 +8,7 @@ import {
useDisclosure,
useOutsideClick,
} from '@chakra-ui/react';
-import _debounce from 'lodash/debounce';
+import { debounce } from 'es-toolkit';
import { useRouter } from 'next/router';
import type { FormEvent } from 'react';
import React from 'react';
@@ -115,7 +115,7 @@ const SearchBar = ({ isHomepage }: Props) => {
}
calculateMenuWidth();
- const resizeHandler = _debounce(calculateMenuWidth, 200);
+ const resizeHandler = debounce(calculateMenuWidth, 200);
const resizeObserver = new ResizeObserver(resizeHandler);
resizeObserver.observe(inputRef.current);
diff --git a/ui/snippets/searchBar/SearchBarInput.tsx b/ui/snippets/searchBar/SearchBarInput.tsx
index 4a8a0e8952..62f1fde327 100644
--- a/ui/snippets/searchBar/SearchBarInput.tsx
+++ b/ui/snippets/searchBar/SearchBarInput.tsx
@@ -1,5 +1,5 @@
import { InputGroup, Input, InputLeftElement, chakra, useColorModeValue, forwardRef, InputRightElement, Center } from '@chakra-ui/react';
-import throttle from 'lodash/throttle';
+import { throttle } from 'es-toolkit';
import React from 'react';
import type { ChangeEvent, FormEvent, FocusEvent } from 'react';
diff --git a/ui/snippets/searchBar/SearchBarSuggest/SearchBarSuggest.tsx b/ui/snippets/searchBar/SearchBarSuggest/SearchBarSuggest.tsx
index a3a01f0a50..e8f392d441 100644
--- a/ui/snippets/searchBar/SearchBarSuggest/SearchBarSuggest.tsx
+++ b/ui/snippets/searchBar/SearchBarSuggest/SearchBarSuggest.tsx
@@ -1,6 +1,6 @@
import { Box, Tab, TabList, Tabs, Text, useColorModeValue } from '@chakra-ui/react';
import type { UseQueryResult } from '@tanstack/react-query';
-import throttle from 'lodash/throttle';
+import { throttle } from 'es-toolkit';
import React from 'react';
import { scroller, Element } from 'react-scroll';
diff --git a/ui/snippets/searchBar/__screenshots__/SearchBar.pw.tsx_default_scroll-suggest-to-category-1.png b/ui/snippets/searchBar/__screenshots__/SearchBar.pw.tsx_default_scroll-suggest-to-category-1.png
index ca47f6fdd9..266acbdea6 100644
Binary files a/ui/snippets/searchBar/__screenshots__/SearchBar.pw.tsx_default_scroll-suggest-to-category-1.png and b/ui/snippets/searchBar/__screenshots__/SearchBar.pw.tsx_default_scroll-suggest-to-category-1.png differ
diff --git a/ui/tokenInstance/metadata/utils.ts b/ui/tokenInstance/metadata/utils.ts
index d99db798e9..9442b19714 100644
--- a/ui/tokenInstance/metadata/utils.ts
+++ b/ui/tokenInstance/metadata/utils.ts
@@ -1,11 +1,11 @@
-import _upperFirst from 'lodash/upperFirst';
+import { upperFirst } from 'es-toolkit';
export function formatName(_name: string) {
const name = _name
.replaceAll('_', ' ')
.replaceAll(/\burl|nft|id\b/gi, (str) => str.toUpperCase());
- return _upperFirst(name.trim());
+ return upperFirst(name.trim());
}
const PINNED_FIELDS = [ 'name', 'description' ];
diff --git a/ui/tx/TxAssetFlows.tsx b/ui/tx/TxAssetFlows.tsx
index c4d0dac409..97ec6a3603 100644
--- a/ui/tx/TxAssetFlows.tsx
+++ b/ui/tx/TxAssetFlows.tsx
@@ -1,5 +1,5 @@
import { Table, Tbody, Tr, Th, Box, Text, Show, Hide } from '@chakra-ui/react';
-import _chunk from 'lodash/chunk';
+import { chunk } from 'es-toolkit';
import React, { useMemo, useState } from 'react';
import type { PaginationParams } from 'ui/shared/pagination/types';
@@ -34,7 +34,7 @@ export default function TxAssetFlows(props: FlowViewProps) {
const [ page, setPage ] = useState(1);
const ViewData = useMemo(() => (queryData ? generateFlowViewData(queryData) : []), [ queryData ]);
- const chunkedViewData = _chunk(ViewData, 50);
+ const chunkedViewData = chunk(ViewData, 50);
const paginationProps: PaginationParams = useMemo(() => ({
onNextPageClick: () => setPage(page + 1),
diff --git a/ui/tx/assetFlows/utils/generateFlowViewData.ts b/ui/tx/assetFlows/utils/generateFlowViewData.ts
index e4adb0d348..5024942104 100644
--- a/ui/tx/assetFlows/utils/generateFlowViewData.ts
+++ b/ui/tx/assetFlows/utils/generateFlowViewData.ts
@@ -1,5 +1,3 @@
-import _findIndex from 'lodash/findIndex';
-
import type { NovesNft, NovesResponseData, NovesSentReceived, NovesToken } from 'types/api/noves';
export interface NovesAction {
@@ -27,7 +25,7 @@ export function generateFlowViewData(data: NovesResponseData): Array item.action === 'paidGas');
+ const paidGasIndex = txItems.findIndex((item) => item.action === 'paidGas');
if (paidGasIndex >= 0) {
const element = txItems.splice(paidGasIndex, 1)[0];
element.to.name = 'Validators';
diff --git a/ui/tx/assetFlows/utils/getTokensData.ts b/ui/tx/assetFlows/utils/getTokensData.ts
index 159dcca11a..d4a1d51a22 100644
--- a/ui/tx/assetFlows/utils/getTokensData.ts
+++ b/ui/tx/assetFlows/utils/getTokensData.ts
@@ -1,6 +1,4 @@
-import _groupBy from 'lodash/groupBy';
-import _keysIn from 'lodash/keysIn';
-import _mapValues from 'lodash/mapValues';
+import { groupBy, mapValues } from 'es-toolkit';
import type { NovesResponseData } from 'types/api/noves';
import type { TokenInfo } from 'types/api/token';
@@ -49,28 +47,28 @@ export function getTokensData(data: NovesResponseData): TokensData {
});
// Group tokens by property into arrays
- const tokensGroupByname = _groupBy(tokens, 'name');
- const tokensGroupBySymbol = _groupBy(tokens, 'symbol');
- const tokensGroupById = _groupBy(tokens, 'id');
+ const tokensGroupByName = groupBy(tokens, (item) => item.name || 'null');
+ const tokensGroupBySymbol = groupBy(tokens, (item) => item.symbol || 'null');
+ const tokensGroupById = groupBy(tokens, (item) => item.id || 'null');
// Map properties to an object and remove duplicates
- const mappedNames = _mapValues(tokensGroupByname, (i) => {
+ const mappedNames = mapValues(tokensGroupByName, (i) => {
return i[0];
});
- const mappedSymbols = _mapValues(tokensGroupBySymbol, (i) => {
+ const mappedSymbols = mapValues(tokensGroupBySymbol, (i) => {
return i[0];
});
- const mappedIds = _mapValues(tokensGroupById, (i) => {
+ const mappedIds = mapValues(tokensGroupById, (i) => {
return i[0];
});
const filters = [ 'undefined', 'null' ];
// Array of keys to match in string
- const nameList = _keysIn(mappedNames).filter(i => !filters.includes(i));
- const symbolList = _keysIn(mappedSymbols).filter(i => !filters.includes(i));
- const idList = _keysIn(mappedIds).filter(i => !filters.includes(i));
+ const nameList = Object.keys(mappedNames).filter(i => !filters.includes(i));
+ const symbolList = Object.keys(mappedSymbols).filter(i => !filters.includes(i));
+ const idList = Object.keys(mappedIds).filter(i => !filters.includes(i));
return {
nameList,
diff --git a/ui/txs/noves/useDescribeTxs.tsx b/ui/txs/noves/useDescribeTxs.tsx
index 1d2f611da4..888ec91c04 100644
--- a/ui/txs/noves/useDescribeTxs.tsx
+++ b/ui/txs/noves/useDescribeTxs.tsx
@@ -1,6 +1,5 @@
import { useQuery } from '@tanstack/react-query';
-import _chunk from 'lodash/chunk';
-import _uniq from 'lodash/uniq';
+import { uniq, chunk } from 'es-toolkit';
import React from 'react';
import type { NovesDescribeTxsResponse } from 'types/api/noves';
@@ -16,8 +15,8 @@ const translateEnabled = feature.isEnabled && feature.provider === 'noves';
export default function useDescribeTxs(items: Array | undefined, viewAsAccountAddress: string | undefined, isPlaceholderData: boolean) {
const apiFetch = useApiFetch();
- const txsHash = _uniq(items?.map(i => i.hash));
- const txChunks = _chunk(txsHash, 10);
+ const txsHash = items ? uniq(items.map(i => i.hash)) : [];
+ const txChunks = chunk(txsHash, 10);
const queryKey = {
viewAsAccountAddress,
diff --git a/yarn.lock b/yarn.lock
index cb671a6f9d..eedbade03b 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -10376,6 +10376,11 @@ es-to-primitive@^1.2.1:
is-date-object "^1.0.1"
is-symbol "^1.0.2"
+es-toolkit@1.31.0:
+ version "1.31.0"
+ resolved "https://registry.yarnpkg.com/es-toolkit/-/es-toolkit-1.31.0.tgz#f4fc1382aea09cb239afa38f3c724a5658ff3163"
+ integrity sha512-vwS0lv/tzjM2/t4aZZRAgN9I9TP0MSkWuvt6By+hEXfG/uLs8yg2S1/ayRXH/x3pinbLgVJYT+eppueg3cM6tg==
+
esbuild@^0.21.3:
version "0.21.5"
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.21.5.tgz#9ca301b120922959b766360d8ac830da0d02997d"
@@ -13573,7 +13578,7 @@ lodash.throttle@^4.1.1:
resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4"
integrity sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==
-lodash@^4.0.0, lodash@^4.15.0, lodash@^4.17.21:
+lodash@^4.15.0, lodash@^4.17.21:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==