woocommerce/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/edit.tsx

196 lines
4.8 KiB
TypeScript

/* eslint-disable jsdoc/check-alignment */
/**
* External dependencies
*/
import {
useBlockProps,
InnerBlocks,
InspectorControls,
} from '@wordpress/block-editor';
import { EditorProvider } from '@woocommerce/base-context';
import { isFeaturePluginBuild } from '@woocommerce/block-settings';
import type { TemplateArray } from '@wordpress/blocks';
import { useEffect } from '@wordpress/element';
import type { FocusEvent, ReactElement } from 'react';
import { __ } from '@wordpress/i18n';
import {
PanelBody,
// eslint-disable-next-line @wordpress/no-unsafe-wp-apis
__experimentalUnitControl as UnitControl,
} from '@wordpress/components';
/**
* Internal dependencies
*/
import { useForcedLayout } from '../../cart-checkout-shared';
import { MiniCartInnerBlocksStyle } from './inner-blocks-style';
import './editor.scss';
import { attributes as defaultAttributes } from './attributes';
// Array of allowed block names.
const ALLOWED_BLOCKS = [
'woocommerce/filled-mini-cart-contents-block',
'woocommerce/empty-mini-cart-contents-block',
];
const MIN_WIDTH = 300;
interface Props {
clientId: string;
attributes: Record< string, unknown >;
setAttributes: ( attributes: Record< string, unknown > ) => void;
}
const Edit = ( {
clientId,
attributes,
setAttributes,
}: Props ): ReactElement => {
const { currentView, width } = attributes;
const blockProps = useBlockProps( {
/**
* This is a workaround for the Site Editor to calculate the
* correct height of the Mini-Cart template part on the first load.
*
* @see https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/5825
*/
style: {
minHeight: '100vh',
width,
},
} );
const defaultTemplate = [
[ 'woocommerce/filled-mini-cart-contents-block', {}, [] ],
[ 'woocommerce/empty-mini-cart-contents-block', {}, [] ],
] as TemplateArray;
useForcedLayout( {
clientId,
registeredBlocks: ALLOWED_BLOCKS,
defaultTemplate,
} );
/**
* This is a workaround for the Site Editor to set the correct
* background color of the Mini-Cart Contents block base on
* the main background color set by the theme.
*/
useEffect( () => {
const canvasEl = document.querySelector(
'.edit-site-visual-editor__editor-canvas'
);
if ( ! ( canvasEl instanceof HTMLIFrameElement ) ) {
return;
}
const canvas =
canvasEl.contentDocument || canvasEl.contentWindow?.document;
if ( ! canvas ) {
return;
}
if ( canvas.getElementById( 'mini-cart-contents-background-color' ) ) {
return;
}
const styles = canvas.querySelectorAll( 'style' );
const [ cssRule ] = Array.from( styles )
.map( ( style ) => Array.from( style.sheet?.cssRules || [] ) )
.flatMap( ( style ) => style )
.filter( Boolean )
.filter(
( rule ) =>
rule.selectorText === '.editor-styles-wrapper' &&
rule.style.backgroundColor
);
if ( ! cssRule ) {
return;
}
const backgroundColor = cssRule.style.backgroundColor;
if ( ! backgroundColor ) {
return;
}
const style = document.createElement( 'style' );
style.id = 'mini-cart-contents-background-color';
style.appendChild(
document.createTextNode(
`:where(.wp-block-woocommerce-mini-cart-contents) {
background-color: ${ backgroundColor };
}`
)
);
const body = canvas.querySelector( '.editor-styles-wrapper' );
if ( ! body ) {
return;
}
body.appendChild( style );
}, [] );
return (
<>
{ isFeaturePluginBuild() && (
<InspectorControls key="inspector">
<PanelBody
title={ __(
'Dimensions',
'woo-gutenberg-products-block'
) }
initialOpen
>
<UnitControl
onChange={ ( value ) => {
setAttributes( { width: value } );
} }
onBlur={ ( e: FocusEvent< HTMLInputElement > ) => {
if ( e.target.value === '' ) {
setAttributes( {
width: defaultAttributes.width.default,
} );
} else if (
Number( e.target.value ) < MIN_WIDTH
) {
setAttributes( {
width: MIN_WIDTH + 'px',
} );
}
} }
value={ width }
units={ [
{
value: 'px',
label: 'px',
default: defaultAttributes.width.default,
},
] }
/>
</PanelBody>
</InspectorControls>
) }
<div
className="wc-block-components-drawer__screen-overlay"
aria-hidden="true"
></div>
<div className="wc-block-editor-mini-cart-contents__wrapper">
<div { ...blockProps }>
<EditorProvider currentView={ currentView }>
<InnerBlocks
allowedBlocks={ ALLOWED_BLOCKS }
template={ defaultTemplate }
templateLock={ false }
/>
</EditorProvider>
<MiniCartInnerBlocksStyle style={ blockProps.style } />
</div>
</div>
</>
);
};
export default Edit;
export const Save = (): JSX.Element => {
return (
<div { ...useBlockProps.save() }>
<InnerBlocks.Content />
</div>
);
};