The Draggable kit gives you a full subcomponent structure that allows it to be used with almost any kits.
DraggableProvider
= This provider manages all settings that allows drag and drop to function and must be used as the outermost wrapper. It has 2 REQUIRED props: initialItems
(initial data) and onReorder
(function that returns mutated data as items are reordered via drag and drop). Devs must manage state as shown.
Draggable.Container
= This specifies the container within which items can be dropped.
Draggable.Item
= This specifies the items that can be dragged and dropped. dragId
is a REQUIRED prop for Draggable.Item.
import React, { useState } from "react"; import { Flex, Image, Draggable, DraggableProvider } from "playbook-ui"; // Initial items to be dragged const data = [ { id: "21", url: "https://unsplash.it/500/400/?image=633", }, { id: "22", url: "https://unsplash.it/500/400/?image=634", }, { id: "23", url: "https://unsplash.it/500/400/?image=637", }, ]; const DraggableDefault = (props) => { const [initialState, setInitialState] = useState(data); return ( <> <DraggableProvider initialItems={data} onReorder={(items) => setInitialState(items)} > <Draggable.Container> <Flex> {initialState.map(({ id, url }) => ( <Draggable.Item dragId={id} key={id} > <Image alt={id} margin="xs" size="md" url={url} /> </Draggable.Item> ))} </Flex> </Draggable.Container> </DraggableProvider> </> ); }; export default DraggableDefault;
For a simplified version of the Draggable API for the List kit, you can do the following:
Use DraggableProvider
and manage state as shown.
The List kit is optimized to work with the draggable kit. To enable drag, use the enableDrag
prop on List kit AND dragId
prop on ListItem. An additional optional boolean prop (set to true by default) of dragHandle
is also available on List kit to show the drag handle icon.
import React, { useState } from "react"; import { DraggableProvider, List, ListItem } from "playbook-ui"; // Initial items to be dragged const data = [ { id: "31", text: "Philadelphia", }, { id: "32", text: "New Jersey", }, { id: "33", text: "Maryland", }, { id: "34", text: "Connecticut", }, ]; const DraggableWithList = (props) => { const [initialState, setInitialState] = useState(data); return ( <> <DraggableProvider initialItems={data} onReorder={(items) => setInitialState(items)} > <List enableDrag > {initialState.map(({ id, text }) => ( <ListItem dragId={id} key={id} > {text} </ListItem> ))} </List> </DraggableProvider> </> ); }; export default DraggableWithList;
For a simplified version of the Draggable API for the SelectableList kit, you can do the following:
Use DraggableProvider
and manage state as shown.
The SelectableList kit is optimized to work with the draggable kit. To enable drag, use the enableDrag
prop on SelectableList kit AND dragId
prop on SelectableList.Item. An additional optional boolean prop (set to true by default) of dragHandle
is also available on SelectableList kit to show the drag handle icon.
import React, { useState } from "react"; import { SelectableList, DraggableProvider } from "playbook-ui"; // Initial items to be dragged const data = [ { id: "41", text: "Task 1", }, { id: "42", text: "Task 2", }, { id: "43", text: "Task 3", }, { id: "44", text: "Task 4", }, ]; const DraggableWithSelectableList = (props) => { const [initialState, setInitialState] = useState(data); return ( <> <DraggableProvider initialItems={data} onReorder={(items) => setInitialState(items)} > <SelectableList enableDrag variant="radio" > {initialState.map(({ id, text }) => ( <SelectableList.Item dragId={id} key={id} label={text} name="radio-test" value={id} /> ))} </SelectableList> </DraggableProvider> </> ); }; export default DraggableWithSelectableList
For a simplified version of the Draggable API for the Card kit, you can do the following:
Use DraggableProvider
and manage state as shown.
Draggable.Container
creates the container within which the cards can be dragged and dropped.
The Card kit is optimized to work with the draggable kit. To enable drag, use the draggableItem
and dragId
props on the Card kit as shown. An additional optional boolean prop (set to true by default) of dragHandle
is also available to show the drag handle icon.
import React, { useState } from "react"; import { Flex, Badge, Title, Icon, Draggable, DraggableProvider, Card, Caption, } from "playbook-ui"; // Initial items to be dragged const data = [ { id: "21", text: "Joe Black", }, { id: "22", text: "Nancy White", }, { id: "23", text: "Bill Green", }, ]; const DraggableWithCards = (props) => { const [initialState, setInitialState] = useState(data); return ( <DraggableProvider initialItems={data} onReorder={(items) => setInitialState(items)} > <Draggable.Container > {initialState.map(({ id, text }) => ( <Card dragId={id} draggableItem highlight={{ color: "primary", position: "side" }} key={id} marginBottom="xs" padding="xs" > <Flex alignItems="stretch" flexDirection="column" > <Flex gap="xs"> <Title size={4} text={text} /> <Badge text="35-12345" variant="primary" /> </Flex> <Caption size="xs" text="8:00A • Township Name • 90210" /> <Flex gap="xxs" spacing="between" > <Flex gap="xxs"> <Caption color="error" size="xs" > <Icon icon="house-circle-exclamation" /> </Caption> <Caption color="success" size="xs"> <Icon icon="file-circle-check" /> </Caption> </Flex> <Flex> <Badge rounded text="Schedule QA" variant="warning" /> <Badge rounded text="Flex" variant="primary" /> <Badge rounded text="R99" variant="primary" /> </Flex> </Flex> </Flex> </Card> ))} </Draggable.Container> </DraggableProvider> ); }; export default DraggableWithCards;
The Draggable kit can also be used to achieve more complex, multiple container functionality as shown here. This complex usage requires the full subcomponent structure.
import React, { useState } from "react"; import { Flex, Caption, Card, FlexItem, Badge, Avatar, Title, Body, Draggable, DraggableProvider, } from "playbook-ui"; // Initial groups to drag between const containers = ["To Do", "In Progress", "Done"]; // Initial items to be dragged const data = [ { id: "11", container: "To Do", title: "Task 1", description: "Bug fixes", assignee_name: "Terry Miles", assignee_img: "https://randomuser.me/api/portraits/men/44.jpg", }, { id: "12", container: "To Do", title: "Task 2", description: "Documentation", assignee_name: "Sophia Miles", assignee_img: "https://randomuser.me/api/portraits/women/8.jpg", }, { id: "13", container: "In Progress", title: "Task 3", description: "Add a variant", assignee_name: "Alice Jones", assignee_img: "https://randomuser.me/api/portraits/women/10.jpg", }, { id: "14", container: "To Do", title: "Task 4", description: "Add jest tests", assignee_name: "Mike James", assignee_img: "https://randomuser.me/api/portraits/men/8.jpg", }, { id: "15", container: "Done", title: "Task 5", description: "Alpha testing", assignee_name: "James Guy", assignee_img: "https://randomuser.me/api/portraits/men/18.jpg", }, { id: "16", container: "In Progress", title: "Task 6", description: "Release", assignee_name: "Sally Jones", assignee_img: "https://randomuser.me/api/portraits/women/28.jpg", }, ]; const DraggableMultipleContainer = (props) => { const [initialState, setInitialState] = useState(data); const badgeProperties = (container) => { switch (container) { case "To Do": return { text: "queue", color: "warning" }; case "In Progress": return { text: "progress", color: "primary" }; default: return { text: "done", color: "success" }; } }; return ( <DraggableProvider initialItems={data} onReorder={(items) => setInitialState(items)} > <Flex justifyContent="center" > {containers?.map((container) => ( <Draggable.Container container={container} htmlOptions={{style:{ width: "200px", height: "70vh"}}} key={container} padding="sm" > <Caption textAlign="center">{container}</Caption> <Flex alignItems="stretch" orientation="column" > {initialState .filter((item) => item.container === container) .map( ({ assignee_img, assignee_name, description, id, title, }) => ( <Draggable.Item container={container} dragId={id} key={id} > <Card marginBottom="sm" padding="sm" > <Flex justify="between"> <FlexItem> <Flex> <Avatar imageUrl={assignee_img} name={assignee_name} size="xxs" /> <Title paddingLeft="xs" size={4} text={title} /> </Flex> </FlexItem> <Badge marginLeft="sm" rounded text={badgeProperties(container).text} variant={badgeProperties(container).color} /> </Flex> <Body paddingTop="xs" text={description} /> </Card> </Draggable.Item> ) )} </Flex> </Draggable.Container> ))} </Flex> </DraggableProvider> ); }; export default DraggableMultipleContainer;