import { Box, Button, Fade, Flex, IconButton, Stack } from '@chakra-ui/react' import { TrashIcon, PlusIcon } from 'assets/icons' import { dequal } from 'dequal' import { Draft } from 'immer' import React, { useEffect, useState } from 'react' import { generate } from 'short-uuid' import { useImmer } from 'use-immer' type ItemWithId = T & { id: string } export type TableListItemProps = { item: T debounceTimeout?: number onItemChange: (item: T) => void } type Props = { initialItems: ItemWithId[] addLabel?: string debounceTimeout?: number onItemsChange: (items: ItemWithId[]) => void Item: (props: TableListItemProps) => JSX.Element ComponentBetweenItems?: (props: unknown) => JSX.Element } export const TableList = ({ initialItems, onItemsChange, addLabel = 'Add', debounceTimeout, Item, ComponentBetweenItems = () => <>, }: Props) => { const [items, setItems] = useImmer(initialItems) const [showDeleteIndex, setShowDeleteIndex] = useState(null) useEffect(() => { if (dequal(items, initialItems)) return onItemsChange(items) // eslint-disable-next-line react-hooks/exhaustive-deps }, [items]) const createItem = () => { setItems((items) => { const id = generate() const newItem = { id } as Draft> items.push(newItem) }) } const updateItem = (itemIndex: number, updates: Partial) => setItems((items) => { items[itemIndex] = { ...items[itemIndex], ...updates } }) const deleteItem = (itemIndex: number) => () => { setItems((items) => { items.splice(itemIndex, 1) }) } const handleMouseEnter = (itemIndex: number) => () => setShowDeleteIndex(itemIndex) const handleCellChange = (itemIndex: number) => (item: T) => updateItem(itemIndex, item) const handleMouseLeave = () => setShowDeleteIndex(null) return ( {items.map((item, itemIndex) => ( {itemIndex !== 0 && } } aria-label="Remove cell" onClick={deleteItem(itemIndex)} pos="absolute" left="-15px" top="-15px" size="sm" shadow="md" /> ))} ) }