route-announcer.js 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.default = exports.RouteAnnouncer = void 0;
  6. var _interop_require_default = require("@swc/helpers/lib/_interop_require_default.js").default;
  7. var _react = _interop_require_default(require("react"));
  8. var _router = require("./router");
  9. const nextjsRouteAnnouncerStyles = {
  10. border: 0,
  11. clip: 'rect(0 0 0 0)',
  12. height: '1px',
  13. margin: '-1px',
  14. overflow: 'hidden',
  15. padding: 0,
  16. position: 'absolute',
  17. width: '1px',
  18. // https://medium.com/@jessebeach/beware-smushed-off-screen-accessible-text-5952a4c2cbfe
  19. whiteSpace: 'nowrap',
  20. wordWrap: 'normal'
  21. };
  22. const RouteAnnouncer = ()=>{
  23. const { asPath } = (0, _router).useRouter();
  24. const [routeAnnouncement, setRouteAnnouncement] = _react.default.useState('');
  25. // Only announce the path change, but not for the first load because screen
  26. // reader will do that automatically.
  27. const previouslyLoadedPath = _react.default.useRef(asPath);
  28. // Every time the path changes, announce the new page’s title following this
  29. // priority: first the document title (from head), otherwise the first h1, or
  30. // if none of these exist, then the pathname from the URL. This methodology is
  31. // inspired by Marcy Sutton’s accessible client routing user testing. More
  32. // information can be found here:
  33. // https://www.gatsbyjs.com/blog/2019-07-11-user-testing-accessible-client-routing/
  34. _react.default.useEffect(()=>{
  35. // If the path hasn't change, we do nothing.
  36. if (previouslyLoadedPath.current === asPath) return;
  37. previouslyLoadedPath.current = asPath;
  38. if (document.title) {
  39. setRouteAnnouncement(document.title);
  40. } else {
  41. const pageHeader = document.querySelector('h1');
  42. var ref;
  43. const content = (ref = pageHeader == null ? void 0 : pageHeader.innerText) != null ? ref : pageHeader == null ? void 0 : pageHeader.textContent;
  44. setRouteAnnouncement(content || asPath);
  45. }
  46. }, // TODO: switch to pathname + query object of dynamic route requirements
  47. [
  48. asPath
  49. ]);
  50. return /*#__PURE__*/ _react.default.createElement("p", {
  51. "aria-live": "assertive" // Make the announcement immediately.
  52. ,
  53. id: "__next-route-announcer__",
  54. role: "alert",
  55. style: nextjsRouteAnnouncerStyles
  56. }, routeAnnouncement);
  57. };
  58. exports.RouteAnnouncer = RouteAnnouncer;
  59. var _default = RouteAnnouncer;
  60. exports.default = _default;
  61. if ((typeof exports.default === 'function' || (typeof exports.default === 'object' && exports.default !== null)) && typeof exports.default.__esModule === 'undefined') {
  62. Object.defineProperty(exports.default, '__esModule', { value: true });
  63. Object.assign(exports.default, exports);
  64. module.exports = exports.default;
  65. }
  66. //# sourceMappingURL=route-announcer.js.map