PluginProbe
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor / 2.0.6
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor v2.0.6
2.0.13 2.0.12 2.0.11 2.0.10 2.0.9 trunk 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8
blockenberg / blocks / accordion / index.js

index.js in Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor 2.0.6, at blocks/accordion/index.js

670 lines 34.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 wp.domReady(function () {
2 var el = wp.element.createElement;
3 var Fragment = wp.element.Fragment;
4 var __ = wp.i18n.__;
5 var registerBlockType = wp.blocks.registerBlockType;
6 var InspectorControls = wp.blockEditor.InspectorControls;
7 var useBlockProps = wp.blockEditor.useBlockProps;
8 var RichText = wp.blockEditor.RichText;
9 var PanelBody = wp.components.PanelBody;
10 var PanelColorSettings = wp.blockEditor.PanelColorSettings;
11 var Button = wp.components.Button;
12 var ToggleControl = wp.components.ToggleControl;
13 var RangeControl = wp.components.RangeControl;
14 var SelectControl = wp.components.SelectControl;
15 var __experimentalBoxControl = wp.components.__experimentalBoxControl;
16 var BoxControl = __experimentalBoxControl;
17
18 // Icon SVGs
19 var icons = {
20 chevron: el('svg', { viewBox: '0 0 24 24', xmlns: 'http://www.w3.org/2000/svg' },
21 el('path', { d: 'M7 10l5 5 5-5z' })
22 ),
23 plus: el('svg', { viewBox: '0 0 24 24', xmlns: 'http://www.w3.org/2000/svg' },
24 el('path', { d: 'M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z' })
25 ),
26 arrow: el('svg', { viewBox: '0 0 24 24', xmlns: 'http://www.w3.org/2000/svg' },
27 el('path', { d: 'M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z' })
28 ),
29 caret: el('svg', { viewBox: '0 0 24 24', xmlns: 'http://www.w3.org/2000/svg' },
30 el('path', { d: 'M7 14l5-5 5 5H7z' })
31 )
32 };
33
34 function getIcon(type) {
35 return icons[type] || icons.chevron;
36 }
37
38 registerBlockType('blockenberg/accordion', {
39 title: __('Accordion', 'blockenberg'),
40 icon: 'list-view',
41 category: 'blockenberg',
42 description: __('Collapsible accordion panels for FAQ, features, and more.', 'blockenberg'),
43
44 edit: function (props) {
45 var attributes = props.attributes;
46 var setAttributes = props.setAttributes;
47 var a = attributes;
48
49 function updateItem(index, field, value) {
50 var newItems = a.items.map(function (item, i) {
51 if (i === index) {
52 var updated = {};
53 for (var k in item) { updated[k] = item[k]; }
54 updated[field] = value;
55 return updated;
56 }
57 return item;
58 });
59 setAttributes({ items: newItems });
60 }
61
62 function removeItem(index) {
63 if (a.items.length <= 1) return;
64 var newItems = a.items.filter(function (_, i) { return i !== index; });
65 var newActive = a.activeItems.filter(function (i) { return i !== index; }).map(function (i) {
66 return i > index ? i - 1 : i;
67 });
68 setAttributes({ items: newItems, activeItems: newActive });
69 }
70
71 function addItem() {
72 setAttributes({
73 items: a.items.concat([{
74 title: __('New Accordion Item', 'blockenberg'),
75 content: __('Add your content here. Click to edit.', 'blockenberg')
76 }])
77 });
78 }
79
80 function moveItem(index, direction) {
81 var newIndex = index + direction;
82 if (newIndex < 0 || newIndex >= a.items.length) return;
83 var newItems = a.items.slice();
84 var temp = newItems[index];
85 newItems[index] = newItems[newIndex];
86 newItems[newIndex] = temp;
87 // Update activeItems indices
88 var newActive = a.activeItems.map(function (i) {
89 if (i === index) return newIndex;
90 if (i === newIndex) return index;
91 return i;
92 });
93 setAttributes({ items: newItems, activeItems: newActive });
94 }
95
96 function toggleItem(index) {
97 var isActive = a.activeItems.indexOf(index) !== -1;
98 var newActive;
99 if (isActive) {
100 newActive = a.activeItems.filter(function (i) { return i !== index; });
101 } else {
102 if (a.allowMultiple) {
103 newActive = a.activeItems.concat([index]);
104 } else {
105 newActive = [index];
106 }
107 }
108 setAttributes({ activeItems: newActive });
109 }
110
111 function createShadowString(h, v, blur, spread, color) {
112 return h + 'px ' + v + 'px ' + blur + 'px ' + spread + 'px ' + color;
113 }
114
115 // Style options
116 var styleOptions = [
117 { label: __('Default (Separated)', 'blockenberg'), value: 'default' },
118 { label: __('Connected', 'blockenberg'), value: 'connected' },
119 { label: __('Minimal', 'blockenberg'), value: 'minimal' },
120 { label: __('Boxed', 'blockenberg'), value: 'boxed' }
121 ];
122
123 var iconTypeOptions = [
124 { label: __('Chevron', 'blockenberg'), value: 'chevron' },
125 { label: __('Plus/Minus', 'blockenberg'), value: 'plus' },
126 { label: __('Arrow', 'blockenberg'), value: 'arrow' },
127 { label: __('Caret', 'blockenberg'), value: 'caret' }
128 ];
129
130 var iconPositionOptions = [
131 { label: __('Right', 'blockenberg'), value: 'right' },
132 { label: __('Left', 'blockenberg'), value: 'left' }
133 ];
134
135 var borderStyleOptions = [
136 { label: __('Solid', 'blockenberg'), value: 'solid' },
137 { label: __('Dashed', 'blockenberg'), value: 'dashed' },
138 { label: __('Dotted', 'blockenberg'), value: 'dotted' },
139 { label: __('None', 'blockenberg'), value: 'none' }
140 ];
141
142 var animationTypeOptions = [
143 { label: __('Slide', 'blockenberg'), value: 'slide' },
144 { label: __('Fade', 'blockenberg'), value: 'fade' },
145 { label: __('None', 'blockenberg'), value: 'none' }
146 ];
147
148 var fontWeightOptions = [
149 { label: '300', value: 300 },
150 { label: '400', value: 400 },
151 { label: '500', value: 500 },
152 { label: '600', value: 600 },
153 { label: '700', value: 700 },
154 { label: '800', value: 800 }
155 ];
156
157 // Inspector Controls
158 var inspector = el(InspectorControls, {},
159 // Behavior Panel
160 el(PanelBody, { title: __('Behavior', 'blockenberg'), initialOpen: true },
161 el(ToggleControl, {
162 label: __('Allow multiple open', 'blockenberg'),
163 help: __('Allow several panels to be open simultaneously.', 'blockenberg'),
164 checked: a.allowMultiple,
165 __nextHasNoMarginBottom: true,
166 onChange: function (v) { setAttributes({ allowMultiple: v }); }
167 }),
168 el(ToggleControl, {
169 label: __('First panel open by default', 'blockenberg'),
170 checked: a.firstOpen,
171 __nextHasNoMarginBottom: true,
172 onChange: function (v) { setAttributes({ firstOpen: v }); }
173 }),
174 el(ToggleControl, {
175 label: __('Collapse all initially', 'blockenberg'),
176 help: __('Start with all panels closed.', 'blockenberg'),
177 checked: a.collapseAll,
178 __nextHasNoMarginBottom: true,
179 onChange: function (v) { setAttributes({ collapseAll: v }); }
180 }),
181 el(ToggleControl, {
182 label: __('Enable FAQ Schema', 'blockenberg'),
183 help: __('Add FAQPage structured data for SEO.', 'blockenberg'),
184 checked: a.schemaEnabled,
185 __nextHasNoMarginBottom: true,
186 onChange: function (v) { setAttributes({ schemaEnabled: v }); }
187 })
188 ),
189
190 // Style Panel
191 el(PanelBody, { title: __('Accordion Style', 'blockenberg'), initialOpen: false },
192 el(SelectControl, {
193 label: __('Style', 'blockenberg'),
194 value: a.accordionStyle,
195 options: styleOptions,
196 onChange: function (v) { setAttributes({ accordionStyle: v }); }
197 }),
198 el(SelectControl, {
199 label: __('Icon Type', 'blockenberg'),
200 value: a.iconType,
201 options: iconTypeOptions,
202 onChange: function (v) { setAttributes({ iconType: v }); }
203 }),
204 el(SelectControl, {
205 label: __('Icon Position', 'blockenberg'),
206 value: a.iconPosition,
207 options: iconPositionOptions,
208 onChange: function (v) { setAttributes({ iconPosition: v }); }
209 }),
210 el(RangeControl, {
211 label: __('Icon Size', 'blockenberg'),
212 value: a.iconSize,
213 min: 12,
214 max: 32,
215 onChange: function (v) { setAttributes({ iconSize: v }); }
216 })
217 ),
218
219 // Spacing Panel
220 el(PanelBody, { title: __('Spacing', 'blockenberg'), initialOpen: false },
221 el(RangeControl, {
222 label: __('Gap Between Items', 'blockenberg'),
223 value: a.gap,
224 min: 0,
225 max: 40,
226 onChange: function (v) { setAttributes({ gap: v }); }
227 }),
228 el('p', { className: 'components-base-control__label', style: { marginBottom: '8px' } }, __('Header Padding', 'blockenberg')),
229 el('div', { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '8px', marginBottom: '16px' } },
230 el(RangeControl, { label: __('Top', 'blockenberg'), value: a.headerPaddingTop, min: 0, max: 40, onChange: function (v) { setAttributes({ headerPaddingTop: v }); } }),
231 el(RangeControl, { label: __('Right', 'blockenberg'), value: a.headerPaddingRight, min: 0, max: 40, onChange: function (v) { setAttributes({ headerPaddingRight: v }); } }),
232 el(RangeControl, { label: __('Bottom', 'blockenberg'), value: a.headerPaddingBottom, min: 0, max: 40, onChange: function (v) { setAttributes({ headerPaddingBottom: v }); } }),
233 el(RangeControl, { label: __('Left', 'blockenberg'), value: a.headerPaddingLeft, min: 0, max: 40, onChange: function (v) { setAttributes({ headerPaddingLeft: v }); } })
234 ),
235 el('p', { className: 'components-base-control__label', style: { marginBottom: '8px' } }, __('Content Padding', 'blockenberg')),
236 el('div', { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '8px', marginBottom: '16px' } },
237 el(RangeControl, { label: __('Top', 'blockenberg'), value: a.contentPaddingTop, min: 0, max: 40, onChange: function (v) { setAttributes({ contentPaddingTop: v }); } }),
238 el(RangeControl, { label: __('Right', 'blockenberg'), value: a.contentPaddingRight, min: 0, max: 40, onChange: function (v) { setAttributes({ contentPaddingRight: v }); } }),
239 el(RangeControl, { label: __('Bottom', 'blockenberg'), value: a.contentPaddingBottom, min: 0, max: 40, onChange: function (v) { setAttributes({ contentPaddingBottom: v }); } }),
240 el(RangeControl, { label: __('Left', 'blockenberg'), value: a.contentPaddingLeft, min: 0, max: 40, onChange: function (v) { setAttributes({ contentPaddingLeft: v }); } })
241 )
242 ),
243
244 // Border Panel
245 el(PanelBody, { title: __('Border', 'blockenberg'), initialOpen: false },
246 el(RangeControl, {
247 label: __('Border Radius', 'blockenberg'),
248 value: a.borderRadius,
249 min: 0,
250 max: 24,
251 onChange: function (v) { setAttributes({ borderRadius: v }); }
252 }),
253 el(RangeControl, {
254 label: __('Border Width', 'blockenberg'),
255 value: a.borderWidth,
256 min: 0,
257 max: 5,
258 onChange: function (v) { setAttributes({ borderWidth: v }); }
259 }),
260 el(SelectControl, {
261 label: __('Border Style', 'blockenberg'),
262 value: a.borderStyle,
263 options: borderStyleOptions,
264 onChange: function (v) { setAttributes({ borderStyle: v }); }
265 }),
266 el(ToggleControl, {
267 label: __('Show Divider', 'blockenberg'),
268 help: __('Show line between header and content.', 'blockenberg'),
269 checked: a.dividerEnabled,
270 __nextHasNoMarginBottom: true,
271 onChange: function (v) { setAttributes({ dividerEnabled: v }); }
272 }),
273 a.dividerEnabled && el(RangeControl, {
274 label: __('Divider Width', 'blockenberg'),
275 value: a.dividerWidth,
276 min: 1,
277 max: 5,
278 onChange: function (v) { setAttributes({ dividerWidth: v }); }
279 })
280 ),
281
282 // Typography Panel
283 el(PanelBody, { title: __('Typography', 'blockenberg'), initialOpen: false },
284 el('p', { className: 'components-base-control__label' }, __('Header Typography', 'blockenberg')),
285 el(RangeControl, {
286 label: __('Font Size', 'blockenberg'),
287 value: a.headerFontSize,
288 min: 12,
289 max: 28,
290 onChange: function (v) { setAttributes({ headerFontSize: v }); }
291 }),
292 el(SelectControl, {
293 label: __('Font Weight', 'blockenberg'),
294 value: a.headerFontWeight,
295 options: fontWeightOptions,
296 onChange: function (v) { setAttributes({ headerFontWeight: parseInt(v, 10) }); }
297 }),
298 el(RangeControl, {
299 label: __('Line Height', 'blockenberg'),
300 value: a.headerLineHeight,
301 min: 1,
302 max: 2.5,
303 step: 0.1,
304 onChange: function (v) { setAttributes({ headerLineHeight: v }); }
305 }),
306 el('hr', {}),
307 el('p', { className: 'components-base-control__label' }, __('Content Typography', 'blockenberg')),
308 el(RangeControl, {
309 label: __('Font Size', 'blockenberg'),
310 value: a.contentFontSize,
311 min: 12,
312 max: 24,
313 onChange: function (v) { setAttributes({ contentFontSize: v }); }
314 }),
315 el(SelectControl, {
316 label: __('Font Weight', 'blockenberg'),
317 value: a.contentFontWeight,
318 options: fontWeightOptions,
319 onChange: function (v) { setAttributes({ contentFontWeight: parseInt(v, 10) }); }
320 }),
321 el(RangeControl, {
322 label: __('Line Height', 'blockenberg'),
323 value: a.contentLineHeight,
324 min: 1,
325 max: 2.5,
326 step: 0.1,
327 onChange: function (v) { setAttributes({ contentLineHeight: v }); }
328 })
329 ),
330
331 // Effects Panel
332 el(PanelBody, { title: __('Effects', 'blockenberg'), initialOpen: false },
333 el(ToggleControl, {
334 label: __('Enable Animation', 'blockenberg'),
335 checked: a.enableAnimation,
336 __nextHasNoMarginBottom: true,
337 onChange: function (v) { setAttributes({ enableAnimation: v }); }
338 }),
339 a.enableAnimation && el(RangeControl, {
340 label: __('Animation Duration (ms)', 'blockenberg'),
341 value: a.animationDuration,
342 min: 100,
343 max: 800,
344 step: 50,
345 onChange: function (v) { setAttributes({ animationDuration: v }); }
346 }),
347 el(ToggleControl, {
348 label: __('Enable Hover Effect', 'blockenberg'),
349 checked: a.enableHoverEffect,
350 __nextHasNoMarginBottom: true,
351 onChange: function (v) { setAttributes({ enableHoverEffect: v }); }
352 }),
353 el(ToggleControl, {
354 label: __('Enable Shadow', 'blockenberg'),
355 checked: a.enableShadow,
356 __nextHasNoMarginBottom: true,
357 onChange: function (v) { setAttributes({ enableShadow: v }); }
358 }),
359 a.enableShadow && el(Fragment, {},
360 el(RangeControl, {
361 label: __('Shadow Horizontal', 'blockenberg'),
362 value: a.shadowHorizontal,
363 min: -20,
364 max: 20,
365 onChange: function (v) { setAttributes({ shadowHorizontal: v }); }
366 }),
367 el(RangeControl, {
368 label: __('Shadow Vertical', 'blockenberg'),
369 value: a.shadowVertical,
370 min: -20,
371 max: 20,
372 onChange: function (v) { setAttributes({ shadowVertical: v }); }
373 }),
374 el(RangeControl, {
375 label: __('Shadow Blur', 'blockenberg'),
376 value: a.shadowBlur,
377 min: 0,
378 max: 40,
379 onChange: function (v) { setAttributes({ shadowBlur: v }); }
380 }),
381 el(RangeControl, {
382 label: __('Shadow Spread', 'blockenberg'),
383 value: a.shadowSpread,
384 min: -10,
385 max: 10,
386 onChange: function (v) { setAttributes({ shadowSpread: v }); }
387 })
388 )
389 ),
390
391 // Colors Panel
392 el(PanelBody, { title: __('Colors', 'blockenberg'), initialOpen: false },
393 el(PanelColorSettings, {
394 title: __('Header Colors', 'blockenberg'),
395 initialOpen: false,
396 colorSettings: [
397 { value: a.headerBg, onChange: function (c) { setAttributes({ headerBg: c }); }, label: __('Background', 'blockenberg') },
398 { value: a.headerBgHover, onChange: function (c) { setAttributes({ headerBgHover: c }); }, label: __('Background (Hover)', 'blockenberg') },
399 { value: a.headerBgActive, onChange: function (c) { setAttributes({ headerBgActive: c }); }, label: __('Background (Active)', 'blockenberg') },
400 { value: a.headerColor, onChange: function (c) { setAttributes({ headerColor: c }); }, label: __('Text', 'blockenberg') },
401 { value: a.headerColorHover, onChange: function (c) { setAttributes({ headerColorHover: c }); }, label: __('Text (Hover)', 'blockenberg') },
402 { value: a.headerColorActive, onChange: function (c) { setAttributes({ headerColorActive: c }); }, label: __('Text (Active)', 'blockenberg') }
403 ]
404 }),
405
406 el(PanelColorSettings, {
407 title: __('Content Colors', 'blockenberg'),
408 initialOpen: false,
409 colorSettings: [
410 { value: a.contentBg, onChange: function (c) { setAttributes({ contentBg: c }); }, label: __('Background', 'blockenberg') },
411 { value: a.contentColor, onChange: function (c) { setAttributes({ contentColor: c }); }, label: __('Text', 'blockenberg') }
412 ]
413 }),
414
415 el(PanelColorSettings, {
416 title: __('Border & Icon Colors', 'blockenberg'),
417 initialOpen: false,
418 colorSettings: [
419 { value: a.borderColor, onChange: function (c) { setAttributes({ borderColor: c }); }, label: __('Border', 'blockenberg') },
420 { value: a.borderColorActive, onChange: function (c) { setAttributes({ borderColorActive: c }); }, label: __('Border (Active)', 'blockenberg') },
421 { value: a.iconColor, onChange: function (c) { setAttributes({ iconColor: c }); }, label: __('Icon', 'blockenberg') },
422 { value: a.iconColorActive, onChange: function (c) { setAttributes({ iconColorActive: c }); }, label: __('Icon (Active)', 'blockenberg') },
423 { value: a.accentColor, onChange: function (c) { setAttributes({ accentColor: c }); }, label: __('Accent', 'blockenberg') },
424 { value: a.dividerColor, onChange: function (c) { setAttributes({ dividerColor: c }); }, label: __('Divider', 'blockenberg') },
425 { value: a.shadowColor, onChange: function (c) { setAttributes({ shadowColor: c }); }, label: __('Shadow', 'blockenberg') }
426 ]
427 })
428 )
429 );
430
431 // CSS variables for preview
432 var wrapStyle = {
433 '--bkbg-ac-gap': a.gap + 'px',
434 '--bkbg-ac-radius': a.borderRadius + 'px',
435 '--bkbg-ac-brd-w': a.borderWidth + 'px',
436 '--bkbg-ac-brd-style': a.borderStyle,
437 '--bkbg-ac-header-padding': a.headerPaddingTop + 'px ' + a.headerPaddingRight + 'px ' + a.headerPaddingBottom + 'px ' + a.headerPaddingLeft + 'px',
438 '--bkbg-ac-content-padding': a.contentPaddingTop + 'px ' + a.contentPaddingRight + 'px ' + a.contentPaddingBottom + 'px ' + a.contentPaddingLeft + 'px',
439 '--bkbg-ac-header-bg': a.headerBg,
440 '--bkbg-ac-header-bg-hover': a.headerBgHover,
441 '--bkbg-ac-header-bg-active': a.headerBgActive,
442 '--bkbg-ac-header-color': a.headerColor,
443 '--bkbg-ac-header-color-hover': a.headerColorHover,
444 '--bkbg-ac-header-color-active': a.headerColorActive,
445 '--bkbg-ac-content-bg': a.contentBg,
446 '--bkbg-ac-content-color': a.contentColor,
447 '--bkbg-ac-border-color': a.borderColor,
448 '--bkbg-ac-border-color-active': a.borderColorActive,
449 '--bkbg-ac-icon-color': a.iconColor,
450 '--bkbg-ac-icon-color-active': a.iconColorActive,
451 '--bkbg-ac-accent': a.accentColor,
452 '--bkbg-ac-header-font-size': a.headerFontSize + 'px',
453 '--bkbg-ac-header-font-weight': a.headerFontWeight,
454 '--bkbg-ac-header-line-height': a.headerLineHeight,
455 '--bkbg-ac-content-font-size': a.contentFontSize + 'px',
456 '--bkbg-ac-content-font-weight': a.contentFontWeight,
457 '--bkbg-ac-content-line-height': a.contentLineHeight,
458 '--bkbg-ac-icon-size': a.iconSize + 'px',
459 '--bkbg-ac-shadow': a.enableShadow ? createShadowString(a.shadowHorizontal, a.shadowVertical, a.shadowBlur, a.shadowSpread, a.shadowColor) : 'none',
460 '--bkbg-ac-animation-duration': a.animationDuration + 'ms',
461 '--bkbg-ac-divider-color': a.dividerColor,
462 '--bkbg-ac-divider-width': a.dividerWidth + 'px'
463 };
464
465 var wrapDataAttrs = {
466 'data-style': a.accordionStyle,
467 'data-icon': a.iconType,
468 'data-icon-pos': a.iconPosition,
469 'data-animation': a.enableAnimation ? '1' : '0',
470 'data-hover': a.enableHoverEffect ? '1' : '0',
471 'data-shadow': a.enableShadow ? '1' : '0',
472 'data-divider': a.dividerEnabled ? '1' : '0'
473 };
474
475 // Build accordion items (WYSIWYG)
476 var itemsEl = a.items.map(function (item, index) {
477 var isActive = a.activeItems.indexOf(index) !== -1;
478
479 return el('div', {
480 className: 'bkbg-ac-item' + (isActive ? ' is-active' : ''),
481 key: 'item-' + index
482 },
483 // Item actions toolbar
484 el('div', { className: 'bkbg-ac-item-actions' },
485 el(Button, {
486 icon: 'arrow-up-alt2',
487 label: __('Move up', 'blockenberg'),
488 onClick: function () { moveItem(index, -1); },
489 disabled: index === 0,
490 isSmall: true
491 }),
492 el(Button, {
493 icon: 'arrow-down-alt2',
494 label: __('Move down', 'blockenberg'),
495 onClick: function () { moveItem(index, 1); },
496 disabled: index === a.items.length - 1,
497 isSmall: true
498 }),
499 el(Button, {
500 icon: 'trash',
501 label: __('Remove', 'blockenberg'),
502 onClick: function () { removeItem(index); },
503 isDestructive: true,
504 isSmall: true,
505 disabled: a.items.length <= 1
506 })
507 ),
508
509 // Header (clickable)
510 el('button', {
511 className: 'bkbg-ac-header',
512 'aria-expanded': isActive ? 'true' : 'false',
513 onClick: function (e) {
514 // Don't toggle if clicking on input
515 if (e.target.tagName === 'INPUT') return;
516 toggleItem(index);
517 }
518 },
519 el('input', {
520 className: 'bkbg-ac-title-input',
521 type: 'text',
522 value: item.title,
523 placeholder: __('Enter title...', 'blockenberg'),
524 onChange: function (e) { updateItem(index, 'title', e.target.value); },
525 onClick: function (e) { e.stopPropagation(); }
526 }),
527 el('span', { className: 'bkbg-ac-icon', 'aria-hidden': 'true' }, getIcon(a.iconType))
528 ),
529
530 // Content panel
531 el('div', {
532 className: 'bkbg-ac-content',
533 'aria-hidden': isActive ? 'false' : 'true'
534 },
535 el('div', { className: 'bkbg-ac-inner' },
536 el(RichText, {
537 tagName: 'div',
538 className: 'bkbg-ac-body bkbg-ac-body-editor',
539 value: item.content,
540 onChange: function (value) { updateItem(index, 'content', value); },
541 placeholder: __('Add content...', 'blockenberg')
542 })
543 )
544 )
545 );
546 });
547
548 var blockProps = useBlockProps({
549 className: 'bkbg-editor-wrap',
550 'data-block-label': 'Accordion'
551 });
552
553 return el('div', blockProps,
554 inspector,
555 el('div', Object.assign({ className: 'bkbg-ac-wrap', style: wrapStyle }, wrapDataAttrs),
556 itemsEl,
557 ),
558 el('div', { className: 'bkbg-editor-actions' },
559 el(Button, { variant: 'secondary', icon: 'plus-alt2', onClick: addItem }, __('Add Item', 'blockenberg'))
560 )
561 );
562 },
563
564 save: function (props) {
565 var a = props.attributes;
566
567 function createShadowString(h, v, blur, spread, color) {
568 return h + 'px ' + v + 'px ' + blur + 'px ' + spread + 'px ' + color;
569 }
570
571 var wrapStyle = {
572 '--bkbg-ac-gap': a.gap + 'px',
573 '--bkbg-ac-radius': a.borderRadius + 'px',
574 '--bkbg-ac-brd-w': a.borderWidth + 'px',
575 '--bkbg-ac-brd-style': a.borderStyle,
576 '--bkbg-ac-header-padding': a.headerPaddingTop + 'px ' + a.headerPaddingRight + 'px ' + a.headerPaddingBottom + 'px ' + a.headerPaddingLeft + 'px',
577 '--bkbg-ac-content-padding': a.contentPaddingTop + 'px ' + a.contentPaddingRight + 'px ' + a.contentPaddingBottom + 'px ' + a.contentPaddingLeft + 'px',
578 '--bkbg-ac-header-bg': a.headerBg,
579 '--bkbg-ac-header-bg-hover': a.headerBgHover,
580 '--bkbg-ac-header-bg-active': a.headerBgActive,
581 '--bkbg-ac-header-color': a.headerColor,
582 '--bkbg-ac-header-color-hover': a.headerColorHover,
583 '--bkbg-ac-header-color-active': a.headerColorActive,
584 '--bkbg-ac-content-bg': a.contentBg,
585 '--bkbg-ac-content-color': a.contentColor,
586 '--bkbg-ac-border-color': a.borderColor,
587 '--bkbg-ac-border-color-active': a.borderColorActive,
588 '--bkbg-ac-icon-color': a.iconColor,
589 '--bkbg-ac-icon-color-active': a.iconColorActive,
590 '--bkbg-ac-accent': a.accentColor,
591 '--bkbg-ac-header-font-size': a.headerFontSize + 'px',
592 '--bkbg-ac-header-font-weight': a.headerFontWeight,
593 '--bkbg-ac-header-line-height': a.headerLineHeight,
594 '--bkbg-ac-content-font-size': a.contentFontSize + 'px',
595 '--bkbg-ac-content-font-weight': a.contentFontWeight,
596 '--bkbg-ac-content-line-height': a.contentLineHeight,
597 '--bkbg-ac-icon-size': a.iconSize + 'px',
598 '--bkbg-ac-shadow': a.enableShadow ? createShadowString(a.shadowHorizontal, a.shadowVertical, a.shadowBlur, a.shadowSpread, a.shadowColor) : 'none',
599 '--bkbg-ac-animation-duration': a.animationDuration + 'ms',
600 '--bkbg-ac-divider-color': a.dividerColor,
601 '--bkbg-ac-divider-width': a.dividerWidth + 'px'
602 };
603
604 // Icons
605 var iconSvgs = {
606 chevron: el('svg', { viewBox: '0 0 24 24', xmlns: 'http://www.w3.org/2000/svg' }, el('path', { d: 'M7 10l5 5 5-5z' })),
607 plus: el('svg', { viewBox: '0 0 24 24', xmlns: 'http://www.w3.org/2000/svg' }, el('path', { d: 'M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z' })),
608 arrow: el('svg', { viewBox: '0 0 24 24', xmlns: 'http://www.w3.org/2000/svg' }, el('path', { d: 'M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z' })),
609 caret: el('svg', { viewBox: '0 0 24 24', xmlns: 'http://www.w3.org/2000/svg' }, el('path', { d: 'M7 14l5-5 5 5H7z' }))
610 };
611 var iconEl = iconSvgs[a.iconType] || iconSvgs.chevron;
612
613 // Determine initial open items
614 var initialOpen = [];
615 if (!a.collapseAll) {
616 if (a.firstOpen) {
617 initialOpen = [0];
618 }
619 }
620
621 var itemsEl = a.items.map(function (item, index) {
622 var isOpen = initialOpen.indexOf(index) !== -1;
623 var headerId = 'bkbg-ac-h-' + index;
624 var contentId = 'bkbg-ac-c-' + index;
625
626 return el('div', { className: 'bkbg-ac-item' + (isOpen ? ' is-active' : ''), key: 'item-' + index },
627 el('button', {
628 className: 'bkbg-ac-header',
629 id: headerId,
630 'aria-expanded': isOpen ? 'true' : 'false',
631 'aria-controls': contentId
632 },
633 el('span', { className: 'bkbg-ac-title' }, item.title),
634 el('span', { className: 'bkbg-ac-icon', 'aria-hidden': 'true' }, iconEl)
635 ),
636 el('div', {
637 className: 'bkbg-ac-content',
638 id: contentId,
639 role: 'region',
640 'aria-labelledby': headerId,
641 'aria-hidden': isOpen ? 'false' : 'true'
642 },
643 el('div', { className: 'bkbg-ac-inner' },
644 el(wp.blockEditor.RichText.Content, {
645 tagName: 'div',
646 className: 'bkbg-ac-body',
647 value: item.content
648 })
649 )
650 )
651 );
652 });
653
654 return el('div', {
655 className: 'bkbg-ac-wrap',
656 style: wrapStyle,
657 'data-allow-multiple': a.allowMultiple ? '1' : '0',
658 'data-style': a.accordionStyle,
659 'data-icon': a.iconType,
660 'data-icon-pos': a.iconPosition,
661 'data-animation': a.enableAnimation ? '1' : '0',
662 'data-hover': a.enableHoverEffect ? '1' : '0',
663 'data-shadow': a.enableShadow ? '1' : '0',
664 'data-divider': a.dividerEnabled ? '1' : '0',
665 'data-schema': a.schemaEnabled ? '1' : '0'
666 }, itemsEl);
667 }
668 });
669 });
670