From 9780d41373e1a197ddaa7490953f1a3181d3d8fb Mon Sep 17 00:00:00 2001 From: Evgenii Alaev Date: Thu, 4 Jun 2026 19:41:43 +0200 Subject: [PATCH] feat: support React 19 - Extend `react` peer dependency range with `^19.0.0` - Bump `@types/react`/`@types/react-dom` to `^19` and React dev deps to `^19` - Replace `useRef()` with `useRef(undefined)` / `useRef(null)` (zero-arg overload removed in @types/react@19) - Tighten `HighchartsReactRefObject.container` to `RefObject` --- package-lock.json | 61 ++++++++----------- package.json | 10 +-- src/components/ChartKit.tsx | 2 +- src/hooks/misc.ts | 2 +- .../__stories__/components/ChartStory.tsx | 2 +- .../scatter/PerformanceIssue.stories.tsx | 2 +- .../renderer/components/HighchartsReact.tsx | 4 +- .../__stories__/Indicator.stories.tsx | 2 +- .../yagr/__stories__/Playground.stories.tsx | 2 +- src/plugins/yagr/__stories__/Yagr.stories.tsx | 8 +-- 10 files changed, 41 insertions(+), 54 deletions(-) diff --git a/package-lock.json b/package-lock.json index a883b3da..836d2402 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32,8 +32,8 @@ "@types/d3-selection": "^3.0.10", "@types/lodash": "^4.14.177", "@types/node": "^18.0.0", - "@types/react": "^18.3.28", - "@types/react-dom": "^18.3.7", + "@types/react": "^19.2.16", + "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^5.1.4", "@vitest/browser-playwright": "^4.0.18", "@vitest/coverage-v8": "^4.0.18", @@ -55,8 +55,8 @@ "npm-run-all": "^4.1.5", "playwright": "^1.58.2", "prettier": "^3.2.5", - "react": "^18.3.1", - "react-dom": "^18.3.1", + "react": "^19.2.7", + "react-dom": "^19.2.7", "rimraf": "^5.0.5", "sass": "^1.56.2", "storybook": "^10.2.0", @@ -69,7 +69,7 @@ }, "peerDependencies": { "@gravity-ui/uikit": "^7.0.0", - "react": "^16.0.0 || ^17.0.0 || ^18.0.0" + "react": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -3364,30 +3364,24 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/prop-types": { - "version": "15.7.5", - "dev": true, - "license": "MIT" - }, "node_modules/@types/react": { - "version": "18.3.28", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.28.tgz", - "integrity": "sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==", + "version": "19.2.16", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.16.tgz", + "integrity": "sha512-esJiCAnl0kfpNdE69f3So4WJUXy95dLZydX0KwK46riIHDzHM7O9Vtf9xCHW0PXIqvgqNrswl522kA/5yx+F4w==", "dev": true, "license": "MIT", "dependencies": { - "@types/prop-types": "*", "csstype": "^3.2.2" } }, "node_modules/@types/react-dom": { - "version": "18.3.7", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", - "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "dev": true, "license": "MIT", "peerDependencies": { - "@types/react": "^18.0.0" + "@types/react": "^19.2.0" } }, "node_modules/@types/react-redux": { @@ -13218,14 +13212,11 @@ } }, "node_modules/react": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.7.tgz", + "integrity": "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==", "dev": true, "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - }, "engines": { "node": ">=0.10.0" } @@ -13288,17 +13279,16 @@ } }, "node_modules/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz", + "integrity": "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==", "dev": true, "license": "MIT", "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" + "scheduler": "^0.27.0" }, "peerDependencies": { - "react": "^18.3.1" + "react": "^19.2.7" } }, "node_modules/react-is": { @@ -14016,14 +14006,11 @@ } }, "node_modules/scheduler": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", - "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", "dev": true, - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - } + "license": "MIT" }, "node_modules/semver": { "version": "6.3.1", diff --git a/package.json b/package.json index c60da8bb..03daf106 100644 --- a/package.json +++ b/package.json @@ -69,8 +69,8 @@ "@types/d3-selection": "^3.0.10", "@types/lodash": "^4.14.177", "@types/node": "^18.0.0", - "@types/react": "^18.3.28", - "@types/react-dom": "^18.3.7", + "@types/react": "^19.2.16", + "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^5.1.4", "@vitest/browser-playwright": "^4.0.18", "@vitest/coverage-v8": "^4.0.18", @@ -92,8 +92,8 @@ "npm-run-all": "^4.1.5", "playwright": "^1.58.2", "prettier": "^3.2.5", - "react": "^18.3.1", - "react-dom": "^18.3.1", + "react": "^19.2.7", + "react-dom": "^19.2.7", "rimraf": "^5.0.5", "sass": "^1.56.2", "storybook": "^10.2.0", @@ -106,7 +106,7 @@ }, "peerDependencies": { "@gravity-ui/uikit": "^7.0.0", - "react": "^16.0.0 || ^17.0.0 || ^18.0.0" + "react": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "scripts": { "test": "vitest run --project unit", diff --git a/src/components/ChartKit.tsx b/src/components/ChartKit.tsx index 593039d2..22e28158 100644 --- a/src/components/ChartKit.tsx +++ b/src/components/ChartKit.tsx @@ -18,7 +18,7 @@ type ChartKitComponentProps = Omit, 'on }; const ChartKitComponent = (props: ChartKitComponentProps) => { - const widgetRef = React.useRef(); + const widgetRef = React.useRef(undefined); const {instanceRef, id: propsId, type, isMobile, renderPluginLoader, ...restProps} = props; const ckId = React.useMemo(() => getRandomCKId(), []); diff --git a/src/hooks/misc.ts b/src/hooks/misc.ts index fcec1119..7034f4c5 100644 --- a/src/hooks/misc.ts +++ b/src/hooks/misc.ts @@ -1,7 +1,7 @@ import React from 'react'; export function usePrevious(value: T) { - const ref = React.useRef(); + const ref = React.useRef(undefined); React.useEffect(() => { ref.current = value; diff --git a/src/plugins/highcharts/__stories__/components/ChartStory.tsx b/src/plugins/highcharts/__stories__/components/ChartStory.tsx index ed1d1129..0e3cc7ab 100644 --- a/src/plugins/highcharts/__stories__/components/ChartStory.tsx +++ b/src/plugins/highcharts/__stories__/components/ChartStory.tsx @@ -26,7 +26,7 @@ export const ChartStory: React.FC = (props: ChartStoryProps) => const initRef = React.useRef(false); const [visible, setVisible] = React.useState(Boolean(props.visible)); - const chartKitRef = React.useRef(); + const chartKitRef = React.useRef(undefined); if (!initRef.current) { if (!props.withoutPlugin) { diff --git a/src/plugins/highcharts/__stories__/scatter/PerformanceIssue.stories.tsx b/src/plugins/highcharts/__stories__/scatter/PerformanceIssue.stories.tsx index 28a2af74..9a557824 100644 --- a/src/plugins/highcharts/__stories__/scatter/PerformanceIssue.stories.tsx +++ b/src/plugins/highcharts/__stories__/scatter/PerformanceIssue.stories.tsx @@ -21,7 +21,7 @@ type Story = StoryObj; export const PerformanceIssue: Story = { render: () => { const [shown, setShown] = React.useState(false); - const chartkitRef = React.useRef(); + const chartkitRef = React.useRef(undefined); const widgetData = React.useMemo(() => { const categories = Array.from({length: 5000}).map((_, i) => String(i)); diff --git a/src/plugins/highcharts/renderer/components/HighchartsReact.tsx b/src/plugins/highcharts/renderer/components/HighchartsReact.tsx index ec8a2236..1a384b5e 100644 --- a/src/plugins/highcharts/renderer/components/HighchartsReact.tsx +++ b/src/plugins/highcharts/renderer/components/HighchartsReact.tsx @@ -12,7 +12,7 @@ import {useElementSize} from './useElementSize'; interface HighchartsReactRefObject { chart: Highcharts.Chart | null | undefined; - container: React.RefObject; + container: React.RefObject; } interface HighchartsReactProps { @@ -33,7 +33,7 @@ export const HighchartsReact = React.memo( function HighchartsReact(props, ref) { const {onRender} = props; const containerRef = React.useRef(null); - const chartRef = React.useRef(); + const chartRef = React.useRef(null); const {width, height} = useElementSize(containerRef); const performanceMeasure = React.useRef | null>( measurePerformance(), diff --git a/src/plugins/indicator/__stories__/Indicator.stories.tsx b/src/plugins/indicator/__stories__/Indicator.stories.tsx index ffc351ab..27002456 100644 --- a/src/plugins/indicator/__stories__/Indicator.stories.tsx +++ b/src/plugins/indicator/__stories__/Indicator.stories.tsx @@ -32,7 +32,7 @@ interface ChartStoryProps { const ChartStory = ({color, size, title, nowrap}: ChartStoryProps) => { const [shown, setShown] = React.useState(false); - const chartkitRef = React.useRef(); + const chartkitRef = React.useRef(undefined); const resultData = cloneDeep(data); if (resultData.data) { diff --git a/src/plugins/yagr/__stories__/Playground.stories.tsx b/src/plugins/yagr/__stories__/Playground.stories.tsx index b9246b48..f42fb448 100644 --- a/src/plugins/yagr/__stories__/Playground.stories.tsx +++ b/src/plugins/yagr/__stories__/Playground.stories.tsx @@ -61,7 +61,7 @@ function prepareData(): YagrWidgetData { const ChartStory = ({data}: {data: YagrWidgetData}) => { const [shown, setShown] = React.useState(false); - const chartkitRef = React.useRef(); + const chartkitRef = React.useRef(undefined); if (!shown) { settings.set({plugins: [YagrPlugin]}); diff --git a/src/plugins/yagr/__stories__/Yagr.stories.tsx b/src/plugins/yagr/__stories__/Yagr.stories.tsx index 02703ff2..9269f307 100644 --- a/src/plugins/yagr/__stories__/Yagr.stories.tsx +++ b/src/plugins/yagr/__stories__/Yagr.stories.tsx @@ -72,7 +72,7 @@ function Tooltip({yagr}: CustomTooltipProps) { export const Line: Story = { render: () => { const [shown, setShown] = React.useState(false); - const chartkitRef = React.useRef(); + const chartkitRef = React.useRef(undefined); if (!shown) { settings.set({plugins: [YagrPlugin]}); @@ -90,7 +90,7 @@ export const Line: Story = { export const Updates: Story = { render: () => { const [shown, setShown] = React.useState(false); - const chartkitRef = React.useRef(); + const chartkitRef = React.useRef(undefined); const [state, setState] = React.useState(line10); @@ -118,7 +118,7 @@ export const Updates: Story = { export const CustomTooltip: Story = { render: () => { const [shown, setShown] = React.useState(false); - const chartkitRef = React.useRef(); + const chartkitRef = React.useRef(undefined); const [state, setState] = React.useState(line10); @@ -145,7 +145,7 @@ export const CustomTooltip: Story = { export const Area: Story = { render: () => { const [shown, setShown] = React.useState(false); - const chartkitRef = React.useRef(); + const chartkitRef = React.useRef(undefined); if (!shown) { settings.set({plugins: [YagrPlugin]});