PluginProbe ʕ •ᴥ•ʔ
GenerateBlocks / 2.2.0
GenerateBlocks v2.2.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 / blocks / media / components / BlockSettings.jsx
generateblocks / src / blocks / media / components Last commit date
BlockSettings.jsx 10 months ago Image.jsx 10 months ago ImagePlaceholder.jsx 1 year ago
BlockSettings.jsx
281 lines
1 import { __ } from '@wordpress/i18n';
2 import { SelectControl, TextControl, Flex, FlexBlock } from '@wordpress/components';
3 import { useEffect, useState, useMemo, useCallback } from '@wordpress/element';
4 import apiFetch from '@wordpress/api-fetch';
5 import { addQueryArgs, isURL } from '@wordpress/url';
6 import { applyFilters } from '@wordpress/hooks';
7 import { debounce } from '@wordpress/compose';
8
9 import { OpenPanel } from '@edge22/components';
10 import { UnitControl } from '@edge22/styles-builder';
11
12 import {
13 ApplyFilters,
14 ImageUpload,
15 URLControls,
16 DynamicTagsOnboarder,
17 } from '@components/index.js';
18 import { useBlockStyles } from '@hooks/useBlockStyles';
19
20 async function getImageByUrl( url ) {
21 const image = await apiFetch( {
22 path: addQueryArgs( `/generateblocks/v1/get-attachment-by-url`, {
23 url,
24 } ),
25 method: 'GET',
26 } );
27
28 if ( image.success ) {
29 return image.response;
30 }
31
32 return null;
33 }
34
35 export function BlockSettings( {
36 getStyleValue,
37 onStyleChange,
38 name,
39 attributes,
40 setAttributes,
41 onSelectImage,
42 htmlAttributes,
43 context,
44 } ) {
45 const {
46 linkHtmlAttributes,
47 mediaId,
48 tagName,
49 } = attributes;
50
51 const {
52 atRule,
53 } = useBlockStyles();
54 const [ imageData, setImageData ] = useState( null );
55 const [ hasResolved, setHasResolved ] = useState( false );
56
57 const debouncedOnStyleChange = useCallback(
58 debounce( ( property, value, atRuleValue ) => {
59 onStyleChange( property, value, atRuleValue );
60 }, 250 ),
61 [ onStyleChange ]
62 );
63
64 useEffect( () => {
65 if ( ! isURL( htmlAttributes?.src ) ) {
66 setImageData( null );
67 setHasResolved( true );
68 return;
69 }
70
71 ( async function() {
72 try {
73 const image = await getImageByUrl( htmlAttributes?.src );
74
75 if ( image ) {
76 setImageData( image );
77 }
78
79 setHasResolved( true );
80 } catch ( error ) {
81 console.info( 'Error fetching image:', error ); // eslint-disable-line no-console
82 setImageData( null );
83 setHasResolved( true );
84 }
85 }() );
86 }, [ htmlAttributes?.src ] );
87
88 useEffect( () => {
89 const id = imageData?.id;
90
91 if ( hasResolved && id !== mediaId ) {
92 setAttributes( {
93 mediaId: id ?? 0,
94 } );
95 }
96 }, [ imageData?.id ] );
97
98 const sizes = useMemo( () => {
99 const imageSizes = imageData?.sizes
100 ? Object.keys( imageData?.sizes )
101 : [];
102
103 if ( ! hasResolved ) {
104 return [ { label: __( 'Loading sizes…', 'generateblocks' ), value: '' } ];
105 }
106
107 if ( ! imageSizes.length ) {
108 return [ { label: __( 'No sizes available', 'generateblocks' ), value: '' } ];
109 }
110
111 const options = imageSizes.map( ( imageSize ) => {
112 return {
113 label: imageSize.charAt( 0 ).toUpperCase() + imageSize.slice( 1 ),
114 value: imageSize,
115 };
116 } );
117
118 options.unshift( { label: __( 'Full', 'generateblocks-pro' ), value: '' } );
119
120 return options;
121 }, [ imageData?.sizes, hasResolved ] );
122
123 const imageSizeValue = useMemo( () => {
124 const imageSizes = imageData?.sizes
125 ? Object.keys( imageData?.sizes )
126 : [];
127
128 if ( ! imageSizes.length ) {
129 return '';
130 }
131
132 // Get the key by using the value (htmlAttributes?.src) in the imageData?.sizes array
133 const key = imageSizes.find( ( sizeKey ) => imageData?.sizes[ sizeKey ]?.url === htmlAttributes?.src );
134
135 if ( ! key ) {
136 return '';
137 }
138
139 return key;
140 }, [ htmlAttributes?.src, imageData?.sizes ] );
141
142 const panelProps = {
143 name,
144 attributes,
145 setAttributes,
146 getStyleValue,
147 onStyleChange,
148 };
149
150 return (
151 <ApplyFilters
152 name="generateblocks.editor.blockControls"
153 blockName={ name }
154 getStyleValue={ getStyleValue }
155 onStyleChange={ onStyleChange }
156 currentAtRule={ atRule }
157 attributes={ attributes }
158 setAttributes={ setAttributes }
159 >
160 <OpenPanel
161 { ...panelProps }
162 panelId="settings"
163 >
164 { '' === atRule && (
165 <>
166 <ImageUpload
167 context={ context }
168 value={ htmlAttributes?.src ?? '' }
169 onInsert={ ( value ) => {
170 const newHtmlAttributes = {
171 ...htmlAttributes,
172 src: value,
173 };
174
175 setAttributes( {
176 htmlAttributes: newHtmlAttributes,
177 } );
178 } }
179 onSelectImage={ onSelectImage }
180 allowDynamicTags={ true }
181 onInsertDynamicTag={ ( value ) => {
182 const newHtmlAttributes = {
183 ...htmlAttributes,
184 src: value,
185 };
186
187 setAttributes( {
188 htmlAttributes: newHtmlAttributes,
189 mediaId: 0,
190 } );
191 } }
192 sizeSlug={ imageSizeValue }
193 />
194
195 <URLControls
196 setAttributes={ setAttributes }
197 htmlAttributes={ linkHtmlAttributes }
198 attributesName="linkHtmlAttributes"
199 context={ context }
200 tagName={ tagName }
201 />
202
203 { applyFilters(
204 'generateblocks.blockSettings.afterImageUrlControls',
205 null,
206 panelProps
207 ) }
208
209 <SelectControl
210 label={ __( 'Size', 'generateblocks' ) }
211 options={ sizes }
212 value={ imageSizeValue }
213 disabled={ ! hasResolved || ( hasResolved && ! imageData?.sizes ) }
214 onChange={ ( value ) => {
215 if ( '' === value ) {
216 setAttributes( {
217 htmlAttributes: {
218 ...htmlAttributes,
219 src: imageData?.full_url ?? '',
220 width: imageData?.width ?? '',
221 height: imageData?.height ?? '',
222 },
223 } );
224
225 return;
226 }
227
228 setAttributes( {
229 htmlAttributes: {
230 ...htmlAttributes,
231 src: imageData?.sizes[ value ]?.url ?? '',
232 width: imageData?.sizes[ value ]?.width ?? '',
233 height: imageData?.sizes[ value ]?.height ?? '',
234 },
235 } );
236 } }
237 />
238 </>
239 ) }
240
241 <Flex>
242 <FlexBlock>
243 <UnitControl
244 id="width"
245 label={ __( 'Width', 'generateblocks' ) }
246 value={ getStyleValue( 'width', atRule ) }
247 onChange={ ( value ) => debouncedOnStyleChange( 'width', value, atRule ) }
248 />
249 </FlexBlock>
250
251 <FlexBlock>
252 <UnitControl
253 id="height"
254 label={ __( 'Height', 'generateblocks' ) }
255 value={ getStyleValue( 'height', atRule ) }
256 onChange={ ( value ) => debouncedOnStyleChange( 'height', value, atRule ) }
257 />
258 </FlexBlock>
259 </Flex>
260
261 { '' === atRule && (
262 <TextControl
263 label={ __( 'Alt text', 'generateblocks' ) }
264 value={ htmlAttributes?.alt ?? '' }
265 onChange={ ( value ) => {
266 setAttributes( {
267 htmlAttributes: {
268 ...htmlAttributes,
269 alt: value,
270 },
271 } );
272 } }
273 />
274 ) }
275 </OpenPanel>
276
277 <DynamicTagsOnboarder />
278 </ApplyFilters>
279 );
280 }
281