Add animation to group open

This commit is contained in:
Mitchell McCaffrey 2021-05-24 17:11:46 +10:00
parent 0917ef05a1
commit 4e5bd8bf02
12 changed files with 170 additions and 76 deletions

View File

@ -16,9 +16,13 @@ function MapTileGroup({ group, maps, isSelected, onSelect, onDoubleClick }) {
onSelect={() => onSelect(group.id)}
onDoubleClick={onDoubleClick}
>
<Grid columns={layout.gridTemplate} p={2} sx={{ gridGap: 2 }}>
<Grid columns={layout.groupGridTemplate} p={2} sx={{ gridGap: 2 }}>
{maps.slice(0, 16).map((map) => (
<MapTileImage sx={{ borderRadius: "8px" }} map={map} key={map.id} />
<MapTileImage
sx={{ borderRadius: "8px" }}
map={map}
key={`${map.id}-group-tile`}
/>
))}
</Grid>
</Tile>

View File

@ -13,6 +13,7 @@ function MapTiles({ maps, onMapEdit, onMapSelect, subgroup }) {
const {
groups,
selectedGroupIds,
openGroupId,
openGroupItems,
selectMode,
onGroupOpen,
@ -63,6 +64,7 @@ function MapTiles({ maps, onMapEdit, onMapSelect, subgroup }) {
renderTile={renderTile}
onTileSelect={onGroupSelect}
disableGrouping={subgroup}
openGroupId={openGroupId}
/>
);
}

View File

@ -2,8 +2,9 @@ import React from "react";
import { Box } from "theme-ui";
import { useDroppable } from "@dnd-kit/core";
import { useSortable } from "@dnd-kit/sortable";
import { animated, useSpring } from "react-spring";
function Sortable({ id, disableGrouping, children }) {
function Sortable({ id, disableGrouping, hidden, children }) {
const {
attributes,
listeners,
@ -48,8 +49,10 @@ function Sortable({ id, disableGrouping, children }) {
over?.id === `__group__${id}` && active.id !== id ? "solid" : "none",
};
const { opacity } = useSpring({ opacity: hidden ? 0 : 1 });
return (
<Box sx={{ position: "relative" }}>
<animated.div style={{ opacity, position: "relative" }}>
<Box
ref={setDraggableNodeRef}
style={dragStyle}
@ -75,7 +78,7 @@ function Sortable({ id, disableGrouping, children }) {
sx={{ borderColor: "primary" }}
/>
</Box>
</Box>
</animated.div>
);
}

View File

@ -11,12 +11,9 @@ import {
} from "@dnd-kit/core";
import { SortableContext, arrayMove } from "@dnd-kit/sortable";
import { animated, useSpring, config } from "react-spring";
import { Grid } from "theme-ui";
import { combineGroups, moveGroups } from "../../helpers/group";
import useResponsiveLayout from "../../hooks/useResponsiveLayout";
import SortableTile from "./SortableTile";
function SortableTiles({
@ -25,9 +22,8 @@ function SortableTiles({
renderTile,
onTileSelect,
disableGrouping,
openGroupId,
}) {
const layout = useResponsiveLayout();
const mouseSensor = useSensor(MouseSensor, {
activationConstraint: { delay: 250, tolerance: 5 },
});
@ -105,27 +101,16 @@ function SortableTiles({
collisionDetection={closestCenter}
>
<SortableContext items={groups}>
<Grid
p={3}
pb={4}
sx={{
borderRadius: "4px",
overflow: "hidden",
}}
gap={2}
columns={layout.gridTemplate}
onClick={() => onTileSelect()}
>
{groups.map((group) => (
<SortableTile
id={group.id}
key={group.id}
disableGrouping={disableGrouping}
>
{renderSortableGroup(group)}
</SortableTile>
))}
</Grid>
{groups.map((group) => (
<SortableTile
id={group.id}
key={group.id}
disableGrouping={disableGrouping}
hidden={group.id === openGroupId}
>
{renderSortableGroup(group)}
</SortableTile>
))}
{createPortal(
<DragOverlay dropAnimation={null}>
{dragId && (

View File

@ -1,14 +1,40 @@
import React from "react";
import { Box, Grid } from "theme-ui";
import SimpleBar from "simplebar-react";
import { useGroup } from "../../contexts/GroupContext";
import useResponsiveLayout from "../../hooks/useResponsiveLayout";
function TilesContainer({ children }) {
const { onGroupSelect } = useGroup();
const layout = useResponsiveLayout();
return (
<SimpleBar style={{ height: layout.tileContainerHeight }}>
{children}
<Box
sx={{
position: "absolute",
width: "100%",
height: "100%",
top: 0,
}}
bg="muted"
onClick={() => onGroupSelect()}
/>
<Grid
p={3}
pb={4}
sx={{
borderRadius: "4px",
overflow: "hidden",
}}
gap={2}
columns={layout.gridTemplate}
>
{children}
</Grid>
</SimpleBar>
);
}

View File

@ -1,48 +1,111 @@
import React from "react";
import { Box, Close } from "theme-ui";
import React, { useState } from "react";
import { Box, Close, Grid } from "theme-ui";
import { useSpring, animated, config } from "react-spring";
import ReactResizeDetector from "react-resize-detector";
import SimpleBar from "simplebar-react";
import { useGroup } from "../../contexts/GroupContext";
function TilesOverlay({ children }) {
const { openGroupId, onGroupClose } = useGroup();
import useResponsiveLayout from "../../hooks/useResponsiveLayout";
if (!openGroupId) {
return null;
function TilesOverlay({ children }) {
const { openGroupId, onGroupClose, onGroupSelect } = useGroup();
const openAnimation = useSpring({
opacity: openGroupId ? 1 : 0,
transform: openGroupId ? "scale(1)" : "scale(0.95)",
config: config.gentle,
});
const [containerSize, setContinerSize] = useState(0);
function handleResize(width, height) {
const size = Math.min(width, height) - 16;
setContinerSize(size);
}
const layout = useResponsiveLayout();
return (
<Box
sx={{
position: "absolute",
width: "100%",
height: "100%",
top: 0,
cursor: "pointer",
}}
p={3}
bg="overlay"
onClick={() => onGroupClose()}
>
<Box
sx={{
width: "100%",
height: "100%",
borderRadius: "8px",
border: "1px solid",
borderColor: "border",
cursor: "default",
}}
bg="muted"
onClick={(e) => e.stopPropagation()}
p={3}
>
{children}
</Box>
<Close
onClick={() => onGroupClose()}
sx={{ position: "absolute", top: "16px", right: "16px" }}
/>
</Box>
<>
{openGroupId && (
<Box
sx={{
position: "absolute",
width: "100%",
height: "100%",
top: 0,
}}
bg="overlay"
/>
)}
<ReactResizeDetector handleWidth handleHeight onResize={handleResize}>
<animated.div
style={{
...openAnimation,
position: "absolute",
width: "100%",
height: "100%",
top: 0,
display: "flex",
alignItems: "center",
justifyContent: "center",
cursor: "pointer",
pointerEvents: openGroupId ? undefined : "none",
}}
onClick={() => openGroupId && onGroupClose()}
>
<Box
sx={{
width: containerSize,
height: containerSize,
borderRadius: "8px",
border: "1px solid",
borderColor: "border",
cursor: "default",
display: "flex",
alignItems: "center",
justifyContent: "center",
position: "relative",
}}
bg="background"
onClick={(e) => e.stopPropagation()}
>
<Box
sx={{
position: "absolute",
width: "100%",
height: "100%",
top: 0,
}}
bg="muted"
onClick={() => onGroupSelect()}
/>
<SimpleBar
style={{
width: containerSize - 16,
height: containerSize - 48,
}}
>
<Grid
sx={{
borderRadius: "4px",
overflow: "hidden",
}}
gap={2}
columns={layout.groupGridTemplate}
px={3}
>
{children}
</Grid>
</SimpleBar>
<Close
onClick={() => onGroupClose()}
sx={{ position: "absolute", top: 0, right: 0 }}
/>
</Box>
</animated.div>
</ReactResizeDetector>
</>
);
}

View File

@ -57,7 +57,7 @@ function TokenBar({ onMapTokenStateCreate }) {
height: "100%",
width: "80px",
minWidth: "80px",
overflowY: "scroll",
overflowY: "hidden",
overflowX: "hidden",
display: fullScreen ? "none" : "block",
}}

View File

@ -23,12 +23,12 @@ function TokenTileGroup({
onDoubleClick={onDoubleClick}
columns="1fr 1fr"
>
<Grid columns={layout.gridTemplate} p={2} sx={{ gridGap: 2 }}>
<Grid columns={layout.groupGridTemplate} p={2} sx={{ gridGap: 2 }}>
{tokens.slice(0, 16).map((token) => (
<TokenTileImage
sx={{ borderRadius: "8px" }}
token={token}
key={token.id}
key={`${token.id}-group-tile`}
/>
))}
</Grid>

View File

@ -13,6 +13,7 @@ function TokenTiles({ tokens, onTokenEdit, subgroup }) {
const {
groups,
selectedGroupIds,
openGroupId,
openGroupItems,
selectMode,
onGroupOpen,
@ -68,6 +69,7 @@ function TokenTiles({ tokens, onTokenEdit, subgroup }) {
renderTile={renderTile}
onTileSelect={onGroupSelect}
disableGrouping={subgroup}
openGroupId={openGroupId}
/>
);
}

View File

@ -27,9 +27,18 @@ function useResponsiveLayout() {
? "1fr 1fr 1fr"
: "1fr 1fr";
const groupGridTemplate = isLargeScreen ? "1fr 1fr 1fr" : "1fr 1fr";
const tileContainerHeight = isLargeScreen ? "600px" : "400px";
return { screenSize, modalSize, tileSize, gridTemplate, tileContainerHeight };
return {
screenSize,
modalSize,
tileSize,
gridTemplate,
tileContainerHeight,
groupGridTemplate,
};
}
export default useResponsiveLayout;

View File

@ -252,7 +252,7 @@ function SelectMapModal({
<Label pt={2} pb={1}>
Select or import a map
</Label>
<Box sx={{ position: "relative" }} bg="muted">
<Box sx={{ position: "relative" }}>
<GroupProvider
groups={mapGroups}
onGroupsChange={updateMapGroups}

View File

@ -193,7 +193,7 @@ function SelectTokensModal({ isOpen, onRequestClose }) {
<Label pt={2} pb={1}>
Edit or import a token
</Label>
<Box sx={{ position: "relative" }} bg="muted">
<Box sx={{ position: "relative" }}>
<GroupProvider
groups={tokenGroups}
onGroupsChange={updateTokenGroups}