puck
puck copied to clipboard
Adding up/down and add buttons in Action Bar
These features can Puck Actionbar which can be implemented using the override prop but it would be better if they are included by default.
1. Having the ability to move your component up and down using arrows is usually provided with most drag n drop editors.
For example:
Shopify Actionbar
WordPress Actionbbar
Puck Implementation
I have implemented it using the override:
import { rootDroppableId } from "@/puck/lib/root-droppable-id";
import { IconButton, usePuck } from "@measured/puck";
import { ReactNode, memo } from "react";
import { LuChevronDown, LuChevronUp } from "react-icons/lu";
import { ActionBar as PuckActionBar } from "@measured/puck";
export default function ActionBar({
label,
children,
}: {
label?: string;
children: ReactNode;
}) {
const {
appState: {
ui: { itemSelector },
data,
},
dispatch,
} = usePuck();
if (!itemSelector) return null;
const upDisabled = itemSelector?.index === 0;
const downDisabled =
(itemSelector.zone && itemSelector?.zone !== rootDroppableId && data.zones
? data.zones[itemSelector.zone]?.length
: data.content.length) ===
itemSelector.index + 1;
return (
<PuckActionBar label={label}>
<IconButton
onClick={() => {
dispatch({
type: "reorder",
sourceIndex: itemSelector.index,
destinationIndex: itemSelector.index - 1,
destinationZone: itemSelector.zone || rootDroppableId,
});
dispatch({
type: "setUi",
ui: (ui) => ({
...ui,
itemSelector: { ...itemSelector, index: itemSelector.index - 1 },
}),
});
}}
title="Move Up"
disabled={upDisabled}
>
<LuChevronUp />
</IconButton>
<IconButton
onClick={() => {
dispatch({
type: "reorder",
sourceIndex: itemSelector.index,
destinationIndex: itemSelector.index + 1,
destinationZone: itemSelector.zone || rootDroppableId,
});
dispatch({
type: "setUi",
ui: (ui) => ({
...ui,
itemSelector: { ...itemSelector, index: itemSelector.index + 1 },
}),
});
}}
title="Move Down"
disabled={downDisabled}
>
<LuChevronDown />
</IconButton>
{children}
</PuckActionBar>
);
}
2. Adding components before and after the selected component via the action bar.
<IconButton
onClick={() => {
addModal.dispatch({
type: "open",
payload: {
addComponent: (component) =>
dispatch({
type: "insert",
destinationZone: props.zone || rootDroppableId,
destinationIndex:
props.zone && props.zone !== rootDroppableId
? appState.data.zones?.[props.zone]?.length || 0
: appState.data.content.length,
componentType: component,
}),
},
});
}}
title="Add"
>
<LuPlus />
</IconButton>
Where add component opens a popup asks to which component to add and whether to add it before or after the component.
Again implementing these features is entierly possible using the override prop. It would be better to include them from accessibility point of view. What are your thoughts about this?
Love this suggestion, and adding it to the core action set would be fantastic. Going to mark this as Ready as I think it's pretty clear.