UNPKG

@gravityforms/components

Version:

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

315 lines (292 loc) 11.7 kB
import { consoleInfo, getNode, objectToAttributes, trigger, uniqueId, isObject, isEmptyObject, spacerClasses } from '@gravityforms/utils'; import { helpTextTemplate } from '../HelpText/index'; import { labelTemplate } from '../Label/index'; /** * @function selectTemplate * @description A select component to use wherever a simple select is needed. * * @since 2.2.0 * * @param {object} options The options for the select component. * @param {object} options.customAttributes Custom attributes for the select. * @param {Array} options.customClasses An array of additional classes for the select. * @param {boolean} options.disabled If select is disabled. * @param {string} options.helpTextAttributes Custom attribute for the help text. * @param {string} options.helpTextPosition The position of the help text. Above or below. * @param {string} options.id Optional id. Auto generated if not passed. * @param {string} options.initialValue Initial value for the select. * @param {string} options.labelAttributes Any custom attributes for the label. * @param {string} options.name The name attribute for the select. * @param {Array} options.options An array of options, each option as an object in the following structure: * { * customOptionAttrs: {}, // Key-value pairs of custom attributes. * customOptionClasses: [], // Array of strings of custom classes. * label: '', // Label as a string. * value: '', // Value as a string. * } * @param {string} options.size The select size. Small (size-s), Regular (size-r), or extra large (size-xl). * @param {string|number|Array} options.spacing The spacing for the component, string or array. * @param {string} options.theme The theme of the select. * @param options.customAttributes.optionGroup * @param options.customAttributes.groups * @param {object} options.wrapperAttributes Any custom attributes for the wrapper element. * @param {Array} options.wrapperClasses Any custom classes for the wrapper element. * @param {object} options.wrapperTagName Tag to use for the textarea wrapper. Defaults to 'div'. * @param {string} options.ariaLabel The aria-label text for the select element. * * @return {string} The html for the select component. * @example * import { selectTemplate } from '@gravityforms/components/html/admin/elements/Select'; * * function Example() { * const selectTemplateHTML = selectTemplate( options ); * document.body.insertAdjacentHTML( 'beforeend', selectTemplateHTML ); * } * */ export const selectTemplate = ( { customAttributes = {}, customClasses = [], disabled = false, helpTextAttributes = {}, helpTextPosition = 'below', id = uniqueId( 'gform-admin-select' ), initialValue = '', labelAttributes = {}, name = '', options = [], size = 'size-r', spacing = '', theme = 'cosmos', wrapperAttributes = {}, wrapperClasses = [], wrapperTagName = 'div', ariaLabel = '', } ) => { const inputId = id || uniqueId( 'gform-select' ); const helpTextId = `${ inputId }-help-text`; const wrapperAttrs = objectToAttributes( { ...wrapperAttributes, class: [ 'gform-input-wrapper', `gform-input-wrapper--theme-${ theme ? theme : 'cosmos' }`, 'gform-input-wrapper--select', `gform-input-wrapper--${ size ? size : 'size-r' }`, disabled && 'gform-input-wrapper--disabled', ...Object.keys( spacerClasses( spacing ) ), ...wrapperClasses, ], } ); const selectObj = { ...customAttributes, class: [ 'gform-select', ...customClasses, ], id: inputId, name, value: initialValue, }; if ( disabled ) { selectObj.disabled = true; } if ( helpTextAttributes.content ) { selectObj[ 'aria-describedby' ] = helpTextId; } const selectAttrs = objectToAttributes( selectObj ); if ( ariaLabel ) { selectObj[ 'aria-label' ] = ariaLabel; } const labelObj = { ...labelAttributes, htmlFor: inputId, }; const helpTextObj = { ...helpTextAttributes, id: helpTextId, }; const getSubOptions = ( choices = [] ) => { if ( isObject( choices ) && ! isEmptyObject( choices ) ) { return Object.entries( choices ).map( ( [ key ] ) => choices[ key ] ); } return choices; }; const getOption = ( { customOptionAttributes = {}, customOptionClasses = [], label = '', value = '', } ) => { const optionObj = { ...customOptionAttributes, class: [ 'gform-select__option', ...customOptionClasses, ], id: inputId, name, value, }; return ` <option ${ objectToAttributes( optionObj ) }> ${ label } </option> `; }; const getOptions = options.map( ( data ) => { const subOptions = getSubOptions( data.choices ); return subOptions.length ? ` <optgroup label="${ data.label }"> ${ subOptions.map( ( subData ) => getOption( subData ) ) } </optgroup> ` : getOption( data ); } ); const helpText = helpTextTemplate( helpTextObj ); return ` <${ wrapperTagName } ${ wrapperAttrs }> ${ labelTemplate( labelObj ) } ${ helpTextPosition === 'above' ? helpText : '' } <div class="gform-select__wrapper"> <select ${ selectAttrs }> ${ getOptions } </select> </div> ${ helpTextPosition === 'below' ? helpText : '' } </${ wrapperTagName }> `; }; /** * @class Select * @description A select component to use wherever a simple select is needed. * * @since 2.2.0 * * @param {object} options Component options. * @param {object} options.customAttributes Custom attributes for the component. * @param {string|Array|object} options.customClasses Custom classes for the component. * @param {boolean} options.disabled If select is disabled. * @param {string} options.helpTextAttributes Custom attribute for the help text. * @param {string} options.helpTextPosition The position of the help text. Above or below. * @param {string} options.id Optional id. Auto generated if not passed. * @param {string} options.initialValue Initial value for the select. * @param {string} options.labelAttributes Any custom attributes for the label. * @param {string} options.name The name attribute for the select. * @param {Array} options.options An array of options, each option as an object in the following structure: * { * customOptionAttrs: {}, // Key-value pairs of custom attributes. * customOptionClasses: [], // Array of strings of custom classes. * label: '', // Label as a string. * value: '', // Value as a string. * } * @param {string} options.size The select size. Regular (size-r) or extra large (size-xl). * @param {boolean} options.rendered Is this select already rendered in the dom, eg by php? * @param {boolean} options.renderOnInit Render the select on init of the class? * @param {string|number|Array|object} options.spacing The spacing for the component, as a string, number, array, or object. * @param {string} options.theme The theme of the select. * @param {string} options.target The target to render to. Any valid css selector string. * @param {string} options.targetPosition The insert position for the target. * @param {object} options.wrapperAttributes Custom attributes for the wrapper element. * @param {string|Array|object} options.wrapperClasses Custom classes for the wrapper element. * @param {object} options.wrapperTagName Tag to use for the textarea wrapper. Defaults to `div`. * @param {string} options.ariaLabel The aria-label text for the select element. * * @return {Class} The select instance. * @example * import Select from '@gravityforms/components/html/admin/elements/Select'; * * function Example() { * const selectInstance = new Select( { * name: 'select-name' * options: { [ * { * label: 'Option 1', * value: 'option-1', * }, * { * label: 'Option 2', * value: 'option-2', * }, * { * label: 'Option 3', * value: 'option-3', * }, * ] }, * target: '#select-target' * } ); * } * */ export default class Select { /** * @description The class constructor. * * @param {object} options The options object. Check defaults for descriptions. */ constructor( options = {} ) { this.options = {}; Object.assign( this.options, { customAttributes: {}, customClasses: [], disabled: false, helpTextAttributes: {}, helpTextPosition: 'below', id: '', initialValue: '', labelAttributes: {}, name: '', options: [], rendered: false, renderOnInit: true, size: 'size-r', spacing: '', theme: 'cosmos', target: '', targetPosition: 'afterbegin', wrapperAttributes: {}, wrapperClasses: [], wrapperTagName: 'div', ariaLabel: '', }, options ); trigger( { event: 'gform/select/pre_init', native: false, data: { instance: this } } ); this.elements = {}; if ( this.options.renderOnInit ) { this.init(); } } /** * @function render * @description Renders the component into the dom. * * @since 1.0.0 * * @return {void} */ render() { const { rendered, target, targetPosition } = this.options; if ( ! rendered ) { const renderTarget = getNode( target, document, true ); renderTarget.insertAdjacentHTML( targetPosition, selectTemplate( this.options ) ); } this.elements.select = getNode( `#${ this.options.id }`, document, true ); } /** * @function init * @description Initialize the component. * * @since 1.0.0 * * @return {void} */ init() { this.render(); trigger( { event: 'gform/select/post_render', native: false, data: { instance: this } } ); consoleInfo( `Gravity Forms Admin: Initialized select component.` ); } }