@primer/react
Version:
An implementation of GitHub's Primer Design System using React
161 lines (160 loc) • 4.34 kB
JavaScript
import { useEffectOnce } from "../internal/hooks/useEffectOnce.js";
import { useEffectCallback } from "../internal/hooks/useEffectCallback.js";
import { c } from "react-compiler-runtime";
import { jsx } from "react/jsx-runtime";
import { useEffect, useRef } from "react";
import { announceFromElement } from "@primer/live-region-element";
//#region src/live-region/Announce.tsx
/**
* `Announce` is a component that will announce the text content of the
* `children` passed in to screen readers using the given politeness level. It
* will also announce any changes to the text content of `children`
*/
function Announce(props) {
const $ = c(24);
let children;
let delayMs;
let rest;
let t0;
let t1;
let t2;
let t3;
if ($[0] !== props) {
({as: t0, announceOnShow: t1, children, delayMs, hidden: t2, politeness: t3, ...rest} = props);
$[0] = props;
$[1] = children;
$[2] = delayMs;
$[3] = rest;
$[4] = t0;
$[5] = t1;
$[6] = t2;
$[7] = t3;
} else {
children = $[1];
delayMs = $[2];
rest = $[3];
t0 = $[4];
t1 = $[5];
t2 = $[6];
t3 = $[7];
}
const BaseComponent = t0 === void 0 ? "div" : t0;
const announceOnShow = t1 === void 0 ? true : t1;
const hidden = t2 === void 0 ? false : t2;
const politeness = t3 === void 0 ? "polite" : t3;
const ref = useRef(null);
const previousAnnouncementText = useRef(null);
const savedAnnouncement = useRef(null);
let t4;
if ($[8] !== delayMs || $[9] !== hidden || $[10] !== politeness) {
t4 = () => {
var _savedAnnouncement$cu;
const { current: element } = ref;
if (!element) return;
if (hidden) return;
const textContent = getTextContent(element);
if (!textContent) return;
if (textContent === previousAnnouncementText.current) return;
if (!isVisible(element)) return;
(_savedAnnouncement$cu = savedAnnouncement.current) === null || _savedAnnouncement$cu === void 0 || _savedAnnouncement$cu.cancel();
savedAnnouncement.current = announceFromElement(element, politeness === "assertive" ? { politeness } : {
politeness,
delayMs
});
previousAnnouncementText.current = textContent;
};
$[8] = delayMs;
$[9] = hidden;
$[10] = politeness;
$[11] = t4;
} else t4 = $[11];
const announce = useEffectCallback(t4);
let t5;
if ($[12] !== announce || $[13] !== announceOnShow) {
t5 = () => {
if (announceOnShow) announce();
};
$[12] = announce;
$[13] = announceOnShow;
$[14] = t5;
} else t5 = $[14];
useEffectOnce(t5);
let t6;
let t7;
if ($[15] !== announce) {
t6 = () => {
const { current: container } = ref;
if (container === null) return;
const observer = new MutationObserver(() => {
announce();
});
observer.observe(container, {
subtree: true,
childList: true,
characterData: true
});
return () => {
observer.disconnect();
};
};
t7 = [announce];
$[15] = announce;
$[16] = t6;
$[17] = t7;
} else {
t6 = $[16];
t7 = $[17];
}
useEffect(t6, t7);
let t8;
let t9;
if ($[18] === Symbol.for("react.memo_cache_sentinel")) {
t8 = () => () => {
if (savedAnnouncement.current !== null) {
savedAnnouncement.current.cancel();
savedAnnouncement.current = null;
}
};
t9 = [];
$[18] = t8;
$[19] = t9;
} else {
t8 = $[18];
t9 = $[19];
}
useEffect(t8, t9);
let t10;
if ($[20] !== BaseComponent || $[21] !== children || $[22] !== rest) {
t10 = /*#__PURE__*/ jsx(BaseComponent, {
...rest,
ref,
children
});
$[20] = BaseComponent;
$[21] = children;
$[22] = rest;
$[23] = t10;
} else t10 = $[23];
return t10;
}
function getTextContent(element) {
let value = "";
if (element.hasAttribute("aria-label")) value = element.getAttribute("aria-label");
else if (element.textContent) value = element.textContent;
return value ? value.trim() : "";
}
/**
* Determine if an element is visible (not hidden via `display: none` or
* `visibility: hidden`). Prefers the native `checkVisibility()` API when
* available and falls back to `getComputedStyle` for older browsers.
*/
function isVisible(element) {
if (typeof element.checkVisibility === "function") return element.checkVisibility({
visibilityProperty: true,
checkVisibilityCSS: true
});
const style = window.getComputedStyle(element);
return style.display !== "none" && style.visibility !== "hidden";
}
//#endregion
export { Announce };