import { Fragment, JSXElementConstructor, ReactElement, useEffect, useState } from "react"; import { Field, FieldProps, Focusable, GamepadButton } from "../deck-components"; export type ReorderableEntry = { label: string, data?:T, position:number } type ListProps = { entries: ReorderableEntry[], onSave: (entries: ReorderableEntry[]) => void, interactables?: JSXElementConstructor<{entry:ReorderableEntry}>, fieldProps?: FieldProps } /** * A component for creating reorderable lists. * * Implementation example can be found {@link https://github.com/Tormak9970/Component-Testing-Plugin/blob/main/src/testing-window/ReorderableListTest.tsx here}. */ export function ReorderableList(props: ListProps) { const [entryList, setEntryList] = useState[]>(props.entries.sort((a:ReorderableEntry, b:ReorderableEntry) => a.position - b.position)); const [reorderEnabled, setReorderEnabled] = useState(false); useEffect(() => { setEntryList(props.entries.sort((a: ReorderableEntry, b: ReorderableEntry) => a.position - b.position)); }, [props.entries]); function toggleReorderEnabled(): void { let newReorderValue = !reorderEnabled; setReorderEnabled(newReorderValue); if (!newReorderValue){ props.onSave(entryList); } } return (
{ entryList.map((entry: ReorderableEntry) => ( {props.interactables ? : null} )) }
); } type ListEntryProps = { fieldProps?: FieldProps, listData: ReorderableEntry[], entryData: ReorderableEntry, reorderEntryFunc: CallableFunction, reorderEnabled: boolean, children: ReactElement | null } function ReorderableItem(props: ListEntryProps) { const listEntries = props.listData; function onReorder(e: Event): void { if (!props.reorderEnabled) return; const event = e as CustomEvent; const currentIdx = listEntries.findIndex((entryData: ReorderableEntry) => entryData === props.entryData); const currentIdxValue = listEntries[currentIdx]; if (currentIdx < 0) return; let targetPosition: number = -1; if (event.detail.button == GamepadButton.DIR_DOWN) { targetPosition = currentIdxValue.position+1; } else if (event.detail.button == GamepadButton.DIR_UP) { targetPosition = currentIdxValue.position-1; } if (targetPosition >= listEntries.length || targetPosition < 0) return; let otherToUpdate = listEntries.find((entryData: ReorderableEntry) => entryData.position === targetPosition); if (!otherToUpdate) return; let currentPosition = currentIdxValue.position; currentIdxValue.position = otherToUpdate.position; otherToUpdate.position = currentPosition; props.reorderEntryFunc([...listEntries].sort((a:ReorderableEntry, b:ReorderableEntry) => a.position - b.position)); } const baseCssProps = { display: "flex", flexDirection: "row", justifyContent: "space-between", width: "100%" }; return( // @ts-ignore {props.children} ); }