-
Notifications
You must be signed in to change notification settings - Fork 5.3k
chore: upgrade React to 19 and React Router to 8 #9530
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: preview
Are you sure you want to change the base?
Changes from all commits
d6d7b9f
b1947f5
5c1cba7
f6124ad
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,2 @@ | ||
| [tools] | ||
| node = "22.18.0" | ||
| node = "22.22.0" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| 22.22.0 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,7 +8,7 @@ import React, { useState, useRef, useCallback, useMemo } from "react"; | |
| import { observer } from "mobx-react"; | ||
| import { useParams } from "next/navigation"; | ||
| import { useDropzone } from "react-dropzone"; | ||
| import type { Control } from "react-hook-form"; | ||
| import type { Control, FieldPath, FieldValues } from "react-hook-form"; | ||
| import { Controller } from "react-hook-form"; | ||
| import useSWR from "swr"; | ||
| import { Popover } from "@headlessui/react"; | ||
|
|
@@ -34,10 +34,13 @@ type TTabOption = { | |
| isEnabled: boolean; | ||
| }; | ||
|
|
||
| type Props = { | ||
| // Generic over the form's values because react-hook-form's Control is invariant: its | ||
| // `_options.validate` narrows `name` to a keyof union, so `Control<any>` no longer | ||
| // accepts a typed form's control. Inferring from `control` keeps call sites unchanged. | ||
| type Props<TFieldValues extends FieldValues = FieldValues> = { | ||
| label: string | React.ReactNode; | ||
| value: string | null; | ||
| control: Control<any>; | ||
| control: Control<TFieldValues>; | ||
| onChange: (data: string) => void; | ||
| disabled?: boolean; | ||
| tabIndex?: number; | ||
|
|
@@ -48,7 +51,7 @@ type Props = { | |
| // services | ||
| const fileService = new FileService(); | ||
|
|
||
| export const ImagePickerPopover = observer(function ImagePickerPopover(props: Props) { | ||
| function ImagePickerPopoverComponent<TFieldValues extends FieldValues = FieldValues>(props: Props<TFieldValues>) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. React Doctor · Component "ImagePickerPopoverComponent" is over 300 lines long, which is hard to read & change. Split it into a few smaller components. Fix → Pull each section into its own component so the parent is easier to read, test, and change. |
||
| const { label, value, control, onChange, disabled = false, tabIndex, isProfileCover = false, projectId } = props; | ||
| // states | ||
| const [image, setImage] = useState<File | null>(null); | ||
|
|
@@ -218,7 +221,7 @@ export const ImagePickerPopover = observer(function ImagePickerPopover(props: Pr | |
| <div className="flex items-center gap-x-2"> | ||
| <Controller | ||
| control={control} | ||
| name="search" | ||
| name={"search" as FieldPath<TFieldValues>} | ||
| render={({ field: { value, ref } }) => ( | ||
| <Input | ||
| id="search" | ||
|
|
@@ -372,4 +375,7 @@ export const ImagePickerPopover = observer(function ImagePickerPopover(props: Pr | |
| )} | ||
| </Popover> | ||
| ); | ||
| }); | ||
| } | ||
|
|
||
| // observer() erases the generic signature, so restore it with a cast. | ||
| export const ImagePickerPopover = observer(ImagePickerPopoverComponent) as typeof ImagePickerPopoverComponent; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: makeplane/plane
Length of output: 19539
🏁 Script executed:
Repository: makeplane/plane
Length of output: 2089
🌐 Web query:
react-hook-form React Hook Fields FieldPath FieldValues Controller name generic💡 Result:
In React Hook Form, the Controller component (and the useController hook) utilizes TypeScript generics to ensure type safety for form fields, particularly when connecting custom components to the form state [1][2][3]. Key Generics and Types: 1. TFieldValues: This generic represents the shape of your entire form data object. It must extend FieldValues (which is essentially a Record<string, any>) [2][4]. When you provide this type, it enables the library to infer the available paths for the name prop [3][5]. 2. TName: This generic represents the path to a specific field within TFieldValues [2][4]. It is constrained by the FieldPath type, which uses TypeScript's template literal types to validate that the name string provided to the Controller actually exists within your form data structure [4][5]. 3. ControllerProps and useController: Both accept these generics to maintain consistency [2][6]. When you use <Controller<FormValues, "fieldName"> />, TypeScript will restrict the name prop to valid keys within FormValues and ensure the value returned in the render prop matches the type defined at that path (via FieldPathValue<TFieldValues, TName>) [2][4]. Example Usage: type FormValues = { firstName: string; age: number; }; // Using Controller with generics <Controller<FormValues, "firstName"> name="firstName" control={control} render={({ field }) => <input {...field} />} /> In this example, the "name" prop is strictly typed to "firstName" or "age", and the "field.value" property is correctly inferred as a string [2][4]. If you omit the explicit generic arguments, React Hook Form often infers them automatically from the control object provided [1][7][3]. Top Results: [1], [2], [3]
Citations:
🌐 Web query:
FieldPath<TFieldValues> react-hook-form 7 FieldPath generic definition💡 Result:
In React Hook Form 7, FieldPath is a TypeScript generic type that represents a union of all valid dot-notation string paths for a given form data structure [1][2]. The type is defined as an alias for the Path utility type [1][3]: export type FieldPath = Path; Key characteristics of FieldPath: 1. Type Safety: It enables compile-time validation of field names, ensuring that string identifiers provided to functions like register, control, or watch correspond to existing properties within your form's data object [1][2]. 2. Deep Nesting: It recursively traverses the TFieldValues structure to generate all possible paths, including support for nested objects and array indices (e.g., 'user.name' or 'items.0.id') [2]. 3. Integration: It is used throughout the React Hook Form API to provide auto-completion and type checking for the name prop of form inputs and other field-related identifiers [1]. Associated utility types often used with FieldPath include: - FieldPathValue<TFieldValues, TFieldPath>: Determines the specific TypeScript type of the value located at a given path [4][3][2]. - FieldPathValues<TFieldValues, TPath>: Maps an array of paths to a tuple of their corresponding value types [4][3][2]. - FieldPathByValue<TFieldValues, TValue>: Filters paths to include only those whose values match a specific type [4][5][2].
Citations:
Preserve the
nametype constraint.name: stringaccepts paths outsideTFieldValues. DeclarenameasFieldPath<TFieldValues>and pass it directly toControllerto avoid the cast.Proposed fix
📝 Committable suggestion
🤖 Prompt for AI Agents
Source: Coding guidelines