Skip to content

Commit 9883d53

Browse files
authored
feat: added ploymorphicProps to UIShell Link (#18540)
* feat: added ploymorphicProps to Link in UIShell * fix: fixex typescript error * fix: fixed typescript error * fix: fixed typescript error in switcheritem * fix: clean up comments
1 parent 8b69ead commit 9883d53

File tree

4 files changed

+41
-32
lines changed

4 files changed

+41
-32
lines changed

packages/react/src/components/UIShell/HeaderMenuItem.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,23 @@ import React, {
1515
WeakValidationMap,
1616
} from 'react';
1717
import cx from 'classnames';
18-
import Link, { LinkProps, LinkPropTypes } from './Link';
18+
import Link, { LinkPropTypes } from './Link';
1919
import { usePrefix } from '../../internal/usePrefix';
2020
import deprecate from '../../prop-types/deprecate';
21+
import { PolymorphicComponentPropWithRef } from '../../internal/PolymorphicProps';
2122

22-
export type HeaderMenuItemProps<E extends ElementType> = LinkProps<E> & {
23+
export interface HeaderMenuItemBaseProps {
2324
className?: string | undefined;
2425
isActive?: boolean | undefined;
2526
isCurrentPage?: boolean | undefined;
2627
'aria-current'?: string | undefined;
2728
children: ReactNode;
2829
role?: ComponentProps<'li'>['role'];
2930
tabIndex?: number | undefined;
30-
};
31+
}
32+
33+
export type HeaderMenuItemProps<E extends ElementType = 'a'> =
34+
PolymorphicComponentPropWithRef<E, HeaderMenuItemBaseProps>;
3135

3236
export interface HeaderMenuItemComponent {
3337
<E extends ElementType = 'a'>(

packages/react/src/components/UIShell/Link.tsx

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,32 +7,42 @@
77

88
import PropTypes from 'prop-types';
99
import React, {
10+
ForwardedRef,
1011
type ElementType,
11-
type ForwardedRef,
12-
forwardRef,
1312
type WeakValidationMap,
14-
type Ref,
1513
} from 'react';
1614
import deprecate from '../../prop-types/deprecate';
17-
import { type PolymorphicProps } from '../../types/common';
15+
import { PolymorphicRef } from '../../internal/PolymorphicProps';
16+
import { PolymorphicProps } from '../../types/common';
17+
import { HeaderMenuItemBaseProps } from './HeaderMenuItem';
1818

1919
// Note: Maybe we should use `as` instead of `element`? `as` appears to be
2020
// standard and is used in other places in this project.
2121

22-
type LinkBaseProps<E extends ElementType> = {
22+
export interface LinkBaseProps {
2323
/**
2424
* @deprecated Use `as` instead
2525
*/
26-
element?: E | undefined;
27-
ref?: Ref<E>;
28-
};
26+
element?: undefined;
27+
ref?: ForwardedRef<ElementType>;
28+
}
2929

30-
export type LinkProps<E extends ElementType> = PolymorphicProps<
30+
export type LinkProps<E extends React.ElementType> = PolymorphicProps<
3131
E,
32-
LinkBaseProps<E>
32+
LinkBaseProps
3333
>;
3434

35-
function LinkRenderFunction<E extends ElementType = 'a'>(
35+
export interface LinkComponent {
36+
<E extends ElementType = 'a'>(
37+
props: LinkProps<E> | HeaderMenuItemBaseProps
38+
): JSX.Element | null;
39+
displayName?: string;
40+
propTypes?: WeakValidationMap<LinkProps<any>>;
41+
}
42+
43+
export const Link: LinkComponent = React.forwardRef(function LinkRenderFunction<
44+
E extends ElementType = 'a',
45+
>(
3646
{
3747
element,
3848
as: BaseComponent,
@@ -41,24 +51,17 @@ function LinkRenderFunction<E extends ElementType = 'a'>(
4151
isSideNavExpanded: _isSideNavExpanded,
4252
...rest
4353
}: LinkProps<E>,
44-
ref: ForwardedRef<E>
54+
ref: PolymorphicRef<E>
4555
) {
4656
const BaseComponentAsAny = (BaseComponent ?? element ?? 'a') as any;
4757
return <BaseComponentAsAny ref={ref} {...rest} />;
48-
}
49-
58+
}) as LinkComponent;
5059
/**
5160
* Link is a custom component that allows us to supporting rendering elements
5261
* other than `a` in our markup. The goal is to allow users to support passing
5362
* in their own components to support use-cases like `react-router` or
5463
* `@reach/router`
5564
*/
56-
const Link = forwardRef(LinkRenderFunction) as (<E extends ElementType = 'a'>(
57-
props: LinkProps<E>
58-
) => JSX.Element) & {
59-
displayName?: string;
60-
propTypes?: WeakValidationMap<LinkProps<any>>;
61-
};
6265

6366
const LinkPropTypes = {
6467
/**

packages/react/src/components/UIShell/SideNavMenuItem.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import SideNavLinkText from './SideNavLinkText';
1212
import Link from './Link';
1313
import { usePrefix } from '../../internal/usePrefix';
1414

15-
export interface SideNavMenuItemProps extends ComponentProps<typeof Link> {
15+
export type SideNavMenuItemProps = ComponentProps<typeof Link> & {
1616
/**
1717
* Specify the children to be rendered inside of the `SideNavMenuItem`
1818
*/
@@ -39,7 +39,7 @@ export interface SideNavMenuItemProps extends ComponentProps<typeof Link> {
3939
* Optional component to render instead of default Link
4040
*/
4141
as?: ElementType;
42-
}
42+
};
4343

4444
const SideNavMenuItem = React.forwardRef<HTMLElement, SideNavMenuItemProps>(
4545
function SideNavMenuItem(props, ref: ForwardedRef<HTMLElement>) {
@@ -72,6 +72,11 @@ const SideNavMenuItem = React.forwardRef<HTMLElement, SideNavMenuItemProps>(
7272

7373
SideNavMenuItem.displayName = 'SideNavMenuItem';
7474
SideNavMenuItem.propTypes = {
75+
/**
76+
* Optional component to render instead of default Link
77+
*/
78+
as: PropTypes.elementType as PropTypes.Validator<React.ElementType>,
79+
7580
/**
7681
* Specify the children to be rendered inside of the `SideNavMenuItem`
7782
*/
@@ -93,11 +98,6 @@ SideNavMenuItem.propTypes = {
9398
* `aria-current="page"`, as well.
9499
*/
95100
isActive: PropTypes.bool,
96-
97-
/**
98-
* Optional component to render instead of default Link
99-
*/
100-
as: PropTypes.elementType,
101101
};
102102

103103
export default SideNavMenuItem;

packages/react/src/components/UIShell/SwitcherItem.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import React, {
22
ElementType,
3+
ForwardedRef,
34
forwardRef,
45
HTMLAttributeAnchorTarget,
6+
KeyboardEvent,
57
} from 'react';
68
import cx from 'classnames';
79
import PropTypes from 'prop-types';
@@ -131,14 +133,14 @@ const SwitcherItem = forwardRef<ElementType, SwitcherItemProps>(
131133
return (
132134
<li className={classNames}>
133135
<Link
134-
onKeyDown={(evt) => {
136+
onKeyDown={(evt: KeyboardEvent<HTMLAnchorElement>) => {
135137
setTabFocus(evt);
136138
onKeyDown(evt);
137139
}}
138140
href={href}
139141
target={target}
140142
rel={rel}
141-
ref={forwardRef}
143+
ref={forwardRef as ForwardedRef<HTMLAnchorElement | any>}
142144
{...rest}
143145
className={linkClassName}
144146
tabIndex={tabIndex}

0 commit comments

Comments
 (0)