diff --git a/elm.json b/elm.json index 0b8bf4e..ae03e96 100644 --- a/elm.json +++ b/elm.json @@ -5,12 +5,10 @@ "license": "BSD-3-Clause", "version": "1.0.0", "exposed-modules": [ - "Widget", - "Widget.FilterSelect", - "Widget.ValidatedInput", + "Widget.Layout", + "Widget.Style", "Widget.ScrollingNav", - "Widget.Snackbar", - "Widget.SortTable" + "Widget.Snackbar" ], "elm-version": "0.19.0 <= v < 0.20.0", "dependencies": { @@ -29,4 +27,4 @@ "test-dependencies": { "elm-explorations/test": "1.2.1 <= v < 2.0.0" } -} +} \ No newline at end of file diff --git a/example/elm.json b/example/elm.json index ec138fb..d7b3bbb 100644 --- a/example/elm.json +++ b/example/elm.json @@ -8,6 +8,7 @@ "dependencies": { "direct": { "Orasund/elm-ui-framework": "1.6.1", + "avh4/elm-color": "1.0.0", "elm/browser": "1.0.2", "elm/core": "1.0.5", "elm/html": "1.0.0", @@ -17,14 +18,17 @@ "feathericons/elm-feather": "1.4.0", "jasonliang512/elm-heroicons": "1.0.2", "mdgriffith/elm-ui": "1.1.5", + "noahzgordon/elm-color-extra": "1.0.2", "ryannhg/elm-spa": "4.1.0", "turboMaCk/queue": "1.0.2", "wernerdegroot/listzipper": "4.0.0" }, "indirect": { "elm/json": "1.1.3", + "elm/regex": "1.0.0", "elm/url": "1.0.0", - "elm/virtual-dom": "1.0.2" + "elm/virtual-dom": "1.0.2", + "fredcy/elm-parseint": "2.0.1" } }, "test-dependencies": { diff --git a/example/src/Data/Example.elm b/example/src/Data/Example.elm index 881a8dd..e6e5424 100644 --- a/example/src/Data/Example.elm +++ b/example/src/Data/Example.elm @@ -3,10 +3,15 @@ module Data.Example exposing (Model, Msg, init, subscriptions, toCardList, updat import Data.Style exposing (Style) import Element exposing (Element) import Example.Button as Button +import Example.Dialog as Dialog import Example.ExpansionPanel as ExpansionPanel +import Example.List as List +import Example.Modal as Modal import Example.MultiSelect as MultiSelect import Example.Select as Select +import Example.SortTable as SortTable import Example.Tab as Tab +import Example.TextInput as TextInput import Framework.Grid as Grid import View.Test as Test @@ -17,6 +22,11 @@ type Msg | MultiSelect MultiSelect.Msg | ExpansionPanel ExpansionPanel.Msg | Tab Tab.Msg + | SortTable SortTable.Msg + | Modal Modal.Msg + | Dialog Dialog.Msg + | TextInput TextInput.Msg + | List List.Msg type alias Model = @@ -25,6 +35,34 @@ type alias Model = , multiSelect : MultiSelect.Model , expansionPanel : ExpansionPanel.Model , tab : Tab.Model + , sortTable : SortTable.Model + , modal : Modal.Model + , dialog : Dialog.Model + , textInput : TextInput.Model + , list : List.Model + } + + +type alias UpgradeRecord model msg = + { from : Model -> model + , to : Model -> model -> Model + , msgMapper : msg -> Msg + , updateFun : msg -> model -> ( model, Cmd msg ) + , subscriptionsFun : model -> Sub msg + } + + +type alias UpgradeCollection = + { button : UpgradeRecord Button.Model Button.Msg + , select : UpgradeRecord Select.Model Select.Msg + , multiSelect : UpgradeRecord MultiSelect.Model MultiSelect.Msg + , expansionPanel : UpgradeRecord ExpansionPanel.Model ExpansionPanel.Msg + , tab : UpgradeRecord Tab.Model Tab.Msg + , sortTable : UpgradeRecord SortTable.Model SortTable.Msg + , modal : UpgradeRecord Modal.Model Modal.Msg + , dialog : UpgradeRecord Dialog.Model Dialog.Msg + , textInput : UpgradeRecord TextInput.Model TextInput.Msg + , list : UpgradeRecord List.Model List.Msg } @@ -45,63 +83,175 @@ init = ( tabModel, tabMsg ) = Tab.init + + ( sortTableModel, sortTableMsg ) = + SortTable.init + + ( modalModel, modalMsg ) = + Modal.init + + ( dialogModel, dialogMsg ) = + Dialog.init + + ( textInputModel, textInputMsg ) = + TextInput.init + + ( listModel, listMsg ) = + List.init in ( { button = buttonModel , select = selectModel , multiSelect = multiSelectModel , expansionPanel = expansionPanelModel , tab = tabModel + , sortTable = sortTableModel + , modal = modalModel + , dialog = dialogModel + , textInput = textInputModel + , list = listModel } , [ Cmd.map Button buttonMsg , Cmd.map Select selectMsg , Cmd.map MultiSelect multiSelectMsg + , Cmd.map ExpansionPanel expansionPanelMsg , Cmd.map Tab tabMsg + , Cmd.map SortTable sortTableMsg + , Cmd.map Modal modalMsg + , Cmd.map Dialog dialogMsg + , Cmd.map TextInput textInputMsg + , Cmd.map List listMsg ] |> Cmd.batch ) +upgradeRecord : UpgradeCollection +upgradeRecord = + { button = + { from = .button + , to = \model a -> { model | button = a } + , msgMapper = Button + , updateFun = Button.update + , subscriptionsFun = Button.subscriptions + } + , select = + { from = .select + , to = \model a -> { model | select = a } + , msgMapper = Select + , updateFun = Select.update + , subscriptionsFun = Select.subscriptions + } + , multiSelect = + { from = .multiSelect + , to = \model a -> { model | multiSelect = a } + , msgMapper = MultiSelect + , updateFun = MultiSelect.update + , subscriptionsFun = MultiSelect.subscriptions + } + , expansionPanel = + { from = .expansionPanel + , to = \model a -> { model | expansionPanel = a } + , msgMapper = ExpansionPanel + , updateFun = ExpansionPanel.update + , subscriptionsFun = ExpansionPanel.subscriptions + } + , tab = + { from = .tab + , to = \model a -> { model | tab = a } + , msgMapper = Tab + , updateFun = Tab.update + , subscriptionsFun = Tab.subscriptions + } + , sortTable = + { from = .sortTable + , to = \model a -> { model | sortTable = a } + , msgMapper = SortTable + , updateFun = SortTable.update + , subscriptionsFun = SortTable.subscriptions + } + , modal = + { from = .modal + , to = \model a -> { model | modal = a } + , msgMapper = Modal + , updateFun = Modal.update + , subscriptionsFun = Modal.subscriptions + } + , dialog = + { from = .dialog + , to = \model a -> { model | dialog = a } + , msgMapper = Dialog + , updateFun = Dialog.update + , subscriptionsFun = Dialog.subscriptions + } + , textInput = + { from = .textInput + , to = \model a -> { model | textInput = a } + , msgMapper = TextInput + , updateFun = TextInput.update + , subscriptionsFun = TextInput.subscriptions + } + , list = + { from = .list + , to = \model a -> { model | list = a } + , msgMapper = List + , updateFun = List.update + , subscriptionsFun = List.subscriptions + } + } + + update : Msg -> Model -> ( Model, Cmd Msg ) update msg model = - case msg of - Button buttonMsg -> - Button.update buttonMsg model.button - |> Tuple.mapBoth - (\a -> { model | button = a }) - (Cmd.map Button) + (case msg of + Button m -> + updateField .button m - Select selectMsg -> - Select.update selectMsg model.select - |> Tuple.mapBoth - (\a -> { model | select = a }) - (Cmd.map Select) + Select m -> + updateField .select m - MultiSelect multiSelectMsg -> - MultiSelect.update multiSelectMsg model.multiSelect - |> Tuple.mapBoth - (\a -> { model | multiSelect = a }) - (Cmd.map MultiSelect) + MultiSelect m -> + updateField .multiSelect m - ExpansionPanel expansionPanelMsg -> - ExpansionPanel.update expansionPanelMsg model.expansionPanel - |> Tuple.mapBoth - (\a -> { model | expansionPanel = a }) - (Cmd.map ExpansionPanel) + ExpansionPanel m -> + updateField .expansionPanel m - Tab tabMsg -> - Tab.update tabMsg model.tab - |> Tuple.mapBoth - (\a -> { model | tab = a }) - (Cmd.map Tab) + Tab m -> + updateField .tab m + + SortTable m -> + updateField .sortTable m + + Modal m -> + updateField .modal m + + Dialog m -> + updateField .dialog m + + TextInput m -> + updateField .textInput m + + List m -> + updateField .list m + ) + model subscriptions : Model -> Sub Msg subscriptions model = - [ Button.subscriptions model.button |> Sub.map Button - , Select.subscriptions model.select |> Sub.map Select - , MultiSelect.subscriptions model.multiSelect |> Sub.map MultiSelect - , ExpansionPanel.subscriptions model.expansionPanel |> Sub.map ExpansionPanel - , Tab.subscriptions model.tab |> Sub.map Tab + let + subFun { from, msgMapper, subscriptionsFun } = + subscriptionsFun (from model) |> Sub.map msgMapper + in + [ upgradeRecord.button |> subFun + , upgradeRecord.select |> subFun + , upgradeRecord.multiSelect |> subFun + , upgradeRecord.expansionPanel |> subFun + , upgradeRecord.tab |> subFun + , upgradeRecord.sortTable |> subFun + , upgradeRecord.modal |> subFun + , upgradeRecord.dialog |> subFun + , upgradeRecord.textInput |> subFun + , upgradeRecord.list |> subFun ] |> Sub.batch @@ -116,33 +266,33 @@ view : , multiSelect : Element msg , expansionPanel : Element msg , tab : Element msg + , sortTable : Element msg + , modal : Element msg + , dialog : Element msg + , textInput : Element msg + , list : Element msg } view msgMapper style model = { button = - Button.view - (Button >> msgMapper) - style - model.button + Button.view (Button >> msgMapper) style (.button model) , select = - Select.view - (Select >> msgMapper) - style - model.select + Select.view (Select >> msgMapper) style (.select model) , multiSelect = - MultiSelect.view - (MultiSelect >> msgMapper) - style - model.multiSelect + MultiSelect.view (MultiSelect >> msgMapper) style (.multiSelect model) , expansionPanel = - ExpansionPanel.view - (ExpansionPanel >> msgMapper) - style - model.expansionPanel + ExpansionPanel.view (ExpansionPanel >> msgMapper) style (.expansionPanel model) , tab = - Tab.view - (Tab >> msgMapper) - style - model.tab + Tab.view (Tab >> msgMapper) style (.tab model) + , sortTable = + SortTable.view (SortTable >> msgMapper) style (.sortTable model) + , modal = + Modal.view (Modal >> msgMapper) style (.modal model) + , dialog = + Dialog.view (Dialog >> msgMapper) style (.dialog model) + , textInput = + TextInput.view (TextInput >> msgMapper) style (.textInput model) + , list = + List.view (List >> msgMapper) style (.list model) } @@ -154,9 +304,9 @@ toCardList : } -> List ( String, Element msg, Element msg ) toCardList { idle, msgMapper, style, model } = - [ { title = "Icon Button" + [ { title = "Button" , example = .button - , test = Test.iconButton + , test = Test.button } , { title = "Select" , example = .select @@ -174,7 +324,28 @@ toCardList { idle, msgMapper, style, model } = , example = .tab , test = Test.tab } + , { title = "Sort Table" + , example = .sortTable + , test = Test.sortTable + } + , { title = "Modal" + , example = .modal + , test = Test.modal + } + , { title = "Dialog" + , example = .dialog + , test = Test.dialog + } + , { title = "Text Input" + , example = .textInput + , test = Test.textInput + } + , { title = "List" + , example = .list + , test = Test.list + } ] + |> List.sortBy .title |> List.map (\{ title, example, test } -> ( title @@ -182,6 +353,39 @@ toCardList { idle, msgMapper, style, model } = |> view msgMapper style |> example , test idle style - |> Element.column Grid.simple + |> List.map + (\( name, elem ) -> + Element.row Grid.spacedEvenly + [ name + |> Element.text + |> List.singleton + |> Element.wrappedRow [ Element.width <| Element.shrink ] + , elem + |> Element.el [ Element.width <| Element.shrink ] + ] + ) + |> Element.column + (Grid.simple + ++ [ Element.width <| Element.fill ] + ) ) ) + + + +{------------------------------------------------------------------------------- +-------------------------------------------------------------------------------} + + +updateField : + (UpgradeCollection -> UpgradeRecord model msg) + -> msg + -> Model + -> ( Model, Cmd Msg ) +updateField getter msg model = + let + { from, to, msgMapper, updateFun } = + getter upgradeRecord + in + updateFun msg (from model) + |> Tuple.mapBoth (to model) (Cmd.map msgMapper) diff --git a/example/src/Data/Style.elm b/example/src/Data/Style.elm index ad1deb4..cd00a69 100644 --- a/example/src/Data/Style.elm +++ b/example/src/Data/Style.elm @@ -1,8 +1,17 @@ module Data.Style exposing (Style) -import Element exposing (Attribute) -import Widget.Style exposing (ButtonStyle, DialogStyle, ExpansionPanelStyle, - SnackbarStyle ,RowStyle,ColumnStyle,TextInputStyle,TabStyle) +import Widget.Style + exposing + ( ButtonStyle + , ColumnStyle + , DialogStyle + , ExpansionPanelStyle + , RowStyle + , SortTableStyle + , TabStyle + , TextInputStyle + ) + type alias Style msg = Widget.Style.Style @@ -16,5 +25,6 @@ type alias Style msg = , row : RowStyle msg , column : ColumnStyle msg , cardColumn : ColumnStyle msg + , sortTable : SortTableStyle msg } - msg \ No newline at end of file + msg diff --git a/example/src/Data/Style/ElmUiFramework.elm b/example/src/Data/Style/ElmUiFramework.elm index b16d5cc..9b522c5 100644 --- a/example/src/Data/Style/ElmUiFramework.elm +++ b/example/src/Data/Style/ElmUiFramework.elm @@ -1,9 +1,9 @@ module Data.Style.ElmUiFramework exposing (style) -import Element exposing (Attribute) +import Data.Style exposing (Style) +import Element import Element.Border as Border import Element.Font as Font -import Element.Input as Input import Framework import Framework.Button as Button import Framework.Card as Card @@ -11,12 +11,21 @@ import Framework.Color as Color import Framework.Grid as Grid import Framework.Group as Group import Framework.Heading as Heading -import Framework.Input as Input import Framework.Tag as Tag import Icons -import Data.Style exposing (Style) -import Widget.Style exposing (ButtonStyle, DialogStyle, ExpansionPanelStyle, - SnackbarStyle ,RowStyle,ColumnStyle,TextInputStyle,TabStyle) +import Widget.Style + exposing + ( ButtonStyle + , ColumnStyle + , DialogStyle + , ExpansionPanelStyle + , RowStyle + , SnackbarStyle + , SortTableStyle + , TabStyle + , TextInputStyle + ) + textButton : ButtonStyle msg textButton = @@ -24,6 +33,7 @@ textButton = , labelRow = Grid.simple , ifDisabled = Color.disabled , ifActive = Color.primary + , otherwise = [] } @@ -33,6 +43,7 @@ simpleButton = , labelRow = Grid.simple , ifDisabled = Color.disabled , ifActive = Color.primary + , otherwise = [] } @@ -57,6 +68,7 @@ menuTabButton = , labelRow = Grid.simple , ifDisabled = Color.disabled , ifActive = [ Border.color Color.turquoise ] + , otherwise = [] } @@ -66,6 +78,7 @@ menuButton = , container = Button.simple ++ Group.center ++ Color.dark , ifDisabled = Color.disabled , ifActive = Color.primary + , otherwise = [] } @@ -79,6 +92,7 @@ sheetButton = , labelRow = Grid.simple , ifDisabled = Color.disabled , ifActive = Color.primary + , otherwise = [] } @@ -88,6 +102,7 @@ buttonStyle = , container = Button.simple , ifDisabled = Color.disabled , ifActive = Color.primary + , otherwise = [] } @@ -97,6 +112,7 @@ snackbarButton = , container = Button.simple ++ Color.dark , ifDisabled = Color.disabled , ifActive = Color.primary + , otherwise = [] } @@ -106,8 +122,10 @@ tabButtonStyle = , container = Button.simple ++ Group.top , ifDisabled = Color.disabled , ifActive = Color.primary + , otherwise = [] } + textInputStyle : TextInputStyle msg textInputStyle = { chipButton = chipButtonStyle @@ -143,41 +161,43 @@ chipButtonStyle = , ifDisabled = [] , labelRow = Grid.simple , ifActive = Color.primary + , otherwise = [] } + expansionPanelStyle : ExpansionPanelStyle msg expansionPanelStyle = - { containerColumn = Card.simple ++ Grid.simple ++ [Element.height <| Element.shrink] - , panelRow = Grid.spacedEvenly ++ [Element.height <| Element.shrink] - , labelRow = Grid.simple ++ [Element.height <| Element.shrink] + { containerColumn = Card.simple ++ Grid.simple ++ [ Element.height <| Element.shrink ] + , panelRow = Grid.spacedEvenly ++ [ Element.height <| Element.shrink ] + , labelRow = Grid.simple ++ [ Element.height <| Element.shrink ] , content = [] - , expandIcon = Icons.chevronDown |> Element.html |> Element.el [] - , collapseIcon = Icons.chevronUp |> Element.html |> Element.el [] + , expandIcon = Icons.chevronDown |> Element.html |> Element.el [] + , collapseIcon = Icons.chevronUp |> Element.html |> Element.el [] } - dialog : DialogStyle msg dialog = { containerColumn = - Card.simple - ++ Grid.simple - ++ [ Element.centerY - , Element.width <| Element.minimum 280 <| Element.maximum 560 <| Element.fill - ] - , title = Heading.h3 - , buttonRow = - Grid.simple - ++ [ Element.paddingEach - { top = 28 - , bottom = 0 - , left = 0 - , right = 0 - } - ] - , acceptButton = simpleButton - , dismissButton = textButton - } + Card.simple + ++ Grid.simple + ++ [ Element.centerY + , Element.width <| Element.minimum 280 <| Element.maximum 560 <| Element.fill + ] + , title = Heading.h3 + , buttonRow = + Grid.simple + ++ [ Element.paddingEach + { top = 28 + , bottom = 0 + , left = 0 + , right = 0 + } + ] + , acceptButton = simpleButton + , dismissButton = textButton + } + snackbar : SnackbarStyle msg snackbar = @@ -186,19 +206,21 @@ snackbar = ++ Color.dark ++ Grid.simple ++ [ Element.paddingXY 8 6 - , Element.height <| Element.px <| 54 - ] + , Element.height <| Element.px <| 54 + ] , button = snackbarButton , text = [ Element.paddingXY 8 0 ] } + tab : TabStyle msg tab = { button = tabButtonStyle - , optionRow = Grid.simple - , containerColumn = Grid.compact - , content = (Card.small ++ Group.bottom) - } + , optionRow = Grid.simple + , containerColumn = Grid.compact + , content = Card.small ++ Group.bottom + } + row : RowStyle msg row = @@ -206,30 +228,44 @@ row = , element = [] , ifFirst = Group.left , ifLast = Group.right - , ifCenter = Group.center + , otherwise = Group.center } + cardColumn : ColumnStyle msg cardColumn = - { containerColumn = Grid.compact ++ [Element.height <| Element.fill] - , element = Card.large ++ [Element.height <| Element.fill] + { containerColumn = Grid.compact ++ [ Element.height <| Element.fill ] + , element = Card.large ++ [ Element.height <| Element.fill ] , ifFirst = Group.top , ifLast = Group.bottom - , ifCenter = Group.center + , otherwise = Group.center } + column : ColumnStyle msg column = { containerColumn = Grid.compact , element = [] , ifFirst = Group.top , ifLast = Group.bottom - , ifCenter =Group.center + , otherwise = Group.center } + +sortTable : SortTableStyle msg +sortTable = + { containerTable = Grid.simple + , headerButton = tabButtonStyle + , ascIcon = Icons.chevronUp |> Element.html |> Element.el [] + , descIcon = Icons.chevronDown |> Element.html |> Element.el [] + , defaultIcon = Element.none + } + + style : Style msg style = - { row = row + { sortTable = sortTable + , row = row , cardColumn = cardColumn , column = column , button = buttonStyle diff --git a/example/src/Data/Style/Material.elm b/example/src/Data/Style/Material.elm new file mode 100644 index 0000000..250319f --- /dev/null +++ b/example/src/Data/Style/Material.elm @@ -0,0 +1,393 @@ +module Data.Style.Material exposing (Palette, defaultPalette, style) + +import Color exposing (Color) +import Color.Accessibility as Accessibility +import Color.Convert as Convert +import Color.Manipulate as Manipulate +import Data.Style exposing (Style) +import Element exposing (Attribute, Element) +import Element.Background as Background +import Element.Border as Border +import Element.Font as Font +import Html.Attributes as Attributes +import Widget.Style + exposing + ( ButtonStyle + , ColumnStyle + , DialogStyle + , ExpansionPanelStyle + , RowStyle + , SnackbarStyle + , SortTableStyle + , TabStyle + , TextInputStyle + ) + + +type alias Palette = + { primary : Color --Color.rgb255 0x62 0x00 0xEE + , secondary : Color --Color.rgb255 0x03 0xda 0xc6 + , background : Color --Color.rgb255 0xFF 0xFF 0xFF + , surface : Color --Color.rgb255 0xFF 0xFF 0xFF + , error : Color --Color.rgb255 0xB0 0x00 0x20 + , on : + { primary : Color --Color.rgb255 0xFF 0xFF 0xFF + , secondary : Color --Color.rgb255 0x00 0x00 0x00 + , background : Color --Color.rgb255 0x00 0x00 0x00 + , surface : Color --Color.rgb255 0x00 0x00 0x00 + , error : Color --Color.rgb255 0xFF 0xFF 0xFF + } + } + + +defaultPalette : Palette +defaultPalette = + { primary = Color.rgb255 0x62 0x00 0xEE + , secondary = Color.rgb255 0x03 0xDA 0xC6 + , background = Color.rgb255 0xFF 0xFF 0xFF + , surface = Color.rgb255 0xFF 0xFF 0xFF + , error = Color.rgb255 0xB0 0x00 0x20 + , on = + { primary = Color.rgb255 0xFF 0xFF 0xFF + , secondary = Color.rgb255 0x00 0x00 0x00 + , background = Color.rgb255 0x00 0x00 0x00 + , surface = Color.rgb255 0x00 0x00 0x00 + , error = Color.rgb255 0xFF 0xFF 0xFF + } + } + + +accessibleTextColor : Color -> Color +accessibleTextColor color = + if (0.05 / (Accessibility.luminance color + 0.05)) < 7 then + Color.rgb 255 255 255 + + else + Color.rgb 0 0 0 + + +{-| using noahzgordon/elm-color-extra for colors +-} +withShade : Color -> Float -> Color -> Color +withShade c2 amount c1 = + let + alpha = c1 + |> Color.toRgba |> .alpha + + + toCIELCH = + Convert.colorToLab + >> (\{ l, a, b } -> + { l = l + , c = sqrt (a * a + b * b) + , h = atan2 b a + } + ) + + fromCIELCH = + (\{ l, c, h } -> + { l = l + , a = c * cos h + , b = c * sin h + } + ) + >> Convert.labToColor + + fun a b = + { l = (a.l * (1 - amount) + b.l * amount) / 1 + , c = (a.c * (1 - amount) + b.c * amount) / 1 + , h = (a.h * (1 - amount) + b.h * amount) / 1 + } + in + fun (toCIELCH c1) (toCIELCH c2) + |> fromCIELCH + |> Color.toRgba + |> (\color -> { color | alpha = alpha }) + |> Color.fromRgba + +scaleOpacity : Float -> Color -> Color +scaleOpacity opacity = + Color.toRgba + >> (\color -> { color | alpha = color.alpha * opacity}) + >> Color.fromRgba + +{-| hsl 265 100 47 (0% onColor) +rgb 98 0 238 +-} +primaryColor : Palette -> Color +primaryColor { primary } = + primary + + +{-| hsl 265 75 59 (24% onColor) +rgb 136 61 242 +-} +primaryColorFocused : Palette -> Color +primaryColorFocused {primary, on } = + primary |> withShade on.primary 0.24 + + + +--Color.rgb255 0x87 0x3D 0xF2 + + +{-| hsl 265 92 51 (08% onColor) +-} +primaryColorHover : Palette -> Color +primaryColorHover {primary, on } = + primary |> withShade on.primary 0.08 + + + +--Color.rgb255 0x6E 0x14 0xEF + + +{-| hsl 265 66 64 (32% onColor) +-} +primaryColorPressed : Palette -> Color +primaryColorPressed {primary, on } = + primary |> withShade on.primary 0.32 + + + +--Color.rgb255 0x94 0x52 0xF3 + + +primaryColorDisabled : Palette ->Color +primaryColorDisabled {primary,on}= + Color.rgb255 0x77 0x77 0x77 |> scaleOpacity 0.38 + +disabledFontColor : Color +disabledFontColor = + Color.rgb255 0x77 0x77 0x77--0x85 0x85 0x85 + + +shadow : + Float + -> + { offset : ( Float, Float ) + , size : Float + , blur : Float + , color : Element.Color + } +shadow float = + { color = Element.rgba255 0x00 0x00 0x00 0.2 + , offset = ( 0, float ) + , size = 0 + , blur = float + } + + +primaryButton : Palette -> ButtonStyle msg +primaryButton palette = + { container = + [ Element.height <| Element.px 36 + , Element.width <| Element.minimum 64 <| Element.shrink + , Border.rounded <| 4 + , Border.shadow <| shadow 2 + , Font.size 14 + , Font.medium + , Font.letterSpacing 1.25 + , Element.htmlAttribute <| Attributes.style "text-transform" "uppercase" + , Element.paddingXY 16 8 + , Element.mouseDown + [ Background.color <| Element.fromRgb <| Color.toRgba <| primaryColorPressed palette + , Font.color <| Element.fromRgb <| Color.toRgba <| accessibleTextColor <| primaryColorPressed palette + , Border.shadow <| shadow 12 + ] + , Element.mouseOver + [ Background.color <| Element.fromRgb <| Color.toRgba <| primaryColorHover palette + , Font.color <| Element.fromRgb <| Color.toRgba <| accessibleTextColor <| primaryColorHover palette + , Border.shadow <| shadow 6 + ] + , Element.focused + [ Background.color <| Element.fromRgb <| Color.toRgba <| primaryColorFocused palette + , Font.color <| Element.fromRgb <| Color.toRgba <| accessibleTextColor <| primaryColorFocused palette + , Border.shadow <| shadow 6 + ] + ] + , labelRow = + [ Element.spacing <| 8 + ] + , ifDisabled = + [ Background.color <| Element.fromRgb <| Color.toRgba <| primaryColorDisabled palette + , Font.color <| Element.fromRgb <| Color.toRgba <| disabledFontColor + , Element.htmlAttribute <| Attributes.style "cursor" "not-allowed" + , Element.mouseDown [] + , Element.mouseOver [] + , Element.focused [] + , Border.shadow <| shadow 0 + ] + , ifActive = + [ Background.color <| Element.fromRgb <| Color.toRgba <| primaryColorFocused palette + , Font.color <| Element.fromRgb <| Color.toRgba <| accessibleTextColor <| primaryColorHover palette + ] + , otherwise = + [ Background.color <| Element.fromRgb <| Color.toRgba <| primaryColor palette + , Font.color <| Element.fromRgb <| Color.toRgba <| accessibleTextColor <| primaryColor palette + + ] + } + + + +{------------------------------------------------------------------------------- +- Template +-------------------------------------------------------------------------------} + + +fontSize : Int +fontSize = + 10 + + +box : String -> List (Attribute msg) +box string = + [ Border.width 1 + , Background.color <| Element.rgba 1 1 1 0.5 + , Element.padding 10 + , Element.spacing 10 + , Element.above <| + Element.el [ Font.size <| fontSize ] <| + Element.text string + ] + + +decoration : String -> List (Attribute msg) +decoration string = + [ Element.below <| + Element.el [ Font.size <| fontSize ] <| + Element.text string + , Background.color <| Element.rgb 0.66 0.66 0.66 + ] + + +icon : String -> Element msg +icon string = + Element.none + |> Element.el + [ Element.width <| Element.px 12 + , Element.height <| Element.px 12 + , Border.rounded 6 + , Border.width 1 + , Element.above <| + Element.el [ Font.size <| fontSize ] <| + Element.text string + ] + + +button : String -> ButtonStyle msg +button string = + { container = box <| string ++ ":container" + , labelRow = box <| string ++ ":labelRow" + , ifDisabled = decoration <| string ++ ":ifDisabled" + , ifActive = decoration <| string ++ ":ifActive" + , otherwise = box <| string ++ ":otherwise" + } + + +snackbar : String -> SnackbarStyle msg +snackbar string = + { containerRow = box <| string ++ ":containerRow" + , button = button <| string ++ ":button" + , text = box <| string ++ ":text" + } + + +dialog : String -> DialogStyle msg +dialog string = + { containerColumn = box <| string ++ ":containerColumn" + , title = box <| string ++ ":title" + , buttonRow = box <| string ++ ":buttonRow" + , acceptButton = button <| string ++ ":acceptButton" + , dismissButton = button <| string ++ ":dismissButton" + } + + +expansionPanel : String -> ExpansionPanelStyle msg +expansionPanel string = + { containerColumn = box <| string ++ ":containerColumn" + , panelRow = box <| string ++ ":panelRow" + , labelRow = box <| string ++ ":labelRow" + , content = box <| string ++ ":content" + , expandIcon = icon <| string ++ ":expandIcon" + , collapseIcon = icon <| string ++ ":collapseIcon" + } + + +textInput : String -> TextInputStyle msg +textInput string = + { chipButton = button <| string ++ ":chipButton" + , chipsRow = box <| string ++ ":chipsRow" + , containerRow = box <| string ++ ":containerRow" + , input = box <| string ++ ":input" + } + + +tab : String -> TabStyle msg +tab string = + { button = button <| string ++ ":button" + , optionRow = box <| string ++ ":optionRow" + , containerColumn = box <| string ++ ":containerColumn" + , content = box <| string ++ ":content" + } + + +row : String -> RowStyle msg +row string = + { containerRow = box <| string ++ ":containerRow" + , element = box <| string ++ ":element" + , ifFirst = box <| string ++ ":ifFirst" + , ifLast = box <| string ++ ":ifLast" + , otherwise = box <| string ++ ":otherwise" + } + + +column : String -> ColumnStyle msg +column string = + { containerColumn = box <| string ++ ":containerColumn" + , element = box <| string ++ ":element" + , ifFirst = box <| string ++ ":ifFirst" + , ifLast = box <| string ++ ":ifLast" + , otherwise = box <| string ++ ":otherwise" + } + + +sortTable : String -> SortTableStyle msg +sortTable string = + { containerTable = box <| string ++ ":containerTable" + , headerButton = button <| string ++ ":headerButton" + , ascIcon = icon <| string ++ ":ascIcon" + , descIcon = icon <| string ++ ":descIcon" + , defaultIcon = icon <| string ++ ":defaultIcon" + } + + +style : Palette -> Style msg +style palette = + { sortTable = sortTable <| "sortTable" + , row = row <| "row" + , cardColumn = column <| "cardRow" + , column = column <| "column" + , button = button <| "button" + , primaryButton = primaryButton palette + , tab = tab <| "tab" + , textInput = textInput <| "textInput" + , chipButton = button <| "chipButton" + , expansionPanel = expansionPanel "expansionPanel" + , dialog = dialog "dialog" + , snackbar = snackbar "snackbar" + , layout = Element.layout + , header = box "header" + , menuButton = button "menuButton" + , sheetButton = button "sheetButton" + , menuTabButton = button "menuTabButton" + , sheet = box "sheet" + , menuIcon = icon "menuIcon" + , moreVerticalIcon = icon "moreVerticalIcon" + , spacing = 8 + , title = box "title" + , searchIcon = icon "searchIcon" + , search = box "search" + , searchFill = box "searchFill" + } diff --git a/example/src/Data/Style/Template.elm b/example/src/Data/Style/Template.elm index 1dca97d..9400875 100644 --- a/example/src/Data/Style/Template.elm +++ b/example/src/Data/Style/Template.elm @@ -1,16 +1,28 @@ module Data.Style.Template exposing (style) import Data.Style exposing (Style) -import Element exposing (Attribute,Element) +import Element exposing (Attribute, Element) +import Element.Background as Background import Element.Border as Border import Element.Font as Font -import Element.Background as Background -import Widget.Style exposing (ButtonStyle, DialogStyle, ExpansionPanelStyle, - SnackbarStyle ,TextInputStyle,TabStyle,ColumnStyle,RowStyle) +import Widget.Style + exposing + ( ButtonStyle + , ColumnStyle + , DialogStyle + , ExpansionPanelStyle + , RowStyle + , SnackbarStyle + , TabStyle + , TextInputStyle + ,SortTableStyle + ) fontSize : Int -fontSize = 10 +fontSize = + 10 + box : String -> List (Attribute msg) box string = @@ -18,15 +30,16 @@ box string = , Background.color <| Element.rgba 1 1 1 0.5 , Element.padding 10 , Element.spacing 10 - , Element.above <| - Element.el [Font.size <| fontSize] <| - Element.text string + , Element.above <| + Element.el [ Font.size <| fontSize ] <| + Element.text string ] + decoration : String -> List (Attribute msg) decoration string = - [ Element.below <| - Element.el [Font.size <| fontSize] <| + [ Element.below <| + Element.el [ Font.size <| fontSize ] <| Element.text string , Background.color <| Element.rgb 0.66 0.66 0.66 ] @@ -35,15 +48,16 @@ decoration string = icon : String -> Element msg icon string = Element.none - |> Element.el - [ Element.width <| Element.px 12 - , Element.height <| Element.px 12 - , Border.rounded 6 - , Border.width 1 - , Element.above <| - Element.el [Font.size <| fontSize] <| - Element.text string - ] + |> Element.el + [ Element.width <| Element.px 12 + , Element.height <| Element.px 12 + , Border.rounded 6 + , Border.width 1 + , Element.above <| + Element.el [ Font.size <| fontSize ] <| + Element.text string + ] + button : String -> ButtonStyle msg button string = @@ -51,8 +65,10 @@ button string = , labelRow = box <| string ++ ":labelRow" , ifDisabled = decoration <| string ++ ":ifDisabled" , ifActive = decoration <| string ++ ":ifActive" + , otherwise = decoration <| string ++ ":otherwise" } + snackbar : String -> SnackbarStyle msg snackbar string = { containerRow = box <| string ++ ":containerRow" @@ -60,15 +76,17 @@ snackbar string = , text = box <| string ++ ":text" } + dialog : String -> DialogStyle msg dialog string = { containerColumn = box <| string ++ ":containerColumn" , title = box <| string ++ ":title" , buttonRow = box <| string ++ ":buttonRow" , acceptButton = button <| string ++ ":acceptButton" - , dismissButton = button <| string ++ ":dismissButton" + , dismissButton = button <| string ++ ":dismissButton" } + expansionPanel : String -> ExpansionPanelStyle msg expansionPanel string = { containerColumn = box <| string ++ ":containerColumn" @@ -79,6 +97,7 @@ expansionPanel string = , collapseIcon = icon <| string ++ ":collapseIcon" } + textInput : String -> TextInputStyle msg textInput string = { chipButton = button <| string ++ ":chipButton" @@ -87,6 +106,7 @@ textInput string = , input = box <| string ++ ":input" } + tab : String -> TabStyle msg tab string = { button = button <| string ++ ":button" @@ -95,27 +115,41 @@ tab string = , content = box <| string ++ ":content" } + row : String -> RowStyle msg row string = { containerRow = box <| string ++ ":containerRow" , element = box <| string ++ ":element" , ifFirst = box <| string ++ ":ifFirst" , ifLast = box <| string ++ ":ifLast" - , ifCenter = box <| string ++ ":ifCenter" + , otherwise = box <| string ++ ":otherwise" } + column : String -> ColumnStyle msg column string = { containerColumn = box <| string ++ ":containerColumn" , element = box <| string ++ ":element" , ifFirst = box <| string ++ ":ifFirst" , ifLast = box <| string ++ ":ifLast" - , ifCenter = box <| string ++ ":ifCenter" + , otherwise = box <| string ++ ":otherwise" } -style :Style msg + +sortTable : String -> SortTableStyle msg +sortTable string = + { containerTable = box <| string ++ ":containerTable" + , headerButton = button <| string ++ ":headerButton" + , ascIcon = icon <| string ++ ":ascIcon" + , descIcon = icon <| string ++ ":descIcon" + , defaultIcon = icon <| string ++ ":defaultIcon" + } + + +style : Style msg style = - { row = row <| "row" + { sortTable = sortTable <| "sortTable" + , row = row <| "row" , cardColumn = column <| "cardRow" , column = column <| "column" , button = button <| "button" @@ -139,4 +173,4 @@ style = , searchIcon = icon "searchIcon" , search = box "search" , searchFill = box "searchFill" - } \ No newline at end of file + } diff --git a/example/src/Data/Theme.elm b/example/src/Data/Theme.elm index 65d172c..6e960d4 100644 --- a/example/src/Data/Theme.elm +++ b/example/src/Data/Theme.elm @@ -1,17 +1,25 @@ -module Data.Theme exposing (Theme(..),toStyle) +module Data.Theme exposing (Theme(..), toStyle) import Data.Style exposing (Style) import Data.Style.ElmUiFramework +import Data.Style.Material import Data.Style.Template -type Theme = - ElmUiFramework + +type Theme + = ElmUiFramework | Template + | Material + toStyle : Theme -> Style msg toStyle theme = case theme of ElmUiFramework -> Data.Style.ElmUiFramework.style + Template -> Data.Style.Template.style + + Material -> + Data.Style.Material.style Data.Style.Material.defaultPalette diff --git a/example/src/Example/Button.elm b/example/src/Example/Button.elm index 36211f0..f09a798 100644 --- a/example/src/Example/Button.elm +++ b/example/src/Example/Button.elm @@ -3,19 +3,19 @@ module Example.Button exposing (Model, Msg, init, subscriptions, update, view) import Element exposing (Element) import FeatherIcons import Widget -import Widget.Style exposing (ButtonStyle) +import Widget.Style exposing (ButtonStyle, RowStyle) type alias Style style msg = { style | primaryButton : ButtonStyle msg , button : ButtonStyle msg + , row : RowStyle msg } -type alias Model = - { isButtonEnabled : Bool - } +type Model + = IsButtonEnabled Bool type Msg @@ -24,17 +24,16 @@ type Msg init : ( Model, Cmd Msg ) init = - ( { isButtonEnabled = True - } + ( IsButtonEnabled True , Cmd.none ) update : Msg -> Model -> ( Model, Cmd Msg ) -update msg model = +update msg _ = case msg of ChangedButtonStatus bool -> - ( { model | isButtonEnabled = bool } + ( IsButtonEnabled bool , Cmd.none ) @@ -45,7 +44,7 @@ subscriptions _ = view : (Msg -> msg) -> Style style msg -> Model -> Element msg -view msgMapper style model = +view msgMapper style (IsButtonEnabled isButtonEnabled) = [ Widget.button style.primaryButton { text = "disable me" , icon = @@ -55,7 +54,7 @@ view msgMapper style model = |> Element.html |> Element.el [] , onPress = - if model.isButtonEnabled then + if isButtonEnabled then ChangedButtonStatus False |> msgMapper |> Just @@ -77,7 +76,4 @@ view msgMapper style model = |> Just } ] - |> Element.row - [ Element.spaceEvenly - , Element.width <| Element.fill - ] + |> Widget.row style.row diff --git a/example/src/Example/Dialog.elm b/example/src/Example/Dialog.elm new file mode 100644 index 0000000..1d2a50e --- /dev/null +++ b/example/src/Example/Dialog.elm @@ -0,0 +1,93 @@ +module Example.Dialog exposing (Model, Msg, init, subscriptions, update, view) + +import Element exposing (Element) +import FeatherIcons +import Widget +import Widget.Style exposing (ButtonStyle, DialogStyle) + + +type alias Style style msg = + { style + | dialog : DialogStyle msg + , primaryButton : ButtonStyle msg + } + + +type Model = + IsOpen Bool + + +type Msg + = OpenDialog Bool + + +init : ( Model, Cmd Msg ) +init = + ( IsOpen True + , Cmd.none + ) + + +update : Msg -> Model -> ( Model, Cmd Msg ) +update msg _ = + case msg of + OpenDialog bool -> + ( IsOpen bool + , Cmd.none + ) + + +subscriptions : Model -> Sub Msg +subscriptions _ = + Sub.none + + +view : (Msg -> msg) -> Style style msg -> Model -> Element msg +view msgMapper style (IsOpen isOpen) = + Widget.button style.primaryButton + { text = "show Dialog" + , icon = + FeatherIcons.eye + |> FeatherIcons.withSize 16 + |> FeatherIcons.toHtml [] + |> Element.html + |> Element.el [] + , onPress = + OpenDialog True + |> msgMapper + |> Just + } + |> Element.el + ([ Element.height <| Element.minimum 200 <| Element.fill + , Element.width <| Element.minimum 400 <| Element.fill + ] + ++ (if isOpen then + { body = + "This is a dialog window" + |> Element.text + |> List.singleton + |> Element.paragraph [] + , title = Just "Dialog" + , accept = + Just + { text = "Ok" + , onPress = + Just <| + msgMapper <| + OpenDialog False + } + , dismiss = + Just + { text = "Dismiss" + , onPress = + Just <| + msgMapper <| + OpenDialog False + } + } + |> Widget.dialog style.dialog + + else + [] + ) + ) diff --git a/example/src/Example/ExpansionPanel.elm b/example/src/Example/ExpansionPanel.elm index 69cb3c3..757c16b 100644 --- a/example/src/Example/ExpansionPanel.elm +++ b/example/src/Example/ExpansionPanel.elm @@ -11,8 +11,8 @@ type alias Style style msg = } -type alias Model = - { isExpanded : Bool } +type Model + = IsExpanded Bool type Msg @@ -21,18 +21,16 @@ type Msg init : ( Model, Cmd Msg ) init = - ( { isExpanded = False } + ( IsExpanded False , Cmd.none ) update : Msg -> Model -> ( Model, Cmd Msg ) -update msg model = +update msg _ = case msg of ToggleCollapsable bool -> - ( { model - | isExpanded = bool - } + ( IsExpanded bool , Cmd.none ) @@ -43,9 +41,9 @@ subscriptions _ = view : (Msg -> msg) -> Style style msg -> Model -> Element msg -view msgMapper style model = +view msgMapper style (IsExpanded isExpanded) = { onToggle = ToggleCollapsable >> msgMapper - , isExpanded = model.isExpanded + , isExpanded = isExpanded , icon = Element.none , text = "Title" , content = Element.text <| "Hello World" diff --git a/example/src/Example/List.elm b/example/src/Example/List.elm new file mode 100644 index 0000000..5e86224 --- /dev/null +++ b/example/src/Example/List.elm @@ -0,0 +1,47 @@ +module Example.List exposing (Model, Msg, init, subscriptions, update, view) + +import Element exposing (Element) +import Widget +import Widget.Style exposing (ColumnStyle) + + +type alias Style style msg = + { style + | cardColumn : ColumnStyle msg + } + + +type alias Model = + () + + +type alias Msg = + Never + + +init : ( Model, Cmd Msg ) +init = + ( () + , Cmd.none + ) + + +update : Msg -> Model -> ( Model, Cmd Msg ) +update _ () = + ( () + , Cmd.none + ) + + +subscriptions : Model -> Sub Msg +subscriptions () = + Sub.none + + +view : (Msg -> msg) -> Style style msg -> Model -> Element msg +view _ style () = + [ Element.text <| "A" + , Element.text <| "B" + , Element.text <| "C" + ] + |> Widget.column style.cardColumn diff --git a/example/src/Example/Modal.elm b/example/src/Example/Modal.elm new file mode 100644 index 0000000..60166a3 --- /dev/null +++ b/example/src/Example/Modal.elm @@ -0,0 +1,88 @@ +module Example.Modal exposing (Model, Msg, init, subscriptions, update, view) + +import Element exposing (Element) +import FeatherIcons +import Widget +import Widget.Style exposing (ButtonStyle, ColumnStyle) + + +type alias Style style msg = + { style + | cardColumn : ColumnStyle msg + , primaryButton : ButtonStyle msg + } + + +type Model + = IsEnabled Bool + + +type Msg + = ToggleModal Bool + + +init : ( Model, Cmd Msg ) +init = + ( IsEnabled True + , Cmd.none + ) + + +update : Msg -> Model -> ( Model, Cmd Msg ) +update msg _ = + case msg of + ToggleModal bool -> + ( IsEnabled bool + , Cmd.none + ) + + +subscriptions : Model -> Sub Msg +subscriptions _ = + Sub.none + + +view : (Msg -> msg) -> Style style msg -> Model -> Element msg +view msgMapper style (IsEnabled isEnabled) = + Widget.button style.primaryButton + { text = "show Modal" + , icon = + FeatherIcons.eye + |> FeatherIcons.withSize 16 + |> FeatherIcons.toHtml [] + |> Element.html + |> Element.el [] + , onPress = + ToggleModal True + |> msgMapper + |> Just + } + |> Element.el + ([ Element.height <| Element.minimum 200 <| Element.fill + , Element.width <| Element.minimum 400 <| Element.fill + ] + ++ (if isEnabled then + Widget.modal + { onDismiss = + ToggleModal False + |> msgMapper + |> Just + , content = + "Click on the area around this box to close it." + |> Element.text + |> List.singleton + |> Element.paragraph [] + |> List.singleton + |> Widget.column style.cardColumn + |> Element.el + [ Element.height <| Element.px 100 + , Element.width <| Element.px 250 + , Element.centerX + , Element.centerY + ] + } + + else + [] + ) + ) diff --git a/example/src/Example/MultiSelect.elm b/example/src/Example/MultiSelect.elm index 977d4ec..3673125 100644 --- a/example/src/Example/MultiSelect.elm +++ b/example/src/Example/MultiSelect.elm @@ -13,9 +13,8 @@ type alias Style style msg = } -type alias Model = - { selected : Set Int - } +type Model + = Selected (Set Int) type Msg @@ -24,25 +23,23 @@ type Msg init : ( Model, Cmd Msg ) init = - ( { selected = Set.empty } + ( Selected <| Set.empty , Cmd.none ) update : Msg -> Model -> ( Model, Cmd Msg ) -update msg model = +update msg (Selected selected) = case msg of ChangedSelected int -> - ( { model - | selected = - model.selected - |> (if model.selected |> Set.member int then - Set.remove int + ( selected + |> (if selected |> Set.member int then + Set.remove int - else - Set.insert int - ) - } + else + Set.insert int + ) + |> Selected , Cmd.none ) @@ -53,8 +50,8 @@ subscriptions _ = view : (Msg -> msg) -> Style style msg -> Model -> Element msg -view msgMapper style model = - { selected = model.selected +view msgMapper style (Selected selected) = + { selected = selected , options = [ 1, 2, 42 ] |> List.map diff --git a/example/src/Example/Select.elm b/example/src/Example/Select.elm index fbebe32..f663c7f 100644 --- a/example/src/Example/Select.elm +++ b/example/src/Example/Select.elm @@ -1,7 +1,6 @@ module Example.Select exposing (Model, Msg, init, subscriptions, update, view) -import Element exposing (Attribute, Element) -import FeatherIcons +import Element exposing (Element) import Widget import Widget.Style exposing (ButtonStyle, RowStyle) @@ -13,8 +12,8 @@ type alias Style style msg = } -type alias Model = - { selected : Maybe Int } +type Model + = Selected (Maybe Int) type Msg @@ -23,18 +22,16 @@ type Msg init : ( Model, Cmd Msg ) init = - ( { selected = Nothing } + ( Selected Nothing , Cmd.none ) update : Msg -> Model -> ( Model, Cmd Msg ) -update msg model = +update msg _ = case msg of ChangedSelected int -> - ( { model - | selected = Just int - } + ( Selected <| Just int , Cmd.none ) @@ -45,8 +42,8 @@ subscriptions _ = view : (Msg -> msg) -> Style style msg -> Model -> Element msg -view msgMapper style model = - { selected = model.selected +view msgMapper style (Selected selected) = + { selected = selected , options = [ 1, 2, 42 ] |> List.map diff --git a/example/src/Example/SortTable.elm b/example/src/Example/SortTable.elm new file mode 100644 index 0000000..585c0e7 --- /dev/null +++ b/example/src/Example/SortTable.elm @@ -0,0 +1,89 @@ +module Example.SortTable exposing (Model, Msg, init, subscriptions, update, view) + +import Element exposing (Element) +import Widget +import Widget.Style exposing (SortTableStyle) + + +type alias Style style msg = + { style + | sortTable : SortTableStyle msg + } + + +type alias Model = + { title : String + , asc : Bool + } + + +type Msg + = ChangedSorting String + + +init : ( Model, Cmd Msg ) +init = + ( { title = "Name", asc = True } + , Cmd.none + ) + + +update : Msg -> Model -> ( Model, Cmd Msg ) +update msg model = + case msg of + ChangedSorting string -> + ( { title = string + , asc = + if model.title == string then + not model.asc + + else + True + } + , Cmd.none + ) + + +subscriptions : Model -> Sub Msg +subscriptions _ = + Sub.none + + +view : (Msg -> msg) -> Style style msg -> Model -> Element msg +view msgMapper style model = + Widget.sortTable style.sortTable + { content = + [ { id = 1, name = "Antonio", rating = 2.456, hash = Nothing } + , { id = 2, name = "Ana", rating = 1.34, hash = Just "45jf" } + , { id = 3, name = "Alfred", rating = 4.22, hash = Just "6fs1" } + , { id = 4, name = "Thomas", rating = 3, hash = Just "k52f" } + ] + , columns = + [ Widget.intColumn + { title = "Id" + , value = .id + , toString = \int -> "#" ++ String.fromInt int + , width = Element.fill + } + , Widget.stringColumn + { title = "Name" + , value = .name + , toString = identity + , width = Element.fill + } + , Widget.floatColumn + { title = "Rating" + , value = .rating + , toString = String.fromFloat + , width = Element.fill + } + , Widget.unsortableColumn + { title = "Hash" + , toString = .hash >> Maybe.withDefault "None" + , width = Element.fill + } + ] + , asc = model.asc + , sortBy = model.title + , onChange = ChangedSorting >> msgMapper + } diff --git a/example/src/Example/Tab.elm b/example/src/Example/Tab.elm index 9da1e79..70c53af 100644 --- a/example/src/Example/Tab.elm +++ b/example/src/Example/Tab.elm @@ -11,9 +11,8 @@ type alias Style style msg = } -type alias Model = - { selected : Maybe Int - } +type Model + = Selected (Maybe Int) type Msg @@ -22,17 +21,16 @@ type Msg init : ( Model, Cmd Msg ) init = - ( { selected = Nothing - } + ( Selected Nothing , Cmd.none ) update : Msg -> Model -> ( Model, Cmd Msg ) -update msg model = +update msg _ = case msg of ChangedTab int -> - ( { model | selected = Just int } + ( Selected <| Just int , Cmd.none ) @@ -43,10 +41,10 @@ subscriptions _ = view : (Msg -> msg) -> Style style msg -> Model -> Element msg -view msgMapper style model = +view msgMapper style (Selected selected) = Widget.tab style.tab { tabs = - { selected = model.selected + { selected = selected , options = [ 1, 2, 3 ] |> List.map @@ -58,8 +56,8 @@ view msgMapper style model = , onSelect = ChangedTab >> msgMapper >> Just } , content = - \selected -> - (case selected of + \s -> + (case s of Just 0 -> "This is Tab 1" diff --git a/example/src/Example/TextInput.elm b/example/src/Example/TextInput.elm new file mode 100644 index 0000000..ee719c9 --- /dev/null +++ b/example/src/Example/TextInput.elm @@ -0,0 +1,104 @@ +module Example.TextInput exposing (Model, Msg, init, subscriptions, update, view) + +import Element exposing (Element) +import Set exposing (Set) +import Widget +import Widget.Style exposing (ColumnStyle, TextInputStyle) + + +type alias Style style msg = + { style + | textInput : TextInputStyle msg + , column : ColumnStyle msg + } + + +type alias Model = + { chipTextInput : Set String + , textInput : String + } + + +type Msg + = ToggleTextInputChip String + | SetTextInput String + + +init : ( Model, Cmd Msg ) +init = + ( { chipTextInput = Set.empty + , textInput = "" + } + , Cmd.none + ) + + +update : Msg -> Model -> ( Model, Cmd Msg ) +update msg model = + case msg of + ToggleTextInputChip string -> + ( { model + | chipTextInput = + model.chipTextInput + |> (if model.chipTextInput |> Set.member string then + Set.remove string + + else + Set.insert string + ) + } + , Cmd.none + ) + + SetTextInput string -> + ( { model | textInput = string }, Cmd.none ) + + +subscriptions : Model -> Sub Msg +subscriptions _ = + Sub.none + + +view : (Msg -> msg) -> Style style msg -> Model -> Element msg +view msgMapper style model = + [ { chips = + model.chipTextInput + |> Set.toList + |> List.map + (\string -> + { icon = Element.none + , text = string + , onPress = + string + |> ToggleTextInputChip + |> msgMapper + |> Just + } + ) + , text = model.textInput + , placeholder = Nothing + , label = "Chips" + , onChange = SetTextInput >> msgMapper + } + |> Widget.textInput style.textInput + , model.chipTextInput + |> Set.diff + ([ "A", "B", "C" ] + |> Set.fromList + ) + |> Set.toList + |> List.map + (\string -> + Widget.button style.textInput.chipButton + { onPress = + string + |> ToggleTextInputChip + |> msgMapper + |> Just + , text = string + , icon = Element.none + } + ) + |> Element.wrappedRow [ Element.spacing 10 ] + ] + |> Widget.column style.column diff --git a/example/src/Icons.elm b/example/src/Icons.elm index be94eae..de4dd0d 100644 --- a/example/src/Icons.elm +++ b/example/src/Icons.elm @@ -3,148 +3,205 @@ module Icons exposing , chevronDown , chevronLeft , chevronRight + , chevronUp , circle , github , menu , moreVertical + , penTool , repeat , search , slash , square , triangle - , chevronUp - , penTool ) import Html exposing (Html) import Svg exposing (Svg, svg) -import Svg.Attributes exposing (..) +import Svg.Attributes as Attributes svgFeatherIcon : String -> List (Svg msg) -> Html msg svgFeatherIcon className = svg - [ class <| "feather feather-" ++ className - , fill "none" - , height "16" - , stroke "currentColor" - , strokeLinecap "round" - , strokeLinejoin "round" - , strokeWidth "2" - , viewBox "0 0 24 24" - , width "16" + [ Attributes.class <| "feather feather-" ++ className + , Attributes.fill "none" + , Attributes.height "16" + , Attributes.stroke "currentColor" + , Attributes.strokeLinecap "round" + , Attributes.strokeLinejoin "round" + , Attributes.strokeWidth "2" + , Attributes.viewBox "0 0 24 24" + , Attributes.width "16" ] chevronDown : Html msg chevronDown = svgFeatherIcon "chevron-down" - [ Svg.polyline [ points "6 9 12 15 18 9" ] [] + [ Svg.polyline [ Attributes.points "6 9 12 15 18 9" ] [] ] chevronRight : Html msg chevronRight = svgFeatherIcon "chevron-right" - [ Svg.polyline [ points "9 18 15 12 9 6" ] [] + [ Svg.polyline [ Attributes.points "9 18 15 12 9 6" ] [] ] chevronLeft : Html msg chevronLeft = svgFeatherIcon "chevron-left" - [ Svg.polyline [ points "15 18 9 12 15 6" ] [] + [ Svg.polyline [ Attributes.points "15 18 9 12 15 6" ] [] ] + chevronUp : Html msg chevronUp = svgFeatherIcon "chevron-up" - [ Svg.polyline [ points "18 15 12 9 6 15" ] [] + [ Svg.polyline [ Attributes.points "18 15 12 9 6 15" ] [] ] + repeat : Html msg repeat = svgFeatherIcon "repeat" - [ Svg.polyline [ points "17 1 21 5 17 9" ] [] - , Svg.path [ d "M3 11V9a4 4 0 0 1 4-4h14" ] [] - , Svg.polyline [ points "7 23 3 19 7 15" ] [] - , Svg.path [ d "M21 13v2a4 4 0 0 1-4 4H3" ] [] + [ Svg.polyline [ Attributes.points "17 1 21 5 17 9" ] [] + , Svg.path [ Attributes.d "M3 11V9a4 4 0 0 1 4-4h14" ] [] + , Svg.polyline [ Attributes.points "7 23 3 19 7 15" ] [] + , Svg.path [ Attributes.d "M21 13v2a4 4 0 0 1-4 4H3" ] [] ] + penTool : Html msg penTool = svgFeatherIcon "pen-tool" - [ Svg.path [ d "M12 19l7-7 3 3-7 7-3-3z" ] [] - , Svg.path [ d "M18 13l-1.5-7.5L2 2l3.5 14.5L13 18l5-5z" ] [] - , Svg.path [ d "M2 2l7.586 7.586" ] [] - , Svg.circle [ cx "11", cy "11", r "2" ] [] + [ Svg.path [ Attributes.d "M12 19l7-7 3 3-7 7-3-3z" ] [] + , Svg.path [ Attributes.d "M18 13l-1.5-7.5L2 2l3.5 14.5L13 18l5-5z" ] [] + , Svg.path [ Attributes.d "M2 2l7.586 7.586" ] [] + , Svg.circle + [ Attributes.cx "11" + , Attributes.cy "11" + , Attributes.r "2" + ] + [] ] + book : Html msg book = svgFeatherIcon "book" - [ Svg.path [ d "M4 19.5A2.5 2.5 0 0 1 6.5 17H20" ] [] - , Svg.path [ d "M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z" ] [] + [ Svg.path [ Attributes.d "M4 19.5A2.5 2.5 0 0 1 6.5 17H20" ] [] + , Svg.path [ Attributes.d "M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z" ] [] ] github : Html msg github = svgFeatherIcon "github" - [ Svg.path [ d "M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22" ] [] + [ Svg.path [ Attributes.d "M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22" ] [] ] menu : Html msg menu = svgFeatherIcon "menu" - [ Svg.line [ x1 "3", y1 "12", x2 "21", y2 "12" ] [] - , Svg.line [ x1 "3", y1 "6", x2 "21", y2 "6" ] [] - , Svg.line [ x1 "3", y1 "18", x2 "21", y2 "18" ] [] + [ Svg.line + [ Attributes.x1 "3" + , Attributes.y1 "12" + , Attributes.x2 "21" + , Attributes.y2 "12" + ] + [] + , Svg.line + [ Attributes.x1 "3" + , Attributes.y1 "6" + , Attributes.x2 "21" + , Attributes.y2 "6" + ] + [] + , Svg.line + [ Attributes.x1 "3" + , Attributes.y1 "18" + , Attributes.x2 "21" + , Attributes.y2 "18" + ] + [] ] moreVertical : Html msg moreVertical = svgFeatherIcon "more-vertical" - [ Svg.circle [ cx "12", cy "12", r "1" ] [] - , Svg.circle [ cx "12", cy "5", r "1" ] [] - , Svg.circle [ cx "12", cy "19", r "1" ] [] + [ Svg.circle [ Attributes.cx "12", Attributes.cy "12", Attributes.r "1" ] [] + , Svg.circle [ Attributes.cx "12", Attributes.cy "5", Attributes.r "1" ] [] + , Svg.circle [ Attributes.cx "12", Attributes.cy "19", Attributes.r "1" ] [] ] circle : Html msg circle = svgFeatherIcon "circle" - [ Svg.circle [ cx "12", cy "12", r "10" ] [] + [ Svg.circle [ Attributes.cx "12", Attributes.cy "12", Attributes.r "10" ] [] ] slash : Html msg slash = svgFeatherIcon "slash" - [ Svg.circle [ cx "12", cy "12", r "10" ] [] - , Svg.line [ x1 "4.93", y1 "4.93", x2 "19.07", y2 "19.07" ] [] + [ Svg.circle + [ Attributes.cx "12" + , Attributes.cy "12" + , Attributes.r "10" + ] + [] + , Svg.line + [ Attributes.x1 "4.93" + , Attributes.y1 "4.93" + , Attributes.x2 "19.07" + , Attributes.y2 "19.07" + ] + [] ] triangle : Html msg triangle = svgFeatherIcon "triangle" - [ Svg.path [ d "M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" ] [] + [ Svg.path [ Attributes.d "M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" ] [] ] square : Html msg square = svgFeatherIcon "square" - [ Svg.rect [ Svg.Attributes.x "3", y "3", width "18", height "18", rx "2", ry "2" ] [] + [ Svg.rect + [ Attributes.x "3" + , Attributes.y "3" + , Attributes.width "18" + , Attributes.height "18" + , Attributes.rx "2" + , Attributes.ry "2" + ] + [] ] search : Html msg search = svgFeatherIcon "search" - [ Svg.circle [ cx "11", cy "11", r "8" ] [] - , Svg.line [ x1 "21", y1 "21", x2 "16.65", y2 "16.65" ] [] + [ Svg.circle + [ Attributes.cx "11" + , Attributes.cy "11" + , Attributes.r "8" + ] + [] + , Svg.line + [ Attributes.x1 "21" + , Attributes.y1 "21" + , Attributes.x2 "16.65" + , Attributes.y2 "16.65" + ] + [] ] diff --git a/example/src/Main.elm b/example/src/Main.elm index 10dc053..8c6895f 100644 --- a/example/src/Main.elm +++ b/example/src/Main.elm @@ -6,34 +6,21 @@ import Browser.Dom as Dom exposing (Viewport) import Browser.Events as Events import Browser.Navigation as Navigation import Data.Section as Section exposing (Section(..)) -import Data.Style as Style exposing (Style) +import Data.Style exposing (Style) import Data.Theme as Theme exposing (Theme(..)) -import Element exposing (Attribute, DeviceClass(..), Element) -import Element.Border as Border -import Element.Font as Font -import Element.Input as Input +import Element exposing (DeviceClass(..)) import Framework -import Framework.Button as Button -import Framework.Card as Card -import Framework.Color as Color import Framework.Grid as Grid -import Framework.Group as Group import Framework.Heading as Heading -import Framework.Input as Input -import Framework.Tag as Tag import Html exposing (Html) -import Html.Attributes as Attributes import Icons -import Layout exposing (Layout, Part) import Reusable -import Set exposing (Set) import Stateless import Task import Time import Widget +import Widget.Layout as Layout exposing (Layout, Part) import Widget.ScrollingNav as ScrollingNav -import Widget.Snackbar as Snackbar -import Widget.Style exposing (ButtonStyle) type alias LoadedModel = @@ -41,7 +28,10 @@ type alias LoadedModel = , scrollingNav : ScrollingNav.Model Section , layout : Layout LoadedMsg , displayDialog : Bool - , window : { height : Int, width : Int } + , window : + { height : Int + , width : Int + } , search : { raw : String , current : String @@ -110,7 +100,7 @@ initialModel { viewport } = , current = "" , remaining = 0 } - , theme = ElmUiFramework + , theme = Material } , [ cmd , statelessCmd |> Cmd.map StatelessSpecific @@ -171,17 +161,17 @@ view model = (\section -> (case section of ReusableViews -> - Reusable.view m.theme - { addSnackbar = AddSnackbar + Reusable.view + { theme = m.theme + , addSnackbar = AddSnackbar } StatelessViews -> - Stateless.view m.theme - { msgMapper = StatelessSpecific - , showDialog = ToggleDialog True - , changedSheet = ChangedSidebar + Stateless.view + { theme = m.theme + , msgMapper = StatelessSpecific + , model = m.stateless } - m.stateless ) |> (\{ title, description, items } -> [ Element.el Heading.h2 <| Element.text <| title @@ -213,12 +203,17 @@ view model = ] |> Element.column Grid.simple , more - |> Element.el [ Element.height <| Element.fill ] + |> Element.el + [ Element.width <| Element.fill + ] ] |> Widget.column style.cardColumn ) |> Element.wrappedRow - (Grid.simple ++ [ Element.height <| Element.shrink ]) + (Grid.simple + ++ [ Element.height <| Element.shrink + ] + ) ] |> Element.column (Grid.section ++ [ Element.centerX ]) ) @@ -266,6 +261,15 @@ view model = , text = "Template Theme" , icon = Icons.penTool |> Element.html |> Element.el [] } + , { onPress = + if m.theme /= Material then + Just <| SetTheme <| Material + + else + Nothing + , text = "Material Theme" + , icon = Icons.penTool |> Element.html |> Element.el [] + } , { onPress = Nothing , text = "Placeholder" , icon = Icons.circle |> Element.html |> Element.el [] @@ -428,7 +432,7 @@ update msg model = subscriptions : Model -> Sub Msg -subscriptions model = +subscriptions _ = Sub.batch [ Time.every 50 (always (TimePassed 50)) , Events.onResize (\h w -> Resized { height = h, width = w }) diff --git a/example/src/Reusable.elm b/example/src/Reusable.elm index cf8e3fa..9587b86 100644 --- a/example/src/Reusable.elm +++ b/example/src/Reusable.elm @@ -1,40 +1,13 @@ -module Reusable exposing ( view) +module Reusable exposing (view) -import Browser -import Element exposing (Color, Element) -import Element.Background as Background -import Element.Font as Font -import Element.Input as Input -import Framework -import Framework.Button as Button -import Framework.Card as Card -import Framework.Color as Color -import Framework.Grid as Grid -import Framework.Group as Group -import Framework.Heading as Heading -import Framework.Input as Input -import Framework.Tag as Tag -import Heroicons.Solid as Heroicons -import Html exposing (Html) -import Html.Attributes as Attributes -import Set exposing (Set) -import Time -import Widget -import Widget.ScrollingNav as ScrollingNav -import Widget.Snackbar as Snackbar import Data.Style exposing (Style) import Data.Theme as Theme exposing (Theme) +import Element exposing (Element) +import Framework.Grid as Grid +import Widget -type alias Item = - { name : String - , amount : Int - , price : Float - } - - - -snackbar : Style msg -> (( String, Bool ) -> msg) -> ( String, Element msg,Element msg ) +snackbar : Style msg -> (( String, Bool ) -> msg) -> ( String, Element msg, Element msg ) snackbar style addSnackbar = ( "Snackbar" , [ Widget.button style.button @@ -45,7 +18,7 @@ snackbar style addSnackbar = , False ) , text = "Add Notification" - , icon =Element.none + , icon = Element.none } , Widget.button style.button { onPress = @@ -63,11 +36,8 @@ snackbar style addSnackbar = ) - - - scrollingNavCard : Style msg -> ( String, Element msg, Element msg ) -scrollingNavCard style = +scrollingNavCard _ = ( "Scrolling Nav" , Element.text "Resize the screen and open the side-menu. Then start scrolling to see the scrolling navigation in action." |> List.singleton @@ -76,23 +46,35 @@ scrollingNavCard style = ) +layout : Style msg -> ( String, Element msg, Element msg ) +layout _ = + ( "Layout" + , Element.text "The layout combines the menu bar, both side bar, the dialog window and the snackbar. Try using all of them and also try resizing the window to see how they interact with each other." + |> List.singleton + |> Element.paragraph [] + , Element.none + ) + + view : - Theme -> - { addSnackbar : ( String, Bool ) -> msg + { theme : Theme + , addSnackbar : ( String, Bool ) -> msg } -> { title : String , description : String - , items : List ( String, Element msg,Element msg ) + , items : List ( String, Element msg, Element msg ) } -view theme { addSnackbar } = +view { theme, addSnackbar } = let - style = Theme.toStyle theme + style = + Theme.toStyle theme in { title = "Reusable Views" , description = "Reusable views have an internal state but no update function. You will need to do some wiring, but nothing complicated." , items = [ snackbar style addSnackbar , scrollingNavCard style + , layout style ] } diff --git a/example/src/Stateless.elm b/example/src/Stateless.elm index c70301c..65d4b30 100644 --- a/example/src/Stateless.elm +++ b/example/src/Stateless.elm @@ -1,37 +1,19 @@ module Stateless exposing (Model, Msg, init, update, view) -import Array import Data.Example as Example -import Data.Style exposing (Style) import Data.Theme as Theme exposing (Theme) import Element exposing (Element) -import Element.Background as Background -import Framework.Card as Card -import Framework.Color as Color -import Framework.Grid as Grid -import Heroicons.Solid as Heroicons -import Html.Attributes as Attributes -import Icons -import Layout exposing (Part(..)) -import Set exposing (Set) -import Widget +import Widget.Layout exposing (Part(..)) type alias Model = - { chipTextInput : Set String - , carousel : Int - , textInput : String - , table : { title : String, asc : Bool } + { carousel : Int , example : Example.Model } type Msg - = ToggleTextInputChip String - | SetCarousel Int - | SetTextInput String - | ChangedSorting String - | ExampleSpecific Example.Msg + = ExampleSpecific Example.Msg | Idle @@ -41,10 +23,7 @@ init = ( example, cmd ) = Example.init in - ( { chipTextInput = Set.empty - , carousel = 0 - , textInput = "" - , table = { title = "Name", asc = True } + ( { carousel = 0 , example = example } , cmd |> Cmd.map ExampleSpecific @@ -63,310 +42,24 @@ update msg model = , exampleCmd |> Cmd.map ExampleSpecific ) - ToggleTextInputChip string -> - ( { model - | chipTextInput = - model.chipTextInput - |> (if model.chipTextInput |> Set.member string then - Set.remove string - - else - Set.insert string - ) - } - , Cmd.none - ) - - SetCarousel int -> - ( if (int < 0) || (int > 3) then - model - - else - { model - | carousel = int - } - , Cmd.none - ) - - SetTextInput string -> - ( { model | textInput = string }, Cmd.none ) - - ChangedSorting string -> - ( { model - | table = - { title = string - , asc = - if model.table.title == string then - not model.table.asc - - else - True - } - } - , Cmd.none - ) - Idle -> ( model, Cmd.none ) -modal : Style msg -> (Maybe Part -> msg) -> Model -> ( String, Element msg, Element msg ) -modal style changedSheet _ = - ( "Modal" - , [ Widget.button style.button - { onPress = Just <| changedSheet <| Just LeftSheet - , text = "show left sheet" - , icon = Element.none - } - , Widget.button style.button - { onPress = Just <| changedSheet <| Just RightSheet - , text = "show right sheet" - , icon = Element.none - } - ] - |> Element.column Grid.simple - , Element.none - ) - - -dialog : Style msg -> msg -> Model -> ( String, Element msg, Element msg ) -dialog style showDialog _ = - ( "Dialog" - , Widget.button style.button - { onPress = Just showDialog - , text = "Show dialog" - , icon = Element.none - } - , Element.none - ) - - -carousel : Style Msg -> Model -> ( String, Element Msg, Element Msg ) -carousel style model = - ( "Carousel" - , Widget.carousel - { content = ( Color.cyan, [ Color.yellow, Color.green, Color.red ] |> Array.fromList ) - , current = model.carousel - , label = - \c -> - [ Element.el [ Element.centerY ] <| - Widget.iconButton style.button - { onPress = - model.carousel - - 1 - |> (\i -> - if i < 0 then - Nothing - - else - SetCarousel i - |> Just - ) - , icon = - Icons.chevronLeft - |> Element.html - |> Element.el [] - , text = "Previous" - } - , Element.el - (Card.simple - ++ [ Background.color <| c - , Element.height <| Element.px <| 100 - , Element.width <| Element.px <| 100 - ] - ) - <| - Element.none - , Element.el [ Element.centerY ] <| - Widget.iconButton style.button - { onPress = - model.carousel - + 1 - |> (\i -> - if i >= 4 then - Nothing - - else - SetCarousel i - |> Just - ) - , icon = - Icons.chevronRight - |> Element.html - |> Element.el [] - , text = "Next" - } - ] - |> Element.row (Grid.simple ++ [ Element.centerX, Element.width <| Element.shrink ]) - } - , Element.none - ) - - -textInput : Style Msg -> Model -> ( String, Element Msg, Element Msg ) -textInput style model = - ( "Chip Text Input" - , [ { chips = - model.chipTextInput - |> Set.toList - |> List.map - (\string -> - { icon = Element.none - , text = string - , onPress = - string - |> ToggleTextInputChip - |> Just - } - ) - , text = model.textInput - , placeholder = Nothing - , label = "Chips" - , onChange = SetTextInput - } - |> Widget.textInput style.textInput - , model.chipTextInput - |> Set.diff - ([ "A", "B", "C" ] - |> Set.fromList - ) - |> Set.toList - |> List.map - (\string -> - Widget.button style.textInput.chipButton - { onPress = - string - |> ToggleTextInputChip - |> Just - , text = string - , icon = Element.none - } - ) - |> Element.wrappedRow [ Element.spacing 10 ] - ] - |> Element.column Grid.simple - , [ Element.row Grid.spacedEvenly - [ "Nothing Selected" - |> Element.text - |> Element.el [ Element.width <| Element.fill ] - , { chips = [] - , text = "" - , placeholder = Nothing - , label = "Label" - , onChange = always Idle - } - |> Widget.textInput style.textInput - ] - , Element.row Grid.spacedEvenly - [ "Some chips" - |> Element.text - |> Element.el [ Element.width <| Element.fill ] - , { chips = - [ { icon = Icons.triangle |> Element.html |> Element.el [] - , text = "A" - , onPress = Just Idle - } - , { icon = Icons.circle |> Element.html |> Element.el [] - , text = "B" - , onPress = Just Idle - } - ] - , text = "" - , placeholder = Nothing - , label = "Label" - , onChange = always Idle - } - |> Widget.textInput style.textInput - ] - ] - |> Element.column Grid.simple - ) - - -list : Style Msg -> Model -> ( String, Element Msg, Element Msg ) -list style _ = - ( "List" - , [ Element.text <| "A" - , Element.text <| "B" - , Element.text <| "C" - ] - |> Widget.column style.cardColumn - , Element.none - ) - - -sortTable : Style Msg -> Model -> ( String, Element Msg, Element Msg ) -sortTable _ model = - ( "Sort Table" - , Widget.sortTable - { containerTable = Grid.simple - , headerButton = - { container = [] - , labelRow = [] - , ifDisabled = [] - , ifActive = [] - } - , ascIcon = Heroicons.cheveronUp [ Attributes.width 16 ] |> Element.html - , descIcon = Heroicons.cheveronDown [ Attributes.width 16 ] |> Element.html - , defaultIcon = Element.none - } - { content = - [ { id = 1, name = "Antonio", rating = 2.456 } - , { id = 2, name = "Ana", rating = 1.34 } - , { id = 3, name = "Alfred", rating = 4.22 } - , { id = 4, name = "Thomas", rating = 3 } - ] - , columns = - [ Widget.intColumn - { title = "Id" - , value = .id - , toString = \int -> "#" ++ String.fromInt int - , width = Element.fill - } - , Widget.stringColumn - { title = "Name" - , value = .name - , toString = identity - , width = Element.fill - } - , Widget.floatColumn - { title = "rating" - , value = .rating - , toString = String.fromFloat - , width = Element.fill - } - ] - , asc = model.table.asc - , sortBy = model.table.title - , onChange = ChangedSorting - } - , Element.none - ) - - view : - Theme - -> - { msgMapper : Msg -> msg - , showDialog : msg - , changedSheet : Maybe Part -> msg - } - -> Model + { theme : Theme + , msgMapper : Msg -> msg + , model : Model + } -> { title : String , description : String , items : List ( String, Element msg, Element msg ) } -view theme { msgMapper, showDialog, changedSheet } model = +view { theme, msgMapper, model } = let style = Theme.toStyle theme - - map ( a, b, c ) = - ( a - , b |> Element.map msgMapper - , c |> Element.map msgMapper - ) in { title = "Stateless Views" , description = "Stateless views are simple functions that view some content. No wiring required." @@ -377,11 +70,4 @@ view theme { msgMapper, showDialog, changedSheet } model = , style = style , model = model.example } - ++ [ modal style changedSheet model - , carousel style model |> map - , dialog style showDialog model - , textInput style model |> map - , list style model |> map - , sortTable style model |> map - ] } diff --git a/example/src/View/Test.elm b/example/src/View/Test.elm index 2264e7f..d239459 100644 --- a/example/src/View/Test.elm +++ b/example/src/View/Test.elm @@ -1,339 +1,280 @@ -module View.Test exposing (expansionPanel, iconButton, multiSelect, select, tab) +module View.Test exposing (button, dialog, expansionPanel, list, modal, multiSelect, select, sortTable, tab, textInput) -import Array import Data.Style exposing (Style) -import Data.Theme as Theme exposing (Theme) import Element exposing (Element) -import Element.Background as Background -import Framework.Card as Card -import Framework.Color as Color -import Framework.Grid as Grid -import Heroicons.Solid as Heroicons -import Html.Attributes as Attributes import Icons -import Layout exposing (Part(..)) -import Set exposing (Set) +import Set import Widget +import Widget.Layout exposing (Part(..)) -iconButton : msg -> Style msg -> List (Element msg) -iconButton idle style = - [ Element.row Grid.spacedEvenly - [ "Button" - |> Element.text - , Widget.button style.button +button : msg -> Style msg -> List ( String, Element msg ) +button idle style = + [ ( "Button" + , Widget.button style.button { text = "Button" , icon = Icons.triangle |> Element.html |> Element.el [] , onPress = Just idle } - ] - , Element.row Grid.spacedEvenly - [ "Text button" - |> Element.text - , Widget.textButton style.button + ) + , ( "Text button" + , Widget.textButton style.button { text = "Button" , onPress = Just idle } - ] - , Element.row Grid.spacedEvenly - [ "Icon button" - |> Element.text - , Widget.iconButton style.button + ) + , ( "Icon button" + , Widget.iconButton style.button { text = "Button" , icon = Icons.triangle |> Element.html |> Element.el [] , onPress = Just idle } - ] - , Element.row Grid.spacedEvenly - [ "Disabled button" - |> Element.text - , Widget.button style.button + ) + , ( "Disabled button" + , Widget.button style.button { text = "Button" , icon = Icons.triangle |> Element.html |> Element.el [] , onPress = Nothing } - ] - , Element.row Grid.spacedEvenly - [ "Inactive Select button" - |> Element.text - , Widget.selectButton style.button + ) + , ( "Inactive Select button" + , Widget.selectButton style.button ( False , { text = "Button" , icon = Icons.triangle |> Element.html |> Element.el [] , onPress = Just idle } ) - ] - , Element.row Grid.spacedEvenly - [ "Active Select button" - |> Element.text - , Widget.selectButton style.button + ) + , ( "Active Select button" + , Widget.selectButton style.button ( True , { text = "Button" , icon = Icons.triangle |> Element.html |> Element.el [] , onPress = Just idle } ) - ] + ) ] -select : msg -> Style msg -> List (Element msg) +select : msg -> Style msg -> List ( String, Element msg ) select idle style = - [ Element.row Grid.spacedEvenly - [ "First selected" - |> Element.text - |> Element.el [ Element.width <| Element.fill ] - , { selected = Just 0 - , options = - [ 1, 2, 42 ] - |> List.map - (\int -> - { text = String.fromInt int - , icon = Element.none - } - ) - , onSelect = always idle >> Just - } + [ ( "First selected" + , { selected = Just 0 + , options = + [ 1, 2, 42 ] + |> List.map + (\int -> + { text = String.fromInt int + , icon = Element.none + } + ) + , onSelect = always idle >> Just + } |> Widget.select |> Widget.buttonRow { list = style.row , button = style.button } - ] - , Element.row Grid.spacedEvenly - [ "Nothing selected" - |> Element.text - |> Element.el [ Element.width <| Element.fill ] - , { selected = Nothing - , options = - [ 1, 2, 42 ] - |> List.map - (\int -> - { text = String.fromInt int - , icon = Element.none - } - ) - , onSelect = always idle >> Just - } + ) + , ( "Nothing selected" + , { selected = Nothing + , options = + [ 1, 2, 42 ] + |> List.map + (\int -> + { text = String.fromInt int + , icon = Element.none + } + ) + , onSelect = always idle >> Just + } |> Widget.select |> Widget.buttonRow { list = style.row , button = style.button } - ] - , Element.row Grid.spacedEvenly - [ "Invalid selection" - |> Element.text - |> Element.el [ Element.width <| Element.fill ] - , { selected = Just -1 - , options = - [ 1, 2, 42 ] - |> List.map - (\int -> - { text = String.fromInt int - , icon = Element.none - } - ) - , onSelect = always idle >> Just - } + ) + , ( "Invalid selection" + , { selected = Just -1 + , options = + [ 1, 2, 42 ] + |> List.map + (\int -> + { text = String.fromInt int + , icon = Element.none + } + ) + , onSelect = always idle >> Just + } |> Widget.select |> Widget.buttonRow { list = style.row , button = style.button } - ] - , Element.row Grid.spacedEvenly - [ "Disabled selection" - |> Element.text - |> Element.el [ Element.width <| Element.fill ] - , { selected = Just 0 - , options = - [ 1, 2, 42 ] - |> List.map - (\int -> - { text = String.fromInt int - , icon = Element.none - } - ) - , onSelect = always Nothing - } + ) + , ( "Disabled selection" + , { selected = Just 0 + , options = + [ 1, 2, 42 ] + |> List.map + (\int -> + { text = String.fromInt int + , icon = Element.none + } + ) + , onSelect = always Nothing + } |> Widget.select |> Widget.buttonRow { list = style.row , button = style.button } - ] - , Element.row Grid.spacedEvenly - [ "Empty Options" - |> Element.text - |> Element.el [ Element.width <| Element.fill ] - , { selected = Nothing - , options = - [] - |> List.map - (\int -> - { text = String.fromInt int - , icon = Element.none - } - ) - , onSelect = always idle >> Just - } + ) + , ( "Empty Options" + , { selected = Nothing + , options = + [] + |> List.map + (\int -> + { text = String.fromInt int + , icon = Element.none + } + ) + , onSelect = always idle >> Just + } |> Widget.select |> Widget.buttonRow { list = style.row , button = style.button } - ] + ) ] -multiSelect : msg -> Style msg -> List (Element msg) +multiSelect : msg -> Style msg -> List ( String, Element msg ) multiSelect idle style = - [ Element.row Grid.spacedEvenly - [ "Some selected" - |> Element.text - |> Element.el [ Element.width <| Element.fill ] - , { selected = Set.fromList [ 0, 1 ] - , options = - [ 1, 2, 42 ] - |> List.map - (\int -> - { text = String.fromInt int - , icon = Element.none - } - ) - , onSelect = always idle >> Just - } + [ ( "Some selected" + , { selected = Set.fromList [ 0, 1 ] + , options = + [ 1, 2, 42 ] + |> List.map + (\int -> + { text = String.fromInt int + , icon = Element.none + } + ) + , onSelect = always idle >> Just + } |> Widget.multiSelect |> Widget.buttonRow { list = style.row , button = style.button } - ] - , Element.row Grid.spacedEvenly - [ "Nothing selected" - |> Element.text - |> Element.el [ Element.width <| Element.fill ] - , { selected = Set.empty - , options = - [ 1, 2, 42 ] - |> List.map - (\int -> - { text = String.fromInt int - , icon = Element.none - } - ) - , onSelect = always idle >> Just - } + ) + , ( "Nothing selected" + , { selected = Set.empty + , options = + [ 1, 2, 42 ] + |> List.map + (\int -> + { text = String.fromInt int + , icon = Element.none + } + ) + , onSelect = always idle >> Just + } |> Widget.multiSelect |> Widget.buttonRow { list = style.row , button = style.button } - ] - , Element.row Grid.spacedEvenly - [ "Invalid selection" - |> Element.text - |> Element.el [ Element.width <| Element.fill ] - , { selected = Set.singleton -1 - , options = - [ 1, 2, 42 ] - |> List.map - (\int -> - { text = String.fromInt int - , icon = Element.none - } - ) - , onSelect = always idle >> Just - } + ) + , ( "Invalid selection" + , { selected = Set.singleton -1 + , options = + [ 1, 2, 42 ] + |> List.map + (\int -> + { text = String.fromInt int + , icon = Element.none + } + ) + , onSelect = always idle >> Just + } |> Widget.multiSelect |> Widget.buttonRow { list = style.row , button = style.button } - ] - , Element.row Grid.spacedEvenly - [ "Disabled selection" - |> Element.text - |> Element.el [ Element.width <| Element.fill ] - , { selected = Set.singleton 0 - , options = - [ 1, 2, 42 ] - |> List.map - (\int -> - { text = String.fromInt int - , icon = Element.none - } - ) - , onSelect = always Nothing - } + ) + , ( "Disabled selection" + , { selected = Set.singleton 0 + , options = + [ 1, 2, 42 ] + |> List.map + (\int -> + { text = String.fromInt int + , icon = Element.none + } + ) + , onSelect = always Nothing + } |> Widget.multiSelect |> Widget.buttonRow { list = style.row , button = style.button } - ] - , Element.row Grid.spacedEvenly - [ "Empty Options" - |> Element.text - |> Element.el [ Element.width <| Element.fill ] - , { selected = Set.empty - , options = - [] - |> List.map - (\int -> - { text = String.fromInt int - , icon = Element.none - } - ) - , onSelect = always idle >> Just - } + ) + , ( "Empty Options" + , { selected = Set.empty + , options = + [] + |> List.map + (\int -> + { text = String.fromInt int + , icon = Element.none + } + ) + , onSelect = always idle >> Just + } |> Widget.multiSelect |> Widget.buttonRow { list = style.row , button = style.button } - ] + ) ] -expansionPanel : msg -> Style msg -> List (Element msg) +expansionPanel : msg -> Style msg -> List ( String, Element msg ) expansionPanel idle style = - [ Element.row Grid.spacedEvenly - [ "Collapsed" - |> Element.text - |> Element.el [ Element.width <| Element.fill ] - , { onToggle = always idle - , isExpanded = False - , icon = Icons.triangle |> Element.html |> Element.el [] - , text = "Button" - , content = Element.text <| "Hidden Message" - } + [ ( "Collapsed" + , { onToggle = always idle + , isExpanded = False + , icon = Icons.triangle |> Element.html |> Element.el [] + , text = "Button" + , content = Element.text <| "Hidden Message" + } |> Widget.expansionPanel style.expansionPanel - ] - , Element.row Grid.spacedEvenly - [ "Expanded" - |> Element.text - |> Element.el [ Element.width <| Element.fill ] - , { onToggle = always idle - , isExpanded = True - , icon = Icons.triangle |> Element.html |> Element.el [] - , text = "Button" - , content = Element.text <| "Hidden Message" - } + ) + , ( "Expanded" + , { onToggle = always idle + , isExpanded = True + , icon = Icons.triangle |> Element.html |> Element.el [] + , text = "Button" + , content = Element.text <| "Hidden Message" + } |> Widget.expansionPanel style.expansionPanel - ] + ) ] -tab : msg -> Style msg -> List (Element msg) +tab : msg -> Style msg -> List ( String, Element msg ) tab idle style = - [ Element.row Grid.spacedEvenly - [ "Nothing selected" - |> Element.text - |> Element.el [ Element.width <| Element.fill ] - , Widget.tab style.tab + [ ( "Nothing selected" + , Widget.tab style.tab { tabs = { selected = Nothing , options = @@ -357,12 +298,9 @@ tab idle style = ) |> Element.text } - ] - , Element.row Grid.spacedEvenly - [ "Tab selected" - |> Element.text - |> Element.el [ Element.width <| Element.fill ] - , Widget.tab style.tab + ) + , ( "Tab selected" + , Widget.tab style.tab { tabs = { selected = Just 0 , options = @@ -386,5 +324,190 @@ tab idle style = ) |> Element.text } - ] + ) + ] + + +sortTable : msg -> Style msg -> List ( String, Element msg ) +sortTable idle style = + [ ( "Int column" + , Widget.sortTable style.sortTable + { content = + [ { id = 1, name = "Antonio", rating = 2.456, hash = Nothing } + , { id = 2, name = "Ana", rating = 1.34, hash = Just "45jf" } + ] + , columns = + [ Widget.intColumn + { title = "Id" + , value = .id + , toString = \int -> "#" ++ String.fromInt int + , width = Element.fill + } + , Widget.stringColumn + { title = "Name" + , value = .name + , toString = identity + , width = Element.fill + } + ] + , asc = True + , sortBy = "Id" + , onChange = always idle + } + ) + , ( "Name column" + , Widget.sortTable style.sortTable + { content = + [ { id = 1, name = "Antonio", rating = 2.456, hash = Nothing } + , { id = 2, name = "Ana", rating = 1.34, hash = Just "45jf" } + ] + , columns = + [ Widget.stringColumn + { title = "Name" + , value = .name + , toString = identity + , width = Element.fill + } + , Widget.floatColumn + { title = "Rating" + , value = .rating + , toString = String.fromFloat + , width = Element.fill + } + ] + , asc = True + , sortBy = "Name" + , onChange = always idle + } + ) + , ( "Float column" + , Widget.sortTable style.sortTable + { content = + [ { id = 1, name = "Antonio", rating = 2.456, hash = Nothing } + , { id = 2, name = "Ana", rating = 1.34, hash = Just "45jf" } + ] + , columns = + [ Widget.floatColumn + { title = "Rating" + , value = .rating + , toString = String.fromFloat + , width = Element.fill + } + , Widget.unsortableColumn + { title = "Hash" + , toString = .hash >> Maybe.withDefault "None" + , width = Element.fill + } + ] + , asc = False + , sortBy = "Rating" + , onChange = always idle + } + ) + , ( "Unsortable column" + , Widget.sortTable style.sortTable + { content = + [ { id = 1, name = "Antonio", rating = 2.456, hash = Nothing } + , { id = 2, name = "Ana", rating = 1.34, hash = Just "45jf" } + ] + , columns = + [ Widget.floatColumn + { title = "Rating" + , value = .rating + , toString = String.fromFloat + , width = Element.fill + } + , Widget.unsortableColumn + { title = "Hash" + , toString = .hash >> Maybe.withDefault "None" + , width = Element.fill + } + ] + , asc = True + , sortBy = "Hash" + , onChange = always idle + } + ) + , ( "Empty Table" + , Widget.sortTable style.sortTable + { content = + [ { id = 1, name = "Antonio", rating = 2.456, hash = Nothing } + , { id = 2, name = "Ana", rating = 1.34, hash = Just "45jf" } + ] + , columns = [] + , asc = True + , sortBy = "" + , onChange = always idle + } + ) + ] + + +modal : msg -> Style msg -> List ( String, Element msg ) +modal _ _ = + [] + + +dialog : msg -> Style msg -> List ( String, Element msg ) +dialog _ _ = + [] + + +textInput : msg -> Style msg -> List ( String, Element msg ) +textInput idle style = + [ ( "Nothing Selected" + , { chips = [] + , text = "" + , placeholder = Nothing + , label = "Label" + , onChange = always idle + } + |> Widget.textInput style.textInput + ) + , ( "Some chips" + , { chips = + [ { icon = Icons.triangle |> Element.html |> Element.el [] + , text = "A" + , onPress = Just idle + } + , { icon = Icons.circle |> Element.html |> Element.el [] + , text = "B" + , onPress = Just idle + } + ] + , text = "" + , placeholder = Nothing + , label = "Label" + , onChange = always idle + } + |> Widget.textInput style.textInput + ) + ] + + +list : msg -> Style msg -> List ( String, Element msg ) +list _ style = + [ ( "Row" + , [ Element.text "A" + , Element.text "B" + , Element.text "C" + ] + |> Widget.row style.row + ) + , ( "Column" + , [ Element.text "A" + , Element.text "B" + , Element.text "C" + ] + |> Widget.column style.cardColumn + ) + , ( "Singleton List" + , [ Element.text "A" + ] + |> Widget.column style.cardColumn + ) + , ( "Empty List" + , [] + |> Widget.column style.cardColumn + ) ] diff --git a/src/Internal/Button.elm b/src/Internal/Button.elm index 0b8a96e..306f41e 100644 --- a/src/Internal/Button.elm +++ b/src/Internal/Button.elm @@ -33,7 +33,7 @@ iconButton style { onPress, text, icon } = style.ifDisabled else - [] + style.otherwise ) ++ [ Region.description text ] ) @@ -63,7 +63,7 @@ button style { onPress, text, icon } = style.ifDisabled else - [] + style.otherwise ) ) { onPress = onPress diff --git a/src/Internal/List.elm b/src/Internal/List.elm index 55fb29f..b7da91c 100644 --- a/src/Internal/List.elm +++ b/src/Internal/List.elm @@ -11,7 +11,7 @@ internal : | element : List (Attribute msg) , ifFirst : List (Attribute msg) , ifLast : List (Attribute msg) - , ifCenter : List (Attribute msg) + , otherwise : List (Attribute msg) } -> List (Element msg) -> List (Element msg) @@ -31,7 +31,7 @@ internal style list = style.ifLast else - style.ifCenter + style.otherwise ) ) @@ -52,7 +52,7 @@ internalButton : | element : List (Attribute msg) , ifFirst : List (Attribute msg) , ifLast : List (Attribute msg) - , ifCenter : List (Attribute msg) + , otherwise : List (Attribute msg) } , button : ButtonStyle msg } @@ -76,7 +76,7 @@ internalButton style list = style.list.ifLast else - style.list.ifCenter + style.list.otherwise ) , labelRow = style.button.labelRow @@ -84,6 +84,8 @@ internalButton style list = style.button.ifDisabled , ifActive = style.button.ifActive + , otherwise = + style.button.otherwise } ) diff --git a/src/Widget.elm b/src/Widget.elm index 38b08c0..a2ff771 100644 --- a/src/Widget.elm +++ b/src/Widget.elm @@ -5,8 +5,8 @@ module Widget exposing , ExpansionPanel, expansionPanel , row, column, buttonRow, buttonColumn , ColumnType, sortTable, floatColumn, intColumn, stringColumn, unsortableColumn - , TextInputStyle, textInput, carousel, tab - , Tab + , TextInputStyle, textInput + , Tab, tab ) {-| This module contains functions for displaying data. @@ -27,7 +27,7 @@ module Widget exposing @docs Dialog, modal, dialog -# ExpansionPanel +# Expansion Panel @docs ExpansionPanel, expansionPanel @@ -37,18 +37,22 @@ module Widget exposing @docs row, column, buttonRow, buttonColumn -# SortTable +# Sort Table @docs ColumnType, sortTable, floatColumn, intColumn, stringColumn, unsortableColumn -# Other Widgets +# Text Input -@docs TextInputStyle, textInput, carousel, tab +@docs TextInputStyle, textInput + + +# Tab + +@docs Tab, tab -} -import Array exposing (Array) import Element exposing (Attribute, Element, Length) import Element.Input exposing (Placeholder) import Internal.Button as Button @@ -57,6 +61,7 @@ import Internal.ExpansionPanel as ExpansionPanel import Internal.List as List import Internal.Select as Select import Internal.SortTable as SortTable +import Internal.Tab as Tab import Internal.TextInput as TextInput import Set exposing (Set) import Widget.Style exposing (ButtonStyle, ColumnStyle, DialogStyle, ExpansionPanelStyle, RowStyle, SortTableStyle, TabStyle) @@ -417,7 +422,7 @@ sortTable = {---------------------------------------------------------- -- OTHER STATELESS WIDGETS +- TAB ----------------------------------------------------------} @@ -436,42 +441,5 @@ tab : , content : Maybe Int -> Element msg } -> Element msg -tab style { tabs, content } = - [ tabs - |> select - |> List.map (selectButton style.button) - |> Element.row style.optionRow - , tabs.selected - |> content - |> Element.el style.content - ] - |> Element.column style.containerColumn - - -{-| A Carousel circles through a non empty list of contents. --} -carousel : - { content : ( a, Array a ) - , current : Int - , label : a -> Element msg - } - -> Element msg -carousel { content, current, label } = - let - ( head, tail ) = - content - in - (if current <= 0 then - head - - else if current > Array.length tail then - tail - |> Array.get (Array.length tail - 1) - |> Maybe.withDefault head - - else - tail - |> Array.get (current - 1) - |> Maybe.withDefault head - ) - |> label +tab = + Tab.tab diff --git a/src/Layout.elm b/src/Widget/Layout.elm similarity index 99% rename from src/Layout.elm rename to src/Widget/Layout.elm index 56388ea..914ac46 100644 --- a/src/Layout.elm +++ b/src/Widget/Layout.elm @@ -1,4 +1,4 @@ -module Layout exposing (Layout, Part(..), activate, init, queueMessage, timePassed, view) +module Widget.Layout exposing (Layout, Part(..), activate, init, queueMessage, timePassed, view) import Array import Element exposing (Attribute, DeviceClass(..), Element) diff --git a/src/Widget/Style.elm b/src/Widget/Style.elm index 5e8af81..f09d5cf 100644 --- a/src/Widget/Style.elm +++ b/src/Widget/Style.elm @@ -9,6 +9,7 @@ type alias ButtonStyle msg = , labelRow : List (Attribute msg) , ifDisabled : List (Attribute msg) , ifActive : List (Attribute msg) + , otherwise : List (Attribute msg) } @@ -59,7 +60,7 @@ type alias RowStyle msg = , element : List (Attribute msg) , ifFirst : List (Attribute msg) , ifLast : List (Attribute msg) - , ifCenter : List (Attribute msg) + , otherwise : List (Attribute msg) } @@ -68,7 +69,7 @@ type alias ColumnStyle msg = , element : List (Attribute msg) , ifFirst : List (Attribute msg) , ifLast : List (Attribute msg) - , ifCenter : List (Attribute msg) + , otherwise : List (Attribute msg) }