@react-aria/live-announcer 3.3.4 → 3.4.1

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.
@@ -19,8 +19,20 @@ $parcel$export(module.exports, "destroyAnnouncer", () => $97cebfa4133ebec3$expor
19
19
  */ /* Inspired by https://github.com/AlmeroSteyn/react-aria-live */ const $97cebfa4133ebec3$var$LIVEREGION_TIMEOUT_DELAY = 7000;
20
20
  let $97cebfa4133ebec3$var$liveAnnouncer = null;
21
21
  function $97cebfa4133ebec3$export$a9b970dcc4ae71a9(message, assertiveness = 'assertive', timeout = $97cebfa4133ebec3$var$LIVEREGION_TIMEOUT_DELAY) {
22
- if (!$97cebfa4133ebec3$var$liveAnnouncer) $97cebfa4133ebec3$var$liveAnnouncer = new $97cebfa4133ebec3$var$LiveAnnouncer();
23
- $97cebfa4133ebec3$var$liveAnnouncer.announce(message, assertiveness, timeout);
22
+ if (!$97cebfa4133ebec3$var$liveAnnouncer) {
23
+ $97cebfa4133ebec3$var$liveAnnouncer = new $97cebfa4133ebec3$var$LiveAnnouncer();
24
+ // wait for the live announcer regions to be added to the dom, then announce
25
+ // otherwise Safari won't announce the message if it's added too quickly
26
+ // found most times less than 100ms were not consistent when announcing with Safari
27
+ // IS_REACT_ACT_ENVIRONMENT is used by React 18. Previous versions checked for the `jest` global.
28
+ // https://github.com/reactwg/react-18/discussions/102
29
+ // if we're in a test environment, announce without waiting
30
+ // @ts-ignore
31
+ if (!(typeof IS_REACT_ACT_ENVIRONMENT === 'boolean' ? IS_REACT_ACT_ENVIRONMENT : typeof jest !== 'undefined')) setTimeout(()=>{
32
+ if ($97cebfa4133ebec3$var$liveAnnouncer === null || $97cebfa4133ebec3$var$liveAnnouncer === void 0 ? void 0 : $97cebfa4133ebec3$var$liveAnnouncer.isAttached()) $97cebfa4133ebec3$var$liveAnnouncer === null || $97cebfa4133ebec3$var$liveAnnouncer === void 0 ? void 0 : $97cebfa4133ebec3$var$liveAnnouncer.announce(message, assertiveness, timeout);
33
+ }, 100);
34
+ else $97cebfa4133ebec3$var$liveAnnouncer.announce(message, assertiveness, timeout);
35
+ } else $97cebfa4133ebec3$var$liveAnnouncer.announce(message, assertiveness, timeout);
24
36
  }
25
37
  function $97cebfa4133ebec3$export$d10ae4f68404609a(assertiveness) {
26
38
  if ($97cebfa4133ebec3$var$liveAnnouncer) $97cebfa4133ebec3$var$liveAnnouncer.clear(assertiveness);
@@ -38,6 +50,10 @@ function $97cebfa4133ebec3$export$d8686216b8b81b2f() {
38
50
  // is simple enough to implement without React, so that's what we do here.
39
51
  // See this discussion for more details: https://github.com/reactwg/react-18/discussions/125#discussioncomment-2382638
40
52
  class $97cebfa4133ebec3$var$LiveAnnouncer {
53
+ isAttached() {
54
+ var _this_node;
55
+ return (_this_node = this.node) === null || _this_node === void 0 ? void 0 : _this_node.isConnected;
56
+ }
41
57
  createLog(ariaLive) {
42
58
  let node = document.createElement('div');
43
59
  node.setAttribute('role', 'log');
@@ -51,41 +67,51 @@ class $97cebfa4133ebec3$var$LiveAnnouncer {
51
67
  this.node = null;
52
68
  }
53
69
  announce(message, assertiveness = 'assertive', timeout = $97cebfa4133ebec3$var$LIVEREGION_TIMEOUT_DELAY) {
70
+ var _this_assertiveLog, _this_politeLog;
54
71
  if (!this.node) return;
55
72
  let node = document.createElement('div');
56
- node.textContent = message;
57
- if (assertiveness === 'assertive') this.assertiveLog.appendChild(node);
58
- else this.politeLog.appendChild(node);
73
+ if (typeof message === 'object') {
74
+ // To read an aria-labelledby, the element must have an appropriate role, such as img.
75
+ node.setAttribute('role', 'img');
76
+ node.setAttribute('aria-labelledby', message['aria-labelledby']);
77
+ } else node.textContent = message;
78
+ if (assertiveness === 'assertive') (_this_assertiveLog = this.assertiveLog) === null || _this_assertiveLog === void 0 ? void 0 : _this_assertiveLog.appendChild(node);
79
+ else (_this_politeLog = this.politeLog) === null || _this_politeLog === void 0 ? void 0 : _this_politeLog.appendChild(node);
59
80
  if (message !== '') setTimeout(()=>{
60
81
  node.remove();
61
82
  }, timeout);
62
83
  }
63
84
  clear(assertiveness) {
64
85
  if (!this.node) return;
65
- if (!assertiveness || assertiveness === 'assertive') this.assertiveLog.innerHTML = '';
66
- if (!assertiveness || assertiveness === 'polite') this.politeLog.innerHTML = '';
86
+ if ((!assertiveness || assertiveness === 'assertive') && this.assertiveLog) this.assertiveLog.innerHTML = '';
87
+ if ((!assertiveness || assertiveness === 'polite') && this.politeLog) this.politeLog.innerHTML = '';
67
88
  }
68
89
  constructor(){
69
- this.node = document.createElement('div');
70
- this.node.dataset.liveAnnouncer = 'true';
71
- // copied from VisuallyHidden
72
- Object.assign(this.node.style, {
73
- border: 0,
74
- clip: 'rect(0 0 0 0)',
75
- clipPath: 'inset(50%)',
76
- height: '1px',
77
- margin: '-1px',
78
- overflow: 'hidden',
79
- padding: 0,
80
- position: 'absolute',
81
- width: '1px',
82
- whiteSpace: 'nowrap'
83
- });
84
- this.assertiveLog = this.createLog('assertive');
85
- this.node.appendChild(this.assertiveLog);
86
- this.politeLog = this.createLog('polite');
87
- this.node.appendChild(this.politeLog);
88
- document.body.prepend(this.node);
90
+ this.node = null;
91
+ this.assertiveLog = null;
92
+ this.politeLog = null;
93
+ if (typeof document !== 'undefined') {
94
+ this.node = document.createElement('div');
95
+ this.node.dataset.liveAnnouncer = 'true';
96
+ // copied from VisuallyHidden
97
+ Object.assign(this.node.style, {
98
+ border: 0,
99
+ clip: 'rect(0 0 0 0)',
100
+ clipPath: 'inset(50%)',
101
+ height: '1px',
102
+ margin: '-1px',
103
+ overflow: 'hidden',
104
+ padding: 0,
105
+ position: 'absolute',
106
+ width: '1px',
107
+ whiteSpace: 'nowrap'
108
+ });
109
+ this.assertiveLog = this.createLog('assertive');
110
+ this.node.appendChild(this.assertiveLog);
111
+ this.politeLog = this.createLog('polite');
112
+ this.node.appendChild(this.politeLog);
113
+ document.body.prepend(this.node);
114
+ }
89
115
  }
90
116
  }
91
117
 
@@ -1 +1 @@
1
- {"mappings":";;;;;;;;AAAA;;;;;;;;;;CAUC,GAID,8DAA8D,GAC9D,MAAM,iDAA2B;AAEjC,IAAI,sCAAsC;AAKnC,SAAS,0CACd,OAAe,EACf,gBAA+B,WAAW,EAC1C,UAAU,8CAAwB;IAElC,IAAI,CAAC,qCACH,sCAAgB,IAAI;IAGtB,oCAAc,QAAQ,CAAC,SAAS,eAAe;AACjD;AAKO,SAAS,0CAAe,aAA4B;IACzD,IAAI,qCACF,oCAAc,KAAK,CAAC;AAExB;AAKO,SAAS;IACd,IAAI,qCAAe;QACjB,oCAAc,OAAO;QACrB,sCAAgB;IAClB;AACF;AAEA,2FAA2F;AAC3F,0FAA0F;AAC1F,mGAAmG;AACnG,iGAAiG;AACjG,0EAA0E;AAC1E,sHAAsH;AACtH,MAAM;IA+BJ,UAAU,QAAgB,EAAE;QAC1B,IAAI,OAAO,SAAS,aAAa,CAAC;QAClC,KAAK,YAAY,CAAC,QAAQ;QAC1B,KAAK,YAAY,CAAC,aAAa;QAC/B,KAAK,YAAY,CAAC,iBAAiB;QACnC,OAAO;IACT;IAEA,UAAU;QACR,IAAI,CAAC,IAAI,CAAC,IAAI,EACZ;QAGF,SAAS,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI;QACnC,IAAI,CAAC,IAAI,GAAG;IACd;IAEA,SAAS,OAAe,EAAE,gBAAgB,WAAW,EAAE,UAAU,8CAAwB,EAAE;QACzF,IAAI,CAAC,IAAI,CAAC,IAAI,EACZ;QAGF,IAAI,OAAO,SAAS,aAAa,CAAC;QAClC,KAAK,WAAW,GAAG;QAEnB,IAAI,kBAAkB,aACpB,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC;aAE9B,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC;QAG7B,IAAI,YAAY,IACd,WAAW;YACT,KAAK,MAAM;QACb,GAAG;IAEP;IAEA,MAAM,aAA4B,EAAE;QAClC,IAAI,CAAC,IAAI,CAAC,IAAI,EACZ;QAGF,IAAI,CAAC,iBAAiB,kBAAkB,aACtC,IAAI,CAAC,YAAY,CAAC,SAAS,GAAG;QAGhC,IAAI,CAAC,iBAAiB,kBAAkB,UACtC,IAAI,CAAC,SAAS,CAAC,SAAS,GAAG;IAE/B;IA5EA,aAAc;QACZ,IAAI,CAAC,IAAI,GAAG,SAAS,aAAa,CAAC;QACnC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,GAAG;QAClC,6BAA6B;QAC7B,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE;YAC7B,QAAQ;YACR,MAAM;YACN,UAAU;YACV,QAAQ;YACR,QAAQ;YACR,UAAU;YACV,SAAS;YACT,UAAU;YACV,OAAO;YACP,YAAY;QACd;QAEA,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,SAAS,CAAC;QACnC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,YAAY;QAEvC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;QAChC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS;QAEpC,SAAS,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI;IACjC;AAqDF","sources":["packages/@react-aria/live-announcer/src/LiveAnnouncer.tsx"],"sourcesContent":["/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\ntype Assertiveness = 'assertive' | 'polite';\n\n/* Inspired by https://github.com/AlmeroSteyn/react-aria-live */\nconst LIVEREGION_TIMEOUT_DELAY = 7000;\n\nlet liveAnnouncer: LiveAnnouncer | null = null;\n\n/**\n * Announces the message using screen reader technology.\n */\nexport function announce(\n message: string,\n assertiveness: Assertiveness = 'assertive',\n timeout = LIVEREGION_TIMEOUT_DELAY\n) {\n if (!liveAnnouncer) {\n liveAnnouncer = new LiveAnnouncer();\n }\n\n liveAnnouncer.announce(message, assertiveness, timeout);\n}\n\n/**\n * Stops all queued announcements.\n */\nexport function clearAnnouncer(assertiveness: Assertiveness) {\n if (liveAnnouncer) {\n liveAnnouncer.clear(assertiveness);\n }\n}\n\n/**\n * Removes the announcer from the DOM.\n */\nexport function destroyAnnouncer() {\n if (liveAnnouncer) {\n liveAnnouncer.destroy();\n liveAnnouncer = null;\n }\n}\n\n// LiveAnnouncer is implemented using vanilla DOM, not React. That's because as of React 18\n// ReactDOM.render is deprecated, and the replacement, ReactDOM.createRoot is moved into a\n// subpath import `react-dom/client`. That makes it hard for us to support multiple React versions.\n// As a global API, we can't use portals without introducing a breaking API change. LiveAnnouncer\n// is simple enough to implement without React, so that's what we do here.\n// See this discussion for more details: https://github.com/reactwg/react-18/discussions/125#discussioncomment-2382638\nclass LiveAnnouncer {\n node: HTMLElement | null;\n assertiveLog: HTMLElement;\n politeLog: HTMLElement;\n\n constructor() {\n this.node = document.createElement('div');\n this.node.dataset.liveAnnouncer = 'true';\n // copied from VisuallyHidden\n Object.assign(this.node.style, {\n border: 0,\n clip: 'rect(0 0 0 0)',\n clipPath: 'inset(50%)',\n height: '1px',\n margin: '-1px',\n overflow: 'hidden',\n padding: 0,\n position: 'absolute',\n width: '1px',\n whiteSpace: 'nowrap'\n });\n\n this.assertiveLog = this.createLog('assertive');\n this.node.appendChild(this.assertiveLog);\n\n this.politeLog = this.createLog('polite');\n this.node.appendChild(this.politeLog);\n\n document.body.prepend(this.node);\n }\n\n createLog(ariaLive: string) {\n let node = document.createElement('div');\n node.setAttribute('role', 'log');\n node.setAttribute('aria-live', ariaLive);\n node.setAttribute('aria-relevant', 'additions');\n return node;\n }\n\n destroy() {\n if (!this.node) {\n return;\n }\n\n document.body.removeChild(this.node);\n this.node = null;\n }\n\n announce(message: string, assertiveness = 'assertive', timeout = LIVEREGION_TIMEOUT_DELAY) {\n if (!this.node) {\n return;\n }\n\n let node = document.createElement('div');\n node.textContent = message;\n\n if (assertiveness === 'assertive') {\n this.assertiveLog.appendChild(node);\n } else {\n this.politeLog.appendChild(node);\n }\n\n if (message !== '') {\n setTimeout(() => {\n node.remove();\n }, timeout);\n }\n }\n\n clear(assertiveness: Assertiveness) {\n if (!this.node) {\n return;\n }\n\n if (!assertiveness || assertiveness === 'assertive') {\n this.assertiveLog.innerHTML = '';\n }\n\n if (!assertiveness || assertiveness === 'polite') {\n this.politeLog.innerHTML = '';\n }\n }\n}\n"],"names":[],"version":3,"file":"LiveAnnouncer.main.js.map"}
1
+ {"mappings":"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","sources":["packages/@react-aria/live-announcer/src/LiveAnnouncer.tsx"],"sourcesContent":["/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\ntype Assertiveness = 'assertive' | 'polite';\n\n/* Inspired by https://github.com/AlmeroSteyn/react-aria-live */\nconst LIVEREGION_TIMEOUT_DELAY = 7000;\n\nlet liveAnnouncer: LiveAnnouncer | null = null;\n\ntype Message = string | {'aria-labelledby': string};\n\n/**\n * Announces the message using screen reader technology.\n */\nexport function announce(\n message: Message,\n assertiveness: Assertiveness = 'assertive',\n timeout = LIVEREGION_TIMEOUT_DELAY\n) {\n if (!liveAnnouncer) {\n liveAnnouncer = new LiveAnnouncer();\n // wait for the live announcer regions to be added to the dom, then announce\n // otherwise Safari won't announce the message if it's added too quickly\n // found most times less than 100ms were not consistent when announcing with Safari\n\n // IS_REACT_ACT_ENVIRONMENT is used by React 18. Previous versions checked for the `jest` global.\n // https://github.com/reactwg/react-18/discussions/102\n // if we're in a test environment, announce without waiting\n // @ts-ignore\n if (!(typeof IS_REACT_ACT_ENVIRONMENT === 'boolean' ? IS_REACT_ACT_ENVIRONMENT : typeof jest !== 'undefined')) {\n setTimeout(() => {\n if (liveAnnouncer?.isAttached()) {\n liveAnnouncer?.announce(message, assertiveness, timeout);\n }\n }, 100);\n } else {\n liveAnnouncer.announce(message, assertiveness, timeout);\n }\n } else {\n liveAnnouncer.announce(message, assertiveness, timeout);\n }\n}\n\n/**\n * Stops all queued announcements.\n */\nexport function clearAnnouncer(assertiveness: Assertiveness) {\n if (liveAnnouncer) {\n liveAnnouncer.clear(assertiveness);\n }\n}\n\n/**\n * Removes the announcer from the DOM.\n */\nexport function destroyAnnouncer() {\n if (liveAnnouncer) {\n liveAnnouncer.destroy();\n liveAnnouncer = null;\n }\n}\n\n// LiveAnnouncer is implemented using vanilla DOM, not React. That's because as of React 18\n// ReactDOM.render is deprecated, and the replacement, ReactDOM.createRoot is moved into a\n// subpath import `react-dom/client`. That makes it hard for us to support multiple React versions.\n// As a global API, we can't use portals without introducing a breaking API change. LiveAnnouncer\n// is simple enough to implement without React, so that's what we do here.\n// See this discussion for more details: https://github.com/reactwg/react-18/discussions/125#discussioncomment-2382638\nclass LiveAnnouncer {\n node: HTMLElement | null = null;\n assertiveLog: HTMLElement | null = null;\n politeLog: HTMLElement | null = null;\n\n constructor() {\n if (typeof document !== 'undefined') {\n this.node = document.createElement('div');\n this.node.dataset.liveAnnouncer = 'true';\n // copied from VisuallyHidden\n Object.assign(this.node.style, {\n border: 0,\n clip: 'rect(0 0 0 0)',\n clipPath: 'inset(50%)',\n height: '1px',\n margin: '-1px',\n overflow: 'hidden',\n padding: 0,\n position: 'absolute',\n width: '1px',\n whiteSpace: 'nowrap'\n });\n\n this.assertiveLog = this.createLog('assertive');\n this.node.appendChild(this.assertiveLog);\n\n this.politeLog = this.createLog('polite');\n this.node.appendChild(this.politeLog);\n\n document.body.prepend(this.node);\n }\n }\n\n isAttached() {\n return this.node?.isConnected;\n }\n\n createLog(ariaLive: string) {\n let node = document.createElement('div');\n node.setAttribute('role', 'log');\n node.setAttribute('aria-live', ariaLive);\n node.setAttribute('aria-relevant', 'additions');\n return node;\n }\n\n destroy() {\n if (!this.node) {\n return;\n }\n\n document.body.removeChild(this.node);\n this.node = null;\n }\n\n announce(message: Message, assertiveness = 'assertive', timeout = LIVEREGION_TIMEOUT_DELAY) {\n if (!this.node) {\n return;\n }\n\n let node = document.createElement('div');\n if (typeof message === 'object') {\n // To read an aria-labelledby, the element must have an appropriate role, such as img.\n node.setAttribute('role', 'img');\n node.setAttribute('aria-labelledby', message['aria-labelledby']);\n } else {\n node.textContent = message;\n }\n\n if (assertiveness === 'assertive') {\n this.assertiveLog?.appendChild(node);\n } else {\n this.politeLog?.appendChild(node);\n }\n\n if (message !== '') {\n setTimeout(() => {\n node.remove();\n }, timeout);\n }\n }\n\n clear(assertiveness: Assertiveness) {\n if (!this.node) {\n return;\n }\n\n if ((!assertiveness || assertiveness === 'assertive') && this.assertiveLog) {\n this.assertiveLog.innerHTML = '';\n }\n\n if ((!assertiveness || assertiveness === 'polite') && this.politeLog) {\n this.politeLog.innerHTML = '';\n }\n }\n}\n"],"names":[],"version":3,"file":"LiveAnnouncer.main.js.map"}
@@ -11,8 +11,20 @@
11
11
  */ /* Inspired by https://github.com/AlmeroSteyn/react-aria-live */ const $319e236875307eab$var$LIVEREGION_TIMEOUT_DELAY = 7000;
12
12
  let $319e236875307eab$var$liveAnnouncer = null;
13
13
  function $319e236875307eab$export$a9b970dcc4ae71a9(message, assertiveness = 'assertive', timeout = $319e236875307eab$var$LIVEREGION_TIMEOUT_DELAY) {
14
- if (!$319e236875307eab$var$liveAnnouncer) $319e236875307eab$var$liveAnnouncer = new $319e236875307eab$var$LiveAnnouncer();
15
- $319e236875307eab$var$liveAnnouncer.announce(message, assertiveness, timeout);
14
+ if (!$319e236875307eab$var$liveAnnouncer) {
15
+ $319e236875307eab$var$liveAnnouncer = new $319e236875307eab$var$LiveAnnouncer();
16
+ // wait for the live announcer regions to be added to the dom, then announce
17
+ // otherwise Safari won't announce the message if it's added too quickly
18
+ // found most times less than 100ms were not consistent when announcing with Safari
19
+ // IS_REACT_ACT_ENVIRONMENT is used by React 18. Previous versions checked for the `jest` global.
20
+ // https://github.com/reactwg/react-18/discussions/102
21
+ // if we're in a test environment, announce without waiting
22
+ // @ts-ignore
23
+ if (!(typeof IS_REACT_ACT_ENVIRONMENT === 'boolean' ? IS_REACT_ACT_ENVIRONMENT : typeof jest !== 'undefined')) setTimeout(()=>{
24
+ if ($319e236875307eab$var$liveAnnouncer === null || $319e236875307eab$var$liveAnnouncer === void 0 ? void 0 : $319e236875307eab$var$liveAnnouncer.isAttached()) $319e236875307eab$var$liveAnnouncer === null || $319e236875307eab$var$liveAnnouncer === void 0 ? void 0 : $319e236875307eab$var$liveAnnouncer.announce(message, assertiveness, timeout);
25
+ }, 100);
26
+ else $319e236875307eab$var$liveAnnouncer.announce(message, assertiveness, timeout);
27
+ } else $319e236875307eab$var$liveAnnouncer.announce(message, assertiveness, timeout);
16
28
  }
17
29
  function $319e236875307eab$export$d10ae4f68404609a(assertiveness) {
18
30
  if ($319e236875307eab$var$liveAnnouncer) $319e236875307eab$var$liveAnnouncer.clear(assertiveness);
@@ -30,6 +42,10 @@ function $319e236875307eab$export$d8686216b8b81b2f() {
30
42
  // is simple enough to implement without React, so that's what we do here.
31
43
  // See this discussion for more details: https://github.com/reactwg/react-18/discussions/125#discussioncomment-2382638
32
44
  class $319e236875307eab$var$LiveAnnouncer {
45
+ isAttached() {
46
+ var _this_node;
47
+ return (_this_node = this.node) === null || _this_node === void 0 ? void 0 : _this_node.isConnected;
48
+ }
33
49
  createLog(ariaLive) {
34
50
  let node = document.createElement('div');
35
51
  node.setAttribute('role', 'log');
@@ -43,41 +59,51 @@ class $319e236875307eab$var$LiveAnnouncer {
43
59
  this.node = null;
44
60
  }
45
61
  announce(message, assertiveness = 'assertive', timeout = $319e236875307eab$var$LIVEREGION_TIMEOUT_DELAY) {
62
+ var _this_assertiveLog, _this_politeLog;
46
63
  if (!this.node) return;
47
64
  let node = document.createElement('div');
48
- node.textContent = message;
49
- if (assertiveness === 'assertive') this.assertiveLog.appendChild(node);
50
- else this.politeLog.appendChild(node);
65
+ if (typeof message === 'object') {
66
+ // To read an aria-labelledby, the element must have an appropriate role, such as img.
67
+ node.setAttribute('role', 'img');
68
+ node.setAttribute('aria-labelledby', message['aria-labelledby']);
69
+ } else node.textContent = message;
70
+ if (assertiveness === 'assertive') (_this_assertiveLog = this.assertiveLog) === null || _this_assertiveLog === void 0 ? void 0 : _this_assertiveLog.appendChild(node);
71
+ else (_this_politeLog = this.politeLog) === null || _this_politeLog === void 0 ? void 0 : _this_politeLog.appendChild(node);
51
72
  if (message !== '') setTimeout(()=>{
52
73
  node.remove();
53
74
  }, timeout);
54
75
  }
55
76
  clear(assertiveness) {
56
77
  if (!this.node) return;
57
- if (!assertiveness || assertiveness === 'assertive') this.assertiveLog.innerHTML = '';
58
- if (!assertiveness || assertiveness === 'polite') this.politeLog.innerHTML = '';
78
+ if ((!assertiveness || assertiveness === 'assertive') && this.assertiveLog) this.assertiveLog.innerHTML = '';
79
+ if ((!assertiveness || assertiveness === 'polite') && this.politeLog) this.politeLog.innerHTML = '';
59
80
  }
60
81
  constructor(){
61
- this.node = document.createElement('div');
62
- this.node.dataset.liveAnnouncer = 'true';
63
- // copied from VisuallyHidden
64
- Object.assign(this.node.style, {
65
- border: 0,
66
- clip: 'rect(0 0 0 0)',
67
- clipPath: 'inset(50%)',
68
- height: '1px',
69
- margin: '-1px',
70
- overflow: 'hidden',
71
- padding: 0,
72
- position: 'absolute',
73
- width: '1px',
74
- whiteSpace: 'nowrap'
75
- });
76
- this.assertiveLog = this.createLog('assertive');
77
- this.node.appendChild(this.assertiveLog);
78
- this.politeLog = this.createLog('polite');
79
- this.node.appendChild(this.politeLog);
80
- document.body.prepend(this.node);
82
+ this.node = null;
83
+ this.assertiveLog = null;
84
+ this.politeLog = null;
85
+ if (typeof document !== 'undefined') {
86
+ this.node = document.createElement('div');
87
+ this.node.dataset.liveAnnouncer = 'true';
88
+ // copied from VisuallyHidden
89
+ Object.assign(this.node.style, {
90
+ border: 0,
91
+ clip: 'rect(0 0 0 0)',
92
+ clipPath: 'inset(50%)',
93
+ height: '1px',
94
+ margin: '-1px',
95
+ overflow: 'hidden',
96
+ padding: 0,
97
+ position: 'absolute',
98
+ width: '1px',
99
+ whiteSpace: 'nowrap'
100
+ });
101
+ this.assertiveLog = this.createLog('assertive');
102
+ this.node.appendChild(this.assertiveLog);
103
+ this.politeLog = this.createLog('polite');
104
+ this.node.appendChild(this.politeLog);
105
+ document.body.prepend(this.node);
106
+ }
81
107
  }
82
108
  }
83
109
 
@@ -11,8 +11,20 @@
11
11
  */ /* Inspired by https://github.com/AlmeroSteyn/react-aria-live */ const $319e236875307eab$var$LIVEREGION_TIMEOUT_DELAY = 7000;
12
12
  let $319e236875307eab$var$liveAnnouncer = null;
13
13
  function $319e236875307eab$export$a9b970dcc4ae71a9(message, assertiveness = 'assertive', timeout = $319e236875307eab$var$LIVEREGION_TIMEOUT_DELAY) {
14
- if (!$319e236875307eab$var$liveAnnouncer) $319e236875307eab$var$liveAnnouncer = new $319e236875307eab$var$LiveAnnouncer();
15
- $319e236875307eab$var$liveAnnouncer.announce(message, assertiveness, timeout);
14
+ if (!$319e236875307eab$var$liveAnnouncer) {
15
+ $319e236875307eab$var$liveAnnouncer = new $319e236875307eab$var$LiveAnnouncer();
16
+ // wait for the live announcer regions to be added to the dom, then announce
17
+ // otherwise Safari won't announce the message if it's added too quickly
18
+ // found most times less than 100ms were not consistent when announcing with Safari
19
+ // IS_REACT_ACT_ENVIRONMENT is used by React 18. Previous versions checked for the `jest` global.
20
+ // https://github.com/reactwg/react-18/discussions/102
21
+ // if we're in a test environment, announce without waiting
22
+ // @ts-ignore
23
+ if (!(typeof IS_REACT_ACT_ENVIRONMENT === 'boolean' ? IS_REACT_ACT_ENVIRONMENT : typeof jest !== 'undefined')) setTimeout(()=>{
24
+ if ($319e236875307eab$var$liveAnnouncer === null || $319e236875307eab$var$liveAnnouncer === void 0 ? void 0 : $319e236875307eab$var$liveAnnouncer.isAttached()) $319e236875307eab$var$liveAnnouncer === null || $319e236875307eab$var$liveAnnouncer === void 0 ? void 0 : $319e236875307eab$var$liveAnnouncer.announce(message, assertiveness, timeout);
25
+ }, 100);
26
+ else $319e236875307eab$var$liveAnnouncer.announce(message, assertiveness, timeout);
27
+ } else $319e236875307eab$var$liveAnnouncer.announce(message, assertiveness, timeout);
16
28
  }
17
29
  function $319e236875307eab$export$d10ae4f68404609a(assertiveness) {
18
30
  if ($319e236875307eab$var$liveAnnouncer) $319e236875307eab$var$liveAnnouncer.clear(assertiveness);
@@ -30,6 +42,10 @@ function $319e236875307eab$export$d8686216b8b81b2f() {
30
42
  // is simple enough to implement without React, so that's what we do here.
31
43
  // See this discussion for more details: https://github.com/reactwg/react-18/discussions/125#discussioncomment-2382638
32
44
  class $319e236875307eab$var$LiveAnnouncer {
45
+ isAttached() {
46
+ var _this_node;
47
+ return (_this_node = this.node) === null || _this_node === void 0 ? void 0 : _this_node.isConnected;
48
+ }
33
49
  createLog(ariaLive) {
34
50
  let node = document.createElement('div');
35
51
  node.setAttribute('role', 'log');
@@ -43,41 +59,51 @@ class $319e236875307eab$var$LiveAnnouncer {
43
59
  this.node = null;
44
60
  }
45
61
  announce(message, assertiveness = 'assertive', timeout = $319e236875307eab$var$LIVEREGION_TIMEOUT_DELAY) {
62
+ var _this_assertiveLog, _this_politeLog;
46
63
  if (!this.node) return;
47
64
  let node = document.createElement('div');
48
- node.textContent = message;
49
- if (assertiveness === 'assertive') this.assertiveLog.appendChild(node);
50
- else this.politeLog.appendChild(node);
65
+ if (typeof message === 'object') {
66
+ // To read an aria-labelledby, the element must have an appropriate role, such as img.
67
+ node.setAttribute('role', 'img');
68
+ node.setAttribute('aria-labelledby', message['aria-labelledby']);
69
+ } else node.textContent = message;
70
+ if (assertiveness === 'assertive') (_this_assertiveLog = this.assertiveLog) === null || _this_assertiveLog === void 0 ? void 0 : _this_assertiveLog.appendChild(node);
71
+ else (_this_politeLog = this.politeLog) === null || _this_politeLog === void 0 ? void 0 : _this_politeLog.appendChild(node);
51
72
  if (message !== '') setTimeout(()=>{
52
73
  node.remove();
53
74
  }, timeout);
54
75
  }
55
76
  clear(assertiveness) {
56
77
  if (!this.node) return;
57
- if (!assertiveness || assertiveness === 'assertive') this.assertiveLog.innerHTML = '';
58
- if (!assertiveness || assertiveness === 'polite') this.politeLog.innerHTML = '';
78
+ if ((!assertiveness || assertiveness === 'assertive') && this.assertiveLog) this.assertiveLog.innerHTML = '';
79
+ if ((!assertiveness || assertiveness === 'polite') && this.politeLog) this.politeLog.innerHTML = '';
59
80
  }
60
81
  constructor(){
61
- this.node = document.createElement('div');
62
- this.node.dataset.liveAnnouncer = 'true';
63
- // copied from VisuallyHidden
64
- Object.assign(this.node.style, {
65
- border: 0,
66
- clip: 'rect(0 0 0 0)',
67
- clipPath: 'inset(50%)',
68
- height: '1px',
69
- margin: '-1px',
70
- overflow: 'hidden',
71
- padding: 0,
72
- position: 'absolute',
73
- width: '1px',
74
- whiteSpace: 'nowrap'
75
- });
76
- this.assertiveLog = this.createLog('assertive');
77
- this.node.appendChild(this.assertiveLog);
78
- this.politeLog = this.createLog('polite');
79
- this.node.appendChild(this.politeLog);
80
- document.body.prepend(this.node);
82
+ this.node = null;
83
+ this.assertiveLog = null;
84
+ this.politeLog = null;
85
+ if (typeof document !== 'undefined') {
86
+ this.node = document.createElement('div');
87
+ this.node.dataset.liveAnnouncer = 'true';
88
+ // copied from VisuallyHidden
89
+ Object.assign(this.node.style, {
90
+ border: 0,
91
+ clip: 'rect(0 0 0 0)',
92
+ clipPath: 'inset(50%)',
93
+ height: '1px',
94
+ margin: '-1px',
95
+ overflow: 'hidden',
96
+ padding: 0,
97
+ position: 'absolute',
98
+ width: '1px',
99
+ whiteSpace: 'nowrap'
100
+ });
101
+ this.assertiveLog = this.createLog('assertive');
102
+ this.node.appendChild(this.assertiveLog);
103
+ this.politeLog = this.createLog('polite');
104
+ this.node.appendChild(this.politeLog);
105
+ document.body.prepend(this.node);
106
+ }
81
107
  }
82
108
  }
83
109
 
@@ -1 +1 @@
1
- {"mappings":"AAAA;;;;;;;;;;CAUC,GAID,8DAA8D,GAC9D,MAAM,iDAA2B;AAEjC,IAAI,sCAAsC;AAKnC,SAAS,0CACd,OAAe,EACf,gBAA+B,WAAW,EAC1C,UAAU,8CAAwB;IAElC,IAAI,CAAC,qCACH,sCAAgB,IAAI;IAGtB,oCAAc,QAAQ,CAAC,SAAS,eAAe;AACjD;AAKO,SAAS,0CAAe,aAA4B;IACzD,IAAI,qCACF,oCAAc,KAAK,CAAC;AAExB;AAKO,SAAS;IACd,IAAI,qCAAe;QACjB,oCAAc,OAAO;QACrB,sCAAgB;IAClB;AACF;AAEA,2FAA2F;AAC3F,0FAA0F;AAC1F,mGAAmG;AACnG,iGAAiG;AACjG,0EAA0E;AAC1E,sHAAsH;AACtH,MAAM;IA+BJ,UAAU,QAAgB,EAAE;QAC1B,IAAI,OAAO,SAAS,aAAa,CAAC;QAClC,KAAK,YAAY,CAAC,QAAQ;QAC1B,KAAK,YAAY,CAAC,aAAa;QAC/B,KAAK,YAAY,CAAC,iBAAiB;QACnC,OAAO;IACT;IAEA,UAAU;QACR,IAAI,CAAC,IAAI,CAAC,IAAI,EACZ;QAGF,SAAS,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI;QACnC,IAAI,CAAC,IAAI,GAAG;IACd;IAEA,SAAS,OAAe,EAAE,gBAAgB,WAAW,EAAE,UAAU,8CAAwB,EAAE;QACzF,IAAI,CAAC,IAAI,CAAC,IAAI,EACZ;QAGF,IAAI,OAAO,SAAS,aAAa,CAAC;QAClC,KAAK,WAAW,GAAG;QAEnB,IAAI,kBAAkB,aACpB,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC;aAE9B,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC;QAG7B,IAAI,YAAY,IACd,WAAW;YACT,KAAK,MAAM;QACb,GAAG;IAEP;IAEA,MAAM,aAA4B,EAAE;QAClC,IAAI,CAAC,IAAI,CAAC,IAAI,EACZ;QAGF,IAAI,CAAC,iBAAiB,kBAAkB,aACtC,IAAI,CAAC,YAAY,CAAC,SAAS,GAAG;QAGhC,IAAI,CAAC,iBAAiB,kBAAkB,UACtC,IAAI,CAAC,SAAS,CAAC,SAAS,GAAG;IAE/B;IA5EA,aAAc;QACZ,IAAI,CAAC,IAAI,GAAG,SAAS,aAAa,CAAC;QACnC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,GAAG;QAClC,6BAA6B;QAC7B,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE;YAC7B,QAAQ;YACR,MAAM;YACN,UAAU;YACV,QAAQ;YACR,QAAQ;YACR,UAAU;YACV,SAAS;YACT,UAAU;YACV,OAAO;YACP,YAAY;QACd;QAEA,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,SAAS,CAAC;QACnC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,YAAY;QAEvC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;QAChC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS;QAEpC,SAAS,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI;IACjC;AAqDF","sources":["packages/@react-aria/live-announcer/src/LiveAnnouncer.tsx"],"sourcesContent":["/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\ntype Assertiveness = 'assertive' | 'polite';\n\n/* Inspired by https://github.com/AlmeroSteyn/react-aria-live */\nconst LIVEREGION_TIMEOUT_DELAY = 7000;\n\nlet liveAnnouncer: LiveAnnouncer | null = null;\n\n/**\n * Announces the message using screen reader technology.\n */\nexport function announce(\n message: string,\n assertiveness: Assertiveness = 'assertive',\n timeout = LIVEREGION_TIMEOUT_DELAY\n) {\n if (!liveAnnouncer) {\n liveAnnouncer = new LiveAnnouncer();\n }\n\n liveAnnouncer.announce(message, assertiveness, timeout);\n}\n\n/**\n * Stops all queued announcements.\n */\nexport function clearAnnouncer(assertiveness: Assertiveness) {\n if (liveAnnouncer) {\n liveAnnouncer.clear(assertiveness);\n }\n}\n\n/**\n * Removes the announcer from the DOM.\n */\nexport function destroyAnnouncer() {\n if (liveAnnouncer) {\n liveAnnouncer.destroy();\n liveAnnouncer = null;\n }\n}\n\n// LiveAnnouncer is implemented using vanilla DOM, not React. That's because as of React 18\n// ReactDOM.render is deprecated, and the replacement, ReactDOM.createRoot is moved into a\n// subpath import `react-dom/client`. That makes it hard for us to support multiple React versions.\n// As a global API, we can't use portals without introducing a breaking API change. LiveAnnouncer\n// is simple enough to implement without React, so that's what we do here.\n// See this discussion for more details: https://github.com/reactwg/react-18/discussions/125#discussioncomment-2382638\nclass LiveAnnouncer {\n node: HTMLElement | null;\n assertiveLog: HTMLElement;\n politeLog: HTMLElement;\n\n constructor() {\n this.node = document.createElement('div');\n this.node.dataset.liveAnnouncer = 'true';\n // copied from VisuallyHidden\n Object.assign(this.node.style, {\n border: 0,\n clip: 'rect(0 0 0 0)',\n clipPath: 'inset(50%)',\n height: '1px',\n margin: '-1px',\n overflow: 'hidden',\n padding: 0,\n position: 'absolute',\n width: '1px',\n whiteSpace: 'nowrap'\n });\n\n this.assertiveLog = this.createLog('assertive');\n this.node.appendChild(this.assertiveLog);\n\n this.politeLog = this.createLog('polite');\n this.node.appendChild(this.politeLog);\n\n document.body.prepend(this.node);\n }\n\n createLog(ariaLive: string) {\n let node = document.createElement('div');\n node.setAttribute('role', 'log');\n node.setAttribute('aria-live', ariaLive);\n node.setAttribute('aria-relevant', 'additions');\n return node;\n }\n\n destroy() {\n if (!this.node) {\n return;\n }\n\n document.body.removeChild(this.node);\n this.node = null;\n }\n\n announce(message: string, assertiveness = 'assertive', timeout = LIVEREGION_TIMEOUT_DELAY) {\n if (!this.node) {\n return;\n }\n\n let node = document.createElement('div');\n node.textContent = message;\n\n if (assertiveness === 'assertive') {\n this.assertiveLog.appendChild(node);\n } else {\n this.politeLog.appendChild(node);\n }\n\n if (message !== '') {\n setTimeout(() => {\n node.remove();\n }, timeout);\n }\n }\n\n clear(assertiveness: Assertiveness) {\n if (!this.node) {\n return;\n }\n\n if (!assertiveness || assertiveness === 'assertive') {\n this.assertiveLog.innerHTML = '';\n }\n\n if (!assertiveness || assertiveness === 'polite') {\n this.politeLog.innerHTML = '';\n }\n }\n}\n"],"names":[],"version":3,"file":"LiveAnnouncer.module.js.map"}
1
+ {"mappings":"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","sources":["packages/@react-aria/live-announcer/src/LiveAnnouncer.tsx"],"sourcesContent":["/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\ntype Assertiveness = 'assertive' | 'polite';\n\n/* Inspired by https://github.com/AlmeroSteyn/react-aria-live */\nconst LIVEREGION_TIMEOUT_DELAY = 7000;\n\nlet liveAnnouncer: LiveAnnouncer | null = null;\n\ntype Message = string | {'aria-labelledby': string};\n\n/**\n * Announces the message using screen reader technology.\n */\nexport function announce(\n message: Message,\n assertiveness: Assertiveness = 'assertive',\n timeout = LIVEREGION_TIMEOUT_DELAY\n) {\n if (!liveAnnouncer) {\n liveAnnouncer = new LiveAnnouncer();\n // wait for the live announcer regions to be added to the dom, then announce\n // otherwise Safari won't announce the message if it's added too quickly\n // found most times less than 100ms were not consistent when announcing with Safari\n\n // IS_REACT_ACT_ENVIRONMENT is used by React 18. Previous versions checked for the `jest` global.\n // https://github.com/reactwg/react-18/discussions/102\n // if we're in a test environment, announce without waiting\n // @ts-ignore\n if (!(typeof IS_REACT_ACT_ENVIRONMENT === 'boolean' ? IS_REACT_ACT_ENVIRONMENT : typeof jest !== 'undefined')) {\n setTimeout(() => {\n if (liveAnnouncer?.isAttached()) {\n liveAnnouncer?.announce(message, assertiveness, timeout);\n }\n }, 100);\n } else {\n liveAnnouncer.announce(message, assertiveness, timeout);\n }\n } else {\n liveAnnouncer.announce(message, assertiveness, timeout);\n }\n}\n\n/**\n * Stops all queued announcements.\n */\nexport function clearAnnouncer(assertiveness: Assertiveness) {\n if (liveAnnouncer) {\n liveAnnouncer.clear(assertiveness);\n }\n}\n\n/**\n * Removes the announcer from the DOM.\n */\nexport function destroyAnnouncer() {\n if (liveAnnouncer) {\n liveAnnouncer.destroy();\n liveAnnouncer = null;\n }\n}\n\n// LiveAnnouncer is implemented using vanilla DOM, not React. That's because as of React 18\n// ReactDOM.render is deprecated, and the replacement, ReactDOM.createRoot is moved into a\n// subpath import `react-dom/client`. That makes it hard for us to support multiple React versions.\n// As a global API, we can't use portals without introducing a breaking API change. LiveAnnouncer\n// is simple enough to implement without React, so that's what we do here.\n// See this discussion for more details: https://github.com/reactwg/react-18/discussions/125#discussioncomment-2382638\nclass LiveAnnouncer {\n node: HTMLElement | null = null;\n assertiveLog: HTMLElement | null = null;\n politeLog: HTMLElement | null = null;\n\n constructor() {\n if (typeof document !== 'undefined') {\n this.node = document.createElement('div');\n this.node.dataset.liveAnnouncer = 'true';\n // copied from VisuallyHidden\n Object.assign(this.node.style, {\n border: 0,\n clip: 'rect(0 0 0 0)',\n clipPath: 'inset(50%)',\n height: '1px',\n margin: '-1px',\n overflow: 'hidden',\n padding: 0,\n position: 'absolute',\n width: '1px',\n whiteSpace: 'nowrap'\n });\n\n this.assertiveLog = this.createLog('assertive');\n this.node.appendChild(this.assertiveLog);\n\n this.politeLog = this.createLog('polite');\n this.node.appendChild(this.politeLog);\n\n document.body.prepend(this.node);\n }\n }\n\n isAttached() {\n return this.node?.isConnected;\n }\n\n createLog(ariaLive: string) {\n let node = document.createElement('div');\n node.setAttribute('role', 'log');\n node.setAttribute('aria-live', ariaLive);\n node.setAttribute('aria-relevant', 'additions');\n return node;\n }\n\n destroy() {\n if (!this.node) {\n return;\n }\n\n document.body.removeChild(this.node);\n this.node = null;\n }\n\n announce(message: Message, assertiveness = 'assertive', timeout = LIVEREGION_TIMEOUT_DELAY) {\n if (!this.node) {\n return;\n }\n\n let node = document.createElement('div');\n if (typeof message === 'object') {\n // To read an aria-labelledby, the element must have an appropriate role, such as img.\n node.setAttribute('role', 'img');\n node.setAttribute('aria-labelledby', message['aria-labelledby']);\n } else {\n node.textContent = message;\n }\n\n if (assertiveness === 'assertive') {\n this.assertiveLog?.appendChild(node);\n } else {\n this.politeLog?.appendChild(node);\n }\n\n if (message !== '') {\n setTimeout(() => {\n node.remove();\n }, timeout);\n }\n }\n\n clear(assertiveness: Assertiveness) {\n if (!this.node) {\n return;\n }\n\n if ((!assertiveness || assertiveness === 'assertive') && this.assertiveLog) {\n this.assertiveLog.innerHTML = '';\n }\n\n if ((!assertiveness || assertiveness === 'polite') && this.politeLog) {\n this.politeLog.innerHTML = '';\n }\n }\n}\n"],"names":[],"version":3,"file":"LiveAnnouncer.module.js.map"}
package/dist/types.d.ts CHANGED
@@ -1,8 +1,11 @@
1
1
  type Assertiveness = 'assertive' | 'polite';
2
+ type Message = string | {
3
+ 'aria-labelledby': string;
4
+ };
2
5
  /**
3
6
  * Announces the message using screen reader technology.
4
7
  */
5
- export function announce(message: string, assertiveness?: Assertiveness, timeout?: number): void;
8
+ export function announce(message: Message, assertiveness?: Assertiveness, timeout?: number): void;
6
9
  /**
7
10
  * Stops all queued announcements.
8
11
  */
@@ -1 +1 @@
1
- {"mappings":"AAYA,qBAAqB,WAAW,GAAG,QAAQ,CAAC;AAO5C;;GAEG;AACH,yBACE,OAAO,EAAE,MAAM,EACf,aAAa,GAAE,aAA2B,EAC1C,OAAO,SAA2B,QAOnC;AAED;;GAEG;AACH,+BAA+B,aAAa,EAAE,aAAa,QAI1D;AAED;;GAEG;AACH,yCAKC","sources":["packages/@react-aria/live-announcer/src/packages/@react-aria/live-announcer/src/LiveAnnouncer.tsx","packages/@react-aria/live-announcer/src/packages/@react-aria/live-announcer/src/index.ts","packages/@react-aria/live-announcer/src/index.ts"],"sourcesContent":[null,null,"/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\nexport {announce, clearAnnouncer, destroyAnnouncer} from './LiveAnnouncer';\n"],"names":[],"version":3,"file":"types.d.ts.map"}
1
+ {"mappings":"AAYA,qBAAqB,WAAW,GAAG,QAAQ,CAAC;AAO5C,eAAe,MAAM,GAAG;IAAC,iBAAiB,EAAE,MAAM,CAAA;CAAC,CAAC;AAEpD;;GAEG;AACH,yBACE,OAAO,EAAE,OAAO,EAChB,aAAa,GAAE,aAA2B,EAC1C,OAAO,SAA2B,QAwBnC;AAED;;GAEG;AACH,+BAA+B,aAAa,EAAE,aAAa,QAI1D;AAED;;GAEG;AACH,yCAKC","sources":["packages/@react-aria/live-announcer/src/packages/@react-aria/live-announcer/src/LiveAnnouncer.tsx","packages/@react-aria/live-announcer/src/packages/@react-aria/live-announcer/src/index.ts","packages/@react-aria/live-announcer/src/index.ts"],"sourcesContent":[null,null,"/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\nexport {announce, clearAnnouncer, destroyAnnouncer} from './LiveAnnouncer';\n"],"names":[],"version":3,"file":"types.d.ts.map"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-aria/live-announcer",
3
- "version": "3.3.4",
3
+ "version": "3.4.1",
4
4
  "description": "Spectrum UI components in React",
5
5
  "license": "Apache-2.0",
6
6
  "main": "dist/main.js",
@@ -27,5 +27,5 @@
27
27
  "publishConfig": {
28
28
  "access": "public"
29
29
  },
30
- "gitHead": "b77d7d594dff4dcfb5359bffbcfd18142b146433"
30
+ "gitHead": "71f0ef23053f9e03ee7e97df736e8b083e006849"
31
31
  }
@@ -17,19 +17,38 @@ const LIVEREGION_TIMEOUT_DELAY = 7000;
17
17
 
18
18
  let liveAnnouncer: LiveAnnouncer | null = null;
19
19
 
20
+ type Message = string | {'aria-labelledby': string};
21
+
20
22
  /**
21
23
  * Announces the message using screen reader technology.
22
24
  */
23
25
  export function announce(
24
- message: string,
26
+ message: Message,
25
27
  assertiveness: Assertiveness = 'assertive',
26
28
  timeout = LIVEREGION_TIMEOUT_DELAY
27
29
  ) {
28
30
  if (!liveAnnouncer) {
29
31
  liveAnnouncer = new LiveAnnouncer();
32
+ // wait for the live announcer regions to be added to the dom, then announce
33
+ // otherwise Safari won't announce the message if it's added too quickly
34
+ // found most times less than 100ms were not consistent when announcing with Safari
35
+
36
+ // IS_REACT_ACT_ENVIRONMENT is used by React 18. Previous versions checked for the `jest` global.
37
+ // https://github.com/reactwg/react-18/discussions/102
38
+ // if we're in a test environment, announce without waiting
39
+ // @ts-ignore
40
+ if (!(typeof IS_REACT_ACT_ENVIRONMENT === 'boolean' ? IS_REACT_ACT_ENVIRONMENT : typeof jest !== 'undefined')) {
41
+ setTimeout(() => {
42
+ if (liveAnnouncer?.isAttached()) {
43
+ liveAnnouncer?.announce(message, assertiveness, timeout);
44
+ }
45
+ }, 100);
46
+ } else {
47
+ liveAnnouncer.announce(message, assertiveness, timeout);
48
+ }
49
+ } else {
50
+ liveAnnouncer.announce(message, assertiveness, timeout);
30
51
  }
31
-
32
- liveAnnouncer.announce(message, assertiveness, timeout);
33
52
  }
34
53
 
35
54
  /**
@@ -58,34 +77,40 @@ export function destroyAnnouncer() {
58
77
  // is simple enough to implement without React, so that's what we do here.
59
78
  // See this discussion for more details: https://github.com/reactwg/react-18/discussions/125#discussioncomment-2382638
60
79
  class LiveAnnouncer {
61
- node: HTMLElement | null;
62
- assertiveLog: HTMLElement;
63
- politeLog: HTMLElement;
80
+ node: HTMLElement | null = null;
81
+ assertiveLog: HTMLElement | null = null;
82
+ politeLog: HTMLElement | null = null;
64
83
 
65
84
  constructor() {
66
- this.node = document.createElement('div');
67
- this.node.dataset.liveAnnouncer = 'true';
68
- // copied from VisuallyHidden
69
- Object.assign(this.node.style, {
70
- border: 0,
71
- clip: 'rect(0 0 0 0)',
72
- clipPath: 'inset(50%)',
73
- height: '1px',
74
- margin: '-1px',
75
- overflow: 'hidden',
76
- padding: 0,
77
- position: 'absolute',
78
- width: '1px',
79
- whiteSpace: 'nowrap'
80
- });
81
-
82
- this.assertiveLog = this.createLog('assertive');
83
- this.node.appendChild(this.assertiveLog);
84
-
85
- this.politeLog = this.createLog('polite');
86
- this.node.appendChild(this.politeLog);
87
-
88
- document.body.prepend(this.node);
85
+ if (typeof document !== 'undefined') {
86
+ this.node = document.createElement('div');
87
+ this.node.dataset.liveAnnouncer = 'true';
88
+ // copied from VisuallyHidden
89
+ Object.assign(this.node.style, {
90
+ border: 0,
91
+ clip: 'rect(0 0 0 0)',
92
+ clipPath: 'inset(50%)',
93
+ height: '1px',
94
+ margin: '-1px',
95
+ overflow: 'hidden',
96
+ padding: 0,
97
+ position: 'absolute',
98
+ width: '1px',
99
+ whiteSpace: 'nowrap'
100
+ });
101
+
102
+ this.assertiveLog = this.createLog('assertive');
103
+ this.node.appendChild(this.assertiveLog);
104
+
105
+ this.politeLog = this.createLog('polite');
106
+ this.node.appendChild(this.politeLog);
107
+
108
+ document.body.prepend(this.node);
109
+ }
110
+ }
111
+
112
+ isAttached() {
113
+ return this.node?.isConnected;
89
114
  }
90
115
 
91
116
  createLog(ariaLive: string) {
@@ -105,18 +130,24 @@ class LiveAnnouncer {
105
130
  this.node = null;
106
131
  }
107
132
 
108
- announce(message: string, assertiveness = 'assertive', timeout = LIVEREGION_TIMEOUT_DELAY) {
133
+ announce(message: Message, assertiveness = 'assertive', timeout = LIVEREGION_TIMEOUT_DELAY) {
109
134
  if (!this.node) {
110
135
  return;
111
136
  }
112
137
 
113
138
  let node = document.createElement('div');
114
- node.textContent = message;
139
+ if (typeof message === 'object') {
140
+ // To read an aria-labelledby, the element must have an appropriate role, such as img.
141
+ node.setAttribute('role', 'img');
142
+ node.setAttribute('aria-labelledby', message['aria-labelledby']);
143
+ } else {
144
+ node.textContent = message;
145
+ }
115
146
 
116
147
  if (assertiveness === 'assertive') {
117
- this.assertiveLog.appendChild(node);
148
+ this.assertiveLog?.appendChild(node);
118
149
  } else {
119
- this.politeLog.appendChild(node);
150
+ this.politeLog?.appendChild(node);
120
151
  }
121
152
 
122
153
  if (message !== '') {
@@ -131,11 +162,11 @@ class LiveAnnouncer {
131
162
  return;
132
163
  }
133
164
 
134
- if (!assertiveness || assertiveness === 'assertive') {
165
+ if ((!assertiveness || assertiveness === 'assertive') && this.assertiveLog) {
135
166
  this.assertiveLog.innerHTML = '';
136
167
  }
137
168
 
138
- if (!assertiveness || assertiveness === 'polite') {
169
+ if ((!assertiveness || assertiveness === 'polite') && this.politeLog) {
139
170
  this.politeLog.innerHTML = '';
140
171
  }
141
172
  }