2023-08-28 01:28:05 +00:00
/* eslint-disable @woocommerce/dependency-group */
/* eslint-disable @typescript-eslint/ban-ts-comment */
/ * *
* External dependencies
* /
// @ts-ignore No types for this exist yet.
2023-09-22 06:27:22 +00:00
import { store as blockEditorStore } from '@wordpress/block-editor' ;
// @ts-ignore No types for this exist yet.
2024-02-29 14:32:44 +00:00
import { useEntityRecords , store as coreStore } from '@wordpress/core-data' ;
import { useSelect } from '@wordpress/data' ;
2023-08-28 01:28:05 +00:00
// @ts-ignore No types for this exist yet.
import { privateApis as routerPrivateApis } from '@wordpress/router' ;
// @ts-ignore No types for this exist yet.
import { unlock } from '@wordpress/edit-site/build-module/lock-unlock' ;
// @ts-ignore No types for this exist yet.
import useSiteEditorSettings from '@wordpress/edit-site/build-module/components/block-editor/use-site-editor-settings' ;
2023-10-05 12:36:08 +00:00
import { useQuery } from '@woocommerce/navigation' ;
2023-10-26 10:15:30 +00:00
import { useContext , useCallback , useMemo } from '@wordpress/element' ;
2023-09-14 08:24:46 +00:00
2023-08-28 01:28:05 +00:00
/ * *
* Internal dependencies
* /
import BlockPreview from './block-preview' ;
2023-09-14 08:24:46 +00:00
import { useEditorBlocks } from './hooks/use-editor-blocks' ;
2023-09-18 09:29:29 +00:00
import { useScrollOpacity } from './hooks/use-scroll-opacity' ;
2023-10-05 12:36:08 +00:00
import { CustomizeStoreContext } from './' ;
2023-10-26 10:15:30 +00:00
import { HighlightedBlockContext } from './context/highlighted-block-context' ;
2023-11-15 13:06:05 +00:00
import Iframe from './iframe' ;
2023-08-28 01:28:05 +00:00
2023-09-18 09:29:29 +00:00
const { useHistory } = unlock ( routerPrivateApis ) ;
2023-08-28 01:28:05 +00:00
type Page = {
link : string ;
title : { rendered : string ; raw : string } ;
[ key : string ] : unknown ;
} ;
2023-09-22 06:27:22 +00:00
const findPageIdByLinkOrTitle = ( event : MouseEvent , _pages : Page [ ] ) = > {
const target = event . target as HTMLAnchorElement ;
const clickedPage =
_pages . find ( ( page ) = > page . link === target . href ) ||
_pages . find ( ( page ) = > page . title . rendered === target . innerText ) ;
return clickedPage ? clickedPage.id : null ;
} ;
const findPageIdByBlockClientId = ( event : MouseEvent ) = > {
const navLink = ( event . target as HTMLAnchorElement ) . closest (
'.wp-block-navigation-link'
) ;
if ( navLink ) {
const blockClientId = navLink . getAttribute ( 'data-block' ) ;
const navLinkBlocks =
// @ts-ignore No types for this exist yet.
select ( blockEditorStore ) . getBlocksByClientId ( blockClientId ) ;
if ( navLinkBlocks && navLinkBlocks . length ) {
return navLinkBlocks [ 0 ] . attributes . id ;
}
}
return null ;
} ;
2023-08-28 01:28:05 +00:00
// We only show the edit option when page count is <= MAX_PAGE_COUNT
// Performance of Navigation Links is not good past this value.
const MAX_PAGE_COUNT = 100 ;
export const BlockEditor = ( { } ) = > {
const history = useHistory ( ) ;
const settings = useSiteEditorSettings ( ) ;
2024-02-29 14:32:44 +00:00
const currentTemplate = useSelect (
( select ) = >
// @ts-expect-error No types for this exist yet.
select ( coreStore ) . __experimentalGetTemplateForLink ( '/' ) ,
[ ]
) ;
const [ blocks , , onChange ] = useEditorBlocks (
'wp_template' ,
currentTemplate . id
) ;
2023-09-18 09:29:29 +00:00
const urlParams = useQuery ( ) ;
2023-10-05 12:36:08 +00:00
const { currentState } = useContext ( CustomizeStoreContext ) ;
2023-09-18 09:29:29 +00:00
const scrollDirection =
urlParams . path === '/customize-store/assembler-hub/footer'
? 'bottomUp'
: 'topDown' ;
const previewOpacity = useScrollOpacity (
2023-09-19 05:54:19 +00:00
'.woocommerce-customize-store__block-editor iframe' ,
2023-09-18 09:29:29 +00:00
scrollDirection
) ;
2023-08-28 01:28:05 +00:00
// // See packages/block-library/src/page-list/edit.js.
const { records : pages } = useEntityRecords ( 'postType' , 'page' , {
per_page : MAX_PAGE_COUNT ,
_fields : [ 'id' , 'link' , 'menu_order' , 'parent' , 'title' , 'type' ] ,
// TODO: When https://core.trac.wordpress.org/ticket/39037 REST API support for multiple orderby
// values is resolved, update 'orderby' to [ 'menu_order', 'post_title' ] to provide a consistent
// sort.
orderby : 'menu_order' ,
order : 'asc' ,
} ) ;
2023-09-05 06:21:19 +00:00
const onClickNavigationItem = useCallback (
( event : MouseEvent ) = > {
2023-09-22 06:27:22 +00:00
// If the user clicks on a navigation item, we want to update the URL to reflect the page they are on.
// Because of bug in the block library (See https://github.com/woocommerce/team-ghidorah/issues/253#issuecomment-1665106817), we're not able to use href link to find the page ID. Instead, we'll use the link/title first, and if that doesn't work, we'll use the block client ID. It depends on the header block type to determine which one to use.
// This is a temporary solution until the block library is fixed.
const pageId =
findPageIdByLinkOrTitle ( event , pages ) ||
findPageIdByBlockClientId ( event ) ;
if ( pageId ) {
2023-09-05 06:21:19 +00:00
history . push ( {
2023-09-18 09:29:29 +00:00
. . . urlParams ,
2023-09-22 06:27:22 +00:00
postId : pageId ,
2023-09-05 06:21:19 +00:00
postType : 'page' ,
} ) ;
2023-09-22 06:27:22 +00:00
return ;
2023-09-05 06:21:19 +00:00
}
2023-09-22 06:27:22 +00:00
// Home page
const { postId , postType , . . . params } = urlParams ;
history . push ( {
. . . params ,
} ) ;
2023-09-05 06:21:19 +00:00
} ,
2023-09-18 09:29:29 +00:00
[ history , urlParams , pages ]
2023-09-05 06:21:19 +00:00
) ;
2023-08-28 01:28:05 +00:00
2024-02-29 14:32:44 +00:00
const { highlightedBlockClientId } = useContext ( HighlightedBlockContext ) ;
const isHighlighting = highlightedBlockClientId !== null ;
2023-10-26 10:15:30 +00:00
const additionalStyles = isHighlighting
? `
. wp - block . preview - opacity {
opacity : $ { previewOpacity } ;
}
`
: '' ;
2024-02-29 14:32:44 +00:00
const opacityClass = 'preview-opacity' ;
2023-10-26 10:15:30 +00:00
const renderedBlocks = useMemo (
( ) = >
2024-02-29 14:32:44 +00:00
blocks . map ( ( block ) = > {
if (
! isHighlighting ||
block . clientId === highlightedBlockClientId
) {
return {
. . . block ,
attributes : {
. . . block . attributes ,
className : block.attributes.className?.replace (
opacityClass ,
''
) ,
} ,
} ;
2023-10-26 10:15:30 +00:00
}
return {
. . . block ,
attributes : {
. . . block . attributes ,
className :
2024-02-29 14:32:44 +00:00
block . attributes . className + ` ${ opacityClass } ` ,
2023-10-26 10:15:30 +00:00
} ,
} ;
} ) ,
2024-02-29 14:32:44 +00:00
[ blocks , highlightedBlockClientId , isHighlighting ]
2023-10-26 10:15:30 +00:00
) ;
2023-09-05 06:21:19 +00:00
return (
< div className = "woocommerce-customize-store__block-editor" >
< div className = { 'woocommerce-block-preview-container' } >
< BlockPreview
2023-10-26 10:15:30 +00:00
blocks = { renderedBlocks }
2023-11-08 02:48:38 +00:00
onChange = {
2024-01-12 12:44:06 +00:00
// We need to pass onChange for the logo screen so that logo block can be updated when we change the logo attributes in logo sidebar navigation screen component.
// We also need to pass onChange for the assembler hub screen so when a block set an attribute during the block initialization, the block editor will be updated.
2024-03-08 09:02:41 +00:00
// We also need to pass onChange when the homepage pattern is updated because the Product Collection block sets a dynamic attribute and we need to update the block editor.
2023-11-08 02:48:38 +00:00
// For other screens, we don't need to pass onChange. Otherwise, we'll get a race condition issue where the block editor will be updated twice: once from the onChange in the sidebar component, and once from the onChange in the block editor component.
2024-01-12 12:44:06 +00:00
[
'/customize-store/assembler-hub/logo' ,
2024-03-08 09:02:41 +00:00
'/customize-store/assembler-hub/homepage' ,
2024-01-12 12:44:06 +00:00
'/customize-store/assembler-hub' ,
] . includes ( urlParams . path )
2023-11-08 02:48:38 +00:00
? onChange
: undefined
}
2023-09-05 06:21:19 +00:00
settings = { settings }
2023-10-26 10:15:30 +00:00
additionalStyles = { additionalStyles }
2023-09-29 03:38:25 +00:00
isNavigable = { false }
2023-11-15 13:06:05 +00:00
isScrollable = {
// Disable scrollable for transitional screen
! (
typeof currentState === 'object' &&
currentState . transitionalScreen === 'transitional'
)
}
2023-09-05 06:21:19 +00:00
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 }
2023-11-01 11:03:04 +00:00
autoScale = { false }
setLogoBlockContext = { true }
2023-11-15 13:06:05 +00:00
CustomIframeComponent = { Iframe }
2023-09-05 06:21:19 +00:00
/ >
< / div >
2023-08-28 01:28:05 +00:00
< / div >
) ;
} ;