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 / extend / inspector-control / controls / borders / index.js
generateblocks / src / extend / inspector-control / controls / borders Last commit date
components 2 years ago BorderCSS.js 2 years ago attributes.js 2 years ago editor.scss 2 years ago index.js 1 year ago
index.js
334 lines
1 import { __ } from '@wordpress/i18n';
2 import { link, linkOff } from '@wordpress/icons';
3 import { useContext, useState, useEffect, useRef } from '@wordpress/element';
4 import { BaseControl, Tooltip, Button } from '@wordpress/components';
5 import { applyFilters } from '@wordpress/hooks';
6 import { isEqual, isEmpty } from 'lodash';
7 import { ColorPicker } from '@edge22/components';
8
9 import PanelArea from '../../../../components/panel-area';
10 import getIcon from '../../../../utils/get-icon';
11 import ControlsContext from '../../../../block-context';
12 import getDeviceType from '../../../../utils/get-device-type';
13 import getResponsivePlaceholder from '../../../../utils/get-responsive-placeholder';
14 import DimensionsControl from '../../../../components/dimensions';
15 import FlexControl from '../../../../components/flex-control';
16 import UnitControl from '../../../../components/unit-control';
17 import StyleDropdown from './components/style-dropdown';
18 import isNumeric from '../../../../utils/is-numeric';
19 import { useStyleIndicator, useDeviceAttributes } from '../../../../hooks';
20 import { getContentAttribute } from '../../../../utils/get-content-attribute';
21
22 import './editor.scss';
23
24 export default function Borders( { attributes, setAttributes, computedStyles } ) {
25 const device = getDeviceType();
26 const { id, blockName, supports: { borders: bordersPanel } } = useContext( ControlsContext );
27 const [ deviceAttributes, setDeviceAttributes ] = useDeviceAttributes( attributes, setAttributes );
28 const borderRadiusAttributes = [ 'borderTopLeftRadius', 'borderTopRightRadius', 'borderBottomLeftRadius', 'borderBottomRightRadius' ];
29 const borderAreas = [ 'borderTop', 'borderRight', 'borderBottom', 'borderLeft' ];
30 const borderLabels = {
31 borderTop: __( 'Top', 'generateblocks' ),
32 borderRight: __( 'Right', 'generateblocks' ),
33 borderBottom: __( 'Bottom', 'generateblocks' ),
34 borderLeft: __( 'Left', 'generateblocks' ),
35 };
36 const [ sync, setSync ] = useState( false );
37 const contentValue = getContentAttribute( attributes, blockName );
38 const panelControls = {
39 borderTopColor: false,
40 borderTopStyle: false,
41 borderTopWidth: false,
42 borderRightColor: false,
43 borderRightStyle: false,
44 borderRightWidth: false,
45 borderBottomColor: false,
46 borderBottomStyle: false,
47 borderBottomWidth: false,
48 borderLeftColor: false,
49 borderLeftStyle: false,
50 borderLeftWidth: false,
51 borderTopLeftRadius: false,
52 borderTopRightRadius: false,
53 borderBottomRightRadius: false,
54 borderBottomLeftRadius: false,
55 };
56 const {
57 dispatchControlGlobalStyle,
58 styleSources,
59 hasGlobalStyle,
60 contentWasUpdated,
61 } = useStyleIndicator( computedStyles, panelControls, contentValue, deviceAttributes );
62 const panelRef = useRef( null );
63
64 function getLabel( defaultLabel, rules ) {
65 return applyFilters(
66 'generateblocks.editor.control.label',
67 defaultLabel,
68 rules,
69 styleSources,
70 dispatchControlGlobalStyle,
71 contentWasUpdated,
72 );
73 }
74
75 const {
76 borderTopColor = '',
77 borderTopStyle = '',
78 borderTopWidth = '',
79 borderRightColor = '',
80 borderRightStyle = '',
81 borderRightWidth = '',
82 borderBottomColor = '',
83 borderBottomStyle = '',
84 borderBottomWidth = '',
85 borderLeftColor = '',
86 borderLeftStyle = '',
87 borderLeftWidth = '',
88 borderTopLeftRadius = '',
89 borderTopRightRadius = '',
90 borderBottomRightRadius = '',
91 borderBottomLeftRadius = '',
92 } = deviceAttributes.borders;
93
94 const labels = {
95 borders: getLabel(
96 __( 'Border', 'generateblocks' ),
97 {
98 borderTopColor,
99 borderTopStyle,
100 borderTopWidth,
101 borderRightColor,
102 borderRightStyle,
103 borderRightWidth,
104 borderBottomColor,
105 borderBottomStyle,
106 borderBottomWidth,
107 borderLeftColor,
108 borderLeftStyle,
109 borderLeftWidth,
110 }
111 ),
112 borderRadius: getLabel(
113 __( 'Border Radius', 'generateblocks' ),
114 {
115 borderTopLeftRadius,
116 borderTopRightRadius,
117 borderBottomRightRadius,
118 borderBottomLeftRadius,
119 }
120 ),
121 };
122
123 useEffect( () => {
124 const allValues = borderAreas.map( ( area ) => {
125 return Object.entries( deviceAttributes.borders ).reduce( ( newObject, [ key, value ] ) => {
126 if ( key.startsWith( area ) && value ) {
127 const newKey = key.replace( area, '' );
128
129 newObject = {
130 ...newObject,
131 [ newKey ]: value,
132 };
133 }
134
135 return newObject;
136 }, {} );
137 } );
138
139 if (
140 4 === allValues.length &&
141 allValues.every( ( obj ) => ! isEmpty( obj ) && isEqual( obj, allValues[ 0 ] ) )
142 ) {
143 setSync( true );
144 }
145 }, [] );
146
147 function manualSync() {
148 const areasWithWidth = borderAreas.filter( ( area ) => deviceAttributes.borders[ area + 'Width' ] || isNumeric( deviceAttributes.borders[ area + 'Width' ] ) );
149
150 if ( ! areasWithWidth.length ) {
151 return;
152 }
153
154 const firstArea = areasWithWidth[ 0 ];
155
156 const valuesToSync = Object.entries( deviceAttributes.borders ).reduce( ( newObject, [ key, value ] ) => {
157 if ( key.startsWith( firstArea ) ) {
158 const newKey = key.replace( firstArea, '' );
159 newObject[ newKey ] = value;
160 }
161
162 return newObject;
163 }, {} );
164
165 const newDeviceAttributes = Object.entries( valuesToSync ).reduce( ( newObject, [ key, value ] ) => {
166 borderAreas.forEach( ( area ) => {
167 newObject[ area + key ] = value;
168 } );
169
170 return newObject;
171 }, {} );
172
173 setDeviceAttributes( newDeviceAttributes, 'borders' );
174 }
175
176 return (
177 <PanelArea
178 title={ __( 'Borders', 'generateblocks' ) }
179 initialOpen={ false }
180 icon={ getIcon( 'borders' ) }
181 className="gblocks-panel-label"
182 ref={ panelRef }
183 hasGlobalStyle={ hasGlobalStyle }
184 id={ `${ id }Borders` }
185 >
186 { ( bordersPanel.borderTop || bordersPanel.borderRight || bordersPanel.borderBottom || bordersPanel.borderLeft ) &&
187 <BaseControl
188 label={ labels.borders }
189 id={ 'gblocks-borderTop-width' }
190 className="gblocks-border-row"
191 >
192 <Tooltip text={ !! sync ? __( 'Unlink Sides', 'generateblocks' ) : __( 'Link Sides', 'generateblocks' ) } >
193 <Button
194 className="components-gblocks-dimensions-control_sync"
195 aria-label={ !! sync ? __( 'Unlink Sides', 'generateblocks' ) : __( 'Link Sides', 'generateblocks' ) }
196 variant={ !! sync ? 'primary' : '' }
197 aria-pressed={ !! sync }
198 onClick={ () => {
199 setSync( ! sync );
200
201 if ( ! sync ) {
202 manualSync();
203 }
204 } }
205 >
206 { !! sync ? link : linkOff }
207 </Button>
208 </Tooltip>
209
210 { borderAreas.map( ( borderArea, areaIndex ) => {
211 if ( ! bordersPanel[ borderArea ] ) {
212 return null;
213 }
214
215 if ( sync && areaIndex > 0 ) {
216 return null;
217 }
218
219 const iconBorderStyle = !! sync
220 ? 'borderAll'
221 : borderArea;
222
223 return (
224 <FlexControl key={ borderArea }>
225 <Tooltip text={ !! sync ? __( 'All sides', 'generateblocks' ) : borderLabels[ borderArea ] }>
226 <div className={ 'gblocks-border-icon ' + iconBorderStyle } style={ { borderStyle: attributes.borders[ borderArea + 'Style' ] } }></div>
227 </Tooltip>
228
229 <UnitControl
230 id={ 'gblocks-' + borderArea + '-width' }
231 value={ deviceAttributes.borders[ borderArea + 'Width' ] || '' }
232 placeholder={ getResponsivePlaceholder( borderArea + 'Width', attributes.borders, device ) }
233 onChange={ ( value ) => {
234 const newAttributes = {
235 [ borderArea + 'Width' ]: value,
236 };
237
238 if ( sync ) {
239 newAttributes.borderRightWidth = value;
240 newAttributes.borderBottomWidth = value;
241 newAttributes.borderLeftWidth = value;
242 }
243
244 if ( ! value ) {
245 newAttributes[ borderArea + 'Style' ] = '';
246
247 if ( sync ) {
248 newAttributes.borderRightStyle = '';
249 newAttributes.borderBottomStyle = '';
250 newAttributes.borderLeftStyle = '';
251 }
252 } else if ( ! attributes.borders[ borderArea + 'Style' ] ) {
253 newAttributes[ borderArea + 'Style' ] = 'solid';
254
255 if ( sync ) {
256 newAttributes.borderRightStyle = 'solid';
257 newAttributes.borderBottomStyle = 'solid';
258 newAttributes.borderLeftStyle = 'solid';
259 }
260 }
261
262 setDeviceAttributes( newAttributes, 'borders' );
263 } }
264 />
265
266 <StyleDropdown
267 value={ deviceAttributes.borders[ borderArea + 'Style' ] || getResponsivePlaceholder( borderArea + 'Style', attributes.borders, device ) }
268 onChange={ ( value ) => {
269 const newAttributes = {
270 [ borderArea + 'Style' ]: value,
271 };
272
273 if ( sync ) {
274 newAttributes.borderRightStyle = value;
275 newAttributes.borderBottomStyle = value;
276 newAttributes.borderLeftStyle = value;
277 }
278
279 setDeviceAttributes( newAttributes, 'borders' );
280 } }
281 />
282
283 { !! bordersPanel.borderColors.length && 'Desktop' === device &&
284 <div className="gblocks-border-colors">
285 { bordersPanel.borderColors.map( ( borderColor, index ) => {
286 return (
287 <ColorPicker
288 key={ 'border' + index }
289 tooltip={ borderColor?.tooltip }
290 value={ attributes.borders[ borderArea + 'Color' + borderColor.state ] || '' }
291 alpha={ borderColor.alpha || false }
292 onChange={ ( nextBackgroundColor ) => {
293 const newAttributes = {
294 [ borderArea + 'Color' + borderColor.state ]: nextBackgroundColor,
295 };
296
297 if ( sync ) {
298 newAttributes[ 'borderRightColor' + borderColor.state ] = nextBackgroundColor;
299 newAttributes[ 'borderBottomColor' + borderColor.state ] = nextBackgroundColor;
300 newAttributes[ 'borderLeftColor' + borderColor.state ] = nextBackgroundColor;
301 }
302
303 setAttributes( {
304 borders: {
305 ...newAttributes,
306 },
307 } );
308 } }
309 />
310 );
311 } ) }
312 </div>
313 }
314 </FlexControl>
315 );
316 } ) }
317 </BaseControl>
318 }
319
320 { bordersPanel.borderRadius &&
321 <DimensionsControl
322 label={ labels.borderRadius }
323 attributeNames={ borderRadiusAttributes }
324 values={ deviceAttributes.borders }
325 placeholders={ borderRadiusAttributes.reduce( ( o, key ) => (
326 { ...o, [ key ]: getResponsivePlaceholder( key, attributes.borders, device, '' ) }
327 ), {} ) }
328 onChange={ ( values ) => setDeviceAttributes( values, 'borders' ) }
329 />
330 }
331 </PanelArea>
332 );
333 }
334