UNPKG

wix-style-react

Version:
452 lines (384 loc) • 17.2 kB
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray"; import _classCallCheck from "@babel/runtime/helpers/classCallCheck"; import _createClass from "@babel/runtime/helpers/createClass"; import _assertThisInitialized from "@babel/runtime/helpers/assertThisInitialized"; import _inherits from "@babel/runtime/helpers/inherits"; import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn"; import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf"; import _defineProperty from "@babel/runtime/helpers/defineProperty"; function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } import React from 'react'; import PropTypes from 'prop-types'; import SelectorListContent from './Content'; import Box from '../Box'; import Search from '../Search'; import Text from '../Text'; import ToggleAllCheckbox from './ToggleAllCheckbox'; import { dataHooks } from './SelectorList.helpers'; import { st, classes } from './SelectorList.st.css'; /** * Use this component when needed to select one / multiple items having complex descriptions. * E.g.: choosing products to promote via ShoutOuts */ var SelectorList = /*#__PURE__*/function (_React$PureComponent) { _inherits(SelectorList, _React$PureComponent); var _super = _createSuper(SelectorList); function SelectorList() { var _this; _classCallCheck(this, SelectorList); for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = _super.call.apply(_super, [this].concat(args)); _defineProperty(_assertThisInitialized(_this), "state", { isLoaded: false, isSearching: false, items: [], searchValue: '', selectedItems: [], noResultsFound: false, isEmpty: false }); _defineProperty(_assertThisInitialized(_this), "_renderList", function () { var _this$props = _this.props, dataHook = _this$props.dataHook, emptyState = _this$props.emptyState, renderNoResults = _this$props.renderNoResults, height = _this$props.height, maxHeight = _this$props.maxHeight, imageSize = _this$props.imageSize, imageShape = _this$props.imageShape, multiple = _this$props.multiple; var _this$state = _this.state, items = _this$state.items, isLoaded = _this$state.isLoaded, isEmpty = _this$state.isEmpty, isSearching = _this$state.isSearching, searchValue = _this$state.searchValue, noResultsFound = _this$state.noResultsFound, selectedItems = _this$state.selectedItems; var hasMore = _this._hasMore(); var contentProps = { items: items, selectedItems: selectedItems, onToggle: _this._onToggle, emptyState: emptyState, renderNoResults: renderNoResults, isEmpty: isEmpty, isLoading: !isLoaded || isSearching, noResultsFound: noResultsFound, imageSize: imageSize, imageShape: imageShape, multiple: multiple, loadMore: _this._loadMore, hasMore: hasMore, checkIsSelected: _this._checkIsSelected, searchValue: searchValue }; var shouldRenderSubheader = isLoaded && !isEmpty; return /*#__PURE__*/React.createElement(Box, { direction: "vertical", overflow: "hidden", dataHook: dataHook, height: height, maxHeight: maxHeight }, shouldRenderSubheader && _this._renderSubheader(), /*#__PURE__*/React.createElement(SelectorListContent, contentProps)); }); _defineProperty(_assertThisInitialized(_this), "_renderSubheader", function () { var _this$props2 = _this.props, subtitle = _this$props2.subtitle, withSearch = _this$props2.withSearch, searchDebounceMs = _this$props2.searchDebounceMs, searchPlaceholder = _this$props2.searchPlaceholder; var searchValue = _this.state.searchValue; return /*#__PURE__*/React.createElement("div", { className: st(classes.subheaderWrapper, { withSearch: withSearch }) }, subtitle && /*#__PURE__*/React.createElement("div", { className: classes.subtitleWrapper }, typeof subtitle === 'string' ? /*#__PURE__*/React.createElement(Text, { dataHook: dataHooks.subtitle }, subtitle) : subtitle), withSearch && /*#__PURE__*/React.createElement(Search, { dataHook: dataHooks.search, placeholder: searchPlaceholder, onChange: _this._onSearchChange, onClear: _this._onClear, debounceMs: searchDebounceMs, value: searchValue })); }); _defineProperty(_assertThisInitialized(_this), "_renderToggleAllCheckbox", function () { var _this$props3 = _this.props, selectAllText = _this$props3.selectAllText, deselectAllText = _this$props3.deselectAllText; var _this$state2 = _this.state, items = _this$state2.items, selectedItems = _this$state2.selectedItems; var enabledItemsAmount = _this._getEnabledItems(items).length; var selectedEnabledItemsAmount = _this._getEnabledItems(selectedItems).length; var checkboxProps = { selectAllText: selectAllText, deselectAllText: deselectAllText, enabledItemsAmount: enabledItemsAmount, selectedEnabledItemsAmount: selectedEnabledItemsAmount, selectAll: _this._selectAll, deselectAll: _this._deselectAll }; return /*#__PURE__*/React.createElement(ToggleAllCheckbox, checkboxProps); }); _defineProperty(_assertThisInitialized(_this), "_updateSearchValue", function (searchValue) { return _this.setState({ searchValue: searchValue, isSearching: true, items: [] }, function () { return _this._loadInitialItems(searchValue); }); }); _defineProperty(_assertThisInitialized(_this), "_onSearchChange", function (event) { return _this._updateSearchValue(event.target.value); }); _defineProperty(_assertThisInitialized(_this), "_onClear", function () { return _this._updateSearchValue(''); }); _defineProperty(_assertThisInitialized(_this), "_checkIsSelected", function (item) { var selectedItems = _this.state.selectedItems; return !!selectedItems.find(function (_ref) { var id = _ref.id; return item.id === id; }); }); _defineProperty(_assertThisInitialized(_this), "_toggleItem", function (item) { var multiple = _this.props.multiple; _this.setState(function (_ref2) { var selectedItems = _ref2.selectedItems; return { selectedItems: multiple ? _this._checkIsSelected(item) ? selectedItems.filter(function (_ref3) { var id = _ref3.id; return item.id !== id; }) : selectedItems.concat(item) : [item] }; }); }); _defineProperty(_assertThisInitialized(_this), "_onToggle", function (item) { var onSelect = _this.props.onSelect; _this._toggleItem(item); if (onSelect) { onSelect(item); } }); _defineProperty(_assertThisInitialized(_this), "_selectAll", function () { var _this$state3 = _this.state, selectedItems = _this$state3.selectedItems, items = _this$state3.items; var enabledItems = _this._getEnabledItems(items); _this.setState({ selectedItems: selectedItems.concat(enabledItems) }); }); _defineProperty(_assertThisInitialized(_this), "_deselectAll", function () { return _this.setState(function (_ref4) { var selectedItems = _ref4.selectedItems; return { selectedItems: selectedItems.filter(function (_ref5) { var disabled = _ref5.disabled; return disabled; }) }; }); }); _defineProperty(_assertThisInitialized(_this), "_updateItems", function (_ref6) { var nextPageItems = _ref6.items, totalCount = _ref6.totalCount, searchValue = _ref6.searchValue; var _this$state4 = _this.state, items = _this$state4.items, selectedItems = _this$state4.selectedItems; // react only to the resolve of the relevant search if (searchValue !== _this.state.searchValue) { return; } var newItems = [].concat(_toConsumableArray(items), _toConsumableArray(nextPageItems)); var newSelectedItems = selectedItems.concat(nextPageItems.filter(function (_ref7) { var selected = _ref7.selected; return selected; })); var noResultsFound = newItems.length === 0 && Boolean(searchValue); var isEmpty = newItems.length === 0 && !searchValue; _this.setState({ items: newItems, selectedItems: newSelectedItems, isLoaded: true, isEmpty: isEmpty, isSearching: false, totalCount: totalCount, noResultsFound: noResultsFound }); }); _defineProperty(_assertThisInitialized(_this), "_loadInitialItems", function () { var searchValue = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; var _this$props4 = _this.props, dataSource = _this$props4.dataSource, itemsPerPage = _this$props4.itemsPerPage; var initialAmountToLoad = _this.props.initialAmountToLoad || itemsPerPage; dataSource(searchValue, 0, initialAmountToLoad).then(function (dataSourceProps) { return _this._updateItems(_objectSpread(_objectSpread({}, dataSourceProps), {}, { searchValue: searchValue })); }); }); _defineProperty(_assertThisInitialized(_this), "_loadMore", function () { var _this$props5 = _this.props, dataSource = _this$props5.dataSource, itemsPerPage = _this$props5.itemsPerPage; var _this$state5 = _this.state, items = _this$state5.items, searchValue = _this$state5.searchValue; dataSource(searchValue, items.length, itemsPerPage).then(function (dataSourceProps) { return _this._updateItems(_objectSpread(_objectSpread({}, dataSourceProps), {}, { searchValue: searchValue })); }); }); _defineProperty(_assertThisInitialized(_this), "_getEnabledItems", function (items) { return items.filter(function (_ref8) { var disabled = _ref8.disabled; return !disabled; }); }); return _this; } _createClass(SelectorList, [{ key: "componentDidMount", value: function componentDidMount() { this._loadInitialItems(); } /** Resets list items and loads first page from dataSource while persisting searchValue */ }, { key: "reloadInitialItems", value: function reloadInitialItems() { var searchValue = this.state.searchValue; this.setState({ items: [], searchValue: searchValue, isSearching: Boolean(searchValue), isLoaded: false }); this._loadInitialItems(searchValue); } }, { key: "render", value: function render() { var children = this.props.children; var selectedItems = this.state.selectedItems; if (typeof children === 'function') { return children({ renderList: this._renderList, renderToggleAllCheckbox: this._renderToggleAllCheckbox, selectedItems: selectedItems }); } return this._renderList(); } }, { key: "_hasMore", value: function _hasMore() { var _this$state6 = this.state, items = _this$state6.items, isLoaded = _this$state6.isLoaded, totalCount = _this$state6.totalCount, isSearching = _this$state6.isSearching; return items.length === 0 && !isLoaded || items.length < totalCount || isSearching; } }]); return SelectorList; }(React.PureComponent); _defineProperty(SelectorList, "displayName", 'SelectorList'); _defineProperty(SelectorList, "propTypes", { /** applied as data-hook HTML attribute that can be used to create driver in testing */ dataHook: PropTypes.string, /** * paging function that should have a signature of * ```typescript * (searchQuery: string, offset: number, limit: number) => * Promise<{ * items: Array<{ * id: number | string, * title: node, * subtitle?: string, * extraText?: string, * extraNode?: node, * disabled?: boolean // show item as disabled, dont count it in "select all", exclude from `onOk` * selected?: boolean // force item as selected * image?: node * subtitleNode?: node, * belowNode?: node, * showBelowNodeOnSelect?: boolean, * }>, * totalCount: number * }> * ``` * `offset` - next requested item's index<br> * `limit` - number of items requested<br> * `totalCount` - total number of items that suffice the current search query * */ dataSource: PropTypes.func.isRequired, /** Image icon size */ imageSize: PropTypes.oneOf(['tiny', 'small', 'portrait', 'large', 'cinema']), /** * Image icon shape, `rectangular` or `circle`.<br> * NOTE: `circle` is not compatible with `imageSize` of `portrait` or `cinema` * */ imageShape: function imageShape(props, propName, componentName) { if (['portrait', 'cinema'].includes(props.imageSize) && props[propName] === 'circle') { return new Error("".concat(componentName, ": prop \"imageSize\" with value of \"").concat(props.imageSize, "\" is incompatible with prop imageShape with value of \"circle\" \u2014 use \"rectangular\" instead.")); } }, /** Placeholder text of the search input */ searchPlaceholder: PropTypes.string, /** * Component/element that will be rendered when there is nothing to display, * i.e. empty `{items:[], totalCount: 0}` was returned on the first call to `dataSource` * */ emptyState: PropTypes.node, /** * Function that will get the current `searchQuery` and should return the component/element * that will be rendered when there are no items that suffice the entered search query * */ renderNoResults: PropTypes.func, /** Number of items loaded each time the user scrolls down */ itemsPerPage: PropTypes.number, /** Whether to display the search input or not */ withSearch: PropTypes.bool, /** Search debounce in milliseconds */ searchDebounceMs: PropTypes.number, /** Height classes property, sets the height of the list container */ height: PropTypes.string, /** Max-height classes property, sets the maximum height of the list container. */ maxHeight: PropTypes.string, /** display checkbox and allow multi selection */ multiple: PropTypes.bool, /** callback that triggers on select and return selected item object*/ onSelect: PropTypes.func, /** string to be displayed in footer when `multiple` prop is used and no items are selected */ selectAllText: PropTypes.string, /** string to be displayed in footer when `multiple` prop is used and some or all items ar selected */ deselectAllText: PropTypes.string, /** amount of items to load on initial render or after search */ initialAmountToLoad: PropTypes.number, /** Fixed text displayed above the list */ subtitle: PropTypes.node }); _defineProperty(SelectorList, "defaultProps", { searchPlaceholder: 'Search...', imageSize: 'large', imageShape: 'rectangular', itemsPerPage: 50, withSearch: true, height: '100%', maxHeight: '100%' }); export { SelectorList as default };