You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Application-Web/front/components/Rack.tsx

73 lines
1.8 KiB

import { ReactElement, useRef } from "react"
import Draggable from "react-draggable"
export interface RackProps<E extends { key: string | number }> {
id: string
objects: E[]
onChange: (objects: E[]) => void
canDetach: (ref: HTMLDivElement) => boolean
onElementDetached: (ref: HTMLDivElement, el: E) => void
render: (e: E) => ReactElement
}
interface RackItemProps<E extends { key: string | number }> {
item: E
onTryDetach: (ref: HTMLDivElement, el: E) => void
render: (e: E) => ReactElement
}
/**
* A container of draggable objects
* */
export function Rack<E extends { key: string | number }>({
id,
objects,
onChange,
canDetach,
onElementDetached,
render,
}: RackProps<E>) {
return (
<div
id={id}
style={{
display: "flex",
}}>
{objects.map((element) => (
<RackItem
key={element.key}
item={element}
render={render}
onTryDetach={(ref, element) => {
if (!canDetach(ref)) return
const index = objects.findIndex(
(o) => o.key === element.key,
)
onChange(objects.toSpliced(index, 1))
onElementDetached(ref, element)
}}
/>
))}
</div>
)
}
function RackItem<E extends { key: string | number }>({
item,
onTryDetach,
render,
}: RackItemProps<E>) {
const divRef = useRef<HTMLDivElement>(null)
return (
<Draggable
position={{ x: 0, y: 0 }}
nodeRef={divRef}
onStop={() => onTryDetach(divRef.current!, item)}>
<div ref={divRef}>{render(item)}</div>
</Draggable>
)
}