Skip to content

Instantly share code, notes, and snippets.

@kyasu1
Created May 26, 2019 00:27
Show Gist options
  • Save kyasu1/6641af49b22e097cf149907bcc18018e to your computer and use it in GitHub Desktop.
Save kyasu1/6641af49b22e097cf149907bcc18018e to your computer and use it in GitHub Desktop.
a dropdown in @elmlang that opens when you either click or tab into it and closes when you click again or click outside
-- https://twitter.com/unsoundscapes/status/1132405048338780161
-- https://ellie-app.com/5DBFLkbVVCwa1
module Main exposing (main)
import Browser
import Html exposing (Html, button, div, text)
import Html.Attributes exposing (class)
import Html.Events exposing (on, onClick, onFocus)
import Json.Decode as Decode exposing (Decoder, Value)
type alias Model =
{ expand : Bool, justFocused : Bool }
initialModel : Model
initialModel =
{ expand = False, justFocused = False }
type Msg
= Toggle
| Collapse
| Focus
update : Msg -> Model -> Model
update msg model =
case msg of
Collapse ->
{ expand = False, justFocused = False }
Focus ->
if not model.expand then
{ justFocused = True, expand = True }
else
model
Toggle ->
if not model.justFocused then
{ model | expand = not model.expand }
else
{ model | justFocused = False }
view : Model -> Html Msg
view { expand } =
div [ class "dropdown", on "focusout" onFocusout ]
[ button
[ onClick Toggle
, onFocus Focus
]
[ text "toggle" ]
, div []
(if expand then
[ div [] [ button [] [ text "item1" ] ]
, div [] [ button [] [ text "item2" ] ]
, div [] [ button [] [ text "item3" ] ]
, div [] [ button [] [ text "item4" ] ]
]
else
[]
)
]
main : Program () Model Msg
main =
Browser.sandbox
{ init = initialModel
, view = view
, update = update
}
onFocusout : Decoder Msg
onFocusout =
Decode.field "relatedTarget" outsideDropdown
|> Decode.andThen
(\outside ->
if outside then
Decode.succeed Collapse
else
Decode.fail "inside the dropdown"
)
outsideDropdown : Decoder Bool
outsideDropdown =
Decode.oneOf
[ Decode.andThen
(\id ->
if id == "dropdown" then
Decode.succeed False
else
Decode.fail "continue"
)
(Decode.field "className" Decode.string)
, Decode.lazy (\_ -> Decode.field "parentNode" outsideDropdown)
, Decode.succeed True
]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment