Browse Source

CSS units API is CSSOM-agnostic and supports homogenous arithmetic operations

pull/764/head 0.5.0-build219
Shagen Ogandzhanian 3 years ago
parent
commit
6048760a1a
  1. 24
      examples/web_landing/src/jsMain/kotlin/com/sample/style/Stylesheet.kt
  2. 4
      examples/web_landing/src/jsMain/kotlin/com/sample/style/WtCol.kt
  3. 28
      web/benchmark-core/src/jsMain/kotlin/com/sample/style/Stylesheet.kt
  4. 8
      web/benchmark-core/src/jsMain/kotlin/com/sample/style/WtCol.kt
  5. 105
      web/core/src/jsMain/kotlin/androidx/compose/web/css/CSS.kt
  6. 8
      web/core/src/jsMain/kotlin/androidx/compose/web/css/CSSMediaRule.kt
  7. 77
      web/core/src/jsMain/kotlin/androidx/compose/web/css/CSSProperties.kt
  8. 285
      web/core/src/jsMain/kotlin/androidx/compose/web/css/CSSUnits.kt
  9. 8
      web/core/src/jsMain/kotlin/androidx/compose/web/css/Color.kt
  10. 291
      web/core/src/jsTest/kotlin/CSSUnitApiTests.kt

24
examples/web_landing/src/jsMain/kotlin/com/sample/style/Stylesheet.kt

@ -7,18 +7,18 @@ object AppCSSVariables : CSSVariables {
val wtColorGreyLight by variable<Color>()
val wtColorGreyDark by variable<Color>()
val wtOffsetTopUnit by variable<CSSSizeValue>()
val wtHorizontalLayoutGutter by variable<CSSSizeValue>()
val wtFlowUnit by variable<CSSSizeValue>()
val wtHeroFontSize by variable<CSSSizeValue>()
val wtHeroLineHeight by variable<CSSSizeValue>()
val wtSubtitle2FontSize by variable<CSSSizeValue>()
val wtSubtitle2LineHeight by variable<CSSSizeValue>()
val wtH2FontSize by variable<CSSSizeValue>()
val wtH2LineHeight by variable<CSSSizeValue>()
val wtH3FontSize by variable<CSSSizeValue>()
val wtH3LineHeight by variable<CSSSizeValue>()
val wtOffsetTopUnit by variable<CSSUnitValue>()
val wtHorizontalLayoutGutter by variable<CSSUnitValue>()
val wtFlowUnit by variable<CSSUnitValue>()
val wtHeroFontSize by variable<CSSUnitValue>()
val wtHeroLineHeight by variable<CSSUnitValue>()
val wtSubtitle2FontSize by variable<CSSUnitValue>()
val wtSubtitle2LineHeight by variable<CSSUnitValue>()
val wtH2FontSize by variable<CSSUnitValue>()
val wtH2LineHeight by variable<CSSUnitValue>()
val wtH3FontSize by variable<CSSUnitValue>()
val wtH3LineHeight by variable<CSSUnitValue>()
val wtColCount by variable<Int>()
}

4
examples/web_landing/src/jsMain/kotlin/com/sample/style/WtCol.kt

@ -4,7 +4,7 @@ import org.jetbrains.compose.web.css.*
import org.jetbrains.compose.web.css.selectors.CSSSelector
fun <TBuilder> GenericStyleSheetBuilder<TBuilder>.mediaMaxWidth(
value: CSSSizeValue,
value: CSSUnitValue,
cssSelector: CSSSelector,
rulesBuild: TBuilder.() -> Unit
) {
@ -13,7 +13,7 @@ fun <TBuilder> GenericStyleSheetBuilder<TBuilder>.mediaMaxWidth(
}
}
fun CSSBuilder.forMaxWidth(value: CSSSizeValue, builder: CSSBuilder.() -> Unit) {
fun CSSBuilder.forMaxWidth(value: CSSUnitValue, builder: CSSBuilder.() -> Unit) {
mediaMaxWidth(value, self, builder)
}

28
web/benchmark-core/src/jsMain/kotlin/com/sample/style/Stylesheet.kt

@ -1,28 +1,24 @@
package com.sample.style
import androidx.compose.runtime.Composable
import org.jetbrains.compose.web.css.*
import org.jetbrains.compose.web.css.selectors.*
import org.jetbrains.compose.web.attributes.*
import org.jetbrains.compose.web.dom.*
import org.jetbrains.compose.web.*
object AppCSSVariables : CSSVariables {
val wtColorGreyLight by variable<Color>()
val wtColorGreyDark by variable<Color>()
val wtOffsetTopUnit by variable<CSSSizeValue>()
val wtHorizontalLayoutGutter by variable<CSSSizeValue>()
val wtFlowUnit by variable<CSSSizeValue>()
val wtHeroFontSize by variable<CSSSizeValue>()
val wtHeroLineHeight by variable<CSSSizeValue>()
val wtSubtitle2FontSize by variable<CSSSizeValue>()
val wtSubtitle2LineHeight by variable<CSSSizeValue>()
val wtH2FontSize by variable<CSSSizeValue>()
val wtH2LineHeight by variable<CSSSizeValue>()
val wtH3FontSize by variable<CSSSizeValue>()
val wtH3LineHeight by variable<CSSSizeValue>()
val wtOffsetTopUnit by variable<CSSUnitValue>()
val wtHorizontalLayoutGutter by variable<CSSUnitValue>()
val wtFlowUnit by variable<CSSUnitValue>()
val wtHeroFontSize by variable<CSSUnitValue>()
val wtHeroLineHeight by variable<CSSUnitValue>()
val wtSubtitle2FontSize by variable<CSSUnitValue>()
val wtSubtitle2LineHeight by variable<CSSUnitValue>()
val wtH2FontSize by variable<CSSUnitValue>()
val wtH2LineHeight by variable<CSSUnitValue>()
val wtH3FontSize by variable<CSSUnitValue>()
val wtH3LineHeight by variable<CSSUnitValue>()
val wtColCount by variable<Int>()
}

8
web/benchmark-core/src/jsMain/kotlin/com/sample/style/WtCol.kt

@ -1,14 +1,10 @@
package com.sample.style
import androidx.compose.runtime.Composable
import org.jetbrains.compose.web.css.*
import org.jetbrains.compose.web.css.selectors.*
import org.jetbrains.compose.web.attributes.*
import org.jetbrains.compose.web.dom.*
import org.jetbrains.compose.web.*
fun <TBuilder> GenericStyleSheetBuilder<TBuilder>.mediaMaxWidth(
value: CSSSizeValue,
value: CSSUnitValue,
cssSelector: CSSSelector,
rulesBuild: TBuilder.() -> Unit
) {
@ -17,7 +13,7 @@ fun <TBuilder> GenericStyleSheetBuilder<TBuilder>.mediaMaxWidth(
}
}
fun CSSBuilder.forMaxWidth(value: CSSSizeValue, builder: CSSBuilder.() -> Unit) {
fun CSSBuilder.forMaxWidth(value: CSSUnitValue, builder: CSSBuilder.() -> Unit) {
mediaMaxWidth(value, self, builder)
}

105
web/core/src/jsMain/kotlin/androidx/compose/web/css/CSS.kt

@ -87,7 +87,7 @@ interface CSSNumberish {
}
fun CSSNumberish.asNumber() = this.asDynamic() as? Number
fun CSSNumberish.asCSSNumericValue(): CSSNumericValue? = this.asDynamic() as? CSSNumericValueJS
fun CSSNumberish.asCSSNumericValue(): CSSNumericValue? = this.asDynamic() as? CSSNumericValue
// declare enum CSSNumericBaseType {
// 'length',
@ -124,47 +124,7 @@ val CSSNumericType.percentHint
get() = CSSNumericBaseType.valueOf(this.asDynamic().percentHint)
// set(value) { this.asDynamic().percentHint = value.value }
external interface CSSNumericValue : CSSStyleValue {
fun add(vararg values: CSSNumberish): CSSNumericValue
fun sub(vararg values: CSSNumberish): CSSNumericValue
fun mul(vararg values: CSSNumberish): CSSNumericValue
fun div(vararg values: CSSNumberish): CSSNumericValue
fun min(vararg values: CSSNumberish): CSSNumericValue
fun max(vararg values: CSSNumberish): CSSNumericValue
fun to(unit: String): CSSUnitValue
fun toSum(vararg units: String): CSSMathSum
fun type(): CSSNumericType
@Suppress("NESTED_CLASS_IN_EXTERNAL_INTERFACE")
companion object {
fun parse(cssText: String): CSSNumericValue
}
}
abstract external class CSSNumericValueJS : CSSNumericValue {
override fun add(vararg values: CSSNumberish): CSSNumericValue
override fun sub(vararg values: CSSNumberish): CSSNumericValue
override fun mul(vararg values: CSSNumberish): CSSNumericValue
override fun div(vararg values: CSSNumberish): CSSNumericValue
override fun min(vararg values: CSSNumberish): CSSNumericValue
override fun max(vararg values: CSSNumberish): CSSNumericValue
override fun to(unit: String): CSSUnitValue
override fun toSum(vararg units: String): CSSMathSum
override fun type(): CSSNumericType
}
external interface CSSUnitValue : CSSNumericValue {
val value: Number
val unit: String
}
@JsName("CSSUnitValue")
external class CSSUnitValueJS(value: Number, unit: String) : CSSNumericValueJS, CSSUnitValue {
override val value: Number
override val unit: String
}
external interface CSSNumericValue : CSSStyleValue
// declare enum CSSMathOperator {
// 'sum',
@ -185,9 +145,7 @@ enum class CSSMathOperator(val value: String) {
clamp("clamp")
}
open external class CSSMathValue : CSSNumericValueJS {
// readonly operator: CSSMathOperator
}
open external class CSSMathValue : CSSNumericValue
val CSSMathValue.operator
get() = CSSMathOperator.valueOf(this.asDynamic().operator)
@ -217,16 +175,6 @@ external class CSSMathMax(vararg args: CSSNumberish) : CSSMathValue {
val values: CSSNumericArray
}
// TODO(yavanosta) : conflict with base class properties
// Since there is no support for this class in any browser, it's better
// wait for the implementation.
// declare class CSSMathClamp extends CSSMathValue {
// constructor(min: CSSNumberish, val: CSSNumberish, max: CSSNumberish)
// readonly min: CSSNumericValue
// readonly val: CSSNumericValue
// readonly max: CSSNumericValue
// }
external class CSSNumericArray {
// TODO: [Symbol.iterator]() : IterableIterator<CSSNumericValue>
fun forEach(handler: (CSSNumericValue) -> Unit)
@ -340,6 +288,7 @@ external interface StylePropertyValue
fun String.asStylePropertyValue() = unsafeCast<StylePropertyValue>()
fun Number.asStylePropertyValue() = unsafeCast<StylePropertyValue>()
fun CSSStyleValue.asStylePropertyValue() = unsafeCast<StylePropertyValue>()
fun CSSUnitValue.asStylePropertyValue() = asString().asStylePropertyValue()
external class StylePropertyMap : StylePropertyMapReadOnly {
fun set(property: String, vararg values: StylePropertyValue)
@ -351,51 +300,5 @@ external class StylePropertyMap : StylePropertyMapReadOnly {
inline fun Element.computedStyleMap(): StylePropertyMapReadOnly =
this.asDynamic().computedStyleMap().unsafeCast<StylePropertyMapReadOnly>()
external class CSS {
companion object {
fun number(value: Number): CSSUnitValue
fun percent(value: Number): CSSpercentValue
// <length>
fun em(value: Number): CSSemValue
fun ex(value: Number): CSSexValue
fun ch(value: Number): CSSchValue
fun rem(value: Number): CSSremValue
fun vw(value: Number): CSSvwValue
fun vh(value: Number): CSSvhValue
fun vmin(value: Number): CSSvminValue
fun vmax(value: Number): CSSvmaxValue
fun cm(value: Number): CSScmValue
fun mm(value: Number): CSSmmValue
fun Q(value: Number): CSSQValue
fun pt(value: Number): CSSptValue
fun pc(value: Number): CSSpcValue
fun px(value: Number): CSSpxValue
// <angle>
fun deg(value: Number): CSSdegValue
fun grad(value: Number): CSSgradValue
fun rad(value: Number): CSSradValue
fun turn(value: Number): CSSturnValue
// <time>
fun s(value: Number): CSSsValue
fun ms(value: Number): CSSmsValue
// <frequency>
fun Hz(value: Number): CSSHzValue
fun kHz(value: Number): CSSkHzValue
// <resolution>
fun dpi(value: Number): CSSdpiValue
fun dpcm(value: Number): CSSdpcmValue
fun dppx(value: Number): CSSdppxValue
// <flex>
fun fr(value: Number): CSSfrValue
}
}
@Suppress("unused")
val cssTypedOMPolyfill = CSSTypedOMPolyfill.default(window)

8
web/core/src/jsMain/kotlin/androidx/compose/web/css/CSSMediaRule.kt

@ -124,14 +124,14 @@ fun <TBuilder> GenericStyleSheetBuilder<TBuilder>.not(
query: CSSMediaQuery.Invertible
) = CSSMediaQuery.Not(query)
fun <TBuilder> GenericStyleSheetBuilder<TBuilder>.minWidth(value: CSSSizeValue) =
fun <TBuilder> GenericStyleSheetBuilder<TBuilder>.minWidth(value: CSSUnitValue) =
CSSMediaQuery.MediaFeature("min-width", value.asStylePropertyValue())
fun <TBuilder> GenericStyleSheetBuilder<TBuilder>.maxWidth(value: CSSSizeValue) =
fun <TBuilder> GenericStyleSheetBuilder<TBuilder>.maxWidth(value: CSSUnitValue) =
CSSMediaQuery.MediaFeature("max-width", value.asStylePropertyValue())
fun <TBuilder> GenericStyleSheetBuilder<TBuilder>.minHeight(value: CSSSizeValue) =
fun <TBuilder> GenericStyleSheetBuilder<TBuilder>.minHeight(value: CSSUnitValue) =
CSSMediaQuery.MediaFeature("min-height", value.asStylePropertyValue())
fun <TBuilder> GenericStyleSheetBuilder<TBuilder>.maxHeight(value: CSSSizeValue) =
fun <TBuilder> GenericStyleSheetBuilder<TBuilder>.maxHeight(value: CSSUnitValue) =
CSSMediaQuery.MediaFeature("max-height", value.asStylePropertyValue())

77
web/core/src/jsMain/kotlin/androidx/compose/web/css/CSSProperties.kt

@ -16,7 +16,7 @@ fun StyleBuilder.flexShrink(value: Number) {
property("flex-shrink", value.asStylePropertyValue())
}
fun StyleBuilder.opacity(value: CSSpercentValue) {
fun StyleBuilder.opacity(value: CSSSizeValue<CSSUnit.percent>) {
property("opacity", value(value.value as Double / 100))
}
@ -193,7 +193,7 @@ class CSSBorder : CustomStyleValue {
var style: StylePropertyValue? = null
var color: StylePropertyValue? = null
fun width(size: CSSSizeValue) {
fun width(size: CSSUnitValue) {
width = size.asStylePropertyValue()
}
@ -227,7 +227,7 @@ inline fun StyleBuilder.border(crossinline borderBuild: CSSBorder.() -> Unit) {
}
fun StyleBuilder.border(
width: CSSSizeValue? = null,
width: CSSUnitValue? = null,
style: LineStyle? = null,
color: Color? = null
) {
@ -291,97 +291,100 @@ fun StyleBuilder.position(position: Position) {
)
}
fun StyleBuilder.borderRadius(r: CSSSizeValue) {
property("border-radius", r.toString().asStylePropertyValue())
fun StyleBuilder.borderRadius(r: CSSUnitValue) {
property("border-radius", r.asStylePropertyValue())
}
fun StyleBuilder.borderRadius(topLeft: CSSSizeValue, bottomRight: CSSSizeValue) {
property("border-radius", "$topLeft $bottomRight".asStylePropertyValue())
fun StyleBuilder.borderRadius(topLeft: CSSUnitValue, bottomRight: CSSUnitValue) {
property("border-radius", "${topLeft.asString()} ${bottomRight.asString()}".asStylePropertyValue())
}
fun StyleBuilder.borderRadius(
topLeft: CSSSizeValue,
topRightAndBottomLeft: CSSSizeValue,
bottomRight: CSSSizeValue
topLeft: CSSUnitValue,
topRightAndBottomLeft: CSSUnitValue,
bottomRight: CSSUnitValue
) {
property("border-radius", "$topLeft $topRightAndBottomLeft $bottomRight".asStylePropertyValue())
property("border-radius", "${topLeft.asString()} ${topRightAndBottomLeft.asString()} ${bottomRight.asString()}".asStylePropertyValue())
}
fun StyleBuilder.borderRadius(
topLeft: CSSSizeValue,
topRight: CSSSizeValue,
bottomRight: CSSSizeValue,
bottomLeft: CSSSizeValue
topLeft: CSSUnitValue,
topRight: CSSUnitValue,
bottomRight: CSSUnitValue,
bottomLeft: CSSUnitValue
) {
property("border-radius", "$topLeft $topRight $bottomRight $bottomLeft".asStylePropertyValue())
property(
"border-radius",
"${topLeft.asString()} ${topRight.asString()} ${bottomRight.asString()} ${bottomLeft.asString()}".asStylePropertyValue()
)
}
fun StyleBuilder.width(value: CSSSizeValue) {
property("width", value)
fun StyleBuilder.width(value: CSSUnitValue) {
property("width", value.asStylePropertyValue())
}
fun StyleBuilder.width(value: CSSAutoValue) {
property("width", value)
}
fun StyleBuilder.height(value: CSSSizeValue) {
property("height", value)
fun StyleBuilder.height(value: CSSUnitValue) {
property("height", value.asStylePropertyValue())
}
fun StyleBuilder.height(value: CSSAutoValue) {
property("height", value)
}
fun StyleBuilder.top(value: CSSSizeValue) {
property("top", value)
fun StyleBuilder.top(value: CSSUnitValue) {
property("top", value.asStylePropertyValue())
}
fun StyleBuilder.top(value: CSSAutoValue) {
property("top", value)
}
fun StyleBuilder.bottom(value: CSSSizeValue) {
property("bottom", value)
fun StyleBuilder.bottom(value: CSSUnitValue) {
property("bottom", value.asStylePropertyValue())
}
fun StyleBuilder.bottom(value: CSSAutoValue) {
property("bottom", value)
}
fun StyleBuilder.left(value: CSSSizeValue) {
property("left", value)
fun StyleBuilder.left(value: CSSUnitValue) {
property("left", value.asStylePropertyValue())
}
fun StyleBuilder.left(value: CSSAutoValue) {
property("left", value)
}
fun StyleBuilder.right(value: CSSSizeValue) {
property("right", value)
fun StyleBuilder.right(value: CSSUnitValue) {
property("right", value.asStylePropertyValue())
}
fun StyleBuilder.right(value: CSSAutoValue) {
property("right", value)
}
fun StyleBuilder.fontSize(value: CSSSizeValue) {
fun StyleBuilder.fontSize(value: CSSUnitValue) {
property("font-size", value(value))
}
fun StyleBuilder.margin(value: CSSSizeValue) {
fun StyleBuilder.margin(value: CSSUnitValue) {
// marign hasn't Typed OM yet
property("margin", value(value.toString()))
property("margin", value(value.asString()))
}
fun StyleBuilder.marginLeft(value: CSSSizeValue) {
property("margin-left", value(value.toString()))
fun StyleBuilder.marginLeft(value: CSSUnitValue) {
property("margin-left", value(value.asString()))
}
fun StyleBuilder.marginTop(value: CSSSizeValue) {
property("margin-top", value(value.toString()))
fun StyleBuilder.marginTop(value: CSSUnitValue) {
property("margin-top", value(value.asString()))
}
fun StyleBuilder.padding(value: CSSSizeValue) {
fun StyleBuilder.padding(value: CSSUnitValue) {
// padding hasn't Typed OM yet
property("padding", value(value.toString()))
property("padding", value(value.asString()))
}

285
web/core/src/jsMain/kotlin/androidx/compose/web/css/CSSUnits.kt

@ -1,114 +1,249 @@
package org.jetbrains.compose.web.css
interface CSSSizeValue : CSSUnitValue, StylePropertyValue
interface CSSRelValue : CSSSizeValue
interface CSSpercentValue : CSSRelValue
interface CSSemValue : CSSRelValue
interface CSSexValue : CSSRelValue
interface CSSchValue : CSSRelValue
interface CSSicValue : CSSRelValue
interface CSSremValue : CSSRelValue
interface CSSlhValue : CSSRelValue
interface CSSrlhValue : CSSRelValue
interface CSSvwValue : CSSRelValue
interface CSSvhValue : CSSRelValue
interface CSSviValue : CSSRelValue
interface CSSvbValue : CSSRelValue
interface CSSvminValue : CSSRelValue
interface CSSvmaxValue : CSSRelValue
interface CSScmValue : CSSRelValue
interface CSSmmValue : CSSRelValue
interface CSSQValue : CSSRelValue
interface CSSAbsValue : CSSSizeValue
interface CSSptValue : CSSAbsValue
interface CSSpcValue : CSSAbsValue
interface CSSpxValue : CSSAbsValue
interface CSSangleValue : CSSUnitValue
interface CSSdegValue : CSSangleValue
interface CSSgradValue : CSSangleValue
interface CSSradValue : CSSangleValue
interface CSSturnValue : CSSangleValue
interface CSSTimeValue : CSSUnitValue
interface CSSsValue : CSSTimeValue
interface CSSmsValue : CSSTimeValue
interface CSSFrequencyValue : CSSUnitValue
interface CSSHzValue : CSSFrequencyValue
interface CSSkHzValue : CSSFrequencyValue
interface CSSResolutionValue : CSSUnitValue
interface CSSdpiValue : CSSResolutionValue
interface CSSdpcmValue : CSSResolutionValue
interface CSSdppxValue : CSSResolutionValue
interface CSSFlexValue : CSSUnitValue
interface CSSfrValue : CSSFlexValue
interface CSSSizeValue<out T : CSSUnit> : CSSNumericValue {
val value: Float
val unit: T
fun asString(): String = "${value}${unit.value}"
fun newUnit(value: Float): CSSSizeValue<T>
}
private data class CSSUnitValueTyped<out T : CSSUnit>(
override val value: Float,
override val unit: T
) : CSSSizeValue<T> {
override fun newUnit(value: Float): CSSSizeValue<T> = copy(value = value)
}
operator fun <T : CSSUnit> CSSSizeValue<T>.times(num: Number): CSSSizeValue<T> = newUnit(value * num.toFloat())
operator fun <T : CSSUnit> Number.times(unit: CSSSizeValue<T>): CSSSizeValue<T> = unit.newUnit(unit.value * toFloat())
operator fun <T : CSSUnit> CSSSizeValue<T>.div(num: Number): CSSSizeValue<T> = newUnit(value / num.toFloat())
operator fun <T: CSSUnit> CSSSizeValue<T>.plus(b: CSSSizeValue<T>): CSSSizeValue<T> = newUnit(value + b.value)
operator fun <T: CSSUnit> CSSSizeValue<T>.minus(b: CSSSizeValue<T>): CSSSizeValue<T> = newUnit(value - b.value)
typealias CSSUnitValue = CSSSizeValue<CSSUnit>
typealias CSSpxValue = CSSSizeValue<CSSUnit.px>
interface CSSUnitRel : CSSUnit
interface CSSUnitAbs: CSSUnit
interface CSSUnitAngle: CSSUnit
interface CSSUnitTime: CSSUnit
interface CSSUnitFrequency: CSSUnit
interface CSSUnitResolution: CSSUnit
interface CSSUnitFlex: CSSUnit
typealias CSSAngleValue = CSSSizeValue<CSSUnitAngle>
sealed interface CSSUnit {
val value: String
object percent: CSSUnitRel {
override val value: String = "%"
}
object em: CSSUnitRel {
override val value = "em"
}
object ex: CSSUnitRel {
override val value = "ex"
}
object ch: CSSUnitRel {
override val value = "ch"
}
object ic: CSSUnitRel {
override val value = "ic"
}
object rem: CSSUnitRel {
override val value = "rem"
}
object lh: CSSUnitRel {
override val value = "lh"
}
object rlh: CSSUnitRel {
override val value = "rlh"
}
object vw: CSSUnitRel {
override val value = "vw"
}
object vh: CSSUnitRel {
override val value = "vh"
}
object vi: CSSUnitRel {
override val value = "vi"
}
object vb: CSSUnitRel {
override val value = "vb"
}
object vmin: CSSUnitRel {
override val value = "vmin"
}
object vmax: CSSUnitRel {
override val value = "vmax"
}
object cm: CSSUnitRel {
override val value = "cm"
}
object mm: CSSUnitRel {
override val value = "mm"
}
object q: CSSUnitRel {
override val value = "q"
}
object pt: CSSUnitAbs {
override val value = "pt"
}
object pc: CSSUnitAbs {
override val value = "pc"
}
object px: CSSUnitAbs {
override val value = "px"
}
object deg: CSSUnitAngle {
override val value = "deg"
}
object grad: CSSUnitAngle {
override val value = "grad"
}
object rad: CSSUnitAngle {
override val value = "rad"
}
object turn: CSSUnitAngle {
override val value = "turn"
}
object s: CSSUnitTime {
override val value = "s"
}
object ms: CSSUnitTime {
override val value = "ms"
}
object hz: CSSUnitFrequency {
override val value = "hz"
}
object khz: CSSUnitFrequency {
override val value = "khz"
}
object dpi: CSSUnitResolution {
override val value = "dpi"
}
object dpcm: CSSUnitResolution {
override val value = "dpcm"
}
object dppx: CSSUnitResolution {
override val value = "dppx"
}
object fr: CSSUnitFlex {
override val value = "fr"
}
object number: CSSUnit {
override val value = "number"
}
}
val Number.number
get(): CSSUnitValue = CSS.number(this)
get(): CSSSizeValue<CSSUnit.number> = CSSUnitValueTyped(this.toFloat(), CSSUnit.number)
val Number.percent
get(): CSSpercentValue = CSS.percent(this)
get() : CSSSizeValue<CSSUnit.percent> = CSSUnitValueTyped(this.toFloat(), CSSUnit.percent)
val Number.em
get(): CSSemValue = CSS.em(this)
get() : CSSSizeValue<CSSUnit.em> = CSSUnitValueTyped(this.toFloat(), CSSUnit.em)
val Number.ex
get(): CSSexValue = CSS.ex(this)
get(): CSSSizeValue<CSSUnit.ex> = CSSUnitValueTyped(this.toFloat(), CSSUnit.ex)
val Number.ch
get(): CSSchValue = CSS.ch(this)
get(): CSSSizeValue<CSSUnit.ch> = CSSUnitValueTyped(this.toFloat(), CSSUnit.ch)
val Number.cssRem
get(): CSSremValue = CSS.rem(this)
get(): CSSSizeValue<CSSUnit.rem> = CSSUnitValueTyped(this.toFloat(), CSSUnit.rem)
val Number.vw
get(): CSSvwValue = CSS.vw(this)
get(): CSSSizeValue<CSSUnit.vw> = CSSUnitValueTyped(this.toFloat(), CSSUnit.vw)
val Number.vh
get(): CSSvhValue = CSS.vh(this)
get(): CSSSizeValue<CSSUnit.vh> = CSSUnitValueTyped(this.toFloat(), CSSUnit.vh)
val Number.vmin
get(): CSSvminValue = CSS.vmin(this)
get(): CSSSizeValue<CSSUnit.vmin> = CSSUnitValueTyped(this.toFloat(), CSSUnit.vmin)
val Number.vmax
get(): CSSvmaxValue = CSS.vmax(this)
get(): CSSSizeValue<CSSUnit.vmax> = CSSUnitValueTyped(this.toFloat(), CSSUnit.vmax)
val Number.cm
get(): CSScmValue = CSS.cm(this)
get(): CSSSizeValue<CSSUnit.cm> = CSSUnitValueTyped(this.toFloat(), CSSUnit.cm)
val Number.mm
get(): CSSmmValue = CSS.mm(this)
get(): CSSSizeValue<CSSUnit.mm> = CSSUnitValueTyped(this.toFloat(), CSSUnit.mm)
val Number.Q
get(): CSSQValue = CSS.Q(this)
get() : CSSSizeValue<CSSUnit.q> = CSSUnitValueTyped(this.toFloat(), CSSUnit.q)
val Number.pt
get(): CSSptValue = CSS.pt(this)
get(): CSSSizeValue<CSSUnit.pt> = CSSUnitValueTyped(this.toFloat(), CSSUnit.pt)
val Number.pc
get(): CSSpcValue = CSS.pc(this)
get(): CSSSizeValue<CSSUnit.pc> = CSSUnitValueTyped(this.toFloat(), CSSUnit.pc)
val Number.px
get(): CSSpxValue = CSS.px(this)
get(): CSSSizeValue<CSSUnit.px> = CSSUnitValueTyped(this.toFloat(), CSSUnit.px)
val Number.deg
get(): CSSdegValue = CSS.deg(this)
get(): CSSSizeValue<CSSUnit.deg> = CSSUnitValueTyped(this.toFloat(), CSSUnit.deg)
val Number.grad
get(): CSSgradValue = CSS.grad(this)
get(): CSSSizeValue<CSSUnit.grad> = CSSUnitValueTyped(this.toFloat(), CSSUnit.grad)
val Number.rad
get(): CSSradValue = CSS.rad(this)
get(): CSSSizeValue<CSSUnit.rad> = CSSUnitValueTyped(this.toFloat(), CSSUnit.rad)
val Number.turn
get(): CSSturnValue = CSS.turn(this)
get(): CSSSizeValue<CSSUnit.turn> = CSSUnitValueTyped(this.toFloat(), CSSUnit.turn)
val Number.s
get(): CSSsValue = CSS.s(this)
get(): CSSSizeValue<CSSUnit.s> = CSSUnitValueTyped(this.toFloat(), CSSUnit.s)
val Number.ms
get(): CSSmsValue = CSS.ms(this)
get(): CSSSizeValue<CSSUnit.ms> = CSSUnitValueTyped(this.toFloat(), CSSUnit.ms)
val Number.Hz
get(): CSSHzValue = CSS.Hz(this)
get(): CSSSizeValue<CSSUnit.hz> = CSSUnitValueTyped(this.toFloat(), CSSUnit.hz)
val Number.kHz
get(): CSSkHzValue = CSS.kHz(this)
get(): CSSSizeValue<CSSUnit.khz> = CSSUnitValueTyped(this.toFloat(), CSSUnit.khz)
val Number.dpi
get(): CSSdpiValue = CSS.dpi(this)
get(): CSSSizeValue<CSSUnit.dpi> = CSSUnitValueTyped(this.toFloat(), CSSUnit.dpi)
val Number.dpcm
get(): CSSdpcmValue = CSS.dpcm(this)
get(): CSSSizeValue<CSSUnit.dpcm> = CSSUnitValueTyped(this.toFloat(), CSSUnit.dpcm)
val Number.dppx
get(): CSSdppxValue = CSS.dppx(this)
get(): CSSSizeValue<CSSUnit.dppx> = CSSUnitValueTyped(this.toFloat(), CSSUnit.dppx)
val Number.fr
get(): CSSfrValue = CSS.fr(this)
get(): CSSSizeValue<CSSUnit.fr> = CSSUnitValueTyped(this.toFloat(), CSSUnit.fr)

8
web/core/src/jsMain/kotlin/androidx/compose/web/css/Color.kt

@ -15,16 +15,16 @@ abstract class Color : CustomStyleValue {
override fun toString(): String = "rgba($r, $g, $b, $a)"
}
data class HSL(val h: CSSangleValue, val s: Number, val l: Number) : Color() {
data class HSL(val h: CSSAngleValue, val s: Number, val l: Number) : Color() {
constructor(h: Number, s: Number, l: Number) : this(h.deg, s, l)
override fun toString(): String = "hsl($h, $s%, $l%)"
override fun toString(): String = "hsl(${h.asString()}, $s%, $l%)"
}
data class HSLA(val h: CSSangleValue, val s: Number, val l: Number, val a: Number) : Color() {
data class HSLA(val h: CSSAngleValue, val s: Number, val l: Number, val a: Number) : Color() {
constructor(h: Number, s: Number, l: Number, a: Number) : this(h.deg, s, l, a)
override fun toString(): String = "hsla($h, $s%, $l%, $a)"
override fun toString(): String = "hsla(${h.asString()}, $s%, $l%, $a)"
}
companion object {

291
web/core/src/jsTest/kotlin/CSSUnitApiTests.kt

@ -5,27 +5,29 @@
package org.jetbrains.compose.web.core.tests
import org.jetbrains.compose.web.css.CSS
import org.jetbrains.compose.web.css.CSSUnitValue
import org.jetbrains.compose.web.css.ch
import org.jetbrains.compose.web.css.cm
import org.jetbrains.compose.web.css.cssRem
import org.jetbrains.compose.web.css.deg
import org.jetbrains.compose.web.css.div
import org.jetbrains.compose.web.css.dpcm
import org.jetbrains.compose.web.css.dpi
import org.jetbrains.compose.web.css.dppx
import org.jetbrains.compose.web.css.em
import org.jetbrains.compose.web.css.fr
import org.jetbrains.compose.web.css.grad
import org.jetbrains.compose.web.css.minus
import org.jetbrains.compose.web.css.mm
import org.jetbrains.compose.web.css.ms
import org.jetbrains.compose.web.css.number
import org.jetbrains.compose.web.css.pc
import org.jetbrains.compose.web.css.percent
import org.jetbrains.compose.web.css.plus
import org.jetbrains.compose.web.css.pt
import org.jetbrains.compose.web.css.px
import org.jetbrains.compose.web.css.rad
import org.jetbrains.compose.web.css.s
import org.jetbrains.compose.web.css.times
import org.jetbrains.compose.web.css.turn
import org.jetbrains.compose.web.css.vh
import org.jetbrains.compose.web.css.vmax
@ -37,88 +39,261 @@ import kotlin.test.assertEquals
class CSSUnitApiTests {
// TODO: Cover CSS.Q, CSS.khz and CSS.hz after we'll get rid from polyfill
private fun CSSUnitValue.assertStructure(value: Number, unit: String, description: String? = null) {
assertEquals(this.value, value, description)
assertEquals(this.unit, unit, description)
@Test
fun postfixInvocation() {
// TODO: review what exactly number does - most likely we don't need it in our ecosystem
assertEquals("4number", 4.number.asString())
assertEquals("4%", 4.percent.asString())
assertEquals("4em", 4.em.asString())
assertEquals("4ch", 4.ch.asString())
assertEquals("4rem", 4.cssRem.asString())
assertEquals("4vw", 4.vw.asString())
assertEquals("4vh", 4.vh.asString())
assertEquals("4vmin", 4.vmin.asString())
assertEquals("4vmax", 4.vmax.asString())
assertEquals("4cm", 4.cm.asString())
assertEquals("4mm", 4.mm.asString())
assertEquals("4pt", 4.pt.asString())
assertEquals("4pc", 4.pc.asString())
assertEquals("4px", 4.px.asString())
assertEquals("4deg", 4.deg.asString())
assertEquals("4grad", 4.grad.asString())
assertEquals("4rad", 4.rad.asString())
assertEquals("4turn", 4.turn.asString())
assertEquals("4s", 4.s.asString())
assertEquals("4ms", 4.ms.asString())
assertEquals("4dpi", 4.dpi.asString())
assertEquals("4dpcm", 4.dpcm.asString())
assertEquals("4dppx", 4.dppx.asString())
assertEquals("4fr", 4.fr.asString())
}
// TODO: use regular assertEqual after we'll get rid from polyfill
private fun CSSUnitValue.assertStructure(otherUnit: CSSUnitValue, description: String? = null) {
return assertStructure(otherUnit.value, otherUnit.unit, description)
@Test
fun id() {
// TODO: review what exactly number does - most likely we don't need it in our ecosystem
assertEquals(4.number, 4.number)
assertEquals(4.percent, 4.percent)
assertEquals(4.em, 4.em)
assertEquals(4.ch, 4.ch)
assertEquals(4.cssRem, 4.cssRem)
assertEquals(4.vw, 4.vw)
assertEquals(4.vh, 4.vh)
assertEquals(4.vmin, 4.vmin)
assertEquals(4.vmax, 4.vmax)
assertEquals(4.cm, 4.cm)
assertEquals(4.mm, 4.mm)
assertEquals(4.pt, 4.pt)
assertEquals(4.pc, 4.pc)
assertEquals(4.px, 4.px)
assertEquals(4.deg, 4.deg)
assertEquals(4.grad, 4.grad)
assertEquals(4.rad, 4.rad)
assertEquals(4.turn, 4.turn)
assertEquals(4.s, 4.s)
assertEquals(4.ms, 4.ms)
assertEquals(4.dpi, 4.dpi)
assertEquals(4.dpcm, 4.dpcm)
assertEquals(4.dppx, 4.dppx)
assertEquals(4.fr, 4.fr)
}
@Test
fun builderInvocation() {
CSS.number(4).assertStructure(4, "number")
CSS.percent(4).assertStructure(4, "percent")
fun arithmeticMultiplicationLeft() {
assertEquals(16.percent, 4.percent * 4)
CSS.em(4).assertStructure(4, "em")
CSS.ch(4).assertStructure(4, "ch")
assertEquals(16.em, 4.em * 4)
assertEquals(16.ch, 4.ch * 4)
CSS.rem(4).assertStructure(4, "rem")
assertEquals(16.cssRem, 4.cssRem * 4)
CSS.vw(4).assertStructure(4, "vw")
CSS.vh(4).assertStructure(4, "vh")
assertEquals(16.vw, 4.vw * 4)
assertEquals(16.vh, 4.vh * 4)
CSS.vmin(4).assertStructure(4, "vmin")
CSS.vmax(4).assertStructure(4, "vmax")
CSS.cm(4).assertStructure(4, "cm")
CSS.mm(4).assertStructure(4, "mm")
assertEquals(16.vmin, 4.vmin * 4)
assertEquals(16.vmax, 4.vmax * 4)
assertEquals(16.cm, 4.cm * 4)
assertEquals(16.mm, 4.mm * 4)
CSS.pt(4).assertStructure(4, "pt")
CSS.pc(4).assertStructure(4, "pc")
CSS.px(4).assertStructure(4, "px")
assertEquals(16.pt, 4.pt * 4)
assertEquals(16.pc, 4.pc * 4)
assertEquals(16.px, 4.px * 4)
CSS.deg(4).assertStructure(4, "deg")
CSS.grad(4).assertStructure(4, "grad")
CSS.rad(4).assertStructure(4, "rad")
CSS.turn(4).assertStructure(4, "turn")
assertEquals(16.deg, 4.deg * 4)
assertEquals(16.grad, 4.grad * 4)
assertEquals(16.rad, 4.rad * 4)
assertEquals(16.turn, 4.turn * 4)
CSS.s(4).assertStructure(4, "s")
CSS.ms(4).assertStructure(4, "ms")
assertEquals(16.s, 4.s * 4)
assertEquals(16.ms, 4.ms * 4)
CSS.dpi(4).assertStructure(4, "dpi")
CSS.dpcm(4).assertStructure(4, "dpcm")
CSS.dppx(4).assertStructure(4, "dppx")
assertEquals(16.dpi, 4.dpi * 4)
assertEquals(16.dpcm, 4.dpcm * 4)
assertEquals(16.dppx, 4.dppx * 4)
CSS.fr(4).assertStructure(4, "fr")
assertEquals(16.fr, 4.fr * 4)
}
@Test
fun postfixInvocation() {
4.number.assertStructure(CSS.number(4), "number postfix")
4.percent.assertStructure(CSS.percent(4), "percent posfix")
fun arithmeticDivisionLeft() {
assertEquals(1.percent, 4.percent / 4)
4.em.assertStructure(CSS.em(4), "em postfix")
4.ch.assertStructure(CSS.ch(4), "ch postfix")
assertEquals(1.em, 4.em / 4)
assertEquals(1.ch, 4.ch / 4)
4.cssRem.assertStructure(CSS.rem(4))
assertEquals(1.cssRem, 4.cssRem / 4)
4.vw.assertStructure(CSS.vw(4),"vw postfix")
4.vh.assertStructure(CSS.vh(4), "vh postfix")
assertEquals(1.vw, 4.vw / 4)
assertEquals(1.vh, 4.vh / 4)
4.vmin.assertStructure(CSS.vmin(4), "vmin postfix")
4.vmax.assertStructure(CSS.vmax(4), "vmax postfix")
4.cm.assertStructure(CSS.cm(4), "cm postfix")
4.mm.assertStructure(CSS.mm(4), "mm postfix")
assertEquals(1.vmin, 4.vmin / 4)
assertEquals(1.vmax, 4.vmax / 4)
assertEquals(1.cm, 4.cm / 4)
assertEquals(1.mm, 4.mm / 4)
4.pt.assertStructure(CSS.pt(4), "pt postfix")
4.pc.assertStructure(CSS.pc(4), "pc postfix")
4.px.assertStructure(CSS.px(4), "px postfix")
assertEquals(1.pt, 4.pt / 4)
assertEquals(1.pc, 4.pc / 4)
assertEquals(1.px, 4.px / 4)
4.deg.assertStructure(CSS.deg(4), "deg postfix")
4.grad.assertStructure(CSS.grad(4), "grad postfix")
4.rad.assertStructure(CSS.rad(4), "rad postfix")
4.turn.assertStructure(CSS.turn(4), "turn postfix")
assertEquals(1.deg, 4.deg / 4)
assertEquals(1.grad, 4.grad / 4)
assertEquals(1.rad, 4.rad / 4)
assertEquals(1.turn, 4.turn / 4)
4.s.assertStructure(CSS.s(4), "s postfix")
4.ms.assertStructure(CSS.ms(4), "ms postfix")
assertEquals(1.s, 4.s / 4)
assertEquals(1.ms, 4.ms / 4)
4.dpi.assertStructure(CSS.dpi(4), "dpi postfix")
4.dpcm.assertStructure(CSS.dpcm(4), "dpcm postfix")
4.dppx.assertStructure(CSS.dppx(4), "dppx postfix")
assertEquals(1.dpi, 4.dpi / 4)
assertEquals(1.dpcm, 4.dpcm / 4)
assertEquals(1.dppx, 4.dppx / 4)
4.fr.assertStructure(CSS.fr(4), "fr postfix")
assertEquals(1.fr, 4.fr / 4)
}
@Test
fun arithmeticMultiplicationRight() {
assertEquals(12.percent, 3 * 4.percent)
assertEquals(12.em, 3 * 4.em)
assertEquals(12.ch, 3 * 4.ch)
assertEquals(12.cssRem, 3 * 4.cssRem)
assertEquals(12.vw, 3 * 4.vw)
assertEquals(12.vh, 3 * 4.vh)
assertEquals(12.vmin, 3 * 4.vmin)
assertEquals(12.vmax, 3 * 4.vmax)
assertEquals(12.cm, 3 * 4.cm)
assertEquals(12.mm, 3 * 4.mm)
assertEquals(12.pt, 3 * 4.pt)
assertEquals(12.pc, 3 * 4.pc)
assertEquals(12.px, 3 * 4.px)
assertEquals(12.deg, 3 * 4.deg)
assertEquals(12.grad, 3 * 4.grad)
assertEquals(12.rad, 3 * 4.rad)
assertEquals(12.turn, 3 * 4.turn)
assertEquals(12.s, 3 * 4.s)
assertEquals(12.ms, 3 * 4.ms)
assertEquals(12.dpi, 3 * 4.dpi)
assertEquals(12.dpcm, 3 * 4.dpcm)
assertEquals(12.dppx, 3 * 4.dppx)
assertEquals(12.fr, 3 * 4.fr)
}
@Test
fun addHomogenous() {
assertEquals(13.percent, 7.percent + 4.percent + 2.percent)
assertEquals(13.em, 7.em + 4.em + 2.em)
assertEquals(13.ch, 7.ch + 4.ch + 2.ch)
assertEquals(13.cssRem, 7.cssRem + 4.cssRem + 2.cssRem)
assertEquals(13.vw, 7.vw + 4.vw + 2.vw)
assertEquals(13.vh, 7.vh + 4.vh + 2.vh)
assertEquals(13.vmin, 7.vmin + 4.vmin + 2.vmin)
assertEquals(13.vmax, 7.vmax + 4.vmax + 2.vmax)
assertEquals(13.cm, 7.cm + 4.cm + 2.cm)
assertEquals(13.mm, 7.mm + 4.mm + 2.mm)
assertEquals(13.pt, 7.pt + 4.pt + 2.pt)
assertEquals(13.pc, 7.pc + 4.pc + 2.pc)
assertEquals(13.px, 7.px + 4.px + 2.px)
assertEquals(13.deg, 7.deg + 4.deg + 2.deg)
assertEquals(13.grad, 7.grad + 4.grad + 2.grad)
assertEquals(13.rad, 7.rad + 4.rad + 2.rad)
assertEquals(13.turn, 7.turn + 4.turn + 2.turn)
assertEquals(13.s, 7.s + 4.s + 2.s)
assertEquals(13.ms, 7.ms + 4.ms + 2.ms)
assertEquals(13.dpi, 7.dpi + 4.dpi + 2.dpi)
assertEquals(13.dpcm, 7.dpcm + 4.dpcm + 2.dpcm)
assertEquals(13.dppx, 7.dppx + 4.dppx + 2.dppx)
assertEquals(13.fr, 7.fr + 4.fr + 2.fr)
}
@Test
fun substractHomogenous() {
assertEquals(1.percent, 7.percent - 4.percent - 2.percent)
assertEquals(1.em, 7.em - 4.em - 2.em)
assertEquals(1.ch, 7.ch - 4.ch - 2.ch)
assertEquals(1.cssRem, 7.cssRem - 4.cssRem - 2.cssRem)
assertEquals(1.vw, 7.vw - 4.vw - 2.vw)
assertEquals(1.vh, 7.vh - 4.vh - 2.vh)
assertEquals(1.vmin, 7.vmin - 4.vmin - 2.vmin)
assertEquals(1.vmax, 7.vmax - 4.vmax - 2.vmax)
assertEquals(1.cm, 7.cm - 4.cm - 2.cm)
assertEquals(1.mm, 7.mm - 4.mm - 2.mm)
assertEquals(1.pt, 7.pt - 4.pt - 2.pt)
assertEquals(1.pc, 7.pc - 4.pc - 2.pc)
assertEquals(1.px, 7.px - 4.px - 2.px)
assertEquals(1.deg, 7.deg - 4.deg - 2.deg)
assertEquals(1.grad, 7.grad - 4.grad - 2.grad)
assertEquals(1.rad, 7.rad - 4.rad - 2.rad)
assertEquals(1.turn, 7.turn - 4.turn - 2.turn)
assertEquals(1.s, 7.s - 4.s - 2.s)
assertEquals(1.ms, 7.ms - 4.ms - 2.ms)
assertEquals(1.dpi, 7.dpi - 4.dpi - 2.dpi)
assertEquals(1.dpcm, 7.dpcm - 4.dpcm - 2.dpcm)
assertEquals(1.dppx, 7.dppx - 4.dppx - 2.dppx)
assertEquals(1.fr, 7.fr - 4.fr - 2.fr)
}
}
Loading…
Cancel
Save