1
- import PropTypes from 'prop-types' ;
2
1
import React , { forwardRef , useCallback , useRef , useState } from 'react' ;
3
2
import styled from 'styled-components' ;
4
3
import { remSize , prop } from '../../theme' ;
5
4
import { useModalClose } from '../../common/useModalClose' ;
6
5
import DownArrowIcon from '../../images/down-filled-triangle.svg' ;
7
6
8
- // TODO: enable arrow keys to navigate options from list
9
- const DropdownWrapper = styled . ul `
7
+ enum DropdownMenuAlignment {
8
+ RIGHT = 'right' ,
9
+ LEFT = 'left'
10
+ }
11
+
12
+ interface StyledDropdownMenuProps {
13
+ align : DropdownMenuAlignment ;
14
+ }
15
+
16
+ const DropdownWrapper = styled . ul < StyledDropdownMenuProps > `
10
17
background-color: ${ prop ( 'Modal.background' ) } ;
11
18
border: 1px solid ${ prop ( 'Modal.border' ) } ;
12
19
box-shadow: 0 0 18px 0 ${ prop ( 'shadowColor' ) } ;
13
20
color: ${ prop ( 'primaryTextColor' ) } ;
14
21
15
22
position: absolute;
16
- right: ${ ( props ) => ( props . right ? 0 : 'initial' ) } ;
17
- left: ${ ( props ) => ( props . left ? 0 : 'initial' ) } ;
23
+ right: ${ ( props ) =>
24
+ props . align === DropdownMenuAlignment . RIGHT ? 0 : 'initial' } ;
25
+ left: ${ ( props ) =>
26
+ props . align === DropdownMenuAlignment . LEFT ? 0 : 'initial' } ;
18
27
19
- ${ ( props ) => props . align === 'right' && 'right: 0;' }
20
- ${ ( props ) => props . align === 'left' && 'left: 0;' }
28
+ ${ ( props ) => props . align === DropdownMenuAlignment . RIGHT && 'right: 0;' }
29
+ ${ ( props ) => props . align === DropdownMenuAlignment . LEFT && 'left: 0;' }
21
30
22
31
23
32
text-align: left;
@@ -72,15 +81,34 @@ const DropdownWrapper = styled.ul`
72
81
}
73
82
` ;
74
83
75
- const DropdownMenu = forwardRef (
84
+ export interface DropdownMenuProps extends StyledDropdownMenuProps {
85
+ /**
86
+ * Provide <MenuItem> elements as children to control the contents of the menu.
87
+ */
88
+ children : React . ReactNode ;
89
+ /**
90
+ * Can optionally override the contents of the button which opens the menu.
91
+ * Defaults to <DownArrowIcon>
92
+ */
93
+ anchor ?: React . ReactNode ;
94
+ 'aria-label' : string ;
95
+ className ?: string ;
96
+ classes ?: {
97
+ button ?: string ;
98
+ list ?: string ;
99
+ } ;
100
+ maxHeight ?: string ;
101
+ }
102
+
103
+ export const DropdownMenu = forwardRef < HTMLDivElement , DropdownMenuProps > (
76
104
(
77
105
{
78
106
children,
79
107
anchor,
80
108
'aria-label' : ariaLabel ,
81
- align,
82
- className,
83
- classes,
109
+ align = DropdownMenuAlignment . RIGHT ,
110
+ className = '' ,
111
+ classes = { } ,
84
112
maxHeight
85
113
} ,
86
114
ref
@@ -92,7 +120,7 @@ const DropdownMenu = forwardRef(
92
120
93
121
const close = useCallback ( ( ) => setIsOpen ( false ) , [ setIsOpen ] ) ;
94
122
95
- const anchorRef = useModalClose ( close , ref ) ;
123
+ const anchorRef = useModalClose < HTMLDivElement > ( close , ref ) ;
96
124
97
125
const toggle = useCallback ( ( ) => {
98
126
setIsOpen ( ( prevState ) => ! prevState ) ;
@@ -116,7 +144,7 @@ const DropdownMenu = forwardRef(
116
144
< button
117
145
className = { classes . button }
118
146
aria-label = { ariaLabel }
119
- tabIndex = "0"
147
+ tabIndex = { 0 }
120
148
onClick = { toggle }
121
149
onBlur = { handleBlur }
122
150
onFocus = { handleFocus }
@@ -133,7 +161,7 @@ const DropdownMenu = forwardRef(
133
161
} }
134
162
onBlur = { handleBlur }
135
163
onFocus = { handleFocus }
136
- style = { maxHeight && { maxHeight, overflowY : 'auto' } }
164
+ style = { maxHeight ? { maxHeight, overflowY : 'auto' } : undefined }
137
165
>
138
166
{ children }
139
167
</ DropdownWrapper >
@@ -142,33 +170,3 @@ const DropdownMenu = forwardRef(
142
170
) ;
143
171
}
144
172
) ;
145
-
146
- DropdownMenu . propTypes = {
147
- /**
148
- * Provide <MenuItem> elements as children to control the contents of the menu.
149
- */
150
- children : PropTypes . node . isRequired ,
151
- /**
152
- * Can optionally override the contents of the button which opens the menu.
153
- * Defaults to <DownArrowIcon>
154
- */
155
- anchor : PropTypes . node ,
156
- 'aria-label' : PropTypes . string . isRequired ,
157
- align : PropTypes . oneOf ( [ 'left' , 'right' ] ) ,
158
- className : PropTypes . string ,
159
- classes : PropTypes . shape ( {
160
- button : PropTypes . string ,
161
- list : PropTypes . string
162
- } ) ,
163
- maxHeight : PropTypes . string
164
- } ;
165
-
166
- DropdownMenu . defaultProps = {
167
- anchor : null ,
168
- align : 'right' ,
169
- className : '' ,
170
- classes : { } ,
171
- maxHeight : undefined
172
- } ;
173
-
174
- export default DropdownMenu ;
0 commit comments