@huin-core/react-announce 1.0.2 → 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/index.d.mts +68 -0
- package/dist/index.d.ts +68 -0
- package/dist/index.js +139 -0
- package/dist/index.js.map +7 -0
- package/dist/index.mjs +107 -0
- package/dist/index.mjs.map +7 -0
- package/package.json +1 -1
package/dist/index.d.mts
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
import * as React from 'react';
|
2
|
+
import { Primitive } from '@huin-core/react-primitive';
|
3
|
+
|
4
|
+
type RegionType = 'polite' | 'assertive' | 'off';
|
5
|
+
type RegionRole = 'status' | 'alert' | 'log' | 'none';
|
6
|
+
type PrimitiveDivProps = React.ComponentPropsWithoutRef<typeof Primitive.div>;
|
7
|
+
interface AnnounceProps extends PrimitiveDivProps {
|
8
|
+
/**
|
9
|
+
* Mirrors the `aria-atomic` DOM attribute for live regions. It is an optional attribute that
|
10
|
+
* indicates whether assistive technologies will present all, or only parts of, the changed region
|
11
|
+
* based on the change notifications defined by the `aria-relevant` attribute.
|
12
|
+
*
|
13
|
+
* @see WAI-ARIA https://www.w3.org/TR/wai-aria-1.2/#aria-atomic
|
14
|
+
* @see Demo http://pauljadam.com/demos/aria-atomic-relevant.html
|
15
|
+
*/
|
16
|
+
'aria-atomic'?: boolean;
|
17
|
+
/**
|
18
|
+
* Mirrors the `aria-relevant` DOM attribute for live regions. It is an optional attribute used to
|
19
|
+
* describe what types of changes have occurred to the region, and which changes are relevant and
|
20
|
+
* should be announced. Any change that is not relevant acts in the same manner it would if the
|
21
|
+
* `aria-live` attribute were set to off.
|
22
|
+
*
|
23
|
+
* Unfortunately, `aria-relevant` doesn't behave as expected across all device/screen reader
|
24
|
+
* combinations. It's important to test its implementation before relying on it to work for your
|
25
|
+
* users. The attribute is omitted by default.
|
26
|
+
*
|
27
|
+
* @see WAI-ARIA https://www.w3.org/TR/wai-aria-1.2/#aria-relevant
|
28
|
+
* @see MDN https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_aria-relevant_attribute
|
29
|
+
* @see Opinion https://medium.com/dev-channel/why-authors-should-avoid-aria-relevant-5d3164fab1e3
|
30
|
+
* @see Demo http://pauljadam.com/demos/aria-atomic-relevant.html
|
31
|
+
*/
|
32
|
+
'aria-relevant'?: PrimitiveDivProps['aria-relevant'];
|
33
|
+
/**
|
34
|
+
* React children of your component. Children can be mirrored directly or modified to optimize for
|
35
|
+
* screen reader user experience.
|
36
|
+
*/
|
37
|
+
children: React.ReactNode;
|
38
|
+
/**
|
39
|
+
* An optional unique identifier for the live region.
|
40
|
+
*
|
41
|
+
* By default, `Announce` components create, at most, two unique `aria-live` regions in the
|
42
|
+
* document (one for all `polite` notifications, one for all `assertive` notifications). In some
|
43
|
+
* cases you may wish to append additional `aria-live` regions for distinct purposes (for example,
|
44
|
+
* simple status updates may need to be separated from a stack of toast-style notifications). By
|
45
|
+
* passing an id, you indicate that any content rendered by components with the same identifier
|
46
|
+
* should be mirrored in a separate `aria-live` region.
|
47
|
+
*/
|
48
|
+
regionIdentifier?: string;
|
49
|
+
/**
|
50
|
+
* Mirrors the `role` DOM attribute. This is optional and may be useful as an override in some
|
51
|
+
* cases. By default, the role is determined by the `type` prop.
|
52
|
+
*
|
53
|
+
* @see MDN https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Live_Regions#Preferring_specialized_live_region_roles
|
54
|
+
*/
|
55
|
+
role?: RegionRole;
|
56
|
+
/**
|
57
|
+
* Mirrors the `aria-live` DOM attribute. The `aria-live=POLITENESS_SETTING` is used to set the
|
58
|
+
* priority with which screen reader should treat updates to live regions. Its possible settings
|
59
|
+
* are: off, polite or assertive. Defaults to `polite`.
|
60
|
+
*
|
61
|
+
* @see MDN https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Live_Regions
|
62
|
+
*/
|
63
|
+
type?: RegionType;
|
64
|
+
}
|
65
|
+
declare const Announce: React.ForwardRefExoticComponent<AnnounceProps & React.RefAttributes<HTMLDivElement>>;
|
66
|
+
declare const Root: React.ForwardRefExoticComponent<AnnounceProps & React.RefAttributes<HTMLDivElement>>;
|
67
|
+
|
68
|
+
export { Announce, type AnnounceProps, Root };
|
package/dist/index.d.ts
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
import * as React from 'react';
|
2
|
+
import { Primitive } from '@huin-core/react-primitive';
|
3
|
+
|
4
|
+
type RegionType = 'polite' | 'assertive' | 'off';
|
5
|
+
type RegionRole = 'status' | 'alert' | 'log' | 'none';
|
6
|
+
type PrimitiveDivProps = React.ComponentPropsWithoutRef<typeof Primitive.div>;
|
7
|
+
interface AnnounceProps extends PrimitiveDivProps {
|
8
|
+
/**
|
9
|
+
* Mirrors the `aria-atomic` DOM attribute for live regions. It is an optional attribute that
|
10
|
+
* indicates whether assistive technologies will present all, or only parts of, the changed region
|
11
|
+
* based on the change notifications defined by the `aria-relevant` attribute.
|
12
|
+
*
|
13
|
+
* @see WAI-ARIA https://www.w3.org/TR/wai-aria-1.2/#aria-atomic
|
14
|
+
* @see Demo http://pauljadam.com/demos/aria-atomic-relevant.html
|
15
|
+
*/
|
16
|
+
'aria-atomic'?: boolean;
|
17
|
+
/**
|
18
|
+
* Mirrors the `aria-relevant` DOM attribute for live regions. It is an optional attribute used to
|
19
|
+
* describe what types of changes have occurred to the region, and which changes are relevant and
|
20
|
+
* should be announced. Any change that is not relevant acts in the same manner it would if the
|
21
|
+
* `aria-live` attribute were set to off.
|
22
|
+
*
|
23
|
+
* Unfortunately, `aria-relevant` doesn't behave as expected across all device/screen reader
|
24
|
+
* combinations. It's important to test its implementation before relying on it to work for your
|
25
|
+
* users. The attribute is omitted by default.
|
26
|
+
*
|
27
|
+
* @see WAI-ARIA https://www.w3.org/TR/wai-aria-1.2/#aria-relevant
|
28
|
+
* @see MDN https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_aria-relevant_attribute
|
29
|
+
* @see Opinion https://medium.com/dev-channel/why-authors-should-avoid-aria-relevant-5d3164fab1e3
|
30
|
+
* @see Demo http://pauljadam.com/demos/aria-atomic-relevant.html
|
31
|
+
*/
|
32
|
+
'aria-relevant'?: PrimitiveDivProps['aria-relevant'];
|
33
|
+
/**
|
34
|
+
* React children of your component. Children can be mirrored directly or modified to optimize for
|
35
|
+
* screen reader user experience.
|
36
|
+
*/
|
37
|
+
children: React.ReactNode;
|
38
|
+
/**
|
39
|
+
* An optional unique identifier for the live region.
|
40
|
+
*
|
41
|
+
* By default, `Announce` components create, at most, two unique `aria-live` regions in the
|
42
|
+
* document (one for all `polite` notifications, one for all `assertive` notifications). In some
|
43
|
+
* cases you may wish to append additional `aria-live` regions for distinct purposes (for example,
|
44
|
+
* simple status updates may need to be separated from a stack of toast-style notifications). By
|
45
|
+
* passing an id, you indicate that any content rendered by components with the same identifier
|
46
|
+
* should be mirrored in a separate `aria-live` region.
|
47
|
+
*/
|
48
|
+
regionIdentifier?: string;
|
49
|
+
/**
|
50
|
+
* Mirrors the `role` DOM attribute. This is optional and may be useful as an override in some
|
51
|
+
* cases. By default, the role is determined by the `type` prop.
|
52
|
+
*
|
53
|
+
* @see MDN https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Live_Regions#Preferring_specialized_live_region_roles
|
54
|
+
*/
|
55
|
+
role?: RegionRole;
|
56
|
+
/**
|
57
|
+
* Mirrors the `aria-live` DOM attribute. The `aria-live=POLITENESS_SETTING` is used to set the
|
58
|
+
* priority with which screen reader should treat updates to live regions. Its possible settings
|
59
|
+
* are: off, polite or assertive. Defaults to `polite`.
|
60
|
+
*
|
61
|
+
* @see MDN https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Live_Regions
|
62
|
+
*/
|
63
|
+
type?: RegionType;
|
64
|
+
}
|
65
|
+
declare const Announce: React.ForwardRefExoticComponent<AnnounceProps & React.RefAttributes<HTMLDivElement>>;
|
66
|
+
declare const Root: React.ForwardRefExoticComponent<AnnounceProps & React.RefAttributes<HTMLDivElement>>;
|
67
|
+
|
68
|
+
export { Announce, type AnnounceProps, Root };
|
package/dist/index.js
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
"use strict";
|
2
|
+
"use client";
|
3
|
+
var __create = Object.create;
|
4
|
+
var __defProp = Object.defineProperty;
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
9
|
+
var __export = (target, all) => {
|
10
|
+
for (var name in all)
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
12
|
+
};
|
13
|
+
var __copyProps = (to, from, except, desc) => {
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
15
|
+
for (let key of __getOwnPropNames(from))
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
17
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
18
|
+
}
|
19
|
+
return to;
|
20
|
+
};
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
27
|
+
mod
|
28
|
+
));
|
29
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
30
|
+
|
31
|
+
// packages/react/announce/src/index.ts
|
32
|
+
var src_exports = {};
|
33
|
+
__export(src_exports, {
|
34
|
+
Announce: () => Announce,
|
35
|
+
Root: () => Root
|
36
|
+
});
|
37
|
+
module.exports = __toCommonJS(src_exports);
|
38
|
+
|
39
|
+
// packages/react/announce/src/Announce.tsx
|
40
|
+
var React = __toESM(require("react"));
|
41
|
+
var import_react_dom = __toESM(require("react-dom"));
|
42
|
+
var import_react_compose_refs = require("@huin-core/react-compose-refs");
|
43
|
+
var import_react_primitive = require("@huin-core/react-primitive");
|
44
|
+
var import_react_use_layout_effect = require("@huin-core/react-use-layout-effect");
|
45
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
46
|
+
var ROLES = {
|
47
|
+
polite: "status",
|
48
|
+
assertive: "alert",
|
49
|
+
off: "none"
|
50
|
+
};
|
51
|
+
var listenerMap = /* @__PURE__ */ new Map();
|
52
|
+
var NAME = "Announce";
|
53
|
+
var Announce = React.forwardRef((props, forwardedRef) => {
|
54
|
+
const {
|
55
|
+
"aria-relevant": ariaRelevant,
|
56
|
+
children,
|
57
|
+
type = "polite",
|
58
|
+
role = ROLES[type],
|
59
|
+
regionIdentifier,
|
60
|
+
...regionProps
|
61
|
+
} = props;
|
62
|
+
const ariaAtomic = ["true", true].includes(regionProps["aria-atomic"]);
|
63
|
+
const ownerDocumentRef = React.useRef(document);
|
64
|
+
const setOwnerDocumentFromRef = React.useCallback((node) => {
|
65
|
+
if (node) {
|
66
|
+
ownerDocumentRef.current = node.ownerDocument;
|
67
|
+
}
|
68
|
+
}, []);
|
69
|
+
const ownRef = React.useRef(null);
|
70
|
+
const ref = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, ownRef, setOwnerDocumentFromRef);
|
71
|
+
const [region, setRegion] = React.useState();
|
72
|
+
const relevant = ariaRelevant ? Array.isArray(ariaRelevant) ? ariaRelevant.join(" ") : ariaRelevant : void 0;
|
73
|
+
const getLiveRegionElement = React.useCallback(() => {
|
74
|
+
const ownerDocument = ownerDocumentRef.current;
|
75
|
+
const regionConfig = { type, role, relevant, id: regionIdentifier, atomic: ariaAtomic };
|
76
|
+
const regionSelector = buildSelector(regionConfig);
|
77
|
+
const element = ownerDocument.querySelector(regionSelector);
|
78
|
+
return element || buildLiveRegionElement(ownerDocument, regionConfig);
|
79
|
+
}, [ariaAtomic, relevant, role, type, regionIdentifier]);
|
80
|
+
(0, import_react_use_layout_effect.useLayoutEffect)(() => {
|
81
|
+
setRegion(getLiveRegionElement());
|
82
|
+
}, [getLiveRegionElement]);
|
83
|
+
React.useEffect(() => {
|
84
|
+
const ownerDocument = ownerDocumentRef.current;
|
85
|
+
function updateAttributesOnVisibilityChange() {
|
86
|
+
regionElement.setAttribute("role", ownerDocument.hidden ? "none" : role);
|
87
|
+
regionElement.setAttribute("aria-live", ownerDocument.hidden ? "off" : type);
|
88
|
+
}
|
89
|
+
const regionElement = getLiveRegionElement();
|
90
|
+
if (!listenerMap.get(regionElement)) {
|
91
|
+
ownerDocument.addEventListener("visibilitychange", updateAttributesOnVisibilityChange);
|
92
|
+
listenerMap.set(regionElement, 1);
|
93
|
+
} else {
|
94
|
+
const announceCount = listenerMap.get(regionElement);
|
95
|
+
listenerMap.set(regionElement, announceCount + 1);
|
96
|
+
}
|
97
|
+
return function() {
|
98
|
+
const announceCount = listenerMap.get(regionElement);
|
99
|
+
listenerMap.set(regionElement, announceCount - 1);
|
100
|
+
if (announceCount === 1) {
|
101
|
+
ownerDocument.removeEventListener("visibilitychange", updateAttributesOnVisibilityChange);
|
102
|
+
}
|
103
|
+
};
|
104
|
+
}, [getLiveRegionElement, role, type]);
|
105
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(React.Fragment, { children: [
|
106
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_primitive.Primitive.div, { ...regionProps, ref, children }),
|
107
|
+
region && import_react_dom.default.createPortal(/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children }), region)
|
108
|
+
] });
|
109
|
+
});
|
110
|
+
Announce.displayName = NAME;
|
111
|
+
function buildLiveRegionElement(ownerDocument, { type, relevant, role, atomic, id }) {
|
112
|
+
const element = ownerDocument.createElement("div");
|
113
|
+
element.setAttribute(getLiveRegionPartDataAttr(id), "");
|
114
|
+
element.setAttribute(
|
115
|
+
"style",
|
116
|
+
"position: absolute; top: -1px; width: 1px; height: 1px; overflow: hidden;"
|
117
|
+
);
|
118
|
+
ownerDocument.body.appendChild(element);
|
119
|
+
element.setAttribute("aria-live", type);
|
120
|
+
element.setAttribute("aria-atomic", String(atomic || false));
|
121
|
+
element.setAttribute("role", role);
|
122
|
+
if (relevant) {
|
123
|
+
element.setAttribute("aria-relevant", relevant);
|
124
|
+
}
|
125
|
+
return element;
|
126
|
+
}
|
127
|
+
function buildSelector({ type, relevant, role, atomic, id }) {
|
128
|
+
return `[${getLiveRegionPartDataAttr(id)}]${[
|
129
|
+
["aria-live", type],
|
130
|
+
["aria-atomic", atomic],
|
131
|
+
["aria-relevant", relevant],
|
132
|
+
["role", role]
|
133
|
+
].filter(([, val]) => !!val).map(([attr, val]) => `[${attr}=${val}]`).join("")}`;
|
134
|
+
}
|
135
|
+
function getLiveRegionPartDataAttr(id) {
|
136
|
+
return "data-huin-core-announce-region" + (id ? `-${id}` : "");
|
137
|
+
}
|
138
|
+
var Root = Announce;
|
139
|
+
//# sourceMappingURL=index.js.map
|
@@ -0,0 +1,7 @@
|
|
1
|
+
{
|
2
|
+
"version": 3,
|
3
|
+
"sources": ["../src/index.ts", "../src/Announce.tsx"],
|
4
|
+
"sourcesContent": ["'use client';\nexport {\n Announce,\n //\n Root,\n} from './Announce';\nexport type { AnnounceProps } from './Announce';\n", "import * as React from 'react';\nimport ReactDOM from 'react-dom';\nimport { useComposedRefs } from '@huin-core/react-compose-refs';\nimport { Primitive } from '@huin-core/react-primitive';\nimport { useLayoutEffect } from '@huin-core/react-use-layout-effect';\n\ntype RegionType = 'polite' | 'assertive' | 'off';\ntype RegionRole = 'status' | 'alert' | 'log' | 'none';\n\nconst ROLES: { [key in RegionType]: RegionRole } = {\n polite: 'status',\n assertive: 'alert',\n off: 'none',\n};\n\nconst listenerMap = new Map<Element, number>();\n\n/* -------------------------------------------------------------------------------------------------\n * Announce\n * -----------------------------------------------------------------------------------------------*/\n\nconst NAME = 'Announce';\n\ntype AnnounceElement = React.ElementRef<typeof Primitive.div>;\ntype PrimitiveDivProps = React.ComponentPropsWithoutRef<typeof Primitive.div>;\ninterface AnnounceProps extends PrimitiveDivProps {\n /**\n * Mirrors the `aria-atomic` DOM attribute for live regions. It is an optional attribute that\n * indicates whether assistive technologies will present all, or only parts of, the changed region\n * based on the change notifications defined by the `aria-relevant` attribute.\n *\n * @see WAI-ARIA https://www.w3.org/TR/wai-aria-1.2/#aria-atomic\n * @see Demo http://pauljadam.com/demos/aria-atomic-relevant.html\n */\n 'aria-atomic'?: boolean;\n /**\n * Mirrors the `aria-relevant` DOM attribute for live regions. It is an optional attribute used to\n * describe what types of changes have occurred to the region, and which changes are relevant and\n * should be announced. Any change that is not relevant acts in the same manner it would if the\n * `aria-live` attribute were set to off.\n *\n * Unfortunately, `aria-relevant` doesn't behave as expected across all device/screen reader\n * combinations. It's important to test its implementation before relying on it to work for your\n * users. The attribute is omitted by default.\n *\n * @see WAI-ARIA https://www.w3.org/TR/wai-aria-1.2/#aria-relevant\n * @see MDN https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_aria-relevant_attribute\n * @see Opinion https://medium.com/dev-channel/why-authors-should-avoid-aria-relevant-5d3164fab1e3\n * @see Demo http://pauljadam.com/demos/aria-atomic-relevant.html\n */\n 'aria-relevant'?: PrimitiveDivProps['aria-relevant'];\n /**\n * React children of your component. Children can be mirrored directly or modified to optimize for\n * screen reader user experience.\n */\n children: React.ReactNode;\n /**\n * An optional unique identifier for the live region.\n *\n * By default, `Announce` components create, at most, two unique `aria-live` regions in the\n * document (one for all `polite` notifications, one for all `assertive` notifications). In some\n * cases you may wish to append additional `aria-live` regions for distinct purposes (for example,\n * simple status updates may need to be separated from a stack of toast-style notifications). By\n * passing an id, you indicate that any content rendered by components with the same identifier\n * should be mirrored in a separate `aria-live` region.\n */\n regionIdentifier?: string;\n /**\n * Mirrors the `role` DOM attribute. This is optional and may be useful as an override in some\n * cases. By default, the role is determined by the `type` prop.\n *\n * @see MDN https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Live_Regions#Preferring_specialized_live_region_roles\n */\n role?: RegionRole;\n /**\n * Mirrors the `aria-live` DOM attribute. The `aria-live=POLITENESS_SETTING` is used to set the\n * priority with which screen reader should treat updates to live regions. Its possible settings\n * are: off, polite or assertive. Defaults to `polite`.\n *\n * @see MDN https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Live_Regions\n */\n type?: RegionType;\n}\n\nconst Announce = React.forwardRef<AnnounceElement, AnnounceProps>((props, forwardedRef) => {\n const {\n 'aria-relevant': ariaRelevant,\n children,\n type = 'polite',\n role = ROLES[type],\n regionIdentifier,\n ...regionProps\n } = props;\n\n const ariaAtomic = ['true', true].includes(regionProps['aria-atomic'] as any);\n\n // The region is appended to the root document node, which is usually the global `document` but in\n // some contexts may be another node. After the Announce element ref is attached, we set the\n // ownerDocumentRef to make sure we have the right root node. We should only need to do this once.\n const ownerDocumentRef = React.useRef(document);\n const setOwnerDocumentFromRef = React.useCallback((node: HTMLDivElement) => {\n if (node) {\n ownerDocumentRef.current = node.ownerDocument;\n }\n }, []);\n const ownRef = React.useRef<HTMLDivElement | null>(null);\n const ref = useComposedRefs(forwardedRef, ownRef, setOwnerDocumentFromRef);\n\n const [region, setRegion] = React.useState<HTMLElement>();\n const relevant = ariaRelevant\n ? Array.isArray(ariaRelevant)\n ? ariaRelevant.join(' ')\n : ariaRelevant\n : undefined;\n\n const getLiveRegionElement = React.useCallback(() => {\n const ownerDocument = ownerDocumentRef.current;\n const regionConfig = { type, role, relevant, id: regionIdentifier, atomic: ariaAtomic };\n const regionSelector = buildSelector(regionConfig);\n const element = ownerDocument.querySelector(regionSelector);\n\n return element || buildLiveRegionElement(ownerDocument, regionConfig);\n }, [ariaAtomic, relevant, role, type, regionIdentifier]);\n\n useLayoutEffect(() => {\n setRegion(getLiveRegionElement() as HTMLElement);\n }, [getLiveRegionElement]);\n\n // In some screen reader/browser combinations, alerts coming from an inactive browser tab may be\n // announced, which is a confusing experience for a user interacting with a completely different\n // page. When the page visibility changes we'll update the `role` and `aria-live` attributes of\n // our region element to prevent that.\n // https://inclusive-components.design/notifications/#restrictingmessagestocontexts\n React.useEffect(() => {\n const ownerDocument = ownerDocumentRef.current;\n function updateAttributesOnVisibilityChange() {\n regionElement.setAttribute('role', ownerDocument.hidden ? 'none' : role);\n regionElement.setAttribute('aria-live', ownerDocument.hidden ? 'off' : type);\n }\n\n // Ok, so this might look a little weird and confusing, but here's what's going on:\n // - We need to hide `aria-live` regions via a global event listener, as noted in the comment\n // above.\n // - We only need one listener per region. Keep in mind that each `Announce` does not\n // necessarily generate a unique live region element.\n // - We track whether or not a listener has already been attached for a given region in a map\n // so we can skip these effects after `Announce` is used again with a shared live region.\n const regionElement = getLiveRegionElement();\n\n if (!listenerMap.get(regionElement)) {\n ownerDocument.addEventListener('visibilitychange', updateAttributesOnVisibilityChange);\n listenerMap.set(regionElement, 1);\n } else {\n const announceCount = listenerMap.get(regionElement)!;\n listenerMap.set(regionElement, announceCount + 1);\n }\n\n return function () {\n const announceCount = listenerMap.get(regionElement)!;\n listenerMap.set(regionElement, announceCount - 1);\n if (announceCount === 1) {\n ownerDocument.removeEventListener('visibilitychange', updateAttributesOnVisibilityChange);\n }\n };\n }, [getLiveRegionElement, role, type]);\n\n return (\n <React.Fragment>\n <Primitive.div {...regionProps} ref={ref}>\n {children}\n </Primitive.div>\n\n {/* portal into live region for screen reader announcements */}\n {region && ReactDOM.createPortal(<div>{children}</div>, region)}\n </React.Fragment>\n );\n});\n\nAnnounce.displayName = NAME;\n\n/* ---------------------------------------------------------------------------------------------- */\n\ntype LiveRegionOptions = {\n type: string;\n relevant?: string;\n role: string;\n atomic?: boolean;\n id?: string;\n};\n\nfunction buildLiveRegionElement(\n ownerDocument: Document,\n { type, relevant, role, atomic, id }: LiveRegionOptions\n) {\n const element = ownerDocument.createElement('div');\n element.setAttribute(getLiveRegionPartDataAttr(id), '');\n element.setAttribute(\n 'style',\n 'position: absolute; top: -1px; width: 1px; height: 1px; overflow: hidden;'\n );\n ownerDocument.body.appendChild(element);\n\n element.setAttribute('aria-live', type);\n element.setAttribute('aria-atomic', String(atomic || false));\n element.setAttribute('role', role);\n if (relevant) {\n element.setAttribute('aria-relevant', relevant);\n }\n\n return element;\n}\n\nfunction buildSelector({ type, relevant, role, atomic, id }: LiveRegionOptions) {\n return `[${getLiveRegionPartDataAttr(id)}]${[\n ['aria-live', type],\n ['aria-atomic', atomic],\n ['aria-relevant', relevant],\n ['role', role],\n ]\n .filter(([, val]) => !!val)\n .map(([attr, val]) => `[${attr}=${val}]`)\n .join('')}`;\n}\n\nfunction getLiveRegionPartDataAttr(id?: string) {\n return 'data-huin-core-announce-region' + (id ? `-${id}` : '');\n}\n\nconst Root = Announce;\n\nexport {\n Announce,\n //\n Root,\n};\nexport type { AnnounceProps };\n"],
|
5
|
+
"mappings": "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",
|
6
|
+
"names": ["ReactDOM"]
|
7
|
+
}
|
package/dist/index.mjs
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
"use client";
|
2
|
+
|
3
|
+
// packages/react/announce/src/Announce.tsx
|
4
|
+
import * as React from "react";
|
5
|
+
import ReactDOM from "react-dom";
|
6
|
+
import { useComposedRefs } from "@huin-core/react-compose-refs";
|
7
|
+
import { Primitive } from "@huin-core/react-primitive";
|
8
|
+
import { useLayoutEffect } from "@huin-core/react-use-layout-effect";
|
9
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
10
|
+
var ROLES = {
|
11
|
+
polite: "status",
|
12
|
+
assertive: "alert",
|
13
|
+
off: "none"
|
14
|
+
};
|
15
|
+
var listenerMap = /* @__PURE__ */ new Map();
|
16
|
+
var NAME = "Announce";
|
17
|
+
var Announce = React.forwardRef((props, forwardedRef) => {
|
18
|
+
const {
|
19
|
+
"aria-relevant": ariaRelevant,
|
20
|
+
children,
|
21
|
+
type = "polite",
|
22
|
+
role = ROLES[type],
|
23
|
+
regionIdentifier,
|
24
|
+
...regionProps
|
25
|
+
} = props;
|
26
|
+
const ariaAtomic = ["true", true].includes(regionProps["aria-atomic"]);
|
27
|
+
const ownerDocumentRef = React.useRef(document);
|
28
|
+
const setOwnerDocumentFromRef = React.useCallback((node) => {
|
29
|
+
if (node) {
|
30
|
+
ownerDocumentRef.current = node.ownerDocument;
|
31
|
+
}
|
32
|
+
}, []);
|
33
|
+
const ownRef = React.useRef(null);
|
34
|
+
const ref = useComposedRefs(forwardedRef, ownRef, setOwnerDocumentFromRef);
|
35
|
+
const [region, setRegion] = React.useState();
|
36
|
+
const relevant = ariaRelevant ? Array.isArray(ariaRelevant) ? ariaRelevant.join(" ") : ariaRelevant : void 0;
|
37
|
+
const getLiveRegionElement = React.useCallback(() => {
|
38
|
+
const ownerDocument = ownerDocumentRef.current;
|
39
|
+
const regionConfig = { type, role, relevant, id: regionIdentifier, atomic: ariaAtomic };
|
40
|
+
const regionSelector = buildSelector(regionConfig);
|
41
|
+
const element = ownerDocument.querySelector(regionSelector);
|
42
|
+
return element || buildLiveRegionElement(ownerDocument, regionConfig);
|
43
|
+
}, [ariaAtomic, relevant, role, type, regionIdentifier]);
|
44
|
+
useLayoutEffect(() => {
|
45
|
+
setRegion(getLiveRegionElement());
|
46
|
+
}, [getLiveRegionElement]);
|
47
|
+
React.useEffect(() => {
|
48
|
+
const ownerDocument = ownerDocumentRef.current;
|
49
|
+
function updateAttributesOnVisibilityChange() {
|
50
|
+
regionElement.setAttribute("role", ownerDocument.hidden ? "none" : role);
|
51
|
+
regionElement.setAttribute("aria-live", ownerDocument.hidden ? "off" : type);
|
52
|
+
}
|
53
|
+
const regionElement = getLiveRegionElement();
|
54
|
+
if (!listenerMap.get(regionElement)) {
|
55
|
+
ownerDocument.addEventListener("visibilitychange", updateAttributesOnVisibilityChange);
|
56
|
+
listenerMap.set(regionElement, 1);
|
57
|
+
} else {
|
58
|
+
const announceCount = listenerMap.get(regionElement);
|
59
|
+
listenerMap.set(regionElement, announceCount + 1);
|
60
|
+
}
|
61
|
+
return function() {
|
62
|
+
const announceCount = listenerMap.get(regionElement);
|
63
|
+
listenerMap.set(regionElement, announceCount - 1);
|
64
|
+
if (announceCount === 1) {
|
65
|
+
ownerDocument.removeEventListener("visibilitychange", updateAttributesOnVisibilityChange);
|
66
|
+
}
|
67
|
+
};
|
68
|
+
}, [getLiveRegionElement, role, type]);
|
69
|
+
return /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
70
|
+
/* @__PURE__ */ jsx(Primitive.div, { ...regionProps, ref, children }),
|
71
|
+
region && ReactDOM.createPortal(/* @__PURE__ */ jsx("div", { children }), region)
|
72
|
+
] });
|
73
|
+
});
|
74
|
+
Announce.displayName = NAME;
|
75
|
+
function buildLiveRegionElement(ownerDocument, { type, relevant, role, atomic, id }) {
|
76
|
+
const element = ownerDocument.createElement("div");
|
77
|
+
element.setAttribute(getLiveRegionPartDataAttr(id), "");
|
78
|
+
element.setAttribute(
|
79
|
+
"style",
|
80
|
+
"position: absolute; top: -1px; width: 1px; height: 1px; overflow: hidden;"
|
81
|
+
);
|
82
|
+
ownerDocument.body.appendChild(element);
|
83
|
+
element.setAttribute("aria-live", type);
|
84
|
+
element.setAttribute("aria-atomic", String(atomic || false));
|
85
|
+
element.setAttribute("role", role);
|
86
|
+
if (relevant) {
|
87
|
+
element.setAttribute("aria-relevant", relevant);
|
88
|
+
}
|
89
|
+
return element;
|
90
|
+
}
|
91
|
+
function buildSelector({ type, relevant, role, atomic, id }) {
|
92
|
+
return `[${getLiveRegionPartDataAttr(id)}]${[
|
93
|
+
["aria-live", type],
|
94
|
+
["aria-atomic", atomic],
|
95
|
+
["aria-relevant", relevant],
|
96
|
+
["role", role]
|
97
|
+
].filter(([, val]) => !!val).map(([attr, val]) => `[${attr}=${val}]`).join("")}`;
|
98
|
+
}
|
99
|
+
function getLiveRegionPartDataAttr(id) {
|
100
|
+
return "data-huin-core-announce-region" + (id ? `-${id}` : "");
|
101
|
+
}
|
102
|
+
var Root = Announce;
|
103
|
+
export {
|
104
|
+
Announce,
|
105
|
+
Root
|
106
|
+
};
|
107
|
+
//# sourceMappingURL=index.mjs.map
|
@@ -0,0 +1,7 @@
|
|
1
|
+
{
|
2
|
+
"version": 3,
|
3
|
+
"sources": ["../src/Announce.tsx"],
|
4
|
+
"sourcesContent": ["import * as React from 'react';\nimport ReactDOM from 'react-dom';\nimport { useComposedRefs } from '@huin-core/react-compose-refs';\nimport { Primitive } from '@huin-core/react-primitive';\nimport { useLayoutEffect } from '@huin-core/react-use-layout-effect';\n\ntype RegionType = 'polite' | 'assertive' | 'off';\ntype RegionRole = 'status' | 'alert' | 'log' | 'none';\n\nconst ROLES: { [key in RegionType]: RegionRole } = {\n polite: 'status',\n assertive: 'alert',\n off: 'none',\n};\n\nconst listenerMap = new Map<Element, number>();\n\n/* -------------------------------------------------------------------------------------------------\n * Announce\n * -----------------------------------------------------------------------------------------------*/\n\nconst NAME = 'Announce';\n\ntype AnnounceElement = React.ElementRef<typeof Primitive.div>;\ntype PrimitiveDivProps = React.ComponentPropsWithoutRef<typeof Primitive.div>;\ninterface AnnounceProps extends PrimitiveDivProps {\n /**\n * Mirrors the `aria-atomic` DOM attribute for live regions. It is an optional attribute that\n * indicates whether assistive technologies will present all, or only parts of, the changed region\n * based on the change notifications defined by the `aria-relevant` attribute.\n *\n * @see WAI-ARIA https://www.w3.org/TR/wai-aria-1.2/#aria-atomic\n * @see Demo http://pauljadam.com/demos/aria-atomic-relevant.html\n */\n 'aria-atomic'?: boolean;\n /**\n * Mirrors the `aria-relevant` DOM attribute for live regions. It is an optional attribute used to\n * describe what types of changes have occurred to the region, and which changes are relevant and\n * should be announced. Any change that is not relevant acts in the same manner it would if the\n * `aria-live` attribute were set to off.\n *\n * Unfortunately, `aria-relevant` doesn't behave as expected across all device/screen reader\n * combinations. It's important to test its implementation before relying on it to work for your\n * users. The attribute is omitted by default.\n *\n * @see WAI-ARIA https://www.w3.org/TR/wai-aria-1.2/#aria-relevant\n * @see MDN https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_aria-relevant_attribute\n * @see Opinion https://medium.com/dev-channel/why-authors-should-avoid-aria-relevant-5d3164fab1e3\n * @see Demo http://pauljadam.com/demos/aria-atomic-relevant.html\n */\n 'aria-relevant'?: PrimitiveDivProps['aria-relevant'];\n /**\n * React children of your component. Children can be mirrored directly or modified to optimize for\n * screen reader user experience.\n */\n children: React.ReactNode;\n /**\n * An optional unique identifier for the live region.\n *\n * By default, `Announce` components create, at most, two unique `aria-live` regions in the\n * document (one for all `polite` notifications, one for all `assertive` notifications). In some\n * cases you may wish to append additional `aria-live` regions for distinct purposes (for example,\n * simple status updates may need to be separated from a stack of toast-style notifications). By\n * passing an id, you indicate that any content rendered by components with the same identifier\n * should be mirrored in a separate `aria-live` region.\n */\n regionIdentifier?: string;\n /**\n * Mirrors the `role` DOM attribute. This is optional and may be useful as an override in some\n * cases. By default, the role is determined by the `type` prop.\n *\n * @see MDN https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Live_Regions#Preferring_specialized_live_region_roles\n */\n role?: RegionRole;\n /**\n * Mirrors the `aria-live` DOM attribute. The `aria-live=POLITENESS_SETTING` is used to set the\n * priority with which screen reader should treat updates to live regions. Its possible settings\n * are: off, polite or assertive. Defaults to `polite`.\n *\n * @see MDN https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Live_Regions\n */\n type?: RegionType;\n}\n\nconst Announce = React.forwardRef<AnnounceElement, AnnounceProps>((props, forwardedRef) => {\n const {\n 'aria-relevant': ariaRelevant,\n children,\n type = 'polite',\n role = ROLES[type],\n regionIdentifier,\n ...regionProps\n } = props;\n\n const ariaAtomic = ['true', true].includes(regionProps['aria-atomic'] as any);\n\n // The region is appended to the root document node, which is usually the global `document` but in\n // some contexts may be another node. After the Announce element ref is attached, we set the\n // ownerDocumentRef to make sure we have the right root node. We should only need to do this once.\n const ownerDocumentRef = React.useRef(document);\n const setOwnerDocumentFromRef = React.useCallback((node: HTMLDivElement) => {\n if (node) {\n ownerDocumentRef.current = node.ownerDocument;\n }\n }, []);\n const ownRef = React.useRef<HTMLDivElement | null>(null);\n const ref = useComposedRefs(forwardedRef, ownRef, setOwnerDocumentFromRef);\n\n const [region, setRegion] = React.useState<HTMLElement>();\n const relevant = ariaRelevant\n ? Array.isArray(ariaRelevant)\n ? ariaRelevant.join(' ')\n : ariaRelevant\n : undefined;\n\n const getLiveRegionElement = React.useCallback(() => {\n const ownerDocument = ownerDocumentRef.current;\n const regionConfig = { type, role, relevant, id: regionIdentifier, atomic: ariaAtomic };\n const regionSelector = buildSelector(regionConfig);\n const element = ownerDocument.querySelector(regionSelector);\n\n return element || buildLiveRegionElement(ownerDocument, regionConfig);\n }, [ariaAtomic, relevant, role, type, regionIdentifier]);\n\n useLayoutEffect(() => {\n setRegion(getLiveRegionElement() as HTMLElement);\n }, [getLiveRegionElement]);\n\n // In some screen reader/browser combinations, alerts coming from an inactive browser tab may be\n // announced, which is a confusing experience for a user interacting with a completely different\n // page. When the page visibility changes we'll update the `role` and `aria-live` attributes of\n // our region element to prevent that.\n // https://inclusive-components.design/notifications/#restrictingmessagestocontexts\n React.useEffect(() => {\n const ownerDocument = ownerDocumentRef.current;\n function updateAttributesOnVisibilityChange() {\n regionElement.setAttribute('role', ownerDocument.hidden ? 'none' : role);\n regionElement.setAttribute('aria-live', ownerDocument.hidden ? 'off' : type);\n }\n\n // Ok, so this might look a little weird and confusing, but here's what's going on:\n // - We need to hide `aria-live` regions via a global event listener, as noted in the comment\n // above.\n // - We only need one listener per region. Keep in mind that each `Announce` does not\n // necessarily generate a unique live region element.\n // - We track whether or not a listener has already been attached for a given region in a map\n // so we can skip these effects after `Announce` is used again with a shared live region.\n const regionElement = getLiveRegionElement();\n\n if (!listenerMap.get(regionElement)) {\n ownerDocument.addEventListener('visibilitychange', updateAttributesOnVisibilityChange);\n listenerMap.set(regionElement, 1);\n } else {\n const announceCount = listenerMap.get(regionElement)!;\n listenerMap.set(regionElement, announceCount + 1);\n }\n\n return function () {\n const announceCount = listenerMap.get(regionElement)!;\n listenerMap.set(regionElement, announceCount - 1);\n if (announceCount === 1) {\n ownerDocument.removeEventListener('visibilitychange', updateAttributesOnVisibilityChange);\n }\n };\n }, [getLiveRegionElement, role, type]);\n\n return (\n <React.Fragment>\n <Primitive.div {...regionProps} ref={ref}>\n {children}\n </Primitive.div>\n\n {/* portal into live region for screen reader announcements */}\n {region && ReactDOM.createPortal(<div>{children}</div>, region)}\n </React.Fragment>\n );\n});\n\nAnnounce.displayName = NAME;\n\n/* ---------------------------------------------------------------------------------------------- */\n\ntype LiveRegionOptions = {\n type: string;\n relevant?: string;\n role: string;\n atomic?: boolean;\n id?: string;\n};\n\nfunction buildLiveRegionElement(\n ownerDocument: Document,\n { type, relevant, role, atomic, id }: LiveRegionOptions\n) {\n const element = ownerDocument.createElement('div');\n element.setAttribute(getLiveRegionPartDataAttr(id), '');\n element.setAttribute(\n 'style',\n 'position: absolute; top: -1px; width: 1px; height: 1px; overflow: hidden;'\n );\n ownerDocument.body.appendChild(element);\n\n element.setAttribute('aria-live', type);\n element.setAttribute('aria-atomic', String(atomic || false));\n element.setAttribute('role', role);\n if (relevant) {\n element.setAttribute('aria-relevant', relevant);\n }\n\n return element;\n}\n\nfunction buildSelector({ type, relevant, role, atomic, id }: LiveRegionOptions) {\n return `[${getLiveRegionPartDataAttr(id)}]${[\n ['aria-live', type],\n ['aria-atomic', atomic],\n ['aria-relevant', relevant],\n ['role', role],\n ]\n .filter(([, val]) => !!val)\n .map(([attr, val]) => `[${attr}=${val}]`)\n .join('')}`;\n}\n\nfunction getLiveRegionPartDataAttr(id?: string) {\n return 'data-huin-core-announce-region' + (id ? `-${id}` : '');\n}\n\nconst Root = Announce;\n\nexport {\n Announce,\n //\n Root,\n};\nexport type { AnnounceProps };\n"],
|
5
|
+
"mappings": "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",
|
6
|
+
"names": []
|
7
|
+
}
|