import { Group } from "react-konva"; import { Map, MapToolId } from "../types/Map"; import { MapState } from "../types/MapState"; import { TokenCategory, TokenDraggingOptions, TokenMenuOptions, } from "../types/Token"; import { TokenState } from "../types/TokenState"; import { TokenStateRemoveHandler, TokenStateChangeEventHandler, } from "../types/Events"; import { useState } from "react"; import Konva from "konva"; import Token from "../components/konva/Token"; import { KonvaEventObject } from "konva/lib/Node"; import TokenMenu from "../components/token/TokenMenu"; import TokenDragOverlay from "../components/token/TokenDragOverlay"; function useMapTokens( map: Map | null, mapState: MapState | null, onTokenStateChange: TokenStateChangeEventHandler, onTokenStateRemove: TokenStateRemoveHandler, selectedToolId: MapToolId, disabledTokens: Record ) { const [isTokenMenuOpen, setIsTokenMenuOpen] = useState(false); const [tokenMenuOptions, setTokenMenuOptions] = useState(); const [tokenDraggingOptions, setTokenDraggingOptions] = useState(); function handleTokenMenuOpen(tokenStateId: string, tokenImage: Konva.Node) { setTokenMenuOptions({ tokenStateId, tokenImage }); setIsTokenMenuOpen(true); } function handleTokenDragStart( event: KonvaEventObject, tokenStateId: string ) { setTokenDraggingOptions({ dragging: true, tokenStateId, tokenNode: event.target, }); } function handleTokenDragEnd() { tokenDraggingOptions && setTokenDraggingOptions({ ...tokenDraggingOptions, dragging: false, }); } function handleTokenStateRemove(tokenState: TokenState) { onTokenStateRemove(tokenState); setTokenDraggingOptions(undefined); } const tokens = map && mapState && ( {Object.values(mapState.tokens) .sort((a, b) => sortMapTokenStates(a, b, tokenDraggingOptions)) .map((tokenState) => ( ))} ); const tokenMenu = ( setIsTokenMenuOpen(false)} onTokenStateChange={onTokenStateChange} tokenState={ tokenMenuOptions && mapState?.tokens[tokenMenuOptions.tokenStateId] } tokenImage={tokenMenuOptions?.tokenImage} map={map} /> ); const tokenDraggingState = tokenDraggingOptions && mapState?.tokens[tokenDraggingOptions.tokenStateId]; const tokenDragOverlay = tokenDraggingOptions && tokenDraggingState && ( ); return { tokens, tokenMenu, tokenDragOverlay }; } export default useMapTokens; function getMapTokenCategoryWeight(category: TokenCategory) { switch (category) { case "character": return 0; case "vehicle": return 1; case "prop": return 2; default: return 0; } } // Sort so vehicles render below other tokens function sortMapTokenStates( a: TokenState, b: TokenState, tokenDraggingOptions?: TokenDraggingOptions ) { // If categories are different sort in order "prop", "vehicle", "character" if (b.category !== a.category) { const aWeight = getMapTokenCategoryWeight(a.category); const bWeight = getMapTokenCategoryWeight(b.category); return bWeight - aWeight; } else if ( tokenDraggingOptions && tokenDraggingOptions.dragging && tokenDraggingOptions.tokenStateId === a.id ) { // If dragging token a move above return 1; } else if ( tokenDraggingOptions && tokenDraggingOptions.dragging && tokenDraggingOptions.tokenStateId === b.id ) { // If dragging token b move above return -1; } else { // Else sort so last modified is on top return a.lastModified - b.lastModified; } }