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-12 21:03:13 +00:00
|
|
|
We recommend going with the one that uses
|
|
|
|
[the one that uses](http://github.com/debois/elm-mdl/blob/master/examples/Component.elm)
|
|
|
|
the library's component support rather than working directly in plain Elm
|
|
|
|
Architecture.
|
2016-03-14 09:42:49 +00:00
|
|
|
|
2016-04-12 21:03:13 +00:00
|
|
|
# Colors and CSS
|
|
|
|
|
|
|
|
The view function of most components has this signature:
|
|
|
|
|
|
|
|
view : Signal.Address -> Model -> List Style -> Html
|
|
|
|
|
|
|
|
The address is standard, and `Model` is just the model type of the component.
|
|
|
|
The third argument, `List Style`, is a mechanism for you to specify additional
|
|
|
|
classes and CSS for the component. You need this, e.g., when you want to
|
|
|
|
specify the width of a button. See the
|
|
|
|
[Style](http://package.elm-lang.org/packages/debois/elm-mdl/latest/Material-Style)
|
|
|
|
module for details.
|
|
|
|
|
|
|
|
Material Design defines a color palette. The
|
|
|
|
[Color](http://package.elm-lang.org/packages/debois/elm-mdl/latest/Material-Color)
|
|
|
|
module contains various `Style` values and helper functions for working with
|
|
|
|
this color palette.
|
2016-04-12 13:09:12 +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
|
2016-04-12 21:03:13 +00:00
|
|
|
module that uses only the components you need. To do so, you need to provide your
|
|
|
|
own versions of the type `Model` and the value `model` of the present module.
|
|
|
|
Use the corresponding definitions in this module as a starting point
|
|
|
|
([source](https://github.com/debois/elm-mdl/blob/master/src/Material.elm))
|
|
|
|
and simply comment out the components you do not need.
|
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-12 22:13:43 +00:00
|
|
|
--import Material.Template as Template
|
2016-04-06 13:28:37 +00:00
|
|
|
|
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-12 13:09:12 +00:00
|
|
|
type alias Model =
|
2016-04-06 13:28:37 +00:00
|
|
|
{ button : Indexed Button.Model
|
|
|
|
, textfield : Indexed Textfield.Model
|
2016-04-12 13:09:12 +00:00
|
|
|
, snackbar : Maybe (Snackbar.Model Int)
|
2016-04-12 22:13:43 +00:00
|
|
|
-- , template : Indexed Template.Model
|
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-12 13:09:12 +00:00
|
|
|
model : Model
|
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-12 22:13:43 +00:00
|
|
|
--, template = Dict.empty
|
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 =
|
2016-04-12 13:09:12 +00:00
|
|
|
Component.Action Model obs
|
2016-04-06 13:28:37 +00:00
|
|
|
|
|
|
|
|
2016-04-12 21:03:13 +00:00
|
|
|
{-| Update function for the above Action. Provide as the first
|
|
|
|
argument a lifting function that embeds the generic MDL action in
|
|
|
|
your own Action type.
|
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
|
2016-04-12 13:09:12 +00:00
|
|
|
-> Model
|
|
|
|
-> (Model, Effects obs)
|
2016-04-06 13:28:37 +00:00
|
|
|
update =
|
|
|
|
Component.update
|