Created
November 9, 2022 16:30
-
-
Save richaber/481e1b463c1bac7e4efed1b12686200b to your computer and use it in GitHub Desktop.
components/SelectOptions.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* SelectOptions is a child Component | |
* for use with WordPress' SelectControl Component | |
* to easily implement Optgroups. | |
* See the {@link Option} and {@link Optgroup} typedefs for the expected data shape(s). | |
* | |
* SelectControl doesn't appear to natively support an optgroup data shape | |
* (as of @wordpress/components v 22.0.0 anyway), | |
* and the SelectControl documentation | |
* only provides a lone optgroup example using hardcoded markup. | |
* | |
* @link https://developer.wordpress.org/block-editor/reference-guides/components/select-control/ | |
* | |
* @example <caption>SelectControl without SelectOptions example</caption> | |
* <SelectControl | |
* label={ __( 'Select an item:' ) } | |
* value={ item } // e.g: value = 'a' | |
* onChange={ ( selection ) => { setItem( selection ) } } > | |
* <optgroup label="America"> | |
* <option value="America/Chicago">Chicago</option> | |
* <option value="America/Chihuahua">Chihuahua</option> | |
* <option value="America/Costa_Rica">Costa Rica</option> | |
* </optgroup> | |
* </SelectControl> | |
* | |
* @example <caption>SelectControl with SelectOptions example (where optGroups is | |
* a variable defined elsewhere in the shape of {@link Optgroup})</caption> | |
* <SelectControl | |
* label={ __( 'Select an item:' ) } | |
* value={ item } // e.g: value = 'a' | |
* onChange={ ( selection ) => { setItem( selection ) } } > | |
* <SelectOptions options={optGroups} /> | |
* </SelectControl> | |
*/ | |
import {Component} from '@wordpress/element'; | |
/** | |
* The Option element data object. | |
* | |
* @typedef {Object} Option | |
* @property {string} Option.label - The Option label (Also used as inner text). | |
* @property {string} Option.value - The Option value. | |
* @property {bool} [Option.disabled] - If this Boolean attribute is set, this option is not selectable. | |
* | |
* @example <caption>Option example shape</caption> | |
* { | |
* "value": "America/Chicago", | |
* "label": "Chicago", | |
* "disabled": false | |
* } | |
*/ | |
/** | |
* The Option Group element data object. | |
* | |
* @typedef {Object} Optgroup | |
* @property {string} Optgroup.label - The Optgroup label. | |
* @property {Option[]} Optgroup.options - An array of Option elements. | |
* @property {bool} [Optgroup.disabled] - If this Boolean attribute is set, none of the items in this option group are selectable. | |
* | |
* @example <caption>Optgroup example shape</caption> | |
* { | |
* "label": "America", | |
* "disabled": false | |
* "options": [ | |
* { | |
* "value": "America/Chicago", | |
* "label": "Chicago", | |
* "disabled": false | |
* } | |
* ], | |
* } | |
*/ | |
/** | |
* SelectOptions Component. | |
*/ | |
export default class SelectOptions extends Component { | |
constructor(props) { | |
super(props); | |
this.state = { | |
hasError: false | |
}; | |
} | |
static getDerivedStateFromError() { | |
return { | |
hasError: true | |
}; | |
} | |
componentDidCatch(error) { | |
const { | |
name, | |
onError | |
} = this.props; | |
if (onError) { | |
onError(name, error); | |
} | |
} | |
/** | |
* Return an option tag element. | |
* | |
* @param {Option} option - An {@link Option} object. | |
* | |
* @returns {JSX.Element} | |
*/ | |
getOptionTag = function (option) { | |
return ( | |
<option value={option.value} | |
key={option.value} | |
disabled={option.disabled}> | |
{option.label} | |
</option> | |
); | |
}; | |
/** | |
* Get the option tags. | |
* | |
* @param {Option[]|Option} options - An array of, or a single {@link Option} object. | |
* | |
* @returns {JSX.Element[]|JSX.Element} - Returns an array of, or a single, {@link JSX.Element} | |
*/ | |
getOptionTags = function (options) { | |
if ( | |
!options.isArray && options.hasOwnProperty('label') | |
&& options.hasOwnProperty('value') | |
) { | |
// Single Option object. | |
return this.getOptionTag(options); | |
} | |
return options.map((option) => { | |
// Array of Option objects. | |
return this.getOptionTag(option); | |
}); | |
}; | |
/** | |
* Get the Option and Optgroup tags. | |
* | |
* @param {(Optgroup|Option)[]} data Array of {@link Option}/{@link Optgroup} objects. | |
* @returns {JSX.Element[]} | |
*/ | |
getOptions = function (data) { | |
var tags = []; | |
for (let i = 0; i < data.length; i++) { | |
if ( | |
data[i].hasOwnProperty('label') | |
&& data[i].hasOwnProperty('options') | |
) { | |
/** | |
* If it has a label and options, it is an {@link Optgroup}. | |
*/ | |
tags.push(this.getOptgroupTag(data[i])); | |
} else if ( | |
data[i].hasOwnProperty('label') | |
&& data[i].hasOwnProperty('value') | |
) { | |
/** | |
* If it has a label and value, it is an {@link Option}. | |
*/ | |
tags.push(this.getOptionTag(data[i])); | |
} | |
} | |
return tags; | |
}; | |
/** | |
* Return an optgroup tag element, with it's child option tag elements. | |
* | |
* @param {Optgroup} optgroup - An Optgroup object. | |
* | |
* @returns {JSX.Element} | |
*/ | |
getOptgroupTag = function (optgroup) { | |
var children = this.getOptionTags(optgroup.options); | |
return ( | |
<optgroup key={optgroup.label} | |
label={optgroup.label} | |
disabled={optgroup.disabled}> | |
{children} | |
</optgroup> | |
); | |
}; | |
render() { | |
if (!this.state.hasError) { | |
return this.getOptions(this.props.options); | |
} | |
return null; | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment