I am creating a nested sortable list in react using the dnd package. Each item inside the draggable contains input fields wrapped inside the Disclosure component from @headlessui. I am updating the item value with onChange on each input field.
The item field is updating on every input but the problem is disclosure panel closes immediately on keystroke. The issue is probably due to rerendering the list I simply tried making a list of the Disclosure panels without dnd and it doesn't close the Disclosure panel on input.
I have reproduced the issue in repl.it sample and I think it's too long to post code here.
export default function App() {
const [items, setItems] = useState([
{id: 1, title: 'My Item 1'},
{id: 2, title: 'My Item 2'},
{id: 3, title: 'My Item 3'},
{id: 4, title: 'My Item 4'},
]);
const handleInputChange = (e, item) => {
const {name, value} = event.target;
setItems(prev =>
[
...prev.map((elm) => {
if (elm.id === item.id) {
elm[name] = value;
}
return elm;
})
]
)
}
return (
<main>
<SortableTree
items={items}
onItemsChanged={setItems}
TreeItemComponent={forwardRef((props, ref) => {
return (
<SimpleTreeItemWrapper
{...props}
showDragHandle={false}
disableCollapseOnItemClick={true}
hideCollapseButton={true}
indentationWidth={20}
ref={ref}
className={"w-[400px]"}
>
<Disclosure as="div" className={"w-full mb-2"}>
{({ open }) => (
<>
<Disclosure.Button
open={true}
className="flex items-center w-full justify-between bg-[#F6F7F7] border border-gray-200 px-3 py-2 text-left text-xs font-medium text-gray-600 shadow-sm hover:border-gray-400 focus:outline-none focus-visible:ring focus-visible:ring-purple-500 focus-visible:ring-opacity-75"
>
<span>{props.item.title}</span>
<ChevronUpIcon
className={`${
open ? "rotate-180 transform" : ""
} h-5 w-5 text-gray-500`}
/>
</Disclosure.Button>
<Disclosure.Panel className="px-4 pt-4 pb-2 text-sm text-gray-500">
<div className="flex flex-col mb-2">
<label
htmlFor="nav_label"
className="text-xs mb-1"
>
Navigation Label
</label>
<input
onChange={(e) => handleInputChange(e, props.item)}
name='title'
type={"text"}
className="px-2 py-1 border border-gray-400"
value={props.item.title}
/>
</div>
<div className="">
<button
className="text-red-500 text-xs"
>
Remove
</button>
</div>
</Disclosure.Panel>
</>
)}
</Disclosure>
</SimpleTreeItemWrapper>
);
})}
/>
</main>
)
}