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.
58 lines
1.7 KiB
58 lines
1.7 KiB
import {ReactElement, useRef} from "react";
|
|
import Draggable from "react-draggable";
|
|
|
|
export interface RackProps<E> {
|
|
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> {
|
|
item: E,
|
|
onTryDetach: (ref: HTMLDivElement, el: E) => void,
|
|
render: (e: E) => ReactElement,
|
|
}
|
|
|
|
/**
|
|
* A container of draggable objects
|
|
* */
|
|
export function Rack<E>({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>({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>
|
|
)
|
|
} |