reworked Lists

This commit is contained in:
Lucas Payr 2021-01-22 15:05:25 +01:00
parent 4ef62708a6
commit abb7ec3a7f
14 changed files with 698 additions and 382 deletions

View File

@ -2,9 +2,9 @@
This package contains **independent** widgets (no components) written for [Elm-Ui](https://dark.elm.dmy.fr/packages/mdgriffith/elm-ui/latest/). These widgets have no dependencies to other parts of this package. So you can just use as much as you need.
It also supports custom themes and has a material design theme already ready to use.
[Examples of all widgets can be found here](https://orasund.github.io/elm-ui-widgets/2.0.0/).
* It also supports custom themes and has a material design theme already ready to use.
* [Examples of all widgets can be found here](https://orasund.github.io/elm-ui-widgets/2.0.0/).
* It is highly customizable. Checkout [Widget.Style.Customize](https://package.elm-lang.org/packages/Orasund/elm-ui-widgets/latest/Widget-Style-Customize) for more information.
Feel free to start an [issue on the repository](https://github.com/Orasund/elm-ui-widgets/issues) if you have any questions.
@ -26,7 +26,7 @@ Let's look at the button widget.
button: ButtonStyle msg
->
{ text : String
, icon : Element Never
, icon : Icon
, onPress : Maybe msg
}
-> Element msg
@ -36,14 +36,17 @@ In comparison to Elm-Ui's button, we see that `List (Attribute msg)` has change
```
type alias ButtonStyle msg =
{ element : List (Attribute msg)
, content :
{ elementRow : List (Attribute msg)
, contentText : List (Attribute msg)
}
}
, ifDisabled : List (Attribute msg)
, ifActive : List (Attribute msg)
, otherwise : List (Attribute msg)
, content :
{ elementRow : List (Attribute msg)
, content :
{ text : { contentText : List (Attribute msg) }
, icon : IconStyle
}
}
}
}
```
@ -55,7 +58,7 @@ iconButton :
ButtonStyle msg
->
{ text : String --for screen readers
, icon : Element Never
, icon : Icon
, onPress : Maybe msg
}
-> Element msg
@ -75,7 +78,7 @@ button :
ButtonStyle msg
->
{ text : String
, icon : Element Never
, icon : Icon
, onPress : Maybe msg
}
-> Element msg
@ -86,7 +89,7 @@ We also have a `Widget Type` for the button:
```
type alias Button msg =
{ text : String
, icon : Element Never
, icon : Icon
, onPress : Maybe msg
}
```
@ -99,7 +102,7 @@ type alias Select msg =
, options :
List
{ text : String
, icon : Element Never
, icon : Icon
}
, onSelect : Int -> Maybe msg
}
@ -152,4 +155,5 @@ This package tries to solve both of these problems.
## Changelog
* **Version 3.0.0** - Reworked Style Types making it easier to customize. Added full icon support.
* **Version 2.0.0** - Complete rewrite of the package. Now including a material design implementation.

View File

@ -19,6 +19,7 @@ import Widget.Style
type alias Style msg =
{ dialog : DialogStyle msg
, expansionPanel : ExpansionPanelStyle msg
, expansionPanelItem : ExpansionPanelStyle msg
, button : ButtonStyle msg
, switch : SwitchStyle msg
, primaryButton : ButtonStyle msg

View File

@ -54,6 +54,7 @@ style palette =
, textInput = Material.textInput palette
, chipButton = Material.chip palette
, expansionPanel = Material.expansionPanel palette
, expansionPanelItem = Material.expansionPanelItem palette
, dialog = Material.alertDialog palette
, progressIndicator = Material.progressIndicator palette
, layout = Material.layout palette

View File

@ -75,8 +75,8 @@ view msgMapper style (Selected selected) =
}
|> Widget.multiSelect
|> Widget.buttonRow
{ list = style.buttonRow
, button = style.selectButton
{ elementRow = style.buttonRow
, content = style.selectButton
}

View File

@ -67,8 +67,8 @@ view msgMapper style (Selected selected) =
}
|> Widget.select
|> Widget.buttonRow
{ list = style.buttonRow
, button = style.selectButton
{ elementRow = style.buttonRow
, content = style.selectButton
}

View File

@ -26,7 +26,7 @@ import Widget
import Widget.Icon as Icon
import Widget.Layout as Layout exposing (Layout, Part)
import Widget.ScrollingNav as ScrollingNav
import Element.Input as Input
type alias LoadedModel =
{ stateless : Stateless.Model
@ -354,9 +354,14 @@ view model =
|> Element.el Heading.h1
, search =
Just
{ text = m.search.raw
{ chips = []
, text = m.search.raw
, onChange = ChangedSearch
, label = "Search"
, placeholder =
Just <|
Input.placeholder []
<| Element.text "Search Widgets..."
}
}
<|
@ -431,7 +436,7 @@ viewLoaded m =
[]
else
[ Widget.expansionPanel style.expansionPanel
[ Widget.expansionPanel style.expansionPanelItem
{ onToggle =
always
(name

View File

@ -102,8 +102,8 @@ select idle style =
}
|> Widget.select
|> Widget.buttonRow
{ list = style.buttonRow
, button = style.selectButton
{ elementRow = style.buttonRow
, content = style.selectButton
}
)
, ( "Nothing selected"
@ -120,8 +120,8 @@ select idle style =
}
|> Widget.select
|> Widget.buttonRow
{ list = style.buttonRow
, button = style.selectButton
{ elementRow = style.buttonRow
, content = style.selectButton
}
)
, ( "Invalid selection"
@ -138,8 +138,8 @@ select idle style =
}
|> Widget.select
|> Widget.buttonRow
{ list = style.buttonRow
, button = style.selectButton
{ elementRow = style.buttonRow
, content = style.selectButton
}
)
, ( "Disabled selection"
@ -156,8 +156,8 @@ select idle style =
}
|> Widget.select
|> Widget.buttonRow
{ list = style.buttonRow
, button = style.selectButton
{ elementRow = style.buttonRow
, content = style.selectButton
}
)
, ( "Empty Options"
@ -174,8 +174,8 @@ select idle style =
}
|> Widget.select
|> Widget.buttonRow
{ list = style.buttonRow
, button = style.selectButton
{ elementRow = style.buttonRow
, content = style.selectButton
}
)
]
@ -197,8 +197,8 @@ multiSelect idle style =
}
|> Widget.multiSelect
|> Widget.buttonRow
{ list = style.buttonRow
, button = style.selectButton
{ elementRow = style.buttonRow
, content = style.selectButton
}
)
, ( "Nothing selected"
@ -215,8 +215,8 @@ multiSelect idle style =
}
|> Widget.multiSelect
|> Widget.buttonRow
{ list = style.buttonRow
, button = style.selectButton
{ elementRow = style.buttonRow
, content = style.selectButton
}
)
, ( "Invalid selection"
@ -233,8 +233,8 @@ multiSelect idle style =
}
|> Widget.multiSelect
|> Widget.buttonRow
{ list = style.buttonRow
, button = style.selectButton
{ elementRow = style.buttonRow
, content = style.selectButton
}
)
, ( "Disabled selection"
@ -251,8 +251,8 @@ multiSelect idle style =
}
|> Widget.multiSelect
|> Widget.buttonRow
{ list = style.buttonRow
, button = style.selectButton
{ elementRow = style.buttonRow
, content = style.selectButton
}
)
, ( "Empty Options"
@ -269,8 +269,8 @@ multiSelect idle style =
}
|> Widget.multiSelect
|> Widget.buttonRow
{ list = style.buttonRow
, button = style.selectButton
{ elementRow = style.buttonRow
, content = style.selectButton
}
)
]

View File

@ -3,17 +3,12 @@ module Internal.List exposing (buttonColumn, buttonRow, column, row)
import Element exposing (Attribute, Element)
import Internal.Button exposing (Button)
import Internal.Select as Select
import Widget.Style exposing (ButtonStyle, ColumnStyle, RowStyle)
import Widget.Style exposing (ButtonStyle, ColumnStyle, ItemStyle, RowStyle)
import Widget.Style.Customize as Customize
internal :
{ list
| content : List (Attribute msg)
, ifFirst : List (Attribute msg)
, ifLast : List (Attribute msg)
, otherwise : List (Attribute msg)
}
ItemStyle msg
-> List (Element msg)
-> List (Element msg)
internal style list =
@ -21,9 +16,9 @@ internal style list =
|> List.indexedMap
(\i ->
Element.el <|
style.content
style.element
++ (if List.length list == 1 then
[]
style.ifSingleton
else if i == 0 then
style.ifFirst
@ -39,23 +34,21 @@ internal style list =
row : RowStyle msg -> List (Element msg) -> Element msg
row style =
internal style >> Element.row style.elementRow
internal style.content >> Element.row style.elementRow
column : ColumnStyle msg -> List (Element msg) -> Element msg
column style =
internal style >> Element.column style.elementColumn
internal style.content >> Element.column style.elementColumn
internalButton :
{ list :
{ list
| content : List (Attribute msg)
, ifFirst : List (Attribute msg)
, ifLast : List (Attribute msg)
, otherwise : List (Attribute msg)
}
, button : ButtonStyle msg
{ element : List (Attribute msg)
, ifSingleton : List (Attribute msg)
, ifFirst : List (Attribute msg)
, ifLast : List (Attribute msg)
, otherwise : List (Attribute msg)
, content : ButtonStyle msg
}
-> List ( Bool, Button msg )
-> List (Element msg)
@ -64,20 +57,20 @@ internalButton style list =
|> List.indexedMap
(\i ->
Select.selectButton
(style.button
(style.content
|> Customize.elementButton
(style.list.content
(style.element
++ (if List.length list == 1 then
[]
style.ifSingleton
else if i == 0 then
style.list.ifFirst
style.ifFirst
else if i == (List.length list - 1) then
style.list.ifLast
style.ifLast
else
style.list.otherwise
style.otherwise
)
)
)
@ -85,20 +78,36 @@ internalButton style list =
buttonRow :
{ list : RowStyle msg
, button : ButtonStyle msg
{ elementRow : RowStyle msg
, content : ButtonStyle msg
}
-> List ( Bool, Button msg )
-> Element msg
buttonRow style =
internalButton style >> Element.row style.list.elementRow
internalButton
{ element = style.elementRow.content.element
, ifSingleton = style.elementRow.content.ifSingleton
, ifFirst = style.elementRow.content.ifFirst
, ifLast = style.elementRow.content.ifLast
, otherwise = style.elementRow.content.otherwise
, content = style.content
}
>> Element.row style.elementRow.elementRow
buttonColumn :
{ list : ColumnStyle msg
, button : ButtonStyle msg
{ elementColumn : ColumnStyle msg
, content : ButtonStyle msg
}
-> List ( Bool, Button msg )
-> Element msg
buttonColumn style =
internalButton style >> Element.column style.list.elementColumn
internalButton
{ element = style.elementColumn.content.element
, ifSingleton = style.elementColumn.content.ifSingleton
, ifFirst = style.elementColumn.content.ifFirst
, ifLast = style.elementColumn.content.ifLast
, otherwise = style.elementColumn.content.otherwise
, content = style.content
}
>> Element.column style.elementColumn.elementColumn

View File

@ -10,6 +10,7 @@ module Widget exposing
, TextInput, textInput
, Tab, tab
, ProgressIndicator, circularProgressIndicator
, buttonSheet
)
{-| This module contains different stateless view functions. No wiring required.
@ -90,7 +91,7 @@ You can create you own widgets by sticking widgets types together.
[Open in Ellie](https://ellie-app.com/9p5RJnDVVCKa1)
@docs row, column, buttonRow, buttonColumn
@docs row, column, buttonRow, buttonColumn, buttonDrawer
# Sort Table
@ -144,7 +145,20 @@ import Internal.Switch as Switch
import Internal.Tab as Tab
import Internal.TextInput as TextInput
import Set exposing (Set)
import Widget.Style exposing (ButtonStyle, ColumnStyle, DialogStyle, ExpansionPanelStyle, ProgressIndicatorStyle, RowStyle, SortTableStyle, SwitchStyle, TabStyle, TextInputStyle)
import Widget.Style
exposing
( ButtonSheetStyle
, ButtonStyle
, ColumnStyle
, DialogStyle
, ExpansionPanelStyle
, ProgressIndicatorStyle
, RowStyle
, SortTableStyle
, SwitchStyle
, TabStyle
, TextInputStyle
)
@ -494,8 +508,8 @@ column =
{-| A row of buttons
-}
buttonRow :
{ list : RowStyle msg
, button : ButtonStyle msg
{ elementRow : RowStyle msg
, content : ButtonStyle msg
}
-> List ( Bool, Button msg )
-> Element msg
@ -506,8 +520,8 @@ buttonRow =
{-| A column of buttons
-}
buttonColumn :
{ list : ColumnStyle msg
, button : ButtonStyle msg
{ elementColumn : ColumnStyle msg
, content : ButtonStyle msg
}
-> List ( Bool, Button msg )
-> Element msg
@ -515,6 +529,21 @@ buttonColumn =
List.buttonColumn
{-| A side sheet containing only buttons. Will use the full hight.
-}
buttonSheet :
ButtonSheetStyle msg
-> List (Button msg)
-> Element msg
buttonSheet style actions =
actions
|> List.map (button style.content.content)
|> Element.column
(style.content.elementColumn ++ [ Element.width <| Element.fill ])
|> Element.el
(style.element ++ [ Element.height <| Element.fill ])
{----------------------------------------------------------
- SORT TABLE

View File

@ -29,9 +29,10 @@ import Array
import Element exposing (Attribute, DeviceClass(..), Element)
import Element.Input as Input
import Html exposing (Html)
import Widget exposing (Button, Select)
import Widget exposing (Button, Select, TextInput)
import Widget.Snackbar as Snackbar exposing (Message)
import Widget.Style exposing (LayoutStyle)
import Widget.Style exposing (ButtonStyle, LayoutStyle, TextInputStyle)
import Widget.Style.Customize as Customize
{-| The currently visible part: either the left sheet, right sheet or the search bar
@ -95,7 +96,203 @@ timePassed sec layout =
}
{-| View the layout. Replacement of `Element.layout`.
--------------------------------------------------------------------------------
-- View
--------------------------------------------------------------------------------
getDeviceClass : { height : Int, width : Int } -> DeviceClass
getDeviceClass window =
window
|> Element.classifyDevice
|> .class
partitionActions : List (Button msg) -> { primaryActions : List (Button msg), moreActions : List (Button msg) }
partitionActions actions =
{ primaryActions =
if (actions |> List.length) > 4 then
actions |> List.take 2
else if (actions |> List.length) == 4 then
actions |> List.take 1
else if (actions |> List.length) == 3 then
[]
else
actions |> List.take 2
, moreActions =
if (actions |> List.length) > 4 then
actions |> List.drop 2
else if (actions |> List.length) == 4 then
actions |> List.drop 1
else if (actions |> List.length) == 3 then
actions
else
actions |> List.drop 2
}
viewNav :
LayoutStyle msg
->
{ title : Element msg
, menu : Select msg
, deviceClass : DeviceClass
, onChangedSidebar : Maybe Part -> msg
, primaryActions : List (Button msg)
, moreActions : List (Button msg)
, search : Maybe (TextInput msg)
}
-> Element msg
viewNav style { title, menu, deviceClass, onChangedSidebar, primaryActions, moreActions, search } =
[ (if
(deviceClass == Phone)
|| (deviceClass == Tablet)
|| ((menu.options |> List.length) > 5)
then
[ Widget.iconButton style.menuButton
{ onPress = Just <| onChangedSidebar <| Just LeftSheet
, icon = style.menuIcon
, text = "Menu"
}
, menu.selected
|> Maybe.andThen
(\option ->
menu.options
|> Array.fromList
|> Array.get option
)
|> Maybe.map (.text >> Element.text)
|> Maybe.withDefault title
|> Element.el style.title
]
else
[ title |> Element.el style.title
, menu
|> Widget.select
|> List.map (Widget.selectButton style.menuTabButton)
|> Element.row
[ Element.width <| Element.shrink
]
]
)
|> Element.row
[ Element.width <| Element.shrink
, Element.spacing style.spacing
]
, if deviceClass == Phone || deviceClass == Tablet then
Element.none
else
search
|> Maybe.map
(\{ onChange, text, label } ->
Widget.textInput style.search
{ chips = []
, onChange = onChange
, text = text
, placeholder =
Just <|
Input.placeholder [] <|
Element.text label
, label = label
}
)
|> Maybe.withDefault Element.none
, [ search
|> Maybe.map
(\{ label } ->
if deviceClass == Tablet then
[ Widget.button style.menuButton
{ onPress = Just <| onChangedSidebar <| Just Search
, icon = style.searchIcon
, text = label
}
]
else if deviceClass == Phone then
[ Widget.iconButton style.menuButton
{ onPress = Just <| onChangedSidebar <| Just Search
, icon = style.searchIcon
, text = label
}
]
else
[]
)
|> Maybe.withDefault []
, primaryActions
|> List.map
(if deviceClass == Phone then
Widget.iconButton style.menuButton
else
Widget.button style.menuButton
)
, if moreActions |> List.isEmpty then
[]
else
[ Widget.iconButton style.menuButton
{ onPress = Just <| onChangedSidebar <| Just RightSheet
, icon = style.moreVerticalIcon
, text = "More"
}
]
]
|> List.concat
|> Element.row
[ Element.width <| Element.shrink
, Element.alignRight
]
]
|> Element.row
(style.header
++ [ Element.padding 0
, Element.centerX
, Element.spacing style.spacing
, Element.alignTop
, Element.width <| Element.fill
]
)
{-| left sheet.
-}
viewLeftSheet :
LayoutStyle msg
->
{ title : Element msg
, menu : Select msg
}
-> Element msg
viewLeftSheet style { title, menu } =
[ [ title
]
, menu
|> Widget.select
|> List.map
(Widget.selectButton style.sheetButton)
]
|> List.concat
|> Element.column [ Element.width <| Element.fill ]
|> Element.el
(style.sheet
++ [ Element.height <| Element.fill
, Element.alignLeft
]
)
{-| View the layout.
-}
view :
LayoutStyle msg
@ -105,12 +302,7 @@ view :
, layout : Layout msg
, title : Element msg
, menu : Select msg
, search :
Maybe
{ onChange : String -> msg
, text : String
, label : String
}
, search : Maybe (TextInput msg)
, actions : List (Button msg)
, onChangedSidebar : Maybe Part -> msg
}
@ -120,148 +312,24 @@ view style { search, title, onChangedSidebar, menu, actions, window, dialog, lay
let
deviceClass : DeviceClass
deviceClass =
window
|> Element.classifyDevice
|> .class
getDeviceClass window
( primaryActions, moreActions ) =
( if (actions |> List.length) > 4 then
actions |> List.take 2
else if (actions |> List.length) == 4 then
actions |> List.take 1
else if (actions |> List.length) == 3 then
[]
else
actions |> List.take 2
, if (actions |> List.length) > 4 then
actions |> List.drop 2
else if (actions |> List.length) == 4 then
actions |> List.drop 1
else if (actions |> List.length) == 3 then
actions
else
actions |> List.drop 2
)
{ primaryActions, moreActions } =
partitionActions actions
nav : Element msg
nav =
[ (if
(deviceClass == Phone)
|| (deviceClass == Tablet)
|| ((menu.options |> List.length) > 5)
then
[ Widget.iconButton style.menuButton
{ onPress = Just <| onChangedSidebar <| Just LeftSheet
, icon = style.menuIcon
, text = "Menu"
}
, menu.selected
|> Maybe.andThen
(\option ->
menu.options
|> Array.fromList
|> Array.get option
)
|> Maybe.map (.text >> Element.text)
|> Maybe.withDefault title
|> Element.el style.title
]
else
[ title |> Element.el style.title
, menu
|> Widget.select
|> List.map (Widget.selectButton style.menuTabButton)
|> Element.row
[ Element.width <| Element.shrink
]
]
)
|> Element.row
[ Element.width <| Element.shrink
, Element.spacing style.spacing
]
, if deviceClass == Phone || deviceClass == Tablet then
Element.none
else
search
|> Maybe.map
(\{ onChange, text, label } ->
Input.text style.search
{ onChange = onChange
, text = text
, placeholder =
Just <|
Input.placeholder [] <|
Element.text label
, label = Input.labelHidden label
}
)
|> Maybe.withDefault Element.none
, [ search
|> Maybe.map
(\{ label } ->
if deviceClass == Tablet then
[ Widget.button style.menuButton
{ onPress = Just <| onChangedSidebar <| Just Search
, icon = style.searchIcon
, text = label
}
]
else if deviceClass == Phone then
[ Widget.iconButton style.menuButton
{ onPress = Just <| onChangedSidebar <| Just Search
, icon = style.searchIcon
, text = label
}
]
else
[]
)
|> Maybe.withDefault []
, primaryActions
|> List.map
(if deviceClass == Phone then
Widget.iconButton style.menuButton
else
Widget.button style.menuButton
)
, if moreActions |> List.isEmpty then
[]
else
[ Widget.iconButton style.menuButton
{ onPress = Just <| onChangedSidebar <| Just RightSheet
, icon = style.moreVerticalIcon
, text = "More"
}
]
]
|> List.concat
|> Element.row
[ Element.width <| Element.shrink
, Element.alignRight
]
]
|> Element.row
(style.header
++ [ Element.padding 0
, Element.centerX
, Element.spacing style.spacing
, Element.alignTop
, Element.width <| Element.fill
]
)
viewNav style
{ title = title
, menu = menu
, deviceClass = deviceClass
, onChangedSidebar = onChangedSidebar
, primaryActions = primaryActions
, moreActions = moreActions
, search = search
}
snackbar : Element msg
snackbar =
layout.snackbar
|> Snackbar.view style.snackbar identity
@ -277,56 +345,42 @@ view style { search, title, onChangedSidebar, menu, actions, window, dialog, lay
sheet =
case layout.active of
Just LeftSheet ->
[ [ title
]
, menu
|> Widget.select
|> List.map
(Widget.selectButton style.sheetButton)
]
|> List.concat
|> Element.column [ Element.width <| Element.fill ]
|> Element.el
(style.sheet
++ [ Element.height <| Element.fill
, Element.alignLeft
]
)
viewLeftSheet style
{ title = title
, menu = menu
}
Just RightSheet ->
moreActions
|> List.map (Widget.button style.sheetButton)
|> Element.column [ Element.width <| Element.fill ]
|> Element.el
(style.sheet
++ [ Element.height <| Element.fill
, Element.alignRight
]
)
Widget.buttonSheet
{ element = style.sheet ++ [ Element.alignRight ]
, content =
{ elementColumn = []
, content = style.sheetButton
}
}
moreActions
Just Search ->
case search of
Just { onChange, text, label } ->
Input.text
search
|> Maybe.map
(Widget.textInput
(style.searchFill
++ [ Element.width <| Element.fill
]
|> Customize.mapContent
(\record ->
{ record
| text =
record.text
|> Customize.elementTextInput
[ Element.width <| Element.fill ]
}
)
)
{ onChange = onChange
, text = text
, placeholder =
Just <|
Input.placeholder [] <|
Element.text label
, label = Input.labelHidden label
}
|> Element.el
>> Element.el
[ Element.alignTop
, Element.width <| Element.fill
]
Nothing ->
Element.none
)
|> Maybe.withDefault Element.none
Nothing ->
Element.none

View File

@ -1,8 +1,14 @@
module Widget.Style exposing (ButtonStyle, SwitchStyle, ColumnStyle, DialogStyle, ExpansionPanelStyle, LayoutStyle, RowStyle, SnackbarStyle, SortTableStyle, TabStyle, TextInputStyle, ProgressIndicatorStyle)
module Widget.Style exposing
( IconStyle, ButtonStyle, SwitchStyle, ColumnStyle, DialogStyle, ItemStyle
, ExpansionPanelStyle, LayoutStyle, RowStyle, SnackbarStyle, SortTableStyle
, TabStyle, TextInputStyle, ProgressIndicatorStyle, ButtonSheetStyle
)
{-| This module contains style types for every widget.
@docs ButtonStyle, SwitchStyle, ColumnStyle, DialogStyle, ExpansionPanelStyle, LayoutStyle, RowStyle, SnackbarStyle, SortTableStyle, TabStyle, TextInputStyle, ProgressIndicatorStyle
@docs IconStyle, ButtonStyle, SwitchStyle, ColumnStyle, DialogStyle, ItemStyle
@docs ExpansionPanelStyle, LayoutStyle, RowStyle, SnackbarStyle, SortTableStyle
@docs TabStyle, TextInputStyle, ProgressIndicatorStyle, ButtonSheetStyle
-}
@ -155,22 +161,36 @@ type alias TabStyle msg =
{-| -}
type alias RowStyle msg =
{ elementRow : List (Attribute msg)
type alias ItemStyle msg =
{ element : List (Attribute msg)
, ifFirst : List (Attribute msg)
, ifLast : List (Attribute msg)
, ifSingleton : List (Attribute msg)
, otherwise : List (Attribute msg)
, content : List (Attribute msg)
}
{-| -}
type alias RowStyle msg =
{ elementRow : List (Attribute msg)
, content : ItemStyle msg
}
{-| -}
type alias ColumnStyle msg =
{ elementColumn : List (Attribute msg)
, ifFirst : List (Attribute msg)
, ifLast : List (Attribute msg)
, otherwise : List (Attribute msg)
, content : List (Attribute msg)
, content : ItemStyle msg
}
{-| -}
type alias ButtonSheetStyle msg =
{ element : List (Attribute msg)
, content :
{ elementColumn : List (Attribute msg)
, content : ButtonStyle msg
}
}
@ -211,8 +231,8 @@ type alias LayoutStyle msg =
, spacing : Int
, title : List (Attribute msg)
, searchIcon : Icon
, search : List (Attribute msg)
, searchFill : List (Attribute msg)
, search : TextInputStyle msg
, searchFill : TextInputStyle msg
}

View File

@ -4,9 +4,15 @@ module Widget.Style.Customize exposing
, elementColumn, mapElementColumn
, elementRow, mapElementRow
, elementTable, mapElementTable
, elementTextInput, mapElementTextInput
, content, mapContent
, contentText, mapContentText
, contentInFront, mapContentInFront
, otherwise, mapOtherwise
, ifActive, mapIfActive
, ifDisabled, mapIfDisabled
, ifFirst, mapIfFirst
, ifLast, mapIfLast
)
{-| Each and every widget can be customized by modifing the Style Type.
@ -38,8 +44,29 @@ This module will contain helpfull functions to make customization easier.
# Element
A simple style type would be the following:
type alias MyStyle =
{ element : List (Attribute msg) }
myWidget : MyStyle -> Element msg
myWidget style =
Element.el style.element <| Element.none
@docs element, mapElement
A styling for a simple Elm-Ui button would be like this:
type alias MyStyle =
{ elementButton : List (Attribute msg) }
myWidget : MyStyle -> Element msg
myWidget style =
Element.button style.elementButton
{ onPress = Just Something
, label = Element.none
}
@docs elementButton, mapElementButton
@docs elementColumn, mapElementColumn
@ -53,15 +80,84 @@ This module will contain helpfull functions to make customization easier.
# Content
We can also style the content of an element.
type alias MyStyle =
{ element : List (Attribute msg)
, content : List (Attribute msg)
}
myWidget : MyStyle -> Element msg
myWidget style =
Element.el style.element <|
Element.el style.content <|
Element.none
@docs content, mapContent
If the content is just a text (or paragraph), then we use `contentText` instead:
type alias MyStyle =
{ element : List (Attribute msg)
, contentText : List (Attribute msg)
}
myWidget : MyStyle -> Element msg
myWidget style =
Element.el style.element <|
Element.text style.contentText <|
"Hello World"
@docs contentText, mapContentText
If some content is infront, we use `contentInFront`:
type alias MyStyle =
{ element : List (Attribute msg)
, content : List (Attribute msg)
, contentInFront : List (Attribute msg)
}
myWidget : MyStyle -> Element msg
myWidget style =
Element.el
(style.element
++ [ Element.contentInFront <|
Element.el style.contentInFront <|
Element.none
]
)
<|
Element.el style.contentInFront <|
Element.none
@docs contentInFront, mapContentInFront
# Conditional Styling
We can include styling that depends on some state.
type alias MyStyle =
{ element : List (Attribute msg)
, ifDisabled : List (Attribute msg)
, otherwise : List (Attribute msg)
}
myWidget : MyStyle -> Bool -> Element msg
myWidget style isDisabled =
Element.el
(style.element
++ (if isDisabled then
style.ifDisabled
else
style.otherwise
)
)
<|
Element.none
@docs otherwise, mapOtherwise
@docs ifActive, mapIfActive

View File

@ -6,7 +6,7 @@ module Widget.Style.Material exposing
, cardColumn
, chip, textInput
, alertDialog
, expansionPanel
, expansionPanel, expansionPanelItem
, row, column
, progressIndicator
, snackbar
@ -122,7 +122,7 @@ Thus for now we only provide a card containing a list.
# Expansion Panel
@docs expansionPanel
@docs expansionPanel, expansionPanelItem
# List
@ -1046,10 +1046,13 @@ row =
[ Element.paddingXY 0 8
, Element.spacing 8
]
, content = []
, ifFirst = []
, ifLast = []
, otherwise = []
, content =
{ element = []
, ifSingleton = []
, ifFirst = []
, ifLast = []
, otherwise = []
}
}
@ -1061,10 +1064,13 @@ column =
[ Element.paddingXY 0 8
, Element.spacing 8
]
, content = []
, ifFirst = []
, ifLast = []
, otherwise = []
, content =
{ element = []
, ifSingleton = []
, ifFirst = []
, ifLast = []
, otherwise = []
}
}
@ -1077,27 +1083,30 @@ buttonRow : RowStyle msg
buttonRow =
{ elementRow = []
, content =
[ Border.rounded 2
]
, ifFirst =
[ Border.roundEach
{ topLeft = 2
, topRight = 0
, bottomLeft = 2
, bottomRight = 0
}
]
, ifLast =
[ Border.roundEach
{ topLeft = 0
, topRight = 2
, bottomLeft = 0
, bottomRight = 2
}
]
, otherwise =
[ Border.rounded 0
]
{ element = []
, ifSingleton =
[ Border.rounded 2
]
, ifFirst =
[ Border.roundEach
{ topLeft = 2
, topRight = 0
, bottomLeft = 2
, bottomRight = 0
}
]
, ifLast =
[ Border.roundEach
{ topLeft = 0
, topRight = 2
, bottomLeft = 0
, bottomRight = 2
}
]
, otherwise =
[ Border.rounded 0
]
}
}
@ -1119,53 +1128,57 @@ cardColumn palette =
, Border.rounded 4
]
, content =
[ Element.padding 16
, Border.rounded 4
, Border.width 1
, palette.surface
|> fromColor
|> Background.color
, palette.surface
|> MaterialColor.accessibleTextColor
|> fromColor
|> Font.color
, palette.on.surface
|> MaterialColor.scaleOpacity 0.14
|> fromColor
|> Border.color
, Element.width <| Element.minimum 344 <| Element.fill
]
, ifFirst =
[ Border.roundEach
{ topLeft = 4
, topRight = 4
, bottomLeft = 0
, bottomRight = 0
}
]
, ifLast =
[ Border.roundEach
{ topLeft = 0
, topRight = 0
, bottomLeft = 4
, bottomRight = 4
}
, Border.widthEach
{ top = 0
, left = 1
, right = 1
, bottom = 1
}
]
, otherwise =
[ Border.rounded 0
, Border.widthEach
{ top = 0
, left = 1
, right = 1
, bottom = 1
}
]
{ element =
[ Element.padding 16
, Border.width 1
, palette.surface
|> fromColor
|> Background.color
, palette.surface
|> MaterialColor.accessibleTextColor
|> fromColor
|> Font.color
, palette.on.surface
|> MaterialColor.scaleOpacity 0.14
|> fromColor
|> Border.color
, Element.width <| Element.minimum 344 <| Element.fill
]
, ifSingleton =
[ Border.rounded 4
]
, ifFirst =
[ Border.roundEach
{ topLeft = 4
, topRight = 4
, bottomLeft = 0
, bottomRight = 0
}
]
, ifLast =
[ Border.roundEach
{ topLeft = 0
, topRight = 0
, bottomLeft = 4
, bottomRight = 4
}
, Border.widthEach
{ top = 0
, left = 1
, right = 1
, bottom = 1
}
]
, otherwise =
[ Border.rounded 0
, Border.widthEach
{ top = 0
, left = 1
, right = 1
, bottom = 1
}
]
}
}
@ -1271,16 +1284,46 @@ Technical Remarks:
-}
expansionPanel : Palette -> ExpansionPanelStyle msg
expansionPanel palette =
expansionPanelItem palette
|> Customize.mapContent
(\record ->
{ record
| panel =
record.panel
|> Customize.elementRow
[ Element.height <| Element.px 48
, Element.padding 14
]
, content =
record.content
|> Customize.element
[ Element.paddingEach
{ top = 0
, right = 14
, bottom = 14
, left = 14
}
]
}
)
{-| A variant on the expansion Panel optimized to be used inside a card.
This is a small workaround to allow expansion panels within cards.
-}
expansionPanelItem : Palette -> ExpansionPanelStyle msg
expansionPanelItem palette =
{ elementColumn =
[ Background.color <| fromColor <| palette.surface
, Element.spacing 14
, Element.width <| Element.fill
]
, content =
{ panel =
{ elementRow =
[ Element.height <| Element.px 48
, Element.spaceEvenly
, Element.padding 14
[ Element.spaceEvenly
, Element.width <| Element.fill
]
, content =
@ -1303,7 +1346,7 @@ expansionPanel palette =
}
}
, content =
{ element = [ Element.padding 14 ]
{ element = [ Element.width <| Element.fill ]
}
}
}
@ -1511,6 +1554,54 @@ textInput palette =
]
, Element.mouseOver [ Border.shadow <| MaterialColor.shadow 2 ]
]
, content =
{ chips =
{ elementRow = [ Element.spacing 8 ]
, content = chip palette
}
, text =
{ elementTextInput =
(palette.surface
|> textAndBackground
)
++ [ Border.width 0
, Element.mouseOver []
, Element.focused []
, Element.centerY
]
}
}
}
searchInput : Palette -> TextInputStyle msg
searchInput palette =
textInputBase palette
|> Customize.mapElementRow
(always
[ Element.alignRight
, Element.paddingXY 8 8
, Border.rounded 4
]
)
|> Customize.mapContent
(\record ->
{ record
| text =
record.text
|> Customize.elementTextInput
[ Border.width 0
, Element.paddingXY 8 8
, Element.height <| Element.px 32
, Element.width <| Element.maximum 360 <| Element.fill
]
}
)
textInputBase : Palette -> TextInputStyle msg
textInputBase palette =
{ elementRow = palette.surface |> textAndBackground
, content =
{ chips =
{ elementRow = [ Element.spacing 8 ]
@ -1824,7 +1915,7 @@ drawerButton palette =
, icon =
{ ifActive =
{ size = 18
, color = palette.primary
, color = palette.surface |> MaterialColor.accessibleTextColor
}
, ifDisabled =
{ size = 18
@ -1832,7 +1923,7 @@ drawerButton palette =
}
, otherwise =
{ size = 18
, color = palette.primary |> MaterialColor.accessibleTextColor
, color = palette.surface |> MaterialColor.accessibleTextColor
}
}
}
@ -1878,7 +1969,31 @@ layout palette =
, Element.padding 16
, Element.width <| Element.minimum 360 <| Element.fill
]
, menuButton = iconButton palette
, menuButton =
iconButton palette
|> Customize.mapContent
(Customize.mapContent
(\record ->
{ record
| icon =
{ ifActive =
{ size = record.icon.ifActive.size
, color =
palette.primary
|> MaterialColor.accessibleTextColor
}
, ifDisabled =
record.icon.ifDisabled
, otherwise =
{ size = record.icon.otherwise.size
, color =
palette.primary
|> MaterialColor.accessibleTextColor
}
}
}
)
)
, sheetButton = drawerButton palette
, menuTabButton = menuTabButton palette
, sheet =
@ -1892,24 +2007,6 @@ layout palette =
, spacing = 8
, title = Typography.h6 ++ [ Element.paddingXY 8 0 ]
, searchIcon = search
, search =
(palette.surface |> textAndBackground)
++ [ Element.spacing 8
, Element.paddingXY 8 8
, Element.height <| Element.px 32
, Border.width 1
, Border.rounded 4
, palette.on.surface
|> MaterialColor.scaleOpacity 0.14
|> fromColor
|> Border.color
, Element.focused
[ Border.shadow <| MaterialColor.shadow 4
]
, Element.mouseOver [ Border.shadow <| MaterialColor.shadow 2 ]
, Element.width <| Element.maximum 360 <| Element.fill
, Element.alignRight
]
, searchFill =
palette.surface |> textAndBackground
, search = searchInput palette
, searchFill = textInputBase palette
}

View File

@ -140,7 +140,7 @@ view msgMapper style (IsButtonEnabled isButtonEnabled) =
in
[ Widget.button (primaryButtonStyle color)
{ text = colorCode ++ " - Elm UI Widgets"
, icon = Element.none
, icon = always Element.none
, onPress =
if isButtonEnabled then
Noop