chore: update package.json with new Atlaskit drag-and-drop dependencies; refactor TypeTag component for improved state management
This commit is contained in:
parent
fbfa075c51
commit
410ba207de
|
|
@ -1,19 +1,4 @@
|
||||||
import { useLocal } from "@/lib/utils/use-local";
|
|
||||||
import { Input } from "../../ui/input";
|
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import {
|
|
||||||
useEditor,
|
|
||||||
EditorContent,
|
|
||||||
useCurrentEditor,
|
|
||||||
EditorProvider,
|
|
||||||
} from "@tiptap/react";
|
|
||||||
import Link from "@tiptap/extension-link";
|
|
||||||
import StarterKit from "@tiptap/starter-kit";
|
|
||||||
import { Color } from "@tiptap/extension-color";
|
|
||||||
import ListItem from "@tiptap/extension-list-item";
|
|
||||||
import TextStyle from "@tiptap/extension-text-style";
|
|
||||||
import { Popover } from "../../Popover/Popover";
|
|
||||||
import { ButtonBetter } from "../../ui/button";
|
|
||||||
import get from "lodash.get";
|
import get from "lodash.get";
|
||||||
|
|
||||||
export const TypeTag: React.FC<any> = ({
|
export const TypeTag: React.FC<any> = ({
|
||||||
|
|
@ -31,17 +16,17 @@ export const TypeTag: React.FC<any> = ({
|
||||||
const [editingIndex, setEditingIndex] = useState<number | null>(null); // Index tag yang sedang diedit
|
const [editingIndex, setEditingIndex] = useState<number | null>(null); // Index tag yang sedang diedit
|
||||||
const [tempValue, setTempValue] = useState<string>(""); // Nilai sementara untuk pengeditan
|
const [tempValue, setTempValue] = useState<string>(""); // Nilai sementara untuk pengeditan
|
||||||
const tagRefs = useRef<(HTMLDivElement | null)[]>([]);
|
const tagRefs = useRef<(HTMLDivElement | null)[]>([]);
|
||||||
|
const val = fm?.data?.[name];
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (get(fm, `data.[${name}].length`)) {
|
if (get(fm, `data.[${name}].length`)) {
|
||||||
setTags(fm.data?.[name]);
|
setTags(fm.data?.[name]);
|
||||||
}
|
}
|
||||||
}, []);
|
}, [val]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log("NEW");
|
console.log("MASUK", tags);
|
||||||
fm.data[name] = tags;
|
fm.data[name] = tags;
|
||||||
fm.render();
|
fm.render();
|
||||||
|
console.log("MASUK");
|
||||||
if (typeof onChange === "function") {
|
if (typeof onChange === "function") {
|
||||||
onChange(tags);
|
onChange(tags);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,503 @@
|
||||||
|
"use client";
|
||||||
|
import {
|
||||||
|
createContext,
|
||||||
|
FC,
|
||||||
|
Fragment,
|
||||||
|
useCallback,
|
||||||
|
useContext,
|
||||||
|
useEffect,
|
||||||
|
useMemo,
|
||||||
|
useRef,
|
||||||
|
useState,
|
||||||
|
} from "react";
|
||||||
|
import ReactDOM from "react-dom";
|
||||||
|
import invariant from "tiny-invariant";
|
||||||
|
|
||||||
|
import { triggerPostMoveFlash } from "@atlaskit/pragmatic-drag-and-drop-flourish/trigger-post-move-flash";
|
||||||
|
import {
|
||||||
|
attachClosestEdge,
|
||||||
|
type Edge,
|
||||||
|
extractClosestEdge,
|
||||||
|
} from "@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge";
|
||||||
|
import { getReorderDestinationIndex } from "@atlaskit/pragmatic-drag-and-drop-hitbox/util/get-reorder-destination-index";
|
||||||
|
import * as liveRegion from "@atlaskit/pragmatic-drag-and-drop-live-region";
|
||||||
|
import { DropIndicator } from "@atlaskit/pragmatic-drag-and-drop-react-drop-indicator/box";
|
||||||
|
import { combine } from "@atlaskit/pragmatic-drag-and-drop/combine";
|
||||||
|
import {
|
||||||
|
draggable,
|
||||||
|
dropTargetForElements,
|
||||||
|
monitorForElements,
|
||||||
|
} from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
|
||||||
|
import { pointerOutsideOfPreview } from "@atlaskit/pragmatic-drag-and-drop/element/pointer-outside-of-preview";
|
||||||
|
import { setCustomNativeDragPreview } from "@atlaskit/pragmatic-drag-and-drop/element/set-custom-native-drag-preview";
|
||||||
|
import { reorder } from "@atlaskit/pragmatic-drag-and-drop/reorder";
|
||||||
|
import { Box, xcss } from "@atlaskit/primitives";
|
||||||
|
import { token } from "@atlaskit/tokens";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import { ButtonBetter } from "./button";
|
||||||
|
import { RiDraggable } from "react-icons/ri";
|
||||||
|
|
||||||
|
type ItemPosition = "first" | "last" | "middle" | "only";
|
||||||
|
|
||||||
|
type CleanupFn = () => void;
|
||||||
|
|
||||||
|
type ItemEntry = { itemId: string; element: HTMLElement };
|
||||||
|
|
||||||
|
type ListContextValue = {
|
||||||
|
getListLength: () => number;
|
||||||
|
registerItem: (entry: ItemEntry) => CleanupFn;
|
||||||
|
reorderItem: (args: {
|
||||||
|
startIndex: number;
|
||||||
|
indexOfTarget: number;
|
||||||
|
closestEdgeOfTarget: Edge | null;
|
||||||
|
}) => void;
|
||||||
|
instanceId: symbol;
|
||||||
|
};
|
||||||
|
|
||||||
|
const ListContext = createContext<ListContextValue | null>(null);
|
||||||
|
|
||||||
|
function useListContext() {
|
||||||
|
const listContext = useContext(ListContext);
|
||||||
|
invariant(listContext !== null);
|
||||||
|
return listContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
type Item = {
|
||||||
|
id: string;
|
||||||
|
label: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const itemKey = Symbol("item");
|
||||||
|
type ItemData = {
|
||||||
|
[itemKey]: true;
|
||||||
|
item: Item;
|
||||||
|
index: number;
|
||||||
|
instanceId: symbol;
|
||||||
|
};
|
||||||
|
|
||||||
|
function getItemData({
|
||||||
|
item,
|
||||||
|
index,
|
||||||
|
instanceId,
|
||||||
|
}: {
|
||||||
|
item: Item;
|
||||||
|
index: number;
|
||||||
|
instanceId: symbol;
|
||||||
|
}): ItemData {
|
||||||
|
return {
|
||||||
|
[itemKey]: true,
|
||||||
|
item,
|
||||||
|
index,
|
||||||
|
instanceId,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function isItemData(data: Record<string | symbol, unknown>): data is ItemData {
|
||||||
|
return data[itemKey] === true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getItemPosition({
|
||||||
|
index,
|
||||||
|
items,
|
||||||
|
}: {
|
||||||
|
index: number;
|
||||||
|
items: Item[];
|
||||||
|
}): ItemPosition {
|
||||||
|
if (items.length === 1) {
|
||||||
|
return "only";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index === 0) {
|
||||||
|
return "first";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index === items.length - 1) {
|
||||||
|
return "last";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "middle";
|
||||||
|
}
|
||||||
|
|
||||||
|
const listItemContainerStyles = xcss({
|
||||||
|
position: "relative",
|
||||||
|
backgroundColor: "elevation.surface",
|
||||||
|
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-selectors -- Ignored via go/DSP-18766
|
||||||
|
});
|
||||||
|
|
||||||
|
const listItemStyles = xcss({
|
||||||
|
position: "relative",
|
||||||
|
padding: "space.100",
|
||||||
|
});
|
||||||
|
|
||||||
|
const listItemDisabledStyles = xcss({ opacity: 0.4 });
|
||||||
|
|
||||||
|
type DraggableState =
|
||||||
|
| { type: "idle" }
|
||||||
|
| { type: "preview"; container: HTMLElement }
|
||||||
|
| { type: "dragging" };
|
||||||
|
|
||||||
|
const idleState: DraggableState = { type: "idle" };
|
||||||
|
const draggingState: DraggableState = { type: "dragging" };
|
||||||
|
|
||||||
|
const listItemPreviewStyles = xcss({
|
||||||
|
paddingBlock: "space.050",
|
||||||
|
paddingInline: "space.100",
|
||||||
|
borderRadius: "border.radius.100",
|
||||||
|
backgroundColor: "elevation.surface.overlay",
|
||||||
|
maxWidth: "360px",
|
||||||
|
whiteSpace: "nowrap",
|
||||||
|
overflow: "hidden",
|
||||||
|
textOverflow: "ellipsis",
|
||||||
|
});
|
||||||
|
|
||||||
|
const itemLabelStyles = xcss({
|
||||||
|
flexGrow: 1,
|
||||||
|
whiteSpace: "nowrap",
|
||||||
|
textOverflow: "ellipsis",
|
||||||
|
overflow: "hidden",
|
||||||
|
});
|
||||||
|
|
||||||
|
function ListItem({
|
||||||
|
item,
|
||||||
|
index,
|
||||||
|
position,
|
||||||
|
children,
|
||||||
|
className,
|
||||||
|
classDragBtn,
|
||||||
|
}: {
|
||||||
|
item: Item;
|
||||||
|
index: number;
|
||||||
|
position: ItemPosition;
|
||||||
|
children: (data?: any, index?: number) => any;
|
||||||
|
className?: string;
|
||||||
|
classDragBtn?: string;
|
||||||
|
}) {
|
||||||
|
const { registerItem, instanceId } = useListContext();
|
||||||
|
|
||||||
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
|
const [closestEdge, setClosestEdge] = useState<Edge | null>(null);
|
||||||
|
|
||||||
|
const dragHandleRef = useRef<HTMLButtonElement>(null);
|
||||||
|
|
||||||
|
const [draggableState, setDraggableState] =
|
||||||
|
useState<DraggableState>(idleState);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const element = ref.current;
|
||||||
|
const dragHandle = dragHandleRef?.current;
|
||||||
|
invariant(element);
|
||||||
|
invariant(dragHandle);
|
||||||
|
|
||||||
|
const data = getItemData({ item, index, instanceId });
|
||||||
|
|
||||||
|
return combine(
|
||||||
|
registerItem({ itemId: item.id, element }),
|
||||||
|
draggable({
|
||||||
|
element: dragHandle,
|
||||||
|
getInitialData: () => data,
|
||||||
|
onGenerateDragPreview({ nativeSetDragImage }) {
|
||||||
|
setCustomNativeDragPreview({
|
||||||
|
nativeSetDragImage,
|
||||||
|
getOffset: pointerOutsideOfPreview({
|
||||||
|
x: token("space.200", "16px"),
|
||||||
|
y: token("space.100", "8px"),
|
||||||
|
}),
|
||||||
|
render({ container }) {
|
||||||
|
setDraggableState({ type: "preview", container });
|
||||||
|
|
||||||
|
return () => setDraggableState(draggingState);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onDragStart() {
|
||||||
|
setDraggableState(draggingState);
|
||||||
|
},
|
||||||
|
onDrop() {
|
||||||
|
setDraggableState(idleState);
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
dropTargetForElements({
|
||||||
|
element,
|
||||||
|
canDrop({ source }) {
|
||||||
|
return (
|
||||||
|
isItemData(source.data) && source.data.instanceId === instanceId
|
||||||
|
);
|
||||||
|
},
|
||||||
|
getData({ input }) {
|
||||||
|
return attachClosestEdge(data, {
|
||||||
|
element,
|
||||||
|
input,
|
||||||
|
allowedEdges: ["top", "bottom"],
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onDrag({ self, source }) {
|
||||||
|
const isSource = source.element === element;
|
||||||
|
if (isSource) {
|
||||||
|
setClosestEdge(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const closestEdge = extractClosestEdge(self.data);
|
||||||
|
|
||||||
|
const sourceIndex = source.data.index;
|
||||||
|
invariant(typeof sourceIndex === "number");
|
||||||
|
|
||||||
|
const isItemBeforeSource = index === sourceIndex - 1;
|
||||||
|
const isItemAfterSource = index === sourceIndex + 1;
|
||||||
|
|
||||||
|
const isDropIndicatorHidden =
|
||||||
|
(isItemBeforeSource && closestEdge === "bottom") ||
|
||||||
|
(isItemAfterSource && closestEdge === "top");
|
||||||
|
|
||||||
|
if (isDropIndicatorHidden) {
|
||||||
|
setClosestEdge(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setClosestEdge(closestEdge);
|
||||||
|
},
|
||||||
|
onDragLeave() {
|
||||||
|
setClosestEdge(null);
|
||||||
|
},
|
||||||
|
onDrop() {
|
||||||
|
setClosestEdge(null);
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}, [instanceId, item, index, registerItem]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<Box ref={ref} xcss={listItemContainerStyles}>
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
"group relative flex flex-row items-center gap-x-1 pt-2",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
"drag-grab hidden group-hover:flex absolute top-0",
|
||||||
|
css`
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<ButtonBetter
|
||||||
|
ref={dragHandleRef}
|
||||||
|
variant={"outline"}
|
||||||
|
className={cn(
|
||||||
|
classDragBtn,
|
||||||
|
"p-0 bg-transparent h-auto shadow-none hover:shadow-none hover:bg-transparent border-none "
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<RiDraggable className="text-gray-500 rotate-90" />
|
||||||
|
</ButtonBetter>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col flex-grow">
|
||||||
|
{typeof children === "function" ? children(item, index) : <></>}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{closestEdge && <DropIndicator edge={closestEdge} gap="1px" />}
|
||||||
|
</Box>
|
||||||
|
{draggableState.type === "preview" &&
|
||||||
|
ReactDOM.createPortal(
|
||||||
|
<Box xcss={listItemPreviewStyles}>{item.label}</Box>,
|
||||||
|
draggableState.container
|
||||||
|
)}
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getItemRegistry() {
|
||||||
|
const registry = new Map<string, HTMLElement>();
|
||||||
|
|
||||||
|
function register({ itemId, element }: ItemEntry) {
|
||||||
|
registry.set(itemId, element);
|
||||||
|
|
||||||
|
return function unregister() {
|
||||||
|
registry.delete(itemId);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getElement(itemId: string): HTMLElement | null {
|
||||||
|
return registry.get(itemId) ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return { register, getElement };
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListState = {
|
||||||
|
items: Item[];
|
||||||
|
lastCardMoved: {
|
||||||
|
item: Item;
|
||||||
|
previousIndex: number;
|
||||||
|
currentIndex: number;
|
||||||
|
numberOfItems: number;
|
||||||
|
} | null;
|
||||||
|
};
|
||||||
|
export const ListBetterDragDrop: FC<{
|
||||||
|
data: any[];
|
||||||
|
onChange: (data: any) => void | Promise<void>;
|
||||||
|
className?: string;
|
||||||
|
classContainer?: string;
|
||||||
|
children: (data?: any, index?: number) => any;
|
||||||
|
classDragBtn?: string;
|
||||||
|
}> = ({
|
||||||
|
children,
|
||||||
|
data,
|
||||||
|
onChange,
|
||||||
|
className,
|
||||||
|
classContainer,
|
||||||
|
classDragBtn,
|
||||||
|
}) => {
|
||||||
|
const [item, setItem] = useState(data);
|
||||||
|
|
||||||
|
const [{ items, lastCardMoved }, setListState] = useState<ListState>({
|
||||||
|
items: data,
|
||||||
|
lastCardMoved: null,
|
||||||
|
});
|
||||||
|
const [registry] = useState(getItemRegistry);
|
||||||
|
|
||||||
|
// Isolated instances of this component from one another
|
||||||
|
const [instanceId] = useState(() => Symbol("instance-id"));
|
||||||
|
|
||||||
|
const reorderItem = useCallback(
|
||||||
|
({
|
||||||
|
startIndex,
|
||||||
|
indexOfTarget,
|
||||||
|
closestEdgeOfTarget,
|
||||||
|
}: {
|
||||||
|
startIndex: number;
|
||||||
|
indexOfTarget: number;
|
||||||
|
closestEdgeOfTarget: Edge | null;
|
||||||
|
}) => {
|
||||||
|
const finishIndex = getReorderDestinationIndex({
|
||||||
|
startIndex,
|
||||||
|
closestEdgeOfTarget,
|
||||||
|
indexOfTarget,
|
||||||
|
axis: "vertical",
|
||||||
|
});
|
||||||
|
|
||||||
|
if (finishIndex === startIndex) {
|
||||||
|
// If there would be no change, we skip the update
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setListState((listState) => {
|
||||||
|
const item = listState.items[startIndex];
|
||||||
|
|
||||||
|
return {
|
||||||
|
items: reorder({
|
||||||
|
list: listState.items,
|
||||||
|
startIndex,
|
||||||
|
finishIndex,
|
||||||
|
}),
|
||||||
|
lastCardMoved: {
|
||||||
|
item,
|
||||||
|
previousIndex: startIndex,
|
||||||
|
currentIndex: finishIndex,
|
||||||
|
numberOfItems: listState.items.length,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
const moveItem = (fromIndex: any, toIndex: any) => {
|
||||||
|
setItem((prevItems) => {
|
||||||
|
const updatedItems = [...prevItems];
|
||||||
|
const [movedItem] = updatedItems.splice(fromIndex, 1); // Hapus elemen
|
||||||
|
updatedItems.splice(toIndex, 0, movedItem); // Masukkan ke target index
|
||||||
|
return updatedItems;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
// finishIndex === startIndex
|
||||||
|
moveItem(startIndex, finishIndex);
|
||||||
|
onChange(items);
|
||||||
|
},
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
console.log(data);
|
||||||
|
return monitorForElements({
|
||||||
|
canMonitor({ source }) {
|
||||||
|
return isItemData(source.data) && source.data.instanceId === instanceId;
|
||||||
|
},
|
||||||
|
onDrop({ location, source }) {
|
||||||
|
const target = location.current.dropTargets[0];
|
||||||
|
if (!target) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sourceData = source.data;
|
||||||
|
const targetData = target.data;
|
||||||
|
if (!isItemData(sourceData) || !isItemData(targetData)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const indexOfTarget = items.findIndex(
|
||||||
|
(item) => item.id === targetData.item.id
|
||||||
|
);
|
||||||
|
if (indexOfTarget < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const closestEdgeOfTarget = extractClosestEdge(targetData);
|
||||||
|
|
||||||
|
reorderItem({
|
||||||
|
startIndex: sourceData.index,
|
||||||
|
indexOfTarget,
|
||||||
|
closestEdgeOfTarget,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}, [instanceId, items, reorderItem]);
|
||||||
|
|
||||||
|
// once a drag is finished, we have some post drop actions to take
|
||||||
|
useEffect(() => {
|
||||||
|
if (lastCardMoved === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { item, previousIndex, currentIndex, numberOfItems } = lastCardMoved;
|
||||||
|
const element = registry.getElement(item.id);
|
||||||
|
if (element) {
|
||||||
|
triggerPostMoveFlash(element);
|
||||||
|
}
|
||||||
|
}, [lastCardMoved, registry]);
|
||||||
|
|
||||||
|
// cleanup the live region when this component is finished
|
||||||
|
useEffect(() => {
|
||||||
|
return function cleanup() {
|
||||||
|
liveRegion.cleanup();
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const getListLength = useCallback(() => items.length, [items.length]);
|
||||||
|
|
||||||
|
const contextValue: ListContextValue = useMemo(() => {
|
||||||
|
return {
|
||||||
|
registerItem: registry.register,
|
||||||
|
reorderItem,
|
||||||
|
instanceId,
|
||||||
|
getListLength,
|
||||||
|
};
|
||||||
|
}, [registry.register, reorderItem, instanceId, getListLength]);
|
||||||
|
if (!items?.length) return <></>;
|
||||||
|
return (
|
||||||
|
<ListContext.Provider value={contextValue}>
|
||||||
|
<div className={cn("flex flex-col gap-y-1 w-full", classContainer)}>
|
||||||
|
{items.map((item, index) => (
|
||||||
|
<ListItem
|
||||||
|
key={item.id}
|
||||||
|
item={item}
|
||||||
|
index={index}
|
||||||
|
position={getItemPosition({ index, items })}
|
||||||
|
children={children}
|
||||||
|
className={className}
|
||||||
|
classDragBtn={classDragBtn}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</ListContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -3,6 +3,11 @@
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@atlaskit/pragmatic-drag-and-drop-flourish": "^1.2.0",
|
||||||
|
"@atlaskit/pragmatic-drag-and-drop-hitbox": "^1.0.3",
|
||||||
|
"@atlaskit/pragmatic-drag-and-drop-live-region": "^1.3.0",
|
||||||
|
"@atlaskit/pragmatic-drag-and-drop-react-accessibility": "^1.3.1",
|
||||||
|
"@atlaskit/pragmatic-drag-and-drop-react-drop-indicator": "^1.2.0",
|
||||||
"@emotion/css": "^11.13.5",
|
"@emotion/css": "^11.13.5",
|
||||||
"@faker-js/faker": "^9.2.0",
|
"@faker-js/faker": "^9.2.0",
|
||||||
"@floating-ui/react": "^0.26.28",
|
"@floating-ui/react": "^0.26.28",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue