Add back tile search and action bar

This commit is contained in:
Mitchell McCaffrey 2021-06-05 16:38:01 +10:00
parent d6b6d6a1eb
commit e3353c1c44
11 changed files with 161 additions and 83 deletions

View File

@ -20,18 +20,10 @@ function MapEditBar({ currentMap, disabled, onMapChange, onMapReset, onLoad }) {
const { maps, mapStates, removeMaps, resetMap } = useMapData(); const { maps, mapStates, removeMaps, resetMap } = useMapData();
const { const { activeGroups, selectedGroupIds, onGroupSelect } = useGroup();
groups: allGroups,
selectedGroupIds,
onGroupSelect,
openGroupId,
openGroupItems,
} = useGroup();
const groups = openGroupId ? openGroupItems : allGroups;
useEffect(() => { useEffect(() => {
const selectedGroups = groupsFromIds(selectedGroupIds, groups); const selectedGroups = groupsFromIds(selectedGroupIds, activeGroups);
const selectedMaps = itemsFromGroups(selectedGroups, maps); const selectedMaps = itemsFromGroups(selectedGroups, maps);
const selectedMapStates = itemsFromGroups( const selectedMapStates = itemsFromGroups(
selectedGroups, selectedGroups,
@ -57,10 +49,10 @@ function MapEditBar({ currentMap, disabled, onMapChange, onMapReset, onLoad }) {
} }
setHasMapState(_hasMapState); setHasMapState(_hasMapState);
}, [selectedGroupIds, maps, mapStates, groups]); }, [selectedGroupIds, maps, mapStates, activeGroups]);
function getSelectedMaps() { function getSelectedMaps() {
const selectedGroups = groupsFromIds(selectedGroupIds, groups); const selectedGroups = groupsFromIds(selectedGroupIds, activeGroups);
return itemsFromGroups(selectedGroups, maps); return itemsFromGroups(selectedGroups, maps);
} }

View File

@ -6,18 +6,11 @@ import { useGroup } from "../../contexts/GroupContext";
import { findGroup } from "../../helpers/group"; import { findGroup } from "../../helpers/group";
function SelectMapSelectButton({ onMapSelect, disabled }) { function SelectMapSelectButton({ onMapSelect, disabled }) {
const { const { activeGroups, selectedGroupIds } = useGroup();
groups: allGroups,
selectedGroupIds,
openGroupId,
openGroupItems,
} = useGroup();
const groups = openGroupId ? openGroupItems : allGroups;
function handleSelectClick() { function handleSelectClick() {
if (selectedGroupIds.length === 1) { if (selectedGroupIds.length === 1) {
const group = findGroup(groups, selectedGroupIds[0]); const group = findGroup(activeGroups, selectedGroupIds[0]);
if (group && group.type === "item") { if (group && group.type === "item") {
onMapSelect(group.id); onMapSelect(group.id);
} }

View File

@ -22,7 +22,7 @@ function SortableTile({
setDraggableNodeRef, setDraggableNodeRef,
over, over,
active, active,
} = useSortable({ id, disabled: disableSorting }); } = useSortable({ id });
const { setNodeRef: setGroupNodeRef } = useDroppable({ const { setNodeRef: setGroupNodeRef } = useDroppable({
id: `${GROUP_ID_PREFIX}${id}`, id: `${GROUP_ID_PREFIX}${id}`,
@ -42,7 +42,7 @@ function SortableTile({
width: "2px", width: "2px",
height: "100%", height: "100%",
borderRadius: "2px", borderRadius: "2px",
visibility: over?.id === id ? "visible" : "hidden", visibility: over?.id === id && !disableSorting ? "visible" : "hidden",
}; };
// Group div center aligned // Group div center aligned

View File

@ -22,22 +22,29 @@ import { useGroup } from "../../contexts/GroupContext";
function SortableTiles({ renderTile, subgroup }) { function SortableTiles({ renderTile, subgroup }) {
const { dragId, overId, dragCursor } = useTileDrag(); const { dragId, overId, dragCursor } = useTileDrag();
const { const {
groups: allGroups, groups,
selectedGroupIds: allSelectedIds, selectedGroupIds: allSelectedIds,
filter,
openGroupId, openGroupId,
openGroupItems, openGroupItems,
filteredGroupItems,
} = useGroup(); } = useGroup();
const activeGroups = subgroup
? openGroupItems
: filter
? filteredGroupItems
: groups;
const sortableId = subgroup ? GROUP_SORTABLE_ID : BASE_SORTABLE_ID; const sortableId = subgroup ? GROUP_SORTABLE_ID : BASE_SORTABLE_ID;
const groups = subgroup ? openGroupItems : allGroups;
// Only populate selected groups if needed // Only populate selected groups if needed
let selectedGroupIds = []; let selectedGroupIds = [];
if ((subgroup && openGroupId) || (!subgroup && !openGroupId)) { if ((subgroup && openGroupId) || (!subgroup && !openGroupId)) {
selectedGroupIds = allSelectedIds; selectedGroupIds = allSelectedIds;
} }
const disableSorting = openGroupId && !subgroup; const disableSorting = (openGroupId && !subgroup) || filter;
const disableGrouping = subgroup || disableSorting; const disableGrouping = subgroup || disableSorting || filter;
const dragBounce = useSpring({ const dragBounce = useSpring({
transform: !!dragId ? "scale(0.9)" : "scale(1)", transform: !!dragId ? "scale(0.9)" : "scale(1)",
@ -63,9 +70,9 @@ function SortableTiles({ renderTile, subgroup }) {
function renderDragOverlays() { function renderDragOverlays() {
let selectedIndices = selectedGroupIds.map((groupId) => let selectedIndices = selectedGroupIds.map((groupId) =>
groups.findIndex((group) => group.id === groupId) activeGroups.findIndex((group) => group.id === groupId)
); );
const activeIndex = groups.findIndex((group) => group.id === dragId); const activeIndex = activeGroups.findIndex((group) => group.id === dragId);
// Sort so the draging tile is the first element // Sort so the draging tile is the first element
selectedIndices = selectedIndices.sort((a, b) => selectedIndices = selectedIndices.sort((a, b) =>
a === activeIndex ? -1 : b === activeIndex ? 1 : 0 a === activeIndex ? -1 : b === activeIndex ? 1 : 0
@ -81,7 +88,7 @@ function SortableTiles({ renderTile, subgroup }) {
selectedIndices = selectedIndices.reverse(); selectedIndices = selectedIndices.reverse();
coords = coords.reverse(); coords = coords.reverse();
const selectedGroups = selectedIndices.map((index) => groups[index]); const selectedGroups = selectedIndices.map((index) => activeGroups[index]);
return selectedGroups.map((group, index) => ( return selectedGroups.map((group, index) => (
<DragOverlay dropAnimation={null} key={group.id}> <DragOverlay dropAnimation={null} key={group.id}>
@ -113,7 +120,7 @@ function SortableTiles({ renderTile, subgroup }) {
} }
function renderTiles() { function renderTiles() {
const groupsByIds = keyBy(groups, "id"); const groupsByIds = keyBy(activeGroups, "id");
const selectedGroupIdsSet = new Set(selectedGroupIds); const selectedGroupIdsSet = new Set(selectedGroupIds);
let selectedGroups = []; let selectedGroups = [];
let hasSelectedContainerGroup = false; let hasSelectedContainerGroup = false;
@ -126,7 +133,7 @@ function SortableTiles({ renderTile, subgroup }) {
} }
} }
} }
return groups.map((group) => { return activeGroups.map((group) => {
const isDragging = dragId && selectedGroupIdsSet.has(group.id); const isDragging = dragId && selectedGroupIdsSet.has(group.id);
const disableTileGrouping = const disableTileGrouping =
disableGrouping || isDragging || hasSelectedContainerGroup; disableGrouping || isDragging || hasSelectedContainerGroup;
@ -147,7 +154,7 @@ function SortableTiles({ renderTile, subgroup }) {
} }
return ( return (
<SortableContext items={groups} id={sortableId}> <SortableContext items={activeGroups} id={sortableId}>
{renderTiles()} {renderTiles()}
{createPortal(dragId && renderDragOverlays(), document.body)} {createPortal(dragId && renderDragOverlays(), document.body)}
</SortableContext> </SortableContext>

View File

@ -1,22 +1,24 @@
import React from "react"; import React from "react";
import { Flex, IconButton } from "theme-ui"; import { Flex, IconButton } from "theme-ui";
import AddIcon from "../icons/AddIcon"; import AddIcon from "../../icons/AddIcon";
import SelectMultipleIcon from "../icons/SelectMultipleIcon"; import SelectMultipleIcon from "../../icons/SelectMultipleIcon";
import SelectSingleIcon from "../icons/SelectSingleIcon"; import SelectSingleIcon from "../../icons/SelectSingleIcon";
import Search from "./Search"; import Search from "../Search";
import RadioIconButton from "./RadioIconButton"; import RadioIconButton from "../RadioIconButton";
import { useGroup } from "../../contexts/GroupContext";
function TileActionBar({ onAdd, addTitle }) {
const {
selectMode,
onSelectModeChange,
onGroupSelect,
filter,
onFilterChange,
} = useGroup();
function FilterBar({
onFocus,
search,
onSearchChange,
selectMode,
onSelectModeChange,
onAdd,
addTitle,
}) {
return ( return (
<Flex <Flex
bg="muted" bg="muted"
@ -31,9 +33,9 @@ function FilterBar({
outlineOffset: "0px", outlineOffset: "0px",
}, },
}} }}
onFocus={onFocus} onFocus={() => onGroupSelect()}
> >
<Search value={search} onChange={onSearchChange} /> <Search value={filter} onChange={(e) => onFilterChange(e.target.value)} />
<Flex <Flex
mr={1} mr={1}
px={1} px={1}
@ -66,4 +68,4 @@ function FilterBar({
); );
} }
export default FilterBar; export default TileActionBar;

View File

@ -18,31 +18,23 @@ import shortcuts from "../../shortcuts";
function TokenEditBar({ disabled, onLoad }) { function TokenEditBar({ disabled, onLoad }) {
const { tokens, removeTokens, updateTokensHidden } = useTokenData(); const { tokens, removeTokens, updateTokensHidden } = useTokenData();
const { const { activeGroups, selectedGroupIds, onGroupSelect } = useGroup();
groups: allGroups,
selectedGroupIds,
onGroupSelect,
openGroupId,
openGroupItems,
} = useGroup();
const groups = openGroupId ? openGroupItems : allGroups;
const [hasSelectedDefaultToken, setHasSelectedDefaultToken] = useState(false); const [hasSelectedDefaultToken, setHasSelectedDefaultToken] = useState(false);
const [allTokensVisible, setAllTokensVisisble] = useState(false); const [allTokensVisible, setAllTokensVisisble] = useState(false);
useEffect(() => { useEffect(() => {
const selectedGroups = groupsFromIds(selectedGroupIds, groups); const selectedGroups = groupsFromIds(selectedGroupIds, activeGroups);
const selectedTokens = itemsFromGroups(selectedGroups, tokens); const selectedTokens = itemsFromGroups(selectedGroups, tokens);
setHasSelectedDefaultToken( setHasSelectedDefaultToken(
selectedTokens.some((token) => token.type === "default") selectedTokens.some((token) => token.type === "default")
); );
setAllTokensVisisble(selectedTokens.every((token) => !token.hideInSidebar)); setAllTokensVisisble(selectedTokens.every((token) => !token.hideInSidebar));
}, [selectedGroupIds, tokens, groups]); }, [selectedGroupIds, tokens, activeGroups]);
function getSelectedTokens() { function getSelectedTokens() {
const selectedGroups = groupsFromIds(selectedGroupIds, groups); const selectedGroups = groupsFromIds(selectedGroupIds, activeGroups);
return itemsFromGroups(selectedGroups, tokens); return itemsFromGroups(selectedGroups, tokens);
} }

View File

@ -1,5 +1,6 @@
import React, { useState, useContext, useEffect } from "react"; import React, { useState, useContext, useEffect } from "react";
import cloneDeep from "lodash.clonedeep"; import cloneDeep from "lodash.clonedeep";
import Fuse from "fuse.js";
import { useKeyboard, useBlur } from "./KeyboardContext"; import { useKeyboard, useBlur } from "./KeyboardContext";
@ -11,17 +12,18 @@ const GroupContext = React.createContext();
export function GroupProvider({ export function GroupProvider({
groups, groups,
itemNames,
onGroupsChange, onGroupsChange,
onGroupsSelect, onGroupsSelect,
disabled, disabled,
children, children,
}) { }) {
const [selectedGroupIds, setSelectedGroupIds] = useState([]); const [selectedGroupIds, setSelectedGroupIds] = useState([]);
const [openGroupId, setOpenGroupId] = useState();
const [openGroupItems, setOpenGroupItems] = useState([]);
// Either single, multiple or range // Either single, multiple or range
const [selectMode, setSelectMode] = useState("single"); const [selectMode, setSelectMode] = useState("single");
const [openGroupId, setOpenGroupId] = useState();
const [openGroupItems, setOpenGroupItems] = useState([]);
useEffect(() => { useEffect(() => {
if (openGroupId) { if (openGroupId) {
setOpenGroupItems(getGroupItems(groupsFromIds([openGroupId], groups)[0])); setOpenGroupItems(getGroupItems(groupsFromIds([openGroupId], groups)[0]));
@ -117,16 +119,58 @@ export function GroupProvider({
useBlur(handleBlur); useBlur(handleBlur);
/**
* Search
*/
const [filter, setFilter] = useState();
const [filteredGroupItems, setFilteredGroupItems] = useState([]);
const [fuse, setFuse] = useState();
// Update search index when items change
useEffect(() => {
let items = [];
for (let group of groups) {
const itemsToAdd = getGroupItems(group);
const namedItems = itemsToAdd.map((item) => ({
...item,
name: itemNames[item.id],
}));
items.push(...namedItems);
}
setFuse(new Fuse(items, { keys: ["name"] }));
}, [groups, itemNames]);
// Perform search when search changes
useEffect(() => {
if (filter) {
const query = fuse.search(filter);
setFilteredGroupItems(query.map((result) => result.item));
setOpenGroupId();
} else {
setFilteredGroupItems([]);
}
}, [filter, fuse]);
const activeGroups = openGroupId
? openGroupItems
: filter
? filteredGroupItems
: groups;
const value = { const value = {
groups, groups,
activeGroups,
openGroupId, openGroupId,
openGroupItems, openGroupItems,
filter,
filteredGroupItems,
selectedGroupIds, selectedGroupIds,
selectMode, selectMode,
onSelectModeChange: setSelectMode,
onGroupOpen: handleGroupOpen, onGroupOpen: handleGroupOpen,
onGroupClose: handleGroupClose, onGroupClose: handleGroupClose,
onGroupsChange: handleGroupsChange, onGroupsChange: handleGroupsChange,
onGroupSelect: handleGroupSelect, onGroupSelect: handleGroupSelect,
onFilterChange: setFilter,
}; };
return ( return (
@ -136,6 +180,7 @@ export function GroupProvider({
GroupProvider.defaultProps = { GroupProvider.defaultProps = {
groups: [], groups: [],
itemNames: {},
onGroupsChange: () => {}, onGroupsChange: () => {},
onGroupsSelect: () => {}, onGroupsSelect: () => {},
disabled: false, disabled: false,

View File

@ -23,19 +23,16 @@ export const ADD_TO_MAP_ID_PREFIX = "__add__";
export function TileDragProvider({ onDragAdd, children }) { export function TileDragProvider({ onDragAdd, children }) {
const { const {
groups: allGroups, groups,
activeGroups,
openGroupId, openGroupId,
openGroupItems,
selectedGroupIds, selectedGroupIds,
onGroupsChange, onGroupsChange,
onGroupSelect, onGroupSelect,
onGroupClose, onGroupClose,
filter,
} = useGroup(); } = useGroup();
const groupOpen = !!openGroupId;
const groups = groupOpen ? openGroupItems : allGroups;
const mouseSensor = useSensor(MouseSensor, { const mouseSensor = useSensor(MouseSensor, {
activationConstraint: { delay: 250, tolerance: 5 }, activationConstraint: { delay: 250, tolerance: 5 },
}); });
@ -83,7 +80,7 @@ export function TileDragProvider({ onDragAdd, children }) {
} }
let selectedIndices = selectedGroupIds.map((groupId) => let selectedIndices = selectedGroupIds.map((groupId) =>
groups.findIndex((group) => group.id === groupId) activeGroups.findIndex((group) => group.id === groupId)
); );
// Maintain current group sorting // Maintain current group sorting
selectedIndices = selectedIndices.sort((a, b) => a - b); selectedIndices = selectedIndices.sort((a, b) => a - b);
@ -96,15 +93,17 @@ export function TileDragProvider({ onDragAdd, children }) {
return; return;
} }
const overGroupIndex = groups.findIndex((group) => group.id === overId); const overGroupIndex = activeGroups.findIndex(
(group) => group.id === overId
);
onGroupsChange( onGroupsChange(
moveGroupsInto(groups, overGroupIndex, selectedIndices), moveGroupsInto(activeGroups, overGroupIndex, selectedIndices),
openGroupId openGroupId
); );
} else if (over.id.startsWith(UNGROUP_ID_PREFIX)) { } else if (over.id.startsWith(UNGROUP_ID_PREFIX)) {
onGroupSelect(); onGroupSelect();
// Handle tile ungroup // Handle tile ungroup
const newGroups = ungroup(allGroups, openGroupId, selectedIndices); const newGroups = ungroup(groups, openGroupId, selectedIndices);
// Close group if it was removed // Close group if it was removed
if (!newGroups.find((group) => group.id === openGroupId)) { if (!newGroups.find((group) => group.id === openGroupId)) {
onGroupClose(); onGroupClose();
@ -112,11 +111,13 @@ export function TileDragProvider({ onDragAdd, children }) {
onGroupsChange(newGroups); onGroupsChange(newGroups);
} else if (over.id.startsWith(ADD_TO_MAP_ID_PREFIX)) { } else if (over.id.startsWith(ADD_TO_MAP_ID_PREFIX)) {
onDragAdd && onDragAdd(selectedGroupIds, over.rect); onDragAdd && onDragAdd(selectedGroupIds, over.rect);
} else { } else if (!filter) {
// Hanlde tile move // Hanlde tile move only if we have no filter
const overGroupIndex = groups.findIndex((group) => group.id === over.id); const overGroupIndex = activeGroups.findIndex(
(group) => group.id === over.id
);
onGroupsChange( onGroupsChange(
moveGroups(groups, overGroupIndex, selectedIndices), moveGroups(activeGroups, overGroupIndex, selectedIndices),
openGroupId openGroupId
); );
} }
@ -124,7 +125,7 @@ export function TileDragProvider({ onDragAdd, children }) {
function customCollisionDetection(rects, rect) { function customCollisionDetection(rects, rect) {
// Handle group rects // Handle group rects
if (groupOpen) { if (openGroupId) {
const ungroupRects = rects.filter(([id]) => const ungroupRects = rects.filter(([id]) =>
id.startsWith(UNGROUP_ID_PREFIX) id.startsWith(UNGROUP_ID_PREFIX)
); );

View File

@ -208,3 +208,16 @@ export function findGroup(groups, groupId) {
} }
} }
} }
/**
* Transform and item array to a record of item ids to item names
* @param {any[]} items
* @param {string=} itemKey
*/
export function getItemNames(items, itemKey = "id") {
let names = {};
for (let item of items) {
names[item[itemKey]] = item.name;
}
return names;
}

View File

@ -1,4 +1,4 @@
import React, { useRef, useState } from "react"; import React, { useRef, useState, useEffect } from "react";
import { Flex, Label, Box } from "theme-ui"; import { Flex, Label, Box } from "theme-ui";
import { useToasts } from "react-toast-notifications"; import { useToasts } from "react-toast-notifications";
import ReactResizeDetector from "react-resize-detector"; import ReactResizeDetector from "react-resize-detector";
@ -17,8 +17,9 @@ import SelectMapSelectButton from "../components/map/SelectMapSelectButton";
import TilesOverlay from "../components/tile/TilesOverlay"; import TilesOverlay from "../components/tile/TilesOverlay";
import TilesContainer from "../components/tile/TilesContainer"; import TilesContainer from "../components/tile/TilesContainer";
import TilesAddDroppable from "../components/tile/TilesAddDroppable"; import TilesAddDroppable from "../components/tile/TilesAddDroppable";
import TileActionBar from "../components/tile/TileActionBar";
import { findGroup } from "../helpers/group"; import { findGroup, getItemNames } from "../helpers/group";
import { createMapFromFile } from "../helpers/map"; import { createMapFromFile } from "../helpers/map";
import useResponsiveLayout from "../hooks/useResponsiveLayout"; import useResponsiveLayout from "../hooks/useResponsiveLayout";
@ -54,6 +55,12 @@ function SelectMapModal({
} = useMapData(); } = useMapData();
const { addAssets } = useAssets(); const { addAssets } = useAssets();
// Get map names for group filtering
const [mapNames, setMapNames] = useState(getItemNames(maps));
useEffect(() => {
setMapNames(getItemNames(maps));
}, [maps]);
/** /**
* Image Upload * Image Upload
*/ */
@ -102,6 +109,12 @@ function SelectMapModal({
} }
} }
function openImageDialog() {
if (fileInputRef.current) {
fileInputRef.current.click();
}
}
function handleLargeImageWarningCancel() { function handleLargeImageWarningCancel() {
largeImageWarningFiles.current = undefined; largeImageWarningFiles.current = undefined;
setShowLargeImageWarning(false); setShowLargeImageWarning(false);
@ -201,6 +214,7 @@ function SelectMapModal({
> >
<GroupProvider <GroupProvider
groups={mapGroups} groups={mapGroups}
itemNames={mapNames}
onGroupsChange={updateMapGroups} onGroupsChange={updateMapGroups}
onGroupsSelect={handleGroupsSelect} onGroupsSelect={handleGroupsSelect}
disabled={!isOpen} disabled={!isOpen}
@ -213,6 +227,7 @@ function SelectMapModal({
<Label pt={2} pb={1}> <Label pt={2} pb={1}>
Select or import a map Select or import a map
</Label> </Label>
<TileActionBar onAdd={openImageDialog} addTitle="Import Map(s)" />
<Box sx={{ position: "relative" }}> <Box sx={{ position: "relative" }}>
<TileDragProvider onDragAdd={canAddDraggedMap && handleDragAdd}> <TileDragProvider onDragAdd={canAddDraggedMap && handleDragAdd}>
<TilesAddDroppable containerSize={modalSize} /> <TilesAddDroppable containerSize={modalSize} />

View File

@ -1,4 +1,4 @@
import React, { useRef, useState } from "react"; import React, { useRef, useState, useEffect } from "react";
import { Flex, Label, Button, Box } from "theme-ui"; import { Flex, Label, Button, Box } from "theme-ui";
import { useToasts } from "react-toast-notifications"; import { useToasts } from "react-toast-notifications";
import ReactResizeDetector from "react-resize-detector"; import ReactResizeDetector from "react-resize-detector";
@ -16,8 +16,9 @@ import TokenEditBar from "../components/token/TokenEditBar";
import TilesOverlay from "../components/tile/TilesOverlay"; import TilesOverlay from "../components/tile/TilesOverlay";
import TilesContainer from "../components/tile/TilesContainer"; import TilesContainer from "../components/tile/TilesContainer";
import TilesAddDroppable from "../components/tile/TilesAddDroppable"; import TilesAddDroppable from "../components/tile/TilesAddDroppable";
import TileActionBar from "../components/tile/TileActionBar";
import { getGroupItems } from "../helpers/group"; import { getGroupItems, getItemNames } from "../helpers/group";
import { import {
createTokenFromFile, createTokenFromFile,
createTokenState, createTokenState,
@ -49,6 +50,12 @@ function SelectTokensModal({ isOpen, onRequestClose, onMapTokensStateCreate }) {
} = useTokenData(); } = useTokenData();
const { addAssets } = useAssets(); const { addAssets } = useAssets();
// Get token names for group filtering
const [tokenNames, setTokenNames] = useState(getItemNames(tokens));
useEffect(() => {
setTokenNames(getItemNames(tokens));
}, [tokens]);
/** /**
* Image Upload * Image Upload
*/ */
@ -97,6 +104,12 @@ function SelectTokensModal({ isOpen, onRequestClose, onMapTokensStateCreate }) {
} }
} }
function openImageDialog() {
if (fileInputRef.current) {
fileInputRef.current.click();
}
}
function handleLargeImageWarningCancel() { function handleLargeImageWarningCancel() {
largeImageWarningFiles.current = undefined; largeImageWarningFiles.current = undefined;
setShowLargeImageWarning(false); setShowLargeImageWarning(false);
@ -202,6 +215,7 @@ function SelectTokensModal({ isOpen, onRequestClose, onMapTokensStateCreate }) {
> >
<GroupProvider <GroupProvider
groups={tokenGroups} groups={tokenGroups}
itemNames={tokenNames}
onGroupsChange={updateTokenGroups} onGroupsChange={updateTokenGroups}
disabled={!isOpen} disabled={!isOpen}
> >
@ -213,6 +227,10 @@ function SelectTokensModal({ isOpen, onRequestClose, onMapTokensStateCreate }) {
<Label pt={2} pb={1}> <Label pt={2} pb={1}>
Edit or import a token Edit or import a token
</Label> </Label>
<TileActionBar
onAdd={openImageDialog}
addTitle="Import Token(s)"
/>
<Box sx={{ position: "relative" }}> <Box sx={{ position: "relative" }}>
<TileDragProvider onDragAdd={handleTokensAddToMap}> <TileDragProvider onDragAdd={handleTokensAddToMap}>
<TilesAddDroppable containerSize={modalSize} /> <TilesAddDroppable containerSize={modalSize} />