Skip to content

Commit

Permalink
feat: simplify sortable component
Browse files Browse the repository at this point in the history
  • Loading branch information
sohrab- committed Jul 21, 2022
1 parent 1749c67 commit 55ec85e
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 79 deletions.
12 changes: 7 additions & 5 deletions src/components/client/Account.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<TransactionState>) =>
state.transaction.instructions.map[instruction.id].accounts.map[data.id];

Expand All @@ -42,7 +44,7 @@ export const Account: React.FC<
const isWallet = data.pubkey === walletPubkey?.toBase58();

return (
<Flex mb="2" ref={setNodeRef} style={style}>
<Flex mb="2">
<DragHandleIcon h="3" w="3" mt="3.5" {...attributes} {...listeners} />
<Text
ml="2"
Expand Down
5 changes: 1 addition & 4 deletions src/components/client/Accounts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import { addTo, toSortedArray } from "../../models/sortable";
import { instructionGetter } from "../../models/state";
import { newAccount } from "../../models/web3";
import { Sortable } from "../common/Sortable";
import { SortableItem } from "../common/SortableItem";
import { Account } from "./Account";
import { InstructionContext } from "./Instructions";

Expand Down Expand Up @@ -73,9 +72,7 @@ export const Accounts: React.FC = () => {
}}
>
{toSortedArray(instruction.accounts).map((account, index) => (
<SortableItem key={account.id}>
<Account data={account} index={index} />
</SortableItem>
<Account data={account} index={index} key={account.id} />
))}
</Sortable>
</Box>
Expand Down
12 changes: 3 additions & 9 deletions src/components/client/Instruction.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<SortableItemProps> = ({
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
);
Expand All @@ -36,8 +32,6 @@ export const Instruction: React.FC<SortableItemProps> = ({

return (
<Grid
ref={setNodeRef}
style={style}
mb="2"
p="5"
border="1px"
Expand Down
5 changes: 1 addition & 4 deletions src/components/client/Instructions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { useTransactionStore } from "../../hooks/useTransactionStore";
import { IID, toSortedArray } from "../../models/sortable";
import { newInstruction } from "../../models/web3";
import { Sortable } from "../common/Sortable";
import { SortableItem } from "../common/SortableItem";
import { Instruction } from "./Instruction";

export const InstructionContext = React.createContext(newInstruction());
Expand All @@ -30,9 +29,7 @@ export const Instructions: React.FC = () => {
{toSortedArray(transaction.instructions).map((instruction) => (
// key must be stable so it can't be loop index
<InstructionContext.Provider value={instruction} key={instruction.id}>
<SortableItem>
<Instruction />
</SortableItem>
<Instruction />
</InstructionContext.Provider>
))}
</Sortable>
Expand Down
49 changes: 41 additions & 8 deletions src/components/common/Sortable.tsx
Original file line number Diff line number Diff line change
@@ -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 `<Sortable>`
* - 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 `<Accounts>` and `<Account>` for an example
* See `<Accounts>` and `<Account>` for an example.
*/
export const Sortable: React.FC<{
itemOrder: IID[];
Expand Down Expand Up @@ -66,11 +74,36 @@ export const Sortable: React.FC<{
>
<SortableContext items={itemOrder} strategy={verticalListSortingStrategy}>
{React.Children.map(children, (child, index) => (
<SortableItemContext.Provider value={itemOrder[index]}>
<SortableItem id={itemOrder[index]} key={itemOrder[index]}>
{child}
</SortableItemContext.Provider>
</SortableItem>
))}
</SortableContext>
</DndContext>
);
};

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 (
<Box ref={setNodeRef} style={style}>
<SortableItemContext.Provider value={{ attributes, listeners }}>
{children}
</SortableItemContext.Provider>
</Box>
);
};
49 changes: 0 additions & 49 deletions src/components/common/SortableItem.tsx

This file was deleted.

0 comments on commit 55ec85e

Please sign in to comment.