UNPKG

@talend/react-components

Version:
237 lines (236 loc) 7.8 kB
import { PureComponent } from 'react'; import { withTranslation } from 'react-i18next'; import { AutoSizer, CellMeasurer, CellMeasurerCache, List } from 'react-virtualized'; import classNames from 'classnames'; import PropTypes from 'prop-types'; import Checkbox from '../../Checkbox'; import I18N_DOMAIN_COMPONENTS from '../../constants'; import getDefaultT from '../../translate'; import Item from './Item/Item.component'; import theme from './Items.module.scss'; import { jsx as _jsx } from "react/jsx-runtime"; const listClasses = classNames(theme['tc-list-items'], 'tc-list-items'); const itemsClasses = classNames(theme['tc-listview-items'], 'tc-listview-items'); const itemContainer = classNames(theme['tc-item-container'], 'tc-item-container'); /** * Converts a string px size in a JS valid number * @param {String} sizeInPixels * @returns {Number} */ function pxToInt(sizeInPixels = '0') { return parseFloat(sizeInPixels.replace('px', '')) || 0; } const TOGGLE_ALL_ROW_HEIGHT = 40; const ROW_LINE_HEIGHT = pxToInt(theme['row-height']); const ROW_VERTICAL_MARGIN = pxToInt(theme['row-vertical-margin']); const ROW_HEIGHT = ROW_LINE_HEIGHT + ROW_VERTICAL_MARGIN; const ROW_NESTED_INNER_MARGINS = pxToInt(theme['row-nested-inner-margin-top']) + pxToInt(theme['row-nested-inner-margin-bottom']); export class ItemsComponent extends PureComponent { constructor(props) { super(props); this.renderItem = this.renderItem.bind(this); this.getRowHeight = this.getRowHeight.bind(this); this.rowRenderer = this.rowRenderer.bind(this); this.renderToggleAllOrItem = this.renderToggleAllOrItem.bind(this); this.renderToggleAll = this.renderToggleAll.bind(this); this.cache = new CellMeasurerCache({ defaultHeight: props.getItemHeight ? props.getItemHeight() : ROW_HEIGHT, fixedWidth: true }); } getItemByIndex(index) { return this.props.items[index - Number(this.hasToggleAll)]; } getRowHeight({ index }) { if (this.props.getItemHeight) { // If an height computation has been provided, use the "old" // way of computing row height with the provided computation return this.oldGetRowHeight.call(this, { index }); } if (this.hasToggleAll && index === 0) { return TOGGLE_ALL_ROW_HEIGHT; } const isLastItem = index + (this.hasToggleAll ? 0 : 1) === this.props.items.length; const currentItem = this.getItemByIndex(index); let height = ROW_HEIGHT; if (isLastItem) { height += ROW_NESTED_INNER_MARGINS; height += this.hasToggleAll ? 1 : 0; // Horizontal "Toggle all" separation height } if (!currentItem || !currentItem.children || !currentItem.expanded) { return height; } return height + // Own height currentItem.children.length * ROW_HEIGHT + // Children heights ROW_NESTED_INNER_MARGINS // Inner nested margins ; } getRowCount() { if (this.hasToggleAll) { return this.props.items.length + 1; } return this.props.items.length; } oldGetRowHeight({ index }) { if (this.hasToggleAll && index === 0) { return TOGGLE_ALL_ROW_HEIGHT; } let extraHeight = 0; const currentItem = this.getItemByIndex(index); if (currentItem && currentItem.children && currentItem.expanded) { extraHeight = currentItem.children.length * this.props.getItemHeight(); } return this.props.getItemHeight() + extraHeight; } rowRenderer(props) { const { key, index, style } = props; const isToggle = this.hasToggleAll && index === 0; const currentItem = this.getItemByIndex(index); return /*#__PURE__*/_jsx(CellMeasurer, { cache: this.cache, columnIndex: 0, parent: this.list, rowIndex: index, children: ({ measure }) => /*#__PURE__*/_jsx("div", { className: classNames(itemContainer, { [theme.toggle]: isToggle, toggle: isToggle, expanded: currentItem && currentItem.expanded }), style: style, children: this.renderToggleAllOrItem(index, measure) }, key) }, key); } renderToggleAllOrItem(index, measure) { let computedIndex = index; if (this.hasToggleAll) { if (index === 0) { return this.renderToggleAll(); } computedIndex = index - 1; } return this.renderItem(this.props.items[computedIndex], computedIndex, measure); } renderToggleAll() { const { id, isSwitchBox, toggleAllChecked, onToggleAll, t } = this.props; const toggleAllId = `${id || 'tc-listview'}-toggle-all`; const toggleAllSelector = isSwitchBox ? 'switch checkbox' : 'checkbox'; const label = toggleAllChecked ? t('LISTVIEW_ITEMS_DESELECT_ALL', { defaultValue: 'Deselect all' }) : t('LISTVIEW_ITEMS_SELECT_ALL', { defaultValue: 'Select all' }); return /*#__PURE__*/_jsx("div", { className: toggleAllSelector, children: /*#__PURE__*/_jsx(Checkbox, { id: toggleAllId, onChange: onToggleAll, checked: toggleAllChecked, label: /*#__PURE__*/_jsx("strong", { children: label }) }) }); } renderItem(item, index, measure) { const { dataTest } = this.props; let computedId; if (this.props.id) { const computedIndex = this.hasToggleAll ? index + 1 : index; computedId = `${this.props.id}-${computedIndex}-item`; } return /*#__PURE__*/_jsx(Item, { measure: measure, id: computedId, item: item, isSwitchBox: this.props.isSwitchBox && !item.children, searchCriteria: this.props.searchCriteria, dataTest: dataTest && `${dataTest}-${index}`, children: item.children && item.children.map((nestedItem, nestedIndex) => /*#__PURE__*/_jsx(Item, { measure: measure, item: nestedItem, parentItem: item, searchCriteria: this.props.searchCriteria, dataTest: dataTest && `${dataTest}-${index}.nested-${nestedIndex}` }, nestedIndex)) }, computedId); } render() { this.hasToggleAll = this.props.showToggleAll && this.props.items.length > 1; return /*#__PURE__*/_jsx("div", { className: itemsClasses, children: /*#__PURE__*/_jsx(AutoSizer, { children: ({ height, width }) => /*#__PURE__*/_jsx(List /** * The props 'items' and 'actions' does not exist in <List> * but only way to refresh component when items or actions change * See https://github.com/bvaughn/react-virtualized/#pure-components */, { ref: node => { this.list = node; }, items: this.props.items, className: listClasses, rowRenderer: this.rowRenderer, width: width, height: height, rowCount: this.getRowCount(), rowHeight: this.getRowHeight, role: "listbox", containerProps: this.props.containerProps }) }) }); } } ItemsComponent.propTypes = { containerProps: PropTypes.object, id: PropTypes.string, items: PropTypes.arrayOf(PropTypes.shape({ label: PropTypes.string, onChange: PropTypes.func, checked: PropTypes.bool, index: PropTypes.number })), isSwitchBox: PropTypes.bool, getItemHeight: PropTypes.func, searchCriteria: PropTypes.string, toggleAllChecked: PropTypes.bool, showToggleAll: PropTypes.bool, onToggleAll: PropTypes.func, dataTest: PropTypes.string, t: PropTypes.func }; ItemsComponent.defaultProps = { t: getDefaultT(), isSwitchBox: false, showToggleAll: true }; export default withTranslation(I18N_DOMAIN_COMPONENTS)(ItemsComponent); //# sourceMappingURL=Items.component.js.map