fix(LOY-128): add rounded filter chip variant

This commit is contained in:
Christian Andolf
2025-06-09 16:28:21 +02:00
parent d560ac0fca
commit f292cc7922
6 changed files with 200 additions and 48 deletions

View File

@@ -2,7 +2,7 @@
import { cx } from "class-variance-authority" import { cx } from "class-variance-authority"
import { Typography } from "@scandic-hotels/design-system/Typography" import { ChipButton } from "@scandic-hotels/design-system/ChipButton"
import useScrollShadows from "@/hooks/useScrollShadows" import useScrollShadows from "@/hooks/useScrollShadows"
@@ -32,29 +32,23 @@ export default function TabFilters({
return ( return (
<div <div
className={cx( className={cx(styles.containerWrapper, {
styles.containerWrapper, [styles.showLeftShadow]: showLeftShadow,
showLeftShadow && styles.showLeftShadow, [styles.showRightShadow]: showRightShadow,
showRightShadow && styles.showRightShadow })}
)}
> >
<div className={styles.container} ref={containerRef}> <div className={styles.container} ref={containerRef}>
{categories.map((category) => ( {categories.map((category) => (
<Typography <ChipButton
key={category.identifier} key={category.identifier}
variant="Body/Supporting text (caption)/smRegular" onPress={() => onFilterSelect(category.identifier)}
variant="FilterRounded"
selected={selectedFilter === category.identifier}
className={styles.filter}
> >
<button <IconByCSSelect identifier={category.iconIdentifier} />
onClick={() => onFilterSelect(category.identifier)} {category.label}
className={cx(styles.filter, { </ChipButton>
[styles.selected]: selectedFilter === category.identifier,
})}
type="button"
>
<IconByCSSelect identifier={category.iconIdentifier} />
{category.label}
</button>
</Typography>
))} ))}
</div> </div>
</div> </div>

View File

@@ -38,25 +38,10 @@
scrollbar-width: none; scrollbar-width: none;
position: relative; position: relative;
width: 100%; width: 100%;
padding: var(--Space-x05);
} }
.filter { .filter {
display: flex; scroll-snap-align: center;
align-items: center;
gap: var(--Space-x1);
background-color: transparent;
border: 1px solid var(--Border-Interactive-Selected);
border-radius: var(--Corner-radius-rounded);
padding: var(--Space-x1) var(--Space-x2);
transition: all 0.2s ease-in-out;
scroll-snap-align: start;
flex-shrink: 0; flex-shrink: 0;
cursor: pointer;
color: var(--Text-Default);
}
.filter.selected {
border-color: transparent;
background-color: var(--Base-Button-Tertiary-Fill-Normal);
color: var(--Text-Inverted);
} }

View File

@@ -51,3 +51,61 @@ export const Outlined: Story = {
), ),
}, },
} }
export const FilterRoundedLarge: Story = {
args: {
variant: 'FilterRounded',
onPress: fn(),
size: 'Large',
children: (
<>
<MaterialIcon icon="location_city" size={20} color="CurrentColor" />
Button Chip
</>
),
},
}
export const FilterRoundedLargeSelected: Story = {
args: {
variant: 'FilterRounded',
onPress: fn(),
size: 'Large',
selected: true,
children: (
<>
<MaterialIcon icon="location_city" size={20} color="CurrentColor" />
Button Chip
</>
),
},
}
export const FilterRoundedMedium: Story = {
args: {
variant: 'FilterRounded',
onPress: fn(),
size: 'Medium',
children: (
<>
<MaterialIcon icon="location_city" size={20} color="CurrentColor" />
Button Chip
</>
),
},
}
export const FilterRoundedMediumSelected: Story = {
args: {
variant: 'FilterRounded',
onPress: fn(),
size: 'Medium',
selected: true,
children: (
<>
<MaterialIcon icon="location_city" size={20} color="CurrentColor" />
Button Chip
</>
),
},
}

View File

@@ -1,24 +1,25 @@
import { Button as ButtonRAC } from 'react-aria-components' import { Button as ButtonRAC } from 'react-aria-components'
import { Typography } from '../Typography'
import { ChipButtonProps } from './types' import { ChipButtonProps } from './types'
import { variants } from './variants' import { variants } from './variants'
export function ChipButton({ export function ChipButton({
children, children,
variant, variant,
selected = false,
size = 'Large',
className, className,
...props ...props
}: ChipButtonProps) { }: ChipButtonProps) {
const classNames = variants({ const classNames = variants({
variant, variant,
selected,
size,
}) })
return ( return (
<Typography variant="Body/Supporting text (caption)/smBold"> <ButtonRAC {...props} className={[className, classNames].join(' ')}>
<ButtonRAC {...props} className={[className, classNames].join(' ')}> {children}
{children} </ButtonRAC>
</ButtonRAC>
</Typography>
) )
} }

View File

@@ -7,6 +7,7 @@
align-items: center; align-items: center;
justify-content: center; justify-content: center;
cursor: pointer; cursor: pointer;
gap: var(--Space-x05);
} }
.Default { .Default {
@@ -30,8 +31,31 @@
border-color: var(--Border-Interactive-Selected); border-color: var(--Border-Interactive-Selected);
} }
.FilterRounded {
background-color: transparent;
border: 1px solid var(--Border-Interactive-Selected);
border-radius: var(--Corner-radius-rounded);
padding: var(--Space-x025) var(--Space-x2);
color: var(--Text-Default);
}
.selected {
border-color: transparent;
background-color: var(--Surface-Brand-Primary-3-Default);
color: var(--Text-Inverted);
}
.large {
height: 40px;
}
.medium {
height: 32px;
}
.Default:focus, .Default:focus,
.Outlined:focus { .Outlined:focus,
.FilterRounded:focus {
outline-offset: 4px; outline-offset: 4px;
outline-color: var(--Border-Interactive-Focus); outline-color: var(--Border-Interactive-Focus);
} }

View File

@@ -2,24 +2,114 @@ import { cva } from 'class-variance-authority'
import { deepmerge } from 'deepmerge-ts' import { deepmerge } from 'deepmerge-ts'
import styles from './chip-button.module.css' import styles from './chip-button.module.css'
import { config as typographyConfig } from '../Typography/variants'
const variantKeys = {
variant: {
Default: 'Default',
Outlined: 'Outlined',
FilterRounded: 'FilterRounded',
},
style: {
Medium: 'Medium',
Large: 'Large',
},
typography: {
Bold: 'Body/Supporting text (caption)/smBold',
Regular: 'Body/Supporting text (caption)/smRegular',
},
} as const
export const config = { export const config = {
variants: { variants: {
variant: { variant: {
Default: styles.Default, [variantKeys.variant.Default]: styles.Default,
Outlined: styles.Outlined, [variantKeys.variant.Outlined]: styles.Outlined,
[variantKeys.variant.FilterRounded]: styles.FilterRounded,
},
selected: {
true: '',
false: '',
},
size: {
[variantKeys.style.Medium]: '',
[variantKeys.style.Large]: '',
}, },
}, },
compoundVariants: [
{
variant: variantKeys.variant.Default,
className: [
typographyConfig.variants.variant[
'Body/Supporting text (caption)/smBold'
],
],
},
{
variant: variantKeys.variant.Outlined,
className: [
typographyConfig.variants.variant[
'Body/Supporting text (caption)/smBold'
],
],
},
{
variant: variantKeys.variant.FilterRounded,
size: variantKeys.style.Medium,
selected: true,
className: [
typographyConfig.variants.variant[
'Body/Supporting text (caption)/smRegular'
],
styles.selected,
styles.medium,
],
},
{
variant: variantKeys.variant.FilterRounded,
size: variantKeys.style.Medium,
selected: false,
className: [
typographyConfig.variants.variant[
'Body/Supporting text (caption)/smRegular'
],
styles.medium,
],
},
{
variant: variantKeys.variant.FilterRounded,
size: variantKeys.style.Large,
selected: true,
className: [
typographyConfig.variants.variant[
'Body/Supporting text (caption)/smRegular'
],
styles.selected,
styles.large,
],
},
{
variant: variantKeys.variant.FilterRounded,
size: variantKeys.style.Large,
selected: false,
className: [
typographyConfig.variants.variant[
'Body/Supporting text (caption)/smRegular'
],
styles.large,
],
},
],
defaultVariants: { defaultVariants: {
variant: 'Default', variant: variantKeys.variant.Default,
}, },
} as const }
export const variants = cva(styles.chip, config) export const variants = cva(styles.chip, config)
const chipConfig = { const chipConfig = {
variants: { variants: {
typography: config.variants.variant, ...config.variants,
}, },
defaultVariants: config.defaultVariants, defaultVariants: config.defaultVariants,
} as const } as const