mirror of
https://github.com/NoRedInk/noredink-ui.git
synced 2025-01-03 03:46:37 +03:00
Generalize the FocusTrap module
This commit is contained in:
parent
90bdd4c703
commit
7beb363b6e
@ -7,8 +7,7 @@ module Nri.Ui.FocusTrap.V1 exposing (FocusTrap, toAttribute)
|
||||
-}
|
||||
|
||||
import Accessibility.Styled as Html
|
||||
import Html.Styled.Events as Events
|
||||
import Json.Decode as Decode exposing (Decoder)
|
||||
import Nri.Ui.WhenFocusLeaves.V1 as WhenFocusLeaves
|
||||
|
||||
|
||||
{-| Defines how focus will wrap in reponse to tab keypresses in a part of the UI.
|
||||
@ -28,53 +27,13 @@ type alias FocusTrap msg =
|
||||
-}
|
||||
toAttribute : FocusTrap msg -> Html.Attribute msg
|
||||
toAttribute { firstId, lastId, focus } =
|
||||
onTab <|
|
||||
\elementId shiftKey ->
|
||||
-- if the user tabs back while on the first id,
|
||||
-- we want to wrap around to the last id.
|
||||
if elementId == firstId && shiftKey then
|
||||
Decode.succeed
|
||||
{ message = focus lastId
|
||||
, preventDefault = True
|
||||
, stopPropagation = False
|
||||
}
|
||||
|
||||
else if elementId == lastId && not shiftKey then
|
||||
-- if the user tabs forward while on the last id,
|
||||
-- we want to wrap around to the first id.
|
||||
Decode.succeed
|
||||
{ message = focus firstId
|
||||
, preventDefault = True
|
||||
, stopPropagation = False
|
||||
}
|
||||
|
||||
else
|
||||
Decode.fail "No need to intercept the key press"
|
||||
|
||||
|
||||
onTab :
|
||||
(String
|
||||
-> Bool
|
||||
-> Decoder { message : msg, preventDefault : Bool, stopPropagation : Bool }
|
||||
)
|
||||
-> Html.Attribute msg
|
||||
onTab do =
|
||||
Events.custom "keydown"
|
||||
(Decode.andThen
|
||||
(\( id, keyCode, shiftKey ) ->
|
||||
if keyCode == 9 then
|
||||
do id shiftKey
|
||||
|
||||
else
|
||||
Decode.fail "No need to intercept the key press"
|
||||
)
|
||||
decodeKeydown
|
||||
)
|
||||
|
||||
|
||||
decodeKeydown : Decoder ( String, Int, Bool )
|
||||
decodeKeydown =
|
||||
Decode.map3 (\id keyCode shiftKey -> ( id, keyCode, shiftKey ))
|
||||
(Decode.at [ "target", "id" ] Decode.string)
|
||||
(Decode.field "keyCode" Decode.int)
|
||||
(Decode.field "shiftKey" Decode.bool)
|
||||
WhenFocusLeaves.toAttribute
|
||||
{ firstId = firstId
|
||||
, lastId = lastId
|
||||
, -- if the user tabs back while on the first id,
|
||||
-- we want to wrap around to the last id.
|
||||
tabBackAction = focus lastId
|
||||
, -- if the user tabs forward while on the last id,
|
||||
-- we want to wrap around to the first id.
|
||||
tabForwardAction = focus firstId
|
||||
}
|
||||
|
78
src/Nri/Ui/WhenFocusLeaves/V1.elm
Normal file
78
src/Nri/Ui/WhenFocusLeaves/V1.elm
Normal file
@ -0,0 +1,78 @@
|
||||
module Nri.Ui.WhenFocusLeaves.V1 exposing (toAttribute)
|
||||
|
||||
{-| Listen for when the focus leaves the area, and then do an action.
|
||||
|
||||
@docs toAttribute
|
||||
|
||||
-}
|
||||
|
||||
import Accessibility.Styled as Html
|
||||
import Html.Styled.Events as Events
|
||||
import Json.Decode as Decode exposing (Decoder)
|
||||
|
||||
|
||||
{-| Attach this attribute to add a focus watcher to an HTML element and define
|
||||
what to do in reponse to tab keypresses in a part of the UI.
|
||||
|
||||
The ids referenced here are expected to correspond to elements in the container
|
||||
we are adding the attribute to.
|
||||
|
||||
-}
|
||||
toAttribute :
|
||||
{ firstId : String
|
||||
, lastId : String
|
||||
, tabBackAction : msg
|
||||
, tabForwardAction : msg
|
||||
}
|
||||
-> Html.Attribute msg
|
||||
toAttribute { firstId, lastId, tabBackAction, tabForwardAction } =
|
||||
onTab <|
|
||||
\elementId shiftKey ->
|
||||
-- if the user tabs back while on the first id,
|
||||
-- we execute the action
|
||||
if elementId == firstId && shiftKey then
|
||||
Decode.succeed
|
||||
{ message = tabBackAction
|
||||
, preventDefault = False
|
||||
, stopPropagation = False
|
||||
}
|
||||
|
||||
else if elementId == lastId && not shiftKey then
|
||||
-- if the user tabs forward while on the last id,
|
||||
-- we want to wrap around to the first id.
|
||||
Decode.succeed
|
||||
{ message = tabForwardAction
|
||||
, preventDefault = False
|
||||
, stopPropagation = False
|
||||
}
|
||||
|
||||
else
|
||||
Decode.fail "No need to intercept the key press"
|
||||
|
||||
|
||||
onTab :
|
||||
(String
|
||||
-> Bool
|
||||
-> Decoder { message : msg, preventDefault : Bool, stopPropagation : Bool }
|
||||
)
|
||||
-> Html.Attribute msg
|
||||
onTab do =
|
||||
Events.custom "keydown"
|
||||
(Decode.andThen
|
||||
(\( id, keyCode, shiftKey ) ->
|
||||
if keyCode == 9 then
|
||||
do id shiftKey
|
||||
|
||||
else
|
||||
Decode.fail "No need to intercept the key press"
|
||||
)
|
||||
decodeKeydown
|
||||
)
|
||||
|
||||
|
||||
decodeKeydown : Decoder ( String, Int, Bool )
|
||||
decodeKeydown =
|
||||
Decode.map3 (\id keyCode shiftKey -> ( id, keyCode, shiftKey ))
|
||||
(Decode.at [ "target", "id" ] Decode.string)
|
||||
(Decode.field "keyCode" Decode.int)
|
||||
(Decode.field "shiftKey" Decode.bool)
|
Loading…
Reference in New Issue
Block a user