UNPKG

@shopify/polaris

Version:

Shopify’s product component library

414 lines (365 loc) • 14.2 kB
import React$1, { PureComponent, createRef } from 'react'; import { durationBase } from '@shopify/polaris-tokens'; import { clamp as clamp$1 } from '../../utilities/clamp.js'; import debounce$1 from 'lodash/debounce'; import { EventListener as EventListener$1 } from '../EventListener/EventListener.js'; import { useI18n } from '../../utilities/i18n/hooks.js'; import { classNames } from '../../utilities/css.js'; import { Popover as Popover$1 } from '../Popover/Popover.js'; import { ActionList as ActionList$1 } from '../ActionList/ActionList.js'; import { Button as Button$1 } from '../Button/Button.js'; import { ButtonGroup as ButtonGroup$1 } from '../ButtonGroup/ButtonGroup.js'; import { Transition, CSSTransition } from 'react-transition-group'; import { CheckableButton as CheckableButton$1 } from '../CheckableButton/CheckableButton.js'; import styles from './BulkActions.scss.js'; import { BulkActionButton as BulkActionButton$1 } from './components/BulkActionButton/BulkActionButton.js'; var MAX_PROMOTED_ACTIONS = 2; var slideClasses = { appear: classNames(styles.Slide, styles['Slide-appear']), appearActive: classNames(styles.Slide, styles['Slide-appearing']), enter: classNames(styles.Slide, styles['Slide-enter']), enterActive: classNames(styles.Slide, styles['Slide-entering']), exit: classNames(styles.Slide, styles['Slide-exit']) }; class BulkActionsInner extends PureComponent { constructor(...args) { super(...args); this.state = { smallScreenPopoverVisible: false, largeScreenPopoverVisible: false, containerWidth: 0, measuring: true }; this.containerNode = null; this.largeScreenButtonsNode = null; this.moreActionsNode = null; this.checkableWrapperNode = /*#__PURE__*/createRef(); this.largeScreenGroupNode = /*#__PURE__*/createRef(); this.smallScreenGroupNode = /*#__PURE__*/createRef(); this.promotedActionsWidths = []; this.bulkActionsWidth = 0; this.addedMoreActionsWidthForMeasuring = 0; this.handleResize = debounce$1(() => { var { smallScreenPopoverVisible, largeScreenPopoverVisible } = this.state; if (this.containerNode) { var containerWidth = this.containerNode.getBoundingClientRect().width; if (containerWidth > 0) { this.setState({ containerWidth }); } } if (smallScreenPopoverVisible || largeScreenPopoverVisible) { this.setState({ smallScreenPopoverVisible: false, largeScreenPopoverVisible: false }); } }, 50, { trailing: true }); this.setLargeScreenButtonsNode = node => { this.largeScreenButtonsNode = node; }; this.setContainerNode = node => { this.containerNode = node; }; this.setMoreActionsNode = node => { this.moreActionsNode = node; }; this.setSelectMode = val => { var { onSelectModeToggle } = this.props; if (onSelectModeToggle) { onSelectModeToggle(val); } }; this.toggleSmallScreenPopover = () => { if (this.props.onMoreActionPopoverToggle) { this.props.onMoreActionPopoverToggle(this.state.smallScreenPopoverVisible); } this.setState(({ smallScreenPopoverVisible }) => ({ smallScreenPopoverVisible: !smallScreenPopoverVisible })); }; this.toggleLargeScreenPopover = () => { if (this.props.onMoreActionPopoverToggle) { this.props.onMoreActionPopoverToggle(this.state.largeScreenPopoverVisible); } this.setState(({ largeScreenPopoverVisible }) => ({ largeScreenPopoverVisible: !largeScreenPopoverVisible })); }; this.handleMeasurement = width => { var { measuring } = this.state; if (measuring) { this.promotedActionsWidths.push(width); } }; } numberOfPromotedActionsToRender() { var { promotedActions } = this.props; var { containerWidth, measuring } = this.state; if (!promotedActions) { return 0; } if (containerWidth >= this.bulkActionsWidth || measuring) { return promotedActions.length; } var sufficientSpace = false; var counter = promotedActions.length - 1; var totalWidth = 0; while (!sufficientSpace && counter >= 0) { totalWidth += this.promotedActionsWidths[counter]; var widthWithRemovedAction = this.bulkActionsWidth - totalWidth + this.addedMoreActionsWidthForMeasuring; if (containerWidth >= widthWithRemovedAction) { sufficientSpace = true; } else { counter--; } } return clamp$1(counter, 0, promotedActions.length); } hasActions() { var { promotedActions, actions } = this.props; return Boolean(promotedActions && promotedActions.length > 0 || actions && actions.length > 0); } actionSections() { var { actions } = this.props; if (!actions || actions.length === 0) { return; } if (instanceOfBulkActionListSectionArray(actions)) { return actions; } if (instanceOfBulkActionArray(actions)) { return [{ items: actions }]; } } // eslint-disable-next-line @typescript-eslint/member-ordering componentDidMount() { var { actions, promotedActions } = this.props; if (promotedActions && !actions && this.moreActionsNode) { this.addedMoreActionsWidthForMeasuring = this.moreActionsNode.getBoundingClientRect().width; } this.bulkActionsWidth = this.largeScreenButtonsNode ? this.largeScreenButtonsNode.getBoundingClientRect().width - this.addedMoreActionsWidthForMeasuring : 0; if (this.containerNode) { this.setState({ containerWidth: this.containerNode.getBoundingClientRect().width, measuring: false }); } } // eslint-disable-next-line @typescript-eslint/member-ordering render() { var { selectMode, accessibilityLabel, label = '', onToggleAll, selected, smallScreen, disabled, promotedActions, paginatedSelectAllText = null, paginatedSelectAllAction, i18n } = this.props; var actionSections = this.actionSections(); if (promotedActions && promotedActions.length > MAX_PROMOTED_ACTIONS) { // eslint-disable-next-line no-console console.warn(i18n.translate('Polaris.ResourceList.BulkActions.warningMessage', { maxPromotedActions: MAX_PROMOTED_ACTIONS })); } var { smallScreenPopoverVisible, largeScreenPopoverVisible, measuring } = this.state; var paginatedSelectAllActionMarkup = paginatedSelectAllAction ? /*#__PURE__*/React$1.createElement(Button$1, { onClick: paginatedSelectAllAction.onAction, plain: true, disabled: disabled }, paginatedSelectAllAction.content) : null; var paginatedSelectAllTextMarkup = paginatedSelectAllText && paginatedSelectAllAction ? /*#__PURE__*/React$1.createElement("span", { "aria-live": "polite" }, paginatedSelectAllText) : paginatedSelectAllText; var paginatedSelectAllMarkup = paginatedSelectAllActionMarkup || paginatedSelectAllTextMarkup ? /*#__PURE__*/React$1.createElement("div", { className: styles.PaginatedSelectAll }, paginatedSelectAllTextMarkup, " ", paginatedSelectAllActionMarkup) : null; var cancelButton = /*#__PURE__*/React$1.createElement(Button$1, { onClick: this.setSelectMode.bind(this, false), disabled: disabled }, i18n.translate('Polaris.Common.cancel')); var numberOfPromotedActionsToRender = this.numberOfPromotedActionsToRender(); var allActionsPopover = this.hasActions() ? /*#__PURE__*/React$1.createElement("div", { className: styles.Popover, ref: this.setMoreActionsNode }, /*#__PURE__*/React$1.createElement(Popover$1, { active: smallScreenPopoverVisible, activator: /*#__PURE__*/React$1.createElement(BulkActionButton$1, { disclosure: true, onAction: this.toggleSmallScreenPopover, content: i18n.translate('Polaris.ResourceList.BulkActions.actionsActivatorLabel'), disabled: disabled, indicator: this.isNewBadgeInBadgeActions() }), onClose: this.toggleSmallScreenPopover }, /*#__PURE__*/React$1.createElement(ActionList$1, { items: promotedActions, sections: actionSections, onActionAnyItem: this.toggleSmallScreenPopover }))) : null; var promotedActionsMarkup = promotedActions && numberOfPromotedActionsToRender > 0 ? [...promotedActions].slice(0, numberOfPromotedActionsToRender).map((action, index) => /*#__PURE__*/React$1.createElement(BulkActionButton$1, Object.assign({ disabled: disabled }, action, { key: index, handleMeasurement: this.handleMeasurement }))) : null; var rolledInPromotedActions = promotedActions && numberOfPromotedActionsToRender < promotedActions.length ? [...promotedActions].slice(numberOfPromotedActionsToRender) : []; var activatorLabel = !promotedActions || promotedActions && numberOfPromotedActionsToRender === 0 && !measuring ? i18n.translate('Polaris.ResourceList.BulkActions.actionsActivatorLabel') : i18n.translate('Polaris.ResourceList.BulkActions.moreActionsActivatorLabel'); var combinedActions = []; if (actionSections && rolledInPromotedActions.length > 0) { combinedActions = [{ items: rolledInPromotedActions }, ...actionSections]; } else if (actionSections) { combinedActions = actionSections; } else if (rolledInPromotedActions.length > 0) { combinedActions = [{ items: rolledInPromotedActions }]; } var actionsPopover = actionSections || rolledInPromotedActions.length > 0 || measuring ? /*#__PURE__*/React$1.createElement("div", { className: styles.Popover, ref: this.setMoreActionsNode }, /*#__PURE__*/React$1.createElement(Popover$1, { active: largeScreenPopoverVisible, activator: /*#__PURE__*/React$1.createElement(BulkActionButton$1, { disclosure: true, onAction: this.toggleLargeScreenPopover, content: activatorLabel, disabled: disabled, indicator: this.isNewBadgeInBadgeActions() }), onClose: this.toggleLargeScreenPopover }, /*#__PURE__*/React$1.createElement(ActionList$1, { sections: combinedActions, onActionAnyItem: this.toggleLargeScreenPopover }))) : null; var checkableButtonProps = { accessibilityLabel, label, selected, selectMode, onToggleAll, measuring, disabled }; var smallScreenGroup = smallScreen ? /*#__PURE__*/React$1.createElement(Transition, { timeout: 0, in: selectMode, key: "smallGroup", nodeRef: this.smallScreenGroupNode }, status => { var smallScreenGroupClassName = classNames(styles.Group, styles['Group-smallScreen'], styles["Group-".concat(status)]); return /*#__PURE__*/React$1.createElement("div", { className: smallScreenGroupClassName, ref: this.smallScreenGroupNode }, /*#__PURE__*/React$1.createElement("div", { className: styles.ButtonGroupWrapper }, /*#__PURE__*/React$1.createElement(ButtonGroup$1, { segmented: true }, /*#__PURE__*/React$1.createElement(CSSTransition, { nodeRef: this.checkableWrapperNode, in: selectMode, timeout: durationBase, classNames: slideClasses, appear: !selectMode }, /*#__PURE__*/React$1.createElement("div", { className: styles.CheckableContainer, ref: this.checkableWrapperNode }, /*#__PURE__*/React$1.createElement(CheckableButton$1, Object.assign({}, checkableButtonProps, { smallScreen: true })))), allActionsPopover, cancelButton)), paginatedSelectAllMarkup); }) : null; var largeGroupContent = promotedActionsMarkup || actionsPopover ? /*#__PURE__*/React$1.createElement(ButtonGroup$1, { segmented: true }, /*#__PURE__*/React$1.createElement(CheckableButton$1, checkableButtonProps), promotedActionsMarkup, actionsPopover) : /*#__PURE__*/React$1.createElement(CheckableButton$1, checkableButtonProps); var largeScreenGroup = smallScreen ? null : /*#__PURE__*/React$1.createElement(Transition, { timeout: 0, in: selectMode, key: "largeGroup", nodeRef: this.largeScreenGroupNode }, status => { var largeScreenGroupClassName = classNames(styles.Group, styles['Group-largeScreen'], !measuring && styles["Group-".concat(status)], measuring && styles['Group-measuring']); return /*#__PURE__*/React$1.createElement("div", { className: largeScreenGroupClassName, ref: this.largeScreenGroupNode }, /*#__PURE__*/React$1.createElement(EventListener$1, { event: "resize", handler: this.handleResize }), /*#__PURE__*/React$1.createElement("div", { className: styles.ButtonGroupWrapper, ref: this.setLargeScreenButtonsNode }, largeGroupContent), paginatedSelectAllMarkup); }); return /*#__PURE__*/React$1.createElement("div", { ref: this.setContainerNode }, smallScreenGroup, largeScreenGroup); } isNewBadgeInBadgeActions() { var actions = this.actionSections(); if (!actions) return false; for (var action of actions) { for (var item of action.items) { var _item$badge; if (((_item$badge = item.badge) == null ? void 0 : _item$badge.status) === 'new') return true; } } return false; } } function instanceOfBulkActionListSectionArray(actions) { var validList = actions.filter(action => { return action.items; }); return actions.length === validList.length; } function instanceOfBulkActionArray(actions) { var validList = actions.filter(action => { return !action.items; }); return actions.length === validList.length; } function BulkActions(props) { var i18n = useI18n(); return /*#__PURE__*/React$1.createElement(BulkActionsInner, Object.assign({}, props, { i18n: i18n })); } export { BulkActions };