Files
ncd-fe/packages/pl-fe/src/components/list.tsx
nicole mikołajczyk a80bb6d938 pl-fe: change import alias so it won't change on each project rename
Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>
2026-02-07 22:41:47 +01:00

106 lines
2.7 KiB
TypeScript

import { Link, type LinkOptions } from '@tanstack/react-router';
import clsx from 'clsx';
import React, { useState } from 'react';
import HStack from '@/components/ui/hstack';
import Icon from '@/components/ui/icon';
import Select from '@/components/ui/select';
import { SelectDropdown } from '@/features/forms';
interface IList {
children: React.ReactNode;
}
const List: React.FC<IList> = ({ children }) => (
<div className='⁂-list'>{children}</div>
);
type IListItem = {
className?: string;
label: React.ReactNode;
hint?: React.ReactNode;
href?: string;
onClick?(): void;
isSelected?: boolean;
children?: React.ReactNode;
size?: 'sm' | 'md';
} & (LinkOptions | {});
const ListItem: React.FC<IListItem> = ({ className, label, hint, children, href, onClick, isSelected, size = 'md', ...rest }) => {
const [domId] = useState(`list-group-${crypto.randomUUID()}`);
const onKeyDown = (e: React.KeyboardEvent) => {
if (e.key === 'Enter') {
onClick!();
}
};
const LabelComp = 'to' in rest || href || onClick ? 'span' : 'label';
const renderChildren = React.useCallback(() => React.Children.map(children, (child) => {
if (React.isValidElement(child)) {
const isSelect = child.type === SelectDropdown || child.type === Select;
return React.cloneElement(child, {
// @ts-ignore
id: domId,
className: clsx({
'w-auto': isSelect,
}, child.props.className),
});
}
return null;
}), [children, domId]);
const classNames = clsx('⁂-list-item',
className,
{
'⁂-list-item--md': size === 'md',
'⁂-list-item--sm': size === 'sm',
},
);
const body = (
<>
<div className='⁂-list-item__label'>
<LabelComp htmlFor={domId}>{label}</LabelComp>
{hint ? (
<span className='⁂-list-item__hint'>{hint}</span>
) : null}
</div>
{('to' in rest || href || onClick) ? (
<HStack space={1} alignItems='center' className='⁂-list-item__body'>
{children}
<Icon src={require('@phosphor-icons/core/regular/caret-right.svg')} />
</HStack>
) : null}
{!('to' in rest) && typeof onClick === 'undefined' ? renderChildren() : null}
</>
);
if ('to' in rest) return (
<Link className={classNames} {...rest}>
{body}
</Link>
);
const Comp = onClick || href ? 'a' : 'div';
const linkProps = onClick || href ? { onClick, onKeyDown, tabIndex: 0, role: 'link', ...(href && { href, target: '_blank' }) } : {};
return (
<Comp
className={classNames}
{...linkProps}
>
{body}
</Comp>
);
};
export { List as default, type IListItem, ListItem };