@rtfeldman consider a button that should automatically remove focus when you click on it:
module App.Components.Button exposing (Config, Container, button)
import Components exposing (Component, Signal, convertSignal, send)
import Components.Html as Html exposing (Html)
import Components.Html.Attributes as Attr
import Components.Html.Events as Events
import Css
import Dom
import Task
type alias Container =
Components.Container State Msg Parts
type alias Config m p =
{ onClick : Signal m p
, css : List Css.Style
}
type alias State =
()
type Msg
= Clicked
| BlurAttempted (Result Dom.Error ())
type alias Parts =
()
type alias Self p =
Components.Self State Msg Parts p
button : Config m p -> List (Html m p) -> Component Container m p
button config contents =
Components.mixed
{ init = \_ -> ( (), Cmd.none, [] )
, update = update config
, subscriptions = \_ _ -> Sub.none
, view = view config contents
, parts = ()
}
update :
Config m p
-> Self p
-> Msg
-> State
-> ( State, Cmd Msg, List (Signal m p) )
update config self msg state =
case msg of
Clicked ->
( state
, Task.attempt BlurAttempted (Dom.blur self.id)
, [ config.onClick ]
)
BlurAttempted focusResult ->
case focusResult of
Ok () ->
( state, Cmd.none, [] )
Err (Dom.NotFound id) ->
Debug.crash "TODO: Handle error"
view : Config m p -> List (Html m p) -> Self p -> State -> Html m p
view config contents self () =
Html.button
[ Attr.id self.id
, Attr.type_ "button"
, Attr.css config.css
, Events.onClick (send Clicked |> convertSignal self)
]
contents
I want all buttons in my app to have this functionality. It doesn’t even have any state, but you’ll need to manually call its update and use an OutMsg each time you need a button. You may argue that I shouldn’t do things like this at all because browser vendors know better how a button should behave, but I don’t agree (I really want it). And it’s not fully completed actually, ideally I want to distinguish between keyboard and mouse “clicks” and leave the focus where it is if the “click” is made via keyboard (this seems to be not that easy and may introduce some state). Also imaging adding an animation which will also introduce state and subscriptions.
A couple more examples:
- Each text field has quite complex HTML/CSS (looks a bit like material design text field boxes, but even more complex) and needs to maintain a focus state. Also it makes calls to a port to implement “reset” functionality (
Html.Keyed doesn’t work for me because I have issues with Chrome’s autofill. But this won’t be needed after 0.19 of course).
- Password field wraps the text field component and adds a “reveal” button. It needs some state to handle how it works (also that button is a
Button component from the example above).
- Dialog component with animated background. This one isn’t used that often but still I’m uncomfortable that nothing prevents me from forgetting to connect its subscriptions.