@wordpress/block-library 7.15.0 → 7.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (180) hide show
  1. package/CHANGELOG.md +3 -0
  2. package/build/code/utils.js +3 -3
  3. package/build/code/utils.js.map +1 -1
  4. package/build/comments-pagination-numbers/index.js +7 -0
  5. package/build/comments-pagination-numbers/index.js.map +1 -1
  6. package/build/gallery/gallery.js +2 -28
  7. package/build/gallery/gallery.js.map +1 -1
  8. package/build/group/edit.js +1 -1
  9. package/build/group/edit.js.map +1 -1
  10. package/build/navigation/edit/index.js +12 -12
  11. package/build/navigation/edit/index.js.map +1 -1
  12. package/build/paragraph/deprecated.js +49 -10
  13. package/build/paragraph/deprecated.js.map +1 -1
  14. package/build/paragraph/drop-zone.js +99 -0
  15. package/build/paragraph/drop-zone.js.map +1 -0
  16. package/build/paragraph/edit.js +30 -6
  17. package/build/paragraph/edit.js.map +1 -1
  18. package/build/paragraph/save.js +3 -1
  19. package/build/paragraph/save.js.map +1 -1
  20. package/build/post-author/edit.js +20 -2
  21. package/build/post-author/edit.js.map +1 -1
  22. package/build/post-author/index.js +8 -0
  23. package/build/post-author/index.js.map +1 -1
  24. package/build/post-content/edit.js +6 -1
  25. package/build/post-content/edit.js.map +1 -1
  26. package/build/post-featured-image/index.js +1 -1
  27. package/build/post-featured-image/overlay.js +2 -2
  28. package/build/post-featured-image/overlay.js.map +1 -1
  29. package/build/post-terms/index.js +4 -0
  30. package/build/post-terms/index.js.map +1 -1
  31. package/build/query/edit/inspector-controls/author-control.js +2 -1
  32. package/build/query/edit/inspector-controls/author-control.js.map +1 -1
  33. package/build/query/edit/inspector-controls/index.js +1 -1
  34. package/build/query/edit/inspector-controls/index.js.map +1 -1
  35. package/build/query/edit/inspector-controls/parent-control.js +2 -1
  36. package/build/query/edit/inspector-controls/parent-control.js.map +1 -1
  37. package/build/query/edit/inspector-controls/taxonomy-controls.js +2 -1
  38. package/build/query/edit/inspector-controls/taxonomy-controls.js.map +1 -1
  39. package/build/query/utils.js +1 -1
  40. package/build/query/utils.js.map +1 -1
  41. package/build/quote/index.js +0 -1
  42. package/build/quote/index.js.map +1 -1
  43. package/build/site-title/index.js +2 -1
  44. package/build/site-title/index.js.map +1 -1
  45. package/build/template-part/index.js +2 -2
  46. package/build/template-part/index.js.map +1 -1
  47. package/build/video/edit.js +13 -1
  48. package/build/video/edit.js.map +1 -1
  49. package/build-module/code/utils.js +3 -3
  50. package/build-module/code/utils.js.map +1 -1
  51. package/build-module/comments-pagination-numbers/index.js +7 -0
  52. package/build-module/comments-pagination-numbers/index.js.map +1 -1
  53. package/build-module/gallery/gallery.js +2 -29
  54. package/build-module/gallery/gallery.js.map +1 -1
  55. package/build-module/group/edit.js +1 -1
  56. package/build-module/group/edit.js.map +1 -1
  57. package/build-module/navigation/edit/index.js +12 -12
  58. package/build-module/navigation/edit/index.js.map +1 -1
  59. package/build-module/paragraph/deprecated.js +49 -11
  60. package/build-module/paragraph/deprecated.js.map +1 -1
  61. package/build-module/paragraph/drop-zone.js +88 -0
  62. package/build-module/paragraph/drop-zone.js.map +1 -0
  63. package/build-module/paragraph/edit.js +29 -6
  64. package/build-module/paragraph/edit.js.map +1 -1
  65. package/build-module/paragraph/save.js +2 -1
  66. package/build-module/paragraph/save.js.map +1 -1
  67. package/build-module/post-author/edit.js +21 -2
  68. package/build-module/post-author/edit.js.map +1 -1
  69. package/build-module/post-author/index.js +8 -0
  70. package/build-module/post-author/index.js.map +1 -1
  71. package/build-module/post-content/edit.js +6 -1
  72. package/build-module/post-content/edit.js.map +1 -1
  73. package/build-module/post-featured-image/index.js +1 -1
  74. package/build-module/post-featured-image/overlay.js +2 -2
  75. package/build-module/post-featured-image/overlay.js.map +1 -1
  76. package/build-module/post-terms/index.js +4 -0
  77. package/build-module/post-terms/index.js.map +1 -1
  78. package/build-module/query/edit/inspector-controls/author-control.js +2 -1
  79. package/build-module/query/edit/inspector-controls/author-control.js.map +1 -1
  80. package/build-module/query/edit/inspector-controls/index.js +1 -1
  81. package/build-module/query/edit/inspector-controls/index.js.map +1 -1
  82. package/build-module/query/edit/inspector-controls/parent-control.js +2 -1
  83. package/build-module/query/edit/inspector-controls/parent-control.js.map +1 -1
  84. package/build-module/query/edit/inspector-controls/taxonomy-controls.js +2 -1
  85. package/build-module/query/edit/inspector-controls/taxonomy-controls.js.map +1 -1
  86. package/build-module/query/utils.js +1 -1
  87. package/build-module/query/utils.js.map +1 -1
  88. package/build-module/quote/index.js +0 -1
  89. package/build-module/quote/index.js.map +1 -1
  90. package/build-module/site-title/index.js +2 -1
  91. package/build-module/site-title/index.js.map +1 -1
  92. package/build-module/template-part/index.js +2 -2
  93. package/build-module/template-part/index.js.map +1 -1
  94. package/build-module/video/edit.js +15 -3
  95. package/build-module/video/edit.js.map +1 -1
  96. package/build-style/classic-rtl.css +85 -0
  97. package/build-style/classic.css +85 -0
  98. package/build-style/code/style-rtl.css +3 -0
  99. package/build-style/code/style.css +3 -0
  100. package/build-style/editor-rtl.css +110 -31
  101. package/build-style/editor.css +110 -31
  102. package/build-style/group/editor-rtl.css +11 -1
  103. package/build-style/group/editor.css +11 -1
  104. package/build-style/image/editor-rtl.css +3 -0
  105. package/build-style/image/editor.css +3 -0
  106. package/build-style/navigation/editor-rtl.css +15 -1
  107. package/build-style/navigation/editor.css +15 -1
  108. package/build-style/navigation/style-rtl.css +3 -0
  109. package/build-style/navigation/style.css +3 -0
  110. package/build-style/paragraph/editor-rtl.css +16 -0
  111. package/build-style/paragraph/editor.css +16 -0
  112. package/build-style/paragraph/style-rtl.css +5 -0
  113. package/build-style/paragraph/style.css +5 -0
  114. package/build-style/post-featured-image/editor-rtl.css +39 -29
  115. package/build-style/post-featured-image/editor.css +39 -29
  116. package/build-style/post-terms/style-rtl.css +4 -1
  117. package/build-style/post-terms/style.css +4 -1
  118. package/build-style/site-title/editor-rtl.css +4 -0
  119. package/build-style/site-title/editor.css +4 -0
  120. package/build-style/site-title/style-rtl.css +79 -0
  121. package/build-style/site-title/style.css +79 -0
  122. package/build-style/style-rtl.css +19 -1
  123. package/build-style/style.css +19 -1
  124. package/build-style/video/editor-rtl.css +22 -0
  125. package/build-style/video/editor.css +22 -0
  126. package/package.json +28 -28
  127. package/src/archives/index.php +4 -7
  128. package/src/categories/index.php +1 -1
  129. package/src/classic.scss +15 -0
  130. package/src/code/style.scss +12 -7
  131. package/src/code/utils.js +3 -3
  132. package/src/comment-author-name/index.php +1 -1
  133. package/src/comment-reply-link/index.php +1 -1
  134. package/src/comment-template/index.php +18 -9
  135. package/src/comments-pagination-numbers/block.json +7 -0
  136. package/src/cover/index.php +1 -1
  137. package/src/gallery/gallery.js +1 -31
  138. package/src/group/edit.js +1 -1
  139. package/src/image/editor.scss +4 -0
  140. package/src/latest-posts/index.php +1 -1
  141. package/src/navigation/edit/index.js +12 -10
  142. package/src/navigation/editor.scss +6 -0
  143. package/src/navigation/style.scss +8 -0
  144. package/src/navigation-submenu/index.php +11 -2
  145. package/src/page-list/index.php +3 -3
  146. package/src/paragraph/deprecated.js +36 -0
  147. package/src/paragraph/drop-zone.js +105 -0
  148. package/src/paragraph/edit.js +37 -9
  149. package/src/paragraph/editor.scss +20 -0
  150. package/src/paragraph/save.js +5 -1
  151. package/src/paragraph/style.scss +5 -0
  152. package/src/post-author/block.json +8 -0
  153. package/src/post-author/edit.js +29 -3
  154. package/src/post-author/index.php +7 -1
  155. package/src/post-content/edit.js +3 -1
  156. package/src/post-featured-image/block.json +1 -1
  157. package/src/post-featured-image/editor.scss +79 -72
  158. package/src/post-featured-image/index.php +18 -24
  159. package/src/post-featured-image/overlay.js +17 -14
  160. package/src/post-terms/block.json +4 -0
  161. package/src/post-terms/style.scss +7 -2
  162. package/src/query/edit/inspector-controls/author-control.js +1 -0
  163. package/src/query/edit/inspector-controls/index.js +1 -4
  164. package/src/query/edit/inspector-controls/parent-control.js +1 -0
  165. package/src/query/edit/inspector-controls/taxonomy-controls.js +1 -0
  166. package/src/query/utils.js +1 -1
  167. package/src/quote/block.json +0 -1
  168. package/src/site-title/block.json +2 -1
  169. package/src/site-title/editor.scss +6 -0
  170. package/src/site-title/style.scss +5 -0
  171. package/src/style.scss +1 -0
  172. package/src/tag-cloud/index.php +1 -8
  173. package/src/template-part/index.js +2 -2
  174. package/src/video/edit.js +19 -0
  175. package/src/video/editor.scss +37 -0
  176. package/build/navigation-submenu/view.js +0 -56
  177. package/build/navigation-submenu/view.js.map +0 -1
  178. package/build-module/navigation-submenu/view.js +0 -54
  179. package/build-module/navigation-submenu/view.js.map +0 -1
  180. package/src/navigation-submenu/view.js +0 -67
@@ -34,7 +34,7 @@ function render_block_core_comment_reply_link( $attributes, $content, $block ) {
34
34
 
35
35
  // Compute comment's depth iterating over its ancestors.
36
36
  while ( ! empty( $parent_id ) ) {
37
- $depth++;
37
+ ++$depth;
38
38
  $parent_id = get_comment( $parent_id )->comment_parent;
39
39
  }
40
40
 
@@ -16,6 +16,8 @@
16
16
  */
17
17
  function block_core_comment_template_render_comments( $comments, $block ) {
18
18
  global $comment_depth;
19
+ $thread_comments = get_option( 'thread_comments' );
20
+ $thread_comments_depth = get_option( 'thread_comments_depth' );
19
21
 
20
22
  if ( empty( $comment_depth ) ) {
21
23
  $comment_depth = 1;
@@ -46,21 +48,28 @@ function block_core_comment_template_render_comments( $comments, $block ) {
46
48
 
47
49
  // If the comment has children, recurse to create the HTML for the nested
48
50
  // comments.
49
- if ( ! empty( $children ) ) {
50
- $comment_depth += 1;
51
- $inner_content = block_core_comment_template_render_comments(
52
- $children,
53
- $block
54
- );
55
- $block_content .= sprintf( '<ol>%1$s</ol>', $inner_content );
56
- $comment_depth -= 1;
51
+ if ( ! empty( $children ) && ! empty( $thread_comments ) ) {
52
+ if ( $comment_depth < $thread_comments_depth ) {
53
+ ++$comment_depth;
54
+ $inner_content = block_core_comment_template_render_comments(
55
+ $children,
56
+ $block
57
+ );
58
+ $block_content .= sprintf( '<ol>%1$s</ol>', $inner_content );
59
+ --$comment_depth;
60
+ } else {
61
+ $inner_content = block_core_comment_template_render_comments(
62
+ $children,
63
+ $block
64
+ );
65
+ $block_content .= sprintf( $inner_content );
66
+ }
57
67
  }
58
68
 
59
69
  $content .= sprintf( '<li id="comment-%1$s" %2$s>%3$s</li>', $comment->comment_ID, $comment_classes, $block_content );
60
70
  }
61
71
 
62
72
  return $content;
63
-
64
73
  }
65
74
 
66
75
  /**
@@ -11,6 +11,13 @@
11
11
  "supports": {
12
12
  "reusable": false,
13
13
  "html": false,
14
+ "color": {
15
+ "gradients": true,
16
+ "text": false,
17
+ "__experimentalDefaultControls": {
18
+ "background": true
19
+ }
20
+ },
14
21
  "typography": {
15
22
  "fontSize": true,
16
23
  "lineHeight": true,
@@ -25,7 +25,7 @@ function render_block_core_cover( $attributes, $content ) {
25
25
  );
26
26
 
27
27
  if ( isset( $attributes['focalPoint'] ) ) {
28
- $object_position = round( $attributes['focalPoint']['x'] * 100 ) . '%' . ' ' . round( $attributes['focalPoint']['y'] * 100 ) . '%';
28
+ $object_position = round( $attributes['focalPoint']['x'] * 100 ) . '% ' . round( $attributes['focalPoint']['y'] * 100 ) . '%';
29
29
  $attr['data-object-position'] = $object_position;
30
30
  $attr['style'] = 'object-position: ' . $object_position;
31
31
  }
@@ -12,7 +12,6 @@ import {
12
12
  __experimentalGetElementClassName,
13
13
  } from '@wordpress/block-editor';
14
14
  import { VisuallyHidden } from '@wordpress/components';
15
- import { useState, useEffect } from '@wordpress/element';
16
15
  import { __ } from '@wordpress/i18n';
17
16
  import { createBlock, getDefaultBlockName } from '@wordpress/blocks';
18
17
  import { View } from '@wordpress/primitives';
@@ -38,26 +37,6 @@ export const Gallery = ( props ) => {
38
37
  __experimentalLayout: { type: 'default', alignments: [] },
39
38
  } );
40
39
 
41
- const [ captionFocused, setCaptionFocused ] = useState( false );
42
-
43
- function onFocusCaption() {
44
- if ( ! captionFocused ) {
45
- setCaptionFocused( true );
46
- }
47
- }
48
-
49
- function removeCaptionFocus() {
50
- if ( captionFocused ) {
51
- setCaptionFocused( false );
52
- }
53
- }
54
-
55
- useEffect( () => {
56
- if ( ! isSelected ) {
57
- setCaptionFocused( false );
58
- }
59
- }, [ isSelected ] );
60
-
61
40
  return (
62
41
  <figure
63
42
  { ...innerBlocksProps }
@@ -74,17 +53,12 @@ export const Gallery = ( props ) => {
74
53
  >
75
54
  { children }
76
55
  { isSelected && ! children && (
77
- <View
78
- className="blocks-gallery-media-placeholder-wrapper"
79
- onClick={ removeCaptionFocus }
80
- >
56
+ <View className="blocks-gallery-media-placeholder-wrapper">
81
57
  { mediaPlaceholder }
82
58
  </View>
83
59
  ) }
84
60
  <RichTextVisibilityHelper
85
61
  isHidden={ ! isSelected && RichText.isEmpty( caption ) }
86
- captionFocused={ captionFocused }
87
- onFocusCaption={ onFocusCaption }
88
62
  tagName="figcaption"
89
63
  className={ classnames(
90
64
  'blocks-gallery-caption',
@@ -105,8 +79,6 @@ export const Gallery = ( props ) => {
105
79
 
106
80
  function RichTextVisibilityHelper( {
107
81
  isHidden,
108
- captionFocused,
109
- onFocusCaption,
110
82
  className,
111
83
  value,
112
84
  placeholder,
@@ -125,8 +97,6 @@ function RichTextVisibilityHelper( {
125
97
  placeholder={ placeholder }
126
98
  className={ className }
127
99
  tagName={ tagName }
128
- isSelected={ captionFocused }
129
- onClick={ onFocusCaption }
130
100
  { ...richTextProps }
131
101
  />
132
102
  );
package/src/group/edit.js CHANGED
@@ -53,7 +53,7 @@ function GroupEdit( { attributes, setAttributes, clientId } ) {
53
53
  ? { ...defaultLayout, ...layout, type: 'default' }
54
54
  : { ...defaultLayout, ...layout };
55
55
  const { type = 'default' } = usedLayout;
56
- const layoutSupportEnabled = themeSupportsLayout || type !== 'default';
56
+ const layoutSupportEnabled = themeSupportsLayout || type === 'flex';
57
57
 
58
58
  const blockProps = useBlockProps();
59
59
 
@@ -22,6 +22,10 @@
22
22
  .components-placeholder__illustration {
23
23
  display: none;
24
24
  }
25
+
26
+ &::before {
27
+ opacity: 0;
28
+ }
25
29
  }
26
30
 
27
31
  // Remove the transition while we still have a legacy placeholder style.
@@ -55,7 +55,7 @@ function render_block_core_latest_posts( $attributes ) {
55
55
  $args['author'] = $attributes['selectedAuthor'];
56
56
  }
57
57
 
58
- $query = new WP_Query;
58
+ $query = new WP_Query();
59
59
  $recent_posts = $query->query( $args );
60
60
 
61
61
  if ( isset( $attributes['displayFeaturedImage'] ) && $attributes['displayFeaturedImage'] ) {
@@ -282,16 +282,18 @@ function Navigation( {
282
282
  hasResolvedNavigationMenus &&
283
283
  ! hasUncontrolledInnerBlocks;
284
284
 
285
- if ( isPlaceholder && ! ref ) {
286
- /**
287
- * this fallback only displays (both in editor and on front)
288
- * the list of pages block if no menu is available as a fallback.
289
- * We don't want the fallback to request a save,
290
- * nor to be undoable, hence we mark it non persistent.
291
- */
292
- __unstableMarkNextChangeAsNotPersistent();
293
- replaceInnerBlocks( clientId, [ createBlock( 'core/page-list' ) ] );
294
- }
285
+ useEffect( () => {
286
+ if ( isPlaceholder && ! ref ) {
287
+ /**
288
+ * this fallback only displays (both in editor and on front)
289
+ * the list of pages block if no menu is available as a fallback.
290
+ * We don't want the fallback to request a save,
291
+ * nor to be undoable, hence we mark it non persistent.
292
+ */
293
+ __unstableMarkNextChangeAsNotPersistent();
294
+ replaceInnerBlocks( clientId, [ createBlock( 'core/page-list' ) ] );
295
+ }
296
+ }, [ clientId, isPlaceholder, ref ] );
295
297
 
296
298
  const isEntityAvailable =
297
299
  ! isNavigationMenuMissing && isNavigationMenuResolved;
@@ -629,3 +629,9 @@ body.editor-styles-wrapper
629
629
  margin-bottom: $grid-unit-20;
630
630
  width: 100%;
631
631
  }
632
+
633
+ // Buttons inside a disabled component get semitransparent when there's a clickthrough overlay.
634
+ // Since this navigation button is content rather than UI, however, override that.
635
+ .wp-block-navigation__responsive-container-open.components-button {
636
+ opacity: 1;
637
+ }
@@ -47,6 +47,14 @@ $navigation-icon-size: 24px;
47
47
  display: block;
48
48
  }
49
49
 
50
+ // This rule needs extra specificity so that it inherits the correct color from its parent.
51
+ // Otherwise, a link color set by a parent group can override the value.
52
+ // This also fixes an issue where a navigation with an explicitly set color is overridden
53
+ // by link colors defined in Global Styles.
54
+ .wp-block-navigation-item__content.wp-block-navigation-item__content {
55
+ color: inherit;
56
+ }
57
+
50
58
  // The following rules provide class based application of user selected text
51
59
  // decoration via block supports.
52
60
  &.has-text-decoration-underline .wp-block-navigation-item__content {
@@ -148,7 +148,7 @@ function render_block_core_navigation_submenu( $attributes, $content, $block ) {
148
148
 
149
149
  $css_classes = trim( implode( ' ', $classes ) );
150
150
  $has_submenu = count( $block->inner_blocks ) > 0;
151
- $is_active = ! empty( $attributes['id'] ) && ( get_the_ID() === (int) $attributes['id'] );
151
+ $is_active = ! empty( $attributes['id'] ) && ( get_queried_object_id() === (int) $attributes['id'] );
152
152
 
153
153
  $show_submenu_indicators = isset( $block->context['showSubmenuIcon'] ) && $block->context['showSubmenuIcon'];
154
154
  $open_on_click = isset( $block->context['openSubmenusOnClick'] ) && $block->context['openSubmenusOnClick'];
@@ -183,7 +183,16 @@ function render_block_core_navigation_submenu( $attributes, $content, $block ) {
183
183
  if ( ! $open_on_click ) {
184
184
  $item_url = isset( $attributes['url'] ) ? $attributes['url'] : '';
185
185
  // Start appending HTML attributes to anchor tag.
186
- $html .= '<a class="wp-block-navigation-item__content" href="' . esc_url( $item_url ) . '"';
186
+ $html .= '<a class="wp-block-navigation-item__content"';
187
+
188
+ // The href attribute on a and area elements is not required;
189
+ // when those elements do not have href attributes they do not create hyperlinks.
190
+ // But also The href attribute must have a value that is a valid URL potentially
191
+ // surrounded by spaces.
192
+ // see: https://html.spec.whatwg.org/multipage/links.html#links-created-by-a-and-area-elements.
193
+ if ( ! empty( $item_url ) ) {
194
+ $html .= ' href="' . esc_url( $item_url ) . '"';
195
+ }
187
196
 
188
197
  if ( $is_active ) {
189
198
  $html .= ' aria-current="page"';
@@ -189,7 +189,7 @@ function block_core_page_list_render_nested_page_list( $open_submenus_on_click,
189
189
 
190
190
  if ( isset( $page['children'] ) && $is_navigation_child && $open_submenus_on_click ) {
191
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>';
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
  }
@@ -243,7 +243,7 @@ function block_core_page_list_nest_pages( $current_level, $children ) {
243
243
  */
244
244
  function render_block_core_page_list( $attributes, $content, $block ) {
245
245
  static $block_id = 0;
246
- $block_id++;
246
+ ++$block_id;
247
247
 
248
248
  $all_pages = get_pages(
249
249
  array(
@@ -264,7 +264,7 @@ function render_block_core_page_list( $attributes, $content, $block ) {
264
264
  $active_page_ancestor_ids = array();
265
265
 
266
266
  foreach ( (array) $all_pages as $page ) {
267
- $is_active = ! empty( $page->ID ) && ( get_the_ID() === $page->ID );
267
+ $is_active = ! empty( $page->ID ) && ( get_queried_object_id() === $page->ID );
268
268
 
269
269
  if ( $is_active ) {
270
270
  $active_page_ancestor_ids = get_post_ancestors( $page->ID );
@@ -11,8 +11,11 @@ import {
11
11
  getColorClassName,
12
12
  getFontSizeClass,
13
13
  RichText,
14
+ useBlockProps,
14
15
  } from '@wordpress/block-editor';
15
16
 
17
+ import { isRTL } from '@wordpress/i18n';
18
+
16
19
  const supports = {
17
20
  className: false,
18
21
  };
@@ -90,6 +93,39 @@ const migrateCustomColorsAndFontSizes = ( attributes ) => {
90
93
  const { style, ...restBlockAttributes } = blockAttributes;
91
94
 
92
95
  const deprecated = [
96
+ // Version without drop cap on aligned text.
97
+ {
98
+ supports,
99
+ attributes: {
100
+ ...restBlockAttributes,
101
+ customTextColor: {
102
+ type: 'string',
103
+ },
104
+ customBackgroundColor: {
105
+ type: 'string',
106
+ },
107
+ customFontSize: {
108
+ type: 'number',
109
+ },
110
+ },
111
+ save( { attributes } ) {
112
+ const { align, content, dropCap, direction } = attributes;
113
+ const className = classnames( {
114
+ 'has-drop-cap':
115
+ align === ( isRTL() ? 'left' : 'right' ) ||
116
+ align === 'center'
117
+ ? false
118
+ : dropCap,
119
+ [ `has-text-align-${ align }` ]: align,
120
+ } );
121
+
122
+ return (
123
+ <p { ...useBlockProps.save( { className, dir: direction } ) }>
124
+ <RichText.Content value={ content } />
125
+ </p>
126
+ );
127
+ },
128
+ },
93
129
  {
94
130
  supports,
95
131
  attributes: {
@@ -0,0 +1,105 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useState } from '@wordpress/element';
5
+ import { useSelect } from '@wordpress/data';
6
+ import {
7
+ __experimentalUseOnBlockDrop as useOnBlockDrop,
8
+ store as blockEditorStore,
9
+ } from '@wordpress/block-editor';
10
+ import {
11
+ __experimentalUseDropZone as useDropZone,
12
+ useReducedMotion,
13
+ } from '@wordpress/compose';
14
+ import {
15
+ Popover,
16
+ __unstableMotion as motion,
17
+ __unstableAnimatePresence as AnimatePresence,
18
+ } from '@wordpress/components';
19
+
20
+ const animateVariants = {
21
+ hide: { opacity: 0, scaleY: 0.75 },
22
+ show: { opacity: 1, scaleY: 1 },
23
+ exit: { opacity: 0, scaleY: 0.9 },
24
+ };
25
+
26
+ export default function DropZone( { paragraphElement, clientId } ) {
27
+ const { rootClientId, blockIndex } = useSelect(
28
+ ( select ) => {
29
+ const selectors = select( blockEditorStore );
30
+ return {
31
+ rootClientId: selectors.getBlockRootClientId( clientId ),
32
+ blockIndex: selectors.getBlockIndex( clientId ),
33
+ };
34
+ },
35
+ [ clientId ]
36
+ );
37
+ const onBlockDrop = useOnBlockDrop( rootClientId, blockIndex, {
38
+ action: 'replace',
39
+ } );
40
+ const [ isDragging, setIsDragging ] = useState( false );
41
+ const [ isVisible, setIsVisible ] = useState( false );
42
+ const popoverRef = useDropZone( {
43
+ onDragStart: () => {
44
+ setIsDragging( true );
45
+ },
46
+ onDragEnd: () => {
47
+ setIsDragging( false );
48
+ },
49
+ } );
50
+ const dropZoneRef = useDropZone( {
51
+ onDrop: onBlockDrop,
52
+ onDragEnter: () => {
53
+ setIsVisible( true );
54
+ },
55
+ onDragLeave: () => {
56
+ setIsVisible( false );
57
+ },
58
+ } );
59
+ const reducedMotion = useReducedMotion();
60
+
61
+ return (
62
+ <Popover
63
+ anchor={ paragraphElement }
64
+ animate={ false }
65
+ placement="top-start"
66
+ focusOnMount={ false }
67
+ flip={ false }
68
+ resize={ false }
69
+ className="wp-block-paragraph__drop-zone"
70
+ ref={ popoverRef }
71
+ >
72
+ { isDragging ? (
73
+ <div
74
+ className="wp-block-paragraph__drop-zone-backdrop"
75
+ ref={ dropZoneRef }
76
+ style={ {
77
+ width: paragraphElement?.offsetWidth,
78
+ height: paragraphElement?.offsetHeight,
79
+ } }
80
+ >
81
+ <AnimatePresence>
82
+ { isVisible ? (
83
+ <motion.div
84
+ key="drop-zone-foreground"
85
+ data-testid="empty-paragraph-drop-zone"
86
+ initial={
87
+ reducedMotion
88
+ ? animateVariants.show
89
+ : animateVariants.hide
90
+ }
91
+ animate={ animateVariants.show }
92
+ exit={
93
+ reducedMotion
94
+ ? animateVariants.show
95
+ : animateVariants.exit
96
+ }
97
+ className="wp-block-paragraph__drop-zone-foreground"
98
+ />
99
+ ) : null }
100
+ </AnimatePresence>
101
+ </div>
102
+ ) : null }
103
+ </Popover>
104
+ );
105
+ }
@@ -6,6 +6,7 @@ import classnames from 'classnames';
6
6
  /**
7
7
  * WordPress dependencies
8
8
  */
9
+ import { useState } from '@wordpress/element';
9
10
  import { __, _x, isRTL } from '@wordpress/i18n';
10
11
  import {
11
12
  ToolbarButton,
@@ -20,6 +21,7 @@ import {
20
21
  useBlockProps,
21
22
  useSetting,
22
23
  } from '@wordpress/block-editor';
24
+ import { useMergeRefs } from '@wordpress/compose';
23
25
  import { createBlock } from '@wordpress/blocks';
24
26
  import { formatLtr } from '@wordpress/icons';
25
27
 
@@ -27,6 +29,7 @@ import { formatLtr } from '@wordpress/icons';
27
29
  * Internal dependencies
28
30
  */
29
31
  import { useOnEnter } from './use-enter';
32
+ import DropZone from './drop-zone';
30
33
 
31
34
  const name = 'core/paragraph';
32
35
 
@@ -45,6 +48,10 @@ function ParagraphRTLControl( { direction, setDirection } ) {
45
48
  );
46
49
  }
47
50
 
51
+ function hasDropCapDisabled( align ) {
52
+ return align === ( isRTL() ? 'left' : 'right' ) || align === 'center';
53
+ }
54
+
48
55
  function ParagraphBlock( {
49
56
  attributes,
50
57
  mergeBlocks,
@@ -55,22 +62,40 @@ function ParagraphBlock( {
55
62
  } ) {
56
63
  const { align, content, direction, dropCap, placeholder } = attributes;
57
64
  const isDropCapFeatureEnabled = useSetting( 'typography.dropCap' );
65
+ const [ paragraphElement, setParagraphElement ] = useState( null );
58
66
  const blockProps = useBlockProps( {
59
- ref: useOnEnter( { clientId, content } ),
67
+ ref: useMergeRefs( [
68
+ useOnEnter( { clientId, content } ),
69
+ setParagraphElement,
70
+ ] ),
60
71
  className: classnames( {
61
- 'has-drop-cap': dropCap,
72
+ 'has-drop-cap': hasDropCapDisabled( align ) ? false : dropCap,
62
73
  [ `has-text-align-${ align }` ]: align,
63
74
  } ),
64
75
  style: { direction },
65
76
  } );
66
77
 
78
+ let helpText;
79
+ if ( hasDropCapDisabled( align ) ) {
80
+ helpText = __( 'Not available for aligned text.' );
81
+ } else if ( dropCap ) {
82
+ helpText = __( 'Showing large initial letter.' );
83
+ } else {
84
+ helpText = __( 'Toggle to show a large initial letter.' );
85
+ }
86
+
67
87
  return (
68
88
  <>
69
89
  <BlockControls group="block">
70
90
  <AlignmentControl
71
91
  value={ align }
72
92
  onChange={ ( newAlign ) =>
73
- setAttributes( { align: newAlign } )
93
+ setAttributes( {
94
+ align: newAlign,
95
+ dropCap: hasDropCapDisabled( newAlign )
96
+ ? false
97
+ : dropCap,
98
+ } )
74
99
  }
75
100
  />
76
101
  <ParagraphRTLControl
@@ -97,17 +122,20 @@ function ParagraphBlock( {
97
122
  onChange={ () =>
98
123
  setAttributes( { dropCap: ! dropCap } )
99
124
  }
100
- help={
101
- dropCap
102
- ? __( 'Showing large initial letter.' )
103
- : __(
104
- 'Toggle to show a large initial letter.'
105
- )
125
+ help={ helpText }
126
+ disabled={
127
+ hasDropCapDisabled( align ) ? true : false
106
128
  }
107
129
  />
108
130
  </ToolsPanelItem>
109
131
  </InspectorControls>
110
132
  ) }
133
+ { ! content && (
134
+ <DropZone
135
+ clientId={ clientId }
136
+ paragraphElement={ paragraphElement }
137
+ />
138
+ ) }
111
139
  <RichText
112
140
  identifier="content"
113
141
  tagName="p"
@@ -17,3 +17,23 @@
17
17
  }
18
18
  }
19
19
  }
20
+
21
+ .components-popover.wp-block-paragraph__drop-zone {
22
+ .components-popover__content {
23
+ border: none;
24
+ outline: none;
25
+ box-shadow: none;
26
+ }
27
+
28
+ .wp-block-paragraph__drop-zone-backdrop {
29
+ position: absolute;
30
+ }
31
+
32
+ .wp-block-paragraph__drop-zone-foreground {
33
+ position: absolute;
34
+ inset: 0;
35
+ pointer-events: none;
36
+ background-color: var(--wp-admin-theme-color);
37
+ border-radius: 2px;
38
+ }
39
+ }
@@ -7,11 +7,15 @@ import classnames from 'classnames';
7
7
  * WordPress dependencies
8
8
  */
9
9
  import { RichText, useBlockProps } from '@wordpress/block-editor';
10
+ import { isRTL } from '@wordpress/i18n';
10
11
 
11
12
  export default function save( { attributes } ) {
12
13
  const { align, content, dropCap, direction } = attributes;
13
14
  const className = classnames( {
14
- 'has-drop-cap': dropCap,
15
+ 'has-drop-cap':
16
+ align === ( isRTL() ? 'left' : 'right' ) || align === 'center'
17
+ ? false
18
+ : dropCap,
15
19
  [ `has-text-align-${ align }` ]: align,
16
20
  } );
17
21
 
@@ -28,6 +28,11 @@
28
28
  font-style: normal;
29
29
  }
30
30
 
31
+ body.rtl .has-drop-cap:not(:focus)::first-letter {
32
+ float: initial;
33
+ margin-left: 0.1em;
34
+ }
35
+
31
36
  // Prevent the dropcap from breaking out of the box when a background is applied.
32
37
  p.has-drop-cap.has-background {
33
38
  overflow: hidden;
@@ -23,6 +23,14 @@
23
23
  },
24
24
  "byline": {
25
25
  "type": "string"
26
+ },
27
+ "isLink": {
28
+ "type": "boolean",
29
+ "default": false
30
+ },
31
+ "linkTarget": {
32
+ "type": "string",
33
+ "default": "_self"
26
34
  }
27
35
  },
28
36
  "usesContext": [ "postType", "postId", "queryId" ],