mirror of
https://github.com/NoRedInk/noredink-ui.git
synced 2024-11-27 03:14:25 +03:00
Merge pull request #487 from NoRedInk/ink/email-inputs
Ink/email inputs
This commit is contained in:
commit
97c4b65b25
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user