/** * External dependencies */ import { useEffect, useMemo, useRef, useState } from '@wordpress/element'; import { useAsyncList } from '@wordpress/compose'; import { useSelect } from '@wordpress/data'; import { BlockInstance } from '@wordpress/blocks'; import { close } from '@wordpress/icons'; import { __ } from '@wordpress/i18n'; import { getNewPath, navigateTo } from '@woocommerce/navigation'; import { capitalize } from 'lodash'; import { Button, Spinner } from '@wordpress/components'; // @ts-expect-error No types for this exist yet. // eslint-disable-next-line @woocommerce/dependency-group import { useIsSiteEditorLoading } from '@wordpress/edit-site/build-module/components/layout/hooks'; // eslint-disable-next-line @woocommerce/dependency-group import { store as coreStore, // @ts-expect-error No types for this exist yet. } from '@wordpress/core-data'; // eslint-disable-next-line @woocommerce/dependency-group import { __experimentalBlockPatternsList as BlockPatternList, // @ts-expect-error No types for this exist yet. } from '@wordpress/block-editor'; /** * Internal dependencies */ import { usePatternsByCategory } from '../../hooks/use-patterns'; import './style.scss'; import { useEditorBlocks } from '../../hooks/use-editor-blocks'; import { PATTERN_CATEGORIES } from './categories'; import { THEME_SLUG } from '~/customize-store/data/constants'; import { findButtonBlockInsideCoverBlockWithBlackBackgroundPatternAndUpdate, PRODUCT_HERO_PATTERN_BUTTON_STYLE, } from '../../utils/black-background-pattern-update-button'; import { useIsActiveNewNeutralVariation } from '../../hooks/use-is-active-new-neutral-variation'; import { sortPatternsByCategory, addIsAddedClassToPatternPreview, } from './utils'; import { trackEvent } from '~/customize-store/tracking'; import { useInsertPattern } from '../../hooks/use-insert-pattern'; export const SidebarPatternScreen = ( { category }: { category: string } ) => { const { patterns, isLoading } = usePatternsByCategory( category ); const isActiveNewNeutralVariation = useIsActiveNewNeutralVariation(); const sortedPatterns = useMemo( () => { const patternsWithoutThemePatterns = patterns.filter( ( pattern ) => ! pattern.name.includes( THEME_SLUG ) && pattern.source !== 'pattern-directory/theme' && pattern.source !== 'pattern-directory/core' ); const patternWithPatchedProductHeroPattern = patternsWithoutThemePatterns.map( ( pattern ) => { if ( pattern.name !== 'woocommerce-blocks/just-arrived-full-hero' && pattern.name !== 'woocommerce-blocks/featured-category-cover-image' ) { return pattern; } if ( ! isActiveNewNeutralVariation ) { const blocks = findButtonBlockInsideCoverBlockWithBlackBackgroundPatternAndUpdate( pattern.blocks, ( patternBlocks: BlockInstance[] ) => { patternBlocks.forEach( ( block: BlockInstance ) => ( block.attributes.style = {} ) ); } ); return { ...pattern, blocks }; } const blocks = findButtonBlockInsideCoverBlockWithBlackBackgroundPatternAndUpdate( pattern.blocks, ( patternBlocks: BlockInstance[] ) => { patternBlocks.forEach( ( block ) => ( block.attributes.style = PRODUCT_HERO_PATTERN_BUTTON_STYLE ) ); } ); return { ...pattern, blocks }; } ); return sortPatternsByCategory( patternWithPatchedProductHeroPattern, category as keyof typeof PATTERN_CATEGORIES ); }, [ category, isActiveNewNeutralVariation, patterns ] ); const asyncSortedPatterns = useAsyncList( sortedPatterns ); const [ patternPagination, setPatternPagination ] = useState( 10 ); const refElement = useRef< HTMLDivElement >( null ); const currentTemplate = useSelect( ( sel ) => // @ts-expect-error No types for this exist yet. sel( coreStore ).__experimentalGetTemplateForLink( '/' ), [] ); const [ blocks ] = useEditorBlocks( 'wp_template', currentTemplate?.id ?? '' ); const isEditorLoading = useIsSiteEditorLoading(); const isSpinnerVisible = isLoading || isEditorLoading; useEffect( () => { if ( isSpinnerVisible || refElement.current === null ) { return; } // We want to add the is-added class to the pattern preview when the pattern is loaded in the editor and for each mutation. addIsAddedClassToPatternPreview( refElement.current, blocks ); const observer = new MutationObserver( () => { addIsAddedClassToPatternPreview( refElement.current as HTMLElement, blocks ); } ); const previewPatternList = document.querySelector( '.woocommerce-customize-store-edit-site-layout__sidebar-extra__pattern .block-editor-block-patterns-list' ); if ( previewPatternList ) { observer.observe( previewPatternList, { childList: true, } ); } return () => { observer.disconnect(); }; }, [ isLoading, blocks, isSpinnerVisible ] ); const { insertPattern, insertedPattern: blockToScroll } = useInsertPattern(); useEffect( () => { if ( isEditorLoading ) { return; } const iframe = window.document.querySelector( '.woocommerce-customize-store-assembler > .block-editor-iframe__container iframe[name="editor-canvas"]' ) as HTMLIFrameElement; const blockList = iframe?.contentWindow?.document.body.querySelector( '.block-editor-block-list__layout' ); const observer = new MutationObserver( () => { if ( blockToScroll.current ) { const block = blockList?.querySelector( `[id="block-${ blockToScroll.current }"]` ); if ( block ) { block.scrollIntoView( { behavior: 'smooth', block: 'end', } ); blockToScroll.current = null; } } } ); if ( blockList ) { observer.observe( blockList, { childList: true } ); } return () => { observer.disconnect(); }; }, [ blockToScroll, isEditorLoading ] ); return (
{ const element = event.target as HTMLElement; const scrollTop = element.scrollTop; const percentage = scrollTop / ( element.scrollHeight - element.clientHeight ); if ( percentage > 0.5 ) { setPatternPagination( ( prev ) => prev + 10 ); } } } >

{ capitalize( PATTERN_CATEGORIES[ category as keyof typeof PATTERN_CATEGORIES ].label ) }

{ PATTERN_CATEGORIES[ category as keyof typeof PATTERN_CATEGORIES ].description }
{ isSpinnerVisible && ( ) } { ! isSpinnerVisible && ( ) }
); };