-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Expand file tree
/
Copy pathLinkDefinitions.tsx
More file actions
126 lines (113 loc) · 3.96 KB
/
LinkDefinitions.tsx
File metadata and controls
126 lines (113 loc) · 3.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import { useStyles } from '@msinternal/botframework-webchat-styles/react';
import { hooks } from 'botframework-webchat-api';
import cx from 'classnames';
import random from 'math-random';
import React, {
Children,
useCallback,
useMemo,
useRef,
useState,
type ComponentType,
type ReactEventHandler,
type ReactNode
} from 'react';
import { ComponentIcon } from '../Icon';
import styles from './LinkDefinitions.module.css';
const { useLocalizer, useStyleOptions } = hooks;
const { count: childrenCount, map: childrenMap } = Children;
type Props<TAccessoryProps> = Readonly<{
accessoryComponentType: ComponentType<TAccessoryProps>;
accessoryProps: TAccessoryProps;
children?: ReactNode | undefined;
}>;
const REFERENCE_LIST_HEADER_IDS = {
one: 'REFERENCE_LIST_HEADER_ONE',
few: 'REFERENCE_LIST_HEADER_FEW',
many: 'REFERENCE_LIST_HEADER_MANY',
other: 'REFERENCE_LIST_HEADER_OTHER',
two: 'REFERENCE_LIST_HEADER_TWO'
};
function uniqueId(count = Infinity) {
return (
random()
// eslint-disable-next-line no-magic-numbers
.toString(36)
// eslint-disable-next-line no-magic-numbers
.substring(2, 2 + count)
);
}
// Following @types/react to use {} for props.
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
const LinkDefinitions = <TAccessoryProps extends {}>({
accessoryComponentType,
accessoryProps,
children
}: Props<TAccessoryProps>) => {
const [id] = useState(() => `webchat-link-definitions-${uniqueId()}`);
const localizeWithPlural = useLocalizer({ plural: true });
const summaryRef = useRef<HTMLElement>(null);
const classNames = useStyles(styles);
const [{ referenceListDefaultOpen }] = useStyleOptions();
const headerText = localizeWithPlural(REFERENCE_LIST_HEADER_IDS, childrenCount(children));
const defaultOpenString = useMemo(() => (referenceListDefaultOpen ? 'true' : 'false'), [referenceListDefaultOpen]);
const handleToggle = useCallback<ReactEventHandler<HTMLDetailsElement>>(event => {
const summary = summaryRef.current;
const details = event.target;
if (summary && details && details instanceof HTMLDetailsElement) {
const isDetailsOpen = details.open.toString();
summary.setAttribute('aria-expanded', isDetailsOpen);
summary.setAttribute('aria-pressed', isDetailsOpen);
}
}, []);
return (
<details
className={classNames['link-definitions']}
// eslint-disable-next-line react/forbid-dom-props
id={id}
onToggle={handleToggle}
open={referenceListDefaultOpen}
>
<summary
aria-controls={id}
aria-expanded={defaultOpenString}
aria-pressed={defaultOpenString}
className={classNames['link-definitions__header']}
ref={summaryRef}
role="button"
>
<div
className={cx(
classNames['link-definitions__header-section'],
classNames['link-definitions__header-section--left']
)}
>
<div className={classNames['link-definitions__header-text']}>{headerText}</div>
<ComponentIcon appearance="text" className={classNames['link-definitions__header-chevron']} icon="chevron" />
</div>
<div
className={cx(
classNames['link-definitions__header-section'],
classNames['link-definitions__header-section--right']
)}
>
{accessoryComponentType && (
<div className={classNames['link-definitions__header-accessory']}>
{React.createElement(accessoryComponentType, accessoryProps)}
</div>
)}
</div>
</summary>
<div className={classNames['link-definitions__list']} role="list">
{childrenMap(children, child => (
<div className={classNames['link-definitions__list-item']} role="listitem">
{child}
</div>
))}
</div>
</details>
);
};
LinkDefinitions.displayName = 'LinkDefinitions';
// TODO: [P1] Add memo().
export default LinkDefinitions;