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 / alert / index.js

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

494 lines 27.8 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 useState = wp.element.useState;
5 var __ = wp.i18n.__;
6 var registerBlockType = wp.blocks.registerBlockType;
7 var InspectorControls = wp.blockEditor.InspectorControls;
8 var useBlockProps = wp.blockEditor.useBlockProps;
9 var RichText = wp.blockEditor.RichText;
10 var PanelBody = wp.components.PanelBody;
11 var ColorPicker = wp.components.ColorPicker;
12 var Popover = wp.components.Popover;
13 var Button = wp.components.Button;
14 var ToggleControl = wp.components.ToggleControl;
15 var RangeControl = wp.components.RangeControl;
16 var SelectControl = wp.components.SelectControl;
17
18 // ── Preset palettes per alert type ──────────────────────────────────────────
19 var PRESETS = {
20 info: {
21 bg: '#eff6ff', border: '#3b82f6', icon: '#3b82f6',
22 title: '#1e3a5f', text: '#1d4ed8'
23 },
24 success: {
25 bg: '#f0fdf4', border: '#22c55e', icon: '#16a34a',
26 title: '#14532d', text: '#166534'
27 },
28 warning: {
29 bg: '#fffbeb', border: '#f59e0b', icon: '#d97706',
30 title: '#78350f', text: '#92400e'
31 },
32 error: {
33 bg: '#fef2f2', border: '#ef4444', icon: '#dc2626',
34 title: '#7f1d1d', text: '#991b1b'
35 },
36 tip: {
37 bg: '#f5f3ff', border: '#8b5cf6', icon: '#7c3aed',
38 title: '#2e1065', text: '#5b21b6'
39 },
40 note: {
41 bg: '#f8fafc', border: '#94a3b8', icon: '#64748b',
42 title: '#1e293b', text: '#475569'
43 },
44 dark: {
45 bg: '#1e293b', border: '#475569', icon: '#94a3b8',
46 title: '#f1f5f9', text: '#cbd5e1'
47 }
48 };
49
50 // ── Inline SVG icons per alert type ────────────────────────────────────────
51 // All 24×24 viewBox paths
52 var ICONS = {
53 info: {
54 auto: 'M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z',
55 outline: 'M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm-1-5h2v2h-2zm0-8h2v6h-2z'
56 },
57 success: {
58 auto: 'M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z',
59 outline: 'M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm-2-5.83l-2.59-2.58L6 13l4 4 8-8-1.41-1.42L10 14.17z'
60 },
61 warning: {
62 auto: 'M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z',
63 outline: 'M12 5.99L19.53 19H4.47L12 5.99M12 2L1 21h22L12 2zm1 14h-2v2h2v-2zm0-6h-2v4h2v-4z'
64 },
65 error: {
66 auto: 'M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z',
67 outline: 'M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm-1-5h2v2h-2zm0-8h2v6h-2z'
68 },
69 tip: {
70 auto: 'M9 21c0 .55.45 1 1 1h4c.55 0 1-.45 1-1v-1H9v1zm3-19C8.14 2 5 5.14 5 9c0 2.38 1.19 4.47 3 5.74V17c0 .55.45 1 1 1h6c.55 0 1-.45 1-1v-2.26c1.81-1.27 3-3.36 3-5.74 0-3.86-3.14-7-7-7z',
71 outline: 'M9 21c0 .55.45 1 1 1h4c.55 0 1-.45 1-1v-1H9v1zm3-19C8.14 2 5 5.14 5 9c0 2.38 1.19 4.47 3 5.74V17c0 .55.45 1 1 1h6c.55 0 1-.45 1-1v-2.26c1.81-1.27 3-3.36 3-5.74 0-3.86-3.14-7-7-7zm2.85 11.1l-.85.6V16h-4v-2.3l-.85-.6A4.997 4.997 0 0 1 7 9c0-2.76 2.24-5 5-5s5 2.24 5 5c0 1.63-.8 3.16-2.15 4.1z'
72 },
73 note: {
74 auto: 'M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2z',
75 outline: 'M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z'
76 },
77 dark: {
78 auto: 'M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z',
79 outline: 'M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm-1-5h2v2h-2zm0-8h2v6h-2z'
80 }
81 };
82
83 // Extra standalone icon paths (when iconStyle overrides default)
84 var ICON_OVERRIDES = {
85 star: 'M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z',
86 heart: 'M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z',
87 shield: 'M12 1L3 5v6c0 5.55 3.84 10.74 9 12 5.16-1.26 9-6.45 9-12V5l-9-4zm0 4l6 2.67V11c0 3.83-2.62 7.43-6 8.93-3.38-1.5-6-5.1-6-8.93V7.67L12 5z',
88 bell: 'M12 22c1.1 0 2-.9 2-2h-4c0 1.1.9 2 2 2zm6-6v-5c0-3.07-1.64-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68C7.63 5.36 6 7.92 6 11v5l-2 2v1h16v-1l-2-2z',
89 lock: 'M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zm-6 9c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm3.1-9H8.9V6c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2z',
90 check: 'M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z',
91 zap: 'M7 2v11h3v9l7-12h-4l4-8z',
92 book: 'M18 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zM6 4h5v8l-2.5-1.5L6 12V4z'
93 };
94
95 // ── Resolve icon path ────────────────────────────────────────────────────────
96 function resolveIconPath(alertType, iconStyle) {
97 if (iconStyle !== 'auto' && iconStyle !== 'outline' && ICON_OVERRIDES[iconStyle]) {
98 return ICON_OVERRIDES[iconStyle];
99 }
100 var typeIcons = ICONS[alertType] || ICONS.info;
101 return iconStyle === 'outline' ? typeIcons.outline : typeIcons.auto;
102 }
103
104 // ── Build icon SVG ───────────────────────────────────────────────────────────
105 function buildIconSVG(alertType, iconStyle, iconColor, iconSize) {
106 var d = resolveIconPath(alertType, iconStyle);
107 return el('svg', {
108 viewBox: '0 0 24 24',
109 xmlns: 'http://www.w3.org/2000/svg',
110 width: iconSize,
111 height: iconSize,
112 'aria-hidden': 'true',
113 focusable: 'false',
114 style: { display: 'block', flexShrink: 0 }
115 }, el('path', { d: d, fill: iconColor }));
116 }
117
118 // ── Resolve colors (preset or custom) ───────────────────────────────────────
119 function resolveColors(a) {
120 if (a.useCustomColors) {
121 return {
122 bg: a.customBgColor,
123 border: a.customBorderColor,
124 icon: a.customIconColor,
125 title: a.customTitleColor,
126 text: a.customTextColor
127 };
128 }
129 return PRESETS[a.alertType] || PRESETS.info;
130 }
131
132 // ── CSS vars on wrapper ──────────────────────────────────────────────────────
133 function buildWrapStyle(a) {
134 var c = resolveColors(a);
135 return {
136 '--bkbg-al-bg': c.bg,
137 '--bkbg-al-border': c.border,
138 '--bkbg-al-icon-color': c.icon,
139 '--bkbg-al-title': c.title,
140 '--bkbg-al-text': c.text,
141 '--bkbg-al-brd-w': a.borderWidth + 'px',
142 '--bkbg-al-radius': a.borderRadius + 'px',
143 '--bkbg-al-pad-t': a.paddingTop + 'px',
144 '--bkbg-al-pad-r': a.paddingRight + 'px',
145 '--bkbg-al-pad-b': a.paddingBottom + 'px',
146 '--bkbg-al-pad-l': a.paddingLeft + 'px',
147 '--bkbg-al-gap-ic': a.gapIconContent + 'px',
148 '--bkbg-al-gap-tb': a.gapTitleBody + 'px',
149 '--bkbg-al-title-size': a.titleSize + 'px',
150 '--bkbg-al-title-w': a.titleWeight,
151 '--bkbg-al-body-size': a.bodySize + 'px',
152 '--bkbg-al-body-w': a.bodyWeight,
153 '--bkbg-al-body-lh': a.bodyLH
154 };
155 }
156
157 registerBlockType('blockenberg/alert', {
158 title: __('Alert / Notice', 'blockenberg'),
159 icon: 'warning',
160 category: 'blockenberg',
161 description: __('Info, success, warning or error notice with icon, title and body. Pure CSS.', 'blockenberg'),
162
163 edit: function (props) {
164 var a = props.attributes;
165 var setAttributes = props.setAttributes;
166
167 // ── Color picker state ────────────────────────────────────────────
168 var openColorKeyState = useState(null);
169 var openColorKey = openColorKeyState[0];
170 var setOpenColorKey = openColorKeyState[1];
171
172 function renderColorControl(key, label, value, onChange) {
173 var isOpen = openColorKey === key;
174 return el('div', { key: key, style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '4px 0', gap: '8px' } },
175 el('span', { style: { fontSize: '12px', color: '#1e1e1e', flex: 1, lineHeight: 1.4 } }, label),
176 el('div', { style: { position: 'relative', flexShrink: 0 } },
177 el('button', {
178 type: 'button',
179 title: value || 'none',
180 onClick: function () { setOpenColorKey(isOpen ? null : key); },
181 style: {
182 width: '28px', height: '28px', borderRadius: '4px',
183 border: isOpen ? '2px solid #007cba' : '2px solid #ddd',
184 cursor: 'pointer', padding: 0, display: 'block',
185 background: value || '#ffffff', flexShrink: 0
186 }
187 }),
188 isOpen && el(Popover, {
189 position: 'bottom left',
190 onClose: function () { setOpenColorKey(null); }
191 },
192 el('div', {
193 style: { padding: '8px' },
194 onMouseDown: function (e) { e.stopPropagation(); }
195 },
196 el('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '6px' } },
197 el('strong', { style: { fontSize: '12px' } }, label),
198 el(Button, { icon: 'no-alt', isSmall: true, onClick: function () { setOpenColorKey(null); } })
199 ),
200 el(ColorPicker, {
201 color: value,
202 enableAlpha: true,
203 onChange: function (c) { onChange(c); }
204 })
205 )
206 )
207 )
208 );
209 }
210
211 // ── Option lists ──────────────────────────────────────────────────
212 var alertTypeOptions = [
213 { label: __('ℹ Info', 'blockenberg'), value: 'info' },
214 { label: __('✓ Success', 'blockenberg'), value: 'success' },
215 { label: __('⚠ Warning', 'blockenberg'), value: 'warning' },
216 { label: __('✕ Error', 'blockenberg'), value: 'error' },
217 { label: __('💡 Tip', 'blockenberg'), value: 'tip' },
218 { label: __('📝 Note', 'blockenberg'), value: 'note' },
219 { label: __('■ Dark', 'blockenberg'), value: 'dark' }
220 ];
221
222 var borderStyleOptions = [
223 { label: __('Left bar', 'blockenberg'), value: 'left' },
224 { label: __('Top bar', 'blockenberg'), value: 'top' },
225 { label: __('Full border','blockenberg'), value: 'full' },
226 { label: __('None', 'blockenberg'), value: 'none' }
227 ];
228
229 var iconStyleOptions = [
230 { label: __('Auto (matches type)', 'blockenberg'), value: 'auto' },
231 { label: __('Outline', 'blockenberg'), value: 'outline' },
232 { label: __('Star', 'blockenberg'), value: 'star' },
233 { label: __('Heart', 'blockenberg'), value: 'heart' },
234 { label: __('Shield', 'blockenberg'), value: 'shield' },
235 { label: __('Bell', 'blockenberg'), value: 'bell' },
236 { label: __('Lock', 'blockenberg'), value: 'lock' },
237 { label: __('Check', 'blockenberg'), value: 'check' },
238 { label: __('Zap / Lightning', 'blockenberg'), value: 'zap' },
239 { label: __('Book', 'blockenberg'), value: 'book' }
240 ];
241
242 var iconPositionOptions = [
243 { label: __('Top (align to first line)', 'blockenberg'), value: 'top' },
244 { label: __('Centre (middle of block)', 'blockenberg'), value: 'center' }
245 ];
246
247 var titleTagOptions = [
248 { label: 'p', value: 'p' },
249 { label: 'h3', value: 'h3' },
250 { label: 'h4', value: 'h4' },
251 { label: 'h5', value: 'h5' }
252 ];
253
254 var fontWeightOptions = [
255 { label: '300 — Light', value: 300 },
256 { label: '400 — Regular', value: 400 },
257 { label: '500 — Medium', value: 500 },
258 { label: '600 — Semi Bold', value: 600 },
259 { label: '700 — Bold', value: 700 },
260 { label: '800 — Extra Bold',value: 800 }
261 ];
262
263 var c = resolveColors(a);
264
265 // ── Inspector panels ──────────────────────────────────────────────
266 var inspector = el(InspectorControls, {},
267
268 // ── Alert Type ────────────────────────────────────────────────
269 el(PanelBody, { title: __('Alert Type', 'blockenberg'), initialOpen: true },
270 el(SelectControl, {
271 label: __('Type / Preset', 'blockenberg'),
272 value: a.alertType,
273 options: alertTypeOptions,
274 onChange: function (v) { setAttributes({ alertType: v }); }
275 }),
276 el(SelectControl, {
277 label: __('Border Style', 'blockenberg'),
278 value: a.borderStyle,
279 options: borderStyleOptions,
280 onChange: function (v) { setAttributes({ borderStyle: v }); }
281 }),
282 a.borderStyle !== 'none' && el(RangeControl, {
283 label: __('Border Width (px)', 'blockenberg'),
284 value: a.borderWidth, min: 1, max: 12,
285 onChange: function (v) { setAttributes({ borderWidth: v }); }
286 }),
287 el(RangeControl, {
288 label: __('Border Radius (px)', 'blockenberg'),
289 value: a.borderRadius, min: 0, max: 32,
290 onChange: function (v) { setAttributes({ borderRadius: v }); }
291 })
292 ),
293
294 // ── Icon ──────────────────────────────────────────────────────
295 el(PanelBody, { title: __('Icon', 'blockenberg'), initialOpen: false },
296 el(ToggleControl, {
297 label: __('Show Icon', 'blockenberg'),
298 checked: a.showIcon,
299 __nextHasNoMarginBottom: true,
300 onChange: function (v) { setAttributes({ showIcon: v }); }
301 }),
302 a.showIcon && el(Fragment, {},
303 el(SelectControl, {
304 label: __('Icon Style', 'blockenberg'),
305 value: a.iconStyle,
306 options: iconStyleOptions,
307 onChange: function (v) { setAttributes({ iconStyle: v }); }
308 }),
309 el(SelectControl, {
310 label: __('Icon Vertical Alignment', 'blockenberg'),
311 value: a.iconPosition,
312 options: iconPositionOptions,
313 onChange: function (v) { setAttributes({ iconPosition: v }); }
314 }),
315 el(RangeControl, {
316 label: __('Icon Size (px)', 'blockenberg'),
317 value: a.iconSize, min: 14, max: 64,
318 onChange: function (v) { setAttributes({ iconSize: v }); }
319 }),
320 el(RangeControl, {
321 label: __('Gap icon → text (px)', 'blockenberg'),
322 value: a.gapIconContent, min: 0, max: 48,
323 onChange: function (v) { setAttributes({ gapIconContent: v }); }
324 })
325 )
326 ),
327
328 // ── Typography ────────────────────────────────────────────────
329 el(PanelBody, { title: __('Typography', 'blockenberg'), initialOpen: false },
330 el(ToggleControl, {
331 label: __('Show Title', 'blockenberg'),
332 checked: a.showTitle,
333 __nextHasNoMarginBottom: true,
334 onChange: function (v) { setAttributes({ showTitle: v }); }
335 }),
336 a.showTitle && el(Fragment, {},
337 el('p', { style: { margin: '4px 0 6px', fontWeight: 600, fontSize: '11px', textTransform: 'uppercase', color: '#888' } },
338 __('Title', 'blockenberg')),
339 el(SelectControl, {
340 label: __('HTML Tag', 'blockenberg'),
341 value: a.titleTag,
342 options: titleTagOptions,
343 onChange: function (v) { setAttributes({ titleTag: v }); }
344 }),
345 el(RangeControl, {
346 label: __('Font Size (px)', 'blockenberg'),
347 value: a.titleSize, min: 11, max: 36,
348 onChange: function (v) { setAttributes({ titleSize: v }); }
349 }),
350 el(SelectControl, {
351 label: __('Font Weight', 'blockenberg'),
352 value: a.titleWeight,
353 options: fontWeightOptions,
354 onChange: function (v) { setAttributes({ titleWeight: parseInt(v, 10) }); }
355 })
356 ),
357 el('hr', {}),
358 el('p', { style: { margin: '4px 0 6px', fontWeight: 600, fontSize: '11px', textTransform: 'uppercase', color: '#888' } },
359 __('Body Text', 'blockenberg')),
360 el(RangeControl, {
361 label: __('Font Size (px)', 'blockenberg'),
362 value: a.bodySize, min: 11, max: 28,
363 onChange: function (v) { setAttributes({ bodySize: v }); }
364 }),
365 el(SelectControl, {
366 label: __('Font Weight', 'blockenberg'),
367 value: a.bodyWeight,
368 options: fontWeightOptions,
369 onChange: function (v) { setAttributes({ bodyWeight: parseInt(v, 10) }); }
370 }),
371 el(RangeControl, {
372 label: __('Line Height', 'blockenberg'),
373 value: a.bodyLH, min: 1, max: 2.5, step: 0.05,
374 onChange: function (v) { setAttributes({ bodyLH: v }); }
375 }),
376 el('hr', {}),
377 el(RangeControl, {
378 label: __('Gap title → body (px)', 'blockenberg'),
379 value: a.gapTitleBody, min: 0, max: 32,
380 onChange: function (v) { setAttributes({ gapTitleBody: v }); }
381 })
382 ),
383
384 // ── Colors ────────────────────────────────────────────────────
385 el(PanelBody, { title: __('Colors', 'blockenberg'), initialOpen: false },
386 el(ToggleControl, {
387 label: __('Override preset colors', 'blockenberg'),
388 checked: a.useCustomColors,
389 __nextHasNoMarginBottom: true,
390 onChange: function (v) { setAttributes({ useCustomColors: v }); }
391 }),
392 a.useCustomColors
393 ? el(Fragment, {},
394 el('p', { style: { margin: '8px 0 6px', fontWeight: 600, fontSize: '11px', textTransform: 'uppercase', color: '#888' } },
395 __('Custom Colors', 'blockenberg')),
396 renderColorControl('customBgColor', __('Background', 'blockenberg'), a.customBgColor, function (c) { setAttributes({ customBgColor: c }); }),
397 renderColorControl('customBorderColor', __('Border / accent', 'blockenberg'), a.customBorderColor, function (c) { setAttributes({ customBorderColor: c }); }),
398 renderColorControl('customIconColor', __('Icon', 'blockenberg'), a.customIconColor, function (c) { setAttributes({ customIconColor: c }); }),
399 renderColorControl('customTitleColor', __('Title', 'blockenberg'), a.customTitleColor, function (c) { setAttributes({ customTitleColor: c }); }),
400 renderColorControl('customTextColor', __('Body Text', 'blockenberg'), a.customTextColor, function (c) { setAttributes({ customTextColor: c }); })
401 )
402 : el('p', { style: { fontSize: '12px', color: '#757575', margin: '8px 0' } },
403 __('Colors are driven by the preset type above. Enable "Override preset colors" to customise.', 'blockenberg'))
404 ),
405
406 // ── Spacing ───────────────────────────────────────────────────
407 el(PanelBody, { title: __('Spacing', 'blockenberg'), initialOpen: false },
408 el(RangeControl, { label: __('Padding Top (px)', 'blockenberg'), value: a.paddingTop, min: 0, max: 80, onChange: function (v) { setAttributes({ paddingTop: v }); } }),
409 el(RangeControl, { label: __('Padding Right (px)', 'blockenberg'), value: a.paddingRight, min: 0, max: 80, onChange: function (v) { setAttributes({ paddingRight: v }); } }),
410 el(RangeControl, { label: __('Padding Bottom (px)', 'blockenberg'), value: a.paddingBottom, min: 0, max: 80, onChange: function (v) { setAttributes({ paddingBottom: v }); } }),
411 el(RangeControl, { label: __('Padding Left (px)', 'blockenberg'), value: a.paddingLeft, min: 0, max: 80, onChange: function (v) { setAttributes({ paddingLeft: v }); } })
412 )
413 );
414
415 // ── Build render elements ─────────────────────────────────────────
416 var iconEl = a.showIcon
417 ? el('span', { className: 'bkbg-al-icon', 'aria-hidden': 'true' },
418 buildIconSVG(a.alertType, a.iconStyle, c.icon, a.iconSize))
419 : null;
420
421 var titleEl = a.showTitle
422 ? el(RichText, {
423 tagName: a.titleTag,
424 className: 'bkbg-al-title',
425 value: a.titleText,
426 onChange: function (v) { setAttributes({ titleText: v }); },
427 placeholder: __('Alert title…', 'blockenberg'),
428 allowedFormats: ['core/bold', 'core/italic', 'core/text-color']
429 })
430 : null;
431
432 var bodyEl = el(RichText, {
433 tagName: 'p',
434 className: 'bkbg-al-body',
435 value: a.bodyText,
436 onChange: function (v) { setAttributes({ bodyText: v }); },
437 placeholder: __('Notice body text…', 'blockenberg'),
438 allowedFormats: ['core/bold', 'core/italic', 'core/text-color', 'core/link']
439 });
440
441 var blockProps = useBlockProps({
442 className: 'bkbg-editor-wrap',
443 'data-block-label': 'Alert'
444 });
445
446 return el('div', blockProps,
447 inspector,
448 el('div', Object.assign(
449 { className: 'bkbg-al-wrap', style: buildWrapStyle(a) },
450 {
451 'data-type': a.alertType,
452 'data-border': a.borderStyle,
453 'data-icon-pos': a.iconPosition
454 }
455 ),
456 iconEl,
457 el('div', { className: 'bkbg-al-content' },
458 titleEl,
459 bodyEl
460 )
461 )
462 );
463 },
464
465 // ── Save ─────────────────────────────────────────────────────────────────
466 save: function (props) {
467 var a = props.attributes;
468 var RichTextContent = wp.blockEditor.RichText.Content;
469 var c = resolveColors(a);
470
471 var iconEl = a.showIcon
472 ? el('span', { className: 'bkbg-al-icon', 'aria-hidden': 'true' },
473 buildIconSVG(a.alertType, a.iconStyle, c.icon, a.iconSize))
474 : null;
475
476 return el('div', Object.assign(
477 { className: 'bkbg-al-wrap', style: buildWrapStyle(a) },
478 {
479 'data-type': a.alertType,
480 'data-border': a.borderStyle,
481 'data-icon-pos': a.iconPosition,
482 role: 'note'
483 }
484 ),
485 iconEl,
486 el('div', { className: 'bkbg-al-content' },
487 a.showTitle && el(RichTextContent, { tagName: a.titleTag, className: 'bkbg-al-title', value: a.titleText }),
488 el(RichTextContent, { tagName: 'p', className: 'bkbg-al-body', value: a.bodyText })
489 )
490 );
491 }
492 });
493 });
494