@wordpress/block-library 8.15.0 → 8.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.
- package/CHANGELOG.md +2 -0
- package/build/avatar/index.js +3 -0
- package/build/avatar/index.js.map +1 -1
- package/build/block/edit.js +2 -30
- package/build/block/edit.js.map +1 -1
- package/build/cover/index.js +2 -1
- package/build/cover/index.js.map +1 -1
- package/build/footnotes/edit.js +11 -0
- package/build/footnotes/edit.js.map +1 -1
- package/build/footnotes/format.js +101 -8
- package/build/footnotes/format.js.map +1 -1
- package/build/footnotes/index.js +45 -3
- package/build/footnotes/index.js.map +1 -1
- package/build/gallery/edit.js +7 -5
- package/build/gallery/edit.js.map +1 -1
- package/build/image/deprecated.js +106 -2
- package/build/image/deprecated.js.map +1 -1
- package/build/image/image.js +2 -2
- package/build/image/image.js.map +1 -1
- package/build/image/index.js +2 -1
- package/build/image/index.js.map +1 -1
- package/build/index.js +3 -1
- package/build/index.js.map +1 -1
- package/build/list-item/hooks/use-merge.js +10 -1
- package/build/list-item/hooks/use-merge.js.map +1 -1
- package/build/navigation/edit/menu-inspector-controls.js +1 -1
- package/build/navigation/edit/menu-inspector-controls.js.map +1 -1
- package/build/navigation/edit/navigation-menu-selector.js +4 -4
- package/build/navigation/edit/navigation-menu-selector.js.map +1 -1
- package/build/navigation/view-modal.js +93 -32
- package/build/navigation/view-modal.js.map +1 -1
- package/build/navigation/view.js +63 -31
- package/build/navigation/view.js.map +1 -1
- package/build/pattern/edit.js +28 -4
- package/build/pattern/edit.js.map +1 -1
- package/build/preformatted/index.js +4 -0
- package/build/preformatted/index.js.map +1 -1
- package/build/search/view.js +166 -62
- package/build/search/view.js.map +1 -1
- package/build/social-link/icons/index.js +13 -0
- package/build/social-link/icons/index.js.map +1 -1
- package/build/social-link/icons/threads.js +25 -0
- package/build/social-link/icons/threads.js.map +1 -0
- package/build/social-link/variations.js +7 -0
- package/build/social-link/variations.js.map +1 -1
- package/build/template-part/edit/import-controls.js +1 -1
- package/build/template-part/edit/import-controls.js.map +1 -1
- package/build-module/avatar/index.js +3 -0
- package/build-module/avatar/index.js.map +1 -1
- package/build-module/block/edit.js +4 -29
- package/build-module/block/edit.js.map +1 -1
- package/build-module/cover/index.js +2 -1
- package/build-module/cover/index.js.map +1 -1
- package/build-module/footnotes/edit.js +11 -0
- package/build-module/footnotes/edit.js.map +1 -1
- package/build-module/footnotes/format.js +102 -10
- package/build-module/footnotes/format.js.map +1 -1
- package/build-module/footnotes/index.js +45 -3
- package/build-module/footnotes/index.js.map +1 -1
- package/build-module/gallery/edit.js +7 -5
- package/build-module/gallery/edit.js.map +1 -1
- package/build-module/image/deprecated.js +107 -3
- package/build-module/image/deprecated.js.map +1 -1
- package/build-module/image/image.js +2 -2
- package/build-module/image/image.js.map +1 -1
- package/build-module/image/index.js +2 -1
- package/build-module/image/index.js.map +1 -1
- package/build-module/index.js +3 -1
- package/build-module/index.js.map +1 -1
- package/build-module/list-item/hooks/use-merge.js +10 -1
- package/build-module/list-item/hooks/use-merge.js.map +1 -1
- package/build-module/navigation/edit/menu-inspector-controls.js +1 -1
- package/build-module/navigation/edit/menu-inspector-controls.js.map +1 -1
- package/build-module/navigation/edit/navigation-menu-selector.js +4 -4
- package/build-module/navigation/edit/navigation-menu-selector.js.map +1 -1
- package/build-module/navigation/view-modal.js +93 -31
- package/build-module/navigation/view-modal.js.map +1 -1
- package/build-module/navigation/view.js +63 -31
- package/build-module/navigation/view.js.map +1 -1
- package/build-module/pattern/edit.js +27 -4
- package/build-module/pattern/edit.js.map +1 -1
- package/build-module/preformatted/index.js +4 -0
- package/build-module/preformatted/index.js.map +1 -1
- package/build-module/search/view.js +166 -62
- package/build-module/search/view.js.map +1 -1
- package/build-module/social-link/icons/index.js +1 -0
- package/build-module/social-link/icons/index.js.map +1 -1
- package/build-module/social-link/icons/threads.js +15 -0
- package/build-module/social-link/icons/threads.js.map +1 -0
- package/build-module/social-link/variations.js +8 -1
- package/build-module/social-link/variations.js.map +1 -1
- package/build-module/template-part/edit/import-controls.js +2 -2
- package/build-module/template-part/edit/import-controls.js.map +1 -1
- package/build-style/preformatted/style-rtl.css +2 -1
- package/build-style/preformatted/style.css +2 -1
- package/build-style/social-links/style-rtl.css +7 -0
- package/build-style/social-links/style.css +7 -0
- package/build-style/style-rtl.css +10 -1
- package/build-style/style.css +10 -1
- package/build-style/video/style-rtl.css +1 -0
- package/build-style/video/style.css +1 -0
- package/package.json +32 -32
- package/src/audio/test/__snapshots__/edit.native.js.snap +60 -0
- package/src/avatar/block.json +3 -0
- package/src/block/edit.js +1 -39
- package/src/buttons/test/edit.native.js +4 -0
- package/src/columns/test/edit.native.js +5 -0
- package/src/comment-template/index.php +2 -0
- package/src/cover/block.json +2 -1
- package/src/cover/test/edit.native.js +8 -0
- package/src/embed/test/index.native.js +8 -0
- package/src/file/index.php +1 -1
- package/src/file/test/__snapshots__/edit.native.js.snap +61 -0
- package/src/footnotes/block.json +44 -1
- package/src/footnotes/edit.js +12 -0
- package/src/footnotes/format.js +70 -7
- package/src/footnotes/index.js +0 -1
- package/src/footnotes/index.php +207 -0
- package/src/gallery/edit.js +41 -37
- package/src/gallery/test/index.native.js +15 -3
- package/src/heading/test/index.native.js +4 -0
- package/src/image/block.json +2 -1
- package/src/image/deprecated.js +109 -3
- package/src/image/image.js +2 -2
- package/src/image/index.php +1 -3
- package/src/image/test/edit.native.js +0 -1
- package/src/index.js +5 -1
- package/src/list/test/edit.native.js +5 -0
- package/src/list-item/hooks/use-merge.js +12 -5
- package/src/missing/test/__snapshots__/edit.native.js.snap +21 -0
- package/src/navigation/edit/menu-inspector-controls.js +1 -1
- package/src/navigation/edit/navigation-menu-selector.js +8 -4
- package/src/navigation/index.php +27 -13
- package/src/navigation/view-modal.js +88 -39
- package/src/navigation/view.js +69 -36
- package/src/paragraph/test/edit.native.js +55 -35
- package/src/pattern/edit.js +21 -0
- package/src/pattern/index.php +13 -1
- package/src/post-template/index.php +2 -0
- package/src/post-title/index.php +2 -0
- package/src/preformatted/block.json +4 -0
- package/src/preformatted/style.scss +4 -1
- package/src/pullquote/test/edit.native.js +12 -4
- package/src/quote/test/edit.native.js +12 -4
- package/src/search/index.php +4 -0
- package/src/search/test/__snapshots__/edit.native.js.snap +63 -0
- package/src/search/view.js +171 -67
- package/src/social-link/icons/index.js +1 -0
- package/src/social-link/icons/threads.js +10 -0
- package/src/social-link/index.php +4 -0
- package/src/social-link/socials-with-bg.scss +5 -0
- package/src/social-link/socials-without-bg.scss +4 -0
- package/src/social-link/variations.js +7 -0
- package/src/template-part/edit/import-controls.js +2 -2
- package/src/template-part/index.php +6 -9
- package/src/video/style.scss +1 -0
package/src/index.js
CHANGED
|
@@ -282,7 +282,11 @@ export const registerCoreBlocks = (
|
|
|
282
282
|
blocks.forEach( ( { init } ) => init() );
|
|
283
283
|
|
|
284
284
|
setDefaultBlockName( paragraph.name );
|
|
285
|
-
if (
|
|
285
|
+
if (
|
|
286
|
+
window.wp &&
|
|
287
|
+
window.wp.oldEditor &&
|
|
288
|
+
blocks.some( ( { name } ) => name === classic.name )
|
|
289
|
+
) {
|
|
286
290
|
setFreeformContentHandlerName( classic.name );
|
|
287
291
|
}
|
|
288
292
|
setUnregisteredTypeHandlerName( missing.name );
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* External dependencies
|
|
3
3
|
*/
|
|
4
4
|
import {
|
|
5
|
+
act,
|
|
5
6
|
selectRangeInRichText,
|
|
6
7
|
typeInRichText,
|
|
7
8
|
fireEvent,
|
|
@@ -577,6 +578,10 @@ describe( 'List block', () => {
|
|
|
577
578
|
preventDefault() {},
|
|
578
579
|
keyCode: BACKSPACE,
|
|
579
580
|
} );
|
|
581
|
+
// Inner blocks batch store updates with microtasks.
|
|
582
|
+
// To avoid `act` warnings, we let queued microtasks to be executed.
|
|
583
|
+
// Reference: https://t.ly/b95nA
|
|
584
|
+
await act( async () => {} );
|
|
580
585
|
|
|
581
586
|
expect( getEditorHtml() ).toMatchInlineSnapshot( `
|
|
582
587
|
"<!-- wp:paragraph -->
|
|
@@ -107,11 +107,18 @@ export default function useMerge( clientId, onMerge ) {
|
|
|
107
107
|
} else if ( previousBlockClientId ) {
|
|
108
108
|
const trailingId = getTrailingId( previousBlockClientId );
|
|
109
109
|
registry.batch( () => {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
);
|
|
110
|
+
// When merging a list item with a previous trailing list
|
|
111
|
+
// item, we also need to move any nested list items. First,
|
|
112
|
+
// check if there's a listed list. If there's a nested list,
|
|
113
|
+
// append its nested list items to the trailing list.
|
|
114
|
+
const [ nestedListClientId ] = getBlockOrder( clientId );
|
|
115
|
+
if ( nestedListClientId ) {
|
|
116
|
+
moveBlocksToPosition(
|
|
117
|
+
getBlockOrder( nestedListClientId ),
|
|
118
|
+
nestedListClientId,
|
|
119
|
+
getBlockRootClientId( trailingId )
|
|
120
|
+
);
|
|
121
|
+
}
|
|
115
122
|
mergeBlocks( trailingId, clientId );
|
|
116
123
|
} );
|
|
117
124
|
} else {
|
|
@@ -7,7 +7,11 @@ exports[`Missing block renders without crashing 1`] = `
|
|
|
7
7
|
accessibilityRole="button"
|
|
8
8
|
accessibilityState={
|
|
9
9
|
{
|
|
10
|
+
"busy": undefined,
|
|
11
|
+
"checked": undefined,
|
|
10
12
|
"disabled": true,
|
|
13
|
+
"expanded": undefined,
|
|
14
|
+
"selected": undefined,
|
|
11
15
|
}
|
|
12
16
|
}
|
|
13
17
|
accessible={true}
|
|
@@ -24,6 +28,23 @@ exports[`Missing block renders without crashing 1`] = `
|
|
|
24
28
|
accessibilityHint="Tap here to show help"
|
|
25
29
|
accessibilityLabel="Help button"
|
|
26
30
|
accessibilityRole="button"
|
|
31
|
+
accessibilityState={
|
|
32
|
+
{
|
|
33
|
+
"busy": undefined,
|
|
34
|
+
"checked": undefined,
|
|
35
|
+
"disabled": undefined,
|
|
36
|
+
"expanded": undefined,
|
|
37
|
+
"selected": undefined,
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
accessibilityValue={
|
|
41
|
+
{
|
|
42
|
+
"max": undefined,
|
|
43
|
+
"min": undefined,
|
|
44
|
+
"now": undefined,
|
|
45
|
+
"text": undefined,
|
|
46
|
+
}
|
|
47
|
+
}
|
|
27
48
|
accessible={true}
|
|
28
49
|
collapsable={false}
|
|
29
50
|
focusable={true}
|
|
@@ -103,7 +103,7 @@ const MainContent = ( {
|
|
|
103
103
|
? sprintf(
|
|
104
104
|
/* translators: %s: The name of a menu. */
|
|
105
105
|
__( 'Structure for navigation menu: %s' ),
|
|
106
|
-
navigationMenu?.title
|
|
106
|
+
navigationMenu?.title || __( 'Untitled menu' )
|
|
107
107
|
)
|
|
108
108
|
: __(
|
|
109
109
|
'You have not yet created any menus. Displaying a list of your Pages'
|
|
@@ -20,19 +20,19 @@ import useNavigationMenu from '../use-navigation-menu';
|
|
|
20
20
|
import useNavigationEntities from '../use-navigation-entities';
|
|
21
21
|
|
|
22
22
|
function buildMenuLabel( title, id, status ) {
|
|
23
|
-
if ( ! title
|
|
23
|
+
if ( ! title ) {
|
|
24
24
|
/* translators: %s is the index of the menu in the list of menus. */
|
|
25
25
|
return sprintf( __( '(no title %s)' ), id );
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
if ( status === 'publish' ) {
|
|
29
|
-
return decodeEntities( title
|
|
29
|
+
return decodeEntities( title );
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
return sprintf(
|
|
33
33
|
// translators: %1s: title of the menu; %2s: status of the menu (draft, pending, etc.).
|
|
34
34
|
__( '%1$s (%2$s)' ),
|
|
35
|
-
decodeEntities( title
|
|
35
|
+
decodeEntities( title ),
|
|
36
36
|
status
|
|
37
37
|
);
|
|
38
38
|
}
|
|
@@ -72,7 +72,11 @@ function NavigationMenuSelector( {
|
|
|
72
72
|
const menuChoices = useMemo( () => {
|
|
73
73
|
return (
|
|
74
74
|
navigationMenus?.map( ( { id, title, status }, index ) => {
|
|
75
|
-
const label = buildMenuLabel(
|
|
75
|
+
const label = buildMenuLabel(
|
|
76
|
+
title?.rendered,
|
|
77
|
+
index + 1,
|
|
78
|
+
status
|
|
79
|
+
);
|
|
76
80
|
|
|
77
81
|
return {
|
|
78
82
|
value: id,
|
package/src/navigation/index.php
CHANGED
|
@@ -671,19 +671,33 @@ function render_block_core_navigation( $attributes, $content, $block ) {
|
|
|
671
671
|
$inner_blocks_html .= '</ul>';
|
|
672
672
|
}
|
|
673
673
|
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
674
|
+
$needed_script_map = array(
|
|
675
|
+
'wp-block-navigation-view' => ( $has_submenus && ( $attributes['openSubmenusOnClick'] || $attributes['showSubmenuIcon'] ) ),
|
|
676
|
+
'wp-block-navigation-view-2' => $is_responsive_menu,
|
|
677
|
+
);
|
|
678
|
+
|
|
679
|
+
$should_load_view_script = false;
|
|
680
|
+
if ( gutenberg_should_block_use_interactivity_api( 'core/navigation' ) ) {
|
|
681
|
+
// TODO: The script is still loaded even when it isn't needed when the Interactivity API is used.
|
|
682
|
+
$should_load_view_script = count( array_filter( $needed_script_map ) ) > 0;
|
|
683
|
+
} else {
|
|
684
|
+
foreach ( $needed_script_map as $view_script_handle => $is_view_script_needed ) {
|
|
685
|
+
|
|
686
|
+
// If the script already exists, there is no point in removing it from viewScript.
|
|
687
|
+
if ( wp_script_is( $view_script_handle ) ) {
|
|
688
|
+
continue;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
$script_handles = $block->block_type->view_script_handles;
|
|
692
|
+
|
|
693
|
+
// If the script is not needed, and it is still in the `view_script_handles`, remove it.
|
|
694
|
+
if ( ! $is_view_script_needed && in_array( $view_script_handle, $script_handles, true ) ) {
|
|
695
|
+
$block->block_type->view_script_handles = array_diff( $script_handles, array( $view_script_handle ) );
|
|
696
|
+
}
|
|
697
|
+
// If the script is needed, but it was previously removed, add it again.
|
|
698
|
+
if ( $is_view_script_needed && ! in_array( $view_script_handle, $script_handles, true ) ) {
|
|
699
|
+
$block->block_type->view_script_handles = array_merge( $script_handles, array( $view_script_handle ) );
|
|
700
|
+
}
|
|
687
701
|
}
|
|
688
702
|
}
|
|
689
703
|
|
|
@@ -1,16 +1,22 @@
|
|
|
1
|
+
/*eslint-env browser*/
|
|
1
2
|
/**
|
|
2
3
|
* External dependencies
|
|
3
4
|
*/
|
|
4
5
|
import MicroModal from 'micromodal';
|
|
5
6
|
|
|
6
7
|
// Responsive navigation toggle.
|
|
7
|
-
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Toggles responsive navigation.
|
|
11
|
+
*
|
|
12
|
+
* @param {HTMLDivElement} modal
|
|
13
|
+
* @param {boolean} isHidden
|
|
14
|
+
*/
|
|
15
|
+
function navigationToggleModal( modal, isHidden ) {
|
|
8
16
|
const dialogContainer = modal.querySelector(
|
|
9
17
|
`.wp-block-navigation__responsive-dialog`
|
|
10
18
|
);
|
|
11
19
|
|
|
12
|
-
const isHidden = 'true' === modal.getAttribute( 'aria-hidden' );
|
|
13
|
-
|
|
14
20
|
modal.classList.toggle( 'has-modal-open', ! isHidden );
|
|
15
21
|
dialogContainer.toggleAttribute( 'aria-modal', ! isHidden );
|
|
16
22
|
|
|
@@ -23,10 +29,15 @@ function navigationToggleModal( modal ) {
|
|
|
23
29
|
}
|
|
24
30
|
|
|
25
31
|
// Add a class to indicate the modal is open.
|
|
26
|
-
|
|
27
|
-
htmlElement.classList.toggle( 'has-modal-open' );
|
|
32
|
+
document.documentElement.classList.toggle( 'has-modal-open' );
|
|
28
33
|
}
|
|
29
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Checks whether the provided link is an anchor on the current page.
|
|
37
|
+
*
|
|
38
|
+
* @param {HTMLAnchorElement} node
|
|
39
|
+
* @return {boolean} Is anchor.
|
|
40
|
+
*/
|
|
30
41
|
function isLinkToAnchorOnCurrentPage( node ) {
|
|
31
42
|
return (
|
|
32
43
|
node.hash &&
|
|
@@ -37,42 +48,80 @@ function isLinkToAnchorOnCurrentPage( node ) {
|
|
|
37
48
|
);
|
|
38
49
|
}
|
|
39
50
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
51
|
+
/**
|
|
52
|
+
* Handles effects after opening the modal.
|
|
53
|
+
*
|
|
54
|
+
* @param {HTMLDivElement} modal
|
|
55
|
+
*/
|
|
56
|
+
function onShow( modal ) {
|
|
57
|
+
navigationToggleModal( modal, false );
|
|
58
|
+
modal.addEventListener( 'click', handleAnchorLinkClicksInsideModal, {
|
|
59
|
+
passive: true,
|
|
45
60
|
} );
|
|
61
|
+
}
|
|
46
62
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
63
|
+
/**
|
|
64
|
+
* Handles effects after closing the modal.
|
|
65
|
+
*
|
|
66
|
+
* @param {HTMLDivElement} modal
|
|
67
|
+
*/
|
|
68
|
+
function onClose( modal ) {
|
|
69
|
+
navigationToggleModal( modal, true );
|
|
70
|
+
modal.removeEventListener( 'click', handleAnchorLinkClicksInsideModal, {
|
|
71
|
+
passive: true,
|
|
72
|
+
} );
|
|
73
|
+
}
|
|
51
74
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
75
|
+
/**
|
|
76
|
+
* Handle clicks to anchor links in modal using event delegation by closing modal automatically
|
|
77
|
+
*
|
|
78
|
+
* @param {UIEvent} event
|
|
79
|
+
*/
|
|
80
|
+
function handleAnchorLinkClicksInsideModal( event ) {
|
|
81
|
+
const link = event.target.closest( '.wp-block-navigation-item__content' );
|
|
82
|
+
if ( ! ( link instanceof HTMLAnchorElement ) ) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
60
85
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
86
|
+
// Ignore non-anchor links and anchor links which open on a new tab.
|
|
87
|
+
if (
|
|
88
|
+
! isLinkToAnchorOnCurrentPage( link ) ||
|
|
89
|
+
link.attributes?.target === '_blank'
|
|
90
|
+
) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
68
93
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
94
|
+
// Find the specific parent modal for this link
|
|
95
|
+
// since .close() won't work without an ID if there are
|
|
96
|
+
// multiple navigation menus in a post/page.
|
|
97
|
+
const modal = link.closest( '.wp-block-navigation__responsive-container' );
|
|
98
|
+
const modalId = modal?.getAttribute( 'id' );
|
|
99
|
+
if ( ! modalId ) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// check if modal exists and is open before trying to close it
|
|
104
|
+
// otherwise Micromodal will toggle the `has-modal-open` class
|
|
105
|
+
// on the html tag which prevents scrolling
|
|
106
|
+
if ( modalId && modal.classList.contains( 'has-modal-open' ) ) {
|
|
107
|
+
MicroModal.close( modalId );
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// MicroModal.init() does not support event delegation for the open trigger, so here MicroModal.show() is called manually.
|
|
112
|
+
document.addEventListener(
|
|
113
|
+
'click',
|
|
114
|
+
( event ) => {
|
|
115
|
+
/** @type {HTMLElement} */
|
|
116
|
+
const target = event.target;
|
|
117
|
+
|
|
118
|
+
if ( target.dataset.micromodalTrigger ) {
|
|
119
|
+
MicroModal.show( target.dataset.micromodalTrigger, {
|
|
120
|
+
onShow,
|
|
121
|
+
onClose,
|
|
122
|
+
openClass: 'is-menu-open',
|
|
123
|
+
} );
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
{ passive: true }
|
|
127
|
+
);
|
package/src/navigation/view.js
CHANGED
|
@@ -1,62 +1,94 @@
|
|
|
1
|
+
/*eslint-env browser*/
|
|
1
2
|
// Open on click functionality.
|
|
2
|
-
|
|
3
|
-
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Keep track of whether a submenu is open to short-circuit delegated event listeners.
|
|
6
|
+
*
|
|
7
|
+
* @type {boolean}
|
|
8
|
+
*/
|
|
9
|
+
let hasOpenSubmenu = false;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Close submenu items for a navigation item.
|
|
13
|
+
*
|
|
14
|
+
* @param {HTMLElement} navigationItem - Either a NAV or LI element.
|
|
15
|
+
*/
|
|
16
|
+
function closeSubmenus( navigationItem ) {
|
|
17
|
+
navigationItem
|
|
4
18
|
.querySelectorAll( '[aria-expanded="true"]' )
|
|
5
19
|
.forEach( function ( toggle ) {
|
|
6
20
|
toggle.setAttribute( 'aria-expanded', 'false' );
|
|
7
21
|
} );
|
|
22
|
+
hasOpenSubmenu = false;
|
|
8
23
|
}
|
|
9
24
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
25
|
+
/**
|
|
26
|
+
* Toggle submenu on click.
|
|
27
|
+
*
|
|
28
|
+
* @param {HTMLButtonElement} buttonToggle
|
|
29
|
+
*/
|
|
30
|
+
function toggleSubmenuOnClick( buttonToggle ) {
|
|
31
|
+
const isSubmenuOpen =
|
|
32
|
+
buttonToggle.getAttribute( 'aria-expanded' ) === 'true';
|
|
33
|
+
const navigationItem = buttonToggle.closest( '.wp-block-navigation-item' );
|
|
13
34
|
|
|
14
|
-
if ( isSubmenuOpen
|
|
15
|
-
closeSubmenus(
|
|
35
|
+
if ( isSubmenuOpen ) {
|
|
36
|
+
closeSubmenus( navigationItem );
|
|
16
37
|
} else {
|
|
17
38
|
// Close all sibling submenus.
|
|
18
|
-
const parentElement = buttonToggle.closest(
|
|
19
|
-
'.wp-block-navigation-item'
|
|
20
|
-
);
|
|
21
39
|
const navigationParent = buttonToggle.closest(
|
|
22
40
|
'.wp-block-navigation__submenu-container, .wp-block-navigation__container, .wp-block-page-list'
|
|
23
41
|
);
|
|
24
42
|
navigationParent
|
|
25
43
|
.querySelectorAll( '.wp-block-navigation-item' )
|
|
26
|
-
.forEach(
|
|
27
|
-
if ( child !==
|
|
44
|
+
.forEach( ( child ) => {
|
|
45
|
+
if ( child !== navigationItem ) {
|
|
28
46
|
closeSubmenus( child );
|
|
29
47
|
}
|
|
30
48
|
} );
|
|
49
|
+
|
|
31
50
|
// Open submenu.
|
|
32
51
|
buttonToggle.setAttribute( 'aria-expanded', 'true' );
|
|
52
|
+
hasOpenSubmenu = true;
|
|
33
53
|
}
|
|
34
54
|
}
|
|
35
55
|
|
|
36
|
-
//
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
56
|
+
// Open on button click or close on click outside.
|
|
57
|
+
document.addEventListener(
|
|
58
|
+
'click',
|
|
59
|
+
function ( event ) {
|
|
60
|
+
const target = event.target;
|
|
61
|
+
const button = target.closest( '.wp-block-navigation-submenu__toggle' );
|
|
42
62
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
63
|
+
// Close any other open submenus.
|
|
64
|
+
if ( hasOpenSubmenu ) {
|
|
65
|
+
const navigationBlocks = document.querySelectorAll(
|
|
66
|
+
'.wp-block-navigation'
|
|
67
|
+
);
|
|
68
|
+
navigationBlocks.forEach( function ( block ) {
|
|
69
|
+
if ( ! block.contains( target ) ) {
|
|
70
|
+
closeSubmenus( block );
|
|
71
|
+
}
|
|
72
|
+
} );
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Now open the submenu if one was clicked.
|
|
76
|
+
if ( button instanceof HTMLButtonElement ) {
|
|
77
|
+
toggleSubmenuOnClick( button );
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
{ passive: true }
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
// Close on focus outside or escape key.
|
|
84
|
+
document.addEventListener(
|
|
85
|
+
'keyup',
|
|
86
|
+
function ( event ) {
|
|
87
|
+
// Abort if there aren't any submenus open anyway.
|
|
88
|
+
if ( ! hasOpenSubmenu ) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
46
91
|
|
|
47
|
-
// Close on click outside.
|
|
48
|
-
document.addEventListener( 'click', function ( event ) {
|
|
49
|
-
const navigationBlocks = document.querySelectorAll(
|
|
50
|
-
'.wp-block-navigation'
|
|
51
|
-
);
|
|
52
|
-
navigationBlocks.forEach( function ( block ) {
|
|
53
|
-
if ( ! block.contains( event.target ) ) {
|
|
54
|
-
closeSubmenus( block );
|
|
55
|
-
}
|
|
56
|
-
} );
|
|
57
|
-
} );
|
|
58
|
-
// Close on focus outside or escape key.
|
|
59
|
-
document.addEventListener( 'keyup', function ( event ) {
|
|
60
92
|
const submenuBlocks = document.querySelectorAll(
|
|
61
93
|
'.wp-block-navigation-item.has-child'
|
|
62
94
|
);
|
|
@@ -70,5 +102,6 @@ window.addEventListener( 'load', () => {
|
|
|
70
102
|
toggle?.focus();
|
|
71
103
|
}
|
|
72
104
|
} );
|
|
73
|
-
}
|
|
74
|
-
}
|
|
105
|
+
},
|
|
106
|
+
{ passive: true }
|
|
107
|
+
);
|
|
@@ -13,6 +13,8 @@ import {
|
|
|
13
13
|
setupCoreBlocks,
|
|
14
14
|
waitFor,
|
|
15
15
|
within,
|
|
16
|
+
withFakeTimers,
|
|
17
|
+
waitForElementToBeRemoved,
|
|
16
18
|
} from 'test/helpers';
|
|
17
19
|
import Clipboard from '@react-native-clipboard/clipboard';
|
|
18
20
|
|
|
@@ -26,6 +28,19 @@ import { ENTER } from '@wordpress/keycodes';
|
|
|
26
28
|
*/
|
|
27
29
|
import Paragraph from '../edit';
|
|
28
30
|
|
|
31
|
+
// Mock debounce to prevent potentially belated state updates.
|
|
32
|
+
jest.mock( '@wordpress/compose/src/utils/debounce', () => ( {
|
|
33
|
+
debounce: ( fn ) => {
|
|
34
|
+
fn.cancel = jest.fn();
|
|
35
|
+
return fn;
|
|
36
|
+
},
|
|
37
|
+
} ) );
|
|
38
|
+
// Mock link suggestions that are fetched by the link picker
|
|
39
|
+
// when typing a search query.
|
|
40
|
+
jest.mock( '@wordpress/core-data/src/fetch', () => ( {
|
|
41
|
+
__experimentalFetchLinkSuggestions: jest.fn().mockResolvedValue( [ {} ] ),
|
|
42
|
+
} ) );
|
|
43
|
+
|
|
29
44
|
setupCoreBlocks();
|
|
30
45
|
|
|
31
46
|
const getTestComponentWithContent = ( content ) => {
|
|
@@ -238,26 +253,27 @@ describe( 'Paragraph block', () => {
|
|
|
238
253
|
// Act
|
|
239
254
|
const paragraphBlock = getBlock( screen, 'Paragraph' );
|
|
240
255
|
fireEvent.press( paragraphBlock );
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
// Await React Navigation: https://github.com/WordPress/gutenberg/issues/35685#issuecomment-961919931
|
|
244
|
-
await act( () =>
|
|
245
|
-
fireEvent.press(
|
|
246
|
-
screen.getByLabelText( 'Link to, Search or type URL' )
|
|
247
|
-
)
|
|
248
|
-
);
|
|
249
|
-
fireEvent.changeText(
|
|
250
|
-
screen.getByPlaceholderText( 'Search or type URL' ),
|
|
251
|
-
'wordpress.org'
|
|
252
|
-
);
|
|
256
|
+
fireEvent.press( screen.getByLabelText( 'Link' ) );
|
|
257
|
+
|
|
253
258
|
fireEvent.changeText(
|
|
254
|
-
screen.getByPlaceholderText( 'Add link text'
|
|
259
|
+
screen.getByPlaceholderText( 'Add link text' ),
|
|
255
260
|
'WordPress'
|
|
256
261
|
);
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
262
|
+
fireEvent.press(
|
|
263
|
+
screen.getByLabelText( 'Link to, Search or type URL' )
|
|
264
|
+
);
|
|
265
|
+
const typeURLInput = await waitFor( () =>
|
|
266
|
+
screen.getByPlaceholderText( 'Search or type URL' )
|
|
267
|
+
);
|
|
268
|
+
fireEvent.changeText( typeURLInput, 'wordpress.org' );
|
|
269
|
+
await waitForElementToBeRemoved( () =>
|
|
270
|
+
screen.getByTestId( 'link-picker-loading' )
|
|
271
|
+
);
|
|
272
|
+
// Back navigation from link picker uses `setTimeout`
|
|
273
|
+
await withFakeTimers( () => {
|
|
274
|
+
fireEvent.press( screen.getByLabelText( 'Apply' ) );
|
|
275
|
+
act( () => jest.runOnlyPendingTimers() );
|
|
276
|
+
} );
|
|
261
277
|
|
|
262
278
|
// Assert
|
|
263
279
|
expect( getEditorHtml() ).toMatchInlineSnapshot( `
|
|
@@ -265,8 +281,6 @@ describe( 'Paragraph block', () => {
|
|
|
265
281
|
<p><a href="http://wordpress.org">WordPress</a></p>
|
|
266
282
|
<!-- /wp:paragraph -->"
|
|
267
283
|
` );
|
|
268
|
-
|
|
269
|
-
jest.useRealTimers();
|
|
270
284
|
} );
|
|
271
285
|
|
|
272
286
|
it( 'should link text with selection', async () => {
|
|
@@ -287,22 +301,22 @@ describe( 'Paragraph block', () => {
|
|
|
287
301
|
finalSelectionEnd: 7,
|
|
288
302
|
}
|
|
289
303
|
);
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
await act( () =>
|
|
294
|
-
fireEvent.press(
|
|
295
|
-
screen.getByLabelText( 'Link to, Search or type URL' )
|
|
296
|
-
)
|
|
304
|
+
fireEvent.press( screen.getByLabelText( 'Link' ) );
|
|
305
|
+
fireEvent.press(
|
|
306
|
+
screen.getByLabelText( 'Link to, Search or type URL' )
|
|
297
307
|
);
|
|
298
|
-
|
|
299
|
-
screen.getByPlaceholderText( 'Search or type URL' )
|
|
300
|
-
'wordpress.org'
|
|
308
|
+
const typeURLInput = await waitFor( () =>
|
|
309
|
+
screen.getByPlaceholderText( 'Search or type URL' )
|
|
301
310
|
);
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
311
|
+
fireEvent.changeText( typeURLInput, 'wordpress.org' );
|
|
312
|
+
await waitForElementToBeRemoved( () =>
|
|
313
|
+
screen.getByTestId( 'link-picker-loading' )
|
|
314
|
+
);
|
|
315
|
+
// Back navigation from link picker uses `setTimeout`
|
|
316
|
+
await withFakeTimers( () => {
|
|
317
|
+
fireEvent.press( screen.getByLabelText( 'Apply' ) );
|
|
318
|
+
act( () => jest.runOnlyPendingTimers() );
|
|
319
|
+
} );
|
|
306
320
|
|
|
307
321
|
// Assert
|
|
308
322
|
expect( getEditorHtml() ).toMatchInlineSnapshot( `
|
|
@@ -310,8 +324,6 @@ describe( 'Paragraph block', () => {
|
|
|
310
324
|
<p>A <a href="http://wordpress.org">quick</a> brown fox jumps over the lazy dog.</p>
|
|
311
325
|
<!-- /wp:paragraph -->"
|
|
312
326
|
` );
|
|
313
|
-
|
|
314
|
-
jest.useRealTimers();
|
|
315
327
|
} );
|
|
316
328
|
|
|
317
329
|
it( 'should link text with clipboard contents', async () => {
|
|
@@ -402,6 +414,10 @@ describe( 'Paragraph block', () => {
|
|
|
402
414
|
|
|
403
415
|
// Tap one color
|
|
404
416
|
fireEvent.press( screen.getByLabelText( 'Pale pink' ) );
|
|
417
|
+
// TODO(jest-console): Fix the warning and remove the expect below.
|
|
418
|
+
expect( console ).toHaveWarnedWith(
|
|
419
|
+
`Non-serializable values were found in the navigation state. Check:\n\nColor > params.onColorChange (Function)\n\nThis can break usage such as persisting and restoring state. This might happen if you passed non-serializable values such as function, class instances etc. in params. If you need to use components with callbacks in your options, you can use 'navigation.setOptions' instead. See https://reactnavigation.org/docs/troubleshooting#i-get-the-warning-non-serializable-values-were-found-in-the-navigation-state for more details.`
|
|
420
|
+
);
|
|
405
421
|
|
|
406
422
|
// Dismiss the Block Settings modal.
|
|
407
423
|
fireEvent( blockSettingsModal, 'backdropPress' );
|
|
@@ -657,6 +673,10 @@ describe( 'Paragraph block', () => {
|
|
|
657
673
|
);
|
|
658
674
|
fireEvent.press( screen.getByLabelText( 'Text color' ) );
|
|
659
675
|
fireEvent.press( await screen.findByLabelText( 'Tertiary' ) );
|
|
676
|
+
// TODO(jest-console): Fix the warning and remove the expect below.
|
|
677
|
+
expect( console ).toHaveWarnedWith(
|
|
678
|
+
`Non-serializable values were found in the navigation state. Check:\n\ntext-color > Palette > params.onColorChange (Function)\n\nThis can break usage such as persisting and restoring state. This might happen if you passed non-serializable values such as function, class instances etc. in params. If you need to use components with callbacks in your options, you can use 'navigation.setOptions' instead. See https://reactnavigation.org/docs/troubleshooting#i-get-the-warning-non-serializable-values-were-found-in-the-navigation-state for more details.`
|
|
679
|
+
);
|
|
660
680
|
|
|
661
681
|
// Assert
|
|
662
682
|
expect( getEditorHtml() ).toMatchInlineSnapshot( `
|