Skip to content

Commit

Permalink
feat: update sortable
Browse files Browse the repository at this point in the history
  • Loading branch information
sadmann7 committed Jul 7, 2024
1 parent 8a27b96 commit 01848c3
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 9 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"@dnd-kit/modifiers": "^7.0.0",
"@dnd-kit/sortable": "^8.0.0",
"@dnd-kit/utilities": "^3.2.2",
"@faker-js/faker": "^8.4.1",
"@hookform/resolvers": "^3.9.0",
"@radix-ui/react-checkbox": "^1.1.1",
"@radix-ui/react-dropdown-menu": "^2.1.1",
Expand Down
8 changes: 8 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

51 changes: 51 additions & 0 deletions src/app/_components/items.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
"use client"

import * as React from "react"

import { getItems } from "@/lib/queries"
import { Skeleton } from "@/components/ui/skeleton"
import { Sortable, SortableItem } from "@/components/ui/sortable"
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table"

export function Items() {
const items = getItems()
const [allItems, setAllItems] = React.useState(items)

return (
<Table>
<TableHeader>
<TableRow>
<Sortable
orientation="horizontal"
value={allItems}
onValueChange={setAllItems}
overlay={<Skeleton className="h-8 w-full" />}
>
{["Name", "Description", "Price", "Stock"].map((heading) => (
<SortableItem key={heading} value={heading} asChild>
<TableHead key={heading}>{heading}</TableHead>
</SortableItem>
))}
</Sortable>
</TableRow>
</TableHeader>
<TableBody>
{items.map((item) => (
<TableRow key={item.id}>
<TableCell>{item.name}</TableCell>
<TableCell>{item.description}</TableCell>
<TableCell>{item.price}</TableCell>
<TableCell>{item.stock}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
)
}
2 changes: 2 additions & 0 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { Shell } from "@/components/shell"

import { HookFormDemo } from "./_components/hook-form-demo"
import { Items } from "./_components/items"

export default function IndexPage() {
return (
<Shell>
<HookFormDemo />
<Items />
</Shell>
)
}
44 changes: 35 additions & 9 deletions src/components/ui/sortable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@ import {
useSensors,
} from "@dnd-kit/core"
import {
restrictToHorizontalAxis,
restrictToParentElement,
restrictToVerticalAxis,
} from "@dnd-kit/modifiers"
import {
arrayMove,
horizontalListSortingStrategy,
SortableContext,
useSortable,
verticalListSortingStrategy,
Expand All @@ -36,6 +38,21 @@ import { composeRefs } from "@/lib/compose-refs"
import { cn } from "@/lib/utils"
import { Button, type ButtonProps } from "@/components/ui/button"

const orientationConfig = {
vertical: {
modifiers: [restrictToVerticalAxis, restrictToParentElement],
strategy: verticalListSortingStrategy,
},
horizontal: {
modifiers: [restrictToHorizontalAxis, restrictToParentElement],
strategy: horizontalListSortingStrategy,
},
both: {
modifiers: [restrictToParentElement],
strategy: undefined,
},
}

interface SortableProps<TData extends { id: UniqueIdentifier }>
extends DndContextProps {
/**
Expand Down Expand Up @@ -97,30 +114,37 @@ interface SortableProps<TData extends { id: UniqueIdentifier }>
* overlay={<Skeleton className="w-full h-8" />}
*/
overlay?: React.ReactNode | null

/**
* Specifies the axis for the drag-and-drop operation. It can be "vertical", "horizontal", or "both".
* @default "vertical"
* @type "vertical" | "horizontal" | "both"
*/
orientation?: "vertical" | "horizontal" | "both"
}

function Sortable<TData extends { id: UniqueIdentifier }>({
value,
onValueChange,
collisionDetection = closestCenter,
modifiers = [restrictToVerticalAxis, restrictToParentElement],
strategy = verticalListSortingStrategy,
orientation = "vertical",
onMove,
children,
overlay,
...props
}: SortableProps<TData>) {
const [activeId, setActiveId] = React.useState<UniqueIdentifier | null>(null)

const sensors = useSensors(
useSensor(MouseSensor),
useSensor(TouchSensor),
useSensor(KeyboardSensor)
useSensor(MouseSensor, {}),
useSensor(TouchSensor, {}),
useSensor(KeyboardSensor, {})
)

const config = orientationConfig[orientation]

return (
<DndContext
modifiers={modifiers}
modifiers={config.modifiers}
sensors={sensors}
onDragStart={({ active }) => setActiveId(active.id)}
onDragEnd={({ active, over }) => {
Expand All @@ -140,7 +164,7 @@ function Sortable<TData extends { id: UniqueIdentifier }>({
collisionDetection={collisionDetection}
{...props}
>
<SortableContext items={value} strategy={strategy}>
<SortableContext items={value} strategy={config.strategy}>
{children}
</SortableContext>
{overlay ? (
Expand Down Expand Up @@ -236,9 +260,11 @@ const SortableItem = React.forwardRef<HTMLDivElement, SortableItemProps>(
return (
<SortableItemContext.Provider value={context}>
<Comp
className={cn(isDragging && "cursor-grabbing", className)}
className={cn({ "cursor-grabbing": isDragging }, className)}
ref={composeRefs(ref, setNodeRef as React.Ref<HTMLDivElement>)}
style={style}
{...attributes}
{...listeners}
{...props}
/>
</SortableItemContext.Provider>
Expand Down
11 changes: 11 additions & 0 deletions src/lib/queries.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { faker } from "@faker-js/faker"

export function getItems() {
return Array.from({ length: 10 }, () => ({
id: faker.string.uuid(),
name: faker.lorem.words(),
description: faker.lorem.sentence(),
price: faker.finance.amount(),
stock: faker.number.int({ min: 0, max: 100 }),
}))
}

0 comments on commit 01848c3

Please sign in to comment.