Add Hsla color functions, v. 0.3.10-SNAPSHOT
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,3 +2,4 @@
|
||||
build
|
||||
.idea
|
||||
local.properties
|
||||
gradle.properties
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
import org.jetbrains.kotlin.fir.declarations.builder.buildResolvedImport
|
||||
|
||||
plugins {
|
||||
kotlin("multiplatform") version "1.4.0-rc"
|
||||
kotlin("multiplatform") version "1.4.30"
|
||||
`maven-publish`
|
||||
}
|
||||
|
||||
group = "nl.astraeus"
|
||||
version = "0.3.6-SNAPSHOT"
|
||||
version = "0.3.10-SNAPSHOT"
|
||||
|
||||
repositories {
|
||||
maven { setUrl("https://dl.bintray.com/kotlin/kotlin-eap") }
|
||||
@@ -17,21 +15,36 @@ repositories {
|
||||
kotlin {
|
||||
jvm()
|
||||
js(BOTH) {
|
||||
browser()
|
||||
|
||||
//produceKotlinLibrary()
|
||||
}
|
||||
val hostOs = System.getProperty("os.name")
|
||||
val isMingwX64 = hostOs.startsWith("Windows")
|
||||
val nativeTarget = when {
|
||||
hostOs == "Mac OS X" -> macosX64("native")
|
||||
hostOs == "Linux" -> linuxX64("native")
|
||||
isMingwX64 -> mingwX64("native")
|
||||
else -> throw GradleException("Host OS is not supported in Kotlin/Native.")
|
||||
browser {
|
||||
testTask {
|
||||
useKarma {
|
||||
useFirefox()
|
||||
//useChrome()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
val commonMain by getting {}
|
||||
val commonMain by getting {
|
||||
|
||||
}
|
||||
val commonTest by getting {
|
||||
dependencies {
|
||||
implementation(kotlin("test-common"))
|
||||
implementation(kotlin("test-annotations-common"))
|
||||
}
|
||||
}
|
||||
val jvmTest by getting {
|
||||
dependencies {
|
||||
implementation(kotlin("test-junit"))
|
||||
}
|
||||
}
|
||||
val jsTest by getting {
|
||||
dependencies {
|
||||
implementation(kotlin("test-js"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,3 +81,4 @@ publishing {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
kotlin.code.style=official
|
||||
kotlin.js.compiler=both
|
||||
|
||||
nexusUsername=
|
||||
nexusPassword=
|
||||
|
||||
nexusUsername=deployment
|
||||
nexusPassword=nhPTzBWizph86j2Jz5KhPdiB4C
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
package nl.astraeus.css.properties
|
||||
|
||||
class Color(
|
||||
value: String,
|
||||
val readOnly: Boolean = true
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
open class Color(
|
||||
value: String,
|
||||
val readOnly: Boolean = false
|
||||
) : CssProperty(value) {
|
||||
|
||||
/* val hue: Int? = null
|
||||
val saturation: Int? = null
|
||||
val lightness: Int? = null
|
||||
@@ -41,42 +45,46 @@ class Color(
|
||||
return this
|
||||
}*/
|
||||
|
||||
companion object {
|
||||
val auto = Color("auto")
|
||||
val transparant = Color("transparant")
|
||||
val initial = Color("initial")
|
||||
val inherit = Color("inherit")
|
||||
fun hex(hex: String) = Color("#$hex")
|
||||
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, $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%, $alpha)")
|
||||
companion object {
|
||||
val auto = Color("auto", true)
|
||||
val transparant = Color("transparant", true)
|
||||
val initial = Color("initial", true)
|
||||
val inherit = Color("inherit", true)
|
||||
|
||||
private fun fromHex(
|
||||
red: Int,
|
||||
green: Int,
|
||||
blue: Int
|
||||
) {
|
||||
fun hex(hex: String) = Color("#$hex")
|
||||
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, $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%, $alpha)")
|
||||
|
||||
private fun fromHex(
|
||||
red: Int,
|
||||
green: Int,
|
||||
blue: Int
|
||||
) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ interface CssValue {
|
||||
}
|
||||
|
||||
open class CssProperty(
|
||||
val value: String
|
||||
var value: String
|
||||
): CssValue {
|
||||
|
||||
override fun css(): String = value
|
||||
|
||||
168
src/commonMain/kotlin/nl/astraeus/css/properties/HslaColor.kt
Normal file
168
src/commonMain/kotlin/nl/astraeus/css/properties/HslaColor.kt
Normal file
@@ -0,0 +1,168 @@
|
||||
package nl.astraeus.css.properties
|
||||
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
class HslaColor(
|
||||
val hue: Int,
|
||||
val saturation: Int,
|
||||
val lightness: Int,
|
||||
val alpha: Double = 1.0
|
||||
): Color("hsla($hue,$saturation%,$lightness%,$alpha)") {
|
||||
|
||||
fun darken(amount: Int): HslaColor = HslaColor(
|
||||
hue,
|
||||
saturation,
|
||||
max(0, lightness - amount),
|
||||
alpha
|
||||
)
|
||||
|
||||
fun lighten(amount: Int): HslaColor = HslaColor(
|
||||
hue,
|
||||
saturation,
|
||||
min(100, lightness + amount),
|
||||
alpha
|
||||
)
|
||||
|
||||
fun saturize(amount: Int): HslaColor = HslaColor(
|
||||
hue,
|
||||
min(100, saturation + amount),
|
||||
lightness,
|
||||
alpha
|
||||
)
|
||||
|
||||
fun desaturize(amount: Int): HslaColor = HslaColor(
|
||||
hue,
|
||||
max(0, saturation - amount),
|
||||
lightness,
|
||||
alpha
|
||||
)
|
||||
|
||||
fun adjustHue(amount: Int): HslaColor {
|
||||
var hue = this.hue + amount
|
||||
while (hue < 0) {
|
||||
hue += 360
|
||||
}
|
||||
while(hue > 359) {
|
||||
hue -= 360
|
||||
}
|
||||
|
||||
return HslaColor(
|
||||
hue,
|
||||
saturation,
|
||||
lightness,
|
||||
alpha
|
||||
)
|
||||
}
|
||||
|
||||
fun toRgba() = RgbaColor.fromHsla(this)
|
||||
|
||||
companion object {
|
||||
private fun findValues(value: String, expectedNumber: Int): List<String> {
|
||||
check(value.contains('(') && value.contains(')'))
|
||||
|
||||
val parts = value.split('(')[1].split(')')[0].split(',')
|
||||
|
||||
check(parts.size == expectedNumber)
|
||||
|
||||
return parts
|
||||
}
|
||||
|
||||
fun fromString(value: String): HslaColor = when {
|
||||
value.trim().startsWith("#") -> {
|
||||
fromHex(value.substringAfterLast('#'))
|
||||
}
|
||||
value.trim().startsWith("hsla") -> {
|
||||
val values = findValues(value, 4)
|
||||
HslaColor(
|
||||
values[0].trim().toInt(),
|
||||
values[1].trim().toInt(),
|
||||
values[2].trim().toInt(),
|
||||
values[3].trim().toDouble()
|
||||
)
|
||||
}
|
||||
value.trim().startsWith("hsl") -> {
|
||||
val values = findValues(value, 3)
|
||||
HslaColor(
|
||||
values[0].trim().toInt(),
|
||||
values[1].trim().toInt(),
|
||||
values[2].trim().toInt()
|
||||
)
|
||||
}
|
||||
value.trim().startsWith("rgba") -> {
|
||||
val values = findValues(value, 4)
|
||||
fromRgba(
|
||||
values[0].trim().toInt(),
|
||||
values[1].trim().toInt(),
|
||||
values[2].trim().toInt(),
|
||||
values[3].trim().toDouble()
|
||||
)
|
||||
}
|
||||
value.trim().startsWith("rgb") -> {
|
||||
val values = findValues(value, 3)
|
||||
fromRgb(
|
||||
values[0].trim().toInt(),
|
||||
values[1].trim().toInt(),
|
||||
values[2].trim().toInt()
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
throw IllegalArgumentException("Unable to parse $value as color")
|
||||
}
|
||||
}
|
||||
|
||||
fun fromHex(value: String): HslaColor = fromRgba(RgbaColor.fromHex(value))
|
||||
|
||||
fun fromRgba(rgba: RgbaColor): HslaColor = fromRgba(rgba.red, rgba.green, rgba.blue, rgba.alpha)
|
||||
|
||||
fun fromRgb(
|
||||
red: Int,
|
||||
green: Int,
|
||||
blue: Int,
|
||||
): HslaColor {
|
||||
return fromRgba(red, green, blue, 1.0)
|
||||
}
|
||||
|
||||
fun fromRgba(
|
||||
red: Int,
|
||||
green: Int,
|
||||
blue: Int,
|
||||
alpha: Double
|
||||
): HslaColor {
|
||||
val r = red / 255.0
|
||||
val g = green / 255.0
|
||||
val b = blue / 255.0
|
||||
|
||||
val v = max(r,max(g,b))
|
||||
val c = v - min(r,min(g,b))
|
||||
val f = (1 - abs(v+v-c-1))
|
||||
var h = if (c > 0) {
|
||||
when (v) {
|
||||
r -> {
|
||||
(g-b)/c
|
||||
}
|
||||
g -> {
|
||||
2+(b-r)/c
|
||||
}
|
||||
else -> {
|
||||
2+(b-r)/c
|
||||
}
|
||||
}
|
||||
} else {
|
||||
0.0
|
||||
}
|
||||
|
||||
if (h < 0) {
|
||||
h += 6
|
||||
}
|
||||
|
||||
return HslaColor(
|
||||
(60*h).toInt(),
|
||||
if (f>0) { ((c * 100)/f).toInt() } else { 0 },
|
||||
(100*((v+v-c)/2)).toInt(),
|
||||
alpha
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,28 +11,41 @@ open class Measurement(
|
||||
val normal = Measurement("normal")
|
||||
|
||||
fun px(nr: Int) = if (nr == 0) { Measurement("0") } else { Measurement("${nr}px") }
|
||||
fun px(nr: Double) = Measurement("${nr}px")
|
||||
fun em(nr: Int) = Measurement("${nr}em")
|
||||
fun em(nr: Double) = Measurement("${nr}em")
|
||||
fun perc(nr: Int) = Measurement("${nr}%")
|
||||
fun perc(nr: Double) = Measurement("${nr}%")
|
||||
fun pc(nr: Int) = Measurement("${nr}pc")
|
||||
fun pc(nr: Double) = Measurement("${nr}pc")
|
||||
fun cm(nr: Int) = Measurement("${nr}cm")
|
||||
fun cm(nr: Double) = Measurement("${nr}cm")
|
||||
fun px(nr: Double) = nr.px
|
||||
fun em(nr: Int) = nr.em
|
||||
fun em(nr: Double) = nr.em
|
||||
fun perc(nr: Int) = nr.perc
|
||||
fun perc(nr: Double) = nr.perc
|
||||
fun pc(nr: Int) = nr.pc
|
||||
fun pc(nr: Double) = nr.pc
|
||||
fun cm(nr: Int) = nr.cm
|
||||
fun cm(nr: Double) = nr.cm
|
||||
}
|
||||
}
|
||||
|
||||
val Int.px: Measurement
|
||||
get() = Measurement("${this}${if (this == 0) { "" } else { "px"}}")
|
||||
val Int.em: Measurement
|
||||
get() = Measurement("${this}${if (this == 0) { "" } else { "em"}}")
|
||||
val Int.perc: Measurement
|
||||
get() = Measurement("${this}%")
|
||||
val Int.pc: Measurement
|
||||
get() = Measurement("${this}pc")
|
||||
val Int.cm: Measurement
|
||||
get() = Measurement("${this}cm")
|
||||
fun Int.px(): Measurement = Measurement.px(this)
|
||||
|
||||
val Double.px: Measurement
|
||||
get() = Measurement("${this}px")
|
||||
val Double.em: Measurement
|
||||
get() = Measurement("${this}em")
|
||||
val Double.perc: Measurement
|
||||
get() = Measurement("${this}%")
|
||||
val Double.pc: Measurement
|
||||
get() = Measurement("${this}pc")
|
||||
val Double.cm: Measurement
|
||||
get() = Measurement("${this}cm")
|
||||
fun Double.px(): Measurement = Measurement.px(this)
|
||||
fun Int.em(): Measurement = Measurement.em(this)
|
||||
fun Double.em(): Measurement = Measurement.em(this)
|
||||
fun Int.perc(): Measurement = Measurement.perc(this)
|
||||
fun Double.perc(): Measurement = Measurement.perc(this)
|
||||
fun Int.pc(): Measurement = Measurement.pc(this)
|
||||
fun Double.pc(): Measurement = Measurement.pc(this)
|
||||
fun Int.cm(): Measurement = Measurement.cm(this)
|
||||
fun Double.cm(): Measurement = Measurement.cm(this)
|
||||
|
||||
open class LineHeight(value: String) : CssProperty(value) {
|
||||
companion object {
|
||||
|
||||
107
src/commonMain/kotlin/nl/astraeus/css/properties/RgbaColor.kt
Normal file
107
src/commonMain/kotlin/nl/astraeus/css/properties/RgbaColor.kt
Normal file
@@ -0,0 +1,107 @@
|
||||
package nl.astraeus.css.properties
|
||||
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
class RgbaColor(
|
||||
val red: Int,
|
||||
val green: Int,
|
||||
val blue: Int,
|
||||
val alpha: Double = 1.0
|
||||
): Color("rgba($red,$green,$blue,$alpha)") {
|
||||
|
||||
fun toHsla(): HslaColor = HslaColor.fromRgba(this)
|
||||
|
||||
companion object {
|
||||
private fun findValues(value: String, expectedNumber: Int): List<String> {
|
||||
check(value.contains('(') && value.contains(')'))
|
||||
|
||||
val parts = value.split('(')[1].split(')')[0].split(',')
|
||||
|
||||
check(parts.size == expectedNumber)
|
||||
|
||||
return parts
|
||||
}
|
||||
|
||||
fun fromString(value: String): RgbaColor = when {
|
||||
value.trim().startsWith("#") -> {
|
||||
fromHex(value.substringAfterLast('#'))
|
||||
}
|
||||
value.trim().startsWith("hsla") -> {
|
||||
val values = findValues(value, 4)
|
||||
fromHsla(
|
||||
values[0].toInt(),
|
||||
values[1].toInt(),
|
||||
values[2].toInt(),
|
||||
values[3].toDouble()
|
||||
)
|
||||
}
|
||||
value.trim().startsWith("hsl") -> {
|
||||
val values = findValues(value, 3)
|
||||
fromHsl(
|
||||
values[0].toInt(),
|
||||
values[1].toInt(),
|
||||
values[2].toInt()
|
||||
)
|
||||
}
|
||||
value.trim().startsWith("rgba") -> {
|
||||
val values = findValues(value, 4)
|
||||
RgbaColor(
|
||||
values[0].toInt(),
|
||||
values[1].toInt(),
|
||||
values[2].toInt(),
|
||||
values[3].toDouble()
|
||||
)
|
||||
}
|
||||
value.trim().startsWith("rgb") -> {
|
||||
val values = findValues(value, 3)
|
||||
RgbaColor(
|
||||
values[0].toInt(),
|
||||
values[1].toInt(),
|
||||
values[2].toInt()
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
throw IllegalArgumentException("Unable to parse $value as color")
|
||||
}
|
||||
}
|
||||
|
||||
fun fromHex(value: String): RgbaColor {
|
||||
TODO("Implement parsing hex to rgba")
|
||||
}
|
||||
|
||||
fun fromHsla(hsla: HslaColor): RgbaColor = fromHsla(
|
||||
hsla.hue,
|
||||
hsla.saturation,
|
||||
hsla.lightness,
|
||||
hsla.alpha
|
||||
)
|
||||
|
||||
fun fromHsl(
|
||||
hue: Int,
|
||||
saturation: Int,
|
||||
lightness: Int
|
||||
): RgbaColor {
|
||||
return fromHsla(hue, saturation, lightness, 1.0)
|
||||
}
|
||||
|
||||
fun fromHsla(
|
||||
hue: Int,
|
||||
saturation: Int,
|
||||
lightness: Int,
|
||||
alpha: Double
|
||||
): RgbaColor {
|
||||
val h = hue
|
||||
val s = saturation / 100.0
|
||||
val l = lightness / 100.0
|
||||
|
||||
val a = s * min(l, 1 - l)
|
||||
fun f(n: Int): Int {
|
||||
val k: Int = (n + h / 30) % 12
|
||||
return (255 * (l - a * max(min(k - 3, min(9 - k, 1)), -1))).toInt()
|
||||
}
|
||||
|
||||
return RgbaColor(f(0), f(8), f(4), alpha)
|
||||
}
|
||||
}
|
||||
}
|
||||
71
src/commonTest/kotlin/nl/astraeus/css/TestColor.kt
Normal file
71
src/commonTest/kotlin/nl/astraeus/css/TestColor.kt
Normal file
@@ -0,0 +1,71 @@
|
||||
package nl.astraeus.css
|
||||
|
||||
import nl.astraeus.css.properties.*
|
||||
import kotlin.test.Test
|
||||
|
||||
class TestColor {
|
||||
|
||||
@Test
|
||||
fun testBuilder() {
|
||||
val css = style {
|
||||
val baseColor = HslaColor(20, 50, 50)
|
||||
val baseColorRgb = RgbaColor.fromHsla(baseColor)
|
||||
|
||||
println("BaseColor: ${baseColor.value} - ${baseColorRgb.value}")
|
||||
|
||||
val darkerColor = baseColor.darken(10)
|
||||
val darkerColorRgb = RgbaColor.fromHsla(darkerColor)
|
||||
println("DarkerColor: ${darkerColor.value} - ${darkerColorRgb.value}")
|
||||
|
||||
val saturizedColor = baseColor.saturize(10)
|
||||
val saturizedColorRgb = RgbaColor.fromHsla(saturizedColor)
|
||||
println("SaturizedColor: ${saturizedColor.value} - ${saturizedColorRgb.value}")
|
||||
|
||||
val redColor = RgbaColor(0,255,0,1.0)
|
||||
val redColorHsla = redColor.toHsla()
|
||||
val shiftedColor = redColorHsla.adjustHue(120)
|
||||
val shiftedColorRgb = shiftedColor.toRgba()
|
||||
|
||||
println("RedColor: ${redColor.value} - ${redColorHsla.value}")
|
||||
println("ShiftedColor: ${shiftedColor.value} - ${shiftedColorRgb.value}")
|
||||
|
||||
select(".test") {
|
||||
top(10.px)
|
||||
left(4.em)
|
||||
|
||||
backgroundColor(
|
||||
RgbaColor.fromHsla(baseColor.darken(10))
|
||||
)
|
||||
|
||||
animationIterationMode(
|
||||
Count.auto,
|
||||
Count.auto,
|
||||
Count.auto,
|
||||
Count.auto,
|
||||
Count.auto
|
||||
)
|
||||
|
||||
child("li") {
|
||||
color(Color.hsl(200, 50, 50))
|
||||
}
|
||||
|
||||
select("> a") {
|
||||
color(Color.hsl(200, 50, 50))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
println(css.generateCss())
|
||||
|
||||
val css2 = style {
|
||||
cls("button") {
|
||||
fontSize(12.px)
|
||||
color(Color.hsl(200, 50, 50))
|
||||
}
|
||||
}
|
||||
|
||||
println(css2.generateCss())
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,16 +1,20 @@
|
||||
package nl.astraeus.css
|
||||
|
||||
object TestCssBuilder {
|
||||
/*
|
||||
@Test
|
||||
fun testBuilder() {
|
||||
val css = CssBuilder()
|
||||
import nl.astraeus.css.properties.Color.Companion.hsl
|
||||
import nl.astraeus.css.properties.Color.Companion.rgba
|
||||
import nl.astraeus.css.properties.Count
|
||||
import nl.astraeus.css.properties.em
|
||||
import nl.astraeus.css.properties.px
|
||||
|
||||
css.style {
|
||||
object TestCssBuilder {
|
||||
|
||||
//@Test
|
||||
fun testBuilder() {
|
||||
val css = css {
|
||||
|
||||
select(".test") {
|
||||
top(10.px())
|
||||
left(4.em())
|
||||
top(10.px)
|
||||
left(4.em)
|
||||
backgroundColor(rgba(255, 255, 255, 0.75))
|
||||
animationIterationMode(
|
||||
Count.auto,
|
||||
@@ -20,6 +24,9 @@ object TestCssBuilder {
|
||||
Count.auto
|
||||
)
|
||||
|
||||
child("li") {
|
||||
color(hsl(200,50,50))
|
||||
}
|
||||
|
||||
select("> a") {
|
||||
color(hsl(200, 50, 50))
|
||||
@@ -28,6 +35,17 @@ object TestCssBuilder {
|
||||
}
|
||||
|
||||
println(css)
|
||||
}*/
|
||||
|
||||
val css2 = css {
|
||||
cls("button") {
|
||||
fontSize(12.px)
|
||||
color(hsl(200, 50, 50))
|
||||
}
|
||||
}
|
||||
|
||||
println(css2)
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user