UNPKG

@carbon/ibm-security

Version:

Carbon for Cloud & Cognitive IBM Security UI components

188 lines (182 loc) 8.77 kB
import _extends from "@babel/runtime/helpers/extends"; import _slicedToArray from "@babel/runtime/helpers/slicedToArray"; import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties"; import _classCallCheck from "@babel/runtime/helpers/classCallCheck"; import _createClass from "@babel/runtime/helpers/createClass"; import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn"; import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf"; import _inherits from "@babel/runtime/helpers/inherits"; import _defineProperty from "@babel/runtime/helpers/defineProperty"; var _excluded = ["as", "children", "className", "expandButtonClassName", "getExpandButtonLabel", "scrollGradientColor", "truncateThreshold", "collapsedItemLimit", "expandedItemLimit"]; function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); } function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); } /** * @file Truncated list component. * @copyright IBM Security 2020 - 2021 */ import classnames from 'classnames'; import PropTypes from 'prop-types'; import React, { Children, Component } from 'react'; import Button from '../Button'; import ScrollGradient from '../ScrollGradient'; import { carbonPrefix, getComponentNamespace } from '../../globals/namespace'; import theme from '../../globals/theme'; var namespace = getComponentNamespace('truncated-list'); var toArray = Children.toArray; var TruncatedList = /*#__PURE__*/function (_Component) { function TruncatedList() { var _this; _classCallCheck(this, TruncatedList); for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = _callSuper(this, TruncatedList, [].concat(args)); _defineProperty(_this, "state", { isExpanded: false }); _defineProperty(_this, "handleExpand", function () { // Pre-set the height of the list container to its own current height so we can smoothly // transition into its new height in the React Effect hook. _this.updateListContainerHeight(); _this.setState(function (_ref) { var isExpanded = _ref.isExpanded; return { isExpanded: !isExpanded }; }); }); _defineProperty(_this, "listContainer", null); _defineProperty(_this, "setListContainer", function (listContainer) { return _this.listContainer = listContainer; }); return _this; } _inherits(TruncatedList, _Component); return _createClass(TruncatedList, [{ key: "getDisplayCount", value: /** * Defines how many items must be displayed at a time and whether it should truncate. */ function getDisplayCount(childrenLength) { var _this$props = this.props, collapsedItemLimit = _this$props.collapsedItemLimit, expandedItemLimit = _this$props.expandedItemLimit, truncateThreshold = _this$props.truncateThreshold, isExpanded = this.state.isExpanded; var shouldTruncate = childrenLength > truncateThreshold; // If we do not need to truncate, we can just show the entire list of items. if (!shouldTruncate) { return [childrenLength, shouldTruncate]; } // When the list is truncated and expanded, we use the expanded item limit. if (isExpanded) { return [expandedItemLimit, shouldTruncate]; } // If the truncate threshold is lower than the collapsed item limit, and the list needs to be // truncated, we must display the lowest of the two counts otherwise the expand button would // have a negative count. return [Math.min(collapsedItemLimit, truncateThreshold), shouldTruncate]; } /** * Adjusts the height of the list container so only the amount of items from the calculated * display amount can be viewed at a time. */ }, { key: "updateListContainerHeight", value: function updateListContainerHeight() { var listContainer = this.listContainer, children = this.props.children; if (!listContainer) { return; } var items = listContainer.firstElementChild.children; // Calculate which item in the list is the last to show in our list. It either has to be the // calculate display count or the last item on the list. Whichever comes first. var lastItemToShow = items[Math.min(this.getDisplayCount(toArray(children).length)[0], items.length - 1)]; listContainer.style.height = lastItemToShow.offsetTop + lastItemToShow.offsetHeight + 4 + 'px'; } }, { key: "componentDidUpdate", value: function componentDidUpdate(prevProps, _ref2) { var isExpanded = _ref2.isExpanded; // After the component's expanded state has changed update the height of the list container to be // the same as its visible children set. if (isExpanded != this.state.isExpanded) { this.updateListContainerHeight(); } } }, { key: "render", value: function render() { var _this$props2 = this.props, List = _this$props2.as, children = _this$props2.children, className = _this$props2.className, expandButtonClassName = _this$props2.expandButtonClassName, getExpandButtonLabel = _this$props2.getExpandButtonLabel, scrollGradientColor = _this$props2.scrollGradientColor, _ = _this$props2.truncateThreshold, __ = _this$props2.collapsedItemLimit, ___ = _this$props2.expandedItemLimit, other = _objectWithoutProperties(_this$props2, _excluded), isExpanded = this.state.isExpanded; var childrenArray = toArray(children); var childrenLength = childrenArray.length; var _this$getDisplayCount = this.getDisplayCount(childrenLength), _this$getDisplayCount2 = _slicedToArray(_this$getDisplayCount, 2), displayCount = _this$getDisplayCount2[0], shouldTruncate = _this$getDisplayCount2[1]; return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(ScrollGradient, { className: "".concat(namespace, "__scroller-container"), scrollElementClassName: "".concat(namespace, "__scroller"), color: scrollGradientColor, getScrollElementRef: this.setListContainer }, /*#__PURE__*/React.createElement(List, _extends({ className: classnames(className, namespace) }, other), childrenArray.slice(0, displayCount), shouldTruncate && isExpanded && childrenArray.slice(displayCount))), shouldTruncate && /*#__PURE__*/React.createElement(Button, { className: classnames(expandButtonClassName, "".concat(carbonPrefix, "--link"), "".concat(namespace, "__expand-button")), iconDescription: "", size: "small", onClick: this.handleExpand }, getExpandButtonLabel(isExpanded, isExpanded ? childrenLength : displayCount, isExpanded ? 0 : childrenLength - displayCount))); } }]); }(Component); TruncatedList.propTypes = { /** The type of list element to render. This could be a ul, ol, or a custom React component. (Optional) */ as: PropTypes.oneOfType([PropTypes.elementType, PropTypes.string]), /** Items to have in the list. */ children: PropTypes.node, /** Optional list class name. */ className: PropTypes.string, /** Number of items to display when the list is truncated and collapsed. */ collapsedItemLimit: PropTypes.number, /** Optional class name for expand button. */ expandButtonClassName: PropTypes.string, /** * Number of items to show when the list is truncated and expanded. All items are rendered when * the list is expanded, this prop is to limit the visual height of the list. */ expandedItemLimit: PropTypes.number, /** Function to compute the label for the expand toggle button. */ getExpandButtonLabel: PropTypes.func, /** Optional scroll gradient color. */ scrollGradientColor: PropTypes.string, /** Number of items allowed in the list before the list is truncated. */ truncateThreshold: PropTypes.number }; TruncatedList.defaultProps = { children: undefined, className: undefined, expandButtonClassName: undefined, as: 'ul', scrollGradientColor: theme.uiBackground, getExpandButtonLabel: function getExpandButtonLabel() { return 'getExpandButtonLabel'; }, truncateThreshold: 10, collapsedItemLimit: 5, expandedItemLimit: 10 }; export default TruncatedList;