PluginProbe
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor / 2.0.7
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor v2.0.7
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 / styled-list / index.js

index.js in Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor 2.0.7, at blocks/styled-list/index.js

1,073 lines 60.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 ( function () {
2 var el = wp.element.createElement;
3 var Fragment = wp.element.Fragment;
4 var __ = wp.i18n.__;
5 var useState = wp.element.useState;
6 var useEffect = wp.element.useEffect;
7 var useMemo = wp.element.useMemo;
8 var registerBlockType = wp.blocks.registerBlockType;
9 var InspectorControls = wp.blockEditor.InspectorControls;
10 var BlockControls = wp.blockEditor.BlockControls;
11 var useBlockProps = wp.blockEditor.useBlockProps;
12 var RichText = wp.blockEditor.RichText;
13 var PanelBody = wp.components.PanelBody;
14 var PanelColorSettings = wp.blockEditor.PanelColorSettings;
15 var Button = wp.components.Button;
16 var ToggleControl = wp.components.ToggleControl;
17 var RangeControl = wp.components.RangeControl;
18 var SelectControl = wp.components.SelectControl;
19 var TextControl = wp.components.TextControl;
20 var ColorPicker = wp.components.ColorPicker;
21 var Popover = wp.components.Popover;
22 var ToolbarGroup = wp.components.ToolbarGroup;
23 var ToolbarButton = wp.components.ToolbarButton;
24 var TabPanel = wp.components.TabPanel;
25
26 var _tc; function getTypoControl() { return _tc || (_tc = window.bkbgTypographyControl); }
27 var _tv; function getTypoCssVars() { return _tv || (_tv = window.bkbgTypoCssVars); }
28
29 // ── Built-in SVG icons ──────────────────────────────────────────────────────
30 var builtInIcons = {
31 check: el('svg', { viewBox: '0 0 24 24', xmlns: 'http://www.w3.org/2000/svg' },
32 el('path', { d: 'M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z' })
33 ),
34 check2: el('svg', { viewBox: '0 0 24 24', xmlns: 'http://www.w3.org/2000/svg' },
35 el('path', { d: 'M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 14.5l-4.5-4.5 1.41-1.41L10 13.67l7.59-7.59L19 7.5l-9 9z' })
36 ),
37 arrow: el('svg', { viewBox: '0 0 24 24', xmlns: 'http://www.w3.org/2000/svg' },
38 el('path', { d: 'M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z' })
39 ),
40 'arrow-right': el('svg', { viewBox: '0 0 24 24', xmlns: 'http://www.w3.org/2000/svg' },
41 el('path', { d: 'M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z' })
42 ),
43 star: el('svg', { viewBox: '0 0 24 24', xmlns: 'http://www.w3.org/2000/svg' },
44 el('path', { d: 'M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z' })
45 ),
46 disc: el('svg', { viewBox: '0 0 24 24', xmlns: 'http://www.w3.org/2000/svg' },
47 el('circle', { cx: '12', cy: '12', r: '6' })
48 ),
49 square: el('svg', { viewBox: '0 0 24 24', xmlns: 'http://www.w3.org/2000/svg' },
50 el('rect', { x: '6', y: '6', width: '12', height: '12', rx: '2' })
51 ),
52 dash: el('svg', { viewBox: '0 0 24 24', xmlns: 'http://www.w3.org/2000/svg' },
53 el('path', { d: 'M4 11h16v2H4z' })
54 ),
55 cross: el('svg', { viewBox: '0 0 24 24', xmlns: 'http://www.w3.org/2000/svg' },
56 el('path', { d: 'M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z' })
57 ),
58 sparkle: el('svg', { viewBox: '0 0 24 24', xmlns: 'http://www.w3.org/2000/svg' },
59 el('path', { d: 'M12 2l2.4 7.4H22l-6.2 4.5 2.4 7.4L12 17l-6.2 4.3 2.4-7.4L2 9.4h7.6z' })
60 ),
61 bolt: el('svg', { viewBox: '0 0 24 24', xmlns: 'http://www.w3.org/2000/svg' },
62 el('path', { d: 'M7 2v11h3v9l7-12h-4l4-8z' })
63 )
64 };
65
66 // ── Dashicons list (subset) ──────────────────────────────────────────────────
67 var dashicons = [
68 'yes', 'yes-alt', 'no', 'no-alt', 'arrow-right', 'arrow-right-alt', 'arrow-right-alt2',
69 'arrow-left-alt2', 'arrow-up-alt2', 'arrow-down-alt2',
70 'star-filled', 'star-half', 'star-empty', 'heart', 'thumbs-up', 'thumbs-down',
71 'awards', 'flag', 'warning', 'info', 'lightbulb', 'marker', 'tag', 'category',
72 'location', 'location-alt', 'clock', 'calendar', 'calendar-alt',
73 'groups', 'businessman', 'businesswoman', 'admin-users', 'id', 'id-alt',
74 'products', 'cart', 'money', 'money-alt', 'bank', 'feedback', 'forms',
75 'edit', 'trash', 'upload', 'download', 'cloud', 'cloud-upload', 'cloud-saved',
76 'search', 'lock', 'unlock', 'performance', 'analytics', 'chart-bar', 'chart-pie',
77 'chart-line', 'chart-area', 'list-view', 'grid-view', 'slides',
78 'desktop', 'laptop', 'tablet', 'smartphone', 'phone',
79 'media-audio', 'media-video', 'media-document', 'format-image', 'camera',
80 'portfolio', 'book', 'book-alt', 'text-page', 'welcome-write-blog',
81 'hammer', 'art', 'schedule', 'rest-api', 'database', 'code-standards',
82 'rss', 'email', 'email-alt', 'share', 'share-alt', 'networking',
83 'facebook', 'twitter', 'instagram', 'linkedin', 'youtube',
84 'wordpress', 'superhero', 'superhero-alt', 'plugins-checked',
85 'food', 'coffee', 'beer', 'car', 'airplane', 'palmtree', 'building', 'store',
86 'smiley', 'bell', 'megaphone', 'microphone', 'games', 'tickets', 'tickets-alt',
87 'privacy', 'shield', 'shield-alt', 'vault', 'sos', 'nametag', 'clipboard',
88 'sticky', 'open-folder', 'paperclip', 'printer', 'shortcode', 'layout', 'saved',
89 'plus', 'plus-alt', 'plus-alt2', 'minus', 'dismiss', 'remove', 'insert',
90 'ellipsis', 'external', 'exit', 'fullscreen-alt', 'fullscreen-exit-alt'
91 ];
92
93 function getBuiltInIcon(type) {
94 return builtInIcons[type] || builtInIcons.check;
95 }
96
97 // ── Helper: resolve effective icon settings for an item ─────────────────────
98 function resolveItemIcon(a, item) {
99 // Per-item icon overrides global if set (no flag required)
100 var hasPerItem = item && item.itemIconType;
101 var type = hasPerItem ? item.itemIconType : a.iconType;
102 var customChar = hasPerItem ? (item.itemIconChar || a.customChar) : a.customChar;
103 var dashicon = hasPerItem ? (item.itemIconDashicon || a.customDashicon) : a.customDashicon;
104 var imageUrl = hasPerItem ? (item.itemIconUrl || a.customImageUrl) : a.customImageUrl;
105 return { type: type, customChar: customChar, dashicon: dashicon, imageUrl: imageUrl };
106 }
107
108 // ── Helper: build icon element for editor/save ───────────────────────────────
109 function buildIconEl(a, item, index) {
110 var resolved = resolveItemIcon(a, item);
111 var type = resolved.type;
112 var color = (a.perItemColor && item && item.customColor) ? item.customColor : a.iconColor;
113
114 if (type === 'none') return null;
115
116 var inner;
117
118 if (type === 'custom-image') {
119 var url = resolved.imageUrl;
120 if (!url) return null;
121 inner = el('img', {
122 src: url,
123 alt: '',
124 className: 'bkbg-sl-img-icon',
125 style: { width: '100%', height: '100%', objectFit: 'contain', display: 'block' }
126 });
127 } else if (type === 'number') {
128 inner = el('span', { className: 'bkbg-sl-num' }, (index + 1) + '');
129 } else if (type === 'custom-char') {
130 inner = el('span', { className: 'bkbg-sl-char' }, resolved.customChar || '');
131 } else if (type === 'dashicon') {
132 inner = el('span', { className: 'dashicons dashicons-' + resolved.dashicon });
133 } else if (builtInIcons[type]) {
134 inner = getBuiltInIcon(type);
135 } else {
136 inner = getBuiltInIcon('check');
137 }
138
139 return el('span', {
140 className: 'bkbg-sl-icon',
141 'aria-hidden': 'true',
142 style: (color && type !== 'custom-image') ? { color: color } : {}
143 }, inner);
144 }
145
146 registerBlockType('blockenberg/styled-list', {
147 title: __('Styled List', 'blockenberg'),
148 icon: 'editor-ul',
149 category: 'bkbg-content',
150 description: __('Fully customizable list with icons, rich text, and flexible layout options.', 'blockenberg'),
151
152 edit: function (props) {
153 var attributes = props.attributes;
154 var setAttributes = props.setAttributes;
155 var isSelected = props.isSelected;
156 var a = attributes;
157
158 // State: which item is focused
159 var activeState = useState(null);
160 var activeItem = activeState[0];
161 var setActiveItem = activeState[1];
162
163 // FIX: clear active item when block is deselected
164 useEffect(function () {
165 if (!isSelected) { setActiveItem(null); }
166 }, [isSelected]);
167
168 // State: dashicon picker open for which item ('global' | index | null)
169 var iconPickerState = useState(null);
170 var openIconPicker = iconPickerState[0];
171 var setOpenIconPicker = iconPickerState[1];
172
173 // State: per-item icon picker open (stores index or null)
174 var itemIconPickerState = useState(null);
175 var openItemIconPicker = itemIconPickerState[0];
176 var setOpenItemIconPicker = itemIconPickerState[1];
177
178 // State: per-item color picker
179 var colorPickerState = useState(null);
180 var colorPicker = colorPickerState[0];
181 var setColorPicker = colorPickerState[1];
182
183 // State: dashicon search
184 var searchState = useState('');
185 var iconSearch = searchState[0];
186 var setIconSearch = searchState[1];
187
188 // Filtered dashicons
189 var filteredDashicons = useMemo(function () {
190 if (!iconSearch) return dashicons;
191 var s = iconSearch.toLowerCase();
192 return dashicons.filter(function (d) { return d.includes(s); });
193 }, [iconSearch]);
194
195 // ── Helpers ────────────────────────────────────────────────────────────
196 function updateItem(index, key, value) {
197 var newItems = a.items.slice();
198 newItems[index] = Object.assign({}, newItems[index]);
199 newItems[index][key] = value;
200 setAttributes({ items: newItems });
201 }
202
203 function addItem() {
204 setAttributes({
205 items: a.items.concat([{
206 text: __('New list item — click to edit', 'blockenberg'),
207 description: '',
208 customColor: ''
209 }])
210 });
211 }
212
213 function removeItem(index) {
214 if (a.items.length <= 1) return;
215 setAttributes({ items: a.items.filter(function (_, i) { return i !== index; }) });
216 }
217
218 function moveItem(index, dir) {
219 var next = index + dir;
220 if (next < 0 || next >= a.items.length) return;
221 var newItems = a.items.slice();
222 var tmp = newItems[index];
223 newItems[index] = newItems[next];
224 newItems[next] = tmp;
225 setAttributes({ items: newItems });
226 }
227
228 function duplicateItem(index) {
229 var newItems = a.items.slice();
230 newItems.splice(index + 1, 0, Object.assign({}, a.items[index]));
231 setAttributes({ items: newItems });
232 }
233
234 // ── Option lists ───────────────────────────────────────────────────────
235 var listStyleOptions = [
236 { label: __('Vertical (Stack)', 'blockenberg'), value: 'vertical' },
237 { label: __('Two Columns', 'blockenberg'), value: 'grid' },
238 { label: __('Custom Columns', 'blockenberg'), value: 'grid-custom' }
239 ];
240 var iconTypeOptions = [
241 { label: __('Checkmark ✓', 'blockenberg'), value: 'check' },
242 { label: __('Check Circle ●✓', 'blockenberg'), value: 'check2' },
243 { label: __('Arrow ›', 'blockenberg'), value: 'arrow' },
244 { label: __('Arrow Right →', 'blockenberg'), value: 'arrow-right' },
245 { label: __('Disc •', 'blockenberg'), value: 'disc' },
246 { label: __('Square ▪', 'blockenberg'), value: 'square' },
247 { label: __('Star �
248 ', 'blockenberg'), value: 'star' },
249 { label: __('Sparkle ✦', 'blockenberg'), value: 'sparkle' },
250 { label: __('Bolt ⚡', 'blockenberg'), value: 'bolt' },
251 { label: __('Dash —', 'blockenberg'), value: 'dash' },
252 { label: __('Cross ✕', 'blockenberg'), value: 'cross' },
253 { label: __('Number 1 2 3', 'blockenberg'), value: 'number' },
254 { label: __('Custom Character', 'blockenberg'), value: 'custom-char' },
255 { label: __('Custom Image', 'blockenberg'), value: 'custom-image' },
256 { label: __('Dashicon', 'blockenberg'), value: 'dashicon' },
257 { label: __('None', 'blockenberg'), value: 'none' }
258 ];
259
260 // Also used for per-item picker — same options + "Use Global"
261 var itemIconTypeOptions = [{ label: __('— Use Global Icon —', 'blockenberg'), value: '' }].concat(iconTypeOptions);
262 var iconShapeOptions = [
263 { label: __('None (icon only)', 'blockenberg'), value: 'none' },
264 { label: __('Circle — Filled', 'blockenberg'), value: 'circle-filled' },
265 { label: __('Circle — Outline', 'blockenberg'), value: 'circle-outline' },
266 { label: __('Square — Filled', 'blockenberg'), value: 'square-filled' },
267 { label: __('Square — Outline', 'blockenberg'), value: 'square-outline' },
268 { label: __('Rounded Square — Filled', 'blockenberg'), value: 'rounded-filled' },
269 { label: __('Rounded Square — Outline', 'blockenberg'), value: 'rounded-outline' }
270 ];
271 var iconPositionOptions = [
272 { label: __('Left', 'blockenberg'), value: 'left' },
273 { label: __('Right', 'blockenberg'), value: 'right' }
274 ];
275 var borderStyleOptions = [
276 { label: __('Solid', 'blockenberg'), value: 'solid' },
277 { label: __('Dashed', 'blockenberg'), value: 'dashed' },
278 { label: __('Dotted', 'blockenberg'), value: 'dotted' }
279 ];
280 var fontWeightOptions = [
281 { label: '300', value: 300 },
282 { label: '400 — Regular', value: 400 },
283 { label: '500 — Medium', value: 500 },
284 { label: '600 — Semibold', value: 600 },
285 { label: '700 — Bold', value: 700 },
286 { label: '800 — Extrabold', value: 800 }
287 ];
288 var alignmentOptions = [
289 { label: __('Left', 'blockenberg'), value: 'left' },
290 { label: __('Center', 'blockenberg'), value: 'center' },
291 { label: __('Right', 'blockenberg'), value: 'right' }
292 ];
293
294 // ── Dynamic computed styles for preview ────────────────────────────────
295 var wrapDataAttrs = {
296 'data-list-style': a.listStyle,
297 'data-icon-type': a.iconType,
298 'data-icon-shape': a.iconShape,
299 'data-icon-pos': a.iconPosition,
300 'data-icon-align': a.iconAlignTop ? 'top' : 'center',
301 'data-divider': a.dividerEnabled ? '1' : '0',
302 'data-align': a.alignment
303 };
304
305 // Compute inline layout so it always wins over editor iframe resets
306 var isHorizontal = a.listStyle === 'horizontal';
307 var isGrid = a.listStyle === 'grid' || a.listStyle === 'grid-custom';
308 var computedDisplay = isGrid ? 'grid' : 'flex';
309 var computedFlexDir = isHorizontal ? 'row' : 'column';
310
311 var wrapStyle = {
312 display: computedDisplay,
313 flexDirection: isHorizontal ? 'row' : (isGrid ? undefined : 'column'),
314 flexWrap: isHorizontal ? 'wrap' : undefined,
315 gridTemplateColumns: isGrid ? ('repeat(' + ((a.listStyle === 'grid-custom') ? a.columns : 2) + ', 1fr)') : undefined,
316 gap: isHorizontal ? (a.gap + 'px ' + a.columnGap + 'px') : (a.gap + 'px'),
317 columnGap: isGrid ? (a.columnGap + 'px') : undefined,
318 '--bkbg-sl-gap': a.gap + 'px',
319 '--bkbg-sl-col-gap': a.columnGap + 'px',
320 '--bkbg-sl-columns': (a.listStyle === 'grid-custom') ? a.columns : (a.listStyle === 'grid' ? 2 : 1),
321 '--bkbg-sl-icon-size': a.iconSize + 'px',
322 '--bkbg-sl-icon-color': a.iconColor,
323 '--bkbg-sl-icon-bg': a.iconBgColor,
324 '--bkbg-sl-icon-bg-size': a.iconBgSize + 'px',
325 '--bkbg-sl-icon-radius': a.iconBgRadius + '%',
326 '--bkbg-sl-item-padding': a.itemPaddingTop + 'px ' + a.itemPaddingRight + 'px ' + a.itemPaddingBottom + 'px ' + a.itemPaddingLeft + 'px',
327 '--bkbg-sl-item-bg': a.itemBg,
328 '--bkbg-sl-item-bg-hover': a.itemBgHover || a.itemBg,
329 '--bkbg-sl-item-brd-w': a.itemBorderWidth + 'px',
330 '--bkbg-sl-item-brd-color': a.itemBorderColor,
331 '--bkbg-sl-item-brd-style': a.itemBorderStyle,
332 '--bkbg-sl-item-radius': a.itemBorderRadius + 'px',
333 '--bkbg-sl-divider-color': a.dividerColor,
334 '--bkbg-sl-divider-w': a.dividerWidth + 'px',
335 '--bkbg-sl-text-color': a.textColor,
336 '--bkbg-sl-desc-color': a.descColor
337 };
338 var _tvf = getTypoCssVars();
339 Object.assign(wrapStyle, _tvf(a.textTypo, '--bksl-tx-'));
340 Object.assign(wrapStyle, _tvf(a.descTypo, '--bksl-ds-'));
341
342 // ── Open media library for image icon ─────────────────────────────────
343 function openMediaLibrary(onSelect) {
344 var frame = wp.media({
345 title: __('Select Icon Image', 'blockenberg'),
346 button: { text: __('Use as Icon', 'blockenberg') },
347 multiple: false,
348 library: { type: 'image' }
349 });
350 frame.on('select', function () {
351 var attachment = frame.state().get('selection').first().toJSON();
352 onSelect(attachment.url);
353 });
354 frame.open();
355 }
356
357 // ── Dashicon picker popover ────────────────────────────────────────────
358 function renderDashiconPicker(onPick) {
359 return el(Popover, {
360 position: 'bottom left',
361 className: 'bkbg-sl-icon-popover',
362 onClose: function () {
363 setOpenIconPicker(null);
364 setIconSearch('');
365 }
366 },
367 el('div', {
368 className: 'bkbg-sc-icon-picker-modal',
369 onMouseDown: function (e) { e.stopPropagation(); },
370 onClick: function (e) { e.stopPropagation(); }
371 },
372 el('div', { className: 'bkbg-sc-icon-picker-header' },
373 el('h3', {}, __('Choose Dashicon', 'blockenberg')),
374 el(Button, {
375 icon: 'no-alt',
376 onClick: function () { setOpenIconPicker(null); setIconSearch(''); },
377 className: 'bkbg-sc-icon-picker-close'
378 })
379 ),
380 el(TextControl, {
381 placeholder: __('Search icons…', 'blockenberg'),
382 value: iconSearch,
383 onChange: setIconSearch,
384 className: 'bkbg-sc-icon-search'
385 }),
386 el('div', { className: 'bkbg-sc-dashicons-grid' },
387 filteredDashicons.length === 0
388 ? el('p', { className: 'bkbg-sc-no-icons' }, __('No icons found', 'blockenberg'))
389 : filteredDashicons.map(function (icon) {
390 var isActive = (typeof onPick === 'function' ? false : a.customDashicon === icon);
391 return el('button', {
392 key: icon,
393 type: 'button',
394 className: 'bkbg-sc-dashicon-btn' + (isActive ? ' is-active' : ''),
395 onClick: function () {
396 if (typeof onPick === 'function') { onPick(icon); }
397 else { setAttributes({ customDashicon: icon }); }
398 setOpenIconPicker(null);
399 setIconSearch('');
400 },
401 title: icon
402 },
403 el('span', { className: 'dashicons dashicons-' + icon })
404 );
405 })
406 )
407 )
408 );
409 }
410
411 // ── Inspector Controls ─────────────────────────────────────────────────
412 var inspector = el(InspectorControls, {},
413
414 // ── Layout ────────────────────────────────────────────────────────
415 el(PanelBody, { title: __('Layout', 'blockenberg'), initialOpen: true },
416 el(SelectControl, {
417 label: __('List Layout', 'blockenberg'),
418 value: a.listStyle,
419 options: listStyleOptions,
420 onChange: function (v) { setAttributes({ listStyle: v }); }
421 }),
422 (a.listStyle === 'grid-custom') && el(RangeControl, {
423 label: __('Columns', 'blockenberg'),
424 value: a.columns,
425 min: 2,
426 max: 6,
427 onChange: function (v) { setAttributes({ columns: v }); }
428 }),
429 el(SelectControl, {
430 label: __('Text Alignment', 'blockenberg'),
431 value: a.alignment,
432 options: alignmentOptions,
433 onChange: function (v) { setAttributes({ alignment: v }); }
434 }),
435 el(RangeControl, {
436 label: __('Row Gap', 'blockenberg'),
437 value: a.gap,
438 min: 0,
439 max: 60,
440 onChange: function (v) { setAttributes({ gap: v }); }
441 }),
442 (a.listStyle === 'grid' || a.listStyle === 'grid-custom' || a.listStyle === 'horizontal') && el(RangeControl, {
443 label: __('Column Gap', 'blockenberg'),
444 value: a.columnGap,
445 min: 0,
446 max: 80,
447 onChange: function (v) { setAttributes({ columnGap: v }); }
448 })
449 ),
450
451 // ── Icon ──────────────────────────────────────────────────────────
452 el(PanelBody, { title: __('Icon', 'blockenberg'), initialOpen: false },
453 el(SelectControl, {
454 label: __('Icon Type', 'blockenberg'),
455 value: a.iconType,
456 options: iconTypeOptions,
457 onChange: function (v) { setAttributes({ iconType: v }); }
458 }),
459
460 // Custom char input
461 (a.iconType === 'custom-char') && el(TextControl, {
462 label: __('Custom Character', 'blockenberg'),
463 value: a.customChar,
464 onChange: function (v) { setAttributes({ customChar: v }); },
465 help: __('Enter any character or emoji, e.g. → ✦ ◆ 🔥', 'blockenberg')
466 }),
467
468 // Custom image upload
469 (a.iconType === 'custom-image') && el('div', { style: { marginBottom: '16px' } },
470 el('p', { className: 'components-base-control__label' }, __('Image Icon', 'blockenberg')),
471 a.customImageUrl && el('div', { style: { marginBottom: '8px', display: 'flex', alignItems: 'center', gap: '8px' } },
472 el('img', { src: a.customImageUrl, alt: '', style: { width: '40px', height: '40px', objectFit: 'contain', border: '1px solid #e2e8f0', borderRadius: '4px', padding: '2px' } }),
473 el(Button, {
474 isSmall: true,
475 isDestructive: true,
476 variant: 'secondary',
477 onClick: function () { setAttributes({ customImageUrl: '' }); }
478 }, __('Remove', 'blockenberg'))
479 ),
480 el(Button, {
481 variant: 'secondary',
482 onClick: function () { openMediaLibrary(function (url) { setAttributes({ customImageUrl: url }); }); }
483 },
484 el('span', { className: 'dashicons dashicons-upload', style: { marginRight: '4px' } }),
485 a.customImageUrl ? __('Replace Image', 'blockenberg') : __('Select from Media Library', 'blockenberg')
486 )
487 ),
488
489 // Dashicon picker button
490 (a.iconType === 'dashicon') && el('div', { style: { marginBottom: '16px' } },
491 el('p', { className: 'components-base-control__label' }, __('Dashicon', 'blockenberg')),
492 el('div', { style: { display: 'flex', alignItems: 'center', gap: '8px' } },
493 el('span', { className: 'dashicons dashicons-' + a.customDashicon, style: { fontSize: '24px', width: '24px', height: '24px' } }),
494 el(Button, {
495 variant: 'secondary',
496 isSmall: true,
497 onClick: function () { setOpenIconPicker(openIconPicker ? null : 'global'); }
498 }, __('Change Icon', 'blockenberg')),
499 openIconPicker === 'global' && renderDashiconPicker()
500 )
501 ),
502
503 el(SelectControl, {
504 label: __('Icon Shape', 'blockenberg'),
505 value: a.iconShape,
506 options: iconShapeOptions,
507 onChange: function (v) { setAttributes({ iconShape: v }); }
508 }),
509 el(SelectControl, {
510 label: __('Icon Position', 'blockenberg'),
511 value: a.iconPosition,
512 options: iconPositionOptions,
513 onChange: function (v) { setAttributes({ iconPosition: v }); }
514 }),
515 el(ToggleControl, {
516 label: __('Align icon to top', 'blockenberg'),
517 help: __('By default icon aligns to the first line of text.', 'blockenberg'),
518 checked: a.iconAlignTop,
519 __nextHasNoMarginBottom: true,
520 onChange: function (v) { setAttributes({ iconAlignTop: v }); }
521 }),
522 el(RangeControl, {
523 label: __('Icon Size', 'blockenberg'),
524 value: a.iconSize,
525 min: 10,
526 max: 60,
527 onChange: function (v) { setAttributes({ iconSize: v }); }
528 }),
529 (a.iconShape !== 'none') && el(RangeControl, {
530 label: __('Icon Container Size', 'blockenberg'),
531 value: a.iconBgSize,
532 min: 20,
533 max: 80,
534 onChange: function (v) { setAttributes({ iconBgSize: v }); }
535 }),
536 (a.iconShape !== 'none' && (a.iconShape === 'rounded-filled' || a.iconShape === 'rounded-outline')) && el(RangeControl, {
537 label: __('Container Radius', 'blockenberg'),
538 value: a.iconBgRadius,
539 min: 0,
540 max: 50,
541 onChange: function (v) { setAttributes({ iconBgRadius: v }); }
542 })
543 ),
544
545 // ── Item Style ────────────────────────────────────────────────────
546 el(PanelBody, { title: __('Item Style', 'blockenberg'), initialOpen: false },
547 el('p', { className: 'components-base-control__label', style: { marginBottom: '8px' } }, __('Item Padding', 'blockenberg')),
548 el('div', { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '8px', marginBottom: '16px' } },
549 el(RangeControl, { label: __('Top', 'blockenberg'), value: a.itemPaddingTop, min: 0, max: 40, onChange: function (v) { setAttributes({ itemPaddingTop: v }); } }),
550 el(RangeControl, { label: __('Right', 'blockenberg'), value: a.itemPaddingRight, min: 0, max: 40, onChange: function (v) { setAttributes({ itemPaddingRight: v }); } }),
551 el(RangeControl, { label: __('Bottom', 'blockenberg'), value: a.itemPaddingBottom, min: 0, max: 40, onChange: function (v) { setAttributes({ itemPaddingBottom: v }); } }),
552 el(RangeControl, { label: __('Left', 'blockenberg'), value: a.itemPaddingLeft, min: 0, max: 40, onChange: function (v) { setAttributes({ itemPaddingLeft: v }); } })
553 ),
554 el(RangeControl, {
555 label: __('Border Width', 'blockenberg'),
556 value: a.itemBorderWidth,
557 min: 0,
558 max: 6,
559 onChange: function (v) { setAttributes({ itemBorderWidth: v }); }
560 }),
561 (a.itemBorderWidth > 0) && el(SelectControl, {
562 label: __('Border Style', 'blockenberg'),
563 value: a.itemBorderStyle,
564 options: borderStyleOptions,
565 onChange: function (v) { setAttributes({ itemBorderStyle: v }); }
566 }),
567 el(RangeControl, {
568 label: __('Border Radius', 'blockenberg'),
569 value: a.itemBorderRadius,
570 min: 0,
571 max: 32,
572 onChange: function (v) { setAttributes({ itemBorderRadius: v }); }
573 }),
574 el(ToggleControl, {
575 label: __('Item Shadow', 'blockenberg'),
576 checked: a.itemShadow,
577 __nextHasNoMarginBottom: true,
578 onChange: function (v) { setAttributes({ itemShadow: v }); }
579 }),
580 el(ToggleControl, {
581 label: __('Divider between items', 'blockenberg'),
582 checked: a.dividerEnabled,
583 __nextHasNoMarginBottom: true,
584 onChange: function (v) { setAttributes({ dividerEnabled: v }); }
585 }),
586 a.dividerEnabled && el(RangeControl, {
587 label: __('Divider Height', 'blockenberg'),
588 value: a.dividerWidth,
589 min: 1,
590 max: 4,
591 onChange: function (v) { setAttributes({ dividerWidth: v }); }
592 })
593 ),
594
595 // ── Typography ────────────────────────────────────────────────────
596 el(PanelBody, { title: __('Typography', 'blockenberg'), initialOpen: false },
597 getTypoControl()({ label: __('Main Text', 'blockenberg'), value: a.textTypo, onChange: function (v) { setAttributes({ textTypo: v }); } }),
598 el(ToggleControl, {
599 label: __('Show description line', 'blockenberg'),
600 help: __('Add a secondary text beneath each item.', 'blockenberg'),
601 checked: a.showDescription,
602 __nextHasNoMarginBottom: true,
603 onChange: function (v) { setAttributes({ showDescription: v }); }
604 }),
605 a.showDescription && getTypoControl()({ label: __('Description Text', 'blockenberg'), value: a.descTypo, onChange: function (v) { setAttributes({ descTypo: v }); } })
606 ),
607
608 // ── Colors ────────────────────────────────────────────────────────
609 el(PanelBody, { title: __('Colors', 'blockenberg'), initialOpen: false },
610 el(PanelColorSettings, {
611 title: __('Icon', 'blockenberg'),
612 initialOpen: false,
613 colorSettings: [
614 {
615 value: a.iconColor,
616 onChange: function (v) { setAttributes({ iconColor: v || '#3b82f6' }); },
617 label: __('Icon Color', 'blockenberg')
618 },
619 (a.iconShape !== 'none') ? {
620 value: a.iconBgColor,
621 onChange: function (v) { setAttributes({ iconBgColor: v || '#dbeafe' }); },
622 label: __('Icon Background', 'blockenberg')
623 } : null
624 ].filter(Boolean)
625 }),
626 el(PanelColorSettings, {
627 title: __('Text', 'blockenberg'),
628 initialOpen: false,
629 colorSettings: [
630 {
631 value: a.textColor,
632 onChange: function (v) { setAttributes({ textColor: v || '#374151' }); },
633 label: __('Text Color', 'blockenberg')
634 },
635 a.showDescription ? {
636 value: a.descColor,
637 onChange: function (v) { setAttributes({ descColor: v || '#6b7280' }); },
638 label: __('Description Color', 'blockenberg')
639 } : null
640 ].filter(Boolean)
641 }),
642 el(PanelColorSettings, {
643 title: __('Item', 'blockenberg'),
644 initialOpen: false,
645 colorSettings: [
646 {
647 value: a.itemBg,
648 onChange: function (v) { setAttributes({ itemBg: v || 'transparent' }); },
649 label: __('Item Background', 'blockenberg')
650 },
651 (a.itemBorderWidth > 0) ? {
652 value: a.itemBorderColor,
653 onChange: function (v) { setAttributes({ itemBorderColor: v || '#e2e8f0' }); },
654 label: __('Item Border Color', 'blockenberg')
655 } : null,
656 a.dividerEnabled ? {
657 value: a.dividerColor,
658 onChange: function (v) { setAttributes({ dividerColor: v || '#e2e8f0' }); },
659 label: __('Divider Color', 'blockenberg')
660 } : null
661 ].filter(Boolean)
662 })
663 ),
664
665 // ── Per-item settings ─────────────────────────────────────────────
666 el(PanelBody, { title: __('Per-item Options', 'blockenberg'), initialOpen: false },
667 el(ToggleControl, {
668 label: __('Enable per-item icon color', 'blockenberg'),
669 help: __('Set a custom icon color per item in the canvas.', 'blockenberg'),
670 checked: a.perItemColor,
671 __nextHasNoMarginBottom: true,
672 onChange: function (v) { setAttributes({ perItemColor: v }); }
673 }),
674 el(ToggleControl, {
675 label: __('Enable per-item icon override', 'blockenberg'),
676 help: __('Set a custom icon type / image for individual items.', 'blockenberg'),
677 checked: a.perItemIcon,
678 __nextHasNoMarginBottom: true,
679 onChange: function (v) { setAttributes({ perItemIcon: v }); }
680 })
681 )
682 );
683
684 // ── Block Controls (Toolbar) ───────────────────────────────────────────
685 var blockControls = el(BlockControls, {},
686 el(ToolbarGroup, {},
687 el(ToolbarButton, {
688 icon: 'editor-alignleft',
689 title: __('Align Left', 'blockenberg'),
690 isActive: a.alignment === 'left',
691 onClick: function () { setAttributes({ alignment: 'left' }); }
692 }),
693 el(ToolbarButton, {
694 icon: 'editor-aligncenter',
695 title: __('Align Center', 'blockenberg'),
696 isActive: a.alignment === 'center',
697 onClick: function () { setAttributes({ alignment: 'center' }); }
698 }),
699 el(ToolbarButton, {
700 icon: 'editor-alignright',
701 title: __('Align Right', 'blockenberg'),
702 isActive: a.alignment === 'right',
703 onClick: function () { setAttributes({ alignment: 'right' }); }
704 })
705 )
706 );
707
708 // ── Render items ──────────────────────────────────────────────────────
709 var itemsEl = a.items.map(function (item, index) {
710 // Toolbar only when block is selected AND this item is focused
711 var isActive2 = isSelected && activeItem === index;
712 var itemColor = (a.perItemColor && item.customColor) ? item.customColor : null;
713 var iconEl = buildIconEl(a, item, index);
714
715 return el('div', {
716 key: 'item-' + index,
717 className: 'bkbg-sl-item' + (isActive2 ? ' is-focused' : '') + (a.itemShadow ? ' has-shadow' : ''),
718 onClick: function () { setActiveItem(index); }
719 },
720 // ── Item toolbar ──────────────────────────────────────────
721 isActive2 && el('div', { className: 'bkbg-sl-item-toolbar' },
722 el(Button, {
723 icon: 'arrow-up-alt2',
724 label: __('Move Up', 'blockenberg'),
725 isSmall: true,
726 disabled: index === 0,
727 onClick: function (e) { e.stopPropagation(); moveItem(index, -1); }
728 }),
729 el(Button, {
730 icon: 'arrow-down-alt2',
731 label: __('Move Down', 'blockenberg'),
732 isSmall: true,
733 disabled: index === a.items.length - 1,
734 onClick: function (e) { e.stopPropagation(); moveItem(index, 1); }
735 }),
736 el(Button, {
737 icon: 'admin-page',
738 label: __('Duplicate', 'blockenberg'),
739 isSmall: true,
740 onClick: function (e) { e.stopPropagation(); duplicateItem(index); }
741 }),
742 // Per-item color picker
743 a.perItemColor && el('div', { style: { position: 'relative', display: 'inline-block' } },
744 el(Button, {
745 isSmall: true,
746 onClick: function (e) {
747 e.stopPropagation();
748 setColorPicker(colorPicker === index ? null : index);
749 },
750 style: { display: 'flex', alignItems: 'center', gap: '4px' }
751 },
752 el('span', {
753 style: {
754 display: 'inline-block',
755 width: '14px',
756 height: '14px',
757 borderRadius: '50%',
758 background: item.customColor || a.iconColor,
759 border: '1px solid rgba(0,0,0,.2)'
760 }
761 }),
762 __('Color', 'blockenberg')
763 ),
764 colorPicker === index && el(Popover, {
765 position: 'bottom center',
766 onClose: function () { setColorPicker(null); }
767 },
768 el('div', {
769 style: { padding: '8px' },
770 onMouseDown: function (e) { e.stopPropagation(); }
771 },
772 el(ColorPicker, {
773 color: item.customColor || a.iconColor,
774 onChange: function (v) { updateItem(index, 'customColor', v); }
775 }),
776 item.customColor && el(Button, {
777 isSmall: true,
778 isDestructive: true,
779 onClick: function () { updateItem(index, 'customColor', ''); }
780 }, __('Reset', 'blockenberg'))
781 )
782 )
783 ),
784 el(Button, {
785 icon: 'trash',
786 label: __('Remove Item', 'blockenberg'),
787 isSmall: true,
788 isDestructive: true,
789 disabled: a.items.length <= 1,
790 onClick: function (e) { e.stopPropagation(); removeItem(index); }
791 }),
792
793 // Per-item icon override picker – always available
794 el('div', { style: { position: 'relative', display: 'inline-block' } },
795 el(Button, {
796 isSmall: true,
797 onClick: function (e) {
798 e.stopPropagation();
799 setOpenItemIconPicker(openItemIconPicker === index ? null : index);
800 },
801 style: { display: 'flex', alignItems: 'center', gap: '4px' }
802 },
803 el('span', { className: 'dashicons dashicons-insert', style: { fontSize: '16px', width: '16px', height: '16px' } }),
804 __('Icon', 'blockenberg')
805 ),
806 openItemIconPicker === index && el(Popover, {
807 position: 'bottom center',
808 onClose: function () { setOpenItemIconPicker(null); }
809 },
810 el('div', {
811 style: { padding: '12px', minWidth: '200px' },
812 onMouseDown: function (e) { e.stopPropagation(); }
813 },
814 el('p', { style: { margin: '0 0 8px', fontWeight: 600, fontSize: '12px', textTransform: 'uppercase', color: '#888' } }, __('Per-item Icon', 'blockenberg')),
815 el(SelectControl, {
816 label: __('Icon Type', 'blockenberg'),
817 value: item.itemIconType || '',
818 options: itemIconTypeOptions,
819 onChange: function (v) { updateItem(index, 'itemIconType', v); }
820 }),
821 (item.itemIconType === 'custom-char') && el(TextControl, {
822 label: __('Character', 'blockenberg'),
823 value: item.itemIconChar || '',
824 onChange: function (v) { updateItem(index, 'itemIconChar', v); }
825 }),
826 (item.itemIconType === 'dashicon') && el('div', {},
827 el('div', { style: { display: 'flex', alignItems: 'center', gap: '8px', marginBottom: '8px' } },
828 el('span', { className: 'dashicons dashicons-' + (item.itemIconDashicon || a.customDashicon), style: { fontSize: '20px', width: '20px', height: '20px' } }),
829 el(Button, {
830 variant: 'secondary',
831 isSmall: true,
832 onClick: function () { setOpenIconPicker('item-' + index); }
833 }, __('Pick Dashicon', 'blockenberg'))
834 ),
835 openIconPicker === ('item-' + index) && renderDashiconPicker(function (icon) {
836 updateItem(index, 'itemIconDashicon', icon);
837 })
838 ),
839 (item.itemIconType === 'custom-image') && el('div', {},
840 item.itemIconUrl && el('div', { style: { marginBottom: '8px', display: 'flex', alignItems: 'center', gap: '6px' } },
841 el('img', { src: item.itemIconUrl, alt: '', style: { width: '32px', height: '32px', objectFit: 'contain', border: '1px solid #e2e8f0', borderRadius: '4px' } }),
842 el(Button, { isSmall: true, isDestructive: true, onClick: function () { updateItem(index, 'itemIconUrl', ''); } }, __('Remove', 'blockenberg'))
843 ),
844 el(Button, {
845 variant: 'secondary',
846 isSmall: true,
847 onClick: function () {
848 openMediaLibrary(function (url) { updateItem(index, 'itemIconUrl', url); });
849 }
850 }, item.itemIconUrl ? __('Replace Image', 'blockenberg') : __('Select Image', 'blockenberg'))
851 )
852 )
853 )
854 )
855 ),
856
857 // ── Icon (left) ───────────────────────────────────────────
858 (a.iconPosition === 'left') && iconEl && el('div', {
859 className: 'bkbg-sl-icon-wrap',
860 style: itemColor ? { color: itemColor } : {}
861 }, iconEl),
862
863 // ── Text area ─────────────────────────────────────────────
864 el('div', { className: 'bkbg-sl-content' },
865 el(RichText, {
866 tagName: 'div',
867 className: 'bkbg-sl-text',
868 value: item.text,
869 onChange: function (v) { updateItem(index, 'text', v); },
870 placeholder: __('List item text…', 'blockenberg'),
871 allowedFormats: ['core/bold', 'core/italic', 'core/strikethrough', 'core/link', 'core/underline', 'core/text-color']
872 }),
873 a.showDescription && el(RichText, {
874 tagName: 'div',
875 className: 'bkbg-sl-desc',
876 value: item.description,
877 onChange: function (v) { updateItem(index, 'description', v); },
878 placeholder: __('Optional description…', 'blockenberg'),
879 allowedFormats: ['core/bold', 'core/italic', 'core/link']
880 })
881 ),
882
883 // ── Icon (right) ──────────────────────────────────────────
884 (a.iconPosition === 'right') && iconEl && el('div', {
885 className: 'bkbg-sl-icon-wrap',
886 style: itemColor ? { color: itemColor } : {}
887 }, iconEl)
888 );
889 });
890
891 var blockProps = useBlockProps({
892 className: 'bkbg-editor-wrap',
893 'data-block-label': 'Styled List'
894 });
895
896 return el('div', blockProps,
897 inspector,
898 blockControls,
899 el('ul', Object.assign({
900 className: 'bkbg-sl-wrap',
901 style: wrapStyle
902 }, wrapDataAttrs),
903 itemsEl.map(function (item, i) {
904 return el('li', { key: 'li-' + i, className: 'bkbg-sl-li' }, item);
905 })
906 ),
907 el('div', { className: 'bkbg-editor-actions' },
908 el(Button, {
909 variant: 'secondary',
910 icon: 'plus-alt2',
911 onClick: addItem
912 }, __('Add Item', 'blockenberg'))
913 )
914 );
915 },
916
917 // ── Save ─────────────────────────────────────────────────────────────────
918 save: function (props) {
919 var a = props.attributes;
920 var RichTextContent = wp.blockEditor.RichText.Content;
921
922 var saveIsHorizontal = a.listStyle === 'horizontal';
923 var saveIsGrid = a.listStyle === 'grid' || a.listStyle === 'grid-custom';
924
925 var wrapStyle = {
926 display: saveIsGrid ? 'grid' : 'flex',
927 flexDirection: saveIsHorizontal ? 'row' : (saveIsGrid ? undefined : 'column'),
928 flexWrap: saveIsHorizontal ? 'wrap' : undefined,
929 gridTemplateColumns: saveIsGrid ? ('repeat(' + ((a.listStyle === 'grid-custom') ? a.columns : 2) + ', 1fr)') : undefined,
930 gap: saveIsHorizontal ? (a.gap + 'px ' + a.columnGap + 'px') : (a.gap + 'px'),
931 '--bkbg-sl-gap': a.gap + 'px',
932 '--bkbg-sl-col-gap': a.columnGap + 'px',
933 '--bkbg-sl-columns': (a.listStyle === 'grid-custom') ? a.columns : (a.listStyle === 'grid' ? 2 : 1),
934 '--bkbg-sl-icon-size': a.iconSize + 'px',
935 '--bkbg-sl-icon-color': a.iconColor,
936 '--bkbg-sl-icon-bg': a.iconBgColor,
937 '--bkbg-sl-icon-bg-size': a.iconBgSize + 'px',
938 '--bkbg-sl-icon-radius': a.iconBgRadius + '%',
939 '--bkbg-sl-item-padding': a.itemPaddingTop + 'px ' + a.itemPaddingRight + 'px ' + a.itemPaddingBottom + 'px ' + a.itemPaddingLeft + 'px',
940 '--bkbg-sl-item-bg': a.itemBg,
941 '--bkbg-sl-item-bg-hover': a.itemBgHover || a.itemBg,
942 '--bkbg-sl-item-brd-w': a.itemBorderWidth + 'px',
943 '--bkbg-sl-item-brd-color': a.itemBorderColor,
944 '--bkbg-sl-item-brd-style': a.itemBorderStyle,
945 '--bkbg-sl-item-radius': a.itemBorderRadius + 'px',
946 '--bkbg-sl-divider-color': a.dividerColor,
947 '--bkbg-sl-divider-w': a.dividerWidth + 'px',
948 '--bkbg-sl-text-color': a.textColor,
949 '--bkbg-sl-desc-color': a.descColor
950 };
951 var _tvf = window.bkbgTypoCssVars || function () { return {}; };
952 Object.assign(wrapStyle, _tvf(a.textTypo, '--bksl-tx-'));
953 Object.assign(wrapStyle, _tvf(a.descTypo, '--bksl-ds-'));
954
955 // Build SVG icons inline for save (no React)
956 var svgPaths = {
957 check: 'M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z',
958 check2: 'M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 14.5l-4.5-4.5 1.41-1.41L10 13.67l7.59-7.59L19 7.5l-9 9z',
959 arrow: 'M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z',
960 'arrow-right': 'M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z',
961 star: 'M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z',
962 dash: 'M4 11h16v2H4z',
963 cross: 'M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z',
964 sparkle: 'M12 2l2.4 7.4H22l-6.2 4.5 2.4 7.4L12 17l-6.2 4.3 2.4-7.4L2 9.4h7.6z',
965 bolt: 'M7 2v11h3v9l7-12h-4l4-8z'
966 };
967
968 function buildSaveIconEl(item, index) {
969 // Resolve per-item override (no flag required)
970 var hasPerItem = item && item.itemIconType;
971 var type = hasPerItem ? item.itemIconType : a.iconType;
972 var customChar = hasPerItem ? (item.itemIconChar || a.customChar) : a.customChar;
973 var dashiconName = hasPerItem ? (item.itemIconDashicon || a.customDashicon) : a.customDashicon;
974 var imageUrl = hasPerItem ? (item.itemIconUrl || a.customImageUrl) : a.customImageUrl;
975
976 if (type === 'none') return null;
977 var color = (a.perItemColor && item.customColor) ? item.customColor : null;
978 var iconStyle = (color && type !== 'custom-image') ? { color: color } : {};
979
980 var inner;
981 if (type === 'custom-image') {
982 if (!imageUrl) return null;
983 inner = el('img', {
984 src: imageUrl,
985 alt: '',
986 className: 'bkbg-sl-img-icon',
987 style: { width: '100%', height: '100%', objectFit: 'contain', display: 'block' }
988 });
989 } else if (type === 'number') {
990 inner = el('span', { className: 'bkbg-sl-num' }, (index + 1) + '');
991 } else if (type === 'custom-char') {
992 inner = el('span', { className: 'bkbg-sl-char' }, customChar || '');
993 } else if (type === 'dashicon') {
994 inner = el('span', { className: 'dashicons dashicons-' + dashiconName });
995 } else if (type === 'disc') {
996 inner = el('svg', { viewBox: '0 0 24 24', xmlns: 'http://www.w3.org/2000/svg', 'aria-hidden': 'true' },
997 el('circle', { cx: '12', cy: '12', r: '6' })
998 );
999 } else if (type === 'square') {
1000 inner = el('svg', { viewBox: '0 0 24 24', xmlns: 'http://www.w3.org/2000/svg', 'aria-hidden': 'true' },
1001 el('rect', { x: '6', y: '6', width: '12', height: '12', rx: '2' })
1002 );
1003 } else if (svgPaths[type]) {
1004 inner = el('svg', { viewBox: '0 0 24 24', xmlns: 'http://www.w3.org/2000/svg', 'aria-hidden': 'true' },
1005 el('path', { d: svgPaths[type] })
1006 );
1007 } else {
1008 inner = el('svg', { viewBox: '0 0 24 24', xmlns: 'http://www.w3.org/2000/svg', 'aria-hidden': 'true' },
1009 el('path', { d: svgPaths.check })
1010 );
1011 }
1012
1013 return el('span', {
1014 className: 'bkbg-sl-icon',
1015 'aria-hidden': 'true',
1016 style: iconStyle
1017 }, inner);
1018 }
1019
1020 var itemEls = a.items.map(function (item, index) {
1021 var iconEl = buildSaveIconEl(item, index);
1022 // Effective icon type (per-item or global)
1023 var effectiveType = item.itemIconType ? item.itemIconType : a.iconType;
1024 var showIcon = effectiveType !== 'none' && iconEl !== null;
1025 var itemColor = (a.perItemColor && item.customColor) ? item.customColor : null;
1026
1027 return el('li', {
1028 key: 'li-' + index,
1029 className: 'bkbg-sl-li'
1030 },
1031 el('div', {
1032 className: 'bkbg-sl-item' + (a.itemShadow ? ' has-shadow' : '')
1033 },
1034 (a.iconPosition === 'left') && showIcon && el('div', {
1035 className: 'bkbg-sl-icon-wrap',
1036 style: itemColor ? { color: itemColor } : {}
1037 }, iconEl),
1038 el('div', { className: 'bkbg-sl-content' },
1039 el(RichTextContent, {
1040 tagName: 'div',
1041 className: 'bkbg-sl-text',
1042 value: item.text
1043 }),
1044 (a.showDescription && item.description) && el(RichTextContent, {
1045 tagName: 'div',
1046 className: 'bkbg-sl-desc',
1047 value: item.description
1048 })
1049 ),
1050 (a.iconPosition === 'right') && showIcon && el('div', {
1051 className: 'bkbg-sl-icon-wrap',
1052 style: itemColor ? { color: itemColor } : {}
1053 }, iconEl)
1054 )
1055 );
1056 });
1057
1058 return el('ul', {
1059 className: 'bkbg-sl-wrap',
1060 style: wrapStyle,
1061 'data-list-style': a.listStyle,
1062 'data-icon-type': a.iconType,
1063 'data-icon-shape': a.iconShape,
1064 'data-icon-pos': a.iconPosition,
1065 'data-divider': a.dividerEnabled ? '1' : '0',
1066 'data-align': a.alignment,
1067 'data-shadow': a.itemShadow ? '1' : '0',
1068 'data-icon-align': a.iconAlignTop ? 'top' : 'center'
1069 }, itemEls);
1070 }
1071 });
1072 }() );
1073