You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(react): restore intrinsic HTML props under React 19 types (#121)
* fix(react): restore intrinsic HTML props under React 19 types
`React.PropsWithRef<JSX.IntrinsicElements['x']>` relied on the global
`JSX` namespace, which @types/react@19 no longer augments. Under React
19 the type collapsed to `any`, silently dropping `onClick`, `type`,
`disabled`, `aria-*`, `children`, etc. from every affected component.
Replaced with `React.ComponentProps<'x'>` /
`React.ComponentPropsWithoutRef<'x'>` across ~60 type files. Works on
React 18 and 19.
Fixes#120.
* refactor(react): normalize forwardRef props to ComponentPropsWithoutRef
The codebase mixed `ComponentProps` (with ref) and `ComponentPropsWithoutRef`
across prop interfaces, all consumed by `React.forwardRef`. Normalize to
`ComponentPropsWithoutRef` throughout — the idiomatic pattern React docs
recommend for forwardRef, since forwardRef re-adds ref via `RefAttributes<T>`
to the external component type.
Side benefit: for the handful of non-forwardRef components (Link, Form,
FormItem, Descriptions), this removes `ref` from the prop type so consumers
can no longer pass a non-functional `ref` prop.
Zero external API change for forwardRef components — `<Button ref={...}/>`
still type-checks via `RefAttributes<HTMLButtonElement>`.
* fix(react): normalize ref exposure policy
Fix TypeScript compatibility with React 19. Component prop interfaces used the pattern `React.PropsWithRef<JSX.IntrinsicElements['x']>`, which relied on a globally-augmented `JSX` namespace that `@types/react@19` no longer provides. The resolved prop types collapsed to `any`, silently dropping every intrinsic HTML attribute (`onClick`, `type`, `disabled`, `aria-*`, `children`, etc.) for consumers on React 19. Replaced the pattern with `React.ComponentProps<'x'>` / `React.ComponentPropsWithoutRef<'x'>` across ~60 component type files. Works on React 18 and 19.
This package treats `ref` as an explicit component capability, not an accidental side effect of inheriting DOM props.
4
+
5
+
## Rules
6
+
7
+
- Use `React.ComponentPropsWithoutRef<'tag'>` for DOM-derived prop interfaces by default.
8
+
- Only expose `ref` when the component intentionally supports DOM access through `React.forwardRef`.
9
+
- Do not rely on `React.ComponentProps<'tag'>` to leak `ref` into props interfaces.
10
+
- If a component is primarily compositional or layout-only, do not expose `ref` unless there is a concrete DOM integration need.
11
+
12
+
## Components That Should Expose `ref`
13
+
14
+
- Interactive controls and focus targets such as `Button`, `Input`, `NativeSelect`, `Link`, `Switch`, `Checkbox`, `Radio`.
15
+
- Components frequently used for measurement, scrolling, positioning, or animation integration such as `Tree`, `Slider`, `Grid`, `Space`, `Flex`, `Layout`, `Anchor`, `Waterfall`, `Transfer`, `Steps`, and typography primitives.
16
+
17
+
## Components That Usually Should Not Expose `ref`
18
+
19
+
- Grouping or compositional wrappers such as `Button.Group`, `Checkbox.Group`, `Radio.Group`, `Input.Group`, `Input.Addon`, `Form.Item`, `Descriptions`, `Descriptions.Item`.
20
+
21
+
## Practical Guidance
22
+
23
+
- If consumers need the outer wrapper and an inner native control, expose both intentionally, for example `Checkbox` plus `checkboxRef`, or `Radio` plus `radioRef`.
24
+
- If a component renders different DOM elements by state, make the forwarded ref type reflect that reality instead of pretending it always points to one tag.
25
+
- When adding a new forwarded ref, add a focused test that proves the ref resolves to the expected DOM node.
0 commit comments