-
Notifications
You must be signed in to change notification settings - Fork 267
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
Add forwardRef support to Button & View #698
Changes from all commits
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 |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@aws-amplify/ui-react": minor | ||
--- | ||
|
||
Add forwardRef support to Button & View |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,37 +1,47 @@ | ||
import classNames from 'classnames'; | ||
import * as React from 'react'; | ||
|
||
import { ComponentClassNames } from '../shared/constants'; | ||
import { ButtonProps, Primitive } from '../types'; | ||
import { ButtonProps, PrimitiveWithForwardRef } from '../types'; | ||
import { View } from '../View'; | ||
|
||
export const Button: Primitive<ButtonProps, 'button'> = ({ | ||
className, | ||
children, | ||
isFullWidth = false, | ||
isDisabled, | ||
isLoading, | ||
loadingText = '', | ||
size, | ||
type = 'button', | ||
variation, | ||
...rest | ||
}) => ( | ||
<View | ||
as="button" | ||
className={classNames( | ||
ComponentClassNames.Button, | ||
ComponentClassNames.FieldGroupControl, | ||
className | ||
)} | ||
data-fullwidth={isFullWidth} | ||
data-loading={isLoading} | ||
data-size={size} | ||
data-variation={variation} | ||
isDisabled={isDisabled || isLoading} | ||
type={type} | ||
{...rest} | ||
> | ||
{isLoading && loadingText ? <span>{loadingText}</span> : children} | ||
</View> | ||
); | ||
const ButtonInner: PrimitiveWithForwardRef<ButtonProps, 'button'> = ( | ||
{ | ||
className, | ||
children, | ||
isFullWidth = false, | ||
isDisabled, | ||
isLoading, | ||
loadingText = '', | ||
size, | ||
type = 'button', | ||
variation, | ||
...rest | ||
}, | ||
ref | ||
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. Added |
||
) => { | ||
return ( | ||
<View | ||
ref={ref} | ||
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. This is the only change to the returned jsx, setting the |
||
as="button" | ||
className={classNames( | ||
ComponentClassNames.Button, | ||
ComponentClassNames.FieldGroupControl, | ||
className | ||
)} | ||
data-fullwidth={isFullWidth} | ||
data-loading={isLoading} | ||
data-size={size} | ||
data-variation={variation} | ||
isDisabled={isDisabled || isLoading} | ||
type={type} | ||
{...rest} | ||
> | ||
{isLoading && loadingText ? <span>{loadingText}</span> : children} | ||
</View> | ||
); | ||
}; | ||
|
||
export const Button = React.forwardRef(ButtonInner); | ||
|
||
Button.displayName = 'Button'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,20 @@ type MergeProps<A, B> = A & Omit<B, keyof A>; | |
|
||
export type ElementType = React.FC<any> | keyof JSX.IntrinsicElements; | ||
|
||
/** | ||
* Convert string element type to DOMElement Type | ||
* e.g. 'button' => HTMLButtonElement | ||
*/ | ||
export type HTMLElementType<Element extends ElementType> = | ||
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. Hat tip to @hvergara for this type magic |
||
Element extends keyof JSX.IntrinsicElements | ||
? JSX.IntrinsicElements[Element] extends React.DetailedHTMLProps< | ||
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. This could potentially be And can you explain why always return 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. It might be more accurate to return 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. I am asking because we do have 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. yeah, good idea |
||
unknown, | ||
infer HTMLType | ||
> | ||
? HTMLType | ||
: never | ||
: HTMLDivElement; | ||
|
||
export type ElementProps<Element extends ElementType> = | ||
Element extends keyof JSX.IntrinsicElements | ||
? JSX.IntrinsicElements[Element] | ||
|
@@ -18,15 +32,32 @@ export type PrimitiveProps< | |
Props extends ViewProps, | ||
Element extends ElementType | ||
> = MergeProps< | ||
Omit<Props, 'as'> & { as?: Element | Props['as'] }, | ||
ElementProps<Element> | ||
Omit<Props, 'as'> & { | ||
as?: Element | Props['as']; | ||
}, | ||
Omit<ElementProps<Element>, 'ref'> // exclude `ref?: LegacyRef` included in DetailedHTMLProps | ||
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. This Omit is required because 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. 🙌🏽 |
||
>; | ||
|
||
export type PrimitivePropsWithRef< | ||
Props extends ViewProps, | ||
Element extends ElementType | ||
> = PrimitiveProps<Props, Element> & { | ||
ref?: React.Ref<HTMLElementType<Element>>; | ||
}; | ||
|
||
export type Primitive< | ||
Props extends ViewProps, | ||
Element extends ElementType | ||
> = React.FC<PrimitiveProps<Props, Element>>; | ||
|
||
export type PrimitiveWithForwardRef< | ||
Props extends ViewProps, | ||
Element extends ElementType | ||
> = React.ForwardRefRenderFunction< | ||
HTMLElementType<Element>, | ||
PrimitivePropsWithRef<Props, Element> | ||
>; | ||
|
||
export interface ViewProps | ||
extends BaseComponentProps, | ||
BaseStyleProps, | ||
|
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.
Should this be major since it's technically a change in behavior?