Skip to content

Commit 4c41bf4

Browse files
authored
Merge 9a7c517 into 5fdb5b4
2 parents 5fdb5b4 + 9a7c517 commit 4c41bf4

11 files changed

Lines changed: 64 additions & 33 deletions

File tree

‎packages/block-editor/src/components/global-styles/utils.js‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,18 @@ export function useToolsPanelDropdownMenuProps() {
2626
return ! isMobile ? { popoverProps: dropdown } : {};
2727
}
2828

29+
/**
30+
* @typedef {Pick<
31+
* NonNullable<import('react').ComponentProps<import('@wordpress/components').Dropdown>['popoverProps']>,
32+
* 'placement' | 'offset' | 'shift'
33+
* >} ToolsPanelPopoverProps
34+
*/
35+
36+
/**
37+
* Popover props for a tools panel item.
38+
*
39+
* @return {ToolsPanelPopoverProps} Popover props for a tools panel item.
40+
*/
2941
export function useToolsPanelItemPopoverProps() {
3042
return useContext( ToolsPanelPopoverPropsContext ).item;
3143
}

‎packages/components/CHANGELOG.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
### Internal
4646

4747
- `Menu`: Deprecate the private API while preserving it for older bundled consumers. Target removal for WordPress 7.3 after package compatibility checks pass ([#82947](https://github.com/WordPress/gutenberg/pull/82947)).
48+
- Fix internal `WordPressComponent` polymorphic typings to avoid unsupported `as` props unintentionally surfacing ([#82704](https://github.com/WordPress/gutenberg/pull/82704)).
4849
- `ProgressBar`: Use the WordPress Design System color tokens. ([#83779](https://github.com/WordPress/gutenberg/pull/83779)).
4950

5051
## 41.0.0 (2026-09-23)

‎packages/components/src/color-picker/stories/index.story.tsx‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ const meta: Meta< typeof ColorPicker > = {
88
title: 'Components/@wordpress-components/Selection & Input/Color/ColorPicker',
99
id: 'components-colorpicker',
1010
argTypes: {
11-
as: { control: false },
1211
color: { control: false },
1312
},
1413
args: {

‎packages/components/src/context/test/wordpress-component.tsx‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { describe, it } from 'vitest';
22
import type { ForwardedRef } from 'react';
33
import { forwardRef } from '@wordpress/element';
44
import type { WordPressComponentProps } from '../wordpress-component';
5+
import { contextConnect, contextConnectWithoutRef } from '../context-connect';
56

67
// Static TypeScript checks
78
/* eslint-disable vitest/expect-expect -- TypeScript checks these cases during typecheck. */
@@ -25,4 +26,26 @@ describe( 'WordPressComponentProps', () => {
2526
<ForwardedFoo ref={ null } />;
2627
} );
2728
} );
29+
30+
describe( 'WordPressComponentFromProps', () => {
31+
it( 'should preserve as for polymorphic connected components', () => {
32+
const Unconnected = (
33+
props: WordPressComponentProps< {}, 'div' >,
34+
ref: ForwardedRef< any >
35+
) => <div { ...props } ref={ ref } />;
36+
const Connected = contextConnect( Unconnected, 'Polymorphic' );
37+
38+
<Connected as="label" htmlFor="field" />;
39+
} );
40+
41+
it( 'should reject as on a non-polymorphic connected component', () => {
42+
const Unconnected = (
43+
props: WordPressComponentProps< {}, null, false >
44+
) => <div { ...props } />;
45+
const Foo = contextConnectWithoutRef( Unconnected, 'Foo' );
46+
47+
// @ts-expect-error Non-polymorphic components must not accept `as`.
48+
<Foo as="div" />;
49+
} );
50+
} );
2851
/* eslint-enable vitest/expect-expect */

‎packages/components/src/context/wordpress-component.ts‎

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -82,17 +82,20 @@ export type WordPressComponent<
8282
selector?: `.${ string }`;
8383
};
8484

85+
type RefProps< ForwardsRef extends boolean > = ForwardsRef extends true
86+
? Pick< React.RefAttributes< any >, 'ref' >
87+
: {};
88+
8589
export type WordPressComponentFromProps<
8690
Props,
8791
ForwardsRef extends boolean = true,
88-
> =
89-
Props extends WordPressComponentProps< infer P, infer T, infer I >
90-
? WordPressComponent<
91-
T,
92-
P &
93-
( ForwardsRef extends true
94-
? React.RefAttributes< any >
95-
: {} ),
96-
I
97-
>
98-
: never;
92+
> = 'as' extends keyof Props
93+
? // When `Props` includes `as`, treat the component as polymorphic and
94+
// reverse-infer `P` / `T` from the component props.
95+
Props extends WordPressComponentProps< infer P, infer T, true >
96+
? WordPressComponent< T, P & RefProps< ForwardsRef >, true >
97+
: never
98+
: // Otherwise, keep `Props` intact and force types non-polymorphic, since
99+
// reverse-inferring `T`/`IsPolymorphic` widens them (`ElementType | null`
100+
// and `boolean`), leaving the connected type open to arbitrary props.
101+
WordPressComponent< null, Props & RefProps< ForwardsRef >, false >;

‎packages/components/src/menu/README.md‎

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,6 @@ This component is deprecated. When building for the Gutenberg repo, use `Menu` f
1919

2020
## Props
2121

22-
### `as`
23-
24-
- Type: `any`
25-
- Required: No
26-
27-
The HTML element or React component to render the component as.
28-
2922
### `children`
3023

3124
- Type: `ReactNode`
@@ -66,7 +59,7 @@ A callback that gets called when the `open` state changes.
6659

6760
### `placement`
6861

69-
- Type: `"left" | "right" | "top" | "bottom" | "left-start" | "right-start" | "top-start" | "bottom-start" | "left-end" | "right-end" | ...`
62+
- Type: `"top" | "bottom" | "left" | "right" | "top-start" | "bottom-start" | "left-start" | "right-start" | "top-end" | "bottom-end" | ...`
7063
- Required: No
7164
- Default: `'bottom-start' for root-level menus, 'right-start' for submenus`
7265

‎packages/dataviews/CHANGELOG.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
### Internal
2121

2222
- Remove the `use-memo-one` dependency, which the `./wp` bundle no longer imports ([#83952](https://github.com/WordPress/gutenberg/pull/83952)).
23+
- Keep popover `placement` values as string literals so they remain valid after stricter component prop types ([#82704](https://github.com/WordPress/gutenberg/pull/82704)).
2324

2425
### Documentation
2526

‎packages/dataviews/src/components/dataform-layouts/panel/dropdown.tsx‎

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -80,14 +80,15 @@ function PanelDropdown< Item >( {
8080
);
8181
// Memoize popoverProps to avoid returning a new object every time.
8282
const popoverProps = useMemo(
83-
() => ( {
84-
// Anchor the popover to the middle of the entire row so that it doesn't
85-
// move around when the label changes.
86-
anchor: popoverAnchor,
87-
placement: 'left-start',
88-
offset: 36,
89-
shift: true,
90-
} ),
83+
() =>
84+
( {
85+
// Anchor the popover to the middle of the entire row so that it doesn't
86+
// move around when the label changes.
87+
anchor: popoverAnchor,
88+
placement: 'left-start',
89+
offset: 36,
90+
shift: true,
91+
} ) as const,
9192
[ popoverAnchor ]
9293
);
9394
const [ dialogRef, dialogProps ] = useDialog( {

‎packages/dataviews/src/components/dataviews-view-config/index.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ const DATAVIEWS_CONFIG_POPOVER_PROPS = {
2525
className: 'dataviews-config__popover',
2626
placement: 'bottom-end',
2727
offset: 9,
28-
};
28+
} as const;
2929

3030
export function ViewTypeMenu() {
3131
const { view, onChangeView, defaultLayouts } =

‎routes/navigation-edit/editor/leaf-more-menu.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { hasBlockSupport, store as blocksStore } from '@wordpress/blocks';
99
const POPOVER_PROPS = {
1010
className: 'block-editor-block-settings-menu__popover',
1111
placement: 'bottom-start',
12-
};
12+
} as const;
1313

1414
export default function LeafMoreMenu( {
1515
clientId,

0 commit comments

Comments
 (0)