feat(ui): animation of items changes

This commit is contained in:
Ou 2024-10-17 16:39:18 +08:00
parent 0d84e4b70d
commit 51018d4adb

View File

@ -1,4 +1,3 @@
import type { PropsWithChildren } from "react"
import { useCallback, useState } from "react" import { useCallback, useState } from "react"
import type { DragEndEvent, DragStartEvent } from "@dnd-kit/core" import type { DragEndEvent, DragStartEvent } from "@dnd-kit/core"
import { import {
@ -14,7 +13,7 @@ import { SortableContext, arrayMove, rectSortingStrategy, useSortable } from "@d
import { useAtom } from "jotai" import { useAtom } from "jotai"
import type { SourceID } from "@shared/types" import type { SourceID } from "@shared/types"
import { CSS } from "@dnd-kit/utilities" import { CSS } from "@dnd-kit/utilities"
import { motion } from "framer-motion" import { LayoutGroup, motion } from "framer-motion"
import type { ItemsProps } from "./card" import type { ItemsProps } from "./card"
import { CardOverlay, CardWrapper } from "./card" import { CardOverlay, CardWrapper } from "./card"
import { currentSourcesAtom } from "~/atoms" import { currentSourcesAtom } from "~/atoms"
@ -23,7 +22,8 @@ export function Dnd() {
const [items, setItems] = useAtom(currentSourcesAtom) const [items, setItems] = useAtom(currentSourcesAtom)
return ( return (
<DndWrapper items={items} setItems={setItems}> <DndWrapper items={items} setItems={setItems}>
<motion.div {activeid => (
<motion.ol
className="grid w-full gap-6" className="grid w-full gap-6"
style={{ style={{
gridTemplateColumns: "repeat(auto-fill, minmax(350px, 1fr))", gridTemplateColumns: "repeat(auto-fill, minmax(350px, 1fr))",
@ -33,14 +33,16 @@ export function Dnd() {
variants={{ variants={{
visible: { visible: {
transition: { transition: {
delayChildren: 0.5, delayChildren: 0.3,
staggerChildren: 0.2, staggerChildren: 0.2,
}, },
}, },
}} }}
> >
<LayoutGroup>
{items.map(id => ( {items.map(id => (
<motion.div <motion.li
layout={!activeid}
key={id} key={id}
variants={{ variants={{
hidden: { y: 20, opacity: 0 }, hidden: { y: 20, opacity: 0 },
@ -51,9 +53,11 @@ export function Dnd() {
}} }}
> >
<SortableCardWrapper id={id} /> <SortableCardWrapper id={id} />
</motion.div> </motion.li>
))} ))}
</motion.div> </LayoutGroup>
</motion.ol>
)}
</DndWrapper> </DndWrapper>
) )
} }
@ -61,9 +65,10 @@ export function Dnd() {
interface DndProps { interface DndProps {
items: SourceID[] items: SourceID[]
setItems: (update: SourceID[]) => void setItems: (update: SourceID[]) => void
children: (activeId: string | null) => React.ReactNode
} }
export function DndWrapper({ items, setItems, children }: PropsWithChildren<DndProps>) { export function DndWrapper({ items, setItems, children }: DndProps) {
const [activeId, setActiveId] = useState<string | null>(null) const [activeId, setActiveId] = useState<string | null>(null)
const sensors = useSensors(useSensor(MouseSensor), useSensor(TouchSensor)) const sensors = useSensors(useSensor(MouseSensor), useSensor(TouchSensor))
@ -95,7 +100,7 @@ export function DndWrapper({ items, setItems, children }: PropsWithChildren<DndP
onDragCancel={handleDragCancel} onDragCancel={handleDragCancel}
> >
<SortableContext items={items} strategy={rectSortingStrategy}> <SortableContext items={items} strategy={rectSortingStrategy}>
{children} {children(activeId)}
</SortableContext> </SortableContext>
<DragOverlay adjustScale style={{ transformOrigin: "0 0 " }}> <DragOverlay adjustScale style={{ transformOrigin: "0 0 " }}>
{!!activeId && <CardOverlay id={activeId as SourceID} />} {!!activeId && <CardOverlay id={activeId as SourceID} />}