99 lines
2.5 KiB
TypeScript
99 lines
2.5 KiB
TypeScript
import classNames from 'classnames';
|
|
import { Link } from 'react-router-dom';
|
|
|
|
import { polymorphicForwardRef } from '@/types/polymorphic';
|
|
|
|
import classes from './styles.module.scss';
|
|
|
|
interface WrapperProps extends Omit<
|
|
React.ComponentPropsWithoutRef<'div'>,
|
|
'title'
|
|
> {
|
|
icon?: React.ReactNode;
|
|
sideContent?: React.ReactNode;
|
|
}
|
|
|
|
/**
|
|
* A basic list item component that can be used as a base for more bespoke list items.
|
|
*
|
|
* Choose the child of the wrapper component based on needed interactivity:
|
|
* `ListItemContent` for a non-interactive item, `ListItemButton` or `ListItemLink`
|
|
* for interactive items.
|
|
*/
|
|
export const ListItemWrapper: React.FC<WrapperProps> = ({
|
|
icon,
|
|
sideContent,
|
|
children,
|
|
className,
|
|
...otherProps
|
|
}) => {
|
|
return (
|
|
<div {...otherProps} className={classNames(classes.wrapper, className)}>
|
|
{icon}
|
|
<div className={classes.main}>{children}</div>
|
|
{sideContent && (
|
|
<span className={classes.sideContent}>{sideContent}</span>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
interface ContentProps {
|
|
subtitle?: React.ReactNode;
|
|
subtitleId?: string;
|
|
}
|
|
|
|
export const ListItemContent = polymorphicForwardRef<'h3', ContentProps>(
|
|
(
|
|
{ as: Component = 'h3', subtitle, subtitleId, children, ...otherProps },
|
|
ref,
|
|
) => {
|
|
return (
|
|
<>
|
|
<Component className={classes.title} ref={ref} {...otherProps}>
|
|
{children}
|
|
</Component>
|
|
{subtitle && (
|
|
<div className={classes.subtitle} id={subtitleId}>
|
|
{subtitle}
|
|
</div>
|
|
)}
|
|
</>
|
|
);
|
|
},
|
|
);
|
|
|
|
interface LinkProps
|
|
extends React.ComponentPropsWithoutRef<typeof Link>, ContentProps {}
|
|
|
|
export const ListItemLink = polymorphicForwardRef<'h3', LinkProps>(
|
|
({ as, subtitle, children, className, ...otherProps }, ref) => {
|
|
return (
|
|
<ListItemContent ref={ref} as={as} subtitle={subtitle}>
|
|
<Link className={classNames(className, 'focusable')} {...otherProps}>
|
|
{children}
|
|
</Link>
|
|
</ListItemContent>
|
|
);
|
|
},
|
|
);
|
|
|
|
interface ButtonProps
|
|
extends React.ComponentPropsWithoutRef<'button'>, ContentProps {}
|
|
|
|
export const ListItemButton = polymorphicForwardRef<'h3', ButtonProps>(
|
|
({ as, subtitle, children, className, ...otherProps }, ref) => {
|
|
return (
|
|
<ListItemContent as={as} ref={ref} subtitle={subtitle}>
|
|
<button
|
|
type='button'
|
|
className={classNames(className, 'focusable')}
|
|
{...otherProps}
|
|
>
|
|
{children}
|
|
</button>
|
|
</ListItemContent>
|
|
);
|
|
},
|
|
);
|