Dispatch does not update array fields correctly
Description
When using the replace action of dispatch, the array fields in the sidebar do not update for the selected environment
We have custom copy/paste functionality that saves a component's props to the clipboard on copy and dispatches a replace action on paste. I'm running into an issue when pasting array fields -- the component's actual props update correctly but the fields in the sidebar do not.
Environment
- Puck version: 0.0.20
Steps to reproduce
- Add this component
Test: {
label: "Test",
fields: {
example: {
type: "custom",
render: () => {
const getPuck = useGetPuck();
const copyToClipboard = () => {
const { appState, getItemBySelector } = getPuck();
if (!appState.ui.itemSelector) {
return;
}
const selectedComponent = getItemBySelector(
appState.ui.itemSelector
);
navigator.clipboard.writeText(
JSON.stringify(selectedComponent, null, 2)
);
};
const pasteFromClipboard = async () => {
const { appState, dispatch, getItemBySelector } = getPuck();
const rawClipboardText = await navigator.clipboard.readText();
const pastedData = JSON.parse(rawClipboardText);
if (!appState.ui.itemSelector || !appState.ui.itemSelector.zone) {
return;
}
const selectedComponent = getItemBySelector({
index: appState.ui.itemSelector?.index,
zone: appState.ui.itemSelector?.zone,
});
dispatch({
type: "replace",
destinationZone: appState.ui.itemSelector.zone,
destinationIndex: appState.ui.itemSelector.index,
data: {
type: pastedData.type,
props: {
...pastedData.props,
id: selectedComponent?.props.id,
},
},
});
};
return (
<div>
<button
onClick={copyToClipboard}
style={{ margin: 8, padding: 8, border: "2px solid black" }}
>
Copy
</button>
<button
onClick={pasteFromClipboard}
style={{ margin: 8, padding: 8, border: "2px solid black" }}
>
Paste
</button>
</div>
);
},
},
list: {
type: "array",
arrayFields: {
text: {
type: "text",
},
},
getItemSummary: (item: any, index?: number) => {
return item.text || `Item ${index}`;
},
},
},
render: (props) => {
return (
<div style={{ margin: 16 }}>
{props?.list?.length ? (
props.list.map((l: any) => l.text).join(",")
) : (
<div style={{ height: 32 }} />
)}
</div>
);
},
defaultProps: {
list: [],
},
},
- Drag two instances of the component onto the page
- Add n pieces of data to the first component and n-1 pieces of data to the second component
- Copy the second component and paste into the first component
What happens
The actual props/rendering for the component update correctly but the fields in the sidebar do not.
What I expect to happen
The data in the sidebar and the data being rendered should match.
Additional Media
https://jam.dev/c/0ebba475-ed44-4e8f-9327-afbbf57eb576
Hey @benlife5! Thanks for opening this issue and reporting the bug.
I can confirm that I can reproduce this with Puck 0.20.2.
Interestingly this doesn't happen if the paste target is empty.
This PR might resolve the issue once it's finished, mentioning it here as a reminder to test this again once it's more mature: #1213