/** * Gallery Masonry Display Block Settings * Adds masonry layout option to core/gallery block * * @package Brandy\BlockSettings\GalleryMasonryDisplay */ (function () { const { addFilter } = wp.hooks; const { createHigherOrderComponent } = wp.compose; const { Fragment, useEffect } = wp.element; const { InspectorControls } = wp.blockEditor; const { ToggleControl, PanelBody } = wp.components; const { __ } = wp.i18n; /** * Check if block is a gallery block */ function isGalleryBlock(name) { return name === "core/gallery"; } /** * Add custom attributes to gallery block */ function addGalleryMasonryAttributes(settings) { if (!settings.attributes || !isGalleryBlock(settings.name)) { return settings; } settings.attributes = Object.assign(settings.attributes, { masonryDisplay: { type: "boolean", default: false, }, }); return settings; } addFilter( "blocks.registerBlockType", "brandy-blocks/gallery-masonry-attribute", addGalleryMasonryAttributes ); /** * Add inspector controls for masonry display setting */ const GalleryMasonryControls = createHigherOrderComponent((BlockEdit) => { return (props) => { const { isSelected, attributes, setAttributes, name, clientId } = props; if (!isGalleryBlock(name)) { return React.createElement(BlockEdit, props); } // Update masonry columns in editor when attribute changes useEffect(() => { if (!attributes?.masonryDisplay) return; const columns = attributes.columns || 3; // Find and update gallery in editor iframe const updateMasonryColumns = () => { const editorFrame = document.querySelector('iframe[name="editor-canvas"]') || document.querySelector("iframe.editor-canvas__iframe") || document.querySelector('iframe[title="Editor canvas"]'); if (!editorFrame?.contentDocument) return; try { const galleries = editorFrame.contentDocument.querySelectorAll( `[data-block="${clientId}"], .wp-block-gallery.has-masonry-display` ); galleries.forEach((gallery) => { if (gallery.classList.contains("has-masonry-display")) { gallery.setAttribute("data-masonry-columns", columns); gallery.style.setProperty("--masonry-columns", columns); } }); } catch (e) { // Cross-origin or other error - ignore } }; updateMasonryColumns(); const timeoutId = setTimeout(updateMasonryColumns, 100); return () => clearTimeout(timeoutId); }, [attributes.columns, attributes.masonryDisplay, clientId]); return React.createElement( Fragment, null, React.createElement(BlockEdit, props), isSelected && React.createElement( InspectorControls, null, React.createElement( PanelBody, { title: __("Masonry Layout", "brandy"), initialOpen: false, }, React.createElement(ToggleControl, { label: __("Enable Masonry Display", "brandy"), help: __( "Display gallery images in a masonry layout (Pinterest-style grid).", "brandy" ), checked: attributes?.masonryDisplay ?? false, onChange: (value) => setAttributes({ masonryDisplay: value }), }) ) ) ); }; }, "GalleryMasonryControls"); addFilter( "editor.BlockEdit", "brandy-blocks/gallery-masonry-controls", GalleryMasonryControls ); /** * Apply masonry class to block wrapper in editor */ addFilter( "editor.BlockListBlock", "brandy-blocks/gallery-masonry-block-wrapper", function (BlockListBlock) { return function (props) { if (isGalleryBlock(props.name) && props.attributes?.masonryDisplay) { const columns = props.attributes.columns || 3; props.wrapperProps = { ...props.wrapperProps, className: ((props.wrapperProps?.className || "") + " has-masonry-display").trim(), "data-masonry-columns": columns, style: { ...props.wrapperProps?.style, "--masonry-columns": columns, }, }; } return React.createElement(BlockListBlock, props); }; } ); })();