UNPKG

@wix/design-system

Version:

@wix/design-system

112 lines 5.26 kB
import React from 'react'; import { ChevronDownSmall } from '@wix/wix-ui-icons-common'; import { classes } from './BadgeSelect.st.css.js'; import DropdownLayout from '../DropdownLayout'; import PopoverNext from '../PopoverNext'; import Badge from '../Badge'; import { badgeSelectItemBuilder } from '../BadgeSelectItem'; import * as DATA_ATTR from './DataAttr'; import { IconThemeContext } from '../WixDesignSystemIconThemeProvider/IconThemeContext'; class BadgeSelect extends React.Component { constructor(props) { super(props); this._isControlled = () => { return typeof this.props.selectedId !== 'undefined'; }; /** * Determine if a certain key should open the DropdownLayout * * @param {KeyboardEvent.key} key - The key name * @return {boolean} - Whether the key should cause the DropdownLayout to open */ this._isOpenKey = key => { return ['Enter', 'Spacebar', ' ', 'ArrowDown'].includes(key); }; this._getBadgeOptionById = (options, wantedId) => { return options.find(({ id }) => id === wantedId); }; this._handleSelect = ({ id: selectedId }) => { const { onSelect, options } = this.props; const selectedBadge = this._getBadgeOptionById(options, selectedId); const newState = { visible: false }; if (!this._isControlled()) { newState.selectedBadge = selectedBadge; } this.setState(newState); onSelect && onSelect(selectedBadge); }; this._onKeyDown = event => { // Delegate the event to the DropdownLayout. It'll handle the navigation, // option selection and closing of the dropdown. const isHandledByDropdownLayout = this.dropdownLayout ? this.dropdownLayout._onSelectListKeyDown(event) : false; // If the event wasn't handled by the DropdownLayout correctly, check if // the pressed key should open the dropdown and act accordingly. if (!isHandledByDropdownLayout) { if (this._isOpenKey(event.key)) { this.showDropdown(); event.preventDefault(); } } }; this.getSelectedOption = props => { return (this._getBadgeOptionById(props.options, props.selectedId) || props.options[0]); }; this.hideDropdown = () => { this.setState({ visible: false }); }; this.showDropdown = () => { this.setState({ visible: true }); }; this.toggleDropdown = () => { this.setState({ visible: !this.state.visible }); }; this.state = { visible: false, selectedBadge: this.getSelectedOption(props), }; } get options() { const { options } = this.props; return Array.isArray(options) ? options.map(option => badgeSelectItemBuilder({ ...option })) : []; } UNSAFE_componentWillReceiveProps(nextProps) { if (this.props.selectedId !== nextProps.selectedId) { this.setState({ selectedBadge: this.getSelectedOption(nextProps), }); } } render() { const { type, size, uppercase, dataHook, popoverProps } = this.props; const { visible, selectedBadge } = this.state; return (React.createElement(IconThemeContext.Consumer, null, ({ icons = {} }) => { const ChevronDownSmallIcon = icons.BadgeSelect?.ChevronDownSmall || ChevronDownSmall; return (React.createElement(PopoverNext, { open: visible, onOpenChange: (open, reason) => { if (!open && (reason === 'outside-press' || reason === 'escape-key')) { this.hideDropdown(); } }, focusManagerEnabled: false, dataHook: dataHook, placement: "bottom", moveBy: { y: 4 }, maxWidth: "300px", onKeyDown: this._onKeyDown, autoUpdateOptions: { animationFrame: true }, ...popoverProps, className: classes.root }, React.createElement(PopoverNext.Trigger, null, React.createElement("span", null, React.createElement(Badge, { type: type, size: size, uppercase: uppercase, suffixIcon: React.createElement(ChevronDownSmallIcon, null), skin: this.state.selectedBadge.skin, onClick: this.toggleDropdown, dataHook: DATA_ATTR.DATA_BADGE }, this.state.selectedBadge.text))), React.createElement(PopoverNext.Content, null, React.createElement(DropdownLayout, { ref: r => { this.dropdownLayout = r; }, dataHook: DATA_ATTR.DATA_DROPDOWN, visible: true, selectedId: selectedBadge.id, options: this.options, onSelect: this._handleSelect, onClose: this.hideDropdown, inContainer: true })))); })); } } BadgeSelect.displayName = 'BadgeSelect'; BadgeSelect.defaultProps = { size: 'medium', type: 'solid', uppercase: true, }; export default BadgeSelect; //# sourceMappingURL=BadgeSelect.js.map