-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
Refactor Button
component to TypeScript
#46997
Changes from 20 commits
c05948f
5b57ef6
718959c
d8cae0c
d007837
6ab8806
878c77d
78e0aaf
00c05da
9e6cc7d
9298bd7
7314d0a
0b616c7
3998f8b
67efafe
bbc7cd4
0f7a242
ca6ded1
dadbb4b
a447deb
e702dd4
0badec8
b9a3b50
57866b7
d8dcaee
5e270a1
8ce4937
fd4144a
916f9ac
3632a42
309db5c
31cbdab
2ca61e5
be1359d
35f8efb
b84337d
14e1137
12fa70f
a38c275
cea1f6b
ccd87bc
561d6aa
3892543
01f3c9c
07b7002
dfef117
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 |
---|---|---|
|
@@ -166,7 +166,7 @@ const BorderControlDropdown = ( | |
onClick={ onToggle } | ||
variant="tertiary" | ||
aria-label={ toggleAriaLabel } | ||
position={ dropdownPosition } | ||
tooltipPosition={ dropdownPosition } | ||
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 also has a |
||
label={ __( 'Border color and style picker' ) } | ||
showTooltip={ true } | ||
> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,8 @@ | ||
// @ts-nocheck | ||
/** | ||
* External dependencies | ||
*/ | ||
import classnames from 'classnames'; | ||
import type { ForwardedRef, HTMLProps, MouseEvent, ReactElement } from 'react'; | ||
|
||
/** | ||
* WordPress dependencies | ||
|
@@ -17,8 +17,18 @@ import { useInstanceId } from '@wordpress/compose'; | |
import Tooltip from '../tooltip'; | ||
import Icon from '../icon'; | ||
import { VisuallyHidden } from '../visually-hidden'; | ||
|
||
const disabledEventsOnDisabledButton = [ 'onMouseDown', 'onClick' ]; | ||
import type { WordPressComponentProps } from '../ui/context'; | ||
import type { | ||
ButtonProps, | ||
DeprecatedButtonProps, | ||
DisabledEvent, | ||
TagName, | ||
} from './types'; | ||
|
||
const disabledEventsOnDisabledButton: DisabledEvent[] = [ | ||
'onMouseDown', | ||
'onClick', | ||
]; | ||
kienstra marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
function useDeprecatedProps( { | ||
isDefault, | ||
|
@@ -28,7 +38,7 @@ function useDeprecatedProps( { | |
isLink, | ||
variant, | ||
...otherProps | ||
} ) { | ||
}: WordPressComponentProps< ButtonProps & DeprecatedButtonProps, TagName > ) { | ||
let computedVariant = variant; | ||
|
||
if ( isPrimary ) { | ||
|
@@ -63,7 +73,10 @@ function useDeprecatedProps( { | |
}; | ||
} | ||
|
||
export function Button( props, ref ) { | ||
export function UnforwardedButton( | ||
props: WordPressComponentProps< ButtonProps, TagName >, | ||
ref: ForwardedRef< any > | ||
) { | ||
const { | ||
href, | ||
target, | ||
|
@@ -93,10 +106,12 @@ export function Button( props, ref ) { | |
); | ||
|
||
const hasChildren = | ||
children?.[ 0 ] && | ||
children[ 0 ] !== null && | ||
// Tooltip should not considered as a child | ||
children?.[ 0 ]?.props?.className !== 'components-tooltip'; | ||
( 'string' === typeof children && !! children ) || | ||
( Array.isArray( children ) && | ||
children?.[ 0 ] && | ||
children[ 0 ] !== null && | ||
// Tooltip should not considered as a child | ||
children?.[ 0 ]?.props?.className !== 'components-tooltip' ); | ||
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 more complex than I'd like. But simply checking for This is because |
||
|
||
const classes = classnames( 'components-button', className, { | ||
'is-secondary': variant === 'secondary', | ||
|
@@ -113,7 +128,7 @@ export function Button( props, ref ) { | |
|
||
const trulyDisabled = disabled && ! isFocusable; | ||
const Tag = href !== undefined && ! trulyDisabled ? 'a' : 'button'; | ||
const tagProps = | ||
const tagProps: HTMLProps< TagName > = | ||
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 typing looks unnecessary, but it prevents a TS error below. |
||
Tag === 'a' | ||
? { href, target } | ||
: { | ||
|
@@ -128,9 +143,11 @@ export function Button( props, ref ) { | |
tagProps[ 'aria-disabled' ] = true; | ||
|
||
for ( const disabledEvent of disabledEventsOnDisabledButton ) { | ||
additionalProps[ disabledEvent ] = ( event ) => { | ||
event.stopPropagation(); | ||
event.preventDefault(); | ||
additionalProps[ disabledEvent ] = ( event: MouseEvent ) => { | ||
if ( event ) { | ||
event.stopPropagation(); | ||
event.preventDefault(); | ||
} | ||
}; | ||
} | ||
} | ||
|
@@ -145,24 +162,26 @@ export function Button( props, ref ) { | |
// There's a label and... | ||
( !! label && | ||
// The children are empty and... | ||
! children?.length && | ||
! ( children as string | ReactElement[] )?.length && | ||
// The tooltip is not explicitly disabled. | ||
false !== showTooltip ) ); | ||
|
||
const descriptionId = describedBy ? instanceId : null; | ||
const descriptionId = describedBy ? instanceId : undefined; | ||
|
||
const describedById = | ||
additionalProps[ 'aria-describedby' ] || descriptionId; | ||
|
||
const element = ( | ||
<Tag | ||
{ ...tagProps } | ||
{ ...additionalProps } | ||
className={ classes } | ||
aria-label={ additionalProps[ 'aria-label' ] || label } | ||
aria-describedby={ describedById } | ||
ref={ ref } | ||
> | ||
const elementProps = { | ||
...tagProps, | ||
...additionalProps, | ||
className: classes, | ||
'aria-label': additionalProps[ 'aria-label' ] || label, | ||
'aria-describedby': describedById, | ||
ref, | ||
}; | ||
|
||
const elementChildren = ( | ||
<> | ||
{ icon && iconPosition === 'left' && ( | ||
<Icon icon={ icon } size={ iconSize } /> | ||
) } | ||
|
@@ -171,9 +190,30 @@ export function Button( props, ref ) { | |
<Icon icon={ icon } size={ iconSize } /> | ||
) } | ||
{ children } | ||
</Tag> | ||
</> | ||
); | ||
|
||
const element = | ||
Tag === 'a' ? ( | ||
<a | ||
{ ...( elementProps as WordPressComponentProps< | ||
ButtonProps, | ||
'a' | ||
> ) } | ||
> | ||
{ elementChildren } | ||
</a> | ||
) : ( | ||
<button | ||
{ ...( elementProps as WordPressComponentProps< | ||
ButtonProps, | ||
'button' | ||
> ) } | ||
> | ||
{ elementChildren } | ||
</button> | ||
); | ||
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.
But without this, there are type errors:
|
||
|
||
if ( ! shouldShowTooltip ) { | ||
return ( | ||
<> | ||
|
@@ -190,7 +230,12 @@ export function Button( props, ref ) { | |
return ( | ||
<> | ||
<Tooltip | ||
text={ children?.length && describedBy ? describedBy : label } | ||
text={ | ||
( children as string | ReactElement[] )?.length && | ||
describedBy | ||
? describedBy | ||
: label | ||
} | ||
shortcut={ shortcut } | ||
position={ tooltipPosition } | ||
> | ||
|
@@ -205,4 +250,5 @@ export function Button( props, ref ) { | |
); | ||
} | ||
|
||
export default forwardRef( Button ); | ||
export const Button = forwardRef( UnforwardedButton ); | ||
export default Button; |
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.
Sorry to expand the scope outside of
components/src/button/
This corrects a TS error:
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.
Not at all, you caught a legitimate typing error here 🙂
The error is coming from the fact that the props for
BorderBoxControlLinkedButton
(and alsouseBorderBoxControlLinkedButton
) are typed as if the rest props would forward to adiv
, when in fact they forward to abutton
.gutenberg/packages/components/src/border-box-control/border-box-control-linked-button/component.tsx
Line 19 in 16f74d3
☝️ So we should fix these to
'button'
instead of castingbuttonProps
withas
.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.
Great idea, committed in 31cbdab