/**
* Internal dependencies
*/
import isCoreBlockWithExt from '../../utils/is-core-block-with-ext';
import dynamicStylesBYkey from '../../utils/dynamic-styles-by-key';
import ComponentColors from '../../components/colors';
import ComponentSpacings from '../../components/spacings';
import ComponentRadius from '../../components/radius';
import ComponentSchemeWrapper from '../../components/scheme-wrapper';
import ComponentResponsiveWrapper from '../../components/responsive-wrapper';
const {
canvasSchemes,
canvasBreakpoints,
} = window;
/**
* WordPress dependencies
*/
const { __ } = wp.i18n;
const {
addFilter,
} = wp.hooks;
const {
Component,
Fragment,
} = wp.element;
const {
createHigherOrderComponent,
} = wp.compose;
const { InspectorControls } = wp.blockEditor;
const {
PanelBody,
SelectControl,
} = wp.components;
const {
hasBlockSupport,
} = wp.blocks;
const allBorders = {
'borderWidthTop': 'border-top-width',
'borderWidthBottom': 'border-bottom-width',
'borderWidthLeft': 'border-left-width',
'borderWidthRight': 'border-right-width',
};
const allBordersRadius = {
'borderRadiusTopLeft': 'border-top-left-radius',
'borderRadiusTopRight': 'border-top-right-radius',
'borderRadiusBottomLeft': 'border-bottom-left-radius',
'borderRadiusBottomRight': 'border-bottom-right-radius',
};
/**
* Extend block attributes with borders.
*
* @param {Object} blockSettings Original block settings.
* @param {String} name Original block name.
*
* @return {Object} Filtered block settings.
*/
function addAttribute( blockSettings, name ) {
let supports = hasBlockSupport( name, 'canvasBorder', false );
// add support to core blocks
if ( isCoreBlockWithExt( name ) ) {
blockSettings.supports = {
...blockSettings.supports,
canvasBorder: true,
};
supports = true;
}
if ( supports ) {
if ( ! blockSettings.attributes ) {
blockSettings.attributes = {};
}
// style.
if ( ! blockSettings.attributes.borderStyle ) {
blockSettings.attributes.borderStyle = {
type: 'string',
};
}
// color.
Object.keys( canvasSchemes ).forEach( ( scheme ) => {
let suffix = '';
if ( scheme && 'default' !== scheme ) {
suffix = `_${ scheme }`;
}
if ( ! blockSettings.attributes[ `borderColor${ suffix }` ] ) {
blockSettings.attributes[ `borderColor${ suffix }` ] = {
type: 'string',
};
}
} );
// responsive attributes.
Object.keys( canvasBreakpoints ).forEach( ( breakpoint ) => {
let suffix = '';
if ( breakpoint && 'desktop' !== breakpoint ) {
suffix = `_${ breakpoint }`;
}
// width.
Object.keys( allBorders ).forEach( ( spacing ) => {
if ( ! blockSettings.attributes[ spacing + suffix ] ) {
blockSettings.attributes[ spacing + suffix ] = {
type: 'number',
};
}
} );
// link.
if ( ! blockSettings.attributes[ `borderWidthLink${ suffix }` ] ) {
blockSettings.attributes[ `borderWidthLink${ suffix }` ] = {
type: 'boolean',
};
}
// unit.
if ( ! blockSettings.attributes[ `borderWidthUnit${ suffix }` ] ) {
blockSettings.attributes[ `borderWidthUnit${ suffix }` ] = {
type: 'string',
};
}
// radius.
Object.keys( allBordersRadius ).forEach( ( radius ) => {
if ( ! blockSettings.attributes[ radius + suffix ] ) {
blockSettings.attributes[ radius + suffix ] = {
type: 'number',
};
}
} );
// link.
if ( ! blockSettings.attributes[ `borderRadiusLink${ suffix }` ] ) {
blockSettings.attributes[ `borderRadiusLink${ suffix }` ] = {
type: 'boolean',
};
}
// unit.
if ( ! blockSettings.attributes[ `borderRadiusUnit${ suffix }` ] ) {
blockSettings.attributes[ `borderRadiusUnit${ suffix }` ] = {
type: 'string',
};
}
} );
}
return blockSettings;
}
/**
* Override the default edit UI to include a new block inspector control for
* assigning the custom borders if needed.
*
* @param {function|Component} BlockEdit Original component.
*
* @return {string} Wrapped component.
*/
const withInspectorControl = createHigherOrderComponent( ( OriginalComponent ) => {
return class CanvasBordersWrapper extends Component {
constructor() {
super( ...arguments );
this.getCurrentBorderStyles = this.getCurrentBorderStyles.bind( this );
this.getCurrentValue = this.getCurrentValue.bind( this );
}
/**
* Get current border styles for preview purposes.
*
* @returns {String} border styles.
*/
getCurrentBorderStyles() {
const {
attributes,
} = this.props;
const {
canvasClassName,
borderStyle,
} = attributes;
let customStyles = '';
if ( canvasClassName ) {
Object.keys( canvasBreakpoints ).forEach( ( name ) => {
let suffix = '';
let borderRadiusUnit = 'px';
let breakpointStyles = '';
if ( name && name !== 'desktop' ) {
suffix = '_' + name;
}
if ( attributes[ 'borderRadiusUnit' + suffix ] ) {
borderRadiusUnit = attributes[ 'borderRadiusUnit' + suffix ];
}
Object.keys( allBordersRadius ).forEach( ( radius ) => {
if ( typeof attributes[ radius + suffix ] !== 'undefined' ) {
breakpointStyles += `${ allBordersRadius[ radius ] }: ${ attributes[ radius + suffix ] }${ borderRadiusUnit }; `;
}
} );
if ( breakpointStyles ) {
breakpointStyles = `.${ canvasClassName } { ${ breakpointStyles } }`;
if ( suffix ) {
breakpointStyles = `@media (max-width: ${ canvasBreakpoints[ name ].width }px) { ${ breakpointStyles } } `;
}
customStyles += breakpointStyles;
}
} );
}
if ( canvasClassName && borderStyle ) {
let mainStyles = '';
mainStyles = `border-style: ${ borderStyle };`;
mainStyles += `border-width: 0;`;
customStyles += `.${ canvasClassName } { ${ mainStyles } }`;
Object.keys( canvasSchemes ).forEach( ( name ) => {
let rule = '';
let suffix = '';
if ( name && 'default' !== name ) {
suffix = `_${ name }`;
rule = `[data-scheme="${ name }"]`;
}
if ( attributes[ 'borderColor' + suffix ] ) {
mainStyles = `border-color: ${ attributes[ 'borderColor' + suffix ] };`;
customStyles += `${rule} .${ canvasClassName } { ${ mainStyles } }`;
}
} );
Object.keys( canvasBreakpoints ).forEach( ( name ) => {
let suffix = '';
let borderWidthUnit = 'px';
let breakpointStyles = '';
if ( name && name !== 'desktop' ) {
suffix = '_' + name;
}
if ( attributes[ 'borderWidthUnit' + suffix ] ) {
borderWidthUnit = attributes[ 'borderWidthUnit' + suffix ];
}
Object.keys( allBorders ).forEach( ( spacing ) => {
if ( typeof attributes[ spacing + suffix ] !== 'undefined' ) {
breakpointStyles += `${ allBorders[ spacing ] }: ${ attributes[ spacing + suffix ] }${ borderWidthUnit }; `;
}
} );
if ( breakpointStyles ) {
breakpointStyles = `.${ canvasClassName } { ${ breakpointStyles } }`;
if ( suffix ) {
breakpointStyles = `@media (max-width: ${ canvasBreakpoints[ name ].width }px) { ${ breakpointStyles } } `;
}
customStyles += breakpointStyles;
}
} );
}
return customStyles;
}
/**
* Get current value.
*
* @param {String} name - name.
* @param {String} suffix - suffix.
*
* @return {Int}
*/
getCurrentValue( name, suffix = '' ) {
const {
attributes,
} = this.props;
return attributes[ `${ name }${ suffix }` ];
}
render() {
if ( ! hasBlockSupport( this.props.name, 'canvasBorder', false ) ) {
return ;
}
const {
attributes,
setAttributes,
} = this.props;
const {
canvasClassName,
} = attributes;
dynamicStylesBYkey( 'borders', canvasClassName, this.getCurrentBorderStyles() );
// add new borders controls.
return (
{ ( { responsiveSuffix, ComponentResponsiveDropdown } ) => {
return (
{ __( 'Radius' ) }
{
setAttributes( attributes );
} }
/>
);
} }
{
setAttributes( {
borderStyle: val,
} );
} }
/>
{ attributes.borderStyle ? (
{ ( { responsiveSuffix, ComponentResponsiveDropdown } ) => {
return (
{ __( 'Width' ) }
{
setAttributes( attributes );
} }
/>
);
} }
) : '' }
{ attributes.borderStyle ? (
{({ schemeSuffix, ComponentSchemeDropdown }) => {
return (
{ __( 'Color' ) }
{
setAttributes( attributes );
} }
/>
)
}}
) : '' }
);
}
};
}, 'withInspectorControl' );
// Init filters.
addFilter( 'blocks.registerBlockType', 'canvas/borders/additional-attributes', addAttribute );
addFilter( 'editor.BlockEdit', 'canvas/borders/additional-attributes', withInspectorControl );