mirror of
https://github.com/NoRedInk/noredink-ui.git
synced 2024-12-25 06:33:09 +03:00
Merge branch 'master' into lab/stickyable-segmented-control
This commit is contained in:
commit
ef6ee0ab21
1
elm.json
1
elm.json
@ -49,7 +49,6 @@
|
|||||||
"Nri.Ui.Select.V7",
|
"Nri.Ui.Select.V7",
|
||||||
"Nri.Ui.Slide.V1",
|
"Nri.Ui.Slide.V1",
|
||||||
"Nri.Ui.SlideModal.V2",
|
"Nri.Ui.SlideModal.V2",
|
||||||
"Nri.Ui.SortableTable.V1",
|
|
||||||
"Nri.Ui.SortableTable.V2",
|
"Nri.Ui.SortableTable.V2",
|
||||||
"Nri.Ui.Svg.V1",
|
"Nri.Ui.Svg.V1",
|
||||||
"Nri.Ui.Table.V4",
|
"Nri.Ui.Table.V4",
|
||||||
|
@ -2,7 +2,6 @@ filename,name,version
|
|||||||
src/Nri/Ui/Page/V3.elm,Nri.Ui.Text,2
|
src/Nri/Ui/Page/V3.elm,Nri.Ui.Text,2
|
||||||
src/Nri/Ui/SlideModal/V2.elm,Nri.Ui.Button,8
|
src/Nri/Ui/SlideModal/V2.elm,Nri.Ui.Button,8
|
||||||
src/Nri/Ui/SlideModal/V2.elm,Nri.Ui.Text,2
|
src/Nri/Ui/SlideModal/V2.elm,Nri.Ui.Text,2
|
||||||
src/Nri/Ui/SortableTable/V1.elm,Nri.Ui.Table,4
|
|
||||||
src/Nri/Ui/Button/V8.elm,Html,DEPRECATED
|
src/Nri/Ui/Button/V8.elm,Html,DEPRECATED
|
||||||
src/Nri/Ui/Icon/V3.elm,Accessibility.Role,DEPRECATED
|
src/Nri/Ui/Icon/V3.elm,Accessibility.Role,DEPRECATED
|
||||||
src/Nri/Ui/Icon/V3.elm,Html,DEPRECATED
|
src/Nri/Ui/Icon/V3.elm,Html,DEPRECATED
|
||||||
|
|
@ -1,362 +0,0 @@
|
|||||||
module Nri.Ui.SortableTable.V1 exposing
|
|
||||||
( Column, Config, Sorter, State
|
|
||||||
, init, initDescending
|
|
||||||
, custom, string, view, viewLoading
|
|
||||||
, invariantSort, simpleSort, combineSorters
|
|
||||||
)
|
|
||||||
|
|
||||||
{-|
|
|
||||||
|
|
||||||
@docs Column, Config, Sorter, State
|
|
||||||
@docs init, initDescending
|
|
||||||
@docs custom, string, view, viewLoading
|
|
||||||
@docs invariantSort, simpleSort, combineSorters
|
|
||||||
|
|
||||||
-}
|
|
||||||
|
|
||||||
import Color
|
|
||||||
import Css exposing (..)
|
|
||||||
import Css.Global exposing (Snippet, adjacentSiblings, children, class, descendants, each, everything, media, selector, withClass)
|
|
||||||
import Html.Styled as Html exposing (Html)
|
|
||||||
import Html.Styled.Attributes exposing (css)
|
|
||||||
import Html.Styled.Events
|
|
||||||
import Nri.Ui.Colors.Extra
|
|
||||||
import Nri.Ui.Colors.V1
|
|
||||||
import Nri.Ui.CssVendorPrefix.V1 as CssVendorPrefix
|
|
||||||
import Nri.Ui.Table.V4
|
|
||||||
import Svg.Styled as Svg exposing (Svg)
|
|
||||||
import Svg.Styled.Attributes as SvgAttributes
|
|
||||||
|
|
||||||
|
|
||||||
type SortDirection
|
|
||||||
= Ascending
|
|
||||||
| Descending
|
|
||||||
|
|
||||||
|
|
||||||
{-| -}
|
|
||||||
type alias Sorter a =
|
|
||||||
SortDirection -> a -> a -> Order
|
|
||||||
|
|
||||||
|
|
||||||
{-| -}
|
|
||||||
type Column id entry msg
|
|
||||||
= Column
|
|
||||||
{ id : id
|
|
||||||
, header : Html msg
|
|
||||||
, view : entry -> Html msg
|
|
||||||
, sorter : Sorter entry
|
|
||||||
, width : Int
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{-| -}
|
|
||||||
type alias State id =
|
|
||||||
{ column : id
|
|
||||||
, sortDirection : SortDirection
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{-| -}
|
|
||||||
type alias Config id entry msg =
|
|
||||||
{ updateMsg : State id -> msg
|
|
||||||
, columns : List (Column id entry msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{-| -}
|
|
||||||
init : id -> State id
|
|
||||||
init initialSort =
|
|
||||||
{ column = initialSort
|
|
||||||
, sortDirection = Ascending
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{-| -}
|
|
||||||
initDescending : id -> State id
|
|
||||||
initDescending initialSort =
|
|
||||||
{ column = initialSort
|
|
||||||
, sortDirection = Descending
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{-| -}
|
|
||||||
string :
|
|
||||||
{ id : id
|
|
||||||
, header : String
|
|
||||||
, value : entry -> String
|
|
||||||
, width : Int
|
|
||||||
}
|
|
||||||
-> Column id entry msg
|
|
||||||
string { id, header, value, width } =
|
|
||||||
Column
|
|
||||||
{ id = id
|
|
||||||
, header = Html.text header
|
|
||||||
, view = value >> Html.text
|
|
||||||
, sorter = simpleSort value
|
|
||||||
, width = width
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{-| -}
|
|
||||||
custom :
|
|
||||||
{ id : id
|
|
||||||
, header : Html msg
|
|
||||||
, view : entry -> Html msg
|
|
||||||
, sorter : Sorter entry
|
|
||||||
, width : Int
|
|
||||||
}
|
|
||||||
-> Column id entry msg
|
|
||||||
custom config =
|
|
||||||
Column
|
|
||||||
{ id = config.id
|
|
||||||
, header = config.header
|
|
||||||
, view = config.view
|
|
||||||
, sorter = config.sorter
|
|
||||||
, width = config.width
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{-| Create a sorter function that always orders the entries in the same order.
|
|
||||||
For example, this is useful when we want to resolve ties and sort the tied
|
|
||||||
entries by name, no matter of the sort direction set on the table.
|
|
||||||
-}
|
|
||||||
invariantSort : (entry -> comparable) -> Sorter entry
|
|
||||||
invariantSort mapper =
|
|
||||||
\sortDirection elem1 elem2 ->
|
|
||||||
compare (mapper elem1) (mapper elem2)
|
|
||||||
|
|
||||||
|
|
||||||
{-| Create a simple sorter function that orders entries by mapping a function
|
|
||||||
over the collection. It will also reverse it when the sort direction is descending.
|
|
||||||
-}
|
|
||||||
simpleSort : (entry -> comparable) -> Sorter entry
|
|
||||||
simpleSort mapper =
|
|
||||||
\sortDirection elem1 elem2 ->
|
|
||||||
let
|
|
||||||
result =
|
|
||||||
compare (mapper elem1) (mapper elem2)
|
|
||||||
in
|
|
||||||
case sortDirection of
|
|
||||||
Ascending ->
|
|
||||||
result
|
|
||||||
|
|
||||||
Descending ->
|
|
||||||
flipOrder result
|
|
||||||
|
|
||||||
|
|
||||||
flipOrder : Order -> Order
|
|
||||||
flipOrder order =
|
|
||||||
case order of
|
|
||||||
LT ->
|
|
||||||
GT
|
|
||||||
|
|
||||||
EQ ->
|
|
||||||
EQ
|
|
||||||
|
|
||||||
GT ->
|
|
||||||
LT
|
|
||||||
|
|
||||||
|
|
||||||
{-| -}
|
|
||||||
combineSorters : List (Sorter entry) -> Sorter entry
|
|
||||||
combineSorters sorters =
|
|
||||||
\sortDirection elem1 elem2 ->
|
|
||||||
let
|
|
||||||
folder =
|
|
||||||
\sorter acc ->
|
|
||||||
case acc of
|
|
||||||
EQ ->
|
|
||||||
sorter sortDirection elem1 elem2
|
|
||||||
|
|
||||||
_ ->
|
|
||||||
acc
|
|
||||||
in
|
|
||||||
List.foldl folder EQ sorters
|
|
||||||
|
|
||||||
|
|
||||||
{-| -}
|
|
||||||
viewLoading : Config id entry msg -> State id -> Html msg
|
|
||||||
viewLoading config state =
|
|
||||||
let
|
|
||||||
tableColumns =
|
|
||||||
List.map (buildTableColumn config.updateMsg state) config.columns
|
|
||||||
in
|
|
||||||
Nri.Ui.Table.V4.viewLoading
|
|
||||||
tableColumns
|
|
||||||
|
|
||||||
|
|
||||||
{-| -}
|
|
||||||
view : Config id entry msg -> State id -> List entry -> Html msg
|
|
||||||
view config state entries =
|
|
||||||
let
|
|
||||||
tableColumns =
|
|
||||||
List.map (buildTableColumn config.updateMsg state) config.columns
|
|
||||||
|
|
||||||
sorter =
|
|
||||||
findSorter config.columns state.column
|
|
||||||
in
|
|
||||||
Nri.Ui.Table.V4.view
|
|
||||||
tableColumns
|
|
||||||
(List.sortWith (sorter state.sortDirection) entries)
|
|
||||||
|
|
||||||
|
|
||||||
findSorter : List (Column id entry msg) -> id -> Sorter entry
|
|
||||||
findSorter columns columnId =
|
|
||||||
columns
|
|
||||||
|> listExtraFind (\(Column column) -> column.id == columnId)
|
|
||||||
|> Maybe.map (\(Column column) -> column.sorter)
|
|
||||||
|> Maybe.withDefault identitySorter
|
|
||||||
|
|
||||||
|
|
||||||
{-| Taken from <https://github.com/elm-community/list-extra/blob/8.2.0/src/List/Extra.elm#L556>
|
|
||||||
-}
|
|
||||||
listExtraFind : (a -> Bool) -> List a -> Maybe a
|
|
||||||
listExtraFind predicate list =
|
|
||||||
case list of
|
|
||||||
[] ->
|
|
||||||
Nothing
|
|
||||||
|
|
||||||
first :: rest ->
|
|
||||||
if predicate first then
|
|
||||||
Just first
|
|
||||||
|
|
||||||
else
|
|
||||||
listExtraFind predicate rest
|
|
||||||
|
|
||||||
|
|
||||||
identitySorter : Sorter a
|
|
||||||
identitySorter =
|
|
||||||
\sortDirection item1 item2 ->
|
|
||||||
EQ
|
|
||||||
|
|
||||||
|
|
||||||
buildTableColumn : (State id -> msg) -> State id -> Column id entry msg -> Nri.Ui.Table.V4.Column entry msg
|
|
||||||
buildTableColumn updateMsg state (Column column) =
|
|
||||||
Nri.Ui.Table.V4.custom
|
|
||||||
{ header = viewSortHeader column.header updateMsg state column.id
|
|
||||||
, view = column.view
|
|
||||||
, width = Css.px (toFloat column.width)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
viewSortHeader : Html msg -> (State id -> msg) -> State id -> id -> Html msg
|
|
||||||
viewSortHeader header updateMsg state id =
|
|
||||||
let
|
|
||||||
nextState =
|
|
||||||
nextTableState state id
|
|
||||||
in
|
|
||||||
Html.div
|
|
||||||
[ css
|
|
||||||
[ Css.displayFlex
|
|
||||||
, Css.alignItems Css.center
|
|
||||||
, Css.justifyContent Css.spaceBetween
|
|
||||||
, cursor pointer
|
|
||||||
, CssVendorPrefix.property "user-select" "none"
|
|
||||||
, if state.column == id then
|
|
||||||
fontWeight bold
|
|
||||||
|
|
||||||
else
|
|
||||||
fontWeight normal
|
|
||||||
]
|
|
||||||
, Html.Styled.Events.onClick (updateMsg nextState)
|
|
||||||
]
|
|
||||||
[ Html.div [] [ header ]
|
|
||||||
, viewSortButton updateMsg state id
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
viewSortButton : (State id -> msg) -> State id -> id -> Html msg
|
|
||||||
viewSortButton updateMsg state id =
|
|
||||||
let
|
|
||||||
arrows upHighlighted downHighlighted =
|
|
||||||
Html.div
|
|
||||||
[ css
|
|
||||||
[ Css.displayFlex
|
|
||||||
, Css.flexDirection Css.column
|
|
||||||
, Css.alignItems Css.center
|
|
||||||
, Css.justifyContent Css.center
|
|
||||||
]
|
|
||||||
]
|
|
||||||
[ sortArrow Up upHighlighted
|
|
||||||
, sortArrow Down downHighlighted
|
|
||||||
]
|
|
||||||
|
|
||||||
buttonContent =
|
|
||||||
case ( state.column == id, state.sortDirection ) of
|
|
||||||
( True, Ascending ) ->
|
|
||||||
arrows True False
|
|
||||||
|
|
||||||
( True, Descending ) ->
|
|
||||||
arrows False True
|
|
||||||
|
|
||||||
( False, _ ) ->
|
|
||||||
arrows False False
|
|
||||||
in
|
|
||||||
Html.div [ css [ padding (px 2) ] ] [ buttonContent ]
|
|
||||||
|
|
||||||
|
|
||||||
nextTableState : State id -> id -> State id
|
|
||||||
nextTableState state id =
|
|
||||||
if state.column == id then
|
|
||||||
{ column = id
|
|
||||||
, sortDirection = flipSortDirection state.sortDirection
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{ column = id
|
|
||||||
, sortDirection = Ascending
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
flipSortDirection : SortDirection -> SortDirection
|
|
||||||
flipSortDirection order =
|
|
||||||
case order of
|
|
||||||
Ascending ->
|
|
||||||
Descending
|
|
||||||
|
|
||||||
Descending ->
|
|
||||||
Ascending
|
|
||||||
|
|
||||||
|
|
||||||
type Direction
|
|
||||||
= Up
|
|
||||||
| Down
|
|
||||||
|
|
||||||
|
|
||||||
sortArrow : Direction -> Bool -> Html msg
|
|
||||||
sortArrow direction active =
|
|
||||||
Html.div
|
|
||||||
[ css
|
|
||||||
[ width (px 8)
|
|
||||||
, height (px 6)
|
|
||||||
, position relative
|
|
||||||
, margin2 (px 1) zero
|
|
||||||
]
|
|
||||||
]
|
|
||||||
[ Svg.svg
|
|
||||||
[ SvgAttributes.viewBox "0 0 8 6"
|
|
||||||
, SvgAttributes.css
|
|
||||||
[ position absolute
|
|
||||||
, top zero
|
|
||||||
, left zero
|
|
||||||
, case direction of
|
|
||||||
Up ->
|
|
||||||
Css.batch []
|
|
||||||
|
|
||||||
Down ->
|
|
||||||
Css.batch [ transform <| rotate (deg 180) ]
|
|
||||||
]
|
|
||||||
, if active then
|
|
||||||
SvgAttributes.fill (toCssString Nri.Ui.Colors.V1.azure)
|
|
||||||
|
|
||||||
else
|
|
||||||
SvgAttributes.fill (toCssString Nri.Ui.Colors.V1.gray75)
|
|
||||||
]
|
|
||||||
[ Svg.polygon [ SvgAttributes.points "0 6 4 0 8 6 0 6" ] []
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
toCssString : Css.Color -> String
|
|
||||||
toCssString =
|
|
||||||
Color.toRGBString << Nri.Ui.Colors.Extra.fromCssColor
|
|
@ -12,7 +12,7 @@ import Example exposing (Example)
|
|||||||
import Html.Styled as Html
|
import Html.Styled as Html
|
||||||
import KeyboardSupport exposing (Direction(..), Key(..))
|
import KeyboardSupport exposing (Direction(..), Key(..))
|
||||||
import Nri.Ui.Heading.V2 as Heading
|
import Nri.Ui.Heading.V2 as Heading
|
||||||
import Nri.Ui.SortableTable.V1 as SortableTable
|
import Nri.Ui.SortableTable.V2 as SortableTable
|
||||||
|
|
||||||
|
|
||||||
type Column
|
type Column
|
||||||
@ -35,7 +35,7 @@ type alias State =
|
|||||||
{-| -}
|
{-| -}
|
||||||
example : Example State Msg
|
example : Example State Msg
|
||||||
example =
|
example =
|
||||||
{ name = "Nri.Ui.SortableTable.V1"
|
{ name = "Nri.Ui.SortableTable.V2"
|
||||||
, categories = [ Tables, Layout ]
|
, categories = [ Tables, Layout ]
|
||||||
, atomicDesignType = Molecule
|
, atomicDesignType = Molecule
|
||||||
, keyboardSupport = []
|
, keyboardSupport = []
|
||||||
@ -53,12 +53,14 @@ example =
|
|||||||
, header = "First name"
|
, header = "First name"
|
||||||
, value = .firstName
|
, value = .firstName
|
||||||
, width = 125
|
, width = 125
|
||||||
|
, cellStyles = \_ -> []
|
||||||
}
|
}
|
||||||
, SortableTable.string
|
, SortableTable.string
|
||||||
{ id = LastName
|
{ id = LastName
|
||||||
, header = "Last name"
|
, header = "Last name"
|
||||||
, value = .lastName
|
, value = .lastName
|
||||||
, width = 125
|
, width = 125
|
||||||
|
, cellStyles = \_ -> []
|
||||||
}
|
}
|
||||||
, SortableTable.custom
|
, SortableTable.custom
|
||||||
{ id = Coins
|
{ id = Coins
|
||||||
@ -66,6 +68,7 @@ example =
|
|||||||
, view = .coins >> String.fromInt >> Html.text
|
, view = .coins >> String.fromInt >> Html.text
|
||||||
, sorter = SortableTable.simpleSort .coins
|
, sorter = SortableTable.simpleSort .coins
|
||||||
, width = 125
|
, width = 125
|
||||||
|
, cellStyles = \_ -> []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
module Spec.Nri.Ui.SortableTable.V1 exposing (spec)
|
module Spec.Nri.Ui.SortableTable.V2 exposing (spec)
|
||||||
|
|
||||||
import Expect exposing (Expectation)
|
import Expect exposing (Expectation)
|
||||||
import Html.Styled
|
import Html.Styled
|
||||||
import Nri.Ui.SortableTable.V1 as SortableTable
|
import Nri.Ui.SortableTable.V2 as SortableTable
|
||||||
import Test exposing (..)
|
import Test exposing (..)
|
||||||
import Test.Html.Query as Query
|
import Test.Html.Query as Query
|
||||||
import Test.Html.Selector as Selector
|
import Test.Html.Selector as Selector
|
||||||
@ -33,12 +33,14 @@ config =
|
|||||||
, header = "First name"
|
, header = "First name"
|
||||||
, value = .firstName
|
, value = .firstName
|
||||||
, width = 125
|
, width = 125
|
||||||
|
, cellStyles = \_ -> []
|
||||||
}
|
}
|
||||||
, SortableTable.string
|
, SortableTable.string
|
||||||
{ id = LastName
|
{ id = LastName
|
||||||
, header = "Last name"
|
, header = "Last name"
|
||||||
, value = .lastName
|
, value = .lastName
|
||||||
, width = 125
|
, width = 125
|
||||||
|
, cellStyles = \_ -> []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
@ -45,7 +45,6 @@
|
|||||||
"Nri.Ui.Select.V7",
|
"Nri.Ui.Select.V7",
|
||||||
"Nri.Ui.Slide.V1",
|
"Nri.Ui.Slide.V1",
|
||||||
"Nri.Ui.SlideModal.V2",
|
"Nri.Ui.SlideModal.V2",
|
||||||
"Nri.Ui.SortableTable.V1",
|
|
||||||
"Nri.Ui.SortableTable.V2",
|
"Nri.Ui.SortableTable.V2",
|
||||||
"Nri.Ui.Svg.V1",
|
"Nri.Ui.Svg.V1",
|
||||||
"Nri.Ui.Table.V4",
|
"Nri.Ui.Table.V4",
|
||||||
|
Loading…
Reference in New Issue
Block a user