@wordpress/edit-site 5.19.2 → 5.19.4

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.
Files changed (162) hide show
  1. package/build/components/add-new-pattern/index.js +6 -10
  2. package/build/components/add-new-pattern/index.js.map +1 -1
  3. package/build/components/global-styles/font-library-modal/collection-font-details.js +3 -1
  4. package/build/components/global-styles/font-library-modal/collection-font-details.js.map +1 -1
  5. package/build/components/global-styles/font-library-modal/context.js +26 -30
  6. package/build/components/global-styles/font-library-modal/context.js.map +1 -1
  7. package/build/components/global-styles/font-library-modal/font-collection.js +31 -11
  8. package/build/components/global-styles/font-library-modal/font-collection.js.map +1 -1
  9. package/build/components/global-styles/font-library-modal/index.js +10 -3
  10. package/build/components/global-styles/font-library-modal/index.js.map +1 -1
  11. package/build/components/global-styles/font-library-modal/installed-fonts.js +27 -7
  12. package/build/components/global-styles/font-library-modal/installed-fonts.js.map +1 -1
  13. package/build/components/global-styles/font-library-modal/local-fonts.js +35 -8
  14. package/build/components/global-styles/font-library-modal/local-fonts.js.map +1 -1
  15. package/build/components/global-styles/font-library-modal/resolvers.js +1 -1
  16. package/build/components/global-styles/font-library-modal/resolvers.js.map +1 -1
  17. package/build/components/global-styles/font-library-modal/upload-fonts.js +26 -0
  18. package/build/components/global-styles/font-library-modal/upload-fonts.js.map +1 -0
  19. package/build/components/global-styles/font-library-modal/utils/fonts-outline.js +4 -1
  20. package/build/components/global-styles/font-library-modal/utils/fonts-outline.js.map +1 -1
  21. package/build/components/global-styles/font-library-modal/utils/get-notice-from-response.js +71 -0
  22. package/build/components/global-styles/font-library-modal/utils/get-notice-from-response.js.map +1 -0
  23. package/build/components/global-styles/font-library-modal/utils/index.js +4 -1
  24. package/build/components/global-styles/font-library-modal/utils/index.js.map +1 -1
  25. package/build/components/page-patterns/grid.js +0 -1
  26. package/build/components/page-patterns/grid.js.map +1 -1
  27. package/build/components/page-patterns/patterns-list.js +1 -1
  28. package/build/components/page-patterns/patterns-list.js.map +1 -1
  29. package/build/components/page-patterns/use-patterns.js +5 -1
  30. package/build/components/page-patterns/use-patterns.js.map +1 -1
  31. package/build/components/page-template-parts/index.js +12 -1
  32. package/build/components/page-template-parts/index.js.map +1 -1
  33. package/build/components/sidebar-edit-mode/page-panels/reset-default-template.js +1 -1
  34. package/build/components/sidebar-edit-mode/page-panels/reset-default-template.js.map +1 -1
  35. package/build/components/sidebar-edit-mode/template-panel/hooks.js +71 -0
  36. package/build/components/sidebar-edit-mode/template-panel/hooks.js.map +1 -0
  37. package/build/components/sidebar-edit-mode/template-panel/pattern-categories.js +2 -2
  38. package/build/components/sidebar-edit-mode/template-panel/pattern-categories.js.map +1 -1
  39. package/build/components/sidebar-edit-mode/template-panel/replace-template-button.js +82 -0
  40. package/build/components/sidebar-edit-mode/template-panel/replace-template-button.js.map +1 -0
  41. package/build/components/sidebar-edit-mode/template-panel/template-actions.js +10 -3
  42. package/build/components/sidebar-edit-mode/template-panel/template-actions.js.map +1 -1
  43. package/build/components/sidebar-edit-mode/template-panel/template-areas.js +1 -1
  44. package/build/components/sidebar-edit-mode/template-panel/template-areas.js.map +1 -1
  45. package/build/components/sidebar-navigation-screen-pattern/template-part-navigation-menu-list-item.js +5 -3
  46. package/build/components/sidebar-navigation-screen-pattern/template-part-navigation-menu-list-item.js.map +1 -1
  47. package/build/components/sidebar-navigation-screen-pattern/template-part-navigation-menu.js +5 -4
  48. package/build/components/sidebar-navigation-screen-pattern/template-part-navigation-menu.js.map +1 -1
  49. package/build/components/sidebar-navigation-screen-pattern/use-navigation-menu-content.js +8 -1
  50. package/build/components/sidebar-navigation-screen-pattern/use-navigation-menu-content.js.map +1 -1
  51. package/build/components/sidebar-navigation-screen-pattern/use-navigation-menu-title.js +29 -0
  52. package/build/components/sidebar-navigation-screen-pattern/use-navigation-menu-title.js.map +1 -0
  53. package/build/components/sidebar-navigation-screen-patterns/index.js +14 -2
  54. package/build/components/sidebar-navigation-screen-patterns/index.js.map +1 -1
  55. package/build/components/sidebar-navigation-screen-template/home-template-details.js +13 -18
  56. package/build/components/sidebar-navigation-screen-template/home-template-details.js.map +1 -1
  57. package/build/components/sidebar-navigation-screen-templates-browse/index.js +16 -4
  58. package/build/components/sidebar-navigation-screen-templates-browse/index.js.map +1 -1
  59. package/build/store/selectors.js +4 -5
  60. package/build/store/selectors.js.map +1 -1
  61. package/build/utils/constants.js +1 -1
  62. package/build/utils/constants.js.map +1 -1
  63. package/build-module/components/add-new-pattern/index.js +7 -11
  64. package/build-module/components/add-new-pattern/index.js.map +1 -1
  65. package/build-module/components/global-styles/font-library-modal/collection-font-details.js +3 -1
  66. package/build-module/components/global-styles/font-library-modal/collection-font-details.js.map +1 -1
  67. package/build-module/components/global-styles/font-library-modal/context.js +26 -30
  68. package/build-module/components/global-styles/font-library-modal/context.js.map +1 -1
  69. package/build-module/components/global-styles/font-library-modal/font-collection.js +32 -12
  70. package/build-module/components/global-styles/font-library-modal/font-collection.js.map +1 -1
  71. package/build-module/components/global-styles/font-library-modal/index.js +10 -3
  72. package/build-module/components/global-styles/font-library-modal/index.js.map +1 -1
  73. package/build-module/components/global-styles/font-library-modal/installed-fonts.js +28 -8
  74. package/build-module/components/global-styles/font-library-modal/installed-fonts.js.map +1 -1
  75. package/build-module/components/global-styles/font-library-modal/local-fonts.js +38 -11
  76. package/build-module/components/global-styles/font-library-modal/local-fonts.js.map +1 -1
  77. package/build-module/components/global-styles/font-library-modal/resolvers.js +1 -1
  78. package/build-module/components/global-styles/font-library-modal/resolvers.js.map +1 -1
  79. package/build-module/components/global-styles/font-library-modal/upload-fonts.js +17 -0
  80. package/build-module/components/global-styles/font-library-modal/upload-fonts.js.map +1 -0
  81. package/build-module/components/global-styles/font-library-modal/utils/fonts-outline.js +4 -1
  82. package/build-module/components/global-styles/font-library-modal/utils/fonts-outline.js.map +1 -1
  83. package/build-module/components/global-styles/font-library-modal/utils/get-notice-from-response.js +63 -0
  84. package/build-module/components/global-styles/font-library-modal/utils/get-notice-from-response.js.map +1 -0
  85. package/build-module/components/global-styles/font-library-modal/utils/index.js +4 -1
  86. package/build-module/components/global-styles/font-library-modal/utils/index.js.map +1 -1
  87. package/build-module/components/page-patterns/grid.js +0 -1
  88. package/build-module/components/page-patterns/grid.js.map +1 -1
  89. package/build-module/components/page-patterns/patterns-list.js +1 -1
  90. package/build-module/components/page-patterns/patterns-list.js.map +1 -1
  91. package/build-module/components/page-patterns/use-patterns.js +5 -1
  92. package/build-module/components/page-patterns/use-patterns.js.map +1 -1
  93. package/build-module/components/page-template-parts/index.js +12 -1
  94. package/build-module/components/page-template-parts/index.js.map +1 -1
  95. package/build-module/components/sidebar-edit-mode/page-panels/reset-default-template.js +1 -1
  96. package/build-module/components/sidebar-edit-mode/page-panels/reset-default-template.js.map +1 -1
  97. package/build-module/components/sidebar-edit-mode/template-panel/hooks.js +64 -0
  98. package/build-module/components/sidebar-edit-mode/template-panel/hooks.js.map +1 -0
  99. package/build-module/components/sidebar-edit-mode/template-panel/pattern-categories.js +3 -3
  100. package/build-module/components/sidebar-edit-mode/template-panel/pattern-categories.js.map +1 -1
  101. package/build-module/components/sidebar-edit-mode/template-panel/replace-template-button.js +76 -0
  102. package/build-module/components/sidebar-edit-mode/template-panel/replace-template-button.js.map +1 -0
  103. package/build-module/components/sidebar-edit-mode/template-panel/template-actions.js +10 -3
  104. package/build-module/components/sidebar-edit-mode/template-panel/template-actions.js.map +1 -1
  105. package/build-module/components/sidebar-edit-mode/template-panel/template-areas.js +1 -1
  106. package/build-module/components/sidebar-edit-mode/template-panel/template-areas.js.map +1 -1
  107. package/build-module/components/sidebar-navigation-screen-pattern/template-part-navigation-menu-list-item.js +5 -3
  108. package/build-module/components/sidebar-navigation-screen-pattern/template-part-navigation-menu-list-item.js.map +1 -1
  109. package/build-module/components/sidebar-navigation-screen-pattern/template-part-navigation-menu.js +5 -4
  110. package/build-module/components/sidebar-navigation-screen-pattern/template-part-navigation-menu.js.map +1 -1
  111. package/build-module/components/sidebar-navigation-screen-pattern/use-navigation-menu-content.js +7 -1
  112. package/build-module/components/sidebar-navigation-screen-pattern/use-navigation-menu-content.js.map +1 -1
  113. package/build-module/components/sidebar-navigation-screen-pattern/use-navigation-menu-title.js +22 -0
  114. package/build-module/components/sidebar-navigation-screen-pattern/use-navigation-menu-title.js.map +1 -0
  115. package/build-module/components/sidebar-navigation-screen-patterns/index.js +14 -2
  116. package/build-module/components/sidebar-navigation-screen-patterns/index.js.map +1 -1
  117. package/build-module/components/sidebar-navigation-screen-template/home-template-details.js +14 -19
  118. package/build-module/components/sidebar-navigation-screen-template/home-template-details.js.map +1 -1
  119. package/build-module/components/sidebar-navigation-screen-templates-browse/index.js +16 -4
  120. package/build-module/components/sidebar-navigation-screen-templates-browse/index.js.map +1 -1
  121. package/build-module/store/selectors.js +4 -5
  122. package/build-module/store/selectors.js.map +1 -1
  123. package/build-module/utils/constants.js +1 -1
  124. package/build-module/utils/constants.js.map +1 -1
  125. package/build-style/style-rtl.css +35 -2
  126. package/build-style/style.css +35 -2
  127. package/package.json +40 -40
  128. package/src/components/add-new-pattern/index.js +7 -10
  129. package/src/components/global-styles/font-library-modal/collection-font-details.js +1 -1
  130. package/src/components/global-styles/font-library-modal/context.js +36 -38
  131. package/src/components/global-styles/font-library-modal/font-collection.js +41 -12
  132. package/src/components/global-styles/font-library-modal/index.js +16 -6
  133. package/src/components/global-styles/font-library-modal/installed-fonts.js +36 -6
  134. package/src/components/global-styles/font-library-modal/local-fonts.js +65 -23
  135. package/src/components/global-styles/font-library-modal/resolvers.js +1 -1
  136. package/src/components/global-styles/font-library-modal/style.scss +18 -1
  137. package/src/components/global-styles/font-library-modal/upload-fonts.js +20 -0
  138. package/src/components/global-styles/font-library-modal/utils/fonts-outline.js +4 -3
  139. package/src/components/global-styles/font-library-modal/utils/get-notice-from-response.js +62 -0
  140. package/src/components/global-styles/font-library-modal/utils/index.js +5 -1
  141. package/src/components/global-styles/font-library-modal/utils/test/makeFormDataFromFontFamilies.spec.js +1 -1
  142. package/src/components/page-patterns/grid.js +1 -1
  143. package/src/components/page-patterns/patterns-list.js +1 -1
  144. package/src/components/page-patterns/use-patterns.js +7 -3
  145. package/src/components/page-template-parts/index.js +14 -1
  146. package/src/components/sidebar-edit-mode/page-panels/reset-default-template.js +1 -1
  147. package/src/components/sidebar-edit-mode/template-panel/hooks.js +97 -0
  148. package/src/components/sidebar-edit-mode/template-panel/pattern-categories.js +18 -16
  149. package/src/components/sidebar-edit-mode/template-panel/replace-template-button.js +89 -0
  150. package/src/components/sidebar-edit-mode/template-panel/style.scss +18 -0
  151. package/src/components/sidebar-edit-mode/template-panel/template-actions.js +27 -12
  152. package/src/components/sidebar-edit-mode/template-panel/template-areas.js +1 -1
  153. package/src/components/sidebar-navigation-screen/style.scss +0 -1
  154. package/src/components/sidebar-navigation-screen-pattern/template-part-navigation-menu-list-item.js +5 -8
  155. package/src/components/sidebar-navigation-screen-pattern/template-part-navigation-menu.js +5 -9
  156. package/src/components/sidebar-navigation-screen-pattern/use-navigation-menu-content.js +11 -5
  157. package/src/components/sidebar-navigation-screen-pattern/use-navigation-menu-title.js +32 -0
  158. package/src/components/sidebar-navigation-screen-patterns/index.js +25 -4
  159. package/src/components/sidebar-navigation-screen-template/home-template-details.js +27 -35
  160. package/src/components/sidebar-navigation-screen-templates-browse/index.js +12 -4
  161. package/src/store/selectors.js +9 -10
  162. package/src/utils/constants.js +1 -1
@@ -0,0 +1,62 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { __ } from '@wordpress/i18n';
5
+
6
+ export function getNoticeFromInstallResponse( response ) {
7
+ const { errors = [], successes = [] } = response;
8
+ // Everything failed.
9
+ if ( errors.length && ! successes.length ) {
10
+ return {
11
+ type: 'error',
12
+ message: __( 'Error installing the fonts.' ),
13
+ };
14
+ }
15
+
16
+ // Eveerything succeeded.
17
+ if ( ! errors.length && successes.length ) {
18
+ return {
19
+ type: 'success',
20
+ message: __( 'Fonts were installed successfully.' ),
21
+ };
22
+ }
23
+
24
+ // Some succeeded, some failed.
25
+ if ( errors.length && successes.length ) {
26
+ return {
27
+ type: 'warning',
28
+ message: __(
29
+ 'Some fonts were installed successfully and some failed.'
30
+ ),
31
+ };
32
+ }
33
+ }
34
+
35
+ export function getNoticeFromUninstallResponse( response ) {
36
+ const { errors = [], successes = [] } = response;
37
+ // Everything failed.
38
+ if ( errors.length && ! successes.length ) {
39
+ return {
40
+ type: 'error',
41
+ message: __( 'Error uninstalling the fonts.' ),
42
+ };
43
+ }
44
+
45
+ // Everything succeeded.
46
+ if ( ! errors.length && successes.length ) {
47
+ return {
48
+ type: 'success',
49
+ message: __( 'Fonts were uninstalled successfully.' ),
50
+ };
51
+ }
52
+
53
+ // Some succeeded, some failed.
54
+ if ( errors.length && successes.length ) {
55
+ return {
56
+ type: 'warning',
57
+ message: __(
58
+ 'Some fonts were uninstalled successfully and some failed.'
59
+ ),
60
+ };
61
+ }
62
+ }
@@ -109,6 +109,10 @@ export async function loadFontFaceInBrowser( fontFace, source, addTo = 'all' ) {
109
109
  }
110
110
 
111
111
  export function getDisplaySrcFromFontFace( input, urlPrefix ) {
112
+ if ( ! input ) {
113
+ return;
114
+ }
115
+
112
116
  let src;
113
117
  if ( Array.isArray( input ) ) {
114
118
  src = input[ 0 ];
@@ -148,6 +152,6 @@ export function makeFormDataFromFontFamilies( fontFamilies ) {
148
152
  }
149
153
  return family;
150
154
  } );
151
- formData.append( 'fontFamilies', JSON.stringify( newFontFamilies ) );
155
+ formData.append( 'font_families', JSON.stringify( newFontFamilies ) );
152
156
  return formData;
153
157
  }
@@ -55,7 +55,7 @@ describe( 'makeFormDataFromFontFamilies', () => {
55
55
  fontFamily: 'Bebas',
56
56
  },
57
57
  ];
58
- expect( JSON.parse( formData.get( 'fontFamilies' ) ) ).toEqual(
58
+ expect( JSON.parse( formData.get( 'font_families' ) ) ).toEqual(
59
59
  expectedFontFamilies
60
60
  );
61
61
  } );
@@ -9,7 +9,7 @@ export default function Grid( { categoryId, items, ...props } ) {
9
9
  }
10
10
 
11
11
  return (
12
- <ul role="listbox" className="edit-site-patterns__grid" { ...props }>
12
+ <ul className="edit-site-patterns__grid" { ...props }>
13
13
  { items.map( ( item ) => (
14
14
  <GridItem
15
15
  key={ item.name }
@@ -35,7 +35,7 @@ const { useLocation, useHistory } = unlock( routerPrivateApis );
35
35
  const SYNC_FILTERS = {
36
36
  all: __( 'All' ),
37
37
  [ PATTERN_SYNC_TYPES.full ]: __( 'Synced' ),
38
- [ PATTERN_SYNC_TYPES.unsynced ]: __( 'Standard' ),
38
+ [ PATTERN_SYNC_TYPES.unsynced ]: __( 'Not synced' ),
39
39
  };
40
40
 
41
41
  const SYNC_DESCRIPTIONS = {
@@ -155,9 +155,13 @@ const selectPatterns = createSelector(
155
155
  ];
156
156
 
157
157
  if ( syncStatus ) {
158
- patterns = patterns.filter(
159
- ( pattern ) => pattern.syncStatus === syncStatus
160
- );
158
+ // User patterns can have their sync statuses checked directly
159
+ // Non-user patterns are all unsynced for the time being.
160
+ patterns = patterns.filter( ( pattern ) => {
161
+ return pattern.id
162
+ ? pattern.syncStatus === syncStatus
163
+ : syncStatus === PATTERN_SYNC_TYPES.unsynced;
164
+ } );
161
165
  }
162
166
 
163
167
  if ( categoryId ) {
@@ -9,6 +9,7 @@ import {
9
9
  import { __ } from '@wordpress/i18n';
10
10
  import { useEntityRecords } from '@wordpress/core-data';
11
11
  import { decodeEntities } from '@wordpress/html-entities';
12
+ import { privateApis as routerPrivateApis } from '@wordpress/router';
12
13
 
13
14
  /**
14
15
  * Internal dependencies
@@ -20,8 +21,15 @@ import AddedBy from '../list/added-by';
20
21
  import TemplateActions from '../template-actions';
21
22
  import AddNewTemplatePart from './add-new-template-part';
22
23
  import { TEMPLATE_PART_POST_TYPE } from '../../utils/constants';
24
+ import { unlock } from '../../lock-unlock';
25
+
26
+ const { useLocation } = unlock( routerPrivateApis );
23
27
 
24
28
  export default function PageTemplateParts() {
29
+ const {
30
+ params: { didAccessPatternsPage },
31
+ } = useLocation();
32
+
25
33
  const { records: templateParts } = useEntityRecords(
26
34
  'postType',
27
35
  TEMPLATE_PART_POST_TYPE,
@@ -40,8 +48,13 @@ export default function PageTemplateParts() {
40
48
  params={ {
41
49
  postId: templatePart.id,
42
50
  postType: templatePart.type,
51
+ didAccessPatternsPage: !! didAccessPatternsPage
52
+ ? 1
53
+ : undefined,
54
+ } }
55
+ state={ {
56
+ backPath: '/wp_template_part/all',
43
57
  } }
44
- state={ { backPath: '/wp_template_part/all' } }
45
58
  >
46
59
  { decodeEntities(
47
60
  templatePart.title?.rendered ||
@@ -37,7 +37,7 @@ export default function ResetDefaultTemplate( { onClick } ) {
37
37
  } );
38
38
  } }
39
39
  >
40
- { __( 'Reset' ) }
40
+ { __( 'Use default template' ) }
41
41
  </MenuItem>
42
42
  </MenuGroup>
43
43
  );
@@ -0,0 +1,97 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useSelect } from '@wordpress/data';
5
+ import { useMemo } from '@wordpress/element';
6
+ import { store as coreStore } from '@wordpress/core-data';
7
+ import { parse } from '@wordpress/blocks';
8
+
9
+ /**
10
+ * Internal dependencies
11
+ */
12
+ import { store as editSiteStore } from '../../../store';
13
+ import { PATTERN_CORE_SOURCES, PATTERN_TYPES } from '../../../utils/constants';
14
+ import { unlock } from '../../../lock-unlock';
15
+
16
+ function injectThemeAttributeInBlockTemplateContent(
17
+ block,
18
+ currentThemeStylesheet
19
+ ) {
20
+ block.innerBlocks = block.innerBlocks.map( ( innerBlock ) => {
21
+ return injectThemeAttributeInBlockTemplateContent(
22
+ innerBlock,
23
+ currentThemeStylesheet
24
+ );
25
+ } );
26
+
27
+ if (
28
+ block.name === 'core/template-part' &&
29
+ block.attributes.theme === undefined
30
+ ) {
31
+ block.attributes.theme = currentThemeStylesheet;
32
+ }
33
+ return block;
34
+ }
35
+
36
+ function preparePatterns( patterns, template, currentThemeStylesheet ) {
37
+ // Filter out duplicates.
38
+ const filterOutDuplicatesByName = ( currentItem, index, items ) =>
39
+ index === items.findIndex( ( item ) => currentItem.name === item.name );
40
+
41
+ // Filter out core patterns.
42
+ const filterOutCorePatterns = ( pattern ) =>
43
+ ! PATTERN_CORE_SOURCES.includes( pattern.source );
44
+
45
+ // Filter only the patterns that are compatible with the current template.
46
+ const filterCompatiblePatterns = ( pattern ) =>
47
+ pattern.templateTypes?.includes( template.slug );
48
+
49
+ return patterns
50
+ .filter(
51
+ filterOutCorePatterns &&
52
+ filterOutDuplicatesByName &&
53
+ filterCompatiblePatterns
54
+ )
55
+ .map( ( pattern ) => ( {
56
+ ...pattern,
57
+ keywords: pattern.keywords || [],
58
+ type: PATTERN_TYPES.theme,
59
+ blocks: parse( pattern.content, {
60
+ __unstableSkipMigrationLogs: true,
61
+ } ).map( ( block ) =>
62
+ injectThemeAttributeInBlockTemplateContent(
63
+ block,
64
+ currentThemeStylesheet
65
+ )
66
+ ),
67
+ } ) );
68
+ }
69
+
70
+ export function useAvailablePatterns( template ) {
71
+ const { blockPatterns, restBlockPatterns, currentThemeStylesheet } =
72
+ useSelect( ( select ) => {
73
+ const { getSettings } = unlock( select( editSiteStore ) );
74
+ const settings = getSettings();
75
+
76
+ return {
77
+ blockPatterns:
78
+ settings.__experimentalAdditionalBlockPatterns ??
79
+ settings.__experimentalBlockPatterns,
80
+ restBlockPatterns: select( coreStore ).getBlockPatterns(),
81
+ currentThemeStylesheet:
82
+ select( coreStore ).getCurrentTheme().stylesheet,
83
+ };
84
+ }, [] );
85
+
86
+ return useMemo( () => {
87
+ const mergedPatterns = [
88
+ ...( blockPatterns || [] ),
89
+ ...( restBlockPatterns || [] ),
90
+ ];
91
+ return preparePatterns(
92
+ mergedPatterns,
93
+ template,
94
+ currentThemeStylesheet
95
+ );
96
+ }, [ blockPatterns, restBlockPatterns, template, currentThemeStylesheet ] );
97
+ }
@@ -3,7 +3,7 @@
3
3
  */
4
4
  import { __, _x, sprintf } from '@wordpress/i18n';
5
5
  import { useEffect, useMemo, useState } from '@wordpress/element';
6
- import { FormTokenField, PanelRow } from '@wordpress/components';
6
+ import { FormTokenField, FlexBlock, PanelRow } from '@wordpress/components';
7
7
  import { useSelect, useDispatch } from '@wordpress/data';
8
8
  import { store as coreStore } from '@wordpress/core-data';
9
9
  import { useDebounce } from '@wordpress/compose';
@@ -257,21 +257,23 @@ export default function PatternCategories( { post } ) {
257
257
 
258
258
  return (
259
259
  <PanelRow initialOpen={ true } title={ __( 'Categories' ) }>
260
- <FormTokenField
261
- __next40pxDefaultSize
262
- value={ values }
263
- suggestions={ suggestions }
264
- onChange={ onChange }
265
- onInputChange={ debouncedSearch }
266
- maxSuggestions={ MAX_TERMS_SUGGESTIONS }
267
- label={ __( 'Pattern categories' ) }
268
- messages={ {
269
- added: termAddedLabel,
270
- removed: termRemovedLabel,
271
- remove: removeTermLabel,
272
- } }
273
- tokenizeOnBlur
274
- />
260
+ <FlexBlock>
261
+ <FormTokenField
262
+ __next40pxDefaultSize
263
+ value={ values }
264
+ suggestions={ suggestions }
265
+ onChange={ onChange }
266
+ onInputChange={ debouncedSearch }
267
+ maxSuggestions={ MAX_TERMS_SUGGESTIONS }
268
+ label={ __( 'Pattern categories' ) }
269
+ messages={ {
270
+ added: termAddedLabel,
271
+ removed: termRemovedLabel,
272
+ remove: removeTermLabel,
273
+ } }
274
+ tokenizeOnBlur
275
+ />
276
+ </FlexBlock>
275
277
  </PanelRow>
276
278
  );
277
279
  }
@@ -0,0 +1,89 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useSelect, useDispatch } from '@wordpress/data';
5
+ import { useState } from '@wordpress/element';
6
+ import { __experimentalBlockPatternsList as BlockPatternsList } from '@wordpress/block-editor';
7
+ import { MenuItem, Modal } from '@wordpress/components';
8
+ import { __ } from '@wordpress/i18n';
9
+ import { store as coreStore } from '@wordpress/core-data';
10
+ import { useAsyncList } from '@wordpress/compose';
11
+ import { serialize } from '@wordpress/blocks';
12
+
13
+ /**
14
+ * Internal dependencies
15
+ */
16
+ import { store as editSiteStore } from '../../../store';
17
+
18
+ export default function ReplaceTemplateButton( {
19
+ onClick,
20
+ availableTemplates,
21
+ } ) {
22
+ const { editEntityRecord } = useDispatch( coreStore );
23
+ const [ showModal, setShowModal ] = useState( false );
24
+ const onClose = () => {
25
+ setShowModal( false );
26
+ };
27
+
28
+ const { postId, postType } = useSelect( ( select ) => {
29
+ return {
30
+ postId: select( editSiteStore ).getEditedPostId(),
31
+ postType: select( editSiteStore ).getEditedPostType(),
32
+ };
33
+ }, [] );
34
+
35
+ const onTemplateSelect = async ( selectedTemplate ) => {
36
+ onClose(); // Close the template suggestions modal first.
37
+ onClick();
38
+ await editEntityRecord( 'postType', postType, postId, {
39
+ blocks: selectedTemplate.blocks,
40
+ content: serialize( selectedTemplate.blocks ),
41
+ } );
42
+ };
43
+
44
+ if ( ! availableTemplates.length || availableTemplates.length < 1 ) {
45
+ return null;
46
+ }
47
+
48
+ return (
49
+ <>
50
+ <MenuItem
51
+ info={ __(
52
+ 'Replace the contents of this template with another.'
53
+ ) }
54
+ onClick={ () => setShowModal( true ) }
55
+ >
56
+ { __( 'Replace template' ) }
57
+ </MenuItem>
58
+
59
+ { showModal && (
60
+ <Modal
61
+ title={ __( 'Choose a template' ) }
62
+ onRequestClose={ onClose }
63
+ overlayClassName="edit-site-template-panel__replace-template-modal"
64
+ isFullScreen
65
+ >
66
+ <div className="edit-site-template-panel__replace-template-modal__content">
67
+ <TemplatesList
68
+ availableTemplates={ availableTemplates }
69
+ onSelect={ onTemplateSelect }
70
+ />
71
+ </div>
72
+ </Modal>
73
+ ) }
74
+ </>
75
+ );
76
+ }
77
+
78
+ function TemplatesList( { availableTemplates, onSelect } ) {
79
+ const shownTemplates = useAsyncList( availableTemplates );
80
+
81
+ return (
82
+ <BlockPatternsList
83
+ label={ __( 'Templates' ) }
84
+ blockPatterns={ availableTemplates }
85
+ shownPatterns={ shownTemplates }
86
+ onClickPattern={ onSelect }
87
+ />
88
+ );
89
+ }
@@ -37,3 +37,21 @@ h3.edit-site-template-card__template-areas-title {
37
37
  font-weight: 500;
38
38
  margin: 0 0 $grid-unit-10;
39
39
  }
40
+
41
+
42
+ .edit-site-template-panel__replace-template-modal {
43
+ z-index: z-index(".edit-site-template-panel__replace-template-modal");
44
+ }
45
+
46
+ .edit-site-template-panel__replace-template-modal__content {
47
+ column-count: 2;
48
+ column-gap: $grid-unit-30;
49
+
50
+ @include break-medium() {
51
+ column-count: 3;
52
+ }
53
+
54
+ @include break-wide() {
55
+ column-count: 4;
56
+ }
57
+ }
@@ -11,13 +11,21 @@ import { moreVertical } from '@wordpress/icons';
11
11
  */
12
12
  import { store as editSiteStore } from '../../../store';
13
13
  import isTemplateRevertable from '../../../utils/is-template-revertable';
14
+ import ReplaceTemplateButton from './replace-template-button';
15
+ import { useAvailablePatterns } from './hooks';
14
16
 
15
17
  export default function Actions( { template } ) {
18
+ const availablePatterns = useAvailablePatterns( template );
16
19
  const { revertTemplate } = useDispatch( editSiteStore );
17
20
  const isRevertable = isTemplateRevertable( template );
18
- if ( ! isRevertable ) {
21
+
22
+ if (
23
+ ! isRevertable &&
24
+ ( ! availablePatterns.length || availablePatterns.length < 1 )
25
+ ) {
19
26
  return null;
20
27
  }
28
+
21
29
  return (
22
30
  <DropdownMenu
23
31
  icon={ moreVertical }
@@ -27,17 +35,24 @@ export default function Actions( { template } ) {
27
35
  >
28
36
  { ( { onClose } ) => (
29
37
  <MenuGroup>
30
- <MenuItem
31
- info={ __(
32
- 'Use the template as supplied by the theme.'
33
- ) }
34
- onClick={ () => {
35
- revertTemplate( template );
36
- onClose();
37
- } }
38
- >
39
- { __( 'Clear customizations' ) }
40
- </MenuItem>
38
+ { isRevertable && (
39
+ <MenuItem
40
+ info={ __(
41
+ 'Use the template as supplied by the theme.'
42
+ ) }
43
+ onClick={ () => {
44
+ revertTemplate( template );
45
+ onClose();
46
+ } }
47
+ >
48
+ { __( 'Clear customizations' ) }
49
+ </MenuItem>
50
+ ) }
51
+ <ReplaceTemplateButton
52
+ availableTemplates={ availablePatterns }
53
+ template={ template }
54
+ onClick={ onClose }
55
+ />
41
56
  </MenuGroup>
42
57
  ) }
43
58
  </DropdownMenu>
@@ -73,7 +73,7 @@ export default function TemplateAreas() {
73
73
 
74
74
  <ul className="edit-site-template-card__template-areas-list">
75
75
  { templateParts.map( ( { templatePart, block } ) => (
76
- <li key={ templatePart.slug }>
76
+ <li key={ block.clientId }>
77
77
  <TemplateAreaItem
78
78
  area={ templatePart.area }
79
79
  clientId={ block.clientId }
@@ -68,7 +68,6 @@
68
68
  .edit-site-sidebar-navigation-screen__title {
69
69
  flex-grow: 1;
70
70
  padding: $grid-unit-15 * 0.5 0 0 0;
71
- overflow: hidden;
72
71
  overflow-wrap: break-word;
73
72
  }
74
73
 
@@ -1,30 +1,27 @@
1
1
  /**
2
2
  * WordPress dependencies
3
3
  */
4
- import { useEntityProp } from '@wordpress/core-data';
5
4
  import { __ } from '@wordpress/i18n';
6
5
 
7
6
  /**
8
7
  * Internal dependencies
9
8
  */
10
9
  import SidebarNavigationItem from '../sidebar-navigation-item';
10
+ import useNavigationMenuTitle from './use-navigation-menu-title';
11
11
  import { useLink } from '../routes/link';
12
12
  import { NAVIGATION_POST_TYPE } from '../../utils/constants';
13
13
 
14
14
  export default function TemplatePartNavigationMenuListItem( { id } ) {
15
- const [ title ] = useEntityProp(
16
- 'postType',
17
- NAVIGATION_POST_TYPE,
18
- 'title',
19
- id
20
- );
15
+ const title = useNavigationMenuTitle( id );
21
16
 
22
17
  const linkInfo = useLink( {
23
18
  postId: id,
24
19
  postType: NAVIGATION_POST_TYPE,
25
20
  } );
26
21
 
27
- if ( ! id ) return null;
22
+ if ( ! id || title === undefined ) {
23
+ return null;
24
+ }
28
25
 
29
26
  return (
30
27
  <SidebarNavigationItem withChevron { ...linkInfo }>
@@ -3,23 +3,19 @@
3
3
  */
4
4
  import { __ } from '@wordpress/i18n';
5
5
  import { __experimentalHeading as Heading } from '@wordpress/components';
6
- import { useEntityProp } from '@wordpress/core-data';
7
6
 
8
7
  /**
9
8
  * Internal dependencies
10
9
  */
11
10
  import NavigationMenuEditor from '../sidebar-navigation-screen-navigation-menu/navigation-menu-editor';
12
- import { NAVIGATION_POST_TYPE } from '../../utils/constants';
11
+ import useNavigationMenuTitle from './use-navigation-menu-title';
13
12
 
14
13
  export default function TemplatePartNavigationMenu( { id } ) {
15
- const [ title ] = useEntityProp(
16
- 'postType',
17
- NAVIGATION_POST_TYPE,
18
- 'title',
19
- id
20
- );
14
+ const title = useNavigationMenuTitle( id );
21
15
 
22
- if ( ! id ) return null;
16
+ if ( ! id || title === undefined ) {
17
+ return null;
18
+ }
23
19
 
24
20
  return (
25
21
  <>
@@ -10,6 +10,16 @@ import TemplatePartNavigationMenus from './template-part-navigation-menus';
10
10
  import useEditedEntityRecord from '../use-edited-entity-record';
11
11
  import { TEMPLATE_PART_POST_TYPE } from '../../utils/constants';
12
12
 
13
+ function getBlocksFromRecord( record ) {
14
+ if ( record?.blocks ) {
15
+ return record?.blocks;
16
+ }
17
+
18
+ return record?.content && typeof record.content !== 'function'
19
+ ? parse( record.content )
20
+ : [];
21
+ }
22
+
13
23
  /**
14
24
  * Retrieves a list of specific blocks from a given tree of blocks.
15
25
  *
@@ -60,11 +70,7 @@ export default function useNavigationMenuContent( postType, postId ) {
60
70
  return;
61
71
  }
62
72
 
63
- const blocks =
64
- record?.content && typeof record.content !== 'function'
65
- ? parse( record.content )
66
- : [];
67
-
73
+ const blocks = getBlocksFromRecord( record );
68
74
  const navigationBlocks = getBlocksOfTypeFromBlocks(
69
75
  'core/navigation',
70
76
  blocks
@@ -0,0 +1,32 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useSelect } from '@wordpress/data';
5
+ import { store as coreStore } from '@wordpress/core-data';
6
+
7
+ /**
8
+ * Internal dependencies
9
+ */
10
+ import { NAVIGATION_POST_TYPE } from '../../utils/constants';
11
+
12
+ export default function useNavigationMenuTitle( id ) {
13
+ return useSelect(
14
+ ( select ) => {
15
+ if ( ! id ) {
16
+ return undefined;
17
+ }
18
+
19
+ const editedRecord = select( coreStore ).getEditedEntityRecord(
20
+ 'postType',
21
+ NAVIGATION_POST_TYPE,
22
+ id
23
+ );
24
+
25
+ // Do not display a 'trashed' navigation menu.
26
+ return editedRecord.status === 'trash'
27
+ ? undefined
28
+ : editedRecord.title;
29
+ },
30
+ [ id ]
31
+ );
32
+ }