Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
C
coopwire-hypothesis
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
孙灵跃 Leon Sun
coopwire-hypothesis
Commits
c65e2b09
Commit
c65e2b09
authored
Jan 12, 2023
by
Lyza Danger Gardner
Committed by
Lyza Gardner
Jan 19, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Convert Menu to TS
parent
9c2c147d
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
69 additions
and
47 deletions
+69
-47
Menu.tsx
src/sidebar/components/Menu.tsx
+69
-47
No files found.
src/sidebar/components/Menu.
js
→
src/sidebar/components/Menu.
tsx
View file @
c65e2b09
import
classnames
from
'classnames'
;
import
classnames
from
'classnames'
;
import
{
useElementShouldClose
}
from
'@hypothesis/frontend-shared'
;
import
{
useElementShouldClose
}
from
'@hypothesis/frontend-shared'
;
import
{
MenuExpandIcon
}
from
'@hypothesis/frontend-shared/lib/next'
;
import
{
MenuExpandIcon
}
from
'@hypothesis/frontend-shared/lib/next'
;
import
type
{
ComponentChildren
}
from
'preact'
;
import
{
useCallback
,
useEffect
,
useRef
,
useState
}
from
'preact/hooks'
;
import
{
useCallback
,
useEffect
,
useRef
,
useState
}
from
'preact/hooks'
;
import
MenuArrow
from
'./MenuArrow'
;
import
MenuArrow
from
'./MenuArrow'
;
...
@@ -13,37 +14,62 @@ import MenuKeyboardNavigation from './MenuKeyboardNavigation';
...
@@ -13,37 +14,62 @@ import MenuKeyboardNavigation from './MenuKeyboardNavigation';
*/
*/
let
ignoreNextClick
=
false
;
let
ignoreNextClick
=
false
;
/**
export
type
MenuProps
=
{
* @typedef MenuProps
/**
* @prop {'left'|'right'} [align] -
* Whether the menu content is aligned with the left (default) or right edges
* Whether the menu content is aligned with the left (default) or right edges of the
* of the toggle element.
* toggle element.
*/
* @prop {string} [arrowClass] -
align
?:
'left'
|
'right'
;
* Additional CSS class for the arrow caret at the edge of the menu content that "points"
* toward the menu's toggle button. This can be used to adjust the position of that caret
/**
* respective to the toggle button.
* Additional CSS class for the arrow caret at the edge of the menu content
* @prop {object|string} [label] - Label element for the toggle button that hides and shows the menu.
* that "points" toward the menu's toggle button. This can be used to adjust
* @prop {object} [children] -
* the position of that caret respective to the toggle button.
* Menu items and sections to display in the content area of the menu. These are typically
*/
* `MenuSection` and `MenuItem` components, but other custom content is also allowed.
arrowClass
?:
string
;
* @prop {boolean} [containerPositioned] -
* Whether the menu elements should be positioned relative to the Menu container. When
/**
* `false`, the consumer is responsible for positioning.
* Label element or string for the toggle button that hides and shows the menu
* @prop {string} [contentClass] - Additional CSS classes to apply to the menu.
* @prop {boolean} [defaultOpen] - Whether the menu is open or closed when initially rendered.
* Ignored if `open` is present.
* @prop {(open: boolean) => void} [onOpenChanged] - Callback invoked when the menu is
* opened or closed. This can be used, for example, to reset any ephemeral state that the
* menu content may have.
* @prop {boolean} [open] - Whether the menu is currently open; overrides internal state
* management for openness. External components managing state in this way should
* also pass an `onOpenChanged` handler to respond when the user closes the menu.
* @prop {string} title -
* A title for the menu. This is important for accessibility if the menu's toggle button
* has only an icon as a label.
* @prop {boolean} [menuIndicator] -
* Whether to display an indicator next to the label that there is a dropdown menu.
*/
*/
label
:
ComponentChildren
;
/** Menu content, typically `MenuSection` and `MenuItem` components */
children
:
ComponentChildren
;
/**
* Whether the menu elements should be positioned relative to the Menu
* container. When `false`, the consumer is responsible for positioning.
*/
containerPositioned
?:
boolean
;
/** Additional CSS classes to apply to the Menu */
contentClass
?:
string
;
/**
* Whether the menu is open when initially rendered. Ignored if `open` is
* present.
*/
defaultOpen
?:
boolean
;
/** Whether to render an (arrow) indicator next to the Menu label */
menuIndicator
?:
boolean
;
/** Callback when the Menu is opened or closed. */
onOpenChanged
?:
(
open
:
boolean
)
=>
void
;
/**
* Whether the Menu is currently open, when the Menu is being used as a
* controlled component. In these cases, an `onOpenChanged` handler should
* be provided to respond to the user opening or closing the menu.
*/
open
?:
boolean
;
/**
* A title for the menu. This is important for accessibility if the menu's
* toggle button has only an icon as a label.
*/
title
:
string
;
};
const
noop
=
()
=>
{};
const
noop
=
()
=>
{};
...
@@ -64,8 +90,6 @@ const noop = () => {};
...
@@ -64,8 +90,6 @@ const noop = () => {};
* <MenuItem label="Log out"/>
* <MenuItem label="Log out"/>
* </MenuSection>
* </MenuSection>
* </Menu>
* </Menu>
*
* @param {MenuProps} props
*/
*/
export
default
function
Menu
({
export
default
function
Menu
({
align
=
'left'
,
align
=
'left'
,
...
@@ -79,9 +103,9 @@ export default function Menu({
...
@@ -79,9 +103,9 @@ export default function Menu({
onOpenChanged
,
onOpenChanged
,
menuIndicator
=
true
,
menuIndicator
=
true
,
title
,
title
,
})
{
}
:
MenuProps
)
{
/** @type {[boolean, (open: boolean) => void]} */
let
[
isOpen
,
setOpen
]:
[
boolean
,
(
open
:
boolean
)
=>
void
]
=
let
[
isOpen
,
setOpen
]
=
useState
(
defaultOpen
);
useState
(
defaultOpen
);
if
(
typeof
open
===
'boolean'
)
{
if
(
typeof
open
===
'boolean'
)
{
isOpen
=
open
;
isOpen
=
open
;
setOpen
=
onOpenChanged
||
noop
;
setOpen
=
onOpenChanged
||
noop
;
...
@@ -96,11 +120,12 @@ export default function Menu({
...
@@ -96,11 +120,12 @@ export default function Menu({
}
}
},
[
isOpen
,
onOpenChanged
]);
},
[
isOpen
,
onOpenChanged
]);
// Toggle menu when user presses toggle button. The menu is shown on mouse
/**
// press for a more responsive/native feel but also handles a click event for
* Toggle menu when user presses toggle button. The menu is shown on mouse
// activation via other input methods.
* press for a more responsive/native feel but also handles a click event for
/** @param {Event} event */
* activation via other input methods.
const
toggleMenu
=
event
=>
{
*/
const
toggleMenu
=
(
event
:
Event
)
=>
{
// If the menu was opened on press, don't close it again on the subsequent
// If the menu was opened on press, don't close it again on the subsequent
// mouse up ("click") event.
// mouse up ("click") event.
if
(
event
.
type
===
'mousedown'
)
{
if
(
event
.
type
===
'mousedown'
)
{
...
@@ -122,18 +147,16 @@ export default function Menu({
...
@@ -122,18 +147,16 @@ export default function Menu({
//
//
// These handlers close the menu when the user taps or clicks outside the
// These handlers close the menu when the user taps or clicks outside the
// menu or presses Escape.
// menu or presses Escape.
const
menuRef
=
/** @type {{ current: HTMLDivElement }} */
(
useRef
()
);
const
menuRef
=
useRef
<
HTMLDivElement
|
null
>
(
null
);
// Menu element should close via `closeMenu` whenever it's open and there
// Menu element should close via `closeMenu` whenever it's open and there
// are user interactions outside of it (e.g. clicks) in the document
// are user interactions outside of it (e.g. clicks) in the document
useElementShouldClose
(
menuRef
,
isOpen
,
closeMenu
);
useElementShouldClose
(
menuRef
,
isOpen
,
closeMenu
);
/** @param {Event} e */
const
stopPropagation
=
(
e
:
Event
)
=>
e
.
stopPropagation
();
const
stopPropagation
=
e
=>
e
.
stopPropagation
();
// It should also close if the user presses a key which activates menu items.
// It should also close if the user presses a key which activates menu items.
/** @param {KeyboardEvent} event */
const
handleMenuKeyDown
=
(
event
:
KeyboardEvent
)
=>
{
const
handleMenuKeyDown
=
event
=>
{
const
key
=
event
.
key
;
const
key
=
event
.
key
;
if
(
key
===
'Enter'
||
key
===
' '
)
{
if
(
key
===
'Enter'
||
key
===
' '
)
{
// The browser will not open the link if the link element is removed
// The browser will not open the link if the link element is removed
...
@@ -145,7 +168,6 @@ export default function Menu({
...
@@ -145,7 +168,6 @@ export default function Menu({
}
}
};
};
/** @type {{ position: 'relative'|'static' }} */
const
containerStyle
=
{
const
containerStyle
=
{
position
:
containerPositioned
?
'relative'
:
'static'
,
position
:
containerPositioned
?
'relative'
:
'static'
,
};
};
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment