-
Notifications
You must be signed in to change notification settings - Fork 10.7k
/
block-editor-container.tsx
213 lines (187 loc) · 6.37 KB
/
block-editor-container.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
/* eslint-disable @woocommerce/dependency-group */
/* eslint-disable @typescript-eslint/ban-ts-comment */
/**
* External dependencies
*/
// @ts-expect-error No types for this exist yet.
import { store as blockEditorStore } from '@wordpress/block-editor';
// @ts-expect-error No types for this exist yet.
import { store as coreStore, useEntityRecords } from '@wordpress/core-data';
import { useSelect } from '@wordpress/data';
// @ts-expect-error No types for this exist yet.
import { privateApis as routerPrivateApis } from '@wordpress/router';
// @ts-expect-error No types for this exist yet.
import { unlock } from '@wordpress/edit-site/build-module/lock-unlock';
import { useQuery } from '@woocommerce/navigation';
// @ts-expect-error No types for this exist yet.
import useSiteEditorSettings from '@wordpress/edit-site/build-module/components/block-editor/use-site-editor-settings';
import { useCallback, useContext, useMemo } from '@wordpress/element';
// @ts-expect-error No types for this exist yet.
import { store as editSiteStore } from '@wordpress/edit-site/build-module/store';
/**
* Internal dependencies
*/
import { CustomizeStoreContext } from './';
import { BlockEditor } from './block-editor';
import { HighlightedBlockContext } from './context/highlighted-block-context';
import { useEditorBlocks } from './hooks/use-editor-blocks';
import { useScrollOpacity } from './hooks/use-scroll-opacity';
const { useHistory } = unlock( routerPrivateApis );
type Page = {
link: string;
title: { rendered: string; raw: string };
[ key: string ]: unknown;
};
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-expect-error No types for this exist yet.
select( blockEditorStore ).getBlocksByClientId( blockClientId );
if ( navLinkBlocks && navLinkBlocks.length ) {
return navLinkBlocks[ 0 ].attributes.id;
}
}
return null;
};
// 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 BlockEditorContainer = () => {
const history = useHistory();
const settings = useSiteEditorSettings();
const currentTemplate:
| {
id: string;
}
| undefined = useSelect(
( select ) =>
// @ts-expect-error No types for this exist yet.
select( coreStore ).__experimentalGetTemplateForLink( '/' ),
[]
);
// This is necessary to avoid this issue: https://github.com/woocommerce/woocommerce/issues/45593
// Related PR: https://github.com/woocommerce/woocommerce/pull/45600
const { templateType } = useSelect( ( select ) => {
const { getEditedPostType } = unlock( select( editSiteStore ) );
return {
templateType: getEditedPostType(),
};
}, [] );
const [ blocks, , onChange ] = useEditorBlocks(
templateType,
currentTemplate?.id ?? ''
);
const urlParams = useQuery();
const { currentState } = useContext( CustomizeStoreContext );
const scrollDirection =
urlParams.path === '/customize-store/assembler-hub/footer'
? 'bottomUp'
: 'topDown';
const previewOpacity = useScrollOpacity(
'.woocommerce-customize-store__block-editor iframe',
scrollDirection
);
// // 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',
} );
const onClickNavigationItem = useCallback(
( event: MouseEvent ) => {
// 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 ) {
history.push( {
...urlParams,
postId: pageId,
postType: 'page',
} );
return;
}
// Home page
const { postId, postType, ...params } = urlParams;
history.push( {
...params,
} );
},
[ history, urlParams, pages ]
);
const { highlightedBlockClientId } = useContext( HighlightedBlockContext );
const isHighlighting = highlightedBlockClientId !== null;
const additionalStyles = isHighlighting
? `
.wp-block.preview-opacity {
opacity: ${ previewOpacity };
}
`
: '';
const opacityClass = 'preview-opacity';
const renderedBlocks = useMemo(
() =>
blocks.map( ( block ) => {
if (
! isHighlighting ||
block.clientId === highlightedBlockClientId
) {
return {
...block,
attributes: {
...block.attributes,
className: block.attributes.className?.replace(
opacityClass,
''
),
},
};
}
return {
...block,
attributes: {
...block.attributes,
className:
block.attributes.className + ` ${ opacityClass }`,
},
};
} ),
[ blocks, highlightedBlockClientId, isHighlighting ]
);
const isScrollable = useMemo(
() =>
// Disable scrollable for transitional screen
! (
typeof currentState === 'object' &&
currentState.transitionalScreen === 'transitional'
),
[ currentState ]
);
return (
<BlockEditor
renderedBlocks={ renderedBlocks }
isScrollable={ isScrollable }
onChange={ onChange }
settings={ settings }
additionalStyles={ additionalStyles }
onClickNavigationItem={ onClickNavigationItem }
/>
);
};