Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: Dynamic styles #8

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion elm-package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"source-directories": [
"src"
],
"exposed-modules": ["Style"],
"exposed-modules": ["Style", "Style.Dynamic"],
"dependencies": {
"coreytrampe/elm-vendor": "2.0.2 <= v < 3.0.0",
"elm-lang/core": "4.0.1 <= v < 5.0.0",
Expand Down
102 changes: 102 additions & 0 deletions example/DynamicExample.elm
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
-- DYNAMIC EXAMPLE
module Main exposing (..)


-- THIRD PARTY IMPORTS


import Html exposing (..)
import Html.Attributes exposing (style)


-- MY IMPORTS


import MyStyles


-- MODEL


type alias Model =
{ header : List String
, title : String
, description : String
, subDescription : String
, callToAction : String
}


initialModel : Model
initialModel =
{ header = [ "examples", "docs", "community", "blog" ]
, title = "elm"
, description = "the best of functional programming in your browser"
, subDescription = "writing great code should be easy ... now it is"
, callToAction = "try or install"
}


-- VIEW


header : Model -> Html msg
header model =
div
[ style MyStyles.header ]
(List.map (\x -> div [] [ text x ]) model.header)


title : Model -> Html msg
title model =
div
MyStyles.interactiveTitle
[ text model.title ]


description : Model -> Html msg
description model =
div
[ style MyStyles.description ]
[ text model.description ]


subDescription : Model -> Html msg
subDescription model =
div
[ style MyStyles.subDescription ]
[ text model.subDescription ]


callToAction : Model -> Html msg
callToAction model =
div
MyStyles.interactiveCallToAction
[ text model.callToAction ]


view : Model -> Html msg
view model =
div
[ style MyStyles.container ]
[ div
[ style MyStyles.top ]
[ header model
, title model
, description model
, subDescription model
, callToAction model
]

, div
[ style MyStyles.bottom ]
[]
]


-- WIRING


main : Html msg
main =
view initialModel
13 changes: 11 additions & 2 deletions example/MyStyles.elm
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import Html.Attributes exposing (style)


import Style exposing (..)

import Style.Dynamic exposing (..)

type alias Styles = List ( String, String )

Expand Down Expand Up @@ -88,7 +88,9 @@ title =
]
]


interactiveTitle : List (Html.Attribute msg)
interactiveTitle =
dynamicEffect [hover] title [dS fontSize (px 100) [px 150]]

description : Styles
description =
Expand Down Expand Up @@ -122,6 +124,13 @@ callToAction =
]
]

interactiveCallToAction : List (Html.Attribute msg)
interactiveCallToAction =
dynamicEffect [hover,pressure] callToAction
[dS color (color' white) [(color' red), (color' black)],
dS fontSize (px 24) [(px 32), (px 32)]]



bottom : Styles
bottom =
Expand Down
109 changes: 109 additions & 0 deletions src/Style/Dynamic.elm
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
module Style.Dynamic exposing ( InterEvent, Effect, DynamicStyle, dS, dynamicEffect, hover, pressure )


{-| Extension for the Style library to add dynamic effects

# Dynamics
@docs DynamicStyle, InterEvent, Effect

# Functions
@docs dS, dynamicEffect

# Effects
@docs hover, pressure
-}

import Html exposing (Attribute)
import Html.Attributes exposing (style, attribute)
import String
import List
import Style exposing (..)

{-| Alias for inline dynamic styles

myDynamicStyle : DynamicStyle
myDynamicStyle =
(offStyle, [onStyle1, onStyle2])
-}
type alias DynamicStyle = (Style, List Style)

{-| JS interactive event

myEvent : InterEvent
myEvent = "onmouseover"
-}
type alias InterEvent = String

{-| A tuple of event lists to turn the effect on and off

pressure =
(["onmouseup", "onmouseout"], ["onmousedown"])
-}
type alias Effect = (List InterEvent, List InterEvent)


applyToFirst : (String -> String) -> String -> String
applyToFirst f str = f (String.left 1 str) ++ (String.dropLeft 1 str)

transpose : List (List a) -> List (List a)
transpose ll =
case ll of
[] -> []
([]::xss) -> transpose xss
((x::xs)::xss) ->
let
heads = List.filterMap List.head xss
tails = List.filterMap List.tail xss
in
(x::heads)::transpose (xs::tails)

-- Change the CSS notation to JS: "background-color" -> "backgroundColor"
toJs : String -> String
toJs = applyToFirst String.toLower << String.concat << List.map (applyToFirst String.toUpper) << String.split "-"

-- Generate the JS code to set the style
toJsCode : List (String, String) -> String
toJsCode = List.foldl (\(key,value) acc -> acc ++ "this.style." ++ toJs key ++ "= '" ++ value ++ "';") ""

{-| Dynamic State Function. It takes a CSS attribute, a value describing the off-state and a list of values for on-states, one for each effect included
changingColor : DynamicStyle
changingColor = dS color (color' red) [(color' blue), (color' black)]
-}
dS : (String -> (String, String)) -> String -> List String -> DynamicStyle
dS cssKey offStateValue onStateValues = (cssKey offStateValue, List.map cssKey onStateValues)

-- Obtain the Events that switch the effects on and off
switchEvents : List Effect -> (List InterEvent, List InterEvent)
switchEvents = List.foldl (\(switchOff,switchOn) (accOff, accOn) -> (accOff ++ switchOff, accOn ++ switchOn)) ([],[])

---- Response to an event in JS
eventReactor : List (String, String) -> InterEvent -> Attribute msg
eventReactor params event = attribute event (toJsCode params)

{-| Function to generate Dynamic Effects.
myEffect : List (Attribute msg)
myEffect =
dynamicEffect [hover, pressure]
[style [fontSize (px 24)]]
[dS fontColor (color' red) [(color' blue), (color' black)]]

-}
dynamicEffect : List Effect -> List Style -> List DynamicStyle -> List (Attribute msg)
dynamicEffect effects staticParameters dynamicParameters =
let
(switchOff, switchOn) = switchEvents effects
inactiveParameters = List.map (\(a,_) -> a) dynamicParameters
startingParameters = staticParameters ++ inactiveParameters
activeParameters = transpose (List.map (\(_,a)->a) dynamicParameters)
in
[style startingParameters] ++ List.map2 eventReactor activeParameters switchOn ++ List.map (eventReactor inactiveParameters) switchOff

{-| hover
-}
hover : Effect
hover = (["onmouseout"], ["onmouseover"])

{-| presure
-}
pressure : Effect
pressure = (["onmouseup", "onmouseout"], ["onmousedown"])