elements_DescriptionList_index.js

import { React, PropTypes, classnames } from '@gravityforms/libraries';
import { spacerClasses } from '@gravityforms/utils';
import Heading from '../Heading';
import DescriptionListItem from '../../utils/description-list-item';

const { Fragment, forwardRef } = React;

/**
 * @module DescriptionList
 * @description A Description List component.
 *
 * @since 3.4.0
 *
 * @param {object}                     props                  Component props.
 * @param {object}                     props.customAttributes Custom attributes for the component.
 * @param {string|Array|object}        props.customClasses    Custom classes for the component.
 * @param {Array}                      props.groups           Array of groups of terms and descriptions.
 * @param {string}                     props.id               The ID of the component.
 * @param {string|number|Array|object} props.spacing          The spacing for the component, as a string, number, array, or object.
 * @param {string}                     props.title            The title for the component.
 * @param {object}                     props.titleAttributes  Custom attributes for the title.
 * @param {string|Array|object}        props.titleClasses     Custom classes for the title.
 * @param {string}                     props.type             The type of description list, one of `default` or `list`.
 * @param {object|null}                ref                    Ref to the component.
 *
 * @return {JSX.Element} The description list component.
 *
 * @example
 * import DescriptionList from '@gravityforms/components/react/admin/elements/DescriptionList';
 *
 * const groups = [
 *   {
 *     terms: {
 *       component: 'Text',
 *       props: {
 *         content: 'Chrome',
 *         size: 'text-sm',
 *         weight: 'semibold',
 *       },
 *     },
 *     descriptions: {
 *       component: 'Text',
 *       props: {
 *         content: 'A cross-platform web browser developed by Google.',
 *         size: 'text-sm',
 *       },
 *     },
 *     wrapper: true,
 *   },
 *   {
 *     terms: {
 *       component: 'Text',
 *       props: {
 *         content: 'Firefox',
 *         size: 'text-sm',
 *         weight: 'semibold',
 *       },
 *     },
 *     descriptions: [
 *       {
 *         component: 'Text',
 *         props: {
 *           content: 'A free, open source, cross-platform, graphical web browser developed by the Mozilla Corporation and hundreds of volunteers.',
 *           size: 'text-sm',
 *         },
 *       },
 *       {
 *         component: 'Text',
 *         props: {
 *           content: 'The Red Panda also known as the Lesser Panda, Wah, Bear Cat or Firefox, is a mostly herbivorous mammal, slightly larger than a domestic cat (60 cm long).',
 *           size: 'text-sm',
 *         },
 *       },
 *     ],
 *   },
 *   {
 *     terms: [
 *       {
 *         component: 'Text',
 *         props: {
 *           content: 'Internet Explorer',
 *           size: 'text-sm',
 *           weight: 'semibold',
 *         },
 *       },
 *       {
 *         component: 'Text',
 *         props: {
 *           content: 'Netscape',
 *           size: 'text-sm',
 *           weight: 'semibold',
 *         },
 *       },
 *     ],
 *     descriptions: {
 *       component: 'Text',
 *       props: {
 *         content: 'Browsers that have been discontinued.',
 *         size: 'text-sm',
 *       },
 *     },
 *   },
 * ];
 *
 * return <DescriptionList groups={ groups } />;
 *
 */
const DescriptionList = forwardRef( ( {
	customAttributes = {},
	customClasses = [],
	groups = [],
	id = '',
	spacing = '',
	title = null,
	titleAttributes = {},
	titleClasses = [],
	type = 'default',
}, ref ) => {
	const componentProps = {
		className: classnames( {
			'gform-description-list': true,
			[ `gform-description-list--${ type }` ]: true,
			...spacerClasses( spacing ),
		}, customClasses ),
		ref,
		...customAttributes,
	};

	const titleProps = {
		customClasses: classnames( {
			'gform-description-list__title': true,
		}, titleClasses ),
		size: 'text-lg',
		tagName: 'h2',
		weight: 'medium',
		...titleAttributes,
	};

	const ListElement = 'default' === type ? 'div' : 'dl';
	const TermElement = 'default' === type ? 'div' : 'dt';
	const DescElement = 'default' === type ? 'div' : 'dd';

	return (
		<div { ...componentProps }>
			{ title && <Heading { ...titleProps }>{ title }</Heading> }
			<ListElement className="gform-description-list__list">
				{ groups.map( ( group, index ) => {
					let terms = null;
					if ( Array.isArray( group.terms ) ) {
						terms = group.terms.map( ( term, termIndex ) => (
							<TermElement
								key={ `${ id }-group-${ index }-term-${ termIndex }` }
								className="gform-description-list__term"
							>
								<DescriptionListItem data={ term } />
							</TermElement>
						) );
					} else {
						terms = (
							<TermElement
								className="gform-description-list__term"
							>
								<DescriptionListItem data={ group.terms } />
							</TermElement>
						);
					}

					let descriptions = null;
					if ( Array.isArray( group.descriptions ) ) {
						descriptions = group.descriptions.map( ( description, descIndex ) => (
							<DescElement
								key={ `${ id }-group-${ index }-description-${ descIndex }` }
								className="gform-description-list__description"
							>
								<DescriptionListItem data={ description } />
							</DescElement>
						) );
					} else {
						descriptions = (
							<DescElement
								className="gform-description-list__description"
							>
								<DescriptionListItem data={ group.descriptions } />
							</DescElement>
						);
					}

					if ( group.wrapper ) {
						return (
							<div
								key={ `${ id }-group-${ index }-group` }
								className="gform-description-list__group"
							>
								{ terms }
								{ descriptions }
							</div>
						);
					}

					return (
						<Fragment key={ `${ id }-group-${ index }` }>
							{ terms }
							{ descriptions }
						</Fragment>
					);
				} ) }
			</ListElement>
		</div>
	);
} );

DescriptionList.propTypes = {
	customAttributes: PropTypes.object,
	customClasses: PropTypes.oneOfType( [
		PropTypes.string,
		PropTypes.array,
		PropTypes.object,
	] ),
	groups: PropTypes.arrayOf( PropTypes.object ),
	id: PropTypes.string.isRequired,
	spacing: PropTypes.oneOfType( [
		PropTypes.string,
		PropTypes.number,
		PropTypes.array,
		PropTypes.object,
	] ),
	title: PropTypes.string,
	titleAttributes: PropTypes.object,
	titleClasses: PropTypes.oneOfType( [
		PropTypes.string,
		PropTypes.array,
		PropTypes.object,
	] ),
	type: PropTypes.oneOf( [ 'default', 'list' ] ),
};

DescriptionList.displayName = 'DescriptionList';

export default DescriptionList;