2016-04-06 13:28:37 +00:00
|
|
|
module Material
|
|
|
|
( Model, model
|
|
|
|
, Action, update
|
|
|
|
)
|
|
|
|
where
|
2016-03-14 09:42:49 +00:00
|
|
|
|
2016-04-06 13:28:37 +00:00
|
|
|
{-|
|
|
|
|
|
|
|
|
Material Design component library for Elm based on Google's
|
2016-03-14 09:42:49 +00:00
|
|
|
[Material Design Lite](https://www.getmdl.io/).
|
|
|
|
|
2016-04-06 13:28:37 +00:00
|
|
|
Click
|
|
|
|
[here](https://debois.github.io/elm-mdl/)
|
|
|
|
for a live demo.
|
2016-03-19 22:47:21 +00:00
|
|
|
|
2016-04-06 13:28:37 +00:00
|
|
|
# Component model
|
2016-03-15 16:35:34 +00:00
|
|
|
|
2016-04-07 07:52:11 +00:00
|
|
|
The component model of the library is simply the Elm Architecture (TEA), i.e.,
|
|
|
|
each component has types `Model` and `Action`, and values `view` and `update`. A
|
|
|
|
minimal example using this library in plain TEA can be found
|
|
|
|
[here](https://github.com/debois/elm-mdl/blob/master/examples/Component-TEA.elm).
|
2016-03-14 09:42:49 +00:00
|
|
|
|
2016-04-07 07:52:11 +00:00
|
|
|
Using more than a few component in plain TEA is unwieldy because of the large
|
|
|
|
amount of boilerplate one has to write. This library provides the "component
|
|
|
|
support" for getting rid of most of that boilerplate. A minimal example using
|
|
|
|
component support is
|
2016-04-06 13:28:37 +00:00
|
|
|
[here](http://github.com/debois/elm-mdl/blob/master/examples/Component.elm).
|
2016-03-14 09:42:49 +00:00
|
|
|
|
2016-04-07 07:52:11 +00:00
|
|
|
It is important to note that component support lives __within__ TEA;
|
|
|
|
it is not an alternative architecture.
|
2016-03-14 09:42:49 +00:00
|
|
|
|
2016-04-06 13:28:37 +00:00
|
|
|
# Getting started
|
2016-03-19 22:47:21 +00:00
|
|
|
|
2016-04-06 13:28:37 +00:00
|
|
|
The easiest way to get started is to start with one of the minimal examples above.
|
2016-04-07 07:52:11 +00:00
|
|
|
We recommend going with the library's
|
|
|
|
[component support](http://github.com/debois/elm-mdl/blob/master/examples/Component.elm)
|
|
|
|
rather than working directly in plain Elm Architecture.
|
2016-03-14 09:42:49 +00:00
|
|
|
|
2016-04-07 07:52:11 +00:00
|
|
|
# Component Support
|
2016-03-14 09:42:49 +00:00
|
|
|
|
2016-04-06 13:28:37 +00:00
|
|
|
This module contains only convenience functions for working with nested
|
|
|
|
components in the Elm architecture. A minimal example using this library
|
|
|
|
with component support can be found
|
|
|
|
[here](http://github.com/debois/elm-mdl/blob/master/examples/Component.elm).
|
|
|
|
We encourage you to use the library in this fashion.
|
2016-03-14 09:42:49 +00:00
|
|
|
|
2016-04-06 13:28:37 +00:00
|
|
|
All examples in this subsection is from the
|
|
|
|
[above minimal example](http://github.com/debois/elm-mdl/blob/master/examples/Component.elm)
|
2016-03-14 09:42:49 +00:00
|
|
|
|
2016-04-06 13:28:37 +00:00
|
|
|
Here is how you use component support in general. First, boilerplate.
|
2016-03-14 09:42:49 +00:00
|
|
|
|
2016-04-06 13:28:37 +00:00
|
|
|
1. Include `Material`:
|
2016-03-14 09:42:49 +00:00
|
|
|
|
|
|
|
<!-- MDL -->
|
|
|
|
<link href='https://fonts.googleapis.com/css?family=Roboto:400,300,500|Roboto+Mono|Roboto+Condensed:400,700&subset=latin,latin-ext' rel='stylesheet' type='text/css'>
|
|
|
|
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
|
2016-03-28 19:25:11 +00:00
|
|
|
<link rel="stylesheet" href="https://code.getmdl.io/1.1.3/material.min.css" />
|
2016-03-14 09:42:49 +00:00
|
|
|
|
2016-04-06 13:28:37 +00:00
|
|
|
2. Add a model container Material components to your model:
|
2016-03-14 09:42:49 +00:00
|
|
|
|
2016-04-07 07:52:11 +00:00
|
|
|
type alias Model =
|
|
|
|
{ ...
|
|
|
|
, mdl : Material.Model
|
|
|
|
}
|
2016-03-14 09:42:49 +00:00
|
|
|
|
2016-04-07 07:52:11 +00:00
|
|
|
model : Model =
|
|
|
|
{ ...
|
|
|
|
, mdl = Material.model
|
|
|
|
}
|
2016-03-15 16:35:34 +00:00
|
|
|
|
2016-04-06 13:28:37 +00:00
|
|
|
3. Add an action for Material components.
|
2016-03-15 16:35:34 +00:00
|
|
|
|
2016-04-07 07:52:11 +00:00
|
|
|
type Action =
|
|
|
|
...
|
|
|
|
| MDL (Material.Action Action)
|
2016-04-06 13:28:37 +00:00
|
|
|
|
|
|
|
4. Handle that action in your update function as follows:
|
|
|
|
|
2016-04-07 07:52:11 +00:00
|
|
|
update action model =
|
|
|
|
case action of
|
|
|
|
...
|
|
|
|
MDL action' ->
|
|
|
|
let (mdl', fx) =
|
|
|
|
Material.update MDL action' model.mdl
|
|
|
|
in
|
|
|
|
( { model | mdl = mdl' } , fx )
|
2016-04-06 13:28:37 +00:00
|
|
|
|
|
|
|
Next, make the component instances you need. Do this in the View section of your
|
|
|
|
source file. Let's say you need a textfield for name entry, and you'd like to
|
|
|
|
be notifed whenever the field changes value through your own NameChanged action:
|
|
|
|
|
2016-04-07 07:52:11 +00:00
|
|
|
import Material.Textfield as Textfield
|
2016-04-06 13:28:37 +00:00
|
|
|
|
2016-04-07 07:52:11 +00:00
|
|
|
...
|
2016-04-06 13:28:37 +00:00
|
|
|
|
2016-04-07 07:52:11 +00:00
|
|
|
type Action =
|
|
|
|
...
|
|
|
|
| NameChanged String
|
2016-04-06 13:28:37 +00:00
|
|
|
|
2016-04-07 07:52:11 +00:00
|
|
|
...
|
2016-03-17 12:31:43 +00:00
|
|
|
|
2016-04-07 07:52:11 +00:00
|
|
|
update action model =
|
|
|
|
case action of
|
|
|
|
...
|
|
|
|
NameChanged name ->
|
|
|
|
-- Do whatever you need to do.
|
2016-03-17 12:31:43 +00:00
|
|
|
|
2016-04-07 07:52:11 +00:00
|
|
|
...
|
2016-03-17 12:31:43 +00:00
|
|
|
|
2016-04-07 07:52:11 +00:00
|
|
|
nameInput : Textfield.Instance Material.Model Action
|
|
|
|
nameInput =
|
|
|
|
Textfield.instance 2 MDL Textfield.model
|
|
|
|
[ Textfield.fwdInput NameChanged
|
|
|
|
]
|
|
|
|
|
|
|
|
view addr model =
|
|
|
|
...
|
|
|
|
nameInput.view addr model.mdl
|
2016-04-06 13:28:37 +00:00
|
|
|
|
|
|
|
|
|
|
|
The win relative to using plain Elm Architecture is that adding a component
|
|
|
|
neither requires you to update your model, your Actions, nor your update function.
|
|
|
|
(As in the above example, you will frequently have to update the latter two anyway,
|
|
|
|
but now it's not boilerplate, its "business logic".)
|
|
|
|
|
|
|
|
|
|
|
|
## Optimising for size
|
|
|
|
|
|
|
|
Using this module will force all elm-mdl components to be built and included in
|
|
|
|
your application. If this is unacceptable, you can custom-build a version of this
|
|
|
|
module that uses only the components you need. To do so, you need to re-implement
|
2016-04-07 07:52:11 +00:00
|
|
|
the present module, modifying the values `model` and `Model` by commenting out the
|
|
|
|
components you are not using. The module source can be found
|
|
|
|
[here](https://github.com/debois/elm-mdl/blob/master/src/Material.elm).
|
2016-04-06 13:28:37 +00:00
|
|
|
|
|
|
|
You do not need to re-build the entire elm-mdl library; simply copy the
|
2016-04-07 07:52:11 +00:00
|
|
|
source of this module, give it a new name, modify as it as indicated above,
|
|
|
|
then use your modified module rather than this one.
|
2016-04-06 13:28:37 +00:00
|
|
|
|
|
|
|
@docs Model, model, Action, update
|
2016-03-17 12:31:43 +00:00
|
|
|
-}
|
|
|
|
|
2016-04-06 13:28:37 +00:00
|
|
|
import Dict
|
|
|
|
import Effects exposing (Effects)
|
2016-03-17 12:31:43 +00:00
|
|
|
|
2016-04-06 13:28:37 +00:00
|
|
|
import Material.Button as Button
|
|
|
|
import Material.Textfield as Textfield
|
2016-04-06 18:16:54 +00:00
|
|
|
import Material.Snackbar as Snackbar
|
2016-04-06 13:28:37 +00:00
|
|
|
import Material.Component as Component exposing (Indexed)
|
|
|
|
|
|
|
|
|
2016-04-07 07:52:11 +00:00
|
|
|
{-| Model encompassing all Material components. Since some components store
|
|
|
|
user actions in their model (notably Snackbar), the model is generic in the
|
|
|
|
type of such "observations".
|
2016-03-17 12:31:43 +00:00
|
|
|
-}
|
2016-04-07 07:52:11 +00:00
|
|
|
type alias Model obs =
|
2016-04-06 13:28:37 +00:00
|
|
|
{ button : Indexed Button.Model
|
|
|
|
, textfield : Indexed Textfield.Model
|
2016-04-07 07:52:11 +00:00
|
|
|
, snackbar : Maybe (Snackbar.Model obs)
|
2016-04-06 13:28:37 +00:00
|
|
|
}
|
|
|
|
|
2016-03-17 12:31:43 +00:00
|
|
|
|
2016-04-06 13:28:37 +00:00
|
|
|
{-| Initial model.
|
|
|
|
-}
|
2016-04-07 07:52:11 +00:00
|
|
|
model : Model obs
|
2016-04-06 13:28:37 +00:00
|
|
|
model =
|
|
|
|
{ button = Dict.empty
|
|
|
|
, textfield = Dict.empty
|
2016-04-07 07:52:11 +00:00
|
|
|
, snackbar = Nothing
|
2016-04-06 13:28:37 +00:00
|
|
|
}
|
2016-03-17 12:31:43 +00:00
|
|
|
|
|
|
|
|
2016-04-06 13:28:37 +00:00
|
|
|
{-| Action encompassing actions of all Material components.
|
2016-03-17 12:31:43 +00:00
|
|
|
-}
|
2016-04-07 07:52:11 +00:00
|
|
|
type alias Action obs =
|
|
|
|
Component.Action (Model obs) obs
|
2016-04-06 13:28:37 +00:00
|
|
|
|
|
|
|
|
|
|
|
{-| Update function for the above Action.
|
2016-03-17 12:31:43 +00:00
|
|
|
-}
|
2016-04-06 13:28:37 +00:00
|
|
|
update :
|
2016-04-07 07:52:11 +00:00
|
|
|
(Action obs -> obs)
|
|
|
|
-> Action obs
|
|
|
|
-> Model obs
|
|
|
|
-> (Model obs, Effects obs)
|
2016-04-06 13:28:37 +00:00
|
|
|
update =
|
|
|
|
Component.update
|