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 in conjunction with the table kit to create draggable table rows. To do this:
DraggableProvider
and manage state as shown. draggableContainer
prop on the Table.Body to designate it as the Draggable ContainerdraggableItem
prop on the Table.Row to designate it as the Draggable Item. Make sure to also pass id to the dragId
prop here. import React, { useState } from "react"; import { Flex, Table, Body, Avatar, DraggableProvider } from "playbook-ui"; // Initial items to be dragged const data = [ { id: "1", task: "Task 1", assignee_name: "Terry Miles", assignee_img: "https://randomuser.me/api/portraits/men/44.jpg", }, { id: "2", task: "Task 2", assignee_name: "Sophia Miles", assignee_img: "https://randomuser.me/api/portraits/women/8.jpg", }, { id: "3", task: "Task 3", assignee_name: "Alice Jones", assignee_img: "https://randomuser.me/api/portraits/women/10.jpg", }, { id: "4", task: "Task 4", assignee_name: "Mike James", assignee_img: "https://randomuser.me/api/portraits/men/8.jpg", }, { id: "5", task: "Task 5", assignee_name: "James Guy", assignee_img: "https://randomuser.me/api/portraits/men/18.jpg", } ]; const DraggableWithTableReact = (props) => { const [initialState, setInitialState] = useState(data); return ( <> <DraggableProvider initialItems={data} onReorder={(items) => setInitialState(items)} > <Table responsive="none" size="sm" > <Table.Head> <Table.Row> <Table.Header>{"id"}</Table.Header> <Table.Header>{"name"}</Table.Header> <Table.Header>{"task number"}</Table.Header> </Table.Row> </Table.Head> <Table.Body draggableContainer> {initialState.map(({ id, task, assignee_name, assignee_img }) => ( <Table.Row dragId={id} draggableItem key={id} > <Table.Cell>{id}</Table.Cell> <Table.Cell> <Flex align="center"> <Avatar imageUrl={assignee_img} size="xs" /> <Body paddingLeft="xxs" text={assignee_name} /> </Flex> </Table.Cell> <Table.Cell>{task}</Table.Cell> </Table.Row> ))} </Table.Body> </Table> </DraggableProvider> </> ); }; export default DraggableWithTableReact;
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;