Skip to content

Commit

Permalink
Interactivity Router: Move ARIA live region and loading bar to the In…
Browse files Browse the repository at this point in the history
…teractivity Router (#58377)

* Expose state related to navigations

* Remove loading bar and aria region from query block

* Implement wp-router-region processor

* Remove aria regions and loading bar logic from query block

* Move loading bar CSS from query to router region processor

* Recover `navigatingTo` variable

* Fix flaky test

* Remove unnecessary PHPUnit checks

* Ensure the callback is executed once

* Update boolean flags and message only if page exists

* Clarify usage of unresolved promise

* More code reordering

* Save current link URL after navigating

* Add topLoadingBar and screenReaderAnnounce options

* Fix url updating after navigating back or forward

* Rename internal `url` variable to `pagePath`

* Always set a string in `state.url`

* Remove confusing comment

* Use internal state instance instead of `wp_interactivity_state`

* Add id to the router animations style tag

* Test the `data-wp-router-region` directive processor

* Rename topLoadingBar option to loadingAnimation

* Update docs for options.loadingAnimation

* Move router-region flag to the WP_Interactivity_API class

* Fix screenReaderAnnouncement name
  • Loading branch information
DAreRodz authored Feb 2, 2024
1 parent 04bb9e8 commit fd68223
Show file tree
Hide file tree
Showing 8 changed files with 334 additions and 202 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,13 @@ class WP_Interactivity_API {
* @var array
*/
private static $directive_processors = array(
'data-wp-interactive' => 'data_wp_interactive_processor',
'data-wp-context' => 'data_wp_context_processor',
'data-wp-bind' => 'data_wp_bind_processor',
'data-wp-class' => 'data_wp_class_processor',
'data-wp-style' => 'data_wp_style_processor',
'data-wp-text' => 'data_wp_text_processor',
'data-wp-interactive' => 'data_wp_interactive_processor',
'data-wp-router-region' => 'data_wp_router_region_processor',
'data-wp-context' => 'data_wp_context_processor',
'data-wp-bind' => 'data_wp_bind_processor',
'data-wp-class' => 'data_wp_class_processor',
'data-wp-style' => 'data_wp_style_processor',
'data-wp-text' => 'data_wp_text_processor',
);

/**
Expand All @@ -49,6 +50,21 @@ class WP_Interactivity_API {
*/
private $config_data = array();

/**
* Flag that indicates whether the `data-wp-router-region` directive has
* been found in the HTML and processed.
*
* The value is saved in a private property of the WP_Interactivity_API
* instance instead of using a static variable inside the processor
* function, which would hold the same value for all instances
* independently of whether they have processed any
* `data-wp-router-region` directive or not.
*
* @since 6.5.0
* @var bool
*/
private $has_processed_router_region = false;

/**
* Gets and/or sets the initial state of an Interactivity API store for a
* given namespace.
Expand Down Expand Up @@ -673,6 +689,88 @@ private function data_wp_text_processor( WP_Interactivity_API_Directives_Process
}
}
}

/**
* Processes the `data-wp-router-region` directive.
*
* It renders in the footer a set of HTML elements to notify users about
* client-side navigations. More concretely, the elements added are 1) a
* top loading bar to visually inform that a navigation is in progress
* and 2) an `aria-live` region for accessible navigation announcements.
*
* @since 6.5.0
*
* @param WP_Interactivity_API_Directives_Processor $p The directives processor instance.
*/
private function data_wp_router_region_processor( WP_Interactivity_API_Directives_Processor $p ) {
if ( ! $p->is_tag_closer() && ! $this->has_processed_router_region ) {
$this->has_processed_router_region = true;

// Initialize the `core/router` store.
$this->state(
'core/router',
array(
'navigation' => array(
'message' => '',
'hasStarted' => false,
'hasFinished' => false,
'texts' => array(
'loading' => __( 'Loading page, please wait.' ),
'loaded' => __( 'Page Loaded.' ),
),
),
)
);

$callback = static function () {
echo <<<HTML
<style id="wp-interactivity-router_animations">
.wp-interactivity-router_loading-bar {
position: fixed;
top: 0;
left: 0;
margin: 0;
padding: 0;
width: 100vw;
max-width: 100vw !important;
height: 4px;
background-color: var(--wp--preset--color--primary, #000);
opacity: 0
}
.wp-interactivity-router_loading-bar.start-animation {
animation: wp-interactivity-router_loading-bar-start-animation 30s cubic-bezier(0.03, 0.5, 0, 1) forwards
}
.wp-interactivity-router_loading-bar.finish-animation {
animation: wp-interactivity-router_loading-bar-finish-animation 300ms ease-in
}
@keyframes wp-interactivity-router_loading-bar-start-animation {
0% { transform: scaleX(0); transform-origin: 0% 0%; opacity: 1 }
100% { transform: scaleX(1); transform-origin: 0% 0%; opacity: 1 }
}
@keyframes wp-interactivity-router_loading-bar-finish-animation {
0% { opacity: 1 }
50% { opacity: 1 }
100% { opacity: 0 }
}
</style>
<div
class="wp-interactivity-router_loading-bar"
data-wp-interactive='{"namespace":"core/router"}'
data-wp-class--start-animation="state.navigation.hasStarted"
data-wp-class--finish-animation="state.navigation.hasFinished"
></div>
<div
class="screen-reader-text"
aria-live="polite"
data-wp-interactive='{"namespace":"core/router"}'
data-wp-text="state.navigation.message"
></div>
HTML;
};
add_action( 'wp_footer', $callback );
}
}
}

}
3 changes: 1 addition & 2 deletions packages/block-library/src/query/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,5 @@
"html": false,
"layout": true
},
"editorStyle": "wp-block-query-editor",
"style": "wp-block-query"
"editorStyle": "wp-block-query-editor"
}
37 changes: 1 addition & 36 deletions packages/block-library/src/query/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,43 +30,8 @@ function render_block_core_query( $attributes, $content, $block ) {
$p->set_attribute( 'data-wp-interactive', '{"namespace":"core/query"}' );
$p->set_attribute( 'data-wp-router-region', 'query-' . $attributes['queryId'] );
$p->set_attribute( 'data-wp-init', 'callbacks.setQueryRef' );
// Use context to send translated strings.
$p->set_attribute(
'data-wp-context',
wp_json_encode(
array(
'loadingText' => __( 'Loading page, please wait.' ),
'loadedText' => __( 'Page Loaded.' ),
),
JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP
)
);
$p->set_attribute( 'data-wp-context', '{}' );
$content = $p->get_updated_html();

// Mark the block as interactive.
$block->block_type->supports['interactivity'] = true;

// Add a div to announce messages using `aria-live`.
$html_tag = 'div';
if ( ! empty( $attributes['tagName'] ) ) {
$html_tag = esc_attr( $attributes['tagName'] );
}
$last_tag_position = strripos( $content, '</' . $html_tag . '>' );
$content = substr_replace(
$content,
'<div
class="screen-reader-text"
aria-live="polite"
data-wp-text="context.message"
></div>
<div
class="wp-block-query__enhanced-pagination-animation"
data-wp-class--start-animation="state.startAnimation"
data-wp-class--finish-animation="state.finishAnimation"
></div>',
$last_tag_position,
0
);
}
}

Expand Down
52 changes: 0 additions & 52 deletions packages/block-library/src/query/style.scss

This file was deleted.

26 changes: 0 additions & 26 deletions packages/block-library/src/query/view.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,6 @@ const isValidEvent = ( event ) =>
! event.defaultPrevented;

store( 'core/query', {
state: {
get startAnimation() {
return getContext().animation === 'start';
},
get finishAnimation() {
return getContext().animation === 'finish';
},
},
actions: {
*navigate( event ) {
const ctx = getContext();
Expand All @@ -37,28 +29,10 @@ store( 'core/query', {
if ( isValidLink( ref ) && isValidEvent( event ) && ! isDisabled ) {
event.preventDefault();

// Don't announce the navigation immediately, wait 400 ms.
const timeout = setTimeout( () => {
ctx.message = ctx.loadingText;
ctx.animation = 'start';
}, 400 );

const { actions } = yield import(
'@wordpress/interactivity-router'
);
yield actions.navigate( ref.href );

// Dismiss loading message if it hasn't been added yet.
clearTimeout( timeout );

// Announce that the page has been loaded. If the message is the
// same, we use a no-break space similar to the @wordpress/a11y
// package: https://github.com/WordPress/gutenberg/blob/c395242b8e6ee20f8b06c199e4fc2920d7018af1/packages/a11y/src/filter-message.js#L20-L26
ctx.message =
ctx.loadedText +
( ctx.message === ctx.loadedText ? '\u00A0' : '' );

ctx.animation = 'finish';
ctx.url = ref.href;

// Focus the first anchor of the Query block.
Expand Down
Loading

1 comment on commit fd68223

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Flaky tests detected in fd68223.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/7758713792
📝 Reported issues:

Please sign in to comment.