@wordpress/block-library 8.23.0 → 8.24.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 (136) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/build/block/edit.js +8 -11
  3. package/build/block/edit.js.map +1 -1
  4. package/build/block/edit.native.js +3 -4
  5. package/build/block/edit.native.js.map +1 -1
  6. package/build/button/edit.js +4 -7
  7. package/build/button/edit.js.map +1 -1
  8. package/build/column/edit.js +1 -1
  9. package/build/column/edit.js.map +1 -1
  10. package/build/column/edit.native.js +1 -1
  11. package/build/column/edit.native.js.map +1 -1
  12. package/build/cover/edit/index.js +2 -1
  13. package/build/cover/edit/index.js.map +1 -1
  14. package/build/file/edit.js +8 -9
  15. package/build/file/edit.js.map +1 -1
  16. package/build/file/view.js +4 -6
  17. package/build/file/view.js.map +1 -1
  18. package/build/group/edit.js +3 -7
  19. package/build/group/edit.js.map +1 -1
  20. package/build/image/edit.js +17 -18
  21. package/build/image/edit.js.map +1 -1
  22. package/build/image/edit.native.js +22 -15
  23. package/build/image/edit.native.js.map +1 -1
  24. package/build/image/image.js +35 -27
  25. package/build/image/image.js.map +1 -1
  26. package/build/image/index.js +2 -3
  27. package/build/image/index.js.map +1 -1
  28. package/build/image/view.js +233 -268
  29. package/build/image/view.js.map +1 -1
  30. package/build/navigation/view.js +153 -176
  31. package/build/navigation/view.js.map +1 -1
  32. package/build/navigation-link/index.js +2 -1
  33. package/build/navigation-link/index.js.map +1 -1
  34. package/build/pattern/edit.js +1 -3
  35. package/build/pattern/edit.js.map +1 -1
  36. package/build/post-template/edit.js +1 -1
  37. package/build/post-template/edit.js.map +1 -1
  38. package/build/query/view.js +52 -60
  39. package/build/query/view.js.map +1 -1
  40. package/build/search/view.js +66 -74
  41. package/build/search/view.js.map +1 -1
  42. package/build/utils/remove-anchor-tag.js +17 -0
  43. package/build/utils/remove-anchor-tag.js.map +1 -0
  44. package/build-module/block/edit.js +8 -11
  45. package/build-module/block/edit.js.map +1 -1
  46. package/build-module/block/edit.native.js +3 -4
  47. package/build-module/block/edit.native.js.map +1 -1
  48. package/build-module/button/edit.js +4 -7
  49. package/build-module/button/edit.js.map +1 -1
  50. package/build-module/column/edit.js +1 -1
  51. package/build-module/column/edit.js.map +1 -1
  52. package/build-module/column/edit.native.js +1 -1
  53. package/build-module/column/edit.native.js.map +1 -1
  54. package/build-module/cover/edit/index.js +2 -1
  55. package/build-module/cover/edit/index.js.map +1 -1
  56. package/build-module/file/edit.js +8 -9
  57. package/build-module/file/edit.js.map +1 -1
  58. package/build-module/file/view.js +5 -7
  59. package/build-module/file/view.js.map +1 -1
  60. package/build-module/group/edit.js +3 -7
  61. package/build-module/group/edit.js.map +1 -1
  62. package/build-module/image/edit.js +18 -19
  63. package/build-module/image/edit.js.map +1 -1
  64. package/build-module/image/edit.native.js +23 -16
  65. package/build-module/image/edit.native.js.map +1 -1
  66. package/build-module/image/image.js +36 -28
  67. package/build-module/image/image.js.map +1 -1
  68. package/build-module/image/index.js +2 -3
  69. package/build-module/image/index.js.map +1 -1
  70. package/build-module/image/view.js +234 -269
  71. package/build-module/image/view.js.map +1 -1
  72. package/build-module/navigation/view.js +154 -177
  73. package/build-module/navigation/view.js.map +1 -1
  74. package/build-module/navigation-link/index.js +2 -1
  75. package/build-module/navigation-link/index.js.map +1 -1
  76. package/build-module/pattern/edit.js +1 -3
  77. package/build-module/pattern/edit.js.map +1 -1
  78. package/build-module/post-template/edit.js +1 -1
  79. package/build-module/post-template/edit.js.map +1 -1
  80. package/build-module/query/view.js +53 -61
  81. package/build-module/query/view.js.map +1 -1
  82. package/build-module/search/view.js +67 -75
  83. package/build-module/search/view.js.map +1 -1
  84. package/build-module/utils/remove-anchor-tag.js +11 -0
  85. package/build-module/utils/remove-anchor-tag.js.map +1 -0
  86. package/build-style/cover/style-rtl.css +14 -14
  87. package/build-style/cover/style.css +14 -14
  88. package/build-style/editor-rtl.css +6 -9
  89. package/build-style/editor.css +6 -9
  90. package/build-style/gallery/style-rtl.css +28 -0
  91. package/build-style/gallery/style.css +28 -0
  92. package/build-style/image/editor-rtl.css +0 -3
  93. package/build-style/image/editor.css +0 -3
  94. package/build-style/style-rtl.css +42 -14
  95. package/build-style/style.css +42 -14
  96. package/package.json +32 -32
  97. package/src/block/edit.js +18 -19
  98. package/src/block/edit.native.js +5 -13
  99. package/src/button/edit.js +6 -6
  100. package/src/buttons/test/__snapshots__/edit.native.js.snap +0 -6
  101. package/src/buttons/test/edit.native.js +0 -27
  102. package/src/column/edit.js +1 -1
  103. package/src/column/edit.native.js +1 -1
  104. package/src/cover/edit/index.js +1 -0
  105. package/src/cover/style.scss +1 -1
  106. package/src/cover/test/edit.js +1 -1
  107. package/src/editor.scss +6 -6
  108. package/src/file/edit.js +11 -10
  109. package/src/file/index.php +30 -11
  110. package/src/file/view.js +5 -7
  111. package/src/gallery/style.scss +1 -0
  112. package/src/group/edit.js +3 -11
  113. package/src/heading/test/__snapshots__/index.native.js.snap +6 -0
  114. package/src/heading/test/index.native.js +40 -0
  115. package/src/image/block.json +2 -3
  116. package/src/image/edit.js +16 -21
  117. package/src/image/edit.native.js +17 -18
  118. package/src/image/editor.scss +0 -7
  119. package/src/image/image.js +48 -51
  120. package/src/image/index.php +54 -45
  121. package/src/image/view.js +278 -334
  122. package/src/navigation/index.php +19 -10
  123. package/src/navigation/view.js +159 -192
  124. package/src/navigation-link/block.json +2 -1
  125. package/src/paragraph/test/edit.native.js +37 -1
  126. package/src/pattern/edit.js +5 -3
  127. package/src/post-template/edit.js +1 -1
  128. package/src/query/index.php +36 -22
  129. package/src/query/view.js +58 -65
  130. package/src/query-pagination-next/index.php +3 -3
  131. package/src/query-pagination-numbers/index.php +1 -1
  132. package/src/query-pagination-previous/index.php +3 -3
  133. package/src/search/index.php +40 -40
  134. package/src/search/view.js +58 -63
  135. package/src/utils/remove-anchor-tag.js +10 -0
  136. package/tsconfig.json +1 -0
@@ -101,11 +101,11 @@ function block_core_navigation_add_directives_to_submenu( $tags, $block_attribut
101
101
  )
102
102
  ) ) {
103
103
  // Add directives to the parent `<li>`.
104
- $tags->set_attribute( 'data-wp-interactive', true );
105
- $tags->set_attribute( 'data-wp-context', '{ "core": { "navigation": { "submenuOpenedBy": {}, "type": "submenu" } } }' );
106
- $tags->set_attribute( 'data-wp-effect', 'effects.core.navigation.initMenu' );
107
- $tags->set_attribute( 'data-wp-on--focusout', 'actions.core.navigation.handleMenuFocusout' );
108
- $tags->set_attribute( 'data-wp-on--keydown', 'actions.core.navigation.handleMenuKeydown' );
104
+ $tags->set_attribute( 'data-wp-interactive', '{ "namespace": "core/navigation" }' );
105
+ $tags->set_attribute( 'data-wp-context', '{ "submenuOpenedBy": {}, "type": "submenu" }' );
106
+ $tags->set_attribute( 'data-wp-watch', 'callbacks.initMenu' );
107
+ $tags->set_attribute( 'data-wp-on--focusout', 'actions.handleMenuFocusout' );
108
+ $tags->set_attribute( 'data-wp-on--keydown', 'actions.handleMenuKeydown' );
109
109
 
110
110
  // This is a fix for Safari. Without it, Safari doesn't change the active
111
111
  // element when the user clicks on a button. It can be removed once we add
@@ -114,8 +114,8 @@ function block_core_navigation_add_directives_to_submenu( $tags, $block_attribut
114
114
  $tags->set_attribute( 'tabindex', '-1' );
115
115
 
116
116
  if ( ! isset( $block_attributes['openSubmenusOnClick'] ) || false === $block_attributes['openSubmenusOnClick'] ) {
117
- $tags->set_attribute( 'data-wp-on--mouseenter', 'actions.core.navigation.openMenuOnHover' );
118
- $tags->set_attribute( 'data-wp-on--mouseleave', 'actions.core.navigation.closeMenuOnHover' );
117
+ $tags->set_attribute( 'data-wp-on--mouseenter', 'actions.openMenuOnHover' );
118
+ $tags->set_attribute( 'data-wp-on--mouseleave', 'actions.closeMenuOnHover' );
119
119
  }
120
120
 
121
121
  // Add directives to the toggle submenu button.
@@ -125,8 +125,8 @@ function block_core_navigation_add_directives_to_submenu( $tags, $block_attribut
125
125
  'class_name' => 'wp-block-navigation-submenu__toggle',
126
126
  )
127
127
  ) ) {
128
- $tags->set_attribute( 'data-wp-on--click', 'actions.core.navigation.toggleMenuOnClick' );
129
- $tags->set_attribute( 'data-wp-bind--aria-expanded', 'selectors.core.navigation.isMenuOpen' );
128
+ $tags->set_attribute( 'data-wp-on--click', 'actions.toggleMenuOnClick' );
129
+ $tags->set_attribute( 'data-wp-bind--aria-expanded', 'state.isMenuOpen' );
130
130
  // The `aria-expanded` attribute for SSR is already added in the submenu block.
131
131
  }
132
132
  // Add directives to the submenu.
@@ -136,7 +136,7 @@ function block_core_navigation_add_directives_to_submenu( $tags, $block_attribut
136
136
  'class_name' => 'wp-block-navigation__submenu-container',
137
137
  )
138
138
  ) ) {
139
- $tags->set_attribute( 'data-wp-on--focus', 'actions.core.navigation.openMenuOnFocus' );
139
+ $tags->set_attribute( 'data-wp-on--focus', 'actions.openMenuOnFocus' );
140
140
  }
141
141
 
142
142
  // Iterate through subitems if exist.
@@ -426,6 +426,15 @@ function register_block_core_navigation() {
426
426
  'render_callback' => 'render_block_core_navigation',
427
427
  )
428
428
  );
429
+
430
+ if ( defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN ) {
431
+ gutenberg_register_module(
432
+ '@wordpress/block-library/navigation-block',
433
+ gutenberg_url( '/build/interactivity/navigation.min.js' ),
434
+ array( '@wordpress/interactivity' ),
435
+ defined( 'GUTENBERG_VERSION' ) ? GUTENBERG_VERSION : get_bloginfo( 'version' )
436
+ );
437
+ }
429
438
  }
430
439
 
431
440
  add_action( 'init', 'register_block_core_navigation' );
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * WordPress dependencies
3
3
  */
4
- import { store as wpStore } from '@wordpress/interactivity';
4
+ import { store, getContext, getElement } from '@wordpress/interactivity';
5
5
 
6
6
  const focusableSelectors = [
7
7
  'a[href]',
@@ -18,205 +18,172 @@ const focusableSelectors = [
18
18
  // capture the clicks, instead of relying on the focusout event.
19
19
  document.addEventListener( 'click', () => {} );
20
20
 
21
- const openMenu = ( store, menuOpenedOn ) => {
22
- const { context, selectors } = store;
23
- selectors.core.navigation.menuOpenedBy( store )[ menuOpenedOn ] = true;
24
- if ( context.core.navigation.type === 'overlay' ) {
25
- // Add a `has-modal-open` class to the <html> root.
26
- document.documentElement.classList.add( 'has-modal-open' );
27
- }
28
- };
29
-
30
- const closeMenu = ( store, menuClosedOn ) => {
31
- const { context, selectors } = store;
32
- selectors.core.navigation.menuOpenedBy( store )[ menuClosedOn ] = false;
33
- // Check if the menu is still open or not.
34
- if ( ! selectors.core.navigation.isMenuOpen( store ) ) {
35
- if (
36
- context.core.navigation.modal?.contains(
37
- window.document.activeElement
38
- )
39
- ) {
40
- context.core.navigation.previousFocus?.focus();
41
- }
42
- context.core.navigation.modal = null;
43
- context.core.navigation.previousFocus = null;
44
- if ( context.core.navigation.type === 'overlay' ) {
45
- document.documentElement.classList.remove( 'has-modal-open' );
46
- }
47
- }
48
- };
49
-
50
- wpStore( {
51
- effects: {
52
- core: {
53
- navigation: {
54
- initMenu: ( store ) => {
55
- const { context, selectors, ref } = store;
56
- if ( selectors.core.navigation.isMenuOpen( store ) ) {
57
- const focusableElements =
58
- ref.querySelectorAll( focusableSelectors );
59
- context.core.navigation.modal = ref;
60
- context.core.navigation.firstFocusableElement =
61
- focusableElements[ 0 ];
62
- context.core.navigation.lastFocusableElement =
63
- focusableElements[ focusableElements.length - 1 ];
64
- }
65
- },
66
- focusFirstElement: ( store ) => {
67
- const { selectors, ref } = store;
68
- if ( selectors.core.navigation.isMenuOpen( store ) ) {
69
- ref.querySelector(
70
- '.wp-block-navigation-item > *:first-child'
71
- ).focus();
72
- }
73
- },
74
- },
21
+ const { state, actions } = store( 'core/navigation', {
22
+ state: {
23
+ get roleAttribute() {
24
+ const ctx = getContext();
25
+ return ctx.type === 'overlay' && state.isMenuOpen ? 'dialog' : null;
75
26
  },
76
- },
77
- selectors: {
78
- core: {
79
- navigation: {
80
- roleAttribute: ( store ) => {
81
- const { context, selectors } = store;
82
- return context.core.navigation.type === 'overlay' &&
83
- selectors.core.navigation.isMenuOpen( store )
84
- ? 'dialog'
85
- : null;
86
- },
87
- ariaModal: ( store ) => {
88
- const { context, selectors } = store;
89
- return context.core.navigation.type === 'overlay' &&
90
- selectors.core.navigation.isMenuOpen( store )
91
- ? 'true'
92
- : null;
93
- },
94
- ariaLabel: ( store ) => {
95
- const { context, selectors } = store;
96
- return context.core.navigation.type === 'overlay' &&
97
- selectors.core.navigation.isMenuOpen( store )
98
- ? context.core.navigation.ariaLabel
99
- : null;
100
- },
101
- isMenuOpen: ( { context } ) =>
102
- // The menu is opened if either `click`, `hover` or `focus` is true.
103
- Object.values(
104
- context.core.navigation[
105
- context.core.navigation.type === 'overlay'
106
- ? 'overlayOpenedBy'
107
- : 'submenuOpenedBy'
108
- ]
109
- ).filter( Boolean ).length > 0,
110
- menuOpenedBy: ( { context } ) =>
111
- context.core.navigation[
112
- context.core.navigation.type === 'overlay'
113
- ? 'overlayOpenedBy'
114
- : 'submenuOpenedBy'
115
- ],
116
- },
27
+ get ariaModal() {
28
+ const ctx = getContext();
29
+ return ctx.type === 'overlay' && state.isMenuOpen ? 'true' : null;
30
+ },
31
+ get ariaLabel() {
32
+ const ctx = getContext();
33
+ return ctx.type === 'overlay' && state.isMenuOpen
34
+ ? ctx.ariaLabel
35
+ : null;
36
+ },
37
+ get isMenuOpen() {
38
+ // The menu is opened if either `click`, `hover` or `focus` is true.
39
+ return (
40
+ Object.values( state.menuOpenedBy ).filter( Boolean ).length > 0
41
+ );
42
+ },
43
+ get menuOpenedBy() {
44
+ const ctx = getContext();
45
+ return ctx.type === 'overlay'
46
+ ? ctx.overlayOpenedBy
47
+ : ctx.submenuOpenedBy;
117
48
  },
118
49
  },
119
50
  actions: {
120
- core: {
121
- navigation: {
122
- openMenuOnHover( store ) {
123
- const { navigation } = store.context.core;
124
- if (
125
- navigation.type === 'submenu' &&
126
- // Only open on hover if the overlay is closed.
127
- Object.values(
128
- navigation.overlayOpenedBy || {}
129
- ).filter( Boolean ).length === 0
130
- )
131
- openMenu( store, 'hover' );
132
- },
133
- closeMenuOnHover( store ) {
134
- closeMenu( store, 'hover' );
135
- },
136
- openMenuOnClick( store ) {
137
- const { context, ref } = store;
138
- context.core.navigation.previousFocus = ref;
139
- openMenu( store, 'click' );
140
- },
141
- closeMenuOnClick( store ) {
142
- closeMenu( store, 'click' );
143
- closeMenu( store, 'focus' );
144
- },
145
- openMenuOnFocus( store ) {
146
- openMenu( store, 'focus' );
147
- },
148
- toggleMenuOnClick: ( store ) => {
149
- const { selectors, context, ref } = store;
150
- // Safari won't send focus to the clicked element, so we need to manually place it: https://bugs.webkit.org/show_bug.cgi?id=22261
151
- if ( window.document.activeElement !== ref ) ref.focus();
152
- const menuOpenedBy =
153
- selectors.core.navigation.menuOpenedBy( store );
154
- if ( menuOpenedBy.click || menuOpenedBy.focus ) {
155
- closeMenu( store, 'click' );
156
- closeMenu( store, 'focus' );
157
- } else {
158
- context.core.navigation.previousFocus = ref;
159
- openMenu( store, 'click' );
160
- }
161
- },
162
- handleMenuKeydown: ( store ) => {
163
- const { context, selectors, event } = store;
164
- if (
165
- selectors.core.navigation.menuOpenedBy( store ).click
166
- ) {
167
- // If Escape close the menu.
168
- if ( event?.key === 'Escape' ) {
169
- closeMenu( store, 'click' );
170
- closeMenu( store, 'focus' );
171
- return;
172
- }
173
-
174
- // Trap focus if it is an overlay (main menu).
175
- if (
176
- context.core.navigation.type === 'overlay' &&
177
- event.key === 'Tab'
178
- ) {
179
- // If shift + tab it change the direction.
180
- if (
181
- event.shiftKey &&
182
- window.document.activeElement ===
183
- context.core.navigation
184
- .firstFocusableElement
185
- ) {
186
- event.preventDefault();
187
- context.core.navigation.lastFocusableElement.focus();
188
- } else if (
189
- ! event.shiftKey &&
190
- window.document.activeElement ===
191
- context.core.navigation.lastFocusableElement
192
- ) {
193
- event.preventDefault();
194
- context.core.navigation.firstFocusableElement.focus();
195
- }
196
- }
197
- }
198
- },
199
- handleMenuFocusout: ( store ) => {
200
- const { context, event } = store;
201
- // If focus is outside modal, and in the document, close menu
202
- // event.target === The element losing focus
203
- // event.relatedTarget === The element receiving focus (if any)
204
- // When focusout is outsite the document,
205
- // `window.document.activeElement` doesn't change.
51
+ openMenuOnHover() {
52
+ const { type, overlayOpenedBy } = getContext();
53
+ if (
54
+ type === 'submenu' &&
55
+ // Only open on hover if the overlay is closed.
56
+ Object.values( overlayOpenedBy || {} ).filter( Boolean )
57
+ .length === 0
58
+ )
59
+ actions.openMenu( 'hover' );
60
+ },
61
+ closeMenuOnHover() {
62
+ actions.closeMenu( 'hover' );
63
+ },
64
+ openMenuOnClick() {
65
+ const ctx = getContext();
66
+ const { ref } = getElement();
67
+ ctx.previousFocus = ref;
68
+ actions.openMenu( 'click' );
69
+ },
70
+ closeMenuOnClick() {
71
+ actions.closeMenu( 'click' );
72
+ actions.closeMenu( 'focus' );
73
+ },
74
+ openMenuOnFocus() {
75
+ actions.openMenu( 'focus' );
76
+ },
77
+ toggleMenuOnClick() {
78
+ const ctx = getContext();
79
+ const { ref } = getElement();
80
+ // Safari won't send focus to the clicked element, so we need to manually place it: https://bugs.webkit.org/show_bug.cgi?id=22261
81
+ if ( window.document.activeElement !== ref ) ref.focus();
82
+ const { menuOpenedBy } = state;
83
+ if ( menuOpenedBy.click || menuOpenedBy.focus ) {
84
+ actions.closeMenu( 'click' );
85
+ actions.closeMenu( 'focus' );
86
+ } else {
87
+ ctx.previousFocus = ref;
88
+ actions.openMenu( 'click' );
89
+ }
90
+ },
91
+ handleMenuKeydown( event ) {
92
+ const { type, firstFocusableElement, lastFocusableElement } =
93
+ getContext();
94
+ if ( state.menuOpenedBy.click ) {
95
+ // If Escape close the menu.
96
+ if ( event?.key === 'Escape' ) {
97
+ actions.closeMenu( 'click' );
98
+ actions.closeMenu( 'focus' );
99
+ return;
100
+ }
206
101
 
207
- // The event.relatedTarget is null when something outside the navigation menu is clicked. This is only necessary for Safari.
102
+ // Trap focus if it is an overlay (main menu).
103
+ if ( type === 'overlay' && event.key === 'Tab' ) {
104
+ // If shift + tab it change the direction.
208
105
  if (
209
- event.relatedTarget === null ||
210
- ( ! context.core.navigation.modal?.contains(
211
- event.relatedTarget
212
- ) &&
213
- event.target !== window.document.activeElement )
106
+ event.shiftKey &&
107
+ window.document.activeElement === firstFocusableElement
214
108
  ) {
215
- closeMenu( store, 'click' );
216
- closeMenu( store, 'focus' );
109
+ event.preventDefault();
110
+ lastFocusableElement.focus();
111
+ } else if (
112
+ ! event.shiftKey &&
113
+ window.document.activeElement === lastFocusableElement
114
+ ) {
115
+ event.preventDefault();
116
+ firstFocusableElement.focus();
217
117
  }
218
- },
219
- },
118
+ }
119
+ }
120
+ },
121
+ handleMenuFocusout( event ) {
122
+ const { modal } = getContext();
123
+ // If focus is outside modal, and in the document, close menu
124
+ // event.target === The element losing focus
125
+ // event.relatedTarget === The element receiving focus (if any)
126
+ // When focusout is outsite the document,
127
+ // `window.document.activeElement` doesn't change.
128
+
129
+ // The event.relatedTarget is null when something outside the navigation menu is clicked. This is only necessary for Safari.
130
+ if (
131
+ event.relatedTarget === null ||
132
+ ( ! modal?.contains( event.relatedTarget ) &&
133
+ event.target !== window.document.activeElement )
134
+ ) {
135
+ actions.closeMenu( 'click' );
136
+ actions.closeMenu( 'focus' );
137
+ }
138
+ },
139
+
140
+ openMenu( menuOpenedOn = 'click' ) {
141
+ const { type } = getContext();
142
+ state.menuOpenedBy[ menuOpenedOn ] = true;
143
+ if ( type === 'overlay' ) {
144
+ // Add a `has-modal-open` class to the <html> root.
145
+ document.documentElement.classList.add( 'has-modal-open' );
146
+ }
147
+ },
148
+
149
+ closeMenu( menuClosedOn = 'click' ) {
150
+ const ctx = getContext();
151
+ state.menuOpenedBy[ menuClosedOn ] = false;
152
+ // Check if the menu is still open or not.
153
+ if ( ! state.isMenuOpen ) {
154
+ if ( ctx.modal?.contains( window.document.activeElement ) ) {
155
+ ctx.previousFocus?.focus();
156
+ }
157
+ ctx.modal = null;
158
+ ctx.previousFocus = null;
159
+ if ( ctx.type === 'overlay' ) {
160
+ document.documentElement.classList.remove(
161
+ 'has-modal-open'
162
+ );
163
+ }
164
+ }
165
+ },
166
+ },
167
+ callbacks: {
168
+ initMenu() {
169
+ const ctx = getContext();
170
+ const { ref } = getElement();
171
+ if ( state.isMenuOpen ) {
172
+ const focusableElements =
173
+ ref.querySelectorAll( focusableSelectors );
174
+ ctx.modal = ref;
175
+ ctx.firstFocusableElement = focusableElements[ 0 ];
176
+ ctx.lastFocusableElement =
177
+ focusableElements[ focusableElements.length - 1 ];
178
+ }
179
+ },
180
+ focusFirstElement() {
181
+ const { ref } = getElement();
182
+ if ( state.isMenuOpen ) {
183
+ ref.querySelector(
184
+ '.wp-block-navigation-item > *:first-child'
185
+ ).focus();
186
+ }
220
187
  },
221
188
  },
222
189
  } );
@@ -71,7 +71,8 @@
71
71
  "__experimentalDefaultControls": {
72
72
  "fontSize": true
73
73
  }
74
- }
74
+ },
75
+ "renaming": false
75
76
  },
76
77
  "editorStyle": "wp-block-navigation-link-editor",
77
78
  "style": "wp-block-navigation-link"
@@ -17,11 +17,12 @@ import {
17
17
  waitForElementToBeRemoved,
18
18
  } from 'test/helpers';
19
19
  import Clipboard from '@react-native-clipboard/clipboard';
20
+ import TextInputState from 'react-native/Libraries/Components/TextInput/TextInputState';
20
21
 
21
22
  /**
22
23
  * WordPress dependencies
23
24
  */
24
- import { ENTER } from '@wordpress/keycodes';
25
+ import { BACKSPACE, ENTER } from '@wordpress/keycodes';
25
26
 
26
27
  /**
27
28
  * Internal dependencies
@@ -685,4 +686,39 @@ describe( 'Paragraph block', () => {
685
686
  <!-- /wp:paragraph -->"
686
687
  ` );
687
688
  } );
689
+
690
+ it( 'should focus on the previous Paragraph block when backspacing in an empty Paragraph block', async () => {
691
+ // Arrange
692
+ const screen = await initializeEditor();
693
+ await addBlock( screen, 'Paragraph' );
694
+
695
+ // Act
696
+ const paragraphBlock = getBlock( screen, 'Paragraph' );
697
+ fireEvent.press( paragraphBlock );
698
+ const paragraphTextInput =
699
+ within( paragraphBlock ).getByPlaceholderText( 'Start writing…' );
700
+ typeInRichText( paragraphTextInput, 'A quick brown fox jumps' );
701
+
702
+ await addBlock( screen, 'Paragraph' );
703
+ const secondParagraphBlock = getBlock( screen, 'Paragraph', {
704
+ rowIndex: 2,
705
+ } );
706
+ fireEvent.press( secondParagraphBlock );
707
+
708
+ // Clear mock history
709
+ TextInputState.focusTextInput.mockClear();
710
+
711
+ const secondParagraphTextInput =
712
+ within( secondParagraphBlock ).getByPlaceholderText(
713
+ 'Start writing…'
714
+ );
715
+ fireEvent( secondParagraphTextInput, 'onKeyDown', {
716
+ nativeEvent: {},
717
+ preventDefault() {},
718
+ keyCode: BACKSPACE,
719
+ } );
720
+
721
+ // Assert
722
+ expect( TextInputState.focusTextInput ).toHaveBeenCalled();
723
+ } );
688
724
  } );
@@ -24,9 +24,11 @@ const PatternEdit = ( { attributes, clientId } ) => {
24
24
  []
25
25
  );
26
26
 
27
- const { replaceBlocks, __unstableMarkNextChangeAsNotPersistent } =
28
- useDispatch( blockEditorStore );
29
- const { setBlockEditingMode } = useDispatch( blockEditorStore );
27
+ const {
28
+ replaceBlocks,
29
+ setBlockEditingMode,
30
+ __unstableMarkNextChangeAsNotPersistent,
31
+ } = useDispatch( blockEditorStore );
30
32
  const { getBlockRootClientId, getBlockEditingMode } =
31
33
  useSelect( blockEditorStore );
32
34
 
@@ -123,7 +123,7 @@ export default function PostTemplateEdit( {
123
123
  slug: templateSlug.replace( 'category-', '' ),
124
124
  } );
125
125
  const query = {
126
- offset: perPage ? perPage + offset : 0,
126
+ offset: offset || 0,
127
127
  order,
128
128
  orderby: orderBy,
129
129
  };
@@ -21,19 +21,15 @@ function render_block_core_query( $attributes, $content, $block ) {
21
21
  $p = new WP_HTML_Tag_Processor( $content );
22
22
  if ( $p->next_tag() ) {
23
23
  // Add the necessary directives.
24
- $p->set_attribute( 'data-wp-interactive', true );
24
+ $p->set_attribute( 'data-wp-interactive', '{"namespace":"core/query"}' );
25
25
  $p->set_attribute( 'data-wp-navigation-id', 'query-' . $attributes['queryId'] );
26
26
  // Use context to send translated strings.
27
27
  $p->set_attribute(
28
28
  'data-wp-context',
29
29
  wp_json_encode(
30
30
  array(
31
- 'core' => array(
32
- 'query' => array(
33
- 'loadingText' => __( 'Loading page, please wait.' ),
34
- 'loadedText' => __( 'Page Loaded.' ),
35
- ),
36
- ),
31
+ 'loadingText' => __( 'Loading page, please wait.' ),
32
+ 'loadedText' => __( 'Page Loaded.' ),
37
33
  ),
38
34
  JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP
39
35
  )
@@ -54,12 +50,12 @@ function render_block_core_query( $attributes, $content, $block ) {
54
50
  '<div
55
51
  class="screen-reader-text"
56
52
  aria-live="polite"
57
- data-wp-text="context.core.query.message"
53
+ data-wp-text="context.message"
58
54
  ></div>
59
55
  <div
60
56
  class="wp-block-query__enhanced-pagination-animation"
61
- data-wp-class--start-animation="selectors.core.query.startAnimation"
62
- data-wp-class--finish-animation="selectors.core.query.finishAnimation"
57
+ data-wp-class--start-animation="state.startAnimation"
58
+ data-wp-class--finish-animation="state.finishAnimation"
63
59
  ></div>',
64
60
  $last_tag_position,
65
61
  0
@@ -67,19 +63,28 @@ function render_block_core_query( $attributes, $content, $block ) {
67
63
  }
68
64
  }
69
65
 
70
- $view_asset = 'wp-block-query-view';
71
- if ( ! wp_script_is( $view_asset ) ) {
72
- $script_handles = $block->block_type->view_script_handles;
73
- // If the script is not needed, and it is still in the `view_script_handles`, remove it.
74
- if (
75
- ( ! $attributes['enhancedPagination'] || ! isset( $attributes['queryId'] ) )
76
- && in_array( $view_asset, $script_handles, true )
77
- ) {
78
- $block->block_type->view_script_handles = array_diff( $script_handles, array( $view_asset ) );
66
+ $is_gutenberg_plugin = defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN;
67
+ $should_load_view_script = $attributes['enhancedPagination'] && isset( $attributes['queryId'] );
68
+ $view_asset = 'wp-block-query-view';
69
+ $script_handles = $block->block_type->view_script_handles;
70
+
71
+ if ( $is_gutenberg_plugin ) {
72
+ if ( $should_load_view_script ) {
73
+ gutenberg_enqueue_module( '@wordpress/block-library/query' );
79
74
  }
80
- // If the script is needed, but it was previously removed, add it again.
81
- if ( $attributes['enhancedPagination'] && isset( $attributes['queryId'] ) && ! in_array( $view_asset, $script_handles, true ) ) {
82
- $block->block_type->view_script_handles = array_merge( $script_handles, array( $view_asset ) );
75
+ // Remove the view script because we are using the module.
76
+ $block->block_type->view_script_handles = array_diff( $script_handles, array( $view_asset ) );
77
+ } else {
78
+ if ( ! wp_script_is( $view_asset ) ) {
79
+ // If the script is not needed, and it is still in the `view_script_handles`, remove it.
80
+ if ( ! $should_load_view_script && in_array( $view_asset, $script_handles, true )
81
+ ) {
82
+ $block->block_type->view_script_handles = array_diff( $script_handles, array( $view_asset ) );
83
+ }
84
+ // If the script is needed, but it was previously removed, add it again.
85
+ if ( $should_load_view_script && ! in_array( $view_asset, $script_handles, true ) ) {
86
+ $block->block_type->view_script_handles = array_merge( $script_handles, array( $view_asset ) );
87
+ }
83
88
  }
84
89
  }
85
90
 
@@ -131,6 +136,15 @@ function register_block_core_query() {
131
136
  'render_callback' => 'render_block_core_query',
132
137
  )
133
138
  );
139
+
140
+ if ( defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN ) {
141
+ gutenberg_register_module(
142
+ '@wordpress/block-library/query',
143
+ '/wp-content/plugins/gutenberg/build/interactivity/query.min.js',
144
+ array( '@wordpress/interactivity' ),
145
+ defined( 'GUTENBERG_VERSION' ) ? GUTENBERG_VERSION : get_bloginfo( 'version' )
146
+ );
147
+ }
134
148
  }
135
149
  add_action( 'init', 'register_block_core_query' );
136
150