@huin-core/react-announce 1.0.2 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,YAAuB;AACvB,uBAAqB;AACrB,gCAAgC;AAChC,6BAA0B;AAC1B,qCAAgC;AAmK5B;AA9JJ,IAAM,QAA6C;AAAA,EACjD,QAAQ;AAAA,EACR,WAAW;AAAA,EACX,KAAK;AACP;AAEA,IAAM,cAAc,oBAAI,IAAqB;AAM7C,IAAM,OAAO;AA+Db,IAAM,WAAiB,iBAA2C,CAAC,OAAO,iBAAiB;AACzF,QAAM;AAAA,IACJ,iBAAiB;AAAA,IACjB;AAAA,IACA,OAAO;AAAA,IACP,OAAO,MAAM,IAAI;AAAA,IACjB;AAAA,IACA,GAAG;AAAA,EACL,IAAI;AAEJ,QAAM,aAAa,CAAC,QAAQ,IAAI,EAAE,SAAS,YAAY,aAAa,CAAQ;AAK5E,QAAM,mBAAyB,aAAO,QAAQ;AAC9C,QAAM,0BAAgC,kBAAY,CAAC,SAAyB;AAC1E,QAAI,MAAM;AACR,uBAAiB,UAAU,KAAK;AAAA,IAClC;AAAA,EACF,GAAG,CAAC,CAAC;AACL,QAAM,SAAe,aAA8B,IAAI;AACvD,QAAM,UAAM,2CAAgB,cAAc,QAAQ,uBAAuB;AAEzE,QAAM,CAAC,QAAQ,SAAS,IAAU,eAAsB;AACxD,QAAM,WAAW,eACb,MAAM,QAAQ,YAAY,IACxB,aAAa,KAAK,GAAG,IACrB,eACF;AAEJ,QAAM,uBAA6B,kBAAY,MAAM;AACnD,UAAM,gBAAgB,iBAAiB;AACvC,UAAM,eAAe,EAAE,MAAM,MAAM,UAAU,IAAI,kBAAkB,QAAQ,WAAW;AACtF,UAAM,iBAAiB,cAAc,YAAY;AACjD,UAAM,UAAU,cAAc,cAAc,cAAc;AAE1D,WAAO,WAAW,uBAAuB,eAAe,YAAY;AAAA,EACtE,GAAG,CAAC,YAAY,UAAU,MAAM,MAAM,gBAAgB,CAAC;AAEvD,sDAAgB,MAAM;AACpB,cAAU,qBAAqB,CAAgB;AAAA,EACjD,GAAG,CAAC,oBAAoB,CAAC;AAOzB,EAAM,gBAAU,MAAM;AACpB,UAAM,gBAAgB,iBAAiB;AACvC,aAAS,qCAAqC;AAC5C,oBAAc,aAAa,QAAQ,cAAc,SAAS,SAAS,IAAI;AACvE,oBAAc,aAAa,aAAa,cAAc,SAAS,QAAQ,IAAI;AAAA,IAC7E;AASA,UAAM,gBAAgB,qBAAqB;AAE3C,QAAI,CAAC,YAAY,IAAI,aAAa,GAAG;AACnC,oBAAc,iBAAiB,oBAAoB,kCAAkC;AACrF,kBAAY,IAAI,eAAe,CAAC;AAAA,IAClC,OAAO;AACL,YAAM,gBAAgB,YAAY,IAAI,aAAa;AACnD,kBAAY,IAAI,eAAe,gBAAgB,CAAC;AAAA,IAClD;AAEA,WAAO,WAAY;AACjB,YAAM,gBAAgB,YAAY,IAAI,aAAa;AACnD,kBAAY,IAAI,eAAe,gBAAgB,CAAC;AAChD,UAAI,kBAAkB,GAAG;AACvB,sBAAc,oBAAoB,oBAAoB,kCAAkC;AAAA,MAC1F;AAAA,IACF;AAAA,EACF,GAAG,CAAC,sBAAsB,MAAM,IAAI,CAAC;AAErC,SACE,6CAAO,gBAAN,EACC;AAAA,gDAAC,iCAAU,KAAV,EAAe,GAAG,aAAa,KAC7B,UACH;AAAA,IAGC,UAAU,iBAAAA,QAAS,aAAa,4CAAC,SAAK,UAAS,GAAQ,MAAM;AAAA,KAChE;AAEJ,CAAC;AAED,SAAS,cAAc;AAYvB,SAAS,uBACP,eACA,EAAE,MAAM,UAAU,MAAM,QAAQ,GAAG,GACnC;AACA,QAAM,UAAU,cAAc,cAAc,KAAK;AACjD,UAAQ,aAAa,0BAA0B,EAAE,GAAG,EAAE;AACtD,UAAQ;AAAA,IACN;AAAA,IACA;AAAA,EACF;AACA,gBAAc,KAAK,YAAY,OAAO;AAEtC,UAAQ,aAAa,aAAa,IAAI;AACtC,UAAQ,aAAa,eAAe,OAAO,UAAU,KAAK,CAAC;AAC3D,UAAQ,aAAa,QAAQ,IAAI;AACjC,MAAI,UAAU;AACZ,YAAQ,aAAa,iBAAiB,QAAQ;AAAA,EAChD;AAEA,SAAO;AACT;AAEA,SAAS,cAAc,EAAE,MAAM,UAAU,MAAM,QAAQ,GAAG,GAAsB;AAC9E,SAAO,IAAI,0BAA0B,EAAE,CAAC,IAAI;AAAA,IAC1C,CAAC,aAAa,IAAI;AAAA,IAClB,CAAC,eAAe,MAAM;AAAA,IACtB,CAAC,iBAAiB,QAAQ;AAAA,IAC1B,CAAC,QAAQ,IAAI;AAAA,EACf,EACG,OAAO,CAAC,CAAC,EAAE,GAAG,MAAM,CAAC,CAAC,GAAG,EACzB,IAAI,CAAC,CAAC,MAAM,GAAG,MAAM,IAAI,IAAI,IAAI,GAAG,GAAG,EACvC,KAAK,EAAE,CAAC;AACb;AAEA,SAAS,0BAA0B,IAAa;AAC9C,SAAO,oCAAoC,KAAK,IAAI,EAAE,KAAK;AAC7D;AAEA,IAAM,OAAO;",
|
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
|
+
}
|