diff --git a/src/Nri/Ui/Select/V1.elm b/src/Nri/Ui/Select/V1.elm new file mode 100644 index 00000000..361e5153 --- /dev/null +++ b/src/Nri/Ui/Select/V1.elm @@ -0,0 +1,87 @@ +module Nri.Ui.Select.V1 + exposing + ( Config + , customView + , view + ) + +{-| Build a select input. + + +# Configure + +@docs Config + + +# Render + +@docs view, customView + +-} + +import Dict +import Html exposing (..) +import Html.Attributes exposing (..) +import Html.Events exposing (..) +import Json.Decode exposing (Decoder, andThen, succeed) +import Nri.Ui.Util + + +{-| Select-specific Choice.Config +-} +type alias Config a = + { choices : List { label : String, value : a } + , current : a + } + + +{-| TODO: move this to View.Extra +-} +niceId : String -> a -> String +niceId prefix x = + x + |> toString + |> Nri.Ui.Util.removePunctuation + |> Nri.Ui.Util.dashify + |> (++) (prefix ++ "-") + + +{-| A normal select dropdown +-} +view : Config a -> Html a +view config = + customView [] config + + +{-| A select dropdown with custom attributes. +This should be phased out as the new Select style is implemented, +all pages should use the new, consistent style. +-} +customView : List (Html.Attribute a) -> Config a -> Html a +customView attributes config = + let + valueLookup = + -- TODO: probably worth using Lazy here, since choices won't change often + config.choices + |> List.map (\x -> ( niceId "nri-select" x.value, x.value )) + |> Dict.fromList + + decodeValue string = + Dict.get string valueLookup + |> Maybe.map Json.Decode.succeed + |> Maybe.withDefault (Json.Decode.fail ("Nri.Select: could not decode the value: " ++ toString string ++ "\nexpected one of: " ++ toString (Dict.keys valueLookup))) + + onSelectHandler = + on "change" (targetValue |> andThen decodeValue) + + viewChoice choice = + Html.option + [ Html.Attributes.id (niceId "nri-select" choice.value) + , Html.Attributes.value (niceId "nri-select" choice.value) + , Html.Attributes.selected (choice.value == config.current) + ] + [ Html.text choice.label ] + in + config.choices + |> List.map viewChoice + |> Html.select (onSelectHandler :: attributes) diff --git a/styleguide-app/Examples/Select.elm b/styleguide-app/Examples/Select.elm new file mode 100644 index 00000000..c6109598 --- /dev/null +++ b/styleguide-app/Examples/Select.elm @@ -0,0 +1,74 @@ +module Examples.Select + exposing + ( Msg + , State + , Value + , example + , init + , update + ) + +{-| + +@docs Msg +@docs State +@docs Value +@docs example +@docs init +@docs update + +-} + +import Html +import ModuleExample exposing (Category(..), ModuleExample) +import Nri.Ui.Select.V1 + + +{-| -} +type alias Value = + String + + +{-| -} +type Msg + = ConsoleLog String + + +{-| -} +type alias State value = + Nri.Ui.Select.V1.Config value + + +{-| -} +example : (Msg -> msg) -> State Value -> ModuleExample msg +example parentMessage state = + { filename = "ui/src/Nri/Select.elm" + , category = Inputs + , content = + [ Html.map (parentMessage << ConsoleLog) (Nri.Ui.Select.V1.view state) + ] + } + + +{-| -} +init : State Value +init = + { current = "" + , choices = + [ { label = "Tacos", value = "Tacos" } + , { label = "Burritos", value = "Burritos" } + , { label = "Enchiladas", value = "Enchiladas" } + ] + } + + +{-| -} +update : Msg -> State Value -> ( State Value, Cmd Msg ) +update msg state = + case msg of + ConsoleLog message -> + let + _ = + Debug.log "SelectExample" message + in + ( state, Cmd.none ) diff --git a/styleguide-app/NriModules.elm b/styleguide-app/NriModules.elm index 834638b3..5bb98b6a 100644 --- a/styleguide-app/NriModules.elm +++ b/styleguide-app/NriModules.elm @@ -6,6 +6,7 @@ import Examples.Colors import Examples.Fonts import Examples.Icon import Examples.SegmentedControl +import Examples.Select import Examples.Text import Examples.Text.Writing import Examples.TextArea as TextAreaExample @@ -23,6 +24,7 @@ import String.Extra type alias ModuleStates = { segmentedControlState : Examples.SegmentedControl.State + , selectState : Examples.Select.State Examples.Select.Value , textAreaExampleState : TextAreaExample.State } @@ -30,12 +32,14 @@ type alias ModuleStates = init : ModuleStates init = { segmentedControlState = Examples.SegmentedControl.init + , selectState = Examples.Select.init , textAreaExampleState = TextAreaExample.init } type Msg = SegmentedControlMsg Examples.SegmentedControl.Msg + | SelectMsg Examples.Select.Msg | ShowItWorked String String | TextAreaExampleMsg TextAreaExample.Msg | NoOp @@ -53,6 +57,15 @@ update msg moduleStates = , Cmd.map SegmentedControlMsg cmd ) + SelectMsg msg -> + let + ( selectState, cmd ) = + Examples.Select.update msg moduleStates.selectState + in + ( { moduleStates | selectState = selectState } + , Cmd.map SelectMsg cmd + ) + ShowItWorked group message -> let _ = @@ -95,6 +108,7 @@ nriThemedModules : ModuleStates -> List (ModuleExample Msg) nriThemedModules model = [ Examples.Icon.example , Examples.SegmentedControl.example SegmentedControlMsg model.segmentedControlState + , Examples.Select.example SelectMsg model.selectState , Examples.Text.example , Examples.Text.Writing.example , Examples.Fonts.example