Skip to content

Commit

Permalink
Remove OverridableComponent from Button
Browse files Browse the repository at this point in the history
  • Loading branch information
TomasSlama committed Sep 16, 2024
1 parent 894bfd3 commit a6bdbba
Show file tree
Hide file tree
Showing 6 changed files with 201 additions and 192 deletions.
9 changes: 4 additions & 5 deletions packages/base/Button/src/Button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import type {
StandardProps,
SizeType,
ButtonOrAnchorProps,
OverridableComponent,
TextLabelProps,
} from '@toptal/picasso-shared'
import { noop } from '@toptal/picasso-utils'
Expand Down Expand Up @@ -95,10 +94,10 @@ const getIcon = ({
})
}

export const Button: OverridableComponent<Props> = forwardRef<
HTMLButtonElement,
Props
>(function Button(props, ref) {
export const Button = forwardRef<HTMLButtonElement, Props>(function Button(
props,
ref
) {
const {
icon,
iconPosition,
Expand Down
85 changes: 40 additions & 45 deletions packages/base/Button/src/ButtonAction/ButtonAction.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
import type { ReactElement, MouseEvent, ElementType, ReactNode } from 'react'
import React, { forwardRef } from 'react'
import cx from 'classnames'
import type {
BaseProps,
ButtonOrAnchorProps,
OverridableComponent,
} from '@toptal/picasso-shared'
import type { BaseProps, ButtonOrAnchorProps } from '@toptal/picasso-shared'
import { Loader } from '@toptal/picasso-loader'

import type { IconPositionType } from '../Button'
Expand Down Expand Up @@ -59,49 +55,48 @@ export interface Props extends BaseProps, ButtonOrAnchorProps {

const loaderIcon = <Loader size='small' variant='inherit' />

export const ButtonAction: OverridableComponent<Props> = forwardRef<
HTMLButtonElement,
Props
>(function ButtonAction(props, ref) {
const {
/* eslint-disable @typescript-eslint/no-unused-vars */
// We use these props only to determine styles
active,
focused,
hovered,
/* eslint-enable @typescript-eslint/no-unused-vars */
className,
disabled,
loading,
icon,
iconPosition,
onClick,
...rest
} = props
export const ButtonAction = forwardRef<HTMLButtonElement, Props>(
function ButtonAction(props, ref) {
const {
/* eslint-disable @typescript-eslint/no-unused-vars */
// We use these props only to determine styles
active,
focused,
hovered,
/* eslint-enable @typescript-eslint/no-unused-vars */
className,
disabled,
loading,
icon,
iconPosition,
onClick,
...rest
} = props

const usedIcon = loading ? loaderIcon : icon
const usedIconPosition = icon ? iconPosition : 'right'
const usedIcon = loading ? loaderIcon : icon
const usedIconPosition = icon ? iconPosition : 'right'

const finalClassName = cx(createRootClassNames(props), className)
const finalIcon = getIcon({
children: rest.children,
icon: usedIcon,
iconPosition: usedIconPosition,
})
const finalClassName = cx(createRootClassNames(props), className)
const finalIcon = getIcon({
children: rest.children,
icon: usedIcon,
iconPosition: usedIconPosition,
})

return (
<ButtonBase
{...rest}
ref={ref}
icon={finalIcon}
iconPosition={usedIconPosition}
onClick={loading ? undefined : onClick}
className={finalClassName}
contentClassName='font-semibold text-blue-500 text-md'
disabled={disabled}
/>
)
})
return (
<ButtonBase
{...rest}
ref={ref}
icon={finalIcon}
iconPosition={usedIconPosition}
onClick={loading ? undefined : onClick}
className={finalClassName}
contentClassName='font-semibold text-blue-500 text-md'
disabled={disabled}
/>
)
}
)

ButtonAction.defaultProps = {
iconPosition: 'left',
Expand Down
157 changes: 79 additions & 78 deletions packages/base/Button/src/ButtonBase/ButtonBase.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { twMerge } from '@toptal/picasso-tailwind-merge'
import type {
StandardProps,
ButtonOrAnchorProps,
OverridableComponent,
TextLabelProps,
} from '@toptal/picasso-shared'
import { useTitleCase } from '@toptal/picasso-shared'
Expand All @@ -31,7 +30,7 @@ export interface Props
/** ClassName for the content */
contentClassName?: string
/** Add an `<Icon />` along Button's children */
icon?: ReactElement
icon?: ReactElement | null
/** Icon can be positioned on the left or right */
iconPosition?: IconPositionType
/** Shows a loading indicator and disables click events */
Expand Down Expand Up @@ -69,86 +68,88 @@ const RootElement = forwardRef(
}
)

export const ButtonBase: OverridableComponent<Props> = forwardRef<
HTMLButtonElement,
Props
>(function ButtonBase(props, ref) {
const {
icon,
iconPosition,
loading,
children,
className,
contentClassName,
style,
disabled,
onClick,
title,
value,
type,
as = 'button',
titleCase: propsTitleCase,
...rest
} = props

const titleCase = useTitleCase(propsTitleCase)
const finalChildren = [titleCase ? toTitleCase(children) : children]
const finalRootElementName = typeof as === 'string' ? as : 'a'

if (icon) {
const iconComponent = getIcon({ icon })

if (iconPosition === 'left') {
finalChildren.unshift(iconComponent)
} else {
finalChildren.push(iconComponent)
export const ButtonBase = forwardRef<HTMLButtonElement, Props>(
function ButtonBase(props, ref) {
const {
icon,
iconPosition,
loading,
children,
className,
contentClassName,
style,
disabled,
onClick,
title,
value,
type,
as = 'button',
titleCase: propsTitleCase,
...rest
} = props

const titleCase = useTitleCase(propsTitleCase)
const finalChildren = [titleCase ? toTitleCase(children) : children]
const finalRootElementName = typeof as === 'string' ? as : 'a'

if (icon) {
const iconComponent = getIcon({ icon })

if (iconPosition === 'left') {
finalChildren.unshift(iconComponent)
} else {
finalChildren.push(iconComponent)
}
}
}

const finalClassName = twMerge(createCoreClassNames({ disabled }), className)

return (
<MUIButtonBase
{...rest}
ref={ref}
onClick={getClickHandler(loading, onClick)}
className={finalClassName}
style={style}
aria-disabled={disabled}
disabled={disabled}
title={title}
value={value}
type={type}
data-component-type='button'
tabIndex={rest.tabIndex ?? disabled ? -1 : 0}
role={rest.role ?? 'button'}
rootElementName={finalRootElementName as keyof HTMLElementTagNameMap}
slots={{ root: RootElement }}
// @ts-ignore
slotProps={{ root: { as } }}
>
<Container
as='span'
inline
flex
direction='row'
alignItems='center'
className={contentClassName}
const finalClassName = twMerge(
createCoreClassNames({ disabled }),
className
)

return (
<MUIButtonBase
{...rest}
ref={ref}
onClick={getClickHandler(loading, onClick)}
className={finalClassName}
style={style}
aria-disabled={disabled}
disabled={disabled}
title={title}
value={value}
type={type}
data-component-type='button'
tabIndex={rest.tabIndex ?? disabled ? -1 : 0}
role={rest.role ?? 'button'}
rootElementName={finalRootElementName as keyof HTMLElementTagNameMap}
slots={{ root: RootElement }}
// @ts-ignore
slotProps={{ root: { as } }}
>
{finalChildren}
</Container>

{loading && (
<Loader
variant='inherit'
className='absolute top-1/2 left-1/2 translate-x-[-50%] translate-y-[-50%]'
<Container
as='span'
inline
size='small'
/>
)}
</MUIButtonBase>
)
})
flex
direction='row'
alignItems='center'
className={contentClassName}
>
{finalChildren}
</Container>

{loading && (
<Loader
variant='inherit'
className='absolute top-1/2 left-1/2 translate-x-[-50%] translate-y-[-50%]'
inline
size='small'
/>
)}
</MUIButtonBase>
)
}
)

ButtonBase.defaultProps = {
as: 'button',
Expand Down
Loading

0 comments on commit a6bdbba

Please sign in to comment.