@wordpress/edit-site 4.9.0 → 4.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +2 -0
- package/build/components/add-new-template/add-custom-generic-template-modal.js +84 -0
- package/build/components/add-new-template/add-custom-generic-template-modal.js.map +1 -0
- package/build/components/add-new-template/add-custom-template-modal.js +92 -53
- package/build/components/add-new-template/add-custom-template-modal.js.map +1 -1
- package/build/components/add-new-template/new-template.js +77 -81
- package/build/components/add-new-template/new-template.js.map +1 -1
- package/build/components/add-new-template/utils.js +310 -44
- package/build/components/add-new-template/utils.js.map +1 -1
- package/build/components/code-editor/index.js +17 -4
- package/build/components/code-editor/index.js.map +1 -1
- package/build/components/editor/index.js +16 -0
- package/build/components/editor/index.js.map +1 -1
- package/build/components/error-boundary/index.js +6 -0
- package/build/components/error-boundary/index.js.map +1 -1
- package/build/components/global-styles/dimensions-panel.js +2 -6
- package/build/components/global-styles/dimensions-panel.js.map +1 -1
- package/build/components/global-styles/global-styles-provider.js +4 -2
- package/build/components/global-styles/global-styles-provider.js.map +1 -1
- package/build/components/global-styles/hooks.js +10 -1
- package/build/components/global-styles/hooks.js.map +1 -1
- package/build/components/global-styles/screen-color-palette.js +13 -17
- package/build/components/global-styles/screen-color-palette.js.map +1 -1
- package/build/components/global-styles/screen-colors.js +9 -1
- package/build/components/global-styles/screen-colors.js.map +1 -1
- package/build/components/global-styles/screen-link-color.js +48 -14
- package/build/components/global-styles/screen-link-color.js.map +1 -1
- package/build/components/global-styles/use-global-styles-output.js +171 -33
- package/build/components/global-styles/use-global-styles-output.js.map +1 -1
- package/build/components/global-styles/utils.js +1 -1
- package/build/components/global-styles/utils.js.map +1 -1
- package/build/components/keyboard-shortcut-help-modal/index.js +1 -3
- package/build/components/keyboard-shortcut-help-modal/index.js.map +1 -1
- package/build/components/template-details/edit-template-title.js +11 -3
- package/build/components/template-details/edit-template-title.js.map +1 -1
- package/build/components/template-details/index.js +1 -20
- package/build/components/template-details/index.js.map +1 -1
- package/build/store/selectors.js +4 -1
- package/build/store/selectors.js.map +1 -1
- package/build-module/components/add-new-template/add-custom-generic-template-modal.js +77 -0
- package/build-module/components/add-new-template/add-custom-generic-template-modal.js.map +1 -0
- package/build-module/components/add-new-template/add-custom-template-modal.js +92 -53
- package/build-module/components/add-new-template/add-custom-template-modal.js.map +1 -1
- package/build-module/components/add-new-template/new-template.js +80 -83
- package/build-module/components/add-new-template/new-template.js.map +1 -1
- package/build-module/components/add-new-template/utils.js +286 -40
- package/build-module/components/add-new-template/utils.js.map +1 -1
- package/build-module/components/code-editor/index.js +18 -5
- package/build-module/components/code-editor/index.js.map +1 -1
- package/build-module/components/editor/index.js +16 -0
- package/build-module/components/editor/index.js.map +1 -1
- package/build-module/components/error-boundary/index.js +5 -0
- package/build-module/components/error-boundary/index.js.map +1 -1
- package/build-module/components/global-styles/dimensions-panel.js +2 -6
- package/build-module/components/global-styles/dimensions-panel.js.map +1 -1
- package/build-module/components/global-styles/global-styles-provider.js +4 -2
- package/build-module/components/global-styles/global-styles-provider.js.map +1 -1
- package/build-module/components/global-styles/hooks.js +10 -1
- package/build-module/components/global-styles/hooks.js.map +1 -1
- package/build-module/components/global-styles/screen-color-palette.js +14 -19
- package/build-module/components/global-styles/screen-color-palette.js.map +1 -1
- package/build-module/components/global-styles/screen-colors.js +9 -1
- package/build-module/components/global-styles/screen-colors.js.map +1 -1
- package/build-module/components/global-styles/screen-link-color.js +47 -14
- package/build-module/components/global-styles/screen-link-color.js.map +1 -1
- package/build-module/components/global-styles/use-global-styles-output.js +171 -35
- package/build-module/components/global-styles/use-global-styles-output.js.map +1 -1
- package/build-module/components/global-styles/utils.js +2 -2
- package/build-module/components/global-styles/utils.js.map +1 -1
- package/build-module/components/keyboard-shortcut-help-modal/index.js +1 -2
- package/build-module/components/keyboard-shortcut-help-modal/index.js.map +1 -1
- package/build-module/components/template-details/edit-template-title.js +12 -3
- package/build-module/components/template-details/edit-template-title.js.map +1 -1
- package/build-module/components/template-details/index.js +2 -21
- package/build-module/components/template-details/index.js.map +1 -1
- package/build-module/store/selectors.js +5 -2
- package/build-module/store/selectors.js.map +1 -1
- package/build-style/style-rtl.css +21 -23
- package/build-style/style.css +21 -23
- package/package.json +29 -29
- package/src/components/add-new-template/add-custom-generic-template-modal.js +97 -0
- package/src/components/add-new-template/add-custom-template-modal.js +92 -58
- package/src/components/add-new-template/new-template.js +142 -94
- package/src/components/add-new-template/style.scss +21 -0
- package/src/components/add-new-template/utils.js +290 -46
- package/src/components/code-editor/index.js +15 -5
- package/src/components/editor/index.js +11 -0
- package/src/components/error-boundary/index.js +5 -0
- package/src/components/global-styles/dimensions-panel.js +2 -7
- package/src/components/global-styles/global-styles-provider.js +8 -9
- package/src/components/global-styles/hooks.js +15 -0
- package/src/components/global-styles/screen-color-palette.js +25 -27
- package/src/components/global-styles/screen-colors.js +9 -3
- package/src/components/global-styles/screen-link-color.js +65 -23
- package/src/components/global-styles/style.scss +7 -11
- package/src/components/global-styles/test/use-global-styles-output.js +168 -0
- package/src/components/global-styles/use-global-styles-output.js +234 -59
- package/src/components/global-styles/utils.js +2 -2
- package/src/components/keyboard-shortcut-help-modal/index.js +1 -2
- package/src/components/keyboard-shortcut-help-modal/style.scss +0 -5
- package/src/components/list/style.scss +0 -8
- package/src/components/template-details/edit-template-title.js +10 -2
- package/src/components/template-details/index.js +4 -21
- package/src/components/test/error-boundary.js +38 -0
- package/src/store/selectors.js +11 -5
|
@@ -8,16 +8,138 @@ import { get } from 'lodash';
|
|
|
8
8
|
*/
|
|
9
9
|
import { useSelect } from '@wordpress/data';
|
|
10
10
|
import { store as coreStore } from '@wordpress/core-data';
|
|
11
|
+
import { store as editorStore } from '@wordpress/editor';
|
|
11
12
|
import { decodeEntities } from '@wordpress/html-entities';
|
|
12
13
|
import { useMemo } from '@wordpress/element';
|
|
14
|
+
import { __, sprintf } from '@wordpress/i18n';
|
|
15
|
+
import { blockMeta, post } from '@wordpress/icons';
|
|
13
16
|
|
|
14
|
-
|
|
17
|
+
/**
|
|
18
|
+
* @typedef IHasNameAndId
|
|
19
|
+
* @property {string|number} id The entity's id.
|
|
20
|
+
* @property {string} name The entity's name.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Helper util to map records to add a `name` prop from a
|
|
25
|
+
* provided path, in order to handle all entities in the same
|
|
26
|
+
* fashion(implementing`IHasNameAndId` interface).
|
|
27
|
+
*
|
|
28
|
+
* @param {Object[]} entities The array of entities.
|
|
29
|
+
* @param {string} path The path to map a `name` property from the entity.
|
|
30
|
+
* @return {IHasNameAndId[]} An array of enitities that now implement the `IHasNameAndId` interface.
|
|
31
|
+
*/
|
|
32
|
+
export const mapToIHasNameAndId = ( entities, path ) => {
|
|
33
|
+
return ( entities || [] ).map( ( entity ) => ( {
|
|
34
|
+
...entity,
|
|
35
|
+
name: decodeEntities( get( entity, path ) ),
|
|
36
|
+
} ) );
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @typedef {Object} EntitiesInfo
|
|
41
|
+
* @property {boolean} hasEntities If an entity has available records(posts, terms, etc..).
|
|
42
|
+
* @property {number[]} existingEntitiesIds An array of the existing entities ids.
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* @typedef {Object} EntityConfig
|
|
47
|
+
* @property {string} entityName The entity's name.
|
|
48
|
+
* @property {Function} getOrderBy Getter for an entity's `orderBy` query parameter, given the object
|
|
49
|
+
* {search} as argument.
|
|
50
|
+
* @property {Function} getIcon Getter function for returning an entity's icon for the menu item.
|
|
51
|
+
* @property {Function} getTitle Getter function for returning an entity's title for the menu item.
|
|
52
|
+
* @property {Function} getDescription Getter function for returning an entity's description for the menu item.
|
|
53
|
+
* @property {string} recordNamePath The path to an entity's properties to use as a `name`. If not provided
|
|
54
|
+
* is assumed that `name` property exists.
|
|
55
|
+
* @property {string} templatePrefix The template prefix to create new templates and check against existing
|
|
56
|
+
* templates. For example custom post types need a `single-` prefix to all
|
|
57
|
+
* templates(`single-post-hello`), whereas `pages` don't (`page-hello`).
|
|
58
|
+
* @property {string} templateSlug If this property is provided, it is going to be used for the creation of
|
|
59
|
+
* new templates and the check against existing templates in the place
|
|
60
|
+
* of the actual entity's `slug`. An example is `Tag` templates where the
|
|
61
|
+
* the Tag's taxonomy slug is `post_tag`, but template hierarchy is based
|
|
62
|
+
* on `tag` alias.
|
|
63
|
+
*/
|
|
64
|
+
|
|
65
|
+
const taxonomyBaseConfig = {
|
|
66
|
+
entityName: 'taxonomy',
|
|
67
|
+
getOrderBy: ( { search } ) => ( search ? 'name' : 'count' ),
|
|
68
|
+
getIcon: () => blockMeta,
|
|
69
|
+
getTitle: ( labels ) =>
|
|
70
|
+
sprintf(
|
|
71
|
+
// translators: %s: Name of the taxonomy e.g: "Cagegory".
|
|
72
|
+
__( 'Single taxonomy: %s' ),
|
|
73
|
+
labels.singular_name
|
|
74
|
+
),
|
|
75
|
+
getDescription: ( labels ) =>
|
|
76
|
+
sprintf(
|
|
77
|
+
// translators: %s: Name of the taxonomy e.g: "Product Categories".
|
|
78
|
+
__( 'Displays a single taxonomy: %s.' ),
|
|
79
|
+
labels.singular_name
|
|
80
|
+
),
|
|
81
|
+
};
|
|
82
|
+
const postTypeBaseConfig = {
|
|
83
|
+
entityName: 'postType',
|
|
84
|
+
getOrderBy: ( { search } ) => ( search ? 'relevance' : 'modified' ),
|
|
85
|
+
recordNamePath: 'title.rendered',
|
|
86
|
+
// `icon` is the `menu_icon` property of a post type. We
|
|
87
|
+
// only handle `dashicons` for now, even if the `menu_icon`
|
|
88
|
+
// also supports urls and svg as values.
|
|
89
|
+
getIcon: ( _icon ) =>
|
|
90
|
+
_icon?.startsWith( 'dashicons-' ) ? _icon.slice( 10 ) : post,
|
|
91
|
+
getTitle: ( labels ) =>
|
|
92
|
+
sprintf(
|
|
93
|
+
// translators: %s: Name of the post type e.g: "Post".
|
|
94
|
+
__( 'Single item: %s' ),
|
|
95
|
+
labels.singular_name
|
|
96
|
+
),
|
|
97
|
+
getDescription: ( labels ) =>
|
|
98
|
+
sprintf(
|
|
99
|
+
// translators: %s: Name of the post type e.g: "Post".
|
|
100
|
+
__( 'Displays a single item: %s.' ),
|
|
101
|
+
labels.singular_name
|
|
102
|
+
),
|
|
103
|
+
};
|
|
104
|
+
export const entitiesConfig = {
|
|
105
|
+
postType: {
|
|
106
|
+
...postTypeBaseConfig,
|
|
107
|
+
templatePrefix: 'single-',
|
|
108
|
+
},
|
|
109
|
+
page: { ...postTypeBaseConfig },
|
|
110
|
+
taxonomy: {
|
|
111
|
+
...taxonomyBaseConfig,
|
|
112
|
+
templatePrefix: 'taxonomy-',
|
|
113
|
+
},
|
|
114
|
+
category: { ...taxonomyBaseConfig },
|
|
115
|
+
tag: { ...taxonomyBaseConfig, templateSlug: 'tag' },
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
export const useExistingTemplates = () => {
|
|
119
|
+
return useSelect(
|
|
120
|
+
( select ) =>
|
|
121
|
+
select( coreStore ).getEntityRecords( 'postType', 'wp_template', {
|
|
122
|
+
per_page: -1,
|
|
123
|
+
} ),
|
|
124
|
+
[]
|
|
125
|
+
);
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
export const useDefaultTemplateTypes = () => {
|
|
129
|
+
return useSelect(
|
|
130
|
+
( select ) =>
|
|
131
|
+
select( editorStore ).__experimentalGetDefaultTemplateTypes(),
|
|
132
|
+
[]
|
|
133
|
+
);
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const usePublicPostTypes = () => {
|
|
15
137
|
const postTypes = useSelect(
|
|
16
138
|
( select ) => select( coreStore ).getPostTypes( { per_page: -1 } ),
|
|
17
139
|
[]
|
|
18
140
|
);
|
|
19
141
|
return useMemo( () => {
|
|
20
|
-
const excludedPostTypes = [ 'attachment'
|
|
142
|
+
const excludedPostTypes = [ 'attachment' ];
|
|
21
143
|
return postTypes?.filter(
|
|
22
144
|
( { viewable, slug } ) =>
|
|
23
145
|
viewable && ! excludedPostTypes.includes( slug )
|
|
@@ -25,32 +147,97 @@ export const usePostTypes = () => {
|
|
|
25
147
|
}, [ postTypes ] );
|
|
26
148
|
};
|
|
27
149
|
|
|
150
|
+
// `page` post type is a special case in the template hierarchy,
|
|
151
|
+
// so we exclude it from the list of post types and we handle it
|
|
152
|
+
// separately.
|
|
153
|
+
export const usePostTypes = () => {
|
|
154
|
+
const postTypes = usePublicPostTypes();
|
|
155
|
+
return useMemo( () => {
|
|
156
|
+
return postTypes?.filter( ( { slug } ) => slug !== 'page' );
|
|
157
|
+
}, [ postTypes ] );
|
|
158
|
+
};
|
|
159
|
+
export const usePostTypePage = () => {
|
|
160
|
+
const postTypes = usePublicPostTypes();
|
|
161
|
+
return useMemo( () => {
|
|
162
|
+
return postTypes?.filter( ( { slug } ) => slug === 'page' );
|
|
163
|
+
}, [ postTypes ] );
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
const usePublicTaxonomies = () => {
|
|
167
|
+
const taxonomies = useSelect(
|
|
168
|
+
( select ) => select( coreStore ).getTaxonomies( { per_page: -1 } ),
|
|
169
|
+
[]
|
|
170
|
+
);
|
|
171
|
+
return useMemo( () => {
|
|
172
|
+
return taxonomies?.filter(
|
|
173
|
+
( { visibility } ) => visibility?.publicly_queryable
|
|
174
|
+
);
|
|
175
|
+
}, [ taxonomies ] );
|
|
176
|
+
};
|
|
177
|
+
|
|
28
178
|
/**
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
179
|
+
* `category` and `post_tag` are handled specifically in template
|
|
180
|
+
* hierarchy so we need to differentiate them and return the rest,
|
|
181
|
+
* e.g. `category-$slug` and `taxonomy-$taxonomy-$term`.
|
|
32
182
|
*/
|
|
183
|
+
export const useTaxonomies = () => {
|
|
184
|
+
const taxonomies = usePublicTaxonomies();
|
|
185
|
+
const specialTaxonomies = [ 'category', 'post_tag' ];
|
|
186
|
+
return useMemo(
|
|
187
|
+
() =>
|
|
188
|
+
taxonomies?.filter(
|
|
189
|
+
( { slug } ) => ! specialTaxonomies.includes( slug )
|
|
190
|
+
),
|
|
191
|
+
[ taxonomies ]
|
|
192
|
+
);
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
export const useTaxonomyCategory = () => {
|
|
196
|
+
const taxonomies = usePublicTaxonomies();
|
|
197
|
+
return useMemo(
|
|
198
|
+
() => taxonomies?.filter( ( { slug } ) => slug === 'category' ),
|
|
199
|
+
[ taxonomies ]
|
|
200
|
+
);
|
|
201
|
+
};
|
|
202
|
+
export const useTaxonomyTag = () => {
|
|
203
|
+
const taxonomies = usePublicTaxonomies();
|
|
204
|
+
return useMemo(
|
|
205
|
+
() => taxonomies?.filter( ( { slug } ) => slug === 'post_tag' ),
|
|
206
|
+
[ taxonomies ]
|
|
207
|
+
);
|
|
208
|
+
};
|
|
33
209
|
|
|
34
210
|
/**
|
|
35
|
-
* Helper hook that returns information about
|
|
36
|
-
*
|
|
211
|
+
* Helper hook that returns information about an entity having
|
|
212
|
+
* records that we can create a specific template for.
|
|
37
213
|
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
214
|
+
* For example we can search for `terms` in `taxonomy` entity or
|
|
215
|
+
* `posts` in `postType` entity.
|
|
40
216
|
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
217
|
+
* First we need to find the existing records with an associated template,
|
|
218
|
+
* to query afterwards for any remaing record, by excluding them.
|
|
219
|
+
*
|
|
220
|
+
* @param {string[]} existingTemplates The existing templates.
|
|
221
|
+
* @param {Object[]} entities The array of entities we need to get extra information.
|
|
222
|
+
* @param {EntityConfig} entityConfig The entity config.
|
|
223
|
+
* @return {Record<string,EntitiesInfo>} An object with the `entities.slug` as `keys` and EntitiesInfo as values.
|
|
43
224
|
*/
|
|
44
|
-
|
|
45
|
-
|
|
225
|
+
const useEntitiesInfo = (
|
|
226
|
+
existingTemplates,
|
|
227
|
+
entities,
|
|
228
|
+
{ entityName, templatePrefix, templateSlug }
|
|
229
|
+
) => {
|
|
46
230
|
const slugsToExcludePerEntity = useMemo( () => {
|
|
47
|
-
return
|
|
231
|
+
return entities?.reduce( ( accumulator, entity ) => {
|
|
232
|
+
let _prefix = `${ templateSlug || entity.slug }-`;
|
|
233
|
+
if ( templatePrefix ) {
|
|
234
|
+
_prefix = templatePrefix + _prefix;
|
|
235
|
+
}
|
|
48
236
|
const slugsWithTemplates = ( existingTemplates || [] ).reduce(
|
|
49
237
|
( _accumulator, existingTemplate ) => {
|
|
50
|
-
|
|
51
|
-
if ( existingTemplate.slug.startsWith( prefix ) ) {
|
|
238
|
+
if ( existingTemplate.slug.startsWith( _prefix ) ) {
|
|
52
239
|
_accumulator.push(
|
|
53
|
-
existingTemplate.slug.substring(
|
|
240
|
+
existingTemplate.slug.substring( _prefix.length )
|
|
54
241
|
);
|
|
55
242
|
}
|
|
56
243
|
return _accumulator;
|
|
@@ -58,68 +245,125 @@ export const usePostTypesEntitiesInfo = ( existingTemplates ) => {
|
|
|
58
245
|
[]
|
|
59
246
|
);
|
|
60
247
|
if ( slugsWithTemplates.length ) {
|
|
61
|
-
accumulator[
|
|
248
|
+
accumulator[ entity.slug ] = slugsWithTemplates;
|
|
62
249
|
}
|
|
63
250
|
return accumulator;
|
|
64
251
|
}, {} );
|
|
65
|
-
}, [
|
|
66
|
-
const
|
|
252
|
+
}, [ entities, existingTemplates ] );
|
|
253
|
+
const recordsToExcludePerEntity = useSelect(
|
|
67
254
|
( select ) => {
|
|
68
255
|
if ( ! slugsToExcludePerEntity ) {
|
|
69
256
|
return;
|
|
70
257
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
slug,
|
|
77
|
-
{
|
|
258
|
+
return Object.entries( slugsToExcludePerEntity ).reduce(
|
|
259
|
+
( accumulator, [ slug, slugsWithTemplates ] ) => {
|
|
260
|
+
const postsWithTemplates = select(
|
|
261
|
+
coreStore
|
|
262
|
+
).getEntityRecords( entityName, slug, {
|
|
78
263
|
_fields: 'id',
|
|
79
264
|
context: 'view',
|
|
80
265
|
slug: slugsWithTemplates,
|
|
266
|
+
} );
|
|
267
|
+
if ( postsWithTemplates?.length ) {
|
|
268
|
+
accumulator[ slug ] = postsWithTemplates;
|
|
81
269
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
return accumulator;
|
|
87
|
-
}, {} );
|
|
88
|
-
return postsToExclude;
|
|
270
|
+
return accumulator;
|
|
271
|
+
},
|
|
272
|
+
{}
|
|
273
|
+
);
|
|
89
274
|
},
|
|
90
275
|
[ slugsToExcludePerEntity ]
|
|
91
276
|
);
|
|
92
277
|
const entitiesInfo = useSelect(
|
|
93
278
|
( select ) => {
|
|
94
|
-
return
|
|
95
|
-
const
|
|
96
|
-
|
|
279
|
+
return entities?.reduce( ( accumulator, { slug } ) => {
|
|
280
|
+
const existingEntitiesIds =
|
|
281
|
+
recordsToExcludePerEntity?.[ slug ]?.map(
|
|
97
282
|
( { id } ) => id
|
|
98
283
|
) || [];
|
|
99
284
|
accumulator[ slug ] = {
|
|
100
285
|
hasEntities: !! select( coreStore ).getEntityRecords(
|
|
101
|
-
|
|
286
|
+
entityName,
|
|
102
287
|
slug,
|
|
103
288
|
{
|
|
104
289
|
per_page: 1,
|
|
105
290
|
_fields: 'id',
|
|
106
291
|
context: 'view',
|
|
107
|
-
exclude:
|
|
292
|
+
exclude: existingEntitiesIds,
|
|
108
293
|
}
|
|
109
294
|
)?.length,
|
|
110
|
-
|
|
295
|
+
existingEntitiesIds,
|
|
111
296
|
};
|
|
112
297
|
return accumulator;
|
|
113
298
|
}, {} );
|
|
114
299
|
},
|
|
115
|
-
[
|
|
300
|
+
[ entities, recordsToExcludePerEntity ]
|
|
116
301
|
);
|
|
117
302
|
return entitiesInfo;
|
|
118
303
|
};
|
|
119
304
|
|
|
120
|
-
export const
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
305
|
+
export const useExtraTemplates = (
|
|
306
|
+
entities,
|
|
307
|
+
entityConfig,
|
|
308
|
+
onClickMenuItem
|
|
309
|
+
) => {
|
|
310
|
+
const existingTemplates = useExistingTemplates();
|
|
311
|
+
const defaultTemplateTypes = useDefaultTemplateTypes();
|
|
312
|
+
const entitiesInfo = useEntitiesInfo(
|
|
313
|
+
existingTemplates,
|
|
314
|
+
entities,
|
|
315
|
+
entityConfig
|
|
316
|
+
);
|
|
317
|
+
const existingTemplateSlugs = ( existingTemplates || [] ).map(
|
|
318
|
+
( { slug } ) => slug
|
|
319
|
+
);
|
|
320
|
+
const extraTemplates = ( entities || [] ).reduce(
|
|
321
|
+
( accumulator, entity ) => {
|
|
322
|
+
const { slug, labels, icon } = entity;
|
|
323
|
+
const slugForGeneralTemplate = entityConfig.templateSlug || slug;
|
|
324
|
+
// We need to check if the general template is part of the
|
|
325
|
+
// defaultTemplateTypes. If it is, just use that info and
|
|
326
|
+
// augment it with the specific template functionality.
|
|
327
|
+
const defaultTemplateType = defaultTemplateTypes?.find(
|
|
328
|
+
( { slug: _slug } ) => _slug === slugForGeneralTemplate
|
|
329
|
+
);
|
|
330
|
+
const generalTemplateSlug =
|
|
331
|
+
defaultTemplateType?.slug ||
|
|
332
|
+
`${ entityConfig.templatePrefix }${ slug }`;
|
|
333
|
+
const hasGeneralTemplate =
|
|
334
|
+
existingTemplateSlugs?.includes( generalTemplateSlug );
|
|
335
|
+
const menuItem = defaultTemplateType
|
|
336
|
+
? { ...defaultTemplateType }
|
|
337
|
+
: {
|
|
338
|
+
slug: generalTemplateSlug,
|
|
339
|
+
title: entityConfig.getTitle( labels ),
|
|
340
|
+
description: entityConfig.getDescription( labels ),
|
|
341
|
+
icon: entityConfig.getIcon?.( icon ),
|
|
342
|
+
};
|
|
343
|
+
const hasEntities = entitiesInfo?.[ slug ]?.hasEntities;
|
|
344
|
+
// We have a different template creation flow only if they have entities.
|
|
345
|
+
if ( hasEntities ) {
|
|
346
|
+
menuItem.onClick = ( template ) => {
|
|
347
|
+
onClickMenuItem( {
|
|
348
|
+
type: entityConfig.entityName,
|
|
349
|
+
slug,
|
|
350
|
+
config: entityConfig,
|
|
351
|
+
labels,
|
|
352
|
+
hasGeneralTemplate,
|
|
353
|
+
template,
|
|
354
|
+
postsToExclude:
|
|
355
|
+
entitiesInfo[ slug ].existingEntitiesIds,
|
|
356
|
+
} );
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
// We don't need to add the menu item if there are no
|
|
360
|
+
// entities and the general template exists.
|
|
361
|
+
if ( ! hasGeneralTemplate || hasEntities ) {
|
|
362
|
+
accumulator.push( menuItem );
|
|
363
|
+
}
|
|
364
|
+
return accumulator;
|
|
365
|
+
},
|
|
366
|
+
[]
|
|
367
|
+
);
|
|
368
|
+
return extraTemplates;
|
|
125
369
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* WordPress dependencies
|
|
3
3
|
*/
|
|
4
|
-
import { parse } from '@wordpress/blocks';
|
|
4
|
+
import { parse, __unstableSerializeAndClean } from '@wordpress/blocks';
|
|
5
5
|
import { useEntityBlockEditor, useEntityProp } from '@wordpress/core-data';
|
|
6
6
|
import { useSelect, useDispatch } from '@wordpress/data';
|
|
7
7
|
import { store as keyboardShortcutsStore } from '@wordpress/keyboard-shortcuts';
|
|
@@ -32,10 +32,20 @@ export default function CodeEditor() {
|
|
|
32
32
|
'postType',
|
|
33
33
|
templateType
|
|
34
34
|
);
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
35
|
+
|
|
36
|
+
// Replicates the logic found in getEditedPostContent().
|
|
37
|
+
let content;
|
|
38
|
+
if ( contentStructure instanceof Function ) {
|
|
39
|
+
content = contentStructure( { blocks } );
|
|
40
|
+
} else if ( blocks ) {
|
|
41
|
+
// If we have parsed blocks already, they should be our source of truth.
|
|
42
|
+
// Parsing applies block deprecations and legacy block conversions that
|
|
43
|
+
// unparsed content will not have.
|
|
44
|
+
content = __unstableSerializeAndClean( blocks );
|
|
45
|
+
} else {
|
|
46
|
+
content = contentStructure;
|
|
47
|
+
}
|
|
48
|
+
|
|
39
49
|
const { switchEditorMode } = useDispatch( editSiteStore );
|
|
40
50
|
return (
|
|
41
51
|
<div className="edit-site-code-editor">
|
|
@@ -47,6 +47,17 @@ import { GlobalStylesProvider } from '../global-styles/global-styles-provider';
|
|
|
47
47
|
import useTitle from '../routes/use-title';
|
|
48
48
|
|
|
49
49
|
const interfaceLabels = {
|
|
50
|
+
/* translators: accessibility text for the editor top bar landmark region. */
|
|
51
|
+
header: __( 'Editor top bar' ),
|
|
52
|
+
/* translators: accessibility text for the editor content landmark region. */
|
|
53
|
+
body: __( 'Editor content' ),
|
|
54
|
+
/* translators: accessibility text for the editor settings landmark region. */
|
|
55
|
+
sidebar: __( 'Editor settings' ),
|
|
56
|
+
/* translators: accessibility text for the editor publish landmark region. */
|
|
57
|
+
actions: __( 'Editor publish' ),
|
|
58
|
+
/* translators: accessibility text for the editor footer landmark region. */
|
|
59
|
+
footer: __( 'Editor footer' ),
|
|
60
|
+
/* translators: accessibility text for the navigation sidebar landmark region. */
|
|
50
61
|
drawer: __( 'Navigation Sidebar' ),
|
|
51
62
|
};
|
|
52
63
|
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { Component } from '@wordpress/element';
|
|
5
5
|
import { __ } from '@wordpress/i18n';
|
|
6
|
+
import { doAction } from '@wordpress/hooks';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Internal dependencies
|
|
@@ -20,6 +21,10 @@ export default class ErrorBoundary extends Component {
|
|
|
20
21
|
};
|
|
21
22
|
}
|
|
22
23
|
|
|
24
|
+
componentDidCatch( error ) {
|
|
25
|
+
doAction( 'editor.ErrorBoundary.errorLogged', error );
|
|
26
|
+
}
|
|
27
|
+
|
|
23
28
|
static getDerivedStateFromError( error ) {
|
|
24
29
|
return { error };
|
|
25
30
|
}
|
|
@@ -43,13 +43,8 @@ function useHasMargin( name ) {
|
|
|
43
43
|
function useHasGap( name ) {
|
|
44
44
|
const supports = getSupportedGlobalStylesPanels( name );
|
|
45
45
|
const [ settings ] = useSetting( 'spacing.blockGap', name );
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
// See: https://github.com/WordPress/gutenberg/pull/39845.
|
|
49
|
-
// We can revert this condition when they're working again.
|
|
50
|
-
return !! name
|
|
51
|
-
? false
|
|
52
|
-
: settings && supports.includes( '--wp--style--block-gap' );
|
|
46
|
+
|
|
47
|
+
return settings && supports.includes( 'blockGap' );
|
|
53
48
|
}
|
|
54
49
|
|
|
55
50
|
function filterValuesBySides( values, sides ) {
|
|
@@ -1,14 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* External dependencies
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
5
|
-
mergeWith,
|
|
6
|
-
pickBy,
|
|
7
|
-
isEmpty,
|
|
8
|
-
isObject,
|
|
9
|
-
identity,
|
|
10
|
-
mapValues,
|
|
11
|
-
} from 'lodash';
|
|
4
|
+
import { mergeWith, pickBy, isEmpty, mapValues } from 'lodash';
|
|
12
5
|
|
|
13
6
|
/**
|
|
14
7
|
* WordPress dependencies
|
|
@@ -22,6 +15,8 @@ import { store as coreStore } from '@wordpress/core-data';
|
|
|
22
15
|
*/
|
|
23
16
|
import { GlobalStylesContext } from './context';
|
|
24
17
|
|
|
18
|
+
const identity = ( x ) => x;
|
|
19
|
+
|
|
25
20
|
function mergeTreesCustomizer( _, srcValue ) {
|
|
26
21
|
// We only pass as arrays the presets,
|
|
27
22
|
// in which case we want the new array of values
|
|
@@ -36,7 +31,11 @@ export function mergeBaseAndUserConfigs( base, user ) {
|
|
|
36
31
|
}
|
|
37
32
|
|
|
38
33
|
const cleanEmptyObject = ( object ) => {
|
|
39
|
-
if (
|
|
34
|
+
if (
|
|
35
|
+
object === null ||
|
|
36
|
+
typeof object !== 'object' ||
|
|
37
|
+
Array.isArray( object )
|
|
38
|
+
) {
|
|
40
39
|
return object;
|
|
41
40
|
}
|
|
42
41
|
const cleanedNestedObjects = pickBy(
|
|
@@ -182,6 +182,21 @@ export function getSupportedGlobalStylesPanels( name ) {
|
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
const supportKeys = [];
|
|
185
|
+
|
|
186
|
+
// Check for blockGap support.
|
|
187
|
+
// Block spacing support doesn't map directly to a single style property, so needs to be handled separately.
|
|
188
|
+
// Also, only allow `blockGap` support if serialization has not been skipped, to be sure global spacing can be applied.
|
|
189
|
+
if (
|
|
190
|
+
blockType?.supports?.spacing?.blockGap &&
|
|
191
|
+
blockType?.supports?.spacing?.__experimentalSkipSerialization !==
|
|
192
|
+
true &&
|
|
193
|
+
! blockType?.supports?.spacing?.__experimentalSkipSerialization?.some?.(
|
|
194
|
+
( spacingType ) => spacingType === 'blockGap'
|
|
195
|
+
)
|
|
196
|
+
) {
|
|
197
|
+
supportKeys.push( 'blockGap' );
|
|
198
|
+
}
|
|
199
|
+
|
|
185
200
|
Object.keys( STYLE_PROPERTY ).forEach( ( styleName ) => {
|
|
186
201
|
if ( ! STYLE_PROPERTY[ styleName ].support ) {
|
|
187
202
|
return;
|
|
@@ -2,11 +2,7 @@
|
|
|
2
2
|
* WordPress dependencies
|
|
3
3
|
*/
|
|
4
4
|
import { __ } from '@wordpress/i18n';
|
|
5
|
-
import {
|
|
6
|
-
__experimentalToggleGroupControl as ToggleGroupControl,
|
|
7
|
-
__experimentalToggleGroupControlOption as ToggleGroupControlOption,
|
|
8
|
-
} from '@wordpress/components';
|
|
9
|
-
import { useState } from '@wordpress/element';
|
|
5
|
+
import { TabPanel } from '@wordpress/components';
|
|
10
6
|
|
|
11
7
|
/**
|
|
12
8
|
* Internal dependencies
|
|
@@ -16,8 +12,6 @@ import GradientPalettePanel from './gradients-palette-panel';
|
|
|
16
12
|
import ScreenHeader from './header';
|
|
17
13
|
|
|
18
14
|
function ScreenColorPalette( { name } ) {
|
|
19
|
-
const [ currentTab, setCurrentTab ] = useState( 'solid' );
|
|
20
|
-
|
|
21
15
|
return (
|
|
22
16
|
<>
|
|
23
17
|
<ScreenHeader
|
|
@@ -26,27 +20,31 @@ function ScreenColorPalette( { name } ) {
|
|
|
26
20
|
'Palettes are used to provide default color options for blocks and various design tools. Here you can edit the colors with their labels.'
|
|
27
21
|
) }
|
|
28
22
|
/>
|
|
29
|
-
<
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
23
|
+
<TabPanel
|
|
24
|
+
tabs={ [
|
|
25
|
+
{
|
|
26
|
+
name: 'solid',
|
|
27
|
+
title: 'Solid color',
|
|
28
|
+
value: 'solid',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
name: 'gradient',
|
|
32
|
+
title: 'Gradient',
|
|
33
|
+
value: 'gradient',
|
|
34
|
+
},
|
|
35
|
+
] }
|
|
36
36
|
>
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
<GradientPalettePanel name={ name } />
|
|
49
|
-
) }
|
|
37
|
+
{ ( tab ) => (
|
|
38
|
+
<>
|
|
39
|
+
{ tab.value === 'solid' && (
|
|
40
|
+
<ColorPalettePanel name={ name } />
|
|
41
|
+
) }
|
|
42
|
+
{ tab.value === 'gradient' && (
|
|
43
|
+
<GradientPalettePanel name={ name } />
|
|
44
|
+
) }
|
|
45
|
+
</>
|
|
46
|
+
) }
|
|
47
|
+
</TabPanel>
|
|
50
48
|
</>
|
|
51
49
|
);
|
|
52
50
|
}
|
|
@@ -82,6 +82,7 @@ function LinkColorItem( { name, parentMenu } ) {
|
|
|
82
82
|
const supports = getSupportedGlobalStylesPanels( name );
|
|
83
83
|
const hasSupport = supports.includes( 'linkColor' );
|
|
84
84
|
const [ color ] = useStyle( 'elements.link.color.text', name );
|
|
85
|
+
const [ colorHover ] = useStyle( 'elements.link.:hover.color.text', name );
|
|
85
86
|
|
|
86
87
|
if ( ! hasSupport ) {
|
|
87
88
|
return null;
|
|
@@ -93,9 +94,14 @@ function LinkColorItem( { name, parentMenu } ) {
|
|
|
93
94
|
aria-label={ __( 'Colors link styles' ) }
|
|
94
95
|
>
|
|
95
96
|
<HStack justify="flex-start">
|
|
96
|
-
<
|
|
97
|
-
<
|
|
98
|
-
|
|
97
|
+
<ZStack isLayered={ false } offset={ -8 }>
|
|
98
|
+
<ColorIndicatorWrapper expanded={ false }>
|
|
99
|
+
<ColorIndicator colorValue={ color } />
|
|
100
|
+
</ColorIndicatorWrapper>
|
|
101
|
+
<ColorIndicatorWrapper expanded={ false }>
|
|
102
|
+
<ColorIndicator colorValue={ colorHover } />
|
|
103
|
+
</ColorIndicatorWrapper>
|
|
104
|
+
</ZStack>
|
|
99
105
|
<FlexItem>{ __( 'Links' ) }</FlexItem>
|
|
100
106
|
</HStack>
|
|
101
107
|
</NavigationButtonAsItem>
|