mirror of
https://github.com/NoRedInk/noredink-ui.git
synced 2024-11-14 03:48:13 +03:00
Bring disclosure back and keep alog with dialog
This commit is contained in:
parent
0a9695073f
commit
dc59910584
@ -1,7 +1,7 @@
|
||||
module Nri.Ui.Menu.V3 exposing
|
||||
( view, button, custom, Config
|
||||
, Attribute, Button, ButtonAttribute
|
||||
, alignment, isDisabled, menuWidth, buttonId, menuId, menuZIndex, opensOnHover, dialog
|
||||
, alignment, isDisabled, menuWidth, buttonId, menuId, menuZIndex, opensOnHover, disclosure, dialog
|
||||
, Alignment(..)
|
||||
, icon, wrapping, hasBorder, buttonWidth
|
||||
, TitleWrapping(..)
|
||||
@ -30,7 +30,7 @@ A togglable menu view and related buttons.
|
||||
|
||||
## Menu attributes
|
||||
|
||||
@docs alignment, isDisabled, menuWidth, buttonId, menuId, menuZIndex, opensOnHover, dialog
|
||||
@docs alignment, isDisabled, menuWidth, buttonId, menuId, menuZIndex, opensOnHover, disclosure, dialog
|
||||
@docs Alignment
|
||||
|
||||
|
||||
@ -121,6 +121,7 @@ type alias ButtonConfig =
|
||||
|
||||
type Purpose
|
||||
= NavMenu
|
||||
| Disclosure { lastId : String }
|
||||
| Dialog ExitFocusManager
|
||||
|
||||
|
||||
@ -215,6 +216,21 @@ opensOnHover value =
|
||||
Attribute <| \config -> { config | opensOnHover = value }
|
||||
|
||||
|
||||
{-| Makes the menu behave as a disclosure.
|
||||
|
||||
For more information, please read [Disclosure (Show/Hide) pattern](https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/).
|
||||
|
||||
You will need to pass in the last focusable element in the disclosed content in order for:
|
||||
|
||||
- any focusable elements in the disclosed content to be keyboard accessible
|
||||
- the disclosure to close appropriately when the user tabs past all of the disclosed content
|
||||
|
||||
-}
|
||||
disclosure : { lastId : String } -> Attribute msg
|
||||
disclosure exitFocusManager =
|
||||
Attribute (\config -> { config | purpose = Disclosure exitFocusManager })
|
||||
|
||||
|
||||
{-| Makes the menu behave as a dialog.
|
||||
|
||||
For more information, please read [Dialog pattern](https://w3c.github.io/aria-practices/examples/dialog-modal/dialog.html/).
|
||||
@ -485,6 +501,30 @@ viewCustom config =
|
||||
)
|
||||
]
|
||||
|
||||
Disclosure { lastId } ->
|
||||
Key.onKeyDown
|
||||
[ Key.escape
|
||||
(config.focusAndToggle
|
||||
{ isOpen = False
|
||||
, focus = Just config.buttonId
|
||||
}
|
||||
)
|
||||
, WhenFocusLeaves.toDecoder
|
||||
{ firstId = config.buttonId
|
||||
, lastId = lastId
|
||||
, tabBackAction =
|
||||
config.focusAndToggle
|
||||
{ isOpen = False
|
||||
, focus = Nothing
|
||||
}
|
||||
, tabForwardAction =
|
||||
config.focusAndToggle
|
||||
{ isOpen = False
|
||||
, focus = Nothing
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
Dialog { firstId, lastId } ->
|
||||
Key.onKeyDownPreventDefault
|
||||
[ Key.escape
|
||||
@ -552,7 +592,7 @@ viewCustom config =
|
||||
[ Aria.disabled config.isDisabled
|
||||
, -- Whether the menu is open or closed, move to the
|
||||
-- first menu item if the "down" arrow is pressed
|
||||
-- as long as it's not a Dialog
|
||||
-- as long as it's not a Disclosed or Dialog
|
||||
case ( config.purpose, maybeFirstFocusableElementId, maybeLastFocusableElementId ) of
|
||||
( NavMenu, Just firstFocusableElementId, Just lastFocusableElementId ) ->
|
||||
Key.onKeyDownPreventDefault
|
||||
@ -606,6 +646,11 @@ viewCustom config =
|
||||
, Aria.controls [ config.menuId ]
|
||||
]
|
||||
|
||||
Disclosure _ ->
|
||||
[ Aria.expanded config.isOpen
|
||||
, Aria.controls [ config.menuId ]
|
||||
]
|
||||
|
||||
Dialog _ ->
|
||||
[ AttributesExtra.none ]
|
||||
)
|
||||
@ -631,6 +676,9 @@ viewCustom config =
|
||||
NavMenu ->
|
||||
Role.menu
|
||||
|
||||
Disclosure _ ->
|
||||
AttributesExtra.none
|
||||
|
||||
Dialog _ ->
|
||||
Role.dialog
|
||||
, Aria.labelledBy config.buttonId
|
||||
|
@ -262,6 +262,35 @@ view ellieLinkConfig state =
|
||||
button buttonAttributes [ text "Custom Menu trigger button" ]
|
||||
}
|
||||
)
|
||||
, ( "Menu.button (with Menu.disclosure)"
|
||||
, Menu.view
|
||||
(menuAttributes
|
||||
++ [ Menu.buttonId "with_controls__button"
|
||||
, Menu.menuId "with_controls__menu"
|
||||
, Menu.disclosure { lastId = "login__button" }
|
||||
]
|
||||
)
|
||||
{ isOpen = isOpen "with_controls"
|
||||
, focusAndToggle = FocusAndToggle "with_controls"
|
||||
, entries =
|
||||
[ Menu.entry "username-input" <|
|
||||
\attrs ->
|
||||
div []
|
||||
[ TextInput.view "Username"
|
||||
[ TextInput.id "username-input"
|
||||
]
|
||||
, TextInput.view "Password" []
|
||||
, Button.button "Log in disclosure"
|
||||
[ Button.primary
|
||||
, Button.id "login__button"
|
||||
, Button.fillContainerWidth
|
||||
, Button.css [ Css.marginTop (Css.px 15) ]
|
||||
]
|
||||
]
|
||||
]
|
||||
, button = Menu.button defaultButtonAttributes "Log In"
|
||||
}
|
||||
)
|
||||
, ( "Menu.button (with Menu.dialog)"
|
||||
, Menu.view
|
||||
(menuAttributes
|
||||
@ -280,7 +309,7 @@ view ellieLinkConfig state =
|
||||
[ TextInput.id "username-input"
|
||||
]
|
||||
, TextInput.view "Password" []
|
||||
, Button.button "Log in"
|
||||
, Button.button "Log in dialog"
|
||||
[ Button.primary
|
||||
, Button.id "login__button"
|
||||
, Button.fillContainerWidth
|
||||
|
@ -64,6 +64,15 @@ pressTabKey { targetDetails } =
|
||||
pressKey { targetDetails = targetDetails, keyCode = 9, shiftKey = False }
|
||||
|
||||
|
||||
pressTabBackKey :
|
||||
{ targetDetails : List ( String, Encode.Value ) }
|
||||
-> List Selector
|
||||
-> ProgramTest model msg effect
|
||||
-> ProgramTest model msg effect
|
||||
pressTabBackKey { targetDetails } =
|
||||
pressKey { targetDetails = targetDetails, keyCode = 9, shiftKey = True }
|
||||
|
||||
|
||||
pressEscKey :
|
||||
{ targetDetails : List ( String, Encode.Value ) }
|
||||
-> List Selector
|
||||
|
@ -52,6 +52,26 @@ spec =
|
||||
|> pressEscKey { targetId = Nothing }
|
||||
|> ensureViewHasNot (menuContentSelector menuContent)
|
||||
|> ProgramTest.done
|
||||
, describe "disclosure" <|
|
||||
[ test "Close on esc key" <|
|
||||
\() ->
|
||||
program [ Menu.disclosure { lastId = "last-button" } ]
|
||||
-- Menu opens on mouse click and closes on esc key
|
||||
|> clickMenuButton
|
||||
|> ensureViewHas (menuContentSelector menuContent)
|
||||
|> pressEscKey { targetId = Nothing }
|
||||
|> ensureViewHasNot (menuContentSelector menuContent)
|
||||
|> ProgramTest.done
|
||||
, test "Closes after tab on lastId" <|
|
||||
\() ->
|
||||
program [ Menu.disclosure { lastId = "last-button" } ]
|
||||
|> clickMenuButton
|
||||
|> ensureViewHas (menuContentSelector menuContent)
|
||||
-- NOTE: unable to simulate pressTabKey with other targetId since those decoders will fail
|
||||
|> pressTabKey { targetId = Just "last-button" }
|
||||
|> ensureViewHasNot (menuContentSelector menuContent)
|
||||
|> ProgramTest.done
|
||||
]
|
||||
, describe "dialog" <|
|
||||
[ test "Close on esc key" <|
|
||||
\() ->
|
||||
@ -62,14 +82,23 @@ spec =
|
||||
|> pressEscKey { targetId = Nothing }
|
||||
|> ensureViewHasNot (menuContentSelector menuContent)
|
||||
|> ProgramTest.done
|
||||
, test "Closes after tab on lastId" <|
|
||||
, test "Selects firstId after tab on lastId" <|
|
||||
\() ->
|
||||
program [ Menu.dialog { firstId = "hello-button", lastId = "last-button" } ]
|
||||
|> clickMenuButton
|
||||
|> ensureViewHas (menuContentSelector menuContent)
|
||||
-- NOTE: unable to simulate pressTabKey with other targetId since those decoders will fail
|
||||
|> pressTabKey { targetId = Just "last-button" }
|
||||
|> ensureViewHasNot (menuContentSelector menuContent)
|
||||
|> ensureViewHas (menuContentSelector menuContent)
|
||||
|> ProgramTest.done
|
||||
, test "Selects lastId after back tab on firstId" <|
|
||||
\() ->
|
||||
program [ Menu.dialog { firstId = "hello-button", lastId = "last-button" } ]
|
||||
|> clickMenuButton
|
||||
|> ensureViewHas (menuContentSelector menuContent)
|
||||
-- NOTE: unable to simulate pressTabKey with other targetId since those decoders will fail
|
||||
|> pressTabBackKey { targetId = Just "hellow-button" }
|
||||
|> ensureViewHas (menuContentSelector menuContent)
|
||||
|> ProgramTest.done
|
||||
]
|
||||
]
|
||||
@ -182,6 +211,13 @@ pressTabKey { targetId } =
|
||||
[ Selector.class "Container" ]
|
||||
|
||||
|
||||
pressTabBackKey : { targetId : Maybe String } -> ProgramTest model msg effect -> ProgramTest model msg effect
|
||||
pressTabBackKey { targetId } =
|
||||
KeyboardHelpers.pressTabBackKey
|
||||
{ targetDetails = targetDetails targetId }
|
||||
[ Selector.class "Container" ]
|
||||
|
||||
|
||||
pressEscKey : { targetId : Maybe String } -> ProgramTest model msg effect -> ProgramTest model msg effect
|
||||
pressEscKey { targetId } =
|
||||
KeyboardHelpers.pressEscKey
|
||||
|
Loading…
Reference in New Issue
Block a user