Added Switch Widget #5

This commit is contained in:
Lucas Payr 2021-01-20 16:24:06 +01:00
parent 2bc1d31d09
commit 643a68595f
16 changed files with 436 additions and 41 deletions

View File

@ -3,6 +3,7 @@ module Data.Example exposing (Example, Model, Msg, asList, fromString, init, sub
import Data.Style exposing (Style)
import Element exposing (Element)
import Example.Button as Button
import Example.Switch as Switch
import Example.Dialog as Dialog
import Example.ExpansionPanel as ExpansionPanel
import Example.List as List
@ -19,6 +20,7 @@ import View.Test as Test
type Example
= ButtonExample
| SwitchExample
| SelectExample
| MultiSelectExample
| ExpansionPanelExample
@ -34,6 +36,7 @@ type Example
asList : List Example
asList =
[ ButtonExample
, SwitchExample
, SelectExample
, MultiSelectExample
, ExpansionPanelExample
@ -54,6 +57,9 @@ toString example =
ButtonExample ->
"Button"
SwitchExample ->
"Switch"
SelectExample ->
"Select"
@ -91,6 +97,9 @@ fromString string =
"Button" ->
Just ButtonExample
"Switch" ->
Just SwitchExample
"Select" ->
Just SelectExample
@ -131,6 +140,9 @@ get example =
ButtonExample ->
.button
SwitchExample ->
.switch
SelectExample ->
.select
@ -168,6 +180,9 @@ toTests example =
ButtonExample ->
Test.button
SwitchExample ->
Test.switch
SelectExample ->
Test.select
@ -201,6 +216,7 @@ toTests example =
type Msg
= Button Button.Msg
| Switch Switch.Msg
| Select Select.Msg
| MultiSelect MultiSelect.Msg
| ExpansionPanel ExpansionPanel.Msg
@ -215,6 +231,7 @@ type Msg
type alias Model =
{ button : Button.Model
, switch : Switch.Model
, select : Select.Model
, multiSelect : MultiSelect.Model
, expansionPanel : ExpansionPanel.Model
@ -239,6 +256,7 @@ type alias UpgradeRecord model msg =
type alias UpgradeCollection =
{ button : UpgradeRecord Button.Model Button.Msg
, switch : UpgradeRecord Switch.Model Switch.Msg
, select : UpgradeRecord Select.Model Select.Msg
, multiSelect : UpgradeRecord MultiSelect.Model MultiSelect.Msg
, expansionPanel : UpgradeRecord ExpansionPanel.Model ExpansionPanel.Msg
@ -254,6 +272,7 @@ type alias UpgradeCollection =
type alias ExampleView msg =
{ button : Element msg
, switch : Element msg
, select : Element msg
, multiSelect : Element msg
, expansionPanel : Element msg
@ -273,6 +292,9 @@ init =
( buttonModel, buttonMsg ) =
Button.init
( switchModel, switchMsg ) =
Switch.init
( selectModel, selectMsg ) =
Select.init
@ -304,6 +326,7 @@ init =
ProgressIndicator.init
in
( { button = buttonModel
, switch = switchModel
, select = selectModel
, multiSelect = multiSelectModel
, expansionPanel = expansionPanelModel
@ -316,6 +339,7 @@ init =
, progressIndicator = progressIndicatorModel
}
, [ Cmd.map Button buttonMsg
, Cmd.map Switch switchMsg
, Cmd.map Select selectMsg
, Cmd.map MultiSelect multiSelectMsg
, Cmd.map ExpansionPanel expansionPanelMsg
@ -340,6 +364,13 @@ upgradeRecord =
, updateFun = Button.update
, subscriptionsFun = Button.subscriptions
}
, switch =
{ from = .switch
, to = \model a -> { model | switch = a }
, msgMapper = Switch
, updateFun = Switch.update
, subscriptionsFun = Switch.subscriptions
}
, select =
{ from = .select
, to = \model a -> { model | select = a }
@ -419,6 +450,9 @@ update msg model =
Button m ->
updateField .button m
Switch m ->
updateField .switch m
Select m ->
updateField .select m
@ -459,6 +493,7 @@ subscriptions model =
subscriptionsFun (from model) |> Sub.map msgMapper
in
[ upgradeRecord.button |> subFun
, upgradeRecord.switch |> subFun
, upgradeRecord.select |> subFun
, upgradeRecord.multiSelect |> subFun
, upgradeRecord.expansionPanel |> subFun
@ -481,6 +516,8 @@ view :
view msgMapper style model =
{ button =
Button.view (Button >> msgMapper) style (.button model)
, switch =
Switch.view (Switch >> msgMapper) style (.switch model)
, select =
Select.view (Select >> msgMapper) style (.select model)
, multiSelect =

View File

@ -12,6 +12,7 @@ import Widget.Style
, SortTableStyle
, TabStyle
, TextInputStyle
, SwitchStyle
)
@ -19,6 +20,7 @@ type alias Style msg =
{ dialog : DialogStyle msg
, expansionPanel : ExpansionPanelStyle msg
, button : ButtonStyle msg
, switch : SwitchStyle msg
, primaryButton : ButtonStyle msg
, tab : TabStyle msg
, textInput : TextInputStyle msg

View File

@ -333,8 +333,6 @@ layout =
Color.light ++ Group.center
}
style : Style msg
style =
{ sortTable = sortTable
, row = row

View File

@ -54,4 +54,5 @@ style palette =
, dialog = Material.alertDialog palette
, progressIndicator = Material.progressIndicator palette
, layout = Material.layout palette
, switch = Material.switch palette
}

View File

@ -260,7 +260,6 @@ layout =
}
style : Style msg
style =
{ sortTable = sortTable
, row = row
@ -277,4 +276,5 @@ style =
, dialog = dialog
, progressIndicator = progressIndicator
, layout = Template.layout "layout"
, switch = button
}

View File

@ -25,4 +25,5 @@ style =
, dialog = Template.dialog "dialog"
, progressIndicator = Template.progressIndicator "progressIndicator"
, layout = Template.layout "layout"
, switch = Template.switch <| "switch"
}

View File

@ -8,9 +8,7 @@ import Widget.Style.Material
import Data.Style.SemanticUI
type Theme
= ElmUiFramework
| SemanticUI
| Template
= Template
| Material
| DarkMaterial
@ -18,12 +16,6 @@ type Theme
toStyle : Theme -> Style msg
toStyle theme =
case theme of
ElmUiFramework ->
Data.Style.ElmUiFramework.style
SemanticUI ->
Data.Style.SemanticUI.style
Template ->
Data.Style.Template.style

View File

@ -0,0 +1,69 @@
module Example.Switch exposing (Model, Msg, init, subscriptions, update, view)
import Element exposing (Element)
import FeatherIcons
import Widget
import Widget.Style exposing (SwitchStyle, RowStyle)
import Widget.Style.Material as Material
import Browser
type alias Style style msg =
{ style
| switch : SwitchStyle msg
}
materialStyle : Style {} msg
materialStyle =
{ switch = Material.switch Material.defaultPalette
}
type Model
= IsButtonEnabled Bool
type Msg
= ToggledButtonStatus
init : ( Model, Cmd Msg )
init =
( IsButtonEnabled False
, Cmd.none
)
update : Msg -> Model -> ( Model, Cmd Msg )
update msg (IsButtonEnabled buttonEnabled) =
case msg of
ToggledButtonStatus ->
( IsButtonEnabled <| not buttonEnabled
, Cmd.none
)
subscriptions : Model -> Sub Msg
subscriptions _ =
Sub.none
{-| You can remove the msgMapper. But by doing so, make sure to also change `msg` to `Msg` in the line below.
--}
view : (Msg -> msg) -> Style style msg -> Model -> Element msg
view msgMapper style (IsButtonEnabled isButtonEnabled) =
Widget.switch style.switch
{ description = "click me"
, active = isButtonEnabled
, onPress =
ToggledButtonStatus
|> msgMapper
|> Just
}
main : Program () Model Msg
main =
Browser.element
{ init = always init
, view = view identity materialStyle >> Element.layout []
, update = update
, subscriptions = subscriptions
}

View File

@ -345,24 +345,6 @@ view model =
, text = "Dark Material Theme"
, icon = Icons.penTool |> Element.html |> Element.el []
}
, { onPress =
if m.theme /= SemanticUI then
Just <| SetTheme <| SemanticUI
else
Nothing
, text = "Semantic UI Theme"
, icon = Icons.penTool |> Element.html |> Element.el []
}
, { onPress =
if m.theme /= ElmUiFramework then
Just <| SetTheme <| ElmUiFramework
else
Nothing
, text = "Elm-Ui-Framework Theme"
, icon = Icons.penTool |> Element.html |> Element.el []
}
, { onPress =
if m.theme /= Template then
Just <| SetTheme <| Template

View File

@ -1,4 +1,4 @@
module View.Test exposing (button, dialog, expansionPanel, list, modal, multiSelect, progressIndicator, select, sortTable, tab, textInput)
module View.Test exposing (button,switch, dialog, expansionPanel, list, modal, multiSelect, progressIndicator, select, sortTable, tab, textInput)
import Data.Style exposing (Style)
import Element exposing (Element)
@ -57,6 +57,30 @@ button idle style =
)
]
switch : msg -> Style msg -> List ( String, Element msg )
switch idle style =
[ ( "Disabled switch"
, Widget.switch style.switch
{ description = "Disabled switch"
, onPress = Nothing
, active = False
}
)
, ( "Inactive Select switch"
, Widget.switch style.switch
{ description = "Inactive Select switch"
, onPress = Just idle
, active = False
}
)
, ( "Active Select switch"
, Widget.switch style.switch
{ description = "Active Select switch"
, onPress = Just idle
, active = True
}
)
]
select : msg -> Style msg -> List ( String, Element msg )
select idle style =

View File

@ -38,8 +38,7 @@ iconButton style { onPress, text, icon } =
++ [ Region.description text ]
)
{ onPress = onPress
, label =
icon |> Element.map never |> Element.el style.labelRow
, label = icon |> Element.map never |> Element.el style.labelRow
}
@ -73,4 +72,3 @@ button style { onPress, text, icon } =
, Element.text text |> Element.el style.text
]
}

65
src/Internal/Switch.elm Normal file
View File

@ -0,0 +1,65 @@
module Internal.Switch exposing (Switch, switch)
import Element exposing (Element)
import Element.Input as Input
import Element.Region as Region
import Widget.Style exposing (SwitchStyle)
type alias Switch msg =
{ description : String
, onPress : Maybe msg
, active : Bool
}
switch : SwitchStyle msg -> Switch msg -> Element msg
switch style { onPress, description, active } =
Input.button
(style.containerButton
++ [ Region.description description
, Element.none
|> Element.el
(style.contentInFront.content.container
++ (
if active then
style.contentInFront.content.ifActive
else if onPress == Nothing then
style.contentInFront.content.ifDisabled
else
style.contentInFront.content.otherwise
))
|> Element.el
(style.contentInFront.container
++ (
if active then
style.contentInFront.ifActive
else if onPress == Nothing then
style.contentInFront.ifDisabled
else
style.contentInFront.otherwise
))
|> Element.inFront
]
)
{ onPress = onPress
, label =
Element.none
|> Element.el
( style.content.container
++ (
if active then
style.content.ifActive
else if onPress == Nothing then
style.content.ifDisabled
else
style.content.otherwise
)
)
}

View File

@ -10,6 +10,7 @@ module Widget exposing
, Tab, tab
, ProgressIndicator, circularProgressIndicator
, Dialog, ExpansionPanel
, Switch, switch
)
{-| This module contains different stateless view functions. No wiring required.
@ -46,6 +47,11 @@ You can create you own widgets by sticking widgets types together.
@docs Button, TextButton, iconButton, textButton, button
# Switch
@docs Switch, switch
# Select
![Select](https://orasund.github.io/elm-ui-widgets/assets/select.png)
@ -139,10 +145,11 @@ import Internal.List as List
import Internal.ProgressIndicator as ProgressIndicator
import Internal.Select as Select
import Internal.SortTable as SortTable
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, TabStyle, TextInputStyle)
import Widget.Style exposing (ButtonStyle, ColumnStyle, DialogStyle, ExpansionPanelStyle, ProgressIndicatorStyle, RowStyle, SortTableStyle, SwitchStyle, TabStyle, TextInputStyle)
@ -229,6 +236,39 @@ button =
{----------------------------------------------------------
- SWITCH
----------------------------------------------------------}
{-| Switch widget type
-}
type alias Switch msg =
{ description : String
, onPress : Maybe msg
, active : Bool
}
{-| A boolean switch
-}
switch :
SwitchStyle msg
->
{ description : String
, onPress : Maybe msg
, active : Bool
}
-> Element msg
switch =
let
fun : SwitchStyle msg -> Switch msg -> Element msg
fun =
Switch.switch
in
fun
{----------------------------------------------------------
- SELECT
----------------------------------------------------------}

View File

@ -1,8 +1,11 @@
module Widget.Style exposing (ButtonStyle, ColumnStyle, DialogStyle, ExpansionPanelStyle, LayoutStyle, RowStyle, SnackbarStyle, SortTableStyle, TabStyle, TextInputStyle, ProgressIndicatorStyle)
module Widget.Style exposing
( ButtonStyle, ColumnStyle, DialogStyle, ExpansionPanelStyle, LayoutStyle, RowStyle, SnackbarStyle, SortTableStyle, TabStyle, TextInputStyle, ProgressIndicatorStyle
, SwitchStyle
)
{-| This module contains style types for every widget.
@docs ButtonStyle, ColumnStyle, DialogStyle, ExpansionPanelStyle, LayoutStyle, RowStyle, SnackbarStyle, SortTableStyle, TabStyle, TextInputStyle, ProgressIndicatorStyle
@docs ButtonStyle,SwitchStyle, ColumnStyle, DialogStyle, ExpansionPanelStyle, LayoutStyle, RowStyle, SnackbarStyle, SortTableStyle, TabStyle, TextInputStyle, ProgressIndicatorStyle
-}
@ -10,6 +13,30 @@ import Element exposing (Attribute, Element)
import Html exposing (Html)
{-| -}
type alias SwitchStyle msg =
{ containerButton : List (Attribute msg)
, content :
{ container : List (Attribute msg)
, ifDisabled : List (Attribute msg)
, ifActive : List (Attribute msg)
, otherwise : List (Attribute msg)
}
, contentInFront :
{ container : List (Attribute msg)
, ifDisabled : List (Attribute msg)
, ifActive : List (Attribute msg)
, otherwise : List (Attribute msg)
, content :
{ container : List (Attribute msg)
, ifDisabled : List (Attribute msg)
, ifActive : List (Attribute msg)
, otherwise : List (Attribute msg)
}
}
}
{-| -}
type alias ButtonStyle msg =
{ container : List (Attribute msg)

View File

@ -1,7 +1,7 @@
module Widget.Style.Material exposing
( Palette, defaultPalette, darkPalette
, containedButton, outlinedButton, textButton
, iconButton, toggleButton, buttonRow
, iconButton, toggleButton, buttonRow, switch
, cardColumn
, chip, textInput
, alertDialog
@ -94,6 +94,10 @@ Different styles for buttons have different meanings.
@docs iconButton, toggleButton, buttonRow
# Switch
@docs switch
# Card
@ -174,6 +178,7 @@ import Widget.Style
, ProgressIndicatorStyle
, RowStyle
, SnackbarStyle
, SwitchStyle
, TabStyle
, TextInputStyle
)
@ -638,6 +643,135 @@ iconButton palette =
}
{-| A boolean switch
Technical Remark:
- The specification states that the disabled switch should have a color dependend on its activness. This is not implemented.
-}
switch : Palette -> SwitchStyle msg
switch palette =
{ containerButton =
[ Element.height <| Element.px 38
, Element.width <| Element.px 58
, Element.mouseDown []
, Element.focused []
, Element.mouseOver []
]
, content =
{ container =
[ Element.height <| Element.px 14
, Element.width <| Element.px 34
, Border.rounded <| 10
]
, ifDisabled =
[ Element.htmlAttribute <| Attributes.style "cursor" "not-allowed"
, palette.surface
|> MaterialColor.withShade MaterialColor.gray (0.5 * MaterialColor.buttonDisabledOpacity)
|> fromColor
|> Background.color
]
, ifActive = [
palette.primary
|> MaterialColor.scaleOpacity 0.5
|> fromColor
|> Background.color
]
, otherwise = [
MaterialColor.gray
|> MaterialColor.scaleOpacity 0.5
|> fromColor
|> Background.color
]
}
, contentInFront =
{ container =
[ Element.height <| Element.px 38
, Element.width <| Element.px 38
, Border.rounded <| 19
]
, ifDisabled =
[ Element.htmlAttribute <| Attributes.style "cursor" "not-allowed" ]
, ifActive =
[ Element.mouseDown
[ palette.primary
|> MaterialColor.scaleOpacity MaterialColor.buttonPressedOpacity
|> fromColor
|> Background.color
]
, Element.focused
[ palette.primary
|> MaterialColor.scaleOpacity MaterialColor.buttonFocusOpacity
|> fromColor
|> Background.color
]
, Element.mouseOver
[ palette.primary
|> MaterialColor.scaleOpacity MaterialColor.buttonHoverOpacity
|> fromColor
|> Background.color
]
, Element.alignRight
]
, otherwise =
[ Element.mouseDown
[ Color.gray
|> MaterialColor.scaleOpacity MaterialColor.buttonPressedOpacity
|> fromColor
|> Background.color
]
, Element.focused
[ Color.gray
|> MaterialColor.scaleOpacity MaterialColor.buttonFocusOpacity
|> fromColor
|> Background.color
]
, Element.mouseOver
[ Color.gray
|> MaterialColor.scaleOpacity MaterialColor.buttonHoverOpacity
|> fromColor
|> Background.color
]
, Element.alignLeft
]
, content =
{ container =
[ Element.height <| Element.px 20
, Element.width <| Element.px 20
, Element.centerY
, Element.centerX
, Border.rounded <| 10
,Border.shadow <| MaterialColor.shadow 2
, palette.surface
|> fromColor
|> Background.color
]
, ifDisabled =
[ palette.surface
|> MaterialColor.withShade Color.gray MaterialColor.buttonDisabledOpacity
|> fromColor
|> Background.color
, Element.mouseDown []
, Element.mouseOver []
, Element.focused []
]
, ifActive =
[ palette.primary
|> MaterialColor.withShade palette.on.primary MaterialColor.buttonHoverOpacity
|> fromColor
|> Background.color
]
, otherwise =
[ palette.surface
|> MaterialColor.withShade palette.on.surface MaterialColor.buttonHoverOpacity
|> fromColor
|> Background.color
]
}
}
}
{-------------------------------------------------------------------------------
-- C H I P

View File

@ -1,6 +1,6 @@
module Widget.Style.Template exposing
( box, decoration, icon
, button, column, dialog, expansionPanel, layout, row, snackbar, sortTable, tab, textInput, progressIndicator
, button, switch, column, dialog, expansionPanel, layout, row, snackbar, sortTable, tab, textInput, progressIndicator
)
{-| ![Example using the Template style](https://orasund.github.io/elm-ui-widgets/assets/template-style.png)
@ -54,7 +54,7 @@ style =
# Mockups
@docs button, column, dialog, expansionPanel, layout, row, snackbar, sortTable, tab, textInput, progressIndicator
@docs button, switch, column, dialog, expansionPanel, layout, row, snackbar, sortTable, tab, textInput, progressIndicator
-}
@ -75,6 +75,7 @@ import Widget.Style
, SortTableStyle
, TabStyle
, TextInputStyle
, SwitchStyle
)
@ -123,6 +124,30 @@ icon string =
Element.text string
]
{-| A boolean switch
-}
switch : String -> SwitchStyle msg
switch string =
{ containerButton = box <| string ++ ":containerButton"
, content =
{ container = box <| string ++ ":content:container"
, ifDisabled = decoration <| string ++ ":content:ifDisabled"
, ifActive = decoration <| string ++ ":content:ifActive"
, otherwise = decoration <| string ++ ":content:otherwise"
}
, contentInFront =
{ container = box <| string ++ ":contentInFront:container"
, ifDisabled = decoration <| string ++ ":contentInFront:ifDisabled"
, ifActive = decoration <| string ++ ":contentInFront:ifActive"
, otherwise = decoration <| string ++ ":contentInFront:otherwise"
, content =
{ container = box <| string ++ ":contentInFront:content:container"
, ifDisabled = decoration <| string ++ ":contentInFront:content:ifDisabled"
, ifActive = decoration <| string ++ ":contentInFront:content:ifActive"
, otherwise = decoration <| string ++ ":contentInFront:content:otherwise"
}
}
}
{-|