205 lines
9 KiB
TypeScript
205 lines
9 KiB
TypeScript
import React from "react";
|
|
import { TagInputStyleClassesProps, type Tag as TagType } from "./tag-input";
|
|
import { Tag, TagProps } from "./tag";
|
|
import SortableList, { SortableItem } from "react-easy-sort";
|
|
import { cn } from "@app/lib/cn";
|
|
|
|
export type TagListProps = {
|
|
tags: TagType[];
|
|
customTagRenderer?: (tag: TagType, isActiveTag: boolean) => React.ReactNode;
|
|
direction?: TagProps["direction"];
|
|
onSortEnd: (oldIndex: number, newIndex: number) => void;
|
|
className?: string;
|
|
inlineTags?: boolean;
|
|
activeTagIndex?: number | null;
|
|
setActiveTagIndex?: (index: number | null) => void;
|
|
classStyleProps: {
|
|
tagListClasses: TagInputStyleClassesProps["tagList"];
|
|
tagClasses: TagInputStyleClassesProps["tag"];
|
|
};
|
|
disabled?: boolean;
|
|
} & Omit<TagProps, "tagObj">;
|
|
|
|
const DropTarget: React.FC = () => {
|
|
return <div className={cn("h-full rounded-md bg-secondary/50")} />;
|
|
};
|
|
|
|
export const TagList: React.FC<TagListProps> = ({
|
|
tags,
|
|
customTagRenderer,
|
|
direction,
|
|
draggable,
|
|
onSortEnd,
|
|
className,
|
|
inlineTags,
|
|
activeTagIndex,
|
|
setActiveTagIndex,
|
|
classStyleProps,
|
|
disabled,
|
|
...tagListProps
|
|
}) => {
|
|
const [draggedTagId, setDraggedTagId] = React.useState<string | null>(null);
|
|
|
|
const handleMouseDown = (id: string) => {
|
|
setDraggedTagId(id);
|
|
};
|
|
|
|
const handleMouseUp = () => {
|
|
setDraggedTagId(null);
|
|
};
|
|
|
|
return (
|
|
<>
|
|
{!inlineTags ? (
|
|
<div
|
|
className={cn(
|
|
"rounded-md w-full",
|
|
// className,
|
|
{
|
|
"flex flex-wrap gap-2": direction === "row",
|
|
"flex flex-col gap-2": direction === "column"
|
|
},
|
|
classStyleProps?.tagListClasses?.container
|
|
)}
|
|
>
|
|
{draggable ? (
|
|
<SortableList
|
|
onSortEnd={onSortEnd}
|
|
// className="flex flex-wrap gap-2 list"
|
|
className={`flex flex-wrap gap-2 list ${classStyleProps?.tagListClasses?.sortableList}`}
|
|
dropTarget={<DropTarget />}
|
|
>
|
|
{tags.map((tagObj, index) => (
|
|
<SortableItem key={tagObj.id}>
|
|
<div
|
|
onMouseDown={() =>
|
|
handleMouseDown(tagObj.id)
|
|
}
|
|
onMouseLeave={handleMouseUp}
|
|
className={cn(
|
|
{
|
|
"border border-solid border-primary rounded-md":
|
|
draggedTagId === tagObj.id
|
|
},
|
|
"transition-all duration-200 ease-in-out"
|
|
)}
|
|
>
|
|
{customTagRenderer ? (
|
|
customTagRenderer(
|
|
tagObj,
|
|
index === activeTagIndex
|
|
)
|
|
) : (
|
|
<Tag
|
|
tagObj={tagObj}
|
|
isActiveTag={
|
|
index === activeTagIndex
|
|
}
|
|
direction={direction}
|
|
draggable={draggable}
|
|
tagClasses={
|
|
classStyleProps?.tagClasses
|
|
}
|
|
{...tagListProps}
|
|
disabled={disabled}
|
|
/>
|
|
)}
|
|
</div>
|
|
</SortableItem>
|
|
))}
|
|
</SortableList>
|
|
) : (
|
|
tags.map((tagObj, index) =>
|
|
customTagRenderer ? (
|
|
customTagRenderer(
|
|
tagObj,
|
|
index === activeTagIndex
|
|
)
|
|
) : (
|
|
<Tag
|
|
key={tagObj.id}
|
|
tagObj={tagObj}
|
|
isActiveTag={index === activeTagIndex}
|
|
direction={direction}
|
|
draggable={draggable}
|
|
tagClasses={classStyleProps?.tagClasses}
|
|
{...tagListProps}
|
|
disabled={disabled}
|
|
/>
|
|
)
|
|
)
|
|
)}
|
|
</div>
|
|
) : (
|
|
<>
|
|
{draggable ? (
|
|
<SortableList
|
|
onSortEnd={onSortEnd}
|
|
className="flex flex-wrap gap-2 list"
|
|
dropTarget={<DropTarget />}
|
|
>
|
|
{tags.map((tagObj, index) => (
|
|
<SortableItem key={tagObj.id}>
|
|
<div
|
|
onMouseDown={() =>
|
|
handleMouseDown(tagObj.id)
|
|
}
|
|
onMouseLeave={handleMouseUp}
|
|
className={cn(
|
|
{
|
|
"border border-solid border-primary rounded-md":
|
|
draggedTagId === tagObj.id
|
|
},
|
|
"transition-all duration-200 ease-in-out"
|
|
)}
|
|
>
|
|
{customTagRenderer ? (
|
|
customTagRenderer(
|
|
tagObj,
|
|
index === activeTagIndex
|
|
)
|
|
) : (
|
|
<Tag
|
|
tagObj={tagObj}
|
|
isActiveTag={
|
|
index === activeTagIndex
|
|
}
|
|
direction={direction}
|
|
draggable={draggable}
|
|
tagClasses={
|
|
classStyleProps?.tagClasses
|
|
}
|
|
{...tagListProps}
|
|
disabled={disabled}
|
|
/>
|
|
)}
|
|
</div>
|
|
</SortableItem>
|
|
))}
|
|
</SortableList>
|
|
) : (
|
|
tags.map((tagObj, index) =>
|
|
customTagRenderer ? (
|
|
customTagRenderer(
|
|
tagObj,
|
|
index === activeTagIndex
|
|
)
|
|
) : (
|
|
<Tag
|
|
key={tagObj.id}
|
|
tagObj={tagObj}
|
|
isActiveTag={index === activeTagIndex}
|
|
direction={direction}
|
|
draggable={draggable}
|
|
tagClasses={classStyleProps?.tagClasses}
|
|
{...tagListProps}
|
|
disabled={disabled}
|
|
/>
|
|
)
|
|
)
|
|
)}
|
|
</>
|
|
)}
|
|
</>
|
|
);
|
|
};
|