Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F121681475
MenuList.js
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Sun, Jul 13, 03:03
Size
9 KB
Mime Type
text/x-java
Expires
Tue, Jul 15, 03:03 (2 d)
Engine
blob
Format
Raw Data
Handle
27373487
Attached To
rOACCT Open Access Compliance Check Tool (OACCT)
MenuList.js
View Options
import
_extends
from
"@babel/runtime/helpers/esm/extends"
;
import
_objectWithoutPropertiesLoose
from
"@babel/runtime/helpers/esm/objectWithoutPropertiesLoose"
;
const
_excluded
=
[
"actions"
,
"autoFocus"
,
"autoFocusItem"
,
"children"
,
"className"
,
"disabledItemsFocusable"
,
"disableListWrap"
,
"onKeyDown"
,
"variant"
];
import
*
as
React
from
'react'
;
import
{
isFragment
}
from
'react-is'
;
import
PropTypes
from
'prop-types'
;
import
ownerDocument
from
'../utils/ownerDocument'
;
import
List
from
'../List'
;
import
getScrollbarSize
from
'../utils/getScrollbarSize'
;
import
useForkRef
from
'../utils/useForkRef'
;
import
useEnhancedEffect
from
'../utils/useEnhancedEffect'
;
import
{
jsx
as
_jsx
}
from
"react/jsx-runtime"
;
function
nextItem
(
list
,
item
,
disableListWrap
)
{
if
(
list
===
item
)
{
return
list
.
firstChild
;
}
if
(
item
&&
item
.
nextElementSibling
)
{
return
item
.
nextElementSibling
;
}
return
disableListWrap
?
null
:
list
.
firstChild
;
}
function
previousItem
(
list
,
item
,
disableListWrap
)
{
if
(
list
===
item
)
{
return
disableListWrap
?
list
.
firstChild
:
list
.
lastChild
;
}
if
(
item
&&
item
.
previousElementSibling
)
{
return
item
.
previousElementSibling
;
}
return
disableListWrap
?
null
:
list
.
lastChild
;
}
function
textCriteriaMatches
(
nextFocus
,
textCriteria
)
{
if
(
textCriteria
===
undefined
)
{
return
true
;
}
let
text
=
nextFocus
.
innerText
;
if
(
text
===
undefined
)
{
// jsdom doesn't support innerText
text
=
nextFocus
.
textContent
;
}
text
=
text
.
trim
().
toLowerCase
();
if
(
text
.
length
===
0
)
{
return
false
;
}
if
(
textCriteria
.
repeating
)
{
return
text
[
0
]
===
textCriteria
.
keys
[
0
];
}
return
text
.
indexOf
(
textCriteria
.
keys
.
join
(
''
))
===
0
;
}
function
moveFocus
(
list
,
currentFocus
,
disableListWrap
,
disabledItemsFocusable
,
traversalFunction
,
textCriteria
)
{
let
wrappedOnce
=
false
;
let
nextFocus
=
traversalFunction
(
list
,
currentFocus
,
currentFocus
?
disableListWrap
:
false
);
while
(
nextFocus
)
{
// Prevent infinite loop.
if
(
nextFocus
===
list
.
firstChild
)
{
if
(
wrappedOnce
)
{
return
false
;
}
wrappedOnce
=
true
;
}
// Same logic as useAutocomplete.js
const
nextFocusDisabled
=
disabledItemsFocusable
?
false
:
nextFocus
.
disabled
||
nextFocus
.
getAttribute
(
'aria-disabled'
)
===
'true'
;
if
(
!
nextFocus
.
hasAttribute
(
'tabindex'
)
||
!
textCriteriaMatches
(
nextFocus
,
textCriteria
)
||
nextFocusDisabled
)
{
// Move to the next element.
nextFocus
=
traversalFunction
(
list
,
nextFocus
,
disableListWrap
);
}
else
{
nextFocus
.
focus
();
return
true
;
}
}
return
false
;
}
/**
* A permanently displayed menu following https://www.w3.org/WAI/ARIA/apg/patterns/menubutton/.
* It's exposed to help customization of the [`Menu`](/material-ui/api/menu/) component if you
* use it separately you need to move focus into the component manually. Once
* the focus is placed inside the component it is fully keyboard accessible.
*/
const
MenuList
=
/*#__PURE__*/
React
.
forwardRef
(
function
MenuList
(
props
,
ref
)
{
const
{
// private
// eslint-disable-next-line react/prop-types
actions
,
autoFocus
=
false
,
autoFocusItem
=
false
,
children
,
className
,
disabledItemsFocusable
=
false
,
disableListWrap
=
false
,
onKeyDown
,
variant
=
'selectedMenu'
}
=
props
,
other
=
_objectWithoutPropertiesLoose
(
props
,
_excluded
);
const
listRef
=
React
.
useRef
(
null
);
const
textCriteriaRef
=
React
.
useRef
({
keys
:
[],
repeating
:
true
,
previousKeyMatched
:
true
,
lastTime
:
null
});
useEnhancedEffect
(()
=>
{
if
(
autoFocus
)
{
listRef
.
current
.
focus
();
}
},
[
autoFocus
]);
React
.
useImperativeHandle
(
actions
,
()
=>
({
adjustStyleForScrollbar
:
(
containerElement
,
theme
)
=>
{
// Let's ignore that piece of logic if users are already overriding the width
// of the menu.
const
noExplicitWidth
=
!
listRef
.
current
.
style
.
width
;
if
(
containerElement
.
clientHeight
<
listRef
.
current
.
clientHeight
&&
noExplicitWidth
)
{
const
scrollbarSize
=
`
$
{
getScrollbarSize
(
ownerDocument
(
containerElement
))}
px
`
;
listRef
.
current
.
style
[
theme
.
direction
===
'rtl'
?
'paddingLeft'
:
'paddingRight'
]
=
scrollbarSize
;
listRef
.
current
.
style
.
width
=
`
calc
(
100
%
+
$
{
scrollbarSize
})
`
;
}
return
listRef
.
current
;
}
}),
[]);
const
handleKeyDown
=
event
=>
{
const
list
=
listRef
.
current
;
const
key
=
event
.
key
;
/**
* @type {Element} - will always be defined since we are in a keydown handler
* attached to an element. A keydown event is either dispatched to the activeElement
* or document.body or document.documentElement. Only the first case will
* trigger this specific handler.
*/
const
currentFocus
=
ownerDocument
(
list
).
activeElement
;
if
(
key
===
'ArrowDown'
)
{
// Prevent scroll of the page
event
.
preventDefault
();
moveFocus
(
list
,
currentFocus
,
disableListWrap
,
disabledItemsFocusable
,
nextItem
);
}
else
if
(
key
===
'ArrowUp'
)
{
event
.
preventDefault
();
moveFocus
(
list
,
currentFocus
,
disableListWrap
,
disabledItemsFocusable
,
previousItem
);
}
else
if
(
key
===
'Home'
)
{
event
.
preventDefault
();
moveFocus
(
list
,
null
,
disableListWrap
,
disabledItemsFocusable
,
nextItem
);
}
else
if
(
key
===
'End'
)
{
event
.
preventDefault
();
moveFocus
(
list
,
null
,
disableListWrap
,
disabledItemsFocusable
,
previousItem
);
}
else
if
(
key
.
length
===
1
)
{
const
criteria
=
textCriteriaRef
.
current
;
const
lowerKey
=
key
.
toLowerCase
();
const
currTime
=
performance
.
now
();
if
(
criteria
.
keys
.
length
>
0
)
{
// Reset
if
(
currTime
-
criteria
.
lastTime
>
500
)
{
criteria
.
keys
=
[];
criteria
.
repeating
=
true
;
criteria
.
previousKeyMatched
=
true
;
}
else
if
(
criteria
.
repeating
&&
lowerKey
!==
criteria
.
keys
[
0
])
{
criteria
.
repeating
=
false
;
}
}
criteria
.
lastTime
=
currTime
;
criteria
.
keys
.
push
(
lowerKey
);
const
keepFocusOnCurrent
=
currentFocus
&&
!
criteria
.
repeating
&&
textCriteriaMatches
(
currentFocus
,
criteria
);
if
(
criteria
.
previousKeyMatched
&&
(
keepFocusOnCurrent
||
moveFocus
(
list
,
currentFocus
,
false
,
disabledItemsFocusable
,
nextItem
,
criteria
)))
{
event
.
preventDefault
();
}
else
{
criteria
.
previousKeyMatched
=
false
;
}
}
if
(
onKeyDown
)
{
onKeyDown
(
event
);
}
};
const
handleRef
=
useForkRef
(
listRef
,
ref
);
/**
* the index of the item should receive focus
* in a `variant="selectedMenu"` it's the first `selected` item
* otherwise it's the very first item.
*/
let
activeItemIndex
=
-
1
;
// since we inject focus related props into children we have to do a lookahead
// to check if there is a `selected` item. We're looking for the last `selected`
// item and use the first valid item as a fallback
React
.
Children
.
forEach
(
children
,
(
child
,
index
)
=>
{
if
(
!
/*#__PURE__*/
React
.
isValidElement
(
child
))
{
return
;
}
if
(
process
.
env
.
NODE_ENV
!==
'production'
)
{
if
(
isFragment
(
child
))
{
console
.
error
([
"MUI: The Menu component doesn't accept a Fragment as a child."
,
'Consider providing an array instead.'
].
join
(
'\n'
));
}
}
if
(
!
child
.
props
.
disabled
)
{
if
(
variant
===
'selectedMenu'
&&
child
.
props
.
selected
)
{
activeItemIndex
=
index
;
}
else
if
(
activeItemIndex
===
-
1
)
{
activeItemIndex
=
index
;
}
}
});
const
items
=
React
.
Children
.
map
(
children
,
(
child
,
index
)
=>
{
if
(
index
===
activeItemIndex
)
{
const
newChildProps
=
{};
if
(
autoFocusItem
)
{
newChildProps
.
autoFocus
=
true
;
}
if
(
child
.
props
.
tabIndex
===
undefined
&&
variant
===
'selectedMenu'
)
{
newChildProps
.
tabIndex
=
0
;
}
return
/*#__PURE__*/
React
.
cloneElement
(
child
,
newChildProps
);
}
return
child
;
});
return
/*#__PURE__*/
_jsx
(
List
,
_extends
({
role
:
"menu"
,
ref
:
handleRef
,
className
:
className
,
onKeyDown
:
handleKeyDown
,
tabIndex
:
autoFocus
?
0
:
-
1
},
other
,
{
children
:
items
}));
});
process
.
env
.
NODE_ENV
!==
"production"
?
MenuList
.
propTypes
/* remove-proptypes */
=
{
// ----------------------------- Warning --------------------------------
// | These PropTypes are generated from the TypeScript type definitions |
// | To update them edit the d.ts file and run "yarn proptypes" |
// ----------------------------------------------------------------------
/**
* If `true`, will focus the `[role="menu"]` container and move into tab order.
* @default false
*/
autoFocus
:
PropTypes
.
bool
,
/**
* If `true`, will focus the first menuitem if `variant="menu"` or selected item
* if `variant="selectedMenu"`.
* @default false
*/
autoFocusItem
:
PropTypes
.
bool
,
/**
* MenuList contents, normally `MenuItem`s.
*/
children
:
PropTypes
.
node
,
/**
* @ignore
*/
className
:
PropTypes
.
string
,
/**
* If `true`, will allow focus on disabled items.
* @default false
*/
disabledItemsFocusable
:
PropTypes
.
bool
,
/**
* If `true`, the menu items will not wrap focus.
* @default false
*/
disableListWrap
:
PropTypes
.
bool
,
/**
* @ignore
*/
onKeyDown
:
PropTypes
.
func
,
/**
* The variant to use. Use `menu` to prevent selected items from impacting the initial focus
* and the vertical alignment relative to the anchor element.
* @default 'selectedMenu'
*/
variant
:
PropTypes
.
oneOf
([
'menu'
,
'selectedMenu'
])
}
:
void
0
;
export
default
MenuList
;
Event Timeline
Log In to Comment