Fix CYS pattern thumbnail size (#41126)

* Fix pattern thumbnail size

* Add changelog and doc

* Remove unused import
This commit is contained in:
Chi-Hsuan Huang 2023-11-01 19:03:04 +08:00 committed by GitHub
parent 23e8324163
commit f7012536cc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 394 additions and 181 deletions

View File

@ -6,7 +6,7 @@
* External dependencies
*/
import { useResizeObserver, pure, useRefEffect } from '@wordpress/compose';
import { useContext } from '@wordpress/element';
import { useContext, useMemo, useState } from '@wordpress/element';
import { Disabled } from '@wordpress/components';
import {
__unstableEditorStyles as EditorStyles,
@ -36,6 +36,7 @@ const { Provider: DisabledProvider } = Disabled.Context;
let MemoizedBlockList: typeof BlockList | undefined;
const { useGlobalSetting } = unlock( blockEditorPrivateApis );
const MAX_HEIGHT = 2000;
export type ScaledBlockPreviewProps = {
viewportWidth?: number;
@ -49,6 +50,8 @@ export type ScaledBlockPreviewProps = {
onClickNavigationItem: ( event: MouseEvent ) => void;
isNavigable?: boolean;
isScrollable?: boolean;
autoScale?: boolean;
setLogoBlockContext?: boolean;
};
function ScaledBlockPreview( {
@ -59,12 +62,16 @@ function ScaledBlockPreview( {
onClickNavigationItem,
isNavigable = false,
isScrollable = true,
autoScale = true,
setLogoBlockContext = false,
}: ScaledBlockPreviewProps ) {
const [ contentHeight, setContentHeight ] = useState< number | null >(
null
);
const { setLogoBlockIds } = useContext( LogoBlockContext );
const [ fontFamilies ] = useGlobalSetting(
'typography.fontFamilies.theme'
) as [ FontFamily[] ];
const externalFontFamilies = fontFamilies.filter(
( { slug } ) => slug !== SYSTEM_FONT_SLUG
);
@ -73,163 +80,213 @@ function ScaledBlockPreview( {
viewportWidth = containerWidth;
}
// Avoid scrollbars for pattern previews.
const editorStyles = useMemo( () => {
if ( ! isScrollable && settings.styles ) {
return [
...settings.styles,
{
css: 'body{height:auto;overflow:hidden;border:none;padding:0;}',
__unstableType: 'presets',
},
];
}
return settings.styles;
}, [ settings.styles, isScrollable ] );
const scale = containerWidth / viewportWidth;
const aspectRatio = contentHeight
? containerWidth / ( contentHeight * scale )
: 0;
// Initialize on render instead of module top level, to avoid circular dependency issues.
MemoizedBlockList = MemoizedBlockList || pure( BlockList );
const updateIframeContent = ( bodyElement: HTMLBodyElement ) => {
let navigationContainers: NodeListOf< HTMLDivElement >;
let siteTitles: NodeListOf< HTMLAnchorElement >;
const onMouseMove = ( event: MouseEvent ) => {
event.stopImmediatePropagation();
};
const onClickNavigation = ( event: MouseEvent ) => {
event.preventDefault();
onClickNavigationItem( event );
};
const possiblyRemoveAllListeners = () => {
bodyElement.removeEventListener( 'mousemove', onMouseMove, false );
if ( navigationContainers ) {
navigationContainers.forEach( ( element ) => {
element.removeEventListener( 'click', onClickNavigation );
} );
}
if ( siteTitles ) {
siteTitles.forEach( ( element ) => {
element.removeEventListener( 'click', onClickNavigation );
} );
}
};
const enableNavigation = () => {
// Remove contenteditable and inert attributes from editable elements so that users can click on navigation links.
bodyElement
.querySelectorAll(
'.block-editor-rich-text__editable[contenteditable="true"]'
)
.forEach( ( element ) => {
element.removeAttribute( 'contenteditable' );
} );
bodyElement
.querySelectorAll( '*[inert="true"]' )
.forEach( ( element ) => {
element.removeAttribute( 'inert' );
} );
possiblyRemoveAllListeners();
navigationContainers = bodyElement.querySelectorAll(
'.wp-block-navigation__container'
);
navigationContainers.forEach( ( element ) => {
element.addEventListener( 'click', onClickNavigation, true );
} );
siteTitles = bodyElement.querySelectorAll(
'.wp-block-site-title a'
);
siteTitles.forEach( ( element ) => {
element.addEventListener( 'click', onClickNavigation, true );
} );
};
const findAndSetLogoBlock = () => {
// Get the current logo block client ID from DOM and set it in the logo block context. This is used for the logo settings. See: ./sidebar/sidebar-navigation-screen-logo.tsx
// Ideally, we should be able to get the logo block client ID from the block editor store but it is not available.
// We should update this code once the there is a selector in the block editor store that can be used to get the logo block client ID.
const siteLogos = bodyElement.querySelectorAll(
'.wp-block-site-logo'
);
const logoBlockIds = Array.from( siteLogos )
.map( ( siteLogo ) => {
return siteLogo.getAttribute( 'data-block' );
} )
.filter( Boolean ) as string[];
setLogoBlockIds( logoBlockIds );
};
const onChange = () => {
if ( autoScale ) {
const rootContainer =
bodyElement.querySelector( '.is-root-container' );
setContentHeight(
rootContainer ? rootContainer.clientHeight : null
);
}
if ( isNavigable ) {
enableNavigation();
}
if ( setLogoBlockContext ) {
findAndSetLogoBlock();
}
};
// Stop mousemove event listener to disable block tool insertion feature.
bodyElement.addEventListener( 'mousemove', onMouseMove, true );
const observer = new window.MutationObserver( onChange );
observer.observe( bodyElement, {
attributes: true,
characterData: false,
subtree: true,
childList: true,
} );
return () => {
observer.disconnect();
possiblyRemoveAllListeners();
if ( setLogoBlockContext ) {
setLogoBlockIds( [] );
}
};
};
return (
<DisabledProvider value={ true }>
<Iframe
aria-hidden
scrolling={ isScrollable ? 'yes' : 'no' }
tabIndex={ -1 }
readonly={ ! isNavigable }
contentRef={ useRefEffect(
( bodyElement: HTMLBodyElement ) => {
const {
ownerDocument: { documentElement },
} = bodyElement;
documentElement.classList.add(
'block-editor-block-preview__content-iframe'
);
documentElement.style.position = 'absolute';
documentElement.style.width = '100%';
// Necessary for contentResizeListener to work.
bodyElement.style.boxSizing = 'border-box';
bodyElement.style.position = 'absolute';
bodyElement.style.width = '100%';
let navigationContainers: NodeListOf< HTMLDivElement >;
let siteTitles: NodeListOf< HTMLAnchorElement >;
const onClickNavigation = ( event: MouseEvent ) => {
event.preventDefault();
onClickNavigationItem( event );
};
const onMouseMove = ( event: MouseEvent ) => {
event.stopImmediatePropagation();
};
const possiblyRemoveAllListeners = () => {
bodyElement.removeEventListener(
'mousemove',
onMouseMove,
false
);
if ( navigationContainers ) {
navigationContainers.forEach( ( element ) => {
element.removeEventListener(
'click',
onClickNavigation
);
} );
}
if ( siteTitles ) {
siteTitles.forEach( ( element ) => {
element.removeEventListener(
'click',
onClickNavigation
);
} );
}
};
const enableNavigation = () => {
// Remove contenteditable and inert attributes from editable elements so that users can click on navigation links.
bodyElement
.querySelectorAll(
'.block-editor-rich-text__editable[contenteditable="true"]'
)
.forEach( ( element ) => {
element.removeAttribute(
'contenteditable'
);
} );
bodyElement
.querySelectorAll( '*[inert="true"]' )
.forEach( ( element ) => {
element.removeAttribute( 'inert' );
} );
possiblyRemoveAllListeners();
navigationContainers = bodyElement.querySelectorAll(
'.wp-block-navigation__container'
);
navigationContainers.forEach( ( element ) => {
element.addEventListener(
'click',
onClickNavigation,
true
);
} );
siteTitles = bodyElement.querySelectorAll(
'.wp-block-site-title a'
);
siteTitles.forEach( ( element ) => {
element.addEventListener(
'click',
onClickNavigation,
true
);
} );
};
const onChange = () => {
// Get the current logo block client ID from DOM and set it in the logo block context. This is used for the logo settings. See: ./sidebar/sidebar-navigation-screen-logo.tsx
// Ideally, we should be able to get the logo block client ID from the block editor store but it is not available.
// We should update this code once the there is a selector in the block editor store that can be used to get the logo block client ID.
const siteLogos = bodyElement.querySelectorAll(
'.wp-block-site-logo'
);
const logoBlockIds = Array.from( siteLogos )
.map( ( siteLogo ) => {
return siteLogo.getAttribute(
'data-block'
);
} )
.filter( Boolean ) as string[];
setLogoBlockIds( logoBlockIds );
if ( isNavigable ) {
enableNavigation();
}
};
// Stop mousemove event listener to disable block tool insertion feature.
bodyElement.addEventListener(
'mousemove',
onMouseMove,
true
);
const observer = new window.MutationObserver(
onChange
);
observer.observe( bodyElement, {
attributes: true,
characterData: false,
subtree: true,
childList: true,
} );
return () => {
observer.disconnect();
possiblyRemoveAllListeners();
setLogoBlockIds( [] );
};
},
[ isNavigable ]
) }
<div
className="block-editor-block-preview__content"
style={
autoScale
? {
transform: `scale(${ scale })`,
// Using width + aspect-ratio instead of height here triggers browsers' native
// handling of scrollbar's visibility. It prevents the flickering issue seen
// in https://github.com/WordPress/gutenberg/issues/52027.
// See https://github.com/WordPress/gutenberg/pull/52921 for more info.
aspectRatio,
maxHeight:
contentHeight !== null &&
contentHeight > MAX_HEIGHT
? MAX_HEIGHT * scale
: undefined,
}
: {}
}
>
<EditorStyles styles={ settings.styles } />
<style>
{ `
<Iframe
aria-hidden
scrolling={ isScrollable ? 'yes' : 'no' }
tabIndex={ -1 }
readonly={ ! isNavigable }
style={
autoScale
? {
position: 'absolute',
width: viewportWidth,
height: contentHeight,
pointerEvents: 'none',
// This is a catch-all max-height for patterns.
// See: https://github.com/WordPress/gutenberg/pull/38175.
maxHeight: MAX_HEIGHT,
}
: {}
}
contentRef={ useRefEffect(
( bodyElement: HTMLBodyElement ) => {
const {
ownerDocument: { documentElement },
} = bodyElement;
documentElement.classList.add(
'block-editor-block-preview__content-iframe'
);
documentElement.style.position = 'absolute';
documentElement.style.width = '100%';
// Necessary for contentResizeListener to work.
bodyElement.style.boxSizing = 'border-box';
bodyElement.style.position = 'absolute';
bodyElement.style.width = '100%';
const cleanup = updateIframeContent( bodyElement );
return () => {
cleanup();
setContentHeight( null );
};
},
[ isNavigable ]
) }
>
<EditorStyles styles={ editorStyles } />
<style>
{ `
.block-editor-block-list__block::before,
.is-selected::after,
.is-hovered::after,
@ -257,13 +314,14 @@ function ScaledBlockPreview( {
${ additionalStyles }
` }
</style>
<MemoizedBlockList renderAppender={ false } />
<FontFamiliesLoader
fontFamilies={ externalFontFamilies }
onLoad={ noop }
/>
</Iframe>
</style>
<MemoizedBlockList renderAppender={ false } />
<FontFamiliesLoader
fontFamilies={ externalFontFamilies }
onLoad={ noop }
/>
</Iframe>
</div>
</DisabledProvider>
);
}

View File

@ -66,7 +66,7 @@ const MAX_PAGE_COUNT = 100;
export const BlockEditor = ( {} ) => {
const history = useHistory();
const settings = useSiteEditorSettings();
const [ blocks ] = useEditorBlocks();
const [ blocks, onChange ] = useEditorBlocks();
const urlParams = useQuery();
const { currentState } = useContext( CustomizeStoreContext );
@ -119,8 +119,6 @@ export const BlockEditor = ( {} ) => {
[ history, urlParams, pages ]
);
const [ , , onChange ] = useEditorBlocks();
const { highlightedBlockIndex } = useContext( HighlightedBlockContext );
const isHighlighting = highlightedBlockIndex !== -1;
const additionalStyles = isHighlighting
@ -163,7 +161,8 @@ export const BlockEditor = ( {} ) => {
onClickNavigationItem={ onClickNavigationItem }
// Don't use sub registry so that we can get the logo block from the main registry on the logo sidebar navigation screen component.
useSubRegistry={ false }
previewOpacity={ previewOpacity }
autoScale={ false }
setLogoBlockContext={ true }
/>
</div>
</div>

View File

@ -0,0 +1,139 @@
// Reference: https://github.com/WordPress/gutenberg/blob/94ff2ba55379d9ad7f6bed743b20b85ff26cf56d/packages/block-editor/src/components/block-patterns-list/index.js#L1
/* eslint-disable @woocommerce/dependency-group */
/* eslint-disable @typescript-eslint/ban-ts-comment */
/**
* External dependencies
*/
import {
VisuallyHidden,
__unstableComposite as Composite,
__unstableUseCompositeState as useCompositeState,
__unstableCompositeItem as CompositeItem,
Tooltip,
} from '@wordpress/components';
import { useInstanceId } from '@wordpress/compose';
import { __ } from '@wordpress/i18n';
import { useSelect } from '@wordpress/data';
import { useMemo } from '@wordpress/element';
import { store as blockEditorStore } from '@wordpress/block-editor';
/**
* Internal dependencies
*/
import BlockPreview from './block-preview';
const WithToolTip = ( { showTooltip, title, children } ) => {
if ( showTooltip ) {
return <Tooltip text={ title }>{ children }</Tooltip>;
}
return <>{ children }</>;
};
function BlockPattern( { pattern, onClick, onHover, composite, showTooltip } ) {
const { blocks, viewportWidth } = pattern;
const instanceId = useInstanceId( BlockPattern );
const descriptionId = `block-editor-block-patterns-list__item-description-${ instanceId }`;
const originalSettings = useSelect(
( select ) => select( blockEditorStore ).getSettings(),
[]
);
const settings = useMemo(
() => ( { ...originalSettings, __unstableIsPreviewMode: true } ),
[ originalSettings ]
);
return (
<div>
<div className="block-editor-block-patterns-list__list-item">
<WithToolTip
showTooltip={ showTooltip }
title={ pattern.title }
>
<CompositeItem
role="option"
as="div"
{ ...composite }
className="block-editor-block-patterns-list__item"
onClick={ () => {
onClick( pattern, blocks );
onHover?.( null );
} }
onMouseEnter={ () => {
onHover?.( pattern );
} }
onMouseLeave={ () => onHover?.( null ) }
aria-label={ pattern.title }
aria-describedby={
pattern.description ? descriptionId : undefined
}
>
<BlockPreview
blocks={ blocks }
viewportWidth={ viewportWidth || 1200 }
additionalStyles=""
useSubRegistry={ true }
settings={ settings }
isScrollable={ false }
autoScale={ true }
/>
{ ! showTooltip && (
<div className="block-editor-block-patterns-list__item-title">
{ pattern.title }
</div>
) }
{ !! pattern.description && (
<VisuallyHidden id={ descriptionId }>
{ pattern.description }
</VisuallyHidden>
) }
</CompositeItem>
</WithToolTip>
</div>
</div>
);
}
function BlockPatternPlaceholder() {
return (
<div className="block-editor-block-patterns-list__item is-placeholder" />
);
}
function BlockPatternList( {
isDraggable,
blockPatterns,
shownPatterns,
onHover,
onClickPattern,
orientation,
label = __( 'Block Patterns', 'woocommerce' ),
showTitlesAsTooltip,
} ) {
const composite = useCompositeState( { orientation } );
return (
<Composite
{ ...composite }
role="listbox"
className="block-editor-block-patterns-list"
aria-label={ label }
>
{ blockPatterns.map( ( pattern ) => {
const isShown = shownPatterns.includes( pattern );
return isShown ? (
<BlockPattern
key={ pattern.name }
pattern={ pattern }
onClick={ onClickPattern }
onHover={ onHover }
isDraggable={ isDraggable }
composite={ composite }
showTooltip={ showTitlesAsTooltip }
/>
) : (
<BlockPatternPlaceholder key={ pattern.name } />
);
} ) }
</Composite>
);
}
export default BlockPatternList;

View File

@ -22,7 +22,6 @@ export const BlockPreview = ( {
blocks,
settings,
useSubRegistry = true,
additionalStyles,
onChange,
...props
}: {
@ -30,7 +29,6 @@ export const BlockPreview = ( {
settings: Record< string, unknown >;
onChange?: ChangeHandler | undefined;
useSubRegistry?: boolean;
previewOpacity?: number;
} & Omit< ScaledBlockPreviewProps, 'containerWidth' > ) => {
const renderedBlocks = useMemo( () => {
const _blocks = Array.isArray( blocks ) ? blocks : [ blocks ];
@ -45,11 +43,7 @@ export const BlockPreview = ( {
onChange={ onChange }
useSubRegistry={ useSubRegistry }
>
<AutoHeightBlockPreview
settings={ settings }
additionalStyles={ additionalStyles }
{ ...props }
/>
<AutoHeightBlockPreview settings={ settings } { ...props } />
</BlockEditorProvider>
);
};

View File

@ -14,8 +14,6 @@ import {
import { Link } from '@woocommerce/components';
import { recordEvent } from '@woocommerce/tracks';
import { Spinner } from '@wordpress/components';
// @ts-expect-error Missing type in core-data.
import { __experimentalBlockPatternsList as BlockPatternList } from '@wordpress/block-editor';
/**
* Internal dependencies
@ -28,6 +26,7 @@ import { HighlightedBlockContext } from '../context/highlighted-block-context';
import { useEditorScroll } from '../hooks/use-editor-scroll';
import { useSelectedPattern } from '../hooks/use-selected-pattern';
import { findPatternByBlock } from './utils';
import BlockPatternList from '../block-pattern-list';
const SUPPORTED_FOOTER_PATTERNS = [
'woocommerce-blocks/footer-simple-menu-and-cart',
@ -140,8 +139,8 @@ export const SidebarNavigationScreenFooter = () => {
onClickPattern={ onClickFooterPattern }
label={ 'Footers' }
orientation="vertical"
category={ 'footer' }
isDraggable={ false }
onHover={ () => {} }
showTitlesAsTooltip={ true }
/>
) }

View File

@ -14,8 +14,6 @@ import {
import { Link } from '@woocommerce/components';
import { recordEvent } from '@woocommerce/tracks';
import { Spinner } from '@wordpress/components';
// @ts-ignore No types for this exist yet.
import { __experimentalBlockPatternsList as BlockPatternList } from '@wordpress/block-editor';
/**
* Internal dependencies
@ -28,6 +26,7 @@ import { useEditorBlocks } from '../hooks/use-editor-blocks';
import { HighlightedBlockContext } from '../context/highlighted-block-context';
import { useEditorScroll } from '../hooks/use-editor-scroll';
import { findPatternByBlock } from './utils';
import BlockPatternList from '../block-pattern-list';
const SUPPORTED_HEADER_PATTERNS = [
'woocommerce-blocks/header-essential',
@ -138,8 +137,8 @@ export const SidebarNavigationScreenHeader = () => {
onClickPattern={ onClickHeaderPattern }
label={ 'Headers' }
orientation="vertical"
category={ 'header' }
isDraggable={ false }
onHover={ () => {} }
showTitlesAsTooltip={ true }
/>
) }

View File

@ -472,23 +472,44 @@
/* Layout sidebar */
.block-editor-block-patterns-list__item {
.block-editor-block-preview__container {
.auto-block-preview__container {
border-radius: 4px;
border: 1.5px solid transparent;
align-items: center;
display: flex;
overflow: hidden;
}
&.is-selected,
&:hover,
&:focus {
.block-editor-block-preview__container {
.auto-block-preview__container {
box-shadow: none;
border-color: var(--wp-admin-theme-color);
}
}
}
.edit-site-sidebar-navigation-screen__content .block-editor-block-patterns-list {
width: 324px;
.block-editor-block-preview__content {
height: 100%;
width: 100%;
}
.edit-site-sidebar-navigation-screen__content {
.block-editor-block-preview__content {
left: 0;
margin: 0;
min-height: auto;
overflow: visible;
text-align: initial;
top: 0;
transform-origin: top left;
position: relative;
}
.block-editor-block-patterns-list {
width: 324px;
}
}
.woocommerce-customize-store__sidebar-homepage-content {

View File

@ -0,0 +1,4 @@
Significance: patch
Type: fix
Fix cys pattern thumbnail size