PluginProbe
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor / 2.0.2
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor v2.0.2
2.0.14 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 / column / index.js

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

326 lines 14.3 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 useEffect = wp.element.useEffect;
4 var __ = wp.i18n.__;
5 var registerBlockType = wp.blocks.registerBlockType;
6 var InspectorControls = wp.blockEditor.InspectorControls;
7 var useBlockProps = wp.blockEditor.useBlockProps;
8 var InnerBlocks = wp.blockEditor.InnerBlocks;
9 var useSelect = wp.data.useSelect;
10 var useDispatch = wp.data.useDispatch;
11 var PanelBody = wp.components.PanelBody;
12 var SelectControl = wp.components.SelectControl;
13 var RangeControl = wp.components.RangeControl;
14 var BaseControl = wp.components.BaseControl;
15 var Button = wp.components.Button;
16
17 // Custom Appender that opens sidebar inserter instead of popover
18 function SidebarInserterAppender(props) {
19 var rootClientId = props.rootClientId;
20
21 // Get the inserter toggle function
22 var insertionPoint = useSelect(function (select) {
23 var blockEditor = select('core/block-editor');
24 var innerBlocks = blockEditor.getBlocks(rootClientId);
25 return {
26 index: innerBlocks.length
27 };
28 }, [rootClientId]);
29
30 function handleClick() {
31 // Toggle the global inserter sidebar (not the popover).
32 try {
33 var editPostDispatch = wp.data.dispatch('core/edit-post');
34 if (editPostDispatch && typeof editPostDispatch.setIsInserterOpened === 'function') {
35 editPostDispatch.setIsInserterOpened(true);
36 }
37 } catch (e) {}
38
39 try {
40 var editSiteDispatch = wp.data.dispatch('core/edit-site');
41 if (editSiteDispatch && typeof editSiteDispatch.setIsInserterOpened === 'function') {
42 editSiteDispatch.setIsInserterOpened(true);
43 }
44 } catch (e) {}
45
46 // Attempt to set an insertion point inside this column.
47 try {
48 var beDispatch = wp.data.dispatch('core/block-editor');
49 if (beDispatch) {
50 if (typeof beDispatch.setInsertionPoint === 'function') {
51 beDispatch.setInsertionPoint(rootClientId, insertionPoint.index);
52 } else if (typeof beDispatch.__unstableSetInsertionPoint === 'function') {
53 try {
54 beDispatch.__unstableSetInsertionPoint({ rootClientId: rootClientId, index: insertionPoint.index });
55 } catch (e2) {
56 beDispatch.__unstableSetInsertionPoint(rootClientId, insertionPoint.index);
57 }
58 }
59 }
60 } catch (e) {}
61 }
62
63 return el(Button, {
64 className: 'bkbg-sidebar-appender block-editor-button-block-appender',
65 onClick: handleClick,
66 label: __('Add block', 'blockenberg')
67 },
68 el('svg', {
69 xmlns: 'http://www.w3.org/2000/svg',
70 viewBox: '0 0 24 24',
71 width: '24',
72 height: '24',
73 'aria-hidden': 'true',
74 focusable: 'false'
75 },
76 el('path', { d: 'M11 12.5V17.5H12.5V12.5H17.5V11H12.5V6H11V11H6V12.5H11Z' })
77 )
78 );
79 }
80
81 // Spacing token scale for inner padding
82 var paddingOptions = [
83 { label: __('None', 'blockenberg'), value: 'none' },
84 { label: __('XS (8px)', 'blockenberg'), value: 'xs' },
85 { label: __('S (16px)', 'blockenberg'), value: 's' },
86 { label: __('M (24px)', 'blockenberg'), value: 'm' },
87 { label: __('L (32px)', 'blockenberg'), value: 'l' },
88 { label: __('XL (48px)', 'blockenberg'), value: 'xl' }
89 ];
90
91 // Column icon
92 var columnIcon = el('svg', {
93 width: 24,
94 height: 24,
95 viewBox: '0 0 24 24',
96 xmlns: 'http://www.w3.org/2000/svg'
97 },
98 el('path', {
99 d: 'M5 4h14v16H5V4zm2 2v12h10V6H7z',
100 fill: 'currentColor'
101 })
102 );
103
104 // Generate unique ID
105 function generateUid() {
106 return 'col-' + Date.now() + '-' + Math.random().toString(36).substr(2, 9);
107 }
108
109 registerBlockType('blockenberg/column', {
110 title: __('Column', 'blockenberg'),
111 icon: columnIcon,
112 category: 'blockenberg',
113 parent: ['blockenberg/row'],
114 description: __('A column container within a row for content.', 'blockenberg'),
115
116 edit: function (props) {
117 var attributes = props.attributes;
118 var setAttributes = props.setAttributes;
119 var clientId = props.clientId;
120 var a = attributes;
121
122 var moveBlockToPosition = useDispatch('core/block-editor').moveBlockToPosition;
123
124 // Generate UID if not set
125 useEffect(function () {
126 if (!a.uid) {
127 setAttributes({ uid: generateUid() });
128 }
129 }, []);
130
131 // Get parent row info (responsive mode + column index)
132 var parentData = useSelect(function (select) {
133 var parents = select('core/block-editor').getBlockParents(clientId);
134 for (var i = parents.length - 1; i >= 0; i--) {
135 var parent = select('core/block-editor').getBlock(parents[i]);
136 if (parent && parent.name === 'blockenberg/row') {
137 var siblings = parent.innerBlocks || [];
138 var colIndex = siblings.findIndex(function (b) { return b.clientId === clientId; });
139 return {
140 rowClientId: parents[i],
141 colIndex: colIndex,
142 colCount: siblings.length,
143 responsiveMode: parent.attributes.responsiveMode || 'desktop',
144 stackOnMobile: parent.attributes.stackOnMobile !== false
145 };
146 }
147 }
148 return { rowClientId: null, colIndex: -1, colCount: 0, responsiveMode: 'desktop', stackOnMobile: true };
149 }, [clientId]);
150
151 var responsiveMode = parentData.responsiveMode;
152 var stackOnMobile = parentData.stackOnMobile;
153
154 function moveSelf(direction) {
155 if (!parentData.rowClientId) return;
156 if (parentData.colIndex < 0) return;
157 var newIndex = direction === 'left' ? parentData.colIndex - 1 : parentData.colIndex + 1;
158 if (newIndex < 0 || newIndex >= parentData.colCount) return;
159 moveBlockToPosition(clientId, parentData.rowClientId, parentData.rowClientId, newIndex);
160 }
161
162 // Get width for current mode with fallback
163 function getWidth(mode) {
164 var widths = a.widths || { desktop: 50, tablet: 50, mobile: 100 };
165 if (mode === 'mobile') {
166 return widths.mobile !== undefined ? widths.mobile :
167 (widths.tablet !== undefined ? widths.tablet :
168 (widths.desktop !== undefined ? widths.desktop : 50));
169 }
170 if (mode === 'tablet') {
171 return widths.tablet !== undefined ? widths.tablet :
172 (widths.desktop !== undefined ? widths.desktop : 50);
173 }
174 return widths.desktop !== undefined ? widths.desktop : 50;
175 }
176
177 var currentWidth = getWidth(responsiveMode);
178 var displayWidth = (responsiveMode === 'mobile' && stackOnMobile) ? 100 : currentWidth;
179
180 // Update width for specific mode
181 function updateWidth(mode, value) {
182 var newWidths = Object.assign({}, a.widths || { desktop: 50, tablet: 50, mobile: 100 });
183 newWidths[mode] = value;
184 setAttributes({ widths: newWidths });
185 }
186
187 var blockProps = useBlockProps({
188 className: [
189 'bkbg-column',
190 'bkbg-column--padding-' + a.paddingInner
191 ].join(' '),
192 style: {
193 '--bkbg-col-desktop': (a.widths && a.widths.desktop || 50) + '%',
194 '--bkbg-col-tablet': (a.widths && a.widths.tablet || a.widths && a.widths.desktop || 50) + '%',
195 '--bkbg-col-mobile': (a.widths && a.widths.mobile || 100) + '%',
196 flexBasis: displayWidth + '%',
197 maxWidth: displayWidth + '%',
198 width: displayWidth + '%'
199 },
200 'data-uid': a.uid
201 });
202
203 // Inspector controls
204 var inspector = el(InspectorControls, {},
205 el(PanelBody, { title: __('Column Settings', 'blockenberg'), initialOpen: true },
206 el(BaseControl, {
207 label: __('Column Widths', 'blockenberg'),
208 help: __('Widths are typically controlled via drag handles on the row. You can fine-tune them here.', 'blockenberg')
209 }),
210 el('div', { className: 'bkbg-column-widths-controls' },
211 el(RangeControl, {
212 label: __('Desktop', 'blockenberg'),
213 value: a.widths && a.widths.desktop || 50,
214 onChange: function (v) { updateWidth('desktop', v); },
215 min: 5,
216 max: 100,
217 step: 0.5,
218 marks: [
219 { value: 25, label: '25%' },
220 { value: 50, label: '50%' },
221 { value: 75, label: '75%' },
222 { value: 100, label: '100%' }
223 ]
224 }),
225 el(RangeControl, {
226 label: __('Tablet', 'blockenberg'),
227 value: a.widths && a.widths.tablet || a.widths && a.widths.desktop || 50,
228 onChange: function (v) { updateWidth('tablet', v); },
229 min: 5,
230 max: 100,
231 step: 0.5
232 }),
233 el(RangeControl, {
234 label: __('Mobile', 'blockenberg'),
235 value: a.widths && a.widths.mobile || 100,
236 onChange: function (v) { updateWidth('mobile', v); },
237 min: 5,
238 max: 100,
239 step: 0.5,
240 help: stackOnMobile ? __('Mobile width is overridden when "Stack on Mobile" is enabled in the row settings.', 'blockenberg') : ''
241 })
242 ),
243 el(SelectControl, {
244 label: __('Inner Padding', 'blockenberg'),
245 value: a.paddingInner,
246 options: paddingOptions,
247 onChange: function (v) { setAttributes({ paddingInner: v }); }
248 })
249 ),
250 el(PanelBody, { title: __('Column Info', 'blockenberg'), initialOpen: false },
251 el('div', { className: 'bkbg-column-info' },
252 el('p', {},
253 el('strong', {}, __('Current Mode:', 'blockenberg')),
254 ' ' + responsiveMode.charAt(0).toUpperCase() + responsiveMode.slice(1)
255 ),
256 el('p', {},
257 el('strong', {}, __('Current Width:', 'blockenberg')),
258 ' ' + Math.round(currentWidth * 10) / 10 + '%'
259 ),
260 el('p', {},
261 el('strong', {}, __('UID:', 'blockenberg')),
262 ' ' + (a.uid || 'N/A')
263 )
264 )
265 )
266 );
267
268 return el('div', blockProps,
269 inspector,
270 // Move controls (hover)
271 parentData.colCount > 1 && el('div', { className: 'bkbg-column__move-actions' },
272 el(Button, {
273 className: 'bkbg-column__move-btn',
274 icon: 'arrow-left-alt2',
275 label: __('Move column left', 'blockenberg'),
276 onClick: function () { moveSelf('left'); },
277 disabled: parentData.colIndex <= 0
278 }),
279 el(Button, {
280 className: 'bkbg-column__move-btn',
281 icon: 'arrow-right-alt2',
282 label: __('Move column right', 'blockenberg'),
283 onClick: function () { moveSelf('right'); },
284 disabled: parentData.colIndex >= parentData.colCount - 1
285 })
286 ),
287 el('div', { className: 'bkbg-column__inner' },
288 el(InnerBlocks, {
289 templateLock: false,
290 renderAppender: function () {
291 return el(SidebarInserterAppender, { rootClientId: clientId });
292 }
293 })
294 ),
295 el('div', { className: 'bkbg-column__width-label' },
296 Math.round(currentWidth) + '%'
297 )
298 );
299 },
300
301 save: function (props) {
302 var a = props.attributes;
303 var widths = a.widths || { desktop: 50, tablet: 50, mobile: 100 };
304
305 var blockProps = useBlockProps.save({
306 className: [
307 'bkbg-column',
308 'bkbg-column--padding-' + a.paddingInner
309 ].join(' '),
310 style: {
311 '--bkbg-col-desktop': widths.desktop + '%',
312 '--bkbg-col-tablet': (widths.tablet || widths.desktop) + '%',
313 '--bkbg-col-mobile': (widths.mobile || 100) + '%'
314 },
315 'data-uid': a.uid
316 });
317
318 return el('div', blockProps,
319 el('div', { className: 'bkbg-column__inner' },
320 el(InnerBlocks.Content)
321 )
322 );
323 }
324 });
325 });
326