import React, { memo } from "react"; import styled, { css } from "styled-components"; import { useItemActions, useItemInteraction, useWire } from "react-sync-board"; import { opacify } from "color2k"; import { media2Url } from "../mediaLibrary"; import { isItemInsideElement, getItemElement } from "../utils"; const BagWrapper = styled.div` ${({ width, height, labelBackgroundColor = "#cccccc33", }) => css` width: ${width}px; height: ${height}px; position: relative; & .bag__label { font-size: 1.5em; user-select: none; background-color: ${opacify(labelBackgroundColor, 1)}; position: absolute; border-radius: 0.5em; color: var(--color-darkGrey); } & .bag__label.left { padding: 1em 0em; top: 1em; left: -1em; letter-spacing: -3px; writing-mode: vertical-rl; text-orientation: upright; } & .bag__label.top { padding: 0em 1em; top: -1em; left: 1em; } `} `; const BagImage = styled.img` transition: opacity 300ms; pointer-events: none; display: ${({ visible }) => (visible ? 'block' : 'none')}; `; const ItemCounter = styled.div` position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: ${({ counterSize }) => `${counterSize}px`} `; const Bag = ({ families, storedItems = [], label, width, height, bagImage = "/bag.png", emptyBagImage = "/bag_empty.png", labelPosition = "left", countersize = 50, countervisible = true, labelBackgroundColor = "#cccccc33", id, setState, }) => { const { isMaster } = useWire("board"); const { register } = useItemInteraction("place"); const { pushItem, getItems, batchUpdateItems, removeItems, } = useItemActions(); const bagRef = React.useRef(null); const noFamilies = !Array.isArray(families) || families.length === 0; const imageContent = media2Url(bagImage) || "/bag.png"; const emptyImageContent = media2Url(emptyBagImage) || "/bag_empty.png"; const size = {}; if (width) { size.width = width; } if (height) { size.height = height; } const onInsideItem = React.useCallback( async (itemIds) => { const items = await getItems(itemIds); const insideItems = items .filter((item) => noFamilies || families.includes(item.groupId)) .filter(({ id: itemId }) => // Skip the container itself. itemId !== id && isItemInsideElement(getItemElement(itemId), bagRef.current) ) .map(({ id }) => id); if (!insideItems.length) return; const newItems = await getItems(insideItems); await removeItems(newItems.map(item => item.id)); storedItems = newItems.concat(storedItems); setState((prevState) => ({ ...prevState, storedItems: storedItems, })); }, [families, storedItems, id, setState, getItems, removeItems] ); const onExtract = React.useCallback( async () => { const [bag] = await getItems([id]); storedItems = [...storedItems]; const item = storedItems.shift(); if (item) { setState((prevState) => ({ ...prevState, storedItems: storedItems, })); await pushItem({ ...item, x: bag.x + bagRef.current.clientWidth / 3.0, y: bag.y + bagRef.current.clientHeight / 3.0, }); } }, [id, bagRef, storedItems, setState, pushItem] ); const extract = (e) => { e.stopPropagation(); onExtract(); } React.useEffect(() => { const unregisterList = []; unregisterList.push(register(onInsideItem)); return () => { unregisterList.forEach((callback) => callback()); }; }, [onInsideItem, register]); return ( {countervisible && ({storedItems.length})}
{label}
); }; export default memo(Bag);