elm-mdl/src/Material.elm

209 lines
6.4 KiB
Elm
Raw Normal View History

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-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-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">
<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-04-06 13:28:37 +00:00
3. Add an action for Material components.
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
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
-}
type alias Model =
2016-04-06 13:28:37 +00:00
{ button : Indexed Button.Model
, textfield : Indexed Textfield.Model
, 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.
-}
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 =
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
-> Model
-> (Model, Effects obs)
2016-04-06 13:28:37 +00:00
update =
Component.update