31 Commits

Author SHA1 Message Date
0e1c1cd99f Version 1.1.0, add oklch color option
- Update publish plugin
2025-05-03 10:49:00 +02:00
996a8f385e version 1.0.11-SNAPSHOT 2024-10-23 14:00:59 +02:00
d2349c9308 version 1.0.10 2024-10-23 13:50:36 +02:00
e0a4ff54de v. 1.0.8 update Kotlin to 1.9.22, gradle to 8.5 and test-logger to 4.0.0 2024-01-27 12:04:24 +01:00
3f5f1c6543 Example
Took 15 minutes
2023-07-24 10:34:20 +02:00
ac491761d9 v. 1.0.7, kotlin v. 1.7.20, gradle 7.5.1
Took 24 minutes
2022-10-15 11:11:11 +02:00
0d8157cabf Update to snapshot version 2022-03-24 09:29:47 +01:00
1e37ac07ba v. 1.0.6
- Fix not

Took 9 minutes
2022-03-24 09:24:10 +01:00
780dd0782a Update to snapshot version
Took 6 minutes
2021-11-09 13:45:34 +01:00
70a52a3bb5 v. 1.0.4, add vh,vw measurements
Took 47 seconds
2021-11-09 13:38:36 +01:00
68ce4ffa16 Merge remote-tracking branch 'github/main' into main 2021-10-23 11:56:35 +02:00
9f3be7cadd v. 1.0.3, add inline style, fix TemplateRowColumn value types
Took 27 minutes
2021-10-23 11:56:18 +02:00
9217476ae7 Update readme.md 2021-10-15 15:08:08 +02:00
7e86441d84 v. 1.0.2, fix minified option
Took 8 minutes
2021-10-15 15:04:22 +02:00
6375a0d78d v. 1.0.1, update readme.md
Took 1 hour 56 minutes
2021-10-09 20:13:38 +02:00
b2c112f711 Merge branch 'master' into main 2021-10-03 13:26:11 +02:00
95c190defd Initial commit 2021-10-03 13:19:37 +02:00
4137427989 v. 1.0.0
Took 1 hour 52 minutes
2021-10-03 13:18:00 +02:00
ca68871eca Fixes
Took 14 seconds
2021-08-30 12:38:52 +02:00
d4a8b18ec2 Fixes 2021-08-15 08:36:23 +02:00
1dc6f6cf9f Add UoM 2021-07-09 11:16:29 +02:00
adec3b21b0 Add Color conversion options (add hsla -> hex) 2021-07-08 16:15:42 +02:00
9e43f5b746 Add Color conversion options 2021-07-08 13:17:15 +02:00
57edc59853 Add fr uom 2021-06-15 13:20:30 +02:00
536d095b96 Disallow comma in selector by default 2021-06-11 11:07:46 +02:00
95fb7ec923 Allow multiple selectors for one style (or operator) 2021-06-11 09:45:04 +02:00
c5ba12032d Reformat code 2021-05-11 17:26:08 +02:00
2b725f6af2 Add gradle.properties.example 2021-05-11 09:09:52 +02:00
46d99d4122 Delete gradle.properties 2021-05-11 09:06:27 +02:00
d1094bddef Merge function-builder branch into master 2021-05-11 09:04:49 +02:00
4730e6d3d7 Fix js test 2020-03-01 13:21:00 +01:00
93 changed files with 4796 additions and 1363 deletions

2
.gitignore vendored
View File

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

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 Rien
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,59 +1,118 @@
@file:OptIn(ExperimentalWasmDsl::class)
import com.vanniktech.maven.publish.SonatypeHost
import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
plugins { plugins {
kotlin("multiplatform") version "1.3.70-eap-184" kotlin("multiplatform") version "2.1.10"
id("com.vanniktech.maven.publish") version "0.31.0"
signing
id("org.jetbrains.dokka") version "2.0.0"
} }
group = "nl.astraeus" group = "nl.astraeus"
version = "0.1.0-SNAPSHOT" version = "1.1.0"
repositories { repositories {
maven { setUrl("https://dl.bintray.com/kotlin/kotlin-eap") }
mavenCentral() mavenCentral()
} }
apply(plugin = "kotlin-dce-js")
kotlin { kotlin {
/* Targets configuration omitted.
* To find out how to configure the targets, please follow the link:
* https://kotlinlang.org/docs/reference/building-mpp-with-gradle.html#setting-up-targets */
jvm() jvm()
js() js(IR) {
browser {
/* testTask {
// work around, browser test is broken atm
enabled = false
}*/
}
}
wasmJs {
//moduleName = project.name
browser()
mavenPublication {
groupId = group as String
pom { name = "${project.name}-wasm-js" }
}
}
sourceSets { sourceSets {
val commonMain by getting { val commonMain by getting
dependencies {
implementation(kotlin("stdlib-common"))
implementation("io.github.microutils:kotlin-logging-common:1.7.8")
}
}
val commonTest by getting { val commonTest by getting {
dependencies { dependencies {
implementation(kotlin("test-common")) implementation(kotlin("test"))
//implementation(kotlin("test-annotations-common"))
} }
} }
val jsMain by getting { val jvmTest by getting {
dependencies { dependencies {
implementation(kotlin("stdlib-js")) implementation(kotlin("test-junit"))
}
}
val jsMain by getting
val wasmJsMain by getting
}
}
implementation("io.github.microutils:kotlin-logging-js:1.7.8") val javadocJar by tasks.registering(Jar::class) {
} archiveClassifier.set("javadoc")
} }
val jsTest by getting {
dependencies {
implementation(kotlin("test-js"))
//implementation(kotlin("test-annotations-js"))
}
}
val jvmMain by getting {
dependencies {
implementation(kotlin("stdlib-jdk8"))
implementation("org.slf4j:slf4j-api:1.7.29") publishing {
implementation("org.slf4j:slf4j-simple:1.7.29") repositories {
implementation("io.github.microutils:kotlin-logging:1.7.8") mavenLocal()
maven {
name = "gitea"
setUrl("https://gitea.astraeus.nl/api/packages/rnentjes/maven")
credentials() {
val giteaUsername: kotlin.String? by project
val giteaPassword: kotlin.String? by project
username = giteaUsername
password = giteaPassword
} }
} }
} }
} }
signing {
sign(publishing.publications)
}
tasks.withType<AbstractPublishToMaven> {
dependsOn(tasks.withType<Sign>())
}
mavenPublishing {
publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL)
signAllPublications()
coordinates(group.toString(), name, version.toString())
pom {
name = "kotlin-css-generator"
description = "Kotlin css generator"
inceptionYear = "2020"
url = "https://github.com/rnentjes/kotlin-css-generator"
licenses {
license {
name = "MIT"
url = "https://opensource.org/licenses/MIT"
}
}
developers {
developer {
id = "rnentjes"
name = "Rien Nentjes"
email = "info@nentjes.com"
}
}
scm {
url = "https://github.com/rnentjes/kotlin-css-generator"
}
}
}

View File

@@ -1 +0,0 @@
kotlin.code.style=official

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=

View File

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

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")

176
readme.md Normal file
View File

@@ -0,0 +1,176 @@
# 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.
## Usage
Include in build.gradle.kts:
```kotlin
repositories {
mavenCentral()
}
val commonMain by getting {
dependencies {
api("nl.astraeus:kotlin-css-generator:1.0.9")
}
}
```
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%;
}
```

View File

@@ -1,10 +1,20 @@
pluginManagement { pluginManagement {
repositories { repositories {
maven { setUrl("https://dl.bintray.com/kotlin/kotlin-eap") } google()
mavenCentral() mavenCentral()
gradlePluginPortal()
maven { setUrl("https://plugins.gradle.org/m2/") }
} }
} }
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
}
}
plugins {
id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
}
rootProject.name = "kotlin-css-generator" rootProject.name = "kotlin-css-generator"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,77 +1,55 @@
package nl.astraeus.css.properties package nl.astraeus.css.properties
class AnimationDirection( class AnimationDirection(
value: String value: String
) : CssProperty(value) { ) : CssProperty(value) {
companion object { companion object {
fun normal() = AnimationDirection("normal") val normal = AnimationDirection("normal")
fun reverse() = AnimationDirection("reverse") val reverse = AnimationDirection("reverse")
fun alternate() = AnimationDirection("alternate") val alternate = AnimationDirection("alternate")
fun alternateReverse() = AnimationDirection("alternate-reverse") val alternateReverse = AnimationDirection("alternate-reverse")
fun initial() = AnimationDirection("initial") val initial = AnimationDirection("initial")
fun inherit() = AnimationDirection("inherit") val inherit = AnimationDirection("inherit")
} }
} }
class AnimationFillMode( class AnimationFillMode(
value: String value: String
) : CssProperty(value) { ) : CssProperty(value) {
companion object { companion object {
fun none() = AnimationFillMode("none") val none = AnimationFillMode("none")
fun forwards() = AnimationFillMode("forwards") val forwards = AnimationFillMode("forwards")
fun backwards() = AnimationFillMode("backwards") val backwards = AnimationFillMode("backwards")
fun both() = AnimationFillMode("both") val both = AnimationFillMode("both")
fun initial() = AnimationFillMode("initial") val initial = AnimationFillMode("initial")
fun inherit() = AnimationFillMode("inherit") val inherit = AnimationFillMode("inherit")
} }
} }
class AnimationFrame( class AnimationFrame(
value: String = "" value: String = ""
): CssProperty(value) { ) : CssProperty(value) {
companion object { companion object {
fun name(name: String): AnimationFrame = AnimationFrame(name) fun name(name: String) = AnimationFrame(name)
fun none(): AnimationFrame = AnimationFrame("none") val none: AnimationFrame = AnimationFrame("none")
fun initial(): AnimationFrame = AnimationFrame("initial") val initial: AnimationFrame = AnimationFrame("initial")
fun inherit(): AnimationFrame = AnimationFrame("inherit") val inherit: AnimationFrame = AnimationFrame("inherit")
} }
} }
class AnimationPlayState( class AnimationPlayState(
value: String value: String
) : CssProperty(value) { ) : CssProperty(value) {
companion object { companion object {
fun name(name: String) = AnimationPlayState(name) fun name(name: String) = AnimationPlayState(name)
fun paused() = AnimationPlayState("paused") val paused = AnimationPlayState("paused")
fun running() = AnimationPlayState("running") val running = AnimationPlayState("running")
fun initial() = AnimationPlayState("initial") val initial = AnimationPlayState("initial")
fun inherit() = AnimationPlayState("inherit") val inherit = AnimationPlayState("inherit")
} }
}
class AnimationTimingFunction(
value: String = ""
) : CssProperty(value) {
companion object {
fun linear() = AnimationTimingFunction("linear")
fun ease() = AnimationTimingFunction("ease")
fun easeIn() = AnimationTimingFunction("ease-in")
fun easeOut() = AnimationTimingFunction("ease-out")
fun easeInOut() = AnimationTimingFunction("ease-in-out")
fun cubicBezier(
n1: Double,
n2: Double,
n3: Double,
n4: Double
) = AnimationTimingFunction("cubic-bezier($n1,$n2,$n3,$n4)")
fun initial() = AnimationTimingFunction("initial")
fun inherit() = AnimationTimingFunction("inherit")
}
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,31 @@
package nl.astraeus.css.properties
fun calc(expression: CalcExpression) = Calc(expression)
infix operator fun CalcExpression.plus(other: CalcExpression) = CompoundCalcExpression(
this,
"+",
other
)
infix operator fun CalcExpression.minus(other: CalcExpression) = CompoundCalcExpression(
this,
"-",
other
)
interface CalcExpression
class CompoundCalcExpression(
val left: CalcExpression,
val operator: String,
val right: CalcExpression
): CalcExpression {
override fun toString(): String {
return "$left $operator $right"
}
}
class Calc(
expression: CalcExpression
) : CssProperty(expression.toString())

View File

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

View File

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

View File

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

View File

@@ -1,36 +1,596 @@
package nl.astraeus.css.properties package nl.astraeus.css.properties
class Color( import kotlin.math.PI
value: String import kotlin.math.abs
) : CssProperty(value) { import kotlin.math.max
import kotlin.math.roundToInt
companion object { private val hexString = "0123456789abcdef"
fun auto() = Color("auto")
fun transparant() = Color("transparant") private fun Int.toColorHex(minimumDigits: Int = 2): String {
fun initial() = Color("initial") val result = StringBuilder()
fun inherit() = Color("inherit") var value = this
fun hex(hex: String) = Color("#$hex")
fun rgb( while(value > 0) {
red: Int, result.append(hexString[value%16])
green: Int,
blue: Int value /= 16
) = Color("rgb($red, $green, $blue)") }
fun rgba(
red: Int, while(result.length < minimumDigits) {
green: Int, result.append("0")
blue: Int, }
alpha: Double
) = Color("rgba($red, $green, $blue, $alpha)") return result.reverse().toString()
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, $alpha)")
}
} }
/**
* 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 oklch(lightness: Int, chroma: Double, hue: Double) = Color("oklch($lightness% $chroma $hue)")
fun oklch(lightness: Int, chroma: Double, hue: Double, alpha: Double) = Color("oklch($lightness% $chroma $hue / ${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

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

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,80 +1,142 @@
package nl.astraeus.css.properties package nl.astraeus.css.properties
class FontSize( class FontSize(
value: String value: String
) : CssProperty(value) { ) : CssProperty(value) {
companion object { companion object {
fun xxSmall() = FontSize("xx-small") val xxSmall = FontSize("xx-small")
fun xSmall() = FontSize("x-small") val xSmall = FontSize("x-small")
fun small() = FontSize("small") val small = FontSize("small")
fun medium() = FontSize("medium") val medium = FontSize("medium")
fun large() = FontSize("large") val large = FontSize("large")
fun xLarge() = FontSize("x-large") val xLarge = FontSize("x-large")
fun xxLarge() = FontSize("xx-large") val xxLarge = FontSize("xx-large")
fun smaller() = FontSize("smaller") val smaller = FontSize("smaller")
fun larger() = FontSize("larger") val larger = FontSize("larger")
fun initial() = FontSize("initial") val initial = FontSize("initial")
fun inherit() = FontSize("inherit") val inherit = FontSize("inherit")
fun px(nr: Int) = FontSize("${nr}px")
fun em(nr: Int) = FontSize("${nr}em") fun px(nr: Int) = FontSize("${nr}px")
fun em(nr: Double) = FontSize("${nr}em") fun em(nr: Int) = FontSize("${nr}em")
fun perc(nr: Int) = FontSize("${nr}%") fun em(nr: Double) = FontSize("${nr}em")
fun perc(nr: Double) = FontSize("${nr}%") fun perc(nr: Int) = FontSize("${nr}%")
fun pc(nr: Int) = FontSize("${nr}pc") fun perc(nr: Double) = FontSize("${nr}%")
fun pc(nr: Double) = FontSize("${nr}pc") fun pc(nr: Int) = FontSize("${nr}pc")
fun cm(nr: Int) = FontSize("${nr}cm") fun pc(nr: Double) = FontSize("${nr}pc")
fun cm(nr: Double) = FontSize("${nr}cm") fun cm(nr: Int) = FontSize("${nr}cm")
} fun cm(nr: Double) = FontSize("${nr}cm")
}
} }
class FontStretch( class FontStretch(
value: String value: String
) : CssProperty(value) { ) : CssProperty(value) {
companion object { companion object {
fun normal() = FontStretch("normal") val normal = FontStretch("normal")
fun condensed() = FontStretch("condensed") val condensed = FontStretch("condensed")
fun ultraCondensed() = FontStretch("ultra-condensed") val ultraCondensed = FontStretch("ultra-condensed")
fun extraCondensed() = FontStretch("extra-condensed") val extraCondensed = FontStretch("extra-condensed")
fun semiCondensed() = FontStretch("semi-condensed") val semiCondensed = FontStretch("semi-condensed")
fun expanded() = FontStretch("expanded") val expanded = FontStretch("expanded")
fun semiExpanded() = FontStretch("semi-expanded") val semiExpanded = FontStretch("semi-expanded")
fun extraExpanded() = FontStretch("extra-expanded") val extraExpanded = FontStretch("extra-expanded")
fun ultraExpanded() = FontStretch("ultra-expanded") val ultraExpanded = FontStretch("ultra-expanded")
} val initial = FontWeight("initial")
val inherit = FontWeight("inherit")
}
} }
class FontStyle( class FontStyle(
value: String value: String
) : CssProperty(value) { ) : CssProperty(value) {
companion object { companion object {
fun normal() = FontStyle("normal") val normal = FontStyle("normal")
fun italic() = FontStyle("italic") val italic = FontStyle("italic")
fun oblique() = FontStyle("oblique") val oblique = FontStyle("oblique")
} val initial = FontStyle("initial")
val inherit = FontStyle("inherit")
}
} }
class FontWeight( class FontWeight(
value: String value: String
) : CssProperty(value) { ) : CssProperty(value) {
companion object { companion object {
fun normal() = FontWeight("normal") val normal = FontWeight("normal")
fun bold() = FontWeight("bold") val bold = FontWeight("bold")
fun _100() = FontWeight("100") val _100 = FontWeight("100")
fun _200() = FontWeight("200") val _200 = FontWeight("200")
fun _300() = FontWeight("300") val _300 = FontWeight("300")
fun _400() = FontWeight("400") val _400 = FontWeight("400")
fun _500() = FontWeight("500") val _500 = FontWeight("500")
fun _600() = FontWeight("600") val _600 = FontWeight("600")
fun _700() = FontWeight("700") val _700 = FontWeight("700")
fun _800() = FontWeight("800") val _800 = FontWeight("800")
fun _900() = FontWeight("900") 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 = TemplateRowColumn("none")
val auto = TemplateRowColumn("auto")
val maxContent = TemplateRowColumn("max-content")
val minContent = TemplateRowColumn("min-content")
val initial = TemplateRowColumn("initial")
val inherit = TemplateRowColumn("inherit")
fun length(length: Measurement) = TemplateRowColumn(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

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

@@ -1,22 +1,112 @@
package nl.astraeus.css.properties package nl.astraeus.css.properties
open class Measurement( enum class MeasurementUoM {
value: String NONE,
) : CssProperty(value) { PX,
EM,
companion object { REL,
fun auto() = Measurement("auto") REM,
fun initial() = Measurement("initial") PC,
fun inherit() = Measurement("inherit") PRC,
fun normal() = Measurement("normal") CM,
fun px(nr: Int) = Measurement("${nr}px") FR,
fun em(nr: Int) = Measurement("${nr}em") VH,
fun em(nr: Double) = Measurement("${nr}em") VW
fun perc(nr: Int) = Measurement("${nr}%") }
fun perc(nr: Double) = Measurement("${nr}%")
fun pc(nr: Int) = Measurement("${nr}pc") open class Measurement(
fun pc(nr: Double) = Measurement("${nr}pc") value: String,
fun cm(nr: Int) = Measurement("${nr}cm") val uom: MeasurementUoM = MeasurementUoM.NONE
fun cm(nr: Double) = Measurement("${nr}cm") ) : CssProperty(value), CalcExpression {
}
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")
}
}
}
}
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)
val Int.vw: Measurement
get() = Measurement("${this}vw", MeasurementUoM.VW)
val Int.vh: Measurement
get() = Measurement("${this}vh", MeasurementUoM.VH)
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)
val Double.fr: Measurement
get() = Measurement("${this}fr", MeasurementUoM.FR)
val Double.vw: Measurement
get() = Measurement("${this}vw", MeasurementUoM.VW)
val Double.vh: Measurement
get() = Measurement("${this}vh", MeasurementUoM.VH)
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

@@ -1,14 +1,14 @@
package nl.astraeus.css.properties package nl.astraeus.css.properties
class Span( class Span(
value: String value: String
) : CssProperty(value) { ) : CssProperty(value) {
companion object { companion object {
fun none() = Clip("none") val none = Clip("none")
fun all() = Clip("all") val all = Clip("all")
fun initial() = Clip("initial") val initial = Clip("initial")
fun inherit() = Clip("inherit") 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

@@ -1,27 +1,42 @@
package nl.astraeus.css.style package nl.astraeus.css.style
import nl.astraeus.css.properties.* 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 @CssTagMarker
open class FontFace( open class FontFace : CssGenerator() {
var fontFamily: TextProperty? = null,
var fontSize: FontSize? = null,
var src: TextProperty? = null,
var fontStretch: FontStretch? = null,
var fontStyle: FontStyle? = null,
var fontWeight: FontWeight? = null,
var unicodeRange: TextProperty? = null
) : CssGenerator() {
override fun getValidator(name: String) = null 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))
}
override fun getMapping(): Map<String, Any?> = mapOf(
"font-family" to fontFamily,
"font-size" to fontSize,
"src" to src,
"font-stretch" to fontStretch,
"font-style" to fontStyle,
"font-weight" to fontWeight,
"unicode-range" to 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

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

View File

@@ -1,5 +0,0 @@
package nl.astraeus.logging
import mu.KotlinLogging
val log = KotlinLogging.logger {}

View File

@@ -0,0 +1,20 @@
package nl.astraeus.css
import nl.astraeus.css.properties.oklch
import kotlin.test.Test
class ColorTest {
@Test
fun testColor() {
val css = style {
select("body") {
color(oklch(100, 0.5, 0.5))
backgroundColor(oklch(100, 0.5, 0.5, 0.25))
}
}
println(css.generateCss())
}
}

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,157 @@
package nl.astraeus.css
import nl.astraeus.css.properties.BorderStyle
import nl.astraeus.css.properties.Color
import nl.astraeus.css.properties.FontStyle
import nl.astraeus.css.properties.FontWeight
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
))
}
@Test
fun testFontFace() {
val css = style {
select("*") {
fontFace {
fontFamily("UbuntuCondensed")
fontStyle(FontStyle.normal)
fontWeight(FontWeight.normal)
//fontDisplay("auto")
src("fonts/ubuntu.condensed.ttf")
}
}
}
val cssTxt = css.generateCss(
minified = false,
sortProperties = true,
combineEqualBlocks = true
)
println(cssTxt)
}
}

View File

@@ -0,0 +1,18 @@
package nl.astraeus.css
import nl.astraeus.css.properties.calc
import nl.astraeus.css.properties.em
import nl.astraeus.css.properties.minus
import nl.astraeus.css.properties.plus
import nl.astraeus.css.properties.px
import kotlin.test.Test
class TestCalcExpression {
@Test
fun testCalcExpression() {
val a = calc(10.px + 20.px - 5.em)
println(a)
}
}

View File

@@ -1,32 +1,267 @@
package nl.astraeus.css package nl.astraeus.css
import nl.astraeus.css.properties.Color.Companion.hsl import nl.astraeus.css.properties.BoxSizing
import nl.astraeus.css.properties.Color.Companion.rgba import nl.astraeus.css.properties.Color
import nl.astraeus.css.properties.Measurement.Companion.em import nl.astraeus.css.properties.Count
import nl.astraeus.css.properties.Measurement.Companion.px 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
//import kotlin.test.Test class TestCssBuilder {
object TestCssBuilder { @Test
fun testBuilder() {
val css = style {
//@Test select("*", "*::before", "*::after") {
fun testBuilder() { boxSizing(BoxSizing.borderBox)
val css = CssBuilder() }
css.style { select("html") {
transition("background-color 1s ease")
select(".test") { margin(0.px)
top = px(10) padding(0.px)
left = em(5)
backgroundColor = rgba(255, 255, 255, 0.75)
select("> a") { focus {
color = hsl(200, 50, 50) 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))
} }
println(css) 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())
}
} }

View File

@@ -1,99 +0,0 @@
package nl.astraeus.css
import nl.astraeus.css.properties.*
import nl.astraeus.css.properties.Measurement.Companion.em
import nl.astraeus.css.properties.Measurement.Companion.px
import nl.astraeus.css.style.StyleDefinition
class StyleBase(
val mainColor: Color = Color.hsl(128, 50, 50),
val mainBackgroundColor: Color = Color.hsl(64, 50, 50),
val mainFont: TextProperty = text("Arial")
)
private fun StyleDefinition.sizePX(
left: Int,
top: Int,
width: Int,
height: Int
) {
this@sizePX.top = px(top)
this@sizePX.left = px(left)
this@sizePX.width = px(width)
this@sizePX.height = px(height)
}
private fun generateCss(
base: StyleBase
): String {
val css = CssBuilder()
css.style {
select("body") {
fontFamily = base.mainFont
color = base.mainColor
backgroundColor = base.mainBackgroundColor
alignContent = AlignContent.initial()
}
select(".test") {
top = px(10)
left = em(5)
backgroundColor = Color.rgba(255, 255, 255, 0.75)
select("> a") {
color = Color.hsl(200, 50, 50)
}
}
select("nav") {
select("ul") {
color = Color.hsl(0, 100, 25)
backgroundColor = base.mainBackgroundColor
}
select("li") {
sizePX(25, 25, 200, 200)
select("a") {
width = px(725)
background = text("")
backgroundColor = base.mainBackgroundColor
}
}
}
}
return css.getCss()
}
fun main() {
val css1 = generateCss(StyleBase())
val css2 = generateCss(StyleBase(
Color.hsl(32, 40, 50),
Color.hsl(64, 60, 35),
text("Courier")
))
println(css1)
println(css2)
val sd = css {
select("#pipo") {
backgroundColor = Color.hex("eeeeee")
fontFamily = text("Arial, Courier")
animationDelay = listOf(DelayDuration.initial())
select("div") {
color = Color.hex("1b1b1b1")
alignContent = AlignContent.flexStart()
animationName = listOf(text("foo"), text("bar"))
animationIterationCount = listOf(
Count.count(3), Count.infinite())
animationTimingFunction = listOf(AnimationTimingFunction.cubicBezier(0.1, 0.2, 0.3, 0.4), AnimationTimingFunction.easeInOut())
}
}
}
println("======")
println(sd.generateCss())
}

View File

@@ -1,167 +0,0 @@
package nl.astraeus.css
import nl.astraeus.css.properties.*
import nl.astraeus.css.properties.AlignContent.Companion.flexStart
import nl.astraeus.css.style.Css
import nl.astraeus.css.style.Style
class StyleBase(
val mainColor: Color = Color.hsl(128, 50, 50),
val mainBackgroundColor: Color = Color.hsl(64, 50, 50),
val mainFont: TextProperty = text("Arial")
)
private fun Style.sizePX(
left: Int,
top: Int,
width: Int,
height: Int
) {
this@sizePX.top = Measurement.px(top)
this@sizePX.left = Measurement.px(left)
this@sizePX.width = Measurement.px(width)
this@sizePX.height = Measurement.px(height)
}
private fun generateCss(
base: StyleBase
): String {
val css = CssBuilder()
css.style {
select("body") {
fontFamily = base.mainFont
color = base.mainColor
backgroundColor = base.mainBackgroundColor
}
select(".test") {
top = Measurement.px(10)
left = Measurement.em(5)
backgroundColor = Color.rgba(255, 255, 255, 0.75)
select("> a") {
color = Color.hsl(200, 50, 50)
}
}
select("nav") {
select("ul") {
color = Color.hsl(0, 100, 25)
backgroundColor = base.mainBackgroundColor
}
select("li") {
sizePX(25, 25, 200, 200)
select("a") {
width = Measurement.px(725)
background = text("red initial")
backgroundColor = base.mainBackgroundColor
all = All.initial()
}
}
}
}
return css.getCss()
}
fun main() {
val css1 = generateCss(StyleBase())
val css2 = generateCss(StyleBase(
Color.hsl(32, 40, 50),
Color.hsl(64, 60, 35),
text("Courier")
))
println(css1)
println(css2)
val border = css {
borderRadius = BorderRadius(1, 2, 3, 4)
borderColor = listOf(Color.hsl(22,66,55))
select("a") {
width = Measurement.px(10)
}
}
val border2: Css = {
borderRadius = BorderRadius(1, 2, 3, 4)
borderColor = listOf(Color.hsl(20,60,50))
}
val font: Css = {
fontFamily = text("Arial, Courier")
fontSize = FontSize.larger()
}
val sd = style {
select("#pipo") {
backgroundColor = Color.hex("eeeeee")
fontFamily = text("Arial, Courier")
animationDelay = listOf(DelayDuration.initial())
select("div") {
fontFace {
fontFamily = text("SanSation")
fontSize = FontSize.larger()
src = text("font/sansation_bold.woff")
fontStretch = FontStretch.condensed()
fontStyle = FontStyle.italic()
fontWeight = FontWeight._600()
}
fontFamily = text("SanSation")
color = Color.hex("1b1b1b1")
alignContent = flexStart()
animationName = listOf(
text("foo"),
text("bar")
)
select("span") {
animationIterationCount = listOf(
Count.count(3),
Count.infinite()
)
animationTimingFunction = listOf(
AnimationTimingFunction.cubicBezier(0.1, 0.2, 0.3, 0.4),
AnimationTimingFunction.easeInOut()
)
}
select("border-0") {
apply(border)
borderRadius = BorderRadius(4, 5, 6, 7)
}
select("border-1") {
apply(border2)
borderRadius = BorderRadius(4, 5, 6, 7)
}
select("border-2") {
borderRadius = BorderRadius(4, 5, 6, 7)
apply(border2)
display = Display.none()
borderBottomWidth = BorderWidth.perc(13)
}
}
}
}
val borderStyle = style {
select(".border") {
apply(border)
apply(font)
select("> p") {
fontSize = FontSize.smaller()
}
}
}
println("======")
println(sd.generateCss())
println("======")
println(sd.generateCss(minified = true))
println("======")
println(borderStyle.generateCss())
}