Commit 02393619 authored by Max Alekseenko's avatar Max Alekseenko Committed by GitHub

Bump `react` to v19 (#2782)

Co-authored-by: default avatartom <tom@ohhhh.me>
parent dd445832
......@@ -4,7 +4,7 @@ import React from 'react';
export default function useClientRect<E extends Element>(): [ DOMRect | null, LegacyRef<E> | undefined ] {
const [ rect, setRect ] = React.useState<DOMRect | null>(null);
const nodeRef = React.useRef<E>();
const nodeRef = React.useRef<E>(null);
const ref = React.useCallback((node: E) => {
if (node !== null) {
......
......@@ -3,7 +3,7 @@ import React from 'react';
// run effect only if value is updated since initial mount
const useUpdateValueEffect = (effect: () => void, value: string) => {
const mountedRef = React.useRef(false);
const valueRef = React.useRef<string>();
const valueRef = React.useRef<string>(undefined);
const isChangedRef = React.useRef(false);
React.useEffect(() => {
......
......@@ -17,8 +17,8 @@ interface Params {
export default function useSocketChannel({ topic, params, isDisabled, onJoin, onSocketClose, onSocketError }: Params) {
const socket = useSocket();
const [ channel, setChannel ] = useState<Channel>();
const onCloseRef = useRef<string>();
const onErrorRef = useRef<string>();
const onCloseRef = useRef<string>(undefined);
const onErrorRef = useRef<string>(undefined);
const onJoinRef = useRef(onJoin);
onJoinRef.current = onJoin;
......
......@@ -6,25 +6,25 @@ export function monaco(): CspDev.DirectiveDescriptor {
return {
'script-src': [
KEY_WORDS.BLOB,
'https://cdn.jsdelivr.net/npm/monaco-editor@0.33.0/min/vs/loader.js',
'https://cdn.jsdelivr.net/npm/monaco-editor@0.33.0/min/vs/editor/editor.main.js',
'https://cdn.jsdelivr.net/npm/monaco-editor@0.33.0/min/vs/editor/editor.main.nls.js',
'https://cdn.jsdelivr.net/npm/monaco-editor@0.33.0/min/vs/basic-languages/solidity/solidity.js',
'https://cdn.jsdelivr.net/npm/monaco-editor@0.33.0/min/vs/basic-languages/elixir/elixir.js',
'https://cdn.jsdelivr.net/npm/monaco-editor@0.33.0/min/vs/basic-languages/javascript/javascript.js',
'https://cdn.jsdelivr.net/npm/monaco-editor@0.33.0/min/vs/basic-languages/typescript/typescript.js',
'https://cdn.jsdelivr.net/npm/monaco-editor@0.33.0/min/vs/basic-languages/rust/rust.js',
'https://cdn.jsdelivr.net/npm/monaco-editor@0.33.0/min/vs/language/json/jsonMode.js',
'https://cdn.jsdelivr.net/npm/monaco-editor@0.33.0/min/vs/language/json/jsonWorker.js',
'https://cdn.jsdelivr.net/npm/monaco-editor@0.33.0/min/vs/language/typescript/tsMode.js',
'https://cdn.jsdelivr.net/npm/monaco-editor@0.33.0/min/vs/language/typescript/tsWorker.js',
'https://cdn.jsdelivr.net/npm/monaco-editor@0.33.0/min/vs/base/worker/workerMain.js',
'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs/loader.js',
'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs/editor/editor.main.js',
'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs/editor/editor.main.nls.js',
'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs/basic-languages/solidity/solidity.js',
'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs/basic-languages/elixir/elixir.js',
'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs/basic-languages/javascript/javascript.js',
'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs/basic-languages/typescript/typescript.js',
'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs/basic-languages/rust/rust.js',
'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs/language/json/jsonMode.js',
'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs/language/json/jsonWorker.js',
'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs/language/typescript/tsMode.js',
'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs/language/typescript/tsWorker.js',
'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs/base/worker/workerMain.js',
],
'style-src': [
'https://cdn.jsdelivr.net/npm/monaco-editor@0.33.0/min/vs/editor/editor.main.css',
'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs/editor/editor.main.css',
],
'font-src': [
'https://cdn.jsdelivr.net/npm/monaco-editor@0.33.0/min/vs/base/browser/ui/codicons/codicon/codicon.ttf',
'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs/base/browser/ui/codicons/codicon/codicon.ttf',
],
};
}
......@@ -44,8 +44,8 @@
"dependencies": {
"@blockscout/bens-types": "1.4.1",
"@blockscout/points-types": "1.3.0-alpha.2",
"@blockscout/tac-operation-lifecycle-types": "0.0.1-alpha.6",
"@blockscout/stats-types": "^2.9.0",
"@blockscout/tac-operation-lifecycle-types": "0.0.1-alpha.6",
"@blockscout/visualizer-types": "0.2.0",
"@chakra-ui/react": "3.15.0",
"@cloudnouns/kit": "1.1.6",
......@@ -55,7 +55,7 @@
"@hypelab/sdk-react": "^1.0.0",
"@metamask/post-message-stream": "^7.0.0",
"@metamask/providers": "^10.2.1",
"@monaco-editor/react": "^4.4.6",
"@monaco-editor/react": "^4.7.0",
"@next/bundle-analyzer": "15.0.3",
"@opentelemetry/api": "^1.4.1",
"@opentelemetry/auto-instrumentations-node": "0.43.0",
......@@ -82,7 +82,7 @@
"chakra-react-select": "^4.4.3",
"crypto-js": "^4.2.0",
"d3": "^7.6.1",
"dappscout-iframe": "0.2.6",
"dappscout-iframe": "0.3.0",
"dayjs": "^1.11.5",
"dom-to-image": "^2.6.0",
"es-toolkit": "1.31.0",
......@@ -106,9 +106,9 @@
"pino-pretty": "^9.1.1",
"prom-client": "15.1.1",
"qrcode": "^1.5.1",
"react": "18.3.1",
"react": "19.1.0",
"react-device-detect": "^2.2.3",
"react-dom": "18.3.1",
"react-dom": "19.1.0",
"react-google-recaptcha": "3.1.0",
"react-hook-form": "7.52.1",
"react-icons": "5.4.0",
......@@ -119,7 +119,7 @@
"react-scroll": "^1.8.7",
"rollbar": "2.26.4",
"swagger-ui-react": "5.20.3",
"use-font-face-observer": "^1.2.1",
"use-font-face-observer": "^1.3.0",
"valibot": "0.38.0",
"viem": "2.23.14",
"wagmi": "2.14.15",
......@@ -147,8 +147,8 @@
"@types/node": "20.16.7",
"@types/phoenix": "^1.5.4",
"@types/qrcode": "^1.5.0",
"@types/react": "18.3.12",
"@types/react-dom": "18.3.1",
"@types/react": "19.1.7",
"@types/react-dom": "19.1.6",
"@types/react-google-recaptcha": "^2.1.5",
"@types/swagger-ui-react": "5.18.0",
"@types/ws": "^8.5.3",
......
import type { Locator } from '@playwright/test';
import { expect } from 'playwright/lib';
export async function stableHover(element: Locator) {
await expect(element).toBeVisible();
await expect(element).toBeAttached();
const page = element.page();
const box = await element.boundingBox();
await page.mouse.move(box!.x + box!.width / 2, box!.y + box!.height / 2);
await page.waitForTimeout(50);
}
......@@ -13,7 +13,7 @@ export const IconButton = React.forwardRef<HTMLButtonElement, IconButtonProps>(
// FIXME: I have to clone the children instead of using _icon props because of style overrides
// in some pw tests for some reason the _icon style will be applied before the style of child (IconSvg component)
const child = React.Children.only<React.ReactElement>(children as React.ReactElement);
const clonedChildren = size ? React.cloneElement(child, { boxSize: 5 }) : child;
const clonedChildren = size ? React.cloneElement(child, { boxSize: 5 } as React.HTMLAttributes<HTMLElement>) : child;
const sizeStyle = (() => {
switch (size) {
......
......@@ -7,10 +7,10 @@ import type { TabItemRegular } from './types';
import { useScrollDirection } from 'lib/contexts/scrollDirection';
import useIsMobile from 'lib/hooks/useIsMobile';
import { useIsSticky } from '../..//hooks/useIsSticky';
import { Skeleton } from '../../chakra/skeleton';
import type { TabsProps } from '../../chakra/tabs';
import { TabsCounter, TabsList, TabsTrigger } from '../../chakra/tabs';
import { useIsSticky } from '../../hooks/useIsSticky';
import AdaptiveTabsMenu from './AdaptiveTabsMenu';
import useAdaptiveTabs from './useAdaptiveTabs';
import useScrollToActiveTab from './useScrollToActiveTab';
......
......@@ -3,7 +3,7 @@ import React from 'react';
interface Props {
activeTabIndex: number;
tabsRefs: Array<React.RefObject<HTMLButtonElement>>;
listRef: React.RefObject<HTMLDivElement>;
listRef: React.RefObject<HTMLDivElement | null>;
isMobile?: boolean;
isLoading?: boolean;
}
......
......@@ -74,7 +74,7 @@ export const TruncatedTextTooltip = React.memo(({ children, label, placement, in
onClick: handleClick,
onMouseEnter: onOpen,
onMouseLeave: onClose,
},
} as React.HTMLAttributes<HTMLElement>,
);
if (isTruncated) {
......
import { throttle } from 'es-toolkit';
import React from 'react';
export function useIsSticky(ref: React.RefObject<HTMLDivElement>, offset = 0, isEnabled = true) {
export function useIsSticky(ref: React.RefObject<HTMLElement | null>, offset = 0, isEnabled = true): boolean {
const [ isSticky, setIsSticky ] = React.useState(false);
const handleScroll = React.useCallback(() => {
......
......@@ -32,7 +32,7 @@ interface Props {
}
const ContractMethodFieldInput = ({ data, hideLabel, path: name, className, isDisabled, isOptional: isOptionalProp, level }: Props) => {
const ref = React.useRef<HTMLInputElement>();
const ref = React.useRef<HTMLInputElement>(null);
const [ intPower, setIntPower ] = React.useState<number>(18);
......
......@@ -49,8 +49,8 @@ const ContractVerificationForm = ({ method: methodFromQuery, config, hash }: Pro
defaultValues: getDefaultValues(methodFromQuery, config, hash, []),
});
const { handleSubmit, watch, formState, setError, reset, getFieldState, getValues, clearErrors } = formApi;
const submitPromiseResolver = React.useRef<(value: unknown) => void>();
const methodNameRef = React.useRef<string>();
const submitPromiseResolver = React.useRef<((value: unknown) => void)>(undefined);
const methodNameRef = React.useRef<string>(undefined);
const apiFetch = useApiFetch();
const { trackContract } = useRewardsActivity();
......
......@@ -79,7 +79,7 @@ const Chart = () => {
const interval = intervalState || getIntervalByResolution(resolution);
const ref = React.useRef(null);
const ref = React.useRef<HTMLDivElement>(null);
const isMobile = useIsMobile();
const isInBrowser = isBrowser();
......
import type { Page } from '@playwright/test';
import React from 'react';
import { apps as appsMock } from 'mocks/apps/apps';
......@@ -7,8 +8,13 @@ import { test, expect } from 'playwright/lib';
import SearchResults from './SearchResults';
async function resetScroll(page: Page) {
await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
await page.evaluate(() => window.scrollTo(0, 0));
}
test.describe('search by name', () => {
test('+@mobile +@dark-mode', async({ render, mockApiResponse, mockAssetResponse, mockEnvs }) => {
test('+@mobile +@dark-mode', async({ render, mockApiResponse, mockAssetResponse, mockEnvs, page }) => {
const hooksConfig = {
router: {
query: { q: 'o' },
......@@ -31,12 +37,13 @@ test.describe('search by name', () => {
await mockApiResponse('general:search', data, { queryParams: { q: 'o' } });
await mockAssetResponse(searchMock.token1.icon_url as string, './playwright/mocks/image_s.jpg');
const component = await render(<SearchResults/>, { hooksConfig });
await resetScroll(page);
await expect(component.locator('main')).toHaveScreenshot();
});
});
test('search by address hash +@mobile', async({ render, mockApiResponse }) => {
test('search by address hash +@mobile', async({ render, mockApiResponse, page }) => {
const hooksConfig = {
router: {
query: { q: searchMock.address1.address_hash },
......@@ -49,11 +56,12 @@ test('search by address hash +@mobile', async({ render, mockApiResponse }) => {
await mockApiResponse('general:search', data, { queryParams: { q: searchMock.address1.address_hash } });
const component = await render(<SearchResults/>, { hooksConfig });
await resetScroll(page);
await expect(component.locator('main')).toHaveScreenshot();
});
test('search by meta tag +@mobile', async({ render, mockApiResponse }) => {
test('search by meta tag +@mobile', async({ render, mockApiResponse, page }) => {
const hooksConfig = {
router: {
query: { q: 'utko' },
......@@ -66,11 +74,12 @@ test('search by meta tag +@mobile', async({ render, mockApiResponse }) => {
await mockApiResponse('general:search', data, { queryParams: { q: 'utko' } });
const component = await render(<SearchResults/>, { hooksConfig });
await resetScroll(page);
await expect(component.locator('main')).toHaveScreenshot();
});
test('search by block number +@mobile', async({ render, mockApiResponse }) => {
test('search by block number +@mobile', async({ render, mockApiResponse, page }) => {
const hooksConfig = {
router: {
query: { q: String(searchMock.block1.block_number) },
......@@ -82,11 +91,12 @@ test('search by block number +@mobile', async({ render, mockApiResponse }) => {
};
await mockApiResponse('general:search', data, { queryParams: { q: searchMock.block1.block_number } });
const component = await render(<SearchResults/>, { hooksConfig });
await resetScroll(page);
await expect(component.locator('main')).toHaveScreenshot();
});
test('search by block hash +@mobile', async({ render, mockApiResponse }) => {
test('search by block hash +@mobile', async({ render, mockApiResponse, page }) => {
const hooksConfig = {
router: {
query: { q: searchMock.block1.block_hash },
......@@ -98,11 +108,12 @@ test('search by block hash +@mobile', async({ render, mockApiResponse }) => {
};
await mockApiResponse('general:search', data, { queryParams: { q: searchMock.block1.block_hash } });
const component = await render(<SearchResults/>, { hooksConfig });
await resetScroll(page);
await expect(component.locator('main')).toHaveScreenshot();
});
test('search by tx hash +@mobile', async({ render, mockApiResponse }) => {
test('search by tx hash +@mobile', async({ render, mockApiResponse, page }) => {
const hooksConfig = {
router: {
query: { q: searchMock.tx1.transaction_hash },
......@@ -114,11 +125,12 @@ test('search by tx hash +@mobile', async({ render, mockApiResponse }) => {
};
await mockApiResponse('general:search', data, { queryParams: { q: searchMock.tx1.transaction_hash } });
const component = await render(<SearchResults/>, { hooksConfig });
await resetScroll(page);
await expect(component.locator('main')).toHaveScreenshot();
});
test('search by tac operation hash +@mobile', async({ render, mockApiResponse, mockEnvs }) => {
test('search by tac operation hash +@mobile', async({ render, mockApiResponse, mockEnvs, page }) => {
await mockEnvs(ENVS_MAP.tac);
const hooksConfig = {
router: {
......@@ -131,11 +143,12 @@ test('search by tac operation hash +@mobile', async({ render, mockApiResponse, m
};
await mockApiResponse('general:search', data, { queryParams: { q: searchMock.tacOperation1.tac_operation.operation_id } });
const component = await render(<SearchResults/>, { hooksConfig });
await resetScroll(page);
await expect(component.locator('main')).toHaveScreenshot();
});
test('search by blob hash +@mobile', async({ render, mockApiResponse, mockEnvs }) => {
test('search by blob hash +@mobile', async({ render, mockApiResponse, mockEnvs, page }) => {
const hooksConfig = {
router: {
query: { q: searchMock.blob1.blob_hash },
......@@ -148,11 +161,12 @@ test('search by blob hash +@mobile', async({ render, mockApiResponse, mockEnvs }
await mockEnvs(ENVS_MAP.dataAvailability);
await mockApiResponse('general:search', data, { queryParams: { q: searchMock.blob1.blob_hash } });
const component = await render(<SearchResults/>, { hooksConfig });
await resetScroll(page);
await expect(component.locator('main')).toHaveScreenshot();
});
test('search by domain name +@mobile', async({ render, mockApiResponse, mockEnvs }) => {
test('search by domain name +@mobile', async({ render, mockApiResponse, mockEnvs, page }) => {
const hooksConfig = {
router: {
query: { q: searchMock.domain1.ens_info.name },
......@@ -165,10 +179,12 @@ test('search by domain name +@mobile', async({ render, mockApiResponse, mockEnvs
await mockEnvs(ENVS_MAP.nameService);
await mockApiResponse('general:search', data, { queryParams: { q: searchMock.domain1.ens_info.name } });
const component = await render(<SearchResults/>, { hooksConfig });
await resetScroll(page);
await expect(component.locator('main')).toHaveScreenshot();
});
test('search by user op hash +@mobile', async({ render, mockApiResponse, mockEnvs }) => {
test('search by user op hash +@mobile', async({ render, mockApiResponse, mockEnvs, page }) => {
const hooksConfig = {
router: {
query: { q: searchMock.userOp1.user_operation_hash },
......@@ -181,12 +197,13 @@ test('search by user op hash +@mobile', async({ render, mockApiResponse, mockEnv
await mockEnvs(ENVS_MAP.userOps);
await mockApiResponse('general:search', data, { queryParams: { q: searchMock.userOp1.user_operation_hash } });
const component = await render(<SearchResults/>, { hooksConfig });
await resetScroll(page);
await expect(component.locator('main')).toHaveScreenshot();
});
test.describe('with apps', () => {
test('default view +@mobile', async({ render, mockApiResponse, mockConfigResponse, mockAssetResponse, mockEnvs }) => {
test('default view +@mobile', async({ render, mockApiResponse, mockConfigResponse, mockAssetResponse, mockEnvs, page }) => {
const MARKETPLACE_CONFIG_URL = 'https://localhost:4000/marketplace-config.json';
const hooksConfig = {
router: {
......@@ -216,6 +233,7 @@ test.describe('with apps', () => {
await mockAssetResponse(appsMock[0].logo, './playwright/mocks/image_s.jpg');
await mockAssetResponse(appsMock[1].logo, './playwright/mocks/image_s.jpg');
const component = await render(<SearchResults/>, { hooksConfig });
await resetScroll(page);
await expect(component.locator('main')).toHaveScreenshot();
});
......@@ -229,20 +247,22 @@ test.describe('block countdown', () => {
},
};
test('no results', async({ render, mockApiResponse }) => {
test('no results', async({ render, mockApiResponse, page }) => {
await mockApiResponse('general:search', { items: [], next_page_params: null }, { queryParams: { q: blockHeight } });
const component = await render(<SearchResults/>, { hooksConfig });
await resetScroll(page);
await expect(component.locator('main')).toHaveScreenshot();
});
test('with results +@mobile', async({ render, mockApiResponse }) => {
test('with results +@mobile', async({ render, mockApiResponse, page }) => {
await mockApiResponse(
'general:search',
{ items: [ { ...searchMock.token1, name: '1234567890123456789' } ], next_page_params: null },
{ queryParams: { q: blockHeight } },
);
const component = await render(<SearchResults/>, { hooksConfig });
await resetScroll(page);
await expect(component.locator('main')).toHaveScreenshot();
});
......
......@@ -65,7 +65,9 @@ const SearchResultsInput = ({ searchTerm, handleSubmit, handleSearchTermChange }
const resizeHandler = debounce(calculateMenuWidth, 200);
const resizeObserver = new ResizeObserver(resizeHandler);
if (inputRef.current) {
resizeObserver.observe(inputRef.current);
}
return function cleanup() {
resizeObserver.unobserve(inputEl);
......
......@@ -9,7 +9,7 @@ const INCREMENT = 3;
const ChartLineLoader = ({ className }: { className?: string }) => {
const ref = React.useRef<SVGPathElement>(null);
const raf = React.useRef<number>();
const raf = React.useRef<number>(undefined);
const offset = React.useRef(0);
const [ lineBgColor ] = useToken('colors', useColorModeValue('gray.200', 'gray.500'));
......
......@@ -22,7 +22,7 @@ export type Props = {
description?: string;
units?: string;
isLoading: boolean;
chartRef: React.RefObject<HTMLDivElement>;
chartRef: React.RefObject<HTMLDivElement | null>;
chartUrl?: string;
resolution?: Resolution;
zoomRange?: [ Date, Date ];
......
......@@ -21,8 +21,8 @@ const ChartSelectionX = ({ anchorEl, height, scale, data, onSelect }: Props) =>
const ref = React.useRef(null);
const isActive = React.useRef(false);
const startX = React.useRef<number>();
const endX = React.useRef<number>();
const startX = React.useRef<number>(undefined);
const endX = React.useRef<number>(undefined);
const getIndexByX = React.useCallback((x: number) => {
const xDate = scale.invert(x);
......
......@@ -38,7 +38,7 @@ const ChartTooltip = ({
...props
}: Props) => {
const ref = React.useRef<SVGGElement>(null);
const trackerId = React.useRef<number>();
const trackerId = React.useRef<number>(undefined);
const isVisible = React.useRef(false);
const transitionDuration = !noAnimation ? 100 : null;
......
......@@ -24,7 +24,7 @@ interface UseRenderBackdropParams {
transitionDuration: number | null;
}
export function useRenderBackdrop(ref: React.RefObject<SVGGElement>, { seriesNum, transitionDuration }: UseRenderBackdropParams) {
export function useRenderBackdrop(ref: React.RefObject<SVGGElement | null>, { seriesNum, transitionDuration }: UseRenderBackdropParams) {
return React.useCallback((width: number, isIncompleteData: boolean) => {
const height = calculateContainerHeight(seriesNum, isIncompleteData);
......
......@@ -22,7 +22,7 @@ interface UseRenderContentParams {
transitionDuration: number | null;
}
export function useRenderContent(ref: React.RefObject<SVGGElement>, { chart, transitionDuration }: UseRenderContentParams) {
export function useRenderContent(ref: React.RefObject<SVGGElement | null>, { chart, transitionDuration }: UseRenderContentParams) {
return React.useCallback((x: number, y: number) => {
const tooltipContent = d3.select(ref.current).select('.ChartTooltip__content');
......
......@@ -9,7 +9,7 @@ const ChartTooltipLine = () => {
export default React.memo(ChartTooltipLine);
export function useRenderLine(ref: React.RefObject<SVGGElement>, chartHeight: number | undefined) {
export function useRenderLine(ref: React.RefObject<SVGGElement | null>, chartHeight: number | undefined) {
return React.useCallback((x: number) => {
d3.select(ref.current)
.select('.ChartTooltip__line')
......
......@@ -43,7 +43,7 @@ interface RenderPointsReturnType {
currentPoints: Array<CurrentPoint>;
}
export function useRenderPoints(ref: React.RefObject<SVGGElement>, params: UseRenderPointsParams) {
export function useRenderPoints(ref: React.RefObject<SVGGElement | null>, params: UseRenderPointsParams) {
return React.useCallback((x: number): RenderPointsReturnType => {
const xDate = params.xScale.invert(x);
const bisectDate = d3.bisector<TimeChartItem, unknown>((d) => d.date).left;
......
......@@ -51,7 +51,7 @@ interface UseRenderRowsReturnType {
width: number;
}
export function useRenderRows(ref: React.RefObject<SVGGElement>, { data, xScale, minWidth }: UseRenderRowsParams) {
export function useRenderRows(ref: React.RefObject<SVGGElement | null>, { data, xScale, minWidth }: UseRenderRowsParams) {
return React.useCallback((x: number, currentPoints: Array<CurrentPoint>): UseRenderRowsReturnType => {
// update "transform" prop of all rows
......
......@@ -29,7 +29,7 @@ const ChartTooltipTitle = ({ resolution = Resolution.DAY }: { resolution?: Resol
export default React.memo(ChartTooltipTitle);
export function useRenderTitle(ref: React.RefObject<SVGGElement>) {
export function useRenderTitle(ref: React.RefObject<SVGGElement | null>) {
return React.useCallback((isVisible: boolean) => {
d3.select(ref.current)
.select('.ChartTooltip__title')
......
......@@ -11,7 +11,7 @@ interface Props {
}
export default function useBrushX({ limits, anchor, setRange }: Props) {
const brushRef = React.useRef<d3.BrushBehavior<unknown>>();
const brushRef = React.useRef<d3.BrushBehavior<unknown>>(undefined);
const [ brushSelectionBg ] = useToken('colors', useColorModeValue('blackAlpha.400', 'whiteAlpha.500'));
React.useEffect(() => {
......
import React from 'react';
import * as domainMock from 'mocks/ens/domain';
import { stableHover } from 'playwright/helpers/stableHover';
import { test, expect } from 'playwright/lib';
import EnsEntity from './EnsEntity';
......@@ -43,7 +44,7 @@ test('with long name', async({ render }) => {
/>,
);
await component.getByText(name.slice(0, 4)).hover();
await stableHover(component.getByText(name.slice(0, 4)));
await expect(component).toHaveScreenshot();
});
......
......@@ -2,6 +2,7 @@ import { Box } from '@chakra-ui/react';
import React from 'react';
import * as tokenMock from 'mocks/tokens/tokenInfo';
import { stableHover } from 'playwright/helpers/stableHover';
import { test, expect } from 'playwright/lib';
import TokenEntity from './TokenEntity';
......@@ -46,10 +47,10 @@ test('with logo, long name and symbol', async({ page, render }) => {
/>,
);
await page.getByText(/this/i).hover();
await stableHover(page.getByText(/this/i));
await expect(page).toHaveScreenshot();
await page.getByText(/duc/i).hover();
await stableHover(page.getByText(/duc/i));
await expect(page).toHaveScreenshot();
});
......
......@@ -7,7 +7,7 @@ import type { Params as ApiInfiniteQueryParams } from 'lib/api/useApiInfiniteQue
import useApiInfiniteQuery from 'lib/api/useApiInfiniteQuery';
interface Params<Resource extends PaginatedResourceName> extends ApiInfiniteQueryParams<Resource> {
rootRef: React.RefObject<HTMLElement>;
rootRef: React.RefObject<HTMLElement | null>;
}
interface ReturnType<Resource extends PaginatedResourceName> {
......
......@@ -22,7 +22,7 @@ export interface Params<Resource extends PaginatedResourceName> {
pathParams?: UseApiQueryParams<Resource>['pathParams'];
filters?: PaginationFilters<Resource>;
sorting?: PaginationSorting<Resource>;
scrollRef?: React.RefObject<HTMLDivElement>;
scrollRef?: React.RefObject<HTMLDivElement | null>;
}
type NextPageParams = Record<string, unknown>;
......
......@@ -4,7 +4,6 @@ import { debounce } from 'es-toolkit';
import { useRouter } from 'next/router';
import type { FormEvent } from 'react';
import React from 'react';
import { Element } from 'react-scroll';
import type { Route } from 'nextjs-routes';
import { route } from 'nextjs-routes';
......@@ -123,7 +122,9 @@ const SearchBar = ({ isHomepage }: Props) => {
const resizeHandler = debounce(calculateMenuWidth, 200);
const resizeObserver = new ResizeObserver(resizeHandler);
if (inputRef.current) {
resizeObserver.observe(inputRef.current);
}
return function cleanup() {
resizeObserver.unobserve(inputEl);
......@@ -170,7 +171,6 @@ const SearchBar = ({ isHomepage }: Props) => {
overflowY="auto"
id={ SCROLL_CONTAINER_ID }
ref={ scrollRef }
as={ Element }
px={ 4 }
>
{ searchTerm.trim().length === 0 && recentSearchKeywords.length > 0 && (
......
......@@ -24,7 +24,7 @@ interface Props {
data?: TokenInstance;
token?: TokenInfo;
isLoading?: boolean;
scrollRef?: React.RefObject<HTMLDivElement>;
scrollRef?: React.RefObject<HTMLDivElement | null>;
}
const TokenInstanceDetails = ({ data, token, scrollRef, isLoading }: Props) => {
......
......@@ -28,7 +28,7 @@ interface Props {
}
const TokenInstanceMetadataFetcher = ({ hash, id }: Props) => {
const timeoutId = React.useRef<number>();
const timeoutId = React.useRef<number>(undefined);
const { status, setStatus } = useMetadataUpdateContext() || {};
const apiFetch = useApiFetch();
......
......@@ -4143,20 +4143,19 @@
semver "^7.5.4"
superstruct "^1.0.3"
"@monaco-editor/loader@^1.3.2":
version "1.3.2"
resolved "https://registry.yarnpkg.com/@monaco-editor/loader/-/loader-1.3.2.tgz#04effbb87052d19cd7d3c9d81c0635490f9bb6d8"
integrity sha512-BTDbpHl3e47r3AAtpfVFTlAi7WXv4UQ/xZmz8atKl4q7epQV5e7+JbigFDViWF71VBi4IIBdcWP57Hj+OWuc9g==
"@monaco-editor/loader@^1.5.0":
version "1.5.0"
resolved "https://registry.yarnpkg.com/@monaco-editor/loader/-/loader-1.5.0.tgz#dcdbc7fe7e905690fb449bed1c251769f325c55d"
integrity sha512-hKoGSM+7aAc7eRTRjpqAZucPmoNOC4UUbknb/VNoTkEIkCPhqV8LfbsgM1webRM7S/z21eHEx9Fkwx8Z/C/+Xw==
dependencies:
state-local "^1.0.6"
"@monaco-editor/react@^4.4.6":
version "4.4.6"
resolved "https://registry.yarnpkg.com/@monaco-editor/react/-/react-4.4.6.tgz#8ae500b0edf85276d860ed702e7056c316548218"
integrity sha512-Gr3uz3LYf33wlFE3eRnta4RxP5FSNxiIV9ENn2D2/rN8KgGAD8ecvcITRtsbbyuOuNkwbuHYxfeaz2Vr+CtyFA==
"@monaco-editor/react@^4.7.0":
version "4.7.0"
resolved "https://registry.yarnpkg.com/@monaco-editor/react/-/react-4.7.0.tgz#35a1ec01bfe729f38bfc025df7b7bac145602a60"
integrity sha512-cyzXQCtO47ydzxpQtCGSQGOC8Gk3ZUeBXFAxD+CWXYFo5OqZyZUonFl0DwUlTyAfRHntBfw2p3w4s9R6oe1eCA==
dependencies:
"@monaco-editor/loader" "^1.3.2"
prop-types "^15.7.2"
"@monaco-editor/loader" "^1.5.0"
"@motionone/animation@^10.15.1":
version "10.15.1"
......@@ -7676,6 +7675,11 @@
dependencies:
"@types/react" "*"
"@types/react-dom@19.1.6":
version "19.1.6"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-19.1.6.tgz#4af629da0e9f9c0f506fc4d1caa610399c595d64"
integrity sha512-4hOiT/dwO8Ko0gV1m/TJZYk3y0KBnY9vzDh7W+DH17b2HFSOGgdj33dhihPeuy3l0q23+4e+hoXHV6hCC4dCXw==
"@types/react-google-recaptcha@^2.1.5":
version "2.1.5"
resolved "https://registry.yarnpkg.com/@types/react-google-recaptcha/-/react-google-recaptcha-2.1.5.tgz#af157dc2e4bde3355f9b815a64f90e85cfa9df8b"
......@@ -7684,9 +7688,9 @@
"@types/react" "*"
"@types/react-scroll@^1.8.4":
version "1.8.4"
resolved "https://registry.yarnpkg.com/@types/react-scroll/-/react-scroll-1.8.4.tgz#2b6258fb34104d3fcc7a22e8eceaadc669ba3ad1"
integrity sha512-DpHA9PYw42/rBrfKbGE/kAEvHRfyDL/ACfKB/ORWUYuCLi/yGrntxSzYXmg/7TLgQsJ5ma13GCDOzFSOz+8XOA==
version "1.8.10"
resolved "https://registry.yarnpkg.com/@types/react-scroll/-/react-scroll-1.8.10.tgz#585a5c4bd0654434f3e55a08e94ed2e048bae7c7"
integrity sha512-RD4Z7grbdNGOKwKnUBKar6zNxqaW3n8m9QSrfvljW+gmkj1GArb8AFBomVr6xMOgHPD3v1uV3BrIf01py57daQ==
dependencies:
"@types/react" "*"
......@@ -7705,6 +7709,13 @@
"@types/prop-types" "*"
csstype "^3.0.2"
"@types/react@19.1.7":
version "19.1.7"
resolved "https://registry.yarnpkg.com/@types/react/-/react-19.1.7.tgz#9fc4ab6003a8e4f38710c83cb5f8afbdacb7d687"
integrity sha512-BnsPLV43ddr05N71gaGzyZ5hzkCmGwhMvYc8zmvI8Ci1bRkkDSzDDVfAXfN2tk748OwI7ediiPX6PfT9p0QGVg==
dependencies:
csstype "^3.0.2"
"@types/retry@0.12.2":
version "0.12.2"
resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.2.tgz#ed279a64fa438bb69f2480eda44937912bb7480a"
......@@ -10791,13 +10802,13 @@ damerau-levenshtein@^1.0.8:
resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7"
integrity sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==
dappscout-iframe@0.2.6:
version "0.2.6"
resolved "https://registry.yarnpkg.com/dappscout-iframe/-/dappscout-iframe-0.2.6.tgz#2d3411f1f24ee28b0227fdbd78eb6fc7f832c828"
integrity sha512-RmAa8qo8a8YZeffJxIUefU5WG8hwztDFso9W/4fGnGdvQsC+xJ3HYrcTCo08ASdRuaYahEaVkVrebBEsGAkTMQ==
dappscout-iframe@0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/dappscout-iframe/-/dappscout-iframe-0.3.0.tgz#785d46774552dbc2a29f4196b6f39daa53689cd6"
integrity sha512-vHiDO9jXG4Q80ZZbtqiHrDXEYbO1q3nNGYnF5nbUpe7lrYiCHvXK/NUKXC6sHt1zp8tSfD95fmgY/6ZDCrgfpA==
dependencies:
react "18.3.1"
react-dom "18.3.1"
react "19.1.0"
react-dom "19.1.0"
viem "^1.20.3"
data-uri-to-buffer@^4.0.0:
......@@ -15002,7 +15013,7 @@ look-it-up@2.1.0:
resolved "https://registry.yarnpkg.com/look-it-up/-/look-it-up-2.1.0.tgz#278a7ffc9da60a928452a0bab5452bb8855d7d13"
integrity sha512-nMoGWW2HurtuJf6XAL56FWTDCWLOTSsanrgwOyaR5Y4e3zfG5N/0cU5xWZSEU3tBxhQugRbV1xL9jb+ug7yZww==
loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0:
loose-envify@^1.0.0, loose-envify@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
......@@ -16805,13 +16816,12 @@ react-device-detect@^2.2.3:
dependencies:
ua-parser-js "^1.0.33"
react-dom@18.3.1:
version "18.3.1"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4"
integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==
react-dom@19.1.0:
version "19.1.0"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.1.0.tgz#133558deca37fa1d682708df8904b25186793623"
integrity sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==
dependencies:
loose-envify "^1.1.0"
scheduler "^0.23.2"
scheduler "^0.26.0"
react-focus-lock@^2.5.2:
version "2.9.4"
......@@ -16951,9 +16961,9 @@ react-script-hook@^1.7.2:
integrity sha512-fhyCEfXb94fag34UPRF0zry1XGwmVY+79iibWwTqAoOiCzYJQOYTiWJ7CnqglA9tMSV8g45cQpHCMcBwr7dwhA==
react-scroll@^1.8.7:
version "1.8.7"
resolved "https://registry.yarnpkg.com/react-scroll/-/react-scroll-1.8.7.tgz#8020035329efad00f03964e18aff6822137de3aa"
integrity sha512-fBOIwweAlhicx8RqP9tQXn/Uhd+DTtVRjw+0VBsIn1Z+MjRYLhTZ0tMoTAU1vOD3dce8mI6copexI4yWII+Luw==
version "1.9.3"
resolved "https://registry.yarnpkg.com/react-scroll/-/react-scroll-1.9.3.tgz#8312831244a7a8f86036e72c71de155a454a78c0"
integrity sha512-xv7FXqF3k63aSLNu4/NjFvRNI0ge7DmmmsbeGarP7LZVAlJMSjUuW3dTtLxp1Afijyv0lS2qwC0GiFHvx1KBHQ==
dependencies:
lodash.throttle "^4.1.1"
prop-types "^15.7.2"
......@@ -17004,20 +17014,10 @@ react-transition-group@^4.3.0:
loose-envify "^1.4.0"
prop-types "^15.6.2"
react@17.0.2:
version "17.0.2"
resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037"
integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
react@18.3.1:
version "18.3.1"
resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891"
integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==
dependencies:
loose-envify "^1.1.0"
react@19.1.0:
version "19.1.0"
resolved "https://registry.yarnpkg.com/react/-/react-19.1.0.tgz#926864b6c48da7627f004795d6cce50e90793b75"
integrity sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==
readable-stream@3.6.2, readable-stream@^3.4.0, readable-stream@^3.6.2:
version "3.6.2"
......@@ -17493,12 +17493,10 @@ saxes@^6.0.0:
dependencies:
xmlchars "^2.2.0"
scheduler@^0.23.2:
version "0.23.2"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3"
integrity sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==
dependencies:
loose-envify "^1.1.0"
scheduler@^0.26.0:
version "0.26.0"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.26.0.tgz#4ce8a8c2a2095f13ea11bf9a445be50c555d6337"
integrity sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==
scslre@^0.3.0:
version "0.3.0"
......@@ -18999,13 +18997,12 @@ use-callback-ref@^1.3.0:
dependencies:
tslib "^2.0.0"
use-font-face-observer@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/use-font-face-observer/-/use-font-face-observer-1.2.1.tgz#2b33a389b82b48e2744f439abc1d5d6201fc099d"
integrity sha512-5ieKTMvtUux0l7YoOEz842djfgMH3oVg+tO13E/kyS+gGRLDyfAMmRv0D3fzM7UdFag1kz+3AQIFLkkfEF3TUg==
use-font-face-observer@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/use-font-face-observer/-/use-font-face-observer-1.3.0.tgz#12987ed66450fdb1f48749be7ef70a3542951f70"
integrity sha512-gS5UoSPcOoCF+JMbw2By1E3FtXl6ZPxgFo8MW4shpM15lf+MNyzEfjsLJFJ3T/mHLdGTBhQgZYSAXEzubr6v5Q==
dependencies:
fontfaceobserver "2.1.0"
react "17.0.2"
use-isomorphic-layout-effect@^1.1.2:
version "1.1.2"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment