saagie-ui
Version:
Saagie UI from Saagie Design System
226 lines (208 loc) • 5.87 kB
JavaScript
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import { getColumnClasses } from './helpers';
import { modifierCSS } from '../../../helpers';
const propTypes = {
children: PropTypes.oneOfType([
PropTypes.element,
PropTypes.arrayOf(PropTypes.element),
]),
className: PropTypes.string,
defaultClassName: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]),
headerLabels: PropTypes.arrayOf(PropTypes.node),
preHeader: PropTypes.arrayOf(
PropTypes.shape({ label: PropTypes.string, size: PropTypes.number })
),
isBordered: PropTypes.bool,
innerBorder: PropTypes.bool,
isHover: PropTypes.bool,
isLight: PropTypes.bool,
levelBreakpoint: PropTypes.oneOf(['none', 'xxs', 'xs', 'sm', 'md', 'lg', 'xl', 'xxl']),
sortIndexes: PropTypes.arrayOf(PropTypes.number),
onSort: PropTypes.func,
/**
* The component used for the root node.
* Either a string to use a DOM element or a component.
*/
tag: PropTypes.elementType,
};
const defaultProps = {
children: null,
className: '',
defaultClassName: 'sui-o-datalist',
headerLabels: null,
preHeader: [],
isBordered: false,
innerBorder: false,
isHover: true,
isLight: false,
levelBreakpoint: 'md',
sortIndexes: null,
onSort: () => {},
tag: 'div',
};
export const Datalist = (props) => {
const {
children,
className,
defaultClassName,
headerLabels,
preHeader,
isBordered,
innerBorder,
isHover,
isLight,
levelBreakpoint,
sortIndexes,
onSort,
tag: Tag,
...attributes
} = props;
const [activeSortByIndex, setActiveSortByIndex] = useState({});
const classes = classnames(
defaultClassName,
className,
modifierCSS(levelBreakpoint, 'level-breakpoint'),
{
'as--sorted': sortIndexes,
'as--inner-border': innerBorder,
'as--bordered': isBordered,
'as--light': isLight,
'as--hover': isHover,
},
);
const rows = (React.Children.toArray(children) || [])
.map((row) => React.Children.toArray(row.props.children));
const firstRow = rows[0];
const headerClasses = firstRow ? firstRow.map((col) => getColumnClasses(col.props)) : '';
const handleSort = (type, index) => {
setActiveSortByIndex({
[index]: type,
});
onSort(type, index);
};
const renderHeader = () => {
if (!headerLabels) {
return '';
}
const preHeaders = () => {
if (preHeader.length === 0) {
return null;
}
if (rows.length === 0) {
return null;
}
let sizeIndex = 0;
return preHeader.map((elem, i) => {
sizeIndex += elem.size || 1;
return (
// eslint-disable-next-line react/no-array-index-key
<div key={i} style={{ flexGrow: elem.size && elem.size.toString(), borderBottom: headerLabels[sizeIndex - 1] === '' ? 'none' : '0.0625rem solid #d9dbe3' }} className={`${headerClasses[i]} sui-o-datalist__col`}>
{elem.label}
</div>
);
}
);
};
const headers = () => {
if (rows.length === 0) {
return headerLabels.map((x, i) => (
// eslint-disable-next-line react/no-array-index-key
<div key={i} className="sui-o-datalist__col">
{x}
</div>
));
}
return firstRow.map((x, i) => {
const canSort = sortIndexes && sortIndexes.indexOf(i) > -1;
return (
<div
// eslint-disable-next-line react/no-array-index-key
key={i}
className={classnames(
headerClasses[i],
{
'sui-o-datalist__col--sortable': canSort,
},
)}
>
{headerLabels[i]}
{canSort && (
<div className="sui-o-datalist__col__sort">
<button
type="button"
aria-label="Sort ASC"
className={classnames(
'sui-o-datalist__col__sort-up',
{
'as--active': activeSortByIndex[i] === 'ASC',
},
)}
onClick={() => handleSort('ASC', i)}
/>
<button
type="button"
aria-label="Sort DESC"
className={classnames(
'sui-o-datalist__col__sort-down',
{
'as--active': activeSortByIndex[i] === 'DESC',
},
)}
onClick={() => handleSort('DESC', i)}
/>
</div>
)}
</div>
);
});
};
return (
<div>
{preHeader.length
? (
<div className="sui-o-datalist__preheader">
{preHeaders()}
</div>
) : ''}
<div className="sui-o-datalist__header">
{headers()}
</div>
</div>
);
};
const renderRows = () => {
if (!headerLabels) {
return children;
}
return React.Children.map(children, (row) => {
if (!row.props || !row.props.children) {
return '';
}
const columns = React.Children
.map(row.props.children, (col, index = 1) => ({
...col,
props: {
...col.props,
label: col.props.label === null ? headerLabels[index] : col.props.label,
},
}));
return {
...row,
props: {
...row.props,
children: columns,
},
};
});
};
return (
<Tag {...attributes} className={classes}>
{renderHeader()}
{renderRows()}
</Tag>
);
};
Datalist.propTypes = propTypes;
Datalist.defaultProps = defaultProps;