Skip to content

Instantly share code, notes, and snippets.

@ArnaudRinquin
Created January 17, 2024 09:03
Show Gist options
  • Save ArnaudRinquin/870b48d86ac9560e0b4e87c2860cf3e6 to your computer and use it in GitHub Desktop.
Save ArnaudRinquin/870b48d86ac9560e0b4e87c2860cf3e6 to your computer and use it in GitHub Desktop.
Navie > Better > twc

What's interesting to note on this not so trivial example (we have variants -> className; base style attrs that can be expended)

  • comprehensive img props types + automatically passed
  • auto extra classNames (& style) merging
  • auto ref forwarding, if need be

It's debatable that writing such component is simpler than the classic approach but the outcome is undoubtly better.

There are also nice ways to handle variants and such.

// before I reworked it yesterday
import classNames from 'classnames'
import React from 'react'
import { CardProps } from './Card'
export type CardImageProps = {
radiusSize?: CardProps['radiusSize']
className?: string
src: string
alt: string
}
export const CardImage = ({
radiusSize = 'normal',
className,
src,
alt,
}: CardImageProps) => {
return (
<img
className={classNames(
'block width-full',
'background-shade-60 transition',
`radius-top-${radiusSize}`, // classnames should not be composed (hard to figure usage afterward)
className
)}
style={{ minHeight: 170 }}
src={src}
alt={alt}
/>
)
}
import classNames from 'classnames'
import React from 'react'
import { CardProps } from './Card'
const classesPerRadiusSize: Record<
Exclude<CardProps['radiusSize'], undefined>,
string
> = {
large: 'radius-top-large',
none: 'radius-top-none',
normal: 'radius-top-normal',
}
// proper props -> you may pass everything an img element accepts
export type CardImageProps = React.ImgHTMLAttributes<HTMLImageElement> & {
radiusSize?: CardProps['radiusSize']
}
export const CardImage = ({
radiusSize = 'normal',
className,
style,
alt, // extracting it only to ease linter rules
...imageProps
}: CardImageProps) => {
return (
<img
className={classNames(
'block width-full',
'background-shade-60 transition',
classesPerRadiusSize[radiusSize],
className
)}
alt={alt}
style={{ minHeight: 170, ...style }}
{...imageProps} // proper props spreading
/>
)
}
import { CardProps } from './Card'
import { twc, TwcComponentProps } from 'react-twc'
const classesPerRadiusSize: Record<
Exclude<CardProps['radiusSize'], undefined>,
string
> = {
large: 'radius-top-large',
none: 'radius-top-none',
normal: 'radius-top-normal',
}
export type CardImageProps = TwcComponentProps<'img'> & {
radiusSize: CardProps['radiusSize']
}
export const CardImage = twc.img.attrs<CardImageProps>({
style: { minHeight: 170 },
})((props) => [
classesPerRadiusSize[props.radiusSize ?? 'normal'],
`block width-full background-shade-60 transition`,
])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment