1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 | import {AriaLabelingProps} from '@react-types/shared';
|
14 | import {useLayoutEffect} from './useLayoutEffect';
|
15 | import {useState} from 'react';
|
16 |
|
17 | let descriptionId = 0;
|
18 | const descriptionNodes = new Map<string, {refCount: number, element: Element}>();
|
19 |
|
20 | export function useDescription(description: string): AriaLabelingProps {
|
21 | let [id, setId] = useState(undefined);
|
22 |
|
23 | useLayoutEffect(() => {
|
24 | if (!description) {
|
25 | return;
|
26 | }
|
27 |
|
28 | let desc = descriptionNodes.get(description);
|
29 | if (!desc) {
|
30 | let id = `react-aria-description-${descriptionId++}`;
|
31 | setId(id);
|
32 |
|
33 | let node = document.createElement('div');
|
34 | node.id = id;
|
35 | node.style.display = 'none';
|
36 | node.textContent = description;
|
37 | document.body.appendChild(node);
|
38 | desc = {refCount: 0, element: node};
|
39 | descriptionNodes.set(description, desc);
|
40 | } else {
|
41 | setId(desc.element.id);
|
42 | }
|
43 |
|
44 | desc.refCount++;
|
45 | return () => {
|
46 | if (--desc.refCount === 0) {
|
47 | desc.element.remove();
|
48 | descriptionNodes.delete(description);
|
49 | }
|
50 | };
|
51 | }, [description]);
|
52 |
|
53 | return {
|
54 | 'aria-describedby': description ? id : undefined
|
55 | };
|
56 | }
|