/** * Renders one option from its schema entry. * * Every branch here maps a type from SettingsSchema.php to a control. The help * text is never optional -- it comes from the schema, and the schema requires * one for every field. */ import { __ } from '@wordpress/i18n'; import { useState } from '@wordpress/element'; import { BaseControl, Button, RadioControl, SelectControl, TextControl, TextareaControl, ToggleControl, __experimentalVStack as VStack, } from '@wordpress/components'; /** * Whether a field's condition is met by the current values. * * @param {Object} field The schema entry. * @param {Object} values Current values. * @return {boolean} True when the field should be shown. */ export function isVisible( field, values ) { if ( ! field.depends ) { return true; } return Object.entries( field.depends ).every( // Loose comparison: a choice value of 1 arrives as a number from the // schema but may sit in the form state as the string "1". // eslint-disable-next-line eqeqeq ( [ key, expected ] ) => values[ key ] == expected ); } /** * Opens the media library and hands back the chosen attachment. * * @param {Function} onSelect Receives the attachment id and its preview url. */ function openMediaLibrary( onSelect ) { if ( ! window.wp?.media ) { return; } const frame = window.wp.media( { title: __( 'Choose an image', 'cryptx' ), multiple: false, library: { type: 'image' }, } ); frame.on( 'select', () => { const attachment = frame.state().get( 'selection' ).first().toJSON(); onSelect( attachment.id, attachment.url ); } ); frame.open(); } export default function Field( { field, value, onChange } ) { const [ mediaUrl, setMediaUrl ] = useState( null ); const id = `cryptx-field-${ field.key }`; switch ( field.type ) { case 'boolean': return ( onChange( field.key, checked ? 1 : 0 ) } /> ); case 'choice': { const options = field.choices.map( ( choice ) => ( { label: choice.label, value: String( choice.value ), } ) ); // Radio buttons show every option and its consequence at a glance, // which matters for the security choices. Beyond four they turn // into a wall, so those become a select. if ( options.length <= 4 ) { return ( onChange( field.key, next ) } /> ); } return ( onChange( field.key, next ) } /> ); } case 'integer': return ( onChange( field.key, next ) } /> ); case 'idlist': case 'addresslist': return ( onChange( field.key, next ) } /> ); case 'color': return (
{ /* A native colour input works on every device, including the phone's own colour picker, and needs no extra bundle. */ } onChange( field.key, event.target.value ) } /> onChange( field.key, next ) } />
); case 'media': return ( { mediaUrl && ( ) }
{ !! Number( value ) && ( ) }
); case 'url': return ( onChange( field.key, next ) } /> ); case 'htmlid': case 'string': default: return ( onChange( field.key, next ) } /> ); } }