├── .eslintrc.json ├── .gitignore ├── .lintstagedrc ├── License ├── Readme.md ├── assets ├── logo.png └── logo.svg ├── demo ├── Animation.elm ├── Basic.elm ├── Dynamic.elm └── Overriding.elm ├── elm-package.json ├── package.json ├── src ├── Internal.elm ├── Native │ └── Css.js ├── Styled.elm └── Styled │ ├── Colors.elm │ ├── Cursors.elm │ ├── FontVariants.elm │ ├── Gradients.elm │ ├── Html.elm │ ├── Keyframes.elm │ ├── ListStyles.elm │ ├── Selectors.elm │ ├── Timings.elm │ ├── Transforms.elm │ └── Types.elm ├── test └── Native │ ├── .eslintrc.json │ ├── Css.js │ └── __snapshots__ │ └── Css.js.snap └── yarn.lock /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint:recommended", 3 | "parserOptions": { 4 | "ecmaVersion": 5 5 | }, 6 | "env": { 7 | "browser": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | documentation.json 2 | 3 | # Created by https://www.gitignore.io/api/elm,node 4 | 5 | ### Elm ### 6 | # elm-package generated files 7 | elm-stuff 8 | # elm-repl generated files 9 | repl-temp-* 10 | 11 | ### Node ### 12 | # Logs 13 | logs 14 | *.log 15 | npm-debug.log* 16 | yarn-debug.log* 17 | yarn-error.log* 18 | 19 | # Runtime data 20 | pids 21 | *.pid 22 | *.seed 23 | *.pid.lock 24 | 25 | # Directory for instrumented libs generated by jscoverage/JSCover 26 | lib-cov 27 | 28 | # Coverage directory used by tools like istanbul 29 | coverage 30 | 31 | # nyc test coverage 32 | .nyc_output 33 | 34 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 35 | .grunt 36 | 37 | # Bower dependency directory (https://bower.io/) 38 | bower_components 39 | 40 | # node-waf configuration 41 | .lock-wscript 42 | 43 | # Compiled binary addons (http://nodejs.org/api/addons.html) 44 | build/Release 45 | 46 | # Dependency directories 47 | node_modules/ 48 | jspm_packages/ 49 | 50 | # Typescript v1 declaration files 51 | typings/ 52 | 53 | # Optional npm cache directory 54 | .npm 55 | 56 | # Optional eslint cache 57 | .eslintcache 58 | 59 | # Optional REPL history 60 | .node_repl_history 61 | 62 | # Output of 'npm pack' 63 | *.tgz 64 | 65 | # Yarn Integrity file 66 | .yarn-integrity 67 | 68 | # dotenv environment variables file 69 | .env 70 | 71 | 72 | # End of https://www.gitignore.io/api/elm,node 73 | -------------------------------------------------------------------------------- /.lintstagedrc: -------------------------------------------------------------------------------- 1 | { 2 | "linters": { 3 | "*.js": [ 4 | "eslint --fix", 5 | "git add" 6 | ], 7 | "*.elm": [ 8 | "elm-format --yes", 9 | "git add", 10 | "elm-make --warn --output=/dev/null" 11 | ] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /License: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Konstantin Pschera (kons.ch) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | > **Unreleased!** At the moment I can't release this package to the elm package manager because it is [using Native code](https://github.com/styled-components/elm-styled/issues/14). If you still want to expirement with it you can install it directly from GitHub. ❤️ 2 | 3 | 4 | 5 | elm-styled logo 6 | 7 | 8 | Use typed CSS inside your Elm files to style your Html elements. 9 | 10 | ``` 11 | elm-package install styled-components/elm-styled 12 | ``` 13 | 14 | # Usage 15 | 16 | ## Basic 17 | 18 | This creates two Elm functions, title and wrapper. 19 | 20 | ```elm 21 | import Html exposing (..) 22 | import Styled exposing (..) 23 | import Styled.Colors exposing (pink, lightYellow) 24 | 25 | 26 | title = 27 | styled h1 28 | [ fontSize (Styled.em 1.5) 29 | , textAlign center 30 | , color pink 31 | , fontFamily monospace 32 | ] 33 | 34 | 35 | wrapper = 36 | styled div 37 | [ padding (Styled.em 4) 38 | , backgroundColor lightYellow 39 | ] 40 | ``` 41 | 42 | You render them like every other Elm node. 43 | 44 | 45 | ```elm 46 | main = 47 | wrapper [] 48 | [ title [] 49 | [ text "Hello World, this is my first styled function 💅" ] 50 | ] 51 | ``` 52 | 53 |
54 | Screenshot of the above code ran in a browser 💅 55 |
56 | 57 | ## Overriding Styles 58 | 59 | We can create a simple button function and using this function to create a new styled function. The new styled function will have all of the styles from both styled functions. 60 | 61 | ```elm 62 | import Html exposing (div, text) 63 | import Styled exposing (..) 64 | import Styled.Colors exposing (white, pink) 65 | 66 | 67 | button = 68 | styled Html.button 69 | [ backgroundColor white 70 | , color pink 71 | , fontSize (Styled.em 1) 72 | , margin (Styled.em 1) 73 | , padding2 (Styled.em 0.25) (Styled.em 1) 74 | , border (px 2) solid pink 75 | , borderRadius (px 3) 76 | ] 77 | 78 | 79 | primaryButton = 80 | styled button 81 | [ backgroundColor pink 82 | , color white 83 | ] 84 | 85 | 86 | main = 87 | div 88 | [] 89 | [ button [] [ text "Normal" ] 90 | , primaryButton [] [ text "Primary" ] 91 | ] 92 | ``` 93 | 94 |
95 | Screenshot of the above code ran in a browser 💅 96 |
97 | 98 | ## Dynamic Styles 99 | 100 | If you want to have dynamic styles you can create a function which will return a styled function. 101 | 102 | ```elm 103 | import Html exposing (..) 104 | import Styled exposing (..) 105 | import Styled.Colors exposing (red, yellow, green) 106 | 107 | 108 | light paint = 109 | styled div 110 | [ backgroundColor paint 111 | , borderRadius (percent 50) 112 | , display inlineBlock 113 | , height (px 60) 114 | , width (px 60) 115 | , margin (px 20) 116 | ] 117 | 118 | 119 | trafficLight = 120 | div [] 121 | [ light red [] [] 122 | , light yellow [] [] 123 | , light green [] [] 124 | ] 125 | 126 | 127 | main = 128 | trafficLight 129 | ``` 130 | 131 |
132 | Screenshot of the above code ran in a browser 💅 133 |
134 | 135 | ## Animations 136 | 137 | CSS animations with @keyframes aren't scoped to a single function but you still don't want them to be global. This is why we export a keyframes helper which will generate a unique name for your keyframes. You can then use that unique name throughout your app. 138 | 139 | ```elm 140 | import Html exposing (..) 141 | import Styled exposing (..) 142 | import Styled.Keyframes exposing (keyframes) 143 | import Styled.Transforms exposing (rotate) 144 | import Styled.Timings exposing (linear) 145 | 146 | 147 | spin = 148 | keyframes 149 | [ ( 0 150 | , [ transform (rotate (deg 0)) 151 | ] 152 | ) 153 | , ( 100 154 | , [ transform (rotate (deg 360)) 155 | ] 156 | ) 157 | ] 158 | 159 | 160 | loader = 161 | styled div 162 | [ display inlineBlock 163 | , animationName spin 164 | , animationDuration (Styled.s 2) 165 | , animationTimingFunction linear 166 | , animationIterationCount infinite 167 | ] 168 | 169 | 170 | main = 171 | loader [] [ text "[ 💅 ]" ] 172 | ``` 173 | 174 |
175 | Screenshot of the above code ran in a browser 💅 176 |
177 | -------------------------------------------------------------------------------- /assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/styled-components/elm-styled/b12c12a6811726e945b90ad707a6e9a6df629b39/assets/logo.png -------------------------------------------------------------------------------- /assets/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | styled-components 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | elm 18 | 19 | 20 | styled 21 | 22 | 23 | 24 | 25 | [ 26 | 27 | 28 | ] 29 | 30 | 31 | 32 | 💅 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /demo/Animation.elm: -------------------------------------------------------------------------------- 1 | module Main exposing (..) 2 | 3 | import Html exposing (..) 4 | import Styled exposing (..) 5 | import Styled.Keyframes exposing (keyframes) 6 | import Styled.Transforms exposing (rotate) 7 | import Styled.Timings exposing (linear) 8 | 9 | 10 | spin = 11 | keyframes 12 | [ ( 0 13 | , [ transform (rotate (deg 0)) 14 | ] 15 | ) 16 | , ( 100 17 | , [ transform (rotate (deg 360)) 18 | ] 19 | ) 20 | ] 21 | 22 | 23 | loader = 24 | styled div 25 | [ margin (Styled.rem 2) 26 | , display inlineBlock 27 | , animationName spin 28 | , animationDuration (Styled.s 2) 29 | , animationTimingFunction linear 30 | , animationIterationCount infinite 31 | ] 32 | 33 | 34 | main = 35 | loader [] [ text "[ 💅 ]" ] 36 | -------------------------------------------------------------------------------- /demo/Basic.elm: -------------------------------------------------------------------------------- 1 | module Main exposing (..) 2 | 3 | import Html exposing (..) 4 | import Styled exposing (..) 5 | import Styled.Colors exposing (pink, lightYellow) 6 | 7 | 8 | title = 9 | styled h1 10 | [ fontSize (Styled.em 1.5) 11 | , textAlign center 12 | , color pink 13 | , fontFamily monospace 14 | ] 15 | 16 | 17 | wrapper = 18 | styled div 19 | [ padding (Styled.em 4) 20 | , backgroundColor lightYellow 21 | ] 22 | 23 | 24 | main = 25 | wrapper [] 26 | [ title [] 27 | [ text "Hello World, this is my first styled function 💅" ] 28 | ] 29 | -------------------------------------------------------------------------------- /demo/Dynamic.elm: -------------------------------------------------------------------------------- 1 | module Main exposing (..) 2 | 3 | import Html exposing (..) 4 | import Styled exposing (..) 5 | import Styled.Colors exposing (red, yellow, green) 6 | 7 | 8 | light paint = 9 | styled div 10 | [ backgroundColor paint 11 | , borderRadius (percent 50) 12 | , display inlineBlock 13 | , height (px 60) 14 | , width (px 60) 15 | , margin (px 20) 16 | ] 17 | 18 | 19 | trafficLight = 20 | div [] 21 | [ light red [] [] 22 | , light yellow [] [] 23 | , light green [] [] 24 | ] 25 | 26 | 27 | main = 28 | trafficLight 29 | -------------------------------------------------------------------------------- /demo/Overriding.elm: -------------------------------------------------------------------------------- 1 | module Main exposing (..) 2 | 3 | import Html exposing (div, text) 4 | import Styled exposing (..) 5 | import Styled.Colors exposing (white, pink) 6 | 7 | 8 | button = 9 | styled Html.button 10 | [ backgroundColor white 11 | , color pink 12 | , fontSize (Styled.em 1) 13 | , margin (Styled.em 1) 14 | , padding2 (Styled.em 0.25) (Styled.em 1) 15 | , border (px 2) solid pink 16 | , borderRadius (px 3) 17 | ] 18 | 19 | 20 | primaryButton = 21 | styled button 22 | [ backgroundColor pink 23 | , color white 24 | ] 25 | 26 | 27 | main = 28 | div 29 | [] 30 | [ button [] [ text "Normal" ] 31 | , primaryButton [] [ text "Primary" ] 32 | ] 33 | -------------------------------------------------------------------------------- /elm-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0.0", 3 | "summary": "Styling your Html elements with typed CSS in Elm", 4 | "repository": "https://github.com/styled-components/elm-styled.git", 5 | "license": "MIT", 6 | "source-directories": [ 7 | "src" 8 | ], 9 | "native-modules": true, 10 | "exposed-modules": [ 11 | "Styled", 12 | "Styled.Colors", 13 | "Styled.Cursors", 14 | "Styled.FontVariants", 15 | "Styled.Gradients", 16 | "Styled.Html", 17 | "Styled.Keyframes", 18 | "Styled.ListStyles", 19 | "Styled.Selectors", 20 | "Styled.Timings", 21 | "Styled.Transforms", 22 | "Styled.Types" 23 | ], 24 | "dependencies": { 25 | "Skinney/murmur3": "2.0.4 <= v < 3.0.0", 26 | "elm-lang/core": "5.1.1 <= v < 6.0.0", 27 | "elm-lang/html": "2.0.0 <= v < 3.0.0", 28 | "elm-lang/virtual-dom": "2.0.4 <= v < 3.0.0" 29 | }, 30 | "elm-version": "0.18.0 <= v < 0.19.0" 31 | } 32 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "elm-styled", 3 | "description": "Styling your Html elements with typed CSS in Elm", 4 | "repository": "https://github.com/styled-components/elm-styled.git", 5 | "author": "Konstantin Pschera ", 6 | "license": "MIT", 7 | "devDependencies": { 8 | "elm": "0.18.0", 9 | "elm-format": "0.5.2", 10 | "eslint": "3.18.0", 11 | "husky": "0.13.2", 12 | "jest": "19.0.2", 13 | "lint-staged": "3.4.0" 14 | }, 15 | "scripts": { 16 | "precommit": "lint-staged", 17 | "lint": "eslint {src,test} && elm-make --warn --output=/dev/null {src,test}/**/*.elm", 18 | "test": "jest" 19 | }, 20 | "jest": { 21 | "testMatch": [ 22 | "**/test/**/*.js" 23 | ] 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Internal.elm: -------------------------------------------------------------------------------- 1 | module Internal exposing (..) 2 | 3 | import Murmur3 exposing (hashString) 4 | import Styled.Types exposing (..) 5 | 6 | 7 | isDeclaration : Rule -> Bool 8 | isDeclaration rule = 9 | case rule of 10 | Declaration _ _ _ -> 11 | True 12 | 13 | _ -> 14 | False 15 | 16 | 17 | createHash : String -> a -> String 18 | createHash prefix hashable = 19 | toString hashable 20 | |> hashString 571130 21 | |> toString 22 | |> String.append (prefix ++ "-") 23 | 24 | 25 | concatDeclaration : Rule -> String 26 | concatDeclaration rule = 27 | case rule of 28 | Declaration property values important -> 29 | if important then 30 | property ++ ": " ++ (String.join " " values) ++ " !important;" 31 | else 32 | property ++ ": " ++ (String.join " " values) ++ ";" 33 | 34 | _ -> 35 | "" 36 | 37 | 38 | concatOtherRule : String -> Rule -> List String 39 | concatOtherRule parentSelector rule = 40 | case rule of 41 | Declaration _ _ _ -> 42 | List.singleton "" 43 | 44 | Selector selector rules -> 45 | createCss (parentSelector ++ selector) rules 46 | |> String.join " " 47 | |> List.singleton 48 | 49 | Media query rules -> 50 | createCss (parentSelector) rules 51 | |> String.join " " 52 | |> (\css -> 53 | "@media " 54 | ++ query 55 | ++ " { " 56 | ++ css 57 | ++ " } " 58 | ) 59 | |> List.singleton 60 | 61 | Mixin rules -> 62 | createCss parentSelector rules 63 | 64 | 65 | createCss : String -> List Rule -> List String 66 | createCss selector rules = 67 | let 68 | ( declarations, otherRules ) = 69 | List.partition isDeclaration rules 70 | 71 | declarationsCss = 72 | List.map concatDeclaration declarations 73 | |> String.join " " 74 | |> (\css -> 75 | selector 76 | ++ " { " 77 | ++ css 78 | ++ " } " 79 | ) 80 | 81 | otherRulesCss = 82 | List.concatMap (concatOtherRule selector) otherRules 83 | in 84 | declarationsCss :: otherRulesCss 85 | -------------------------------------------------------------------------------- /src/Native/Css.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-unused-vars 2 | var _styled_components$elm_styled$Native_Css = (function () { 3 | var styleTags = [] 4 | var insertedRules = {} 5 | var maxLength = 65000 6 | 7 | function stringHash(string) { 8 | var hash = 5381 9 | var index = string.length 10 | 11 | while(index) { 12 | hash = (hash * 33) ^ string.charCodeAt(--index) 13 | } 14 | 15 | return hash >>> 0 16 | } 17 | 18 | function insertStyleSheet() { 19 | // Create the