Skip to content

Commit

Permalink
chore(DataList): removed deprecated props and logic
Browse files Browse the repository at this point in the history
  • Loading branch information
thatblindgeye committed Nov 23, 2022
1 parent 775e43c commit 50de1ff
Showing 1 changed file with 3 additions and 250 deletions.
253 changes: 3 additions & 250 deletions packages/react-core/src/components/DataList/DataList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export interface SelectableRowObject {
onChange: (id: string, event: React.FormEvent<HTMLInputElement>) => void;
}

export interface DataListProps extends Omit<React.HTMLProps<HTMLUListElement>, 'onDragStart' | 'ref'> {
export interface DataListProps extends Omit<React.HTMLProps<HTMLUListElement>, 'ref'> {
/** Content rendered inside the DataList list */
children?: React.ReactNode;
/** Additional classes added to the DataList list */
Expand All @@ -34,14 +34,6 @@ export interface DataListProps extends Omit<React.HTMLProps<HTMLUListElement>, '
'aria-label': string;
/** Optional callback to make DataList selectable, fired when DataListItem selected */
onSelectDataListItem?: (id: string) => void;
/** @deprecated Optional callback to make DataList draggable, fired when dragging ends */
onDragFinish?: (newItemOrder: string[]) => void;
/** @deprecated Optional informational callback for dragging, fired when dragging starts */
onDragStart?: (id: string) => void;
/** @deprecated Optional informational callback for dragging, fired when an item moves */
onDragMove?: (oldIndex: number, newIndex: number) => void;
/** @deprecated Optional informational callback for dragging, fired when dragging is cancelled */
onDragCancel?: () => void;
/** Id of DataList item currently selected */
selectedDataListItemId?: string;
/** Flag indicating if DataList should have compact styling */
Expand All @@ -50,47 +42,22 @@ export interface DataListProps extends Omit<React.HTMLProps<HTMLUListElement>, '
gridBreakpoint?: 'none' | 'always' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';
/** Determines which wrapping modifier to apply to the DataList */
wrapModifier?: DataListWrapModifier | 'nowrap' | 'truncate' | 'breakWord';
/** @deprecated Order of items in a draggable DataList */
itemOrder?: string[];
/** Object that causes the data list to render hidden inputs which improve selectable item a11y */
selectableRow?: SelectableRowObject;
}

interface DataListState {
draggedItemId: string;
draggingToItemIndex: number;
dragging: boolean;
tempItemOrder: string[];
}

interface DataListContextProps {
isSelectable: boolean;
selectedDataListItemId: string;
updateSelectedDataListItem: (id: string) => void;
selectableRow?: SelectableRowObject;
isDraggable: boolean;
dragStart: (e: React.DragEvent) => void;
dragEnd: (e: React.DragEvent) => void;
drop: (e: React.DragEvent) => void;
dragKeyHandler: (e: React.KeyboardEvent) => void;
}

export const DataListContext = React.createContext<Partial<DataListContextProps>>({
isSelectable: false
});

const moveItem = (arr: string[], i1: string, toIndex: number) => {
const fromIndex = arr.indexOf(i1);
if (fromIndex === toIndex) {
return arr;
}
const temp = arr.splice(fromIndex, 1);
arr.splice(toIndex, 0, temp[0]);

return arr;
};

export class DataList extends React.Component<DataListProps, DataListState> {
export class DataList extends React.Component<DataListProps> {
static displayName = 'DataList';
static defaultProps: PickOptional<DataListProps> = {
children: null,
Expand All @@ -100,207 +67,14 @@ export class DataList extends React.Component<DataListProps, DataListState> {
gridBreakpoint: 'md',
wrapModifier: null
};
dragFinished: boolean = false;
html5DragDrop: boolean = false;
arrayCopy: React.ReactElement[] = React.Children.toArray(this.props.children) as React.ReactElement[];
ref = React.createRef<HTMLUListElement>();

state: DataListState = {
tempItemOrder: [],
draggedItemId: null,
draggingToItemIndex: null,
dragging: false
};

constructor(props: DataListProps) {
super(props);

this.html5DragDrop = Boolean(props.onDragFinish || props.onDragStart || props.onDragMove || props.onDragCancel);
if (this.html5DragDrop) {
// eslint-disable-next-line no-console
console.warn("DataList's onDrag API is deprecated. Use DragDrop instead.");
}
}

componentDidUpdate(oldProps: DataListProps) {
if (this.dragFinished) {
this.dragFinished = false;

this.setState({
tempItemOrder: [...this.props.itemOrder],
draggedItemId: null,
dragging: false
});
}
if (oldProps.itemOrder !== this.props.itemOrder) {
this.move(this.props.itemOrder);
}
}

getIndex = (id: string) => Array.from(this.ref.current.children).findIndex(item => item.id === id);

move = (itemOrder: string[]) => {
const ulNode = this.ref.current;
const nodes = Array.from(ulNode.children);
if (nodes.map(node => node.id).every((id, i) => id === itemOrder[i])) {
return;
}
while (ulNode.firstChild) {
ulNode.removeChild(ulNode.lastChild);
}

itemOrder.forEach(id => {
ulNode.appendChild(nodes.find(n => n.id === id));
});
};

dragStart0 = (el: HTMLElement) => {
const { onDragStart } = this.props;
const draggedItemId = el.id;

el.classList.add(styles.modifiers.ghostRow);
el.setAttribute('aria-pressed', 'true');
this.setState({
draggedItemId,
dragging: true
});
onDragStart && onDragStart(draggedItemId);
};

dragStart = (evt: React.DragEvent) => {
evt.dataTransfer.effectAllowed = 'move';
evt.dataTransfer.setData('text/plain', evt.currentTarget.id);
this.dragStart0(evt.currentTarget as HTMLElement);
};

onDragCancel = () => {
this.move(this.props.itemOrder);
Array.from(this.ref.current.children).forEach(el => {
el.classList.remove(styles.modifiers.ghostRow);
el.classList.remove(styles.modifiers.dragOver);
el.setAttribute('aria-pressed', 'false');
});
this.setState({
draggedItemId: null,
draggingToItemIndex: null,
dragging: false
});

if (this.props.onDragCancel) {
this.props.onDragCancel();
}
};

dragLeave = (evt: React.DragEvent) => {
// This event false fires when we call `this.move()`, so double check we're out of zone
if (!this.isValidDrop(evt)) {
this.move(this.props.itemOrder);
this.setState({
draggingToItemIndex: null
});
}
};

dragEnd0 = (el: HTMLElement) => {
el.classList.remove(styles.modifiers.ghostRow);
el.classList.remove(styles.modifiers.dragOver);
el.setAttribute('aria-pressed', 'false');
this.setState({
draggedItemId: null,
draggingToItemIndex: null,
dragging: false
});
};

dragEnd = (evt: React.DragEvent) => {
this.dragEnd0(evt.target as HTMLElement);
};

isValidDrop = (evt: React.DragEvent) => {
const ulRect = this.ref.current.getBoundingClientRect();
return (
evt.clientX > ulRect.x &&
evt.clientX < ulRect.x + ulRect.width &&
evt.clientY > ulRect.y &&
evt.clientY < ulRect.y + ulRect.height
);
};

drop = (evt: React.DragEvent) => {
if (this.isValidDrop(evt)) {
this.props.onDragFinish(this.state.tempItemOrder);
} else {
this.onDragCancel();
}
};

dragOver0 = (id: string) => {
const draggingToItemIndex = Array.from(this.ref.current.children).findIndex(item => item.id === id);
if (draggingToItemIndex !== this.state.draggingToItemIndex) {
const tempItemOrder = moveItem([...this.props.itemOrder], this.state.draggedItemId, draggingToItemIndex);
this.move(tempItemOrder);

this.setState({
draggingToItemIndex,
tempItemOrder
});
}
};

dragOver = (evt: React.DragEvent): string | null => {
evt.preventDefault();

const curListItem = (evt.target as HTMLElement).closest('li');
if (!curListItem || !this.ref.current.contains(curListItem) || curListItem.id === this.state.draggedItemId) {
// We're going nowhere, don't bother calling `dragOver0`
return null;
} else {
this.dragOver0(curListItem.id);
}
};

handleDragButtonKeys = (evt: React.KeyboardEvent) => {
const { dragging } = this.state;
if (![' ', 'Escape', 'Enter', 'ArrowUp', 'ArrowDown'].includes(evt.key) || !this.html5DragDrop) {
if (dragging) {
evt.preventDefault();
}
return;
}
evt.preventDefault();

const dragItem = (evt.target as Element).closest('li');

if (evt.key === ' ' || (evt.key === 'Enter' && !dragging)) {
this.dragStart0(dragItem);
} else if (dragging) {
if (evt.key === 'Escape' || evt.key === 'Enter') {
this.setState({
dragging: false
});
this.dragFinished = true;
if (evt.key === 'Enter') {
this.dragEnd0(dragItem);
this.props.onDragFinish(this.state.tempItemOrder);
} else {
this.onDragCancel();
}
} else if (evt.key === 'ArrowUp') {
const nextSelection = dragItem.previousSibling as HTMLElement;
if (nextSelection) {
this.dragOver0(nextSelection.id);
(dragItem.querySelector(`.${styles.dataListItemDraggableButton}`) as HTMLElement).focus();
}
} else if (evt.key === 'ArrowDown') {
const nextSelection = dragItem.nextSibling as HTMLElement;
if (nextSelection) {
this.dragOver0(nextSelection.id);
(dragItem.querySelector(`.${styles.dataListItemDraggableButton}`) as HTMLElement).focus();
}
}
}
};

render() {
const {
className,
Expand All @@ -309,42 +83,23 @@ export class DataList extends React.Component<DataListProps, DataListState> {
selectedDataListItemId,
isCompact,
wrapModifier,
/* eslint-disable @typescript-eslint/no-unused-vars */
onDragStart,
onDragMove,
onDragCancel,
onDragFinish,
gridBreakpoint,
itemOrder,
selectableRow,
/* eslint-enable @typescript-eslint/no-unused-vars */
...props
} = this.props;
const { dragging } = this.state;
const isSelectable = onSelectDataListItem !== undefined;

const updateSelectedDataListItem = (id: string) => {
onSelectDataListItem(id);
};

const dragProps = this.html5DragDrop && {
onDragOver: this.dragOver,
onDrop: this.dragOver,
onDragLeave: this.dragLeave
};

return (
<DataListContext.Provider
value={{
isSelectable,
selectedDataListItemId,
updateSelectedDataListItem,
selectableRow,
isDraggable: this.html5DragDrop,
dragStart: this.dragStart,
dragEnd: this.dragEnd,
drop: this.drop,
dragKeyHandler: this.handleDragButtonKeys
selectableRow
}}
>
<ul
Expand All @@ -353,12 +108,10 @@ export class DataList extends React.Component<DataListProps, DataListState> {
isCompact && styles.modifiers.compact,
gridBreakpointClasses[gridBreakpoint],
wrapModifier && styles.modifiers[wrapModifier],
dragging && styles.modifiers.dragOver,
className
)}
style={props.style}
{...props}
{...dragProps}
ref={this.ref}
>
{children}
Expand Down

0 comments on commit 50de1ff

Please sign in to comment.