Check in packages.

This commit is contained in:
Richard Feldman
2017-10-26 03:03:03 +02:00
parent ef07ce6f52
commit b964fb9a6d
2046 changed files with 401572 additions and 101 deletions

View File

@@ -0,0 +1 @@
elm-stuff

View File

@@ -0,0 +1,27 @@
Copyright (c) 2016, Richard Feldman
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of elm-css-util nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -0,0 +1,16 @@
{
"version": "1.0.2",
"summary": "Utility functions shared by elm-css and elm-css-helpers.",
"repository": "https://github.com/rtfeldman/elm-css-util.git",
"license": "BSD-3-Clause",
"source-directories": [
"src"
],
"exposed-modules": [
"Css.Helpers"
],
"dependencies": {
"elm-lang/core": "5.0.0 <= v < 6.0.0"
},
"elm-version": "0.18.0 <= v < 0.19.0"
}

View File

@@ -0,0 +1,30 @@
module Css.Helpers exposing (toCssIdentifier, identifierToString)
{-| Utility functions for elm-css.
@docs toCssIdentifier, identifierToString
-}
import Regex
import String
{-| Converts an arbitrary value to a valid CSS identifier by calling
`toString` on it, trimming it, replacing chunks of whitespace with `-`,
and stripping out invalid characters.
-}
toCssIdentifier : a -> String
toCssIdentifier identifier =
identifier
|> toString
|> String.trim
|> Regex.replace Regex.All (Regex.regex "\\s+") (\_ -> "-")
|> Regex.replace Regex.All (Regex.regex "[^a-zA-Z0-9_-]") (\_ -> "")
{-| Converts an arbitrary identifier to a valid CSS identifier, then prepends
the given namespace.
-}
identifierToString : a -> b -> String
identifierToString name identifier =
(toCssIdentifier name) ++ (toCssIdentifier identifier)

View File

@@ -0,0 +1,3 @@
elm-stuff
node_modules
tests/homepage.css

View File

@@ -0,0 +1,28 @@
Copyright (c) 2015, Richard Feldman
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of elm-stylesheets nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -0,0 +1,43 @@
#!/usr/bin/env node
var elmCss = require('./');
var program = require('commander');
var chalk = require('chalk');
var pkg = require('./package.json');
var sourcePath = null;
program
.version(pkg.version)
.usage('elm-css PATH # path to your Stylesheets.elm file')
.option('-o, --output [outputDir]', '(optional) directory in which to write CSS file', process.cwd())
.option('-m, --module [moduleName]', '(optional) name of stylesheets module in your project', null, 'Stylesheets')
.option('-p, --port [portName]', '(optional) name of the port from which to read CSS results', null, 'files')
.option('-r, --root [projectDir]', '(optional) root directory of the project', process.cwd())
.option('-e, --pathToMake [pathToMake]', '(optional) path to elm-make')
.action(function(src) {
sourcePath = src;
})
.parse(process.argv);
if(!sourcePath) {
console.log(chalk.red("You must specifiy a path to your Stylesheets.elm file. See the README for information on how to build a Stylesheets.elm file."));
program.outputHelp();
process.exit(1);
}
elmCss(
program.root,
sourcePath,
program.output,
program.module,
program.port,
program.pathToMake
).then(function (results) {
console.log(chalk.green('Successfully generated output! The following css files were created: '));
results.forEach(function (result) {
console.log(chalk.blue('- ' + result.filename));
});
}).catch(function (error) {
console.log(chalk.red(error));
process.exit(1);
});

View File

@@ -0,0 +1,20 @@
{
"version": "7.0.0",
"summary": "CSS Preprocessor for Elm",
"repository": "https://github.com/rtfeldman/elm-css.git",
"license": "BSD-3-Clause",
"source-directories": [
"src"
],
"exposed-modules": [
"Css",
"Css.Elements",
"Css.File",
"Css.Namespace"
],
"dependencies": {
"elm-lang/core": "5.0.0 <= v < 6.0.0",
"rtfeldman/elm-css-util": "1.0.2 <= v < 2.0.0"
},
"elm-version": "0.18.0 <= v < 0.19.0"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 254 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 668 KiB

View File

@@ -0,0 +1,17 @@
{
"version": "1.0.0",
"summary": "Examples for elm-css",
"repository": "https://github.com/rtfeldman/elm-css.git",
"license": "BSD-3-Clause",
"source-directories": [
"src",
"../src"
],
"exposed-modules": [],
"dependencies": {
"elm-lang/core": "5.0.0 <= v < 6.0.0",
"rtfeldman/elm-css-helpers": "2.0.0 <= v < 3.0.0",
"rtfeldman/elm-css-util": "1.0.2 <= v < 2.0.0"
},
"elm-version": "0.18.0 <= v <= 0.18.0"
}

View File

@@ -0,0 +1,41 @@
module HomepageCss exposing (css)
import Css exposing (..)
import Css.Elements exposing (..)
import Css.Namespace exposing (namespace)
import SharedStyles exposing (..)
css =
(stylesheet << namespace homepageNamespace.name)
[ header
[ backgroundColor (rgb 90 90 90)
, boxSizing borderBox
, padding (px -80)
, boxShadow5 inset (px 2) (px 3) (px 4) (hex "333")
]
, nav
[ display inlineBlock
, paddingBottom (px 12)
]
, (.) NavLink
[ margin (px 12)
, color (rgb 255 255 255)
]
, (#) ReactiveLogo
[ display inlineBlock
, marginLeft (px 150)
, marginRight (px 80)
, verticalAlign middle
]
, (#) BuyTickets
[ padding (px 16)
, paddingLeft (px 24)
, paddingRight (px 24)
, marginLeft (px 50)
, marginRight auto
, color (rgb 255 255 255)
, backgroundColor (rgb 27 217 130)
, verticalAlign middle
]
]

View File

@@ -0,0 +1,30 @@
module HomepageView exposing (..)
import Html exposing (..)
import Html.CssHelpers exposing (..)
import Html.Attributes exposing (..)
import HomepageCss exposing (..)
import Json.Encode as Encode
import SharedStyles exposing (..)
{ id, class, classList } =
homepageNamespace
main : Html a
main =
div []
[ header []
[ img [ id ReactiveLogo, src "assets/logo.png" ] []
, nav []
navElems
, span [ id BuyTickets ]
[ text "BUY TICKETS" ]
]
, div []
[ img [ src "assets/banner.png" ] [] ]
]
navElems =
[ "SPEAKERS", "SCHEDULE", "WORKSHOPS", "VENUE", "BLOG", "CONTACT" ]
|> List.map (\name -> span [ class [ NavLink ] ] [ text name ])

View File

@@ -0,0 +1,16 @@
module SharedStyles exposing (..)
import Html.CssHelpers exposing (withNamespace)
type CssClasses
= NavLink
type CssIds
= ReactiveLogo
| BuyTickets
homepageNamespace =
withNamespace "homepage"

View File

@@ -0,0 +1,18 @@
port module Stylesheets exposing (..)
import Css.File exposing (CssFileStructure, CssCompilerProgram)
import HomepageCss as Homepage
port files : CssFileStructure -> Cmd msg
fileStructure : CssFileStructure
fileStructure =
Css.File.toFileStructure
[ ( "homepage.css", Css.File.compile [ Homepage.css ] ) ]
main : CssCompilerProgram
main =
Css.File.compiler files fileStructure

View File

@@ -0,0 +1,229 @@
var fs = require("fs");
var tmp = require("tmp");
var path = require("path");
var compile = require("node-elm-compiler").compile;
var jsEmitterFilename = "emitter.js";
var KNOWN_MODULES =
[
"Native",
"fullscreen",
"embed",
"worker",
"Basics",
"Maybe",
"List",
"Array",
"Char",
"Color",
"Transform2D",
"Text",
"Graphics",
"Debug",
"Result",
"Task",
"Signal",
"String",
"Dict",
"Json",
"Regex",
"VirtualDom",
"Html",
"Css"
];
// elmModuleName is optional, and is by default inferred based on the filename.
module.exports = function(projectDir, stylesheetsPath, outputDir, stylesheetsModule, stylesheetsPort, pathToMake) {
var originalWorkingDir = process.cwd();
process.chdir(projectDir);
return createTmpDir()
.then(function (tmpDirPath) {
return generateCssFiles(
stylesheetsPath,
path.join(tmpDirPath, jsEmitterFilename),
outputDir,
stylesheetsModule || "Stylesheets",
stylesheetsPort || "files",
pathToMake
);
})
.then(function(result) {
process.chdir(originalWorkingDir);
return result;
})
.catch(function(err) {
process.chdir(originalWorkingDir);
throw Error(err);
});
}
function createTmpDir() {
return new Promise(function (resolve, reject) {
tmp.dir(function (err, tmpDirPath) {
if (err) {
reject(err);
} else {
resolve(tmpDirPath);
}
});
});
}
function generateCssFiles(stylesheetsPath, emitterDest, outputDir, stylesheetsModule, stylesheetsPort, pathToMake) {
return emit(stylesheetsPath, emitterDest, stylesheetsModule, stylesheetsPort, pathToMake)
.then(writeResults(outputDir));
}
function emit(src, dest, stylesheetsModule, stylesheetsPort, pathToMake) {
// Compile the temporary file.
return compileEmitter(src, {output: dest, yes: true, pathToMake: pathToMake})
.then(extractCssResults(dest, stylesheetsModule, stylesheetsPort));
}
function suggestModulesNames(Elm){
return Object.keys(Elm).filter(function(key){
return KNOWN_MODULES.indexOf(key) === -1;
})
}
function missingEntryModuleMessage(stylesheetsModule, Elm){
var errorMessage = "I couldn't find the entry module " + stylesheetsModule + ".\n";
var suggestions = suggestModulesNames(Elm);
if (suggestions.length > 1){
errorMessage += "\nMaybe you meant one of these: " + suggestions.join(",");
} else if (suggestions.length === 1){
errorMessage += "\nMaybe you meant: " + suggestions;
}
errorMessage += "\nYou can pass me a different module to use with --module=<moduleName>";
return errorMessage;
}
function noPortsMessage(stylesheetsModule, stylesheetsPort){
var errorMessage = "The module " + stylesheetsModule + " doesn't expose any ports!\n";
errorMessage += "\nI was looking for a port called `" + stylesheetsPort + "` but couldn't find it!";
errorMessage += "\n\nTry adding something like";
errorMessage += `
port ${stylesheetsPort} : CssFileStructure
port ${stylesheetsPort} =
toFileStructure
[]
to ${stylesheetsModule}!
`;
return errorMessage.trim();
}
function noMatchingPortMessage(stylesheetsModule, stylesheetsPort, ports){
var errorMessage = `The module ${stylesheetsModule} has no port called ${stylesheetsPort}.\n`;
errorMessage += "\nI was looking for a port called `" + stylesheetsPort + "` but couldn't find it!";
var portKeys = Object.keys(ports);
if (portKeys.length === 1){
errorMessage += "\nHowever, I did find the port: " + portKeys[0];
errorMessage += "\nMaybe you meant that instead?";
} else {
errorMessage += "\nHowever, I did find the ports : " + Object.keys(ports).join(",");
}
errorMessage += "\n\nYou can specify which port to use by doing";
errorMessage += "\nelm-css -p <port-name>";
return errorMessage.trim();
}
/*
This is a poor man's type error. To get better error messages, might be worth
considered moving to how elm-static-site does it instead, and use Elm's compiler
for type errors!
*/
function portTypeErrorMessage(stylesheetsModule, stylesheetsPort, portValue){
var errorMessage = `
The type of the port ${stylesheetsPort} was not what I wanted!
I was expecting a List CssFileStructure but got ${typeof portValue}!
`;
return errorMessage.trim();
}
function extractCssResults(dest, stylesheetsModule, stylesheetsPort) {
return function () {
return new Promise(function (resolve, reject) {
var Elm = require(dest);
if (!(stylesheetsModule in Elm)){
return reject(missingEntryModuleMessage(stylesheetsModule, Elm));
}
var worker = Elm[stylesheetsModule].worker();
if (Object.keys(worker.ports).length === 0){
return reject(noPortsMessage(stylesheetsModule, stylesheetsPort));
}
if (!(stylesheetsPort in worker.ports)){
return reject(noMatchingPortMessage(stylesheetsModule, stylesheetsPort, worker.ports));
}
worker.ports[stylesheetsPort].subscribe(function (stylesheets) {
if (!Array.isArray(stylesheets)){
return reject(portTypeErrorMessage(stylesheetsModule, stylesheetsPort, stylesheets));
}
var failures = stylesheets.filter(function(result) {
return !result.success;
});
return failures.length > 0
? reject(reportFailures(failures))
: resolve(stylesheets);
});
});
};
}
function writeResults(outputDir) {
return function(results) {
return Promise.all(
results.map(writeResult(outputDir))
);
};
}
function writeResult(outputDir) {
return function (result) {
return new Promise(function(resolve, reject) {
fs.writeFile(path.join(outputDir, result.filename), result.content + "\n", function(err, file) {
return err ? reject(err) : resolve(result);
});
});
}
}
function reportFailures(failures) {
return "The following errors occurred during compilation:\n\n" +
failures.map(function(result) {
return result.filename + ": " + result.content;
}).join("\n\n");
}
function compileEmitter(src, options) {
return new Promise(function(resolve, reject) {
compile(src, options)
.on("close", function(exitCode) {
if (exitCode === 0) {
resolve();
} else {
reject("Errored with exit code " + exitCode);
}
});
});
}

View File

@@ -0,0 +1,46 @@
{
"name": "elm-css",
"version": "0.6.0",
"description": "Elm-based CSS Preprocessor",
"main": "index.js",
"bin": {
"elm-css": "./elm-css.js"
},
"directories": {
"test": "tests"
},
"scripts": {
"test": "elm-test && cd tests && mocha *.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/rtfeldman/elm-css.git"
},
"keywords": [
"elm",
"css",
"sass",
"less",
"preprocessor"
],
"author": "Richard Feldman <richard.t.feldman@gmail.com>",
"license": "BSD-3-Clause",
"bugs": {
"url": "https://github.com/rtfeldman/elm-css/issues"
},
"homepage": "https://github.com/rtfeldman/elm-css#readme",
"dependencies": {
"chalk": "1.1.1",
"commander": "2.9.0",
"node-elm-compiler": "2.3.2",
"tmp": "0.0.28"
},
"devDependencies": {
"chai": "3.4.1",
"mocha": "2.3.4"
},
"engineStrict": true,
"engines": {
"node": ">=4.0.0"
}
}

View File

@@ -0,0 +1,2 @@
styles.css
index.html

View File

@@ -0,0 +1,18 @@
{
"version": "1.0.0",
"summary": "helpful summary of your project, less than 80 characters",
"repository": "https://github.com/user/project.git",
"license": "BSD3",
"source-directories": [
"src",
"../src"
],
"exposed-modules": [],
"dependencies": {
"elm-lang/core": "5.0.0 <= v < 6.0.0",
"elm-lang/html": "2.0.0 <= v < 3.0.0",
"rtfeldman/elm-css-helpers": "2.0.1 <= v < 3.0.0",
"rtfeldman/elm-css-util": "1.0.2 <= v < 2.0.0"
},
"elm-version": "0.18.0 <= v < 0.19.0"
}

View File

@@ -0,0 +1,15 @@
module Main exposing (main)
import Html exposing (Html)
import MyCss
import Html.CssHelpers
{ id, class, classList } =
Html.CssHelpers.withNamespace "dreamwriter"
main : Html msg
main =
Html.div []
[ Html.div [ class [ MyCss.NavBar ] ] [ Html.text "this has the navbar class" ]
, Html.div [ id MyCss.Page ] [ Html.text "this has the Page id" ]
]

View File

@@ -0,0 +1,45 @@
module MyCss exposing (CssClasses(..), CssIds(..), css)
import Css exposing (..)
import Css.Elements exposing (body, li)
import Css.Namespace exposing (namespace)
type CssClasses
= NavBar
type CssIds
= Page
css =
(stylesheet << namespace "dreamwriter")
[ body
[ overflowX auto
, minWidth (px 1280)
]
, (#) Page
[ backgroundColor (rgb 200 128 64)
, color (hex "CCFFFF")
, width (pct 100)
, height (pct 100)
, boxSizing borderBox
, padding (px 8)
, margin zero
]
, (.) NavBar
[ margin zero
, padding zero
, children
[ li
[ (display inlineBlock) |> important
, color primaryAccentColor
]
]
]
]
primaryAccentColor =
hex "ccffaa"

View File

@@ -0,0 +1,24 @@
port module Stylesheets exposing (..)
import Css.File exposing (..)
import MyCss
import Html exposing (div)
import Html.App as Html
port files : CssFileStructure -> Cmd msg
cssFiles : CssFileStructure
cssFiles =
toFileStructure [ ( "styles.css", compile [ MyCss.css ] ) ]
main : Program Never
main =
Html.program
{ init = ( (), files cssFiles )
, view = \_ -> (div [] [])
, update = \_ _ -> ( (), Cmd.none )
, subscriptions = \_ -> Sub.none
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,131 @@
module Css.Colors exposing (navy, blue, aqua, teal, olive, green, lime, yellow, orange, red, maroon, fuchsia, purple, black, gray, silver)
{-| A nicer default set of colors than the ones CSS ships with. Color codes taken from [clrs.cc](http://clrs.cc).
import Css.Colors exposing (..)
stylesheet
[ button
[ backgroundColor blue ]
]
...compiles to:
button {
backgroundColor: #0074D9;
}
-}
import Css exposing (Color, hex)
{-| [Colors](http://clrs.cc) hex code #001F3F
-}
navy : Color
navy =
hex "001F3F"
{-| [Colors](http://clrs.cc) hex code #0074D9
-}
blue : Color
blue =
hex "0074D9"
{-| [Colors](http://clrs.cc) hex code #7FDBFF
-}
aqua : Color
aqua =
hex "7FDBFF"
{-| [Colors](http://clrs.cc) hex code #39CCCC
-}
teal : Color
teal =
hex "39CCCC"
{-| [Colors](http://clrs.cc) hex code #3D9970
-}
olive : Color
olive =
hex "3D9970"
{-| [Colors](http://clrs.cc) hex code #2ECC40
-}
green : Color
green =
hex "2ECC40"
{-| [Colors](http://clrs.cc) hex code #01FF70
-}
lime : Color
lime =
hex "01FF70"
{-| [Colors](http://clrs.cc) hex code #FFDC00
-}
yellow : Color
yellow =
hex "FFDC00"
{-| [Colors](http://clrs.cc) hex code #FF851B
-}
orange : Color
orange =
hex "FF851B"
{-| [Colors](http://clrs.cc) hex code #FF4136
-}
red : Color
red =
hex "FF4136"
{-| [Colors](http://clrs.cc) hex code #85144b
-}
maroon : Color
maroon =
hex "85144b"
{-| [Colors](http://clrs.cc) hex code #F012BE
-}
fuchsia : Color
fuchsia =
hex "F012BE"
{-| [Colors](http://clrs.cc) hex code #B10DC9
-}
purple : Color
purple =
hex "B10DC9"
{-| [Colors](http://clrs.cc) hex code #111111
-}
black : Color
black =
hex "111111"
{-| [Colors](http://clrs.cc) hex code #AAAAAA
-}
gray : Color
gray =
hex "AAAAAA"
{-| [Colors](http://clrs.cc) hex code #dddddd
-}
silver : Color
silver =
hex "dddddd"

View File

@@ -0,0 +1,419 @@
module Css.Elements exposing (html, body, article, header, footer, h1, h2, h3, h4, h5, h6, nav, section, div, hr, li, main_, ol, p, ul, pre, a, code, small, span, strong, img, audio, video, canvas, caption, col, colgroup, table, tbody, td, tfoot, th, thead, tr, button, fieldset, form, input, label, legend, optgroup, option, progress, select)
{-| Selectors for HTML elements.
# Basic elements
@docs html, body
# Content sectioning
@docs article, header, footer, h1, h2, h3, h4, h5, h6, nav, section
# Text content
@docs div, hr, li, main_, ol, p, ul, pre
# Inline text semantics
@docs a, code, small, span, strong
# Image and multimedia
@docs img, audio, video, canvas
# Table content
@docs caption, col, colgroup, table, tbody, td, tfoot, th, thead, tr
# Forms
@docs button, fieldset, form, input, label, legend, optgroup, option, progress, select
-}
import Css.Preprocess exposing (Mixin, Snippet(Snippet), StyleBlock(StyleBlock), SnippetDeclaration(StyleBlockDeclaration))
import Css.Structure as Structure
typeSelector : String -> List Mixin -> Snippet
typeSelector selectorStr mixins =
let
sequence =
Structure.TypeSelectorSequence (Structure.TypeSelector selectorStr) []
selector =
Structure.Selector sequence [] Nothing
in
[ StyleBlockDeclaration (StyleBlock selector [] mixins) ]
|> Snippet
{- BASIC ELEMENTS -}
{-| Selector for a html element.
-}
html : List Mixin -> Snippet
html =
typeSelector "html"
{-| Selector for a body element.
-}
body : List Mixin -> Snippet
body =
typeSelector "body"
{- CONTENT SECTIONING -}
{-| Selector for an article element.
-}
article : List Mixin -> Snippet
article =
typeSelector "article"
{-| Selector for a header element.
-}
header : List Mixin -> Snippet
header =
typeSelector "header"
{-| Selector for a footer element.
-}
footer : List Mixin -> Snippet
footer =
typeSelector "footer"
{-| Selector for an h1 element.
-}
h1 : List Mixin -> Snippet
h1 =
typeSelector "h1"
{-| Selector for an h2 element.
-}
h2 : List Mixin -> Snippet
h2 =
typeSelector "h2"
{-| Selector for an h3 element.
-}
h3 : List Mixin -> Snippet
h3 =
typeSelector "h3"
{-| Selector for an h4 element.
-}
h4 : List Mixin -> Snippet
h4 =
typeSelector "h4"
{-| Selector for an h5 element.
-}
h5 : List Mixin -> Snippet
h5 =
typeSelector "h5"
{-| Selector for an h6 element.
-}
h6 : List Mixin -> Snippet
h6 =
typeSelector "h6"
{-| Selector for a nav element.
-}
nav : List Mixin -> Snippet
nav =
typeSelector "nav"
{-| Selector for a section element.
-}
section : List Mixin -> Snippet
section =
typeSelector "section"
{- TEXT CONTENT -}
{-| Selector for a div element.
-}
div : List Mixin -> Snippet
div =
typeSelector "div"
{-| Selector for an hr element.
-}
hr : List Mixin -> Snippet
hr =
typeSelector "hr"
{-| Selector for an li element.
-}
li : List Mixin -> Snippet
li =
typeSelector "li"
{-| Selector for a main element.
-}
main_ : List Mixin -> Snippet
main_ =
typeSelector "main"
{-| Selector for an ol element.
-}
ol : List Mixin -> Snippet
ol =
typeSelector "ol"
{-| Selector for a p element.
-}
p : List Mixin -> Snippet
p =
typeSelector "p"
{-| Selector for a ul element.
-}
ul : List Mixin -> Snippet
ul =
typeSelector "ul"
{-| Selector for a pre element.
-}
pre : List Mixin -> Snippet
pre =
typeSelector "pre"
{- INLINE TEXT SEMANTICS -}
{-| Selector for an `<a>` element.
-}
a : List Mixin -> Snippet
a =
typeSelector "a"
{-| Selector for a code element.
-}
code : List Mixin -> Snippet
code =
typeSelector "code"
{-| Selector for a small element.
-}
small : List Mixin -> Snippet
small =
typeSelector "small"
{-| Selector for a span element.
-}
span : List Mixin -> Snippet
span =
typeSelector "span"
{-| Selector for a strong element.
-}
strong : List Mixin -> Snippet
strong =
typeSelector "strong"
{- IMAGE AND MULTIMEDIA -}
{-| Selector for a img element.
-}
img : List Mixin -> Snippet
img =
typeSelector "img"
{-| Selector for an audio element.
-}
audio : List Mixin -> Snippet
audio =
typeSelector "audio"
{-| Selector for a video element.
-}
video : List Mixin -> Snippet
video =
typeSelector "video"
{-| Selector for a canvas element.
-}
canvas : List Mixin -> Snippet
canvas =
typeSelector "canvas"
{- TABLE CONTENT -}
{-| Selector for a caption element.
-}
caption : List Mixin -> Snippet
caption =
typeSelector "caption"
{-| Selector for a col element.
-}
col : List Mixin -> Snippet
col =
typeSelector "col"
{-| Selector for a colgroup element.
-}
colgroup : List Mixin -> Snippet
colgroup =
typeSelector "colgroup"
{-| Selector for a table element.
-}
table : List Mixin -> Snippet
table =
typeSelector "table"
{-| Selector for a tbody element.
-}
tbody : List Mixin -> Snippet
tbody =
typeSelector "tbody"
{-| Selector for a td element.
-}
td : List Mixin -> Snippet
td =
typeSelector "td"
{-| Selector for a tfoot element.
-}
tfoot : List Mixin -> Snippet
tfoot =
typeSelector "tfoot"
{-| Selector for a th element.
-}
th : List Mixin -> Snippet
th =
typeSelector "th"
{-| Selector for a thead element.
-}
thead : List Mixin -> Snippet
thead =
typeSelector "thead"
{-| Selector for a thead element.
-}
tr : List Mixin -> Snippet
tr =
typeSelector "tr"
{- FORMS -}
{-| Selector for a button element.
-}
button : List Mixin -> Snippet
button =
typeSelector "button"
{-| Selector for a fieldset element.
-}
fieldset : List Mixin -> Snippet
fieldset =
typeSelector "fieldset"
{-| Selector for a form element.
-}
form : List Mixin -> Snippet
form =
typeSelector "form"
{-| Selector for an input element.
-}
input : List Mixin -> Snippet
input =
typeSelector "input"
{-| Selector for a label element.
-}
label : List Mixin -> Snippet
label =
typeSelector "label"
{-| Selector for a legend element.
-}
legend : List Mixin -> Snippet
legend =
typeSelector "legend"
{-| Selector for an optgroup element.
-}
optgroup : List Mixin -> Snippet
optgroup =
typeSelector "optgroup"
{-| Selector for an option element.
-}
option : List Mixin -> Snippet
option =
typeSelector "option"
{-| Selector for a progress element.
-}
progress : List Mixin -> Snippet
progress =
typeSelector "progress"
{-| Selector for a select element.
-}
select : List Mixin -> Snippet
select =
typeSelector "select"

View File

@@ -0,0 +1,75 @@
module Css.File exposing (compile, compiler, toFileStructure, CssFileStructure, CssCompilerProgram)
{-| Functions for writing CSS files from elm-css.
@docs compile, compiler, toFileStructure, CssFileStructure, CssCompilerProgram
-}
import Css exposing (Stylesheet)
{-| A description of CSS files that will be created by elm-css.
-}
type alias CssFileStructure =
List
{ filename : String
, content : String
, success : Bool
}
{-| Translate a list of filenames and [`prettyPrint`](#prettyPrint) results
to a list of tuples suitable for being sent to a port in a Stylesheets.elm file.
-}
toFileStructure : List ( String, { css : String, warnings : List String } ) -> CssFileStructure
toFileStructure stylesheets =
let
asTuple ( filename, { css, warnings } ) =
{ success = List.isEmpty warnings, filename = filename, content = css }
in
List.map asTuple stylesheets
{-| Convenience re-export of Css.compile
-}
compile : List Stylesheet -> { css : String, warnings : List String }
compile =
Css.compile
{-| Create a program that compiles an elm-css stylesheet to a CSS file.
port module Stylesheets exposing (..)
import Css.File exposing (CssFileStructure, CssCompilerProgram)
import HomepageCss as Homepage
port files : CssFileStructure -> Cmd msg
fileStructure : CssFileStructure
fileStructure =
Css.File.toFileStructure
[ ( "homepage.css", Css.File.compile [ Homepage.css ] ) ]
main : CssCompilerProgram
main =
Css.File.compiler files fileStructure
-}
compiler : (CssFileStructure -> Cmd Never) -> CssFileStructure -> CssCompilerProgram
compiler filesPort structure =
Platform.program
{ init = ( (), filesPort structure )
, update = \_ _ -> ( (), Cmd.none )
, subscriptions = \_ -> Sub.none
}
{-| A prorgam that compiles a CSS file.
See [`compiler`](#compiler).
-}
type alias CssCompilerProgram =
Program Never () Never

View File

@@ -0,0 +1,148 @@
module Css.Namespace exposing (namespace)
{-| Namespacing
@docs namespace
-}
import Css.Helpers exposing (toCssIdentifier, identifierToString)
import Css.Preprocess as Preprocess exposing (SnippetDeclaration, Snippet(Snippet), Mixin(AppendProperty, ExtendSelector, NestSnippet), unwrapSnippet)
import Css.Structure as Structure exposing (mapLast, SimpleSelectorSequence(UniversalSelectorSequence, TypeSelectorSequence, CustomSelector), RepeatableSimpleSelector(IdSelector, ClassSelector, PseudoClassSelector))
{-|
takes an identifier, namespaces the list of snippets given with that identifier
-}
namespace : a -> List Snippet -> List Snippet
namespace rawIdentifier snippets =
List.map (applyNamespaceToSnippet (toCssIdentifier rawIdentifier)) snippets
applyNamespaceToRepeatable : String -> RepeatableSimpleSelector -> RepeatableSimpleSelector
applyNamespaceToRepeatable name selector =
case selector of
ClassSelector str ->
ClassSelector (name ++ str)
IdSelector str ->
IdSelector str
PseudoClassSelector str ->
PseudoClassSelector str
applyNamespaceToSequence : String -> SimpleSelectorSequence -> SimpleSelectorSequence
applyNamespaceToSequence name sequence =
case sequence of
TypeSelectorSequence selector repeatables ->
TypeSelectorSequence selector (List.map (applyNamespaceToRepeatable name) repeatables)
UniversalSelectorSequence repeatables ->
UniversalSelectorSequence (List.map (applyNamespaceToRepeatable name) repeatables)
CustomSelector str repeatables ->
CustomSelector str (List.map (applyNamespaceToRepeatable name) repeatables)
applyNamespaceToSelector : String -> Structure.Selector -> Structure.Selector
applyNamespaceToSelector name (Structure.Selector sequence chain pseudoElement) =
let
apply =
applyNamespaceToSequence name
in
Structure.Selector (apply sequence)
(List.map (\( combinator, next ) -> ( combinator, apply next )) chain)
pseudoElement
applyNamespaceToMixin : String -> Mixin -> Mixin
applyNamespaceToMixin name mixin =
case mixin of
Preprocess.AppendProperty property ->
applyNamespaceToProperty name property
|> Preprocess.AppendProperty
Preprocess.ExtendSelector selector mixins ->
List.map (applyNamespaceToMixin name) mixins
|> Preprocess.ExtendSelector (applyNamespaceToRepeatable name selector)
Preprocess.NestSnippet combinator snippets ->
List.map (applyNamespaceToSnippet name) snippets
|> Preprocess.NestSnippet combinator
Preprocess.WithPseudoElement pseudoElement mixins ->
List.map (applyNamespaceToMixin name) mixins
|> Preprocess.WithPseudoElement pseudoElement
Preprocess.WithMedia mediaQueries mixins ->
List.map (applyNamespaceToMixin name) mixins
|> Preprocess.WithMedia mediaQueries
Preprocess.ApplyMixins mixins ->
List.map (applyNamespaceToMixin name) mixins
|> Preprocess.ApplyMixins
applyNamespaceToProperty : String -> Preprocess.Property -> Preprocess.Property
applyNamespaceToProperty name property =
case property.key of
"animation-name" ->
{ property | value = name ++ property.value }
_ ->
property
applyNamespaceToStyleBlock : String -> Preprocess.StyleBlock -> Preprocess.StyleBlock
applyNamespaceToStyleBlock name (Preprocess.StyleBlock firstSelector otherSelectors mixins) =
Preprocess.StyleBlock (applyNamespaceToSelector name firstSelector)
(List.map (applyNamespaceToSelector name) otherSelectors)
(List.map (applyNamespaceToMixin name) mixins)
applyNamespaceToSnippet : String -> Snippet -> Snippet
applyNamespaceToSnippet name (Snippet declarations) =
List.map (applyNamespaceToDeclaration name) declarations
|> Snippet
applyNamespaceToDeclaration : String -> SnippetDeclaration -> SnippetDeclaration
applyNamespaceToDeclaration name declaration =
case declaration of
Preprocess.StyleBlockDeclaration styleBlock ->
applyNamespaceToStyleBlock name styleBlock
|> Preprocess.StyleBlockDeclaration
Preprocess.MediaRule mediaQueries styleBlocks ->
styleBlocks
|> List.map (applyNamespaceToStyleBlock name)
|> Preprocess.MediaRule mediaQueries
Preprocess.SupportsRule str snippets ->
snippets
|> List.concatMap unwrapSnippet
|> List.map (applyNamespaceToDeclaration name)
|> (\declarations -> [ Snippet declarations ])
|> Preprocess.SupportsRule str
-- TODO give these more descritpive names
Preprocess.DocumentRule str1 str2 str3 str4 styleBlock ->
applyNamespaceToStyleBlock name styleBlock
|> Preprocess.DocumentRule str1 str2 str3 str4
Preprocess.PageRule _ _ ->
declaration
Preprocess.FontFace _ ->
declaration
Preprocess.Keyframes str properties ->
Preprocess.Keyframes (name ++ str) properties
Preprocess.Viewport _ ->
declaration
Preprocess.CounterStyle _ ->
declaration
Preprocess.FontFeatureValues _ ->
declaration

View File

@@ -0,0 +1,165 @@
module Css.Preprocess exposing (..)
{-| A representation of the preprocessing to be done. The elm-css DSL generates
the data structures found in this module.
-}
import Css.Structure as Structure exposing (mapLast, concatMapLast)
stylesheet : List Snippet -> Stylesheet
stylesheet snippets =
{ charset = Nothing
, imports = []
, namespaces = []
, snippets = snippets
}
type alias Property =
{ key : String
, value : String
, important : Bool
, warnings : List String
}
type alias Stylesheet =
{ charset : Maybe String
, imports : List ( String, List Structure.MediaQuery )
, namespaces : List ( String, String )
, snippets : List Snippet
}
type Mixin
= AppendProperty Property
| ExtendSelector Structure.RepeatableSimpleSelector (List Mixin)
| NestSnippet Structure.SelectorCombinator (List Snippet)
| WithPseudoElement Structure.PseudoElement (List Mixin)
| WithMedia (List Structure.MediaQuery) (List Mixin)
| ApplyMixins (List Mixin)
type Snippet
= Snippet (List SnippetDeclaration)
type SnippetDeclaration
= StyleBlockDeclaration StyleBlock
| MediaRule (List Structure.MediaQuery) (List StyleBlock)
| SupportsRule String (List Snippet)
| DocumentRule String String String String StyleBlock
| PageRule String (List Property)
| FontFace (List Property)
| Keyframes String (List Structure.KeyframeProperty)
| Viewport (List Property)
| CounterStyle (List Property)
| FontFeatureValues (List ( String, List Property ))
type StyleBlock
= StyleBlock Structure.Selector (List Structure.Selector) (List Mixin)
toMediaRule : List Structure.MediaQuery -> Structure.Declaration -> Structure.Declaration
toMediaRule mediaQueries declaration =
case declaration of
Structure.StyleBlockDeclaration structureStyleBlock ->
Structure.MediaRule mediaQueries [ structureStyleBlock ]
Structure.MediaRule newMediaQueries structureStyleBlocks ->
Structure.MediaRule (mediaQueries ++ newMediaQueries) structureStyleBlocks
Structure.SupportsRule str declarations ->
Structure.SupportsRule str (List.map (toMediaRule mediaQueries) declarations)
-- TODO give these more descriptive names
Structure.DocumentRule str1 str2 str3 str4 structureStyleBlock ->
Structure.DocumentRule str1 str2 str3 str4 structureStyleBlock
Structure.PageRule _ _ ->
declaration
Structure.FontFace _ ->
declaration
Structure.Keyframes _ _ ->
declaration
Structure.Viewport _ ->
declaration
Structure.CounterStyle _ ->
declaration
Structure.FontFeatureValues _ ->
declaration
mapLastProperty : (Property -> Property) -> Mixin -> Mixin
mapLastProperty update mixin =
case mixin of
AppendProperty property ->
AppendProperty (update property)
ExtendSelector selector mixins ->
ExtendSelector selector (mapAllLastProperty update mixins)
NestSnippet _ _ ->
mixin
WithPseudoElement _ _ ->
mixin
WithMedia _ _ ->
mixin
ApplyMixins otherMixins ->
ApplyMixins (mapLast (mapLastProperty update) otherMixins)
mapAllLastProperty : (Property -> Property) -> List Mixin -> List Mixin
mapAllLastProperty update mixins =
case mixins of
[] ->
mixins
only :: [] ->
[ mapLastProperty update only ]
first :: rest ->
first :: mapAllLastProperty update rest
unwrapSnippet : Snippet -> List SnippetDeclaration
unwrapSnippet (Snippet declarations) =
declarations
toPropertyPairs : List Mixin -> List ( String, String )
toPropertyPairs mixins =
case mixins of
[] ->
[]
(AppendProperty property) :: rest ->
(propertyToPair property) :: (toPropertyPairs rest)
(ApplyMixins mixins) :: rest ->
(toPropertyPairs mixins) ++ (toPropertyPairs rest)
_ :: rest ->
toPropertyPairs rest
propertyToPair : Property -> ( String, String )
propertyToPair property =
let
value =
if property.important then
property.value ++ " !important"
else
property.value
in
( property.key, value )

View File

@@ -0,0 +1,544 @@
module Css.Preprocess.Resolve exposing (compile)
{-| Functions responsible for resolving Preprocess data structures into
Structure data structures and gathering warnings along the way.
-}
import String
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
import Tuple
compile : List Preprocess.Stylesheet -> { warnings : List String, css : String }
compile styles =
let
results =
List.map compile1 styles
in
{ warnings = List.concatMap .warnings results
, css = String.join "\n\n" (List.map .css results)
}
compile1 : Preprocess.Stylesheet -> { warnings : List String, css : String }
compile1 sheet =
let
( structureStylesheet, warnings ) =
toStructure sheet
in
{ warnings = warnings
, css = Output.prettyPrint (Structure.dropEmpty structureStylesheet)
}
type alias DeclarationsAndWarnings =
{ declarations : List Structure.Declaration
, warnings : List String
}
resolveMediaRule : List Structure.MediaQuery -> List Preprocess.StyleBlock -> DeclarationsAndWarnings
resolveMediaRule mediaQueries styleBlocks =
let
handleStyleBlock : Preprocess.StyleBlock -> DeclarationsAndWarnings
handleStyleBlock styleBlock =
let
{ declarations, warnings } =
expandStyleBlock styleBlock
in
{ declarations = List.map (toMediaRule mediaQueries) declarations
, warnings = warnings
}
results =
List.map handleStyleBlock styleBlocks
in
{ warnings = List.concatMap .warnings results
, declarations = List.concatMap .declarations results
}
resolveSupportsRule : String -> List Snippet -> DeclarationsAndWarnings
resolveSupportsRule str snippets =
let
{ declarations, warnings } =
extract (List.concatMap unwrapSnippet snippets)
in
{ declarations = [ Structure.SupportsRule str declarations ]
, warnings = warnings
}
resolveDocumentRule : String -> String -> String -> String -> Preprocess.StyleBlock -> DeclarationsAndWarnings
resolveDocumentRule str1 str2 str3 str4 styleBlock =
-- TODO give these more descriptive names
let
{ declarations, warnings } =
expandStyleBlock styleBlock
in
{ declarations =
List.map (toDocumentRule str1 str2 str3 str4) declarations
, warnings = warnings
}
toMediaRule : List Structure.MediaQuery -> Structure.Declaration -> Structure.Declaration
toMediaRule mediaQueries declaration =
case declaration of
Structure.StyleBlockDeclaration structureStyleBlock ->
Structure.MediaRule mediaQueries [ structureStyleBlock ]
Structure.MediaRule newMediaQueries structureStyleBlocks ->
Structure.MediaRule (mediaQueries ++ newMediaQueries) structureStyleBlocks
Structure.SupportsRule str declarations ->
Structure.SupportsRule str (List.map (toMediaRule mediaQueries) declarations)
-- TODO give these more descriptive names
Structure.DocumentRule str1 str2 str3 str4 structureStyleBlock ->
Structure.DocumentRule str1 str2 str3 str4 structureStyleBlock
Structure.PageRule _ _ ->
declaration
Structure.FontFace _ ->
declaration
Structure.Keyframes _ _ ->
declaration
Structure.Viewport _ ->
declaration
Structure.CounterStyle _ ->
declaration
Structure.FontFeatureValues _ ->
declaration
resolvePageRule : String -> List Preprocess.Property -> DeclarationsAndWarnings
resolvePageRule str pageRuleProperties =
let
( warnings, properties ) =
extractWarnings pageRuleProperties
in
{ declarations = [ Structure.PageRule str properties ]
, warnings = warnings
}
resolveFontFace : List Preprocess.Property -> DeclarationsAndWarnings
resolveFontFace fontFaceProperties =
let
( warnings, properties ) =
extractWarnings fontFaceProperties
in
{ declarations = [ Structure.FontFace properties ]
, warnings = warnings
}
resolveKeyframes : String -> List Structure.KeyframeProperty -> DeclarationsAndWarnings
resolveKeyframes str properties =
{ declarations = [ Structure.Keyframes str properties ]
, warnings = []
}
resolveViewport : List Preprocess.Property -> DeclarationsAndWarnings
resolveViewport viewportProperties =
let
( warnings, properties ) =
extractWarnings viewportProperties
in
{ declarations = [ Structure.Viewport properties ]
, warnings = warnings
}
resolveCounterStyle : List Preprocess.Property -> DeclarationsAndWarnings
resolveCounterStyle counterStyleProperties =
let
( warnings, properties ) =
extractWarnings counterStyleProperties
in
{ declarations = [ Structure.Viewport properties ]
, warnings = warnings
}
resolveFontFeatureValues : List ( String, List Preprocess.Property ) -> DeclarationsAndWarnings
resolveFontFeatureValues tuples =
let
expandTuples tuplesToExpand =
case tuplesToExpand of
[] ->
( [], [] )
( str, tupleProperties ) :: rest ->
let
( warnings, properties ) =
extractWarnings tupleProperties
( nextWarnings, nextTuples ) =
expandTuples rest
in
( warnings ++ nextWarnings, ( str, properties ) :: nextTuples )
( warnings, newTuples ) =
expandTuples tuples
in
{ declarations = [ Structure.FontFeatureValues newTuples ]
, warnings = warnings
}
toDeclarations : SnippetDeclaration -> DeclarationsAndWarnings
toDeclarations snippetDeclaration =
case snippetDeclaration of
Preprocess.StyleBlockDeclaration styleBlock ->
expandStyleBlock styleBlock
Preprocess.MediaRule mediaQueries styleBlocks ->
resolveMediaRule mediaQueries styleBlocks
Preprocess.SupportsRule str snippets ->
resolveSupportsRule str snippets
-- TODO give these more descriptive names
Preprocess.DocumentRule str1 str2 str3 str4 styleBlock ->
resolveDocumentRule str1 str2 str3 str4 styleBlock
Preprocess.PageRule str pageRuleProperties ->
resolvePageRule str pageRuleProperties
Preprocess.FontFace fontFaceProperties ->
resolveFontFace fontFaceProperties
Preprocess.Keyframes str properties ->
resolveKeyframes str properties
Preprocess.Viewport viewportProperties ->
resolveViewport viewportProperties
Preprocess.CounterStyle counterStyleProperties ->
resolveCounterStyle counterStyleProperties
Preprocess.FontFeatureValues tuples ->
resolveFontFeatureValues tuples
concatDeclarationsAndWarnings : List DeclarationsAndWarnings -> DeclarationsAndWarnings
concatDeclarationsAndWarnings declarationsAndWarnings =
case declarationsAndWarnings of
[] ->
{ declarations = []
, warnings = []
}
{ declarations, warnings } :: rest ->
let
result =
concatDeclarationsAndWarnings rest
in
{ declarations = declarations ++ result.declarations
, warnings = warnings ++ result.warnings
}
extract : List SnippetDeclaration -> DeclarationsAndWarnings
extract snippetDeclarations =
case snippetDeclarations of
[] ->
{ declarations = [], warnings = [] }
first :: rest ->
let
nextResult =
extract rest
{ declarations, warnings } =
toDeclarations first
in
{ declarations = declarations ++ nextResult.declarations
, warnings = warnings ++ nextResult.warnings
}
applyMixins : List Mixin -> List Structure.Declaration -> DeclarationsAndWarnings
applyMixins mixins declarations =
case mixins of
[] ->
{ declarations = declarations, warnings = [] }
(AppendProperty propertyToAppend) :: rest ->
let
( warnings, property ) =
extractWarning propertyToAppend
result =
declarations
|> Structure.appendProperty property
|> applyMixins rest
in
{ declarations = result.declarations
, warnings = warnings ++ result.warnings
}
(ExtendSelector selector nestedMixins) :: rest ->
applyNestedMixinsToLast
nestedMixins
rest
(Structure.appendRepeatableToLastSelector selector)
declarations
(NestSnippet selectorCombinator snippets) :: rest ->
let
chain : Structure.Selector -> Structure.Selector -> Structure.Selector
chain (Structure.Selector originalSequence originalTuples originalPseudoElement) (Structure.Selector newSequence newTuples newPseudoElement) =
Structure.Selector originalSequence
(originalTuples ++ (( selectorCombinator, newSequence ) :: newTuples))
(oneOf [ newPseudoElement, originalPseudoElement ])
expandDeclaration : SnippetDeclaration -> DeclarationsAndWarnings
expandDeclaration declaration =
case declaration of
Preprocess.StyleBlockDeclaration (Preprocess.StyleBlock firstSelector otherSelectors nestedMixins) ->
let
newSelectors =
(collectSelectors declarations)
|> List.concatMap (\originalSelector -> List.map (chain originalSelector) (firstSelector :: otherSelectors))
newDeclarations =
case newSelectors of
[] ->
[]
first :: rest ->
[ Structure.StyleBlockDeclaration (Structure.StyleBlock first rest [])
]
in
[ applyMixins nestedMixins newDeclarations ]
|> concatDeclarationsAndWarnings
Preprocess.MediaRule mediaQueries styleBlocks ->
resolveMediaRule mediaQueries styleBlocks
Preprocess.SupportsRule str snippets ->
resolveSupportsRule str snippets
-- TODO give these more descriptive names
Preprocess.DocumentRule str1 str2 str3 str4 styleBlock ->
resolveDocumentRule str1 str2 str3 str4 styleBlock
Preprocess.PageRule str pageRuleProperties ->
resolvePageRule str pageRuleProperties
Preprocess.FontFace fontFaceProperties ->
resolveFontFace fontFaceProperties
Preprocess.Keyframes str properties ->
resolveKeyframes str properties
Preprocess.Viewport viewportProperties ->
resolveViewport viewportProperties
Preprocess.CounterStyle counterStyleProperties ->
resolveCounterStyle counterStyleProperties
Preprocess.FontFeatureValues tuples ->
resolveFontFeatureValues tuples
in
snippets
|> List.concatMap unwrapSnippet
|> List.map expandDeclaration
|> (++) [ applyMixins rest declarations ]
|> concatDeclarationsAndWarnings
(Preprocess.WithPseudoElement pseudoElement nestedMixins) :: rest ->
applyNestedMixinsToLast
nestedMixins
rest
(Structure.appendPseudoElementToLastSelector pseudoElement)
declarations
(Preprocess.WithMedia mediaQueries nestedMixins) :: rest ->
let
newDeclarations =
case collectSelectors declarations of
[] ->
[]
firstSelector :: otherSelectors ->
[ [ Structure.StyleBlock firstSelector otherSelectors [] ]
|> Structure.MediaRule mediaQueries
]
in
[ applyMixins rest declarations
, applyMixins nestedMixins newDeclarations
]
|> concatDeclarationsAndWarnings
(Preprocess.ApplyMixins otherMixins) :: rest ->
declarations
|> applyMixins (otherMixins ++ rest)
{- To apply nested mixins to a list of declarations, the following flow is used:
* initialResult: we pop off the last declaration, and run function `f` that appends the nested selector to it using `mapLast handleInitial`.
* nextResult: we pop off the last declaration, and resolve the rest of the remaining children
At the end, we rebuild the declarations using
* current `declarations`
* declarations of the nested selector, __without__ the last declaration that we popped off (to avoid duplicates inside the variable `declarations`)
* the declarations of the rest, __without__ the last declaration that we popped off.
This is done in order to facilitate multiple `ExtendSelectors` inside a single `StyleBlock`.
-}
applyNestedMixinsToLast : List Mixin -> List Mixin -> (Structure.StyleBlock -> List Structure.StyleBlock) -> List Structure.Declaration -> DeclarationsAndWarnings
applyNestedMixinsToLast nestedMixins rest f declarations =
let
handleInitial declarationsAndWarnings =
let
result =
applyMixins nestedMixins declarationsAndWarnings.declarations
in
{ warnings = declarationsAndWarnings.warnings ++ result.warnings
, declarations = result.declarations
}
initialResult =
lastDeclaration declarations
|> Maybe.map insertMixinsToNestedDecl
|> Maybe.withDefault { warnings = [], declarations = [] }
insertMixinsToNestedDecl lastDecl =
Structure.concatMapLastStyleBlock f lastDecl
|> List.map (\declaration -> { declarations = [ declaration ], warnings = [] })
|> mapLast handleInitial
|> concatDeclarationsAndWarnings
nextResult =
lastDeclaration declarations
|> Maybe.withDefault []
|> applyMixins rest
withoutParent decls =
List.tail decls
|> Maybe.withDefault []
{- We recreate the declarations if necessary. It is possible that
there was an `AppendProperty` in between two `ExtendSelectors` or two `WithPseudoElements`
or an `AppendProperty` after an `ExtendSelector` or `WithPseudoElement`.
-}
newDeclarations =
case ( List.head nextResult.declarations, List.head <| List.reverse declarations ) of
( Just nextResultParent, Just originalParent ) ->
List.take (List.length declarations - 1) declarations
++ [ if originalParent /= nextResultParent then
nextResultParent
else
originalParent
]
_ ->
declarations
in
{ warnings = initialResult.warnings ++ nextResult.warnings
, declarations = newDeclarations ++ (withoutParent initialResult.declarations) ++ (withoutParent nextResult.declarations)
}
lastDeclaration : List Structure.Declaration -> Maybe (List Structure.Declaration)
lastDeclaration declarations =
case declarations of
[] ->
Nothing
x :: [] ->
Just [ x ]
_ :: xs ->
lastDeclaration xs
expandStyleBlock : Preprocess.StyleBlock -> DeclarationsAndWarnings
expandStyleBlock (Preprocess.StyleBlock firstSelector otherSelectors mixins) =
[ Structure.StyleBlockDeclaration (Structure.StyleBlock firstSelector otherSelectors []) ]
|> applyMixins mixins
toStructure : Preprocess.Stylesheet -> ( Structure.Stylesheet, List String )
toStructure { charset, imports, namespaces, snippets } =
let
{ warnings, declarations } =
snippets
|> List.concatMap unwrapSnippet
|> extract
in
( { charset = charset
, imports = imports
, namespaces = namespaces
, declarations = declarations
}
, warnings
)
toDocumentRule : String -> String -> String -> String -> Structure.Declaration -> Structure.Declaration
toDocumentRule str1 str2 str3 str4 declaration =
case declaration of
Structure.StyleBlockDeclaration structureStyleBlock ->
Structure.DocumentRule str1 str2 str3 str4 structureStyleBlock
_ ->
-- TODO do something more interesting here?
declaration
extractWarnings : List Preprocess.Property -> ( List String, List Structure.Property )
extractWarnings properties =
( List.concatMap .warnings properties
, List.map (\prop -> Tuple.second (extractWarning prop)) properties
)
extractWarning : Preprocess.Property -> ( List String, Structure.Property )
extractWarning { warnings, key, value, important } =
( warnings, { key = key, value = value, important = important } )
collectSelectors : List Structure.Declaration -> List Structure.Selector
collectSelectors declarations =
case declarations of
[] ->
[]
(Structure.StyleBlockDeclaration (Structure.StyleBlock firstSelector otherSelectors _)) :: rest ->
(firstSelector :: otherSelectors) ++ (collectSelectors rest)
_ :: rest ->
collectSelectors rest
oneOf : List (Maybe a) -> Maybe a
oneOf maybes =
case maybes of
[] ->
Nothing
maybe :: rest ->
case maybe of
Nothing ->
oneOf rest
Just _ ->
maybe

View File

@@ -0,0 +1,467 @@
module Css.Structure exposing (..)
{-| A representation of the structure of a stylesheet. This module is concerned
solely with representing valid stylesheets; it is not concerned with the
elm-css DSL, collecting warnings, or
-}
{-| A property consisting of a key, a value, and a flag for whether or not
the property is `!important`.
-}
type alias Property =
{ important : Bool
, key : String
, value : String
}
{-| A stylesheet. Since they follow such specific rules, the following at-rules
are specified once rather than intermingled with normal declarations:
* [`@charset`](https://developer.mozilla.org/en-US/docs/Web/CSS/@charset)
* [`@import`](https://developer.mozilla.org/en-US/docs/Web/CSS/@import)
* [`@namespace`](https://developer.mozilla.org/en-US/docs/Web/CSS/@namespace)
-}
type alias Stylesheet =
{ charset : Maybe String
, imports : List ( String, List MediaQuery )
, namespaces : List ( String, String )
, declarations : List Declaration
}
{-| A Declaration, meaning either a [`StyleBlock`](#StyleBlock) declaration
or an [at-rule](https://developer.mozilla.org/en-US/docs/Web/CSS/At-rule)
declaration. Since each at-rule works differently, the supported ones are
enumerated as follows.
* `MediaRule`: an [`@media`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media) rule.
* `SupportsRule`: an [`@supports`](https://developer.mozilla.org/en-US/docs/Web/CSS/@supports) rule.
* `DocumentRule`: an [`@document`](https://developer.mozilla.org/en-US/docs/Web/CSS/@document) rule.
* `PageRule`: an [`@page`](https://developer.mozilla.org/en-US/docs/Web/CSS/@page) rule.
* `FontFace`: an [`@font-face`](https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face) rule.
* `Keyframes`: an [`@keyframes`](https://developer.mozilla.org/en-US/docs/Web/CSS/@keyframes) rule.
* `Viewport`: an [`@viewport`](https://developer.mozilla.org/en-US/docs/Web/CSS/@viewport) rule.
* `CounterStyle`: an [`@counter-style`](https://developer.mozilla.org/en-US/docs/Web/CSS/@counter-style) rule.
* `FontFeatureValues`: an [`@font-feature-values`](https://developer.mozilla.org/en-US/docs/Web/CSS/@font-feature-values) rule.
-}
type Declaration
= StyleBlockDeclaration StyleBlock
| MediaRule (List MediaQuery) (List StyleBlock)
| SupportsRule String (List Declaration)
| 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 ))
{-| One or more selectors followed by their properties.
-}
type StyleBlock
= StyleBlock Selector (List Selector) (List Property)
{-| A media query.
-}
type MediaQuery
= MediaQuery String
{-| A [CSS3 Selector](https://www.w3.org/TR/css3-selectors/). All selectors
begin with either a type selector or the universal selector, and end with either
zero or one pseudo-elements. In between can be zero or more simple selectors,
separated by combinators.
-}
type Selector
= Selector SimpleSelectorSequence (List ( SelectorCombinator, SimpleSelectorSequence )) (Maybe PseudoElement)
{-| Either the universal selector or a type selector, followed by zero or
more repeatable selectors.
-}
type SimpleSelectorSequence
= TypeSelectorSequence TypeSelector (List RepeatableSimpleSelector)
| UniversalSelectorSequence (List RepeatableSimpleSelector)
| CustomSelector String (List RepeatableSimpleSelector)
{-| A selector that can appear multiple times in a simple selector. (It doesn't
make a ton of sense that the specification permits multiple id selectors, but
here we are.)
-}
type RepeatableSimpleSelector
= ClassSelector String
| IdSelector String
| PseudoClassSelector String
{-| A type selector. That's what the CSS spec calls them, but it could be
better. Maybe "element selector" or "tag selector" perhaps?
-}
type TypeSelector
= TypeSelector String
{-| A pseudo-element.
-}
type PseudoElement
= PseudoElement String
{-| A selector combinator used to link together selector chains.
-}
type SelectorCombinator
= AdjacentSibling
| GeneralSibling
| Child
| Descendant
type alias KeyframeProperty =
String
{-| Add a property to the last style block in the given declarations.
-}
appendProperty : Property -> List Declaration -> List Declaration
appendProperty property declarations =
case declarations of
[] ->
declarations
(StyleBlockDeclaration styleBlock) :: [] ->
[ StyleBlockDeclaration (withPropertyAppended property styleBlock) ]
(MediaRule mediaQueries styleBlocks) :: [] ->
[ MediaRule mediaQueries
(mapLast (withPropertyAppended property) styleBlocks)
]
-- TODO
_ :: [] ->
declarations
--| SupportsRule String (List Declaration)
--| 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 ))
first :: rest ->
first :: appendProperty property rest
withPropertyAppended : Property -> StyleBlock -> StyleBlock
withPropertyAppended property (StyleBlock firstSelector otherSelectors properties) =
StyleBlock firstSelector otherSelectors (properties ++ [ property ])
extendLastSelector : RepeatableSimpleSelector -> List Declaration -> List Declaration
extendLastSelector selector declarations =
case declarations of
[] ->
declarations
(StyleBlockDeclaration (StyleBlock only [] properties)) :: [] ->
[ StyleBlockDeclaration (StyleBlock (appendRepeatableSelector selector only) [] properties) ]
(StyleBlockDeclaration (StyleBlock first rest properties)) :: [] ->
let
newRest =
mapLast (appendRepeatableSelector selector) rest
in
[ StyleBlockDeclaration (StyleBlock first newRest properties) ]
(MediaRule mediaQueries ((StyleBlock only [] properties) :: [])) :: [] ->
let
newStyleBlock =
StyleBlock (appendRepeatableSelector selector only) [] properties
in
[ MediaRule mediaQueries [ newStyleBlock ] ]
(MediaRule mediaQueries ((StyleBlock first rest properties) :: [])) :: [] ->
let
newRest =
mapLast (appendRepeatableSelector selector) rest
newStyleBlock =
StyleBlock first newRest properties
in
[ MediaRule mediaQueries [ newStyleBlock ] ]
(MediaRule mediaQueries (first :: rest)) :: [] ->
case extendLastSelector selector [ MediaRule mediaQueries rest ] of
(MediaRule newMediaQueries newStyleBlocks) :: [] ->
[ MediaRule newMediaQueries (first :: newStyleBlocks) ]
_ as declarations ->
declarations
(SupportsRule str nestedDeclarations) :: [] ->
[ SupportsRule str (extendLastSelector selector nestedDeclarations) ]
(DocumentRule str1 str2 str3 str4 (StyleBlock only [] properties)) :: [] ->
let
newStyleBlock =
StyleBlock (appendRepeatableSelector selector only) [] properties
in
[ DocumentRule str1 str2 str3 str4 newStyleBlock ]
(DocumentRule str1 str2 str3 str4 (StyleBlock first rest properties)) :: [] ->
let
newRest =
mapLast (appendRepeatableSelector selector) rest
newStyleBlock =
StyleBlock first newRest properties
in
[ DocumentRule str1 str2 str3 str4 newStyleBlock ]
(PageRule _ _) :: [] ->
declarations
(FontFace _) :: [] ->
declarations
(Keyframes _ _) :: [] ->
declarations
(Viewport _) :: [] ->
declarations
(CounterStyle _) :: [] ->
declarations
(FontFeatureValues _) :: [] ->
declarations
first :: rest ->
first :: extendLastSelector selector rest
appendToLastSelector : (Selector -> Selector) -> StyleBlock -> List StyleBlock
appendToLastSelector f styleBlock =
case styleBlock of
StyleBlock only [] properties ->
[ StyleBlock only [] properties
, StyleBlock (f only) [] []
]
StyleBlock first rest properties ->
let
newRest =
List.map f rest
newFirst =
f first
in
[ StyleBlock first rest properties
, StyleBlock newFirst newRest []
]
appendRepeatableToLastSelector : RepeatableSimpleSelector -> StyleBlock -> List StyleBlock
appendRepeatableToLastSelector selector styleBlock =
appendToLastSelector (appendRepeatableSelector selector) styleBlock
appendPseudoElementToLastSelector : PseudoElement -> StyleBlock -> List StyleBlock
appendPseudoElementToLastSelector pseudo styleBlock =
appendToLastSelector (applyPseudoElement pseudo) styleBlock
applyPseudoElement : PseudoElement -> Selector -> Selector
applyPseudoElement pseudo (Selector sequence selectors _) =
Selector sequence selectors <| Just pseudo
concatMapLastStyleBlock : (StyleBlock -> List StyleBlock) -> List Declaration -> List Declaration
concatMapLastStyleBlock update declarations =
case declarations of
[] ->
declarations
(StyleBlockDeclaration styleBlock) :: [] ->
update styleBlock
|> List.map StyleBlockDeclaration
(MediaRule mediaQueries (styleBlock :: [])) :: [] ->
[ MediaRule mediaQueries (update styleBlock) ]
(MediaRule mediaQueries (first :: rest)) :: [] ->
case concatMapLastStyleBlock update [ MediaRule mediaQueries rest ] of
(MediaRule newMediaQueries newStyleBlocks) :: [] ->
[ MediaRule newMediaQueries (first :: newStyleBlocks) ]
_ as declarations ->
declarations
(SupportsRule str nestedDeclarations) :: [] ->
[ SupportsRule str (concatMapLastStyleBlock update nestedDeclarations) ]
-- TODO give these more descritpive names
(DocumentRule str1 str2 str3 str4 styleBlock) :: [] ->
update styleBlock
|> List.map (DocumentRule str1 str2 str3 str4)
(PageRule _ _) :: [] ->
declarations
(FontFace _) :: [] ->
declarations
(Keyframes _ _) :: [] ->
declarations
(Viewport _) :: [] ->
declarations
(CounterStyle _) :: [] ->
declarations
(FontFeatureValues _) :: [] ->
declarations
first :: rest ->
first :: concatMapLastStyleBlock update rest
appendRepeatableSelector : RepeatableSimpleSelector -> Selector -> Selector
appendRepeatableSelector repeatableSimpleSelector selector =
case selector of
Selector sequence [] pseudoElement ->
Selector (appendRepeatable repeatableSimpleSelector sequence) [] pseudoElement
Selector firstSelector tuples pseudoElement ->
Selector firstSelector (appendRepeatableWithCombinator repeatableSimpleSelector tuples) pseudoElement
appendRepeatableWithCombinator : RepeatableSimpleSelector -> List ( SelectorCombinator, SimpleSelectorSequence ) -> List ( SelectorCombinator, SimpleSelectorSequence )
appendRepeatableWithCombinator selector list =
case list of
[] ->
[]
( combinator, sequence ) :: [] ->
[ ( combinator, appendRepeatable selector sequence ) ]
first :: rest ->
first :: appendRepeatableWithCombinator selector rest
appendRepeatable : RepeatableSimpleSelector -> SimpleSelectorSequence -> SimpleSelectorSequence
appendRepeatable selector sequence =
case sequence of
TypeSelectorSequence typeSelector list ->
TypeSelectorSequence typeSelector (list ++ [ selector ])
UniversalSelectorSequence list ->
UniversalSelectorSequence (list ++ [ selector ])
CustomSelector str list ->
CustomSelector str (list ++ [ selector ])
mapLast : (a -> a) -> List a -> List a
mapLast update list =
case list of
[] ->
list
only :: [] ->
[ update only ]
first :: rest ->
first :: mapLast update rest
concatMapLast : (a -> List a) -> List a -> List a
concatMapLast update list =
case list of
[] ->
list
only :: [] ->
update only
first :: rest ->
first :: concatMapLast update rest
dropEmpty : Stylesheet -> Stylesheet
dropEmpty { charset, imports, namespaces, declarations } =
{ charset = charset
, imports = imports
, namespaces = namespaces
, declarations = dropEmptyDeclarations declarations
}
dropEmptyDeclarations : List Declaration -> List Declaration
dropEmptyDeclarations declarations =
case declarations of
[] ->
[]
((StyleBlockDeclaration (StyleBlock _ _ properties)) as declaration) :: rest ->
if List.isEmpty properties then
dropEmptyDeclarations rest
else
declaration :: (dropEmptyDeclarations rest)
((MediaRule _ styleBlocks) as declaration) :: rest ->
if List.all (\(StyleBlock _ _ properties) -> List.isEmpty properties) styleBlocks then
dropEmptyDeclarations rest
else
declaration :: (dropEmptyDeclarations rest)
((SupportsRule _ otherDeclarations) as declaration) :: rest ->
if List.isEmpty otherDeclarations then
dropEmptyDeclarations rest
else
declaration :: (dropEmptyDeclarations rest)
((DocumentRule _ _ _ _ _) as declaration) :: rest ->
declaration :: (dropEmptyDeclarations rest)
((PageRule _ properties) as declaration) :: rest ->
if List.isEmpty properties then
dropEmptyDeclarations rest
else
declaration :: (dropEmptyDeclarations rest)
((FontFace properties) as declaration) :: rest ->
if List.isEmpty properties then
dropEmptyDeclarations rest
else
declaration :: (dropEmptyDeclarations rest)
((Keyframes _ properties) as declaration) :: rest ->
if List.isEmpty properties then
dropEmptyDeclarations rest
else
declaration :: (dropEmptyDeclarations rest)
((Viewport properties) as declaration) :: rest ->
if List.isEmpty properties then
dropEmptyDeclarations rest
else
declaration :: (dropEmptyDeclarations rest)
((CounterStyle properties) as declaration) :: rest ->
if List.isEmpty properties then
dropEmptyDeclarations rest
else
declaration :: (dropEmptyDeclarations rest)
((FontFeatureValues tuples) as declaration) :: rest ->
if List.all (\( _, properties ) -> List.isEmpty properties) tuples then
dropEmptyDeclarations rest
else
declaration :: (dropEmptyDeclarations rest)

View File

@@ -0,0 +1,174 @@
module Css.Structure.Output exposing (prettyPrint)
import Css.Structure exposing (..)
import String
prettyPrint : Stylesheet -> String
prettyPrint { charset, imports, namespaces, declarations } =
[ charsetToString charset
, String.join "\n" (List.map importToString imports)
, String.join "\n" (List.map namespaceToString namespaces)
, String.join "\n\n" (List.map prettyPrintDeclaration declarations)
]
|> List.filter (not << String.isEmpty)
|> String.join "\n\n"
charsetToString : Maybe String -> String
charsetToString charset =
charset
|> Maybe.map (\str -> "@charset \"" ++ str ++ "\"")
|> Maybe.withDefault ""
importToString : ( String, List MediaQuery ) -> String
importToString ( name, mediaQueries ) =
-- TODO
"@import \"" ++ name ++ toString mediaQueries ++ "\""
namespaceToString : ( String, String ) -> String
namespaceToString ( prefix, str ) =
"@namespace "
++ prefix
++ "\""
++ str
++ "\""
prettyPrintStyleBlock : StyleBlock -> String
prettyPrintStyleBlock (StyleBlock firstSelector otherSelectors properties) =
let
selectorStr =
(firstSelector :: otherSelectors)
|> List.map selectorToString
|> String.join ", "
in
selectorStr
++ " {\n"
++ (prettyPrintProperties properties)
++ "\n}"
prettyPrintDeclaration : Declaration -> String
prettyPrintDeclaration declaration =
case declaration of
StyleBlockDeclaration styleBlock ->
prettyPrintStyleBlock styleBlock
MediaRule mediaQueries styleBlocks ->
let
blocks =
(List.map (indent << prettyPrintStyleBlock) styleBlocks)
|> String.join "\n\n"
query =
(List.map (\(MediaQuery str) -> str) mediaQueries)
|> String.join " "
in
"@media " ++ query ++ " {\n" ++ indent blocks ++ "\n}"
_ ->
Debug.crash "not yet implemented :x"
simpleSelectorSequenceToString : SimpleSelectorSequence -> String
simpleSelectorSequenceToString simpleSelectorSequence =
case simpleSelectorSequence of
TypeSelectorSequence (TypeSelector str) repeatableSimpleSelectors ->
(str :: (List.map repeatableSimpleSelectorToString repeatableSimpleSelectors))
|> String.join ""
UniversalSelectorSequence repeatableSimpleSelectors ->
if List.isEmpty repeatableSimpleSelectors then
"*"
else
List.map repeatableSimpleSelectorToString repeatableSimpleSelectors
|> String.join ""
CustomSelector str repeatableSimpleSelectors ->
(str :: (List.map repeatableSimpleSelectorToString repeatableSimpleSelectors))
|> String.join ""
repeatableSimpleSelectorToString : RepeatableSimpleSelector -> String
repeatableSimpleSelectorToString repeatableSimpleSelector =
case repeatableSimpleSelector of
ClassSelector str ->
"." ++ str
IdSelector str ->
"#" ++ str
PseudoClassSelector str ->
":" ++ str
selectorChainToString : ( SelectorCombinator, SimpleSelectorSequence ) -> String
selectorChainToString ( combinator, sequence ) =
[ combinatorToString combinator
, simpleSelectorSequenceToString sequence
]
|> String.join " "
pseudoElementToString : PseudoElement -> String
pseudoElementToString (PseudoElement str) =
"::" ++ str
selectorToString : Selector -> String
selectorToString (Selector simpleSelectorSequence chain pseudoElement) =
let
segments =
[ simpleSelectorSequenceToString simpleSelectorSequence ]
++ List.map selectorChainToString chain
pseudoElementsString =
String.join "" [ Maybe.withDefault "" (Maybe.map pseudoElementToString pseudoElement) ]
in
segments
|> List.filter (not << String.isEmpty)
|> String.join " "
|> (flip (++)) pseudoElementsString
combinatorToString : SelectorCombinator -> String
combinatorToString combinator =
case combinator of
AdjacentSibling ->
"+"
GeneralSibling ->
"~"
Child ->
">"
Descendant ->
""
prettyPrintProperty : Property -> String
prettyPrintProperty { key, value, important } =
let
suffix =
if important then
" !important;"
else
";"
in
key ++ ": " ++ value ++ suffix
indent : String -> String
indent str =
" " ++ str
prettyPrintProperties : List Property -> String
prettyPrintProperties properties =
properties
|> List.map (indent << prettyPrintProperty)
|> String.join "\n"

View File

@@ -0,0 +1,167 @@
module Compile exposing (all)
import Test exposing (..)
import Expect
import Fuzz exposing (Fuzzer, tuple3, tuple4)
import TestUtil exposing (..)
import CompileFixtures
import Css exposing (..)
all : Test
all =
describe "elm-css"
[ unstyledDiv
, dreamwriter
, colorWarnings
, compileTest
]
getRgbaWarnings : ( Int, Int, Int, Float ) -> Int
getRgbaWarnings ( red, green, blue, alpha ) =
rgba red green blue alpha |> .warnings |> List.length
getRgbWarnings : ( Int, Int, Int ) -> Int
getRgbWarnings ( red, green, blue ) =
rgb red green blue |> .warnings |> List.length
colorWarnings : Test
colorWarnings =
describe "color warnings"
[ describe "rgb"
[ fuzz (tuple3 ( validRgbValue, validRgbValue, validRgbValue ))
"does not warn when everything is valid"
(getRgbWarnings >> Expect.equal 0)
, fuzz (tuple3 ( invalidRgbValue, validRgbValue, validRgbValue ))
"warns for invalid r values"
(getRgbWarnings >> Expect.equal 1)
, fuzz (tuple3 ( validRgbValue, invalidRgbValue, validRgbValue ))
"warns for invalid g values"
(getRgbWarnings >> Expect.equal 1)
, fuzz (tuple3 ( validRgbValue, validRgbValue, invalidRgbValue ))
"warns for invalid b values"
(getRgbWarnings >> Expect.equal 1)
]
, describe "rgba"
[ fuzz (tuple4 ( validRgbValue, validRgbValue, validRgbValue, validAlphaValue ))
"does not warn when everything is valid"
(getRgbaWarnings >> Expect.equal 0)
, fuzz (tuple4 ( invalidRgbValue, validRgbValue, validRgbValue, validAlphaValue ))
"warns for invalid r values"
(getRgbaWarnings >> Expect.equal 1)
, fuzz (tuple4 ( validRgbValue, invalidRgbValue, validRgbValue, validAlphaValue ))
"warns for invalid g values"
(getRgbaWarnings >> Expect.equal 1)
, fuzz (tuple4 ( validRgbValue, validRgbValue, invalidRgbValue, validAlphaValue ))
"warns for invalid b values"
(getRgbaWarnings >> Expect.equal 1)
, fuzz (tuple4 ( validRgbValue, validRgbValue, validRgbValue, invalidAlphaValue ))
"warns for invalid a values"
(getRgbaWarnings >> Expect.equal 1)
]
]
unstyledDiv : Test
unstyledDiv =
let
input =
CompileFixtures.unstyledDiv
output =
""
in
describe "unstyled div"
[ test "pretty prints the expected output" <|
\() ->
prettyPrint input
|> Expect.equal output
]
dreamwriter : Test
dreamwriter =
let
input =
CompileFixtures.dreamwriter
output =
"""
html, body {
width: 100%;
height: 100%;
box-sizing: border-box;
padding: 0;
margin: 0;
}
body {
min-width: 1280px;
overflow-x: auto;
}
body > div {
width: 100%;
height: 100%;
}
.dreamwriterHidden {
display: none !important;
}
#Page {
width: 100%;
height: 100%;
box-sizing: border-box;
margin: 0;
padding: 8px;
background-color: rgb(100, 90, 128);
color: rgb(40, 35, 76);
}
"""
in
describe "Sample stylesheet from Dreamwriter"
[ test "pretty prints the expected output" <|
\() ->
outdented (prettyPrint input)
|> Expect.equal (outdented output)
]
compileTest : Test
compileTest =
let
input =
compile
[ CompileFixtures.basicStyle1
, CompileFixtures.basicStyle2
]
output =
"""
.basic1BasicStyle1 {
display: none;
}
.basic2BasicStyle2 {
display: none;
}
"""
in
describe "compiles multiple stylesheets"
[ test "compile output" <|
\() ->
input
|> .css
|> outdented
|> Expect.equal (outdented output)
, test "compile warnings" <|
\() ->
input
|> .warnings
|> Expect.equal []
]

View File

@@ -0,0 +1,79 @@
module CompileFixtures exposing (..)
import Css exposing (..)
import Css.Elements exposing (..)
import Css.Namespace exposing (namespace)
pageBackground : Color
pageBackground =
rgb 100 90 128
pageDefaultText : Color
pageDefaultText =
rgb 40 35 76
type CssClasses
= Hidden
| BasicStyle1
| BasicStyle2
type CssIds
= Page
unstyledDiv : Stylesheet
unstyledDiv =
stylesheet [ div [] ]
dreamwriter : Stylesheet
dreamwriter =
(stylesheet << namespace "dreamwriter")
[ (each [ html, body ])
[ width (pct 100)
, height (pct 100)
, boxSizing borderBox
, padding zero
, margin zero
]
, body
[ minWidth (px 1280)
, overflowX auto
, children
[ div
[ width (pct 100)
, height (pct 100)
]
]
]
, ((.) Hidden) [ (display none) |> important ]
, ((#) Page)
[ width (pct 100)
, height (pct 100)
, boxSizing borderBox
, margin zero
, padding (px 8)
, backgroundColor pageBackground
, color pageDefaultText
]
]
basicStyle1 : Stylesheet
basicStyle1 =
(stylesheet << namespace "basic1")
[ (.) BasicStyle1
[ display none ]
]
basicStyle2 : Stylesheet
basicStyle2 =
(stylesheet << namespace "basic2")
[ (.) BasicStyle2
[ display none ]
]

View File

@@ -0,0 +1,432 @@
module Fixtures exposing (..)
import Css exposing (..)
import Css.Elements exposing (..)
import Css.Namespace exposing (namespace)
type CssClasses
= Hidden
type CssIds
= Page
type CssAnimations
= Wobble
unstyledDiv : Stylesheet
unstyledDiv =
stylesheet [ div [] ]
divWidthHeight : Stylesheet
divWidthHeight =
stylesheet
[ div
[ width (pct 32)
, height (px 50)
]
]
atRule : Stylesheet
atRule =
(stylesheet << namespace "homepage")
[ body [ padding zero ]
, (media [ print ]) [ body [ margin (em 2) ] ]
, mediaQuery "screen and ( max-width: 600px )"
[ body [ margin (em 3) ] ]
, button [ margin auto ]
]
nestedAtRule : Stylesheet
nestedAtRule =
(stylesheet << namespace "homepage")
[ button [ padding zero ]
, body
[ margin auto
, (withMedia [ print ]) [ margin (em 2) ]
]
, a [ textDecoration none ]
]
bug99 : Stylesheet
bug99 =
stylesheet
[ article
[ margin zero
, children
[ header [ margin (em 1) ]
, section [ margin (px 2) ]
, nav [ margin (pct 3) ]
]
]
]
bug140 : Stylesheet
bug140 =
stylesheet
[ each [ input, select, selector "textarea" ]
[ focus
[ borderColor (hex "#000000")
]
, after
[ color (hex "#aaaaaa")
]
]
]
simpleEach : Stylesheet
simpleEach =
stylesheet
[ span
[ width (px 30)
, height (em 2)
]
, (each [ html, body ])
[ boxSizing borderBox
, display none
]
, button
[ color (rgb 22 23 24)
, padding zero
]
]
multiDescendent : Stylesheet
multiDescendent =
stylesheet
[ (each [ html, body ])
[ boxSizing borderBox
, display none
, children
[ div
[ width (pct 100)
, height (pct 100)
]
]
]
, (each [ h1, h2 ])
[ padding zero
, margin zero
, children
[ h3
[ width (pct 100)
, children
[ h4 [ height (pct 100) ]
]
]
]
]
, span
[ padding (px 10)
, margin (px 11)
, children
[ h2
[ children
[ h1
[ width (px 1)
, height (pct 2)
]
]
]
]
]
]
universal : Stylesheet
universal =
(stylesheet << namespace "universal")
[ everything
[ display none
, children
[ everything
[ width (pct 100)
, height (pct 100)
]
]
]
, span
[ children [ everything [ margin (px 11) ] ]
]
]
multiSelector : Stylesheet
multiSelector =
(stylesheet << namespace "multiSelector")
[ div
[ (withClass Page)
[ (withClass Hidden)
[ display none
, width (pct 100)
, height (pct 100)
]
]
]
, span
[ padding (px 10)
, margin (px 11)
]
]
keyValue : Stylesheet
keyValue =
stylesheet
[ body
[ property "-webkit-font-smoothing" "none"
, (property "-moz-font-smoothing" "none") |> important
]
]
leftRightTopBottom : Stylesheet
leftRightTopBottom =
(stylesheet << namespace "left-right-top-bottom")
[ div
[ position absolute
, top (em 2)
, left (px 5)
, textAlign left
, verticalAlign bottom
]
, a
[ position relative
, right zero
, textAlign right
, bottom (em 2)
, verticalAlign top
]
]
borders : Stylesheet
borders =
(stylesheet << namespace "border-test")
[ button
[ borderLeft3 (px 5) dashed (rgb 11 14 17)
, borderRight (px 7)
, borderImageOutset2 (int 3) (em 4)
]
, a [ border2 (px 10) solid ]
]
underlineOnHover : Mixin
underlineOnHover =
mixin
--~ textDecoration none
[ color (rgb 128 127 126)
, hover
--[ textDecoration underline ]
[ color (rgb 23 24 25) ]
]
greenOnHover : Mixin
greenOnHover =
mixin
[ hover [ color (rgb 0 0 122) ]
]
mixinGreenOnHoverStylesheet : Stylesheet
mixinGreenOnHoverStylesheet =
(stylesheet << namespace "greenOnHoverStylesheetsheet")
[ button
[ color (rgb 11 22 33)
, greenOnHover
]
]
mixinUnderlineOnHoverStylesheet : Stylesheet
mixinUnderlineOnHoverStylesheet =
(stylesheet << namespace "underlineOnHoverStylesheetsheet")
[ a
--[ color (rgb 128 64 32) ]
[ underlineOnHover ]
]
manualUnderlineOnHoverStylesheet : Stylesheet
manualUnderlineOnHoverStylesheet =
(stylesheet << namespace "underlineOnHoverStylesheetsheet")
[ a
[ color (rgb 128 127 126)
, hover [ color (rgb 23 24 25) ]
]
]
transformsStylesheet : Stylesheet
transformsStylesheet =
(stylesheet << namespace "transformsStylesheet")
[ body
[ transforms []
, transforms
[ matrix 1 2 3 4 5 6
, matrix3d 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
]
, transform (perspective 1)
, transforms
[ rotate (deg 90)
, rotateX (rad 3.14)
, rotateY (grad 3.14)
, rotateZ (turn 1)
, rotate3d 1 1 1 (deg 90)
]
, transforms
[ scale 1
, scale2 1 1
, scaleX 1
, scaleY 1
, scale3d 1 1 1
]
, transforms
[ skew (deg 90)
, skew2 (deg 90) (deg 90)
, skewX (deg 90)
, skewY (deg 90)
]
, transforms
[ translate (px 1)
, translate2 (px 1) (px 1)
, translateX (px 1)
, translateY (px 1)
, translate3d (px 1) (px 1) (px 1)
]
, transformBox viewBox
, transformStyle preserve3d
]
]
fontStylesheet : Stylesheet
fontStylesheet =
(stylesheet << namespace "fontStylesheet")
[ body
[ lineHeight (px 14)
, fontFamily serif
, fontFamilies
[ qt "Gill Sans Extrabold"
, "Helvetica"
, .value sansSerif
]
, fontSize xSmall
, fontStyle italic
, fontWeight bold
, fontWeight (int 100)
, fontVariant smallCaps
, fontVariant2 commonLigatures slashedZero
, fontVariantNumerics
[ oldstyleNums
, tabularNums
, stackedFractions
, ordinal
, slashedZero
]
]
]
fontWeightWarning : Stylesheet
fontWeightWarning =
(stylesheet << namespace "fontWeightWarning") [ body [ fontWeight (int 22) ] ]
colorHexWarning : Stylesheet
colorHexWarning =
(stylesheet << namespace "colorHexWarning") [ body [ color (hex "ababah") ] ]
colorHexAbbrWarning : Stylesheet
colorHexAbbrWarning =
(stylesheet << namespace "colorHexAbbrWarning") [ body [ color (hex "#00i") ] ]
pseudoElementStylesheet : Stylesheet
pseudoElementStylesheet =
(stylesheet << namespace "pseudoElements")
[ (#) Page
[ margin (px 10)
, before
[ color (hex "#fff") ]
, after
[ color (hex "#000") ]
, color (hex "#aaa")
]
]
pseudoClassStylesheet : Stylesheet
pseudoClassStylesheet =
(stylesheet << namespace "pseudoClasses")
[ (#) Page
[ color (hex "#fff")
, hover
[ marginTop (px 10)
, focus
[ color (hex "#000") ]
]
, first
[ fontSize (em 3) ]
, disabled
[ marginTop (px 20) ]
, backgroundColor (hex "#aaa")
]
]
backgrounds : Stylesheet
backgrounds =
(stylesheet << namespace "background-test")
[ div
[ backgroundColor (rgb 128 127 126)
, backgroundRepeat repeatX
, backgroundRepeat repeatY
, backgroundRepeat2 repeat noRepeat
, backgroundRepeat2 space Css.round
, backgroundAttachment local
, backgroundAttachment scroll
, backgroundAttachment fixed
, backgroundBlendMode color
, backgroundBlendMode screenBlendMode
, backgroundBlendMode multiply
, backgroundBlendMode overlay
, backgroundBlendMode darken
, backgroundBlendMode lighten
, backgroundBlendMode colorDodge
, backgroundBlendMode colorBurn
, backgroundBlendMode hardLight
, backgroundBlendMode softLight
, backgroundBlendMode difference
, backgroundBlendMode exclusion
, backgroundBlendMode hue
, backgroundBlendMode saturation
, backgroundBlendMode luminosity
, backgroundClip borderBox
, backgroundClip paddingBox
, backgroundClip contentBox
, backgroundImage (url "http://example.com/elm.png")
, backgroundOrigin borderBox
, backgroundOrigin paddingBox
, backgroundOrigin contentBox
, backgroundSize cover
, backgroundSize contain
, backgroundSize (px 50)
, backgroundSize2 auto (px 20)
, backgroundPosition center
, backgroundPosition2 (pct 10) zero
]
]

View File

@@ -0,0 +1,13 @@
port module Main exposing (..)
import Test.Runner.Node exposing (run, TestProgram)
import Tests
import Json.Encode exposing (Value)
main : TestProgram
main =
run emit Tests.all
port emit : ( String, Value ) -> Cmd msg

View File

@@ -0,0 +1,520 @@
module Properties exposing (all)
import Test exposing (..)
import Expect
import TestUtil exposing (prettyPrint)
import Css exposing (..)
import Css.Elements exposing (p)
import Css.Namespace exposing (namespace)
all : Test
all =
describe "properties"
[ testProperty "box-sizing"
[ ( boxSizing initial, "initial" )
, ( boxSizing unset, "unset" )
, ( boxSizing inherit, "inherit" )
, ( boxSizing contentBox, "content-box" )
, ( boxSizing borderBox, "border-box" )
]
, testProperty "width"
[ ( width initial, "initial" )
, ( width unset, "unset" )
, ( width inherit, "inherit" )
, ( width auto, "auto" )
, ( width (pct 90), "90%" )
]
, testProperty "min-width"
[ ( minWidth initial, "initial" )
, ( minWidth unset, "unset" )
, ( minWidth inherit, "inherit" )
, ( minWidth maxContent, "max-content" )
, ( minWidth minContent, "min-content" )
, ( minWidth fitContent, "fit-content" )
, ( minWidth fillAvailable, "fill-available" )
, ( minWidth (pc 9), "9pc" )
]
, testProperty "max-width"
[ ( maxWidth initial, "initial" )
, ( maxWidth unset, "unset" )
, ( maxWidth inherit, "inherit" )
, ( maxWidth none, "none" )
, ( maxWidth maxContent, "max-content" )
, ( maxWidth minContent, "min-content" )
, ( maxWidth fitContent, "fit-content" )
, ( maxWidth fillAvailable, "fill-available" )
, ( maxWidth (cm 17), "17cm" )
]
, testProperty "height"
[ ( height initial, "initial" )
, ( height unset, "unset" )
, ( height inherit, "inherit" )
, ( height auto, "auto" )
, ( height (mm 8), "8mm" )
]
, testProperty "min-height"
[ ( minHeight initial, "initial" )
, ( minHeight unset, "unset" )
, ( minHeight inherit, "inherit" )
, ( minHeight maxContent, "max-content" )
, ( minHeight minContent, "min-content" )
, ( minHeight fitContent, "fit-content" )
, ( minHeight fillAvailable, "fill-available" )
, ( minHeight (pc 9), "9pc" )
]
, testProperty "max-height"
[ ( maxHeight initial, "initial" )
, ( maxHeight unset, "unset" )
, ( maxHeight inherit, "inherit" )
, ( maxHeight none, "none" )
, ( maxHeight maxContent, "max-content" )
, ( maxHeight minContent, "min-content" )
, ( maxHeight fitContent, "fit-content" )
, ( maxHeight fillAvailable, "fill-available" )
, ( maxHeight (cm 17), "17cm" )
]
, testProperty "text-indent"
[ ( textIndent initial, "initial" )
, ( textIndent unset, "unset" )
, ( textIndent inherit, "inherit" )
, ( textIndent (px 5), "5px" )
, ( textIndent2 initial initial, "initial initial" )
, ( textIndent2 unset unset, "unset unset" )
, ( textIndent2 inherit inherit, "inherit inherit" )
, ( textIndent2 (em 3) hanging, "3em hanging" )
, ( textIndent2 (pc 2) eachLine, "2pc each-line" )
]
, testProperty "text-decoration"
[ ( textDecoration initial, "initial" )
, ( textDecoration unset, "unset" )
, ( textDecoration inherit, "inherit" )
, ( textDecoration none, "none" )
, ( textDecoration underline, "underline" )
, ( textDecoration overline, "overline" )
, ( textDecoration lineThrough, "line-through" )
, ( textDecoration2 initial wavy, "initial wavy" )
, ( textDecoration2 unset dotted, "unset dotted" )
, ( textDecoration2 inherit dashed, "inherit dashed" )
, ( textDecoration2 none solid, "none solid" )
, ( textDecoration2 underline double, "underline double" )
, ( textDecoration2 overline initial, "overline initial" )
, ( textDecoration2 lineThrough unset, "line-through unset" )
, ( textDecoration2 lineThrough inherit, "line-through inherit" )
, ( textDecoration3 initial wavy (rgb 11 12 13), "initial wavy rgb(11, 12, 13)" )
, ( textDecoration3 unset dotted (rgb 11 12 13), "unset dotted rgb(11, 12, 13)" )
, ( textDecoration3 inherit dashed (rgb 11 12 13), "inherit dashed rgb(11, 12, 13)" )
, ( textDecoration3 none solid (rgb 11 12 13), "none solid rgb(11, 12, 13)" )
, ( textDecoration3 underline double (hex "aabbcc"), "underline double #aabbcc" )
, ( textDecoration3 overline initial (hex "aabbcc"), "overline initial #aabbcc" )
, ( textDecoration3 lineThrough unset (hex "#bbccdd"), "line-through unset #bbccdd" )
, ( textDecoration3 lineThrough inherit (hex "bbccdd05"), "line-through inherit #bbccdd05" )
, ( textDecorations [], "none" )
, ( textDecorations [ initial ], "initial" )
, ( textDecorations [ unset, inherit ], "unset inherit" )
, ( textDecorations [ none ], "none" )
, ( textDecorations [ underline, overline, lineThrough ], "underline overline line-through" )
, ( textDecorations2 [] double, "none double" )
, ( textDecorations2 [ initial ] solid, "initial solid" )
, ( textDecorations2 [ unset, inherit ] dashed, "unset inherit dashed" )
, ( textDecorations2 [ none ] dotted, "none dotted" )
, ( textDecorations2 [ underline, overline, lineThrough ] wavy, "underline overline line-through wavy" )
, ( textDecorations2 [ underline, overline, lineThrough ] initial, "underline overline line-through initial" )
, ( textDecorations2 [ underline, overline, lineThrough ] unset, "underline overline line-through unset" )
, ( textDecorations2 [ underline, overline, lineThrough ] inherit, "underline overline line-through inherit" )
, ( textDecorations3 [] double (rgb 11 12 13), "none double rgb(11, 12, 13)" )
, ( textDecorations3 [ initial ] solid (rgb 11 12 13), "initial solid rgb(11, 12, 13)" )
, ( textDecorations3 [ unset, inherit ] dashed (rgb 11 12 13), "unset inherit dashed rgb(11, 12, 13)" )
, ( textDecorations3 [ none ] dotted (rgb 11 12 13), "none dotted rgb(11, 12, 13)" )
, ( textDecorations3 [ underline, overline, lineThrough ] wavy (rgb 11 12 13), "underline overline line-through wavy rgb(11, 12, 13)" )
, ( textDecorations3 [ underline, overline, lineThrough ] initial (rgb 11 12 13), "underline overline line-through initial rgb(11, 12, 13)" )
, ( textDecorations3 [ underline, overline, lineThrough ] unset (rgb 11 12 13), "underline overline line-through unset rgb(11, 12, 13)" )
, ( textDecorations3 [ underline, overline, lineThrough ] inherit (rgb 11 12 13), "underline overline line-through inherit rgb(11, 12, 13)" )
]
, testProperty "text-decoration-line"
[ ( textDecorationLine initial, "initial" )
, ( textDecorationLine unset, "unset" )
, ( textDecorationLine inherit, "inherit" )
, ( textDecorationLine none, "none" )
, ( textDecorationLine underline, "underline" )
, ( textDecorationLine overline, "overline" )
, ( textDecorationLine lineThrough, "line-through" )
, ( textDecorationLines [], "none" )
, ( textDecorationLines [ initial ], "initial" )
, ( textDecorationLines [ unset, inherit ], "unset inherit" )
, ( textDecorationLines [ none ], "none" )
, ( textDecorationLines [ underline, overline, lineThrough ], "underline overline line-through" )
]
, testProperty "line-height"
[ ( lineHeight (px 1), "1px" )
, ( lineHeight (pct 10), "10%" )
, ( lineHeight (em 1.2), "1.2em" )
, ( lineHeight (pt 12), "12pt" )
, ( lineHeight (num 1.8), "1.8" )
, ( lineHeight (num 0), "0" )
, ( lineHeight inherit, "inherit" )
, ( lineHeight initial, "initial" )
, ( lineHeight unset, "unset" )
]
, testProperty "overflow-x"
[ ( overflowX initial, "initial" )
, ( overflowX unset, "unset" )
, ( overflowX inherit, "inherit" )
, ( overflowX auto, "auto" )
, ( overflowX visible, "visible" )
, ( overflowX hidden, "hidden" )
, ( overflowX scroll, "scroll" )
]
, testProperty "overflow-y"
[ ( overflowY initial, "initial" )
, ( overflowY unset, "unset" )
, ( overflowY inherit, "inherit" )
, ( overflowY auto, "auto" )
, ( overflowY visible, "visible" )
, ( overflowY hidden, "hidden" )
, ( overflowY scroll, "scroll" )
]
, testProperty "overflow"
[ ( overflow initial, "initial" )
, ( overflow unset, "unset" )
, ( overflow inherit, "inherit" )
, ( overflow auto, "auto" )
, ( overflow visible, "visible" )
, ( overflow hidden, "hidden" )
, ( overflow scroll, "scroll" )
]
, testProperty "text-rendering"
[ ( textRendering initial, "initial" )
, ( textRendering unset, "unset" )
, ( textRendering inherit, "inherit" )
, ( textRendering auto, "auto" )
, ( textRendering optimizeSpeed, "optimizeSpeed" )
, ( textRendering optimizeLegibility, "optimizeLegibility" )
, ( textRendering geometricPrecision, "geometricPrecision" )
]
, testProperty "display"
[ ( display initial, "initial" )
, ( display unset, "unset" )
, ( display inherit, "inherit" )
, ( display none, "none" )
, ( display inline, "inline" )
, ( display block, "block" )
, ( display inlineBlock, "inline-block" )
, ( display listItem, "list-item" )
, ( display inlineListItem, "inline-list-item" )
, ( displayFlex, "flex" )
-- TODO display: contents;
-- TODO display: table;
-- TODO display: inline-table;
-- TODO display: table-cell;
-- TODO display: table-column;
-- TODO display: table-column-group;
-- TODO display: table-footer-group;
-- TODO display: table-header-group;
-- TODO display: table-row;
-- TODO display: table-row-group;
-- TODO display: flex;
-- TODO display: inline-flex;
-- TODO display: grid;
-- TODO display: inline-grid;
-- TODO display: ruby;
-- TODO display: ruby-base;
-- TODO display: ruby-text;
-- TODO display: ruby-base-container;
-- TODO display: ruby-text-container ;
-- TODO display: run-in;
]
, testProperty "flex"
[ ( flex initial, "initial" )
, ( flex unset, "unset" )
, ( flex inherit, "inherit" )
, ( flex auto, "auto" )
, ( flex content, "content" )
, ( flex none, "none" )
, ( flex (int 2), "2" )
, ( flex (mm 8), "8mm" )
, ( flex2 (int 1) (int 2), "1 2" )
, ( flex2 (int 1) (px 30), "1 30px" )
, ( flex3 (int 1) (int 2) (px 20), "1 2 20px" )
]
, testProperty "flex-basis"
[ ( flexBasis initial, "initial" )
, ( flexBasis unset, "unset" )
, ( flexBasis inherit, "inherit" )
, ( flexBasis auto, "auto" )
, ( flexBasis content, "content" )
, ( flexBasis (px 10), "10px" )
, ( flexBasis (mm 8), "8mm" )
]
, testProperty "flex-wrap"
[ ( flexWrap initial, "initial" )
, ( flexWrap unset, "unset" )
, ( flexWrap inherit, "inherit" )
, ( flexWrap wrap, "wrap" )
, ( flexWrap noWrap, "nowrap" )
, ( flexWrap wrapReverse, "wrap-reverse" )
]
, testProperty "flex-grow"
[ ( flexGrow (int 1), "1" )
, ( flexGrow (num 0.2), "0.2" )
]
, testProperty "flex-shrink"
[ ( flexShrink (int 1), "1" )
, ( flexShrink (num 0.2), "0.2" )
]
, testProperty "flex-direction"
[ ( flexDirection initial, "initial" )
, ( flexDirection unset, "unset" )
, ( flexDirection inherit, "inherit" )
, ( flexDirection row, "row" )
, ( flexDirection rowReverse, "row-reverse" )
, ( flexDirection column, "column" )
, ( flexDirection columnReverse, "column-reverse" )
]
, testProperty "flex-flow"
[ ( flexFlow1 initial, "initial" )
, ( flexFlow1 unset, "unset" )
, ( flexFlow1 inherit, "inherit" )
, ( flexFlow1 row, "row" )
, ( flexFlow1 rowReverse, "row-reverse" )
, ( flexFlow1 column, "column" )
, ( flexFlow1 columnReverse, "column-reverse" )
, ( flexFlow1 noWrap, "nowrap" )
, ( flexFlow1 wrap, "wrap" )
, ( flexFlow1 wrapReverse, "wrap-reverse" )
, ( flexFlow2 row wrap, "row wrap" )
, ( flexFlow2 row noWrap, "row nowrap" )
, ( flexFlow2 row wrapReverse, "row wrap-reverse" )
, ( flexFlow2 rowReverse wrap, "row-reverse wrap" )
, ( flexFlow2 rowReverse noWrap, "row-reverse nowrap" )
, ( flexFlow2 rowReverse wrapReverse, "row-reverse wrap-reverse" )
, ( flexFlow2 column wrap, "column wrap" )
, ( flexFlow2 column noWrap, "column nowrap" )
, ( flexFlow2 column wrapReverse, "column wrap-reverse" )
, ( flexFlow2 columnReverse wrap, "column-reverse wrap" )
, ( flexFlow2 columnReverse noWrap, "column-reverse nowrap" )
, ( flexFlow2 columnReverse wrapReverse, "column-reverse wrap-reverse" )
]
, testProperty "order"
[ ( order (int 1), "1" ) ]
, testProperty "font-weight"
[ ( fontWeight bold, "bold" )
, ( fontWeight normal, "normal" )
, ( fontWeight (int 100), "100" )
, ( fontWeight (int 200), "200" )
, ( fontWeight (int 300), "300" )
, ( fontWeight (int 400), "400" )
, ( fontWeight (int 500), "500" )
, ( fontWeight (int 600), "600" )
, ( fontWeight (int 700), "700" )
, ( fontWeight (int 800), "800" )
, ( fontWeight (int 900), "900" )
]
, testProperty "font-feature-settings"
[ ( fontFeatureSettings (featureTag "smcp"), "\"smcp\" 1" )
, ( fontFeatureSettings (featureTag2 "liga" 0), "\"liga\" 0" )
, ( fontFeatureSettingsList [ featureTag2 "liga" 0, featureTag2 "swsh" 2 ], "\"liga\" 0, \"swsh\" 2" )
, ( fontFeatureSettings normal, "normal" )
]
, testProperty "align-items"
[ ( alignItems flexStart, "flex-start" )
, ( alignItems flexEnd, "flex-end" )
, ( alignItems center, "center" )
, ( alignItems baseline, "baseline" )
, ( alignItems stretch, "stretch" )
]
, testProperty "align-self"
[ ( alignSelf flexStart, "flex-start" )
, ( alignSelf flexEnd, "flex-end" )
, ( alignSelf center, "center" )
, ( alignSelf baseline, "baseline" )
, ( alignSelf stretch, "stretch" )
]
, testProperty "opacity"
[ ( opacity inherit, "inherit" )
, ( opacity (int 1), "1" )
]
, testProperty "color"
[ ( color (hsl 120 0.5 0.5), "hsl(120, 50%, 50%)" )
, ( color (hsla 120 0.5 0.5 0.5), "hsla(120, 50%, 50%, 0.5)" )
, ( color inherit, "inherit" )
, ( color unset, "unset" )
, ( color initial, "initial" )
]
, testProperty "cursor"
[ ( cursor pointer, "pointer" )
, ( cursor crosshair, "crosshair" )
, ( cursor contextMenu, "context-menu" )
, ( cursor help, "help" )
, ( cursor Css.progress, "progress" )
, ( cursor wait, "wait" )
, ( cursor cell, "cell" )
, ( cursor text, "text" )
, ( cursor verticalText, "vertical-text" )
, ( cursor cursorAlias, "alias" )
, ( cursor copy, "copy" )
, ( cursor move, "move" )
, ( cursor noDrop, "no-drop" )
, ( cursor notAllowed, "not-allowed" )
, ( cursor eResize, "e-resize" )
, ( cursor nResize, "n-resize" )
, ( cursor neResize, "ne-resize" )
, ( cursor nwResize, "nw-resize" )
, ( cursor sResize, "s-resize" )
, ( cursor seResize, "se-resize" )
, ( cursor swResize, "sw-resize" )
, ( cursor wResize, "w-resize" )
, ( cursor ewResize, "ew-resize" )
, ( cursor nsResize, "ns-resize" )
, ( cursor neswResize, "nesw-resize" )
, ( cursor nwseResize, "nwse-resize" )
, ( cursor colResize, "col-resize" )
, ( cursor rowResize, "row-resize" )
, ( cursor allScroll, "all-scroll" )
, ( cursor zoomIn, "zoom-in" )
, ( cursor zoomOut, "zoom-out" )
, ( cursor grab, "grab" )
, ( cursor grabbing, "grabbing" )
, ( cursor default, "default" )
, ( cursor auto, "auto" )
, ( cursor none, "none" )
, ( cursor initial, "initial" )
, ( cursor inherit, "inherit" )
]
, testProperty "outline"
[ ( outline3 (px 10) dashed (hsl 120 0.5 0.5), "10px dashed hsl(120, 50%, 50%)" )
, ( outline3 (em 1.4) solid (hsla 120 0.5 0.5 0.5), "1.4em solid hsla(120, 50%, 50%, 0.5)" )
, ( outline inherit, "inherit" )
, ( outline unset, "unset" )
, ( outline initial, "initial" )
, ( outline zero, "0" )
, ( outline none, "none" )
]
, testProperty "outline-width"
[ ( outlineWidth (px 10), "10px" )
, ( outlineWidth (em 1.4), "1.4em" )
, ( outlineWidth (pct 20), "20%" )
, ( outlineWidth inherit, "inherit" )
, ( outlineWidth unset, "unset" )
, ( outlineWidth initial, "initial" )
, ( outlineWidth zero, "0" )
, ( outlineWidth none, "none" )
]
, testProperty "outline-color"
[ ( outlineColor (hsl 120 0.5 0.5), "hsl(120, 50%, 50%)" )
, ( outlineColor (hsla 120 0.5 0.5 0.5), "hsla(120, 50%, 50%, 0.5)" )
, ( outlineColor transparent, "transparent" )
, ( outlineColor inherit, "inherit" )
, ( outlineColor unset, "unset" )
, ( outlineColor initial, "initial" )
]
, testProperty "outline-style"
[ ( outlineStyle none, "none" )
, ( outlineStyle dashed, "dashed" )
, ( outlineStyle dotted, "dotted" )
, ( outlineStyle inherit, "inherit" )
, ( outlineStyle unset, "unset" )
, ( outlineStyle initial, "initial" )
]
, testProperty "outline-offset"
[ ( outlineOffset zero, "0" )
, ( outlineOffset (px 10), "10px" )
, ( outlineOffset (pct 10), "10%" )
, ( outlineOffset (px 10), "10px" )
, ( outlineOffset inherit, "inherit" )
, ( outlineOffset unset, "unset" )
, ( outlineOffset initial, "initial" )
]
, testProperty "list-style-type"
[ ( listStyleType none, "none" )
, ( listStyleType initial, "initial" )
, ( listStyleType inherit, "inherit" )
, ( listStyleType disc, "disc" )
, ( listStyleType circle, "circle" )
, ( listStyleType square, "square" )
, ( listStyleType decimal, "decimal" )
, ( listStyleType decimalLeadingZero, "decimal-leading-zero" )
, ( listStyleType lowerRoman, "lower-roman" )
, ( listStyleType upperRoman, "upper-roman" )
, ( listStyleType lowerGreek, "lower-greek" )
, ( listStyleType lowerAlpha, "lower-alpha" )
, ( listStyleType lowerLatin, "lower-latin" )
, ( listStyleType upperAlpha, "upper-alpha" )
, ( listStyleType upperLatin, "upper-latin" )
, ( listStyleType arabicIndic, "arabic-indic" )
, ( listStyleType armenian, "armenian" )
, ( listStyleType bengali, "bengali" )
, ( listStyleType cjkEarthlyBranch, "cjk-earthly-branch" )
, ( listStyleType cjkHeavenlyStem, "cjk-heavenly-stem" )
, ( listStyleType devanagari, "devanagari" )
, ( listStyleType georgian, "georgian" )
, ( listStyleType gujarati, "gujarati" )
, ( listStyleType gurmukhi, "gurmukhi" )
, ( listStyleType kannada, "kannada" )
, ( listStyleType khmer, "khmer" )
, ( listStyleType lao, "lao" )
, ( listStyleType malayalam, "malayalam" )
, ( listStyleType myanmar, "myanmar" )
, ( listStyleType oriya, "oriya" )
, ( listStyleType telugu, "telugu" )
, ( listStyleType thai, "thai" )
]
, testProperty "list-style-position"
[ ( listStylePosition inherit, "inherit" )
, ( listStylePosition initial, "initial" )
, ( listStylePosition unset, "unset" )
, ( listStylePosition inside, "inside" )
, ( listStylePosition outside, "outside" )
]
, testProperty "list-style"
[ ( listStyle inherit, "inherit" )
, ( listStyle initial, "initial" )
, ( listStyle unset, "unset" )
, ( listStyle none, "none" )
, ( listStyle inside, "inside" )
, ( listStyle outside, "outside" )
, ( listStyle disc, "disc" )
, ( listStyle circle, "circle" )
, ( listStyle square, "square" )
, ( listStyle decimal, "decimal" )
, ( listStyle2 disc inside, "disc inside" )
, ( listStyle2 inside disc, "inside disc" )
, ( listStyle2 outside decimal, "outside decimal" )
, ( listStyle3 disc inside none, "disc inside none" )
, ( listStyle3 inside none circle, "inside none circle" )
, ( listStyle3 none outside decimal, "none outside decimal" )
]
, testProperty "box-shadow"
[ ( boxShadow none, "none" )
, ( boxShadow2 (px 1) (px 2), "1px 2px" )
, ( boxShadow3 (px 1) (px 2) (hex "333"), "1px 2px #333" )
, ( boxShadow3 (px 1) (px 2) (px 3), "1px 2px 3px" )
, ( boxShadow3 inset (px 2) (px 3), "inset 2px 3px" )
, ( boxShadow4 (px 1) (px 2) (px 3) (hex "333"), "1px 2px 3px #333" )
, ( boxShadow4 inset (px 2) (px 3) (hex "333"), "inset 2px 3px #333" )
, ( boxShadow4 (px 1) (px 2) (px 3) (px 4), "1px 2px 3px 4px" )
, ( boxShadow4 inset (px 2) (px 3) (px 4), "inset 2px 3px 4px" )
, ( boxShadow5 (px 1) (px 2) (px 3) (px 4) (hex "333"), "1px 2px 3px 4px #333" )
, ( boxShadow5 inset (px 2) (px 3) (px 4) (hex "333"), "inset 2px 3px 4px #333" )
]
]
testProperty : String -> List ( Mixin, String ) -> Test
testProperty propertyName modifierPairs =
describe (propertyName ++ " property")
(List.map (expectPropertyWorks propertyName) modifierPairs)
expectPropertyWorks : String -> ( Mixin, String ) -> Test
expectPropertyWorks propertyName ( mixin, expectedStr ) =
describe "works properly"
[ (test "pretty prints the expected output") <|
\() ->
prettyPrint ((stylesheet << namespace "test") [ p [ mixin ] ])
|> Expect.equal ("p {\n " ++ propertyName ++ ": " ++ expectedStr ++ ";\n}")
, (test "can be converted to a key-value pair") <|
\() ->
[ ( propertyName, expectedStr ) ]
|> Expect.equal (asPairs [ mixin ])
]

View File

@@ -0,0 +1,89 @@
module Selectors exposing (all)
import Test exposing (..)
import Expect
import TestUtil exposing (prettyPrint)
import Css exposing (..)
import Css.Elements exposing (..)
all : Test
all =
describe "selectors"
[ nonElements, elements ]
nonElements : Test
nonElements =
describe "non-elements"
[ testSelector ".foo" ((.) "foo")
, testSelector "#foo" ((#) "foo")
, testSelector "div:hover" (\children -> div [ hover children ])
, testSelector "div::before" (\children -> div [ before children ])
]
elements : Test
elements =
describe "selectors"
[ testSelector "ol" ol
, testSelector "ul" ul
, testSelector "html" html
, testSelector "body" body
, testSelector "article" article
, testSelector "header" header
, testSelector "footer" footer
, testSelector "h1" h1
, testSelector "h2" h2
, testSelector "h3" h3
, testSelector "h4" h4
, testSelector "h5" h5
, testSelector "h6" h6
, testSelector "nav" nav
, testSelector "section" section
, testSelector "div" div
, testSelector "hr" hr
, testSelector "li" li
, testSelector "main" main_
, testSelector "ol" ol
, testSelector "p" p
, testSelector "ul" ul
, testSelector "pre" pre
, testSelector "a" a
, testSelector "code" code
, testSelector "small" Css.Elements.small
, testSelector "span" span
, testSelector "strong" strong
, testSelector "img" img
, testSelector "audio" audio
, testSelector "video" video
, testSelector "canvas" canvas
, testSelector "caption" caption
, testSelector "col" col
, testSelector "colgroup" colgroup
, testSelector "table" table
, testSelector "tbody" tbody
, testSelector "td" td
, testSelector "tfoot" tfoot
, testSelector "th" th
, testSelector "thead" thead
, testSelector "tr" tr
, testSelector "button" button
, testSelector "fieldset" fieldset
, testSelector "form" form
, testSelector "input" input
, testSelector "label" label
, testSelector "legend" legend
, testSelector "optgroup" optgroup
, testSelector "option" option
, testSelector "progress" Css.Elements.progress
, testSelector "select" select
]
testSelector : String -> (List Mixin -> Snippet) -> Test
testSelector expectedOutput applySelector =
(test (expectedOutput ++ " selector")) <|
\() ->
prettyPrint (stylesheet [ applySelector [ display none ] ])
|> Expect.equal (expectedOutput ++ " {\n display: none;\n}")

View File

@@ -0,0 +1,52 @@
module TestUtil exposing (..)
import String
import Css exposing (Snippet, rgb, rgba)
import Fuzz exposing (Fuzzer)
outdented : String -> String
outdented str =
str
|> String.split "\n"
|> List.map String.trim
|> String.join "\n"
|> String.trim
prettyPrint : Css.Stylesheet -> String
prettyPrint sheet =
let
{ warnings, css } =
Css.compile [ sheet ]
in
if List.isEmpty warnings then
css
else
"Invalid Stylesheet:\n" ++ (String.join "\n" warnings)
validRgbValue : Fuzzer Int
validRgbValue =
Fuzz.intRange 0 255
validAlphaValue : Fuzzer Float
validAlphaValue =
Fuzz.floatRange 0 1
invalidRgbValue : Fuzzer Int
invalidRgbValue =
Fuzz.frequencyOrCrash
[ ( 1, Fuzz.intRange -300 -1 )
, ( 1, Fuzz.intRange 256 300 )
]
invalidAlphaValue : Fuzzer Float
invalidAlphaValue =
Fuzz.frequencyOrCrash
[ ( 1, Fuzz.floatRange -300 -1.0e-3 )
, ( 1, Fuzz.floatRange 1.0001 300 )
]

View File

@@ -0,0 +1,738 @@
module Tests exposing (all)
import Test exposing (..)
import Expect
import TestUtil exposing (outdented, prettyPrint)
import Compile
import Fixtures
import Properties
import Selectors
all : Test
all =
describe "elm-css"
[ Compile.all
, unstyledDiv
, keyValue
, simpleEach
, divWidthHeight
, leftRightTopBottom
, borders
, atRule
, nestedAtRule
, bug99
, bug140
, universal
, multiSelector
, multiDescendent
, underlineOnHoverMixin
, underlineOnHoverManual
, greenOnHoverMixin
, transformsStyle
, fonts
, weightWarning
, hexWarning
, pseudoClasses
, pseudoElements
, Properties.all
, Selectors.all
, backgrounds
]
unstyledDiv : Test
unstyledDiv =
let
input =
Fixtures.unstyledDiv
output =
""
in
describe "unstyled div"
[ test "pretty prints nothing, because the stylesheet had no properties." <|
\_ ->
prettyPrint input
|> Expect.equal (output)
]
divWidthHeight : Test
divWidthHeight =
let
actual =
Fixtures.divWidthHeight
expected =
"div {\n width: 32%;\n height: 50px;\n}"
in
describe "basic div with fixed width and height"
[ test "pretty prints the expected output" <|
\_ ->
prettyPrint actual
|> Expect.equal expected
]
simpleEach : Test
simpleEach =
let
input =
Fixtures.simpleEach
output =
"""
span {
width: 30px;
height: 2em;
}
html, body {
box-sizing: border-box;
display: none;
}
button {
color: rgb(22, 23, 24);
padding: 0;
}
"""
in
describe "simple each function test"
[ test "pretty prints the expected output" <|
\_ ->
outdented (prettyPrint input)
|> Expect.equal (outdented output)
]
leftRightTopBottom : Test
leftRightTopBottom =
let
input =
Fixtures.leftRightTopBottom
output =
"""
div {
position: absolute;
top: 2em;
left: 5px;
text-align: left;
vertical-align: bottom;
}
a {
position: relative;
right: 0;
text-align: right;
bottom: 2em;
vertical-align: top;
}
"""
in
describe "left & right, top & bottom property/value duality test"
[ test "pretty prints the expected output" <|
\_ ->
outdented (prettyPrint input)
|> Expect.equal (outdented output)
]
atRule : Test
atRule =
let
input =
Fixtures.atRule
output =
"""
body {
padding: 0;
}
@media print {
body {
margin: 2em;
}
}
@media screen and ( max-width: 600px ) {
body {
margin: 3em;
}
}
button {
margin: auto;
}
"""
in
describe "@media test"
[ test "pretty prints the expected output" <|
\_ ->
outdented (prettyPrint input)
|> Expect.equal (outdented output)
]
nestedAtRule : Test
nestedAtRule =
let
input =
Fixtures.nestedAtRule
output =
"""
button {
padding: 0;
}
body {
margin: auto;
}
@media print {
body {
margin: 2em;
}
}
a {
text-decoration: none;
}
"""
in
describe "nested @media test"
[ test "pretty prints the expected output" <|
\_ ->
outdented (prettyPrint input)
|> Expect.equal (outdented output)
]
{-| Regression test for https://github.com/rtfeldman/elm-css/issues/140
-}
bug140 : Test
bug140 =
let
input =
Fixtures.bug140
output =
"""
input:focus, select:focus, textarea:focus {
border-color: #000000;
}
input::after, select::after, textarea::after {
color: #aaaaaa;
}
"""
in
describe "`each` with pseudo classes"
[ test "pretty prints the expected output" <|
\_ ->
outdented (prettyPrint input)
|> Expect.equal (outdented output)
]
{-| Regression test for https://github.com/rtfeldman/elm-css/issues/99
-}
bug99 : Test
bug99 =
let
input =
Fixtures.bug99
output =
"""
article {
margin: 0;
}
article > header {
margin: 1em;
}
article > section {
margin: 2px;
}
article > nav {
margin: 3%;
} """
in
describe "Parents do not print duplicate rules for each child."
[ test "pretty prints the expected output" <|
\_ ->
outdented (prettyPrint input)
|> Expect.equal (outdented output)
]
borders : Test
borders =
let
input =
Fixtures.borders
output =
"""
button {
border-left: 5px dashed rgb(11, 14, 17);
border-right: 7px;
border-image-outset: 3 4em;
}
a {
border: 10px solid;
}
"""
in
describe "Borders test"
[ test "pretty prints the expected output" <|
\_ ->
outdented (prettyPrint input)
|> Expect.equal (outdented output)
]
multiDescendent : Test
multiDescendent =
let
input =
Fixtures.multiDescendent
output =
"""
html, body {
box-sizing: border-box;
display: none;
}
html > div, body > div {
width: 100%;
height: 100%;
}
h1, h2 {
padding: 0;
margin: 0;
}
h1 > h3, h2 > h3 {
width: 100%;
}
h1 > h3 > h4, h2 > h3 > h4 {
height: 100%;
}
span {
padding: 10px;
margin: 11px;
}
span > h2 > h1 {
width: 1px;
height: 2%;
}
"""
in
describe "Multi-descendent stylesheet"
[ test "pretty prints the expected output" <|
\_ ->
outdented (prettyPrint input)
|> Expect.equal (outdented output)
]
universal : Test
universal =
let
input =
Fixtures.universal
output =
"""
* {
display: none;
}
* > * {
width: 100%;
height: 100%;
}
span > * {
margin: 11px;
}
"""
in
describe "Universal selector stylesheet"
[ test "pretty prints the expected output" <|
\_ ->
outdented (prettyPrint input)
|> Expect.equal (outdented output)
]
multiSelector : Test
multiSelector =
let
input =
Fixtures.multiSelector
output =
"""
div.multiSelectorPage.multiSelectorHidden {
display: none;
width: 100%;
height: 100%;
}
span {
padding: 10px;
margin: 11px;
}
"""
in
describe "Multi-selector stylesheet"
[ test "pretty prints the expected output" <|
\_ ->
outdented (prettyPrint input)
|> Expect.equal (outdented output)
]
keyValue : Test
keyValue =
let
input =
Fixtures.keyValue
output =
"""
body {
-webkit-font-smoothing: none;
-moz-font-smoothing: none !important;
}
"""
in
describe "Custom key-value properties"
[ test "pretty prints the expected output" <|
\_ ->
outdented (prettyPrint input)
|> Expect.equal (outdented output)
]
underlineOnHoverMixin : Test
underlineOnHoverMixin =
let
input =
Fixtures.mixinUnderlineOnHoverStylesheet
output =
"""
a {
color: rgb(128, 127, 126);
}
a:hover {
color: rgb(23, 24, 25);
}
"""
in
describe "underline on hover link (mixin)"
[ test "pretty prints the expected output" <|
\_ ->
outdented (prettyPrint input)
|> Expect.equal (outdented output)
]
underlineOnHoverManual : Test
underlineOnHoverManual =
let
input =
Fixtures.manualUnderlineOnHoverStylesheet
output =
"""
a {
color: rgb(128, 127, 126);
}
a:hover {
color: rgb(23, 24, 25);
}
"""
in
describe "underline on hover link (manual)"
[ test "pretty prints the expected output" <|
\_ ->
outdented (prettyPrint input)
|> Expect.equal (outdented output)
]
greenOnHoverMixin : Test
greenOnHoverMixin =
let
input =
Fixtures.mixinGreenOnHoverStylesheet
output =
"""
button {
color: rgb(11, 22, 33);
}
button:hover {
color: rgb(0, 0, 122);
}
"""
in
describe "green on hover (mixin)"
[ test "pretty prints the expected output" <|
\_ ->
outdented (prettyPrint input)
|> Expect.equal (outdented output)
]
transformsStyle : Test
transformsStyle =
let
input =
Fixtures.transformsStylesheet
output =
"""
body {
transform: none;
transform: matrix(1, 2, 3, 4, 5, 6) matrix3d(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
transform: perspective(1);
transform: rotate(90deg) rotateX(3.14rad) rotateY(3.14grad) rotateZ(1turn) rotate3d(1, 1, 1, 90deg);
transform: scale(1) scale(1, 1) scaleX(1) scaleY(1) scale3d(1, 1, 1);
transform: skew(90deg) skew(90deg, 90deg) skewX(90deg) skewY(90deg);
transform: translate(1px) translate(1px, 1px) translateX(1px) translateY(1px) translate3d(1px, 1px, 1px);
transform-box: view-box;
transform-style: preserve-3d;
}
"""
in
describe "transforms"
[ test "pretty prints the expected output" <|
\_ ->
outdented (prettyPrint input)
|> Expect.equal (outdented output)
]
fonts : Test
fonts =
let
input =
Fixtures.fontStylesheet
output =
"""
body {
line-height: 14px;
font-family: serif;
font-family: "Gill Sans Extrabold", Helvetica, sans-serif;
font-size: x-small;
font-style: italic;
font-weight: bold;
font-weight: 100;
font-variant: small-caps;
font-variant: common-ligatures slashed-zero;
font-variant-numeric: oldstyle-nums tabular-nums stacked-fractions ordinal slashed-zero;
}
"""
in
describe "fonts"
[ test "pretty prints the expected output" <|
\_ ->
outdented (prettyPrint input)
|> Expect.equal (outdented output)
]
weightWarning : Test
weightWarning =
let
input =
Fixtures.fontWeightWarning
output =
"""
Invalid Stylesheet:
fontWeight 22 is invalid. Valid weights are: 100, 200, 300, 400, 500, 600, 700, 800, 900. Please see https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight#Values"""
in
describe "fontWeightWarning"
[ test "pretty prints the expected output" <|
\_ ->
outdented (prettyPrint input)
|> Expect.equal (outdented output)
]
hexWarning : Test
hexWarning =
let
input1 =
Fixtures.colorHexWarning
input2 =
Fixtures.colorHexAbbrWarning
output1 =
"""
Invalid Stylesheet:
The syntax of a hex-color is a token whose value consists of 3, 4, 6, or 8 hexadecimal digits. #ababah is not valid. Please see: https://drafts.csswg.org/css-color/#hex-notation"""
output2 =
"""
Invalid Stylesheet:
The syntax of a hex-color is a token whose value consists of 3, 4, 6, or 8 hexadecimal digits. #00i is not valid. Please see: https://drafts.csswg.org/css-color/#hex-notation"""
in
describe "colorHexWarning"
[ test "pretty prints the expected output" <|
\_ ->
outdented (prettyPrint input1)
|> Expect.equal (outdented output1)
, test "pretty prints the expected output" <|
\_ ->
outdented (prettyPrint input2)
|> Expect.equal (outdented output2)
]
pseudoElements : Test
pseudoElements =
let
input =
Fixtures.pseudoElementStylesheet
output =
"""
#Page {
margin: 10px;
color: #aaa;
}
#Page::before {
color: #fff;
}
#Page::after {
color: #000;
}
"""
in
describe "pseudo elements"
[ test "pretty prints the expected output" <|
\_ ->
outdented (prettyPrint input)
|> Expect.equal (outdented output)
]
pseudoClasses : Test
pseudoClasses =
let
input =
Fixtures.pseudoClassStylesheet
output =
"""
#Page {
color: #fff;
background-color: #aaa;
}
#Page:hover {
margin-top: 10px;
}
#Page:hover:focus {
color: #000;
}
#Page:first {
font-size: 3em;
}
#Page:disabled {
margin-top: 20px;
}
"""
in
describe "pseudo classes"
[ test "pretty prints the expected output" <|
\_ ->
outdented (prettyPrint input)
|> Expect.equal (outdented output)
]
backgrounds : Test
backgrounds =
let
input =
Fixtures.backgrounds
output =
"""
div {
background-color: rgb(128, 127, 126);
background-repeat: repeat-x;
background-repeat: repeat-y;
background-repeat: repeat no-repeat;
background-repeat: space round;
background-attachment: local;
background-attachment: scroll;
background-attachment: fixed;
background-blend-mode: color;
background-blend-mode: screen;
background-blend-mode: multiply;
background-blend-mode: overlay;
background-blend-mode: darken;
background-blend-mode: lighten;
background-blend-mode: color-dodge;
background-blend-mode: color-burn;
background-blend-mode: hard-light;
background-blend-mode: soft-light;
background-blend-mode: difference;
background-blend-mode: exclusion;
background-blend-mode: hue;
background-blend-mode: saturation;
background-blend-mode: luminosity;
background-clip: border-box;
background-clip: padding-box;
background-clip: content-box;
background-image: url(http://example.com/elm.png);
background-origin: border-box;
background-origin: padding-box;
background-origin: content-box;
background-size: cover;
background-size: contain;
background-size: 50px;
background-size: auto 20px;
background-position: center;
background-position: 10% 0;
}
"""
in
describe "borders"
[ test "pretty prints the expected output" <|
\_ ->
outdented (prettyPrint input)
|> Expect.equal (outdented output)
]

View File

@@ -0,0 +1,18 @@
{
"version": "1.0.0",
"summary": "Unit tests for elm-css",
"repository": "https://github.com/rtfeldman/elm-css.git",
"license": "BSD-3-Clause",
"source-directories": [
".",
"../src"
],
"exposed-modules": [],
"dependencies": {
"elm-community/elm-test": "3.0.0 <= v < 4.0.0",
"elm-lang/core": "5.0.0 <= v < 6.0.0",
"rtfeldman/elm-css-util": "1.0.2 <= v < 2.0.0",
"rtfeldman/node-test-runner": "3.0.1 <= v < 4.0.0"
},
"elm-version": "0.18.0 <= v < 0.19.0"
}

View File

@@ -0,0 +1,25 @@
var assert = require("chai").assert;
var path = require("path");
var emitter = require(path.join(__dirname, ".."));
var fs = require("fs");
var fixturesDir = path.join(__dirname, "fixtures");
describe("emitting", function() {
it("works with HomepageCss.elm", function (done) {
// Use an epic timeout, because Travis on Linux is SO SLOW.
this.timeout(6000000);
var projectDir = path.join(__dirname, "..", "examples");
var srcFile = path.join(projectDir, "src", "Stylesheets.elm");
var outputDir = __dirname;
emitter(projectDir, srcFile, outputDir).then(function() {
var expectedFile = path.join(fixturesDir, "homepage-compiled.css");
var expected = fs.readFileSync(expectedFile, {encoding: "utf8"});
var actual = fs.readFileSync(path.join(outputDir, "homepage.css"), {encoding: "utf8"});
return assert.strictEqual(expected, actual);
}).then(done, function() { setTimeout(assert.fail, 1); });
});
});

View File

@@ -0,0 +1,34 @@
header {
background-color: rgb(90, 90, 90);
box-sizing: border-box;
padding: -80px;
box-shadow: inset 2px 3px 4px #333;
}
nav {
display: inline-block;
padding-bottom: 12px;
}
.homepageNavLink {
margin: 12px;
color: rgb(255, 255, 255);
}
#ReactiveLogo {
display: inline-block;
margin-left: 150px;
margin-right: 80px;
vertical-align: middle;
}
#BuyTickets {
padding: 16px;
padding-left: 24px;
padding-right: 24px;
margin-left: 50px;
margin-right: auto;
color: rgb(255, 255, 255);
background-color: rgb(27, 217, 130);
vertical-align: middle;
}