@shopify/polaris
Version:
Shopify’s product component library
341 lines (306 loc) • 10.9 kB
JavaScript
import { objectSpread2 as _objectSpread2 } from '../../_virtual/_rollupPluginBabelHelpers.js';
import React$1, { PureComponent, createRef } from 'react';
import debounce$1 from 'lodash/debounce';
import { EventListener as EventListener$1 } from '../EventListener/EventListener.js';
import { useI18n } from '../../utilities/i18n/hooks.js';
import { headerCell } from '../shared.js';
import { classNames } from '../../utilities/css.js';
import isEqual$1 from 'lodash/isEqual';
import styles from './DataTable.scss.js';
import { Cell as Cell$1 } from './components/Cell/Cell.js';
import { Navigation as Navigation$1 } from './components/Navigation/Navigation.js';
import { measureColumn, getPrevAndCurrentColumns } from './utilities.js';
class DataTableInner extends PureComponent {
constructor(...args) {
super(...args);
this.state = {
condensed: false,
columnVisibilityData: [],
isScrolledFarthestLeft: true,
isScrolledFarthestRight: false
};
this.dataTable = /*#__PURE__*/createRef();
this.scrollContainer = /*#__PURE__*/createRef();
this.table = /*#__PURE__*/createRef();
this.handleResize = debounce$1(() => {
var {
table: {
current: table
},
scrollContainer: {
current: scrollContainer
}
} = this;
var condensed = false;
if (table && scrollContainer) {
condensed = table.scrollWidth > scrollContainer.clientWidth;
}
this.setState(_objectSpread2({
condensed
}, this.calculateColumnVisibilityData(condensed)));
});
this.calculateColumnVisibilityData = condensed => {
var {
table: {
current: table
},
scrollContainer: {
current: scrollContainer
},
dataTable: {
current: dataTable
}
} = this;
if (condensed && table && scrollContainer && dataTable) {
var headerCells = table.querySelectorAll(headerCell.selector);
if (headerCells.length > 0) {
var firstVisibleColumnIndex = headerCells.length - 1;
var tableLeftVisibleEdge = scrollContainer.scrollLeft;
var tableRightVisibleEdge = scrollContainer.scrollLeft + dataTable.offsetWidth;
var tableData = {
firstVisibleColumnIndex,
tableLeftVisibleEdge,
tableRightVisibleEdge
};
var columnVisibilityData = [...headerCells].map(measureColumn(tableData));
var lastColumn = columnVisibilityData[columnVisibilityData.length - 1];
return _objectSpread2(_objectSpread2({
columnVisibilityData
}, getPrevAndCurrentColumns(tableData, columnVisibilityData)), {}, {
isScrolledFarthestLeft: tableLeftVisibleEdge === 0,
isScrolledFarthestRight: lastColumn.rightEdge <= tableRightVisibleEdge
});
}
}
return {
columnVisibilityData: [],
previousColumn: undefined,
currentColumn: undefined
};
};
this.scrollListener = () => {
this.setState(prevState => _objectSpread2({}, this.calculateColumnVisibilityData(prevState.condensed)));
};
this.navigateTable = direction => {
var {
currentColumn,
previousColumn
} = this.state;
var {
current: scrollContainer
} = this.scrollContainer;
var handleScroll = () => {
if (!currentColumn || !previousColumn) {
return;
}
if (scrollContainer) {
scrollContainer.scrollLeft = direction === 'right' ? currentColumn.rightEdge : previousColumn.leftEdge;
requestAnimationFrame(() => {
this.setState(prevState => _objectSpread2({}, this.calculateColumnVisibilityData(prevState.condensed)));
});
}
};
return handleScroll;
};
this.renderHeadings = (heading, headingIndex) => {
var {
sortable,
truncate = false,
columnContentTypes,
defaultSortDirection,
initialSortColumnIndex = 0,
verticalAlign
} = this.props;
var {
sortDirection = defaultSortDirection,
sortedColumnIndex = initialSortColumnIndex
} = this.state;
var sortableHeadingProps;
var id = "heading-cell-".concat(headingIndex);
if (sortable) {
var isSortable = sortable[headingIndex];
var isSorted = isSortable && sortedColumnIndex === headingIndex;
var _direction = isSorted ? sortDirection : 'none';
sortableHeadingProps = {
defaultSortDirection,
sorted: isSorted,
sortable: isSortable,
sortDirection: _direction,
onSort: this.defaultOnSort(headingIndex)
};
}
return /*#__PURE__*/React$1.createElement(Cell$1, Object.assign({
header: true,
key: id,
content: heading,
contentType: columnContentTypes[headingIndex],
firstColumn: headingIndex === 0,
truncate: truncate
}, sortableHeadingProps, {
verticalAlign: verticalAlign
}));
};
this.totalsRowHeading = () => {
var {
i18n,
totals,
totalsName
} = this.props;
var totalsLabel = totalsName ? totalsName : {
singular: i18n.translate('Polaris.DataTable.totalRowHeading'),
plural: i18n.translate('Polaris.DataTable.totalsRowHeading')
};
return totals && totals.filter(total => total !== '').length > 1 ? totalsLabel.plural : totalsLabel.singular;
};
this.renderTotals = (total, index) => {
var id = "totals-cell-".concat(index);
var {
truncate = false,
verticalAlign
} = this.props;
var content;
var contentType;
if (index === 0) {
content = this.totalsRowHeading();
}
if (total !== '' && index > 0) {
contentType = 'numeric';
content = total;
}
var totalInFooter = this.props.showTotalsInFooter;
return /*#__PURE__*/React$1.createElement(Cell$1, {
total: true,
totalInFooter: totalInFooter,
firstColumn: index === 0,
key: id,
content: content,
contentType: contentType,
truncate: truncate,
verticalAlign: verticalAlign
});
};
this.defaultRenderRow = (row, index) => {
var className = classNames(styles.TableRow);
var {
columnContentTypes,
truncate = false,
verticalAlign
} = this.props;
return /*#__PURE__*/React$1.createElement("tr", {
key: "row-".concat(index),
className: className
}, row.map((content, cellIndex) => {
var id = "cell-".concat(cellIndex, "-row-").concat(index);
return /*#__PURE__*/React$1.createElement(Cell$1, {
key: id,
content: content,
contentType: columnContentTypes[cellIndex],
firstColumn: cellIndex === 0,
truncate: truncate,
verticalAlign: verticalAlign
});
}));
};
this.defaultOnSort = headingIndex => {
var {
onSort,
defaultSortDirection = 'ascending',
initialSortColumnIndex
} = this.props;
var {
sortDirection = defaultSortDirection,
sortedColumnIndex = initialSortColumnIndex
} = this.state;
var newSortDirection = defaultSortDirection;
if (sortedColumnIndex === headingIndex) {
newSortDirection = sortDirection === 'ascending' ? 'descending' : 'ascending';
}
var handleSort = () => {
this.setState({
sortDirection: newSortDirection,
sortedColumnIndex: headingIndex
}, () => {
if (onSort) {
onSort(headingIndex, newSortDirection);
}
});
};
return handleSort;
};
}
componentDidMount() {
// We need to defer the calculation in development so the styles have time to be injected.
if (process.env.NODE_ENV === 'development') {
setTimeout(() => {
this.handleResize();
}, 10);
} else {
this.handleResize();
}
}
componentDidUpdate(prevProps) {
if (isEqual$1(prevProps, this.props)) {
return;
}
this.handleResize();
}
render() {
var {
headings,
totals,
showTotalsInFooter,
rows,
footerContent,
hideScrollIndicator = false
} = this.props;
var {
condensed,
columnVisibilityData,
isScrolledFarthestLeft,
isScrolledFarthestRight
} = this.state;
var className = classNames(styles.DataTable, condensed && styles.condensed);
var wrapperClassName = classNames(styles.TableWrapper, condensed && styles.condensed);
var headingMarkup = /*#__PURE__*/React$1.createElement("tr", null, headings.map(this.renderHeadings));
var totalsMarkup = totals ? /*#__PURE__*/React$1.createElement("tr", null, totals.map(this.renderTotals)) : null;
var bodyMarkup = rows.map(this.defaultRenderRow);
var footerMarkup = footerContent ? /*#__PURE__*/React$1.createElement("div", {
className: styles.Footer
}, footerContent) : null;
var headerTotalsMarkup = !showTotalsInFooter ? totalsMarkup : null;
var footerTotalsMarkup = showTotalsInFooter ? /*#__PURE__*/React$1.createElement("tfoot", null, totalsMarkup) : null;
var navigationMarkup = hideScrollIndicator ? null : /*#__PURE__*/React$1.createElement(Navigation$1, {
columnVisibilityData: columnVisibilityData,
isScrolledFarthestLeft: isScrolledFarthestLeft,
isScrolledFarthestRight: isScrolledFarthestRight,
navigateTableLeft: this.navigateTable('left'),
navigateTableRight: this.navigateTable('right')
});
return /*#__PURE__*/React$1.createElement("div", {
className: wrapperClassName
}, navigationMarkup, /*#__PURE__*/React$1.createElement("div", {
className: className,
ref: this.dataTable
}, /*#__PURE__*/React$1.createElement("div", {
className: styles.ScrollContainer,
ref: this.scrollContainer
}, /*#__PURE__*/React$1.createElement(EventListener$1, {
event: "resize",
handler: this.handleResize
}), /*#__PURE__*/React$1.createElement(EventListener$1, {
capture: true,
event: "scroll",
handler: this.scrollListener
}), /*#__PURE__*/React$1.createElement("table", {
className: styles.Table,
ref: this.table
}, /*#__PURE__*/React$1.createElement("thead", null, headingMarkup, headerTotalsMarkup), /*#__PURE__*/React$1.createElement("tbody", null, bodyMarkup), footerTotalsMarkup)), footerMarkup));
}
}
function DataTable(props) {
var i18n = useI18n();
return /*#__PURE__*/React$1.createElement(DataTableInner, Object.assign({}, props, {
i18n: i18n
}));
}
export { DataTable };