/** @format */ /** * External dependencies */ import { __, sprintf } from '@wordpress/i18n'; import { Component, createRef, Fragment } from '@wordpress/element'; import classnames from 'classnames'; import { IconButton } from '@wordpress/components'; import { find, get, isEqual, noop, uniqueId } from 'lodash'; import Gridicon from 'gridicons'; import PropTypes from 'prop-types'; const ASC = 'asc'; const DESC = 'desc'; const getDisplay = cell => cell.display || null; class Table extends Component { constructor( props ) { super( props ); this.state = { tabIndex: null, rows: props.rows || [], }; this.container = createRef(); this.sortBy = this.sortBy.bind( this ); this.headersID = uniqueId( 'header-' ); this.captionID = uniqueId( 'caption-' ); } componentDidUpdate( prevProps ) { if ( ! isEqual( this.props.rows, prevProps.rows ) ) { /* eslint-disable react/no-did-update-set-state */ this.setState( { rows: this.props.rows, } ); /* eslint-enable react/no-did-update-set-state */ } } componentDidMount() { const { scrollWidth, clientWidth } = this.container.current; const scrollable = scrollWidth > clientWidth; /* eslint-disable react/no-did-mount-set-state */ this.setState( { tabIndex: scrollable ? '0' : null, } ); /* eslint-enable react/no-did-mount-set-state */ } sortBy( key ) { const { headers, query } = this.props; return () => { const currentKey = query.orderby || get( find( headers, { defaultSort: true } ), 'key', false ); const currentDir = query.order || DESC; let dir = DESC; if ( key === currentKey ) { dir = DESC === currentDir ? ASC : DESC; } this.props.onSort( key, dir ); }; } render() { const { caption, classNames, headers, query, rowHeader } = this.props; const { rows, tabIndex } = this.state; const classes = classnames( 'woocommerce-table__table', classNames ); const sortedBy = query.orderby || get( find( headers, { defaultSort: true } ), 'key', false ); const sortDir = query.order || DESC; return (
{ headers.map( ( header, i ) => { const { isSortable, key, label } = header; const thProps = { className: classnames( 'woocommerce-table__header', { 'is-sortable': isSortable, 'is-sorted': sortedBy === key, } ), }; if ( isSortable ) { thProps[ 'aria-sort' ] = 'none'; if ( sortedBy === key ) { thProps[ 'aria-sort' ] = sortDir === ASC ? 'ascending' : 'descending'; } } // We only sort by ascending if the col is already sorted descending const iconLabel = sortedBy === key && sortDir !== ASC ? sprintf( __( 'Sort by %s in ascending order', 'wc-admin' ), label ) : sprintf( __( 'Sort by %s in descending order', 'wc-admin' ), label ); return ( ); } ) } { rows.map( ( row, i ) => ( { row.map( ( cell, j ) => rowHeader === j ? ( ) : ( ) ) } ) ) }
{ caption } { tabIndex === '0' && { __( '(scroll to see more)', 'wc-admin' ) } }
{ isSortable ? ( ) : ( ) } aria-describedby={ `${ this.headersID }-${ i }` } onClick={ this.sortBy( key ) } isDefault > { label } { iconLabel } ) : ( label ) }
{ getDisplay( cell ) } { getDisplay( cell ) }
); } } Table.propTypes = { caption: PropTypes.string.isRequired, className: PropTypes.string, headers: PropTypes.arrayOf( PropTypes.shape( { defaultSort: PropTypes.bool, isSortable: PropTypes.bool, key: PropTypes.string, label: PropTypes.string, required: PropTypes.bool, } ) ), onSort: PropTypes.func, query: PropTypes.object, rows: PropTypes.arrayOf( PropTypes.arrayOf( PropTypes.shape( { display: PropTypes.node, value: PropTypes.oneOfType( [ PropTypes.string, PropTypes.number, PropTypes.bool ] ), } ) ) ).isRequired, rowHeader: PropTypes.oneOfType( [ PropTypes.number, PropTypes.bool ] ), }; Table.defaultProps = { headers: [], onSort: noop, query: {}, rowHeader: 0, }; export default Table;