Elm Rater - Live Demo
A reusable rater for Elm.
import Rater
import Rater.Rating as Rating exposing (Rating)
type alias Model =
{ rating : Rating }
init =
{ rating = Rating.outOf5 3 }
view { rating } =
div []
[ Rater.viewReadOnly rating
, Rater.viewDisabled rating
]
Supports:
- click to change
type alias Model =
{ rating : Rating }
init =
{ rating = Rating.outOf5 3 }
type Msg
= ChangedRating Rating
update msg model =
case msg of
ChangedRating newRating ->
{ model | rating = newRating }
view { rating } =
div []
[ Rater.viewSimple ChangedRating rating ]
Supports:
- click to change
- click to clear
type alias Model =
{ rating : Rating }
init =
{ rating = Rating.outOf5 3 }
type Msg
= ChangedRating Rating
| ClearedRating
update msg model =
case msg of
ChangedRating newRating ->
{ model | rating = newRating }
ClearedRating ->
{ model | rating = Rating.zero model.rating }
view { rating } =
div []
[ Rater.viewClearable ChangedRating ClearedRating rating ]
Supports:
- click to change
- click to clear
- mouse over
- mouse out
type alias Model =
{ rating : Rating
, rater : Rater.State
, transientValue : Maybe Int
}
init =
{ rating = Rating.outOf5 3
, rater = Rater.init
, transientValue = Nothing
}
type Msg
= ChangedRating Rating
| ClearedRating
| HoveredOverRater Rater.State Int
| LeftRater Rater.State
update msg model =
case msg of
ChangedRating newRating ->
{ model | rating = newRating }
ClearedRating ->
{ model | rating = Rating.zero model.rating }
HoveredOverRater state newTransientValue ->
{ model | rater = state, transientValue = Just newTransientValue }
LeftRater state ->
{ model | rater = state, transientValue = Nothing }
view { rating, rater } =
div []
[ Rater.viewHoverable
-- options
{ onChange = ChangedRating
, onClear = Just ClearedRating
, onHover = HoveredOverRater
, onLeave = LeftRater
}
-- view state
rater
-- data
rating
, case transientValue of
Nothing ->
text "Hover over the rater to see this value change."
Just value ->
text <| String.fromInt value
]
Customize the presets using one of the functions:
viewCustomReadOnly
viewCustomDisabled
viewCustomSimple
viewCustomClearable
viewCustomHoverable
For e.g. suppose you wanted these features for your rater:
- click to change
- no click to clear
- mouse over
- mouse out
- hearts instead of stars
Then, you could use viewCustomHoverable
.
type alias Model =
{ rating : Rating
, rater : Rater.State
}
init =
{ rating = Rating.outOf5 3
, rater = Rater.init
}
type Msg
= ChangedRating Rating
| HoveredOverRater Rater.State Int
| LeftRater Rater.State
update msg model =
case msg of
ChangedRating newRating ->
{ model | rating = newRating }
HoveredOverRater state _ ->
{ model | rater = state }
LeftRater state ->
{ model | rater = state }
view { rating, rater } =
div []
[ Rater.viewCustomHoverable
-- options
{ orientation = Rater.horizontal
, symbols =
Rater.sameSymbols <|
\value ->
span
[ class "elm-rater__heart"
, title <| String.fromInt value
]
[ text "\u{2764}" ]
, onChange = ChangedRating
, onClear = Nothing
, onHover = HoveredOverRater
, onLeave = LeftRater
}
-- view state
rater
-- data
rating
]
For unadulterated customization check out the Rater.customConfig
and
Rater.view
functions.
These are some of the design principles I tried to put into practice.
The Rater.Rating
type is a data structure that represents a rating. You pass
it to the various view functions provided by this library in order for it to be
presented on the page. However, you maintain ownership of the value.
Check out the You own the rating example from the demo.
It's designed to have a smooth learning curve. You can start by using the simple functions and as your needs get more demanding you can switch to using the more complex functions.
When you need support for hovering you will need to start using view state. The
view state, of type Rater.State
, is a value that gets passed around in order
to keep track of what your mouse is currently over.
The view state is kept completely separate from the data.
Why?
Because the view state is only necessary to make the view work when hovering is enabled. It's not needed otherwise. If you choose to present the rating differently then you might not need view state or you may need a different type of view state. In any case, view state is state you keep that is highly specific to the way you choose to present your data. It must never mix with your data.
The views return Html msg
and there is no need for an update function. The way
you end up using the library is similar to how you'd use Html.input
. You
provide msg
builders that wrap the values that need to be communicated.
Rater.viewCustomClearable
: { orientation : ...
, symbols : ...
, onChange : Rating -> msg
, onClear : msg
}
-> Rating
-> Html msg
Rater.viewCustomClearable
-- options
{ orientation = ...
, symbols = ...
, onChange = ChangedRating
, onClear = ClearedRating
}
-- data
rating
ChangedRating : Rating -> Msg
ClearedRating : Msg
Use BEM to give the CSS a solid structure.
Well structured HTML and CSS combined with Elm leads to bliss.
Even though evancz/elm-sortable-table is DEPRECATED it still has tremendous value for learning how to write reusable views.