Last active
July 6, 2017 14:39
-
-
Save mdgriffith/b2a59e77cb6e3467053a757366651cdf to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{- | |
Form elements could use some love as far as standardizing how they work. | |
Every form element has the following in common: | |
- a value (except button) | |
- a change event | |
- a label | |
- style | |
- label content | |
We can have every form input generate an `Input` type that can only be converted to an `Element` through labeling. | |
As far as I can see, this is what Tessa did for the A11y library: http://package.elm-lang.org/packages/tesk9/elm-html-a11y/2.1.0/Html-A11y | |
and it's awesome. | |
The standard pattern for form elements could be the following | |
formElement ChangeMsg style [] value | |
Here's what that might look like | |
-} | |
checkbox Change style [] True | |
-- For more involved checkbox styling | |
checkboxWith ChangeMsg True | |
{ checked = el CheckedStyle [] (text "✓") | |
, unchecked el UnChecked [] empty | |
} | |
-- Do we need the distinction between single line and multiline text? | |
textarea Change style [] "My Text Area!" | |
inputText Change style [] "Some text" | |
password Change style [] "superpass" | |
button Change style [] (text "Button text!") | |
-- Button's child can be any `el` | |
-- We can disable the form submit on the button as the default | |
-- Do we need to be able to re-enable it? | |
-- Radio Buttons | |
type Lunch = Burrito | Taco | |
radio ChangeRadio RadioStyle [] | |
[ option Burrito (text "A Burrito!") | |
, option Taco (text "A Taco!") | |
] | |
currentlySelected -- : Lunch | |
-- More involved styling | |
-- Communicate which element is selected | |
-- Be able to style the selected statement | |
radio ChangeRadio RadioStyle [] | |
[ optionWith Burrito | |
{ selected = text "Burrito!" | |
, unselected = text "Unselected burrito :(" | |
} | |
, option Taco (text "A Taco!") | |
] | |
currentlySelected -- : Lunch | |
-- The `<select>` element. | |
-- Do we even need a `<select>`? It's a weird, non-stylable subclass of a dropdown menu. Is there any advantage? | |
type Animal = Manatee | Pangolin | Bee | |
optionList ChangeSelection SelectStyle [] | |
[ option Manatee (text "Manatees are pretty cool") | |
, option Pangolin (text "But so are pangolins") | |
, option Bee (text "Bees") | |
] | |
currentlySelected -- : Animal | |
-- Here's what a normal dropdown looks like | |
type Animal = Manatee | Pangolin | Bee | |
el DropDown [] (text "My Animal Menu") | |
|> below | |
[ when menu.open <| | |
radio ChangeSelection Style [] | |
[ option Manatee (text "Manatees are pretty cool") | |
, option Pangolin (text "But so are pangolins") | |
, option Bee (text "Bees") | |
] | |
currentlySelected -- : Animal | |
] | |
{- Labels! -} | |
{-| We can use the labeler that's currently in the lib. | |
It'll just have a different signature of label : style -> List Attr -> Element -> Input -> Element | |
There should be versions for labelBelow, labelLeft, labelRight | |
The label element itself is a layout element that corresponds to row or column depending on the directionality | |
-} | |
label style [] (text "First Name") <| | |
inputText change style [] "LazerCat" | |
{- Error States! -} | |
{-| We want to be able to model error states easily, because that's very common with forms. | |
Here's an example. | |
We want a text input that changes style when there is an error. | |
We want to show that error message if it's present. | |
Labels for inputs are always required. | |
firstname.error -- Maybe (List String), a list of validation errors | |
-} | |
let | |
inputStyle = | |
if firstname.error == Nothing then | |
TextInputStyle | |
else | |
TextError | |
in | |
(inputText ChangeFirstName inputStyle [] "LazerCat") | |
|> label style [] (text "First Name") | |
|> below | |
[ whenJust firstname.error | |
(text << String.join ", ") | |
] | |
{-| With inline styles | |
-} | |
test = | |
inputText ChangeFirstName | |
[ style | |
[ Color.text blue | |
, Color.background lightGrey | |
, Color.mixIf firstname.error | |
[ Color.text blue | |
, Color.background lightGrey | |
] | |
] | |
] | |
"LazerCat" | |
|> label style [] (text "First Name") | |
|> below | |
[ whenJust firstname.error | |
(text << String.join ", ") | |
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{- This exploration focuses on records instead of positional arguments. | |
It also explores what things would look like if styles were defined inline isntead of having a style identifier. | |
-} | |
checkbox [ style ] | |
{ value = True | |
, onChange = Just ChangeMsg | |
} | |
-- For more involved checkbox styling | |
checkboxWith | |
{ value = True | |
, onChange = Just ChangeMsg | |
, checked = el CheckedStyle [] (text "✓") | |
, unchecked el UnChecked [] empty | |
} | |
-- Do we need the distinction between single line and multiline text? | |
textarea [ style, attrs ] | |
{ value = "My Text Area!" | |
, change = Just Change | |
} | |
inputText [ style, attrs ] | |
{ value = "Some Text" | |
, change = Just Change | |
} | |
password [ style, attrs ] | |
{ value = "Some Text" | |
, change = Just Change | |
} | |
button [ style ] | |
{ value = text "Button text!" | |
, change = Just Change | |
} | |
-- Button's child can be any `el` | |
-- We can disable the form submit on the button as the default | |
-- Do we need to be able to re-enable it? | |
-- Radio Buttons | |
type Lunch = Burrito | Taco | |
radio [ radioStyle, attrs ] | |
{ change = Just ChangeRadio | |
, options = | |
[ option Burrito (text "A Burrito!") | |
, option Taco (text "A Taco!") | |
] | |
, value = currentlySelected -- : Lunch | |
} | |
-- More involved styling | |
-- Communicate which element is selected | |
-- Be able to style the selected statement | |
radio [ radioStyle, attrs ] | |
{ change = Just ChangeRadio | |
, options = | |
[ optionWith Burrito | |
{ selected = text "Burrito!" | |
, unselected = text "Unselected burrito :(" | |
} | |
, option Taco (text "A Taco!") | |
] | |
, value = currentlySelected -- : Lunch | |
} | |
-- The `<select>` element. | |
-- Do we even need a `<select>`? It's a weird, non-stylable subclass of a dropdown menu. Is there any advantage? | |
type Animal = Manatee | Pangolin | Bee | |
optionList [ radioStyle, attrs ] | |
{ change = Just ChangeRadio | |
, options = | |
[ optionWith Burrito | |
{ selected = text "Burrito!" | |
, unselected = text "Unselected burrito :(" | |
} | |
, option Taco (text "A Taco!") | |
] | |
, value = currentlySelected -- : Lunch | |
} | |
-- Here's what a normal dropdown looks like | |
type Animal = Manatee | Pangolin | Bee | |
el DropDown [] (text "My Animal Menu") | |
|> below | |
[ when menu.open <| | |
radio [ radioStyle, attrs ] | |
{ change = Just ChangeRadio | |
, options = | |
[ optionWith Burrito | |
{ selected = text "Burrito!" | |
, unselected = text "Unselected burrito :(" | |
} | |
, option Taco (text "A Taco!") | |
] | |
, value = currentlySelected -- : Lunch | |
} | |
] | |
{- Labels! -} | |
{-| We can use the labeler that's currently in the lib. | |
It'll just have a different signature of label : style -> List Attr -> Element -> Input -> Element | |
There should be versions for labelBelow, labelLeft, labelRight | |
The label element itself is a layout element that corresponds to row or column depending on the directionality | |
-} | |
label [ style ] (text "First Name") <| | |
inputText [ style, attrs ] | |
{ value = "LazerCat" | |
, change = Just Change | |
} | |
{- Error States! -} | |
{-| We want to be able to model error states easily, because that's very common with forms. | |
Here's an example. | |
We want a text input that changes style when there is an error. | |
We want to show that error message if it's present. | |
Labels for inputs are always required. | |
firstname.error -- Maybe (List String), a list of validation errors | |
-} | |
let | |
style = | |
if firstname.error == Nothing then | |
TextInputStyle | |
else | |
TextError | |
in | |
inputText [ style, attrs ] | |
{ value = "LazerCat" | |
, change = Just ChangeFirstName | |
} | |
|> label style [] (text "First Name") | |
|> below | |
[ whenJust firstname.error | |
(politeError << String.join ", ") | |
] | |
{-| With inline styles | |
-} | |
test = | |
inputText | |
[ style | |
[ Color.text blue | |
, Color.background lightGrey | |
, Color.mixIf firstname.error | |
[ Color.text blue | |
, Color.background lightGrey | |
] | |
] | |
] | |
{ value = "LazerCat" | |
, change = Just ChangeFirstName | |
} | |
|> label style [] (text "First Name") | |
|> below | |
[ whenJust firstname.error | |
(politeError << String.join ", ") | |
] |
My thought was that those would be handled the normal way, just by adding onFocus Msg
as an attribute.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
What about other events? Blur, Focus?