Skip to content

Commit

Permalink
update duallistselector example, try exporting interface from separat…
Browse files Browse the repository at this point in the history
…e file
  • Loading branch information
kmcfaul committed Nov 20, 2023
1 parent 6394a55 commit d11d772
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 73 deletions.
16 changes: 2 additions & 14 deletions packages/react-drag-drop/src/components/DragDrop/DragDropSort.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,12 @@ import {
import { Draggable } from './Draggable';
import { DraggableDataListItem } from './DraggableDataListItem';
import { DraggableDualListSelectorListItem } from './DraggableDualListSelectorListItem';
import { DraggableObject } from './DragDropUtil';
import styles from '@patternfly/react-styles/css/components/DragDrop/drag-drop';

export type DragDropSortDragEndEvent = DragEndEvent;
export type DragDropSortDragStartEvent = DragStartEvent;

export interface DraggableObject {
/** Unique id of the draggable object */
id: string;
/** Content rendered in the draggable object */
content: React.ReactNode;
/** Props spread to the rendered wrapper of the draggable object */
props?: any;
}

export interface DragDropSortProps extends DndContextProps {
/** Custom defined content wrapper for draggable items. By default, draggable items are wrapped in a styled div.
* Intended to be a 'DataList' or 'DualListSelectorList' without children. */
Expand Down Expand Up @@ -63,8 +55,6 @@ export const DragDropSort: React.FunctionComponent<DragDropSortProps> = ({
...props
}: DragDropSortProps) => {
const [activeId, setActiveId] = React.useState<string>(null);
// const [dragging, setDragging] = React.useState(false);

const itemIds = React.useMemo(() => (items ? Array.from(items, (item) => item.id as string) : []), [items]);

const getItemById = (id: string): DraggableObject => items.find((item) => item.id === id);
Expand All @@ -81,14 +71,12 @@ export const DragDropSort: React.FunctionComponent<DragDropSortProps> = ({
const oldIndex = itemIds.indexOf(active.id as string);
const newIndex = itemIds.indexOf(over.id as string);
const newItems = arrayMove(items, oldIndex, newIndex);
// setDragging(false);
onDrop(event, newItems, oldIndex, newIndex);
return newItems;
setActiveId(null);
};

const handleDragStart = (event: DragStartEvent) => {
setActiveId(event.active.id as string);
// setDragging(true);
onDrag(event, itemIds.indexOf(event.active.id as string));
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export interface DraggableObject {
/** Unique id of the draggable object */
id: string;
/** Content rendered in the draggable object */
content: React.ReactNode;
/** Props spread to the rendered wrapper of the draggable object */
props?: any;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
DualListSelectorControlsWrapper,
DualListSelectorControl
} from '@patternfly/react-core';
import { DragDropSort, DragDropSortDragEndEvent, DraggableObject } from '@patternfly/react-drag-drop';
import { DragDropSort, DraggableObject } from '@patternfly/react-drag-drop';

import AngleDoubleLeftIcon from '@patternfly/react-icons/dist/esm/icons/angle-double-left-icon';
import AngleLeftIcon from '@patternfly/react-icons/dist/esm/icons/angle-left-icon';
Expand All @@ -16,27 +16,28 @@ import AngleRightIcon from '@patternfly/react-icons/dist/esm/icons/angle-right-i

export const ComposableDualListSelector: React.FunctionComponent = () => {
const [ignoreNextOptionSelect, setIgnoreNextOptionSelect] = React.useState(false);
const [availableOptions, setAvailableOptions] = React.useState([
{ text: 'Apple', selected: false, isVisible: true },
{ text: 'Banana', selected: false, isVisible: true },
{ text: 'Pineapple', selected: false, isVisible: true }
const [availableOptions, setAvailableOptions] = React.useState<DraggableObject[]>([
{ id: 'Apple', content: 'Apple', props: { key: 'Apple', isSelected: false } },
{ id: 'Banana', content: 'Banana', props: { key: 'Banana', isSelected: false } },
{ id: 'Pineapple', content: 'Pineapple', props: { key: 'Pineapple', isSelected: false } }
]);
const [chosenOptions, setChosenOptions] = React.useState([
{ text: 'Orange', selected: false, isVisible: true },
{ text: 'Grape', selected: false, isVisible: true },
{ text: 'Peach', selected: false, isVisible: true },
{ text: 'Strawberry', selected: false, isVisible: true }

const [chosenOptions, setChosenOptions] = React.useState<DraggableObject[]>([
{ id: 'Orange', content: 'Orange', props: { key: 'Orange', isSelected: false } },
{ id: 'Grape', content: 'Grape', props: { key: 'Grape', isSelected: false } },
{ id: 'Peach', content: 'Peach', props: { key: 'Peach', isSelected: false } },
{ id: 'Strawberry', content: 'Strawberry', props: { key: 'Strawberry', isSelected: false } }
]);

const moveSelected = (fromAvailable) => {
const sourceOptions = fromAvailable ? availableOptions : chosenOptions;
const destinationOptions = fromAvailable ? chosenOptions : availableOptions;
for (let i = 0; i < sourceOptions.length; i++) {
const option = sourceOptions[i];
if (option.selected && option.isVisible) {
if (option.props.isSelected) {
sourceOptions.splice(i, 1);
destinationOptions.push(option);
option.selected = false;
option.props.isSelected = false;
i--;
}
}
Expand All @@ -51,11 +52,11 @@ export const ComposableDualListSelector: React.FunctionComponent = () => {

const moveAll = (fromAvailable) => {
if (fromAvailable) {
setChosenOptions([...availableOptions.filter((x) => x.isVisible), ...chosenOptions]);
setAvailableOptions([...availableOptions.filter((x) => !x.isVisible)]);
setChosenOptions([...availableOptions, ...chosenOptions]);
setAvailableOptions([]);
} else {
setAvailableOptions([...chosenOptions.filter((x) => x.isVisible), ...availableOptions]);
setChosenOptions([...chosenOptions.filter((x) => !x.isVisible)]);
setAvailableOptions([...chosenOptions, ...availableOptions]);
setChosenOptions([]);
}
};

Expand All @@ -66,62 +67,39 @@ export const ComposableDualListSelector: React.FunctionComponent = () => {
}
if (isChosen) {
const newChosen = [...chosenOptions];
newChosen[index].selected = !chosenOptions[index].selected;
newChosen[index].props.isSelected = !chosenOptions[index].props.isSelected;
setChosenOptions(newChosen);
} else {
const newAvailable = [...availableOptions];
newAvailable[index].selected = !availableOptions[index].selected;
newAvailable[index].props.isSelected = !availableOptions[index].props.isSelected;
setAvailableOptions(newAvailable);
}
};

const onDrop = (event: DragDropSortDragEndEvent, newItems: DraggableObject[], oldIndex: number, newIndex: number) => {
const newList = [...chosenOptions];
const [removed] = newList.splice(oldIndex, 1);
newList.splice(newIndex, 0, removed);
setChosenOptions(newList);
};

const sortableChosenOptions = chosenOptions.map((option, index) =>
option.isVisible
? {
id: `composable-available-option-${option.text}`,
content: option.text,
props: {
key: index,
isSelected: option.selected,
onOptionSelect: (e) => onOptionSelect(e, index, true)
}
}
: null
);

return (
<DualListSelector>
<DualListSelectorPane
title="Available"
status={`${availableOptions.filter((x) => x.selected && x.isVisible).length} of ${
availableOptions.filter((x) => x.isVisible).length
status={`${availableOptions.filter((x) => x.props.isSelected).length} of ${
availableOptions.length
} options selected`}
>
<DualListSelectorList>
{availableOptions.map((option, index) =>
option.isVisible ? (
<DualListSelectorListItem
key={index}
isSelected={option.selected}
id={`composable-available-option-${option.text}`}
onOptionSelect={(e) => onOptionSelect(e, index, false)}
>
{option.text}
</DualListSelectorListItem>
) : null
)}
{availableOptions.map((option, index) => (
<DualListSelectorListItem
key={index}
isSelected={option.props.isSelected}
id={`composable-available-option-${option.content}`}
onOptionSelect={(e) => onOptionSelect(e, index, false)}
>
{option.content}
</DualListSelectorListItem>
))}
</DualListSelectorList>
</DualListSelectorPane>
<DualListSelectorControlsWrapper aria-label="Selector controls">
<DualListSelectorControl
isDisabled={!availableOptions.some((option) => option.selected)}
isDisabled={!availableOptions.some((option) => option.props.isSelected)}
onClick={() => moveSelected(true)}
aria-label="Add selected"
>
Expand All @@ -143,20 +121,31 @@ export const ComposableDualListSelector: React.FunctionComponent = () => {
</DualListSelectorControl>
<DualListSelectorControl
onClick={() => moveSelected(false)}
isDisabled={!chosenOptions.some((option) => option.selected)}
isDisabled={!chosenOptions.some((option) => option.props.isSelected)}
aria-label="Remove selected"
>
<AngleLeftIcon />
</DualListSelectorControl>
</DualListSelectorControlsWrapper>
<DualListSelectorPane
title="Chosen"
status={`${chosenOptions.filter((x) => x.selected && x.isVisible).length} of ${
chosenOptions.filter((x) => x.isVisible).length
} options selected`}
status={`${chosenOptions.filter((x) => x.props.isSelected).length} of ${chosenOptions.length} options selected`}
isChosen
>
<DragDropSort items={sortableChosenOptions} onDrop={onDrop} variant="DualListSelectorList">
<DragDropSort
items={chosenOptions.map((option, index) => ({
...option,
props: {
key: option.props.key,
isSelected: option.props.isSelected,
onOptionSelect: (e) => onOptionSelect(e, index, true)
}
}))}
onDrop={(_, newItems) => {
setChosenOptions(newItems);
}}
variant="DualListSelectorList"
>
<DualListSelectorList />
</DragDropSort>
</DualListSelectorPane>
Expand Down
1 change: 1 addition & 0 deletions packages/react-drag-drop/src/components/DragDrop/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './DragDropSort';
export * from './DragDropUtil';

0 comments on commit d11d772

Please sign in to comment.