Merge pull request #487 from NoRedInk/ink/email-inputs

Ink/email inputs
This commit is contained in:
Aaron VonderHaar 2020-04-10 15:13:10 -07:00 committed by GitHub
commit 97c4b65b25
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 117 additions and 103 deletions

View File

@ -12,7 +12,7 @@ jq -r -f script/axe-report.jq "$JSON_FILE"
# Hey there! Did this script tell you to check out this file because the
# expected error count went down? Well done! Just change this number to the new
# value.
TARGET_ERRORS=12
TARGET_ERRORS=1
# ideally we'd fail on any failures, but we have had a bunch build up over time!
# So right now, we need to fail if the error count is not exactly what we

View File

@ -2,7 +2,7 @@ module Nri.Ui.TextInput.V5 exposing
( Model
, view, writing
, generateId
, number, float, text, password
, InputType, number, float, text, password, email
)
{-|
@ -19,12 +19,12 @@ module Nri.Ui.TextInput.V5 exposing
## Input types
@docs number, float, text, password
@docs InputType, number, float, text, password, email
-}
import Accessibility.Styled.Style as Accessibility
import Css exposing (batch, center, position, px, relative, textAlign)
import Css exposing (center, position, px, relative, textAlign)
import Css.Global
import Html.Styled as Html exposing (..)
import Html.Styled.Attributes as Attributes exposing (..)
@ -54,6 +54,8 @@ type InputType value
{ toString : value -> String
, fromString : String -> value
, fieldType : String
, inputMode : Maybe String
, autocomplete : Maybe String
}
@ -65,6 +67,8 @@ text =
{ toString = identity
, fromString = identity
, fieldType = "text"
, inputMode = Nothing
, autocomplete = Nothing
}
@ -76,6 +80,8 @@ number =
{ toString = Maybe.map String.fromInt >> Maybe.withDefault ""
, fromString = String.toInt
, fieldType = "number"
, inputMode = Nothing
, autocomplete = Nothing
}
@ -87,6 +93,8 @@ float =
{ toString = Maybe.map String.fromFloat >> Maybe.withDefault ""
, fromString = String.toFloat
, fieldType = "number"
, inputMode = Nothing
, autocomplete = Nothing
}
@ -98,6 +106,26 @@ password =
{ toString = identity
, fromString = identity
, fieldType = "password"
, inputMode = Nothing
, autocomplete = Just "current-password"
}
{-| An input that is optimized for email entry
NOTE: this uses `inputmode="email"` so that mobile devices will use the email keyboard,
but not `type="email"` because that would enable browser-provided validation which is inconsistent and at odds
with our validation UI.
-}
email : InputType String
email =
InputType
{ toString = identity
, fromString = identity
, fieldType = "text"
, inputMode = Just "email"
, autocomplete = Just "email"
}
@ -128,6 +156,11 @@ view_ theme model =
else
[]
maybeAttr attr maybeValue =
maybeValue
|> Maybe.map attr
|> Maybe.withDefault Extra.none
in
div
[ Attributes.css [ position relative ]
@ -151,9 +184,11 @@ view_ theme model =
, placeholder model.placeholder
, value (inputType.toString model.value)
, onInput (inputType.fromString >> model.onInput)
, Maybe.withDefault Extra.none (Maybe.map Events.onBlur model.onBlur)
, maybeAttr Events.onBlur model.onBlur
, autofocus model.autofocus
, type_ inputType.fieldType
, maybeAttr (attribute "inputmode") inputType.inputMode
, maybeAttr (attribute "autocomplete") inputType.autocomplete
, class "override-sass-styles"
, Attributes.attribute "aria-invalid" <|
if model.isInError then

View File

@ -6,10 +6,11 @@ module Examples.TextInput exposing (Msg, State, example)
-}
import Accessibility.Styled as Html exposing (..)
import Category exposing (Category(..))
import Debug.Control as Control exposing (Control)
import Dict exposing (Dict)
import Example exposing (Example)
import Html.Styled as Html
import Nri.Ui.Heading.V2 as Heading
import Nri.Ui.TextInput.V5 as TextInput
@ -20,14 +21,24 @@ type Msg
| SetNumberInput (Maybe Int)
| SetFloatInput (Maybe Float)
| SetPassword String
| UpdateControl (Control ExampleConfig)
{-| -}
type alias State =
{ numberInputValue : Maybe Int
, floatInputValue : Maybe Float
, textInputValues : Dict Id String
, stringInputValues : Dict Id String
, passwordInputValue : String
, control : Control ExampleConfig
}
type alias ExampleConfig =
{ showLabel : Bool
, label : String
, isInError : Bool
, placeholder : String
}
@ -41,137 +52,96 @@ example =
, subscriptions = \_ -> Sub.none
, view =
\state ->
let
exampleConfig =
Control.currentValue state.control
in
[ Html.div []
[ TextInput.view
{ label = "Criterion"
, isInError = False
, placeholder = "For example, \"Something!!\""
, value = Maybe.withDefault "" <| Dict.get 1 state.textInputValues
[ Control.view UpdateControl state.control
|> Html.fromUnstyled
, Heading.h3 [] [ text "TextInput.view { type_ = TextInput.text }" ]
, TextInput.view
{ label = exampleConfig.label ++ " (text)"
, isInError = exampleConfig.isInError
, placeholder = exampleConfig.placeholder
, showLabel = exampleConfig.showLabel
, value = Maybe.withDefault "" <| Dict.get 1 state.stringInputValues
, onInput = SetTextInput 1
, onBlur = Nothing
, autofocus = False
, type_ = TextInput.text
, showLabel = True
}
, Html.br [] []
, Heading.h3 [] [ text "... type_ = TextInput.number" ]
, TextInput.view
{ label = "Points"
, isInError = False
, placeholder = "enter a number"
{ label = exampleConfig.label ++ " (number)"
, isInError = exampleConfig.isInError
, placeholder = exampleConfig.placeholder
, showLabel = exampleConfig.showLabel
, value = state.numberInputValue
, onInput = SetNumberInput
, onBlur = Nothing
, autofocus = False
, type_ = TextInput.number
, showLabel = True
}
, Html.br [] []
, Heading.h3 [] [ text "... type_ = TextInput.float" ]
, TextInput.view
{ label = "Points (decimal)"
, isInError = False
, placeholder = "enter a decimal"
{ label = exampleConfig.label ++ " (float)"
, isInError = exampleConfig.isInError
, placeholder = exampleConfig.placeholder
, showLabel = exampleConfig.showLabel
, value = state.floatInputValue
, onInput = SetFloatInput
, onBlur = Nothing
, autofocus = False
, type_ = TextInput.float
, showLabel = True
}
, Html.br [] []
, Heading.h3 [] [ text "... type_ = TextInput.password" ]
, TextInput.view
{ label = "Password"
, isInError = False
, placeholder = ""
{ label = exampleConfig.label ++ " (password)"
, isInError = exampleConfig.isInError
, placeholder = exampleConfig.placeholder
, showLabel = exampleConfig.showLabel
, value = state.passwordInputValue
, onInput = SetPassword
, onBlur = Nothing
, autofocus = False
, type_ = TextInput.password
, showLabel = True
}
, Html.br [] []
, Heading.h3 [] [ text "... type_ = TextInput.email" ]
, TextInput.view
{ label = "Error"
, isInError = True
, placeholder = "Wrong!"
, value = state.numberInputValue
, onInput = SetNumberInput
, onBlur = Nothing
, autofocus = False
, type_ = TextInput.number
, showLabel = True
}
, Heading.h3 [] [ Html.text "invisible label" ]
, TextInput.view
{ label = "Invisible label text input"
, isInError = False
, placeholder = "For example, \"Something!!\""
, value = Maybe.withDefault "" <| Dict.get 2 state.textInputValues
{ label = exampleConfig.label ++ " (email)"
, isInError = exampleConfig.isInError
, placeholder = exampleConfig.placeholder
, showLabel = exampleConfig.showLabel
, value = Maybe.withDefault "" <| Dict.get 2 state.stringInputValues
, onInput = SetTextInput 2
, onBlur = Nothing
, autofocus = False
, type_ = TextInput.text
, showLabel = False
, type_ = TextInput.email
}
, Html.br [] []
, TextInput.view
{ label = "Invisible label text input with error"
, placeholder = "Everything you type is wrong!"
, value = Maybe.withDefault "" <| Dict.get 3 state.textInputValues
, onInput = SetTextInput 3
, onBlur = Nothing
, isInError = True
, autofocus = False
, type_ = TextInput.text
, showLabel = False
}
, Heading.h3 [] [ Html.text "Writing Style" ]
, Heading.h3 [] [ Html.text "TextInput.writing { type_ = TextInput.text }" ]
, TextInput.writing
{ label = "Writing!"
, isInError = False
, placeholder = "Writing is good for me and my family"
, value = Maybe.withDefault "" <| Dict.get 4 state.textInputValues
{ label = exampleConfig.label ++ " (writing)"
, isInError = exampleConfig.isInError
, placeholder = exampleConfig.placeholder
, value = Maybe.withDefault "" <| Dict.get 4 state.stringInputValues
, onInput = SetTextInput 4
, onBlur = Nothing
, autofocus = False
, type_ = TextInput.text
, showLabel = True
, showLabel = exampleConfig.showLabel
}
, Html.br [] []
, Heading.h3 [] [ text "onBlur demonstration" ]
, TextInput.writing
{ label = "Writing with errors!"
, isInError = True
, placeholder = "Oopsie!"
, value = Maybe.withDefault "" <| Dict.get 5 state.textInputValues
, onInput = SetTextInput 5
, onBlur = Nothing
, autofocus = False
, type_ = TextInput.text
, showLabel = True
}
, Html.br [] []
, TextInput.writing
{ label = "Writing without labels!"
, isInError = False
, placeholder = "No label on this writing input!"
, value = Maybe.withDefault "" <| Dict.get 6 state.textInputValues
, onInput = SetTextInput 6
, onBlur = Nothing
, autofocus = False
, type_ = TextInput.text
, showLabel = False
}
, Html.br [] []
, TextInput.writing
{ label = "Writing onBlur demonstration!"
, isInError = False
, placeholder = "Click away to blur!"
, value = Maybe.withDefault "" <| Dict.get 7 state.textInputValues
{ label = exampleConfig.label ++ " (onBlur)"
, isInError = exampleConfig.isInError
, placeholder = exampleConfig.placeholder
, value = Maybe.withDefault "" <| Dict.get 7 state.stringInputValues
, onInput = SetTextInput 7
, onBlur = Just (SetTextInput 7 "Blurred!")
, autofocus = False
, type_ = TextInput.text
, showLabel = True
, showLabel = exampleConfig.showLabel
}
]
]
@ -183,8 +153,14 @@ init : State
init =
{ numberInputValue = Nothing
, floatInputValue = Nothing
, textInputValues = Dict.empty
, stringInputValues = Dict.empty
, passwordInputValue = ""
, control =
Control.record ExampleConfig
|> Control.field "showLabel" (Control.bool True)
|> Control.field "label" (Control.string "Assignment name")
|> Control.field "isInError" (Control.bool False)
|> Control.field "placeholder" (Control.string "Learning with commas")
}
@ -193,7 +169,7 @@ update : Msg -> State -> ( State, Cmd Msg )
update msg state =
case msg of
SetTextInput id textInputValue ->
( { state | textInputValues = Dict.insert id textInputValue state.textInputValues }, Cmd.none )
( { state | stringInputValues = Dict.insert id textInputValue state.stringInputValues }, Cmd.none )
SetNumberInput numberInputValue ->
( { state | numberInputValue = numberInputValue }, Cmd.none )
@ -204,6 +180,9 @@ update msg state =
SetPassword password ->
( { state | passwordInputValue = password }, Cmd.none )
UpdateControl newControl ->
( { state | control = newControl }, Cmd.none )
-- INTERNAL

View File

@ -7,9 +7,9 @@
"elm-version": "0.19.0",
"dependencies": {
"direct": {
"avh4/elm-debug-controls": "2.0.0",
"elm/browser": "1.0.1",
"elm/core": "1.0.2",
"avh4/elm-debug-controls": "2.2.1",
"elm/browser": "1.0.2",
"elm/core": "1.0.5",
"elm/html": "1.0.0",
"elm/json": "1.1.3",
"elm/parser": "1.1.0",
@ -18,7 +18,7 @@
"elm/url": "1.0.0",
"elm-community/string-extra": "4.0.1",
"pablohirafuji/elm-markdown": "2.0.5",
"rtfeldman/elm-css": "16.0.0",
"rtfeldman/elm-css": "16.0.1",
"rtfeldman/elm-sorter-experiment": "2.1.1",
"tesk9/accessible-html": "4.0.0",
"tesk9/accessible-html-with-css": "2.1.1",
@ -27,11 +27,11 @@
"wernerdegroot/listzipper": "4.0.0"
},
"indirect": {
"NoRedInk/datetimepicker-legacy": "1.0.1",
"NoRedInk/datetimepicker-legacy": "1.0.4",
"Skinney/murmur3": "2.0.8",
"elm/time": "1.0.0",
"elm/virtual-dom": "1.0.2",
"justinmimbs/date": "3.1.2",
"justinmimbs/date": "3.2.0",
"justinmimbs/time-extra": "1.1.0",
"rtfeldman/elm-hex": "1.0.0"
}