@wordpress/edit-site 5.12.7 → 5.12.9

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 (166) hide show
  1. package/build/components/block-editor/editor-canvas.js +1 -1
  2. package/build/components/block-editor/editor-canvas.js.map +1 -1
  3. package/build/components/block-editor/index.js +0 -4
  4. package/build/components/block-editor/index.js.map +1 -1
  5. package/build/components/block-editor/use-site-editor-settings.js +12 -6
  6. package/build/components/block-editor/use-site-editor-settings.js.map +1 -1
  7. package/build/components/create-pattern-modal/index.js +7 -3
  8. package/build/components/create-pattern-modal/index.js.map +1 -1
  9. package/build/components/page-patterns/duplicate-menu-item.js +163 -0
  10. package/build/components/page-patterns/duplicate-menu-item.js.map +1 -0
  11. package/build/components/page-patterns/grid-item.js +83 -59
  12. package/build/components/page-patterns/grid-item.js.map +1 -1
  13. package/build/components/page-patterns/grid.js +81 -13
  14. package/build/components/page-patterns/grid.js.map +1 -1
  15. package/build/components/page-patterns/header.js +69 -0
  16. package/build/components/page-patterns/header.js.map +1 -0
  17. package/build/components/page-patterns/index.js +3 -1
  18. package/build/components/page-patterns/index.js.map +1 -1
  19. package/build/components/page-patterns/patterns-list.js +66 -27
  20. package/build/components/page-patterns/patterns-list.js.map +1 -1
  21. package/build/components/page-patterns/rename-menu-item.js +109 -0
  22. package/build/components/page-patterns/rename-menu-item.js.map +1 -0
  23. package/build/components/page-patterns/use-patterns.js +99 -118
  24. package/build/components/page-patterns/use-patterns.js.map +1 -1
  25. package/build/components/page-template-parts/add-new-template-part.js +74 -0
  26. package/build/components/page-template-parts/add-new-template-part.js.map +1 -0
  27. package/build/components/page-template-parts/index.js +2 -23
  28. package/build/components/page-template-parts/index.js.map +1 -1
  29. package/build/components/resizable-frame/index.js +75 -32
  30. package/build/components/resizable-frame/index.js.map +1 -1
  31. package/build/components/sidebar-navigation-screen/index.js +14 -8
  32. package/build/components/sidebar-navigation-screen/index.js.map +1 -1
  33. package/build/components/sidebar-navigation-screen-main/template-part-hint.js +1 -1
  34. package/build/components/sidebar-navigation-screen-main/template-part-hint.js.map +1 -1
  35. package/build/components/sidebar-navigation-screen-navigation-menu/more-menu.js +1 -0
  36. package/build/components/sidebar-navigation-screen-navigation-menu/more-menu.js.map +1 -1
  37. package/build/components/sidebar-navigation-screen-navigation-menu/single-navigation-menu.js +3 -3
  38. package/build/components/sidebar-navigation-screen-navigation-menu/single-navigation-menu.js.map +1 -1
  39. package/build/components/sidebar-navigation-screen-page/status-label.js +1 -34
  40. package/build/components/sidebar-navigation-screen-page/status-label.js.map +1 -1
  41. package/build/components/sidebar-navigation-screen-pages/index.js +33 -25
  42. package/build/components/sidebar-navigation-screen-pages/index.js.map +1 -1
  43. package/build/components/sidebar-navigation-screen-pattern/template-part-navigation-menu.js +3 -2
  44. package/build/components/sidebar-navigation-screen-pattern/template-part-navigation-menu.js.map +1 -1
  45. package/build/components/sidebar-navigation-screen-pattern/template-part-navigation-menus.js +3 -2
  46. package/build/components/sidebar-navigation-screen-pattern/template-part-navigation-menus.js.map +1 -1
  47. package/build/components/sidebar-navigation-screen-patterns/index.js +5 -6
  48. package/build/components/sidebar-navigation-screen-patterns/index.js.map +1 -1
  49. package/build/components/sidebar-navigation-screen-patterns/use-my-patterns.js +9 -5
  50. package/build/components/sidebar-navigation-screen-patterns/use-my-patterns.js.map +1 -1
  51. package/build/components/site-hub/index.js +4 -2
  52. package/build/components/site-hub/index.js.map +1 -1
  53. package/build/components/sync-state-with-url/use-sync-path-with-url.js +15 -12
  54. package/build/components/sync-state-with-url/use-sync-path-with-url.js.map +1 -1
  55. package/build/components/template-actions/index.js +3 -1
  56. package/build/components/template-actions/index.js.map +1 -1
  57. package/build/components/template-actions/rename-menu-item.js +9 -6
  58. package/build/components/template-actions/rename-menu-item.js.map +1 -1
  59. package/build/hooks/push-changes-to-global-styles/index.js +3 -1
  60. package/build/hooks/push-changes-to-global-styles/index.js.map +1 -1
  61. package/build/utils/use-activate-theme.js +1 -1
  62. package/build/utils/use-activate-theme.js.map +1 -1
  63. package/build-module/components/block-editor/editor-canvas.js +1 -1
  64. package/build-module/components/block-editor/editor-canvas.js.map +1 -1
  65. package/build-module/components/block-editor/index.js +0 -4
  66. package/build-module/components/block-editor/index.js.map +1 -1
  67. package/build-module/components/block-editor/use-site-editor-settings.js +13 -7
  68. package/build-module/components/block-editor/use-site-editor-settings.js.map +1 -1
  69. package/build-module/components/create-pattern-modal/index.js +6 -3
  70. package/build-module/components/create-pattern-modal/index.js.map +1 -1
  71. package/build-module/components/page-patterns/duplicate-menu-item.js +147 -0
  72. package/build-module/components/page-patterns/duplicate-menu-item.js.map +1 -0
  73. package/build-module/components/page-patterns/grid-item.js +84 -65
  74. package/build-module/components/page-patterns/grid-item.js.map +1 -1
  75. package/build-module/components/page-patterns/grid.js +82 -15
  76. package/build-module/components/page-patterns/grid.js.map +1 -1
  77. package/build-module/components/page-patterns/header.js +54 -0
  78. package/build-module/components/page-patterns/header.js.map +1 -0
  79. package/build-module/components/page-patterns/index.js +3 -1
  80. package/build-module/components/page-patterns/index.js.map +1 -1
  81. package/build-module/components/page-patterns/patterns-list.js +68 -30
  82. package/build-module/components/page-patterns/patterns-list.js.map +1 -1
  83. package/build-module/components/page-patterns/rename-menu-item.js +97 -0
  84. package/build-module/components/page-patterns/rename-menu-item.js.map +1 -0
  85. package/build-module/components/page-patterns/use-patterns.js +100 -119
  86. package/build-module/components/page-patterns/use-patterns.js.map +1 -1
  87. package/build-module/components/page-template-parts/add-new-template-part.js +58 -0
  88. package/build-module/components/page-template-parts/add-new-template-part.js.map +1 -0
  89. package/build-module/components/page-template-parts/index.js +3 -22
  90. package/build-module/components/page-template-parts/index.js.map +1 -1
  91. package/build-module/components/resizable-frame/index.js +76 -35
  92. package/build-module/components/resizable-frame/index.js.map +1 -1
  93. package/build-module/components/sidebar-navigation-screen/index.js +15 -9
  94. package/build-module/components/sidebar-navigation-screen/index.js.map +1 -1
  95. package/build-module/components/sidebar-navigation-screen-main/template-part-hint.js +1 -1
  96. package/build-module/components/sidebar-navigation-screen-main/template-part-hint.js.map +1 -1
  97. package/build-module/components/sidebar-navigation-screen-navigation-menu/more-menu.js +1 -0
  98. package/build-module/components/sidebar-navigation-screen-navigation-menu/more-menu.js.map +1 -1
  99. package/build-module/components/sidebar-navigation-screen-navigation-menu/single-navigation-menu.js +3 -3
  100. package/build-module/components/sidebar-navigation-screen-navigation-menu/single-navigation-menu.js.map +1 -1
  101. package/build-module/components/sidebar-navigation-screen-page/status-label.js +1 -32
  102. package/build-module/components/sidebar-navigation-screen-page/status-label.js.map +1 -1
  103. package/build-module/components/sidebar-navigation-screen-pages/index.js +33 -25
  104. package/build-module/components/sidebar-navigation-screen-pages/index.js.map +1 -1
  105. package/build-module/components/sidebar-navigation-screen-pattern/template-part-navigation-menu.js +3 -2
  106. package/build-module/components/sidebar-navigation-screen-pattern/template-part-navigation-menu.js.map +1 -1
  107. package/build-module/components/sidebar-navigation-screen-pattern/template-part-navigation-menus.js +3 -2
  108. package/build-module/components/sidebar-navigation-screen-pattern/template-part-navigation-menus.js.map +1 -1
  109. package/build-module/components/sidebar-navigation-screen-patterns/index.js +5 -6
  110. package/build-module/components/sidebar-navigation-screen-patterns/index.js.map +1 -1
  111. package/build-module/components/sidebar-navigation-screen-patterns/use-my-patterns.js +9 -5
  112. package/build-module/components/sidebar-navigation-screen-patterns/use-my-patterns.js.map +1 -1
  113. package/build-module/components/site-hub/index.js +4 -2
  114. package/build-module/components/site-hub/index.js.map +1 -1
  115. package/build-module/components/sync-state-with-url/use-sync-path-with-url.js +16 -12
  116. package/build-module/components/sync-state-with-url/use-sync-path-with-url.js.map +1 -1
  117. package/build-module/components/template-actions/index.js +2 -1
  118. package/build-module/components/template-actions/index.js.map +1 -1
  119. package/build-module/components/template-actions/rename-menu-item.js +8 -6
  120. package/build-module/components/template-actions/rename-menu-item.js.map +1 -1
  121. package/build-module/hooks/push-changes-to-global-styles/index.js +4 -2
  122. package/build-module/hooks/push-changes-to-global-styles/index.js.map +1 -1
  123. package/build-module/utils/use-activate-theme.js +1 -1
  124. package/build-module/utils/use-activate-theme.js.map +1 -1
  125. package/build-style/style-rtl.css +150 -54
  126. package/build-style/style.css +150 -54
  127. package/package.json +14 -14
  128. package/src/components/block-editor/editor-canvas.js +1 -1
  129. package/src/components/block-editor/index.js +0 -4
  130. package/src/components/block-editor/use-site-editor-settings.js +16 -11
  131. package/src/components/create-pattern-modal/index.js +5 -2
  132. package/src/components/header-edit-mode/document-actions/style.scss +4 -0
  133. package/src/components/layout/style.scss +1 -0
  134. package/src/components/page-patterns/duplicate-menu-item.js +196 -0
  135. package/src/components/page-patterns/grid-item.js +187 -137
  136. package/src/components/page-patterns/grid.js +118 -20
  137. package/src/components/page-patterns/header.js +69 -0
  138. package/src/components/page-patterns/index.js +6 -1
  139. package/src/components/page-patterns/patterns-list.js +87 -46
  140. package/src/components/page-patterns/rename-menu-item.js +115 -0
  141. package/src/components/page-patterns/style.scss +106 -26
  142. package/src/components/page-patterns/use-patterns.js +96 -167
  143. package/src/components/page-template-parts/add-new-template-part.js +57 -0
  144. package/src/components/page-template-parts/index.js +3 -22
  145. package/src/components/resizable-frame/index.js +100 -31
  146. package/src/components/resizable-frame/style.scss +26 -9
  147. package/src/components/sidebar-navigation-item/style.scss +10 -1
  148. package/src/components/sidebar-navigation-screen/index.js +14 -7
  149. package/src/components/sidebar-navigation-screen-main/template-part-hint.js +1 -3
  150. package/src/components/sidebar-navigation-screen-navigation-menu/more-menu.js +1 -0
  151. package/src/components/sidebar-navigation-screen-navigation-menu/single-navigation-menu.js +1 -1
  152. package/src/components/sidebar-navigation-screen-page/status-label.js +1 -35
  153. package/src/components/sidebar-navigation-screen-pages/index.js +39 -29
  154. package/src/components/sidebar-navigation-screen-pattern/template-part-navigation-menu.js +2 -1
  155. package/src/components/sidebar-navigation-screen-pattern/template-part-navigation-menus.js +2 -1
  156. package/src/components/sidebar-navigation-screen-patterns/index.js +20 -24
  157. package/src/components/sidebar-navigation-screen-patterns/style.scss +0 -3
  158. package/src/components/sidebar-navigation-screen-patterns/use-my-patterns.js +7 -6
  159. package/src/components/site-hub/index.js +6 -2
  160. package/src/components/site-hub/style.scss +5 -0
  161. package/src/components/sync-state-with-url/use-sync-path-with-url.js +73 -66
  162. package/src/components/template-actions/index.js +2 -1
  163. package/src/components/template-actions/rename-menu-item.js +8 -6
  164. package/src/hooks/push-changes-to-global-styles/index.js +8 -1
  165. package/src/style.scss +10 -12
  166. package/src/utils/use-activate-theme.js +1 -1
@@ -0,0 +1,196 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { MenuItem } from '@wordpress/components';
5
+ import { store as coreStore } from '@wordpress/core-data';
6
+ import { useDispatch } from '@wordpress/data';
7
+ import { __, sprintf } from '@wordpress/i18n';
8
+ import { store as noticesStore } from '@wordpress/notices';
9
+ import { privateApis as routerPrivateApis } from '@wordpress/router';
10
+
11
+ /**
12
+ * Internal dependencies
13
+ */
14
+ import {
15
+ TEMPLATE_PARTS,
16
+ PATTERNS,
17
+ SYNC_TYPES,
18
+ USER_PATTERNS,
19
+ USER_PATTERN_CATEGORY,
20
+ } from './utils';
21
+ import {
22
+ useExistingTemplateParts,
23
+ getUniqueTemplatePartTitle,
24
+ getCleanTemplatePartSlug,
25
+ } from '../../utils/template-part-create';
26
+ import { unlock } from '../../lock-unlock';
27
+
28
+ const { useHistory } = unlock( routerPrivateApis );
29
+
30
+ function getPatternMeta( item ) {
31
+ if ( item.type === PATTERNS ) {
32
+ return { wp_pattern_sync_status: SYNC_TYPES.unsynced };
33
+ }
34
+
35
+ const syncStatus = item.reusableBlock.wp_pattern_sync_status;
36
+ const isUnsynced = syncStatus === SYNC_TYPES.unsynced;
37
+
38
+ return {
39
+ ...item.reusableBlock.meta,
40
+ wp_pattern_sync_status: isUnsynced ? syncStatus : undefined,
41
+ };
42
+ }
43
+
44
+ export default function DuplicateMenuItem( {
45
+ categoryId,
46
+ item,
47
+ label = __( 'Duplicate' ),
48
+ onClose,
49
+ } ) {
50
+ const { saveEntityRecord } = useDispatch( coreStore );
51
+ const { createErrorNotice, createSuccessNotice } =
52
+ useDispatch( noticesStore );
53
+
54
+ const history = useHistory();
55
+ const existingTemplateParts = useExistingTemplateParts();
56
+
57
+ async function createTemplatePart() {
58
+ try {
59
+ const copiedTitle = sprintf(
60
+ /* translators: %s: Existing template part title */
61
+ __( '%s (Copy)' ),
62
+ item.title
63
+ );
64
+ const title = getUniqueTemplatePartTitle(
65
+ copiedTitle,
66
+ existingTemplateParts
67
+ );
68
+ const slug = getCleanTemplatePartSlug( title );
69
+ const { area, content } = item.templatePart;
70
+
71
+ const result = await saveEntityRecord(
72
+ 'postType',
73
+ 'wp_template_part',
74
+ { slug, title, content, area },
75
+ { throwOnError: true }
76
+ );
77
+
78
+ createSuccessNotice(
79
+ sprintf(
80
+ // translators: %s: The new template part's title e.g. 'Call to action (copy)'.
81
+ __( '"%s" created.' ),
82
+ title
83
+ ),
84
+ {
85
+ type: 'snackbar',
86
+ id: 'edit-site-patterns-success',
87
+ actions: [
88
+ {
89
+ label: __( 'Edit' ),
90
+ onClick: () =>
91
+ history.push( {
92
+ postType: TEMPLATE_PARTS,
93
+ postId: result?.id,
94
+ categoryType: TEMPLATE_PARTS,
95
+ categoryId,
96
+ } ),
97
+ },
98
+ ],
99
+ }
100
+ );
101
+
102
+ onClose();
103
+ } catch ( error ) {
104
+ const errorMessage =
105
+ error.message && error.code !== 'unknown_error'
106
+ ? error.message
107
+ : __(
108
+ 'An error occurred while creating the template part.'
109
+ );
110
+
111
+ createErrorNotice( errorMessage, {
112
+ type: 'snackbar',
113
+ id: 'edit-site-patterns-error',
114
+ } );
115
+ onClose();
116
+ }
117
+ }
118
+
119
+ async function createPattern() {
120
+ try {
121
+ const isThemePattern = item.type === PATTERNS;
122
+ const title = sprintf(
123
+ /* translators: %s: Existing pattern title */
124
+ __( '%s (Copy)' ),
125
+ item.title
126
+ );
127
+
128
+ const result = await saveEntityRecord(
129
+ 'postType',
130
+ 'wp_block',
131
+ {
132
+ content: isThemePattern
133
+ ? item.content
134
+ : item.reusableBlock.content,
135
+ meta: getPatternMeta( item ),
136
+ status: 'publish',
137
+ title,
138
+ },
139
+ { throwOnError: true }
140
+ );
141
+
142
+ const actionLabel = isThemePattern
143
+ ? __( 'View my patterns' )
144
+ : __( 'Edit' );
145
+
146
+ const newLocation = isThemePattern
147
+ ? {
148
+ categoryType: USER_PATTERNS,
149
+ categoryId: USER_PATTERN_CATEGORY,
150
+ path: '/patterns',
151
+ }
152
+ : {
153
+ categoryType: USER_PATTERNS,
154
+ categoryId: USER_PATTERN_CATEGORY,
155
+ postType: USER_PATTERNS,
156
+ postId: result?.id,
157
+ };
158
+
159
+ createSuccessNotice(
160
+ sprintf(
161
+ // translators: %s: The new pattern's title e.g. 'Call to action (copy)'.
162
+ __( '"%s" added to my patterns.' ),
163
+ title
164
+ ),
165
+ {
166
+ type: 'snackbar',
167
+ id: 'edit-site-patterns-success',
168
+ actions: [
169
+ {
170
+ label: actionLabel,
171
+ onClick: () => history.push( newLocation ),
172
+ },
173
+ ],
174
+ }
175
+ );
176
+
177
+ onClose();
178
+ } catch ( error ) {
179
+ const errorMessage =
180
+ error.message && error.code !== 'unknown_error'
181
+ ? error.message
182
+ : __( 'An error occurred while creating the pattern.' );
183
+
184
+ createErrorNotice( errorMessage, {
185
+ type: 'snackbar',
186
+ id: 'edit-site-patterns-error',
187
+ } );
188
+ onClose();
189
+ }
190
+ }
191
+
192
+ const createItem =
193
+ item.type === TEMPLATE_PARTS ? createTemplatePart : createPattern;
194
+
195
+ return <MenuItem onClick={ createItem }>{ label }</MenuItem>;
196
+ }
@@ -8,87 +8,103 @@ import classnames from 'classnames';
8
8
  */
9
9
  import { BlockPreview } from '@wordpress/block-editor';
10
10
  import {
11
+ Button,
11
12
  __experimentalConfirmDialog as ConfirmDialog,
12
13
  DropdownMenu,
13
14
  MenuGroup,
14
15
  MenuItem,
15
16
  __experimentalHeading as Heading,
16
17
  __experimentalHStack as HStack,
17
- __unstableCompositeItem as CompositeItem,
18
18
  Tooltip,
19
19
  Flex,
20
20
  } from '@wordpress/components';
21
21
  import { useDispatch } from '@wordpress/data';
22
- import { useState, useId } from '@wordpress/element';
22
+ import { useState, useId, memo } from '@wordpress/element';
23
23
  import { __, sprintf } from '@wordpress/i18n';
24
24
  import {
25
25
  Icon,
26
26
  header,
27
27
  footer,
28
- symbolFilled,
28
+ symbolFilled as uncategorized,
29
+ symbol,
29
30
  moreHorizontal,
30
31
  lockSmall,
31
32
  } from '@wordpress/icons';
32
33
  import { store as noticesStore } from '@wordpress/notices';
33
34
  import { store as reusableBlocksStore } from '@wordpress/reusable-blocks';
34
- import { DELETE, BACKSPACE } from '@wordpress/keycodes';
35
35
 
36
36
  /**
37
37
  * Internal dependencies
38
38
  */
39
- import { PATTERNS, USER_PATTERNS } from './utils';
39
+ import RenameMenuItem from './rename-menu-item';
40
+ import DuplicateMenuItem from './duplicate-menu-item';
41
+ import { PATTERNS, TEMPLATE_PARTS, USER_PATTERNS, SYNC_TYPES } from './utils';
42
+ import { store as editSiteStore } from '../../store';
40
43
  import { useLink } from '../routes/link';
41
44
 
42
- const THEME_PATTERN_TOOLTIP = __( 'Theme patterns cannot be edited.' );
45
+ const templatePartIcons = { header, footer, uncategorized };
43
46
 
44
- export default function GridItem( { categoryId, composite, icon, item } ) {
47
+ function GridItem( { categoryId, item, ...props } ) {
45
48
  const descriptionId = useId();
46
49
  const [ isDeleteDialogOpen, setIsDeleteDialogOpen ] = useState( false );
47
50
 
51
+ const { removeTemplate } = useDispatch( editSiteStore );
48
52
  const { __experimentalDeleteReusableBlock } =
49
53
  useDispatch( reusableBlocksStore );
50
54
  const { createErrorNotice, createSuccessNotice } =
51
55
  useDispatch( noticesStore );
52
56
 
57
+ const isUserPattern = item.type === USER_PATTERNS;
58
+ const isNonUserPattern = item.type === PATTERNS;
59
+ const isTemplatePart = item.type === TEMPLATE_PARTS;
60
+
53
61
  const { onClick } = useLink( {
54
62
  postType: item.type,
55
- postId: item.type === USER_PATTERNS ? item.id : item.name,
63
+ postId: isUserPattern ? item.id : item.name,
56
64
  categoryId,
57
65
  categoryType: item.type,
58
66
  } );
59
67
 
60
- const onKeyDown = ( event ) => {
61
- if ( DELETE === event.keyCode || BACKSPACE === event.keyCode ) {
62
- setIsDeleteDialogOpen( true );
63
- }
64
- };
65
-
66
68
  const isEmpty = ! item.blocks?.length;
67
69
  const patternClassNames = classnames( 'edit-site-patterns__pattern', {
68
70
  'is-placeholder': isEmpty,
69
71
  } );
70
72
  const previewClassNames = classnames( 'edit-site-patterns__preview', {
71
- 'is-inactive': item.type === PATTERNS,
73
+ 'is-inactive': isNonUserPattern,
72
74
  } );
73
75
 
74
76
  const deletePattern = async () => {
75
77
  try {
76
78
  await __experimentalDeleteReusableBlock( item.id );
77
- createSuccessNotice( __( 'Pattern successfully deleted.' ), {
78
- type: 'snackbar',
79
- } );
79
+ createSuccessNotice(
80
+ sprintf(
81
+ // translators: %s: The pattern's title e.g. 'Call to action'.
82
+ __( '"%s" deleted.' ),
83
+ item.title
84
+ ),
85
+ { type: 'snackbar', id: 'edit-site-patterns-success' }
86
+ );
80
87
  } catch ( error ) {
81
88
  const errorMessage =
82
89
  error.message && error.code !== 'unknown_error'
83
90
  ? error.message
84
91
  : __( 'An error occurred while deleting the pattern.' );
85
- createErrorNotice( errorMessage, { type: 'snackbar' } );
92
+ createErrorNotice( errorMessage, {
93
+ type: 'snackbar',
94
+ id: 'edit-site-patterns-error',
95
+ } );
86
96
  }
87
97
  };
98
+ const deleteItem = () =>
99
+ isTemplatePart ? removeTemplate( item ) : deletePattern();
88
100
 
89
- const isUserPattern = item.type === USER_PATTERNS;
101
+ // Only custom patterns or custom template parts can be renamed or deleted.
102
+ const isCustomPattern =
103
+ isUserPattern || ( isTemplatePart && item.isCustom );
104
+ const hasThemeFile = isTemplatePart && item.templatePart.has_theme_file;
90
105
  const ariaDescriptions = [];
91
- if ( isUserPattern ) {
106
+
107
+ if ( isCustomPattern ) {
92
108
  // User patterns don't have descriptions, but can be edited and deleted, so include some help text.
93
109
  ariaDescriptions.push(
94
110
  __( 'Press Enter to edit, or Delete to delete the pattern.' )
@@ -96,139 +112,173 @@ export default function GridItem( { categoryId, composite, icon, item } ) {
96
112
  } else if ( item.description ) {
97
113
  ariaDescriptions.push( item.description );
98
114
  }
99
- if ( item.type === PATTERNS ) {
100
- ariaDescriptions.push( THEME_PATTERN_TOOLTIP );
101
- }
102
115
 
103
- let itemIcon = icon;
104
- if ( categoryId === 'header' ) {
105
- itemIcon = header;
106
- } else if ( categoryId === 'footer' ) {
107
- itemIcon = footer;
108
- } else if ( categoryId === 'uncategorized' ) {
109
- itemIcon = symbolFilled;
116
+ if ( isNonUserPattern ) {
117
+ ariaDescriptions.push( __( 'Theme patterns cannot be edited.' ) );
110
118
  }
111
119
 
120
+ const itemIcon =
121
+ templatePartIcons[ categoryId ] ||
122
+ ( item.syncStatus === SYNC_TYPES.full ? symbol : undefined );
123
+
124
+ const confirmButtonText = hasThemeFile ? __( 'Clear' ) : __( 'Delete' );
125
+ const confirmPrompt = hasThemeFile
126
+ ? __( 'Are you sure you want to clear these customizations?' )
127
+ : sprintf(
128
+ // translators: %s: The pattern or template part's title e.g. 'Call to action'.
129
+ __( 'Are you sure you want to delete "%s"?' ),
130
+ item.title
131
+ );
132
+
112
133
  return (
113
- <>
114
- <div className={ patternClassNames }>
115
- <CompositeItem
116
- className={ previewClassNames }
117
- role="option"
118
- as="div"
119
- { ...composite }
120
- onClick={ item.type !== PATTERNS ? onClick : undefined }
121
- onKeyDown={ isUserPattern ? onKeyDown : undefined }
122
- aria-label={ item.title }
123
- aria-describedby={
124
- ariaDescriptions.length
125
- ? ariaDescriptions
126
- .map(
127
- ( _, index ) =>
128
- `${ descriptionId }-${ index }`
129
- )
130
- .join( ' ' )
131
- : undefined
132
- }
134
+ <li className={ patternClassNames }>
135
+ <button
136
+ className={ previewClassNames }
137
+ // Even though still incomplete, passing ids helps performance.
138
+ // @see https://reakit.io/docs/composite/#performance.
139
+ id={ `edit-site-patterns-${ item.name }` }
140
+ { ...props }
141
+ onClick={ item.type !== PATTERNS ? onClick : undefined }
142
+ aria-disabled={ item.type !== PATTERNS ? 'false' : 'true' }
143
+ aria-label={ item.title }
144
+ aria-describedby={
145
+ ariaDescriptions.length
146
+ ? ariaDescriptions
147
+ .map(
148
+ ( _, index ) =>
149
+ `${ descriptionId }-${ index }`
150
+ )
151
+ .join( ' ' )
152
+ : undefined
153
+ }
154
+ >
155
+ { isEmpty && __( 'Empty pattern' ) }
156
+ { ! isEmpty && <BlockPreview blocks={ item.blocks } /> }
157
+ </button>
158
+ { ariaDescriptions.map( ( ariaDescription, index ) => (
159
+ <div
160
+ key={ index }
161
+ hidden
162
+ id={ `${ descriptionId }-${ index }` }
133
163
  >
134
- { isEmpty && __( 'Empty pattern' ) }
135
- { ! isEmpty && <BlockPreview blocks={ item.blocks } /> }
136
- </CompositeItem>
137
- { ariaDescriptions.map( ( ariaDescription, index ) => (
138
- <div
139
- key={ index }
140
- hidden
141
- id={ `${ descriptionId }-${ index }` }
142
- >
143
- { ariaDescription }
144
- </div>
145
- ) ) }
164
+ { ariaDescription }
165
+ </div>
166
+ ) ) }
167
+ <HStack
168
+ className="edit-site-patterns__footer"
169
+ justify="space-between"
170
+ >
146
171
  <HStack
147
- aria-hidden="true"
148
- className="edit-site-patterns__footer"
149
- justify="space-between"
172
+ alignment="center"
173
+ justify="left"
174
+ spacing={ 3 }
175
+ className="edit-site-patterns__pattern-title"
150
176
  >
151
- <HStack
152
- alignment="center"
153
- justify="left"
154
- spacing={ 3 }
155
- className="edit-site-patterns__pattern-title"
156
- >
157
- { icon && (
158
- <Icon
159
- className="edit-site-patterns__pattern-icon"
160
- icon={ itemIcon }
161
- />
162
- ) }
163
- <Flex
164
- as={ Heading }
165
- level={ 5 }
166
- gap={ 0 }
167
- justify="left"
177
+ { itemIcon && (
178
+ <Tooltip
179
+ position="top center"
180
+ text={ __(
181
+ 'Editing this pattern will also update anywhere it is used'
182
+ ) }
168
183
  >
169
- { item.title }
170
- { item.type === PATTERNS && (
171
- <Tooltip
172
- position="top center"
173
- text={ __(
174
- 'Theme patterns cannot be edited.'
175
- ) }
184
+ <span>
185
+ <Icon
186
+ className="edit-site-patterns__pattern-icon"
187
+ icon={ itemIcon }
188
+ />
189
+ </span>
190
+ </Tooltip>
191
+ ) }
192
+ <Flex as="span" gap={ 0 } justify="left">
193
+ { item.type === PATTERNS ? (
194
+ item.title
195
+ ) : (
196
+ <Heading level={ 5 }>
197
+ <Button
198
+ variant="link"
199
+ onClick={ onClick }
200
+ // Required for the grid's roving tab index system.
201
+ // See https://github.com/WordPress/gutenberg/pull/51898#discussion_r1243399243.
202
+ tabIndex="-1"
176
203
  >
177
- <span className="edit-site-patterns__pattern-lock-icon">
178
- <Icon
179
- style={ { fill: 'currentcolor' } }
180
- icon={ lockSmall }
181
- size={ 24 }
182
- />
183
- </span>
184
- </Tooltip>
204
+ { item.title }
205
+ </Button>
206
+ </Heading>
207
+ ) }
208
+ { item.type === PATTERNS && (
209
+ <Tooltip
210
+ position="top center"
211
+ text={ __(
212
+ 'Theme patterns cannot be edited.'
213
+ ) }
214
+ >
215
+ <span className="edit-site-patterns__pattern-lock-icon">
216
+ <Icon icon={ lockSmall } size={ 24 } />
217
+ </span>
218
+ </Tooltip>
219
+ ) }
220
+ </Flex>
221
+ </HStack>
222
+ <DropdownMenu
223
+ icon={ moreHorizontal }
224
+ label={ __( 'Actions' ) }
225
+ className="edit-site-patterns__dropdown"
226
+ popoverProps={ { placement: 'bottom-end' } }
227
+ toggleProps={ {
228
+ className: 'edit-site-patterns__button',
229
+ isSmall: true,
230
+ describedBy: sprintf(
231
+ /* translators: %s: pattern name */
232
+ __( 'Action menu for %s pattern' ),
233
+ item.title
234
+ ),
235
+ } }
236
+ >
237
+ { ( { onClose } ) => (
238
+ <MenuGroup>
239
+ { isCustomPattern && ! hasThemeFile && (
240
+ <RenameMenuItem
241
+ item={ item }
242
+ onClose={ onClose }
243
+ />
185
244
  ) }
186
- </Flex>
187
- </HStack>
188
- { item.type === USER_PATTERNS && (
189
- <DropdownMenu
190
- icon={ moreHorizontal }
191
- label={ __( 'Actions' ) }
192
- className="edit-site-patterns__dropdown"
193
- popoverProps={ { placement: 'bottom-end' } }
194
- toggleProps={ {
195
- className: 'edit-site-patterns__button',
196
- isSmall: true,
197
- describedBy: sprintf(
198
- /* translators: %s: pattern name */
199
- __( 'Action menu for %s pattern' ),
200
- item.title
201
- ),
202
- // The dropdown menu is not focusable using the
203
- // keyboard as this would interfere with the grid's
204
- // roving tab index system. Instead, keyboard users
205
- // use keyboard shortcuts to trigger actions.
206
- tabIndex: -1,
207
- } }
208
- >
209
- { () => (
210
- <MenuGroup>
211
- <MenuItem
212
- onClick={ () =>
213
- setIsDeleteDialogOpen( true )
214
- }
215
- >
216
- { __( 'Delete' ) }
217
- </MenuItem>
218
- </MenuGroup>
245
+ <DuplicateMenuItem
246
+ categoryId={ categoryId }
247
+ item={ item }
248
+ onClose={ onClose }
249
+ label={
250
+ isNonUserPattern
251
+ ? __( 'Copy to My patterns' )
252
+ : __( 'Duplicate' )
253
+ }
254
+ />
255
+ { isCustomPattern && (
256
+ <MenuItem
257
+ onClick={ () =>
258
+ setIsDeleteDialogOpen( true )
259
+ }
260
+ >
261
+ { hasThemeFile
262
+ ? __( 'Clear customizations' )
263
+ : __( 'Delete' ) }
264
+ </MenuItem>
219
265
  ) }
220
- </DropdownMenu>
266
+ </MenuGroup>
221
267
  ) }
222
- </HStack>
223
- </div>
268
+ </DropdownMenu>
269
+ </HStack>
270
+
224
271
  { isDeleteDialogOpen && (
225
272
  <ConfirmDialog
226
- onConfirm={ deletePattern }
273
+ confirmButtonText={ confirmButtonText }
274
+ onConfirm={ deleteItem }
227
275
  onCancel={ () => setIsDeleteDialogOpen( false ) }
228
276
  >
229
- { __( 'Are you sure you want to delete this pattern?' ) }
277
+ { confirmPrompt }
230
278
  </ConfirmDialog>
231
279
  ) }
232
- </>
280
+ </li>
233
281
  );
234
282
  }
283
+
284
+ export default memo( GridItem );