UNPKG

@gravityforms/components

Version:

UI components for use in Gravity Forms development. Both React and vanilla js flavors.

178 lines (167 loc) 6.03 kB
import { React, classnames, PropTypes } from '@gravityforms/libraries'; import Icon from '../../elements/Icon'; import Text from '../../elements/Text'; const { forwardRef } = React; /** * @module DroplistItem * @description The DroplistItem component. * * @since 4.3.0 * * @param {object} props Props for the DroplistItem component. * @param {object} props.customAttributes Custom attributes for the droplist item. * @param {string|Array|object} props.customClasses Custom classes for the droplist item. * @param {number} props.depth The depth of the droplist item. * @param {string} props.element The element type to render, one of `button` or `link`. * @param {string} props.iconAfter The icon after the text. * @param {object} props.iconAfterAttributes Custom attributes for the icon after the text. * @param {string|Array|object} props.iconAfterClasses Custom classes for the icon after the text. * @param {string} props.iconBefore The icon before the text. * @param {object} props.iconBeforeAttributes Custom attributes for the icon before the text. * @param {string|Array|object} props.iconBeforeClasses Custom classes for the icon before the text. * @param {string} props.iconPrefix The icon prefix to use. * @param {number} props.index The index of the droplist item. * @param {string} props.label The label to display. * @param {object} props.labelAttributes Custom attributes for the label component. * @param {string|Array|object} props.labelClasses Custom classes for the label component. * @param {object} props.propsWithState Props and state to pass to the droplist item. * @param {string} props.style The style of the droplist item, one of `info` or `error`. * @param {object|null} ref Ref to the component. * * @return {JSX.Element|null} The DroplistItem component. */ export const DroplistItem = forwardRef( ( { customAttributes = {}, customClasses = [], depth = 0, element = 'button', iconAfter = '', iconAfterAttributes = {}, iconAfterClasses = [], iconBefore = '', iconBeforeAttributes = {}, iconBeforeClasses = [], iconPrefix = 'gravity-component-icon', index = 0, label = '', labelAttributes = {}, labelClasses = [], propsWithState = {}, style = 'info', }, ref ) => { // Check if element type is valid, return null if not. if ( ! [ 'button', 'link' ].includes( element ) ) { return null; } const { openOnHover, selectedState, setSelectedState, stackNestedGroups } = propsWithState; const setSelectedStateOpen = () => { const { id = '' } = customAttributes; // If the group is already open, do nothing. if ( selectedState[ depth ] === id ) { return; } const depthKeys = Object.keys( selectedState ); const filteredState = depthKeys .filter( ( key ) => key < depth ) .reduce( ( acc, key ) => { acc[ key ] = selectedState[ key ]; return acc; }, {} ); const newSelectedState = { ...filteredState, [ depth ]: id, }; setSelectedState( newSelectedState ); }; const triggerProps = { className: classnames( { 'gform-droplist__item-trigger': true, [ `gform-droplist__item-trigger--${ style }` ]: true, [ `gform-droplist__item-trigger--depth-${ depth }` ]: true, [ `gform-droplist__item-trigger--${ index }` ]: true, 'gform-droplist__item-trigger--disabled': element === 'button' && customAttributes.disabled, }, customClasses ), onMouseEnter: openOnHover && ! stackNestedGroups ? () => { setSelectedStateOpen(); } : undefined, ...customAttributes, }; if ( propsWithState.closeOnClick ) { triggerProps.onClick = ( event ) => { const { onClick = () => {} } = customAttributes; onClick( event ); propsWithState.closeDroplist(); }; } const iconBeforeProps = { icon: iconBefore, iconPrefix, customClasses: classnames( { 'gform-droplist__item-trigger-icon': true, 'gform-droplist__item-trigger-icon--before': true, }, iconBeforeClasses ), ...iconBeforeAttributes, }; const iconAfterProps = { icon: iconAfter, iconPrefix, customClasses: classnames( { 'gform-droplist__item-trigger-icon': true, 'gform-droplist__item-trigger-icon--after': true, }, iconAfterClasses ), ...iconAfterAttributes, }; const labelProps = { content: label, customClasses: classnames( { 'gform-droplist__item-trigger-text': true, }, labelClasses ), color: style === 'error' ? 'red' : undefined, size: 'text-sm', ...labelAttributes, }; const Component = element === 'link' ? 'a' : element; return ( <Component ref={ ref } { ...triggerProps }> { iconBefore && <Icon { ...iconBeforeProps } /> } { label && <Text { ...labelProps } /> } { iconAfter && <Icon { ...iconAfterProps } /> } </Component> ); } ); DroplistItem.propTypes = { customAttributes: PropTypes.object, customClasses: PropTypes.oneOfType( [ PropTypes.string, PropTypes.array, PropTypes.object, ] ), depth: PropTypes.number, element: PropTypes.oneOf( [ 'button', 'link' ] ), iconAfter: PropTypes.string, iconAfterAttributes: PropTypes.object, iconAfterClasses: PropTypes.oneOfType( [ PropTypes.string, PropTypes.array, PropTypes.object, ] ), iconBefore: PropTypes.string, iconBeforeAttributes: PropTypes.object, iconBeforeClasses: PropTypes.oneOfType( [ PropTypes.string, PropTypes.array, PropTypes.object, ] ), iconPrefix: PropTypes.string, label: PropTypes.string, labelAttributes: PropTypes.object, labelClasses: PropTypes.oneOfType( [ PropTypes.string, PropTypes.array, PropTypes.object, ] ), propsWithState: PropTypes.object, style: PropTypes.oneOf( [ 'info', 'error' ] ), }; DroplistItem.displayName = 'DroplistItem'; export default DroplistItem;