diff --git a/src/components/client/Account.tsx b/src/components/client/Account.tsx index 593bc14..3f61bb2 100644 --- a/src/components/client/Account.tsx +++ b/src/components/client/Account.tsx @@ -21,15 +21,17 @@ import { removeFrom } from "../../models/sortable"; import { TransactionState } from "../../models/state"; import { IAccount } from "../../models/web3"; import { ExplorerButton } from "../common/ExplorerButton"; -import { SortableItemProps } from "../common/SortableItem"; +import { SortableItemContext } from "../common/Sortable"; import { ToggleIconButton } from "../common/ToggleIconButton"; import { TruncatableEditable } from "../common/TruncatableEditable"; import { InstructionContext } from "./Instructions"; -export const Account: React.FC< - { data: IAccount; index: number } & SortableItemProps -> = ({ data, index, attributes, listeners, setNodeRef, style }) => { +export const Account: React.FC<{ data: IAccount; index: number }> = ({ + data, + index, +}) => { const instruction = useContext(InstructionContext); + const { listeners, attributes } = useContext(SortableItemContext); const account = (state: WritableDraft) => state.transaction.instructions.map[instruction.id].accounts.map[data.id]; @@ -42,7 +44,7 @@ export const Account: React.FC< const isWallet = data.pubkey === walletPubkey?.toBase58(); return ( - + { }} > {toSortedArray(instruction.accounts).map((account, index) => ( - - - + ))} diff --git a/src/components/client/Instruction.tsx b/src/components/client/Instruction.tsx index 9959fec..2582c7f 100644 --- a/src/components/client/Instruction.tsx +++ b/src/components/client/Instruction.tsx @@ -11,19 +11,15 @@ import { useOptionsStore } from "../../hooks/useOptionsStore"; import { useTransactionStore } from "../../hooks/useTransactionStore"; import { instructionGetter } from "../../models/state"; import { ExplorerButton } from "../common/ExplorerButton"; -import { SortableItemProps } from "../common/SortableItem"; +import { SortableItemContext } from "../common/Sortable"; import { Accounts } from "./Accounts"; import { Data } from "./Data"; import { InstructionHeader } from "./InstructionHeader"; import { InstructionContext } from "./Instructions"; -export const Instruction: React.FC = ({ - attributes, - listeners, - setNodeRef, - style, -}) => { +export const Instruction: React.FC = () => { const instruction = useContext(InstructionContext); + const { listeners, attributes } = useContext(SortableItemContext); const network = useOptionsStore( (state) => state.transactionOptions.rpcEndpoint.network ); @@ -36,8 +32,6 @@ export const Instruction: React.FC = ({ return ( { {toSortedArray(transaction.instructions).map((instruction) => ( // key must be stable so it can't be loop index - - - + ))} diff --git a/src/components/common/Sortable.tsx b/src/components/common/Sortable.tsx index 1be8c7e..8984aa8 100644 --- a/src/components/common/Sortable.tsx +++ b/src/components/common/Sortable.tsx @@ -1,36 +1,44 @@ +import { Box } from "@chakra-ui/react"; import { closestCenter, DndContext, DragEndEvent, + DraggableAttributes, KeyboardSensor, MeasuringStrategy, PointerSensor, useSensor, useSensors, } from "@dnd-kit/core"; +import { SyntheticListenerMap } from "@dnd-kit/core/dist/hooks/utilities"; import { restrictToParentElement, restrictToVerticalAxis, } from "@dnd-kit/modifiers"; import { arrayMove, + defaultAnimateLayoutChanges, SortableContext, sortableKeyboardCoordinates, + useSortable, verticalListSortingStrategy, } from "@dnd-kit/sortable"; +import { CSS } from "@dnd-kit/utilities"; import React from "react"; import { IID } from "../../models/sortable"; -export const SortableItemContext = React.createContext(""); +export const SortableItemContext = React.createContext<{ + attributes?: DraggableAttributes; + listeners?: SyntheticListenerMap; +}>({}); /** - * Sortable container. All sortable items should be under this. + * Makes the children into a drag-n-drop sortable vertical list. * - * For this to work ensure that: - * - Each item is wrapped in `` - * - Each item accepts `SortableItemProps` + * The only thing the child items need to do is to explode `attributes` + * and `listeners` from `SortableItemContext` into the drag handle. * - * See `` and `` for an example + * See `` and `` for an example. */ export const Sortable: React.FC<{ itemOrder: IID[]; @@ -66,11 +74,36 @@ export const Sortable: React.FC<{ > {React.Children.map(children, (child, index) => ( - + {child} - + ))} ); }; + +const SortableItem: React.FC<{ + id: IID; + children: React.ReactNode; +}> = ({ id, children }) => { + const { attributes, listeners, setNodeRef, transform, transition } = + useSortable({ + id, + animateLayoutChanges: (args) => + defaultAnimateLayoutChanges({ ...args, wasDragging: true }), + }); + + const style = { + transform: CSS.Translate.toString(transform), + transition, + }; + + return ( + + + {children} + + + ); +}; diff --git a/src/components/common/SortableItem.tsx b/src/components/common/SortableItem.tsx deleted file mode 100644 index 492236f..0000000 --- a/src/components/common/SortableItem.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import { DraggableAttributes } from "@dnd-kit/core"; -import { SyntheticListenerMap } from "@dnd-kit/core/dist/hooks/utilities"; -import { defaultAnimateLayoutChanges, useSortable } from "@dnd-kit/sortable"; -import { CSS } from "@dnd-kit/utilities"; -import React, { useContext } from "react"; -import { SortableItemContext } from "./Sortable"; - -/** - * Each sortable item should accept these props - * - * `id` should be provided by user. The rest is set by `` - */ -export type SortableItemProps = { - attributes?: DraggableAttributes; - listeners?: SyntheticListenerMap; - setNodeRef?: (node: HTMLElement | null) => void; - style?: React.CSSProperties; -}; - -// This has to be its own component that user wraps the items in, -// in case the actual sortable item is not an immediate child, i.e. -// a few levels down. - -/** - * Each sortable item inside `` should be wrapped in this. - */ -export const SortableItem: React.FC<{ - children: React.ReactElement; -}> = ({ children }) => { - const id = useContext(SortableItemContext); - const { attributes, listeners, setNodeRef, transform, transition } = - useSortable({ - id, - animateLayoutChanges: (args) => - defaultAnimateLayoutChanges({ ...args, wasDragging: true }), - }); - - const style = { - transform: CSS.Translate.toString(transform), - transition, - }; - - return React.cloneElement(children, { - attributes, - listeners, - setNodeRef, - style, - }); -};