PluginProbe ʕ •ᴥ•ʔ
GenerateBlocks / 1.9.0
GenerateBlocks v1.9.0
trunk 1.0 1.0.1 1.0.2 1.1.0 1.1.1 1.1.2 1.2.0 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.7.0 1.7.1 1.7.2 1.7.3 1.8.0 1.8.1 1.8.2 1.8.3 1.9.0 1.9.1 2.0.0 2.0.1 2.0.2 2.1.0 2.1.1 2.1.2 2.2.0 2.2.1 2.3.0
generateblocks / src / components / unit-control / index.js
generateblocks / src / components / unit-control Last commit date
editor.scss 2 years ago index.js 2 years ago unit-dropdown.js 2 years ago unit-list.js 2 years ago
index.js
187 lines
1 /**
2 * External dependencies
3 */
4 import { useEffect, useState, useRef } from '@wordpress/element';
5 import { TextControl, BaseControl } from '@wordpress/components';
6 import classnames from 'classnames';
7
8 /**
9 * Internal dependencies
10 */
11
12 import './editor.scss';
13 import UnitDropdown from './unit-dropdown';
14 import unitList from './unit-list';
15
16 export default function UnitControl( props ) {
17 const {
18 label,
19 units = [],
20 defaultUnit = '',
21 unitCount = 7,
22 min = 0,
23 max,
24 step,
25 id,
26 disabled = false,
27 overrideValue = null,
28 overrideAction = () => null,
29 onChange,
30 value,
31 placeholder,
32 help = '',
33 focusOnMount = false,
34 onFocus = () => null,
35 } = props;
36
37 const visibleUnits = units.concat( unitList ).slice( 0, unitCount );
38 const [ unitValue, setUnitValue ] = useState( '' );
39 const [ numericValue, setNumericValue ] = useState( '' );
40 const [ placeholderValue, setPlaceholderValue ] = useState( '' );
41 const isMounted = useRef( false );
42 const wrapperRef = useRef( false );
43 const inputRef = useRef( false );
44
45 const splitValues = ( values ) => {
46 const unitRegex = unitList.join( '|' );
47 const splitRegex = new RegExp( `(${ unitRegex })` );
48
49 return values
50 ? values.toString().toLowerCase().split( splitRegex ).filter( ( singleValue ) => '' !== singleValue )
51 : [];
52 };
53
54 const getNumericValue = ( values ) => values.length > 0 ? values[ 0 ].trim() : '';
55 const defaultUnitValue = defaultUnit ? defaultUnit : visibleUnits[ 0 ];
56 const getUnitValue = ( values ) => values.length > 1 ? values[ 1 ] : defaultUnitValue;
57
58 // Test if the value starts with a number, decimal or a single dash.
59 const startsWithNumber = ( number ) => /^([-]?\d|[-]?\.)/.test( number );
60
61 const setPlaceholders = () => {
62 if ( ! value ) {
63 const placeholderValues = overrideValue
64 ? splitValues( overrideValue )
65 : splitValues( placeholder );
66
67 setPlaceholderValue( getNumericValue( placeholderValues ) );
68 setUnitValue( getUnitValue( placeholderValues ) );
69 }
70 };
71
72 // Split the number and unit into two values.
73 useEffect( () => {
74 const newValue = overrideValue && disabled ? overrideValue : value;
75
76 // Split our values if we're starting with a number.
77 if ( startsWithNumber( newValue ) ) {
78 const values = splitValues( newValue );
79
80 setNumericValue( getNumericValue( values ) );
81 setUnitValue( getUnitValue( values ) );
82 } else {
83 setNumericValue( newValue );
84 setUnitValue( '' );
85 }
86
87 setPlaceholders();
88 }, [ value, overrideValue ] );
89
90 useEffect( () => {
91 // Don't run this on first render.
92 if ( ! isMounted.current ) {
93 isMounted.current = true;
94 return;
95 }
96
97 const hasOverride = !! overrideValue && !! disabled;
98
99 const fullValue = startsWithNumber( numericValue )
100 ? numericValue + unitValue
101 : numericValue;
102
103 // Clear the placeholder if the units don't match.
104 if ( ! fullValue ) {
105 if ( unitValue !== getUnitValue( splitValues( placeholder ) ) ) {
106 setPlaceholderValue( '' );
107 } else {
108 setPlaceholders();
109 }
110 }
111
112 if ( ! hasOverride && fullValue !== value ) {
113 onChange( fullValue );
114 }
115 }, [ numericValue, unitValue ] );
116
117 useEffect( () => {
118 if ( focusOnMount && inputRef?.current ) {
119 inputRef.current.focus();
120 }
121 }, [ label ] );
122
123 return (
124 <BaseControl
125 label={ label }
126 help={ help }
127 id={ id }
128 className={ classnames( {
129 'gblocks-unit-control': true,
130 'gblocks-unit-control__disabled': !! disabled,
131 } ) }
132 >
133 <div className="gblocks-unit-control__input" ref={ wrapperRef }>
134 <TextControl
135 type="text"
136 value={ numericValue }
137 placeholder={ placeholderValue }
138 id={ id }
139 min={ min }
140 max={ max }
141 step={ step }
142 autoComplete="off"
143 disabled={ disabled }
144 onKeyDown={ ( event ) => {
145 const keyPressed = event.key;
146 const newValue = event.target.value;
147
148 if ( keyPressed === 'ArrowUp' ) {
149 if ( ! isNaN( newValue ) ) {
150 setNumericValue( +newValue + 1 );
151 }
152 } else if ( keyPressed === 'ArrowDown' ) {
153 if ( ! isNaN( newValue ) ) {
154 setNumericValue( +newValue - 1 );
155 }
156 }
157 } }
158 onChange={ ( newValue ) => setNumericValue( newValue ) }
159 onFocus={ () => {
160 onFocus();
161 } }
162 ref={ inputRef }
163 />
164
165 <div className="gblocks-unit-control__input--action">
166 { !! overrideAction && <div className="gblocks-unit-control__override-action">{ overrideAction() } </div> }
167
168 { (
169 startsWithNumber( numericValue ) ||
170 (
171 ! numericValue &&
172 ( ! placeholderValue || startsWithNumber( placeholderValue ) )
173 )
174 ) &&
175 <UnitDropdown
176 value={ unitValue }
177 disabled={ disabled || 1 === visibleUnits.length }
178 units={ visibleUnits }
179 onChange={ ( newValue ) => setUnitValue( newValue ) }
180 />
181 }
182 </div>
183 </div>
184 </BaseControl>
185 );
186 }
187