@wordpress/block-library 8.19.3 → 8.19.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/build/cover/edit/inspector-controls.js +1 -1
  3. package/build/cover/edit/inspector-controls.js.map +1 -1
  4. package/build/embed/edit.js +17 -0
  5. package/build/embed/edit.js.map +1 -1
  6. package/build/embed/edit.native.js +17 -0
  7. package/build/embed/edit.native.js.map +1 -1
  8. package/build/image/image.js +1 -1
  9. package/build/image/image.js.map +1 -1
  10. package/build/image/view.js +14 -4
  11. package/build/image/view.js.map +1 -1
  12. package/build/latest-posts/edit.js +6 -2
  13. package/build/latest-posts/edit.js.map +1 -1
  14. package/build/media-text/edit.js +1 -1
  15. package/build/media-text/edit.js.map +1 -1
  16. package/build/navigation/edit/deleted-navigation-warning.js +6 -4
  17. package/build/navigation/edit/deleted-navigation-warning.js.map +1 -1
  18. package/build/navigation/edit/index.js +3 -2
  19. package/build/navigation/edit/index.js.map +1 -1
  20. package/build/navigation/edit/inner-blocks.js +2 -1
  21. package/build/navigation/edit/inner-blocks.js.map +1 -1
  22. package/build-module/cover/edit/inspector-controls.js +1 -1
  23. package/build-module/cover/edit/inspector-controls.js.map +1 -1
  24. package/build-module/embed/edit.js +17 -0
  25. package/build-module/embed/edit.js.map +1 -1
  26. package/build-module/embed/edit.native.js +17 -0
  27. package/build-module/embed/edit.native.js.map +1 -1
  28. package/build-module/image/image.js +1 -1
  29. package/build-module/image/image.js.map +1 -1
  30. package/build-module/image/view.js +14 -4
  31. package/build-module/image/view.js.map +1 -1
  32. package/build-module/latest-posts/edit.js +6 -2
  33. package/build-module/latest-posts/edit.js.map +1 -1
  34. package/build-module/media-text/edit.js +1 -1
  35. package/build-module/media-text/edit.js.map +1 -1
  36. package/build-module/navigation/edit/deleted-navigation-warning.js +7 -4
  37. package/build-module/navigation/edit/deleted-navigation-warning.js.map +1 -1
  38. package/build-module/navigation/edit/index.js +3 -2
  39. package/build-module/navigation/edit/index.js.map +1 -1
  40. package/build-module/navigation/edit/inner-blocks.js +2 -1
  41. package/build-module/navigation/edit/inner-blocks.js.map +1 -1
  42. package/build-style/image/style-rtl.css +17 -2
  43. package/build-style/image/style.css +17 -2
  44. package/build-style/post-featured-image/style-rtl.css +3 -0
  45. package/build-style/post-featured-image/style.css +3 -0
  46. package/build-style/post-template/style-rtl.css +25 -0
  47. package/build-style/post-template/style.css +25 -0
  48. package/build-style/style-rtl.css +46 -2
  49. package/build-style/style.css +46 -2
  50. package/package.json +32 -32
  51. package/src/cover/edit/inspector-controls.js +1 -1
  52. package/src/embed/edit.js +15 -0
  53. package/src/embed/edit.native.js +15 -0
  54. package/src/image/image.js +1 -1
  55. package/src/image/index.php +64 -46
  56. package/src/image/style.scss +23 -2
  57. package/src/image/view.js +14 -4
  58. package/src/latest-posts/edit.js +10 -2
  59. package/src/latest-posts/index.php +18 -8
  60. package/src/media-text/edit.js +1 -1
  61. package/src/navigation/edit/deleted-navigation-warning.js +9 -4
  62. package/src/navigation/edit/index.js +26 -17
  63. package/src/navigation/edit/inner-blocks.js +1 -0
  64. package/src/post-featured-image/style.scss +4 -0
  65. package/src/post-template/style.scss +20 -0
@@ -1628,6 +1628,8 @@ h6.has-text-align-left[style*=writing-mode]:where([style*="vertical-lr"]) {
1628
1628
 
1629
1629
  .wp-lightbox-container {
1630
1630
  position: relative;
1631
+ display: flex;
1632
+ flex-direction: column;
1631
1633
  }
1632
1634
  .wp-lightbox-container button {
1633
1635
  border: none;
@@ -1643,6 +1645,10 @@ h6.has-text-align-left[style*=writing-mode]:where([style*="vertical-lr"]) {
1643
1645
  outline: 5px auto -webkit-focus-ring-color;
1644
1646
  outline-offset: 5px;
1645
1647
  }
1648
+ .wp-lightbox-container button:hover, .wp-lightbox-container button:focus, .wp-lightbox-container button:not(:hover):not(:active):not(.has-background) {
1649
+ background: none;
1650
+ border: none;
1651
+ }
1646
1652
 
1647
1653
  .wp-lightbox-overlay {
1648
1654
  position: fixed;
@@ -1658,11 +1664,20 @@ h6.has-text-align-left[style*=writing-mode]:where([style*="vertical-lr"]) {
1658
1664
  }
1659
1665
  .wp-lightbox-overlay .close-button {
1660
1666
  position: absolute;
1661
- top: calc(env(safe-area-inset-top) + 20px);
1662
- right: calc(env(safe-area-inset-right) + 20px);
1667
+ top: calc(env(safe-area-inset-top) + 16px);
1668
+ right: calc(env(safe-area-inset-right) + 16px);
1663
1669
  padding: 0;
1664
1670
  cursor: pointer;
1665
1671
  z-index: 5000000;
1672
+ min-width: 40px;
1673
+ min-height: 40px;
1674
+ display: flex;
1675
+ align-items: center;
1676
+ justify-content: center;
1677
+ }
1678
+ .wp-lightbox-overlay .close-button:hover, .wp-lightbox-overlay .close-button:focus, .wp-lightbox-overlay .close-button:not(:hover):not(:active):not(.has-background) {
1679
+ background: none;
1680
+ border: none;
1666
1681
  }
1667
1682
  .wp-lightbox-overlay .lightbox-image-container {
1668
1683
  position: absolute;
@@ -2836,6 +2851,9 @@ p.has-text-align-left[style*="writing-mode:vertical-lr"] {
2836
2851
  .wp-block-post-featured-image .wp-block-post-featured-image__overlay.has-background-dim-100 {
2837
2852
  opacity: 1;
2838
2853
  }
2854
+ .wp-block-post-featured-image:where(.alignleft, .alignright) {
2855
+ width: 100%;
2856
+ }
2839
2857
 
2840
2858
  .wp-block-post-navigation-link .wp-block-post-navigation-link__arrow-previous {
2841
2859
  display: inline-block;
@@ -2982,6 +3000,32 @@ p.has-text-align-left[style*="writing-mode:vertical-lr"] {
2982
3000
  grid-template-columns: 1fr;
2983
3001
  }
2984
3002
  }
3003
+ .wp-block-post-template-is-layout-constrained > li > .alignright,
3004
+ .wp-block-post-template-is-layout-flow > li > .alignright {
3005
+ float: right;
3006
+ -webkit-margin-start: 2em;
3007
+ margin-inline-start: 2em;
3008
+ -webkit-margin-end: 0;
3009
+ margin-inline-end: 0;
3010
+ }
3011
+
3012
+ .wp-block-post-template-is-layout-constrained > li > .alignleft,
3013
+ .wp-block-post-template-is-layout-flow > li > .alignleft {
3014
+ float: left;
3015
+ -webkit-margin-start: 0;
3016
+ margin-inline-start: 0;
3017
+ -webkit-margin-end: 2em;
3018
+ margin-inline-end: 2em;
3019
+ }
3020
+
3021
+ .wp-block-post-template-is-layout-constrained > li > .aligncenter,
3022
+ .wp-block-post-template-is-layout-flow > li > .aligncenter {
3023
+ -webkit-margin-start: auto;
3024
+ margin-inline-start: auto;
3025
+ -webkit-margin-end: auto;
3026
+ margin-inline-end: auto;
3027
+ }
3028
+
2985
3029
  .wp-block-query-pagination > .wp-block-query-pagination-next,
2986
3030
  .wp-block-query-pagination > .wp-block-query-pagination-previous,
2987
3031
  .wp-block-query-pagination > .wp-block-query-pagination-numbers {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/block-library",
3
- "version": "8.19.3",
3
+ "version": "8.19.4",
4
4
  "description": "Block library for the WordPress editor.",
5
5
  "author": "The WordPress Contributors",
6
6
  "license": "GPL-2.0-or-later",
@@ -31,36 +31,36 @@
31
31
  ],
32
32
  "dependencies": {
33
33
  "@babel/runtime": "^7.16.0",
34
- "@wordpress/a11y": "^3.42.3",
35
- "@wordpress/api-fetch": "^6.39.3",
36
- "@wordpress/autop": "^3.42.3",
37
- "@wordpress/blob": "^3.42.3",
38
- "@wordpress/block-editor": "^12.10.3",
39
- "@wordpress/blocks": "^12.19.3",
40
- "@wordpress/components": "^25.8.3",
41
- "@wordpress/compose": "^6.19.3",
42
- "@wordpress/core-data": "^6.19.3",
43
- "@wordpress/data": "^9.12.3",
44
- "@wordpress/date": "^4.42.3",
45
- "@wordpress/deprecated": "^3.42.3",
46
- "@wordpress/dom": "^3.42.3",
47
- "@wordpress/element": "^5.19.3",
48
- "@wordpress/escape-html": "^2.42.3",
49
- "@wordpress/hooks": "^3.42.3",
50
- "@wordpress/html-entities": "^3.42.3",
51
- "@wordpress/i18n": "^4.42.3",
52
- "@wordpress/icons": "^9.33.3",
53
- "@wordpress/interactivity": "^2.3.3",
54
- "@wordpress/keycodes": "^3.42.3",
55
- "@wordpress/notices": "^4.10.3",
56
- "@wordpress/primitives": "^3.40.3",
57
- "@wordpress/private-apis": "^0.24.3",
58
- "@wordpress/reusable-blocks": "^4.19.3",
59
- "@wordpress/rich-text": "^6.19.3",
60
- "@wordpress/server-side-render": "^4.19.3",
61
- "@wordpress/url": "^3.43.3",
62
- "@wordpress/viewport": "^5.19.3",
63
- "@wordpress/wordcount": "^3.42.3",
34
+ "@wordpress/a11y": "^3.42.4",
35
+ "@wordpress/api-fetch": "^6.39.4",
36
+ "@wordpress/autop": "^3.42.4",
37
+ "@wordpress/blob": "^3.42.4",
38
+ "@wordpress/block-editor": "^12.10.4",
39
+ "@wordpress/blocks": "^12.19.4",
40
+ "@wordpress/components": "^25.8.4",
41
+ "@wordpress/compose": "^6.19.4",
42
+ "@wordpress/core-data": "^6.19.4",
43
+ "@wordpress/data": "^9.12.4",
44
+ "@wordpress/date": "^4.42.4",
45
+ "@wordpress/deprecated": "^3.42.4",
46
+ "@wordpress/dom": "^3.42.4",
47
+ "@wordpress/element": "^5.19.4",
48
+ "@wordpress/escape-html": "^2.42.4",
49
+ "@wordpress/hooks": "^3.42.4",
50
+ "@wordpress/html-entities": "^3.42.4",
51
+ "@wordpress/i18n": "^4.42.4",
52
+ "@wordpress/icons": "^9.33.4",
53
+ "@wordpress/interactivity": "^2.3.4",
54
+ "@wordpress/keycodes": "^3.42.4",
55
+ "@wordpress/notices": "^4.10.4",
56
+ "@wordpress/primitives": "^3.40.4",
57
+ "@wordpress/private-apis": "^0.24.4",
58
+ "@wordpress/reusable-blocks": "^4.19.4",
59
+ "@wordpress/rich-text": "^6.19.4",
60
+ "@wordpress/server-side-render": "^4.19.4",
61
+ "@wordpress/url": "^3.43.4",
62
+ "@wordpress/viewport": "^5.19.4",
63
+ "@wordpress/wordcount": "^3.42.4",
64
64
  "change-case": "^4.1.2",
65
65
  "classnames": "^2.3.1",
66
66
  "colord": "^2.7.0",
@@ -78,5 +78,5 @@
78
78
  "publishConfig": {
79
79
  "access": "public"
80
80
  },
81
- "gitHead": "6256f93c37705d142f75a99f1fc808540ca7dca8"
81
+ "gitHead": "d1072bbcaf037a18d414da7865ebaf366a0e7062"
82
82
  }
@@ -149,7 +149,7 @@ export default function CoverInspectorControls( {
149
149
  'The <header> element should represent introductory content, typically a group of introductory or navigational aids.'
150
150
  ),
151
151
  main: __(
152
- 'The <main> element should be used for the primary content of your document only. '
152
+ 'The <main> element should be used for the primary content of your document only.'
153
153
  ),
154
154
  section: __(
155
155
  "The <section> element should represent a standalone portion of the document that can't be better represented by another element."
package/src/embed/edit.js CHANGED
@@ -29,6 +29,7 @@ import { useDispatch, useSelect } from '@wordpress/data';
29
29
  import { useBlockProps } from '@wordpress/block-editor';
30
30
  import { store as coreStore } from '@wordpress/core-data';
31
31
  import { View } from '@wordpress/primitives';
32
+ import { getAuthority } from '@wordpress/url';
32
33
 
33
34
  const EmbedEdit = ( props ) => {
34
35
  const {
@@ -137,6 +138,20 @@ const EmbedEdit = ( props ) => {
137
138
  setAttributes( { url: newURL } );
138
139
  }, [ preview?.html, attributesUrl, cannotEmbed, fetching ] );
139
140
 
141
+ // Try a different provider in case the embed url is not supported.
142
+ useEffect( () => {
143
+ if ( ! cannotEmbed || fetching || ! url ) {
144
+ return;
145
+ }
146
+
147
+ // Until X provider is supported in WordPress, as a workaround we use Twitter provider.
148
+ if ( getAuthority( url ) === 'x.com' ) {
149
+ const newURL = new URL( url );
150
+ newURL.host = 'twitter.com';
151
+ setAttributes( { url: newURL.toString() } );
152
+ }
153
+ }, [ url, cannotEmbed, fetching, setAttributes ] );
154
+
140
155
  // Handle incoming preview.
141
156
  useEffect( () => {
142
157
  if ( preview && ! isEditingURL ) {
@@ -33,6 +33,7 @@ import {
33
33
  } from '@wordpress/block-editor';
34
34
  import { store as coreStore } from '@wordpress/core-data';
35
35
  import { View } from '@wordpress/primitives';
36
+ import { getAuthority } from '@wordpress/url';
36
37
 
37
38
  // The inline preview feature will be released progressible, for this reason
38
39
  // the embed will only be considered previewable for the following providers list.
@@ -160,6 +161,20 @@ const EmbedEdit = ( props ) => {
160
161
  setAttributes( { url: newURL } );
161
162
  }, [ preview?.html, url, cannotEmbed, fetching ] );
162
163
 
164
+ // Try a different provider in case the embed url is not supported.
165
+ useEffect( () => {
166
+ if ( ! cannotEmbed || fetching || ! url ) {
167
+ return;
168
+ }
169
+
170
+ // Until X provider is supported in WordPress, as a workaround we use Twitter provider.
171
+ if ( getAuthority( url ) === 'x.com' ) {
172
+ const newURL = new URL( url );
173
+ newURL.host = 'twitter.com';
174
+ setAttributes( { url: newURL.toString() } );
175
+ }
176
+ }, [ url, cannotEmbed, fetching, setAttributes ] );
177
+
163
178
  // Handle incoming preview.
164
179
  useEffect( () => {
165
180
  if ( preview && ! isEditingURL ) {
@@ -375,7 +375,7 @@ export default function Image( {
375
375
  !! lightbox || lightboxSetting?.allowEditing === true;
376
376
 
377
377
  const lightboxChecked =
378
- lightbox?.enabled || ( ! lightbox && lightboxSetting?.enabled );
378
+ !! lightbox?.enabled || ( ! lightbox && !! lightboxSetting?.enabled );
379
379
 
380
380
  const dimensionsControl = (
381
381
  <DimensionsTool
@@ -9,10 +9,11 @@
9
9
  * Renders the `core/image` block on the server,
10
10
  * adding a data-id attribute to the element if core/gallery has added on pre-render.
11
11
  *
12
- * @param array $attributes The block attributes.
13
- * @param string $content The block content.
14
- * @param WP_Block $block The block object.
15
- * @return string Returns the block content with the data-id attribute added.
12
+ * @param array $attributes The block attributes.
13
+ * @param string $content The block content.
14
+ * @param WP_Block $block The block object.
15
+ *
16
+ * @return string The block content with the data-id attribute added.
16
17
  */
17
18
  function render_block_core_image( $attributes, $content, $block ) {
18
19
 
@@ -76,12 +77,13 @@ function render_block_core_image( $attributes, $content, $block ) {
76
77
  }
77
78
 
78
79
  /**
79
- * Add the lightboxEnabled flag to the block data.
80
+ * Adds the lightboxEnabled flag to the block data.
80
81
  *
81
82
  * This is used to determine whether the lightbox should be rendered or not.
82
83
  *
83
- * @param array $block Block data.
84
- * @return array Filtered block data.
84
+ * @param array $block Block data.
85
+ *
86
+ * @return array Filtered block data.
85
87
  */
86
88
  function block_core_image_get_lightbox_settings( $block ) {
87
89
  // Get the lightbox setting from the block attributes.
@@ -113,43 +115,44 @@ function block_core_image_get_lightbox_settings( $block ) {
113
115
  }
114
116
 
115
117
  /**
116
- * Add the directives and layout needed for the lightbox behavior.
118
+ * Adds the directives and layout needed for the lightbox behavior.
119
+ *
120
+ * @param string $block_content Rendered block content.
121
+ * @param array $block Block object.
117
122
  *
118
- * @param string $block_content Rendered block content.
119
- * @param array $block Block object.
120
- * @return string Filtered block content.
123
+ * @return string Filtered block content.
121
124
  */
122
125
  function block_core_image_render_lightbox( $block_content, $block ) {
123
126
  $processor = new WP_HTML_Tag_Processor( $block_content );
124
127
 
125
128
  $aria_label = __( 'Enlarge image' );
126
129
 
130
+ $processor->next_tag( 'img' );
127
131
  $alt_attribute = $processor->get_attribute( 'alt' );
128
132
 
129
- if ( null !== $alt_attribute ) {
133
+ // An empty alt attribute `alt=""` is valid for decorative images.
134
+ if ( is_string( $alt_attribute ) ) {
130
135
  $alt_attribute = trim( $alt_attribute );
131
136
  }
132
137
 
138
+ // It only makes sense to append the alt text to the button aria-label when the alt text is non-empty.
133
139
  if ( $alt_attribute ) {
134
140
  /* translators: %s: Image alt text. */
135
141
  $aria_label = sprintf( __( 'Enlarge image: %s' ), $alt_attribute );
136
142
  }
137
- $content = $processor->get_updated_html();
138
143
 
139
144
  // Currently, we are only enabling the zoom animation.
140
145
  $lightbox_animation = 'zoom';
141
146
 
142
- // We want to store the src in the context so we can set it dynamically when the lightbox is opened.
143
- $z = new WP_HTML_Tag_Processor( $content );
144
- $z->next_tag( 'img' );
145
-
147
+ // Note: We want to store the `src` in the context so we
148
+ // can set it dynamically when the lightbox is opened.
146
149
  if ( isset( $block['attrs']['id'] ) ) {
147
150
  $img_uploaded_src = wp_get_attachment_url( $block['attrs']['id'] );
148
151
  $img_metadata = wp_get_attachment_metadata( $block['attrs']['id'] );
149
152
  $img_width = $img_metadata['width'];
150
153
  $img_height = $img_metadata['height'];
151
154
  } else {
152
- $img_uploaded_src = $z->get_attribute( 'src' );
155
+ $img_uploaded_src = $processor->get_attribute( 'src' );
153
156
  $img_width = 'none';
154
157
  $img_height = 'none';
155
158
  }
@@ -160,7 +163,7 @@ function block_core_image_render_lightbox( $block_content, $block ) {
160
163
  $scale_attr = false;
161
164
  }
162
165
 
163
- $w = new WP_HTML_Tag_Processor( $content );
166
+ $w = new WP_HTML_Tag_Processor( $block_content );
164
167
  $w->next_tag( 'figure' );
165
168
  $w->add_class( 'wp-lightbox-container' );
166
169
  $w->set_attribute( 'data-wp-interactive', true );
@@ -180,7 +183,8 @@ function block_core_image_render_lightbox( $block_content, $block ) {
180
183
  "imageCurrentSrc": "",
181
184
  "targetWidth": "%s",
182
185
  "targetHeight": "%s",
183
- "scaleAttr": "%s"
186
+ "scaleAttr": "%s",
187
+ "dialogLabel": "%s"
184
188
  }
185
189
  }
186
190
  }',
@@ -188,7 +192,8 @@ function block_core_image_render_lightbox( $block_content, $block ) {
188
192
  $img_uploaded_src,
189
193
  $img_width,
190
194
  $img_height,
191
- $scale_attr
195
+ $scale_attr,
196
+ __( 'Enlarged image' )
192
197
  )
193
198
  );
194
199
  $w->next_tag( 'img' );
@@ -200,19 +205,20 @@ function block_core_image_render_lightbox( $block_content, $block ) {
200
205
  // Wrap the image in the body content with a button.
201
206
  $img = null;
202
207
  preg_match( '/<img[^>]+>/', $body_content, $img );
203
- $button =
204
- '<button
205
- type="button"
206
- aria-haspopup="dialog"
207
- aria-label="' . esc_attr( $aria_label ) . '"
208
- data-wp-on--click="actions.core.image.showLightbox"
209
- data-wp-style--width="context.core.image.imageButtonWidth"
210
- data-wp-style--height="context.core.image.imageButtonHeight"
211
- data-wp-style--left="context.core.image.imageButtonLeft"
212
- data-wp-style--top="context.core.image.imageButtonTop"
213
- >
214
- </button>'
215
- . $img[0];
208
+
209
+ $button =
210
+ $img[0]
211
+ . '<button
212
+ type="button"
213
+ aria-haspopup="dialog"
214
+ aria-label="' . esc_attr( $aria_label ) . '"
215
+ data-wp-on--click="actions.core.image.showLightbox"
216
+ data-wp-style--width="context.core.image.imageButtonWidth"
217
+ data-wp-style--height="context.core.image.imageButtonHeight"
218
+ data-wp-style--left="context.core.image.imageButtonLeft"
219
+ data-wp-style--top="context.core.image.imageButtonTop"
220
+ ></button>';
221
+
216
222
  $body_content = preg_replace( '/<img[^>]+>/', $button, $body_content );
217
223
 
218
224
  // We need both a responsive image and an enlarged image to animate
@@ -220,7 +226,7 @@ function block_core_image_render_lightbox( $block_content, $block ) {
220
226
  // image is a copy of the one in the body, which animates immediately
221
227
  // as the lightbox is opened, while the enlarged one is a full-sized
222
228
  // version that will likely still be loading as the animation begins.
223
- $m = new WP_HTML_Tag_Processor( $content );
229
+ $m = new WP_HTML_Tag_Processor( $block_content );
224
230
  $m->next_tag( 'figure' );
225
231
  $m->add_class( 'responsive-image' );
226
232
  $m->next_tag( 'img' );
@@ -236,7 +242,7 @@ function block_core_image_render_lightbox( $block_content, $block ) {
236
242
  $m->set_attribute( 'data-wp-style--object-fit', 'selectors.core.image.lightboxObjectFit' );
237
243
  $initial_image_content = $m->get_updated_html();
238
244
 
239
- $q = new WP_HTML_Tag_Processor( $content );
245
+ $q = new WP_HTML_Tag_Processor( $block_content );
240
246
  $q->next_tag( 'figure' );
241
247
  $q->add_class( 'enlarged-image' );
242
248
  $q->next_tag( 'img' );
@@ -252,24 +258,32 @@ function block_core_image_render_lightbox( $block_content, $block ) {
252
258
  $q->set_attribute( 'data-wp-style--object-fit', 'selectors.core.image.lightboxObjectFit' );
253
259
  $enlarged_image_content = $q->get_updated_html();
254
260
 
255
- $background_color = esc_attr( wp_get_global_styles( array( 'color', 'background' ) ) );
261
+ // If the current theme does NOT have a `theme.json`, or the colors are not defined,
262
+ // we need to set the background color & close button color to some default values
263
+ // because we can't get them from the Global Styles.
264
+ $background_color = '#fff';
265
+ $close_button_color = '#000';
266
+ if ( wp_theme_has_theme_json() ) {
267
+ $global_styles_color = wp_get_global_styles( array( 'color' ) );
268
+ if ( ! empty( $global_styles_color['background'] ) ) {
269
+ $background_color = esc_attr( $global_styles_color['background'] );
270
+ }
271
+ if ( ! empty( $global_styles_color['text'] ) ) {
272
+ $close_button_color = esc_attr( $global_styles_color['text'] );
273
+ }
274
+ }
256
275
 
257
276
  $close_button_icon = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="15" height="15" aria-hidden="true" focusable="false"><path d="M13 11.8l6.1-6.3-1-1-6.1 6.2-6.1-6.2-1 1 6.1 6.3-6.5 6.7 1 1 6.5-6.6 6.5 6.6 1-1z"></path></svg>';
258
- $close_button_color = esc_attr( wp_get_global_styles( array( 'color', 'text' ) ) );
259
- $dialog_label = $alt_attribute ? esc_attr( $alt_attribute ) : esc_attr__( 'Image' );
260
277
  $close_button_label = esc_attr__( 'Close' );
261
278
 
262
279
  $lightbox_html = <<<HTML
263
280
  <div data-wp-body="" class="wp-lightbox-overlay $lightbox_animation"
264
281
  data-wp-bind--role="selectors.core.image.roleAttribute"
265
- aria-label="$dialog_label"
282
+ data-wp-bind--aria-label="selectors.core.image.dialogLabel"
266
283
  data-wp-class--initialized="context.core.image.initialized"
267
284
  data-wp-class--active="context.core.image.lightboxEnabled"
268
285
  data-wp-class--hideAnimationEnabled="context.core.image.hideAnimationEnabled"
269
- data-wp-bind--aria-hidden="!context.core.image.lightboxEnabled"
270
- aria-hidden="true"
271
- data-wp-bind--aria-modal="context.core.image.lightboxEnabled"
272
- aria-modal="false"
286
+ data-wp-bind--aria-modal="selectors.core.image.ariaModal"
273
287
  data-wp-effect="effects.core.image.initLightbox"
274
288
  data-wp-on--keydown="actions.core.image.handleKeydown"
275
289
  data-wp-on--touchstart="actions.core.image.handleTouchStart"
@@ -282,7 +296,7 @@ function block_core_image_render_lightbox( $block_content, $block ) {
282
296
  </button>
283
297
  <div class="lightbox-image-container">$initial_image_content</div>
284
298
  <div class="lightbox-image-container">$enlarged_image_content</div>
285
- <div class="scrim" style="background-color: $background_color"></div>
299
+ <div class="scrim" style="background-color: $background_color" aria-hidden="true"></div>
286
300
  </div>
287
301
  HTML;
288
302
 
@@ -290,11 +304,13 @@ HTML;
290
304
  }
291
305
 
292
306
  /**
293
- * Ensure that the view script has the `wp-interactivity` dependency.
307
+ * Ensures that the view script has the `wp-interactivity` dependency.
294
308
  *
295
309
  * @since 6.4.0
296
310
  *
297
311
  * @global WP_Scripts $wp_scripts
312
+ *
313
+ * @return void
298
314
  */
299
315
  function block_core_image_ensure_interactivity_dependency() {
300
316
  global $wp_scripts;
@@ -310,6 +326,8 @@ add_action( 'wp_print_scripts', 'block_core_image_ensure_interactivity_dependenc
310
326
 
311
327
  /**
312
328
  * Registers the `core/image` block on server.
329
+ *
330
+ * @return void
313
331
  */
314
332
  function register_block_core_image() {
315
333
  register_block_type_from_metadata(
@@ -154,6 +154,8 @@
154
154
 
155
155
  .wp-lightbox-container {
156
156
  position: relative;
157
+ display: flex;
158
+ flex-direction: column;
157
159
 
158
160
  button {
159
161
  border: none;
@@ -169,6 +171,13 @@
169
171
  outline: 5px auto -webkit-focus-ring-color;
170
172
  outline-offset: 5px;
171
173
  }
174
+
175
+ &:hover,
176
+ &:focus,
177
+ &:not(:hover):not(:active):not(.has-background) {
178
+ background: none;
179
+ border: none;
180
+ }
172
181
  }
173
182
  }
174
183
 
@@ -186,11 +195,23 @@
186
195
 
187
196
  .close-button {
188
197
  position: absolute;
189
- top: calc(env(safe-area-inset-top) + 20px);
190
- right: calc(env(safe-area-inset-right) + 20px);
198
+ top: calc(env(safe-area-inset-top) + 16px); // equivalent to $grid-unit-20
199
+ right: calc(env(safe-area-inset-right) + 16px); // equivalent to $grid-unit-20
191
200
  padding: 0;
192
201
  cursor: pointer;
193
202
  z-index: 5000000;
203
+ min-width: 40px; // equivalent to $button-size-next-default-40px
204
+ min-height: 40px; // equivalent to $button-size-next-default-40px
205
+ display: flex;
206
+ align-items: center;
207
+ justify-content: center;
208
+
209
+ &:hover,
210
+ &:focus,
211
+ &:not(:hover):not(:active):not(.has-background) {
212
+ background: none;
213
+ border: none;
214
+ }
194
215
  }
195
216
 
196
217
  .lightbox-image-container {
package/src/image/view.js CHANGED
@@ -227,7 +227,17 @@ store(
227
227
  roleAttribute: ( { context } ) => {
228
228
  return context.core.image.lightboxEnabled
229
229
  ? 'dialog'
230
- : '';
230
+ : null;
231
+ },
232
+ ariaModal: ( { context } ) => {
233
+ return context.core.image.lightboxEnabled
234
+ ? 'true'
235
+ : null;
236
+ },
237
+ dialogLabel: ( { context } ) => {
238
+ return context.core.image.lightboxEnabled
239
+ ? context.core.image.dialogLabel
240
+ : null;
231
241
  },
232
242
  lightboxObjectFit: ( { context } ) => {
233
243
  if ( context.core.image.initialized ) {
@@ -237,7 +247,7 @@ store(
237
247
  enlargedImgSrc: ( { context } ) => {
238
248
  return context.core.image.initialized
239
249
  ? context.core.image.imageUploadedSrc
240
- : '';
250
+ : 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=';
241
251
  },
242
252
  },
243
253
  },
@@ -360,9 +370,9 @@ function setStyles( context, event ) {
360
370
  naturalHeight,
361
371
  offsetWidth: originalWidth,
362
372
  offsetHeight: originalHeight,
363
- } = event.target.nextElementSibling;
373
+ } = event.target.previousElementSibling;
364
374
  let { x: screenPosX, y: screenPosY } =
365
- event.target.nextElementSibling.getBoundingClientRect();
375
+ event.target.previousElementSibling.getBoundingClientRect();
366
376
 
367
377
  // Natural ratio of the image clicked to open the lightbox.
368
378
  const naturalRatio = naturalWidth / naturalHeight;
@@ -483,12 +483,17 @@ export default function LatestPostsEdit( { attributes, setAttributes } ) {
483
483
  .split( ' ', excerptLength )
484
484
  .join( ' ' ) }
485
485
  { createInterpolateElement(
486
- /* translators: excerpt truncation character, default … */
487
- __( ' <a>Read more</a>' ),
486
+ sprintf(
487
+ /* translators: 1: The static string "Read more", 2: The post title only visible to screen readers. */
488
+ __( '… <a>%1$s<span>: %2$s</span></a>' ),
489
+ __( 'Read more' ),
490
+ titleTrimmed || __( '(no title)' )
491
+ ),
488
492
  {
489
493
  a: (
490
494
  // eslint-disable-next-line jsx-a11y/anchor-has-content
491
495
  <a
496
+ className="wp-block-latest-posts__read-more"
492
497
  href={ post.link }
493
498
  rel="noopener noreferrer"
494
499
  onClick={
@@ -496,6 +501,9 @@ export default function LatestPostsEdit( { attributes, setAttributes } ) {
496
501
  }
497
502
  />
498
503
  ),
504
+ span: (
505
+ <span className="screen-reader-text" />
506
+ ),
499
507
  }
500
508
  ) }
501
509
  </>
@@ -48,14 +48,6 @@ function render_block_core_latest_posts( $attributes ) {
48
48
  $block_core_latest_posts_excerpt_length = $attributes['excerptLength'];
49
49
  add_filter( 'excerpt_length', 'block_core_latest_posts_get_excerpt_length', 20 );
50
50
 
51
- $filter_latest_posts_excerpt_more = static function ( $more ) use ( $attributes ) {
52
- $use_excerpt = 'excerpt' === $attributes['displayPostContentRadio'];
53
- /* translators: %1$s is a URL to a post, excerpt truncation character, default … */
54
- return $use_excerpt ? sprintf( __( ' … <a href="%1$s" rel="noopener noreferrer">Read more</a>' ), esc_url( get_permalink() ) ) : $more;
55
- };
56
-
57
- add_filter( 'excerpt_more', $filter_latest_posts_excerpt_more );
58
-
59
51
  if ( ! empty( $attributes['categories'] ) ) {
60
52
  $args['category__in'] = array_column( $attributes['categories'], 'id' );
61
53
  }
@@ -151,6 +143,24 @@ function render_block_core_latest_posts( $attributes ) {
151
143
 
152
144
  $trimmed_excerpt = get_the_excerpt( $post );
153
145
 
146
+ /*
147
+ * Adds a "Read more" link with screen reader text.
148
+ * [&hellip;] is the default excerpt ending from wp_trim_excerpt() in Core.
149
+ */
150
+ if ( str_ends_with( $trimmed_excerpt, ' [&hellip;]' ) ) {
151
+ $excerpt_length = (int) apply_filters( 'excerpt_length', $block_core_latest_posts_excerpt_length );
152
+ if ( $excerpt_length <= $block_core_latest_posts_excerpt_length ) {
153
+ $trimmed_excerpt = substr( $trimmed_excerpt, 0, -11 );
154
+ $trimmed_excerpt .= sprintf(
155
+ /* translators: 1: A URL to a post, 2: The static string "Read more", 3: The post title only visible to screen readers. */
156
+ __( '… <a href="%1$s" rel="noopener noreferrer">%2$s<span class="screen-reader-text">: %3$s</span></a>' ),
157
+ esc_url( $post_link ),
158
+ __( 'Read more' ),
159
+ esc_html( $title )
160
+ );
161
+ }
162
+ }
163
+
154
164
  if ( post_password_required( $post ) ) {
155
165
  $trimmed_excerpt = __( 'This content is password protected.' );
156
166
  }
@@ -244,7 +244,7 @@ function MediaTextEdit( { attributes, isSelected, setAttributes } ) {
244
244
  <ToggleControl
245
245
  __nextHasNoMarginBottom
246
246
  label={ __( 'Crop image to fill entire column' ) }
247
- checked={ imageFill }
247
+ checked={ !! imageFill }
248
248
  onChange={ () =>
249
249
  setAttributes( {
250
250
  imageFill: ! imageFill,