1- import React , { useRef , forwardRef , useCallback , useState , MutableRefObject , RefObject } from 'react'
1+ import React , { useRef , forwardRef , useCallback , useState , MutableRefObject , RefObject , useEffect } from 'react'
22import Box from '../Box'
33import sx , { merge , BetterSystemStyleObject , SxProp } from '../sx'
44import { UnderlineNavContext } from './UnderlineNavContext'
5- import { ActionMenu } from '../ActionMenu'
6- import { ActionList } from '../ActionList'
75import { useResizeObserver , ResizeObserverEntry } from '../hooks/useResizeObserver'
86import CounterLabel from '../CounterLabel'
97import { useTheme } from '../ThemeProvider'
@@ -12,6 +10,13 @@ import {ChildWidthArray, ResponsiveProps} from './types'
1210import { moreBtnStyles , getDividerStyle , getNavStyles , ulStyles , moreMenuStyles , menuItemStyles , GAP } from './styles'
1311import styled from 'styled-components'
1412import { LoadingCounter } from './LoadingCounter'
13+ import { Button } from '../Button'
14+ import Link from '../Link'
15+ import { useFocusZone } from '../hooks/useFocusZone'
16+ import { FocusKeys , getAnchoredPosition } from '@primer/behaviors'
17+ import { ChevronDownIcon , TriangleDownIcon } from '@primer/octicons-react'
18+ import { useOnEscapePress } from '../hooks/useOnEscapePress'
19+ import { useOnOutsideClick } from '../hooks/useOnOutsideClick'
1520
1621export type UnderlineNavProps = {
1722 'aria-label' ?: React . AriaAttributes [ 'aria-label' ]
@@ -131,6 +136,8 @@ export const UnderlineNav = forwardRef(
131136 const navRef = ( forwardedRef ?? backupRef ) as MutableRefObject < HTMLElement >
132137 const listRef = useRef < HTMLUListElement > ( null )
133138 const moreMenuRef = useRef < HTMLLIElement > ( null )
139+ const moreMenuBtnRef = useRef < HTMLButtonElement > ( null )
140+ const containerRef = React . useRef < HTMLUListElement > ( null )
134141
135142 const { theme} = useTheme ( )
136143
@@ -241,6 +248,49 @@ export const UnderlineNav = forwardRef(
241248 // eslint-disable-next-line no-console
242249 console . warn ( 'Use the `aria-label` prop to provide an accessible label for assistive technology' )
243250 }
251+ const [ isWidgetOpen , setIsWidgetOpen ] = useState ( false )
252+
253+ const closeOverlay = React . useCallback ( ( ) => {
254+ setIsWidgetOpen ( false )
255+ } , [ setIsWidgetOpen ] )
256+
257+ const toggleOverlay = React . useCallback ( ( ) => {
258+ setIsWidgetOpen ( ! isWidgetOpen )
259+ } , [ setIsWidgetOpen , isWidgetOpen ] )
260+
261+ useOnOutsideClick ( { onClickOutside : closeOverlay , containerRef, ignoreClickRefs : [ moreMenuBtnRef ] } )
262+
263+ useFocusZone ( {
264+ containerRef : backupRef ,
265+ bindKeys : FocusKeys . ArrowVertical | FocusKeys . ArrowHorizontal | FocusKeys . HomeAndEnd | FocusKeys . Tab
266+ } )
267+
268+ useFocusZone ( {
269+ containerRef,
270+ bindKeys : FocusKeys . ArrowVertical | FocusKeys . ArrowHorizontal | FocusKeys . HomeAndEnd ,
271+ focusInStrategy : 'first'
272+ } )
273+
274+ useOnEscapePress (
275+ ( event : KeyboardEvent ) => {
276+ if ( isWidgetOpen ) {
277+ event . preventDefault ( )
278+ closeOverlay ( )
279+ }
280+ // onClose('escape')
281+ // event.preventDefault()
282+ } ,
283+ [ isWidgetOpen ]
284+ )
285+ const onAnchorClick = useCallback (
286+ ( event : React . MouseEvent < HTMLButtonElement > ) => {
287+ if ( event . defaultPrevented || event . button !== 0 ) {
288+ return
289+ }
290+ toggleOverlay ( )
291+ } ,
292+ [ toggleOverlay ]
293+ )
244294
245295 return (
246296 < UnderlineNavContext . Provider
@@ -271,46 +321,68 @@ export const UnderlineNav = forwardRef(
271321 { actions . length > 0 && (
272322 < MoreMenuListItem ref = { moreMenuRef } >
273323 < Box sx = { getDividerStyle ( theme ) } > </ Box >
274- < ActionMenu >
275- < ActionMenu . Button sx = { moreBtnStyles } > More</ ActionMenu . Button >
276- < ActionMenu . Overlay align = "end" >
277- < ActionList selectionVariant = "single" >
278- { actions . map ( ( action , index ) => {
279- const { children : actionElementChildren , ...actionElementProps } = action . props
280- return (
281- < Box key = { index } as = "li" >
282- < ActionList . Item
283- sx = { menuItemStyles }
284- as = { asNavItem }
285- { ...actionElementProps }
286- onSelect = { (
287- event : React . MouseEvent < HTMLLIElement > | React . KeyboardEvent < HTMLLIElement >
288- ) => {
289- swapMenuItemWithListItem ( action , index , event , updateListAndMenu )
290- setSelectEvent ( event )
291- } }
292- >
293- < Box
294- as = "span"
295- sx = { { display : 'flex' , alignItems : 'center' , justifyContent : 'space-between' } }
296- >
297- { actionElementChildren }
298-
299- { loadingCounters ? (
300- < LoadingCounter />
301- ) : (
302- actionElementProps . counter !== undefined && (
303- < CounterLabel > { actionElementProps . counter } </ CounterLabel >
304- )
305- ) }
306- </ Box >
307- </ ActionList . Item >
324+ < Button
325+ ref = { moreMenuBtnRef }
326+ sx = { moreBtnStyles }
327+ aria-controls = "disclosure-widget"
328+ aria-expanded = { isWidgetOpen }
329+ onClick = { onAnchorClick }
330+ trailingIcon = { TriangleDownIcon }
331+ >
332+ More
333+ </ Button >
334+
335+ < Box
336+ as = "ul"
337+ // @ts -ignore Box doesn't have type support for `ref` used in combination with `as`
338+ ref = { containerRef }
339+ id = "disclosure-widget"
340+ sx = { {
341+ position : 'absolute' ,
342+ top : '90%' ,
343+ boxShadow : '0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24)' ,
344+ borderRadius : '12px' ,
345+ right : '0' ,
346+ backgroundColor : `${ theme ?. colors . canvas . overlay } ` ,
347+ listStyle : 'none' ,
348+ padding : '8px' ,
349+ minWidth : '192px' ,
350+ maxWidth : '640px' ,
351+ display : isWidgetOpen ? 'block' : 'none'
352+ } }
353+ // onEscape={() => setIsWidgetOpen(false)}
354+ >
355+ { actions . map ( ( action , index ) => {
356+ const { children : actionElementChildren , ...actionElementProps } = action . props
357+ return (
358+ < Box key = { index } as = "li" >
359+ < a
360+ href = "#hello"
361+ // sx={menuItemStyles}
362+ // as={asNavItem}
363+ onClick = { ( event : React . MouseEvent < HTMLAnchorElement > ) => {
364+ swapMenuItemWithListItem ( action , index , event , updateListAndMenu )
365+ setSelectEvent ( event )
366+ closeOverlay ( )
367+ moreMenuBtnRef . current ?. focus ( )
368+ } }
369+ >
370+ < Box as = "span" sx = { { display : 'flex' , alignItems : 'center' , justifyContent : 'space-between' } } >
371+ { actionElementChildren }
372+
373+ { loadingCounters ? (
374+ < LoadingCounter />
375+ ) : (
376+ actionElementProps . counter !== undefined && (
377+ < CounterLabel > { actionElementProps . counter } </ CounterLabel >
378+ )
379+ ) }
308380 </ Box >
309- )
310- } ) }
311- </ ActionList >
312- </ ActionMenu . Overlay >
313- </ ActionMenu >
381+ </ a >
382+ </ Box >
383+ )
384+ } ) }
385+ </ Box >
314386 </ MoreMenuListItem >
315387 ) }
316388 </ NavigationList >
0 commit comments