diff --git a/wp-includes/assets/script-modules-packages.min.php b/wp-includes/assets/script-modules-packages.min.php index 204c67f1be..e3c7915456 100644 --- a/wp-includes/assets/script-modules-packages.min.php +++ b/wp-includes/assets/script-modules-packages.min.php @@ -1 +1 @@ - array('dependencies' => array(), 'version' => '2d6d1fdbcb3fda39c768', 'type' => 'module'), 'interactivity/debug.min.js' => array('dependencies' => array(), 'version' => '1ccc67b05c275e51a8f8', 'type' => 'module'), 'interactivity-router/index.min.js' => array('dependencies' => array('@wordpress/interactivity'), 'version' => '64645ef3cd2d32860d7d', 'type' => 'module'), 'block-library/file/view.min.js' => array('dependencies' => array('@wordpress/interactivity'), 'version' => 'fdc2f6842e015af83140', 'type' => 'module'), 'block-library/image/view.min.js' => array('dependencies' => array('@wordpress/interactivity'), 'version' => 'acfec7b3c0be4a859b31', 'type' => 'module'), 'block-library/navigation/view.min.js' => array('dependencies' => array('@wordpress/interactivity'), 'version' => '8ff192874fc8910a284c', 'type' => 'module'), 'block-library/query/view.min.js' => array('dependencies' => array('@wordpress/interactivity', array('id' => '@wordpress/interactivity-router', 'import' => 'dynamic')), 'version' => 'f4c91c89fa5271f3dad9', 'type' => 'module'), 'block-library/search/view.min.js' => array('dependencies' => array('@wordpress/interactivity'), 'version' => '2a73400a693958f604de', 'type' => 'module')); + array('dependencies' => array(), 'version' => '2d6d1fdbcb3fda39c768', 'type' => 'module'), 'interactivity/debug.min.js' => array('dependencies' => array(), 'version' => '1ccc67b05c275e51a8f8', 'type' => 'module'), 'interactivity-router/index.min.js' => array('dependencies' => array('@wordpress/interactivity'), 'version' => '64645ef3cd2d32860d7d', 'type' => 'module'), 'a11y/index.min.js' => array('dependencies' => array(), 'version' => 'b7d06936b8bc23cff2ad', 'type' => 'module'), 'block-library/file/view.min.js' => array('dependencies' => array('@wordpress/interactivity'), 'version' => 'fdc2f6842e015af83140', 'type' => 'module'), 'block-library/image/view.min.js' => array('dependencies' => array('@wordpress/interactivity'), 'version' => 'acfec7b3c0be4a859b31', 'type' => 'module'), 'block-library/navigation/view.min.js' => array('dependencies' => array('@wordpress/interactivity'), 'version' => '8ff192874fc8910a284c', 'type' => 'module'), 'block-library/query/view.min.js' => array('dependencies' => array('@wordpress/interactivity', array('id' => '@wordpress/interactivity-router', 'import' => 'dynamic')), 'version' => 'f4c91c89fa5271f3dad9', 'type' => 'module'), 'block-library/search/view.min.js' => array('dependencies' => array('@wordpress/interactivity'), 'version' => '2a73400a693958f604de', 'type' => 'module')); diff --git a/wp-includes/assets/script-modules-packages.php b/wp-includes/assets/script-modules-packages.php index f2bdb51e67..0df72865e8 100644 --- a/wp-includes/assets/script-modules-packages.php +++ b/wp-includes/assets/script-modules-packages.php @@ -1 +1 @@ - array('dependencies' => array(), 'version' => 'ff86b5988014bd364de8', 'type' => 'module'), 'interactivity/debug.js' => array('dependencies' => array(), 'version' => 'd05372e68bd7a4cb0676', 'type' => 'module'), 'interactivity-router/index.js' => array('dependencies' => array('@wordpress/interactivity'), 'version' => 'd76e562ff4609c2ae7fc', 'type' => 'module'), 'block-library/file/view.js' => array('dependencies' => array('@wordpress/interactivity'), 'version' => 'b0cd471b6fde34702d88', 'type' => 'module'), 'block-library/image/view.js' => array('dependencies' => array('@wordpress/interactivity'), 'version' => 'e1ce544dd878f3a09f70', 'type' => 'module'), 'block-library/navigation/view.js' => array('dependencies' => array('@wordpress/interactivity'), 'version' => '9510985aedc1f8e088f3', 'type' => 'module'), 'block-library/query/view.js' => array('dependencies' => array('@wordpress/interactivity', array('id' => '@wordpress/interactivity-router', 'import' => 'dynamic')), 'version' => '8e6f28f734f3c306b648', 'type' => 'module'), 'block-library/search/view.js' => array('dependencies' => array('@wordpress/interactivity'), 'version' => 'acdb7febda1392ad28de', 'type' => 'module')); + array('dependencies' => array(), 'version' => 'ff86b5988014bd364de8', 'type' => 'module'), 'interactivity/debug.js' => array('dependencies' => array(), 'version' => 'd05372e68bd7a4cb0676', 'type' => 'module'), 'interactivity-router/index.js' => array('dependencies' => array('@wordpress/interactivity'), 'version' => 'd76e562ff4609c2ae7fc', 'type' => 'module'), 'a11y/index.js' => array('dependencies' => array(), 'version' => 'b3a7f46c0ef4f3484886', 'type' => 'module'), 'block-library/file/view.js' => array('dependencies' => array('@wordpress/interactivity'), 'version' => 'b0cd471b6fde34702d88', 'type' => 'module'), 'block-library/image/view.js' => array('dependencies' => array('@wordpress/interactivity'), 'version' => 'e1ce544dd878f3a09f70', 'type' => 'module'), 'block-library/navigation/view.js' => array('dependencies' => array('@wordpress/interactivity'), 'version' => '9510985aedc1f8e088f3', 'type' => 'module'), 'block-library/query/view.js' => array('dependencies' => array('@wordpress/interactivity', array('id' => '@wordpress/interactivity-router', 'import' => 'dynamic')), 'version' => '8e6f28f734f3c306b648', 'type' => 'module'), 'block-library/search/view.js' => array('dependencies' => array('@wordpress/interactivity'), 'version' => 'acdb7febda1392ad28de', 'type' => 'module')); diff --git a/wp-includes/class-wp-script-modules.php b/wp-includes/class-wp-script-modules.php index 2f2cf967f4..384bf9ef2f 100644 --- a/wp-includes/class-wp-script-modules.php +++ b/wp-includes/class-wp-script-modules.php @@ -30,6 +30,17 @@ class WP_Script_Modules { */ private $enqueued_before_registered = array(); + /** + * Tracks whether the @wordpress/a11y script module is available. + * + * Some additional HTML is required on the page for the module to work. Track + * whether it's available to print at the appropriate time. + * + * @since 6.7.0 + * @var bool + */ + private $a11y_available = false; + /** * Registers the script module if no script module with that script module * identifier has already been registered. @@ -185,6 +196,8 @@ class WP_Script_Modules { add_action( 'wp_footer', array( $this, 'print_script_module_data' ) ); add_action( 'admin_print_footer_scripts', array( $this, 'print_script_module_data' ) ); + add_action( 'wp_footer', array( $this, 'print_a11y_script_module_html' ), 20 ); + add_action( 'admin_print_footer_scripts', array( $this, 'print_a11y_script_module_html' ), 20 ); } /** @@ -367,9 +380,15 @@ class WP_Script_Modules { public function print_script_module_data(): void { $modules = array(); foreach ( array_keys( $this->get_marked_for_enqueue() ) as $id ) { + if ( '@wordpress/a11y' === $id ) { + $this->a11y_available = true; + } $modules[ $id ] = true; } foreach ( array_keys( $this->get_import_map()['imports'] ) as $id ) { + if ( '@wordpress/a11y' === $id ) { + $this->a11y_available = true; + } $modules[ $id ] = true; } @@ -465,4 +484,20 @@ class WP_Script_Modules { } } } + + /** + * @access private This is only intended to be called by the registered actions. + * + * @since 6.7.0 + */ + public function print_a11y_script_module_html() { + if ( ! $this->a11y_available ) { + return; + } + echo '
'; + } } diff --git a/wp-includes/js/dist/script-modules/a11y/index.js b/wp-includes/js/dist/script-modules/a11y/index.js new file mode 100644 index 0000000000..f892b62815 --- /dev/null +++ b/wp-includes/js/dist/script-modules/a11y/index.js @@ -0,0 +1,144 @@ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/define property getters */ +/******/ (() => { +/******/ // define getter functions for harmony exports +/******/ __webpack_require__.d = (exports, definition) => { +/******/ for(var key in definition) { +/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { +/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); +/******/ } +/******/ } +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; + +// EXPORTS +__webpack_require__.d(__webpack_exports__, { + m: () => (/* binding */ setup), + L: () => (/* reexport */ speak) +}); + +;// CONCATENATED MODULE: ./node_modules/@wordpress/a11y/build-module/shared/clear.js +/** + * Clears the a11y-speak-region elements and hides the explanatory text. + */ +function clear() { + const regions = document.getElementsByClassName('a11y-speak-region'); + const introText = document.getElementById('a11y-speak-intro-text'); + for (let i = 0; i < regions.length; i++) { + regions[i].textContent = ''; + } + + // Make sure the explanatory text is hidden from assistive technologies. + if (introText) { + introText.setAttribute('hidden', 'hidden'); + } +} + +;// CONCATENATED MODULE: ./node_modules/@wordpress/a11y/build-module/shared/filter-message.js +let previousMessage = ''; + +/** + * Filter the message to be announced to the screenreader. + * + * @param {string} message The message to be announced. + * + * @return {string} The filtered message. + */ +function filterMessage(message) { + /* + * Strip HTML tags (if any) from the message string. Ideally, messages should + * be simple strings, carefully crafted for specific use with A11ySpeak. + * When re-using already existing strings this will ensure simple HTML to be + * stripped out and replaced with a space. Browsers will collapse multiple + * spaces natively. + */ + message = message.replace(/<[^<>]+>/g, ' '); + + /* + * Safari + VoiceOver don't announce repeated, identical strings. We use + * a `no-break space` to force them to think identical strings are different. + */ + if (previousMessage === message) { + message += '\u00A0'; + } + previousMessage = message; + return message; +} + +;// CONCATENATED MODULE: ./node_modules/@wordpress/a11y/build-module/shared/index.js +/** + * Internal dependencies + */ + + + +/** + * Allows you to easily announce dynamic interface updates to screen readers using ARIA live regions. + * This module is inspired by the `speak` function in `wp-a11y.js`. + * + * @param {string} message The message to be announced by assistive technologies. + * @param {'polite'|'assertive'} [ariaLive] The politeness level for aria-live; default: 'polite'. + * + * @example + * ```js + * import { speak } from '@wordpress/a11y'; + * + * // For polite messages that shouldn't interrupt what screen readers are currently announcing. + * speak( 'The message you want to send to the ARIA live region' ); + * + * // For assertive messages that should interrupt what screen readers are currently announcing. + * speak( 'The message you want to send to the ARIA live region', 'assertive' ); + * ``` + */ +function speak(message, ariaLive) { + /* + * Clear previous messages to allow repeated strings being read out and hide + * the explanatory text from assistive technologies. + */ + clear(); + message = filterMessage(message); + const introText = document.getElementById('a11y-speak-intro-text'); + const containerAssertive = document.getElementById('a11y-speak-assertive'); + const containerPolite = document.getElementById('a11y-speak-polite'); + if (containerAssertive && ariaLive === 'assertive') { + containerAssertive.textContent = message; + } else if (containerPolite) { + containerPolite.textContent = message; + } + + /* + * Make the explanatory text available to assistive technologies by removing + * the 'hidden' HTML attribute. + */ + if (introText) { + introText.removeAttribute('hidden'); + } +} + +;// CONCATENATED MODULE: ./node_modules/@wordpress/a11y/build-module/module/index.js +/** + * Internal dependencies + */ + + +/** + * This no-op function is exported to provide compatibility with the `wp-a11y` Script. + * + * Filters should inject the relevant HTML on page load instead of requiring setup. + */ +const setup = () => {}; + +var __webpack_exports__setup = __webpack_exports__.m; +var __webpack_exports__speak = __webpack_exports__.L; +export { __webpack_exports__setup as setup, __webpack_exports__speak as speak }; diff --git a/wp-includes/js/dist/script-modules/a11y/index.min.js b/wp-includes/js/dist/script-modules/a11y/index.min.js new file mode 100644 index 0000000000..fdc6a437b6 --- /dev/null +++ b/wp-includes/js/dist/script-modules/a11y/index.min.js @@ -0,0 +1 @@ +var e={d:(t,n)=>{for(var o in n)e.o(n,o)&&!e.o(t,o)&&Object.defineProperty(t,o,{enumerable:!0,get:n[o]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)},t={};e.d(t,{m:()=>a,L:()=>o});let n="";function o(e,t){!function(){const e=document.getElementsByClassName("a11y-speak-region"),t=document.getElementById("a11y-speak-intro-text");for(let t=0;t