Skip to content

Instantly share code, notes, and snippets.

@Nemo64
Created July 14, 2023 17:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Nemo64/fdc7a31341a5851a1736d070bb4d41f4 to your computer and use it in GitHub Desktop.
Save Nemo64/fdc7a31341a5851a1736d070bb4d41f4 to your computer and use it in GitHub Desktop.
sortable tags in ant.design Select mode="multiple"
function SortableSelect<ValueType extends Array<unknown>, OptionType>(
props: SelectProps<ValueType, OptionType>
) {
return (
<DndProvider backend={HTML5Backend}>
<Select<ValueType, OptionType>
{...props}
tagRender={({ label, ...tagProps }) => (
<DraggableTag
{...tagProps}
index={props.value?.indexOf(tagProps.value) ?? 0}
move={(from, to) => {
if (!Array.isArray(props.value)) {
return;
}
const newValue = [...props.value];
newValue.splice(from, 1);
newValue.splice(to, 0, props.value[from]);
props.onChange?.(
newValue as any,
props.options?.filter((_, index) =>
newValue.includes(index)
) as any
);
}}
>
{label}
</DraggableTag>
)}
/>
</DndProvider>
);
}
function DraggableTag({
index,
move,
...props
}: { index: number; move: (from: number, to: number) => void } & TagProps) {
const ref = useRef<HTMLElement>(null);
const [styles, drop] = useDrop<{ index: number }, unknown, CSSProperties>({
accept: "DraggableTag",
collect: (monitor) => {
const item = monitor.isOver() && monitor.getItem();
if (item && item.index > index) {
return {
borderLeft: "5px solid #1890ff",
paddingLeft: "5px",
};
} else if (item && item.index < index) {
return {
borderRight: "5px solid #1890ff",
paddingRight: "5px",
};
} else {
return {};
}
},
drop: (item) => {
move(item.index, index);
},
});
const [, drag] = useDrag<{ index: number }, unknown, CSSProperties>({
type: "DraggableTag",
item: { index },
});
drop(drag(ref));
return (
<span style={{ display: "inline-block", cursor: "move", ...styles }}>
<Tag
{...props}
ref={ref}
onMouseDown={(event) => {
// stop antd from preventing the default
event.stopPropagation();
}}
/>
</span>
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment