Fix tag and tabs (#584)

This commit is contained in:
Jakub Kotula 2024-10-03 22:27:25 +02:00 committed by GitHub
parent 006d57f7d1
commit 4e53b3e6ef
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 65 additions and 29 deletions

View File

@ -0,0 +1,5 @@
---
"@status-im/components": patch
---
Fix tag and tabs

View File

@ -101,7 +101,7 @@ Trigger.displayName = Tabs.Trigger.displayName
const tabStyles = cva({ const tabStyles = cva({
base: [ base: [
'group inline-flex items-center gap-1 whitespace-nowrap', 'group inline-flex items-center gap-1 whitespace-nowrap',
'disabled:pointer-events-none disabled:opacity-[.3]', 'disabled:opacity-[.3]',
], ],
variants: { variants: {
variant: { variant: {

View File

@ -1,15 +1,17 @@
import { PlaceholderIcon } from '@status-im/icons/20' import { PlaceholderIcon } from '@status-im/icons/20'
import { action } from '@storybook/addon-actions'
import { Tag } from './tag' import { Tag } from './tag'
import type { Meta, StoryObj } from '@storybook/react' import type { Meta, StoryObj } from '@storybook/react'
const meta = { const meta: Meta<typeof Tag> = {
component: Tag, component: Tag,
title: 'Components/Tag', title: 'Components/Tag',
args: { args: {
label: 'Tag', label: 'Tag',
disabled: false, disabled: false,
selected: false,
icon: <PlaceholderIcon />, icon: <PlaceholderIcon />,
iconPlacement: 'left', iconPlacement: 'left',
}, },
@ -24,17 +26,17 @@ const meta = {
render: props => ( render: props => (
<div className="flex flex-col items-start gap-4"> <div className="flex flex-col items-start gap-4">
<Tag {...props} /> <Tag {...props} />
<Tag {...props} selected /> <Tag {...props} onPress={action('pressed')} selected />
<Tag {...props} disabled /> <Tag {...props} onPress={action('pressed')} disabled />
<Tag {...props} size="24" /> <Tag {...props} size="24" />
<Tag {...props} size="24" selected /> <Tag {...props} size="24" onPress={action('pressed')} selected />
<Tag {...props} size="24" disabled /> <Tag {...props} size="24" onPress={action('pressed')} disabled />
<Tag {...props} icon={undefined} /> <Tag {...props} icon={undefined} />
<Tag {...props} label={undefined} /> <Tag {...props} label={undefined} />
<Tag {...props} iconPlacement="right" /> <Tag {...props} iconPlacement="right" />
</div> </div>
), ),
} satisfies Meta<typeof Tag> }
type Story = StoryObj<typeof Tag> type Story = StoryObj<typeof Tag>

View File

@ -8,53 +8,84 @@ import type { Ref } from 'react'
type Variants = VariantProps<typeof styles> type Variants = VariantProps<typeof styles>
type Props = React.ComponentProps<'button'> & { type Props = {
size?: Variants['size'] size?: Variants['size']
label?: string label?: string
icon?: IconElement icon?: IconElement
iconPlacement?: 'left' | 'right' iconPlacement?: 'left' | 'right'
selected?: boolean
onPress?: () => void
} }
const Tag = (props: Props, ref: Ref<HTMLButtonElement>) => { type ButtonProps = {
onPress: () => void
selected?: boolean
disabled?: boolean
} & Omit<React.ComponentPropsWithoutRef<'button'>, 'children'>
type DivProps = Omit<React.ComponentPropsWithoutRef<'div'>, 'children'>
function Tag(
props: Props & (ButtonProps | DivProps),
ref: Ref<HTMLButtonElement | HTMLDivElement>,
) {
const { const {
size = '32', size = '32',
icon, icon,
iconPlacement = 'left', iconPlacement = 'left',
label, label,
selected = false, ...rest
disabled = false,
onPress: onClick,
...buttonProps
} = props } = props
const iconOnly = Boolean(icon && !label) const iconOnly = Boolean(icon && !label)
return ( const content = (
<button <>
onClick={onClick}
{...buttonProps}
disabled={disabled}
ref={ref}
data-selected={selected}
className={styles({ size, selected, disabled, iconOnly })}
>
{icon && iconPlacement === 'left' && ( {icon && iconPlacement === 'left' && (
<span className={iconStyles({ size, placement: 'left', iconOnly })}> <span className={iconStyles({ size, placement: 'left', iconOnly })}>
{cloneElement(icon)} {cloneElement(icon)}
</span> </span>
)} )}
{label && <span className="flex-1 whitespace-nowrap">{label}</span>} {label && <span className="flex-1 whitespace-nowrap">{label}</span>}
{icon && iconPlacement === 'right' && ( {icon && iconPlacement === 'right' && (
<span className={iconStyles({ size, placement: 'right', iconOnly })}> <span className={iconStyles({ size, placement: 'right', iconOnly })}>
{cloneElement(icon)} {cloneElement(icon)}
</span> </span>
)} )}
</>
)
if ('onPress' in props) {
const { selected, disabled, ...buttonProps } = props as ButtonProps
return (
<button
{...buttonProps}
onClick={props.onPress}
ref={ref as Ref<HTMLButtonElement>}
data-selected={selected ? selected : undefined}
className={styles({
size,
selected,
disabled,
iconOnly,
})}
>
{content}
</button> </button>
) )
}
return (
<div
{...(rest as DivProps)}
ref={ref as Ref<HTMLDivElement>}
className={styles({
size,
iconOnly,
})}
>
{content}
</div>
)
} }
const styles = cva({ const styles = cva({
@ -62,8 +93,6 @@ const styles = cva({
'inline-flex shrink-0 items-center justify-center gap-1 border border-neutral-20 font-medium transition-all hover:border-neutral-30', 'inline-flex shrink-0 items-center justify-center gap-1 border border-neutral-20 font-medium transition-all hover:border-neutral-30',
'outline-none focus:outline-none focus-visible:ring-2 focus-visible:ring-customisation-50 focus-visible:ring-offset-2', 'outline-none focus:outline-none focus-visible:ring-2 focus-visible:ring-customisation-50 focus-visible:ring-offset-2',
'disabled:cursor-default disabled:opacity-[.3]', 'disabled:cursor-default disabled:opacity-[.3]',
// dark
'dark:border-neutral-80 dark:text-white-100 dark:hover:border-neutral-60', 'dark:border-neutral-80 dark:text-white-100 dark:hover:border-neutral-60',
], ],
variants: { variants: {