@shopify/polaris
Version:
Shopify’s product component library
414 lines (365 loc) • 14.2 kB
JavaScript
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 };