PluginProbe ʕ •ᴥ•ʔ
GenerateBlocks / 2.0.0
GenerateBlocks v2.0.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 1 year ago unit-dropdown.js 2 years ago unit-list.js 2 years ago
index.js
181 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 import { useUpdateEffect } from 'react-use';
8
9 /**
10 * Internal dependencies
11 */
12
13 import './editor.scss';
14 import UnitDropdown from './unit-dropdown';
15 import unitList from './unit-list';
16
17 export default function UnitControl( props ) {
18 const {
19 label,
20 units = [],
21 defaultUnit = '',
22 unitCount = 7,
23 min = 0,
24 max,
25 step,
26 id,
27 disabled = false,
28 overrideValue = null,
29 overrideAction = () => null,
30 onChange,
31 value,
32 placeholder,
33 help = '',
34 focusOnMount = false,
35 onFocus = () => null,
36 } = props;
37
38 const visibleUnits = units.concat( unitList ).slice( 0, unitCount );
39 const [ unitValue, setUnitValue ] = useState( '' );
40 const [ numericValue, setNumericValue ] = useState( '' );
41 const [ placeholderValue, setPlaceholderValue ] = useState( '' );
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 useUpdateEffect( () => {
91 const hasOverride = !! overrideValue && !! disabled;
92
93 const fullValue = startsWithNumber( numericValue )
94 ? numericValue + unitValue
95 : numericValue;
96
97 // Clear the placeholder if the units don't match.
98 if ( ! fullValue ) {
99 if ( unitValue !== getUnitValue( splitValues( placeholder ) ) ) {
100 setPlaceholderValue( '' );
101 } else {
102 setPlaceholders();
103 }
104 }
105
106 if ( ! hasOverride && fullValue !== value ) {
107 onChange( fullValue );
108 }
109 }, [ numericValue, unitValue ] );
110
111 useEffect( () => {
112 if ( focusOnMount && inputRef?.current ) {
113 inputRef.current.focus();
114 }
115 }, [ label ] );
116
117 return (
118 <BaseControl
119 label={ label }
120 help={ help }
121 id={ id }
122 className={ classnames( {
123 'gblocks-unit-control': true,
124 'gblocks-unit-control__disabled': !! disabled,
125 } ) }
126 >
127 <div className="gblocks-unit-control__input" ref={ wrapperRef }>
128 <TextControl
129 type="text"
130 value={ numericValue }
131 placeholder={ placeholderValue }
132 id={ id }
133 min={ min }
134 max={ max }
135 step={ step }
136 autoComplete="off"
137 disabled={ disabled }
138 onKeyDown={ ( event ) => {
139 const keyPressed = event.key;
140 const newValue = event.target.value;
141
142 if ( keyPressed === 'ArrowUp' ) {
143 if ( ! isNaN( newValue ) ) {
144 setNumericValue( +newValue + 1 );
145 }
146 } else if ( keyPressed === 'ArrowDown' ) {
147 if ( ! isNaN( newValue ) ) {
148 setNumericValue( +newValue - 1 );
149 }
150 }
151 } }
152 onChange={ ( newValue ) => setNumericValue( newValue ) }
153 onFocus={ () => {
154 onFocus();
155 } }
156 ref={ inputRef }
157 />
158
159 <div className="gblocks-unit-control__input--action">
160 { !! overrideAction && <div className="gblocks-unit-control__override-action">{ overrideAction() } </div> }
161
162 { (
163 startsWithNumber( numericValue ) ||
164 (
165 ! numericValue &&
166 ( ! placeholderValue || startsWithNumber( placeholderValue ) )
167 )
168 ) &&
169 <UnitDropdown
170 value={ unitValue }
171 disabled={ disabled || 1 === visibleUnits.length }
172 units={ visibleUnits }
173 onChange={ ( newValue ) => setUnitValue( newValue ) }
174 />
175 }
176 </div>
177 </div>
178 </BaseControl>
179 );
180 }
181