From 805cd2cd3c1e983af804a07067b7de18f85a9e48 Mon Sep 17 00:00:00 2001 From: Brad Jorsch Date: Wed, 7 Oct 2026 15:29:08 -0400 Subject: [PATCH 1/2] Miscellaneous React 19 cleanups A bunch of one-off fixes: * ai-client: onInput is an `InputEvent`, not a `ChangeEvent`. * charts: `FC<>` now wants to allow for returning async, which the places we use `renderLabel` and `renderLabelPopover` can't actually handle. So declare their types without the `FC<>` helper. * charts: React 19 recognizes `popoverTarget` and `popoverTargetAction`, and rejects `popovertarget` and `popovertargetaction`, while React 18 needs the latter as it doesn't recognize the former. So supply whichever is appropriate at runtime based on the React version. * components: React 19 wants `transformOrigin`, while 18 needs `transform-origin`. It turns out there are no transforms anymore needing an origin in the first place, so just remove it. * backup: The `useRestore` test was advancing jest's fake timer by a large amount. React 19 doesn't like this: it doesn't get a gap between updates and winds up throwing a "Maximum update depth exceeded" error. Advance in steps of `POLL_INTERVAL_MS` instead, which gives React 19 the gaps it needs. * publicize: The `ManageConnectionsModal` test breaks in React 19. Using `await jest.runAllTimersAsync()` instead of `jest.runAllTimers()` in the already-async `act()` call fixes this. * videopress: Fix another argless `useRef` added since #53002 fixed all the rest. Sigh. * jetpack: An `AI admin page` test was looking for the "Writing Assistant" checkbox synchronously, even though it gets added asynchronously and all the other tests look for it async. Somehow this worked ok in React 18, but breaks in 19; looking async like everything else does fixes it. --- .../changelog/fix-misc-react-19-stuff | 5 ++++ .../src/logo-generator/components/prompt.tsx | 6 ++-- .../charts/changelog/fix-misc-react-19-stuff | 5 ++++ .../changelog/fix-misc-react-19-stuff#2 | 5 ++++ .../line-chart-annotation-label-popover.tsx | 28 +++++++++++++------ .../charts/line-chart/stories/index.api.mdx | 4 +-- .../charts/src/charts/line-chart/types.ts | 6 ++-- .../changelog/fix-misc-react-19-stuff | 5 ++++ .../components/donut-meter/index.tsx | 1 - .../backup/changelog/fix-misc-react-19-stuff | 5 ++++ .../dashboard/hooks/test/use-restore.test.ts | 10 +++++-- .../tests/index.test.jsx | 4 +-- .../changelog/fix-misc-react-19-stuff | 5 ++++ .../changelog/fix-misc-react-19-stuff | 5 ++++ .../videopress/routes/video/stage.tsx | 2 +- .../jetpack/_inc/client/ai/test/main.jsx | 4 ++- .../jetpack/changelog/fix-misc-react-19-stuff | 5 ++++ 17 files changed, 80 insertions(+), 25 deletions(-) create mode 100644 projects/js-packages/ai-client/changelog/fix-misc-react-19-stuff create mode 100644 projects/js-packages/charts/changelog/fix-misc-react-19-stuff create mode 100644 projects/js-packages/charts/changelog/fix-misc-react-19-stuff#2 create mode 100644 projects/js-packages/components/changelog/fix-misc-react-19-stuff create mode 100644 projects/packages/backup/changelog/fix-misc-react-19-stuff create mode 100644 projects/packages/publicize/changelog/fix-misc-react-19-stuff create mode 100644 projects/packages/videopress/changelog/fix-misc-react-19-stuff create mode 100644 projects/plugins/jetpack/changelog/fix-misc-react-19-stuff diff --git a/projects/js-packages/ai-client/changelog/fix-misc-react-19-stuff b/projects/js-packages/ai-client/changelog/fix-misc-react-19-stuff new file mode 100644 index 000000000000..295742aecbf1 --- /dev/null +++ b/projects/js-packages/ai-client/changelog/fix-misc-react-19-stuff @@ -0,0 +1,5 @@ +Significance: patch +Type: fixed +Comment: Fix typing for React 19: onInput is an `InputEvent`, not a `ChangeEvent`. + + diff --git a/projects/js-packages/ai-client/src/logo-generator/components/prompt.tsx b/projects/js-packages/ai-client/src/logo-generator/components/prompt.tsx index 7774c23b2f30..1541d3ae9fbc 100644 --- a/projects/js-packages/ai-client/src/logo-generator/components/prompt.tsx +++ b/projects/js-packages/ai-client/src/logo-generator/components/prompt.tsx @@ -30,7 +30,7 @@ import './prompt.scss'; * Types */ import type { ImageStyle, ImageStyleObject } from '../../hooks/use-image-generator/constants.ts'; -import type { ChangeEvent, ClipboardEvent, KeyboardEvent } from 'react'; +import type { ClipboardEvent, InputEvent, KeyboardEvent } from 'react'; const debug = debugFactory( 'jetpack-ai-calypso:prompt-box' ); @@ -57,8 +57,8 @@ export const AiModalPromptInput = ( { } ) => { const inputRef = useRef< HTMLDivElement | null >( null ); - const onPromptInput = ( event: ChangeEvent< HTMLInputElement > ) => { - setPrompt( event.target.textContent || '' ); + const onPromptInput = ( event: InputEvent< HTMLInputElement > ) => { + setPrompt( ( event.target as HTMLInputElement ).textContent || '' ); }; const onPromptPaste = ( event: ClipboardEvent< HTMLInputElement > ) => { diff --git a/projects/js-packages/charts/changelog/fix-misc-react-19-stuff b/projects/js-packages/charts/changelog/fix-misc-react-19-stuff new file mode 100644 index 000000000000..975a4a94cf95 --- /dev/null +++ b/projects/js-packages/charts/changelog/fix-misc-react-19-stuff @@ -0,0 +1,5 @@ +Significance: patch +Type: changed +Comment: Fix typing for React 19: `FC<>` now wants to allow for returning async, which the places we use `renderLabel` and `renderLabelPopover` can't actually handle. So declare their types without the `FC<>` helper. + + diff --git a/projects/js-packages/charts/changelog/fix-misc-react-19-stuff#2 b/projects/js-packages/charts/changelog/fix-misc-react-19-stuff#2 new file mode 100644 index 000000000000..d257ee09cc23 --- /dev/null +++ b/projects/js-packages/charts/changelog/fix-misc-react-19-stuff#2 @@ -0,0 +1,5 @@ +Significance: patch +Type: changed +Comment: React 19 recognizes `popoverTarget` and `popoverTargetAction`, and rejects `popovertarget` and `popovertargetaction`, while React 18 needs the latter as it doesn't recognize the former. So supply whichever is appropriate at runtime based on the React version. + + diff --git a/projects/js-packages/charts/src/charts/line-chart/private/line-chart-annotation-label-popover.tsx b/projects/js-packages/charts/src/charts/line-chart/private/line-chart-annotation-label-popover.tsx index c3bf2692f4bb..1a5a81e1b579 100644 --- a/projects/js-packages/charts/src/charts/line-chart/private/line-chart-annotation-label-popover.tsx +++ b/projects/js-packages/charts/src/charts/line-chart/private/line-chart-annotation-label-popover.tsx @@ -1,14 +1,17 @@ import { __ } from '@wordpress/i18n'; import { Stack } from '@wordpress/ui'; import clsx from 'clsx'; -import { useEffect, useId, useRef, useState } from 'react'; +import { useEffect, useId, useRef, useState, version as reactVersion } from 'react'; import { isSafari } from '../../../utils'; import styles from '../line-chart.module.scss'; import type { ButtonWithPopover, PopoverElement, ToggleEvent } from '../../../types'; -import type { FC } from 'react'; +import type { FC, ReactNode } from 'react'; export const POPOVER_BUTTON_SIZE = 44; +// @todo Remove this (and uses of it below) when we drop support for WordPress versions shipping React 18. +const isReact18 = reactVersion.startsWith( '18.' ); + const CloseIcon = () => ( ( interface LineChartAnnotationLabelWithPopoverProps { title: string; subtitle?: string; - renderLabel: FC< { title: string; subtitle?: string } >; - renderLabelPopover: FC< { title: string; subtitle?: string } >; + renderLabel: ( props: { title: string; subtitle?: string } ) => ReactNode; + renderLabelPopover: ( props: { title: string; subtitle?: string } ) => ReactNode; } const LineChartAnnotationLabelWithPopover: FC< LineChartAnnotationLabelWithPopoverProps > = ( { @@ -83,7 +86,9 @@ const LineChartAnnotationLabelWithPopover: FC< LineChartAnnotationLabelWithPopov