import * as React from 'react'; import { css } from '@breakaway/react-styles'; import styles from '@breakaway/react-styles/css/components/DataList/data-list'; import { DataListContext } from './DataList'; import { KeyTypes } from '../../helpers/constants'; import { DataListDragButton, DataListDragButtonProps } from './DataListDragButton'; export interface DataListItemProps extends Omit, 'children' | 'ref'> { /** Flag to show if the expanded content of the DataList item is visible */ isExpanded?: boolean; /** Content rendered inside the DataList item */ children: React.ReactNode; /** Additional classes added to the DataList item should be either or */ className?: string; /** Adds accessible text to the DataList item */ 'aria-labelledby': string; /** Unique id for the DataList item */ id?: string; /** Aria label to apply to the selectable input if one is rendered */ selectableInputAriaLabel?: string; } export interface DataListItemChildProps { /** Id for the row */ rowid: string; } function findDataListDragButton(node: React.ReactNode): React.ReactElement | null { if (!React.isValidElement(node)) { return null; } if (node.type === DataListDragButton) { return node as React.ReactElement; } if (node.props.children) { for (const child of React.Children.toArray(node.props.children)) { const button = findDataListDragButton(child); if (button) { return button; } } } return null; } export class DataListItem extends React.Component { static displayName = 'DataListItem'; static defaultProps: DataListItemProps = { isExpanded: false, className: '', id: '', children: null, 'aria-labelledby': '' }; render() { const { children, isExpanded, className, id, 'aria-labelledby': ariaLabelledBy, selectableInputAriaLabel, ...props } = this.props; return ( {({ isSelectable, selectedDataListItemId, updateSelectedDataListItem, selectableRow, isDraggable, dragStart, dragEnd, drop }) => { const selectDataListItem = (event: React.MouseEvent) => { let target: any = event.target; while (event.currentTarget !== target) { if ( ('onclick' in target && target.onclick) || target.parentNode.classList.contains(styles.dataListItemAction) || target.parentNode.classList.contains(styles.dataListItemControl) ) { // check other event handlers are not present. return; } else { target = target.parentNode; } } updateSelectedDataListItem(id); }; const onKeyDown = (event: React.KeyboardEvent) => { if (event.key === KeyTypes.Enter) { updateSelectedDataListItem(id); } }; // We made the DataListDragButton determine if the entire item is draggable instead of // DataListItem like we should have. // Recursively search children for the DataListDragButton and see if it's disabled... const dragButton = findDataListDragButton(children); const dragProps = isDraggable && { draggable: dragButton ? !dragButton.props.isDisabled : true, onDrop: drop, onDragEnd: dragEnd, onDragStart: dragStart }; const isSelected = selectedDataListItemId === id; const selectableInputAriaProps = selectableInputAriaLabel ? { 'aria-label': selectableInputAriaLabel } : { 'aria-labelledby': ariaLabelledBy }; return (
  • {selectableRow && ( selectableRow.onChange(id, event)} tabIndex={-1} {...selectableInputAriaProps} /> )} {React.Children.map( children, child => React.isValidElement(child) && React.cloneElement(child as React.ReactElement, { rowid: ariaLabelledBy }) )}
  • ); }}
    ); } }