import {
consoleInfo,
getNode,
objectToAttributes,
spacerClasses,
trigger,
uniqueId,
} from '@gravityforms/utils';
/**
* @function toggleTemplate
* @description Generates the markup for a toggle in the admin.
*
* @since 1.1.16
*
* @param {object} options The options for the component template.
* @param {object} options.customAttributes Any custom attributes.
* @param {Array} options.customClasses An array of additional classes for the toggle.
* @param {boolean} options.disabled If the toggle is disabled.
* @param {boolean} options.icons Do we use the checkmark and x icons for this instance.
* @param {string} options.iconPrefix Prefix for the icon class.
* @param {string} options.iconBefore Icon to display when toggle is off.
* @param {string} options.iconAfter Icon to display when toggle is on.
* @param {string} options.id Id for the toggle, auto generated if not passed.
* @param {boolean} options.initialChecked Is it checked on render?
* @param {string} options.label The label, required for accessibility.
* @param {string} options.labelPosition Position for the label, defaults to right.
* @param {boolean} options.labelVisible Is the label visible?
* @param {string} options.name Name for the input.
* @param {string} options.size Size for the toggle. Small (size-s), medium (size-m), or large (size-l).
* @param {string|number|Array|object} options.spacing The spacing for the component, string, number, object or array.
* @param {string} options.theme Theme for the toggle, primary or cosmos.
* @param {string} options.ariaDescribedby Class of the element that describes this input.
* @return {string}
* @example
* import { toggleTemplate } from '@gravityforms/components/html/admin/elements/Toggle';
*
* function Example() {
* const toggleHTML = toggleTemplate( options );
* document.body.insertAdjacentHTML( 'beforeend', toggleHTML );
* }
*
*/
export const toggleTemplate = ( {
customAttributes = {},
customClasses = [],
disabled = false,
icons = false,
id = '',
initialChecked = false,
label = '',
labelPosition = 'right',
labelVisible = false,
name = '',
size = 'size-s',
spacing = '',
theme = 'primary',
ariaDescribedby = '',
} ) => {
const componentAttrs = objectToAttributes( {
...customAttributes,
class: [
'gform-toggle',
theme === 'cosmos' ? 'gform-toggle--theme-cosmos' : '',
`gform-toggle--label-${ labelPosition }`,
`gform-toggle--${ size }`,
...Object.keys( spacerClasses( spacing ) ),
...customClasses,
],
} );
const labelClassName = [
'gform-toggle__label',
! labelVisible ? 'gform-visually-hidden' : '',
];
return `
<div ${ componentAttrs }>
<input
${ initialChecked ? 'checked' : '' }
class="gform-toggle__toggle${ icons ? ' gform-toggle__toggle--has-icons' : '' }"
id="${ id }"
name="${ name }"
type="checkbox"
${ disabled ? 'disabled' : '' }
${ ariaDescribedby ? `aria-describedby="${ ariaDescribedby }"` : '' }
/>
<label
class="${ labelClassName.join( ' ' ) }"
for="${ id }"
>
${ label }
</label>
</div>
`;
};
/**
* @class Toggle
* @description A toggle component to use wherever boolean based form fields are needed.
*
* @since 1.1.16
*
* @borrows toggleTemplate as toggleTemplate
*
* @param {object} options The options for the component.
* @param {object} options.customAttributes Any custom attributes for the component.
* @param {Array} options.customClasses An array of additional classes for the component.
* @param {Array} options.disabled Is the toggle disabled on render?
* @param {boolean} options.icons Do we use the checkmark and x icons for this instance?
* @param {string} options.id Id for the component, auto generated if not passed.
* @param {boolean} options.initialChecked Is it checked on render?
* @param {string} options.label The label, required for accessibility.
* @param {string} options.labelPosition Position for the label, defaults to right.
* @param {boolean} options.labelVisible Is the label visible?
* @param {string} options.rendered Is the component already rendered in the dom, eg by php?
* @param {string} options.renderOnInit Render the component on init of the class?
* @param {string} options.name Name for the input.
* @param {string} options.size Size for the component. Small (size-s), medium (size-m), or large (size-l).
* @param {string} options.spacing Spacing for the component.
* @param {string} options.target The target to render to. Any valid css selector string.
* @param {string} options.targetPosition The insert position for the component relative to the target.
* @param {string} options.theme Theme for the component, primary or cosmos.
*
* @return {Class} The class instance.
* @example
* import Toggle from '@gravityforms/components/html/admin/elements/Toggle';
*
* function Example() {
* const toggleInstance = new Toggle( {
* id: 'example-toggle',
* label: 'Example Toggle',
* name: 'example-toggle',
* renderOnInit: false,
* target: '#example-target',
* targetPosition: 'beforeend',
* theme: 'cosmos',
* } );
*
* // Some time later we can render it. This is only done if we set renderOnInit to false.
* // If true it will render on initialization.
* toggleInstance.init();
* }
*
*/
export default class Toggle {
constructor( options = {} ) {
this.options = {};
Object.assign(
this.options,
{
customAttributes: {},
customClasses: [],
disabled: false,
icons: false,
id: '',
initialChecked: false,
label: '',
labelPosition: 'right',
labelVisible: false,
name: '',
rendered: false,
renderOnInit: true,
size: 'size-s',
spacing: '',
target: '',
targetPosition: 'afterbegin',
theme: 'cosmos',
},
options
);
/**
* @event gform/toggle/pre_init
* @type {object}
* @description Fired before the component has started any internal init functions. A great chance to augment the options.
*
* @since 1.1.16
*
* @property {object} instance The Component class instance.
*/
trigger( { event: 'gform/toggle/pre_init', native: false, data: { instance: this } } );
this.options.id = this.options.id || uniqueId( 'toggle' );
this.elements = {};
if ( this.options.renderOnInit ) {
this.init();
}
}
/**
* @memberof Toggle
* @description Renders the component into the dom.
*
* @since 1.1.16
*
* @return {void}
*/
render() {
const { rendered, target, targetPosition } = this.options;
if ( ! rendered ) {
const renderTarget = getNode( target, document, true );
renderTarget.insertAdjacentHTML(
targetPosition,
toggleTemplate( this.options )
);
}
this.elements.input = getNode( `#${ this.options.id }`, document, true );
this.elements.wrapper = this.elements.input.parentNode;
}
/**
* @memberof Toggle
* @description Initialize the component.
*
* @fires gform/toggle/post_render
*
* @since 1.1.16
*
* @return {void}
*/
init() {
this.render();
/**
* @event gform/toggle/post_render
* @type {object}
* @description Fired when the component has completed rendering and all class init functions have completed.
*
* @since 1.1.16
*
* @property {object} instance The Component class instance.
*/
trigger( { event: 'gform/toggle/post_render', native: false, data: { instance: this } } );
consoleInfo( `Gravity Forms Admin: Initialized toggle component.` );
}
}