Attempting to add forwardRef

Signed-off-by: James Brooks <jamesbrooks@spotify.com>
This commit is contained in:
James Brooks
2025-06-18 17:49:05 +01:00
parent 32384c1ee8
commit 6f9b502232
3 changed files with 75 additions and 58 deletions
+60 -44
View File
@@ -15,54 +15,70 @@
*/
import clsx from 'clsx';
import {
ComponentPropsWithRef,
ElementType,
forwardRef,
ReactElement,
Ref,
} from 'react';
import { Button as RAButton } from 'react-aria-components';
import { useResponsiveValue } from '../../hooks/useResponsiveValue';
import type { ButtonProps } from './types';
/** @public */
export const Button = <C extends React.ElementType = 'button'>(
props: ButtonProps<C>,
) => {
const {
as,
size = 'small',
variant = 'primary',
iconStart,
iconEnd,
children,
className,
...rest
} = props;
export const Button = forwardRef(
(props: ButtonProps<typeof RAButton>, ref: Ref<HTMLButtonElement>) => {
const {
as,
size = 'small',
variant = 'primary',
iconStart,
iconEnd,
children,
className,
...rest
} = props;
const Component = as || 'button';
const responsiveSize = useResponsiveValue(size);
const responsiveVariant = useResponsiveValue(variant);
const Component = as || RAButton;
const responsiveSize = useResponsiveValue(size);
const responsiveVariant = useResponsiveValue(variant);
return (
<Component
className={clsx('canon-Button', className)}
data-variant={responsiveVariant}
data-size={responsiveSize}
{...rest}
>
{iconStart && (
<span
className="canon-ButtonIcon"
aria-hidden="true"
data-size={responsiveSize}
>
{iconStart}
</span>
)}
{children}
{iconEnd && (
<span
className="canon-ButtonIcon"
aria-hidden="true"
data-size={responsiveSize}
>
{iconEnd}
</span>
)}
</Component>
);
return (
<Component
className={clsx('canon-Button', className)}
data-variant={responsiveVariant}
data-size={responsiveSize}
ref={ref}
{...rest}
>
{iconStart && (
<span
className="canon-ButtonIcon"
aria-hidden="true"
data-size={responsiveSize}
>
{iconStart}
</span>
)}
{children}
{iconEnd && (
<span
className="canon-ButtonIcon"
aria-hidden="true"
data-size={responsiveSize}
>
{iconEnd}
</span>
)}
</Component>
);
},
) as {
<TAs extends ElementType = typeof RAButton>(
props: ButtonProps<TAs> & { ref?: ComponentPropsWithRef<TAs>['ref'] },
): ReactElement;
displayName: string;
};
Button.displayName = 'Button';
@@ -15,17 +15,18 @@
*/
import { Breakpoint } from '@backstage/canon';
import { ReactElement } from 'react';
import { PolymorphicComponentProp } from '../../types';
import { ElementType, ReactElement, ReactNode } from 'react';
import { PolymorphicComponentProps } from '../../types';
/**
* Properties for {@link Button}
*
* @public
*/
export type ButtonProps<C extends React.ElementType> = PolymorphicComponentProp<
C,
export type ButtonProps<TAs extends ElementType> = PolymorphicComponentProps<
TAs,
{
children?: ReactNode;
size?: 'small' | 'medium' | Partial<Record<Breakpoint, 'small' | 'medium'>>;
variant?:
| 'primary'
+10 -10
View File
@@ -14,6 +14,8 @@
* limitations under the License.
*/
import { ComponentPropsWithoutRef, ElementType } from 'react';
/** @public */
export type AsProps =
| 'div'
@@ -133,19 +135,17 @@ export interface UtilityProps extends SpaceProps {
}
/** @public */
export type AsProp<C extends React.ElementType> = {
as?: C;
export type As<TAs extends ElementType> = {
as?: TAs;
};
/** @public */
export type PropsToOmit<C extends React.ElementType, P> = keyof (AsProp<C> & P);
/**
* This is the first reusable type utility we built
* @public
*/
export type PolymorphicComponentProp<
C extends React.ElementType,
Props = {},
> = React.PropsWithChildren<Props & AsProp<C>> &
Omit<React.ComponentPropsWithoutRef<C>, PropsToOmit<C, Props>>;
export type PolymorphicComponentProps<
TAs extends ElementType,
TProps = {},
> = TProps &
As<TAs> &
Omit<ComponentPropsWithoutRef<TAs>, keyof (As<TAs> & TProps)>;