noredink-ui/src-0.18/Nri/Ui/Dropdown/V2.elm
Richard Feldman e2907d9ba2 Prep for 0.19 dual-publish (#163)
* Use elm-css 16.0.0

* 💀 Ui.Checkbox V1 and V2

* s/Css.Foreign/Css.Global/g

* 💀 Nri.Ui.Styles.V1

* 💀 BannerAlert.V1

* 💀 Modal.V1

* 💀 Dropdown.V1

* 💀 Select.V1 and V2

* 💀 Alert.V1

* 💀 Button.V1 and V2

* 💀 Divider.V1

* 💀 Icon.V1 and V2

* 💀 Outline.V1

* 💀 SegmentedControl.V1-V5

* 💀 TextArea.V1 and V2

* 💀 TextInput.V1

* delete the rest of the modules

* actually more deletions

* InputStyles v1 is unused

* move to src-0.18

* do the 0.19 upgrade

* select options are addressable by index

* elm-css 16

* update scripts

* elm-format

* Update V2.elm

* put the nbsp back

* elm-format validation for both versions
2018-11-12 15:38:19 -08:00

164 lines
5.0 KiB
Elm

module Nri.Ui.Dropdown.V2 exposing
( ViewOptionEntry
, view
, viewWithoutLabel
)
{-|
@docs ViewOptionEntry
@docs view
@docs viewWithoutLabel
-}
import Accessibility.Styled.Style exposing (invisible)
import Css
import Dict
import Html.Styled as Html exposing (..)
import Html.Styled.Attributes exposing (..)
import Html.Styled.Events exposing (on, targetValue)
import Json.Decode
import Nri.Ui.Colors.V1
import Nri.Ui.Util exposing (dashify)
import String
{-| This dropdown has atypical select tag behavior.
This dropdown, when closed, will display some default text, no matter
what is actually selected.
When the dropdown is opened, the first option will display that default text,
be selected, and disabled. The option the user has actually chosen's displayText
won't show up at all.
-}
type alias ViewOptionEntry a =
{ isSelected : Bool
, val : a
, displayText : String
}
{-| -}
view : String -> List (ViewOptionEntry a) -> (a -> msg) -> Html msg
view defaultDisplayText optionEntries onSelect =
viewWithLabelMarkup True defaultDisplayText optionEntries onSelect
{-| -}
viewWithoutLabel : String -> List (ViewOptionEntry a) -> (a -> msg) -> Html msg
viewWithoutLabel defaultDisplayText optionEntries onSelect =
viewWithLabelMarkup False defaultDisplayText optionEntries onSelect
viewWithLabelMarkup : Bool -> String -> List (ViewOptionEntry a) -> (a -> msg) -> Html msg
viewWithLabelMarkup displayLabel defaultDisplayText optionEntries onSelect =
let
defaultOption =
option
[ selected True
, disabled True
]
[ text defaultDisplayText ]
options =
List.map (viewOption defaultDisplayText) optionEntries
identifier =
dashify (String.toLower defaultDisplayText)
changeHandlers : List (Attribute msg)
changeHandlers =
case optionEntries of
[] ->
-- If we have no entries, there's no point in having
-- a change handler; it could never fire anyway.
[]
{ val } :: _ ->
let
-- When we get a `String` from the `onChange` event,
-- look up the `msg` that goes with it.
msgForValue : String -> msg
msgForValue valString =
case Dict.get valString msgsByVal of
Just msg ->
msg
Nothing ->
-- If it's somehow not in the Dict
-- (which should never happen),
-- fall back on a known `msg` value:
-- the first one in the list.
onSelect val
msgsByVal : Dict.Dict String msg
msgsByVal =
optionEntries
|> List.map (\{ val } -> ( toString val, onSelect val ))
|> Dict.fromList
in
[ on "change" (Json.Decode.map msgForValue targetValue) ]
in
span []
[ label
(if displayLabel then
[ for identifier ]
else
[ for identifier, invisible ]
)
[ text defaultDisplayText ]
, Html.styled select
[ dropdownStyles ]
([ id identifier
, {-
NOTE: form controls are also being styled on a global CSS that
sets a margin.
It would be better to remove the margin from the component and
decide whether we need it or not in each use case.
It will be really hard to track down and review all of those,
so we reset the margin here as a workaround.
-}
style [ ( "margin", "0" ) ]
]
++ changeHandlers
)
(defaultOption :: options)
]
viewOption : String -> ViewOptionEntry a -> Html msg
viewOption defaultDisplayText { isSelected, val, displayText } =
if isSelected then
option
[ value <| toString val
, selected isSelected
, style [ ( "display", "none" ) ]
]
[ text defaultDisplayText ]
else
option
[ value <| toString val
, selected isSelected
]
[ text displayText ]
dropdownStyles : Css.Style
dropdownStyles =
Css.batch
[ Css.backgroundColor Nri.Ui.Colors.V1.white
, Css.border3 (Css.px 1) Css.solid Nri.Ui.Colors.V1.gray75
, Css.borderRadius (Css.px 8)
, Css.color Nri.Ui.Colors.V1.gray20
, Css.cursor Css.pointer
, Css.fontSize (Css.px 15)
, Css.height (Css.px 45)
]