Skip to content

Instantly share code, notes, and snippets.

@3cL1p5e7
Last active October 18, 2022 19:49
Show Gist options
  • Save 3cL1p5e7/04bb6d2a6133e7bfa5bf1b8302e8017d to your computer and use it in GitHub Desktop.
Save 3cL1p5e7/04bb6d2a6133e7bfa5bf1b8302e8017d to your computer and use it in GitHub Desktop.
import React from 'react';
import { cn } from '@bem-react/classname';
// Суть в том, что ListItem с дополнительной UI логикой типа disabled пригодится в будущем еще много где
// И в будущем ляжет в UIKIT
const cls = cn('list-item');
export interface ListItemProps<T extends keyof React.ReactHTML = 'li'>
extends Omit<React.HTMLAttributes<T>, 'onClick'> {
disabled?: boolean;
as?: T;
onClick?(id: string, e: React.MouseEvent<T>): void;
}
export const ListItem = <T extends keyof React.ReactHTML = 'li'>({
as = 'li',
children,
className, // вложен в React.HTMLAttributes<T>
disabled,
...props
}: ListItemProps<T>) =>
React.createElement(
as,
{ className: cls({ disabled }, [className]), disabled, ...props },
children,
);
import React from 'react';
import { cn } from '@bem-react/classname';
import { ListItem, ListItemProps } from './ListItem';
const classname = cn('order');
export interface OrderProps extends ListItemProps {
order: IOrder;
}
// спорный нейминг через I, но тут как раз кстати
// этот интерфейс должен быть импортирован из папки domain, содержащей все интерфейсы модели данных
//
// либо это должен быть интерфейс локальной UI репрезентации Order, как его понимает текущий UI компонент
// и тогда ему тут самое место, но он необязательно будет соотвествовать интерфейсу Order, полученному с сервера
export interface IOrder {
id: string;
name: string;
}
export const Order = ({ className, order, disabled, ...props }: OrderProps) => (
<ListItem className={classname({ disabled }, [className])} disabled={disabled} {...props}>
{order.name}
</ListItem>
);
import React from 'react';
import { cn } from '@bem-react/classname';
import { Order, IOrder } from './Order';
const classname = cn('orders-list');
export interface OrderListProps {
className?: string;
style?: React.CSSProperties;
orders: IOrder[];
disabledIds?: string[];
onClick(id: string): void;
}
export const OrdersList = ({ className = '', style, orders, onClick, disabledIds = [] }: OrderListProps) => {
const disabledSet = React.useMemo(
() => new Set(disabledIds), // тк сложность метода has() равна O(1)
[disabledIds],
);
return (
<ul className={classname({}, [className])} style={style}>
{orders.map((order) => (
<Order
key={order.id}
className={classname('order', {
/* shifted: true, // place for your mods if needed */
})}
// моды будут использоваться только в случае, если влияют на верстку списка, а не элемента (как было в условии)
// Например: пусть мод shifted указывает на сдвиг по горизонтали в вертикальном списке. Тогда ему тут самое место
disabled={disabledSet.has(order.id)}
// disabled должно быть свойством компонента, а не стилем сверху (как и highlighted, muted, blured и тд)
// тк компонент должен сам реализовать поведение disabled исходя из его внутренней структуры,
// которая снаружи, вообще говоря, неизвестна
order={order}
onClick={onClick} // API компонента должно предоставлять любые хэндлеры с id на манер MaterialUI
/>
))}
</ul>
);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment