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

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

250 lines 16.1 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 PanelBody = wp.components.PanelBody;
10 var ToggleControl = wp.components.ToggleControl;
11 var RangeControl = wp.components.RangeControl;
12 var SelectControl = wp.components.SelectControl;
13 var TextControl = wp.components.TextControl;
14 var ColorPicker = wp.components.ColorPicker;
15 var Popover = wp.components.Popover;
16
17 function getTypographyControl() {
18 return (typeof window.bkbgTypographyControl !== 'undefined') ? window.bkbgTypographyControl : null;
19 }
20 function getTypoCssVars() {
21 return (typeof window.bkbgTypoCssVars !== 'undefined') ? window.bkbgTypoCssVars : function () { return {}; };
22 }
23 function _tv(typoObj, prefix) { return getTypoCssVars()(typoObj || {}, prefix); }
24
25 function renderColorControl(key, label, value, onChange, openKey, setOpenKey) {
26 var isOpen = openKey === key;
27 return el('div', { key: key, style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '4px 0', gap: '8px' } },
28 el('span', { style: { fontSize: '12px', color: '#1e1e1e', flex: 1 } }, label),
29 el('div', { style: { position: 'relative', flexShrink: 0 } },
30 el('button', { type: 'button', title: value || 'default', onClick: function () { setOpenKey(isOpen ? null : key); }, style: { width: '28px', height: '28px', borderRadius: '4px', border: isOpen ? '2px solid #007cba' : '2px solid #ddd', cursor: 'pointer', padding: 0, background: value || '#cccccc' } }),
31 isOpen && el(Popover, { position: 'bottom left', onClose: function () { setOpenKey(null); } },
32 el('div', { style: { padding: '8px' } }, el(ColorPicker, { color: value, enableAlpha: true, onChange: onChange }))
33 )
34 )
35 );
36 }
37
38 function buildWrapStyle(a) {
39 return Object.assign({
40 '--bkbg-cf-bg' : a.bgColor,
41 '--bkbg-cf-label-color' : a.labelColor,
42 '--bkbg-cf-field-bg' : a.fieldBg,
43 '--bkbg-cf-field-border': a.fieldBorderColor,
44 '--bkbg-cf-field-focus' : a.fieldFocusColor,
45 '--bkbg-cf-btn-bg' : a.btnBg,
46 '--bkbg-cf-btn-color' : a.btnColor,
47 '--bkbg-cf-radius' : a.fieldRadius + 'px',
48 '--bkbg-cf-btn-radius' : a.btnRadius + 'px',
49 '--bkbg-cf-pad' : a.fieldPadding + 'px',
50 '--bkbg-cf-label-sz' : a.labelSize + 'px',
51 '--bkbg-cf-field-sz' : a.fieldSize + 'px',
52 maxWidth: a.maxWidth + 'px',
53 width: '100%'
54 }, _tv(a.typoLabel, '--bkcf-label-'), _tv(a.typoButton, '--bkcf-btn-'));
55 }
56
57 /* simple field preview */
58 function previewField(label, placeholder, type) {
59 return el('div', { className: 'bkbg-cf-field-group' },
60 el('label', { className: 'bkbg-cf-label' }, label),
61 type === 'textarea'
62 ? el('textarea', { className: 'bkbg-cf-field bkbg-cf-textarea', placeholder: placeholder, rows: 5, readOnly: true })
63 : el('input', { className: 'bkbg-cf-field', type: type || 'text', placeholder: placeholder, readOnly: true })
64 );
65 }
66
67 registerBlockType('blockenberg/contact-form', {
68 title: __('Contact Form', 'blockenberg'),
69 icon: 'email-alt',
70 category: 'bkbg-business',
71 description: __('A styled contact form that sends email via WordPress — no plugin needed.', 'blockenberg'),
72
73 edit: function (props) {
74 var a = props.attributes;
75 var setAttributes = props.setAttributes;
76
77 var openColorState = useState(null);
78 var openColorKey = openColorState[0];
79 var setOpenColorKey = openColorState[1];
80
81 function cc(key, label, attrKey) {
82 return renderColorControl(key, label, a[attrKey], function (val) {
83 var upd = {}; upd[attrKey] = val; setAttributes(upd);
84 }, openColorKey, setOpenColorKey);
85 }
86
87 function sa(obj) { setAttributes(obj); }
88
89 var blockProps = useBlockProps({ className: 'bkbg-cf-wrapper', style: buildWrapStyle(a) });
90
91 var inspector = el(InspectorControls, {},
92 el(PanelBody, { title: __('Fields', 'blockenberg'), initialOpen: true },
93 el(ToggleControl, { label: __('Name Field', 'blockenberg'), checked: a.showName, onChange: function (v) { sa({ showName: v }); } }),
94 el(ToggleControl, { label: __('Email Field', 'blockenberg'), checked: a.showEmail, onChange: function (v) { sa({ showEmail: v }); } }),
95 el(ToggleControl, { label: __('Phone Field', 'blockenberg'), checked: a.showPhone, onChange: function (v) { sa({ showPhone: v }); } }),
96 el(ToggleControl, { label: __('Message Field', 'blockenberg'), checked: a.showMessage, onChange: function (v) { sa({ showMessage: v }); } }),
97 el(ToggleControl, { label: __('GDPR Checkbox', 'blockenberg'), checked: a.showGdpr, onChange: function (v) { sa({ showGdpr: v }); } })
98 ),
99
100 el(PanelBody, { title: __('Labels & Placeholders', 'blockenberg'), initialOpen: false },
101 a.showName && el(Fragment, {},
102 el(TextControl, { label: __('Name Label', 'blockenberg'), value: a.labelName, onChange: function (v) { sa({ labelName: v }); } }),
103 el(TextControl, { label: __('Name Placeholder', 'blockenberg'), value: a.placeholderName, onChange: function (v) { sa({ placeholderName: v }); } })
104 ),
105 a.showEmail && el(Fragment, {},
106 el(TextControl, { label: __('Email Label', 'blockenberg'), value: a.labelEmail, onChange: function (v) { sa({ labelEmail: v }); } }),
107 el(TextControl, { label: __('Email Placeholder', 'blockenberg'), value: a.placeholderEmail, onChange: function (v) { sa({ placeholderEmail: v }); } })
108 ),
109 a.showPhone && el(Fragment, {},
110 el(TextControl, { label: __('Phone Label', 'blockenberg'), value: a.labelPhone, onChange: function (v) { sa({ labelPhone: v }); } }),
111 el(TextControl, { label: __('Phone Placeholder', 'blockenberg'), value: a.placeholderPhone, onChange: function (v) { sa({ placeholderPhone: v }); } })
112 ),
113 a.showMessage && el(Fragment, {},
114 el(TextControl, { label: __('Message Label', 'blockenberg'), value: a.labelMessage, onChange: function (v) { sa({ labelMessage: v }); } }),
115 el(TextControl, { label: __('Message Placeholder', 'blockenberg'), value: a.placeholderMessage, onChange: function (v) { sa({ placeholderMessage: v }); } })
116 ),
117 a.showGdpr && el(TextControl, { label: __('GDPR Label', 'blockenberg'), value: a.labelGdpr, onChange: function (v) { sa({ labelGdpr: v }); } })
118 ),
119
120 el(PanelBody, { title: __('Email Settings', 'blockenberg'), initialOpen: false },
121 el(TextControl, { label: __('Submit Button Label', 'blockenberg'), value: a.submitLabel, onChange: function (v) { sa({ submitLabel: v }); } }),
122 el(TextControl, { label: __('Recipient Email (blank = admin)', 'blockenberg'), value: a.recipientEmail, onChange: function (v) { sa({ recipientEmail: v }); }, type: 'email', help: __('Leave blank to use the WordPress admin email.', 'blockenberg') }),
123 el(TextControl, { label: __('Email Subject', 'blockenberg'), value: a.emailSubject, onChange: function (v) { sa({ emailSubject: v }); } }),
124 el(TextControl, { label: __('Success Message', 'blockenberg'), value: a.successMessage, onChange: function (v) { sa({ successMessage: v }); } }),
125 el(TextControl, { label: __('Error Message', 'blockenberg'), value: a.errorMessage, onChange: function (v) { sa({ errorMessage: v }); } })
126 ),
127
128 el(PanelBody, { title: __('Style & Layout', 'blockenberg'), initialOpen: false },
129 el(RangeControl, { label: __('Max Width (px)', 'blockenberg'), value: a.maxWidth, min: 300, max: 1200, onChange: function (v) { sa({ maxWidth: v }); } }),
130 el(RangeControl, { label: __('Field Padding (px)', 'blockenberg'), value: a.fieldPadding, min: 6, max: 24, onChange: function (v) { sa({ fieldPadding: v }); } }),
131 el(RangeControl, { label: __('Field Border Radius (px)', 'blockenberg'), value: a.fieldRadius, min: 0, max: 24, onChange: function (v) { sa({ fieldRadius: v }); } }),
132 el(RangeControl, { label: __('Button Border Radius (px)', 'blockenberg'), value: a.btnRadius, min: 0, max: 40, onChange: function (v) { sa({ btnRadius: v }); } }),
133 el(SelectControl, {
134 label: __('Button Style', 'blockenberg'), value: a.btnStyle,
135 options: [{ label: 'Primary (solid)', value: 'primary' }, { label: 'Outline', value: 'outline' }, { label: 'Full Width', value: 'full' }],
136 onChange: function (v) { sa({ btnStyle: v }); }
137 }),
138 cc('bgColor', __('Form Background', 'blockenberg'), 'bgColor'),
139 cc('labelColor', __('Label Color', 'blockenberg'), 'labelColor'),
140 cc('fieldBg', __('Field Background', 'blockenberg'), 'fieldBg'),
141 cc('fieldBorderColor', __('Field Border Color', 'blockenberg'), 'fieldBorderColor'),
142 cc('fieldFocusColor', __('Field Focus Color', 'blockenberg'), 'fieldFocusColor'),
143 cc('btnBg', __('Button Background', 'blockenberg'), 'btnBg'),
144 cc('btnColor', __('Button Text Color', 'blockenberg'), 'btnColor')
145 ),
146 el( PanelBody, { title: __( 'Typography', 'blockenberg' ), initialOpen: false },
147 (function () {
148 var TC = getTypographyControl();
149 if (!TC) return el('p', { style: { color: '#999', fontSize: '12px', padding: '8px 0' } }, __('Typography control loading…', 'blockenberg'));
150 return el(Fragment, {},
151 el(TC, {
152 label: __('Labels', 'blockenberg'),
153 value: a.typoLabel || {},
154 onChange: function (v) { sa({ typoLabel: v }); }
155 }),
156 el(TC, {
157 label: __('Submit Button', 'blockenberg'),
158 value: a.typoButton || {},
159 onChange: function (v) { sa({ typoButton: v }); }
160 })
161 );
162 })()
163 )
164 );
165
166 /* ── Editor Preview ─────────────────────────────────────────── */
167 return el(Fragment, {},
168 inspector,
169 el('div', blockProps,
170 el('form', { className: 'bkbg-cf-form', onSubmit: function (e) { e.preventDefault(); } },
171 a.showName && previewField(a.labelName, a.placeholderName, 'text'),
172 a.showEmail && previewField(a.labelEmail, a.placeholderEmail, 'email'),
173 a.showPhone && previewField(a.labelPhone, a.placeholderPhone, 'tel'),
174 a.showMessage && previewField(a.labelMessage, a.placeholderMessage, 'textarea'),
175 a.showGdpr && el('div', { className: 'bkbg-cf-field-group bkbg-cf-gdpr' },
176 el('label', { className: 'bkbg-cf-gdpr-label' },
177 el('input', { type: 'checkbox', readOnly: true }),
178 el('span', {}, a.labelGdpr)
179 )
180 ),
181 el('button', { className: 'bkbg-cf-submit bkbg-cf-btn-' + a.btnStyle, type: 'button' }, a.submitLabel)
182 )
183 )
184 );
185 },
186
187 save: function (props) {
188 var a = props.attributes;
189
190 function fld(label, name, type, placeholder, required) {
191 if (type === 'textarea') {
192 return el('div', { className: 'bkbg-cf-field-group' },
193 el('label', { className: 'bkbg-cf-label', htmlFor: 'bkbg-cf-' + name }, label),
194 el('textarea', { className: 'bkbg-cf-field bkbg-cf-textarea', id: 'bkbg-cf-' + name, name: name, placeholder: placeholder, rows: 5, required: required || undefined })
195 );
196 }
197 return el('div', { className: 'bkbg-cf-field-group' },
198 el('label', { className: 'bkbg-cf-label', htmlFor: 'bkbg-cf-' + name }, label),
199 el('input', { className: 'bkbg-cf-field', id: 'bkbg-cf-' + name, type: type, name: name, placeholder: placeholder, required: required || undefined })
200 );
201 }
202
203 var saveProps = wp.blockEditor.useBlockProps.save({
204 className: 'bkbg-cf-wrapper',
205 style: Object.assign({
206 '--bkbg-cf-bg' : a.bgColor,
207 '--bkbg-cf-label-color' : a.labelColor,
208 '--bkbg-cf-field-bg' : a.fieldBg,
209 '--bkbg-cf-field-border': a.fieldBorderColor,
210 '--bkbg-cf-field-focus' : a.fieldFocusColor,
211 '--bkbg-cf-btn-bg' : a.btnBg,
212 '--bkbg-cf-btn-color' : a.btnColor,
213 '--bkbg-cf-radius' : a.fieldRadius + 'px',
214 '--bkbg-cf-btn-radius' : a.btnRadius + 'px',
215 '--bkbg-cf-pad' : a.fieldPadding + 'px',
216 '--bkbg-cf-label-sz' : a.labelSize + 'px',
217 '--bkbg-cf-field-sz' : a.fieldSize + 'px',
218 maxWidth: a.maxWidth + 'px',
219 width: '100%'
220 }, _tv(a.typoLabel, '--bkcf-label-'), _tv(a.typoButton, '--bkcf-btn-')),
221 'data-recipient': a.recipientEmail,
222 'data-subject' : a.emailSubject,
223 'data-success' : a.successMessage,
224 'data-error' : a.errorMessage
225 });
226
227 return el('div', saveProps,
228 el('form', { className: 'bkbg-cf-form', noValidate: true },
229 a.showName && fld(a.labelName, 'name', 'text', a.placeholderName, true),
230 a.showEmail && fld(a.labelEmail, 'email', 'email', a.placeholderEmail, true),
231 a.showPhone && fld(a.labelPhone, 'phone', 'tel', a.placeholderPhone, false),
232 a.showMessage && fld(a.labelMessage, 'message', 'textarea', a.placeholderMessage, true),
233 // Honeypot
234 el('div', { className: 'bkbg-cf-hp', 'aria-hidden': 'true', style: { display: 'none' } },
235 el('input', { type: 'text', name: 'website', tabIndex: '-1', autoComplete: 'off' })
236 ),
237 a.showGdpr && el('div', { className: 'bkbg-cf-field-group bkbg-cf-gdpr' },
238 el('label', { className: 'bkbg-cf-gdpr-label' },
239 el('input', { type: 'checkbox', name: 'gdpr', required: true }),
240 el('span', {}, a.labelGdpr)
241 )
242 ),
243 el('div', { className: 'bkbg-cf-status', role: 'status', 'aria-live': 'polite' }),
244 el('button', { className: 'bkbg-cf-submit bkbg-cf-btn-' + a.btnStyle, type: 'submit' }, a.submitLabel)
245 )
246 );
247 }
248 });
249 }() );
250