PluginProbe
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor / 2.0.13
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor v2.0.13
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.13, at blocks/alert/index.js

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