Upgrade to 0.19
This commit is contained in:
parent
bf632ced14
commit
2d1117eac2
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"type": "package",
|
||||
"name": "NoRedInk/elm-sortable-table",
|
||||
"summary": "Sortable tables for whatever data you want to display.",
|
||||
"license": "BSD-3-Clause",
|
||||
"version": "1.0.0",
|
||||
"exposed-modules": [
|
||||
"Table"
|
||||
],
|
||||
"elm-version": "0.19.0 <= v < 0.20.0",
|
||||
"dependencies": {
|
||||
"elm/core": "1.0.0 <= v < 2.0.0",
|
||||
"elm/html": "1.0.0 <= v < 2.0.0",
|
||||
"elm/json": "1.0.0 <= v < 2.0.0"
|
||||
},
|
||||
"test-dependencies": {}
|
||||
}
|
156
src/Table.elm
156
src/Table.elm
|
@ -5,30 +5,31 @@ module Table exposing
|
|||
, Column, customColumn, veryCustomColumn
|
||||
, Sorter, unsortable, increasingBy, decreasingBy
|
||||
, increasingOrDecreasingBy, decreasingOrIncreasingBy
|
||||
, Config, customConfig
|
||||
, Customizations, HtmlDetails, Status(..), defaultCustomizations
|
||||
, Config, customConfig, Customizations, HtmlDetails, Status(..)
|
||||
, defaultCustomizations
|
||||
)
|
||||
|
||||
{-|
|
||||
|
||||
This library helps you create sortable tables. The crucial feature is that it
|
||||
{-| This library helps you create sortable tables. The crucial feature is that it
|
||||
lets you own your data separately and keep it in whatever format is best for
|
||||
you. This way you are free to change your data without worrying about the table
|
||||
“getting out of sync” with the data. Having a single source of
|
||||
truth is pretty great!
|
||||
|
||||
I recommend checking out the [examples][] to get a feel for how it works.
|
||||
I recommend checking out the [examples] to get a feel for how it works.
|
||||
|
||||
[examples]: https://github.com/evancz/elm-sortable-table/tree/master/examples
|
||||
|
||||
|
||||
# View
|
||||
|
||||
@docs view
|
||||
|
||||
|
||||
# Configuration
|
||||
|
||||
@docs config, stringColumn, intColumn, floatColumn
|
||||
|
||||
|
||||
# State
|
||||
|
||||
@docs State, initialSort
|
||||
|
@ -41,19 +42,22 @@ point are a bunch of ways to customize your table further. If it does not
|
|||
provide what you need, you may just want to write a custom table yourself. It
|
||||
is not that crazy.
|
||||
|
||||
|
||||
## Custom Columns
|
||||
|
||||
@docs Column, customColumn, veryCustomColumn,
|
||||
Sorter, unsortable, increasingBy, decreasingBy,
|
||||
increasingOrDecreasingBy, decreasingOrIncreasingBy
|
||||
@docs Column, customColumn, veryCustomColumn
|
||||
@docs Sorter, unsortable, increasingBy, decreasingBy
|
||||
@docs increasingOrDecreasingBy, decreasingOrIncreasingBy
|
||||
|
||||
|
||||
## Custom Tables
|
||||
|
||||
@docs Config, customConfig, Customizations, HtmlDetails, Status,
|
||||
defaultCustomizations
|
||||
@docs Config, customConfig, Customizations, HtmlDetails, Status
|
||||
@docs defaultCustomizations
|
||||
|
||||
-}
|
||||
|
||||
import Html exposing (Html, Attribute)
|
||||
import Html exposing (Attribute, Html)
|
||||
import Html.Attributes as Attr
|
||||
import Html.Events as E
|
||||
import Html.Keyed as Keyed
|
||||
|
@ -67,8 +71,8 @@ import Json.Decode as Json
|
|||
|
||||
{-| Tracks which column to sort by.
|
||||
-}
|
||||
type State =
|
||||
State String Bool
|
||||
type State
|
||||
= State String Bool
|
||||
|
||||
|
||||
{-| Create a table state. By providing a column name, you determine which
|
||||
|
@ -78,6 +82,7 @@ yachts to be sorted by length by default, you might say:
|
|||
import Table
|
||||
|
||||
Table.initialSort "Length"
|
||||
|
||||
-}
|
||||
initialSort : String -> State
|
||||
initialSort header =
|
||||
|
@ -90,11 +95,12 @@ initialSort header =
|
|||
|
||||
{-| Configuration for your table, describing your columns.
|
||||
|
||||
**Note:** Your `Config` should *never* be held in your model.
|
||||
**Note:** Your `Config` should _never_ be held in your model.
|
||||
It should only appear in `view` code.
|
||||
|
||||
-}
|
||||
type Config data msg =
|
||||
Config
|
||||
type Config data msg
|
||||
= Config
|
||||
{ toId : data -> String
|
||||
, toMsg : State -> msg
|
||||
, columns : List (ColumnData data msg)
|
||||
|
@ -130,13 +136,14 @@ You provide the following information in your table configuration:
|
|||
- `columns` — specify some columns to show.
|
||||
- `toMsg` — a way to send new table states to your app as messages.
|
||||
|
||||
See the [examples][] to get a better feel for this!
|
||||
See the [examples] to get a better feel for this!
|
||||
|
||||
[keyed]: http://package.elm-lang.org/packages/elm-lang/html/latest/Html-Keyed
|
||||
[examples]: https://github.com/evancz/elm-sortable-table/tree/master/examples
|
||||
|
||||
-}
|
||||
config
|
||||
: { toId : data -> String
|
||||
config :
|
||||
{ toId : data -> String
|
||||
, toMsg : State -> msg
|
||||
, columns : List (Column data msg)
|
||||
}
|
||||
|
@ -152,8 +159,8 @@ config { toId, toMsg, columns } =
|
|||
|
||||
{-| Just like `config` but you can specify a bunch of table customizations.
|
||||
-}
|
||||
customConfig
|
||||
: { toId : data -> String
|
||||
customConfig :
|
||||
{ toId : data -> String
|
||||
, toMsg : State -> msg
|
||||
, columns : List (Column data msg)
|
||||
, customizations : Customizations data msg
|
||||
|
@ -175,14 +182,15 @@ summaries of various columns. And maybe you want to put attributes on `<tbody>`
|
|||
or on particular rows in the body. All these customizations are available to you.
|
||||
|
||||
**Note:** The level of craziness possible in `<thead>` and `<tfoot>` are so
|
||||
high that I could not see how to provide the full functionality *and* make it
|
||||
high that I could not see how to provide the full functionality _and_ make it
|
||||
impossible to do bad stuff. So just be aware of that, and share any stories
|
||||
you have. Stories make it possible to design better!
|
||||
|
||||
-}
|
||||
type alias Customizations data msg =
|
||||
{ tableAttrs : List (Attribute msg)
|
||||
, caption : Maybe (HtmlDetails msg)
|
||||
, thead : List (String, Status, Attribute msg) -> HtmlDetails msg
|
||||
, thead : List ( String, Status, Attribute msg ) -> HtmlDetails msg
|
||||
, tfoot : Maybe (HtmlDetails msg)
|
||||
, tbodyAttrs : List (Attribute msg)
|
||||
, rowAttrs : data -> List (Attribute msg)
|
||||
|
@ -212,13 +220,13 @@ defaultCustomizations =
|
|||
}
|
||||
|
||||
|
||||
simpleThead : List (String, Status, Attribute msg) -> HtmlDetails msg
|
||||
simpleThead : List ( String, Status, Attribute msg ) -> HtmlDetails msg
|
||||
simpleThead headers =
|
||||
HtmlDetails [] (List.map simpleTheadHelp headers)
|
||||
|
||||
|
||||
simpleTheadHelp : ( String, Status, Attribute msg ) -> Html msg
|
||||
simpleTheadHelp (name, status, onClick) =
|
||||
simpleTheadHelp ( name, status, onClick_ ) =
|
||||
let
|
||||
content =
|
||||
case status of
|
||||
|
@ -227,7 +235,11 @@ simpleTheadHelp (name, status, onClick) =
|
|||
|
||||
Sortable selected ->
|
||||
[ Html.text name
|
||||
, if selected then darkGrey "↓" else lightGrey "↓"
|
||||
, if selected then
|
||||
darkGrey "↓"
|
||||
|
||||
else
|
||||
lightGrey "↓"
|
||||
]
|
||||
|
||||
Reversible Nothing ->
|
||||
|
@ -237,20 +249,26 @@ simpleTheadHelp (name, status, onClick) =
|
|||
|
||||
Reversible (Just isReversed) ->
|
||||
[ Html.text name
|
||||
, darkGrey (if isReversed then "↑" else "↓")
|
||||
, darkGrey
|
||||
(if isReversed then
|
||||
"↑"
|
||||
|
||||
else
|
||||
"↓"
|
||||
)
|
||||
]
|
||||
in
|
||||
Html.th [ onClick ] content
|
||||
Html.th [ onClick_ ] content
|
||||
|
||||
|
||||
darkGrey : String -> Html msg
|
||||
darkGrey symbol =
|
||||
Html.span [ Attr.style [("color", "#555")] ] [ Html.text (" " ++ symbol) ]
|
||||
Html.span [ Attr.style "color" "#555" ] [ Html.text (" " ++ symbol) ]
|
||||
|
||||
|
||||
lightGrey : String -> Html msg
|
||||
lightGrey symbol =
|
||||
Html.span [ Attr.style [("color", "#ccc")] ] [ Html.text (" " ++ symbol) ]
|
||||
Html.span [ Attr.style "color" "#ccc" ] [ Html.text (" " ++ symbol) ]
|
||||
|
||||
|
||||
simpleRowAttrs : data -> List (Attribute msg)
|
||||
|
@ -272,6 +290,7 @@ simpleRowAttrs _ =
|
|||
is sorted.
|
||||
|
||||
This information lets you do custom header decorations for each scenario.
|
||||
|
||||
-}
|
||||
type Status
|
||||
= Unsortable
|
||||
|
@ -285,8 +304,8 @@ type Status
|
|||
|
||||
{-| Describes how to turn `data` into a column in your table.
|
||||
-}
|
||||
type Column data msg =
|
||||
Column (ColumnData data msg)
|
||||
type Column data msg
|
||||
= Column (ColumnData data msg)
|
||||
|
||||
|
||||
type alias ColumnData data msg =
|
||||
|
@ -296,7 +315,7 @@ type alias ColumnData data msg =
|
|||
}
|
||||
|
||||
|
||||
{-|-}
|
||||
{-| -}
|
||||
stringColumn : String -> (data -> String) -> Column data msg
|
||||
stringColumn name toStr =
|
||||
Column
|
||||
|
@ -306,22 +325,22 @@ stringColumn name toStr =
|
|||
}
|
||||
|
||||
|
||||
{-|-}
|
||||
{-| -}
|
||||
intColumn : String -> (data -> Int) -> Column data msg
|
||||
intColumn name toInt =
|
||||
Column
|
||||
{ name = name
|
||||
, viewData = textDetails << toString << toInt
|
||||
, viewData = textDetails << String.fromInt << toInt
|
||||
, sorter = increasingOrDecreasingBy toInt
|
||||
}
|
||||
|
||||
|
||||
{-|-}
|
||||
{-| -}
|
||||
floatColumn : String -> (data -> Float) -> Column data msg
|
||||
floatColumn name toFloat =
|
||||
Column
|
||||
{ name = name
|
||||
, viewData = textDetails << toString << toFloat
|
||||
, viewData = textDetails << String.fromFloat << toFloat
|
||||
, sorter = increasingOrDecreasingBy toFloat
|
||||
}
|
||||
|
||||
|
@ -352,11 +371,12 @@ quite cut it. You could define a custom column like this:
|
|||
The `viewData` field means we will displays the number `12345.67` as `$12k`.
|
||||
|
||||
The `sorter` field specifies how the column can be sorted. In `dollarColumn` we
|
||||
are saying that it can *only* be shown from highest-to-lowest monetary value.
|
||||
are saying that it can _only_ be shown from highest-to-lowest monetary value.
|
||||
More about sorters soon!
|
||||
|
||||
-}
|
||||
customColumn
|
||||
: { name : String
|
||||
customColumn :
|
||||
{ name : String
|
||||
, viewData : data -> String
|
||||
, sorter : Sorter data
|
||||
}
|
||||
|
@ -366,13 +386,13 @@ customColumn { name, viewData, sorter } =
|
|||
ColumnData name (textDetails << viewData) sorter
|
||||
|
||||
|
||||
{-| It is *possible* that you want something crazier than `customColumn`. In
|
||||
{-| It is _possible_ that you want something crazier than `customColumn`. In
|
||||
that unlikely scenario, this function lets you have full control over the
|
||||
attributes and children of each `<td>` cell in this column.
|
||||
|
||||
So maybe you want to a dollars column, and the dollar signs should be green.
|
||||
|
||||
import Html exposing (Html, Attribute, span, text)
|
||||
import Html exposing (Attribute, Html, span, text)
|
||||
import Html.Attributes exposing (style)
|
||||
import Table
|
||||
|
||||
|
@ -387,12 +407,13 @@ So maybe you want to a dollars column, and the dollar signs should be green.
|
|||
viewDollars : Float -> Table.HtmlDetails msg
|
||||
viewDollars dollars =
|
||||
Table.HtmlDetails []
|
||||
[ span [ style [("color","green")] ] [ text "$" ]
|
||||
[ span [ style [ ( "color", "green" ) ] ] [ text "$" ]
|
||||
, text (toString (round (dollars / 1000)) ++ "k")
|
||||
]
|
||||
|
||||
-}
|
||||
veryCustomColumn
|
||||
: { name : String
|
||||
veryCustomColumn :
|
||||
{ name : String
|
||||
, viewData : data -> HtmlDetails msg
|
||||
, sorter : Sorter data
|
||||
}
|
||||
|
@ -414,6 +435,7 @@ for the table belongs in your `view` code. I very strongly recommend against
|
|||
putting `Config` in your model. Describe any potential table configurations
|
||||
statically, and look for a different library if you need something crazier than
|
||||
that.
|
||||
|
||||
-}
|
||||
view : Config data msg -> State -> List data -> Html msg
|
||||
view (Config { toId, toMsg, columns, customizations }) state data =
|
||||
|
@ -463,19 +485,22 @@ toHeaderInfo (State sortName isReversed) toMsg { name, sorter } =
|
|||
IncOrDec _ ->
|
||||
if name == sortName then
|
||||
( name, Reversible (Just isReversed), onClick name (not isReversed) toMsg )
|
||||
|
||||
else
|
||||
( name, Reversible Nothing, onClick name False toMsg )
|
||||
|
||||
DecOrInc _ ->
|
||||
if name == sortName then
|
||||
( name, Reversible (Just isReversed), onClick name (not isReversed) toMsg )
|
||||
|
||||
else
|
||||
( name, Reversible Nothing, onClick name False toMsg )
|
||||
|
||||
|
||||
onClick : String -> Bool -> (State -> msg) -> Attribute msg
|
||||
onClick name isReversed toMsg =
|
||||
E.on "click" <| Json.map toMsg <|
|
||||
E.on "click" <|
|
||||
Json.map toMsg <|
|
||||
Json.map2 State (Json.succeed name) (Json.succeed isReversed)
|
||||
|
||||
|
||||
|
@ -492,7 +517,7 @@ viewRowHelp columns toRowAttrs data =
|
|||
|
||||
|
||||
viewCell : data -> ColumnData data msg -> Html msg
|
||||
viewCell data {viewData} =
|
||||
viewCell data { viewData } =
|
||||
let
|
||||
details =
|
||||
viewData data
|
||||
|
@ -520,17 +545,25 @@ applySorter isReversed sorter data =
|
|||
None ->
|
||||
data
|
||||
|
||||
Increasing sort ->
|
||||
sort data
|
||||
Increasing sort_ ->
|
||||
sort_ data
|
||||
|
||||
Decreasing sort ->
|
||||
List.reverse (sort data)
|
||||
Decreasing sort_ ->
|
||||
List.reverse (sort_ data)
|
||||
|
||||
IncOrDec sort ->
|
||||
if isReversed then List.reverse (sort data) else sort data
|
||||
IncOrDec sort_ ->
|
||||
if isReversed then
|
||||
List.reverse (sort_ data)
|
||||
|
||||
DecOrInc sort ->
|
||||
if isReversed then sort data else List.reverse (sort data)
|
||||
else
|
||||
sort_ data
|
||||
|
||||
DecOrInc sort_ ->
|
||||
if isReversed then
|
||||
sort_ data
|
||||
|
||||
else
|
||||
List.reverse (sort_ data)
|
||||
|
||||
|
||||
findSorter : String -> List (ColumnData data msg) -> Maybe (Sorter data)
|
||||
|
@ -539,9 +572,10 @@ findSorter selectedColumn columnData =
|
|||
[] ->
|
||||
Nothing
|
||||
|
||||
{name, sorter} :: remainingColumnData ->
|
||||
{ name, sorter } :: remainingColumnData ->
|
||||
if name == selectedColumn then
|
||||
Just sorter
|
||||
|
||||
else
|
||||
findSorter selectedColumn remainingColumnData
|
||||
|
||||
|
@ -575,6 +609,7 @@ want a table of people, sorted alphabetically by name, we would say this:
|
|||
sorter : Sorter { a | name : comparable }
|
||||
sorter =
|
||||
increasingBy .name
|
||||
|
||||
-}
|
||||
increasingBy : (data -> comparable) -> Sorter data
|
||||
increasingBy toComparable =
|
||||
|
@ -588,13 +623,14 @@ would say this:
|
|||
sorter : Sorter { a | population : comparable }
|
||||
sorter =
|
||||
decreasingBy .population
|
||||
|
||||
-}
|
||||
decreasingBy : (data -> comparable) -> Sorter data
|
||||
decreasingBy toComparable =
|
||||
Decreasing (List.sortBy toComparable)
|
||||
|
||||
|
||||
{-| Sometimes you want to be able to sort data in increasing *or* decreasing
|
||||
{-| Sometimes you want to be able to sort data in increasing _or_ decreasing
|
||||
order. Maybe you have a bunch of data about orange juice, and you want to know
|
||||
both which has the most sugar, and which has the least sugar. Both interesting!
|
||||
This function lets you see both, starting with decreasing order.
|
||||
|
@ -602,19 +638,21 @@ This function lets you see both, starting with decreasing order.
|
|||
sorter : Sorter { a | sugar : comparable }
|
||||
sorter =
|
||||
decreasingOrIncreasingBy .sugar
|
||||
|
||||
-}
|
||||
decreasingOrIncreasingBy : (data -> comparable) -> Sorter data
|
||||
decreasingOrIncreasingBy toComparable =
|
||||
DecOrInc (List.sortBy toComparable)
|
||||
|
||||
|
||||
{-| Sometimes you want to be able to sort data in increasing *or* decreasing
|
||||
{-| Sometimes you want to be able to sort data in increasing _or_ decreasing
|
||||
order. Maybe you have race times for the 100 meter sprint. This function lets
|
||||
sort by best time by default, but also see the other order.
|
||||
|
||||
sorter : Sorter { a | time : comparable }
|
||||
sorter =
|
||||
increasingOrDecreasingBy .time
|
||||
|
||||
-}
|
||||
increasingOrDecreasingBy : (data -> comparable) -> Sorter data
|
||||
increasingOrDecreasingBy toComparable =
|
||||
|
|
Loading…
Reference in New Issue