1- import PropTypes from 'prop-types' ;
21import React , { forwardRef , useCallback , useRef , useState } from 'react' ;
32import styled from 'styled-components' ;
43import { remSize , prop } from '../../theme' ;
54import { useModalClose } from '../../common/useModalClose' ;
65import DownArrowIcon from '../../images/down-filled-triangle.svg' ;
76
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 > `
1017 background-color: ${ prop ( 'Modal.background' ) } ;
1118 border: 1px solid ${ prop ( 'Modal.border' ) } ;
1219 box-shadow: 0 0 18px 0 ${ prop ( 'shadowColor' ) } ;
1320 color: ${ prop ( 'primaryTextColor' ) } ;
1421
1522 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' } ;
1827
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;' }
2130
2231
2332 text-align: left;
@@ -72,15 +81,34 @@ const DropdownWrapper = styled.ul`
7281 }
7382` ;
7483
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 > (
76104 (
77105 {
78106 children,
79107 anchor,
80108 'aria-label' : ariaLabel ,
81- align,
82- className,
83- classes,
109+ align = DropdownMenuAlignment . RIGHT ,
110+ className = '' ,
111+ classes = { } ,
84112 maxHeight
85113 } ,
86114 ref
@@ -92,7 +120,7 @@ const DropdownMenu = forwardRef(
92120
93121 const close = useCallback ( ( ) => setIsOpen ( false ) , [ setIsOpen ] ) ;
94122
95- const anchorRef = useModalClose ( close , ref ) ;
123+ const anchorRef = useModalClose < HTMLDivElement > ( close , ref ) ;
96124
97125 const toggle = useCallback ( ( ) => {
98126 setIsOpen ( ( prevState ) => ! prevState ) ;
@@ -116,7 +144,7 @@ const DropdownMenu = forwardRef(
116144 < button
117145 className = { classes . button }
118146 aria-label = { ariaLabel }
119- tabIndex = "0"
147+ tabIndex = { 0 }
120148 onClick = { toggle }
121149 onBlur = { handleBlur }
122150 onFocus = { handleFocus }
@@ -133,7 +161,7 @@ const DropdownMenu = forwardRef(
133161 } }
134162 onBlur = { handleBlur }
135163 onFocus = { handleFocus }
136- style = { maxHeight && { maxHeight, overflowY : 'auto' } }
164+ style = { maxHeight ? { maxHeight, overflowY : 'auto' } : undefined }
137165 >
138166 { children }
139167 </ DropdownWrapper >
@@ -142,33 +170,3 @@ const DropdownMenu = forwardRef(
142170 ) ;
143171 }
144172) ;
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