UNPKG

@gravityforms/components

Version:

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

213 lines (199 loc) 7.86 kB
import { React, PropTypes, classnames } from '@gravityforms/libraries'; import { ConditionalWrapper, useStateWithDep } from '@gravityforms/react-utils'; import { spacerClasses, uniqueId } from '@gravityforms/utils'; import HelpText from '../HelpText'; import Label from '../Label'; const { useState, forwardRef } = React; /** * @module Toggle * @description A toggle component to use wherever boolean based form fields are needed. * * @since 1.1.15 * * @param {object} props Component props. * @param {string} props.ariaLabel The aria-label text for the toggle. * @param {JSX.Element} props.children React element children. * @param {object} props.customAttributes Custom attributes for the component. * @param {string|Array|object} props.customClasses Custom classes for the component. * @param {boolean} props.disabled If toggle is disabled. * @param {boolean} props.externalChecked If toggle is checked or not, can change current checked state if changed. * @param {boolean} props.externalControl If toggle can be controlled externally. * @param {object} props.helpTextAttributes Attributes for the help text component. * @param {string} props.helpTextWidth Width of the help text, one of `auto` or `full`. * @param {boolean} props.icons Do we use the checkmark and x icons for this instance. * @param {string} props.iconPrefix The icon prefix to use for the icons. * @param {string} props.iconBefore The icon to use when the toggle is unchecked. * @param {string} props.iconAfter The icon to use when the toggle is checked. * @param {string} props.id Id for the toggle, auto generated if not passed. * @param {boolean} props.initialChecked Is it checked on render? * @param {object} props.labelAttributes Attributes for the label component. * @param {string} props.labelPosition Position of the label, one of `left` or `right`. * @param {string} props.name Name for the input. * @param {Function} props.onBlur On blur function handler. * @param {Function} props.onChange On change function handler. * @param {Function} props.onFocus On focus function handler. * @param {string} props.size Size for the toggle. Small (`size-s`), medium (`size-m`), or large (`size-l`). * @param {string|number|Array|object} props.spacing The spacing for the component, as a string, number, array, or object. * @param {string} props.theme Theme for the toggle, one of `primary` or `cosmos`. * @param {string} props.width Width for the toggle, one of `auto` or `full`. * @param {object} props.wrapperAttributes Custom attributes for the wrapper element. * @param {string|Array|object} props.wrapperClasses Custom classes for the wrapper element. * @param {object} props.wrapperTagName Tag to use for the toggle wrapper. Defaults to `div`. * @param {object|null} ref Ref to the component. * * @return {JSX.Element} The toggle component. * * @example * import Toggle from '@gravityforms/components/react/admin/elements/Toggle'; * * return <Toggle disabled={ true } initialChecked={ true } onChange={ () => {} } />; * */ const Toggle = forwardRef( ( { ariaLabel = '', children = null, customAttributes = {}, customClasses = [], disabled = false, externalChecked = false, externalControl = false, helpTextAttributes = {}, helpTextWidth = 'auto', icons = true, id = '', initialChecked = false, labelAttributes = {}, labelPosition = 'right', name = '', onBlur = () => {}, onChange = () => {}, onFocus = () => {}, size = 'size-s', spacing = '', theme = 'cosmos', width = 'auto', wrapperAttributes = {}, wrapperClasses = [], wrapperTagName = 'div', }, ref ) => { const [ checked, setChecked ] = useState( initialChecked ); const [ controlChecked, setControlChecked ] = useStateWithDep( externalChecked ); // eslint-disable-line no-unused-vars const inputId = id || uniqueId( 'toggle' ); const helpTextId = `${ inputId }-help-text`; const wrapperProps = { ...wrapperAttributes, className: classnames( { 'gform-toggle': true, [ `gform-toggle--theme-${ theme }` ]: true, [ `gform-toggle--${ size }` ]: true, [ `gform-toggle--label-${ labelPosition }` ]: true, [ `gform-toggle--width-${ width }` ]: true, [ `gform-toggle--help-text-width-${ helpTextWidth }` ]: helpTextAttributes.content, 'gform-toggle--disabled': disabled, ...spacerClasses( spacing ), }, wrapperClasses ), ref, }; const inputProps = { ...customAttributes, checked: externalControl ? controlChecked : checked, className: classnames( { 'gform-toggle__toggle': true, 'gform-toggle__toggle--has-icons': icons, }, customClasses ), disabled: disabled || labelAttributes?.locked === true, id: inputId, name, onBlur, onChange: ( event ) => { const { checked: toggleChecked } = event.target; if ( ! externalControl ) { setChecked( toggleChecked ); } setTimeout( () => { onChange( toggleChecked ); }, 150 ); }, onFocus, type: 'checkbox', }; if ( ariaLabel ) { inputProps[ 'aria-label' ] = ariaLabel; } if ( helpTextAttributes.content ) { inputProps[ 'aria-describedby' ] = helpTextId; } if ( ! helpTextAttributes.spacing ) { helpTextAttributes.spacing = [ 4, 0, 0, 0 ]; } const labelProps = { ...labelAttributes, customClasses: classnames( [ 'gform-toggle__label', ], labelAttributes.customClasses ), htmlFor: inputId, }; const helpTextProps = { ...helpTextAttributes, id: helpTextId, }; const Container = wrapperTagName; return ( <Container { ...wrapperProps }> <input { ...inputProps } /> <ConditionalWrapper condition={ helpTextAttributes.content && labelAttributes.label } wrapper={ ( ch ) => <div className="gform-toggle__label-wrapper">{ ch }</div> } > <Label { ...labelProps } /> { helpTextAttributes.content && <HelpText { ...helpTextProps } /> } { children } </ConditionalWrapper> </Container> ); } ); Toggle.propTypes = { ariaLabel: PropTypes.string, children: PropTypes.oneOfType( [ PropTypes.arrayOf( PropTypes.node ), PropTypes.node, ] ), customAttributes: PropTypes.object, customClasses: PropTypes.oneOfType( [ PropTypes.string, PropTypes.array, PropTypes.object, ] ), disabled: PropTypes.bool, externalChecked: PropTypes.bool, externalControl: PropTypes.bool, helpTextAttributes: PropTypes.object, helpTextWidth: PropTypes.oneOf( [ 'auto', 'full' ] ), icons: PropTypes.bool, id: PropTypes.string, initialChecked: PropTypes.bool, labelAttributes: PropTypes.object, labelPosition: PropTypes.string, name: PropTypes.string, onBlur: PropTypes.func, onChange: PropTypes.func, onFocus: PropTypes.func, size: PropTypes.string, spacing: PropTypes.oneOfType( [ PropTypes.string, PropTypes.number, PropTypes.array, PropTypes.object, ] ), theme: PropTypes.string, width: PropTypes.oneOf( [ 'auto', 'full' ] ), wrapperAttributes: PropTypes.object, wrapperClasses: PropTypes.oneOfType( [ PropTypes.string, PropTypes.array, PropTypes.object, ] ), wrapperTagName: PropTypes.string, }; Toggle.displayName = 'Toggle'; export default Toggle;