@wordpress/block-library 7.0.0 → 7.0.2

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 (230) hide show
  1. package/README.md +16 -0
  2. package/build/button/edit.native.js +2 -2
  3. package/build/button/edit.native.js.map +1 -1
  4. package/build/columns/index.js +12 -0
  5. package/build/columns/index.js.map +1 -1
  6. package/build/comment-author-avatar/edit.js +17 -4
  7. package/build/comment-author-avatar/edit.js.map +1 -1
  8. package/build/comment-template/edit.js +94 -36
  9. package/build/comment-template/edit.js.map +1 -1
  10. package/build/comment-template/hooks.js +175 -0
  11. package/build/comment-template/hooks.js.map +1 -0
  12. package/build/comment-template/index.js +1 -1
  13. package/build/comment-template/util.js.map +1 -1
  14. package/build/comments-pagination-next/index.js +1 -1
  15. package/build/comments-pagination-numbers/index.js +1 -1
  16. package/build/comments-query-loop/edit/comments-inspector-controls.js +20 -9
  17. package/build/comments-query-loop/edit/comments-inspector-controls.js.map +1 -1
  18. package/build/comments-query-loop/edit.js +1 -19
  19. package/build/comments-query-loop/edit.js.map +1 -1
  20. package/build/comments-query-loop/index.js +5 -0
  21. package/build/comments-query-loop/index.js.map +1 -1
  22. package/build/cover/edit.js +21 -22
  23. package/build/cover/edit.js.map +1 -1
  24. package/build/cover/edit.native.js +7 -5
  25. package/build/cover/edit.native.js.map +1 -1
  26. package/build/cover/overlay-color-settings.native.js +4 -3
  27. package/build/cover/overlay-color-settings.native.js.map +1 -1
  28. package/build/cover/transforms.js +4 -2
  29. package/build/cover/transforms.js.map +1 -1
  30. package/build/group/index.js +1 -0
  31. package/build/group/index.js.map +1 -1
  32. package/build/heading/edit.js +14 -2
  33. package/build/heading/edit.js.map +1 -1
  34. package/build/image/deprecated.js +89 -5
  35. package/build/image/deprecated.js.map +1 -1
  36. package/build/image/save.js +0 -7
  37. package/build/image/save.js.map +1 -1
  38. package/build/latest-posts/edit.js +1 -0
  39. package/build/latest-posts/edit.js.map +1 -1
  40. package/build/navigation/edit/index.js +17 -15
  41. package/build/navigation/edit/index.js.map +1 -1
  42. package/build/navigation/edit/navigation-menu-selector.js +44 -27
  43. package/build/navigation/edit/navigation-menu-selector.js.map +1 -1
  44. package/build/navigation/edit/placeholder/index.js +8 -22
  45. package/build/navigation/edit/placeholder/index.js.map +1 -1
  46. package/build/navigation/use-navigation-menu.js +6 -6
  47. package/build/navigation/use-navigation-menu.js.map +1 -1
  48. package/build/navigation-submenu/edit.js +41 -9
  49. package/build/navigation-submenu/edit.js.map +1 -1
  50. package/build/page-list/edit.js +11 -17
  51. package/build/page-list/edit.js.map +1 -1
  52. package/build/social-links/deprecated.js +1 -62
  53. package/build/social-links/deprecated.js.map +1 -1
  54. package/build/template-part/edit/index.js +36 -64
  55. package/build/template-part/edit/index.js.map +1 -1
  56. package/build/template-part/edit/placeholder.js +64 -0
  57. package/build/template-part/edit/placeholder.js.map +1 -0
  58. package/build/template-part/edit/selection-modal.js +103 -0
  59. package/build/template-part/edit/selection-modal.js.map +1 -0
  60. package/build/template-part/edit/title-modal.js +54 -0
  61. package/build/template-part/edit/title-modal.js.map +1 -0
  62. package/build/template-part/edit/utils/hooks.js +156 -0
  63. package/build/template-part/edit/utils/hooks.js.map +1 -0
  64. package/build/template-part/index.js +3 -1
  65. package/build/template-part/index.js.map +1 -1
  66. package/build-module/button/edit.native.js +4 -4
  67. package/build-module/button/edit.native.js.map +1 -1
  68. package/build-module/columns/index.js +12 -0
  69. package/build-module/columns/index.js.map +1 -1
  70. package/build-module/comment-author-avatar/edit.js +18 -6
  71. package/build-module/comment-author-avatar/edit.js.map +1 -1
  72. package/build-module/comment-template/edit.js +95 -37
  73. package/build-module/comment-template/edit.js.map +1 -1
  74. package/build-module/comment-template/hooks.js +156 -0
  75. package/build-module/comment-template/hooks.js.map +1 -0
  76. package/build-module/comment-template/index.js +1 -1
  77. package/build-module/comment-template/util.js.map +1 -1
  78. package/build-module/comments-pagination-next/index.js +1 -1
  79. package/build-module/comments-pagination-numbers/index.js +1 -1
  80. package/build-module/comments-query-loop/edit/comments-inspector-controls.js +20 -9
  81. package/build-module/comments-query-loop/edit/comments-inspector-controls.js.map +1 -1
  82. package/build-module/comments-query-loop/edit.js +2 -19
  83. package/build-module/comments-query-loop/edit.js.map +1 -1
  84. package/build-module/comments-query-loop/index.js +5 -0
  85. package/build-module/comments-query-loop/index.js.map +1 -1
  86. package/build-module/cover/edit.js +23 -24
  87. package/build-module/cover/edit.js.map +1 -1
  88. package/build-module/cover/edit.native.js +10 -8
  89. package/build-module/cover/edit.native.js.map +1 -1
  90. package/build-module/cover/overlay-color-settings.native.js +4 -4
  91. package/build-module/cover/overlay-color-settings.native.js.map +1 -1
  92. package/build-module/cover/transforms.js +4 -2
  93. package/build-module/cover/transforms.js.map +1 -1
  94. package/build-module/group/index.js +1 -0
  95. package/build-module/group/index.js.map +1 -1
  96. package/build-module/heading/edit.js +15 -3
  97. package/build-module/heading/edit.js.map +1 -1
  98. package/build-module/image/deprecated.js +90 -7
  99. package/build-module/image/deprecated.js.map +1 -1
  100. package/build-module/image/save.js +0 -7
  101. package/build-module/image/save.js.map +1 -1
  102. package/build-module/latest-posts/edit.js +1 -0
  103. package/build-module/latest-posts/edit.js.map +1 -1
  104. package/build-module/navigation/edit/index.js +17 -15
  105. package/build-module/navigation/edit/index.js.map +1 -1
  106. package/build-module/navigation/edit/navigation-menu-selector.js +45 -27
  107. package/build-module/navigation/edit/navigation-menu-selector.js.map +1 -1
  108. package/build-module/navigation/edit/placeholder/index.js +8 -21
  109. package/build-module/navigation/edit/placeholder/index.js.map +1 -1
  110. package/build-module/navigation/use-navigation-menu.js +6 -6
  111. package/build-module/navigation/use-navigation-menu.js.map +1 -1
  112. package/build-module/navigation-submenu/edit.js +41 -10
  113. package/build-module/navigation-submenu/edit.js.map +1 -1
  114. package/build-module/page-list/edit.js +12 -18
  115. package/build-module/page-list/edit.js.map +1 -1
  116. package/build-module/social-links/deprecated.js +1 -62
  117. package/build-module/social-links/deprecated.js.map +1 -1
  118. package/build-module/template-part/edit/index.js +37 -65
  119. package/build-module/template-part/edit/index.js.map +1 -1
  120. package/build-module/template-part/edit/placeholder.js +52 -0
  121. package/build-module/template-part/edit/placeholder.js.map +1 -0
  122. package/build-module/template-part/edit/selection-modal.js +89 -0
  123. package/build-module/template-part/edit/selection-modal.js.map +1 -0
  124. package/build-module/template-part/edit/title-modal.js +46 -0
  125. package/build-module/template-part/edit/title-modal.js.map +1 -0
  126. package/build-module/template-part/edit/utils/hooks.js +135 -0
  127. package/build-module/template-part/edit/utils/hooks.js.map +1 -0
  128. package/build-module/template-part/index.js +2 -1
  129. package/build-module/template-part/index.js.map +1 -1
  130. package/build-style/comment-author-avatar/editor-rtl.css +83 -0
  131. package/build-style/comment-author-avatar/editor.css +83 -0
  132. package/build-style/cover/style-rtl.css +4 -0
  133. package/build-style/cover/style.css +4 -0
  134. package/build-style/editor-rtl.css +27 -81
  135. package/build-style/editor.css +27 -81
  136. package/build-style/image/editor-rtl.css +0 -16
  137. package/build-style/image/editor.css +0 -16
  138. package/build-style/image/style-rtl.css +2 -0
  139. package/build-style/image/style.css +2 -0
  140. package/build-style/navigation/style-rtl.css +14 -3
  141. package/build-style/navigation/style.css +14 -3
  142. package/build-style/page-list/editor-rtl.css +0 -9
  143. package/build-style/page-list/editor.css +0 -9
  144. package/build-style/style-rtl.css +20 -3
  145. package/build-style/style.css +20 -3
  146. package/build-style/template-part/editor-rtl.css +19 -56
  147. package/build-style/template-part/editor.css +19 -56
  148. package/package.json +15 -15
  149. package/src/archives/index.php +1 -1
  150. package/src/button/edit.native.js +3 -3
  151. package/src/columns/block.json +12 -0
  152. package/src/comment-author-avatar/edit.js +13 -8
  153. package/src/comment-author-avatar/editor.scss +7 -0
  154. package/src/comment-template/block.json +7 -1
  155. package/src/comment-template/edit.js +102 -40
  156. package/src/comment-template/hooks.js +151 -0
  157. package/src/comment-template/index.php +8 -0
  158. package/src/comment-template/util.js +1 -0
  159. package/src/comments-pagination-next/block.json +8 -1
  160. package/src/comments-pagination-next/index.php +6 -8
  161. package/src/comments-pagination-numbers/block.json +7 -1
  162. package/src/comments-pagination-numbers/index.php +3 -10
  163. package/src/comments-query-loop/block.json +5 -0
  164. package/src/comments-query-loop/edit/comments-inspector-controls.js +22 -4
  165. package/src/comments-query-loop/edit.js +1 -16
  166. package/src/cover/edit.js +15 -28
  167. package/src/cover/edit.native.js +15 -7
  168. package/src/cover/overlay-color-settings.native.js +3 -4
  169. package/src/cover/style.scss +4 -0
  170. package/src/cover/transforms.js +2 -0
  171. package/src/editor.scss +1 -0
  172. package/src/gallery/index.php +1 -8
  173. package/src/group/block.json +1 -0
  174. package/src/heading/edit.js +18 -5
  175. package/src/home-link/index.php +1 -19
  176. package/src/image/deprecated.js +105 -1
  177. package/src/image/editor.scss +0 -18
  178. package/src/image/save.js +0 -8
  179. package/src/image/style.scss +3 -0
  180. package/src/image/test/edit.native.js +0 -10
  181. package/src/latest-posts/edit.js +1 -0
  182. package/src/latest-posts/index.php +1 -1
  183. package/src/navigation/edit/index.js +25 -26
  184. package/src/navigation/edit/navigation-menu-selector.js +73 -28
  185. package/src/navigation/edit/placeholder/index.js +8 -32
  186. package/src/navigation/index.php +4 -4
  187. package/src/navigation/style.scss +22 -3
  188. package/src/navigation/use-navigation-menu.js +6 -6
  189. package/src/navigation-link/index.php +3 -22
  190. package/src/navigation-submenu/edit.js +50 -12
  191. package/src/navigation-submenu/index.php +3 -21
  192. package/src/page-list/edit.js +21 -25
  193. package/src/page-list/editor.scss +0 -10
  194. package/src/page-list/index.php +4 -4
  195. package/src/post-navigation-link/index.php +3 -3
  196. package/src/search/index.php +6 -3
  197. package/src/site-logo/index.php +1 -1
  198. package/src/social-links/deprecated.js +0 -59
  199. package/src/template-part/edit/index.js +61 -71
  200. package/src/template-part/edit/placeholder.js +78 -0
  201. package/src/template-part/edit/selection-modal.js +115 -0
  202. package/src/template-part/edit/title-modal.js +59 -0
  203. package/src/template-part/edit/utils/hooks.js +158 -0
  204. package/src/template-part/editor.scss +16 -74
  205. package/src/template-part/index.js +4 -1
  206. package/build/navigation/edit/existing-menus-options.js +0 -62
  207. package/build/navigation/edit/existing-menus-options.js.map +0 -1
  208. package/build/template-part/edit/placeholder/index.js +0 -141
  209. package/build/template-part/edit/placeholder/index.js.map +0 -1
  210. package/build/template-part/edit/placeholder/patterns-setup.js +0 -100
  211. package/build/template-part/edit/placeholder/patterns-setup.js.map +0 -1
  212. package/build/template-part/edit/selection/index.js +0 -45
  213. package/build/template-part/edit/selection/index.js.map +0 -1
  214. package/build/template-part/edit/selection/template-part-previews.js +0 -317
  215. package/build/template-part/edit/selection/template-part-previews.js.map +0 -1
  216. package/build-module/navigation/edit/existing-menus-options.js +0 -53
  217. package/build-module/navigation/edit/existing-menus-options.js.map +0 -1
  218. package/build-module/template-part/edit/placeholder/index.js +0 -124
  219. package/build-module/template-part/edit/placeholder/index.js.map +0 -1
  220. package/build-module/template-part/edit/placeholder/patterns-setup.js +0 -91
  221. package/build-module/template-part/edit/placeholder/patterns-setup.js.map +0 -1
  222. package/build-module/template-part/edit/selection/index.js +0 -35
  223. package/build-module/template-part/edit/selection/index.js.map +0 -1
  224. package/build-module/template-part/edit/selection/template-part-previews.js +0 -298
  225. package/build-module/template-part/edit/selection/template-part-previews.js.map +0 -1
  226. package/src/navigation/edit/existing-menus-options.js +0 -70
  227. package/src/template-part/edit/placeholder/index.js +0 -172
  228. package/src/template-part/edit/placeholder/patterns-setup.js +0 -124
  229. package/src/template-part/edit/selection/index.js +0 -37
  230. package/src/template-part/edit/selection/template-part-previews.js +0 -372
@@ -178,7 +178,7 @@ function block_core_page_list_render_nested_page_list( $open_submenus_on_click,
178
178
  $css_class .= ' menu-item-home';
179
179
  }
180
180
 
181
- $title = wp_kses( $page['title'], wp_kses_allowed_html( 'post' ) );
181
+ $title = wp_kses_post( $page['title'] );
182
182
  $aria_label = sprintf(
183
183
  /* translators: Accessibility text. %s: Parent page title. */
184
184
  __( '%s submenu' ),
@@ -188,8 +188,8 @@ function block_core_page_list_render_nested_page_list( $open_submenus_on_click,
188
188
  $markup .= '<li class="wp-block-pages-list__item' . esc_attr( $css_class ) . '"' . $style_attribute . '>';
189
189
 
190
190
  if ( isset( $page['children'] ) && $is_navigation_child && $open_submenus_on_click ) {
191
- $markup .= '<button aria-label="' . esc_attr( $aria_label ) . '" class="' . esc_attr( $navigation_child_content_class ) . ' wp-block-navigation-submenu__toggle" aria-expanded="false">' . $title . '<span class="wp-block-page-list__submenu-icon wp-block-navigation__submenu-icon"><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12" fill="none" aria-hidden="true" focusable="false"><path d="M1.50002 4L6.00002 8L10.5 4" stroke-width="1.5"></path></svg></span>' .
192
- '</button>';
191
+ $markup .= '<button aria-label="' . esc_attr( $aria_label ) . '" class="' . esc_attr( $navigation_child_content_class ) . ' wp-block-navigation-submenu__toggle" aria-expanded="false">' . esc_html( $title ) .
192
+ '</button>' . '<span class="wp-block-page-list__submenu-icon wp-block-navigation__submenu-icon"><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12" fill="none" aria-hidden="true" focusable="false"><path d="M1.50002 4L6.00002 8L10.5 4" stroke-width="1.5"></path></svg></span>';
193
193
  } else {
194
194
  $markup .= '<a class="wp-block-pages-list__item__link' . esc_attr( $navigation_child_content_class ) . '" href="' . esc_url( $page['link'] ) . '"' . $aria_current . '>' . $title . '</a>';
195
195
  }
@@ -197,7 +197,7 @@ function block_core_page_list_render_nested_page_list( $open_submenus_on_click,
197
197
  if ( isset( $page['children'] ) ) {
198
198
  if ( $is_navigation_child && $show_submenu_icons && ! $open_submenus_on_click ) {
199
199
  $markup .= '<button aria-label="' . esc_attr( $aria_label ) . '" class="wp-block-navigation__submenu-icon wp-block-navigation-submenu__toggle" aria-expanded="false">';
200
- $markup .= '<span class="wp-block-page-list__submenu-icon wp-block-navigation__submenu-icon"><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12" fill="none" aria-hidden="true" focusable="false"><path d="M1.50002 4L6.00002 8L10.5 4" stroke-width="1.5"></path></svg></span>';
200
+ $markup .= '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12" fill="none" aria-hidden="true" focusable="false"><path d="M1.50002 4L6.00002 8L10.5 4" stroke-width="1.5"></path></svg>';
201
201
  $markup .= '</button>';
202
202
  }
203
203
  $markup .= '<ul class="submenu-container';
@@ -49,13 +49,13 @@ function render_block_core_post_navigation_link( $attributes, $content ) {
49
49
  */
50
50
  if ( ! $attributes['linkLabel'] ) {
51
51
  if ( $label ) {
52
- $format = '<span class="post-navigation-link__label">' . esc_html( $label ) . '</span> %link';
52
+ $format = '<span class="post-navigation-link__label">' . wp_kses_post( $label ) . '</span> %link';
53
53
  }
54
54
  $link = '%title';
55
55
  } elseif ( isset( $attributes['linkLabel'] ) && $attributes['linkLabel'] ) {
56
56
  // If the label link option is enabled and there is a custom label, display it before the title.
57
57
  if ( $label ) {
58
- $link = '<span class="post-navigation-link__label">' . esc_html( $label ) . '</span> <span class="post-navigation-link__title">%title</title>';
58
+ $link = '<span class="post-navigation-link__label">' . wp_kses_post( $label ) . '</span> <span class="post-navigation-link__title">%title</span>';
59
59
  } else {
60
60
  /*
61
61
  * If the label link option is enabled and there is no custom label,
@@ -64,7 +64,7 @@ function render_block_core_post_navigation_link( $attributes, $content ) {
64
64
  $label = 'next' === $navigation_type ? _x( 'Next:', 'label before the title of the next post' ) : _x( 'Previous:', 'label before the title of the previous post' );
65
65
  $link = sprintf(
66
66
  '<span class="post-navigation-link__label">%1$s</span> <span class="post-navigation-link__title">%2$s</span>',
67
- esc_html( $label ),
67
+ wp_kses_post( $label ),
68
68
  '%title'
69
69
  );
70
70
  }
@@ -72,6 +72,7 @@ function render_block_core_search( $attributes ) {
72
72
  if ( $show_button ) {
73
73
  $button_internal_markup = '';
74
74
  $button_classes = $color_classes;
75
+ $aria_label = '';
75
76
 
76
77
  if ( ! $is_button_inside ) {
77
78
  $button_classes .= ' ' . $border_color_classes;
@@ -81,17 +82,19 @@ function render_block_core_search( $attributes ) {
81
82
  $button_internal_markup = wp_kses_post( $attributes['buttonText'] );
82
83
  }
83
84
  } else {
85
+ $aria_label = sprintf( 'aria-label="%s"', esc_attr( wp_strip_all_tags( $attributes['label'] ) ) );
84
86
  $button_classes .= ' has-icon';
85
87
  $button_internal_markup =
86
88
  '<svg id="search-icon" class="search-icon" viewBox="0 0 24 24" width="24" height="24">
87
- <path d="M13.5 6C10.5 6 8 8.5 8 11.5c0 1.1.3 2.1.9 3l-3.4 3 1 1.1 3.4-2.9c1 .9 2.2 1.4 3.6 1.4 3 0 5.5-2.5 5.5-5.5C19 8.5 16.5 6 13.5 6zm0 9.5c-2.2 0-4-1.8-4-4s1.8-4 4-4 4 1.8 4 4-1.8 4-4 4z"></path>
88
- </svg>';
89
+ <path d="M13.5 6C10.5 6 8 8.5 8 11.5c0 1.1.3 2.1.9 3l-3.4 3 1 1.1 3.4-2.9c1 .9 2.2 1.4 3.6 1.4 3 0 5.5-2.5 5.5-5.5C19 8.5 16.5 6 13.5 6zm0 9.5c-2.2 0-4-1.8-4-4s1.8-4 4-4 4 1.8 4 4-1.8 4-4 4z"></path>
90
+ </svg>';
89
91
  }
90
92
 
91
93
  $button_markup = sprintf(
92
- '<button type="submit" class="wp-block-search__button %s" %s>%s</button>',
94
+ '<button type="submit" class="wp-block-search__button %s" %s %s>%s</button>',
93
95
  esc_attr( $button_classes ),
94
96
  $inline_styles['button'],
97
+ $aria_label,
95
98
  $button_internal_markup
96
99
  );
97
100
  }
@@ -14,7 +14,7 @@
14
14
  */
15
15
  function render_block_core_site_logo( $attributes ) {
16
16
  $adjust_width_height_filter = function ( $image ) use ( $attributes ) {
17
- if ( empty( $attributes['width'] ) || empty( $image ) ) {
17
+ if ( empty( $attributes['width'] ) || empty( $image ) || ! $image[1] || ! $image[2] ) {
18
18
  return $image;
19
19
  }
20
20
  $height = (float) $attributes['width'] / ( (float) $image[1] / (float) $image[2] );
@@ -49,65 +49,6 @@ const migrateWithLayout = ( attributes ) => {
49
49
 
50
50
  // Social Links block deprecations.
51
51
  const deprecated = [
52
- // Implement `flex` layout.
53
- {
54
- attributes: {
55
- iconColor: {
56
- type: 'string',
57
- },
58
- customIconColor: {
59
- type: 'string',
60
- },
61
- iconColorValue: {
62
- type: 'string',
63
- },
64
- iconBackgroundColor: {
65
- type: 'string',
66
- },
67
- customIconBackgroundColor: {
68
- type: 'string',
69
- },
70
- iconBackgroundColorValue: {
71
- type: 'string',
72
- },
73
- openInNewTab: {
74
- type: 'boolean',
75
- default: false,
76
- },
77
- size: {
78
- type: 'string',
79
- },
80
- },
81
- supports: {
82
- align: [ 'left', 'center', 'right' ],
83
- anchor: true,
84
- __experimentalExposeControlsToChildren: true,
85
- },
86
- isEligible: ( { layout } ) => ! layout,
87
- migrate: migrateWithLayout,
88
- save( props ) {
89
- const {
90
- attributes: {
91
- iconBackgroundColorValue,
92
- iconColorValue,
93
- itemsJustification,
94
- size,
95
- },
96
- } = props;
97
-
98
- const className = classNames( size, {
99
- 'has-icon-color': iconColorValue,
100
- 'has-icon-background-color': iconBackgroundColorValue,
101
- [ `items-justified-${ itemsJustification }` ]: itemsJustification,
102
- } );
103
-
104
- return (
105
- <ul { ...useBlockProps.save( { className } ) }>
106
- <InnerBlocks.Content />
107
- </ul>
108
- );
109
- },
110
- },
111
52
  // V1. Remove CSS variable use for colors.
112
53
  {
113
54
  attributes: {
@@ -15,22 +15,28 @@ import {
15
15
  store as blockEditorStore,
16
16
  } from '@wordpress/block-editor';
17
17
  import {
18
- Dropdown,
19
18
  ToolbarGroup,
20
19
  ToolbarButton,
21
20
  Spinner,
21
+ Modal,
22
22
  } from '@wordpress/components';
23
23
  import { __, sprintf } from '@wordpress/i18n';
24
24
  import { store as coreStore } from '@wordpress/core-data';
25
+ import { useState } from '@wordpress/element';
25
26
 
26
27
  /**
27
28
  * Internal dependencies
28
29
  */
29
30
  import TemplatePartPlaceholder from './placeholder';
30
- import TemplatePartSelection from './selection';
31
+ import TemplatePartSelectionModal from './selection-modal';
31
32
  import { TemplatePartAdvancedControls } from './advanced-controls';
32
33
  import TemplatePartInnerBlocks from './inner-blocks';
33
34
  import { createTemplatePartId } from './utils/create-template-part-id';
35
+ import {
36
+ useAlternativeBlockPatterns,
37
+ useAlternativeTemplateParts,
38
+ useTemplatePartArea,
39
+ } from './utils/hooks';
34
40
 
35
41
  export default function TemplatePartEdit( {
36
42
  attributes,
@@ -39,29 +45,22 @@ export default function TemplatePartEdit( {
39
45
  } ) {
40
46
  const { slug, theme, tagName, layout = {} } = attributes;
41
47
  const templatePartId = createTemplatePartId( theme, slug );
42
-
43
48
  const [ hasAlreadyRendered, RecursionProvider ] = useNoRecursiveRenders(
44
49
  templatePartId
45
50
  );
51
+ const [
52
+ isTemplatePartSelectionOpen,
53
+ setIsTemplatePartSelectionOpen,
54
+ ] = useState( false );
46
55
 
47
56
  // Set the postId block attribute if it did not exist,
48
57
  // but wait until the inner blocks have loaded to allow
49
58
  // new edits to trigger this.
50
- const {
51
- isResolved,
52
- innerBlocks,
53
- isMissing,
54
- defaultWrapper,
55
- area,
56
- enableSelection,
57
- hasResolvedReplacements,
58
- } = useSelect(
59
+ const { isResolved, innerBlocks, isMissing, area } = useSelect(
59
60
  ( select ) => {
60
- const {
61
- getEditedEntityRecord,
62
- getEntityRecords,
63
- hasFinishedResolution,
64
- } = select( coreStore );
61
+ const { getEditedEntityRecord, hasFinishedResolution } = select(
62
+ coreStore
63
+ );
65
64
  const { getBlocks } = select( blockEditorStore );
66
65
 
67
66
  const getEntityArgs = [
@@ -73,20 +72,6 @@ export default function TemplatePartEdit( {
73
72
  ? getEditedEntityRecord( ...getEntityArgs )
74
73
  : null;
75
74
  const _area = entityRecord?.area || attributes.area;
76
-
77
- // Check whether other entities exist for switching/selection.
78
- const availableReplacementArgs = [
79
- 'postType',
80
- 'wp_template_part',
81
- _area && 'uncategorized' !== _area && { area: _area },
82
- ];
83
- const matchingReplacements = getEntityRecords(
84
- ...availableReplacementArgs
85
- );
86
- const _enableSelection = templatePartId
87
- ? matchingReplacements?.length > 1
88
- : matchingReplacements?.length > 0;
89
-
90
75
  const hasResolvedEntity = templatePartId
91
76
  ? hasFinishedResolution(
92
77
  'getEditedEntityRecord',
@@ -94,33 +79,26 @@ export default function TemplatePartEdit( {
94
79
  )
95
80
  : false;
96
81
 
97
- // FIXME: @wordpress/block-library should not depend on @wordpress/editor.
98
- // Blocks can be loaded into a *non-post* block editor.
99
- // eslint-disable-next-line @wordpress/data-no-store-string-literals
100
- const defaultWrapperElement = select( 'core/editor' )
101
- .__experimentalGetDefaultTemplatePartAreas()
102
- .find( ( { area: value } ) => value === _area )?.area_tag;
103
-
104
82
  return {
105
83
  innerBlocks: getBlocks( clientId ),
106
84
  isResolved: hasResolvedEntity,
107
85
  isMissing: hasResolvedEntity && isEmpty( entityRecord ),
108
- defaultWrapper: defaultWrapperElement || 'div',
109
86
  area: _area,
110
- enableSelection: _enableSelection,
111
- hasResolvedReplacements: hasFinishedResolution(
112
- 'getEntityRecords',
113
- availableReplacementArgs
114
- ),
115
87
  };
116
88
  },
117
89
  [ templatePartId, clientId ]
118
90
  );
119
-
91
+ const { templateParts } = useAlternativeTemplateParts(
92
+ area,
93
+ templatePartId
94
+ );
95
+ const blockPatterns = useAlternativeBlockPatterns( area, clientId );
96
+ const hasReplacements = !! templateParts.length || !! blockPatterns.length;
97
+ const areaObject = useTemplatePartArea( area );
120
98
  const blockProps = useBlockProps();
121
99
  const isPlaceholder = ! slug;
122
100
  const isEntityAvailable = ! isPlaceholder && ! isMissing && isResolved;
123
- const TagName = tagName || defaultWrapper;
101
+ const TagName = tagName || areaObject.tagName;
124
102
 
125
103
  // We don't want to render a missing state if we have any inner blocks.
126
104
  // A new template part is automatically created if we have any inner blocks but no entity.
@@ -160,43 +138,31 @@ export default function TemplatePartEdit( {
160
138
  setAttributes={ setAttributes }
161
139
  isEntityAvailable={ isEntityAvailable }
162
140
  templatePartId={ templatePartId }
163
- defaultWrapper={ defaultWrapper }
141
+ defaultWrapper={ areaObject.tagName }
164
142
  />
165
143
  { isPlaceholder && (
166
144
  <TagName { ...blockProps }>
167
145
  <TemplatePartPlaceholder
168
146
  area={ attributes.area }
147
+ templatePartId={ templatePartId }
169
148
  clientId={ clientId }
170
149
  setAttributes={ setAttributes }
171
- enableSelection={ enableSelection }
172
- hasResolvedReplacements={ hasResolvedReplacements }
150
+ onOpenSelectionModal={ () =>
151
+ setIsTemplatePartSelectionOpen( true )
152
+ }
173
153
  />
174
154
  </TagName>
175
155
  ) }
176
- { isEntityAvailable && enableSelection && (
156
+ { isEntityAvailable && hasReplacements && (
177
157
  <BlockControls>
178
158
  <ToolbarGroup className="wp-block-template-part__block-control-group">
179
- <Dropdown
180
- className="wp-block-template-part__preview-dropdown-button"
181
- contentClassName="wp-block-template-part__preview-dropdown-content"
182
- position="bottom right left"
183
- renderToggle={ ( { isOpen, onToggle } ) => (
184
- <ToolbarButton
185
- aria-expanded={ isOpen }
186
- onClick={ onToggle }
187
- >
188
- { __( 'Replace' ) }
189
- </ToolbarButton>
190
- ) }
191
- renderContent={ ( { onClose } ) => (
192
- <TemplatePartSelection
193
- setAttributes={ setAttributes }
194
- onClose={ onClose }
195
- area={ area }
196
- templatePartId={ templatePartId }
197
- />
198
- ) }
199
- />
159
+ <ToolbarButton
160
+ onClick={ () =>
161
+ setIsTemplatePartSelectionOpen( true )
162
+ }
163
+ >
164
+ { __( 'Replace' ) }
165
+ </ToolbarButton>
200
166
  </ToolbarGroup>
201
167
  </BlockControls>
202
168
  ) }
@@ -215,6 +181,30 @@ export default function TemplatePartEdit( {
215
181
  <Spinner />
216
182
  </TagName>
217
183
  ) }
184
+ { isTemplatePartSelectionOpen && (
185
+ <Modal
186
+ className="block-editor-template-part__selection-modal"
187
+ title={ sprintf(
188
+ // Translators: %s as template part area title ("Header", "Footer", etc.).
189
+ __( 'Choose a %s' ),
190
+ areaObject.label.toLowerCase()
191
+ ) }
192
+ closeLabel={ __( 'Cancel' ) }
193
+ onRequestClose={ () =>
194
+ setIsTemplatePartSelectionOpen( false )
195
+ }
196
+ >
197
+ <TemplatePartSelectionModal
198
+ templatePartId={ templatePartId }
199
+ clientId={ clientId }
200
+ area={ area }
201
+ setAttributes={ setAttributes }
202
+ onClose={ () =>
203
+ setIsTemplatePartSelectionOpen( false )
204
+ }
205
+ />
206
+ </Modal>
207
+ ) }
218
208
  </RecursionProvider>
219
209
  );
220
210
  }
@@ -0,0 +1,78 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { __, sprintf } from '@wordpress/i18n';
5
+ import { Placeholder, Button, Spinner } from '@wordpress/components';
6
+ import { useState } from '@wordpress/element';
7
+
8
+ /**
9
+ * Internal dependencies
10
+ */
11
+ import {
12
+ useAlternativeBlockPatterns,
13
+ useAlternativeTemplateParts,
14
+ useCreateTemplatePartFromBlocks,
15
+ useTemplatePartArea,
16
+ } from './utils/hooks';
17
+ import TitleModal from './title-modal';
18
+
19
+ export default function TemplatePartPlaceholder( {
20
+ area,
21
+ clientId,
22
+ templatePartId,
23
+ onOpenSelectionModal,
24
+ setAttributes,
25
+ } ) {
26
+ const { templateParts, isResolving } = useAlternativeTemplateParts(
27
+ area,
28
+ templatePartId
29
+ );
30
+ const blockPatterns = useAlternativeBlockPatterns( area, clientId );
31
+ const [ showTitleModal, setShowTitleModal ] = useState( false );
32
+ const areaObject = useTemplatePartArea( area );
33
+ const createFromBlocks = useCreateTemplatePartFromBlocks(
34
+ area,
35
+ setAttributes
36
+ );
37
+
38
+ return (
39
+ <Placeholder
40
+ icon={ areaObject.icon }
41
+ label={ areaObject.label }
42
+ instructions={ sprintf(
43
+ // Translators: %s as template part area title ("Header", "Footer", etc.).
44
+ __( 'Choose an existing %s or create a new one.' ),
45
+ areaObject.label.toLowerCase()
46
+ ) }
47
+ >
48
+ { isResolving && <Spinner /> }
49
+
50
+ { ! isResolving &&
51
+ !! ( templateParts.length || blockPatterns.length ) && (
52
+ <Button variant="primary" onClick={ onOpenSelectionModal }>
53
+ { __( 'Choose' ) }
54
+ </Button>
55
+ ) }
56
+
57
+ { ! isResolving && (
58
+ <Button
59
+ variant="secondary"
60
+ onClick={ () => {
61
+ setShowTitleModal( true );
62
+ } }
63
+ >
64
+ { __( 'Start blank' ) }
65
+ </Button>
66
+ ) }
67
+ { showTitleModal && (
68
+ <TitleModal
69
+ areaLabel={ areaObject.label }
70
+ onClose={ () => setShowTitleModal( false ) }
71
+ onSubmit={ ( title ) => {
72
+ createFromBlocks( [], title );
73
+ } }
74
+ />
75
+ ) }
76
+ </Placeholder>
77
+ );
78
+ }
@@ -0,0 +1,115 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useCallback, useMemo } from '@wordpress/element';
5
+ import { __, sprintf } from '@wordpress/i18n';
6
+ import { store as noticesStore } from '@wordpress/notices';
7
+ import { useDispatch } from '@wordpress/data';
8
+ import { parse } from '@wordpress/blocks';
9
+ import { useAsyncList } from '@wordpress/compose';
10
+ import {
11
+ __experimentalBlockPatternsList as BlockPatternsList,
12
+ store as blockEditorStore,
13
+ } from '@wordpress/block-editor';
14
+
15
+ /**
16
+ * Internal dependencies
17
+ */
18
+ import {
19
+ useAlternativeBlockPatterns,
20
+ useAlternativeTemplateParts,
21
+ useCreateTemplatePartFromBlocks,
22
+ } from './utils/hooks';
23
+ import { createTemplatePartId } from './utils/create-template-part-id';
24
+
25
+ export default function TemplatePartSelectionModal( {
26
+ setAttributes,
27
+ onClose,
28
+ templatePartId = null,
29
+ area,
30
+ clientId,
31
+ } ) {
32
+ // When the templatePartId is undefined,
33
+ // it means the user is creating a new one from the placeholder.
34
+ const isReplacingTemplatePartContent = !! templatePartId;
35
+ const { templateParts } = useAlternativeTemplateParts(
36
+ area,
37
+ templatePartId
38
+ );
39
+ // We can map template parts to block patters to reuse the BlockPatternsList UI
40
+ const templartPartsAsBlockPatterns = useMemo( () => {
41
+ return templateParts.map( ( templatePart ) => ( {
42
+ name: createTemplatePartId( templatePart.theme, templatePart.slug ),
43
+ title: templatePart.title.rendered,
44
+ blocks: parse( templatePart.content.raw ),
45
+ templatePart,
46
+ } ) );
47
+ }, [ templateParts ] );
48
+ const shownTemplateParts = useAsyncList( templartPartsAsBlockPatterns );
49
+ const { createSuccessNotice } = useDispatch( noticesStore );
50
+ const blockPatterns = useAlternativeBlockPatterns( area, clientId );
51
+ const shownBlockPatterns = useAsyncList( blockPatterns );
52
+ const { replaceInnerBlocks } = useDispatch( blockEditorStore );
53
+
54
+ const onTemplatePartSelect = useCallback( ( templatePart ) => {
55
+ setAttributes( {
56
+ slug: templatePart.slug,
57
+ theme: templatePart.theme,
58
+ area: undefined,
59
+ } );
60
+ createSuccessNotice(
61
+ sprintf(
62
+ /* translators: %s: template part title. */
63
+ __( 'Template Part "%s" inserted.' ),
64
+ templatePart.title?.rendered || templatePart.slug
65
+ ),
66
+ {
67
+ type: 'snackbar',
68
+ }
69
+ );
70
+ onClose();
71
+ }, [] );
72
+
73
+ const createFromBlocks = useCreateTemplatePartFromBlocks(
74
+ area,
75
+ setAttributes
76
+ );
77
+
78
+ return (
79
+ <>
80
+ <div className="block-library-template-part__selection-content">
81
+ { !! templartPartsAsBlockPatterns.length && (
82
+ <div>
83
+ <h2>{ __( 'Existing template parts' ) }</h2>
84
+ <BlockPatternsList
85
+ blockPatterns={ templartPartsAsBlockPatterns }
86
+ shownPatterns={ shownTemplateParts }
87
+ onClickPattern={ ( pattern ) => {
88
+ onTemplatePartSelect( pattern.templatePart );
89
+ } }
90
+ />
91
+ </div>
92
+ ) }
93
+
94
+ { !! blockPatterns.length && (
95
+ <div>
96
+ <h2>{ __( 'Patterns' ) }</h2>
97
+ <BlockPatternsList
98
+ blockPatterns={ blockPatterns }
99
+ shownPatterns={ shownBlockPatterns }
100
+ onClickPattern={ ( pattern, blocks ) => {
101
+ if ( isReplacingTemplatePartContent ) {
102
+ replaceInnerBlocks( clientId, blocks );
103
+ } else {
104
+ createFromBlocks( blocks, pattern.title );
105
+ }
106
+
107
+ onClose();
108
+ } }
109
+ />
110
+ </div>
111
+ ) }
112
+ </div>
113
+ </>
114
+ );
115
+ }
@@ -0,0 +1,59 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useState } from '@wordpress/element';
5
+ import { __, sprintf } from '@wordpress/i18n';
6
+ import {
7
+ TextControl,
8
+ Flex,
9
+ FlexItem,
10
+ Button,
11
+ Modal,
12
+ } from '@wordpress/components';
13
+
14
+ export default function TitleModal( { areaLabel, onClose, onSubmit } ) {
15
+ // Restructure onCreate to set the blocks on local state.
16
+ // Add modal to confirm title and trigger onCreate.
17
+ const [ title, setTitle ] = useState( __( 'Untitled Template Part' ) );
18
+
19
+ const submitForCreation = ( event ) => {
20
+ event.preventDefault();
21
+ onSubmit( title );
22
+ };
23
+
24
+ return (
25
+ <Modal
26
+ title={ sprintf(
27
+ // Translators: %s as template part area title ("Header", "Footer", etc.).
28
+ __( 'Name and create your new %s' ),
29
+ areaLabel.toLowerCase()
30
+ ) }
31
+ closeLabel={ __( 'Cancel' ) }
32
+ overlayClassName="wp-block-template-part__placeholder-create-new__title-form"
33
+ onRequestClose={ onClose }
34
+ >
35
+ <form onSubmit={ submitForCreation }>
36
+ <TextControl
37
+ label={ __( 'Name' ) }
38
+ value={ title }
39
+ onChange={ setTitle }
40
+ />
41
+ <Flex
42
+ className="wp-block-template-part__placeholder-create-new__title-form-actions"
43
+ justify="flex-end"
44
+ >
45
+ <FlexItem>
46
+ <Button
47
+ variant="primary"
48
+ type="submit"
49
+ disabled={ ! title.length }
50
+ aria-disabled={ ! title.length }
51
+ >
52
+ { __( 'Create' ) }
53
+ </Button>
54
+ </FlexItem>
55
+ </Flex>
56
+ </form>
57
+ </Modal>
58
+ );
59
+ }