Merge branch 'master' into main

This commit is contained in:
2021-10-03 13:26:11 +02:00
88 changed files with 5355 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
.gradle
build
.idea
local.properties
gradle.properties

138
build.gradle.kts Normal file
View File

@@ -0,0 +1,138 @@
plugins {
kotlin("multiplatform") version "1.5.31"
`maven-publish`
signing
}
group = "nl.astraeus"
version = "1.0.0"
repositories {
mavenLocal()
mavenCentral()
maven { setUrl("https://dl.bintray.com/kotlin/kotlin-eap") }
}
kotlin {
jvm()
js(BOTH) {
browser {
testTask {
useKarma {
useFirefox()
//useChrome()
}
}
}
}
sourceSets {
val commonMain by getting {}
val commonTest by getting {
dependencies {
implementation(kotlin("test-common"))
implementation(kotlin("test-annotations-common"))
}
}
val jvmTest by getting {
dependencies {
implementation(kotlin("test-junit"))
}
}
val jsTest by getting {
dependencies {
implementation(kotlin("test-js"))
}
}
}
}
extra["PUBLISH_GROUP_ID"] = "nl.astraeus"
extra["PUBLISH_VERSION"] = "1.0.0"
extra["PUBLISH_ARTIFACT_ID"] = "kotlin-css-generator"
// Stub secrets to let the project sync and build without the publication values set up
val signingKeyId: String by project
val signingPassword: String by project
val signingSecretKeyRingFile: String by project
val ossrhUsername: String by project
val ossrhPassword: String by project
extra["signing.keyId"] = signingKeyId
extra["signing.password"] = signingPassword
extra["signing.secretKeyRingFile"] = signingSecretKeyRingFile
extra["ossrhUsername"] = ossrhUsername
extra["ossrhPassword"] = ossrhPassword
publishing {
repositories {
maven {
name = "releases"
// change to point to your repo, e.g. http://my.org/repo
url = uri("http://nexus.astraeus.nl/nexus/content/repositories/releases")
credentials {
val nexusUsername: String by project
val nexusPassword: String by project
username = nexusUsername
password = nexusPassword
}
}
maven {
name = "snapshots"
// change to point to your repo, e.g. http://my.org/repo
url = uri("http://nexus.astraeus.nl/nexus/content/repositories/snapshots")
credentials {
val nexusUsername: String by project
val nexusPassword: String by project
username = nexusUsername
password = nexusPassword
}
}
maven {
name = "sonatype"
setUrl("https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/")
credentials {
username = ossrhUsername
password = ossrhPassword
}
}
}
// Configure all publications
publications.withType<MavenPublication> {
// Stub javadoc.jar artifact
//artifact(javadocJar.get())
// Provide artifacts information requited by Maven Central
pom {
name.set("kotlin-css-generator")
description.set("Kotlin css generator")
url.set("https://github.com/rnentjes/kotlin-css-generator")
licenses {
license {
name.set("MIT")
url.set("https://opensource.org/licenses/MIT")
}
}
developers {
developer {
id.set("rnentjes")
name.set("Rien Nentjes")
email.set("info@nentjes.com")
}
}
scm {
url.set("https://github.com/rnentjes/kotlin-css-generator")
}
}
}
}
signing {
sign(publishing.publications)
}

11
gradle.properties.example Normal file
View File

@@ -0,0 +1,11 @@
kotlin.code.style=official
kotlin.js.compiler=both
nexusUsername=deployment
nexusPassword=
signingKeyId=
signingPassword=
signingSecretKeyRingFile=
ossrhUsername=
ossrhPassword=

BIN
gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

183
gradlew vendored Executable file
View File

@@ -0,0 +1,183 @@
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
exec "$JAVACMD" "$@"

100
gradlew.bat vendored Normal file
View File

@@ -0,0 +1,100 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

98
publish/build.gradle.kts Normal file
View File

@@ -0,0 +1,98 @@
import java.util.*
plugins {
`maven-publish`
signing
}
repositories {
mavenCentral()
}
project.extra.set("PUBLISH_GROUP_ID", "nl.astraeus")
project.extra.set("PUBLISH_VERSION", "1.0.0")
project.extra.set("PUBLISH_ARTIFACT_ID", "kotlin-css-generator")
apply(from = "${rootProject.projectDir}/build.gradle.kts")
// Stub secrets to let the project sync and build without the publication values set up
extra["signing.keyId"] = null
extra["signing.password"] = null
extra["signing.secretKeyRingFile"] = null
extra["ossrhUsername"] = null
extra["ossrhPassword"] = null
// Grabbing secrets from local.properties file or from environment variables, which could be used on CI
val secretPropsFile = project.rootProject.file("local.properties")
if (secretPropsFile.exists()) {
secretPropsFile.reader().use {
Properties().apply {
load(it)
}
}.onEach { (name, value) ->
extra[name.toString()] = value
}
} else {
extra["signing.keyId"] = System.getenv("SIGNING_KEY_ID")
extra["signing.password"] = System.getenv("SIGNING_PASSWORD")
extra["signing.secretKeyRingFile"] = System.getenv("SIGNING_SECRET_KEY_RING_FILE")
extra["ossrhUsername"] = System.getenv("OSSRH_USERNAME")
extra["ossrhPassword"] = System.getenv("OSSRH_PASSWORD")
}
val javadocJar by tasks.registering(Jar::class) {
archiveClassifier.set("javadoc")
}
fun getExtraString(name: String) = extra[name]?.toString()
publishing {
// Configure maven central repository
repositories {
maven {
name = "sonatype"
setUrl("https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/")
credentials {
username = getExtraString("ossrhUsername")
password = getExtraString("ossrhPassword")
}
}
}
// Configure all publications
publications.withType<MavenPublication> {
// Stub javadoc.jar artifact
artifact(javadocJar.get())
// Provide artifacts information requited by Maven Central
pom {
name.set("kotlin-css-generator")
description.set("Kotlin css generator")
url.set("https://github.com/rnentjes/kotlin-css-generator")
licenses {
license {
name.set("MIT")
url.set("https://opensource.org/licenses/MIT")
}
}
developers {
developer {
id.set("rnentjes")
name.set("Rien Nentjes")
email.set("info@nentjes.com")
}
}
scm {
url.set("https://github.com/rnentjes/kotlin-css-generator")
}
}
}
}
// Signing artifacts. Signing.* extra properties values will be used
signing {
sign(publishing.publications)
}

View File

@@ -0,0 +1,121 @@
apply plugin: 'maven-publish'
apply plugin: 'signing'
task publishSourcesJar(type: Jar) {
archiveClassifier.set('sources')
// For pure Kotlin libraries, in case you have them
from sourceSets.main.java.srcDirs
//from sourceSets.main.kotlin.srcDirs
}
task packageJavadoc(type: Jar) {
from javadoc
classifier = 'javadoc'
}
artifacts {
archives publishSourcesJar
}
File secretPropsFile = project.rootProject.file('local.properties')
ext["signing.keyId"] = ''
ext["signing.password"] = ''
ext["signing.secretKeyRingFile"] = ''
ext["ossrhUsername"] = ''
ext["ossrhPassword"] = ''
ext["sonatypeStagingProfileId"] = ''
if (secretPropsFile.exists()) {
Properties p = new Properties()
new FileInputStream(secretPropsFile).withCloseable { is ->
p.load(is)
}
p.each { name, value ->
ext[name] = value
}
}
afterEvaluate {
publishing {
publications {
release(MavenPublication) {
// The coordinates of the library, being set from variables that
// we'll set up later
groupId PUBLISH_GROUP_ID
artifactId PUBLISH_ARTIFACT_ID
version PUBLISH_VERSION
// Two artifacts, the `aar` (or `jar`) and the sources
if (project.plugins.findPlugin("com.android.library")) {
artifact("$buildDir/outputs/aar/${project.getName()}-release.aar")
} else {
artifact("$buildDir/libs/${project.getName()}-${version}.jar")
}
artifact publishSourcesJar
artifact packageJavadoc
// Mostly self-explanatory metadata
pom {
name = PUBLISH_ARTIFACT_ID
description = 'Simple JDBC wrapper for query statistics'
url = 'https://github.com/rnentjes/Simple-jdbc-statistics'
licenses {
license {
name = 'MIT License'
url = 'https://github.com/rnentjes/Simple-jdbc-statistics/blob/master/LICENCE.txt'
}
}
developers {
developer {
id = 'rnentjes'
name = 'Rien Nentjes'
email = 'info@nentjes.com'
}
// Add all other devs here...
}
// Version control info - if you're using GitHub, follow the format as seen here
scm {
connection = 'scm:git:github.com/rnentjes/Simple-jdbc-statistics.git'
developerConnection = 'scm:git:ssh://github.com/rnentjes/Simple-jdbc-statistics.git'
url = 'https://github.com/rnentjes/Simple-jdbc-statistics.git/tree/main'
}
// A slightly hacky fix so that your POM will include any transitive dependencies
// that your library builds upon
/*
witXml {
def dependenciesNode = asNode().appendNode('dependencies')
project.configurations.implementation.allDependencies.each {
def dependencyNode = dependenciesNode.appendNode('dependency')
dependencyNode.appendNode('groupId', it.group)
dependencyNode.appendNode('artifactId', it.name)
dependencyNode.appendNode('version', it.version)
}
}*/
}
}
}
// The repository to publish to, Sonatype/MavenCentral
repositories {
maven {
// This is an arbitrary name, you may also use "mavencentral" or
// any other name that's descriptive for you
name = "sonatype"
url = "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/"
credentials {
username ossrhUsername
password ossrhPassword
}
}
}
}
}
signing {
sign publishing.publications
}

View File

@@ -0,0 +1,12 @@
pluginManagement {
repositories {
mavenCentral()
maven { setUrl("https://plugins.gradle.org/m2/") }
}
}
rootProject.name = "publish-kotlin-css-generator"
//enableFeaturePreview("GRADLE_METADATA")
//include(":publish")

160
readme.md Normal file
View File

@@ -0,0 +1,160 @@
# Css generator like less/sass in kotlin multiplatform
This library is for generating css from a kotlin dsl.
It can be used as an alternative to less/sass or as a runtime library to generate css on-the-fly.
Tools like less and sass are often used as a build step and take some time.
This library is meant to be fast enough to generate the css on the fly either from the server or directly in the browser.
Examples:
## Nesting / colors / variables
```kotlin
val color = hsla(0, 50, 50, 1.0)
val backgroundColor = Color.white
val css = style {
select(cls("button")) {
padding(5.px)
select("a") {
color(color)
backgroundColor(backgroundColor)
hover {
color(color.lighten(10))
backgroundColor(backgroundColor.darken(10))
}
}
}
}
```
To generate the css call get generateCss function:
```kotlin
val cssString: String = css.generateCss()
```
Result:
```css
.button {
padding: 5px;
}
.button a {
color: hsla(0, 50%, 50%, 1.0);
background-color: white;
}
.button a:hover {
color: hsla(0, 50%, 55%, 1.0);
background-color: rgba(229, 229, 229, 1.0);
}
```
There are several options when generating the css, for example minified:
```kotlin
val cssString: String = css.generateCss(minified = true)
```
Result:
```css
.button{padding:5px;}.buttona{color:hsla(0,50%,50%,1.0);background-color:white;}.buttona:hover{color:hsla(0,50%,55%,1.0);background-color:rgba(229,229,229,1.0);}
```
## Mixins
As it's all just kotlin code, includes and mixins etc. are just functions calls.
```kotlin
fun Style.borderStyles(borderWidth: Measurement = 2.px) {
borderWidth(borderWidth)
borderColor(Color.aquamarine)
borderStyle(BorderStyle.solid)
}
val css = style {
select(txt("a"), cls("button")) {
borderStyles()
color(Color.white)
}
select(cls("btn-primary")) {
borderStyles(3.px)
color(Color.blue)
}
}
```
Result:
```css
a {
border-width: 2px;
border-color: aquamarine;
border-style: solid;
color: white;
}
.button {
border-width: 2px;
border-color: aquamarine;
border-style: solid;
color: white;
}
.btn-primary {
border-width: 3px;
border-color: aquamarine;
border-style: solid;
color: blue;
}
```
Giving the option combineEqualBlocks to the generateCss call will combine the a and .button blocks with the following result:
```css
a,
.button {
border-width: 2px;
border-color: aquamarine;
border-style: solid;
color: white;
}
.btn-primary {
border-width: 3px;
border-color: aquamarine;
border-style: solid;
color: blue;
}
```
## Measurements
Sizes and widths are given in measurements, there are extension variables to help with these:
```kotlin
select("body") {
fontSize(1.2.em)
borderWidth(3.px)
width(75.prc)
}
```
Result:
```css
body {
font-size: 1.2em;
border-width: 3px;
width: 75%;
}
```

13
settings.gradle.kts Normal file
View File

@@ -0,0 +1,13 @@
pluginManagement {
repositories {
maven { setUrl("https://dl.bintray.com/kotlin/kotlin-eap") }
mavenCentral()
maven { setUrl("https://plugins.gradle.org/m2/") }
}
}
rootProject.name = "kotlin-css-generator"
//enableFeaturePreview("GRADLE_METADATA")

View File

@@ -0,0 +1,30 @@
package nl.astraeus.css
import nl.astraeus.css.style.ConditionalCss
import nl.astraeus.css.style.ConditionalStyle
import nl.astraeus.css.style.Css
import nl.astraeus.css.style.Style
fun css(definition: Css) = definition
fun style(definition: ConditionalCss): ConditionalStyle {
val css = ConditionalStyle()
definition(css)
return css
}
class CssBuilder {
var definition: Style = Style()
fun style(definition: Style.() -> Unit) {
definition(this.definition)
}
fun getCss(minified: Boolean = false): String = definition.generateCss(minified = minified)
override fun toString(): String {
return "CssBuilder(${definition.generateCss()})"
}
}

View File

@@ -0,0 +1,17 @@
package nl.astraeus.css.properties
class AlignContent(
value: String
) : CssProperty(value) {
companion object {
val stretch = AlignContent("stretch")
val center = AlignContent("center")
val flexStart = AlignContent("flex-start")
val flexEnd = AlignContent("flex-end")
val spaceBetween = AlignContent("space-between")
val spaceAround = AlignContent("space-around")
val initial = AlignContent("initial")
val inherit = AlignContent("inherit")
}
}

View File

@@ -0,0 +1,17 @@
package nl.astraeus.css.properties
class AlignItems(
value: String
) : CssProperty(value) {
companion object {
val stretch = AlignItems("stretch")
val center = AlignItems("center")
val flexStart = AlignItems("flex-start")
val flexEnd = AlignItems("flex-end")
val baseline = AlignItems("baseline")
val initial = AlignItems("initial")
val inherit = AlignItems("inherit")
}
}

View File

@@ -0,0 +1,18 @@
package nl.astraeus.css.properties
class AlignSelf(
value: String
) : CssProperty(value) {
companion object {
val auto = AlignSelf("auto")
val stretch = AlignSelf("stretch")
val center = AlignSelf("center")
val flexStart = AlignSelf("flex-start")
val flexEnd = AlignSelf("flex-end")
val baseline = AlignSelf("baseline")
val initial = AlignSelf("initial")
val inherit = AlignSelf("inherit")
}
}

View File

@@ -0,0 +1,14 @@
package nl.astraeus.css.properties
class All(
value: String
) : CssProperty(value) {
companion object {
val unset = All("unset")
val revert = All("revert")
val initial = All("initial")
val inherit = All("inherit")
}
}

View File

@@ -0,0 +1,55 @@
package nl.astraeus.css.properties
class AnimationDirection(
value: String
) : CssProperty(value) {
companion object {
val normal = AnimationDirection("normal")
val reverse = AnimationDirection("reverse")
val alternate = AnimationDirection("alternate")
val alternateReverse = AnimationDirection("alternate-reverse")
val initial = AnimationDirection("initial")
val inherit = AnimationDirection("inherit")
}
}
class AnimationFillMode(
value: String
) : CssProperty(value) {
companion object {
val none = AnimationFillMode("none")
val forwards = AnimationFillMode("forwards")
val backwards = AnimationFillMode("backwards")
val both = AnimationFillMode("both")
val initial = AnimationFillMode("initial")
val inherit = AnimationFillMode("inherit")
}
}
class AnimationFrame(
value: String = ""
) : CssProperty(value) {
companion object {
fun name(name: String) = AnimationFrame(name)
val none: AnimationFrame = AnimationFrame("none")
val initial: AnimationFrame = AnimationFrame("initial")
val inherit: AnimationFrame = AnimationFrame("inherit")
}
}
class AnimationPlayState(
value: String
) : CssProperty(value) {
companion object {
fun name(name: String) = AnimationPlayState(name)
val paused = AnimationPlayState("paused")
val running = AnimationPlayState("running")
val initial = AnimationPlayState("initial")
val inherit = AnimationPlayState("inherit")
}
}

View File

@@ -0,0 +1,13 @@
package nl.astraeus.css.properties
class BackfaceVisibility(
value: String
) : CssProperty(value) {
companion object {
val visible = BackfaceVisibility("visible")
val hidden = BackfaceVisibility("hidden")
val initial = BackfaceVisibility("initial")
val inherit = BackfaceVisibility("inherit")
}
}

View File

@@ -0,0 +1,79 @@
package nl.astraeus.css.properties
class BackgroundAttachment(
value: String
) : CssProperty(value) {
companion object {
val scroll = BackgroundAttachment("scroll")
val fixed = BackgroundAttachment("fixed")
val local = BackgroundAttachment("local")
val initial = BackgroundAttachment("initial")
val inherit = BackgroundAttachment("inherit")
}
}
class BackgroundBlendMode(
value: String
) : CssProperty(value) {
companion object {
val normal = BackgroundBlendMode("normal")
val multiply = BackgroundBlendMode("multiply")
val screen = BackgroundBlendMode("screen")
val overlay = BackgroundBlendMode("overlay")
val darken = BackgroundBlendMode("darken")
val lighten = BackgroundBlendMode("lighten")
val colorDodge = BackgroundBlendMode("color-dodge")
val saturation = BackgroundBlendMode("saturation")
val color = BackgroundBlendMode("color")
val luminosity = BackgroundBlendMode("luminosity")
}
}
class BackgroundPosition(
value: String
) : CssProperty(value) {
companion object {
val left = BackgroundPosition("left")
val center = BackgroundPosition("center")
val right = BackgroundPosition("right")
val initial = BackgroundPosition("initial")
val inherit = BackgroundPosition("inherit")
}
}
class BackgroundRepeat(
value: String
) : CssProperty(value) {
companion object {
val repeat = BackgroundRepeat("repeat")
val repeatX = BackgroundRepeat("repeat-x")
val repeatY = BackgroundRepeat("repeat-y")
val noRepeat = BackgroundRepeat("no-repeat")
val space = BackgroundRepeat("space")
val round = BackgroundRepeat("round")
val initial = BackgroundRepeat("initial")
val inherit = BackgroundRepeat("inherit")
val unset = BackgroundRepeat("unset")
}
}
class BackgroundSize(
value: String
) : CssProperty(value) {
companion object {
fun px(px: Int) = BackgroundSize("${px}px")
fun perc(pc: Double) = BackgroundSize("${pc}%")
val auto = BackgroundSize("auto")
val cover = BackgroundSize("cover")
val contain = BackgroundSize("contain")
val initial = BackgroundSize("initial")
val inherit = BackgroundSize("inherit")
}
}

View File

@@ -0,0 +1,78 @@
package nl.astraeus.css.properties
class BorderStyle(
value: String
) : CssProperty(value) {
companion object {
val none = BorderStyle("none")
val hidden = BorderStyle("hidden")
val dotted = BorderStyle("dotted")
val dashed = BorderStyle("dashed")
val solid = BorderStyle("solid")
val double = BorderStyle("double")
val groove = BorderStyle("groove")
val ridge = BorderStyle("ridge")
val inset = BorderStyle("inset")
val outset = BorderStyle("outset")
val initial = BorderStyle("initial")
val inherit = BorderStyle("inherit")
}
}
class BorderWidth(
value: String
) : CssProperty(value) {
companion object {
val thin = BorderWidth("thin")
val medium = BorderWidth("medium")
val thick = BorderWidth("thick")
val initial = BorderWidth("initial")
val inherit = BorderWidth("inherit")
}
}
class BorderCollapse(
value: String
) : CssProperty(value) {
companion object {
val separate = BorderCollapse("separate")
val collapse = BorderCollapse("collapse")
}
}
class BorderImageWidth(
value: String
) : CssProperty(value) {
companion object {
fun px(nr: Int) = BorderImageWidth("${nr}px")
fun nr(nr: Int) = BorderImageWidth("$nr")
fun perc(nr: Int) = BorderImageWidth("${nr}%")
fun perc(nr: Double) = BorderImageWidth("${nr}%")
val auto = BorderImageWidth("auto")
val initial = BorderImageWidth("initial")
val inherit = BorderImageWidth("inherit")
}
}
class BorderSpacing(
value: String
) : CssProperty(value) {
companion object {
fun px(nr: Int) = BorderSpacing("${nr}px")
fun em(nr: Int) = BorderSpacing("${nr}em")
fun em(nr: Double) = BorderSpacing("${nr}em")
fun perc(nr: Int) = BorderSpacing("${nr}%")
fun perc(nr: Double) = BorderSpacing("${nr}%")
fun pc(nr: Int) = BorderSpacing("${nr}pc")
fun pc(nr: Double) = BorderSpacing("${nr}pc")
fun cm(nr: Int) = BorderSpacing("${nr}cm")
fun cm(nr: Double) = BorderSpacing("${nr}cm")
val initial = BorderSpacing("initial")
val inherit = BorderSpacing("inherit")
}
}

View File

@@ -0,0 +1,40 @@
package nl.astraeus.css.properties
class BoxDecorationBreak(
value: String
) : CssProperty(value) {
companion object {
val slice = BoxDecorationBreak("slice")
val clone = BoxDecorationBreak("clone")
val initial = BoxDecorationBreak("initial")
val inherit = BoxDecorationBreak("inherit")
val unset = BoxDecorationBreak("unset")
}
}
class BoxShadow(
value: String
) : CssProperty(value) {
companion object {
val none = BoxShadow("none")
val inset = BoxShadow("inset")
val initial = BoxShadow("initial")
val inherit = BoxShadow("inherit")
fun text(txt: String) = BoxShadow(txt)
}
}
class BoxSizing(
value: String
) : CssProperty(value) {
companion object {
val contextBox = BoxSizing("content-box")
val borderBox = BoxSizing("border-box")
val initial = BoxShadow("initial")
val inherit = BoxShadow("inherit")
}
}

View File

@@ -0,0 +1,27 @@
package nl.astraeus.css.properties
class Break(
value: String
) : CssProperty(value) {
companion object {
val auto = Break("auto")
val all = Break("all")
val always = Break("always")
val avoid = Break("avoid")
val avoidColumn = Break("avoid-column")
val avoidPage = Break("avoid-page")
val avoidRegion = Break("avoid-region")
val column = Break("column")
val left = Break("left")
val page = Break("page")
val recto = Break("recto")
val region = Break("region")
val right = Break("right")
val verso = Break("verso")
val initial = Break("initial")
val inherit = Break("inherit")
}
}

View File

@@ -0,0 +1,14 @@
package nl.astraeus.css.properties
class CaptionSide(
value: String
) : CssProperty(value) {
companion object {
val top = CaptionSide("top")
val bottom = CaptionSide("bottom")
val initial = CaptionSide("initial")
val inherit = CaptionSide("inherit")
}
}

View File

@@ -0,0 +1,17 @@
package nl.astraeus.css.properties
class Clear(
value: String
) : CssProperty(value) {
companion object {
val none = Clear("none")
val left = Clear("left")
val right = Clear("right")
val both = Clear("both")
val initial = Clear("initial")
val inherit = Clear("inherit")
}
}

View File

@@ -0,0 +1,57 @@
package nl.astraeus.css.properties
class Clip(
value: String
) : CssProperty(value) {
companion object {
fun rect(top: Int, right: Int, bottom: Int, left: Int) = Clip("rect(${top}px,${right}px,${bottom}px,${left}px)")
val auto = Clip("auto")
val initial = Clip("initial")
val inherit = Clip("inherit")
}
}
class ClipPath(
value: String
) : CssProperty(value) {
companion object {
val auto = ClipPath("auto")
fun circle(perc: Double) = ClipPath("circle(${perc}%)")
fun ellipse(radiusX: Double, radiusY: Double) = ClipPath("ellipse(${radiusX}%,${radiusY}%)")
fun ellipse(
radiusX: Double,
radiusY: Double,
positionX: Double,
positionY: Double
) = ClipPath("ellipse(${radiusX}%,${radiusY}% at ${positionX}%,${positionY}%)")
// todo: other options
fun other(text: String) = ClipPath(text)
val marginBox = ClipPath("margin-box")
val borderBox = ClipPath("border-box")
val paddingBox = ClipPath("padding-box")
val contentBox = ClipPath("content-box")
val fillBox = ClipPath("fill-box")
val strokeBox = ClipPath("stroke-box")
val viewBox = ClipPath("view-box")
val none = ClipPath("none")
}
}
class ClipOrigin(
value: String
) : CssProperty(value) {
companion object {
val borderBox = ClipOrigin("border-box")
val paddingBox = ClipOrigin("padding-box")
val contentBox = ClipOrigin("content-box")
val initial = ClipOrigin("initial")
val inherit = ClipOrigin("inherit")
}
}

View File

@@ -0,0 +1,594 @@
package nl.astraeus.css.properties
import kotlin.math.PI
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.roundToInt
private val hexString = "0123456789abcdef"
private fun Int.toColorHex(minimumDigits: Int = 2): String {
val result = StringBuilder()
var value = this
while(value > 0) {
result.append(hexString[value%16])
value /= 16
}
while(result.length < minimumDigits) {
result.append("0")
}
return result.reverse().toString()
}
/**
* See [CSS Color Module Level 3](https://www.w3.org/TR/2018/REC-css-color-3-20180619/)
*
* This class represents a CSS color value. String parameters to the constructor argument
* can take one of the following forms:
*
* * HTML color name, e.g. ``Red``, ``DarkSalmon`` (case-insensitive), though in this case the use of the pre-defined constants is recommended.
* * ``#rgb`` or ``#rrggbb``
* * ``rgb(0..255, 0..255, 0..255)``, ``rgb(0..100%, 0..100%, 0..100%)``, ``rgb(0..100%, 0..100%, 0..100%, 0..1)``, ``rgba(0..255, 0..255, 0..255, 0..1)``
* * ``hsl(0..360, 0-100%, 0..100%)`` or ``hsla(0..360, 0-100%, 0..100%, 0..1)``
*
* Technically, the Hue parameter to ``hsl`` or ``hsla`` can exceed ``360``, because it represents a *degree* (angle) on
* the color wheel. But as per the algorithm proposed by the W3C, the value will ultimately be capped to ``360`` through
* a series of modulus operations; see section *4.2.4. HSL color values* of the above specification.
*
* Taken from: https://github.com/JetBrains/kotlin-wrappers/tree/master/kotlin-css
*/
@Suppress("SpellCheckingInspection")
class Color(value: String) : CssProperty(value) {
private var rgb: String? = null
private constructor(value: String, rgb: String) : this(value) {
this.rgb = rgb
}
fun hasAlpha(): Boolean = isRgba() || isHexa() || isHsla()
fun getAlpha(): Double = when {
isHexa() || isRgba() -> {
toRGBA().alpha
}
isHsla() -> {
fromHSLANotation().alpha
}
else -> {
1.0
}
}
fun toHex(): String = if (isHsla() || isHsl()) {
fromHSLANotation().asRGBA().asHex()
} else {
toRGBA().asHex()
}
fun isHsla(): Boolean {
val v = rgb ?: value
return v.startsWith("hsla")
}
fun isHsl(): Boolean {
val v = rgb ?: value
return v.startsWith("hsl(")
}
fun isRgba(): Boolean {
val v = rgb ?: value
return v.startsWith("rgba(")
}
fun isRgb(): Boolean {
val v = rgb ?: value
return v.startsWith("rgb(")
}
fun isHex(): Boolean {
val v = rgb ?: value
return v.startsWith("#") && v.length < 8
}
fun isHexa(): Boolean {
val v = rgb ?: value
return v.startsWith("#") && v.length > 7
}
/**
* withAlpha preserves existing alpha value: rgba(0, 0, 0, 0.5).withAlpha(0.1) = rgba(0, 0, 0, 0.05)
*/
fun withAlpha(alpha: Double) =
when {
value.startsWith("hsl", true) -> with(fromHSLANotation()) { hsla(hue, saturation, lightness, normalizeAlpha(alpha) * this.alpha) }
else -> with(toRGBA()) { rgba(red, green, blue, normalizeAlpha(alpha) * this.alpha) }
}
/**
* changeAlpha rewrites existing alpha value: rgba(0, 0, 0, 0.5).withAlpha(0.1) = rgba(0, 0, 0, 0.1)
*/
fun changeAlpha(alpha: Double) =
when {
value.startsWith("hsl", true) -> with(fromHSLANotation()) { hsla(hue, saturation, lightness, normalizeAlpha(alpha)) }
else -> with(toRGBA()) { rgba(red, green, blue, normalizeAlpha(alpha)) }
}
// https://stackoverflow.com/questions/2049230/convert-rgba-color-to-rgb
fun blend(backgroundColor: Color): Color {
val source = this.toRGBA()
val background = backgroundColor.toRGBA()
val targetR = ((1 - source.alpha) * background.red) + (source.alpha * source.red)
val targetG = ((1 - source.alpha) * background.green) + (source.alpha * source.green)
val targetB = ((1 - source.alpha) * background.blue) + (source.alpha * source.blue)
return rgb(targetR.roundToInt(), targetG.roundToInt(), targetB.roundToInt())
}
/**
* Lighten the color by the specified percent (between 0-100), returning a new instance of Color.
*
* @param percent the percent to lighten the Color
* @return a new lightened version of this color
*/
fun lighten(percent: Int): Color {
val isHSLA = value.startsWith("hsl", ignoreCase = true)
val hsla = if (isHSLA) fromHSLANotation() else toRGBA().asHSLA()
val lightness = hsla.lightness + (hsla.lightness * (normalizePercent(percent) / 100.0)).roundToInt()
val newHSLa = hsla.copy(lightness = normalizePercent(lightness))
return if (isHSLA) {
hsla(newHSLa.hue, newHSLa.saturation, newHSLa.lightness, newHSLa.alpha)
} else {
with(newHSLa.asRGBA()) { rgba(red, green, blue, alpha) }
}
}
/**
* Darken the color by the specified percent (between 0-100), returning a new instance of Color.
*
* @param percent the percent to darken the Color
* @return a new darkened version of this color
*/
fun darken(percent: Int): Color {
val isHSLA = value.startsWith("hsl", ignoreCase = true)
val hsla = if (isHSLA) fromHSLANotation() else toRGBA().asHSLA()
val darkness = hsla.lightness - (hsla.lightness * (normalizePercent(percent) / 100.0)).roundToInt()
val newHSLa = hsla.copy(lightness = normalizePercent(darkness))
return if (isHSLA) {
hsla(newHSLa.hue, newHSLa.saturation, newHSLa.lightness, newHSLa.alpha)
} else {
with(newHSLa.asRGBA()) { rgba(red, green, blue, alpha) }
}
}
/**
* Increase contrast, if lightness > 50 then darken else lighten
*
* @param percent the percent to lighten/darken the Color
* @return a new ligtened/darkened version of this color
*/
fun contrast(percent: Int): Color {
val isHSLA = value.startsWith("hsl", ignoreCase = true)
val hsla = if (isHSLA) fromHSLANotation() else toRGBA().asHSLA()
val darkness = if (hsla.lightness > 50) {
hsla.lightness - (hsla.lightness * (normalizePercent(percent) / 100.0)).roundToInt()
} else {
hsla.lightness + (hsla.lightness * (normalizePercent(percent) / 100.0)).roundToInt()
}
val newHSLa = hsla.copy(lightness = normalizePercent(darkness))
return if (isHSLA) {
hsla(newHSLa.hue, newHSLa.saturation, newHSLa.lightness, newHSLa.alpha)
} else {
with(newHSLa.asRGBA()) { rgba(red, green, blue, alpha) }
}
}
/**
* Saturate the color by the specified percent (between 0-100), returning a new instance of Color.
*
* @param percent the percent to saturate the Color
* @return a new saturated version of this color
*/
fun saturate(percent: Int): Color {
val isHSLA = value.startsWith("hsl", ignoreCase = true)
val hsla = if (isHSLA) fromHSLANotation() else toRGBA().asHSLA()
val saturation = hsla.saturation + (hsla.saturation * (normalizePercent(percent) / 100.0)).roundToInt()
val newHSLa = hsla.copy(saturation = normalizePercent(saturation))
return if (isHSLA) {
hsla(newHSLa.hue, newHSLa.saturation, newHSLa.lightness, newHSLa.alpha)
} else {
with(newHSLa.asRGBA()) { rgba(red, green, blue, alpha) }
}
}
/**
* Desaturate the color by the specified percent (between 0-100), returning a new instance of Color.
*
* @param percent the percent to desaturate the Color
* @return a new desaturated version of this color
*/
fun desaturate(percent: Int): Color {
val isHSLA = value.startsWith("hsl", ignoreCase = true)
val hsla = if (isHSLA) fromHSLANotation() else toRGBA().asHSLA()
val desaturation = hsla.saturation - (hsla.saturation * (normalizePercent(percent) / 100.0)).roundToInt()
val newHSLa = hsla.copy(saturation = normalizePercent(desaturation))
return if (isHSLA) {
hsla(newHSLa.hue, newHSLa.saturation, newHSLa.lightness, newHSLa.alpha)
} else {
with(newHSLa.asRGBA()) { rgba(red, green, blue, alpha) }
}
}
internal data class RGBA(
val red: Int,
val green: Int,
val blue: Int,
val alpha: Double = 1.0
) {
// Algorithm adapted from http://www.niwa.nu/2013/05/math-behind-colorspace-conversions-rgb-hsl/
fun asHSLA(): HSLA {
// scale R, G, B values into 0..1 fractions
val r = red / 255.0
val g = green / 255.0
val b = blue / 255.0
val cMax = maxOf(r, g, b)
val cMin = minOf(r, g, b)
val chroma = cMax - cMin
val lg = normalizeFractionalPercent((cMax + cMin) / 2)
val s = if (chroma != 0.0) normalizeFractionalPercent(chroma / (1.0 - abs((2.0 * lg) - 1.0))) else 0.0
val h = when (cMax) {
cMin -> 0.0
r -> 60 * (((g - b) / chroma) % 6.0)
g -> 60 * (((b - r) / chroma) + 2)
b -> 60 * (((r - g) / chroma) + 4)
else -> error("Unexpected value for max") // theoretically unreachable bc maxOf(r, g, b) above
}
return HSLA(normalizeHue(h), (s * 100).roundToInt(), (lg * 100).roundToInt(), alpha)
}
fun asHex(): String {
val result = StringBuilder()
result.append(red.toColorHex(2))
result.append(green.toColorHex(2))
result.append(blue.toColorHex(2))
return result.toString()
}
}
internal data class HSLA(
val hue: Int,
val saturation: Int,
val lightness: Int,
val alpha: Double = 1.0
) {
// Algorithm from W3C link referenced in class comment (section 4.2.4. HSL color values)
fun asRGBA(): RGBA {
fun hueToRGB(m1: Double, m2: Double, h: Double): Double {
val hu = if (h < 0) h + 1 else if (h > 1) h - 1 else h
return when {
(hu < 1.0 / 6) -> m1 + (m2 - m1) * 6 * hu
(hu < 1.0 / 2) -> m2
(hu < 2.0 / 3) -> m1 + ((m2 - m1) * 6 * (2.0 / 3 - hu))
else -> m1
}
}
val lightness255 = lightness * 255 / 100
if (saturation == 0) return RGBA(lightness255, lightness255, lightness255)
// scale H, S, V values into 0..1 fractions
val h = (hue % 360.0) / 360.0
val s = saturation / 100.0
val lg = lightness / 100.0
val m2 = if (lg < 0.5) lg * (1 + s) else (lg + s - lg * s)
val m1 = 2 * lg - m2
val r = normalizeFractionalPercent(hueToRGB(m1, m2, h + (1.0 / 3)))
val g = normalizeFractionalPercent(hueToRGB(m1, m2, h))
val b = normalizeFractionalPercent(hueToRGB(m1, m2, h - (1.0 / 3)))
return RGBA((r * 255).roundToInt(), (g * 255).roundToInt(), (b * 255).roundToInt(), alpha)
}
}
internal fun fromHSLANotation(): HSLA {
val match = HSLA_REGEX.find(value)
fun getHSLParameter(index: Int) =
match?.groups?.get(index)?.value
?: throw IllegalArgumentException("Expected hsl or hsla notation, got $value")
val hueShape = getHSLParameter(1)
val hue = normalizeHue(
when {
hueShape.endsWith("grad", true) -> hueShape.substringBefore("grad").toDouble() * (9.0 / 10)
hueShape.endsWith("rad", true) -> (hueShape.substringBefore("rad").toDouble() * 180) / PI
hueShape.endsWith("turn", true) -> hueShape.substringBefore("turn").toDouble() * 360.0
hueShape.endsWith("deg", true) -> hueShape.substringBefore("deg").toDouble()
else -> hueShape.toDouble()
}
)
val saturation = normalizePercent(getHSLParameter(2).toInt())
val lightness = normalizePercent(getHSLParameter(3).toInt())
val alpha = normalizeAlpha(match?.groups?.get(4)?.value?.toDouble() ?: 1.0)
return HSLA(hue, saturation, lightness, alpha)
}
internal fun fromRGBANotation(): RGBA {
val match = RGBA_REGEX.find(value)
fun getRGBParameter(index: Int): Int {
val group = match?.groups?.get(index)?.value
?: throw IllegalArgumentException("Expected rgb or rgba notation, got $value")
return when {
(group.endsWith('%')) -> (normalizeFractionalPercent(group.substringBefore('%').toDouble() / 100.0) * 255.0).toInt()
else -> normalizeRGB(group.toInt())
}
}
val red = getRGBParameter(1)
val green = getRGBParameter(2)
val blue = getRGBParameter(3)
val alpha = normalizeAlpha(match?.groups?.get(4)?.value?.toDouble() ?: 1.0)
return RGBA(red, green, blue, alpha)
}
internal fun toRGBA(): RGBA {
val v = rgb ?: value
return when {
v.startsWith("rgb") -> fromRGBANotation()
// Matches #rgb
v.startsWith("#") && v.length == 4 -> RGBA(
"${v[1]}${v[1]}".toInt(16),
"${v[2]}${v[2]}".toInt(16),
"${v[3]}${v[3]}".toInt(16)
)
// Matches both #rrggbb
v.startsWith("#") && v.length == 7 -> RGBA(
(v.substring(1..2)).toInt(16),
(v.substring(3..4)).toInt(16),
(v.substring(5..6)).toInt(16)
)
// Matches both #rrggbbaa
v.startsWith("#") && v.length == 9 -> RGBA(
(v.substring(1..2)).toInt(16),
(v.substring(3..4)).toInt(16),
(v.substring(5..6)).toInt(16),
(v.substring(7..8)).toInt(16) / 255.0
)
else -> throw IllegalArgumentException("Only hexadecimal, rgb, and rgba notations are accepted, got $v")
}
}
companion object {
val initial = Color("initial")
val inherit = Color("inherit")
val unset = Color("unset")
val transparent = Color("transparent")
val currentColor = Color("currentColor")
// W3C predefined HTML colors (147), see the referenced specification above.
val aliceBlue = Color("aliceblue", "#f0f8ff")
val antiqueWhite = Color("antiquewhite", "#faebd7")
val aqua = Color("aqua", "#00ffff")
val aquamarine = Color("aquamarine", "#7fffd4")
val azure = Color("azure", "#f0ffff")
val beige = Color("beige", "#f5f5dc")
val bisque = Color("bisque", "#ffe4c4")
val black = Color("black", "#000000")
val blanchedAlmond = Color("blanchedalmond", "#ffebcd")
val blue = Color("blue", "#0000ff")
val blueViolet = Color("blueviolet", "#8a2be2")
val brown = Color("brown", "#a52a2a")
val burlyWood = Color("burlywood", "#deb887")
val cadetBlue = Color("cadetblue", "#5f9ea0")
val chartreuse = Color("chartreuse", "#7fff00")
val chocolate = Color("chocolate", "#d2691e")
val coral = Color("coral", "#ff7f50")
val cornflowerBlue = Color("cornflowerblue", "#6495ed")
val cornsilk = Color("cornsilk", "#fff8dc")
val crimson = Color("crimson", "#dc143c")
val cyan = Color("cyan", "#00ffff")
val darkBlue = Color("darkblue", "#00008b")
val darkCyan = Color("darkcyan", "#008b8b")
val darkGoldenrod = Color("darkgoldenrod", "#b8860b")
val darkGray = Color("darkgray", "#a9a9a9")
val darkGreen = Color("darkgreen", "#006400")
val darkGrey = Color("darkgrey", "#a9a9a9")
val darkKhaki = Color("darkkhaki", "#bdb76b")
val darkMagenta = Color("darkmagenta", "#8b008b")
val darkOliveGreen = Color("darkolivegreen", "#556b2f")
val darkOrange = Color("darkorange", "#ff8c00")
val darkOrchid = Color("darkorchid", "#9932cc")
val darkRed = Color("darkred", "#8b0000")
val darkSalmon = Color("darksalmon", "#e9967a")
val darkSeaGreen = Color("darkseagreen", "#8fbc8f")
val darkSlateBlue = Color("darkslateblue", "#483d8b")
val darkSlateGray = Color("darkslategray", "#2f4f4f")
val darkSlateGrey = Color("darkslategrey", "#2f4f4f")
val darkTurquoise = Color("darkturquoise", "#00ced1")
val darkViolet = Color("darkviolet", "#9400d3")
val deepPink = Color("deeppink", "#ff1493")
val deepSkyBlue = Color("deepskyblue", "#00bfff")
val dimGray = Color("dimgray", "#696969")
val dimGrey = Color("dimgrey", "#696969")
val dodgerBlue = Color("dodgerblue", "#1e90ff")
val firebrick = Color("firebrick", "#b22222")
val floralWhite = Color("floralwhite", "#fffaf0")
val forestGreen = Color("forestgreen", "#228b22")
val fuchsia = Color("fuchsia", "#ff00ff")
val gainsboro = Color("gainsboro", "#dcdcdc")
val ghostWhite = Color("ghostwhite", "#f8f8ff")
val gold = Color("gold", "#ffd700")
val goldenrod = Color("goldenrod", "#daa520")
val gray = Color("gray", "#808080")
val green = Color("green", "#008000")
val greenYellow = Color("greenyellow", "#adff2f")
val grey = Color("grey", "#808080")
val honeydew = Color("honeydew", "#f0fff0")
val hotPink = Color("hotpink", "#ff69b4")
val indianRed = Color("indianred", "#cd5c5c")
val indigo = Color("indigo", "#4b0082")
val ivory = Color("ivory", "#fffff0")
val khaki = Color("khaki", "#f0e68c")
val lavender = Color("lavender", "#e6e6fa")
val lavenderBlush = Color("lavenderblush", "#fff0f5")
val lawnGreen = Color("lawngreen", "#7cfc00")
val lemonChiffon = Color("lemonchiffon", "#fffacd")
val lightBlue = Color("lightblue", "#add8e6")
val lightCoral = Color("lightcoral", "#f08080")
val lightCyan = Color("lightcyan", "#e0ffff")
val lightGoldenrodYellow = Color("lightgoldenrodyellow", "#fafad2")
val lightGray = Color("lightgray", "#d3d3d3")
val lightGreen = Color("lightgreen", "#90ee90")
val lightGrey = Color("lightgrey", "#d3d3d3")
val lightPink = Color("lightpink", "#ffb6c1")
val lightSalmon = Color("lightsalmon", "#ffa07a")
val lightSeaGreen = Color("lightseagreen", "#20b2aa")
val lightSkyBlue = Color("lightskyblue", "#87cefa")
val lightSlateGray = Color("lightslategray", "#778899")
val lightSlateGrey = Color("lightslategrey", "#778899")
val lightSteelBlue = Color("lightsteelblue", "#b0c4de")
val lightYellow = Color("lightyellow", "#ffffe0")
val lime = Color("lime", "#00ff00")
val limeGreen = Color("limegreen", "#32cd32")
val linen = Color("linen", "#faf0e6")
val magenta = Color("magenta", "#ff00ff")
val maroon = Color("maroon", "#800000")
val mediumAquamarine = Color("mediumaquamarine", "#66cdaa")
val mediumBlue = Color("mediumblue", "#0000cd")
val mediumOrchid = Color("mediumorchid", "#ba55d3")
val mediumPurple = Color("mediumpurple", "#9370d8")
val mediumSeaGreen = Color("mediumseagreen", "#3cb371")
val mediumSlateBlue = Color("mediumslateblue", "#7b68ee")
val mediumSpringGreen = Color("mediumspringgreen", "#00fa9a")
val mediumTurquoise = Color("mediumturquoise", "#48d1cc")
val mediumVioletRed = Color("mediumvioletred", "#c71585")
val midnightBlue = Color("midnightblue", "#191970")
val mintCream = Color("mintcream", "#f5fffa")
val mistyRose = Color("mistyrose", "#ffe4e1")
val moccasin = Color("moccasin", "#ffe4b5")
val navajoWhite = Color("navajowhite", "#ffdead")
val navy = Color("navy", "#000080")
val oldLace = Color("oldlace", "#fdf5e6")
val olive = Color("olive", "#808000")
val oliveDrab = Color("olivedrab", "#6b8e23")
val orange = Color("orange", "#ffa500")
val orangeRed = Color("orangered", "#ff4500")
val orchid = Color("orchid", "#da70d6")
val paleGoldenrod = Color("palegoldenrod", "#eee8aa")
val paleGreen = Color("palegreen", "#98fb98")
val paleTurquoise = Color("paleturquoise", "#afeeee")
val paleVioletRed = Color("palevioletred", "#db7093")
val papayaWhip = Color("papayawhip", "#ffefd5")
val peachPuff = Color("peachpuff", "#ffdab9")
val peru = Color("peru", "#cd853f")
val pink = Color("pink", "#ffc0cb")
val plum = Color("plum", "#dda0dd")
val powderBlue = Color("powderblue", "#b0e0e6")
val purple = Color("purple", "#800080")
val red = Color("red", "#ff0000")
val rosyBrown = Color("rosybrown", "#bc8f8f")
val royalBlue = Color("royalblue", "#4169e1")
val saddleBrown = Color("saddlebrown", "#8b4513")
val salmon = Color("salmon", "#fa8072")
val sandyBrown = Color("sandybrown", "#f4a460")
val seaGreen = Color("seagreen", "#2e8b57")
val seaShell = Color("seashell", "#fff5ee")
val sienna = Color("sienna", "#a0522d")
val silver = Color("silver", "#c0c0c0")
val skyBlue = Color("skyblue", "#87ceeb")
val slateBlue = Color("slateblue", "#6a5acd")
val slateGray = Color("slategray", "#708090")
val slateGrey = Color("slategrey", "#708090")
val snow = Color("snow", "#fffafa")
val springGreen = Color("springgreen", "#00ff7f")
val steelBlue = Color("steelblue", "#4682b4")
val tan = Color("tan", "#d2b48c")
val teal = Color("teal", "#008080")
val thistle = Color("thistle", "#d8bfd8")
val tomato = Color("tomato", "#ff6347")
val turquoise = Color("turquoise", "#40e0d0")
val violet = Color("violet", "#ee82ee")
val wheat = Color("wheat", "#f5deb3")
val white = Color("white", "#ffffff")
val whiteSmoke = Color("whitesmoke", "#f5f5f5")
val yellow = Color("yellow", "#ffff00")
val yellowGreen = Color("yellowgreen", "#9acd32")
fun normalizeFractionalPercent(value: Double): Double =
value.coerceIn(minimumValue = 0.0, maximumValue = 1.0)
fun normalizePercent(value: Int): Int =
value.coerceIn(minimumValue = 0, maximumValue = 100)
fun normalizeRGB(value: Int): Int =
value.coerceIn(minimumValue = 0, maximumValue = 255)
// algorithm for capping from W3C
fun normalizeHue(value: Double): Int =
(((value % 360) + 360) % 360).roundToInt()
fun normalizeAlpha(value: Double): Double =
normalizeFractionalPercent(value)
// Match for hsl(int, int%, int%) | hsla(int, int%, int%, 0.5) | etc.
private val HSLA_REGEX by lazy {
Regex(
"^hsla?\\((-?[0-9]+\\.?[0-9]*(?:deg|grad|rad|turn)?)\\s*[, ]?\\s*(\\d{1,3})%\\s*[, ]\\s*(\\d{1,3})%\\s*[, ]?\\s*(\\d|(?:\\d?\\.\\d+))?\\)\$",
RegexOption.IGNORE_CASE
)
}
// Match for rgb(255, 255, 255) | rgba(255, 255, 255, 0.5) | rgb(100% 100% 100%) | etc.
private val RGBA_REGEX by lazy {
Regex(
"^rgba?\\((\\d{1,3}%?)\\s*[, ]\\s*(\\d{1,3}%?)\\s*[, ]\\s*(\\d{1,3}%?)[, ]?\\s*(\\d|(?:\\d?\\.\\d+))?\\)\$",
RegexOption.IGNORE_CASE
)
}
}
}
private fun String.withZeros() = this + "0".repeat(max(0, 3 - this.length))
fun hex(value: Int) = Color("#${value.toString(16).withZeros()}")
fun rgb(red: Int, green: Int, blue: Int) = Color("rgb($red, $green, $blue)")
fun rgba(red: Int, green: Int, blue: Int, alpha: Double) = Color("rgba($red, $green, $blue, ${formatAlpha(alpha)})")
fun hsl(hue: Int, saturation: Int, lightness: Int) = Color("hsl($hue, $saturation%, $lightness%)")
fun hsla(hue: Int, saturation: Int, lightness: Int, alpha: Double) = Color("hsla($hue, $saturation%, $lightness%, ${formatAlpha(alpha)})")
fun blackAlpha(alpha: Double) = Color.black.withAlpha(alpha)
fun whiteAlpha(alpha: Double) = Color.white.withAlpha(alpha)
private fun formatAlpha(alpha: Double): String =
alpha.toString().let {
if ("." in it) it else "$it.0"
}

View File

@@ -0,0 +1,33 @@
package nl.astraeus.css.properties
class Length(
value: String
) : CssProperty(value) {
companion object {
fun px(nr: Int) = Length("${nr}px")
fun em(nr: Int) = Length("${nr}em")
fun em(nr: Double) = Length("${nr}em")
fun perc(nr: Int) = Length("${nr}%")
fun perc(nr: Double) = Length("${nr}%")
fun pc(nr: Int) = Length("${nr}pc")
fun pc(nr: Double) = Length("${nr}pc")
fun cm(nr: Int) = Length("${nr}cm")
fun cm(nr: Double) = Length("${nr}cm")
val initial = Length("initial")
val inherit = Length("inherit")
}
}
class Fill(
value: String
) : CssProperty(value) {
companion object {
val balance = Fill("balance")
val auto = Fill("auto")
val initial = Fill("initial")
val inherit = Fill("inherit")
}
}

View File

@@ -0,0 +1,23 @@
package nl.astraeus.css.properties
class Content(
value: String
) : CssProperty(value) {
companion object {
val normal = Content("normal")
val none = Content("none")
val counter = Content("counter")
val openQuote = Content("open-quote")
val closeQuote = Content("close-quote")
val noOpenQuote = Content("no-open-quote")
val noCloseQuote = Content("no-close-quote")
val initial = Content("initial")
val inherit = Content("inherit")
fun attr(attribute: String) = Content("attr($attribute)")
fun string(txt: String) = Content("\"$txt\"")
fun url(url: String) = Content("url($url)")
}
}

View File

@@ -0,0 +1,15 @@
package nl.astraeus.css.properties
class Count(
value: String
) : CssProperty(value) {
companion object {
val auto: Count = Count("auto")
val infinite: Count = Count("infinite")
val initial: Count = Count("initial")
val inherit: Count = Count("inherit")
fun count(number: Int): Count = Count("$number")
}
}

View File

@@ -0,0 +1,15 @@
package nl.astraeus.css.properties
class CssFloat(
value: String
) : CssProperty(value) {
companion object {
val none = CssFloat("none")
val left = CssFloat("left")
val right = CssFloat("right")
val initial = CssFloat("initial")
val inherit = CssFloat("inherit")
}
}

View File

@@ -0,0 +1,19 @@
package nl.astraeus.css.properties
interface CssValue {
fun css(): String
}
open class CssProperty(
var value: String
) : CssValue {
override fun css(): String = value
}
fun text(value: String) = TextProperty(value)
class TextProperty(
value: String
) : CssProperty(value)

View File

@@ -0,0 +1,14 @@
package nl.astraeus.css.properties
class DelayDuration(
value: String
) : CssProperty(value) {
companion object {
val initial = DelayDuration("initial")
val inherit = DelayDuration("inherit")
fun seconds(seconds: Int) = DelayDuration("${seconds}s")
fun millis(milliSeconds: Int) = DelayDuration("${milliSeconds}ms")
}
}

View File

@@ -0,0 +1,14 @@
package nl.astraeus.css.properties
class Direction(
value: String
) : CssProperty(value) {
companion object {
val ltr = Direction("ltr")
val rtl = Direction("rtl")
val initial = Direction("initial")
val inherit = Direction("inherit")
}
}

View File

@@ -0,0 +1,33 @@
package nl.astraeus.css.properties
class Display(
value: String
) : CssProperty(value) {
companion object {
val inline = Display("inline")
val block = Display("block")
val contents = Display("contents")
val flex = Display("flex")
val grid = Display("grid")
val inlineBlock = Display("inline-block")
val inlineFlex = Display("inline-flex")
val inlineGrid = Display("inline-grid")
val inlineTable = Display("inline-table")
val listItem = Display("list-item")
val runIn = Display("run-in")
val table = Display("table")
val tableCaption = Display("table-caption")
val tableColumnGroup = Display("table-column-group")
val tableHeaderGroup = Display("table-header-group")
val tableFooterGroup = Display("table-footer-group")
val tableRowGroup = Display("table-row-group")
val tableCell = Display("table-cell")
val tableColumn = Display("table-column")
val tableRow = Display("table-row")
val none = Display("none")
val initial = Display("initial")
val inherit = Display("inherit")
}
}

View File

@@ -0,0 +1,14 @@
package nl.astraeus.css.properties
class EmptyCells(
value: String
) : CssProperty(value) {
companion object {
val show = EmptyCells("show")
val hide = EmptyCells("hide")
val initial = EmptyCells("initial")
val inherit = EmptyCells("inherit")
}
}

View File

@@ -0,0 +1,43 @@
package nl.astraeus.css.properties
class FlexDirection(
value: String
) : CssProperty(value) {
companion object {
val row = FlexDirection("row")
val rowReverse = FlexDirection("row-reverse")
val column = FlexDirection("column")
val columnReverse = FlexDirection("column-reverse")
val initial = FlexDirection("initial")
val inherit = FlexDirection("inherit")
}
}
class FlexGrowShrink(
value: String
) : CssProperty(value) {
companion object {
val initial = FlexGrowShrink("initial")
val inherit = FlexGrowShrink("inherit")
fun number(number: Int) = FlexGrowShrink("$number")
}
}
class FlexWrap(
value: String
) : CssProperty(value) {
companion object {
val nowrap = FlexWrap("nowrap")
val wrap = FlexWrap("wrap")
val wrapReverse = FlexWrap("wrap-reverse")
val initial = FlexWrap("initial")
val inherit = FlexWrap("inherit")
}
}

View File

@@ -0,0 +1,142 @@
package nl.astraeus.css.properties
class FontSize(
value: String
) : CssProperty(value) {
companion object {
val xxSmall = FontSize("xx-small")
val xSmall = FontSize("x-small")
val small = FontSize("small")
val medium = FontSize("medium")
val large = FontSize("large")
val xLarge = FontSize("x-large")
val xxLarge = FontSize("xx-large")
val smaller = FontSize("smaller")
val larger = FontSize("larger")
val initial = FontSize("initial")
val inherit = FontSize("inherit")
fun px(nr: Int) = FontSize("${nr}px")
fun em(nr: Int) = FontSize("${nr}em")
fun em(nr: Double) = FontSize("${nr}em")
fun perc(nr: Int) = FontSize("${nr}%")
fun perc(nr: Double) = FontSize("${nr}%")
fun pc(nr: Int) = FontSize("${nr}pc")
fun pc(nr: Double) = FontSize("${nr}pc")
fun cm(nr: Int) = FontSize("${nr}cm")
fun cm(nr: Double) = FontSize("${nr}cm")
}
}
class FontStretch(
value: String
) : CssProperty(value) {
companion object {
val normal = FontStretch("normal")
val condensed = FontStretch("condensed")
val ultraCondensed = FontStretch("ultra-condensed")
val extraCondensed = FontStretch("extra-condensed")
val semiCondensed = FontStretch("semi-condensed")
val expanded = FontStretch("expanded")
val semiExpanded = FontStretch("semi-expanded")
val extraExpanded = FontStretch("extra-expanded")
val ultraExpanded = FontStretch("ultra-expanded")
val initial = FontWeight("initial")
val inherit = FontWeight("inherit")
}
}
class FontStyle(
value: String
) : CssProperty(value) {
companion object {
val normal = FontStyle("normal")
val italic = FontStyle("italic")
val oblique = FontStyle("oblique")
val initial = FontStyle("initial")
val inherit = FontStyle("inherit")
}
}
class FontWeight(
value: String
) : CssProperty(value) {
companion object {
val normal = FontWeight("normal")
val bold = FontWeight("bold")
val _100 = FontWeight("100")
val _200 = FontWeight("200")
val _300 = FontWeight("300")
val _400 = FontWeight("400")
val _500 = FontWeight("500")
val _600 = FontWeight("600")
val _700 = FontWeight("700")
val _800 = FontWeight("800")
val _900 = FontWeight("900")
val initial = FontWeight("initial")
val inherit = FontWeight("inherit")
}
}
class FontKerning(
value: String
) : CssProperty(value) {
companion object {
val auto = FontKerning("auto")
val normal = FontKerning("normal")
val none = FontKerning("none")
}
}
class FontSizeAdjust(
value: String
) : CssProperty(value) {
companion object {
val none = FontSizeAdjust("none")
val initial = FontSizeAdjust("initial")
val inherit = FontSizeAdjust("inherit")
}
}
class FontVariant(
value: String
) : CssProperty(value) {
companion object {
val normal = FontVariant("normal")
val smallCaps = FontVariant("small-caps")
val initial = FontVariant("initial")
val inherit = FontVariant("inherit")
}
}
class FontVariantCaps(
value: String
) : CssProperty(value) {
companion object {
val normal = FontVariantCaps("normal")
val smallCaps = FontVariantCaps("small-caps")
val allSmallCaps = FontVariantCaps("all-small-caps")
val petiteCaps = FontVariantCaps("petite-caps")
val allPetiteCaps = FontVariantCaps("all-petite-caps")
val unicase = FontVariantCaps("unicase")
val initial = FontVariantCaps("initial")
val inherit = FontVariantCaps("inherit")
val unset = FontVariantCaps("unset")
}
}

View File

@@ -0,0 +1,72 @@
package nl.astraeus.css.properties
class Grid(
value: String
) : CssProperty(value) {
companion object {
val none = Grid("none")
val initial = Grid("initial")
val inherit = Grid("inherit")
}
}
class GridAuto(
value: String
) : CssProperty(value) {
companion object {
val auto = GridAuto("auto")
val maxContent = GridAuto("max-content")
val minContent = GridAuto("min-content")
}
}
class GridFlow(
value: String
) : CssProperty(value) {
companion object {
val row = GridFlow("row")
val column = GridFlow("column")
val dense = GridFlow("dense")
val rowDense = GridFlow("row dense")
val columnDense = GridFlow("column dense")
}
}
class GridValue(
value: String
) : CssProperty(value) {
companion object {
val auto = GridValue("auto")
fun span(column: Int) = GridValue("span $column")
fun column(line: Int) = GridValue("$line")
fun row(line: Int) = GridValue("$line")
}
}
class TemplateRowColumn(
value: String
) : CssProperty(value) {
companion object {
val none = GridValue("none")
val auto = GridValue("auto")
val maxContent = GridValue("max-content")
val minContent = GridValue("min-content")
val initial = GridValue("initial")
val inherit = GridValue("inherit")
fun length(length: Measurement) = GridValue(length.value)
}
}

View File

@@ -0,0 +1,15 @@
package nl.astraeus.css.properties
class Hyphens(
value: String
) : CssProperty(value) {
companion object {
val none = Hyphens("none")
val manual = Hyphens("manual")
val auto = Hyphens("auto")
val initial = Hyphens("initial")
val inherit = Hyphens("inherit")
}
}

View File

@@ -0,0 +1,62 @@
package nl.astraeus.css.properties
class Image(
value: String
) : CssProperty(value) {
companion object {
val none = Image("none")
val initial = Image("initial")
val inherit = Image("inherit")
fun url(url: String) = Image("url($url)")
}
}
class ImageRepeat(
value: String
) : CssProperty(value) {
companion object {
val repeat = ImageRepeat("repeat")
val round = ImageRepeat("round")
val initial = ImageRepeat("initial")
val inherit = ImageRepeat("inherit")
fun stretch(url: String) = ImageRepeat("stretch")
}
}
class ImageSlice(
value: String
) : CssProperty(value) {
companion object {
val repeat = ImageSlice("repeat")
val fill = ImageSlice("fill")
val initial = ImageSlice("initial")
val inherit = ImageSlice("inherit")
fun nr(nr: Int) = ImageSlice("$nr")
fun perc(perc: Int) = ImageSlice("$perc%")
fun perc(perc: Double) = ImageSlice("$perc%")
fun stretch(url: String) = ImageSlice("stretch")
}
}
class ImageSource(
value: String
) : CssProperty(value) {
companion object {
val none = ImageSource("none")
val initial = ImageSource("initial")
val inherit = ImageSource("inherit")
fun text(txt: String) = ImageSource(txt)
fun image(url: String) = ImageSource("'$url'")
}
}

View File

@@ -0,0 +1,12 @@
package nl.astraeus.css.properties
class InitialInherit(
value: String
) : CssProperty(value) {
companion object {
val initial = InitialInherit("initial")
val inherit = InitialInherit("inherit")
}
}

View File

@@ -0,0 +1,14 @@
package nl.astraeus.css.properties
class Isolation(
value: String
) : CssProperty(value) {
companion object {
val auto = Isolation("auto")
val isolate = Isolation("isolate")
val initial = Isolation("initial")
val inherit = Isolation("inherit")
}
}

View File

@@ -0,0 +1,17 @@
package nl.astraeus.css.properties
class JustifyContent(
value: String
) : CssProperty(value) {
companion object {
val flexStart = JustifyContent("flex-start")
val flexEnd = JustifyContent("flex-end")
val center = JustifyContent("center")
val spaceBetween = JustifyContent("space-between")
val spaceAround = JustifyContent("space-around")
val initial = JustifyContent("initial")
val inherit = JustifyContent("inherit")
}
}

View File

@@ -0,0 +1,13 @@
package nl.astraeus.css.properties
class LetterSpacing(
value: String
) : CssProperty(value) {
companion object {
val normal = LetterSpacing("normal")
val initial = LetterSpacing("initial")
val inherit = LetterSpacing("inherit")
}
}

View File

@@ -0,0 +1,48 @@
package nl.astraeus.css.properties
class ListStylePosition(
value: String
) : CssProperty(value) {
companion object {
val inside = ListStylePosition("inside")
val outside = ListStylePosition("outside")
val initial = ListStylePosition("initial")
val inherit = ListStylePosition("inherit")
}
}
class ListStyleType(
value: String
) : CssProperty(value) {
companion object {
val disc = ListStyleType("disc")
val armenian = ListStyleType("armenian")
val circle = ListStyleType("circle")
val cjkIdeographic = ListStyleType("cjk-ideographic")
val decimal = ListStyleType("decimal")
val decimalLeadingZero = ListStyleType("decimal-leading-zero")
val georgian = ListStyleType("georgian")
val hebrew = ListStyleType("hebrew")
val hiragana = ListStyleType("hiragana")
val hiraganaIroha = ListStyleType("hiragana-iroha")
val katakana = ListStyleType("katakana")
val katakanaIroha = ListStyleType("katakana-iroha")
val lowerAlpha = ListStyleType("lower-alpha")
val lowerGreek = ListStyleType("lower-greek")
val lowerLatin = ListStyleType("lower-latin")
val lowerRoman = ListStyleType("lower-roman")
val none = ListStyleType("none")
val square = ListStyleType("square")
val upperAlpha = ListStyleType("upper-alpha")
val upperGreek = ListStyleType("upper-greek")
val upperLatin = ListStyleType("upper-latin")
val upperRoman = ListStyleType("upper-roman")
val initial = ListStyleType("initial")
val inherit = ListStyleType("inherit")
}
}

View File

@@ -0,0 +1,127 @@
package nl.astraeus.css.properties
enum class MeasurementUoM {
NONE,
PX,
EM,
REL,
REM,
PC,
PRC,
CM,
FR
}
open class Measurement(
value: String,
val uom: MeasurementUoM = MeasurementUoM.NONE
) : CssProperty(value) {
override fun toString(): String = super.value
companion object {
val auto = Measurement("auto")
val initial = Measurement("initial")
val inherit = Measurement("inherit")
val normal = Measurement("normal")
fun fromString(value:String): Measurement = when {
value == "0" -> Measurement("0", MeasurementUoM.PX)
value.endsWith("px") -> Measurement(value.slice(0..(value.length-2)), MeasurementUoM.PX)
value.endsWith("rel") -> Measurement(value.slice(0..(value.length-3)), MeasurementUoM.REL)
else -> {
TODO("Unable to parse $value")
}
}
fun px(nr: Int) = if (nr == 0) {
Measurement(
"0",
MeasurementUoM.PX
)
} else {
Measurement(
"${nr}px",
MeasurementUoM.PX
)
}
fun px(nr: Double) = nr.px
fun em(nr: Int) = nr.em
fun em(nr: Double) = nr.em
fun prc(nr: Int) = nr.prc
fun prc(nr: Double) = nr.prc
fun pc(nr: Int) = nr.pc
fun pc(nr: Double) = nr.pc
fun cm(nr: Int) = nr.cm
fun cm(nr: Double) = nr.cm
fun fr(nr: Int) = nr.fr
}
}
val Int.px: Measurement
get() = Measurement(
"${this}${
if (this == 0) {
""
} else {
"px"
}
}",
MeasurementUoM.PX
)
val Int.em: Measurement
get() = Measurement(
"${this}${
if (this == 0) {
""
} else {
"em"
}
}",
MeasurementUoM.EM
)
val Int.rem: Measurement
get() = Measurement(
"${this}${
if (this == 0) {
""
} else {
"rem"
}
}",
MeasurementUoM.REM
)
val Int.prc: Measurement
get() = Measurement("${this}%", MeasurementUoM.PRC)
val Int.pc: Measurement
get() = Measurement("${this}pc", MeasurementUoM.PC)
val Int.cm: Measurement
get() = Measurement("${this}cm", MeasurementUoM.CM)
val Int.fr: Measurement
get() = Measurement("${this}fr", MeasurementUoM.FR)
fun Int.px(): Measurement = Measurement.px(this)
val Double.px: Measurement
get() = Measurement("${this}px", MeasurementUoM.PX)
val Double.em: Measurement
get() = Measurement("${this}em", MeasurementUoM.EM)
val Double.rem: Measurement
get() = Measurement("${this}rem", MeasurementUoM.REM)
val Double.prc: Measurement
get() = Measurement("${this}%", MeasurementUoM.PRC)
val Double.pc: Measurement
get() = Measurement("${this}pc", MeasurementUoM.PC)
val Double.cm: Measurement
get() = Measurement("${this}cm", MeasurementUoM.CM)
fun Double.px(): Measurement = Measurement.px(this)
open class LineHeight(value: String) : CssProperty(value) {
companion object {
val normal = LineHeight("normal")
val initial = LineHeight("initial")
val inherit = LineHeight("inherit")
}
}

View File

@@ -0,0 +1,25 @@
package nl.astraeus.css.properties
class MixBlendMode(
value: String
) : CssProperty(value) {
companion object {
val normal = MixBlendMode("normal")
val multiply = MixBlendMode("multiply")
val screen = MixBlendMode("screen")
val overlay = MixBlendMode("overlay")
val darken = MixBlendMode("darken")
val lighten = MixBlendMode("lighten")
val colorDodge = MixBlendMode("color-dodge")
val colorBurn = MixBlendMode("color-burn")
val difference = MixBlendMode("difference")
val exclusion = MixBlendMode("exclusion")
val hue = MixBlendMode("hue")
val saturation = MixBlendMode("saturation")
val color = MixBlendMode("color")
val luminosity = MixBlendMode("luminosity")
}
}

View File

@@ -0,0 +1,17 @@
package nl.astraeus.css.properties
class ObjectFit(
value: String
) : CssProperty(value) {
companion object {
val fill = ObjectFit("fill")
val contain = ObjectFit("contain")
val cover = ObjectFit("cover")
val scaleDown = ObjectFit("scale-down")
val none = ObjectFit("none")
val initial = ObjectFit("initial")
val inherit = ObjectFit("inherit")
}
}

View File

@@ -0,0 +1,14 @@
package nl.astraeus.css.properties
class OutlineWidth(
value: String
) : CssProperty(value) {
companion object {
val thin = OutlineWidth("thin")
val medium = OutlineWidth("medium")
val thick = OutlineWidth("thick")
val initial = BorderWidth("initial")
val inherit = BorderWidth("inherit")
}
}

View File

@@ -0,0 +1,15 @@
package nl.astraeus.css.properties
class Overflow(
value: String
) : CssProperty(value) {
companion object {
val visible = Overflow("visible")
val hidden = Overflow("hidden")
val scroll = Overflow("scroll")
val auto = Overflow("auto")
val initial = BorderWidth("initial")
val inherit = BorderWidth("inherit")
}
}

View File

@@ -0,0 +1,17 @@
package nl.astraeus.css.properties
class PageBreak(
value: String
) : CssProperty(value) {
companion object {
val auto = PageBreak("auto")
val always = PageBreak("always")
val avoid = PageBreak("avoid")
val left = PageBreak("left")
val right = PageBreak("right")
val initial = PageBreak("initial")
val inherit = PageBreak("inherit")
}
}

View File

@@ -0,0 +1,13 @@
package nl.astraeus.css.properties
class Perspective(
value: String
) : CssProperty(value) {
companion object {
val none = Perspective("none")
val initial = Perspective("initial")
val inherit = Perspective("inherit")
}
}

View File

@@ -0,0 +1,14 @@
package nl.astraeus.css.properties
class PointerEvents(
value: String
) : CssProperty(value) {
companion object {
val auto = PointerEvents("auto")
val none = PointerEvents("none")
val initial = PointerEvents("initial")
val inherit = PointerEvents("inherit")
}
}

View File

@@ -0,0 +1,17 @@
package nl.astraeus.css.properties
class Position(
value: String
) : CssProperty(value) {
companion object {
val static = Position("static")
val absolute = Position("absolute")
val fixed = Position("fixed")
val relative = Position("relative")
val sticky = Position("sticky")
val initial = Position("initial")
val inherit = Position("inherit")
}
}

View File

@@ -0,0 +1,17 @@
package nl.astraeus.css.properties
class HangingPunctuation(
value: String
) : CssProperty(value) {
companion object {
val none = HangingPunctuation("none")
val first = HangingPunctuation("first")
val last = HangingPunctuation("last")
val allowEnd = HangingPunctuation("allow-end")
val forceEnd = HangingPunctuation("force-end")
val initial = HangingPunctuation("initial")
val inherit = HangingPunctuation("inherit")
}
}

View File

@@ -0,0 +1,16 @@
package nl.astraeus.css.properties
class Resize(
value: String
) : CssProperty(value) {
companion object {
val none = Resize("none")
val both = Resize("both")
val horizontal = Resize("horizontal")
val vertical = Resize("vertical")
val initial = Resize("initial")
val inherit = Resize("inherit")
}
}

View File

@@ -0,0 +1,14 @@
package nl.astraeus.css.properties
class ScrollBehavior(
value: String
) : CssProperty(value) {
companion object {
val auto = ScrollBehavior("auto")
val smooth = ScrollBehavior("smooth")
val initial = ScrollBehavior("initial")
val inherit = ScrollBehavior("inherit")
}
}

View File

@@ -0,0 +1,14 @@
package nl.astraeus.css.properties
class Span(
value: String
) : CssProperty(value) {
companion object {
val none = Clip("none")
val all = Clip("all")
val initial = Clip("initial")
val inherit = Clip("inherit")
}
}

View File

@@ -0,0 +1,14 @@
package nl.astraeus.css.properties
class TableLayout(
value: String
) : CssProperty(value) {
companion object {
val auto = TableLayout("auto")
val fixed = TableLayout("fixed")
val initial = TableLayout("initial")
val inherit = TableLayout("auto")
}
}

View File

@@ -0,0 +1,16 @@
package nl.astraeus.css.properties
class TextAlign(
value: String
) : CssProperty(value) {
companion object {
val left = TextAlign("left")
val right = TextAlign("right")
val center = TextAlign("center")
val justify = TextAlign("justify")
val initial = TextAlign("initial")
val inherit = TextAlign("inherit")
}
}

View File

@@ -0,0 +1,19 @@
package nl.astraeus.css.properties
class TextAlignLast(
value: String
) : CssProperty(value) {
companion object {
val auto = TextAlignLast("auto")
val left = TextAlignLast("left")
val right = TextAlignLast("right")
val center = TextAlignLast("center")
val justify = TextAlignLast("justify")
val start = TextAlignLast("start")
val end = TextAlignLast("end")
val initial = TextAlignLast("initial")
val inherit = TextAlignLast("inherit")
}
}

View File

@@ -0,0 +1,16 @@
package nl.astraeus.css.properties
class TextDecorationLine(
value: String
) : CssProperty(value) {
companion object {
val none = TextDecorationLine("none")
val underline = TextDecorationLine("underline")
val overline = TextDecorationLine("overline")
val lineThrough = TextDecorationLine("line-through")
val initial = TextDecorationLine("initial")
val inherit = TextDecorationLine("inherit")
}
}

View File

@@ -0,0 +1,17 @@
package nl.astraeus.css.properties
class TextDecorationStyle(
value: String
) : CssProperty(value) {
companion object {
val solid = TextDecorationStyle("solid")
val double = TextDecorationStyle("double")
val dotted = TextDecorationStyle("dotted")
val dashed = TextDecorationStyle("dashed")
val wavy = TextDecorationStyle("wavy")
val initial = TextDecorationStyle("initial")
val inherit = TextDecorationStyle("inherit")
}
}

View File

@@ -0,0 +1,16 @@
package nl.astraeus.css.properties
class TextJustify(
value: String
) : CssProperty(value) {
companion object {
val auto = TextJustify("auto")
val interWord = TextJustify("inter-word")
val interCharacter = TextJustify("inter-character")
val none = TextJustify("none")
val initial = TextJustify("initial")
val inherit = TextJustify("inherit")
}
}

View File

@@ -0,0 +1,16 @@
package nl.astraeus.css.properties
class TextTransform(
value: String
) : CssProperty(value) {
companion object {
val none = TextTransform("none")
val capitalize = TextTransform("capitalize")
val uppercase = TextTransform("uppercase")
val lowercase = TextTransform("lowercase")
val initial = TextTransform("initial")
val inherit = TextTransform("inherit")
}
}

View File

@@ -0,0 +1,31 @@
package nl.astraeus.css.properties
class TimingFunction(
value: String
) : CssProperty(value) {
companion object {
val linear = TimingFunction("linear")
val ease = TimingFunction("ease")
val easeIn = TimingFunction("ease-in")
val easeOut = TimingFunction("ease-out")
val easeInOut = TimingFunction("ease-in-out")
val stepStart = TimingFunction("step-start")
val stepEnd = TimingFunction("step-end")
val initial = TimingFunction("initial")
val inherit = TimingFunction("inherit")
fun steps(steps: Int, start: Boolean) = TimingFunction(
"steps($steps, ${
if (start) {
"start"
} else {
"end"
}
}"
)
fun cubicBezier(n1: Double, n2: Double, n3: Double, n4: Double) = TimingFunction("cubic-bezier($n1, $n2, $n3, $n4)")
}
}

View File

@@ -0,0 +1,51 @@
package nl.astraeus.css.properties
class Transform(
value: String
) : CssProperty(value) {
companion object {
val none = Transform("none")
val initial = Transform("initial")
val inherit = Transform("inherit")
fun matrix(
n1: Double,
n2: Double,
n3: Double,
n4: Double,
n5: Double,
n6: Double
) = Transform("matrix($n1, $n2, $n3, $n4, $n5, $n6)")
fun matrix3d(
n01: Double, n02: Double, n03: Double, n04: Double,
n05: Double, n06: Double, n07: Double, n08: Double,
n09: Double, n10: Double, n11: Double, n12: Double,
n13: Double, n14: Double, n15: Double, n16: Double
) = Transform(
"matrix3d($n01, $n02, $n03, $n04, $n05, $n06, $n07, $n08, $n09, $n10, $n11, $n12, $n13, $n14, $n15, $n16)"
)
fun translate(x: Double, y: Double) = Transform("translate($x, $y)")
fun translate3d(x: Double, y: Double, z: Double) = Transform("translate3d($x, $y, $z)")
fun translateX(x: Double) = Transform("translateX($x)")
fun translateY(y: Double) = Transform("translateY($y)")
fun translateZ(z: Double) = Transform("translateZ($z)")
fun scale(x: Double, y: Double) = Transform("scale($x, $y)")
fun scale3d(x: Double, y: Double, z: Double) = Transform("scale3d($x, $y, $z)")
fun scaleX(x: Double) = Transform("scaleX($x)")
fun scaleY(y: Double) = Transform("scaleY($y)")
fun scaleZ(z: Double) = Transform("scaleZ($z)")
fun rotate(angle: Double) = Transform("rotate($angle)")
fun rotate3d(x: Double, y: Double, z: Double, angle: Double) = Transform("scale3d($x, $y, $z, $angle")
fun rotateX(x: Double) = Transform("rotateX($x)")
fun rotateY(y: Double) = Transform("rotateY($y)")
fun rotateZ(z: Double) = Transform("rotateZ($z)")
fun skew(x: Double, y: Double) = Transform("skew($x, $y)")
fun skewX(x: Double) = Transform("skew($x)")
fun skewY(y: Double) = Transform("skew($y)")
fun perspective(length: Measurement) = Transform("perspective(${length.css()})")
}
}

View File

@@ -0,0 +1,14 @@
package nl.astraeus.css.properties
class TransformStyle(
value: String
) : CssProperty(value) {
companion object {
val flat = TransformStyle("flat")
val preserve3d = TransformStyle("preserve-3d")
val initial = TransformStyle("initial")
val inherit = TransformStyle("inherit")
}
}

View File

@@ -0,0 +1,15 @@
package nl.astraeus.css.properties
class UnicodeBidi(
value: String
) : CssProperty(value) {
companion object {
val normal = UnicodeBidi("normal")
val embed = UnicodeBidi("embed")
val bidiOverride = UnicodeBidi("bidi-override")
val initial = UnicodeBidi("initial")
val inherit = UnicodeBidi("inherit")
}
}

View File

@@ -0,0 +1,14 @@
package nl.astraeus.css.properties
class UserSelect(
value: String
) : CssProperty(value) {
companion object {
val auto = UserSelect("auto")
val none = UserSelect("none")
val text = UserSelect("text")
val all = UserSelect("all")
}
}

View File

@@ -0,0 +1,20 @@
package nl.astraeus.css.properties
class VerticalAlign(
value: String
) : CssProperty(value) {
companion object {
val baseline = VerticalAlign("baseline")
val sub = VerticalAlign("sub")
val _super = VerticalAlign("super")
val top = VerticalAlign("top")
val textTop = VerticalAlign("text-top")
val middle = VerticalAlign("middle")
val bottom = VerticalAlign("bottom")
val textBottom = VerticalAlign("text-bottom")
val initial = VerticalAlign("initial")
val inherit = VerticalAlign("inherit")
}
}

View File

@@ -0,0 +1,15 @@
package nl.astraeus.css.properties
class Visibility(
value: String
) : CssProperty(value) {
companion object {
val visible = Visibility("visible")
val hidden = Visibility("hidden")
val collapse = Visibility("collapse")
val initial = Visibility("initial")
val inherit = Visibility("inherit")
}
}

View File

@@ -0,0 +1,17 @@
package nl.astraeus.css.properties
class WhiteSpace(
value: String
) : CssProperty(value) {
companion object {
val normal = WhiteSpace("normal")
val nowrap = WhiteSpace("nowrap")
val pre = WhiteSpace("pre")
val preLine = WhiteSpace("pre-line")
val preWrap = WhiteSpace("pre-wrap")
val initial = WhiteSpace("initial")
val inherit = WhiteSpace("inherit")
}
}

View File

@@ -0,0 +1,16 @@
package nl.astraeus.css.properties
class WordBreak(
value: String
) : CssProperty(value) {
companion object {
val normal = WordBreak("normal")
val breakAll = WordBreak("break-all")
val keepAll = WordBreak("keep-all")
val breakWord = WordBreak("break-word")
val initial = WordBreak("initial")
val inherit = WordBreak("inherit")
}
}

View File

@@ -0,0 +1,13 @@
package nl.astraeus.css.properties
class WordSpacing(
value: String
) : CssProperty(value) {
companion object {
val normal = WordSpacing("normal")
val initial = WordSpacing("initial")
val inherit = WordSpacing("inherit")
}
}

View File

@@ -0,0 +1,14 @@
package nl.astraeus.css.properties
class WordWrap(
value: String
) : CssProperty(value) {
companion object {
val normal = WordWrap("normal")
val breakWord = WordWrap("break-word")
val initial = WordWrap("initial")
val inherit = WordWrap("inherit")
}
}

View File

@@ -0,0 +1,13 @@
package nl.astraeus.css.properties
class WritingMode(
value: String
) : CssProperty(value) {
companion object {
val horizontalTb = WritingMode("horizontal-tb")
val verticalRl = WritingMode("vertical-rl")
val verticalLr = WritingMode("vertical-lr")
}
}

View File

@@ -0,0 +1,13 @@
package nl.astraeus.css.properties
class ZIndex(
value: String
) : CssProperty(value) {
companion object {
val auto = ZIndex("auto")
val initial = ZIndex("initial")
val inherit = ZIndex("inherit")
}
}

View File

@@ -0,0 +1,6 @@
package nl.astraeus.css.style
data class CssBlock(
val selector: String,
val content: String
)

View File

@@ -0,0 +1,11 @@
package nl.astraeus.css.style
import nl.astraeus.css.properties.Color
object CssFunctions {
fun darken(color: Color, percentage: Int): Color {
return color
}
}

View File

@@ -0,0 +1,42 @@
package nl.astraeus.css.style
import nl.astraeus.css.properties.CssProperty
import nl.astraeus.css.properties.FontSize
import nl.astraeus.css.properties.FontStretch
import nl.astraeus.css.properties.FontStyle
import nl.astraeus.css.properties.FontWeight
@CssTagMarker
open class FontFace : CssGenerator() {
override fun getValidator(name: String) = null
fun fontFamily(font: String) {
props["font-family"] = listOf(CssProperty(font))
}
fun fontSize(size: FontSize) {
props["font-size"] = listOf(size)
}
fun src(src: String) {
props["src"] = listOf(CssProperty(src))
}
fun fontStretch(stretch: FontStretch) {
props["font-stretch"] = listOf(stretch)
}
fun fontStyle(style: FontStyle) {
props["font-style"] = listOf(style)
}
fun fontWeight(weight: FontWeight) {
props["font-weight"] = listOf(weight)
}
fun unicodeRange(unicodeRange: String) {
props["unicode-range"] = listOf(CssProperty(unicodeRange))
}
}

View File

@@ -0,0 +1,16 @@
package nl.astraeus.css.style
@CssTagMarker
open class KeyFrames : CssGenerator() {
val frames: MutableMap<Int, Css> = mutableMapOf()
override fun getValidator(name: String): List<Validator>? = listOf()
fun percentage(percentage: Int, style: Css) {
val css = Style()
style(css)
frames[percentage] = style
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,37 @@
package nl.astraeus.css.style
import nl.astraeus.css.properties.CssProperty
abstract class Validator {
open fun validate(properties: List<CssProperty>): Boolean = true
open fun getMessage(name: String): String = "'$name' validation message not defined for $this"
}
class MaxCountValidator(
val number: Int
) : Validator() {
override fun validate(property: List<CssProperty>): Boolean = property.size <= number
override fun getMessage(name: String): String = "'$name' should not have more than 4 entries"
}
class InitialInheritSingleValue : Validator() {
override fun validate(properties: List<CssProperty>): Boolean {
for (prop in properties) {
if (prop.css() == "initial" || prop.css() == "inherit") {
return properties.size == 1
}
}
return true
}
override fun getMessage(name: String): String = "'$name' can only have single value when 'initial' or 'inherit'"
}

View File

@@ -0,0 +1,43 @@
package nl.astraeus.css
import nl.astraeus.css.properties.Color
import nl.astraeus.css.style.DescriptionProvider
import kotlin.test.Test
private val CAPITAL_LETTER by lazy { Regex("[A-Z]") }
fun String.hyphenize(): String =
replace(CAPITAL_LETTER) {
"-${it.value.lowercase()}"
}
open class CssName(name: String? = null) : DescriptionProvider {
val name: String = if (name != null) {
"css-$name"
} else{
"css${this::class.simpleName?.hyphenize() ?: this::class}"
}
override fun description() = name
}
object MainTitle : CssName()
object SectionTitle : CssName("sct-title")
class CssNameExample {
@Test
fun testCssName() {
val css = style {
select(MainTitle) {
color(Color.white)
}
select(SectionTitle) {
color(Color.red)
}
}
println(css.generateCss())
}
}

View File

@@ -0,0 +1,131 @@
package nl.astraeus.css
import nl.astraeus.css.properties.BorderStyle
import nl.astraeus.css.properties.Color
import nl.astraeus.css.properties.Measurement
import nl.astraeus.css.properties.em
import nl.astraeus.css.properties.hsla
import nl.astraeus.css.properties.prc
import nl.astraeus.css.properties.px
import nl.astraeus.css.style.Style
import nl.astraeus.css.style.cls
import nl.astraeus.css.style.txt
import kotlin.test.Test
class Examples {
@Test
fun testColor() {
val color = hsla(0, 50, 50, 1.0)
val backgroundColor = Color.white
val css = style {
select(cls("button")) {
padding(5.px)
select("a") {
color(color)
backgroundColor(backgroundColor)
hover {
color(color.lighten(10))
backgroundColor(backgroundColor.darken(10))
}
}
}
}
println(css.generateCss(minified = true))
}
@Test
fun testMixins() {
fun Style.borderStyles(borderWidth: Measurement = 2.px) {
borderWidth(borderWidth)
borderColor(Color.aquamarine)
borderStyle(BorderStyle.solid)
}
val css = style {
select(txt("a"), cls("button")) {
borderStyles()
color(Color.white)
}
select(cls("btn-primary")) {
borderStyles(3.px)
color(Color.blue)
}
}
println(css.generateCss())
}
@Test
fun testMeasurements() {
val css = style {
select("body") {
fontSize(1.2.em)
borderWidth(3.px)
width(75.prc)
}
}
println(css.generateCss())
}
@Test
fun testGeneration() {
val color = hsla(0, 50, 50, 1.0)
val backgroundColor = Color.white
val css = style {
select(cls("button")) {
padding(5.px)
select("a", "span") {
color(color)
backgroundColor(backgroundColor)
hover {
color(color.lighten(10))
backgroundColor(backgroundColor.darken(10))
}
}
}
}
println(css.generateCss(
minified = false,
sortProperties = true,
combineEqualBlocks = false
))
}
@Test
fun testMediaQueries() {
val css = style {
media("screen and (min-width: 30em)") {
select("html", "body") {
backgroundColor(Color.purple)
color(Color.blue)
}
}
media("print") {
select("html", "body") {
backgroundColor(Color.white)
color(Color.darkGrey)
}
}
}
println(css.generateCss(
minified = false,
sortProperties = true,
combineEqualBlocks = true
))
}
}

View File

@@ -0,0 +1,268 @@
package nl.astraeus.css
import nl.astraeus.css.properties.BoxSizing
import nl.astraeus.css.properties.Color
import nl.astraeus.css.properties.Count
import nl.astraeus.css.properties.Display
import nl.astraeus.css.properties.em
import nl.astraeus.css.properties.hsl
import nl.astraeus.css.properties.hsla
import nl.astraeus.css.properties.px
import nl.astraeus.css.properties.rgb
import nl.astraeus.css.properties.rgba
import nl.astraeus.css.style.attr
import nl.astraeus.css.style.attrEquals
import nl.astraeus.css.style.cls
import nl.astraeus.css.style.id
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue
class TestCssBuilder {
@Test
fun testBuilder() {
val css = style {
select("*", "*::before", "*::after") {
boxSizing(BoxSizing.borderBox)
}
select("html") {
transition("background-color 1s ease")
margin(0.px)
padding(0.px)
focus {
backgroundColor(Color.blue)
}
}
select("body") {
margin(0.px)
padding(0.px)
focus {
backgroundColor(Color.blue)
}
transition("background-color 1s ease")
}
select(".test") {
top(10.px)
left(4.em)
backgroundColor(rgba(255, 255, 255, 0.75))
animationIterationMode(
Count.auto,
Count.auto,
Count.auto,
Count.auto,
Count.auto
)
child("li") {
color(hsl(200, 50, 50))
}
select("> a") {
color(hsl(200, 50, 50))
}
hover {
color(Color.red)
}
child("li") {
listStyle("none")
child("ul") {
opacity(0.0)
display(Display.none)
paddingLeft(20.px)
child("li") {
listStyle("none")
child("ul") {
paddingLeft(30.px)
child("li") {
listStyle("none")
}
}
}
}
hover {
child("ul") {
opacity(1.0)
display(Display.block)
}
}
}
}
}
println(css.generateCss(combineEqualBlocks = true, sortProperties = true))
}
@Test
fun testClass() {
val css2 = style {
select(id("my-label")) {
color(Color.antiqueWhite)
}
select(cls("my-label")) {
color(Color.aliceBlue)
}
// tr.even {}
select("tr") {
and(cls("even")) {
color(Color.gray)
}
/*
nthChild(2) {
}
*/
// not(bla) {
not(cls("bla")) {
color(Color.blue)
}
}
// table .even {}
select("tr") {
select(cls("even")) {
color(Color.green)
}
// [type]
select(attr("type")) {
}
// [type="checkbox"]
select(attrEquals("type", "checkbox")) {
}
// table > .odd
child(cls("odd")) {
}
//adjSibling()
}
select(cls("button")) {
fontSize(12.px)
color(hsl(200, 50, 50))
// .button:hover
hover {
color(hsl(200, 40, 40))
}
child(".green") {
color(Color.green)
}
sibling(".red") {
color(Color.red)
}
adjSibling(".blue") {
color(Color.blue)
}
}
}
println(css2.generateCss())
}
@Test
fun testOr() {
val css = style {
select("h1") {
color(Color.blue)
select("table") {
color(Color.red)
select("th", "td") {
color(Color.green)
}
}
}
}
println(css.generateCss())
}
@Test
fun testOrWithComma() {
var excepted = false
try {
val css = style {
select("h1") {
color(Color.blue)
select("table") {
color(Color.red)
select("th, td") {
color(Color.green)
}
}
}
}
println(css.generateCss())
} catch (e: Exception) {
excepted = true
assertTrue {
e is IllegalStateException
}
assertTrue {
e.message?.contains("Comma is not allowed in selector") ?: false
}
}
assertTrue {
excepted
}
}
@Test
fun testAlphaFunctions() {
val hsl = hsl(1, 50, 50)
val hsla = hsla(1, 50, 50, 0.5)
val rgb = rgb(101, 111, 121)
val rgba = rgba(100, 110, 120, 0.4)
val hex = Color("#88ff44")
val hexa = Color("#88ff4466")
assertFalse { hsl.hasAlpha() }
assertFalse { rgb.hasAlpha() }
assertFalse { hex.hasAlpha() }
assertTrue { hsla.hasAlpha() }
assertTrue { rgba.hasAlpha() }
assertTrue { hexa.hasAlpha() }
assertEquals(0.5, hsla.getAlpha())
assertEquals(0.4, rgba.getAlpha())
assertEquals(0.5, hsla.getAlpha())
assertEquals(0.4, hexa.getAlpha())
assertEquals("646e78", rgba.toHex())
assertEquals("bf4240", hsla.toHex())
}
}