From 51ccf72152935f98b5a95dce0ce53d44f90b7261 Mon Sep 17 00:00:00 2001 From: Maxime Dantec Date: Fri, 17 Feb 2017 01:47:18 +0100 Subject: [PATCH 1/3] Add support for css animations (@keyframes) --- package.json | 1 + src/Css.elm | 22 +++++++++++++++- src/Css/Preprocess.elm | 6 ++++- src/Css/Preprocess/Resolve.elm | 47 +++++++++++++++++++++++++++++----- src/Css/Structure.elm | 19 ++++++++++---- src/Css/Structure/Output.elm | 25 ++++++++++++++++++ tests/Animations.elm | 40 +++++++++++++++++++++++++++++ tests/Tests.elm | 2 ++ 8 files changed, 148 insertions(+), 14 deletions(-) create mode 100644 tests/Animations.elm diff --git a/package.json b/package.json index e8ba1030..0531646b 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "dependencies": { "chalk": "1.1.1", "commander": "2.9.0", + "elm-test": "^0.18.2", "node-elm-compiler": "2.3.2", "tmp": "0.0.28" }, diff --git a/src/Css.elm b/src/Css.elm index 2b048ae1..db3b6429 100644 --- a/src/Css.elm +++ b/src/Css.elm @@ -462,6 +462,7 @@ module Css , projection , tv , mediaQuery + , keyframes , src , qt , fontFamilies @@ -615,7 +616,7 @@ module Css @docs screen, tv, projection, print # Properties -@docs property, flex, flex2, flex3, medium, alignSelf, alignItems, justifyContent, order, flexDirection, flexFlow1, flexFlow2, flexWrap, flexBasis, flexGrow, flexShrink, transformStyle, transformBox, transform, transforms, currentColor, underline, overline, lineThrough, textOrientation, textDecoration, textDecoration2, textDecoration3, textDecorationLine, textDecorations, textDecorations2, textDecorations3, textDecorationLine, textDecorationLines, textDecorationStyle, textEmphasisColor, capitalize, uppercase, lowercase, fullWidth, hanging, eachLine, textIndent, textIndent2, textIndent3, clip, ellipsis, textOverflow, optimizeSpeed, optimizeLegibility, geometricPrecision, textRendering, textTransform, textAlign, textAlignLast, left, right, center, textJustify, justifyAll, start, end, matchParent, true, verticalAlign, display, opacity, minContent, maxContent, fitContent, fillAvailable, width, minWidth, maxWidth, height, minHeight, maxHeight, padding, padding2, padding3, padding4, paddingTop, paddingBottom, paddingRight, paddingLeft, paddingBlockStart, paddingBlockEnd, paddingInlineStart, paddingInlineEnd, margin, margin2, margin3, margin4, marginTop, marginBottom, marginRight, marginLeft, marginBlockStart, marginBlockEnd, marginInlineStart, marginInlineEnd, boxSizing, overflow, overflowX, overflowY, overflowWrap, whiteSpace, backgroundColor, color, withMedia, each, media, mediaQuery, textShadow, textShadow2, textShadow3, textShadow4, boxShadow, boxShadow2, boxShadow3, boxShadow4, boxShadow5, boxShadow6, lineHeight, letterSpacing, fontFace, fontFamily, fontSize, fontStyle, fontWeight, fontVariant, fontVariant2, fontVariant3, fontVariantLigatures, fontVariantCaps, fontVariantNumeric, fontVariantNumeric2, fontVariantNumeric3, fontFamilies, fontVariantNumerics, fontFeatureSettings, fontFeatureSettingsList, cursor, outline, outline3, outlineColor, outlineWidth, outlineStyle, outlineOffset, zIndex, spaceAround, spaceBetween, resize, fill +@docs property, flex, flex2, flex3, medium, alignSelf, alignItems, justifyContent, order, flexDirection, flexFlow1, flexFlow2, flexWrap, flexBasis, flexGrow, flexShrink, transformStyle, transformBox, transform, transforms, currentColor, underline, overline, lineThrough, textOrientation, textDecoration, textDecoration2, textDecoration3, textDecorationLine, textDecorations, textDecorations2, textDecorations3, textDecorationLine, textDecorationLines, textDecorationStyle, textEmphasisColor, capitalize, uppercase, lowercase, fullWidth, hanging, eachLine, textIndent, textIndent2, textIndent3, clip, ellipsis, textOverflow, optimizeSpeed, optimizeLegibility, geometricPrecision, textRendering, textTransform, textAlign, textAlignLast, left, right, center, textJustify, justifyAll, start, end, matchParent, true, verticalAlign, display, opacity, minContent, maxContent, fitContent, fillAvailable, width, minWidth, maxWidth, height, minHeight, maxHeight, padding, padding2, padding3, padding4, paddingTop, paddingBottom, paddingRight, paddingLeft, paddingBlockStart, paddingBlockEnd, paddingInlineStart, paddingInlineEnd, margin, margin2, margin3, margin4, marginTop, marginBottom, marginRight, marginLeft, marginBlockStart, marginBlockEnd, marginInlineStart, marginInlineEnd, boxSizing, overflow, overflowX, overflowY, overflowWrap, whiteSpace, backgroundColor, color, withMedia, each, media, mediaQuery, keyframes, textShadow, textShadow2, textShadow3, textShadow4, boxShadow, boxShadow2, boxShadow3, boxShadow4, boxShadow5, boxShadow6, lineHeight, letterSpacing, fontFace, fontFamily, fontSize, fontStyle, fontWeight, fontVariant, fontVariant2, fontVariant3, fontVariantLigatures, fontVariantCaps, fontVariantNumeric, fontVariantNumeric2, fontVariantNumeric3, fontFamilies, fontVariantNumerics, fontFeatureSettings, fontFeatureSettingsList, cursor, outline, outline3, outlineColor, outlineWidth, outlineStyle, outlineOffset, zIndex, spaceAround, spaceBetween, resize, fill # Values @@ -6390,6 +6391,25 @@ withMedia = Preprocess.WithMedia +{-| Animation's @keyframe + + keyframes "animationName" + [( 0 + , [ backgroundColor blue + ] + ) + [( 100 + , [ backgroundColor red + ] + ) + ] + +-} +keyframes : String -> List ( Float, List Mixin ) -> Snippet +keyframes name steps = + Preprocess.Snippet ([ Preprocess.Keyframes name steps ]) + + {- FONT PROPERTIES -} diff --git a/src/Css/Preprocess.elm b/src/Css/Preprocess.elm index 09208567..e4065408 100644 --- a/src/Css/Preprocess.elm +++ b/src/Css/Preprocess.elm @@ -52,12 +52,16 @@ type SnippetDeclaration | DocumentRule String String String String StyleBlock | PageRule String (List Property) | FontFace (List Property) - | Keyframes String (List Structure.KeyframeProperty) + | Keyframes String (List KeyframeStep) | Viewport (List Property) | CounterStyle (List Property) | FontFeatureValues (List ( String, List Property )) +type alias KeyframeStep = + ( Float, List Mixin ) + + type StyleBlock = StyleBlock Structure.Selector (List Structure.Selector) (List Mixin) diff --git a/src/Css/Preprocess/Resolve.elm b/src/Css/Preprocess/Resolve.elm index a325d9a7..6cc87ebc 100644 --- a/src/Css/Preprocess/Resolve.elm +++ b/src/Css/Preprocess/Resolve.elm @@ -5,6 +5,7 @@ Structure data structures and gathering warnings along the way. -} import String +import List import Css.Preprocess as Preprocess exposing (SnippetDeclaration, Snippet(Snippet), Mixin(AppendProperty, ExtendSelector, NestSnippet), unwrapSnippet) import Css.Structure as Structure exposing (mapLast) import Css.Structure.Output as Output @@ -141,11 +142,43 @@ resolveFontFace fontFaceProperties = } -resolveKeyframes : String -> List Structure.KeyframeProperty -> DeclarationsAndWarnings -resolveKeyframes str properties = - { declarations = [ Structure.Keyframes str properties ] - , warnings = [] - } +resolveKeyframes : String -> List Preprocess.KeyframeStep -> DeclarationsAndWarnings +resolveKeyframes name steps = + let + ( warnings, keyframes ) = + extractWarningsFromKeyframes steps ( [], [] ) + in + { declarations = [ Structure.Keyframes name keyframes ] + , warnings = warnings + } + + +extractWarningsFromKeyframes : List Preprocess.KeyframeStep -> ( List String, List Structure.KeyframeStep ) -> ( List String, List Structure.KeyframeStep ) +extractWarningsFromKeyframes ls ( warnings, steps ) = + case ls of + ( step, mixins ) :: tl -> + if step < 0 || step > 100 then + -- keyframe is dropped + extractWarningsFromKeyframes tl + ( "Keyframe must be between 0 and 100 (those are percents)." :: warnings + , steps + ) + else + let + props = + Preprocess.toPropertyPairs mixins + |> List.map pairToProperty + + pairToProperty ( k, v ) = + { important = False + , key = k + , value = v + } + in + extractWarningsFromKeyframes tl ( warnings, ( step, props ) :: steps ) + + [] -> + ( warnings, steps ) resolveViewport : List Preprocess.Property -> DeclarationsAndWarnings @@ -218,8 +251,8 @@ toDeclarations snippetDeclaration = Preprocess.FontFace fontFaceProperties -> resolveFontFace fontFaceProperties - Preprocess.Keyframes str properties -> - resolveKeyframes str properties + Preprocess.Keyframes name steps -> + resolveKeyframes name steps Preprocess.Viewport viewportProperties -> resolveViewport viewportProperties diff --git a/src/Css/Structure.elm b/src/Css/Structure.elm index ced7205f..d0781809 100644 --- a/src/Css/Structure.elm +++ b/src/Css/Structure.elm @@ -53,7 +53,7 @@ type Declaration | DocumentRule String String String String StyleBlock | PageRule String (List Property) | FontFace (List Property) - | Keyframes String (List KeyframeProperty) + | Keyframes String (List KeyframeStep) | Viewport (List Property) | CounterStyle (List Property) | FontFeatureValues (List ( String, List Property )) @@ -121,8 +121,8 @@ type SelectorCombinator | Descendant -type alias KeyframeProperty = - String +type alias KeyframeStep = + ( Float, List Property ) {-| Add a property to the last style block in the given declarations. @@ -141,6 +141,11 @@ appendProperty property declarations = (mapLast (withPropertyAppended property) styleBlocks) ] + (Keyframes name steps) :: [] -> + [ Keyframes name + (mapLast (appendPropertyToKeyframe property) steps) + ] + -- TODO _ :: [] -> declarations @@ -149,7 +154,6 @@ appendProperty property declarations = --| DocumentRule String String String String StyleBlock --| PageRule String (List Property) --| FontFace (List Property) - --| Keyframes String (List KeyframeProperty) --| Viewport (List Property) --| CounterStyle (List Property) --| FontFeatureValues (List ( String, List Property )) @@ -162,6 +166,11 @@ withPropertyAppended property (StyleBlock firstSelector otherSelectors propertie StyleBlock firstSelector otherSelectors (properties ++ [ property ]) +appendPropertyToKeyframe : Property -> KeyframeStep -> KeyframeStep +appendPropertyToKeyframe prop ( step, props ) = + ( step, prop :: props ) + + extendLastSelector : RepeatableSimpleSelector -> List Declaration -> List Declaration extendLastSelector selector declarations = case declarations of @@ -229,7 +238,7 @@ extendLastSelector selector declarations = (FontFace _) :: [] -> declarations - (Keyframes _ _) :: [] -> + (Keyframes name steps) :: [] -> declarations (Viewport _) :: [] -> diff --git a/src/Css/Structure/Output.elm b/src/Css/Structure/Output.elm index 5e21bb07..04306ff2 100644 --- a/src/Css/Structure/Output.elm +++ b/src/Css/Structure/Output.elm @@ -69,6 +69,24 @@ prettyPrintDeclaration declaration = in "@media " ++ query ++ " {\n" ++ indent blocks ++ "\n}" + Keyframes name steps -> + let + prettyPrintStep ( step, props ) = + (toString step) + ++ "% {\n" + ++ (prettyPrintProperties props |> indentLines) + ++ "\n}" + in + "@keyframes " + ++ name + ++ " {\n" + ++ (List.map prettyPrintStep steps + |> List.reverse + |> String.join "\n" + |> indentLines + ) + ++ "\n}" + _ -> Debug.crash "not yet implemented :x" @@ -167,6 +185,13 @@ indent str = " " ++ str +indentLines : String -> String +indentLines = + String.lines + >> List.map ((++) " ") + >> String.join "\n" + + prettyPrintProperties : List Property -> String prettyPrintProperties properties = properties diff --git a/tests/Animations.elm b/tests/Animations.elm new file mode 100644 index 00000000..fbaee1a9 --- /dev/null +++ b/tests/Animations.elm @@ -0,0 +1,40 @@ +module Animations exposing (all) + +import Test exposing (..) +import Expect +import TestUtil exposing (prettyPrint) +import Css exposing (..) +import Css.Colors exposing (..) + + +all : Test +all = + describe "animations" + [ animations ] + + +animations : Test +animations = + describe "Animations" + [ test "keyframes" <| + \() -> + stylesheet + [ keyframes "foo" + [ ( 0, [ backgroundColor red ] ) + , ( 50, [ backgroundColor blue ] ) + , ( 100, [ backgroundColor yellow ] ) + ] + ] + |> prettyPrint + |> Expect.equal """@keyframes foo { + 0% { + background-color: #FF4136; + } + 50% { + background-color: #0074D9; + } + 100% { + background-color: #FFDC00; + } +}""" + ] diff --git a/tests/Tests.elm b/tests/Tests.elm index a9d813bc..42fea097 100644 --- a/tests/Tests.elm +++ b/tests/Tests.elm @@ -10,6 +10,7 @@ import Fixtures import Properties import Selectors import Colors +import Animations all : Test @@ -43,6 +44,7 @@ all = , Selectors.all , Arithmetic.all , backgrounds + , Animations.all ] From d5a17d46c3e30b5ed985cbd65484417a9f66a48e Mon Sep 17 00:00:00 2001 From: Maxime Dantec Date: Fri, 17 Feb 2017 12:40:20 +0100 Subject: [PATCH 2/3] fix double indentation in properties --- src/Css/Structure/Output.elm | 4 ++-- tests/Animations.elm | 15 +++++++++------ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/Css/Structure/Output.elm b/src/Css/Structure/Output.elm index 04306ff2..aa375192 100644 --- a/src/Css/Structure/Output.elm +++ b/src/Css/Structure/Output.elm @@ -74,7 +74,7 @@ prettyPrintDeclaration declaration = prettyPrintStep ( step, props ) = (toString step) ++ "% {\n" - ++ (prettyPrintProperties props |> indentLines) + ++ (prettyPrintProperties props) ++ "\n}" in "@keyframes " @@ -188,7 +188,7 @@ indent str = indentLines : String -> String indentLines = String.lines - >> List.map ((++) " ") + >> List.map indent >> String.join "\n" diff --git a/tests/Animations.elm b/tests/Animations.elm index fbaee1a9..c7b590aa 100644 --- a/tests/Animations.elm +++ b/tests/Animations.elm @@ -20,21 +20,24 @@ animations = \() -> stylesheet [ keyframes "foo" - [ ( 0, [ backgroundColor red ] ) - , ( 50, [ backgroundColor blue ] ) - , ( 100, [ backgroundColor yellow ] ) + [ ( 0, [ backgroundColor red, color black ] ) + , ( 50, [ backgroundColor blue, color black ] ) + , ( 100, [ backgroundColor yellow, color black ] ) ] ] |> prettyPrint |> Expect.equal """@keyframes foo { 0% { - background-color: #FF4136; + background-color: #FF4136; + color: #111111; } 50% { - background-color: #0074D9; + background-color: #0074D9; + color: #111111; } 100% { - background-color: #FFDC00; + background-color: #FFDC00; + color: #111111; } }""" ] From 4ad6f40fb8df60ff600130f8b60daefa3fe9cba7 Mon Sep 17 00:00:00 2001 From: Maxime Dantec Date: Fri, 17 Feb 2017 12:42:53 +0100 Subject: [PATCH 3/3] fix typo --- src/Css.elm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Css.elm b/src/Css.elm index db3b6429..b5f75f3c 100644 --- a/src/Css.elm +++ b/src/Css.elm @@ -6391,7 +6391,7 @@ withMedia = Preprocess.WithMedia -{-| Animation's @keyframe +{-| Animation's @keyframes keyframes "animationName" [( 0