@gravityforms/components
Version:
UI components for use in Gravity Forms development. Both React and vanilla js flavors.
178 lines (167 loc) • 6.03 kB
JavaScript
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;